commit 0af5775be3fb8f71654171013b1d514fde751558 Author: Zhi Guan Date: Tue Jul 13 19:21:43 2021 +0800 Init commit of gmssl-v3 diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..d582b416 --- /dev/null +++ b/.gitignore @@ -0,0 +1,220 @@ +# Ignore editor artefacts +/.dir-locals.el + +# Top level excludes +/Makefile.orig +/MINFO +/TABLE +/*.a +/*.pc +/rehash.time +/inc.* +/makefile.* +/out.* +/tmp.* +/configdata.pm +/build +/Makefile + +# *all* Makefiles +#Makefile +*.tmp + +# Java +/java/*.class +/java/Makefile* + +# Links under apps +/apps/CA.pl +/apps/tsget +/apps/tsget.pl +/apps/md4.c + +# Auto generated headers +/crypto/buildinf.h +/crypto/include/internal/*_conf.h +/openssl/include/opensslconf.h +/util/domd + +# Executables +/apps/openssl +/test/sha256t +/test/sha512t +/test/gost2814789t +/test/ssltest_old +/test/*test +/test/fips_aesavs +/test/fips_desmovs +/test/fips_dhvs +/test/fips_drbgvs +/test/fips_dssvs +/test/fips_ecdhvs +/test/fips_ecdsavs +/test/fips_rngvs +/test/fips_test_suite +/test/ssltest_old +/test/x509aux +/test/v3ext + +# Certain files that get created by tests on the fly +/test/*.ss +/test/*.srl +/test/.rnd +/test/test*.pem +/test/newkey.pem +/test/*.log +/test/buildtest_* +/test/*.p +/test/*.dd +/test/*.dp +/test/*.pd +/test/*.p + +/util/shlib_wrap.sh + +# Fuzz stuff. +# Anything without an extension is an executable on Unix, so we keep files +# with extensions. And we keep the corpora subddir versioned as well. +# Anything more generic with extensions that should be ignored will be taken +# care of by general ignores for those extensions (*.o, *.obj, *.exe, ...) +/fuzz/* +!/fuzz/README* +!/fuzz/corpora +!/fuzz/*.* + +# Misc auto generated files +/include/openssl/opensslconf.h +/tools/c_rehash +/tools/c_rehash.pl +/tags +/TAGS +/crypto.map +/ssl.map + +# Windows (legacy) +/tmp32 +/tmp32.dbg +/tmp32dll +/tmp32dll.dbg +/out32 +/out32.dbg +/out32dll +/out32dll.dbg +/inc32 +/MINFO +/ms/.rnd +/ms/bcb.mak +/ms/libeay32.def +/ms/nt.mak +/ms/ntdll.mak +/ms/ssleay32.def +/ms/version32.rc + +# Files created on other branches that are not held in git, and are not +# needed on this branch +/include/openssl/asn1_mac.h +/include/openssl/des_old.h +/include/openssl/fips.h +/include/openssl/fips_rand.h +/include/openssl/krb5_asn.h +/include/openssl/kssl.h +/include/openssl/pq_compat.h +/include/openssl/ssl23.h +/include/openssl/tmdiff.h +/include/openssl/ui_compat.h +/test/fips_aesavs.c +/test/fips_desmovs.c +/test/fips_dsatest.c +/test/fips_dssvs.c +/test/fips_hmactest.c +/test/fips_randtest.c +/test/fips_rngvs.c +/test/fips_rsagtest.c +/test/fips_rsastest.c +/test/fips_rsavtest.c +/test/fips_shatest.c +/test/fips_test_suite.c +/test/shatest.c + +##### Generic patterns +# Auto generated assembly language source files +*.s +!/crypto/*/asm/*.s +/crypto/arm*.S +/crypto/*/*.S +*.asm +!/crypto/*/asm/*.asm + +# Object files +*.o +*.obj + +# editor artefacts +*.swp +.#* +\#*# +*~ + +# Certificate symbolic links +*.0 + +# All kinds of executables +*.so +*.so.* +*.dylib +*.dylib.* +*.dll +*.dll.* +*.exe +*.pyc +*.exp +*.lib +*.pdb +*.ilk +*.def +*.rc +*.res + +# Misc generated stuff +Makefile.save +/crypto/**/lib +/engines/**/lib +/ssl/**/lib +*.bak +cscope.* +*.d + +# macOS +.DS_Store +*.tar.gz + +# add by LiTianjue for GmSSL +# auto create by Configure +crypto/opensslconf.h +tool/c_rehash +# exec file +apps/gmssl +apps/gmca/.ca + +# gmtls +/ssl/ssl_load.c + +# demos +/demos +/demos/kdf +/demos/ssl +/demos/otp +/demos/sm9 + +# engines +/engines/e_skf* +/engines/e_sdf* +/engines/sdf +/engines/skf + +include/openssl/srp.h + +/*.sh + +/rust +/python diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 00000000..ef1cbc16 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,201 @@ + +cmake_minimum_required(VERSION 2.8.11) +project(GmSSL) + +include_directories(include) + +add_library( + gmssl + + src/hex.c + src/debug.c + src/rand.c + + src/sm2_lib.c + src/sm2_prn.c + src/sm2_algo.c + src/sm2_asn1.c + src/sm3.c + src/sm3_hmac.c + src/sm4_common.c + src/sm4_setkey.c + src/sm4_enc.c + src/sm4_cbc.c + src/sm9_math.c + src/zuc_core.c + src/zuc_eea.c + src/zuc_eia.c + + src/hash_drbg.c + src/hmac.c + src/hkdf.c + #src/cmac.c + src/pbkdf2.c + src/pkcs8.c + + src/oid.c + src/asn1.c + + src/rc4.c + src/md5.c + src/des.c + src/aes.c + src/chacha20.c + src/sha1.c + src/sha256.c + src/sha512.c + + src/digest.c + #src/digest_asn1.c + src/x509_lib.c + src/x509_asn1.c + src/x509_ext.c + src/x509_algor.c + + src/base64.c + src/pem.c + + src/tls.c + src/tls_cipher.c + src/tls_trace.c + src/tls12.c + src/tlcp.c + + src/cms.c + +) + +target_include_directories (gmssl PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include) + +# tools +add_executable (digest tools/digest.c) +target_link_libraries (digest LINK_PUBLIC gmssl) + +add_executable (certview tools/certview.c) +target_link_libraries (certview LINK_PUBLIC gmssl) + +add_executable (certgen tools/certgen.c) +target_link_libraries (certgen LINK_PUBLIC gmssl) + +add_executable (certverify tools/certverify.c) +target_link_libraries (certverify LINK_PUBLIC gmssl) + +add_executable (reqgen tools/reqgen.c) +target_link_libraries (reqgen LINK_PUBLIC gmssl) + +add_executable (sm3sum tools/sm3sum.c) +target_link_libraries (sm3sum LINK_PUBLIC gmssl) + +add_executable (sm2gen tools/sm2gen.c) +target_link_libraries (sm2gen LINK_PUBLIC gmssl) + +add_executable (sm2sign tools/sm2sign.c) +target_link_libraries (sm2sign LINK_PUBLIC gmssl) +add_executable (sm2verify tools/sm2verify.c) +target_link_libraries (sm2verify LINK_PUBLIC gmssl) +add_executable (sm2encrypt tools/sm2encrypt.c) +target_link_libraries (sm2encrypt LINK_PUBLIC gmssl) +add_executable (sm2decrypt tools/sm2decrypt.c) +target_link_libraries (sm2decrypt LINK_PUBLIC gmssl) + +add_executable (pkcs8gen tools/pkcs8gen.c) +target_link_libraries (pkcs8gen LINK_PUBLIC gmssl) + +add_executable (sm2view tools/sm2view.c) +target_link_libraries (sm2view LINK_PUBLIC gmssl) + +add_executable (pkcs8view tools/pkcs8view.c) +target_link_libraries (pkcs8view LINK_PUBLIC gmssl) + +add_executable (tlcp_client tools/tlcp_client.c) +target_link_libraries (tlcp_client LINK_PUBLIC gmssl) + +add_executable (tlcp_server tools/tlcp_server.c) +target_link_libraries (tlcp_server LINK_PUBLIC gmssl) + +add_executable (tls12_client tools/tls12_client.c) +target_link_libraries (tls12_client LINK_PUBLIC gmssl) +add_executable (tls12_server tools/tls12_server.c) +target_link_libraries (tls12_server LINK_PUBLIC gmssl) + + +# tests +add_executable(sm2test tests/sm2test.c) +target_link_libraries (sm2test LINK_PUBLIC gmssl) +add_executable(sm2asn1test tests/sm2asn1test.c) +target_link_libraries (sm2asn1test LINK_PUBLIC gmssl) + +add_executable(sm3test tests/sm3test.c) +target_link_libraries (sm3test LINK_PUBLIC gmssl) + +add_executable(md5test tests/md5test.c) +target_link_libraries (md5test LINK_PUBLIC gmssl) + +add_executable(sha1test tests/sha1test.c) +target_link_libraries (sha1test LINK_PUBLIC gmssl) + +add_executable(sha224test tests/sha224test.c) +target_link_libraries (sha224test LINK_PUBLIC gmssl) + +add_executable(sha256test tests/sha256test.c) +target_link_libraries (sha256test LINK_PUBLIC gmssl) + +add_executable(sha384test tests/sha384test.c) +target_link_libraries (sha384test LINK_PUBLIC gmssl) + +add_executable(sha512test tests/sha512test.c) +target_link_libraries (sha512test LINK_PUBLIC gmssl) + +add_executable(hmactest tests/hmactest.c) +target_link_libraries (hmactest LINK_PUBLIC gmssl) + +add_executable(hkdftest tests/hkdftest.c) +target_link_libraries (hkdftest LINK_PUBLIC gmssl) + +add_executable(digesttest tests/digesttest.c) +target_link_libraries (digesttest LINK_PUBLIC gmssl) + +add_executable(sm4test tests/sm4test.c) +target_link_libraries (sm4test LINK_PUBLIC gmssl) +add_executable(sm4cbctest tests/sm4cbctest.c) +target_link_libraries (sm4cbctest LINK_PUBLIC gmssl) + +add_executable(zuctest tests/zuctest.c) +target_link_libraries (zuctest LINK_PUBLIC gmssl) + +add_executable(aestest tests/aestest.c) +target_link_libraries (aestest LINK_PUBLIC gmssl) + +add_executable(rc4test tests/rc4test.c) +target_link_libraries (rc4test LINK_PUBLIC gmssl) + +add_executable(chacha20test tests/chacha20test.c) +target_link_libraries (chacha20test LINK_PUBLIC gmssl) + +add_executable(hash_drbgtest tests/hash_drbgtest.c) +target_link_libraries (hash_drbgtest LINK_PUBLIC gmssl) + +add_executable(pbkdf2test tests/pbkdf2test.c) +target_link_libraries (pbkdf2test LINK_PUBLIC gmssl) + +add_executable(pkcs8test tests/pkcs8test.c) +target_link_libraries (pkcs8test LINK_PUBLIC gmssl) + +add_executable(oidtest tests/oidtest.c) +target_link_libraries (oidtest LINK_PUBLIC gmssl) + +add_executable(asn1test tests/asn1test.c) +target_link_libraries (asn1test LINK_PUBLIC gmssl) + +add_executable(base64test tests/base64test.c) +target_link_libraries (base64test LINK_PUBLIC gmssl) + +add_executable(x509test tests/x509test.c) +target_link_libraries (x509test LINK_PUBLIC gmssl) + +add_executable(cmstest tests/cmstest.c) +target_link_libraries (cmstest LINK_PUBLIC gmssl) + +#add_executable(tlstest tests/tlstest.c) +#target_link_libraries (tlstest LINK_PUBLIC gmssl) + diff --git a/README.md b/README.md new file mode 100644 index 00000000..ffd83942 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# GMSSL v3 + + + +更快、更小、更安全是下一个大版本升级(GmSSL v3.0)的主要目标,我们将从下列方向进行改进: + +1. 采用CMake替代目前基于Perl的构建系统 +2. 支持Linux/Windows/macOS/Android/iOS等主流操作系统,移除对嵌入式OS等其他系统的支持 +3. 支持X86/ARM/RISC-V,针对上述平台64位指令集做汇编层面的优化 +4. 将C语言标准由目前的C89更新为最新的C99或C11,及部分GCC特性,移除对Perl的依赖 +5. 移除不安全的算法和协议,仅支持国密算法和主流国际算法,提升对AEAD、TLS 1.3等新标准的默认支持力度 +6. 提升密码算法抗木马、抗侧信道攻击的安全性 +7. 降低运行时堆内存的使用量,降低总体二进制代码体积 +8. 提供特定于国密算法和协议的统一的多语言(支持Rust/Java/Go/PHP)封装 +9. 保持和OpenSSL最新版本的兼容性,实现GmSSL和OpenSSL在同一个软件中的共存 + diff --git a/include/gmssl/aes.h b/include/gmssl/aes.h new file mode 100644 index 00000000..6b7997f4 --- /dev/null +++ b/include/gmssl/aes.h @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2014 - 2021 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + + +#ifndef GMSSL_AES_H +#define GMSSL_AES_H + +#include +#include + +#define AES128_KEY_BITS 128 +#define AES192_KEY_BITS 192 +#define AES256_KEY_BITS 256 + +#define AES128_KEY_SIZE (AES128_KEY_BITS/8) +#define AES192_KEY_SIZE (AES192_KEY_BITS/8) +#define AES256_KEY_SIZE (AES256_KEY_BITS/8) + +#define AES_BLOCK_SIZE 16 + +#define AES128_ROUNDS 10 +#define AES192_ROUNDS 12 +#define AES256_ROUNDS 14 +#define AES_MAX_ROUNDS AES256_ROUNDS + + +#ifdef __cplusplus +extern "C" { +#endif + + +typedef struct { + uint32_t rk[4 * (AES_MAX_ROUNDS + 1)]; + int rounds; +} AES_KEY; + +int aes_set_encrypt_key(AES_KEY *aes_key, const uint8_t *key, size_t keylen); +int aes_set_decrypt_key(AES_KEY *aes_key, const uint8_t *key, size_t keylen); +void aes_encrypt(const AES_KEY *aes_key, const uint8_t in[AES_BLOCK_SIZE], uint8_t out[AES_BLOCK_SIZE]); +void aes_decrypt(const AES_KEY *aes_key, const uint8_t in[AES_BLOCK_SIZE], uint8_t out[AES_BLOCK_SIZE]); + + +#ifdef __cplusplus +} +#endif +#endif diff --git a/include/gmssl/asn1.h b/include/gmssl/asn1.h new file mode 100644 index 00000000..b01ea298 --- /dev/null +++ b/include/gmssl/asn1.h @@ -0,0 +1,272 @@ +/* + * Copyright (c) 2014 - 2021 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + +#ifndef GMSSL_ASN1_H +#define GMSSL_ASN1_H + +#include +#include + +#if __cplusplus +extern "C" { +#endif + + +#define ASN1_TAG_UNIVERSAL 0x00 +#define ASN1_TAG_APPLICATION 0x40 +#define ASN1_TAG_CONTENT_SPECIFIC 0x80 +#define ASN1_TAG_PRIVATE 0xC0 +#define ASN1_TAG_PRIMITIVE 0x00 +#define ASN1_TAG_CONSTRUCTED 0x20 + +#define ASN1_TAG_IMPLICIT(index) (ASN1_TAG_CONTENT_SPECIFIC|(index)) +#define ASN1_TAG_EXPLICIT(index) ASN1_TAG_IMPLICIT(ASN1_TAG_CONSTRUCTED|(index)) + + +// https://www.obj-sys.com/asn1tutorial/node128.html + +enum ASN1_TAG { + ASN1_TAG_BOOLEAN = 1, + ASN1_TAG_INTEGER = 2, + ASN1_TAG_BIT_STRING = 3, + ASN1_TAG_OCTET_STRING = 4, + ASN1_TAG_NULL = 5, + ASN1_TAG_OBJECT_IDENTIFIER = 6, + ASN1_TAG_ObjectDescriptor = 7, + ASN1_TAG_EXTERNAL = 8, + ASN1_TAG_REAL = 9, + ASN1_TAG_ENUMERATED = 10, + ASN1_TAG_EMBEDDED = 11, + ASN1_TAG_UTF8String = 12, + ASN1_TAG_RELATIVE_OID = 13, + ASN1_TAG_NumericString = 18, + ASN1_TAG_PrintableString = 19, // printable subset of ascii + ASN1_TAG_TeletexString = 20, // T61String + ASN1_TAG_VideotexString = 21, + ASN1_TAG_IA5String = 22, // 7-bit ascii + ASN1_TAG_UTCTime = 23, + ASN1_TAG_GeneralizedTime = 24, + ASN1_TAG_GraphicString = 25, + ASN1_TAG_VisibleString = 26, + ASN1_TAG_GeneralString = 27, + ASN1_TAG_UniversalString = 28, + ASN1_TAG_CHARACTER_STRING = 29, + ASN1_TAG_BMPString = 30, // 2-byte unicode with zeros + ASN1_TAG_SEQUENCE = 0x30, + ASN1_TAG_SET = 0x31, + ASN1_TAG_EXPLICIT = 0xa0, +}; + + + +#define ASN1_TRUE 0xff +#define ASN1_FALSE 0x00 + + + +// 用来解析未定义的OID +typedef struct { + int oid; + uint32_t nodes[16]; + size_t nodes_count; +} ASN1_OID_INFO; + +const char *asn1_tag_name(int tag); + + + + +// private +void asn1_tag_to_der(int tag, uint8_t **out, size_t *outlen); +void asn1_length_to_der(size_t len, uint8_t **in, size_t *inlen); +void asn1_data_to_der(const uint8_t *data, size_t datalen, uint8_t **out, size_t *outlen); + +int asn1_tag_from_der(int tag, const uint8_t **in, size_t *inlen); +int asn1_length_from_der(size_t *len, const uint8_t **in, size_t *inlen); +int asn1_data_from_der(const uint8_t **data, size_t datalen, const uint8_t **in, size_t *inlen); + + +const char *asn1_object_identifier_name(int oid); +const char *asn1_object_identifier_description(int oid); +int asn1_object_identifier_from_name(int *oid, const char *name); + +int asn1_utf8_string_check(const char *a, size_t alen); +int asn1_printable_string_check(const char *a, size_t alen); +int asn1_ia5_string_check(const char *a, size_t alen); + +int asn1_header_to_der(int tag, size_t len, uint8_t **out, size_t *outlen); +int asn1_type_to_der(int tag, const uint8_t *data, size_t datalen, uint8_t **out, size_t *outlen); +int asn1_type_from_der(int tag, const uint8_t **data, size_t *datalen, const uint8_t **in, size_t *inlen); + +int asn1_type_copy_from_der(int tag, size_t maxlen, uint8_t *data, size_t *datalen, const uint8_t **in, size_t *inlen); +#define asn1_sequence_copy_from_der(maxl,d,dl,i,il) asn1_type_copy_from_der(ASN1_TAG_SEQUENCE,maxl,d,dl,i,il) +// FIXME: 调整一下参数位置,maxl放在dl前面 + +int asn1_any_tag_from_der(int *tag, const uint8_t **in, size_t *inlen); +int asn1_any_type_from_der(int *tag, const uint8_t **data, size_t *datalen, const uint8_t **in, size_t *inlen); + +int asn1_any_from_der(const uint8_t **tlv, size_t *tlvlen, const uint8_t **in, size_t *inlen); + +int asn1_boolean_to_der_ex(int tag, int val, uint8_t **out, size_t *outlen); +int asn1_integer_to_der_ex(int tag, const uint8_t *a, size_t alen, uint8_t **out, size_t *outlen); +int asn1_int_to_der_ex(int tag, int a, uint8_t **out, size_t *outlen); +int asn1_bit_string_to_der_ex(int tag, const uint8_t *bits, size_t nbits, uint8_t **out, size_t *outlen); +int asn1_bits_to_der_ex(int tag, int bits, uint8_t **out, size_t *outlen); +int asn1_null_to_der(uint8_t **out, size_t *outlen); +int asn1_object_identifier_to_der_ex(int tag, int oid, const uint32_t *nodes, size_t nodes_count, uint8_t **out, size_t *outlen); +int asn1_utf8_string_to_der_ex(int tag, const char *a, uint8_t **out, size_t *outlen); +int asn1_printable_string_to_der_ex(int tag, const char *a, uint8_t **out, size_t *outlen); +int asn1_ia5_string_to_der_ex(int tag, const char *a, uint8_t **out, size_t *outlen); +int asn1_utc_time_to_der_ex(int tag, time_t a, uint8_t **out, size_t *outlen); +int asn1_generalized_time_to_der_ex(int tag, time_t a, uint8_t **out, size_t *outlen); + +int asn1_boolean_from_der_ex(int tag, int *val, const uint8_t **in, size_t *inlen); +int asn1_integer_from_der_ex(int tag, const uint8_t **a, size_t *alen, const uint8_t **in, size_t *inlen); +int asn1_int_from_der_ex(int tag, int *a, const uint8_t **in, size_t *inlen); +int asn1_bit_string_from_der_ex(int tag, const uint8_t **bits, size_t *nbits, const uint8_t **in, size_t *inlen); +int asn1_bits_from_der_ex(int tag, int *bits, const uint8_t **in, size_t *inlen); +int asn1_octet_string_from_der_ex(int tag, const uint8_t **a, size_t *alen, const uint8_t **in, size_t *inlen); +int asn1_null_from_der(const uint8_t **in, size_t *inlen); +int asn1_object_identifier_from_der_ex(int tag, int *oid, uint32_t *nodes, size_t *nodes_count, const uint8_t **in, size_t *inlen); +int asn1_utf8_string_from_der_ex(int tag, const char **a, size_t *alen, const uint8_t **in, size_t *inlen); +int asn1_printable_string_from_der_ex(int tag, const char **a, size_t *alen, const uint8_t **in, size_t *inlen); +int asn1_ia5_string_from_der_ex(int tag, const char **a, size_t *alen, const uint8_t **in, size_t *inlen); +int asn1_utc_time_from_der_ex(int tag, time_t *t, const uint8_t **in, size_t *inlen); +int asn1_generalized_time_from_der_ex(int tag, time_t *t, const uint8_t **in, size_t *inlen); + + + +#define asn1_boolean_to_der(a,d,dl) asn1_boolean_to_der_ex(ASN1_TAG_BOOLEAN,a,d,dl) +#define asn1_integer_to_der(a,al,d,dl) asn1_integer_to_der_ex(ASN1_TAG_INTEGER,a,al,d,dl) +#define asn1_int_to_der(a,d,dl) asn1_int_to_der_ex(ASN1_TAG_INTEGER,a,d,dl) +#define asn1_bit_string_to_der(a,al,d,dl) asn1_bit_string_to_der_ex(ASN1_TAG_BIT_STRING,a,al,d,dl) +#define asn1_bits_to_der(a,d,dl) asn1_bits_to_der_ex(ASN1_TAG_BIT_STRING,a,d,dl) +#define asn1_octet_string_to_der(a,al,d,dl) asn1_type_to_der(ASN1_TAG_OCTET_STRING,a,al,d,dl) +#define asn1_object_identifier_to_der(oid,a,al,d,dl) asn1_object_identifier_to_der_ex(ASN1_TAG_OBJECT_IDENTIFIER,oid,a,al,d,dl) +#define asn1_utf8_string_to_der(a,d,dl) asn1_utf8_string_to_der_ex(ASN1_TAG_UTF8String,a,d,dl) +#define asn1_printable_string_to_der(a,d,dl) asn1_printable_string_to_der_ex(ASN1_TAG_PrintableString,a,d,dl) +#define asn1_ia5_string_to_der(a,d,dl) asn1_ia5_string_to_der_ex(ASN1_TAG_IA5String,a,d,dl) +#define asn1_utc_time_to_der(a,d,dl) asn1_utc_time_to_der_ex(ASN1_TAG_UTCTime,a,d,dl) +#define asn1_generalized_time_to_der(a,d,dl) asn1_generalized_time_to_der_ex(ASN1_TAG_GeneralizedTime,a,d,dl) +#define asn1_sequence_header_to_der(al,d,dl) asn1_header_to_der(ASN1_TAG_SEQUENCE,al,d,dl) +#define asn1_set_header_to_der(al,d,dl) asn1_header_to_der(ASN1_TAG_SET,al,d,dl) +#define asn1_explicit_header_to_der(i,al,d,dl) asn1_header_to_der(ASN1_TAG_EXPLICIT(i),al,d,dl) +#define asn1_sequence_to_der(a,al,d,dl) asn1_type_to_der(ASN1_TAG_SEQUENCE,a,al,d,dl) +#define asn1_set_to_der(a,al,d,dl) asn1_type_to_der(ASN1_TAG_SET,a,al,d,dl) +#define asn1_explicit_to_der(i,a,al,d,dl) asn1_type_to_der(ASN1_TAG_EXPLICIT(i),a,al,d,dl) + +#define asn1_boolean_from_der(a,d,dl) asn1_boolean_from_der_ex(ASN1_TAG_BOOLEAN,a,d,dl) +#define asn1_integer_from_der(a,al,d,dl) asn1_integer_from_der_ex(ASN1_TAG_INTEGER,a,al,d,dl) +#define asn1_int_from_der(a,d,dl) asn1_int_from_der_ex(ASN1_TAG_INTEGER,a,d,dl) +#define asn1_bit_string_from_der(a,al,d,dl) asn1_bit_string_from_der_ex(ASN1_TAG_BIT_STRING,a,al,d,dl) +#define asn1_bits_from_der(a,d,dl) asn1_bits_from_der_ex(ASN1_TAG_BIT_STRING,a,d,dl) +#define asn1_octet_string_from_der(a,al,d,dl) asn1_type_from_der(ASN1_TAG_OCTET_STRING,a,al,d,dl) +#define asn1_object_identifier_from_der(oid,a,al,d,dl) asn1_object_identifier_from_der_ex(ASN1_TAG_OBJECT_IDENTIFIER,oid,a,al,d,dl) +#define asn1_utf8_string_from_der(a,al,d,dl) asn1_utf8_string_from_der_ex(ASN1_TAG_UTF8String,a,al,d,dl) +#define asn1_printable_string_from_der(a,al,d,dl) asn1_printable_string_from_der_ex(ASN1_TAG_PrintableString,a,al,d,dl) +#define asn1_ia5_string_from_der(a,al,d,dl) asn1_ia5_string_from_der_ex(ASN1_TAG_IA5String,a,al,d,dl) +#define asn1_utc_time_from_der(a,d,dl) asn1_utc_time_from_der_ex(ASN1_TAG_UTCTime,a,d,dl) +#define asn1_generalized_time_from_der(a,d,dl) asn1_generalized_time_from_der_ex(ASN1_TAG_GeneralizedTime,a,d,dl) +#define asn1_sequence_from_der(a,al,d,dl) asn1_type_from_der(ASN1_TAG_SEQUENCE,a,al,d,dl) +#define asn1_set_from_der(a,al,d,dl) asn1_type_from_der(ASN1_TAG_SET,a,al,d,dl) +#define asn1_implicit_from_der(i,a,al,d,dl) asn1_type_from_der(ASN1_TAG_EXPLICIT(i),a,al,d,dl) +#define asn1_explicit_from_der(i,a,al,d,dl) asn1_type_from_der(ASN1_TAG_EXPLICIT(i),a,al,d,dl) + +#define asn1_implicit_boolean_to_der(i,a,d,dl) asn1_boolean_to_der_ex(ASN1_TAG_IMPLICIT(i),a,d,dl) +#define asn1_implicit_integer_to_der(i,a,al,d,dl) asn1_integer_to_der_ex(ASN1_TAG_IMPLICIT(i),a,al,d,dl) +#define asn1_implicit_int_to_der(i,a,d,dl) asn1_int_to_der_ex(ASN1_TAG_IMPLICIT(i),a,d,dl) +#define asn1_implicit_bit_string_to_der(i,a,al,d,dl) asn1_bit_string_to_der_ex(ASN1_TAG_IMPLICIT(i),a,al,d,dl) +#define asn1_implicit_bits_to_der(i,a,d,dl) asn1_bits_to_der_ex(ASN1_TAG_IMPLICIT(i),a,d,dl) +#define asn1_implicit_octet_string_to_der(i,a,al,d,dl) asn1_type_to_der(ASN1_TAG_IMPLICIT(i),a,al,d,dl) +#define asn1_implicit_object_identifier_to_der(i,oid,a,al,d,dl) asn1_object_identifier_to_der_ex(ASN1_TAG_IMPLICIT(i),oid,a,al,d,dl) +#define asn1_implicit_utf8_string_to_der(i,a,d,dl) asn1_utf8_string_to_der_ex(ASN1_TAG_IMPLICIT(i),a,d,dl) +#define asn1_implicit_printable_string_to_der(i,a,d,dl) asn1_printable_string_to_der_ex(ASN1_TAG_IMPLICIT(i),a,d,dl) +#define asn1_implicit_ia5_string_to_der(i,a,d,dl) asn1_ia5_string_to_der_ex(ASN1_TAG_IMPLICIT(i),a,d,dl) +#define asn1_implicit_utc_time_to_der(i,a,d,dl) asn1_utc_time_to_der_ex(ASN1_TAG_IMPLICIT(i),a,d,dl) +#define asn1_implicit_generalized_time_to_der(i,a,d,dl) asn1_generalized_time_to_der_ex(ASN1_TAG_IMPLICIT(i),a,d,dl) +#define asn1_implicit_sequence_header_to_der(i,al,d,dl) asn1_header_to_der(ASN1_TAG_EXPLICIT(i),al,d,dl) +#define asn1_implicit_set_header_to_der(i,al,d,dl) asn1_header_to_der(ASN1_TAG_EXPLICIT(i),al,d,dl) +#define asn1_implicit_sequence_to_der(i,a,al,d,dl) asn1_type_to_der(ASN1_TAG_EXPLICIT(i),a,al,d,dl) +#define asn1_implicit_set_to_der(i,a,al,d,dl) asn1_type_to_der(ASN1_TAG_EXPLICIT(i),a,al,d,dl) + +#define asn1_implicit_boolean_from_der(i,a,d,dl) asn1_boolean_from_der_ex(ASN1_TAG_IMPLICIT(i),a,d,dl) +#define asn1_implicit_integer_from_der(i,a,al,d,dl) asn1_integer_from_der_ex(ASN1_TAG_IMPLICIT(i),a,al,d,dl) +#define asn1_implicit_int_from_der(i,a,d,dl) asn1_int_from_der_ex(ASN1_TAG_IMPLICIT(i),a,d,dl) +#define asn1_implicit_bit_string_from_der(i,a,al,d,dl) asn1_bit_string_from_der_ex(ASN1_TAG_IMPLICIT(i),a,al,d,dl) +#define asn1_implicit_bits_from_der(i,a,d,dl) asn1_bits_from_der_ex(ASN1_TAG_IMPLICIT(i),a,d,dl) +#define asn1_implicit_octet_string_from_der(i,a,al,d,dl) asn1_type_from_der(ASN1_TAG_IMPLICIT(i),a,al,d,dl) +#define asn1_implicit_object_identifier_from_der(i,oid,a,al,d,dl) asn1_object_identifier_from_der_ex(ASN1_TAG_IMPLICIT(i),oid,a,al,d,dl) +#define asn1_implicit_utf8_string_from_der(i,a,d,dl) asn1_utf8_string_from_der_ex(ASN1_TAG_IMPLICIT(i),a,d,dl) +#define asn1_implicit_printable_string_from_der(i,a,d,dl) asn1_printable_string_from_der_ex(ASN1_TAG_IMPLICIT(i),a,d,dl) +#define asn1_implicit_ia5_string_from_der(i,a,d,dl) asn1_ia5_string_from_der_ex(ASN1_TAG_IMPLICIT(i),a,d,dl) +#define asn1_implicit_utc_time_from_der(i,a,d,dl) asn1_utc_time_from_der_ex(ASN1_TAG_IMPLICIT(i),a,d,dl) +#define asn1_implicit_generalized_time_from_der(i,a,d,dl) asn1_generalized_time_from_der_ex(ASN1_TAG_IMPLICIT(i),a,d,dl) +#define asn1_implicit_sequence_from_der(i,a,al,d,dl) asn1_type_from_der(ASN1_TAG_EXPLICIT(i),a,al,d,dl) +#define asn1_implicit_set_from_der(i,a,al,d,dl) asn1_type_from_der(ASN1_TAG_EXPLICIT(i),a,al,d,dl) + + +int asn1_cstring_to_der(int tag, const char *a, uint8_t **out, size_t *outlen); +int asn1_cstring_from_der(int tag, const char **a, size_t *alen, const uint8_t **in, size_t *inlen); + + + + +typedef struct { + size_t datalen; + uint8_t data[1]; +} ASN1_SEQUENCE_OF; + +int asn1_sequence_of_get_next_item(const ASN1_SEQUENCE_OF *a, const uint8_t **next, const uint8_t **data, size_t *datalen); +int asn1_sequence_of_get_count(const ASN1_SEQUENCE_OF *a, size_t *count); + + + +#if __cplusplus +} +#endif +#endif diff --git a/include/gmssl/base64.h b/include/gmssl/base64.h new file mode 100644 index 00000000..ae94ef93 --- /dev/null +++ b/include/gmssl/base64.h @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2014 - 2021 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + + +#ifndef GMSSL_BASE64_H +#define GMSSL_BASE64_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + /* number saved in a partial encode/decode */ + int num; + /* + * The length is either the output line length (in input bytes) or the + * shortest input line length that is ok. Once decoding begins, the + * length is adjusted up each time a longer line is decoded + */ + int length; + /* data to encode */ + unsigned char enc_data[80]; + /* number read on current line */ + int line_num; + int expect_nl; +} BASE64_CTX; + +# define BASE64_ENCODE_LENGTH(l) (((l+2)/3*4)+(l/48+1)*2+80) +# define BASE64_DECODE_LENGTH(l) ((l+3)/4*3+80) + + +void base64_encode_init(BASE64_CTX *ctx); +int base64_encode_update(BASE64_CTX *ctx, const uint8_t *in, int inlen, uint8_t *out, int *outlen); +void base64_encode_finish(BASE64_CTX *ctx, uint8_t *out, int *outlen); + +void base64_decode_init(BASE64_CTX *ctx); +int base64_decode_update(BASE64_CTX *ctx, const uint8_t *in, int inlen, uint8_t *out, int *outlen); +int base64_decode_finish(BASE64_CTX *ctx, uint8_t *out, int *outlen); + + +int base64_encode_block(unsigned char *t, const unsigned char *f, int dlen); +int base64_decode_block(unsigned char *t, const unsigned char *f, int n); + + +#ifdef __cplusplus +} +#endif +#endif diff --git a/include/gmssl/block_cipher.h b/include/gmssl/block_cipher.h new file mode 100644 index 00000000..d47c7bc0 --- /dev/null +++ b/include/gmssl/block_cipher.h @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2014 - 2021 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + + + +#ifndef GMSSL_BLOCK_CIPHER_H +#define GMSSL_BLOCK_CIPHER_H + + +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct BLOCK_CIPHER BLOCK_CIPHER; +typedef struct BLOCK_CIPHER_KEY BLOCK_CIPHER_KEY; + +struct BLOCK_CIPHER_KEY { + union { + SM4_KEY sm4_key; + AES_KEY aes_key; + } u; + const BLOCK_CIPHER *cipher; +}; + +typedef int (*block_cipher_set_encrypt_key_func)(BLOCK_CIPHER_KEY *key, const uint8_t *user_key, size_t keylen); +typedef int (*block_cipher_set_decrypt_key_func)(BLOCK_CIPHER_KEY *key, const uint8_t *user_key, size_t keylen); +typedef void (*block_cipher_encrypt_func)(const BLOCK_CIPHER_KEY *key, const uint8_t *in, uint8_t *out); +typedef void (*block_cipher_decrypt_func)(const BLOCK_CIPHER_KEY *key, const uint8_t *in, uint8_t *out); + +struct BLOCK_CIPHER { + int oid; + size_t key_min_size; + size_t key_max_size; + size_t block_size; + block_cipher_set_encrypt_key_func set_encrypt_key; + block_cipher_set_decrypt_key_func set_decrypt_key; + block_cipher_encrypt_func encrypt; + block_cipher_decrypt_func decrypt; +}; + +int block_cipher_set_encrypt_key(BLOCK_CIPHER_KEY *key, const uint8_t *user_key, size_t keylen); +int block_cipher_set_decrypt_key(BLOCK_CIPHER_KEY *key, const uint8_t *user_key, size_t keylen); +void block_cipher_encrypt(const BLOCK_CIPHER_KEY *key, const uint8_t *in, uint8_t *out); +void block_cipher_decrypt(const BLOCK_CIPHER_KEY *key, const uint8_t *in, uint8_t *out); + +const BLOCK_CIPHER *BLOCK_CIPHER_aes(void); +const BLOCK_CIPHER *BLOCK_CIPHER_sm4(void); +const BLOCK_CIPHER *block_cipher_from_name(const char *name); + +void block_cipher_ecb_encrypt(const BLOCK_CIPHER_KEY *key, const uint8_t *in, size_t nblocks, uint8_t *out); +void block_cipher_ecb_decrypt(const BLOCK_CIPHER_KEY *key, const uint8_t *in, size_t nblocks, uint8_t *out); +void block_cipher_cbc_encrypt(const BLOCK_CIPHER_KEY *key, const uint8_t *iv, + const uint8_t *in, size_t nblocks, uint8_t *out); +void block_cipher_cbc_decrypt(const BLOCK_CIPHER_KEY *key, const uint8_t *iv, + const uint8_t *in, size_t nblocks, uint8_t *out); +void block_cipher_ctr_encrypt(const BLOCK_CIPHER_KEY *key, uint8_t *counter, + const uint8_t *in, size_t nblocks, uint8_t *out); + + + +#ifdef __cplusplus +} +#endif +#endif diff --git a/include/gmssl/chacha20.h b/include/gmssl/chacha20.h new file mode 100644 index 00000000..a8a04250 --- /dev/null +++ b/include/gmssl/chacha20.h @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2014 - 2021 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + +/* RFC 8439 "ChaCha20 and Poly1305 for IETF Protocols" */ + +#ifndef GMSSL_CHACHA20_H +#define GMSSL_CHACHA20_H + +#define CHACHA20_IS_BIG_ENDIAN 0 + +#include +#include + +#include + +#define CHACHA20_KEY_BITS 256 +#define CHACHA20_NONCE_BITS 96 +#define CHACHA20_COUNTER_BITS 32 + +#define CHACHA20_KEY_SIZE (CHACHA20_KEY_BITS/8) +#define CHACHA20_NONCE_SIZE (CHACHA20_NONCE_BITS/8) +#define CHACHA20_COUNTER_SIZE (CHACHA20_COUNTER_BITS/8) + +#define CHACHA20_KEY_WORDS (CHACHA20_KEY_SIZE/sizeof(uint32_t)) +#define CHACHA20_NONCE_WORDS (CHACHA20_NONCE_SIZE/sizeof(uint32_t)) +#define CHACHA20_COUNTER_WORDS (CHACHA20_COUNTER_SIZE/sizeof(uint32_t)) + + +#ifdef __cplusplus +extern "C" { +#endif + + +typedef struct { + uint32_t d[16]; +} CHACHA20_STATE; + + +void chacha20_set_key(CHACHA20_STATE *state, + const uint8_t key[CHACHA20_KEY_SIZE], + const uint8_t nonce[CHACHA20_NONCE_SIZE], + uint32_t counter); + +void chacha20_generate_keystream(CHACHA20_STATE *state, + unsigned int counts, + uint8_t *out); + + +#ifdef __cplusplus +} +#endif +#endif diff --git a/include/gmssl/cipher.h b/include/gmssl/cipher.h new file mode 100644 index 00000000..9daba8be --- /dev/null +++ b/include/gmssl/cipher.h @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2014 - 2021 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + + + +#ifndef GMSSL_CIPHER_H +#define GMSSL_CIPHER_H + +#ifdef __cplusplus +extern "C" { +#endif + + + + + + +struct cipher_st { + int nid; + size_t block_size; + size_t key_size; + size_t iv_size; + unsigned long flags; + int (*init)(CIPHER_CTX *ctx, const uint8_t *key); + int (*encrypt)(CIPHER_CTX *ctx); +}; + +struct cipher_ctx_st { + CIPHER *cipher; + int is_encrypt; + uint8_t iv[16]; + uint8_t block[16]; +}; + +int cipher_encyrpt_init(CIPHER_CTX *ctx, const CIPHER *cipher, const uint8_t *key, const uint8_t *iv); +int cipher_encrypt_update(CIPHER_CTX *ctx, const uint8_t *in, size_t inlen, uint8_t *out, size_t *outlen); +int cipher_encrypt_finish(CIPHER_CTX *ctx, uint8_t *out, size_t *outlen); + +int cipher_decrypt_init(CIPHER_CTX *ctx, const CIPHER *cipher, const uint8_t *key, const uint8_t *iv); +int cipher_decrypt_update(CIPHER_CTX *ctx, const uint8_t *in, size_t inlen, uint8_t *out, size_t *outlen); +int cipher_decrypt_finish(CIPHER_CTX *ctx, uint8_t *out, size_t *outlen); + +int cipher_init(CIPHER_CTX *ctx, const CIPHER *cipher, const uint8_t *key, const uint8_t *iv, int enc); +int cipher_update(CIPHER_CTX *ctx, const uint8_t *in, size_t inlen, uint8_t *out, size_t *outlen); +int cipher_finish(CIPHER_CTX *ctx, uint8_t *out, size_t *outlen); + + +const CIPHER *CIPHER_sm4_ecb(void); +const CIPHER *CIPHER_sm4_cbc(void); +const CIPHER *CIPHER_sm4_ofb(void); +const CIPHER *CIPHER_sm4_cfb1(void); +const CIPHER *CIPHER_sm4_cfb8(void); +const CIPHER *CIPHER_sm4_cfb128(void); +const CIPHER *CIPHER_sm4_ctr(void); +const CIPHER *CIPHER_sm4_gcm(void); +const CIPHER *CIPHER_zuc(void); +const CIPHER *CIPHER_zuc256(void); + + + +#ifdef __cplusplus +} +#endif +#endif diff --git a/include/gmssl/cmac.h b/include/gmssl/cmac.h new file mode 100644 index 00000000..44ff7f5a --- /dev/null +++ b/include/gmssl/cmac.h @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2014 - 2021 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + +/* NIST SP 800-38B "Recommendation for Block Cipher Modes of Operation: + * The CMAC Mode for Authentication" + */ + +#ifndef GMSSL_CMAC_H +#define GMSSL_CMAC_H + + +#include +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif + + +typedef struct { + const BLOCK_CIPHER *cipher; + BLOCK_CIPHER_KEY cipher_key; + uint8_t k1[16]; + uint8_t k2[16]; + uint8_t temp_block[16]; + uint8_t last_block[16]; + int last_block_nbytes; /* -1 means context not initialised */ +} CMAC_CTX; + +int cmac_init(CMAC_CTX *ctx, const BLOCK_CIPHER *cipher, const uint8_t *key, size_t keylen); +int cmac_update(CMAC_CTX *ctx, const uint8_t *in, size_t inlen); +int cmac_finish(CMAC_CTX *ctx, uint8_t *out, size_t *outlen); +int cmac_finish_and_verify(CMAC_CTX *ctx, const uint8_t *mac, size_t maclen); + + +#ifdef __cplusplus +} +#endif +#endif diff --git a/include/gmssl/cms.h b/include/gmssl/cms.h new file mode 100755 index 00000000..c164660d --- /dev/null +++ b/include/gmssl/cms.h @@ -0,0 +1,276 @@ +/* + * Copyright (c) 2021 - 2021 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + + +/* + + + +ContentInfo ::= SEQUENCE { + contentType OBJECT IDENTIFIER, + content [0] EXPLICIT ANY OPTIONAL +} + + +data 1.2.156.10197.6.1.4.2.1 + + + + + +data ::= OCTET STRING + +SignedData ::= SEQUENCE { + version INTEGER (1), + digestAlgorithms SET OF AlgorithmIdentifier, + contentInfo ContentInfo, + certificates [0] IMPLICIT SET OF Certificate OPTIONAL, + crls [1] IMPLICIT SET OF CertificateRevocationList OPTIONAL, + signerInfos SET OF SignerInfo +} + +SignerInfo ::= SEQUENCE { + version INTEGER (1), + issuerAndSerialNumber IssuerAndSerialNumber, + digestAlgorithm AlgorithmIdentifier, + authenticatedAttributes [0] IMPLICIT SET OF Attribute OPTINOAL, + digestEncryptionAlgorithm AlgorithmIdentifier, + encryptedDigest OCTET STRING, + unauthenticatedAttributes [1] IMPLICIT SET OF Attribute OPTINOAL, +} + +EnvelopedData ::= SEQUENCE { + version INTEGER (1), + recipientInfos SET OF RecipientInfo, + encryptedContentInfo EncryptedContentInfo +} + +EncryptedContentInfo ::= SEQUENCE { + contentType OBJECT IDENTIFIER, + contentEncryptionAlgorithm AlgorithmIdentifier, + encryptedContent [0] IMPLICIT OCTET STRING OPTIONAL, + sharedInfo1 [1] IMPLICIT OCTET STRING OPTIONAL, + sharedInfo2 [2] IMPLICIT OCTET STRING OPTIONAL, +} + +RecipientInfo ::= SEQUENCE { + version INTEGER (1), + issuerAndSerialNumber IssuerAndSerialNumber, + keyEncryptionAlgorithm AlgorithmIdentifier, + encryptedKey OCTET STRING +} + +SignedAndEnvelopedData ::= SEQUENCE { + version INTEGER (1), + recipientInfos SET OF RecipientInfo, + digestAlgorithms SET OF AlgorithmIdentifier, + encryptedContentInfo EncryptedContentInfo, + certificates [0] IMPLICIT SET OF Certificate OPTIONAL, + crls [1] IMPLICIT SET OF CertificateRevocationList OPTIONAL, + signerInfos SET OF SignerInfo +} + +EncryptedData ::= SEQUENCE { + version INTEGER (1), + encryptedContentInfo EncryptedContentInfo +} + +KeyAgreementInfo ::= SEQUENCE { + version INTEGER (1), + tempPublicKeyR SM2PublicKey, + userCertificate Certificate, + userID OCTET STRING +} +*/ + + +#ifndef GMSSL_CMS_H +#define GMSSL_CMS_H + + +#include +#include +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif + + + +enum { + CMS_version = 1, +}; + + + +typedef enum { + CMS_data = 1, + CMS_signed_data = 2, + CMS_enveloped_data = 3, + CMS_signed_and_enveloped_data = 4, + CMS_encrypted_data = 5, + CMS_key_agreement_info = 6, +} CMS_CONTENT_TYPE; + + + + +/* +IssuerAndSerialNumber ::= SEQUENCE { + issuer Name, + serialNumber INTEGER } +*/ +int cms_issuer_and_serial_number_from_certificate(const X509_NAME **issuer, + const uint8_t **serial_number, size_t *serial_number_len, + const X509_CERTIFICATE *cert); +int cms_public_key_from_certificate(const SM2_KEY **pub_key, + const X509_CERTIFICATE *cert); +int cms_issuer_and_serial_number_to_der(const X509_NAME *issuer, + const uint8_t *serial_number, size_t serial_number_len, + uint8_t **out, size_t *outlen); +int cms_issuer_and_serial_number_from_der(X509_NAME *issuer, + const uint8_t **serial_number, size_t *serial_number_len, + const uint8_t **in, size_t *inlen); + + +const char *cms_content_type_name(int type); +int cms_content_type_to_der(int type, uint8_t **out, size_t *outlen); +int cms_content_type_from_der(int *type, const uint8_t **in, size_t *inlen); + + + +int cms_content_info_print(FILE *fp, const uint8_t *a, size_t alen, int format, int indent); + + +int cms_content_info_set_data(uint8_t *content_info, size_t *content_info_len, + const uint8_t *data, size_t datalen); +int cms_content_info_get_data(const uint8_t *content_info, size_t content_info_len, + const uint8_t **data, size_t *datalen); + + + + +int cms_data_print(FILE *fp, const uint8_t *in, size_t inlen, int format, int indent); + + + +int cms_signer_info_to_der(const X509_NAME *issuer, + const uint8_t *serial_number, size_t serial_number_len, int digest_algor, + const uint8_t *authed_attrs, size_t authed_attrs_len, + const uint8_t *enced_digest, size_t enced_digest_len, + const uint8_t *unauthed_attrs, size_t unauthed_attrs_len, + uint8_t **out, size_t *outlen); + +int cms_signer_info_from_der(X509_NAME *issuer, + const uint8_t **serial_number, size_t *serial_number_len, + int *digest_algor, uint32_t *nodes, size_t *nodes_count, + const uint8_t **authed_attrs, size_t *authed_attrs_len, + int *sign_algor, uint32_t *sign_algor_nodes, size_t *sign_algor_nodes_count, + const uint8_t **enced_digest, size_t *enced_digest_len, + const uint8_t **unauthed_attrs, size_t *unauthed_attrs_len, + const uint8_t **in, size_t *inlen); + +int cms_signer_info_print(FILE *fp, const uint8_t *a, size_t alen, int format, int indent); + +int cms_signer_info_sign_to_der(const SM2_KEY *sm2_key, const SM3_CTX *sm3_ctx, + const X509_NAME *issuer, const uint8_t *serial_number, size_t serial_number_len, + const uint8_t *authed_attrs, size_t authed_attrs_len, + const uint8_t *unauthed_attrs, size_t unauthed_attrs_len, + uint8_t **out, size_t *outlen); + +int cms_signer_info_verify_from_der( + const SM2_KEY *sm2_key, const SM3_CTX *sm3_ctx, + X509_NAME *issuer, const uint8_t **serial_number, size_t *serial_number_len, + int *digest_algor, uint32_t *digest_nodes, size_t *digest_algor_nodes_count, + const uint8_t **authed_attrs, size_t *authed_attrs_len, + int *sign_algor, uint32_t *sign_algor_nodes, size_t *sign_algor_nodes_count, + const uint8_t **unauthed_attrs, size_t *unauthed_attrs_len, + const uint8_t **in, size_t *inlen); + +int cms_signed_data_to_der( + const int *digest_algors, const size_t digset_algors_count, + const int content_type, const uint8_t *content, const size_t content_len, + const X509_CERTIFICATE *certs, size_t certs_count, + const uint8_t **crls, const size_t *crls_lens, const size_t crls_count, + const uint8_t **signer_infos, size_t *signer_infos_lens, size_t signer_infos_count, + uint8_t **out, size_t *outlen); + +int cms_signed_data_from_der( + const uint8_t **digest_algors, size_t *digest_algors_len, + int *content_type, const uint8_t **content, size_t *content_len, + const uint8_t **certs, size_t *certs_len, + const uint8_t **crls, size_t *crls_len, + const uint8_t **signer_infos, size_t *signer_infos_len, + const uint8_t **in, size_t *inlen); + +int cms_signed_data_print(FILE *fp, const uint8_t *in, size_t inlen, int format, int indent); + +int cms_signed_data_sign_to_der(const SM2_KEY *sign_keys, const X509_CERTIFICATE *sign_certs, size_t sign_count, + int content_type, const uint8_t *content, size_t content_len, + const uint8_t **crls, size_t *crls_lens, size_t crls_count, + uint8_t **out, size_t *outlen); + +int cms_signed_data_verify_from_der(const uint8_t *signed_data, size_t signed_data_len); + + +int cms_sign(const SM2_KEY *sign_keys, + const X509_CERTIFICATE *sign_certs, size_t sign_count, + int content_type, const uint8_t *content, size_t content_len, + const uint8_t **crls, size_t *crls_lens, size_t crls_count, + uint8_t *content_info, size_t *content_info_len); + + + + +#ifdef __cplusplus +} +#endif +#endif diff --git a/include/gmssl/crl.h b/include/gmssl/crl.h new file mode 100644 index 00000000..0d128277 --- /dev/null +++ b/include/gmssl/crl.h @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2020 - 2021 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + + +#ifndef GMSSL_CRL_H +#define GMSSL_CRL_H + + + +#ifdef __cplusplus +extern "C" { +#endif + + +typedef enum X509_CRLReason { + X509_cr_unspecified = 0, + X509_cr_keyCompromise, + X509_cr_cACompromise, + X509_cr_affiliationChanged, + X509_cr_superseded, + X509_cr_cessationOfOperation, + X509_cr_certificateHold, + X509_cr_7_not_assigned = 7, + X509_cr_removeFromCRL, + X509_cr_privilegeWithdrawn, + X509_cr_aACompromise, +} CRL_REASON; + + + + + + + + + + + +typedef struct { + uint8_t serial_number[20]; + size_t serial_number_len; + time_t revoke_date; + CRL_EXTENSIONS crlEntryExtensions; +} CRL_REVOKED_CERT; + +typedef struct { + int version; // OPTIONAL, if present MUST be v2 + int signature_algor; + X509_NAME issuer; + time_t this_update; + time_t next_update; + uint8_t *revoked_certs; + size_t revoked_certs_count; + X509_EXTENSION crl_exts[32]; + size_t crl_exts_count; + + uint8_t buf[1024]; +} CRL_TBS_CERT_LIST; + +typedef struct { + X509_TBS_CERT_LIST tbs_cert_list; + int signature_algor; + uint8_t signature[128]; + size_t signature_len; +} CRL_CERT_LIST; + + + + + + + + +#ifdef __cplusplus +} +#endif +#endif diff --git a/include/gmssl/des.h b/include/gmssl/des.h new file mode 100644 index 00000000..78647cde --- /dev/null +++ b/include/gmssl/des.h @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2014 - 2021 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + +/* FIPS PUB 46-3 "Data Encryption Standard (DES)" */ + +#ifndef GMSSL_DES_H +#define GMSSL_DES_H + + +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif + + +#define DES_KEY_BITS 56 +#define DES_BLOCK_BITS 64 +#define DES_KEY_SIZE (DES_KEY_BITS/8) +#define DES_BLOCK_SIZE (DES_BLOCK_BITS/8) + +#define DES_RK_BITS 48 +#define DES_RK_SIZE (DES_RK_BITS/8) +#define DES_ROUNDS 16 + + +typedef struct { + uint64_t rk[DES_ROUNDS]; +} DES_KEY; + +void des_set_encrypt_key(DES_KEY *key, const unsigned char user_key[8]); +void des_set_decrypt_key(DES_KEY *key, const unsigned char user_key[8]); +void des_encrypt(DES_KEY *key, const unsigned char in[8], unsigned char out[8]); + + +typedef struct { + DES_KEY K[3]; +} DES_EDE_KEY; + +void des_ede_set_encrypt_key(DES_EDE_KEY *key, const unsigned char user_key[24]); +void des_ede_set_decrypt_key(DES_EDE_KEY *key, const unsigned char user_key[24]); +void des_ede_encrypt(DES_EDE_KEY *key, const unsigned char in[8], unsigned char out[8]); + + +#ifdef __cplusplus +} +#endif +#endif diff --git a/include/gmssl/digest.h b/include/gmssl/digest.h new file mode 100644 index 00000000..7887a63c --- /dev/null +++ b/include/gmssl/digest.h @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2021 - 2021 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + + +#ifndef GMSSL_DIGEST_H +#define GMSSL_DIGEST_H + + +#include +#include +#include +#include +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif + + +typedef struct digest_st DIGEST; +typedef struct digest_ctx_st DIGEST_CTX; + + +#define DIGEST_MAX_SIZE 64 +#define DIGEST_MAX_BLOCK_SIZE (1024/8) + + +struct digest_ctx_st { + const DIGEST *digest; + union { + SM3_CTX sm3_ctx; + MD5_CTX md5_ctx; + SHA1_CTX sha1_ctx; + SHA224_CTX sha224_ctx; + SHA256_CTX sha256_ctx; + SHA384_CTX sha384_ctx; + SHA512_CTX sha512_ctx; + } u; +}; + +struct digest_st { + int nid; + size_t digest_size; + size_t block_size; + size_t ctx_size; + int (*init)(DIGEST_CTX *ctx); + int (*update)(DIGEST_CTX *ctx, const unsigned char *data, size_t datalen); + int (*finish)(DIGEST_CTX *ctx, unsigned char *dgst); +}; + +int digest_nid(const DIGEST *digest); +const char *digest_name(const DIGEST *digest); +size_t digest_size(const DIGEST *digest); +size_t digest_block_size(const DIGEST *digest); + +const DIGEST *DIGEST_sm3(void); +const DIGEST *DIGEST_md5(void); +const DIGEST *DIGEST_sha1(void); +const DIGEST *DIGEST_sha224(void); +const DIGEST *DIGEST_sha256(void); +const DIGEST *DIGEST_sha384(void); +const DIGEST *DIGEST_sha512(void); +const DIGEST *DIGEST_sha512_224(void); +const DIGEST *DIGEST_sha512_256(void); + +const DIGEST *digest_from_name(const char *name); + +int digest_ctx_nid(const DIGEST_CTX *ctx); +const char *digest_ctx_name(const DIGEST_CTX *ctx); +size_t digest_ctx_size(const DIGEST_CTX *ctx); +size_t digest_ctx_block_size(const DIGEST_CTX *ctx); +const DIGEST *digest_ctx_digest(const DIGEST_CTX *ctx); + +int digest_ctx_init(DIGEST_CTX *ctx); +int digest_init(DIGEST_CTX *ctx, const DIGEST *algor); +int digest_update(DIGEST_CTX *ctx, const unsigned char *data, size_t datalen); +int digest_finish(DIGEST_CTX *ctx, unsigned char *dgst, size_t *dgstlen); +void digest_ctx_cleanup(DIGEST_CTX *ctx); + +int digest(const DIGEST *digest, const unsigned char *data, size_t datalen, + unsigned char *dgst, size_t *dgstlen); + +const char *digest_algor_name(int oid); +int digest_algor_to_der(int oid, uint8_t **out, size_t *outlen); +int digest_algor_from_der(int *oid, uint32_t *nodes, size_t *nodes_count, + const uint8_t **in, size_t *inlen); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/include/gmssl/error.h b/include/gmssl/error.h new file mode 100644 index 00000000..f5846a45 --- /dev/null +++ b/include/gmssl/error.h @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2014 - 2021 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + + +#ifndef GMSSL_ERROR_H +#define GMSSL_ERROR_H + + +#include +#include +#include + +#define error_print(fmt, args...) \ + fprintf(stderr, "error: %s %d: %s: " fmt "\n", basename(__FILE__), __LINE__, __FUNCTION__, ##args) + + + +#ifdef __cplusplus +extern "C" { +#endif + +void print_der(const uint8_t *in, size_t inlen); +void print_bytes(const uint8_t *in, size_t inlen); +void print_nodes(const uint32_t *in, size_t inlen); + + +int format_print(FILE *fp, int format, int indent, const char *str, ...); +int format_bytes(FILE *fp, int format, int indent, const char *str, const uint8_t *data, size_t datalen); + +//int tls_trace(int format, int indent, const char *str, ...); + + +#ifdef __cplusplus +} +#endif +#endif diff --git a/include/gmssl/gcm.h b/include/gmssl/gcm.h new file mode 100644 index 00000000..050f259d --- /dev/null +++ b/include/gmssl/gcm.h @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2014 - 2021 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + +#ifndef GMSSL_GCM_H +#define GMSSL_GCM_H + + +#ifdef __cplusplus +extern "C" { +#endif + + + +#define GCM_IV_MIN_SIZE 1 +#define GCM_IV_MAX_SIZE ((uint64_t)(1 << (64-3))) +#define GCM_IV_DEFAULT_BITS 96 +#define GCM_IV_DEFAULT_SIZE 12 + +#define GCM_MIN_AAD_SIZE 0 +#define GCM_MAX_AAD_SIZE ((uint64_t)(1 << (64-3))) + +#define GCM_MIN_PLAINTEXT_SIZE 0 +#define GCM_MAX_PLAINTEXT_SIZE ((((uint64_t)1 << 39) - 256) >> 3) + + + +#define GCM_IS_LITTLE_ENDIAN 1 + + +typedef struct { + __uint128_t H; + __uint128_t X; + size_t aadlen; + size_t cipherlen; + uint8_t block[16]; + unsigned int num; +} GHASH_CTX; + +void ghash_init(GHASH_CTX *ctx, const uint8_t h[16], const uint8_t *aad, size_t aadlen); +void ghash_update(GHASH_CTX *ctx, const uint8_t *c, size_t clen); +void ghash_finish(GHASH_CTX *ctx, uint8_t out[16]); + + +typedef struct { + BLOCK_CIPHER *cipher; + BLOCK_CIPHER_KEY key; + uint8_t counter[16]; + uint8_t enced_iv[16]; + GHASH_CTX ghash_ctx; +} GCM_CTX; + +#ifdef __cplusplus +} +#endif +#endif diff --git a/include/gmssl/hash_drbg.h b/include/gmssl/hash_drbg.h new file mode 100644 index 00000000..81880892 --- /dev/null +++ b/include/gmssl/hash_drbg.h @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2014 - 2021 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + +/* NIST SP800-90A Rev.1 "Recommendation for Random Number Generation + * Using Deterministic Random Bit Generators", 10.1.1 Hash_DRBG */ + +#ifndef GMSSL_HASH_DRBG_H +#define GMSSL_HASH_DRBG_H + + +#include +#include +#include + + +/* seedlen for hash_drgb, table 2 of nist sp 800-90a rev.1 */ +#define HASH_DRBG_SM3_SEED_BITS 440 /* 55 bytes */ +#define HASH_DRBG_SHA1_SEED_BITS 440 +#define HASH_DRBG_SHA224_SEED_BITS 440 +#define HASH_DRBG_SHA512_224_SEED_BITS 440 +#define HASH_DRBG_SHA256_SEED_BITS 440 +#define HASH_DRBG_SHA512_256_SEED_BITS 440 +#define HASH_DRBG_SHA384_SEED_BITS 888 /* 110 bytes */ +#define HASH_DRBG_SHA512_SEED_BITS 888 +#define HASH_DRBG_MAX_SEED_BITS 888 + +#define HASH_DRBG_SM3_SEED_SIZE (HASH_DRBG_SM3_SEED_BITS/8) +#define HASH_DRBG_SHA1_SEED_SIZE (HASH_DRBG_SHA1_SEED_BITS/8) +#define HASH_DRBG_SHA224_SEED_SIZE (HASH_DRBG_SHA224_SEED_BITS/8) +#define HASH_DRBG_SHA512_224_SEED_SIZE (HASH_DRBG_SHA512_224_SEED_BITS/8) +#define HASH_DRBG_SHA256_SEED_SIZE (HASH_DRBG_SHA256_SEED_BITS/8) +#define HASH_DRBG_SHA512_256_SEED_SIZE (HASH_DRBG_SHA512_256_SEED_BITS/8) +#define HASH_DRBG_SHA384_SEED_SIZE (HASH_DRBG_SHA384_SEED_BITS/8) +#define HASH_DRBG_SHA512_SEED_SIZE (HASH_DRBG_SHA512_SEED_BITS/8) +#define HASH_DRBG_MAX_SEED_SIZE (HASH_DRBG_MAX_SEED_BITS/8) + +#define HASH_DRBG_RESEED_INTERVAL ((uint64_t)1 << 48) + +#ifdef __cplusplus +extern "C" { +#endif + + +typedef struct { + const DIGEST *digest; + uint8_t V[HASH_DRBG_MAX_SEED_SIZE]; + uint8_t C[HASH_DRBG_MAX_SEED_SIZE]; + size_t seedlen; + uint64_t reseed_counter; +} HASH_DRBG; + + +int hash_drbg_init(HASH_DRBG *drbg, + const DIGEST *digest, + const uint8_t *entropy, size_t entropy_len, + const uint8_t *nonce, size_t nonce_len, + const uint8_t *personalstr, size_t personalstr_len); + +int hash_drbg_reseed(HASH_DRBG *drbg, + const uint8_t *entropy, size_t entropy_len, + const uint8_t *additional, size_t additional_len); + +int hash_drbg_generate(HASH_DRBG *drbg, + const uint8_t *additional, size_t additional_len, + size_t outlen, uint8_t *out); + +void hash_drbg_cleanup(HASH_DRBG *drbg); + + +#ifdef __cplusplus +} +#endif +#endif diff --git a/include/gmssl/hex.h b/include/gmssl/hex.h new file mode 100644 index 00000000..0011eac4 --- /dev/null +++ b/include/gmssl/hex.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2014 - 2021 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + + +#ifndef GMSSL_HEX_H +#define GMSSL_HEX_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include + +int hex2bin(const char *in, size_t inlen, uint8_t *out); +int OPENSSL_hexchar2int(unsigned char c); +unsigned char *OPENSSL_hexstr2buf(const char *str, size_t *len); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/include/gmssl/hkdf.h b/include/gmssl/hkdf.h new file mode 100644 index 00000000..8c0f2396 --- /dev/null +++ b/include/gmssl/hkdf.h @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2021 - 2021 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ +// RFC 5869 + +#ifndef GMSSL_HKDF_H +#define GMSSL_HKDF_H + +#include +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif + + +int hkdf_extract(const DIGEST *digest, const uint8_t *salt, size_t saltlen, + const uint8_t *ikm, size_t ikmlen, + uint8_t *prk, size_t *prklen); + +int hkdf_expand(const DIGEST *digest, const uint8_t *prk, size_t prklen, + const uint8_t *info, size_t infolen, + size_t L, uint8_t *okm); + + + +#ifdef __cplusplus +} +#endif +#endif diff --git a/include/gmssl/hmac.h b/include/gmssl/hmac.h new file mode 100644 index 00000000..40268cb5 --- /dev/null +++ b/include/gmssl/hmac.h @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2014 - 2021 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + +#ifndef GMSSL_HMAC_H +#define GMSSL_HMAC_H + +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif + +#define HMAC_MAX_SIZE (DIGEST_MAX_SIZE) + + +typedef struct hmac_ctx_st { + const DIGEST *digest; + DIGEST_CTX digest_ctx; + DIGEST_CTX i_ctx; + DIGEST_CTX o_ctx; +} HMAC_CTX; + + +size_t hmac_size(const HMAC_CTX *ctx); + +int hmac_init(HMAC_CTX *ctx, const DIGEST *digest, const unsigned char *key, size_t keylen); +int hmac_update(HMAC_CTX *ctx, const unsigned char *data, size_t datalen); +int hmac_finish(HMAC_CTX *ctx, unsigned char *mac, size_t *maclen); +int hmac_reset(HMAC_CTX *ctx); + +int hmac(const DIGEST *md, const unsigned char *key, size_t keylen, + const unsigned char *data, size_t dlen, + unsigned char *mac, size_t *maclen); + + +#ifdef __cplusplus +} +#endif +#endif diff --git a/include/gmssl/md5.h b/include/gmssl/md5.h new file mode 100755 index 00000000..bb343564 --- /dev/null +++ b/include/gmssl/md5.h @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2014 - 2021 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + + +#ifndef GMSSL_MD5_H +#define GMSSL_MD5_H + +#define MD5_IS_BIG_ENDIAN 0 + +#define MD5_DIGEST_SIZE 16 +#define MD5_BLOCK_SIZE 64 + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +typedef struct { + uint32_t state[4]; + uint64_t nblocks; /* num of processed blocks */ + unsigned char block[64]; /* buffer */ + int num; /* buffered bytes in |block| */ +} MD5_CTX; + + +void md5_init(MD5_CTX *ctx); +void md5_update(MD5_CTX *ctx, const uint8_t* data, size_t datalen); +void md5_finish(MD5_CTX *ctx, uint8_t dgst[MD5_DIGEST_SIZE]); +void md5_compress(uint32_t state[4], const uint8_t block[MD5_BLOCK_SIZE]); +void md5_digest(const uint8_t *data, size_t datalen, uint8_t dgst[MD5_DIGEST_SIZE]); + + +#ifdef __cplusplus +} +#endif +#endif diff --git a/include/gmssl/oid.h b/include/gmssl/oid.h new file mode 100644 index 00000000..a6d9a44e --- /dev/null +++ b/include/gmssl/oid.h @@ -0,0 +1,313 @@ +/* + * Copyright (c) 2014 - 2021 The GmSSL Project. All rights reserved. + * +OCSPSigning * 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + + +#ifndef GMSSL_OID_H +#define GMSSL_OID_H + +#ifdef __cplusplus +extern "C" { +#endif + + +enum { + OID_undef = 0, + //OID_aes, + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + // ShangMi schemes in GM/T 0006-2012 + OID_sm1, + OID_ssf33, + OID_sm4, + OID_zuc, + OID_sm2, + OID_sm2sign, + OID_sm2keyagreement, + OID_sm2encrypt, + OID_sm9, + OID_sm9sign, + OID_sm9keyagreement, + OID_sm9encrypt, + OID_sm3, + OID_sm3_keyless, + OID_hmac_sm3, + OID_sm2sign_with_sm3, + OID_rsasign_with_sm3, + OID_x9_62_ecPublicKey, // start of X9.62 curves + OID_prime192v1, + OID_prime192v2, + OID_prime192v3, + OID_prime239v1, + OID_prime239v2, + OID_prime239v3, + OID_prime256v1, + OID_secp256k1, // start of SECG curves (secure curves only!) + OID_secp192k1, + OID_secp224k1, + OID_secp224r1, + OID_secp384r1, + OID_secp521r1, + OID_at_commonName, // start of X.509 Attributes + OID_at_surname, + OID_at_serialNumber, + OID_at_countryName, + OID_at_localityName, + OID_at_stateOrProvinceName, + OID_at_streetAddress, + OID_at_organizationName, + OID_at_organizationalUnitName, + OID_at_title, + OID_at_description, + OID_at_searchGuide, + OID_at_businessCategory, + OID_at_postalAddress, + OID_at_postalCode, + OID_at_postOfficeBox, + OID_at_physicalDeliveryOfficeName, + OID_at_telephoneNumber, + OID_at_telexNumber, + OID_at_teletexTerminalIdentifier, + OID_at_facsimileTelephoneNumber, + OID_at_x121Address, + OID_at_internationaliSDNNumber, + OID_at_registeredAddress, + OID_at_destinationIndicator, + OID_at_preferredDeliveryMethod, + OID_at_presentationAddress, + OID_at_supportedApplicationContext, + OID_at_member, + OID_at_owner, + OID_at_roleOccupant, + OID_at_seeAlso, + OID_at_userPassword, + OID_at_userCertificate, + OID_at_caCertificate, + OID_at_authorityRevocationList, + OID_at_certificateRevocationList, + OID_at_crossCertificatePair, + OID_at_name, + OID_at_givenName, + OID_at_initials, + OID_at_generationQualifier, + OID_at_x500UniqueIdentifier, + OID_at_dnQualifier, + OID_at_enhancedSearchGuide, + OID_at_protocolInformation, + OID_at_distinguishedName, + OID_at_uniqueMember, + OID_at_houseIdentifier, + OID_at_supportedAlgorithms, + OID_at_deltaRevocationList, + OID_at_dmdName, + OID_at_pseudonym, + OID_at_role, + + /* ext 1 */ OID_ce_authorityKeyIdentifier, + /* ext 2 */ OID_ce_subjectKeyIdentifier, + /* ext 3 */ OID_ce_keyUsage, + /* ext 4 */ OID_ce_certificatePolicies, // start of X.500v3 Certificate Extensions + /* ext 5 */ OID_ce_policyMappings, // start of OID_ce_certificatePolicies, + /* ext 6 */ OID_ce_subjectAltName, + /* ext 7 */ OID_ce_issuerAltName, + /* ext 8 */ OID_ce_subjectDirectoryAttributes, + /* ext 9 */ OID_ce_basicConstraints, + /* ext 10 */ OID_ce_nameConstraints, + /* ext 11 */ OID_ce_policyConstraints, + /* ext 12 */ OID_ce_extKeyUsage, + /* ext 13 */ OID_ce_crlDistributionPoints, + /* ext 14 */ OID_ce_inhibitAnyPolicy, + /* ext 15 */ OID_ce_freshestCRL, + + OID_ce_primaryKeyUsageRestriction, + + + + OID_ce_privateKeyUsagePeriod, + + + + OID_ce_crlNumber, + OID_ce_reasonCode, + OID_ce_instructionCode, + OID_ce_invalidityDate, + OID_ce_deltaCRLIndicator, + OID_ce_issuingDistributionPoint, + OID_ce_certificateIssuer, + + + + + + + + + + + OID_kp_serverAuth, // start of X.509 KeyPropuseID + OID_kp_clientAuth, + OID_kp_codeSigning, + OID_kp_emailProtection, + OID_kp_timeStamping, + OID_kp_OCSPSigning, + + + OID_qt_cps, + OID_qt_unotice, + + OID_MAX, + + OID_md5, + OID_sha1, + OID_sha224, + OID_sha256, + OID_sha384, + OID_sha512, + OID_sha512_224, + OID_sha512_256, + + + OID_pbkdf2, // {pkcs-5 12} + OID_pbes2, // {pkcs-5 13} + OID_hmacWithSHA1, + OID_hmacWithSHA224, + + OID_sm4_ecb, // 1 2 156 10197 1 104 1 + OID_sm4_cbc, // 1 2 156 10197 1 104 2 + +}; + +typedef struct { + int oid; + uint32_t nodes[32]; + int nodes_count; +} ASN1_OBJECT_IDENTIFIER; + + + + +const char *asn1_sm_oid_name(int oid); +const char *asn1_sm_oid_description(int oid); +void asn1_sm_oid_to_octets(int oid, uint8_t *out, size_t *outlen); +int asn1_sm_oid_from_octets(const uint8_t *in, size_t inlen); +int asn1_sm_oid_from_name(const char *name); + +const char *asn1_x9_62_curve_oid_name(int oid); +const char *asn1_x9_62_curve_oid_description(int oid); +void asn1_x9_62_curve_oid_to_octets(int oid, uint8_t *out, size_t *outlen); +int asn1_x9_62_curve_oid_from_octets(const uint8_t *in, size_t inlen); +int asn1_x9_62_curve_oid_from_name(const char *name); + +const char *asn1_secg_curve_oid_name(int oid); +const char *asn1_secg_curve_oid_description(int oid); +void asn1_secg_curve_oid_to_octets(int oid, uint8_t *out, size_t *outlen); +int asn1_secg_curve_oid_from_octets(const uint8_t *in, size_t inlen); +int asn1_secg_curve_oid_from_name(const char *name); + +const char *asn1_x509_oid_name(int oid); +const char *asn1_x509_oid_description(int oid); +void asn1_x509_oid_to_octets(int oid, uint8_t *out, size_t *outlen); +int asn1_x509_oid_from_octets(const uint8_t *in, size_t inlen); +int asn1_x509_oid_from_name(const char *name); + + +const char *asn1_x509_kp_oid_name(int oid); +const char *asn1_x509_kp_oid_description(int oid); +void asn1_x509_kp_oid_to_octets(int oid, uint8_t *out, size_t *outlen); +int asn1_x509_kp_oid_from_octets(const uint8_t *in, size_t inlen); +int asn1_x509_kp_oid_from_name(const char *name); + + +void asn1_oid_to_octets(int oid, uint8_t *out, size_t *outlen); +int asn1_oid_from_octets(const uint8_t *in, size_t inlen); +int asn1_oid_nodes_to_octets(const uint32_t *nodes, size_t nodes_count, uint8_t *out, size_t *outlen); +int asn1_oid_nodes_from_octets(uint32_t *nodes, size_t *nodes_count, const uint8_t *in, size_t inlen); + +int test_asn1_oid(void); +int test_asn1_object_identifier(void); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/include/gmssl/pbkdf2.h b/include/gmssl/pbkdf2.h new file mode 100644 index 00000000..70b07804 --- /dev/null +++ b/include/gmssl/pbkdf2.h @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2014 - 2021 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + +#ifndef GMSSL_PBKDF2_H +#define GMSSL_PBKDF2_H + + +#include +#include +#include +#include + + +#define PBKDF2_MIN_ITER 10000 +#define PBKDF2_MIN_SALT_SIZE 64 +#define PBKDF2_DEFAULT_SALT_SIZE 8 + + +#ifdef __cplusplus +extern "C" { +#endif + + +int pbkdf2_genkey(const DIGEST *digest, + const char *pass, size_t passlen, + const uint8_t *salt, size_t saltlen, + unsigned int count, size_t outlen, uint8_t *out); + + + +#ifdef __cplusplus +} +#endif +#endif diff --git a/include/gmssl/pem.h b/include/gmssl/pem.h new file mode 100644 index 00000000..4506ccc1 --- /dev/null +++ b/include/gmssl/pem.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2014 - 2021 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + +#ifndef GMSSL_PEM_H +#define GMSSL_PEM_H + + +#include +#include +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif + + +int pem_read(FILE *fp, const char *name, uint8_t *data, size_t *datalen); +int pem_write(FILE *fp, const char *name, const uint8_t *data, size_t datalen); + + + +#ifdef __cplusplus +} +#endif +#endif diff --git a/include/gmssl/pkcs8.h b/include/gmssl/pkcs8.h new file mode 100644 index 00000000..a95fbe53 --- /dev/null +++ b/include/gmssl/pkcs8.h @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2021 - 2021 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + +#ifndef GMSSL_PKCS8_H +#define GMSSL_PKCS8_H + + +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// EncryptedPrivateKeyInfo +int sm2_enced_private_key_info_to_der(const SM2_KEY *key, const char *pass, uint8_t **out, size_t *outlen); +int sm2_enced_private_key_info_from_der(SM2_KEY *key, const uint8_t **attrs, size_t *attrslen, const char *pass, const uint8_t **in, size_t *inlen); +int sm2_enced_private_key_info_to_pem(const SM2_KEY *key, const char *pass, FILE *fp); +int sm2_enced_private_key_info_from_pem(SM2_KEY *key, const char *pass, FILE *fp); + +/* + prf must be OID_hmac_sm3 + cipher must be OID_sm4_cbc +*/ + +int pbkdf2_params_to_der( + const uint8_t *salt, size_t saltlen, + int iter, + int keylen, // optional, -1 + int prf, + uint8_t **out, size_t *outlen); + +int pbkdf2_params_from_der( + const uint8_t **salt, size_t *saltlen, + int *iter, + int *keylen, // -1, optional + int *prf, + const uint8_t **in, size_t *inlen); + +int pbkdf2_algor_to_der( + const uint8_t *salt, size_t saltlen, + int iter, + int keylen, + int prf, + uint8_t **out, size_t *outlen); + +int pbkdf2_algor_from_der( + const uint8_t **salt, size_t *saltlen, + int *iter, + int *keylen, + int *prf, + const uint8_t **in, size_t *inlen); + +int pbes2_enc_algor_to_der( + int cipher, + const uint8_t *iv, size_t ivlen, + uint8_t **out, size_t *outlen); + +int pbes2_enc_algor_from_der( + int *cipher, + const uint8_t **iv, size_t *ivlen, + const uint8_t **in, size_t *inlen); + +int pbes2_params_to_der( + const uint8_t *salt, size_t saltlen, + int iter, + int prf, + int cipher, + const uint8_t *iv, size_t ivlen, + uint8_t **out, size_t *outlen); + +int pbes2_params_from_der( + const uint8_t **salt, size_t *saltlen, + int *iter, + int *prf, + int *cipher, + const uint8_t **iv, size_t *ivlen, + const uint8_t **in, size_t *inlen); + +int pbes2_algor_to_der( + const uint8_t *salt, size_t saltlen, + int iter, + int prf, + int cipher, + const uint8_t *iv, size_t ivlen, + uint8_t **out, size_t *outlen); + +int pbes2_algor_from_der( + const uint8_t **salt, size_t *saltlen, + int *iter, + int *prf, + int *cipher, + const uint8_t **iv, size_t *ivlen, + const uint8_t **in, size_t *inlen); + +int pkcs8_enced_private_key_info_to_der( + const uint8_t *salt, size_t saltlen, + int iter, + int prf, + int cipher, + const uint8_t *iv, size_t ivlen, + const uint8_t *enced, size_t encedlen, + uint8_t **out, size_t *outlen); + +int pkcs8_enced_private_key_info_from_der( + const uint8_t **salt, size_t *saltlen, + int *iter, + int *prf, + int *cipher, + const uint8_t **iv, size_t *ivlen, + const uint8_t **enced, size_t *encedlen, + const uint8_t **in, size_t *inlen); + + + +#ifdef __cplusplus +} +#endif +#endif diff --git a/include/gmssl/rand.h b/include/gmssl/rand.h new file mode 100644 index 00000000..d88c2ecf --- /dev/null +++ b/include/gmssl/rand.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2014 - 2021 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + +#ifndef GMSSL_RAND_H +#define GMSSL_RAND_H + + +#include +#include + + +int rand_bytes(uint8_t *buf, size_t len); + + +#ifdef __cplusplus +} +#endif +#endif diff --git a/include/gmssl/rc4.h b/include/gmssl/rc4.h new file mode 100644 index 00000000..e6a23817 --- /dev/null +++ b/include/gmssl/rc4.h @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2014 - 2021 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + + +#ifndef GMSSL_RC4_H +#define GMSSL_RC4_H + + +#define RC4_MIN_KEY_BITS 40 +#define RC4_STATE_NUM_WORDS 256 + +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +typedef struct { + unsigned char d[256]; +} RC4_STATE; + +void rc4_set_key(RC4_STATE *state, const uint8_t *key, size_t keylen); +void rc4_generate_keystream(RC4_STATE *state, size_t outlen, uint8_t *out); + + +#ifdef __cplusplus +} +#endif +#endif diff --git a/include/gmssl/sha1.h b/include/gmssl/sha1.h new file mode 100755 index 00000000..b63d68ed --- /dev/null +++ b/include/gmssl/sha1.h @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2014 - 2021 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + + +#ifndef GMSSL_SHA1_H +#define GMSSL_SHA1_H + +#define SHA1_IS_BIG_ENDIAN 1 + +#define SHA1_DIGEST_LENGTH 20 +#define SHA1_BLOCK_SIZE 64 +#define SHA1_STATE_WORDS (SHA1_DIGEST_LENGTH/sizeof(uint32_t)) + +#include +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif + + +typedef struct { + uint32_t state[SHA1_STATE_WORDS]; + uint64_t nblocks; /* num of processed blocks */ + uint8_t block[SHA1_BLOCK_SIZE]; /* buffer */ + int num; /* buffered bytes in |block| */ +} SHA1_CTX; + +void sha1_init(SHA1_CTX *ctx); +void sha1_update(SHA1_CTX *ctx, const uint8_t *data, size_t datalen); +void sha1_finish(SHA1_CTX *ctx, uint8_t dgst[SHA1_DIGEST_LENGTH]); +void sha1_compress(uint32_t state[SHA1_STATE_WORDS], const uint8_t block[SHA1_BLOCK_SIZE]); +void sha1_digest(const uint8_t *data, size_t datalen, uint8_t dgst[SHA1_DIGEST_LENGTH]); + + +#ifdef __cplusplus +} +#endif +#endif diff --git a/include/gmssl/sha2.h b/include/gmssl/sha2.h new file mode 100755 index 00000000..6f7bde92 --- /dev/null +++ b/include/gmssl/sha2.h @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2014 - 2021 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + + +#ifndef GMSSL_SHA2_H +#define GMSSL_SHA2_H + +#define SHA2_IS_BIG_ENDIAN 1 + +#define SHA224_DIGEST_SIZE 28 +#define SHA256_DIGEST_SIZE 32 +#define SHA384_DIGEST_SIZE 48 +#define SHA512_DIGEST_SIZE 64 + +#define SHA224_BLOCK_SIZE 64 +#define SHA256_BLOCK_SIZE 64 +#define SHA384_BLOCK_SIZE 128 +#define SHA512_BLOCK_SIZE 128 + +#define SHA224_STATE_WORDS 8 +#define SHA256_STATE_WORDS 8 +#define SHA384_STATE_WORDS 8 +#define SHA512_STATE_WORDS 8 + + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +typedef struct { + uint32_t state[SHA224_STATE_WORDS]; + uint64_t nblocks; + unsigned char block[SHA224_BLOCK_SIZE]; + int num; +} SHA224_CTX; + +void sha224_init(SHA224_CTX *ctx); +void sha224_update(SHA224_CTX *ctx, const unsigned char* data, size_t datalen); +void sha224_finish(SHA224_CTX *ctx, unsigned char dgst[SHA224_DIGEST_SIZE]); +void sha224_compress(uint32_t dgst[8], const unsigned char block[SHA224_BLOCK_SIZE]); +void sha224_digest(const unsigned char *data, size_t datalen, + unsigned char dgst[SHA224_DIGEST_SIZE]); + +typedef struct { + uint32_t state[8]; + uint64_t nblocks; + unsigned char block[64]; + int num; +} SHA256_CTX; + +void sha256_init(SHA256_CTX *ctx); +void sha256_update(SHA256_CTX *ctx, const unsigned char* data, size_t datalen); +void sha256_finish(SHA256_CTX *ctx, unsigned char dgst[SHA256_DIGEST_SIZE]); +void sha256_compress(uint32_t dgst[8], const unsigned char block[SHA256_BLOCK_SIZE]); +void sha256_digest(const unsigned char *data, size_t datalen, + unsigned char dgst[SHA256_DIGEST_SIZE]); + +typedef struct { + uint64_t state[8]; + uint64_t nblocks; + unsigned char block[128]; + int num; +} SHA384_CTX; + +void sha384_init(SHA384_CTX *ctx); +void sha384_update(SHA384_CTX *ctx, const unsigned char* data, size_t datalen); +void sha384_finish(SHA384_CTX *ctx, unsigned char dgst[SHA384_DIGEST_SIZE]); +void sha384_compress(uint64_t dgst[8], const unsigned char block[SHA384_BLOCK_SIZE]); +void sha384_digest(const unsigned char *data, size_t datalen, + unsigned char dgst[SHA384_DIGEST_SIZE]); + +typedef struct { + uint64_t state[8]; + uint64_t nblocks; + unsigned char block[128]; + int num; +} SHA512_CTX; + +void sha512_init(SHA512_CTX *ctx); +void sha512_update(SHA512_CTX *ctx, const unsigned char* data, size_t datalen); +void sha512_finish(SHA512_CTX *ctx, unsigned char dgst[SHA512_DIGEST_SIZE]); +void sha512_compress(uint64_t dgst[8], const unsigned char block[SHA512_BLOCK_SIZE]); +void sha512_digest(const unsigned char *data, size_t datalen, + unsigned char dgst[SHA512_DIGEST_SIZE]); + + +#ifdef __cplusplus +} +#endif +#endif diff --git a/include/gmssl/sha3.h b/include/gmssl/sha3.h new file mode 100644 index 00000000..b6dd4a0d --- /dev/null +++ b/include/gmssl/sha3.h @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2014 - 2020 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + + +#ifndef GMSSL_SHA3_H +#define GMSSL_SHA3_H + + +#include +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif + + +#define SHA3_KECCAK_P_SIZE (1600/8) + +#define SHA3_224_DIGEST_SIZE (224/8) +#define SHA3_256_DIGEST_SIZE (256/8) +#define SHA3_384_DIGEST_SIZE (384/8) +#define SHA3_512_DIGEST_SIZE (512/8) + +#define SHA3_224_CAPACITY (SHA3_224_DIGEST_SIZE * 2) +#define SHA3_256_CAPACITY (SHA3_256_DIGEST_SIZE * 2) +#define SHA3_384_CAPACITY (SHA3_384_DIGEST_SIZE * 2) +#define SHA3_512_CAPACITY (SHA3_512_DIGEST_SIZE * 2) + +#define SHA3_224_BLOCK_SIZE (SHA3_KECCAK_P_SIZE - SHA3_224_CAPACITY) // 144 +#define SHA3_256_BLOCK_SIZE (SHA3_KECCAK_P_SIZE - SHA3_224_CAPACITY) // 136 +#define SHA3_384_BLOCK_SIZE (SHA3_KECCAK_P_SIZE - SHA3_224_CAPACITY) // 104 +#define SHA3_512_BLOCK_SIZE (SHA3_KECCAK_P_SIZE - SHA3_224_CAPACITY) // 72 + + +typedef struct { + uint64_t A[5][5]; + uint8_t buf[SHA3_224_BLOCK_SIZE]; + int num; +} SHA3_224_CTX; + +void sha3_224_init(SHA3_224_CTX *ctx); +void sha3_224_update(SHA3_224_CTX *ctx, const uint8_t *data, size_t datalen); +void sha3_224_finish(SHA3_224_CTX *ctx, uint8_t dgst[SHA3_224_DIGEST_SIZE]); + +typedef struct { + uint64_t A[5][5]; + uint8_t buf[SHA3_256_BLOCK_SIZE]; + int num; +} SHA3_256_CTX; + +void sha3_256_init(SHA3_256_CTX *ctx); +void sha3_256_update(SHA3_256_CTX *ctx, const uint8_t *data, size_t datalen); +void sha3_256_finish(SHA3_256_CTX *ctx, uint8_t dgst[SHA3_256_DIGEST_SIZE]); + +typedef struct { + uint64_t A[5][5]; + uint8_t buf[SHA3_384_BLOCK_SIZE]; + int num; +} SHA3_384_CTX; + +void sha3_384_init(SHA3_384_CTX *ctx); +void sha3_384_update(SHA3_384_CTX *ctx, const uint8_t *data, size_t datalen); +void sha3_384_finish(SHA3_384_CTX *ctx, uint8_t dgst[SHA3_384_DIGEST_SIZE]); + +typedef struct { + uint64_t A[5][5]; + uint8_t buf[SHA3_512_BLOCK_SIZE]; + int num; +} SHA3_512_CTX; + +void sha3_512_init(SHA3_512_CTX *ctx); +void sha3_512_update(SHA3_512_CTX *ctx, const uint8_t *data, size_t datalen); +void sha3_512_finish(SHA3_512_CTX *ctx, uint8_t dgst[SHA3_512_DIGEST_SIZE]); + +void sha3_shake128(const uint8_t *in, size_t *inlen, size_t outlen, uint8_t *out); +void sha3_shake256(const uint8_t *in, size_t *inlen, size_t outlen, uint8_t *out); +void sha3_keccak_p(uint8_t state[SHA3_KECCAK_P_SIZE]); + + +#ifdef __cplusplus +} +#endif +#endif diff --git a/include/gmssl/sm2.h b/include/gmssl/sm2.h new file mode 100644 index 00000000..71527150 --- /dev/null +++ b/include/gmssl/sm2.h @@ -0,0 +1,196 @@ +/* + * Copyright (c) 2014 - 2021 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + + +#ifndef GMSSL_SM2_H +#define GMSSL_SM2_H + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + + + +typedef struct { + uint8_t x[32]; + uint8_t y[32]; +} SM2_POINT; + +void sm2_point_to_compressed_octets(const SM2_POINT *P, uint8_t out[33]); +void sm2_point_to_uncompressed_octets(const SM2_POINT *P, uint8_t out[65]); +int sm2_point_from_octets(SM2_POINT *P, const uint8_t *in, size_t inlen); +int sm2_point_to_der(const SM2_POINT *a, uint8_t **out, size_t *outlen); +int sm2_point_from_der(SM2_POINT *a, const uint8_t **in, size_t *inlen); +int sm2_point_from_x(SM2_POINT *P, const uint8_t x[32], int y); +int sm2_point_from_xy(SM2_POINT *P, const uint8_t x[32], const uint8_t y[32]); +int sm2_point_is_on_curve(const SM2_POINT *P); +int sm2_point_mul(SM2_POINT *R, const uint8_t k[32], const SM2_POINT *P); +int sm2_point_mul_generator(SM2_POINT *R, const uint8_t k[32]); +int sm2_point_mul_sum(SM2_POINT *R, const uint8_t k[32], const SM2_POINT *P, const uint8_t s[32]); +int sm2_point_print(FILE *fp, const SM2_POINT *P, int format, int indent); + +int sm2_compute_z(uint8_t z[32], const SM2_POINT *pub, const char *id); + + +typedef struct { + SM2_POINT public_key; + uint8_t private_key[32]; + uint8_t key_usage[4]; +} SM2_KEY; + +int sm2_keygen(SM2_KEY *key); +int sm2_set_private_key(SM2_KEY *key, const uint8_t private_key[32]); +int sm2_set_public_key(SM2_KEY *key, const uint8_t public_key[64]); // FIXME: 这里是否应该用octets呢?这算是椭圆曲线点的一个公开格式了 +int sm2_key_print(FILE *fp, const SM2_KEY *key, int format, int indent); +int sm2_public_key_digest(const SM2_KEY *key, uint8_t dgst[32]); + +// ECPrivateKey +int sm2_private_key_to_der(const SM2_KEY *key, uint8_t **out, size_t *outlen); +int sm2_private_key_to_pem(const SM2_KEY *key, FILE *fp); +int sm2_private_key_from_der(SM2_KEY *key, const uint8_t **in, size_t *inlen); +int sm2_private_key_from_pem(SM2_KEY *key, FILE *fp); + +// AlgorithmIdentifier +int sm2_public_key_algor_to_der(uint8_t **out, size_t *outlen); +int sm2_public_key_algor_from_der(const uint8_t **in, size_t *inlen); + +// X.509 SubjectPublicKeyInfo +int sm2_public_key_info_to_der(const SM2_KEY *a, uint8_t **out, size_t *outlen); +int sm2_public_key_info_to_pem(const SM2_KEY *a, FILE *fp); +int sm2_public_key_info_from_der(SM2_KEY *a, const uint8_t **in, size_t *inlen); +int sm2_public_key_info_from_pem(SM2_KEY *a, FILE *fp); + +// PKCS #8 PrivateKeyInfo +int sm2_private_key_info_to_der(const SM2_KEY *key, uint8_t **out, size_t *outlen); +int sm2_private_key_info_from_der(SM2_KEY *key, const uint8_t **attrs, size_t *attrslen, const uint8_t **in, size_t *inlen); +int sm2_private_key_info_to_pem(const SM2_KEY *key, FILE *fp); +int sm2_private_key_info_from_pem(SM2_KEY *key, const uint8_t **attrs, size_t *attrslen, FILE *fp); + + +typedef struct { + uint8_t r[32]; + uint8_t s[32]; +} SM2_SIGNATURE; + +int sm2_signature_to_der(const SM2_SIGNATURE *sig, uint8_t **out, size_t *outlen); +int sm2_signature_from_der(SM2_SIGNATURE *sig, const uint8_t **in, size_t *inlen); +int sm2_do_sign(const SM2_KEY *key, const uint8_t dgst[32], SM2_SIGNATURE *sig); +int sm2_do_verify(const SM2_KEY *key, const uint8_t dgst[32], const SM2_SIGNATURE *sig); +int sm2_print_signature(FILE *fp, const uint8_t *sig, size_t siglen, int format, int indent); + +#define SM2_MAX_SIGNATURE_SIZE 72 + +int sm2_sign(const SM2_KEY *key, const uint8_t dgst[32], uint8_t *sig, size_t *siglen); +int sm2_verify(const SM2_KEY *key, const uint8_t dgst[32], const uint8_t *sig, size_t siglen); + +#define SM2_MAX_ID_BITS 65535 +#define SM2_MAX_ID_LENGTH (SM2_MAX_ID_BITS/8) +#define SM2_MAX_ID_SIZE (SM2_MAX_ID_BITS/8) +#define SM2_DEFAULT_ID_GMT09 "1234567812345678" +#define SM2_DEFAULT_ID_GMSSL "anonym@gmssl.org" +#define SM2_DEFAULT_ID SM2_DEFAULT_ID_GMT09 +#define SM2_DEFAULT_ID_LENGTH (sizeof(SM2_DEFAULT_ID) - 1) +#define SM2_DEFAULT_ID_BITS (SM2_DEFAULT_ID_LENGTH * 8) +#define SM2_DEFAULT_ID_DIGEST_LENGTH SM3_DIGEST_LENGTH + + +typedef struct { + SM2_KEY key; + SM3_CTX sm3_ctx; + int flags; +} SM2_SIGN_CTX; + +int sm2_sign_init(SM2_SIGN_CTX *ctx, const SM2_KEY *key, const char *id); +int sm2_sign_update(SM2_SIGN_CTX *ctx, const uint8_t *data, size_t datalen); +int sm2_sign_finish(SM2_SIGN_CTX *ctx, uint8_t *sig, size_t *siglen); +int sm2_verify_init(SM2_SIGN_CTX *ctx, const SM2_KEY *key, const char *id); +int sm2_verify_update(SM2_SIGN_CTX *ctx, const uint8_t *data, size_t datalen); +int sm2_verify_finish(SM2_SIGN_CTX *ctx, const uint8_t *sig, size_t siglen); + + +typedef struct { + SM2_POINT point; + uint8_t hash[32]; + uint32_t ciphertext_size; + uint8_t ciphertext[1]; +} SM2_CIPHERTEXT; + +#define SM2_MAX_PLAINTEXT 256 +#define SM2_MAX_PLAINTEXT_SIZE 256 + +#define SM2_CIPHERTEXT_SIZE(inlen) (sizeof(SM2_CIPHERTEXT)-1+inlen) + +#define SM2_MAX_CIPHERTEXT_SIZE 512 + + + +int sm2_ciphertext_to_der(const SM2_CIPHERTEXT *c, uint8_t **out, size_t *outlen); +int sm2_ciphertext_from_der(SM2_CIPHERTEXT *c, const uint8_t **in, size_t *inlen); +int sm2_ciphertext_print(FILE *fp, const SM2_CIPHERTEXT *c, int format, int indent); +int sm2_do_encrypt(const SM2_KEY *key, const uint8_t *in, size_t inlen, SM2_CIPHERTEXT *out); +int sm2_do_decrypt(const SM2_KEY *key, const SM2_CIPHERTEXT *in, uint8_t *out, size_t *outlen); + +int sm2_encrypt(const SM2_KEY *key, const uint8_t *in, size_t inlen, uint8_t *out, size_t *outlen); +int sm2_decrypt(const SM2_KEY *key, const uint8_t *in, size_t inlen, uint8_t *out, size_t *outlen); +int sm2_print_ciphertext(FILE *fp, const uint8_t *c, size_t clen, int format, int indent); + +int sm2_ecdh(const SM2_KEY *key, const SM2_POINT *peer_public, SM2_POINT *out); + + +int sm2_algo_selftest(void); + + +#ifdef __cplusplus +extern "C" { +#endif +#endif diff --git a/include/gmssl/sm3.h b/include/gmssl/sm3.h new file mode 100755 index 00000000..88e2eee1 --- /dev/null +++ b/include/gmssl/sm3.h @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2014 - 2021 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + +#ifndef GMSSL_SM3_H +#define GMSSL_SM3_H + +#define SM3_IS_BIG_ENDIAN 1 + +#define SM3_DIGEST_SIZE 32 +#define SM3_BLOCK_SIZE 64 +#define SM3_STATE_WORDS 8 +#define SM3_HMAC_SIZE (SM3_DIGEST_SIZE) + +#include +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif + + +typedef struct { + uint32_t digest[SM3_STATE_WORDS]; + uint64_t nblocks; + uint8_t block[SM3_BLOCK_SIZE]; + int num; +} SM3_CTX; + +void sm3_init(SM3_CTX *ctx); +void sm3_update(SM3_CTX *ctx, const uint8_t *data, size_t datalen); +void sm3_finish(SM3_CTX *ctx, uint8_t dgst[SM3_DIGEST_SIZE]); +void sm3_compress(uint32_t dgst[SM3_STATE_WORDS], const uint8_t block[SM3_BLOCK_SIZE]); +void sm3_digest(const uint8_t *data, size_t datalen, uint8_t dgst[SM3_DIGEST_SIZE]); + + +typedef struct { + SM3_CTX sm3_ctx; + unsigned char key[SM3_BLOCK_SIZE]; +} SM3_HMAC_CTX; + +void sm3_hmac_init(SM3_HMAC_CTX *ctx, const uint8_t *key, size_t keylen); +void sm3_hmac_update(SM3_HMAC_CTX *ctx, const uint8_t *data, size_t datalen); +void sm3_hmac_finish(SM3_HMAC_CTX *ctx, uint8_t mac[SM3_HMAC_SIZE]); +void sm3_hmac_reset(SM3_HMAC_CTX *ctx); +void sm3_hmac(const uint8_t *key, size_t keylen, + const uint8_t *data, size_t datalen, + uint8_t mac[SM3_HMAC_SIZE]); + +int sm3_hmac_finish_and_verify(SM3_HMAC_CTX *ctx, const uint8_t mac[SM3_HMAC_SIZE]); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/include/gmssl/sm4.h b/include/gmssl/sm4.h new file mode 100644 index 00000000..2ef4ff4b --- /dev/null +++ b/include/gmssl/sm4.h @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2014 - 2021 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + +#ifndef GMSSL_SM4_H +#define GMSSL_SM4_H + +#define SM4_KEY_SIZE 16 + +#define SM4_KEY_LENGTH 16 +#define SM4_BLOCK_SIZE 16 +#define SM4_IV_LENGTH (SM4_BLOCK_SIZE) +#define SM4_NUM_ROUNDS 32 + +#include +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + uint32_t rk[SM4_NUM_ROUNDS]; +} SM4_KEY; + +void sm4_set_encrypt_key(SM4_KEY *key, const unsigned char user_key[16]); +void sm4_set_decrypt_key(SM4_KEY *key, const unsigned char user_key[16]); +void sm4_encrypt(const SM4_KEY *key, const unsigned char in[16], unsigned char out[16]); +#define sm4_decrypt(key,in,out) sm4_encrypt(key,in,out) + + +# define SM4_EDE_KEY_LENGTH (SM4_KEY_LENGTH * 3) + +typedef struct { + SM4_KEY k1; + SM4_KEY k2; + SM4_KEY k3; +} SM4_EDE_KEY; + +void sm4_ede_set_encrypt_key(SM4_EDE_KEY *key, const unsigned char user_key[48]); +void sm4_ede_set_decrypt_key(SM4_EDE_KEY *key, const unsigned char user_key[48]); +void sm4_ede_encrypt(const SM4_EDE_KEY *key, const unsigned char in[16], unsigned char out[16]); +# define sm4_ede_decrypt(key,in,out) sm4_ede_encrypt(key,in,out) + +void sm4_cbc_encrypt(const SM4_KEY *key, const uint8_t iv[16], const uint8_t *in, size_t nblocks, uint8_t *out); +void sm4_cbc_decrypt(const SM4_KEY *key, const uint8_t iv[16], const uint8_t *in, size_t nblocks, uint8_t *out); + +int sm4_cbc_padding_encrypt(const SM4_KEY *key, const uint8_t iv[16], + const uint8_t *in, size_t inlen, + uint8_t *out, size_t *outlen); +int sm4_cbc_padding_decrypt(const SM4_KEY *key, const uint8_t iv[16], + const uint8_t *in, size_t inlen, + uint8_t *out, size_t *outlen); + + +#ifdef __cplusplus +} +#endif +#endif diff --git a/include/gmssl/sm9.h b/include/gmssl/sm9.h new file mode 100644 index 00000000..8e69070b --- /dev/null +++ b/include/gmssl/sm9.h @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2016 - 2021 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + +#ifndef GMSSL_SM9_H +#define GMSSL_SM9_H + +#ifdef __cplusplus +extern "C" { +#endif + + +// set the same value as sm2 +#define SM9_MAX_ID_BITS 65535 +#define SM9_MAX_ID_SIZE (SM9_MAX_ID_BITS/8) + +typedef struct { + uint8_t x[32]; + uint8_t y[32]; +} SM9_POINT; + +typedef struct { + uint8_t x[64]; + uint8_t y[64]; +} SM9_TWIST_POINT; + +typedef struct { + uint8_t ks[32]; + SM9_TWIST_POINT Ppubs; // Ppubs = ks * P2 +} SM9_SIGN_MASTER_KEY; + +typedef struct { + SM9_POINT ds; +} SM9_SIGN_KEY; + +typedef struct { + uint8_t h[32]; + SM9_TWIST_POINT S; +} SM9_SIGNATURE; + +int sm9_sign_setup(SM9_SIGN_MASTER_KEY *msk); +int sm9_sign_keygen(SM9_SIGN_MASTER_KEY *msk, const char *id, size_t idlen, SM9_POINT *ds); + +int sm9_do_sign(SM9_SIGN_KEY *key, const uint8_t dgst[32], SM9_SIGNATURE *sig); +int sm9_do_verify(SM9_SIGN_KEY *key, const uint8_t dgst[32], const SM9_SIGNATURE *sig); + + + +# ifdef __cplusplus +} +# endif +# endif diff --git a/include/gmssl/tls.h b/include/gmssl/tls.h new file mode 100644 index 00000000..dab5b223 --- /dev/null +++ b/include/gmssl/tls.h @@ -0,0 +1,640 @@ +/* + * Copyright (c) 2020 - 2021 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + + +#ifndef GMSSL_TLS_H +#define GMSSL_TLS_H + + +#include +#include +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif + +typedef uint32_t uint24_t; + +void tls_uint8_to_bytes(uint8_t a, uint8_t **out, size_t *outlen); +void tls_uint16_to_bytes(uint16_t a, uint8_t **out, size_t *outlen); +void tls_uint24_to_bytes(uint24_t a, uint8_t **out, size_t *outlen); +void tls_uint32_to_bytes(uint32_t a, uint8_t **out, size_t *outlen); +void tls_array_to_bytes(const uint8_t *data, size_t len, uint8_t **out, size_t *outlen); +void tls_uint8array_to_bytes(const uint8_t *data, size_t datalen, uint8_t **out, size_t *outlen); +void tls_uint16array_to_bytes(const uint8_t *data, size_t datalen, uint8_t **out, size_t *outlen); +void tls_uint24array_to_bytes(const uint8_t *data, size_t datalen, uint8_t **out, size_t *outlen); +int tls_uint8_from_bytes(uint8_t *a, const uint8_t **in, size_t *inlen); +int tls_uint16_from_bytes(uint16_t *a, const uint8_t **in, size_t *inlen); +int tls_uint24_from_bytes(uint24_t *a, const uint8_t **in, size_t *inlen); +int tls_uint32_from_bytes(uint32_t *a, const uint8_t **in, size_t *inlen); +int tls_array_from_bytes(const uint8_t **data, size_t datalen, const uint8_t **in, size_t *inlen); +int tls_uint8array_from_bytes(const uint8_t **data, size_t *datalen, const uint8_t **in, size_t *inlen); +int tls_uint16array_from_bytes(const uint8_t **data, size_t *datalen, const uint8_t **in, size_t *inlen); +int tls_uint24array_from_bytes(const uint8_t **data, size_t *datalen, const uint8_t **in, size_t *inlen); +int tls_array_copy_from_bytes(uint8_t *data, size_t datalen, const uint8_t **in, size_t *inlen); +int tls_uint8array_copy_from_bytes(uint8_t *data, size_t *datalen, size_t maxlen, const uint8_t **in, size_t *inlen); +int tls_uint16array_copy_from_bytes(uint8_t *data, size_t *datalen, size_t maxlen, const uint8_t **in, size_t *inlen); +int tls_uint24array_copy_from_bytes(uint8_t *data, size_t *datalen, size_t maxlen, const uint8_t **in, size_t *inlen); + + +#define TLCP_VERSION_MAJOR 1 +#define TLCP_VERSION_MINOR 1 + + +typedef enum { + TLS_version_tlcp = 0x0101, + TLS_version_ssl2 = 0x0200, + TLS_version_ssl3 = 0x0300, + TLS_version_tls1 = 0x0301, + TLS_version_tls11 = 0x0302, + TLS_version_tls12 = 0x0303, + TLS_version_tls13 = 0x0304, + TLS_version_dtls1 = 0xfeff, // {254, 255} + TLS_version_dtls12 = 0xfefd, // {254, 253} +} TLS_VERSION; + +typedef enum { + TLS_cipher_null_with_null_null = 0x0000, + TLS_cipher_sm4_gcm_sm3 = 0x00c6, + TLS_cipher_sm4_ccm_sm3 = 0x00c7, + TLCP_cipher_ecdhe_sm4_cbc_sm3 = 0xe011, + TLCP_cipher_ecdhe_sm4_gcm_sm3 = 0xe051, + TLCP_cipher_ecc_sm4_cbc_sm3 = 0xe013, + TLCP_cipher_ecc_sm4_gcm_sm3 = 0xe053, + TLCP_cipher_ibsdh_sm4_cbc_sm3 = 0xe015, + TLCP_cipher_ibsdh_sm4_gcm_sm3 = 0xe055, + TLCP_cipher_ibc_sm4_cbc_sm3 = 0xe017, + TLCP_cipher_ibc_sm4_gcm_sm3 = 0xe057, + TLCP_cipher_rsa_sm4_cbc_sm3 = 0xe019, + TLCP_cipher_rsa_sm4_gcm_sm3 = 0xe059, + TLCP_cipher_rsa_sm4_cbc_sha256 = 0xe01c, + TLCP_cipher_rsa_sm4_gcm_sha256 = 0xe05a, + GMSSL_cipher_ecdhe_sm2_with_sm4_sm3 = 0xe102, + GMSSL_cipher_ecdhe_sm2_with_sm4_gcm_sm3 = 0xe107, + GMSSL_cipher_ecdhe_sm2_with_sm4_ccm_sm3 = 0xe108, + GMSSL_cipher_ecdhe_sm2_with_zuc_sm3 = 0xe10d, + TLS_cipher_empty_renegotiation_info_scsv = 0x00ff, +} TLS_CIPHER_SUITE; + +typedef enum { + TLS_record_change_cipher_spec = 20, + TLS_record_alert = 21, + TLS_record_handshake = 22, + TLS_record_application_data = 23, + TLS_record_heartbeat = 24, + TLS_record_tls12_cid = 25, +} TLS_RECORD_TYPE; + +typedef enum { + TLS_handshake_hello_request = 0, + TLS_handshake_client_hello = 1, + TLS_handshake_server_hello = 2, + TLS_handshake_hello_verify_request = 3, + TLS_handshake_new_session_ticket = 4, + TLS_handshake_end_of_early_data = 5, + TLS_handshake_hello_retry_request = 6, + TLS_handshake_encrypted_extensions = 8, + TLS_handshake_certificate = 11, + TLS_handshake_server_key_exchange = 12, + TLS_handshake_certificate_request = 13, + TLS_handshake_server_hello_done = 14, + TLS_handshake_certificate_verify = 15, + TLS_handshake_client_key_exchange = 16, + TLS_handshake_finished = 20, + TLS_handshake_certificate_url = 21, + TLS_handshake_certificate_status = 22, + TLS_handshake_supplemental_data = 23, + TLS_handshake_key_update = 24, + TLS_handshake_compressed_certificate = 25, + TLS_handshake_ekt_key = 26, + TLS_handshake_message_hash = 254, +} TLS_HANDSHAKE_TYPE; + +typedef enum { + TLS_compression_null = 0, + TLS_compression_default = 1, +} TLS_COMPRESSION_METHOD; + +typedef enum { + TLS_cert_type_rsa_sign = 1, + TLS_cert_type_dss_sign = 2, + TLS_cert_type_rsa_fixed_dh = 3, + TLS_cert_type_dss_fixed_dh = 4, + TLS_cert_type_rsa_ephemeral_dh_RESERVED = 5, + TLS_cert_type_dss_ephemeral_dh_RESERVED = 6, + TLS_cert_type_fortezza_dms_RESERVED = 20, + TLS_cert_type_ecdsa_sign = 64, // also for sm2 + TLS_cert_type_rsa_fixed_ecdh = 65, + TLS_cert_type_ecdsa_fixed_ecdh = 66, + TLS_cert_type_gost_sign256 = 67, + TLS_cert_type_gost_sign512 = 68, + TLS_cert_type_ibc_params = 80, +} TLS_CERTIFICATE_TYPE; + +typedef enum { + TLS_extension_server_name = 0, + TLS_extension_max_fragment_length = 1, + TLS_extension_client_certificate_url = 2, + TLS_extension_trusted_ca_keys = 3, + TLS_extension_truncated_hmac = 4, + TLS_extension_status_request = 5, + TLS_extension_user_mapping = 6, + TLS_extension_client_authz = 7, + TLS_extension_server_authz = 8, + TLS_extension_cert_type = 9, // 这个是支持服务器证书的类型吗?仅仅用CIPHER_SUITE不够吗? + TLS_extension_supported_groups = 10, // 必须支持 + TLS_extension_ec_point_formats = 11, // 必须支持 + TLS_extension_srp = 12, + TLS_extension_signature_algorithms = 13, // 必须支持 + TLS_extension_use_srtp = 14, + TLS_extension_heartbeat = 15, + TLS_extension_application_layer_protocol_negotiation= 16, + TLS_extension_status_request_v2 = 17, + TLS_extension_signed_certificate_timestamp = 18, + TLS_extension_client_certificate_type = 19, + TLS_extension_server_certificate_type = 20, + TLS_extension_padding = 21, + TLS_extension_encrypt_then_mac = 22, // 应该支持 + TLS_extension_extended_master_secret = 23, // 这个是什么意思? + TLS_extension_token_binding = 24, + TLS_extension_cached_info = 25, + TLS_extension_tls_lts = 26, + TLS_extension_compress_certificate = 27, + TLS_extension_record_size_limit = 28, + TLS_extension_pwd_protect = 29, + TLS_extension_pwd_clear = 30, + TLS_extension_password_salt = 31, + TLS_extension_ticket_pinning = 32, + TLS_extension_tls_cert_with_extern_psk = 33, + TLS_extension_delegated_credentials = 34, + TLS_extension_session_ticket = 35, // 应该支持 + TLS_extension_TLMSP = 36, + TLS_extension_TLMSP_proxying = 37, + TLS_extension_TLMSP_delegate = 38, + TLS_extension_supported_ekt_ciphers = 39, + TLS_extension_pre_shared_key = 41, + TLS_extension_early_data = 42, + TLS_extension_supported_versions = 43, + TLS_extension_cookie = 44, + TLS_extension_psk_key_exchange_modes = 46, + TLS_extension_certificate_authorities = 47, + TLS_extension_oid_filters = 48, + TLS_extension_post_handshake_auth = 49, + TLS_extension_signature_algorithms_cert = 50, + TLS_extension_key_share = 51, + TLS_extension_transparency_info = 52, + TLS_extension_connection_id = 53, + TLS_extension_external_id_hash = 55, + TLS_extension_external_session_id = 56, + TLS_extension_quic_transport_parameters = 57, + TLS_extension_ticket_request = 58, + TLS_extension_renegotiation_info = 65281, +} TLS_EXTENSION_TYPE; + +typedef enum { + TLS_point_uncompressed = 0, + TLS_point_ansix962_compressed_prime = 1, + TLS_point_ansix962_compressed_char2 = 2, +} TLS_EC_POINT_FORMAT; + +typedef enum { + TLS_curve_type_explicit_prime = 1, + TLS_curve_type_explicit_char2 = 2, + TLS_curve_type_named_curve = 3, +} TLS_CURVE_TYPE; + +typedef enum { + TLS_curve_secp256k1 = 22, + TLS_curve_secp256r1 = 23, + TLS_curve_secp384r1 = 24, + TLS_curve_secp521r1 = 25, + TLS_curve_brainpoolp256r1 = 26, + TLS_curve_brainpoolp384r1 = 27, + TLS_curve_brainpoolp512r1 = 28, + TLS_curve_x25519 = 29, + TLS_curve_x448 = 99, //30, + TLS_curve_brainpoolp256r1tls13 = 31, + TLS_curve_brainpoolp384r1tls13 = 32, + TLS_curve_brainpoolp512r1tls13 = 33, + TLS_curve_sm2p256v1 = 30,//41, // in gmssl v2, is 30 +} TLS_NAMED_CURVE; + +typedef enum { + TLS_sig_rsa_pkcs1_sha1 = 0x0201, + TLS_sig_ecdsa_sha1 = 0x0203, + TLS_sig_rsa_pkcs1_sha256 = 0x0401, + TLS_sig_ecdsa_secp256r1_sha256 = 0x0403, + TLS_sig_rsa_pkcs1_sha256_legacy = 0x0420, + TLS_sig_rsa_pkcs1_sha384 = 0x0501, + TLS_sig_ecdsa_secp384r1_sha384 = 0x0503, + TLS_sig_rsa_pkcs1_sha384_legacy = 0x0520, + TLS_sig_rsa_pkcs1_sha512 = 0x0601, + TLS_sig_ecdsa_secp521r1_sha512 = 0x0603, + TLS_sig_rsa_pkcs1_sha512_legacy = 0x0620, + TLS_sig_sm2sig_sm3 = 0x0707,//0x0708, // is 0707 in gmsslv2 + TLS_sig_rsa_pss_rsae_sha256 = 0x0804, + TLS_sig_rsa_pss_rsae_sha384 = 0x0805, + TLS_sig_rsa_pss_rsae_sha512 = 0x0806, + TLS_sig_ed25519 = 0x0807, + TLS_sig_ed448 = 0x0808, + TLS_sig_rsa_pss_pss_sha256 = 0x0809, + TLS_sig_rsa_pss_pss_sha384 = 0x080A, + TLS_sig_rsa_pss_pss_sha512 = 0x080B, + TLS_sig_ecdsa_brainpoolP256r1tls13_sha256 = 0x081A, + TLS_sig_ecdsa_brainpoolP384r1tls13_sha384 = 0x081B, + TLS_sig_ecdsa_brainpoolP512r1tls13_sha512 = 0x081C, +} TLS_SIGNATURE_SCHEME; + +typedef enum { + TLS_change_cipher_spec = 1, +} TLS_CHANGE_CIPHER_SPEC_TYPE; + +typedef enum { + TLS_alert_level_warning = 1, + TLS_alert_level_fatal = 2, +} TLS_ALERT_LEVEL; + +typedef enum { + TLS_alert_close_notify = 0, + TLS_alert_unexpected_message = 10, + TLS_alert_bad_record_mac = 20, + TLS_alert_decryption_failed = 21, + TLS_alert_record_overflow = 22, + TLS_alert_decompression_failure = 30, + TLS_alert_handshake_failure = 40, + TLS_alert_no_certificate = 41, + TLS_alert_bad_certificate = 42, + TLS_alert_unsupported_certificate = 43, + TLS_alert_certificate_revoked = 44, + TLS_alert_certificate_expired = 45, + TLS_alert_certificate_unknown = 46, + TLS_alert_illegal_parameter = 47, + TLS_alert_unknown_ca = 48, + TLS_alert_access_denied = 49, + TLS_alert_decode_error = 50, + TLS_alert_decrypt_error = 51, + TLS_alert_export_restriction = 60, + TLS_alert_protocol_version = 70, + TLS_alert_insufficient_security = 71, + TLS_alert_internal_error = 80, + TLS_alert_user_canceled = 90, + TLS_alert_no_renegotiation = 100, + TLS_alert_unsupported_site2site = 200, + TLS_alert_no_area = 201, + TLS_alert_unsupported_areatype = 202, + TLS_alert_bad_ibcparam = 203, + TLS_alert_unsupported_ibcparam = 204, + TLS_alert_identity_need = 205, +} TLS_ALERT_DESCRIPTION; + + + + +#define TLS_RECORD_MAX_PLAINDATA_SIZE 16384 // 2^14 +#define TLS_RECORD_MAX_DATA_SIZE 18432 // 2^24 + 2048 +#define TLS_RECORD_MAX_SIZE 18437 // 5 + (2^24 + 2048) + +#define TLS_MAX_RECORD_SIZE 18437 // 5 + (2^24 + 2048) + +#define TLS_MAX_SIGNATURE_SIZE SM2_MAX_SIGNATURE_SIZE + +#define TLS_MAX_EXTENSIONS_SIZE 512 +#define TLS_MAX_CERT_SIZE 1024 +#define TLS_MAX_CERTIFICATES_SIZE 2048 +#define TLS_MAX_SERVER_CERTS_SIZE 2048 + +#define TLS_MAX_HANDSHAKES_SIZE 4096 + + +// 应该保留对方的证书 + +// 我们应该讲这个值编码为一个标准的TLS的结构 + + +typedef struct { + int is_client; + int version; + int cipher_suite; + int compression_method; + uint8_t master_secret[48]; + uint8_t server_certs[1600]; + size_t server_certs_size; + uint8_t client_cert[1024]; + size_t client_cert_size; +} TLS_SESSION; + + +typedef struct { + int sock; + int is_client; + int version; + int cipher_suite; + uint8_t session_id[32]; + size_t session_id_len; + uint8_t master_secret[48]; + uint8_t key_block[96]; + int do_trace; + + uint8_t server_certs[TLS_MAX_CERTIFICATES_SIZE]; + size_t server_certs_len; + + uint8_t client_certs[TLS_MAX_CERTIFICATES_SIZE]; + size_t client_certs_len; + + SM3_HMAC_CTX client_write_mac_ctx; + SM3_HMAC_CTX server_write_mac_ctx; + SM4_KEY client_write_enc_key; + SM4_KEY server_write_enc_key; + uint8_t client_seq_num[8]; + uint8_t server_seq_num[8]; + + uint8_t record[TLS_MAX_RECORD_SIZE]; + uint8_t handshakes[TLS_MAX_HANDSHAKES_SIZE]; + size_t handshakes_len; + +} TLS_CONNECT; + + +// 有可能在连接建立之后,客户端还是想获得一些这个连接的有关信息呢?比如random中有时间信息? +// 服务器的证书一定是需要的吧 + + +// 客户端证书应该是预置的 +int tlcp_connect(TLS_CONNECT *conn, const char *hostname, int port, + FILE *ca_certs_fp, FILE *client_certs_fp, const SM2_KEY *client_sign_key); + +int tlcp_accept(TLS_CONNECT *conn, int port, + FILE *server_certs_fp, const SM2_KEY *server_sign_key, const SM2_KEY *server_enc_key, + FILE *client_cacerts_fp, uint8_t *client_cert_verify_buf, size_t client_cert_verify_buflen); + + +int tls_send(TLS_CONNECT *conn, const uint8_t *data, size_t datalen); +int tls_recv(TLS_CONNECT *conn, uint8_t *data, size_t *datalen); + + + +int tls_seq_num_incr(uint8_t seq_num[8]); + + +int tls_prf(const uint8_t *secret, size_t secretlen, const char *label, + const uint8_t *seed, size_t seedlen, + const uint8_t *more, size_t morelen, + size_t outlen, uint8_t *out); + +int tls_cbc_encrypt(const SM3_HMAC_CTX *hmac_ctx, const SM4_KEY *enc_key, + const uint8_t seq_num[8], const uint8_t header[5], + const uint8_t *in, size_t inlen, uint8_t *out, size_t *outlen); + +int tls_cbc_decrypt(const SM3_HMAC_CTX *hmac_ctx, const SM4_KEY *dec_key, + const uint8_t seq_num[8], const uint8_t header[5], + const uint8_t *in, size_t inlen, uint8_t *out, size_t *outlen); + + +const char *tls_record_type_name(int type); +int tls_record_version(const uint8_t *record); +int tls_record_length(const uint8_t *record); + +const char *tls_version_text(int version); + +int tls_record_set_version(uint8_t *record, int version); + + +int tls_record_encrypt(const SM3_HMAC_CTX *hmac_ctx, const SM4_KEY *cbc_key, + const uint8_t seq_num[8], const uint8_t *in, size_t inlen, + uint8_t *out, size_t *outlen); +int tls_record_decrypt(const SM3_HMAC_CTX *hmac_ctx, const SM4_KEY *cbc_key, + const uint8_t seq_num[8], const uint8_t *in, size_t inlen, + uint8_t *out, size_t *outlen); + + +int tls_record_send(const uint8_t *record, size_t recordlen, int sock); +int tls_record_recv(uint8_t *record, size_t *recordlen, int sock); + + +int tls_random_generate(uint8_t random[32]); +int tls_random_print(FILE *fp, const uint8_t random[32], int format, int indent); +int tls_pre_master_secret_generate(uint8_t pre_master_secret[48], int version); +int tls_pre_master_secret_print(FILE *fp, const uint8_t pre_master_secret[48], int format, int indent); + + +int tls_cipher_suite_in_list(int cipher, const int *list, size_t list_count); +const char *tlcp_cipher_suite_name(int cipher); +const char *tls_cipher_suite_name(int cipher); +const char *tls_compression_method_name(int meth); + + +int tls_record_set_handshake(uint8_t *record, size_t *recordlen, + int type, const uint8_t *data, size_t datalen); +int tls_record_get_handshake(const uint8_t *record, + int *type, const uint8_t **data, size_t *datalen); + + +int tls_record_set_handshake_client_hello(uint8_t *record, size_t *recordlen, + int client_version, const uint8_t random[32], + const uint8_t *session_id, size_t session_id_len, + const int *cipher_suites, size_t cipher_suites_count, + const uint8_t *exts, size_t exts_len); + +int tls_record_get_handshake_client_hello(const uint8_t *record, + int *client_version, uint8_t random[32], + uint8_t *session_id, size_t *session_id_len, + int *cipher_suites, size_t *cipher_suites_count, + uint8_t *exts, size_t *exts_len); + +int tls_client_hello_print(FILE *fp, const uint8_t *data, size_t datalen, int format, int indent); + +int tls_record_set_handshake_server_hello(uint8_t *record, size_t *recordlen, + int server_version, const uint8_t random[32], + const uint8_t *session_id, size_t session_id_len, int cipher_suite, + const uint8_t *exts, size_t exts_len); + +int tls_record_get_handshake_server_hello(const uint8_t *record, + int *version, uint8_t random[32], uint8_t *session_id, size_t *session_id_len, + int *cipher_suite, uint8_t *exts, size_t *exts_len); + +int tls_server_hello_print(FILE *fp, const uint8_t *server_hello, size_t len, int format, int indent); + +int tls_record_set_handshake_certificate(uint8_t *record, size_t *recordlen, + const uint8_t *certs, size_t certslen); +int tls_record_set_handshake_certificate_from_pem(uint8_t *record, size_t *recordlen, FILE *fp); +int tls_record_get_handshake_certificate(const uint8_t *record, uint8_t *certs, size_t *certslen); +int tls_certificate_get_subject_names(const uint8_t *certs, size_t certslen, uint8_t *names, size_t *nameslen); +int tls_certificate_get_public_keys(const uint8_t *certs, size_t certslen, SM2_KEY *sign_key, SM2_KEY *enc_key); +int tls_certificate_print(FILE *fp, const uint8_t *certs, size_t certslen, int format, int indent); + +int tls_certificate_chain_verify(const uint8_t *certs, size_t certslen, FILE *ca_certs_fp, int depth); + +int tls_certificate_get_first(const uint8_t *data, size_t datalen, const uint8_t **cert, size_t *certlen); +int tls_certificate_get_second(const uint8_t *data, size_t datalen, const uint8_t **cert, size_t *certlen); + + +// 应该把所有TLCP协议的内容放到一起 +int tlcp_record_set_handshake_server_key_exchange_pke(uint8_t *record, size_t *recordlen, + const uint8_t *sig, size_t siglen); +int tlcp_record_get_handshake_server_key_exchange_pke(const uint8_t *record, + uint8_t *sig, size_t *siglen); +int tlcp_server_key_exchange_pke_print(FILE *fp, const uint8_t *sig, size_t siglen, int format, int indent); + + + +int tls_server_key_exchange_print(FILE *fp, const uint8_t *ske, size_t skelen, int format, int indent); +const char *tls_cert_type_name(int type); + + +#define TLS_MAX_CERTIFICATE_TYPES 16 +#define TLS_MAX_CA_NAMES_SIZE 256 + + +int tls_record_set_handshake_certificate_request(uint8_t *record, size_t *recordlen, + const int *cert_types, size_t cert_types_count, + const uint8_t *ca_names, size_t ca_names_len); + +int tls_record_get_handshake_certificate_request(const uint8_t *record, + int *cert_types, size_t *cert_types_count, + uint8_t *ca_names, size_t *ca_names_len); + + + +int tls_certificate_request_print(FILE *fp, const uint8_t *data, size_t datalen, int format, int indent); +int tls_record_set_handshake_server_hello_done(uint8_t *record, size_t *recordlen); +int tls_record_get_handshake_server_hello_done(const uint8_t *record); +int tls_server_hello_done_print(FILE *fp, const uint8_t *data, size_t datalen, int format, int indent); + +int tls_record_set_handshake_client_key_exchange_pke(uint8_t *record, size_t *recordlen, + const uint8_t *enced_pms, size_t enced_pms_len); +int tls_record_get_handshake_client_key_exchange_pke(const uint8_t *record, + uint8_t *enced_pms, size_t *enced_pms_len); +int tls_client_key_exchange_pke_print(FILE *fp, const uint8_t *cke, size_t ckelen, int format, int indent); +int tls_client_key_exchange_print(FILE *fp, const uint8_t *cke, size_t ckelen, int format, int indent); +int tls_record_set_handshake_certificate_verify(uint8_t *record, size_t *recordlen, + const uint8_t *sig, size_t siglen); +int tls_record_get_handshake_certificate_verify(const uint8_t *record, + uint8_t *sig, size_t *siglen); +int tls_certificate_verify_print(FILE *fp, const uint8_t *p, size_t len, int format, int indent); + +int tls_record_set_handshake_finished(uint8_t *record, size_t *recordlen, + const uint8_t verify_data[12]); +int tls_record_get_handshake_finished(const uint8_t *record, uint8_t verify_data[12]); +int tls_finished_print(FILE *fp, const uint8_t *a, size_t len, int format, int indent); +const char *tls_handshake_type_name(int type); +int tls_handshake_print(FILE *fp, const uint8_t *handshake, size_t handshakelen, int format, int indent); + + +const char *tls_alert_level_name(int level); +const char *tls_alert_description_text(int description); +int tls_alert_print(FILE *fp, const uint8_t *data, size_t datalen, int format, int indent); + + +int tls_record_set_alert(uint8_t *record, size_t *recordlen, + int alert_level, + int alert_description); +int tls_record_get_alert(const uint8_t *record, + int *alert_level, + int *alert_description); + +const char *tls_change_cipher_spec_text(int change_cipher_spec); +int tls_record_set_change_cipher_spec(uint8_t *record, size_t *recordlen); +int tls_record_get_change_cipher_spec(const uint8_t *record); +int tls_change_cipher_spec_print(FILE *fp, const uint8_t *data, size_t datalen, int format, int indent); + +int tls_record_set_application_data(uint8_t *record, size_t *recordlen, + const uint8_t *data, size_t datalen); +int tls_record_get_application_data(uint8_t *record, + const uint8_t **data, size_t *datalen); +int tls_application_data_print(FILE *fp, const uint8_t *data, size_t datalen, int format, int indent); + + +int tls_record_print(FILE *fp, const uint8_t *record, size_t recordlen, int format, int indent); + + + +const char *tls_ec_point_format_name(int format); +const char *tls_curve_type_name(int type); +const char *tls_named_curve_name(int curve); +const char *tls_signature_scheme_name(int scheme); +int tls_sign_server_ecdh_params(const SM2_KEY *server_sign_key, + const uint8_t client_random[32], const uint8_t server_random[32], + int curve, const SM2_POINT *point, uint8_t *sig, size_t *siglen); +int tls_verify_server_ecdh_params(const SM2_KEY *server_sign_key, + const uint8_t client_random[32], const uint8_t server_random[32], + int curve, const SM2_POINT *point, const uint8_t *sig, size_t siglen); +int tls_record_set_handshake_server_key_exchange_ecdhe(uint8_t *record, size_t *recordlen, + int curve, const SM2_POINT *point, const uint8_t *sig, size_t siglen); +int tls_record_get_handshake_server_key_exchange_ecdhe(const uint8_t *record, + int *curve, SM2_POINT *point, uint8_t *sig, size_t *siglen); +int tls_server_key_exchange_ecdhe_print(FILE *fp, const uint8_t *data, size_t datalen, + int format, int indent); +int tls_record_set_handshake_client_key_exchange_ecdhe(uint8_t *record, size_t *recordlen, + const SM2_POINT *point); +int tls_record_get_handshake_client_key_exchange_ecdhe(const uint8_t *record, SM2_POINT *point); +int tls_client_key_exchange_ecdhe_print(FILE *fp, const uint8_t *data, size_t datalen, + int format, int indent); +int tls12_connect(TLS_CONNECT *conn, const char *hostname, int port, + FILE *ca_certs_fp, FILE *client_certs_fp, const SM2_KEY *client_sign_key); +int tls12_accept(TLS_CONNECT *conn, int port, + FILE *certs_fp, const SM2_KEY *server_sign_key, + FILE *client_cacerts_fp, uint8_t *handshakes_buf, size_t handshakes_buflen); + +int tls_secrets_print(FILE *fp, + const uint8_t *pre_master_secret, size_t pre_master_secret_len, + const uint8_t client_random[32], const uint8_t server_random[32], + const uint8_t master_secret[48], + const uint8_t *key_block, size_t key_block_len, + int format, int indent); + + +#define tls_trace printf + + +#ifdef __cplusplus +} +#endif +#endif diff --git a/include/gmssl/x509.h b/include/gmssl/x509.h new file mode 100644 index 00000000..361b0bf9 --- /dev/null +++ b/include/gmssl/x509.h @@ -0,0 +1,1114 @@ +/* + * Copyright (c) 2014 - 2021 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + +#ifndef GMSSL_X509_H +#define GMSSL_X509_H + + +#include +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +/* + ASN.1 API 规则 + + * SEQUENCE OF/SET OF 类型是存储类型 + * 如果一个CHOICE类型可选项中有存储类型,那么这个CHOICE也设置为存储类型 + +*/ + + +enum X509_Version { + X509_version_v1 = 0, + X509_version_v2 = 1, + X509_version_v3 = 2, +}; + +int x509_time_to_der(time_t a, uint8_t **out, size_t *outlen); +int x509_time_from_der(time_t *a, const uint8_t **in, size_t *inlen); + +typedef struct { + time_t not_before; + time_t not_after; +} X509_VALIDITY; + +int x509_validity_set_days(X509_VALIDITY *a, time_t not_before, int days); +int x509_validity_to_der(const X509_VALIDITY *a, uint8_t **out, size_t *outlen); +int x509_validity_from_der(X509_VALIDITY *a, const uint8_t **in, size_t *inlen); +int x509_validity_print(FILE *fp, const X509_VALIDITY *validity, int format, int indent); + +/* +DirectoryString ::= CHOICE { + teletexString TeletexString (SIZE (1..MAX)), + printableString PrintableString (SIZE (1..MAX)), + universalString UniversalString (SIZE (1..MAX)), + utf8String UTF8String (SIZE (1..MAX)), + bmpString BMPString (SIZE (1..MAX)), +} +DirectoryString 实际上就是一个 Universal 类型,因此提供和 asn1.h 中基本类型一致的接口 +*/ +int x509_directory_string_to_der(int tag, const char *a, size_t alen, uint8_t **out, size_t *outlen); +int x509_directory_string_from_der(int *tag, const char **a, size_t *alen, const uint8_t **in, size_t *inlen); + + +/* +Name ::= SEQUENCE OF RelativeDistinguishedName + +RelativeDistinguishedName ::= SET SIZE (1..MAX) OF AttributeTypeAndValue + -- 我们只支持 SIZE == 1 的情况 + +AttributeTypeAndValue ::= SEQUENCE { + type OBJECT IDENTIFIER, + value ANY -- DEFINED BY AttributeType + -- mostly DirectoryString or PrintableString +} + + type == domainComponent 可能出现多次,因此目前X509_NAME并不支持这种情况 + 这个在实际中出现的多吗? + +*/ + +typedef struct { + size_t datalen; + uint8_t data[256]; +} X509_RDN; + +int x509_rdn_to_der(int oid, int tag, const char *str, uint8_t **out, size_t *outlen); +int x509_rdn_from_der(int *oid, int *tag, const char **str, size_t *slen, const uint8_t **in, size_t *inlen); + +typedef struct { + int count; + int oids[8]; + int tags[8]; + + char country[3]; // printableString + char state_or_province[129]; + char locality[129]; + char org[65]; + char org_unit[65]; + char common_name[65]; + char serial_number[65]; // printableString + char dn_qualifier[65]; // printableString +} X509_NAME; + +int x509_name_add_rdn_ex(X509_NAME *a, int oid, int tag, const char *str, size_t len); +int x509_name_equ(const X509_NAME *a, const X509_NAME *b); +int x509_name_from_der(X509_NAME *a, const uint8_t **in, size_t *inlen); +int x509_name_to_der(const X509_NAME *a, uint8_t **out, size_t *outlen); +int x509_name_print(FILE *fp, const X509_NAME *a, int format, int indent); + + +#define x509_name_add_rdn(a,oid,tag,s) x509_name_add_rdn_ex((a),(oid),(tag),(s),strlen(s)) +#define x509_name_set_country(a,s) x509_name_add_rdn((a),OID_at_countryName,ASN1_TAG_PrintableString,(s)) +#define x509_name_set_state_or_province(a,s) x509_name_add_rdn((a),OID_at_stateOrProvinceName,ASN1_TAG_PrintableString,(s)) +#define x509_name_set_organization(a,s) x509_name_add_rdn((a),OID_at_organizationName,ASN1_TAG_PrintableString,(s)) +#define x509_name_set_organizational_unit(a,s) x509_name_add_rdn((a),OID_at_organizationalUnitName,ASN1_TAG_PrintableString,(s)) +#define x509_name_set_common_name(a,s) x509_name_add_rdn((a),OID_at_commonName,ASN1_TAG_PrintableString,(s)) + +/* +AlgorithmIdentifier ::= SEQUENCE { + algorithm OBJECT IDENTIFIER, + parameters ANY DEFINED BY algorithm OPTIONAL } + + SignatureAlgorithm 是特殊的 AlgorithmIdentifier + 当 algorithm 为 ECDSA/SM2 时,parameters 为空 + 当 algorithm 为 RSA 时,parameters 为 ASN1_NULL 对象 +*/ +int x509_signature_algor_to_der(int oid, uint8_t **out, size_t *outlen); +int x509_signature_algor_from_der(int *oid, const uint8_t **in, size_t *inlen); + +const char *x509_digest_algor_name(int oid); + +int x509_digest_algor_to_der(int oid, uint8_t **out, size_t *outlen); +int x509_digest_algor_from_der(int *oid, uint32_t *nodes, size_t *nodes_count, + const uint8_t **in, size_t *inlen); +int x509_encryption_algor_to_der(int cipher, const uint8_t *iv, size_t ivlen, + uint8_t **out, size_t *outlen); +int x509_encryption_algor_from_der(int *cipher, + const uint8_t **iv, size_t *ivlen, + const uint8_t **in, size_t *inlen); +int x509_public_key_encryption_algor_to_der(int algor, uint8_t **out, size_t *outlen); +int x509_public_key_encryption_algor_from_der(int *algor, + uint32_t *nodes, size_t *nodes_count, + const uint8_t *params, size_t *params_len, + const uint8_t **in, size_t *inlen); + + +/* +SubjectPublicKeyInfo ::= SEQUENCE { + algorithm AlgorithmIdentifier, + subjectPublicKey BIT STRING } + + algorithm.algorithm = OID_x9_62_ecPublicKey; + algorithm.parameters = OID_sm2p256v1; + subjectPublicKey = ECPoint +*/ +typedef struct { + int algor_oid; + int curve_oid; + SM2_KEY sm2_key; +} X509_PUBLIC_KEY_INFO; + +int x509_public_key_info_set_sm2(X509_PUBLIC_KEY_INFO *a, const SM2_KEY *sm2_key); +#define x509_public_key_info_set(a,pk) x509_public_key_info_set_sm2((a),(pk)) +int x509_public_key_info_to_der(const X509_PUBLIC_KEY_INFO *a, uint8_t **out, size_t *outlen); +int x509_public_key_info_from_der(X509_PUBLIC_KEY_INFO *a, const uint8_t **in, size_t *inlen); +int x509_public_key_info_print(FILE *fp, const X509_PUBLIC_KEY_INFO *a, int format, int indent); + +/* +Extension ::= SEQUENCE { + extnID OBJECT IDENTIFIER, + critical BOOLEAN DEFAULT FALSE, + extnValue OCTET STRING -- contains the DER encoding of an ASN.1 value +*/ +const char *x509_extension_oid_name(int oid); +int x509_extension_oid_to_der(int oid, uint8_t **out, size_t *outlen); +int x509_extension_oid_from_der(int *oid, uint32_t *nodes, size_t *nodes_count, const uint8_t **in, size_t *inlen); + +int x509_extension_to_der(int oid, + int is_critical, const uint8_t *data, size_t datalen, + uint8_t **out, size_t *outlen); +int x509_extension_from_der(int *oid, uint32_t *nodes, size_t *nodes_count, + int *is_critical, const uint8_t **data, size_t *datalen, + const uint8_t **in, size_t *inlen); +int x509_extension_print(FILE *fp, int oid, const uint32_t *nodes, size_t nodes_count, + int is_critical, const uint8_t *data, size_t datalen, + int format, int indent); + +typedef struct { + size_t datalen; + uint8_t data[2048]; +} X509_EXTENSIONS; + +int x509_extensions_add_item(X509_EXTENSIONS *a, + int oid, int is_critical, const uint8_t *data, size_t datalen); +int x509_extensions_get_next_item(const X509_EXTENSIONS *a, const uint8_t **next, + int *oid, uint32_t *nodes, size_t *nodes_count, + int *is_critical, const uint8_t **data, size_t *datalen); +int x509_extensions_print(FILE *fp, const X509_EXTENSIONS *a, int format, int indent); + + + + + + +typedef struct { + int version; // [0] EXPLICIT INTEGER DEFAULT v1 + uint8_t serial_number[20]; // INTEGER + size_t serial_number_len; + int signature_algor; // AlgorithmIdentifier + X509_NAME issuer; + X509_VALIDITY validity; + X509_NAME subject; + X509_PUBLIC_KEY_INFO subject_public_key_info; + uint8_t issuer_unique_id[64]; // [1] IMPLICIT BIT STRING OPTIONAL + size_t issuer_unique_id_len; + uint8_t subject_unique_id[64]; // [2] IMPLICIT BIT STRING OPTIONAL + size_t subject_unique_id_len; + X509_EXTENSIONS extensions; // [3] EXPLICIT, If present, version MUST be v3 +} X509_TBS_CERTIFICATE; + +int x509_tbs_certificate_to_der(const X509_TBS_CERTIFICATE *a, uint8_t **out, size_t *outlen); +int x509_tbs_certificate_from_der(X509_TBS_CERTIFICATE *a, const uint8_t **in, size_t *inlen); + + + +/* +Certificate ::= SEQUENCE { + tbsCertificate TBSCertificate, + signatureAlgorithm AlgorithmIdentifier, + signatureValue BIT STRING } +*/ +typedef struct { + X509_TBS_CERTIFICATE tbs_certificate; + int signature_algor; + uint8_t signature[256]; + size_t signature_len; +} X509_CERTIFICATE; + + +int x509_certificate_set_version(X509_CERTIFICATE *cert, int version); +int x509_certificate_set_serial_number(X509_CERTIFICATE *cert, const uint8_t *sn, size_t snlen); +int x509_certificate_set_signature_algor(X509_CERTIFICATE *cert, int oid); // 这个应该直接指定SM2吗? +int x509_certificate_set_issuer(X509_CERTIFICATE *cert, const X509_NAME *name); +int x509_certificate_set_subject(X509_CERTIFICATE *cert, const X509_NAME *name); +int x509_certificate_set_validity(X509_CERTIFICATE *cert, time_t not_before, int days); +int x509_certificate_set_subject_public_key_info_sm2(X509_CERTIFICATE *cert, const SM2_KEY *sm2_key); +int x509_certificate_set_issuer_unique_id(X509_CERTIFICATE *cert, const uint8_t *id, size_t idlen); +int x509_certificate_set_subject_unique_id(X509_CERTIFICATE *cert, const uint8_t *id, size_t idlen); +int x509_certificate_set_issuer_unique_id_from_public_key_sm2(X509_CERTIFICATE *cert, const SM2_KEY *sm2_key); +int x509_certificate_set_subject_unique_id_from_public_key_sm2(X509_CERTIFICATE *cert, const SM2_KEY *sm2_key); +#define x509_certificate_set_subject_public_key_info(c,pk) x509_certificate_set_subject_public_key_info_sm2((c),(pk)) +#define x509_certificate_set_issuer_unique_id_from_public_key(c,pk) x509_certificate_set_issuer_unique_id_from_public_key_sm2((c),(pk)) +#define x509_certificate_set_subject_unique_id_from_public_key(c,pk) x509_certificate_set_subject_unique_id_from_public_key_sm2((c),(pk)) + + +int x509_certificate_add_extension(X509_CERTIFICATE *a, int oid, int is_critical, + const uint8_t *data, size_t datalen); +int x509_certificate_get_extension_from_oid(const X509_CERTIFICATE *a, int oid, + int *is_critical, const uint8_t **data, size_t *datalen); + +int x509_certificate_sign_sm2(X509_CERTIFICATE *cert, const SM2_KEY *key); +int x509_certificate_verify_sm2(const X509_CERTIFICATE *cert, const SM2_KEY *sm2_key); +int x509_certificate_get_public_key_sm2(const X509_CERTIFICATE *cert, SM2_KEY *sm2_key); +#define x509_certificate_sign(c,sk) x509_certificate_sign_sm2((c),(sk)) +#define x509_certificate_verify(c,pk) x509_certificate_verify_sm2((c),(pk)) +#define x509_certificate_get_public_key(c,pk) x509_certificate_get_public_key_sm2((c),(pk)) + +int x509_certificate_to_der(const X509_CERTIFICATE *a, uint8_t **out, size_t *outlen); +int x509_certificate_to_pem(const X509_CERTIFICATE *a, FILE *fp); +int x509_certificate_from_der(X509_CERTIFICATE *a, const uint8_t **in, size_t *inlen); +int x509_certificate_from_pem(X509_CERTIFICATE *a, FILE *fp); +int x509_certificate_print(FILE *fp, const X509_CERTIFICATE *a, int format, int indent); + +int x509_certificate_from_pem_by_name(X509_CERTIFICATE *cert, FILE *certs_fp, const X509_NAME *issuer); + +int x509_certificate_verify_by_certificate(const X509_CERTIFICATE *cert, const X509_CERTIFICATE *cacert); + + + + + + + +// Extension 1 AuthorityKeyIdentifier + +/* +OtherName ::= SEQUENCE { + type-id OBJECT IDENTIFIER, + value [0] EXPLICIT ANY DEFINED BY type-id } +*/ +int x509_other_name_to_der_ex(int tag, + int oid, const uint32_t *nodes, size_t nodes_count, + const uint8_t *value, size_t valuelen, + uint8_t **out, size_t *outlen); + +int x509_other_name_from_der_ex(int tag, + int *oid, uint32_t *nodes, size_t *nodes_count, + const uint8_t **value, size_t *valuelen, + const uint8_t **in, size_t *inlen); + +/* +EDIPartyName ::= SEQUENCE { + nameAssigner [0] DirectoryString OPTIONAL, + partyName [1] DirectoryString } +*/ +int x509_edi_party_name_to_der_ex( + int tag, + int assigner_tag, const char *assigner, size_t assigner_len, + int party_name_tag, const char *party_name, size_t party_name_len, + uint8_t **out, size_t *outlen); + +int x509_edi_party_name_from_der_ex( + int tag, + int *assigner_tag, const char **assigner, size_t *assigner_len, + int *party_name_tag, const char **party_name, size_t *party_name_len, + const uint8_t **in, size_t *inlen); + +/* +GeneralName ::= CHOICE { + otherName [0] OtherName, + rfc822Name [1] IA5String, + dNSName [2] IA5String, + x400Address [3] ORAddress, + directoryName [4] Name, + ediPartyName [5] EDIPartyName, + uniformResourceIdentifier [6] IA5String, + iPAddress [7] OCTET STRING, + registeredID [8] OBJECT IDENTIFIER + } +*/ +enum { + X509_gn_otherName = 0, + X509_gn_rfc822Name, + X509_gn_dnsName, + X509_gn_x400Address, + X509_gn_directoryName, + X509_gn_ediPartyName, + X509_gn_uniformResourceIdentifier, + X509_gn_ipAddress, + X509_gn_registeredID, +}; + +int x509_general_name_to_der(int choice, const uint8_t *data, size_t datalen, uint8_t **out, size_t *outlen); +int x509_general_name_from_der(int *choice, const uint8_t **data, size_t *datalen, const uint8_t **in, size_t *inlen); + + +typedef struct { + size_t datalen; + uint8_t data[256]; +} X509_GENERAL_NAMES; + +int x509_general_names_add_item(X509_GENERAL_NAMES *a, int choice, const uint8_t *data, size_t datalen); +int x509_general_names_get_next_item(const X509_GENERAL_NAMES *a, const uint8_t **next, + int *choice, const uint8_t **data, size_t *datalen); + +#define x509_general_names_to_der(a,d,dl) \ + asn1_sequence_to_der((a)->data,(a)->datalen,d,dl) + +#define x509_general_names_from_der(a,d,dl) \ + asn1_sequence_copy_from_der((a)->data,&((a)->datalen),d,dl) + +#define x509_implicit_general_names_to_der(i,a,d,dl) \ + asn1_type_to_der(ASN1_TAG_EXPLICIT(i),(a)->data,(a)->datalen,d,dl) + +#define x509_implicit_general_names_from_der(i,a,d,dl) \ + asn1_type_copy_from_der(ASN1_TAG_EXPLICIT(i),256,(a)->data,&((a)->datalen),d,dl) + + +/* +Extension 1 +AuthorityKeyIdentifier ::= SEQUENCE { + keyIdentifier [0] IMPLICIT OCTET STRING OPTIONAL, + authorityCertIssuer [1] IMPLICIT GeneralNames OPTIONAL, + authorityCertSerialNumber [2] IMPLICIT INTEGER OPTIONAL +} + 在验证证书时,签名方公钥是通过 issuer 在备选的CA证书列表中检索得到的 + 但是某些CA可能存在一个同一个名字对应了多个证书,因此需要一个格外的公钥ID + 也许我们可以对所有这种SEQUENCE OF类型的都支持一个IMPLICIT + +用于从多个subject同名的CA证书中挑选出需要的证书 + + * 如果这些同名CA证书中使用的公钥不同,那么这些公钥的key_id不同 + * 如果这些同名CA证书(不是根CA证书)是由不同的上级CA签发,那么可以由issuer来区分 + * 如果这些同名CA证书的序列号 + + +AuthorityKeyIdentifier 扩展中包含签发该证书的上级CA证书的部分信息 +*/ + +int x509_authority_key_identifier_to_der( + const uint8_t *keyid, size_t keyid_len, + const X509_GENERAL_NAMES *issuer, + const uint8_t *serial_number, size_t serial_number_len, + uint8_t **out, size_t *outlen); + +int x509_authority_key_identifier_from_der( + const uint8_t **keyid, size_t *keyid_len, + X509_GENERAL_NAMES *issuer, + const uint8_t **serial_number, size_t *serial_number_len, + const uint8_t **in, size_t *inlen); + +int x509_certificate_set_authority_key_identifier(X509_CERTIFICATE *cert, + int is_critical, + const uint8_t *keyid, size_t keyid_len, + const X509_GENERAL_NAMES *issuer, + const uint8_t *serial_number, size_t serial_number_len); + +int x509_certificate_get_authority_key_identifier(const X509_CERTIFICATE *cert, + int *is_critical, + const uint8_t **keyid, size_t *keyid_len, + X509_GENERAL_NAMES *issuer, + const uint8_t **serial_number, size_t *serial_number_len); + +/* +Extension 2 +SubjectKeyIdentifier ::= OCTET STRING +*/ +int x509_certificate_set_subject_key_identifier(X509_CERTIFICATE *cert, + int is_critical, + const uint8_t *keyid, size_t keyid_len); + +// keyid = sm3(uncompressed_sm2_public_key_point) +int x509_certificate_generate_subject_key_identifier(X509_CERTIFICATE *cert, + int is_critical); + +int x509_certificate_get_subject_key_identifier(const X509_CERTIFICATE *cert, + int *is_critical, + const uint8_t **keyid, size_t *keyid_len); + + +int x509_subject_key_identifier_print(FILE *fp, const uint8_t *data, size_t datalen, int format, int indent); + + +/* +Extension 3 KeyUsage + +KeyUsage ::= BIT STRING { + digitalSignature (0), + nonRepudiation (1), -- recent editions of X.509 have + -- renamed this bit to contentCommitment + keyEncipherment (2), + dataEncipherment (3), + keyAgreement (4), + keyCertSign (5), + cRLSign (6), + encipherOnly (7), + decipherOnly (8) } +*/ +enum X509_KeyUsage { + X509_ku_digital_signature = 0, + X509_ku_non_repudiation, // -- renamed this bit to contentCommitment + X509_ku_key_encipherment, + X509_ku_data_encipherment, + X509_ku_key_agreement, + X509_ku_key_cert_sign, + X509_ku_crl_sign, + X509_ku_encipher_only, + X509_ku_decipher_only, +}; + +int x509_certificate_set_key_usage(X509_CERTIFICATE *cert, + int is_critical, + int usage_bits); + +int x509_certificate_get_key_usage(const X509_CERTIFICATE *cert, + int *is_critical, + int *usage_bits); + + +// Extension 4 CertificatePolicies + +/* + DisplayText ::= CHOICE { + ia5String IA5String (SIZE (1..200)), + visibleString VisibleString (SIZE (1..200)), + bmpString BMPString (SIZE (1..200)), + utf8String UTF8String (SIZE (1..200)) } +*/ +int x509_display_text_to_der(int tag, const char *text, size_t textlen, uint8_t **out, size_t *outlen); +int x509_display_text_from_der(int *tag, const char **text, size_t *textlen, const uint8_t **in, size_t *inlen); + + +/* +NoticeReference ::= SEQUENCE { + organization DisplayText, + noticeNumbers SEQUENCE OF INTEGER } +*/ +int x509_notice_reference_to_der( + int organization_tag, const char *organization, size_t organization_len, + const int *notice_numbers, size_t notice_numbers_count, + uint8_t **out, size_t *outlen); + +int x509_notice_reference_from_der( + int *organization_tag, const char **organization, size_t *organization_len, + int *notice_numbers, size_t *notice_numbers_count, + const uint8_t **in, size_t *inlen); + +/* +UserNotice ::= SEQUENCE { + noticeRef NoticeReference OPTIONAL, + explicitText DisplayText OPTIONAL } +*/ +int x509_user_notice_to_der( + const uint8_t *notice_ref_der, size_t notice_ref_der_len, + int explicit_text_tag, const char *explicit_text, size_t explicit_text_len, + uint8_t **out, size_t *outlen); + +int x509_user_notice_from_der( + const uint8_t **notice_ref_der, size_t *notice_ref_der_len, + int *explicit_text_tag, const char **explicit_text, size_t *explicit_text_len, + const uint8_t **in, size_t *inlen); + +/* +PolicyQualifierInfo ::= SEQUENCE { + policyQualifierId PolicyQualifierId, + qualifier ANY DEFINED BY policyQualifierId } + + switch(policyQualifierId) + case id-qt-cps : qualifier ::= IA5String + case id-qt-unotice : qualifier ::= UserNotice +*/ +int x509_policy_qualifier_info_to_der(int oid, + const uint8_t *qualifier, size_t qualifier_len, + uint8_t **out, size_t *outlen); + +int x509_policy_qualifier_info_from_der(int *oid, + const uint8_t **qualifier, size_t *qualifier_len, + const uint8_t **in, size_t *inlen); + +/* +PolicyInformation ::= SEQUENCE { + policyIdentifier CertPolicyId, + policyQualifiers SEQUENCE SIZE (1..MAX) OF + PolicyQualifierInfo OPTIONAL } + +CertPolicyId ::= OBJECT IDENTIFIER +*/ +typedef struct { + size_t datalen; + uint8_t data[256]; +} X509_POLICY_QUALIFIER_INFOS; + +int x509_policy_qualifier_infos_add_item(X509_POLICY_QUALIFIER_INFOS *a, + int oid, const uint8_t *qualifier, size_t qualifier_len); + +int x509_policy_qualifier_infos_get_next_item(const X509_POLICY_QUALIFIER_INFOS *a, const uint8_t **next, + int *oid, const uint8_t **qualifier, size_t *qualifier_len); + +#define x509_policy_qualifier_infos_to_der(a,d,dl) \ + asn1_sequence_to_der((a)->data,(a)->datalen,d,dl) + +#define x509_policy_qualifier_infos_from_der(a,d,dl) \ + asn1_sequence_copy_from_der(256, (a)->data,&((a)->datalen),d,dl) + +int x509_policy_information_to_der( + int oid, const uint32_t *nodes, size_t nodes_count, + const X509_POLICY_QUALIFIER_INFOS *qualifiers, + uint8_t **out, size_t *outlen); + +int x509_policy_information_from_der( + int *oid, uint32_t *nodes, size_t *nodes_count, + X509_POLICY_QUALIFIER_INFOS *qualifiers, + const uint8_t **in, size_t *inlen); + +/* +Extension 4 Certificate Policies +CertificatePolicies ::= SEQUENCE SIZE (1..MAX) OF PolicyInformation +*/ +typedef struct { + size_t datalen; + uint8_t data[1024]; +} X509_CERTIFICATE_POLICIES; + +int x509_certificate_policies_add_item(X509_CERTIFICATE_POLICIES *a, + int oid, const uint32_t *nodes, size_t nodes_count, + const X509_POLICY_QUALIFIER_INFOS *qualifiers); + +int x509_certificate_policies_get_next_item(const X509_CERTIFICATE_POLICIES *a, const uint8_t **next, + int *oid, const uint32_t *nodes, size_t *nodes_count, + X509_POLICY_QUALIFIER_INFOS *qualifiers); + +#define x509_certificate_policies_to_der(a,d,dl) \ + asn1_sequence_to_der((a)->data,(a)->datalen,d,dl) + +#define x509_certificate_policies_from_der(a,d,dl) \ + asn1_sequence_copy_from_der(1024, (a)->data,&((a)->datalen),d,dl) + + + +int x509_certificate_set_certificate_policies(X509_CERTIFICATE *cert, + int is_critical, + const X509_CERTIFICATE_POLICIES *policies); + +int x509_certificate_get_certificate_policies(const X509_CERTIFICATE *cert, + int *is_critical, + X509_CERTIFICATE_POLICIES *policies); + + + +// Extension 5. Policy Mappings + +/* + PolicyMappings ::= SEQUENCE SIZE (1..MAX) OF SEQUENCE { + issuerDomainPolicy CertPolicyId, + subjectDomainPolicy CertPolicyId } +*/ +int x509_policy_mapping_to_der( + int issuer_policy_oid, const uint32_t *issuer_policy_nodes, size_t issuer_policy_nodes_count, + int subject_policy_oid, const uint32_t *subject_policy_nodes, size_t subject_policy_nodes_count, + uint8_t **out, size_t *outlen); + +int x509_policy_mapping_from_der( + int *issuer_policy_oid, uint32_t *issuer_policy_nodes, size_t *issuer_policy_nodes_count, + int *subject_policy_oid, uint32_t *subject_policy_nodes, size_t *subject_policy_nodes_count, + const uint8_t **in, size_t *inlen); + +typedef struct { + size_t datalen; + uint8_t data[1024]; +} X509_POLICY_MAPPINGS; + +int x509_policy_mappings_add_item(X509_POLICY_MAPPINGS *a, + int issuer_policy_oid, const uint32_t *issuer_policy_nodes, size_t issuer_policy_nodes_count, + int subject_policy_oid, const uint32_t *subject_policy_nodes, size_t subject_policy_nodes_count); +int x509_policy_mappings_get_next_item(const X509_POLICY_MAPPINGS *a, const uint8_t **next, + uint32_t *issuer_policy_nodes, size_t *issuer_policy_nodes_count, + uint32_t *subject_policy_nodes, size_t *subject_policy_nodes_count); + +#define x509_policy_mappings_to_der(a,d,dl) \ + asn1_sequence_to_der((a)->data,(a)->datalen,d,dl) + +#define x509_policy_mappings_from_der(a,d,dl) \ + asn1_sequence_copy_from_der(1024,(a)->data,&((a)->datalen),d,dl) + + +int x509_certificate_set_policy_mappings(X509_CERTIFICATE *cert, + int is_critical, + const X509_POLICY_MAPPINGS *mappings); + +int x509_certificate_get_policy_mappings(const X509_CERTIFICATE *cert, + int *is_critical, + X509_POLICY_MAPPINGS *mappings); + + +// Extension 6 Subject Alternative Names +// SubjectAltName ::= GeneralNames + +int x509_certificate_set_subject_alt_name(X509_CERTIFICATE *a, + int is_critical, + const X509_GENERAL_NAMES *name); + +int x509_certificate_get_subject_alt_name(const X509_CERTIFICATE *a, + int *is_critical, + X509_GENERAL_NAMES *name); + + +// Extension 7 Issuer Alternative Name +// IssuerAltName ::= GeneralNames + +int x509_certificate_set_issuer_alt_name(X509_CERTIFICATE *a, + int is_critical, + const X509_GENERAL_NAMES *name); + +int x509_certificate_get_issuer_alt_name(X509_CERTIFICATE *a, + int *is_critical, + X509_GENERAL_NAMES *name); + +// Extension 8. Subject Directory Attributes +/* +SubjectDirectoryAttributes ::= SEQUENCE SIZE (1..MAX) OF Attribute + +Attribute ::= SEQUENCE { + type OBJECT IDENTIFIER, + values SET OF AttributeValue } + -- at least one value is required + + AttributeValue ::= ANY + + Conforming CAs MUST mark this extension as non-critical. +*/ +int x509_attribute_to_der( + int oid, const uint32_t *nodes, size_t nodes_count, + const uint8_t *values, size_t valueslen, + uint8_t **out, size_t *outlen); +int x509_attribute_from_der( + int *oid, uint32_t *nodes, size_t *nodes_count, + const uint8_t **values, size_t *valueslen, + const uint8_t **in, size_t *inlen); + +typedef struct { + size_t datalen; + uint8_t data[128]; +} X509_ATTRIBUTES; + +int x509_attributes_add_item(X509_ATTRIBUTES *a, + int oid, const uint32_t *nodes, size_t nodes_count, + const uint8_t *values, size_t valueslen); + +int x509_attributes_get_next_item(const X509_ATTRIBUTES *a, const uint8_t **next, + int *oid, uint32_t *nodes, size_t *nodes_count, + const uint8_t **data, size_t *datalen); + +#define x509_attributes_to_der(a,d,dl) \ + asn1_sequence_to_der((a)->data,(a)->datalen,d,dl) + +#define x509_attributes_from_der(a,d,dl) \ + asn1_sequence_copy_from_der(128,(a)->data,&((a)->datalen),d,dl) + + +int x509_certificate_set_subject_directory_attributes(X509_CERTIFICATE *cert, + int is_critical, + const X509_ATTRIBUTES *attrs); + +int x509_certificate_get_subject_directory_attributes(const X509_CERTIFICATE *cert, + int *is_critical, + X509_ATTRIBUTES *attrs); + + + + +// Extension 9. Basic Constraints +/* +BasicConstraints ::= SEQUENCE { + cA BOOLEAN DEFAULT FALSE, + pathLenConstraint INTEGER (0..MAX) OPTIONAL } +*/ + +int x509_basic_constraints_to_der(int is_ca_cert, // 必须设置为 0 或 1,如果设为 0 那么不编码 + int cert_chain_maxlen, // -1 means omitted,FIXME: 应该设置一个最大值 + uint8_t **out, size_t *outlen); + +int x509_basic_constraints_from_der(int *is_ca_cert, int *cert_chain_maxlen, const uint8_t **in, size_t *inlen); + +int x509_certificate_set_basic_constraints(X509_CERTIFICATE *cert, + int is_critical, + int is_ca_cert, + int cert_chain_maxlen); + +int x509_certificate_get_basic_constraints(const X509_CERTIFICATE *cert, + int *is_critical, + int *is_ca_cert, + int *cert_chain_maxlen); + +int x509_basic_constraints_print(FILE *fp, const uint8_t *data, size_t datalen, int format, int indent); +int x509_key_usage_print(FILE *fp, const uint8_t *data, size_t datalen, int format, int indent); +int x509_authority_key_identifier_print(FILE *fp, const uint8_t *data, size_t datalen, int format, int indent); + + + +// Extension 10. Name Constraints +/* + NameConstraints ::= SEQUENCE { + permittedSubtrees [0] GeneralSubtrees OPTIONAL, + excludedSubtrees [1] GeneralSubtrees OPTIONAL } + + GeneralSubtrees ::= SEQUENCE SIZE (1..MAX) OF GeneralSubtree + + GeneralSubtree ::= SEQUENCE { + base GeneralName, + minimum [0] BaseDistance DEFAULT 0, + maximum [1] BaseDistance OPTIONAL } + + BaseDistance ::= INTEGER (0..MAX) +*/ +int x509_general_subtree_to_der( + int base_choise, const uint8_t *base_data, size_t base_datalen, + int minimum, + int maximum, + uint8_t **out, size_t *outlen); +int x509_general_subtree_from_der( + int *base_choise, const uint8_t **base_data, size_t *base_datalen, + int *minimum, + int *maximum, + const uint8_t **in, size_t *inlen); + +typedef struct { + size_t datalen; + uint8_t data[128]; +} X509_GENERAL_SUBTREES; + +int x509_general_subtrees_add_item(X509_GENERAL_SUBTREES *a, + int base_choise, const uint8_t *base_data, size_t base_datalen, + int minimum, + int maximum); +int x509_general_subtrees_get_next_item(const X509_GENERAL_SUBTREES *a, const uint8_t **next, + int *base_choise, const uint8_t **base_data, size_t *base_datalen, + int *minimum, + int *maximum); + +int x509_general_subtrees_to_der_ex(int tag, const X509_GENERAL_SUBTREES *a, uint8_t **out, size_t *outlen); +int x509_general_subtrees_from_der_ex(int tag, X509_GENERAL_SUBTREES *a, const uint8_t **in, size_t *inlen); + +#define x509_general_subtrees_to_der(a,d,dl) \ + asn1_sequence_to_der((a)->data,(a)->datalen,d,dl) + +#define x509_general_subtrees_from_der(a,d,dl) \ + asn1_sequence_copy_from_der(128,(a)->data,&((a)->datalen),d,dl) + +int x509_name_constraints_to_der( + const X509_GENERAL_SUBTREES *permitted_subtrees, + const X509_GENERAL_SUBTREES *excluded_subtrees, + uint8_t **out, size_t *outlen); + +int x509_name_constraints_from_der( + X509_GENERAL_SUBTREES *permitted_subtrees, + X509_GENERAL_SUBTREES *excluded_subtrees, + const uint8_t **in, size_t *inlen); + +int x509_certificate_set_name_constraints(X509_CERTIFICATE *cert, + int is_critical, + const X509_GENERAL_SUBTREES *permitted_subtrees, + const X509_GENERAL_SUBTREES *excluded_subtrees); + +int x509_certificate_get_name_constraints(X509_CERTIFICATE *cert, + int *is_critical, + X509_GENERAL_SUBTREES *permitted_subtrees, + X509_GENERAL_SUBTREES *excluded_subtrees); + + + +// Extension 11. Policy Constraints +/* + PolicyConstraints ::= SEQUENCE { + requireExplicitPolicy [0] SkipCerts OPTIONAL, + inhibitPolicyMapping [1] SkipCerts OPTIONAL } + + SkipCerts ::= INTEGER (0..MAX) +*/ + +int x509_policy_constraints_to_der( + int require_explicit_policy, + int inhibit_policy_mapping, + uint8_t **out, size_t *outlen); + +int x509_policy_constraints_from_der( + int *require_explicit_policy, + int *inhibit_policy_mapping, + const uint8_t **in, size_t *inlen); + +int x509_certificate_set_policy_constraints(X509_CERTIFICATE *cert, + int is_critical, + int require_explicit_policy, + int inhibit_policy_mapping); + +int x509_certificate_get_policy_constraints(const X509_CERTIFICATE *cert, + int *is_critical, + int *requireExplicitPolicy, + int *inhibitPolicyMapping); + + +/* +12. Extended Key Usage + + ExtKeyUsageSyntax ::= SEQUENCE SIZE (1..MAX) OF KeyPurposeId + KeyPurposeId ::= OBJECT IDENTIFIER + +*/ +int x509_key_purpose_from_name(int *oid, const char *name); +const char *x509_key_purpose_name(int oid); +const char *x509_key_purpose_text(int oid); +int x509_key_purpose_to_der(int oid, uint8_t **out, size_t *outlen); +int x509_key_purpose_from_der(int *oid, const uint8_t **in, size_t *inlen); +int x509_ext_key_usage_to_der(const int *oids, size_t oids_count, uint8_t **out, size_t *outlen); +int x509_ext_key_usage_from_der(int *oids, size_t *oids_count, const uint8_t **in, size_t *inlen); + +int x509_certificate_set_ext_key_usage(X509_CERTIFICATE *cert, + int is_critical, + const int *key_purpose_oids, size_t key_purpose_oids_count); + +int x509_certificate_get_ext_key_usage(const X509_CERTIFICATE *cert, + int *is_critical, + int *key_purpose_oids, size_t *key_purpose_oids_count); + +/* + +13. CRL Distribution Points + + CRLDistributionPoints ::= SEQUENCE SIZE (1..MAX) OF DistributionPoint + + DistributionPoint ::= SEQUENCE { + distributionPoint [0] DistributionPointName OPTIONAL, + reasons [1] ReasonFlags OPTIONAL, + cRLIssuer [2] GeneralNames OPTIONAL } + + DistributionPointName ::= CHOICE { + fullName [0] GeneralNames, + nameRelativeToCRLIssuer [1] RelativeDistinguishedName } + + 由于 GeneralNames 是存储类型,因此 DistributionPointName 也是存储类型 + + ReasonFlags ::= BIT STRING { + unused (0), + keyCompromise (1), + cACompromise (2), + affiliationChanged (3), + superseded (4), + cessationOfOperation (5), + certificateHold (6), + privilegeWithdrawn (7), + aACompromise (8) } +*/ +enum { + X509_rf_unused = 0, + X509_rf_keyCompromise, + X509_rf_caCompromise, + X509_rf_affiliationChanged, + X509_rf_superseded, + X509_rf_cessationOfOperation, + X509_rf_certificateHold, + X509_rf_privilegeWithdrawn, + X509_rf_aaCompromise, +}; + +typedef struct { + int choice; + union { + X509_GENERAL_NAMES full_name; // [0] IMPLICIT + X509_RDN relative_name; // [1] IMPLICIT + } u; +} X509_DISTRIBUTION_POINT_NAME; + +int x509_distribution_point_name_to_der_ex( + int tag, + const X509_DISTRIBUTION_POINT_NAME *a, + uint8_t **out, size_t *outlen); + +int x509_distribution_point_name_from_der_ex( + int tag, + X509_DISTRIBUTION_POINT_NAME *a, + const uint8_t **in, size_t *inlen); + + +int x509_distribution_point_to_der( // DistributionPoint + const X509_DISTRIBUTION_POINT_NAME *dist_point_name, // [0] EXPLICIT OPTIONAL + int reason_bits, // [1] IMPLICIT OPTIONAL + const X509_GENERAL_NAMES *crl_issuer, // [2] IMPLICIT OPTIONAL + uint8_t **out, size_t *outlen); + +int x509_distribution_point_from_der( + X509_DISTRIBUTION_POINT_NAME *dist_point_name, + int *reason_bits, + X509_GENERAL_NAMES *crl_issuer, + const uint8_t **in, size_t *inlen); + +typedef struct { + size_t datalen; + uint8_t data[128]; +} X509_CRL_DISTRIBUTION_POINTS; + +int x509_crl_distribution_points_add_item(X509_CRL_DISTRIBUTION_POINTS *a, + const X509_DISTRIBUTION_POINT_NAME *dist_point_name, + int reason_bits, + const X509_GENERAL_NAMES *crl_issuer); +int x509_crl_distribution_points_get_next_item(const X509_CRL_DISTRIBUTION_POINTS *a, + const uint8_t **next, + X509_DISTRIBUTION_POINT_NAME *distribution_point, + int *reasons, + X509_GENERAL_NAMES *crl_issuer); +int x509_crl_distribution_points_to_der(const X509_CRL_DISTRIBUTION_POINTS *a, uint8_t **out, size_t *outlen); +int x509_crl_distribution_points_from_der(X509_CRL_DISTRIBUTION_POINTS *a, const uint8_t **in, size_t *inlen); + +int x509_certificate_set_crl_distribution_points(X509_CERTIFICATE *cert, + int is_critical, + const X509_CRL_DISTRIBUTION_POINTS *crl_dist_points); + +int x509_certificate_get_crl_distribution_points(const X509_CERTIFICATE *cert, + int *is_critical, + X509_CRL_DISTRIBUTION_POINTS *crl_dist_points); + + +/* +14. Inhibit anyPolicy + + id-ce-inhibitAnyPolicy OBJECT IDENTIFIER ::= { id-ce 54 } + + InhibitAnyPolicy ::= SkipCerts + + SkipCerts ::= INTEGER (0..MAX) +*/ +int x509_certificate_set_inhibit_any_policy(X509_CERTIFICATE *cert, + int is_critical, + int skip_certs); +int x509_certificate_get_inhibit_any_policy(const X509_CERTIFICATE *cert, + int *is_critical, + int *skip_certs); + +/* +15. Freshest CRL (a.k.a. Delta CRL Distribution Point) +FreshestCRL ::= CRLDistributionPoints +*/ +int x509_certificate_set_freshest_crl(X509_CERTIFICATE *cert, + int is_critical, + const X509_CRL_DISTRIBUTION_POINTS *crl_dist_points); +int x509_certificate_get_freshest_crl(const X509_CERTIFICATE *cert, + int *is_critical, + X509_CRL_DISTRIBUTION_POINTS *crl_dist_points); + + +#define X509_ub_name 32768 +#define X509_ub_common_name 64 +#define X509_ub_locality_name 128 +#define X509_ub_state_name 128 +#define X509_ub_organization_name 64 +#define X509_ub_organizational_unit_name 64 +#define X509_ub_title 64 +#define X509_ub_serial_number 64 +#define X509_ub_match 128 +#define X509_ub_emailaddress_length 255 +#define X509_ub_common_name_length 64 +#define X509_ub_country_name_alpha_length 2 +#define X509_ub_country_name_numeric_length 3 +#define X509_ub_domain_defined_attributes 4 +#define X509_ub_domain_defined_attribute_type_length 8 +#define X509_ub_domain_defined_attribute_value_length 128 +#define X509_ub_domain_name_length 16 +#define X509_ub_extension_attributes 256 +#define X509_ub_e163_4_number_length 15 +#define X509_ub_e163_4_sub_address_length 40 +#define X509_ub_generation_qualifier_length 3 +#define X509_ub_given_name_length 16 +#define X509_ub_initials_length 5 +#define X509_ub_integer_options 256 +#define X509_ub_numeric_user_id_length 32 +#define X509_ub_organization_name_length 64 +#define X509_ub_organizational_unit_name_length 32 +#define X509_ub_organizational_units 4 +#define X509_ub_pds_name_length 16 +#define X509_ub_pds_parameter_length 30 +#define X509_ub_pds_physical_address_lines 6 +#define X509_ub_postal_code_length 16 +#define X509_ub_pseudonym 128 +#define X509_ub_surname_length 40 +#define X509_ub_terminal_id_length 24 +#define X509_ub_unformatted_address_length 180 +#define X509_ub_x121_address_length 16 + + +typedef struct { + int version; + X509_NAME subject; + X509_PUBLIC_KEY_INFO subject_public_key_info; +} X509_CERT_REQUEST_INFO; + +int x509_cert_request_info_to_der(const X509_CERT_REQUEST_INFO *a, uint8_t **out, size_t *outlen); +int x509_cert_request_info_from_der(X509_CERT_REQUEST_INFO *a, const uint8_t **in, size_t *inlen); + +typedef struct { + X509_CERT_REQUEST_INFO req_info; + int signature_algor; + uint8_t signature[128]; + size_t signature_len; +} X509_CERT_REQUEST; + +int x509_cert_request_set_sm2(X509_CERT_REQUEST *a, const X509_NAME *subject, const SM2_KEY *sm2_key); +int x509_cert_request_sign_sm2(X509_CERT_REQUEST *a, const SM2_KEY *sm2_key); +int x509_cert_request_verify(const X509_CERT_REQUEST *a); +#define x509_cert_request_set(a,subj,pk) x509_cert_request_set_sm2((a),(subj),(pk)) +#define x509_cert_request_sign(a,sk) x509_cert_request_sign_sm2((a),(sk)) + +int x509_cert_request_to_der(const X509_CERT_REQUEST *a, uint8_t **out, size_t *outlen); +int x509_cert_request_to_pem(const X509_CERT_REQUEST *a, FILE *fp); +int x509_cert_request_from_der(X509_CERT_REQUEST *a, const uint8_t **in, size_t *inlen); +int x509_cert_request_from_pem(X509_CERT_REQUEST *a, FILE *fp); +int x509_cert_request_print(FILE *fp, const X509_CERT_REQUEST *a, int format, int indent); + + +#ifdef __cplusplus +} +#endif +#endif diff --git a/include/gmssl/zuc.h b/include/gmssl/zuc.h new file mode 100755 index 00000000..aabea41e --- /dev/null +++ b/include/gmssl/zuc.h @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2014 - 2021 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + +#ifndef GMSSL_ZUC_H +#define GMSSL_ZUC_H + +#include +#include + +typedef uint32_t ZUC_BIT; +typedef uint32_t ZUC_UINT5; +typedef uint8_t ZUC_UINT6; +typedef uint32_t ZUC_UINT15; +typedef uint32_t ZUC_UINT31; +typedef uint32_t ZUC_UINT32; + +#ifdef __cplusplus +extern "C" { +#endif + + +# define ZUC_KEY_LENGTH 16 +# define ZUC_IV_LENGTH 16 +# define ZUC_MAC_LENGTH 4 + + +typedef struct ZUC_KEY_st { + ZUC_UINT31 LFSR[16]; + ZUC_UINT32 R1; + ZUC_UINT32 R2; +} ZUC_KEY; + +void zuc_set_key(ZUC_KEY *key, const unsigned char user_key[16], const unsigned char iv[16]); +void zuc_generate_keystream(ZUC_KEY *key, size_t nwords, ZUC_UINT32 *words); +ZUC_UINT32 zuc_generate_keyword(ZUC_KEY *key); + +typedef struct ZUC_MAC_CTX_st { + ZUC_UINT31 LFSR[16]; + ZUC_UINT32 R1; + ZUC_UINT32 R2; + ZUC_UINT32 T; + ZUC_UINT32 K0; + unsigned char buf[4]; + int buflen; +} ZUC_MAC_CTX; + +void zuc_mac_init(ZUC_MAC_CTX *ctx, const unsigned char key[16], const unsigned char iv[16]); +void zuc_mac_update(ZUC_MAC_CTX *ctx, const unsigned char *data, size_t len); +void zuc_mac_finish(ZUC_MAC_CTX *ctx, const unsigned char *data, size_t nbits, unsigned char mac[4]); + +void zuc_eea_encrypt(const ZUC_UINT32 *in, ZUC_UINT32 *out, size_t nbits, + const unsigned char key[16], ZUC_UINT32 count, ZUC_UINT5 bearer, + ZUC_BIT direction); +ZUC_UINT32 zuc_eia_generate_mac(const ZUC_UINT32 *data, size_t nbits, + const unsigned char user_key[16], ZUC_UINT32 count, ZUC_UINT5 bearer, + ZUC_BIT direction); + +# define ZUC256_KEY_LENGTH 32 +# define ZUC256_IV_LENGTH 23 +# define ZUC256_MAC32_LENGTH 4 +# define ZUC256_MAC64_LENGTH 8 +# define ZUC256_MAC128_LENGTH 16 +# define ZUC256_MIN_MAC_LENGTH ZUC256_MAC32_LENGTH +# define ZUC256_MAX_MAC_LENGTH ZUC256_MAC128_LENGTH + +typedef ZUC_KEY ZUC256_KEY; + +void zuc256_set_key(ZUC256_KEY *key, const unsigned char user_key[32], + const unsigned char iv[23]); +#define zuc256_generate_keystream(k,n,out) zuc_generate_keystream(k,n,out) +#define zuc256_generate_keyword(k) zuc_generate_keyword(k) + +typedef struct ZUC256_MAC_CTX_st { + ZUC_UINT31 LFSR[16]; + ZUC_UINT32 R1; + ZUC_UINT32 R2; + ZUC_UINT32 T[4]; + ZUC_UINT32 K0[4]; + unsigned char buf[4]; + int buflen; + int macbits; +} ZUC256_MAC_CTX; + +void zuc256_mac_init(ZUC256_MAC_CTX *ctx, const unsigned char key[32], const unsigned char iv[23], int macbits); +void zuc256_mac_update(ZUC256_MAC_CTX *ctx, const unsigned char *data, size_t len); +void zuc256_mac_finish(ZUC256_MAC_CTX *ctx, const unsigned char *data, size_t nbits, unsigned char *mac); + + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/aes.c b/src/aes.c new file mode 100644 index 00000000..9e2e4c81 --- /dev/null +++ b/src/aes.c @@ -0,0 +1,480 @@ +/* + * Copyright (c) 2014 - 2020 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + + +#include +#include +#include +#include +#include "bswap.h" +#include "rotate.h" + + +static const uint8_t S[256] = { + 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, + 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, + 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, + 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, + 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, + 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, + 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, + 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, + 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, + 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, + 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, + 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, + 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, + 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, + 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, + 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16, +}; + +static const uint8_t S_inv[256] = { + 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb, + 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, + 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e, + 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25, + 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, + 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84, + 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06, + 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, + 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73, + 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e, + 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, + 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4, + 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f, + 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef, + 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61, + 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d, +}; + +static const uint8_t Rcon[11] = { + 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, +}; + +static uint32_t sub_word(uint32_t A) +{ + return S[(A >> 24) & 0xff] << 24 | + S[(A >> 16) & 0xff] << 16 | + S[(A >> 8) & 0xff] << 8 | + S[A & 0xff]; +} + +/* (a0,a1,a2,a3) => (a1,a2,a3,a0) */ +static uint32_t rot_word(uint32_t A) +{ + return ROL32(A, 8); +} + +#ifdef CRYPTO_INFO +static void print_rk(const AES_KEY *aes_key) +{ + int i; + for (i = 0; i <= aes_key->rounds; i++) { + printf("%08x ", aes_key->rk[4 * i]); + printf("%08x ", aes_key->rk[4 * i + 1]); + printf("%08x ", aes_key->rk[4 * i + 2]); + printf("%08x\n", aes_key->rk[4 * i + 3]); + } + printf("\n"); +} +#endif + +int aes_set_encrypt_key(AES_KEY *aes_key, const uint8_t *key, size_t keylen) +{ + /* Nk: num user key words + * AES-128 Nk = 4 W[44] + * AES-192 Nk = 6 W[52] + * AES-256 Nk = 8 W[60] + */ + uint32_t *W = (uint32_t *)aes_key->rk; + size_t Nk = keylen/sizeof(uint32_t); + int i; + + switch (keylen) { + case AES128_KEY_SIZE: + aes_key->rounds = 10; + break; + case AES192_KEY_SIZE: + aes_key->rounds = 12; + break; + case AES256_KEY_SIZE: + aes_key->rounds = 14; + break; + default: + return 0; + } + + for (i = 0; i < Nk; i++) { + W[i] = GETU32(key + sizeof(uint32_t) * i); + } + for (; i < 4 * (aes_key->rounds + 1); i++) { + uint32_t T = W[i - 1]; + if (i % Nk == 0) { + T = rot_word(T); + T = sub_word(T); + T ^= ((uint32_t)Rcon[i/Nk] << 24); + + } else if (Nk == 8 && i % 8 == 4) { + T = sub_word(T); + } + W[i] = W[i - Nk] ^ T; + } + +#ifdef CRYPTO_INFO + print_rk(aes_key); +#endif + + return 1; +} + +int aes_set_decrypt_key(AES_KEY *aes_key, const uint8_t *key, size_t keylen) +{ + int ret = 0; + AES_KEY enc_key; + int i; + + if (!aes_set_encrypt_key(&enc_key, key, keylen)) { + goto end; + } + + for (i = 0; i <= enc_key.rounds; i++) { + aes_key->rk[4*i ] = enc_key.rk[4*(enc_key.rounds - i)]; + aes_key->rk[4*i + 1] = enc_key.rk[4*(enc_key.rounds - i) + 1]; + aes_key->rk[4*i + 2] = enc_key.rk[4*(enc_key.rounds - i) + 2]; + aes_key->rk[4*i + 3] = enc_key.rk[4*(enc_key.rounds - i) + 3]; + } + ret = 1; + +#ifdef CRYPTO_INFO + print_rk(aes_key); +#endif + +end: + memset(&enc_key, 0, sizeof(AES_KEY)); + return ret; +} + +/* + * |S00 S01 S02 S03| | | + * |S10 S11 S12 S13| xor |W0 W1 W2 W3| + * |S20 S21 S22 S23| | | + * |S30 S31 S32 S33| | | + */ +static void add_round_key(uint8_t state[4][4], const uint32_t *W) +{ + int i; + for (i = 0; i < 4; i++) { + state[0][i] ^= (W[i] >> 24) & 0xff; + state[1][i] ^= (W[i] >> 16) & 0xff; + state[2][i] ^= (W[i] >> 8) & 0xff; + state[3][i] ^= (W[i] ) & 0xff; + } +} + +static void sub_bytes(uint8_t state[4][4]) +{ + int i, j; + for (i = 0; i < 4; i++) { + for (j = 0; j < 4; j++) { + state[i][j] = S[state[i][j]]; + } + } +} + +static void inv_sub_bytes(uint8_t state[4][4]) +{ + int i, j; + for (i = 0; i < 4; i++) { + for (j = 0; j < 4; j++) { + state[i][j] = S_inv[state[i][j]]; + } + } +} + +/* + * |S00 S01 S02 S03| <<<0 |S00 S01 S02 S03| + * |S10 S11 S12 S13| <<<1 => |S11 S12 S13 S10| + * |S20 S21 S22 S23| <<<2 |S22 S23 S20 S21| + * |S30 S31 S32 S33| <<<3 |S33 S30 S31 S32| + */ +static void shift_rows(uint8_t state[4][4]) +{ + uint8_t tmp[4][4]; + + tmp[0][0] = state[0][0]; + tmp[0][1] = state[0][1]; + tmp[0][2] = state[0][2]; + tmp[0][3] = state[0][3]; + + tmp[1][0] = state[1][1]; + tmp[1][1] = state[1][2]; + tmp[1][2] = state[1][3]; + tmp[1][3] = state[1][0]; + + tmp[2][0] = state[2][2]; + tmp[2][1] = state[2][3]; + tmp[2][2] = state[2][0]; + tmp[2][3] = state[2][1]; + + tmp[3][0] = state[3][3]; + tmp[3][1] = state[3][0]; + tmp[3][2] = state[3][1]; + tmp[3][3] = state[3][2]; + + memcpy(state, tmp, sizeof(tmp)); + memset(tmp, 0, sizeof(tmp)); +} + + +/* + * |S00 S01 S02 S03| >>>0 |S00 S01 S02 S03| + * |S10 S11 S12 S13| >>>1 => |S13 S10 S11 S12| + * |S20 S21 S22 S23| >>>2 |S22 S23 S20 S21| + * |S30 S31 S32 S33| >>>3 |S31 S32 S33 S30| + */ +static void inv_shift_rows(uint8_t state[4][4]) +{ + uint8_t tmp[4][4]; + + tmp[0][0] = state[0][0]; + tmp[0][1] = state[0][1]; + tmp[0][2] = state[0][2]; + tmp[0][3] = state[0][3]; + + tmp[1][0] = state[1][3]; + tmp[1][1] = state[1][0]; + tmp[1][2] = state[1][1]; + tmp[1][3] = state[1][2]; + + tmp[2][0] = state[2][2]; + tmp[2][1] = state[2][3]; + tmp[2][2] = state[2][0]; + tmp[2][3] = state[2][1]; + + tmp[3][0] = state[3][1]; + tmp[3][1] = state[3][2]; + tmp[3][2] = state[3][3]; + tmp[3][3] = state[3][0]; + + memcpy(state, tmp, sizeof(tmp)); + memset(tmp, 0, sizeof(tmp)); +} + +/* + * GF(2^8) defSed by f(x) = x^8 + x^4 + x^3 + x + 1 + * x^8 == x^4 + x^3 + x + 1 = 0001,1011 = 0x1b + * if A[7] == 0 then 2 * A = (A << 1) + * else 2 * A = (A << 1) xor A + */ +#define x1(a) (a) + +static uint8_t x2(uint8_t a) { + return (a >> 7) ? ((a << 1) ^ 0x1b) : (a << 1); +} + +static uint8_t x3(uint8_t a) { + return x2(a) ^ x1(a); +} + +static uint8_t x9(uint8_t a) { + return x2(x2(x2(a))) ^ x1(a); +} + +/* 0x0b = 11 = 8 + 2 + 1 */ +static uint8_t xb(uint8_t a) { + return x2(x2(x2(a))) ^ x2(a) ^ x1(a); +} + +/* 0x0d = 13 = 8 + 4 + 1 */ +static uint8_t xd(uint8_t a) { + return x2(x2(x2(a))) ^ x2(x2(a)) ^ x1(a); +} + +/* 0x0e = 14 = 8 + 4 + 2 */ +static uint8_t xe(uint8_t a) { + return x2(x2(x2(a))) ^ x2(x2(a)) ^ x2(a); +} + +/* + * |2 3 1 1| |S00 S01 S02 S03| + * |1 2 3 1| |S10 S11 S12 S13| + * |1 1 2 3|*|S20 S21 S22 S23| + * |3 1 1 2| |S30 S31 S32 S33| + */ +static void mix_columns(uint8_t S[4][4]) +{ + uint8_t tmp[4][4]; + int i; + + /* i-th column */ + for (i = 0; i < 4; i++) { + tmp[0][i] = x2(S[0][i]) ^ x3(S[1][i]) ^ x1(S[2][i]) ^ x1(S[3][i]); + tmp[1][i] = x1(S[0][i]) ^ x2(S[1][i]) ^ x3(S[2][i]) ^ x1(S[3][i]); + tmp[2][i] = x1(S[0][i]) ^ x1(S[1][i]) ^ x2(S[2][i]) ^ x3(S[3][i]); + tmp[3][i] = x3(S[0][i]) ^ x1(S[1][i]) ^ x1(S[2][i]) ^ x2(S[3][i]); + } + + memcpy(S, tmp, sizeof(tmp)); + memset(tmp, 0, sizeof(tmp)); +} + +/* + * |0E 0B 0D 09| |02 03 01 01| |1 0 0 0| + * |09 0E 0B 0D|*|01 02 03 01| = |0 1 0 0| + * |0D 09 0E 0B| |01 01 02 03| |0 0 1 0| + * |0B 0D 09 0E| |03 01 01 02| |0 0 0 1| + * + */ +static void inv_mix_columns(uint8_t S[4][4]) +{ + uint8_t tmp[4][4]; + int i; + + /* i-th column */ + for (i = 0; i < 4; i++) { + tmp[0][i] = xe(S[0][i]) ^ xb(S[1][i]) ^ xd(S[2][i]) ^ x9(S[3][i]); + tmp[1][i] = x9(S[0][i]) ^ xe(S[1][i]) ^ xb(S[2][i]) ^ xd(S[3][i]); + tmp[2][i] = xd(S[0][i]) ^ x9(S[1][i]) ^ xe(S[2][i]) ^ xb(S[3][i]); + tmp[3][i] = xb(S[0][i]) ^ xd(S[1][i]) ^ x9(S[2][i]) ^ xe(S[3][i]); + } + + memcpy(S, tmp, sizeof(tmp)); + memset(tmp, 0, sizeof(tmp)); +} + +#ifdef CRYPTO_INFO +static void print_state(const uint8_t S[4][4]) +{ + int i; + for (i = 0; i < 4; i++) { + printf("%02x %02x %02x %02x\n", S[i][0], S[i][1], S[i][2], S[i][3]); + } + printf("\n"); +} +#endif + +void aes_encrypt(const AES_KEY *key, const uint8_t in[16], uint8_t out[16]) +{ + uint8_t state[4][4]; + int i; + + /* fill state columns */ + for (i = 0; i < 4; i++) { + state[0][i] = *in++; + state[1][i] = *in++; + state[2][i] = *in++; + state[3][i] = *in++; + } + + /* Sitial add round key */ + add_round_key(state, key->rk); + + /* first n-1 rounds */ + for (i = 1; i < key->rounds; i++) { + sub_bytes(state); + shift_rows(state); + mix_columns(state); + add_round_key(state, key->rk + 4*i); + } + + /* last round withtmp mix columns */ + sub_bytes(state); + shift_rows(state); + add_round_key(state, key->rk + 4*i); + + /* tmpput state columns */ + for (i = 0; i < 4; i++) { + *out++ = state[0][i]; + *out++ = state[1][i]; + *out++ = state[2][i]; + *out++ = state[3][i]; + } + + memset(state, 0, sizeof(state)); +} + +void aes_decrypt(const AES_KEY *aes_key, const uint8_t in[16], uint8_t out[16]) +{ + uint8_t state[4][4]; + int i; + + /* fill state columns */ + for (i = 0; i < 4; i++) { + state[0][i] = *in++; + state[1][i] = *in++; + state[2][i] = *in++; + state[3][i] = *in++; + } + + /* Sitial add round key */ + add_round_key(state, aes_key->rk); + + /* first n-1 rounds */ + for (i = 1; i < aes_key->rounds; i++) { + inv_shift_rows(state); + inv_sub_bytes(state); + add_round_key(state, aes_key->rk + 4*i); + inv_mix_columns(state); + } + + /* last round withtmp mix columns */ + inv_shift_rows(state); + inv_sub_bytes(state); + add_round_key(state, aes_key->rk + 4*i); + + /* tmpput state columns */ + for (i = 0; i < 4; i++) { + *out++ = state[0][i]; + *out++ = state[1][i]; + *out++ = state[2][i]; + *out++ = state[3][i]; + } + + memset(state, 0, sizeof(state)); +} diff --git a/src/asn1.c b/src/asn1.c new file mode 100644 index 00000000..a347c2ff --- /dev/null +++ b/src/asn1.c @@ -0,0 +1,1017 @@ +/* + * Copyright (c) 2014 - 2020 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "endian.h" + + +/* + +## 返回值 + +解析函数返回错误: + +1. 输入数据长度为0,如待解析的对象具有OPTIONAL属性,那么不意味错误。 + 应显式告知调用方对象编码为空,由调用方判断是否为错误。 +2. 输入数据和目标对象类型不符,如待解析的对象具有OPTIONAL属性,那么意味目标对象为空。 +3. 长度和负载数据解析出错,这意味绝对的错误。 +4. 数据类型具有IMPLICIT属性时,意味着该对象的Tag被修改了,那么解析时调用方必须提供新的Tag。 + +DEFAULT值在接口上不提供这个功能,这个可以在数据的初始化时完成。 + + 内部接口不支持参数默认值或者多态的接口,例如不允许输入参数为空。 + 接口具有单一的逻辑可以通过严格的检查避免隐藏错误,提高健壮性。 + +*/ + + +static char *asn1_tag_index[] = { + "[0]", "[1]", "[2]", "[3]", "[4]", "[5]", "[6]", "[7]", "[8]", "[9]", + "[10]", "[11]", "[12]", "[13]", "[14]", "[15]", "[16]", "[17]", "[18]", "[19]", + "[20]", "[21]", "[22]", "[23]", "[24]", "[25]", "[26]", "[27]", "[28]", "[29]", + "[30]", "[31]", +}; + +const char *asn1_tag_name(int tag) +{ + if (tag < 0 || tag > 0xff) { + error_print("invalid tag value\n"); + return NULL; + } + + switch (tag & 0xc0) { + case ASN1_TAG_CONTENT_SPECIFIC: return asn1_tag_index[tag & 0xe0]; + case ASN1_TAG_APPLICATION: return "Application"; + case ASN1_TAG_PRIVATE: return "Private"; + } + + switch (tag) { + case ASN1_TAG_BOOLEAN: return "BOOLEAN"; + case ASN1_TAG_INTEGER: return "INTEGER"; + case ASN1_TAG_BIT_STRING: return "BIT STRING"; + case ASN1_TAG_OCTET_STRING: return "OCTET STRING"; + case ASN1_TAG_NULL: return "NULL"; + case ASN1_TAG_OBJECT_IDENTIFIER: return "OBJECT IDENTIFIER"; + case ASN1_TAG_ObjectDescriptor: return "ObjectDescriptor"; + case ASN1_TAG_EXTERNAL: return "EXTERNAL"; + case ASN1_TAG_REAL: return "REAL"; + case ASN1_TAG_ENUMERATED: return "ENUMERATED"; + case ASN1_TAG_UTF8String: return "UTF8String"; + case ASN1_TAG_PrintableString: return "PrintableString"; + case ASN1_TAG_TeletexString: return "TeletexString"; + case ASN1_TAG_VideotexString: return "VideotexString"; + case ASN1_TAG_IA5String: return "IA5String"; + case ASN1_TAG_UTCTime: return "UTCTime"; + case ASN1_TAG_GeneralizedTime: return "GeneralizedTime"; + case ASN1_TAG_GraphicString: return "GraphicString"; + case ASN1_TAG_VisibleString: return "VisibleString"; + case ASN1_TAG_GeneralString: return "GeneralString"; + case ASN1_TAG_UniversalString: return "UniversalString"; + case ASN1_TAG_CHARACTER_STRING: return "CHARACTER STRING"; + case ASN1_TAG_BMPString: return "BMPString"; + case ASN1_TAG_SEQUENCE: return "SEQUENCE"; + case ASN1_TAG_SET: return "SET"; + } + + error_print("unknown universal tag %d\n", tag); + return NULL; +} + +static int asn1_tag_is_cstring(int tag) +{ + switch (tag) { + case ASN1_TAG_UTF8String: + case ASN1_TAG_NumericString: + case ASN1_TAG_PrintableString: + case ASN1_TAG_TeletexString: + case ASN1_TAG_IA5String: + case ASN1_TAG_GeneralString: + return 1; + } + return 0; +} + +int asn1_utf8_string_check(const char *a, size_t alen) +{ + return 1; +} + +int asn1_printable_string_check(const char *a, size_t alen) +{ + return 1; +} + +int asn1_ia5_string_check(const char *a, size_t alen) +{ + return 1; +} + +///////////////////////////////////////////////////////////////////////////////////////////// +// DER encoding +///////////////////////////////////////////////////////////////////////////////////////////// +// 这组函数不对输入进行检查 + +void asn1_tag_to_der(int tag, uint8_t **out, size_t *outlen) +{ + if (out) { + *(*out)++ = (uint8_t)tag; + } + (*outlen)++; +} + +void asn1_length_to_der(size_t len, uint8_t **out, size_t *outlen) +{ + if (len < 128) { + if (out) { + *(*out)++ = (uint8_t)len; + } + (*outlen)++; + + } else { + uint8_t buf[4]; + int i; + + PUTU32(buf, (uint32_t)len); + if (len < 256) i = 1; + else if (len < 65536) i = 2; + else if (len < (1 << 24)) i = 3; + else i = 4; + + if (out) { + *(*out)++ = 0x80 + i; + memcpy(*out, buf + 4 - i, i); + (*out) += i; + } + (*outlen) += 1 + i; + } +} + +void asn1_data_to_der(const uint8_t *data, size_t datalen, uint8_t **out, size_t *outlen) +{ + if (out) { + memcpy(*out, data, datalen); + *out += datalen; + } + *outlen += datalen; +} + +int asn1_tag_from_der(int tag, const uint8_t **in, size_t *inlen) +{ + if (*inlen == 0 || **in != tag) { + return 0; + } + (*in)++; + (*inlen)--; + return 1; +} + +int asn1_length_from_der(size_t *plen, const uint8_t **pin, size_t *pinlen) +{ + const uint8_t *in = *pin; + size_t inlen = *pinlen; + size_t len; + + if (inlen <= 0) { + return -1; + } + + if (*in < 128) { + len = *in++; + inlen--; + } else { + uint8_t buf[4] = {0}; + int nbytes = *in++ & 0x7f; + + if (nbytes < 1 || nbytes > 4) { + error_print(); + return -1; + } + inlen--; + if (inlen < nbytes) { + error_print(); + return -1; + } + memcpy(buf + sizeof(buf) - nbytes, in, nbytes); + len = (size_t)GETU32(buf); + in += nbytes; + inlen -= nbytes; + } + + if (inlen < len) { + error_print("inlen (%zu) < length(%zu)", inlen, len); + return -1; + } + + *plen = len; + *pin = in; + *pinlen = inlen; + return 1; +} + +int asn1_data_from_der(const uint8_t **data, size_t datalen, const uint8_t **in, size_t *inlen) +{ + if (*inlen < datalen) { + error_print(); + return -1; + } + *data = *in; + *in += datalen; + *inlen -= datalen; + return 1; +} + +int asn1_header_to_der(int tag, size_t len, uint8_t **out, size_t *outlen) +{ + if ((out && !(*out)) || !outlen) { + error_print(); + return -1; + } + asn1_tag_to_der(tag, out, outlen); + asn1_length_to_der(len, out, outlen); + return 1; +} + +// If data == NULL, out should not be NULL +// 这个实现是不支持OPTIONAL的, +int asn1_type_to_der(int tag, const uint8_t *data, size_t datalen, uint8_t **out, size_t *outlen) +{ + if (data == NULL && datalen == 0 && out) { + return 0; + } + + if ((!data && out) || datalen >= INT_MAX || (out && !(*out)) || !outlen) { + error_print(); + return -1; + } + asn1_tag_to_der(tag, out, outlen); + asn1_length_to_der(datalen, out, outlen); + asn1_data_to_der(data, datalen, out, outlen); + return 1; +} + + +int asn1_type_from_der(int tag, const uint8_t **data, size_t *datalen, const uint8_t **in, size_t *inlen) +{ + int ret; + if ((ret = asn1_tag_from_der(tag, in, inlen)) != 1) { + if (ret < 0) error_print(); + return ret; + } + if (asn1_length_from_der(datalen, in, inlen) != 1 + || asn1_data_from_der(data, *datalen, in, inlen) != 1) { + error_print(); + return -1; + } + return 1; +} + +int asn1_type_copy_from_der(int tag, size_t maxlen, uint8_t *data, size_t *datalen, const uint8_t **in, size_t *inlen) +{ + int ret; + const uint8_t *p; + + if ((ret = asn1_tag_from_der(tag, in, inlen)) != 1) { + return ret; + } + if (asn1_length_from_der(datalen, in, inlen) != 1 + || asn1_data_from_der(&p, *datalen, in, inlen) != 1) { + error_print(); + return -1; + } + if (*datalen > maxlen) { + error_print(); + return -1; + } + memcpy(data, p, *datalen); + return 1; +} + +int asn1_any_tag_from_der(int *tag, const uint8_t **in, size_t *inlen) +{ + if (*inlen == 0) { + return 0; + } + *tag = *(*in)++; + (*inlen)--; + return 1; +} + + + +int asn1_any_type_from_der(int *tag, const uint8_t **data, size_t *datalen, const uint8_t **in, size_t *inlen) +{ + int ret; + if ((ret = asn1_any_tag_from_der(tag, in, inlen)) != 1) { + return ret; + } + if (asn1_length_from_der(datalen, in, inlen) != 1) { + error_print(); + return -1; + } + *data = *in; + *in += *datalen; + *inlen -= *datalen; + return 1; +} + +int asn1_any_from_der(const uint8_t **tlv, size_t *tlvlen, const uint8_t **in, size_t *inlen) +{ + int ret; + int tag; + const uint8_t *data; + size_t datalen; + + *tlv = *in; + *tlvlen = *inlen; + if ((ret = asn1_any_type_from_der(&tag, &data, &datalen, in, inlen)) != 1) { + error_print(); + return ret; + } + *tlvlen -= *inlen; + return 1; +} + +////////////////////////////////////////////////////////////////////////////////////////////////////////// + +int asn1_boolean_to_der_ex(int tag, int val, uint8_t **out, size_t *outlen) +{ + if ((out && !(*out)) || !outlen) { + return -1; + } + if (out) { + *(*out)++ = tag; + *(*out)++ = 0x01; + *(*out)++ = val ? 0xff : 0x00; + } + (*outlen) += 3; + return 1; +} + +int asn1_integer_to_der_ex(int tag, const uint8_t *a, size_t alen, uint8_t **out, size_t *outlen) +{ + if (!a || alen <= 0 || alen > INT_MAX || (out && !(*out)) || !outlen) { + error_print(); + return -1; + } + + if (out) + *(*out)++ = tag; + (*outlen)++; + + if (a[0] & 0x80) { + asn1_length_to_der(alen + 1, out, outlen); + if (out) { + *(*out)++ = 0x00; + memcpy(*out, a, alen); + (*out) += alen; + } + (*outlen) += 1 + alen; + } else { + while (*a == 0 && alen > 1) { + a++; + alen--; + } + asn1_length_to_der(alen, out, outlen); + if (out) { + memcpy(*out, a, alen); + (*out) += alen; + } + (*outlen) += alen; + } + + return 1; +} + +int asn1_int_to_der_ex(int tag, int a, uint8_t **out, size_t *outlen) +{ + int i; + uint8_t buf[4] = {0}; + size_t len = 0; + + if (a == -1) { + return 0; + } + + while (a > 0) { + buf[3 - len] = a & 0xff; + a >>= 8; + len++; + } + if (!len) { + len = 1; + } + + return asn1_integer_to_der_ex(tag, buf + 4 - len, len, out, outlen); +} + +int asn1_bit_string_to_der_ex(int tag, const uint8_t *bits, size_t nbits, uint8_t **out, size_t *outlen) +{ + int unused = (8 - nbits % 8) % 8; + size_t nbytes = (nbits + 7) / 8; + + if (!bits || nbits >= INT_MAX || (out && !(*out)) || !outlen) { + return -1; + } + + if (out) + *(*out)++ = tag; + (*outlen)++; + + asn1_length_to_der(nbytes + 1, out, outlen); + + if (out) { + *(*out)++ = (uint8_t)unused; + memcpy(*out, bits, nbytes); + (*out) += nbytes; + } + *outlen += 1 + nbytes; + + + return 1; +} + +int asn1_bits_to_der_ex(int tag, int bits, uint8_t **out, size_t *outlen) +{ + size_t nbits = 0; + uint8_t buf[4] = {0}; + int i = 0; + + if (bits < 0) { + return 0; + } + while (bits) { + buf[i] = (buf[i] << 1) | (bits & 1); + bits >>= 1; + nbits++; + if (nbits % 8) { + i++; + } + } + if (!nbits) { + nbits = 1; + } + return asn1_bit_string_to_der_ex(tag, buf, nbits, out, outlen); +} + +int asn1_null_to_der(uint8_t **out, size_t *outlen) +{ + if ((out && !(*out)) || !outlen) { + return -1; + } + + if (out) { + *(*out)++ = ASN1_TAG_NULL; + *(*out)++ = 0x00; + } + *outlen += 2; + return 1; +} + +int asn1_object_identifier_to_der_ex(int tag, int oid, const uint32_t *nodes, size_t nodes_count, uint8_t **out, size_t *outlen) +{ + uint8_t octets[32]; + size_t octetslen = 0; + + if ((out && !(*out)) || !outlen) { + return -1; + } + + if (out) + *(*out)++ = tag; + (*outlen)++; + + if (oid != OID_undef) + asn1_oid_to_octets(oid, octets, &octetslen); + else asn1_oid_nodes_to_octets(nodes, nodes_count, octets, &octetslen); + + asn1_length_to_der(octetslen, out, outlen); + + if (out) { + // 注意:If out == NULL, *out ==> Segment Fault + memcpy(*out, octets, octetslen); + *out += octetslen; + } + *outlen += octetslen; + return 1; +} + +int asn1_utf8_string_to_der_ex(int tag, const char *a, uint8_t **out, size_t *outlen) +{ + return asn1_type_to_der(tag, (const uint8_t *)a, strlen(a), out, outlen); +} + +int asn1_printable_string_to_der_ex(int tag, const char *a, uint8_t **out, size_t *outlen) +{ + return asn1_type_to_der(tag, (const uint8_t *)a, strlen(a), out, outlen); +} + +int asn1_ia5_string_to_der_ex(int tag, const char *a, uint8_t **out, size_t *outlen) +{ + return asn1_type_to_der(tag, (const uint8_t *)a, strlen(a), out, outlen); +} + +int asn1_utc_time_to_der_ex(int tag, time_t a, uint8_t **out, size_t *outlen) +{ + struct tm tm_val; + char buf[sizeof("YYMMDDHHMMSSZ")]; + + if ((out && !(*out)) || !outlen) { + return -1; + } + + gmtime_r(&a, &tm_val); + strftime(buf, sizeof(buf), "%y%m%d%H%M%SZ", &tm_val); + + if (out) + *(*out)++ = tag; + (*outlen)++; + asn1_length_to_der(sizeof(buf)-1, out, outlen); + if (out) { + memcpy(*out, buf, sizeof(buf)-1); + (*out) += sizeof(buf)-1; + } + *outlen += sizeof(buf)-1; + + return 1; +} + +int asn1_generalized_time_to_der_ex(int tag, time_t a, uint8_t **out, size_t *outlen) +{ + struct tm tm_val; + char buf[sizeof("YYYYMMDDHHMMSSZ")]; + + if ((out && !(*out)) || !outlen) { + error_print(); + return -1; + } + + gmtime_r(&a, &tm_val); + strftime(buf, sizeof(buf), "%Y%m%d%H%M%SZ", &tm_val); + + if (out) + *(*out)++ = tag; + (*outlen)++; + asn1_length_to_der(sizeof(buf)-1, out, outlen); + if (out) { + memcpy(*out, buf, sizeof(buf)-1); + (*out) += sizeof(buf)-1; + } + *outlen += sizeof(buf)-1; + + return 1; +} + + +///////////////////////////////////////////////////////////////////////////////////////////// +// DER decoding +///////////////////////////////////////////////////////////////////////////////////////////// + + +/* +解码函数的返回值: + + ret == 0 + 当前剩余的数据数据长度为0 + 或者下一个对象与期待不符,即输入对象的标签不等于输入的tag + 当对象为OPTIONAL时,调用方可以通过判断返回值是否为0进行处理 + ret < 0 + 标签正确但是长度或数据解析出错 + ret == 1 + 解析正确 + + +解码函数的输入: + + *in != NULL + 例如一个SEQUENCE中的属性均为OPTIONAL,解析后指针仍不为空 + 因此不允许输入空的输入数据指针 + + +处理规则 + + 当返回值 ret <= 0 时,*tag, *in, *inlen 的值保持不变 + + 如果一个类型有 DEFAULT 属性,调用方可以将返回数据预先设置为默认值, + 如果该对象未被编码,即返回值为0,那么解码函数不会修改已经设置的默认值 + +*/ + +int asn1_boolean_from_der_ex(int tag, int *val, const uint8_t **in, size_t *inlen) +{ + if (!val || !in || !(*in) || !inlen) { + return -1; + } + + if (*inlen <= 0 || **in != tag) { + return 0; + } + if (*inlen < 3 + || *(*in + 1) != 0x01 + || (*(*in + 2) != 0 && *(*in + 2) != 0xff)) { + return -1; + } + *val = *(*in + 2) ? 1 : 0; + *in += 3; + *inlen -= 3; + return 1; +} + +int asn1_integer_from_der_ex(int tag, const uint8_t **a, size_t *alen, const uint8_t **pin, size_t *pinlen) +{ + const uint8_t *in = *pin; + size_t inlen = *pinlen; + size_t len; + + if (!a || !alen || !pin || !(*pin) || !pinlen) { + error_print(); + return -1; + } + + if (inlen-- <= 0 || *in++ != tag) { + return 0; + } + if (asn1_length_from_der(&len, &in, &inlen) != 1 + || len <= 0) { + error_print(); + return -1; + } + + // 判断 ASN1_INTEGER 是否为负数,我们不支持负整数,返回特性不支持错误 + if (*in & 0x80) { + error_print(); + return -255; + } + + if (*in == 0 && len > 1) { + inlen--; + in++; + len--; + } + if (*in == 0 && len > 1) { + error_print(); + return -1; + } + *a = in; + *alen = len; + *pin = in + len; + *pinlen = inlen - len; + return 1; +} + +int asn1_int_from_der_ex(int tag, int *a, const uint8_t **in, size_t *inlen) +{ + int ret; + const uint8_t *p; + size_t len, i; + unsigned int val = 0; + + if (!a || !in || !(*in) || !inlen) { + error_print(); + return -1; + } + if ((ret = asn1_integer_from_der_ex(tag, &p, &len, in, inlen)) != 1) { + if (ret < 0) error_print(); + else *a = -1; + return ret; + } + if (len > 8) { + error_print(); + return -1; + } + + for (i = 0; i < len; i++) { + val = (val << 8) | p[i]; + } + *a = val; + return 1; +} + +int asn1_bit_string_from_der_ex(int tag, const uint8_t **bits, size_t *nbits, const uint8_t **pin, size_t *pinlen) +{ + const uint8_t *in = *pin; + size_t inlen = *pinlen; + size_t len; + int unused_bits; + + if (!bits || !nbits || !pin || !(*pin) || !pinlen) { + return -1; + } + if (inlen-- < 1 || *in++ != tag) { + return 0; + } + if (asn1_length_from_der(&len, &in, &inlen) != 1 + || len <= 0) { + return -1; + } + + unused_bits = *in; + if (unused_bits > 8 || (len == 1 && unused_bits > 0)) { + return -1; + } + + *bits = in + 1; + *nbits = (len - 1) * 8 - unused_bits; + *pin = in + len; + *pinlen = inlen - len; + return 1; +} + +int asn1_bits_from_der_ex(int tag, int *bits, const uint8_t **in, size_t *inlen) +{ + int ret; + const uint8_t *p; + size_t nbits, i; + uint8_t c; + + if ((ret = asn1_bit_string_from_der_ex(tag, &p, &nbits, in, inlen)) != 1) { + if (ret < 0) error_print(); + return ret; + } + if (nbits > 31) { + error_print(); + return -1; + } + + *bits = 0; + for (i = 0; i < nbits; i++) { + if (i % 8 == 0) { + c = *p++; + } + *bits |= ((c & 0x80) >> 7) << i; + c <<= 1; + } + return 1; +} + +int asn1_null_from_der(const uint8_t **in, size_t *inlen) +{ + if (!in || !(*in) || !inlen) { + return -1; + } + if (*inlen <= 0 || **in != ASN1_TAG_NULL) { + return 0; + } + if (*inlen < 2 + || (*in)[1] != 0x00) { + return -1; + } + *in += 2; + *inlen -= 2; + return 1; +} + +int asn1_object_identifier_from_der_ex(int tag, int *oid, uint32_t nodes[32], size_t *nodes_count, + const uint8_t **pin, size_t *pinlen) +{ + const uint8_t *in = *pin; + size_t inlen = *pinlen; + size_t len; + + if (!oid || !nodes || !nodes_count || !pin || !(*pin) || !pinlen) { + error_print(); + return -1; + } + + if (inlen-- <= 0 || *in++ != tag) { + error_print(); + return 0; + } + if (asn1_length_from_der(&len, &in, &inlen) != 1 + || len <= 0) { + error_print(); + return -1; + } + // 由于 asn1_oid_from_der 无法判断不识别的 OID 数据编码是否正确,因此必须先解码 + if (asn1_oid_nodes_from_octets(nodes, nodes_count, in, len) < 0) { + error_print(); + return -1; + } + *oid = asn1_oid_from_octets(in, len); + *pin = in + len; + *pinlen = inlen - len; + return 1; +} + +int asn1_string_from_der(int tag, const char **a, size_t *alen, const uint8_t **pin, size_t *pinlen) +{ + const uint8_t *in = *pin; + size_t inlen = *pinlen; + size_t len; + + if (!a || !alen || !pin || !(*pin) || !pinlen) { + return -1; + } + + if (inlen-- <= 0 || *in++ != tag) { + return 0; + } + if (asn1_length_from_der(&len, &in, &inlen) != 1 + || len <= 0) { + return -1; + } + *a = (char *)in; + *alen = len; + + *pin = in + len; + *pinlen = inlen - len; + return 1; +} + +int asn1_utf8_string_from_der_ex(int tag, const char **a, size_t *alen, const uint8_t **in, size_t *inlen) +{ + return asn1_type_from_der(tag, (const uint8_t **)a, alen, in, inlen); +} + +int asn1_printable_string_from_der_ex(int tag, const char **a, size_t *alen, const uint8_t **in, size_t *inlen) +{ + return asn1_type_from_der(tag, (const uint8_t **)a, alen, in, inlen); +} + +int asn1_ia5_string_from_der_ex(int tag, const char **a, size_t *alen, const uint8_t **in, size_t *inlen) +{ + return asn1_type_from_der(tag, (const uint8_t **)a, alen, in, inlen); +} + +int asn1_utc_time_from_der_ex(int tag, time_t *t, const uint8_t **pin, size_t *pinlen) +{ + const uint8_t *in = *pin; + size_t inlen = *pinlen; + struct tm tm_val; + char buf[sizeof("YYYYMMDDHHMMSSZ")] = {0}; + size_t len; + int year; + + + if (!t || !pin || !(*pin) || !pinlen) { + return -1; + } + if (inlen-- <= 0 || *in++ != tag) { + return 0; + } + if (asn1_length_from_der(&len, &in, &inlen) != 1 + || (len != sizeof("YYMMDDHHMMSSZ")-1 && len != sizeof("YYMMDDHHMMSS+HHMM")-1)) { + return -1; + } + memcpy(buf + 2, in, len); + + if (!isdigit(buf[2]) && !isdigit(buf[3])) { + return -1; + } + year = (buf[2] - '0') * 10 + (buf[3] - '0'); + if (year >= 50) { + buf[0] = '1'; + buf[1] = '9'; + } else { + buf[0] = '2'; + buf[1] = '0'; + } + if (len == sizeof("YYMMDDHHMMSSZ")-1) { + if (!strptime(buf, "%Y%m%d%H%M%SZ", &tm_val)) { + return -1; + } + } else { + return -1; + } + *t = timegm(&tm_val); + + *pin = in + len; + *pinlen = inlen - len; + return 1; +} + +int asn1_generalized_time_from_der_ex(int tag, time_t *t, const uint8_t **pin, size_t *pinlen) +{ + int ret; + const uint8_t *in = *pin; + size_t inlen = *pinlen; + struct tm tm_val; + char buf[sizeof("YYYYMMDDHHMMSS+HHMM")] = {0}; + size_t len; + + if ((ret = asn1_tag_from_der(tag, &in, &inlen)) != 1) { + if (ret < 0) error_print(); + return ret; + } + if (asn1_length_from_der(&len, &in, &inlen) != 1) { + error_print(); + return -1; + } + if (len != sizeof("YYYYMMDDHHMMSSZ")-1 && len != sizeof("YYYYMMDDHHMMSS+HHMM")-1) { + error_print(); + return -1; + } + memcpy(buf, in, len); + + + + if (len == sizeof("YYYYMMDDHHMMSSZ")-1) { + if (!strptime(buf, "%Y%m%d%H%M%SZ", &tm_val)) { + error_print(); + return -1; + } + } else { + // TODO: 处理这种情况 + error_print(); + return -2; + } + *t = timegm(&tm_val); + *pin = in + len; + *pinlen = inlen - len; + return 1; +} + +// 其中的每一个data/datalen都是一个ASN1的TLV,因此我们可以去解析 +int asn1_sequence_of_get_next_item(const ASN1_SEQUENCE_OF *a, const uint8_t **next, const uint8_t **data, size_t *datalen) +{ + int ret; + size_t len; + int tag; + const uint8_t *value; + size_t valuelen; + + if (*next == NULL) { + *next = a->data; + } + if (*next < a->data || *next > a->data + a->datalen) { + error_print(); + return -1; + } + *data = *next; + len = a->data + a->datalen - *next; + ret = asn1_any_type_from_der(&tag, &value, &valuelen, next, &len); + if (ret < 0) error_print(); + *datalen = *next - *data; + return ret; +} + +int asn1_sequence_of_get_count(const ASN1_SEQUENCE_OF *a, size_t *count) +{ + int ret; + const uint8_t *next = NULL; + const uint8_t *data; + size_t datalen; + + *count = 0; + while ((ret = asn1_sequence_of_get_next_item(a, &next, &data, &datalen)) == 1) { + (*count)++; + } + if (ret < 0) { + error_print(); + return -1; + } + return 1; +} diff --git a/src/base64.c b/src/base64.c new file mode 100644 index 00000000..48a4796b --- /dev/null +++ b/src/base64.c @@ -0,0 +1,377 @@ +/* + * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include +#include +#include +#include +#include +#include +#include + +static unsigned char conv_ascii2bin(unsigned char a); +#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) + +static const unsigned char data_bin2ascii[65] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ\ +abcdefghijklmnopqrstuvwxyz0123456789+/"; + +/*- + * 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) +#define B64_BASE64(a) (!B64_NOT_BASE64(a)) + +static const unsigned char 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, 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 unsigned char conv_ascii2bin(unsigned char a) +{ + if (a & 0x80) + return B64_ERROR; + return data_ascii2bin[a]; +} + + +int base64_ctx_num(BASE64_CTX *ctx) +{ + return ctx->num; +} + +void base64_encode_init(BASE64_CTX *ctx) +{ + ctx->length = 48; + ctx->num = 0; + ctx->line_num = 0; +} + +int base64_encode_update(BASE64_CTX *ctx, const uint8_t *in, int inl, uint8_t *out, int *outl) +{ + int i, j; + size_t total = 0; + + *outl = 0; + if (inl <= 0) + return 0; + assert(ctx->length <= (int)sizeof(ctx->enc_data)); + if (ctx->length - ctx->num > inl) { + memcpy(&(ctx->enc_data[ctx->num]), in, inl); + ctx->num += inl; + return 1; + } + if (ctx->num != 0) { + i = ctx->length - ctx->num; + memcpy(&(ctx->enc_data[ctx->num]), in, i); + in += i; + inl -= i; + j = base64_encode_block(out, ctx->enc_data, ctx->length); + ctx->num = 0; + out += j; + *(out++) = '\n'; + *out = '\0'; + total = j + 1; + } + while (inl >= ctx->length && total <= INT_MAX) { + j = base64_encode_block(out, in, ctx->length); + in += ctx->length; + inl -= ctx->length; + out += j; + *(out++) = '\n'; + *out = '\0'; + total += j + 1; + } + if (total > INT_MAX) { + /* Too much output data! */ + *outl = 0; + return 0; + } + if (inl != 0) + memcpy(&(ctx->enc_data[0]), in, inl); + ctx->num = inl; + *outl = total; + + return 1; +} + +void base64_encode_finish(BASE64_CTX *ctx, uint8_t *out, int *outl) +{ + unsigned int ret = 0; + + if (ctx->num != 0) { + ret = base64_encode_block(out, ctx->enc_data, ctx->num); + out[ret++] = '\n'; + out[ret] = '\0'; + ctx->num = 0; + } + *outl = ret; +} + +int base64_encode_block(unsigned char *t, const unsigned char *f, int dlen) +{ + int i, ret = 0; + unsigned long l; + + for (i = dlen; i > 0; i -= 3) { + if (i >= 3) { + l = (((unsigned long)f[0]) << 16L) | + (((unsigned long)f[1]) << 8L) | f[2]; + *(t++) = conv_bin2ascii(l >> 18L); + *(t++) = conv_bin2ascii(l >> 12L); + *(t++) = conv_bin2ascii(l >> 6L); + *(t++) = conv_bin2ascii(l); + } else { + l = ((unsigned long)f[0]) << 16L; + if (i == 2) + l |= ((unsigned long)f[1] << 8L); + + *(t++) = conv_bin2ascii(l >> 18L); + *(t++) = conv_bin2ascii(l >> 12L); + *(t++) = (i == 1) ? '=' : conv_bin2ascii(l >> 6L); + *(t++) = '='; + } + ret += 4; + f += 3; + } + + *t = '\0'; + return (ret); +} + +void base64_decode_init(BASE64_CTX *ctx) +{ + /* Only ctx->num is used during decoding. */ + ctx->num = 0; + ctx->length = 0; + ctx->line_num = 0; + ctx->expect_nl = 0; +} + +/*- + * -1 for error + * 0 for last line + * 1 for full line + * + * Note: even though base64_decode_update attempts to detect and report end of + * content, the context doesn't currently remember it and will accept more data + * in the next call. Therefore, the caller is responsible for checking and + * rejecting a 0 return value in the middle of content. + * + * Note: even though base64_decode_update has historically tried to detect end of + * content based on line length, this has never worked properly. Therefore, + * we now return 0 when one of the following is true: + * - Padding or B64_EOF was detected and the last block is complete. + * - Input has zero-length. + * -1 is returned if: + * - Invalid characters are detected. + * - There is extra trailing padding, or data after padding. + * - B64_EOF is detected after an incomplete base64 block. + */ +int base64_decode_update(BASE64_CTX *ctx, const uint8_t *in, int inl, uint8_t *out, int *outl) +{ + int seof = 0, eof = 0, rv = -1, ret = 0, i, v, tmp, n, decoded_len; + unsigned char *d; + + n = ctx->num; + d = ctx->enc_data; + + if (n > 0 && d[n - 1] == '=') { + eof++; + if (n > 1 && d[n - 2] == '=') + eof++; + } + + /* Legacy behaviour: an empty input chunk signals end of input. */ + if (inl == 0) { + rv = 0; + goto end; + } + + for (i = 0; i < inl; i++) { + tmp = *(in++); + v = conv_ascii2bin(tmp); + if (v == B64_ERROR) { + rv = -1; + error_print(); + goto end; + } + + if (tmp == '=') { + eof++; + } else if (eof > 0 && B64_BASE64(v)) { + /* More data after padding. */ + rv = -1; + error_print(); + goto end; + } + + if (eof > 2) { + rv = -1; + error_print(); + goto end; + } + + if (v == B64_EOF) { + seof = 1; + goto tail; + } + + /* Only save valid base64 characters. */ + if (B64_BASE64(v)) { + if (n >= 64) { + /* + * We increment n once per loop, and empty the buffer as soon as + * we reach 64 characters, so this can only happen if someone's + * manually messed with the ctx. Refuse to write any more data. + */ + rv = -1; + error_print(); + goto end; + } + assert(n < (int)sizeof(ctx->enc_data)); + d[n++] = tmp; + } + + if (n == 64) { + decoded_len = base64_decode_block(out, d, n); + n = 0; + if (decoded_len < 0 || eof > decoded_len) { + rv = -1; + goto end; + } + ret += decoded_len - eof; + out += decoded_len - eof; + } + } + + /* + * Legacy behaviour: if the current line is a full base64-block (i.e., has + * 0 mod 4 base64 characters), it is processed immediately. We keep this + * behaviour as applications may not be calling base64_decode_final properly. + */ +tail: + if (n > 0) { + if ((n & 3) == 0) { + decoded_len = base64_decode_block(out, d, n); + n = 0; + if (decoded_len < 0 || eof > decoded_len) { + error_print(); + rv = -1; + goto end; + } + ret += (decoded_len - eof); + } else if (seof) { + /* EOF in the middle of a base64 block. */ + error_print(); + rv = -1; + goto end; + } + } + + rv = seof || (n == 0 && eof) ? 0 : 1; +end: + /* Legacy behaviour. This should probably rather be zeroed on error. */ + *outl = ret; + ctx->num = n; + return (rv); +} + +int base64_decode_block(unsigned char *t, const unsigned char *f, int n) +{ + int i, ret = 0, a, b, c, d; + unsigned long l; + + /* trim white space from the start of the line. */ + while ((conv_ascii2bin(*f) == B64_WS) && (n > 0)) { + f++; + n--; + } + + /* + * strip off stuff at the end of the line ascii2bin values B64_WS, + * B64_EOLN, B64_EOLN and B64_EOF + */ + while ((n > 3) && (B64_NOT_BASE64(conv_ascii2bin(f[n - 1])))) + n--; + + if (n % 4 != 0) + return (-1); + + for (i = 0; i < n; i += 4) { + a = conv_ascii2bin(*(f++)); + b = conv_ascii2bin(*(f++)); + c = conv_ascii2bin(*(f++)); + d = conv_ascii2bin(*(f++)); + if ((a & 0x80) || (b & 0x80) || (c & 0x80) || (d & 0x80)) + return (-1); + l = ((((unsigned long)a) << 18L) | + (((unsigned long)b) << 12L) | + (((unsigned long)c) << 6L) | (((unsigned long)d))); + *(t++) = (unsigned char)(l >> 16L) & 0xff; + *(t++) = (unsigned char)(l >> 8L) & 0xff; + *(t++) = (unsigned char)(l) & 0xff; + ret += 3; + } + return (ret); +} + +int base64_decode_finish(BASE64_CTX *ctx, uint8_t *out, int *outl) +{ + int i; + + *outl = 0; + if (ctx->num != 0) { + i = base64_decode_block(out, ctx->enc_data, ctx->num); + if (i < 0) { + error_print(); + return (-1); + } + ctx->num = 0; + *outl = i; + return (1); + } else + return (1); +} diff --git a/src/block_cipher.c b/src/block_cipher.c new file mode 100644 index 00000000..14ceaea6 --- /dev/null +++ b/src/block_cipher.c @@ -0,0 +1,203 @@ +/* + * Copyright (c) 2014 - 2020 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + + +#include +#include +#include +#include +#include +#include "internal/endian.h" + + +int block_cipher_encrypt_init(BLOCK_CIPHER_KEY *key, const BLOCK_CIPHER *cipher, + const uint8_t *user_key, size_t keylen) +{ + memset(key, 0, sizeof(BLOCK_CIPHER_KEY)); + key->cipher = cipher; + return key->cipher->set_encrypt_key(key, user_key, keylen); +} + +int block_cipher_decrypt_init(BLOCK_CIPHER_KEY *key, const BLOCK_CIPHER *cipher, + const uint8_t *user_key, size_t keylen) +{ + memset(key, 0, sizeof(BLOCK_CIPHER_KEY)); + key->cipher = cipher; + return key->cipher->set_decrypt_key(key, user_key, keylen); +} + +void block_cipher_encrypt(const BLOCK_CIPHER_KEY *key, const uint8_t *in, uint8_t *out) +{ + key->cipher->encrypt(key, in, out); +} + +void block_cipher_decrypt(const BLOCK_CIPHER_KEY *key, const uint8_t *in, uint8_t *out) +{ + key->cipher->decrypt(key, in, out); +} + +void block_cipher_ecb_encrypt(const BLOCK_CIPHER_KEY *key, const uint8_t *in, size_t nblocks, uint8_t *out) +{ + while (nblocks--) { + key->cipher->encrypt(key, in, out); + in += key->cipher->block_size; + out += key->cipher->block_size; + } +} + +void block_cipher_ecb_decrypt(const BLOCK_CIPHER_KEY *key, const uint8_t *in, size_t nblocks, uint8_t *out) +{ + while (nblocks--) { + key->cipher->decrypt(key, in, out); + in += key->cipher->block_size; + out += key->cipher->block_size; + } +} + +void block_cipher_cbc_encrypt(const BLOCK_CIPHER_KEY *key, const uint8_t *iv, + const uint8_t *in, size_t nblocks, uint8_t *out) +{ + while (nblocks--) { + gmssl_memxor(out, in, iv, key->cipher->block_size); + key->cipher->encrypt(key, out, out); + iv = out; + in += key->cipher->block_size; + out += key->cipher->block_size; + } +} + +void block_cipher_cbc_decrypt(const BLOCK_CIPHER_KEY *key, const uint8_t *iv, + const uint8_t *in, size_t nblocks, uint8_t *out) +{ + while (nblocks--) { + key->cipher->decrypt(key, in, out); + gmssl_memxor(out, out, iv, key->cipher->block_size); + iv = in; + in += key->cipher->block_size; + out += key->cipher->block_size; + } +} + +void block_cipher_ctr_encrypt(const BLOCK_CIPHER_KEY *key, uint8_t *counter, + const uint8_t *in, size_t nblocks, uint8_t *out) +{ + size_t block_size = key->cipher->block_size; + uint8_t block[block_size]; + uint64_t ctr = GETU64(counter + block_size - sizeof(uint64_t)); + + while (nblocks--) { + key->cipher->encrypt(key, counter, block); + gmssl_memxor(out, in, block, block_size); + in += block_size; + out += block_size; + ctr++; + PUTU64(counter + block_size - sizeof(uint64_t), ctr); + } +} + + +static const BLOCK_CIPHER aes_block_cipher_object = { + OID_aes, + AES128_KEY_SIZE, + AES256_KEY_SIZE, + AES_BLOCK_SIZE, + (block_cipher_set_encrypt_key_func)aes_set_encrypt_key, + (block_cipher_set_decrypt_key_func)aes_set_decrypt_key, + (block_cipher_encrypt_func)aes_encrypt, + (block_cipher_decrypt_func)aes_encrypt, +}; + +const BLOCK_CIPHER *BLOCK_CIPHER_aes(void) +{ + return &aes_block_cipher_object; +} + + +static int set_encrypt_key(BLOCK_CIPHER_KEY *key, const uint8_t *user_key, size_t keylen) +{ + if (keylen != SM4_KEY_SIZE) { + return -1; + } + sm4_set_encrypt_key(&key->u.sm4_key, user_key); + return 1; +} + +static int set_decrypt_key(BLOCK_CIPHER_KEY *key, const uint8_t *user_key, size_t keylen) +{ + if (keylen != SM4_KEY_SIZE) { + return -1; + } + sm4_set_decrypt_key(&key->u.sm4_key, user_key); + return 1; +} + +static const BLOCK_CIPHER sm4_block_cipher_object = { + OID_sm4, + SM4_KEY_SIZE, + SM4_KEY_SIZE, + SM4_BLOCK_SIZE, + set_encrypt_key, + set_decrypt_key, + (block_cipher_encrypt_func)sm4_encrypt, + (block_cipher_decrypt_func)sm4_encrypt, +}; + +const BLOCK_CIPHER *BLOCK_CIPHER_sm4(void) +{ + return &sm4_block_cipher_object; +} + +const BLOKC_CIPHER *block_cipher_from_name(const char *name) +{ + if (strcmp(name, "aes") == 0) { + return BLOCK_CIPHER_aes(); + } else if (strcmp(name, "sm4") == 0) { + return BLOCK_CIPHER_sm4(); + } + return NULL; +} diff --git a/src/bswap.h b/src/bswap.h new file mode 100644 index 00000000..f78deaf3 --- /dev/null +++ b/src/bswap.h @@ -0,0 +1,56 @@ +/* + * Copyright 2010-2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ +#ifndef GMSSL_MODES_LCL_H +#define GMSSL_MODES_LCL_H + + +# if defined(__GNUC__) && __GNUC__>=2 +# if defined(__x86_64) || defined(__x86_64__) +# define BSWAP8(x) ({ uint64_t ret_=(x); \ + asm ("bswapq %0" \ + : "+r"(ret_)); ret_; }) +# define BSWAP4(x) ({ uint32_t ret_=(x); \ + asm ("bswapl %0" \ + : "+r"(ret_)); ret_; }) +# elif defined(__aarch64__) +# define BSWAP8(x) ({ uint64_t ret_; \ + asm ("rev %0,%1" \ + : "=r"(ret_) : "r"(x)); ret_; }) +# define BSWAP4(x) ({ uint32_t ret_; \ + asm ("rev %w0,%w1" \ + : "=r"(ret_) : "r"(x)); ret_; }) +# endif +# elif defined(_MSC_VER) +# if _MSC_VER>=1300 +# pragma intrinsic(_byteswap_uint64,_byteswap_ulong) +# define BSWAP8(x) _byteswap_uint64((uint64_t)(x)) +# define BSWAP4(x) _byteswap_ulong((uint32_t)(x)) +# endif +#endif + +#if defined(BSWAP4) && !defined(STRICT_ALIGNMENT) +# define GETU32(p) BSWAP4(*(const uint32_t *)(p)) +# define PUTU32(p,v) *(uint32_t *)(p) = BSWAP4(v) +# define GETU64(p) BSWAP8(*(const uint64_t *)(p)) +# define PUTU64(p,v) *(uint64_t *)(p) = BSWAP8(v) +#else +# define GETU32(p) ((uint32_t)(p)[0]<<24|(uint32_t)(p)[1]<<16|(uint32_t)(p)[2]<<8|(uint32_t)(p)[3]) +# define PUTU32(p,v) ((p)[0]=(u8)((v)>>24),(p)[1]=(u8)((v)>>16),(p)[2]=(u8)((v)>>8),(p)[3]=(u8)(v)) +# define GETU64(p) ((uint64_t)(p)[0]<<56|(uint64_t)(p)[1]<<48|(uint64_t)(p)[2]<<40|(uint64_t)(p)[3]<<32| \ + (uint64_t)(p)[4]<<24|(uint64_t)(p)[5]<<16|(uint64_t)(p)[6]<<8|(uint64_t)(p)[7]) +# define PUTU64(p,v) ((p)[0]=(u8)((v)>>56),(p)[1]=(u8)((v)>>48),(p)[2]=(u8)((v)>>40),(p)[3]=(u8)((v)>>32),\ + (p)[4]=(u8)((v)>>24),(p)[5]=(u8)((v)>>16),(p)[6]=(u8)((v)>>8),(p)[7]=(u8)(v) +#endif + +#define GETU32_LE(p) (*(const uint32_t *)(p)) +#define PUTU32_LE(p,a) *(uint32_t *)(p) = (a) +#define PUTU64_LE(p,a) *(uint64_t *)(p) = (a) + +#endif + diff --git a/src/chacha20.c b/src/chacha20.c new file mode 100644 index 00000000..88d57c3e --- /dev/null +++ b/src/chacha20.c @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2014 - 2020 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + + +#include +#include +#include +#include +#include "bswap.h" +#include "rotate.h" + +void chacha20_set_key(CHACHA20_STATE *state, + const unsigned char key[CHACHA20_KEY_SIZE], + const unsigned char nonce[CHACHA20_NONCE_SIZE], + uint32_t counter) +{ + state->d[ 0] = 0x61707865; + state->d[ 1] = 0x3320646e; + state->d[ 2] = 0x79622d32; + state->d[ 3] = 0x6b206574; + state->d[ 4] = GETU32_LE(key ); + state->d[ 5] = GETU32_LE(key + 4); + state->d[ 6] = GETU32_LE(key + 8); + state->d[ 7] = GETU32_LE(key + 12); + state->d[ 8] = GETU32_LE(key + 16); + state->d[ 9] = GETU32_LE(key + 20); + state->d[10] = GETU32_LE(key + 24); + state->d[11] = GETU32_LE(key + 28); + state->d[12] = counter; + state->d[13] = GETU32_LE(nonce); + state->d[14] = GETU32_LE(nonce + 4); + state->d[15] = GETU32_LE(nonce + 8); +} + +/* quarter round */ +#define QR(A, B, C, D) \ + A += B; D ^= A; D = ROL32(D, 16); \ + C += D; B ^= C; B = ROL32(B, 12); \ + A += B; D ^= A; D = ROL32(D, 8); \ + C += D; B ^= C; B = ROL32(B, 7) + +/* double round on state 4x4 matrix: + * four column rounds and and four diagonal rounds + * + * 0 1 2 3 + * 4 5 6 7 + * 8 9 10 11 + * 12 13 14 15 + * + */ +#define DR(S) \ + QR(S[0], S[4], S[ 8], S[12]); \ + QR(S[1], S[5], S[ 9], S[13]); \ + QR(S[2], S[6], S[10], S[14]); \ + QR(S[3], S[7], S[11], S[15]); \ + QR(S[0], S[5], S[10], S[15]); \ + QR(S[1], S[6], S[11], S[12]); \ + QR(S[2], S[7], S[ 8], S[13]); \ + QR(S[3], S[4], S[ 9], S[14]) + +void chacha20_generate_keystream(CHACHA20_STATE *state, unsigned int counts, unsigned char *out) +{ + uint32_t working_state[16]; + int i; + + while (counts-- > 0) { + memcpy(working_state, state->d, sizeof(working_state)); + for (i = 0; i < 10; i++) { + DR(working_state); + } + for (i = 0; i < 16; i++) { + working_state[i] += state->d[i]; + PUTU32_LE(out, working_state[i]); + out += sizeof(uint32_t); + } + state->d[12]++; + } +} diff --git a/src/cmac.c b/src/cmac.c new file mode 100644 index 00000000..062fb034 --- /dev/null +++ b/src/cmac.c @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2014 - 2020 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + +#include +#include +#include +#include +#include "internal/gf128.h" + +/* +CMAC的主体是CBC-MAC,或者说是CBC模式 +CMAC初始化的时候需要初始化E_K()中分组密码中的密钥编排 +用GSK算法通过密钥K生成K1, K2,这两个密钥最后是用来和最后一个分组做异或的 +*/ + +int cmac_init(CMAC_CTX *ctx, const BLOCK_CIPHER *cipher, const uint8_t *key, size_t keylen) +{ + gf128_t L; + + ctx->cipher = cipher; + cipher->set_encrypt_key(&ctx->cipher_key, key, keylen); + + /* L = E_K(0^128) */ + memset(ctx->temp_block, 0, 16); + cipher->encrypt(&ctx->cipher_key, ctx->temp_block, ctx->temp_block); + L = gf128_from_bytes(ctx->temp_block); + + + /* K1 = L * 2 over GF(2^128) */ + L = gf128_mul2(L); + gf128_to_bytes(L, ctx->k1); + + + /* K2 = K1 * 2 over GF(2^128) */ + L = gf128_mul2(L); + gf128_to_bytes(L, ctx->k2); + + memset(&L, 0, sizeof(gf128_t)); + return 0; +} + +int cmac_update(CMAC_CTX *ctx, const uint8_t *in, size_t inlen) +{ + if (ctx->last_block_nbytes) { + unsigned int left = BLOCK_CIPHER_BLOCK_SIZE - ctx->num; + if (inlen < left) { + memcpy(ctx->block + ctx->last_block_nbytes, in, inlen); + ctx->last_block_nbytes += inlen; + return 1; + } else { + memcpy(ctx->block + ctx->last_block_nbytes, in, inlen); + } + + } + + while (inlen > 16) { + XOR128(block, in); + ctx->cipher->encrypt(ctx->cipher_key, block, block); + } + + return 0; +} + +// 在Finish的时候我们不应该清空密钥的内容 +int cmac_finish(CMAC_CTX *ctx, size_t maclen, uint8_t *mac) +{ + if (ctx->last_block_nbytes == 16) { + xor128(ctx->data, ctx->k1); + } else { + ctx->data[ctx->last_block_nbytes] = 0x01; + memset(ctx->data + ctx->last_block_nbytes, 0, 16 - ctx->last_block_nbytes); + xor128(ctx->data, ctx->k2); + } + xor128(cipher, data); + + ctx->cipher->encrypt(ctx->cipher_key, ctx->block, ctx->block); + memcpy(out, block, outlen); + return 0; +} + +int cmac_finish_and_verify(CMAC_CTX *ctx, const uint8_t *mac, size_t maclen) +{ + uint8_t buf[16]; + cmac_finish(ctx, maclen, buf); + if (memcmp(buf, mac, maclen) != 0) { + return 0; + } + return 1; +} diff --git a/src/cms.c b/src/cms.c new file mode 100644 index 00000000..38669a3a --- /dev/null +++ b/src/cms.c @@ -0,0 +1,1526 @@ +/* + * Copyright (c) 2021 - 2021 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +int cms_issuer_and_serial_number_from_certificate(const X509_NAME **issuer, + const uint8_t **serial_number, size_t *serial_number_len, + const X509_CERTIFICATE *cert) +{ + const X509_TBS_CERTIFICATE *tbs = &cert->tbs_certificate; + *issuer = &tbs->issuer; + *serial_number = tbs->serial_number; + *serial_number_len = tbs->serial_number_len; + return 1; +} + +int cms_public_key_from_certificate(const SM2_KEY **sm2_key, + const X509_CERTIFICATE *cert) +{ + const X509_TBS_CERTIFICATE *tbs = &cert->tbs_certificate; + *sm2_key = &tbs->subject_public_key_info.sm2_key; + return 1; +} + + +int cms_issuer_and_serial_number_to_der(const X509_NAME *issuer, + const uint8_t *serial_number, size_t serial_number_len, + uint8_t **out, size_t *outlen) +{ + size_t len = 0; + + if (x509_name_to_der(issuer, NULL, &len) != 1 + || asn1_integer_to_der(serial_number, serial_number_len, NULL, &len) != 1 + || asn1_sequence_header_to_der(len, out, outlen) != 1 + || x509_name_to_der(issuer, out, outlen) != 1 + || asn1_integer_to_der(serial_number, serial_number_len, out, outlen) != 1) { + error_print(); + return -1; + } + return 1; +} + +int cms_issuer_and_serial_number_from_der(X509_NAME *issuer, + const uint8_t **serial_number, size_t *serial_number_len, + const uint8_t **in, size_t *inlen) +{ + int ret; + const uint8_t *data; + size_t datalen; + + if ((ret = asn1_sequence_from_der(&data, &datalen, in, inlen)) != 1) { + if (ret < 0) error_print(); + return ret; + } + if (x509_name_from_der(issuer, &data, &datalen) != 1 + || asn1_integer_from_der(serial_number, serial_number_len, &data, &datalen) != 1 + || datalen > 0) { + error_print(); + return -1; + } + return 1; +} + +// 打印的使用场景可能是没有header的 +int cms_issuer_and_serial_number_print(FILE *fp, const uint8_t *in, size_t inlen, int format, int indent) +{ + /* + int ret; + const uint8_t *data; + size_t datalen; + X509_NAME issuer; + const uint8_t *serial_number; + size_t serial_number_len; + + if ((ret = asn1_sequence_from_der(&data, &datalen, in, inlen)) != 1) { + if (ret < 0) error_print(); + return ret; + } + format_print(fp, format, indent, "IssuerAndSerialNumber\n"); + indent += 4; + + if (x509_name_from_der(&issuer, &data, &datalen) != 1) goto bad; + format_print(fp, format, indent, "issuer :\n"); + x509_name_print(fp, &issuer, format, indent); + + if (asn1_integer_from_der(&serial_number, &serial_number_len, &data, &datalen) != 1) goto bad; + format_bytes(fp, format, indent, "serialNumber : ", serial_number, serial_number_len); + return 1; +bad: + error_print(); + */ + return -1; +} + + + + + + + +static const uint32_t SM2_cms_oid[] = {1,2,156,10197,6,1,4,2}; + +const char *cms_content_type_name(int type) +{ + switch (type) { + case CMS_data: return "data"; + case CMS_signed_data: return "signedData"; + case CMS_enveloped_data: return "envelopedData"; + case CMS_signed_and_enveloped_data: return "signedAndEnvelopedData"; + case CMS_encrypted_data: return "encryptedData"; + case CMS_key_agreement_info: return "keyAgreementInfo"; + } + return NULL; +} + +int cms_content_type_to_der(int type, uint8_t **out, size_t *outlen) +{ + uint32_t cms_nodes[9] = {1,2,156,10197,6,1,4,2,0}; + + if (!cms_content_type_name(type)) { + error_print(); + return -1; + } + cms_nodes[8] = type; + if (asn1_object_identifier_to_der(OID_undef, cms_nodes, 9, out, outlen) != 1) { + error_print(); + return -1; + } + return 1; +} + +int cms_content_type_from_der(int *type, const uint8_t **in, size_t *inlen) +{ + const uint32_t cms_nodes[] = {1,2,156,10197,6,1,4,2,0}; + int ret; + + uint32_t nodes[32]; + size_t nodes_count; + + if (( ret = asn1_object_identifier_from_der(type, nodes, &nodes_count, in, inlen)) != 1) { + if (ret < 0) error_print(); + return ret; + } + + if (*type == OID_undef) { + if (nodes_count != 9) { + error_print(); + return -1; + } + if (memcmp(nodes, cms_nodes, 8) != 0) { + error_print(); + return -1; + } + if (cms_content_type_name(nodes[8]) == NULL) { + error_print(); + return -1; + } + *type = nodes[8]; + } + return 1; +} + +int cms_content_info_to_der(int content_type, const uint8_t *content, size_t content_len, + uint8_t **out, size_t *outlen) +{ + size_t len = 0; + + if (cms_content_type_to_der(content_type, NULL, &len) != 1 + || asn1_explicit_to_der(0, content, content_len, NULL, &len) != 1 + || asn1_sequence_header_to_der(len, out, outlen) != 1 + || cms_content_type_to_der(content_type, out, outlen) != 1 + || asn1_explicit_to_der(0, content, content_len, out, outlen) != 1) { + error_print(); + return -1; + } + return 1; +} + +int cms_content_info_from_der(int *content_type, const uint8_t **content, size_t *content_len, + const uint8_t **in, size_t *inlen) +{ + int ret; + const uint8_t *data; + size_t datalen; + + if ((ret = asn1_sequence_from_der(&data, &datalen, in, inlen)) != 1) { + if (ret < 0) error_print(); + return ret; + } + if (cms_content_type_from_der(content_type, &data, &datalen) != 1 + || asn1_explicit_from_der(0, content, content_len, &data, &datalen) != 1 + || datalen > 0) { + error_print(); + return -1; + } + return 1; +} + +int cms_content_info_set_data(uint8_t *content_info, size_t *content_info_len, + const uint8_t *data, size_t datalen) +{ + size_t len = 0; + size_t content_len = 0; + + *content_info_len = 0; + if (cms_content_type_to_der(CMS_data, NULL, &len) != 1 + || asn1_octet_string_to_der(data, datalen, NULL, &content_len) != 1 + || asn1_explicit_to_der(0, NULL, content_len, NULL, &len) != 1 + || asn1_sequence_header_to_der(len, &content_info, content_info_len) != 1 + || cms_content_type_to_der(CMS_data, &content_info, content_info_len) != 1 + || asn1_explicit_header_to_der(0, content_len, &content_info, content_info_len) != 1 + || asn1_octet_string_to_der(data, datalen, &content_info, content_info_len) != 1) { + error_print(); + return -1; + } + return 1; +} + +int cms_content_info_get_data(const uint8_t *content_info, size_t content_info_len, + const uint8_t **data, size_t *datalen) +{ + int ret; + const uint8_t *p; + size_t len; + int content_type; + const uint8_t *content; + size_t content_len; + + if (asn1_sequence_from_der(&p, &len, &content_info, &content_info_len) != 1 + || content_info_len > 0) { + error_print(); + return ret; + } + if (cms_content_type_from_der(&content_type, &p, &len) != 1 + || asn1_explicit_from_der(0, &content, &content_len, &p, &len) != 1 + || len > 0 + || asn1_octet_string_from_der(data, datalen, &content, &content_len) != 1 + || content_len > 0) { + error_print(); + return -1; + } + return 1; +} + +int cms_data_print(FILE *fp, const uint8_t *a, size_t alen, int format, int indent) +{ + const uint8_t *data; + size_t datalen; + + if (asn1_octet_string_from_der(&data, &datalen, &a, &alen) != 1) { + error_print(); + return -1; + } + format_bytes(fp, format, indent, "data : ", data, datalen); + if (alen > 0) { + error_print(); + return -1; + } + return 1; +} + +int cms_signer_info_to_der( + const X509_NAME *issuer, + const uint8_t *serial_number, size_t serial_number_len, + int digest_algor, + const uint8_t *authed_attrs, size_t authed_attrs_len, + const uint8_t *enced_digest, size_t enced_digest_len, + const uint8_t *unauthed_attrs, size_t unauthed_attrs_len, + uint8_t **out, size_t *outlen) +{ + size_t len = 0; + + if (asn1_int_to_der(CMS_version, NULL, &len) != 1 + || cms_issuer_and_serial_number_to_der(issuer, serial_number, serial_number_len, NULL, &len) != 1 + || x509_digest_algor_to_der(OID_sm3, NULL, &len) != 1 + || asn1_implicit_set_to_der(0, authed_attrs, authed_attrs_len, NULL, &len) < 0 + || x509_signature_algor_to_der(OID_sm2sign_with_sm3, NULL, &len) != 1 + || asn1_octet_string_to_der(enced_digest, enced_digest_len, NULL, &len) != 1 + || asn1_implicit_set_to_der(1, unauthed_attrs, unauthed_attrs_len, NULL, &len) < 0) { + error_print(); + return -1; + } + if (asn1_sequence_header_to_der(len, out, outlen) != 1 + || asn1_int_to_der(CMS_version, out, outlen) != 1 + || cms_issuer_and_serial_number_to_der(issuer, serial_number, serial_number_len, out, outlen) != 1 + || x509_digest_algor_to_der(OID_sm3, out, outlen) != 1) { + error_print(); + return -1; + } + if (0 + || asn1_implicit_set_to_der(0, authed_attrs, authed_attrs_len, out, outlen) < 0) { + error_print(); + return -1; + } + if (0 + || x509_signature_algor_to_der(OID_sm2sign_with_sm3, out, outlen) != 1) { + error_print(); + return -1; + } + if (0 + || asn1_octet_string_to_der(enced_digest, enced_digest_len, out, outlen) != 1 + || asn1_implicit_set_to_der(1, unauthed_attrs, unauthed_attrs_len, out, outlen) < 0) { + error_print(); + return -1; + } + return 1; +} + +int cms_signer_info_from_der(X509_NAME *issuer, + const uint8_t **serial_number, size_t *serial_number_len, + int *digest_algor, uint32_t *nodes, size_t *nodes_count, + const uint8_t **authed_attrs, size_t *authed_attrs_len, + int *sign_algor, uint32_t *sign_algor_nodes, size_t *sign_algor_nodes_count, + const uint8_t **enced_digest, size_t *enced_digest_len, + const uint8_t **unauthed_attrs, size_t *unauthed_attrs_len, + const uint8_t **in, size_t *inlen) +{ + int ret; + const uint8_t *data; + size_t datalen; + int version; + + if ((ret = asn1_sequence_from_der(&data, &datalen, in, inlen)) != 1) { + if (ret < 0) error_print(); + return ret; + } + if (asn1_int_from_der(&version, &data, &datalen) != 1 + || cms_issuer_and_serial_number_from_der(issuer, serial_number, serial_number_len, &data, &datalen) != 1 + || x509_digest_algor_from_der(digest_algor, nodes, nodes_count, &data, &datalen) != 1 + || asn1_implicit_set_from_der(0, authed_attrs, authed_attrs_len, &data, &datalen) < 0 + || x509_signature_algor_from_der(sign_algor, /*sign_algor_nodes, &sign_algor_nodes_count,*/ &data, &datalen) != 1 + || asn1_octet_string_from_der(enced_digest, enced_digest_len, &data, &datalen) != 1 + || asn1_implicit_set_from_der(1, unauthed_attrs, unauthed_attrs_len, &data, &datalen) < 0 + || datalen) { + error_print(); + return -1; + } + return 1; +} + +int cms_signer_info_print(FILE *fp, const uint8_t *a, size_t alen, int format, int indent) +{ + /* + int ret; + const uint8_t *data; + size_t datalen; + int version; + X509_NAME issuer; + + if ((ret = asn1_sequence_from_der(&data, &datalen, in, inlen)) != 1) { + if (ret < 0) error_print(); + return ret; + } + format_print(fp, format, indent, "SignerInfo:\n"); + indent += 4; + + if (asn1_int_from_der(&version, &data, &datalen) != 1) goto bad; + format_print(fp, format, indent, "Version: %d\n", version); + + if (cms_issuer_and_serial_number_from_der(&issuer, &serial_number, &serial_number_len, &data, &datalen) != 1) goto bad; + cms_issuer_and_serial_number_print(); // 这个不能这么弄啊! + + */ + return 1; +} + +int cms_signer_info_sign_to_der(const SM2_KEY *sm2_key, const SM3_CTX *sm3_ctx, + const X509_NAME *issuer, const uint8_t *serial_number, size_t serial_number_len, + const uint8_t *authed_attrs, size_t authed_attrs_len, + const uint8_t *unauthed_attrs, size_t unauthed_attrs_len, + uint8_t **out, size_t *outlen) +{ + SM3_CTX ctx; + uint8_t dgst[32]; + uint8_t sig[SM2_MAX_SIGNATURE_SIZE]; + size_t sig_len; + + memcpy(&ctx, sm3_ctx, sizeof(SM3_CTX)); + if (authed_attrs) { + uint8_t header[8]; + uint8_t *p = header; + size_t header_len = 0; + asn1_set_header_to_der(authed_attrs_len, &p, &header_len); + sm3_update(&ctx, header, header_len); + sm3_update(&ctx, authed_attrs, authed_attrs_len); + } + sm3_finish(&ctx, dgst); + sm2_sign(sm2_key, dgst, sig, &sig_len); + + if (cms_signer_info_to_der(issuer, serial_number, serial_number_len, + OID_sm3, authed_attrs, authed_attrs_len, sig, sig_len, + unauthed_attrs, unauthed_attrs_len, + out, outlen) != 1) { + error_print(); + return -1; + } + return 1; +} + +int cms_signer_info_verify_from_der( + const SM2_KEY *sm2_key, const SM3_CTX *sm3_ctx, + X509_NAME *issuer, const uint8_t **serial_number, size_t *serial_number_len, + int *digest_algor, uint32_t *digest_algor_nodes, size_t *digest_algor_nodes_count, + const uint8_t **authed_attrs, size_t *authed_attrs_len, + int *sign_algor, uint32_t *sign_algor_nodes, size_t *sign_algor_nodes_count, + const uint8_t **unauthed_attrs, size_t *unauthed_attrs_len, + const uint8_t **in, size_t *inlen) +{ + int ret; + SM3_CTX ctx; + uint8_t dgst[32]; + const uint8_t *sig; + size_t sig_len; + + if (cms_signer_info_from_der(issuer, serial_number, serial_number_len, + digest_algor, digest_algor_nodes, digest_algor_nodes_count, + authed_attrs, authed_attrs_len, + sign_algor, sign_algor_nodes, sign_algor_nodes_count, + &sig, &sig_len, + unauthed_attrs, unauthed_attrs_len, + in, inlen) != 1) { + error_print(); + return -1; + } + if (*digest_algor != OID_sm3) { + error_print(); + return -1; + } + if (*sign_algor != OID_sm2sign_with_sm3) { + error_print(); + return -1; + } + + memcpy(&ctx, sm3_ctx, sizeof(SM3_CTX)); + if (*authed_attrs) { + uint8_t header[8]; + uint8_t *p = header; + size_t header_len = 0; + asn1_set_header_to_der(*authed_attrs_len, &p, &header_len); + sm3_update(&ctx, header, header_len); + sm3_update(&ctx, *authed_attrs, *authed_attrs_len); + } + sm3_finish(&ctx, dgst); + + if ((ret = sm2_verify(sm2_key, dgst, sig, sig_len)) != 1) { + error_print(); + return -1; + } + return ret; +} + +int cms_signed_data_to_der( + const int *digest_algors, const size_t digest_algors_count, + const int content_type, const uint8_t *content, const size_t content_len, + const X509_CERTIFICATE *certs, size_t certs_count, + const uint8_t **crls, const size_t *crls_lens, const size_t crls_count, + const uint8_t **signer_infos, size_t *signer_infos_lens, size_t signer_infos_count, + uint8_t **out, size_t *outlen) +{ + size_t len = 0; + size_t digest_algors_len = 0; + size_t certs_len = 0; + size_t crls_len = 0; + size_t signer_infos_len = 0; + int i; + + /* + for (i = 0; i < digest_algors_count; i++) + x509_digest_algor_to_der(digest_algors[i], NULL, &digest_algors_len); + for (i = 0; i < certs_count; i++) + x509_certificate_to_der(&certs[i], NULL, &certs_len); + for (i = 0; i < crls_count; i++) + crls_len += crls_lens[i]; + for (i = 0; i < signer_infos_count; i++) + signer_infos_len += signer_infos_lens[i]; + + if (asn1_int_to_der(CMS_version, NULL, &len) != 1 + || asn1_set_to_der(NULL, digest_algors_len, NULL, &len) != 1 + || cms_content_info_to_der(content_type, content, content_len, NULL, &len) != 1 + || asn1_implicit_set_to_der(0, NULL, certs_len, NULL, &len) < 0 + || asn1_implicit_set_to_der(1, NULL, crls_len, NULL, &len) < 0 + || asn1_set_to_der(NULL, signer_infos_len, NULL, &len) != 1) { + error_print(); + return -1; + } + + if (asn1_sequence_to_der(len, out, outlen) != 1 + || asn1_int_to_der(CMS_version, out, outlen) != 1 + || asn1_set_header_to_der(digest_algors_len, out, outlen) != 1) { + error_print(); + return -1; + } + for (i = 0; i < digest_algors_count; i++) { + if (x509_digest_algor_to_der(digest_algors[i], out, outlen) != 1) { + error_print(); + return -1; + } + } + if (cms_content_info_to_der(content_type, content, content_len, out, outlen) != 1) { + error_print(); + return -1; + } + if (certs) { + if (asn1_implicit_set_header_to_der(0, certs_len, out, outlen) != 1) { + error_print(); + return -1; + } + for (i = 0; i < certs_count; i++) { + } + } + if (crls) { + for (i = 0; i < crls_count; i++) { + } + } + + + if (asn1_set_to_der(signer_infos_len, out, outlen) != 1) { + } + for (i = 0; i < signer_infos_count; i++) { + asn1_data_to_der(signer_infos[i], signer_infos_lens[i], out, outlen); + } + + */ + return -1; +} + +int cms_signed_data_from_der( + const uint8_t **digest_algors, size_t *digest_algors_len, + int *content_type, const uint8_t **content, size_t *content_len, + const uint8_t **certs, size_t *certs_len, + const uint8_t **crls, size_t *crls_len, + const uint8_t **signer_infos, size_t *signer_infos_len, + const uint8_t **in, size_t *inlen) +{ + int ret; + const uint8_t *data; + size_t datalen; + int version; + + if ((ret = asn1_sequence_from_der(&data, &datalen, in, inlen)) != 1) { + if (ret < 0) error_print(); + return ret; + } + if (asn1_int_from_der(&version, &data, &datalen) != 1 + || asn1_set_from_der(digest_algors, digest_algors_len, &data, &datalen) != 1 + || cms_content_info_from_der(content_type, content, content_len, &data, &datalen) != 1 + || asn1_implicit_set_from_der(0, certs, certs_len, &data, &datalen) < 0 + || asn1_implicit_set_from_der(1, crls, crls_len, &data, &datalen) < 0 + || asn1_set_from_der(signer_infos, signer_infos_len, &data, &datalen) != 1 + || datalen) { + error_print(); + return -1; + } + if (version != CMS_version) { + error_print(); + return -1; + } + return 1; +} + +int cms_signed_data_print(FILE *fp, const uint8_t *a, size_t alen, int format, int indent) +{ + const uint8_t *data; + size_t datalen; + + int version; + int algor; + uint32_t nodes[32]; + size_t nodes_count; + const uint8_t *certs; + size_t certslen; + const uint8_t *crls; + size_t crlslen; + const uint8_t *signer_infos; + size_t signer_infos_len; + + if (asn1_sequence_from_der(&data, &datalen, &a, &alen) != 1) { + error_print(); + return -1; + } + + if (asn1_int_from_der(&version, &data, &datalen) != 1) goto bad; + format_print(fp, format, indent, "Version : %d\n", version); + + if (x509_digest_algor_from_der(&algor, nodes, &nodes_count, &data, &datalen) != 1) goto bad; + format_print(fp, format, indent, "DigestAlgorithm : %s\n", x509_digest_algor_name(algor)); + + if (asn1_implicit_sequence_from_der(0, &certs, &certslen, &data, &datalen) < 0) goto bad; + + if (asn1_implicit_sequence_from_der(1, &crls, &crlslen, &data, &datalen) < 0) goto bad; + + if (asn1_sequence_from_der(&signer_infos, &signer_infos_len, &data, &datalen) != 1) goto bad; + + +bad: + error_print(); + + return -1; +} + +int cms_signed_data_sign_to_der(const SM2_KEY *sign_keys, + const X509_CERTIFICATE *sign_certs, size_t sign_count, + int content_type, const uint8_t *content, size_t content_len, + const uint8_t **crls, size_t *crls_lens, size_t crls_count, + uint8_t **out, size_t *outlen) +{ + uint8_t *p; + size_t len = 0; + uint8_t digest_algors[16]; + size_t digest_algors_len = 0; + size_t sign_certs_len = 0; + size_t certs_len = 0; + size_t crls_len = 0; + size_t signer_infos_len = 0; + uint8_t sigs[sign_count][SM2_MAX_SIGNATURE_SIZE]; + size_t siglens[sign_count]; + int i; + + p = digest_algors; + x509_digest_algor_to_der(OID_sm3, &p, &digest_algors_len); + for (i = 0; i < sign_count; i++) { + if (x509_certificate_to_der(&sign_certs[i], NULL, &sign_certs_len) != 1) { + error_print(); + return -1; + } + } + for (i = 0; i < crls_count; i++) { + crls_len += crls_lens[i]; + } + + for (i = 0; i < sign_count; i++) { + const X509_CERTIFICATE *cert = &sign_certs[i]; + const X509_NAME *issuer = &cert->tbs_certificate.issuer; + const uint8_t *serial_number = cert->tbs_certificate.serial_number; + size_t serial_number_len = cert->tbs_certificate.serial_number_len; + + SM2_SIGN_CTX sign_ctx; + sm2_sign_init(&sign_ctx, &sign_keys[i], SM2_DEFAULT_ID); + sm2_sign_update(&sign_ctx, content, content_len); + sm2_sign_finish(&sign_ctx, sigs[i], &siglens[i]); + + if (cms_signer_info_to_der(issuer, serial_number, serial_number_len, + OID_sm3, NULL, 0, sigs[i], siglens[i], NULL, 0, + NULL, &signer_infos_len) != 1) { + error_print(); + return -1; + } + } + + len = 0; + if (asn1_int_to_der(CMS_version, NULL, &len) != 1 + || asn1_set_to_der(digest_algors, digest_algors_len, NULL, &len) != 1 + || cms_content_info_to_der(content_type, content, content_len, NULL, &len) != 1 + || asn1_implicit_set_to_der(0, NULL, certs_len, NULL, &len) < 0 + || asn1_implicit_set_to_der(1, NULL, crls_len, NULL, &len) < 0 + || asn1_set_to_der(NULL, signer_infos_len, NULL, &len) != 1) { + error_print(); + return -1; + } + + + if (asn1_sequence_header_to_der(len, out, outlen) != 1 + || asn1_int_to_der(CMS_version, out, outlen) != 1 + || asn1_set_to_der(digest_algors, digest_algors_len, out, outlen) != 1 + || cms_content_info_to_der(content_type, content, content_len, out, outlen) != 1 + || asn1_implicit_set_header_to_der(0, certs_len, out, outlen) != 1) { + error_print(); + return -1; + } + for (i = 0; i < sign_count; i++) { + if (x509_certificate_to_der(&sign_certs[i], out, outlen) != 1) { + error_print(); + return -1; + } + } + if (crls) { + if (asn1_implicit_set_header_to_der(1, crls_len, out, outlen) != 1) { + error_print(); + return -1; + } + for (i = 0; i < crls_count; i++) { + asn1_data_to_der(crls[i], crls_lens[i], out, outlen); + } + } + asn1_set_header_to_der(signer_infos_len, out, outlen); + for (i = 0; i < sign_count; i++) { + const X509_CERTIFICATE *cert = &sign_certs[i]; + const X509_NAME *issuer = &cert->tbs_certificate.issuer; + const uint8_t *serial_number = cert->tbs_certificate.serial_number; + size_t serial_number_len = cert->tbs_certificate.serial_number_len; + + if (cms_signer_info_to_der(issuer, serial_number, serial_number_len, + OID_sm3, NULL, 0, sigs[i], siglens[i], NULL, 0, out, outlen) != 1) { + error_print(); + return -1; + } + } + + return 1; +} + +int cms_signed_data_verify_from_der(const uint8_t *signed_data, size_t signed_data_len) +{ + int version; + int content_type; + const uint8_t *digest_algors; + const uint8_t *content; + const uint8_t *certs; + const uint8_t *crls; + const uint8_t *signer_infos; + size_t digest_algors_len; + size_t content_len; + size_t certs_len; + size_t crls_len; + size_t signer_infos_len; + + /* + if (asn1_sequence_from_der(&data, &datalen, &signed_data, &signed_data_len) != 1 + || signed_data_len > 0) { + error_print(); + return -1; + } + if (asn1_int_from_der(&version, &data, &datalen) != 1 + || asn1_set_from_der(&digest_algors, &digest_algors_len, &data, &datalen) != 1 + || cms_content_info_from_der(&content_type, &content, &content_len, &data, &datalen) != 1 + || asn1_implicit_set_from_der(0, &certs, &certs_len, &data, &datalen) < 0 + || asn1_implicit_set_from_der(1, &crls, &crls_len, &data, &datalen) < 0 + || asn1_set_from_der(&signer_infos, &signer_infos_len, &data, &datalen) != 1) { + error_print(); + return -1; + } + + len = signer_infos_len; + + while (len > 0) { + cms_signer_info_from_der(); + + + cms_signer_info_match(); + + cms_signer_info_verify(); + + } + */ + + return -1; +} + +int cms_sign(const SM2_KEY *sign_keys, + const X509_CERTIFICATE *sign_certs, size_t sign_count, + int content_type, const uint8_t *content, size_t content_len, + const uint8_t **crls, size_t *crls_lens, size_t crls_count, + uint8_t *content_info, size_t *content_info_len) +{ + size_t len = 0; + size_t signed_data_len = 0; + + if (cms_signed_data_sign_to_der(sign_keys, sign_certs, sign_count, + content_type, content, content_len, crls, crls_lens, crls_count, + NULL, &signed_data_len) != 1) { + error_print(); + return -1; + } + if (cms_content_type_to_der(CMS_signed_data, NULL, &len) != 1 + || asn1_explicit_to_der(0, NULL, signed_data_len, NULL, &len) != 1 + || asn1_sequence_header_to_der(len, &content_info, content_info_len) != 1 + || cms_content_type_to_der(CMS_signed_data, &content_info, content_info_len) != 1 + || asn1_explicit_header_to_der(0, signed_data_len, &content_info, content_info_len) != 1 + || cms_signed_data_sign_to_der(sign_keys, sign_certs, sign_count, + content_type, content, content_len, crls, crls_lens, crls_count, + &content_info, content_info_len) != 1) { + error_print(); + return -1; + } + return 1; +} + + +int cms_verify(int *content_type, const uint8_t **content, size_t *content_len, + const uint8_t *content_info, size_t content_info_len) +{ + return -1; +} + +int cms_content_info_print(FILE *fp, const uint8_t *a, size_t alen, int format, int indent) +{ + int ret; + int oid; + const uint8_t *data; + size_t datalen; + uint32_t nodes[32]; + size_t nodes_count; + const uint8_t *content; + size_t content_len; + + format_print(fp, format, indent, "ContentInfo:\n"); + indent += 4; + if ((ret = asn1_sequence_from_der(&data, &datalen, &a, &alen)) != 1) { + error_print(); + return -1; + } + + if (cms_content_type_from_der(&oid, &data, &datalen) != 1) goto bad; + format_print(fp, format, indent, "Type : %s\n", cms_content_type_name(oid)); + if (asn1_explicit_from_der(0, &content, &content_len, &data, &datalen) != 1) goto bad; + + switch (oid) { + case CMS_data: return cms_data_print(fp, content, content_len, format, indent); + case CMS_signed_data: return cms_signed_data_print(fp, content, content_len, format, indent); + case CMS_enveloped_data: + case CMS_signed_and_enveloped_data: + case CMS_encrypted_data: + case CMS_key_agreement_info: + break; + } + return 1; + +bad: + error_print(); + return -1; +} + + + +#if 0 + +int cms_recipient_info_to_der(const X509_NAME *issuer, + const uint8_t *serial_number, size_t serial_number_len, + const uint8_t *enced_key, size_t enced_key_len, + uint8_t **out, size_t *outlen) +{ + size_t len = 0; + + if (asn1_int_to_der(CMS_version, NULL, &len) != 1 + || cms_issuer_and_serial_number_to_der(issuer, serial_number, serial_number_len, NULL, &len) != 1 + || x509_key_encryption_algor_to_der(OID_sm2encrypt, NULL, &len) != 1 + || asn1_octet_string_to_der(enced_key, enced_key_len, NULL, &len) != 1) { + error_print(); + return -1; + } + if (asn1_sequence_header_to_der(len, out, outlen) != 1 + || asn1_int_to_der(CMS_version, out, &outlen) != 1 + || cms_issuer_and_serial_number_to_der(issuer, serial_number, serial_number_len, out, &outlen) != 1 + || x509_key_encryption_algor_to_der(OID_sm2encrypt, out, &outlen) != 1 + || asn1_octet_string_to_der(enced_key, enced_key_len, out, &outlen) != 1) { + error_print(); + return -1; + } + return 1; +} + +int cms_recipient_info_from_der(X509_NAME *issuer, + const uint8_t **serial_number, size_t *serial_number_len, + const uint8_t **enced_key, size_t *enced_key_len, + const uint8_t **in, size_t *inlen) +{ + int ret; + const uint8_t *data; + size_t datalen; + + if ((ret = asn1_sequence_from_der(&data, &datalen, in, inlen)) != 1) { + if (ret < 0) error_print(); + return ret; + } + if (asn1_int_from_der(&version, &data, &datalen) != 1 + || cms_issuer_and_serial_number_from_der(issuer, serial_number, serial_number_len, &data, &datalen) != 1 + || x509_public_key_algor_from_der(kenc_algor, enc_algor_nodes, enc_algor_nodes, &data, &datalen) != 1 + || asn1_octet_string_from(enced_key, enced_key_len, &data, &datalen) != 1 + || datalen) { + error_print(); + return -1; + } + if (version != CMS_version) { + error_print(); + return -1; + } + + return -1; +} + +int cms_recipient_info_print(FILE *fp, const uint8_t *a, size_t alen, int format, int indent) +{ + return -1; +} + +int sm2_recipient_info_encrypt_to_der(const SM2_KEY *sm2_key, + const X509_NAME *issuer, const uint8_t *serial_number, size_t serial_number_len, + const uint8_t *key, size_t keylen, + uint8_t *rcpt_info, size_t *rcpt_info_len) +{ + size_t len = 0; + uint8_t buf[keylen + 256]; + size_t buflen; + + sm2_encrypt(sm2_key, key, keylen, buf, &buflen); + + *rcpt_info_len = 0; + cms_recipient_info_to_der(issuer, serial_number, serial_number_len, + buf, buflen, &rcpt_info, rcpt_info_len); + + return 1; +} + +int sm2_recipient_info_decrypt_from_der(const SM2_KEY *sm2_key, + X509_NAME *issuer, const uint8_t **serial_number, size_t *serial_number_len, + uint8_t *key, size_t *keylen, + const uint8_t **in, size_t *inlen) +{ + if (cms_recipient_info_from_der(issuer, serial_number, serial_number_len, + &enced_key, &enced_key_len, &rcpt_info, &rcpt_info_len) != 1 + || rcpt_info_len) { + error_print(); + return -1; + } + + sm2_decrypt(sm2_key, enced_key, enced_key_len, key, keylen); + return -1; +} + +int cms_enced_content_info_to_der(int enc_algor, const uint8_t enc_iv[16], + int content_type, const uint8_t *enced_content, size_t enced_content_len, + const uint8_t *shared_info1, size_t shared_info1_len, + const uint8_t *shared_info2, size_t shared_info2_len, + uint8_t **out, size_t *outlen) +{ + size_t len = 0; + + if (cms_content_type_to_der(content_type, NULL, &len) != 1 + || x509_encryption_algor_to_der(enc_algor, enc_iv, NULL, &len) != 1 + || asn1_implicit_octet_string_to_der(0, enced_content, enced_content_len, NULL, &len) < 0 + || asn1_implicit_octet_string_to_der(1, shared_info1, shared_info1_len, NULL, &len) < 0 + || asn1_implicit_octet_string_to_der(2, shared_info2, shared_info2_len, NULL, &len) < 0) { + error_print(); + return -1; + } + if (asn1_sequence_header_to_der(len, out, outlen) != 1 + || cms_content_type_to_der(content_type, out, outlen) != 1 + || x509_encryption_algor_to_der(enc_algor, enc_iv, out, outlen) != 1 + || asn1_implicit_octet_string_to_der(0, enced_content, enced_content_len, out, outlen) < 0 + || asn1_implicit_octet_string_to_der(1, shared_info1, shared_info1_len, out, outlen) < 0 + || asn1_implicit_octet_string_to_der(2, shared_info2, shared_info2_len, out, outlen) < 0) { + error_print(); + return -1; + } + return 1; +} + +int cms_enced_content_info_from_der( + int *content_type, + int *enc_algor, uint32_t *enc_algor_nodes, size_t *enc_algor_nodes_count, + const uint8_t **enc_iv, size_t *enc_iv_len, + const uint8_t **enced_content, size_t *enced_content_len, + const uint8_t **shared_info1, size_t *shared_info1_len, + const uint8_t **shared_info2, size_t *shared_info2_len, + const uint8_t **in, size_t *inlen) +{ + int ret; + const uint8_t *data; + size_t datalen; + + if ((ret = asn1_sequence_from_der(&data, &datalen, in, inlen)) != 1) { + if (ret < 0) error_print(); + return ret; + } + if (cms_content_type_from_der(content_type, &data, &datalen) != 1 + || x509_encryption_algor_from_der(enc_algor, enc_algor_nodes, enc_algor_nodes_count, + enc_iv, enc_iv_len, &data, &datalen) != 1 + || asn1_implicit_octet_string_from_der(0, enced_content, enced_content_len, &data, &datalen) < 0 + || asn1_implicit_octet_string_from_der(1, shared_info1, shared_info1_len, &data, &datalen) < 0 + || asn1_implicit_octet_string_from_der(1, shared_info2, shared_info2_len, &data, &datalen) < 0 + || datalen) { + error_print(); + return -1; + } + return 1; +} + +int cms_enced_content_info_print(FILE *fp, const uint8_t *a, size_t alen, int format, int indent) +{ + return -1; +} + +int cms_enced_content_info_encrypt_to_der(const SM4_KEY *sm4_key, const uint8_t iv[16], + int content_type, const uint8_t *content, size_t content_len, + const uint8_t *shared_info1, size_t shared_info1_len, + const uint8_t *shared_info2, size_t shared_info2_len, + uint8_t *enced_content_info, size_t *enced_content_info_len) +{ + uint8_t enced_content[content_len + 256]; + size_t enced_content_len; + + if (sm4_cbc_padding_encrypt(sm4_key, iv, content, content_len, + enced_content, &enced_content_len) != 1) { + error_print(); + return -1; + } + + *enced_content_info_len = 0; + if (cms_enced_content_info_to_der(OID_sm4_cbc, iv, + content_type, enced_content, enced_content_len, + shared_info1, shared_info1_len, + shared_info2, shared_info2_len, + &enced_content_info, enced_content_info_len) != 1) { + error_print(); + return -1; + } + return 1; +} + +int cms_enced_content_info_decrypt_from_der(const SM4_KEY *sm4_key, + const uint8_t *enced_content_info, size_t enced_content_info_len, + int *content_type, uint8_t *content, size_t *content_len, + const uint8_t **shared_info1, size_t *shared_info1_len, + const uint8_t **shared_info2, size_t *shared_info2_len) +{ + int enc_algor; + uint32_t enc_algor_nodes[32]; + size_t enc_algor_nodes_count; + const uint8_t *enc_iv; + size_t enc_iv_len; + const uint8_t *enced_content; + size_t enced_content_len; + + if (cms_enced_content_info_from_der(content_type, + &enc_algor, enc_algor_nodes, &enc_algor_nodes_count, + &enc_iv, &enc_iv_len, + &enced_content, &enced_content_len, + shared_info1, shared_info1_len, + shared_info2, shared_info2_len, + &enced_content_info, &enced_content_info_len) != 1 + || enced_content_info_len) { + error_print(); + return -1; + } + if (sm4_cbc_padding_decrypt(sm4_key, enc_iv, enced_content, enced_content_len, + content, content_len) != 1) { + error_print(); + return -1; + } + return 1; +} + +int cms_enveloped_data_to_der() +{ +} + +int cms_enveloped_data_from_der(const uint8_t **rcpt_infos, size_t *rcpt_infos_len, + int *content_type, + int *enc_algor, uint32_t *enc_algor_nodes, size_t *enc_algor_nodes_count, + const uint8_t **enc_iv, size_t *enc_iv_len, + const uint8_t **enced_content, size_t *enced_content_len, + const uint8_t **shared_info1, size_t *shared_info1_len, + const uint8_t **shared_info2, size_t *shared_info2_len, + const uint8_t **in, size_t *inlen) +{ + int ret; + const uint8_t *data; + size_t datalen; + + if ((ret = asn1_sequence_from_der(&data, &datalen, in, inlen)) != 1) { + if (ret < 0) error_print(); + return ret; + } + if (asn1_int_from_der(&version, &data, &datalen) != 1 + || asn1_set_from_der(rcpt_infos, rcpt_infos_len, &data, &datalen) != 1 + || asn1_type_from_der(enced_content_info, enced_content_info_len, &data, &datalen) != 1 //FIXME: + || datalen > 0) { + error_print(); + return -1; + } + return 1; +} + +int cms_enveloped_data_print(FILE *fp, const uint8_t *a, size_t alen, int format, int indent) +{ + return -1; +} + +int cms_enveloped_data_encrypt_to_der(const X509_CERTIFICATE *rcpt_certs, size_t rcpt_count, + int content_type, const uint8_t *content, size_t content_len, + const uint8_t *shared_info1, size_t shared_info1_len, + const uint8_t *shared_info2, size_t shared_info2_len, + uint8_t *enveloped_data, size_t *enveloped_data_len) +{ + size_t len = 0; + SM4_KEY sm4_key; + uint8_t enc_key[16]; + uint8_t enc_iv[16]; + uint8_t enced_key[rcpt_count][256 + 16]; + uint8_t enced_content_info[content_len + 512]; + size_t enced_content_info_len; + + rand_bytes(enc_key, 16); + rand_bytes(enc_iv, 16); + + for (i = 0; i < rcpt_count; i++) { + const SM2_KEY *sm2_key = x509_certificate_get_public_key(rcpt_certs[i]); + sm2_encrypt(sm2_key, enc_key, 16, enced_key[i], enced_key_len[i]); + } + + for (i = 0; i < rcpt_count; i++) { + x509_certificate_get_recipient_info(rcpt_cert, + &issuer, + &serial_number, &serial_number_len, + &sm2_key); + + cms_recipient_info_encrypt_to_der(issuer, + serial_number, serial_number_len, + enced_key, enced_key_len, + NULL, &rcpt_infos_len); + } + + + if (asn1_int_to_der(CMS_version, NULL, &len) != 1 + || asn1_set_to_der(NULL, rcpt_infos_len, NULL, &len) != 1 + || cms_enced_content_info_encrypt_to_der(&sm4_key, enc_iv, + content_type, content, content_len, + shared_info1, shared_info1_len, + shared_info2, shared_info2_len, + NULL, &len) != 1) { + error_print(); + return -1; + } + + if (asn1_sequence_header_to_der(len, out, outlen) != 1 + || asn1_int_to_der(CMS_version, out, outlen) != 1 + || asn1_set_header_to_der(rcpt_infos_len, out, outlen) != 1) { + error_print(); + return -1; + } + for (i = 0; i < rcpt_count; i++) { + if (cms_recipient_info_encrypt_to_der(&sm2_key, issuer, + serial_number, serial_number_len, + enc_key, sizeof(enc_key), out, outlen) != 1) { + error_print(); + return -1; + } + } + if (cms_enced_content_info_encrypt_to_der(&sm4_key, enc_iv, + content_type, content, content_len, + shared_info1, shared_info1_len, + shared_info2, shared_info2_len, + out, &outlen) != 1) { + error_print(); + return -1; + } + + return 1; +} + +int cms_enveloped_data_decrypt_from_der(const SM2_KEY *sm2_key, const X509_CERTIFICATE *cert, + const uint8_t *enveloped_data, size_t enveloped_data_len, + int *content_type, uint8_t *content, size_t *content_len) +{ + const uint8_t *rcpt_infos; + size_t rcpt_infos_len; + int enc_algor; + uint32_t enc_algor_nodes[32]; + size_t enc_algor_nodes_count; + const uint8_t *enced_content; + size_t enced_content_len; + const uint8_t *shared_info1; + size_t shared_info1_len; + const uint8_t *shared_info2; + size_t shared_info2_len; + uint8_t enc_key[64]; + size_t enc_key_len; + + if (cms_enveloped_data_from_der(&rcpt_infos, &rcpt_infos_len, + content_type, &enc_algor, enc_algor_nodes, &enc_algor_nodes_count, + &enc_iv, &enc_iv_len, + &enced_content, &enced_content_len, &shared_info1, &shared_info1_len, + &shared_info2, &shared_info2_len, &enveloped_data, &enveloped_data_len) != 1 + || enced_content_info_len > 0) { + error_print(); + return -1; + } + if (enc_algor != OID_sm4_cbc) { + error_print(); + return -1; + } + if (!enc_iv || enc_iv_len != 16) { + error_print(); + return -1; + } + + while (rcpt_infos_len) { + X509_NAME issuer; + const uint8_t *serial_number; + size_t serial_number_len; + const uint8_t *enced_key; + size_t enced_key_len; + + if (cms_recipient_info_from_der(&issuer, &serial_number, &serial_number_len + &enced_key, &enced_key_len, &rcpt_infos, &rcpt_infos_len) != 1) { + error_print(); + return -1; + } + if (cms_issuer_and_serial_number_match_certificate(&issuer, + serial_number, serial_number_len, cert) != 1) { + break; + } + if (sm2_decrypt(sm2_key, enced_key, enced_key_len, enc_key, &enc_key_len) != 1) { + error_print(); + return -1; + } + } + + sm4_set_decrypt_key(&sm4_key, enc_key); + if (sm4_cbc_paddnig_decrypt(&sm4_key, enc_iv, enced_content, enced_content_len, + content, content_len) != 1) { + error_print(); + return -1; + } + + return -1; +} + +int cms_signed_and_enveloped_data_to_der() +{ +} + +int cms_signed_and_enveloped_data_from_der() +{ +} + +int cms_signed_and_enveloped_data_print() +{ +} + +int cms_signed_and_enveloped_data_sign_encrypt_to_der( + const int *digest_algors, const size_t digset_algors_count, + const X509_CERTIFICATE *sign_certs, size_t sign_count, + const uint8_t **crls, const size_t *crls_lens, const size_t crls_count, + const uint8_t **signer_infos, size_t *signer_infos_lens, size_t signer_infos_count, + const X509_CERTIFICATE *rcpt_certs, size_t rcpt_count, + int content_type, const uint8_t *content, size_t content_len, + const uint8_t *shared_info1, size_t shared_info1_len, + const uint8_t *shared_info2, size_t shared_info2_len, + uint8_t **out, size_t *outlen) +{ + + size_t len = 0; + SM4_KEY sm4_key; + uint8_t enc_key[16]; + uint8_t enc_iv[16]; + uint8_t enced_key[rcpt_count][256 + 16]; + uint8_t enced_content_info[content_len + 512]; + size_t enced_content_info_len; + + rand_bytes(enc_key, 16); + rand_bytes(enc_iv, 16); + + for (i = 0; i < rcpt_count; i++) { + const SM2_KEY *sm2_key = x509_certificate_get_public_key(rcpt_certs[i]); + sm2_encrypt(sm2_key, enc_key, 16, enced_key[i], enced_key_len[i]); + } + + for (i = 0; i < rcpt_count; i++) { + x509_certificate_get_recipient_info(rcpt_cert, + &issuer, + &serial_number, &serial_number_len, + &sm2_key); + + cms_recipient_info_encrypt_to_der(issuer, + serial_number, serial_number_len, + enced_key, enced_key_len, + NULL, &rcpt_infos_len); + } + + if (asn1_int_to_der(CMS_version, NULL, &len) != 1 + || asn1_set_to_der(NULL, rcpt_infos_len, NULL, &len) != 1 + || cms_enced_content_info_encrypt_to_der(&sm4_key, enc_iv, + content_type, content, content_len, + shared_info1, shared_info1_len, + shared_info2, shared_info2_len, + NULL, &len) != 1) { + error_print(); + return -1; + } + + if (asn1_sequence_header_to_der(len, out, outlen) != 1 + || asn1_int_to_der(CMS_version, out, outlen) != 1 + || asn1_set_header_to_der(rcpt_infos_len, out, outlen) != 1) { + error_print(); + return -1; + } + for (i = 0; i < rcpt_count; i++) { + if (cms_recipient_info_encrypt_to_der(&sm2_key, issuer, + serial_number, serial_number_len, + enc_key, sizeof(enc_key), out, outlen) != 1) { + error_print(); + return -1; + } + } + if (cms_enced_content_info_encrypt_to_der(&sm4_key, enc_iv, + content_type, content, content_len, + shared_info1, shared_info1_len, + shared_info2, shared_info2_len, + out, &outlen) != 1) { + error_print(); + return -1; + } + + return 1; +} + +int cms_signed_and_enveloped_data_decrypt_verify_from_der() +{ + return -1; +} + + + + + + + + + + + + + + + +int cms_enced_data_to_der(int enc_algor, const uint8_t enc_iv[16], + int content_type, const uint8_t *enced_content, size_t enced_content_len, + const uint8_t *shared_info1, size_t shared_info1_len, + const uint8_t *shared_info2, size_t shared_info2_len, + uint8_t **out, size_t *outlen) +{ + size_t len = 0; + + if (asn1_int_to_der(CMS_version, NULL, &len) != 1 + || cms_enced_content_info_to_der(enc_algor, enc_iv, + content_type, enced_content, enced_content_len + shared_info1, shared_info1_len, + shared_info2, shared_info2_len, + NULL, &len) != 1) { + error_print(); + return -1; + } + if (asn1_sequence_header_to_der(len, out, outlen) != 1 + || asn1_int_to_der(CMS_version, out, outlen) != 1 + || cms_enced_content_info_to_der(enc_algor, enc_iv, + content_type, enced_content, enced_content_len + shared_info1, shared_info1_len, + shared_info2, shared_info2_len, + out, outlen) != 1) { + error_print(); + return -1; + } + return 1; +} + +int cms_enced_data_from_der( + int *content_type, + int *enc_algor, uint32_t *enc_algor_nodes, size_t *enc_algor_nodes_count, + const uint8_t **enc_iv, size_t *enc_iv_len, + const uint8_t **enced_content, size_t *enced_content_len, + const uint8_t **shared_info1, size_t *shared_info1_len, + const uint8_t **shared_info2, size_t *shared_info2_len, + const uint8_t **in, size_t *inlen) +{ + int ret; + const uint8_t *data; + size_t datalen; + int version; + + if ((ret = asn1_sequence_from_der(&data, &datalen, in, inlen)) != 1) { + if (ret < 0) error_print(); + return ret; + } + if (asn1_int_from_der(&version, &data, &datalen) != 1 + || cms_enced_content_info_from_der(content_type, + enc_algor, enc_algor_nodes, enc_algor_nodes_count, + enc_iv, enc_iv_len, + enced_content, enced_content_len, + shared_info1, shared_info1_len, + shared_info2, shared_info2_len, + &data, &datalen) != 1 + || datalen > 0) { + error_print(); + return -1; + } + if (version != CMS_version) { + error_print(); + return -1; + } + return 1; +} + +int cms_encrypted_data_encrypt_to_der(const SM4_KEY *sm4_key, const uint8_t iv[16], + int content_type, const uint8_t *content, size_t content_len, + const uint8_t *shared_info1, size_t shared_info1_len, + const uint8_t *shared_info2, size_t shared_info2_len, + uint8_t **out, size_t *outlen) +{ + size_t len = 0; + + if (asn1_int_to_der(CMS_version, NULL, &len) != 1 + || cms_encrypted_content_info_to_der(sm4_key, iv, + content_type, content, content_len, + shared_info1, shared_info1_len, + shared_info2, shared_info2_len, + NULL, &len) != 1) { + error_print(); + return -1; + } + if (asn1_sequence_header_to_der(len, out, outlen) != 1 + || asn1_int_to_der(CMS_version, out, outlen) != 1 + || cms_encrypted_content_info_to_der(sm4_key, iv, + content_type, content, content_len, + shared_info1, shared_info1_len, + shared_info2, shared_info2_len, + out, outlen) != 1) { + error_print(); + return -1; + } + return 1; +} + +int cms_key_agreement_info_to_der(const SM2_KEY *pub_key, const X509_CERTIFICATE *cert, + const uint8_t *user_id, size_t user_id_len, uint8_t **out, size_t *outlen) +{ + size_t len = 0; + + if (asn1_int_to_der(CMS_version, NULL, &len) != 1 + || sm2_public_key_info_to_der(pub_key, NULL, &len) != 1 + || x509_certificate_to_der(cert, NULL, &len) != 1 + || asn1_octet_string_to_der(user_id, user_id_len, NULL, &len) != 1) { + error_print(); + return -1; + } + if (asn1_sequence_header_to_der(len, out, outlen) != 1 + || asn1_int_to_der(CMS_version, out, &outlen) != 1 + || sm2_public_key_info_to_der(pub_key, out, &outlen) != 1 + || x509_certificate_to_der(cert, out, &outlen) != 1 + || asn1_octet_string_to_der(user_id, user_id_len, out, &outlen) != 1) { + error_print(); + return -1; + } + return 1; +} + +int cms_key_agreement_info_from_der(SM2_KEY *pub_key, X509_CERTIFICATE *cert, + const uint8_t **user_id, size_t *user_id_len, const uint8_t **in, size_t *inlen) +{ + int ret; + const uint8_t *data; + size_t datalen; + + if ((ret = asn1_sequence_from_der(&data, &datalen, in, inlen)) != 1) { + if (ret < 0) error_print(); + return ret; + } + if (asn1_int_from_der(&version, &data, &datalen) != 1 + || sm2_public_key_info_from_der(pub_key, &data, &datalen) != 1 + || x509_certificate_from_der(cert, &data, &datalen) != 1 + || asn1_octet_string_from_der(user_id, user_id_len, &data, &datalen) != 1 + || datalen > 0) { + error_print(); + return -1; + } + return 1; +} + + +#endif diff --git a/src/ctr.c b/src/ctr.c new file mode 100644 index 00000000..3e645ac4 --- /dev/null +++ b/src/ctr.c @@ -0,0 +1,298 @@ +/* + * Copyright (c) 2014 - 2020 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + + +#include +#include +#include + + +/* + * GHASH(H, A, C) = X_{m + n + 1} + * A additional authenticated data, A = A_1, ..., A_{m-1}, A_m^*, nbits(A_m^*) = v + * C ciphertext, C = C_1, ..., C_{n-1}, C_n^*, nbits(C_n^*) = u + * H = E_K(0^128) + * + * X_i = 0 for i = 0 + * = (X_{i-1} xor A_i ) * H for i = 1, ..., m-1 + * = (X_{m-1} xor (A_m^* || 0^{128-v})) * H for i = m + * = (X_{i-1} xor C_i ) * H for i = m+1, ..., m + n − 1 + * = (X_{m+n-1} xor (C_m^* || 0^{128-u})) * H for i = m + n + * = (X_{m+n} xor (nbits(A)||nbits(A))) * H for i = m + n + 1 + */ +void ghash_init(GHASH_CTX *ctx, const uint8_t h[16], const uint8_t *aad, size_t aadlen) +{ + __uint128_t H; + __uint128_t X; + __uint128_t A; + + memset(ctx, 0, sizeof(GHASH_CTX)); + + /* get H in GF(2^128) as little endian */ + ctx->H = H = GETU128_LE(h); + ctx->aadlen = aadlen; + + /* process AAD */ + X = 0; + while (aadlen >= 16) { + A = GETU128_LE(aad); + X = gf128_add(X, A); + X = gf128_mul(X, H); + aad += 16; + aadlen -= 16; + } + if (aadlen) { + memcpy(ctx->buf, aad, aadlen); + A = GETU128_LE(ctx->block); + X = gf128_add(X, A); + X = gf128_mul(X, H); + } + + ctx->H = H; + ctx->X = X; + + /* this clean ok? */ + H = X = A = 0; +} + +void ghash_update(GHASH_CTX *ctx, const uint8_t *c, size_t clen) +{ + __uint128_t X; + __uint128_t H; + __uint128_t C; + + if (!c && clen) { + return 0; + } + + ctx->cipherlen += clen; + + X = ctx->X; + H = ctx->H; + + if (ctx->num) { + unsigned int left = 16 - ctx->num; + if (clen < left) { + memcpy(ctx->block + ctx->num, c, clen); + ctx->num += clen; + return 1; + } else { + memcpy(ctx->block + ctx->num, c, left); + C = GETU128_LE(ctx->block); + X = GF128_ADD(X, C); + X = GF128_MUL(X, H); + c += left; + clen -= left; + } + } + + while (clen >= 16) { + C = GETU128_LE(c); + X = gf128_add(X, C); + X = gf128_mul(X, H); + c += 16; + clen -= 16; + } + + ctx->num = clen; + if (clen) { + memcpy(ctx->block, c, clen); + } + + ctx->X = X; + X = H = C = 0; +} + +void ghash_finish(GHASH_CTX *ctx, uint8_t out[16]) +{ + __uint128_t X = ctx->X; + __uint128_t H = ctx->H; + __uint128_t C; + + if (ctx->num < 0) { + return 0; + } + + if (ctx->num) { + memset(ctx->block + ctx->num, 0, 16 - ctx->num); + C = GETU128_LE(ctx->block); + X = GF128_ADD(X, C); + X = GF128_MUL(X, H); + } + + PUTU64_LE(ctx->block, (uint64_t)ctx->aadlen << 3); + PUTU64_LE(ctx->block + sizeof(uint64_t), (uint64_t)ctx->cipherlen << 3); + C = GETU128_LE(ctx->block); + X = GF128_ADD(X, C); + X = GF128_MUL(X, H); + + PUTU128_LE(out, X); + + memset(ctx, 0, sizeof(GHASH_CTX)); + X = H = C = 0; +} + +/* + * GCM(K, IV, A, P) + * + * H = E_K(0^128) + * Y_0 = IV || 0^{31}1 if nbits(IV) == 96 + * = GHASH(H, {}, IV) otherwise + * Y_i = Y_{i-1} + 1 for i = 1, ..., n + * C_i = P_i xor E_K(Y_i) for i = 1, ..., n + * C_n^* = P_n^* xor MSB_u(E_K(Y_n)) + * T = MSB_t(GHASH(H, A, C) xor E_K(Y_0)) + */ +int gcm_init(GCM_CTX *ctx, const BLOCK_CIPEHR *cipher, + const uint8_t *key, size_t keylen, const uint8_t *iv, size_t ivlen, + const uint8_t *aad, size_t aadlen) +{ + memset(ctx, 0, sizeof(GCM_CTX)); + ctx->cipher = cipher; + + /* H = E_K(0^128) */ + if (!cipher->set_encrypt_key(ctx->key, key, keylen)) { + return 0; + } + cipher->encrypt(ctx->key, ctx->block, ctx->block); + + /* init counter as Y_0 */ + if (ivlen == GCM_DEFAULT_IV_SIZE) { + memcpy(ctx->counter, iv, ivlen); + PUTU32(ctx->counter + 12, 1); + } else { + ghash_init(&ctx->ghash_ctx, ctx->block, NULL, 0); + ghash_update(&ctx->ghash_ctx, iv, ivlen); + ghash_finish(&ctx->ghash_ctx, ctx->counter); + } + + ghash_init(&ctx->ghash-ctx, ctx->block, aad, aadlen); + return 1; +} + +// gcm 加密解密显然是不一样的 +int gcm_update(GCM_CTX *ctx, const uint8_t *in, size_t inlen, uint8_t *out) +{ + uint32_t r; + size_t i; + + uint8_t *c = out; + size_t clen = inlen; + + if (ctx->num) { + uint8_t *k = ctx->block + 16 - ctx->num; + size_t len = inlen < ctx->num ? inlen : ctx->num; + for (i = 0; i < len; i++) { + out[i] = in[i] ^ k[i]; + } + in += len; + out += len; + inlen -= len; + ctx->num -= len; + } + + /* gcm only use the last 32 bits as counter */ + r = GETU32(ctx->counter + 12); + + while (inlen >= 16) { + r++; + PUTU32(ctx->counter + 12, r); + ctx->cipher->encrypt(ctx->key, ctx->counter, out); + for (i = 0; i < 16; i++) { + out[i] ^= in[i]; + } + + in += 16; + out += 16; + inlen -= 16; + } + + if (inlen) { + r++; + PUTU32(ctx->counter + 12, r); + ctx->cipher->encrypt(ctx->key, ctx->counter, ctx->block); + for (i = 0; i < inlen; i++) { + out[i] = in[i] ^ ctx->block[i]; + } + ctx->num = 16 - inlen; + } + + ghash_update(ctx->ghash_ctx, c, inlen); + return 1; +} + +int gcm_encrypt_update(GCM_CTX *ctx, const uint8_t *in, size_t inlen, uint8_t *out) +{ + ctr_update(ctx->ctr_ctx, in, inlen, out); + ghash_update(ctx->ghash_ctx, out, inlen); +} + +int gcm_encrypt_finish(GCM_CTX *ctx, size_t taglen, uint8_t *tag) +{ + int i; + ghash_finish(ctx->ghash_ctx, ctx->block); + + for (i = 0; i < ctx->taglen; i++) { + tag[i] = ctx->block[i] ^ ctx->enced_iv[i]; + } + + memset(ctx, 0, sizeof(GCM_CTX)); +} + +int gcm_decrypt_finish(GCM_CTX *ctx, const uint8_t *tag, size_t taglen) +{ + uint8_t buf[16]; + if (taglen != ctx->taglen) { + return 0; + } + gcm_finish(ctx, buf); + if (memcmp(buf, tag, taglen) != 0) { + return 0; + } + return 1; +} diff --git a/src/debug.c b/src/debug.c new file mode 100644 index 00000000..ebafd7ac --- /dev/null +++ b/src/debug.c @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2014 - 2020 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + +#include +#include +#include +#include +#include + +void print_der(const uint8_t *in, size_t inlen) +{ + size_t i; + for (i = 0; i < inlen; i++) { + printf("%02x ", in[i]); + } +} + +void print_bytes(const uint8_t *data, size_t datalen) +{ + size_t i; + for (i = 0; i < datalen; i++) { + printf("%02X ", data[i]); + if ((i + 1) % 32 == 0) + printf("\n"); + } + printf("\n"); +} + +void print_nodes(const uint32_t *in, size_t inlen) +{ + size_t i; + printf("%u", in[0]); + for (i = 1; i < inlen; i++) { + printf(".%u", in[i]); + } +} + + + +int format_print(FILE *fp, int format, int indent, const char *str, ...) +{ + va_list args; + int i; + for (i = 0; i < indent; i++) { + fprintf(fp, " "); + } + va_start(args, str); + vfprintf(fp, str, args); + va_end(args); + return 1; +} + +int format_bytes(FILE *fp, int format, int indent, const char *str, const uint8_t *data, size_t datalen) +{ + int i; + for (i = 0; i < indent; i++) { + fprintf(fp, " "); + } + fprintf(fp, "%s", str); + if (!datalen) { + fprintf(fp, "(null)\n"); + return 1; + } + for (i = 0; i < datalen; i++) { + fprintf(fp, "%02X", data[i]); + } + fprintf(fp, "\n"); + return 1; +} + + +int tls_trace(int format, int indent, const char *str, ...) +{ + FILE *fp = stderr; + va_list args; + int i; + for (i = 0; i < indent; i++) { + fprintf(fp, " "); + } + va_start(args, str); + vfprintf(fp, str, args); + va_end(args); + fprintf(fp, "\n"); + return 1; +} + diff --git a/src/des.c b/src/des.c new file mode 100644 index 00000000..6bd6d70b --- /dev/null +++ b/src/des.c @@ -0,0 +1,267 @@ +/* + * Copyright (c) 2014 - 2020 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + +#include +#include +#include +#include +#include "bswap.h" + + +/* permuted choice 1 for key schedule, 64 bits to 56 bits */ +static unsigned char PC1[56] = { + 57, 49, 41, 33, 25, 17, 9, + 1, 58, 50, 42, 34, 26, 18, + 10, 2, 59, 51, 43, 35, 27, + 19, 11, 3, 60, 52, 44, 36, + 63, 55, 47, 39, 31, 23, 15, + 7, 62, 54, 46, 38, 30, 22, + 14, 6, 61, 53, 45, 37, 29, + 21, 13, 5, 28, 20, 12, 4, +}; + +/* permuted choice 2 for key schedule, 48 bits to 48 bits */ +static unsigned char PC2[48] = { + 14, 17, 11, 24, 1, 5, + 3, 28, 15, 6, 21, 10, + 23, 19, 12, 4, 26, 8, + 16, 7, 27, 20, 13, 2, + 41, 52, 31, 37, 47, 55, + 30, 40, 51, 45, 33, 48, + 44, 49, 39, 56, 34, 53, + 46, 42, 50, 36, 29, 32, +}; + +/* rotations for every round of key schedule */ +static unsigned char S[16] = { + 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1, +}; + +/* initial permutation, 64 bits to 64 bits */ +static unsigned char IP[64] = { + 58, 50, 42, 34, 26, 18, 10, 2, + 60, 52, 44, 36, 28, 20, 12, 4, + 62, 54, 46, 38, 30, 22, 14, 6, + 64, 56, 48, 40, 32, 24, 16, 8, + 57, 49, 41, 33, 25, 17, 9, 1, + 59, 51, 43, 35, 27, 19, 11, 3, + 61, 53, 45, 37, 29, 21, 13, 5, + 63, 55, 47, 39, 31, 23, 15, 7, +}; + +/* inverse initial permutation, 64 bits to 64 bits */ +static unsigned char IP_inv[64] = { + 40, 8, 48, 16, 56, 24, 64, 32, + 39, 7, 47, 15, 55, 23, 63, 31, + 38, 6, 46, 14, 54, 22, 62, 30, + 37, 5, 45, 13, 53, 21, 61, 29, + 36, 4, 44, 12, 52, 20, 60, 28, + 35, 3, 43, 11, 51, 19, 59, 27, + 34, 2, 42, 10, 50, 18, 58, 26, + 33, 1, 41, 9, 49, 17, 57, 25, +}; + +/* expansion permutation, 32 bits to 48 bits */ +static unsigned char E[48] = { + 32, 1, 2, 3, 4, 5, + 4, 5, 6, 7, 8, 9, + 8, 9, 10, 11, 12, 13, + 12, 13, 14, 15, 16, 17, + 16, 17, 18, 19, 20, 21, + 20, 21, 22, 23, 24, 25, + 24, 25, 26, 27, 28, 29, + 28, 29, 30, 31, 32, 1, +}; + +/* eight s-box, 6 bits to 4 bits */ +static unsigned char S1[64] = { + 14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7, + 0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8, + 4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0, + 15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13, +}; + +static unsigned char S2[64] = { + 15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10, + 3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5, + 0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15, + 13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9, +}; + +static unsigned char S3[64] = { + 10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8, + 13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1, + 13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7, + 1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12, +}; + +static unsigned char S4[64] = { + 7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15, + 13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9, + 10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4, + 3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14, +}; + +static unsigned char S5[64] = { + 2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9, + 14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6, + 4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14, + 11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3, +}; + +static unsigned char S6[64] = { + 12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11, + 10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8, + 9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6, + 4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13, +}; + +static unsigned char S7[64] = { + 4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1, + 13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6, + 1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2, + 6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12, +}; + +static unsigned char S8[64] = { + 13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7, + 1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2, + 7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8, + 2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11, +}; + +/* permutation, 32 bits to 32 bits */ +static unsigned char P[32] = { + 16, 7, 20, 21, 29, 12, 28, 17, 1, 15, 23, 26, 5, 18, 31, 10, + 2, 8, 24, 14, 32, 27, 3, 9, 19, 13, 30, 6, 22, 11, 4, 25, +}; + + +static uint64_t permute(const unsigned char *table, size_t n, uint64_t A) +{ + uint64_t R = 0; + for (size_t i = 0; i < n; i++) { + R |= (A >> (n - table[i])) & 0x01; + } + return R; +} + +static uint32_t substitution(const uint64_t A) +{ + return (((uint32_t)S1[(A >> 42) & 0x3f]) << 28) | + (((uint32_t)S2[(A >> 36) & 0x3f]) << 24) | + (((uint32_t)S3[(A >> 30) & 0x3f]) << 20) | + (((uint32_t)S4[(A >> 24) & 0x3f]) << 16) | + (((uint32_t)S5[(A >> 18) & 0x3f]) << 12) | + (((uint32_t)S6[(A >> 12) & 0x3f]) << 8) | + (((uint32_t)S7[(A >> 6) & 0x3f]) << 4) | + (((uint32_t)S8[(A ) & 0x3f]) ); +} + +#define ROL32(A,Si) (((A)<<(Si))|((A)>>(32-(Si)))) + +void des_set_encrypt_key(DES_KEY *key, const unsigned char user_key[8]) +{ + uint64_t K; + uint32_t L, R; + int i; + + K = GETU64(user_key); + K = permute(PC1, sizeof(PC1), K); + L = K >> 28; + R = K & 0x0fffffff; + + for (i = 0; i < 16; i++) { + L = ROL32(L, S[i]); + R = ROL32(R, S[i]); + K = ((uint64_t)L << 28) | R; + key->rk[i] = permute(PC2, sizeof(PC2), K); + } +} + +void des_set_decrypt_key(DES_KEY *key, const unsigned char user_key[8]) +{ + // TODO +} + +void des_encrypt(DES_KEY *key, const unsigned char in[DES_BLOCK_SIZE], + unsigned char out[DES_BLOCK_SIZE]) +{ + uint64_t T; + uint32_t L, R; + int i; + + T = GETU64(in); + + /* initial permutation */ + T = permute(IP, sizeof(IP), T); + + L = T >> 32; + R = T & 0xffffffff; + + for (i = 0; i < 16; i++) { + + /* compute F_{Ki}(R) */ + T = permute(E, sizeof(E), R); + T ^= key->rk[i]; + T = substitution(T); + T = permute(P, sizeof(P), T); + + T ^= L; + + L = R; + R = T; + } + + T = ((uint64_t)L << 32) | R; + + /* inverse initial permutation */ + T = permute(IP_inv, sizeof(IP_inv), T); + + PUTU64(out, T); +} diff --git a/src/digest.c b/src/digest.c new file mode 100644 index 00000000..4ac728af --- /dev/null +++ b/src/digest.c @@ -0,0 +1,527 @@ +/* + * Copyright (c) 2014 - 2020 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + + +#include +#include +#include +#include + + +int digest_nid(const DIGEST *digest) +{ + return digest->nid; +} + +typedef struct { + int nid; + char *short_name; + char *display_name; +} DIGEST_TABLE; + +DIGEST_TABLE digest_table[] = { + { OID_sm3, "sm3", "SM3" }, + { OID_md5, "md5", "MD5" }, + { OID_sha1, "sha1", "SHA-1" }, + { OID_sha224, "sha224", "SHA-224" }, + { OID_sha256, "sha256", "SHA-256" }, + { OID_sha384, "sha384", "SHA-384" }, + { OID_sha512, "sha512", "SHA-512" }, +}; + +const char *digest_name(const DIGEST *digest) +{ + int i; + for (i = 0; i < sizeof(digest_table)/sizeof(digest_table[0]); i++) { + if (digest->nid == digest_table[i].nid) { + return digest_table[i].short_name; + } + } + return NULL; +} + +size_t digest_size(const DIGEST *digest) +{ + return digest->digest_size; +} + +size_t digest_block_size(const DIGEST *digest) +{ + return digest->block_size; +} + +int digest_ctx_init(DIGEST_CTX *ctx) +{ + memset(ctx, 0, sizeof(DIGEST_CTX)); + return 1; +} + +void digest_ctx_cleanup(DIGEST_CTX *ctx) +{ + memset(ctx, 0, sizeof(DIGEST_CTX)); +} + +int digest_init(DIGEST_CTX *ctx, const DIGEST *algor) +{ + ctx->digest = algor; + ctx->digest->init(ctx); + return 1; +} + +int digest_update(DIGEST_CTX *ctx, const unsigned char *data, size_t datalen) +{ + ctx->digest->update(ctx, data, datalen); + return 1; +} + +int digest_finish(DIGEST_CTX *ctx, unsigned char *dgst, size_t *dgstlen) +{ + ctx->digest->finish(ctx, dgst); + *dgstlen = ctx->digest->digest_size; + return 1; +} + +int digest(const DIGEST *digest, const unsigned char *data, size_t datalen, + unsigned char *dgst, size_t *dgstlen) +{ + DIGEST_CTX ctx; + if (!digest_ctx_init(&ctx) + || !digest_init(&ctx, digest) + || !digest_update(&ctx, data, datalen) + || !digest_finish(&ctx, dgst, dgstlen)) { + return 0; + } + digest_ctx_cleanup(&ctx); + return 1; +} + +const DIGEST *digest_from_name(const char *name) +{ + if (!strcmp(name, "sm3") || !strcmp(name, "SM3")) { + return DIGEST_sm3(); + } else if (!strcmp(name, "md5") || !strcmp(name, "MD5")) { + return DIGEST_md5(); + } else if (!strcmp(name, "sha1") || !strcmp(name, "SHA1")) { + return DIGEST_sha1(); + } else if (!strcmp(name, "sha224") || !strcmp(name, "SHA224")) { + return DIGEST_sha224(); + } else if (!strcmp(name, "sha256") || !strcmp(name, "SHA256")) { + return DIGEST_sha256(); + } else if (!strcmp(name, "sha384") || !strcmp(name, "SHA384")) { + return DIGEST_sha384(); + } else if (!strcmp(name, "sha512") || !strcmp(name, "SHA512")) { + return DIGEST_sha512(); + } else if (!strcmp(name, "sha512-224") || !strcmp(name, "SHA512-224")) { + return DIGEST_sha512_224(); + } else if (!strcmp(name, "sha512-256") || !strcmp(name, "SHA512-256")) { + return DIGEST_sha512_256(); + } + return NULL; +} + +static int sm3_digest_init(DIGEST_CTX *ctx) +{ + if (!ctx) { + return 0; + } + sm3_init(&ctx->u.sm3_ctx); + return 1; +} + +static int sm3_digest_update(DIGEST_CTX *ctx, const unsigned char *in, size_t inlen) +{ + if (!ctx || (!in && inlen != 0)) { + return 0; + } + sm3_update(&ctx->u.sm3_ctx, in, inlen); + return 1; +} + +static int sm3_digest_finish(DIGEST_CTX *ctx, unsigned char *dgst) +{ + if (!ctx || !dgst) { + return 0; + } + sm3_finish(&ctx->u.sm3_ctx, dgst); + return 1; +} + +static const DIGEST sm3_digest_object = { + OID_sm3, + SM3_DIGEST_SIZE, + SM3_BLOCK_SIZE, + sizeof(SM3_CTX), + sm3_digest_init, + sm3_digest_update, + sm3_digest_finish, +}; + +const DIGEST *DIGEST_sm3(void) +{ + return &sm3_digest_object; +} + + +#include + +static int md5_digest_init(DIGEST_CTX *ctx) +{ + if (!ctx) { + return 0; + } + md5_init(&ctx->u.md5_ctx); + return 1; +} + +static int md5_digest_update(DIGEST_CTX *ctx, const unsigned char *in, size_t inlen) +{ + if (!ctx || (!in && inlen != 0)) { + return 0; + } + md5_update(&ctx->u.md5_ctx, in, inlen); + return 1; +} + +static int md5_digest_finish(DIGEST_CTX *ctx, unsigned char *dgst) +{ + if (!ctx || !dgst) { + return 0; + } + md5_finish(&ctx->u.md5_ctx, dgst); + return 1; +} + +static const DIGEST md5_digest_object = { + OID_md5, + MD5_DIGEST_SIZE, + MD5_BLOCK_SIZE, + sizeof(MD5_CTX), + md5_digest_init, + md5_digest_update, + md5_digest_finish, +}; + +const DIGEST *DIGEST_md5(void) +{ + return &md5_digest_object; +} + + +#include + +static int sha1_digest_init(DIGEST_CTX *ctx) +{ + if (!ctx) { + return 0; + } + sha1_init(&ctx->u.sha1_ctx); + return 1; +} + +static int sha1_digest_update(DIGEST_CTX *ctx, const unsigned char *in, size_t inlen) +{ + if (!ctx || (!in && inlen != 0)) { + return 0; + } + sha1_update(&ctx->u.sha1_ctx, in, inlen); + return 1; +} + +static int sha1_digest_finish(DIGEST_CTX *ctx, unsigned char *dgst) +{ + if (!ctx || !dgst) { + return 0; + } + sha1_finish(&ctx->u.sha1_ctx, dgst); + return 1; +} + +static const DIGEST sha1_digest_object = { + OID_sha1, + SHA1_DIGEST_LENGTH, + SHA1_BLOCK_SIZE, + sizeof(SHA1_CTX), + sha1_digest_init, + sha1_digest_update, + sha1_digest_finish, +}; + +const DIGEST *DIGEST_sha1(void) +{ + return &sha1_digest_object; +} + + +#include + +static int sha224_digest_init(DIGEST_CTX *ctx) +{ + if (!ctx) { + return 0; + } + sha224_init(&ctx->u.sha224_ctx); + return 1; +} + +static int sha224_digest_update(DIGEST_CTX *ctx, const unsigned char *in, size_t inlen) +{ + if (!ctx || (!in && inlen != 0)) { + return 0; + } + sha224_update(&ctx->u.sha224_ctx, in, inlen); + return 1; +} + +static int sha224_digest_finish(DIGEST_CTX *ctx, unsigned char *dgst) +{ + if (!ctx || !dgst) { + return 0; + } + sha224_finish(&ctx->u.sha224_ctx, dgst); + return 1; +} + +static const DIGEST sha224_digest_object = { + OID_sha224, + SHA224_DIGEST_SIZE, + SHA224_BLOCK_SIZE, + sizeof(SHA224_CTX), + sha224_digest_init, + sha224_digest_update, + sha224_digest_finish, +}; + +const DIGEST *DIGEST_sha224(void) +{ + return &sha224_digest_object; +} + +static int sha256_digest_init(DIGEST_CTX *ctx) +{ + if (!ctx) { + return 0; + } + sha256_init(&ctx->u.sha256_ctx); + return 1; +} + +static int sha256_digest_update(DIGEST_CTX *ctx, const unsigned char *in, size_t inlen) +{ + if (!ctx || (!in && inlen != 0)) { + return 0; + } + sha256_update(&ctx->u.sha256_ctx, in, inlen); + return 1; +} + +static int sha256_digest_finish(DIGEST_CTX *ctx, unsigned char *dgst) +{ + if (!ctx || !dgst) { + return 0; + } + sha256_finish(&ctx->u.sha256_ctx, dgst); + return 1; +} + +static const DIGEST sha256_digest_object = { + OID_sha256, + SHA256_DIGEST_SIZE, + SHA256_BLOCK_SIZE, + sizeof(SHA256_CTX), + sha256_digest_init, + sha256_digest_update, + sha256_digest_finish, +}; + +const DIGEST *DIGEST_sha256(void) +{ + return &sha256_digest_object; +} + + +static int sha384_digest_init(DIGEST_CTX *ctx) +{ + if (!ctx) { + return 0; + } + sha384_init(&ctx->u.sha384_ctx); + return 1; +} + +static int sha384_digest_update(DIGEST_CTX *ctx, const unsigned char *in, size_t inlen) +{ + if (!ctx || (!in && inlen != 0)) { + return 0; + } + sha384_update(&ctx->u.sha384_ctx, in, inlen); + return 1; +} + +static int sha384_digest_finish(DIGEST_CTX *ctx, unsigned char *dgst) +{ + if (!ctx || !dgst) { + return 0; + } + sha384_finish(&ctx->u.sha384_ctx, dgst); + return 1; +} + +static const DIGEST sha384_digest_object = { + OID_sha384, + SHA384_DIGEST_SIZE, + SHA384_BLOCK_SIZE, + sizeof(SHA384_CTX), + sha384_digest_init, + sha384_digest_update, + sha384_digest_finish, +}; + +const DIGEST *DIGEST_sha384(void) +{ + return &sha384_digest_object; +} + + +static int sha512_digest_init(DIGEST_CTX *ctx) +{ + if (!ctx) { + return 0; + } + sha512_init(&ctx->u.sha512_ctx); + return 1; +} + +static int sha512_digest_update(DIGEST_CTX *ctx, const unsigned char *in, size_t inlen) +{ + if (!ctx || (!in && inlen != 0)) { + return 0; + } + sha512_update(&ctx->u.sha512_ctx, in, inlen); + return 1; +} + +static int sha512_digest_finish(DIGEST_CTX *ctx, unsigned char *dgst) +{ + if (!ctx || !dgst) { + return 0; + } + sha512_finish(&ctx->u.sha512_ctx, dgst); + return 1; +} + +static const DIGEST sha512_digest_object = { + OID_sha512, + SHA512_DIGEST_SIZE, + SHA512_BLOCK_SIZE, + sizeof(SHA512_CTX), + sha512_digest_init, + sha512_digest_update, + sha512_digest_finish, +}; + +const DIGEST *DIGEST_sha512(void) +{ + return &sha512_digest_object; +} + + +static int sha512_224_digest_finish(DIGEST_CTX *ctx, unsigned char *dgst) +{ + unsigned char buf[SHA512_DIGEST_SIZE]; + if (!ctx || !dgst) { + return 0; + } + sha512_finish(&ctx->u.sha512_ctx, buf); + memcpy(dgst, buf, SHA224_DIGEST_SIZE); + memset(buf, 0, sizeof(buf)); + return 1; +} + +static const DIGEST sha512_224_digest_object = { + OID_sha512_224, + SHA224_DIGEST_SIZE, + SHA512_BLOCK_SIZE, + sizeof(SHA512_CTX), + sha512_digest_init, + sha512_digest_update, + sha512_224_digest_finish, +}; + +const DIGEST *DIGEST_sha512_224(void) +{ + return &sha512_224_digest_object; +} + + +static int sha512_256_digest_finish(DIGEST_CTX *ctx, unsigned char *dgst) +{ + unsigned char buf[SHA512_DIGEST_SIZE]; + if (!ctx || !dgst) { + return 0; + } + sha512_finish(&ctx->u.sha512_ctx, buf); + memcpy(dgst, buf, SHA256_DIGEST_SIZE); + memset(buf, 0, sizeof(buf)); + return 1; +} + + +static const DIGEST sha512_256_digest_object = { + OID_sha512_256, + SHA256_DIGEST_SIZE, + SHA512_BLOCK_SIZE, + sizeof(SHA512_CTX), + sha512_digest_init, + sha512_digest_update, + sha512_256_digest_finish, +}; + +const DIGEST *DIGEST_sha512_256(void) +{ + return &sha512_256_digest_object; +} diff --git a/src/endian.h b/src/endian.h new file mode 100644 index 00000000..1fb67c2d --- /dev/null +++ b/src/endian.h @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2014 - 2020 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + +#ifndef GMSSL_ENDIAN_H +#define GMSSL_ENDIAN_H + + +/* Big Endian R/W */ + +#define GETU16(p) \ + ((uint16_t)(p)[0] << 8 | \ + (uint16_t)(p)[1]) + +#define GETU32(p) \ + ((uint32_t)(p)[0] << 24 | \ + (uint32_t)(p)[1] << 16 | \ + (uint32_t)(p)[2] << 8 | \ + (uint32_t)(p)[3]) + +#define GETU64(p) \ + ((uint64_t)(p)[0] << 56 | \ + (uint64_t)(p)[1] << 48 | \ + (uint64_t)(p)[2] << 40 | \ + (uint64_t)(p)[3] << 32 | \ + (uint64_t)(p)[4] << 24 | \ + (uint64_t)(p)[5] << 16 | \ + (uint64_t)(p)[6] << 8 | \ + (uint64_t)(p)[7]) + + +// 注意:PUTU32(buf, val++) 会出错! +#define PUTU16(p,V) \ + ((p)[0] = (uint8_t)((V) >> 8), \ + (p)[1] = (uint8_t)(V)) + +#define PUTU32(p,V) \ + ((p)[0] = (uint8_t)((V) >> 24), \ + (p)[1] = (uint8_t)((V) >> 16), \ + (p)[2] = (uint8_t)((V) >> 8), \ + (p)[3] = (uint8_t)(V)) + +#define PUTU64(p,V) \ + ((p)[0] = (uint64_t)((V) >> 56), \ + (p)[1] = (uint64_t)((V) >> 48), \ + (p)[2] = (uint64_t)((V) >> 40), \ + (p)[3] = (uint64_t)((V) >> 32), \ + (p)[4] = (uint64_t)((V) >> 24), \ + (p)[5] = (uint64_t)((V) >> 16), \ + (p)[6] = (uint64_t)((V) >> 8), \ + (p)[7] = (uint64_t)(V)) + +/* Little Endian R/W */ + +#define GETU16_LE(p) (*(const uint16_t *)(p)) +#define GETU32_LE(p) (*(const uint32_t *)(p)) +#define GETU64_LE(p) (*(const uint64_t *)(p)) + +#define PUTU16_LE(p,V) *(uint16_t *)(p) = (V) +#define PUTU32_LE(p,V) *(uint32_t *)(p) = (V) +#define PUTU64_LE(p,V) *(uint64_t *)(p) = (V) + +/* Rotate */ + +#define ROL32(a,n) (((a)<<(n))|(((a)&0xffffffff)>>(32-(n)))) +#define ROL64(a,n) (((a)<<(n))|((a)>>(64-(n)))) + +#define ROR32(a,n) ROL32((a),32-(n)) +#define ROR64(a,n) ROL64(a,64-n) + + +#endif diff --git a/src/ffx.c b/src/ffx.c new file mode 100644 index 00000000..88fade8a --- /dev/null +++ b/src/ffx.c @@ -0,0 +1,351 @@ +/* ==================================================================== + * Copyright (c) 2014 - 2017 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + * ==================================================================== + */ + +#include +#include +#include +#include +#include +#include +#include +#include "../modes/modes_lcl.h" + + +static uint32_t modulo[] = { + 1, + 10, + 100, + 1000, + 10000, + 100000, + 1000000, + 10000000, + 100000000, + 1000000000, + 1000000000, +}; + +struct FFX_CTX_st { + EVP_CIPHER_CTX *cctx; + int flag; +}; + +FFX_CTX *FFX_CTX_new(void) +{ + FFX_CTX *ret = NULL; + ret = OPENSSL_zalloc(sizeof(*ret)); + return ret; +} + +void FFX_CTX_free(FFX_CTX *ctx) +{ + if (ctx) { + EVP_CIPHER_CTX_free(ctx->cctx); + } + OPENSSL_free(ctx); +} + +int FFX_init(FFX_CTX *ctx, const EVP_CIPHER *cipher, const unsigned char *key, + int flag) +{ + int ret = 0; + EVP_CIPHER_CTX *cctx = NULL; + + if (!ctx || !cipher || !key) { + FFXerr(FFX_F_FFX_INIT, ERR_R_PASSED_NULL_PARAMETER); + return 0; + } + if (EVP_CIPHER_mode(cipher) != EVP_CIPH_ECB_MODE) { + FFXerr(FFX_F_FFX_INIT, FFX_R_INVALID_CIPHER_MODE); + return 0; + } + if (EVP_CIPHER_block_size(cipher) != 16) { + FFXerr(FFX_F_FFX_INIT, FFX_R_INVALID_BLOCK_SIZE); + return 0; + } + + if (!ctx->cctx) { + if (!(cctx = EVP_CIPHER_CTX_new())) { + FFXerr(FFX_F_FFX_INIT, ERR_R_MALLOC_FAILURE); + goto end; + } + ctx->cctx = cctx; + cctx = NULL; + } + ctx->flag = flag; + + if (!EVP_EncryptInit_ex(ctx->cctx, cipher, NULL, key, NULL)) { + FFXerr(FFX_F_FFX_INIT, FFX_R_ENCRYPT_INIT_FAILURE); + goto end; + } + + ret = 1; +end: + EVP_CIPHER_CTX_free(cctx); + return ret; +} + +int FFX_encrypt(FFX_CTX *ctx, const char *in, char *out, size_t iolen, + unsigned char *tweak, size_t tweaklen) +{ + int llen, rlen; + uint32_t lval, rval; + unsigned char pblock[16] = { + 0x01, 0x02, 0x01, 0x0a, 0x00, 0x00, 0x0a, 0xff, + 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00}; + unsigned char qblock[16]; + char lbuf[FFX_MAX_DIGITS/2 + 2]; + uint64_t yval; + size_t i; + + if (!ctx || !in || !out || !tweak) { + FFXerr(FFX_F_FFX_ENCRYPT, ERR_R_PASSED_NULL_PARAMETER); + return 0; + } + + if (iolen < FFX_MIN_DIGITS || iolen > FFX_MAX_DIGITS) { + FFXerr(FFX_F_FFX_ENCRYPT, FFX_R_INVALID_INPUT_LENGTH); + return 0; + } + + for (i = 0; i < iolen; i++) { + if (!isdigit(in[i])) { + FFXerr(FFX_F_FFX_ENCRYPT, FFX_R_INVALID_INPUT_DIGIT); + return 0; + } + } + llen = iolen / 2; + rlen = iolen - llen; + + if (tweaklen < FFX_MIN_TWEAKLEN || tweaklen > FFX_MAX_TWEAKLEN) { + FFXerr(FFX_F_FFX_ENCRYPT, FFX_R_INVALID_TWEAK_LENGTH); + return 0; + } + + memcpy(lbuf, in, llen); + lbuf[llen] = 0; + lval = atoi(lbuf); + rval = atoi(in + llen); + + pblock[7] = llen & 0xff; + pblock[8] = iolen & 0xff; + pblock[12] = tweaklen & 0xff; + + if (!EVP_Cipher(ctx->cctx, pblock, pblock, + EVP_CIPHER_CTX_block_size(ctx->cctx))) { + FFXerr(FFX_F_FFX_ENCRYPT, ERR_R_EVP_LIB); + return 0; + } + + memset(qblock, 0, sizeof(qblock)); + memcpy(qblock, tweak, tweaklen); + + for (i = 0; i < FFX_NUM_ROUNDS; i += 2) { + + unsigned char rblock[16]; + size_t j; + + qblock[11] = i & 0xff; + memcpy(qblock + 12, &rval, sizeof(rval)); + for (j = 0; j < sizeof(rblock); j++) { + rblock[j] = pblock[j] ^ qblock[j]; + } + if (!EVP_Cipher(ctx->cctx, rblock, rblock, + EVP_CIPHER_CTX_block_size(ctx->cctx))) { + FFXerr(FFX_F_FFX_ENCRYPT, ERR_R_EVP_LIB); + return 0; + } + + yval = *((uint64_t *)rblock) % modulo[llen]; + lval = (lval + yval) % modulo[llen]; + + qblock[11] = (i + 1) & 0xff; + memcpy(qblock + 12, &lval, sizeof(lval)); + for (j = 0; j < sizeof(rblock); j++) { + rblock[j] = pblock[j] ^ qblock[j]; + } + if (!EVP_Cipher(ctx->cctx, rblock, rblock, + EVP_CIPHER_CTX_block_size(ctx->cctx))) { + FFXerr(FFX_F_FFX_ENCRYPT, ERR_R_EVP_LIB); + return 0; + } + yval = *((uint64_t *)rblock) % modulo[rlen]; + rval = (rval + yval) % modulo[rlen]; + } + + memset(out, '0', iolen); + sprintf(lbuf, "%d", rval); + memcpy(out + rlen - strlen(lbuf), lbuf, strlen(lbuf)); + sprintf(lbuf, "%d", lval); + strcpy(out + iolen - strlen(lbuf), lbuf); + + return 1; +} + +int FFX_decrypt(FFX_CTX *ctx, const char *in, char *out, size_t iolen, + unsigned char *tweak, size_t tweaklen) +{ + int llen, rlen; + uint32_t lval, rval; + unsigned char pblock[16] = { + 0x01, 0x02, 0x01, 0x0a, 0x00, 0x00, 0x0a, 0xff, + 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00}; + unsigned char qblock[16]; + char lbuf[FFX_MAX_DIGITS/2 + 2]; + uint64_t yval; + size_t i; + + if (!ctx || !in || !out || !tweak) { + FFXerr(FFX_F_FFX_DECRYPT, ERR_R_PASSED_NULL_PARAMETER); + return 0; + } + + if (iolen < FFX_MIN_DIGITS || iolen > FFX_MAX_DIGITS) { + FFXerr(FFX_F_FFX_DECRYPT, FFX_R_INVALID_INPUT_LENGTH); + return 0; + } + + for (i = 0; i < iolen; i++) { + if (!isdigit(in[i])) { + FFXerr(FFX_F_FFX_DECRYPT, FFX_R_INVALID_INPUT_DIGIT); + return 0; + } + } + rlen = iolen / 2; + llen = iolen - rlen; + + + if (tweaklen < FFX_MIN_TWEAKLEN || tweaklen > FFX_MAX_TWEAKLEN) { + FFXerr(FFX_F_FFX_DECRYPT, FFX_R_INVALID_TWEAK_LENGTH); + return 0; + } + + memcpy(lbuf, in, llen); + lbuf[llen] = 0; + lval = atoi(lbuf); + rval = atoi(in + llen); + + pblock[7] = rlen & 0xff; + pblock[8] = iolen & 0xff; + pblock[12] = tweaklen & 0xff; + + if (!EVP_Cipher(ctx->cctx, pblock, pblock, + EVP_CIPHER_CTX_block_size(ctx->cctx))) { + FFXerr(FFX_F_FFX_DECRYPT, ERR_R_EVP_LIB); + return 0; + } + + memset(qblock, 0, sizeof(qblock)); + memcpy(qblock, tweak, tweaklen); + + for (i = FFX_NUM_ROUNDS - 1; i > 0; i -= 2) { + + unsigned char rblock[16]; + size_t j; + + qblock[11] = i & 0xff; + memcpy(qblock + 12, &rval, sizeof(rval)); + for (j = 0; j < sizeof(rblock); j++) { + rblock[j] = pblock[j] ^ qblock[j]; + } + if (!EVP_Cipher(ctx->cctx, rblock, rblock, + EVP_CIPHER_CTX_block_size(ctx->cctx))) { + FFXerr(FFX_F_FFX_DECRYPT, ERR_R_EVP_LIB); + return 0; + } + + yval = *((uint64_t *)rblock) % modulo[llen]; + lval = (lval >= yval) ? (lval - yval) : lval + modulo[llen] - yval; + + qblock[11] = (i - 1) & 0xff; + memcpy(qblock + 12, &lval, sizeof(lval)); + for (j = 0; j < sizeof(rblock); j++) { + rblock[j] = pblock[j] ^ qblock[j]; + } + if (!EVP_Cipher(ctx->cctx, rblock, rblock, + EVP_CIPHER_CTX_block_size(ctx->cctx))) { + FFXerr(FFX_F_FFX_DECRYPT, ERR_R_EVP_LIB); + return 0; + } + + yval = *((uint64_t *)rblock) % modulo[rlen]; + rval = (rval >= yval) ? (rval - yval) : rval + modulo[rlen] - yval; + } + + memset(out, '0', iolen); + sprintf(lbuf, "%d", rval); + memcpy(out + rlen - strlen(lbuf), lbuf, strlen(lbuf)); + sprintf(lbuf, "%d", lval); + strcpy(out + iolen - strlen(lbuf), lbuf); + + return 1; +} + +static int luhn_table[10] = {0, 2, 4, 6, 8, 1, 3, 5, 7, 9}; + +int FFX_compute_luhn(const char *in, size_t inlen) +{ + int r = 0; + int i; + + for (i = inlen - 1; i >= 0; i--) { + int a; + if (!isdigit(in[i])) { + return -2; + } + a = in[i] - '0'; + if (i % 2 != inlen % 2) + a = luhn_table[a]; + r += a; + } + + r = ((r * 9) % 10) + '0'; + return r; +} + diff --git a/src/gcm.c b/src/gcm.c new file mode 100644 index 00000000..0e9c541a --- /dev/null +++ b/src/gcm.c @@ -0,0 +1,250 @@ +/* + * Copyright (c) 2014 - 2020 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + +#include +#include +#include + + +/* + * GHASH(H, A, C) = X_{m + n + 1} + * A additional authenticated data, A = A_1, ..., A_{m-1}, A_m^*, nbits(A_m^*) = v + * C ciphertext, C = C_1, ..., C_{n-1}, C_n^*, nbits(C_n^*) = u + * H = E_K(0^128) + * + * X_i = 0 for i = 0 + * = (X_{i-1} xor A_i ) * H for i = 1, ..., m-1 + * = (X_{m-1} xor (A_m^* || 0^{128-v})) * H for i = m + * = (X_{i-1} xor C_i ) * H for i = m+1, ..., m + n − 1 + * = (X_{m+n-1} xor (C_m^* || 0^{128-u})) * H for i = m + n + * = (X_{m+n} xor (nbits(A)||nbits(A))) * H for i = m + n + 1 + */ +void ghash_init(GHASH_CTX *ctx, const uint8_t h[16], const uint8_t *aad, size_t aadlen) +{ + __uint128_t H; + __uint128_t X; + __uint128_t A; + + memset(ctx, 0, sizeof(GHASH_CTX)); + + /* get H in GF(2^128) as little endian */ + ctx->H = H = GETU128_LE(h); + ctx->aadlen = aadlen; + + /* process AAD */ + X = 0; + while (aadlen >= 16) { + A = GETU128_LE(aad); + X = gf128_add(X, A); + X = gf128_mul(X, H); + aad += 16; + aadlen -= 16; + } + if (aadlen) { + memcpy(ctx->buf, aad, aadlen); + A = GETU128_LE(ctx->block); + X = gf128_add(X, A); + X = gf128_mul(X, H); + } + + ctx->H = H; + ctx->X = X; + + /* this clean ok? */ + H = X = A = 0; +} + +void ghash_update(GHASH_CTX *ctx, const uint8_t *c, size_t clen) +{ + __uint128_t X; + __uint128_t H; + __uint128_t C; + + if (!c && clen) { + return 0; + } + + ctx->cipherlen += clen; + + X = ctx->X; + H = ctx->H; + + if (ctx->num) { + unsigned int left = 16 - ctx->num; + if (clen < left) { + memcpy(ctx->block + ctx->num, c, clen); + ctx->num += clen; + return 1; + } else { + memcpy(ctx->block + ctx->num, c, left); + C = GETU128_LE(ctx->block); + X = GF128_ADD(X, C); + X = GF128_MUL(X, H); + c += left; + clen -= left; + } + } + + while (clen >= 16) { + C = GETU128_LE(c); + X = gf128_add(X, C); + X = gf128_mul(X, H); + c += 16; + clen -= 16; + } + + ctx->num = clen; + if (clen) { + memcpy(ctx->block, c, clen); + } + + ctx->X = X; + X = H = C = 0; +} + +void ghash_finish(GHASH_CTX *ctx, uint8_t out[16]) +{ + __uint128_t X = ctx->X; + __uint128_t H = ctx->H; + __uint128_t C; + + if (ctx->num < 0) { + return 0; + } + + if (ctx->num) { + memset(ctx->block + ctx->num, 0, 16 - ctx->num); + C = GETU128_LE(ctx->block); + X = GF128_ADD(X, C); + X = GF128_MUL(X, H); + } + + PUTU64_LE(ctx->block, (uint64_t)ctx->aadlen << 3); + PUTU64_LE(ctx->block + sizeof(uint64_t), (uint64_t)ctx->cipherlen << 3); + C = GETU128_LE(ctx->block); + X = GF128_ADD(X, C); + X = GF128_MUL(X, H); + + PUTU128_LE(out, X); + + memset(ctx, 0, sizeof(GHASH_CTX)); + X = H = C = 0; +} + +/* + * GCM(K, IV, A, P) + * + * H = E_K(0^128) + * Y_0 = IV || 0^{31}1 if nbits(IV) == 96 + * = GHASH(H, {}, IV) otherwise + * Y_i = Y_{i-1} + 1 for i = 1, ..., n + * C_i = P_i xor E_K(Y_i) for i = 1, ..., n + * C_n^* = P_n^* xor MSB_u(E_K(Y_n)) + * T = MSB_t(GHASH(H, A, C) xor E_K(Y_0)) + */ +int gcm_init(GCM_CTX *ctx, const BLOCK_CIPEHR *cipher, + const uint8_t *key, size_t keylen, const uint8_t *iv, size_t ivlen, + const uint8_t *aad, size_t aadlen) +{ + memset(ctx, 0, sizeof(GCM_CTX)); + ctx->cipher = cipher; + + /* H = E_K(0^128) */ + if (!cipher->set_encrypt_key(ctx->key, key, keylen)) { + return 0; + } + cipher->encrypt(ctx->key, ctx->block, ctx->block); + + /* init counter as Y_0 */ + if (ivlen == GCM_DEFAULT_IV_SIZE) { + memcpy(ctx->counter, iv, ivlen); + PUTU32(ctx->counter + 12, 1); + } else { + ghash_init(&ctx->ghash_ctx, ctx->block, NULL, 0); + ghash_update(&ctx->ghash_ctx, iv, ivlen); + ghash_finish(&ctx->ghash_ctx, ctx->counter); + } + + ghash_init(&ctx->ghash-ctx, ctx->block, aad, aadlen); + return 1; +} + +int gcm_encrypt_update(GCM_CTX *ctx, const uint8_t *in, size_t iolen, uint8_t *out) +{ + ctr_update(&ctx->ctr_ctx, in, iolen, out); + ghash_update(&ctx->ghash_ctx, out, iolen); +} + +int gcm_decrypt_update(GCM_CTX *ctx, const uint8_t *in, size_t iolen, uint8_t *out) +{ + ghash_update(&ctx->ghash_ctx, in, iolen); + +} + +int gcm_encrypt_finish(GCM_CTX *ctx, size_t taglen, uint8_t *tag) +{ + int i; + ghash_finish(ctx->ghash_ctx, ctx->block); + for (i = 0; i < ctx->taglen; i++) { + tag[i] = ctx->block[i] ^ ctx->enced_iv[i]; + } + memset(ctx, 0, sizeof(GCM_CTX)); +} + +int gcm_decrypt_finish(GCM_CTX *ctx, const uint8_t *tag, size_t taglen) +{ + uint8_t buf[16]; + if (taglen != ctx->taglen) { + return 0; + } + gcm_finish(ctx, buf); + if (memcmp(buf, tag, taglen) != 0) { + return 0; + } + return 1; +} diff --git a/src/gf128.c b/src/gf128.c new file mode 100644 index 00000000..7f3bec31 --- /dev/null +++ b/src/gf128.c @@ -0,0 +1,188 @@ +/* + * Copyright (c) 2014 - 2020 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + +/* GF(2^128) defined by f(x) = x^128 + x^7 + x^2 + x + 1 + * A + B mod f(x) = a xor b + * A * 2 mod f(x) + */ + +#include "internal/endian.h" +#include "internal/gf128.h" + + +#ifdef GMSSL_HAVE_UINT128 +gf128_t gf128_mul(gf128_t a, gf128_t b) +{ + gf128_t r = 0; + gf128_t mask = (gf128_t)1 << 127; + int i; + + for (i = 0; i < 128; i++) { + // r = r * 2 over gf(2^128) + if (r & mask) + r = (r << 1) ^ 0x87; + else r <<= 1; + + // if b[i] == 1, r = r + a + if (b & mask) + r ^= a; + + b <<= 1; + } + + return r; +} + +gf128_t gf128_add(gf128_t a, gf128_t b) +{ + return a ^ b; +} + +gf128_t gf128_mul2(gf128_t a) +{ + if (a & ((gf128_t)1 << 127)) + return (a << 1) ^ 0x87; + else return (a << 1); +} + +gf128_t gf128_from_bytes(const uint8_t p[16]) +{ + uint64_t hi = GETU64(p); + uint64_t lo = GETU64(p + 8); + return (gf128_t)hi << 64 | lo; +} + +void gf128_to_bytes(gf128_t a, uint8_t p[16]) +{ + uint64_t hi = a >> 64; + uint64_t lo = a; + PUTU64(p, hi); + PUTU64(p + 8, lo); +} + +#else +gf128_t gf128_from_bytes(const uint8_t p[16]) +{ + gf128_t r; + r.hi = GETU64(p); + r.lo = GETU64(p + 8); + return r; +} + +void gf128_to_bytes(gf128_t a, uint8_t p[16]) +{ + PUTU64(p, a.hi); + PUTU64(p + 8, a.lo); +} + +gf128_t gf128_add(gf128_t a, gf128_t b) +{ + gf128_t r; + r.hi = a.hi ^ b.hi; + r.lo = a.lo ^ b.lo; + return r; +} + +gf128_t gf128_mul(gf128_t a, gf128_t b) +{ + gf128_t r = {0, 0}; + uint64_t mask = (uint64_t)1 << 63; + int i; + + for (i = 0; i < 64; i++) { + if (r.hi & mask) { + r.hi = r.hi << 1 | r.lo >> 63; + r.lo = (r.lo << 1) ^ 0x87; + } else { + r.hi = a.hi << 1 | a.lo >> 63; + r.lo = a.lo << 1; + } + + if (b.hi & mask) { + r.hi ^= a.hi; + r.lo ^= a.lo; + } + + b.hi <<= 1; + } + for (i = 0; i < 64; i++) { + if (r.hi & mask) { + r.hi = r.hi << 1 | r.lo >> 63; + r.lo = (r.lo << 1) ^ 0x87; + } else { + r.hi = a.hi << 1 | a.lo >> 63; + r.lo = a.lo << 1; + } + + if (b.lo & mask) { + r.hi ^= a.hi; + r.lo ^= a.lo; + } + + b.lo <<= 1; + } + + return r; +} + +gf128_t gf128_mul2(gf128_t a) +{ + gf128_t r; + + if (a.hi & ((uint64_t)1 << 63)) { + r.hi = a.hi << 1 | a.lo >> 63; + r.lo = a.lo << 1; + r.lo ^= 0x87; + } else { + r.hi = a.hi << 1 | a.lo >> 63; + r.lo = a.lo << 1; + } + + return r; +} +#endif diff --git a/src/gf128.h b/src/gf128.h new file mode 100644 index 00000000..87d4b371 --- /dev/null +++ b/src/gf128.h @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2014 - 2020 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + +/* GF(2^128) defined by f(x) = x^128 + x^7 + x^2 + x + 1 + * A + B mod f(x) = a xor b + * A * 2 mod f(x) + */ + +#ifndef GMSSL_GF128_H +#define GMSSL_GF128_H + +#ifdef GMSSL_HAVE_UINT128 +typedef unsigned __int128 gf128_t; +#else +#include + +typedef struct { + uint64_t hi; + uint64_t lo; +} gf128_t; +#endif + +gf128_t gf128_add(gf128_t a, gf128_t b); +gf128_t gf128_mul(gf128_t a, gf128_t b); +gf128_t gf128_mul2(gf128_t a); +gf128_t gf128_from_bytes(const uint8_t p[16]); +void gf128_to_bytes(gf128_t a, uint8_t p[16]); + + +#endif diff --git a/src/hash_drbg.c b/src/hash_drbg.c new file mode 100644 index 00000000..21eac7d7 --- /dev/null +++ b/src/hash_drbg.c @@ -0,0 +1,346 @@ +/* + * Copyright (c) 2014 - 2020 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + + +#include +#include +#include +#include +#include "bswap.h" + +static int hash_df(const DIGEST *digest, const uint8_t *in, size_t inlen, + size_t outlen, uint8_t *out) +{ + int ret = 0; + DIGEST_CTX ctx; + uint8_t counter; + uint8_t outbits[4]; + unsigned char dgst[64]; + size_t len; + + counter = 0x01; + PUTU32(outbits, (uint32_t)outlen << 3); + + digest_ctx_init(&ctx); + + while (outlen > 0) { + if (!digest_init(&ctx, digest) + || !digest_update(&ctx, &counter, sizeof(counter)) + || !digest_update(&ctx, outbits, sizeof(outbits)) + || !digest_update(&ctx, in, inlen) + || !digest_finish(&ctx, dgst, &len)) { + goto end; + } + + if (outlen < len) { + len = outlen; + } + memcpy(out, dgst, len); + out += len; + outlen -= len; + + counter++; + } + + ret = 1; +end: + digest_ctx_cleanup(&ctx); + memset(dgst, 0, sizeof(dgst)); + return ret; +} + +int hash_drbg_init(HASH_DRBG *drbg, const DIGEST *digest, + const uint8_t *entropy, size_t entropy_len, + const uint8_t *nonce, size_t nonce_len, + const uint8_t *personalstr, size_t personalstr_len) +{ + int ret = 0; + unsigned char *seed_material = NULL; + size_t seed_material_len; + uint8_t buf[1 + HASH_DRBG_MAX_SEED_SIZE]; + uint8_t *p; + + memset(drbg, 0, sizeof(HASH_DRBG)); + + /* set digest */ + drbg->digest = digest; + + /* set seedlen */ + if (digest_size(digest) <= 32) { + drbg->seedlen = HASH_DRBG_SM3_SEED_SIZE; + } else { + drbg->seedlen = HASH_DRBG_SHA512_SEED_SIZE; + } + + /* seed_material = entropy_input || nonce || personalization_string */ + seed_material_len = entropy_len + nonce_len + personalstr_len; + if (!(seed_material = malloc(seed_material_len))) { + return 0; + } + p = seed_material; + memcpy(p, entropy, entropy_len); + p += entropy_len; + memcpy(p, nonce, nonce_len); + p += nonce_len; + memcpy(p, personalstr, personalstr_len); + + /* V = Hash_df (seed_material, seedlen) */ + if (!hash_df(drbg->digest, seed_material, seed_material_len, drbg->seedlen, + drbg->V)) { + goto end; + } + + /* C = Hash_df ((0x00 || V), seedlen) */ + buf[0] = 0x00; + memcpy(buf + 1, drbg->V, drbg->seedlen); + if (!hash_df(drbg->digest, buf, 1 + drbg->seedlen, drbg->seedlen, + drbg->C)) { + goto end; + } + + /* reseed_counter = 1 */ + drbg->reseed_counter = 1; + + ret = 1; +end: + if (seed_material) { + memset(seed_material, 0, seed_material_len); + free(seed_material); + } + memset(buf, 0, sizeof(buf)); + return ret; +} + +int hash_drbg_reseed(HASH_DRBG *drbg, + const uint8_t *entropy, size_t entropy_len, + const uint8_t *additional, size_t additional_len) +{ + int ret = 0; + uint8_t *seed_material = NULL; + size_t seed_material_len; + uint8_t *p; + uint8_t buf[1 + HASH_DRBG_MAX_SEED_SIZE]; + + /* seed_material = 0x01 || V || entropy_input || additional_input */ + seed_material_len = 1 + drbg->seedlen + entropy_len + additional_len; + if (!(seed_material = malloc(seed_material_len))) { + return 0; + } + seed_material[0] = 0x01; + p = seed_material + 1; + memcpy(p, drbg->V, drbg->seedlen); + p += drbg->seedlen; + memcpy(p, entropy, entropy_len); + p += entropy_len; + memcpy(p, additional, additional_len); + + /* V = Hash_df(seed_material, seedlen) */ + if (!hash_df(drbg->digest, seed_material, seed_material_len, drbg->seedlen, + drbg->V)) { + goto end; + } + + /* C = Hash_df((0x00 || V), seedlen) */ + buf[0] = 0x00; + memcpy(buf + 1, drbg->V, drbg->seedlen); + if (!hash_df(drbg->digest, buf, 1 + drbg->seedlen, drbg->seedlen, + drbg->C)) { + goto end; + } + + /* reseed_counter = 1 */ + drbg->reseed_counter = 1; + + ret = 1; +end: + if (seed_material) { + memset(seed_material, 0, seed_material_len); + free(seed_material); + } + memset(buf, 0, sizeof(buf)); + return ret; +} + +/* seedlen is always >= dgstlen + * R0 ... Ru-v .. .. .. Ru-1 + * + A0 A1 A2 .. Av-1 + */ +static void drbg_add(uint8_t *R, const uint8_t *A, size_t seedlen) +{ + int temp = 0, i; + for (i = seedlen - 1; i >= 0; i--) { + temp += R[i] + A[i]; + R[i] = temp & 0xff; + temp >>= 8; + } +} + +static void drbg_add1(uint8_t *R, size_t seedlen) +{ + int temp = 1, i; + for (i = seedlen - 1; i >= 0; i--) { + temp += R[i]; + R[i] = temp & 0xff; + temp >>= 8; + } +} + +static int drbg_hashgen(HASH_DRBG *drbg, size_t outlen, uint8_t *out) +{ + int ret = 0; + DIGEST_CTX ctx; + uint8_t data[HASH_DRBG_MAX_SEED_SIZE]; + uint8_t dgst[DIGEST_MAX_SIZE]; + size_t len; + + digest_ctx_init(&ctx); + + /* data = V */ + memcpy(data, drbg->V, drbg->seedlen); + + while (outlen > 0) { + + /* output Hash(data) */ + if (!digest_init(&ctx, drbg->digest) + || !digest_update(&ctx, data, drbg->seedlen) + || !digest_finish(&ctx, dgst, &len)) { + goto end; + } + + if (outlen < len) { + len = outlen; + } + memcpy(out, dgst, len); + out += len; + outlen -= len; + + /* data = (data + 1) mod 2^seedlen */ + drbg_add1(data, drbg->seedlen); + } + + ret = 1; +end: + digest_ctx_cleanup(&ctx); + memset(data, 0, sizeof(data)); + return ret; +} + +int hash_drbg_generate(HASH_DRBG *drbg, + const uint8_t *additional, size_t additional_len, + size_t outlen, uint8_t *out) +{ + int ret = 0; + DIGEST_CTX ctx; + uint8_t prefix; + uint8_t T[HASH_DRBG_MAX_SEED_SIZE]; + uint8_t dgst[DIGEST_MAX_SIZE]; + size_t dgstlen; + + // FIXME: check outlen max value + + if (drbg->reseed_counter > HASH_DRBG_RESEED_INTERVAL) { + return 0; + } + + digest_ctx_init(&ctx); + + if (additional) { + /* w = Hash (0x02 || V || additional_input) */ + prefix = 0x02; + if (!digest_init(&ctx, drbg->digest) + || !digest_update(&ctx, &prefix, 1) + || !digest_update(&ctx, drbg->V, drbg->seedlen) + || !digest_update(&ctx, additional, additional_len) + || !digest_finish(&ctx, dgst, &dgstlen)) { + goto end; + } + + /* V = (V + w) mod 2^seedlen */ + memset(T, 0, drbg->seedlen - dgstlen); + memcpy(T + drbg->seedlen - dgstlen, dgst, dgstlen); + drbg_add(drbg->V, T, drbg->seedlen); + } + + /* (returned_bits) = Hashgen (requested_number_of_bits, V). */ + drbg_hashgen(drbg, outlen, out); + + /* H = Hash (0x03 || V). */ + prefix = 0x03; + if (!digest_init(&ctx, drbg->digest) + || !digest_update(&ctx, &prefix, 1) + || !digest_update(&ctx, drbg->V, drbg->seedlen) + || !digest_finish(&ctx, dgst, &dgstlen)) { + goto end; + } + + /* V = (V + H + C + reseed_counter) mod 2^seedlen */ + memset(T, 0, drbg->seedlen - dgstlen); + memcpy(T + drbg->seedlen - dgstlen, dgst, dgstlen); + drbg_add(drbg->V, T, drbg->seedlen); + + drbg_add(drbg->V, drbg->C, drbg->seedlen); + + memset(T, 0, drbg->seedlen - sizeof(uint64_t)); + PUTU64(T + drbg->seedlen - sizeof(uint64_t), drbg->reseed_counter); + drbg_add(drbg->V, T, drbg->seedlen); + + /* reseed_counter = reseed_counter + 1 */ + drbg->reseed_counter++; + + ret = 1; +end: + digest_ctx_cleanup(&ctx); + memset(T, 0, sizeof(T)); + memset(dgst, 0, sizeof(dgst)); + return ret; +} + +void hash_drbg_cleanup(HASH_DRBG *drbg) +{ + //mem_cleanup(drbg, sizeof(HASH_DRBG)); +} diff --git a/src/hex.c b/src/hex.c new file mode 100644 index 00000000..6fc3ee45 --- /dev/null +++ b/src/hex.c @@ -0,0 +1,188 @@ +/* + * Copyright (c) 2014 - 2021 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + + +#include +#include +#include +#include +#include + +int OPENSSL_hexchar2int(unsigned char c) +{ + switch (c) { + case '0': + return 0; + case '1': + return 1; + case '2': + return 2; + case '3': + return 3; + case '4': + return 4; + case '5': + return 5; + case '6': + return 6; + case '7': + return 7; + case '8': + return 8; + case '9': + return 9; + case 'a': + case 'A': + return 0x0A; + case 'b': case 'B': + return 0x0B; + case 'c': case 'C': + return 0x0C; + case 'd': case 'D': + return 0x0D; + case 'e': case 'E': + return 0x0E; + case 'f': case 'F': + return 0x0F; + } + return -1; +} + +unsigned char *OPENSSL_hexstr2buf(const char *str, size_t *len) +{ + unsigned char *hexbuf, *q; + unsigned char ch, cl; + int chi, cli; + const unsigned char *p; + size_t s; + + s = strlen(str); + if ((hexbuf = malloc(s >> 1)) == NULL) { + return NULL; + } + for (p = (const unsigned char *)str, q = hexbuf; *p; ) { + ch = *p++; + if (ch == ':') + continue; + cl = *p++; + if (!cl) { + //CRYPTOerr(CRYPTO_F_OPENSSL_HEXSTR2BUF, CRYPTO_R_ODD_NUMBER_OF_DIGITS); + free(hexbuf); + return NULL; + } + cli = OPENSSL_hexchar2int(cl); + chi = OPENSSL_hexchar2int(ch); + if (cli < 0 || chi < 0) { + free(hexbuf); + //CRYPTOerr(CRYPTO_F_OPENSSL_HEXSTR2BUF, CRYPTO_R_ILLEGAL_HEX_DIGIT); + return NULL; + } + *q++ = (unsigned char)((chi << 4) | cli); + } + + if (len) + *len = q - hexbuf; + return hexbuf; +} + + +static int hexchar2int(char c) +{ + if ('0' <= c && c <= '9') return c - '0'; + else if ('a' <= c && c <= 'f') return c - 'a' + 10; + else if ('A' <= c && c <= 'F') return c - 'A' + 10; + else return -1; +} + +int hex2bin(const char *in, size_t inlen, uint8_t *out) +{ + int c; + if (inlen % 2) { + error_print(); + return -1; + } + + while (inlen) { + if ((c = hexchar2int(*in++)) < 0) { + error_print(); + return -1; + } + *out = (uint8_t)c << 4; + if ((c = hexchar2int(*in++)) < 0) { + error_print(); + return -1; + } + *out |= (uint8_t)c; + inlen -= 2; + out++; + } + return 1; +} + +void memxor(void *r, const void *a, size_t len) +{ + uint8_t *pr = r; + const uint8_t *pa = a; + size_t i; + for (i = 0; i < len; i++) { + pr[i] ^= pa[i]; + } + +} + + +void gmssl_memxor(void *r, const void *a, const void *b, size_t len) +{ + uint8_t *pr = r; + const uint8_t *pa = a; + const uint8_t *pb = b; + size_t i; + for (i = 0; i < len; i++) { + pr[i] = pa[i] ^ pb[i]; + } +} diff --git a/src/hkdf.c b/src/hkdf.c new file mode 100644 index 00000000..83f4fd4c --- /dev/null +++ b/src/hkdf.c @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2021 - 2021 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + + +#include +#include +#include +#include +#include +#include + +/* + +HKDF-Extract(salt, IKM) -> PRK + + salt optional, len(salt) == hash_len is recommended + IKM input key material + PRK output pseudorandom key, len(PRK) = hashLen + + PRK = HMAC_hash(salt, IKM) + salt as key? + + +HKDF-Expand(PRK, info, L) -> OKM + info optional + L output length, L <= 255 * hashLen + OKM output key + + + N = (L + hashLen - 1)//hashLen + T = T(1) || T(2) || ... | T(N) + OKM = T[0..L-1] + + T(0) = empty string (len = 0) + T(1) = HMAC_hash(PRK, T(0) | info | 0x01) + T(2) = HMAC_hash(PRK, T(1) | info | 0x02) + T(3) = HMAC_hash(PRK, T(2) | info | 0x03) + ... + + +*/ + +int hkdf_extract(const DIGEST *digest, const uint8_t *salt, size_t saltlen, + const uint8_t *ikm, size_t ikmlen, + uint8_t *prk, size_t *prklen) +{ + HMAC_CTX hmac_ctx; + + if (!salt || saltlen == 0) { + uint8_t zeros[DIGEST_MAX_SIZE] = {0}; + if (hmac_init(&hmac_ctx, digest, zeros, digest_size(digest)) != 1) { + error_print(); + return -1; + } + } else { + if (hmac_init(&hmac_ctx, digest, salt, saltlen) != 1) { + error_print(); + return -1; + } + } + + if (hmac_update(&hmac_ctx, ikm, ikmlen) != 1 + || hmac_finish(&hmac_ctx, prk, prklen) != 1) { + error_print(); + return -1; + } + return 1; +} + +int hkdf_expand(const DIGEST *digest, const uint8_t *prk, size_t prklen, + const uint8_t *info, size_t infolen, + size_t L, uint8_t *okm) +{ + HMAC_CTX hmac_ctx; + uint8_t T[HMAC_MAX_SIZE]; + uint8_t counter = 0x01; + size_t len; + + if (L > 0) { + if (hmac_init(&hmac_ctx, digest, prk, prklen) != 1 + || hmac_update(&hmac_ctx, info, infolen) != 1 + || hmac_update(&hmac_ctx, &counter, 1) != 1 + || hmac_finish(&hmac_ctx, T, &len) != 1) { + error_print(); + return -1; + } + counter++; + if (len > L) { + len = L; + } + memcpy(okm, T, len); + okm += len; + L -= len; + } + while (L > 0) { + if (counter == 0) { + error_print(); + return -1; + } + if (hmac_init(&hmac_ctx, digest, prk, prklen) != 1 + || hmac_update(&hmac_ctx, T, len) != 1 + || hmac_update(&hmac_ctx, info, infolen) != 1 + || hmac_update(&hmac_ctx, &counter, 1) != 1 + || hmac_finish(&hmac_ctx, T, &len) != 1) { + error_print(); + return -1; + } + counter++; + if (len > L) { + len = L; + } + memcpy(okm, T, len); + okm += len; + L -= len; + } + return 1; +} diff --git a/src/hmac.c b/src/hmac.c new file mode 100644 index 00000000..754f8b08 --- /dev/null +++ b/src/hmac.c @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2014 - 2020 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + +#include +#include + + +#define IPAD 0x36 +#define OPAD 0x5C + + +int hmac_ctx_init(HMAC_CTX *ctx) +{ + memset(ctx, 0, sizeof(HMAC_CTX)); + return 1; +} + +void hmac_ctx_cleanup(HMAC_CTX *ctx) +{ + memset(ctx, 0, sizeof(HMAC_CTX)); +} + +int hmac_init(HMAC_CTX *ctx, const DIGEST *digest, const unsigned char *key, size_t keylen) +{ + uint8_t i_key[DIGEST_MAX_BLOCK_SIZE] = {0}; + uint8_t o_key[DIGEST_MAX_BLOCK_SIZE] = {0}; + size_t blocksize; + int i; + + if (!ctx || !digest || !key || !keylen) { + return 0; + } + + ctx->digest = digest; + + blocksize = digest_block_size(digest); + if (keylen <= blocksize) { + memcpy(i_key, key, keylen); + memcpy(o_key, key, keylen); + } else { + digest_init(&ctx->digest_ctx, digest); + digest_update(&ctx->digest_ctx, key, keylen); + digest_finish(&ctx->digest_ctx, i_key, &keylen); + memcpy(o_key, i_key, keylen); + } + for (i = 0; i < blocksize; i++) { + i_key[i] ^= IPAD; + o_key[i] ^= OPAD; + } + + digest_init(&ctx->i_ctx, digest); + digest_update(&ctx->i_ctx, i_key, blocksize); + digest_init(&ctx->o_ctx, digest); + digest_update(&ctx->o_ctx, o_key, blocksize); + memcpy(&ctx->digest_ctx, &ctx->i_ctx, sizeof(DIGEST_CTX)); + + memset(i_key, 0, sizeof(i_key)); + memset(o_key, 0, sizeof(o_key)); + return 1; +} + +int hmac_update(HMAC_CTX *ctx, const unsigned char *data, size_t datalen) +{ + if (!ctx || (!data && datalen != 0)) { + return 0; + } + return digest_update(&ctx->digest_ctx, data, datalen); +} + +int hmac_finish(HMAC_CTX *ctx, unsigned char *mac, size_t *maclen) +{ + int ret = 0; + size_t i; + size_t blocksize; + + if (!digest_finish(&ctx->digest_ctx, mac, maclen)) { + return -1; + } + memcpy(&ctx->digest_ctx, &ctx->o_ctx, sizeof(DIGEST_CTX)); + if (!digest_update(&ctx->digest_ctx, mac, *maclen) + || !digest_finish(&ctx->digest_ctx, mac, maclen)) { + goto end; + } + + ret = 1; +end: + return ret; +} + +int hmac_reset(HMAC_CTX *ctx) +{ + memcpy(&ctx->digest_ctx, &ctx->i_ctx, sizeof(DIGEST_CTX)); + return 1; +} + +int hmac(const DIGEST *digest, const unsigned char *key, size_t keylen, + const unsigned char *data, size_t datalen, + unsigned char *mac, size_t *maclen) +{ + int ret = 0; + HMAC_CTX ctx; + + if (!hmac_ctx_init(&ctx) + || !hmac_init(&ctx, digest, key, keylen) + || !hmac_update(&ctx, data, datalen) + || !hmac_finish(&ctx, mac, maclen)) { + goto end; + } + ret = 1; +end: + hmac_ctx_cleanup(&ctx); + return ret; +} diff --git a/src/md5.c b/src/md5.c new file mode 100755 index 00000000..73ab7c08 --- /dev/null +++ b/src/md5.c @@ -0,0 +1,276 @@ +/* + * Copyright (c) 2014 - 2020 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + +/* ==================================================================== + * Copyright (c) 2014 - 2017 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + * ==================================================================== + */ + +#include +#include +#include "bswap.h" + + +static void md5_compress_blocks(uint32_t state[4], + const unsigned char *data, size_t blocks); + + +void md5_init(MD5_CTX *ctx) +{ + memset(ctx, 0, sizeof(*ctx)); + ctx->state[0] = 0x67452301; + ctx->state[1] = 0xefcdab89; + ctx->state[2] = 0x98badcfe; + ctx->state[3] = 0x10325476; +} + +void md5_update(MD5_CTX *ctx, const unsigned char *data, size_t datalen) +{ + size_t blocks; + + if (ctx->num) { + unsigned int left = MD5_BLOCK_SIZE - ctx->num; + if (datalen < left) { + memcpy(ctx->block + ctx->num, data, datalen); + ctx->num += datalen; + return; + } else { + memcpy(ctx->block + ctx->num, data, left); + md5_compress_blocks(ctx->state, ctx->block, 1); + ctx->nblocks++; + data += left; + datalen -= left; + } + } + + blocks = datalen / MD5_BLOCK_SIZE; + md5_compress_blocks(ctx->state, data, blocks); + ctx->nblocks += blocks; + data += MD5_BLOCK_SIZE * blocks; + datalen -= MD5_BLOCK_SIZE * blocks; + + ctx->num = datalen; + if (datalen) { + memcpy(ctx->block, data, datalen); + } +} + +void md5_finish(MD5_CTX *ctx, unsigned char *dgst) +{ + int i; + + ctx->block[ctx->num] = 0x80; + + if (ctx->num + 9 <= MD5_BLOCK_SIZE) { + memset(ctx->block + ctx->num + 1, 0, MD5_BLOCK_SIZE - ctx->num - 9); + } else { + memset(ctx->block + ctx->num + 1, 0, MD5_BLOCK_SIZE - ctx->num - 1); + md5_compress_blocks(ctx->state, ctx->block, 1); + memset(ctx->block, 0, MD5_BLOCK_SIZE - 8); + } + PUTU64_LE(ctx->block + 56, (ctx->nblocks << 9) + (ctx->num << 3)); + md5_compress_blocks(ctx->state, ctx->block, 1); + for (i = 0; i < 4; i++) { + //PUTU32_LE(dgst, ctx->state[i]); + *(uint32_t *)dgst = ctx->state[i]; + dgst += sizeof(uint32_t); + } +} + +#define ROL32(X, n) (((X) << (n)) | ((X) >> (32-(n)))) +#define F(B, C, D) (((B) & (C)) | ((~(B)) & (D))) +#define G(B, C, D) (((B) & (D)) | ((C) & (~(D)))) +#define H(B, C, D) ((B) ^ (C) ^ (D)) +#define I(B, C, D) ((C) ^ ((B) | (~(D)))) + +static const uint32_t K[] = { + 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, + 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, + 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, + 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, + 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, + 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8, + 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, + 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, + 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, + 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, + 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, + 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, + 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, + 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, + 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, + 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391, +}; + +static const int S[] = { + 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, + 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, + 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, + 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, +}; + +static void md5_compress_blocks(uint32_t state[4], + const unsigned char *data, size_t blocks) +{ + uint32_t A; + uint32_t B; + uint32_t C; + uint32_t D; + uint32_t T; + uint32_t W[16]; + int g, i; + + while (blocks--) { + + A = state[0]; + B = state[1]; + C = state[2]; + D = state[3]; + + for (i = 0; i < 16; i++) { + //W[i] = GETU32_LE(data); + W[i] = *((uint32_t *)data); + data += sizeof(uint32_t); + } + + for (i = 0; i < 16; i++) { + T = ROL32(A + F(B, C, D) + W[i] + K[i], S[i]) + B; + A = D; + D = C; + C = B; + B = T; + } + for (; i < 32; i++) { + g = (5 * i + 1) % 16; + T = ROL32(A + G(B, C, D) + W[g] + K[i], S[i]) + B; + A = D; + D = C; + C = B; + B = T; + } + for (; i < 48; i++) { + g = (3 * i + 5) % 16; + T = ROL32(A + H(B, C, D) + W[g] + K[i], S[i]) + B; + A = D; + D = C; + C = B; + B = T; + } + for (; i < 64; i++) { + g = (7 * i) % 16; + T = ROL32(A + I(B, C, D) + W[g] + K[i], S[i]) + B; + A = D; + D = C; + C = B; + B = T; + } + + state[0] += A; + state[1] += B; + state[2] += C; + state[3] += D; + } +} + +void md5_compress(uint32_t state[4], const unsigned char block[64]) +{ + return md5_compress_blocks(state, block, 1); +} + +void md5_digest(const unsigned char *data, size_t datalen, + unsigned char dgst[MD5_DIGEST_SIZE]) +{ + MD5_CTX ctx; + md5_init(&ctx); + md5_update(&ctx, data, datalen); + md5_finish(&ctx, dgst); +} diff --git a/src/mem.h b/src/mem.h new file mode 100644 index 00000000..d459393d --- /dev/null +++ b/src/mem.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2021 - 2021 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + +#ifndef GMSSL_MEM_H +#define GMSSL_MEM_H + +#include // where size_t from + + +void memxor(void *r, const void *a, size_t len); +void gmssl_memxor(void *r, const void *a, const void *b, size_t len); + +#endif diff --git a/src/oid.c b/src/oid.c new file mode 100644 index 00000000..73a41c32 --- /dev/null +++ b/src/oid.c @@ -0,0 +1,958 @@ +/* + * Copyright (c) 2014 - 2020 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + + +#include +#include +#include +#include +#include +#include +#include + + +/* + asn1_type_from_octets 函数有三种返回值 + + * -1 说明编码的前缀错误,也就是不属于本类型的字节点 + * 0 即 OID_undef,说明前缀是匹配的,但是我们不识别这个 OID + * >=1 一个被识别出来的 OID + + asn1_type_from_octets 函数不识别 type 的编码,如 asn1_sm_oid_from_octets 不识别 DER_sm + 但是返回值为 OID_undef,而不是 -1 +*/ + +static uint8_t DER_sm[] = { 0x2A, 0x81, 0x1C, 0xCF, 0x55, 0x01 }; +static uint8_t DER_sm1[] = { 0x66 }; +static uint8_t DER_ssf33[] = { 0x67 }; +static uint8_t DER_sm4[] = { 0x68 }; +static uint8_t DER_zuc[] = { 0x86, 0x20 }; +static uint8_t DER_sm2[] = { 0x82, 0x2D }; +static uint8_t DER_sm2sign[] = { 0x82, 0x2D, 0x01 }; +static uint8_t DER_sm2keyagreement[] = { 0x82, 0x2D, 0x02 }; +static uint8_t DER_sm2encrypt[] = { 0x82, 0x2D, 0x03 }; +static uint8_t DER_sm9[] = { 0x82, 0x2E }; +static uint8_t DER_sm9sign[] = { 0x82, 0x2E, 0x01 }; +static uint8_t DER_sm9keyagreement[] = { 0x82, 0x2E, 0x02 }; +static uint8_t DER_sm9encrypt[] = { 0x82, 0x2E, 0x03 }; +static uint8_t DER_sm3[] = { 0x83, 0x11 }; +static uint8_t DER_sm3_keyless[] = { 0x83, 0x11, 0x01 }; +static uint8_t DER_hmac_sm3[] = { 0x83, 0x11, 0x02 }; +static uint8_t DER_sm2sign_with_sm3[] = { 0x83, 0x75 }; +static uint8_t DER_rsasign_with_sm3[] = { 0x83, 0x78 }; + +static const struct { + uint8_t *der; + size_t derlen; + char *name; + char *desc; +} sm_oids[] = { + { DER_sm1, 1, "sm1", "SM1" }, + { DER_ssf33, 1, "ssf33", "SSF33" }, + { DER_sm4, 1, "sm4", "SM4" }, + { DER_zuc, 2, "zuc", "ZUC" }, + { DER_sm2, 2, "sm2p256v1", "SM2" }, + { DER_sm2sign, 3, "sm2sign", "SM2 Signature Scheme" }, + { DER_sm2keyagreement, 3, "sm2keyagreement", "SM2 Key Agreement" }, + { DER_sm2encrypt, 3, "sm2encrypt", "SM2 Encryption" }, + { DER_sm9, 2, "sm9", "SM9" }, + { DER_sm9sign, 3, "sm9sign", "SM9 Signature Scheme" }, + { DER_sm9keyagreement, 3, "sm9keyagreement", "SM9 Key Agreement" }, + { DER_sm9encrypt, 3, "sm9encrypt", "SM9 Encrpytion" }, + { DER_sm3, 2, "sm3", "SM3" }, + { DER_sm3_keyless, 3, "sm3-keyless", "SM3 without Key" }, + { DER_hmac_sm3, 3, "hmac-sm3", "HMAC-SM3" }, + { DER_sm2sign_with_sm3, 2, "sm2sign-with-sm3", "SM2 Signature with SM3" }, + { DER_rsasign_with_sm3, 2, "rsasign-with-sm3", "RSA Signature with SM3" }, +}; + +const char *asn1_sm_oid_name(int oid) +{ + assert(OID_sm1 <= oid && oid <= OID_rsasign_with_sm3); + return sm_oids[oid - OID_sm1].name; +} + +const char *asn1_sm_oid_description(int oid) +{ + assert(oid >= OID_sm1 && oid <= OID_rsasign_with_sm3); + return sm_oids[oid - OID_sm1].desc; +} + +void asn1_sm_oid_to_octets(int oid, uint8_t *out, size_t *outlen) +{ + int i = oid - OID_sm1; + assert(i >= 0 && i < sizeof(sm_oids)/sizeof(sm_oids[0])); + if (out) { + memcpy(out, DER_sm, sizeof(DER_sm)); + out += sizeof(DER_sm); + memcpy(out, sm_oids[i].der, sm_oids[i].derlen); + out += sm_oids[i].derlen; + } + *outlen = sizeof(DER_sm) + sm_oids[i].derlen; +} + +int asn1_sm_oid_from_octets(const uint8_t *in, size_t inlen) +{ + int i; + + if (inlen < sizeof(DER_sm) + || memcmp(in, DER_sm, sizeof(DER_sm)) != 0) { + return -1; + } + in += sizeof(DER_sm); + inlen -= sizeof(DER_sm); + + for (i = 0; i < sizeof(sm_oids)/sizeof(sm_oids[0]); i++) { + if (sm_oids[i].derlen == inlen + && memcmp(sm_oids[i].der, in, inlen) == 0) { + return OID_sm1 + i; + } + } + return OID_undef; +} + +int asn1_sm_oid_from_name(const char *name) +{ + size_t i; + for (i = 0; i < sizeof(sm_oids)/sizeof(sm_oids[0]); i++) { + if (strcmp(name, sm_oids[i].name) == 0) { + return OID_sm1 + i; + } + } + return OID_undef; +} + + +// FIXME: 支持所有的公钥类型 +static const uint8_t DER_x9_62_ecPublicKey[] = { 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01 }; + + +const char *asn1_pkey_oid_name(int oid) +{ + switch (oid) { + case OID_x9_62_ecPublicKey: return "x9_62_ecPublicKey"; + } + return NULL; +} + +const char *asn1_pkey_oid_description(int oid) +{ + switch (oid) { + case OID_x9_62_ecPublicKey: return "x9_62_ecPublicKey"; + } + return NULL; +} + +void asn1_pkey_oid_to_octets(int oid, uint8_t *out, size_t *outlen) +{ + assert(oid == OID_x9_62_ecPublicKey); + if (out) { + memcpy(out, DER_x9_62_ecPublicKey, sizeof(DER_x9_62_ecPublicKey)); + } + *outlen = sizeof(DER_x9_62_ecPublicKey); +} + +int asn1_pkey_oid_from_octets(const uint8_t *in, size_t inlen) +{ + if (inlen == sizeof(DER_x9_62_ecPublicKey) + && memcmp(DER_x9_62_ecPublicKey, in, inlen) == 0) { + return OID_x9_62_ecPublicKey; + } + return 0; +} + +int asn1_pkey_oid_from_name(const char *name) +{ + if (strcmp(name, "x9_62_ecPublicKey") == 0) { + return OID_x9_62_ecPublicKey; + } + return 0; +} + + +// 本组函数不支持 OID_x9_62_ecPublicKey 的 DER 编解码 +// 这个类型应该归为公钥类型,还包括RSA、DSA、DH等公钥类型 +// 这个错误, 03 01 是 curves prime ,而不是x9_62_ecPublicKey +// x9_62_ecPublicKey 是 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01 +static const uint8_t DER_x9_62_curve_prime[] = { 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01 }; + +static const struct { + uint8_t der; + char *name; +} x9_62_curve_oids[] = { + { 1, "prime192v1" }, + { 2, "prime192v2" }, + { 3, "prime192v3" }, + { 4, "prime239v1" }, + { 5, "prime239v2" }, + { 6, "prime239v3" }, + { 7, "prime256v1" }, +}; + +const char *asn1_x9_62_curve_oid_name(int oid) +{ + assert(OID_prime192v1 <= oid && oid <= OID_prime256v1); + return x9_62_curve_oids[oid - OID_prime192v1].name; +} + +const char *asn1_x9_62_curve_oid_description(int oid) +{ + return asn1_x9_62_curve_oid_name(oid); +} + +void asn1_x9_62_curve_oid_to_octets(int oid, uint8_t *out, size_t *outlen) +{ + assert(OID_prime192v1 <= oid && oid <= OID_prime256v1); + if (out) { + memcpy(out, DER_x9_62_curve_prime, sizeof(DER_x9_62_curve_prime)); + out += sizeof(DER_x9_62_curve_prime); + *out = x9_62_curve_oids[oid - OID_prime192v1].der; + } + (*outlen) = sizeof(DER_x9_62_curve_prime) + 1; +} + +int asn1_x9_62_curve_oid_from_octets(const uint8_t *in, size_t inlen) +{ + if (inlen < sizeof(DER_x9_62_curve_prime) + || memcmp(in, DER_x9_62_curve_prime, sizeof(DER_x9_62_curve_prime)) != 0) { + return -1; + } + in += sizeof(DER_x9_62_curve_prime); + inlen -= sizeof(DER_x9_62_curve_prime); + if (inlen == 1 && *in >= 1 && *in <= 7) { + return OID_prime192v1 + *in - 1; + } + return OID_undef; +} + +int asn1_x9_62_curve_oid_from_name(const char *name) +{ + int i; + for (i = 0; i < sizeof(x9_62_curve_oids)/sizeof(x9_62_curve_oids[0]); i++) { + if (strcmp(name, x9_62_curve_oids[i].name) == 0) { + return OID_prime192v1 + i; + } + } + return OID_undef; +} + + + + +static const uint8_t DER_secg_curve[] = { 0x2B, 0x81, 0x04, 0x00 }; + +static const struct { + uint8_t der; + int oid; + char *name; +} secg_curve_oids[] = { + { 10, OID_secp256k1, "secp256k1" }, + { 31, OID_secp192k1, "secp192k1" }, + { 32, OID_secp224k1, "secp224k1" }, + { 33, OID_secp224r1, "secp224r1" }, + { 34, OID_secp384r1, "secp384r1" }, + { 35, OID_secp521r1, "secp521r1" }, +}; + +const char *asn1_secg_curve_oid_name(int oid) +{ + int i = oid - OID_secp256k1; + + if (i < 0 || i >= sizeof(secg_curve_oids)/sizeof(secg_curve_oids[0])) { + fprintf(stderr, "%s %d: i = %d\n", __FILE__, __LINE__, i); + } + + + assert(i >= 0 && i < sizeof(secg_curve_oids)/sizeof(secg_curve_oids[0])); + return secg_curve_oids[i].name; +} + +const char *asn1_secg_curve_oid_description(int oid) +{ + return asn1_secg_curve_oid_name(oid); +} + +void asn1_secg_curve_oid_to_octets(int oid, uint8_t *out, size_t *outlen) +{ + int i = oid - OID_secp256k1; + if (out) { + memcpy(out, DER_secg_curve, sizeof(DER_secg_curve)); + out += sizeof(DER_secg_curve); + *out++ = secg_curve_oids[i].der; + } + *outlen = sizeof(DER_secg_curve) + 1; +} + +int asn1_secg_curve_oid_from_octets(const uint8_t *in, size_t inlen) +{ + if (inlen < sizeof(DER_secg_curve) + || memcmp(in, DER_secg_curve, sizeof(DER_secg_curve)) != 0) { + return -1; + } + in += sizeof(DER_secg_curve); + inlen -= sizeof(DER_secg_curve); + + if (inlen == 1) { + int i; + for (i = 0; i < sizeof(secg_curve_oids)/sizeof(secg_curve_oids[0]); i++) { + if (*in == secg_curve_oids[i].der) { + return secg_curve_oids[i].oid; + } + } + } + return OID_undef; +} + +int asn1_secg_curve_oid_from_name(const char *name) +{ + uint32_t a; + if (strlen(name) != sizeof("secp256k1")-1 + || *(uint32_t *)name != *(uint32_t *)"secp" + || name[8] != '1') { + return OID_undef; + } + a = *(uint32_t *)(name + 4); + if (a == *(uint32_t *)"256k") return OID_secp256k1; + else if (a == *(uint32_t *)"192k") return OID_secp192k1; + else if (a == *(uint32_t *)"224k") return OID_secp224k1; + else if (a == *(uint32_t *)"224r") return OID_secp224r1; + else if (a == *(uint32_t *)"384r") return OID_secp384r1; + else if (a == *(uint32_t *)"521r") return OID_secp521r1; + else return OID_undef; +} + + + + + +static const uint8_t DER_x509[] = { 0x55, 0x04 }; + +static const struct { + uint8_t der; + char *name; + char *desc; +} x509_oids[] = { + { 3, "commonName", "Common Name" }, + { 4, "surname", "Surname" }, + { 5, "serialNumber", "Serial Number" }, + { 6, "countryName", "Country" }, + { 7, "localityName", "Locality" }, + { 8, "stateOrProvinceName", "State or Province" }, + { 9, "streetAddress", "Street Address" }, + { 10, "organizationName", "Organization" }, + { 11, "organizationalUnitName", "Organizational Unit" }, + { 12, "title", "Title" }, + { 13, "description", "Description" }, + { 14, "searchGuide", "Search Guide" }, + { 15, "businessCategory", "Business Category" }, + { 16, "postalAddress", "Postal Address" }, + { 17, "postalCode", "Postal Code" }, + { 18, "postOfficeBox", "Post Office Box" }, + { 19, "physicalDeliveryOfficeName", "Physical Delivery Office" }, + { 20, "telephoneNumber", "Telephone Number" }, + { 21, "telexNumber", "Telex Number" }, + { 22, "teletexTerminalIdentifier", "Teletex Terminal Identifier" }, + { 23, "facsimileTelephoneNumber", "Facsimile Telephone Number" }, + { 24, "x121Address", "X121 Address" }, + { 25, "internationaliSDNNumber", "InternationaliSDN Number" }, + { 26, "registeredAddress", "Registered Address" }, + { 27, "destinationIndicator", "Destination Indicator" }, + { 28, "preferredDeliveryMethod", "Preferred Delivery Method" }, + { 29, "presentationAddress", "Presentation Address" }, + { 30, "supportedApplicationContext", "Supported ApplicationContext" }, + { 31, "member", "Member" }, + { 32, "owner", "Owner" }, + { 33, "roleOccupant", "Role Occupant" }, + { 34, "seeAlso", "See Also" }, + { 35, "userPassword", "User Password" }, + { 36, "userCertificate", "User Certificate" }, + { 37, "caCertificate", "CA Certificate" }, + { 38, "authorityRevocationList", "Authority Revocation List" }, + { 39, "certificateRevocationList", "Certificate Revocation List" }, + { 40, "crossCertificatePair", "Cros sCertificate Pair" }, + { 41, "name", "Name" }, + { 42, "givenName", "Given Name" }, + { 43, "initials", "Initials" }, + { 44, "generationQualifier", "Generation Qualifier" }, + { 45, "x500UniqueIdentifier", "X500Unique Identifier" }, + { 46, "dnQualifier", "DN Qualifier" }, + { 47, "enhancedSearchGuide", "Enhanced Search Guide" }, + { 48, "protocolInformation", "Protocol Information" }, + { 49, "distinguishedName", "Distinguished Name" }, + { 50, "uniqueMember", "Unique Member" }, + { 51, "houseIdentifier", "House Identifier" }, + { 52, "supportedAlgorithms", "Supported Algorithms" }, + { 53, "deltaRevocationList", "Delta Revocation List" }, + { 55, "dmdName", "DMD Name" }, + { 65, "pseudonym", "Pseudonym" }, + { 72, "role", "Role" }, +}; + +const char *asn1_x509_oid_name(int oid) +{ + int i = oid - OID_at_commonName; + + assert(OID_at_role - OID_at_commonName + 1 == sizeof(x509_oids)/sizeof(x509_oids[0])); + + if (i < 0 || i >= sizeof(x509_oids)/sizeof(x509_oids[0])) { + fprintf(stderr, "%s %d: oid = %d, i = %d\n", __FILE__, __LINE__, oid, i); + } + + + assert(i >= 0 && i < sizeof(x509_oids)/sizeof(x509_oids[0])); + return x509_oids[i].name; +} + +const char *asn1_x509_oid_description(int oid) +{ + int i = oid - OID_at_commonName; + assert(i >= 0 && i < sizeof(x509_oids)/sizeof(x509_oids[0])); + return x509_oids[i].desc; +} + +void asn1_x509_oid_to_octets(int oid, uint8_t *out, size_t *outlen) +{ + int i = oid - OID_at_commonName; + if (i < 0 || i >= sizeof(x509_oids)/sizeof(x509_oids[0])) { + fprintf(stderr, "%s %d: oid = %d, i = %d\n", __FILE__, __LINE__, oid, i); + } + assert(i >= 0 && i < sizeof(x509_oids)/sizeof(x509_oids[0])); + + + if (out) { + memcpy(out, DER_x509, sizeof(DER_x509)); + out += sizeof(DER_x509); + *out = x509_oids[i].der; + } + *outlen = sizeof(DER_x509) + 1; + + +} + +int asn1_x509_oid_from_octets(const uint8_t *in, size_t inlen) +{ + if (inlen < sizeof(DER_x509) + || memcmp(in, DER_x509, sizeof(DER_x509)) != 0) { + return -1; + } + in += sizeof(DER_x509); + inlen -= sizeof(DER_x509); + + if (inlen == 1) { + if (*in >= 3 && *in <= 53) + return OID_at_commonName + *in - 3; + else if (*in == 55) + return OID_at_dmdName; + else if (*in == 65) + return OID_at_pseudonym; + else if (*in == 72) + return OID_at_role; + } + return OID_undef; +} + +int asn1_x509_oid_from_name(const char *name) +{ + int i; + for (i = 0; i < sizeof(x509_oids)/sizeof(x509_oids[0]); i++) { + if (strcmp(name, x509_oids[i].name) == 0) { + return OID_at_commonName + i; + } + } + return OID_undef; +} + + +// OIDs for X.509 extension ExtKeyUsage +// kp means "key purpose" +static const uint8_t DER_x509_kp[] = { 0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, }; + +static const struct { + uint8_t der; + char *name; + char *desc; +} x509_kp_oids[] = { + { 1, "serverAuth", "TLS WWW server authentication" }, + { 2, "clientAuth", "TLS WWW client authentication" }, + { 3, "codeSigning", "Signing of downloadable executable code" }, + { 4, "emailProtection", "Email protection" }, + { 8, "timeStamping", "Binding the hash of an object to a time" }, + { 9, "OCSPSigning", "Signing OCSP responses" }, +}; + +const char *asn1_x509_kp_oid_name(int oid) +{ + int i = oid - OID_kp_serverAuth; + assert(i >= 0 && i < sizeof(x509_kp_oids)/sizeof(x509_kp_oids[0])); + return x509_kp_oids[i].name; +} + +const char *asn1_x509_kp_oid_description(int oid) +{ + int i = oid - OID_kp_serverAuth; + assert(i >= 0 && i < sizeof(x509_kp_oids)/sizeof(x509_kp_oids[0])); + return x509_kp_oids[i].desc; +} + +void asn1_x509_kp_oid_to_octets(int oid, uint8_t *out, size_t *outlen) +{ + int i = oid - OID_kp_serverAuth; + assert(i >= 0 && i < sizeof(x509_kp_oids)/sizeof(x509_kp_oids[0])); + if (out) { + memcpy(out, DER_x509_kp, sizeof(DER_x509_kp)); + out += sizeof(DER_x509_kp); + *out = x509_kp_oids[i].der; + } + *outlen = sizeof(DER_x509_kp) + 1; +} + +int asn1_x509_kp_oid_from_octets(const uint8_t *in, size_t inlen) +{ + if (inlen < sizeof(DER_x509_kp) + || memcmp(in, DER_x509_kp, sizeof(DER_x509_kp)) != 0) { + return -1; + } + in += sizeof(DER_x509_kp); + inlen -= sizeof(DER_x509_kp); + + if (inlen == 1) { + if (*in >= 1 && *in <= 4) + return OID_kp_serverAuth + *in - 1; + else if (*in == 8) + return OID_kp_timeStamping; + else if (*in == 9) + return OID_kp_OCSPSigning; + } + return OID_undef; +} + +int asn1_x509_kp_oid_from_name(const char *name) +{ + int i; + assert(i >= 0 && i < sizeof(x509_kp_oids)/sizeof(x509_kp_oids[0])); + for (i = 0; i < sizeof(x509_kp_oids)/sizeof(x509_kp_oids[0]); i++) { + if (strcmp(name, x509_kp_oids[i].name) == 0) { + return OID_kp_serverAuth + i; + } + } + return OID_undef; +} + +void asn1_oid_to_octets(int oid, uint8_t *out, size_t *outlen) +{ + if (oid <= OID_rsasign_with_sm3) { + asn1_sm_oid_to_octets(oid, out, outlen); + } else if (oid == OID_x9_62_ecPublicKey) { + if (out) // 注意:这里必须验证 out == NULL ? + memcpy(out, DER_x9_62_ecPublicKey, sizeof(DER_x9_62_ecPublicKey)); + *outlen = sizeof(DER_x9_62_ecPublicKey); + } else if (oid <= OID_prime256v1) { + asn1_x9_62_curve_oid_to_octets(oid, out, outlen); + } else if (oid <= OID_secp521r1) { + asn1_secg_curve_oid_to_octets(oid, out, outlen); + } else if (oid <= OID_at_role) { + asn1_x509_oid_to_octets(oid, out, outlen); + } else { + error_print("unknown oid %d\n", oid); + assert(0); + } +} + +// asn1_oid_from_octets 不返回错误值,只返回 OID_undef +// 但是数据编码仍可能是非法的 +// 如果返回 OID_undef,需要通过 asn1_oid_nodes_from_octets 判断格式是否正确 +int asn1_oid_from_octets(const uint8_t *in, size_t inlen) +{ + int ret = OID_undef; + if (inlen == sizeof(DER_x9_62_ecPublicKey) + && memcmp(DER_x9_62_ecPublicKey, in, inlen) == 0) { + return OID_x9_62_ecPublicKey; + } + + if (inlen >= sizeof(DER_x9_62_ecPublicKey) + && memcmp(in, DER_x9_62_ecPublicKey, sizeof(DER_x9_62_ecPublicKey)) == 0) { + if (inlen == sizeof(DER_x9_62_ecPublicKey)) + ret = OID_x9_62_ecPublicKey; + else ret = asn1_x9_62_curve_oid_from_octets(in, inlen); + } else if (inlen > sizeof(DER_sm) + && memcmp(in, DER_sm, sizeof(DER_sm)) == 0) { + ret = asn1_sm_oid_from_octets(in, inlen); + } else if (inlen > sizeof(DER_secg_curve) + && memcmp(in, DER_secg_curve, sizeof(DER_secg_curve)) == 0) { + ret = asn1_secg_curve_oid_from_octets(in, inlen); + } else if (inlen > sizeof(DER_x509) + && memcmp(in, DER_x509, sizeof(DER_x509)) == 0) { + ret = asn1_x509_oid_from_octets(in, inlen); + } else { + /* + int i; + error_print("unknown der\n"); + print_der(in, inlen); + printf("\n"); + */ + return OID_undef; + } + + if (ret < 0) { + error_print("invalid der\n"); + } + return ret; +} + +// 输出长度不固定,并且被多次重复调用,因此提供 **out 形式的参数 +static void uint_to_base128(uint32_t a, uint8_t **out, size_t *outlen) +{ + uint8_t buf[5]; + int n = 0; + + buf[n++] = a & 0x7f; + a >>= 7; + + while (a) { + buf[n++] = 0x80 | (a & 0x7f); + a >>= 7; + } + + while (n--) { + if (out) + *(*out)++ = buf[n]; + (*outlen)++; + } +} + +// 实际上我们在解析的时候是不知道具体在哪里结束的 +// 解析是有可能出错的,如果没有发现最后一个0开头的字节就出错了 +// 还有值太大也会出错,我们最多读取5个字节 +// { 0x81, 0x82 } +// { 0x81, 0x82, 0x83, 0x84, 0x85, 0x06 } +static int uint_from_base128(uint32_t *a, const uint8_t **in, size_t *inlen) +{ + uint8_t buf[5]; + int n = 0; + int i; + + for (;;) { + if ((*inlen)-- < 1 || n >= 5) { + return -1; + } + buf[n] = *(*in)++; + if ((buf[n++] & 0x80) == 0) { + break; + } + } + + // 32 - 7*4 = 4, so the first byte should be like 1000bbbb + if (n == 5 && (buf[0] & 0x70)) { + return -1; + } + + *a = 0; + for (i = 0; i < n; i++) { + *a = ((*a) << 7) | (buf[i] & 0x7f); + } + + return 1; +} + +int asn1_oid_nodes_to_octets(const uint32_t *nodes, size_t nodes_count, uint8_t *out, size_t *outlen) +{ + if (nodes_count < 2 || nodes_count > 32) { + return -1; + } + if (out) + *out++ = (uint8_t)(nodes[0] * 40 + nodes[1]); + (*outlen) = 1; + nodes += 2; + nodes_count -= 2; + + while (nodes_count--) { + uint_to_base128(*nodes++, &out, outlen); + } + return 1; +} + +// 因为这个函数总是被asn1函数调用的,因此给的输入数据长度是已知的 +int asn1_oid_nodes_from_octets(uint32_t *nodes, size_t *nodes_count, const uint8_t *in, size_t inlen) +{ + size_t count = 0; + const uint8_t *p = in; + size_t len = inlen; + + if (!nodes || !nodes_count || !in || inlen <= 0) { + error_print(); + return -1; + } + + if (inlen < 1) { + error_print(); + return -1; + } + + // FIXME: 需要支持 nodes = NULL 吗? + if (nodes) { + *nodes++ = (*in) / 40; + *nodes++ = (*in) % 40; + } + in++; + inlen--; + count += 2; + + while (inlen) { + uint32_t val; + if (count > 32) { + return -1; + } + if (uint_from_base128(&val, &in, &inlen) < 0) { + return -1; + } + if (nodes) { + *nodes++ = val; + } + count++; + } + + *nodes_count = count; + return 1; +} + +// 调用方应提供一个已知的 OID 名字,否则函数会返回错误,而非返回 OID_undef +int asn1_object_identifier_from_name(int *oid, const char *name) +{ + if (!oid || !name) { + return -1; + } + + if ((*oid = asn1_sm_oid_from_name(name)) != OID_undef) + return 1; + if ((*oid = asn1_x9_62_curve_oid_from_name(name)) != OID_undef) + return 1; + if ((*oid = asn1_secg_curve_oid_from_name(name)) != OID_undef) + return 1; + if ((*oid = asn1_x509_oid_from_name(name)) != OID_undef) + return 1; + + return 1; +} + +const char *asn1_object_identifier_name(int oid) +{ + if (oid < 0) { + return NULL; + } else if (oid == OID_undef) { + return "undef"; + } else if (oid <= OID_rsasign_with_sm3) { + return asn1_sm_oid_name(oid); + } else if (oid <= OID_x9_62_ecPublicKey) { // FIXME: 目前单独处理,后续应增加公钥类型 OID 集合 + return "x9_62_ecPublicKey"; + } else if (oid <= OID_prime256v1) { + return asn1_x9_62_curve_oid_name(oid); + } else if (oid <= OID_secp521r1) { + return asn1_secg_curve_oid_name(oid); + } else if (oid <= OID_at_role) { + return asn1_x509_oid_name(oid); + } else { + // FIXME: 还有后续的一些X.509 OID没有支持 + return NULL; + } +} + +const char *asn1_object_identifier_description(int oid) +{ + if (oid < 0) { + return NULL; + } else if (oid == OID_undef) { + return ""; + } else if (oid <= OID_rsasign_with_sm3) { + return asn1_sm_oid_description(oid); + } else if (oid <= OID_x9_62_ecPublicKey) { // FIXME: 目前单独处理,后续应增加公钥类型 OID 集合 + return "x9_62_ecPublicKey"; + } else if (oid <= OID_prime256v1) { + return asn1_x9_62_curve_oid_description(oid); + } else if (oid <= OID_secp521r1) { + return asn1_secg_curve_oid_description(oid); + } else if (oid <= OID_at_role) { + return asn1_x509_oid_description(oid); + } + // FIXME: 还有后续的一些X.509 OID没有支持 + return NULL; +} + +// 测试 oid_nodes 编解码是否正确 +// FIXME: 还应该增加一些外部的测试用例 +int test_asn1_oid_nodes(void) +{ + int oid; + uint8_t octets[64]; + uint8_t buf[64]; + uint32_t nodes[32]; + size_t octetslen, buflen, nodes_count; + + for (oid = 1; oid <= OID_at_role; oid++) { + int i; + asn1_oid_to_octets(oid, octets, &octetslen); + asn1_oid_nodes_from_octets(nodes, &nodes_count, octets, octetslen); + asn1_oid_nodes_to_octets(nodes, nodes_count, buf, &buflen); + if (buflen != octetslen || memcmp(octets, buf, buflen) != 0) { + fprintf(stderr, "%s %d: oid = %d error\n", __FILE__, __LINE__, oid); + } + + printf("%d : ", oid); + for (i = 0; i < nodes_count; i++) { + printf("%d ", (int)nodes[i]); + } + printf("\n"); + } + + return 1; +} + +int test_asn1_oid(void) +{ + uint8_t buf[1024]; + uint8_t *p = buf; + size_t len =0; + int oid; + int i; + + uint32_t nodes[32]; + size_t nodes_count; + + test_asn1_oid_nodes(); + + for (i = 1; i <= OID_at_role; i++) { + int j; + asn1_oid_to_octets(i, buf, &len); + oid = asn1_oid_from_octets(buf, len); + printf("%d %s %s ", oid, asn1_object_identifier_name(oid), asn1_object_identifier_description(oid)); + + asn1_oid_nodes_from_octets(nodes, &nodes_count, buf, len); + for (j = 0; j < nodes_count; j++) { + printf("%d.", nodes[j]); + } + printf("\n"); + } + + return 1; +} + +int test_asn1_object_identifier_to_der(int oid) +{ + uint8_t buf[64] = {0}; + const uint8_t *cp = buf; + uint8_t *p = buf; + size_t len = 0, i; + uint32_t nodes[32] = {0}; + size_t nodes_count; + int roid; + + if (asn1_object_identifier_to_der(oid, NULL, 0, &p, &len) != 1) { + error_print(); + return 0; + } + printf("%d : %s : ", oid, asn1_object_identifier_name(oid)); + print_der(buf, len); + + + if (asn1_object_identifier_from_der(&roid, nodes, &nodes_count, &cp, &len) != 1) { + error_print(); + return 0; + } + printf(" : "); + print_nodes(nodes, nodes_count); + printf("\n"); + + if (roid != oid) { + error_print("oid = %d, parsed oid = %d\n", oid, roid); + return -1; + } + if (len != 0) { + error_print(); + return -1; + } + return 1; +} + +int test_asn1_object_identifier(void) +{ + uint8_t buf[2048]; + const uint8_t *cp = buf; + uint8_t *p = buf; + size_t len = 0; + uint32_t nodes[32] = {0}; + size_t nodes_count; + int oid; + int i; + + // 分别测试每个oid分别编解码是否正确 + for (oid = 1; oid <= OID_at_role; oid++) { + if (test_asn1_object_identifier_to_der(oid) < 0) { + error_print(); + return -1; + } + } + + // 将全部oid编码后再解码 + for (oid = 1; oid <= OID_at_role; oid++) { + if (asn1_object_identifier_to_der(oid, NULL, 0, &p, &len) != 1) { + error_print(); + return -1; + } + } + printf("%s %d: All OIDs encoded length = %zu bytes\n", __FILE__, __LINE__, len); + print_der(buf, len); + printf("\n"); + + while (len) { + int ret; + if (asn1_object_identifier_from_der(&oid, nodes, &nodes_count, &cp, &len) <= 0) { + break; + } + printf("%d %s\n", oid, asn1_object_identifier_name(oid)); + } + return 1; +} diff --git a/src/pbkdf2.c b/src/pbkdf2.c new file mode 100644 index 00000000..7504acfc --- /dev/null +++ b/src/pbkdf2.c @@ -0,0 +1,174 @@ +/* + * Copyright (c) 2014 - 2020 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + + +/* + PBKDF2 (P, S, c, dkLen) + + Options: PRF underlying pseudorandom function (hLen + denotes the length in octets of the + pseudorandom function output) + + Input: P password, an octet string + S salt, an octet string + c iteration count, a positive integer + dkLen intended length in octets of the derived + key, a positive integer, at most + (2^32 - 1) * hLen + + Output: DK derived key, a dkLen-octet string + + Steps: + + 1. If dkLen > (2^32 - 1) * hLen, output "derived key too long" and + stop. + + 2. Let l be the number of hLen-octet blocks in the derived key, + rounding up, and let r be the number of octets in the last + block: + + l = CEIL (dkLen / hLen) , + r = dkLen - (l - 1) * hLen . + + Here, CEIL (x) is the "ceiling" function, i.e. the smallest + integer greater than, or equal to, x. + + 3. For each block of the derived key apply the function F defined + below to the password P, the salt S, the iteration count c, and + the block index to compute the block: + + T_1 = F (P, S, c, 1) , + T_2 = F (P, S, c, 2) , + ... + T_l = F (P, S, c, l) , + + where the function F is defined as the exclusive-or sum of the + first c iterates of the underlying pseudorandom function PRF + applied to the password P and the concatenation of the salt S + and the block index i: + + F (P, S, c, i) = U_1 \xor U_2 \xor ... \xor U_c + + where + + U_1 = PRF (P, S || INT (i)) , + U_2 = PRF (P, U_1) , + ... + U_c = PRF (P, U_{c-1}) . + + Here, INT (i) is a four-octet encoding of the integer i, most + significant octet first. + + 4. Concatenate the blocks and extract the first dkLen octets to + produce a derived key DK: + + DK = T_1 || T_2 || ... || T_l<0..r-1> + + 5. Output the derived key DK. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "endian.h" +#include "mem.h" + +int pbkdf2_genkey(const DIGEST *digest, + const char *pass, size_t passlen, + const uint8_t *salt, size_t saltlen, unsigned int count, + size_t outlen, uint8_t *out) +{ + HMAC_CTX ctx; + uint32_t iter = 1; + uint8_t iter_be[4]; + uint8_t tmp_block[64]; + uint8_t key_block[64]; + size_t len; + + hmac_init(&ctx, digest, (uint8_t *)pass, passlen); + + while (outlen > 0) { + int i; + + PUTU32(iter_be, iter); + iter++; + + hmac_update(&ctx, salt, saltlen); + hmac_update(&ctx, iter_be, sizeof(iter_be)); + hmac_finish(&ctx, tmp_block, &len); + hmac_reset(&ctx); + memcpy(key_block, tmp_block, len); + + for (i = 1; i < count; i++) { + hmac_update(&ctx, tmp_block, len); + hmac_finish(&ctx, tmp_block, &len); + hmac_reset(&ctx); + memxor(key_block, tmp_block, len); + } + + if (outlen < len) { + memcpy(out, key_block, outlen); + out += outlen; + outlen = 0; + } else { + memcpy(out, key_block, len); + out += len; + outlen -= len; + } + } + + memset(&ctx, 0, sizeof(ctx)); + memset(key_block, 0, sizeof(key_block)); + memset(tmp_block, 0, sizeof(key_block)); + return 1; +} diff --git a/src/pem.c b/src/pem.c new file mode 100644 index 00000000..9d7594da --- /dev/null +++ b/src/pem.c @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2020 - 2021 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + +#include +#include +#include +#include +#include + + +int pem_write(FILE *fp, const char *name, const uint8_t *data, size_t datalen) +{ + int ret = 0; + BASE64_CTX ctx; + uint8_t b64[datalen * 2]; + int len; + + base64_encode_init(&ctx); + base64_encode_update(&ctx, data, (int)datalen, b64, &len); + base64_encode_finish(&ctx, b64 + len, &len); + + ret += fprintf(fp, "-----BEGIN %s-----\n", name); + ret += fprintf(fp, "%s", (char *)b64); + ret += fprintf(fp, "-----END %s-----\n", name); + return ret; +} + +int pem_read(FILE *fp, const char *name, uint8_t *data, size_t *datalen) +{ + char line[80]; + char begin_line[80]; + char end_line[80]; + int len; + BASE64_CTX ctx; + + snprintf(begin_line, sizeof(begin_line), "-----BEGIN %s-----\n", name); + snprintf(end_line, sizeof(end_line), "-----END %s-----\n", name); + + if (!fgets(line, sizeof(line), fp)) { + //FIXME: feof 判断是不是文件结束了呢 + return 0; + } + + if (strcmp(line, begin_line) != 0) { + // FIXME: 这里是不是应该容忍一些错误呢? + error_print(); + return -1; + } + + *datalen = 0; + + base64_decode_init(&ctx); + + for (;;) { + if (!fgets(line, sizeof(line), fp)) { + error_print(); + return -1; + } + if (strcmp(line, end_line) == 0) { + break; + } + + base64_decode_update(&ctx, (uint8_t *)line, strlen(line), data, &len); + data += len; + *datalen += len; + } + + base64_decode_finish(&ctx, data, &len); + *datalen += len; + return 1; +} diff --git a/src/pkcs8.c b/src/pkcs8.c new file mode 100644 index 00000000..cfa732f6 --- /dev/null +++ b/src/pkcs8.c @@ -0,0 +1,588 @@ +/* + * Copyright (c) 2021 - 2021 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* +PBKDF2-params ::= SEQUENCE { + salt OCTET STRING, + iterationCount INTEGER (1..MAX), + keyLength INTEGER (1..MAX) OPTIONAL, + prf AlgorithmIdentifier DEFAULT algid-hmacWithSHA1 +} + +这里prf的OID一般来说其他地方是用不到的,并且除了sm3-hmac之外,我们都不支持 + +*/ + +int pbkdf2_params_to_der( + const uint8_t *salt, size_t saltlen, + int iter, + int keylen, + int prf, + uint8_t **out, size_t *outlen) +{ + size_t len = 0; + size_t prflen = 0; + + switch (prf) { + case OID_hmac_sm3: + break; + /* + case OID_hmacWithSHA1: + case OID_hmacWithSHA224: + case OID_hmacWithSHA256: + case OID_hmacWithSHA384: + case OID_hmacWithSHA512: + case OID_hmacWithSHA512_224: + case OID_hmacWithSHA512_256: + error_print(); + return -1; + */ + default: + error_print(); + return -1; + } + + if (asn1_octet_string_to_der(salt, saltlen, NULL, &len) != 1 + || asn1_int_to_der(iter, NULL, &len) != 1 + || asn1_int_to_der(keylen, NULL, &len) < 0 + || asn1_object_identifier_to_der(prf, NULL, 0, NULL, &prflen) != 1 + || asn1_null_to_der(NULL, &prflen) != 1 + || asn1_sequence_to_der(NULL, prflen, NULL, &len) != 1 + || asn1_sequence_header_to_der(len, out, outlen) != 1 + || asn1_octet_string_to_der(salt, saltlen, out, outlen) != 1 + || asn1_int_to_der(iter, out, outlen) != 1 + || asn1_int_to_der(keylen, out, outlen) < 0 + || asn1_sequence_header_to_der(prflen, out, outlen) != 1 + || asn1_object_identifier_to_der(prf, NULL, 0, out, outlen) != 1 + || asn1_null_to_der(out, outlen) != 1) { + error_print(); + return -1; + } + return 1; +} + +int pbkdf2_params_from_der( + const uint8_t **salt, size_t *saltlen, + int *iter, + int *keylen, + int *prf, + const uint8_t **in, size_t *inlen) +{ + int ret; + const uint8_t *data; + const uint8_t *algo; + size_t datalen; + size_t algolen; + + if ((ret = asn1_sequence_from_der(&data, &datalen, in, inlen)) != 1) { + if (ret < 0) error_print(); + return ret; + } + if (asn1_octet_string_from_der(salt, saltlen, &data, &datalen) != 1 + || asn1_int_from_der(iter, &data, &datalen) != 1 + || asn1_int_from_der(keylen, &data, &datalen) < 0 + || asn1_sequence_from_der(&algo, &algolen, &data, &datalen) < 0 + || datalen > 0) { + error_print(); + return -1; + } + if (*saltlen < 1) { + error_print(); + return -1; + } + if (*iter < 1) { + error_print(); + return -1; + } + if (algo) { + uint32_t nodes[32]; + size_t nodes_count; + if (asn1_object_identifier_from_der(prf, nodes, &nodes_count, &algo, &algolen) != 1 + || asn1_null_from_der(&algo, &algolen) != 1 + || algolen > 0) { + error_print(); + return -1; + } + if (*prf != OID_hmac_sm3) { + error_print(); + return -1; + } + } else { + //*prf = OID_hmacWithSHA1; + error_print(); + return -1; + } + + return 1; +} + +int pbkdf2_algor_to_der( + const uint8_t *salt, size_t saltlen, + int iter, + int keylen, + int prf, + uint8_t **out, size_t *outlen) +{ + size_t len = 0; + uint32_t pbkdf2[] = { 1, 2, 840, 113549, 1, 5, 12 }; + size_t pbkdf2_count = sizeof(pbkdf2)/sizeof(pbkdf2[0]); + + if (asn1_object_identifier_to_der(OID_undef, pbkdf2, pbkdf2_count, NULL, &len) != 1 + || pbkdf2_params_to_der(salt, saltlen, iter, keylen, prf, NULL, &len) != 1 + || asn1_sequence_header_to_der(len, out, outlen) != 1 + || asn1_object_identifier_to_der(OID_undef, pbkdf2, pbkdf2_count, out, outlen) != 1 + || pbkdf2_params_to_der(salt, saltlen, iter, keylen, prf, out, outlen) != 1) { + error_print(); + return -1; + } + return 1; +} + +int pbkdf2_algor_from_der( + const uint8_t **salt, size_t *saltlen, + int *iter, + int *keylen, + int *prf, + const uint8_t **in, size_t *inlen) +{ + int ret; + const uint8_t *data; + size_t datalen; + uint32_t pbkdf2[] = { 1, 2, 840, 113549, 1, 5, 12 }; + size_t pbkdf2_count = sizeof(pbkdf2)/sizeof(pbkdf2[0]); + int oid; + uint32_t nodes[32]; + size_t nodes_count; + + if ((ret = asn1_sequence_from_der(&data, &datalen, in, inlen)) != 1) { + if (ret < 0) error_print(); + return ret; + } + if (asn1_object_identifier_from_der(&oid, nodes, &nodes_count, &data, &datalen) != 1 + || pbkdf2_params_from_der(salt, saltlen, iter, keylen, prf, &data, &datalen) != 1 + || datalen > 0) { + error_print(); + return -1; + } + if (oid != OID_undef || nodes_count != pbkdf2_count + || memcmp(nodes, pbkdf2, sizeof(pbkdf2)) != 0) { + error_print(); + return -1; + } + + // FIXME: 检查keylen + return 1; +} + +static uint32_t sm4_cbc_nodes[] = { 1, 2, 156, 10197, 1, 104, 2 }; +static size_t sm4_cbc_nodes_count = sizeof(sm4_cbc_nodes)/sizeof(sm4_cbc_nodes[0]); + + +// 这个应该提取到外面,和digest_algor, encryption_algor, sign_algor 之类的放到一起 +int pbes2_enc_algor_to_der(int cipher, const uint8_t *iv, size_t ivlen, uint8_t **out, size_t *outlen) +{ + size_t len = 0; + + if (cipher != OID_sm4_cbc || ivlen != 16) { + error_print(); + return -1; + } + if (asn1_object_identifier_to_der(OID_undef, sm4_cbc_nodes, sm4_cbc_nodes_count, NULL, &len) != 1 + || asn1_octet_string_to_der(iv, ivlen, NULL, &len) != 1 + || asn1_sequence_header_to_der(len, out, outlen) != 1 + || asn1_object_identifier_to_der(OID_undef, sm4_cbc_nodes, sm4_cbc_nodes_count, out, outlen) != 1 + || asn1_octet_string_to_der(iv, ivlen, out, outlen) != 1) { + error_print(); + return -1; + } + return 1; +} + +int pbes2_enc_algor_from_der(int *cipher, const uint8_t **iv, size_t *ivlen, const uint8_t **in, size_t *inlen) +{ + int ret; + const uint8_t *data; + size_t datalen; + uint32_t nodes[32]; + size_t nodes_count; + + if ((ret = asn1_sequence_from_der(&data, &datalen, in, inlen)) != 1) { + if (ret < 0) error_print(); + return ret; + } + if (asn1_object_identifier_from_der(cipher, nodes, &nodes_count, &data, &datalen) != 1 + || asn1_octet_string_from_der(iv, ivlen, &data, &datalen) != 1 + || datalen > 0) { + error_print(); + return -1; + } + if (*cipher == OID_undef) { + if (nodes_count == sm4_cbc_nodes_count + && memcmp(nodes, sm4_cbc_nodes, sizeof(sm4_cbc_nodes)) == 0) { + *cipher = OID_sm4_cbc; + } else { + size_t i; + error_print("unknown cipher oid :"); + for (i = 0; i < nodes_count; i++) { + fprintf(stderr, " %d", nodes[i]); + } + fprintf(stderr, "\n"); + return -1; + } + } + + // FIXME: 检查ivlen + return 1; +} + +int pbes2_params_to_der( + const uint8_t *salt, size_t saltlen, + int iter, + int prf, + int cipher, + const uint8_t *iv, size_t ivlen, + uint8_t **out, size_t *outlen) +{ + size_t len = 0; + int keylen = -1; + + if (pbkdf2_algor_to_der(salt, saltlen, iter, keylen, prf, NULL, &len) != 1 + || pbes2_enc_algor_to_der(cipher, iv, ivlen, NULL, &len) != 1 + || asn1_sequence_header_to_der(len, out, outlen) != 1 + || pbkdf2_algor_to_der(salt, saltlen, iter, keylen, prf, out, outlen) != 1 + || pbes2_enc_algor_to_der(cipher, iv, ivlen, out, outlen) != 1) { + error_print(); + return -1; + } + return 1; +} + +int pbes2_params_from_der( + const uint8_t **salt, size_t *saltlen, + int *iter, + int *prf, + int *cipher, + const uint8_t **iv, size_t *ivlen, + const uint8_t **in, size_t *inlen) +{ + int ret; + const uint8_t *data; + size_t datalen; + int keylen; + + if ((ret = asn1_sequence_from_der(&data, &datalen, in, inlen)) != 1) { + if (ret < 0) error_print(); + return ret; + } + if (pbkdf2_algor_from_der(salt, saltlen, iter, &keylen, prf, &data, &datalen) != 1 + || pbes2_enc_algor_from_der(cipher, iv, ivlen, &data, &datalen) != 1 + || datalen > 0) { + error_print(); + return -1; + } + if (keylen >= 0 && keylen != 16) { + error_print("keylen = %d\n", keylen); + return -1; + } + return 1; +} + +int pbes2_algor_to_der( + const uint8_t *salt, size_t saltlen, + int iter, + int prf, + int cipher, + const uint8_t *iv, size_t ivlen, + uint8_t **out, size_t *outlen) +{ + size_t len = 0; + uint32_t pbes2[] = { 1, 2, 840, 113549, 1, 5, 13 }; + size_t pbes2_count = sizeof(pbes2)/sizeof(pbes2[0]); + + if (asn1_object_identifier_to_der(OID_undef, pbes2, pbes2_count, NULL, &len) != 1 + || pbes2_params_to_der(salt, saltlen, iter, prf, cipher, iv, ivlen, NULL, &len) != 1 + || asn1_sequence_header_to_der(len, out, outlen) != 1 + || asn1_object_identifier_to_der(OID_undef, pbes2, pbes2_count, out, outlen) != 1 + || pbes2_params_to_der(salt, saltlen, iter, prf, cipher, iv, ivlen, out, outlen) != 1) { + error_print(); + return -1; + } + return 1; +} + +int pbes2_algor_from_der( + const uint8_t **salt, size_t *saltlen, + int *iter, + int *prf, + int *cipher, + const uint8_t **iv, size_t *ivlen, + const uint8_t **in, size_t *inlen) +{ + int ret; + const uint8_t *data; + size_t datalen; + uint32_t pbes2[] = { 1, 2, 840, 113549, 1, 5, 13 }; + size_t pbes2_count = sizeof(pbes2)/sizeof(pbes2[0]); + int oid; + uint32_t nodes[32]; + size_t nodes_count; + + if ((ret = asn1_sequence_from_der(&data, &datalen, in, inlen)) != 1) { + if (ret < 0) error_print(); + return ret; + } + if (asn1_object_identifier_from_der(&oid, nodes, &nodes_count, &data, &datalen) != 1 + || pbes2_params_from_der(salt, saltlen, iter, prf, cipher, iv, ivlen, &data, &datalen) != 1 + || datalen > 0) { + error_print(); + return -1; + } + if (oid != OID_undef) { + error_print(); + return -1; + } + if (nodes_count != pbes2_count && memcmp(nodes, pbes2, sizeof(pbes2)) != 0) { + error_print(); + return -1; + } + return 1; +} + +int pkcs8_enced_private_key_info_to_der( + const uint8_t *salt, size_t saltlen, + int iter, + int prf, + int cipher, + const uint8_t *iv, size_t ivlen, + const uint8_t *enced, size_t encedlen, + uint8_t **out, size_t *outlen) +{ + size_t len = 0; + pbes2_algor_to_der(salt, saltlen, iter, prf, cipher, iv, ivlen, NULL, &len); + asn1_octet_string_to_der(enced, encedlen, NULL, &len); + asn1_sequence_header_to_der(len, out, outlen); + pbes2_algor_to_der(salt, saltlen, iter, prf, cipher, iv, ivlen, out, outlen); + asn1_octet_string_to_der(enced, encedlen, out, outlen); + return 1; +} + +int pkcs8_enced_private_key_info_from_der( + const uint8_t **salt, size_t *saltlen, + int *iter, + int *prf, + int *cipher, + const uint8_t **iv, size_t *ivlen, + const uint8_t **enced, size_t *encedlen, + const uint8_t **in, size_t *inlen) +{ + int ret; + const uint8_t *data; + size_t datalen; + const uint8_t *algid; + size_t algidlen; + uint32_t nodes[32]; + size_t nodes_count; + + if ((ret = asn1_sequence_from_der(&data, &datalen, in, inlen)) != 1) { + if (ret < 0) error_print(); + return ret; + } + if (pbes2_algor_from_der(salt, saltlen, iter, prf, cipher, iv, ivlen, &data, &datalen) != 1 + || asn1_octet_string_from_der(enced, encedlen, &data, &datalen) != 1 + || datalen > 0) { + error_print(); + return -1; + } + return 1; +} + +// output PKCS #8 EncryptedPrivateKeyInfo + +int sm2_enced_private_key_info_to_der(const SM2_KEY *sm2, const char *pass, uint8_t **out, size_t *outlen) +{ + SM4_KEY sm4_key; + uint8_t salt[16]; + int iter = 65536; + int prf = OID_hmac_sm3; + uint8_t key[16]; + int cipher = OID_sm4_cbc; + uint8_t iv[16]; + uint8_t info[256]; + uint8_t *pinfo = info; + size_t infolen = 0; + uint8_t enced[512]; + size_t encedlen; + + if (rand_bytes(salt, sizeof(salt)) != 1 + || rand_bytes(iv, sizeof(iv)) != 1) { + error_print(); + return -1; + } + + // SM2_KEY to PKCS8 PrivateKeyInfo + if (sm2_private_key_info_to_der(sm2, &pinfo, &infolen) != 1) { + error_print(); + return -1; + } + + // password to encryption key + if (pbkdf2_genkey(DIGEST_sm3(), pass, strlen(pass), salt, sizeof(salt), iter, sizeof(key), key) != 1) { + error_print(); + return -1; + } + + // encrypt PrivateKeyInfo + sm4_set_encrypt_key(&sm4_key, key); + if (sm4_cbc_padding_encrypt(&sm4_key, iv, info, infolen, enced, &encedlen) != 1) { + error_print(); + return -1; + } + + // encode EncryptedPrivateKeyInfo + if (pkcs8_enced_private_key_info_to_der(salt, sizeof(salt), iter, prf, + cipher, iv, sizeof(iv), enced, encedlen, out, outlen) != 1) { + error_print(); + return -1; + } + return 1; +} + +int sm2_enced_private_key_info_from_der(SM2_KEY *sm2, const uint8_t **attrs, size_t *attrslen, const char *pass, const uint8_t **in, size_t *inlen) +{ + SM4_KEY sm4_key; + const uint8_t *salt; + size_t saltlen; + int iter; + int prf; + int cipher; + const uint8_t *iv; + size_t ivlen; + const uint8_t *enced; + size_t encedlen; + uint8_t key[16]; + uint8_t info[256]; + const uint8_t *pinfo = info; + size_t infolen; + + if (pkcs8_enced_private_key_info_from_der(&salt, &saltlen, &iter, &prf, + &cipher, &iv, &ivlen, &enced, &encedlen, in, inlen) != 1) { + error_print(); + return -1; + } + + if (pbkdf2_genkey(DIGEST_sm3(), pass, strlen(pass), salt, saltlen, iter, sizeof(key), key) != 1) { + error_print(); + return -1; + } + + sm4_set_decrypt_key(&sm4_key, key); + if (sm4_cbc_padding_decrypt(&sm4_key, iv, enced, encedlen, info, &infolen) != 1) { + error_print(); + return -1; + } + if (sm2_private_key_info_from_der(sm2, attrs, attrslen, &pinfo, &infolen) != 1 + || infolen > 0) { + error_print(); + return -1; + } + + return 1; +} + +int sm2_enced_private_key_info_to_pem(const SM2_KEY *key, const char *pass, FILE *fp) +{ + uint8_t buf[1024]; + uint8_t *p = buf; + size_t len = 0; + + if (sm2_enced_private_key_info_to_der(key, pass, &p, &len) != 1) { + error_print(); + return -1; + } + if (pem_write(fp, "ENCRYPTED PRIVATE KEY", buf, len) <= 0) { + error_print(); + return -1; + } + return 1; +} + +// TODO: return attributes +int sm2_enced_private_key_info_from_pem(SM2_KEY *key, const char *pass, FILE *fp) +{ + uint8_t buf[512]; + const uint8_t *cp = buf; + size_t len; + const uint8_t *attrs; + size_t attrslen; + + if (pem_read(fp, "ENCRYPTED PRIVATE KEY", buf, &len) != 1) { + error_print(); + return -1; + } + + if (sm2_enced_private_key_info_from_der(key, &attrs, &attrslen, pass, &cp, &len) != 1 + || len > 0) { + error_print(); + return -1; + } + return 1; +} + diff --git a/src/rand.c b/src/rand.c new file mode 100644 index 00000000..0e5d5525 --- /dev/null +++ b/src/rand.c @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2014 - 2021 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + + +#include +#include +#include +#include +#include + +int rand_bytes(uint8_t *buf, size_t len) +{ + FILE *fp; + if (!(fp = fopen("/dev/urandom", "rb"))) { + error_print(); + return -1; + } + fread(buf, 1, len, fp); + return 1; +} diff --git a/src/rc4.c b/src/rc4.c new file mode 100644 index 00000000..1d647ab1 --- /dev/null +++ b/src/rc4.c @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2014 - 2020 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + +#include +#include +#include +#include + +void rc4_set_key(RC4_STATE *state, const unsigned char *key, size_t keylen) +{ + int i, j; + unsigned char *s = state->d; + unsigned char k[256]; + unsigned char temp; + + /* expand key */ + for (i = 0; i < keylen; i++) { + k[i] = key[i]; + } + for (i = keylen; i < 256; i++) { + k[i] = key[i % keylen]; + } + + /* init state */ + for (i = 0; i < 256; i++) { + s[i] = i; + } + + /* shuffle state with key */ + j = 0; + for (i = 0; i < 256; i++) { + j = (j + s[i] + k[i]) % 256; + + /* swap(s[i], s[j]) */ + temp = s[j]; + s[j] = s[i]; + s[i] = temp; + } + + /* clean expanded temp key */ + memset(k, 0, sizeof(k)); +} + +void rc4_generate_keystream(RC4_STATE *state, size_t outlen, unsigned char *out) +{ + int i = 0, j = 0; + unsigned char *s = state->d; + int oi; + int temp; + + while (outlen > 0) { + i = (i + 1) % 256; + j = (j + s[i]) % 256; + + /* swap(s[i], s[j]) */ + temp = s[j]; + s[j] = s[i]; + s[i] = temp; + + oi = (s[i] + s[j]) % 256; + *out++ = s[oi]; + + outlen--; + } +} + +unsigned char rc4_generate_keybyte(RC4_STATE *state) +{ + unsigned char out[1]; + rc4_generate_keystream(state, 1, out); + return out[0]; +} diff --git a/src/rotate.h b/src/rotate.h new file mode 100644 index 00000000..8f029366 --- /dev/null +++ b/src/rotate.h @@ -0,0 +1,68 @@ +/* + * Copyright 1999-2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * 应该看看Intel Intrisics中是否支持这个指令,以及VS是否也支持这个指令 + * 这样我们就不需要内联汇编了 + */ + +/* + * Engage compiler specific rotate intrinsic function if available. + */ +#undef ROL32 +#ifndef PEDANTIC +# if defined(_MSC_VER) +# define ROL32(a,n) _lrotl(a,n) +# elif defined(__ICC) +# define ROL32(a,n) _rotl(a,n) +# elif defined(__GNUC__) && __GNUC__>=2 && !defined(OPENSSL_NO_ASM) && !defined(OPENSSL_NO_INLINE_ASM) + /* + * Some GNU C inline assembler templates. Note that these are + * rotates by *constant* number of bits! But that's exactly + * what we need here... + * + */ +# if defined(__i386) || defined(__i386__) || defined(__x86_64) || defined(__x86_64__) +# define ROL32(a,n) ({ register unsigned int ret; \ + asm ( \ + "roll %1,%0" \ + : "=r"(ret) \ + : "I"(n), "0"((unsigned int)(a)) \ + : "cc"); \ + ret; \ + }) +# elif defined(_ARCH_PPC) || defined(_ARCH_PPC64) || \ + defined(__powerpc) || defined(__ppc__) || defined(__powerpc64__) +# define ROL32(a,n) ({ register unsigned int ret; \ + asm ( \ + "rlwinm %0,%1,%2,0,31" \ + : "=r"(ret) \ + : "r"(a), "I"(n)); \ + ret; \ + }) +# elif defined(__s390x__) +# define ROL32(a,n) ({ register unsigned int ret; \ + asm ("rll %0,%1,%2" \ + : "=r"(ret) \ + : "r"(a), "I"(n)); \ + ret; \ + }) +# endif +# endif +#endif /* PEDANTIC */ + +#ifndef ROL32 +# define ROL32(a,n) (((a)<<(n))|(((a)&0xffffffff)>>(32-(n)))) +#endif + +#define ROR32(a,n) ROL32((a),32-(n)) +#define ROL64(a,n) (((a)<<(n))|((a)>>(64-(n)))) +#define ROR64(a,n) ROL64(a,64-n) + + diff --git a/src/sha1.c b/src/sha1.c new file mode 100755 index 00000000..ec2dcc3b --- /dev/null +++ b/src/sha1.c @@ -0,0 +1,219 @@ +/* ==================================================================== + * Copyright (c) 2014 - 2017 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + * ==================================================================== + */ + +#include +#include +#include "bswap.h" +#include "rotate.h" + + +static void sha1_compress_blocks(uint32_t dgst[5], + const unsigned char *data, size_t blocks); + + +void sha1_init(SHA1_CTX *ctx) +{ + memset(ctx, 0, sizeof(*ctx)); + ctx->state[0] = 0x67452301; + ctx->state[1] = 0xEFCDAB89; + ctx->state[2] = 0x98BADCFE; + ctx->state[3] = 0x10325476; + ctx->state[4] = 0xC3D2E1F0; +} + +void sha1_update(SHA1_CTX *ctx, const unsigned char *data, size_t datalen) +{ + size_t blocks; + + if (ctx->num) { + unsigned int left = SHA1_BLOCK_SIZE - ctx->num; + if (datalen < left) { + memcpy(ctx->block + ctx->num, data, datalen); + ctx->num += datalen; + return; + } else { + memcpy(ctx->block + ctx->num, data, left); + sha1_compress_blocks(ctx->state, ctx->block, 1); + ctx->nblocks++; + data += left; + datalen -= left; + } + } + + blocks = datalen / SHA1_BLOCK_SIZE; + sha1_compress_blocks(ctx->state, data, blocks); + ctx->nblocks += blocks; + data += SHA1_BLOCK_SIZE * blocks; + datalen -= SHA1_BLOCK_SIZE * blocks; + + ctx->num = datalen; + if (datalen) { + memcpy(ctx->block, data, datalen); + } +} + +void sha1_finish(SHA1_CTX *ctx, unsigned char *dgst) +{ + int i; + + ctx->block[ctx->num] = 0x80; + + if (ctx->num + 9 <= SHA1_BLOCK_SIZE) { + memset(ctx->block + ctx->num + 1, 0, SHA1_BLOCK_SIZE - ctx->num - 9); + } else { + memset(ctx->block + ctx->num + 1, 0, SHA1_BLOCK_SIZE - ctx->num - 1); + sha1_compress_blocks(ctx->state, ctx->block, 1); + memset(ctx->block, 0, SHA1_BLOCK_SIZE - 8); + } + PUTU32(ctx->block + 56, ctx->nblocks >> 23); + PUTU32(ctx->block + 60, (ctx->nblocks << 9) + (ctx->num << 3)); + + sha1_compress_blocks(ctx->state, ctx->block, 1); + for (i = 0; i < 5; i++) { + PUTU32(dgst + i*4, ctx->state[i]); + } +} + +#define F0(B, C, D) (((B) & (C)) | ((~(B)) & (D))) +#define F1(B, C, D) ((B) ^ (C) ^ (D)) +#define F2(B, C, D) (((B) & (C)) | ((B) & (D)) | ((C) & (D))) +#define F3(B, C, D) ((B) ^ (C) ^ (D)) + +#define K0 0x5A827999 +#define K1 0x6ED9EBA1 +#define K2 0x8F1BBCDC +#define K3 0xCA62C1D6 + +static void sha1_compress_blocks(uint32_t state[5], + const unsigned char *data, size_t blocks) +{ + uint32_t A; + uint32_t B; + uint32_t C; + uint32_t D; + uint32_t E; + uint32_t T; + uint32_t W[80]; + int i; + + while (blocks--) { + + A = state[0]; + B = state[1]; + C = state[2]; + D = state[3]; + E = state[4]; + + for (i = 0; i < 16; i++) { + W[i] = GETU32(data); + data += 4; + } + for (; i < 80; i++) { + W[i] = ROL32(W[i-3] ^ W[i-8] ^ W[i-14] ^ W[i-16], 1); + } + + + /* see https://en.wikipedia.org/wiki/SHA-1#/media/File:SHA-1.svg */ + for (i = 0; i < 20; i++) { + T = E + F0(B, C, D) + ROL32(A, 5) + W[i] + K0; + E = D; + D = C; + C = ROL32(B, 30); + B = A; + A = T; + } + for (; i < 40; i++) { + T = E + F1(B, C, D) + ROL32(A, 5) + W[i] + K1; + E = D; + D = C; + C = ROL32(B, 30); + B = A; + A = T; + } + for (; i < 60; i++) { + T = E + F2(B, C, D) + ROL32(A, 5) + W[i] + K2; + E = D; + D = C; + C = ROL32(B, 30); + B = A; + A = T; + } + for (; i < 80; i++) { + T = E + F3(B, C, D) + ROL32(A, 5) + W[i] + K3; + E = D; + D = C; + C = ROL32(B, 30); + B = A; + A = T; + } + + state[0] += A; + state[1] += B; + state[2] += C; + state[3] += D; + state[4] += E; + } +} + +void sha1_compress(uint32_t state[5], const unsigned char block[64]) +{ + return sha1_compress_blocks(state, block, 1); +} + +void sha1_digest(const unsigned char *data, size_t datalen, + unsigned char dgst[SHA1_DIGEST_LENGTH]) +{ + SHA1_CTX ctx; + + sha1_init(&ctx); + sha1_update(&ctx, data, datalen); + sha1_finish(&ctx, dgst); + + memset(&ctx, 0, sizeof(SHA1_CTX)); +} diff --git a/src/sha256.c b/src/sha256.c new file mode 100755 index 00000000..ca2e1e31 --- /dev/null +++ b/src/sha256.c @@ -0,0 +1,265 @@ +/* ==================================================================== + * Copyright (c) 2014 - 2017 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE GmSSL 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. + * ==================================================================== + */ + +#include +#include +#include +#include +#include "bswap.h" +#include "rotate.h" + +static void sha256_compress_blocks(uint32_t state[8], + const unsigned char *data, size_t blocks); + +void sha256_init(SHA256_CTX *ctx) +{ + memset(ctx, 0, sizeof(*ctx)); + ctx->state[0] = 0x6a09e667; + ctx->state[1] = 0xbb67ae85; + ctx->state[2] = 0x3c6ef372; + ctx->state[3] = 0xa54ff53a; + ctx->state[4] = 0x510e527f; + ctx->state[5] = 0x9b05688c; + ctx->state[6] = 0x1f83d9ab; + ctx->state[7] = 0x5be0cd19; +} + +void sha256_update(SHA256_CTX *ctx, const unsigned char *data, size_t datalen) +{ + size_t blocks; + + if (ctx->num) { + unsigned int left = SHA256_BLOCK_SIZE - ctx->num; + if (datalen < left) { + memcpy(ctx->block + ctx->num, data, datalen); + ctx->num += datalen; + return; + } else { + memcpy(ctx->block + ctx->num, data, left); + sha256_compress_blocks(ctx->state, ctx->block, 1); + ctx->nblocks++; + data += left; + datalen -= left; + } + } + + blocks = datalen / SHA256_BLOCK_SIZE; + sha256_compress_blocks(ctx->state, data, blocks); + ctx->nblocks += blocks; + data += SHA256_BLOCK_SIZE * blocks; + datalen -= SHA256_BLOCK_SIZE * blocks; + + ctx->num = datalen; + if (datalen) { + memcpy(ctx->block, data, datalen); + } +} + +void sha256_finish(SHA256_CTX *ctx, unsigned char dgst[SHA256_DIGEST_SIZE]) +{ + int i; + + ctx->block[ctx->num] = 0x80; + + if (ctx->num + 9 <= SHA256_BLOCK_SIZE) { + memset(ctx->block + ctx->num + 1, 0, SHA256_BLOCK_SIZE - ctx->num - 9); + } else { + memset(ctx->block + ctx->num + 1, 0, SHA256_BLOCK_SIZE - ctx->num - 1); + sha256_compress_blocks(ctx->state, ctx->block, 1); + memset(ctx->block, 0, SHA256_BLOCK_SIZE - 8); + } + PUTU32(ctx->block + 56, ctx->nblocks >> 23); + PUTU32(ctx->block + 60, (ctx->nblocks << 9) + (ctx->num << 3)); + + sha256_compress_blocks(ctx->state, ctx->block, 1); + for (i = 0; i < 8; i++) { + PUTU32(dgst, ctx->state[i]); + dgst += sizeof(uint32_t); + } + memset(ctx, 0, sizeof(SHA256_CTX)); +} + +#define Ch(X, Y, Z) (((X) & (Y)) ^ ((~(X)) & (Z))) +#define Maj(X, Y, Z) (((X) & (Y)) ^ ((X) & (Z)) ^ ((Y) & (Z))) +#define Sigma0(X) (ROR32((X), 2) ^ ROR32((X), 13) ^ ROR32((X), 22)) +#define Sigma1(X) (ROR32((X), 6) ^ ROR32((X), 11) ^ ROR32((X), 25)) +#define sigma0(X) (ROR32((X), 7) ^ ROR32((X), 18) ^ ((X) >> 3)) +#define sigma1(X) (ROR32((X), 17) ^ ROR32((X), 19) ^ ((X) >> 10)) + +static const uint32_t K[64] = { + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, + 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, + 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, + 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, + 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, + 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, + 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, + 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, + 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2, +}; + +static void sha256_compress_blocks(uint32_t state[8], + const unsigned char *data, size_t blocks) +{ + uint32_t A; + uint32_t B; + uint32_t C; + uint32_t D; + uint32_t E; + uint32_t F; + uint32_t G; + uint32_t H; + uint32_t W[64]; + uint32_t T1, T2; + int i; + + while (blocks--) { + + A = state[0]; + B = state[1]; + C = state[2]; + D = state[3]; + E = state[4]; + F = state[5]; + G = state[6]; + H = state[7]; + + for (i = 0; i < 16; i++) { + W[i] = GETU32(data); + data += 4; + } + for (; i < 64; i++) { + W[i] = sigma1(W[i-2]) + W[i-7] + sigma0(W[i-15]) + W[i-16]; + } + + for (i = 0; i < 64; i++) { + T1 = H + Sigma1(E) + Ch(E, F, G) + K[i] + W[i]; + T2 = Sigma0(A) + Maj(A, B, C); + H = G; + G = F; + F = E; + E = D + T1; + D = C; + C = B; + B = A; + A = T1 + T2; + } + + state[0] += A; + state[1] += B; + state[2] += C; + state[3] += D; + state[4] += E; + state[5] += F; + state[6] += G; + state[7] += H; + } +} + +void sha256_compress(uint32_t state[8], const unsigned char block[64]) +{ + sha256_compress_blocks(state, block, 1); +} + +void sha256_digest(const unsigned char *data, size_t datalen, + unsigned char dgst[SHA256_DIGEST_SIZE]) +{ + SHA256_CTX ctx; + sha256_init(&ctx); + sha256_update(&ctx, data, datalen); + sha256_finish(&ctx, dgst); +} + + +void sha224_init(SHA224_CTX *ctx) +{ + memset(ctx, 0, sizeof(*ctx)); + ctx->state[0] = 0xc1059ed8; + ctx->state[1] = 0x367cd507; + ctx->state[2] = 0x3070dd17; + ctx->state[3] = 0xf70e5939; + ctx->state[4] = 0xffc00b31; + ctx->state[5] = 0x68581511; + ctx->state[6] = 0x64f98fa7; + ctx->state[7] = 0xbefa4fa4; +} + +void sha224_update(SHA224_CTX *ctx, const unsigned char *data, size_t datalen) +{ + sha256_update((SHA256_CTX *)ctx, data, datalen); +} + +void sha224_finish(SHA224_CTX *ctx, unsigned char dgst[SHA224_DIGEST_SIZE]) +{ + unsigned char buf[SHA256_DIGEST_SIZE]; + sha256_finish((SHA256_CTX *)ctx, buf); + memcpy(dgst, buf, SHA224_DIGEST_SIZE); + memset(buf, 0, sizeof(buf)); +} + +void sha224_compress(uint32_t state[8], const unsigned char block[64]) +{ + sha256_compress_blocks(state, block, 1); +} + +void sha224_digest(const unsigned char *data, size_t datalen, + unsigned char dgst[SHA224_DIGEST_SIZE]) +{ + SHA224_CTX ctx; + sha224_init(&ctx); + sha224_update(&ctx, data, datalen); + sha224_finish(&ctx, dgst); +} diff --git a/src/sha512.c b/src/sha512.c new file mode 100755 index 00000000..84d4c523 --- /dev/null +++ b/src/sha512.c @@ -0,0 +1,271 @@ +/* ==================================================================== + * Copyright (c) 2014 - 2017 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE GmSSL 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. + * ==================================================================== + */ + +#include +#include +#include +#include +#include "bswap.h" +#include "rotate.h" + + +static void sha512_compress_blocks(uint64_t state[8], + const unsigned char *data, size_t blocks); + +void sha512_init(SHA512_CTX *ctx) +{ + memset(ctx, 0, sizeof(*ctx)); + ctx->state[0] = 0x6a09e667f3bcc908; + ctx->state[1] = 0xbb67ae8584caa73b; + ctx->state[2] = 0x3c6ef372fe94f82b; + ctx->state[3] = 0xa54ff53a5f1d36f1; + ctx->state[4] = 0x510e527fade682d1; + ctx->state[5] = 0x9b05688c2b3e6c1f; + ctx->state[6] = 0x1f83d9abfb41bd6b; + ctx->state[7] = 0x5be0cd19137e2179; +} + +void sha512_update(SHA512_CTX *ctx, const unsigned char *data, size_t datalen) +{ + size_t blocks; + + if (ctx->num) { + unsigned int left = SHA512_BLOCK_SIZE - ctx->num; + if (datalen < left) { + memcpy(ctx->block + ctx->num, data, datalen); + ctx->num += datalen; + return; + } else { + memcpy(ctx->block + ctx->num, data, left); + sha512_compress_blocks(ctx->state, ctx->block, 1); + ctx->nblocks++; + data += left; + datalen -= left; + } + } + + blocks = datalen / SHA512_BLOCK_SIZE; + sha512_compress_blocks(ctx->state, data, blocks); + ctx->nblocks += blocks; + data += SHA512_BLOCK_SIZE * blocks; + datalen -= SHA512_BLOCK_SIZE * blocks; + + ctx->num = datalen; + if (datalen) { + memcpy(ctx->block, data, datalen); + } +} + +void sha512_finish(SHA512_CTX *ctx, unsigned char dgst[SHA512_DIGEST_SIZE]) +{ + int i; + + ctx->block[ctx->num] = 0x80; + + if (ctx->num + 17 <= SHA512_BLOCK_SIZE) { + memset(ctx->block + ctx->num + 1, 0, SHA512_BLOCK_SIZE - ctx->num - 17); + } else { + memset(ctx->block + ctx->num + 1, 0, SHA512_BLOCK_SIZE - ctx->num - 1); + sha512_compress_blocks(ctx->state, ctx->block, 1); + memset(ctx->block, 0, SHA512_BLOCK_SIZE - 16); + } + PUTU64(ctx->block + 112, ctx->nblocks >> 54); + PUTU64(ctx->block + 120, (ctx->nblocks << 10) + (ctx->num << 3)); + + sha512_compress_blocks(ctx->state, ctx->block, 1); + for (i = 0; i < 8; i++) { + PUTU64(dgst, ctx->state[i]); + dgst += sizeof(uint64_t); + } + memset(ctx, 0, sizeof(SHA512_CTX)); +} + +#define Ch(X, Y, Z) (((X) & (Y)) ^ ((~(X)) & (Z))) +#define Maj(X, Y, Z) (((X) & (Y)) ^ ((X) & (Z)) ^ ((Y) & (Z))) +#define Sigma0(X) (ROR64((X), 28) ^ ROR64((X), 34) ^ ROR64((X), 39)) +#define Sigma1(X) (ROR64((X), 14) ^ ROR64((X), 18) ^ ROR64((X), 41)) +#define sigma0(X) (ROR64((X), 1) ^ ROR64((X), 8) ^ ((X) >> 7)) +#define sigma1(X) (ROR64((X), 19) ^ ROR64((X), 61) ^ ((X) >> 6)) + +static const uint64_t K[80] = { + 0x428a2f98d728ae22, 0x7137449123ef65cd, 0xb5c0fbcfec4d3b2f, 0xe9b5dba58189dbbc, + 0x3956c25bf348b538, 0x59f111f1b605d019, 0x923f82a4af194f9b, 0xab1c5ed5da6d8118, + 0xd807aa98a3030242, 0x12835b0145706fbe, 0x243185be4ee4b28c, 0x550c7dc3d5ffb4e2, + 0x72be5d74f27b896f, 0x80deb1fe3b1696b1, 0x9bdc06a725c71235, 0xc19bf174cf692694, + 0xe49b69c19ef14ad2, 0xefbe4786384f25e3, 0x0fc19dc68b8cd5b5, 0x240ca1cc77ac9c65, + 0x2de92c6f592b0275, 0x4a7484aa6ea6e483, 0x5cb0a9dcbd41fbd4, 0x76f988da831153b5, + 0x983e5152ee66dfab, 0xa831c66d2db43210, 0xb00327c898fb213f, 0xbf597fc7beef0ee4, + 0xc6e00bf33da88fc2, 0xd5a79147930aa725, 0x06ca6351e003826f, 0x142929670a0e6e70, + 0x27b70a8546d22ffc, 0x2e1b21385c26c926, 0x4d2c6dfc5ac42aed, 0x53380d139d95b3df, + 0x650a73548baf63de, 0x766a0abb3c77b2a8, 0x81c2c92e47edaee6, 0x92722c851482353b, + 0xa2bfe8a14cf10364, 0xa81a664bbc423001, 0xc24b8b70d0f89791, 0xc76c51a30654be30, + 0xd192e819d6ef5218, 0xd69906245565a910, 0xf40e35855771202a, 0x106aa07032bbd1b8, + 0x19a4c116b8d2d0c8, 0x1e376c085141ab53, 0x2748774cdf8eeb99, 0x34b0bcb5e19b48a8, + 0x391c0cb3c5c95a63, 0x4ed8aa4ae3418acb, 0x5b9cca4f7763e373, 0x682e6ff3d6b2b8a3, + 0x748f82ee5defb2fc, 0x78a5636f43172f60, 0x84c87814a1f0ab72, 0x8cc702081a6439ec, + 0x90befffa23631e28, 0xa4506cebde82bde9, 0xbef9a3f7b2c67915, 0xc67178f2e372532b, + 0xca273eceea26619c, 0xd186b8c721c0c207, 0xeada7dd6cde0eb1e, 0xf57d4f7fee6ed178, + 0x06f067aa72176fba, 0x0a637dc5a2c898a6, 0x113f9804bef90dae, 0x1b710b35131c471b, + 0x28db77f523047d84, 0x32caab7b40c72493, 0x3c9ebe0a15c9bebc, 0x431d67c49c100d4c, + 0x4cc5d4becb3e42b6, 0x597f299cfc657e2a, 0x5fcb6fab3ad6faec, 0x6c44198c4a475817, +}; + +static void sha512_compress_blocks(uint64_t state[8], + const unsigned char *data, size_t blocks) +{ + uint64_t A; + uint64_t B; + uint64_t C; + uint64_t D; + uint64_t E; + uint64_t F; + uint64_t G; + uint64_t H; + uint64_t W[80]; + uint64_t T1, T2; + int i; + + while (blocks--) { + + A = state[0]; + B = state[1]; + C = state[2]; + D = state[3]; + E = state[4]; + F = state[5]; + G = state[6]; + H = state[7]; + + for (i = 0; i < 16; i++) { + W[i] = GETU64(data); + data += sizeof(uint64_t); + } + for (; i < 80; i++) { + W[i] = sigma1(W[i-2]) + W[i-7] + sigma0(W[i-15]) + W[i-16]; + } + + for (i = 0; i < 80; i++) { + T1 = H + Sigma1(E) + Ch(E, F, G) + K[i] + W[i]; + T2 = Sigma0(A) + Maj(A, B, C); + H = G; + G = F; + F = E; + E = D + T1; + D = C; + C = B; + B = A; + A = T1 + T2; + } + + state[0] += A; + state[1] += B; + state[2] += C; + state[3] += D; + state[4] += E; + state[5] += F; + state[6] += G; + state[7] += H; + } +} + +void sha512_compress(uint64_t state[8], const unsigned char block[64]) +{ + sha512_compress_blocks(state, block, 1); +} + +void sha512_digest(const unsigned char *data, size_t datalen, + unsigned char dgst[SHA512_DIGEST_SIZE]) +{ + SHA512_CTX ctx; + sha512_init(&ctx); + sha512_update(&ctx, data, datalen); + sha512_finish(&ctx, dgst); +} + + +void sha384_init(SHA384_CTX *ctx) +{ + memset(ctx, 0, sizeof(*ctx)); + ctx->state[0] = 0xcbbb9d5dc1059ed8; + ctx->state[1] = 0x629a292a367cd507; + ctx->state[2] = 0x9159015a3070dd17; + ctx->state[3] = 0x152fecd8f70e5939; + ctx->state[4] = 0x67332667ffc00b31; + ctx->state[5] = 0x8eb44a8768581511; + ctx->state[6] = 0xdb0c2e0d64f98fa7; + ctx->state[7] = 0x47b5481dbefa4fa4; +} + +void sha384_update(SHA384_CTX *ctx, const unsigned char *data, size_t datalen) +{ + sha512_update((SHA512_CTX *)ctx, data, datalen); +} + +void sha384_finish(SHA384_CTX *ctx, unsigned char dgst[SHA384_DIGEST_SIZE]) +{ + unsigned char buf[SHA512_DIGEST_SIZE]; + sha512_finish((SHA512_CTX *)ctx, buf); + memcpy(dgst, buf, SHA384_DIGEST_SIZE); + memset(buf, 0, sizeof(buf)); +} + +void sha384_compress(uint64_t state[8], const unsigned char block[64]) +{ + sha512_compress_blocks(state, block, 1); +} + +void sha384_digest(const unsigned char *data, size_t datalen, + unsigned char dgst[SHA384_DIGEST_SIZE]) +{ + SHA384_CTX ctx; + sha384_init(&ctx); + sha384_update(&ctx, data, datalen); + sha384_finish(&ctx, dgst); +} + diff --git a/src/sm2_algo.c b/src/sm2_algo.c new file mode 100644 index 00000000..ae79cfe2 --- /dev/null +++ b/src/sm2_algo.c @@ -0,0 +1,1665 @@ +/* + * Copyright (c) 2014 - 2020 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + + +#include +#include +#include +#include +#include +#include "endian.h" + + +typedef uint64_t bignum_t[8]; + +typedef struct { + bignum_t X; + bignum_t Y; + bignum_t Z; +} point_t; + + +static const bignum_t SM2_P = { + 0xffffffff, 0xffffffff, 0x00000000, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xfffffffe, +}; + +static const bignum_t SM2_B = { + 0x4d940e93, 0xddbcbd41, 0x15ab8f92, 0xf39789f5, + 0xcf6509a7, 0x4d5a9e4b, 0x9d9f5e34, 0x28e9fa9e, +}; + +static const point_t _SM2_G = { + { + 0x334c74c7, 0x715a4589, 0xf2660be1, 0x8fe30bbf, + 0x6a39c994, 0x5f990446, 0x1f198119, 0x32c4ae2c, + }, + { + 0x2139f0a0, 0x02df32e5, 0xc62a4740, 0xd0a9877c, + 0x6b692153, 0x59bdcee3, 0xf4f6779c, 0xbc3736a2, + }, + { + 1, 0, 0, 0, 0, 0, 0, 0, + }, +}; +static const point_t *SM2_G = &_SM2_G; + +static const bignum_t SM2_N = { + 0x39d54123, 0x53bbf409, 0x21c6052b, 0x7203df6b, + 0xffffffff, 0xffffffff, 0xffffffff, 0xfffffffe, +}; + +// u = (p - 1)/4, u + 1 = (p + 1)/4 +static const bignum_t SM2_U_PLUS_ONE = { + 0x00000000, 0x40000000, 0xc0000000, 0xffffffff, + 0xffffffff, 0xffffffff, 0xbfffffff, 0x3fffffff, +}; + +static const bignum_t ONE = {1,0,0,0,0,0,0,0}; +static const bignum_t TWO = {2,0,0,0,0,0,0,0}; +static const bignum_t THREE = {3,0,0,0,0,0,0,0}; + +#define bn_init(r) memset((r), 0, sizeof(bignum_t)) +#define bn_set_zero(r) memset((r), 0, sizeof(bignum_t)) +#define bn_copy(r, a) memcpy((r), (a), sizeof(bignum_t)) +#define bn_clean(r) memset((r), 0, sizeof(bignum_t)) + +static int bn_check(const bignum_t a) +{ + int err = 0; + int i; + for (i = 0; i < 8; i++) { + if (a[i] > 0xffffffff) { + fprintf(stderr, "%s %d: error\n", __FILE__, __LINE__); + err++; + } + } + if (err) + return -1; + else return 1; +} + +static int bn_is_zero(const bignum_t a) +{ + int i; + for (i = 0; i < 8; i++) { + if (a[i] != 0) + return 0; + } + return 1; +} + +static int bn_is_one(const bignum_t a) +{ + int i; + if (a[0] != 1) + return 0; + for (i = 1; i < 8; i++) { + if (a[i] != 0) + return 0; + } + return 1; +} + +static void bn_to_bytes(const bignum_t a, uint8_t out[32]) +{ + int i; + uint8_t *p = out; + + /* + fprintf(stderr, "bn_to_bytes:\n"); + for (i = 0; i < 8; i++) { + fprintf(stderr, "%016lx ", a[i]); + } + fprintf(stderr, "\n"); + */ + + for (i = 7; i >= 0; i--) { + uint32_t ai = (uint32_t)a[i]; + PUTU32(out, ai); + out += sizeof(uint32_t); + } + + /* + for (i = 0; i < 32; i++) { + fprintf(stderr, "%02X ", p[i]); + } + */ + +} + +static void bn_from_bytes(bignum_t r, const uint8_t in[32]) +{ + int i; + for (i = 7; i >= 0; i--) { + r[i] = GETU32(in); + in += sizeof(uint32_t); + } +} + +static int hexchar2int(char c) +{ + if ('0' <= c && c <= '9') return c - '0'; + else if ('a' <= c && c <= 'f') return c - 'a' + 10; + else if ('A' <= c && c <= 'F') return c - 'A' + 10; + else return -1; +} + +static int hex2bin(const char *in, size_t inlen, uint8_t *out) +{ + int c; + if (inlen % 2) + return -1; + + while (inlen) { + if ((c = hexchar2int(*in++)) < 0) + return -1; + *out = (uint8_t)c << 4; + if ((c = hexchar2int(*in++)) < 0) + return -1; + *out |= (uint8_t)c; + inlen -= 2; + out++; + } + return 1; +} + +static void bn_to_hex(const bignum_t a, char hex[64]) +{ + int i; + for (i = 7; i >= 0; i--) { + int len; + len = sprintf(hex, "%08x", (uint32_t)a[i]); + assert(len == 8); + hex += 8; + } +} + +static int bn_from_hex(bignum_t r, const char hex[64]) +{ + uint8_t buf[32]; + if (hex2bin(hex, 64, buf) < 0) + return -1; + bn_from_bytes(r, buf); + return 1; +} + +static int bn_print(FILE *fp, const bignum_t a, int format, int indent) +{ + int ret = 0, i; + for (i = 7; i >= 0; i--) { + if (a[i] >= ((uint64_t)1 << 32)) { + printf("bn_print check failed\n"); + } + ret += fprintf(fp, "%08llx", a[i]); + } + ret += fprintf(fp, "\n"); + return ret; +} +#define print_bn(a) bn_print(stdout,a,0,0) + +static void bn_to_bits(const bignum_t a, char bits[256]) +{ + int i, j; + for (i = 7; i >= 0; i--) { + uint32_t w = a[i]; + for (j = 0; j < 32; j++) { + *bits++ = (w & 0x80000000) ? '1' : '0'; + w <<= 1; + } + } +} + +static int bn_cmp(const bignum_t a, const bignum_t b) +{ + int i; + for (i = 7; i >= 0; i--) { + if (a[i] > b[i]) + return 1; + if (a[i] < b[i]) + return -1; + } + return 0; +} + +static int bn_equ_hex(const bignum_t a, const char *hex) +{ + char buf[65] = {0}; + char *p = buf; + int i; + + for (i = 7; i >= 0; i--) { + sprintf(p, "%08x", (uint32_t)a[i]); + p += 8; + } + return (strcmp(buf, hex) == 0); +} + +static int bn_is_odd(const bignum_t a) +{ + return a[0] & 0x01; +} + +static void bn_set_word(bignum_t r, uint32_t a) +{ + int i; + r[0] = a; + for (i = 1; i < 8; i++) { + r[i] = 0; + } +} +#define bn_set_one(r) bn_set_word((r), 1) + +static void bn_add(bignum_t r, const bignum_t a, const bignum_t b) +{ + int i; + r[0] = a[0] + b[0]; + + for (i = 1; i < 8; i++) { + r[i] = a[i] + b[i] + (r[i-1] >> 32); + } + for (i = 0; i < 7; i++) { + r[i] &= 0xffffffff; + } +} + +static void bn_sub(bignum_t ret, const bignum_t a, const bignum_t b) +{ + int i; + bignum_t r; + r[0] = ((uint64_t)1 << 32) + a[0] - b[0]; + for (i = 1; i < 7; i++) { + r[i] = 0xffffffff + a[i] - b[i] + (r[i - 1] >> 32); + r[i - 1] &= 0xffffffff; + } + r[i] = a[i] - b[i] + (r[i - 1] >> 32) - 1; + r[i - 1] &= 0xffffffff; + bn_copy(ret, r); +} + +static void bn_rand_range(bignum_t r, const bignum_t range) +{ + FILE *fp; + uint8_t buf[256]; + + fp = fopen("/dev/urandom", "rb"); + + do { + fread(buf, 1, 256, fp); + bn_from_bytes(r, buf); + } while (bn_cmp(r, range) >= 0); + + fclose(fp); +} + +static void fp_add(bignum_t r, const bignum_t a, const bignum_t b) +{ + bn_add(r, a, b); + if (bn_cmp(r, SM2_P) >= 0) + return bn_sub(r, r, SM2_P); +} + +static void fp_sub(bignum_t r, const bignum_t a, const bignum_t b) +{ + if (bn_cmp(a, b) >= 0) { + bn_sub(r, a, b); + } else { + bignum_t t; + bn_sub(t, SM2_P, b); + bn_add(r, t, a); + } +} + +static void fp_dbl(bignum_t r, const bignum_t a) +{ + fp_add(r, a, a); +} + +static void fp_tri(bignum_t r, const bignum_t a) +{ + bignum_t t; + fp_dbl(t, a); + fp_add(r, t, a); +} + +static void fp_div2(bignum_t r, const bignum_t a) +{ + int i; + bn_copy(r, a); + if (r[0] & 0x01) { + bn_add(r, r, SM2_P); + } + for (i = 0; i < 7; i++) { + r[i] = (r[i] >> 1) | ((r[i + 1] & 0x01) << 31); + } + r[i] >>= 1; +} + +static void fp_neg(bignum_t r, const bignum_t a) +{ + if (bn_is_zero(a)) { + bn_copy(r, a); + } else { + bn_sub(r, SM2_P, a); + } +} + +static void fp_mul(bignum_t r, const bignum_t a, const bignum_t b) +{ + int i, j; + uint64_t s[16] = {0}; + bignum_t d = {0}; + uint64_t u; + + // s = a * b + for (i = 0; i < 8; i++) { + u = 0; + for (j = 0; j < 8; j++) { + u = s[i + j] + a[i] * b[j] + u; + s[i + j] = u & 0xffffffff; + u >>= 32; + } + s[i + 8] = u; + } + + r[0] = s[0] + s[ 8] + s[ 9] + s[10] + s[11] + s[12] + ((s[13] + s[14] + s[15]) << 1); + r[1] = s[1] + s[ 9] + s[10] + s[11] + s[12] + s[13] + ((s[14] + s[15]) << 1); + r[2] = s[2]; + r[3] = s[3] + s[ 8] + s[11] + s[12] + s[14] + s[15] + (s[13] << 1); + r[4] = s[4] + s[ 9] + s[12] + s[13] + s[15] + (s[14] << 1); + r[5] = s[5] + s[10] + s[13] + s[14] + (s[15] << 1); + r[6] = s[6] + s[11] + s[14] + s[15]; + r[7] = s[7] + s[ 8] + s[ 9] + s[10] + s[11] + s[15] + ((s[12] + s[13] + s[14] + s[15]) << 1); + + for (i = 1; i < 8; i++) { + r[i] += r[i - 1] >> 32; + r[i - 1] &= 0xffffffff; + } + + d[2] = s[8] + s[9] + s[13] + s[14]; + d[3] = d[2] >> 32; + d[2] &= 0xffffffff; + bn_sub(r, r, d); + + // max times ? + while (bn_cmp(r, SM2_P) >= 0) { + bn_sub(r, r, SM2_P); + } +} + +static void fp_sqr(bignum_t r, const bignum_t a) +{ + fp_mul(r, a, a); +} + +static void fp_exp(bignum_t r, const bignum_t a, const bignum_t e) +{ + bignum_t t; + uint32_t w; + int i, j; + + bn_set_one(t); + for (i = 7; i >= 0; i--) { + w = (uint32_t)e[i]; + for (j = 0; j < 32; j++) { + fp_sqr(t, t); + if (w & 0x80000000) + fp_mul(t, t, a); + w <<= 1; + } + } + + bn_copy(r, t); +} + +static void fp_inv(bignum_t r, const bignum_t a) +{ + bignum_t a1; + bignum_t a2; + bignum_t a3; + bignum_t a4; + bignum_t a5; + int i; + + fp_sqr(a1, a); + fp_mul(a2, a1, a); + fp_sqr(a3, a2); + fp_sqr(a3, a3); + fp_mul(a3, a3, a2); + fp_sqr(a4, a3); + fp_sqr(a4, a4); + fp_sqr(a4, a4); + fp_sqr(a4, a4); + fp_mul(a4, a4, a3); + fp_sqr(a5, a4); + for (i = 1; i < 8; i++) + fp_sqr(a5, a5); + fp_mul(a5, a5, a4); + for (i = 0; i < 8; i++) + fp_sqr(a5, a5); + fp_mul(a5, a5, a4); + for (i = 0; i < 4; i++) + fp_sqr(a5, a5); + fp_mul(a5, a5, a3); + fp_sqr(a5, a5); + fp_sqr(a5, a5); + fp_mul(a5, a5, a2); + fp_sqr(a5, a5); + fp_mul(a5, a5, a); + fp_sqr(a4, a5); + fp_mul(a3, a4, a1); + fp_sqr(a5, a4); + for (i = 1; i< 31; i++) + fp_sqr(a5, a5); + fp_mul(a4, a5, a4); + fp_sqr(a4, a4); + fp_mul(a4, a4, a); + fp_mul(a3, a4, a2); + for (i = 0; i < 33; i++) + fp_sqr(a5, a5); + fp_mul(a2, a5, a3); + fp_mul(a3, a2, a3); + for (i = 0; i < 32; i++) + fp_sqr(a5, a5); + fp_mul(a2, a5, a3); + fp_mul(a3, a2, a3); + fp_mul(a4, a2, a4); + for (i = 0; i < 32; i++) + fp_sqr(a5, a5); + fp_mul(a2, a5, a3); + fp_mul(a3, a2, a3); + fp_mul(a4, a2, a4); + for (i = 0; i < 32; i++) + fp_sqr(a5, a5); + fp_mul(a2, a5, a3); + fp_mul(a3, a2, a3); + fp_mul(a4, a2, a4); + for (i = 0; i < 32; i++) + fp_sqr(a5, a5); + fp_mul(a2, a5, a3); + fp_mul(a3, a2, a3); + fp_mul(a4, a2, a4); + for (i = 0; i < 32; i++) + fp_sqr(a5, a5); + fp_mul(r, a4, a5); + + bn_clean(a1); + bn_clean(a2); + bn_clean(a3); + bn_clean(a4); + bn_clean(a5); +} + + +static void fn_add(bignum_t r, const bignum_t a, const bignum_t b) +{ + bn_add(r, a, b); + if (bn_cmp(r, SM2_N) >= 0) { + return bn_sub(r, r, SM2_N); + } +} + +static void fn_sub(bignum_t r, const bignum_t a, const bignum_t b) +{ + if (bn_cmp(a, b) >= 0) { + bn_sub(r, a, b); + } else { + bignum_t t; + bn_add(t, a, SM2_N); + bn_sub(r, t, b); + } +} + +static void fn_neg(bignum_t r, const bignum_t a) +{ + if (bn_is_zero(a)) { + bn_copy(r, a); + } else { + bn_sub(r, SM2_N, a); + } +} + +/* bn288 only used in barrett reduction */ +static int bn288_cmp(const uint64_t a[9], const uint64_t b[9]) +{ + int i; + for (i = 8; i >= 0; i--) { + if (a[i] > b[i]) + return 1; + if (a[i] < b[i]) + return -1; + } + return 0; +} + +static void bn288_add(uint64_t r[9], const uint64_t a[9], const uint64_t b[9]) +{ + int i; + r[0] = a[0] + b[0]; + for (i = 1; i < 9; i++) { + r[i] = a[i] + b[i] + (r[i-1] >> 32); + } + for (i = 0; i < 8; i++) { + r[i] &= 0xffffffff; + } +} + +static void bn288_sub(uint64_t ret[9], const uint64_t a[9], const uint64_t b[9]) +{ + int i; + uint64_t r[9]; + + r[0] = ((uint64_t)1 << 32) + a[0] - b[0]; + for (i = 1; i < 8; i++) { + r[i] = 0xffffffff + a[i] - b[i] + (r[i - 1] >> 32); + r[i - 1] &= 0xffffffff; + } + r[i] = a[i] - b[i] + (r[i - 1] >> 32) - 1; + r[i - 1] &= 0xffffffff; + + for (i = 0; i < 9; i++) { + ret[i] = r[i]; + } +} + +static void fn_mul(bignum_t r, const bignum_t a, const bignum_t b) +{ + static const uint64_t mu[8] = { + 0xf15149a0, 0x12ac6361, 0xfa323c01, 0x8dfc2096, + 1, 1, 1, 0x100000001, + }; + + uint64_t s[17]; + uint64_t zh[9]; + uint64_t zl[9]; + uint64_t q[9]; + uint64_t w; + int i, j; + + + /* z = a * b */ + for (i = 0; i < 8; i++) { + s[i] = 0; + } + for (i = 0; i < 8; i++) { + w = 0; + for (j = 0; j < 8; j++) { + w += s[i + j] + a[i] * b[j]; + s[i + j] = w & 0xffffffff; + w >>= 32; + } + s[i + 8] = w; + } + + /* zl = z mod (2^32)^9 = z[0..8] + * zh = z // (2^32)^7 = z[7..15] */ + for (i = 0; i < 9; i++) { + zl[i] = s[i]; + zh[i] = s[7 + i]; + } + //printf("zl = "); for (i = 8; i >= 0; i--) printf("%08x", (uint32_t)zl[i]); printf("\n"); + //printf("zh = "); for (i = 8; i >= 0; i--) printf("%08x", (uint32_t)zh[i]); printf("\n"); + + /* q = zh * mu // (2^32)^9 */ + for (i = 0; i < 9; i++) { + s[i] = 0; + } + for (i = 0; i < 9; i++) { + w = 0; + for (j = 0; j < 8; j++) { + w += s[i + j] + zh[i] * mu[j]; + s[i + j] = w & 0xffffffff; + w >>= 32; + } + s[i + 8] = w; + } + for (i = 0; i < 8; i++) { + q[i] = s[9 + i]; + } + //printf("q = "); for (i = 7; i >= 0; i--) printf("%08x", (uint32_t)q[i]); printf("\n"); + + + /* q = q * n mod (2^32)^9 */ + for (i = 0; i < 8; i++) { + s[i] = 0; + } + for (i = 0; i < 8; i++) { + w = 0; + for (j = 0; j < 8; j++) { + w += s[i + j] + q[i] * SM2_N[j]; + s[i + j] = w & 0xffffffff; + w >>= 32; + } + s[i + 8] = w; + } + for (i = 0; i < 9; i++) { + q[i] = s[i]; + } + //printf("qn = "); for (i = 8; i >= 0; i--) printf("%08x", (uint32_t)q[i]); printf("\n"); + + /* r = zl - q (mod (2^32)^9) */ + + if (bn288_cmp(zl, q)) { + bn288_sub(zl, zl, q); + } else { + uint64_t c[9] = {0,0,0,0,0,0,0,0,0x100000000}; + bn288_sub(q, c, q); + bn288_add(zl, q, zl); + printf("******\n"); + printf("******\n"); + printf("******\n"); + printf("******\n"); + printf("******\n"); + + } + + //printf("r = "); for (i = 8; i >= 0; i--) printf("%08x", (uint32_t)zl[i]); printf("\n"); + + for (i = 0; i < 8; i++) { + r[i] = zl[i]; + } + r[7] += zl[8] << 32; + + /* while r >= p do: r = r - n */ + while (bn_cmp(r, SM2_N) >= 0) { + bn_sub(r, r, SM2_N); + //printf("r = r -n = "); for (i = 8; i >= 0; i--) printf("%08x", (uint32_t)zl[i]); printf("\n"); + } +} + +static void fn_sqr(bignum_t r, const bignum_t a) +{ + return fn_mul(r, a, a); +} + +static void fn_exp(bignum_t r, const bignum_t a, const bignum_t e) +{ + bignum_t t; + uint32_t w; + int i, j; + + bn_set_one(t); + for (i = 7; i >= 0; i--) { + w = (uint32_t)e[i]; + for (j = 0; j < 32; j++) { + fn_sqr(t, t); + if (w & 0x80000000) { + fn_mul(t, t, a); + } + w <<= 1; + } + } + + bn_copy(r, t); +} + +static void fn_inv(bignum_t r, const bignum_t a) +{ + bignum_t e; + bn_sub(e, SM2_N, TWO); + fn_exp(r, a, e); +} + +static void fn_rand(bignum_t r) +{ + return bn_rand_range(r, SM2_N); +} + +#define hex_fp_add_x_y "eefbe4cf140ff8b5b956d329d5a2eae8608c933cb89053217439786e54866567" +#define hex_fp_sub_x_y "768d77882a23097d05db3562fed0a840bf3984422c3bc4a26e7b12a412128426" +#define hex_fp_sub_y_x "89728876d5dcf682fa24ca9d012f57bf40c67bbcd3c43b5e9184ed5beded7bd9" +#define hex_fp_neg_x "cd3b51d2e0e67ee6a066fbb995c6366b701cf43f0d99f41f8ea5ba76ccb38b38" +#define hex_fp_mul_x_y "edd7e745bdc4630ccfa1da1057033a525346dbf202f082f3c431349991ace76a" +#define hex_fp_squ_x "f4e2cca0bcfd67fba8531eebff519e4cb3d47f9fe8c5eff5151f4c497ec99fbf" +#define hex_fp_exp_x_y "8cafd11b1a0d2072b82911ba87e0d376103a1be5986fce91d8d297b758f68146" +#define hex_fp_inv_x "053b878fb82e213c17e554b9a574b7bd31775222704b7fd9c7d6f8441026cd80" + +#define hex_fn_add_x_y "eefbe4cf140ff8b5b956d329d5a2eae8608c933cb89053217439786e54866567" +#define hex_fn_sub_x_y "768d77882a23097d05db3562fed0a840313d63ae4e01c9ccc23706ad4be7c54a" +#define hex_fn_sub_y_x "89728876d5dcf682fa24ca9d012f57bf40c67bbcd3c43b5e9184ed5beded7bd9" +#define hex_fn_neg_x "cd3b51d2e0e67ee6a066fbb995c6366ae220d3ab2f5ff949e261ae800688cc5c" +#define hex_fn_mul_x_y "cf7296d5cbf0b64bb5e9a11b294962e9c779b41c038e9c8d815234a0df9d6623" +#define hex_fn_sqr_x "82d3d1b296d3a3803888b7ffc78f23eca824e7ec8d7ddaf231ffb0d256a19da2" +#define hex_fn_exp_x_y "0cf4df7e76d7d49ff23b94853a98aba1e36e9ca0358acbf23a3bbda406f46df3" +#define hex_fn_inv_x "96340ec8b80f44e9b345a706bdb5c9e3ab8a6474a5cb4e0d4645dbaecf1cf03d" +#define hex_v "d3da0ef661be97360e1b32f834e6ca5673b1984b22bb420133da05e56ccd59fb" +#define hex_fn_mul_x_v "0375c61e1ed13e460f4b5d462dc5b2c846f36c7b481cd4bed8f7dd55908a6afd" + +#define hex_t \ + "2fbadf57b52dc19e8470bf201cb182e0a4f7fa5e28d356b15da173132b94b325" + +static int bn_test(void) +{ + bignum_t r; + bignum_t x; + bignum_t y; + bn_copy(x, SM2_G->X); + bn_copy(y, SM2_G->Y); + int ok, i = 1; + + char hex[65]; + + bignum_t v = { + 0x6ccd59fb, 0x33da05e5, 0x22bb4201, 0x73b1984b, + 0x34e6ca56, 0x0e1b32f8, 0x61be9736, 0xd3da0ef6, + }; + + bignum_t t; + + bn_from_hex(r, hex_v); + print_bn(r); + + // fp tests + fp_add(r, x, y); + ok = bn_equ_hex(r, hex_fp_add_x_y); + printf("sm2 bn test %d %s\n", i++, ok ? "ok" : "failed"); + + fp_sub(r, x, y); + ok = bn_equ_hex(r, hex_fp_sub_x_y); + printf("sm2 bn test %d %s\n", i++, ok ? "ok" : "failed"); + + fp_mul(r, x, y); + ok = bn_equ_hex(r, hex_fp_mul_x_y); + printf("sm2 bn test %d %s\n", i++, ok ? "ok" : "failed"); + + fp_exp(r, x, y); + ok = bn_equ_hex(r, hex_fp_exp_x_y); + printf("sm2 bn test %d %s\n", i++, ok ? "ok" : "failed"); + + fp_inv(r, x); + ok = bn_equ_hex(r, hex_fp_inv_x); + printf("sm2 bn test %d %s\n", i++, ok ? "ok" : "failed"); + + fp_neg(r, x); + ok = bn_equ_hex(r, hex_fp_neg_x); + printf("sm2 bn test %d %s\n", i++, ok ? "ok" : "failed"); + + // fn tests + fn_add(r, x, y); + ok = bn_equ_hex(r, hex_fn_add_x_y); + printf("sm2 bn test %d %s\n", i++, ok ? "ok" : "failed"); + + fn_sub(r, x, y); + ok = bn_equ_hex(r, hex_fn_sub_x_y); + printf("sm2 bn test %d %s\n", i++, ok ? "ok" : "failed"); + + fn_sub(r, y, x); + ok = bn_equ_hex(r, hex_fn_sub_y_x); + printf("sm2 bn test %d %s\n", i++, ok ? "ok" : "failed"); + + fn_neg(r, x); + ok = bn_equ_hex(r, hex_fn_neg_x); + printf("sm2 bn test %d %s\n", i++, ok ? "ok" : "failed"); + + fn_mul(r, x, y); + ok = bn_equ_hex(r, hex_fn_mul_x_y); + printf("sm2 bn test %d %s\n", i++, ok ? "ok" : "failed"); + + fn_mul(r, x, v); + ok = bn_equ_hex(r, hex_fn_mul_x_v); + printf("sm2 bn test %d %s\n", i++, ok ? "ok" : "failed"); + + fn_sqr(r, x); + ok = bn_equ_hex(r, hex_fn_sqr_x); + printf("sm2 bn test %d %s\n", i++, ok ? "ok" : "failed"); + + fn_exp(r, x, y); + ok = bn_equ_hex(r, hex_fn_exp_x_y); + printf("sm2 bn test %d %s\n", i++, ok ? "ok" : "failed"); + + fn_inv(r, x); + ok = bn_equ_hex(r, hex_fn_inv_x); + printf("sm2 bn test %d %s\n", i++, ok ? "ok" : "failed"); + + bignum_t tv = { + 0x2b94b325, 0x5da17313, 0x28d356b1, 0xa4f7fa5e, + 0x1cb182e0, 0x8470bf20, 0xb52dc19e, 0x2fbadf57, + }; + bn_from_hex(t, hex_t); + ok = (bn_cmp(t, tv) == 0); + + bn_to_hex(t, hex); + bn_check(t); + + printf("end\n"); + return 0; +} + +static void point_init(point_t *R) +{ + memset(R, 0, sizeof(point_t)); + R->X[0] = 1; + R->Y[0] = 1; +} +#define point_set_infinity(R) point_init(R) + +static int point_is_at_infinity(const point_t *P) +{ + return bn_is_zero(P->Z); +} + +#define point_copy(R, P) memcpy((R), (P), sizeof(point_t)) + +static void point_set_xy(point_t *R, const bignum_t x, const bignum_t y) +{ + bn_copy(R->X, x); + bn_copy(R->Y, y); + bn_set_one(R->Z); +} + +static void point_get_xy(const point_t *P, bignum_t x, bignum_t y) +{ + bignum_t z_inv; + + if (bn_is_one(P->Z)) { + bn_copy(x, P->X); + bn_copy(y, P->Y); + } else { + fp_inv(z_inv, P->Z); + if (y) + fp_mul(y, P->Y, z_inv); + fp_sqr(z_inv, z_inv); + fp_mul(x, P->X, z_inv); + if (y) + fp_mul(y, y, z_inv); + } +} + +static int point_print(FILE *fp, const point_t *P, int format, int indent) +{ + int len = 0; + bignum_t x; + bignum_t y; + point_get_xy(P, x, y); + len += bn_print(fp, x, format, indent); + len += bn_print(fp, y, format, indent); + + return len; +} + +#define print_point(P) point_print(stdout,P,0,0) + +static int point_is_on_curve(const point_t *P) +{ + bignum_t t0; + bignum_t t1; + bignum_t t2; + + if (bn_is_one(P->Z)) { + fp_sqr(t0, P->Y); + fp_add(t0, t0, P->X); + fp_add(t0, t0, P->X); + fp_add(t0, t0, P->X); + fp_sqr(t1, P->X); + fp_mul(t1, t1, P->X); + fp_add(t1, t1, SM2_B); + } else { + fp_sqr(t0, P->Y); + fp_sqr(t1, P->Z); + fp_sqr(t2, t1); + fp_mul(t1, t1, t2); + fp_mul(t1, t1, SM2_B); + fp_mul(t2, t2, P->X); + fp_add(t0, t0, t2); + fp_add(t0, t0, t2); + fp_add(t0, t0, t2); + fp_sqr(t2, P->X); + fp_mul(t2, t2, P->X); + fp_add(t1, t1, t2); + } + + return (bn_cmp(t0, t1) == 0); +} + +static void point_neg(point_t *R, const point_t *P) +{ + bn_copy(R->X, P->X); + fp_neg(R->Y, P->Y); + bn_copy(R->Z, P->Z); +} + +static void point_dbl(point_t *R, const point_t *P) +{ + const uint64_t *X1 = P->X; + const uint64_t *Y1 = P->Y; + const uint64_t *Z1 = P->Z; + bignum_t T1; + bignum_t T2; + bignum_t T3; + bignum_t X3; + bignum_t Y3; + bignum_t Z3; + //printf("X1 = "); print_bn(X1); + //printf("Y1 = "); print_bn(Y1); + //printf("Z1 = "); print_bn(Z1); + + if (point_is_at_infinity(P)) { + point_copy(R, P); + return; + } + + fp_sqr(T1, Z1); //printf("T1 = Z1^2 = "); print_bn(T1); + fp_sub(T2, X1, T1); //printf("T2 = X1 - T1 = "); print_bn(T2); + fp_add(T1, X1, T1); //printf("T1 = X1 + T1 = "); print_bn(T1); + fp_mul(T2, T2, T1); //printf("T2 = T2 * T1 = "); print_bn(T2); + fp_tri(T2, T2); //printf("T2 = 3 * T2 = "); print_bn(T2); + fp_dbl(Y3, Y1); //printf("Y3 = 2 * Y1 = "); print_bn(Y3); + fp_mul(Z3, Y3, Z1); //printf("Z3 = Y3 * Z1 = "); print_bn(Z3); + fp_sqr(Y3, Y3); //printf("Y3 = Y3^2 = "); print_bn(Y3); + fp_mul(T3, Y3, X1); //printf("T3 = Y3 * X1 = "); print_bn(T3); + fp_sqr(Y3, Y3); //printf("Y3 = Y3^2 = "); print_bn(Y3); + fp_div2(Y3, Y3); //printf("Y3 = Y3/2 = "); print_bn(Y3); + fp_sqr(X3, T2); //printf("X3 = T2^2 = "); print_bn(X3); + fp_dbl(T1, T3); //printf("T1 = 2 * T1 = "); print_bn(T1); + fp_sub(X3, X3, T1); //printf("X3 = X3 - T1 = "); print_bn(X3); + fp_sub(T1, T3, X3); //printf("T1 = T3 - X3 = "); print_bn(T1); + fp_mul(T1, T1, T2); //printf("T1 = T1 * T2 = "); print_bn(T1); + fp_sub(Y3, T1, Y3); //printf("Y3 = T1 - Y3 = "); print_bn(Y3); + + bn_copy(R->X, X3); + bn_copy(R->Y, Y3); + bn_copy(R->Z, Z3); + + //printf("X3 = "); print_bn(R->X); + //printf("Y3 = "); print_bn(R->Y); + //printf("Z3 = "); print_bn(R->Z); + +} + +// 这个函数有一个严重的问题,就是我们假定Q是一个已经正规化的点 +// 因此如果这个点不是仿射坐标的就出现问题了 +static void point_add(point_t *R, const point_t *P, const point_t *Q) +{ + const uint64_t *X1 = P->X; + const uint64_t *Y1 = P->Y; + const uint64_t *Z1 = P->Z; + const uint64_t *x2 = Q->X; + const uint64_t *y2 = Q->Y; + bignum_t T1; + bignum_t T2; + bignum_t T3; + bignum_t T4; + bignum_t X3; + bignum_t Y3; + bignum_t Z3; + + if (point_is_at_infinity(Q)) { + point_copy(R, P); + return; + } + + if (point_is_at_infinity(P)) { + point_copy(R, Q); + return; + } + + assert(bn_is_one(Q->Z)); + + fp_sqr(T1, Z1); + fp_mul(T2, T1, Z1); + fp_mul(T1, T1, x2); + fp_mul(T2, T2, y2); + fp_sub(T1, T1, X1); + fp_sub(T2, T2, Y1); + if (bn_is_zero(T1)) { + if (bn_is_zero(T2)) { + point_t _Q, *Q = &_Q; + point_set_xy(Q, x2, y2); + + point_dbl(R, Q); + return; + } else { + point_set_infinity(R); + return; + } + } + fp_mul(Z3, Z1, T1); + fp_sqr(T3, T1); + fp_mul(T4, T3, T1); + fp_mul(T3, T3, X1); + fp_dbl(T1, T3); + fp_sqr(X3, T2); + fp_sub(X3, X3, T1); + fp_sub(X3, X3, T4); + fp_sub(T3, T3, X3); + fp_mul(T3, T3, T2); + fp_mul(T4, T4, Y1); + fp_sub(Y3, T3, T4); + + bn_copy(R->X, X3); + bn_copy(R->Y, Y3); + bn_copy(R->Z, Z3); +} + +static void point_sub(point_t *R, const point_t *P, const point_t *Q) +{ + point_t _T, *T = &_T; + point_neg(T, Q); + point_add(R, P, T); +} + +static void point_mul(point_t *R, const bignum_t k, const point_t *P) +{ + char bits[257] = {0}; + point_t _Q, *Q = &_Q; + point_t _T, *T = &_T; + int i; + + // point_add要求输入的P必须为仿射坐标 + if (!bn_is_one(P->Z)) { + bignum_t x; + bignum_t y; + point_get_xy(P, x, y); + point_set_xy(T, x, y); + P = T; + } + + point_set_infinity(Q); + bn_to_bits(k, bits); + for (i = 0; i < 256; i++) { + point_dbl(Q, Q); + if (bits[i] == '1') { + point_add(Q, Q, P); + } + } + point_copy(R, Q); +} + +static void point_to_bytes(const point_t *P, uint8_t out[64]) +{ + bignum_t x; + bignum_t y; + point_get_xy(P, x, y); + bn_to_bytes(x, out); + bn_to_bytes(y, out + 32); +} + +static void point_from_bytes(point_t *P, const uint8_t in[64]) +{ + bn_from_bytes(P->X, in); + bn_from_bytes(P->Y, in + 32); + bn_set_word(P->Z, 1); + /* should we check if point_is_on_curve */ +} + +static void point_mul_generator(point_t *R, const bignum_t k) +{ + point_mul(R, k, SM2_G); +} + +/* R = t * P + s * G */ +static void point_mul_sum(point_t *R, const bignum_t t, const point_t *P, const bignum_t s) +{ + point_t _sG, *sG = &_sG; + bignum_t x; + bignum_t y; + + /* T = s * G */ + point_mul_generator(sG, s); + + // R = t * P + point_mul(R, t, P); + point_get_xy(R, x, y); + point_set_xy(R, x, y); + + // R = R + T + point_add(R, sG, R); +} + +static void point_from_hex(point_t *P, const char hex[64 * 2]) +{ + bn_from_hex(P->X, hex); + bn_from_hex(P->Y, hex + 64); + bn_set_one(P->Z); +} + +static int point_equ_hex(const point_t *P, const char hex[128]) +{ + bignum_t x; + bignum_t y; + point_t _T, *T = &_T; + + point_get_xy(P, x, y); + point_from_hex(T, hex); + + return (bn_cmp(x, T->X) == 0) && (bn_cmp(y, T->Y) == 0); +} + +#define hex_G \ + "32c4ae2c1f1981195f9904466a39c9948fe30bbff2660be1715a4589334c74c7" \ + "bc3736a2f4f6779c59bdcee36b692153d0a9877cc62a474002df32e52139f0a0" +#define hex_2G \ + "56cefd60d7c87c000d58ef57fa73ba4d9c0dfa08c08a7331495c2e1da3f2bd52" \ + "31b7e7e6cc8189f668535ce0f8eaf1bd6de84c182f6c8e716f780d3a970a23c3" +#define hex_3G \ + "a97f7cd4b3c993b4be2daa8cdb41e24ca13f6bd945302244e26918f1d0509ebf" \ + "530b5dd88c688ef5ccc5cec08a72150f7c400ee5cd045292aaacdd037458f6e6" +#define hex_negG \ + "32c4ae2c1f1981195f9904466a39c9948fe30bbff2660be1715a4589334c74c7" \ + "43c8c95c0b098863a642311c9496deac2f56788239d5b8c0fd20cd1adec60f5f" +#define hex_10G \ + "d3f94862519621c121666061f65c3e32b2d0d065cd219e3284a04814db522756" \ + "4b9030cf676f6a742ebd57d146dca428f6b743f64d1482d147d46fb2bab82a14" +#define hex_bG \ + "528470bc74a6ebc663c06fc4cfa1b630d1e9d4a80c0a127b47f73c324c46c0ba" \ + "832cf9c5a15b997e60962b4cf6e2c9cee488faaec98d20599d323d4cabfc1bf4" + +#define hex_P \ + "504cfe2fae749d645e99fbb5b25995cc6fed70196007b039bdc44706bdabc0d9" \ + "b80a8018eda5f55ddc4b870d7784b7b84e53af02f575ab53ed8a99a3bbe2abc2" +#define hex_2P \ + "a53d20e89312b5243f66aec12ef6471f5911941d86302d5d8337cb70937d65ae" \ + "96953c46815e4259363256ddd6c77fcc33787aeafc6a57beec5833f476dd69e0" + +#define hex_tP \ + "02deff2c5b3656ca3f7c7ca9d710ca1d69860c75a9c7ec284b96b8adc50b2936" \ + "b74bcba937e9267fce4ccc069a6681f5b04dcedd9e2794c6a25ddc7856df7145" + + +static int point_test(void) +{ + point_t _P, *P = &_P; + point_t _G, *G = &_G; + bignum_t k; + int err = 0, i = 1, ok; + + uint8_t buf[64]; + + printf("point_test\n"); + + point_copy(G, SM2_G); + ok = point_equ_hex(G, hex_G); + printf("sm2 point test %d %s\n", i++, ok ? "ok" : "failed"); err += ok ^ 1; + + ok = point_is_on_curve(G); + printf("sm2 point test %d %s\n", i++, ok ? "ok" : "failed"); err += ok ^ 1; + + point_dbl(P, G); + ok = point_equ_hex(P, hex_2G); + printf("sm2 point test %d %s\n", i++, ok ? "ok" : "failed"); err += ok ^ 1; + + point_add(P, P, G); + ok = point_equ_hex(P, hex_3G); + printf("sm2 point test %d %s\n", i++, ok ? "ok" : "failed"); err += ok ^ 1; + + point_sub(P, P, G); + ok = point_equ_hex(P, hex_2G); + printf("sm2 point test %d %s\n", i++, ok ? "ok" : "failed"); err += ok ^ 1; + + point_neg(P, G); + ok = point_equ_hex(P, hex_negG); + printf("sm2 point test %d %s\n", i++, ok ? "ok" : "failed"); err += ok ^ 1; + + bn_set_word(k, 10); + point_mul(P, k, G); + ok = point_equ_hex(P, hex_10G); + printf("sm2 point test %d %s\n", i++, ok ? "ok" : "failed"); err += ok ^ 1; + + point_mul_generator(P, SM2_B); + ok = point_equ_hex(P, hex_bG); + printf("sm2 point test %d %s\n", i++, ok ? "ok" : "failed"); err += ok ^ 1; + + point_to_bytes(P, buf); + point_from_hex(P, hex_P); + + return err; +} + +int sm2_algo_selftest(void) +{ + point_test(); + return 0; +} + +int sm2_keygen(SM2_KEY *key) +{ + bignum_t x; + bignum_t y; + point_t _P, *P = &_P; + + if (!key) { + return -1; + } + + do { + bn_rand_range(x, SM2_N); + } while (bn_is_zero(x)); + bn_to_bytes(x, key->private_key); + + point_mul_generator(P, x); + point_get_xy(P, x, y); + bn_to_bytes(x, key->public_key.x); + bn_to_bytes(y, key->public_key.y); + return 1; +} + +int sm2_point_is_on_curve(const SM2_POINT *P) +{ + point_t T; + point_from_bytes(&T, (const uint8_t *)P); + return point_is_on_curve(&T); +} + +int sm2_point_from_x(SM2_POINT *P, const uint8_t x[32], int y) +{ + bignum_t _x, _y, _g, _z; + bn_from_bytes(_x, x); + + // g = x^3 - 3x + b = (x^2 - 3)*x + b + fp_sqr(_g, _x); + fp_sub(_g, _g, THREE); + fp_mul(_g, _g, _x); + fp_add(_g, _g, SM2_B); + + // y = g^(u + 1) mod p, u = (p - 3)/4 + fp_exp(_y, _g, SM2_U_PLUS_ONE); + + // z = y^2 mod p + fp_sqr(_z, _y); + if (bn_cmp(_z, _g)) { + error_print(); + return -1; + } + + if ((y == 0x02 && bn_is_odd(_y)) || (y == 0x03) && !bn_is_odd(_y)) { + fp_neg(_y, _y); + } + + bn_to_bytes(_x, P->x); + bn_to_bytes(_y, P->y); + + bn_clean(_x); + bn_clean(_y); + bn_clean(_g); + bn_clean(_z); + + if (!sm2_point_is_on_curve(P)) { + error_print(); + return -1; + } + return 1; +} + +int sm2_point_from_xy(SM2_POINT *P, const uint8_t x[32], const uint8_t y[32]) +{ + memcpy(P->x, x, 32); + memcpy(P->y, y, 32); + return sm2_point_is_on_curve(P); +} + +int sm2_point_mul(SM2_POINT *R, const uint8_t k[32], const SM2_POINT *P) +{ + bignum_t _k; + point_t _P; + + bn_from_bytes(_k, k); + point_from_bytes(&_P, (uint8_t *)P); + point_mul(&_P, _k, &_P); + point_to_bytes(&_P, (uint8_t *)R); + + bn_clean(_k); + return 1; +} + +int sm2_point_mul_generator(SM2_POINT *R, const uint8_t k[32]) +{ + bignum_t _k; + point_t _R; + + bn_from_bytes(_k, k); + point_mul_generator(&_R, _k); + point_to_bytes(&_R, (uint8_t *)R); + + bn_clean(_k); + return 1; +} + +int sm2_point_mul_sum(SM2_POINT *R, const uint8_t k[32], const SM2_POINT *P, const uint8_t s[32]) +{ + bignum_t _k; + point_t _P; + bignum_t _s; + + bn_from_bytes(_k, k); + point_from_bytes(&_P, (uint8_t *)P); + bn_from_bytes(_s, s); + point_mul_sum(&_P, _k, &_P, _s); + point_to_bytes(&_P, (uint8_t *)R); + + bn_clean(_k); + bn_clean(_s); + return 1; +} + +#define hex_d "5aebdfd947543b713bc0df2c65baaecc5dadd2cab39c6971402daf92c263fad2" +#define hex_e "c0881c19beec741b9af27cc26493dcc33b05d481bfeab2f3ce9cc056e6ff8400" +#define hex_k "981325ee1ab171e9d2cffb317181a02957b18a34bca610a6d2f8afcdeb53f6b8" +#define hex_x1 "17d2dfe83f23cce8499bca983950d59f0fd56c4c671dd63c04b27e4e94cfd767" +#define hex_r "d85afc01fe104103e48e475a9de4b2624adb40ce2708892fd34f3ea57bcf5b67" +#define hex_rd "a70ba64f9c30e05095f39fe26675114e3f157b2c35191bf6ff06246452f82eb3" +#define hex_di "3ecfdb51c24b0eecb2d4238d1da8c013b8b575cef14ef43e2ddb7bce740ce9cf" +#define hex_krd "f1077f9d7e8091993cdc5b4f0b0c8eda8a9fee73a952f9db27ae7f72d2310928" +#define hex_s "006bac5b8057ca829534dfde72a0d7883444a3b9bfe9bcdfb383fb90ed7d9486" + +int sm2_do_sign(const SM2_KEY *key, const uint8_t dgst[32], SM2_SIGNATURE *sig) +{ + point_t _P, *P = &_P; + bignum_t d; + bignum_t e; + bignum_t k; + bignum_t x; + bignum_t r; + bignum_t s; + + if (!key || !dgst || !sig) { + return -1; + } + + bn_from_bytes(d, key->private_key); + + // e = H(M) + bn_from_bytes(e, dgst); //print_bn("e", e); + +retry: + + // rand k in [1, n - 1] + do { + fn_rand(k); + } while (bn_is_zero(k)); + //print_bn("k", k); + + // (x, y) = kG + point_mul_generator(P, k); + point_get_xy(P, x, NULL); //print_bn("x", x); + + + // r = e + x (mod n) + fn_add(r, e, x); //print_bn("r = e + x (mod n)", r); + + /* if r == 0 or r + k == n re-generate k */ + if (bn_is_zero(r)) { + goto retry; + } + bn_add(x, r, k); + if (bn_cmp(x, SM2_N) == 0) { + goto retry; + } + + /* s = ((1 + d)^-1 * (k - r * d)) mod n */ + + fn_mul(e, r, d); //print_bn("r*d", e); + fn_sub(k, k, e); //print_bn("k-r*d", k); + fn_add(e, ONE, d); //print_bn("1 +d", e); + fn_inv(e, e); //printf("(1+d)^-1", e); + fn_mul(s, e, k); //print_bn("s = ((1 + d)^-1 * (k - r * d)) mod n", s); + + bn_clean(d); + bn_clean(k); + bn_to_bytes(r, sig->r); //print_bn("r", r); + bn_to_bytes(s, sig->s); //print_bn("s", s); + return 1; +} + +int sm2_do_verify(const SM2_KEY *key, const uint8_t dgst[32], const SM2_SIGNATURE *sig) +{ + point_t _P, *P = &_P; + point_t _R, *R = &_R; + bignum_t r; + bignum_t s; + bignum_t e; + bignum_t x; + bignum_t t; + + if (!key || !dgst || !sig) { + error_print(); + return -1; + } + + // parse signature values + bn_from_bytes(r, sig->r); //print_bn("r", r); + bn_from_bytes(s, sig->s); //print_bn("s", s); + if (bn_is_zero(r) + || bn_cmp(r, SM2_N) >= 0 + || bn_is_zero(s) + || bn_cmp(s, SM2_N) >= 0) { + error_print(); + return -1; + } + + // parse public key + point_from_bytes(P, (const uint8_t *)&key->public_key); + //print_point("P", P); + + // t = r + s (mod n) + // check t != 0 + fn_add(t, r, s); //print_bn("t = r + s (mod n)", t); + if (bn_is_zero(t)) { + error_print(); + return -1; + } + + // Q = s * G + t * P + point_mul_sum(R, t, P, s); + point_get_xy(R, x, NULL); //print_bn("x", x); + + // e = H(M) + // r' = e + x (mod n) + bn_from_bytes(e, dgst); //print_bn("e = H(M)", e); + fn_add(e, e, x); //print_bn("e + x (mod n)", e); + + // check if r == r' + if (bn_cmp(e, r) == 0) { + return 1; + } else { + error_print(); + return 0; + } +} + +int sm2_point_from_signature(SM2_POINT *point, const SM2_SIGNATURE *sig) +{ + return -1; +} + +int sm2_kdf(const uint8_t *in, size_t inlen, size_t outlen, uint8_t *out) +{ + SM3_CTX ctx; + uint8_t counter_be[4]; + uint8_t dgst[SM3_DIGEST_SIZE]; + uint32_t counter = 1; + size_t len; + + /* + size_t i; fprintf(stderr, "kdf input : "); + for (i = 0; i < inlen; i++) fprintf(stderr, "%02x", in[i]); fprintf(stderr, "\n"); + */ + + while (outlen) { + PUTU32(counter_be, counter); + counter++; + + sm3_init(&ctx); + sm3_update(&ctx, in, inlen); + sm3_update(&ctx, counter_be, sizeof(counter_be)); + sm3_finish(&ctx, dgst); + + len = outlen < SM3_DIGEST_SIZE ? outlen : SM3_DIGEST_SIZE; + memcpy(out, dgst, len); + out += len; + outlen -= len; + } + + memset(&ctx, 0, sizeof(SM3_CTX)); + memset(dgst, 0, sizeof(dgst)); + return 1; +} + +// `sm2_do_encrypt` does not check validity of `key` +int sm2_do_encrypt(const SM2_KEY *key, const uint8_t *in, size_t inlen, SM2_CIPHERTEXT *out) +{ + bignum_t k; + point_t _P, *P = &_P; + SM3_CTX sm3_ctx; + uint8_t buf[64]; + int i; + + if (!key || !in || !inlen || !out) { + return -1; + } + + // rand k in [1, n - 1] + do { + bn_rand_range(k, SM2_N); + } while (bn_is_zero(k)); + + // C1 = k * G = (x1, y1) + point_mul_generator(P, k); + point_to_bytes(P, (uint8_t *)&out->point); + + + // Q = k * P = (x2, y2) + point_from_bytes(P, (uint8_t *)&key->public_key); + + point_mul(P, k, P); + + point_to_bytes(P, buf); + + + // t = KDF(x2 || y2, klen) + sm2_kdf(buf, sizeof(buf), inlen, out->ciphertext); + + + // C2 = M xor t + for (i = 0; i < inlen; i++) { + out->ciphertext[i] ^= in[i]; + } + out->ciphertext_size = (uint32_t)inlen; + + // C3 = Hash(x2 || m || y2) + sm3_init(&sm3_ctx); + sm3_update(&sm3_ctx, buf, 32); + sm3_update(&sm3_ctx, in, inlen); + sm3_update(&sm3_ctx, buf + 32, 32); + sm3_finish(&sm3_ctx, out->hash); + + return 1; +} + +int sm2_do_decrypt(const SM2_KEY *key, const SM2_CIPHERTEXT *in, uint8_t *out, size_t *outlen) +{ + uint32_t inlen; + bignum_t d; + point_t _P, *P = &_P; + SM3_CTX sm3_ctx; + uint8_t buf[64]; + uint8_t hash[32]; + int i; + + // FIXME: 检查SM2_CIPHERTEXT格式 + + // check C1 + point_from_bytes(P, (uint8_t *)&in->point); + //point_print(stdout, P, 0, 2); + + /* + if (!point_is_on_curve(P)) { + fprintf(stderr, "%s %d: invalid ciphertext\n", __FILE__, __LINE__); + return -1; + } + */ + + // d * C1 = (x2, y2) + bn_from_bytes(d, key->private_key); + point_mul(P, d, P); + bn_clean(d); + point_to_bytes(P, buf); + + // t = KDF(x2 || y2, klen) + if ((inlen = in->ciphertext_size) <= 0) { + fprintf(stderr, "%s %d: invalid ciphertext\n", __FILE__, __LINE__); + return -1; + } + + sm2_kdf(buf, sizeof(buf), inlen, out); + + // M = C2 xor t + for (i = 0; i < inlen; i++) { + out[i] ^= in->ciphertext[i]; + } + + // u = Hash(x2 || M || y2) + sm3_init(&sm3_ctx); + sm3_update(&sm3_ctx, buf, 32); + sm3_update(&sm3_ctx, out, inlen); + sm3_update(&sm3_ctx, buf + 32, 32); + sm3_finish(&sm3_ctx, hash); + + // check if u == C3 + if (memcmp(in->hash, hash, sizeof(hash)) != 0) { + fprintf(stderr, "%s %d: invalid ciphertext\n", __FILE__, __LINE__); + return -1; + } + + return 1; +} + +int sm2_ecdh(const SM2_KEY *key, const SM2_POINT *peer_public, SM2_POINT *out) +{ + bignum_t d; + point_t _P, *P = &_P; + + bn_from_bytes(d, key->private_key); + point_from_bytes(P, (uint8_t *)peer_public); + if (!point_is_on_curve(P)) { + error_print(); + return -1; + } + point_mul(P, d, P); + point_to_bytes(P, (uint8_t *)out); + return 1; +} diff --git a/src/sm2_asn1.c b/src/sm2_asn1.c new file mode 100644 index 00000000..cf424d16 --- /dev/null +++ b/src/sm2_asn1.c @@ -0,0 +1,581 @@ +/* + * Copyright (c) 2014 - 2020 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + +#include +#include +#include +#include +#include +#include + +void sm2_point_to_compressed_octets(const SM2_POINT *P, uint8_t out[33]) +{ + *out++ = (P->y[31] & 0x01) ? 0x03 : 0x02; + memcpy(out, P->x, 32); +} + +void sm2_point_to_uncompressed_octets(const SM2_POINT *P, uint8_t out[65]) +{ + *out++ = 0x04; + memcpy(out, P, 64); +} + +int sm2_point_from_octets(SM2_POINT *P, const uint8_t *in, size_t inlen) +{ + if ((*in == 0x02 || *in == 0x03) && inlen == 33) { + return sm2_point_from_x(P, in + 1, *in); + } else if (*in == 0x04 && inlen == 65) { + return sm2_point_from_xy(P, in + 1, in + 33); + } else { + error_print(); + return -1; + } +} + +int sm2_point_to_der(const SM2_POINT *a, uint8_t **out, size_t *outlen) +{ + uint8_t buf[65]; + sm2_point_to_uncompressed_octets(a, buf); + asn1_octet_string_to_der(buf, sizeof(buf), out, outlen); + return 1; +} + +int sm2_point_from_der(SM2_POINT *a, const uint8_t **in, size_t *inlen) +{ + int ret; + const uint8_t *data; + size_t datalen; + error_print("inlen = %zu\n", *inlen); + + if ((ret = asn1_octet_string_from_der(&data, &datalen, in, inlen)) != 1) { + if (ret < 0) error_print(); + else error_print(); + return ret; + } + if (sm2_point_from_octets(a, data, datalen) != 1) { + error_print(); + return -1; + } + error_print("inlen = %zu\n", *inlen); + return 1; +} + +int sm2_signature_to_der(const SM2_SIGNATURE *sig, uint8_t **out, size_t *outlen) +{ + size_t len = 0; + asn1_integer_to_der(sig->r, 32, NULL, &len); + asn1_integer_to_der(sig->s, 32, NULL, &len); + asn1_sequence_header_to_der(len, out, outlen); + asn1_integer_to_der(sig->r, 32, out, outlen); + asn1_integer_to_der(sig->s, 32, out, outlen); + return 1; +} + +int sm2_signature_from_der(SM2_SIGNATURE *sig, const uint8_t **in, size_t *inlen) +{ + const uint8_t *data, *r, *s; + size_t datalen, rlen, slen; + + if (asn1_sequence_from_der(&data, &datalen, in, inlen) < 0 + || asn1_integer_from_der(&r, &rlen, &data, &datalen) < 0 + || asn1_integer_from_der(&s, &slen, &data, &datalen) < 0 + || datalen > 0) { + return -1; + } + if (rlen != 32 || slen != 32) { + return -2; + } + + memcpy(sig->r, r, 32); + memcpy(sig->s, s, 32); + return 1; +} + +int sm2_ciphertext_to_der(const SM2_CIPHERTEXT *c, uint8_t **out, size_t *outlen) +{ + size_t len = 0; + asn1_integer_to_der(c->point.x, 32, NULL, &len); + asn1_integer_to_der(c->point.y, 32, NULL, &len); + asn1_octet_string_to_der(c->hash, 32, NULL, &len); + asn1_octet_string_to_der(c->ciphertext, c->ciphertext_size, NULL, &len); + asn1_sequence_header_to_der(len, out, outlen); + asn1_integer_to_der(c->point.x, 32, out, outlen); + asn1_integer_to_der(c->point.y, 32, out, outlen); + asn1_octet_string_to_der(c->hash, 32, out, outlen); + asn1_octet_string_to_der(c->ciphertext, c->ciphertext_size, out, outlen); + return 1; +} + +int sm2_ciphertext_from_der(SM2_CIPHERTEXT *a, const uint8_t **in, size_t *inlen) +{ + const uint8_t *data, *x, *y, *hash, *c; + size_t datalen, xlen, ylen, hashlen, clen; + + if (asn1_sequence_from_der(&data, &datalen, in, inlen) < 0 + || asn1_integer_from_der(&x, &xlen, &data, &datalen) < 0 + || asn1_integer_from_der(&y, &ylen, &data, &datalen) < 0 + || asn1_octet_string_from_der(&hash, &hashlen, &data, &datalen) < 0 + || asn1_octet_string_from_der(&c, &clen, &data, &datalen) < 0 + || datalen > 0) { + return -1; + } + if (xlen != 32 + || ylen != 32 + || hashlen != 32 + || clen < 1) { + return -1; + } + + memcpy(a->point.x, x, 32); + memcpy(a->point.y, y, 32); + memcpy(a->hash, hash, 32); + memcpy(a->ciphertext, c, clen); + a->ciphertext_size = (uint32_t)clen; + return 1; +} + +/* +from RFC 5915 + +ECPrivateKey ::= SEQUENCE { + version INTEGER, -- value MUST be ecPrivkeyVer1(1) + privateKey OCTET STRING, -- big endian encoding of integer + parameters [0] EXPLICIT ECParameters OPTIONAL, + -- ONLY namedCurve OID is permitted, by RFC 5480 + -- MUST always include this field, by RFC 5915 + publicKey [1] EXPLICIT BIT STRING OPTIONAL + -- SHOULD always include this field, by RFC 5915 +} + +ECParameters ::= CHOICE { + namedCurve OBJECT IDENTIFIER +} +*/ +int sm2_private_key_to_der(const SM2_KEY *key, uint8_t **out, size_t *outlen) +{ + int version = 1; + uint8_t public_key[65]; + size_t len = 0; + size_t params_len = 0; + size_t pubkey_len = 0; + + sm2_point_to_uncompressed_octets(&key->public_key, public_key); + + asn1_int_to_der(version, NULL, &len); + asn1_octet_string_to_der(key->private_key, 32, NULL, &len); + asn1_object_identifier_to_der(OID_sm2, NULL, 0, NULL, ¶ms_len); + asn1_explicit_to_der(0, NULL, params_len, NULL, &len); + asn1_bit_string_to_der(public_key, sizeof(public_key) * 8, NULL, &pubkey_len); + asn1_explicit_to_der(1, NULL, pubkey_len, NULL, &len); + + asn1_sequence_header_to_der(len, out, outlen); + asn1_int_to_der(version, out, outlen); + asn1_octet_string_to_der(key->private_key, 32, out, outlen); + asn1_explicit_header_to_der(0, params_len, out, outlen); + asn1_object_identifier_to_der(OID_sm2, NULL, 0, out, outlen); + asn1_explicit_header_to_der(1, pubkey_len, out, outlen); + asn1_bit_string_to_der(public_key, sizeof(public_key) * 8, out, outlen); + + return 1; +} + +int sm2_private_key_from_der(SM2_KEY *key, const uint8_t **in, size_t *inlen) +{ + int ret; + const uint8_t *data; + size_t datalen; + int version; + const uint8_t *prikey; + const uint8_t *params; + const uint8_t *pubkey; + size_t prikey_len; + size_t params_len; + size_t pubkey_len; + + memset(key, 0, sizeof(SM2_KEY)); + + if ((ret = asn1_sequence_from_der(&data, &datalen, in, inlen)) != 1) { + if (ret < 0) error_print(); + return ret; + } + if (asn1_int_from_der(&version, &data, &datalen) != 1 + || asn1_octet_string_from_der(&prikey, &prikey_len, &data, &datalen) != 1 + || asn1_explicit_from_der(0, ¶ms, ¶ms_len, &data, &datalen) < 0 + || asn1_explicit_from_der(1, &pubkey, &pubkey_len, &data, &datalen) < 0 + || datalen > 0) { + return -1; + } + if (version != 1) { + error_print(); + return -1; + } + if (prikey_len != 32) { + error_print(); + return -1; + } + if (sm2_set_private_key(key, prikey) != 1) { + error_print(); + return -1; + } + if (params) { + int curve_oid; + uint32_t nodes[16]; + size_t nodes_count; + + if (asn1_object_identifier_from_der(&curve_oid, nodes, &nodes_count, ¶ms, ¶ms_len) != 1 + || params_len > 0) { + error_print(); + return -1; + } + if (curve_oid != OID_sm2) { + error_print(); + return -1; + } + } + if (pubkey) { + const uint8_t *bits; + size_t nbits; + + if (asn1_bit_string_from_der(&bits, &nbits, &pubkey, &pubkey_len) != 1 + || pubkey_len > 0) { + error_print(); + return -1; + } + if (nbits % 8) { + error_print(); + return -1; + } + if (sm2_point_from_octets(&key->public_key, bits, nbits/8) != 1) { + error_print(); + return -1; + } + } + + return 1; +} + +/* +AlgorithmIdentifier ::= { + algorithm OBJECT IDENTIFIER { id-ecPublicKey }, + parameters OBJECT IDENTIFIER { id-sm2 } } +*/ +int sm2_public_key_algor_to_der(uint8_t **out, size_t *outlen) +{ + size_t len = 0; + asn1_object_identifier_to_der(OID_x9_62_ecPublicKey, NULL, 0, NULL, &len); + asn1_object_identifier_to_der(OID_sm2, NULL, 0, NULL, &len); + asn1_sequence_header_to_der(len, out, outlen); + asn1_object_identifier_to_der(OID_x9_62_ecPublicKey, NULL, 0, out, outlen); + asn1_object_identifier_to_der(OID_sm2, NULL, 0, out, outlen); + return 1; +} + +int sm2_public_key_algor_from_der(const uint8_t **in, size_t *inlen) +{ + int ret; + const uint8_t *data; + size_t datalen; + int oid; + uint32_t nodes[16]; + size_t nodes_count = 16; + + if ((ret = asn1_sequence_from_der(&data, &datalen, in, inlen)) != 1) { + if (ret < 0) error_print(); + return ret; + } + + if (asn1_object_identifier_from_der(&oid, nodes, &nodes_count, &data, &datalen) != 1 + || oid != OID_x9_62_ecPublicKey) { + error_print(); + return -1; + } + + if (asn1_object_identifier_from_der(&oid, nodes, &nodes_count, &data, &datalen) != 1 + || oid != OID_sm2) { + error_print(); + return -1; + } + if (datalen) { + error_print(); + return -1; + } + return 1; +} + +/* +from RFC 5208 + +PrivateKeyInfo ::= SEQUENCE { + version Version { v1(0) }, + privateKeyAlgorithm AlgorithmIdentifier, + privateKey OCTET STRING, -- DER-encoding of ECPrivateKey + attributes [0] IMPLICIT SET OF Attribute OPTIONAL +} +*/ +int sm2_private_key_info_to_der(const SM2_KEY *key, uint8_t **out, size_t *outlen) +{ + size_t len = 0; + uint8_t prikey[512]; + uint8_t *p = prikey; + size_t prikey_len = 0; + + sm2_private_key_to_der(key, &p, &prikey_len); + + asn1_int_to_der(0, NULL, &len); + sm2_public_key_algor_to_der(NULL, &len); + asn1_octet_string_to_der(prikey, prikey_len, NULL, &len); + asn1_sequence_header_to_der(len, out, outlen); + asn1_int_to_der(0, out, outlen); + sm2_public_key_algor_to_der(out, outlen); + asn1_octet_string_to_der(prikey, prikey_len, out, outlen); + return 1; +} + +int sm2_private_key_info_from_der(SM2_KEY *key, const uint8_t **attrs, size_t *attrslen, + const uint8_t **in, size_t *inlen) +{ + int ret; + const uint8_t *data; + size_t datalen; + int version; + const uint8_t *prikey; + size_t prikeylen; + + if ((ret = asn1_sequence_from_der(&data, &datalen, in, inlen)) != 1) { + if (ret < 0) error_print(); + return ret; + } + if (asn1_int_from_der(&version, &data, &datalen) != 1 + || sm2_public_key_algor_from_der(&data, &datalen) != 1 + || asn1_octet_string_from_der(&prikey, &prikeylen, &data, &datalen) != 1 + || asn1_implicit_set_from_der(0, attrs, attrslen, &data, &datalen) < 0 + || datalen > 0) { + error_print(); + return -1; + } + if (version != 0) { + error_print(); + return -1; + } + if (sm2_private_key_from_der(key, &prikey, &prikeylen) != 1 + || prikeylen > 0) { + error_print(); + return -1; + } + return 1; +} + +int sm2_private_key_info_to_pem(const SM2_KEY *key, FILE *fp) +{ + uint8_t buf[512]; + uint8_t *p = buf; + size_t len = 0; + + if (sm2_private_key_info_to_der(key, &p, &len) != 1) { + error_print(); + return -1; + } + if (pem_write(fp, "PRIVATE KEY", buf, len) <= 0) { + error_print(); + return -1; + } + return 1; +} + +int sm2_private_key_info_from_pem(SM2_KEY *key, const uint8_t **attrs, size_t *attrslen, FILE *fp) +{ + uint8_t buf[512]; + const uint8_t *cp = buf; + size_t len; + + if (pem_read(fp, "PRIVATE KEY", buf, &len) != 1) { + error_print(); + return -1; + } + if (sm2_private_key_info_from_der(key, attrs, attrslen, &cp, &len) != 1 + || len > 0) { + return -1; + } + return 1; +} + +/* +SubjectPublicKeyInfo ::= SEQUENCE { + algorithm AlgorithmIdentifier, + subjectPublicKey BIT STRING -- uncompressed octets of ECPoint +} +*/ +int sm2_public_key_info_to_der(const SM2_KEY *a, uint8_t **out, size_t *outlen) +{ + size_t len = 0; + uint8_t bits[65]; + + sm2_point_to_uncompressed_octets(&a->public_key, bits); + + sm2_public_key_algor_to_der(NULL, &len); + asn1_bit_string_to_der(bits, sizeof(bits)*8, NULL, &len); + asn1_sequence_header_to_der(len, out, outlen); + sm2_public_key_algor_to_der(out, outlen); + asn1_bit_string_to_der(bits, sizeof(bits)*8, out, outlen); + return 1; +} + +int sm2_public_key_info_from_der(SM2_KEY *a, const uint8_t **in, size_t *inlen) +{ + int ret; + const uint8_t *data; + size_t datalen; + const uint8_t *bits; + size_t nbits; + SM2_POINT point; + + if ((ret = asn1_sequence_from_der(&data, &datalen, in, inlen)) != 1) { + if (ret < 0) error_print(); + return ret; + } + if (sm2_public_key_algor_from_der(&data, &datalen) != 1 + || asn1_bit_string_from_der(&bits, &nbits, &data, &datalen) != 1 + || datalen > 0) { + error_print(); + return -1; + } + + if (nbits % 8) { + error_print(); + return -1; + } + if (sm2_point_from_octets(&point, bits, nbits/8) != 1) { + error_print(); + return -1; + } + memset(a, 0, sizeof(SM2_KEY)); + if (sm2_set_public_key(a, (uint8_t *)&point) != 1) { + error_print(); + return -1; + } + return 1; +} + +int sm2_private_key_to_pem(const SM2_KEY *a, FILE *fp) +{ + uint8_t buf[512]; + uint8_t *p = buf; + size_t len = 0; + + if (sm2_private_key_to_der(a, &p, &len) != 1) { + error_print(); + return -1; + } + if (pem_write(fp, "EC PRIVATE KEY", buf, len) <= 0) { + error_print(); + return -1; + } + return 1; +} + +int sm2_private_key_from_pem(SM2_KEY *a, FILE *fp) +{ + uint8_t buf[512]; + const uint8_t *cp = buf; + size_t len; + + if (pem_read(fp, "EC PRIVATE KEY", buf, &len) != 1) { + error_print(); + return -1; + } + if (sm2_private_key_from_der(a, &cp, &len) != 1 + || len > 0) { + error_print(); + return -1; + } + return 1; +} + +int sm2_public_key_info_to_pem(const SM2_KEY *a, FILE *fp) +{ + uint8_t buf[512]; + uint8_t *p = buf; + size_t len = 0; + + if (sm2_public_key_info_to_der(a, &p, &len) != 1) { + error_print(); + return -1; + } + if (pem_write(fp, "PUBLIC KEY", buf, len) <= 0) { + error_print(); + return -1; + } + return 1; +} + +int sm2_public_key_info_from_pem(SM2_KEY *a, FILE *fp) +{ + uint8_t buf[512]; + const uint8_t *cp = buf; + size_t len; + + if (pem_read(fp, "PUBLIC KEY", buf, &len) != 1) { + error_print(); + return -1; + } + if (sm2_public_key_info_from_der(a, &cp, &len) != 1 + || len > 0) { + return -1; + } + return 1; +} + + +int sm2_public_key_digest(const SM2_KEY *sm2_key, uint8_t dgst[32]) +{ + uint8_t bits[65]; + sm2_point_to_uncompressed_octets(&sm2_key->public_key, bits); + sm3_digest(bits, sizeof(bits), dgst); + return 1; +} + diff --git a/src/sm2_lib.c b/src/sm2_lib.c new file mode 100644 index 00000000..ab12cbcf --- /dev/null +++ b/src/sm2_lib.c @@ -0,0 +1,277 @@ +/* + * Copyright (c) 2014 - 2020 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + + +#include +#include +#include +#include +#include +#include +#include "endian.h" + + +#define SM2_SIGNATURE_MAX_DER_SIZE 77 + +int sm2_sign(const SM2_KEY *key, const uint8_t dgst[32], uint8_t *der, size_t *derlen) +{ + SM2_SIGNATURE sig; + uint8_t *p = der; + size_t len = 0; + + if (!der && derlen) { + *derlen = SM2_SIGNATURE_MAX_DER_SIZE; + return 1; + } + if (!key || !der || !derlen) { + return -1; + } + + sm2_do_sign(key, dgst, &sig); + sm2_signature_to_der(&sig, &p, &len); + *derlen = len; + + return 1; +} + +int sm2_verify(const SM2_KEY *key, const uint8_t dgst[32], const uint8_t *der, size_t derlen) +{ + int ret; + SM2_SIGNATURE sig; + const uint8_t *p = der; + size_t len = derlen; + + if (!key || !der || !derlen) { + error_print(); + return -1; + } + if (sm2_signature_from_der(&sig, &p, &len) < 0 + || len > 0) { + error_print(); + return -2; + } + if ((ret = sm2_do_verify(key, dgst, &sig)) != 1) { + error_print(); + } + return ret; +} + +int sm2_encrypt(const SM2_KEY *key, const uint8_t *in, size_t inlen, uint8_t *out, size_t *outlen) +{ + size_t clen = SM2_CIPHERTEXT_SIZE(inlen); + size_t cbuf[clen]; + SM2_CIPHERTEXT *c = (SM2_CIPHERTEXT *)cbuf; + + sm2_do_encrypt(key, in, inlen, c); + + *outlen = 0; + sm2_ciphertext_to_der(c, &out, outlen); + return 1; +} + +int sm2_decrypt(const SM2_KEY *key, const uint8_t *in, size_t inlen, uint8_t *out, size_t *outlen) +{ + size_t cbuf[inlen]; + SM2_CIPHERTEXT *c = (SM2_CIPHERTEXT *)cbuf; + + sm2_ciphertext_from_der(c, &in, &inlen); // FIXME: 检查是否有剩余长度 + sm2_do_decrypt(key, c, out, outlen); + return 1; +} + +extern void sm3_compress_blocks(uint32_t digest[8], const uint8_t *data, size_t blocks); + +int sm2_compute_z(uint8_t z[32], const SM2_POINT *pub, const char *id) +{ + uint8_t zin[] = { + 0x00, 0x80, + 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, + 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, + 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, + 0x28, 0xE9, 0xFA, 0x9E, 0x9D, 0x9F, 0x5E, 0x34, + 0x4D, 0x5A, 0x9E, 0x4B, 0xCF, 0x65, 0x09, 0xA7, + 0xF3, 0x97, 0x89, 0xF5, 0x15, 0xAB, 0x8F, 0x92, + 0xDD, 0xBC, 0xBD, 0x41, 0x4D, 0x94, 0x0E, 0x93, + 0x32, 0xC4, 0xAE, 0x2C, 0x1F, 0x19, 0x81, 0x19, + 0x5F, 0x99, 0x04, 0x46, 0x6A, 0x39, 0xC9, 0x94, + 0x8F, 0xE3, 0x0B, 0xBF, 0xF2, 0x66, 0x0B, 0xE1, + 0x71, 0x5A, 0x45, 0x89, 0x33, 0x4C, 0x74, 0xC7, + 0xBC, 0x37, 0x36, 0xA2, 0xF4, 0xF6, 0x77, 0x9C, + 0x59, 0xBD, 0xCE, 0xE3, 0x6B, 0x69, 0x21, 0x53, + 0xD0, 0xA9, 0x87, 0x7C, 0xC6, 0x2A, 0x47, 0x40, + 0x02, 0xDF, 0x32, 0xE5, 0x21, 0x39, 0xF0, 0xA0, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x06, 0x90, + }; + + if (!id || strcmp(id, "1234567812345678")) { + uint32_t digest[8] = { + 0xadadedb5U, 0x0446043fU, 0x08a87aceU, 0xe86d2243U, + 0x8e232383U, 0xbfc81fe2U, 0xcf9117c8U, 0x4707011dU, + }; + memcpy(&zin[128], pub->x, 32); + memcpy(&zin[160], pub->y, 32); + sm3_compress_blocks(digest, zin, 2); + PUTU32(z , digest[0]); + PUTU32(z + 4, digest[1]); + PUTU32(z + 8, digest[2]); + PUTU32(z + 12, digest[3]); + PUTU32(z + 16, digest[4]); + PUTU32(z + 20, digest[5]); + PUTU32(z + 24, digest[6]); + PUTU32(z + 28, digest[7]); + + } else { + SM3_CTX ctx; + uint8_t idbits[2]; + size_t len; + + len = strlen(id); + idbits[0] = (uint8_t)(len >> 5); + idbits[1] = (uint8_t)(len << 3); + + sm3_init(&ctx); + sm3_update(&ctx, idbits, 2); + sm3_update(&ctx, (uint8_t *)id, len); + sm3_update(&ctx, zin + 18, 128); + sm3_update(&ctx, pub->x, 32); + sm3_update(&ctx, pub->y, 32); + sm3_finish(&ctx, z); + } + + return 0; +} + +int sm2_sign_init(SM2_SIGN_CTX *ctx, const SM2_KEY *key, const char *id) +{ + uint8_t z[32]; + if (!ctx || !key || !id || strlen(id) > SM2_MAX_ID_SIZE) { + return -1; + } + sm2_compute_z(z, &key->public_key, id); + + sm3_init(&ctx->sm3_ctx); + sm3_update(&ctx->sm3_ctx, z, 32); + memcpy(&ctx->key, key, sizeof(SM2_KEY)); + return 1; +} + +int sm2_sign_update(SM2_SIGN_CTX *ctx, const uint8_t *data, size_t datalen) +{ + sm3_update(&ctx->sm3_ctx, data, datalen); + return 1; +} + +int sm2_sign_finish(SM2_SIGN_CTX *ctx, uint8_t *sig, size_t *siglen) +{ + uint8_t dgst[32]; + sm3_finish(&ctx->sm3_ctx, dgst); + sm2_sign(&ctx->key, dgst, sig, siglen); + return 1; +} + +int sm2_sign_resume(SM2_SIGN_CTX *ctx) +{ + return 0; +} + +int sm2_verify_init(SM2_SIGN_CTX *ctx, const SM2_KEY *key, const char *id) +{ + uint8_t z[32]; + if (!ctx || !key || !id || strlen(id) > SM2_MAX_ID_SIZE) { + return -1; + } + sm2_compute_z(z, &key->public_key, id); + sm3_init(&ctx->sm3_ctx); + sm3_update(&ctx->sm3_ctx, z, 32); + memcpy(&ctx->key, key, sizeof(SM2_KEY)); + return 1; +} + +int sm2_verify_update(SM2_SIGN_CTX *ctx, const uint8_t *data, size_t datalen) +{ + sm3_update(&ctx->sm3_ctx, data, datalen); + return 1; +} + +int sm2_verify_finish(SM2_SIGN_CTX *ctx, const uint8_t *sig, size_t siglen) +{ + int ret; + uint8_t dgst[32]; + sm3_finish(&ctx->sm3_ctx, dgst); + ret = sm2_verify(&ctx->key, dgst, sig, siglen); + return ret; +} + +int sm2_set_private_key(SM2_KEY *key, const uint8_t private_key[32]) +{ + memcpy(&key->private_key, private_key, 32); + return 1; +} + +// FIXME: 检查公钥是否正确 +int sm2_set_public_key(SM2_KEY *key, const uint8_t public_key[64]) +{ + memcpy(&key->public_key, public_key, 64); + return 1; +} diff --git a/src/sm2_prn.c b/src/sm2_prn.c new file mode 100644 index 00000000..0b258c44 --- /dev/null +++ b/src/sm2_prn.c @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2014 - 2020 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + + +#include +#include +#include +#include +#include + + +int sm2_key_print(FILE *fp, const SM2_KEY *key, int format, int indent) +{ + format_print(fp, format, indent, "SM2PrivateKey\n"); + indent += 4; + format_bytes(fp, format, indent, "private_key : ", key->private_key, 32); + format_print(fp, format, indent, "public_key\n"); + sm2_point_print(fp, &key->public_key, format, indent + 4); + //format_bytes(fp, format, indent + 4, "x : ", (uint8_t *)&key->public_key, 32); + //format_bytes(fp, format, indent + 4, "y : ", (uint8_t *)&key->public_key + 32, 32); + return 1; +} + +int sm2_point_print(FILE *fp, const SM2_POINT *P, int format, int indent) +{ + format_bytes(fp, format, indent, "x : ", P->x, 32); + format_bytes(fp, format, indent, "y : ", P->y, 32); + return 1; +} + +int sm2_print_signature(FILE *fp, const uint8_t *der, size_t derlen, int format, int indent) +{ + uint8_t buf[sizeof(SM2_SIGNATURE)] = {0}; + SM2_SIGNATURE *sig = (SM2_SIGNATURE *)buf; + const uint8_t *p = der; + int i; + + if (sm2_signature_from_der(sig, &p, &derlen) < 0) { + fprintf(stderr, "error: %s %d: invalid signature DER encoding\n", __FILE__, __LINE__); + } + if (derlen > 0) { + fprintf(stderr, "error: %s %d: %zu extra bytes at the end of DER\n", __FILE__, __LINE__, derlen); + } + + format_bytes(fp, format, indent, "r : ", sig->r, 32); + format_bytes(fp, format, indent, "s : ", sig->s, 32); + return 1; +} + +int sm2_print_ciphertext(FILE *fp, const uint8_t *der, size_t derlen, int format, int indent) +{ + uint8_t buf[512 /* derlen */] = {0}; //FIXME: add -std=c99 to CMakeList.txt + SM2_CIPHERTEXT *c = (SM2_CIPHERTEXT *)buf; + const uint8_t *p = der; + int i; + + if (sm2_ciphertext_from_der(c, &p, &derlen) < 0) { + fprintf(stderr, "error: %s %d: invalid ciphertext DER encoding\n", __FILE__, __LINE__); + } + if (derlen > 0) { + fprintf(stderr, "error: %s %d: %zu extra bytes at the end of DER\n", __FILE__, __LINE__, derlen); + } + sm2_ciphertext_print(fp, c, format, indent); + return 1; +} + +int sm2_ciphertext_print(FILE *fp, const SM2_CIPHERTEXT *c, int format, int indent) +{ + format_bytes(fp, format, indent, "x", c->point.x, 32); + format_bytes(fp, format, indent, "y", c->point.y, 32); + format_bytes(fp, format, indent, "hash", c->hash, 32); + format_bytes(fp, format, indent, "ciphertext", c->ciphertext, c->ciphertext_size); + return 1; +} diff --git a/src/sm3.c b/src/sm3.c new file mode 100755 index 00000000..d6347d28 --- /dev/null +++ b/src/sm3.c @@ -0,0 +1,506 @@ +/* ==================================================================== + * Copyright (c) 2014 - 2017 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + * ==================================================================== + */ + +#include +#include +#include "bswap.h" +#include "rotate.h" + +#ifdef SM3_SSE3 +# include +# include + +# define _mm_rotl_epi32(X,i) \ + _mm_xor_si128(_mm_slli_epi32((X),(i)), _mm_srli_epi32((X),32-(i))) +#endif + +void sm3_compress_blocks(uint32_t digest[8], const uint8_t *data, size_t blocks); + + +void sm3_init(SM3_CTX *ctx) +{ + memset(ctx, 0, sizeof(*ctx)); + ctx->digest[0] = 0x7380166F; + ctx->digest[1] = 0x4914B2B9; + ctx->digest[2] = 0x172442D7; + ctx->digest[3] = 0xDA8A0600; + ctx->digest[4] = 0xA96F30BC; + ctx->digest[5] = 0x163138AA; + ctx->digest[6] = 0xE38DEE4D; + ctx->digest[7] = 0xB0FB0E4E; +} + +#if 0 +void sm3_compute_id_digest(uint8_t z[32], const char *id, + const uint8_t x[32], const uint8_t y[32]) +{ + uint8_t zin[] = { + 0x00, 0x80, + 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, + 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, + 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, + 0x28, 0xE9, 0xFA, 0x9E, 0x9D, 0x9F, 0x5E, 0x34, + 0x4D, 0x5A, 0x9E, 0x4B, 0xCF, 0x65, 0x09, 0xA7, + 0xF3, 0x97, 0x89, 0xF5, 0x15, 0xAB, 0x8F, 0x92, + 0xDD, 0xBC, 0xBD, 0x41, 0x4D, 0x94, 0x0E, 0x93, + 0x32, 0xC4, 0xAE, 0x2C, 0x1F, 0x19, 0x81, 0x19, + 0x5F, 0x99, 0x04, 0x46, 0x6A, 0x39, 0xC9, 0x94, + 0x8F, 0xE3, 0x0B, 0xBF, 0xF2, 0x66, 0x0B, 0xE1, + 0x71, 0x5A, 0x45, 0x89, 0x33, 0x4C, 0x74, 0xC7, + 0xBC, 0x37, 0x36, 0xA2, 0xF4, 0xF6, 0x77, 0x9C, + 0x59, 0xBD, 0xCE, 0xE3, 0x6B, 0x69, 0x21, 0x53, + 0xD0, 0xA9, 0x87, 0x7C, 0xC6, 0x2A, 0x47, 0x40, + 0x02, 0xDF, 0x32, 0xE5, 0x21, 0x39, 0xF0, 0xA0, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x06, 0x90, + }; + + if (!id || strcmp(id, "1234567812345678")) { + unsigned int digest[8] = { + 0xadadedb5U, 0x0446043fU, 0x08a87aceU, 0xe86d2243U, + 0x8e232383U, 0xbfc81fe2U, 0xcf9117c8U, 0x4707011dU, + }; + memcpy(&zin[128], x, 32); + memcpy(&zin[160], y, 32); + sm3_compress_blocks(digest, zin, 2); + PUTU32(z , digest[0]); + PUTU32(z + 4, digest[1]); + PUTU32(z + 8, digest[2]); + PUTU32(z + 12, digest[3]); + PUTU32(z + 16, digest[4]); + PUTU32(z + 20, digest[5]); + PUTU32(z + 24, digest[6]); + PUTU32(z + 28, digest[7]); + + } else { + SM3_CTX ctx; + uint8_t idbits[2]; + size_t len; + + len = strlen(id); + idbits[0] = (uint8_t)(len >> 5); + idbits[1] = (uint8_t)(len << 3); + + sm3_init(&ctx); + sm3_update(&ctx, idbits, 2); + sm3_update(&ctx, (uint8_t *)id, len); + sm3_update(&ctx, zin + 18, 128); + sm3_update(&ctx, x, 32); + sm3_update(&ctx, y, 32); + sm3_finish(&ctx, z); + } +} + +int sm3_sm2_init(SM3_CTX *ctx, const char *id, + const uint8_t *x, const uint8_t *y) +{ + uint8_t z[32]; + if ((id && strlen(id) > 65535/8) || !x || !y) { + return 0; + } + sm3_compute_id_digest(z, id, x, y); + sm3_init(ctx); + sm3_update(ctx, z, 32); + return 1; +} +#endif + +void sm3_update(SM3_CTX *ctx, const uint8_t *data, size_t data_len) +{ + size_t blocks; + + if (ctx->num) { + unsigned int left = SM3_BLOCK_SIZE - ctx->num; + if (data_len < left) { + memcpy(ctx->block + ctx->num, data, data_len); + ctx->num += data_len; + return; + } else { + memcpy(ctx->block + ctx->num, data, left); + sm3_compress_blocks(ctx->digest, ctx->block, 1); + ctx->nblocks++; + data += left; + data_len -= left; + } + } + + blocks = data_len / SM3_BLOCK_SIZE; + sm3_compress_blocks(ctx->digest, data, blocks); + ctx->nblocks += blocks; + data += SM3_BLOCK_SIZE * blocks; + data_len -= SM3_BLOCK_SIZE * blocks; + + ctx->num = data_len; + if (data_len) { + memcpy(ctx->block, data, data_len); + } +} + +void sm3_finish(SM3_CTX *ctx, uint8_t *digest) +{ + int i; + + ctx->block[ctx->num] = 0x80; + + if (ctx->num + 9 <= SM3_BLOCK_SIZE) { + memset(ctx->block + ctx->num + 1, 0, SM3_BLOCK_SIZE - ctx->num - 9); + } else { + memset(ctx->block + ctx->num + 1, 0, SM3_BLOCK_SIZE - ctx->num - 1); + sm3_compress(ctx->digest, ctx->block); + memset(ctx->block, 0, SM3_BLOCK_SIZE - 8); + } + PUTU32(ctx->block + 56, ctx->nblocks >> 23); + PUTU32(ctx->block + 60, (ctx->nblocks << 9) + (ctx->num << 3)); + + sm3_compress(ctx->digest, ctx->block); + for (i = 0; i < 8; i++) { + PUTU32(digest + i*4, ctx->digest[i]); + } + memset(ctx, 0, sizeof(SM3_CTX)); +} + +#define ROTL(x,n) (((x)<<(n)) | ((x)>>(32-(n)))) +#define P0(x) ((x) ^ ROL32((x), 9) ^ ROL32((x),17)) +#define P1(x) ((x) ^ ROL32((x),15) ^ ROL32((x),23)) + +#define FF00(x,y,z) ((x) ^ (y) ^ (z)) +#define FF16(x,y,z) (((x)&(y)) | ((x)&(z)) | ((y)&(z))) +#define GG00(x,y,z) ((x) ^ (y) ^ (z)) +#define GG16(x,y,z) ((((y)^(z)) & (x)) ^ (z)) + +#define R(A, B, C, D, E, F, G, H, xx) \ + SS1 = ROL32((ROL32(A, 12) + E + K[j]), 7); \ + SS2 = SS1 ^ ROL32(A, 12); \ + TT1 = FF##xx(A, B, C) + D + SS2 + (W[j] ^ W[j + 4]); \ + TT2 = GG##xx(E, F, G) + H + SS1 + W[j]; \ + B = ROL32(B, 9); \ + H = TT1; \ + F = ROL32(F, 19); \ + D = P0(TT2); \ + j++ + +#define R8(A, B, C, D, E, F, G, H, xx) \ + R(A, B, C, D, E, F, G, H, xx); \ + R(H, A, B, C, D, E, F, G, xx); \ + R(G, H, A, B, C, D, E, F, xx); \ + R(F, G, H, A, B, C, D, E, xx); \ + R(E, F, G, H, A, B, C, D, xx); \ + R(D, E, F, G, H, A, B, C, xx); \ + R(C, D, E, F, G, H, A, B, xx); \ + R(B, C, D, E, F, G, H, A, xx) + + + +#define T00 0x79cc4519U +#define T16 0x7a879d8aU + +#define K0 0x79cc4519U +#define K1 0xf3988a32U +#define K2 0xe7311465U +#define K3 0xce6228cbU +#define K4 0x9cc45197U +#define K5 0x3988a32fU +#define K6 0x7311465eU +#define K7 0xe6228cbcU +#define K8 0xcc451979U +#define K9 0x988a32f3U +#define K10 0x311465e7U +#define K11 0x6228cbceU +#define K12 0xc451979cU +#define K13 0x88a32f39U +#define K14 0x11465e73U +#define K15 0x228cbce6U +#define K16 0x9d8a7a87U +#define K17 0x3b14f50fU +#define K18 0x7629ea1eU +#define K19 0xec53d43cU +#define K20 0xd8a7a879U +#define K21 0xb14f50f3U +#define K22 0x629ea1e7U +#define K23 0xc53d43ceU +#define K24 0x8a7a879dU +#define K25 0x14f50f3bU +#define K26 0x29ea1e76U +#define K27 0x53d43cecU +#define K28 0xa7a879d8U +#define K29 0x4f50f3b1U +#define K30 0x9ea1e762U +#define K31 0x3d43cec5U +#define K32 0x7a879d8aU +#define K33 0xf50f3b14U +#define K34 0xea1e7629U +#define K35 0xd43cec53U +#define K36 0xa879d8a7U +#define K37 0x50f3b14fU +#define K38 0xa1e7629eU +#define K39 0x43cec53dU +#define K40 0x879d8a7aU +#define K41 0x0f3b14f5U +#define K42 0x1e7629eaU +#define K43 0x3cec53d4U +#define K44 0x79d8a7a8U +#define K45 0xf3b14f50U +#define K46 0xe7629ea1U +#define K47 0xcec53d43U +#define K48 0x9d8a7a87U +#define K49 0x3b14f50fU +#define K50 0x7629ea1eU +#define K51 0xec53d43cU +#define K52 0xd8a7a879U +#define K53 0xb14f50f3U +#define K54 0x629ea1e7U +#define K55 0xc53d43ceU +#define K56 0x8a7a879dU +#define K57 0x14f50f3bU +#define K58 0x29ea1e76U +#define K59 0x53d43cecU +#define K60 0xa7a879d8U +#define K61 0x4f50f3b1U +#define K62 0x9ea1e762U +#define K63 0x3d43cec5U + +uint32_t K[64] = { + K0, K1, K2, K3, K4, K5, K6, K7, + K8, K9, K10, K11, K12, K13, K14, K15, + K16, K17, K18, K19, K20, K21, K22, K23, + K24, K25, K26, K27, K28, K29, K30, K31, + K32, K33, K34, K35, K36, K37, K38, K39, + K40, K41, K42, K43, K44, K45, K46, K47, + K48, K49, K50, K51, K52, K53, K54, K55, + K56, K57, K58, K59, K60, K61, K62, K63, + /* + 0x79cc4519U, 0xf3988a32U, 0xe7311465U, 0xce6228cbU, + 0x9cc45197U, 0x3988a32fU, 0x7311465eU, 0xe6228cbcU, + 0xcc451979U, 0x988a32f3U, 0x311465e7U, 0x6228cbceU, + 0xc451979cU, 0x88a32f39U, 0x11465e73U, 0x228cbce6U, + 0x9d8a7a87U, 0x3b14f50fU, 0x7629ea1eU, 0xec53d43cU, + 0xd8a7a879U, 0xb14f50f3U, 0x629ea1e7U, 0xc53d43ceU, + 0x8a7a879dU, 0x14f50f3bU, 0x29ea1e76U, 0x53d43cecU, + 0xa7a879d8U, 0x4f50f3b1U, 0x9ea1e762U, 0x3d43cec5U, + 0x7a879d8aU, 0xf50f3b14U, 0xea1e7629U, 0xd43cec53U, + 0xa879d8a7U, 0x50f3b14fU, 0xa1e7629eU, 0x43cec53dU, + 0x879d8a7aU, 0x0f3b14f5U, 0x1e7629eaU, 0x3cec53d4U, + 0x79d8a7a8U, 0xf3b14f50U, 0xe7629ea1U, 0xcec53d43U, + 0x9d8a7a87U, 0x3b14f50fU, 0x7629ea1eU, 0xec53d43cU, + 0xd8a7a879U, 0xb14f50f3U, 0x629ea1e7U, 0xc53d43ceU, + 0x8a7a879dU, 0x14f50f3bU, 0x29ea1e76U, 0x53d43cecU, + 0xa7a879d8U, 0x4f50f3b1U, 0x9ea1e762U, 0x3d43cec5U, + */ +}; + +void sm3_compress_blocks(uint32_t digest[8], const uint8_t *data, size_t blocks) +{ + uint32_t A; + uint32_t B; + uint32_t C; + uint32_t D; + uint32_t E; + uint32_t F; + uint32_t G; + uint32_t H; + uint32_t W[68]; + uint32_t SS1, SS2, TT1, TT2; + int j; + +#ifdef SM3_SSE3 + __m128i X, T, R; + __m128i M = _mm_setr_epi32(0, 0, 0, 0xffffffff); + __m128i V = _mm_setr_epi8(3,2,1,0,7,6,5,4,11,10,9,8,15,14,13,12); +#endif + + while (blocks--) { + + A = digest[0]; + B = digest[1]; + C = digest[2]; + D = digest[3]; + E = digest[4]; + F = digest[5]; + G = digest[6]; + H = digest[7]; + + +#ifdef SM3_SSE3 + + for (j = 0; j < 16; j += 4) { + X = _mm_loadu_si128((__m128i *)(data + j * 4)); + X = _mm_shuffle_epi8(X, V); + _mm_storeu_si128((__m128i *)(W + j), X); + } + + for (j = 16; j < 68; j += 4) { + /* X = (W[j - 3], W[j - 2], W[j - 1], 0) */ + X = _mm_loadu_si128((__m128i *)(W + j - 3)); + X = _mm_andnot_si128(M, X); + + X = _mm_rotl_epi32(X, 15); + T = _mm_loadu_si128((__m128i *)(W + j - 9)); + X = _mm_xor_si128(X, T); + T = _mm_loadu_si128((__m128i *)(W + j - 16)); + X = _mm_xor_si128(X, T); + + /* P1() */ + T = _mm_rotl_epi32(X, (23 - 15)); + T = _mm_xor_si128(T, X); + T = _mm_rotl_epi32(T, 15); + X = _mm_xor_si128(X, T); + + T = _mm_loadu_si128((__m128i *)(W + j - 13)); + T = _mm_rotl_epi32(T, 7); + X = _mm_xor_si128(X, T); + T = _mm_loadu_si128((__m128i *)(W + j - 6)); + X = _mm_xor_si128(X, T); + + /* W[j + 3] ^= P1(ROL32(W[j + 1], 15)) */ + R = _mm_shuffle_epi32(X, 0); + R = _mm_and_si128(R, M); + T = _mm_rotl_epi32(R, 15); + T = _mm_xor_si128(T, R); + T = _mm_rotl_epi32(T, 9); + R = _mm_xor_si128(R, T); + R = _mm_rotl_epi32(R, 6); + X = _mm_xor_si128(X, R); + + _mm_storeu_si128((__m128i *)(W + j), X); + } +#else + for (j = 0; j < 16; j++) + W[j] = GETU32(data + j*4); + + for (; j < 68; j++) + W[j] = P1(W[j - 16] ^ W[j - 9] ^ ROL32(W[j - 3], 15)) + ^ ROL32(W[j - 13], 7) ^ W[j - 6]; +#endif + + + j = 0; + +#define FULL_UNROLL +#ifdef FULL_UNROLL + R8(A, B, C, D, E, F, G, H, 00); + R8(A, B, C, D, E, F, G, H, 00); + R8(A, B, C, D, E, F, G, H, 16); + R8(A, B, C, D, E, F, G, H, 16); + R8(A, B, C, D, E, F, G, H, 16); + R8(A, B, C, D, E, F, G, H, 16); + R8(A, B, C, D, E, F, G, H, 16); + R8(A, B, C, D, E, F, G, H, 16); +#else + for (; j < 16; j++) { + SS1 = ROL32((ROL32(A, 12) + E + K(j)), 7); + SS2 = SS1 ^ ROL32(A, 12); + TT1 = FF00(A, B, C) + D + SS2 + (W[j] ^ W[j + 4]); + TT2 = GG00(E, F, G) + H + SS1 + W[j]; + D = C; + C = ROL32(B, 9); + B = A; + A = TT1; + H = G; + G = ROL32(F, 19); + F = E; + E = P0(TT2); + } + + for (; j < 64; j++) { + SS1 = ROL32((ROL32(A, 12) + E + K(j)), 7); + SS2 = SS1 ^ ROL32(A, 12); + TT1 = FF16(A, B, C) + D + SS2 + (W[j] ^ W[j + 4]); + TT2 = GG16(E, F, G) + H + SS1 + W[j]; + D = C; + C = ROL32(B, 9); + B = A; + A = TT1; + H = G; + G = ROL32(F, 19); + F = E; + E = P0(TT2); + } +#endif + + digest[0] ^= A; + digest[1] ^= B; + digest[2] ^= C; + digest[3] ^= D; + digest[4] ^= E; + digest[5] ^= F; + digest[6] ^= G; + digest[7] ^= H; + + data += 64; + } +} + +void sm3_compress(uint32_t digest[8], const uint8_t block[64]) +{ + return sm3_compress_blocks(digest, block, 1); +} + +void sm3_digest(const uint8_t *msg, size_t msglen, + uint8_t dgst[SM3_DIGEST_SIZE]) +{ + SM3_CTX ctx; + sm3_init(&ctx); + sm3_update(&ctx, msg, msglen); + sm3_finish(&ctx, dgst); +} diff --git a/src/sm3_hmac.c b/src/sm3_hmac.c new file mode 100644 index 00000000..f89ba3fd --- /dev/null +++ b/src/sm3_hmac.c @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2014 - 2021 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + + +#include +#include +#include + +/** + * HMAC_k(m) = H((k ^ opad) || H((k ^ ipad) || m)) + * pseudo-code: + * function hmac(key, message) + * opad = [0x5c * blocksize] + * ipad = [0x36 * blocksize] + * if (length(key) > blocksize) then + * key = hash(key) + * end if + * for i from 0 to length(key) - 1 step 1 + * ipad[i] = ipad[i] XOR key[i] + * opad[i] = opad[i] XOR key[i] + * end for + * return hash(opad || hash(ipad || message)) + * end function + */ + + +#define IPAD 0x36 +#define OPAD 0x5C + +void sm3_hmac_init(SM3_HMAC_CTX *ctx, const uint8_t *key, size_t key_len) +{ + int i; + + if (key_len <= SM3_BLOCK_SIZE) { + memcpy(ctx->key, key, key_len); + memset(ctx->key + key_len, 0, SM3_BLOCK_SIZE - key_len); + } else { + sm3_init(&ctx->sm3_ctx); + sm3_update(&ctx->sm3_ctx, key, key_len); + sm3_finish(&ctx->sm3_ctx, ctx->key); + memset(ctx->key + SM3_DIGEST_SIZE, 0, + SM3_BLOCK_SIZE - SM3_DIGEST_SIZE); + } + for (i = 0; i < SM3_BLOCK_SIZE; i++) { + ctx->key[i] ^= IPAD; + } + + sm3_init(&ctx->sm3_ctx); + sm3_update(&ctx->sm3_ctx, ctx->key, SM3_BLOCK_SIZE); +} + +void sm3_hmac_update(SM3_HMAC_CTX *ctx, const uint8_t *data, size_t data_len) +{ + sm3_update(&ctx->sm3_ctx, data, data_len); +} + +void sm3_hmac_finish(SM3_HMAC_CTX *ctx, uint8_t mac[SM3_HMAC_SIZE]) +{ + int i; + for (i = 0; i < SM3_BLOCK_SIZE; i++) { + ctx->key[i] ^= (IPAD ^ OPAD); + } + sm3_finish(&ctx->sm3_ctx, mac); + sm3_init(&ctx->sm3_ctx); + sm3_update(&ctx->sm3_ctx, ctx->key, SM3_BLOCK_SIZE); + sm3_update(&ctx->sm3_ctx, mac, SM3_DIGEST_SIZE); + sm3_finish(&ctx->sm3_ctx, mac); +} + +int sm3_hmac_finish_and_verify(SM3_HMAC_CTX *ctx, const uint8_t mac[SM3_HMAC_SIZE]) +{ + uint8_t buf[32]; + sm3_hmac_finish(ctx, buf); + if (memcmp(mac, buf, sizeof(buf)) == 0) { + return 1; + } else { + error_print("sm3_hmac verify failure"); + return 0; + } +} + +void sm3_hmac_reset(SM3_HMAC_CTX *ctx) +{ + sm3_init(&ctx->sm3_ctx); + sm3_update(&ctx->sm3_ctx, ctx->key, SM3_BLOCK_SIZE); + // 不应该保留原始密钥,而是应该保持这次update之后的状态 + // 这样可以降低reset的工作量 +} + +void sm3_hmac(const uint8_t *data, size_t data_len, + const uint8_t *key, size_t key_len, + uint8_t mac[SM3_HMAC_SIZE]) +{ + SM3_HMAC_CTX ctx; + sm3_hmac_init(&ctx, key, key_len); + sm3_hmac_update(&ctx, data, data_len); + sm3_hmac_finish(&ctx, mac); + memset(&ctx, 0, sizeof(ctx)); +} diff --git a/src/sm4_avx2.c b/src/sm4_avx2.c new file mode 100644 index 00000000..d9102eca --- /dev/null +++ b/src/sm4_avx2.c @@ -0,0 +1,208 @@ +/* ==================================================================== + * Copyright (c) 2014 - 2019 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + * ==================================================================== + */ + +#include +#include "internal/bswap.h" +#include "internal/rotate.h" +#include "sm4_lcl.h" + +#ifdef SMS4_AVX2 +# include + +# define GET_BLKS(x0, x1, x2, x3, in) \ + t0 = _mm256_i32gather_epi32((int *)(in+4*0), vindex_4i, 4); \ + t1 = _mm256_i32gather_epi32((int *)(in+4*1), vindex_4i, 4); \ + t2 = _mm256_i32gather_epi32((int *)(in+4*2), vindex_4i, 4); \ + t3 = _mm256_i32gather_epi32((int *)(in+4*3), vindex_4i, 4); \ + x0 = _mm256_shuffle_epi8(t0, vindex_swap); \ + x1 = _mm256_shuffle_epi8(t1, vindex_swap); \ + x2 = _mm256_shuffle_epi8(t2, vindex_swap); \ + x3 = _mm256_shuffle_epi8(t3, vindex_swap) + +# define PUT_BLKS(out, x0, x1, x2, x3) \ + t0 = _mm256_shuffle_epi8(x0, vindex_swap); \ + t1 = _mm256_shuffle_epi8(x1, vindex_swap); \ + t2 = _mm256_shuffle_epi8(x2, vindex_swap); \ + t3 = _mm256_shuffle_epi8(x3, vindex_swap); \ + _mm256_storeu_si256((__m256i *)(out+32*0), t0); \ + _mm256_storeu_si256((__m256i *)(out+32*1), t1); \ + _mm256_storeu_si256((__m256i *)(out+32*2), t2); \ + _mm256_storeu_si256((__m256i *)(out+32*3), t3); \ + x0 = _mm256_i32gather_epi32((int *)(out+8*0), vindex_read, 4); \ + x1 = _mm256_i32gather_epi32((int *)(out+8*1), vindex_read, 4); \ + x2 = _mm256_i32gather_epi32((int *)(out+8*2), vindex_read, 4); \ + x3 = _mm256_i32gather_epi32((int *)(out+8*3), vindex_read, 4); \ + _mm256_storeu_si256((__m256i *)(out+32*0), x0); \ + _mm256_storeu_si256((__m256i *)(out+32*1), x1); \ + _mm256_storeu_si256((__m256i *)(out+32*2), x2); \ + _mm256_storeu_si256((__m256i *)(out+32*3), x3) + +# define _mm256_rotl_epi32(a, i) _mm256_xor_si256( \ + _mm256_slli_epi32(a, i), _mm256_srli_epi32(a, 32 - i)) + +# define INDEX_MASK_TBOX 0xff + +# define ROUND_TBOX(x0, x1, x2, x3, x4, i) \ + t0 = _mm256_set1_epi32(*(rk + i)); \ + t1 = _mm256_xor_si256(x1, x2); \ + t2 = _mm256_xor_si256(x3, t0); \ + x4 = _mm256_xor_si256(t1, t2); \ + t0 = _mm256_and_si256(x4, vindex_mask); \ + t0 = _mm256_i32gather_epi32((int *)SMS4_T, t0, 4); \ + t0 = _mm256_rotl_epi32(t0, 8); \ + x4 = _mm256_srli_epi32(x4, 8); \ + x0 = _mm256_xor_si256(x0, t0); \ + t0 = _mm256_and_si256(x4, vindex_mask); \ + t0 = _mm256_i32gather_epi32((int *)SMS4_T, t0, 4); \ + t0 = _mm256_rotl_epi32(t0, 16); \ + x4 = _mm256_srli_epi32(x4, 8); \ + x0 = _mm256_xor_si256(x0, t0); \ + t0 = _mm256_and_si256(x4, vindex_mask); \ + t0 = _mm256_i32gather_epi32((int *)SMS4_T, t0, 4); \ + t0 = _mm256_rotl_epi32(t0, 24); \ + x4 = _mm256_srli_epi32(x4, 8); \ + x0 = _mm256_xor_si256(x0, t0); \ + t1 = _mm256_i32gather_epi32((int *)SMS4_T, x4, 4); \ + x4 = _mm256_xor_si256(x0, t1) + +# define INDEX_MASK_DBOX 0xffff + +# define ROUND_DBOX(x0, x1, x2, x3, x4, i) \ + t0 = _mm256_set1_epi32(*(rk + i)); \ + t1 = _mm256_xor_si256(x1, x2); \ + t2 = _mm256_xor_si256(x3, t0); \ + x4 = _mm256_xor_si256(t1, t2); \ + t0 = _mm256_srli_epi32(x4, 16); \ + t1 = _mm256_i32gather_epi32((int *)SMS4_D, t0, 4); \ + t2 = _mm256_and_si256(x4, vindex_mask); \ + t3 = _mm256_i32gather_epi32((int *)SMS4_D, t2, 4); \ + t0 = _mm256_rotl_epi32(t3, 16); \ + x4 = _mm256_xor_si256(x0, t1); \ + x4 = _mm256_xor_si256(x4, t0) + +# define ROUND ROUND_TBOX +# define INDEX_MASK INDEX_MASK_TBOX + + +void sm4_avx2_ecb_encrypt_blocks(const unsigned char *in, unsigned char *out, + size_t blocks, const SM4_KEY *key) +{ + const int *rk = (int *)key->rk; + __m256i x0, x1, x2, x3, x4; + __m256i t0, t1, t2, t3; + __m256i vindex_4i = _mm256_setr_epi32(0,4,8,12,16,20,24,28); + __m256i vindex_mask = _mm256_set1_epi32(INDEX_MASK); + __m256i vindex_read = _mm256_setr_epi32(0,8,16,24,1,9,17,25); + __m256i vindex_swap = _mm256_setr_epi8( + 3,2,1,0,7,6,5,4,11,10,9,8,15,14,13,12, + 3,2,1,0,7,6,5,4,11,10,9,8,15,14,13,12 + ); + + while (blocks >= 8) { + GET_BLKS(x0, x1, x2, x3, in); + ROUNDS(x0, x1, x2, x3, x4); + PUT_BLKS(out, x0, x4, x3, x2); + in += 128; + out += 128; + blocks -= 8; + } + + while (blocks--) { + sm4_encrypt(in, out, key); + in += 16; + out += 16; + } +} + +void sm4_avx2_ctr32_encrypt_blocks(const unsigned char *in, unsigned char *out, + size_t blocks, const SM4_KEY *key, const unsigned char iv[16]) +{ + const int *rk = (int *)key->rk; + __m256i x0, x1, x2, x3, x4; + __m256i t0, t1, t2, t3; + __m256i vindex_4i = _mm256_setr_epi32(0,4,8,12,16,20,24,28); + __m256i vindex_mask = _mm256_set1_epi32(INDEX_MASK); + __m256i vindex_read = _mm256_setr_epi32(0,8,16,24,1,9,17,25); + __m256i vindex_swap = _mm256_setr_epi8( + 3,2,1,0,7,6,5,4,11,10,9,8,15,14,13,12, + 3,2,1,0,7,6,5,4,11,10,9,8,15,14,13,12 + ); + __m256i incr = _mm256_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7); + int c0 = (int)GETU32(iv ); + int c1 = (int)GETU32(iv + 4); + int c2 = (int)GETU32(iv + 8); + int c3 = (int)GETU32(iv + 12); + + while (blocks >= 8) { + x0 = _mm256_set1_epi32(c0); + x1 = _mm256_set1_epi32(c1); + x2 = _mm256_set1_epi32(c2); + x3 = _mm256_set1_epi32(c3); + x3 = _mm256_add_epi32(x3, incr); + ROUNDS(x0, x1, x2, x3, x4); + GET_BLKS(t0, t1, t2, t3, in); + x0 = _mm256_xor_si256(x0, t0); + x4 = _mm256_xor_si256(x4, t1); + x3 = _mm256_xor_si256(x3, t2); + x2 = _mm256_xor_si256(x2, t3); + PUT_BLKS(out, x0, x4, x3, x2); + c3 += 8; + in += 128; + out += 128; + blocks -= 8; + } + + if (blocks) { + unsigned char ctr[16]; + memcpy(ctr, iv, 12); + PUTU32(ctr + 12, c3); + sm4_ctr32_encrypt_blocks(in, out, blocks, key, ctr); + } +} +#endif diff --git a/src/sm4_cbc.c b/src/sm4_cbc.c new file mode 100644 index 00000000..88bbc689 --- /dev/null +++ b/src/sm4_cbc.c @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2021 - 2021 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + +#include +#include +#include "mem.h" + +void sm4_cbc_encrypt(const SM4_KEY *key, const uint8_t iv[16], + const uint8_t *in, size_t nblocks, uint8_t *out) +{ + while (nblocks--) { + gmssl_memxor(out, in, iv, 16); + sm4_encrypt(key, out, out); + iv = out; + in += 16; + out += 16; + } +} + +void sm4_cbc_decrypt(const SM4_KEY *key, const uint8_t iv[16], + const uint8_t *in, size_t nblocks, uint8_t *out) +{ + while (nblocks--) { + sm4_decrypt(key, in, out); + memxor(out, iv, 16); + iv = in; + in += 16; + out += 16; + } +} + +int sm4_cbc_padding_encrypt(const SM4_KEY *key, const uint8_t iv[16], + const uint8_t *in, size_t inlen, + uint8_t *out, size_t *outlen) +{ + uint8_t block[16]; + size_t rem = inlen % 16; + int padding = 16 - rem; + + if (in) { + memcpy(block, in + inlen - rem, rem); + } + memset(block + rem, padding, padding); + if (inlen/16) { + sm4_cbc_encrypt(key, iv, in, inlen/16, out); + out += inlen - rem; + iv = out - 16; + } + sm4_cbc_encrypt(key, iv, block, 1, out); + *outlen = inlen - rem + 16; + return 1; +} + +int sm4_cbc_padding_decrypt(const SM4_KEY *key, const uint8_t iv[16], + const uint8_t *in, size_t inlen, + uint8_t *out, size_t *outlen) +{ + uint8_t block[16]; + int padding; + + if (inlen == 0) { + error_print("warning: input lenght = 0"); + return 0; + } + if (inlen%16 != 0 || inlen < 16) { + error_print("invalid cbc ciphertext length"); + return -1; + } + if (inlen > 16) { + sm4_cbc_decrypt(key, iv, in, inlen/16 - 1, out); + iv = in + inlen - 32; + } + sm4_cbc_decrypt(key, iv, in + inlen - 16, 1, block); + padding = block[15]; + if (padding < 1 || padding > 16) { + error_print(); + return -1; + } + memcpy(out + inlen - 16, block, 16 - padding); + *outlen = inlen - padding; + return 1; +} diff --git a/src/sm4_common.c b/src/sm4_common.c new file mode 100644 index 00000000..5835c267 --- /dev/null +++ b/src/sm4_common.c @@ -0,0 +1,16540 @@ +/* ==================================================================== + * Copyright (c) 2014 - 2017 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + * ==================================================================== + */ + +#include "sm4_lcl.h" + + +const uint8_t SM4_S[256] = { + 0xd6, 0x90, 0xe9, 0xfe, 0xcc, 0xe1, 0x3d, 0xb7, + 0x16, 0xb6, 0x14, 0xc2, 0x28, 0xfb, 0x2c, 0x05, + 0x2b, 0x67, 0x9a, 0x76, 0x2a, 0xbe, 0x04, 0xc3, + 0xaa, 0x44, 0x13, 0x26, 0x49, 0x86, 0x06, 0x99, + 0x9c, 0x42, 0x50, 0xf4, 0x91, 0xef, 0x98, 0x7a, + 0x33, 0x54, 0x0b, 0x43, 0xed, 0xcf, 0xac, 0x62, + 0xe4, 0xb3, 0x1c, 0xa9, 0xc9, 0x08, 0xe8, 0x95, + 0x80, 0xdf, 0x94, 0xfa, 0x75, 0x8f, 0x3f, 0xa6, + 0x47, 0x07, 0xa7, 0xfc, 0xf3, 0x73, 0x17, 0xba, + 0x83, 0x59, 0x3c, 0x19, 0xe6, 0x85, 0x4f, 0xa8, + 0x68, 0x6b, 0x81, 0xb2, 0x71, 0x64, 0xda, 0x8b, + 0xf8, 0xeb, 0x0f, 0x4b, 0x70, 0x56, 0x9d, 0x35, + 0x1e, 0x24, 0x0e, 0x5e, 0x63, 0x58, 0xd1, 0xa2, + 0x25, 0x22, 0x7c, 0x3b, 0x01, 0x21, 0x78, 0x87, + 0xd4, 0x00, 0x46, 0x57, 0x9f, 0xd3, 0x27, 0x52, + 0x4c, 0x36, 0x02, 0xe7, 0xa0, 0xc4, 0xc8, 0x9e, + 0xea, 0xbf, 0x8a, 0xd2, 0x40, 0xc7, 0x38, 0xb5, + 0xa3, 0xf7, 0xf2, 0xce, 0xf9, 0x61, 0x15, 0xa1, + 0xe0, 0xae, 0x5d, 0xa4, 0x9b, 0x34, 0x1a, 0x55, + 0xad, 0x93, 0x32, 0x30, 0xf5, 0x8c, 0xb1, 0xe3, + 0x1d, 0xf6, 0xe2, 0x2e, 0x82, 0x66, 0xca, 0x60, + 0xc0, 0x29, 0x23, 0xab, 0x0d, 0x53, 0x4e, 0x6f, + 0xd5, 0xdb, 0x37, 0x45, 0xde, 0xfd, 0x8e, 0x2f, + 0x03, 0xff, 0x6a, 0x72, 0x6d, 0x6c, 0x5b, 0x51, + 0x8d, 0x1b, 0xaf, 0x92, 0xbb, 0xdd, 0xbc, 0x7f, + 0x11, 0xd9, 0x5c, 0x41, 0x1f, 0x10, 0x5a, 0xd8, + 0x0a, 0xc1, 0x31, 0x88, 0xa5, 0xcd, 0x7b, 0xbd, + 0x2d, 0x74, 0xd0, 0x12, 0xb8, 0xe5, 0xb4, 0xb0, + 0x89, 0x69, 0x97, 0x4a, 0x0c, 0x96, 0x77, 0x7e, + 0x65, 0xb9, 0xf1, 0x09, 0xc5, 0x6e, 0xc6, 0x84, + 0x18, 0xf0, 0x7d, 0xec, 0x3a, 0xdc, 0x4d, 0x20, + 0x79, 0xee, 0x5f, 0x3e, 0xd7, 0xcb, 0x39, 0x48, +}; + +const uint32_t SM4_T[256] = { + 0x8ed55b5bU, 0xd0924242U, 0x4deaa7a7U, 0x06fdfbfbU, + 0xfccf3333U, 0x65e28787U, 0xc93df4f4U, 0x6bb5dedeU, + 0x4e165858U, 0x6eb4dadaU, 0x44145050U, 0xcac10b0bU, + 0x8828a0a0U, 0x17f8efefU, 0x9c2cb0b0U, 0x11051414U, + 0x872bacacU, 0xfb669d9dU, 0xf2986a6aU, 0xae77d9d9U, + 0x822aa8a8U, 0x46bcfafaU, 0x14041010U, 0xcfc00f0fU, + 0x02a8aaaaU, 0x54451111U, 0x5f134c4cU, 0xbe269898U, + 0x6d482525U, 0x9e841a1aU, 0x1e061818U, 0xfd9b6666U, + 0xec9e7272U, 0x4a430909U, 0x10514141U, 0x24f7d3d3U, + 0xd5934646U, 0x53ecbfbfU, 0xf89a6262U, 0x927be9e9U, + 0xff33ccccU, 0x04555151U, 0x270b2c2cU, 0x4f420d0dU, + 0x59eeb7b7U, 0xf3cc3f3fU, 0x1caeb2b2U, 0xea638989U, + 0x74e79393U, 0x7fb1ceceU, 0x6c1c7070U, 0x0daba6a6U, + 0xedca2727U, 0x28082020U, 0x48eba3a3U, 0xc1975656U, + 0x80820202U, 0xa3dc7f7fU, 0xc4965252U, 0x12f9ebebU, + 0xa174d5d5U, 0xb38d3e3eU, 0xc33ffcfcU, 0x3ea49a9aU, + 0x5b461d1dU, 0x1b071c1cU, 0x3ba59e9eU, 0x0cfff3f3U, + 0x3ff0cfcfU, 0xbf72cdcdU, 0x4b175c5cU, 0x52b8eaeaU, + 0x8f810e0eU, 0x3d586565U, 0xcc3cf0f0U, 0x7d196464U, + 0x7ee59b9bU, 0x91871616U, 0x734e3d3dU, 0x08aaa2a2U, + 0xc869a1a1U, 0xc76aadadU, 0x85830606U, 0x7ab0cacaU, + 0xb570c5c5U, 0xf4659191U, 0xb2d96b6bU, 0xa7892e2eU, + 0x18fbe3e3U, 0x47e8afafU, 0x330f3c3cU, 0x674a2d2dU, + 0xb071c1c1U, 0x0e575959U, 0xe99f7676U, 0xe135d4d4U, + 0x661e7878U, 0xb4249090U, 0x360e3838U, 0x265f7979U, + 0xef628d8dU, 0x38596161U, 0x95d24747U, 0x2aa08a8aU, + 0xb1259494U, 0xaa228888U, 0x8c7df1f1U, 0xd73bececU, + 0x05010404U, 0xa5218484U, 0x9879e1e1U, 0x9b851e1eU, + 0x84d75353U, 0x00000000U, 0x5e471919U, 0x0b565d5dU, + 0xe39d7e7eU, 0x9fd04f4fU, 0xbb279c9cU, 0x1a534949U, + 0x7c4d3131U, 0xee36d8d8U, 0x0a020808U, 0x7be49f9fU, + 0x20a28282U, 0xd4c71313U, 0xe8cb2323U, 0xe69c7a7aU, + 0x42e9ababU, 0x43bdfefeU, 0xa2882a2aU, 0x9ad14b4bU, + 0x40410101U, 0xdbc41f1fU, 0xd838e0e0U, 0x61b7d6d6U, + 0x2fa18e8eU, 0x2bf4dfdfU, 0x3af1cbcbU, 0xf6cd3b3bU, + 0x1dfae7e7U, 0xe5608585U, 0x41155454U, 0x25a38686U, + 0x60e38383U, 0x16acbabaU, 0x295c7575U, 0x34a69292U, + 0xf7996e6eU, 0xe434d0d0U, 0x721a6868U, 0x01545555U, + 0x19afb6b6U, 0xdf914e4eU, 0xfa32c8c8U, 0xf030c0c0U, + 0x21f6d7d7U, 0xbc8e3232U, 0x75b3c6c6U, 0x6fe08f8fU, + 0x691d7474U, 0x2ef5dbdbU, 0x6ae18b8bU, 0x962eb8b8U, + 0x8a800a0aU, 0xfe679999U, 0xe2c92b2bU, 0xe0618181U, + 0xc0c30303U, 0x8d29a4a4U, 0xaf238c8cU, 0x07a9aeaeU, + 0x390d3434U, 0x1f524d4dU, 0x764f3939U, 0xd36ebdbdU, + 0x81d65757U, 0xb7d86f6fU, 0xeb37dcdcU, 0x51441515U, + 0xa6dd7b7bU, 0x09fef7f7U, 0xb68c3a3aU, 0x932fbcbcU, + 0x0f030c0cU, 0x03fcffffU, 0xc26ba9a9U, 0xba73c9c9U, + 0xd96cb5b5U, 0xdc6db1b1U, 0x375a6d6dU, 0x15504545U, + 0xb98f3636U, 0x771b6c6cU, 0x13adbebeU, 0xda904a4aU, + 0x57b9eeeeU, 0xa9de7777U, 0x4cbef2f2U, 0x837efdfdU, + 0x55114444U, 0xbdda6767U, 0x2c5d7171U, 0x45400505U, + 0x631f7c7cU, 0x50104040U, 0x325b6969U, 0xb8db6363U, + 0x220a2828U, 0xc5c20707U, 0xf531c4c4U, 0xa88a2222U, + 0x31a79696U, 0xf9ce3737U, 0x977aededU, 0x49bff6f6U, + 0x992db4b4U, 0xa475d1d1U, 0x90d34343U, 0x5a124848U, + 0x58bae2e2U, 0x71e69797U, 0x64b6d2d2U, 0x70b2c2c2U, + 0xad8b2626U, 0xcd68a5a5U, 0xcb955e5eU, 0x624b2929U, + 0x3c0c3030U, 0xce945a5aU, 0xab76ddddU, 0x867ff9f9U, + 0xf1649595U, 0x5dbbe6e6U, 0x35f2c7c7U, 0x2d092424U, + 0xd1c61717U, 0xd66fb9b9U, 0xdec51b1bU, 0x94861212U, + 0x78186060U, 0x30f3c3c3U, 0x897cf5f5U, 0x5cefb3b3U, + 0xd23ae8e8U, 0xacdf7373U, 0x794c3535U, 0xa0208080U, + 0x9d78e5e5U, 0x56edbbbbU, 0x235e7d7dU, 0xc63ef8f8U, + 0x8bd45f5fU, 0xe7c82f2fU, 0xdd39e4e4U, 0x68492121U, +}; + +const uint32_t SM4_D[65536] = { + 0xd55b8e00U, 0xcc05c919U, 0x2998b1fcU, 0x75d3a6a0U, + 0xbd299468U, 0x09b0b9dcU, 0x7a1c66afU, 0x50beee85U, + 0xd69b4d03U, 0x54bbef81U, 0xde914f0bU, 0x851f9a50U, + 0x2e5d73fbU, 0x61c2a3b4U, 0x3e4977ebU, 0x9ac45e4fU, + 0x225270f7U, 0x132e3dc6U, 0xe427c331U, 0x577b2c82U, + 0x265771f3U, 0x7493e7a1U, 0x9ec15f4bU, 0x811a9b54U, + 0x24d7f3f1U, 0x9f811e4aU, 0xc28a4817U, 0x166b7dc3U, + 0xabb8137eU, 0x944bdf41U, 0x96cb5d43U, 0xe828c03dU, + 0xfc39c529U, 0x879f1852U, 0xcfc50a1aU, 0x5df1ac88U, + 0xc800c81dU, 0x3186b7e4U, 0xec2dc139U, 0x674720b2U, + 0x422a6897U, 0xdfd10e0aU, 0xa2f25077U, 0x839a1956U, + 0x398cb5ecU, 0xb1269764U, 0x3cc9f5e9U, 0x073f38d2U, + 0x1da1bcc8U, 0x40aaea95U, 0xfeb9472bU, 0x28d8f0fdU, + 0xa938917cU, 0xaefd537bU, 0x2d9db0f8U, 0xd814cc0dU, + 0x8c55d959U, 0xf1768724U, 0xdc11cd09U, 0x65c7a2b0U, + 0x5b742f8eU, 0xb066d665U, 0x721664a7U, 0x14ebffc1U, + 0x938e1d46U, 0x92ce5c47U, 0x10eefec5U, 0x7dd9a4a8U, + 0x41eaab94U, 0x436a2996U, 0xd29e4c07U, 0x6487e3b1U, + 0x805ada55U, 0xebe8033eU, 0x7e1967abU, 0xeaa8423fU, + 0x15abbec0U, 0x9844dc4dU, 0xb3a61566U, 0x2cddf1f9U, + 0x2f1d32faU, 0x231231f6U, 0x8850d85dU, 0x44afeb91U, + 0x4b602b9eU, 0x1f213ecaU, 0xe5678230U, 0xa072d275U, + 0x6dcda0b8U, 0x2192b3f4U, 0xb2e65467U, 0xa3b21176U, + 0x4f652a9aU, 0xd7db0c02U, 0xf83cc42dU, 0x5a346e8fU, + 0xf6b34523U, 0x1e617fcbU, 0xb6e35563U, 0xf7f30422U, + 0x033a39d6U, 0xefed023aU, 0xc940891cU, 0x04fffbd1U, + 0x1a647ecfU, 0x067f79d3U, 0x7f5926aaU, 0x620260b7U, + 0x8ad05a5fU, 0x0a707adfU, 0x6f4d22baU, 0x904ede45U, + 0xdd518c08U, 0x8ed55b5bU, 0x978b1c42U, 0xd3de0d06U, + 0xf036c625U, 0xc14a8b14U, 0x126e7cc7U, 0xc7cf0812U, + 0xbfa9166aU, 0x563b6d83U, 0x86df5953U, 0x11aebfc4U, + 0x0cf5f9d9U, 0x9d019c48U, 0xad3d9078U, 0xf433c721U, + 0x2597b2f0U, 0x7096e6a5U, 0xa477d371U, 0xc54f8a10U, + 0x8f951a5aU, 0x910e9f44U, 0x6e0d63bbU, 0x58b4ec8dU, + 0x00fafad5U, 0x51feaf84U, 0x45efaa90U, 0xb5239660U, + 0x69c8a1bcU, 0x0b303bdeU, 0xda944e0fU, 0x08f0f8ddU, + 0x0db5b8d8U, 0x34c3f7e1U, 0xfbfc072eU, 0x1ce1fdc9U, + 0xe022c235U, 0x5e316f8bU, 0xe6a74133U, 0xdbd40f0eU, + 0x38ccf4edU, 0xc00aca15U, 0x462f6993U, 0x4e256b9bU, + 0x59f4ad8cU, 0xbc69d569U, 0x48a0e89dU, 0x01babbd4U, + 0xfabc462fU, 0x55fbae80U, 0x05bfbad0U, 0x364375e3U, + 0x845fdb51U, 0x172b3cc2U, 0xa5379270U, 0x0f353adaU, + 0x8d159858U, 0x2a5872ffU, 0x027a78d7U, 0x20d2f2f5U, + 0xbaec566fU, 0xc3ca0916U, 0xb7a31462U, 0x330635e6U, + 0xd9548d0cU, 0xe1628334U, 0x523e6c87U, 0x9b841f4eU, + 0xf5738620U, 0x79dca5acU, 0xb463d761U, 0x324674e7U, + 0x82da5857U, 0x71d6a7a4U, 0x271730f2U, 0x476f2892U, + 0x3b0c37eeU, 0x3f0936eaU, 0xe3e20136U, 0xcbc00b1eU, + 0xb86cd46dU, 0xe2a24037U, 0x30c6f6e5U, 0xc40fcb11U, + 0x6082e2b5U, 0xf97c852cU, 0x7c99e5a9U, 0x735625a6U, + 0xca804a1fU, 0xe968813cU, 0xfff9062aU, 0x8b901b5eU, + 0xf2b64427U, 0xce854b1bU, 0xe7e70032U, 0xed6d8038U, + 0xa6f75173U, 0x8910995cU, 0x4a206a9fU, 0xac7dd179U, + 0x18e4fccdU, 0xb92c956cU, 0x634221b6U, 0x789ce4adU, + 0x3a4c76efU, 0x5f712e8aU, 0xcd458818U, 0xc68f4913U, + 0x6c8de1b9U, 0x19a4bdccU, 0x5cb1ed89U, 0x4ca5e999U, + 0xa878d07dU, 0x2b1833feU, 0xd01ece05U, 0xa7b71072U, + 0xbee9576bU, 0xd41bcf01U, 0x537e2d86U, 0x775324a2U, + 0x1b243fceU, 0x6888e0bdU, 0x49e0a99cU, 0xaaf8527fU, + 0x99049d4cU, 0x370334e2U, 0x950b9e40U, 0x9c41dd49U, + 0xeead433bU, 0x4de5a898U, 0x7b5c27aeU, 0x3d89b4e8U, + 0x660761b3U, 0xfd798428U, 0xbbac176eU, 0x0e757bdbU, + 0x6b4823beU, 0x3583b6e0U, 0xf3f60526U, 0x761365a3U, + 0xd15e8f04U, 0xa1329374U, 0x6a0862bfU, 0xafbd127aU, + 0x8b1c9719U, 0x9242d000U, 0x77dfa8e5U, 0x2b94bfb9U, + 0xe36e8d71U, 0x57f7a0c5U, 0x245b7fb6U, 0x0ef9f79cU, + 0x88dc541aU, 0x0afcf698U, 0x80d65612U, 0xdb588349U, + 0x701a6ae2U, 0x3f85baadU, 0x600e6ef2U, 0xc4834756U, + 0x7c1569eeU, 0x4d6924dfU, 0xba60da28U, 0x093c359bU, + 0x781068eaU, 0x2ad4feb8U, 0xc0864652U, 0xdf5d824dU, + 0x7a90eae8U, 0xc1c60753U, 0x9ccd510eU, 0x482c64daU, + 0xf5ff0a67U, 0xca0cc658U, 0xc88c445aU, 0xb66fd924U, + 0xa27edc30U, 0xd9d8014bU, 0x91821303U, 0x03b6b591U, + 0x9647d104U, 0x6fc1aefdU, 0xb26ad820U, 0x390039abU, + 0x1c6d718eU, 0x81961713U, 0xfcb5496eU, 0xdddd004fU, + 0x67cbacf5U, 0xef618e7dU, 0x628eecf0U, 0x597821cbU, + 0x43e6a5d1U, 0x1eedf38cU, 0xa0fe5e32U, 0x769fe9e4U, + 0xf77f8865U, 0xf0ba4a62U, 0x73daa9e1U, 0x8653d514U, + 0xd212c040U, 0xaf319e3dU, 0x8256d410U, 0x3b80bba9U, + 0x05333697U, 0xee21cf7cU, 0x2c517dbeU, 0x4aace6d8U, + 0xcdc9045fU, 0xcc89455eU, 0x4ea9e7dcU, 0x239ebdb1U, + 0x1fadb28dU, 0x1d2d308fU, 0x8cd9551eU, 0x3ac0faa8U, + 0xde1dc34cU, 0xb5af1a27U, 0x205e7eb2U, 0xb4ef5b26U, + 0x4beca7d9U, 0xc603c554U, 0xede10c7fU, 0x729ae8e0U, + 0x715a2be3U, 0x7d5528efU, 0xd617c144U, 0x1ae8f288U, + 0x15273287U, 0x416627d3U, 0xbb209b29U, 0xfe35cb6cU, + 0x338ab9a1U, 0x7fd5aaedU, 0xeca14d7eU, 0xfdf5086fU, + 0x11223383U, 0x899c151bU, 0xa67bdd34U, 0x04737796U, + 0xa8f45c3aU, 0x402666d2U, 0xe8a44c7aU, 0xa9b41d3bU, + 0x5d7d20cfU, 0xb1aa1b23U, 0x97079005U, 0x5ab8e2c8U, + 0x442367d6U, 0x583860caU, 0x211e3fb3U, 0x3c4579aeU, + 0xd4974346U, 0x543763c6U, 0x310a3ba3U, 0xce09c75cU, + 0x83169511U, 0xd0924242U, 0xc9cc055bU, 0x8d99141fU, + 0xae71df3cU, 0x9f0d920dU, 0x4c2965deU, 0x9988110bU, + 0xe1ee0f73U, 0x087c749aU, 0xd898404aU, 0x4fe9a6ddU, + 0x52b2e0c0U, 0xc3468551U, 0xf37a8961U, 0xaa74de38U, + 0x7bd0abe9U, 0x2ed1ffbcU, 0xfa30ca68U, 0x9b089309U, + 0xd1d20343U, 0xcf49865dU, 0x304a7aa2U, 0x06f3f594U, + 0x5ebde3ccU, 0x0fb9b69dU, 0x1ba8b389U, 0xeb648f79U, + 0x378fb8a5U, 0x557722c7U, 0x84d35716U, 0x56b7e1c4U, + 0x53f2a1c1U, 0x6a84eef8U, 0xa5bb1e37U, 0x42a6e4d0U, + 0xbe65db2cU, 0x00767692U, 0xb8e0582aU, 0x85931617U, + 0x668bedf4U, 0x9e4dd30cU, 0x1868708aU, 0x10627282U, + 0x07b3b495U, 0xe22ecc70U, 0x16e7f184U, 0x5ffda2cdU, + 0xa4fb5f36U, 0x0bbcb799U, 0x5bf8a3c9U, 0x68046cfaU, + 0xda18c248U, 0x496c25dbU, 0xfb708b69U, 0x517223c3U, + 0xd3528141U, 0x741f6be6U, 0x5c3d61ceU, 0x7e95ebecU, + 0xe4ab4f76U, 0x9d8d100fU, 0xe9e40d7bU, 0x6d412cffU, + 0x87139415U, 0xbf259a2dU, 0x0c79759eU, 0xc5c30657U, + 0xab349f39U, 0x279bbcb5U, 0xea24ce78U, 0x6c016dfeU, + 0xdc9d414eU, 0x2f91bebdU, 0x795029ebU, 0x1928318bU, + 0x654b2ef7U, 0x614e2ff3U, 0xbda5182fU, 0x95871207U, + 0xe62bcd74U, 0xbce5592eU, 0x6e81effcU, 0x9a48d208U, + 0x3ec5fbacU, 0xa73b9c35U, 0x22defcb0U, 0x2d113cbfU, + 0x94c75306U, 0xb72f9825U, 0xa1be1f33U, 0xd5d70247U, + 0xacf15d3eU, 0x90c25202U, 0xb9a0192bU, 0xb32a9921U, + 0xf8b0486aU, 0xd7578045U, 0x14677386U, 0xf23ac860U, + 0x46a3e5d4U, 0xe76b8c75U, 0x3d0538afU, 0x26dbfdb4U, + 0x640b6ff6U, 0x01363793U, 0x93029101U, 0x98c8500aU, + 0x32caf8a0U, 0x47e3a4d5U, 0x02f6f490U, 0x12e2f080U, + 0xf63fc964U, 0x755f2ae7U, 0x8e59d71cU, 0xf9f0096bU, + 0xe0ae4e72U, 0x8a5cd618U, 0x0d39349fU, 0x29143dbbU, + 0x456326d7U, 0x36cff9a4U, 0x17a7b085U, 0xf4bf4b66U, + 0xc7438455U, 0x69442dfbU, 0xcb4c8759U, 0xc206c450U, + 0xb0ea5a22U, 0x13a2b181U, 0x251b3eb7U, 0x63ceadf1U, + 0x384078aaU, 0xa33e9d31U, 0xe5eb0e77U, 0x503262c2U, + 0x350f3aa7U, 0x6bc4aff9U, 0xadb11c3fU, 0x28547cbaU, + 0x8f19961dU, 0xff758a6dU, 0x344f7ba6U, 0xf1fa0b63U, + 0x166472fcU, 0x0f3a35e5U, 0xeaa74d00U, 0xb6ec5a5cU, + 0x7e166894U, 0xca8f4520U, 0xb9239a53U, 0x93811279U, + 0x15a4b1ffU, 0x9784137dU, 0x1daeb3f7U, 0x462066acU, + 0xed628f07U, 0xa2fd5f48U, 0xfd768b17U, 0x59fba2b3U, + 0xe16d8c0bU, 0xd011c13aU, 0x27183fcdU, 0x9444d07eU, + 0xe5688d0fU, 0xb7ac1b5dU, 0x5dfea3b7U, 0x422567a8U, + 0xe7e80f0dU, 0x5cbee2b6U, 0x01b5b4ebU, 0xd554813fU, + 0x6887ef82U, 0x577423bdU, 0x55f4a1bfU, 0x2b173cc1U, + 0x3f0639d5U, 0x44a0e4aeU, 0x0cfaf6e6U, 0x9ece5074U, + 0x0b3f34e1U, 0xf2b94b18U, 0x2f123dc5U, 0xa478dc4eU, + 0x8115946bU, 0x1ceef2f6U, 0x61cdac8bU, 0x40a5e5aaU, + 0xfab34910U, 0x72196b98U, 0xfff60915U, 0xc400c42eU, + 0xde9e4034U, 0x83951669U, 0x3d86bbd7U, 0xebe70c01U, + 0x6a076d80U, 0x6dc2af87U, 0xeea24c04U, 0x1b2b30f1U, + 0x4f6a25a5U, 0x32497bd8U, 0x1f2e31f5U, 0xa6f85e4cU, + 0x984bd372U, 0x73592a99U, 0xb129985bU, 0xd7d4033dU, + 0x50b1e1baU, 0x51f1a0bbU, 0xd3d10239U, 0xbee65854U, + 0x82d55768U, 0x8055d56aU, 0x11a1b0fbU, 0xa7b81f4dU, + 0x436526a9U, 0x28d7ffc2U, 0xbd269b57U, 0x2997bec3U, + 0xd694423cU, 0x5b7b20b1U, 0x7099e99aU, 0xefe20d05U, + 0xec22ce06U, 0xe02dcd0aU, 0x4b6f24a1U, 0x8790176dU, + 0x885fd762U, 0xdc1ec236U, 0x26587eccU, 0x634d2e89U, + 0xaef25c44U, 0xe2ad4f08U, 0x71d9a89bU, 0x608ded8aU, + 0x8c5ad666U, 0x14e4f0feU, 0x3b0338d1U, 0x990b9273U, + 0x358cb9dfU, 0xdd5e8337U, 0x75dca99fU, 0x34ccf8deU, + 0xc005c52aU, 0x2cd2fec6U, 0x0a7f75e0U, 0xc7c0072dU, + 0xd95b8233U, 0xc540852fU, 0xbc66da56U, 0xa13d9c4bU, + 0x49efa6a3U, 0xc94f8623U, 0xac72de46U, 0x537122b9U, + 0x1e6e70f4U, 0x4deaa7a7U, 0x54b4e0beU, 0x10e1f1faU, + 0x33093ad9U, 0x027577e8U, 0xd151803bU, 0x04f0f4eeU, + 0x7c96ea96U, 0x9504917fU, 0x45e0a5afU, 0xd2914338U, + 0xcfca0525U, 0x5e3e60b4U, 0x6e026c84U, 0x370c3bddU, + 0xe6a84e0cU, 0xb3a91a59U, 0x67482f8dU, 0x067076ecU, + 0x4caae6a6U, 0x523163b8U, 0xad329f47U, 0x9b8b1071U, + 0xc3c50629U, 0x92c15378U, 0x86d0566cU, 0x761c6a9cU, + 0xaaf75d40U, 0xc80fc722U, 0x19abb2f3U, 0xcbcf0421U, + 0xce8a4424U, 0xf7fc0b1dU, 0x38c3fbd2U, 0xdfde0135U, + 0x231d3ec9U, 0x9d0e9377U, 0x2598bdcfU, 0x18ebf3f2U, + 0xfbf30811U, 0x033536e9U, 0x8510956fU, 0x8d1a9767U, + 0x9acb5170U, 0x7f562995U, 0x8b9f1461U, 0xc2854728U, + 0x3983bad3U, 0x96c4527cU, 0xc680462cU, 0xf57c891fU, + 0x476027adU, 0xd414c03eU, 0x66086e8cU, 0xcc0ac626U, + 0x4e2a64a4U, 0xe9678e03U, 0xc145842bU, 0xe3ed0e09U, + 0x79d3aa93U, 0x00f5f5eaU, 0x749ce89eU, 0xf039c91aU, + 0x1a6b71f0U, 0x225d7fc8U, 0x9101907bU, 0x58bbe3b2U, + 0x364c7adcU, 0xbae35950U, 0x775c2b9dU, 0xf179881bU, + 0x41e5a4abU, 0xb2e95b58U, 0xe428cc0eU, 0x8450d46eU, + 0xf833cb12U, 0xfc36ca16U, 0x20ddfdcaU, 0x08fff7e2U, + 0x7b532891U, 0x219dbccbU, 0xf3f90a19U, 0x073037edU, + 0xa3bd1e49U, 0x3a4379d0U, 0xbfa61955U, 0xb069d95aU, + 0x09bfb6e3U, 0x2a577dc0U, 0x3cc6fad6U, 0x48afe7a2U, + 0x3189b8dbU, 0x0dbab7e7U, 0x24d8fcceU, 0x2e527cc4U, + 0x65c8ad8fU, 0x4a2f65a0U, 0x891f9663U, 0x6f422d85U, + 0xdbdb0031U, 0x7a136990U, 0xa07ddd4aU, 0xbba31851U, + 0xf9738a13U, 0x9c4ed276U, 0x0e7a74e4U, 0x05b0b5efU, + 0xafb21d45U, 0xda9b4130U, 0x9f8e1175U, 0x8f9a1565U, + 0x6b472c81U, 0xe827cf02U, 0x132132f9U, 0x6488ec8eU, + 0x7dd6ab97U, 0x172433fdU, 0x9041d17aU, 0xb46cd85eU, + 0xd81bc332U, 0xabb71c41U, 0x8adf5560U, 0x69c7ae83U, + 0x5a3b61b0U, 0xf43cc81eU, 0x563462bcU, 0x5f7e21b5U, + 0x2d92bfc7U, 0x8eda5464U, 0xb863db52U, 0xfeb64814U, + 0xa5389d4fU, 0x3e4678d4U, 0x7893eb92U, 0xcd4a8727U, + 0xa877df42U, 0xf6bc4a1cU, 0x30c9f9daU, 0xb52c995fU, + 0x126173f8U, 0x620d6f88U, 0xa9379e43U, 0x6c82ee86U, + 0x5d732ea0U, 0x442d69b9U, 0xa1b0115cU, 0xfdfb0600U, + 0x350134c8U, 0x8198197cU, 0xf234c60fU, 0xd8964e25U, + 0x5eb3eda3U, 0xdc934f21U, 0x56b9efabU, 0x0d373af0U, + 0xa675d35bU, 0xe9ea0314U, 0xb661d74bU, 0x12ecfeefU, + 0xaa7ad057U, 0x9b069d66U, 0x6c0f6391U, 0xdf538c22U, + 0xae7fd153U, 0xfcbb4701U, 0x16e9ffebU, 0x09323bf4U, + 0xacff5351U, 0x17a9beeaU, 0x4aa2e8b7U, 0x9e43dd63U, + 0x2390b3deU, 0x1c637fe1U, 0x1ee3fde3U, 0x6000609dU, + 0x74116589U, 0x0fb7b8f2U, 0x47edaabaU, 0xd5d90c28U, + 0x402868bdU, 0xb9ae1744U, 0x64056199U, 0xef6f8012U, + 0xca02c837U, 0x57f9aeaaU, 0x2adaf0d7U, 0x0bb2b9f6U, + 0xb1a4154cU, 0x390e37c4U, 0xb4e15549U, 0x8f179872U, + 0x95891c68U, 0xc8824a35U, 0x7691e78bU, 0xa0f0505dU, + 0x211031dcU, 0x26d5f3dbU, 0xa5b51058U, 0x503c6cadU, + 0x047d79f9U, 0x795e2784U, 0x54396da9U, 0xedef0210U, + 0xd35c8f2eU, 0x384e76c5U, 0xfa3ec407U, 0x9cc35f61U, + 0x1ba6bde6U, 0x1ae6fce7U, 0x98c65e65U, 0xf5f10408U, + 0xc9c20b34U, 0xcb428936U, 0x5ab6eca7U, 0xecaf4311U, + 0x08727af5U, 0x63c0a39eU, 0xf631c70bU, 0x6280e29fU, + 0x9d831e60U, 0x106c7cedU, 0x3b8eb5c6U, 0xa4f55159U, + 0xa735925aU, 0xab3a9156U, 0x007878fdU, 0xcc874b31U, + 0xc3488b3eU, 0x97099e6aU, 0x6d4f2290U, 0x285a72d5U, + 0xe5e50018U, 0xa9ba1354U, 0x3acef4c7U, 0x2b9ab1d6U, + 0xc74d8a3aU, 0x5ff3aca2U, 0x7014648dU, 0xd21cce2fU, + 0x7e9be583U, 0x9649df6bU, 0x3ecbf5c3U, 0x7fdba482U, + 0x8b129976U, 0x67c5a29aU, 0x416829bcU, 0x8cd75b71U, + 0x924cde6fU, 0x8e57d973U, 0xf771860aU, 0xea2ac017U, + 0x02f8faffU, 0x8258da7fU, 0xe765821aU, 0x18667ee5U, + 0x55792ca8U, 0x06fdfbfbU, 0x1fa3bce2U, 0x5bf6ada6U, + 0x781e6685U, 0x49622bb4U, 0x9a46dc67U, 0x4fe7a8b2U, + 0x3781b6caU, 0xde13cd23U, 0x0ef7f9f3U, 0x99861f64U, + 0x84dd5979U, 0x15293ce8U, 0x251530d8U, 0x7c1b6781U, + 0xadbf1250U, 0xf8be4605U, 0x2c5f73d1U, 0x4d672ab0U, + 0x07bdbafaU, 0x19263fe4U, 0xe625c31bU, 0xd09c4c2dU, + 0x88d25a75U, 0xd9d60f24U, 0xcdc70a30U, 0x3d0b36c0U, + 0xe1e0011cU, 0x83189b7eU, 0x52bceeafU, 0x80d8587dU, + 0x859d1878U, 0xbceb5741U, 0x73d4a78eU, 0x94c95d69U, + 0x680a6295U, 0xd619cf2bU, 0x6e8fe193U, 0x53fcafaeU, + 0xb0e4544dU, 0x48226ab5U, 0xce07c933U, 0xc60dcb3bU, + 0xd1dc0d2cU, 0x344175c9U, 0xc088483dU, 0x89921b74U, + 0x7294e68fU, 0xddd30e20U, 0x8d971a70U, 0xbe6bd543U, + 0x0c777bf1U, 0x9f039c62U, 0x2d1f32d0U, 0x871d9a7aU, + 0x053d38f8U, 0xa270d25fU, 0x8a52d877U, 0xa8fa5255U, + 0x32c4f6cfU, 0x4be2a9b6U, 0x3f8bb4c2U, 0xbb2e9546U, + 0x517c2dacU, 0x694a2394U, 0xda16cc27U, 0x13acbfeeU, + 0x7d5b2680U, 0xf1f4050cU, 0x3c4b77c1U, 0xba6ed447U, + 0x0af2f8f7U, 0xf9fe0704U, 0xaf3f9052U, 0xcf478832U, + 0xb324974eU, 0xb721964aU, 0x6bcaa196U, 0x43e8abbeU, + 0x304474cdU, 0x6a8ae097U, 0xb8ee5645U, 0x4c276bb1U, + 0xe8aa4215U, 0x7154258cU, 0xf4b14509U, 0xfb7e8506U, + 0x42a8eabfU, 0x6140219cU, 0x77d1a68aU, 0x03b8bbfeU, + 0x7a9ee487U, 0x46adebbbU, 0x6fcfa092U, 0x65452098U, + 0x2edff1d3U, 0x013839fcU, 0xc208ca3fU, 0x245571d9U, + 0x90cc5c6dU, 0x310435ccU, 0xeb6a8116U, 0xf0b4440dU, + 0xb264d64fU, 0xd7598e2aU, 0x456d28b8U, 0x4ea7e9b3U, + 0xe4a54119U, 0x918c1d6cU, 0xd4994d29U, 0xc48d4939U, + 0x205070ddU, 0xa330935eU, 0x58366ea5U, 0x2f9fb0d2U, + 0x36c1f7cbU, 0x5c336fa1U, 0xdb568d26U, 0xff7b8402U, + 0x930c9f6eU, 0xe0a0401dU, 0xc1c8093cU, 0x22d0f2dfU, + 0x112c3decU, 0xbf2b9442U, 0x1d233ee0U, 0x14697de9U, + 0x6685e39bU, 0xc5cd0838U, 0xf374870eU, 0xb5a11448U, + 0xee2fc113U, 0x75512488U, 0x3384b7ceU, 0x865ddb7bU, + 0xe360831eU, 0xbdab1640U, 0x7bdea586U, 0xfe3bc503U, + 0x59762fa4U, 0x291a33d4U, 0xe220c21fU, 0x2795b2daU, + 0xa741e668U, 0xbe1fa171U, 0x5b82d994U, 0x07c9cec8U, + 0xcf33fc00U, 0x7baad1b4U, 0x08060ec7U, 0x22a486edU, + 0xa481256bU, 0x26a187e9U, 0xac8b2763U, 0xf705f238U, + 0x5c471b93U, 0x13d8cbdcU, 0x4c531f83U, 0xe8de3627U, + 0x5048189fU, 0x613455aeU, 0x963dab59U, 0x256144eaU, + 0x544d199bU, 0x06898fc9U, 0xecdb3723U, 0xf300f33cU, + 0x56cd9b99U, 0xed9b7622U, 0xb090207fU, 0x647115abU, + 0xd9a27b16U, 0xe651b729U, 0xe4d1352bU, 0x9a32a855U, + 0x8e23ad41U, 0xf585703aU, 0xbddf6272U, 0x2febc4e0U, + 0xba1aa075U, 0x439cdf8cU, 0x9e37a951U, 0x155d48daU, + 0x303000ffU, 0xadcb6662U, 0xd0e8381fU, 0xf180713eU, + 0x4b96dd84U, 0xc33cff0cU, 0x4ed39d81U, 0x752550baU, + 0x6fbbd4a0U, 0x32b082fdU, 0x8ca32f43U, 0x5ac29895U, + 0xdb22f914U, 0xdce73b13U, 0x5f87d890U, 0xaa0ea465U, + 0xfe4fb131U, 0x836cef4cU, 0xae0ba561U, 0x17ddcad8U, + 0x296e47e6U, 0xc27cbe0dU, 0x000c0ccfU, 0x66f197a9U, + 0xe194752eU, 0xe0d4342fU, 0x62f496adU, 0x0fc3ccc0U, + 0x33f0c3fcU, 0x317041feU, 0xa084246fU, 0x169d8bd9U, + 0xf240b23dU, 0x99f26b56U, 0x0c030fc3U, 0x98b22a57U, + 0x67b1d6a8U, 0xea5eb425U, 0xc1bc7d0eU, 0x5ec79991U, + 0x5d075a92U, 0x5108599eU, 0xfa4ab035U, 0x36b583f9U, + 0x397a43f6U, 0x6d3b56a2U, 0x977dea58U, 0xd268ba1dU, + 0x1fd7c8d0U, 0x5388db9cU, 0xc0fc3c0fU, 0xd1a8791eU, + 0x3d7f42f2U, 0xa5c1646aU, 0x8a26ac45U, 0x282e06e7U, + 0x84a92d4bU, 0x6c7b17a3U, 0xc4f93d0bU, 0x85e96c4aU, + 0x712051beU, 0x9df76a52U, 0xbb5ae174U, 0x76e593b9U, + 0x687e16a7U, 0x746511bbU, 0x0d434ec2U, 0x101808dfU, + 0xf8ca3237U, 0x786a12b7U, 0x1d574ad2U, 0xe254b62dU, + 0xaf4be460U, 0xfccf3333U, 0xe591742aU, 0xa1c4656eU, + 0x822cae4dU, 0xb350e37cU, 0x607414afU, 0xb5d5607aU, + 0xcdb37e02U, 0x242105ebU, 0xf4c5313bU, 0x63b4d7acU, + 0x7eef91b1U, 0xef1bf420U, 0xdf27f810U, 0x8629af49U, + 0x578dda98U, 0x028c8ecdU, 0xd66dbb19U, 0xb755e278U, + 0xfd8f7232U, 0xe314f72cU, 0x1c170bd3U, 0x2aae84e5U, + 0x72e092bdU, 0x23e4c7ecU, 0x37f5c2f8U, 0xc739fe08U, + 0x1bd2c9d4U, 0x792a53b6U, 0xa88e2667U, 0x7aea90b5U, + 0x7fafd0b0U, 0x46d99f89U, 0x89e66f46U, 0x6efb95a1U, + 0x9238aa5dU, 0x2c2b07e3U, 0x94bd295bU, 0xa9ce6766U, + 0x4ad69c85U, 0xb210a27dU, 0x343501fbU, 0x3c3f03f3U, + 0x2beec5e4U, 0xce73bd01U, 0x3aba80f5U, 0x73a0d3bcU, + 0x88a62e47U, 0x27e1c6e8U, 0x77a5d2b8U, 0x44591d8bU, + 0xf645b339U, 0x653154aaU, 0xd72dfa18U, 0x7d2f52b2U, + 0xff0ff030U, 0x58421a97U, 0x706010bfU, 0x52c89a9dU, + 0xc8f63e07U, 0xb1d0617eU, 0xc5b97c0aU, 0x411c5d8eU, + 0xab4ee564U, 0x9378eb5cU, 0x202404efU, 0xe99e7726U, + 0x8769ee48U, 0x0bc6cdc4U, 0xc679bf09U, 0x405c1c8fU, + 0xf0c0303fU, 0x03cccfccU, 0x550d589aU, 0x357540faU, + 0x49165f86U, 0x4d135e82U, 0x91f8695eU, 0xb9da6376U, + 0xca76bc05U, 0x90b8285fU, 0x42dc9e8dU, 0xb615a379U, + 0x12988addU, 0x8b66ed44U, 0x0e838dc1U, 0x014c4dceU, + 0xb89a2277U, 0x9b72e954U, 0x8de36e42U, 0xf98a7336U, + 0x80ac2c4fU, 0xbc9f2373U, 0x95fd685aU, 0x9f77e850U, + 0xd4ed391bU, 0xfb0af134U, 0x383a02f7U, 0xde67b911U, + 0x6afe94a5U, 0xcb36fd04U, 0x115849deU, 0x0a868cc5U, + 0x48561e87U, 0x2d6b46e2U, 0xbf5fe070U, 0xb495217bU, + 0x1e9789d1U, 0x6bbed5a4U, 0x2eab85e1U, 0x3ebf81f1U, + 0xda62b815U, 0x59025b96U, 0xa204a66dU, 0xd5ad781aU, + 0xccf33f03U, 0xa601a769U, 0x216445eeU, 0x05494ccaU, + 0x693e57a6U, 0x1a9288d5U, 0x3bfac1f4U, 0xd8e23a17U, + 0xeb1ef524U, 0x45195c8aU, 0xe711f628U, 0xee5bb521U, + 0x9cb72b53U, 0x3fffc0f0U, 0x09464fc6U, 0x4f93dc80U, + 0x141d09dbU, 0x8f63ec40U, 0xc9b67f06U, 0x7c6f13b3U, + 0x19524bd6U, 0x4799de88U, 0x81ec6d4eU, 0x04090dcbU, + 0xa344e76cU, 0xd328fb1cU, 0x18120ad7U, 0xdda77a12U, + 0x3e6c52dcU, 0x273215c5U, 0xc2af6d20U, 0x9ee47a7cU, + 0x561e48b4U, 0xe2876500U, 0x912bba73U, 0xbb893259U, + 0x3dac91dfU, 0xbf8c335dU, 0x35a693d7U, 0x6e28468cU, + 0xc56aaf27U, 0x8af57f68U, 0xd57eab37U, 0x71f38293U, + 0xc965ac2bU, 0xf819e11aU, 0x0f101fedU, 0xbc4cf05eU, + 0xcd60ad2fU, 0x9fa43b7dU, 0x75f68397U, 0x6a2d4788U, + 0xcfe02f2dU, 0x74b6c296U, 0x29bd94cbU, 0xfd5ca11fU, + 0x408fcfa2U, 0x7f7c039dU, 0x7dfc819fU, 0x031f1ce1U, + 0x170e19f5U, 0x6ca8c48eU, 0x24f2d6c6U, 0xb6c67054U, + 0x233714c1U, 0xdab16b38U, 0x071a1de5U, 0x8c70fc6eU, + 0xa91db44bU, 0x34e6d2d6U, 0x49c58cabU, 0x68adc58aU, + 0xd2bb6930U, 0x5a114bb8U, 0xd7fe2935U, 0xec08e40eU, + 0xf6966014U, 0xab9d3649U, 0x158e9bf7U, 0xc3ef2c21U, + 0x420f4da0U, 0x45ca8fa7U, 0xc6aa6c24U, 0x332310d1U, + 0x67620585U, 0x1a415bf8U, 0x372611d5U, 0x8ef07e6cU, + 0xb043f352U, 0x5b510ab9U, 0x9921b87bU, 0xffdc231dU, + 0x78b9c19aU, 0x79f9809bU, 0xfbd92219U, 0x96ee7874U, + 0xaadd7748U, 0xa85df54aU, 0x39a990dbU, 0x8fb03f6dU, + 0x6b6d0689U, 0x00dfdfe2U, 0x952ebb77U, 0x019f9ee3U, + 0xfe9c621cU, 0x73730091U, 0x5891c9baU, 0xc7ea2d25U, + 0xc42aee26U, 0xc825ed2aU, 0x63670481U, 0xaf98374dU, + 0xa057f742U, 0xf416e216U, 0x0e505eecU, 0x4b450ea9U, + 0x86fa7c64U, 0xcaa56f28U, 0x59d188bbU, 0x4885cdaaU, + 0xa452f646U, 0x3cecd0deU, 0x130b18f1U, 0xb103b253U, + 0x1d8499ffU, 0xf556a317U, 0x5dd489bfU, 0x1cc4d8feU, + 0xe80de50aU, 0x04dadee6U, 0x227755c0U, 0xefc8270dU, + 0xf153a213U, 0xed48a50fU, 0x946efa76U, 0x8935bc6bU, + 0x61e78683U, 0xe147a603U, 0x847afe66U, 0x7b790299U, + 0x366650d4U, 0x65e28787U, 0x7cbcc09eU, 0x38e9d1daU, + 0x1b011af9U, 0x2a7d57c8U, 0xf959a01bU, 0x2cf8d4ceU, + 0x549ecab6U, 0xbd0cb15fU, 0x6de8858fU, 0xfa996318U, + 0xe7c22505U, 0x76364094U, 0x460a4ca4U, 0x1f041bfdU, + 0xcea06e2cU, 0x9ba13a79U, 0x4f400fadU, 0x2e7856ccU, + 0x64a2c686U, 0x7a394398U, 0x853abf67U, 0xb3833051U, + 0xebcd2609U, 0xbac97358U, 0xaed8764cU, 0x5e144abcU, + 0x82ff7d60U, 0xe007e702U, 0x31a392d3U, 0xe3c72401U, + 0xe6826404U, 0xdff42b3dU, 0x10cbdbf2U, 0xf7d62115U, + 0x0b151ee9U, 0xb506b357U, 0x0d909defU, 0x30e3d3d2U, + 0xd3fb2831U, 0x2b3d16c9U, 0xad18b54fU, 0xa512b747U, + 0xb2c37150U, 0x575e09b5U, 0xa3973441U, 0xea8d6708U, + 0x118b9af3U, 0xbecc725cU, 0xee88660cU, 0xdd74a93fU, + 0x6f68078dU, 0xfc1ce01eU, 0x4e004eacU, 0xe402e606U, + 0x66224484U, 0xc16fae23U, 0xe94da40bU, 0xcbe52e29U, + 0x51db8ab3U, 0x28fdd5caU, 0x5c94c8beU, 0xd831e93aU, + 0x326351d0U, 0x0a555fe8U, 0xb909b05bU, 0x70b3c392U, + 0x1e445afcU, 0x92eb7970U, 0x5f540bbdU, 0xd971a83bU, + 0x69ed848bU, 0x9ae17b78U, 0xcc20ec2eU, 0xac58f44eU, + 0xd03beb32U, 0xd43eea36U, 0x08d5ddeaU, 0x20f7d7c2U, + 0x535b08b1U, 0x09959cebU, 0xdbf12a39U, 0x2f3817cdU, + 0x8bb53e69U, 0x124b59f0U, 0x97ae3975U, 0x9861f97aU, + 0x21b796c3U, 0x025f5de0U, 0x14cedaf6U, 0x60a7c782U, + 0x198198fbU, 0x25b297c7U, 0x0cd0dceeU, 0x065a5ce4U, + 0x4dc08dafU, 0x62274580U, 0xa117b643U, 0x474a0da5U, + 0xf3d32011U, 0x521b49b0U, 0x8875fd6aU, 0x93ab3871U, + 0xd17baa33U, 0xb446f256U, 0x267254c4U, 0x2db895cfU, + 0x87ba3d65U, 0xf2936110U, 0xb7863155U, 0xa7923545U, + 0x434f0ca1U, 0xc02fef22U, 0x3b2912d9U, 0x4c80ccaeU, + 0x55de8bb7U, 0x3f2c13ddU, 0xb849f15aU, 0x9c64f87eU, + 0xf013e312U, 0x83bf3c61U, 0xa2d77540U, 0x41cf8ea3U, + 0x72334190U, 0xdc34e83eU, 0x7e3c429cU, 0x77760195U, + 0x059a9fe7U, 0xa6d27444U, 0x906bfb72U, 0xd6be6834U, + 0x8d30bd6fU, 0x164e58f4U, 0x509bcbb2U, 0xe542a707U, + 0x807fff62U, 0xdeb46a3cU, 0x18c1d9faU, 0x9d24b97fU, + 0x3a6953d8U, 0x4a054fa8U, 0x813fbe63U, 0x448acea6U, + 0x92b321afU, 0x8bed66b6U, 0x6e701e53U, 0x323b090fU, + 0xfac13bc7U, 0x4e581673U, 0x3df4c900U, 0x1756412aU, + 0x9173e2acU, 0x1353402eU, 0x9979e0a4U, 0xc2f735ffU, + 0x69b5dc54U, 0x262a0c1bU, 0x79a1d844U, 0xdd2cf1e0U, + 0x65badf58U, 0x54c69269U, 0xa3cf6c9eU, 0x1093832dU, + 0x61bfde5cU, 0x337b480eU, 0xd929f0e4U, 0xc6f234fbU, + 0x633f5c5eU, 0xd869b1e5U, 0x8562e7b8U, 0x5183d26cU, + 0xec50bcd1U, 0xd3a370eeU, 0xd123f2ecU, 0xafc06f92U, + 0xbbd16a86U, 0xc077b7fdU, 0x882da5b5U, 0x1a190327U, + 0x8fe867b2U, 0x766e184bU, 0xabc56e96U, 0x20af8f1dU, + 0x05c2c738U, 0x9839a1a5U, 0xe51affd8U, 0xc472b6f9U, + 0x7e641a43U, 0xf6ce38cbU, 0x7b215a46U, 0x40d7977dU, + 0x5a491367U, 0x0742453aU, 0xb951e884U, 0x6f305f52U, + 0xeed03ed3U, 0xe915fcd4U, 0x6a751f57U, 0x9ffc63a2U, + 0xcbbd76f6U, 0xb69e288bU, 0x9bf962a6U, 0x222f0d1fU, + 0x1c9c8021U, 0xf78e79caU, 0x35fecb08U, 0x5303506eU, + 0xd466b2e9U, 0xd526f3e8U, 0x5706516aU, 0x3a310b07U, + 0x0602043bU, 0x04828639U, 0x9576e3a8U, 0x236f4c1eU, + 0xc7b275faU, 0xac00ac91U, 0x39f1c804U, 0xad40ed90U, + 0x5243116fU, 0xdfac73e2U, 0xf44ebac9U, 0x6b355e56U, + 0x68f59d55U, 0x64fa9e59U, 0xcfb877f2U, 0x0347443eU, + 0x0c888431U, 0x58c99165U, 0xa28f2d9fU, 0xe79a7ddaU, + 0x2a250f17U, 0x667a1c5bU, 0xf50efbc8U, 0xe45abed9U, + 0x088d8535U, 0x9033a3adU, 0xbfd46b82U, 0x1ddcc120U, + 0xb15bea8cU, 0x5989d064U, 0xf10bfaccU, 0xb01bab8dU, + 0x44d29679U, 0xa805ad95U, 0x8ea826b3U, 0x4317547eU, + 0x5d8cd160U, 0x4197d67cU, 0x38b18905U, 0x25eacf18U, + 0xcd38f5f0U, 0x4d98d570U, 0x28a58d15U, 0xd7a671eaU, + 0x9ab923a7U, 0xc93df4f4U, 0xd063b3edU, 0x9436a2a9U, + 0xb7de698aU, 0x86a224bbU, 0x5586d368U, 0x8027a7bdU, + 0xf841b9c5U, 0x11d3c22cU, 0xc137f6fcU, 0x5646106bU, + 0x4b1d5676U, 0xdae933e7U, 0xead53fd7U, 0xb3db688eU, + 0x627f1d5fU, 0x377e490aU, 0xe39f7cdeU, 0x82a725bfU, + 0xc87db5f5U, 0xd6e630ebU, 0x29e5cc14U, 0x1f5c4322U, + 0x4712557aU, 0x1616002bU, 0x0207053fU, 0xf2cb39cfU, + 0x2e200e13U, 0x4cd89471U, 0x9d7ce1a0U, 0x4f185772U, + 0x4a5d1777U, 0x732b584eU, 0xbc14a881U, 0x5b095266U, + 0xa7ca6d9aU, 0x19d9c024U, 0xa14fee9cU, 0x9c3ca0a1U, + 0x7f245b42U, 0x87e265baU, 0x01c7c63cU, 0x09cdc434U, + 0x1e1c0223U, 0xfb817ac6U, 0x0f484732U, 0x4652147bU, + 0xbd54e980U, 0x1213012fU, 0x4257157fU, 0x71abda4cU, + 0xc3b774feU, 0x50c3936dU, 0xe2df3ddfU, 0x48dd9575U, + 0xcafd37f7U, 0x6db0dd50U, 0x4592d778U, 0x673a5d5aU, + 0xfd04f9c0U, 0x8422a6b9U, 0xf04bbbcdU, 0x74ee9a49U, + 0x9ebc22a3U, 0xa68a2c9bU, 0x15d6c328U, 0xdc6cb0e1U, + 0xb29b298fU, 0x3e340a03U, 0xf38b78ceU, 0x75aedb48U, + 0xc532f7f8U, 0x363e080bU, 0x60ff9f5dU, 0x0087873dU, + 0x7ce49841U, 0x78e19945U, 0xa40aae99U, 0x8c28a4b1U, + 0xff847bc2U, 0xa54aef98U, 0x772e594aU, 0x83e764beU, + 0x276a4d1aU, 0xbe942a83U, 0x3b714a06U, 0x34be8a09U, + 0x8d68e5b0U, 0xae802e93U, 0xb811a985U, 0xcc78b4f1U, + 0xb55eeb88U, 0x896de4b4U, 0xa00faf9dU, 0xaa852f97U, + 0xe11ffedcU, 0xcef836f3U, 0x0dc8c530U, 0xeb957ed6U, + 0x5f0c5362U, 0xfec43ac3U, 0x24aa8e19U, 0x3f744b02U, + 0x7da4d940U, 0x18998125U, 0x8aad27b7U, 0x8167e6bcU, + 0x2b654e16U, 0x5e4c1263U, 0x1b594226U, 0x0b4d4636U, + 0xef907fd2U, 0x6cf09c51U, 0x97f661aaU, 0xe05fbfddU, + 0xf901f8c4U, 0x93f360aeU, 0x14968229U, 0x30bb8b0dU, + 0x5ccc9061U, 0x2f604f12U, 0x0e080633U, 0xed10fdd0U, + 0xdeec32e3U, 0x70eb9b4dU, 0xd2e331efU, 0xdba972e6U, + 0xa945ec94U, 0x0a0d0737U, 0x3cb48801U, 0x7a611b47U, + 0x21efce1cU, 0xba912b87U, 0xfc44b8c1U, 0x499dd474U, + 0x2ca08c11U, 0x726b194fU, 0xb41eaa89U, 0x31fbca0cU, + 0x96b620abU, 0xe6da3cdbU, 0x2de0cd10U, 0xe855bdd5U, + 0x303b0b85U, 0x29654c9cU, 0xccf83479U, 0x90b32325U, + 0x584911edU, 0xecd03c59U, 0x9f7ce32aU, 0xb5de6b00U, + 0x33fbc886U, 0xb1db6a04U, 0x3bf1ca8eU, 0x607f1fd5U, + 0xcb3df67eU, 0x84a22631U, 0xdb29f26eU, 0x7fa4dbcaU, + 0xc732f572U, 0xf64eb843U, 0x014746b4U, 0xb21ba907U, + 0xc337f476U, 0x91f36224U, 0x7ba1daceU, 0x647a1ed1U, + 0xc1b77674U, 0x7ae19bcfU, 0x27eacd92U, 0xf30bf846U, + 0x4ed896fbU, 0x712b5ac4U, 0x73abd8c6U, 0x0d4845b8U, + 0x195940acU, 0x62ff9dd7U, 0x2aa58f9fU, 0xb891290dU, + 0x2d604d98U, 0xd4e63261U, 0x094d44bcU, 0x8227a537U, + 0xa74aed12U, 0x3ab18b8fU, 0x4792d5f2U, 0x66fa9cd3U, + 0xdcec3069U, 0x544612e1U, 0xd9a9706cU, 0xe25fbd57U, + 0xf8c1394dU, 0xa5ca6f10U, 0x1bd9c2aeU, 0xcdb87578U, + 0x4c5814f9U, 0x4b9dd6feU, 0xc8fd357dU, 0x3d744988U, + 0x69355cdcU, 0x141602a1U, 0x3971488cU, 0x80a72735U, + 0xbe14aa0bU, 0x550653e0U, 0x9776e122U, 0xf18b7a44U, + 0x76ee98c3U, 0x77aed9c2U, 0xf58e7b40U, 0x98b9212dU, + 0xa48a2e11U, 0xa60aac13U, 0x37fec982U, 0x81e76634U, + 0x653a5fd0U, 0x0e8886bbU, 0x9b79e22eU, 0x0fc8c7baU, + 0xf0cb3b45U, 0x7d2459c8U, 0x56c690e3U, 0xc9bd747cU, + 0xca7db77fU, 0xc672b473U, 0x6d305dd8U, 0xa1cf6e14U, + 0xae00ae1bU, 0xfa41bb4fU, 0x000707b5U, 0x451257f0U, + 0x88ad253dU, 0xc4f23671U, 0x5786d1e2U, 0x46d294f3U, + 0xaa05af1fU, 0x32bb8987U, 0x1d5c41a8U, 0xbf54eb0aU, + 0x13d3c0a6U, 0xfb01fa4eU, 0x5383d0e6U, 0x129381a7U, + 0xe65abc53U, 0x0a8d87bfU, 0x2c200c99U, 0xe19f7e54U, + 0xff04fb4aU, 0xe31ffc56U, 0x9a39a32fU, 0x8762e532U, + 0x6fb0dfdaU, 0xef10ff5aU, 0x8a2da73fU, 0x752e5bc0U, + 0x3831098dU, 0x6bb5dedeU, 0x72eb99c7U, 0x36be8883U, + 0x155643a0U, 0x242a0e91U, 0xf70ef942U, 0x22af8d97U, + 0x5ac993efU, 0xb35be806U, 0x63bfdcd6U, 0xf4ce3a41U, + 0xe9957c5cU, 0x786119cdU, 0x485d15fdU, 0x115342a4U, + 0xc0f73775U, 0x95f66320U, 0x411756f4U, 0x202f0f95U, + 0x6af59fdfU, 0x746e1ac1U, 0x8b6de63eU, 0xbdd46908U, + 0xe59a7f50U, 0xb49e2a01U, 0xa08f2f15U, 0x504313e5U, + 0x8ca82439U, 0xee50be5bU, 0x3ff4cb8aU, 0xed907d58U, + 0xe8d53d5dU, 0xd1a37264U, 0x1e9c82abU, 0xf981784cU, + 0x054247b0U, 0xbb51ea0eU, 0x03c7c4b6U, 0x3eb48a8bU, + 0xddac7168U, 0x256a4f90U, 0xa34fec16U, 0xab45ee1eU, + 0xbc942809U, 0x590950ecU, 0xadc06d18U, 0xe4da3e51U, + 0x1fdcc3aaU, 0xb09b2b05U, 0xe0df3f55U, 0xd323f066U, + 0x613f5ed4U, 0xf24bb947U, 0x405717f5U, 0xea55bf5fU, + 0x68751dddU, 0xcf38f77aU, 0xe71afd52U, 0xc5b27770U, + 0x5f8cd3eaU, 0x26aa8c93U, 0x52c391e7U, 0xd666b063U, + 0x3c340889U, 0x040206b1U, 0xb75ee902U, 0x7ee49acbU, + 0x101303a5U, 0x9cbc2029U, 0x510352e4U, 0xd726f162U, + 0x67baddd2U, 0x94b62221U, 0xc277b577U, 0xa20fad17U, + 0xde6cb26bU, 0xda69b36fU, 0x068284b3U, 0x2ea08e9bU, + 0x5d0c51e8U, 0x07c2c5b2U, 0xd5a67360U, 0x216f4e94U, + 0x85e26730U, 0x1c1c00a9U, 0x99f9602cU, 0x9636a023U, + 0x2fe0cf9aU, 0x0c0804b9U, 0x1a9983afU, 0x6ef09edbU, + 0x17d6c1a2U, 0x2be5ce9eU, 0x028785b7U, 0x080d05bdU, + 0x4397d4f6U, 0x6c701cd9U, 0xaf40ef1aU, 0x491d54fcU, + 0xfd847948U, 0x5c4c10e9U, 0x8622a433U, 0x9dfc6128U, + 0xdf2cf36aU, 0xba11ab0fU, 0x28250d9dU, 0x23efcc96U, + 0x89ed643cU, 0xfcc43849U, 0xb9d1680cU, 0xa9c56c1cU, + 0x4d1855f8U, 0xce78b67bU, 0x357e4b80U, 0x42d795f7U, + 0x5b89d2eeU, 0x317b4a84U, 0xb61ea803U, 0x9233a127U, + 0xfe44ba4bU, 0x8de86538U, 0xac802c19U, 0x4f98d7faU, + 0x7c6418c9U, 0xd263b167U, 0x706b1bc5U, 0x792158ccU, + 0x0bcdc6beU, 0xa8852d1dU, 0x9e3ca22bU, 0xd8e9316dU, + 0x8367e436U, 0x181901adU, 0x5ecc92ebU, 0xeb15fe5eU, + 0x8e28a63bU, 0xd0e33365U, 0x169680a3U, 0x9373e026U, + 0x343e0a81U, 0x445216f1U, 0x8f68e73aU, 0x4add97ffU, + 0x15988d03U, 0x0cc6ca1aU, 0xe95bb2ffU, 0xb510a5a3U, + 0x7dea976bU, 0xc973badfU, 0xbadf65acU, 0x907ded86U, + 0x16584e00U, 0x9478ec82U, 0x1e524c08U, 0x45dc9953U, + 0xee9e70f8U, 0xa101a0b7U, 0xfe8a74e8U, 0x5a075d4cU, + 0xe29173f4U, 0xd3ed3ec5U, 0x24e4c032U, 0x97b82f81U, + 0xe69472f0U, 0xb450e4a2U, 0x5e025c48U, 0x41d99857U, + 0xe414f0f2U, 0x5f421d49U, 0x02494b14U, 0xd6a87ec0U, + 0x6b7b107dU, 0x5488dc42U, 0x56085e40U, 0x28ebc33eU, + 0x3cfac62aU, 0x475c1b51U, 0x0f060919U, 0x9d32af8bU, + 0x08c3cb1eU, 0xf145b4e7U, 0x2ceec23aU, 0xa78423b1U, + 0x82e96b94U, 0x1f120d09U, 0x62315374U, 0x43591a55U, + 0xf94fb6efU, 0x71e59467U, 0xfc0af6eaU, 0xc7fc3bd1U, + 0xdd62bfcbU, 0x8069e996U, 0x3e7a4428U, 0xe81bf3feU, + 0x69fb927fU, 0x6e3e5078U, 0xed5eb3fbU, 0x18d7cf0eU, + 0x4c96da5aU, 0x31b58427U, 0x1cd2ce0aU, 0xa504a1b3U, + 0x9bb72c8dU, 0x70a5d566U, 0xb2d567a4U, 0xd428fcc2U, + 0x534d1e45U, 0x520d5f44U, 0xd02dfdc6U, 0xbd1aa7abU, + 0x8129a897U, 0x83a92a95U, 0x125d4f04U, 0xa444e0b2U, + 0x4099d956U, 0x2b2b003dU, 0xbeda64a8U, 0x2a6b413cU, + 0xd568bdc3U, 0x5887df4eU, 0x73651665U, 0xec1ef2faU, + 0xefde31f9U, 0xe3d132f5U, 0x4893db5eU, 0x846ce892U, + 0x8ba3289dU, 0xdfe23dc9U, 0x25a48133U, 0x60b1d176U, + 0xad0ea3bbU, 0xe151b0f7U, 0x72255764U, 0x63711275U, + 0x8fa62999U, 0x17180f01U, 0x38ffc72eU, 0x9af76d8cU, + 0x36704620U, 0xdea27cc8U, 0x76205660U, 0x37300721U, + 0xc3f93ad5U, 0x2f2e0139U, 0x09838a1fU, 0xc43cf8d2U, + 0xdaa77dccU, 0xc6bc7ad0U, 0xbf9a25a9U, 0xa2c163b4U, + 0x4a13595cU, 0xcab379dcU, 0xaf8e21b9U, 0x508ddd46U, + 0x1d928f0bU, 0x4e165858U, 0x57481f41U, 0x131d0e05U, + 0x30f5c526U, 0x01898817U, 0xd2ad7fc4U, 0x070c0b11U, + 0x7f6a1569U, 0x96f86e80U, 0x461c5a50U, 0xd16dbcc7U, + 0xcc36fadaU, 0x5dc29f4bU, 0x6dfe937bU, 0x34f0c422U, + 0xe554b1f3U, 0xb055e5a6U, 0x64b4d072U, 0x058c8913U, + 0x4f561959U, 0x51cd9c47U, 0xaece60b8U, 0x9877ef8eU, + 0xc039f9d6U, 0x913dac87U, 0x852ca993U, 0x75e09563U, + 0xa90ba2bfU, 0xcbf338ddU, 0x1a574d0cU, 0xc833fbdeU, + 0xcd76bbdbU, 0xf400f4e2U, 0x3b3f042dU, 0xdc22fecaU, + 0x20e1c136U, 0x9ef26c88U, 0x26644230U, 0x1b170c0dU, + 0xf80ff7eeU, 0x00c9c916U, 0x86ec6a90U, 0x8ee66898U, + 0x9937ae8fU, 0x7caad66aU, 0x8863eb9eU, 0xc179b8d7U, + 0x3a7f452cU, 0x9538ad83U, 0xc57cb9d3U, 0xf68076e0U, + 0x449cd852U, 0xd7e83fc1U, 0x65f49173U, 0xcff639d9U, + 0x4dd69b5bU, 0xea9b71fcU, 0xc2b97bd4U, 0xe011f1f6U, + 0x7a2f556cU, 0x03090a15U, 0x77601761U, 0xf3c536e5U, + 0x19978e0fU, 0x21a18037U, 0x92fd6f84U, 0x5b471c4dU, + 0x35b08523U, 0xb91fa6afU, 0x74a0d462U, 0xf28577e4U, + 0x42195b54U, 0xb115a4a7U, 0xe7d433f1U, 0x87ac2b91U, + 0xfbcf34edU, 0xffca35e9U, 0x23210235U, 0x0b03081dU, + 0x78afd76eU, 0x22614334U, 0xf005f5e6U, 0x04ccc812U, + 0xa041e1b6U, 0x39bf862fU, 0xbc5ae6aaU, 0xb39526a5U, + 0x0a43491cU, 0x29ab823fU, 0x3f3a0529U, 0x4b53185dU, + 0x32754724U, 0x0e464818U, 0x27240331U, 0x2dae833bU, + 0x66345270U, 0x49d39a5fU, 0x8ae3699cU, 0x6cbed27aU, + 0xd827ffceU, 0x79ef966fU, 0xa38122b5U, 0xb85fe7aeU, + 0xfa8f75ecU, 0x9fb22d89U, 0x0d868b1bU, 0x064c4a10U, + 0xac4ee2baU, 0xd967becfU, 0x9c72ee8aU, 0x8c66ea9aU, + 0x68bbd37eU, 0xebdb30fdU, 0x10ddcd06U, 0x67741371U, + 0x7e2a5468U, 0x14d8cc02U, 0x93bd2e85U, 0xb79027a1U, + 0xdbe73ccdU, 0xa84be3beU, 0x8923aa9fU, 0x6a3b517cU, + 0x59c79e4fU, 0xf7c037e1U, 0x55c89d43U, 0x5c82de4aU, + 0x2e6e4038U, 0x8d26ab9bU, 0xbb9f24adU, 0xfd4ab7ebU, + 0xa6c462b0U, 0x3dba872bU, 0x7b6f146dU, 0xceb678d8U, + 0xab8b20bdU, 0xf540b5e3U, 0x33350625U, 0xb6d066a0U, + 0x119d8c07U, 0x61f19077U, 0xaacb61bcU, 0x6f7e1179U, + 0x353a0f81U, 0x2c644898U, 0xc9f9307dU, 0x95b22721U, + 0x5d4815e9U, 0xe9d1385dU, 0x9a7de72eU, 0xb0df6f04U, + 0x36facc82U, 0xb4da6e00U, 0x3ef0ce8aU, 0x657e1bd1U, + 0xce3cf27aU, 0x81a32235U, 0xde28f66aU, 0x7aa5dfceU, + 0xc233f176U, 0xf34fbc47U, 0x044642b0U, 0xb71aad03U, + 0xc636f072U, 0x94f26620U, 0x7ea0decaU, 0x617b1ad5U, + 0xc4b67270U, 0x7fe09fcbU, 0x22ebc996U, 0xf60afc42U, + 0x4bd992ffU, 0x742a5ec0U, 0x76aadcc2U, 0x084941bcU, + 0x1c5844a8U, 0x67fe99d3U, 0x2fa48b9bU, 0xbd902d09U, + 0x2861499cU, 0xd1e73665U, 0x0c4c40b8U, 0x8726a133U, + 0xa24be916U, 0x3fb08f8bU, 0x4293d1f6U, 0x63fb98d7U, + 0xd9ed346dU, 0x514716e5U, 0xdca87468U, 0xe75eb953U, + 0xfdc03d49U, 0xa0cb6b14U, 0x1ed8c6aaU, 0xc8b9717cU, + 0x495910fdU, 0x4e9cd2faU, 0xcdfc3179U, 0x38754d8cU, + 0x6c3458d8U, 0x111706a5U, 0x3c704c88U, 0x85a62331U, + 0xbb15ae0fU, 0x500757e4U, 0x9277e526U, 0xf48a7e40U, + 0x73ef9cc7U, 0x72afddc6U, 0xf08f7f44U, 0x9db82529U, + 0xa18b2a15U, 0xa30ba817U, 0x32ffcd86U, 0x84e66230U, + 0x603b5bd4U, 0x0b8982bfU, 0x9e78e62aU, 0x0ac9c3beU, + 0xf5ca3f41U, 0x78255dccU, 0x53c794e7U, 0xccbc7078U, + 0xcf7cb37bU, 0xc373b077U, 0x683159dcU, 0xa4ce6a10U, + 0xab01aa1fU, 0xff40bf4bU, 0x050603b1U, 0x401353f4U, + 0x8dac2139U, 0xc1f33275U, 0x5287d5e6U, 0x43d390f7U, + 0xaf04ab1bU, 0x37ba8d83U, 0x185d45acU, 0xba55ef0eU, + 0x16d2c4a2U, 0xfe00fe4aU, 0x5682d4e2U, 0x179285a3U, + 0xe35bb857U, 0x0f8c83bbU, 0x2921089dU, 0xe49e7a50U, + 0xfa05ff4eU, 0xe61ef852U, 0x9f38a72bU, 0x8263e136U, + 0x6ab1dbdeU, 0xea11fb5eU, 0x8f2ca33bU, 0x702f5fc4U, + 0x3d300d89U, 0x6eb4dadaU, 0x77ea9dc3U, 0x33bf8c87U, + 0x105747a4U, 0x212b0a95U, 0xf20ffd46U, 0x27ae8993U, + 0x5fc897ebU, 0xb65aec02U, 0x66bed8d2U, 0xf1cf3e45U, + 0xec947858U, 0x7d601dc9U, 0x4d5c11f9U, 0x145246a0U, + 0xc5f63371U, 0x90f76724U, 0x441652f0U, 0x252e0b91U, + 0x6ff49bdbU, 0x716f1ec5U, 0x8e6ce23aU, 0xb8d56d0cU, + 0xe09b7b54U, 0xb19f2e05U, 0xa58e2b11U, 0x554217e1U, + 0x89a9203dU, 0xeb51ba5fU, 0x3af5cf8eU, 0xe891795cU, + 0xedd43959U, 0xd4a27660U, 0x1b9d86afU, 0xfc807c48U, + 0x004343b4U, 0xbe50ee0aU, 0x06c6c0b2U, 0x3bb58e8fU, + 0xd8ad756cU, 0x206b4b94U, 0xa64ee812U, 0xae44ea1aU, + 0xb9952c0dU, 0x5c0854e8U, 0xa8c1691cU, 0xe1db3a55U, + 0x1addc7aeU, 0xb59a2f01U, 0xe5de3b51U, 0xd622f462U, + 0x643e5ad0U, 0xf74abd43U, 0x455613f1U, 0xef54bb5bU, + 0x6d7419d9U, 0xca39f37eU, 0xe21bf956U, 0xc0b37374U, + 0x5a8dd7eeU, 0x23ab8897U, 0x57c295e3U, 0xd367b467U, + 0x39350c8dU, 0x010302b5U, 0xb25fed06U, 0x7be59ecfU, + 0x151207a1U, 0x99bd242dU, 0x540256e0U, 0xd227f566U, + 0x62bbd9d6U, 0x91b72625U, 0xc776b173U, 0xa70ea913U, + 0xdb6db66fU, 0xdf68b76bU, 0x038380b7U, 0x2ba18a9fU, + 0x580d55ecU, 0x02c3c1b6U, 0xd0a77764U, 0x246e4a90U, + 0x80e36334U, 0x191d04adU, 0x9cf86428U, 0x9337a427U, + 0x2ae1cb9eU, 0x090900bdU, 0x1f9887abU, 0x6bf19adfU, + 0x12d7c5a6U, 0x2ee4ca9aU, 0x078681b3U, 0x0d0c01b9U, + 0x4696d0f2U, 0x697118ddU, 0xaa41eb1eU, 0x4c1c50f8U, + 0xf8857d4cU, 0x594d14edU, 0x8323a037U, 0x98fd652cU, + 0xda2df76eU, 0xbf10af0bU, 0x2d240999U, 0x26eec892U, + 0x8cec6038U, 0xf9c53c4dU, 0xbcd06c08U, 0xacc46818U, + 0x481951fcU, 0xcb79b27fU, 0x307f4f84U, 0x47d691f3U, + 0x5e88d6eaU, 0x347a4e80U, 0xb31fac07U, 0x9732a523U, + 0xfb45be4fU, 0x88e9613cU, 0xa981281dU, 0x4a99d3feU, + 0x79651ccdU, 0xd762b563U, 0x756a1fc1U, 0x7c205cc8U, + 0x0eccc2baU, 0xad842919U, 0x9b3da62fU, 0xdde83569U, + 0x8666e032U, 0x1d1805a9U, 0x5bcd96efU, 0xee14fa5aU, + 0x8b29a23fU, 0xd5e23761U, 0x139784a7U, 0x9672e422U, + 0x313f0e85U, 0x415312f5U, 0x8a69e33eU, 0x4fdc93fbU, + 0x1f9a850bU, 0x06c4c212U, 0xe359baf7U, 0xbf12adabU, + 0x77e89f63U, 0xc371b2d7U, 0xb0dd6da4U, 0x9a7fe58eU, + 0x1c5a4608U, 0x9e7ae48aU, 0x14504400U, 0x4fde915bU, + 0xe49c78f0U, 0xab03a8bfU, 0xf4887ce0U, 0x50055544U, + 0xe8937bfcU, 0xd9ef36cdU, 0x2ee6c83aU, 0x9dba2789U, + 0xec967af8U, 0xbe52ecaaU, 0x54005440U, 0x4bdb905fU, + 0xee16f8faU, 0x55401541U, 0x084b431cU, 0xdcaa76c8U, + 0x61791875U, 0x5e8ad44aU, 0x5c0a5648U, 0x22e9cb36U, + 0x36f8ce22U, 0x4d5e1359U, 0x05040111U, 0x9730a783U, + 0x02c1c316U, 0xfb47bcefU, 0x26ecca32U, 0xad862bb9U, + 0x88eb639cU, 0x15100501U, 0x68335b7cU, 0x495b125dU, + 0xf34dbee7U, 0x7be79c6fU, 0xf608fee2U, 0xcdfe33d9U, + 0xd760b7c3U, 0x8a6be19eU, 0x34784c20U, 0xe219fbf6U, + 0x63f99a77U, 0x643c5870U, 0xe75cbbf3U, 0x12d5c706U, + 0x4694d252U, 0x3bb78c2fU, 0x16d0c602U, 0xaf06a9bbU, + 0x91b52485U, 0x7aa7dd6eU, 0xb8d76facU, 0xde2af4caU, + 0x594f164dU, 0x580f574cU, 0xda2ff5ceU, 0xb718afa3U, + 0x8b2ba09fU, 0x89ab229dU, 0x185f470cU, 0xae46e8baU, + 0x4a9bd15eU, 0x21290835U, 0xb4d86ca0U, 0x20694934U, + 0xdf6ab5cbU, 0x5285d746U, 0x79671e6dU, 0xe61cfaf2U, + 0xe5dc39f1U, 0xe9d33afdU, 0x4291d356U, 0x8e6ee09aU, + 0x81a12095U, 0xd5e035c1U, 0x2fa6893bU, 0x6ab3d97eU, + 0xa70cabb3U, 0xeb53b8ffU, 0x78275f6cU, 0x69731a7dU, + 0x85a42191U, 0x1d1a0709U, 0x32fdcf26U, 0x90f56584U, + 0x3c724e28U, 0xd4a074c0U, 0x7c225e68U, 0x3d320f29U, + 0xc9fb32ddU, 0x252c0931U, 0x03818217U, 0xce3ef0daU, + 0xd0a575c4U, 0xccbe72d8U, 0xb5982da1U, 0xa8c36bbcU, + 0x40115154U, 0xc0b171d4U, 0xa58c29b1U, 0x5a8fd54eU, + 0x17908703U, 0x44145050U, 0x5d4a1749U, 0x191f060dU, + 0x3af7cd2eU, 0x0b8b801fU, 0xd8af77ccU, 0x0d0e0319U, + 0x75681d61U, 0x9cfa6688U, 0x4c1e5258U, 0xdb6fb4cfU, + 0xc634f2d2U, 0x57c09743U, 0x67fc9b73U, 0x3ef2cc2aU, + 0xef56b9fbU, 0xba57edaeU, 0x6eb6d87aU, 0x0f8e811bU, + 0x45541151U, 0x5bcf944fU, 0xa4cc68b0U, 0x9275e786U, + 0xca3bf1deU, 0x9b3fa48fU, 0x8f2ea19bU, 0x7fe29d6bU, + 0xa309aab7U, 0xc1f130d5U, 0x10554504U, 0xc231f3d6U, + 0xc774b3d3U, 0xfe02fceaU, 0x313d0c25U, 0xd620f6c2U, + 0x2ae3c93eU, 0x94f06480U, 0x2c664a38U, 0x11150405U, + 0xf20dffe6U, 0x0acbc11eU, 0x8cee6298U, 0x84e46090U, + 0x9335a687U, 0x76a8de62U, 0x8261e396U, 0xcb7bb0dfU, + 0x307d4d24U, 0x9f3aa58bU, 0xcf7eb1dbU, 0xfc827ee8U, + 0x4e9ed05aU, 0xddea37c9U, 0x6ff6997bU, 0xc5f431d1U, + 0x47d49353U, 0xe09979f4U, 0xc8bb73dcU, 0xea13f9feU, + 0x702d5d64U, 0x090b021dU, 0x7d621f69U, 0xf9c73eedU, + 0x13958607U, 0x2ba3883fU, 0x98ff678cU, 0x51451445U, + 0x3fb28d2bU, 0xb31daea7U, 0x7ea2dc6aU, 0xf8877fecU, + 0x481b535cU, 0xbb17acafU, 0xedd63bf9U, 0x8dae2399U, + 0xf1cd3ce5U, 0xf5c83de1U, 0x29230a3dU, 0x01010015U, + 0x72addf66U, 0x28634b3cU, 0xfa07fdeeU, 0x0ecec01aU, + 0xaa43e9beU, 0x33bd8e27U, 0xb658eea2U, 0xb9972eadU, + 0x00414114U, 0x23a98a37U, 0x35380d21U, 0x41511055U, + 0x38774f2cU, 0x04444010U, 0x2d260b39U, 0x27ac8b33U, + 0x6c365a78U, 0x43d19257U, 0x80e16194U, 0x66bcda72U, + 0xd225f7c6U, 0x73ed9e67U, 0xa9832abdU, 0xb25defa6U, + 0xf08d7de4U, 0x95b02581U, 0x07848313U, 0x0c4e4218U, + 0xa64ceab2U, 0xd365b6c7U, 0x9670e682U, 0x8664e292U, + 0x62b9db76U, 0xe1d938f5U, 0x1adfc50eU, 0x6d761b79U, + 0x74285c60U, 0x1edac40aU, 0x99bf268dU, 0xbd922fa9U, + 0xd1e534c5U, 0xa249ebb6U, 0x8321a297U, 0x60395974U, + 0x53c59647U, 0xfdc23fe9U, 0x5fca954bU, 0x5680d642U, + 0x246c4830U, 0x8724a393U, 0xb19d2ca5U, 0xf748bfe3U, + 0xacc66ab8U, 0x37b88f23U, 0x716d1c65U, 0xc4b470d0U, + 0xa18928b5U, 0xff42bdebU, 0x39370e2dU, 0xbcd26ea8U, + 0x1b9f840fU, 0x6bf3987fU, 0xa0c969b4U, 0x657c1971U, + 0x914fde50U, 0x88119949U, 0x6d8ce1acU, 0x31c7f6f0U, + 0xf93dc438U, 0x4da4e98cU, 0x3e0836ffU, 0x14aabed5U, + 0x928f1d53U, 0x10afbfd1U, 0x9a851f5bU, 0xc10bca00U, + 0x6a4923abU, 0x25d6f3e4U, 0x7a5d27bbU, 0xded00e1fU, + 0x664620a7U, 0x573a6d96U, 0xa0339361U, 0x136f7cd2U, + 0x624321a3U, 0x3087b7f1U, 0xdad50f1bU, 0xc50ecb04U, + 0x60c3a3a1U, 0xdb954e1aU, 0x869e1847U, 0x527f2d93U, + 0xefac432eU, 0xd05f8f11U, 0xd2df0d13U, 0xac3c906dU, + 0xb82d9579U, 0xc38b4802U, 0x8bd15a4aU, 0x19e5fcd8U, + 0x8c14984dU, 0x7592e7b4U, 0xa8399169U, 0x235370e2U, + 0x063e38c7U, 0x9bc55e5aU, 0xe6e60027U, 0xc78e4906U, + 0x7d98e5bcU, 0xf532c734U, 0x78dda5b9U, 0x432b6882U, + 0x59b5ec98U, 0x04bebac5U, 0xbaad177bU, 0x6ccca0adU, + 0xed2cc12cU, 0xeae9032bU, 0x6989e0a8U, 0x9c009c5dU, + 0xc8418909U, 0xb562d774U, 0x98059d59U, 0x21d3f2e0U, + 0x1f607fdeU, 0xf4728635U, 0x360234f7U, 0x50ffaf91U, + 0xd79a4d16U, 0xd6da0c17U, 0x54faae95U, 0x39cdf4f8U, + 0x05fefbc4U, 0x077e79c6U, 0x968a1c57U, 0x2093b3e1U, + 0xc44e8a05U, 0xaffc536eU, 0x3a0d37fbU, 0xaebc126fU, + 0x51bfee90U, 0xdc508c1dU, 0xf7b24536U, 0x68c9a1a9U, + 0x6b0962aaU, 0x670661a6U, 0xcc44880dU, 0x00bbbbc1U, + 0x0f747bceU, 0x5b356e9aU, 0xa173d260U, 0xe4668225U, + 0x29d9f0e8U, 0x6586e3a4U, 0xf6f20437U, 0xe7a64126U, + 0x0b717acaU, 0x93cf5c52U, 0xbc28947dU, 0x1e203edfU, + 0xb2a71573U, 0x5a752f9bU, 0xf2f70533U, 0xb3e75472U, + 0x472e6986U, 0xabf9526aU, 0x8d54d94cU, 0x40ebab81U, + 0x5e702e9fU, 0x426b2983U, 0x3b4d76faU, 0x261630e7U, + 0xcec40a0fU, 0x4e642a8fU, 0x2b5972eaU, 0xd45a8e15U, + 0x9945dc58U, 0xcac10b0bU, 0xd39f4c12U, 0x97ca5d56U, + 0xb4229675U, 0x855edb44U, 0x567a2c97U, 0x83db5842U, + 0xfbbd463aU, 0x122f3dd3U, 0xc2cb0903U, 0x55baef94U, + 0x48e1a989U, 0xd915cc18U, 0xe929c028U, 0xb0279771U, + 0x6183e2a0U, 0x3482b6f5U, 0xe0638321U, 0x815bda40U, + 0xcb814a0aU, 0xd51acf14U, 0x2a1933ebU, 0x1ca0bcddU, + 0x44eeaa85U, 0x15eaffd4U, 0x01fbfac0U, 0xf137c630U, + 0x2ddcf1ecU, 0x4f246b8eU, 0x9e801e5fU, 0x4ce4a88dU, + 0x49a1e888U, 0x70d7a7b1U, 0xbfe8577eU, 0x58f5ad99U, + 0xa4369265U, 0x1a253fdbU, 0xa2b31163U, 0x9fc05f5eU, + 0x7cd8a4bdU, 0x841e9a45U, 0x023b39c3U, 0x0a313bcbU, + 0x1de0fddcU, 0xf87d8539U, 0x0cb4b8cdU, 0x45aeeb84U, + 0xbea8167fU, 0x11effed0U, 0x41abea80U, 0x725725b3U, + 0xc04b8b01U, 0x533f6c92U, 0xe123c220U, 0x4b216a8aU, + 0xc901c808U, 0x6e4c22afU, 0x466e2887U, 0x64c6a2a5U, + 0xfef8063fU, 0x87de5946U, 0xf3b74432U, 0x771265b6U, + 0x9d40dd5cU, 0xa576d364U, 0x162a3cd7U, 0xdf904f1eU, + 0xb167d670U, 0x3dc8f5fcU, 0xf0778731U, 0x765224b7U, + 0xc6ce0807U, 0x35c2f7f4U, 0x630360a2U, 0x037b78c2U, + 0x7f1867beU, 0x7b1d66baU, 0xa7f65166U, 0x8fd45b4eU, + 0xfc78843dU, 0xa6b61067U, 0x74d2a6b5U, 0x801b9b41U, + 0x2496b2e5U, 0xbd68d57cU, 0x388db5f9U, 0x374275f6U, + 0x8e941a4fU, 0xad7cd16cU, 0xbbed567aU, 0xcf844b0eU, + 0xb6a21477U, 0x8a911b4bU, 0xa3f35062U, 0xa979d068U, + 0xe2e30123U, 0xcd04c90cU, 0x0e343acfU, 0xe8698129U, + 0x5cf0ac9dU, 0xfd38c53cU, 0x275671e6U, 0x3c88b4fdU, + 0x7e5826bfU, 0x1b657edaU, 0x8951d848U, 0x829b1943U, + 0x2899b1e9U, 0x5db0ed9cU, 0x18a5bdd9U, 0x08b1b9c9U, + 0xec6c802dU, 0x6f0c63aeU, 0x940a9e55U, 0xe3a34022U, + 0xfafd073bU, 0x900f9f51U, 0x176a7dd6U, 0x334774f2U, + 0x5f306f9eU, 0x2c9cb0edU, 0x0df4f9ccU, 0xeeec022fU, + 0xdd10cd1cU, 0x731764b2U, 0xd11fce10U, 0xd8558d19U, + 0xaab9136bU, 0x09f1f8c8U, 0x3f4877feU, 0x799de4b8U, + 0x221331e3U, 0xb96dd478U, 0xffb8473eU, 0x4a612b8bU, + 0x2f5c73eeU, 0x7197e6b0U, 0xb7e25576U, 0x320735f3U, + 0x954adf54U, 0xe526c324U, 0x2e1c32efU, 0xeba9422aU, + 0xd3a675fbU, 0xcaf832e2U, 0x2f654a07U, 0x732e5d5bU, + 0xbbd46f93U, 0x0f4d4227U, 0x7ce19d54U, 0x5643157eU, + 0xd066b6f8U, 0x5246147aU, 0xd86cb4f0U, 0x83e261abU, + 0x28a08800U, 0x673f584fU, 0x38b48c10U, 0x9c39a5b4U, + 0x24af8b0cU, 0x15d3c63dU, 0xe2da38caU, 0x5186d779U, + 0x20aa8a08U, 0x726e1c5aU, 0x983ca4b0U, 0x87e760afU, + 0x222a080aU, 0x997ce5b1U, 0xc477b3ecU, 0x10968638U, + 0xad45e885U, 0x92b624baU, 0x9036a6b8U, 0xeed53bc6U, + 0xfac43ed2U, 0x8162e3a9U, 0xc938f1e1U, 0x5b0c5773U, + 0xcefd33e6U, 0x377b4c1fU, 0xead03ac2U, 0x61badb49U, + 0x44d7936cU, 0xd92cf5f1U, 0xa40fab8cU, 0x8567e2adU, + 0x3f714e17U, 0xb7db6c9fU, 0x3a340e12U, 0x01c2c329U, + 0x1b5c4733U, 0x4657116eU, 0xf844bcd0U, 0x2e250b06U, + 0xafc56a87U, 0xa800a880U, 0x2b604b03U, 0xdee937f6U, + 0x8aa822a2U, 0xf78b7cdfU, 0xdaec36f2U, 0x633a594bU, + 0x5d89d475U, 0xb69b2d9eU, 0x74eb9f5cU, 0x1216043aU, + 0x9573e6bdU, 0x9433a7bcU, 0x1613053eU, 0x7b245f53U, + 0x4717506fU, 0x4597d26dU, 0xd463b7fcU, 0x627a184aU, + 0x86a721aeU, 0xed15f8c5U, 0x78e49c50U, 0xec55b9c4U, + 0x1356453bU, 0x9eb927b6U, 0xb55bee9dU, 0x2a200a02U, + 0x29e0c901U, 0x25efca0dU, 0x8ead23a6U, 0x4252106aU, + 0x4d9dd065U, 0x19dcc531U, 0xe39a79cbU, 0xa68f298eU, + 0x6b305b43U, 0x276f480fU, 0xb41baf9cU, 0xa54fea8dU, + 0x4998d161U, 0xd126f7f9U, 0xfec13fd6U, 0x5cc99574U, + 0xf04ebed8U, 0x189c8430U, 0xb01eae98U, 0xf10effd9U, + 0x05c7c22dU, 0xe910f9c1U, 0xcfbd72e7U, 0x0202002aU, + 0x1c998534U, 0x00828228U, 0x79a4dd51U, 0x64ff9b4cU, + 0x8c2da1a4U, 0x0c8d8124U, 0x69b0d941U, 0x96b325beU, + 0xdbac77f3U, 0x8828a0a0U, 0x9176e7b9U, 0xd523f6fdU, + 0xf6cb3ddeU, 0xc7b770efU, 0x1493873cU, 0xc132f3e9U, + 0xb954ed91U, 0x50c69678U, 0x8022a2a8U, 0x1753443fU, + 0x0a080222U, 0x9bfc67b3U, 0xabc06b83U, 0xf2ce3cdaU, + 0x236a490bU, 0x766b1d5eU, 0xa28a288aU, 0xc3b271ebU, + 0x8968e1a1U, 0x97f364bfU, 0x68f09840U, 0x5e491776U, + 0x0607012eU, 0x5703547fU, 0x4312516bU, 0xb3de6d9bU, + 0x6f355a47U, 0x0dcdc025U, 0xdc69b5f4U, 0x0e0d0326U, + 0x0b484323U, 0x323e0c1aU, 0xfd01fcd5U, 0x1a1c0632U, + 0xe6df39ceU, 0x58cc9470U, 0xe05abac8U, 0xdd29f4f5U, + 0x3e310f16U, 0xc6f731eeU, 0x40d29268U, 0x48d89060U, + 0x5f095677U, 0xba942e92U, 0x4e5d1366U, 0x0747402fU, + 0xfc41bdd4U, 0x5306557bU, 0x0342412bU, 0x30be8e18U, + 0x82a220aaU, 0x11d6c739U, 0xa3ca698bU, 0x09c8c121U, + 0x8be863a3U, 0x2ca58904U, 0x0487832cU, 0x262f090eU, + 0xbc11ad94U, 0xc537f2edU, 0xb15eef99U, 0x35fbce1dU, + 0xdfa976f7U, 0xe79f78cfU, 0x54c3977cU, 0x9d79e4b5U, + 0xf38e7ddbU, 0x7f215e57U, 0xb29e2c9aU, 0x34bb8f1cU, + 0x8427a3acU, 0x772b5c5fU, 0x21eacb09U, 0x4192d369U, + 0x3df1cc15U, 0x39f4cd11U, 0xe51ffacdU, 0xcd3df0e5U, + 0xbe912f96U, 0xe45fbbccU, 0x363b0d1eU, 0xc2f230eaU, + 0x667f194eU, 0xff817ed7U, 0x7a641e52U, 0x75abde5dU, + 0xcc7db1e4U, 0xef957ac7U, 0xf904fdd1U, 0x8d6de0a5U, + 0xf44bbfdcU, 0xc878b0e0U, 0xe11afbc9U, 0xeb907bc3U, + 0xa00aaa88U, 0x8fed62a7U, 0x4cdd9164U, 0xaa802a82U, + 0x1e190736U, 0xbfd16e97U, 0x65bfda4dU, 0x7e611f56U, + 0x3cb18d14U, 0x598cd571U, 0xcbb873e3U, 0xc072b2e8U, + 0x6a701a42U, 0x1f594637U, 0x5a4c1672U, 0x4a581262U, + 0xae852b86U, 0x2de5c805U, 0xd6e335feU, 0xa14aeb89U, + 0xb814ac90U, 0xd2e634faU, 0x5583d67dU, 0x71aedf59U, + 0x1dd9c435U, 0x6e751b46U, 0x4f1d5267U, 0xac05a984U, + 0x9ff966b7U, 0x31fecf19U, 0x93f665bbU, 0x9abc26b2U, + 0xe850b8c0U, 0x4b185363U, 0x7da1dc55U, 0x3b744f13U, + 0x60fa9a48U, 0xfb847fd3U, 0xbd51ec95U, 0x08888020U, + 0x6db5d845U, 0x337e4d1bU, 0xf50bfeddU, 0x70ee9e58U, + 0xd7a374ffU, 0xa7cf688fU, 0x6cf59944U, 0xa940e981U, + 0x4c763ab4U, 0x55287dadU, 0xb0b50548U, 0xecfe1214U, + 0x240420dcU, 0x909d0d68U, 0xe331d21bU, 0xc9935a31U, + 0x4fb6f9b7U, 0xcd965b35U, 0x47bcfbbfU, 0x1c322ee4U, + 0xb770c74fU, 0xf8ef1700U, 0xa764c35fU, 0x03e9eafbU, + 0xbb7fc443U, 0x8a038972U, 0x7d0a7785U, 0xce569836U, + 0xbf7ac547U, 0xedbe5315U, 0x07ecebffU, 0x18372fe0U, + 0xbdfa4745U, 0x06acaafeU, 0x5ba7fca3U, 0x8f46c977U, + 0x3295a7caU, 0x0d666bf5U, 0x0fe6e9f7U, 0x71057489U, + 0x6514719dU, 0x1eb2ace6U, 0x56e8beaeU, 0xc4dc183cU, + 0x512d7ca9U, 0xa8ab0350U, 0x7500758dU, 0xfe6a9406U, + 0xdb07dc23U, 0x46fcbabeU, 0x3bdfe4c3U, 0x1ab7ade2U, + 0xa0a10158U, 0x280b23d0U, 0xa5e4415dU, 0x9e128c66U, + 0x848c087cU, 0xd9875e21U, 0x6794f39fU, 0xb1f54449U, + 0x301525c8U, 0x37d0e7cfU, 0xb4b0044cU, 0x413978b9U, + 0x15786dedU, 0x685b3390U, 0x453c79bdU, 0xfcea1604U, + 0xc2599b3aU, 0x294b62d1U, 0xeb3bd013U, 0x8dc64b75U, + 0x0aa3a9f2U, 0x0be3e8f3U, 0x89c34a71U, 0xe4f4101cU, + 0xd8c71f20U, 0xda479d22U, 0x4bb3f8b3U, 0xfdaa5705U, + 0x19776ee1U, 0x72c5b78aU, 0xe734d31fU, 0x7385f68bU, + 0x8c860a74U, 0x016968f9U, 0x2a8ba1d2U, 0xb5f0454dU, + 0xb630864eU, 0xba3f8542U, 0x117d6ce9U, 0xdd825f25U, + 0xd24d9f2aU, 0x860c8a7eU, 0x7c4a3684U, 0x395f66c1U, + 0xf4e0140cU, 0xb8bf0740U, 0x2bcbe0d3U, 0x3a9fa5c2U, + 0xd6489e2eU, 0x4ef6b8b6U, 0x61117099U, 0xc319da3bU, + 0x6f9ef197U, 0x874ccb7fU, 0x2fcee1d7U, 0x6edeb096U, + 0x9a178d62U, 0x76c0b68eU, 0x506d3da8U, 0x9dd24f65U, + 0x8349ca7bU, 0x9f52cd67U, 0xe674921eU, 0xfb2fd403U, + 0x13fdeeebU, 0x935dce6bU, 0xf660960eU, 0x09636af1U, + 0x447c38bcU, 0x17f8efefU, 0x0ea6a8f6U, 0x4af3b9b2U, + 0x691b7291U, 0x58673fa0U, 0x8b43c873U, 0x5ee2bca6U, + 0x2684a2deU, 0xcf16d937U, 0x1ff2ede7U, 0x88830b70U, + 0x95d84d6dU, 0x042c28fcU, 0x341024ccU, 0x6d1e7395U, + 0xbcba0644U, 0xe9bb5211U, 0x3d5a67c5U, 0x5c623ea4U, + 0x16b8aeeeU, 0x08232bf0U, 0xf720d70fU, 0xc1995839U, + 0x99d74e61U, 0xc8d31b30U, 0xdcc21e24U, 0x2c0e22d4U, + 0xf0e51508U, 0x921d8f6aU, 0x43b9fabbU, 0x91dd4c69U, + 0x94980c6cU, 0xadee4355U, 0x62d1b39aU, 0x85cc497dU, + 0x790f7681U, 0xc71cdb3fU, 0x7f8af587U, 0x42f9bbbaU, + 0xa1e14059U, 0x59277ea1U, 0xdf02dd27U, 0xd708df2fU, + 0xc0d91938U, 0x254461ddU, 0xd18d5c29U, 0x98970f60U, + 0x6391f29bU, 0xccd61a34U, 0x9c920e64U, 0xaf6ec157U, + 0x1d726fe5U, 0x8e068876U, 0x3c1a26c4U, 0x96188e6eU, + 0x14382cecU, 0xb375c64bU, 0x9b57cc63U, 0xb9ff4641U, + 0x23c1e2dbU, 0x5ae7bda2U, 0x2e8ea0d6U, 0xaa2b8152U, + 0x407939b8U, 0x784f3780U, 0xcb13d833U, 0x02a9abfaU, + 0x6c5e3294U, 0xe0f11118U, 0x2d4e63d5U, 0xab6bc053U, + 0x1bf7ece3U, 0xe8fb1310U, 0xbe3a8446U, 0xde429c26U, + 0xa221835aU, 0xa624825eU, 0x7acfb582U, 0x52edbfaaU, + 0x214160d9U, 0x7b8ff483U, 0xa9eb4251U, 0x5d227fa5U, + 0xf9af5601U, 0x60513198U, 0xe5b4511dU, 0xea7b9112U, + 0x53adfeabU, 0x70453588U, 0x66d4b29eU, 0x12bdafeaU, + 0x6b9bf093U, 0x57a8ffafU, 0x7ecab486U, 0x7440348cU, + 0x3fdae5c7U, 0x103d2de8U, 0xd30dde2bU, 0x355065cdU, + 0x81c94879U, 0x200121d8U, 0xfa6f9502U, 0xe1b15019U, + 0xa361c25bU, 0xc65c9a3eU, 0x54683cacU, 0x5fa2fda7U, + 0xf5a0550dU, 0x80890978U, 0xc59c593dU, 0xd5885d2dU, + 0x315564c9U, 0xb235874aU, 0x49337ab1U, 0x3e9aa4c6U, + 0x27c4e3dfU, 0x4d367bb5U, 0xca539932U, 0xee7e9016U, + 0x82098b7aU, 0xf1a55409U, 0xd0cd1d28U, 0x33d5e6cbU, + 0x002929f8U, 0xae2e8056U, 0x0c262af4U, 0x056c69fdU, + 0x7780f78fU, 0xd4c81c2cU, 0xe271931aU, 0xa4a4005cU, + 0xff2ad507U, 0x6454309cU, 0x2281a3daU, 0x9758cf6fU, + 0xf265970aU, 0xacae0254U, 0x6adbb192U, 0xef3ed117U, + 0x48733bb0U, 0x381f27c0U, 0xf325d60bU, 0x3690a6ceU, + 0xc7a265ebU, 0xdefc22f2U, 0x3b615a17U, 0x672a4d4bU, + 0xafd07f83U, 0x1b495237U, 0x68e58d44U, 0x4247056eU, + 0xc462a6e8U, 0x4642046aU, 0xcc68a4e0U, 0x97e671bbU, + 0x3ca49810U, 0x733b485fU, 0x2cb09c00U, 0x883db5a4U, + 0x30ab9b1cU, 0x01d7d62dU, 0xf6de28daU, 0x4582c769U, + 0x34ae9a18U, 0x666a0c4aU, 0x8c38b4a0U, 0x93e370bfU, + 0x362e181aU, 0x8d78f5a1U, 0xd073a3fcU, 0x04929628U, + 0xb941f895U, 0x86b234aaU, 0x8432b6a8U, 0xfad12bd6U, + 0xeec02ec2U, 0x9566f3b9U, 0xdd3ce1f1U, 0x4f084763U, + 0xdaf923f6U, 0x237f5c0fU, 0xfed42ad2U, 0x75becb59U, + 0x50d3837cU, 0xcd28e5e1U, 0xb00bbb9cU, 0x9163f2bdU, + 0x2b755e07U, 0xa3df7c8fU, 0x2e301e02U, 0x15c6d339U, + 0x0f585723U, 0x5253017eU, 0xec40acc0U, 0x3a211b16U, + 0xbbc17a97U, 0xbc04b890U, 0x3f645b13U, 0xcaed27e6U, + 0x9eac32b2U, 0xe38f6ccfU, 0xcee826e2U, 0x773e495bU, + 0x498dc465U, 0xa29f3d8eU, 0x60ef8f4cU, 0x0612142aU, + 0x8177f6adU, 0x8037b7acU, 0x0217152eU, 0x6f204f43U, + 0x5313407fU, 0x5193c27dU, 0xc067a7ecU, 0x767e085aU, + 0x92a331beU, 0xf911e8d5U, 0x6ce08c40U, 0xf851a9d4U, + 0x0752552bU, 0x8abd37a6U, 0xa15ffe8dU, 0x3e241a12U, + 0x3de4d911U, 0x31ebda1dU, 0x9aa933b6U, 0x5656007aU, + 0x5999c075U, 0x0dd8d521U, 0xf79e69dbU, 0xb28b399eU, + 0x7f344b53U, 0x336b581fU, 0xa01fbf8cU, 0xb14bfa9dU, + 0x5d9cc171U, 0xc522e7e9U, 0xeac52fc6U, 0x48cd8564U, + 0xe44aaec8U, 0x0c989420U, 0xa41abe88U, 0xe50aefc9U, + 0x11c3d23dU, 0xfd14e9d1U, 0xdbb962f7U, 0x1606103aU, + 0x089d9524U, 0x14869238U, 0x6da0cd41U, 0x70fb8b5cU, + 0x9829b1b4U, 0x18899134U, 0x7db4c951U, 0x82b735aeU, + 0xcfa867e3U, 0x9c2cb0b0U, 0x8572f7a9U, 0xc127e6edU, + 0xe2cf2dceU, 0xd3b360ffU, 0x0097972cU, 0xd536e3f9U, + 0xad50fd81U, 0x44c28668U, 0x9426b2b8U, 0x0357542fU, + 0x1e0c1232U, 0x8ff877a3U, 0xbfc47b93U, 0xe6ca2ccaU, + 0x376e591bU, 0x626f0d4eU, 0xb68e389aU, 0xd7b661fbU, + 0x9d6cf1b1U, 0x83f774afU, 0x7cf48850U, 0x4a4d0766U, + 0x1203113eU, 0x4307446fU, 0x5716417bU, 0xa7da7d8bU, + 0x7b314a57U, 0x19c9d035U, 0xc86da5e4U, 0x1a091336U, + 0x1f4c5333U, 0x263a1c0aU, 0xe905ecc5U, 0x0e181622U, + 0xf2db29deU, 0x4cc88460U, 0xf45eaad8U, 0xc92de4e5U, + 0x2a351f06U, 0xd2f321feU, 0x54d68278U, 0x5cdc8070U, + 0x4b0d4667U, 0xae903e82U, 0x5a590376U, 0x1343503fU, + 0xe845adc4U, 0x4702456bU, 0x1746513bU, 0x24ba9e08U, + 0x96a630baU, 0x05d2d729U, 0xb7ce799bU, 0x1dccd131U, + 0x9fec73b3U, 0x38a19914U, 0x1083933cU, 0x322b191eU, + 0xa815bd84U, 0xd133e2fdU, 0xa55aff89U, 0x21ffde0dU, + 0xcbad66e7U, 0xf39b68dfU, 0x40c7876cU, 0x897df4a5U, + 0xe78a6dcbU, 0x6b254e47U, 0xa69a3c8aU, 0x20bf9f0cU, + 0x9023b3bcU, 0x632f4c4fU, 0x35eedb19U, 0x5596c379U, + 0x29f5dc05U, 0x2df0dd01U, 0xf11beaddU, 0xd939e0f5U, + 0xaa953f86U, 0xf05babdcU, 0x223f1d0eU, 0xd6f620faU, + 0x727b095eU, 0xeb856ec7U, 0x6e600e42U, 0x61afce4dU, + 0xd879a1f4U, 0xfb916ad7U, 0xed00edc1U, 0x9969f0b5U, + 0xe04fafccU, 0xdc7ca0f0U, 0xf51eebd9U, 0xff946bd3U, + 0xb40eba98U, 0x9be972b7U, 0x58d98174U, 0xbe843a92U, + 0x0a1d1726U, 0xabd57e87U, 0x71bbca5dU, 0x6a650f46U, + 0x28b59d04U, 0x4d88c561U, 0xdfbc63f3U, 0xd476a2f8U, + 0x7e740a52U, 0x0b5d5627U, 0x4e480662U, 0x5e5c0272U, + 0xba813b96U, 0x39e1d815U, 0xc2e725eeU, 0xb54efb99U, + 0xac10bc80U, 0xc6e224eaU, 0x4187c66dU, 0x65aacf49U, + 0x09ddd425U, 0x7a710b56U, 0x5b194277U, 0xb801b994U, + 0x8bfd76a7U, 0x25fadf09U, 0x87f275abU, 0x8eb836a2U, + 0xfc54a8d0U, 0x5f1c4373U, 0x69a5cc45U, 0x2f705f03U, + 0x74fe8a58U, 0xef806fc3U, 0xa955fc85U, 0x1c8c9030U, + 0x79b1c855U, 0x277a5d0bU, 0xe10feecdU, 0x64ea8e48U, + 0xc3a764efU, 0xb3cb789fU, 0x78f18954U, 0xbd44f991U, + 0x4a8bc14fU, 0x53d58656U, 0xb648feb3U, 0xea03e9efU, + 0x22f9db27U, 0x9660f693U, 0xe5cc29e0U, 0xcf6ea1caU, + 0x494b024cU, 0xcb6ba0ceU, 0x41410044U, 0x1acfd51fU, + 0xb18d3cb4U, 0xfe12ecfbU, 0xa19938a4U, 0x05141100U, + 0xbd823fb8U, 0x8cfe7289U, 0x7bf78c7eU, 0xc8ab63cdU, + 0xb9873ebcU, 0xeb43a8eeU, 0x01111004U, 0x1ecad41bU, + 0xbb07bcbeU, 0x00515105U, 0x5d5a0758U, 0x89bb328cU, + 0x34685c31U, 0x0b9b900eU, 0x091b120cU, 0x77f88f72U, + 0x63e98a66U, 0x184f571dU, 0x50154555U, 0xc221e3c7U, + 0x57d08752U, 0xae56f8abU, 0x73fd8e76U, 0xf8976ffdU, + 0xddfa27d8U, 0x40014145U, 0x3d221f38U, 0x1c4a5619U, + 0xa65cfaa3U, 0x2ef6d82bU, 0xa319baa6U, 0x98ef779dU, + 0x8271f387U, 0xdf7aa5daU, 0x61690864U, 0xb708bfb2U, + 0x36e8de33U, 0x312d1c34U, 0xb24dffb7U, 0x47c48342U, + 0x13859616U, 0x6ea6c86bU, 0x43c18246U, 0xfa17edffU, + 0xc4a460c1U, 0x2fb6992aU, 0xedc62be8U, 0x8b3bb08eU, + 0x0c5e5209U, 0x0d1e1308U, 0x8f3eb18aU, 0xe209ebe7U, + 0xde3ae4dbU, 0xdcba66d9U, 0x4d4e0348U, 0xfb57acfeU, + 0x1f8a951aU, 0x74384c71U, 0xe1c928e4U, 0x75780d70U, + 0x8a7bf18fU, 0x07949302U, 0x2c765a29U, 0xb30dbeb6U, + 0xb0cd7db5U, 0xbcc27eb9U, 0x17809712U, 0xdb7fa4deU, + 0xd4b064d1U, 0x80f17185U, 0x7ab7cd7fU, 0x3fa29d3aU, + 0xf21deff7U, 0xbe42fcbbU, 0x2d361b28U, 0x3c625e39U, + 0xd0b565d5U, 0x480b434dU, 0x67ec8b62U, 0xc5e421c0U, + 0x69630a6cU, 0x81b13084U, 0x29331a2cU, 0x68234b6dU, + 0x9cea7699U, 0x703d4d75U, 0x5690c653U, 0x9b2fb49eU, + 0x85b43180U, 0x99af369cU, 0xe08969e5U, 0xfdd22ff8U, + 0x15001510U, 0x95a03590U, 0xf09d6df5U, 0x0f9e910aU, + 0x4281c347U, 0x11051414U, 0x085b530dU, 0x4c0e4249U, + 0x6fe6896aU, 0x5e9ac45bU, 0x8dbe3388U, 0x581f475dU, + 0x20795925U, 0xc9eb22ccU, 0x190f161cU, 0x8e7ef08bU, + 0x9325b696U, 0x02d1d307U, 0x32eddf37U, 0x6be3886eU, + 0xba47fdbfU, 0xef46a9eaU, 0x3ba79c3eU, 0x5a9fc55fU, + 0x10455515U, 0x0eded00bU, 0xf1dd2cf4U, 0xc764a3c2U, + 0x9f2ab59aU, 0xce2ee0cbU, 0xda3fe5dfU, 0x2af3d92fU, + 0xf618eef3U, 0x94e07491U, 0x45440140U, 0x9720b792U, + 0x9265f797U, 0xab13b8aeU, 0x642c4861U, 0x8331b286U, + 0x7ff28d7aU, 0xc1e120c4U, 0x79770e7cU, 0x44044041U, + 0xa71cbba2U, 0x5fda855aU, 0xd9ff26dcU, 0xd1f524d4U, + 0xc624e2c3U, 0x23b99a26U, 0xd770a7d2U, 0x9e6af49bU, + 0x656c0960U, 0xca2be1cfU, 0x9a6ff59fU, 0xa9933aacU, + 0x1b8f941eU, 0x88fb738dU, 0x3ae7dd3fU, 0x90e57595U, + 0x12c5d717U, 0xb5883db0U, 0x9daa3798U, 0xbf02bdbaU, + 0x253c1920U, 0x5c1a4659U, 0x28735b2dU, 0xacd67aa9U, + 0x4684c243U, 0x7eb2cc7bU, 0xcdee23c8U, 0x04545001U, + 0x6aa3c96fU, 0xe60ceae3U, 0x2bb3982eU, 0xad963ba8U, + 0x1d0a1718U, 0xee06e8ebU, 0xb8c77fbdU, 0xd8bf67ddU, + 0xa4dc78a1U, 0xa0d979a5U, 0x7c324e79U, 0x54104451U, + 0x27bc9b22U, 0x7d720f78U, 0xaf16b9aaU, 0x5bdf845eU, + 0xff52adfaU, 0x66acca63U, 0xe349aae6U, 0xec866ae9U, + 0x55500550U, 0x76b8ce73U, 0x60294965U, 0x14405411U, + 0x6d660b68U, 0x51550454U, 0x78374f7dU, 0x72bdcf77U, + 0x39271e3cU, 0x16c0d613U, 0xd5f025d0U, 0x33ad9e36U, + 0x8734b382U, 0x26fcda23U, 0xfc926ef9U, 0xe74cabe2U, + 0xa59c39a0U, 0xc0a161c5U, 0x5295c757U, 0x595f065cU, + 0xf35daef6U, 0x8674f283U, 0xc361a2c6U, 0xd375a6d6U, + 0x37a89f32U, 0xb4c87cb1U, 0x4fce814aU, 0x38675f3dU, + 0x21391824U, 0x4bcb804eU, 0xccae62c9U, 0xe8836bedU, + 0x84f47081U, 0xf758aff2U, 0xd630e6d3U, 0x35281d30U, + 0x06d4d203U, 0xa8d37badU, 0x0adbd10fU, 0x03919206U, + 0x717d0c74U, 0xd235e7d7U, 0xe48c68e1U, 0xa259fba7U, + 0xf9d72efcU, 0x62a9cb67U, 0x247c5821U, 0x91a53494U, + 0xf4986cf1U, 0xaa53f9afU, 0x6c264a69U, 0xe9c32aecU, + 0x4e8ec04bU, 0x3ee2dc3bU, 0xf5d82df0U, 0x306d5d35U, + 0xdca579f7U, 0xc5fb3eeeU, 0x2066460bU, 0x7c2d5157U, + 0xb4d7639fU, 0x004e4e2bU, 0x73e29158U, 0x59401972U, + 0xdf65baf4U, 0x5d451876U, 0xd76fb8fcU, 0x8ce16da7U, + 0x27a3840cU, 0x683c5443U, 0x37b7801cU, 0x933aa9b8U, + 0x2bac8700U, 0x1ad0ca31U, 0xedd934c6U, 0x5e85db75U, + 0x2fa98604U, 0x7d6d1056U, 0x973fa8bcU, 0x88e46ca3U, + 0x2d290406U, 0x967fe9bdU, 0xcb74bfe0U, 0x1f958a34U, + 0xa246e489U, 0x9db528b6U, 0x9f35aab4U, 0xe1d637caU, + 0xf5c732deU, 0x8e61efa5U, 0xc63bfdedU, 0x540f5b7fU, + 0xc1fe3feaU, 0x38784013U, 0xe5d336ceU, 0x6eb9d745U, + 0x4bd49f60U, 0xd62ff9fdU, 0xab0ca780U, 0x8a64eea1U, + 0x3072421bU, 0xb8d86093U, 0x3537021eU, 0x0ec1cf25U, + 0x145f4b3fU, 0x49541d62U, 0xf747b0dcU, 0x2126070aU, + 0xa0c6668bU, 0xa703a48cU, 0x2463470fU, 0xd1ea3bfaU, + 0x85ab2eaeU, 0xf88870d3U, 0xd5ef3afeU, 0x6c395547U, + 0x528ad879U, 0xb9982192U, 0x7be89350U, 0x1d150836U, + 0x9a70eab1U, 0x9b30abb0U, 0x19100932U, 0x7427535fU, + 0x48145c63U, 0x4a94de61U, 0xdb60bbf0U, 0x6d791446U, + 0x89a42da2U, 0xe216f4c9U, 0x77e7905cU, 0xe356b5c8U, + 0x1c554937U, 0x91ba2bbaU, 0xba58e291U, 0x2523060eU, + 0x26e3c50dU, 0x2aecc601U, 0x81ae2faaU, 0x4d511c66U, + 0x429edc69U, 0x16dfc93dU, 0xec9975c7U, 0xa98c2582U, + 0x6433574fU, 0x286c4403U, 0xbb18a390U, 0xaa4ce681U, + 0x469bdd6dU, 0xde25fbf5U, 0xf1c233daU, 0x53ca9978U, + 0xff4db2d4U, 0x179f883cU, 0xbf1da294U, 0xfe0df3d5U, + 0x0ac4ce21U, 0xe613f5cdU, 0xc0be7eebU, 0x0d010c26U, + 0x139a8938U, 0x0f818e24U, 0x76a7d15dU, 0x6bfc9740U, + 0x832eada8U, 0x038e8d28U, 0x66b3d54dU, 0x99b029b2U, + 0xd4af7bffU, 0x872bacacU, 0x9e75ebb5U, 0xda20faf1U, + 0xf9c831d2U, 0xc8b47ce3U, 0x1b908b30U, 0xce31ffe5U, + 0xb657e19dU, 0x5fc59a74U, 0x8f21aea4U, 0x18504833U, + 0x050b0e2eU, 0x94ff6bbfU, 0xa4c3678fU, 0xfdcd30d6U, + 0x2c694507U, 0x79681152U, 0xad892486U, 0xccb17de7U, + 0x866bedadU, 0x98f068b3U, 0x67f3944cU, 0x514a1b7aU, + 0x09040d22U, 0x58005873U, 0x4c115d67U, 0xbcdd6197U, + 0x6036564bU, 0x02cecc29U, 0xd36ab9f8U, 0x010e0f2aU, + 0x044b4f2fU, 0x3d3d0016U, 0xf202f0d9U, 0x151f0a3eU, + 0xe9dc35c2U, 0x57cf987cU, 0xef59b6c4U, 0xd22af8f9U, + 0x3132031aU, 0xc9f43de2U, 0x4fd19e64U, 0x47db9c6cU, + 0x500a5a7bU, 0xb597229eU, 0x415e1f6aU, 0x08444c23U, + 0xf342b1d8U, 0x5c055977U, 0x0c414d27U, 0x3fbd8214U, + 0x8da12ca6U, 0x1ed5cb35U, 0xacc96587U, 0x06cbcd2dU, + 0x84eb6fafU, 0x23a68508U, 0x0b848f20U, 0x292c0502U, + 0xb312a198U, 0xca34fee1U, 0xbe5de395U, 0x3af8c211U, + 0xd0aa7afbU, 0xe89c74c3U, 0x5bc09b70U, 0x927ae8b9U, + 0xfc8d71d7U, 0x7022525bU, 0xbd9d2096U, 0x3bb88310U, + 0x8b24afa0U, 0x78285053U, 0x2ee9c705U, 0x4e91df65U, + 0x32f2c019U, 0x36f7c11dU, 0xea1cf6c1U, 0xc23efce9U, + 0xb192239aU, 0xeb5cb7c0U, 0x39380112U, 0xcdf13ce6U, + 0x697c1542U, 0xf08272dbU, 0x7567125eU, 0x7aa8d251U, + 0xc37ebde8U, 0xe09676cbU, 0xf607f1ddU, 0x826eeca9U, + 0xfb48b3d0U, 0xc77bbcecU, 0xee19f7c5U, 0xe49377cfU, + 0xaf09a684U, 0x80ee6eabU, 0x43de9d68U, 0xa583268eU, + 0x111a0b3aU, 0xb0d2629bU, 0x6abcd641U, 0x7162135aU, + 0x33b28118U, 0x568fd97dU, 0xc4bb7fefU, 0xcf71bee4U, + 0x6573164eU, 0x105a4a3bU, 0x554f1a7eU, 0x455b1e6eU, + 0xa186278aU, 0x22e6c409U, 0xd9e039f2U, 0xae49e785U, + 0xb717a09cU, 0xdde538f6U, 0x5a80da71U, 0x7eadd355U, + 0x12dac839U, 0x6176174aU, 0x401e5e6bU, 0xa306a588U, + 0x90fa6abbU, 0x3efdc315U, 0x9cf569b7U, 0x95bf2abeU, + 0xe753b4ccU, 0x441b5f6fU, 0x72a2d059U, 0x3477431fU, + 0x6ff99644U, 0xf48773dfU, 0xb252e099U, 0x078b8c2cU, + 0x62b6d449U, 0x3c7d4117U, 0xfa08f2d1U, 0x7fed9254U, + 0xd8a078f3U, 0xa8cc6483U, 0x63f69548U, 0xa643e58dU, + 0xa0e848c6U, 0xb9b60fdfU, 0x5c2b773aU, 0x00606066U, + 0xc89a52aeU, 0x7c037f1aU, 0x0fafa069U, 0x250d2843U, + 0xa3288bc5U, 0x21082947U, 0xab2289cdU, 0xf0ac5c96U, + 0x5beeb53dU, 0x14716572U, 0x4bfab12dU, 0xef779889U, + 0x57e1b631U, 0x669dfb00U, 0x919405f7U, 0x22c8ea44U, + 0x53e4b735U, 0x01202167U, 0xeb72998dU, 0xf4a95d92U, + 0x51643537U, 0xea32d88cU, 0xb7398ed1U, 0x63d8bb05U, + 0xde0bd5b8U, 0xe1f81987U, 0xe3789b85U, 0x9d9b06fbU, + 0x898a03efU, 0xf22cde94U, 0xba76ccdcU, 0x28426a4eU, + 0xbdb30edbU, 0x44357122U, 0x999e07ffU, 0x12f4e674U, + 0x3799ae51U, 0xaa62c8ccU, 0xd74196b1U, 0xf629df90U, + 0x4c3f732aU, 0xc49551a2U, 0x497a332fU, 0x728cfe14U, + 0x68127a0eU, 0x35192c53U, 0x8b0a81edU, 0x5d6b363bU, + 0xdc8b57baU, 0xdb4e95bdU, 0x582e763eU, 0xada70acbU, + 0xf9e61f9fU, 0x84c541e2U, 0xa9a20bcfU, 0x10746476U, + 0x2ec7e948U, 0xc5d510a3U, 0x07a5a261U, 0x61583907U, + 0xe63ddb80U, 0xe77d9a81U, 0x655d3803U, 0x086a626eU, + 0x34596d52U, 0x36d9ef50U, 0xa72d8ac1U, 0x11342577U, + 0xf5e91c93U, 0x9e5bc5f8U, 0x0baaa16dU, 0x9f1b84f9U, + 0x60187806U, 0xedf71a8bU, 0xc615d3a0U, 0x596e373fU, + 0x5aaef43cU, 0x56a1f730U, 0xfde31e9bU, 0x311c2d57U, + 0x3ed3ed58U, 0x6a92f80cU, 0x90d444f6U, 0xd5c114b3U, + 0x187e667eU, 0x54217532U, 0xc75592a1U, 0xd601d7b0U, + 0x3ad6ec5cU, 0xa268cac4U, 0x8d8f02ebU, 0x2f87a849U, + 0x830083e5U, 0x6bd2b90dU, 0xc35093a5U, 0x8240c2e4U, + 0x7689ff10U, 0x9a5ec4fcU, 0xbcf34fdaU, 0x714c3d17U, + 0x6fd7b809U, 0x73ccbf15U, 0x0aeae06cU, 0x17b1a671U, + 0xff639c99U, 0x7fc3bc19U, 0x1afee47cU, 0xe5fd1883U, + 0xa8e24aceU, 0xfb669d9dU, 0xe238da84U, 0xa66dcbc0U, + 0x858500e3U, 0xb4f94dd2U, 0x67ddba01U, 0xb27cced4U, + 0xca1ad0acU, 0x2388ab45U, 0xf36c9f95U, 0x641d7902U, + 0x79463f1fU, 0xe8b25a8eU, 0xd88e56beU, 0x818001e7U, + 0x50247436U, 0x05252063U, 0xd1c415b7U, 0xb0fc4cd6U, + 0xfa26dc9cU, 0xe4bd5982U, 0x1bbea57dU, 0x2d072a4bU, + 0x75493c13U, 0x244d6942U, 0x305c6c56U, 0xc09050a6U, + 0x1c7b677aU, 0x7e83fd18U, 0xaf2788c9U, 0x7d433e1bU, + 0x78067e1eU, 0x41703127U, 0x8e4fc1e8U, 0x69523b0fU, + 0x959104f3U, 0x2b82a94dU, 0x931487f5U, 0xae67c9c8U, + 0x4d7f322bU, 0xb5b90cd3U, 0x339caf55U, 0x3b96ad5dU, + 0x2c476b4aU, 0xc9da13afU, 0x3d132e5bU, 0x74097d12U, + 0x8f0f80e9U, 0x20486846U, 0x700c7c16U, 0x43f0b325U, + 0xf1ec1d97U, 0x6298fa04U, 0xd08454b6U, 0x7a86fc1cU, + 0xf8a65e9eU, 0x5febb439U, 0x77c9be11U, 0x55613433U, + 0xcf5f90a9U, 0xb679cfd0U, 0xc210d2a4U, 0x46b5f320U, + 0xace74bcaU, 0x94d145f2U, 0x278daa41U, 0xee37d988U, + 0x80c040e6U, 0x0c6f636aU, 0xc1d011a7U, 0x47f5b221U, + 0xf7699e91U, 0x04656162U, 0x52a4f634U, 0x32dcee54U, + 0x4ebff128U, 0x4abaf02cU, 0x9651c7f0U, 0xbe73cdd8U, + 0xcddf12abU, 0x971186f1U, 0x45753023U, 0xb1bc0dd7U, + 0x15312473U, 0x8ccf43eaU, 0x092a236fU, 0x06e5e360U, + 0xbf338cd9U, 0x9cdb47faU, 0x8a4ac0ecU, 0xfe23dd98U, + 0x870582e1U, 0xbb368dddU, 0x9254c6f4U, 0x98de46feU, + 0xd34497b5U, 0xfca35f9aU, 0x3f93ac59U, 0xd9ce17bfU, + 0x6d573a0bU, 0xcc9f53aaU, 0x16f1e770U, 0x0d2f226bU, + 0x4fffb029U, 0x2ac2e84cU, 0xb8f64edeU, 0xb33c8fd5U, + 0x193e277fU, 0x6c177b0aU, 0x29022b4fU, 0x39162f5fU, + 0xddcb16bbU, 0x5eabf538U, 0xa5ad08c3U, 0xd204d6b4U, + 0xcb5a91adU, 0xa1a809c7U, 0x26cdeb40U, 0x02e0e264U, + 0x6e97f908U, 0x1d3b267bU, 0x3c536f5aU, 0xdf4b94b9U, + 0xecb75b8aU, 0x42b0f224U, 0xe0b85886U, 0xe9f21b8fU, + 0x9b1e85fdU, 0x38566e5eU, 0x0eefe168U, 0x483a722eU, + 0x13b4a775U, 0x88ca42eeU, 0xce1fd1a8U, 0x7bc6bd1dU, + 0x1efbe578U, 0x40307026U, 0x8645c3e0U, 0x03a0a365U, + 0xa4ed49c2U, 0xd48155b2U, 0x1fbba479U, 0xda0ed4bcU, + 0xa916bf31U, 0xb048f828U, 0x55d580cdU, 0x099e9791U, + 0xc164a559U, 0x75fd88edU, 0x0651579eU, 0x2cf3dfb4U, + 0xaad67c32U, 0x28f6deb0U, 0xa2dc7e3aU, 0xf952ab61U, + 0x521042caU, 0x1d8f9285U, 0x420446daU, 0xe6896f7eU, + 0x5e1f41c6U, 0x6f630cf7U, 0x986af200U, 0x2b361db3U, + 0x5a1a40c2U, 0x08ded690U, 0xe28c6e7aU, 0xfd57aa65U, + 0x589ac2c0U, 0xe3cc2f7bU, 0xbec77926U, 0x6a264cf2U, + 0xd7f5224fU, 0xe806ee70U, 0xea866c72U, 0x9465f10cU, + 0x8074f418U, 0xfbd22963U, 0xb3883b2bU, 0x21bc9db9U, + 0xb44df92cU, 0x4dcb86d5U, 0x9060f008U, 0x1b0a1183U, + 0x3e6759a6U, 0xa39c3f3bU, 0xdebf6146U, 0xffd72867U, + 0x45c184ddU, 0xcd6ba655U, 0x4084c4d8U, 0x7b7209e3U, + 0x61ec8df9U, 0x3ce7dba4U, 0x82f4761aU, 0x5495c1ccU, + 0xd575a04dU, 0xd2b0624aU, 0x51d081c9U, 0xa459fd3cU, + 0xf018e868U, 0x8d3bb615U, 0xa05cfc38U, 0x198a9381U, + 0x27391ebfU, 0xcc2be754U, 0x0e5b5596U, 0x68a6cef0U, + 0xefc32c77U, 0xee836d76U, 0x6ca3cff4U, 0x01949599U, + 0x3da79aa5U, 0x3f2718a7U, 0xaed37d36U, 0x18cad280U, + 0xfc17eb64U, 0x97a5320fU, 0x0254569aU, 0x96e5730eU, + 0x69e68ff1U, 0xe409ed7cU, 0xcfeb2457U, 0x5090c0c8U, + 0x535003cbU, 0x5f5f00c7U, 0xf41de96cU, 0x38e2daa0U, + 0x372d1aafU, 0x636c0ffbU, 0x992ab301U, 0xdc3fe344U, + 0x11809189U, 0x5ddf82c5U, 0xceab6556U, 0xdfff2047U, + 0x33281babU, 0xab963d33U, 0x8471f51cU, 0x26795fbeU, + 0x8afe7412U, 0x622c4efaU, 0xcaae6452U, 0x8bbe3513U, + 0x7f7708e7U, 0x93a0330bU, 0xb50db82dU, 0x78b2cae0U, + 0x66294ffeU, 0x7a3248e2U, 0x0314179bU, 0x1e4f5186U, + 0xf69d6b6eU, 0x763d4beeU, 0x1300138bU, 0xec03ef74U, + 0xa11cbd39U, 0xf2986a6aU, 0xebc62d73U, 0xaf933c37U, + 0x8c7bf714U, 0xbd07ba25U, 0x6e234df6U, 0xbb823923U, + 0xc3e4275bU, 0x2a765cb2U, 0xfa926862U, 0x6de38ef5U, + 0x70b8c8e8U, 0xe14cad79U, 0xd170a149U, 0x887ef610U, + 0x59da83c1U, 0x0cdbd794U, 0xd83ae240U, 0xb902bb21U, + 0xf3d82b6bU, 0xed43ae75U, 0x1240528aU, 0x24f9ddbcU, + 0x7cb7cbe4U, 0x2db39eb5U, 0x39a29ba1U, 0xc96ea751U, + 0x1585908dU, 0x777d0aefU, 0xa6d97f3eU, 0x74bdc9ecU, + 0x71f889e9U, 0x488ec6d0U, 0x87b1361fU, 0x60acccf8U, + 0x9c6ff304U, 0x227c5ebaU, 0x9aea7002U, 0xa7993e3fU, + 0x4481c5dcU, 0xbc47fb24U, 0x3a6258a2U, 0x32685aaaU, + 0x25b99cbdU, 0xc024e458U, 0x34edd9acU, 0x7df78ae5U, + 0x86f1771eU, 0x29b69fb1U, 0x79f28be1U, 0x4a0e44d2U, + 0xf812ea60U, 0x6b660df3U, 0xd97aa341U, 0x73780bebU, + 0xf158a969U, 0x561543ceU, 0x7e3749e6U, 0x5c9fc3c4U, + 0xc6a1675eU, 0xbf873827U, 0xcbee2553U, 0x4f4b04d7U, + 0xa519bc3dU, 0x9d2fb205U, 0x2e735db6U, 0xe7c92e7fU, + 0x893eb711U, 0x0591949dU, 0xc82ee650U, 0x4e0b45d6U, + 0xfe976966U, 0x0d9b9695U, 0x5b5a01c3U, 0x3b2219a3U, + 0x474106dfU, 0x434407dbU, 0x9faf3007U, 0xb78d3a2fU, + 0xc421e55cU, 0x9eef7106U, 0x4c8bc7d4U, 0xb842fa20U, + 0x1ccfd384U, 0x8531b41dU, 0x00d4d498U, 0x0f1b1497U, + 0xb6cd7b2eU, 0x9525b00dU, 0x83b4371bU, 0xf7dd2a6fU, + 0x8efb7516U, 0xb2c87a2aU, 0x9baa3103U, 0x9120b109U, + 0xdaba6042U, 0xf55da86dU, 0x366d5baeU, 0xd030e048U, + 0x64a9cdfcU, 0xc561a45dU, 0x1f0f1087U, 0x04d1d59cU, + 0x460147deU, 0x233c1fbbU, 0xb108b929U, 0xbac27822U, + 0x10c0d088U, 0x65e98cfdU, 0x20fcdcb8U, 0x30e8d8a8U, + 0xd435e14cU, 0x575502cfU, 0xac53ff34U, 0xdbfa2143U, + 0xc2a4665aU, 0xa856fe30U, 0x2f331cb7U, 0x0b1e1593U, + 0x67690effU, 0x14c5d18cU, 0x35ad98adU, 0xd6b5634eU, + 0xe549ac7dU, 0x4b4e05d3U, 0xe946af71U, 0xe00cec78U, + 0x92e0720aU, 0x31a899a9U, 0x0711169fU, 0x41c485d9U, + 0x1a4a5082U, 0x8134b519U, 0xc7e1265fU, 0x72384aeaU, + 0x1705128fU, 0x49ce87d1U, 0x8fbb3417U, 0x0a5e5492U, + 0xad13be35U, 0xdd7fa245U, 0x1645538eU, 0xd3f0234bU, + 0xf5f90c82U, 0xeca74b9bU, 0x093a337eU, 0x55712422U, + 0x9d8b16eaU, 0x29123b5eU, 0x5abee42dU, 0x701c6c07U, + 0xf639cf81U, 0x74196d03U, 0xfe33cd89U, 0xa5bd18d2U, + 0x0efff179U, 0x41602136U, 0x1eebf569U, 0xba66dccdU, + 0x02f0f275U, 0x338cbf44U, 0xc48541b3U, 0x77d9ae00U, + 0x06f5f371U, 0x54316523U, 0xbe63ddc9U, 0xa1b819d6U, + 0x04757173U, 0xbf239cc8U, 0xe228ca95U, 0x36c9ff41U, + 0x8b1a91fcU, 0xb4e95dc3U, 0xb669dfc1U, 0xc88a42bfU, + 0xdc9b47abU, 0xa73d9ad0U, 0xef678898U, 0x7d532e0aU, + 0xe8a24a9fU, 0x11243566U, 0xcc8f43bbU, 0x47e5a230U, + 0x6288ea15U, 0xff738c88U, 0x8250d2f5U, 0xa3389bd4U, + 0x192e376eU, 0x918415e6U, 0x1c6b776bU, 0x279dba50U, + 0x3d033e4aU, 0x60086817U, 0xde1bc5a9U, 0x087a727fU, + 0x899a13feU, 0x8e5fd1f9U, 0x0d3f327aU, 0xf8b64e8fU, + 0xacf75bdbU, 0xd1d405a6U, 0xfcb34f8bU, 0x45652032U, + 0x7bd6ad0cU, 0x90c454e7U, 0x52b4e625U, 0x34497d43U, + 0xb32c9fc4U, 0xb26cdec5U, 0x304c7c47U, 0x5d7b262aU, + 0x61482916U, 0x63c8ab14U, 0xf23cce85U, 0x44256133U, + 0xa0f858d7U, 0xcb4a81bcU, 0x5ebbe529U, 0xca0ac0bdU, + 0x35093c42U, 0xb8e65ecfU, 0x930497e4U, 0x0c7f737bU, + 0x0fbfb078U, 0x03b0b374U, 0xa8f25adfU, 0x640d6913U, + 0x6bc2a91cU, 0x3f83bc48U, 0xc5c500b2U, 0x80d050f7U, + 0x4d6f223aU, 0x01303176U, 0x9244d6e5U, 0x831093f4U, + 0x6fc7a818U, 0xf7798e80U, 0xd89e46afU, 0x7a96ec0dU, + 0xd611c7a1U, 0x3ec3fd49U, 0x9641d7e1U, 0xd75186a0U, + 0x2398bb54U, 0xcf4f80b8U, 0xe9e20b9eU, 0x245d7953U, + 0x3ac6fc4dU, 0x26ddfb51U, 0x5ffba428U, 0x42a0e235U, + 0xaa72d8ddU, 0x2ad2f85dU, 0x4fefa038U, 0xb0ec5cc7U, + 0xfdf30e8aU, 0xae77d9d9U, 0xb7299ec0U, 0xf37c8f84U, + 0xd09444a7U, 0xe1e80996U, 0x32ccfe45U, 0xe76d8a90U, + 0x9f0b94e8U, 0x7699ef01U, 0xa67ddbd1U, 0x310c3d46U, + 0x2c577b5bU, 0xbda31ecaU, 0x8d9f12faU, 0xd49145a3U, + 0x05353072U, 0x50346427U, 0x84d551f3U, 0xe5ed0892U, + 0xaf3798d8U, 0xb1ac1dc6U, 0x4eafe139U, 0x78166e0fU, + 0x20587857U, 0x715c2d06U, 0x654d2812U, 0x958114e2U, + 0x496a233eU, 0x2b92b95cU, 0xfa36cc8dU, 0x28527a5fU, + 0x2d173a5aU, 0x14617563U, 0xdb5e85acU, 0x3c437f4bU, + 0xc08040b7U, 0x7e93ed09U, 0xc605c3b1U, 0xfb768d8cU, + 0x186e766fU, 0xe0a84897U, 0x668deb11U, 0x6e87e919U, + 0x79562f0eU, 0x9ccb57ebU, 0x68026a1fU, 0x21183956U, + 0xda1ec4adU, 0x75592c02U, 0x251d3852U, 0x16e1f761U, + 0xa4fd59d3U, 0x3789be40U, 0x859510f2U, 0x2f97b858U, + 0xadb71adaU, 0x0afaf07dU, 0x22d8fa55U, 0x00707077U, + 0x9a4ed4edU, 0xe3688b94U, 0x970196e0U, 0x13a4b764U, + 0xf9f60f8eU, 0xc1c001b6U, 0x729cee05U, 0xbb269dccU, + 0xd5d104a2U, 0x597e272eU, 0x94c155e3U, 0x12e4f665U, + 0xa278dad5U, 0x51742526U, 0x07b5b270U, 0x67cdaa10U, + 0x1baeb56cU, 0x1fabb468U, 0xc34083b4U, 0xeb62899cU, + 0x98ce56efU, 0xc200c2b5U, 0x10647467U, 0xe4ad4993U, + 0x40206037U, 0xd9de07aeU, 0x5c3b672bU, 0x53f4a724U, + 0xea22c89dU, 0xc9ca03beU, 0xdf5b84a8U, 0xab3299dcU, + 0xd214c6a5U, 0xee27c999U, 0xc74582b0U, 0xcdcf02baU, + 0x8655d3f1U, 0xa9b21bdeU, 0x6a82e81dU, 0x8cdf53fbU, + 0x38467e4fU, 0x998e17eeU, 0x43e0a334U, 0x583e662fU, + 0x1aeef46dU, 0x7fd3ac08U, 0xede70a9aU, 0xe62dcb91U, + 0x4c2f633bU, 0x39063f4eU, 0x7c136f0bU, 0x6c076b1bU, + 0x88da52ffU, 0x0bbab17cU, 0xf0bc4c87U, 0x871592f0U, + 0x9e4bd5e9U, 0xf4b94d83U, 0x73dcaf04U, 0x57f1a620U, + 0x3b86bd4cU, 0x482a623fU, 0x69422b1eU, 0x8a5ad0fdU, + 0xb9a61fceU, 0x17a1b660U, 0xb5a91cc2U, 0xbce35fcbU, + 0xce0fc1b9U, 0x6d472a1aU, 0x5bfea52cU, 0x1d2b366aU, + 0x46a5e331U, 0xdddb06aaU, 0x9b0e95ecU, 0x2ed7f959U, + 0x4beaa13cU, 0x15213462U, 0xd35487a4U, 0x56b1e721U, + 0xf1fc0d86U, 0x819011f6U, 0x4aaae03dU, 0x8f1f90f8U, + 0xd9a47df3U, 0xc0fa3aeaU, 0x2567420fU, 0x792c5553U, + 0xb1d6679bU, 0x054f4a2fU, 0x76e3955cU, 0x5c411d76U, + 0xda64bef0U, 0x58441c72U, 0xd26ebcf8U, 0x89e069a3U, + 0x22a28008U, 0x6d3d5047U, 0x32b68418U, 0x963badbcU, + 0x2ead8304U, 0x1fd1ce35U, 0xe8d830c2U, 0x5b84df71U, + 0x2aa88200U, 0x786c1452U, 0x923eacb8U, 0x8de568a7U, + 0x28280002U, 0x937eedb9U, 0xce75bbe4U, 0x1a948e30U, + 0xa747e08dU, 0x98b42cb2U, 0x9a34aeb0U, 0xe4d733ceU, + 0xf0c636daU, 0x8b60eba1U, 0xc33af9e9U, 0x510e5f7bU, + 0xc4ff3beeU, 0x3d794417U, 0xe0d232caU, 0x6bb8d341U, + 0x4ed59b64U, 0xd32efdf9U, 0xae0da384U, 0x8f65eaa5U, + 0x3573461fU, 0xbdd96497U, 0x3036061aU, 0x0bc0cb21U, + 0x115e4f3bU, 0x4c551966U, 0xf246b4d8U, 0x2427030eU, + 0xa5c7628fU, 0xa202a088U, 0x2162430bU, 0xd4eb3ffeU, + 0x80aa2aaaU, 0xfd8974d7U, 0xd0ee3efaU, 0x69385143U, + 0x578bdc7dU, 0xbc992596U, 0x7ee99754U, 0x18140c32U, + 0x9f71eeb5U, 0x9e31afb4U, 0x1c110d36U, 0x7126575bU, + 0x4d155867U, 0x4f95da65U, 0xde61bff4U, 0x68781042U, + 0x8ca529a6U, 0xe717f0cdU, 0x72e69458U, 0xe657b1ccU, + 0x19544d33U, 0x94bb2fbeU, 0xbf59e695U, 0x2022020aU, + 0x23e2c109U, 0x2fedc205U, 0x84af2baeU, 0x48501862U, + 0x479fd86dU, 0x13decd39U, 0xe99871c3U, 0xac8d2186U, + 0x6132534bU, 0x2d6d4007U, 0xbe19a794U, 0xaf4de285U, + 0x439ad969U, 0xdb24fff1U, 0xf4c337deU, 0x56cb9d7cU, + 0xfa4cb6d0U, 0x129e8c38U, 0xba1ca690U, 0xfb0cf7d1U, + 0x0fc5ca25U, 0xe312f1c9U, 0xc5bf7aefU, 0x08000822U, + 0x169b8d3cU, 0x0a808a20U, 0x73a6d559U, 0x6efd9344U, + 0x862fa9acU, 0x068f892cU, 0x63b2d149U, 0x9cb12db6U, + 0xd1ae7ffbU, 0x822aa8a8U, 0x9b74efb1U, 0xdf21fef5U, + 0xfcc935d6U, 0xcdb578e7U, 0x1e918f34U, 0xcb30fbe1U, + 0xb356e599U, 0x5ac49e70U, 0x8a20aaa0U, 0x1d514c37U, + 0x000a0a2aU, 0x91fe6fbbU, 0xa1c2638bU, 0xf8cc34d2U, + 0x29684103U, 0x7c691556U, 0xa8882082U, 0xc9b079e3U, + 0x836ae9a9U, 0x9df16cb7U, 0x62f29048U, 0x544b1f7eU, + 0x0c050926U, 0x5d015c77U, 0x49105963U, 0xb9dc6593U, + 0x6537524fU, 0x07cfc82dU, 0xd66bbdfcU, 0x040f0b2eU, + 0x014a4b2bU, 0x383c0412U, 0xf703f4ddU, 0x101e0e3aU, + 0xecdd31c6U, 0x52ce9c78U, 0xea58b2c0U, 0xd72bfcfdU, + 0x3433071eU, 0xccf539e6U, 0x4ad09a60U, 0x42da9868U, + 0x550b5e7fU, 0xb096269aU, 0x445f1b6eU, 0x0d454827U, + 0xf643b5dcU, 0x59045d73U, 0x09404923U, 0x3abc8610U, + 0x88a028a2U, 0x1bd4cf31U, 0xa9c86183U, 0x03cac929U, + 0x81ea6babU, 0x26a7810cU, 0x0e858b24U, 0x2c2d0106U, + 0xb613a59cU, 0xcf35fae5U, 0xbb5ce791U, 0x3ff9c615U, + 0xd5ab7effU, 0xed9d70c7U, 0x5ec19f74U, 0x977becbdU, + 0xf98c75d3U, 0x7523565fU, 0xb89c2492U, 0x3eb98714U, + 0x8e25aba4U, 0x7d295457U, 0x2be8c301U, 0x4b90db61U, + 0x37f3c41dU, 0x33f6c519U, 0xef1df2c5U, 0xc73ff8edU, + 0xb493279eU, 0xee5db3c4U, 0x3c390516U, 0xc8f038e2U, + 0x6c7d1146U, 0xf58376dfU, 0x7066165aU, 0x7fa9d655U, + 0xc67fb9ecU, 0xe59772cfU, 0xf306f5d9U, 0x876fe8adU, + 0xfe49b7d4U, 0xc27ab8e8U, 0xeb18f3c1U, 0xe19273cbU, + 0xaa08a280U, 0x85ef6aafU, 0x46df996cU, 0xa082228aU, + 0x141b0f3eU, 0xb5d3669fU, 0x6fbdd245U, 0x7463175eU, + 0x36b3851cU, 0x538edd79U, 0xc1ba7bebU, 0xca70bae0U, + 0x6072124aU, 0x155b4e3fU, 0x504e1e7aU, 0x405a1a6aU, + 0xa487238eU, 0x27e7c00dU, 0xdce13df6U, 0xab48e381U, + 0xb216a498U, 0xd8e43cf2U, 0x5f81de75U, 0x7bacd751U, + 0x17dbcc3dU, 0x6477134eU, 0x451f5a6fU, 0xa607a18cU, + 0x95fb6ebfU, 0x3bfcc711U, 0x99f46db3U, 0x90be2ebaU, + 0xe252b0c8U, 0x411a5b6bU, 0x77a3d45dU, 0x3176471bU, + 0x6af89240U, 0xf18677dbU, 0xb753e49dU, 0x028a8828U, + 0x67b7d04dU, 0x397c4513U, 0xff09f6d5U, 0x7aec9650U, + 0xdda17cf7U, 0xadcd6087U, 0x66f7914cU, 0xa342e189U, + 0x1d322fa1U, 0x046c68b8U, 0xe1f1105dU, 0xbdba0701U, + 0x754035c9U, 0xc1d9187dU, 0xb275c70eU, 0x98d74f24U, + 0x1ef2eca2U, 0x9cd24e20U, 0x16f8eeaaU, 0x4d763bf1U, + 0xe634d25aU, 0xa9ab0215U, 0xf620d64aU, 0x52adffeeU, + 0xea3bd156U, 0xdb479c67U, 0x2c4e6290U, 0x9f128d23U, + 0xee3ed052U, 0xbcfa4600U, 0x56a8feeaU, 0x49733af5U, + 0xecbe5250U, 0x57e8bfebU, 0x0ae3e9b6U, 0xde02dc62U, + 0x63d1b2dfU, 0x5c227ee0U, 0x5ea2fce2U, 0x2041619cU, + 0x34506488U, 0x4ff6b9f3U, 0x07acabbbU, 0x95980d29U, + 0x006969bcU, 0xf9ef1645U, 0x24446098U, 0xaf2e8113U, + 0x8a43c936U, 0x17b8afabU, 0x6a9bf1d6U, 0x4bf3b8f7U, + 0xf1e5144dU, 0x794f36c5U, 0xf4a05448U, 0xcf569973U, + 0xd5c81d69U, 0x88c34b34U, 0x36d0e68aU, 0xe0b1515cU, + 0x615130ddU, 0x6694f2daU, 0xe5f41159U, 0x107d6dacU, + 0x443c78f8U, 0x391f2685U, 0x14786ca8U, 0xadae0311U, + 0x931d8e2fU, 0x780f77c4U, 0xba7fc506U, 0xdc825e60U, + 0x5be7bce7U, 0x5aa7fde6U, 0xd8875f64U, 0xb5b00509U, + 0x89830a35U, 0x8b038837U, 0x1af7eda6U, 0xacee4210U, + 0x48337bf4U, 0x2381a29fU, 0xb670c60aU, 0x22c1e39eU, + 0xddc21f61U, 0x502d7decU, 0x7bcfb4c7U, 0xe4b45058U, + 0xe774935bU, 0xeb7b9057U, 0x403979fcU, 0x8cc64a30U, + 0x83098a3fU, 0xd7489f6bU, 0x2d0e2391U, 0x681b73d4U, + 0xa5a40119U, 0xe9fb1255U, 0x7a8ff5c6U, 0x6bdbb0d7U, + 0x870c8b3bU, 0x1fb2ada3U, 0x3055658cU, 0x925dcf2eU, + 0x3edae482U, 0xd608de6aU, 0x7e8af4c2U, 0x3f9aa583U, + 0xcb539877U, 0x2784a39bU, 0x012928bdU, 0xcc965a70U, + 0xd20ddf6eU, 0xce16d872U, 0xb730870bU, 0xaa6bc116U, + 0x42b9fbfeU, 0xc219db7eU, 0xa724831bU, 0x58277fe4U, + 0x15382da9U, 0x46bcfafaU, 0x5fe2bde3U, 0x1bb7aca7U, + 0x385f6784U, 0x09232ab5U, 0xda07dd66U, 0x0fa6a9b3U, + 0x77c0b7cbU, 0x9e52cc22U, 0x4eb6f8f2U, 0xd9c71e65U, + 0xc49c5878U, 0x55683de9U, 0x655431d9U, 0x3c5a6680U, + 0xedfe1351U, 0xb8ff4704U, 0x6c1e72d0U, 0x0d262bb1U, + 0x47fcbbfbU, 0x59673ee5U, 0xa664c21aU, 0x90dd4d2cU, + 0xc8935b74U, 0x99970e25U, 0x8d860b31U, 0x7d4a37c1U, + 0xa1a1001dU, 0xc3599a7fU, 0x12fdefaeU, 0xc099597cU, + 0xc5dc1979U, 0xfcaa5640U, 0x3395a68fU, 0xd4885c68U, + 0x284b6394U, 0x9658ce2aU, 0x2ecee092U, 0x13bdaeafU, + 0xf0a5554cU, 0x08636bb4U, 0x8e46c832U, 0x864cca3aU, + 0x919d0c2dU, 0x740074c8U, 0x80c9493cU, 0xc9d31a75U, + 0x32d5e78eU, 0x9d920f21U, 0xcdd61b71U, 0xfe2ad442U, + 0x4c367af0U, 0xdf429d63U, 0x6d5e33d1U, 0xc75c9b7bU, + 0x457c39f9U, 0xe231d35eU, 0xca13d976U, 0xe8bb5354U, + 0x7285f7ceU, 0x0ba3a8b7U, 0x7fcab5c3U, 0xfb6f9447U, + 0x113d2cadU, 0x290b2295U, 0x9a57cd26U, 0x53edbeefU, + 0x3d1a2781U, 0xb1b5040dU, 0x7c0a76c0U, 0xfa2fd546U, + 0x4ab3f9f6U, 0xb9bf0605U, 0xef7e9153U, 0x8f068933U, + 0xf365964fU, 0xf760974bU, 0x2b8ba097U, 0x03a9aabfU, + 0x700575ccU, 0x2acbe196U, 0xf8af5744U, 0x0c666ab0U, + 0xa8eb4314U, 0x3115248dU, 0xb4f04408U, 0xbb3f8407U, + 0x02e9ebbeU, 0x2101209dU, 0x3790a78bU, 0x43f9baffU, + 0x3adfe586U, 0x06eceabaU, 0x2f8ea193U, 0x25042199U, + 0x6e9ef0d2U, 0x417938fdU, 0x8249cb3eU, 0x641470d8U, + 0xd08d5d6cU, 0x714534cdU, 0xab2b8017U, 0xb0f5450cU, + 0xf225d74eU, 0x97188f2bU, 0x052c29b9U, 0x0ee6e8b2U, + 0xa4e44018U, 0xd1cd1c6dU, 0x94d84c28U, 0x84cc4838U, + 0x601171dcU, 0xe371925fU, 0x18776fa4U, 0x6fdeb1d3U, + 0x7680f6caU, 0x1c726ea0U, 0x9b178c27U, 0xbf3a8503U, + 0xd34d9e6fU, 0xa0e1411cU, 0x8189083dU, 0x6291f3deU, + 0x516d3cedU, 0xff6a9543U, 0x5d623fe1U, 0x54287ce8U, + 0x26c4e29aU, 0x858c0939U, 0xb335860fU, 0xf5e01549U, + 0xae6ec012U, 0x35102589U, 0x73c5b6cfU, 0xc61cda7aU, + 0xa321821fU, 0xfdea1741U, 0x3b9fa487U, 0xbe7ac402U, + 0x19372ea5U, 0x695b32d5U, 0xa261c31eU, 0x67d4b3dbU, + 0x4f8ac54bU, 0x56d48252U, 0xb349fab7U, 0xef02edebU, + 0x27f8df23U, 0x9361f297U, 0xe0cd2de4U, 0xca6fa5ceU, + 0x4c4a0648U, 0xce6aa4caU, 0x44400440U, 0x1fced11bU, + 0xb48c38b0U, 0xfb13e8ffU, 0xa4983ca0U, 0x00151504U, + 0xb8833bbcU, 0x89ff768dU, 0x7ef6887aU, 0xcdaa67c9U, + 0xbc863ab8U, 0xee42aceaU, 0x04101400U, 0x1bcbd01fU, + 0xbe06b8baU, 0x05505501U, 0x585b035cU, 0x8cba3688U, + 0x31695835U, 0x0e9a940aU, 0x0c1a1608U, 0x72f98b76U, + 0x66e88e62U, 0x1d4e5319U, 0x55144151U, 0xc720e7c3U, + 0x52d18356U, 0xab57fcafU, 0x76fc8a72U, 0xfd966bf9U, + 0xd8fb23dcU, 0x45004541U, 0x38231b3cU, 0x194b521dU, + 0xa35dfea7U, 0x2bf7dc2fU, 0xa618bea2U, 0x9dee7399U, + 0x8770f783U, 0xda7ba1deU, 0x64680c60U, 0xb209bbb6U, + 0x33e9da37U, 0x342c1830U, 0xb74cfbb3U, 0x42c58746U, + 0x16849212U, 0x6ba7cc6fU, 0x46c08642U, 0xff16e9fbU, + 0xc1a564c5U, 0x2ab79d2eU, 0xe8c72fecU, 0x8e3ab48aU, + 0x095f560dU, 0x081f170cU, 0x8a3fb58eU, 0xe708efe3U, + 0xdb3be0dfU, 0xd9bb62ddU, 0x484f074cU, 0xfe56a8faU, + 0x1a8b911eU, 0x71394875U, 0xe4c82ce0U, 0x70790974U, + 0x8f7af58bU, 0x02959706U, 0x29775e2dU, 0xb60cbab2U, + 0xb5cc79b1U, 0xb9c37abdU, 0x12819316U, 0xde7ea0daU, + 0xd1b160d5U, 0x85f07581U, 0x7fb6c97bU, 0x3aa3993eU, + 0xf71cebf3U, 0xbb43f8bfU, 0x28371f2cU, 0x39635a3dU, + 0xd5b461d1U, 0x4d0a4749U, 0x62ed8f66U, 0xc0e525c4U, + 0x6c620e68U, 0x84b03480U, 0x2c321e28U, 0x6d224f69U, + 0x99eb729dU, 0x753c4971U, 0x5391c257U, 0x9e2eb09aU, + 0x80b53584U, 0x9cae3298U, 0xe5886de1U, 0xf8d32bfcU, + 0x10011114U, 0x90a13194U, 0xf59c69f1U, 0x0a9f950eU, + 0x4780c743U, 0x14041010U, 0x0d5a5709U, 0x490f464dU, + 0x6ae78d6eU, 0x5b9bc05fU, 0x88bf378cU, 0x5d1e4359U, + 0x25785d21U, 0xccea26c8U, 0x1c0e1218U, 0x8b7ff48fU, + 0x9624b292U, 0x07d0d703U, 0x37ecdb33U, 0x6ee28c6aU, + 0xbf46f9bbU, 0xea47adeeU, 0x3ea6983aU, 0x5f9ec15bU, + 0x15445111U, 0x0bdfd40fU, 0xf4dc28f0U, 0xc265a7c6U, + 0x9a2bb19eU, 0xcb2fe4cfU, 0xdf3ee1dbU, 0x2ff2dd2bU, + 0xf319eaf7U, 0x91e17095U, 0x40450544U, 0x9221b396U, + 0x9764f393U, 0xae12bcaaU, 0x612d4c65U, 0x8630b682U, + 0x7af3897eU, 0xc4e024c0U, 0x7c760a78U, 0x41054445U, + 0xa21dbfa6U, 0x5adb815eU, 0xdcfe22d8U, 0xd4f420d0U, + 0xc325e6c7U, 0x26b89e22U, 0xd271a3d6U, 0x9b6bf09fU, + 0x606d0d64U, 0xcf2ae5cbU, 0x9f6ef19bU, 0xac923ea8U, + 0x1e8e901aU, 0x8dfa7789U, 0x3fe6d93bU, 0x95e47191U, + 0x17c4d313U, 0xb08939b4U, 0x98ab339cU, 0xba03b9beU, + 0x203d1d24U, 0x591b425dU, 0x2d725f29U, 0xa9d77eadU, + 0x4385c647U, 0x7bb3c87fU, 0xc8ef27ccU, 0x01555405U, + 0x6fa2cd6bU, 0xe30deee7U, 0x2eb29c2aU, 0xa8973facU, + 0x180b131cU, 0xeb07ecefU, 0xbdc67bb9U, 0xddbe63d9U, + 0xa1dd7ca5U, 0xa5d87da1U, 0x79334a7dU, 0x51114055U, + 0x22bd9f26U, 0x78730b7cU, 0xaa17bdaeU, 0x5ede805aU, + 0xfa53a9feU, 0x63adce67U, 0xe648aee2U, 0xe9876eedU, + 0x50510154U, 0x73b9ca77U, 0x65284d61U, 0x11415015U, + 0x68670f6cU, 0x54540050U, 0x7d364b79U, 0x77bccb73U, + 0x3c261a38U, 0x13c1d217U, 0xd0f121d4U, 0x36ac9a32U, + 0x8235b786U, 0x23fdde27U, 0xf9936afdU, 0xe24dafe6U, + 0xa09d3da4U, 0xc5a065c1U, 0x5794c353U, 0x5c5e0258U, + 0xf65caaf2U, 0x8375f687U, 0xc660a6c2U, 0xd674a2d2U, + 0x32a99b36U, 0xb1c978b5U, 0x4acf854eU, 0x3d665b39U, + 0x24381c20U, 0x4eca844aU, 0xc9af66cdU, 0xed826fe9U, + 0x81f57485U, 0xf259abf6U, 0xd331e2d7U, 0x30291934U, + 0x03d5d607U, 0xadd27fa9U, 0x0fdad50bU, 0x06909602U, + 0x747c0870U, 0xd734e3d3U, 0xe18d6ce5U, 0xa758ffa3U, + 0xfcd62af8U, 0x67a8cf63U, 0x217d5c25U, 0x94a43090U, + 0xf19968f5U, 0xaf52fdabU, 0x69274e6dU, 0xecc22ee8U, + 0x4b8fc44fU, 0x3be3d83fU, 0xf0d929f4U, 0x356c5931U, + 0x944eda54U, 0x8d109d4dU, 0x688de5a8U, 0x34c6f2f4U, + 0xfc3cc03cU, 0x48a5ed88U, 0x3b0932fbU, 0x11abbad1U, + 0x978e1957U, 0x15aebbd5U, 0x9f841b5fU, 0xc40ace04U, + 0x6f4827afU, 0x20d7f7e0U, 0x7f5c23bfU, 0xdbd10a1bU, + 0x634724a3U, 0x523b6992U, 0xa5329765U, 0x166e78d6U, + 0x674225a7U, 0x3586b3f5U, 0xdfd40b1fU, 0xc00fcf00U, + 0x65c2a7a5U, 0xde944a1eU, 0x839f1c43U, 0x577e2997U, + 0xeaad472aU, 0xd55e8b15U, 0xd7de0917U, 0xa93d9469U, + 0xbd2c917dU, 0xc68a4c06U, 0x8ed05e4eU, 0x1ce4f8dcU, + 0x89159c49U, 0x7093e3b0U, 0xad38956dU, 0x265274e6U, + 0x033f3cc3U, 0x9ec45a5eU, 0xe3e70423U, 0xc28f4d02U, + 0x7899e1b8U, 0xf033c330U, 0x7ddca1bdU, 0x462a6c86U, + 0x5cb4e89cU, 0x01bfbec1U, 0xbfac137fU, 0x69cda4a9U, + 0xe82dc528U, 0xefe8072fU, 0x6c88e4acU, 0x99019859U, + 0xcd408d0dU, 0xb063d370U, 0x9d04995dU, 0x24d2f6e4U, + 0x1a617bdaU, 0xf1738231U, 0x330330f3U, 0x55feab95U, + 0xd29b4912U, 0xd3db0813U, 0x51fbaa91U, 0x3cccf0fcU, + 0x00ffffc0U, 0x027f7dc2U, 0x938b1853U, 0x2592b7e5U, + 0xc14f8e01U, 0xaafd576aU, 0x3f0c33ffU, 0xabbd166bU, + 0x54beea94U, 0xd9518819U, 0xf2b34132U, 0x6dc8a5adU, + 0x6e0866aeU, 0x620765a2U, 0xc9458c09U, 0x05babfc5U, + 0x0a757fcaU, 0x5e346a9eU, 0xa472d664U, 0xe1678621U, + 0x2cd8f4ecU, 0x6087e7a0U, 0xf3f30033U, 0xe2a74522U, + 0x0e707eceU, 0x96ce5856U, 0xb9299079U, 0x1b213adbU, + 0xb7a61177U, 0x5f742b9fU, 0xf7f60137U, 0xb6e65076U, + 0x422f6d82U, 0xaef8566eU, 0x8855dd48U, 0x45eaaf85U, + 0x5b712a9bU, 0x476a2d87U, 0x3e4c72feU, 0x231734e3U, + 0xcbc50e0bU, 0x4b652e8bU, 0x2e5876eeU, 0xd15b8a11U, + 0x9c44d85cU, 0xcfc00f0fU, 0xd69e4816U, 0x92cb5952U, + 0xb1239271U, 0x805fdf40U, 0x537b2893U, 0x86da5c46U, + 0xfebc423eU, 0x172e39d7U, 0xc7ca0d07U, 0x50bbeb90U, + 0x4de0ad8dU, 0xdc14c81cU, 0xec28c42cU, 0xb5269375U, + 0x6482e6a4U, 0x3183b2f1U, 0xe5628725U, 0x845ade44U, + 0xce804e0eU, 0xd01bcb10U, 0x2f1837efU, 0x19a1b8d9U, + 0x41efae81U, 0x10ebfbd0U, 0x04fafec4U, 0xf436c234U, + 0x28ddf5e8U, 0x4a256f8aU, 0x9b811a5bU, 0x49e5ac89U, + 0x4ca0ec8cU, 0x75d6a3b5U, 0xbae9537aU, 0x5df4a99dU, + 0xa1379661U, 0x1f243bdfU, 0xa7b21567U, 0x9ac15b5aU, + 0x79d9a0b9U, 0x811f9e41U, 0x073a3dc7U, 0x0f303fcfU, + 0x18e1f9d8U, 0xfd7c813dU, 0x09b5bcc9U, 0x40afef80U, + 0xbba9127bU, 0x14eefad4U, 0x44aaee84U, 0x775621b7U, + 0xc54a8f05U, 0x563e6896U, 0xe422c624U, 0x4e206e8eU, + 0xcc00cc0cU, 0x6b4d26abU, 0x436f2c83U, 0x61c7a6a1U, + 0xfbf9023bU, 0x82df5d42U, 0xf6b64036U, 0x721361b2U, + 0x9841d958U, 0xa077d760U, 0x132b38d3U, 0xda914b1aU, + 0xb466d274U, 0x38c9f1f8U, 0xf5768335U, 0x735320b3U, + 0xc3cf0c03U, 0x30c3f3f0U, 0x660264a6U, 0x067a7cc6U, + 0x7a1963baU, 0x7e1c62beU, 0xa2f75562U, 0x8ad55f4aU, + 0xf9798039U, 0xa3b71463U, 0x71d3a2b1U, 0x851a9f45U, + 0x2197b6e1U, 0xb869d178U, 0x3d8cb1fdU, 0x324371f2U, + 0x8b951e4bU, 0xa87dd568U, 0xbeec527eU, 0xca854f0aU, + 0xb3a31073U, 0x8f901f4fU, 0xa6f25466U, 0xac78d46cU, + 0xe7e20527U, 0xc805cd08U, 0x0b353ecbU, 0xed68852dU, + 0x59f1a899U, 0xf839c138U, 0x225775e2U, 0x3989b0f9U, + 0x7b5922bbU, 0x1e647adeU, 0x8c50dc4cU, 0x879a1d47U, + 0x2d98b5edU, 0x58b1e998U, 0x1da4b9ddU, 0x0db0bdcdU, + 0xe96d8429U, 0x6a0d67aaU, 0x910b9a51U, 0xe6a24426U, + 0xfffc033fU, 0x950e9b55U, 0x126b79d2U, 0x364670f6U, + 0x5a316b9aU, 0x299db4e9U, 0x08f5fdc8U, 0xebed062bU, + 0xd811c918U, 0x761660b6U, 0xd41eca14U, 0xdd54891dU, + 0xafb8176fU, 0x0cf0fcccU, 0x3a4973faU, 0x7c9ce0bcU, + 0x271235e7U, 0xbc6cd07cU, 0xfab9433aU, 0x4f602f8fU, + 0x2a5d77eaU, 0x7496e2b4U, 0xb2e35172U, 0x370631f7U, + 0x904bdb50U, 0xe027c720U, 0x2b1d36ebU, 0xeea8462eU, + 0x59267ff1U, 0x407838e8U, 0xa5e5400dU, 0xf9ae5751U, + 0x31546599U, 0x85cd482dU, 0xf661975eU, 0xdcc31f74U, + 0x5ae6bcf2U, 0xd8c61e70U, 0x52ecbefaU, 0x09626ba1U, + 0xa220820aU, 0xedbf5245U, 0xb234861aU, 0x16b9afbeU, + 0xae2f8106U, 0x9f53cc37U, 0x685a32c0U, 0xdb06dd73U, + 0xaa2a8002U, 0xf8ee1650U, 0x12bcaebaU, 0x0d676aa5U, + 0xa8aa0200U, 0x13fcefbbU, 0x4ef7b9e6U, 0x9a168c32U, + 0x27c5e28fU, 0x18362eb0U, 0x1ab6acb2U, 0x645531ccU, + 0x704434d8U, 0x0be2e9a3U, 0x43b8fbebU, 0xd18c5d79U, + 0x447d39ecU, 0xbdfb4615U, 0x605030c8U, 0xeb3ad143U, + 0xce579966U, 0x53acfffbU, 0x2e8fa186U, 0x0fe7e8a7U, + 0xb5f1441dU, 0x3d5b6695U, 0xb0b40418U, 0x8b42c923U, + 0x91dc4d39U, 0xccd71b64U, 0x72c4b6daU, 0xa4a5010cU, + 0x2545608dU, 0x2280a28aU, 0xa1e04109U, 0x54693dfcU, + 0x002828a8U, 0x7d0b76d5U, 0x506c3cf8U, 0xe9ba5341U, + 0xd709de7fU, 0x3c1b2794U, 0xfe6b9556U, 0x98960e30U, + 0x1ff3ecb7U, 0x1eb3adb6U, 0x9c930f34U, 0xf1a45559U, + 0xcd975a65U, 0xcf17d867U, 0x5ee3bdf6U, 0xe8fa1240U, + 0x0c272ba4U, 0x6795f2cfU, 0xf264965aU, 0x66d5b3ceU, + 0x99d64f31U, 0x14392dbcU, 0x3fdbe497U, 0xa0a00008U, + 0xa360c30bU, 0xaf6fc007U, 0x042d29acU, 0xc8d21a60U, + 0xc71dda6fU, 0x935ccf3bU, 0x691a73c1U, 0x2c0f2384U, + 0xe1b05149U, 0xadef4205U, 0x3e9ba596U, 0x2fcfe087U, + 0xc318db6bU, 0x5ba6fdf3U, 0x744135dcU, 0xd6499f7eU, + 0x7aceb4d2U, 0x921c8e3aU, 0x3a9ea492U, 0x7b8ef5d3U, + 0x8f47c827U, 0x6390f3cbU, 0x453d78edU, 0x88820a20U, + 0x96198f3eU, 0x8a028822U, 0xf324d75bU, 0xee7f9146U, + 0x06adabaeU, 0x860d8b2eU, 0xe330d34bU, 0x1c332fb4U, + 0x512c7df9U, 0x02a8aaaaU, 0x1bf6edb3U, 0x5fa3fcf7U, + 0x7c4b37d4U, 0x4d377ae5U, 0x9e138d36U, 0x4bb2f9e3U, + 0x33d4e79bU, 0xda469c72U, 0x0aa2a8a2U, 0x9dd34e35U, + 0x80880828U, 0x117c6db9U, 0x21406189U, 0x784e36d0U, + 0xa9ea4301U, 0xfceb1754U, 0x280a2280U, 0x49327be1U, + 0x03e8ebabU, 0x1d736eb5U, 0xe270924aU, 0xd4c91d7cU, + 0x8c870b24U, 0xdd835e75U, 0xc9925b61U, 0x395e6791U, + 0xe5b5504dU, 0x874dca2fU, 0x56e9bffeU, 0x848d092cU, + 0x81c84929U, 0xb8be0610U, 0x7781f6dfU, 0x909c0c38U, + 0x6c5f33c4U, 0xd24c9e7aU, 0x6adab0c2U, 0x57a9feffU, + 0xb4b1051cU, 0x4c773be4U, 0xca529862U, 0xc2589a6aU, + 0xd5895c7dU, 0x30142498U, 0xc4dd196cU, 0x8dc74a25U, + 0x76c1b7deU, 0xd9865f71U, 0x89c24b21U, 0xba3e8412U, + 0x08222aa0U, 0x9b56cd33U, 0x294a6381U, 0x8348cb2bU, + 0x016869a9U, 0xa625830eU, 0x8e078926U, 0xacaf0304U, + 0x3691a79eU, 0x4fb7f8e7U, 0x3bdee593U, 0xbf7bc417U, + 0x55297cfdU, 0x6d1f72c5U, 0xde439d76U, 0x17f9eebfU, + 0x790e77d1U, 0xf5a1545dU, 0x381e2690U, 0xbe3b8516U, + 0x0ea7a9a6U, 0xfdab5655U, 0xab6ac103U, 0xcb12d963U, + 0xb771c61fU, 0xb374c71bU, 0x6f9ff0c7U, 0x47bdfaefU, + 0x3411259cU, 0x6edfb1c6U, 0xbcbb0714U, 0x48723ae0U, + 0xecff1344U, 0x750174ddU, 0xf0e41458U, 0xff2bd457U, + 0x46fdbbeeU, 0x651570cdU, 0x7384f7dbU, 0x07edeaafU, + 0x7ecbb5d6U, 0x42f8baeaU, 0x6b9af1c3U, 0x611071c9U, + 0x2a8aa082U, 0x056d68adU, 0xc65d9b6eU, 0x20002088U, + 0x94990d3cU, 0x3551649dU, 0xef3fd047U, 0xf4e1155cU, + 0xb631871eU, 0xd30cdf7bU, 0x413879e9U, 0x4af2b8e2U, + 0xe0f01048U, 0x95d94c3dU, 0xd0cc1c78U, 0xc0d81868U, + 0x2405218cU, 0xa765c20fU, 0x5c633ff4U, 0x2bcae183U, + 0x3294a69aU, 0x58663ef0U, 0xdf03dc77U, 0xfb2ed553U, + 0x9759ce3fU, 0xe4f5114cU, 0xc59d586dU, 0x2685a38eU, + 0x15796cbdU, 0xbb7ec513U, 0x19766fb1U, 0x103c2cb8U, + 0x62d0b2caU, 0xc1985969U, 0xf721d65fU, 0xb1f44519U, + 0xea7a9042U, 0x710475d9U, 0x37d1e69fU, 0x82088a2aU, + 0xe735d24fU, 0xb9fe4711U, 0x7f8bf4d7U, 0xfa6e9452U, + 0x5d237ef5U, 0x2d4f6285U, 0xe675934eU, 0x23c0e38bU, + 0x0fcbc44aU, 0x16958353U, 0xf308fbb6U, 0xaf43eceaU, + 0x67b9de22U, 0xd320f396U, 0xa08c2ce5U, 0x8a2ea4cfU, + 0x0c0b0749U, 0x8e2ba5cbU, 0x04010541U, 0x5f8fd01aU, + 0xf4cd39b1U, 0xbb52e9feU, 0xe4d93da1U, 0x40541405U, + 0xf8c23abdU, 0xc9be778cU, 0x3eb7897bU, 0x8deb66c8U, + 0xfcc73bb9U, 0xae03adebU, 0x44511501U, 0x5b8ad11eU, + 0xfe47b9bbU, 0x45115400U, 0x181a025dU, 0xccfb3789U, + 0x71285934U, 0x4edb950bU, 0x4c5b1709U, 0x32b88a77U, + 0x26a98f63U, 0x5d0f5218U, 0x15554050U, 0x8761e6c2U, + 0x12908257U, 0xeb16fdaeU, 0x36bd8b73U, 0xbdd76af8U, + 0x98ba22ddU, 0x05414440U, 0x78621a3dU, 0x590a531cU, + 0xe31cffa6U, 0x6bb6dd2eU, 0xe659bfa3U, 0xddaf7298U, + 0xc731f682U, 0x9a3aa0dfU, 0x24290d61U, 0xf248bab7U, + 0x73a8db36U, 0x746d1931U, 0xf70dfab2U, 0x02848647U, + 0x56c59313U, 0x2be6cd6eU, 0x06818743U, 0xbf57e8faU, + 0x81e465c4U, 0x6af69c2fU, 0xa8862eedU, 0xce7bb58bU, + 0x491e570cU, 0x485e160dU, 0xca7eb48fU, 0xa749eee2U, + 0x9b7ae1deU, 0x99fa63dcU, 0x080e064dU, 0xbe17a9fbU, + 0x5aca901fU, 0x31784974U, 0xa4892de1U, 0x30380875U, + 0xcf3bf48aU, 0x42d49607U, 0x69365f2cU, 0xf64dbbb3U, + 0xf58d78b0U, 0xf9827bbcU, 0x52c09217U, 0x9e3fa1dbU, + 0x91f061d4U, 0xc5b17480U, 0x3ff7c87aU, 0x7ae2983fU, + 0xb75deaf2U, 0xfb02f9beU, 0x68761e2dU, 0x79225b3cU, + 0x95f560d0U, 0x0d4b4648U, 0x22ac8e67U, 0x80a424c5U, + 0x2c230f69U, 0xc4f13581U, 0x6c731f29U, 0x2d634e68U, + 0xd9aa739cU, 0x357d4870U, 0x13d0c356U, 0xde6fb19bU, + 0xc0f43485U, 0xdcef3399U, 0xa5c96ce0U, 0xb8922afdU, + 0x50401015U, 0xd0e03095U, 0xb5dd68f0U, 0x4ade940fU, + 0x07c1c642U, 0x54451111U, 0x4d1b5608U, 0x094e474cU, + 0x2aa68c6fU, 0x1bdac15eU, 0xc8fe368dU, 0x1d5f4258U, + 0x65395c20U, 0x8cab27c9U, 0x5c4f1319U, 0xcb3ef58eU, + 0xd665b393U, 0x4791d602U, 0x77adda32U, 0x2ea38d6bU, + 0xff07f8baU, 0xaa06acefU, 0x7ee7993bU, 0x1fdfc05aU, + 0x55055010U, 0x4b9ed50eU, 0xb49d29f1U, 0x8224a6c7U, + 0xda6ab09fU, 0x8b6ee5ceU, 0x9f7fe0daU, 0x6fb3dc2aU, + 0xb358ebf6U, 0xd1a07194U, 0x00040445U, 0xd260b297U, + 0xd725f292U, 0xee53bdabU, 0x216c4d64U, 0xc671b783U, + 0x3ab2887fU, 0x84a125c1U, 0x3c370b79U, 0x01444544U, + 0xe25cbea7U, 0x1a9a805fU, 0x9cbf23d9U, 0x94b521d1U, + 0x8364e7c6U, 0x66f99f23U, 0x9230a2d7U, 0xdb2af19eU, + 0x202c0c65U, 0x8f6be4caU, 0xdf2ff09aU, 0xecd33fa9U, + 0x5ecf911bU, 0xcdbb7688U, 0x7fa7d83aU, 0xd5a57090U, + 0x5785d212U, 0xf0c838b5U, 0xd8ea329dU, 0xfa42b8bfU, + 0x607c1c25U, 0x195a435cU, 0x6d335e28U, 0xe9967facU, + 0x03c4c746U, 0x3bf2c97eU, 0x88ae26cdU, 0x41145504U, + 0x2fe3cc6aU, 0xa34cefe6U, 0x6ef39d2bU, 0xe8d63eadU, + 0x584a121dU, 0xab46edeeU, 0xfd877ab8U, 0x9dff62d8U, + 0xe19c7da4U, 0xe5997ca0U, 0x39724b7cU, 0x11504154U, + 0x62fc9e27U, 0x38320a7dU, 0xea56bcafU, 0x1e9f815bU, + 0xba12a8ffU, 0x23eccf66U, 0xa609afe3U, 0xa9c66fecU, + 0x10100055U, 0x33f8cb76U, 0x25694c60U, 0x51005114U, + 0x28260e6dU, 0x14150151U, 0x3d774a78U, 0x37fdca72U, + 0x7c671b39U, 0x5380d316U, 0x90b020d5U, 0x76ed9b33U, + 0xc274b687U, 0x63bcdf26U, 0xb9d26bfcU, 0xa20caee7U, + 0xe0dc3ca5U, 0x85e164c0U, 0x17d5c252U, 0x1c1f0359U, + 0xb61dabf3U, 0xc334f786U, 0x8621a7c3U, 0x9635a3d3U, + 0x72e89a37U, 0xf18879b4U, 0x0a8e844fU, 0x7d275a38U, + 0x64791d21U, 0x0e8b854bU, 0x89ee67ccU, 0xadc36ee8U, + 0xc1b47584U, 0xb218aaf7U, 0x9370e3d6U, 0x70681835U, + 0x4394d706U, 0xed937ea8U, 0x4f9bd40aU, 0x46d19703U, + 0x343d0971U, 0x9775e2d2U, 0xa1cc6de4U, 0xe719fea2U, + 0xbc972bf9U, 0x27e9ce62U, 0x613c5d24U, 0xd4e53191U, + 0xb1d869f4U, 0xef13fcaaU, 0x29664f6cU, 0xac832fe9U, + 0x0bcec54eU, 0x7ba2d93eU, 0xb09828f5U, 0x752d5830U, + 0x049d9917U, 0x1dc3de0eU, 0xf85ea6ebU, 0xa415b1b7U, + 0x6cef837fU, 0xd876aecbU, 0xabda71b8U, 0x8178f992U, + 0x075d5a14U, 0x857df896U, 0x0f57581cU, 0x54d98d47U, + 0xff9b64ecU, 0xb004b4a3U, 0xef8f60fcU, 0x4b024958U, + 0xf39467e0U, 0xc2e82ad1U, 0x35e1d426U, 0x86bd3b95U, + 0xf79166e4U, 0xa555f0b6U, 0x4f07485cU, 0x50dc8c43U, + 0xf511e4e6U, 0x4e47095dU, 0x134c5f00U, 0xc7ad6ad4U, + 0x7a7e0469U, 0x458dc856U, 0x470d4a54U, 0x39eed72aU, + 0x2dffd23eU, 0x56590f45U, 0x1e031d0dU, 0x8c37bb9fU, + 0x19c6df0aU, 0xe040a0f3U, 0x3debd62eU, 0xb68137a5U, + 0x93ec7f80U, 0x0e17191dU, 0x73344760U, 0x525c0e41U, + 0xe84aa2fbU, 0x60e08073U, 0xed0fe2feU, 0xd6f92fc5U, + 0xcc67abdfU, 0x916cfd82U, 0x2f7f503cU, 0xf91ee7eaU, + 0x78fe866bU, 0x7f3b446cU, 0xfc5ba7efU, 0x09d2db1aU, + 0x5d93ce4eU, 0x20b09033U, 0x0dd7da1eU, 0xb401b5a7U, + 0x8ab23899U, 0x61a0c172U, 0xa3d073b0U, 0xc52de8d6U, + 0x42480a51U, 0x43084b50U, 0xc128e9d2U, 0xac1fb3bfU, + 0x902cbc83U, 0x92ac3e81U, 0x03585b10U, 0xb541f4a6U, + 0x519ccd42U, 0x3a2e1429U, 0xafdf70bcU, 0x3b6e5528U, + 0xc46da9d7U, 0x4982cb5aU, 0x62600271U, 0xfd1be6eeU, + 0xfedb25edU, 0xf2d426e1U, 0x5996cf4aU, 0x9569fc86U, + 0x9aa63c89U, 0xcee729ddU, 0x34a19527U, 0x71b4c562U, + 0xbc0bb7afU, 0xf054a4e3U, 0x63204370U, 0x72740661U, + 0x9ea33d8dU, 0x061d1b15U, 0x29fad33aU, 0x8bf27998U, + 0x27755234U, 0xcfa768dcU, 0x67254274U, 0x26351335U, + 0xd2fc2ec1U, 0x3e2b152dU, 0x18869e0bU, 0xd539ecc6U, + 0xcba269d8U, 0xd7b96ec4U, 0xae9f31bdU, 0xb3c477a0U, + 0x5b164d48U, 0xdbb66dc8U, 0xbe8b35adU, 0x4188c952U, + 0x0c979b1fU, 0x5f134c4cU, 0x464d0b55U, 0x02181a11U, + 0x21f0d132U, 0x108c9c03U, 0xc3a86bd0U, 0x16091f05U, + 0x6e6f017dU, 0x87fd7a94U, 0x57194e44U, 0xc068a8d3U, + 0xdd33eeceU, 0x4cc78b5fU, 0x7cfb876fU, 0x25f5d036U, + 0xf451a5e7U, 0xa150f1b2U, 0x75b1c466U, 0x14899d07U, + 0x5e530d4dU, 0x40c88853U, 0xbfcb74acU, 0x8972fb9aU, + 0xd13cedc2U, 0x8038b893U, 0x9429bd87U, 0x64e58177U, + 0xb80eb6abU, 0xdaf62cc9U, 0x0b525918U, 0xd936efcaU, + 0xdc73afcfU, 0xe505e0f6U, 0x2a3a1039U, 0xcd27eadeU, + 0x31e4d522U, 0x8ff7789cU, 0x37615624U, 0x0a121819U, + 0xe90ae3faU, 0x11ccdd02U, 0x97e97e84U, 0x9fe37c8cU, + 0x8832ba9bU, 0x6dafc27eU, 0x9966ff8aU, 0xd07cacc3U, + 0x2b7a5138U, 0x843db997U, 0xd479adc7U, 0xe78562f4U, + 0x5599cc46U, 0xc6ed2bd5U, 0x74f18567U, 0xdef32dcdU, + 0x5cd38f4fU, 0xfb9e65e8U, 0xd3bc6fc0U, 0xf114e5e2U, + 0x6b2a4178U, 0x120c1e01U, 0x66650375U, 0xe2c022f1U, + 0x08929a1bU, 0x30a49423U, 0x83f87b90U, 0x4a420859U, + 0x24b59137U, 0xa81ab2bbU, 0x65a5c076U, 0xe38063f0U, + 0x531c4f40U, 0xa010b0b3U, 0xf6d127e5U, 0x96a93f85U, + 0xeaca20f9U, 0xeecf21fdU, 0x32241621U, 0x1a061c09U, + 0x69aac37aU, 0x33645720U, 0xe100e1f2U, 0x15c9dc06U, + 0xb144f5a2U, 0x28ba923bU, 0xad5ff2beU, 0xa29032b1U, + 0x1b465d08U, 0x38ae962bU, 0x2e3f113dU, 0x5a560c49U, + 0x23705330U, 0x1f435c0cU, 0x36211725U, 0x3cab972fU, + 0x77314664U, 0x58d68e4bU, 0x9be67d88U, 0x7dbbc66eU, + 0xc922ebdaU, 0x68ea827bU, 0xb28436a1U, 0xa95af3baU, + 0xeb8a61f8U, 0x8eb7399dU, 0x1c839f0fU, 0x17495e04U, + 0xbd4bf6aeU, 0xc862aadbU, 0x8d77fa9eU, 0x9d63fe8eU, + 0x79bec76aU, 0xfade24e9U, 0x01d8d912U, 0x76710765U, + 0x6f2f407cU, 0x05ddd816U, 0x82b83a91U, 0xa69533b5U, + 0xcae228d9U, 0xb94ef7aaU, 0x9826be8bU, 0x7b3e4568U, + 0x48c28a5bU, 0xe6c523f5U, 0x44cd8957U, 0x4d87ca5eU, + 0x3f6b542cU, 0x9c23bf8fU, 0xaa9a30b9U, 0xec4fa3ffU, + 0xb7c176a4U, 0x2cbf933fU, 0x6a6a0079U, 0xdfb36cccU, + 0xba8e34a9U, 0xe445a1f7U, 0x22301231U, 0xa7d572b4U, + 0x00989813U, 0x70f48463U, 0xbbce75a8U, 0x7e7b056dU, + 0xe5a84dc3U, 0xfcf60adaU, 0x196b723fU, 0x45206563U, + 0x8dda57abU, 0x39437a1fU, 0x4aefa56cU, 0x604d2d46U, + 0xe6688ec0U, 0x64482c42U, 0xee628cc8U, 0xb5ec5993U, + 0x1eaeb038U, 0x51316077U, 0x0ebab428U, 0xaa379d8cU, + 0x12a1b334U, 0x23ddfe05U, 0xd4d400f2U, 0x6788ef41U, + 0x16a4b230U, 0x44602462U, 0xae329c88U, 0xb1e95897U, + 0x14243032U, 0xaf72dd89U, 0xf2798bd4U, 0x2698be00U, + 0x9b4bd0bdU, 0xa4b81c82U, 0xa6389e80U, 0xd8db03feU, + 0xccca06eaU, 0xb76cdb91U, 0xff36c9d9U, 0x6d026f4bU, + 0xf8f30bdeU, 0x01757427U, 0xdcde02faU, 0x57b4e371U, + 0x72d9ab54U, 0xef22cdc9U, 0x920193b4U, 0xb369da95U, + 0x097f762fU, 0x81d554a7U, 0x0c3a362aU, 0x37ccfb11U, + 0x2d527f0bU, 0x70592956U, 0xce4a84e8U, 0x182b333eU, + 0x99cb52bfU, 0x9e0e90b8U, 0x1d6e733bU, 0xe8e70fceU, + 0xbca61a9aU, 0xc18544e7U, 0xece20ecaU, 0x55346173U, + 0x6b87ec4dU, 0x809515a6U, 0x42e5a764U, 0x24183c02U, + 0xa37dde85U, 0xa23d9f84U, 0x201d3d06U, 0x4d2a676bU, + 0x71196857U, 0x7399ea55U, 0xe26d8fc4U, 0x54742072U, + 0xb0a91996U, 0xdb1bc0fdU, 0x4eeaa468U, 0xda5b81fcU, + 0x25587d03U, 0xa8b71f8eU, 0x8355d6a5U, 0x1c2e323aU, + 0x1feef139U, 0x13e1f235U, 0xb8a31b9eU, 0x745c2852U, + 0x7b93e85dU, 0x2fd2fd09U, 0xd59441f3U, 0x908111b6U, + 0x5d3e637bU, 0x11617037U, 0x821597a4U, 0x9341d2b5U, + 0x7f96e959U, 0xe728cfc1U, 0xc8cf07eeU, 0x6ac7ad4cU, + 0xc64086e0U, 0x2e92bc08U, 0x861096a0U, 0xc700c7e1U, + 0x33c9fa15U, 0xdf1ec1f9U, 0xf9b34adfU, 0x340c3812U, + 0x2a97bd0cU, 0x368cba10U, 0x4faae569U, 0x52f1a374U, + 0xba23999cU, 0x3a83b91cU, 0x5fbee179U, 0xa0bd1d86U, + 0xeda24fcbU, 0xbe269898U, 0xa778df81U, 0xe32dcec5U, + 0xc0c505e6U, 0xf1b948d7U, 0x229dbf04U, 0xf73ccbd1U, + 0x8f5ad5a9U, 0x66c8ae40U, 0xb62c9a90U, 0x215d7c07U, + 0x3c063a1aU, 0xadf25f8bU, 0x9dce53bbU, 0xc4c004e2U, + 0x15647133U, 0x40652566U, 0x948410b2U, 0xf5bc49d3U, + 0xbf66d999U, 0xa1fd5c87U, 0x5efea078U, 0x68472f4eU, + 0x30093916U, 0x610d6c47U, 0x751c6953U, 0x85d055a3U, + 0x593b627fU, 0x3bc3f81dU, 0xea678dccU, 0x38033b1eU, + 0x3d467b1bU, 0x04303422U, 0xcb0fc4edU, 0x2c123e0aU, + 0xd0d101f6U, 0x6ec2ac48U, 0xd65482f0U, 0xeb27cccdU, + 0x083f372eU, 0xf0f909d6U, 0x76dcaa50U, 0x7ed6a858U, + 0x69076e4fU, 0x8c9a16aaU, 0x78532b5eU, 0x31497817U, + 0xca4f85ecU, 0x65086d43U, 0x354c7913U, 0x06b0b620U, + 0xb4ac1892U, 0x27d8ff01U, 0x95c451b3U, 0x3fc6f919U, + 0xbde65b9bU, 0x1aabb13cU, 0x3289bb14U, 0x10213136U, + 0x8a1f95acU, 0xf339cad5U, 0x8750d7a1U, 0x03f5f625U, + 0xe9a74ecfU, 0xd19140f7U, 0x62cdaf44U, 0xab77dc8dU, + 0xc58045e3U, 0x492f666fU, 0x849014a2U, 0x02b5b724U, + 0xb2299b94U, 0x41256467U, 0x17e4f331U, 0x779ceb51U, + 0x0bfff42dU, 0x0ffaf529U, 0xd311c2f5U, 0xfb33c8ddU, + 0x889f17aeU, 0xd25183f4U, 0x00353526U, 0xf4fc08d2U, + 0x50712176U, 0xc98f46efU, 0x4c6a266aU, 0x43a5e665U, + 0xfa7389dcU, 0xd99b42ffU, 0xcf0ac5e9U, 0xbb63d89dU, + 0xc24587e4U, 0xfe7688d8U, 0xd714c3f1U, 0xdd9e43fbU, + 0x960492b0U, 0xb9e35a9fU, 0x7ad3a95cU, 0x9c8e12baU, + 0x28173f0eU, 0x89df56afU, 0x53b1e275U, 0x486f276eU, + 0x0abfb52cU, 0x6f82ed49U, 0xfdb64bdbU, 0xf67c8ad0U, + 0x5c7e227aU, 0x29577e0fU, 0x6c422e4aU, 0x7c562a5aU, + 0x988b13beU, 0x1bebf03dU, 0xe0ed0dc6U, 0x9744d3b1U, + 0x8e1a94a8U, 0xe4e80cc2U, 0x638dee45U, 0x47a0e761U, + 0x2bd7fc0dU, 0x587b237eU, 0x79136a5fU, 0x9a0b91bcU, + 0xa9f75e8fU, 0x07f0f721U, 0xa5f85d83U, 0xacb21e8aU, + 0xde5e80f8U, 0x7d166b5bU, 0x4bafe46dU, 0x0d7a772bU, + 0x56f4a270U, 0xcd8a47ebU, 0x8b5fd4adU, 0x3e86b818U, + 0x5bbbe07dU, 0x05707523U, 0xc305c6e5U, 0x46e0a660U, + 0xe1ad4cc7U, 0x91c150b7U, 0x5afba17cU, 0x9f4ed1b9U, + 0x36c6f07eU, 0x2f98b767U, 0xca05cf82U, 0x964ed8deU, + 0x5eb4ea16U, 0xea2dc7a2U, 0x998118d1U, 0xb32390fbU, + 0x3506337dU, 0xb72691ffU, 0x3d0c3175U, 0x6682e42eU, + 0xcdc00d85U, 0x825fddcaU, 0xddd40995U, 0x79592031U, + 0xc1cf0e89U, 0xf0b343b8U, 0x07babd4fU, 0xb4e652fcU, + 0xc5ca0f8dU, 0x970e99dfU, 0x7d5c2135U, 0x6287e52aU, + 0xc74a8d8fU, 0x7c1c6034U, 0x21173669U, 0xf5f603bdU, + 0x48256d00U, 0x77d6a13fU, 0x7556233dU, 0x0bb5be43U, + 0x1fa4bb57U, 0x6402662cU, 0x2c587464U, 0xbe6cd2f6U, + 0x2b9db663U, 0xd21bc99aU, 0x0fb0bf47U, 0x84da5eccU, + 0xa1b716e9U, 0x3c4c7074U, 0x416f2e09U, 0x60076728U, + 0xda11cb92U, 0x52bbe91aU, 0xdf548b97U, 0xe4a246acU, + 0xfe3cc2b6U, 0xa33794ebU, 0x1d243955U, 0xcb458e83U, + 0x4aa5ef02U, 0x4d602d05U, 0xce00ce86U, 0x3b89b273U, + 0x6fc8a727U, 0x12ebf95aU, 0x3f8cb377U, 0x865adcceU, + 0xb8e951f0U, 0x53fba81bU, 0x918b1ad9U, 0xf77681bfU, + 0x70136338U, 0x71532239U, 0xf37380bbU, 0x9e44dad6U, + 0xa277d5eaU, 0xa0f757e8U, 0x31033279U, 0x871a9dcfU, + 0x63c7a42bU, 0x08757d40U, 0x9d8419d5U, 0x09353c41U, + 0xf636c0beU, 0x7bd9a233U, 0x503b6b18U, 0xcf408f87U, + 0xcc804c84U, 0xc08f4f88U, 0x6bcda623U, 0xa73295efU, + 0xa8fd55e0U, 0xfcbc40b4U, 0x06fafc4eU, 0x43efac0bU, + 0x8e50dec6U, 0xc20fcd8aU, 0x517b2a19U, 0x402f6f08U, + 0xacf854e4U, 0x3446727cU, 0x1ba1ba53U, 0xb9a910f1U, + 0x152e3b5dU, 0xfdfc01b5U, 0x557e2b1dU, 0x146e7a5cU, + 0xe0a747a8U, 0x0c707c44U, 0x2addf762U, 0xe76285afU, + 0xf9f900b1U, 0xe5e207adU, 0x9cc458d4U, 0x819f1ec9U, + 0x694d2421U, 0xe9ed04a1U, 0x8cd05cc4U, 0x73d3a03bU, + 0x3eccf276U, 0x6d482525U, 0x7416623cU, 0x30437378U, + 0x13abb85bU, 0x22d7f56aU, 0xf1f302b9U, 0x2452766cU, + 0x5c346814U, 0xb5a613fdU, 0x6542272dU, 0xf233c1baU, + 0xef6887a7U, 0x7e9ce236U, 0x4ea0ee06U, 0x17aeb95fU, + 0xc60acc8eU, 0x930b98dbU, 0x47eaad0fU, 0x26d2f46eU, + 0x6c086424U, 0x7293e13aU, 0x8d901dc5U, 0xbb2992f3U, + 0xe36784abU, 0xb263d1faU, 0xa672d4eeU, 0x56bee81eU, + 0x8a55dfc2U, 0xe8ad45a0U, 0x39093071U, 0xeb6d86a3U, + 0xee28c6a6U, 0xd75e899fU, 0x18617950U, 0xff7c83b7U, + 0x03bfbc4bU, 0xbdac11f5U, 0x053a3f4dU, 0x38497170U, + 0xdb518a93U, 0x2397b46bU, 0xa5b217edU, 0xadb815e5U, + 0xba69d3f2U, 0x5ff4ab17U, 0xab3d96e3U, 0xe227c5aaU, + 0x19213851U, 0xb666d0feU, 0xe622c4aeU, 0xd5de0b9dU, + 0x67c2a52fU, 0xf4b642bcU, 0x46aaec0eU, 0xeca844a4U, + 0x6e88e626U, 0xc9c50c81U, 0xe1e706a9U, 0xc34f8c8bU, + 0x59712811U, 0x20577768U, 0x543e6a1cU, 0xd09b4b98U, + 0x3ac9f372U, 0x02fffd4aU, 0xb1a312f9U, 0x78196130U, + 0x16eef85eU, 0x9a41dbd2U, 0x57fea91fU, 0xd1db0a99U, + 0x61472629U, 0x924bd9daU, 0xc48a4e8cU, 0xa4f256ecU, + 0xd8914990U, 0xdc944894U, 0x007f7f48U, 0x285d7560U, + 0x5bf1aa13U, 0x013f3e49U, 0xd35b889bU, 0x2792b56fU, + 0x831f9ccbU, 0x1ae1fb52U, 0x9f049bd7U, 0x90cb5bd8U, + 0x291d3461U, 0x0af5ff42U, 0x1c647854U, 0x680d6520U, + 0x112b3a59U, 0x2d183565U, 0x047a7e4cU, 0x0ef0fe46U, + 0x456a2f0dU, 0x6a8de722U, 0xa9bd14e1U, 0x4fe0af07U, + 0xfb7982b3U, 0x5ab1eb12U, 0x80df5fc8U, 0x9b019ad3U, + 0xd9d10891U, 0xbcec50f4U, 0x2ed8f666U, 0x2512376dU, + 0x8f109fc7U, 0xfa39c3b2U, 0xbf2c93f7U, 0xaf3897e7U, + 0x4be5ae03U, 0xc8854d80U, 0x3383b07bU, 0x442a6e0cU, + 0x5d742915U, 0x3786b17fU, 0xb0e353f8U, 0x94ce5adcU, + 0xf8b941b0U, 0x8b159ec3U, 0xaa7dd7e2U, 0x49652c01U, + 0x7a99e332U, 0xd49e4a9cU, 0x7696e03eU, 0x7fdca337U, + 0x0d303d45U, 0xae78d6e6U, 0x98c159d0U, 0xde14ca96U, + 0x859a1fcdU, 0x1ee4fa56U, 0x58316910U, 0xede805a5U, + 0x88d55dc0U, 0xd61ec89eU, 0x106b7b58U, 0x958e1bddU, + 0x32c3f17aU, 0x42afed0aU, 0x89951cc1U, 0x4c206c04U, + 0xc50acf41U, 0xdc548858U, 0x39c9f0bdU, 0x6582e7e1U, + 0xad78d529U, 0x19e1f89dU, 0x6a4d27eeU, 0x40efafc4U, + 0xc6ca0c42U, 0x44eaaec0U, 0xcec00e4aU, 0x954edb11U, + 0x3e0c32baU, 0x7193e2f5U, 0x2e1836aaU, 0x8a951f0eU, + 0x320331b6U, 0x037f7c87U, 0xf4768270U, 0x472a6dc3U, + 0x360630b2U, 0x64c2a6e0U, 0x8e901e0aU, 0x914bda15U, + 0x3486b2b0U, 0x8fd05f0bU, 0xd2db0956U, 0x063a3c82U, + 0xbbe9523fU, 0x841a9e00U, 0x869a1c02U, 0xf879817cU, + 0xec688468U, 0x97ce5913U, 0xdf944b5bU, 0x4da0edc9U, + 0xd851895cU, 0x21d7f6a5U, 0xfc7c8078U, 0x771661f3U, + 0x527b29d6U, 0xcf804f4bU, 0xb2a31136U, 0x93cb5817U, + 0x29ddf4adU, 0xa177d625U, 0x2c98b4a8U, 0x176e7993U, + 0x0df0fd89U, 0x50fbabd4U, 0xeee8066aU, 0x3889b1bcU, + 0xb969d03dU, 0xbeac123aU, 0x3dccf1b9U, 0xc8458d4cU, + 0x9c049818U, 0xe127c665U, 0xcc408c48U, 0x7596e3f1U, + 0x4b256ecfU, 0xa0379724U, 0x624725e6U, 0x04babe80U, + 0x83df5c07U, 0x829f1d06U, 0x00bfbf84U, 0x6d88e5e9U, + 0x51bbead5U, 0x533b68d7U, 0xc2cf0d46U, 0x74d6a2f0U, + 0x900b9b14U, 0xfbb9427fU, 0x6e4826eaU, 0xfaf9037eU, + 0x05faff81U, 0x88159d0cU, 0xa3f75427U, 0x3c8cb0b8U, + 0x3f4c73bbU, 0x334370b7U, 0x9801991cU, 0x54feaad0U, + 0x5b316adfU, 0x0f707f8bU, 0xf536c371U, 0xb0239334U, + 0x7d9ce1f9U, 0x31c3f2b5U, 0xa2b71526U, 0xb3e35037U, + 0x5f346bdbU, 0xc78a4d43U, 0xe86d856cU, 0x4a652fceU, + 0xe6e20462U, 0x0e303e8aU, 0xa6b21422U, 0xe7a24563U, + 0x136b7897U, 0xffbc437bU, 0xd911c85dU, 0x14aeba90U, + 0x0a353f8eU, 0x162e3892U, 0x6f0867ebU, 0x725321f6U, + 0x9a811b1eU, 0x1a213b9eU, 0x7f1c63fbU, 0x801f9f04U, + 0xcd00cd49U, 0x9e841a1aU, 0x87da5d03U, 0xc38f4c47U, + 0xe0678764U, 0xd11bca55U, 0x023f3d86U, 0xd79e4953U, + 0xaff8572bU, 0x466a2cc2U, 0x968e1812U, 0x01fffe85U, + 0x1ca4b898U, 0x8d50dd09U, 0xbd6cd139U, 0xe4628660U, + 0x35c6f3b1U, 0x60c7a7e4U, 0xb4269230U, 0xd51ecb51U, + 0x9fc45b1bU, 0x815fde05U, 0x7e5c22faU, 0x48e5adccU, + 0x10abbb94U, 0x41afeec5U, 0x55beebd1U, 0xa572d721U, + 0x7999e0fdU, 0x1b617a9fU, 0xcac50f4eU, 0x18a1b99cU, + 0x1de4f999U, 0x2492b6a0U, 0xebad466fU, 0x0cb0bc88U, + 0xf0738374U, 0x4e602ecaU, 0xf6f60072U, 0xcb854e4fU, + 0x289db5acU, 0xd05b8b54U, 0x567e28d2U, 0x5e742adaU, + 0x49a5eccdU, 0xac389428U, 0x58f1a9dcU, 0x11ebfa95U, + 0xeaed076eU, 0x45aaefc1U, 0x15eefb91U, 0x261234a2U, + 0x940e9a10U, 0x077a7d83U, 0xb566d331U, 0x1f647b9bU, + 0x9d44d919U, 0x3a0933beU, 0x122b3996U, 0x3083b3b4U, + 0xaabd172eU, 0xd39b4857U, 0xa7f25523U, 0x235774a7U, + 0xc905cc4dU, 0xf133c275U, 0x426f2dc6U, 0x8bd55e0fU, + 0xe522c761U, 0x698de4edU, 0xa4329620U, 0x221735a6U, + 0x928b1916U, 0x6187e6e5U, 0x374671b3U, 0x573e69d3U, + 0x2b5d76afU, 0x2f5877abU, 0xf3b34077U, 0xdb914a5fU, + 0xa83d952cU, 0xf2f30176U, 0x2097b7a4U, 0xd45e8a50U, + 0x70d3a3f4U, 0xe92dc46dU, 0x6cc8a4e8U, 0x630764e7U, + 0xdad10b5eU, 0xf939c07dU, 0xefa8476bU, 0x9bc15a1fU, + 0xe2e70566U, 0xded40a5aU, 0xf7b64173U, 0xfd3cc179U, + 0xb6a61032U, 0x9941d81dU, 0x5a712bdeU, 0xbc2c9038U, + 0x08b5bd8cU, 0xa97dd42dU, 0x731360f7U, 0x68cda5ecU, + 0x2a1d37aeU, 0x4f206fcbU, 0xdd14c959U, 0xd6de0852U, + 0x7cdca0f8U, 0x09f5fc8dU, 0x4ce0acc8U, 0x5cf4a8d8U, + 0xb829913cU, 0x3b4972bfU, 0xc04f8f44U, 0xb7e65133U, + 0xaeb8162aU, 0xc44a8e40U, 0x432f6cc7U, 0x670265e3U, + 0x0b757e8fU, 0x78d9a1fcU, 0x59b1e8ddU, 0xbaa9133eU, + 0x8955dc0dU, 0x275275a3U, 0x855adf01U, 0x8c109c08U, + 0xfefc027aU, 0x5db4e9d9U, 0x6b0d66efU, 0x2dd8f5a9U, + 0x765620f2U, 0xed28c569U, 0xabfd562fU, 0x1e243a9aU, + 0x7b1962ffU, 0x25d2f7a1U, 0xe3a74467U, 0x664224e2U, + 0xc10fce45U, 0xb163d235U, 0x7a5923feU, 0xbfec533bU, + 0x4588cd43U, 0x5cd68a5aU, 0xb94bf2bfU, 0xe500e5e3U, + 0x2dfad72bU, 0x9963fa9fU, 0xeacf25ecU, 0xc06dadc6U, + 0x46480e40U, 0xc468acc2U, 0x4e420c48U, 0x15ccd913U, + 0xbe8e30b8U, 0xf111e0f7U, 0xae9a34a8U, 0x0a171d0cU, + 0xb28133b4U, 0x83fd7e85U, 0x74f48072U, 0xc7a86fc1U, + 0xb68432b0U, 0xe440a4e2U, 0x0e121c08U, 0x11c9d817U, + 0xb404b0b2U, 0x0f525d09U, 0x52590b54U, 0x86b83e80U, + 0x3b6b503dU, 0x04989c02U, 0x06181e00U, 0x78fb837eU, + 0x6cea866aU, 0x174c5b11U, 0x5f164959U, 0xcd22efcbU, + 0x58d38b5eU, 0xa155f4a7U, 0x7cfe827aU, 0xf79463f1U, + 0xd2f92bd4U, 0x4f024d49U, 0x32211334U, 0x13495a15U, + 0xa95ff6afU, 0x21f5d427U, 0xac1ab6aaU, 0x97ec7b91U, + 0x8d72ff8bU, 0xd079a9d6U, 0x6e6a0468U, 0xb80bb3beU, + 0x39ebd23fU, 0x3e2e1038U, 0xbd4ef3bbU, 0x48c78f4eU, + 0x1c869a1aU, 0x61a5c467U, 0x4cc28e4aU, 0xf514e1f3U, + 0xcba76ccdU, 0x20b59526U, 0xe2c527e4U, 0x8438bc82U, + 0x035d5e05U, 0x021d1f04U, 0x803dbd86U, 0xed0ae7ebU, + 0xd139e8d7U, 0xd3b96ad5U, 0x424d0f44U, 0xf454a0f2U, + 0x10899916U, 0x7b3b407dU, 0xeeca24e8U, 0x7a7b017cU, + 0x8578fd83U, 0x08979f0eU, 0x23755625U, 0xbc0eb2baU, + 0xbfce71b9U, 0xb3c172b5U, 0x18839b1eU, 0xd47ca8d2U, + 0xdbb368ddU, 0x8ff27d89U, 0x75b4c173U, 0x30a19136U, + 0xfd1ee3fbU, 0xb141f0b7U, 0x22351724U, 0x33615235U, + 0xdfb669d9U, 0x47084f41U, 0x68ef876eU, 0xcae72dccU, + 0x66600660U, 0x8eb23c88U, 0x26301620U, 0x67204761U, + 0x93e97a95U, 0x7f3e4179U, 0x5993ca5fU, 0x942cb892U, + 0x8ab73d8cU, 0x96ac3a90U, 0xef8a65e9U, 0xf2d123f4U, + 0x1a03191cU, 0x9aa3399cU, 0xff9e61f9U, 0x009d9d06U, + 0x4d82cf4bU, 0x1e061818U, 0x07585f01U, 0x430d4e45U, + 0x60e58566U, 0x5199c857U, 0x82bd3f84U, 0x571c4b51U, + 0x2f7a5529U, 0xc6e82ec0U, 0x160c1a10U, 0x817dfc87U, + 0x9c26ba9aU, 0x0dd2df0bU, 0x3deed33bU, 0x64e08462U, + 0xb544f1b3U, 0xe045a5e6U, 0x34a49032U, 0x559cc953U, + 0x1f465919U, 0x01dddc07U, 0xfede20f8U, 0xc867afceU, + 0x9029b996U, 0xc12decc7U, 0xd53ce9d3U, 0x25f0d523U, + 0xf91be2ffU, 0x9be3789dU, 0x4a470d4cU, 0x9823bb9eU, + 0x9d66fb9bU, 0xa410b4a2U, 0x6b2f446dU, 0x8c32be8aU, + 0x70f18176U, 0xcee22cc8U, 0x76740270U, 0x4b074c4dU, + 0xa81fb7aeU, 0x50d98956U, 0xd6fc2ad0U, 0xdef628d8U, + 0xc927eecfU, 0x2cba962aU, 0xd873abdeU, 0x9169f897U, + 0x6a6f056cU, 0xc528edc3U, 0x956cf993U, 0xa69036a0U, + 0x148c9812U, 0x87f87f81U, 0x35e4d133U, 0x9fe67999U, + 0x1dc6db1bU, 0xba8b31bcU, 0x92a93b94U, 0xb001b1b6U, + 0x2a3f152cU, 0x53194a55U, 0x27705721U, 0xa3d576a5U, + 0x4987ce4fU, 0x71b1c077U, 0xc2ed2fc4U, 0x0b575c0dU, + 0x65a0c563U, 0xe90fe6efU, 0x24b09422U, 0xa29537a4U, + 0x12091b14U, 0xe105e4e7U, 0xb7c473b1U, 0xd7bc6bd1U, + 0xabdf74adU, 0xafda75a9U, 0x73314275U, 0x5b13485dU, + 0x28bf972eU, 0x72710374U, 0xa015b5a6U, 0x54dc8852U, + 0xf051a1f6U, 0x69afc66fU, 0xec4aa6eaU, 0xe38566e5U, + 0x5a53095cU, 0x79bbc27fU, 0x6f2a4569U, 0x1b43581dU, + 0x62650764U, 0x5e560858U, 0x77344371U, 0x7dbec37bU, + 0x36241230U, 0x19c3da1fU, 0xdaf329dcU, 0x3cae923aU, + 0x8837bf8eU, 0x29ffd62fU, 0xf39162f5U, 0xe84fa7eeU, + 0xaa9f35acU, 0xcfa26dc9U, 0x5d96cb5bU, 0x565c0a50U, + 0xfc5ea2faU, 0x8977fe8fU, 0xcc62aecaU, 0xdc76aadaU, + 0x38ab933eU, 0xbbcb70bdU, 0x40cd8d46U, 0x37645331U, + 0x2e3a1428U, 0x44c88c42U, 0xc3ad6ec5U, 0xe78067e1U, + 0x8bf77c8dU, 0xf85ba3feU, 0xd933eadfU, 0x3a2b113cU, + 0x09d7de0fU, 0xa7d077a1U, 0x05d8dd03U, 0x0c929e0aU, + 0x7e7e0078U, 0xdd36ebdbU, 0xeb8f64edU, 0xad5af7abU, + 0xf6d422f0U, 0x6daac76bU, 0x2b7f542dU, 0x9ea63898U, + 0xfb9b60fdU, 0xa550f5a3U, 0x63254665U, 0xe6c026e0U, + 0x418dcc47U, 0x31e1d037U, 0xfadb21fcU, 0x3f6e5139U, + 0xa615b33dU, 0xbf4bf424U, 0x5ad68cc1U, 0x069d9b9dU, + 0xce67a955U, 0x7afe84e1U, 0x09525b92U, 0x23f0d3b8U, + 0xa5d5703eU, 0x27f5d2bcU, 0xaddf7236U, 0xf651a76dU, + 0x5d134ec6U, 0x128c9e89U, 0x4d074ad6U, 0xe98a6372U, + 0x511c4dcaU, 0x606000fbU, 0x9769fe0cU, 0x243511bfU, + 0x55194cceU, 0x07ddda9cU, 0xed8f6276U, 0xf254a669U, + 0x5799ceccU, 0xeccf2377U, 0xb1c4752aU, 0x652540feU, + 0xd8f62e43U, 0xe705e27cU, 0xe585607eU, 0x9b66fd00U, + 0x8f77f814U, 0xf4d1256fU, 0xbc8b3727U, 0x2ebf91b5U, + 0xbb4ef520U, 0x42c88ad9U, 0x9f63fc04U, 0x14091d8fU, + 0x316455aaU, 0xac9f3337U, 0xd1bc6d4aU, 0xf0d4246bU, + 0x4ac288d1U, 0xc268aa59U, 0x4f87c8d4U, 0x747105efU, + 0x6eef81f5U, 0x33e4d7a8U, 0x8df77a16U, 0x5b96cdc0U, + 0xda76ac41U, 0xddb36e46U, 0x5ed38dc5U, 0xab5af130U, + 0xff1be464U, 0x8238ba19U, 0xaf5ff034U, 0x16899f8dU, + 0x283a12b3U, 0xc328eb58U, 0x0158599aU, 0x67a5c2fcU, + 0xe0c0207bU, 0xe180617aU, 0x63a0c3f8U, 0x0e979995U, + 0x32a496a9U, 0x302414abU, 0xa1d0713aU, 0x17c9de8cU, + 0xf314e768U, 0x98a63e03U, 0x0d575a96U, 0x99e67f02U, + 0x66e583fdU, 0xeb0ae170U, 0xc0e8285bU, 0x5f93ccc4U, + 0x5c530fc7U, 0x505c0ccbU, 0xfb1ee560U, 0x37e1d6acU, + 0x382e16a3U, 0x6c6f03f7U, 0x9629bf0dU, 0xd33cef48U, + 0x1e839d85U, 0x52dc8ec9U, 0xc1a8695aU, 0xd0fc2c4bU, + 0x3c2b17a7U, 0xa495313fU, 0x8b72f910U, 0x297a53b2U, + 0x85fd781eU, 0x6d2f42f6U, 0xc5ad685eU, 0x84bd391fU, + 0x707404ebU, 0x9ca33f07U, 0xba0eb421U, 0x77b1c6ecU, + 0x692a43f2U, 0x753144eeU, 0x0c171b97U, 0x114c5d8aU, + 0xf99e6762U, 0x793e47e2U, 0x1c031f87U, 0xe300e378U, + 0xae1fb135U, 0xfd9b6666U, 0xe4c5217fU, 0xa090303bU, + 0x8378fb18U, 0xb204b629U, 0x612041faU, 0xb481352fU, + 0xcce72b57U, 0x257550beU, 0xf591646eU, 0x62e082f9U, + 0x7fbbc4e4U, 0xee4fa175U, 0xde73ad45U, 0x877dfa1cU, + 0x56d98fcdU, 0x03d8db98U, 0xd739ee4cU, 0xb601b72dU, + 0xfcdb2767U, 0xe240a279U, 0x1d435e86U, 0x2bfad1b0U, + 0x73b4c7e8U, 0x22b092b9U, 0x36a197adU, 0xc66dab5dU, + 0x1a869c81U, 0x787e06e3U, 0xa9da7332U, 0x7bbec5e0U, + 0x7efb85e5U, 0x478dcadcU, 0x88b23a13U, 0x6fafc0f4U, + 0x936cff08U, 0x2d7f52b6U, 0x95e97c0eU, 0xa89a3233U, + 0x4b82c9d0U, 0xb344f728U, 0x356154aeU, 0x3d6b56a6U, + 0x2aba90b1U, 0xcf27e854U, 0x3beed5a0U, 0x72f486e9U, + 0x89f27b12U, 0x26b593bdU, 0x76f187edU, 0x450d48deU, + 0xf711e66cU, 0x646501ffU, 0xd679af4dU, 0x7c7b07e7U, + 0xfe5ba565U, 0x59164fc2U, 0x713445eaU, 0x539ccfc8U, + 0xc9a26b52U, 0xb084342bU, 0xc4ed295fU, 0x404808dbU, + 0xaa1ab031U, 0x922cbe09U, 0x217051baU, 0xe8ca2273U, + 0x863dbb1dU, 0x0a929891U, 0xc72dea5cU, 0x410849daU, + 0xf194656aU, 0x02989a99U, 0x54590dcfU, 0x342115afU, + 0x48420ad3U, 0x4c470bd7U, 0x90ac3c0bU, 0xb88e3623U, + 0xcb22e950U, 0x91ec7d0aU, 0x4388cbd8U, 0xb741f62cU, + 0x13ccdf88U, 0x8a32b811U, 0x0fd7d894U, 0x0018189bU, + 0xb9ce7722U, 0x9a26bc01U, 0x8cb73b17U, 0xf8de2663U, + 0x81f8791aU, 0xbdcb7626U, 0x94a93d0fU, 0x9e23bd05U, + 0xd5b96c4eU, 0xfa5ea461U, 0x396e57a2U, 0xdf33ec44U, + 0x6baac1f0U, 0xca62a851U, 0x100c1c8bU, 0x0bd2d990U, + 0x49024bd2U, 0x2c3f13b7U, 0xbe0bb525U, 0xb5c1742eU, + 0x1fc3dc84U, 0x6aea80f1U, 0x2fffd0b4U, 0x3febd4a4U, + 0xdb36ed40U, 0x58560ec3U, 0xa350f338U, 0xd4f92d4fU, + 0xcda76a56U, 0xa755f23cU, 0x203010bbU, 0x041d199fU, + 0x686a02f3U, 0x1bc6dd80U, 0x3aae94a1U, 0xd9b66f42U, + 0xea4aa071U, 0x444d09dfU, 0xe645a37dU, 0xef0fe074U, + 0x9de37e06U, 0x3eab95a5U, 0x08121a93U, 0x4ec789d5U, + 0x15495c8eU, 0x8e37b915U, 0xc8e22a53U, 0x7d3b46e6U, + 0x18061e83U, 0x46cd8bddU, 0x80b8381bU, 0x055d589eU, + 0xa210b239U, 0xd27cae49U, 0x19465f82U, 0xdcf32f47U, + 0xb710a729U, 0xae4ee030U, 0x4bd398d5U, 0x17988f89U, + 0xdf62bd41U, 0x6bfb90f5U, 0x18574f86U, 0x32f5c7acU, + 0xb4d0642aU, 0x36f0c6a8U, 0xbcda6622U, 0xe754b379U, + 0x4c165ad2U, 0x03898a9dU, 0x5c025ec2U, 0xf88f7766U, + 0x401959deU, 0x716514efU, 0x866cea18U, 0x353005abU, + 0x441c58daU, 0x16d8ce88U, 0xfc8a7662U, 0xe351b27dU, + 0x469cdad8U, 0xfdca3763U, 0xa0c1613eU, 0x742054eaU, + 0xc9f33a57U, 0xf600f668U, 0xf480746aU, 0x8a63e914U, + 0x9e72ec00U, 0xe5d4317bU, 0xad8e2333U, 0x3fba85a1U, + 0xaa4be134U, 0x53cd9ecdU, 0x8e66e810U, 0x050c099bU, + 0x206141beU, 0xbd9a2723U, 0xc0b9795eU, 0xe1d1307fU, + 0x5bc79cc5U, 0xd36dbe4dU, 0x5e82dcc0U, 0x657411fbU, + 0x7fea95e1U, 0x22e1c3bcU, 0x9cf26e02U, 0x4a93d9d4U, + 0xcb73b855U, 0xccb67a52U, 0x4fd699d1U, 0xba5fe524U, + 0xee1ef070U, 0x933dae0dU, 0xbe5ae420U, 0x078c8b99U, + 0x393f06a7U, 0xd22dff4cU, 0x105d4d8eU, 0x76a0d6e8U, + 0xf1c5346fU, 0xf085756eU, 0x72a5d7ecU, 0x1f928d81U, + 0x23a182bdU, 0x212100bfU, 0xb0d5652eU, 0x06ccca98U, + 0xe211f37cU, 0x89a32a17U, 0x1c524e82U, 0x88e36b16U, + 0x77e097e9U, 0xfa0ff564U, 0xd1ed3c4fU, 0x4e96d8d0U, + 0x4d561bd3U, 0x415918dfU, 0xea1bf174U, 0x26e4c2b8U, + 0x292b02b7U, 0x7d6a17e3U, 0x872cab19U, 0xc239fb5cU, + 0x0f868991U, 0x43d99addU, 0xd0ad7d4eU, 0xc1f9385fU, + 0x2d2e03b3U, 0xb590252bU, 0x9a77ed04U, 0x387f47a6U, + 0x94f86c0aU, 0x7c2a56e2U, 0xd4a87c4aU, 0x95b82d0bU, + 0x617110ffU, 0x8da62b13U, 0xab0ba035U, 0x66b4d2f8U, + 0x782f57e6U, 0x643450faU, 0x1d120f83U, 0x0049499eU, + 0xe89b7376U, 0x683b53f6U, 0x0d060b93U, 0xf205f76cU, + 0xbf1aa521U, 0xec9e7272U, 0xf5c0356bU, 0xb195242fU, + 0x927def0cU, 0xa301a23dU, 0x702555eeU, 0xa584213bU, + 0xdde23f43U, 0x347044aaU, 0xe494707aU, 0x73e596edU, + 0x6ebed0f0U, 0xff4ab561U, 0xcf76b951U, 0x9678ee08U, + 0x47dc9bd9U, 0x12ddcf8cU, 0xc63cfa58U, 0xa704a339U, + 0xedde3373U, 0xf345b66dU, 0x0c464a92U, 0x3affc5a4U, + 0x62b1d3fcU, 0x33b586adU, 0x27a483b9U, 0xd768bf49U, + 0x0b838895U, 0x697b12f7U, 0xb8df6726U, 0x6abbd1f4U, + 0x6ffe91f1U, 0x5688dec8U, 0x99b72e07U, 0x7eaad4e0U, + 0x8269eb1cU, 0x3c7a46a2U, 0x84ec681aU, 0xb99f2627U, + 0x5a87ddc4U, 0xa241e33cU, 0x246440baU, 0x2c6e42b2U, + 0x3bbf84a5U, 0xde22fc40U, 0x2aebc1b4U, 0x63f192fdU, + 0x98f76f06U, 0x37b087a9U, 0x67f493f9U, 0x54085ccaU, + 0xe614f278U, 0x756015ebU, 0xc77cbb59U, 0x6d7e13f3U, + 0xef5eb171U, 0x48135bd6U, 0x603151feU, 0x4299dbdcU, + 0xd8a77f46U, 0xa181203fU, 0xd5e83d4bU, 0x514d1ccfU, + 0xbb1fa425U, 0x8329aa1dU, 0x307545aeU, 0xf9cf3667U, + 0x9738af09U, 0x1b978c85U, 0xd628fe48U, 0x500d5dceU, + 0xe091717eU, 0x139d8e8dU, 0x455c19dbU, 0x252401bbU, + 0x59471ec7U, 0x5d421fc3U, 0x81a9281fU, 0xa98b2237U, + 0xda27fd44U, 0x80e9691eU, 0x528ddfccU, 0xa644e238U, + 0x02c9cb9cU, 0x9b37ac05U, 0x1ed2cc80U, 0x111d0c8fU, + 0xa8cb6336U, 0x8b23a815U, 0x9db22f03U, 0xe9db3277U, + 0x90fd6d0eU, 0xacce6232U, 0x85ac291bU, 0x8f26a911U, + 0xc4bc785aU, 0xeb5bb075U, 0x286b43b6U, 0xce36f850U, + 0x7aafd5e4U, 0xdb67bc45U, 0x0109089fU, 0x1ad7cd84U, + 0x58075fc6U, 0x3d3a07a3U, 0xaf0ea131U, 0xa4c4603aU, + 0x0ec6c890U, 0x7bef94e5U, 0x3efac4a0U, 0x2eeec0b0U, + 0xca33f954U, 0x49531ad7U, 0xb255e72cU, 0xc5fc395bU, + 0xdca27e42U, 0xb650e628U, 0x313504afU, 0x15180d8bU, + 0x796f16e7U, 0x0ac3c994U, 0x2bab80b5U, 0xc8b37b56U, + 0xfb4fb465U, 0x55481dcbU, 0xf740b769U, 0xfe0af460U, + 0x8ce66a12U, 0x2fae81b1U, 0x19170e87U, 0x5fc29dc1U, + 0x044c489aU, 0x9f32ad01U, 0xd9e73e47U, 0x6c3e52f2U, + 0x09030a97U, 0x57c89fc9U, 0x91bd2c0fU, 0x14584c8aU, + 0xb315a62dU, 0xc379ba5dU, 0x08434b96U, 0xcdf63b53U, + 0x11cddc52U, 0x08939b4bU, 0xed0ee3aeU, 0xb145f4f2U, + 0x79bfc63aU, 0xcd26eb8eU, 0xbe8a34fdU, 0x9428bcd7U, + 0x120d1f51U, 0x902dbdd3U, 0x1a071d59U, 0x4189c802U, + 0xeacb21a9U, 0xa554f1e6U, 0xfadf25b9U, 0x5e520c1dU, + 0xe6c422a5U, 0xd7b86f94U, 0x20b19163U, 0x93ed7ed0U, + 0xe2c123a1U, 0xb005b5f3U, 0x5a570d19U, 0x458cc906U, + 0xe041a1a3U, 0x5b174c18U, 0x061c1a45U, 0xd2fd2f91U, + 0x6f2e412cU, 0x50dd8d13U, 0x525d0f11U, 0x2cbe926fU, + 0x38af977bU, 0x43094a00U, 0x0b535848U, 0x9967fedaU, + 0x0c969a4fU, 0xf510e5b6U, 0x28bb936bU, 0xa3d172e0U, + 0x86bc3ac5U, 0x1b475c58U, 0x66640225U, 0x470c4b04U, + 0xfd1ae7beU, 0x75b0c536U, 0xf85fa7bbU, 0xc3a96a80U, + 0xd937ee9aU, 0x843cb8c7U, 0x3a2f1579U, 0xec4ea2afU, + 0x6daec32eU, 0x6a6b0129U, 0xe90be2aaU, 0x1c829e5fU, + 0x48c38b0bU, 0x35e0d576U, 0x18879f5bU, 0xa151f0e2U, + 0x9fe27ddcU, 0x74f08437U, 0xb68036f5U, 0xd07dad93U, + 0x57184f14U, 0x56580e15U, 0xd478ac97U, 0xb94ff6faU, + 0x857cf9c6U, 0x87fc7bc4U, 0x16081e55U, 0xa011b1e3U, + 0x44cc8807U, 0x2f7e516cU, 0xba8f35f9U, 0x2e3e106dU, + 0xd13dec92U, 0x5cd28e1fU, 0x77304734U, 0xe84ba3abU, + 0xeb8b60a8U, 0xe78463a4U, 0x4cc68a0fU, 0x8039b9c3U, + 0x8ff679ccU, 0xdbb76c98U, 0x21f1d062U, 0x64e48027U, + 0xa95bf2eaU, 0xe504e1a6U, 0x76700635U, 0x67244324U, + 0x8bf378c8U, 0x134d5e50U, 0x3caa967fU, 0x9ea23cddU, + 0x32251771U, 0xdaf72d99U, 0x72750731U, 0x33655670U, + 0xc7ac6b84U, 0x2b7b5068U, 0x0dd6db4eU, 0xc069a983U, + 0xdef22c9dU, 0xc2e92b81U, 0xbbcf74f8U, 0xa69432e5U, + 0x4e46080dU, 0xcee6288dU, 0xabdb70e8U, 0x54d88c17U, + 0x19c7de5aU, 0x4a430909U, 0x531d4e10U, 0x17485f54U, + 0x34a09477U, 0x05dcd946U, 0xd6f82e95U, 0x03595a40U, + 0x7b3f4438U, 0x92ad3fd1U, 0x42490b01U, 0xd538ed96U, + 0xc863ab8bU, 0x5997ce1aU, 0x69abc22aU, 0x30a59573U, + 0xe101e0a2U, 0xb400b4f7U, 0x60e18123U, 0x01d9d842U, + 0x4b034808U, 0x5598cd16U, 0xaa9b31e9U, 0x9c22bedfU, + 0xc46ca887U, 0x9568fdd6U, 0x8179f8c2U, 0x71b5c432U, + 0xad5ef3eeU, 0xcfa6698cU, 0x1e021c5dU, 0xcc66aa8fU, + 0xc923ea8aU, 0xf055a5b3U, 0x3f6a557cU, 0xd877af9bU, + 0x24b49067U, 0x9aa73dd9U, 0x22311361U, 0x1f425d5cU, + 0xfc5aa6bfU, 0x049c9847U, 0x82b93bc1U, 0x8ab339c9U, + 0x9d62ffdeU, 0x78ff873bU, 0x8c36bacfU, 0xc52ce986U, + 0x3e2a147dU, 0x916dfcd2U, 0xc129e882U, 0xf2d527b1U, + 0x40c98903U, 0xd3bd6e90U, 0x61a1c022U, 0xcba36888U, + 0x4983ca0aU, 0xeece20adU, 0xc6ec2a85U, 0xe444a0a7U, + 0x7e7a043dU, 0x075c5b44U, 0x73354630U, 0xf79067b4U, + 0x1dc2df5eU, 0x25f4d166U, 0x96a83ed5U, 0x5f124d1cU, + 0x31e5d472U, 0xbd4af7feU, 0x70f58533U, 0xf6d026b5U, + 0x464c0a05U, 0xb540f5f6U, 0xe38162a0U, 0x83f97ac0U, + 0xff9a65bcU, 0xfb9f64b8U, 0x27745364U, 0x0f56594cU, + 0x7cfa863fU, 0x26341265U, 0xf450a4b7U, 0x00999943U, + 0xa414b0e7U, 0x3dead77eU, 0xb80fb7fbU, 0xb7c077f4U, + 0x0e16184dU, 0x2dfed36eU, 0x3b6f5478U, 0x4f06490cU, + 0x36201675U, 0x0a131949U, 0x23715260U, 0x29fbd26aU, + 0x62610321U, 0x4d86cb0eU, 0x8eb638cdU, 0x68eb832bU, + 0xdc72ae9fU, 0x7dbac73eU, 0xa7d473e4U, 0xbc0ab6ffU, + 0xfeda24bdU, 0x9be77cd8U, 0x09d3da4aU, 0x02191b41U, + 0xa81bb3ebU, 0xdd32ef9eU, 0x9827bfdbU, 0x8833bbcbU, + 0x6cee822fU, 0xef8e61acU, 0x14889c57U, 0x63214220U, + 0x7a7f0539U, 0x108d9d53U, 0x97e87fd4U, 0xb3c576f0U, + 0xdfb26d9cU, 0xac1eb2efU, 0x8d76fbceU, 0x6e6e002dU, + 0x5d92cf1eU, 0xf39566b0U, 0x519dcc12U, 0x58d78f1bU, + 0x2a3b1169U, 0x8973facaU, 0xbfca75fcU, 0xf91fe6baU, + 0xa29133e1U, 0x39efd67aU, 0x7f3a453cU, 0xcae32989U, + 0xafde71ecU, 0xf115e4b2U, 0x37605774U, 0xb28537f1U, + 0x15c8dd56U, 0x65a4c126U, 0xae9e30edU, 0x6b2b4028U, + 0x4bdf941aU, 0x5281d303U, 0xb71cabe6U, 0xeb57bcbaU, + 0x23ad8e72U, 0x9734a3c6U, 0xe4987cb5U, 0xce3af49fU, + 0x481f5719U, 0xca3ff59bU, 0x40155511U, 0x1b9b804aU, + 0xb0d969e1U, 0xff46b9aeU, 0xa0cd6df1U, 0x04404455U, + 0xbcd66aedU, 0x8daa27dcU, 0x7aa3d92bU, 0xc9ff3698U, + 0xb8d36be9U, 0xea17fdbbU, 0x00454551U, 0x1f9e814eU, + 0xba53e9ebU, 0x01050450U, 0x5c0e520dU, 0x88ef67d9U, + 0x353c0964U, 0x0acfc55bU, 0x084f4759U, 0x76acda27U, + 0x62bddf33U, 0x191b0248U, 0x51411000U, 0xc375b692U, + 0x5684d207U, 0xaf02adfeU, 0x72a9db23U, 0xf9c33aa8U, + 0xdcae728dU, 0x41551410U, 0x3c764a6dU, 0x1d1e034cU, + 0xa708aff6U, 0x2fa28d7eU, 0xa24deff3U, 0x99bb22c8U, + 0x8325a6d2U, 0xde2ef08fU, 0x603d5d31U, 0xb65ceae7U, + 0x37bc8b66U, 0x30794961U, 0xb319aae2U, 0x4690d617U, + 0x12d1c343U, 0x6ff29d3eU, 0x4295d713U, 0xfb43b8aaU, + 0xc5f03594U, 0x2ee2cc7fU, 0xec927ebdU, 0x8a6fe5dbU, + 0x0d0a075cU, 0x0c4a465dU, 0x8e6ae4dfU, 0xe35dbeb2U, + 0xdf6eb18eU, 0xddee338cU, 0x4c1a561dU, 0xfa03f9abU, + 0x1edec04fU, 0x756c1924U, 0xe09d7db1U, 0x742c5825U, + 0x8b2fa4daU, 0x06c0c657U, 0x2d220f7cU, 0xb259ebe3U, + 0xb19928e0U, 0xbd962becU, 0x16d4c247U, 0xda2bf18bU, + 0xd5e43184U, 0x81a524d0U, 0x7be3982aU, 0x3ef6c86fU, + 0xf349baa2U, 0xbf16a9eeU, 0x2c624e7dU, 0x3d360b6cU, + 0xd1e13080U, 0x495f1618U, 0x66b8de37U, 0xc4b07495U, + 0x68375f39U, 0x80e565d1U, 0x28674f79U, 0x69771e38U, + 0x9dbe23ccU, 0x71691820U, 0x57c49306U, 0x9a7be1cbU, + 0x84e064d5U, 0x98fb63c9U, 0xe1dd3cb0U, 0xfc867aadU, + 0x14544045U, 0x94f460c5U, 0xf1c938a0U, 0x0ecac45fU, + 0x43d59612U, 0x10514141U, 0x090f0658U, 0x4d5a171cU, + 0x6eb2dc3fU, 0x5fce910eU, 0x8cea66ddU, 0x594b1208U, + 0x212d0c70U, 0xc8bf7799U, 0x185b4349U, 0x8f2aa5deU, + 0x9271e3c3U, 0x03858652U, 0x33b98a62U, 0x6ab7dd3bU, + 0xbb13a8eaU, 0xee12fcbfU, 0x3af3c96bU, 0x5bcb900aU, + 0x11110040U, 0x0f8a855eU, 0xf08979a1U, 0xc630f697U, + 0x9e7ee0cfU, 0xcf7ab59eU, 0xdb6bb08aU, 0x2ba78c7aU, + 0xf74cbba6U, 0x95b421c4U, 0x44105415U, 0x9674e2c7U, + 0x9331a2c2U, 0xaa47edfbU, 0x65781d34U, 0x8265e7d3U, + 0x7ea6d82fU, 0xc0b57591U, 0x78235b29U, 0x45501514U, + 0xa648eef7U, 0x5e8ed00fU, 0xd8ab7389U, 0xd0a17181U, + 0xc770b796U, 0x22edcf73U, 0xd624f287U, 0x9f3ea1ceU, + 0x64385c35U, 0xcb7fb49aU, 0x9b3ba0caU, 0xa8c76ff9U, + 0x1adbc14bU, 0x89af26d8U, 0x3bb3886aU, 0x91b120c0U, + 0x13918242U, 0xb4dc68e5U, 0x9cfe62cdU, 0xbe56e8efU, + 0x24684c75U, 0x5d4e130cU, 0x29270e78U, 0xad822ffcU, + 0x47d09716U, 0x7fe6992eU, 0xccba769dU, 0x05000554U, + 0x6bf79c3aU, 0xe758bfb6U, 0x2ae7cd7bU, 0xacc26efdU, + 0x1c5e424dU, 0xef52bdbeU, 0xb9932ae8U, 0xd9eb3288U, + 0xa5882df4U, 0xa18d2cf0U, 0x7d661b2cU, 0x55441104U, + 0x26e8ce77U, 0x7c265a2dU, 0xae42ecffU, 0x5a8bd10bU, + 0xfe06f8afU, 0x67f89f36U, 0xe21dffb3U, 0xedd23fbcU, + 0x54045005U, 0x77ec9b26U, 0x617d1c30U, 0x15140144U, + 0x6c325e3dU, 0x50015101U, 0x79631a28U, 0x73e99a22U, + 0x38734b69U, 0x17948346U, 0xd4a47085U, 0x32f9cb63U, + 0x8660e6d7U, 0x27a88f76U, 0xfdc63bacU, 0xe618feb7U, + 0xa4c86cf5U, 0xc1f53490U, 0x53c19202U, 0x580b5309U, + 0xf209fba3U, 0x8720a7d6U, 0xc235f793U, 0xd221f383U, + 0x36fcca67U, 0xb59c29e4U, 0x4e9ad41fU, 0x39330a68U, + 0x206d4d71U, 0x4a9fd51bU, 0xcdfa379cU, 0xe9d73eb8U, + 0x85a025d4U, 0xf60cfaa7U, 0xd764b386U, 0x347c4865U, + 0x07808756U, 0xa9872ef8U, 0x0b8f845aU, 0x02c5c753U, + 0x70295921U, 0xd361b282U, 0xe5d83db4U, 0xa30daef2U, + 0xf8837ba9U, 0x63fd9e32U, 0x25280d74U, 0x90f161c1U, + 0xf5cc39a4U, 0xab07acfaU, 0x6d721f3cU, 0xe8977fb9U, + 0x4fda951eU, 0x3fb6896eU, 0xf48c78a5U, 0x31390860U, + 0x7f790688U, 0x66274191U, 0x83ba3974U, 0xdff12e28U, + 0x170b1ce0U, 0xa3923154U, 0xd03eee27U, 0xfa9c660dU, + 0x7cb9c58bU, 0xfe996709U, 0x74b3c783U, 0x2f3d12d8U, + 0x847ffb73U, 0xcbe02b3cU, 0x946bff63U, 0x30e6d6c7U, + 0x8870f87fU, 0xb90cb54eU, 0x4e054bb9U, 0xfd59a40aU, + 0x8c75f97bU, 0xdeb16f29U, 0x34e3d7c3U, 0x2b3813dcU, + 0x8ef57b79U, 0x35a396c2U, 0x68a8c09fU, 0xbc49f54bU, + 0x019a9bf6U, 0x3e6957c9U, 0x3ce9d5cbU, 0x420a48b5U, + 0x561b4da1U, 0x2dbd90daU, 0x65e78292U, 0xf7d32400U, + 0x62224095U, 0x9ba43f6cU, 0x460f49b1U, 0xcd65a83aU, + 0xe808e01fU, 0x75f38682U, 0x08d0d8ffU, 0x29b891deU, + 0x93ae3d64U, 0x1b041fecU, 0x96eb7d61U, 0xad1db05aU, + 0xb7833440U, 0xea88621dU, 0x549bcfa3U, 0x82fa7875U, + 0x031a19f4U, 0x04dfdbf3U, 0x87bf3870U, 0x72364485U, + 0x267751d1U, 0x5b540facU, 0x76334581U, 0xcfe52a38U, + 0xf156a706U, 0x1a445eedU, 0xd834ec2fU, 0xbec97749U, + 0x39ac95ceU, 0x38ecd4cfU, 0xbacc764dU, 0xd7fb2c20U, + 0xebc8231cU, 0xe948a11eU, 0x78bcc48fU, 0xcea56b39U, + 0x2a7852ddU, 0x41ca8bb6U, 0xd43bef23U, 0x408acab7U, + 0xbf893648U, 0x326654c5U, 0x19849deeU, 0x86ff7971U, + 0x853fba72U, 0x8930b97eU, 0x227250d5U, 0xee8d6319U, + 0xe142a316U, 0xb503b642U, 0x4f450ab8U, 0x0a505afdU, + 0xc7ef2830U, 0x8bb03b7cU, 0x18c4dcefU, 0x099099feU, + 0xe547a212U, 0x7df9848aU, 0x521e4ca5U, 0xf016e607U, + 0x5c91cdabU, 0xb443f743U, 0x1cc1ddebU, 0x5dd18caaU, + 0xa918b15eU, 0x45cf8ab2U, 0x63620194U, 0xaedd7359U, + 0xb046f647U, 0xac5df15bU, 0xd57bae22U, 0xc820e83fU, + 0x20f2d2d7U, 0xa052f257U, 0xc56faa32U, 0x3a6c56cdU, + 0x77730480U, 0x24f7d3d3U, 0x3da994caU, 0x79fc858eU, + 0x5a144eadU, 0x6b68039cU, 0xb84cf44fU, 0x6ded809aU, + 0x158b9ee2U, 0xfc19e50bU, 0x2cfdd1dbU, 0xbb8c374cU, + 0xa6d77151U, 0x372314c0U, 0x071f18f0U, 0x5e114fa9U, + 0x8fb53a78U, 0xdab46e2dU, 0x0e555bf9U, 0x6f6d0298U, + 0x25b792d2U, 0x3b2c17ccU, 0xc42feb33U, 0xf2966405U, + 0xaad8725dU, 0xfbdc270cU, 0xefcd2218U, 0x1f011ee8U, + 0xc3ea2934U, 0xa112b356U, 0x70b6c687U, 0xa2d27055U, + 0xa7973050U, 0x9ee17f69U, 0x51de8fa6U, 0xb6c37541U, + 0x4a004abdU, 0xf413e703U, 0x4c85c9bbU, 0x71f68786U, + 0x92ee7c65U, 0x6a28429dU, 0xec0de11bU, 0xe407e313U, + 0xf3d62504U, 0x164b5de1U, 0xe2826015U, 0xab98335cU, + 0x509ecea7U, 0xffd92608U, 0xaf9d3258U, 0x9c61fd6bU, + 0x2e7d53d9U, 0xbd09b44aU, 0x0f151af8U, 0xa517b252U, + 0x273710d0U, 0x807afa77U, 0xa858f05fU, 0x8af07a7dU, + 0x10cedee7U, 0x69e8819eU, 0x1d819ceaU, 0x9924bd6eU, + 0x73760584U, 0x4b400bbcU, 0xf81ce40fU, 0x31a697c6U, + 0x5f510ea8U, 0xd3fe2d24U, 0x1e415fe9U, 0x9864fc6fU, + 0x28f8d0dfU, 0xdbf42f2cU, 0x8d35b87aU, 0xed4da01aU, + 0x912ebf66U, 0x952bbe62U, 0x49c089beU, 0x61e28396U, + 0x124e5ce5U, 0x4880c8bfU, 0x9ae47e6dU, 0x6e2d4399U, + 0xcaa06a3dU, 0x535e0da4U, 0xd6bb6d21U, 0xd974ad2eU, + 0x60a2c297U, 0x434a09b4U, 0x55db8ea2U, 0x21b293d6U, + 0x5894ccafU, 0x64a7c393U, 0x4dc588baU, 0x474f08b0U, + 0x0cd5d9fbU, 0x233211d4U, 0xe002e217U, 0x065f59f1U, + 0xb2c67445U, 0x130e1de4U, 0xc960a93eU, 0xd2be6c25U, + 0x906efe67U, 0xf553a602U, 0x67670090U, 0x6cadc19bU, + 0xc6af6931U, 0xb3863544U, 0xf6936501U, 0xe6876111U, + 0x025a58f5U, 0x813abb76U, 0x7a3c468dU, 0x0d9598faU, + 0x14cbdfe3U, 0x7e394789U, 0xf95ca50eU, 0xdd71ac2aU, + 0xb106b746U, 0xc2aa6835U, 0xe3c22114U, 0x00dadaf7U, + 0x332615c4U, 0x9d21bc6aU, 0x3f2916c8U, 0x366355c1U, + 0x448fcbb3U, 0xe7c72010U, 0xd17eaf26U, 0x97ab3c60U, + 0xcc25e93bU, 0x575b0ca0U, 0x118e9fe6U, 0xa457f353U, + 0xc16aab36U, 0x9fa13e68U, 0x59d48daeU, 0xdc31ed2bU, + 0x7b7c078cU, 0x0b101bfcU, 0xc02aea37U, 0x059f9af2U, + 0x8e1d931dU, 0x9743d404U, 0x72deace1U, 0x2e95bbbdU, + 0xe66f8975U, 0x52f6a4c1U, 0x215a7bb2U, 0x0bf8f398U, + 0x8ddd501eU, 0x0ffdf29cU, 0x85d75216U, 0xde59874dU, + 0x751b6ee6U, 0x3a84bea9U, 0x650f6af6U, 0xc1824352U, + 0x79146deaU, 0x486820dbU, 0xbf61de2cU, 0x0c3d319fU, + 0x7d116ceeU, 0x2fd5fabcU, 0xc5874256U, 0xda5c8649U, + 0x7f91eeecU, 0xc4c70357U, 0x99cc550aU, 0x4d2d60deU, + 0xf0fe0e63U, 0xcf0dc25cU, 0xcd8d405eU, 0xb36edd20U, + 0xa77fd834U, 0xdcd9054fU, 0x94831707U, 0x06b7b195U, + 0x9346d500U, 0x6ac0aaf9U, 0xb76bdc24U, 0x3c013dafU, + 0x196c758aU, 0x84971317U, 0xf9b44d6aU, 0xd8dc044bU, + 0x62caa8f1U, 0xea608a79U, 0x678fe8f4U, 0x5c7925cfU, + 0x46e7a1d5U, 0x1becf788U, 0xa5ff5a36U, 0x739eede0U, + 0xf27e8c61U, 0xf5bb4e66U, 0x76dbade5U, 0x8352d110U, + 0xd713c444U, 0xaa309a39U, 0x8757d014U, 0x3e81bfadU, + 0x00323293U, 0xeb20cb78U, 0x295079baU, 0x4fade2dcU, + 0xc8c8005bU, 0xc988415aU, 0x4ba8e3d8U, 0x269fb9b5U, + 0x1aacb689U, 0x182c348bU, 0x89d8511aU, 0x3fc1feacU, + 0xdb1cc748U, 0xb0ae1e23U, 0x255f7ab6U, 0xb1ee5f22U, + 0x4eeda3ddU, 0xc302c150U, 0xe8e0087bU, 0x779bece4U, + 0x745b2fe7U, 0x78542cebU, 0xd316c540U, 0x1fe9f68cU, + 0x10263683U, 0x446723d7U, 0xbe219f2dU, 0xfb34cf68U, + 0x368bbda5U, 0x7ad4aee9U, 0xe9a0497aU, 0xf8f40c6bU, + 0x14233787U, 0x8c9d111fU, 0xa37ad930U, 0x01727392U, + 0xadf5583eU, 0x452762d6U, 0xeda5487eU, 0xacb5193fU, + 0x587c24cbU, 0xb4ab1f27U, 0x92069401U, 0x5fb9e6ccU, + 0x412263d2U, 0x5d3964ceU, 0x241f3bb7U, 0x39447daaU, + 0xd1964742U, 0x513667c2U, 0x340b3fa7U, 0xcb08c358U, + 0x86179115U, 0xd5934646U, 0xcccd015fU, 0x8898101bU, + 0xab70db38U, 0x9a0c9609U, 0x492861daU, 0x9c89150fU, + 0xe4ef0b77U, 0x0d7d709eU, 0xdd99444eU, 0x4ae8a2d9U, + 0x57b3e4c4U, 0xc6478155U, 0xf67b8d65U, 0xaf75da3cU, + 0x7ed1afedU, 0x2bd0fbb8U, 0xff31ce6cU, 0x9e09970dU, + 0xd4d30747U, 0xca488259U, 0x354b7ea6U, 0x03f2f190U, + 0x5bbce7c8U, 0x0ab8b299U, 0x1ea9b78dU, 0xee658b7dU, + 0x328ebca1U, 0x507626c3U, 0x81d25312U, 0x53b6e5c0U, + 0x56f3a5c5U, 0x6f85eafcU, 0xa0ba1a33U, 0x47a7e0d4U, + 0xbb64df28U, 0x05777296U, 0xbde15c2eU, 0x80921213U, + 0x638ae9f0U, 0x9b4cd708U, 0x1d69748eU, 0x15637686U, + 0x02b2b091U, 0xe72fc874U, 0x13e6f580U, 0x5afca6c9U, + 0xa1fa5b32U, 0x0ebdb39dU, 0x5ef9a7cdU, 0x6d0568feU, + 0xdf19c64cU, 0x4c6d21dfU, 0xfe718f6dU, 0x547327c7U, + 0xd6538545U, 0x711e6fe2U, 0x593c65caU, 0x7b94efe8U, + 0xe1aa4b72U, 0x988c140bU, 0xece5097fU, 0x684028fbU, + 0x82129011U, 0xba249e29U, 0x0978719aU, 0xc0c20253U, + 0xae359b3dU, 0x229ab8b1U, 0xef25ca7cU, 0x690069faU, + 0xd99c454aU, 0x2a90bab9U, 0x7c512defU, 0x1c29358fU, + 0x604a2af3U, 0x644f2bf7U, 0xb8a41c2bU, 0x90861603U, + 0xe32ac970U, 0xb9e45d2aU, 0x6b80ebf8U, 0x9f49d60cU, + 0x3bc4ffa8U, 0xa23a9831U, 0x27dff8b4U, 0x281038bbU, + 0x91c65702U, 0xb22e9c21U, 0xa4bf1b37U, 0xd0d60643U, + 0xa9f0593aU, 0x95c35606U, 0xbca11d2fU, 0xb62b9d25U, + 0xfdb14c6eU, 0xd2568441U, 0x11667782U, 0xf73bcc64U, + 0x43a2e1d0U, 0xe26a8871U, 0x38043cabU, 0x23daf9b0U, + 0x610a6bf2U, 0x04373397U, 0x96039505U, 0x9dc9540eU, + 0x37cbfca4U, 0x42e2a0d1U, 0x07f7f094U, 0x17e3f484U, + 0xf33ecd60U, 0x705e2ee3U, 0x8b58d318U, 0xfcf10d6fU, + 0xe5af4a76U, 0x8f5dd21cU, 0x0838309bU, 0x2c1539bfU, + 0x406222d3U, 0x33cefda0U, 0x12a6b481U, 0xf1be4f62U, + 0xc2428051U, 0x6c4529ffU, 0xce4d835dU, 0xc707c054U, + 0xb5eb5e26U, 0x16a3b585U, 0x201a3ab3U, 0x66cfa9f5U, + 0x3d417caeU, 0xa63f9935U, 0xe0ea0a73U, 0x553366c6U, + 0x300e3ea3U, 0x6ec5abfdU, 0xa8b0183bU, 0x2d5578beU, + 0x8a189219U, 0xfa748e69U, 0x314e7fa2U, 0xf4fb0f67U, + 0x08626ae4U, 0x113c2dfdU, 0xf4a15518U, 0xa8ea4244U, + 0x6010708cU, 0xd4895d38U, 0xa725824bU, 0x8d870a61U, + 0x0ba2a9e7U, 0x89820b65U, 0x03a8abefU, 0x58267eb4U, + 0xf364971fU, 0xbcfb4750U, 0xe370930fU, 0x47fdbaabU, + 0xff6b9413U, 0xce17d922U, 0x391e27d5U, 0x8a42c866U, + 0xfb6e9517U, 0xa9aa0345U, 0x43f8bbafU, 0x5c237fb0U, + 0xf9ee1715U, 0x42b8faaeU, 0x1fb3acf3U, 0xcb529927U, + 0x7681f79aU, 0x49723ba5U, 0x4bf2b9a7U, 0x351124d9U, + 0x210021cdU, 0x5aa6fcb6U, 0x12fceefeU, 0x80c8486cU, + 0x15392cf9U, 0xecbf5300U, 0x311425ddU, 0xba7ec456U, + 0x9f138c73U, 0x02e8eaeeU, 0x7fcbb493U, 0x5ea3fdb2U, + 0xe4b55108U, 0x6c1f7380U, 0xe1f0110dU, 0xda06dc36U, + 0xc098582cU, 0x9d930e71U, 0x2380a3cfU, 0xf5e11419U, + 0x74017598U, 0x73c4b79fU, 0xf0a4541cU, 0x052d28e9U, + 0x516c3dbdU, 0x2c4f63c0U, 0x012829edU, 0xb8fe4654U, + 0x864dcb6aU, 0x6d5f3281U, 0xaf2f8043U, 0xc9d21b25U, + 0x4eb7f9a2U, 0x4ff7b8a3U, 0xcdd71a21U, 0xa0e0404cU, + 0x9cd34f70U, 0x9e53cd72U, 0x0fa7a8e3U, 0xb9be0755U, + 0x5d633eb1U, 0x36d1e7daU, 0xa320834fU, 0x3791a6dbU, + 0xc8925a24U, 0x457d38a9U, 0x6e9ff182U, 0xf1e4151dU, + 0xf224d61eU, 0xfe2bd512U, 0x55693cb9U, 0x99960f75U, + 0x9659cf7aU, 0xc218da2eU, 0x385e66d4U, 0x7d4b3691U, + 0xb0f4445cU, 0xfcab5710U, 0x6fdfb083U, 0x7e8bf592U, + 0x925cce7eU, 0x0ae2e8e6U, 0x250520c9U, 0x870d8a6bU, + 0x2b8aa1c7U, 0xc3589b2fU, 0x6bdab187U, 0x2acae0c6U, + 0xde03dd32U, 0x32d4e6deU, 0x14796df8U, 0xd9c61f35U, + 0xc75d9a2bU, 0xdb469d37U, 0xa260c24eU, 0xbf3b8453U, + 0x57e9bebbU, 0xd7499e3bU, 0xb274c65eU, 0x4d773aa1U, + 0x006868ecU, 0x53ecbfbfU, 0x4ab2f8a6U, 0x0ee7e9e2U, + 0x2d0f22c1U, 0x1c736ff0U, 0xcf579823U, 0x1af6ecf6U, + 0x6290f28eU, 0x8b028967U, 0x5be6bdb7U, 0xcc975b20U, + 0xd1cc1d3dU, 0x403878acU, 0x7004749cU, 0x290a23c5U, + 0xf8ae5614U, 0xadaf0241U, 0x794e3795U, 0x18766ef4U, + 0x52acfebeU, 0x4c377ba0U, 0xb334875fU, 0x858d0869U, + 0xddc31e31U, 0x8cc74b60U, 0x98d64e74U, 0x681a7284U, + 0xb4f14558U, 0xd609df3aU, 0x07adaaebU, 0xd5c91c39U, + 0xd08c5c3cU, 0xe9fa1305U, 0x26c5e3caU, 0xc1d8192dU, + 0x3d1b26d1U, 0x83088b6fU, 0x3b9ea5d7U, 0x06edebeaU, + 0xe5f51009U, 0x1d332ef1U, 0x9b168d77U, 0x931c8f7fU, + 0x84cd4968U, 0x6150318dU, 0x95990c79U, 0xdc835f30U, + 0x2785a2cbU, 0x88c24a64U, 0xd8865e34U, 0xeb7a9107U, + 0x59663fb5U, 0xca12d826U, 0x780e7694U, 0xd20cde3eU, + 0x502c7cbcU, 0xf761961bU, 0xdf439c33U, 0xfdeb1611U, + 0x67d5b28bU, 0x1ef3edf2U, 0x6a9af086U, 0xee3fd102U, + 0x046d69e8U, 0x3c5b67d0U, 0x8f078863U, 0x46bdfbaaU, + 0x284a62c4U, 0xa4e54148U, 0x695a3385U, 0xef7f9003U, + 0x5fe3bcb3U, 0xacef4340U, 0xfa2ed416U, 0x9a56cc76U, + 0xe635d30aU, 0xe230d20eU, 0x3edbe5d2U, 0x16f9effaU, + 0x65553089U, 0x3f9ba4d3U, 0xedff1201U, 0x19362ff5U, + 0xbdbb0651U, 0x244561c8U, 0xa1a0014dU, 0xae6fc142U, + 0x17b9aefbU, 0x345165d8U, 0x22c0e2ceU, 0x56a9ffbaU, + 0x2f8fa0c3U, 0x13bcafffU, 0x3adee4d6U, 0x305464dcU, + 0x7bceb597U, 0x54297db8U, 0x97198e7bU, 0x7144359dU, + 0xc5dd1829U, 0x64157188U, 0xbe7bc552U, 0xa5a50049U, + 0xe775920bU, 0x8248ca6eU, 0x107c6cfcU, 0x1bb6adf7U, + 0xb1b4055dU, 0xc49d5928U, 0x8188096dU, 0x919c0d7dU, + 0x75413499U, 0xf621d71aU, 0x0d272ae1U, 0x7a8ef496U, + 0x63d0b38fU, 0x09222be5U, 0x8e47c962U, 0xaa6ac046U, + 0xc61ddb2aU, 0xb5b10459U, 0x94d94d78U, 0x77c1b69bU, + 0x443d79a8U, 0xea3ad006U, 0x48327aa4U, 0x417839adU, + 0x3394a7dfU, 0x90dc4c7cU, 0xa665c34aU, 0xe0b0500cU, + 0xbb3e8557U, 0x204060ccU, 0x6695f38aU, 0xd34c9f3fU, + 0xb671c75aU, 0xe8ba5204U, 0x2ecfe1c2U, 0xab2a8147U, + 0x0c676be0U, 0x7c0b7790U, 0xb731865bU, 0x7284f69eU, + 0xa314b739U, 0xba4af020U, 0x5fd788c5U, 0x039c9f99U, + 0xcb66ad51U, 0x7fff80e5U, 0x0c535f96U, 0x26f1d7bcU, + 0xa0d4743aU, 0x22f4d6b8U, 0xa8de7632U, 0xf350a369U, + 0x58124ac2U, 0x178d9a8dU, 0x48064ed2U, 0xec8b6776U, + 0x541d49ceU, 0x656104ffU, 0x9268fa08U, 0x213415bbU, + 0x501848caU, 0x02dcde98U, 0xe88e6672U, 0xf755a26dU, + 0x5298cac8U, 0xe9ce2773U, 0xb4c5712eU, 0x602444faU, + 0xddf72a47U, 0xe204e678U, 0xe084647aU, 0x9e67f904U, + 0x8a76fc10U, 0xf1d0216bU, 0xb98a3323U, 0x2bbe95b1U, + 0xbe4ff124U, 0x47c98eddU, 0x9a62f800U, 0x1108198bU, + 0x346551aeU, 0xa99e3733U, 0xd4bd694eU, 0xf5d5206fU, + 0x4fc38cd5U, 0xc769ae5dU, 0x4a86ccd0U, 0x717001ebU, + 0x6bee85f1U, 0x36e5d3acU, 0x88f67e12U, 0x5e97c9c4U, + 0xdf77a845U, 0xd8b26a42U, 0x5bd289c1U, 0xae5bf534U, + 0xfa1ae060U, 0x8739be1dU, 0xaa5ef430U, 0x13889b89U, + 0x2d3b16b7U, 0xc629ef5cU, 0x04595d9eU, 0x62a4c6f8U, + 0xe5c1247fU, 0xe481657eU, 0x66a1c7fcU, 0x0b969d91U, + 0x37a592adU, 0x352510afU, 0xa4d1753eU, 0x12c8da88U, + 0xf615e36cU, 0x9da73a07U, 0x08565e92U, 0x9ce77b06U, + 0x63e487f9U, 0xee0be574U, 0xc5e92c5fU, 0x5a92c8c0U, + 0x59520bc3U, 0x555d08cfU, 0xfe1fe164U, 0x32e0d2a8U, + 0x3d2f12a7U, 0x696e07f3U, 0x9328bb09U, 0xd63deb4cU, + 0x1b829981U, 0x57dd8acdU, 0xc4a96d5eU, 0xd5fd284fU, + 0x392a13a3U, 0xa194353bU, 0x8e73fd14U, 0x2c7b57b6U, + 0x80fc7c1aU, 0x682e46f2U, 0xc0ac6c5aU, 0x81bc3d1bU, + 0x757500efU, 0x99a23b03U, 0xbf0fb025U, 0x72b0c2e8U, + 0x6c2b47f6U, 0x703040eaU, 0x09161f93U, 0x144d598eU, + 0xfc9f6366U, 0x7c3f43e6U, 0x19021b83U, 0xe601e77cU, + 0xab1eb531U, 0xf89a6262U, 0xe1c4257bU, 0xa591343fU, + 0x8679ff1cU, 0xb705b22dU, 0x642145feU, 0xb180312bU, + 0xc9e62f53U, 0x207454baU, 0xf090606aU, 0x67e186fdU, + 0x7abac0e0U, 0xeb4ea571U, 0xdb72a941U, 0x827cfe18U, + 0x53d88bc9U, 0x06d9df9cU, 0xd238ea48U, 0xb300b329U, + 0xf9da2363U, 0xe741a67dU, 0x18425a82U, 0x2efbd5b4U, + 0x76b5c3ecU, 0x27b196bdU, 0x33a093a9U, 0xc36caf59U, + 0x1f879885U, 0x7d7f02e7U, 0xacdb7736U, 0x7ebfc1e4U, + 0x7bfa81e1U, 0x428cced8U, 0x8db33e17U, 0x6aaec4f0U, + 0x966dfb0cU, 0x287e56b2U, 0x90e8780aU, 0xad9b3637U, + 0x4e83cdd4U, 0xb645f32cU, 0x306050aaU, 0x386a52a2U, + 0x2fbb94b5U, 0xca26ec50U, 0x3eefd1a4U, 0x77f582edU, + 0x8cf37f16U, 0x23b497b9U, 0x73f083e9U, 0x400c4cdaU, + 0xf210e268U, 0x616405fbU, 0xd378ab49U, 0x797a03e3U, + 0xfb5aa161U, 0x5c174bc6U, 0x743541eeU, 0x569dcbccU, + 0xcca36f56U, 0xb585302fU, 0xc1ec2d5bU, 0x45490cdfU, + 0xaf1bb435U, 0x972dba0dU, 0x247155beU, 0xedcb2677U, + 0x833cbf19U, 0x0f939c95U, 0xc22cee58U, 0x44094ddeU, + 0xf495616eU, 0x07999e9dU, 0x515809cbU, 0x312011abU, + 0x4d430ed7U, 0x49460fd3U, 0x95ad380fU, 0xbd8f3227U, + 0xce23ed54U, 0x94ed790eU, 0x4689cfdcU, 0xb240f228U, + 0x16cddb8cU, 0x8f33bc15U, 0x0ad6dc90U, 0x05191c9fU, + 0xbccf7326U, 0x9f27b805U, 0x89b63f13U, 0xfddf2267U, + 0x84f97d1eU, 0xb8ca7222U, 0x91a8390bU, 0x9b22b901U, + 0xd0b8684aU, 0xff5fa065U, 0x3c6f53a6U, 0xda32e840U, + 0x6eabc5f4U, 0xcf63ac55U, 0x150d188fU, 0x0ed3dd94U, + 0x4c034fd6U, 0x293e17b3U, 0xbb0ab121U, 0xb0c0702aU, + 0x1ac2d880U, 0x6feb84f5U, 0x2afed4b0U, 0x3aead0a0U, + 0xde37e944U, 0x5d570ac7U, 0xa651f73cU, 0xd1f8294bU, + 0xc8a66e52U, 0xa254f638U, 0x253114bfU, 0x011c1d9bU, + 0x6d6b06f7U, 0x1ec7d984U, 0x3faf90a5U, 0xdcb76b46U, + 0xef4ba475U, 0x414c0ddbU, 0xe344a779U, 0xea0ee470U, + 0x98e27a02U, 0x3baa91a1U, 0x0d131e97U, 0x4bc68dd1U, + 0x1048588aU, 0x8b36bd11U, 0xcde32e57U, 0x783a42e2U, + 0x1d071a87U, 0x43cc8fd9U, 0x85b93c1fU, 0x005c5c9aU, + 0xa711b63dU, 0xd77daa4dU, 0x1c475b86U, 0xd9f22b43U, + 0xc9f53cb2U, 0xd0ab7babU, 0x3536034eU, 0x697d1412U, + 0xa18726daU, 0x151e0b6eU, 0x66b2d41dU, 0x4c105c37U, + 0xca35ffb1U, 0x48155d33U, 0xc23ffdb9U, 0x99b128e2U, + 0x32f3c149U, 0x7d6c1106U, 0x22e7c559U, 0x866aecfdU, + 0x3efcc245U, 0x0f808f74U, 0xf8897183U, 0x4bd59e30U, + 0x3af9c341U, 0x683d5513U, 0x826fedf9U, 0x9db429e6U, + 0x38794143U, 0x832facf8U, 0xde24faa5U, 0x0ac5cf71U, + 0xb716a1ccU, 0x88e56df3U, 0x8a65eff1U, 0xf486728fU, + 0xe097779bU, 0x9b31aae0U, 0xd36bb8a8U, 0x415f1e3aU, + 0xd4ae7aafU, 0x2d280556U, 0xf083738bU, 0x7be99200U, + 0x5e84da25U, 0xc37fbcb8U, 0xbe5ce2c5U, 0x9f34abe4U, + 0x2522075eU, 0xad8825d6U, 0x2067475bU, 0x1b918a60U, + 0x010f0e7aU, 0x5c045827U, 0xe217f599U, 0x3476424fU, + 0xb59623ceU, 0xb253e1c9U, 0x3133024aU, 0xc4ba7ebfU, + 0x90fb6bebU, 0xedd83596U, 0xc0bf7fbbU, 0x79691002U, + 0x47da9d3cU, 0xacc864d7U, 0x6eb8d615U, 0x08454d73U, + 0x8f20aff4U, 0x8e60eef5U, 0x0c404c77U, 0x6177161aU, + 0x5d441926U, 0x5fc49b24U, 0xce30feb5U, 0x78295103U, + 0x9cf468e7U, 0xf746b18cU, 0x62b7d519U, 0xf606f08dU, + 0x09050c72U, 0x84ea6effU, 0xaf08a7d4U, 0x3073434bU, + 0x33b38048U, 0x3fbc8344U, 0x94fe6aefU, 0x58015923U, + 0x57ce992cU, 0x038f8c78U, 0xf9c93082U, 0xbcdc60c7U, + 0x7163120aU, 0x3d3c0146U, 0xae48e6d5U, 0xbf1ca3c4U, + 0x53cb9828U, 0xcb75beb0U, 0xe492769fU, 0x469adc3dU, + 0xea1df791U, 0x02cfcd79U, 0xaa4de7d1U, 0xeb5db690U, + 0x1f948b64U, 0xf343b088U, 0xd5ee3baeU, 0x18514963U, + 0x06cacc7dU, 0x1ad1cb61U, 0x63f79418U, 0x7eacd205U, + 0x967ee8edU, 0x16dec86dU, 0x73e39008U, 0x8ce06cf7U, + 0xc1ff3ebaU, 0x927be9e9U, 0x8b25aef0U, 0xcf70bfb4U, + 0xec987497U, 0xdde439a6U, 0x0ec0ce75U, 0xdb61baa0U, + 0xa307a4d8U, 0x4a95df31U, 0x9a71ebe1U, 0x0d000d76U, + 0x105b4b6bU, 0x81af2efaU, 0xb19322caU, 0xe89d7593U, + 0x39390042U, 0x6c385417U, 0xb8d961c3U, 0xd9e138a2U, + 0x933ba8e8U, 0x8da02df6U, 0x72a3d109U, 0x441a5e3fU, + 0x1c544867U, 0x4d501d36U, 0x59411822U, 0xa98d24d2U, + 0x7566130eU, 0x179e896cU, 0xc63afcbdU, 0x145e4a6fU, + 0x111b0a6aU, 0x286d4553U, 0xe752b59cU, 0x004f4f7bU, + 0xfc8c7087U, 0x429fdd39U, 0xfa09f381U, 0xc77abdbcU, + 0x2462465fU, 0xdca478a7U, 0x5a81db21U, 0x528bd929U, + 0x455a1f3eU, 0xa0c767dbU, 0x540e5a2fU, 0x1d140966U, + 0xe612f49dU, 0x49551c32U, 0x19110862U, 0x2aedc751U, + 0x98f169e3U, 0x0b858e70U, 0xb99920c2U, 0x139b8868U, + 0x91bb2aeaU, 0x36f6c04dU, 0x1ed4ca65U, 0x3c7c4047U, + 0xa642e4ddU, 0xdf64bba4U, 0xab0da6d0U, 0x2fa88754U, + 0xc5fa3fbeU, 0xfdcc3186U, 0x4e90de35U, 0x872aadfcU, + 0xe9dd3492U, 0x6572171eU, 0xa8cd65d3U, 0x2ee8c655U, + 0x9e74eae5U, 0x6d781516U, 0x3bb98240U, 0x5bc19a20U, + 0x27a2855cU, 0x23a78458U, 0xff4cb384U, 0xd76eb9acU, + 0xa4c266dfU, 0xfe0cf285U, 0x2c684457U, 0xd8a179a3U, + 0x7c2c5007U, 0xe5d2379eU, 0x6037571bU, 0x6ff89714U, + 0xd62ef8adU, 0xf5c6338eU, 0xe357b498U, 0x973ea9ecU, + 0xee18f695U, 0xd22bf9a9U, 0xfb49b280U, 0xf1c3328aU, + 0xba59e3c1U, 0x95be2beeU, 0x568ed82dU, 0xb0d363cbU, + 0x044a4e7fU, 0xa58227deU, 0x7fec9304U, 0x6432561fU, + 0x26e2c45dU, 0x43df9c38U, 0xd1eb3aaaU, 0xda21fba1U, + 0x7023530bU, 0x050a0f7eU, 0x401f5f3bU, 0x500b5b2bU, + 0xb4d662cfU, 0x37b6814cU, 0xccb07cb7U, 0xbb19a2c0U, + 0xa247e5d9U, 0xc8b57db3U, 0x4fd09f34U, 0x6bfd9610U, + 0x078a8d7cU, 0x7426520fU, 0x554e1b2eU, 0xb656e0cdU, + 0x85aa2ffeU, 0x2bad8650U, 0x89a52cf2U, 0x80ef6ffbU, + 0xf203f189U, 0x514b1a2aU, 0x67f2951cU, 0x2127065aU, + 0x7aa9d301U, 0xe1d7369aU, 0xa702a5dcU, 0x12dbc969U, + 0x77e6910cU, 0x292d0452U, 0xef58b794U, 0x6abdd711U, + 0xcdf03db6U, 0xbd9c21c6U, 0x76a6d00dU, 0xb313a0c8U, + 0xa4bd1997U, 0xbde35e8eU, 0x587e266bU, 0x04353137U, + 0xcccf03ffU, 0x78562e4bU, 0x0bfaf138U, 0x21587912U, + 0xa77dda94U, 0x255d7816U, 0xaf77d89cU, 0xf4f90dc7U, + 0x5fbbe46cU, 0x10243423U, 0x4fafe07cU, 0xeb22c9d8U, + 0x53b4e760U, 0x62c8aa51U, 0x95c154a6U, 0x269dbb15U, + 0x57b1e664U, 0x05757036U, 0xef27c8dcU, 0xf0fc0cc3U, + 0x55316466U, 0xee6789ddU, 0xb36cdf80U, 0x678dea54U, + 0xda5e84e9U, 0xe5ad48d6U, 0xe72dcad4U, 0x99ce57aaU, + 0x8ddf52beU, 0xf6798fc5U, 0xbe239d8dU, 0x2c173b1fU, + 0xb9e65f8aU, 0x40602073U, 0x9dcb56aeU, 0x16a1b725U, + 0x33ccff00U, 0xae37999dU, 0xd314c7e0U, 0xf27c8ec1U, + 0x486a227bU, 0xc0c000f3U, 0x4d2f627eU, 0x76d9af45U, + 0x6c472b5fU, 0x314c7d02U, 0x8f5fd0bcU, 0x593e676aU, + 0xd8de06ebU, 0xdf1bc4ecU, 0x5c7b276fU, 0xa9f25b9aU, + 0xfdb34eceU, 0x809010b3U, 0xadf75a9eU, 0x14213527U, + 0x2a92b819U, 0xc18041f2U, 0x03f0f330U, 0x650d6856U, + 0xe2688ad1U, 0xe328cbd0U, 0x61086952U, 0x0c3f333fU, + 0x300c3c03U, 0x328cbe01U, 0xa378db90U, 0x15617426U, + 0xf1bc4dc2U, 0x9a0e94a9U, 0x0ffff03cU, 0x9b4ed5a8U, + 0x644d2957U, 0xe9a24bdaU, 0xc24082f1U, 0x5d3b666eU, + 0x5efba56dU, 0x52f4a661U, 0xf9b64fcaU, 0x35497c06U, + 0x3a86bc09U, 0x6ec7a95dU, 0x948115a7U, 0xd19445e2U, + 0x1c2b372fU, 0x50742463U, 0xc300c3f0U, 0xd25486e1U, + 0x3e83bd0dU, 0xa63d9b95U, 0x89da53baU, 0x2bd2f918U, + 0x8755d2b4U, 0x6f87e85cU, 0xc705c2f4U, 0x861593b5U, + 0x72dcae41U, 0x9e0b95adU, 0xb8a61e8bU, 0x75196c46U, + 0x6b82e958U, 0x7799ee44U, 0x0ebfb13dU, 0x13e4f720U, + 0xfb36cdc8U, 0x7b96ed48U, 0x1eabb52dU, 0xe1a849d2U, + 0xacb71b9fU, 0xff33ccccU, 0xe66d8bd5U, 0xa2389a91U, + 0x81d051b2U, 0xb0ac1c83U, 0x6388eb50U, 0xb6299f85U, + 0xce4f81fdU, 0x27ddfa14U, 0xf739cec4U, 0x60482853U, + 0x7d136e4eU, 0xece70bdfU, 0xdcdb07efU, 0x85d550b6U, + 0x54712567U, 0x01707132U, 0xd59144e6U, 0xb4a91d87U, + 0xfe738dcdU, 0xe0e808d3U, 0x1febf42cU, 0x29527b1aU, + 0x711c6d42U, 0x20183813U, 0x34093d07U, 0xc4c501f7U, + 0x182e362bU, 0x7ad6ac49U, 0xab72d998U, 0x79166f4aU, + 0x7c532f4fU, 0x45256076U, 0x8a1a90b9U, 0x6d076a5eU, + 0x91c455a2U, 0x2fd7f81cU, 0x9741d6a4U, 0xaa329899U, + 0x492a637aU, 0xb1ec5d82U, 0x37c9fe04U, 0x3fc3fc0cU, + 0x28123a1bU, 0xcd8f42feU, 0x39467f0aU, 0x705c2c43U, + 0x8b5ad1b8U, 0x241d3917U, 0x74592d47U, 0x47a5e274U, + 0xf5b94cc6U, 0x66cdab55U, 0xd4d105e7U, 0x7ed3ad4dU, + 0xfcf30fcfU, 0x5bbee568U, 0x739cef40U, 0x51346562U, + 0xcb0ac1f8U, 0xb22c9e81U, 0xc64583f5U, 0x42e0a271U, + 0xa8b21a9bU, 0x908414a3U, 0x23d8fb10U, 0xea6288d9U, + 0x849511b7U, 0x083a323bU, 0xc58540f6U, 0x43a0e370U, + 0xf33ccfc0U, 0x00303033U, 0x56f1a765U, 0x3689bf05U, + 0x4aeaa079U, 0x4eefa17dU, 0x920496a1U, 0xba269c89U, + 0xc98a43faU, 0x9344d7a0U, 0x41206172U, 0xb5e95c86U, + 0x11647522U, 0x889a12bbU, 0x0d7f723eU, 0x02b0b231U, + 0xbb66dd88U, 0x988e16abU, 0x8e1f91bdU, 0xfa768cc9U, + 0x8350d3b0U, 0xbf63dc8cU, 0x960197a5U, 0x9c8b17afU, + 0xd711c6e4U, 0xf8f60ecbU, 0x3bc6fd08U, 0xdd9b46eeU, + 0x69026b5aU, 0xc8ca02fbU, 0x12a4b621U, 0x097a733aU, + 0x4baae178U, 0x2e97b91dU, 0xbca31f8fU, 0xb769de84U, + 0x1d6b762eU, 0x68422a5bU, 0x2d577a1eU, 0x3d437e0eU, + 0xd99e47eaU, 0x5afea469U, 0xa1f85992U, 0xd65187e5U, + 0xcf0fc0fcU, 0xa5fd5896U, 0x2298ba11U, 0x06b5b335U, + 0x6ac2a859U, 0x196e772aU, 0x38063e0bU, 0xdb1ec5e8U, + 0xe8e20adbU, 0x46e5a375U, 0xe4ed09d7U, 0xeda74adeU, + 0x9f4bd4acU, 0x3c033f0fU, 0x0abab039U, 0x4c6f237fU, + 0x17e1f624U, 0x8c9f13bfU, 0xca4a80f9U, 0x7f93ec4cU, + 0x1aaeb429U, 0x44652177U, 0x821092b1U, 0x07f5f234U, + 0xa0b81893U, 0xd0d404e3U, 0x1beef528U, 0xde5b85edU, + 0x5fdb840aU, 0x4685c313U, 0xa318bbf6U, 0xff53acaaU, + 0x37a99e62U, 0x8330b3d6U, 0xf09c6ca5U, 0xda3ee48fU, + 0x5c1b4709U, 0xde3be58bU, 0x54114501U, 0x0f9f905aU, + 0xa4dd79f1U, 0xeb42a9beU, 0xb4c97de1U, 0x10445445U, + 0xa8d27afdU, 0x99ae37ccU, 0x6ea7c93bU, 0xddfb2688U, + 0xacd77bf9U, 0xfe13edabU, 0x14415541U, 0x0b9a915eU, + 0xae57f9fbU, 0x15011440U, 0x480a421dU, 0x9ceb77c9U, + 0x21381974U, 0x1ecbd54bU, 0x1c4b5749U, 0x62a8ca37U, + 0x76b9cf23U, 0x0d1f1258U, 0x45450010U, 0xd771a682U, + 0x4280c217U, 0xbb06bdeeU, 0x66adcb33U, 0xedc72ab8U, + 0xc8aa629dU, 0x55510400U, 0x28725a7dU, 0x091a135cU, + 0xb30cbfe6U, 0x3ba69d6eU, 0xb649ffe3U, 0x8dbf32d8U, + 0x9721b6c2U, 0xca2ae09fU, 0x74394d21U, 0xa258faf7U, + 0x23b89b76U, 0x247d5971U, 0xa71dbaf2U, 0x5294c607U, + 0x06d5d353U, 0x7bf68d2eU, 0x5691c703U, 0xef47a8baU, + 0xd1f42584U, 0x3ae6dc6fU, 0xf8966eadU, 0x9e6bf5cbU, + 0x190e174cU, 0x184e564dU, 0x9a6ef4cfU, 0xf759aea2U, + 0xcb6aa19eU, 0xc9ea239cU, 0x581e460dU, 0xee07e9bbU, + 0x0adad05fU, 0x61680934U, 0xf4996da1U, 0x60284835U, + 0x9f2bb4caU, 0x12c4d647U, 0x39261f6cU, 0xa65dfbf3U, + 0xa59d38f0U, 0xa9923bfcU, 0x02d0d257U, 0xce2fe19bU, + 0xc1e02194U, 0x95a134c0U, 0x6fe7883aU, 0x2af2d87fU, + 0xe74daab2U, 0xab12b9feU, 0x38665e6dU, 0x29321b7cU, + 0xc5e52090U, 0x5d5b0608U, 0x72bcce27U, 0xd0b46485U, + 0x7c334f29U, 0x94e175c1U, 0x3c635f69U, 0x7d730e28U, + 0x89ba33dcU, 0x656d0830U, 0x43c08316U, 0x8e7ff1dbU, + 0x90e474c5U, 0x8cff73d9U, 0xf5d92ca0U, 0xe8826abdU, + 0x00505055U, 0x80f070d5U, 0xe5cd28b0U, 0x1aced44fU, + 0x57d18602U, 0x04555151U, 0x1d0b1648U, 0x595e070cU, + 0x7ab6cc2fU, 0x4bca811eU, 0x98ee76cdU, 0x4d4f0218U, + 0x35291c60U, 0xdcbb6789U, 0x0c5f5359U, 0x9b2eb5ceU, + 0x8675f3d3U, 0x17819642U, 0x27bd9a72U, 0x7eb3cd2bU, + 0xaf17b8faU, 0xfa16ecafU, 0x2ef7d97bU, 0x4fcf801aU, + 0x05151050U, 0x1b8e954eU, 0xe48d69b1U, 0xd234e687U, + 0x8a7af0dfU, 0xdb7ea58eU, 0xcf6fa09aU, 0x3fa39c6aU, + 0xe348abb6U, 0x81b031d4U, 0x50144405U, 0x8270f2d7U, + 0x8735b2d2U, 0xbe43fdebU, 0x717c0d24U, 0x9661f7c3U, + 0x6aa2c83fU, 0xd4b16581U, 0x6c274b39U, 0x51540504U, + 0xb24cfee7U, 0x4a8ac01fU, 0xccaf6399U, 0xc4a56191U, + 0xd374a786U, 0x36e9df63U, 0xc220e297U, 0x8b3ab1deU, + 0x703c4c25U, 0xdf7ba48aU, 0x8f3fb0daU, 0xbcc37fe9U, + 0x0edfd15bU, 0x9dab36c8U, 0x2fb7987aU, 0x85b530d0U, + 0x07959252U, 0xa0d878f5U, 0x88fa72ddU, 0xaa52f8ffU, + 0x306c5c65U, 0x494a031cU, 0x3d231e68U, 0xb9863fecU, + 0x53d48706U, 0x6be2893eU, 0xd8be668dU, 0x11041544U, + 0x7ff38c2aU, 0xf35cafa6U, 0x3ee3dd6bU, 0xb8c67eedU, + 0x085a525dU, 0xfb56adaeU, 0xad973af8U, 0xcdef2298U, + 0xb18c3de4U, 0xb5893ce0U, 0x69620b3cU, 0x41400114U, + 0x32ecde67U, 0x68224a3dU, 0xba46fcefU, 0x4e8fc11bU, + 0xea02e8bfU, 0x73fc8f26U, 0xf619efa3U, 0xf9d62facU, + 0x40004015U, 0x63e88b36U, 0x75790c20U, 0x01101154U, + 0x78364e2dU, 0x44054111U, 0x6d670a38U, 0x67ed8a32U, + 0x2c775b79U, 0x03909356U, 0xc0a06095U, 0x26fddb73U, + 0x9264f6c7U, 0x33ac9f66U, 0xe9c22bbcU, 0xf21ceea7U, + 0xb0cc7ce5U, 0xd5f12480U, 0x47c58212U, 0x4c0f4319U, + 0xe60debb3U, 0x9324b7c6U, 0xd631e783U, 0xc625e393U, + 0x22f8da77U, 0xa19839f4U, 0x5a9ec40fU, 0x2d371a78U, + 0x34695d61U, 0x5e9bc50bU, 0xd9fe278cU, 0xfdd32ea8U, + 0x91a435c4U, 0xe208eab7U, 0xc360a396U, 0x20785875U, + 0x13849746U, 0xbd833ee8U, 0x1f8b944aU, 0x16c1d743U, + 0x642d4931U, 0xc765a292U, 0xf1dc2da4U, 0xb709bee2U, + 0xec876bb9U, 0x77f98e22U, 0x312c1d64U, 0x84f571d1U, + 0xe1c829b4U, 0xbf03bceaU, 0x79760f2cU, 0xfc936fa9U, + 0x5bde850eU, 0x2bb2997eU, 0xe08868b5U, 0x253d1870U, + 0x7c85f977U, 0x65dbbe6eU, 0x8046c68bU, 0xdc0dd1d7U, + 0x14f7e31fU, 0xa06eceabU, 0xd3c211d8U, 0xf96099f2U, + 0x7f453a74U, 0xfd6598f6U, 0x774f387cU, 0x2cc1ed27U, + 0x8783048cU, 0xc81cd4c3U, 0x9797009cU, 0x331a2938U, + 0x8b8c0780U, 0xbaf04ab1U, 0x4df9b446U, 0xfea55bf5U, + 0x8f890684U, 0xdd4d90d6U, 0x371f283cU, 0x28c4ec23U, + 0x8d098486U, 0x365f693dU, 0x6b543f60U, 0xbfb50ab4U, + 0x02666409U, 0x3d95a836U, 0x3f152a34U, 0x41f6b74aU, + 0x55e7b25eU, 0x2e416f25U, 0x661b7d6dU, 0xf42fdbffU, + 0x61debf6aU, 0x9858c093U, 0x45f3b64eU, 0xce9957c5U, + 0xebf41fe0U, 0x760f797dU, 0x0b2c2700U, 0x2a446e21U, + 0x9052c29bU, 0x18f8e013U, 0x9517829eU, 0xaee14fa5U, + 0xb47fcbbfU, 0xe9749de2U, 0x5767305cU, 0x8106878aU, + 0x00e6e60bU, 0x0723240cU, 0x8443c78fU, 0x71cabb7aU, + 0x258bae2eU, 0x58a8f053U, 0x75cfba7eU, 0xcc19d5c7U, + 0xf2aa58f9U, 0x19b8a112U, 0xdbc813d0U, 0xbd3588b6U, + 0x3a506a31U, 0x3b102b30U, 0xb93089b2U, 0xd407d3dfU, + 0xe834dce3U, 0xeab45ee1U, 0x7b403b70U, 0xcd5994c6U, + 0x2984ad22U, 0x42367449U, 0xd7c710dcU, 0x43763548U, + 0xbc75c9b7U, 0x319aab3aU, 0x1a786211U, 0x8503868eU, + 0x86c3458dU, 0x8acc4681U, 0x218eaf2aU, 0xed719ce6U, + 0xe2be5ce9U, 0xb6ff49bdU, 0x4cb9f547U, 0x09aca502U, + 0xc413d7cfU, 0x884cc483U, 0x1b382310U, 0x0a6c6601U, + 0xe6bb5dedU, 0x7e057b75U, 0x51e2b35aU, 0xf3ea19f8U, + 0x5f6d3254U, 0xb7bf08bcU, 0x1f3d2214U, 0x5e2d7355U, + 0xaae44ea1U, 0x4633754dU, 0x609efe6bU, 0xad218ca6U, + 0xb3ba09b8U, 0xafa10ea4U, 0xd68751ddU, 0xcbdc17c0U, + 0x230e2d28U, 0xa3ae0da8U, 0xc69355cdU, 0x3990a932U, + 0x748ffb7fU, 0x270b2c2cU, 0x3e556b35U, 0x7a007a71U, + 0x59e8b152U, 0x6894fc63U, 0xbbb00bb0U, 0x6e117f65U, + 0x1677611dU, 0xffe51af4U, 0x2f012e24U, 0xb870c8b3U, + 0xa52b8eaeU, 0x34dfeb3fU, 0x04e3e70fU, 0x5dedb056U, + 0x8c49c587U, 0xd94891d2U, 0x0da9a406U, 0x6c91fd67U, + 0x264b6d2dU, 0x38d0e833U, 0xc7d314ccU, 0xf16a9bfaU, + 0xa9248da2U, 0xf820d8f3U, 0xec31dde7U, 0x1cfde117U, + 0xc016d6cbU, 0xa2ee4ca9U, 0x734a3978U, 0xa12e8faaU, + 0xa46bcfafU, 0x9d1d8096U, 0x52227059U, 0xb53f8abeU, + 0x49fcb542U, 0xf7ef18fcU, 0x4f793644U, 0x720a7879U, + 0x9112839aU, 0x69d4bd62U, 0xeff11ee4U, 0xe7fb1cecU, + 0xf02adafbU, 0x15b7a21eU, 0xe17e9feaU, 0xa864cca3U, + 0x53623158U, 0xfc25d9f7U, 0xac61cda7U, 0x9f9d0294U, + 0x2d81ac26U, 0xbef54bb5U, 0x0ce9e507U, 0xa6eb4dadU, + 0x24cbef2fU, 0x83860588U, 0xaba40fa0U, 0x890c8582U, + 0x13322118U, 0x6a147e61U, 0x1e7d6315U, 0x9ad84291U, + 0x708afa7bU, 0x48bcf443U, 0xfbe01bf0U, 0x325a6839U, + 0x5cadf157U, 0xd002d2dbU, 0x1dbda016U, 0x9b980390U, + 0x2b042f20U, 0xd808d0d3U, 0x8ec94785U, 0xeeb15fe5U, + 0x92d24099U, 0x96d7419dU, 0x4a3c7641U, 0x621e7c69U, + 0x11b2a31aU, 0x4b7c3740U, 0x99188192U, 0x6dd1bc66U, + 0xc95c95c2U, 0x50a2f25bU, 0xd54792deU, 0xda8852d1U, + 0x635e3d68U, 0x40b6f64bU, 0x5627715dU, 0x224e6c29U, + 0x5b683350U, 0x675b3c6cU, 0x4e397745U, 0x44b3f74fU, + 0x0f292604U, 0x20ceee2bU, 0xe3fe1de8U, 0x05a3a60eU, + 0xb13a8bbaU, 0x10f2e21bU, 0xca9c56c1U, 0xd14293daU, + 0x93920198U, 0xf6af59fdU, 0x649bff6fU, 0x6f513e64U, + 0xc55396ceU, 0xb07acabbU, 0xf56f9afeU, 0xe57b9eeeU, + 0x01a6a70aU, 0x82c64489U, 0x79c0b972U, 0x0e696705U, + 0x1737201cU, 0x7dc5b876U, 0xfaa05af1U, 0xde8d53d5U, + 0xb2fa48b9U, 0xc15697caU, 0xe03edeebU, 0x03262508U, + 0x30daea3bU, 0x9edd4395U, 0x3cd5e937U, 0x359faa3eU, + 0x4773344cU, 0xe43bdfefU, 0xd28250d9U, 0x9457c39fU, + 0xcfd916c4U, 0x54a7f35fU, 0x12726019U, 0xa7ab0cacU, + 0xc29654c9U, 0x9c5dc197U, 0x5a287251U, 0xdfcd12d4U, + 0x7880f873U, 0x08ece403U, 0xc3d615c8U, 0x0663650dU, + 0x14ccd856U, 0x0d929f4fU, 0xe80fe7aaU, 0xb444f0f6U, + 0x7cbec23eU, 0xc827ef8aU, 0xbb8b30f9U, 0x9129b8d3U, + 0x170c1b55U, 0x952cb9d7U, 0x1f06195dU, 0x4488cc06U, + 0xefca25adU, 0xa055f5e2U, 0xffde21bdU, 0x5b530819U, + 0xe3c526a1U, 0xd2b96b90U, 0x25b09567U, 0x96ec7ad4U, + 0xe7c027a5U, 0xb504b1f7U, 0x5f56091dU, 0x408dcd02U, + 0xe540a5a7U, 0x5e16481cU, 0x031d1e41U, 0xd7fc2b95U, + 0x6a2f4528U, 0x55dc8917U, 0x575c0b15U, 0x29bf966bU, + 0x3dae937fU, 0x46084e04U, 0x0e525c4cU, 0x9c66fadeU, + 0x09979e4bU, 0xf011e1b2U, 0x2dba976fU, 0xa6d076e4U, + 0x83bd3ec1U, 0x1e46585cU, 0x63650621U, 0x420d4f00U, + 0xf81be3baU, 0x70b1c132U, 0xfd5ea3bfU, 0xc6a86e84U, + 0xdc36ea9eU, 0x813dbcc3U, 0x3f2e117dU, 0xe94fa6abU, + 0x68afc72aU, 0x6f6a052dU, 0xec0ae6aeU, 0x19839a5bU, + 0x4dc28f0fU, 0x30e1d172U, 0x1d869b5fU, 0xa450f4e6U, + 0x9ae379d8U, 0x71f18033U, 0xb38132f1U, 0xd57ca997U, + 0x52194b10U, 0x53590a11U, 0xd179a893U, 0xbc4ef2feU, + 0x807dfdc2U, 0x82fd7fc0U, 0x13091a51U, 0xa510b5e7U, + 0x41cd8c03U, 0x2a7f5568U, 0xbf8e31fdU, 0x2b3f1469U, + 0xd43ce896U, 0x59d38a1bU, 0x72314330U, 0xed4aa7afU, + 0xee8a64acU, 0xe28567a0U, 0x49c78e0bU, 0x8538bdc7U, + 0x8af77dc8U, 0xdeb6689cU, 0x24f0d466U, 0x61e58423U, + 0xac5af6eeU, 0xe005e5a2U, 0x73710231U, 0x62254720U, + 0x8ef27cccU, 0x164c5a54U, 0x39ab927bU, 0x9ba338d9U, + 0x37241375U, 0xdff6299dU, 0x77740335U, 0x36645274U, + 0xc2ad6f80U, 0x2e7a546cU, 0x08d7df4aU, 0xc568ad87U, + 0xdbf32899U, 0xc7e82f85U, 0xbece70fcU, 0xa39536e1U, + 0x4b470c09U, 0xcbe72c89U, 0xaeda74ecU, 0x51d98813U, + 0x1cc6da5eU, 0x4f420d0dU, 0x561c4a14U, 0x12495b50U, + 0x31a19073U, 0x00dddd42U, 0xd3f92a91U, 0x06585e44U, + 0x7e3e403cU, 0x97ac3bd5U, 0x47480f05U, 0xd039e992U, + 0xcd62af8fU, 0x5c96ca1eU, 0x6caac62eU, 0x35a49177U, + 0xe400e4a6U, 0xb101b0f3U, 0x65e08527U, 0x04d8dc46U, + 0x4e024c0cU, 0x5099c912U, 0xaf9a35edU, 0x9923badbU, + 0xc16dac83U, 0x9069f9d2U, 0x8478fcc6U, 0x74b4c036U, + 0xa85ff7eaU, 0xcaa76d88U, 0x1b031859U, 0xc967ae8bU, + 0xcc22ee8eU, 0xf554a1b7U, 0x3a6b5178U, 0xdd76ab9fU, + 0x21b59463U, 0x9fa639ddU, 0x27301765U, 0x1a435958U, + 0xf95ba2bbU, 0x019d9c43U, 0x87b83fc5U, 0x8fb23dcdU, + 0x9863fbdaU, 0x7dfe833fU, 0x8937becbU, 0xc02ded82U, + 0x3b2b1079U, 0x946cf8d6U, 0xc428ec86U, 0xf7d423b5U, + 0x45c88d07U, 0xd6bc6a94U, 0x64a0c426U, 0xcea26c8cU, + 0x4c82ce0eU, 0xebcf24a9U, 0xc3ed2e81U, 0xe145a4a3U, + 0x7b7b0039U, 0x025d5f40U, 0x76344234U, 0xf29163b0U, + 0x18c3db5aU, 0x20f5d562U, 0x93a93ad1U, 0x5a134918U, + 0x34e4d076U, 0xb84bf3faU, 0x75f48137U, 0xf3d122b1U, + 0x434d0e01U, 0xb041f1f2U, 0xe68066a4U, 0x86f87ec4U, + 0xfa9b61b8U, 0xfe9e60bcU, 0x22755760U, 0x0a575d48U, + 0x79fb823bU, 0x23351661U, 0xf151a0b3U, 0x05989d47U, + 0xa115b4e3U, 0x38ebd37aU, 0xbd0eb3ffU, 0xb2c173f0U, + 0x0b171c49U, 0x28ffd76aU, 0x3e6e507cU, 0x4a074d08U, + 0x33211271U, 0x0f121d4dU, 0x26705664U, 0x2cfad66eU, + 0x67600725U, 0x4887cf0aU, 0x8bb73cc9U, 0x6dea872fU, + 0xd973aa9bU, 0x78bbc33aU, 0xa2d577e0U, 0xb90bb2fbU, + 0xfbdb20b9U, 0x9ee678dcU, 0x0cd2de4eU, 0x07181f45U, + 0xad1ab7efU, 0xd833eb9aU, 0x9d26bbdfU, 0x8d32bfcfU, + 0x69ef862bU, 0xea8f65a8U, 0x11899853U, 0x66204624U, + 0x7f7e013dU, 0x158c9957U, 0x92e97bd0U, 0xb6c472f4U, + 0xdab36998U, 0xa91fb6ebU, 0x8877ffcaU, 0x6b6f0429U, + 0x5893cb1aU, 0xf69462b4U, 0x549cc816U, 0x5dd68b1fU, + 0x2f3a156dU, 0x8c72feceU, 0xbacb71f8U, 0xfc1ee2beU, + 0xa79037e5U, 0x3ceed27eU, 0x7a3b4138U, 0xcfe22d8dU, + 0xaadf75e8U, 0xf414e0b6U, 0x32615370U, 0xb78433f5U, + 0x10c9d952U, 0x60a5c522U, 0xab9f34e9U, 0x6e2a442cU, + 0x026062ecU, 0x1b3e25f5U, 0xfea35d10U, 0xa2e84a4cU, + 0x6a127884U, 0xde8b5530U, 0xad278a43U, 0x87850269U, + 0x01a0a1efU, 0x8380036dU, 0x09aaa3e7U, 0x522476bcU, + 0xf9669f17U, 0xb6f94f58U, 0xe9729b07U, 0x4dffb2a3U, + 0xf5699c1bU, 0xc415d12aU, 0x331c2fddU, 0x8040c06eU, + 0xf16c9d1fU, 0xa3a80b4dU, 0x49fab3a7U, 0x562177b8U, + 0xf3ec1f1dU, 0x48baf2a6U, 0x15b1a4fbU, 0xc150912fU, + 0x7c83ff92U, 0x437033adU, 0x41f0b1afU, 0x3f132cd1U, + 0x2b0229c5U, 0x50a4f4beU, 0x18fee6f6U, 0x8aca4064U, + 0x1f3b24f1U, 0xe6bd5b08U, 0x3b162dd5U, 0xb07ccc5eU, + 0x9511847bU, 0x08eae2e6U, 0x75c9bc9bU, 0x54a1f5baU, + 0xeeb75900U, 0x661d7b88U, 0xebf21905U, 0xd004d43eU, + 0xca9a5024U, 0x97910679U, 0x2982abc7U, 0xffe31c11U, + 0x7e037d90U, 0x79c6bf97U, 0xfaa65c14U, 0x0f2f20e1U, + 0x5b6e35b5U, 0x264d6bc8U, 0x0b2a21e5U, 0xb2fc4e5cU, + 0x8c4fc362U, 0x675d3a89U, 0xa52d884bU, 0xc3d0132dU, + 0x44b5f1aaU, 0x45f5b0abU, 0xc7d51229U, 0xaae24844U, + 0x96d14778U, 0x9451c57aU, 0x05a5a0ebU, 0xb3bc0f5dU, + 0x576136b9U, 0x3cd3efd2U, 0xa9228b47U, 0x3d93aed3U, + 0xc290522cU, 0x4f7f30a1U, 0x649df98aU, 0xfbe61d15U, + 0xf826de16U, 0xf429dd1aU, 0x5f6b34b1U, 0x9394077dU, + 0x9c5bc772U, 0xc81ad226U, 0x325c6edcU, 0x77493e99U, + 0xbaf64c54U, 0xf6a95f18U, 0x65ddb88bU, 0x7489fd9aU, + 0x985ec676U, 0x00e0e0eeU, 0x2f0728c1U, 0x8d0f8263U, + 0x2188a9cfU, 0xc95a9327U, 0x61d8b98fU, 0x20c8e8ceU, + 0xd401d53aU, 0x38d6eed6U, 0x1e7b65f0U, 0xd3c4173dU, + 0xcd5f9223U, 0xd144953fU, 0xa862ca46U, 0xb5398c5bU, + 0x5debb6b3U, 0xdd4b9633U, 0xb876ce56U, 0x477532a9U, + 0x0a6a60e4U, 0x59eeb7b7U, 0x40b0f0aeU, 0x04e5e1eaU, + 0x270d2ac9U, 0x167167f8U, 0xc555902bU, 0x10f4e4feU, + 0x6892fa86U, 0x8100816fU, 0x51e4b5bfU, 0xc6955328U, + 0xdbce1535U, 0x4a3a70a4U, 0x7a067c94U, 0x23082bcdU, + 0xf2ac5e1cU, 0xa7ad0a49U, 0x734c3f9dU, 0x127466fcU, + 0x58aef6b6U, 0x463573a8U, 0xb9368f57U, 0x8f8f0061U, + 0xd7c11639U, 0x86c54368U, 0x92d4467cU, 0x62187a8cU, + 0xbef34d50U, 0xdc0bd732U, 0x0dafa2e3U, 0xdfcb1431U, + 0xda8e5434U, 0xe3f81b0dU, 0x2cc7ebc2U, 0xcbda1125U, + 0x37192ed9U, 0x890a8367U, 0x319caddfU, 0x0cefe3e2U, + 0xeff71801U, 0x173126f9U, 0x9114857fU, 0x991e8777U, + 0x8ecf4160U, 0x6b523985U, 0x9f9b0471U, 0xd6815738U, + 0x2d87aac3U, 0x82c0426cU, 0xd284563cU, 0xe178990fU, + 0x536437bdU, 0xc010d02eU, 0x720c7e9cU, 0xd80ed636U, + 0x5a2e74b4U, 0xfd639e13U, 0xd541943bU, 0xf7e91e19U, + 0x6dd7ba83U, 0x14f1e5faU, 0x6098f88eU, 0xe43dd90aU, + 0x0e6f61e0U, 0x36596fd8U, 0x8505806bU, 0x4cbff3a2U, + 0x22486accU, 0xaee74940U, 0x63583b8dU, 0xe57d980bU, + 0x55e1b4bbU, 0xa6ed4b48U, 0xf02cdc1eU, 0x9054c47eU, + 0xec37db02U, 0xe832da06U, 0x34d9eddaU, 0x1cfbe7f2U, + 0x6f573881U, 0x3599acdbU, 0xe7fd1a09U, 0x133427fdU, + 0xb7b90e59U, 0x2e4769c0U, 0xaba20945U, 0xa46dc94aU, + 0x1dbba6f3U, 0x3e536dd0U, 0x28c2eac6U, 0x5cabf7b2U, + 0x258da8cbU, 0x19bea7f7U, 0x30dcecdeU, 0x3a566cd4U, + 0x71ccbd9fU, 0x5e2b75b0U, 0x9d1b8673U, 0x7b463d95U, + 0xcfdf1021U, 0x6e177980U, 0xb479cd5aU, 0xafa70841U, + 0xed779a03U, 0x884ac266U, 0x1a7e64f4U, 0x11b4a5ffU, + 0xbbb60d55U, 0xce9f5120U, 0x8b8a0165U, 0x9b9e0575U, + 0x7f433c91U, 0xfc23df12U, 0x072522e9U, 0x708cfc9eU, + 0x69d2bb87U, 0x032023edU, 0x8445c16aU, 0xa068c84eU, + 0xcc1fd322U, 0xbfb30c51U, 0x9edb4570U, 0x7dc3be93U, + 0x4e3f71a0U, 0xe038d80eU, 0x423072acU, 0x4b7a31a5U, + 0x3996afd7U, 0x9ade4474U, 0xac67cb42U, 0xeab25804U, + 0xb13c8d5fU, 0x2a4268c4U, 0x6c97fb82U, 0xd94e9737U, + 0xbc73cf52U, 0xe2b85a0cU, 0x24cde9caU, 0xa128894fU, + 0x066563e8U, 0x76097f98U, 0xbd338e53U, 0x7886fe96U, + 0xa842ea64U, 0xb11cad7dU, 0x5481d598U, 0x08cac2c4U, + 0xc030f00cU, 0x74a9ddb8U, 0x070502cbU, 0x2da78ae1U, + 0xab822967U, 0x29a28be5U, 0xa3882b6fU, 0xf806fe34U, + 0x5344179fU, 0x1cdbc7d0U, 0x4350138fU, 0xe7dd3a2bU, + 0x5f4b1493U, 0x6e3759a2U, 0x993ea755U, 0x2a6248e6U, + 0x5b4e1597U, 0x098a83c5U, 0xe3d83b2fU, 0xfc03ff30U, + 0x59ce9795U, 0xe2987a2eU, 0xbf932c73U, 0x6b7219a7U, + 0xd6a1771aU, 0xe952bb25U, 0xebd23927U, 0x9531a459U, + 0x8120a14dU, 0xfa867c36U, 0xb2dc6e7eU, 0x20e8c8ecU, + 0xb519ac79U, 0x4c9fd380U, 0x9134a55dU, 0x1a5e44d6U, + 0x3f330cf3U, 0xa2c86a6eU, 0xdfeb3413U, 0xfe837d32U, + 0x4495d188U, 0xcc3ff300U, 0x41d0918dU, 0x7a265cb6U, + 0x60b8d8acU, 0x3db38ef1U, 0x83a0234fU, 0x55c19499U, + 0xd421f518U, 0xd3e4371fU, 0x5084d49cU, 0xa50da869U, + 0xf14cbd3dU, 0x8c6fe340U, 0xa108a96dU, 0x18dec6d4U, + 0x266d4beaU, 0xcd7fb201U, 0x0f0f00c3U, 0x69f29ba5U, + 0xee977922U, 0xefd73823U, 0x6df79aa1U, 0x00c0c0ccU, + 0x3cf3cff0U, 0x3e734df2U, 0xaf872863U, 0x199e87d5U, + 0xfd43be31U, 0x96f1675aU, 0x030003cfU, 0x97b1265bU, + 0x68b2daa4U, 0xe55db829U, 0xcebf7102U, 0x51c4959dU, + 0x5204569eU, 0x5e0b5592U, 0xf549bc39U, 0x39b68ff5U, + 0x36794ffaU, 0x62385aaeU, 0x987ee654U, 0xdd6bb611U, + 0x10d4c4dcU, 0x5c8bd790U, 0xcfff3003U, 0xdeab7512U, + 0x327c4efeU, 0xaac26866U, 0x8525a049U, 0x272d0aebU, + 0x8baa2147U, 0x63781bafU, 0xcbfa3107U, 0x8aea6046U, + 0x7e235db2U, 0x92f4665eU, 0xb459ed78U, 0x79e69fb5U, + 0x677d1aabU, 0x7b661db7U, 0x024042ceU, 0x1f1b04d3U, + 0xf7c93e3bU, 0x77691ebbU, 0x125446deU, 0xed57ba21U, + 0xa048e86cU, 0xf3cc3f3fU, 0xea927826U, 0xaec76962U, + 0x8d2fa241U, 0xbc53ef70U, 0x6f7718a3U, 0xbad66c76U, + 0xc2b0720eU, 0x2b2209e7U, 0xfbc63d37U, 0x6cb7dba0U, + 0x71ec9dbdU, 0xe018f82cU, 0xd024f41cU, 0x892aa345U, + 0x588ed694U, 0x0d8f82c1U, 0xd96eb715U, 0xb856ee74U, + 0xf28c7e3eU, 0xec17fb20U, 0x131407dfU, 0x25ad88e9U, + 0x7de39eb1U, 0x2ce7cbe0U, 0x38f6cef4U, 0xc83af204U, + 0x14d1c5d8U, 0x76295fbaU, 0xa78d2a6bU, 0x75e99cb9U, + 0x70acdcbcU, 0x49da9385U, 0x86e5634aU, 0x61f899adU, + 0x9d3ba651U, 0x23280befU, 0x9bbe2557U, 0xa6cd6b6aU, + 0x45d59089U, 0xbd13ae71U, 0x3b360df7U, 0x333c0fffU, + 0x24edc9e8U, 0xc170b10dU, 0x35b98cf9U, 0x7ca3dfb0U, + 0x87a5224bU, 0x28e2cae4U, 0x78a6deb4U, 0x4b5a1187U, + 0xf946bf35U, 0x6a3258a6U, 0xd82ef614U, 0x722c5ebeU, + 0xf00cfc3cU, 0x5741169bU, 0x7f631cb3U, 0x5dcb9691U, + 0xc7f5320bU, 0xbed36d72U, 0xcaba7006U, 0x4e1f5182U, + 0xa44de968U, 0x9c7be750U, 0x2f2708e3U, 0xe69d7b2aU, + 0x886ae244U, 0x04c5c1c8U, 0xc97ab305U, 0x4f5f1083U, + 0xffc33c33U, 0x0ccfc3c0U, 0x5a0e5496U, 0x3a764cf6U, + 0x4615538aU, 0x4210528eU, 0x9efb6552U, 0xb6d96f7aU, + 0xc575b009U, 0x9fbb2453U, 0x4ddf9281U, 0xb916af75U, + 0x1d9b86d1U, 0x8465e148U, 0x018081cdU, 0x0e4f41c2U, + 0xb7992e7bU, 0x9471e558U, 0x82e0624eU, 0xf6897f3aU, + 0x8faf2043U, 0xb39c2f7fU, 0x9afe6456U, 0x9074e45cU, + 0xdbee3517U, 0xf409fd38U, 0x37390efbU, 0xd164b51dU, + 0x65fd98a9U, 0xc435f108U, 0x1e5b45d2U, 0x058580c9U, + 0x4755128bU, 0x22684aeeU, 0xb05cec7cU, 0xbb962d77U, + 0x119485ddU, 0x64bdd9a8U, 0x21a889edU, 0x31bc8dfdU, + 0xd561b419U, 0x5601579aU, 0xad07aa61U, 0xdaae7416U, + 0xc3f0330fU, 0xa902ab65U, 0x2e6749e2U, 0x0a4a40c6U, + 0x663d5baaU, 0x159184d9U, 0x34f9cdf8U, 0xd7e1361bU, + 0xe41df928U, 0x4a1a5086U, 0xe812fa24U, 0xe158b92dU, + 0x93b4275fU, 0x30fcccfcU, 0x064543caU, 0x4090d08cU, + 0x1b1e05d7U, 0x8060e04cU, 0xc6b5730aU, 0x736c1fbfU, + 0x165147daU, 0x489ad284U, 0x8eef6142U, 0x0b0a01c7U, + 0xac47eb60U, 0xdc2bf710U, 0x171106dbU, 0xd2a4761eU, + 0x472067e9U, 0x5e7e20f0U, 0xbbe35815U, 0xe7a84f49U, + 0x2f527d81U, 0x9bcb5035U, 0xe8678f46U, 0xc2c5076cU, + 0x44e0a4eaU, 0xc6c00668U, 0x4ceaa6e2U, 0x176473b9U, + 0xbc269a12U, 0xf3b94a5dU, 0xac329e02U, 0x08bfb7a6U, + 0xb029991eU, 0x8155d42fU, 0x765c2ad8U, 0xc500c56bU, + 0xb42c981aU, 0xe6e80e48U, 0x0cbab6a2U, 0x136172bdU, + 0xb6ac1a18U, 0x0dfaf7a3U, 0x50f1a1feU, 0x8410942aU, + 0x39c3fa97U, 0x063036a8U, 0x04b0b4aaU, 0x7a5329d4U, + 0x6e422cc0U, 0x15e4f1bbU, 0x5dbee3f3U, 0xcf8a4561U, + 0x5a7b21f4U, 0xa3fd5e0dU, 0x7e5628d0U, 0xf53cc95bU, + 0xd051817eU, 0x4daae7e3U, 0x3089b99eU, 0x11e1f0bfU, + 0xabf75c05U, 0x235d7e8dU, 0xaeb21c00U, 0x9544d13bU, + 0x8fda5521U, 0xd2d1037cU, 0x6cc2aec2U, 0xbaa31914U, + 0x3b437895U, 0x3c86ba92U, 0xbfe65911U, 0x4a6f25e4U, + 0x1e2e30b0U, 0x630d6ecdU, 0x4e6a24e0U, 0xf7bc4b59U, + 0xc90fc667U, 0x221d3f8cU, 0xe06d8d4eU, 0x86901628U, + 0x01f5f4afU, 0x00b5b5aeU, 0x8295172cU, 0xefa24d41U, + 0xd391427dU, 0xd111c07fU, 0x40e5a5eeU, 0xf6fc0a58U, + 0x122133bcU, 0x7993ead7U, 0xec628e42U, 0x78d3abd6U, + 0x87d05729U, 0x0a3f35a4U, 0x21ddfc8fU, 0xbea61810U, + 0xbd66db13U, 0xb169d81fU, 0x1a2b31b4U, 0xd6d40278U, + 0xd91bc277U, 0x8d5ad723U, 0x771c6bd9U, 0x32093b9cU, + 0xffb64951U, 0xb3e95a1dU, 0x209dbd8eU, 0x31c9f89fU, + 0xdd1ec373U, 0x45a0e5ebU, 0x6a472dc4U, 0xc84f8766U, + 0x64c8accaU, 0x8c1a9622U, 0x2498bc8aU, 0x6588edcbU, + 0x9141d03fU, 0x7d96ebd3U, 0x5b3b60f5U, 0x96841238U, + 0x881f9726U, 0x9404903aU, 0xed22cf43U, 0xf079895eU, + 0x18abb3b6U, 0x980b9336U, 0xfd36cb53U, 0x023537acU, + 0x4f2a65e1U, 0x1caeb2b2U, 0x05f0f5abU, 0x41a5e4efU, + 0x624d2fccU, 0x533162fdU, 0x8015952eU, 0x55b4e1fbU, + 0x2dd2ff83U, 0xc440846aU, 0x14a4b0baU, 0x83d5562dU, + 0x9e8e1030U, 0x0f7a75a1U, 0x3f467991U, 0x66482ec8U, + 0xb7ec5b19U, 0xe2ed0f4cU, 0x360c3a98U, 0x573463f9U, + 0x1deef3b3U, 0x037576adU, 0xfc768a52U, 0xcacf0564U, + 0x9281133cU, 0xc385466dU, 0xd7944379U, 0x27587f89U, + 0xfbb34855U, 0x994bd237U, 0x48efa7e6U, 0x9a8b1134U, + 0x9fce5131U, 0xa6b81e08U, 0x6987eec7U, 0x8e9a1420U, + 0x72592bdcU, 0xcc4a8662U, 0x74dca8daU, 0x49afe6e7U, + 0xaab71d04U, 0x527123fcU, 0xd454807aU, 0xdc5e8272U, + 0xcb8f4465U, 0x2e123c80U, 0xdadb0174U, 0x93c1523dU, + 0x68c7afc6U, 0xc7804769U, 0x97c45339U, 0xa4389c0aU, + 0x162432b8U, 0x8550d52bU, 0x374c7b99U, 0x9d4ed333U, + 0x1f6e71b1U, 0xb8239b16U, 0x9001913eU, 0xb2a91b1cU, + 0x2897bf86U, 0x51b1e0ffU, 0x25d8fd8bU, 0xa17ddc0fU, + 0x4b2f64e5U, 0x73196addU, 0xc045856eU, 0x09fff6a7U, + 0x67086fc9U, 0xeba74c45U, 0x26183e88U, 0xa03d9d0eU, + 0x10a1b1beU, 0xe3ad4e4dU, 0xb56cd91bU, 0xd514c17bU, + 0xa977de07U, 0xad72df03U, 0x7199e8dfU, 0x59bbe2f7U, + 0x2a173d84U, 0x70d9a9deU, 0xa2bd1f0cU, 0x567422f8U, + 0xf2f90b5cU, 0x6b076cc5U, 0xeee20c40U, 0xe12dcc4fU, + 0x58fba3f6U, 0x7b1368d5U, 0x6d82efc3U, 0x19ebf2b7U, + 0x60cdadceU, 0x5cfea2f2U, 0x759ce9dbU, 0x7f1669d1U, + 0x348cb89aU, 0x1b6b70b5U, 0xd85b8376U, 0x3e063890U, + 0x8a9f1524U, 0x2b577c85U, 0xf139c85fU, 0xeae70d44U, + 0xa8379f06U, 0xcd0ac763U, 0x5f3e61f1U, 0x54f4a0faU, + 0xfef60850U, 0x8bdf5425U, 0xceca0460U, 0xdede0070U, + 0x3a033994U, 0xb963da17U, 0x426527ecU, 0x35ccf99bU, + 0x2c92be82U, 0x466026e8U, 0xc105c46fU, 0xe528cd4bU, + 0x895fd627U, 0xfaf30954U, 0xdb9b4075U, 0x3883bb96U, + 0x0b7f74a5U, 0xa578dd0bU, 0x077077a9U, 0x0e3a34a0U, + 0x7cd6aad2U, 0xdf9e4171U, 0xe927ce47U, 0xaff25d01U, + 0xf47c885aU, 0x6f026dc1U, 0x29d7fe87U, 0x9c0e9232U, + 0xf933ca57U, 0xa7f85f09U, 0x618deccfU, 0xe4688c4aU, + 0x432566edU, 0x33497a9dU, 0xf8738b56U, 0x3dc6fb93U, + 0xb1ed5cd2U, 0xa8b31bcbU, 0x4d2e632eU, 0x11657472U, + 0xd99f46baU, 0x6d066b0eU, 0x1eaab47dU, 0x34083c57U, + 0xb22d9fd1U, 0x300d3d53U, 0xba279dd9U, 0xe1a94882U, + 0x4aeba129U, 0x05747166U, 0x5affa539U, 0xfe728c9dU, + 0x46e4a225U, 0x7798ef14U, 0x809111e3U, 0x33cdfe50U, + 0x42e1a321U, 0x10253573U, 0xfa778d99U, 0xe5ac4986U, + 0x40612123U, 0xfb37cc98U, 0xa63c9ac5U, 0x72ddaf11U, + 0xcf0ec1acU, 0xf0fd0d93U, 0xf27d8f91U, 0x8c9e12efU, + 0x988f17fbU, 0xe329ca80U, 0xab73d8c8U, 0x39477e5aU, + 0xacb61acfU, 0x55306536U, 0x889b13ebU, 0x03f1f260U, + 0x269cba45U, 0xbb67dcd8U, 0xc64482a5U, 0xe72ccb84U, + 0x5d3a673eU, 0xd59045b6U, 0x587f273bU, 0x6389ea00U, + 0x79176e1aU, 0x241c3847U, 0x9a0f95f9U, 0x4c6e222fU, + 0xcd8e43aeU, 0xca4b81a9U, 0x492b622aU, 0xbca21edfU, + 0xe8e30b8bU, 0x95c055f6U, 0xb8a71fdbU, 0x01717062U, + 0x3fc2fd5cU, 0xd4d004b7U, 0x16a0b675U, 0x705d2d13U, + 0xf738cf94U, 0xf6788e95U, 0x74582c17U, 0x196f767aU, + 0x255c7946U, 0x27dcfb44U, 0xb6289ed5U, 0x00313163U, + 0xe4ec0887U, 0x8f5ed1ecU, 0x1aafb579U, 0x8e1e90edU, + 0x711d6c12U, 0xfcf20e9fU, 0xd710c7b4U, 0x486b232bU, + 0x4babe028U, 0x47a4e324U, 0xece60a8fU, 0x20193943U, + 0x2fd6f94cU, 0x7b97ec18U, 0x81d150e2U, 0xc4c400a7U, + 0x097b726aU, 0x45246126U, 0xd65086b5U, 0xc704c3a4U, + 0x2bd3f848U, 0xb36dded0U, 0x9c8a16ffU, 0x3e82bc5dU, + 0x920597f1U, 0x7ad7ad19U, 0xd25587b1U, 0x9345d6f0U, + 0x678ceb04U, 0x8b5bd0e8U, 0xadf65bceU, 0x60492903U, + 0x7ed2ac1dU, 0x62c9ab01U, 0x1beff478U, 0x06b4b265U, + 0xee66888dU, 0x6ec6a80dU, 0x0bfbf068U, 0xf4f80c97U, + 0xb9e75edaU, 0xea638989U, 0xf33dce90U, 0xb768dfd4U, + 0x948014f7U, 0xa5fc59c6U, 0x76d8ae15U, 0xa379dac0U, + 0xdb1fc4b8U, 0x328dbf51U, 0xe2698b81U, 0x75186d16U, + 0x68432b0bU, 0xf9b74e9aU, 0xc98b42aaU, 0x908515f3U, + 0x41216022U, 0x14203477U, 0xc0c101a3U, 0xa1f958c2U, + 0xeb23c888U, 0xf5b84d96U, 0x0abbb169U, 0x3c023e5fU, + 0x644c2807U, 0x35487d56U, 0x21597842U, 0xd19544b2U, + 0x0d7e736eU, 0x6f86e90cU, 0xbe229cddU, 0x6c462a0fU, + 0x69036a0aU, 0x50752533U, 0x9f4ad5fcU, 0x78572f1bU, + 0x849410e7U, 0x3a87bd59U, 0x821193e1U, 0xbf62dddcU, + 0x5c7a263fU, 0xa4bc18c7U, 0x2299bb41U, 0x2a93b949U, + 0x3d427f5eU, 0xd8df07bbU, 0x2c163a4fU, 0x650c6906U, + 0x9e0a94fdU, 0x314d7c52U, 0x61096802U, 0x52f5a731U, + 0xe0e90983U, 0x739dee10U, 0xc18140a2U, 0x6b83e808U, + 0xe9a34a8aU, 0x4eeea02dU, 0x66ccaa05U, 0x44642027U, + 0xde5a84bdU, 0xa77cdbc4U, 0xd315c6b0U, 0x57b0e734U, + 0xbde25fdeU, 0x85d451e6U, 0x3688be55U, 0xff32cd9cU, + 0x91c554f2U, 0x1d6a777eU, 0xd0d505b3U, 0x56f0a635U, + 0xe66c8a85U, 0x15607576U, 0x43a1e220U, 0x23d9fa40U, + 0x5fbae53cU, 0x5bbfe438U, 0x8754d3e4U, 0xaf76d9ccU, + 0xdcda06bfU, 0x861492e5U, 0x54702437U, 0xa0b919c3U, + 0x04343067U, 0x9dca57feU, 0x182f377bU, 0x17e0f774U, + 0xae3698cdU, 0x8dde53eeU, 0x9b4fd4f8U, 0xef26c98cU, + 0x960096f5U, 0xaa3399c9U, 0x8351d2e0U, 0x89db52eaU, + 0xc24183a1U, 0xeda64b8eU, 0x2e96b84dU, 0xc8cb03abU, + 0x7c522e1fU, 0xdd9a47beU, 0x07f4f364U, 0x1c2a367fU, + 0x5efaa43dU, 0x3bc7fc58U, 0xa9f35acaU, 0xa2399bc1U, + 0x083b336bU, 0x7d126f1eU, 0x38073f5bU, 0x28133b4bU, + 0xccce02afU, 0x4faee12cU, 0xb4a81cd7U, 0xc301c2a0U, + 0xda5f85b9U, 0xb0ad1dd3U, 0x37c8ff54U, 0x13e5f670U, + 0x7f92ed1cU, 0x0c3e326fU, 0x2d567b4eU, 0xce4e80adU, + 0xfdb24f9eU, 0x53b5e630U, 0xf1bd4c92U, 0xf8f70f9bU, + 0x8a1b91e9U, 0x29537a4aU, 0x1feaf57cU, 0x593f663aU, + 0x02b1b361U, 0x99cf56faU, 0xdf1ac5bcU, 0x6ac3a909U, + 0x0ffef16cU, 0x51356432U, 0x9740d7f4U, 0x12a5b771U, + 0xb5e85dd6U, 0xc58441a6U, 0x0ebeb06dU, 0xcb0bc0a8U, + 0x2f6946c8U, 0x363701d1U, 0xd3aa7934U, 0x8fe16e68U, + 0x471b5ca0U, 0xf3827114U, 0x802eae67U, 0xaa8c264dU, + 0x2ca985cbU, 0xae892749U, 0x24a387c3U, 0x7f2d5298U, + 0xd46fbb33U, 0x9bf06b7cU, 0xc47bbf23U, 0x60f69687U, + 0xd860b83fU, 0xe91cf50eU, 0x1e150bf9U, 0xad49e44aU, + 0xdc65b93bU, 0x8ea12f69U, 0x64f39783U, 0x7b28539cU, + 0xdee53b39U, 0x65b3d682U, 0x38b880dfU, 0xec59b50bU, + 0x518adbb6U, 0x6e791789U, 0x6cf9958bU, 0x121a08f5U, + 0x060b0de1U, 0x7dadd09aU, 0x35f7c2d2U, 0xa7c36440U, + 0x323200d5U, 0xcbb47f2cU, 0x161f09f1U, 0x9d75e87aU, + 0xb818a05fU, 0x25e3c6c2U, 0x58c098bfU, 0x79a8d19eU, + 0xc3be7d24U, 0x4b145facU, 0xc6fb3d21U, 0xfd0df01aU, + 0xe7937400U, 0xba98225dU, 0x048b8fe3U, 0xd2ea3835U, + 0x530a59b4U, 0x54cf9bb3U, 0xd7af7830U, 0x222604c5U, + 0x76671191U, 0x0b444fecU, 0x262305c1U, 0x9ff56a78U, + 0xa146e746U, 0x4a541eadU, 0x8824ac6fU, 0xeed93709U, + 0x69bcd58eU, 0x68fc948fU, 0xeadc360dU, 0x87eb6c60U, + 0xbbd8635cU, 0xb958e15eU, 0x28ac84cfU, 0x9eb52b79U, + 0x7a68129dU, 0x11dacbf6U, 0x842baf63U, 0x109a8af7U, + 0xef997608U, 0x62761485U, 0x4994ddaeU, 0xd6ef3931U, + 0xd52ffa32U, 0xd920f93eU, 0x72621095U, 0xbe9d2359U, + 0xb152e356U, 0xe513f602U, 0x1f554af8U, 0x5a401abdU, + 0x97ff6870U, 0xdba07b3cU, 0x48d49cafU, 0x5980d9beU, + 0xb557e252U, 0x2de9c4caU, 0x020e0ce5U, 0xa006a647U, + 0x0c818debU, 0xe453b703U, 0x4cd19dabU, 0x0dc1cceaU, + 0xf908f11eU, 0x15dfcaf2U, 0x337241d4U, 0xfecd3319U, + 0xe056b607U, 0xfc4db11bU, 0x856bee62U, 0x9830a87fU, + 0x70e29297U, 0xf042b217U, 0x957fea72U, 0x6a7c168dU, + 0x276344c0U, 0x74e79393U, 0x6db9d48aU, 0x29ecc5ceU, + 0x0a040eedU, 0x3b7843dcU, 0xe85cb40fU, 0x3dfdc0daU, + 0x459bdea2U, 0xac09a54bU, 0x7ced919bU, 0xeb9c770cU, + 0xf6c73111U, 0x67335480U, 0x570f58b0U, 0x0e010fe9U, + 0xdfa57a38U, 0x8aa42e6dU, 0x5e451bb9U, 0x3f7d42d8U, + 0x75a7d292U, 0x6b3c578cU, 0x943fab73U, 0xa2862445U, + 0xfac8321dU, 0xabcc674cU, 0xbfdd6258U, 0x4f115ea8U, + 0x93fa6974U, 0xf102f316U, 0x20a686c7U, 0xf2c23015U, + 0xf7877010U, 0xcef13f29U, 0x01cecfe6U, 0xe6d33501U, + 0x1a100afdU, 0xa403a743U, 0x1c9589fbU, 0x21e6c7c6U, + 0xc2fe3c25U, 0x3a3802ddU, 0xbc1da15bU, 0xb417a353U, + 0xa3c66544U, 0x465b1da1U, 0xb2922055U, 0xfb88731cU, + 0x008e8ee7U, 0xafc96648U, 0xff8d7218U, 0xcc71bd2bU, + 0x7e6d1399U, 0xed19f40aU, 0x5f055ab8U, 0xf507f212U, + 0x77275090U, 0xd06aba37U, 0xf848b01fU, 0xdae03a3dU, + 0x40de9ea7U, 0x39f8c1deU, 0x4d91dcaaU, 0xc934fd2eU, + 0x236645c4U, 0x1b504bfcU, 0xa80ca44fU, 0x61b6d786U, + 0x0f414ee8U, 0x83ee6d64U, 0x4e511fa9U, 0xc874bc2fU, + 0x78e8909fU, 0x8be46f6cU, 0xdd25f83aU, 0xbd5de05aU, + 0xc13eff26U, 0xc53bfe22U, 0x19d0c9feU, 0x31f2c3d6U, + 0x425e1ca5U, 0x189088ffU, 0xcaf43e2dU, 0x3e3d03d9U, + 0x9ab02a7dU, 0x034e4de4U, 0x86ab2d61U, 0x8964ed6eU, + 0x30b282d7U, 0x135a49f4U, 0x05cbcee2U, 0x71a2d396U, + 0x08848cefU, 0x34b783d3U, 0x1dd5c8faU, 0x175f48f0U, + 0x5cc599bbU, 0x73225194U, 0xb012a257U, 0x564f19b1U, + 0xe2d63405U, 0x431e5da4U, 0x9970e97eU, 0x82ae2c65U, + 0xc07ebe27U, 0xa543e642U, 0x377740d0U, 0x3cbd81dbU, + 0x96bf2971U, 0xe3967504U, 0xa6832541U, 0xb6972151U, + 0x524a18b5U, 0xd12afb36U, 0x2a2c06cdU, 0x5d85d8baU, + 0x44db9fa3U, 0x2e2907c9U, 0xa94ce54eU, 0x8d61ec6aU, + 0xe116f706U, 0x92ba2875U, 0xb3d26154U, 0x50ca9ab7U, + 0x63365584U, 0xcd31fc2aU, 0x6f395688U, 0x66731581U, + 0x149f8bf3U, 0xb7d76050U, 0x816eef66U, 0xc7bb7c20U, + 0x9c35a97bU, 0x074b4ce0U, 0x419edfa6U, 0xf447b313U, + 0x917aeb76U, 0xcfb17e28U, 0x09c4cdeeU, 0x8c21ad6bU, + 0x2b6c47ccU, 0x5b005bbcU, 0x903aaa77U, 0x558fdab2U, + 0x243f1b95U, 0x3d615c8cU, 0xd8fc2469U, 0x84b73335U, + 0x4c4d01fdU, 0xf8d42c49U, 0x8b78f33aU, 0xa1da7b10U, + 0x27ffd896U, 0xa5df7a14U, 0x2ff5da9eU, 0x747b0fc5U, + 0xdf39e66eU, 0x90a63621U, 0xcf2de27eU, 0x6ba0cbdaU, + 0xd336e562U, 0xe24aa853U, 0x154356a4U, 0xa61fb917U, + 0xd733e466U, 0x85f77234U, 0x6fa5cadeU, 0x707e0ec1U, + 0xd5b36664U, 0x6ee58bdfU, 0x33eedd82U, 0xe70fe856U, + 0x5adc86ebU, 0x652f4ad4U, 0x67afc8d6U, 0x194c55a8U, + 0x0d5d50bcU, 0x76fb8dc7U, 0x3ea19f8fU, 0xac95391dU, + 0x39645d88U, 0xc0e22271U, 0x1d4954acU, 0x9623b527U, + 0xb34efd02U, 0x2eb59b9fU, 0x5396c5e2U, 0x72fe8cc3U, + 0xc8e82079U, 0x404202f1U, 0xcdad607cU, 0xf65bad47U, + 0xecc5295dU, 0xb1ce7f00U, 0x0fddd2beU, 0xd9bc6568U, + 0x585c04e9U, 0x5f99c6eeU, 0xdcf9256dU, 0x29705998U, + 0x7d314cccU, 0x001212b1U, 0x2d75589cU, 0x94a33725U, + 0xaa10ba1bU, 0x410243f0U, 0x8372f132U, 0xe58f6a54U, + 0x62ea88d3U, 0x63aac9d2U, 0xe18a6b50U, 0x8cbd313dU, + 0xb08e3e01U, 0xb20ebc03U, 0x23fad992U, 0x95e37624U, + 0x713e4fc0U, 0x1a8c96abU, 0x8f7df23eU, 0x1bccd7aaU, + 0xe4cf2b55U, 0x692049d8U, 0x42c280f3U, 0xddb9646cU, + 0xde79a76fU, 0xd276a463U, 0x79344dc8U, 0xb5cb7e04U, + 0xba04be0bU, 0xee45ab5fU, 0x140317a5U, 0x511647e0U, + 0x9ca9352dU, 0xd0f62661U, 0x4382c1f2U, 0x52d684e3U, + 0xbe01bf0fU, 0x26bf9997U, 0x095851b8U, 0xab50fb1aU, + 0x07d7d0b6U, 0xef05ea5eU, 0x4787c0f6U, 0x069791b7U, + 0xf25eac43U, 0x1e8997afU, 0x38241c89U, 0xf59b6e44U, + 0xeb00eb5aU, 0xf71bec46U, 0x8e3db33fU, 0x9366f522U, + 0x7bb4cfcaU, 0xfb14ef4aU, 0x9e29b72fU, 0x612a4bd0U, + 0x2c35199dU, 0x7fb1ceceU, 0x66ef89d7U, 0x22ba9893U, + 0x015253b0U, 0x302e1e81U, 0xe30ae952U, 0x36ab9d87U, + 0x4ecd83ffU, 0xa75ff816U, 0x77bbccc6U, 0xe0ca2a51U, + 0xfd916c4cU, 0x6c6509ddU, 0x5c5905edU, 0x055752b4U, + 0xd4f32765U, 0x81f27330U, 0x551346e4U, 0x342b1f85U, + 0x7ef18fcfU, 0x606a0ad1U, 0x9f69f62eU, 0xa9d07918U, + 0xf19e6f40U, 0xa09a3a11U, 0xb48b3f05U, 0x444703f5U, + 0x98ac3429U, 0xfa54ae4bU, 0x2bf0db9aU, 0xf9946d48U, + 0xfcd12d4dU, 0xc5a76274U, 0x0a9892bbU, 0xed85685cU, + 0x114657a0U, 0xaf55fa1eU, 0x17c3d4a6U, 0x2ab09a9bU, + 0xc9a86178U, 0x316e5f80U, 0xb74bfc06U, 0xbf41fe0eU, + 0xa8903819U, 0x4d0d40fcU, 0xb9c47d08U, 0xf0de2e41U, + 0x0bd8d3baU, 0xa49f3b15U, 0xf4db2f45U, 0xc727e076U, + 0x753b4ec4U, 0xe64fa957U, 0x545307e5U, 0xfe51af4fU, + 0x7c710dcdU, 0xdb3ce76aU, 0xf31eed42U, 0xd1b66760U, + 0x4b88c3faU, 0x32ae9c83U, 0x46c781f7U, 0xc262a073U, + 0x28301899U, 0x100616a1U, 0xa35af912U, 0x6ae08adbU, + 0x041713b5U, 0x88b83039U, 0x450742f4U, 0xc322e172U, + 0x73becdc2U, 0x80b23231U, 0xd673a567U, 0xb60bbd07U, + 0xca68a27bU, 0xce6da37fU, 0x128694a3U, 0x3aa49e8bU, + 0x490841f8U, 0x13c6d5a2U, 0xc1a26370U, 0x356b5e84U, + 0x91e67720U, 0x081810b9U, 0x8dfd703cU, 0x8232b033U, + 0x3be4df8aU, 0x180c14a9U, 0x0e9d93bfU, 0x7af48ecbU, + 0x03d2d1b2U, 0x3fe1de8eU, 0x168395a7U, 0x1c0915adU, + 0x5793c4e6U, 0x78740cc9U, 0xbb44ff0aU, 0x5d1944ecU, + 0xe9806958U, 0x484800f9U, 0x9226b423U, 0x89f87138U, + 0xcb28e37aU, 0xae15bb1fU, 0x3c211d8dU, 0x37ebdc86U, + 0x9de9742cU, 0xe8c02859U, 0xadd5781cU, 0xbdc17c0cU, + 0x591c45e8U, 0xda7ca66bU, 0x217a5b90U, 0x56d385e7U, + 0x4f8dc2feU, 0x257f5a94U, 0xa21ab813U, 0x8637b137U, + 0xea40aa5bU, 0x99ec7528U, 0xb8843c09U, 0x5b9cc7eaU, + 0x686008d9U, 0xc667a177U, 0x646f0bd5U, 0x6d2548dcU, + 0x1fc9d6aeU, 0xbc813d0dU, 0x8a38b23bU, 0xcced217dU, + 0x9763f426U, 0x0c1d11bdU, 0x4ac882fbU, 0xff11ee4eU, + 0x9a2cb62bU, 0xc4e72375U, 0x029290b3U, 0x8777f036U, + 0x203a1a91U, 0x505606e1U, 0x9b6cf72aU, 0x5ed987efU, + 0x3792a52bU, 0x2ecce232U, 0xcb519ad7U, 0x971a8d8bU, + 0x5fe0bf43U, 0xeb7992f7U, 0x98d54d84U, 0xb277c5aeU, + 0x34526628U, 0xb672c4aaU, 0x3c586420U, 0x67d6b17bU, + 0xcc9458d0U, 0x830b889fU, 0xdc805cc0U, 0x780d7564U, + 0xc09b5bdcU, 0xf1e716edU, 0x06eee81aU, 0xb5b207a9U, + 0xc49e5ad8U, 0x965acc8aU, 0x7c087460U, 0x63d3b07fU, + 0xc61ed8daU, 0x7d483561U, 0x2043633cU, 0xf4a256e8U, + 0x49713855U, 0x7682f46aU, 0x74027668U, 0x0ae1eb16U, + 0x1ef0ee02U, 0x65563379U, 0x2d0c2131U, 0xbf3887a3U, + 0x2ac9e336U, 0xd34f9ccfU, 0x0ee4ea12U, 0x858e0b99U, + 0xa0e343bcU, 0x3d182521U, 0x403b7b5cU, 0x6153327dU, + 0xdb459ec7U, 0x53efbc4fU, 0xde00dec2U, 0xe5f613f9U, + 0xff6897e3U, 0xa263c1beU, 0x1c706c00U, 0xca11dbd6U, + 0x4bf1ba57U, 0x4c347850U, 0xcf549bd3U, 0x3adde726U, + 0x6e9cf272U, 0x13bfac0fU, 0x3ed8e622U, 0x870e899bU, + 0xb9bd04a5U, 0x52affd4eU, 0x90df4f8cU, 0xf622d4eaU, + 0x7147366dU, 0x7007776cU, 0xf227d5eeU, 0x9f108f83U, + 0xa32380bfU, 0xa1a302bdU, 0x3057672cU, 0x864ec89aU, + 0x6293f17eU, 0x09212815U, 0x9cd04c80U, 0x08616914U, + 0xf76295ebU, 0x7a8df766U, 0x516f3e4dU, 0xce14dad2U, + 0xcdd419d1U, 0xc1db1addU, 0x6a99f376U, 0xa666c0baU, + 0xa9a900b5U, 0xfde815e1U, 0x07aea91bU, 0x42bbf95eU, + 0x8f048b93U, 0xc35b98dfU, 0x502f7f4cU, 0x417b3a5dU, + 0xadac01b1U, 0x35122729U, 0x1af5ef06U, 0xb8fd45a4U, + 0x147a6e08U, 0xfca854e0U, 0x542a7e48U, 0x153a2f09U, + 0xe1f312fdU, 0x0d242911U, 0x2b89a237U, 0xe636d0faU, + 0xf8ad55e4U, 0xe4b652f8U, 0x9d900d81U, 0x80cb4b9cU, + 0x68197174U, 0xe8b951f4U, 0x8d840991U, 0x7287f56eU, + 0x3f98a723U, 0x6c1c7070U, 0x75423769U, 0x3117262dU, + 0x12ffed0eU, 0x2383a03fU, 0xf0a757ecU, 0x25062339U, + 0x5d603d41U, 0xb4f246a8U, 0x64167278U, 0xf36794efU, + 0xee3cd2f2U, 0x7fc8b763U, 0x4ff4bb53U, 0x16faec0aU, + 0xc75e99dbU, 0x925fcd8eU, 0x46bef85aU, 0x2786a13bU, + 0x6d5c3171U, 0x73c7b46fU, 0x8cc44890U, 0xba7dc7a6U, + 0xe233d1feU, 0xb33784afU, 0xa72681bbU, 0x57eabd4bU, + 0x8b018a97U, 0xe9f910f5U, 0x385d6524U, 0xea39d3f6U, + 0xef7c93f3U, 0xd60adccaU, 0x19352c05U, 0xfe28d6e2U, + 0x02ebe91eU, 0xbcf844a0U, 0x046e6a18U, 0x391d2425U, + 0xda05dfc6U, 0x22c3e13eU, 0xa4e642b8U, 0xacec40b0U, + 0xbb3d86a7U, 0x5ea0fe42U, 0xaa69c3b6U, 0xe37390ffU, + 0x18756d04U, 0xb73285abU, 0xe77691fbU, 0xd48a5ec8U, + 0x6696f07aU, 0xf5e217e9U, 0x47feb95bU, 0xedfc11f1U, + 0x6fdcb373U, 0xc89159d4U, 0xe0b353fcU, 0xc21bd9deU, + 0x58257d44U, 0x2103223dU, 0x556a3f49U, 0xd1cf1ecdU, + 0x3b9da627U, 0x03aba81fU, 0xb0f747acU, 0x794d3465U, + 0x17baad0bU, 0x9b158e87U, 0x56aafc4aU, 0xd08f5fccU, + 0x6013737cU, 0x931f8c8fU, 0xc5de1bd9U, 0xa5a603b9U, + 0xd9c51cc5U, 0xddc01dc1U, 0x012b2a1dU, 0x29092035U, + 0x5aa5ff46U, 0x006b6b1cU, 0xd20fddceU, 0x26c6e03aU, + 0x824bc99eU, 0x1bb5ae07U, 0x9e50ce82U, 0x919f0e8dU, + 0x28496134U, 0x0ba1aa17U, 0x1d302d01U, 0x69593075U, + 0x107f6f0cU, 0x2c4c6030U, 0x052e2b19U, 0x0fa4ab13U, + 0x443e7a58U, 0x6bd9b277U, 0xa8e941b4U, 0x4eb4fa52U, + 0xfa2dd7e6U, 0x5be5be47U, 0x818b0a9dU, 0x9a55cf86U, + 0xd8855dc4U, 0xbdb805a1U, 0x2f8ca333U, 0x24466238U, + 0x8e44ca92U, 0xfb6d96e7U, 0xbe78c6a2U, 0xae6cc2b2U, + 0x4ab1fb56U, 0xc9d118d5U, 0x32d7e52eU, 0x457e3b59U, + 0x5c207c40U, 0x36d2e42aU, 0xb1b706adU, 0x959a0f89U, + 0xf9ed14e5U, 0x8a41cb96U, 0xab2982b7U, 0x48317954U, + 0x7bcdb667U, 0xd5ca1fc9U, 0x77c2b56bU, 0x7e88f662U, + 0x0c646810U, 0xaf2c83b3U, 0x99950c85U, 0xdf409fc3U, + 0x84ce4a98U, 0x1fb0af03U, 0x59653c45U, 0xecbc50f0U, + 0x89810895U, 0xd74a9dcbU, 0x113f2e0dU, 0x94da4e88U, + 0x3397a42fU, 0x43fbb85fU, 0x88c14994U, 0x4d743951U, + 0x562573fdU, 0x4f7b34e4U, 0xaae64c01U, 0xf6ad5b5dU, + 0x3e576995U, 0x8ace4421U, 0xf9629b52U, 0xd3c01378U, + 0x55e5b0feU, 0xd7c5127cU, 0x5defb2f6U, 0x066167adU, + 0xad238e06U, 0xe2bc5e49U, 0xbd378a16U, 0x19baa3b2U, + 0xa12c8d0aU, 0x9050c03bU, 0x67593eccU, 0xd405d17fU, + 0xa5298c0eU, 0xf7ed1a5cU, 0x1dbfa2b6U, 0x026466a9U, + 0xa7a90e0cU, 0x1cffe3b7U, 0x41f4b5eaU, 0x9515803eU, + 0x28c6ee83U, 0x173522bcU, 0x15b5a0beU, 0x6b563dc0U, + 0x7f4738d4U, 0x04e1e5afU, 0x4cbbf7e7U, 0xde8f5175U, + 0x4b7e35e0U, 0xb2f84a19U, 0x6f533cc4U, 0xe439dd4fU, + 0xc154956aU, 0x5caff3f7U, 0x218cad8aU, 0x00e4e4abU, + 0xbaf24811U, 0x32586a99U, 0xbfb70814U, 0x8441c52fU, + 0x9edf4135U, 0xc3d41768U, 0x7dc7bad6U, 0xaba60d00U, + 0x2a466c81U, 0x2d83ae86U, 0xaee34d05U, 0x5b6a31f0U, + 0x0f2b24a4U, 0x72087ad9U, 0x5f6f30f4U, 0xe6b95f4dU, + 0xd80ad273U, 0x33182b98U, 0xf168995aU, 0x9795023cU, + 0x10f0e0bbU, 0x11b0a1baU, 0x93900338U, 0xfea75955U, + 0xc2945669U, 0xc014d46bU, 0x51e0b1faU, 0xe7f91e4cU, + 0x032427a8U, 0x6896fec3U, 0xfd679a56U, 0x69d6bfc2U, + 0x96d5433dU, 0x1b3a21b0U, 0x30d8e89bU, 0xafa30c04U, + 0xac63cf07U, 0xa06ccc0bU, 0x0b2e25a0U, 0xc7d1166cU, + 0xc81ed663U, 0x9c5fc337U, 0x66197fcdU, 0x230c2f88U, + 0xeeb35d45U, 0xa2ec4e09U, 0x3198a99aU, 0x20ccec8bU, + 0xcc1bd767U, 0x54a5f1ffU, 0x7b4239d0U, 0xd94a9372U, + 0x75cdb8deU, 0x9d1f8236U, 0x359da89eU, 0x748df9dfU, + 0x8044c42bU, 0x6c93ffc7U, 0x4a3e74e1U, 0x8781062cU, + 0x991a8332U, 0x8501842eU, 0xfc27db57U, 0xe17c9d4aU, + 0x09aea7a2U, 0x890e8722U, 0xec33df47U, 0x133023b8U, + 0x5e2f71f5U, 0x0daba6a6U, 0x14f5e1bfU, 0x50a0f0fbU, + 0x73483bd8U, 0x423476e9U, 0x9110813aU, 0x44b1f5efU, + 0x3cd7eb97U, 0xd545907eU, 0x05a1a4aeU, 0x92d04239U, + 0x8f8b0424U, 0x1e7f61b5U, 0x2e436d85U, 0x774d3adcU, + 0xa6e94f0dU, 0xf3e81b58U, 0x27092e8cU, 0x463177edU, + 0x0cebe7a7U, 0x127062b9U, 0xed739e46U, 0xdbca1170U, + 0x83840728U, 0xd2805279U, 0xc691576dU, 0x365d6b9dU, + 0xeab65c41U, 0x884ec623U, 0x59eab3f2U, 0x8b8e0520U, + 0x8ecb4525U, 0xb7bd0a1cU, 0x7882fad3U, 0x9f9f0034U, + 0x635c3fc8U, 0xdd4f9276U, 0x65d9bcceU, 0x58aaf2f3U, + 0xbbb20910U, 0x437437e8U, 0xc551946eU, 0xcd5b9666U, + 0xda8a5071U, 0x3f172894U, 0xcbde1560U, 0x82c44629U, + 0x79c2bbd2U, 0xd685537dU, 0x86c1472dU, 0xb53d881eU, + 0x072126acU, 0x9455c13fU, 0x26496f8dU, 0x8c4bc727U, + 0x0e6b65a5U, 0xa9268f02U, 0x8104852aU, 0xa3ac0f08U, + 0x3992ab92U, 0x40b4f4ebU, 0x34dde99fU, 0xb078c81bU, + 0x5a2a70f1U, 0x621c7ec9U, 0xd140917aU, 0x18fae2b3U, + 0x760d7bddU, 0xfaa25851U, 0x371d2a9cU, 0xb138891aU, + 0x01a4a5aaU, 0xf2a85a59U, 0xa469cd0fU, 0xc411d56fU, + 0xb872ca13U, 0xbc77cb17U, 0x609cfccbU, 0x48bef6e3U, + 0x3b122990U, 0x61dcbdcaU, 0xb3b80b18U, 0x477136ecU, + 0xe3fc1f48U, 0x7a0278d1U, 0xffe71854U, 0xf028d85bU, + 0x49feb7e2U, 0x6a167cc1U, 0x7c87fbd7U, 0x08eee6a3U, + 0x71c8b9daU, 0x4dfbb6e6U, 0x6499fdcfU, 0x6e137dc5U, + 0x2589ac8eU, 0x0a6e64a1U, 0xc95e9762U, 0x2f032c84U, + 0x9b9a0130U, 0x3a526891U, 0xe03cdc4bU, 0xfbe21950U, + 0xb9328b12U, 0xdc0fd377U, 0x4e3b75e5U, 0x45f1b4eeU, + 0xeff31c44U, 0x9ada4031U, 0xdfcf1074U, 0xcfdb1464U, + 0x2b062d80U, 0xa866ce03U, 0x536033f8U, 0x24c9ed8fU, + 0x3d97aa96U, 0x576532fcU, 0xd000d07bU, 0xf42dd95fU, + 0x985ac233U, 0xebf61d40U, 0xca9e5461U, 0x2986af82U, + 0x1a7a60b1U, 0xb47dc91fU, 0x167563bdU, 0x1f3f20b4U, + 0x6dd3bec6U, 0xce9b5565U, 0xf822da53U, 0xbef74915U, + 0xe5799c4eU, 0x7e0779d5U, 0x38d2ea93U, 0x8d0b8626U, + 0xe836de43U, 0xb6fd4b1dU, 0x7088f8dbU, 0xf56d985eU, + 0x522072f9U, 0x224c6e89U, 0xe9769f42U, 0x2cc3ef87U, + 0xb644f27cU, 0xaf1ab565U, 0x4a87cd80U, 0x16ccdadcU, + 0xde36e814U, 0x6aafc5a0U, 0x19031ad3U, 0x33a192f9U, + 0xb584317fU, 0x37a493fdU, 0xbd8e3377U, 0xe600e62cU, + 0x4d420f87U, 0x02dddfc8U, 0x5d560b97U, 0xf9db2233U, + 0x414d0c8bU, 0x703141baU, 0x8738bf4dU, 0x346450feU, + 0x45480d8fU, 0x178c9bddU, 0xfdde2337U, 0xe205e728U, + 0x47c88f8dU, 0xfc9e6236U, 0xa195346bU, 0x757401bfU, + 0xc8a76f02U, 0xf754a33dU, 0xf5d4213fU, 0x8b37bc41U, + 0x9f26b955U, 0xe480642eU, 0xacda7666U, 0x3eeed0f4U, + 0xab1fb461U, 0x5299cb98U, 0x8f32bd45U, 0x04585cceU, + 0x213514ebU, 0xbcce7276U, 0xc1ed2c0bU, 0xe085652aU, + 0x5a93c990U, 0xd239eb18U, 0x5fd68995U, 0x642044aeU, + 0x7ebec0b4U, 0x23b596e9U, 0x9da63b57U, 0x4bc78c81U, + 0xca27ed00U, 0xcde22f07U, 0x4e82cc84U, 0xbb0bb071U, + 0xef4aa525U, 0x9269fb58U, 0xbf0eb175U, 0x06d8deccU, + 0x386b53f2U, 0xd379aa19U, 0x110918dbU, 0x77f483bdU, + 0xf091613aU, 0xf1d1203bU, 0x73f182b9U, 0x1ec6d8d4U, + 0x22f5d7e8U, 0x207555eaU, 0xb181307bU, 0x07989fcdU, + 0xe345a629U, 0x88f77f42U, 0x1d061bd7U, 0x89b73e43U, + 0x76b4c2bcU, 0xfb5ba031U, 0xd0b9691aU, 0x4fc28d85U, + 0x4c024e86U, 0x400d4d8aU, 0xeb4fa421U, 0x27b097edU, + 0x287f57e2U, 0x7c3e42b6U, 0x8678fe4cU, 0xc36dae09U, + 0x0ed2dcc4U, 0x428dcf88U, 0xd1f9281bU, 0xc0ad6d0aU, + 0x2c7a56e6U, 0xb4c4707eU, 0x9b23b851U, 0x392b12f3U, + 0x95ac395fU, 0x7d7e03b7U, 0xd5fc291fU, 0x94ec785eU, + 0x602545aaU, 0x8cf27e46U, 0xaa5ff560U, 0x67e087adU, + 0x797b02b3U, 0x656005afU, 0x1c465ad6U, 0x011d1ccbU, + 0xe9cf2623U, 0x696f06a3U, 0x0c525ec6U, 0xf351a239U, + 0xbe4ef074U, 0xedca2727U, 0xf494603eU, 0xb0c1717aU, + 0x9329ba59U, 0xa255f768U, 0x717100bbU, 0xa4d0746eU, + 0xdcb66a16U, 0x352411ffU, 0xe5c0252fU, 0x72b1c3b8U, + 0x6fea85a5U, 0xfe1ee034U, 0xce22ec04U, 0x972cbb5dU, + 0x4688ce8cU, 0x13899ad9U, 0xc768af0dU, 0xa650f66cU, + 0xec8a6626U, 0xf211e338U, 0x0d121fc7U, 0x3bab90f1U, + 0x63e586a9U, 0x32e1d3f8U, 0x26f0d6ecU, 0xd63cea1cU, + 0x0ad7ddc0U, 0x682f47a2U, 0xb98b3273U, 0x6bef84a1U, + 0x6eaac4a4U, 0x57dc8b9dU, 0x98e37b52U, 0x7ffe81b5U, + 0x833dbe49U, 0x3d2e13f7U, 0x85b83d4fU, 0xb8cb7372U, + 0x5bd38891U, 0xa315b669U, 0x253015efU, 0x2d3a17e7U, + 0x3aebd1f0U, 0xdf76a915U, 0x2bbf94e1U, 0x62a5c7a8U, + 0x99a33a53U, 0x36e4d2fcU, 0x66a0c6acU, 0x555c099fU, + 0xe740a72dU, 0x743440beU, 0xc628ee0cU, 0x6c2a46a6U, + 0xee0ae424U, 0x49470e83U, 0x616504abU, 0x43cd8e89U, + 0xd9f32a13U, 0xa0d5756aU, 0xd4bc681eU, 0x5019499aU, + 0xba4bf170U, 0x827dff48U, 0x312110fbU, 0xf89b6332U, + 0x966cfa5cU, 0x1ac3d9d0U, 0xd77cab1dU, 0x5159089bU, + 0xe1c5242bU, 0x12c9dbd8U, 0x44084c8eU, 0x247054eeU, + 0x58134b92U, 0x5c164a96U, 0x80fd7d4aU, 0xa8df7762U, + 0xdb73a811U, 0x81bd3c4bU, 0x53d98a99U, 0xa710b76dU, + 0x039d9ec9U, 0x9a63f950U, 0x1f8699d5U, 0x104959daU, + 0xa99f3663U, 0x8a77fd40U, 0x9ce67a56U, 0xe88f6722U, + 0x91a9385bU, 0xad9a3767U, 0x84f87c4eU, 0x8e72fc44U, + 0xc5e82d0fU, 0xea0fe520U, 0x293f16e3U, 0xcf62ad05U, + 0x7bfb80b1U, 0xda33e910U, 0x005d5dcaU, 0x1b8398d1U, + 0x59530a93U, 0x3c6e52f6U, 0xae5af464U, 0xa590356fU, + 0x0f929dc5U, 0x7abbc1b0U, 0x3fae91f5U, 0x2fba95e5U, + 0xcb67ac01U, 0x48074f82U, 0xb301b279U, 0xc4a86c0eU, + 0xddf62b17U, 0xb704b37dU, 0x306151faU, 0x144c58deU, + 0x783b43b2U, 0x0b979cc1U, 0x2affd5e0U, 0xc9e72e03U, + 0xfa1be130U, 0x541c489eU, 0xf614e23cU, 0xff5ea135U, + 0x8db23f47U, 0x2efad4e4U, 0x18435bd2U, 0x5e96c894U, + 0x05181dcfU, 0x9e66f854U, 0xd8b36b12U, 0x6d6a07a7U, + 0x08575fc2U, 0x569cca9cU, 0x90e9795aU, 0x150c19dfU, + 0xb241f378U, 0xc22def08U, 0x09171ec3U, 0xcca26e06U, + 0x7386f57bU, 0x6ad8b262U, 0x8f45ca87U, 0xd30edddbU, + 0x1bf4ef13U, 0xaf6dc2a7U, 0xdcc11dd4U, 0xf66395feU, + 0x70463678U, 0xf26694faU, 0x784c3470U, 0x23c2e12bU, + 0x88800880U, 0xc71fd8cfU, 0x98940c90U, 0x3c192534U, + 0x848f0b8cU, 0xb5f346bdU, 0x42fab84aU, 0xf1a657f9U, + 0x808a0a88U, 0xd24e9cdaU, 0x381c2430U, 0x27c7e02fU, + 0x820a888aU, 0x395c6531U, 0x6457336cU, 0xb0b606b8U, + 0x0d656805U, 0x3296a43aU, 0x30162638U, 0x4ef5bb46U, + 0x5ae4be52U, 0x21426329U, 0x69187161U, 0xfb2cd7f3U, + 0x6eddb366U, 0x975bcc9fU, 0x4af0ba42U, 0xc19a5bc9U, + 0xe4f713ecU, 0x790c7571U, 0x042f2b0cU, 0x2547622dU, + 0x9f51ce97U, 0x17fbec1fU, 0x9a148e92U, 0xa1e243a9U, + 0xbb7cc7b3U, 0xe67791eeU, 0x58643c50U, 0x8e058b86U, + 0x0fe5ea07U, 0x08202800U, 0x8b40cb83U, 0x7ec9b776U, + 0x2a88a222U, 0x57abfc5fU, 0x7accb672U, 0xc31ad9cbU, + 0xfda954f5U, 0x16bbad1eU, 0xd4cb1fdcU, 0xb23684baU, + 0x3553663dU, 0x3413273cU, 0xb63385beU, 0xdb04dfd3U, + 0xe737d0efU, 0xe5b752edU, 0x7443377cU, 0xc25a98caU, + 0x2687a12eU, 0x4d357845U, 0xd8c41cd0U, 0x4c753944U, + 0xb376c5bbU, 0x3e99a736U, 0x157b6e1dU, 0x8a008a82U, + 0x89c04981U, 0x85cf4a8dU, 0x2e8da326U, 0xe27290eaU, + 0xedbd50e5U, 0xb9fc45b1U, 0x43baf94bU, 0x06afa90eU, + 0xcb10dbc3U, 0x874fc88fU, 0x143b2f1cU, 0x056f6a0dU, + 0xe9b851e1U, 0x71067779U, 0x5ee1bf56U, 0xfce915f4U, + 0x506e3e58U, 0xb8bc04b0U, 0x103e2e18U, 0x512e7f59U, + 0xa5e742adU, 0x49307941U, 0x6f9df267U, 0xa22280aaU, + 0xbcb905b4U, 0xa0a202a8U, 0xd9845dd1U, 0xc4df1bccU, + 0x2c0d2124U, 0xacad01a4U, 0xc99059c1U, 0x3693a53eU, + 0x7b8cf773U, 0x28082020U, 0x31566739U, 0x7503767dU, + 0x56ebbd5eU, 0x6797f06fU, 0xb4b307bcU, 0x61127369U, + 0x19746d11U, 0xf0e616f8U, 0x20022228U, 0xb773c4bfU, + 0xaa2882a2U, 0x3bdce733U, 0x0be0eb03U, 0x52eebc5aU, + 0x834ac98bU, 0xd64b9ddeU, 0x02aaa80aU, 0x6392f16bU, + 0x29486121U, 0x37d3e43fU, 0xc8d018c0U, 0xfe6997f6U, + 0xa62781aeU, 0xf723d4ffU, 0xe332d1ebU, 0x13feed1bU, + 0xcf15dac7U, 0xaded40a5U, 0x7c493574U, 0xae2d83a6U, + 0xab68c3a3U, 0x921e8c9aU, 0x5d217c55U, 0xba3c86b2U, + 0x46ffb94eU, 0xf8ec14f0U, 0x407a3a48U, 0x7d097475U, + 0x9e118f96U, 0x66d7b16eU, 0xe0f212e8U, 0xe8f810e0U, + 0xff29d6f7U, 0x1ab4ae12U, 0xee7d93e6U, 0xa767c0afU, + 0x5c613d54U, 0xf326d5fbU, 0xa362c1abU, 0x909e0e98U, + 0x2282a02aU, 0xb1f647b9U, 0x03eae90bU, 0xa9e841a1U, + 0x2bc8e323U, 0x8c850984U, 0xa4a703acU, 0x860f898eU, + 0x1c312d14U, 0x6517726dU, 0x117e6f19U, 0x95db4e9dU, + 0x7f89f677U, 0x47bff84fU, 0xf4e317fcU, 0x3d596435U, + 0x53aefd5bU, 0xdf01ded7U, 0x12beac1aU, 0x949b0f9cU, + 0x2407232cU, 0xd70bdcdfU, 0x81ca4b89U, 0xe1b253e9U, + 0x9dd14c95U, 0x99d44d91U, 0x453f7a4dU, 0x6d1d7065U, + 0x1eb1af16U, 0x447f3b4cU, 0x961b8d9eU, 0x62d2b06aU, + 0xc65f99ceU, 0x5fa1fe57U, 0xda449ed2U, 0xd58b5eddU, + 0x6c5d3164U, 0x4fb5fa47U, 0x59247d51U, 0x2d4d6025U, + 0x546b3f5cU, 0x68583060U, 0x413a7b49U, 0x4bb0fb43U, + 0x002a2a08U, 0x2fcde227U, 0xecfd11e4U, 0x0aa0aa02U, + 0xbe3987b6U, 0x1ff1ee17U, 0xc59f5acdU, 0xde419fd6U, + 0x9c910d94U, 0xf9ac55f1U, 0x6b98f363U, 0x60523268U, + 0xca509ac2U, 0xbf79c6b7U, 0xfa6c96f2U, 0xea7892e2U, + 0x0ea5ab06U, 0x8dc54885U, 0x76c3b57eU, 0x016a6b09U, + 0x18342c10U, 0x72c6b47aU, 0xf5a356fdU, 0xd18e5fd9U, + 0xbdf944b5U, 0xce559bc6U, 0xef3dd2e7U, 0x0c252904U, + 0x3fd9e637U, 0x91de4f99U, 0x33d6e53bU, 0x3a9ca632U, + 0x48703840U, 0xeb38d3e3U, 0xdd815cd5U, 0x9b54cf93U, + 0xc0da1ac8U, 0x5ba4ff53U, 0x1d716c15U, 0xa8a800a0U, + 0xcd9558c5U, 0x935ecd9bU, 0x552b7e5dU, 0xd0ce1ed8U, + 0x7783f47fU, 0x07efe80fU, 0xccd519c4U, 0x09606901U, + 0x136576f8U, 0x0a3b31e1U, 0xefa64904U, 0xb3ed5e58U, + 0x7b176c90U, 0xcf8e4124U, 0xbc229e57U, 0x9680167dU, + 0x10a5b5fbU, 0x92851779U, 0x18afb7f3U, 0x432162a8U, + 0xe8638b03U, 0xa7fc5b4cU, 0xf8778f13U, 0x5cfaa6b7U, + 0xe46c880fU, 0xd510c53eU, 0x22193bc9U, 0x9145d47aU, + 0xe069890bU, 0xb2ad1f59U, 0x58ffa7b3U, 0x472463acU, + 0xe2e90b09U, 0x59bfe6b2U, 0x04b4b0efU, 0xd055853bU, + 0x6d86eb86U, 0x527527b9U, 0x50f5a5bbU, 0x2e1638c5U, + 0x3a073dd1U, 0x41a1e0aaU, 0x09fbf2e2U, 0x9bcf5470U, + 0x0e3e30e5U, 0xf7b84f1cU, 0x2a1339c1U, 0xa179d84aU, + 0x8414906fU, 0x19eff6f2U, 0x64cca88fU, 0x45a4e1aeU, + 0xffb24d14U, 0x77186f9cU, 0xfaf70d11U, 0xc101c02aU, + 0xdb9f4430U, 0x8694126dU, 0x3887bfd3U, 0xeee60805U, + 0x6f066984U, 0x68c3ab83U, 0xeba34800U, 0x1e2a34f5U, + 0x4a6b21a1U, 0x37487fdcU, 0x1a2f35f1U, 0xa3f95a48U, + 0x9d4ad776U, 0x76582e9dU, 0xb4289c5fU, 0xd2d50739U, + 0x55b0e5beU, 0x54f0a4bfU, 0xd6d0063dU, 0xbbe75c50U, + 0x87d4536cU, 0x8554d16eU, 0x14a0b4ffU, 0xa2b91b49U, + 0x466422adU, 0x2dd6fbc6U, 0xb8279f53U, 0x2c96bac7U, + 0xd3954638U, 0x5e7a24b5U, 0x7598ed9eU, 0xeae30901U, + 0xe923ca02U, 0xe52cc90eU, 0x4e6e20a5U, 0x82911369U, + 0x8d5ed366U, 0xd91fc632U, 0x23597ac8U, 0x664c2a8dU, + 0xabf35840U, 0xe7ac4b0cU, 0x74d8ac9fU, 0x658ce98eU, + 0x895bd262U, 0x11e5f4faU, 0x3e023cd5U, 0x9c0a9677U, + 0x308dbddbU, 0xd85f8733U, 0x70ddad9bU, 0x31cdfcdaU, + 0xc504c12eU, 0x29d3fac2U, 0x0f7e71e4U, 0xc2c10329U, + 0xdc5a8637U, 0xc041812bU, 0xb967de52U, 0xa43c984fU, + 0x4ceea2a7U, 0xcc4e8227U, 0xa973da42U, 0x567026bdU, + 0x1b6f74f0U, 0x48eba3a3U, 0x51b5e4baU, 0x15e0f5feU, + 0x36083eddU, 0x077473ecU, 0xd450843fU, 0x01f1f0eaU, + 0x7997ee92U, 0x9005957bU, 0x40e1a1abU, 0xd790473cU, + 0xcacb0121U, 0x5b3f64b0U, 0x6b036880U, 0x320d3fd9U, + 0xe3a94a08U, 0xb6a81e5dU, 0x62492b89U, 0x037172e8U, + 0x49abe2a2U, 0x573067bcU, 0xa8339b43U, 0x9e8a1475U, + 0xc6c4022dU, 0x97c0577cU, 0x83d15268U, 0x731d6e98U, + 0xaff65944U, 0xcd0ec326U, 0x1caab6f7U, 0xcece0025U, + 0xcb8b4020U, 0xf2fd0f19U, 0x3dc2ffd6U, 0xdadf0531U, + 0x261c3acdU, 0x980f9773U, 0x2099b9cbU, 0x1deaf7f6U, + 0xfef20c15U, 0x063432edU, 0x8011916bU, 0x881b9363U, + 0x9fca5574U, 0x7a572d91U, 0x8e9e1065U, 0xc784432cU, + 0x3c82bed7U, 0x93c55678U, 0xc3814228U, 0xf07d8d1bU, + 0x426123a9U, 0xd115c43aU, 0x63096a88U, 0xc90bc222U, + 0x4b2b60a0U, 0xec668a07U, 0xc444802fU, 0xe6ec0a0dU, + 0x7cd2ae97U, 0x05f4f1eeU, 0x719dec9aU, 0xf538cd1eU, + 0x1f6a75f4U, 0x275c7bccU, 0x9400947fU, 0x5dbae7b6U, + 0x334d7ed8U, 0xbfe25d54U, 0x725d2f99U, 0xf4788c1fU, + 0x44e4a0afU, 0xb7e85f5cU, 0xe129c80aU, 0x8151d06aU, + 0xfd32cf16U, 0xf937ce12U, 0x25dcf9ceU, 0x0dfef3e6U, + 0x7e522c95U, 0x249cb8cfU, 0xf6f80e1dU, 0x023133e9U, + 0xa6bc1a4dU, 0x3f427dd4U, 0xbaa71d51U, 0xb568dd5eU, + 0x0cbeb2e7U, 0x2f5679c4U, 0x39c7fed2U, 0x4daee3a6U, + 0x3488bcdfU, 0x08bbb3e3U, 0x21d9f8caU, 0x2b5378c0U, + 0x60c9a98bU, 0x4f2e61a4U, 0x8c1e9267U, 0x6a432981U, + 0xdeda0435U, 0x7f126d94U, 0xa57cd94eU, 0xbea21c55U, + 0xfc728e17U, 0x994fd672U, 0x0b7b70e0U, 0x00b1b1ebU, + 0xaab31941U, 0xdf9a4534U, 0x9a8f1571U, 0x8a9b1161U, + 0x6e462885U, 0xed26cb06U, 0x162036fdU, 0x6189e88aU, + 0x78d7af93U, 0x122537f9U, 0x9540d57eU, 0xb16ddc5aU, + 0xdd1ac736U, 0xaeb61845U, 0x8fde5164U, 0x6cc6aa87U, + 0x5f3a65b4U, 0xf13dcc1aU, 0x533566b8U, 0x5a7f25b1U, + 0x2893bbc3U, 0x8bdb5060U, 0xbd62df56U, 0xfbb74c10U, + 0xa039994bU, 0x3b477cd0U, 0x7d92ef96U, 0xc84b8323U, + 0xad76db46U, 0xf3bd4e18U, 0x35c8fddeU, 0xb02d9d5bU, + 0x176077fcU, 0x670c6b8cU, 0xac369a47U, 0x6983ea82U, + 0x9a19830dU, 0x8347c414U, 0x66dabcf1U, 0x3a91abadU, + 0xf26b9965U, 0x46f2b4d1U, 0x355e6ba2U, 0x1ffce388U, + 0x99d9400eU, 0x1bf9e28cU, 0x91d34206U, 0xca5d975dU, + 0x611f7ef6U, 0x2e80aeb9U, 0x710b7ae6U, 0xd5865342U, + 0x6d107dfaU, 0x5c6c30cbU, 0xab65ce3cU, 0x1839218fU, + 0x69157cfeU, 0x3bd1eaacU, 0xd1835246U, 0xce589659U, + 0x6b95fefcU, 0xd0c31347U, 0x8dc8451aU, 0x592970ceU, + 0xe4fa1e73U, 0xdb09d24cU, 0xd989504eU, 0xa76acd30U, + 0xb37bc824U, 0xc8dd155fU, 0x80870717U, 0x12b3a185U, + 0x8742c510U, 0x7ec4bae9U, 0xa36fcc34U, 0x28052dbfU, + 0x0d68659aU, 0x90930307U, 0xedb05d7aU, 0xccd8145bU, + 0x76ceb8e1U, 0xfe649a69U, 0x738bf8e4U, 0x487d35dfU, + 0x52e3b1c5U, 0x0fe8e798U, 0xb1fb4a26U, 0x679afdf0U, + 0xe67a9c71U, 0xe1bf5e76U, 0x62dfbdf5U, 0x9756c100U, + 0xc317d454U, 0xbe348a29U, 0x9353c004U, 0x2a85afbdU, + 0x14362283U, 0xff24db68U, 0x3d5469aaU, 0x5ba9f2ccU, + 0xdccc104bU, 0xdd8c514aU, 0x5facf3c8U, 0x329ba9a5U, + 0x0ea8a699U, 0x0c28249bU, 0x9ddc410aU, 0x2bc5eebcU, + 0xcf18d758U, 0xa4aa0e33U, 0x315b6aa6U, 0xa5ea4f32U, + 0x5ae9b3cdU, 0xd706d140U, 0xfce4186bU, 0x639ffcf4U, + 0x605f3ff7U, 0x6c503cfbU, 0xc712d550U, 0x0bede69cU, + 0x04222693U, 0x506333c7U, 0xaa258f3dU, 0xef30df78U, + 0x228fadb5U, 0x6ed0bef9U, 0xfda4596aU, 0xecf01c7bU, + 0x00272797U, 0x9899010fU, 0xb77ec920U, 0x15766382U, + 0xb9f1482eU, 0x512372c6U, 0xf9a1586eU, 0xb8b1092fU, + 0x4c7834dbU, 0xa0af0f37U, 0x86028411U, 0x4bbdf6dcU, + 0x552673c2U, 0x493d74deU, 0x301b2ba7U, 0x2d406dbaU, + 0xc5925752U, 0x453277d2U, 0x200f2fb7U, 0xdf0cd348U, + 0x92138105U, 0xc1975656U, 0xd8c9114fU, 0x9c9c000bU, + 0xbf74cb28U, 0x8e088619U, 0x5d2c71caU, 0x888d051fU, + 0xf0eb1b67U, 0x1979608eU, 0xc99d545eU, 0x5eecb2c9U, + 0x43b7f4d4U, 0xd2439145U, 0xe27f9d75U, 0xbb71ca2cU, + 0x6ad5bffdU, 0x3fd4eba8U, 0xeb35de7cU, 0x8a0d871dU, + 0xc0d71757U, 0xde4c9249U, 0x214f6eb6U, 0x17f6e180U, + 0x4fb8f7d8U, 0x1ebca289U, 0x0aada79dU, 0xfa619b6dU, + 0x268aacb1U, 0x447236d3U, 0x95d64302U, 0x47b2f5d0U, + 0x42f7b5d5U, 0x7b81faecU, 0xb4be0a23U, 0x53a3f0c4U, + 0xaf60cf38U, 0x11736286U, 0xa9e54c3eU, 0x94960203U, + 0x778ef9e0U, 0x8f48c718U, 0x096d649eU, 0x01676696U, + 0x16b6a081U, 0xf32bd864U, 0x07e2e590U, 0x4ef8b6d9U, + 0xb5fe4b22U, 0x1ab9a38dU, 0x4afdb7ddU, 0x790178eeU, + 0xcb1dd65cU, 0x586931cfU, 0xea759f7dU, 0x407737d7U, + 0xc2579555U, 0x651a7ff2U, 0x4d3875daU, 0x6f90fff8U, + 0xf5ae5b62U, 0x8c88041bU, 0xf8e1196fU, 0x7c4438ebU, + 0x96168001U, 0xae208e39U, 0x1d7c618aU, 0xd4c61243U, + 0xba318b2dU, 0x369ea8a1U, 0xfb21da6cU, 0x7d0479eaU, + 0xcd98555aU, 0x3e94aaa9U, 0x68553dffU, 0x082d259fU, + 0x744e3ae3U, 0x704b3be7U, 0xaca00c3bU, 0x84820613U, + 0xf72ed960U, 0xade04d3aU, 0x7f84fbe8U, 0x8b4dc61cU, + 0x2fc0efb8U, 0xb63e8821U, 0x33dbe8a4U, 0x3c1428abU, + 0x85c24712U, 0xa62a8c31U, 0xb0bb0b27U, 0xc4d21653U, + 0xbdf4492aU, 0x81c74616U, 0xa8a50d3fU, 0xa22f8d35U, + 0xe9b55c7eU, 0xc6529451U, 0x05626792U, 0xe33fdc74U, + 0x57a6f1c0U, 0xf66e9861U, 0x2c002cbbU, 0x37dee9a0U, + 0x750e7be2U, 0x10332387U, 0x82078515U, 0x89cd441eU, + 0x23cfecb4U, 0x56e6b0c1U, 0x13f3e084U, 0x03e7e494U, + 0xe73add70U, 0x645a3ef3U, 0x9f5cc308U, 0xe8f51d7fU, + 0xf1ab5a66U, 0x9b59c20cU, 0x1c3c208bU, 0x381129afU, + 0x546632c3U, 0x27caedb0U, 0x06a2a491U, 0xe5ba5f72U, + 0xd6469041U, 0x784139efU, 0xda49934dU, 0xd303d044U, + 0xa1ef4e36U, 0x02a7a595U, 0x341e2aa3U, 0x72cbb9e5U, + 0x29456cbeU, 0xb23b8925U, 0xf4ee1a63U, 0x413776d6U, + 0x240a2eb3U, 0x7ac1bbedU, 0xbcb4082bU, 0x395168aeU, + 0x9e1c8209U, 0xee709e79U, 0x254a6fb2U, 0xe0ff1f77U, + 0xdb0cd759U, 0xc2529040U, 0x27cfe8a5U, 0x7b84fff9U, + 0xb37ecd31U, 0x07e7e085U, 0x744b3ff6U, 0x5ee9b7dcU, + 0xd8cc145aU, 0x5aecb6d8U, 0xd0c61652U, 0x8b48c309U, + 0x200a2aa2U, 0x6f95faedU, 0x301e2eb2U, 0x94930716U, + 0x2c0529aeU, 0x1d79649fU, 0xea709a68U, 0x592c75dbU, + 0x280028aaU, 0x7ac4bef8U, 0x90960612U, 0x8f4dc20dU, + 0x2a80aaa8U, 0x91d64713U, 0xccdd114eU, 0x183c249aU, + 0xa5ef4a27U, 0x9a1c8618U, 0x989c041aU, 0xe67f9964U, + 0xf26e9c70U, 0x89c8410bU, 0xc1925343U, 0x53a6f5d1U, + 0xc6579144U, 0x3fd1eebdU, 0xe27a9860U, 0x691079ebU, + 0x4c7d31ceU, 0xd1865753U, 0xaca5092eU, 0x8dcd400fU, + 0x37dbecb5U, 0xbf71ce3dU, 0x329eacb0U, 0x0968618bU, + 0x13f6e591U, 0x4efdb3ccU, 0xf0ee1e72U, 0x268fa9a4U, + 0xa76fc825U, 0xa0aa0a22U, 0x23cae9a1U, 0xd6439554U, + 0x82028000U, 0xff21de7dU, 0xd2469450U, 0x6b90fbe9U, + 0x552376d7U, 0xbe318f3cU, 0x7c413dfeU, 0x1abca698U, + 0x9dd9441fU, 0x9c99051eU, 0x1eb9a79cU, 0x738efdf1U, + 0x4fbdf2cdU, 0x4d3d70cfU, 0xdcc9155eU, 0x6ad0bae8U, + 0x8e0d830cU, 0xe5bf5a67U, 0x704e3ef2U, 0xe4ff1b66U, + 0x1bfce799U, 0x96138514U, 0xbdf14c3fU, 0x228aa8a0U, + 0x214a6ba3U, 0x2d4568afU, 0x86078104U, 0x4af8b2c8U, + 0x453772c7U, 0x11766793U, 0xeb30db69U, 0xae258b2cU, + 0x639af9e1U, 0x2fc5eaadU, 0xbcb10d3eU, 0xade5482fU, + 0x413273c3U, 0xd98c555bU, 0xf66b9d74U, 0x546337d6U, + 0xf8e41c7aU, 0x10362692U, 0xb8b40c3aU, 0xf9a45d7bU, + 0x0d6d608fU, 0xe1ba5b63U, 0xc717d045U, 0x0aa8a288U, + 0x14332796U, 0x0828208aU, 0x710e7ff3U, 0x6c5539eeU, + 0x84870306U, 0x04272386U, 0x611a7be3U, 0x9e19871cU, + 0xd306d551U, 0x80820202U, 0x99dc451bU, 0xdd89545fU, + 0xfe619f7cU, 0xcf1dd24dU, 0x1c39259eU, 0xc998514bU, + 0xb1fe4f33U, 0x586c34daU, 0x8888000aU, 0x1ff9e69dU, + 0x02a2a080U, 0x9356c511U, 0xa36ac921U, 0xfa649e78U, + 0x2bc0eba9U, 0x7ec1bffcU, 0xaa208a28U, 0xcb18d349U, + 0x81c24303U, 0x9f59c61dU, 0x605a3ae2U, 0x56e3b5d4U, + 0x0eada38cU, 0x5fa9f6ddU, 0x4bb8f3c9U, 0xbb74cf39U, + 0x679ff8e5U, 0x05676287U, 0xd4c31756U, 0x06a7a184U, + 0x03e2e181U, 0x3a94aeb8U, 0xf5ab5e77U, 0x12b6a490U, + 0xee759b6cU, 0x506636d2U, 0xe8f0186aU, 0xd5835657U, + 0x369badb4U, 0xce5d934cU, 0x487830caU, 0x407232c2U, + 0x57a3f4d5U, 0xb23e8c30U, 0x46f7b1c4U, 0x0fede28dU, + 0xf4eb1f76U, 0x5bacf7d9U, 0x0be8e389U, 0x38142cbaU, + 0x8a088208U, 0x197c659bU, 0xab60cb29U, 0x01626383U, + 0x8342c101U, 0x240f2ba6U, 0x0c2d218eU, 0x2e85abacU, + 0xb4bb0f36U, 0xcd9d504fU, 0xb9f44d3bU, 0x3d516cbfU, + 0xd703d455U, 0xef35da6dU, 0x5c6935deU, 0x95d34617U, + 0xfb24df79U, 0x778bfcf5U, 0xba348e38U, 0x3c112dbeU, + 0x8c8d010eU, 0x7f81fefdU, 0x294069abU, 0x493871cbU, + 0x355b6eb7U, 0x315e6fb3U, 0xedb5586fU, 0xc5975247U, + 0xb63b8d34U, 0xecf5196eU, 0x3e91afbcU, 0xca589248U, + 0x6ed5bbecU, 0xf72bdc75U, 0x72cebcf0U, 0x7d017cffU, + 0xc4d71346U, 0xe73fd865U, 0xf1ae5f73U, 0x85c74207U, + 0xfce11d7eU, 0xc0d21242U, 0xe9b0596bU, 0xe33ad961U, + 0xa8a0082aU, 0x8747c005U, 0x447733c6U, 0xa22a8820U, + 0x16b3a594U, 0xb77bcc35U, 0x6d1578efU, 0x76cbbdf4U, + 0x341b2fb6U, 0x512677d3U, 0xc312d141U, 0xc8d8104aU, + 0x62dab8e0U, 0x17f3e495U, 0x52e6b4d0U, 0x42f2b0c0U, + 0xa62f8924U, 0x254f6aa7U, 0xde49975cU, 0xa9e0492bU, + 0xb0be0e32U, 0xda4c9658U, 0x5d2974dfU, 0x79047dfbU, + 0x15736697U, 0x66dfb9e4U, 0x47b7f0c5U, 0xa4af0b26U, + 0x9753c415U, 0x39546dbbU, 0x9b5cc719U, 0x92168410U, + 0xe0fa1a62U, 0x43b2f1c1U, 0x750b7ef7U, 0x33deedb1U, + 0x685038eaU, 0xf32edd71U, 0xb5fb4e37U, 0x00222282U, + 0x651f7ae7U, 0x3bd4efb9U, 0xfda15c7fU, 0x78443cfaU, + 0xdf09d65dU, 0xaf65ca2dU, 0x645f3be6U, 0xa1ea4b23U, + 0xf852aa24U, 0xe10ced3dU, 0x049195d8U, 0x58da8284U, + 0x9020b04cU, 0x24b99df8U, 0x5715428bU, 0x7db7caa1U, + 0xfb926927U, 0x79b2cba5U, 0xf3986b2fU, 0xa816be74U, + 0x035457dfU, 0x4ccb8790U, 0x134053cfU, 0xb7cd7a6bU, + 0x0f5b54d3U, 0x3e2719e2U, 0xc92ee715U, 0x7a7208a6U, + 0x0b5e55d7U, 0x599ac385U, 0xb3c87b6fU, 0xac13bf70U, + 0x09ded7d5U, 0xb2883a6eU, 0xef836c33U, 0x3b6259e7U, + 0x86b1375aU, 0xb942fb65U, 0xbbc27967U, 0xc521e419U, + 0xd130e10dU, 0xaa963c76U, 0xe2cc2e3eU, 0x70f888acU, + 0xe509ec39U, 0x1c8f93c0U, 0xc124e51dU, 0x4a4e0496U, + 0x6f234cb3U, 0xf2d82a2eU, 0x8ffb7453U, 0xae933d72U, + 0x148591c8U, 0x9c2fb340U, 0x11c0d1cdU, 0x2a361cf6U, + 0x30a898ecU, 0x6da3ceb1U, 0xd3b0630fU, 0x05d1d4d9U, + 0x8431b558U, 0x83f4775fU, 0x009494dcU, 0xf51de829U, + 0xa15cfd7dU, 0xdc7fa300U, 0xf118e92dU, 0x48ce8694U, + 0x767d0baaU, 0x9d6ff241U, 0x5f1f4083U, 0x39e2dbe5U, + 0xbe873962U, 0xbfc77863U, 0x3de7dae1U, 0x50d0808cU, + 0x6ce38fb0U, 0x6e630db2U, 0xff976823U, 0x498ec795U, + 0xad53fe71U, 0xc6e1271aU, 0x5310438fU, 0xc7a1661bU, + 0x38a29ae4U, 0xb54df869U, 0x9eaf3142U, 0x01d4d5ddU, + 0x021416deU, 0x0e1b15d2U, 0xa559fc79U, 0x69a6cfb5U, + 0x66690fbaU, 0x32281aeeU, 0xc86ea614U, 0x8d7bf651U, + 0x40c4849cU, 0x0c9b97d0U, 0x9fef7043U, 0x8ebb3552U, + 0x626c0ebeU, 0xfad22826U, 0xd535e009U, 0x773d4aabU, + 0xdbba6107U, 0x33685befU, 0x9bea7147U, 0xdafa2006U, + 0x2e331df2U, 0xc2e4261eU, 0xe449ad38U, 0x29f6dff5U, + 0x376d5aebU, 0x2b765df7U, 0x5250028eU, 0x4f0b4493U, + 0xa7d97e7bU, 0x27795efbU, 0x4244069eU, 0xbd47fa61U, + 0xf058a82cU, 0xa3dc7f7fU, 0xba823866U, 0xfed72922U, + 0xdd3fe201U, 0xec43af30U, 0x3f6758e3U, 0xeac62c36U, + 0x92a0324eU, 0x7b3249a7U, 0xabd67d77U, 0x3ca79be0U, + 0x21fcddfdU, 0xb008b86cU, 0x8034b45cU, 0xd93ae305U, + 0x089e96d4U, 0x5d9fc281U, 0x897ef755U, 0xe846ae34U, + 0xa29c3e7eU, 0xbc07bb60U, 0x4304479fU, 0x75bdc8a9U, + 0x2df3def1U, 0x7cf78ba0U, 0x68e68eb4U, 0x982ab244U, + 0x44c18598U, 0x26391ffaU, 0xf79d6a2bU, 0x25f9dcf9U, + 0x20bc9cfcU, 0x19cad3c5U, 0xd6f5230aU, 0x31e8d9edU, + 0xcd2be611U, 0x73384bafU, 0xcbae6517U, 0xf6dd2b2aU, + 0x15c5d0c9U, 0xed03ee31U, 0x6b264db7U, 0x632c4fbfU, + 0x74fd89a8U, 0x9160f14dU, 0x65a9ccb9U, 0x2cb39ff0U, + 0xd7b5620bU, 0x78f28aa4U, 0x28b69ef4U, 0x1b4a51c7U, + 0xa956ff75U, 0x3a2218e6U, 0x883eb654U, 0x223c1efeU, + 0xa01cbc7cU, 0x075156dbU, 0x2f735cf3U, 0x0ddbd6d1U, + 0x97e5724bU, 0xeec32d32U, 0x9aaa3046U, 0x1e0f11c2U, + 0xf45da928U, 0xcc6ba710U, 0x7f3748a3U, 0xb68d3b6aU, + 0xd87aa204U, 0x54d58188U, 0x996af345U, 0x1f4f50c3U, + 0xafd37c73U, 0x5cdf8380U, 0x0a1e14d6U, 0x6a660cb6U, + 0x160513caU, 0x120012ceU, 0xceeb2512U, 0xe6c92f3aU, + 0x9565f049U, 0xcfab6413U, 0x1dcfd2c1U, 0xe906ef35U, + 0x4d8bc691U, 0xd475a108U, 0x5190c18dU, 0x5e5f0182U, + 0xe7896e3bU, 0xc461a518U, 0xd2f0220eU, 0xa6993f7aU, + 0xdfbf6003U, 0xe38c6f3fU, 0xcaee2416U, 0xc064a41cU, + 0x8bfe7557U, 0xa419bd78U, 0x67294ebbU, 0x8174f55dU, + 0x35edd8e9U, 0x9425b148U, 0x4e4b0592U, 0x5595c089U, + 0x174552cbU, 0x72780aaeU, 0xe04cac3cU, 0xeb866d37U, + 0x4184c59dU, 0x34ad99e8U, 0x71b8c9adU, 0x61accdbdU, + 0x8571f459U, 0x061117daU, 0xfd17ea21U, 0x8abe3456U, + 0x93e0734fU, 0xf912eb25U, 0x7e7709a2U, 0x5a5a0086U, + 0x362d1beaU, 0x4581c499U, 0x64e98db8U, 0x87f1765bU, + 0xb40db968U, 0x1a0a10c6U, 0xb802ba64U, 0xb148f96dU, + 0xc3a4671fU, 0x60ec8cbcU, 0x5655038aU, 0x108090ccU, + 0x4b0e4597U, 0xd070a00cU, 0x96a5334aU, 0x237c5fffU, + 0x4641079aU, 0x188a92c4U, 0xdeff2102U, 0x5b1a4187U, + 0xfc57ab20U, 0x8c3bb750U, 0x4701469bU, 0x82b4365eU, + 0x9f188709U, 0x8646c010U, 0x63dbb8f5U, 0x3f90afa9U, + 0xf76a9d61U, 0x43f3b0d5U, 0x305f6fa6U, 0x1afde78cU, + 0x9cd8440aU, 0x1ef8e688U, 0x94d24602U, 0xcf5c9359U, + 0x641e7af2U, 0x2b81aabdU, 0x740a7ee2U, 0xd0875746U, + 0x681179feU, 0x596d34cfU, 0xae64ca38U, 0x1d38258bU, + 0x6c1478faU, 0x3ed0eea8U, 0xd4825642U, 0xcb59925dU, + 0x6e94faf8U, 0xd5c21743U, 0x88c9411eU, 0x5c2874caU, + 0xe1fb1a77U, 0xde08d648U, 0xdc88544aU, 0xa26bc934U, + 0xb67acc20U, 0xcddc115bU, 0x85860313U, 0x17b2a581U, + 0x8243c114U, 0x7bc5beedU, 0xa66ec830U, 0x2d0429bbU, + 0x0869619eU, 0x95920703U, 0xe8b1597eU, 0xc9d9105fU, + 0x73cfbce5U, 0xfb659e6dU, 0x768afce0U, 0x4d7c31dbU, + 0x57e2b5c1U, 0x0ae9e39cU, 0xb4fa4e22U, 0x629bf9f4U, + 0xe37b9875U, 0xe4be5a72U, 0x67deb9f1U, 0x9257c504U, + 0xc616d050U, 0xbb358e2dU, 0x9652c400U, 0x2f84abb9U, + 0x11372687U, 0xfa25df6cU, 0x38556daeU, 0x5ea8f6c8U, + 0xd9cd144fU, 0xd88d554eU, 0x5aadf7ccU, 0x379aada1U, + 0x0ba9a29dU, 0x0929209fU, 0x98dd450eU, 0x2ec4eab8U, + 0xca19d35cU, 0xa1ab0a37U, 0x345a6ea2U, 0xa0eb4b36U, + 0x5fe8b7c9U, 0xd207d544U, 0xf9e51c6fU, 0x669ef8f0U, + 0x655e3bf3U, 0x695138ffU, 0xc213d154U, 0x0eece298U, + 0x01232297U, 0x556237c3U, 0xaf248b39U, 0xea31db7cU, + 0x278ea9b1U, 0x6bd1bafdU, 0xf8a55d6eU, 0xe9f1187fU, + 0x05262393U, 0x9d98050bU, 0xb27fcd24U, 0x10776786U, + 0xbcf04c2aU, 0x542276c2U, 0xfca05c6aU, 0xbdb00d2bU, + 0x497930dfU, 0xa5ae0b33U, 0x83038015U, 0x4ebcf2d8U, + 0x502777c6U, 0x4c3c70daU, 0x351a2fa3U, 0x284169beU, + 0xc0935356U, 0x403373d6U, 0x250e2bb3U, 0xda0dd74cU, + 0x97128501U, 0xc4965252U, 0xddc8154bU, 0x999d040fU, + 0xba75cf2cU, 0x8b09821dU, 0x582d75ceU, 0x8d8c011bU, + 0xf5ea1f63U, 0x1c78648aU, 0xcc9c505aU, 0x5bedb6cdU, + 0x46b6f0d0U, 0xd7429541U, 0xe77e9971U, 0xbe70ce28U, + 0x6fd4bbf9U, 0x3ad5efacU, 0xee34da78U, 0x8f0c8319U, + 0xc5d61353U, 0xdb4d964dU, 0x244e6ab2U, 0x12f7e584U, + 0x4ab9f3dcU, 0x1bbda68dU, 0x0faca399U, 0xff609f69U, + 0x238ba8b5U, 0x417332d7U, 0x90d74706U, 0x42b3f1d4U, + 0x47f6b1d1U, 0x7e80fee8U, 0xb1bf0e27U, 0x56a2f4c0U, + 0xaa61cb3cU, 0x14726682U, 0xace4483aU, 0x91970607U, + 0x728ffde4U, 0x8a49c31cU, 0x0c6c609aU, 0x04666292U, + 0x13b7a485U, 0xf62adc60U, 0x02e3e194U, 0x4bf9b2ddU, + 0xb0ff4f26U, 0x1fb8a789U, 0x4ffcb3d9U, 0x7c007ceaU, + 0xce1cd258U, 0x5d6835cbU, 0xef749b79U, 0x457633d3U, + 0xc7569151U, 0x601b7bf6U, 0x483971deU, 0x6a91fbfcU, + 0xf0af5f66U, 0x8989001fU, 0xfde01d6bU, 0x79453cefU, + 0x93178405U, 0xab218a3dU, 0x187d658eU, 0xd1c71647U, + 0xbf308f29U, 0x339faca5U, 0xfe20de68U, 0x78057deeU, + 0xc899515eU, 0x3b95aeadU, 0x6d5439fbU, 0x0d2c219bU, + 0x714f3ee7U, 0x754a3fe3U, 0xa9a1083fU, 0x81830217U, + 0xf22fdd64U, 0xa8e1493eU, 0x7a85ffecU, 0x8e4cc218U, + 0x2ac1ebbcU, 0xb33f8c25U, 0x36daeca0U, 0x39152cafU, + 0x80c34316U, 0xa32b8835U, 0xb5ba0f23U, 0xc1d31257U, + 0xb8f54d2eU, 0x84c64212U, 0xada4093bU, 0xa72e8931U, + 0xecb4587aU, 0xc3539055U, 0x00636396U, 0xe63ed870U, + 0x52a7f5c4U, 0xf36f9c65U, 0x290128bfU, 0x32dfeda4U, + 0x700f7fe6U, 0x15322783U, 0x87068111U, 0x8ccc401aU, + 0x26cee8b0U, 0x53e7b4c5U, 0x16f2e480U, 0x06e6e090U, + 0xe23bd974U, 0x615b3af7U, 0x9a5dc70cU, 0xedf4197bU, + 0xf4aa5e62U, 0x9e58c608U, 0x193d248fU, 0x3d102dabU, + 0x516736c7U, 0x22cbe9b4U, 0x03a3a095U, 0xe0bb5b76U, + 0xd3479445U, 0x7d403debU, 0xdf489749U, 0xd602d440U, + 0xa4ee4a32U, 0x07a6a191U, 0x311f2ea7U, 0x77cabde1U, + 0x2c4468baU, 0xb73a8d21U, 0xf1ef1e67U, 0x443672d2U, + 0x210b2ab7U, 0x7fc0bfe9U, 0xb9b50c2fU, 0x3c506caaU, + 0x9b1d860dU, 0xeb719a7dU, 0x204b6bb6U, 0xe5fe1b73U, + 0x49773eb0U, 0x502979a9U, 0xb5b4014cU, 0xe9ff1610U, + 0x210524d8U, 0x959c096cU, 0xe630d61fU, 0xcc925e35U, + 0x4ab7fdb3U, 0xc8975f31U, 0x42bdffbbU, 0x19332ae0U, + 0xb271c34bU, 0xfdee1304U, 0xa265c75bU, 0x06e8eeffU, + 0xbe7ec047U, 0x8f028d76U, 0x780b7381U, 0xcb579c32U, + 0xba7bc143U, 0xe8bf5711U, 0x02edeffbU, 0x1d362be4U, + 0xb8fb4341U, 0x03adaefaU, 0x5ea6f8a7U, 0x8a47cd73U, + 0x3794a3ceU, 0x08676ff1U, 0x0ae7edf3U, 0x7404708dU, + 0x60157599U, 0x1bb3a8e2U, 0x53e9baaaU, 0xc1dd1c38U, + 0x542c78adU, 0xadaa0754U, 0x70017189U, 0xfb6b9002U, + 0xde06d827U, 0x43fdbebaU, 0x3edee0c7U, 0x1fb6a9e6U, + 0xa5a0055cU, 0x2d0a27d4U, 0xa0e54559U, 0x9b138862U, + 0x818d0c78U, 0xdc865a25U, 0x6295f79bU, 0xb4f4404dU, + 0x351421ccU, 0x32d1e3cbU, 0xb1b10048U, 0x44387cbdU, + 0x107969e9U, 0x6d5a3794U, 0x403d7db9U, 0xf9eb1200U, + 0xc7589f3eU, 0x2c4a66d5U, 0xee3ad417U, 0x88c74f71U, + 0x0fa2adf6U, 0x0ee2ecf7U, 0x8cc24e75U, 0xe1f51418U, + 0xddc61b24U, 0xdf469926U, 0x4eb2fcb7U, 0xf8ab5301U, + 0x1c766ae5U, 0x77c4b38eU, 0xe235d71bU, 0x7684f28fU, + 0x89870e70U, 0x04686cfdU, 0x2f8aa5d6U, 0xb0f14149U, + 0xb331824aU, 0xbf3e8146U, 0x147c68edU, 0xd8835b21U, + 0xd74c9b2eU, 0x830d8e7aU, 0x794b3280U, 0x3c5e62c5U, + 0xf1e11008U, 0xbdbe0344U, 0x2ecae4d7U, 0x3f9ea1c6U, + 0xd3499a2aU, 0x4bf7bcb2U, 0x6410749dU, 0xc618de3fU, + 0x6a9ff593U, 0x824dcf7bU, 0x2acfe5d3U, 0x6bdfb492U, + 0x9f168966U, 0x73c1b28aU, 0x556c39acU, 0x98d34b61U, + 0x8648ce7fU, 0x9a53c963U, 0xe375961aU, 0xfe2ed007U, + 0x16fceaefU, 0x965cca6fU, 0xf361920aU, 0x0c626ef5U, + 0x417d3cb8U, 0x12f9ebebU, 0x0ba7acf2U, 0x4ff2bdb6U, + 0x6c1a7695U, 0x5d663ba4U, 0x8e42cc77U, 0x5be3b8a2U, + 0x2385a6daU, 0xca17dd33U, 0x1af3e9e3U, 0x8d820f74U, + 0x90d94969U, 0x012d2cf8U, 0x311120c8U, 0x681f7791U, + 0xb9bb0240U, 0xecba5615U, 0x385b63c1U, 0x59633aa0U, + 0x13b9aaeaU, 0x0d222ff4U, 0xf221d30bU, 0xc4985c3dU, + 0x9cd64a65U, 0xcdd21f34U, 0xd9c31a20U, 0x290f26d0U, + 0xf5e4110cU, 0x971c8b6eU, 0x46b8febfU, 0x94dc486dU, + 0x91990868U, 0xa8ef4751U, 0x67d0b79eU, 0x80cd4d79U, + 0x7c0e7285U, 0xc21ddf3bU, 0x7a8bf183U, 0x47f8bfbeU, + 0xa4e0445dU, 0x5c267aa5U, 0xda03d923U, 0xd209db2bU, + 0xc5d81d3cU, 0x204565d9U, 0xd48c582dU, 0x9d960b64U, + 0x6690f69fU, 0xc9d71e30U, 0x99930a60U, 0xaa6fc553U, + 0x18736be1U, 0x8b078c72U, 0x391b22c0U, 0x93198a6aU, + 0x113928e8U, 0xb674c24fU, 0x9e56c867U, 0xbcfe4245U, + 0x26c0e6dfU, 0x5fe6b9a6U, 0x2b8fa4d2U, 0xaf2a8556U, + 0x45783dbcU, 0x7d4e3384U, 0xce12dc37U, 0x07a8affeU, + 0x695f3690U, 0xe5f0151cU, 0x284f67d1U, 0xae6ac457U, + 0x1ef6e8e7U, 0xedfa1714U, 0xbb3b8042U, 0xdb439822U, + 0xa720875eU, 0xa325865aU, 0x7fceb186U, 0x57ecbbaeU, + 0x244064ddU, 0x7e8ef087U, 0xacea4655U, 0x58237ba1U, + 0xfcae5205U, 0x6550359cU, 0xe0b55519U, 0xef7a9516U, + 0x56acfaafU, 0x7544318cU, 0x63d5b69aU, 0x17bcabeeU, + 0x6e9af497U, 0x52a9fbabU, 0x7bcbb082U, 0x71413088U, + 0x3adbe1c3U, 0x153c29ecU, 0xd60cda2fU, 0x305161c9U, + 0x84c84c7dU, 0x250025dcU, 0xff6e9106U, 0xe4b0541dU, + 0xa660c65fU, 0xc35d9e3aU, 0x516938a8U, 0x5aa3f9a3U, + 0xf0a15109U, 0x85880d7cU, 0xc09d5d39U, 0xd0895929U, + 0x345460cdU, 0xb734834eU, 0x4c327eb5U, 0x3b9ba0c2U, + 0x22c5e7dbU, 0x48377fb1U, 0xcf529d36U, 0xeb7f9412U, + 0x87088f7eU, 0xf4a4500dU, 0xd5cc192cU, 0x36d4e2cfU, + 0x05282dfcU, 0xab2f8452U, 0x09272ef0U, 0x006d6df9U, + 0x7281f38bU, 0xd1c91828U, 0xe770971eU, 0xa1a50458U, + 0xfa2bd103U, 0x61553498U, 0x2780a7deU, 0x9259cb6bU, + 0xf764930eU, 0xa9af0650U, 0x6fdab596U, 0xea3fd513U, + 0x4d723fb4U, 0x3d1e23c4U, 0xf624d20fU, 0x3391a2caU, + 0xfafa008eU, 0xe3a44797U, 0x06393f72U, 0x5a72282eU, + 0x92881ae6U, 0x26113752U, 0x55bde821U, 0x7f1f600bU, + 0xf93ac38dU, 0x7b1a610fU, 0xf130c185U, 0xaabe14deU, + 0x01fcfd75U, 0x4e632d3aU, 0x11e8f965U, 0xb565d0c1U, + 0x0df3fe79U, 0x3c8fb348U, 0xcb864dbfU, 0x78daa20cU, + 0x09f6ff7dU, 0x5b32692fU, 0xb160d1c5U, 0xaebb15daU, + 0x0b767d7fU, 0xb02090c4U, 0xed2bc699U, 0x39caf34dU, + 0x84199df0U, 0xbbea51cfU, 0xb96ad3cdU, 0xc7894eb3U, + 0xd3984ba7U, 0xa83e96dcU, 0xe0648494U, 0x72502206U, + 0xe7a14693U, 0x1e27396aU, 0xc38c4fb7U, 0x48e6ae3cU, + 0x6d8be619U, 0xf0708084U, 0x8d53def9U, 0xac3b97d8U, + 0x162d3b62U, 0x9e8719eaU, 0x13687b67U, 0x289eb65cU, + 0x32003246U, 0x6f0b641bU, 0xd118c9a5U, 0x07797e73U, + 0x86991ff2U, 0x815cddf5U, 0x023c3e76U, 0xf7b54283U, + 0xa3f457d7U, 0xded709aaU, 0xf3b04387U, 0x4a662c3eU, + 0x74d5a100U, 0x9fc758ebU, 0x5db7ea29U, 0x3b4a714fU, + 0xbc2f93c8U, 0xbd6fd2c9U, 0x3f4f704bU, 0x52782a26U, + 0x6e4b251aU, 0x6ccba718U, 0xfd3fc289U, 0x4b266d3fU, + 0xaffb54dbU, 0xc4498db0U, 0x51b8e925U, 0xc509ccb1U, + 0x3a0a304eU, 0xb7e552c3U, 0x9c079be8U, 0x037c7f77U, + 0x00bcbc74U, 0x0cb3bf78U, 0xa7f156d3U, 0x6b0e651fU, + 0x64c1a510U, 0x3080b044U, 0xcac60cbeU, 0x8fd35cfbU, + 0x426c2e36U, 0x0e333d7aU, 0x9d47dae9U, 0x8c139ff8U, + 0x60c4a414U, 0xf87a828cU, 0xd79d4aa3U, 0x7595e001U, + 0xd912cbadU, 0x31c0f145U, 0x9942dbedU, 0xd8528aacU, + 0x2c9bb758U, 0xc04c8cb4U, 0xe6e10792U, 0x2b5e755fU, + 0x35c5f041U, 0x29def75dU, 0x50f8a824U, 0x4da3ee39U, + 0xa571d4d1U, 0x25d1f451U, 0x40ecac34U, 0xbfef50cbU, + 0xf2f00286U, 0xa174d5d5U, 0xb82a92ccU, 0xfc7f8388U, + 0xdf9748abU, 0xeeeb059aU, 0x3dcff249U, 0xe86e869cU, + 0x900898e4U, 0x799ae30dU, 0xa97ed7ddU, 0x3e0f314aU, + 0x23547757U, 0xb2a012c6U, 0x829c1ef6U, 0xdb9249afU, + 0x0a363c7eU, 0x5f37682bU, 0x8bd65dffU, 0xeaee049eU, + 0xa03494d4U, 0xbeaf11caU, 0x41aced35U, 0x77156203U, + 0x2f5b745bU, 0x7e5f210aU, 0x6a4e241eU, 0x9a8218eeU, + 0x46692f32U, 0x2491b550U, 0xf535c081U, 0x27517653U, + 0x22143656U, 0x1b62796fU, 0xd45d89a0U, 0x33407347U, + 0xcf834cbbU, 0x7190e105U, 0xc906cfbdU, 0xf4758180U, + 0x176d7a63U, 0xefab449bU, 0x698ee71dU, 0x6184e515U, + 0x76552302U, 0x93c85be7U, 0x67016613U, 0x2e1b355aU, + 0xd51dc8a1U, 0x7a5a200eU, 0x2a1e345eU, 0x19e2fb6dU, + 0xabfe55dfU, 0x388ab24cU, 0x8a961cfeU, 0x2094b454U, + 0xa2b416d6U, 0x05f9fc71U, 0x2ddbf659U, 0x0f737c7bU, + 0x954dd8e1U, 0xec6b8798U, 0x98029aecU, 0x1ca7bb68U, + 0xf6f50382U, 0xcec30dbaU, 0x7d9fe209U, 0xb42591c0U, + 0xdad208aeU, 0x567d2b22U, 0x9bc259efU, 0x1de7fa69U, + 0xad7bd6d9U, 0x5e77292aU, 0x08b6be7cU, 0x68cea61cU, + 0x14adb960U, 0x10a8b864U, 0xcc438fb8U, 0xe4618590U, + 0x97cd5ae3U, 0xcd03ceb9U, 0x1f67786bU, 0xebae459fU, + 0x4f236c3bU, 0xd6dd0ba2U, 0x53386b27U, 0x5cf7ab28U, + 0xe521c491U, 0xc6c90fb2U, 0xd05888a4U, 0xa43195d0U, + 0xdd17caa9U, 0xe124c595U, 0xc8468ebcU, 0xc2cc0eb6U, + 0x8956dffdU, 0xa6b117d2U, 0x6581e411U, 0x83dc5ff7U, + 0x37457243U, 0x968d1be2U, 0x4ce3af38U, 0x573d6a23U, + 0x15edf861U, 0x70d0a004U, 0xe2e40696U, 0xe92ec79dU, + 0x432c6f37U, 0x36053342U, 0x73106307U, 0x63046717U, + 0x87d95ef3U, 0x04b9bd70U, 0xffbf408bU, 0x88169efcU, + 0x9148d9e5U, 0xfbba418fU, 0x7cdfa308U, 0x58f2aa2cU, + 0x3485b140U, 0x47296e33U, 0x66412712U, 0x8559dcf1U, + 0xb6a513c2U, 0x18a2ba6cU, 0xbaaa10ceU, 0xb3e053c7U, + 0xc10ccdb5U, 0x62442616U, 0x54fda920U, 0x12283a66U, + 0x49a6ef3dU, 0xd2d80aa6U, 0x940d99e0U, 0x21d4f555U, + 0x44e9ad30U, 0x1a22386eU, 0xdc578ba8U, 0x59b2eb2dU, + 0xfeff018aU, 0x8e931dfaU, 0x45a9ec31U, 0x801c9cf4U, + 0xe803eb65U, 0xf15dac7cU, 0x14c0d499U, 0x488bc3c5U, + 0x8071f10dU, 0x34e8dcb9U, 0x474403caU, 0x6de68be0U, + 0xebc32866U, 0x69e38ae4U, 0xe3c92a6eU, 0xb847ff35U, + 0x1305169eU, 0x5c9ac6d1U, 0x0311128eU, 0xa79c3b2aU, + 0x1f0a1592U, 0x2e7658a3U, 0xd97fa654U, 0x6a2349e7U, + 0x1b0f1496U, 0x49cb82c4U, 0xa3993a2eU, 0xbc42fe31U, + 0x198f9694U, 0xa2d97b2fU, 0xffd22d72U, 0x2b3318a6U, + 0x96e0761bU, 0xa913ba24U, 0xab933826U, 0xd570a558U, + 0xc161a04cU, 0xbac77d37U, 0xf29d6f7fU, 0x60a9c9edU, + 0xf558ad78U, 0x0cded281U, 0xd175a45cU, 0x5a1f45d7U, + 0x7f720df2U, 0xe2896b6fU, 0x9faa3512U, 0xbec27c33U, + 0x04d4d089U, 0x8c7ef201U, 0x0191908cU, 0x3a675db7U, + 0x20f9d9adU, 0x7df28ff0U, 0xc3e1224eU, 0x15809598U, + 0x9460f419U, 0x93a5361eU, 0x10c5d59dU, 0xe54ca968U, + 0xb10dbc3cU, 0xcc2ee241U, 0xe149a86cU, 0x589fc7d5U, + 0x662c4aebU, 0x8d3eb300U, 0x4f4e01c2U, 0x29b39aa4U, + 0xaed67823U, 0xaf963922U, 0x2db69ba0U, 0x4081c1cdU, + 0x7cb2cef1U, 0x7e324cf3U, 0xefc62962U, 0x59df86d4U, + 0xbd02bf30U, 0xd6b0665bU, 0x434102ceU, 0xd7f0275aU, + 0x28f3dba5U, 0xa51cb928U, 0x8efe7003U, 0x1185949cU, + 0x1245579fU, 0x1e4a5493U, 0xb508bd38U, 0x79f78ef4U, + 0x76384efbU, 0x22795bafU, 0xd83fe755U, 0x9d2ab710U, + 0x5095c5ddU, 0x1ccad691U, 0x8fbe3102U, 0x9eea7413U, + 0x723d4fffU, 0xea836967U, 0xc564a148U, 0x676c0beaU, + 0xcbeb2046U, 0x23391aaeU, 0x8bbb3006U, 0xcaab6147U, + 0x3e625cb3U, 0xd2b5675fU, 0xf418ec79U, 0x39a79eb4U, + 0x273c1baaU, 0x3b271cb6U, 0x420143cfU, 0x5f5a05d2U, + 0xb7883f3aU, 0x37281fbaU, 0x521547dfU, 0xad16bb20U, + 0xe009e96dU, 0xb38d3e3eU, 0xaad37927U, 0xee866863U, + 0xcd6ea340U, 0xfc12ee71U, 0x2f3619a2U, 0xfa976d77U, + 0x82f1730fU, 0x6b6308e6U, 0xbb873c36U, 0x2cf6daa1U, + 0x31ad9cbcU, 0xa059f92dU, 0x9065f51dU, 0xc96ba244U, + 0x18cfd795U, 0x4dce83c0U, 0x992fb614U, 0xf817ef75U, + 0xb2cd7f3fU, 0xac56fa21U, 0x535506deU, 0x65ec89e8U, + 0x3da29fb0U, 0x6ca6cae1U, 0x78b7cff5U, 0x887bf305U, + 0x5490c4d9U, 0x36685ebbU, 0xe7cc2b6aU, 0x35a89db8U, + 0x30edddbdU, 0x099b9284U, 0xc6a4624bU, 0x21b998acU, + 0xdd7aa750U, 0x63690aeeU, 0xdbff2456U, 0xe68c6a6bU, + 0x05949188U, 0xfd52af70U, 0x7b770cf6U, 0x737d0efeU, + 0x64acc8e9U, 0x8131b00cU, 0x75f88df8U, 0x3ce2deb1U, + 0xc7e4234aU, 0x68a3cbe5U, 0x38e7dfb5U, 0x0b1b1086U, + 0xb907be34U, 0x2a7359a7U, 0x986ff715U, 0x326d5fbfU, + 0xb04dfd3dU, 0x1700179aU, 0x3f221db2U, 0x1d8a9790U, + 0x87b4330aU, 0xfe926c73U, 0x8afb7107U, 0x0e5e5083U, + 0xe40ce869U, 0xdc3ae651U, 0x6f6609e2U, 0xa6dc7a2bU, + 0xc82be345U, 0x4484c0c9U, 0x893bb204U, 0x0f1e1182U, + 0xbf823d32U, 0x4c8ec2c1U, 0x1a4f5597U, 0x7a374df7U, + 0x0654528bU, 0x0251538fU, 0xdeba6453U, 0xf6986e7bU, + 0x8534b108U, 0xdffa2552U, 0x0d9e9380U, 0xf957ae74U, + 0x5dda87d0U, 0xc424e049U, 0x41c180ccU, 0x4e0e40c3U, + 0xf7d82f7aU, 0xd430e459U, 0xc2a1634fU, 0xb6c87e3bU, + 0xcfee2142U, 0xf3dd2e7eU, 0xdabf6557U, 0xd035e55dU, + 0x9baf3416U, 0xb448fc39U, 0x77780ffaU, 0x9125b41cU, + 0x25bc99a8U, 0x8474f009U, 0x5e1a44d3U, 0x45c481c8U, + 0x0714138aU, 0x62294befU, 0xf01ded7dU, 0xfbd72c76U, + 0x51d584dcU, 0x24fcd8a9U, 0x61e988ecU, 0x71fd8cfcU, + 0x9520b518U, 0x1640569bU, 0xed46ab60U, 0x9aef7517U, + 0x83b1320eU, 0xe943aa64U, 0x6e2648e3U, 0x4a0b41c7U, + 0x267c5aabU, 0x55d085d8U, 0x74b8ccf9U, 0x97a0371aU, + 0xa45cf829U, 0x0a5b5187U, 0xa853fb25U, 0xa119b82cU, + 0xd3f5265eU, 0x70bdcdfdU, 0x460442cbU, 0x00d1d18dU, + 0x5b5f04d6U, 0xc021e14dU, 0x86f4720bU, 0x332d1ebeU, + 0x561046dbU, 0x08dbd385U, 0xceae6043U, 0x4b4b00c6U, + 0xec06ea61U, 0x9c6af611U, 0x575007daU, 0x92e5771fU, + 0x98b129a7U, 0x81ef6ebeU, 0x6472165bU, 0x38390107U, + 0xf0c333cfU, 0x445a1e7bU, 0x37f6c108U, 0x1d544922U, + 0x9b71eaa4U, 0x19514826U, 0x937be8acU, 0xc8f53df7U, + 0x63b7d45cU, 0x2c280413U, 0x73a3d04cU, 0xd72ef9e8U, + 0x6fb8d750U, 0x5ec49a61U, 0xa9cd6496U, 0x1a918b25U, + 0x6bbdd654U, 0x39794006U, 0xd32bf8ecU, 0xccf03cf3U, + 0x693d5456U, 0xd26bb9edU, 0x8f60efb0U, 0x5b81da64U, + 0xe652b4d9U, 0xd9a178e6U, 0xdb21fae4U, 0xa5c2679aU, + 0xb1d3628eU, 0xca75bff5U, 0x822fadbdU, 0x101b0b2fU, + 0x85ea6fbaU, 0x7c6c1043U, 0xa1c7669eU, 0x2aad8715U, + 0x0fc0cf30U, 0x923ba9adU, 0xef18f7d0U, 0xce70bef1U, + 0x7466124bU, 0xfccc30c3U, 0x7123524eU, 0x4ad59f75U, + 0x504b1b6fU, 0x0d404d32U, 0xb353e08cU, 0x6532575aU, + 0xe4d236dbU, 0xe317f4dcU, 0x6077175fU, 0x95fe6baaU, + 0xc1bf7efeU, 0xbc9c2083U, 0x91fb6aaeU, 0x282d0517U, + 0x169e8829U, 0xfd8c71c2U, 0x3ffcc300U, 0x59015866U, + 0xde64bae1U, 0xdf24fbe0U, 0x5d045962U, 0x3033030fU, + 0x0c000c33U, 0x0e808e31U, 0x9f74eba0U, 0x296d4416U, + 0xcdb07df2U, 0xa602a499U, 0x33f3c00cU, 0xa742e598U, + 0x58411967U, 0xd5ae7beaU, 0xfe4cb2c1U, 0x6137565eU, + 0x62f7955dU, 0x6ef89651U, 0xc5ba7ffaU, 0x09454c36U, + 0x068a8c39U, 0x52cb996dU, 0xa88d2597U, 0xed9875d2U, + 0x2027071fU, 0x6c781453U, 0xff0cf3c0U, 0xee58b6d1U, + 0x028f8d3dU, 0x9a31aba5U, 0xb5d6638aU, 0x17dec928U, + 0xbb59e284U, 0x538bd86cU, 0xfb09f2c4U, 0xba19a385U, + 0x4ed09e71U, 0xa207a59dU, 0x84aa2ebbU, 0x49155c76U, + 0x578ed968U, 0x4b95de74U, 0x32b3810dU, 0x2fe8c710U, + 0xc73afdf8U, 0x479add78U, 0x22a7851dU, 0xdda479e2U, + 0x90bb2bafU, 0xc33ffcfcU, 0xda61bbe5U, 0x9e34aaa1U, + 0xbddc6182U, 0x8ca02cb3U, 0x5f84db60U, 0x8a25afb5U, + 0xf243b1cdU, 0x1bd1ca24U, 0xcb35fef4U, 0x5c441863U, + 0x411f5e7eU, 0xd0eb3befU, 0xe0d737dfU, 0xb9d96086U, + 0x687d1557U, 0x3d7c4102U, 0xe99d74d6U, 0x88a52db7U, + 0xc27fbdfdU, 0xdce438e3U, 0x23e7c41cU, 0x155e4b2aU, + 0x4d105d72U, 0x1c140823U, 0x08050d37U, 0xf8c931c7U, + 0x2422061bU, 0x46da9c79U, 0x977ee9a8U, 0x451a5f7aU, + 0x405f1f7fU, 0x79295046U, 0xb616a089U, 0x510b5a6eU, + 0xadc86592U, 0x13dbc82cU, 0xab4de694U, 0x963ea8a9U, + 0x7526534aU, 0x8de06db2U, 0x0bc5ce34U, 0x03cfcc3cU, + 0x141e0a2bU, 0xf18372ceU, 0x054a4f3aU, 0x4c501c73U, + 0xb756e188U, 0x18110927U, 0x48551d77U, 0x7ba9d244U, + 0xc9b57cf6U, 0x5ac19b65U, 0xe8dd35d7U, 0x42df9d7dU, + 0xc0ff3fffU, 0x67b2d558U, 0x4f90df70U, 0x6d385552U, + 0xf706f1c8U, 0x8e20aeb1U, 0xfa49b3c5U, 0x7eec9241U, + 0x94be2aabU, 0xac882493U, 0x1fd4cb20U, 0xd66eb8e9U, + 0xb8992187U, 0x3436020bU, 0xf98970c6U, 0x7facd340U, + 0xcf30fff0U, 0x3c3c0003U, 0x6afd9755U, 0x0a858f35U, + 0x76e69049U, 0x72e3914dU, 0xae08a691U, 0x862aacb9U, + 0xf58673caU, 0xaf48e790U, 0x7d2c5142U, 0x89e56cb6U, + 0x2d684512U, 0xb496228bU, 0x3173420eU, 0x3ebc8201U, + 0x876aedb8U, 0xa482269bU, 0xb213a18dU, 0xc67abcf9U, + 0xbf5ce380U, 0x836fecbcU, 0xaa0da795U, 0xa087279fU, + 0xeb1df6d4U, 0xc4fa3efbU, 0x07cacd38U, 0xe19776deU, + 0x550e5b6aU, 0xf4c632cbU, 0x2ea88611U, 0x3576430aU, + 0x77a6d148U, 0x129b892dU, 0x80af2fbfU, 0x8b65eeb4U, + 0x2167461eU, 0x544e1a6bU, 0x115b4a2eU, 0x014f4e3eU, + 0xe59277daU, 0x66f29459U, 0x9df469a2U, 0xea5db7d5U, + 0xf303f0ccU, 0x99f168a6U, 0x1e948a21U, 0x3ab98305U, + 0x56ce9869U, 0x2562471aU, 0x040a0e3bU, 0xe712f5d8U, + 0xd4ee3aebU, 0x7ae99345U, 0xd8e139e7U, 0xd1ab7aeeU, + 0xa347e49cU, 0x000f0f3fU, 0x36b68009U, 0x7063134fU, + 0x2bedc614U, 0xb093238fU, 0xf646b0c9U, 0x439fdc7cU, + 0x26a28419U, 0x78691147U, 0xbe1ca281U, 0x3bf9c204U, + 0x9cb428a3U, 0xecd834d3U, 0x27e2c518U, 0xe257b5ddU, + 0x652a4fc1U, 0x7c7408d8U, 0x99e9703dU, 0xc5a26761U, + 0x0d5855a9U, 0xb9c1781dU, 0xca6da76eU, 0xe0cf2f44U, + 0x66ea8cc2U, 0xe4ca2e40U, 0x6ee08ecaU, 0x356e5b91U, + 0x9e2cb23aU, 0xd1b36275U, 0x8e38b62aU, 0x2ab59f8eU, + 0x9223b136U, 0xa35ffc07U, 0x545602f0U, 0xe70aed43U, + 0x9626b032U, 0xc4e22660U, 0x2eb09e8aU, 0x316b5a95U, + 0x94a63230U, 0x2ff0df8bU, 0x72fb89d6U, 0xa61abc02U, + 0x1bc9d2bfU, 0x243a1e80U, 0x26ba9c82U, 0x585901fcU, + 0x4c4804e8U, 0x37eed993U, 0x7fb4cbdbU, 0xed806d49U, + 0x787109dcU, 0x81f77625U, 0x5c5c00f8U, 0xd736e173U, + 0xf25ba956U, 0x6fa0cfcbU, 0x128391b6U, 0x33ebd897U, + 0x89fd742dU, 0x015756a5U, 0x8cb83428U, 0xb74ef913U, + 0xadd07d09U, 0xf0db2b54U, 0x4ec886eaU, 0x98a9313cU, + 0x194950bdU, 0x1e8c92baU, 0x9dec7139U, 0x68650dccU, + 0x3c241898U, 0x410746e5U, 0x6c600cc8U, 0xd5b66371U, + 0xeb05ee4fU, 0x001717a4U, 0xc267a566U, 0xa49a3e00U, + 0x23ffdc87U, 0x22bf9d86U, 0xa09f3f04U, 0xcda86569U, + 0xf19b6a55U, 0xf31be857U, 0x62ef8dc6U, 0xd4f62270U, + 0x302b1b94U, 0x5b99c2ffU, 0xce68a66aU, 0x5ad983feU, + 0xa5da7f01U, 0x28351d8cU, 0x03d7d4a7U, 0x9cac3038U, + 0x9f6cf33bU, 0x9363f037U, 0x3821199cU, 0xf4de2a50U, + 0xfb11ea5fU, 0xaf50ff0bU, 0x551643f1U, 0x100313b4U, + 0xddbc6179U, 0x91e37235U, 0x029795a6U, 0x13c3d0b7U, + 0xff14eb5bU, 0x67aacdc3U, 0x484d05ecU, 0xea45af4eU, + 0x46c284e2U, 0xae10be0aU, 0x069294a2U, 0x4782c5e3U, + 0xb34bf817U, 0x5f9cc3fbU, 0x793148ddU, 0xb48e3a10U, + 0xaa15bf0eU, 0xb60eb812U, 0xcf28e76bU, 0xd273a176U, + 0x3aa19b9eU, 0xba01bb1eU, 0xdf3ce37bU, 0x203f1f84U, + 0x6d204dc9U, 0x3ea49a9aU, 0x27fadd83U, 0x63afccc7U, + 0x404707e4U, 0x713b4ad5U, 0xa21fbd06U, 0x77bec9d3U, + 0x0fd8d7abU, 0xe64aac42U, 0x36ae9892U, 0xa1df7e05U, + 0xbc843818U, 0x2d705d89U, 0x1d4c51b9U, 0x444206e0U, + 0x95e67331U, 0xc0e72764U, 0x140612b0U, 0x753e4bd1U, + 0x3fe4db9bU, 0x217f5e85U, 0xde7ca27aU, 0xe8c52d4cU, + 0xb08b3b14U, 0xe18f6e45U, 0xf59e6b51U, 0x055257a1U, + 0xd9b9607dU, 0xbb41fa1fU, 0x6ae58fceU, 0xb881391cU, + 0xbdc47919U, 0x84b23620U, 0x4b8dc6efU, 0xac903c08U, + 0x505303f4U, 0xee40ae4aU, 0x56d680f2U, 0x6ba5cecfU, + 0x88bd352cU, 0x707b0bd4U, 0xf65ea852U, 0xfe54aa5aU, + 0xe9856c4dU, 0x0c1814a8U, 0xf8d1295cU, 0xb1cb7a15U, + 0x4acd87eeU, 0xe58a6f41U, 0xb5ce7b11U, 0x8632b422U, + 0x342e1a90U, 0xa75afd03U, 0x154653b1U, 0xbf44fb1bU, + 0x3d645999U, 0x9a29b33eU, 0xb20bb916U, 0x90a33334U, + 0x0a9d97aeU, 0x73bbc8d7U, 0x07d2d5a3U, 0x8377f427U, + 0x69254ccdU, 0x511342f5U, 0xe24fad46U, 0x2bf5de8fU, + 0x450247e1U, 0xc9ad646dU, 0x041216a0U, 0x8237b526U, + 0x32ab9996U, 0xc1a76665U, 0x9766f133U, 0xf71ee953U, + 0x8b7df62fU, 0x8f78f72bU, 0x5393c0f7U, 0x7bb1cadfU, + 0x081d15acU, 0x52d381f6U, 0x80b73724U, 0x747e0ad0U, + 0xd0f32374U, 0x490d44edU, 0xcce82468U, 0xc327e467U, + 0x7af18bdeU, 0x591940fdU, 0x4f88c7ebU, 0x3be1da9fU, + 0x42c785e6U, 0x7ef48adaU, 0x5796c1f3U, 0x5d1c41f9U, + 0x168690b2U, 0x3961589dU, 0xfa51ab5eU, 0x1c0c10b8U, + 0xa8953d0cU, 0x095d54adU, 0xd333e077U, 0xc8ed256cU, + 0x8a3db72eU, 0xef00ef4bU, 0x7d3449d9U, 0x76fe88d2U, + 0xdcfc2078U, 0xa9d57c0dU, 0xecc02c48U, 0xfcd42858U, + 0x180911bcU, 0x9b69f23fU, 0x606f0fc4U, 0x17c6d1b3U, + 0x0e9896aaU, 0x646a0ec0U, 0xe30fec47U, 0xc722e563U, + 0xab55fe0fU, 0xd8f9217cU, 0xf991685dU, 0x1a8993beU, + 0x29755c8dU, 0x8772f523U, 0x257a5f81U, 0x2c301c88U, + 0x5edc82faU, 0xfd946959U, 0xcb2de66fU, 0x8df87529U, + 0xd676a072U, 0x4d0845e9U, 0x0bddd6afU, 0xbe04ba1aU, + 0xdb39e27fU, 0x85f27721U, 0x4387c4e7U, 0xc662a462U, + 0x612f4ec5U, 0x114352b5U, 0xda79a37eU, 0x1fccd3bbU, + 0x00c8c846U, 0x19968f5fU, 0xfc0bf7baU, 0xa040e0e6U, + 0x68bad22eU, 0xdc23ff9aU, 0xaf8f20e9U, 0x852da8c3U, + 0x03080b45U, 0x8128a9c7U, 0x0b02094dU, 0x508cdc16U, + 0xfbce35bdU, 0xb451e5f2U, 0xebda31adU, 0x4f571809U, + 0xf7c136b1U, 0xc6bd7b80U, 0x31b48577U, 0x82e86ac4U, + 0xf3c437b5U, 0xa100a1e7U, 0x4b52190dU, 0x5489dd12U, + 0xf144b5b7U, 0x4a12580cU, 0x17190e51U, 0xc3f83b85U, + 0x7e2b5538U, 0x41d89907U, 0x43581b05U, 0x3dbb867bU, + 0x29aa836fU, 0x520c5e14U, 0x1a564c5cU, 0x8862eaceU, + 0x1d938e5bU, 0xe415f1a2U, 0x39be877fU, 0xb2d466f4U, + 0x97b92ed1U, 0x0a42484cU, 0x77611631U, 0x56095f10U, + 0xec1ff3aaU, 0x64b5d122U, 0xe95ab3afU, 0xd2ac7e94U, + 0xc832fa8eU, 0x9539acd3U, 0x2b2a016dU, 0xfd4bb6bbU, + 0x7cabd73aU, 0x7b6e153dU, 0xf80ef6beU, 0x0d878a4bU, + 0x59c69f1fU, 0x24e5c162U, 0x09828b4fU, 0xb054e4f6U, + 0x8ee769c8U, 0x65f59023U, 0xa78522e1U, 0xc178b987U, + 0x461d5b00U, 0x475d1a01U, 0xc57db883U, 0xa84ae2eeU, + 0x9479edd2U, 0x96f96fd0U, 0x070d0a41U, 0xb114a5f7U, + 0x55c99c13U, 0x3e7b4578U, 0xab8a21edU, 0x3f3b0479U, + 0xc038f886U, 0x4dd79a0bU, 0x66355320U, 0xf94eb7bfU, + 0xfa8e74bcU, 0xf68177b0U, 0x5dc39e1bU, 0x913cadd7U, + 0x9ef36dd8U, 0xcab2788cU, 0x30f4c476U, 0x75e19433U, + 0xb85ee6feU, 0xf401f5b2U, 0x67751221U, 0x76215730U, + 0x9af66cdcU, 0x02484a44U, 0x2daf826bU, 0x8fa728c9U, + 0x23200365U, 0xcbf2398dU, 0x63701325U, 0x22604264U, + 0xd6a97f90U, 0x3a7e447cU, 0x1cd3cf5aU, 0xd16cbd97U, + 0xcff73889U, 0xd3ec3f95U, 0xaaca60ecU, 0xb79126f1U, + 0x5f431c19U, 0xdfe33c99U, 0xbade64fcU, 0x45dd9803U, + 0x08c2ca4eU, 0x5b461d1dU, 0x42185a04U, 0x064d4b40U, + 0x25a58063U, 0x14d9cd52U, 0xc7fd3a81U, 0x125c4e54U, + 0x6a3a502cU, 0x83a82bc5U, 0x534c1f15U, 0xc43df982U, + 0xd966bf9fU, 0x4892da0eU, 0x78aed63eU, 0x21a08167U, + 0xf004f4b6U, 0xa505a0e3U, 0x71e49537U, 0x10dccc56U, + 0x5a065c1cU, 0x449dd902U, 0xbb9e25fdU, 0x8d27aacbU, + 0xd569bc93U, 0x846de9c2U, 0x907cecd6U, 0x60b0d026U, + 0xbc5be7faU, 0xdea37d98U, 0x0f070849U, 0xdd63be9bU, + 0xd826fe9eU, 0xe150b1a7U, 0x2e6f4168U, 0xc972bb8fU, + 0x35b18473U, 0x8ba229cdU, 0x33340775U, 0x0e474948U, + 0xed5fb2abU, 0x15998c53U, 0x93bc2fd5U, 0x9bb62dddU, + 0x8c67ebcaU, 0x69fa932fU, 0x9d33aedbU, 0xd429fd92U, + 0x2f2f0069U, 0x8068e8c6U, 0xd02cfc96U, 0xe3d033a5U, + 0x51cc9d17U, 0xc2b87a84U, 0x70a4d436U, 0xdaa67c9cU, + 0x5886de1eU, 0xffcb34b9U, 0xd7e93e91U, 0xf541b4b3U, + 0x6f7f1029U, 0x16594f50U, 0x62305224U, 0xe69573a0U, + 0x0cc7cb4aU, 0x34f1c572U, 0x87ad2ac1U, 0x4e175908U, + 0x20e0c066U, 0xac4fe3eaU, 0x61f09127U, 0xe7d532a1U, + 0x57491e11U, 0xa445e1e2U, 0xf28476b4U, 0x92fc6ed4U, + 0xee9f71a8U, 0xea9a70acU, 0x36714770U, 0x1e534d58U, + 0x6dff922bU, 0x37310671U, 0xe555b0a3U, 0x119c8d57U, + 0xb511a4f3U, 0x2cefc36aU, 0xa90aa3efU, 0xa6c563e0U, + 0x1f130c59U, 0x3cfbc77aU, 0x2a6a406cU, 0x5e035d18U, + 0x27250261U, 0x1b160d5dU, 0x32744674U, 0x38fec67eU, + 0x73641735U, 0x5c83df1aU, 0x9fb32cd9U, 0x79ee973fU, + 0xcd77ba8bU, 0x6cbfd32aU, 0xb6d167f0U, 0xad0fa2ebU, + 0xefdf30a9U, 0x8ae268ccU, 0x18d6ce5eU, 0x131c0f55U, + 0xb91ea7ffU, 0xcc37fb8aU, 0x8922abcfU, 0x9936afdfU, + 0x7deb963bU, 0xfe8b75b8U, 0x058d8843U, 0x72245634U, + 0x6b7a112dU, 0x01888947U, 0x86ed6bc0U, 0xa2c062e4U, + 0xceb77988U, 0xbd1ba6fbU, 0x9c73efdaU, 0x7f6b1439U, + 0x4c97db0aU, 0xe29072a4U, 0x4098d806U, 0x49d29b0fU, + 0x3b3e057dU, 0x9876eedeU, 0xaecf61e8U, 0xe81af2aeU, + 0xb39427f5U, 0x28eac26eU, 0x6e3f5128U, 0xdbe63d9dU, + 0xbedb65f8U, 0xe010f0a6U, 0x26654360U, 0xa38023e5U, + 0x04cdc942U, 0x74a1d532U, 0xbf9b24f9U, 0x7a2e543cU, + 0x4089c947U, 0x59d78e5eU, 0xbc4af6bbU, 0xe001e1e7U, + 0x28fbd32fU, 0x9c62fe9bU, 0xefce21e8U, 0xc56ca9c2U, + 0x43490a44U, 0xc169a8c6U, 0x4b43084cU, 0x10cddd17U, + 0xbb8f34bcU, 0xf410e4f3U, 0xab9b30acU, 0x0f161908U, + 0xb78037b0U, 0x86fc7a81U, 0x71f58476U, 0xc2a96bc5U, + 0xb38536b4U, 0xe141a0e6U, 0x0b13180cU, 0x14c8dc13U, + 0xb105b4b6U, 0x0a53590dU, 0x57580f50U, 0x83b93a84U, + 0x3e6a5439U, 0x01999806U, 0x03191a04U, 0x7dfa877aU, + 0x69eb826eU, 0x124d5f15U, 0x5a174d5dU, 0xc823ebcfU, + 0x5dd28f5aU, 0xa454f0a3U, 0x79ff867eU, 0xf29567f5U, + 0xd7f82fd0U, 0x4a03494dU, 0x37201730U, 0x16485e11U, + 0xac5ef2abU, 0x24f4d023U, 0xa91bb2aeU, 0x92ed7f95U, + 0x8873fb8fU, 0xd578add2U, 0x6b6b006cU, 0xbd0ab7baU, + 0x3cead63bU, 0x3b2f143cU, 0xb84ff7bfU, 0x4dc68b4aU, + 0x19879e1eU, 0x64a4c063U, 0x49c38a4eU, 0xf015e5f7U, + 0xcea668c9U, 0x25b49122U, 0xe7c423e0U, 0x8139b886U, + 0x065c5a01U, 0x071c1b00U, 0x853cb982U, 0xe80be3efU, + 0xd438ecd3U, 0xd6b86ed1U, 0x474c0b40U, 0xf155a4f6U, + 0x15889d12U, 0x7e3a4479U, 0xebcb20ecU, 0x7f7a0578U, + 0x8079f987U, 0x0d969b0aU, 0x26745221U, 0xb90fb6beU, + 0xbacf75bdU, 0xb6c076b1U, 0x1d829f1aU, 0xd17dacd6U, + 0xdeb26cd9U, 0x8af3798dU, 0x70b5c577U, 0x35a09532U, + 0xf81fe7ffU, 0xb440f4b3U, 0x27341320U, 0x36605631U, + 0xdab76dddU, 0x42094b45U, 0x6dee836aU, 0xcfe629c8U, + 0x63610264U, 0x8bb3388cU, 0x23311224U, 0x62214365U, + 0x96e87e91U, 0x7a3f457dU, 0x5c92ce5bU, 0x912dbc96U, + 0x8fb63988U, 0x93ad3e94U, 0xea8b61edU, 0xf7d027f0U, + 0x1f021d18U, 0x9fa23d98U, 0xfa9f65fdU, 0x059c9902U, + 0x4883cb4fU, 0x1b071c1cU, 0x02595b05U, 0x460c4a41U, + 0x65e48162U, 0x5498cc53U, 0x87bc3b80U, 0x521d4f55U, + 0x2a7b512dU, 0xc3e92ac4U, 0x130d1e14U, 0x847cf883U, + 0x9927be9eU, 0x08d3db0fU, 0x38efd73fU, 0x61e18066U, + 0xb045f5b7U, 0xe544a1e2U, 0x31a59436U, 0x509dcd57U, + 0x1a475d1dU, 0x04dcd803U, 0xfbdf24fcU, 0xcd66abcaU, + 0x9528bd92U, 0xc42ce8c3U, 0xd03dedd7U, 0x20f1d127U, + 0xfc1ae6fbU, 0x9ee27c99U, 0x4f460948U, 0x9d22bf9aU, + 0x9867ff9fU, 0xa111b0a6U, 0x6e2e4069U, 0x8933ba8eU, + 0x75f08572U, 0xcbe328ccU, 0x73750674U, 0x4e064849U, + 0xad1eb3aaU, 0x55d88d52U, 0xd3fd2ed4U, 0xdbf72cdcU, + 0xcc26eacbU, 0x29bb922eU, 0xdd72afdaU, 0x9468fc93U, + 0x6f6e0168U, 0xc029e9c7U, 0x906dfd97U, 0xa39132a4U, + 0x118d9c16U, 0x82f97b85U, 0x30e5d537U, 0x9ae77d9dU, + 0x18c7df1fU, 0xbf8a35b8U, 0x97a83f90U, 0xb500b5b2U, + 0x2f3e1128U, 0x56184e51U, 0x22715325U, 0xa6d472a1U, + 0x4c86ca4bU, 0x74b0c473U, 0xc7ec2bc0U, 0x0e565809U, + 0x60a1c167U, 0xec0ee2ebU, 0x21b19026U, 0xa79433a0U, + 0x17081f10U, 0xe404e0e3U, 0xb2c577b5U, 0xd2bd6fd5U, + 0xaede70a9U, 0xaadb71adU, 0x76304671U, 0x5e124c59U, + 0x2dbe932aU, 0x77700770U, 0xa514b1a2U, 0x51dd8c56U, + 0xf550a5f2U, 0x6caec26bU, 0xe94ba2eeU, 0xe68462e1U, + 0x5f520d58U, 0x7cbac67bU, 0x6a2b416dU, 0x1e425c19U, + 0x67640360U, 0x5b570c5cU, 0x72354775U, 0x78bfc77fU, + 0x33251634U, 0x1cc2de1bU, 0xdff22dd8U, 0x39af963eU, + 0x8d36bb8aU, 0x2cfed22bU, 0xf69066f1U, 0xed4ea3eaU, + 0xaf9e31a8U, 0xcaa369cdU, 0x5897cf5fU, 0x535d0e54U, + 0xf95fa6feU, 0x8c76fa8bU, 0xc963aaceU, 0xd977aedeU, + 0x3daa973aU, 0xbeca74b9U, 0x45cc8942U, 0x32655735U, + 0x2b3b102cU, 0x41c98846U, 0xc6ac6ac1U, 0xe28163e5U, + 0x8ef67889U, 0xfd5aa7faU, 0xdc32eedbU, 0x3f2a1538U, + 0x0cd6da0bU, 0xa2d173a5U, 0x00d9d907U, 0x09939a0eU, + 0x7b7f047cU, 0xd837efdfU, 0xee8e60e9U, 0xa85bf3afU, + 0xf3d526f4U, 0x68abc36fU, 0x2e7e5029U, 0x9ba73c9cU, + 0xfe9a64f9U, 0xa051f1a7U, 0x66244261U, 0xe3c122e4U, + 0x448cc843U, 0x34e0d433U, 0xffda25f8U, 0x3a6f553dU, + 0x602b4bc5U, 0x79750cdcU, 0x9ce87439U, 0xc0a36365U, + 0x085951adU, 0xbcc07c19U, 0xcf6ca36aU, 0xe5ce2b40U, + 0x63eb88c6U, 0xe1cb2a44U, 0x6be18aceU, 0x306f5f95U, + 0x9b2db63eU, 0xd4b26671U, 0x8b39b22eU, 0x2fb49b8aU, + 0x9722b532U, 0xa65ef803U, 0x515706f4U, 0xe20be947U, + 0x9327b436U, 0xc1e32264U, 0x2bb19a8eU, 0x346a5e91U, + 0x91a73634U, 0x2af1db8fU, 0x77fa8dd2U, 0xa31bb806U, + 0x1ec8d6bbU, 0x213b1a84U, 0x23bb9886U, 0x5d5805f8U, + 0x494900ecU, 0x32efdd97U, 0x7ab5cfdfU, 0xe881694dU, + 0x7d700dd8U, 0x84f67221U, 0x595d04fcU, 0xd237e577U, + 0xf75aad52U, 0x6aa1cbcfU, 0x178295b2U, 0x36eadc93U, + 0x8cfc7029U, 0x045652a1U, 0x89b9302cU, 0xb24ffd17U, + 0xa8d1790dU, 0xf5da2f50U, 0x4bc982eeU, 0x9da83538U, + 0x1c4854b9U, 0x1b8d96beU, 0x98ed753dU, 0x6d6409c8U, + 0x39251c9cU, 0x440642e1U, 0x696108ccU, 0xd0b76775U, + 0xee04ea4bU, 0x051613a0U, 0xc766a162U, 0xa19b3a04U, + 0x26fed883U, 0x27be9982U, 0xa59e3b00U, 0xc8a9616dU, + 0xf49a6e51U, 0xf61aec53U, 0x67ee89c2U, 0xd1f72674U, + 0x352a1f90U, 0x5e98c6fbU, 0xcb69a26eU, 0x5fd887faU, + 0xa0db7b05U, 0x2d341988U, 0x06d6d0a3U, 0x99ad343cU, + 0x9a6df73fU, 0x9662f433U, 0x3d201d98U, 0xf1df2e54U, + 0xfe10ee5bU, 0xaa51fb0fU, 0x501747f5U, 0x150217b0U, + 0xd8bd657dU, 0x94e27631U, 0x079691a2U, 0x16c2d4b3U, + 0xfa15ef5fU, 0x62abc9c7U, 0x4d4c01e8U, 0xef44ab4aU, + 0x43c380e6U, 0xab11ba0eU, 0x039390a6U, 0x4283c1e7U, + 0xb64afc13U, 0x5a9dc7ffU, 0x7c304cd9U, 0xb18f3e14U, + 0xaf14bb0aU, 0xb30fbc16U, 0xca29e36fU, 0xd772a572U, + 0x3fa09f9aU, 0xbf00bf1aU, 0xda3de77fU, 0x253e1b80U, + 0x682149cdU, 0x3ba59e9eU, 0x22fbd987U, 0x66aec8c3U, + 0x454603e0U, 0x743a4ed1U, 0xa71eb902U, 0x72bfcdd7U, + 0x0ad9d3afU, 0xe34ba846U, 0x33af9c96U, 0xa4de7a01U, + 0xb9853c1cU, 0x2871598dU, 0x184d55bdU, 0x414302e4U, + 0x90e77735U, 0xc5e62360U, 0x110716b4U, 0x703f4fd5U, + 0x3ae5df9fU, 0x247e5a81U, 0xdb7da67eU, 0xedc42948U, + 0xb58a3f10U, 0xe48e6a41U, 0xf09f6f55U, 0x005353a5U, + 0xdcb86479U, 0xbe40fe1bU, 0x6fe48bcaU, 0xbd803d18U, + 0xb8c57d1dU, 0x81b33224U, 0x4e8cc2ebU, 0xa991380cU, + 0x555207f0U, 0xeb41aa4eU, 0x53d784f6U, 0x6ea4cacbU, + 0x8dbc3128U, 0x757a0fd0U, 0xf35fac56U, 0xfb55ae5eU, + 0xec846849U, 0x091910acU, 0xfdd02d58U, 0xb4ca7e11U, + 0x4fcc83eaU, 0xe08b6b45U, 0xb0cf7f15U, 0x8333b026U, + 0x312f1e94U, 0xa25bf907U, 0x104757b5U, 0xba45ff1fU, + 0x38655d9dU, 0x9f28b73aU, 0xb70abd12U, 0x95a23730U, + 0x0f9c93aaU, 0x76baccd3U, 0x02d3d1a7U, 0x8676f023U, + 0x6c2448c9U, 0x541246f1U, 0xe74ea942U, 0x2ef4da8bU, + 0x400343e5U, 0xccac6069U, 0x011312a4U, 0x8736b122U, + 0x37aa9d92U, 0xc4a66261U, 0x9267f537U, 0xf21fed57U, + 0x8e7cf22bU, 0x8a79f32fU, 0x5692c4f3U, 0x7eb0cedbU, + 0x0d1c11a8U, 0x57d285f2U, 0x85b63320U, 0x717f0ed4U, + 0xd5f22770U, 0x4c0c40e9U, 0xc9e9206cU, 0xc626e063U, + 0x7ff08fdaU, 0x5c1844f9U, 0x4a89c3efU, 0x3ee0de9bU, + 0x47c681e2U, 0x7bf58edeU, 0x5297c5f7U, 0x581d45fdU, + 0x138794b6U, 0x3c605c99U, 0xff50af5aU, 0x190d14bcU, + 0xad943908U, 0x0c5c50a9U, 0xd632e473U, 0xcdec2168U, + 0x8f3cb32aU, 0xea01eb4fU, 0x78354dddU, 0x73ff8cd6U, + 0xd9fd247cU, 0xacd47809U, 0xe9c1284cU, 0xf9d52c5cU, + 0x1d0815b8U, 0x9e68f63bU, 0x656e0bc0U, 0x12c7d5b7U, + 0x0b9992aeU, 0x616b0ac4U, 0xe60ee843U, 0xc223e167U, + 0xae54fa0bU, 0xddf82578U, 0xfc906c59U, 0x1f8897baU, + 0x2c745889U, 0x8273f127U, 0x207b5b85U, 0x2931188cU, + 0x5bdd86feU, 0xf8956d5dU, 0xce2ce26bU, 0x88f9712dU, + 0xd377a476U, 0x480941edU, 0x0edcd2abU, 0xbb05be1eU, + 0xde38e67bU, 0x80f37325U, 0x4686c0e3U, 0xc363a066U, + 0x642e4ac1U, 0x144256b1U, 0xdf78a77aU, 0x1acdd7bfU, + 0x577126a8U, 0x4e2f61b1U, 0xabb21954U, 0xf7f90e08U, + 0x3f033cc0U, 0x8b9a1174U, 0xf836ce07U, 0xd294462dU, + 0x54b1e5abU, 0xd6914729U, 0x5cbbe7a3U, 0x073532f8U, + 0xac77db53U, 0xe3e80b1cU, 0xbc63df43U, 0x18eef6e7U, + 0xa078d85fU, 0x9104956eU, 0x660d6b99U, 0xd551842aU, + 0xa47dd95bU, 0xf6b94f09U, 0x1cebf7e3U, 0x033033fcU, + 0xa6fd5b59U, 0x1dabb6e2U, 0x40a0e0bfU, 0x9441d56bU, + 0x2992bbd6U, 0x166177e9U, 0x14e1f5ebU, 0x6a026895U, + 0x7e136d81U, 0x05b5b0faU, 0x4defa2b2U, 0xdfdb0420U, + 0x4a2a60b5U, 0xb3ac1f4cU, 0x6e076991U, 0xe56d881aU, + 0xc000c03fU, 0x5dfba6a2U, 0x20d8f8dfU, 0x01b0b1feU, + 0xbba61d44U, 0x330c3fccU, 0xbee35d41U, 0x8515907aU, + 0x9f8b1460U, 0xc280423dU, 0x7c93ef83U, 0xaaf25855U, + 0x2b1239d4U, 0x2cd7fbd3U, 0xafb71850U, 0x5a3e64a5U, + 0x0e7f71f1U, 0x735c2f8cU, 0x5e3b65a1U, 0xe7ed0a18U, + 0xd95e8726U, 0x324c7ecdU, 0xf03ccc0fU, 0x96c15769U, + 0x11a4b5eeU, 0x10e4f4efU, 0x92c4566dU, 0xfff30c00U, + 0xc3c0033cU, 0xc140813eU, 0x50b4e4afU, 0xe6ad4b19U, + 0x027072fdU, 0x69c2ab96U, 0xfc33cf03U, 0x6882ea97U, + 0x97811668U, 0x1a6e74e5U, 0x318cbdceU, 0xaef75951U, + 0xad379a52U, 0xa138995eU, 0x0a7a70f5U, 0xc6854339U, + 0xc94a8336U, 0x9d0b9662U, 0x674d2a98U, 0x22587addU, + 0xefe70810U, 0xa3b81b5cU, 0x30ccfccfU, 0x2198b9deU, + 0xcd4f8232U, 0x55f1a4aaU, 0x7a166c85U, 0xd81ec627U, + 0x7499ed8bU, 0x9c4bd763U, 0x34c9fdcbU, 0x75d9ac8aU, + 0x8110917eU, 0x6dc7aa92U, 0x4b6a21b4U, 0x86d55379U, + 0x984ed667U, 0x8455d17bU, 0xfd738e02U, 0xe028c81fU, + 0x08faf2f7U, 0x885ad277U, 0xed678a12U, 0x126476edU, + 0x5f7b24a0U, 0x0cfff3f3U, 0x15a1b4eaU, 0x51f4a5aeU, + 0x721c6e8dU, 0x436023bcU, 0x9044d46fU, 0x45e5a0baU, + 0x3d83bec2U, 0xd411c52bU, 0x04f5f1fbU, 0x9384176cU, + 0x8edf5171U, 0x1f2b34e0U, 0x2f1738d0U, 0x76196f89U, + 0xa7bd1a58U, 0xf2bc4e0dU, 0x265d7bd9U, 0x476522b8U, + 0x0dbfb2f2U, 0x132437ecU, 0xec27cb13U, 0xda9e4425U, + 0x82d0527dU, 0xd3d4072cU, 0xc7c50238U, 0x37093ec8U, + 0xebe20914U, 0x891a9376U, 0x58bee6a7U, 0x8ada5075U, + 0x8f9f1070U, 0xb6e95f49U, 0x79d6af86U, 0x9ecb5561U, + 0x62086a9dU, 0xdc1bc723U, 0x648de99bU, 0x59fea7a6U, + 0xbae65c45U, 0x422062bdU, 0xc405c13bU, 0xcc0fc333U, + 0xdbde0524U, 0x3e437dc1U, 0xca8a4035U, 0x8390137cU, + 0x7896ee87U, 0xd7d10628U, 0x87951278U, 0xb469dd4bU, + 0x067573f9U, 0x9501946aU, 0x271d3ad8U, 0x8d1f9272U, + 0x0f3f30f0U, 0xa872da57U, 0x8050d07fU, 0xa2f85a5dU, + 0x38c6fec7U, 0x41e0a1beU, 0x3589bccaU, 0xb12c9d4eU, + 0x5b7e25a4U, 0x63482b9cU, 0xd014c42fU, 0x19aeb7e6U, + 0x77592e88U, 0xfbf60d04U, 0x36497fc9U, 0xb06cdc4fU, + 0x00f0f0ffU, 0xf3fc0f0cU, 0xa53d985aU, 0xc545803aU, + 0xb9269f46U, 0xbd239e42U, 0x61c8a99eU, 0x49eaa3b6U, + 0x3a467cc5U, 0x6088e89fU, 0xb2ec5e4dU, 0x462563b9U, + 0xe2a84a1dU, 0x7b562d84U, 0xfeb34d01U, 0xf17c8d0eU, + 0x48aae2b7U, 0x6b422994U, 0x7dd3ae82U, 0x09bab3f6U, + 0x709cec8fU, 0x4cafe3b3U, 0x65cda89aU, 0x6f472890U, + 0x24ddf9dbU, 0x0b3a31f4U, 0xc80ac237U, 0x2e5779d1U, + 0x9ace5465U, 0x3b063dc4U, 0xe168891eU, 0xfab64c05U, + 0xb866de47U, 0xdd5b8622U, 0x4f6f20b0U, 0x44a5e1bbU, + 0xeea74911U, 0x9b8e1564U, 0xde9b4521U, 0xce8f4131U, + 0x2a5278d5U, 0xa9329b56U, 0x523466adU, 0x259db8daU, + 0x3cc3ffc3U, 0x563167a9U, 0xd154852eU, 0xf5798c0aU, + 0x990e9766U, 0xeaa24815U, 0xcbca0134U, 0x28d2fad7U, + 0x1b2e35e4U, 0xb5299c4aU, 0x172136e8U, 0x1e6b75e1U, + 0x6c87eb93U, 0xcfcf0030U, 0xf9768f06U, 0xbfa31c40U, + 0xe42dc91bU, 0x7f532c80U, 0x3986bfc6U, 0x8c5fd373U, + 0xe9628b16U, 0xb7a91e48U, 0x71dcad8eU, 0xf439cd0bU, + 0x537427acU, 0x23183bdcU, 0xe822ca17U, 0x2d97bad2U, + 0x647e1a94U, 0x7d205d8dU, 0x98bd2568U, 0xc4f63234U, + 0x0c0c00fcU, 0xb8952d48U, 0xcb39f23bU, 0xe19b7a11U, + 0x67bed997U, 0xe59e7b15U, 0x6fb4db9fU, 0x343a0ec4U, + 0x9f78e76fU, 0xd0e73720U, 0x8f6ce37fU, 0x2be1cadbU, + 0x9377e463U, 0xa20ba952U, 0x550257a5U, 0xe65eb816U, + 0x9772e567U, 0xc5b67335U, 0x2fe4cbdfU, 0x303f0fc0U, + 0x95f26765U, 0x2ea48adeU, 0x73afdc83U, 0xa74ee957U, + 0x1a9d87eaU, 0x256e4bd5U, 0x27eec9d7U, 0x590d54a9U, + 0x4d1c51bdU, 0x36ba8cc6U, 0x7ee09e8eU, 0xecd4381cU, + 0x79255c89U, 0x80a32370U, 0x5d0855adU, 0xd662b426U, + 0xf30ffc03U, 0x6ef49a9eU, 0x13d7c4e3U, 0x32bf8dc2U, + 0x88a92178U, 0x000303f0U, 0x8dec617dU, 0xb61aac46U, + 0xac84285cU, 0xf18f7e01U, 0x4f9cd3bfU, 0x99fd6469U, + 0x181d05e8U, 0x1fd8c7efU, 0x9cb8246cU, 0x69315899U, + 0x3d704dcdU, 0x405313b0U, 0x6d34599dU, 0xd4e23624U, + 0xea51bb1aU, 0x014342f1U, 0xc333f033U, 0xa5ce6b55U, + 0x22ab89d2U, 0x23ebc8d3U, 0xa1cb6a51U, 0xccfc303cU, + 0xf0cf3f00U, 0xf24fbd02U, 0x63bbd893U, 0xd5a27725U, + 0x317f4ec1U, 0x5acd97aaU, 0xcf3cf33fU, 0x5b8dd6abU, + 0xa48e2a54U, 0x296148d9U, 0x028381f2U, 0x9df8656dU, + 0x9e38a66eU, 0x9237a562U, 0x39754cc9U, 0xf58a7f05U, + 0xfa45bf0aU, 0xae04aa5eU, 0x544216a4U, 0x115746e1U, + 0xdce8342cU, 0x90b72760U, 0x03c3c0f3U, 0x129785e2U, + 0xfe40be0eU, 0x66fe9896U, 0x491950b9U, 0xeb11fa1bU, + 0x4796d1b7U, 0xaf44eb5fU, 0x07c6c1f7U, 0x46d690b6U, + 0xb21fad42U, 0x5ec896aeU, 0x78651d88U, 0xb5da6f45U, + 0xab41ea5bU, 0xb75aed47U, 0xce7cb23eU, 0xd327f423U, + 0x3bf5cecbU, 0xbb55ee4bU, 0xde68b62eU, 0x216b4ad1U, + 0x6c74189cU, 0x3ff0cfcfU, 0x26ae88d6U, 0x62fb9992U, + 0x411352b1U, 0x706f1f80U, 0xa34be853U, 0x76ea9c86U, + 0x0e8c82feU, 0xe71ef917U, 0x37facdc7U, 0xa08b2b50U, + 0xbdd06d4dU, 0x2c2408dcU, 0x1c1804ecU, 0x451653b5U, + 0x94b22664U, 0xc1b37231U, 0x155247e5U, 0x746a1e84U, + 0x3eb08eceU, 0x202b0bd0U, 0xdf28f72fU, 0xe9917819U, + 0xb1df6e41U, 0xe0db3b10U, 0xf4ca3e04U, 0x040602f4U, + 0xd8ed3528U, 0xba15af4aU, 0x6bb1da9bU, 0xb9d56c49U, + 0xbc902c4cU, 0x85e66375U, 0x4ad993baU, 0xadc4695dU, + 0x510756a1U, 0xef14fb1fU, 0x5782d5a7U, 0x6af19b9aU, + 0x89e96079U, 0x712f5e81U, 0xf70afd07U, 0xff00ff0fU, + 0xe8d13918U, 0x0d4c41fdU, 0xf9857c09U, 0xb09f2f40U, + 0x4b99d2bbU, 0xe4de3a14U, 0xb49a2e44U, 0x8766e177U, + 0x357a4fc5U, 0xa60ea856U, 0x141206e4U, 0xbe10ae4eU, + 0x3c300cccU, 0x9b7de66bU, 0xb35fec43U, 0x91f76661U, + 0x0bc9c2fbU, 0x72ef9d82U, 0x068680f6U, 0x8223a172U, + 0x68711998U, 0x504717a0U, 0xe31bf813U, 0x2aa18bdaU, + 0x445612b4U, 0xc8f93138U, 0x054643f5U, 0x8363e073U, + 0x33ffccc3U, 0xc0f33330U, 0x9632a466U, 0xf64abc06U, + 0x8a29a37aU, 0x8e2ca27eU, 0x52c795a2U, 0x7ae59f8aU, + 0x094940f9U, 0x5387d4a3U, 0x81e36271U, 0x752a5f85U, + 0xd1a77621U, 0x485911b8U, 0xcdbc713dU, 0xc273b132U, + 0x7ba5de8bU, 0x584d15a8U, 0x4edc92beU, 0x3ab58fcaU, + 0x4393d0b3U, 0x7fa0df8fU, 0x56c294a6U, 0x5c4814acU, + 0x17d2c5e7U, 0x38350dc8U, 0xfb05fe0bU, 0x1d5845edU, + 0xa9c16859U, 0x080901f8U, 0xd267b522U, 0xc9b97039U, + 0x8b69e27bU, 0xee54ba1eU, 0x7c601c8cU, 0x77aadd87U, + 0xdda8752dU, 0xa8812958U, 0xed94791dU, 0xfd807d0dU, + 0x195d44e9U, 0x9a3da76aU, 0x613b5a91U, 0x169284e6U, + 0x0fccc3ffU, 0x653e5b95U, 0xe25bb912U, 0xc676b036U, + 0xaa01ab5aU, 0xd9ad7429U, 0xf8c53d08U, 0x1bddc6ebU, + 0x282109d8U, 0x8626a076U, 0x242e0ad4U, 0x2d6449ddU, + 0x5f88d7afU, 0xfcc03c0cU, 0xca79b33aU, 0x8cac207cU, + 0xd722f527U, 0x4c5c10bcU, 0x0a8983faU, 0xbf50ef4fU, + 0xda6db72aU, 0x84a62274U, 0x42d391b2U, 0xc736f137U, + 0x607b1b90U, 0x101707e0U, 0xdb2df62bU, 0x1e9886eeU, + 0xe4fc1896U, 0xfda25f8fU, 0x183f276aU, 0x44743036U, + 0x8c8e02feU, 0x38172f4aU, 0x4bbbf039U, 0x61197813U, + 0xe73cdb95U, 0x651c7917U, 0xef36d99dU, 0xb4b80cc6U, + 0x1ffae56dU, 0x50653522U, 0x0feee17dU, 0xab63c8d9U, + 0x13f5e661U, 0x2289ab50U, 0xd58055a7U, 0x66dcba14U, + 0x17f0e765U, 0x45347137U, 0xaf66c9ddU, 0xb0bd0dc2U, + 0x15706567U, 0xae2688dcU, 0xf32dde81U, 0x27cceb55U, + 0x9a1f85e8U, 0xa5ec49d7U, 0xa76ccbd5U, 0xd98f56abU, + 0xcd9e53bfU, 0xb6388ec4U, 0xfe629c8cU, 0x6c563a1eU, + 0xf9a75e8bU, 0x00212172U, 0xdd8a57afU, 0x56e0b624U, + 0x738dfe01U, 0xee76989cU, 0x9355c6e1U, 0xb23d8fc0U, + 0x082b237aU, 0x808101f2U, 0x0d6e637fU, 0x3698ae44U, + 0x2c062a5eU, 0x710d7c03U, 0xcf1ed1bdU, 0x197f666bU, + 0x989f07eaU, 0x9f5ac5edU, 0x1c3a266eU, 0xe9b35a9bU, + 0xbdf24fcfU, 0xc0d111b2U, 0xedb65b9fU, 0x54603426U, + 0x6ad3b918U, 0x81c140f3U, 0x43b1f231U, 0x254c6957U, + 0xa2298bd0U, 0xa369cad1U, 0x21496853U, 0x4c7e323eU, + 0x704d3d02U, 0x72cdbf00U, 0xe339da91U, 0x55207527U, + 0xb1fd4cc3U, 0xda4f95a8U, 0x4fbef13dU, 0xdb0fd4a9U, + 0x240c2856U, 0xa9e34adbU, 0x820183f0U, 0x1d7a676fU, + 0x1ebaa46cU, 0x12b5a760U, 0xb9f74ecbU, 0x75087d07U, + 0x7ac7bd08U, 0x2e86a85cU, 0xd4c014a6U, 0x91d544e3U, + 0x5c6a362eU, 0x10352562U, 0x8341c2f1U, 0x921587e0U, + 0x7ec2bc0cU, 0xe67c9a94U, 0xc99b52bbU, 0x6b93f819U, + 0xc714d3b5U, 0x2fc6e95dU, 0x8744c3f5U, 0xc65492b4U, + 0x329daf40U, 0xde4a94acU, 0xf8e71f8aU, 0x35586d47U, + 0x2bc3e859U, 0x37d8ef45U, 0x4efeb03cU, 0x53a5f621U, + 0xbb77ccc9U, 0x3bd7ec49U, 0x5eeab42cU, 0xa1e948d3U, + 0xecf61a9eU, 0xbf72cdcdU, 0xa62c8ad4U, 0xe2799b90U, + 0xc19150b3U, 0xf0ed1d82U, 0x23c9ea51U, 0xf6689e84U, + 0x8e0e80fcU, 0x679cfb15U, 0xb778cfc5U, 0x20092952U, + 0x3d526f4fU, 0xaca60adeU, 0x9c9a06eeU, 0xc59451b7U, + 0x14302466U, 0x41317033U, 0x95d045e7U, 0xf4e81c86U, + 0xbe328cccU, 0xa0a909d2U, 0x5faaf52dU, 0x69137a1bU, + 0x315d6c43U, 0x60593912U, 0x74483c06U, 0x848400f6U, + 0x586f372aU, 0x3a97ad48U, 0xeb33d899U, 0x39576e4bU, + 0x3c122e4eU, 0x05646177U, 0xca5b91b8U, 0x2d466b5fU, + 0xd18554a3U, 0x6f96f91dU, 0xd700d7a5U, 0xea739998U, + 0x096b627bU, 0xf1ad5c83U, 0x7788ff05U, 0x7f82fd0dU, + 0x68533b1aU, 0x8dce43ffU, 0x79077e0bU, 0x301d2d42U, + 0xcb1bd0b9U, 0x645c3816U, 0x34182c46U, 0x07e4e375U, + 0xb5f84dc7U, 0x268caa54U, 0x949004e6U, 0x3e92ac4cU, + 0xbcb20eceU, 0x1bffe469U, 0x33ddee41U, 0x11756463U, + 0x8b4bc0f9U, 0xf26d9f80U, 0x860482f4U, 0x02a1a370U, + 0xe8f31b9aU, 0xd0c515a2U, 0x6399fa11U, 0xaa2389d8U, + 0xc4d410b6U, 0x487b333aU, 0x85c441f7U, 0x03e1e271U, + 0xb37dcec1U, 0x40713132U, 0x16b0a664U, 0x76c8be04U, + 0x0aaba178U, 0x0eaea07cU, 0xd24597a0U, 0xfa679d88U, + 0x89cb42fbU, 0xd305d6a1U, 0x01616073U, 0xf5a85d87U, + 0x51257423U, 0xc8db13baU, 0x4d3e733fU, 0x42f1b330U, + 0xfb27dc89U, 0xd8cf17aaU, 0xce5e90bcU, 0xba378dc8U, + 0xc311d2b1U, 0xff22dd8dU, 0xd64096a4U, 0xdcca16aeU, + 0x9750c7e5U, 0xb8b70fcaU, 0x7b87fc09U, 0x9dda47efU, + 0x29436a5bU, 0x888b03faU, 0x52e5b720U, 0x493b723bU, + 0x0bebe079U, 0x6ed6b81cU, 0xfce21e8eU, 0xf728df85U, + 0x5d2a772fU, 0x28032b5aU, 0x6d167b1fU, 0x7d027f0fU, + 0x99df46ebU, 0x1abfa568U, 0xe1b95893U, 0x961086e4U, + 0x8f4ec1fdU, 0xe5bc5997U, 0x62d9bb10U, 0x46f4b234U, + 0x2a83a958U, 0x592f762bU, 0x78473f0aU, 0x9b5fc4e9U, + 0xa8a30bdaU, 0x06a4a274U, 0xa4ac08d6U, 0xade64bdfU, + 0xdf0ad5adU, 0x7c423e0eU, 0x4afbb138U, 0x0c2e227eU, + 0x57a0f725U, 0xccde12beU, 0x8a0b81f8U, 0x3fd2ed4dU, + 0x5aefb528U, 0x04242076U, 0xc25193b0U, 0x47b4f335U, + 0xe0f91992U, 0x909505e2U, 0x5baff429U, 0x9e1a84ecU, + 0x10998907U, 0x09c7ce1eU, 0xec5ab6fbU, 0xb011a1a7U, + 0x78eb936fU, 0xcc72bedbU, 0xbfde61a8U, 0x957ce982U, + 0x13594a04U, 0x9179e886U, 0x1b53480cU, 0x40dd9d57U, + 0xeb9f74fcU, 0xa400a4b3U, 0xfb8b70ecU, 0x5f065948U, + 0xe79077f0U, 0xd6ec3ac1U, 0x21e5c436U, 0x92b92b85U, + 0xe39576f4U, 0xb151e0a6U, 0x5b03584cU, 0x44d89c53U, + 0xe115f4f6U, 0x5a43194dU, 0x07484f10U, 0xd3a97ac4U, + 0x6e7a1479U, 0x5189d846U, 0x53095a44U, 0x2deac73aU, + 0x39fbc22eU, 0x425d1f55U, 0x0a070d1dU, 0x9833ab8fU, + 0x0dc2cf1aU, 0xf444b0e3U, 0x29efc63eU, 0xa28527b5U, + 0x87e86f90U, 0x1a13090dU, 0x67305770U, 0x46581e51U, + 0xfc4eb2ebU, 0x74e49063U, 0xf90bf2eeU, 0xc2fd3fd5U, + 0xd863bbcfU, 0x8568ed92U, 0x3b7b402cU, 0xed1af7faU, + 0x6cfa967bU, 0x6b3f547cU, 0xe85fb7ffU, 0x1dd6cb0aU, + 0x4997de5eU, 0x34b48023U, 0x19d3ca0eU, 0xa005a5b7U, + 0x9eb62889U, 0x75a4d162U, 0xb7d463a0U, 0xd129f8c6U, + 0x564c1a41U, 0x570c5b40U, 0xd52cf9c2U, 0xb81ba3afU, + 0x8428ac93U, 0x86a82e91U, 0x175c4b00U, 0xa145e4b6U, + 0x4598dd52U, 0x2e2a0439U, 0xbbdb60acU, 0x2f6a4538U, + 0xd069b9c7U, 0x5d86db4aU, 0x76641261U, 0xe91ff6feU, + 0xeadf35fdU, 0xe6d036f1U, 0x4d92df5aU, 0x816dec96U, + 0x8ea22c99U, 0xdae339cdU, 0x20a58537U, 0x65b0d572U, + 0xa80fa7bfU, 0xe450b4f3U, 0x77245360U, 0x66701671U, + 0x8aa72d9dU, 0x12190b05U, 0x3dfec32aU, 0x9ff66988U, + 0x33714224U, 0xdba378ccU, 0x73215264U, 0x32310325U, + 0xc6f83ed1U, 0x2a2f053dU, 0x0c828e1bU, 0xc13dfcd6U, + 0xdfa679c8U, 0xc3bd7ed4U, 0xba9b21adU, 0xa7c067b0U, + 0x4f125d58U, 0xcfb27dd8U, 0xaa8f25bdU, 0x558cd942U, + 0x18938b0fU, 0x4b175c5cU, 0x52491b45U, 0x161c0a01U, + 0x35f4c122U, 0x04888c13U, 0xd7ac7bc0U, 0x020d0f15U, + 0x7a6b116dU, 0x93f96a84U, 0x431d5e54U, 0xd46cb8c3U, + 0xc937fedeU, 0x58c39b4fU, 0x68ff977fU, 0x31f1c026U, + 0xe055b5f7U, 0xb554e1a2U, 0x61b5d476U, 0x008d8d17U, + 0x4a571d5dU, 0x54cc9843U, 0xabcf64bcU, 0x9d76eb8aU, + 0xc538fdd2U, 0x943ca883U, 0x802dad97U, 0x70e19167U, + 0xac0aa6bbU, 0xcef23cd9U, 0x1f564908U, 0xcd32ffdaU, + 0xc877bfdfU, 0xf101f0e6U, 0x3e3e0029U, 0xd923faceU, + 0x25e0c532U, 0x9bf3688cU, 0x23654634U, 0x1e160809U, + 0xfd0ef3eaU, 0x05c8cd12U, 0x83ed6e94U, 0x8be76c9cU, + 0x9c36aa8bU, 0x79abd26eU, 0x8d62ef9aU, 0xc478bcd3U, + 0x3f7e4128U, 0x9039a987U, 0xc07dbdd7U, 0xf38172e4U, + 0x419ddc56U, 0xd2e93bc5U, 0x60f59577U, 0xcaf73dddU, + 0x48d79f5fU, 0xef9a75f8U, 0xc7b87fd0U, 0xe510f5f2U, + 0x7f2e5168U, 0x06080e11U, 0x72611365U, 0xf6c432e1U, + 0x1c968a0bU, 0x24a08433U, 0x97fc6b80U, 0x5e461849U, + 0x30b18127U, 0xbc1ea2abU, 0x71a1d066U, 0xf78473e0U, + 0x47185f50U, 0xb414a0a3U, 0xe2d537f5U, 0x82ad2f95U, + 0xfece30e9U, 0xfacb31edU, 0x26200631U, 0x0e020c19U, + 0x7daed36aU, 0x27604730U, 0xf504f1e2U, 0x01cdcc16U, + 0xa540e5b2U, 0x3cbe822bU, 0xb95be2aeU, 0xb69422a1U, + 0x0f424d18U, 0x2caa863bU, 0x3a3b012dU, 0x4e521c59U, + 0x37744320U, 0x0b474c1cU, 0x22250735U, 0x28af873fU, + 0x63355674U, 0x4cd29e5bU, 0x8fe26d98U, 0x69bfd67eU, + 0xdd26fbcaU, 0x7cee926bU, 0xa68026b1U, 0xbd5ee3aaU, + 0xff8e71e8U, 0x9ab3298dU, 0x08878f1fU, 0x034d4e14U, + 0xa94fe6beU, 0xdc66bacbU, 0x9973ea8eU, 0x8967ee9eU, + 0x6dbad77aU, 0xeeda34f9U, 0x15dcc902U, 0x62751775U, + 0x7b2b506cU, 0x11d9c806U, 0x96bc2a81U, 0xb29123a5U, + 0xdee638c9U, 0xad4ae7baU, 0x8c22ae9bU, 0x6f3a5578U, + 0x5cc69a4bU, 0xf2c133e5U, 0x50c99947U, 0x5983da4eU, + 0x2b6f443cU, 0x8827af9fU, 0xbe9e20a9U, 0xf84bb3efU, + 0xa3c566b4U, 0x38bb832fU, 0x7e6e1069U, 0xcbb77cdcU, + 0xae8a24b9U, 0xf041b1e7U, 0x36340221U, 0xb3d162a4U, + 0x149c8803U, 0x64f09473U, 0xafca65b8U, 0x6a7f157dU, + 0x09363fb1U, 0x106878a8U, 0xf5f5004dU, 0xa9be1711U, + 0x614425d9U, 0xd5dd086dU, 0xa671d71eU, 0x8cd35f34U, + 0x0af6fcb2U, 0x88d65e30U, 0x02fcfebaU, 0x59722be1U, + 0xf230c24aU, 0xbdaf1205U, 0xe224c65aU, 0x46a9effeU, + 0xfe3fc146U, 0xcf438c77U, 0x384a7280U, 0x8b169d33U, + 0xfa3ac042U, 0xa8fe5610U, 0x42aceefaU, 0x5d772ae5U, + 0xf8ba4240U, 0x43ecaffbU, 0x1ee7f9a6U, 0xca06cc72U, + 0x77d5a2cfU, 0x48266ef0U, 0x4aa6ecf2U, 0x3445718cU, + 0x20547498U, 0x5bf2a9e3U, 0x13a8bbabU, 0x819c1d39U, + 0x146d79acU, 0xedeb0655U, 0x30407088U, 0xbb2a9103U, + 0x9e47d926U, 0x03bcbfbbU, 0x7e9fe1c6U, 0x5ff7a8e7U, + 0xe5e1045dU, 0x6d4b26d5U, 0xe0a44458U, 0xdb528963U, + 0xc1cc0d79U, 0x9cc75b24U, 0x22d4f69aU, 0xf4b5414cU, + 0x755520cdU, 0x7290e2caU, 0xf1f00149U, 0x04797dbcU, + 0x503868e8U, 0x2d1b3695U, 0x007c7cb8U, 0xb9aa1301U, + 0x87199e3fU, 0x6c0b67d4U, 0xae7bd516U, 0xc8864e70U, + 0x4fe3acf7U, 0x4ea3edf6U, 0xcc834f74U, 0xa1b41519U, + 0x9d871a25U, 0x9f079827U, 0x0ef3fdb6U, 0xb8ea5200U, + 0x5c376be4U, 0x3785b28fU, 0xa274d61aU, 0x36c5f38eU, + 0xc9c60f71U, 0x44296dfcU, 0x6fcba4d7U, 0xf0b04048U, + 0xf370834bU, 0xff7f8047U, 0x543d69ecU, 0x98c25a20U, + 0x970d9a2fU, 0xc34c8f7bU, 0x390a3381U, 0x7c1f63c4U, + 0xb1a01109U, 0xfdff0245U, 0x6e8be5d6U, 0x7fdfa0c7U, + 0x93089b2bU, 0x0bb6bdb3U, 0x2451759cU, 0x8659df3eU, + 0x2adef492U, 0xc20cce7aU, 0x6a8ee4d2U, 0x2b9eb593U, + 0xdf578867U, 0x3380b38bU, 0x152d38adU, 0xd8924a60U, + 0xc609cf7eU, 0xda12c862U, 0xa334971bU, 0xbe6fd106U, + 0x56bdebeeU, 0xd61dcb6eU, 0xb320930bU, 0x4c236ff4U, + 0x013c3db9U, 0x52b8eaeaU, 0x4be6adf3U, 0x0fb3bcb7U, + 0x2c5b7794U, 0x1d273aa5U, 0xce03cd76U, 0x1ba2b9a3U, + 0x63c4a7dbU, 0x8a56dc32U, 0x5ab2e8e2U, 0xcdc30e75U, + 0xd0984868U, 0x416c2df9U, 0x715021c9U, 0x285e7690U, + 0xf9fa0341U, 0xacfb5714U, 0x781a62c0U, 0x19223ba1U, + 0x53f8abebU, 0x4d632ef5U, 0xb260d20aU, 0x84d95d3cU, + 0xdc974b64U, 0x8d931e35U, 0x99821b21U, 0x694e27d1U, + 0xb5a5100dU, 0xd75d8a6fU, 0x06f9ffbeU, 0xd49d496cU, + 0xd1d80969U, 0xe8ae4650U, 0x2791b69fU, 0xc08c4c78U, + 0x3c4f7384U, 0x825cde3aU, 0x3acaf082U, 0x07b9bebfU, + 0xe4a1455cU, 0x1c677ba4U, 0x9a42d822U, 0x9248da2aU, + 0x85991c3dU, 0x600464d8U, 0x94cd592cU, 0xddd70a65U, + 0x26d1f79eU, 0x89961f31U, 0xd9d20b61U, 0xea2ec452U, + 0x58326ae0U, 0xcb468d73U, 0x795a23c1U, 0xd3588b6bU, + 0x517829e9U, 0xf635c34eU, 0xde17c966U, 0xfcbf4344U, + 0x6681e7deU, 0x1fa7b8a7U, 0x6bcea5d3U, 0xef6b8457U, + 0x05393cbdU, 0x3d0f3285U, 0x8e53dd36U, 0x47e9aeffU, + 0x291e3791U, 0xa5b1141dU, 0x680e66d0U, 0xee2bc556U, + 0x5eb7e9e6U, 0xadbb1615U, 0xfb7a8143U, 0x9b029923U, + 0xe761865fU, 0xe364875bU, 0x3f8fb087U, 0x17adbaafU, + 0x640165dcU, 0x3ecff186U, 0xecab4754U, 0x18627aa0U, + 0xbcef5304U, 0x2511349dU, 0xa0f45418U, 0xaf3b9417U, + 0x16edfbaeU, 0x3505308dU, 0x2394b79bU, 0x57fdaaefU, + 0x2edbf596U, 0x12e8faaaU, 0x3b8ab183U, 0x31003189U, + 0x7a9ae0c2U, 0x557d28edU, 0x964ddb2eU, 0x701060c8U, + 0xc4894d7cU, 0x654124ddU, 0xbf2f9007U, 0xa4f1551cU, + 0xe621c75eU, 0x831c9f3bU, 0x112839a9U, 0x1ae2f8a2U, + 0xb0e05008U, 0xc5c90c7dU, 0x80dc5c38U, 0x90c85828U, + 0x741561ccU, 0xf775824fU, 0x0c737fb4U, 0x7bdaa1c3U, + 0x6284e6daU, 0x08767eb0U, 0x8f139c37U, 0xab3e9513U, + 0xc7498e7fU, 0xb4e5510cU, 0x958d182dU, 0x7695e3ceU, + 0x45692cfdU, 0xeb6e8553U, 0x49662ff1U, 0x402c6cf8U, + 0x32c0f28aU, 0x91881929U, 0xa731961fU, 0xe1e40559U, + 0xba6ad002U, 0x21143599U, 0x67c1a6dfU, 0xd218ca6aU, + 0xb725920fU, 0xe9ee0751U, 0x2f9bb497U, 0xaa7ed412U, + 0x0d333eb5U, 0x7d5f22c5U, 0xb665d30eU, 0x73d0a3cbU, + 0xd40fdb55U, 0xcd519c4cU, 0x28cce4a9U, 0x7487f3f5U, + 0xbc7dc13dU, 0x08e4ec89U, 0x7b4833faU, 0x51eabbd0U, + 0xd7cf1856U, 0x55efbad4U, 0xdfc51a5eU, 0x844bcf05U, + 0x2f0926aeU, 0x6096f6e1U, 0x3f1d22beU, 0x9b900b1aU, + 0x230625a2U, 0x127a6893U, 0xe5739664U, 0x562f79d7U, + 0x270324a6U, 0x75c7b2f4U, 0x9f950a1eU, 0x804ece01U, + 0x2583a6a4U, 0x9ed54b1fU, 0xc3de1d42U, 0x173f2896U, + 0xaaec462bU, 0x951f8a14U, 0x979f0816U, 0xe97c9568U, + 0xfd6d907cU, 0x86cb4d07U, 0xce915f4fU, 0x5ca5f9ddU, + 0xc9549d48U, 0x30d2e2b1U, 0xed79946cU, 0x661375e7U, + 0x437e3dc2U, 0xde855b5fU, 0xa3a60522U, 0x82ce4c03U, + 0x38d8e0b9U, 0xb072c231U, 0x3d9da0bcU, 0x066b6d87U, + 0x1cf5e99dU, 0x41febfc0U, 0xffed127eU, 0x298ca5a8U, + 0xa86cc429U, 0xafa9062eU, 0x2cc9e5adU, 0xd9409958U, + 0x8d018c0cU, 0xf022d271U, 0xdd45985cU, 0x6493f7e5U, + 0x5a207adbU, 0xb1328330U, 0x734231f2U, 0x15bfaa94U, + 0x92da4813U, 0x939a0912U, 0x11baab90U, 0x7c8df1fdU, + 0x40befec1U, 0x423e7cc3U, 0xd3ca1952U, 0x65d3b6e4U, + 0x810e8f00U, 0xeabc566bU, 0x7f4d32feU, 0xebfc176aU, + 0x14ffeb95U, 0x99108918U, 0xb2f24033U, 0x2d89a4acU, + 0x2e4967afU, 0x224664a3U, 0x89048d08U, 0x45fbbec4U, + 0x4a347ecbU, 0x1e756b9fU, 0xe433d765U, 0xa1268720U, + 0x6c99f5edU, 0x20c6e6a1U, 0xb3b20132U, 0xa2e64423U, + 0x4e317fcfU, 0xd68f5957U, 0xf9689178U, 0x5b603bdaU, + 0xf7e71076U, 0x1f352a9eU, 0xb7b70036U, 0xf6a75177U, + 0x026e6c83U, 0xeeb9576fU, 0xc814dc49U, 0x05abae84U, + 0x1b302b9aU, 0x072b2c86U, 0x7e0d73ffU, 0x635635e2U, + 0x8b840f0aU, 0x0b242f8aU, 0x6e1977efU, 0x911a8b10U, + 0xdc05d95dU, 0x8f810e0eU, 0x96df4917U, 0xd28a5853U, + 0xf1629370U, 0xc01ede41U, 0x133a2992U, 0xc69b5d47U, + 0xbefd433fU, 0x576f38d6U, 0x878b0c06U, 0x10faea91U, + 0x0da1ac8cU, 0x9c55c91dU, 0xac69c52dU, 0xf5679274U, + 0x24c3e7a5U, 0x71c2b3f0U, 0xa5238624U, 0xc41bdf45U, + 0x8ec14f0fU, 0x905aca11U, 0x6f5936eeU, 0x59e0b9d8U, + 0x01aeaf80U, 0x50aafad1U, 0x44bbffc5U, 0xb477c335U, + 0x689cf4e9U, 0x0a646e8bU, 0xdbc01b5aU, 0x09a4ad88U, + 0x0ce1ed8dU, 0x3597a2b4U, 0xfaa8527bU, 0x1db5a89cU, + 0xe1769760U, 0x5f653adeU, 0xe7f31466U, 0xda805a5bU, + 0x3998a1b8U, 0xc15e9f40U, 0x477b3cc6U, 0x4f713eceU, + 0x58a0f8d9U, 0xbd3d803cU, 0x49f4bdc8U, 0x00eeee81U, + 0xfbe8137aU, 0x54affbd5U, 0x04ebef85U, 0x371720b6U, + 0x850b8e04U, 0x167f6997U, 0xa463c725U, 0x0e616f8fU, + 0x8c41cd0dU, 0x2b0c27aaU, 0x032e2d82U, 0x2186a7a0U, + 0xbbb8033aU, 0xc29e5c43U, 0xb6f74137U, 0x325260b3U, + 0xd800d859U, 0xe036d661U, 0x536a39d2U, 0x9ad04a1bU, + 0xf427d375U, 0x7888f0f9U, 0xb5378234U, 0x331221b2U, + 0x838e0d02U, 0x7082f2f1U, 0x264365a7U, 0x463b7dc7U, + 0x3a5862bbU, 0x3e5d63bfU, 0xe2b65463U, 0xca945e4bU, + 0xb9388138U, 0xe3f61562U, 0x3192a3b0U, 0xc55b9e44U, + 0x61d6b7e0U, 0xf828d079U, 0x7dcdb0fcU, 0x720270f3U, + 0xcbd41f4aU, 0xe83cd469U, 0xfead537fU, 0x8ac44e0bU, + 0xf3e21172U, 0xcfd11e4eU, 0xe6b35567U, 0xec39d56dU, + 0xa7a30426U, 0x8844cc09U, 0x4b743fcaU, 0xad29842cU, + 0x19b0a998U, 0xb878c039U, 0x621674e3U, 0x79c8b1f8U, + 0x3b1823baU, 0x5e257bdfU, 0xcc11dd4dU, 0xc7db1c46U, + 0x6dd9b4ecU, 0x18f0e899U, 0x5de5b8dcU, 0x4df1bcccU, + 0xa92c8528U, 0x2a4c66abU, 0xd14a9b50U, 0xa6e34527U, + 0xbfbd023eU, 0xd54f9a54U, 0x522a78d3U, 0x760771f7U, + 0x1a706a9bU, 0x69dcb5e8U, 0x48b4fcc9U, 0xabac072aU, + 0x9850c819U, 0x365761b7U, 0x945fcb15U, 0x9d15881cU, + 0xeff9166eU, 0x4cb1fdcdU, 0x7a0872fbU, 0x3cdde1bdU, + 0x675334e6U, 0xfc2dd17dU, 0xbaf8423bU, 0x0f212e8eU, + 0x6a1c76ebU, 0x34d7e3b5U, 0xf2a25073U, 0x774730f6U, + 0xd00ada51U, 0xa066c621U, 0x6b5c37eaU, 0xaee9472fU, + 0x66d6b03eU, 0x7f88f727U, 0x9a158fc2U, 0xc65e989eU, + 0x0ea4aa56U, 0xba3d87e2U, 0xc9915891U, 0xe333d0bbU, + 0x6516733dU, 0xe736d1bfU, 0x6d1c7135U, 0x3692a46eU, + 0x9dd04dc5U, 0xd24f9d8aU, 0x8dc449d5U, 0x29496071U, + 0x91df4ec9U, 0xa0a303f8U, 0x57aafd0fU, 0xe4f612bcU, + 0x95da4fcdU, 0xc71ed99fU, 0x2d4c6175U, 0x3297a56aU, + 0x975acdcfU, 0x2c0c2074U, 0x71077629U, 0xa5e643fdU, + 0x18352d40U, 0x27c6e17fU, 0x2546637dU, 0x5ba5fe03U, + 0x4fb4fb17U, 0x3412266cU, 0x7c483424U, 0xee7c92b6U, + 0x7b8df623U, 0x820b89daU, 0x5fa0ff07U, 0xd4ca1e8cU, + 0xf1a756a9U, 0x6c5c3034U, 0x117f6e49U, 0x30172768U, + 0x8a018bd2U, 0x02aba95aU, 0x8f44cbd7U, 0xb4b206ecU, + 0xae2c82f6U, 0xf327d4abU, 0x4d347915U, 0x9b55cec3U, + 0x1ab5af42U, 0x1d706d45U, 0x9e108ec6U, 0x6b99f233U, + 0x3fd8e767U, 0x42fbb91aU, 0x6f9cf337U, 0xd64a9c8eU, + 0xe8f911b0U, 0x03ebe85bU, 0xc19b5a99U, 0xa766c1ffU, + 0x20032378U, 0x21436279U, 0xa363c0fbU, 0xce549a96U, + 0xf26795aaU, 0xf0e717a8U, 0x61137239U, 0xd70add8fU, + 0x33d7e46bU, 0x58653d00U, 0xcd945995U, 0x59257c01U, + 0xa62680feU, 0x2bc9e273U, 0x002b2b58U, 0x9f50cfc7U, + 0x9c900cc4U, 0x909f0fc8U, 0x3bdde663U, 0xf722d5afU, + 0xf8ed15a0U, 0xacac00f4U, 0x56eabc0eU, 0x13ffec4bU, + 0xde409e86U, 0x921f8dcaU, 0x016b6a59U, 0x103f2f48U, + 0xfce814a4U, 0x6456323cU, 0x4bb1fa13U, 0xe9b950b1U, + 0x453e7b1dU, 0xadec41f5U, 0x056e6b5dU, 0x447e3a1cU, + 0xb0b707e8U, 0x5c603c04U, 0x7acdb722U, 0xb772c5efU, + 0xa9e940f1U, 0xb5f247edU, 0xccd41894U, 0xd18f5e89U, + 0x395d6461U, 0xb9fd44e1U, 0xdcc01c84U, 0x23c3e07bU, + 0x6edcb236U, 0x3d586565U, 0x2406227cU, 0x60533338U, + 0x43bbf81bU, 0x72c7b52aU, 0xa1e342f9U, 0x7442362cU, + 0x0c242854U, 0xe5b653bdU, 0x3552676dU, 0xa22381faU, + 0xbf78c7e7U, 0x2e8ca276U, 0x1eb0ae46U, 0x47bef91fU, + 0x961a8cceU, 0xc31bd89bU, 0x17faed4fU, 0x76c2b42eU, + 0x3c182464U, 0x2283a17aU, 0xdd805d85U, 0xeb39d2b3U, + 0xb377c4ebU, 0xe27391baU, 0xf66294aeU, 0x06aea85eU, + 0xda459f82U, 0xb8bd05e0U, 0x69197031U, 0xbb7dc6e3U, + 0xbe3886e6U, 0x874ec9dfU, 0x48713910U, 0xaf6cc3f7U, + 0x53affc0bU, 0xedbc51b5U, 0x552a7f0dU, 0x68593130U, + 0x8b41cad3U, 0x7387f42bU, 0xf5a257adU, 0xfda855a5U, + 0xea7993b2U, 0x0fe4eb57U, 0xfb2dd6a3U, 0xb23785eaU, + 0x49317811U, 0xe67690beU, 0xb63284eeU, 0x85ce4bddU, + 0x37d2e56fU, 0xa4a602fcU, 0x16baac4eU, 0xbcb804e4U, + 0x3e98a666U, 0x99d54cc1U, 0xb1f746e9U, 0x935fcccbU, + 0x09616851U, 0x70473728U, 0x042e2a5cU, 0x808b0bd8U, + 0x6ad9b332U, 0x52efbd0aU, 0xe1b352b9U, 0x28092170U, + 0x46feb81eU, 0xca519b92U, 0x07eee95fU, 0x81cb4ad9U, + 0x31576669U, 0xc25b999aU, 0x949a0eccU, 0xf4e216acU, + 0x888109d0U, 0x8c8408d4U, 0x506f3f08U, 0x784d3520U, + 0x0be1ea53U, 0x512f7e09U, 0x834bc8dbU, 0x7782f52fU, + 0xd30fdc8bU, 0x4af1bb12U, 0xcf14db97U, 0xc0db1b98U, + 0x790d7421U, 0x5ae5bf02U, 0x4c743814U, 0x381d2560U, + 0x413b7a19U, 0x7d087525U, 0x546a3e0cU, 0x5ee0be06U, + 0x157a6f4dU, 0x3a9da762U, 0xf9ad54a1U, 0x1ff0ef47U, + 0xab69c2f3U, 0x0aa1ab52U, 0xd0cf1f88U, 0xcb11da93U, + 0x89c148d1U, 0xecfc10b4U, 0x7ec8b626U, 0x7502772dU, + 0xdf00df87U, 0xaa2983f2U, 0xef3cd3b7U, 0xff28d7a7U, + 0x1bf5ee43U, 0x98950dc0U, 0x6393f03bU, 0x143a2e4cU, + 0x0d646955U, 0x6796f13fU, 0xe0f313b8U, 0xc4de1a9cU, + 0xa8a901f0U, 0xdb05de83U, 0xfa6d97a2U, 0x19756c41U, + 0x2a89a372U, 0x848e0adcU, 0x2686a07eU, 0x2fcce377U, + 0x5d207d05U, 0xfe6896a6U, 0xc8d11990U, 0x8e048ad6U, + 0xd58a5f8dU, 0x4ef4ba16U, 0x08212950U, 0xbdf845e5U, + 0xd8c51d80U, 0x860e88deU, 0x407b3b18U, 0xc59e5b9dU, + 0x62d3b13aU, 0x12bfad4aU, 0xd9855c81U, 0x1c302c44U, + 0x97b225abU, 0x8eec62b2U, 0x6b711a57U, 0x373a0d0bU, + 0xffc03fc3U, 0x4b591277U, 0x38f5cd04U, 0x1257452eU, + 0x9472e6a8U, 0x1652442aU, 0x9c78e4a0U, 0xc7f631fbU, + 0x6cb4d850U, 0x232b081fU, 0x7ca0dc40U, 0xd82df5e4U, + 0x60bbdb5cU, 0x51c7966dU, 0xa6ce689aU, 0x15928729U, + 0x64beda58U, 0x367a4c0aU, 0xdc28f4e0U, 0xc3f330ffU, + 0x663e585aU, 0xdd68b5e1U, 0x8063e3bcU, 0x5482d668U, + 0xe951b8d5U, 0xd6a274eaU, 0xd422f6e8U, 0xaac16b96U, + 0xbed06e82U, 0xc576b3f9U, 0x8d2ca1b1U, 0x1f180723U, + 0x8ae963b6U, 0x736f1c4fU, 0xaec46a92U, 0x25ae8b19U, + 0x00c3c33cU, 0x9d38a5a1U, 0xe01bfbdcU, 0xc173b2fdU, + 0x7b651e47U, 0xf3cf3ccfU, 0x7e205e42U, 0x45d69379U, + 0x5f481763U, 0x0243413eU, 0xbc50ec80U, 0x6a315b56U, + 0xebd13ad7U, 0xec14f8d0U, 0x6f741b53U, 0x9afd67a6U, + 0xcebc72f2U, 0xb39f2c8fU, 0x9ef866a2U, 0x272e091bU, + 0x199d8425U, 0xf28f7dceU, 0x30ffcf0cU, 0x5602546aU, + 0xd167b6edU, 0xd027f7ecU, 0x5207556eU, 0x3f300f03U, + 0x0303003fU, 0x0183823dU, 0x9077e7acU, 0x266e481aU, + 0xc2b371feU, 0xa901a895U, 0x3cf0cc00U, 0xa841e994U, + 0x5742156bU, 0xdaad77e6U, 0xf14fbecdU, 0x6e345a52U, + 0x6df49951U, 0x61fb9a5dU, 0xcab973f6U, 0x0646403aU, + 0x09898035U, 0x5dc89561U, 0xa78e299bU, 0xe29b79deU, + 0x2f240b13U, 0x637b185fU, 0xf00fffccU, 0xe15bbaddU, + 0x0d8c8131U, 0x9532a7a9U, 0xbad56f86U, 0x18ddc524U, + 0xb45aee88U, 0x5c88d460U, 0xf40afec8U, 0xb51aaf89U, + 0x41d3927dU, 0xad04a991U, 0x8ba922b7U, 0x4616507aU, + 0x588dd564U, 0x4496d278U, 0x3db08d01U, 0x20ebcb1cU, + 0xc839f1f4U, 0x4899d174U, 0x2da48911U, 0xd2a775eeU, + 0x9fb827a3U, 0xcc3cf0f0U, 0xd562b7e9U, 0x9137a6adU, + 0xb2df6d8eU, 0x83a320bfU, 0x5087d76cU, 0x8526a3b9U, + 0xfd40bdc1U, 0x14d2c628U, 0xc436f2f8U, 0x5347146fU, + 0x4e1c5272U, 0xdfe837e3U, 0xefd43bd3U, 0xb6da6c8aU, + 0x677e195bU, 0x327f4d0eU, 0xe69e78daU, 0x87a621bbU, + 0xcd7cb1f1U, 0xd3e734efU, 0x2ce4c810U, 0x1a5d4726U, + 0x4213517eU, 0x1317042fU, 0x0706013bU, 0xf7ca3dcbU, + 0x2b210a17U, 0x49d99075U, 0x987de5a4U, 0x4a195376U, + 0x4f5c1373U, 0x762a5c4aU, 0xb915ac85U, 0x5e085662U, + 0xa2cb699eU, 0x1cd8c420U, 0xa44eea98U, 0x993da4a5U, + 0x7a255f46U, 0x82e361beU, 0x04c6c238U, 0x0cccc030U, + 0x1b1d0627U, 0xfe807ec2U, 0x0a494336U, 0x4353107fU, + 0xb855ed84U, 0x1712052bU, 0x4756117bU, 0x74aade48U, + 0xc6b670faU, 0x55c29769U, 0xe7de39dbU, 0x4ddc9171U, + 0xcffc33f3U, 0x68b1d954U, 0x4093d37cU, 0x623b595eU, + 0xf805fdc4U, 0x8123a2bdU, 0xf54abfc9U, 0x71ef9e4dU, + 0x9bbd26a7U, 0xa38b289fU, 0x10d7c72cU, 0xd96db4e5U, + 0xb79a2d8bU, 0x3b350e07U, 0xf68a7ccaU, 0x70afdf4cU, + 0xc033f3fcU, 0x333f0c0fU, 0x65fe9b59U, 0x05868339U, + 0x79e59c45U, 0x7de09d41U, 0xa10baa9dU, 0x8929a0b5U, + 0xfa857fc6U, 0xa04beb9cU, 0x722f5d4eU, 0x86e660baU, + 0x226b491eU, 0xbb952e87U, 0x3e704e02U, 0x31bf8e0dU, + 0x8869e1b4U, 0xab812a97U, 0xbd10ad81U, 0xc979b0f5U, + 0xb05fef8cU, 0x8c6ce0b0U, 0xa50eab99U, 0xaf842b93U, + 0xe41efad8U, 0xcbf932f7U, 0x08c9c134U, 0xee947ad2U, + 0x5a0d5766U, 0xfbc53ec7U, 0x21ab8a1dU, 0x3a754f06U, + 0x78a5dd44U, 0x1d988521U, 0x8fac23b3U, 0x8466e2b8U, + 0x2e644a12U, 0x5b4d1667U, 0x1e584622U, 0x0e4c4232U, + 0xea917bd6U, 0x69f19855U, 0x92f765aeU, 0xe55ebbd9U, + 0xfc00fcc0U, 0x96f264aaU, 0x1197862dU, 0x35ba8f09U, + 0x59cd9465U, 0x2a614b16U, 0x0b090237U, 0xe811f9d4U, + 0xdbed36e7U, 0x75ea9f49U, 0xd7e235ebU, 0xdea876e2U, + 0xac44e890U, 0x0f0c0333U, 0x39b58c05U, 0x7f601f43U, + 0x24eeca18U, 0xbf902f83U, 0xf945bcc5U, 0x4c9cd070U, + 0x29a18815U, 0x776a1d4bU, 0xb11fae8dU, 0x34face08U, + 0x93b724afU, 0xe3db38dfU, 0x28e1c914U, 0xed54b9d1U, + 0x2697b13fU, 0x3fc9f626U, 0xda548ec3U, 0x861f999fU, + 0x4ee5ab57U, 0xfa7c86e3U, 0x89d05990U, 0xa372d1baU, + 0x2557723cU, 0xa777d0beU, 0x2d5d7034U, 0x76d3a56fU, + 0xdd914cc4U, 0x920e9c8bU, 0xcd8548d4U, 0x69086170U, + 0xd19e4fc8U, 0xe0e202f9U, 0x17ebfc0eU, 0xa4b713bdU, + 0xd59b4eccU, 0x875fd89eU, 0x6d0d6074U, 0x72d6a46bU, + 0xd71bccceU, 0x6c4d2175U, 0x31467728U, 0xe5a742fcU, + 0x58742c41U, 0x6787e07eU, 0x6507627cU, 0x1be4ff02U, + 0x0ff5fa16U, 0x7453276dU, 0x3c093525U, 0xae3d93b7U, + 0x3bccf722U, 0xc24a88dbU, 0x1fe1fe06U, 0x948b1f8dU, + 0xb1e657a8U, 0x2c1d3135U, 0x513e6f48U, 0x70562669U, + 0xca408ad3U, 0x42eaa85bU, 0xcf05cad6U, 0xf4f307edU, + 0xee6d83f7U, 0xb366d5aaU, 0x0d757814U, 0xdb14cfc2U, + 0x5af4ae43U, 0x5d316c44U, 0xde518fc7U, 0x2bd8f332U, + 0x7f99e666U, 0x02bab81bU, 0x2fddf236U, 0x960b9d8fU, + 0xa8b810b1U, 0x43aae95aU, 0x81da5b98U, 0xe727c0feU, + 0x60422279U, 0x61026378U, 0xe322c1faU, 0x8e159b97U, + 0xb22694abU, 0xb0a616a9U, 0x21527338U, 0x974bdc8eU, + 0x7396e56aU, 0x18243c01U, 0x8dd55894U, 0x19647d00U, + 0xe66781ffU, 0x6b88e372U, 0x406a2a59U, 0xdf11cec6U, + 0xdcd10dc5U, 0xd0de0ec9U, 0x7b9ce762U, 0xb763d4aeU, + 0xb8ac14a1U, 0xeced01f5U, 0x16abbd0fU, 0x53beed4aU, + 0x9e019f87U, 0xd25e8ccbU, 0x412a6b58U, 0x507e2e49U, + 0xbca915a5U, 0x2417333dU, 0x0bf0fb12U, 0xa9f851b0U, + 0x057f7a1cU, 0xedad40f4U, 0x452f6a5cU, 0x043f3b1dU, + 0xf0f606e9U, 0x1c213d05U, 0x3a8cb623U, 0xf733c4eeU, + 0xe9a841f0U, 0xf5b346ecU, 0x8c951995U, 0x91ce5f88U, + 0x791c6560U, 0xf9bc45e0U, 0x9c811d85U, 0x6382e17aU, + 0x2e9db337U, 0x7d196464U, 0x6447237dU, 0x20123239U, + 0x03faf91aU, 0x3286b42bU, 0xe1a243f8U, 0x3403372dU, + 0x4c652955U, 0xa5f752bcU, 0x7513666cU, 0xe26280fbU, + 0xff39c6e6U, 0x6ecda377U, 0x5ef1af47U, 0x07fff81eU, + 0xd65b8dcfU, 0x835ad99aU, 0x57bbec4eU, 0x3683b52fU, + 0x7c592565U, 0x62c2a07bU, 0x9dc15c84U, 0xab78d3b2U, + 0xf336c5eaU, 0xa23290bbU, 0xb62395afU, 0x46efa95fU, + 0x9a049e83U, 0xf8fc04e1U, 0x29587130U, 0xfb3cc7e2U, + 0xfe7987e7U, 0xc70fc8deU, 0x08303811U, 0xef2dc2f6U, + 0x13eefd0aU, 0xadfd50b4U, 0x156b7e0cU, 0x28183031U, + 0xcb00cbd2U, 0x33c6f52aU, 0xb5e356acU, 0xbde954a4U, + 0xaa3892b3U, 0x4fa5ea56U, 0xbb6cd7a2U, 0xf27684ebU, + 0x09707910U, 0xa63791bfU, 0xf67385efU, 0xc58f4adcU, + 0x7793e46eU, 0xe4e703fdU, 0x56fbad4fU, 0xfcf905e5U, + 0x7ed9a767U, 0xd9944dc0U, 0xf1b647e8U, 0xd31ecdcaU, + 0x49206950U, 0x30063629U, 0x446f2b5dU, 0xc0ca0ad9U, + 0x2a98b233U, 0x12aebc0bU, 0xa1f253b8U, 0x68482071U, + 0x06bfb91fU, 0x8a109a93U, 0x47afe85eU, 0xc18a4bd8U, + 0x71166768U, 0x821a989bU, 0xd4db0fcdU, 0xb4a317adU, + 0xc8c008d1U, 0xccc509d5U, 0x102e3e09U, 0x380c3421U, + 0x4ba0eb52U, 0x116e7f08U, 0xc30ac9daU, 0x37c3f42eU, + 0x934edd8aU, 0x0ab0ba13U, 0x8f55da96U, 0x809a1a99U, + 0x394c7520U, 0x1aa4be03U, 0x0c353915U, 0x785c2461U, + 0x017a7b18U, 0x3d497424U, 0x142b3f0dU, 0x1ea1bf07U, + 0x553b6e4cU, 0x7adca663U, 0xb9ec55a0U, 0x5fb1ee46U, + 0xeb28c3f2U, 0x4ae0aa53U, 0x908e1e89U, 0x8b50db92U, + 0xc98049d0U, 0xacbd11b5U, 0x3e89b727U, 0x3543762cU, + 0x9f41de86U, 0xea6882f3U, 0xaf7dd2b6U, 0xbf69d6a6U, + 0x5bb4ef42U, 0xd8d40cc1U, 0x23d2f13aU, 0x547b2f4dU, + 0x4d256854U, 0x27d7f03eU, 0xa0b212b9U, 0x849f1b9dU, + 0xe8e800f1U, 0x9b44df82U, 0xba2c96a3U, 0x59346d40U, + 0x6ac8a273U, 0xc4cf0bddU, 0x66c7a17fU, 0x6f8de276U, + 0x1d617c04U, 0xbe2997a7U, 0x88901891U, 0xce458bd7U, + 0x95cb5e8cU, 0x0eb5bb17U, 0x48602851U, 0xfdb944e4U, + 0x98841c81U, 0xc64f89dfU, 0x003a3a19U, 0x85df5a9cU, + 0x2292b03bU, 0x52feac4bU, 0x99c45d80U, 0x5c712d45U, + 0x256b4ec0U, 0x3c3509d9U, 0xd9a8713cU, 0x85e36660U, + 0x4d1954a8U, 0xf980791cU, 0x8a2ca66fU, 0xa08e2e45U, + 0x26ab8dc3U, 0xa48b2f41U, 0x2ea18fcbU, 0x752f5a90U, + 0xde6db33bU, 0x91f26374U, 0xce79b72bU, 0x6af49e8fU, + 0xd262b037U, 0xe31efd06U, 0x141703f1U, 0xa74bec42U, + 0xd667b133U, 0x84a32761U, 0x6ef19f8bU, 0x712a5b94U, + 0xd4e73331U, 0x6fb1de8aU, 0x32ba88d7U, 0xe65bbd03U, + 0x5b88d3beU, 0x647b1f81U, 0x66fb9d83U, 0x181800fdU, + 0x0c0905e9U, 0x77afd892U, 0x3ff5cadaU, 0xadc16c48U, + 0x383008ddU, 0xc1b67724U, 0x1c1d01f9U, 0x9777e072U, + 0xb21aa857U, 0x2fe1cecaU, 0x52c290b7U, 0x73aad996U, + 0xc9bc752cU, 0x411657a4U, 0xccf93529U, 0xf70ff812U, + 0xed917c08U, 0xb09a2a55U, 0x0e8987ebU, 0xd8e8303dU, + 0x590851bcU, 0x5ecd93bbU, 0xddad7038U, 0x28240ccdU, + 0x7c651999U, 0x014647e4U, 0x2c210dc9U, 0x95f76270U, + 0xab44ef4eU, 0x405616a5U, 0x8226a467U, 0xe4db3f01U, + 0x63bedd86U, 0x62fe9c87U, 0xe0de3e05U, 0x8de96468U, + 0xb1da6b54U, 0xb35ae956U, 0x22ae8cc7U, 0x94b72371U, + 0x706a1a95U, 0x1bd8c3feU, 0x8e29a76bU, 0x1a9882ffU, + 0xe59b7e00U, 0x68741c8dU, 0x4396d5a6U, 0xdced3139U, + 0xdf2df23aU, 0xd322f136U, 0x7860189dU, 0xb49f2b51U, + 0xbb50eb5eU, 0xef11fe0aU, 0x155742f0U, 0x504212b5U, + 0x9dfd6078U, 0xd1a27334U, 0x42d694a7U, 0x5382d1b6U, + 0xbf55ea5aU, 0x27ebccc2U, 0x080c04edU, 0xaa04ae4fU, + 0x068385e3U, 0xee51bf0bU, 0x46d395a3U, 0x07c3c4e2U, + 0xf30af916U, 0x1fddc2faU, 0x397049dcU, 0xf4cf3b11U, + 0xea54be0fU, 0xf64fb913U, 0x8f69e66aU, 0x9232a077U, + 0x7ae09a9fU, 0xfa40ba1fU, 0x9f7de27aU, 0x607e1e85U, + 0x2d614cc8U, 0x7ee59b9bU, 0x67bbdc82U, 0x23eecdc6U, + 0x000606e5U, 0x317a4bd4U, 0xe25ebc07U, 0x37ffc8d2U, + 0x4f99d6aaU, 0xa60bad43U, 0x76ef9993U, 0xe19e7f04U, + 0xfcc53919U, 0x6d315c88U, 0x5d0d50b8U, 0x040307e1U, + 0xd5a77230U, 0x80a62665U, 0x544713b1U, 0x357f4ad0U, + 0x7fa5da9aU, 0x613e5f84U, 0x9e3da37bU, 0xa8842c4dU, + 0xf0ca3a15U, 0xa1ce6f44U, 0xb5df6a50U, 0x451356a0U, + 0x99f8617cU, 0xfb00fb1eU, 0x2aa48ecfU, 0xf8c0381dU, + 0xfd857818U, 0xc4f33721U, 0x0bccc7eeU, 0xecd13d09U, + 0x101202f5U, 0xae01af4bU, 0x169781f3U, 0x2be4cfceU, + 0xc8fc342dU, 0x303a0ad5U, 0xb61fa953U, 0xbe15ab5bU, + 0xa9c46d4cU, 0x4c5915a9U, 0xb890285dU, 0xf18a7b14U, + 0x0a8c86efU, 0xa5cb6e40U, 0xf58f7a10U, 0xc673b523U, + 0x746f1b91U, 0xe71bfc02U, 0x550752b0U, 0xff05fa1aU, + 0x7d255898U, 0xda68b23fU, 0xf24ab817U, 0xd0e23235U, + 0x4adc96afU, 0x33fac9d6U, 0x4793d4a2U, 0xc336f526U, + 0x29644dccU, 0x115243f4U, 0xa20eac47U, 0x6bb4df8eU, + 0x054346e0U, 0x89ec656cU, 0x445317a1U, 0xc276b427U, + 0x72ea9897U, 0x81e66764U, 0xd727f032U, 0xb75fe852U, + 0xcb3cf72eU, 0xcf39f62aU, 0x13d2c1f6U, 0x3bf0cbdeU, + 0x485c14adU, 0x129280f7U, 0xc0f63625U, 0x343f0bd1U, + 0x90b22275U, 0x094c45ecU, 0x8ca92569U, 0x8366e566U, + 0x3ab08adfU, 0x195841fcU, 0x0fc9c6eaU, 0x7ba0db9eU, + 0x028684e7U, 0x3eb58bdbU, 0x17d7c0f2U, 0x1d5d40f8U, + 0x56c791b3U, 0x7920599cU, 0xba10aa5fU, 0x5c4d11b9U, + 0xe8d43c0dU, 0x491c55acU, 0x9372e176U, 0x88ac246dU, + 0xca7cb62fU, 0xaf41ee4aU, 0x3d7548d8U, 0x36bf89d3U, + 0x9cbd2179U, 0xe9947d0cU, 0xac812d49U, 0xbc952959U, + 0x584810bdU, 0xdb28f33eU, 0x202e0ec5U, 0x5787d0b2U, + 0x4ed997abU, 0x242b0fc1U, 0xa34eed46U, 0x8763e462U, + 0xeb14ff0eU, 0x98b8207dU, 0xb9d0695cU, 0x5ac892bfU, + 0x69345d8cU, 0xc733f422U, 0x653b5e80U, 0x6c711d89U, + 0x1e9d83fbU, 0xbdd56858U, 0x8b6ce76eU, 0xcdb97428U, + 0x9637a173U, 0x0d4944e8U, 0x4b9cd7aeU, 0xfe45bb1bU, + 0x9b78e37eU, 0xc5b37620U, 0x03c6c5e6U, 0x8623a563U, + 0x216e4fc4U, 0x510253b4U, 0x9a38a27fU, 0x5f8dd2baU, + 0xca09c34dU, 0xd3578454U, 0x36cafcb1U, 0x6a81ebedU, + 0xa27bd925U, 0x16e2f491U, 0x654e2be2U, 0x4feca3c8U, + 0xc9c9004eU, 0x4be9a2ccU, 0xc1c30246U, 0x9a4dd71dU, + 0x310f3eb6U, 0x7e90eef9U, 0x211b3aa6U, 0x85961302U, + 0x3d003dbaU, 0x0c7c708bU, 0xfb758e7cU, 0x482961cfU, + 0x39053cbeU, 0x6bc1aaecU, 0x81931206U, 0x9e48d619U, + 0x3b85bebcU, 0x80d35307U, 0xddd8055aU, 0x0939308eU, + 0xb4ea5e33U, 0x8b19920cU, 0x8999100eU, 0xf77a8d70U, + 0xe36b8864U, 0x98cd551fU, 0xd0974757U, 0x42a3e1c5U, + 0xd7528550U, 0x2ed4faa9U, 0xf37f8c74U, 0x78156dffU, + 0x5d7825daU, 0xc0834347U, 0xbda01d3aU, 0x9cc8541bU, + 0x26def8a1U, 0xae74da29U, 0x239bb8a4U, 0x186d759fU, + 0x02f3f185U, 0x5ff8a7d8U, 0xe1eb0a66U, 0x378abdb0U, + 0xb66adc31U, 0xb1af1e36U, 0x32cffdb5U, 0xc7468140U, + 0x93079414U, 0xee24ca69U, 0xc3438044U, 0x7a95effdU, + 0x442662c3U, 0xaf349b28U, 0x6d4429eaU, 0x0bb9b28cU, + 0x8cdc500bU, 0x8d9c110aU, 0x0fbcb388U, 0x628be9e5U, + 0x5eb8e6d9U, 0x5c3864dbU, 0xcdcc014aU, 0x7bd5aefcU, + 0x9f089718U, 0xf4ba4e73U, 0x614b2ae6U, 0xf5fa0f72U, + 0x0af9f38dU, 0x87169100U, 0xacf4582bU, 0x338fbcb4U, + 0x304f7fb7U, 0x3c407cbbU, 0x97029510U, 0x5bfda6dcU, + 0x543266d3U, 0x00737387U, 0xfa35cf7dU, 0xbf209f38U, + 0x729fedf5U, 0x3ec0feb9U, 0xadb4192aU, 0xbce05c3bU, + 0x503767d7U, 0xc889414fU, 0xe76e8960U, 0x456623c2U, + 0xe9e1086eU, 0x01333286U, 0xa9b1182eU, 0xe8a1496fU, + 0x1c68749bU, 0xf0bf4f77U, 0xd612c451U, 0x1badb69cU, + 0x05363382U, 0x192d349eU, 0x600b6be7U, 0x7d502dfaU, + 0x95821712U, 0x15223792U, 0x701f6ff7U, 0x8f1c9308U, + 0xc203c145U, 0x91871616U, 0x88d9510fU, 0xcc8c404bU, + 0xef648b68U, 0xde18c659U, 0x0d3c318aU, 0xd89d455fU, + 0xa0fb5b27U, 0x496920ceU, 0x998d141eU, 0x0efcf289U, + 0x13a7b494U, 0x8253d105U, 0xb26fdd35U, 0xeb618a6cU, + 0x3ac5ffbdU, 0x6fc4abe8U, 0xbb259e3cU, 0xda1dc75dU, + 0x90c75717U, 0x8e5cd209U, 0x715f2ef6U, 0x47e6a1c0U, + 0x1fa8b798U, 0x4eace2c9U, 0x5abde7ddU, 0xaa71db2dU, + 0x769aecf1U, 0x14627693U, 0xc5c60342U, 0x17a2b590U, + 0x12e7f595U, 0x2b91baacU, 0xe4ae4a63U, 0x03b3b084U, + 0xff708f78U, 0x416322c6U, 0xf9f50c7eU, 0xc4864243U, + 0x279eb9a0U, 0xdf588758U, 0x597d24deU, 0x517726d6U, + 0x46a6e0c1U, 0xa33b9824U, 0x57f2a5d0U, 0x1ee8f699U, + 0xe5ee0b62U, 0x4aa9e3cdU, 0x1aedf79dU, 0x291138aeU, + 0x9b0d961cU, 0x0879718fU, 0xba65df3dU, 0x10677797U, + 0x9247d515U, 0x350a3fb2U, 0x1d28359aU, 0x3f80bfb8U, + 0xa5be1b22U, 0xdc98445bU, 0xa8f1592fU, 0x2c5478abU, + 0xc606c041U, 0xfe30ce79U, 0x4d6c21caU, 0x84d65203U, + 0xea21cb6dU, 0x668ee8e1U, 0xab319a2cU, 0x2d1439aaU, + 0x9d88151aU, 0x6e84eae9U, 0x38457dbfU, 0x583d65dfU, + 0x245e7aa3U, 0x205b7ba7U, 0xfcb04c7bU, 0xd4924653U, + 0xa73e9920U, 0xfdf00d7aU, 0x2f94bba8U, 0xdb5d865cU, + 0x7fd0aff8U, 0xe62ec861U, 0x63cba8e4U, 0x6c0468ebU, + 0xd5d20752U, 0xf63acc71U, 0xe0ab4b67U, 0x94c25613U, + 0xede4096aU, 0xd1d70656U, 0xf8b54d7fU, 0xf23fcd75U, + 0xb9a51c3eU, 0x9642d411U, 0x557227d2U, 0xb32f9c34U, + 0x07b6b180U, 0xa67ed821U, 0x7c106cfbU, 0x67cea9e0U, + 0x251e3ba2U, 0x402363c7U, 0xd217c555U, 0xd9dd045eU, + 0x73dfacf4U, 0x06f6f081U, 0x43e3a0c4U, 0x53f7a4d4U, + 0xb72a9d30U, 0x344a7eb3U, 0xcf4c8348U, 0xb8e55d3fU, + 0xa1bb1a26U, 0xcb49824cU, 0x4c2c60cbU, 0x680169efU, + 0x04767283U, 0x77daadf0U, 0x56b2e4d1U, 0xb5aa1f32U, + 0x8656d001U, 0x285179afU, 0x8a59d30dU, 0x83139004U, + 0xf1ff0e76U, 0x52b7e5d5U, 0x640e6ae3U, 0x22dbf9a5U, + 0x79552cfeU, 0xe22bc965U, 0xa4fe5a23U, 0x11273696U, + 0x741a6ef3U, 0x2ad1fbadU, 0xeca4486bU, 0x694128eeU, + 0xce0cc249U, 0xbe60de39U, 0x755a2ff2U, 0xb0ef5f37U, + 0x28c0e866U, 0x319eaf7fU, 0xd403d79aU, 0x8848c0c6U, + 0x40b2f20eU, 0xf42bdfbaU, 0x878700c9U, 0xad2588e3U, + 0x2b002b65U, 0xa92089e7U, 0x230a296dU, 0x7884fc36U, + 0xd3c6159dU, 0x9c59c5d2U, 0xc3d2118dU, 0x675f3829U, + 0xdfc91691U, 0xeeb55ba0U, 0x19bca557U, 0xaae04ae4U, + 0xdbcc1795U, 0x890881c7U, 0x635a392dU, 0x7c81fd32U, + 0xd94c9597U, 0x621a782cU, 0x3f112e71U, 0xebf01ba5U, + 0x56237518U, 0x69d0b927U, 0x6b503b25U, 0x15b3a65bU, + 0x01a2a34fU, 0x7a047e34U, 0x325e6c7cU, 0xa06acaeeU, + 0x359bae7bU, 0xcc1dd182U, 0x11b6a75fU, 0x9adc46d4U, + 0xbfb10ef1U, 0x224a686cU, 0x5f693611U, 0x7e017f30U, + 0xc417d38aU, 0x4cbdf102U, 0xc152938fU, 0xfaa45eb4U, + 0xe03adaaeU, 0xbd318cf3U, 0x0322214dU, 0xd543969bU, + 0x54a3f71aU, 0x5366351dU, 0xd006d69eU, 0x258faa6bU, + 0x71cebf3fU, 0x0cede142U, 0x218aab6fU, 0x985cc4d6U, + 0xa6ef49e8U, 0x4dfdb003U, 0x8f8d02c1U, 0xe97099a7U, + 0x6e157b20U, 0x6f553a21U, 0xed7598a3U, 0x8042c2ceU, + 0xbc71cdf2U, 0xbef14ff0U, 0x2f052a61U, 0x991c85d7U, + 0x7dc1bc33U, 0x16736558U, 0x838201cdU, 0x17332459U, + 0xe830d8a6U, 0x65dfba2bU, 0x4e3d7300U, 0xd146979fU, + 0xd286549cU, 0xde895790U, 0x75cbbe3bU, 0xb9348df7U, + 0xb6fb4df8U, 0xe2ba58acU, 0x18fce456U, 0x5de9b413U, + 0x9056c6deU, 0xdc09d592U, 0x4f7d3201U, 0x5e297710U, + 0xb2fe4cfcU, 0x2a406a64U, 0x05a7a24bU, 0xa7af08e9U, + 0x0b282345U, 0xe3fa19adU, 0x4b783305U, 0x0a686244U, + 0xfea15fb0U, 0x1276645cU, 0x34dbef7aU, 0xf9649db7U, + 0xe7ff18a9U, 0xfbe41fb5U, 0x82c240ccU, 0x9f9906d1U, + 0x774b3c39U, 0xf7eb1cb9U, 0x92d644dcU, 0x6dd5b823U, + 0x20caea6eU, 0x734e3d3dU, 0x6a107a24U, 0x2e456b60U, + 0x0dada043U, 0x3cd1ed72U, 0xeff51aa1U, 0x3a546e74U, + 0x4232700cU, 0xaba00be5U, 0x7b443f35U, 0xec35d9a2U, + 0xf16e9fbfU, 0x609afa2eU, 0x50a6f61eU, 0x09a8a147U, + 0xd80cd496U, 0x8d0d80c3U, 0x59ecb517U, 0x38d4ec76U, + 0x720e7c3cU, 0x6c95f922U, 0x939605ddU, 0xa52f8aebU, + 0xfd619cb3U, 0xac65c9e2U, 0xb874ccf6U, 0x48b8f006U, + 0x9453c7daU, 0xf6ab5db8U, 0x270f2869U, 0xf56b9ebbU, + 0xf02edebeU, 0xc9589187U, 0x06676148U, 0xe17a9bafU, + 0x1db9a453U, 0xa3aa09edU, 0x1b3c2755U, 0x264f6968U, + 0xc557928bU, 0x3d91ac73U, 0xbbb40ff5U, 0xb3be0dfdU, + 0xa46fcbeaU, 0x41f2b30fU, 0xb53b8efbU, 0xfc21ddb2U, + 0x07272049U, 0xa860c8e6U, 0xf824dcb6U, 0xcbd81385U, + 0x79c4bd37U, 0xeab05aa4U, 0x58acf416U, 0xf2ae5cbcU, + 0x708efe3eU, 0xd7c31499U, 0xffe11eb1U, 0xdd499493U, + 0x47773009U, 0x3e516f70U, 0x4a387204U, 0xce9d5380U, + 0x24cfeb6aU, 0x1cf9e552U, 0xafa50ae1U, 0x661f7928U, + 0x08e8e046U, 0x8447c3caU, 0x49f8b107U, 0xcfdd1281U, + 0x7f413e31U, 0x8c4dc1c2U, 0xda8c5694U, 0xbaf44ef4U, + 0xc6975188U, 0xc292508cU, 0x1e796750U, 0x365b6d78U, + 0x45f7b20bU, 0x1f392651U, 0xcd5d9083U, 0x3994ad77U, + 0x9d1984d3U, 0x04e7e34aU, 0x810283cfU, 0x8ecd43c0U, + 0x371b2c79U, 0x14f3e75aU, 0x0262604cU, 0x760b7d38U, + 0x0f2d2241U, 0x331e2d7dU, 0x1a7c6654U, 0x10f6e65eU, + 0x5b6c3715U, 0x748bff3aU, 0xb7bb0cf9U, 0x51e6b71fU, + 0xe57f9aabU, 0x44b7f30aU, 0x9ed947d0U, 0x850782cbU, + 0xc7d71089U, 0xa2ea48ecU, 0x30deee7eU, 0x3b142f75U, + 0x911687dfU, 0xe43fdbaaU, 0xa12a8befU, 0xb13e8fffU, + 0x55e3b61bU, 0xd6835598U, 0x2d85a863U, 0x5a2c7614U, + 0x4372310dU, 0x2980a967U, 0xaee54be0U, 0x8ac842c4U, + 0xe6bf59a8U, 0x951386dbU, 0xb47bcffaU, 0x57633419U, + 0x649ffb2aU, 0xca985284U, 0x6890f826U, 0x61dabb2fU, + 0x1336255dU, 0xb07ecefeU, 0x86c741c8U, 0xc012d28eU, + 0x9b9c07d5U, 0x00e2e24eU, 0x46377108U, 0xf3ee1dbdU, + 0x96d345d8U, 0xc818d086U, 0x0e6d6340U, 0x8b8803c5U, + 0x2cc5e962U, 0x5ca9f512U, 0x979304d9U, 0x5226741cU, + 0x532477f9U, 0x4a7a30e0U, 0xafe74805U, 0xf3ac5f59U, + 0x3b566d91U, 0x8fcf4025U, 0xfc639f56U, 0xd6c1177cU, + 0x50e4b4faU, 0xd2c41678U, 0x58eeb6f2U, 0x036063a9U, + 0xa8228a02U, 0xe7bd5a4dU, 0xb8368e12U, 0x1cbba7b6U, + 0xa42d890eU, 0x9551c43fU, 0x62583ac8U, 0xd104d57bU, + 0xa028880aU, 0xf2ec1e58U, 0x18bea6b2U, 0x076562adU, + 0xa2a80a08U, 0x19fee7b3U, 0x44f5b1eeU, 0x9014843aU, + 0x2dc7ea87U, 0x123426b8U, 0x10b4a4baU, 0x6e5739c4U, + 0x7a463cd0U, 0x01e0e1abU, 0x49baf3e3U, 0xdb8e5571U, + 0x4e7f31e4U, 0xb7f94e1dU, 0x6a5238c0U, 0xe138d94bU, + 0xc455916eU, 0x59aef7f3U, 0x248da98eU, 0x05e5e0afU, + 0xbff34c15U, 0x37596e9dU, 0xbab60c10U, 0x8140c12bU, + 0x9bde4531U, 0xc6d5136cU, 0x78c6bed2U, 0xaea70904U, + 0x2f476885U, 0x2882aa82U, 0xabe24901U, 0x5e6b35f4U, + 0x0a2a20a0U, 0x77097eddU, 0x5a6e34f0U, 0xe3b85b49U, + 0xdd0bd677U, 0x36192f9cU, 0xf4699d5eU, 0x92940638U, + 0x15f1e4bfU, 0x14b1a5beU, 0x9691073cU, 0xfba65d51U, + 0xc795526dU, 0xc515d06fU, 0x54e1b5feU, 0xe2f81a48U, + 0x062523acU, 0x6d97fac7U, 0xf8669e52U, 0x6cd7bbc6U, + 0x93d44739U, 0x1e3b25b4U, 0x35d9ec9fU, 0xaaa20800U, + 0xa962cb03U, 0xa56dc80fU, 0x0e2f21a4U, 0xc2d01268U, + 0xcd1fd267U, 0x995ec733U, 0x63187bc9U, 0x260d2b8cU, + 0xebb25941U, 0xa7ed4a0dU, 0x3499ad9eU, 0x25cde88fU, + 0xc91ad363U, 0x51a4f5fbU, 0x7e433dd4U, 0xdc4b9776U, + 0x70ccbcdaU, 0x981e8632U, 0x309cac9aU, 0x718cfddbU, + 0x8545c02fU, 0x6992fbc3U, 0x4f3f70e5U, 0x82800228U, + 0x9c1b8736U, 0x8000802aU, 0xf926df53U, 0xe47d994eU, + 0x0cafa3a6U, 0x8c0f8326U, 0xe932db43U, 0x163127bcU, + 0x5b2e75f1U, 0x08aaa2a2U, 0x11f4e5bbU, 0x55a1f4ffU, + 0x76493fdcU, 0x473572edU, 0x9411853eU, 0x41b0f1ebU, + 0x39d6ef93U, 0xd044947aU, 0x00a0a0aaU, 0x97d1463dU, + 0x8a8a0020U, 0x1b7e65b1U, 0x2b426981U, 0x724c3ed8U, + 0xa3e84b09U, 0xf6e91f5cU, 0x22082a88U, 0x433073e9U, + 0x09eae3a3U, 0x177166bdU, 0xe8729a42U, 0xdecb1574U, + 0x8685032cU, 0xd781567dU, 0xc3905369U, 0x335c6f99U, + 0xefb75845U, 0x8d4fc227U, 0x5cebb7f6U, 0x8e8f0124U, + 0x8bca4121U, 0xb2bc0e18U, 0x7d83fed7U, 0x9a9e0430U, + 0x665d3bccU, 0xd84e9672U, 0x60d8b8caU, 0x5dabf6f7U, + 0xbeb30d14U, 0x467533ecU, 0xc050906aU, 0xc85a9262U, + 0xdf8b5475U, 0x3a162c90U, 0xcedf1164U, 0x87c5422dU, + 0x7cc3bfd6U, 0xd3845779U, 0x83c04329U, 0xb03c8c1aU, + 0x022022a8U, 0x9154c53bU, 0x23486b89U, 0x894ac323U, + 0x0b6a61a1U, 0xac278b06U, 0x8405812eU, 0xa6ad0b0cU, + 0x3c93af96U, 0x45b5f0efU, 0x31dced9bU, 0xb579cc1fU, + 0x5f2b74f5U, 0x671d7acdU, 0xd441957eU, 0x1dfbe6b7U, + 0x730c7fd9U, 0xffa35c55U, 0x321c2e98U, 0xb4398d1eU, + 0x04a5a1aeU, 0xf7a95e5dU, 0xa168c90bU, 0xc110d16bU, + 0xbd73ce17U, 0xb976cf13U, 0x659df8cfU, 0x4dbff2e7U, + 0x3e132d94U, 0x64ddb9ceU, 0xb6b90f1cU, 0x427032e8U, + 0xe6fd1b4cU, 0x7f037cd5U, 0xfae61c50U, 0xf529dc5fU, + 0x4cffb3e6U, 0x6f1778c5U, 0x7986ffd3U, 0x0defe2a7U, + 0x74c9bddeU, 0x48fab2e2U, 0x6198f9cbU, 0x6b1279c1U, + 0x2088a88aU, 0x0f6f60a5U, 0xcc5f9366U, 0x2a022880U, + 0x9e9b0534U, 0x3f536c95U, 0xe53dd84fU, 0xfee31d54U, + 0xbc338f16U, 0xd90ed773U, 0x4b3a71e1U, 0x40f0b0eaU, + 0xeaf21840U, 0x9fdb4435U, 0xdace1470U, 0xcada1060U, + 0x2e072984U, 0xad67ca07U, 0x566137fcU, 0x21c8e98bU, + 0x3896ae92U, 0x526436f8U, 0xd501d47fU, 0xf12cdd5bU, + 0x9d5bc637U, 0xeef71944U, 0xcf9f5065U, 0x2c87ab86U, + 0x1f7b64b5U, 0xb17ccd1bU, 0x137467b9U, 0x1a3e24b0U, + 0x68d2bac2U, 0xcb9a5161U, 0xfd23de57U, 0xbbf64d11U, + 0xe078984aU, 0x7b067dd1U, 0x3dd3ee97U, 0x880a8222U, + 0xed37da47U, 0xb3fc4f19U, 0x7589fcdfU, 0xf06c9c5aU, + 0x572176fdU, 0x274d6a8dU, 0xec779b46U, 0x29c2eb83U, + 0x93e774faU, 0x8ab933e3U, 0x6f244b06U, 0x336f5c5aU, + 0xfb956e92U, 0x4f0c4326U, 0x3ca09c55U, 0x1602147fU, + 0x9027b7f9U, 0x1207157bU, 0x982db5f1U, 0xc3a360aaU, + 0x68e18901U, 0x277e594eU, 0x78f58d11U, 0xdc78a4b5U, + 0x64ee8a0dU, 0x5592c73cU, 0xa29b39cbU, 0x11c7d678U, + 0x60eb8b09U, 0x322f1d5bU, 0xd87da5b1U, 0xc7a661aeU, + 0x626b090bU, 0xd93de4b0U, 0x8436b2edU, 0x50d78739U, + 0xed04e984U, 0xd2f725bbU, 0xd077a7b9U, 0xae943ac7U, + 0xba853fd3U, 0xc123e2a8U, 0x8979f0e0U, 0x1b4d5672U, + 0x8ebc32e7U, 0x773a4d1eU, 0xaa913bc3U, 0x21fbda48U, + 0x0496926dU, 0x996df4f0U, 0xe44eaa8dU, 0xc526e3acU, + 0x7f304f16U, 0xf79a6d9eU, 0x7a750f13U, 0x4183c228U, + 0x5b1d4632U, 0x0616106fU, 0xb805bdd1U, 0x6e640a07U, + 0xef846b86U, 0xe841a981U, 0x6b214a02U, 0x9ea836f7U, + 0xcae923a3U, 0xb7ca7ddeU, 0x9aad37f3U, 0x237b584aU, + 0x1dc8d574U, 0xf6da2c9fU, 0x34aa9e5dU, 0x5257053bU, + 0xd532e7bcU, 0xd472a6bdU, 0x5652043fU, 0x3b655e52U, + 0x0756516eU, 0x05d6d36cU, 0x9422b6fdU, 0x223b194bU, + 0xc6e620afU, 0xad54f9c4U, 0x38a59d51U, 0xac14b8c5U, + 0x5317443aU, 0xdef826b7U, 0xf51aef9cU, 0x6a610b03U, + 0x69a1c800U, 0x65aecb0cU, 0xceec22a7U, 0x0213116bU, + 0x0ddcd164U, 0x599dc430U, 0xa3db78caU, 0xe6ce288fU, + 0x2b715a42U, 0x672e490eU, 0xf45aae9dU, 0xe50eeb8cU, + 0x09d9d060U, 0x9167f6f8U, 0xbe803ed7U, 0x1c889475U, + 0xb00fbfd9U, 0x58dd8531U, 0xf05faf99U, 0xb14ffed8U, + 0x4586c32cU, 0xa951f8c0U, 0x8ffc73e6U, 0x4243012bU, + 0x5cd88435U, 0x40c38329U, 0x39e5dc50U, 0x24be9a4dU, + 0xcc6ca0a5U, 0x4ccc8025U, 0x29f1d840U, 0xd6f224bfU, + 0x9bed76f2U, 0xc869a1a1U, 0xd137e6b8U, 0x9562f7fcU, + 0xb68a3cdfU, 0x87f671eeU, 0x54d2863dU, 0x8173f2e8U, + 0xf915ec90U, 0x10879779U, 0xc063a3a9U, 0x5712453eU, + 0x4a490323U, 0xdbbd66b2U, 0xeb816a82U, 0xb28f3ddbU, + 0x632b480aU, 0x362a1c5fU, 0xe2cb298bU, 0x83f370eaU, + 0xc929e0a0U, 0xd7b265beU, 0x28b19941U, 0x1e081677U, + 0x4646002fU, 0x1742557eU, 0x0353506aU, 0xf39f6c9aU, + 0x2f745b46U, 0x4d8cc124U, 0x9c28b4f5U, 0x4e4c0227U, + 0x4b094222U, 0x727f0d1bU, 0xbd40fdd4U, 0x5a5d0733U, + 0xa69e38cfU, 0x188d9571U, 0xa01bbbc9U, 0x9d68f5f4U, + 0x7e700e17U, 0x86b630efU, 0x00939369U, 0x08999161U, + 0x1f485776U, 0xfad52f93U, 0x0e1c1267U, 0x4706412eU, + 0xbc00bcd5U, 0x1347547aU, 0x4303402aU, 0x70ff8f19U, + 0xc2e321abU, 0x5197c638U, 0xe38b688aU, 0x4989c020U, + 0xcba962a2U, 0x6ce48805U, 0x44c6822dU, 0x666e080fU, + 0xfc50ac95U, 0x8576f3ecU, 0xf11fee98U, 0x75bacf1cU, + 0x9fe877f6U, 0xa7de79ceU, 0x1482967dU, 0xdd38e5b4U, + 0xb3cf7cdaU, 0x3f605f56U, 0xf2df2d9bU, 0x74fa8e1dU, + 0xc466a2adU, 0x376a5d5eU, 0x61abca08U, 0x01d3d268U, + 0x7db0cd14U, 0x79b5cc10U, 0xa55efbccU, 0x8d7cf1e4U, + 0xfed02e97U, 0xa41ebacdU, 0x767a0c1fU, 0x82b331ebU, + 0x263e184fU, 0xbfc07fd6U, 0x3a251f53U, 0x35eadf5cU, + 0x8c3cb0e5U, 0xafd47bc6U, 0xb945fcd0U, 0xcd2ce1a4U, + 0xb40abeddU, 0x8839b1e1U, 0xa15bfac8U, 0xabd17ac2U, + 0xe04bab89U, 0xcfac63a6U, 0x0c9c9065U, 0xeac12b83U, + 0x5e580637U, 0xff906f96U, 0x25fedb4cU, 0x3e201e57U, + 0x7cf08c15U, 0x19cdd470U, 0x8bf972e2U, 0x8033b3e9U, + 0x2a311b43U, 0x5f184736U, 0x1a0d1773U, 0x0a191363U, + 0xeec42a87U, 0x6da4c904U, 0x96a234ffU, 0xe10bea88U, + 0xf855ad91U, 0x92a735fbU, 0x15c2d77cU, 0x31efde58U, + 0x5d98c534U, 0x2e341a47U, 0x0f5c5366U, 0xec44a885U, + 0xdfb867b6U, 0x71bfce18U, 0xd3b764baU, 0xdafd27b3U, + 0xa811b9c1U, 0x0b595262U, 0x3de0dd54U, 0x7b354e12U, + 0x20bb9b49U, 0xbbc57ed2U, 0xfd10ed94U, 0x48c98121U, + 0x2df4d944U, 0x733f4c1aU, 0xb54affdcU, 0x30af9f59U, + 0x97e275feU, 0xe78e698eU, 0x2cb49845U, 0xe901e880U, + 0x9ce478f6U, 0x85ba3fefU, 0x6027470aU, 0x3c6c5056U, + 0xf496629eU, 0x400f4f2aU, 0x33a39059U, 0x19011873U, + 0x9f24bbf5U, 0x1d041977U, 0x972eb9fdU, 0xcca06ca6U, + 0x67e2850dU, 0x287d5542U, 0x77f6811dU, 0xd37ba8b9U, + 0x6bed8601U, 0x5a91cb30U, 0xad9835c7U, 0x1ec4da74U, + 0x6fe88705U, 0x3d2c1157U, 0xd77ea9bdU, 0xc8a56da2U, + 0x6d680507U, 0xd63ee8bcU, 0x8b35bee1U, 0x5fd48b35U, + 0xe207e588U, 0xddf429b7U, 0xdf74abb5U, 0xa19736cbU, + 0xb58633dfU, 0xce20eea4U, 0x867afcecU, 0x144e5a7eU, + 0x81bf3eebU, 0x78394112U, 0xa59237cfU, 0x2ef8d644U, + 0x0b959e61U, 0x966ef8fcU, 0xeb4da681U, 0xca25efa0U, + 0x7033431aU, 0xf8996192U, 0x7576031fU, 0x4e80ce24U, + 0x541e4a3eU, 0x09151c63U, 0xb706b1ddU, 0x6167060bU, + 0xe087678aU, 0xe742a58dU, 0x6422460eU, 0x91ab3afbU, + 0xc5ea2fafU, 0xb8c971d2U, 0x95ae3bffU, 0x2c785446U, + 0x12cbd978U, 0xf9d92093U, 0x3ba99251U, 0x5d540937U, + 0xda31ebb0U, 0xdb71aab1U, 0x59510833U, 0x3466525eU, + 0x08555d62U, 0x0ad5df60U, 0x9b21baf1U, 0x2d381547U, + 0xc9e52ca3U, 0xa257f5c8U, 0x37a6915dU, 0xa317b4c9U, + 0x5c144836U, 0xd1fb2abbU, 0xfa19e390U, 0x6562070fU, + 0x66a2c40cU, 0x6aadc700U, 0xc1ef2eabU, 0x0d101d67U, + 0x02dfdd68U, 0x569ec83cU, 0xacd874c6U, 0xe9cd2483U, + 0x2472564eU, 0x682d4502U, 0xfb59a291U, 0xea0de780U, + 0x06dadc6cU, 0x9e64faf4U, 0xb18332dbU, 0x138b9879U, + 0xbf0cb3d5U, 0x57de893dU, 0xff5ca395U, 0xbe4cf2d4U, + 0x4a85cf20U, 0xa652f4ccU, 0x80ff7feaU, 0x4d400d27U, + 0x53db8839U, 0x4fc08f25U, 0x36e6d05cU, 0x2bbd9641U, + 0xc36faca9U, 0x43cf8c29U, 0x26f2d44cU, 0xd9f128b3U, + 0x94ee7afeU, 0xc76aadadU, 0xde34eab4U, 0x9a61fbf0U, + 0xb98930d3U, 0x88f57de2U, 0x5bd18a31U, 0x8e70fee4U, + 0xf616e09cU, 0x1f849b75U, 0xcf60afa5U, 0x58114932U, + 0x454a0f2fU, 0xd4be6abeU, 0xe482668eU, 0xbd8c31d7U, + 0x6c284406U, 0x39291053U, 0xedc82587U, 0x8cf07ce6U, + 0xc62aecacU, 0xd8b169b2U, 0x27b2954dU, 0x110b1a7bU, + 0x49450c23U, 0x18415972U, 0x0c505c66U, 0xfc9c6096U, + 0x2077574aU, 0x428fcd28U, 0x932bb8f9U, 0x414f0e2bU, + 0x440a4e2eU, 0x7d7c0117U, 0xb243f1d8U, 0x555e0b3fU, + 0xa99d34c3U, 0x178e997dU, 0xaf18b7c5U, 0x926bf9f8U, + 0x7173021bU, 0x89b53ce3U, 0x0f909f65U, 0x079a9d6dU, + 0x104b5b7aU, 0xf5d6239fU, 0x011f1e6bU, 0x48054d22U, + 0xb303b0d9U, 0x1c445876U, 0x4c004c26U, 0x7ffc8315U, + 0xcde02da7U, 0x5e94ca34U, 0xec886486U, 0x468acc2cU, + 0xc4aa6eaeU, 0x63e78409U, 0x4bc58e21U, 0x696d0403U, + 0xf353a099U, 0x8a75ffe0U, 0xfe1ce294U, 0x7ab9c310U, + 0x90eb7bfaU, 0xa8dd75c2U, 0x1b819a71U, 0xd23be9b8U, + 0xbccc70d6U, 0x3063535aU, 0xfddc2197U, 0x7bf98211U, + 0xcb65aea1U, 0x38695152U, 0x6ea8c604U, 0x0ed0de64U, + 0x72b3c118U, 0x76b6c01cU, 0xaa5df7c0U, 0x827ffde8U, + 0xf1d3229bU, 0xab1db6c1U, 0x79790013U, 0x8db03de7U, + 0x293d1443U, 0xb0c373daU, 0x3526135fU, 0x3ae9d350U, + 0x833fbce9U, 0xa0d777caU, 0xb646f0dcU, 0xc22feda8U, + 0xbb09b2d1U, 0x873abdedU, 0xae58f6c4U, 0xa4d276ceU, + 0xef48a785U, 0xc0af6faaU, 0x039f9c69U, 0xe5c2278fU, + 0x515b0a3bU, 0xf093639aU, 0x2afdd740U, 0x3123125bU, + 0x73f38019U, 0x16ced87cU, 0x84fa7eeeU, 0x8f30bfe5U, + 0x2532174fU, 0x501b4b3aU, 0x150e1b7fU, 0x051a1f6fU, + 0xe1c7268bU, 0x62a7c508U, 0x99a138f3U, 0xee08e684U, + 0xf756a19dU, 0x9da439f7U, 0x1ac1db70U, 0x3eecd254U, + 0x529bc938U, 0x2137164bU, 0x005f5f6aU, 0xe347a489U, + 0xd0bb6bbaU, 0x7ebcc214U, 0xdcb468b6U, 0xd5fe2bbfU, + 0xa712b5cdU, 0x045a5e6eU, 0x32e3d158U, 0x7436421eU, + 0x2fb89745U, 0xb4c672deU, 0xf213e198U, 0x47ca8d2dU, + 0x22f7d548U, 0x7c3c4016U, 0xba49f3d0U, 0x3fac9355U, + 0x98e179f2U, 0xe88d6582U, 0x23b79449U, 0xe602e48cU, + 0xde0dd35dU, 0xc7539444U, 0x22ceeca1U, 0x7e85fbfdU, + 0xb67fc935U, 0x02e6e481U, 0x714a3bf2U, 0x5be8b3d8U, + 0xddcd105eU, 0x5fedb2dcU, 0xd5c71256U, 0x8e49c70dU, + 0x250b2ea6U, 0x6a94fee9U, 0x351f2ab6U, 0x91920312U, + 0x29042daaU, 0x1878609bU, 0xef719e6cU, 0x5c2d71dfU, + 0x2d012caeU, 0x7fc5bafcU, 0x95970216U, 0x8a4cc609U, + 0x2f81aeacU, 0x94d74317U, 0xc9dc154aU, 0x1d3d209eU, + 0xa0ee4e23U, 0x9f1d821cU, 0x9d9d001eU, 0xe37e9d60U, + 0xf76f9874U, 0x8cc9450fU, 0xc4935747U, 0x56a7f1d5U, + 0xc3569540U, 0x3ad0eab9U, 0xe77b9c64U, 0x6c117defU, + 0x497c35caU, 0xd4875357U, 0xa9a40d2aU, 0x88cc440bU, + 0x32dae8b1U, 0xba70ca39U, 0x379fa8b4U, 0x0c69658fU, + 0x16f7e195U, 0x4bfcb7c8U, 0xf5ef1a76U, 0x238eada0U, + 0xa26ecc21U, 0xa5ab0e26U, 0x26cbeda5U, 0xd3429150U, + 0x87038404U, 0xfa20da79U, 0xd7479054U, 0x6e91ffedU, + 0x502272d3U, 0xbb308b38U, 0x794039faU, 0x1fbda29cU, + 0x98d8401bU, 0x9998011aU, 0x1bb8a398U, 0x768ff9f5U, + 0x4abcf6c9U, 0x483c74cbU, 0xd9c8115aU, 0x6fd1beecU, + 0x8b0c8708U, 0xe0be5e63U, 0x754f3af6U, 0xe1fe1f62U, + 0x1efde39dU, 0x93128110U, 0xb8f0483bU, 0x278baca4U, + 0x244b6fa7U, 0x28446cabU, 0x83068500U, 0x4ff9b6ccU, + 0x403676c3U, 0x14776397U, 0xee31df6dU, 0xab248f28U, + 0x669bfde5U, 0x2ac4eea9U, 0xb9b0093aU, 0xa8e44c2bU, + 0x443377c7U, 0xdc8d515fU, 0xf36a9970U, 0x516233d2U, + 0xfde5187eU, 0x15372296U, 0xbdb5083eU, 0xfca5597fU, + 0x086c648bU, 0xe4bb5f67U, 0xc216d441U, 0x0fa9a68cU, + 0x11322392U, 0x0d29248eU, 0x740f7bf7U, 0x69543deaU, + 0x81860702U, 0x01262782U, 0x641b7fe7U, 0x9b188318U, + 0xd607d155U, 0x85830606U, 0x9cdd411fU, 0xd888505bU, + 0xfb609b78U, 0xca1cd649U, 0x1938219aU, 0xcc99554fU, + 0xb4ff4b37U, 0x5d6d30deU, 0x8d89040eU, 0x1af8e299U, + 0x07a3a484U, 0x9657c115U, 0xa66bcd25U, 0xff659a7cU, + 0x2ec1efadU, 0x7bc0bbf8U, 0xaf218e2cU, 0xce19d74dU, + 0x84c34707U, 0x9a58c219U, 0x655b3ee6U, 0x53e2b1d0U, + 0x0baca788U, 0x5aa8f2d9U, 0x4eb9f7cdU, 0xbe75cb3dU, + 0x629efce1U, 0x00666683U, 0xd1c21352U, 0x03a6a580U, + 0x06e3e585U, 0x3f95aabcU, 0xf0aa5a73U, 0x17b7a094U, + 0xeb749f68U, 0x556732d6U, 0xedf11c6eU, 0xd0825253U, + 0x339aa9b0U, 0xcb5c9748U, 0x4d7934ceU, 0x457336c6U, + 0x52a2f0d1U, 0xb73f8834U, 0x43f6b5c0U, 0x0aece689U, + 0xf1ea1b72U, 0x5eadf3ddU, 0x0ee9e78dU, 0x3d1528beU, + 0x8f09860cU, 0x1c7d619fU, 0xae61cf2dU, 0x04636787U, + 0x8643c505U, 0x210e2fa2U, 0x092c258aU, 0x2b84afa8U, + 0xb1ba0b32U, 0xc89c544bU, 0xbcf5493fU, 0x385068bbU, + 0xd202d051U, 0xea34de69U, 0x596831daU, 0x90d24213U, + 0xfe25db7dU, 0x728af8f1U, 0xbf358a3cU, 0x391029baU, + 0x898c050aU, 0x7a80faf9U, 0x2c416dafU, 0x4c3975cfU, + 0x305a6ab3U, 0x345f6bb7U, 0xe8b45c6bU, 0xc0965643U, + 0xb33a8930U, 0xe9f41d6aU, 0x3b90abb8U, 0xcf59964cU, + 0x6bd4bfe8U, 0xf22ad871U, 0x77cfb8f4U, 0x780078fbU, + 0xc1d61742U, 0xe23edc61U, 0xf4af5b77U, 0x80c64603U, + 0xf9e0197aU, 0xc5d31646U, 0xecb15d6fU, 0xe63bdd65U, + 0xada10c2eU, 0x8246c401U, 0x417637c2U, 0xa72b8c24U, + 0x13b2a190U, 0xb27ac831U, 0x68147cebU, 0x73cab9f0U, + 0x311a2bb2U, 0x542773d7U, 0xc613d545U, 0xcdd9144eU, + 0x67dbbce4U, 0x12f2e091U, 0x57e7b0d4U, 0x47f3b4c4U, + 0xa32e8d20U, 0x204e6ea3U, 0xdb489358U, 0xace14d2fU, + 0xb5bf0a36U, 0xdf4d925cU, 0x582870dbU, 0x7c0579ffU, + 0x10726293U, 0x63debde0U, 0x42b6f4c1U, 0xa1ae0f22U, + 0x9252c011U, 0x3c5569bfU, 0x9e5dc31dU, 0x97178014U, + 0xe5fb1e66U, 0x46b3f5c5U, 0x700a7af3U, 0x36dfe9b5U, + 0x6d513ceeU, 0xf62fd975U, 0xb0fa4a33U, 0x05232686U, + 0x601e7ee3U, 0x3ed5ebbdU, 0xf8a0587bU, 0x7d4538feU, + 0xda08d259U, 0xaa64ce29U, 0x615e3fe2U, 0xa4eb4f27U, + 0x213e1f91U, 0x38605888U, 0xddfd206dU, 0x81b63731U, + 0x494c05f9U, 0xfdd5284dU, 0x8e79f73eU, 0xa4db7f14U, + 0x22fedc92U, 0xa0de7e10U, 0x2af4de9aU, 0x717a0bc1U, + 0xda38e26aU, 0x95a73225U, 0xca2ce67aU, 0x6ea1cfdeU, + 0xd637e166U, 0xe74bac57U, 0x104252a0U, 0xa31ebd13U, + 0xd232e062U, 0x80f67630U, 0x6aa4cedaU, 0x757f0ac5U, + 0xd0b26260U, 0x6be48fdbU, 0x36efd986U, 0xe20eec52U, + 0x5fdd82efU, 0x602e4ed0U, 0x62aeccd2U, 0x1c4d51acU, + 0x085c54b8U, 0x73fa89c3U, 0x3ba09b8bU, 0xa9943d19U, + 0x3c65598cU, 0xc5e32675U, 0x184850a8U, 0x9322b123U, + 0xb64ff906U, 0x2bb49f9bU, 0x5697c1e6U, 0x77ff88c7U, + 0xcde9247dU, 0x454306f5U, 0xc8ac6478U, 0xf35aa943U, + 0xe9c42d59U, 0xb4cf7b04U, 0x0adcd6baU, 0xdcbd616cU, + 0x5d5d00edU, 0x5a98c2eaU, 0xd9f82169U, 0x2c715d9cU, + 0x783048c8U, 0x051316b5U, 0x28745c98U, 0x91a23321U, + 0xaf11be1fU, 0x440347f4U, 0x8673f536U, 0xe08e6e50U, + 0x67eb8cd7U, 0x66abcdd6U, 0xe48b6f54U, 0x89bc3539U, + 0xb58f3a05U, 0xb70fb807U, 0x26fbdd96U, 0x90e27220U, + 0x743f4bc4U, 0x1f8d92afU, 0x8a7cf63aU, 0x1ecdd3aeU, + 0xe1ce2f51U, 0x6c214ddcU, 0x47c384f7U, 0xd8b86068U, + 0xdb78a36bU, 0xd777a067U, 0x7c3549ccU, 0xb0ca7a00U, + 0xbf05ba0fU, 0xeb44af5bU, 0x110213a1U, 0x541743e4U, + 0x99a83129U, 0xd5f72265U, 0x4683c5f6U, 0x57d780e7U, + 0xbb00bb0bU, 0x23be9d93U, 0x0c5955bcU, 0xae51ff1eU, + 0x02d6d4b2U, 0xea04ee5aU, 0x4286c4f2U, 0x039695b3U, + 0xf75fa847U, 0x1b8893abU, 0x3d25188dU, 0xf09a6a40U, + 0xee01ef5eU, 0xf21ae842U, 0x8b3cb73bU, 0x9667f126U, + 0x7eb5cbceU, 0xfe15eb4eU, 0x9b28b32bU, 0x642b4fd4U, + 0x29341d99U, 0x7ab0cacaU, 0x63ee8dd3U, 0x27bb9c97U, + 0x045357b4U, 0x352f1a85U, 0xe60bed56U, 0x33aa9983U, + 0x4bcc87fbU, 0xa25efc12U, 0x72bac8c2U, 0xe5cb2e55U, + 0xf8906848U, 0x69640dd9U, 0x595801e9U, 0x005656b0U, + 0xd1f22361U, 0x84f37734U, 0x501242e0U, 0x312a1b81U, + 0x7bf08bcbU, 0x656b0ed5U, 0x9a68f22aU, 0xacd17d1cU, + 0xf49f6b44U, 0xa59b3e15U, 0xb18a3b01U, 0x414607f1U, + 0x9dad302dU, 0xff55aa4fU, 0x2ef1df9eU, 0xfc95694cU, + 0xf9d02949U, 0xc0a66670U, 0x0f9996bfU, 0xe8846c58U, + 0x144753a4U, 0xaa54fe1aU, 0x12c2d0a2U, 0x2fb19e9fU, + 0xcca9657cU, 0x346f5b84U, 0xb24af802U, 0xba40fa0aU, + 0xad913c1dU, 0x480c44f8U, 0xbcc5790cU, 0xf5df2a45U, + 0x0ed9d7beU, 0xa19e3f11U, 0xf1da2b41U, 0xc226e472U, + 0x703a4ac0U, 0xe34ead53U, 0x515203e1U, 0xfb50ab4bU, + 0x797009c9U, 0xde3de36eU, 0xf61fe946U, 0xd4b76364U, + 0x4e89c7feU, 0x37af9887U, 0x43c685f3U, 0xc763a477U, + 0x2d311c9dU, 0x150712a5U, 0xa65bfd16U, 0x6fe18edfU, + 0x011617b1U, 0x8db9343dU, 0x400646f0U, 0xc623e576U, + 0x76bfc9c6U, 0x85b33635U, 0xd372a163U, 0xb30ab903U, + 0xcf69a67fU, 0xcb6ca77bU, 0x178790a7U, 0x3fa59a8fU, + 0x4c0945fcU, 0x16c7d1a6U, 0xc4a36774U, 0x306a5a80U, + 0x94e77324U, 0x0d1914bdU, 0x88fc7438U, 0x8733b437U, + 0x3ee5db8eU, 0x1d0d10adU, 0x0b9c97bbU, 0x7ff58acfU, + 0x06d3d5b6U, 0x3ae0da8aU, 0x138291a3U, 0x190811a9U, + 0x5292c0e2U, 0x7d7508cdU, 0xbe45fb0eU, 0x581840e8U, + 0xec816d5cU, 0x4d4904fdU, 0x9727b027U, 0x8cf9753cU, + 0xce29e77eU, 0xab14bf1bU, 0x39201989U, 0x32ead882U, + 0x98e87028U, 0xedc12c5dU, 0xa8d47c18U, 0xb8c07808U, + 0x5c1d41ecU, 0xdf7da26fU, 0x247b5f94U, 0x53d281e3U, + 0x4a8cc6faU, 0x207e5e90U, 0xa71bbc17U, 0x8336b533U, + 0xef41ae5fU, 0x9ced712cU, 0xbd85380dU, 0x5e9dc3eeU, + 0x6d610cddU, 0xc366a573U, 0x616e0fd1U, 0x68244cd8U, + 0x1ac8d2aaU, 0xb9803909U, 0x8f39b63fU, 0xc9ec2579U, + 0x9262f022U, 0x091c15b9U, 0x4fc986ffU, 0xfa10ea4aU, + 0x9f2db22fU, 0xc1e62771U, 0x079394b7U, 0x8276f432U, + 0x253b1e95U, 0x555702e5U, 0x9e6df32eU, 0x5bd883ebU, + 0xeefe109eU, 0xf7a05787U, 0x123d2f62U, 0x4e76383eU, + 0x868c0af6U, 0x32152742U, 0x41b9f831U, 0x6b1b701bU, + 0xed3ed39dU, 0x6f1e711fU, 0xe534d195U, 0xbeba04ceU, + 0x15f8ed65U, 0x5a673d2aU, 0x05ece975U, 0xa161c0d1U, + 0x19f7ee69U, 0x288ba358U, 0xdf825dafU, 0x6cdeb21cU, + 0x1df2ef6dU, 0x4f36793fU, 0xa564c1d5U, 0xbabf05caU, + 0x1f726d6fU, 0xa42480d4U, 0xf92fd689U, 0x2dcee35dU, + 0x901d8de0U, 0xafee41dfU, 0xad6ec3ddU, 0xd38d5ea3U, + 0xc79c5bb7U, 0xbc3a86ccU, 0xf4609484U, 0x66543216U, + 0xf3a55683U, 0x0a23297aU, 0xd7885fa7U, 0x5ce2be2cU, + 0x798ff609U, 0xe4749094U, 0x9957cee9U, 0xb83f87c8U, + 0x02292b72U, 0x8a8309faU, 0x076c6b77U, 0x3c9aa64cU, + 0x26042256U, 0x7b0f740bU, 0xc51cd9b5U, 0x137d6e63U, + 0x929d0fe2U, 0x9558cde5U, 0x16382e66U, 0xe3b15293U, + 0xb7f047c7U, 0xcad319baU, 0xe7b45397U, 0x5e623c2eU, + 0x60d1b110U, 0x8bc348fbU, 0x49b3fa39U, 0x2f4e615fU, + 0xa82b83d8U, 0xa96bc2d9U, 0x2b4b605bU, 0x467c3a36U, + 0x7a4f350aU, 0x78cfb708U, 0xe93bd299U, 0x5f227d2fU, + 0xbbff44cbU, 0xd04d9da0U, 0x45bcf935U, 0xd10ddca1U, + 0x2e0e205eU, 0xa3e142d3U, 0x88038bf8U, 0x17786f67U, + 0x14b8ac64U, 0x18b7af68U, 0xb3f546c3U, 0x7f0a750fU, + 0x70c5b500U, 0x2484a054U, 0xdec21caeU, 0x9bd74cebU, + 0x56683e26U, 0x1a372d6aU, 0x8943caf9U, 0x98178fe8U, + 0x74c0b404U, 0xec7e929cU, 0xc3995ab3U, 0x6191f011U, + 0xcd16dbbdU, 0x25c4e155U, 0x8d46cbfdU, 0xcc569abcU, + 0x389fa748U, 0xd4489ca4U, 0xf2e51782U, 0x3f5a654fU, + 0x21c1e051U, 0x3ddae74dU, 0x44fcb834U, 0x59a7fe29U, + 0xb175c4c1U, 0x31d5e441U, 0x54e8bc24U, 0xabeb40dbU, + 0xe6f41296U, 0xb570c5c5U, 0xac2e82dcU, 0xe87b9398U, + 0xcb9358bbU, 0xfaef158aU, 0x29cbe259U, 0xfc6a968cU, + 0x840c88f4U, 0x6d9ef31dU, 0xbd7ac7cdU, 0x2a0b215aU, + 0x37506747U, 0xa6a402d6U, 0x96980ee6U, 0xcf9659bfU, + 0x1e322c6eU, 0x4b33783bU, 0x9fd24defU, 0xfeea148eU, + 0xb43084c4U, 0xaaab01daU, 0x55a8fd25U, 0x63117213U, + 0x3b5f644bU, 0x6a5b311aU, 0x7e4a340eU, 0x8e8608feU, + 0x526d3f22U, 0x3095a540U, 0xe131d091U, 0x33556643U, + 0x36102646U, 0x0f66697fU, 0xc05999b0U, 0x27446357U, + 0xdb875cabU, 0x6594f115U, 0xdd02dfadU, 0xe0719190U, + 0x03696a73U, 0xfbaf548bU, 0x7d8af70dU, 0x7580f505U, + 0x62513312U, 0x87cc4bf7U, 0x73057603U, 0x3a1f254aU, + 0xc119d8b1U, 0x6e5e301eU, 0x3e1a244eU, 0x0de6eb7dU, + 0xbffa45cfU, 0x2c8ea25cU, 0x9e920ceeU, 0x3490a444U, + 0xb6b006c6U, 0x11fdec61U, 0x39dfe649U, 0x1b776c6bU, + 0x8149c8f1U, 0xf86f9788U, 0x8c068afcU, 0x08a3ab78U, + 0xe2f11392U, 0xdac71daaU, 0x699bf219U, 0xa02181d0U, + 0xced618beU, 0x42793b32U, 0x8fc649ffU, 0x09e3ea79U, + 0xb97fc6c9U, 0x4a73393aU, 0x1cb2ae6cU, 0x7ccab60cU, + 0x00a9a970U, 0x04aca874U, 0xd8479fa8U, 0xf0659580U, + 0x83c94af3U, 0xd907dea9U, 0x0b63687bU, 0xffaa558fU, + 0x5b277c2bU, 0xc2d91bb2U, 0x473c7b37U, 0x48f3bb38U, + 0xf125d481U, 0xd2cd1fa2U, 0xc45c98b4U, 0xb03585c0U, + 0xc913dab9U, 0xf520d585U, 0xdc429eacU, 0xd6c81ea6U, + 0x9d52cfedU, 0xb2b507c2U, 0x7185f401U, 0x97d84fe7U, + 0x23416253U, 0x82890bf2U, 0x58e7bf28U, 0x43397a33U, + 0x01e9e871U, 0x64d4b014U, 0xf6e01686U, 0xfd2ad78dU, + 0x57287f27U, 0x22012352U, 0x67147317U, 0x77007707U, + 0x93dd4ee3U, 0x10bdad60U, 0xebbb509bU, 0x9c128eecU, + 0x854cc9f5U, 0xefbe519fU, 0x68dbb318U, 0x4cf6ba3cU, + 0x2081a150U, 0x532d7e23U, 0x72453702U, 0x915dcce1U, + 0xa2a103d2U, 0x0ca6aa7cU, 0xaeae00deU, 0xa7e443d7U, + 0xd508dda5U, 0x76403606U, 0x40f9b930U, 0x062c2a76U, + 0x5da2ff2dU, 0xc6dc1ab6U, 0x800989f0U, 0x35d0e545U, + 0x50edbd20U, 0x0e26287eU, 0xc8539bb8U, 0x4db6fb3dU, + 0xeafb119aU, 0x9a970deaU, 0x51adfc21U, 0x94188ce4U, + 0xafeb44caU, 0xb6b503d3U, 0x53287b36U, 0x0f636c6aU, + 0xc7995ea2U, 0x73007316U, 0x00acac65U, 0x2a0e244fU, + 0xac2b87c9U, 0x2e0b254bU, 0xa42185c1U, 0xffaf509aU, + 0x54edb931U, 0x1b72697eU, 0x44f9bd21U, 0xe0749485U, + 0x58e2ba3dU, 0x699ef70cU, 0x9e9709fbU, 0x2dcbe648U, + 0x5ce7bb39U, 0x0e232d6bU, 0xe4719581U, 0xfbaa519eU, + 0x5e67393bU, 0xe531d480U, 0xb83a82ddU, 0x6cdbb709U, + 0xd108d9b4U, 0xeefb158bU, 0xec7b9789U, 0x92980af7U, + 0x86890fe3U, 0xfd2fd298U, 0xb575c0d0U, 0x27416642U, + 0xb2b002d7U, 0x4b367d2eU, 0x969d0bf3U, 0x1df7ea78U, + 0x389aa25dU, 0xa561c4c0U, 0xd8429abdU, 0xf92ad39cU, + 0x433c7f26U, 0xcb965daeU, 0x46793f23U, 0x7d8ff218U, + 0x67117602U, 0x3a1a205fU, 0x84098de1U, 0x52683a37U, + 0xd3885bb6U, 0xd44d99b1U, 0x572d7a32U, 0xa2a406c7U, + 0xf6e51393U, 0x8bc64deeU, 0xa6a107c3U, 0x1f77687aU, + 0x21c4e544U, 0xcad61cafU, 0x08a6ae6dU, 0x6e5b350bU, + 0xe93ed78cU, 0xe87e968dU, 0x6a5e340fU, 0x07696e62U, + 0x3b5a615eU, 0x39dae35cU, 0xa82e86cdU, 0x1e37297bU, + 0xfaea109fU, 0x9158c9f4U, 0x04a9ad61U, 0x901888f5U, + 0x6f1b740aU, 0xe2f41687U, 0xc916dfacU, 0x566d3b33U, + 0x55adf830U, 0x59a2fb3cU, 0xf2e01297U, 0x3e1f215bU, + 0x31d0e154U, 0x6591f400U, 0x9fd748faU, 0xdac218bfU, + 0x177d6a72U, 0x5b22793eU, 0xc8569eadU, 0xd902dbbcU, + 0x35d5e050U, 0xad6bc6c8U, 0x828c0ee7U, 0x2084a445U, + 0x8c038fe9U, 0x64d1b501U, 0xcc539fa9U, 0x8d43cee8U, + 0x798af31cU, 0x955dc8f0U, 0xb3f043d6U, 0x7e4f311bU, + 0x60d4b405U, 0x7ccfb319U, 0x05e9ec60U, 0x18b2aa7dU, + 0xf0609095U, 0x70c0b015U, 0x15fde870U, 0xeafe148fU, + 0xa7e146c2U, 0xf4659191U, 0xed3bd688U, 0xa96ec7ccU, + 0x8a860cefU, 0xbbfa41deU, 0x68deb60dU, 0xbd7fc2d8U, + 0xc519dca0U, 0x2c8ba749U, 0xfc6f9399U, 0x6b1e750eU, + 0x76453313U, 0xe7b15682U, 0xd78d5ab2U, 0x8e830debU, + 0x5f27783aU, 0x0a262c6fU, 0xdec719bbU, 0xbfff40daU, + 0xf525d090U, 0xebbe558eU, 0x14bda971U, 0x22042647U, + 0x7a4a301fU, 0x2b4e654eU, 0x3f5f605aU, 0xcf935caaU, + 0x13786b76U, 0x7180f114U, 0xa02484c5U, 0x72403217U, + 0x77057212U, 0x4e733d2bU, 0x814ccde4U, 0x66513703U, + 0x9a9208ffU, 0x2481a541U, 0x9c178bf9U, 0xa164c5c4U, + 0x427c3e27U, 0xbaba00dfU, 0x3c9fa359U, 0x3495a151U, + 0x23446746U, 0xc6d91fa3U, 0x32102257U, 0x7b0a711eU, + 0x800c8ce5U, 0x2f4b644aU, 0x7f0f701aU, 0x4cf3bf29U, + 0xfeef119bU, 0x6d9bf608U, 0xdf8758baU, 0x7585f010U, + 0xf7a55292U, 0x50e8b835U, 0x78cab21dU, 0x5a62383fU, + 0xc05c9ca5U, 0xb97ac3dcU, 0xcd13dea8U, 0x49b6ff2cU, + 0xa3e447c6U, 0x9bd249feU, 0x288ea64dU, 0xe134d584U, + 0x8fc34ceaU, 0x036c6f66U, 0xced31dabU, 0x48f6be2dU, + 0xf86a929dU, 0x0b666d6eU, 0x5da7fa38U, 0x3ddfe258U, + 0x41bcfd24U, 0x45b9fc20U, 0x9952cbfcU, 0xb170c1d4U, + 0xc2dc1ea7U, 0x98128afdU, 0x4a763c2fU, 0xbebf01dbU, + 0x1a32287fU, 0x83cc4fe6U, 0x06292f63U, 0x09e6ef6cU, + 0xb03080d5U, 0x93d84bf6U, 0x8549cce0U, 0xf120d194U, + 0x88068eedU, 0xb43581d1U, 0x9d57caf8U, 0x97dd4af2U, + 0xdc479bb9U, 0xf3a05396U, 0x3090a055U, 0xd6cd1bb3U, + 0x62543607U, 0xc39c5fa6U, 0x19f2eb7cU, 0x022c2e67U, + 0x40fcbc25U, 0x25c1e440U, 0xb7f542d2U, 0xbc3f83d9U, + 0x163d2b73U, 0x63147706U, 0x26012743U, 0x36152353U, + 0xd2c81ab7U, 0x51a8f934U, 0xaaae04cfU, 0xdd07dab8U, + 0xc4599da1U, 0xaeab05cbU, 0x29cee74cU, 0x0de3ee68U, + 0x6194f504U, 0x12382a77U, 0x33506356U, 0xd04898b5U, + 0xe3b45786U, 0x4db3fe28U, 0xefbb548aU, 0xe6f11783U, + 0x941d89f1U, 0x37556252U, 0x01eced64U, 0x47397e22U, + 0x1cb7ab79U, 0x87c94ee2U, 0xc11cdda4U, 0x74c5b111U, + 0x11f8e974U, 0x4f337c2aU, 0x8946cfecU, 0x0ca3af69U, + 0xabee45ceU, 0xdb8259beU, 0x10b8a875U, 0xd50dd8b0U, + 0xe957be30U, 0xf009f929U, 0x159481ccU, 0x49df9690U, + 0x8125a458U, 0x35bc89ecU, 0x4610569fU, 0x6cb2deb5U, + 0xea977d33U, 0x68b7dfb1U, 0xe29d7f3bU, 0xb913aa60U, + 0x125143cbU, 0x5dce9384U, 0x024547dbU, 0xa6c86e7fU, + 0x1e5e40c7U, 0x2f220df6U, 0xd82bf301U, 0x6b771cb2U, + 0x1a5b41c3U, 0x489fd791U, 0xa2cd6f7bU, 0xbd16ab64U, + 0x18dbc3c1U, 0xa38d2e7aU, 0xfe867827U, 0x2a674df3U, + 0x97b4234eU, 0xa847ef71U, 0xaac76d73U, 0xd424f00dU, + 0xc035f519U, 0xbb932862U, 0xf3c93a2aU, 0x61fd9cb8U, + 0xf40cf82dU, 0x0d8a87d4U, 0xd021f109U, 0x5b4b1082U, + 0x7e2658a7U, 0xe3dd3e3aU, 0x9efe6047U, 0xbf962966U, + 0x058085dcU, 0x8d2aa754U, 0x00c5c5d9U, 0x3b3308e2U, + 0x21ad8cf8U, 0x7ca6daa5U, 0xc2b5771bU, 0x14d4c0cdU, + 0x9534a14cU, 0x92f1634bU, 0x119180c8U, 0xe418fc3dU, + 0xb059e969U, 0xcd7ab714U, 0xe01dfd39U, 0x59cb9280U, + 0x67781fbeU, 0x8c6ae655U, 0x4e1a5497U, 0x28e7cff1U, + 0xaf822d76U, 0xaec26c77U, 0x2ce2cef5U, 0x41d59498U, + 0x7de69ba4U, 0x7f6619a6U, 0xee927c37U, 0x588bd381U, + 0xbc56ea65U, 0xd7e4330eU, 0x4215579bU, 0xd6a4720fU, + 0x29a78ef0U, 0xa448ec7dU, 0x8faa2556U, 0x10d1c1c9U, + 0x131102caU, 0x1f1e01c6U, 0xb45ce86dU, 0x78a3dba1U, + 0x776c1baeU, 0x232d0efaU, 0xd96bb200U, 0x9c7ee245U, + 0x51c19088U, 0x1d9e83c4U, 0x8eea6457U, 0x9fbe2146U, + 0x73691aaaU, 0xebd73c32U, 0xc430f41dU, 0x66385ebfU, + 0xcabf7513U, 0x226d4ffbU, 0x8aef6553U, 0xcbff3412U, + 0x3f3609e6U, 0xd3e1320aU, 0xf54cb92cU, 0x38f3cbe1U, + 0x26684effU, 0x3a7349e3U, 0x4355169aU, 0x5e0e5087U, + 0xb6dc6a6fU, 0x367c4aefU, 0x5341128aU, 0xac42ee75U, + 0xe15dbc38U, 0xb2d96b6bU, 0xab872c72U, 0xefd23d36U, + 0xcc3af615U, 0xfd46bb24U, 0x2e624cf7U, 0xfbc33822U, + 0x83a5265aU, 0x6a375db3U, 0xbad36963U, 0x2da28ff4U, + 0x30f9c9e9U, 0xa10dac78U, 0x9131a048U, 0xc83ff711U, + 0x199b82c0U, 0x4c9ad695U, 0x987be341U, 0xf943ba20U, + 0xb3992a6aU, 0xad02af74U, 0x5201538bU, 0x64b8dcbdU, + 0x3cf6cae5U, 0x6df29fb4U, 0x79e39aa0U, 0x892fa650U, + 0x55c4918cU, 0x373c0beeU, 0xe6987e3fU, 0x34fcc8edU, + 0x31b988e8U, 0x08cfc7d1U, 0xc7f0371eU, 0x20edcdf9U, + 0xdc2ef205U, 0x623d5fbbU, 0xdaab7103U, 0xe7d83f3eU, + 0x04c0c4ddU, 0xfc06fa25U, 0x7a2359a3U, 0x72295babU, + 0x65f89dbcU, 0x8065e559U, 0x74acd8adU, 0x3db68be4U, + 0xc6b0761fU, 0x69f79eb0U, 0x39b38ae0U, 0x0a4f45d3U, + 0xb853eb61U, 0x2b270cf2U, 0x993ba240U, 0x33390aeaU, + 0xb119a868U, 0x165442cfU, 0x3e7648e7U, 0x1cdec2c5U, + 0x86e0665fU, 0xffc63926U, 0x8baf2452U, 0x0f0a05d6U, + 0xe558bd3cU, 0xdd6eb304U, 0x6e325cb7U, 0xa7882f7eU, + 0xc97fb610U, 0x45d0959cU, 0x886fe751U, 0x0e4a44d7U, + 0xbed66867U, 0x4dda9794U, 0x1b1b00c2U, 0x7b6318a2U, + 0x070007deU, 0x030506daU, 0xdfee3106U, 0xf7cc3b2eU, + 0x8460e45dU, 0xdeae7007U, 0x0ccac6d5U, 0xf803fb21U, + 0x5c8ed285U, 0xc570b51cU, 0x4095d599U, 0x4f5a1596U, + 0xf68c7a2fU, 0xd564b10cU, 0xc3f5361aU, 0xb79c2b6eU, + 0xceba7417U, 0xf2897b2bU, 0xdbeb3002U, 0xd161b008U, + 0x9afb6143U, 0xb51ca96cU, 0x762c5aafU, 0x9071e149U, + 0x24e8ccfdU, 0x8520a55cU, 0x5f4e1186U, 0x4490d49dU, + 0x064046dfU, 0x637d1ebaU, 0xf149b828U, 0xfa837923U, + 0x5081d189U, 0x25a88dfcU, 0x60bdddb9U, 0x70a9d9a9U, + 0x9474e04dU, 0x171403ceU, 0xec12fe35U, 0x9bbb2042U, + 0x82e5675bU, 0xe817ff31U, 0x6f721db6U, 0x4b5f1492U, + 0x27280ffeU, 0x5484d08dU, 0x75ec99acU, 0x96f4624fU, + 0xa508ad7cU, 0x0b0f04d2U, 0xa907ae70U, 0xa04ded79U, + 0xd2a1730bU, 0x71e998a8U, 0x4750179eU, 0x018584d8U, + 0x5a0b5183U, 0xc175b418U, 0x87a0275eU, 0x32794bebU, + 0x5744138eU, 0x098f86d0U, 0xcffa3516U, 0x4a1f5593U, + 0xed52bf34U, 0x9d3ea344U, 0x5604528fU, 0x93b1224aU, + 0xfc07fb75U, 0xe559bc6cU, 0x00c4c489U, 0x5c8fd3d5U, + 0x9475e11dU, 0x20eccca9U, 0x534013daU, 0x79e29bf0U, + 0xffc73876U, 0x7de79af4U, 0xf7cd3a7eU, 0xac43ef25U, + 0x0701068eU, 0x489ed6c1U, 0x1715029eU, 0xb3982b3aU, + 0x0b0e0582U, 0x3a7248b3U, 0xcd7bb644U, 0x7e2759f7U, + 0x0f0b0486U, 0x5dcf92d4U, 0xb79d2a3eU, 0xa846ee21U, + 0x0d8b8684U, 0xb6dd6b3fU, 0xebd63d62U, 0x3f3708b6U, + 0x82e4660bU, 0xbd17aa34U, 0xbf972836U, 0xc174b548U, + 0xd565b05cU, 0xaec36d27U, 0xe6997f6fU, 0x74add9fdU, + 0xe15cbd68U, 0x18dac291U, 0xc571b44cU, 0x4e1b55c7U, + 0x6b761de2U, 0xf68d7b7fU, 0x8bae2502U, 0xaac66c23U, + 0x10d0c099U, 0x987ae211U, 0x1595809cU, 0x2e634da7U, + 0x34fdc9bdU, 0x69f69fe0U, 0xd7e5325eU, 0x01848588U, + 0x8064e409U, 0x87a1260eU, 0x04c1c58dU, 0xf148b978U, + 0xa509ac2cU, 0xd82af251U, 0xf54db87cU, 0x4c9bd7c5U, + 0x72285afbU, 0x993aa310U, 0x5b4a11d2U, 0x3db78ab4U, + 0xbad26833U, 0xbb922932U, 0x39b28bb0U, 0x5485d1ddU, + 0x68b6dee1U, 0x6a365ce3U, 0xfbc23972U, 0x4ddb96c4U, + 0xa906af20U, 0xc2b4764bU, 0x574512deU, 0xc3f4374aU, + 0x3cf7cbb5U, 0xb118a938U, 0x9afa6013U, 0x0581848cU, + 0x0641478fU, 0x0a4e4483U, 0xa10cad28U, 0x6df39ee4U, + 0x623c5eebU, 0x367d4bbfU, 0xcc3bf745U, 0x892ea700U, + 0x4491d5cdU, 0x08cec681U, 0x9bba2112U, 0x8aee6403U, + 0x66395fefU, 0xfe877977U, 0xd160b158U, 0x73681bfaU, + 0xdfef3056U, 0x373d0abeU, 0x9fbf2016U, 0xdeaf7157U, + 0x2a664ca3U, 0xc6b1774fU, 0xe01cfc69U, 0x2da38ea4U, + 0x33380bbaU, 0x2f230ca6U, 0x560553dfU, 0x4b5e15c2U, + 0xa38c2f2aU, 0x232c0faaU, 0x461157cfU, 0xb912ab30U, + 0xf40df97dU, 0xa7892e2eU, 0xbed76937U, 0xfa827873U, + 0xd96ab350U, 0xe816fe61U, 0x3b3209b2U, 0xee937d67U, + 0x96f5631fU, 0x7f6718f6U, 0xaf832c26U, 0x38f2cab1U, + 0x25a98cacU, 0xb45de93dU, 0x8461e50dU, 0xdd6fb254U, + 0x0ccbc785U, 0x59ca93d0U, 0x8d2ba604U, 0xec13ff65U, + 0xa6c96f2fU, 0xb852ea31U, 0x475116ceU, 0x71e899f8U, + 0x29a68fa0U, 0x78a2daf1U, 0x6cb3dfe5U, 0x9c7fe315U, + 0x4094d4c9U, 0x226c4eabU, 0xf3c83b7aU, 0x21ac8da8U, + 0x24e9cdadU, 0x1d9f8294U, 0xd2a0725bU, 0x35bd88bcU, + 0xc97eb740U, 0x776d1afeU, 0xcffb3446U, 0xf2887a7bU, + 0x11908198U, 0xe956bf60U, 0x6f731ce6U, 0x67791eeeU, + 0x70a8d8f9U, 0x9535a01cU, 0x61fc9de8U, 0x28e6cea1U, + 0xd3e0335aU, 0x7ca7dbf5U, 0x2ce3cfa5U, 0x1f1f0096U, + 0xad03ae24U, 0x3e7749b7U, 0x8c6be705U, 0x26694fafU, + 0xa449ed2dU, 0x0304078aU, 0x2b260da2U, 0x098e8780U, + 0x93b0231aU, 0xea967c63U, 0x9eff6117U, 0x1a5a4093U, + 0xf008f879U, 0xc83ef641U, 0x7b6219f2U, 0xb2d86a3bU, + 0xdc2ff355U, 0x5080d0d9U, 0x9d3fa214U, 0x1b1a0192U, + 0xab862d22U, 0x588ad2d1U, 0x0e4b4587U, 0x6e335de7U, + 0x1250429bU, 0x1655439fU, 0xcabe7443U, 0xe29c7e6bU, + 0x9130a118U, 0xcbfe3542U, 0x199a8390U, 0xed53be64U, + 0x49de97c0U, 0xd020f059U, 0x55c590dcU, 0x5a0a50d3U, + 0xe3dc3f6aU, 0xc034f449U, 0xd6a5735fU, 0xa2cc6e2bU, + 0xdbea3152U, 0xe7d93e6eU, 0xcebb7547U, 0xc431f54dU, + 0x8fab2406U, 0xa04cec29U, 0x637c1feaU, 0x8521a40cU, + 0x31b889b8U, 0x9070e019U, 0x4a1e54c3U, 0x51c091d8U, + 0x1310039aU, 0x762d5bffU, 0xe419fd6dU, 0xefd33c66U, + 0x45d194ccU, 0x30f8c8b9U, 0x75ed98fcU, 0x65f99cecU, + 0x8124a508U, 0x0244468bU, 0xf942bb70U, 0x8eeb6507U, + 0x97b5221eU, 0xfd47ba74U, 0x7a2258f3U, 0x5e0f51d7U, + 0x32784abbU, 0x41d495c8U, 0x60bcdce9U, 0x83a4270aU, + 0xb058e839U, 0x1e5f4197U, 0xbc57eb35U, 0xb51da83cU, + 0xc7f1364eU, 0x64b9ddedU, 0x520052dbU, 0x14d5c19dU, + 0x4f5b14c6U, 0xd425f15dU, 0x92f0621bU, 0x27290eaeU, + 0x421456cbU, 0x1cdfc395U, 0xdaaa7053U, 0x5f4f10d6U, + 0xf802fa71U, 0x886ee601U, 0x435417caU, 0x86e1670fU, + 0x437536b8U, 0x5a2b71a1U, 0xbfb60944U, 0xe3fd1e18U, + 0x2b072cd0U, 0x9f9e0164U, 0xec32de17U, 0xc690563dU, + 0x40b5f5bbU, 0xc2955739U, 0x48bff7b3U, 0x133122e8U, + 0xb873cb43U, 0xf7ec1b0cU, 0xa867cf53U, 0x0ceae6f7U, + 0xb47cc84fU, 0x8500857eU, 0x72097b89U, 0xc155943aU, + 0xb079c94bU, 0xe2bd5f19U, 0x08efe7f3U, 0x173423ecU, + 0xb2f94b49U, 0x09afa6f2U, 0x54a4f0afU, 0x8045c57bU, + 0x3d96abc6U, 0x026567f9U, 0x00e5e5fbU, 0x7e067885U, + 0x6a177d91U, 0x11b1a0eaU, 0x59ebb2a2U, 0xcbdf1430U, + 0x5e2e70a5U, 0xa7a80f5cU, 0x7a037981U, 0xf169980aU, + 0xd404d02fU, 0x49ffb6b2U, 0x34dce8cfU, 0x15b4a1eeU, + 0xafa20d54U, 0x27082fdcU, 0xaae74d51U, 0x9111806aU, + 0x8b8f0470U, 0xd684522dU, 0x6897ff93U, 0xbef64845U, + 0x3f1629c4U, 0x38d3ebc3U, 0xbbb30840U, 0x4e3a74b5U, + 0x1a7b61e1U, 0x67583f9cU, 0x4a3f75b1U, 0xf3e91a08U, + 0xcd5a9736U, 0x26486eddU, 0xe438dc1fU, 0x82c54779U, + 0x05a0a5feU, 0x04e0e4ffU, 0x86c0467dU, 0xebf71c10U, + 0xd7c4132cU, 0xd544912eU, 0x44b0f4bfU, 0xf2a95b09U, + 0x167462edU, 0x7dc6bb86U, 0xe837df13U, 0x7c86fa87U, + 0x83850678U, 0x0e6a64f5U, 0x2588addeU, 0xbaf34941U, + 0xb9338a42U, 0xb53c894eU, 0x1e7e60e5U, 0xd2815329U, + 0xdd4e9326U, 0x890f8672U, 0x73493a88U, 0x365c6acdU, + 0xfbe31800U, 0xb7bc0b4cU, 0x24c8ecdfU, 0x359ca9ceU, + 0xd94b9222U, 0x41f5b4baU, 0x6e127c95U, 0xcc1ad637U, + 0x609dfd9bU, 0x884fc773U, 0x20cdeddbU, 0x61ddbc9aU, + 0x9514816eU, 0x79c3ba82U, 0x5f6e31a4U, 0x92d14369U, + 0x8c4ac677U, 0x9051c16bU, 0xe9779e12U, 0xf42cd80fU, + 0x1cfee2e7U, 0x9c5ec267U, 0xf9639a02U, 0x066066fdU, + 0x4b7f34b0U, 0x18fbe3e3U, 0x01a5a4faU, 0x45f0b5beU, + 0x66187e9dU, 0x576433acU, 0x8440c47fU, 0x51e1b0aaU, + 0x2987aed2U, 0xc015d53bU, 0x10f1e1ebU, 0x8780077cU, + 0x9adb4161U, 0x0b2f24f0U, 0x3b1328c0U, 0x621d7f99U, + 0xb3b90a48U, 0xe6b85e1dU, 0x32596bc9U, 0x536132a8U, + 0x19bba2e2U, 0x072027fcU, 0xf823db03U, 0xce9a5435U, + 0x96d4426dU, 0xc7d0173cU, 0xd3c11228U, 0x230d2ed8U, + 0xffe61904U, 0x9d1e8366U, 0x4cbaf6b7U, 0x9ede4065U, + 0x9b9b0060U, 0xa2ed4f59U, 0x6dd2bf96U, 0x8acf4571U, + 0x760c7a8dU, 0xc81fd733U, 0x7089f98bU, 0x4dfab7b6U, + 0xaee24c55U, 0x562472adU, 0xd001d12bU, 0xd80bd323U, + 0xcfda1534U, 0x2a476dd1U, 0xde8e5025U, 0x9794036cU, + 0x6c92fe97U, 0xc3d51638U, 0x93910268U, 0xa06dcd5bU, + 0x127163e9U, 0x8105847aU, 0x33192ac8U, 0x991b8262U, + 0x1b3b20e0U, 0xbc76ca47U, 0x9454c06fU, 0xb6fc4a4dU, + 0x2cc2eed7U, 0x55e4b1aeU, 0x218dacdaU, 0xa5288d5eU, + 0x4f7a35b4U, 0x774c3b8cU, 0xc410d43fU, 0x0daaa7f6U, + 0x635d3e98U, 0xeff21d14U, 0x224d6fd9U, 0xa468cc5fU, + 0x14f4e0efU, 0xe7f81f1cU, 0xb139884aU, 0xd141902aU, + 0xad228f56U, 0xa9278e52U, 0x75ccb98eU, 0x5deeb3a6U, + 0x2e426cd5U, 0x748cf88fU, 0xa6e84e5dU, 0x522173a9U, + 0xf6ac5a0dU, 0x6f523d94U, 0xeab75d11U, 0xe5789d1eU, + 0x5caef2a7U, 0x7f463984U, 0x69d7be92U, 0x1dbea3e6U, + 0x6498fc9fU, 0x58abf3a3U, 0x71c9b88aU, 0x7b433880U, + 0x30d9e9cbU, 0x1f3e21e4U, 0xdc0ed227U, 0x3a5369c1U, + 0x8eca4475U, 0x2f022dd4U, 0xf56c990eU, 0xeeb25c15U, + 0xac62ce57U, 0xc95f9632U, 0x5b6b30a0U, 0x50a1f1abU, + 0xfaa35901U, 0x8f8a0574U, 0xca9f5531U, 0xda8b5121U, + 0x3e5668c5U, 0xbd368b46U, 0x463076bdU, 0x3199a8caU, + 0x28c7efd3U, 0x423577b9U, 0xc550953eU, 0xe17d9c1aU, + 0x8d0a8776U, 0xfea65805U, 0xdfce1124U, 0x3cd6eac7U, + 0x0f2a25f4U, 0xa12d8c5aU, 0x032526f8U, 0x0a6f65f1U, + 0x7883fb83U, 0xdbcb1020U, 0xed729f16U, 0xaba70c50U, + 0xf029d90bU, 0x6b573c90U, 0x2d82afd6U, 0x985bc363U, + 0xfd669b06U, 0xa3ad0e58U, 0x65d8bd9eU, 0xe03ddd1bU, + 0x477037bcU, 0x371c2bccU, 0xfc26da07U, 0x3993aac2U, + 0x1c667af4U, 0x05383dedU, 0xe0a54508U, 0xbcee5254U, + 0x7414609cU, 0xc08d4d28U, 0xb321925bU, 0x99831a71U, + 0x1fa6b9f7U, 0x9d861b75U, 0x17acbbffU, 0x4c226ea4U, + 0xe760870fU, 0xa8ff5740U, 0xf774831fU, 0x53f9aabbU, + 0xeb6f8403U, 0xda13c932U, 0x2d1a37c5U, 0x9e46d876U, + 0xef6a8507U, 0xbdae1355U, 0x57fcabbfU, 0x48276fa0U, + 0xedea0705U, 0x56bceabeU, 0x0bb7bce3U, 0xdf568937U, + 0x6285e78aU, 0x5d762bb5U, 0x5ff6a9b7U, 0x211534c9U, + 0x350431ddU, 0x4ea2eca6U, 0x06f8feeeU, 0x94cc587cU, + 0x013d3ce9U, 0xf8bb4310U, 0x251035cdU, 0xae7ad446U, + 0x8b179c63U, 0x16ecfafeU, 0x6bcfa483U, 0x4aa7eda2U, + 0xf0b14118U, 0x781b6390U, 0xf5f4011dU, 0xce02cc26U, + 0xd49c483cU, 0x89971e61U, 0x3784b3dfU, 0xe1e50409U, + 0x60056588U, 0x67c0a78fU, 0xe4a0440cU, 0x112938f9U, + 0x45682dadU, 0x384b73d0U, 0x152c39fdU, 0xacfa5644U, + 0x9249db7aU, 0x795b2291U, 0xbb2b9053U, 0xddd60b35U, + 0x5ab3e9b2U, 0x5bf3a8b3U, 0xd9d30a31U, 0xb4e4505cU, + 0x88d75f60U, 0x8a57dd62U, 0x1ba3b8f3U, 0xadba1745U, + 0x49672ea1U, 0x22d5f7caU, 0xb724935fU, 0x2395b6cbU, + 0xdc964a34U, 0x517928b9U, 0x7a9be192U, 0xe5e0050dU, + 0xe620c60eU, 0xea2fc502U, 0x416d2ca9U, 0x8d921f65U, + 0x825ddf6aU, 0xd61cca3eU, 0x2c5a76c4U, 0x694f2681U, + 0xa4f0544cU, 0xe8af4700U, 0x7bdba093U, 0x6a8fe582U, + 0x8658de6eU, 0x1ee6f8f6U, 0x310130d9U, 0x93099a7bU, + 0x3f8eb1d7U, 0xd75c8b3fU, 0x7fdea197U, 0x3ecef0d6U, + 0xca07cd22U, 0x26d0f6ceU, 0x007d7de8U, 0xcdc20f25U, + 0xd3598a3bU, 0xcf428d27U, 0xb664d25eU, 0xab3f9443U, + 0x43edaeabU, 0xc34d8e2bU, 0xa670d64eU, 0x59732ab1U, + 0x146c78fcU, 0x47e8afafU, 0x5eb6e8b6U, 0x1ae3f9f2U, + 0x390b32d1U, 0x08777fe0U, 0xdb538833U, 0x0ef2fce6U, + 0x7694e29eU, 0x9f069977U, 0x4fe2ada7U, 0xd8934b30U, + 0xc5c80d2dU, 0x543c68bcU, 0x6400648cU, 0x3d0e33d5U, + 0xecaa4604U, 0xb9ab1251U, 0x6d4a2785U, 0x0c727ee4U, + 0x46a8eeaeU, 0x58336bb0U, 0xa730974fU, 0x91891879U, + 0xc9c70e21U, 0x98c35b70U, 0x8cd25e64U, 0x7c1e6294U, + 0xa0f55548U, 0xc20dcf2aU, 0x13a9bafbU, 0xc1cd0c29U, + 0xc4884c2cU, 0xfdfe0315U, 0x32c1f3daU, 0xd5dc093dU, + 0x291f36c1U, 0x970c9b7fU, 0x2f9ab5c7U, 0x12e9fbfaU, + 0xf1f10019U, 0x09373ee1U, 0x8f129d67U, 0x87189f6fU, + 0x90c95978U, 0x7554219dU, 0x819d1c69U, 0xc8874f20U, + 0x3381b2dbU, 0x9cc65a74U, 0xcc824e24U, 0xff7e8117U, + 0x4d622fa5U, 0xde16c836U, 0x6c0a6684U, 0xc608ce2eU, + 0x44286cacU, 0xe365860bU, 0xcb478c23U, 0xe9ef0601U, + 0x73d1a29bU, 0x0af7fde2U, 0x7e9ee096U, 0xfa3bc112U, + 0x106979f8U, 0x285f77c0U, 0x9b039873U, 0x52b9ebbaU, + 0x3c4e72d4U, 0xb0e15158U, 0x7d5e2395U, 0xfb7b8013U, + 0x4be7aca3U, 0xb8eb5350U, 0xee2ac406U, 0x8e52dc66U, + 0xf231c31aU, 0xf634c21eU, 0x2adff5c2U, 0x02fdffeaU, + 0x71512099U, 0x2b9fb4c3U, 0xf9fb0211U, 0x0d323fe5U, + 0xa9bf1641U, 0x304171d8U, 0xb5a4115dU, 0xba6bd152U, + 0x03bdbeebU, 0x205575c8U, 0x36c4f2deU, 0x42adefaaU, + 0x3b8bb0d3U, 0x07b8bfefU, 0x2edaf4c6U, 0x245074ccU, + 0x6fcaa587U, 0x402d6da8U, 0x831d9e6bU, 0x6540258dU, + 0xd1d90839U, 0x70116198U, 0xaa7fd542U, 0xb1a11059U, + 0xf371821bU, 0x964cda7eU, 0x04787cecU, 0x0fb2bde7U, + 0xa5b0154dU, 0xd0994938U, 0x958c197dU, 0x85981d6dU, + 0x61452489U, 0xe225c70aU, 0x19233af1U, 0x6e8ae486U, + 0x77d4a39fU, 0x1d263bf5U, 0x9a43d972U, 0xbe6ed056U, + 0xd219cb3aU, 0xa1b51449U, 0x80dd5d68U, 0x63c5a68bU, + 0x503969b8U, 0xfe3ec016U, 0x5c366ab4U, 0x557c29bdU, + 0x2790b7cfU, 0x84d85c6cU, 0xb261d35aU, 0xf4b4401cU, + 0xaf3a9547U, 0x344470dcU, 0x7291e39aU, 0xc7488f2fU, + 0xa275d74aU, 0xfcbe4214U, 0x3acbf1d2U, 0xbf2e9157U, + 0x18637bf0U, 0x680f6780U, 0xa335964bU, 0x6680e68eU, + 0x6881e967U, 0x71dfae7eU, 0x9442d69bU, 0xc809c1c7U, + 0x00f3f30fU, 0xb46adebbU, 0xc7c601c8U, 0xed6489e2U, + 0x6b412a64U, 0xe96188e6U, 0x634b286cU, 0x38c5fd37U, + 0x9387149cU, 0xdc18c4d3U, 0x8393108cU, 0x271e3928U, + 0x9f881790U, 0xaef45aa1U, 0x59fda456U, 0xeaa14be5U, + 0x9b8d1694U, 0xc94980c6U, 0x231b382cU, 0x3cc0fc33U, + 0x990d9496U, 0x225b792dU, 0x7f502f70U, 0xabb11aa4U, + 0x16627419U, 0x2991b826U, 0x2b113a24U, 0x55f2a75aU, + 0x41e3a24eU, 0x3a457f35U, 0x721f6d7dU, 0xe02bcbefU, + 0x75daaf7aU, 0x8c5cd083U, 0x51f7a65eU, 0xda9d47d5U, + 0xfff00ff0U, 0x620b696dU, 0x1f283710U, 0x3e407e31U, + 0x8456d28bU, 0x0cfcf003U, 0x8113928eU, 0xbae55fb5U, + 0xa07bdbafU, 0xfd708df2U, 0x4363204cU, 0x9502979aU, + 0x14e2f61bU, 0x1327341cU, 0x9047d79fU, 0x65ceab6aU, + 0x318fbe3eU, 0x4cace043U, 0x61cbaa6eU, 0xd81dc5d7U, + 0xe6ae48e9U, 0x0dbcb102U, 0xcfcc03c0U, 0xa93198a6U, + 0x2e547a21U, 0x2f143b20U, 0xad3499a2U, 0xc003c3cfU, + 0xfc30ccf3U, 0xfeb04ef1U, 0x6f442b60U, 0xd95d84d6U, + 0x3d80bd32U, 0x56326459U, 0xc3c300ccU, 0x57722558U, + 0xa871d9a7U, 0x259ebb2aU, 0x0e7c7201U, 0x9107969eU, + 0x92c7559dU, 0x9ec85691U, 0x358abf3aU, 0xf9758cf6U, + 0xf6ba4cf9U, 0xa2fb59adU, 0x58bde557U, 0x1da8b512U, + 0xd017c7dfU, 0x9c48d493U, 0x0f3c3300U, 0x1e687611U, + 0xf2bf4dfdU, 0x6a016b65U, 0x45e6a34aU, 0xe7ee09e8U, + 0x4b692244U, 0xa3bb18acU, 0x0b393204U, 0x4a296345U, + 0xbee05eb1U, 0x5237655dU, 0x749aee7bU, 0xb9259cb6U, + 0xa7be19a8U, 0xbba51eb4U, 0xc28341cdU, 0xdfd807d0U, + 0x370a3d38U, 0xb7aa1db8U, 0xd29745ddU, 0x2d94b922U, + 0x608beb6fU, 0x330f3c3cU, 0x2a517b25U, 0x6e046a61U, + 0x4deca142U, 0x7c90ec73U, 0xafb41ba0U, 0x7a156f75U, + 0x0273710dU, 0xebe10ae4U, 0x3b053e34U, 0xac74d8a3U, + 0xb12f9ebeU, 0x20dbfb2fU, 0x10e7f71fU, 0x49e9a046U, + 0x984dd597U, 0xcd4c81c2U, 0x19adb416U, 0x7895ed77U, + 0x324f7d3dU, 0x2cd4f823U, 0xd3d704dcU, 0xe56e8beaU, + 0xbd209db2U, 0xec24c8e3U, 0xf835cdf7U, 0x08f9f107U, + 0xd412c6dbU, 0xb6ea5cb9U, 0x674e2968U, 0xb52a9fbaU, + 0xb06fdfbfU, 0x89199086U, 0x46266049U, 0xa13b9aaeU, + 0x5df8a552U, 0xe3eb08ecU, 0x5b7d2654U, 0x660e6869U, + 0x8516938aU, 0x7dd0ad72U, 0xfbf50ef4U, 0xf3ff0cfcU, + 0xe42ecaebU, 0x01b3b20eU, 0xf57a8ffaU, 0xbc60dcb3U, + 0x47662148U, 0xe821c9e7U, 0xb865ddb7U, 0x8b991284U, + 0x3985bc36U, 0xaaf15ba5U, 0x18edf517U, 0xb2ef5dbdU, + 0x30cfff3fU, 0x97821598U, 0xbfa01fb0U, 0x9d089592U, + 0x07363108U, 0x7e106e71U, 0x0a797305U, 0x8edc5281U, + 0x648eea6bU, 0x5cb8e453U, 0xefe40be0U, 0x265e7829U, + 0x48a9e147U, 0xc406c2cbU, 0x09b9b006U, 0x8f9c1380U, + 0x3f003f30U, 0xcc0cc0c3U, 0x9acd5795U, 0xfab54ff5U, + 0x86d65089U, 0x82d3518dU, 0x5e386651U, 0x761a6c79U, + 0x05b6b30aU, 0x5f782750U, 0x8d1c9182U, 0x79d5ac76U, + 0xdd5885d2U, 0x44a6e24bU, 0xc14382ceU, 0xce8c42c1U, + 0x775a2d78U, 0x54b2e65bU, 0x4223614dU, 0x364a7c39U, + 0x4f6c2340U, 0x735f2c7cU, 0x5a3d6755U, 0x50b7e75fU, + 0x1b2d3614U, 0x34cafe3bU, 0xf7fa0df8U, 0x11a7b61eU, + 0xa53e9baaU, 0x04f6f20bU, 0xde9846d1U, 0xc54683caU, + 0x87961188U, 0xe2ab49edU, 0x709fef7fU, 0x7b552e74U, + 0xd15786deU, 0xa47edaabU, 0xe16b8aeeU, 0xf17f8efeU, + 0x15a2b71aU, 0x96c25499U, 0x6dc4a962U, 0x1a6d7715U, + 0x0333300cU, 0x69c1a866U, 0xeea44ae1U, 0xca8943c5U, + 0xa6fe58a9U, 0xd55287daU, 0xf43acefbU, 0x17223518U, + 0x24defa2bU, 0x8ad95385U, 0x28d1f927U, 0x219bba2eU, + 0x5377245cU, 0xf03fcfffU, 0xc68640c9U, 0x8053d38fU, + 0xdbdd06d4U, 0x40a3e34fU, 0x06767009U, 0xb3af1cbcU, + 0xd69244d9U, 0x8859d187U, 0x4e2c6241U, 0xcbc902c4U, + 0x6c84e863U, 0x1ce8f413U, 0xd7d205d8U, 0x1267751dU, + 0x3cc4f876U, 0x259abf6fU, 0xc007c78aU, 0x9c4cd0d6U, + 0x54b6e21eU, 0xe02fcfaaU, 0x938310d9U, 0xb92198f3U, + 0x3f043b75U, 0xbd2499f7U, 0x370e397dU, 0x6c80ec26U, + 0xc7c2058dU, 0x885dd5c2U, 0xd7d6019dU, 0x735b2839U, + 0xcbcd0681U, 0xfab14bb0U, 0x0db8b547U, 0xbee45af4U, + 0xcfc80785U, 0x9d0c91d7U, 0x775e293dU, 0x6885ed22U, + 0xcd488587U, 0x761e683cU, 0x2b153e61U, 0xfff40bb5U, + 0x42276508U, 0x7dd4a937U, 0x7f542b35U, 0x01b7b64bU, + 0x15a6b35fU, 0x6e006e24U, 0x265a7c6cU, 0xb46edafeU, + 0x219fbe6bU, 0xd819c192U, 0x05b2b74fU, 0x8ed856c4U, + 0xabb51ee1U, 0x364e787cU, 0x4b6d2601U, 0x6a056f20U, + 0xd013c39aU, 0x58b9e112U, 0xd556839fU, 0xeea04ea4U, + 0xf43ecabeU, 0xa9359ce3U, 0x1726315dU, 0xc147868bU, + 0x40a7e70aU, 0x4762250dU, 0xc402c68eU, 0x318bba7bU, + 0x65caaf2fU, 0x18e9f152U, 0x358ebb7fU, 0x8c58d4c6U, + 0xb2eb59f8U, 0x59f9a013U, 0x9b8912d1U, 0xfd7489b7U, + 0x7a116b30U, 0x7b512a31U, 0xf97188b3U, 0x9446d2deU, + 0xa875dde2U, 0xaaf55fe0U, 0x3b013a71U, 0x8d1895c7U, + 0x69c5ac23U, 0x02777548U, 0x978611ddU, 0x03373449U, + 0xfc34c8b6U, 0x71dbaa3bU, 0x5a396310U, 0xc542878fU, + 0xc682448cU, 0xca8d4780U, 0x61cfae2bU, 0xad309de7U, + 0xa2ff5de8U, 0xf6be48bcU, 0x0cf8f446U, 0x49eda403U, + 0x8452d6ceU, 0xc80dc582U, 0x5b792211U, 0x4a2d6700U, + 0xa6fa5cecU, 0x3e447a74U, 0x11a3b25bU, 0xb3ab18f9U, + 0x1f2c3355U, 0xf7fe09bdU, 0x5f7c2315U, 0x1e6c7254U, + 0xeaa54fa0U, 0x0672744cU, 0x20dfff6aU, 0xed608da7U, + 0xf3fb08b9U, 0xefe00fa5U, 0x96c650dcU, 0x8b9d16c1U, + 0x634f2c29U, 0xe3ef0ca9U, 0x86d254ccU, 0x79d1a833U, + 0x34cefa7eU, 0x674a2d2dU, 0x7e146a34U, 0x3a417b70U, + 0x19a9b053U, 0x28d5fd62U, 0xfbf10ab1U, 0x2e507e64U, + 0x5636601cU, 0xbfa41bf5U, 0x6f402f25U, 0xf831c9b2U, + 0xe56a8fafU, 0x749eea3eU, 0x44a2e60eU, 0x1dacb157U, + 0xcc08c486U, 0x990990d3U, 0x4de8a507U, 0x2cd0fc66U, + 0x660a6c2cU, 0x7891e932U, 0x879215cdU, 0xb12b9afbU, + 0xe9658ca3U, 0xb861d9f2U, 0xac70dce6U, 0x5cbce016U, + 0x8057d7caU, 0xe2af4da8U, 0x330b3879U, 0xe16f8eabU, + 0xe42aceaeU, 0xdd5c8197U, 0x12637158U, 0xf57e8bbfU, + 0x09bdb443U, 0xb7ae19fdU, 0x0f383745U, 0x324b7978U, + 0xd153829bU, 0x2995bc63U, 0xafb01fe5U, 0xa7ba1dedU, + 0xb06bdbfaU, 0x55f6a31fU, 0xa13f9eebU, 0xe825cda2U, + 0x13233059U, 0xbc64d8f6U, 0xec20cca6U, 0xdfdc0395U, + 0x6dc0ad27U, 0xfeb44ab4U, 0x4ca8e406U, 0xe6aa4cacU, + 0x648aee2eU, 0xc3c70489U, 0xebe50ea1U, 0xc94d8483U, + 0x53732019U, 0x2a557f60U, 0x5e3c6214U, 0xda994390U, + 0x30cbfb7aU, 0x08fdf542U, 0xbba11af1U, 0x721b6938U, + 0x1cecf056U, 0x9043d3daU, 0x5dfca117U, 0xdbd90291U, + 0x6b452e21U, 0x9849d1d2U, 0xce884684U, 0xaef05ee4U, + 0xd2934198U, 0xd696409cU, 0x0a7d7740U, 0x225f7d68U, + 0x51f3a21bU, 0x0b3d3641U, 0xd9598093U, 0x2d90bd67U, + 0x891d94c3U, 0x10e3f35aU, 0x950693dfU, 0x9ac953d0U, + 0x231f3c69U, 0x00f7f74aU, 0x1666705cU, 0x620f6d28U, + 0x1b293251U, 0x271a3d6dU, 0x0e787644U, 0x04f2f64eU, + 0x4f682705U, 0x608fef2aU, 0xa3bf1ce9U, 0x45e2a70fU, + 0xf17b8abbU, 0x50b3e31aU, 0x8add57c0U, 0x910392dbU, + 0xd3d30099U, 0xb6ee58fcU, 0x24dafe6eU, 0x2f103f65U, + 0x851297cfU, 0xf03bcbbaU, 0xb52e9bffU, 0xa53a9fefU, + 0x41e7a60bU, 0xc2874588U, 0x3981b873U, 0x4e286604U, + 0x5776211dU, 0x3d84b977U, 0xbae15bf0U, 0x9ecc52d4U, + 0xf2bb49b8U, 0x811796cbU, 0xa07fdfeaU, 0x43672409U, + 0x709beb3aU, 0xde9c4294U, 0x7c94e836U, 0x75deab3fU, + 0x0732354dU, 0xa47adeeeU, 0x92c351d8U, 0xd416c29eU, + 0x8f9817c5U, 0x14e6f25eU, 0x52336118U, 0xe7ea0dadU, + 0x82d755c8U, 0xdc1cc096U, 0x1a697350U, 0x9f8c13d5U, + 0x38c1f972U, 0x48ade502U, 0x839714c9U, 0x4622640cU, + 0xebff149aU, 0xf2a15383U, 0x173c2b66U, 0x4b773c3aU, + 0x838d0ef2U, 0x37142346U, 0x44b8fc35U, 0x6e1a741fU, + 0xe83fd799U, 0x6a1f751bU, 0xe035d591U, 0xbbbb00caU, + 0x10f9e961U, 0x5f66392eU, 0x00eded71U, 0xa460c4d5U, + 0x1cf6ea6dU, 0x2d8aa75cU, 0xda8359abU, 0x69dfb618U, + 0x18f3eb69U, 0x4a377d3bU, 0xa065c5d1U, 0xbfbe01ceU, + 0x1a73696bU, 0xa12584d0U, 0xfc2ed28dU, 0x28cfe759U, + 0x951c89e4U, 0xaaef45dbU, 0xa86fc7d9U, 0xd68c5aa7U, + 0xc29d5fb3U, 0xb93b82c8U, 0xf1619080U, 0x63553612U, + 0xf6a45287U, 0x0f222d7eU, 0xd2895ba3U, 0x59e3ba28U, + 0x7c8ef20dU, 0xe1759490U, 0x9c56caedU, 0xbd3e83ccU, + 0x07282f76U, 0x8f820dfeU, 0x026d6f73U, 0x399ba248U, + 0x23052652U, 0x7e0e700fU, 0xc01dddb1U, 0x167c6a67U, + 0x979c0be6U, 0x9059c9e1U, 0x13392a62U, 0xe6b05697U, + 0xb2f143c3U, 0xcfd21dbeU, 0xe2b55793U, 0x5b63382aU, + 0x65d0b514U, 0x8ec24cffU, 0x4cb2fe3dU, 0x2a4f655bU, + 0xad2a87dcU, 0xac6ac6ddU, 0x2e4a645fU, 0x437d3e32U, + 0x7f4e310eU, 0x7dceb30cU, 0xec3ad69dU, 0x5a23792bU, + 0xbefe40cfU, 0xd54c99a4U, 0x40bdfd31U, 0xd40cd8a5U, + 0x2b0f245aU, 0xa6e046d7U, 0x8d028ffcU, 0x12796b63U, + 0x11b9a860U, 0x1db6ab6cU, 0xb6f442c7U, 0x7a0b710bU, + 0x75c4b104U, 0x2185a450U, 0xdbc318aaU, 0x9ed648efU, + 0x53693a22U, 0x1f36296eU, 0x8c42cefdU, 0x9d168becU, + 0x71c1b000U, 0xe97f9698U, 0xc6985eb7U, 0x6490f415U, + 0xc817dfb9U, 0x20c5e551U, 0x8847cff9U, 0xc9579eb8U, + 0x3d9ea34cU, 0xd14998a0U, 0xf7e41386U, 0x3a5b614bU, + 0x24c0e455U, 0x38dbe349U, 0x41fdbc30U, 0x5ca6fa2dU, + 0xb474c0c5U, 0x34d4e045U, 0x51e9b820U, 0xaeea44dfU, + 0xe3f51692U, 0xb071c1c1U, 0xa92f86d8U, 0xed7a979cU, + 0xce925cbfU, 0xffee118eU, 0x2ccae65dU, 0xf96b9288U, + 0x810d8cf0U, 0x689ff719U, 0xb87bc3c9U, 0x2f0a255eU, + 0x32516343U, 0xa3a506d2U, 0x93990ae2U, 0xca975dbbU, + 0x1b33286aU, 0x4e327c3fU, 0x9ad349ebU, 0xfbeb108aU, + 0xb13180c0U, 0xafaa05deU, 0x50a9f921U, 0x66107617U, + 0x3e5e604fU, 0x6f5a351eU, 0x7b4b300aU, 0x8b870cfaU, + 0x576c3b26U, 0x3594a144U, 0xe430d495U, 0x36546247U, + 0x33112242U, 0x0a676d7bU, 0xc5589db4U, 0x22456753U, + 0xde8658afU, 0x6095f511U, 0xd803dba9U, 0xe5709594U, + 0x06686e77U, 0xfeae508fU, 0x788bf309U, 0x7081f101U, + 0x67503716U, 0x82cd4ff3U, 0x76047207U, 0x3f1e214eU, + 0xc418dcb5U, 0x6b5f341aU, 0x3b1b204aU, 0x08e7ef79U, + 0xbafb41cbU, 0x298fa658U, 0x9b9308eaU, 0x3191a040U, + 0xb3b102c2U, 0x14fce865U, 0x3cdee24dU, 0x1e76686fU, + 0x8448ccf5U, 0xfd6e938cU, 0x89078ef8U, 0x0da2af7cU, + 0xe7f01796U, 0xdfc619aeU, 0x6c9af61dU, 0xa52085d4U, + 0xcbd71cbaU, 0x47783f36U, 0x8ac74dfbU, 0x0ce2ee7dU, + 0xbc7ec2cdU, 0x4f723d3eU, 0x19b3aa68U, 0x79cbb208U, + 0x05a8ad74U, 0x01adac70U, 0xdd469bacU, 0xf5649184U, + 0x86c84ef7U, 0xdc06daadU, 0x0e626c7fU, 0xfaab518bU, + 0x5e26782fU, 0xc7d81fb6U, 0x423d7f33U, 0x4df2bf3cU, + 0xf424d085U, 0xd7cc1ba6U, 0xc15d9cb0U, 0xb53481c4U, + 0xcc12debdU, 0xf021d181U, 0xd9439aa8U, 0xd3c91aa2U, + 0x9853cbe9U, 0xb7b403c6U, 0x7484f005U, 0x92d94be3U, + 0x26406657U, 0x87880ff6U, 0x5de6bb2cU, 0x46387e37U, + 0x04e8ec75U, 0x61d5b410U, 0xf3e11282U, 0xf82bd389U, + 0x52297b23U, 0x27002756U, 0x62157713U, 0x72017303U, + 0x96dc4ae7U, 0x15bca964U, 0xeeba549fU, 0x99138ae8U, + 0x804dcdf1U, 0xeabf559bU, 0x6ddab71cU, 0x49f7be38U, + 0x2580a554U, 0x562c7a27U, 0x77443306U, 0x945cc8e5U, + 0xa7a007d6U, 0x09a7ae78U, 0xabaf04daU, 0xa2e547d3U, + 0xd009d9a1U, 0x73413202U, 0x45f8bd34U, 0x032d2e72U, + 0x58a3fb29U, 0xc3dd1eb2U, 0x85088df4U, 0x30d1e141U, + 0x55ecb924U, 0x0b272c7aU, 0xcd529fbcU, 0x48b7ff39U, + 0xeffa159eU, 0x9f9609eeU, 0x54acf825U, 0x911988e0U, + 0x55d98c02U, 0x4c87cb1bU, 0xa91ab3feU, 0xf551a4a2U, + 0x3dab966aU, 0x8932bbdeU, 0xfa9e64adU, 0xd03cec87U, + 0x56194f01U, 0xd439ed83U, 0x5e134d09U, 0x059d9852U, + 0xaedf71f9U, 0xe140a1b6U, 0xbecb75e9U, 0x1a465c4dU, + 0xa2d072f5U, 0x93ac3fc4U, 0x64a5c133U, 0xd7f92e80U, + 0xa6d573f1U, 0xf411e5a3U, 0x1e435d49U, 0x01989956U, + 0xa455f1f3U, 0x1f031c48U, 0x42084a15U, 0x96e97fc1U, + 0x2b3a117cU, 0x14c9dd43U, 0x16495f41U, 0x68aac23fU, + 0x7cbbc72bU, 0x071d1a50U, 0x4f470818U, 0xdd73ae8aU, + 0x4882ca1fU, 0xb104b5e6U, 0x6cafc33bU, 0xe7c522b0U, + 0xc2a86a95U, 0x5f530c08U, 0x22705275U, 0x03181b54U, + 0xb90eb7eeU, 0x31a49566U, 0xbc4bf7ebU, 0x87bd3ad0U, + 0x9d23becaU, 0xc028e897U, 0x7e3b4529U, 0xa85af2ffU, + 0x29ba937eU, 0x2e7f5179U, 0xad1fb2faU, 0x5896ce0fU, + 0x0cd7db5bU, 0x71f48526U, 0x5c93cf0bU, 0xe545a0b2U, + 0xdbf62d8cU, 0x30e4d467U, 0xf29466a5U, 0x9469fdc3U, + 0x130c1f44U, 0x124c5e45U, 0x906cfcc7U, 0xfd5ba6aaU, + 0xc168a996U, 0xc3e82b94U, 0x521c4e05U, 0xe405e1b3U, + 0x00d8d857U, 0x6b6a013cU, 0xfe9b65a9U, 0x6a2a403dU, + 0x9529bcc2U, 0x18c6de4fU, 0x33241764U, 0xac5ff3fbU, + 0xaf9f30f8U, 0xa39033f4U, 0x08d2da5fU, 0xc42de993U, + 0xcbe2299cU, 0x9fa33cc8U, 0x65e58032U, 0x20f0d077U, + 0xed4fa2baU, 0xa110b1f6U, 0x32645665U, 0x23301374U, + 0xcfe72898U, 0x57590e00U, 0x78bec62fU, 0xdab66c8dU, + 0x76314721U, 0x9ee37dc9U, 0x36615761U, 0x77710620U, + 0x83b83bd4U, 0x6f6f0038U, 0x49c28b1eU, 0x847df9d3U, + 0x9ae67ccdU, 0x86fd7bd1U, 0xffdb24a8U, 0xe28062b5U, + 0x0a52585dU, 0x8af278ddU, 0xefcf20b8U, 0x10ccdc47U, + 0x5dd38e0aU, 0x0e575959U, 0x17091e40U, 0x535c0f04U, + 0x70b4c427U, 0x41c88916U, 0x92ec7ec5U, 0x474d0a10U, + 0x3f2b1468U, 0xd6b96f81U, 0x065d5b51U, 0x912cbdc6U, + 0x8c77fbdbU, 0x1d839e4aU, 0x2dbf927aU, 0x74b1c523U, + 0xa515b0f2U, 0xf014e4a7U, 0x24f5d173U, 0x45cd8812U, + 0x0f171858U, 0x118c9d46U, 0xee8f61b9U, 0xd836ee8fU, + 0x8078f8d7U, 0xd17cad86U, 0xc56da892U, 0x35a19462U, + 0xe94aa3beU, 0x8bb239dcU, 0x5a164c0dU, 0x8872fadfU, + 0x8d37badaU, 0xb441f5e3U, 0x7b7e052cU, 0x9c63ffcbU, + 0x60a0c037U, 0xdeb36d89U, 0x66254331U, 0x5b560d0cU, + 0xb84ef6efU, 0x4088c817U, 0xc6ad6b91U, 0xcea76999U, + 0xd976af8eU, 0x3cebd76bU, 0xc822ea9fU, 0x8138b9d6U, + 0x7a3e442dU, 0xd579ac82U, 0x853db8d2U, 0xb6c177e1U, + 0x04ddd953U, 0x97a93ec0U, 0x25b59072U, 0x8fb738d8U, + 0x0d979a5aU, 0xaada70fdU, 0x82f87ad5U, 0xa050f0f7U, + 0x3a6e546dU, 0x43480b14U, 0x37211660U, 0xb38437e4U, + 0x59d68f0eU, 0x61e08136U, 0xd2bc6e85U, 0x1b061d4cU, + 0x75f18422U, 0xf95ea7aeU, 0x34e1d563U, 0xb2c476e5U, + 0x02585a55U, 0xf154a5a6U, 0xa79532f0U, 0xc7ed2a90U, + 0xbb8e35ecU, 0xbf8b34e8U, 0x63600334U, 0x4b42091cU, + 0x38eed66fU, 0x62204235U, 0xb044f4e7U, 0x448dc913U, + 0xe000e0b7U, 0x79fe872eU, 0xfc1be7abU, 0xf3d427a4U, + 0x4a02481dU, 0x69ea833eU, 0x7f7b0428U, 0x0b12195cU, + 0x72344625U, 0x4e074919U, 0x67650230U, 0x6def823aU, + 0x26755371U, 0x09929b5eU, 0xcaa2689dU, 0x2cffd37bU, + 0x9866fecfU, 0x39ae976eU, 0xe3c023b4U, 0xf81ee6afU, + 0xbace74edU, 0xdff32c88U, 0x4dc78a1aU, 0x460d4b11U, + 0xec0fe3bbU, 0x9926bfceU, 0xdc33ef8bU, 0xcc27eb9bU, + 0x28fad27fU, 0xab9a31fcU, 0x509ccc07U, 0x27351270U, + 0x3e6b5569U, 0x5499cd03U, 0xd3fc2f84U, 0xf7d126a0U, + 0x9ba63dccU, 0xe80ae2bfU, 0xc962ab9eU, 0x2a7a507dU, + 0x19869f4eU, 0xb78136e0U, 0x15899c42U, 0x1cc3df4bU, + 0x6e2f4139U, 0xcd67aa9aU, 0xfbde25acU, 0xbd0bb6eaU, + 0xe68563b1U, 0x7dfb862aU, 0x3b2e156cU, 0x8ef779d9U, + 0xebca21bcU, 0xb501b4e2U, 0x73740724U, 0xf69167a1U, + 0x51dc8d06U, 0x21b09176U, 0xea8a60bdU, 0x2f3f1078U, + 0xb211a32dU, 0xab4fe434U, 0x4ed29cd1U, 0x12998b8dU, + 0xda63b945U, 0x6efa94f1U, 0x1d564b82U, 0x37f4c3a8U, + 0xb1d1602eU, 0x33f1c2acU, 0xb9db6226U, 0xe255b77dU, + 0x49175ed6U, 0x06888e99U, 0x59035ac6U, 0xfd8e7362U, + 0x45185ddaU, 0x746410ebU, 0x836dee1cU, 0x303101afU, + 0x411d5cdeU, 0x13d9ca8cU, 0xf98b7266U, 0xe650b679U, + 0x439ddedcU, 0xf8cb3367U, 0xa5c0653aU, 0x712150eeU, + 0xccf23e53U, 0xf301f26cU, 0xf181706eU, 0x8f62ed10U, + 0x9b73e804U, 0xe0d5357fU, 0xa88f2737U, 0x3abb81a5U, + 0xaf4ae530U, 0x56cc9ac9U, 0x8b67ec14U, 0x000d0d9fU, + 0x256045baU, 0xb89b2327U, 0xc5b87d5aU, 0xe4d0347bU, + 0x5ec698c1U, 0xd66cba49U, 0x5b83d8c4U, 0x607515ffU, + 0x7aeb91e5U, 0x27e0c7b8U, 0x99f36a06U, 0x4f92ddd0U, + 0xce72bc51U, 0xc9b77e56U, 0x4ad79dd5U, 0xbf5ee120U, + 0xeb1ff474U, 0x963caa09U, 0xbb5be024U, 0x028d8f9dU, + 0x3c3e02a3U, 0xd72cfb48U, 0x155c498aU, 0x73a1d2ecU, + 0xf4c4306bU, 0xf584716aU, 0x77a4d3e8U, 0x1a938985U, + 0x26a086b9U, 0x242004bbU, 0xb5d4612aU, 0x03cdce9cU, + 0xe710f778U, 0x8ca22e13U, 0x19534a86U, 0x8de26f12U, + 0x72e193edU, 0xff0ef160U, 0xd4ec384bU, 0x4b97dcd4U, + 0x48571fd7U, 0x44581cdbU, 0xef1af570U, 0x23e5c6bcU, + 0x2c2a06b3U, 0x786b13e7U, 0x822daf1dU, 0xc738ff58U, + 0x0a878d95U, 0x46d89ed9U, 0xd5ac794aU, 0xc4f83c5bU, + 0x282f07b7U, 0xb091212fU, 0x9f76e900U, 0x3d7e43a2U, + 0x91f9680eU, 0x792b52e6U, 0xd1a9784eU, 0x90b9290fU, + 0x647014fbU, 0x88a72f17U, 0xae0aa431U, 0x63b5d6fcU, + 0x7d2e53e2U, 0x613554feU, 0x18130b87U, 0x05484d9aU, + 0xed9a7772U, 0x6d3a57f2U, 0x08070f97U, 0xf704f368U, + 0xba1ba125U, 0xe99f7676U, 0xf0c1316fU, 0xb494202bU, + 0x977ceb08U, 0xa600a639U, 0x752451eaU, 0xa085253fU, + 0xd8e33b47U, 0x317140aeU, 0xe195747eU, 0x76e492e9U, + 0x6bbfd4f4U, 0xfa4bb165U, 0xca77bd55U, 0x9379ea0cU, + 0x42dd9fddU, 0x17dccb88U, 0xc33dfe5cU, 0xa205a73dU, + 0xe8df3777U, 0xf644b269U, 0x09474e96U, 0x3ffec1a0U, + 0x67b0d7f8U, 0x36b482a9U, 0x22a587bdU, 0xd269bb4dU, + 0x0e828c91U, 0x6c7a16f3U, 0xbdde6322U, 0x6fbad5f0U, + 0x6aff95f5U, 0x5389daccU, 0x9cb62a03U, 0x7babd0e4U, + 0x8768ef18U, 0x397b42a6U, 0x81ed6c1eU, 0xbc9e2223U, + 0x5f86d9c0U, 0xa740e738U, 0x216544beU, 0x296f46b6U, + 0x3ebe80a1U, 0xdb23f844U, 0x2feac5b0U, 0x66f096f9U, + 0x9df66b02U, 0x32b183adU, 0x62f597fdU, 0x510958ceU, + 0xe315f67cU, 0x706111efU, 0xc27dbf5dU, 0x687f17f7U, + 0xea5fb575U, 0x4d125fd2U, 0x653055faU, 0x4798dfd8U, + 0xdda67b42U, 0xa480243bU, 0xd0e9394fU, 0x544c18cbU, + 0xbe1ea021U, 0x8628ae19U, 0x357441aaU, 0xfcce3263U, + 0x9239ab0dU, 0x1e968881U, 0xd329fa4cU, 0x550c59caU, + 0xe590757aU, 0x169c8a89U, 0x405d1ddfU, 0x202505bfU, + 0x5c461ac3U, 0x58431bc7U, 0x84a82c1bU, 0xac8a2633U, + 0xdf26f940U, 0x85e86d1aU, 0x578cdbc8U, 0xa345e63cU, + 0x07c8cf98U, 0x9e36a801U, 0x1bd3c884U, 0x141c088bU, + 0xadca6732U, 0x8e22ac11U, 0x98b32b07U, 0xecda3673U, + 0x95fc690aU, 0xa9cf6636U, 0x80ad2d1fU, 0x8a27ad15U, + 0xc1bd7c5eU, 0xee5ab471U, 0x2d6a47b2U, 0xcb37fc54U, + 0x7faed1e0U, 0xde66b841U, 0x04080c9bU, 0x1fd6c980U, + 0x5d065bc2U, 0x383b03a7U, 0xaa0fa535U, 0xa1c5643eU, + 0x0bc7cc94U, 0x7eee90e1U, 0x3bfbc0a4U, 0x2befc4b4U, + 0xcf32fd50U, 0x4c521ed3U, 0xb754e328U, 0xc0fd3d5fU, + 0xd9a37a46U, 0xb351e22cU, 0x343400abU, 0x1019098fU, + 0x7c6e12e3U, 0x0fc2cd90U, 0x2eaa84b1U, 0xcdb27f52U, + 0xfe4eb061U, 0x504919cfU, 0xf241b36dU, 0xfb0bf064U, + 0x89e76e16U, 0x2aaf85b5U, 0x1c160a83U, 0x5ac399c5U, + 0x014d4c9eU, 0x9a33a905U, 0xdce63a43U, 0x693f56f6U, + 0x0c020e93U, 0x52c99bcdU, 0x94bc280bU, 0x1159488eU, + 0xb614a229U, 0xc678be59U, 0x0d424f92U, 0xc8f73f57U, + 0xbabb018fU, 0xa3e54696U, 0x46783e73U, 0x1a33292fU, + 0xd2c91be7U, 0x66503653U, 0x15fce920U, 0x3f5e610aU, + 0xb97bc28cU, 0x3b5b600eU, 0xb171c084U, 0xeaff15dfU, + 0x41bdfc74U, 0x0e222c3bU, 0x51a9f864U, 0xf524d1c0U, + 0x4db2ff78U, 0x7cceb249U, 0x8bc74cbeU, 0x389ba30dU, + 0x49b7fe7cU, 0x1b73682eU, 0xf121d0c4U, 0xeefa14dbU, + 0x4b377c7eU, 0xf06191c5U, 0xad6ac798U, 0x798bf24cU, + 0xc4589cf1U, 0xfbab50ceU, 0xf92bd2ccU, 0x87c84fb2U, + 0x93d94aa6U, 0xe87f97ddU, 0xa0258595U, 0x32112307U, + 0xa7e04792U, 0x5e66386bU, 0x83cd4eb6U, 0x08a7af3dU, + 0x2dcae718U, 0xb0318185U, 0xcd12dff8U, 0xec7a96d9U, + 0x566c3a63U, 0xdec618ebU, 0x53297a66U, 0x68dfb75dU, + 0x72413347U, 0x2f4a651aU, 0x9159c8a4U, 0x47387f72U, + 0xc6d81ef3U, 0xc11ddcf4U, 0x427d3f77U, 0xb7f44382U, + 0xe3b556d6U, 0x9e9608abU, 0xb3f14286U, 0x0a272d3fU, + 0x3494a001U, 0xdf8659eaU, 0x1df6eb28U, 0x7b0b704eU, + 0xfc6e92c9U, 0xfd2ed3c8U, 0x7f0e714aU, 0x12392b27U, + 0x2e0a241bU, 0x2c8aa619U, 0xbd7ec388U, 0x0b676c3eU, + 0xefba55daU, 0x84088cb1U, 0x11f9e824U, 0x8548cdb0U, + 0x7a4b314fU, 0xf7a453c2U, 0xdc469ae9U, 0x433d7e76U, + 0x40fdbd75U, 0x4cf2be79U, 0xe7b057d2U, 0x2b4f641eU, + 0x2480a411U, 0x70c1b145U, 0x8a870dbfU, 0xcf925dfaU, + 0x022d2f37U, 0x4e723c7bU, 0xdd06dbe8U, 0xcc529ef9U, + 0x2085a515U, 0xb83b838dU, 0x97dc4ba2U, 0x35d4e100U, + 0x9953caacU, 0x7181f044U, 0xd903daecU, 0x98138badU, + 0x6cdab659U, 0x800d8db5U, 0xa6a00693U, 0x6b1f745eU, + 0x7584f140U, 0x699ff65cU, 0x10b9a925U, 0x0de2ef38U, + 0xe530d5d0U, 0x6590f550U, 0x00adad35U, 0xffae51caU, + 0xb2b10387U, 0xe135d4d4U, 0xf86b93cdU, 0xbc3e8289U, + 0x9fd649aaU, 0xaeaa049bU, 0x7d8ef348U, 0xa82f879dU, + 0xd04999e5U, 0x39dbe20cU, 0xe93fd6dcU, 0x7e4e304bU, + 0x63157656U, 0xf2e113c7U, 0xc2dd1ff7U, 0x9bd348aeU, + 0x4a773d7fU, 0x1f76692aU, 0xcb975cfeU, 0xaaaf059fU, + 0xe07595d5U, 0xfeee10cbU, 0x01edec34U, 0x37546302U, + 0x6f1a755aU, 0x3e1e200bU, 0x2a0f251fU, 0xdac319efU, + 0x06282e33U, 0x64d0b451U, 0xb574c180U, 0x67107752U, + 0x62553757U, 0x5b23786eU, 0x941c88a1U, 0x73017246U, + 0x8fc24dbaU, 0x31d1e004U, 0x8947cebcU, 0xb4348081U, + 0x572c7b62U, 0xafea459aU, 0x29cfe61cU, 0x21c5e414U, + 0x36142203U, 0xd3895ae6U, 0x27406712U, 0x6e5a345bU, + 0x955cc9a0U, 0x3a1b210fU, 0x6a5f355fU, 0x59a3fa6cU, + 0xebbf54deU, 0x78cbb34dU, 0xcad71dffU, 0x60d5b555U, + 0xe2f517d7U, 0x45b8fd70U, 0x6d9af758U, 0x4f327d7aU, + 0xd50cd9e0U, 0xac2a8699U, 0xd8439bedU, 0x5ce6ba69U, + 0xb6b40283U, 0x8e820cbbU, 0x3ddee308U, 0xf46490c1U, + 0x9a9309afU, 0x163c2a23U, 0xdb8358eeU, 0x5da6fb68U, + 0xed3ad7d8U, 0x1e36282bU, 0x48f7bf7dU, 0x288fa71dU, + 0x54ecb861U, 0x50e9b965U, 0x8c028eb9U, 0xa4208491U, + 0xd78c5be2U, 0x8d42cfb8U, 0x5f26796aU, 0xabef449eU, + 0x0f626d3aU, 0x969c0aa3U, 0x13796a26U, 0x1cb6aa29U, + 0xa560c590U, 0x86880eb3U, 0x901989a5U, 0xe47094d1U, + 0x9d56cba8U, 0xa165c494U, 0x88078fbdU, 0x828d0fb7U, + 0xc917defcU, 0xe6f016d3U, 0x25c0e510U, 0xc39d5ef6U, + 0x77047342U, 0xd6cc1ae3U, 0x0ca2ae39U, 0x177c6b22U, + 0x55acf960U, 0x3091a105U, 0xa2a50797U, 0xa96fc69cU, + 0x036d6e36U, 0x76443243U, 0x33516206U, 0x23456616U, + 0xc7985ff2U, 0x44f8bc71U, 0xbffe418aU, 0xc8579ffdU, + 0xd109d8e4U, 0xbbfb408eU, 0x3c9ea209U, 0x18b3ab2dU, + 0x74c4b041U, 0x07686f32U, 0x26002613U, 0xc518ddf0U, + 0xf6e412c3U, 0x58e3bb6dU, 0xfaeb11cfU, 0xf3a152c6U, + 0x814dccb4U, 0x22052717U, 0x14bca821U, 0x52693b67U, + 0x09e7ee3cU, 0x92990ba7U, 0xd44c98e1U, 0x6195f454U, + 0x04a8ac31U, 0x5a63396fU, 0x9c168aa9U, 0x19f3ea2cU, + 0xbebe008bU, 0xced21cfbU, 0x05e8ed30U, 0xc05d9df5U, + 0x3d90ad23U, 0x24ceea3aU, 0xc15392dfU, 0x9d188583U, + 0x55e2b74bU, 0xe17b9affU, 0x92d7458cU, 0xb875cda6U, + 0x3e506e20U, 0xbc70cca2U, 0x365a6c28U, 0x6dd4b973U, + 0xc69650d8U, 0x89098097U, 0xd68254c8U, 0x720f7d6cU, + 0xca9953d4U, 0xfbe51ee5U, 0x0cece012U, 0xbfb00fa1U, + 0xce9c52d0U, 0x9c58c482U, 0x760a7c68U, 0x69d1b877U, + 0xcc1cd0d2U, 0x774a3d69U, 0x2a416b34U, 0xfea05ee0U, + 0x4373305dU, 0x7c80fc62U, 0x7e007e60U, 0x00e3e31eU, + 0x14f2e60aU, 0x6f543b71U, 0x270e2939U, 0xb53a8fabU, + 0x20cbeb3eU, 0xd94d94c7U, 0x04e6e21aU, 0x8f8c0391U, + 0xaae14bb4U, 0x371a2d29U, 0x4a397354U, 0x6b513a75U, + 0xd14796cfU, 0x59edb447U, 0xd402d6caU, 0xeff41bf1U, + 0xf56a9febU, 0xa861c9b6U, 0x16726408U, 0xc013d3deU, + 0x41f3b25fU, 0x46367058U, 0xc55693dbU, 0x30dfef2eU, + 0x649efa7aU, 0x19bda407U, 0x34daee2aU, 0x8d0c8193U, + 0xb3bf0cadU, 0x58adf546U, 0x9add4784U, 0xfc20dce2U, + 0x7b453e65U, 0x7a057f64U, 0xf825dde6U, 0x9512878bU, + 0xa92188b7U, 0xaba10ab5U, 0x3a556f24U, 0x8c4cc092U, + 0x6891f976U, 0x0323201dU, 0x96d24488U, 0x0263611cU, + 0xfd609de3U, 0x708fff6eU, 0x5b6d3645U, 0xc416d2daU, + 0xc7d611d9U, 0xcbd912d5U, 0x609bfb7eU, 0xac64c8b2U, + 0xa3ab08bdU, 0xf7ea1de9U, 0x0daca113U, 0x48b9f156U, + 0x8506839bU, 0xc95990d7U, 0x5a2d7744U, 0x4b793255U, + 0xa7ae09b9U, 0x3f102f21U, 0x10f7e70eU, 0xb2ff4dacU, + 0x1e786600U, 0xf6aa5ce8U, 0x5e287640U, 0x1f382701U, + 0xebf11af5U, 0x07262119U, 0x218baa3fU, 0xec34d8f2U, + 0xf2af5decU, 0xeeb45af0U, 0x97920589U, 0x8ac94394U, + 0x621b797cU, 0xe2bb59fcU, 0x87860199U, 0x7885fd66U, + 0x359aaf2bU, 0x661e7878U, 0x7f403f61U, 0x3b152e25U, + 0x18fde506U, 0x2981a837U, 0xfaa55fe4U, 0x2f042b31U, + 0x57623549U, 0xbef04ea0U, 0x6e147a70U, 0xf9659ce7U, + 0xe43edafaU, 0x75cabf6bU, 0x45f6b35bU, 0x1cf8e402U, + 0xcd5c91d3U, 0x985dc586U, 0x4cbcf052U, 0x2d84a933U, + 0x675e3979U, 0x79c5bc67U, 0x86c64098U, 0xb07fcfaeU, + 0xe831d9f6U, 0xb9358ca7U, 0xad2489b3U, 0x5de8b543U, + 0x8103829fU, 0xe3fb18fdU, 0x325f6d2cU, 0xe03bdbfeU, + 0xe57e9bfbU, 0xdc08d4c2U, 0x1337240dU, 0xf42adeeaU, + 0x08e9e116U, 0xb6fa4ca8U, 0x0e6c6210U, 0x331f2c2dU, + 0xd007d7ceU, 0x28c1e936U, 0xaee44ab0U, 0xa6ee48b8U, + 0xb13f8eafU, 0x54a2f64aU, 0xa06bcbbeU, 0xe97198f7U, + 0x1277650cU, 0xbd308da3U, 0xed7499f3U, 0xde8856c0U, + 0x6c94f872U, 0xffe01fe1U, 0x4dfcb153U, 0xe7fe19f9U, + 0x65debb7bU, 0xc29351dcU, 0xeab15bf4U, 0xc819d1d6U, + 0x5227754cU, 0x2b012a35U, 0x5f683741U, 0xdbcd16c5U, + 0x319fae2fU, 0x09a9a017U, 0xbaf54fa4U, 0x734f3c6dU, + 0x1db8a503U, 0x9117868fU, 0x5ca8f442U, 0xda8d57c4U, + 0x6a117b74U, 0x991d8487U, 0xcfdc13d1U, 0xafa40bb1U, + 0xd3c714cdU, 0xd7c215c9U, 0x0b292215U, 0x230b283dU, + 0x50a7f74eU, 0x0a696314U, 0xd80dd5c6U, 0x2cc4e832U, + 0x8849c196U, 0x11b7a60fU, 0x9452c68aU, 0x9b9d0685U, + 0x224b693cU, 0x01a3a21fU, 0x17322509U, 0x635b387dU, + 0x1a7d6704U, 0x264e6838U, 0x0f2c2311U, 0x05a6a31bU, + 0x4e3c7250U, 0x61dbba7fU, 0xa2eb49bcU, 0x44b6f25aU, + 0xf02fdfeeU, 0x51e7b64fU, 0x8b890295U, 0x9057c78eU, + 0xd28755ccU, 0xb7ba0da9U, 0x258eab3bU, 0x2e446a30U, + 0x8446c29aU, 0xf16f9eefU, 0xb47aceaaU, 0xa46ecabaU, + 0x40b3f35eU, 0xc3d310ddU, 0x38d5ed26U, 0x4f7c3351U, + 0x56227448U, 0x3cd0ec22U, 0xbbb50ea5U, 0x9f980781U, + 0xf3ef1cedU, 0x8043c39eU, 0xa12b8abfU, 0x4233715cU, + 0x71cfbe6fU, 0xdfc817c1U, 0x7dc0bd63U, 0x748afe6aU, + 0x06666018U, 0xa52e8bbbU, 0x9397048dU, 0xd54297cbU, + 0x8ecc4290U, 0x15b2a70bU, 0x5367344dU, 0xe6be58f8U, + 0x8383009dU, 0xdd4895c3U, 0x1b3d2605U, 0x9ed84680U, + 0x3995ac27U, 0x49f9b057U, 0x82c3419cU, 0x47763159U, + 0xefaa45cbU, 0xf6f402d2U, 0x13697a37U, 0x4f226d6bU, + 0x87d85fa3U, 0x33417217U, 0x40edad64U, 0x6a4f254eU, + 0xec6a86c8U, 0x6e4a244aU, 0xe46084c0U, 0xbfee519bU, + 0x14acb830U, 0x5b33687fU, 0x04b8bc20U, 0xa0359584U, + 0x18a3bb3cU, 0x29dff60dU, 0xded608faU, 0x6d8ae749U, + 0x1ca6ba38U, 0x4e622c6aU, 0xa4309480U, 0xbbeb509fU, + 0x1e26383aU, 0xa570d581U, 0xf87b83dcU, 0x2c9ab608U, + 0x9149d8b5U, 0xaeba148aU, 0xac3a9688U, 0xd2d90bf6U, + 0xc6c80ee2U, 0xbd6ed399U, 0xf534c1d1U, 0x67006743U, + 0xf2f103d6U, 0x0b777c2fU, 0xd6dc0af2U, 0x5db6eb79U, + 0x78dba35cU, 0xe520c5c1U, 0x98039bbcU, 0xb96bd29dU, + 0x037d7e27U, 0x8bd75cafU, 0x06383e22U, 0x3dcef319U, + 0x27507703U, 0x7a5b215eU, 0xc4488ce0U, 0x12293b36U, + 0x93c95ab7U, 0x940c98b0U, 0x176c7b33U, 0xe2e507c6U, + 0xb6a41292U, 0xcb874cefU, 0xe6e006c2U, 0x5f36697bU, + 0x6185e445U, 0x8a971daeU, 0x48e7af6cU, 0x2e1a340aU, + 0xa97fd68dU, 0xa83f978cU, 0x2a1f350eU, 0x47286f63U, + 0x7b1b605fU, 0x799be25dU, 0xe86f87ccU, 0x5e76287aU, + 0xbaab119eU, 0xd119c8f5U, 0x44e8ac60U, 0xd05989f4U, + 0x2f5a750bU, 0xa2b51786U, 0x8957deadU, 0x162c3a32U, + 0x15ecf931U, 0x19e3fa3dU, 0xb2a11396U, 0x7e5e205aU, + 0x7191e055U, 0x25d0f501U, 0xdf9649fbU, 0x9a8319beU, + 0x573c6b73U, 0x1b63783fU, 0x88179facU, 0x9943dabdU, + 0x7594e151U, 0xed2ac7c9U, 0xc2cd0fe6U, 0x60c5a544U, + 0xcc428ee8U, 0x2490b400U, 0x8c129ea8U, 0xcd02cfe9U, + 0x39cbf21dU, 0xd51cc9f1U, 0xf3b142d7U, 0x3e0e301aU, + 0x2095b504U, 0x3c8eb218U, 0x45a8ed61U, 0x58f3ab7cU, + 0xb0219194U, 0x3081b114U, 0x55bce971U, 0xaabf158eU, + 0xe7a047c3U, 0xb4249090U, 0xad7ad789U, 0xe92fc6cdU, + 0xcac70deeU, 0xfbbb40dfU, 0x289fb70cU, 0xfd3ec3d9U, + 0x8558dda1U, 0x6ccaa648U, 0xbc2e9298U, 0x2b5f740fU, + 0x36043212U, 0xa7f05783U, 0x97cc5bb3U, 0xcec20ceaU, + 0x1f66793bU, 0x4a672d6eU, 0x9e8618baU, 0xffbe41dbU, + 0xb564d191U, 0xabff548fU, 0x54fca870U, 0x62452746U, + 0x3a0b311eU, 0x6b0f644fU, 0x7f1e615bU, 0x8fd25dabU, + 0x53396a77U, 0x31c1f015U, 0xe06585c4U, 0x32013316U, + 0x37447313U, 0x0e323c2aU, 0xc10dcce5U, 0x26103602U, + 0xdad309feU, 0x64c0a440U, 0xdc568af8U, 0xe125c4c5U, + 0x023d3f26U, 0xfafb01deU, 0x7cdea258U, 0x74d4a050U, + 0x63056647U, 0x86981ea2U, 0x72512356U, 0x3b4b701fU, + 0xc04d8de4U, 0x6f0a654bU, 0x3f4e711bU, 0x0cb2be28U, + 0xbeae109aU, 0x2ddaf709U, 0x9fc659bbU, 0x35c4f111U, + 0xb7e45393U, 0x10a9b934U, 0x388bb31cU, 0x1a23393eU, + 0x801d9da4U, 0xf93bc2ddU, 0x8d52dfa9U, 0x09f7fe2dU, + 0xe3a546c7U, 0xdb9348ffU, 0x68cfa74cU, 0xa175d485U, + 0xcf824debU, 0x432d6e67U, 0x8e921caaU, 0x08b7bf2cU, + 0xb82b939cU, 0x4b276c6fU, 0x1de6fb39U, 0x7d9ee359U, + 0x01fdfc25U, 0x05f8fd21U, 0xd913cafdU, 0xf131c0d5U, + 0x829d1fa6U, 0xd8538bfcU, 0x0a373d2eU, 0xfefe00daU, + 0x5a73297eU, 0xc38d4ee7U, 0x46682e62U, 0x49a7ee6dU, + 0xf07181d4U, 0xd3994af7U, 0xc508cde1U, 0xb161d095U, + 0xc8478fecU, 0xf47480d0U, 0xdd16cbf9U, 0xd79c4bf3U, + 0x9c069ab8U, 0xb3e15297U, 0x70d1a154U, 0x968c1ab2U, + 0x22153706U, 0x83dd5ea7U, 0x59b3ea7dU, 0x426d2f66U, + 0x00bdbd24U, 0x6580e541U, 0xf7b443d3U, 0xfc7e82d8U, + 0x567c2a72U, 0x23557607U, 0x66402642U, 0x76542252U, + 0x92891bb6U, 0x11e9f835U, 0xeaef05ceU, 0x9d46dbb9U, + 0x84189ca0U, 0xeeea04caU, 0x698fe64dU, 0x4da2ef69U, + 0x21d5f405U, 0x52792b76U, 0x73116257U, 0x900999b4U, + 0xa3f55687U, 0x0df2ff29U, 0xaffa558bU, 0xa6b01682U, + 0xd45c88f0U, 0x77146353U, 0x41adec65U, 0x07787f23U, + 0x5cf6aa78U, 0xc7884fe3U, 0x815ddca5U, 0x3484b010U, + 0x51b9e875U, 0x0f727d2bU, 0xc907ceedU, 0x4ce2ae68U, + 0xebaf44cfU, 0x9bc358bfU, 0x50f9a974U, 0x954cd9b1U, + 0x6d80ed63U, 0x74deaa7aU, 0x9143d29fU, 0xcd08c5c3U, + 0x05f2f70bU, 0xb16bdabfU, 0xc2c705ccU, 0xe8658de6U, + 0x6e402e60U, 0xec608ce2U, 0x664a2c68U, 0x3dc4f933U, + 0x96861098U, 0xd919c0d7U, 0x86921488U, 0x221f3d2cU, + 0x9a891394U, 0xabf55ea5U, 0x5cfca052U, 0xefa04fe1U, + 0x9e8c1290U, 0xcc4884c2U, 0x261a3c28U, 0x39c1f837U, + 0x9c0c9092U, 0x275a7d29U, 0x7a512b74U, 0xaeb01ea0U, + 0x1363701dU, 0x2c90bc22U, 0x2e103e20U, 0x50f3a35eU, + 0x44e2a64aU, 0x3f447b31U, 0x771e6979U, 0xe52acfebU, + 0x70dbab7eU, 0x895dd487U, 0x54f6a25aU, 0xdf9c43d1U, + 0xfaf10bf4U, 0x670a6d69U, 0x1a293314U, 0x3b417a35U, + 0x8157d68fU, 0x09fdf407U, 0x8412968aU, 0xbfe45bb1U, + 0xa57adfabU, 0xf87189f6U, 0x46622448U, 0x9003939eU, + 0x11e3f21fU, 0x16263018U, 0x9546d39bU, 0x60cfaf6eU, + 0x348eba3aU, 0x49ade447U, 0x64caae6aU, 0xdd1cc1d3U, + 0xe3af4cedU, 0x08bdb506U, 0xcacd07c4U, 0xac309ca2U, + 0x2b557e25U, 0x2a153f24U, 0xa8359da6U, 0xc502c7cbU, + 0xf931c8f7U, 0xfbb14af5U, 0x6a452f64U, 0xdc5c80d2U, + 0x3881b936U, 0x5333605dU, 0xc6c204c8U, 0x5273215cU, + 0xad70dda3U, 0x209fbf2eU, 0x0b7d7605U, 0x9406929aU, + 0x97c65199U, 0x9bc95295U, 0x308bbb3eU, 0xfc7488f2U, + 0xf3bb48fdU, 0xa7fa5da9U, 0x5dbce153U, 0x18a9b116U, + 0xd516c3dbU, 0x9949d097U, 0x0a3d3704U, 0x1b697215U, + 0xf7be49f9U, 0x6f006f61U, 0x40e7a74eU, 0xe2ef0decU, + 0x4e682640U, 0xa6ba1ca8U, 0x0e383600U, 0x4f286741U, + 0xbbe15ab5U, 0x57366159U, 0x719bea7fU, 0xbc2498b2U, + 0xa2bf1dacU, 0xbea41ab0U, 0xc78245c9U, 0xdad903d4U, + 0x320b393cU, 0xb2ab19bcU, 0xd79641d9U, 0x2895bd26U, + 0x658aef6bU, 0x360e3838U, 0x2f507f21U, 0x6b056e65U, + 0x48eda546U, 0x7991e877U, 0xaab51fa4U, 0x7f146b71U, + 0x07727509U, 0xeee00ee0U, 0x3e043a30U, 0xa975dca7U, + 0xb42e9abaU, 0x25daff2bU, 0x15e6f31bU, 0x4ce8a442U, + 0x9d4cd193U, 0xc84d85c6U, 0x1cacb012U, 0x7d94e973U, + 0x374e7939U, 0x29d5fc27U, 0xd6d600d8U, 0xe06f8feeU, + 0xb82199b6U, 0xe925cce7U, 0xfd34c9f3U, 0x0df8f503U, + 0xd113c2dfU, 0xb3eb58bdU, 0x624f2d6cU, 0xb02b9bbeU, + 0xb56edbbbU, 0x8c189482U, 0x4327644dU, 0xa43a9eaaU, + 0x58f9a156U, 0xe6ea0ce8U, 0x5e7c2250U, 0x630f6c6dU, + 0x8017978eU, 0x78d1a976U, 0xfef40af0U, 0xf6fe08f8U, + 0xe12fceefU, 0x04b2b60aU, 0xf07b8bfeU, 0xb961d8b7U, + 0x4267254cU, 0xed20cde3U, 0xbd64d9b3U, 0x8e981680U, + 0x3c84b832U, 0xaff05fa1U, 0x1decf113U, 0xb7ee59b9U, + 0x35cefb3bU, 0x9283119cU, 0xbaa11bb4U, 0x98099196U, + 0x0237350cU, 0x7b116a75U, 0x0f787701U, 0x8bdd5685U, + 0x618fee6fU, 0x59b9e057U, 0xeae50fe4U, 0x235f7c2dU, + 0x4da8e543U, 0xc107c6cfU, 0x0cb8b402U, 0x8a9d1784U, + 0x3a013b34U, 0xc90dc4c7U, 0x9fcc5391U, 0xffb44bf1U, + 0x83d7548dU, 0x87d25589U, 0x5b396255U, 0x731b687dU, + 0x00b7b70eU, 0x5a792354U, 0x881d9586U, 0x7cd4a872U, + 0xd85981d6U, 0x41a7e64fU, 0xc44286caU, 0xcb8d46c5U, + 0x725b297cU, 0x51b3e25fU, 0x47226549U, 0x334b783dU, + 0x4a6d2744U, 0x765e2878U, 0x5f3c6351U, 0x55b6e35bU, + 0x1e2c3210U, 0x31cbfa3fU, 0xf2fb09fcU, 0x14a6b21aU, + 0xa03f9faeU, 0x01f7f60fU, 0xdb9942d5U, 0xc04787ceU, + 0x8297158cU, 0xe7aa4de9U, 0x759eeb7bU, 0x7e542a70U, + 0xd45682daU, 0xa17fdeafU, 0xe46a8eeaU, 0xf47e8afaU, + 0x10a3b31eU, 0x93c3509dU, 0x68c5ad66U, 0x1f6c7311U, + 0x06323408U, 0x6cc0ac62U, 0xeba54ee5U, 0xcf8847c1U, + 0xa3ff5cadU, 0xd05383deU, 0xf13bcaffU, 0x1223311cU, + 0x21dffe2fU, 0x8fd85781U, 0x2dd0fd23U, 0x249abe2aU, + 0x56762058U, 0xf53ecbfbU, 0xc38744cdU, 0x8552d78bU, + 0xdedc02d0U, 0x45a2e74bU, 0x0377740dU, 0xb6ae18b8U, + 0xd39340ddU, 0x8d58d583U, 0x4b2d6645U, 0xcec806c0U, + 0x6985ec67U, 0x19e9f017U, 0xd2d301dcU, 0x17667119U, + 0x7dd1ac22U, 0x648feb3bU, 0x811293deU, 0xdd598482U, + 0x15a3b64aU, 0xa13a9bfeU, 0xd296448dU, 0xf834cca7U, + 0x7e116f21U, 0xfc31cda3U, 0x761b6d29U, 0x2d95b872U, + 0x86d751d9U, 0xc9488196U, 0x96c355c9U, 0x324e7c6dU, + 0x8ad852d5U, 0xbba41fe4U, 0x4cade113U, 0xfff10ea0U, + 0x8edd53d1U, 0xdc19c583U, 0x364b7d69U, 0x2990b976U, + 0x8c5dd1d3U, 0x370b3c68U, 0x6a006a35U, 0xbee15fe1U, + 0x0332315cU, 0x3cc1fd63U, 0x3e417f61U, 0x40a2e21fU, + 0x54b3e70bU, 0x2f153a70U, 0x674f2838U, 0xf57b8eaaU, + 0x608aea3fU, 0x990c95c6U, 0x44a7e31bU, 0xcfcd0290U, + 0xeaa04ab5U, 0x775b2c28U, 0x0a787255U, 0x2b103b74U, + 0x910697ceU, 0x19acb546U, 0x9443d7cbU, 0xafb51af0U, + 0xb52b9eeaU, 0xe820c8b7U, 0x56336509U, 0x8052d2dfU, + 0x01b2b35eU, 0x06777159U, 0x851792daU, 0x709eee2fU, + 0x24dffb7bU, 0x59fca506U, 0x749bef2bU, 0xcd4d8092U, + 0xf3fe0dacU, 0x18ecf447U, 0xda9c4685U, 0xbc61dde3U, + 0x3b043f64U, 0x3a447e65U, 0xb864dce7U, 0xd553868aU, + 0xe96089b6U, 0xebe00bb4U, 0x7a146e25U, 0xcc0dc193U, + 0x28d0f877U, 0x4362211cU, 0xd6934589U, 0x4222601dU, + 0xbd219ce2U, 0x30cefe6fU, 0x1b2c3744U, 0x8457d3dbU, + 0x879710d8U, 0x8b9813d4U, 0x20dafa7fU, 0xec25c9b3U, + 0xe3ea09bcU, 0xb7ab1ce8U, 0x4deda012U, 0x08f8f057U, + 0xc547829aU, 0x891891d6U, 0x1a6c7645U, 0x0b383354U, + 0xe7ef08b8U, 0x7f512e20U, 0x50b6e60fU, 0xf2be4cadU, + 0x5e396701U, 0xb6eb5de9U, 0x1e697741U, 0x5f792600U, + 0xabb01bf4U, 0x47672018U, 0x61caab3eU, 0xac75d9f3U, + 0xb2ee5cedU, 0xaef55bf1U, 0xd7d30488U, 0xca884295U, + 0x225a787dU, 0xa2fa58fdU, 0xc7c70098U, 0x38c4fc67U, + 0x75dbae2aU, 0x265f7979U, 0x3f013e60U, 0x7b542f24U, + 0x58bce407U, 0x69c0a936U, 0xbae45ee5U, 0x6f452a30U, + 0x17233448U, 0xfeb14fa1U, 0x2e557b71U, 0xb9249de6U, + 0xa47fdbfbU, 0x358bbe6aU, 0x05b7b25aU, 0x5cb9e503U, + 0x8d1d90d2U, 0xd81cc487U, 0x0cfdf153U, 0x6dc5a832U, + 0x271f3878U, 0x3984bd66U, 0xc6874199U, 0xf03eceafU, + 0xa870d8f7U, 0xf9748da6U, 0xed6588b2U, 0x1da9b442U, + 0xc142839eU, 0xa3ba19fcU, 0x721e6c2dU, 0xa07adaffU, + 0xa53f9afaU, 0x9c49d5c3U, 0x5376250cU, 0xb46bdfebU, + 0x48a8e017U, 0xf6bb4da9U, 0x4e2d6311U, 0x735e2d2cU, + 0x9046d6cfU, 0x6880e837U, 0xeea54bb1U, 0xe6af49b9U, + 0xf17e8faeU, 0x14e3f74bU, 0xe02acabfU, 0xa93099f6U, + 0x5236640dU, 0xfd718ca2U, 0xad3598f2U, 0x9ec957c1U, + 0x2cd5f973U, 0xbfa11ee0U, 0x0dbdb052U, 0xa7bf18f8U, + 0x259fba7aU, 0x82d250ddU, 0xaaf05af5U, 0x8858d0d7U, + 0x1266744dU, 0x6b402b34U, 0x1f293640U, 0x9b8c17c4U, + 0x71deaf2eU, 0x49e8a116U, 0xfab44ea5U, 0x330e3d6cU, + 0x5df9a402U, 0xd156878eU, 0x1ce9f543U, 0x9acc56c5U, + 0x2a507a75U, 0xd95c8586U, 0x8f9d12d0U, 0xefe50ab0U, + 0x938615ccU, 0x978314c8U, 0x4b682314U, 0x634a293cU, + 0x10e6f64fU, 0x4a286215U, 0x984cd4c7U, 0x6c85e933U, + 0xc808c097U, 0x51f6a70eU, 0xd413c78bU, 0xdbdc0784U, + 0x620a683dU, 0x41e2a31eU, 0x57732408U, 0x231a397cU, + 0x5a3c6605U, 0x660f6939U, 0x4f6d2210U, 0x45e7a21aU, + 0x0e7d7351U, 0x219abb7eU, 0xe2aa48bdU, 0x04f7f35bU, + 0xb06edeefU, 0x11a6b74eU, 0xcbc80394U, 0xd016c68fU, + 0x92c654cdU, 0xf7fb0ca8U, 0x65cfaa3aU, 0x6e056b31U, + 0xc407c39bU, 0xb12e9feeU, 0xf43bcfabU, 0xe42fcbbbU, + 0x00f2f25fU, 0x839211dcU, 0x7894ec27U, 0x0f3d3250U, + 0x16637549U, 0x7c91ed23U, 0xfbf40fa4U, 0xdfd90680U, + 0xb3ae1decU, 0xc002c29fU, 0xe16a8bbeU, 0x0272705dU, + 0x318ebf6eU, 0x9f8916c0U, 0x3d81bc62U, 0x34cbff6bU, + 0x46276119U, 0xe56f8abaU, 0xd3d6058cU, 0x950396caU, + 0xce8d4391U, 0x55f3a60aU, 0x1326354cU, 0xa6ff59f9U, + 0xc3c2019cU, 0x9d0994c2U, 0x5b7c2704U, 0xde994781U, + 0x79d4ad26U, 0x09b8b156U, 0xc282409dU, 0x07373058U, + 0xb4ec58d6U, 0xadb21fcfU, 0x482f672aU, 0x14647076U, + 0xdc9e42beU, 0x68076f0aU, 0x1babb079U, 0x31093853U, + 0xb72c9bd5U, 0x350c3957U, 0xbf2699ddU, 0xe4a84c86U, + 0x4feaa52dU, 0x00757562U, 0x5ffea13dU, 0xfb738899U, + 0x43e5a621U, 0x7299eb10U, 0x859015e7U, 0x36ccfa54U, + 0x47e0a725U, 0x15243177U, 0xff76899dU, 0xe0ad4d82U, + 0x45602527U, 0xfe36c89cU, 0xa33d9ec1U, 0x77dcab15U, + 0xca0fc5a8U, 0xf5fc0997U, 0xf77c8b95U, 0x899f16ebU, + 0x9d8e13ffU, 0xe628ce84U, 0xae72dcccU, 0x3c467a5eU, + 0xa9b71ecbU, 0x50316132U, 0x8d9a17efU, 0x06f0f664U, + 0x239dbe41U, 0xbe66d8dcU, 0xc34586a1U, 0xe22dcf80U, + 0x583b633aU, 0xd09141b2U, 0x5d7e233fU, 0x6688ee04U, + 0x7c166a1eU, 0x211d3c43U, 0x9f0e91fdU, 0x496f262bU, + 0xc88f47aaU, 0xcf4a85adU, 0x4c2a662eU, 0xb9a31adbU, + 0xede20f8fU, 0x90c151f2U, 0xbda61bdfU, 0x04707466U, + 0x3ac3f958U, 0xd1d100b3U, 0x13a1b271U, 0x755c2917U, + 0xf239cb90U, 0xf3798a91U, 0x71592813U, 0x1c6e727eU, + 0x205d7d42U, 0x22ddff40U, 0xb3299ad1U, 0x05303567U, + 0xe1ed0c83U, 0x8a5fd5e8U, 0x1faeb17dU, 0x8b1f94e9U, + 0x741c6816U, 0xf9f30a9bU, 0xd211c3b0U, 0x4d6a272fU, + 0x4eaae42cU, 0x42a5e720U, 0xe9e70e8bU, 0x25183d47U, + 0x2ad7fd48U, 0x7e96e81cU, 0x84d054e6U, 0xc1c504a3U, + 0x0c7a766eU, 0x40256522U, 0xd35182b1U, 0xc205c7a0U, + 0x2ed2fc4cU, 0xb66cdad4U, 0x998b12fbU, 0x3b83b859U, + 0x970493f5U, 0x7fd6a91dU, 0xd75483b5U, 0x9644d2f4U, + 0x628def00U, 0x8e5ad4ecU, 0xa8f75fcaU, 0x65482d07U, + 0x7bd3a819U, 0x67c8af05U, 0x1eeef07cU, 0x03b5b661U, + 0xeb678c89U, 0x6bc7ac09U, 0x0efaf46cU, 0xf1f90893U, + 0xbce65adeU, 0xef628d8dU, 0xf63cca94U, 0xb269dbd0U, + 0x918110f3U, 0xa0fd5dc2U, 0x73d9aa11U, 0xa678dec4U, + 0xde1ec0bcU, 0x378cbb55U, 0xe7688f85U, 0x70196912U, + 0x6d422f0fU, 0xfcb64a9eU, 0xcc8a46aeU, 0x958411f7U, + 0x44206426U, 0x11213073U, 0xc5c005a7U, 0xa4f85cc6U, + 0xee22cc8cU, 0xf0b94992U, 0x0fbab56dU, 0x39033a5bU, + 0x614d2c03U, 0x30497952U, 0x24587c46U, 0xd49440b6U, + 0x087f776aU, 0x6a87ed08U, 0xbb2398d9U, 0x69472e0bU, + 0x6c026e0eU, 0x55742137U, 0x9a4bd1f8U, 0x7d562b1fU, + 0x819514e3U, 0x3f86b95dU, 0x871097e5U, 0xba63d9d8U, + 0x597b223bU, 0xa1bd1cc3U, 0x2798bf45U, 0x2f92bd4dU, + 0x38437b5aU, 0xddde03bfU, 0x29173e4bU, 0x600d6d02U, + 0x9b0b90f9U, 0x344c7856U, 0x64086c06U, 0x57f4a335U, + 0xe5e80d87U, 0x769cea14U, 0xc48044a6U, 0x6e82ec0cU, + 0xeca24e8eU, 0x4befa429U, 0x63cdae01U, 0x41652423U, + 0xdb5b80b9U, 0xa27ddfc0U, 0xd614c2b4U, 0x52b1e330U, + 0xb8e35bdaU, 0x80d555e2U, 0x3389ba51U, 0xfa33c998U, + 0x94c450f6U, 0x186b737aU, 0xd5d401b7U, 0x53f1a231U, + 0xe36d8e81U, 0x10617172U, 0x46a0e624U, 0x26d8fe44U, + 0x5abbe138U, 0x5ebee03cU, 0x8255d7e0U, 0xaa77ddc8U, + 0xd9db02bbU, 0x831596e1U, 0x51712033U, 0xa5b81dc7U, + 0x01353463U, 0x98cb53faU, 0x1d2e337fU, 0x12e1f370U, + 0xab379cc9U, 0x88df57eaU, 0x9e4ed0fcU, 0xea27cd88U, + 0x930192f1U, 0xaf329dcdU, 0x8650d6e4U, 0x8cda56eeU, + 0xc74087a5U, 0xe8a74f8aU, 0x2b97bc49U, 0xcdca07afU, + 0x79532a1bU, 0xd89b43baU, 0x02f5f760U, 0x192b327bU, + 0x5bfba039U, 0x3ec6f85cU, 0xacf25eceU, 0xa7389fc5U, + 0x0d3a376fU, 0x78136b1aU, 0x3d063b5fU, 0x2d123f4fU, + 0xc9cf06abU, 0x4aafe528U, 0xb1a918d3U, 0xc600c6a4U, + 0xdf5e81bdU, 0xb5ac19d7U, 0x32c9fb50U, 0x16e4f274U, + 0x7a93e918U, 0x093f366bU, 0x28577f4aU, 0xcb4f84a9U, + 0xf8b34b9aU, 0x56b4e234U, 0xf4bc4896U, 0xfdf60b9fU, + 0x8f1a95edU, 0x2c527e4eU, 0x1aebf178U, 0x5c3e623eU, + 0x07b0b765U, 0x9cce52feU, 0xda1bc1b8U, 0x6fc2ad0dU, + 0x0afff568U, 0x54346036U, 0x9241d3f0U, 0x17a4b375U, + 0xb0e959d2U, 0xc08545a2U, 0x0bbfb469U, 0xce0ac4acU, + 0x63d7b43aU, 0x7a89f323U, 0x9f148bc6U, 0xc35f9c9aU, + 0x0ba5ae52U, 0xbf3c83e6U, 0xcc905c95U, 0xe632d4bfU, + 0x60177739U, 0xe237d5bbU, 0x681d7531U, 0x3393a06aU, + 0x98d149c1U, 0xd74e998eU, 0x88c54dd1U, 0x2c486475U, + 0x94de4acdU, 0xa5a207fcU, 0x52abf90bU, 0xe1f716b8U, + 0x90db4bc9U, 0xc21fdd9bU, 0x284d6571U, 0x3796a16eU, + 0x925bc9cbU, 0x290d2470U, 0x7406722dU, 0xa0e747f9U, + 0x1d342944U, 0x22c7e57bU, 0x20476779U, 0x5ea4fa07U, + 0x4ab5ff13U, 0x31132268U, 0x79493020U, 0xeb7d96b2U, + 0x7e8cf227U, 0x870a8ddeU, 0x5aa1fb03U, 0xd1cb1a88U, + 0xf4a652adU, 0x695d3430U, 0x147e6a4dU, 0x3516236cU, + 0x8f008fd6U, 0x07aaad5eU, 0x8a45cfd3U, 0xb1b302e8U, + 0xab2d86f2U, 0xf626d0afU, 0x48357d11U, 0x9e54cac7U, + 0x1fb4ab46U, 0x18716941U, 0x9b118ac2U, 0x6e98f637U, + 0x3ad9e363U, 0x47fabd1eU, 0x6a9df733U, 0xd34b988aU, + 0xedf815b4U, 0x06eaec5fU, 0xc49a5e9dU, 0xa267c5fbU, + 0x2502277cU, 0x2442667dU, 0xa662c4ffU, 0xcb559e92U, + 0xf76691aeU, 0xf5e613acU, 0x6412763dU, 0xd20bd98bU, + 0x36d6e06fU, 0x5d643904U, 0xc8955d91U, 0x5c247805U, + 0xa32784faU, 0x2ec8e677U, 0x052a2f5cU, 0x9a51cbc3U, + 0x999108c0U, 0x959e0bccU, 0x3edce267U, 0xf223d1abU, + 0xfdec11a4U, 0xa9ad04f0U, 0x53ebb80aU, 0x16fee84fU, + 0xdb419a82U, 0x971e89ceU, 0x046a6e5dU, 0x153e2b4cU, + 0xf9e910a0U, 0x61573638U, 0x4eb0fe17U, 0xecb854b5U, + 0x403f7f19U, 0xa8ed45f1U, 0x006f6f59U, 0x417f3e18U, + 0xb5b603ecU, 0x59613800U, 0x7fccb326U, 0xb273c1ebU, + 0xace844f5U, 0xb0f343e9U, 0xc9d51c90U, 0xd48e5a8dU, + 0x3c5c6065U, 0xbcfc40e5U, 0xd9c11880U, 0x26c2e47fU, + 0x6bddb632U, 0x38596161U, 0x21072678U, 0x6552373cU, + 0x46bafc1fU, 0x77c6b12eU, 0xa4e246fdU, 0x71433228U, + 0x09252c50U, 0xe0b757b9U, 0x30536369U, 0xa72285feU, + 0xba79c3e3U, 0x2b8da672U, 0x1bb1aa42U, 0x42bffd1bU, + 0x931b88caU, 0xc61adc9fU, 0x12fbe94bU, 0x73c3b02aU, + 0x39192060U, 0x2782a57eU, 0xd8815981U, 0xee38d6b7U, + 0xb676c0efU, 0xe77295beU, 0xf36390aaU, 0x03afac5aU, + 0xdf449b86U, 0xbdbc01e4U, 0x6c187435U, 0xbe7cc2e7U, + 0xbb3982e2U, 0x824fcddbU, 0x4d703d14U, 0xaa6dc7f3U, + 0x56aef80fU, 0xe8bd55b1U, 0x502b7b09U, 0x6d583534U, + 0x8e40ced7U, 0x7686f02fU, 0xf0a353a9U, 0xf8a951a1U, + 0xef7897b6U, 0x0ae5ef53U, 0xfe2cd2a7U, 0xb73681eeU, + 0x4c307c15U, 0xe37794baU, 0xb33380eaU, 0x80cf4fd9U, + 0x32d3e16bU, 0xa1a706f8U, 0x13bba84aU, 0xb9b900e0U, + 0x3b99a262U, 0x9cd448c5U, 0xb4f642edU, 0x965ec8cfU, + 0x0c606c55U, 0x7546332cU, 0x012f2e58U, 0x858a0fdcU, + 0x6fd8b736U, 0x57eeb90eU, 0xe4b256bdU, 0x2d082574U, + 0x43ffbc1aU, 0xcf509f96U, 0x02efed5bU, 0x84ca4eddU, + 0x3456626dU, 0xc75a9d9eU, 0x919b0ac8U, 0xf1e312a8U, + 0x8d800dd4U, 0x89850cd0U, 0x556e3b0cU, 0x7d4c3124U, + 0x0ee0ee57U, 0x542e7a0dU, 0x864accdfU, 0x7283f12bU, + 0xd60ed88fU, 0x4ff0bf16U, 0xca15df93U, 0xc5da1f9cU, + 0x7c0c7025U, 0x5fe4bb06U, 0x49753c10U, 0x3d1c2164U, + 0x443a7e1dU, 0x78097121U, 0x516b3a08U, 0x5be1ba02U, + 0x107b6b49U, 0x3f9ca366U, 0xfcac50a5U, 0x1af1eb43U, + 0xae68c6f7U, 0x0fa0af56U, 0xd5ce1b8cU, 0xce10de97U, + 0x8cc04cd5U, 0xe9fd14b0U, 0x7bc9b222U, 0x70037329U, + 0xda01db83U, 0xaf2887f6U, 0xea3dd7b3U, 0xfa29d3a3U, + 0x1ef4ea47U, 0x9d9409c4U, 0x6692f43fU, 0x113b2a48U, + 0x08656d51U, 0x6297f53bU, 0xe5f217bcU, 0xc1df1e98U, + 0xada805f4U, 0xde04da87U, 0xff6c93a6U, 0x1c746845U, + 0x2f88a776U, 0x818f0ed8U, 0x2387a47aU, 0x2acde773U, + 0x58217901U, 0xfb6992a2U, 0xcdd01d94U, 0x8b058ed2U, + 0xd08b5b89U, 0x4bf5be12U, 0x0d202d54U, 0xb8f941e1U, + 0xddc41984U, 0x830f8cdaU, 0x457a3f1cU, 0xc09f5f99U, + 0x67d2b53eU, 0x17bea94eU, 0xdc845885U, 0x19312840U, + 0xce5c921cU, 0xd702d505U, 0x329fade0U, 0x6ed4babcU, + 0xa62e8874U, 0x12b7a5c0U, 0x611b7ab3U, 0x4bb9f299U, + 0xcd9c511fU, 0x4fbcf39dU, 0xc5965317U, 0x9e18864cU, + 0x355a6fe7U, 0x7ac5bfa8U, 0x254e6bf7U, 0x81c34253U, + 0x39556cebU, 0x082921daU, 0xff20df2dU, 0x4c7c309eU, + 0x3d506defU, 0x6f94fbbdU, 0x85c64357U, 0x9a1d8748U, + 0x3fd0efedU, 0x84860256U, 0xd98d540bU, 0x0d6c61dfU, + 0xb0bf0f62U, 0x8f4cc35dU, 0x8dcc415fU, 0xf32fdc21U, + 0xe73ed935U, 0x9c98044eU, 0xd4c21606U, 0x46f6b094U, + 0xd307d401U, 0x2a81abf8U, 0xf72add25U, 0x7c403caeU, + 0x592d748bU, 0xc4d61216U, 0xb9f54c6bU, 0x989d054aU, + 0x228ba9f0U, 0xaa218b78U, 0x27cee9f5U, 0x1c3824ceU, + 0x06a6a0d4U, 0x5badf689U, 0xe5be5b37U, 0x33dfece1U, + 0xb23f8d60U, 0xb5fa4f67U, 0x369aace4U, 0xc313d011U, + 0x9752c545U, 0xea719b38U, 0xc716d115U, 0x7ec0beacU, + 0x40733392U, 0xab61ca79U, 0x691178bbU, 0x0fece3ddU, + 0x8889015aU, 0x89c9405bU, 0x0be9e2d9U, 0x66deb8b4U, + 0x5aedb788U, 0x586d358aU, 0xc999501bU, 0x7f80ffadU, + 0x9b5dc649U, 0xf0ef1f22U, 0x651e7bb7U, 0xf1af5e23U, + 0x0eaca2dcU, 0x8343c051U, 0xa8a1097aU, 0x37daede5U, + 0x341a2ee6U, 0x38152deaU, 0x9357c441U, 0x5fa8f78dU, + 0x50673782U, 0x042622d6U, 0xfe609e2cU, 0xbb75ce69U, + 0x76cabca4U, 0x3a95afe8U, 0xa9e1487bU, 0xb8b50d6aU, + 0x54623686U, 0xccdc101eU, 0xe33bd831U, 0x41337293U, + 0xedb4593fU, 0x056663d7U, 0xade4497fU, 0xecf4183eU, + 0x183d25caU, 0xf4ea1e26U, 0xd2479500U, 0x1ff8e7cdU, + 0x016362d3U, 0x1d7865cfU, 0x645e3ab6U, 0x79057cabU, + 0x91d74643U, 0x117766c3U, 0x744a3ea6U, 0x8b49c259U, + 0xc6569014U, 0x95d24747U, 0x8c8c005eU, 0xc8d9111aU, + 0xeb31da39U, 0xda4d9708U, 0x096960dbU, 0xdcc8140eU, + 0xa4ae0a76U, 0x4d3c719fU, 0x9dd8454fU, 0x0aa9a3d8U, + 0x17f2e5c5U, 0x86068054U, 0xb63a8c64U, 0xef34db3dU, + 0x3e90aeecU, 0x6b91fab9U, 0xbf70cf6dU, 0xde48960cU, + 0x94920646U, 0x8a098358U, 0x750a7fa7U, 0x43b3f091U, + 0x1bfde6c9U, 0x4af9b398U, 0x5ee8b68cU, 0xae248a7cU, + 0x72cfbda0U, 0x103727c2U, 0xc1935213U, 0x13f7e4c1U, + 0x16b2a4c4U, 0x2fc4ebfdU, 0xe0fb1b32U, 0x07e6e1d5U, + 0xfb25de29U, 0x45367397U, 0xfda05d2fU, 0xc0d31312U, + 0x23cbe8f1U, 0xdb0dd609U, 0x5d28758fU, 0x55227787U, + 0x42f3b190U, 0xa76ec975U, 0x53a7f481U, 0x1abda7c8U, + 0xe1bb5a33U, 0x4efcb29cU, 0x1eb8a6ccU, 0x2d4469ffU, + 0x9f58c74dU, 0x0c2c20deU, 0xbe308e6cU, 0x143226c6U, + 0x96128444U, 0x315f6ee3U, 0x197d64cbU, 0x3bd5eee9U, + 0xa1eb4a73U, 0xd8cd150aU, 0xaca4087eU, 0x280129faU, + 0xc2539110U, 0xfa659f28U, 0x4939709bU, 0x80830352U, + 0xee749a3cU, 0x62dbb9b0U, 0xaf64cb7dU, 0x294168fbU, + 0x99dd444bU, 0x6ad1bbb8U, 0x3c102ceeU, 0x5c68348eU, + 0x200b2bf2U, 0x240e2af6U, 0xf8e51d2aU, 0xd0c71702U, + 0xa36bc871U, 0xf9a55c2bU, 0x2bc1eaf9U, 0xdf08d70dU, + 0x7b85fea9U, 0xe27b9930U, 0x679ef9b5U, 0x685139baU, + 0xd1875603U, 0xf26f9d20U, 0xe4fe1a36U, 0x90970742U, + 0xe9b1583bU, 0xd5825707U, 0xfce01c2eU, 0xf66a9c24U, + 0xbdf04d6fU, 0x92178540U, 0x51277683U, 0xb77acd65U, + 0x03e3e0d1U, 0xa22b8970U, 0x78453daaU, 0x639bf8b1U, + 0x214b6af3U, 0x44763296U, 0xd6429404U, 0xdd88550fU, + 0x778afda5U, 0x02a3a1d0U, 0x47b6f195U, 0x57a2f585U, + 0xb37fcc61U, 0x301f2fe2U, 0xcb19d219U, 0xbcb00c6eU, + 0xa5ee4b77U, 0xcf1cd31dU, 0x4879319aU, 0x6c5438beU, + 0x002323d2U, 0x738ffca1U, 0x52e7b580U, 0xb1ff4e63U, + 0x82038150U, 0x2c0428feU, 0x8e0c825cU, 0x8746c155U, + 0xf5aa5f27U, 0x56e2b484U, 0x605b3bb2U, 0x268ea8f4U, + 0x7d007dafU, 0xe67e9834U, 0xa0ab0b72U, 0x157267c7U, + 0x704f3fa2U, 0x2e84aafcU, 0xe8f1193aU, 0x6d1479bfU, + 0xca599318U, 0xba358f68U, 0x710f7ea3U, 0xb4ba0e66U, + 0x712e5fd1U, 0x687018c8U, 0x8ded602dU, 0xd1a67771U, + 0x195c45b9U, 0xadc5680dU, 0xde69b77eU, 0xf4cb3f54U, + 0x72ee9cd2U, 0xf0ce3e50U, 0x7ae49edaU, 0x216a4b81U, + 0x8a28a22aU, 0xc5b77265U, 0x9a3ca63aU, 0x3eb18f9eU, + 0x8627a126U, 0xb75bec17U, 0x405212e0U, 0xf30efd53U, + 0x8222a022U, 0xd0e63670U, 0x3ab48e9aU, 0x256f4a85U, + 0x80a22220U, 0x3bf4cf9bU, 0x66ff99c6U, 0xb21eac12U, + 0x0fcdc2afU, 0x303e0e90U, 0x32be8c92U, 0x4c5d11ecU, + 0x584c14f8U, 0x23eac983U, 0x6bb0dbcbU, 0xf9847d59U, + 0x6c7519ccU, 0x95f36635U, 0x485810e8U, 0xc332f163U, + 0xe65fb946U, 0x7ba4dfdbU, 0x068781a6U, 0x27efc887U, + 0x9df9643dU, 0x155346b5U, 0x98bc2438U, 0xa34ae903U, + 0xb9d46d19U, 0xe4df3b44U, 0x5acc96faU, 0x8cad212cU, + 0x0d4d40adU, 0x0a8882aaU, 0x89e86129U, 0x7c611ddcU, + 0x28200888U, 0x550356f5U, 0x78641cd8U, 0xc1b27361U, + 0xff01fe5fU, 0x141307b4U, 0xd663b576U, 0xb09e2e10U, + 0x37fbcc97U, 0x36bb8d96U, 0xb49b2f14U, 0xd9ac7579U, + 0xe59f7a45U, 0xe71ff847U, 0x76eb9dd6U, 0xc0f23260U, + 0x242f0b84U, 0x4f9dd2efU, 0xda6cb67aU, 0x4edd93eeU, + 0xb1de6f11U, 0x3c310d9cU, 0x17d3c4b7U, 0x88a82028U, + 0x8b68e32bU, 0x8767e027U, 0x2c25098cU, 0xe0da3a40U, + 0xef15fa4fU, 0xbb54ef1bU, 0x411253e1U, 0x040703a4U, + 0xc9b87169U, 0x85e76225U, 0x169385b6U, 0x07c7c0a7U, + 0xeb10fb4bU, 0x73aeddd3U, 0x5c4915fcU, 0xfe41bf5eU, + 0x52c694f2U, 0xba14ae1aU, 0x129684b2U, 0x5386d5f3U, + 0xa74fe807U, 0x4b98d3ebU, 0x6d3558cdU, 0xa08a2a00U, + 0xbe11af1eU, 0xa20aa802U, 0xdb2cf77bU, 0xc677b166U, + 0x2ea58b8eU, 0xae05ab0eU, 0xcb38f36bU, 0x343b0f94U, + 0x79245dd9U, 0x2aa08a8aU, 0x33fecd93U, 0x77abdcd7U, + 0x544317f4U, 0x653f5ac5U, 0xb61bad16U, 0x63bad9c3U, + 0x1bdcc7bbU, 0xf24ebc52U, 0x22aa8882U, 0xb5db6e15U, + 0xa8802808U, 0x39744d99U, 0x094841a9U, 0x504616f0U, + 0x81e26321U, 0xd4e33774U, 0x000202a0U, 0x613a5bc1U, + 0x2be0cb8bU, 0x357b4e95U, 0xca78b26aU, 0xfcc13d5cU, + 0xa48f2b04U, 0xf58b7e55U, 0xe19a7b41U, 0x115647b1U, + 0xcdbd706dU, 0xaf45ea0fU, 0x7ee19fdeU, 0xac85290cU, + 0xa9c06909U, 0x90b62630U, 0x5f89d6ffU, 0xb8942c18U, + 0x445713e4U, 0xfa44be5aU, 0x42d290e2U, 0x7fa1dedfU, + 0x9cb9253cU, 0x647f1bc4U, 0xe25ab842U, 0xea50ba4aU, + 0xfd817c5dU, 0x181c04b8U, 0xecd5394cU, 0xa5cf6a05U, + 0x5ec997feU, 0xf18e7f51U, 0xa1ca6b01U, 0x9236a432U, + 0x202a0a80U, 0xb35eed13U, 0x014243a1U, 0xab40eb0bU, + 0x29604989U, 0x8e2da32eU, 0xa60fa906U, 0x84a72324U, + 0x1e9987beU, 0x67bfd8c7U, 0x13d6c5b3U, 0x9773e437U, + 0x7d215cddU, 0x451752e5U, 0xf64bbd56U, 0x3ff1ce9fU, + 0x510657f1U, 0xdda9747dU, 0x101606b0U, 0x9633a536U, + 0x26af8986U, 0xd5a37675U, 0x8362e123U, 0xe31af943U, + 0x9f79e63fU, 0x9b7ce73bU, 0x4797d0e7U, 0x6fb5dacfU, + 0x1c1905bcU, 0x46d791e6U, 0x94b32734U, 0x607a1ac0U, + 0xc4f73364U, 0x5d0954fdU, 0xd8ec3478U, 0xd723f477U, + 0x6ef59bceU, 0x4d1d50edU, 0x5b8cd7fbU, 0x2fe5ca8fU, + 0x56c395f6U, 0x6af09acaU, 0x4392d1e3U, 0x491851e9U, + 0x028280a2U, 0x2d65488dU, 0xee55bb4eU, 0x080800a8U, + 0xbc912d1cU, 0x1d5944bdU, 0xc737f067U, 0xdce9357cU, + 0x9e39a73eU, 0xfb04ff5bU, 0x693059c9U, 0x62fa98c2U, + 0xc8f83068U, 0xbdd16c1dU, 0xf8c43c58U, 0xe8d03848U, + 0x0c0d01acU, 0x8f6de22fU, 0x746b1fd4U, 0x03c2c1a3U, + 0x1a9c86baU, 0x706e1ed0U, 0xf70bfc57U, 0xd326f573U, + 0xbf51ee1fU, 0xccfd316cU, 0xed95784dU, 0x0e8d83aeU, + 0x3d714c9dU, 0x9376e533U, 0x317e4f91U, 0x38340c98U, + 0x4ad892eaU, 0xe9907949U, 0xdf29f67fU, 0x99fc6539U, + 0xc272b062U, 0x590c55f9U, 0x1fd9c6bfU, 0xaa00aa0aU, + 0xcf3df26fU, 0x91f66731U, 0x5783d4f7U, 0xd266b472U, + 0x752b5ed5U, 0x054742a5U, 0xce7db36eU, 0x0bc8c3abU, + 0xeaab41cfU, 0xf3f506d6U, 0x16687e33U, 0x4a23696fU, + 0x82d95ba7U, 0x36407613U, 0x45eca960U, 0x6f4e214aU, + 0xe96b82ccU, 0x6b4b204eU, 0xe16180c4U, 0xbaef559fU, + 0x11adbc34U, 0x5e326c7bU, 0x01b9b824U, 0xa5349180U, + 0x1da2bf38U, 0x2cdef209U, 0xdbd70cfeU, 0x688be34dU, + 0x19a7be3cU, 0x4b63286eU, 0xa1319084U, 0xbeea549bU, + 0x1b273c3eU, 0xa071d185U, 0xfd7a87d8U, 0x299bb20cU, + 0x9448dcb1U, 0xabbb108eU, 0xa93b928cU, 0xd7d80ff2U, + 0xc3c90ae6U, 0xb86fd79dU, 0xf035c5d5U, 0x62016347U, + 0xf7f007d2U, 0x0e76782bU, 0xd3dd0ef6U, 0x58b7ef7dU, + 0x7ddaa758U, 0xe021c1c5U, 0x9d029fb8U, 0xbc6ad699U, + 0x067c7a23U, 0x8ed658abU, 0x03393a26U, 0x38cff71dU, + 0x22517307U, 0x7f5a255aU, 0xc14988e4U, 0x17283f32U, + 0x96c85eb3U, 0x910d9cb4U, 0x126d7f37U, 0xe7e403c2U, + 0xb3a51696U, 0xce8648ebU, 0xe3e102c6U, 0x5a376d7fU, + 0x6484e041U, 0x8f9619aaU, 0x4de6ab68U, 0x2b1b300eU, + 0xac7ed289U, 0xad3e9388U, 0x2f1e310aU, 0x42296b67U, + 0x7e1a645bU, 0x7c9ae659U, 0xed6e83c8U, 0x5b772c7eU, + 0xbfaa159aU, 0xd418ccf1U, 0x41e9a864U, 0xd5588df0U, + 0x2a5b710fU, 0xa7b41382U, 0x8c56daa9U, 0x132d3e36U, + 0x10edfd35U, 0x1ce2fe39U, 0xb7a01792U, 0x7b5f245eU, + 0x7490e451U, 0x20d1f105U, 0xda974dffU, 0x9f821dbaU, + 0x523d6f77U, 0x1e627c3bU, 0x8d169ba8U, 0x9c42deb9U, + 0x7095e555U, 0xe82bc3cdU, 0xc7cc0be2U, 0x65c4a140U, + 0xc9438aecU, 0x2191b004U, 0x89139aacU, 0xc803cbedU, + 0x3ccaf619U, 0xd01dcdf5U, 0xf6b046d3U, 0x3b0f341eU, + 0x2594b100U, 0x398fb61cU, 0x40a9e965U, 0x5df2af78U, + 0xb5209590U, 0x3580b510U, 0x50bded75U, 0xafbe118aU, + 0xe2a143c7U, 0xb1259494U, 0xa87bd38dU, 0xec2ec2c9U, + 0xcfc609eaU, 0xfeba44dbU, 0x2d9eb308U, 0xf83fc7ddU, + 0x8059d9a5U, 0x69cba24cU, 0xb92f969cU, 0x2e5e700bU, + 0x33053616U, 0xa2f15387U, 0x92cd5fb7U, 0xcbc308eeU, + 0x1a677d3fU, 0x4f66296aU, 0x9b871cbeU, 0xfabf45dfU, + 0xb065d595U, 0xaefe508bU, 0x51fdac74U, 0x67442342U, + 0x3f0a351aU, 0x6e0e604bU, 0x7a1f655fU, 0x8ad359afU, + 0x56386e73U, 0x34c0f411U, 0xe56481c0U, 0x37003712U, + 0x32457717U, 0x0b33382eU, 0xc40cc8e1U, 0x23113206U, + 0xdfd20dfaU, 0x61c1a044U, 0xd9578efcU, 0xe424c0c1U, + 0x073c3b22U, 0xfffa05daU, 0x79dfa65cU, 0x71d5a454U, + 0x66046243U, 0x83991aa6U, 0x77502752U, 0x3e4a741bU, + 0xc54c89e0U, 0x6a0b614fU, 0x3a4f751fU, 0x09b3ba2cU, + 0xbbaf149eU, 0x28dbf30dU, 0x9ac75dbfU, 0x30c5f515U, + 0xb2e55797U, 0x15a8bd30U, 0x3d8ab718U, 0x1f223d3aU, + 0x851c99a0U, 0xfc3ac6d9U, 0x8853dbadU, 0x0cf6fa29U, + 0xe6a442c3U, 0xde924cfbU, 0x6dcea348U, 0xa474d081U, + 0xca8349efU, 0x462c6a63U, 0x8b9318aeU, 0x0db6bb28U, + 0xbd2a9798U, 0x4e26686bU, 0x18e7ff3dU, 0x789fe75dU, + 0x04fcf821U, 0x00f9f925U, 0xdc12cef9U, 0xf430c4d1U, + 0x879c1ba2U, 0xdd528ff8U, 0x0f36392aU, 0xfbff04deU, + 0x5f722d7aU, 0xc68c4ae3U, 0x43692a66U, 0x4ca6ea69U, + 0xf57085d0U, 0xd6984ef3U, 0xc009c9e5U, 0xb460d491U, + 0xcd468be8U, 0xf17584d4U, 0xd817cffdU, 0xd29d4ff7U, + 0x99079ebcU, 0xb6e05693U, 0x75d0a550U, 0x938d1eb6U, + 0x27143302U, 0x86dc5aa3U, 0x5cb2ee79U, 0x476c2b62U, + 0x05bcb920U, 0x6081e145U, 0xf2b547d7U, 0xf97f86dcU, + 0x537d2e76U, 0x26547203U, 0x63412246U, 0x73552656U, + 0x97881fb2U, 0x14e8fc31U, 0xefee01caU, 0x9847dfbdU, + 0x811998a4U, 0xebeb00ceU, 0x6c8ee249U, 0x48a3eb6dU, + 0x24d4f001U, 0x57782f72U, 0x76106653U, 0x95089db0U, + 0xa6f45283U, 0x08f3fb2dU, 0xaafb518fU, 0xa3b11286U, + 0xd15d8cf4U, 0x72156757U, 0x44ace861U, 0x02797b27U, + 0x59f7ae7cU, 0xc2894be7U, 0x845cd8a1U, 0x3185b414U, + 0x54b8ec71U, 0x0a73792fU, 0xcc06cae9U, 0x49e3aa6cU, + 0xeeae40cbU, 0x9ec25cbbU, 0x55f8ad70U, 0x904dddb5U, + 0xf1ac5dd3U, 0xe8f21acaU, 0x0d6f622fU, 0x51247573U, + 0x99de47bbU, 0x2d476a0fU, 0x5eebb57cU, 0x74493d56U, + 0xf26c9ed0U, 0x704c3c52U, 0xfa669cd8U, 0xa1e84983U, + 0x0aaaa028U, 0x45357067U, 0x1abea438U, 0xbe338d9cU, + 0x06a5a324U, 0x37d9ee15U, 0xc0d010e2U, 0x738cff51U, + 0x02a0a220U, 0x50643472U, 0xba368c98U, 0xa5ed4887U, + 0x00202022U, 0xbb76cd99U, 0xe67d9bc4U, 0x329cae10U, + 0x8f4fc0adU, 0xb0bc0c92U, 0xb23c8e90U, 0xccdf13eeU, + 0xd8ce16faU, 0xa368cb81U, 0xeb32d9c9U, 0x79067f5bU, + 0xecf71bceU, 0x15716437U, 0xc8da12eaU, 0x43b0f361U, + 0x66ddbb44U, 0xfb26ddd9U, 0x860583a4U, 0xa76dca85U, + 0x1d7b663fU, 0x95d144b7U, 0x183e263aU, 0x23c8eb01U, + 0x39566f1bU, 0x645d3946U, 0xda4e94f8U, 0x0c2f232eU, + 0x8dcf42afU, 0x8a0a80a8U, 0x096a632bU, 0xfce31fdeU, + 0xa8a20a8aU, 0xd58154f7U, 0xf8e61edaU, 0x41307163U, + 0x7f83fc5dU, 0x949105b6U, 0x56e1b774U, 0x301c2c12U, + 0xb779ce95U, 0xb6398f94U, 0x34192d16U, 0x592e777bU, + 0x651d7847U, 0x679dfa45U, 0xf6699fd4U, 0x40703062U, + 0xa4ad0986U, 0xcf1fd0edU, 0x5aeeb478U, 0xce5f91ecU, + 0x315c6d13U, 0xbcb30f9eU, 0x9751c6b5U, 0x082a222aU, + 0x0beae129U, 0x07e5e225U, 0xaca70b8eU, 0x60583842U, + 0x6f97f84dU, 0x3bd6ed19U, 0xc19051e3U, 0x848501a6U, + 0x493a736bU, 0x05656027U, 0x961187b4U, 0x8745c2a5U, + 0x6b92f949U, 0xf32cdfd1U, 0xdccb17feU, 0x7ec3bd5cU, + 0xd24496f0U, 0x3a96ac18U, 0x921486b0U, 0xd304d7f1U, + 0x27cdea05U, 0xcb1ad1e9U, 0xedb75acfU, 0x20082802U, + 0x3e93ad1cU, 0x2288aa00U, 0x5baef579U, 0x46f5b364U, + 0xae27898cU, 0x2e87a90cU, 0x4bbaf169U, 0xb4b90d96U, + 0xf9a65fdbU, 0xaa228888U, 0xb37ccf91U, 0xf729ded5U, + 0xd4c115f6U, 0xe5bd58c7U, 0x3699af14U, 0xe338dbc1U, + 0x9b5ec5b9U, 0x72ccbe50U, 0xa2288a80U, 0x35596c17U, + 0x28022a0aU, 0xb9f64f9bU, 0x89ca43abU, 0xd0c414f2U, + 0x01606123U, 0x54613576U, 0x808000a2U, 0xe1b859c3U, + 0xab62c989U, 0xb5f94c97U, 0x4afab068U, 0x7c433f5eU, + 0x240d2906U, 0x75097c57U, 0x61187943U, 0x91d445b3U, + 0x4d3f726fU, 0x2fc7e80dU, 0xfe639ddcU, 0x2c072b0eU, + 0x29426b0bU, 0x10342432U, 0xdf0bd4fdU, 0x38162e1aU, + 0xc4d511e6U, 0x7ac6bc58U, 0xc25092e0U, 0xff23dcddU, + 0x1c3b273eU, 0xe4fd19c6U, 0x62d8ba40U, 0x6ad2b848U, + 0x7d037e5fU, 0x989e06baU, 0x6c573b4eU, 0x254d6807U, + 0xde4b95fcU, 0x710c7d53U, 0x21486903U, 0x12b4a630U, + 0xa0a80882U, 0x33dcef11U, 0x81c041a3U, 0x2bc2e909U, + 0xa9e24b8bU, 0x0eafa12cU, 0x268dab04U, 0x04252126U, + 0x9e1b85bcU, 0xe73ddac5U, 0x9354c7b1U, 0x17f1e635U, + 0xfda35edfU, 0xc59550e7U, 0x76c9bf54U, 0xbf73cc9dU, + 0xd18455f3U, 0x5d2b767fU, 0x909404b2U, 0x16b1a734U, + 0xa62d8b84U, 0x55217477U, 0x03e0e321U, 0x6398fb41U, + 0x1ffbe43dU, 0x1bfee539U, 0xc715d2e5U, 0xef37d8cdU, + 0x9c9b07beU, 0xc65593e4U, 0x14312536U, 0xe0f818c2U, + 0x44753166U, 0xdd8b56ffU, 0x586e367aU, 0x57a1f675U, + 0xee7799ccU, 0xcd9f52efU, 0xdb0ed5f9U, 0xaf67c88dU, + 0xd64197f4U, 0xea7298c8U, 0xc310d3e1U, 0xc99a53ebU, + 0x820082a0U, 0xade74a8fU, 0x6ed7b94cU, 0x888a02aaU, + 0x3c132f1eU, 0x9ddb46bfU, 0x47b5f265U, 0x5c6b377eU, + 0x1ebba53cU, 0x7b86fd59U, 0xe9b25bcbU, 0xe2789ac0U, + 0x487a326aU, 0x3d536e1fU, 0x78463e5aU, 0x68523a4aU, + 0x8c8f03aeU, 0x0fefe02dU, 0xf4e91dd6U, 0x8340c3a1U, + 0x9a1e84b8U, 0xf0ec1cd2U, 0x7789fe55U, 0x53a4f771U, + 0x3fd3ec1dU, 0x4c7f336eU, 0x6d177a4fU, 0x8e0f81acU, + 0xbdf34e9fU, 0x13f4e731U, 0xb1fc4d93U, 0xb8b60e9aU, + 0xca5a90e8U, 0x69127b4bU, 0x5fabf47dU, 0x197e673bU, + 0x42f0b260U, 0xd98e57fbU, 0x9f5bc4bdU, 0x2a82a808U, + 0x4fbff06dU, 0x11746533U, 0xd701d6f5U, 0x52e4b670U, + 0xf5a95cd7U, 0x85c540a7U, 0x4effb16cU, 0x8b4ac1a9U, + 0xd7f324aaU, 0xcead63b3U, 0x2b301b56U, 0x777b0c0aU, + 0xbf813ec2U, 0x0b181376U, 0x78b4cc05U, 0x5216442fU, + 0xd433e7a9U, 0x5613452bU, 0xdc39e5a1U, 0x87b730faU, + 0x2cf5d951U, 0x636a091eU, 0x3ce1dd41U, 0x986cf4e5U, + 0x20fada5dU, 0x1186976cU, 0xe68f699bU, 0x55d38628U, + 0x24ffdb59U, 0x763b4d0bU, 0x9c69f5e1U, 0x83b231feU, + 0x267f595bU, 0x9d29b4e0U, 0xc022e2bdU, 0x14c3d769U, + 0xa910b9d4U, 0x96e375ebU, 0x9463f7e9U, 0xea806a97U, + 0xfe916f83U, 0x8537b2f8U, 0xcd6da0b0U, 0x5f590622U, + 0xcaa862b7U, 0x332e1d4eU, 0xee856b93U, 0x65ef8a18U, + 0x4082c23dU, 0xdd79a4a0U, 0xa05afaddU, 0x8132b3fcU, + 0x3b241f46U, 0xb38e3dceU, 0x3e615f43U, 0x05979278U, + 0x1f091662U, 0x4202403fU, 0xfc11ed81U, 0x2a705a57U, + 0xab903bd6U, 0xac55f9d1U, 0x2f351a52U, 0xdabc66a7U, + 0x8efd73f3U, 0xf3de2d8eU, 0xdeb967a3U, 0x676f081aU, + 0x59dc8524U, 0xb2ce7ccfU, 0x70bece0dU, 0x1643556bU, + 0x9126b7ecU, 0x9066f6edU, 0x1246546fU, 0x7f710e02U, + 0x4342013eU, 0x41c2833cU, 0xd036e6adU, 0x662f491bU, + 0x82f270ffU, 0xe940a994U, 0x7cb1cd01U, 0xe800e895U, + 0x1703146aU, 0x9aec76e7U, 0xb10ebfccU, 0x2e755b53U, + 0x2db59850U, 0x21ba9b5cU, 0x8af872f7U, 0x4607413bU, + 0x49c88134U, 0x1d899460U, 0xe7cf289aU, 0xa2da78dfU, + 0x6f650a12U, 0x233a195eU, 0xb04efecdU, 0xa11abbdcU, + 0x4dcd8030U, 0xd573a6a8U, 0xfa946e87U, 0x589cc425U, + 0xf41bef89U, 0x1cc9d561U, 0xb44bffc9U, 0xf55bae88U, + 0x0192937cU, 0xed45a890U, 0xcbe823b6U, 0x0657517bU, + 0x18ccd465U, 0x04d7d379U, 0x7df18c00U, 0x60aaca1dU, + 0x8878f0f5U, 0x08d8d075U, 0x6de58810U, 0x92e674efU, + 0xdff926a2U, 0x8c7df1f1U, 0x9523b6e8U, 0xd176a7acU, + 0xf29e6c8fU, 0xc3e221beU, 0x10c6d66dU, 0xc567a2b8U, + 0xbd01bcc0U, 0x5493c729U, 0x8477f3f9U, 0x1306156eU, + 0x0e5d5373U, 0x9fa936e2U, 0xaf953ad2U, 0xf69b6d8bU, + 0x273f185aU, 0x723e4c0fU, 0xa6df79dbU, 0xc7e720baU, + 0x8d3db0f0U, 0x93a635eeU, 0x6ca5c911U, 0x5a1c4627U, + 0x0252507fU, 0x5356052eU, 0x4747003aU, 0xb78b3ccaU, + 0x6b600b16U, 0x09989174U, 0xd83ce4a5U, 0x0a585277U, + 0x0f1d1272U, 0x366b5d4bU, 0xf954ad84U, 0x1e495763U, + 0xe28a689fU, 0x5c99c521U, 0xe40feb99U, 0xd97ca5a4U, + 0x3a645e47U, 0xc2a260bfU, 0x4487c339U, 0x4c8dc131U, + 0x5b5c0726U, 0xbec17fc3U, 0x4a084237U, 0x0312117eU, + 0xf814ec85U, 0x5753042aU, 0x0717107aU, 0x34ebdf49U, + 0x86f771fbU, 0x15839668U, 0xa79f38daU, 0x0d9d9070U, + 0x8fbd32f2U, 0x28f0d855U, 0x00d2d27dU, 0x227a585fU, + 0xb844fcc5U, 0xc162a3bcU, 0xb50bbec8U, 0x31ae9f4cU, + 0xdbfc27a6U, 0xe3ca299eU, 0x5096c62dU, 0x992cb5e4U, + 0xf7db2c8aU, 0x7b740f06U, 0xb6cb7dcbU, 0x30eede4dU, + 0x8072f2fdU, 0x737e0d0eU, 0x25bf9a58U, 0x45c78238U, + 0x39a49d44U, 0x3da19c40U, 0xe14aab9cU, 0xc968a1b4U, + 0xbac47ec7U, 0xe00aea9dU, 0x326e5c4fU, 0xc6a761bbU, + 0x622a481fU, 0xfbd42f86U, 0x7e314f03U, 0x71fe8f0cU, + 0xc828e0b5U, 0xebc02b96U, 0xfd51ac80U, 0x8938b1f4U, + 0xf01eee8dU, 0xcc2de1b1U, 0xe54faa98U, 0xefc52a92U, + 0xa45ffbd9U, 0x8bb833f6U, 0x4888c035U, 0xaed57bd3U, + 0x1a4c5667U, 0xbb843fc6U, 0x61ea8b1cU, 0x7a344e07U, + 0x38e4dc45U, 0x5dd98420U, 0xcfed22b2U, 0xc427e3b9U, + 0x6e254b13U, 0x1b0c1766U, 0x5e194723U, 0x4e0d4333U, + 0xaad07ad7U, 0x29b09954U, 0xd2b664afU, 0xa51fbad8U, + 0xbc41fdc1U, 0xd6b365abU, 0x51d6872cU, 0x75fb8e08U, + 0x198c9564U, 0x6a204a17U, 0x4b480336U, 0xa850f8d5U, + 0x9bac37e6U, 0x35ab9e48U, 0x97a334eaU, 0x9ee977e3U, + 0xec05e991U, 0x4f4d0232U, 0x79f48d04U, 0x3f211e42U, + 0x64afcb19U, 0xffd12e82U, 0xb904bdc4U, 0x0cddd171U, + 0x69e08914U, 0x372b1c4aU, 0xf15eaf8cU, 0x74bbcf09U, + 0xd3f625aeU, 0xa39a39deU, 0x68a0c815U, 0xad15b8d0U, + 0x8cb539b7U, 0x95eb7eaeU, 0x7076064bU, 0x2c3d1117U, + 0xe4c723dfU, 0x505e0e6bU, 0x23f2d118U, 0x09505932U, + 0x8f75fab4U, 0x0d555836U, 0x877ff8bcU, 0xdcf12de7U, + 0x77b3c44cU, 0x382c1403U, 0x67a7c05cU, 0xc32ae9f8U, + 0x7bbcc740U, 0x4ac08a71U, 0xbdc97486U, 0x0e959b35U, + 0x7fb9c644U, 0x2d7d5016U, 0xc72fe8fcU, 0xd8f42ce3U, + 0x7d394446U, 0xc66fa9fdU, 0x9b64ffa0U, 0x4f85ca74U, + 0xf256a4c9U, 0xcda568f6U, 0xcf25eaf4U, 0xb1c6778aU, + 0xa5d7729eU, 0xde71afe5U, 0x962bbdadU, 0x041f1b3fU, + 0x91ee7faaU, 0x68680053U, 0xb5c3768eU, 0x3ea99705U, + 0x1bc4df20U, 0x863fb9bdU, 0xfb1ce7c0U, 0xda74aee1U, + 0x6062025bU, 0xe8c820d3U, 0x6527425eU, 0x5ed18f65U, + 0x444f0b7fU, 0x19445d22U, 0xa757f09cU, 0x7136474aU, + 0xf0d626cbU, 0xf713e4ccU, 0x7473074fU, 0x81fa7bbaU, + 0xd5bb6eeeU, 0xa8983093U, 0x85ff7abeU, 0x3c291507U, + 0x029a9839U, 0xe98861d2U, 0x2bf8d310U, 0x4d054876U, + 0xca60aaf1U, 0xcb20ebf0U, 0x49004972U, 0x2437131fU, + 0x18041c23U, 0x1a849e21U, 0x8b70fbb0U, 0x3d695406U, + 0xd9b46de2U, 0xb206b489U, 0x27f7d01cU, 0xb346f588U, + 0x4c450977U, 0xc1aa6bfaU, 0xea48a2d1U, 0x7533464eU, + 0x76f3854dU, 0x7afc8641U, 0xd1be6feaU, 0x1d415c26U, + 0x128e9c29U, 0x46cf897dU, 0xbc893587U, 0xf99c65c2U, + 0x3423170fU, 0x787c0443U, 0xeb08e3d0U, 0xfa5ca6c1U, + 0x168b9d2dU, 0x8e35bbb5U, 0xa1d2739aU, 0x03dad938U, + 0xaf5df294U, 0x478fc87cU, 0xef0de2d4U, 0xae1db395U, + 0x5ad48e61U, 0xb603b58dU, 0x90ae3eabU, 0x5d114c66U, + 0x438ac978U, 0x5f91ce64U, 0x26b7911dU, 0x3becd700U, + 0xd33eede8U, 0x539ecd68U, 0x36a3950dU, 0xc9a069f2U, + 0x84bf3bbfU, 0xd73bececU, 0xce65abf5U, 0x8a30bab1U, + 0xa9d87192U, 0x98a43ca3U, 0x4b80cb70U, 0x9e21bfa5U, + 0xe647a1ddU, 0x0fd5da34U, 0xdf31eee4U, 0x48400873U, + 0x551b4e6eU, 0xc4ef2bffU, 0xf4d327cfU, 0xaddd7096U, + 0x7c790547U, 0x29785112U, 0xfd9964c6U, 0x9ca13da7U, + 0xd67badedU, 0xc8e028f3U, 0x37e3d40cU, 0x015a5b3aU, + 0x59144d62U, 0x08101833U, 0x1c011d27U, 0xeccd21d7U, + 0x3026160bU, 0x52de8c69U, 0x837af9b8U, 0x511e4f6aU, + 0x545b0f6fU, 0x6d2d4056U, 0xa212b099U, 0x450f4a7eU, + 0xb9cc7582U, 0x07dfd83cU, 0xbf49f684U, 0x823ab8b9U, + 0x6122435aU, 0x99e47da2U, 0x1fc1de24U, 0x17cbdc2cU, + 0x001a1a3bU, 0xe58762deU, 0x114e5f2aU, 0x58540c63U, + 0xa352f198U, 0x0c151937U, 0x5c510d67U, 0x6fadc254U, + 0xddb16ce6U, 0x4ec58b75U, 0xfcd925c7U, 0x56db8d6dU, + 0xd4fb2fefU, 0x73b6c548U, 0x5b94cf60U, 0x793c4542U, + 0xe302e1d8U, 0x9a24bea1U, 0xee4da3d5U, 0x6ae88251U, + 0x80ba3abbU, 0xb88c3483U, 0x0bd0db30U, 0xc26aa8f9U, + 0xac9d3197U, 0x2032121bU, 0xed8d60d6U, 0x6ba8c350U, + 0xdb34efe0U, 0x28381013U, 0x7ef98745U, 0x1e819f25U, + 0x62e28059U, 0x66e7815dU, 0xba0cb681U, 0x922ebca9U, + 0xe18263daU, 0xbb4cf780U, 0x69284152U, 0x9de17ca6U, + 0x396c5502U, 0xa092329bU, 0x2577521eU, 0x2ab89211U, + 0x936efda8U, 0xb086368bU, 0xa617b19dU, 0xd27eace9U, + 0xab58f390U, 0x976bfcacU, 0xbe09b785U, 0xb483378fU, + 0xff19e6c4U, 0xd0fe2eebU, 0x13cedd28U, 0xf59366ceU, + 0x410a4b7aU, 0xe0c222dbU, 0x3aac9601U, 0x2172531aU, + 0x63a2c158U, 0x069f993dU, 0x94ab3fafU, 0x9f61fea4U, + 0x3563560eU, 0x404a0a7bU, 0x055f5a3eU, 0x154b5e2eU, + 0xf19667caU, 0x72f68449U, 0x89f079b2U, 0xfe59a7c5U, + 0xe707e0dcU, 0x8df578b6U, 0x0a909a31U, 0x2ebd9315U, + 0x42ca8879U, 0x3166570aU, 0x100e1e2bU, 0xf316e5c8U, + 0xc0ea2afbU, 0x6eed8355U, 0xcce529f7U, 0xc5af6afeU, + 0xb743f48cU, 0x140b1f2fU, 0x22b29019U, 0x6467035fU, + 0x3fe9d604U, 0xa497339fU, 0xe242a0d9U, 0x579bcc6cU, + 0x32a69409U, 0x6c6d0157U, 0xaa18b291U, 0x2ffdd214U, + 0x88b038b3U, 0xf8dc24c3U, 0x33e6d508U, 0xf653a5cdU, + 0x5e8fd15fU, 0x47d19646U, 0xa24ceea3U, 0xfe07f9ffU, + 0x36fdcb37U, 0x8264e683U, 0xf1c839f0U, 0xdb6ab1daU, + 0x5d4f125cU, 0xdf6fb0deU, 0x55451054U, 0x0ecbc50fU, + 0xa5892ca4U, 0xea16fcebU, 0xb59d28b4U, 0x11100110U, + 0xa9862fa8U, 0x98fa6299U, 0x6ff39c6eU, 0xdcaf73ddU, + 0xad832eacU, 0xff47b8feU, 0x15150014U, 0x0acec40bU, + 0xaf03acaeU, 0x14554115U, 0x495e1748U, 0x9dbf229cU, + 0x206c4c21U, 0x1f9f801eU, 0x1d1f021cU, 0x63fc9f62U, + 0x77ed9a76U, 0x0c4b470dU, 0x44115545U, 0xd625f3d7U, + 0x43d49742U, 0xba52e8bbU, 0x67f99e66U, 0xec937fedU, + 0xc9fe37c8U, 0x54055155U, 0x29260f28U, 0x084e4609U, + 0xb258eab3U, 0x3af2c83bU, 0xb71daab6U, 0x8ceb678dU, + 0x9675e397U, 0xcb7eb5caU, 0x756d1874U, 0xa30cafa2U, + 0x22ecce23U, 0x25290c24U, 0xa649efa7U, 0x53c09352U, + 0x07818606U, 0x7aa2d87bU, 0x57c59256U, 0xee13fdefU, + 0xd0a070d1U, 0x3bb2893aU, 0xf9c23bf8U, 0x9f3fa09eU, + 0x185a4219U, 0x191a0318U, 0x9b3aa19aU, 0xf60dfbf7U, + 0xca3ef4cbU, 0xc8be76c9U, 0x594a1358U, 0xef53bceeU, + 0x0b8e850aU, 0x603c5c61U, 0xf5cd38f4U, 0x617c1d60U, + 0x9e7fe19fU, 0x13908312U, 0x38724a39U, 0xa709aea6U, + 0xa4c96da5U, 0xa8c66ea9U, 0x03848702U, 0xcf7bb4ceU, + 0xc0b474c1U, 0x94f56195U, 0x6eb3dd6fU, 0x2ba68d2aU, + 0xe619ffe7U, 0xaa46ecabU, 0x39320b38U, 0x28664e29U, + 0xc4b175c5U, 0x5c0f535dU, 0x73e89b72U, 0xd1e031d0U, + 0x7d671a7cU, 0x95b52094U, 0x3d370a3cU, 0x7c275b7dU, + 0x88ee6689U, 0x64395d65U, 0x4294d643U, 0x8f2ba48eU, + 0x91b02190U, 0x8dab268cU, 0xf48d79f5U, 0xe9d63fe8U, + 0x01040500U, 0x81a42580U, 0xe4997de5U, 0x1b9a811aU, + 0x5685d357U, 0x05010404U, 0x1c5f431dU, 0x580a5259U, + 0x7be2997aU, 0x4a9ed44bU, 0x99ba2398U, 0x4c1b574dU, + 0x347d4935U, 0xddef32dcU, 0x0d0b060cU, 0x9a7ae09bU, + 0x8721a686U, 0x16d5c317U, 0x26e9cf27U, 0x7fe7987eU, + 0xae43edafU, 0xfb42b9faU, 0x2fa38c2eU, 0x4e9bd54fU, + 0x04414505U, 0x1adac01bU, 0xe5d93ce4U, 0xd360b3d2U, + 0x8b2ea58aU, 0xda2af0dbU, 0xce3bf5cfU, 0x3ef7c93fU, + 0xe21cfee3U, 0x80e46481U, 0x51401150U, 0x8324a782U, + 0x8661e787U, 0xbf17a8beU, 0x70285871U, 0x9735a296U, + 0x6bf69d6aU, 0xd5e530d4U, 0x6d731e6cU, 0x50005051U, + 0xb318abb2U, 0x4bde954aU, 0xcdfb36ccU, 0xc5f134c4U, + 0xd220f2d3U, 0x37bd8a36U, 0xc374b7c2U, 0x8a6ee48bU, + 0x71681970U, 0xde2ff1dfU, 0x8e6be58fU, 0xbd972abcU, + 0x0f8b840eU, 0x9cff639dU, 0x2ee3cd2fU, 0x84e16585U, + 0x06c1c707U, 0xa18c2da0U, 0x89ae2788U, 0xab06adaaU, + 0x31380930U, 0x481e5649U, 0x3c774b3dU, 0xb8d26ab9U, + 0x5280d253U, 0x6ab6dc6bU, 0xd9ea33d8U, 0x10504011U, + 0x7ea7d97fU, 0xf208faf3U, 0x3fb7883eU, 0xb9922bb8U, + 0x090e0708U, 0xfa02f8fbU, 0xacc36fadU, 0xccbb77cdU, + 0xb0d868b1U, 0xb4dd69b5U, 0x68365e69U, 0x40145441U, + 0x33b88b32U, 0x69761f68U, 0xbb12a9baU, 0x4fdb944eU, + 0xeb56bdeaU, 0x72a8da73U, 0xf74dbaf6U, 0xf8827af9U, + 0x41541540U, 0x62bcde63U, 0x742d5975U, 0x00444401U, + 0x79621b78U, 0x45511444U, 0x6c335f6dU, 0x66b9df67U, + 0x2d230e2cU, 0x02c4c603U, 0xc1f435c0U, 0x27a98e26U, + 0x9330a392U, 0x32f8ca33U, 0xe8967ee9U, 0xf348bbf2U, + 0xb19829b0U, 0xd4a571d5U, 0x4691d747U, 0x4d5b164cU, + 0xe759bee6U, 0x9270e293U, 0xd765b2d6U, 0xc771b6c6U, + 0x23ac8f22U, 0xa0cc6ca1U, 0x5bca915aU, 0x2c634f2dU, + 0x353d0834U, 0x5fcf905eU, 0xd8aa72d9U, 0xfc877bfdU, + 0x90f06091U, 0xe35cbfe2U, 0xc234f6c3U, 0x212c0d20U, + 0x12d0c213U, 0xbcd76bbdU, 0x1edfc11fU, 0x17958216U, + 0x65791c64U, 0xc631f7c7U, 0xf08878f1U, 0xb65debb7U, + 0xedd33eecU, 0x76addb77U, 0x30784831U, 0x85a12484U, + 0xe09c7ce1U, 0xbe57e9bfU, 0x78225a79U, 0xfdc73afcU, + 0x5a8ad05bU, 0x2ae6cc2bU, 0xe1dc3de0U, 0x24694d25U, + 0xfeaf51dfU, 0xe7f116c6U, 0x026c6e23U, 0x5e27797fU, + 0x96dd4bb7U, 0x22446603U, 0x51e8b970U, 0x7b4a315aU, + 0xfd6f92dcU, 0x7f4f305eU, 0xf56590d4U, 0xaeeb458fU, + 0x05a9ac24U, 0x4a367c6bU, 0x15bda834U, 0xb1308190U, + 0x09a6af28U, 0x38dae219U, 0xcfd31ceeU, 0x7c8ff35dU, + 0x0da3ae2cU, 0x5f67387eU, 0xb5358094U, 0xaaee448bU, + 0x0f232c2eU, 0xb475c195U, 0xe97e97c8U, 0x3d9fa21cU, + 0x804ccca1U, 0xbfbf009eU, 0xbd3f829cU, 0xc3dc1fe2U, + 0xd7cd1af6U, 0xac6bc78dU, 0xe431d5c5U, 0x76057357U, + 0xe3f417c2U, 0x1a72683bU, 0xc7d91ee6U, 0x4cb3ff6dU, + 0x69deb748U, 0xf425d1d5U, 0x89068fa8U, 0xa86ec689U, + 0x12786a33U, 0x9ad248bbU, 0x173d2a36U, 0x2ccbe70dU, + 0x36556317U, 0x6b5e354aU, 0xd54d98f4U, 0x032c2f22U, + 0x82cc4ea3U, 0x85098ca4U, 0x06696f27U, 0xf3e013d2U, + 0xa7a10686U, 0xda8258fbU, 0xf7e512d6U, 0x4e337d6fU, + 0x7080f051U, 0x9b9209baU, 0x59e2bb78U, 0x3f1f201eU, + 0xb87ac299U, 0xb93a8398U, 0x3b1a211aU, 0x562d7b77U, + 0x6a1e744bU, 0x689ef649U, 0xf96a93d8U, 0x4f733c6eU, + 0xabae058aU, 0xc01cdce1U, 0x55edb874U, 0xc15c9de0U, + 0x3e5f611fU, 0xb3b00392U, 0x9852cab9U, 0x07292e26U, + 0x04e9ed25U, 0x08e6ee29U, 0xa3a40782U, 0x6f5b344eU, + 0x6094f441U, 0x34d5e115U, 0xce935defU, 0x8b860daaU, + 0x46397f67U, 0x0a666c2bU, 0x99128bb8U, 0x8846cea9U, + 0x6491f545U, 0xfc2fd3ddU, 0xd3c81bf2U, 0x71c0b150U, + 0xdd479afcU, 0x3595a014U, 0x9d178abcU, 0xdc07dbfdU, + 0x28cee609U, 0xc419dde5U, 0xe2b456c3U, 0x2f0b240eU, + 0x3190a110U, 0x2d8ba60cU, 0x54adf975U, 0x49f6bf68U, + 0xa1248580U, 0x2184a500U, 0x44b9fd65U, 0xbbba019aU, + 0xf6a553d7U, 0xa5218484U, 0xbc7fc39dU, 0xf82ad2d9U, + 0xdbc219faU, 0xeabe54cbU, 0x399aa318U, 0xec3bd7cdU, + 0x945dc9b5U, 0x7dcfb25cU, 0xad2b868cU, 0x3a5a601bU, + 0x27012606U, 0xb6f54397U, 0x86c94fa7U, 0xdfc718feU, + 0x0e636d2fU, 0x5b62397aU, 0x8f830caeU, 0xeebb55cfU, + 0xa461c585U, 0xbafa409bU, 0x45f9bc64U, 0x73403352U, + 0x2b0e250aU, 0x7a0a705bU, 0x6e1b754fU, 0x9ed749bfU, + 0x423c7e63U, 0x20c4e401U, 0xf16091d0U, 0x23042702U, + 0x26416707U, 0x1f37283eU, 0xd008d8f1U, 0x37152216U, + 0xcbd61deaU, 0x75c5b054U, 0xcd539eecU, 0xf020d0d1U, + 0x13382b32U, 0xebfe15caU, 0x6ddbb64cU, 0x65d1b444U, + 0x72007253U, 0x979d0ab6U, 0x63543742U, 0x2a4e640bU, + 0xd14899f0U, 0x7e0f715fU, 0x2e4b650fU, 0x1db7aa3cU, + 0xafab048eU, 0x3cdfe31dU, 0x8ec34dafU, 0x24c1e505U, + 0xa6e14787U, 0x01acad20U, 0x298ea708U, 0x0b262d2aU, + 0x911889b0U, 0xe83ed6c9U, 0x9c57cbbdU, 0x18f2ea39U, + 0xf2a052d3U, 0xca965cebU, 0x79cab358U, 0xb070c091U, + 0xde8759ffU, 0x52287a73U, 0x9f9708beU, 0x19b2ab38U, + 0xa92e8788U, 0x5a22787bU, 0x0ce3ef2dU, 0x6c9bf74dU, + 0x10f8e831U, 0x14fde935U, 0xc816dee9U, 0xe034d4c1U, + 0x93980bb2U, 0xc9569fe8U, 0x1b32293aU, 0xeffb14ceU, + 0x4b763d6aU, 0xd2885af3U, 0x576d3a76U, 0x58a2fa79U, + 0xe17495c0U, 0xc29c5ee3U, 0xd40dd9f5U, 0xa064c481U, + 0xd9429bf8U, 0xe57194c4U, 0xcc13dfedU, 0xc6995fe7U, + 0x8d038eacU, 0xa2e44683U, 0x61d4b540U, 0x87890ea6U, + 0x33102312U, 0x92d84ab3U, 0x48b6fe69U, 0x53683b72U, + 0x11b8a930U, 0x7485f155U, 0xe6b157c7U, 0xed7b96ccU, + 0x47793e66U, 0x32506213U, 0x77453256U, 0x67513646U, + 0x838c0fa2U, 0x00ecec21U, 0xfbea11daU, 0x8c43cfadU, + 0x951d88b4U, 0xffef10deU, 0x788af259U, 0x5ca7fb7dU, + 0x30d0e011U, 0x437c3f62U, 0x62147643U, 0x810c8da0U, + 0xb2f04293U, 0x1cf7eb3dU, 0xbeff419fU, 0xb7b50296U, + 0xc5599ce4U, 0x66117747U, 0x50a8f871U, 0x167d6b37U, + 0x4df3be6cU, 0xd68d5bf7U, 0x9058c8b1U, 0x2581a404U, + 0x40bcfc61U, 0x1e77693fU, 0xd802daf9U, 0x5de7ba7cU, + 0xfaaa50dbU, 0x8ac64cabU, 0x41fcbd60U, 0x8449cda5U, + 0xc3f734baU, 0xdaa973a3U, 0x3f340b46U, 0x637f1c1aU, + 0xab852ed2U, 0x1f1c0366U, 0x6cb0dc15U, 0x4612543fU, + 0xc037f7b9U, 0x4217553bU, 0xc83df5b1U, 0x93b320eaU, + 0x38f1c941U, 0x776e190eU, 0x28e5cd51U, 0x8c68e4f5U, + 0x34feca4dU, 0x0582877cU, 0xf28b798bU, 0x41d79638U, + 0x30fbcb49U, 0x623f5d1bU, 0x886de5f1U, 0x97b621eeU, + 0x327b494bU, 0x892da4f0U, 0xd426f2adU, 0x00c7c779U, + 0xbd14a9c4U, 0x82e765fbU, 0x8067e7f9U, 0xfe847a87U, + 0xea957f93U, 0x9133a2e8U, 0xd969b0a0U, 0x4b5d1632U, + 0xdeac72a7U, 0x272a0d5eU, 0xfa817b83U, 0x71eb9a08U, + 0x5486d22dU, 0xc97db4b0U, 0xb45eeacdU, 0x9536a3ecU, + 0x2f200f56U, 0xa78a2ddeU, 0x2a654f53U, 0x11938268U, + 0x0b0d0672U, 0x5606502fU, 0xe815fd91U, 0x3e744a47U, + 0xbf942bc6U, 0xb851e9c1U, 0x3b310a42U, 0xceb876b7U, + 0x9af963e3U, 0xe7da3d9eU, 0xcabd77b3U, 0x736b180aU, + 0x4dd89534U, 0xa6ca6cdfU, 0x64bade1dU, 0x0247457bU, + 0x8522a7fcU, 0x8462e6fdU, 0x0642447fU, 0x6b751e12U, + 0x5746112eU, 0x55c6932cU, 0xc432f6bdU, 0x722b590bU, + 0x96f660efU, 0xfd44b984U, 0x68b5dd11U, 0xfc04f885U, + 0x0307047aU, 0x8ee866f7U, 0xa50aafdcU, 0x3a714b43U, + 0x39b18840U, 0x35be8b4cU, 0x9efc62e7U, 0x5203512bU, + 0x5dcc9124U, 0x098d8470U, 0xf3cb388aU, 0xb6de68cfU, + 0x7b611a02U, 0x373e094eU, 0xa44aeeddU, 0xb51eabccU, + 0x59c99020U, 0xc177b6b8U, 0xee907e97U, 0x4c98d435U, + 0xe01fff99U, 0x08cdc571U, 0xa04fefd9U, 0xe15fbe98U, + 0x1596836cU, 0xf941b880U, 0xdfec33a6U, 0x1253416bU, + 0x0cc8c475U, 0x10d3c369U, 0x69f59c10U, 0x74aeda0dU, + 0x9c7ce0e5U, 0x1cdcc065U, 0x79e19800U, 0x86e264ffU, + 0xcbfd36b2U, 0x9879e1e1U, 0x8127a6f8U, 0xc572b7bcU, + 0xe69a7c9fU, 0xd7e631aeU, 0x04c2c67dU, 0xd163b2a8U, + 0xa905acd0U, 0x4097d739U, 0x9073e3e9U, 0x0702057eU, + 0x1a594363U, 0x8bad26f2U, 0xbb912ac2U, 0xe29f7d9bU, + 0x333b084aU, 0x663a5c1fU, 0xb2db69cbU, 0xd3e330aaU, + 0x9939a0e0U, 0x87a225feU, 0x78a1d901U, 0x4e185637U, + 0x1656406fU, 0x4752153eU, 0x5343102aU, 0xa38f2cdaU, + 0x7f641b06U, 0x1d9c8164U, 0xcc38f4b5U, 0x1e5c4267U, + 0x1b190262U, 0x226f4d5bU, 0xed50bd94U, 0x0a4d4773U, + 0xf68e788fU, 0x489dd531U, 0xf00bfb89U, 0xcd78b5b4U, + 0x2e604e57U, 0xd6a670afU, 0x5083d329U, 0x5889d121U, + 0x4f581736U, 0xaac56fd3U, 0x5e0c5227U, 0x1716016eU, + 0xec10fc95U, 0x4357143aU, 0x1313006aU, 0x20efcf59U, + 0x92f361ebU, 0x01878678U, 0xb39b28caU, 0x19998060U, + 0x9bb922e2U, 0x3cf4c845U, 0x14d6c26dU, 0x367e484fU, + 0xac40ecd5U, 0xd566b3acU, 0xa10faed8U, 0x25aa8f5cU, + 0xcff837b6U, 0xf7ce398eU, 0x4492d63dU, 0x8d28a5f4U, + 0xe3df3c9aU, 0x6f701f16U, 0xa2cf6ddbU, 0x24eace5dU, + 0x9476e2edU, 0x677a1d1eU, 0x31bb8a48U, 0x51c39228U, + 0x2da08d54U, 0x29a58c50U, 0xf54ebb8cU, 0xdd6cb1a4U, + 0xaec06ed7U, 0xf40efa8dU, 0x266a4c5fU, 0xd2a371abU, + 0x762e580fU, 0xefd03f96U, 0x6a355f13U, 0x65fa9f1cU, + 0xdc2cf0a5U, 0xffc43b86U, 0xe955bc90U, 0x9d3ca1e4U, + 0xe41afe9dU, 0xd829f1a1U, 0xf14bba88U, 0xfbc13a82U, + 0xb05bebc9U, 0x9fbc23e6U, 0x5c8cd025U, 0xbad16bc3U, + 0x0e484677U, 0xaf802fd6U, 0x75ee9b0cU, 0x6e305e17U, + 0x2ce0cc55U, 0x49dd9430U, 0xdbe932a2U, 0xd023f3a9U, + 0x7a215b03U, 0x0f080776U, 0x4a1d5733U, 0x5a095323U, + 0xbed46ac7U, 0x3db48944U, 0xc6b274bfU, 0xb11baac8U, + 0xa845edd1U, 0xc2b775bbU, 0x45d2973cU, 0x61ff9e18U, + 0x0d888574U, 0x7e245a07U, 0x5f4c1326U, 0xbc54e8c5U, + 0x8fa827f6U, 0x21af8e58U, 0x83a724faU, 0x8aed67f3U, + 0xf801f981U, 0x5b491222U, 0x6df09d14U, 0x2b250e52U, + 0x70abdb09U, 0xebd53e92U, 0xad00add4U, 0x18d9c161U, + 0x7de49904U, 0x232f0c5aU, 0xe55abf9cU, 0x60bfdf19U, + 0xc7f235beU, 0xb79e29ceU, 0x7ca4d805U, 0xb911a8c0U, + 0xc00bcb45U, 0xd9558c5cU, 0x3cc8f4b9U, 0x6083e3e5U, + 0xa879d12dU, 0x1ce0fc99U, 0x6f4c23eaU, 0x45eeabc0U, + 0xc3cb0846U, 0x41ebaac4U, 0xcbc10a4eU, 0x904fdf15U, + 0x3b0d36beU, 0x7492e6f1U, 0x2b1932aeU, 0x8f941b0aU, + 0x370235b2U, 0x067e7883U, 0xf1778674U, 0x422b69c7U, + 0x330734b6U, 0x61c3a2e4U, 0x8b911a0eU, 0x944ade11U, + 0x3187b6b4U, 0x8ad15b0fU, 0xd7da0d52U, 0x033b3886U, + 0xbee8563bU, 0x811b9a04U, 0x839b1806U, 0xfd788578U, + 0xe969806cU, 0x92cf5d17U, 0xda954f5fU, 0x48a1e9cdU, + 0xdd508d58U, 0x24d6f2a1U, 0xf97d847cU, 0x721765f7U, + 0x577a2dd2U, 0xca814b4fU, 0xb7a21532U, 0x96ca5c13U, + 0x2cdcf0a9U, 0xa476d221U, 0x2999b0acU, 0x126f7d97U, + 0x08f1f98dU, 0x55faafd0U, 0xebe9026eU, 0x3d88b5b8U, + 0xbc68d439U, 0xbbad163eU, 0x38cdf5bdU, 0xcd448948U, + 0x99059c1cU, 0xe426c261U, 0xc941884cU, 0x7097e7f5U, + 0x4e246acbU, 0xa5369320U, 0x674621e2U, 0x01bbba84U, + 0x86de5803U, 0x879e1902U, 0x05bebb80U, 0x6889e1edU, + 0x54baeed1U, 0x563a6cd3U, 0xc7ce0942U, 0x71d7a6f4U, + 0x950a9f10U, 0xfeb8467bU, 0x6b4922eeU, 0xfff8077aU, + 0x00fbfb85U, 0x8d149908U, 0xa6f65023U, 0x398db4bcU, + 0x3a4d77bfU, 0x364274b3U, 0x9d009d18U, 0x51ffaed4U, + 0x5e306edbU, 0x0a717b8fU, 0xf037c775U, 0xb5229730U, + 0x789de5fdU, 0x34c2f6b1U, 0xa7b61122U, 0xb6e25433U, + 0x5a356fdfU, 0xc28b4947U, 0xed6c8168U, 0x4f642bcaU, + 0xe3e30066U, 0x0b313a8eU, 0xa3b31026U, 0xe2a34167U, + 0x166a7c93U, 0xfabd477fU, 0xdc10cc59U, 0x11afbe94U, + 0x0f343b8aU, 0x132f3c96U, 0x6a0963efU, 0x775225f2U, + 0x9f801f1aU, 0x1f203f9aU, 0x7a1d67ffU, 0x851e9b00U, + 0xc801c94dU, 0x9b851e1eU, 0x82db5907U, 0xc68e4843U, + 0xe5668360U, 0xd41ace51U, 0x073e3982U, 0xd29f4d57U, + 0xaaf9532fU, 0x436b28c6U, 0x938f1c16U, 0x04fefa81U, + 0x19a5bc9cU, 0x8851d90dU, 0xb86dd53dU, 0xe1638264U, + 0x30c7f7b5U, 0x65c6a3e0U, 0xb1279634U, 0xd01fcf55U, + 0x9ac55f1fU, 0x845eda01U, 0x7b5d26feU, 0x4de4a9c8U, + 0x15aabf90U, 0x44aeeac1U, 0x50bfefd5U, 0xa073d325U, + 0x7c98e4f9U, 0x1e607e9bU, 0xcfc40b4aU, 0x1da0bd98U, + 0x18e5fd9dU, 0x2193b2a4U, 0xeeac426bU, 0x09b1b88cU, + 0xf5728770U, 0x4b612aceU, 0xf3f70476U, 0xce844a4bU, + 0x2d9cb1a8U, 0xd55a8f50U, 0x537f2cd6U, 0x5b752edeU, + 0x4ca4e8c9U, 0xa939902cU, 0x5df0add8U, 0x14eafe91U, + 0xefec036aU, 0x40abebc5U, 0x10efff95U, 0x231330a6U, + 0x910f9e14U, 0x027b7987U, 0xb067d735U, 0x1a657f9fU, + 0x9845dd1dU, 0x3f0837baU, 0x172a3d92U, 0x3582b7b0U, + 0xafbc132aU, 0xd69a4c53U, 0xa2f35127U, 0x265670a3U, + 0xcc04c849U, 0xf432c671U, 0x476e29c2U, 0x8ed45a0bU, + 0xe023c365U, 0x6c8ce0e9U, 0xa1339224U, 0x271631a2U, + 0x978a1d12U, 0x6486e2e1U, 0x324775b7U, 0x523f6dd7U, + 0x2e5c72abU, 0x2a5973afU, 0xf6b24473U, 0xde904e5bU, + 0xad3c9128U, 0xf7f20572U, 0x2596b3a0U, 0xd15f8e54U, + 0x75d2a7f0U, 0xec2cc069U, 0x69c9a0ecU, 0x660660e3U, + 0xdfd00f5aU, 0xfc38c479U, 0xeaa9436fU, 0x9ec05e1bU, + 0xe7e60162U, 0xdbd50e5eU, 0xf2b74577U, 0xf83dc57dU, + 0xb3a71436U, 0x9c40dc19U, 0x5f702fdaU, 0xb92d943cU, + 0x0db4b988U, 0xac7cd029U, 0x761264f3U, 0x6dcca1e8U, + 0x2f1c33aaU, 0x4a216bcfU, 0xd815cd5dU, 0xd3df0c56U, + 0x79dda4fcU, 0x0cf4f889U, 0x49e1a8ccU, 0x59f5acdcU, + 0xbd289538U, 0x3e4876bbU, 0xc54e8b40U, 0xb2e75537U, + 0xabb9122eU, 0xc14b8a44U, 0x462e68c3U, 0x620361e7U, + 0x0e747a8bU, 0x7dd8a5f8U, 0x5cb0ecd9U, 0xbfa8173aU, + 0x8c54d809U, 0x225371a7U, 0x805bdb05U, 0x8911980cU, + 0xfbfd067eU, 0x58b5edddU, 0x6e0c62ebU, 0x28d9f1adU, + 0x735724f6U, 0xe829c16dU, 0xaefc522bU, 0x1b253e9eU, + 0x7e1866fbU, 0x20d3f3a5U, 0xe6a64063U, 0x634320e6U, + 0xc40eca41U, 0xb462d631U, 0x7f5827faU, 0xbaed573fU, + 0xdf598608U, 0xc607c111U, 0x239ab9f4U, 0x7fd1aea8U, + 0xb72b9c60U, 0x03b2b1d4U, 0x701e6ea7U, 0x5abce68dU, + 0xdc99450bU, 0x5eb9e789U, 0xd4934703U, 0x8f1d9258U, + 0x245f7bf3U, 0x6bc0abbcU, 0x344b7fe3U, 0x90c65647U, + 0x285078ffU, 0x192c35ceU, 0xee25cb39U, 0x5d79248aU, + 0x2c5579fbU, 0x7e91efa9U, 0x94c35743U, 0x8b18935cU, + 0x2ed5fbf9U, 0x95831642U, 0xc888401fU, 0x1c6975cbU, + 0xa1ba1b76U, 0x9e49d749U, 0x9cc9554bU, 0xe22ac835U, + 0xf63bcd21U, 0x8d9d105aU, 0xc5c70212U, 0x57f3a480U, + 0xc202c015U, 0x3b84bfecU, 0xe62fc931U, 0x6d4528baU, + 0x4828609fU, 0xd5d30602U, 0xa8f0587fU, 0x8998115eU, + 0x338ebde4U, 0xbb249f6cU, 0x36cbfde1U, 0x0d3d30daU, + 0x17a3b4c0U, 0x4aa8e29dU, 0xf4bb4f23U, 0x22daf8f5U, + 0xa33a9974U, 0xa4ff5b73U, 0x279fb8f0U, 0xd216c405U, + 0x8657d151U, 0xfb748f2cU, 0xd613c501U, 0x6fc5aab8U, + 0x51762786U, 0xba64de6dU, 0x78146cafU, 0x1ee9f7c9U, + 0x998c154eU, 0x98cc544fU, 0x1aecf6cdU, 0x77dbaca0U, + 0x4be8a39cU, 0x4968219eU, 0xd89c440fU, 0x6e85ebb9U, + 0x8a58d25dU, 0xe1ea0b36U, 0x741b6fa3U, 0xe0aa4a37U, + 0x1fa9b6c8U, 0x9246d445U, 0xb9a41d6eU, 0x26dff9f1U, + 0x251f3af2U, 0x291039feU, 0x8252d055U, 0x4eade399U, + 0x41622396U, 0x152336c2U, 0xef658a38U, 0xaa70da7dU, + 0x67cfa8b0U, 0x2b90bbfcU, 0xb8e45c6fU, 0xa9b0197eU, + 0x45672292U, 0xddd9040aU, 0xf23ecc25U, 0x50366687U, + 0xfcb14d2bU, 0x146377c3U, 0xbce15d6bU, 0xfdf10c2aU, + 0x093831deU, 0xe5ef0a32U, 0xc3428114U, 0x0efdf3d9U, + 0x106676c7U, 0x0c7d71dbU, 0x755b2ea2U, 0x680068bfU, + 0x80d25257U, 0x007272d7U, 0x654f2ab2U, 0x9a4cd64dU, + 0xd7538400U, 0x84d75353U, 0x9d89144aU, 0xd9dc050eU, + 0xfa34ce2dU, 0xcb48831cU, 0x186c74cfU, 0xcdcd001aU, + 0xb5ab1e62U, 0x5c39658bU, 0x8cdd515bU, 0x1bacb7ccU, + 0x06f7f1d1U, 0x97039440U, 0xa73f9870U, 0xfe31cf29U, + 0x2f95baf8U, 0x7a94eeadU, 0xae75db79U, 0xcf4d8218U, + 0x85971252U, 0x9b0c974cU, 0x640f6bb3U, 0x52b6e485U, + 0x0af8f2ddU, 0x5bfca78cU, 0x4feda298U, 0xbf219e68U, + 0x63caa9b4U, 0x013233d6U, 0xd0964607U, 0x02f2f0d5U, + 0x07b7b0d0U, 0x3ec1ffe9U, 0xf1fe0f26U, 0x16e3f5c1U, + 0xea20ca3dU, 0x54336783U, 0xeca5493bU, 0xd1d60706U, + 0x32cefce5U, 0xca08c21dU, 0x4c2d619bU, 0x44276393U, + 0x53f6a584U, 0xb66bdd61U, 0x42a2e095U, 0x0bb8b3dcU, + 0xf0be4e27U, 0x5ff9a688U, 0x0fbdb2d8U, 0x3c417debU, + 0x8e5dd359U, 0x1d2934caU, 0xaf359a78U, 0x053732d2U, + 0x87179050U, 0x205a7af7U, 0x087870dfU, 0x2ad0fafdU, + 0xb0ee5e67U, 0xc9c8011eU, 0xbda11c6aU, 0x39043deeU, + 0xd3568504U, 0xeb608b3cU, 0x583c648fU, 0x91861746U, + 0xff718e28U, 0x73deada4U, 0xbe61df69U, 0x38447cefU, + 0x88d8505fU, 0x7bd4afacU, 0x2d1538faU, 0x4d6d209aU, + 0x310e3fe6U, 0x350b3ee2U, 0xe9e0093eU, 0xc1c20316U, + 0xb26edc65U, 0xe8a0483fU, 0x3ac4feedU, 0xce0dc319U, + 0x6a80eabdU, 0xf37e8d24U, 0x769beda1U, 0x79542daeU, + 0xc0824217U, 0xe36a8934U, 0xf5fb0e22U, 0x81921356U, + 0xf8b44c2fU, 0xc4874313U, 0xede5083aU, 0xe76f8830U, + 0xacf5597bU, 0x83129154U, 0x40226297U, 0xa67fd971U, + 0x12e6f4c5U, 0xb32e9d64U, 0x694029beU, 0x729eeca5U, + 0x304e7ee7U, 0x55732682U, 0xc7478010U, 0xcc8d411bU, + 0x668fe9b1U, 0x13a6b5c4U, 0x56b3e581U, 0x46a7e191U, + 0xa27ad875U, 0x211a3bf6U, 0xda1cc60dU, 0xadb5187aU, + 0xb4eb5f63U, 0xde19c709U, 0x597c258eU, 0x7d512caaU, + 0x112637c6U, 0x628ae8b5U, 0x43e2a194U, 0xa0fa5a77U, + 0x93069544U, 0x3d013ceaU, 0x9f099648U, 0x9643d541U, + 0xe4af4b33U, 0x47e7a090U, 0x715e2fa6U, 0x378bbce0U, + 0x6c0569bbU, 0xf77b8c20U, 0xb1ae1f66U, 0x047773d3U, + 0x614a2bb6U, 0x3f81bee8U, 0xf9f40d2eU, 0x7c116dabU, + 0xdb5c870cU, 0xab309b7cU, 0x600a6ab7U, 0xa5bf1a72U, + 0x5b8ed55bU, 0x42d09242U, 0xa74deaa7U, 0xfb06fdfbU, + 0x33fccf33U, 0x8765e287U, 0xf4c93df4U, 0xde6bb5deU, + 0x584e1658U, 0xda6eb4daU, 0x50441450U, 0x0bcac10bU, + 0xa08828a0U, 0xef17f8efU, 0xb09c2cb0U, 0x14110514U, + 0xac872bacU, 0x9dfb669dU, 0x6af2986aU, 0xd9ae77d9U, + 0xa8822aa8U, 0xfa46bcfaU, 0x10140410U, 0x0fcfc00fU, + 0xaa02a8aaU, 0x11544511U, 0x4c5f134cU, 0x98be2698U, + 0x256d4825U, 0x1a9e841aU, 0x181e0618U, 0x66fd9b66U, + 0x72ec9e72U, 0x094a4309U, 0x41105141U, 0xd324f7d3U, + 0x46d59346U, 0xbf53ecbfU, 0x62f89a62U, 0xe9927be9U, + 0xccff33ccU, 0x51045551U, 0x2c270b2cU, 0x0d4f420dU, + 0xb759eeb7U, 0x3ff3cc3fU, 0xb21caeb2U, 0x89ea6389U, + 0x9374e793U, 0xce7fb1ceU, 0x706c1c70U, 0xa60daba6U, + 0x27edca27U, 0x20280820U, 0xa348eba3U, 0x56c19756U, + 0x02808202U, 0x7fa3dc7fU, 0x52c49652U, 0xeb12f9ebU, + 0xd5a174d5U, 0x3eb38d3eU, 0xfcc33ffcU, 0x9a3ea49aU, + 0x1d5b461dU, 0x1c1b071cU, 0x9e3ba59eU, 0xf30cfff3U, + 0xcf3ff0cfU, 0xcdbf72cdU, 0x5c4b175cU, 0xea52b8eaU, + 0x0e8f810eU, 0x653d5865U, 0xf0cc3cf0U, 0x647d1964U, + 0x9b7ee59bU, 0x16918716U, 0x3d734e3dU, 0xa208aaa2U, + 0xa1c869a1U, 0xadc76aadU, 0x06858306U, 0xca7ab0caU, + 0xc5b570c5U, 0x91f46591U, 0x6bb2d96bU, 0x2ea7892eU, + 0xe318fbe3U, 0xaf47e8afU, 0x3c330f3cU, 0x2d674a2dU, + 0xc1b071c1U, 0x590e5759U, 0x76e99f76U, 0xd4e135d4U, + 0x78661e78U, 0x90b42490U, 0x38360e38U, 0x79265f79U, + 0x8def628dU, 0x61385961U, 0x4795d247U, 0x8a2aa08aU, + 0x94b12594U, 0x88aa2288U, 0xf18c7df1U, 0xecd73becU, + 0x04050104U, 0x84a52184U, 0xe19879e1U, 0x1e9b851eU, + 0x5384d753U, 0x00000000U, 0x195e4719U, 0x5d0b565dU, + 0x7ee39d7eU, 0x4f9fd04fU, 0x9cbb279cU, 0x491a5349U, + 0x317c4d31U, 0xd8ee36d8U, 0x080a0208U, 0x9f7be49fU, + 0x8220a282U, 0x13d4c713U, 0x23e8cb23U, 0x7ae69c7aU, + 0xab42e9abU, 0xfe43bdfeU, 0x2aa2882aU, 0x4b9ad14bU, + 0x01404101U, 0x1fdbc41fU, 0xe0d838e0U, 0xd661b7d6U, + 0x8e2fa18eU, 0xdf2bf4dfU, 0xcb3af1cbU, 0x3bf6cd3bU, + 0xe71dfae7U, 0x85e56085U, 0x54411554U, 0x8625a386U, + 0x8360e383U, 0xba16acbaU, 0x75295c75U, 0x9234a692U, + 0x6ef7996eU, 0xd0e434d0U, 0x68721a68U, 0x55015455U, + 0xb619afb6U, 0x4edf914eU, 0xc8fa32c8U, 0xc0f030c0U, + 0xd721f6d7U, 0x32bc8e32U, 0xc675b3c6U, 0x8f6fe08fU, + 0x74691d74U, 0xdb2ef5dbU, 0x8b6ae18bU, 0xb8962eb8U, + 0x0a8a800aU, 0x99fe6799U, 0x2be2c92bU, 0x81e06181U, + 0x03c0c303U, 0xa48d29a4U, 0x8caf238cU, 0xae07a9aeU, + 0x34390d34U, 0x4d1f524dU, 0x39764f39U, 0xbdd36ebdU, + 0x5781d657U, 0x6fb7d86fU, 0xdceb37dcU, 0x15514415U, + 0x7ba6dd7bU, 0xf709fef7U, 0x3ab68c3aU, 0xbc932fbcU, + 0x0c0f030cU, 0xff03fcffU, 0xa9c26ba9U, 0xc9ba73c9U, + 0xb5d96cb5U, 0xb1dc6db1U, 0x6d375a6dU, 0x45155045U, + 0x36b98f36U, 0x6c771b6cU, 0xbe13adbeU, 0x4ada904aU, + 0xee57b9eeU, 0x77a9de77U, 0xf24cbef2U, 0xfd837efdU, + 0x44551144U, 0x67bdda67U, 0x712c5d71U, 0x05454005U, + 0x7c631f7cU, 0x40501040U, 0x69325b69U, 0x63b8db63U, + 0x28220a28U, 0x07c5c207U, 0xc4f531c4U, 0x22a88a22U, + 0x9631a796U, 0x37f9ce37U, 0xed977aedU, 0xf649bff6U, + 0xb4992db4U, 0xd1a475d1U, 0x4390d343U, 0x485a1248U, + 0xe258bae2U, 0x9771e697U, 0xd264b6d2U, 0xc270b2c2U, + 0x26ad8b26U, 0xa5cd68a5U, 0x5ecb955eU, 0x29624b29U, + 0x303c0c30U, 0x5ace945aU, 0xddab76ddU, 0xf9867ff9U, + 0x95f16495U, 0xe65dbbe6U, 0xc735f2c7U, 0x242d0924U, + 0x17d1c617U, 0xb9d66fb9U, 0x1bdec51bU, 0x12948612U, + 0x60781860U, 0xc330f3c3U, 0xf5897cf5U, 0xb35cefb3U, + 0xe8d23ae8U, 0x73acdf73U, 0x35794c35U, 0x80a02080U, + 0xe59d78e5U, 0xbb56edbbU, 0x7d235e7dU, 0xf8c63ef8U, + 0x5f8bd45fU, 0x2fe7c82fU, 0xe4dd39e4U, 0x21684921U, + 0x05c9cc42U, 0x1c978b5bU, 0xf90af3beU, 0xa541e4e2U, + 0x6dbbd62aU, 0xd922fb9eU, 0xaa8e24edU, 0x802cacc7U, + 0x06090f41U, 0x8429adc3U, 0x0e030d49U, 0x558dd812U, + 0xfecf31b9U, 0xb150e1f6U, 0xeedb35a9U, 0x4a561c0dU, + 0xf2c032b5U, 0xc3bc7f84U, 0x34b58173U, 0x87e96ec0U, + 0xf6c533b1U, 0xa401a5e3U, 0x4e531d09U, 0x5188d916U, + 0xf445b1b3U, 0x4f135c08U, 0x12180a55U, 0xc6f93f81U, + 0x7b2a513cU, 0x44d99d03U, 0x46591f01U, 0x38ba827fU, + 0x2cab876bU, 0x570d5a10U, 0x1f574858U, 0x8d63eecaU, + 0x18928a5fU, 0xe114f5a6U, 0x3cbf837bU, 0xb7d562f0U, + 0x92b82ad5U, 0x0f434c48U, 0x72601235U, 0x53085b14U, + 0xe91ef7aeU, 0x61b4d526U, 0xec5bb7abU, 0xd7ad7a90U, + 0xcd33fe8aU, 0x9038a8d7U, 0x2e2b0569U, 0xf84ab2bfU, + 0x79aad33eU, 0x7e6f1139U, 0xfd0ff2baU, 0x08868e4fU, + 0x5cc79b1bU, 0x21e4c566U, 0x0c838f4bU, 0xb555e0f2U, + 0x8be66dccU, 0x60f49427U, 0xa28426e5U, 0xc479bd83U, + 0x431c5f04U, 0x425c1e05U, 0xc07cbc87U, 0xad4be6eaU, + 0x9178e9d6U, 0x93f86bd4U, 0x020c0e45U, 0xb415a1f3U, + 0x50c89817U, 0x3b7a417cU, 0xae8b25e9U, 0x3a3a007dU, + 0xc539fc82U, 0x48d69e0fU, 0x63345724U, 0xfc4fb3bbU, + 0xff8f70b8U, 0xf38073b4U, 0x58c29a1fU, 0x943da9d3U, + 0x9bf269dcU, 0xcfb37c88U, 0x35f5c072U, 0x70e09037U, + 0xbd5fe2faU, 0xf100f1b6U, 0x62741625U, 0x73205334U, + 0x9ff768d8U, 0x07494e40U, 0x28ae866fU, 0x8aa62ccdU, + 0x26210761U, 0xcef33d89U, 0x66711721U, 0x27614660U, + 0xd3a87b94U, 0x3f7f4078U, 0x19d2cb5eU, 0xd46db993U, + 0xcaf63c8dU, 0xd6ed3b91U, 0xafcb64e8U, 0xb29022f5U, + 0x5a42181dU, 0xdae2389dU, 0xbfdf60f8U, 0x40dc9c07U, + 0x0dc3ce4aU, 0x5e471919U, 0x47195e00U, 0x034c4f44U, + 0x20a48467U, 0x11d8c956U, 0xc2fc3e85U, 0x175d4a50U, + 0x6f3b5428U, 0x86a92fc1U, 0x564d1b11U, 0xc13cfd86U, + 0xdc67bb9bU, 0x4d93de0aU, 0x7dafd23aU, 0x24a18563U, + 0xf505f0b2U, 0xa004a4e7U, 0x74e59133U, 0x15ddc852U, + 0x5f075818U, 0x419cdd06U, 0xbe9f21f9U, 0x8826aecfU, + 0xd068b897U, 0x816cedc6U, 0x957de8d2U, 0x65b1d422U, + 0xb95ae3feU, 0xdba2799cU, 0x0a060c4dU, 0xd862ba9fU, + 0xdd27fa9aU, 0xe451b5a3U, 0x2b6e456cU, 0xcc73bf8bU, + 0x30b08077U, 0x8ea32dc9U, 0x36350371U, 0x0b464d4cU, + 0xe85eb6afU, 0x10988857U, 0x96bd2bd1U, 0x9eb729d9U, + 0x8966efceU, 0x6cfb972bU, 0x9832aadfU, 0xd128f996U, + 0x2a2e046dU, 0x8569ecc2U, 0xd52df892U, 0xe6d137a1U, + 0x54cd9913U, 0xc7b97e80U, 0x75a5d032U, 0xdfa77898U, + 0x5d87da1aU, 0xfaca30bdU, 0xd2e83a95U, 0xf040b0b7U, + 0x6a7e142dU, 0x13584b54U, 0x67315620U, 0xe39477a4U, + 0x09c6cf4eU, 0x31f0c176U, 0x82ac2ec5U, 0x4b165d0cU, + 0x25e1c462U, 0xa94ee7eeU, 0x64f19523U, 0xe2d436a5U, + 0x52481a15U, 0xa144e5e6U, 0xf78572b0U, 0x97fd6ad0U, + 0xeb9e75acU, 0xef9b74a8U, 0x33704374U, 0x1b52495cU, + 0x68fe962fU, 0x32300275U, 0xe054b4a7U, 0x149d8953U, + 0xb010a0f7U, 0x29eec76eU, 0xac0ba7ebU, 0xa3c467e4U, + 0x1a12085dU, 0x39fac37eU, 0x2f6b4468U, 0x5b02591cU, + 0x22240665U, 0x1e170959U, 0x37754270U, 0x3dffc27aU, + 0x76651331U, 0x5982db1eU, 0x9ab228ddU, 0x7cef933bU, + 0xc876be8fU, 0x69bed72eU, 0xb3d063f4U, 0xa80ea6efU, + 0xeade34adU, 0x8fe36cc8U, 0x1dd7ca5aU, 0x161d0b51U, + 0xbc1fa3fbU, 0xc936ff8eU, 0x8c23afcbU, 0x9c37abdbU, + 0x78ea923fU, 0xfb8a71bcU, 0x008c8c47U, 0x77255230U, + 0x6e7b1529U, 0x04898d43U, 0x83ec6fc4U, 0xa7c166e0U, + 0xcbb67d8cU, 0xb81aa2ffU, 0x9972ebdeU, 0x7a6a103dU, + 0x4996df0eU, 0xe79176a0U, 0x4599dc02U, 0x4cd39f0bU, + 0x3e3f0179U, 0x9d77eadaU, 0xabce65ecU, 0xed1bf6aaU, + 0xb69523f1U, 0x2debc66aU, 0x6b3e552cU, 0xdee73999U, + 0xbbda61fcU, 0xe511f4a2U, 0x23644764U, 0xa68127e1U, + 0x01cccd46U, 0x71a0d136U, 0xba9a20fdU, 0x7f2f5038U, + 0x50d88806U, 0x4986cf1fU, 0xac1bb7faU, 0xf050a0a6U, + 0x38aa926eU, 0x8c33bfdaU, 0xff9f60a9U, 0xd53de883U, + 0x53184b05U, 0xd138e987U, 0x5b12490dU, 0x009c9c56U, + 0xabde75fdU, 0xe441a5b2U, 0xbbca71edU, 0x1f475849U, + 0xa7d176f1U, 0x96ad3bc0U, 0x61a4c537U, 0xd2f82a84U, + 0xa3d477f5U, 0xf110e1a7U, 0x1b42594dU, 0x04999d52U, + 0xa154f5f7U, 0x1a02184cU, 0x47094e11U, 0x93e87bc5U, + 0x2e3b1578U, 0x11c8d947U, 0x13485b45U, 0x6dabc63bU, + 0x79bac32fU, 0x021c1e54U, 0x4a460c1cU, 0xd872aa8eU, + 0x4d83ce1bU, 0xb405b1e2U, 0x69aec73fU, 0xe2c426b4U, + 0xc7a96e91U, 0x5a52080cU, 0x27715671U, 0x06191f50U, + 0xbc0fb3eaU, 0x34a59162U, 0xb94af3efU, 0x82bc3ed4U, + 0x9822baceU, 0xc529ec93U, 0x7b3a412dU, 0xad5bf6fbU, + 0x2cbb977aU, 0x2b7e557dU, 0xa81eb6feU, 0x5d97ca0bU, + 0x09d6df5fU, 0x74f58122U, 0x5992cb0fU, 0xe044a4b6U, + 0xdef72988U, 0x35e5d063U, 0xf79562a1U, 0x9168f9c7U, + 0x160d1b40U, 0x174d5a41U, 0x956df8c3U, 0xf85aa2aeU, + 0xc469ad92U, 0xc6e92f90U, 0x571d4a01U, 0xe104e5b7U, + 0x05d9dc53U, 0x6e6b0538U, 0xfb9a61adU, 0x6f2b4439U, + 0x9028b8c6U, 0x1dc7da4bU, 0x36251360U, 0xa95ef7ffU, + 0xaa9e34fcU, 0xa69137f0U, 0x0dd3de5bU, 0xc12ced97U, + 0xcee32d98U, 0x9aa238ccU, 0x60e48436U, 0x25f1d473U, + 0xe84ea6beU, 0xa411b5f2U, 0x37655261U, 0x26311770U, + 0xcae62c9cU, 0x52580a04U, 0x7dbfc22bU, 0xdfb76889U, + 0x73304325U, 0x9be279cdU, 0x33605365U, 0x72700224U, + 0x86b93fd0U, 0x6a6e043cU, 0x4cc38f1aU, 0x817cfdd7U, + 0x9fe778c9U, 0x83fc7fd5U, 0xfada20acU, 0xe78166b1U, + 0x0f535c59U, 0x8ff37cd9U, 0xeace24bcU, 0x15cdd843U, + 0x58d28a0eU, 0x0b565d5dU, 0x12081a44U, 0x565d0b00U, + 0x75b5c023U, 0x44c98d12U, 0x97ed7ac1U, 0x424c0e14U, + 0x3a2a106cU, 0xd3b86b85U, 0x035c5f55U, 0x942db9c2U, + 0x8976ffdfU, 0x18829a4eU, 0x28be967eU, 0x71b0c127U, + 0xa014b4f6U, 0xf515e0a3U, 0x21f4d577U, 0x40cc8c16U, + 0x0a161c5cU, 0x148d9942U, 0xeb8e65bdU, 0xdd37ea8bU, + 0x8579fcd3U, 0xd47da982U, 0xc06cac96U, 0x30a09066U, + 0xec4ba7baU, 0x8eb33dd8U, 0x5f174809U, 0x8d73fedbU, + 0x8836bedeU, 0xb140f1e7U, 0x7e7f0128U, 0x9962fbcfU, + 0x65a1c433U, 0xdbb2698dU, 0x63244735U, 0x5e570908U, + 0xbd4ff2ebU, 0x4589cc13U, 0xc3ac6f95U, 0xcba66d9dU, + 0xdc77ab8aU, 0x39ead36fU, 0xcd23ee9bU, 0x8439bdd2U, + 0x7f3f4029U, 0xd078a886U, 0x803cbcd6U, 0xb3c073e5U, + 0x01dcdd57U, 0x92a83ac4U, 0x20b49476U, 0x8ab63cdcU, + 0x08969e5eU, 0xafdb74f9U, 0x87f97ed1U, 0xa551f4f3U, + 0x3f6f5069U, 0x46490f10U, 0x32201264U, 0xb68533e0U, + 0x5cd78b0aU, 0x64e18532U, 0xd7bd6a81U, 0x1e071948U, + 0x70f08026U, 0xfc5fa3aaU, 0x31e0d167U, 0xb7c572e1U, + 0x07595e51U, 0xf455a1a2U, 0xa29436f4U, 0xc2ec2e94U, + 0xbe8f31e8U, 0xba8a30ecU, 0x66610730U, 0x4e430d18U, + 0x3defd26bU, 0x67214631U, 0xb545f0e3U, 0x418ccd17U, + 0xe501e4b3U, 0x7cff832aU, 0xf91ae3afU, 0xf6d523a0U, + 0x4f034c19U, 0x6ceb873aU, 0x7a7a002cU, 0x0e131d58U, + 0x77354221U, 0x4b064d1dU, 0x62640634U, 0x68ee863eU, + 0x23745775U, 0x0c939f5aU, 0xcfa36c99U, 0x29fed77fU, + 0x9d67facbU, 0x3caf936aU, 0xe6c127b0U, 0xfd1fe2abU, + 0xbfcf70e9U, 0xdaf2288cU, 0x48c68e1eU, 0x430c4f15U, + 0xe90ee7bfU, 0x9c27bbcaU, 0xd932eb8fU, 0xc926ef9fU, + 0x2dfbd67bU, 0xae9b35f8U, 0x559dc803U, 0x22341674U, + 0x3b6a516dU, 0x5198c907U, 0xd6fd2b80U, 0xf2d022a4U, + 0x9ea739c8U, 0xed0be6bbU, 0xcc63af9aU, 0x2f7b5479U, + 0x1c879b4aU, 0xb28032e4U, 0x10889846U, 0x19c2db4fU, + 0x6b2e453dU, 0xc866ae9eU, 0xfedf21a8U, 0xb80ab2eeU, + 0xe38467b5U, 0x78fa822eU, 0x3e2f1168U, 0x8bf67dddU, + 0xeecb25b8U, 0xb000b0e6U, 0x76750320U, 0xf39063a5U, + 0x54dd8902U, 0x24b19572U, 0xef8b64b9U, 0x2a3e147cU, + 0xb813ab25U, 0xa14dec3cU, 0x44d094d9U, 0x189b8385U, + 0xd061b14dU, 0x64f89cf9U, 0x1754438aU, 0x3df6cba0U, + 0xbbd36826U, 0x39f3caa4U, 0xb3d96a2eU, 0xe857bf75U, + 0x431556deU, 0x0c8a8691U, 0x530152ceU, 0xf78c7b6aU, + 0x4f1a55d2U, 0x7e6618e3U, 0x896fe614U, 0x3a3309a7U, + 0x4b1f54d6U, 0x19dbc284U, 0xf3897a6eU, 0xec52be71U, + 0x499fd6d4U, 0xf2c93b6fU, 0xafc26d32U, 0x7b2358e6U, + 0xc6f0365bU, 0xf903fa64U, 0xfb837866U, 0x8560e518U, + 0x9171e00cU, 0xead73d77U, 0xa28d2f3fU, 0x30b989adU, + 0xa548ed38U, 0x5cce92c1U, 0x8165e41cU, 0x0a0f0597U, + 0x2f624db2U, 0xb2992b2fU, 0xcfba7552U, 0xeed23c73U, + 0x54c490c9U, 0xdc6eb241U, 0x5181d0ccU, 0x6a771df7U, + 0x70e999edU, 0x2de2cfb0U, 0x93f1620eU, 0x4590d5d8U, + 0xc470b459U, 0xc3b5765eU, 0x40d595ddU, 0xb55ce928U, + 0xe11dfc7cU, 0x9c3ea201U, 0xb159e82cU, 0x088f8795U, + 0x363c0aabU, 0xdd2ef340U, 0x1f5e4182U, 0x79a3dae4U, + 0xfec63863U, 0xff867962U, 0x7da6dbe0U, 0x1091818dU, + 0x2ca28eb1U, 0x2e220cb3U, 0xbfd66922U, 0x09cfc694U, + 0xed12ff70U, 0x86a0261bU, 0x1351428eU, 0x87e0671aU, + 0x78e39be5U, 0xf50cf968U, 0xdeee3043U, 0x4195d4dcU, + 0x425517dfU, 0x4e5a14d3U, 0xe518fd78U, 0x29e7ceb4U, + 0x26280ebbU, 0x72691befU, 0x882fa715U, 0xcd3af750U, + 0x0085859dU, 0x4cda96d1U, 0xdfae7142U, 0xcefa3453U, + 0x222d0fbfU, 0xba932927U, 0x9574e108U, 0x377c4baaU, + 0x9bfb6006U, 0x73295aeeU, 0xdbab7046U, 0x9abb2107U, + 0x6e721cf3U, 0x82a5271fU, 0xa408ac39U, 0x69b7def4U, + 0x772c5beaU, 0x6b375cf6U, 0x1211038fU, 0x0f4a4592U, + 0xe7987f7aU, 0x67385ffaU, 0x0205079fU, 0xfd06fb60U, + 0xb019a92dU, 0xe39d7e7eU, 0xfac33967U, 0xbe962823U, + 0x9d7ee300U, 0xac02ae31U, 0x7f2659e2U, 0xaa872d37U, + 0xd2e1334fU, 0x3b7348a6U, 0xeb977c76U, 0x7ce69ae1U, + 0x61bddcfcU, 0xf049b96dU, 0xc075b55dU, 0x997be204U, + 0x48df97d5U, 0x1ddec380U, 0xc93ff654U, 0xa807af35U, + 0xe2dd3f7fU, 0xfc46ba61U, 0x0345469eU, 0x35fcc9a8U, + 0x6db2dff0U, 0x3cb68aa1U, 0x28a78fb5U, 0xd86bb345U, + 0x04808499U, 0x66781efbU, 0xb7dc6b2aU, 0x65b8ddf8U, + 0x60fd9dfdU, 0x598bd2c4U, 0x96b4220bU, 0x71a9d8ecU, + 0x8d6ae710U, 0x33794aaeU, 0x8bef6416U, 0xb69c2a2bU, + 0x5584d1c8U, 0xad42ef30U, 0x2b674cb6U, 0x236d4ebeU, + 0x34bc88a9U, 0xd121f04cU, 0x25e8cdb8U, 0x6cf29ef1U, + 0x97f4630aU, 0x38b38ba5U, 0x68f79ff5U, 0x5b0b50c6U, + 0xe917fe74U, 0x7a6319e7U, 0xc87fb755U, 0x627d1fffU, + 0xe05dbd7dU, 0x471057daU, 0x6f325df2U, 0x4d9ad7d0U, + 0xd7a4734aU, 0xae822c33U, 0xdaeb3147U, 0x5e4e10c3U, + 0xb41ca829U, 0x8c2aa611U, 0x3f7649a2U, 0xf6cc3a6bU, + 0x983ba305U, 0x14948089U, 0xd92bf244U, 0x5f0e51c2U, + 0xef927d72U, 0x1c9e8281U, 0x4a5f15d7U, 0x2a270db7U, + 0x564412cbU, 0x524113cfU, 0x8eaa2413U, 0xa6882e3bU, + 0xd524f148U, 0x8fea6512U, 0x5d8ed3c0U, 0xa947ee34U, + 0x0dcac790U, 0x9434a009U, 0x11d1c08cU, 0x1e1e0083U, + 0xa7c86f3aU, 0x8420a419U, 0x92b1230fU, 0xe6d83e7bU, + 0x9ffe6102U, 0xa3cd6e3eU, 0x8aaf2517U, 0x8025a51dU, + 0xcbbf7456U, 0xe458bc79U, 0x27684fbaU, 0xc135f45cU, + 0x75acd9e8U, 0xd464b049U, 0x0e0a0493U, 0x15d4c188U, + 0x570453caU, 0x32390bafU, 0xa00dad3dU, 0xabc76c36U, + 0x01c5c49cU, 0x74ec98e9U, 0x31f9c8acU, 0x21edccbcU, + 0xc530f558U, 0x465016dbU, 0xbd56eb20U, 0xcaff3557U, + 0xd3a1724eU, 0xb953ea24U, 0x3e3608a3U, 0x1a1b0187U, + 0x766c1aebU, 0x05c0c598U, 0x24a88cb9U, 0xc7b0775aU, + 0xf44cb869U, 0x5a4b11c7U, 0xf843bb65U, 0xf109f86cU, + 0x83e5661eU, 0x20ad8dbdU, 0x1614028bU, 0x50c191cdU, + 0x0b4f4496U, 0x9031a10dU, 0xd6e4324bU, 0x633d5efeU, + 0x0600069bU, 0x58cb93c5U, 0x9ebe2003U, 0x1b5b4086U, + 0xbc16aa21U, 0xcc7ab651U, 0x0740479aU, 0xc2f5375fU, + 0xc45e9a14U, 0xdd00dd0dU, 0x389da5e8U, 0x64d6b2b4U, + 0xac2c807cU, 0x18b5adc8U, 0x6b1972bbU, 0x41bbfa91U, + 0xc79e5917U, 0x45befb95U, 0xcf945b1fU, 0x941a8e44U, + 0x3f5867efU, 0x70c7b7a0U, 0x2f4c63ffU, 0x8bc14a5bU, + 0x335764e3U, 0x022b29d2U, 0xf522d725U, 0x467e3896U, + 0x375265e7U, 0x6596f3b5U, 0x8fc44b5fU, 0x901f8f40U, + 0x35d2e7e5U, 0x8e840a5eU, 0xd38f5c03U, 0x076e69d7U, + 0xbabd076aU, 0x854ecb55U, 0x87ce4957U, 0xf92dd429U, + 0xed3cd13dU, 0x969a0c46U, 0xdec01e0eU, 0x4cf4b89cU, + 0xd905dc09U, 0x2083a3f0U, 0xfd28d52dU, 0x764234a6U, + 0x532f7c83U, 0xced41a1eU, 0xb3f74463U, 0x929f0d42U, + 0x2889a1f8U, 0xa0238370U, 0x2dcce1fdU, 0x163a2cc6U, + 0x0ca4a8dcU, 0x51affe81U, 0xefbc533fU, 0x39dde4e9U, + 0xb83d8568U, 0xbff8476fU, 0x3c98a4ecU, 0xc911d819U, + 0x9d50cd4dU, 0xe0739330U, 0xcd14d91dU, 0x74c2b6a4U, + 0x4a713b9aU, 0xa163c271U, 0x631370b3U, 0x05eeebd5U, + 0x828b0952U, 0x83cb4853U, 0x01ebead1U, 0x6cdcb0bcU, + 0x50efbf80U, 0x526f3d82U, 0xc39b5813U, 0x7582f7a5U, + 0x915fce41U, 0xfaed172aU, 0x6f1c73bfU, 0xfbad562bU, + 0x04aeaad4U, 0x8941c859U, 0xa2a30172U, 0x3dd8e5edU, + 0x3e1826eeU, 0x321725e2U, 0x9955cc49U, 0x55aaff85U, + 0x5a653f8aU, 0x0e242adeU, 0xf4629624U, 0xb177c661U, + 0x7cc8b4acU, 0x3097a7e0U, 0xa3e34073U, 0xb2b70562U, + 0x5e603e8eU, 0xc6de1816U, 0xe939d039U, 0x4b317a9bU, + 0xe7b65137U, 0x0f646bdfU, 0xa7e64177U, 0xe6f61036U, + 0x123f2dc2U, 0xfee8162eU, 0xd8459d08U, 0x15faefc5U, + 0x0b616adbU, 0x177a6dc7U, 0x6e5c32beU, 0x730774a3U, + 0x9bd54e4bU, 0x1b756ecbU, 0x7e4836aeU, 0x814bca51U, + 0xcc54981cU, 0x9fd04f4fU, 0x868e0856U, 0xc2db1912U, + 0xe133d231U, 0xd04f9f00U, 0x036b68d3U, 0xd6ca1c06U, + 0xaeac027eU, 0x473e7997U, 0x97da4d47U, 0x00ababd0U, + 0x1df0edcdU, 0x8c04885cU, 0xbc38846cU, 0xe536d335U, + 0x3492a6e4U, 0x6193f2b1U, 0xb572c765U, 0xd44a9e04U, + 0x9e900e4eU, 0x800b8b50U, 0x7f0877afU, 0x49b1f899U, + 0x11ffeec1U, 0x40fbbb90U, 0x54eabe84U, 0xa4268274U, + 0x78cdb5a8U, 0x1a352fcaU, 0xcb915a1bU, 0x19f5ecc9U, + 0x1cb0acccU, 0x25c6e3f5U, 0xeaf9133aU, 0x0de4e9ddU, + 0xf127d621U, 0x4f347b9fU, 0xf7a25527U, 0xcad11b1aU, + 0x29c9e0f9U, 0xd10fde01U, 0x572a7d87U, 0x5f207f8fU, + 0x48f1b998U, 0xad6cc17dU, 0x59a5fc89U, 0x10bfafc0U, + 0xebb9523bU, 0x44feba94U, 0x14baaec4U, 0x274661f7U, + 0x955acf45U, 0x062e28d6U, 0xb4328664U, 0x1e302eceU, + 0x9c108c4cU, 0x3b5d66ebU, 0x137f6cc3U, 0x31d7e6e1U, + 0xabe9427bU, 0xd2cf1d02U, 0xa6a60076U, 0x220321f2U, + 0xc8519918U, 0xf0679720U, 0x433b7893U, 0x8a810b5aU, + 0xe4769234U, 0x68d9b1b8U, 0xa566c375U, 0x234360f3U, + 0x93df4c43U, 0x60d3b3b0U, 0x361224e6U, 0x566a3c86U, + 0x2a0923faU, 0x2e0c22feU, 0xf2e71522U, 0xdac51f0aU, + 0xa969c079U, 0xf3a75423U, 0x21c3e2f1U, 0xd50adf05U, + 0x7187f6a1U, 0xe8799138U, 0x6d9cf1bdU, 0x625331b2U, + 0xdb855e0bU, 0xf86d9528U, 0xeefc123eU, 0x9a950f4aU, + 0xe3b35033U, 0xdf805f0fU, 0xf6e21426U, 0xfc68942cU, + 0xb7f24567U, 0x98158d48U, 0x5b257e8bU, 0xbd78c56dU, + 0x09e1e8d9U, 0xa8298178U, 0x724735a2U, 0x6999f0b9U, + 0x2b4962fbU, 0x4e743a9eU, 0xdc409c0cU, 0xd78a5d07U, + 0x7d88f5adU, 0x08a1a9d8U, 0x4db4f99dU, 0x5da0fd8dU, + 0xb97dc469U, 0x3a1d27eaU, 0xc11bda11U, 0xb6b20466U, + 0xafec437fU, 0xc51edb15U, 0x427b3992U, 0x665630b6U, + 0x0a212bdaU, 0x798df4a9U, 0x58e5bd88U, 0xbbfd466bU, + 0x88018958U, 0x260620f6U, 0x840e8a54U, 0x8d44c95dU, + 0xffa8572fU, 0x5ce0bc8cU, 0x6a5933baU, 0x2c8ca0fcU, + 0x770275a7U, 0xec7c903cU, 0xaaa9037aU, 0x1f706fcfU, + 0x7a4d37aaU, 0x2486a2f4U, 0xe2f31132U, 0x671671b7U, + 0xc05b9b10U, 0xb0378760U, 0x7b0d76abU, 0xbeb8066eU, + 0xe0a949c7U, 0xf9f70edeU, 0x1c6a763bU, 0x40216167U, + 0x88db53afU, 0x3c427e1bU, 0x4feea168U, 0x654c2942U, + 0xe3698ac4U, 0x61492846U, 0xeb6388ccU, 0xb0ed5d97U, + 0x1bafb43cU, 0x54306473U, 0x0bbbb02cU, 0xaf369988U, + 0x17a0b730U, 0x26dcfa01U, 0xd1d504f6U, 0x6289eb45U, + 0x13a5b634U, 0x41612066U, 0xab33988cU, 0xb4e85c93U, + 0x11253436U, 0xaa73d98dU, 0xf7788fd0U, 0x2399ba04U, + 0x9e4ad4b9U, 0xa1b91886U, 0xa3399a84U, 0xddda07faU, + 0xc9cb02eeU, 0xb26ddf95U, 0xfa37cdddU, 0x68036b4fU, + 0xfdf20fdaU, 0x04747023U, 0xd9df06feU, 0x52b5e775U, + 0x77d8af50U, 0xea23c9cdU, 0x970097b0U, 0xb668de91U, + 0x0c7e722bU, 0x84d450a3U, 0x093b322eU, 0x32cdff15U, + 0x28537b0fU, 0x75582d52U, 0xcb4b80ecU, 0x1d2a373aU, + 0x9cca56bbU, 0x9b0f94bcU, 0x186f773fU, 0xede60bcaU, + 0xb9a71e9eU, 0xc48440e3U, 0xe9e30aceU, 0x50356577U, + 0x6e86e849U, 0x859411a2U, 0x47e4a360U, 0x21193806U, + 0xa67cda81U, 0xa73c9b80U, 0x251c3902U, 0x482b636fU, + 0x74186c53U, 0x7698ee51U, 0xe76c8bc0U, 0x51752476U, + 0xb5a81d92U, 0xde1ac4f9U, 0x4beba06cU, 0xdf5a85f8U, + 0x20597907U, 0xadb61b8aU, 0x8654d2a1U, 0x192f363eU, + 0x1aeff53dU, 0x16e0f631U, 0xbda21f9aU, 0x715d2c56U, + 0x7e92ec59U, 0x2ad3f90dU, 0xd09545f7U, 0x958015b2U, + 0x583f677fU, 0x14607433U, 0x871493a0U, 0x9640d6b1U, + 0x7a97ed5dU, 0xe229cbc5U, 0xcdce03eaU, 0x6fc6a948U, + 0xc34182e4U, 0x2b93b80cU, 0x831192a4U, 0xc201c3e5U, + 0x36c8fe11U, 0xda1fc5fdU, 0xfcb24edbU, 0x310d3c16U, + 0x2f96b908U, 0x338dbe14U, 0x4aabe16dU, 0x57f0a770U, + 0xbf229d98U, 0x3f82bd18U, 0x5abfe57dU, 0xa5bc1982U, + 0xe8a34bcfU, 0xbb279c9cU, 0xa279db85U, 0xe62ccac1U, + 0xc5c401e2U, 0xf4b84cd3U, 0x279cbb00U, 0xf23dcfd5U, + 0x8a5bd1adU, 0x63c9aa44U, 0xb32d9e94U, 0x245c7803U, + 0x39073e1eU, 0xa8f35b8fU, 0x98cf57bfU, 0xc1c100e6U, + 0x10657537U, 0x45642162U, 0x918514b6U, 0xf0bd4dd7U, + 0xba67dd9dU, 0xa4fc5883U, 0x5bffa47cU, 0x6d462b4aU, + 0x35083d12U, 0x640c6843U, 0x701d6d57U, 0x80d151a7U, + 0x5c3a667bU, 0x3ec2fc19U, 0xef6689c8U, 0x3d023f1aU, + 0x38477f1fU, 0x01313026U, 0xce0ec0e9U, 0x29133a0eU, + 0xd5d005f2U, 0x6bc3a84cU, 0xd35586f4U, 0xee26c8c9U, + 0x0d3e332aU, 0xf5f80dd2U, 0x73ddae54U, 0x7bd7ac5cU, + 0x6c066a4bU, 0x899b12aeU, 0x7d522f5aU, 0x34487c13U, + 0xcf4e81e8U, 0x60096947U, 0x304d7d17U, 0x03b1b224U, + 0xb1ad1c96U, 0x22d9fb05U, 0x90c555b7U, 0x3ac7fd1dU, + 0xb8e75f9fU, 0x1faab538U, 0x3788bf10U, 0x15203532U, + 0x8f1e91a8U, 0xf638ced1U, 0x8251d3a5U, 0x06f4f221U, + 0xeca64acbU, 0xd49044f3U, 0x67ccab40U, 0xae76d889U, + 0xc08141e7U, 0x4c2e626bU, 0x819110a6U, 0x07b4b320U, + 0xb7289f90U, 0x44246063U, 0x12e5f735U, 0x729def55U, + 0x0efef029U, 0x0afbf12dU, 0xd610c6f1U, 0xfe32ccd9U, + 0x8d9e13aaU, 0xd75087f0U, 0x05343122U, 0xf1fd0cd6U, + 0x55702572U, 0xcc8e42ebU, 0x496b226eU, 0x46a4e261U, + 0xff728dd8U, 0xdc9a46fbU, 0xca0bc1edU, 0xbe62dc99U, + 0xc74483e0U, 0xfb778cdcU, 0xd215c7f5U, 0xd89f47ffU, + 0x930596b4U, 0xbce25e9bU, 0x7fd2ad58U, 0x998f16beU, + 0x2d163b0aU, 0x8cde52abU, 0x56b0e671U, 0x4d6e236aU, + 0x0fbeb128U, 0x6a83e94dU, 0xf8b74fdfU, 0xf37d8ed4U, + 0x597f267eU, 0x2c567a0bU, 0x69432a4eU, 0x79572e5eU, + 0x9d8a17baU, 0x1eeaf439U, 0xe5ec09c2U, 0x9245d7b5U, + 0x8b1b90acU, 0xe1e908c6U, 0x668cea41U, 0x42a1e365U, + 0x2ed6f809U, 0x5d7a277aU, 0x7c126e5bU, 0x9f0a95b8U, + 0xacf65a8bU, 0x02f1f325U, 0xa0f95987U, 0xa9b31a8eU, + 0xdb5f84fcU, 0x78176f5fU, 0x4eaee069U, 0x087b732fU, + 0x53f5a674U, 0xc88b43efU, 0x8e5ed0a9U, 0x3b87bc1cU, + 0x5ebae479U, 0x00717127U, 0xc604c2e1U, 0x43e1a264U, + 0xe4ac48c3U, 0x94c054b3U, 0x5ffaa578U, 0x9a4fd5bdU, + 0x41dd9c12U, 0x5883db0bU, 0xbd1ea3eeU, 0xe155b4b2U, + 0x29af867aU, 0x9d36abceU, 0xee9a74bdU, 0xc438fc97U, + 0x421d5f11U, 0xc03dfd93U, 0x4a175d19U, 0x11998842U, + 0xbadb61e9U, 0xf544b1a6U, 0xaacf65f9U, 0x0e424c5dU, + 0xb6d462e5U, 0x87a82fd4U, 0x70a1d123U, 0xc3fd3e90U, + 0xb2d163e1U, 0xe015f5b3U, 0x0a474d59U, 0x159c8946U, + 0xb051e1e3U, 0x0b070c58U, 0x560c5a05U, 0x82ed6fd1U, + 0x3f3e016cU, 0x00cdcd53U, 0x024d4f51U, 0x7caed22fU, + 0x68bfd73bU, 0x13190a40U, 0x5b431808U, 0xc977be9aU, + 0x5c86da0fU, 0xa500a5f6U, 0x78abd32bU, 0xf3c132a0U, + 0xd6ac7a85U, 0x4b571c18U, 0x36744265U, 0x171c0b44U, + 0xad0aa7feU, 0x25a08576U, 0xa84fe7fbU, 0x93b92ac0U, + 0x8927aedaU, 0xd42cf887U, 0x6a3f5539U, 0xbc5ee2efU, + 0x3dbe836eU, 0x3a7b4169U, 0xb91ba2eaU, 0x4c92de1fU, + 0x18d3cb4bU, 0x65f09536U, 0x4897df1bU, 0xf141b0a2U, + 0xcff23d9cU, 0x24e0c477U, 0xe69076b5U, 0x806dedd3U, + 0x07080f54U, 0x06484e55U, 0x8468ecd7U, 0xe95fb6baU, + 0xd56cb986U, 0xd7ec3b84U, 0x46185e15U, 0xf001f1a3U, + 0x14dcc847U, 0x7f6e112cU, 0xea9f75b9U, 0x7e2e502dU, + 0x812dacd2U, 0x0cc2ce5fU, 0x27200774U, 0xb85be3ebU, + 0xbb9b20e8U, 0xb79423e4U, 0x1cd6ca4fU, 0xd029f983U, + 0xdfe6398cU, 0x8ba72cd8U, 0x71e19022U, 0x34f4c067U, + 0xf94bb2aaU, 0xb514a1e6U, 0x26604675U, 0x37340364U, + 0xdbe33888U, 0x435d1e10U, 0x6cbad63fU, 0xceb27c9dU, + 0x62355731U, 0x8ae76dd9U, 0x22654771U, 0x63751630U, + 0x97bc2bc4U, 0x7b6b1028U, 0x5dc69b0eU, 0x9079e9c3U, + 0x8ee26cddU, 0x92f96bc1U, 0xebdf34b8U, 0xf68472a5U, + 0x1e56484dU, 0x9ef668cdU, 0xfbcb30a8U, 0x04c8cc57U, + 0x49d79e1aU, 0x1a534949U, 0x030d0e50U, 0x47581f14U, + 0x64b0d437U, 0x55cc9906U, 0x86e86ed5U, 0x53491a00U, + 0x2b2f0478U, 0xc2bd7f91U, 0x12594b41U, 0x8528add6U, + 0x9873ebcbU, 0x09878e5aU, 0x39bb826aU, 0x60b5d533U, + 0xb111a0e2U, 0xe410f4b7U, 0x30f1c163U, 0x51c99802U, + 0x1b130848U, 0x05888d56U, 0xfa8b71a9U, 0xcc32fe9fU, + 0x947ce8c7U, 0xc578bd96U, 0xd169b882U, 0x21a58472U, + 0xfd4eb3aeU, 0x9fb629ccU, 0x4e125c1dU, 0x9c76eacfU, + 0x9933aacaU, 0xa045e5f3U, 0x6f7a153cU, 0x8867efdbU, + 0x74a4d027U, 0xcab77d99U, 0x72215321U, 0x4f521d1cU, + 0xac4ae6ffU, 0x548cd807U, 0xd2a97b81U, 0xdaa37989U, + 0xcd72bf9eU, 0x28efc77bU, 0xdc26fa8fU, 0x953ca9c6U, + 0x6e3a543dU, 0xc17dbc92U, 0x9139a8c2U, 0xa2c567f1U, + 0x10d9c943U, 0x83ad2ed0U, 0x31b18062U, 0x9bb328c8U, + 0x19938a4aU, 0xbede60edU, 0x96fc6ac5U, 0xb454e0e7U, + 0x2e6a447dU, 0x574c1b04U, 0x23250670U, 0xa78027f4U, + 0x4dd29f1eU, 0x75e49126U, 0xc6b87e95U, 0x0f020d5cU, + 0x61f59432U, 0xed5ab7beU, 0x20e5c573U, 0xa6c066f5U, + 0x165c4a45U, 0xe550b5b6U, 0xb39122e0U, 0xd3e93a80U, + 0xaf8a25fcU, 0xab8f24f8U, 0x77641324U, 0x5f46190cU, + 0x2ceac67fU, 0x76245225U, 0xa440e4f7U, 0x5089d903U, + 0xf404f0a7U, 0x6dfa973eU, 0xe81ff7bbU, 0xe7d037b4U, + 0x5e06580dU, 0x7dee932eU, 0x6b7f1438U, 0x1f16094cU, + 0x66305635U, 0x5a035909U, 0x73611220U, 0x79eb922aU, + 0x32714361U, 0x1d968b4eU, 0xdea6788dU, 0x38fbc36bU, + 0x8c62eedfU, 0x2daa877eU, 0xf7c433a4U, 0xec1af6bfU, + 0xaeca64fdU, 0xcbf73c98U, 0x59c39a0aU, 0x52095b01U, + 0xf80bf3abU, 0x8d22afdeU, 0xc837ff9bU, 0xd823fb8bU, + 0x3cfec26fU, 0xbf9e21ecU, 0x4498dc17U, 0x33310260U, + 0x2a6f4579U, 0x409ddd13U, 0xc7f83f94U, 0xe3d536b0U, + 0x8fa22ddcU, 0xfc0ef2afU, 0xdd66bb8eU, 0x3e7e406dU, + 0x0d828f5eU, 0xa38526f0U, 0x018d8c52U, 0x08c7cf5bU, + 0x7a2b5129U, 0xd963ba8aU, 0xefda35bcU, 0xa90fa6faU, + 0xf28173a1U, 0x69ff963aU, 0x2f2a057cU, 0x9af369c9U, + 0xffce31acU, 0xa105a4f2U, 0x67701734U, 0xe29577b1U, + 0x45d89d16U, 0x35b48166U, 0xfe8e70adU, 0x3b3b0068U, + 0x27c3e46aU, 0x3e9da373U, 0xdb00db96U, 0x874bcccaU, + 0x4fb1fe02U, 0xfb28d3b6U, 0x88840cc5U, 0xa22684efU, + 0x24032769U, 0xa62385ebU, 0x2c092561U, 0x7787f03aU, + 0xdcc51991U, 0x935ac9deU, 0xccd11d81U, 0x685c3425U, + 0xd0ca1a9dU, 0xe1b657acU, 0x16bfa95bU, 0xa5e346e8U, + 0xd4cf1b99U, 0x860b8dcbU, 0x6c593521U, 0x7382f13eU, + 0xd64f999bU, 0x6d197420U, 0x3012227dU, 0xe4f317a9U, + 0x59207914U, 0x66d3b52bU, 0x64533729U, 0x1ab0aa57U, + 0x0ea1af43U, 0x75077238U, 0x3d5d6070U, 0xaf69c6e2U, + 0x3a98a277U, 0xc31edd8eU, 0x1eb5ab53U, 0x95df4ad8U, + 0xb0b202fdU, 0x2d496460U, 0x506a3a1dU, 0x7102733cU, + 0xcb14df86U, 0x43befd0eU, 0xce519f83U, 0xf5a752b8U, + 0xef39d6a2U, 0xb23280ffU, 0x0c212d41U, 0xda409a97U, + 0x5ba0fb16U, 0x5c653911U, 0xdf05da92U, 0x2a8ca667U, + 0x7ecdb333U, 0x03eeed4eU, 0x2e89a763U, 0x975fc8daU, + 0xa9ec45e4U, 0x42febc0fU, 0x808e0ecdU, 0xe67395abU, + 0x6116772cU, 0x6056362dU, 0xe27694afU, 0x8f41cec2U, + 0xb372c1feU, 0xb1f243fcU, 0x2006266dU, 0x961f89dbU, + 0x72c2b03fU, 0x19706954U, 0x8c810dc1U, 0x18302855U, + 0xe733d4aaU, 0x6adcb627U, 0x413e7f0cU, 0xde459b93U, + 0xdd855890U, 0xd18a5b9cU, 0x7ac8b237U, 0xb63781fbU, + 0xb9f841f4U, 0xedb954a0U, 0x17ffe85aU, 0x52eab81fU, + 0x9f55cad2U, 0xd30ad99eU, 0x407e3e0dU, 0x512a7b1cU, + 0xbdfd40f0U, 0x25436668U, 0x0aa4ae47U, 0xa8ac04e5U, + 0x042b2f49U, 0xecf915a1U, 0x447b3f09U, 0x056b6e48U, + 0xf1a253bcU, 0x1d756850U, 0x3bd8e376U, 0xf66791bbU, + 0xe8fc14a5U, 0xf4e713b9U, 0x8dc14cc0U, 0x909a0addU, + 0x78483035U, 0xf8e810b5U, 0x9dd548d0U, 0x62d6b42fU, + 0x2fc9e662U, 0x7c4d3131U, 0x65137628U, 0x2146676cU, + 0x02aeac4fU, 0x33d2e17eU, 0xe0f616adU, 0x35576278U, + 0x4d317c00U, 0xa4a307e9U, 0x74473339U, 0xe336d5aeU, + 0xfe6d93b3U, 0x6f99f622U, 0x5fa5fa12U, 0x06abad4bU, + 0xd70fd89aU, 0x820e8ccfU, 0x56efb91bU, 0x37d7e07aU, + 0x7d0d7030U, 0x6396f52eU, 0x9c9509d1U, 0xaa2c86e7U, + 0xf26290bfU, 0xa366c5eeU, 0xb777c0faU, 0x47bbfc0aU, + 0x9b50cbd6U, 0xf9a851b4U, 0x280c2465U, 0xfa6892b7U, + 0xff2dd2b2U, 0xc65b9d8bU, 0x09646d44U, 0xee7997a3U, + 0x12baa85fU, 0xaca905e1U, 0x143f2b59U, 0x294c6564U, + 0xca549e87U, 0x3292a07fU, 0xb4b703f9U, 0xbcbd01f1U, + 0xab6cc7e6U, 0x4ef1bf03U, 0xba3882f7U, 0xf322d1beU, + 0x08242c45U, 0xa763c4eaU, 0xf727d0baU, 0xc4db1f89U, + 0x76c7b13bU, 0xe5b356a8U, 0x57aff81aU, 0xfdad50b0U, + 0x7f8df232U, 0xd8c01895U, 0xf0e212bdU, 0xd24a989fU, + 0x48743c05U, 0x3152637cU, 0x453b7e08U, 0xc19e5f8cU, + 0x2bcce766U, 0x13fae95eU, 0xa0a606edU, 0x691c7524U, + 0x07ebec4aU, 0x8b44cfc6U, 0x46fbbd0bU, 0xc0de1e8dU, + 0x7042323dU, 0x834ecdceU, 0xd58f5a98U, 0xb5f742f8U, + 0xc9945d84U, 0xcd915c80U, 0x117a6b5cU, 0x39586174U, + 0x4af4be07U, 0x103a2a5dU, 0xc25e9c8fU, 0x3697a17bU, + 0x921a88dfU, 0x0be4ef46U, 0x8e018fc3U, 0x81ce4fccU, + 0x38182075U, 0x1bf0eb56U, 0x0d616c40U, 0x79087134U, + 0x002e2e4dU, 0x3c1d2171U, 0x157f6a58U, 0x1ff5ea52U, + 0x546f3b19U, 0x7b88f336U, 0xb8b800f5U, 0x5ee5bb13U, + 0xea7c96a7U, 0x4bb4ff06U, 0x91da4bdcU, 0x8a048ec7U, + 0xc8d41c85U, 0xade944e0U, 0x3fdde272U, 0x34172379U, + 0x9e158bd3U, 0xeb3cd7a6U, 0xae2987e3U, 0xbe3d83f3U, + 0x5ae0ba17U, 0xd9805994U, 0x2286a46fU, 0x552f7a18U, + 0x4c713d01U, 0x2683a56bU, 0xa1e647ecU, 0x85cb4ec8U, + 0xe9bc55a4U, 0x9a108ad7U, 0xbb78c3f6U, 0x58603815U, + 0x6b9cf726U, 0xc59b5e88U, 0x6793f42aU, 0x6ed9b723U, + 0x1c352951U, 0xbf7dc2f2U, 0x89c44dc4U, 0xcf11de82U, + 0x949f0bd9U, 0x0fe1ee42U, 0x49347d04U, 0xfced11b1U, + 0x99d049d4U, 0xc71bdc8aU, 0x016e6f4cU, 0x848b0fc9U, + 0x23c6e56eU, 0x53aaf91eU, 0x989008d5U, 0x5d257810U, + 0xb5b80d83U, 0xace64a9aU, 0x497b327fU, 0x15302523U, + 0xddca17ebU, 0x69533a5fU, 0x1affe52cU, 0x305d6d06U, + 0xb678ce80U, 0x34586c02U, 0xbe72cc88U, 0xe5fc19d3U, + 0x4ebef078U, 0x01212037U, 0x5eaaf468U, 0xfa27ddccU, + 0x42b1f374U, 0x73cdbe45U, 0x84c440b2U, 0x3798af01U, + 0x46b4f270U, 0x14706422U, 0xfe22dcc8U, 0xe1f918d7U, + 0x44347072U, 0xff629dc9U, 0xa269cb94U, 0x7688fe40U, + 0xcb5b90fdU, 0xf4a85cc2U, 0xf628dec0U, 0x88cb43beU, + 0x9cda46aaU, 0xe77c9bd1U, 0xaf268999U, 0x3d122f0bU, + 0xa8e34b9eU, 0x51653467U, 0x8cce42baU, 0x07a4a331U, + 0x22c9eb14U, 0xbf328d89U, 0xc211d3f4U, 0xe3799ad5U, + 0x596f366fU, 0xd1c514e7U, 0x5c2a766aU, 0x67dcbb51U, + 0x7d423f4bU, 0x20496916U, 0x9e5ac4a8U, 0x483b737eU, + 0xc9db12ffU, 0xce1ed0f8U, 0x4d7e337bU, 0xb8f74f8eU, + 0xecb65adaU, 0x919504a7U, 0xbcf24e8aU, 0x05242133U, + 0x3b97ac0dU, 0xd08555e6U, 0x12f5e724U, 0x74087c42U, + 0xf36d9ec5U, 0xf22ddfc4U, 0x700d7d46U, 0x1d3a272bU, + 0x21092817U, 0x2389aa15U, 0xb27dcf84U, 0x04646032U, + 0xe0b959d6U, 0x8b0b80bdU, 0x1efae428U, 0x8a4bc1bcU, + 0x75483d43U, 0xf8a75fceU, 0xd34596e5U, 0x4c3e727aU, + 0x4ffeb179U, 0x43f1b275U, 0xe8b35bdeU, 0x244c6812U, + 0x2b83a81dU, 0x7fc2bd49U, 0x858401b3U, 0xc09151f6U, + 0x0d2e233bU, 0x41713077U, 0xd205d7e4U, 0xc35192f5U, + 0x2f86a919U, 0xb7388f81U, 0x98df47aeU, 0x3ad7ed0cU, + 0x9650c6a0U, 0x7e82fc48U, 0xd600d6e0U, 0x971087a1U, + 0x63d9ba55U, 0x8f0e81b9U, 0xa9a30a9fU, 0x641c7852U, + 0x7a87fd4cU, 0x669cfa50U, 0x1fbaa529U, 0x02e1e334U, + 0xea33d9dcU, 0x6a93f95cU, 0x0faea139U, 0xf0ad5dc6U, + 0xbdb20f8bU, 0xee36d8d8U, 0xf7689fc1U, 0xb33d8e85U, + 0x90d545a6U, 0xa1a90897U, 0x728dff44U, 0xa72c8b91U, + 0xdf4a95e9U, 0x36d8ee00U, 0xe63cdad0U, 0x714d3c47U, + 0x6c167a5aU, 0xfde21fcbU, 0xcdde13fbU, 0x94d044a2U, + 0x45743173U, 0x10756526U, 0xc49450f2U, 0xa5ac0993U, + 0xef7699d9U, 0xf1ed1cc7U, 0x0eeee038U, 0x38576f0eU, + 0x60197956U, 0x311d2c07U, 0x250c2913U, 0xd5c015e3U, + 0x092b223fU, 0x6bd3b85dU, 0xba77cd8cU, 0x68137b5eU, + 0x6d563b5bU, 0x54207462U, 0x9b1f84adU, 0x7c027e4aU, + 0x80c141b6U, 0x3ed2ec08U, 0x8644c2b0U, 0xbb378c8dU, + 0x582f776eU, 0xa0e94996U, 0x26ccea10U, 0x2ec6e818U, + 0x39172e0fU, 0xdc8a56eaU, 0x28436b1eU, 0x61593857U, + 0x9a5fc5acU, 0x35182d03U, 0x655c3953U, 0x56a0f660U, + 0xe4bc58d2U, 0x77c8bf41U, 0xc5d411f3U, 0x6fd6b959U, + 0xedf61bdbU, 0x4abbf17cU, 0x6299fb54U, 0x40317176U, + 0xda0fd5ecU, 0xa3298a95U, 0xd74097e1U, 0x53e5b665U, + 0xb9b70e8fU, 0x818100b7U, 0x32ddef04U, 0xfb679ccdU, + 0x959005a3U, 0x193f262fU, 0xd48054e2U, 0x52a5f764U, + 0xe239dbd4U, 0x11352427U, 0x47f4b371U, 0x278cab11U, + 0x5befb46dU, 0x5feab569U, 0x830182b5U, 0xab23889dU, + 0xd88f57eeU, 0x8241c3b4U, 0x50257566U, 0xa4ec4892U, + 0x00616136U, 0x999f06afU, 0x1c7a662aU, 0x13b5a625U, + 0xaa63c99cU, 0x898b02bfU, 0x9f1a85a9U, 0xeb7398ddU, + 0x9255c7a4U, 0xae66c898U, 0x870483b1U, 0x8d8e03bbU, + 0xc614d2f0U, 0xe9f31adfU, 0x2ac3e91cU, 0xcc9e52faU, + 0x78077f4eU, 0xd9cf16efU, 0x03a1a235U, 0x187f672eU, + 0x5aaff56cU, 0x3f92ad09U, 0xada60b9bU, 0xa66cca90U, + 0x0c6e623aU, 0x79473e4fU, 0x3c526e0aU, 0x2c466a1aU, + 0xc89b53feU, 0x4bfbb07dU, 0xb0fd4d86U, 0xc75493f1U, + 0xde0ad4e8U, 0xb4f84c82U, 0x339dae05U, 0x17b0a721U, + 0x7bc7bc4dU, 0x086b633eU, 0x29032a1fU, 0xca1bd1fcU, + 0xf9e71ecfU, 0x57e0b761U, 0xf5e81dc3U, 0xfca25ecaU, + 0x8e4ec0b8U, 0x2d062b1bU, 0x1bbfa42dU, 0x5d6a376bU, + 0x06e4e230U, 0x9d9a07abU, 0xdb4f94edU, 0x6e96f858U, + 0x0baba03dU, 0x55603563U, 0x931586a5U, 0x16f0e620U, + 0xb1bd0c87U, 0xc1d110f7U, 0x0aebe13cU, 0xcf5e91f9U, + 0x518cdd53U, 0x48d29a4aU, 0xad4fe2afU, 0xf104f5f3U, + 0x39fec73bU, 0x8d67ea8fU, 0xfecb35fcU, 0xd469bdd6U, + 0x524c1e50U, 0xd06cbcd2U, 0x5a461c58U, 0x01c8c903U, + 0xaa8a20a8U, 0xe515f0e7U, 0xba9e24b8U, 0x1e130d1cU, + 0xa68523a4U, 0x97f96e95U, 0x60f09062U, 0xd3ac7fd1U, + 0xa28022a0U, 0xf044b4f2U, 0x1a160c18U, 0x05cdc807U, + 0xa000a0a2U, 0x1b564d19U, 0x465d1b44U, 0x92bc2e90U, + 0x2f6f402dU, 0x109c8c12U, 0x121c0e10U, 0x6cff936eU, + 0x78ee967aU, 0x03484b01U, 0x4b125949U, 0xd926ffdbU, + 0x4cd79b4eU, 0xb551e4b7U, 0x68fa926aU, 0xe39073e1U, + 0xc6fd3bc4U, 0x5b065d59U, 0x26250324U, 0x074d4a05U, + 0xbd5be6bfU, 0x35f1c437U, 0xb81ea6baU, 0x83e86b81U, + 0x9976ef9bU, 0xc47db9c6U, 0x7a6e1478U, 0xac0fa3aeU, + 0x2defc22fU, 0x2a2a0028U, 0xa94ae3abU, 0x5cc39f5eU, + 0x08828a0aU, 0x75a1d477U, 0x58c69e5aU, 0xe110f1e3U, + 0xdfa37cddU, 0x34b18536U, 0xf6c137f4U, 0x903cac92U, + 0x17594e15U, 0x16190f14U, 0x9439ad96U, 0xf90ef7fbU, + 0xc53df8c7U, 0xc7bd7ac5U, 0x56491f54U, 0xe050b0e2U, + 0x048d8906U, 0x6f3f506dU, 0xface34f8U, 0x6e7f116cU, + 0x917ced93U, 0x1c938f1eU, 0x37714635U, 0xa80aa2aaU, + 0xabca61a9U, 0xa7c562a5U, 0x0c878b0eU, 0xc078b8c2U, + 0xcfb778cdU, 0x9bf66d99U, 0x61b0d163U, 0x24a58126U, + 0xe91af3ebU, 0xa545e0a7U, 0x36310734U, 0x27654225U, + 0xcbb279c9U, 0x530c5f51U, 0x7ceb977eU, 0xdee33ddcU, + 0x72641670U, 0x9ab62c98U, 0x32340630U, 0x73245771U, + 0x87ed6a85U, 0x6b3a5169U, 0x4d97da4fU, 0x8028a882U, + 0x9eb32d9cU, 0x82a82a80U, 0xfb8e75f9U, 0xe6d533e4U, + 0x0e07090cU, 0x8ea7298cU, 0xeb9a71e9U, 0x14998d16U, + 0x5986df5bU, 0x0a020808U, 0x135c4f11U, 0x57095e55U, + 0x74e19576U, 0x459dd847U, 0x96b92f94U, 0x43185b41U, + 0x3b7e4539U, 0xd2ec3ed0U, 0x02080a00U, 0x9579ec97U, + 0x8822aa8aU, 0x19d6cf1bU, 0x29eac32bU, 0x70e49472U, + 0xa140e1a3U, 0xf441b5f6U, 0x20a08022U, 0x4198d943U, + 0x0b424909U, 0x15d9cc17U, 0xeada30e8U, 0xdc63bfdeU, + 0x842da986U, 0xd529fcd7U, 0xc138f9c3U, 0x31f4c533U, + 0xed1ff2efU, 0x8fe7688dU, 0x5e431d5cU, 0x8c27ab8eU, + 0x8962eb8bU, 0xb014a4b2U, 0x7f2b547dU, 0x9836ae9aU, + 0x64f59166U, 0xdae63cd8U, 0x62701260U, 0x5f035c5dU, + 0xbc1ba7beU, 0x44dd9946U, 0xc2f83ac0U, 0xcaf238c8U, + 0xdd23fedfU, 0x38be863aU, 0xcc77bbceU, 0x856de887U, + 0x7e6b157cU, 0xd12cfdd3U, 0x8168e983U, 0xb29426b0U, + 0x00888802U, 0x93fc6f91U, 0x21e0c123U, 0x8be26989U, + 0x09c2cb0bU, 0xae8f21acU, 0x86ad2b84U, 0xa405a1a6U, + 0x3e3b053cU, 0x471d5a45U, 0x33744731U, 0xb7d166b5U, + 0x5d83de5fU, 0x65b5d067U, 0xd6e93fd4U, 0x1f534c1dU, + 0x71a4d573U, 0xfd0bf6ffU, 0x30b48432U, 0xb69127b4U, + 0x060d0b04U, 0xf501f4f7U, 0xa3c063a1U, 0xc3b87bc1U, + 0xbfdb64bdU, 0xbbde65b9U, 0x67355265U, 0x4f17584dU, + 0x3cbb873eU, 0x66751364U, 0xb411a5b6U, 0x40d89842U, + 0xe455b1e6U, 0x7dabd67fU, 0xf84eb6faU, 0xf78176f5U, + 0x4e57194cU, 0x6dbfd26fU, 0x7b2e5579U, 0x0f47480dU, + 0x76611774U, 0x4a521848U, 0x63305361U, 0x69bad36bU, + 0x22200220U, 0x0dc7ca0fU, 0xcef739ccU, 0x28aa822aU, + 0x9c33af9eU, 0x3dfbc63fU, 0xe79572e5U, 0xfc4bb7feU, + 0xbe9b25bcU, 0xdba67dd9U, 0x4992db4bU, 0x42581a40U, + 0xe85ab2eaU, 0x9d73ee9fU, 0xd866bedaU, 0xc872bacaU, + 0x2caf832eU, 0xafcf60adU, 0x54c99d56U, 0x23604321U, + 0x3a3e0438U, 0x50cc9c52U, 0xd7a97ed5U, 0xf38477f1U, + 0x9ff36c9dU, 0xec5fb3eeU, 0xcd37facfU, 0x2e2f012cU, + 0x1dd3ce1fU, 0xb3d467b1U, 0x11dccd13U, 0x18968e1aU, + 0x6a7a1068U, 0xc932fbcbU, 0xff8b74fdU, 0xb95ee7bbU, + 0xe2d032e0U, 0x79aed77bU, 0x3f7b443dU, 0x8aa22888U, + 0xef9f70edU, 0xb154e5b3U, 0x77215675U, 0xf2c436f0U, + 0x5589dc57U, 0x25e5c027U, 0xeedf31ecU, 0x2b6a4129U, + 0x206a4ac4U, 0x39340dddU, 0xdca97538U, 0x80e26264U, + 0x481850acU, 0xfc817d18U, 0x8f2da26bU, 0xa58f2a41U, + 0x23aa89c7U, 0xa18a2b45U, 0x2ba08bcfU, 0x702e5e94U, + 0xdb6cb73fU, 0x94f36770U, 0xcb78b32fU, 0x6ff59a8bU, + 0xd763b433U, 0xe61ff902U, 0x111607f5U, 0xa24ae846U, + 0xd366b537U, 0x81a22365U, 0x6bf09b8fU, 0x742b5f90U, + 0xd1e63735U, 0x6ab0da8eU, 0x37bb8cd3U, 0xe35ab907U, + 0x5e89d7baU, 0x617a1b85U, 0x63fa9987U, 0x1d1904f9U, + 0x090801edU, 0x72aedc96U, 0x3af4cedeU, 0xa8c0684cU, + 0x3d310cd9U, 0xc4b77320U, 0x191c05fdU, 0x9276e476U, + 0xb71bac53U, 0x2ae0caceU, 0x57c394b3U, 0x76abdd92U, + 0xccbd7128U, 0x441753a0U, 0xc9f8312dU, 0xf20efc16U, + 0xe890780cU, 0xb59b2e51U, 0x0b8883efU, 0xdde93439U, + 0x5c0955b8U, 0x5bcc97bfU, 0xd8ac743cU, 0x2d2508c9U, + 0x79641d9dU, 0x044743e0U, 0x292009cdU, 0x90f66674U, + 0xae45eb4aU, 0x455712a1U, 0x8727a063U, 0xe1da3b05U, + 0x66bfd982U, 0x67ff9883U, 0xe5df3a01U, 0x88e8606cU, + 0xb4db6f50U, 0xb65bed52U, 0x27af88c3U, 0x91b62775U, + 0x756b1e91U, 0x1ed9c7faU, 0x8b28a36fU, 0x1f9986fbU, + 0xe09a7a04U, 0x6d751889U, 0x4697d1a2U, 0xd9ec353dU, + 0xda2cf63eU, 0xd623f532U, 0x7d611c99U, 0xb19e2f55U, + 0xbe51ef5aU, 0xea10fa0eU, 0x105646f4U, 0x554316b1U, + 0x98fc647cU, 0xd4a37730U, 0x47d790a3U, 0x5683d5b2U, + 0xba54ee5eU, 0x22eac8c6U, 0x0d0d00e9U, 0xaf05aa4bU, + 0x038281e7U, 0xeb50bb0fU, 0x43d291a7U, 0x02c2c0e6U, + 0xf60bfd12U, 0x1adcc6feU, 0x3c714dd8U, 0xf1ce3f15U, + 0xef55ba0bU, 0xf34ebd17U, 0x8a68e26eU, 0x9733a473U, + 0x7fe19e9bU, 0xff41be1bU, 0x9a7ce67eU, 0x657f1a81U, + 0x286048ccU, 0x7be49f9fU, 0x62bad886U, 0x26efc9c2U, + 0x050702e1U, 0x347b4fd0U, 0xe75fb803U, 0x32feccd6U, + 0x4a98d2aeU, 0xa30aa947U, 0x73ee9d97U, 0xe49f7b00U, + 0xf9c43d1dU, 0x6830588cU, 0x580c54bcU, 0x010203e5U, + 0xd0a67634U, 0x85a72261U, 0x514617b5U, 0x307e4ed4U, + 0x7aa4de9eU, 0x643f5b80U, 0x9b3ca77fU, 0xad852849U, + 0xf5cb3e11U, 0xa4cf6b40U, 0xb0de6e54U, 0x401252a4U, + 0x9cf96578U, 0xfe01ff1aU, 0x2fa58acbU, 0xfdc13c19U, + 0xf8847c1cU, 0xc1f23325U, 0x0ecdc3eaU, 0xe9d0390dU, + 0x151306f1U, 0xab00ab4fU, 0x139685f7U, 0x2ee5cbcaU, + 0xcdfd3029U, 0x353b0ed1U, 0xb31ead57U, 0xbb14af5fU, + 0xacc56948U, 0x495811adU, 0xbd912c59U, 0xf48b7f10U, + 0x0f8d82ebU, 0xa0ca6a44U, 0xf08e7e14U, 0xc372b127U, + 0x716e1f95U, 0xe21af806U, 0x500656b4U, 0xfa04fe1eU, + 0x78245c9cU, 0xdf69b63bU, 0xf74bbc13U, 0xd5e33631U, + 0x4fdd92abU, 0x36fbcdd2U, 0x4292d0a6U, 0xc637f122U, + 0x2c6549c8U, 0x145347f0U, 0xa70fa843U, 0x6eb5db8aU, + 0x004242e4U, 0x8ced6168U, 0x415213a5U, 0xc777b023U, + 0x77eb9c93U, 0x84e76360U, 0xd226f436U, 0xb25eec56U, + 0xce3df32aU, 0xca38f22eU, 0x16d3c5f2U, 0x3ef1cfdaU, + 0x4d5d10a9U, 0x179384f3U, 0xc5f73221U, 0x313e0fd5U, + 0x95b32671U, 0x0c4d41e8U, 0x89a8216dU, 0x8667e162U, + 0x3fb18edbU, 0x1c5945f8U, 0x0ac8c2eeU, 0x7ea1df9aU, + 0x078780e3U, 0x3bb48fdfU, 0x12d6c4f6U, 0x185c44fcU, + 0x53c695b7U, 0x7c215d98U, 0xbf11ae5bU, 0x594c15bdU, + 0xedd53809U, 0x4c1d51a8U, 0x9673e572U, 0x8dad2069U, + 0xcf7db22bU, 0xaa40ea4eU, 0x38744cdcU, 0x33be8dd7U, + 0x99bc257dU, 0xec957908U, 0xa980294dU, 0xb9942d5dU, + 0x5d4914b9U, 0xde29f73aU, 0x252f0ac1U, 0x5286d4b6U, + 0x4bd893afU, 0x212a0bc5U, 0xa64fe942U, 0x8262e066U, + 0xee15fb0aU, 0x9db92479U, 0xbcd16d58U, 0x5fc996bbU, + 0x6c355988U, 0xc232f026U, 0x603a5a84U, 0x6970198dU, + 0x1b9c87ffU, 0xb8d46c5cU, 0x8e6de36aU, 0xc8b8702cU, + 0x9336a577U, 0x084840ecU, 0x4e9dd3aaU, 0xfb44bf1fU, + 0x9e79e77aU, 0xc0b27224U, 0x06c7c1e2U, 0x8322a167U, + 0x246f4bc0U, 0x540357b0U, 0x9f39a67bU, 0x5a8cd6beU, + 0x7b2c57d9U, 0x627210c0U, 0x87ef6825U, 0xdba47f79U, + 0x135e4db1U, 0xa7c76005U, 0xd46bbf76U, 0xfec9375cU, + 0x78ec94daU, 0xfacc3658U, 0x70e696d2U, 0x2b684389U, + 0x802aaa22U, 0xcfb57a6dU, 0x903eae32U, 0x34b38796U, + 0x8c25a92eU, 0xbd59e41fU, 0x4a501ae8U, 0xf90cf55bU, + 0x8820a82aU, 0xdae43e78U, 0x30b68692U, 0x2f6d428dU, + 0x8aa02a28U, 0x31f6c793U, 0x6cfd91ceU, 0xb81ca41aU, + 0x05cfcaa7U, 0x3a3c0698U, 0x38bc849aU, 0x465f19e4U, + 0x524e1cf0U, 0x29e8c18bU, 0x61b2d3c3U, 0xf3867551U, + 0x667711c4U, 0x9ff16e3dU, 0x425a18e0U, 0xc930f96bU, + 0xec5db14eU, 0x71a6d7d3U, 0x0c8589aeU, 0x2dedc08fU, + 0x97fb6c35U, 0x1f514ebdU, 0x92be2c30U, 0xa948e10bU, + 0xb3d66511U, 0xeedd334cU, 0x50ce9ef2U, 0x86af2924U, + 0x074f48a5U, 0x008a8aa2U, 0x83ea6921U, 0x766315d4U, + 0x22220080U, 0x5f015efdU, 0x726614d0U, 0xcbb07b69U, + 0xf503f657U, 0x1e110fbcU, 0xdc61bd7eU, 0xba9c2618U, + 0x3df9c49fU, 0x3cb9859eU, 0xbe99271cU, 0xd3ae7d71U, + 0xef9d724dU, 0xed1df04fU, 0x7ce995deU, 0xcaf03a68U, + 0x2e2d038cU, 0x459fdae7U, 0xd06ebe72U, 0x44df9be6U, + 0xbbdc6719U, 0x36330594U, 0x1dd1ccbfU, 0x82aa2820U, + 0x816aeb23U, 0x8d65e82fU, 0x26270184U, 0xead83248U, + 0xe517f247U, 0xb156e713U, 0x4b105be9U, 0x0e050bacU, + 0xc3ba7961U, 0x8fe56a2dU, 0x1c918dbeU, 0x0dc5c8afU, + 0xe112f343U, 0x79acd5dbU, 0x564b1df4U, 0xf443b756U, + 0x58c49cfaU, 0xb016a612U, 0x18948cbaU, 0x5984ddfbU, + 0xad4de00fU, 0x419adbe3U, 0x673750c5U, 0xaa882208U, + 0xb413a716U, 0xa808a00aU, 0xd12eff73U, 0xcc75b96eU, + 0x24a78386U, 0xa407a306U, 0xc13afb63U, 0x3e39079cU, + 0x732655d1U, 0x20a28282U, 0x39fcc59bU, 0x7da9d4dfU, + 0x5e411ffcU, 0x6f3d52cdU, 0xbc19a51eU, 0x69b8d1cbU, + 0x11decfb3U, 0xf84cb45aU, 0x28a8808aU, 0xbfd9661dU, + 0xa2822000U, 0x33764591U, 0x034a49a1U, 0x5a441ef8U, + 0x8be06b29U, 0xdee13f7cU, 0x0a000aa8U, 0x6b3853c9U, + 0x21e2c383U, 0x3f79469dU, 0xc07aba62U, 0xf6c33554U, + 0xae8d230cU, 0xff89765dU, 0xeb987349U, 0x1b544fb9U, + 0xc7bf7865U, 0xa547e207U, 0x74e397d6U, 0xa6872104U, + 0xa3c26101U, 0x9ab42e38U, 0x558bdef7U, 0xb2962410U, + 0x4e551becU, 0xf046b652U, 0x48d098eaU, 0x75a3d6d7U, + 0x96bb2d34U, 0x6e7d13ccU, 0xe858b04aU, 0xe052b242U, + 0xf7837455U, 0x121e0cb0U, 0xe6d73144U, 0xafcd620dU, + 0x54cb9ff6U, 0xfb8c7759U, 0xabc86309U, 0x9834ac3aU, + 0x2a280288U, 0xb95ce51bU, 0x0b404ba9U, 0xa142e303U, + 0x23624181U, 0x842fab26U, 0xac0da10eU, 0x8ea52b2cU, + 0x149b8fb6U, 0x6dbdd0cfU, 0x19d4cdbbU, 0x9d71ec3fU, + 0x772354d5U, 0x4f155aedU, 0xfc49b55eU, 0x35f3c697U, + 0x5b045ff9U, 0xd7ab7c75U, 0x1a140eb8U, 0x9c31ad3eU, + 0x2cad818eU, 0xdfa17e7dU, 0x8960e92bU, 0xe918f14bU, + 0x957bee37U, 0x917eef33U, 0x4d95d8efU, 0x65b7d2c7U, + 0x161b0db4U, 0x4cd599eeU, 0x9eb12f3cU, 0x6a7812c8U, + 0xcef53b6cU, 0x570b5cf5U, 0xd2ee3c70U, 0xdd21fc7fU, + 0x64f793c6U, 0x471f58e5U, 0x518edff3U, 0x25e7c287U, + 0x5cc19dfeU, 0x60f292c2U, 0x4990d9ebU, 0x431a59e1U, + 0x088088aaU, 0x27674085U, 0xe457b346U, 0x020a08a0U, + 0xb6932514U, 0x175b4cb5U, 0xcd35f86fU, 0xd6eb3d74U, + 0x943baf36U, 0xf106f753U, 0x633251c1U, 0x68f890caU, + 0xc2fa3860U, 0xb7d36415U, 0xf2c63450U, 0xe2d23040U, + 0x060f09a4U, 0x856fea27U, 0x7e6917dcU, 0x09c0c9abU, + 0x109e8eb2U, 0x7a6c16d8U, 0xfd09f45fU, 0xd924fd7bU, + 0xb553e617U, 0xc6ff3964U, 0xe7977045U, 0x048f8ba6U, + 0x37734495U, 0x9974ed3bU, 0x3b7c4799U, 0x32360490U, + 0x40da9ae2U, 0xe3927141U, 0xd52bfe77U, 0x93fe6d31U, + 0xc870b86aU, 0x530e5df1U, 0x15dbceb7U, 0xa002a202U, + 0xc53ffa67U, 0x9bf46f39U, 0x5d81dcffU, 0xd864bc7aU, + 0x7f2956ddU, 0x0f454aadU, 0xc47fbb66U, 0x01cacba3U, + 0x8f49c648U, 0x96178151U, 0x738af9b4U, 0x2fc1eee8U, + 0xe73bdc20U, 0x53a2f194U, 0x200e2ee7U, 0x0aaca6cdU, + 0x8c89054bU, 0x0ea9a7c9U, 0x84830743U, 0xdf0dd218U, + 0x744f3bb3U, 0x3bd0ebfcU, 0x645b3fa3U, 0xc0d61607U, + 0x784038bfU, 0x493c758eU, 0xbe358b79U, 0x0d6964caU, + 0x7c4539bbU, 0x2e81afe9U, 0xc4d31703U, 0xdb08d31cU, + 0x7ec5bbb9U, 0xc5935602U, 0x9898005fU, 0x4c79358bU, + 0xf1aa5b36U, 0xce599709U, 0xccd9150bU, 0xb23a8875U, + 0xa62b8d61U, 0xdd8d501aU, 0x95d74252U, 0x07e3e4c0U, + 0x92128055U, 0x6b94ffacU, 0xb63f8971U, 0x3d5568faU, + 0x183820dfU, 0x85c34642U, 0xf8e0183fU, 0xd988511eU, + 0x639efda4U, 0xeb34df2cU, 0x66dbbda1U, 0x5d2d709aU, + 0x47b3f480U, 0x1ab8a2ddU, 0xa4ab0f63U, 0x72cab8b5U, + 0xf32ad934U, 0xf4ef1b33U, 0x778ff8b0U, 0x82068445U, + 0xd6479111U, 0xab64cf6cU, 0x86038541U, 0x3fd5eaf8U, + 0x016667c6U, 0xea749e2dU, 0x28042cefU, 0x4ef9b789U, + 0xc99c550eU, 0xc8dc140fU, 0x4afcb68dU, 0x27cbece0U, + 0x1bf8e3dcU, 0x197861deU, 0x888c044fU, 0x3e95abf9U, + 0xda48921dU, 0xb1fa4b76U, 0x240b2fe3U, 0xb0ba0a77U, + 0x4fb9f688U, 0xc2569405U, 0xe9b45d2eU, 0x76cfb9b1U, + 0x750f7ab2U, 0x790079beU, 0xd2429015U, 0x1ebda3d9U, + 0x117263d6U, 0x45337682U, 0xbf75ca78U, 0xfa609a3dU, + 0x37dfe8f0U, 0x7b80fbbcU, 0xe8f41c2fU, 0xf9a0593eU, + 0x157762d2U, 0x8dc9444aU, 0xa22e8c65U, 0x002626c7U, + 0xaca10d6bU, 0x44733783U, 0xecf11d2bU, 0xade14c6aU, + 0x5928719eU, 0xb5ff4a72U, 0x9352c154U, 0x5eedb399U, + 0x40763687U, 0x5c6d319bU, 0x254b6ee2U, 0x381028ffU, + 0xd0c21217U, 0x50623297U, 0x355f6af2U, 0xca5c960dU, + 0x8743c440U, 0xd4c71313U, 0xcd99540aU, 0x89cc454eU, + 0xaa248e6dU, 0x9b58c35cU, 0x487c348fU, 0x9ddd405aU, + 0xe5bb5e22U, 0x0c2925cbU, 0xdccd111bU, 0x4bbcf78cU, + 0x56e7b191U, 0xc713d400U, 0xf72fd830U, 0xae218f69U, + 0x7f85fab8U, 0x2a84aeedU, 0xfe659b39U, 0x9f5dc258U, + 0xd5875212U, 0xcb1cd70cU, 0x341f2bf3U, 0x02a6a4c5U, + 0x5ae8b29dU, 0x0bece7ccU, 0x1ffde2d8U, 0xef31de28U, + 0x33dae9f4U, 0x51227396U, 0x80860647U, 0x52e2b095U, + 0x57a7f090U, 0x6ed1bfa9U, 0xa1ee4f66U, 0x46f3b581U, + 0xba308a7dU, 0x042327c3U, 0xbcb5097bU, 0x81c64746U, + 0x62debca5U, 0x9a18825dU, 0x1c3d21dbU, 0x143723d3U, + 0x03e6e5c4U, 0xe67b9d21U, 0x12b2a0d5U, 0x5ba8f39cU, + 0xa0ae0e67U, 0x0fe9e6c8U, 0x5fadf298U, 0x6c513dabU, + 0xde4d9319U, 0x4d39748aU, 0xff25da38U, 0x55277292U, + 0xd707d010U, 0x704a3ab7U, 0x5868309fU, 0x7ac0babdU, + 0xe0fe1e27U, 0x99d8415eU, 0xedb15c2aU, 0x69147daeU, + 0x8346c544U, 0xbb70cb7cU, 0x082c24cfU, 0xc1965706U, + 0xaf61ce68U, 0x23ceede4U, 0xee719f29U, 0x68543cafU, + 0xd8c8101fU, 0x2bc4efecU, 0x7d0578baU, 0x1d7d60daU, + 0x611e7fa6U, 0x651b7ea2U, 0xb9f0497eU, 0x91d24356U, + 0xe27e9c25U, 0xb8b0087fU, 0x6ad4beadU, 0x9e1d8359U, + 0x3a90aafdU, 0xa36ecd64U, 0x268bade1U, 0x29446deeU, + 0x90920257U, 0xb37ac974U, 0xa5eb4e62U, 0xd1825316U, + 0xa8a40c6fU, 0x94970353U, 0xbdf5487aU, 0xb77fc870U, + 0xfce5193bU, 0xd302d114U, 0x103222d7U, 0xf66f9931U, + 0x42f6b485U, 0xe33edd24U, 0x395069feU, 0x228eace5U, + 0x605e3ea7U, 0x056366c2U, 0x9757c050U, 0x9c9d015bU, + 0x369fa9f1U, 0x43b6f584U, 0x06a3a5c1U, 0x16b7a1d1U, + 0xf26a9835U, 0x710a7bb6U, 0x8a0c864dU, 0xfda5583aU, + 0xe4fb1f23U, 0x8e098749U, 0x096c65ceU, 0x2d416ceaU, + 0x41367786U, 0x329aa8f5U, 0x13f2e1d4U, 0xf0ea1a37U, + 0xc316d504U, 0x6d117caaU, 0xcf19d608U, 0xc6539501U, + 0xb4bf0b73U, 0x17f7e0d0U, 0x214e6fe6U, 0x679bfca0U, + 0x3c1529fbU, 0xa76bcc60U, 0xe1be5f26U, 0x54673393U, + 0x315a6bf6U, 0x6f91fea8U, 0xa9e44d6eU, 0x2c012debU, + 0x8b4cc74cU, 0xfb20db3cU, 0x301a2af7U, 0xf5af5a32U, + 0xb345f678U, 0xaa1bb161U, 0x4f86c984U, 0x13cdded8U, + 0xdb37ec10U, 0x6faec1a4U, 0x1c021ed7U, 0x36a096fdU, + 0xb085357bU, 0x32a597f9U, 0xb88f3773U, 0xe301e228U, + 0x48430b83U, 0x07dcdbccU, 0x58570f93U, 0xfcda2637U, + 0x444c088fU, 0x753045beU, 0x8239bb49U, 0x316554faU, + 0x4049098bU, 0x128d9fd9U, 0xf8df2733U, 0xe704e32cU, + 0x42c98b89U, 0xf99f6632U, 0xa494306fU, 0x707505bbU, + 0xcda66b06U, 0xf255a739U, 0xf0d5253bU, 0x8e36b845U, + 0x9a27bd51U, 0xe181602aU, 0xa9db7262U, 0x3befd4f0U, + 0xae1eb065U, 0x5798cf9cU, 0x8a33b941U, 0x015958caU, + 0x243410efU, 0xb9cf7672U, 0xc4ec280fU, 0xe584612eU, + 0x5f92cd94U, 0xd738ef1cU, 0x5ad78d91U, 0x612140aaU, + 0x7bbfc4b0U, 0x26b492edU, 0x98a73f53U, 0x4ec68885U, + 0xcf26e904U, 0xc8e32b03U, 0x4b83c880U, 0xbe0ab475U, + 0xea4ba121U, 0x9768ff5cU, 0xba0fb571U, 0x03d9dac8U, + 0x3d6a57f6U, 0xd678ae1dU, 0x14081cdfU, 0x72f587b9U, + 0xf590653eU, 0xf4d0243fU, 0x76f086bdU, 0x1bc7dcd0U, + 0x27f4d3ecU, 0x257451eeU, 0xb480347fU, 0x02999bc9U, + 0xe644a22dU, 0x8df67b46U, 0x18071fd3U, 0x8cb63a47U, + 0x73b5c6b8U, 0xfe5aa435U, 0xd5b86d1eU, 0x4ac38981U, + 0x49034a82U, 0x450c498eU, 0xee4ea025U, 0x22b193e9U, + 0x2d7e53e6U, 0x793f46b2U, 0x8379fa48U, 0xc66caa0dU, + 0x0bd3d8c0U, 0x478ccb8cU, 0xd4f82c1fU, 0xc5ac690eU, + 0x297b52e2U, 0xb1c5747aU, 0x9e22bc55U, 0x3c2a16f7U, + 0x90ad3d5bU, 0x787f07b3U, 0xd0fd2d1bU, 0x91ed7c5aU, + 0x652441aeU, 0x89f37a42U, 0xaf5ef164U, 0x62e183a9U, + 0x7c7a06b7U, 0x606101abU, 0x19475ed2U, 0x041c18cfU, + 0xecce2227U, 0x6c6e02a7U, 0x09535ac2U, 0xf650a63dU, + 0xbb4ff470U, 0xe8cb2323U, 0xf195643aU, 0xb5c0757eU, + 0x9628be5dU, 0xa754f36cU, 0x747004bfU, 0xa1d1706aU, + 0xd9b76e12U, 0x302515fbU, 0xe0c1212bU, 0x77b0c7bcU, + 0x6aeb81a1U, 0xfb1fe430U, 0xcb23e800U, 0x922dbf59U, + 0x4389ca88U, 0x16889eddU, 0xc269ab09U, 0xa351f268U, + 0xe98b6222U, 0xf710e73cU, 0x08131bc3U, 0x3eaa94f5U, + 0x66e482adU, 0x37e0d7fcU, 0x23f1d2e8U, 0xd33dee18U, + 0x0fd6d9c4U, 0x6d2e43a6U, 0xbc8a3677U, 0x6eee80a5U, + 0x6babc0a0U, 0x52dd8f99U, 0x9de27f56U, 0x7aff85b1U, + 0x863cba4dU, 0x382f17f3U, 0x80b9394bU, 0xbdca7776U, + 0x5ed28c95U, 0xa614b26dU, 0x203111ebU, 0x283b13e3U, + 0x3fead5f4U, 0xda77ad11U, 0x2ebe90e5U, 0x67a4c3acU, + 0x9ca23e57U, 0x33e5d6f8U, 0x63a1c2a8U, 0x505d0d9bU, + 0xe241a329U, 0x713544baU, 0xc329ea08U, 0x692b42a2U, + 0xeb0be020U, 0x4c460a87U, 0x646400afU, 0x46cc8a8dU, + 0xdcf22e17U, 0xa5d4716eU, 0xd1bd6c1aU, 0x55184d9eU, + 0xbf4af574U, 0x877cfb4cU, 0x342014ffU, 0xfd9a6736U, + 0x936dfe58U, 0x1fc2ddd4U, 0xd27daf19U, 0x54580c9fU, + 0xe4c4202fU, 0x17c8dfdcU, 0x4109488aU, 0x217150eaU, + 0x5d124f96U, 0x59174e92U, 0x85fc794eU, 0xadde7366U, + 0xde72ac15U, 0x84bc384fU, 0x56d88e9dU, 0xa211b369U, + 0x069c9acdU, 0x9f62fd54U, 0x1a879dd1U, 0x15485ddeU, + 0xac9e3267U, 0x8f76f944U, 0x99e77e52U, 0xed8e6326U, + 0x94a83c5fU, 0xa89b3363U, 0x81f9784aU, 0x8b73f840U, + 0xc0e9290bU, 0xef0ee124U, 0x2c3e12e7U, 0xca63a901U, + 0x7efa84b5U, 0xdf32ed14U, 0x055c59ceU, 0x1e829cd5U, + 0x5c520e97U, 0x396f56f2U, 0xab5bf060U, 0xa091316bU, + 0x0a9399c1U, 0x7fbac5b4U, 0x3aaf95f1U, 0x2abb91e1U, + 0xce66a805U, 0x4d064b86U, 0xb600b67dU, 0xc1a9680aU, + 0xd8f72f13U, 0xb205b779U, 0x356055feU, 0x114d5cdaU, + 0x7d3a47b6U, 0x0e9698c5U, 0x2ffed1e4U, 0xcce62a07U, + 0xff1ae534U, 0x511d4c9aU, 0xf315e638U, 0xfa5fa531U, + 0x88b33b43U, 0x2bfbd0e0U, 0x1d425fd6U, 0x5b97cc90U, + 0x001919cbU, 0x9b67fc50U, 0xddb26f16U, 0x686b03a3U, + 0x0d565bc6U, 0x539dce98U, 0x95e87d5eU, 0x100d1ddbU, + 0xb740f77cU, 0xc72ceb0cU, 0x0c161ac7U, 0xc9a36a02U, + 0xbd12af21U, 0xa44ce838U, 0x41d190ddU, 0x1d9a8781U, + 0xd560b549U, 0x61f998fdU, 0x1255478eU, 0x38f7cfa4U, + 0xbed26c22U, 0x3cf2cea0U, 0xb6d86e2aU, 0xed56bb71U, + 0x461452daU, 0x098b8295U, 0x560056caU, 0xf28d7f6eU, + 0x4a1b51d6U, 0x7b671ce7U, 0x8c6ee210U, 0x3f320da3U, + 0x4e1e50d2U, 0x1cdac680U, 0xf6887e6aU, 0xe953ba75U, + 0x4c9ed2d0U, 0xf7c83f6bU, 0xaac36936U, 0x7e225ce2U, + 0xc3f1325fU, 0xfc02fe60U, 0xfe827c62U, 0x8061e11cU, + 0x9470e408U, 0xefd63973U, 0xa78c2b3bU, 0x35b88da9U, + 0xa049e93cU, 0x59cf96c5U, 0x8464e018U, 0x0f0e0193U, + 0x2a6349b6U, 0xb7982f2bU, 0xcabb7156U, 0xebd33877U, + 0x51c594cdU, 0xd96fb645U, 0x5480d4c8U, 0x6f7619f3U, + 0x75e89de9U, 0x28e3cbb4U, 0x96f0660aU, 0x4091d1dcU, + 0xc171b05dU, 0xc6b4725aU, 0x45d491d9U, 0xb05ded2cU, + 0xe41cf878U, 0x993fa605U, 0xb458ec28U, 0x0d8e8391U, + 0x333d0eafU, 0xd82ff744U, 0x1a5f4586U, 0x7ca2dee0U, + 0xfbc73c67U, 0xfa877d66U, 0x78a7dfe4U, 0x15908589U, + 0x29a38ab5U, 0x2b2308b7U, 0xbad76d26U, 0x0ccec290U, + 0xe813fb74U, 0x83a1221fU, 0x1650468aU, 0x82e1631eU, + 0x7de29fe1U, 0xf00dfd6cU, 0xdbef3447U, 0x4494d0d8U, + 0x475413dbU, 0x4b5b10d7U, 0xe019f97cU, 0x2ce6cab0U, + 0x23290abfU, 0x77681febU, 0x8d2ea311U, 0xc83bf354U, + 0x05848199U, 0x49db92d5U, 0xdaaf7546U, 0xcbfb3057U, + 0x272c0bbbU, 0xbf922d23U, 0x9075e50cU, 0x327d4faeU, + 0x9efa6402U, 0x76285eeaU, 0xdeaa7442U, 0x9fba2503U, + 0x6b7318f7U, 0x87a4231bU, 0xa109a83dU, 0x6cb6daf0U, + 0x722d5feeU, 0x6e3658f2U, 0x1710078bU, 0x0a4b4196U, + 0xe2997b7eU, 0x62395bfeU, 0x0704039bU, 0xf807ff64U, + 0xb518ad29U, 0xe69c7a7aU, 0xffc23d63U, 0xbb972c27U, + 0x987fe704U, 0xa903aa35U, 0x7a275de6U, 0xaf862933U, + 0xd7e0374bU, 0x3e724ca2U, 0xee967872U, 0x79e79ee5U, + 0x64bcd8f8U, 0xf548bd69U, 0xc574b159U, 0x9c7ae600U, + 0x4dde93d1U, 0x18dfc784U, 0xcc3ef250U, 0xad06ab31U, + 0xe7dc3b7bU, 0xf947be65U, 0x0644429aU, 0x30fdcdacU, + 0x68b3dbf4U, 0x39b78ea5U, 0x2da68bb1U, 0xdd6ab741U, + 0x0181809dU, 0x63791affU, 0xb2dd6f2eU, 0x60b9d9fcU, + 0x65fc99f9U, 0x5c8ad6c0U, 0x93b5260fU, 0x74a8dce8U, + 0x886be314U, 0x36784eaaU, 0x8eee6012U, 0xb39d2e2fU, + 0x5085d5ccU, 0xa843eb34U, 0x2e6648b2U, 0x266c4abaU, + 0x31bd8cadU, 0xd420f448U, 0x20e9c9bcU, 0x69f39af5U, + 0x92f5670eU, 0x3db28fa1U, 0x6df69bf1U, 0x5e0a54c2U, + 0xec16fa70U, 0x7f621de3U, 0xcd7eb351U, 0x677c1bfbU, + 0xe55cb979U, 0x421153deU, 0x6a3359f6U, 0x489bd3d4U, + 0xd2a5774eU, 0xab832837U, 0xdfea3543U, 0x5b4f14c7U, + 0xb11dac2dU, 0x892ba215U, 0x3a774da6U, 0xf3cd3e6fU, + 0x9d3aa701U, 0x1195848dU, 0xdc2af640U, 0x5a0f55c6U, + 0xea937976U, 0x199f8685U, 0x4f5e11d3U, 0x2f2609b3U, + 0x534516cfU, 0x574017cbU, 0x8bab2017U, 0xa3892a3fU, + 0xd025f54cU, 0x8aeb6116U, 0x588fd7c4U, 0xac46ea30U, + 0x08cbc394U, 0x9135a40dU, 0x14d0c488U, 0x1b1f0487U, + 0xa2c96b3eU, 0x8121a01dU, 0x97b0270bU, 0xe3d93a7fU, + 0x9aff6506U, 0xa6cc6a3aU, 0x8fae2113U, 0x8524a119U, + 0xcebe7052U, 0xe159b87dU, 0x22694bbeU, 0xc434f058U, + 0x70adddecU, 0xd165b44dU, 0x0b0b0097U, 0x10d5c58cU, + 0x520557ceU, 0x37380fabU, 0xa50ca939U, 0xaec66832U, + 0x04c4c098U, 0x71ed9cedU, 0x34f8cca8U, 0x24ecc8b8U, + 0xc031f15cU, 0x435112dfU, 0xb857ef24U, 0xcffe3153U, + 0xd6a0764aU, 0xbc52ee20U, 0x3b370ca7U, 0x1f1a0583U, + 0x736d1eefU, 0x00c1c19cU, 0x21a988bdU, 0xc2b1735eU, + 0xf14dbc6dU, 0x5f4a15c3U, 0xfd42bf61U, 0xf408fc68U, + 0x86e4621aU, 0x25ac89b9U, 0x1315068fU, 0x55c095c9U, + 0x0e4e4092U, 0x9530a509U, 0xd3e5364fU, 0x663c5afaU, + 0x0301029fU, 0x5dca97c1U, 0x9bbf2407U, 0x1e5a4482U, + 0xb917ae25U, 0xc97bb255U, 0x0241439eU, 0xc7f4335bU, + 0x19677ef0U, 0x003939e9U, 0xe5a4410cU, 0xb9ef5650U, + 0x71156498U, 0xc58c492cU, 0xb620965fU, 0x9c821e75U, + 0x1aa7bdf3U, 0x98871f71U, 0x12adbffbU, 0x49236aa0U, + 0xe261830bU, 0xadfe5344U, 0xf275871bU, 0x56f8aebfU, + 0xee6e8007U, 0xdf12cd36U, 0x281b33c1U, 0x9b47dc72U, + 0xea6b8103U, 0xb8af1751U, 0x52fdafbbU, 0x4d266ba4U, + 0xe8eb0301U, 0x53bdeebaU, 0x0eb6b8e7U, 0xda578d33U, + 0x6784e38eU, 0x58772fb1U, 0x5af7adb3U, 0x241430cdU, + 0x300535d9U, 0x4ba3e8a2U, 0x03f9faeaU, 0x91cd5c78U, + 0x043c38edU, 0xfdba4714U, 0x201131c9U, 0xab7bd042U, + 0x8e169867U, 0x13edfefaU, 0x6ecea087U, 0x4fa6e9a6U, + 0xf5b0451cU, 0x7d1a6794U, 0xf0f50519U, 0xcb03c822U, + 0xd19d4c38U, 0x8c961a65U, 0x3285b7dbU, 0xe4e4000dU, + 0x6504618cU, 0x62c1a38bU, 0xe1a14008U, 0x14283cfdU, + 0x406929a9U, 0x3d4a77d4U, 0x102d3df9U, 0xa9fb5240U, + 0x9748df7eU, 0x7c5a2695U, 0xbe2a9457U, 0xd8d70f31U, + 0x5fb2edb6U, 0x5ef2acb7U, 0xdcd20e35U, 0xb1e55458U, + 0x8dd65b64U, 0x8f56d966U, 0x1ea2bcf7U, 0xa8bb1341U, + 0x4c662aa5U, 0x27d4f3ceU, 0xb225975bU, 0x2694b2cfU, + 0xd9974e30U, 0x54782cbdU, 0x7f9ae596U, 0xe0e10109U, + 0xe321c20aU, 0xef2ec106U, 0x446c28adU, 0x88931b61U, + 0x875cdb6eU, 0xd31dce3aU, 0x295b72c0U, 0x6c4e2285U, + 0xa1f15048U, 0xedae4304U, 0x7edaa497U, 0x6f8ee186U, + 0x8359da6aU, 0x1be7fcf2U, 0x340034ddU, 0x96089e7fU, + 0x3a8fb5d3U, 0xd25d8f3bU, 0x7adfa593U, 0x3bcff4d2U, + 0xcf06c926U, 0x23d1f2caU, 0x057c79ecU, 0xc8c30b21U, + 0xd6588e3fU, 0xca438923U, 0xb365d65aU, 0xae3e9047U, + 0x46ecaaafU, 0xc64c8a2fU, 0xa371d24aU, 0x5c722eb5U, + 0x116d7cf8U, 0x42e9ababU, 0x5bb7ecb2U, 0x1fe2fdf6U, + 0x3c0a36d5U, 0x0d767be4U, 0xde528c37U, 0x0bf3f8e2U, + 0x7395e69aU, 0x9a079d73U, 0x4ae3a9a3U, 0xdd924f34U, + 0xc0c90929U, 0x513d6cb8U, 0x61016088U, 0x380f37d1U, + 0xe9ab4200U, 0xbcaa1655U, 0x684b2381U, 0x09737ae0U, + 0x43a9eaaaU, 0x5d326fb4U, 0xa231934bU, 0x94881c7dU, + 0xccc60a25U, 0x9dc25f74U, 0x89d35a60U, 0x791f6690U, + 0xa5f4514cU, 0xc70ccb2eU, 0x16a8beffU, 0xc4cc082dU, + 0xc1894828U, 0xf8ff0711U, 0x37c0f7deU, 0xd0dd0d39U, + 0x2c1e32c5U, 0x920d9f7bU, 0x2a9bb1c3U, 0x17e8fffeU, + 0xf4f0041dU, 0x0c363ae5U, 0x8a139963U, 0x82199b6bU, + 0x95c85d7cU, 0x70552599U, 0x849c186dU, 0xcd864b24U, + 0x3680b6dfU, 0x99c75e70U, 0xc9834a20U, 0xfa7f8513U, + 0x48632ba1U, 0xdb17cc32U, 0x690b6280U, 0xc309ca2aU, + 0x412968a8U, 0xe664820fU, 0xce468827U, 0xecee0205U, + 0x76d0a69fU, 0x0ff6f9e6U, 0x7b9fe492U, 0xff3ac516U, + 0x15687dfcU, 0x2d5e73c4U, 0x9e029c77U, 0x57b8efbeU, + 0x394f76d0U, 0xb5e0555cU, 0x785f2791U, 0xfe7a8417U, + 0x4ee6a8a7U, 0xbdea5754U, 0xeb2bc002U, 0x8b53d862U, + 0xf730c71eU, 0xf335c61aU, 0x2fdef1c6U, 0x07fcfbeeU, + 0x7450249dU, 0x2e9eb0c7U, 0xfcfa0615U, 0x08333be1U, + 0xacbe1245U, 0x354075dcU, 0xb0a51559U, 0xbf6ad556U, + 0x06bcbaefU, 0x255471ccU, 0x33c5f6daU, 0x47acebaeU, + 0x3e8ab4d7U, 0x02b9bbebU, 0x2bdbf0c2U, 0x215170c8U, + 0x6acba183U, 0x452c69acU, 0x861c9a6fU, 0x60412189U, + 0xd4d80c3dU, 0x7510659cU, 0xaf7ed146U, 0xb4a0145dU, + 0xf670861fU, 0x934dde7aU, 0x017978e8U, 0x0ab3b9e3U, + 0xa0b11149U, 0xd5984d3cU, 0x908d1d79U, 0x80991969U, + 0x6444208dU, 0xe724c30eU, 0x1c223ef5U, 0x6b8be082U, + 0x72d5a79bU, 0x18273ff1U, 0x9f42dd76U, 0xbb6fd452U, + 0xd718cf3eU, 0xa4b4104dU, 0x85dc596cU, 0x66c4a28fU, + 0x55386dbcU, 0xfb3fc412U, 0x59376eb0U, 0x507d2db9U, + 0x2291b3cbU, 0x81d95868U, 0xb760d75eU, 0xf1b54418U, + 0xaa3b9143U, 0x314574d8U, 0x7790e79eU, 0xc2498b2bU, + 0xa774d34eU, 0xf9bf4610U, 0x3fcaf5d6U, 0xba2f9553U, + 0x1d627ff4U, 0x6d0e6384U, 0xa634924fU, 0x6381e28aU, + 0x18332ba5U, 0x016d6cbcU, 0xe4f01459U, 0xb8bb0305U, + 0x704131cdU, 0xc4d81c79U, 0xb774c30aU, 0x9dd64b20U, + 0x1bf3e8a6U, 0x99d34a24U, 0x13f9eaaeU, 0x48773ff5U, + 0xe335d65eU, 0xacaa0611U, 0xf321d24eU, 0x57acfbeaU, + 0xef3ad552U, 0xde469863U, 0x294f6694U, 0x9a138927U, + 0xeb3fd456U, 0xb9fb4204U, 0x53a9faeeU, 0x4c723ef1U, + 0xe9bf5654U, 0x52e9bbefU, 0x0fe2edb2U, 0xdb03d866U, + 0x66d0b6dbU, 0x59237ae4U, 0x5ba3f8e6U, 0x25406598U, + 0x3151608cU, 0x4af7bdf7U, 0x02adafbfU, 0x9099092dU, + 0x05686db8U, 0xfcee1241U, 0x2145649cU, 0xaa2f8517U, + 0x8f42cd32U, 0x12b9abafU, 0x6f9af5d2U, 0x4ef2bcf3U, + 0xf4e41049U, 0x7c4e32c1U, 0xf1a1504cU, 0xca579d77U, + 0xd0c9196dU, 0x8dc24f30U, 0x33d1e28eU, 0xe5b05558U, + 0x645034d9U, 0x6395f6deU, 0xe0f5155dU, 0x157c69a8U, + 0x413d7cfcU, 0x3c1e2281U, 0x117968acU, 0xa8af0715U, + 0x961c8a2bU, 0x7d0e73c0U, 0xbf7ec102U, 0xd9835a64U, + 0x5ee6b8e3U, 0x5fa6f9e2U, 0xdd865b60U, 0xb0b1010dU, + 0x8c820e31U, 0x8e028c33U, 0x1ff6e9a2U, 0xa9ef4614U, + 0x4d327ff0U, 0x2680a69bU, 0xb371c20eU, 0x27c0e79aU, + 0xd8c31b65U, 0x552c79e8U, 0x7eceb0c3U, 0xe1b5545cU, + 0xe275975fU, 0xee7a9453U, 0x45387df8U, 0x89c74e34U, + 0x86088e3bU, 0xd2499b6fU, 0x280f2795U, 0x6d1a77d0U, + 0xa0a5051dU, 0xecfa1651U, 0x7f8ef1c2U, 0x6edab4d3U, + 0x820d8f3fU, 0x1ab3a9a7U, 0x35546188U, 0x975ccb2aU, + 0x3bdbe086U, 0xd309da6eU, 0x7b8bf0c6U, 0x3a9ba187U, + 0xce529c73U, 0x2285a79fU, 0x04282cb9U, 0xc9975e74U, + 0xd70cdb6aU, 0xcb17dc76U, 0xb231830fU, 0xaf6ac512U, + 0x47b8fffaU, 0xc718df7aU, 0xa225871fU, 0x5d267be0U, + 0x103929adU, 0x43bdfefeU, 0x5ae3b9e7U, 0x1eb6a8a3U, + 0x3d5e6380U, 0x0c222eb1U, 0xdf06d962U, 0x0aa7adb7U, + 0x72c1b3cfU, 0x9b53c826U, 0x4bb7fcf6U, 0xdcc61a61U, + 0xc19d5c7cU, 0x506939edU, 0x605535ddU, 0x395b6284U, + 0xe8ff1755U, 0xbdfe4300U, 0x691f76d4U, 0x08272fb5U, + 0x42fdbfffU, 0x5c663ae1U, 0xa365c61eU, 0x95dc4928U, + 0xcd925f70U, 0x9c960a21U, 0x88870f35U, 0x784b33c5U, + 0xa4a00419U, 0xc6589e7bU, 0x17fcebaaU, 0xc5985d78U, + 0xc0dd1d7dU, 0xf9ab5244U, 0x3694a28bU, 0xd189586cU, + 0x2d4a6790U, 0x9359ca2eU, 0x2bcfe496U, 0x16bcaaabU, + 0xf5a45148U, 0x0d626fb0U, 0x8b47cc36U, 0x834dce3eU, + 0x949c0829U, 0x710170ccU, 0x85c84d38U, 0xccd21e71U, + 0x37d4e38aU, 0x98930b25U, 0xc8d71f75U, 0xfb2bd046U, + 0x49377ef4U, 0xda439967U, 0x685f37d5U, 0xc25d9f7fU, + 0x407d3dfdU, 0xe730d75aU, 0xcf12dd72U, 0xedba5750U, + 0x7784f3caU, 0x0ea2acb3U, 0x7acbb1c7U, 0xfe6e9043U, + 0x143c28a9U, 0x2c0a2691U, 0x9f56c922U, 0x56ecbaebU, + 0x381b2385U, 0xb4b40009U, 0x790b72c4U, 0xff2ed142U, + 0x4fb2fdf2U, 0xbcbe0201U, 0xea7f9557U, 0x8a078d37U, + 0xf664924bU, 0xf261934fU, 0x2e8aa493U, 0x06a8aebbU, + 0x750471c8U, 0x2fcae592U, 0xfdae5340U, 0x09676eb4U, + 0xadea4710U, 0x34142089U, 0xb1f1400cU, 0xbe3e8003U, + 0x07e8efbaU, 0x24002499U, 0x3291a38fU, 0x46f8befbU, + 0x3fdee182U, 0x03edeebeU, 0x2a8fa597U, 0x2005259dU, + 0x6b9ff4d6U, 0x44783cf9U, 0x8748cf3aU, 0x611574dcU, + 0xd58c5968U, 0x744430c9U, 0xae2a8413U, 0xb5f44108U, + 0xf724d34aU, 0x92198b2fU, 0x002d2dbdU, 0x0be7ecb6U, + 0xa1e5441cU, 0xd4cc1869U, 0x91d9482cU, 0x81cd4c3cU, + 0x651075d8U, 0xe670965bU, 0x1d766ba0U, 0x6adfb5d7U, + 0x7381f2ceU, 0x19736aa4U, 0x9e168823U, 0xba3b8107U, + 0xd64c9a6bU, 0xa5e04518U, 0x84880c39U, 0x6790f7daU, + 0x546c38e9U, 0xfa6b9147U, 0x58633be5U, 0x512978ecU, + 0x23c5e69eU, 0x808d0d3dU, 0xb634820bU, 0xf0e1114dU, + 0xab6fc416U, 0x3011218dU, 0x76c4b2cbU, 0xc31dde7eU, + 0xa620861bU, 0xf8eb1345U, 0x3e9ea083U, 0xbb7bc006U, + 0x1c362aa1U, 0x6c5a36d1U, 0xa760c71aU, 0x62d5b7dfU, + 0xf906ff71U, 0xe058b868U, 0x05c5c08dU, 0x598ed7d1U, + 0x9174e519U, 0x25edc8adU, 0x564117deU, 0x7ce39ff4U, + 0xfac63c72U, 0x78e69ef0U, 0xf2cc3e7aU, 0xa942eb21U, + 0x0200028aU, 0x4d9fd2c5U, 0x1214069aU, 0xb6992f3eU, + 0x0e0f0186U, 0x3f734cb7U, 0xc87ab240U, 0x7b265df3U, + 0x0a0a0082U, 0x58ce96d0U, 0xb29c2e3aU, 0xad47ea25U, + 0x088a8280U, 0xb3dc6f3bU, 0xeed73966U, 0x3a360cb2U, + 0x87e5620fU, 0xb816ae30U, 0xba962c32U, 0xc475b14cU, + 0xd064b458U, 0xabc26923U, 0xe3987b6bU, 0x71acddf9U, + 0xe45db96cU, 0x1ddbc695U, 0xc070b048U, 0x4b1a51c3U, + 0x6e7719e6U, 0xf38c7f7bU, 0x8eaf2106U, 0xafc76827U, + 0x15d1c49dU, 0x9d7be615U, 0x10948498U, 0x2b6249a3U, + 0x31fccdb9U, 0x6cf79be4U, 0xd2e4365aU, 0x0485818cU, + 0x8565e00dU, 0x82a0220aU, 0x01c0c189U, 0xf449bd7cU, + 0xa008a828U, 0xdd2bf655U, 0xf04cbc78U, 0x499ad3c1U, + 0x77295effU, 0x9c3ba714U, 0x5e4b15d6U, 0x38b68eb0U, + 0xbfd36c37U, 0xbe932d36U, 0x3cb38fb4U, 0x5184d5d9U, + 0x6db7dae5U, 0x6f3758e7U, 0xfec33d76U, 0x48da92c0U, + 0xac07ab24U, 0xc7b5724fU, 0x524416daU, 0xc6f5334eU, + 0x39f6cfb1U, 0xb419ad3cU, 0x9ffb6417U, 0x00808088U, + 0x0340438bU, 0x0f4f4087U, 0xa40da92cU, 0x68f29ae0U, + 0x673d5aefU, 0x337c4fbbU, 0xc93af341U, 0x8c2fa304U, + 0x4190d1c9U, 0x0dcfc285U, 0x9ebb2516U, 0x8fef6007U, + 0x63385bebU, 0xfb867d73U, 0xd461b55cU, 0x76691ffeU, + 0xdaee3452U, 0x323c0ebaU, 0x9abe2412U, 0xdbae7553U, + 0x2f6748a7U, 0xc3b0734bU, 0xe51df86dU, 0x28a28aa0U, + 0x36390fbeU, 0x2a2208a2U, 0x530457dbU, 0x4e5f11c6U, + 0xa68d2b2eU, 0x262d0baeU, 0x431053cbU, 0xbc13af34U, + 0xf10cfd79U, 0xa2882a2aU, 0xbbd66d33U, 0xff837c77U, + 0xdc6bb754U, 0xed17fa65U, 0x3e330db6U, 0xeb927963U, + 0x93f4671bU, 0x7a661cf2U, 0xaa822822U, 0x3df3ceb5U, + 0x20a888a8U, 0xb15ced39U, 0x8160e109U, 0xd86eb650U, + 0x09cac381U, 0x5ccb97d4U, 0x882aa200U, 0xe912fb61U, + 0xa3c86b2bU, 0xbd53ee35U, 0x425012caU, 0x74e99dfcU, + 0x2ca78ba4U, 0x7da3def5U, 0x69b2dbe1U, 0x997ee711U, + 0x4595d0cdU, 0x276d4aafU, 0xf6c93f7eU, 0x24ad89acU, + 0x21e8c9a9U, 0x189e8690U, 0xd7a1765fU, 0x30bc8cb8U, + 0xcc7fb344U, 0x726c1efaU, 0xcafa3042U, 0xf7897e7fU, + 0x1491859cU, 0xec57bb64U, 0x6a7218e2U, 0x62781aeaU, + 0x75a9dcfdU, 0x9034a418U, 0x64fd99ecU, 0x2de7caa5U, + 0xd6e1375eU, 0x79a6dff1U, 0x29e2cba1U, 0x1a1e0492U, + 0xa802aa20U, 0x3b764db3U, 0x896ae301U, 0x23684babU, + 0xa148e929U, 0x0605038eU, 0x2e2709a6U, 0x0c8f8384U, + 0x96b1271eU, 0xef977867U, 0x9bfe6513U, 0x1f5b4497U, + 0xf509fc7dU, 0xcd3ff245U, 0x7e631df6U, 0xb7d96e3fU, + 0xd92ef751U, 0x5581d4ddU, 0x983ea610U, 0x1e1b0596U, + 0xae872926U, 0x5d8bd6d5U, 0x0b4a4183U, 0x6b3259e3U, + 0x1751469fU, 0x1354479bU, 0xcfbf7047U, 0xe79d7a6fU, + 0x9431a51cU, 0xceff3146U, 0x1c9b8794U, 0xe852ba60U, + 0x4cdf93c4U, 0xd521f45dU, 0x50c494d8U, 0x5f0b54d7U, + 0xe6dd3b6eU, 0xc535f04dU, 0xd3a4775bU, 0xa7cd6a2fU, + 0xdeeb3556U, 0xe2d83a6aU, 0xcbba7143U, 0xc130f149U, + 0x8aaa2002U, 0xa54de82dU, 0x667d1beeU, 0x8020a008U, + 0x34b98dbcU, 0x9571e41dU, 0x4f1f50c7U, 0x54c195dcU, + 0x1611079eU, 0x732c5ffbU, 0xe118f969U, 0xead23862U, + 0x40d090c8U, 0x35f9ccbdU, 0x70ec9cf8U, 0x60f898e8U, + 0x8425a10cU, 0x0745428fU, 0xfc43bf74U, 0x8bea6103U, + 0x92b4261aU, 0xf846be70U, 0x7f235cf7U, 0x5b0e55d3U, + 0x37794ebfU, 0x44d591ccU, 0x65bdd8edU, 0x86a5230eU, + 0xb559ec3dU, 0x1b5e4593U, 0xb956ef31U, 0xb01cac38U, + 0xc2f0324aU, 0x61b8d9e9U, 0x570156dfU, 0x11d4c599U, + 0x4a5a10c2U, 0xd124f559U, 0x97f1661fU, 0x22280aaaU, + 0x471552cfU, 0x19dec791U, 0xdfab7457U, 0x5a4e14d2U, + 0xfd03fe75U, 0x8d6fe205U, 0x465513ceU, 0x83e0630bU, + 0xc15f9e10U, 0xd801d909U, 0x3d9ca1ecU, 0x61d7b6b0U, + 0xa92d8478U, 0x1db4a9ccU, 0x6e1876bfU, 0x44bafe95U, + 0xc29f5d13U, 0x40bfff91U, 0xca955f1bU, 0x911b8a40U, + 0x3a5963ebU, 0x75c6b3a4U, 0x2a4d67fbU, 0x8ec04e5fU, + 0x365660e7U, 0x072a2dd6U, 0xf023d321U, 0x437f3c92U, + 0x325361e3U, 0x6097f7b1U, 0x8ac54f5bU, 0x951e8b44U, + 0x30d3e3e1U, 0x8b850e5aU, 0xd68e5807U, 0x026f6dd3U, + 0xbfbc036eU, 0x804fcf51U, 0x82cf4d53U, 0xfc2cd02dU, + 0xe83dd539U, 0x939b0842U, 0xdbc11a0aU, 0x49f5bc98U, + 0xdc04d80dU, 0x2582a7f4U, 0xf829d129U, 0x734330a2U, + 0x562e7887U, 0xcbd51e1aU, 0xb6f64067U, 0x979e0946U, + 0x2d88a5fcU, 0xa5228774U, 0x28cde5f9U, 0x133b28c2U, + 0x09a5acd8U, 0x54aefa85U, 0xeabd573bU, 0x3cdce0edU, + 0xbd3c816cU, 0xbaf9436bU, 0x3999a0e8U, 0xcc10dc1dU, + 0x9851c949U, 0xe5729734U, 0xc815dd19U, 0x71c3b2a0U, + 0x4f703f9eU, 0xa462c675U, 0x661274b7U, 0x00efefd1U, + 0x878a0d56U, 0x86ca4c57U, 0x04eaeed5U, 0x69ddb4b8U, + 0x55eebb84U, 0x576e3986U, 0xc69a5c17U, 0x7083f3a1U, + 0x945eca45U, 0xffec132eU, 0x6a1d77bbU, 0xfeac522fU, + 0x01afaed0U, 0x8c40cc5dU, 0xa7a20576U, 0x38d9e1e9U, + 0x3b1922eaU, 0x371621e6U, 0x9c54c84dU, 0x50abfb81U, + 0x5f643b8eU, 0x0b252edaU, 0xf1639220U, 0xb476c265U, + 0x79c9b0a8U, 0x3596a3e4U, 0xa6e24477U, 0xb7b60166U, + 0x5b613a8aU, 0xc3df1c12U, 0xec38d43dU, 0x4e307e9fU, + 0xe2b75533U, 0x0a656fdbU, 0xa2e74573U, 0xe3f71432U, + 0x173e29c6U, 0xfbe9122aU, 0xdd44990cU, 0x10fbebc1U, + 0x0e606edfU, 0x127b69c3U, 0x6b5d36baU, 0x760670a7U, + 0x9ed44a4fU, 0x1e746acfU, 0x7b4932aaU, 0x844ace55U, + 0xc9559c18U, 0x9ad14b4bU, 0x838f0c52U, 0xc7da1d16U, + 0xe432d635U, 0xd54e9b04U, 0x066a6cd7U, 0xd3cb1802U, + 0xabad067aU, 0x423f7d93U, 0x92db4943U, 0x05aaafd4U, + 0x18f1e9c9U, 0x89058c58U, 0xb9398068U, 0xe037d731U, + 0x3193a2e0U, 0x6492f6b5U, 0xb073c361U, 0xd14b9a00U, + 0x9b910a4aU, 0x850a8f54U, 0x7a0973abU, 0x4cb0fc9dU, + 0x14feeac5U, 0x45fabf94U, 0x51ebba80U, 0xa1278670U, + 0x7dccb1acU, 0x1f342bceU, 0xce905e1fU, 0x1cf4e8cdU, + 0x19b1a8c8U, 0x20c7e7f1U, 0xeff8173eU, 0x08e5edd9U, + 0xf426d225U, 0x4a357f9bU, 0xf2a35123U, 0xcfd01f1eU, + 0x2cc8e4fdU, 0xd40eda05U, 0x522b7983U, 0x5a217b8bU, + 0x4df0bd9cU, 0xa86dc579U, 0x5ca4f88dU, 0x15beabc4U, + 0xeeb8563fU, 0x41ffbe90U, 0x11bbaac0U, 0x224765f3U, + 0x905bcb41U, 0x032f2cd2U, 0xb1338260U, 0x1b312acaU, + 0x99118848U, 0x3e5c62efU, 0x167e68c7U, 0x34d6e2e5U, + 0xaee8467fU, 0xd7ce1906U, 0xa3a70472U, 0x270225f6U, + 0xcd509d1cU, 0xf5669324U, 0x463a7c97U, 0x8f800f5eU, + 0xe1779630U, 0x6dd8b5bcU, 0xa067c771U, 0x264264f7U, + 0x96de4847U, 0x65d2b7b4U, 0x331320e2U, 0x536b3882U, + 0x2f0827feU, 0x2b0d26faU, 0xf7e61126U, 0xdfc41b0eU, + 0xac68c47dU, 0xf6a65027U, 0x24c2e6f5U, 0xd00bdb01U, + 0x7486f2a5U, 0xed78953cU, 0x689df5b9U, 0x675235b6U, + 0xde845a0fU, 0xfd6c912cU, 0xebfd163aU, 0x9f940b4eU, + 0xe6b25437U, 0xda815b0bU, 0xf3e31022U, 0xf9699028U, + 0xb2f34163U, 0x9d14894cU, 0x5e247a8fU, 0xb879c169U, + 0x0ce0ecddU, 0xad28857cU, 0x774631a6U, 0x6c98f4bdU, + 0x2e4866ffU, 0x4b753e9aU, 0xd9419808U, 0xd28b5903U, + 0x7889f1a9U, 0x0da0addcU, 0x48b5fd99U, 0x58a1f989U, + 0xbc7cc06dU, 0x3f1c23eeU, 0xc41ade15U, 0xb3b30062U, + 0xaaed477bU, 0xc01fdf11U, 0x477a3d96U, 0x635734b2U, + 0x0f202fdeU, 0x7c8cf0adU, 0x5de4b98cU, 0xbefc426fU, + 0x8d008d5cU, 0x230724f2U, 0x810f8e50U, 0x8845cd59U, + 0xfaa9532bU, 0x59e1b888U, 0x6f5837beU, 0x298da4f8U, + 0x720371a3U, 0xe97d9438U, 0xafa8077eU, 0x1a716bcbU, + 0x7f4c33aeU, 0x2187a6f0U, 0xe7f21536U, 0x621775b3U, + 0xc55a9f14U, 0xb5368364U, 0x7e0c72afU, 0xbbb9026aU, + 0x1bcfd45aU, 0x02919343U, 0xe70ceba6U, 0xbb47fcfaU, + 0x73bdce32U, 0xc724e386U, 0xb4883cf5U, 0x9e2ab4dfU, + 0x180f1759U, 0x9a2fb5dbU, 0x10051551U, 0x4b8bc00aU, + 0xe0c929a1U, 0xaf56f9eeU, 0xf0dd2db1U, 0x54500415U, + 0xecc62aadU, 0xddba679cU, 0x2ab3996bU, 0x99ef76d8U, + 0xe8c32ba9U, 0xba07bdfbU, 0x50550511U, 0x4f8ec10eU, + 0xea43a9abU, 0x51154410U, 0x0c1e124dU, 0xd8ff2799U, + 0x652c4924U, 0x5adf851bU, 0x585f0719U, 0x26bc9a67U, + 0x32ad9f73U, 0x490b4208U, 0x01515040U, 0x9365f6d2U, + 0x06949247U, 0xff12edbeU, 0x22b99b63U, 0xa9d37ae8U, + 0x8cbe32cdU, 0x11455450U, 0x6c660a2dU, 0x4d0e430cU, + 0xf718efb6U, 0x7fb2cd3eU, 0xf25dafb3U, 0xc9ab6288U, + 0xd335e692U, 0x8e3eb0cfU, 0x302d1d71U, 0xe64caaa7U, + 0x67accb26U, 0x60690921U, 0xe309eaa2U, 0x16809657U, + 0x42c18303U, 0x3fe2dd7eU, 0x12859753U, 0xab53f8eaU, + 0x95e075d4U, 0x7ef28c3fU, 0xbc823efdU, 0xda7fa59bU, + 0x5d1a471cU, 0x5c5a061dU, 0xde7aa49fU, 0xb34dfef2U, + 0x8f7ef1ceU, 0x8dfe73ccU, 0x1c0a165dU, 0xaa13b9ebU, + 0x4ece800fU, 0x257c5964U, 0xb08d3df1U, 0x243c1865U, + 0xdb3fe49aU, 0x56d08617U, 0x7d324f3cU, 0xe249aba3U, + 0xe18968a0U, 0xed866bacU, 0x46c48207U, 0x8a3bb1cbU, + 0x85f471c4U, 0xd1b56490U, 0x2bf3d86aU, 0x6ee6882fU, + 0xa359fae2U, 0xef06e9aeU, 0x7c720e3dU, 0x6d264b2cU, + 0x81f170c0U, 0x194f5658U, 0x36a89e77U, 0x94a034d5U, + 0x38271f79U, 0xd0f52591U, 0x78770f39U, 0x39675e78U, + 0xcdae638cU, 0x21795860U, 0x07d4d346U, 0xca6ba18bU, + 0xd4f02495U, 0xc8eb2389U, 0xb1cd7cf0U, 0xac963aedU, + 0x44440005U, 0xc4e42085U, 0xa1d978e0U, 0x5eda841fU, + 0x13c5d652U, 0x40410101U, 0x591f4618U, 0x1d4a575cU, + 0x3ea29c7fU, 0x0fded14eU, 0xdcfa269dU, 0x095b5248U, + 0x713d4c30U, 0x98af37d9U, 0x484b0309U, 0xdf3ae59eU, + 0xc261a383U, 0x5395c612U, 0x63a9ca22U, 0x3aa79d7bU, + 0xeb03e8aaU, 0xbe02bcffU, 0x6ae3892bU, 0x0bdbd04aU, + 0x41014000U, 0x5f9ac51eU, 0xa09939e1U, 0x9620b6d7U, + 0xce6ea08fU, 0x9f6af5deU, 0x8b7bf0caU, 0x7bb7cc3aU, + 0xa75cfbe6U, 0xc5a46184U, 0x14001455U, 0xc664a287U, + 0xc321e282U, 0xfa57adbbU, 0x35685d74U, 0xd275a793U, + 0x2eb6986fU, 0x90a535d1U, 0x28331b69U, 0x15405554U, + 0xf658aeb7U, 0x0e9e904fU, 0x88bb33c9U, 0x80b131c1U, + 0x9760f7d6U, 0x72fd8f33U, 0x8634b2c7U, 0xcf2ee18eU, + 0x34281c75U, 0x9b6ff4daU, 0xcb2be08aU, 0xf8d72fb9U, + 0x4acb810bU, 0xd9bf6698U, 0x6ba3c82aU, 0xc1a16080U, + 0x4381c202U, 0xe4cc28a5U, 0xccee228dU, 0xee46a8afU, + 0x74780c35U, 0x0d5e534cU, 0x79374e38U, 0xfd926fbcU, + 0x17c0d756U, 0x2ff6d96eU, 0x9caa36ddU, 0x55104514U, + 0x3be7dc7aU, 0xb748fff6U, 0x7af78d3bU, 0xfcd22ebdU, + 0x4c4e020dU, 0xbf42fdfeU, 0xe9836aa8U, 0x89fb72c8U, + 0xf5986db4U, 0xf19d6cb0U, 0x2d765b6cU, 0x05545144U, + 0x76f88e37U, 0x2c361a6dU, 0xfe52acbfU, 0x0a9b914bU, + 0xae16b8efU, 0x37e8df76U, 0xb20dbff3U, 0xbdc27ffcU, + 0x04141045U, 0x27fcdb66U, 0x316d5c70U, 0x45044104U, + 0x3c221e7dU, 0x00111141U, 0x29735a68U, 0x23f9da62U, + 0x68630b29U, 0x4784c306U, 0x84b430c5U, 0x62e98b23U, + 0xd670a697U, 0x77b8cf36U, 0xadd67becU, 0xb608bef7U, + 0xf4d82cb5U, 0x91e574d0U, 0x03d1d242U, 0x081b1349U, + 0xa219bbe3U, 0xd730e796U, 0x9225b7d3U, 0x8231b3c3U, + 0x66ec8a27U, 0xe58c69a4U, 0x1e8a945fU, 0x69234a28U, + 0x707d0d31U, 0x1a8f955bU, 0x9dea77dcU, 0xb9c77ef8U, + 0xd5b06594U, 0xa61cbae7U, 0x8774f3c6U, 0x646c0825U, + 0x5790c716U, 0xf9976eb8U, 0x5b9fc41aU, 0x52d58713U, + 0x20391961U, 0x8371f2c2U, 0xb5c87df4U, 0xf31deeb2U, + 0xa8933be9U, 0x33edde72U, 0x75384d34U, 0xc0e12181U, + 0xa5dc79e4U, 0xfb17ecbaU, 0x3d625f7cU, 0xb8873ff9U, + 0x1fcad55eU, 0x6fa6c92eU, 0xa49c38e5U, 0x61294820U, + 0x804aca44U, 0x99148d5dU, 0x7c89f5b8U, 0x20c2e2e4U, + 0xe838d02cU, 0x5ca1fd98U, 0x2f0d22ebU, 0x05afaac1U, + 0x838a0947U, 0x01aaabc5U, 0x8b800b4fU, 0xd00ede14U, + 0x7b4c37bfU, 0x34d3e7f0U, 0x6b5833afU, 0xcfd51a0bU, + 0x774334b3U, 0x463f7982U, 0xb1368775U, 0x026a68c6U, + 0x734635b7U, 0x2182a3e5U, 0xcbd01b0fU, 0xd40bdf10U, + 0x71c6b7b5U, 0xca905a0eU, 0x979b0c53U, 0x437a3987U, + 0xfea9573aU, 0xc15a9b05U, 0xc3da1907U, 0xbd398479U, + 0xa928816dU, 0xd28e5c16U, 0x9ad44e5eU, 0x08e0e8ccU, + 0x9d118c59U, 0x6497f3a0U, 0xb93c857dU, 0x325664f6U, + 0x173b2cd3U, 0x8ac04a4eU, 0xf7e31433U, 0xd68b5d12U, + 0x6c9df1a8U, 0xe437d320U, 0x69d8b1adU, 0x522e7c96U, + 0x48b0f88cU, 0x15bbaed1U, 0xaba8036fU, 0x7dc9b4b9U, + 0xfc29d538U, 0xfbec173fU, 0x788cf4bcU, 0x8d058849U, + 0xd9449d1dU, 0xa467c360U, 0x8900894dU, 0x30d6e6f4U, + 0x0e656bcaU, 0xe5779221U, 0x270720e3U, 0x41fabb85U, + 0xc69f5902U, 0xc7df1803U, 0x45ffba81U, 0x28c8e0ecU, + 0x14fbefd0U, 0x167b6dd2U, 0x878f0843U, 0x3196a7f5U, + 0xd54b9e11U, 0xbef9477aU, 0x2b0823efU, 0xbfb9067bU, + 0x40bafa84U, 0xcd559809U, 0xe6b75122U, 0x79ccb5bdU, + 0x7a0c76beU, 0x760375b2U, 0xdd419c19U, 0x11beafd5U, + 0x1e716fdaU, 0x4a307a8eU, 0xb076c674U, 0xf5639631U, + 0x38dce4fcU, 0x7483f7b0U, 0xe7f71023U, 0xf6a35532U, + 0x1a746edeU, 0x82ca4846U, 0xad2d8069U, 0x0f252acbU, + 0xa3a20167U, 0x4b703b8fU, 0xe3f21127U, 0xa2e24066U, + 0x562b7d92U, 0xbafc467eU, 0x9c51cd58U, 0x51eebf95U, + 0x4f753a8bU, 0x536e3d97U, 0x2a4862eeU, 0x371324f3U, + 0xdfc11e1bU, 0x5f613e9bU, 0x3a5c66feU, 0xc55f9a01U, + 0x8840c84cU, 0xdbc41f1fU, 0xc29a5806U, 0x86cf4942U, + 0xa5278261U, 0x945bcf50U, 0x477f3883U, 0x92de4c56U, + 0xeab8522eU, 0x032a29c7U, 0xd3ce1d17U, 0x44bffb80U, + 0x59e4bd9dU, 0xc810d80cU, 0xf82cd43cU, 0xa1228365U, + 0x7086f6b4U, 0x2587a2e1U, 0xf1669735U, 0x905ece54U, + 0xda845e1eU, 0xc41fdb00U, 0x3b1c27ffU, 0x0da5a8c9U, + 0x55ebbe91U, 0x04efebc0U, 0x10feeed4U, 0xe032d224U, + 0x3cd9e5f8U, 0x5e217f9aU, 0x8f850a4bU, 0x5de1bc99U, + 0x58a4fc9cU, 0x61d2b3a5U, 0xaeed436aU, 0x49f0b98dU, + 0xb5338671U, 0x0b202bcfU, 0xb3b60577U, 0x8ec54b4aU, + 0x6dddb0a9U, 0x951b8e51U, 0x133e2dd7U, 0x1b342fdfU, + 0x0ce5e9c8U, 0xe978912dU, 0x1db1acd9U, 0x54abff90U, + 0xafad026bU, 0x00eaeac4U, 0x50aefe94U, 0x635231a7U, + 0xd14e9f15U, 0x423a7886U, 0xf026d634U, 0x5a247e9eU, + 0xd804dc1cU, 0x7f4936bbU, 0x576b3c93U, 0x75c3b6b1U, + 0xeffd122bU, 0x96db4d52U, 0xe2b25026U, 0x661771a2U, + 0x8c45c948U, 0xb473c770U, 0x072f28c3U, 0xce955b0aU, + 0xa062c264U, 0x2ccde1e8U, 0xe1729325U, 0x675730a3U, + 0xd7cb1c13U, 0x24c7e3e0U, 0x720674b6U, 0x127e6cd6U, + 0x6e1d73aaU, 0x6a1872aeU, 0xb6f34572U, 0x9ed14f5aU, + 0xed7d9029U, 0xb7b30473U, 0x65d7b2a1U, 0x911e8f55U, + 0x3593a6f1U, 0xac6dc168U, 0x2988a1edU, 0x264761e2U, + 0x9f910e5bU, 0xbc79c578U, 0xaae8426eU, 0xde815f1aU, + 0xa7a70063U, 0x9b940f5fU, 0xb2f64476U, 0xb87cc47cU, + 0xf3e61537U, 0xdc01dd18U, 0x1f312edbU, 0xf96c953dU, + 0x4df5b889U, 0xec3dd128U, 0x365365f2U, 0x2d8da0e9U, + 0x6f5d32abU, 0x0a606aceU, 0x9854cc5cU, 0x939e0d57U, + 0x399ca5fdU, 0x4cb5f988U, 0x09a0a9cdU, 0x19b4adddU, + 0xfd699439U, 0x7e0977baU, 0x850f8a41U, 0xf2a65436U, + 0xebf8132fU, 0x810a8b45U, 0x066f69c2U, 0x224260e6U, + 0x4e357b8aU, 0x3d99a4f9U, 0x1cf1edd8U, 0xffe9163bU, + 0xcc15d908U, 0x621270a6U, 0xc01ada04U, 0xc950990dU, + 0xbbbc077fU, 0x18f4ecdcU, 0x2e4d63eaU, 0x6898f0acU, + 0x331625f7U, 0xa868c06cU, 0xeebd532aU, 0x5b643f9fU, + 0x3e5967faU, 0x6092f2a4U, 0xa6e74162U, 0x230221e7U, + 0x844fcb40U, 0xf423d730U, 0x3f1926fbU, 0xfaac563eU, + 0x83b635bbU, 0x9ae872a2U, 0x7f750a47U, 0x233e1d1bU, + 0xebc42fd3U, 0x5f5d0267U, 0x2cf1dd14U, 0x0653553eU, + 0x8076f6b8U, 0x0256543aU, 0x887cf4b0U, 0xd3f221ebU, + 0x78b0c840U, 0x372f180fU, 0x68a4cc50U, 0xcc29e5f4U, + 0x74bfcb4cU, 0x45c3867dU, 0xb2ca788aU, 0x01969739U, + 0x70baca48U, 0x227e5c1aU, 0xc82ce4f0U, 0xd7f720efU, + 0x723a484aU, 0xc96ca5f1U, 0x9467f3acU, 0x4086c678U, + 0xfd55a8c5U, 0xc2a664faU, 0xc026e6f8U, 0xbec57b86U, + 0xaad47e92U, 0xd172a3e9U, 0x9928b1a1U, 0x0b1c1733U, + 0x9eed73a6U, 0x676b0c5fU, 0xbac07a82U, 0x31aa9b09U, + 0x14c7d32cU, 0x893cb5b1U, 0xf41febccU, 0xd577a2edU, + 0x6f610e57U, 0xe7cb2cdfU, 0x6a244e52U, 0x51d28369U, + 0x4b4c0773U, 0x1647512eU, 0xa854fc90U, 0x7e354b46U, + 0xffd52ac7U, 0xf810e8c0U, 0x7b700b43U, 0x8ef977b6U, + 0xdab862e2U, 0xa79b3c9fU, 0x8afc76b2U, 0x332a190bU, + 0x0d999435U, 0xe68b6ddeU, 0x24fbdf1cU, 0x4206447aU, + 0xc563a6fdU, 0xc423e7fcU, 0x4603457eU, 0x2b341f13U, + 0x1707102fU, 0x1587922dU, 0x8473f7bcU, 0x326a580aU, + 0xd6b761eeU, 0xbd05b885U, 0x28f4dc10U, 0xbc45f984U, + 0x4346057bU, 0xcea967f6U, 0xe54baeddU, 0x7a304a42U, + 0x79f08941U, 0x75ff8a4dU, 0xdebd63e6U, 0x1242502aU, + 0x1d8d9025U, 0x49cc8571U, 0xb38a398bU, 0xf69f69ceU, + 0x3b201b03U, 0x777f084fU, 0xe40befdcU, 0xf55faacdU, + 0x19889121U, 0x8136b7b9U, 0xaed17f96U, 0x0cd9d534U, + 0xa05efe98U, 0x488cc470U, 0xe00eeed8U, 0xa11ebf99U, + 0x55d7826dU, 0xb900b981U, 0x9fad32a7U, 0x5212406aU, + 0x4c89c574U, 0x5092c268U, 0x29b49d11U, 0x34efdb0cU, + 0xdc3de1e4U, 0x5c9dc164U, 0x39a09901U, 0xc6a365feU, + 0x8bbc37b3U, 0xd838e0e0U, 0xc166a7f9U, 0x8533b6bdU, + 0xa6db7d9eU, 0x97a730afU, 0x4483c77cU, 0x9122b3a9U, + 0xe944add1U, 0x00d6d638U, 0xd032e2e8U, 0x4743047fU, + 0x5a184262U, 0xcbec27f3U, 0xfbd02bc3U, 0xa2de7c9aU, + 0x737a094bU, 0x267b5d1eU, 0xf29a68caU, 0x93a231abU, + 0xd978a1e1U, 0xc7e324ffU, 0x38e0d800U, 0x0e595736U, + 0x5617416eU, 0x0713143fU, 0x1302112bU, 0xe3ce2ddbU, + 0x3f251a07U, 0x5ddd8065U, 0x8c79f5b4U, 0x5e1d4366U, + 0x5b580363U, 0x622e4c5aU, 0xad11bc95U, 0x4a0c4672U, + 0xb6cf798eU, 0x08dcd430U, 0xb04afa88U, 0x8d39b4b5U, + 0x6e214f56U, 0x96e771aeU, 0x10c2d228U, 0x18c8d020U, + 0x0f191637U, 0xea846ed2U, 0x1e4d5326U, 0x5757006fU, + 0xac51fd94U, 0x0316153bU, 0x5352016bU, 0x60aece58U, + 0xd2b260eaU, 0x41c68779U, 0xf3da29cbU, 0x59d88161U, + 0xdbf823e3U, 0x7cb5c944U, 0x5497c36cU, 0x763f494eU, + 0xec01edd4U, 0x9527b2adU, 0xe14eafd9U, 0x65eb8e5dU, + 0x8fb936b7U, 0xb78f388fU, 0x04d3d73cU, 0xcd69a4f5U, + 0xa39e3d9bU, 0x2f311e17U, 0xe28e6cdaU, 0x64abcf5cU, + 0xd437e3ecU, 0x273b1c1fU, 0x71fa8b49U, 0x11829329U, + 0x6de18c55U, 0x69e48d51U, 0xb50fba8dU, 0x9d2db0a5U, + 0xee816fd6U, 0xb44ffb8cU, 0x662b4d5eU, 0x92e270aaU, + 0x366f590eU, 0xaf913e97U, 0x2a745e12U, 0x25bb9e1dU, + 0x9c6df1a4U, 0xbf853a87U, 0xa914bd91U, 0xdd7da0e5U, + 0xa45bff9cU, 0x9868f0a0U, 0xb10abb89U, 0xbb803b83U, + 0xf01aeac8U, 0xdffd22e7U, 0x1ccdd124U, 0xfa906ac2U, + 0x4e094776U, 0xefc12ed7U, 0x35af9a0dU, 0x2e715f16U, + 0x6ca1cd54U, 0x099c9531U, 0x9ba833a3U, 0x9062f2a8U, + 0x3a605a02U, 0x4f490677U, 0x0a5c5632U, 0x1a485222U, + 0xfe956bc6U, 0x7df58845U, 0x86f375beU, 0xf15aabc9U, + 0xe804ecd0U, 0x82f674baU, 0x0593963dU, 0x21be9f19U, + 0x4dc98475U, 0x3e655b06U, 0x1f0d1227U, 0xfc15e9c4U, + 0xcfe926f7U, 0x61ee8f59U, 0xc3e625fbU, 0xcaac66f2U, + 0xb840f880U, 0x1b081323U, 0x2db19c15U, 0x6b640f53U, + 0x30eada08U, 0xab943f93U, 0xed41acd5U, 0x5898c060U, + 0x3da59805U, 0x636e0d5bU, 0xa51bbe9dU, 0x20fede18U, + 0x87b334bfU, 0xf7df28cfU, 0x3ce5d904U, 0xf950a9c1U, + 0x3a39038dU, 0x23674494U, 0xc6fa3c71U, 0x9ab12b2dU, + 0x524b19e5U, 0xe6d23451U, 0x957eeb22U, 0xbfdc6308U, + 0x39f9c08eU, 0xbbd9620cU, 0x31f3c286U, 0x6a7d17ddU, + 0xc13ffe76U, 0x8ea02e39U, 0xd12bfa66U, 0x75a6d3c2U, + 0xcd30fd7aU, 0xfc4cb04bU, 0x0b454ebcU, 0xb819a10fU, + 0xc935fc7eU, 0x9bf16a2cU, 0x71a3d2c6U, 0x6e7816d9U, + 0xcbb57e7cU, 0x70e393c7U, 0x2de8c59aU, 0xf909f04eU, + 0x44da9ef3U, 0x7b2952ccU, 0x79a9d0ceU, 0x074a4db0U, + 0x135b48a4U, 0x68fd95dfU, 0x20a78797U, 0xb2932105U, + 0x27624590U, 0xdee43a69U, 0x034f4cb4U, 0x8825ad3fU, + 0xad48e51aU, 0x30b38387U, 0x4d90ddfaU, 0x6cf894dbU, + 0xd6ee3861U, 0x5e441ae9U, 0xd3ab7864U, 0xe85db55fU, + 0xf2c33145U, 0xafc86718U, 0x11dbcaa6U, 0xc7ba7d70U, + 0x465a1cf1U, 0x419fdef6U, 0xc2ff3d75U, 0x37764180U, + 0x633754d4U, 0x1e140aa9U, 0x33734084U, 0x8aa52f3dU, + 0xb416a203U, 0x5f045be8U, 0x9d74e92aU, 0xfb89724cU, + 0x7cec90cbU, 0x7dacd1caU, 0xff8c7348U, 0x92bb2925U, + 0xae882619U, 0xac08a41bU, 0x3dfcc18aU, 0x8be56e3cU, + 0x6f3857d8U, 0x048a8eb3U, 0x917bea26U, 0x05cacfb2U, + 0xfac9334dU, 0x772651c0U, 0x5cc498ebU, 0xc3bf7c74U, + 0xc07fbf77U, 0xcc70bc7bU, 0x673255d0U, 0xabcd661cU, + 0xa402a613U, 0xf043b347U, 0x0a050fbdU, 0x4f105ff8U, + 0x82af2d35U, 0xcef03e79U, 0x5d84d9eaU, 0x4cd09cfbU, + 0xa007a717U, 0x38b9818fU, 0x175e49a0U, 0xb556e302U, + 0x19d1c8aeU, 0xf103f246U, 0x5981d8eeU, 0x189189afU, + 0xec58b45bU, 0x008f8fb7U, 0x26220491U, 0xeb9d765cU, + 0xf506f342U, 0xe91df45eU, 0x903bab27U, 0x8d60ed3aU, + 0x65b2d7d2U, 0xe512f752U, 0x802faf37U, 0x7f2c53c8U, + 0x32330185U, 0x61b7d6d6U, 0x78e991cfU, 0x3cbc808bU, + 0x1f544ba8U, 0x2e280699U, 0xfd0cf14aU, 0x28ad859fU, + 0x50cb9be7U, 0xb959e00eU, 0x69bdd4deU, 0xfecc3249U, + 0xe3977454U, 0x726311c5U, 0x425f1df5U, 0x1b514aacU, + 0xcaf53f7dU, 0x9ff46b28U, 0x4b155efcU, 0x2a2d079dU, + 0x60f797d7U, 0x7e6c12c9U, 0x816fee36U, 0xb7d66100U, + 0xef987758U, 0xbe9c2209U, 0xaa8d271dU, 0x5a411bedU, + 0x86aa2c31U, 0xe452b653U, 0x35f6c382U, 0xe7927550U, + 0xe2d73555U, 0xdba17a6cU, 0x149e8aa3U, 0xf3837044U, + 0x0f404fb8U, 0xb153e206U, 0x09c5ccbeU, 0x34b68283U, + 0xd7ae7960U, 0x2f684798U, 0xa94de41eU, 0xa147e616U, + 0xb6962001U, 0x530b58e4U, 0xa7c26510U, 0xeed83659U, + 0x15decba2U, 0xba99230dU, 0xeadd375dU, 0xd921f86eU, + 0x6b3d56dcU, 0xf849b14fU, 0x4a551ffdU, 0xe057b757U, + 0x627715d5U, 0xc53aff72U, 0xed18f55aU, 0xcfb07f78U, + 0x558edbe2U, 0x2ca8849bU, 0x58c199efU, 0xdc64b86bU, + 0x36360081U, 0x0e000eb9U, 0xbd5ce10aU, 0x74e692c3U, + 0x1a110badU, 0x96be2821U, 0x5b015aecU, 0xdd24f96aU, + 0x6db8d5daU, 0x9eb42a29U, 0xc875bd7fU, 0xa80da51fU, + 0xd46eba63U, 0xd06bbb67U, 0x0c808cbbU, 0x24a28693U, + 0x570e59e0U, 0x0dc0cdbaU, 0xdfa47b68U, 0x2b6d469cU, + 0x8fe06f38U, 0x161e08a1U, 0x93fb6824U, 0x9c34a82bU, + 0x25e2c792U, 0x060a0cb1U, 0x109b8ba7U, 0x64f296d3U, + 0x1dd4c9aaU, 0x21e7c696U, 0x08858dbfU, 0x020f0db5U, + 0x4995dcfeU, 0x667214d1U, 0xa542e712U, 0x431f5cf4U, + 0xf7867140U, 0x564e18e1U, 0x8c20ac3bU, 0x97fe6920U, + 0xd52efb62U, 0xb013a307U, 0x22270595U, 0x29edc49eU, + 0x83ef6c34U, 0xf6c63041U, 0xb3d36004U, 0xa3c76414U, + 0x471a5df0U, 0xc47abe73U, 0x3f7c4388U, 0x48d59dffU, + 0x518bdae6U, 0x3b79428cU, 0xbc1ca00bU, 0x9831a92fU, + 0xf446b243U, 0x87ea6d30U, 0xa6822411U, 0x459adff2U, + 0x766610c1U, 0xd861b96fU, 0x7a6913cdU, 0x732350c4U, + 0x01cfceb6U, 0xa2872515U, 0x943eaa23U, 0xd2eb3965U, + 0x8965ec3eU, 0x121b09a5U, 0x54ce9ae3U, 0xe117f656U, + 0x842aae33U, 0xdae13b6dU, 0x1c9488abU, 0x9971e82eU, + 0x3e3c0289U, 0x4e501ef9U, 0x856aef32U, 0x40df9ff7U, + 0x742f5bd5U, 0x6d711cccU, 0x88ec6429U, 0xd4a77375U, + 0x1c5d41bdU, 0xa8c46c09U, 0xdb68b37aU, 0xf1ca3b50U, + 0x77ef98d6U, 0xf5cf3a54U, 0x7fe59adeU, 0x246b4f85U, + 0x8f29a62eU, 0xc0b67661U, 0x9f3da23eU, 0x3bb08b9aU, + 0x8326a522U, 0xb25ae813U, 0x455316e4U, 0xf60ff957U, + 0x8723a426U, 0xd5e73274U, 0x3fb58a9eU, 0x206e4e81U, + 0x85a32624U, 0x3ef5cb9fU, 0x63fe9dc2U, 0xb71fa816U, + 0x0accc6abU, 0x353f0a94U, 0x37bf8896U, 0x495c15e8U, + 0x5d4d10fcU, 0x26ebcd87U, 0x6eb1dfcfU, 0xfc85795dU, + 0x69741dc8U, 0x90f26231U, 0x4d5914ecU, 0xc633f567U, + 0xe35ebd42U, 0x7ea5dbdfU, 0x038685a2U, 0x22eecc83U, + 0x98f86039U, 0x105242b1U, 0x9dbd203cU, 0xa64bed07U, + 0xbcd5691dU, 0xe1de3f40U, 0x5fcd92feU, 0x89ac2528U, + 0x084c44a9U, 0x0f8986aeU, 0x8ce9652dU, 0x796019d8U, + 0x2d210c8cU, 0x500252f1U, 0x7d6518dcU, 0xc4b37765U, + 0xfa00fa5bU, 0x111203b0U, 0xd362b172U, 0xb59f2a14U, + 0x32fac893U, 0x33ba8992U, 0xb19a2b10U, 0xdcad717dU, + 0xe09e7e41U, 0xe21efc43U, 0x73ea99d2U, 0xc5f33664U, + 0x212e0f80U, 0x4a9cd6ebU, 0xdf6db27eU, 0x4bdc97eaU, + 0xb4df6b15U, 0x39300998U, 0x12d2c0b3U, 0x8da9242cU, + 0x8e69e72fU, 0x8266e423U, 0x29240d88U, 0xe5db3e44U, + 0xea14fe4bU, 0xbe55eb1fU, 0x441357e5U, 0x010607a0U, + 0xccb9756dU, 0x80e66621U, 0x139281b2U, 0x02c6c4a3U, + 0xee11ff4fU, 0x76afd9d7U, 0x594811f8U, 0xfb40bb5aU, + 0x57c790f6U, 0xbf15aa1eU, 0x179780b6U, 0x5687d1f7U, + 0xa24eec03U, 0x4e99d7efU, 0x68345cc9U, 0xa58b2e04U, + 0xbb10ab1aU, 0xa70bac06U, 0xde2df37fU, 0xc376b562U, + 0x2ba48f8aU, 0xab04af0aU, 0xce39f76fU, 0x313a0b90U, + 0x7c2559ddU, 0x2fa18e8eU, 0x36ffc997U, 0x72aad8d3U, + 0x514213f0U, 0x603e5ec1U, 0xb31aa912U, 0x66bbddc7U, + 0x1eddc3bfU, 0xf74fb856U, 0x27ab8c86U, 0xb0da6a11U, + 0xad812c0cU, 0x3c75499dU, 0x0c4945adU, 0x554712f4U, + 0x84e36725U, 0xd1e23370U, 0x050306a4U, 0x643b5fc5U, + 0x2ee1cf8fU, 0x307a4a91U, 0xcf79b66eU, 0xf9c03958U, + 0xa18e2f00U, 0xf08a7a51U, 0xe49b7f45U, 0x145743b5U, + 0xc8bc7469U, 0xaa44ee0bU, 0x7be09bdaU, 0xa9842d08U, + 0xacc16d0dU, 0x95b72234U, 0x5a88d2fbU, 0xbd95281cU, + 0x415617e0U, 0xff45ba5eU, 0x47d394e6U, 0x7aa0dadbU, + 0x99b82138U, 0x617e1fc0U, 0xe75bbc46U, 0xef51be4eU, + 0xf8807859U, 0x1d1d00bcU, 0xe9d43d48U, 0xa0ce6e01U, + 0x5bc893faU, 0xf48f7b55U, 0xa4cb6f05U, 0x9737a036U, + 0x252b0e84U, 0xb65fe917U, 0x044347a5U, 0xae41ef0fU, + 0x2c614d8dU, 0x8b2ca72aU, 0xa30ead02U, 0x81a62720U, + 0x1b9883baU, 0x62bedcc3U, 0x16d7c1b7U, 0x9272e033U, + 0x782058d9U, 0x401656e1U, 0xf34ab952U, 0x3af0ca9bU, + 0x540753f5U, 0xd8a87079U, 0x151702b4U, 0x9332a132U, + 0x23ae8d82U, 0xd0a27271U, 0x8663e527U, 0xe61bfd47U, + 0x9a78e23bU, 0x9e7de33fU, 0x4296d4e3U, 0x6ab4decbU, + 0x191801b8U, 0x43d695e2U, 0x91b22330U, 0x657b1ec4U, + 0xc1f63760U, 0x580850f9U, 0xdded307cU, 0xd222f073U, + 0x6bf49fcaU, 0x481c54e9U, 0x5e8dd3ffU, 0x2ae4ce8bU, + 0x53c291f2U, 0x6ff19eceU, 0x4693d5e7U, 0x4c1955edU, + 0x078384a6U, 0x28644c89U, 0xeb54bf4aU, 0x0d0904acU, + 0xb9902918U, 0x185840b9U, 0xc236f463U, 0xd9e83178U, + 0x9b38a33aU, 0xfe05fb5fU, 0x6c315dcdU, 0x67fb9cc6U, + 0xcdf9346cU, 0xb8d06819U, 0xfdc5385cU, 0xedd13c4cU, + 0x090c05a8U, 0x8a6ce62bU, 0x716a1bd0U, 0x06c3c5a7U, + 0x1f9d82beU, 0x756f1ad4U, 0xf20af853U, 0xd627f177U, + 0xba50ea1bU, 0xc9fc3568U, 0xe8947c49U, 0x0b8c87aaU, + 0x38704899U, 0x9677e137U, 0x347f4b95U, 0x3d35089cU, + 0x4fd996eeU, 0xec917d4dU, 0xda28f27bU, 0x9cfd613dU, + 0xc773b466U, 0x5c0d51fdU, 0x1ad8c2bbU, 0xaf01ae0eU, + 0xca3cf66bU, 0x94f76335U, 0x5282d0f3U, 0xd767b076U, + 0x702a5ad1U, 0x004646a1U, 0xcb7cb76aU, 0x0ec9c7afU, + 0x707a0a84U, 0x69244d9dU, 0x8cb93578U, 0xd0f22224U, + 0x180810ecU, 0xac913d58U, 0xdf3de22bU, 0xf59f6a01U, + 0x73bac987U, 0xf19a6b05U, 0x7bb0cb8fU, 0x203e1ed4U, + 0x8b7cf77fU, 0xc4e32730U, 0x9b68f36fU, 0x3fe5dacbU, + 0x8773f473U, 0xb60fb942U, 0x410647b5U, 0xf25aa806U, + 0x8376f577U, 0xd1b26325U, 0x3be0dbcfU, 0x243b1fd0U, + 0x81f67775U, 0x3aa09aceU, 0x67abcc93U, 0xb34af947U, + 0x0e9997faU, 0x316a5bc5U, 0x33ead9c7U, 0x4d0944b9U, + 0x591841adU, 0x22be9cd6U, 0x6ae48e9eU, 0xf8d0280cU, + 0x6d214c99U, 0x94a73360U, 0x490c45bdU, 0xc266a436U, + 0xe70bec13U, 0x7af08a8eU, 0x07d3d4f3U, 0x26bb9dd2U, + 0x9cad3168U, 0x140713e0U, 0x99e8716dU, 0xa21ebc56U, + 0xb880384cU, 0xe58b6e11U, 0x5b98c3afU, 0x8df97479U, + 0x0c1915f8U, 0x0bdcd7ffU, 0x88bc347cU, 0x7d354889U, + 0x29745dddU, 0x545703a0U, 0x7930498dU, 0xc0e62634U, + 0xfe55ab0aU, 0x154752e1U, 0xd737e023U, 0xb1ca7b45U, + 0x36af99c2U, 0x37efd8c3U, 0xb5cf7a41U, 0xd8f8202cU, + 0xe4cb2f10U, 0xe64bad12U, 0x77bfc883U, 0xc1a66735U, + 0x257b5ed1U, 0x4ec987baU, 0xdb38e32fU, 0x4f89c6bbU, + 0xb08a3a44U, 0x3d6558c9U, 0x168791e2U, 0x89fc757dU, + 0x8a3cb67eU, 0x8633b572U, 0x2d715cd9U, 0xe18e6f15U, + 0xee41af1aU, 0xba00ba4eU, 0x404606b4U, 0x055356f1U, + 0xc8ec243cU, 0x84b33770U, 0x17c7d0e3U, 0x069395f2U, + 0xea44ae1eU, 0x72fa8886U, 0x5d1d40a9U, 0xff15ea0bU, + 0x5392c1a7U, 0xbb40fb4fU, 0x13c2d1e7U, 0x52d280a6U, + 0xa61bbd52U, 0x4acc86beU, 0x6c610d98U, 0xa1de7f55U, + 0xbf45fa4bU, 0xa35efd57U, 0xda78a22eU, 0xc723e433U, + 0x2ff1dedbU, 0xaf51fe5bU, 0xca6ca63eU, 0x356f5ac1U, + 0x7870088cU, 0x2bf4dfdfU, 0x32aa98c6U, 0x76ff8982U, + 0x551742a1U, 0x646b0f90U, 0xb74ff843U, 0x62ee8c96U, + 0x1a8892eeU, 0xf31ae907U, 0x23feddd7U, 0xb48f3b40U, + 0xa9d47d5dU, 0x382018ccU, 0x081c14fcU, 0x511243a5U, + 0x80b63674U, 0xd5b76221U, 0x015657f5U, 0x606e0e94U, + 0x2ab49edeU, 0x342f1bc0U, 0xcb2ce73fU, 0xfd956809U, + 0xa5db7e51U, 0xf4df2b00U, 0xe0ce2e14U, 0x100212e4U, + 0xcce92538U, 0xae11bf5aU, 0x7fb5ca8bU, 0xadd17c59U, + 0xa8943c5cU, 0x91e27365U, 0x5edd83aaU, 0xb9c0794dU, + 0x450346b1U, 0xfb10eb0fU, 0x4386c5b7U, 0x7ef58b8aU, + 0x9ded7069U, 0x652b4e91U, 0xe30eed17U, 0xeb04ef1fU, + 0xfcd52908U, 0x194851edU, 0xed816c19U, 0xa49b3f50U, + 0x5f9dc2abU, 0xf0da2a04U, 0xa09e3e54U, 0x9362f167U, + 0x217e5fd5U, 0xb20ab846U, 0x001616f4U, 0xaa14be5eU, + 0x28341cdcU, 0x8f79f67bU, 0xa75bfc53U, 0x85f37671U, + 0x1fcdd2ebU, 0x66eb8d92U, 0x128290e6U, 0x9627b162U, + 0x7c750988U, 0x444307b0U, 0xf71fe803U, 0x3ea59bcaU, + 0x505202a4U, 0xdcfd2128U, 0x114253e5U, 0x9767f063U, + 0x27fbdcd3U, 0xd4f72320U, 0x8236b476U, 0xe24eac16U, + 0x9e2db36aU, 0x9a28b26eU, 0x46c385b2U, 0x6ee18f9aU, + 0x1d4d50e9U, 0x4783c4b3U, 0x95e77261U, 0x612e4f95U, + 0xc5a36631U, 0x5c5d01a8U, 0xd9b8612dU, 0xd677a122U, + 0x6fa1ce9bU, 0x4c4905b8U, 0x5ad882aeU, 0x2eb19fdaU, + 0x5797c0a3U, 0x6ba4cf9fU, 0x42c684b6U, 0x484c04bcU, + 0x03d6d5f7U, 0x2c311dd8U, 0xef01ee1bU, 0x095c55fdU, + 0xbdc57849U, 0x1c0d11e8U, 0xc663a532U, 0xddbd6029U, + 0x9f6df26bU, 0xfa50aa0eU, 0x68640c9cU, 0x63aecd97U, + 0xc9ac653dU, 0xbc853948U, 0xf990690dU, 0xe9846d1dU, + 0x0d5954f9U, 0x8e39b77aU, 0x753f4a81U, 0x029694f6U, + 0x1bc8d3efU, 0x713a4b85U, 0xf65fa902U, 0xd272a026U, + 0xbe05bb4aU, 0xcda96439U, 0xecc12d18U, 0x0fd9d6fbU, + 0x3c2519c8U, 0x9222b066U, 0x302a1ac4U, 0x396059cdU, + 0x4b8cc7bfU, 0xe8c42c1cU, 0xde7da32aU, 0x98a8306cU, + 0xc326e537U, 0x585800acU, 0x1e8d93eaU, 0xab54ff5fU, + 0xce69a73aU, 0x90a23264U, 0x56d781a2U, 0xd332e127U, + 0x747f0b80U, 0x041317f0U, 0xcf29e63bU, 0x0a9c96feU, + 0x617f1e90U, 0x78215989U, 0x9dbc216cU, 0xc1f73630U, + 0x090d04f8U, 0xbd94294cU, 0xce38f63fU, 0xe49a7e15U, + 0x62bfdd93U, 0xe09f7f11U, 0x6ab5df9bU, 0x313b0ac0U, + 0x9a79e36bU, 0xd5e63324U, 0x8a6de77bU, 0x2ee0cedfU, + 0x9676e067U, 0xa70aad56U, 0x500353a1U, 0xe35fbc12U, + 0x9273e163U, 0xc0b77731U, 0x2ae5cfdbU, 0x353e0bc4U, + 0x90f36361U, 0x2ba58edaU, 0x76aed887U, 0xa24fed53U, + 0x1f9c83eeU, 0x206f4fd1U, 0x22efcdd3U, 0x5c0c50adU, + 0x481d55b9U, 0x33bb88c2U, 0x7be19a8aU, 0xe9d53c18U, + 0x7c24588dU, 0x85a22774U, 0x580951a9U, 0xd363b022U, + 0xf60ef807U, 0x6bf59e9aU, 0x16d6c0e7U, 0x37be89c6U, + 0x8da8257cU, 0x050207f4U, 0x88ed6579U, 0xb31ba842U, + 0xa9852c58U, 0xf48e7a05U, 0x4a9dd7bbU, 0x9cfc606dU, + 0x1d1c01ecU, 0x1ad9c3ebU, 0x99b92068U, 0x6c305c9dU, + 0x387149c9U, 0x455217b4U, 0x68355d99U, 0xd1e33220U, + 0xef50bf1eU, 0x044246f5U, 0xc632f437U, 0xa0cf6f51U, + 0x27aa8dd6U, 0x26eaccd7U, 0xa4ca6e55U, 0xc9fd3438U, + 0xf5ce3b04U, 0xf74eb906U, 0x66badc97U, 0xd0a37321U, + 0x347e4ac5U, 0x5fcc93aeU, 0xca3df73bU, 0x5e8cd2afU, + 0xa18f2e50U, 0x2c604cddU, 0x078285f6U, 0x98f96169U, + 0x9b39a26aU, 0x9736a166U, 0x3c7448cdU, 0xf08b7b01U, + 0xff44bb0eU, 0xab05ae5aU, 0x514312a0U, 0x145642e5U, + 0xd9e93028U, 0x95b62364U, 0x06c2c4f7U, 0x179681e6U, + 0xfb41ba0aU, 0x63ff9c92U, 0x4c1854bdU, 0xee10fe1fU, + 0x4297d5b3U, 0xaa45ef5bU, 0x02c7c5f3U, 0x43d794b2U, + 0xb71ea946U, 0x5bc992aaU, 0x7d64198cU, 0xb0db6b41U, + 0xae40ee5fU, 0xb25be943U, 0xcb7db63aU, 0xd626f027U, + 0x3ef4cacfU, 0xbe54ea4fU, 0xdb69b22aU, 0x246a4ed5U, + 0x69751c98U, 0x3af1cbcbU, 0x23af8cd2U, 0x67fa9d96U, + 0x441256b5U, 0x756e1b84U, 0xa64aec57U, 0x73eb9882U, + 0x0b8d86faU, 0xe21ffd13U, 0x32fbc9c3U, 0xa58a2f54U, + 0xb8d16949U, 0x29250cd8U, 0x191900e8U, 0x401757b1U, + 0x91b32260U, 0xc4b27635U, 0x105343e1U, 0x716b1a80U, + 0x3bb18acaU, 0x252a0fd4U, 0xda29f32bU, 0xec907c1dU, + 0xb4de6a45U, 0xe5da3f14U, 0xf1cb3a00U, 0x010706f0U, + 0xddec312cU, 0xbf14ab4eU, 0x6eb0de9fU, 0xbcd4684dU, + 0xb9912848U, 0x80e76771U, 0x4fd897beU, 0xa8c56d59U, + 0x540652a5U, 0xea15ff1bU, 0x5283d1a3U, 0x6ff09f9eU, + 0x8ce8647dU, 0x742e5a85U, 0xf20bf903U, 0xfa01fb0bU, + 0xedd03d1cU, 0x084d45f9U, 0xfc84780dU, 0xb59e2b44U, + 0x4e98d6bfU, 0xe1df3e10U, 0xb19b2a40U, 0x8267e573U, + 0x307b4bc1U, 0xa30fac52U, 0x111302e0U, 0xbb11aa4aU, + 0x393108c8U, 0x9e7ce26fU, 0xb65ee847U, 0x94f66265U, + 0x0ec8c6ffU, 0x77ee9986U, 0x038784f2U, 0x8722a576U, + 0x6d701d9cU, 0x554613a4U, 0xe61afc17U, 0x2fa08fdeU, + 0x415716b0U, 0xcdf8353cU, 0x004747f1U, 0x8662e477U, + 0x36fec8c7U, 0xc5f23734U, 0x9333a062U, 0xf34bb802U, + 0x8f28a77eU, 0x8b2da67aU, 0x57c691a6U, 0x7fe49b8eU, + 0x0c4844fdU, 0x5686d0a7U, 0x84e26675U, 0x702b5b81U, + 0xd4a67225U, 0x4d5815bcU, 0xc8bd7539U, 0xc772b536U, + 0x7ea4da8fU, 0x5d4c11acU, 0x4bdd96baU, 0x3fb48bceU, + 0x4692d4b7U, 0x7aa1db8bU, 0x53c390a2U, 0x594910a8U, + 0x12d3c1e3U, 0x3d3409ccU, 0xfe04fa0fU, 0x185941e9U, + 0xacc06c5dU, 0x0d0805fcU, 0xd766b126U, 0xccb8743dU, + 0x8e68e67fU, 0xeb55be1aU, 0x79611888U, 0x72abd983U, + 0xd8a97129U, 0xad802d5cU, 0xe8957d19U, 0xf8817909U, + 0x1c5c40edU, 0x9f3ca36eU, 0x643a5e95U, 0x139380e2U, + 0x0acdc7fbU, 0x603f5f91U, 0xe75abd16U, 0xc377b432U, + 0xaf00af5eU, 0xdcac702dU, 0xfdc4390cU, 0x1edcc2efU, + 0x2d200ddcU, 0x8327a472U, 0x212f0ed0U, 0x28654dd9U, + 0x5a89d3abU, 0xf9c13808U, 0xcf78b73eU, 0x89ad2478U, + 0xd223f123U, 0x495d14b8U, 0x0f8887feU, 0xba51eb4bU, + 0xdf6cb32eU, 0x81a72670U, 0x47d295b6U, 0xc237f533U, + 0x657a1f94U, 0x151603e4U, 0xde2cf22fU, 0x1b9982eaU, + 0xad43ee60U, 0xb41da979U, 0x5180d19cU, 0x0dcbc6c0U, + 0xc531f408U, 0x71a8d9bcU, 0x020406cfU, 0x28a68ee5U, + 0xae832d63U, 0x2ca38fe1U, 0xa6892f6bU, 0xfd07fa30U, + 0x5645139bU, 0x19dac3d4U, 0x4651178bU, 0xe2dc3e2fU, + 0x5a4a1097U, 0x6b365da6U, 0x9c3fa351U, 0x2f634ce2U, + 0x5e4f1193U, 0x0c8b87c1U, 0xe6d93f2bU, 0xf902fb34U, + 0x5ccf9391U, 0xe7997e2aU, 0xba922877U, 0x6e731da3U, + 0xd3a0731eU, 0xec53bf21U, 0xeed33d23U, 0x9030a05dU, + 0x8421a549U, 0xff877832U, 0xb7dd6a7aU, 0x25e9cce8U, + 0xb018a87dU, 0x499ed784U, 0x9435a159U, 0x1f5f40d2U, + 0x3a3208f7U, 0xa7c96e6aU, 0xdaea3017U, 0xfb827936U, + 0x4194d58cU, 0xc93ef704U, 0x44d19589U, 0x7f2758b2U, + 0x65b9dca8U, 0x38b28af5U, 0x86a1274bU, 0x50c0909dU, + 0xd120f11cU, 0xd6e5331bU, 0x5585d098U, 0xa00cac6dU, + 0xf44db939U, 0x896ee744U, 0xa409ad69U, 0x1ddfc2d0U, + 0x236c4feeU, 0xc87eb605U, 0x0a0e04c7U, 0x6cf39fa1U, + 0xeb967d26U, 0xead63c27U, 0x68f69ea5U, 0x05c1c4c8U, + 0x39f2cbf4U, 0x3b7249f6U, 0xaa862c67U, 0x1c9f83d1U, + 0xf842ba35U, 0x93f0635eU, 0x060107cbU, 0x92b0225fU, + 0x6db3dea0U, 0xe05cbc2dU, 0xcbbe7506U, 0x54c59199U, + 0x5705529aU, 0x5b0a5196U, 0xf048b83dU, 0x3cb78bf1U, + 0x33784bfeU, 0x67395eaaU, 0x9d7fe250U, 0xd86ab215U, + 0x15d5c0d8U, 0x598ad394U, 0xcafe3407U, 0xdbaa7116U, + 0x377d4afaU, 0xafc36c62U, 0x8024a44dU, 0x222c0eefU, + 0x8eab2543U, 0x66791fabU, 0xcefb3503U, 0x8feb6442U, + 0x7b2259b6U, 0x97f5625aU, 0xb158e97cU, 0x7ce79bb1U, + 0x627c1eafU, 0x7e6719b3U, 0x074146caU, 0x1a1a00d7U, + 0xf2c83a3fU, 0x72681abfU, 0x175542daU, 0xe856be25U, + 0xa549ec68U, 0xf6cd3b3bU, 0xef937c22U, 0xabc66d66U, + 0x882ea645U, 0xb952eb74U, 0x6a761ca7U, 0xbfd76872U, + 0xc7b1760aU, 0x2e230de3U, 0xfec73933U, 0x69b6dfa4U, + 0x74ed99b9U, 0xe519fc28U, 0xd525f018U, 0x8c2ba741U, + 0x5d8fd290U, 0x088e86c5U, 0xdc6fb311U, 0xbd57ea70U, + 0xf78d7a3aU, 0xe916ff24U, 0x161503dbU, 0x20ac8cedU, + 0x78e29ab5U, 0x29e6cfe4U, 0x3df7caf0U, 0xcd3bf600U, + 0x11d0c1dcU, 0x73285bbeU, 0xa28c2e6fU, 0x70e898bdU, + 0x75add8b8U, 0x4cdb9781U, 0x83e4674eU, 0x64f99da9U, + 0x983aa255U, 0x26290febU, 0x9ebf2153U, 0xa3cc6f6eU, + 0x40d4948dU, 0xb812aa75U, 0x3e3709f3U, 0x363d0bfbU, + 0x21eccdecU, 0xc471b509U, 0x30b888fdU, 0x79a2dbb4U, + 0x82a4264fU, 0x2de3cee0U, 0x7da7dab0U, 0x4e5b1583U, + 0xfc47bb31U, 0x6f335ca2U, 0xdd2ff210U, 0x772d5abaU, + 0xf50df838U, 0x5240129fU, 0x7a6218b7U, 0x58ca9295U, + 0xc2f4360fU, 0xbbd26976U, 0xcfbb7402U, 0x4b1e5586U, + 0xa14ced6cU, 0x997ae354U, 0x2a260ce7U, 0xe39c7f2eU, + 0x8d6be640U, 0x01c4c5ccU, 0xcc7bb701U, 0x4a5e1487U, + 0xfac23837U, 0x09cec7c4U, 0x5f0f5092U, 0x3f7748f2U, + 0x4314578eU, 0x4711568aU, 0x9bfa6156U, 0xb3d86b7eU, + 0xc074b40dU, 0x9aba2057U, 0x48de9685U, 0xbc17ab71U, + 0x189a82d5U, 0x8164e54cU, 0x048185c9U, 0x0b4e45c6U, + 0xb2982a7fU, 0x9170e15cU, 0x87e1664aU, 0xf3887b3eU, + 0x8aae2447U, 0xb69d2b7bU, 0x9fff6052U, 0x9575e058U, + 0xdeef3113U, 0xf108f93cU, 0x32380affU, 0xd465b119U, + 0x60fc9cadU, 0xc134f50cU, 0x1b5a41d6U, 0x008484cdU, + 0x4254168fU, 0x27694eeaU, 0xb55de878U, 0xbe972973U, + 0x149581d9U, 0x61bcddacU, 0x24a98de9U, 0x34bd89f9U, + 0xd060b01dU, 0x5300539eU, 0xa806ae65U, 0xdfaf7012U, + 0xc6f1370bU, 0xac03af61U, 0x2b664de6U, 0x0f4b44c2U, + 0x633c5faeU, 0x109080ddU, 0x31f8c9fcU, 0xd2e0321fU, + 0xe11cfd2cU, 0x4f1b5482U, 0xed13fe20U, 0xe459bd29U, + 0x96b5235bU, 0x35fdc8f8U, 0x034447ceU, 0x4591d488U, + 0x1e1f01d3U, 0x8561e448U, 0xc3b4770eU, 0x766d1bbbU, + 0x135043deU, 0x4d9bd680U, 0x8bee6546U, 0x0e0b05c3U, + 0xa946ef64U, 0xd92af314U, 0x121002dfU, 0xd7a5721aU, + 0x467432bcU, 0x5f2a75a5U, 0xbab70d40U, 0xe6fc1a1cU, + 0x2e0628d4U, 0x9a9f0560U, 0xe933da13U, 0xc3915239U, + 0x45b4f1bfU, 0xc794533dU, 0x4dbef3b7U, 0x163026ecU, + 0xbd72cf47U, 0xf2ed1f08U, 0xad66cb57U, 0x09ebe2f3U, + 0xb17dcc4bU, 0x8001817aU, 0x77087f8dU, 0xc454903eU, + 0xb578cd4fU, 0xe7bc5b1dU, 0x0deee3f7U, 0x123527e8U, + 0xb7f84f4dU, 0x0caea2f6U, 0x51a5f4abU, 0x8544c17fU, + 0x3897afc2U, 0x076463fdU, 0x05e4e1ffU, 0x7b077c81U, + 0x6f167995U, 0x14b0a4eeU, 0x5ceab6a6U, 0xcede1034U, + 0x5b2f74a1U, 0xa2a90b58U, 0x7f027d85U, 0xf4689c0eU, + 0xd105d42bU, 0x4cfeb2b6U, 0x31ddeccbU, 0x10b5a5eaU, + 0xaaa30950U, 0x22092bd8U, 0xafe64955U, 0x9410846eU, + 0x8e8e0074U, 0xd3855629U, 0x6d96fb97U, 0xbbf74c41U, + 0x3a172dc0U, 0x3dd2efc7U, 0xbeb20c44U, 0x4b3b70b1U, + 0x1f7a65e5U, 0x62593b98U, 0x4f3e71b5U, 0xf6e81e0cU, + 0xc85b9332U, 0x23496ad9U, 0xe139d81bU, 0x87c4437dU, + 0x00a1a1faU, 0x01e1e0fbU, 0x83c14279U, 0xeef61814U, + 0xd2c51728U, 0xd045952aU, 0x41b1f0bbU, 0xf7a85f0dU, + 0x137566e9U, 0x78c7bf82U, 0xed36db17U, 0x7987fe83U, + 0x8684027cU, 0x0b6b60f1U, 0x2089a9daU, 0xbff24d45U, + 0xbc328e46U, 0xb03d8d4aU, 0x1b7f64e1U, 0xd780572dU, + 0xd84f9722U, 0x8c0e8276U, 0x76483e8cU, 0x335d6ec9U, + 0xfee21c04U, 0xb2bd0f48U, 0x21c9e8dbU, 0x309dadcaU, + 0xdc4a9626U, 0x44f4b0beU, 0x6b137891U, 0xc91bd233U, + 0x659cf99fU, 0x8d4ec377U, 0x25cce9dfU, 0x64dcb89eU, + 0x9015856aU, 0x7cc2be86U, 0x5a6f35a0U, 0x97d0476dU, + 0x894bc273U, 0x9550c56fU, 0xec769a16U, 0xf12ddc0bU, + 0x19ffe6e3U, 0x995fc663U, 0xfc629e06U, 0x036162f9U, + 0x4e7e30b4U, 0x1dfae7e7U, 0x04a4a0feU, 0x40f1b1baU, + 0x63197a99U, 0x526537a8U, 0x8141c07bU, 0x54e0b4aeU, + 0x2c86aad6U, 0xc514d13fU, 0x15f0e5efU, 0x82810378U, + 0x9fda4565U, 0x0e2e20f4U, 0x3e122cc4U, 0x671c7b9dU, + 0xb6b80e4cU, 0xe3b95a19U, 0x37586fcdU, 0x566036acU, + 0x1cbaa6e6U, 0x022123f8U, 0xfd22df07U, 0xcb9b5031U, + 0x93d54669U, 0xc2d11338U, 0xd6c0162cU, 0x260c2adcU, + 0xfae71d00U, 0x981f8762U, 0x49bbf2b3U, 0x9bdf4461U, + 0x9e9a0464U, 0xa7ec4b5dU, 0x68d3bb92U, 0x8fce4175U, + 0x730d7e89U, 0xcd1ed337U, 0x7588fd8fU, 0x48fbb3b2U, + 0xabe34851U, 0x532576a9U, 0xd500d52fU, 0xdd0ad727U, + 0xcadb1130U, 0x2f4669d5U, 0xdb8f5421U, 0x92950768U, + 0x6993fa93U, 0xc6d4123cU, 0x9690066cU, 0xa56cc95fU, + 0x177067edU, 0x8404807eU, 0x36182eccU, 0x9c1a8666U, + 0x1e3a24e4U, 0xb977ce43U, 0x9155c46bU, 0xb3fd4e49U, + 0x29c3ead3U, 0x50e5b5aaU, 0x248ca8deU, 0xa029895aU, + 0x4a7b31b0U, 0x724d3f88U, 0xc111d03bU, 0x08aba3f2U, + 0x665c3a9cU, 0xeaf31910U, 0x274c6bddU, 0xa169c85bU, + 0x11f5e4ebU, 0xe2f91b18U, 0xb4388c4eU, 0xd440942eU, + 0xa8238b52U, 0xac268a56U, 0x70cdbd8aU, 0x58efb7a2U, + 0x2b4368d1U, 0x718dfc8bU, 0xa3e94a59U, 0x572077adU, + 0xf3ad5e09U, 0x6a533990U, 0xefb65915U, 0xe079991aU, + 0x59aff6a3U, 0x7a473d80U, 0x6cd6ba96U, 0x18bfa7e2U, + 0x6199f89bU, 0x5daaf7a7U, 0x74c8bc8eU, 0x7e423c84U, + 0x35d8edcfU, 0x1a3f25e0U, 0xd90fd623U, 0x3f526dc5U, + 0x8bcb4071U, 0x2a0329d0U, 0xf06d9d0aU, 0xebb35811U, + 0xa963ca53U, 0xcc5e9236U, 0x5e6a34a4U, 0x55a0f5afU, + 0xffa25d05U, 0x8a8b0170U, 0xcf9e5135U, 0xdf8a5525U, + 0x3b576cc1U, 0xb8378f42U, 0x433172b9U, 0x3498acceU, + 0x2dc6ebd7U, 0x473473bdU, 0xc051913aU, 0xe47c981eU, + 0x880b8372U, 0xfba75c01U, 0xdacf1520U, 0x39d7eec3U, + 0x0a2b21f0U, 0xa42c885eU, 0x062422fcU, 0x0f6e61f5U, + 0x7d82ff87U, 0xdeca1424U, 0xe8739b12U, 0xaea60854U, + 0xf528dd0fU, 0x6e563894U, 0x2883abd2U, 0x9d5ac767U, + 0xf8679f02U, 0xa6ac0a5cU, 0x60d9b99aU, 0xe53cd91fU, + 0x427133b8U, 0x321d2fc8U, 0xf927de03U, 0x3c92aec6U, + 0xbeee50deU, 0xa7b017c7U, 0x422d6f22U, 0x1e66787eU, + 0xd69c4ab6U, 0x62056702U, 0x11a9b871U, 0x3b0b305bU, + 0xbd2e93ddU, 0x3f0e315fU, 0xb52491d5U, 0xeeaa448eU, + 0x45e8ad25U, 0x0a777d6aU, 0x55fca935U, 0xf1718091U, + 0x49e7ae29U, 0x789be318U, 0x8f921defU, 0x3ccef25cU, + 0x4de2af2dU, 0x1f26397fU, 0xf5748195U, 0xeaaf458aU, + 0x4f622d2fU, 0xf434c094U, 0xa93f96c9U, 0x7ddea31dU, + 0xc00dcda0U, 0xfffe019fU, 0xfd7e839dU, 0x839d1ee3U, + 0x978c1bf7U, 0xec2ac68cU, 0xa470d4c4U, 0x36447256U, + 0xa3b516c3U, 0x5a33693aU, 0x87981fe7U, 0x0cf2fe6cU, + 0x299fb649U, 0xb464d0d4U, 0xc9478ea9U, 0xe82fc788U, + 0x52396b32U, 0xda9349baU, 0x577c2b37U, 0x6c8ae60cU, + 0x76146216U, 0x2b1f344bU, 0x950c99f5U, 0x436d2e23U, + 0xc28d4fa2U, 0xc5488da5U, 0x46286e26U, 0xb3a112d3U, + 0xe7e00787U, 0x9ac359faU, 0xb7a413d7U, 0x0e727c6eU, + 0x30c1f150U, 0xdbd308bbU, 0x19a3ba79U, 0x7f5e211fU, + 0xf83bc398U, 0xf97b8299U, 0x7b5b201bU, 0x166c7a76U, + 0x2a5f754aU, 0x28dff748U, 0xb92b92d9U, 0x0f323d6fU, + 0xebef048bU, 0x805ddde0U, 0x15acb975U, 0x811d9ce1U, + 0x7e1e601eU, 0xf3f10293U, 0xd813cbb8U, 0x47682f27U, + 0x44a8ec24U, 0x48a7ef28U, 0xe3e50683U, 0x2f1a354fU, + 0x20d5f540U, 0x7494e014U, 0x8ed25ceeU, 0xcbc70cabU, + 0x06787e66U, 0x4a276d2aU, 0xd9538ab9U, 0xc807cfa8U, + 0x24d0f444U, 0xbc6ed2dcU, 0x93891af3U, 0x3181b051U, + 0x9d069bfdU, 0x75d4a115U, 0xdd568bbdU, 0x9c46dafcU, + 0x688fe708U, 0x8458dce4U, 0xa2f557c2U, 0x6f4a250fU, + 0x71d1a011U, 0x6dcaa70dU, 0x14ecf874U, 0x09b7be69U, + 0xe1658481U, 0x61c5a401U, 0x04f8fc64U, 0xfbfb009bU, + 0xb6e452d6U, 0xe5608585U, 0xfc3ec29cU, 0xb86bd3d8U, + 0x9b8318fbU, 0xaaff55caU, 0x79dba219U, 0xac7ad6ccU, + 0xd41cc8b4U, 0x3d8eb35dU, 0xed6a878dU, 0x7a1b611aU, + 0x67402707U, 0xf6b44296U, 0xc6884ea6U, 0x9f8619ffU, + 0x4e226c2eU, 0x1b23387bU, 0xcfc20dafU, 0xaefa54ceU, + 0xe420c484U, 0xfabb419aU, 0x05b8bd65U, 0x33013253U, + 0x6b4f240bU, 0x3a4b715aU, 0x2e5a744eU, 0xde9648beU, + 0x027d7f62U, 0x6085e500U, 0xb12190d1U, 0x63452603U, + 0x66006606U, 0x5f76293fU, 0x9049d9f0U, 0x77542317U, + 0x8b971cebU, 0x3584b155U, 0x8d129fedU, 0xb061d1d0U, + 0x53792a33U, 0xabbf14cbU, 0x2d9ab74dU, 0x2590b545U, + 0x32417352U, 0xd7dc0bb7U, 0x23153643U, 0x6a0f650aU, + 0x910998f1U, 0x3e4e705eU, 0x6e0a640eU, 0x5df6ab3dU, + 0xefea058fU, 0x7c9ee21cU, 0xce824caeU, 0x6480e404U, + 0xe6a04686U, 0x41edac21U, 0x69cfa609U, 0x4b672c2bU, + 0xd15988b1U, 0xa87fd7c8U, 0xdc16cabcU, 0x58b3eb38U, + 0xb2e153d2U, 0x8ad75deaU, 0x398bb259U, 0xf031c190U, + 0x9ec658feU, 0x12697b72U, 0xdfd609bfU, 0x59f3aa39U, + 0xe96f8689U, 0x1a63797aU, 0x4ca2ee2cU, 0x2cdaf64cU, + 0x50b9e930U, 0x54bce834U, 0x8857dfe8U, 0xa075d5c0U, + 0xd3d90ab3U, 0x89179ee9U, 0x5b73283bU, 0xafba15cfU, + 0x0b373c6bU, 0x92c95bf2U, 0x172c3b77U, 0x18e3fb78U, + 0xa13594c1U, 0x82dd5fe2U, 0x944cd8f4U, 0xe025c580U, + 0x99039af9U, 0xa53095c5U, 0x8c52deecU, 0x86d85ee6U, + 0xcd428fadU, 0xe2a54782U, 0x2195b441U, 0xc7c80fa7U, + 0x73512213U, 0xd2994bb2U, 0x08f7ff68U, 0x13293a73U, + 0x51f9a831U, 0x34c4f054U, 0xa6f056c6U, 0xad3a97cdU, + 0x07383f67U, 0x72116312U, 0x37043357U, 0x27103747U, + 0xc3cd0ea3U, 0x40aded20U, 0xbbab10dbU, 0xcc02ceacU, + 0xd55c89b5U, 0xbfae11dfU, 0x38cbf358U, 0x1ce6fa7cU, + 0x7091e110U, 0x033d3e63U, 0x22557742U, 0xc14d8ca1U, + 0xf2b14392U, 0x5cb6ea3cU, 0xfebe409eU, 0xf7f40397U, + 0x85189de5U, 0x26507646U, 0x10e9f970U, 0x563c6a36U, + 0x0db2bf6dU, 0x96cc5af6U, 0xd019c9b0U, 0x65c0a505U, + 0x00fdfd60U, 0x5e36683eU, 0x9843dbf8U, 0x1da6bb7dU, + 0xbaeb51daU, 0xca874daaU, 0x01bdbc61U, 0xc408cca4U, + 0x1a9b810fU, 0x03c5c616U, 0xe658bef3U, 0xba13a9afU, + 0x72e99b67U, 0xc670b6d3U, 0xb5dc69a0U, 0x9f7ee18aU, + 0x195b420cU, 0x9b7be08eU, 0x11514004U, 0x4adf955fU, + 0xe19d7cf4U, 0xae02acbbU, 0xf18978e4U, 0x55045140U, + 0xed927ff8U, 0xdcee32c9U, 0x2be7cc3eU, 0x98bb238dU, + 0xe9977efcU, 0xbb53e8aeU, 0x51015044U, 0x4eda945bU, + 0xeb17fcfeU, 0x50411145U, 0x0d4a4718U, 0xd9ab72ccU, + 0x64781c71U, 0x5b8bd04eU, 0x590b524cU, 0x27e8cf32U, + 0x33f9ca26U, 0x485f175dU, 0x00050515U, 0x9231a387U, + 0x07c0c712U, 0xfe46b8ebU, 0x23edce36U, 0xa8872fbdU, + 0x8dea6798U, 0x10110105U, 0x6d325f78U, 0x4c5a1659U, + 0xf64cbae3U, 0x7ee6986bU, 0xf309fae6U, 0xc8ff37ddU, + 0xd261b3c7U, 0x8f6ae59aU, 0x31794824U, 0xe718fff2U, + 0x66f89e73U, 0x613d5c74U, 0xe25dbff7U, 0x17d4c302U, + 0x4395d656U, 0x3eb6882bU, 0x13d1c206U, 0xaa07adbfU, + 0x94b42081U, 0x7fa6d96aU, 0xbdd66ba8U, 0xdb2bf0ceU, + 0x5c4e1249U, 0x5d0e5348U, 0xdf2ef1caU, 0xb219aba7U, + 0x8e2aa49bU, 0x8caa2699U, 0x1d5e4308U, 0xab47ecbeU, + 0x4f9ad55aU, 0x24280c31U, 0xb1d968a4U, 0x25684d30U, + 0xda6bb1cfU, 0x5784d342U, 0x7c661a69U, 0xe31dfef6U, + 0xe0dd3df5U, 0xecd23ef9U, 0x4790d752U, 0x8b6fe49eU, + 0x84a02491U, 0xd0e131c5U, 0x2aa78d3fU, 0x6fb2dd7aU, + 0xa20dafb7U, 0xee52bcfbU, 0x7d265b68U, 0x6c721e79U, + 0x80a52595U, 0x181b030dU, 0x37fccb22U, 0x95f46180U, + 0x39734a2cU, 0xd1a170c4U, 0x79235a6cU, 0x38330b2dU, + 0xccfa36d9U, 0x202d0d35U, 0x06808613U, 0xcb3ff4deU, + 0xd5a471c0U, 0xc9bf76dcU, 0xb09929a5U, 0xadc26fb8U, + 0x45105550U, 0xc5b075d0U, 0xa08d2db5U, 0x5f8ed14aU, + 0x12918307U, 0x41155454U, 0x584b134dU, 0x1c1e0209U, + 0x3ff6c92aU, 0x0e8a841bU, 0xddae73c8U, 0x080f071dU, + 0x70691965U, 0x99fb628cU, 0x491f565cU, 0xde6eb0cbU, + 0xc335f6d6U, 0x52c19347U, 0x62fd9f77U, 0x3bf3c82eU, + 0xea57bdffU, 0xbf56e9aaU, 0x6bb7dc7eU, 0x0a8f851fU, + 0x40551555U, 0x5ece904bU, 0xa1cd6cb4U, 0x9774e382U, + 0xcf3af5daU, 0x9e3ea08bU, 0x8a2fa59fU, 0x7ae3996fU, + 0xa608aeb3U, 0xc4f034d1U, 0x15544100U, 0xc730f7d2U, + 0xc275b7d7U, 0xfb03f8eeU, 0x343c0821U, 0xd321f2c6U, + 0x2fe2cd3aU, 0x91f16084U, 0x29674e3cU, 0x14140001U, + 0xf70cfbe2U, 0x0fcac51aU, 0x89ef669cU, 0x81e56494U, + 0x9634a283U, 0x73a9da66U, 0x8760e792U, 0xce7ab4dbU, + 0x357c4920U, 0x9a3ba18fU, 0xca7fb5dfU, 0xf9837aecU, + 0x4b9fd45eU, 0xd8eb33cdU, 0x6af79d7fU, 0xc0f535d5U, + 0x42d59757U, 0xe5987df0U, 0xcdba77d8U, 0xef12fdfaU, + 0x752c5960U, 0x0c0a0619U, 0x78631b6dU, 0xfcc63ae9U, + 0x16948203U, 0x2ea28c3bU, 0x9dfe6388U, 0x54441041U, + 0x3ab3892fU, 0xb61caaa3U, 0x7ba3d86eU, 0xfd867be8U, + 0x4d1a5758U, 0xbe16a8abU, 0xe8d73ffdU, 0x88af279dU, + 0xf4cc38e1U, 0xf0c939e5U, 0x2c220e39U, 0x04000411U, + 0x77acdb62U, 0x2d624f38U, 0xff06f9eaU, 0x0bcfc41eU, + 0xaf42edbaU, 0x36bc8a23U, 0xb359eaa6U, 0xbc962aa9U, + 0x05404510U, 0x26a88e33U, 0x30390925U, 0x44501451U, + 0x3d764b28U, 0x01454414U, 0x28270f3dU, 0x22ad8f37U, + 0x69375e7cU, 0x46d09653U, 0x85e06590U, 0x63bdde76U, + 0xd724f3c2U, 0x76ec9a63U, 0xac822eb9U, 0xb75ceba2U, + 0xf58c79e0U, 0x90b12185U, 0x02858717U, 0x094f461cU, + 0xa34deeb6U, 0xd664b2c3U, 0x9371e286U, 0x8365e696U, + 0x67b8df72U, 0xe4d83cf1U, 0x1fdec10aU, 0x68771f7dU, + 0x71295864U, 0x1bdbc00eU, 0x9cbe2289U, 0xb8932badU, + 0xd4e430c1U, 0xa748efb2U, 0x8620a693U, 0x65385d70U, + 0x56c49243U, 0xf8c33bedU, 0x5acb914fU, 0x5381d246U, + 0x216d4c34U, 0x8225a797U, 0xb49c28a1U, 0xf249bbe7U, + 0xa9c76ebcU, 0x32b98b27U, 0x746c1861U, 0xc1b574d4U, + 0xa4882cb1U, 0xfa43b9efU, 0x3c360a29U, 0xb9d36aacU, + 0x1e9e800bU, 0x6ef29c7bU, 0xa5c86db0U, 0x607d1d75U, + 0x7e2d53ddU, 0x677314c4U, 0x82ee6c21U, 0xdea57b7dU, + 0x165f49b5U, 0xa2c66401U, 0xd16abb72U, 0xfbc83358U, + 0x7ded90deU, 0xffcd325cU, 0x75e792d6U, 0x2e69478dU, + 0x852bae26U, 0xcab47e69U, 0x953faa36U, 0x31b28392U, + 0x8924ad2aU, 0xb858e01bU, 0x4f511eecU, 0xfc0df15fU, + 0x8d21ac2eU, 0xdfe53a7cU, 0x35b78296U, 0x2a6c4689U, + 0x8fa12e2cU, 0x34f7c397U, 0x69fc95caU, 0xbd1da01eU, + 0x00cecea3U, 0x3f3d029cU, 0x3dbd809eU, 0x435e1de0U, + 0x574f18f4U, 0x2ce9c58fU, 0x64b3d7c7U, 0xf6877155U, + 0x637615c0U, 0x9af06a39U, 0x475b1ce4U, 0xcc31fd6fU, + 0xe95cb54aU, 0x74a7d3d7U, 0x09848daaU, 0x28ecc48bU, + 0x92fa6831U, 0x1a504ab9U, 0x97bf2834U, 0xac49e50fU, + 0xb6d76115U, 0xebdc3748U, 0x55cf9af6U, 0x83ae2d20U, + 0x024e4ca1U, 0x058b8ea6U, 0x86eb6d25U, 0x736211d0U, + 0x27230484U, 0x5a005af9U, 0x776710d4U, 0xceb17f6dU, + 0xf002f253U, 0x1b100bb8U, 0xd960b97aU, 0xbf9d221cU, + 0x38f8c09bU, 0x39b8819aU, 0xbb982318U, 0xd6af7975U, + 0xea9c7649U, 0xe81cf44bU, 0x79e891daU, 0xcff13e6cU, + 0x2b2c0788U, 0x409edee3U, 0xd56fba76U, 0x41de9fe2U, + 0xbedd631dU, 0x33320190U, 0x18d0c8bbU, 0x87ab2c24U, + 0x846bef27U, 0x8864ec2bU, 0x23260580U, 0xefd9364cU, + 0xe016f643U, 0xb457e317U, 0x4e115fedU, 0x0b040fa8U, + 0xc6bb7d65U, 0x8ae46e29U, 0x199089baU, 0x08c4ccabU, + 0xe413f747U, 0x7cadd1dfU, 0x534a19f0U, 0xf142b352U, + 0x5dc598feU, 0xb517a216U, 0x1d9588beU, 0x5c85d9ffU, + 0xa84ce40bU, 0x449bdfe7U, 0x623654c1U, 0xaf89260cU, + 0xb112a312U, 0xad09a40eU, 0xd42ffb77U, 0xc974bd6aU, + 0x21a68782U, 0xa106a702U, 0xc43bff67U, 0x3b380398U, + 0x762751d5U, 0x25a38686U, 0x3cfdc19fU, 0x78a8d0dbU, + 0x5b401bf8U, 0x6a3c56c9U, 0xb918a11aU, 0x6cb9d5cfU, + 0x14dfcbb7U, 0xfd4db05eU, 0x2da9848eU, 0xbad86219U, + 0xa7832404U, 0x36774195U, 0x064b4da5U, 0x5f451afcU, + 0x8ee16f2dU, 0xdbe03b78U, 0x0f010eacU, 0x6e3957cdU, + 0x24e3c787U, 0x3a784299U, 0xc57bbe66U, 0xf3c23150U, + 0xab8c2708U, 0xfa887259U, 0xee99774dU, 0x1e554bbdU, + 0xc2be7c61U, 0xa046e603U, 0x71e293d2U, 0xa3862500U, + 0xa6c36505U, 0x9fb52a3cU, 0x508adaf3U, 0xb7972014U, + 0x4b541fe8U, 0xf547b256U, 0x4dd19ceeU, 0x70a2d2d3U, + 0x93ba2930U, 0x6b7c17c8U, 0xed59b44eU, 0xe553b646U, + 0xf2827051U, 0x171f08b4U, 0xe3d63540U, 0xaacc6609U, + 0x51ca9bf2U, 0xfe8d735dU, 0xaec9670dU, 0x9d35a83eU, + 0x2f29068cU, 0xbc5de11fU, 0x0e414fadU, 0xa443e707U, + 0x26634585U, 0x812eaf22U, 0xa90ca50aU, 0x8ba42f28U, + 0x119a8bb2U, 0x68bcd4cbU, 0x1cd5c9bfU, 0x9870e83bU, + 0x722250d1U, 0x4a145ee9U, 0xf948b15aU, 0x30f2c293U, + 0x5e055bfdU, 0xd2aa7871U, 0x1f150abcU, 0x9930a93aU, + 0x29ac858aU, 0xdaa07a79U, 0x8c61ed2fU, 0xec19f54fU, + 0x907aea33U, 0x947feb37U, 0x4894dcebU, 0x60b6d6c3U, + 0x131a09b0U, 0x49d49deaU, 0x9bb02b38U, 0x6f7916ccU, + 0xcbf43f68U, 0x520a58f1U, 0xd7ef3874U, 0xd820f87bU, + 0x61f697c2U, 0x421e5ce1U, 0x548fdbf7U, 0x20e6c683U, + 0x59c099faU, 0x65f396c6U, 0x4c91ddefU, 0x461b5de5U, + 0x0d818caeU, 0x22664481U, 0xe156b742U, 0x070b0ca4U, + 0xb3922110U, 0x125a48b1U, 0xc834fc6bU, 0xd3ea3970U, + 0x913aab32U, 0xf407f357U, 0x663355c5U, 0x6df994ceU, + 0xc7fb3c64U, 0xb2d26011U, 0xf7c73054U, 0xe7d33444U, + 0x030e0da0U, 0x806eee23U, 0x7b6813d8U, 0x0cc1cdafU, + 0x159f8ab6U, 0x7f6d12dcU, 0xf808f05bU, 0xdc25f97fU, + 0xb052e213U, 0xc3fe3d60U, 0xe2967441U, 0x018e8fa2U, + 0x32724091U, 0x9c75e93fU, 0x3e7d439dU, 0x37370094U, + 0x45db9ee6U, 0xe6937545U, 0xd02afa73U, 0x96ff6935U, + 0xcd71bc6eU, 0x560f59f5U, 0x10dacab3U, 0xa503a606U, + 0xc03efe63U, 0x9ef56b3dU, 0x5880d8fbU, 0xdd65b87eU, + 0x7a2852d9U, 0x0a444ea9U, 0xc17ebf62U, 0x04cbcfa7U, + 0x3b6d56d8U, 0x223311c1U, 0xc7ae6924U, 0x9be57e78U, + 0x531f4cb0U, 0xe7866104U, 0x942abe77U, 0xbe88365dU, + 0x38ad95dbU, 0xba8d3759U, 0x30a797d3U, 0x6b294288U, + 0xc06bab23U, 0x8ff47b6cU, 0xd07faf33U, 0x74f28697U, + 0xcc64a82fU, 0xfd18e51eU, 0x0a111be9U, 0xb94df45aU, + 0xc861a92bU, 0x9aa53f79U, 0x70f78793U, 0x6f2c438cU, + 0xcae12b29U, 0x71b7c692U, 0x2cbc90cfU, 0xf85da51bU, + 0x458ecba6U, 0x7a7d0799U, 0x78fd859bU, 0x061e18e5U, + 0x120f1df1U, 0x69a9c08aU, 0x21f3d2c2U, 0xb3c77450U, + 0x263610c5U, 0xdfb06f3cU, 0x021b19e1U, 0x8971f86aU, + 0xac1cb04fU, 0x31e7d6d2U, 0x4cc488afU, 0x6dacc18eU, + 0xd7ba6d34U, 0x5f104fbcU, 0xd2ff2d31U, 0xe909e00aU, + 0xf3976410U, 0xae9c324dU, 0x108f9ff3U, 0xc6ee2825U, + 0x470e49a4U, 0x40cb8ba3U, 0xc3ab6820U, 0x362214d5U, + 0x62630181U, 0x1f405ffcU, 0x322715d1U, 0x8bf17a68U, + 0xb542f756U, 0x5e500ebdU, 0x9c20bc7fU, 0xfadd2719U, + 0x7db8c59eU, 0x7cf8849fU, 0xfed8261dU, 0x93ef7c70U, + 0xafdc734cU, 0xad5cf14eU, 0x3ca894dfU, 0x8ab13b69U, + 0x6e6c028dU, 0x05dedbe6U, 0x902fbf73U, 0x049e9ae7U, + 0xfb9d6618U, 0x76720495U, 0x5d90cdbeU, 0xc2eb2921U, + 0xc12bea22U, 0xcd24e92eU, 0x66660085U, 0xaa993349U, + 0xa556f346U, 0xf117e612U, 0x0b515ae8U, 0x4e440aadU, + 0x83fb7860U, 0xcfa46b2cU, 0x5cd08cbfU, 0x4d84c9aeU, + 0xa153f242U, 0x39edd4daU, 0x160a1cf5U, 0xb402b657U, + 0x18859dfbU, 0xf057a713U, 0x58d58dbbU, 0x19c5dcfaU, + 0xed0ce10eU, 0x01dbdae2U, 0x277651c4U, 0xeac92309U, + 0xf452a617U, 0xe849a10bU, 0x916ffe72U, 0x8c34b86fU, + 0x64e68287U, 0xe446a207U, 0x817bfa62U, 0x7e78069dU, + 0x336754d0U, 0x60e38383U, 0x79bdc49aU, 0x3de8d5deU, + 0x1e001efdU, 0x2f7c53ccU, 0xfc58a41fU, 0x29f9d0caU, + 0x519fceb2U, 0xb80db55bU, 0x68e9818bU, 0xff98671cU, + 0xe2c32101U, 0x73374490U, 0x430b48a0U, 0x1a051ff9U, + 0xcba16a28U, 0x9ea03e7dU, 0x4a410ba9U, 0x2b7952c8U, + 0x61a3c282U, 0x7f38479cU, 0x803bbb63U, 0xb6823455U, + 0xeecc220dU, 0xbfc8775cU, 0xabd97248U, 0x5b154eb8U, + 0x87fe7964U, 0xe506e306U, 0x34a296d7U, 0xe6c62005U, + 0xe3836000U, 0xdaf52f39U, 0x15cadff6U, 0xf2d72511U, + 0x0e141aedU, 0xb007b753U, 0x089199ebU, 0x35e2d7d6U, + 0xd6fa2c35U, 0x2e3c12cdU, 0xa819b14bU, 0xa013b343U, + 0xb7c27554U, 0x525f0db1U, 0xa6963045U, 0xef8c630cU, + 0x148a9ef7U, 0xbbcd7658U, 0xeb896208U, 0xd875ad3bU, + 0x6a690389U, 0xf91de41aU, 0x4b014aa8U, 0xe103e202U, + 0x63234080U, 0xc46eaa27U, 0xec4ca00fU, 0xcee42a2dU, + 0x54da8eb7U, 0x2dfcd1ceU, 0x5995ccbaU, 0xdd30ed3eU, + 0x376255d4U, 0x0f545becU, 0xbc08b45fU, 0x75b2c796U, + 0x1b455ef8U, 0x97ea7d74U, 0x5a550fb9U, 0xdc70ac3fU, + 0x6cec808fU, 0x9fe07f7cU, 0xc921e82aU, 0xa959f04aU, + 0xd53aef36U, 0xd13fee32U, 0x0dd4d9eeU, 0x25f6d3c6U, + 0x565a0cb5U, 0x0c9498efU, 0xdef02e3dU, 0x2a3913c9U, + 0x8eb43a6dU, 0x174a5df4U, 0x92af3d71U, 0x9d60fd7eU, + 0x24b692c7U, 0x075e59e4U, 0x11cfdef2U, 0x65a6c386U, + 0x1c809cffU, 0x20b393c3U, 0x09d1d8eaU, 0x035b58e0U, + 0x48c189abU, 0x67264184U, 0xa416b247U, 0x424b09a1U, + 0xf6d22415U, 0x571a4db4U, 0x8d74f96eU, 0x96aa3c75U, + 0xd47aae37U, 0xb147f652U, 0x237350c0U, 0x28b991cbU, + 0x82bb3961U, 0xf7926514U, 0xb2873551U, 0xa2933141U, + 0x464e08a5U, 0xc52eeb26U, 0x3e2816ddU, 0x4981c8aaU, + 0x50df8fb3U, 0x3a2d17d9U, 0xbd48f55eU, 0x9965fc7aU, + 0xf512e716U, 0x86be3865U, 0xa7d67144U, 0x44ce8aa7U, + 0x77324594U, 0xd935ec3aU, 0x7b3d4698U, 0x72770591U, + 0x009b9be3U, 0xa3d37040U, 0x956aff76U, 0xd3bf6c30U, + 0x8831b96bU, 0x134f5cf0U, 0x559acfb6U, 0xe043a303U, + 0x857efb66U, 0xdbb56e38U, 0x1dc0ddfeU, 0x9825bd7bU, + 0x3f6857dcU, 0x4f044bacU, 0x843eba67U, 0x418bcaa2U, + 0x4d226fe1U, 0x547c28f8U, 0xb1e1501dU, 0xedaa4741U, + 0x25507589U, 0x91c9583dU, 0xe265874eU, 0xc8c70f64U, + 0x4ee2ace2U, 0xccc20e60U, 0x46e8aeeaU, 0x1d667bb1U, + 0xb624921aU, 0xf9bb4255U, 0xa630960aU, 0x02bdbfaeU, + 0xba2b9116U, 0x8b57dc27U, 0x7c5e22d0U, 0xcf02cd63U, + 0xbe2e9012U, 0xecea0640U, 0x06b8beaaU, 0x19637ab5U, + 0xbcae1210U, 0x07f8ffabU, 0x5af3a9f6U, 0x8e129c22U, + 0x33c1f29fU, 0x0c323ea0U, 0x0eb2bca2U, 0x705121dcU, + 0x644024c8U, 0x1fe6f9b3U, 0x57bcebfbU, 0xc5884d69U, + 0x507929fcU, 0xa9ff5605U, 0x745420d8U, 0xff3ec153U, + 0xda538976U, 0x47a8efebU, 0x3a8bb196U, 0x1be3f8b7U, + 0xa1f5540dU, 0x295f7685U, 0xa4b01408U, 0x9f46d933U, + 0x85d85d29U, 0xd8d30b74U, 0x66c0a6caU, 0xb0a1111cU, + 0x3141709dU, 0x3684b29aU, 0xb5e45119U, 0x406d2decU, + 0x142c38b8U, 0x690f66c5U, 0x44682ce8U, 0xfdbe4351U, + 0xc30dce6fU, 0x281f3784U, 0xea6f8546U, 0x8c921e20U, + 0x0bf7fca7U, 0x0ab7bda6U, 0x88971f24U, 0xe5a04549U, + 0xd9934a75U, 0xdb13c877U, 0x4ae7ade6U, 0xfcfe0250U, + 0x18233bb4U, 0x7391e2dfU, 0xe660864aU, 0x72d1a3deU, + 0x8dd25f21U, 0x003d3dacU, 0x2bdff487U, 0xb4a41018U, + 0xb764d31bU, 0xbb6bd017U, 0x102939bcU, 0xdcd60a70U, + 0xd319ca7fU, 0x8758df2bU, 0x7d1e63d1U, 0x380b3394U, + 0xf5b44159U, 0xb9eb5215U, 0x2a9fb586U, 0x3bcbf097U, + 0xd71ccb7bU, 0x4fa2ede3U, 0x604525ccU, 0xc24d8f6eU, + 0x6ecaa4c2U, 0x86189e2aU, 0x2e9ab482U, 0x6f8ae5c3U, + 0x9b43d837U, 0x7794e3dbU, 0x513968fdU, 0x9c861a30U, + 0x821d9f2eU, 0x9e069832U, 0xe720c74bU, 0xfa7b8156U, + 0x12a9bbbeU, 0x92099b3eU, 0xf734c35bU, 0x08373fa4U, + 0x45286de9U, 0x16acbabaU, 0x0ff2fda3U, 0x4ba7ece7U, + 0x684f27c4U, 0x59336af5U, 0x8a179d26U, 0x5fb6e9f3U, + 0x27d0f78bU, 0xce428c62U, 0x1ea6b8b2U, 0x89d75e25U, + 0x948c1838U, 0x05787da9U, 0x35447199U, 0x6c4a26c0U, + 0xbdee5311U, 0xe8ef0744U, 0x3c0e3290U, 0x5d366bf1U, + 0x17ecfbbbU, 0x09777ea5U, 0xf674825aU, 0xc0cd0d6cU, + 0x98831b34U, 0xc9874e65U, 0xdd964b71U, 0x2d5a7781U, + 0xf1b1405dU, 0x9349da3fU, 0x42edafeeU, 0x9089193cU, + 0x95cc5939U, 0xacba1600U, 0x6385e6cfU, 0x84981c28U, + 0x785b23d4U, 0xc6488e6aU, 0x7edea0d2U, 0x43adeeefU, + 0xa0b5150cU, 0x58732bf4U, 0xde568872U, 0xd65c8a7aU, + 0xc18d4c6dU, 0x24103488U, 0xd0d9097cU, 0x99c35a35U, + 0x62c5a7ceU, 0xcd824f61U, 0x9dc65b31U, 0xae3a9402U, + 0x1c263ab0U, 0x8f52dd23U, 0x3d4e7391U, 0x974cdb3bU, + 0x156c79b9U, 0xb221931eU, 0x9a039936U, 0xb8ab1314U, + 0x2295b78eU, 0x5bb3e8f7U, 0x2fdaf583U, 0xab7fd407U, + 0x412d6cedU, 0x791b62d5U, 0xca478d66U, 0x03fdfeafU, + 0x6d0a67c1U, 0xe1a5444dU, 0x2c1a3680U, 0xaa3f9506U, + 0x1aa3b9b6U, 0xe9af4645U, 0xbf6ed113U, 0xdf16c973U, + 0xa375d60fU, 0xa770d70bU, 0x7b9be0d7U, 0x53b9eaffU, + 0x2015358cU, 0x7adba1d6U, 0xa8bf1704U, 0x5c762af0U, + 0xf8fb0354U, 0x610564cdU, 0xe4e00448U, 0xeb2fc447U, + 0x52f9abfeU, 0x711160ddU, 0x6780e7cbU, 0x13e9fabfU, + 0x6acfa5c6U, 0x56fcaafaU, 0x7f9ee1d3U, 0x751461d9U, + 0x3e8eb092U, 0x116978bdU, 0xd2598b7eU, 0x34043098U, + 0x809d1d2cU, 0x2155748dU, 0xfb3bc057U, 0xe0e5054cU, + 0xa235970eU, 0xc708cf6bU, 0x553c69f9U, 0x5ef6a8f2U, + 0xf4f40058U, 0x81dd5c2dU, 0xc4c80c68U, 0xd4dc0878U, + 0x3001319cU, 0xb361d21fU, 0x48672fe4U, 0x3fcef193U, + 0x2690b68aU, 0x4c622ee0U, 0xcb07cc67U, 0xef2ac543U, + 0x835dde2fU, 0xf0f1015cU, 0xd199487dU, 0x3281b39eU, + 0x017d7cadU, 0xaf7ad503U, 0x0d727fa1U, 0x04383ca8U, + 0x76d4a2daU, 0xd59c4979U, 0xe325c64fU, 0xa5f05509U, + 0xfe7e8052U, 0x650065c9U, 0x23d5f68fU, 0x960c9a3aU, + 0xf331c25fU, 0xadfa5701U, 0x6b8fe4c7U, 0xee6a8442U, + 0x49276ee5U, 0x394b7295U, 0xf271835eU, 0x37c4f39bU, + 0x72d2a02eU, 0x6b8ce737U, 0x8e119fd2U, 0xd25a888eU, + 0x1aa0ba46U, 0xae3997f2U, 0xdd954881U, 0xf737c0abU, + 0x7112632dU, 0xf332c1afU, 0x79186125U, 0x2296b47eU, + 0x89d45dd5U, 0xc64b8d9aU, 0x99c059c5U, 0x3d4d7061U, + 0x85db5ed9U, 0xb4a713e8U, 0x43aeed1fU, 0xf0f202acU, + 0x81de5fddU, 0xd31ac98fU, 0x39487165U, 0x2693b57aU, + 0x835edddfU, 0x38083064U, 0x65036639U, 0xb1e253edU, + 0x0c313d50U, 0x33c2f16fU, 0x3142736dU, 0x4fa1ee13U, + 0x5bb0eb07U, 0x2016367cU, 0x684c2434U, 0xfa7882a6U, + 0x6f89e633U, 0x960f99caU, 0x4ba4ef17U, 0xc0ce0e9cU, + 0xe5a346b9U, 0x78582024U, 0x057b7e59U, 0x24133778U, + 0x9e059bc2U, 0x16afb94aU, 0x9b40dbc7U, 0xa0b616fcU, + 0xba2892e6U, 0xe723c4bbU, 0x59306905U, 0x8f51ded3U, + 0x0eb1bf52U, 0x09747d55U, 0x8a149ed6U, 0x7f9de223U, + 0x2bdcf777U, 0x56ffa90aU, 0x7b98e327U, 0xc24e8c9eU, + 0xfcfd01a0U, 0x17eff84bU, 0xd59f4a89U, 0xb362d1efU, + 0x34073368U, 0x35477269U, 0xb767d0ebU, 0xda508a86U, + 0xe66385baU, 0xe4e307b8U, 0x75176229U, 0xc30ecd9fU, + 0x27d3f47bU, 0x4c612d10U, 0xd9904985U, 0x4d216c11U, + 0xb22290eeU, 0x3fcdf263U, 0x142f3b48U, 0x8b54dfd7U, + 0x88941cd4U, 0x849b1fd8U, 0x2fd9f673U, 0xe326c5bfU, + 0xece905b0U, 0xb8a810e4U, 0x42eeac1eU, 0x07fbfc5bU, + 0xca448e96U, 0x861b9ddaU, 0x156f7a49U, 0x043b3f58U, + 0xe8ec04b4U, 0x7052222cU, 0x5fb5ea03U, 0xfdbd40a1U, + 0x513a6b0dU, 0xb9e851e5U, 0x116a7b4dU, 0x507a2a0cU, + 0xa4b317f8U, 0x48642c14U, 0x6ec9a732U, 0xa376d5ffU, + 0xbded50e1U, 0xa1f657fdU, 0xd8d00884U, 0xc58b4e99U, + 0x2d597471U, 0xadf954f1U, 0xc8c40c94U, 0x37c7f06bU, + 0x7ad8a226U, 0x295c7575U, 0x3002326cU, 0x74572328U, + 0x57bfe80bU, 0x66c3a53aU, 0xb5e752e9U, 0x6046263cU, + 0x18203844U, 0xf1b243adU, 0x2156777dU, 0xb62791eaU, + 0xab7cd7f7U, 0x3a88b266U, 0x0ab4be56U, 0x53bae90fU, + 0x821e9cdeU, 0xd71fc88bU, 0x03fefd5fU, 0x62c6a43eU, + 0x281c3474U, 0x3687b16aU, 0xc9844d95U, 0xff3dc2a3U, + 0xa773d4fbU, 0xf67781aaU, 0xe26684beU, 0x12aab84eU, + 0xce418f92U, 0xacb915f0U, 0x7d1d6021U, 0xaf79d6f3U, + 0xaa3c96f6U, 0x934ad9cfU, 0x5c752900U, 0xbb68d3e7U, + 0x47abec1bU, 0xf9b841a5U, 0x412e6f1dU, 0x7c5d2120U, + 0x9f45dac3U, 0x6783e43bU, 0xe1a647bdU, 0xe9ac45b5U, + 0xfe7d83a2U, 0x1be0fb47U, 0xef29c6b3U, 0xa63395faU, + 0x5d356801U, 0xf27280aeU, 0xa23694feU, 0x91ca5bcdU, + 0x23d6f57fU, 0xb0a212ecU, 0x02bebc5eU, 0xa8bc14f4U, + 0x2a9cb676U, 0x8dd15cd1U, 0xa5f356f9U, 0x875bdcdbU, + 0x1d657841U, 0x64432738U, 0x102a3a4cU, 0x948f1bc8U, + 0x7edda322U, 0x46ebad1aU, 0xf5b742a9U, 0x3c0d3160U, + 0x52faa80eU, 0xde558b82U, 0x13eaf94fU, 0x95cf5ac9U, + 0x25537679U, 0xd65f898aU, 0x809e1edcU, 0xe0e606bcU, + 0x9c8519c0U, 0x988018c4U, 0x446b2f18U, 0x6c492530U, + 0x1fe5fa43U, 0x452b6e19U, 0x974fd8cbU, 0x6386e53fU, + 0xc70bcc9bU, 0x5ef5ab02U, 0xdb10cb87U, 0xd4df0b88U, + 0x6d096431U, 0x4ee1af12U, 0x58702804U, 0x2c193570U, + 0x553f6a09U, 0x690c6535U, 0x406e2e1cU, 0x4ae4ae16U, + 0x017e7f5dU, 0x2e99b772U, 0xeda944b1U, 0x0bf4ff57U, + 0xbf6dd2e3U, 0x1ea5bb42U, 0xc4cb0f98U, 0xdf15ca83U, + 0x9dc558c1U, 0xf8f800a4U, 0x6acca636U, 0x6106673dU, + 0xcb04cf97U, 0xbe2d93e2U, 0xfb38c3a7U, 0xeb2cc7b7U, + 0x0ff1fe53U, 0x8c911dd0U, 0x7797e02bU, 0x003e3e5cU, + 0x19607945U, 0x7392e12fU, 0xf4f703a8U, 0xd0da0a8cU, + 0xbcad11e0U, 0xcf01ce93U, 0xee6987b2U, 0x0d717c51U, + 0x3e8db362U, 0x908a1accU, 0x3282b06eU, 0x3bc8f367U, + 0x49246d15U, 0xea6c86b6U, 0xdcd50980U, 0x9a009ac6U, + 0xc18e4f9dU, 0x5af0aa06U, 0x1c253940U, 0xa9fc55f5U, + 0xccc10d90U, 0x920a98ceU, 0x547f2b08U, 0xd19a4b8dU, + 0x76d7a12aU, 0x06bbbd5aU, 0xcd814c91U, 0x08343c54U, + 0x6f2847c9U, 0x767600d0U, 0x93eb7835U, 0xcfa06f69U, + 0x075a5da1U, 0xb3c37015U, 0xc06faf66U, 0xeacd274cU, + 0x6ce884caU, 0xeec82648U, 0x64e286c2U, 0x3f6c5399U, + 0x942eba32U, 0xdbb16a7dU, 0x843abe22U, 0x20b79786U, + 0x9821b93eU, 0xa95df40fU, 0x5e540af8U, 0xed08e54bU, + 0x9c24b83aU, 0xcee02e68U, 0x24b29682U, 0x3b69529dU, + 0x9ea43a38U, 0x25f2d783U, 0x78f981deU, 0xac18b40aU, + 0x11cbdab7U, 0x2e381688U, 0x2cb8948aU, 0x525b09f4U, + 0x464a0ce0U, 0x3decd19bU, 0x75b6c3d3U, 0xe7826541U, + 0x727301d4U, 0x8bf57e2dU, 0x565e08f0U, 0xdd34e97bU, + 0xf859a15eU, 0x65a2c7c3U, 0x188199beU, 0x39e9d09fU, + 0x83ff7c25U, 0x0b555eadU, 0x86ba3c20U, 0xbd4cf11bU, + 0xa7d27501U, 0xfad9235cU, 0x44ca8ee2U, 0x92ab3934U, + 0x134b58b5U, 0x148e9ab2U, 0x97ee7931U, 0x626705c4U, + 0x36261090U, 0x4b054eedU, 0x666204c0U, 0xdfb46b79U, + 0xe107e647U, 0x0a151facU, 0xc865ad6eU, 0xae983608U, + 0x29fdd48fU, 0x28bd958eU, 0xaa9d370cU, 0xc7aa6d61U, + 0xfb99625dU, 0xf919e05fU, 0x68ed85ceU, 0xdef42a78U, + 0x3a29139cU, 0x519bcaf7U, 0xc46aae62U, 0x50db8bf6U, + 0xafd87709U, 0x22371584U, 0x09d5dcafU, 0x96ae3830U, + 0x956efb33U, 0x9961f83fU, 0x32231194U, 0xfedc2258U, + 0xf113e257U, 0xa552f703U, 0x5f144bf9U, 0x1a011bbcU, + 0xd7be6971U, 0x9be17a3dU, 0x08959daeU, 0x19c1d8bfU, + 0xf516e353U, 0x6da8c5cbU, 0x424f0de4U, 0xe047a746U, + 0x4cc08ceaU, 0xa412b602U, 0x0c909caaU, 0x4d80cdebU, + 0xb949f01fU, 0x559ecbf3U, 0x733340d5U, 0xbe8c3218U, + 0xa017b706U, 0xbc0cb01aU, 0xc52aef63U, 0xd871a97eU, + 0x30a39396U, 0xb003b316U, 0xd53eeb73U, 0x2a3d178cU, + 0x672245c1U, 0x34a69292U, 0x2df8d58bU, 0x69adc4cfU, + 0x4a450fecU, 0x7b3942ddU, 0xa81db50eU, 0x7dbcc1dbU, + 0x05dadfa3U, 0xec48a44aU, 0x3cac909aU, 0xabdd760dU, + 0xb6863010U, 0x27725581U, 0x174e59b1U, 0x4e400ee8U, + 0x9fe47b39U, 0xcae52f6cU, 0x1e041ab8U, 0x7f3c43d9U, + 0x35e6d393U, 0x2b7d568dU, 0xd47eaa72U, 0xe2c72544U, + 0xba89331cU, 0xeb8d664dU, 0xff9c6359U, 0x0f505fa9U, + 0xd3bb6875U, 0xb143f217U, 0x60e787c6U, 0xb2833114U, + 0xb7c67111U, 0x8eb03e28U, 0x418fcee7U, 0xa6923400U, + 0x5a510bfcU, 0xe442a642U, 0x5cd488faU, 0x61a7c6c7U, + 0x82bf3d24U, 0x7a7903dcU, 0xfc5ca05aU, 0xf456a252U, + 0xe3876445U, 0x061a1ca0U, 0xf2d32154U, 0xbbc9721dU, + 0x40cf8fe6U, 0xef886749U, 0xbfcc7319U, 0x8c30bc2aU, + 0x3e2c1298U, 0xad58f50bU, 0x1f445bb9U, 0xb546f313U, + 0x37665191U, 0x902bbb36U, 0xb809b11eU, 0x9aa13b3cU, + 0x009f9fa6U, 0x79b9c0dfU, 0x0dd0ddabU, 0x8975fc2fU, + 0x632744c5U, 0x5b114afdU, 0xe84da54eU, 0x21f7d687U, + 0x4f004fe9U, 0xc3af6c65U, 0x0e101ea8U, 0x8835bd2eU, + 0x38a9919eU, 0xcba56e6dU, 0x9d64f93bU, 0xfd1ce15bU, + 0x817ffe27U, 0x857aff23U, 0x5991c8ffU, 0x71b3c2d7U, + 0x021f1da4U, 0x58d189feU, 0x8ab53f2cU, 0x7e7c02d8U, + 0xdaf12b7cU, 0x430f4ce5U, 0xc6ea2c60U, 0xc925ec6fU, + 0x70f383d6U, 0x531b48f5U, 0x458acfe3U, 0x31e3d297U, + 0x48c58deeU, 0x74f682d2U, 0x5d94c9fbU, 0x571e49f1U, + 0x1c8498baU, 0x33635095U, 0xf053a356U, 0x160e18b0U, + 0xa2973504U, 0x035f5ca5U, 0xd931e87fU, 0xc2ef2d64U, + 0x803fbf26U, 0xe502e743U, 0x773641d1U, 0x7cfc80daU, + 0xd6fe2870U, 0xa3d77405U, 0xe6c22440U, 0xf6d62050U, + 0x120b19b4U, 0x916bfa37U, 0x6a6d07ccU, 0x1dc4d9bbU, + 0x049a9ea2U, 0x6e6806c8U, 0xe90de44fU, 0xcd20ed6bU, + 0xa157f607U, 0xd2fb2974U, 0xf3936055U, 0x108b9bb6U, + 0x23775485U, 0x8d70fd2bU, 0x2f785789U, 0x26321480U, + 0x54de8af2U, 0xf7966151U, 0xc12fee67U, 0x87fa7d21U, + 0xdc74a87aU, 0x470a4de1U, 0x01dfdea7U, 0xb406b212U, + 0xd13bea77U, 0x8ff07f29U, 0x4985ccefU, 0xcc60ac6aU, + 0x6b2d46cdU, 0x1b415abdU, 0xd07bab76U, 0x15cedbb3U, + 0xac17bb35U, 0xb549fc2cU, 0x50d484c9U, 0x0c9f9395U, + 0xc465a15dU, 0x70fc8ce9U, 0x0350539aU, 0x29f2dbb0U, + 0xafd77836U, 0x2df7dab4U, 0xa7dd7a3eU, 0xfc53af65U, + 0x571146ceU, 0x188e9681U, 0x470542deU, 0xe3886b7aU, + 0x5b1e45c2U, 0x6a6208f3U, 0x9d6bf604U, 0x2e3719b7U, + 0x5f1b44c6U, 0x0ddfd294U, 0xe78d6a7eU, 0xf856ae61U, + 0x5d9bc6c4U, 0xe6cd2b7fU, 0xbbc67d22U, 0x6f2748f6U, + 0xd2f4264bU, 0xed07ea74U, 0xef876876U, 0x9164f508U, + 0x8575f01cU, 0xfed32d67U, 0xb6893f2fU, 0x24bd99bdU, + 0xb14cfd28U, 0x48ca82d1U, 0x9561f40cU, 0x1e0b1587U, + 0x3b665da2U, 0xa69d3b3fU, 0xdbbe6542U, 0xfad62c63U, + 0x40c080d9U, 0xc86aa251U, 0x4585c0dcU, 0x7e730de7U, + 0x64ed89fdU, 0x39e6dfa0U, 0x87f5721eU, 0x5194c5c8U, + 0xd074a449U, 0xd7b1664eU, 0x54d185cdU, 0xa158f938U, + 0xf519ec6cU, 0x883ab211U, 0xa55df83cU, 0x1c8b9785U, + 0x22381abbU, 0xc92ae350U, 0x0b5a5192U, 0x6da7caf4U, + 0xeac22873U, 0xeb826972U, 0x69a2cbf0U, 0x0495919dU, + 0x38a69ea1U, 0x3a261ca3U, 0xabd27932U, 0x1dcbd684U, + 0xf916ef60U, 0x92a4360bU, 0x0755529eU, 0x93e4770aU, + 0x6ce78bf5U, 0xe108e978U, 0xcaea2053U, 0x5591c4ccU, + 0x565107cfU, 0x5a5e04c3U, 0xf11ced68U, 0x3de3dea4U, + 0x322c1eabU, 0x666d0bffU, 0x9c2bb705U, 0xd93ee740U, + 0x1481958dU, 0x58de86c1U, 0xcbaa6152U, 0xdafe2443U, + 0x36291fafU, 0xae973937U, 0x8170f118U, 0x23785bbaU, + 0x8fff7016U, 0x672d4afeU, 0xcfaf6056U, 0x8ebf3117U, + 0x7a760ce3U, 0x96a1370fU, 0xb00cbc29U, 0x7db3cee4U, + 0x63284bfaU, 0x7f334ce6U, 0x0615139fU, 0x1b4e5582U, + 0xf39c6f6aU, 0x733c4feaU, 0x1601178fU, 0xe902eb70U, + 0xa41db93dU, 0xf7996e6eU, 0xeec72977U, 0xaa923833U, + 0x897af310U, 0xb806be21U, 0x6b2249f2U, 0xbe833d27U, + 0xc6e5235fU, 0x2f7758b6U, 0xff936c66U, 0x68e28af1U, + 0x75b9ccecU, 0xe44da97dU, 0xd471a54dU, 0x8d7ff214U, + 0x5cdb87c5U, 0x09dad390U, 0xdd3be644U, 0xbc03bf25U, + 0xf6d92f6fU, 0xe842aa71U, 0x1741568eU, 0x21f8d9b8U, + 0x79b6cfe0U, 0x28b29ab1U, 0x3ca39fa5U, 0xcc6fa355U, + 0x10849489U, 0x727c0eebU, 0xa3d87b3aU, 0x71bccde8U, + 0x74f98dedU, 0x4d8fc2d4U, 0x82b0321bU, 0x65adc8fcU, + 0x996ef700U, 0x277d5abeU, 0x9feb7406U, 0xa2983a3bU, + 0x4180c1d8U, 0xb946ff20U, 0x3f635ca6U, 0x37695eaeU, + 0x20b898b9U, 0xc525e05cU, 0x31ecdda8U, 0x78f68ee1U, + 0x83f0731aU, 0x2cb79bb5U, 0x7cf38fe5U, 0x4f0f40d6U, + 0xfd13ee64U, 0x6e6709f7U, 0xdc7ba745U, 0x76790fefU, + 0xf459ad6dU, 0x531447caU, 0x7b364de2U, 0x599ec7c0U, + 0xc3a0635aU, 0xba863c23U, 0xceef2157U, 0x4a4a00d3U, + 0xa018b839U, 0x982eb601U, 0x2b7259b2U, 0xe2c82a7bU, + 0x8c3fb315U, 0x00909099U, 0xcd2fe254U, 0x4b0a41d2U, + 0xfb966d62U, 0x089a9291U, 0x5e5b05c7U, 0x3e231da7U, + 0x424002dbU, 0x464503dfU, 0x9aae3403U, 0xb28c3e2bU, + 0xc120e158U, 0x9bee7502U, 0x498ac3d0U, 0xbd43fe24U, + 0x19ced780U, 0x8030b019U, 0x05d5d09cU, 0x0a1a1093U, + 0xb3cc7f2aU, 0x9024b409U, 0x86b5331fU, 0xf2dc2e6bU, + 0x8bfa7112U, 0xb7c97e2eU, 0x9eab3507U, 0x9421b50dU, + 0xdfbb6446U, 0xf05cac69U, 0x336c5faaU, 0xd531e44cU, + 0x61a8c9f8U, 0xc060a059U, 0x1a0e1483U, 0x01d0d198U, + 0x430043daU, 0x263d1bbfU, 0xb409bd2dU, 0xbfc37c26U, + 0x15c1d48cU, 0x60e888f9U, 0x25fdd8bcU, 0x35e9dcacU, + 0xd134e548U, 0x525406cbU, 0xa952fb30U, 0xdefb2547U, + 0xc7a5625eU, 0xad57fa34U, 0x2a3218b3U, 0x0e1f1197U, + 0x62680afbU, 0x11c4d588U, 0x30ac9ca9U, 0xd3b4674aU, + 0xe048a879U, 0x4e4f01d7U, 0xec47ab75U, 0xe50de87cU, + 0x97e1760eU, 0x34a99dadU, 0x0210129bU, 0x44c581ddU, + 0x1f4b5486U, 0x8435b11dU, 0xc2e0225bU, 0x77394eeeU, + 0x1204168bU, 0x4ccf83d5U, 0x8aba3013U, 0x0f5f5096U, + 0xa812ba31U, 0xd87ea641U, 0x1344578aU, 0xd6f1274fU, + 0xbfba058bU, 0xa6e44292U, 0x43793a77U, 0x1f322d2bU, + 0xd7c81fe3U, 0x63513257U, 0x10fded24U, 0x3a5f650eU, + 0xbc7ac688U, 0x3e5a640aU, 0xb470c480U, 0xeffe11dbU, + 0x44bcf870U, 0x0b23283fU, 0x54a8fc60U, 0xf025d5c4U, + 0x48b3fb7cU, 0x79cfb64dU, 0x8ec648baU, 0x3d9aa709U, + 0x4cb6fa78U, 0x1e726c2aU, 0xf420d4c0U, 0xebfb10dfU, + 0x4e36787aU, 0xf56095c1U, 0xa86bc39cU, 0x7c8af648U, + 0xc15998f5U, 0xfeaa54caU, 0xfc2ad6c8U, 0x82c94bb6U, + 0x96d84ea2U, 0xed7e93d9U, 0xa5248191U, 0x37102703U, + 0xa2e14396U, 0x5b673c6fU, 0x86cc4ab2U, 0x0da6ab39U, + 0x28cbe31cU, 0xb5308581U, 0xc813dbfcU, 0xe97b92ddU, + 0x536d3e67U, 0xdbc71cefU, 0x56287e62U, 0x6ddeb359U, + 0x77403743U, 0x2a4b611eU, 0x9458cca0U, 0x42397b76U, + 0xc3d91af7U, 0xc41cd8f0U, 0x477c3b73U, 0xb2f54786U, + 0xe6b452d2U, 0x9b970cafU, 0xb6f04682U, 0x0f26293bU, + 0x3195a405U, 0xda875deeU, 0x18f7ef2cU, 0x7e0a744aU, + 0xf96f96cdU, 0xf82fd7ccU, 0x7a0f754eU, 0x17382f23U, + 0x2b0b201fU, 0x298ba21dU, 0xb87fc78cU, 0x0e66683aU, + 0xeabb51deU, 0x810988b5U, 0x14f8ec20U, 0x8049c9b4U, + 0x7f4a354bU, 0xf2a557c6U, 0xd9479eedU, 0x463c7a72U, + 0x45fcb971U, 0x49f3ba7dU, 0xe2b153d6U, 0x2e4e601aU, + 0x2181a015U, 0x75c0b541U, 0x8f8609bbU, 0xca9359feU, + 0x072c2b33U, 0x4b73387fU, 0xd807dfecU, 0xc9539afdU, + 0x2584a111U, 0xbd3a8789U, 0x92dd4fa6U, 0x30d5e504U, + 0x9c52cea8U, 0x7480f440U, 0xdc02dee8U, 0x9d128fa9U, + 0x69dbb25dU, 0x850c89b1U, 0xa3a10297U, 0x6e1e705aU, + 0x7085f544U, 0x6c9ef258U, 0x15b8ad21U, 0x08e3eb3cU, + 0xe031d1d4U, 0x6091f154U, 0x05aca931U, 0xfaaf55ceU, + 0xb7b00783U, 0xe434d0d0U, 0xfd6a97c9U, 0xb93f868dU, + 0x9ad74daeU, 0xabab009fU, 0x788ff74cU, 0xad2e8399U, + 0xd5489de1U, 0x3cdae608U, 0xec3ed2d8U, 0x7b4f344fU, + 0x66147252U, 0xf7e017c3U, 0xc7dc1bf3U, 0x9ed24caaU, + 0x4f76397bU, 0x1a776d2eU, 0xce9658faU, 0xafae019bU, + 0xe57491d1U, 0xfbef14cfU, 0x04ece830U, 0x32556706U, + 0x6a1b715eU, 0x3b1f240fU, 0x2f0e211bU, 0xdfc21debU, + 0x03292a37U, 0x61d1b055U, 0xb075c584U, 0x62117356U, + 0x67543353U, 0x5e227c6aU, 0x911d8ca5U, 0x76007642U, + 0x8ac349beU, 0x34d0e400U, 0x8c46cab8U, 0xb1358485U, + 0x522d7f66U, 0xaaeb419eU, 0x2ccee218U, 0x24c4e010U, + 0x33152607U, 0xd6885ee2U, 0x22416316U, 0x6b5b305fU, + 0x905dcda4U, 0x3f1a250bU, 0x6f5e315bU, 0x5ca2fe68U, + 0xeebe50daU, 0x7dcab749U, 0xcfd619fbU, 0x65d4b151U, + 0xe7f413d3U, 0x40b9f974U, 0x689bf35cU, 0x4a33797eU, + 0xd00ddde4U, 0xa92b829dU, 0xdd429fe9U, 0x59e7be6dU, + 0xb3b50687U, 0x8b8308bfU, 0x38dfe70cU, 0xf16594c5U, + 0x9f920dabU, 0x133d2e27U, 0xde825ceaU, 0x58a7ff6cU, + 0xe83bd3dcU, 0x1b372c2fU, 0x4df6bb79U, 0x2d8ea319U, + 0x51edbc65U, 0x55e8bd61U, 0x89038abdU, 0xa1218095U, + 0xd28d5fe6U, 0x8843cbbcU, 0x5a277d6eU, 0xaeee409aU, + 0x0a63693eU, 0x939d0ea7U, 0x16786e22U, 0x19b7ae2dU, + 0xa061c194U, 0x83890ab7U, 0x95188da1U, 0xe17190d5U, + 0x9857cfacU, 0xa464c090U, 0x8d068bb9U, 0x878c0bb3U, + 0xcc16daf8U, 0xe3f112d7U, 0x20c1e114U, 0xc69c5af2U, + 0x72057746U, 0xd3cd1ee7U, 0x09a3aa3dU, 0x127d6f26U, + 0x50adfd64U, 0x3590a501U, 0xa7a40393U, 0xac6ec298U, + 0x066c6a32U, 0x73453647U, 0x36506602U, 0x26446212U, + 0xc2995bf6U, 0x41f9b875U, 0xbaff458eU, 0xcd569bf9U, + 0xd408dce0U, 0xbefa448aU, 0x399fa60dU, 0x1db2af29U, + 0x71c5b445U, 0x02696b36U, 0x23012217U, 0xc019d9f4U, + 0xf3e516c7U, 0x5de2bf69U, 0xffea15cbU, 0xf6a056c2U, + 0x844cc8b0U, 0x27042313U, 0x11bdac25U, 0x57683f63U, + 0x0ce6ea38U, 0x97980fa3U, 0xd14d9ce5U, 0x6494f050U, + 0x01a9a835U, 0x5f623d6bU, 0x99178eadU, 0x1cf2ee28U, + 0xbbbf048fU, 0xcbd318ffU, 0x00e9e934U, 0xc55c99f1U, + 0x2994bd33U, 0x30cafa2aU, 0xd55782cfU, 0x891c9593U, + 0x41e6a75bU, 0xf57f8aefU, 0x86d3559cU, 0xac71ddb6U, + 0x2a547e30U, 0xa874dcb2U, 0x225e7c38U, 0x79d0a963U, + 0xd29240c8U, 0x9d0d9087U, 0xc28644d8U, 0x660b6d7cU, + 0xde9d43c4U, 0xefe10ef5U, 0x18e8f002U, 0xabb41fb1U, + 0xda9842c0U, 0x885cd492U, 0x620e6c78U, 0x7dd5a867U, + 0xd818c0c2U, 0x634e2d79U, 0x3e457b24U, 0xeaa44ef0U, + 0x5777204dU, 0x6884ec72U, 0x6a046e70U, 0x14e7f30eU, + 0x00f6f61aU, 0x7b502b61U, 0x330a3929U, 0xa13e9fbbU, + 0x34cffb2eU, 0xcd4984d7U, 0x10e2f20aU, 0x9b881381U, + 0xbee55ba4U, 0x231e3d39U, 0x5e3d6344U, 0x7f552a65U, + 0xc54386dfU, 0x4de9a457U, 0xc006c6daU, 0xfbf00be1U, + 0xe16e8ffbU, 0xbc65d9a6U, 0x02767418U, 0xd417c3ceU, + 0x55f7a24fU, 0x52326048U, 0xd15283cbU, 0x24dbff3eU, + 0x709aea6aU, 0x0db9b417U, 0x20defe3aU, 0x99089183U, + 0xa7bb1cbdU, 0x4ca9e556U, 0x8ed95794U, 0xe824ccf2U, + 0x6f412e75U, 0x6e016f74U, 0xec21cdf6U, 0x8116979bU, + 0xbd2598a7U, 0xbfa51aa5U, 0x2e517f34U, 0x9848d082U, + 0x7c95e966U, 0x1727300dU, 0x82d65498U, 0x1667710cU, + 0xe9648df3U, 0x648bef7eU, 0x4f692655U, 0xd012c2caU, + 0xd3d201c9U, 0xdfdd02c5U, 0x749feb6eU, 0xb860d8a2U, + 0xb7af18adU, 0xe3ee0df9U, 0x19a8b103U, 0x5cbde146U, + 0x9102938bU, 0xdd5d80c7U, 0x4e296754U, 0x5f7d2245U, + 0xb3aa19a9U, 0x2b143f31U, 0x04f3f71eU, 0xa6fb5dbcU, + 0x0a7c7610U, 0xe2ae4cf8U, 0x4a2c6650U, 0x0b3c3711U, + 0xfff50ae5U, 0x13223109U, 0x358fba2fU, 0xf830c8e2U, + 0xe6ab4dfcU, 0xfab04ae0U, 0x83961599U, 0x9ecd5384U, + 0x761f696cU, 0xf6bf49ecU, 0x93821189U, 0x6c81ed76U, + 0x219ebf3bU, 0x721a6868U, 0x6b442f71U, 0x2f113e35U, + 0x0cf9f516U, 0x3d85b827U, 0xeea14ff4U, 0x3b003b21U, + 0x43662559U, 0xaaf45eb0U, 0x7a106a60U, 0xed618cf7U, + 0xf03acaeaU, 0x61ceaf7bU, 0x51f2a34bU, 0x08fcf412U, + 0xd95881c3U, 0x8c59d596U, 0x58b8e042U, 0x3980b923U, + 0x735a2969U, 0x6dc1ac77U, 0x92c25088U, 0xa47bdfbeU, + 0xfc35c9e6U, 0xad319cb7U, 0xb92099a3U, 0x49eca553U, + 0x9507928fU, 0xf7ff08edU, 0x265b7d3cU, 0xf43fcbeeU, + 0xf17a8bebU, 0xc80cc4d2U, 0x0733341dU, 0xe02ecefaU, + 0x1cedf106U, 0xa2fe5cb8U, 0x1a687200U, 0x271b3c3dU, + 0xc403c7deU, 0x3cc5f926U, 0xbae05aa0U, 0xb2ea58a8U, + 0xa53b9ebfU, 0x40a6e65aU, 0xb46fdbaeU, 0xfd7588e7U, + 0x0673751cU, 0xa9349db3U, 0xf97089e3U, 0xca8c46d0U, + 0x7890e862U, 0xebe40ff1U, 0x59f8a143U, 0xf3fa09e9U, + 0x71daab6bU, 0xd69741ccU, 0xfeb54be4U, 0xdc1dc1c6U, + 0x4623655cU, 0x3f053a25U, 0x4b6c2751U, 0xcfc906d5U, + 0x259bbe3fU, 0x1dadb007U, 0xaef15fb4U, 0x674b2c7dU, + 0x09bcb513U, 0x8513969fU, 0x48ace452U, 0xce8947d4U, + 0x7e156b64U, 0x8d199497U, 0xdbd803c1U, 0xbba01ba1U, + 0xc7c304ddU, 0xc3c605d9U, 0x1f2d3205U, 0x370f382dU, + 0x44a3e75eU, 0x1e6d7304U, 0xcc09c5d6U, 0x38c0f822U, + 0x9c4dd186U, 0x05b3b61fU, 0x8056d69aU, 0x8f991695U, + 0x364f792cU, 0x15a7b20fU, 0x03363519U, 0x775f286dU, + 0x0e797714U, 0x324a7828U, 0x1b283301U, 0x11a2b30bU, + 0x5a386240U, 0x75dfaa6fU, 0xb6ef59acU, 0x50b2e24aU, + 0xe42bcffeU, 0x45e3a65fU, 0x9f8d1285U, 0x8453d79eU, + 0xc68345dcU, 0xa3be1db9U, 0x318abb2bU, 0x3a407a20U, + 0x9042d28aU, 0xe56b8effU, 0xa07edebaU, 0xb06adaaaU, + 0x54b7e34eU, 0xd7d700cdU, 0x2cd1fd36U, 0x5b782341U, + 0x42266458U, 0x28d4fc32U, 0xafb11eb5U, 0x8b9c1791U, + 0xe7eb0cfdU, 0x9447d38eU, 0xb52f9aafU, 0x5637614cU, + 0x65cbae7fU, 0xcbcc07d1U, 0x69c4ad73U, 0x608eee7aU, + 0x12627008U, 0xb12a9babU, 0x8793149dU, 0xc14687dbU, + 0x9ac85280U, 0x01b6b71bU, 0x4763245dU, 0xf2ba48e8U, + 0x9787108dU, 0xc94c85d3U, 0x0f393615U, 0x8adc5690U, + 0x2d91bc37U, 0x5dfda047U, 0x96c7518cU, 0x53722149U, + 0x5ada800eU, 0x4384c717U, 0xa619bff2U, 0xfa52a8aeU, + 0x32a89a66U, 0x8631b7d2U, 0xf59d68a1U, 0xdf3fe08bU, + 0x591a430dU, 0xdb3ae18fU, 0x51104105U, 0x0a9e945eU, + 0xa1dc7df5U, 0xee43adbaU, 0xb1c879e5U, 0x15455041U, + 0xadd37ef9U, 0x9caf33c8U, 0x6ba6cd3fU, 0xd8fa228cU, + 0xa9d67ffdU, 0xfb12e9afU, 0x11405145U, 0x0e9b955aU, + 0xab56fdffU, 0x10001044U, 0x4d0b4619U, 0x99ea73cdU, + 0x24391d70U, 0x1bcad14fU, 0x194a534dU, 0x67a9ce33U, + 0x73b8cb27U, 0x081e165cU, 0x40440414U, 0xd270a286U, + 0x4781c613U, 0xbe07b9eaU, 0x63accf37U, 0xe8c62ebcU, + 0xcdab6699U, 0x50500004U, 0x2d735e79U, 0x0c1b1758U, + 0xb60dbbe2U, 0x3ea7996aU, 0xb348fbe7U, 0x88be36dcU, + 0x9220b2c6U, 0xcf2be49bU, 0x71384925U, 0xa759fef3U, + 0x26b99f72U, 0x217c5d75U, 0xa21cbef6U, 0x5795c203U, + 0x03d4d757U, 0x7ef7892aU, 0x5390c307U, 0xea46acbeU, + 0xd4f52180U, 0x3fe7d86bU, 0xfd976aa9U, 0x9b6af1cfU, + 0x1c0f1348U, 0x1d4f5249U, 0x9f6ff0cbU, 0xf258aaa6U, + 0xce6ba59aU, 0xcceb2798U, 0x5d1f4209U, 0xeb06edbfU, + 0x0fdbd45bU, 0x64690d30U, 0xf19869a5U, 0x65294c31U, + 0x9a2ab0ceU, 0x17c5d243U, 0x3c271b68U, 0xa35cfff7U, + 0xa09c3cf4U, 0xac933ff8U, 0x07d1d653U, 0xcb2ee59fU, + 0xc4e12590U, 0x90a030c4U, 0x6ae68c3eU, 0x2ff3dc7bU, + 0xe24caeb6U, 0xae13bdfaU, 0x3d675a69U, 0x2c331f78U, + 0xc0e42494U, 0x585a020cU, 0x77bdca23U, 0xd5b56081U, + 0x79324b2dU, 0x91e071c5U, 0x39625b6dU, 0x78720a2cU, + 0x8cbb37d8U, 0x606c0c34U, 0x46c18712U, 0x8b7ef5dfU, + 0x95e570c1U, 0x89fe77ddU, 0xf0d828a4U, 0xed836eb9U, + 0x05515451U, 0x85f174d1U, 0xe0cc2cb4U, 0x1fcfd04bU, + 0x52d08206U, 0x01545555U, 0x180a124cU, 0x5c5f0308U, + 0x7fb7c82bU, 0x4ecb851aU, 0x9def72c9U, 0x484e061cU, + 0x30281864U, 0xd9ba638dU, 0x095e575dU, 0x9e2fb1caU, + 0x8374f7d7U, 0x12809246U, 0x22bc9e76U, 0x7bb2c92fU, + 0xaa16bcfeU, 0xff17e8abU, 0x2bf6dd7fU, 0x4ace841eU, + 0x00141454U, 0x1e8f914aU, 0xe18c6db5U, 0xd735e283U, + 0x8f7bf4dbU, 0xde7fa18aU, 0xca6ea49eU, 0x3aa2986eU, + 0xe649afb2U, 0x84b135d0U, 0x55154001U, 0x8771f6d3U, + 0x8234b6d6U, 0xbb42f9efU, 0x747d0920U, 0x9360f3c7U, + 0x6fa3cc3bU, 0xd1b06185U, 0x69264f3dU, 0x54550100U, + 0xb74dfae3U, 0x4f8bc41bU, 0xc9ae679dU, 0xc1a46595U, + 0xd675a382U, 0x33e8db67U, 0xc721e693U, 0x8e3bb5daU, + 0x753d4821U, 0xda7aa08eU, 0x8a3eb4deU, 0xb9c27bedU, + 0x0bded55fU, 0x98aa32ccU, 0x2ab69c7eU, 0x80b434d4U, + 0x02949656U, 0xa5d97cf1U, 0x8dfb76d9U, 0xaf53fcfbU, + 0x356d5861U, 0x4c4b0718U, 0x38221a6cU, 0xbc873be8U, + 0x56d58302U, 0x6ee38d3aU, 0xddbf6289U, 0x14051140U, + 0x7af2882eU, 0xf65daba2U, 0x3be2d96fU, 0xbdc77ae9U, + 0x0d5b5659U, 0xfe57a9aaU, 0xa8963efcU, 0xc8ee269cU, + 0xb48d39e0U, 0xb08838e4U, 0x6c630f38U, 0x44410510U, + 0x37edda63U, 0x6d234e39U, 0xbf47f8ebU, 0x4b8ec51fU, + 0xef03ecbbU, 0x76fd8b22U, 0xf318eba7U, 0xfcd72ba8U, + 0x45014411U, 0x66e98f32U, 0x70780824U, 0x04111550U, + 0x7d374a29U, 0x41044515U, 0x68660e3cU, 0x62ec8e36U, + 0x29765f7dU, 0x06919752U, 0xc5a16491U, 0x23fcdf77U, + 0x9765f2c3U, 0x36ad9b62U, 0xecc32fb8U, 0xf71deaa3U, + 0xb5cd78e1U, 0xd0f02084U, 0x42c48616U, 0x490e471dU, + 0xe30cefb7U, 0x9625b3c2U, 0xd330e387U, 0xc324e797U, + 0x27f9de73U, 0xa4993df0U, 0x5f9fc00bU, 0x28361e7cU, + 0x31685965U, 0x5b9ac10fU, 0xdcff2388U, 0xf8d22aacU, + 0x94a531c0U, 0xe709eeb3U, 0xc661a792U, 0x25795c71U, + 0x16859342U, 0xb8823aecU, 0x1a8a904eU, 0x13c0d347U, + 0x612c4d35U, 0xc264a696U, 0xf4dd29a0U, 0xb208bae6U, + 0xe9866fbdU, 0x72f88a26U, 0x342d1960U, 0x81f475d5U, + 0xe4c92db0U, 0xba02b8eeU, 0x7c770b28U, 0xf9926badU, + 0x5edf810aU, 0x2eb39d7aU, 0xe5896cb1U, 0x203c1c74U, + 0x422163edU, 0x5b7f24f4U, 0xbee25c11U, 0xe2a94b4dU, + 0x2a537985U, 0x9eca5431U, 0xed668b42U, 0xc7c40368U, + 0x41e1a0eeU, 0xc3c1026cU, 0x49eba2e6U, 0x126577bdU, + 0xb9279e16U, 0xf6b84e59U, 0xa9339a06U, 0x0dbeb3a2U, + 0xb5289d1aU, 0x8454d02bU, 0x735d2edcU, 0xc001c16fU, + 0xb12d9c1eU, 0xe3e90a4cU, 0x09bbb2a6U, 0x166076b9U, + 0xb3ad1e1cU, 0x08fbf3a7U, 0x55f0a5faU, 0x8111902eU, + 0x3cc2fe93U, 0x033132acU, 0x01b1b0aeU, 0x7f522dd0U, + 0x6b4328c4U, 0x10e5f5bfU, 0x58bfe7f7U, 0xca8b4165U, + 0x5f7a25f0U, 0xa6fc5a09U, 0x7b572cd4U, 0xf03dcd5fU, + 0xd550857aU, 0x48abe3e7U, 0x3588bd9aU, 0x14e0f4bbU, + 0xaef65801U, 0x265c7a89U, 0xabb31804U, 0x9045d53fU, + 0x8adb5125U, 0xd7d00778U, 0x69c3aac6U, 0xbfa21d10U, + 0x3e427c91U, 0x3987be96U, 0xbae75d15U, 0x4f6e21e0U, + 0x1b2f34b4U, 0x660c6ac9U, 0x4b6b20e4U, 0xf2bd4f5dU, + 0xcc0ec263U, 0x271c3b88U, 0xe56c894aU, 0x8391122cU, + 0x04f4f0abU, 0x05b4b1aaU, 0x87941328U, 0xeaa34945U, + 0xd6904679U, 0xd410c47bU, 0x45e4a1eaU, 0xf3fd0e5cU, + 0x172037b8U, 0x7c92eed3U, 0xe9638a46U, 0x7dd2afd2U, + 0x82d1532dU, 0x0f3e31a0U, 0x24dcf88bU, 0xbba71c14U, + 0xb867df17U, 0xb468dc1bU, 0x1f2a35b0U, 0xd3d5067cU, + 0xdc1ac673U, 0x885bd327U, 0x721d6fddU, 0x37083f98U, + 0xfab74d55U, 0xb6e85e19U, 0x259cb98aU, 0x34c8fc9bU, + 0xd81fc777U, 0x40a1e1efU, 0x6f4629c0U, 0xcd4e8362U, + 0x61c9a8ceU, 0x891b9226U, 0x2199b88eU, 0x6089e9cfU, + 0x9440d43bU, 0x7897efd7U, 0x5e3a64f1U, 0x9385163cU, + 0x8d1e9322U, 0x9105943eU, 0xe823cb47U, 0xf5788d5aU, + 0x1daab7b2U, 0x9d0a9732U, 0xf837cf57U, 0x073433a8U, + 0x4a2b61e5U, 0x19afb6b6U, 0x00f1f1afU, 0x44a4e0ebU, + 0x674c2bc8U, 0x563066f9U, 0x8514912aU, 0x50b5e5ffU, + 0x28d3fb87U, 0xc141806eU, 0x11a5b4beU, 0x86d45229U, + 0x9b8f1434U, 0x0a7b71a5U, 0x3a477d95U, 0x63492accU, + 0xb2ed5f1dU, 0xe7ec0b48U, 0x330d3e9cU, 0x523567fdU, + 0x18eff7b7U, 0x067472a9U, 0xf9778e56U, 0xcfce0160U, + 0x97801738U, 0xc6844269U, 0xd295477dU, 0x22597b8dU, + 0xfeb24c51U, 0x9c4ad633U, 0x4deea3e2U, 0x9f8a1530U, + 0x9acf5535U, 0xa3b91a0cU, 0x6c86eac3U, 0x8b9b1024U, + 0x77582fd8U, 0xc94b8266U, 0x71ddacdeU, 0x4caee2e3U, + 0xafb61900U, 0x577027f8U, 0xd155847eU, 0xd95f8676U, + 0xce8e4061U, 0x2b133884U, 0xdfda0570U, 0x96c05639U, + 0x6dc6abc2U, 0xc281436dU, 0x92c5573dU, 0xa139980eU, + 0x132536bcU, 0x8051d12fU, 0x324d7f9dU, 0x984fd737U, + 0x1a6f75b5U, 0xbd229f12U, 0x9500953aU, 0xb7a81f18U, + 0x2d96bb82U, 0x54b0e4fbU, 0x20d9f98fU, 0xa47cd80bU, + 0x4e2e60e1U, 0x76186ed9U, 0xc544816aU, 0x0cfef2a3U, + 0x62096bcdU, 0xeea64841U, 0x23193a8cU, 0xa53c990aU, + 0x15a0b5baU, 0xe6ac4a49U, 0xb06ddd1fU, 0xd015c57fU, + 0xac76da03U, 0xa873db07U, 0x7498ecdbU, 0x5cbae6f3U, + 0x2f163980U, 0x75d8addaU, 0xa7bc1b08U, 0x537526fcU, + 0xf7f80f58U, 0x6e0668c1U, 0xebe30844U, 0xe42cc84bU, + 0x5dfaa7f2U, 0x7e126cd1U, 0x6883ebc7U, 0x1ceaf6b3U, + 0x65cca9caU, 0x59ffa6f6U, 0x709deddfU, 0x7a176dd5U, + 0x318dbc9eU, 0x1e6a74b1U, 0xdd5a8772U, 0x3b073c94U, + 0x8f9e1120U, 0x2e567881U, 0xf438cc5bU, 0xefe60940U, + 0xad369b02U, 0xc80bc367U, 0x5a3f65f5U, 0x51f5a4feU, + 0xfbf70c54U, 0x8ede5021U, 0xcbcb0064U, 0xdbdf0474U, + 0x3f023d90U, 0xbc62de13U, 0x476423e8U, 0x30cdfd9fU, + 0x2993ba86U, 0x436122ecU, 0xc404c06bU, 0xe029c94fU, + 0x8c5ed223U, 0xfff20d50U, 0xde9a4471U, 0x3d82bf92U, + 0x0e7e70a1U, 0xa079d90fU, 0x027173adU, 0x0b3b30a4U, + 0x79d7aed6U, 0xda9f4575U, 0xec26ca43U, 0xaaf35905U, + 0xf17d8c5eU, 0x6a0369c5U, 0x2cd6fa83U, 0x990f9636U, + 0xfc32ce53U, 0xa2f95b0dU, 0x648ce8cbU, 0xe169884eU, + 0x462462e9U, 0x36487e99U, 0xfd728f52U, 0x38c7ff97U, + 0x841f9b15U, 0x9d41dc0cU, 0x78dca4e9U, 0x2497b3b5U, + 0xec6d817dU, 0x58f4acc9U, 0x2b5873baU, 0x01fafb90U, + 0x87df5816U, 0x05fffa94U, 0x8fd55a1eU, 0xd45b8f45U, + 0x7f1966eeU, 0x3086b6a1U, 0x6f0d62feU, 0xcb804b5aU, + 0x731665e2U, 0x426a28d3U, 0xb563d624U, 0x063f3997U, + 0x771364e6U, 0x25d7f2b4U, 0xcf854a5eU, 0xd05e8e41U, + 0x7593e6e4U, 0xcec50b5fU, 0x93ce5d02U, 0x472f68d6U, + 0xfafc066bU, 0xc50fca54U, 0xc78f4856U, 0xb96cd528U, + 0xad7dd03cU, 0xd6db0d47U, 0x9e811f0fU, 0x0cb5b99dU, + 0x9944dd08U, 0x60c2a2f1U, 0xbd69d42cU, 0x360335a7U, + 0x136e7d82U, 0x8e951b1fU, 0xf3b64562U, 0xd2de0c43U, + 0x68c8a0f9U, 0xe0628271U, 0x6d8de0fcU, 0x567b2dc7U, + 0x4ce5a9ddU, 0x11eeff80U, 0xaffd523eU, 0x799ce5e8U, + 0xf87c8469U, 0xffb9466eU, 0x7cd9a5edU, 0x8950d918U, + 0xdd11cc4cU, 0xa0329231U, 0x8d55d81cU, 0x3483b7a5U, + 0x0a303a9bU, 0xe122c370U, 0x235271b2U, 0x45afead4U, + 0xc2ca0853U, 0xc38a4952U, 0x41aaebd0U, 0x2c9db1bdU, + 0x10aebe81U, 0x122e3c83U, 0x83da5912U, 0x35c3f6a4U, + 0xd11ecf40U, 0xbaac162bU, 0x2f5d72beU, 0xbbec572aU, + 0x44efabd5U, 0xc900c958U, 0xe2e20073U, 0x7d99e4ecU, + 0x7e5927efU, 0x725624e3U, 0xd914cd48U, 0x15ebfe84U, + 0x1a243e8bU, 0x4e652bdfU, 0xb4239725U, 0xf136c760U, + 0x3c89b5adU, 0x70d6a6e1U, 0xe3a24172U, 0xf2f60463U, + 0x1e213f8fU, 0x869f1917U, 0xa978d138U, 0x0b707b9aU, + 0xa7f75036U, 0x4f256adeU, 0xe7a74076U, 0xa6b71137U, + 0x527e2cc3U, 0xbea9172fU, 0x98049c09U, 0x55bbeec4U, + 0x4b206bdaU, 0x573b6cc6U, 0x2e1d33bfU, 0x334675a2U, + 0xdb944f4aU, 0x5b346fcaU, 0x3e0937afU, 0xc10acb50U, + 0x8c15991dU, 0xdf914e4eU, 0xc6cf0957U, 0x829a1813U, + 0xa172d330U, 0x900e9e01U, 0x432a69d2U, 0x968b1d07U, + 0xeeed037fU, 0x077f7896U, 0xd79b4c46U, 0x40eaaad1U, + 0x5db1ecccU, 0xcc45895dU, 0xfc79856dU, 0xa577d234U, + 0x74d3a7e5U, 0x21d2f3b0U, 0xf533c664U, 0x940b9f05U, + 0xded10f4fU, 0xc04a8a51U, 0x3f4976aeU, 0x09f0f998U, + 0x51beefc0U, 0x00baba91U, 0x14abbf85U, 0xe4678375U, + 0x388cb4a9U, 0x5a742ecbU, 0x8bd05b1aU, 0x59b4edc8U, + 0x5cf1adcdU, 0x6587e2f4U, 0xaab8123bU, 0x4da5e8dcU, + 0xb166d720U, 0x0f757a9eU, 0xb7e35426U, 0x8a901a1bU, + 0x6988e1f8U, 0x914edf00U, 0x176b7c86U, 0x1f617e8eU, + 0x08b0b899U, 0xed2dc07cU, 0x19e4fd88U, 0x50feaec1U, + 0xabf8533aU, 0x04bfbb95U, 0x54fbafc5U, 0x670760f6U, + 0xd51bce44U, 0x466f29d7U, 0xf4738765U, 0x5e712fcfU, + 0xdc518d4dU, 0x7b1c67eaU, 0x533e6dc2U, 0x7196e7e0U, + 0xeba8437aU, 0x928e1c03U, 0xe6e70177U, 0x624220f3U, + 0x88109819U, 0xb0269621U, 0x037a7992U, 0xcac00a5bU, + 0xa4379335U, 0x2898b0b9U, 0xe527c274U, 0x630261f2U, + 0xd39e4d42U, 0x2092b2b1U, 0x765325e7U, 0x162b3d87U, + 0x6a4822fbU, 0x6e4d23ffU, 0xb2a61423U, 0x9a841e0bU, + 0xe928c178U, 0xb3e65522U, 0x6182e3f0U, 0x954bde04U, + 0x31c6f7a0U, 0xa8389039U, 0x2dddf0bcU, 0x221230b3U, + 0x9bc45f0aU, 0xb82c9429U, 0xaebd133fU, 0xdad40e4bU, + 0xa3f25132U, 0x9fc15e0eU, 0xb6a31527U, 0xbc29952dU, + 0xf7b34466U, 0xd8548c49U, 0x1b647f8aU, 0xfd39c46cU, + 0x49a0e9d8U, 0xe8688079U, 0x320634a3U, 0x29d8f1b8U, + 0x6b0863faU, 0x0e353b9fU, 0x9c019d0dU, 0x97cb5c06U, + 0x3dc9f4acU, 0x48e0a8d9U, 0x0df5f89cU, 0x1de1fc8cU, + 0xf93cc568U, 0x7a5c26ebU, 0x815adb10U, 0xf6f30567U, + 0xefad427eU, 0x855fda14U, 0x023a3893U, 0x261731b7U, + 0x4a602adbU, 0x39ccf5a8U, 0x18a4bc89U, 0xfbbc476aU, + 0xc8408859U, 0x664721f7U, 0xc44f8b55U, 0xcd05c85cU, + 0xbfe9562eU, 0x1ca1bd8dU, 0x2a1832bbU, 0x6ccda1fdU, + 0x374374a6U, 0xac3d913dU, 0xeae8027bU, 0x5f316eceU, + 0x3a0c36abU, 0x64c7a3f5U, 0xa2b21033U, 0x275770b6U, + 0x801a9a11U, 0xf0768661U, 0x3b4c77aaU, 0xfef9076fU, + 0xa1bc1d93U, 0xb8e25a8aU, 0x5d7f226fU, 0x01343533U, + 0xc9ce07fbU, 0x7d572a4fU, 0x0efbf53cU, 0x24597d16U, + 0xa27cde90U, 0x205c7c12U, 0xaa76dc98U, 0xf1f809c3U, + 0x5abae068U, 0x15253027U, 0x4aaee478U, 0xee23cddcU, + 0x56b5e364U, 0x67c9ae55U, 0x90c050a2U, 0x239cbf11U, + 0x52b0e260U, 0x00747432U, 0xea26ccd8U, 0xf5fd08c7U, + 0x50306062U, 0xeb668dd9U, 0xb66ddb84U, 0x628cee50U, + 0xdf5f80edU, 0xe0ac4cd2U, 0xe22cced0U, 0x9ccf53aeU, + 0x88de56baU, 0xf3788bc1U, 0xbb229989U, 0x29163f1bU, + 0xbce75b8eU, 0x45612477U, 0x98ca52aaU, 0x13a0b321U, + 0x36cdfb04U, 0xab369d99U, 0xd615c3e4U, 0xf77d8ac5U, + 0x4d6b267fU, 0xc5c104f7U, 0x482e667aU, 0x73d8ab41U, + 0x69462f5bU, 0x344d7906U, 0x8a5ed4b8U, 0x5c3f636eU, + 0xdddf02efU, 0xda1ac0e8U, 0x597a236bU, 0xacf35f9eU, + 0xf8b24acaU, 0x859114b7U, 0xa8f65e9aU, 0x11203123U, + 0x2f93bc1dU, 0xc48145f6U, 0x06f1f734U, 0x600c6c52U, + 0xe7698ed5U, 0xe629cfd4U, 0x64096d56U, 0x093e373bU, + 0x350d3807U, 0x378dba05U, 0xa679df94U, 0x10607022U, + 0xf4bd49c6U, 0x9f0f90adU, 0x0afef438U, 0x9e4fd1acU, + 0x614c2d53U, 0xeca34fdeU, 0xc74186f5U, 0x583a626aU, + 0x5bfaa169U, 0x57f5a265U, 0xfcb74bceU, 0x30487802U, + 0x3f87b80dU, 0x6bc6ad59U, 0x918011a3U, 0xd49541e6U, + 0x192a332bU, 0x55752067U, 0xc601c7f4U, 0xd75582e5U, + 0x3b82b909U, 0xa33c9f91U, 0x8cdb57beU, 0x2ed3fd1cU, + 0x8254d6b0U, 0x6a86ec58U, 0xc204c6f0U, 0x831497b1U, + 0x77ddaa45U, 0x9b0a91a9U, 0xbda71a8fU, 0x70186842U, + 0x6e83ed5cU, 0x7298ea40U, 0x0bbeb539U, 0x16e5f324U, + 0xfe37c9ccU, 0x7e97e94cU, 0x1baab129U, 0xe4a94dd6U, + 0xa9b61f9bU, 0xfa32c8c8U, 0xe36c8fd1U, 0xa7399e95U, + 0x84d155b6U, 0xb5ad1887U, 0x6689ef54U, 0xb3289b81U, + 0xcb4e85f9U, 0x22dcfe10U, 0xf238cac0U, 0x65492c57U, + 0x78126a4aU, 0xe9e60fdbU, 0xd9da03ebU, 0x80d454b2U, + 0x51702163U, 0x04717536U, 0xd09040e2U, 0xb1a81983U, + 0xfb7289c9U, 0xe5e90cd7U, 0x1aeaf028U, 0x2c537f1eU, + 0x741d6946U, 0x25193c17U, 0x31083903U, 0xc1c405f3U, + 0x1d2f322fU, 0x7fd7a84dU, 0xae73dd9cU, 0x7c176b4eU, + 0x79522b4bU, 0x40246472U, 0x8f1b94bdU, 0x68066e5aU, + 0x94c551a6U, 0x2ad6fc18U, 0x9240d2a0U, 0xaf339c9dU, + 0x4c2b677eU, 0xb4ed5986U, 0x32c8fa00U, 0x3ac2f808U, + 0x2d133e1fU, 0xc88e46faU, 0x3c477b0eU, 0x755d2847U, + 0x8e5bd5bcU, 0x211c3d13U, 0x71582943U, 0x42a4e670U, + 0xf0b848c2U, 0x63ccaf51U, 0xd1d001e3U, 0x7bd2a949U, + 0xf9f20bcbU, 0x5ebfe16cU, 0x769deb44U, 0x54356166U, + 0xce0bc5fcU, 0xb72d9a85U, 0xc34487f1U, 0x47e1a675U, + 0xadb31e9fU, 0x958510a7U, 0x26d9ff14U, 0xef638cddU, + 0x819415b3U, 0x0d3b363fU, 0xc08444f2U, 0x46a1e774U, + 0xf63dcbc4U, 0x05313437U, 0x53f0a361U, 0x3388bb01U, + 0x4feba47dU, 0x4beea579U, 0x970592a5U, 0xbf27988dU, + 0xcc8b47feU, 0x9645d3a4U, 0x44216576U, 0xb0e85882U, + 0x14657126U, 0x8d9b16bfU, 0x087e763aU, 0x07b1b635U, + 0xbe67d98cU, 0x9d8f12afU, 0x8b1e95b9U, 0xff7788cdU, + 0x8651d7b4U, 0xba62d888U, 0x930093a1U, 0x998a13abU, + 0xd210c2e0U, 0xfdf70acfU, 0x3ec7f90cU, 0xd89a42eaU, + 0x6c036f5eU, 0xcdcb06ffU, 0x17a5b225U, 0x0c7b773eU, + 0x4eabe57cU, 0x2b96bd19U, 0xb9a21b8bU, 0xb268da80U, + 0x186a722aU, 0x6d432e5fU, 0x28567e1aU, 0x38427a0aU, + 0xdc9f43eeU, 0x5fffa06dU, 0xa4f95d96U, 0xd35083e1U, + 0xca0ec4f8U, 0xa0fc5c92U, 0x2799be15U, 0x03b4b731U, + 0x6fc3ac5dU, 0x1c6f732eU, 0x3d073a0fU, 0xde1fc1ecU, + 0xede30edfU, 0x43e4a771U, 0xe1ec0dd3U, 0xe8a64edaU, + 0x9a4ad0a8U, 0x39023b0bU, 0x0fbbb43dU, 0x496e277bU, + 0x12e0f220U, 0x899e17bbU, 0xcf4b84fdU, 0x7a92e848U, + 0x1fafb02dU, 0x41642573U, 0x871196b5U, 0x02f4f630U, + 0xa5b91c97U, 0xd5d500e7U, 0x1eeff12cU, 0xdb5a81e9U, + 0xabbe159bU, 0xb2e05282U, 0x577d2a67U, 0x0b363d3bU, + 0xc3cc0ff3U, 0x77552247U, 0x04f9fd34U, 0x2e5b751eU, + 0xa87ed698U, 0x2a5e741aU, 0xa074d490U, 0xfbfa01cbU, + 0x50b8e860U, 0x1f27382fU, 0x40acec70U, 0xe421c5d4U, + 0x5cb7eb6cU, 0x6dcba65dU, 0x9ac258aaU, 0x299eb719U, + 0x58b2ea68U, 0x0a767c3aU, 0xe024c4d0U, 0xffff00cfU, + 0x5a32686aU, 0xe16485d1U, 0xbc6fd38cU, 0x688ee658U, + 0xd55d88e5U, 0xeaae44daU, 0xe82ec6d8U, 0x96cd5ba6U, + 0x82dc5eb2U, 0xf97a83c9U, 0xb1209181U, 0x23143713U, + 0xb6e55386U, 0x4f632c7fU, 0x92c85aa2U, 0x19a2bb29U, + 0x3ccff30cU, 0xa1349591U, 0xdc17cbecU, 0xfd7f82cdU, + 0x47692e77U, 0xcfc30cffU, 0x422c6e72U, 0x79daa349U, + 0x63442753U, 0x3e4f710eU, 0x805cdcb0U, 0x563d6b66U, + 0xd7dd0ae7U, 0xd018c8e0U, 0x53782b63U, 0xa6f15796U, + 0xf2b042c2U, 0x8f931cbfU, 0xa2f45692U, 0x1b22392bU, + 0x2591b415U, 0xce834dfeU, 0x0cf3ff3cU, 0x6a0e645aU, + 0xed6b86ddU, 0xec2bc7dcU, 0x6e0b655eU, 0x033c3f33U, + 0x3f0f300fU, 0x3d8fb20dU, 0xac7bd79cU, 0x1a62782aU, + 0xfebf41ceU, 0x950d98a5U, 0x00fcfc30U, 0x944dd9a4U, + 0x6b4e255bU, 0xe6a147d6U, 0xcd438efdU, 0x52386a62U, + 0x51f8a961U, 0x5df7aa6dU, 0xf6b543c6U, 0x3a4a700aU, + 0x3585b005U, 0x61c4a551U, 0x9b8219abU, 0xde9749eeU, + 0x13283b23U, 0x5f77286fU, 0xcc03cffcU, 0xdd578aedU, + 0x3180b101U, 0xa93e9799U, 0x86d95fb6U, 0x24d1f514U, + 0x8856deb8U, 0x6084e450U, 0xc806cef8U, 0x89169fb9U, + 0x7ddfa24dU, 0x910899a1U, 0xb7a51287U, 0x7a1a604aU, + 0x6481e554U, 0x789ae248U, 0x01bcbd31U, 0x1ce7fb2cU, + 0xf435c1c4U, 0x7495e144U, 0x11a8b921U, 0xeeab45deU, + 0xa3b41793U, 0xf030c0c0U, 0xe96e87d9U, 0xad3b969dU, + 0x8ed35dbeU, 0xbfaf108fU, 0x6c8be75cU, 0xb92a9389U, + 0xc14c8df1U, 0x28def618U, 0xf83ac2c8U, 0x6f4b245fU, + 0x72106242U, 0xe3e407d3U, 0xd3d80be3U, 0x8ad65cbaU, + 0x5b72296bU, 0x0e737d3eU, 0xda9248eaU, 0xbbaa118bU, + 0xf17081c1U, 0xefeb04dfU, 0x10e8f820U, 0x26517716U, + 0x7e1f614eU, 0x2f1b341fU, 0x3b0a310bU, 0xcbc60dfbU, + 0x172d3a27U, 0x75d5a045U, 0xa471d594U, 0x76156346U, + 0x73502343U, 0x4a266c7aU, 0x85199cb5U, 0x62046652U, + 0x9ec759aeU, 0x20d4f410U, 0x9842daa8U, 0xa5319495U, + 0x46296f76U, 0xbeef518eU, 0x38caf208U, 0x30c0f000U, + 0x27113617U, 0xc28c4ef2U, 0x36457306U, 0x7f5f204fU, + 0x8459ddb4U, 0x2b1e351bU, 0x7b5a214bU, 0x48a6ee78U, + 0xfaba40caU, 0x69cea759U, 0xdbd209ebU, 0x71d0a141U, + 0xf3f003c3U, 0x54bde964U, 0x7c9fe34cU, 0x5e37696eU, + 0xc409cdf4U, 0xbd2f928dU, 0xc9468ff9U, 0x4de3ae7dU, + 0xa7b11697U, 0x9f8718afU, 0x2cdbf71cU, 0xe56184d5U, + 0x8b961dbbU, 0x07393e37U, 0xca864cfaU, 0x4ca3ef7cU, + 0xfc3fc3ccU, 0x0f333c3fU, 0x59f2ab69U, 0x398ab309U, + 0x45e9ac75U, 0x41ecad71U, 0x9d079aadU, 0xb5259085U, + 0xc6894ff6U, 0x9c47dbacU, 0x4e236d7eU, 0xbaea508aU, + 0x1e67792eU, 0x87991eb7U, 0x027c7e32U, 0x0db3be3dU, + 0xb465d184U, 0x978d1aa7U, 0x811c9db1U, 0xf57580c5U, + 0x8c53dfbcU, 0xb060d080U, 0x99029ba9U, 0x93881ba3U, + 0xd812cae8U, 0xf7f502c7U, 0x34c5f104U, 0xd2984ae2U, + 0x66016756U, 0xc7c90ef7U, 0x1da7ba2dU, 0x06797f36U, + 0x44a9ed74U, 0x2194b511U, 0xb3a01383U, 0xb86ad288U, + 0x12687a22U, 0x67412657U, 0x22547612U, 0x32407202U, + 0xd69d4be6U, 0x55fda865U, 0xaefb559eU, 0xd9528be9U, + 0xc00cccf0U, 0xaafe549aU, 0x2d9bb61dU, 0x09b6bf39U, + 0x65c1a455U, 0x166d7b26U, 0x37053207U, 0xd41dc9e4U, + 0xe7e106d7U, 0x49e6af79U, 0xebee05dbU, 0xe2a446d2U, + 0x9048d8a0U, 0x33003303U, 0x05b9bc35U, 0x436c2f73U, + 0x18e2fa28U, 0x839c1fb3U, 0xc5498cf5U, 0x7090e040U, + 0x15adb825U, 0x4b662d7bU, 0x8d139ebdU, 0x08f6fe38U, + 0xafbb149fU, 0xdfd708efU, 0x14edf924U, 0xd15889e1U, + 0x7a78028cU, 0x63264595U, 0x86bb3d70U, 0xdaf02a2cU, + 0x120a18e4U, 0xa6933550U, 0xd53fea23U, 0xff9d6209U, + 0x79b8c18fU, 0xfb98630dU, 0x71b2c387U, 0x2a3c16dcU, + 0x817eff77U, 0xcee12f38U, 0x916afb67U, 0x35e7d2c3U, + 0x8d71fc7bU, 0xbc0db14aU, 0x4b044fbdU, 0xf858a00eU, + 0x8974fd7fU, 0xdbb06b2dU, 0x31e2d3c7U, 0x2e3917d8U, + 0x8bf47f7dU, 0x30a292c6U, 0x6da9c49bU, 0xb948f14fU, + 0x049b9ff2U, 0x3b6853cdU, 0x39e8d1cfU, 0x470b4cb1U, + 0x531a49a5U, 0x28bc94deU, 0x60e68696U, 0xf2d22004U, + 0x67234491U, 0x9ea53b68U, 0x430e4db5U, 0xc864ac3eU, + 0xed09e41bU, 0x70f28286U, 0x0dd1dcfbU, 0x2cb995daU, + 0x96af3960U, 0x1e051be8U, 0x93ea7965U, 0xa81cb45eU, + 0xb2823044U, 0xef896619U, 0x519acba7U, 0x87fb7c71U, + 0x061b1df0U, 0x01dedff7U, 0x82be3c74U, 0x77374081U, + 0x237655d5U, 0x5e550ba8U, 0x73324185U, 0xcae42e3cU, + 0xf457a302U, 0x1f455ae9U, 0xdd35e82bU, 0xbbc8734dU, + 0x3cad91caU, 0x3dedd0cbU, 0xbfcd7249U, 0xd2fa2824U, + 0xeec92718U, 0xec49a51aU, 0x7dbdc08bU, 0xcba46f3dU, + 0x2f7956d9U, 0x44cb8fb2U, 0xd13aeb27U, 0x458bceb3U, + 0xba88324cU, 0x376750c1U, 0x1c8599eaU, 0x83fe7d75U, + 0x803ebe76U, 0x8c31bd7aU, 0x277354d1U, 0xeb8c671dU, + 0xe443a712U, 0xb002b246U, 0x4a440ebcU, 0x0f515ef9U, + 0xc2ee2c34U, 0x8eb13f78U, 0x1dc5d8ebU, 0x0c919dfaU, + 0xe046a616U, 0x78f8808eU, 0x571f48a1U, 0xf517e203U, + 0x5990c9afU, 0xb142f347U, 0x19c0d9efU, 0x58d088aeU, + 0xac19b55aU, 0x40ce8eb6U, 0x66630590U, 0xabdc775dU, + 0xb547f243U, 0xa95cf55fU, 0xd07aaa26U, 0xcd21ec3bU, + 0x25f3d6d3U, 0xa553f653U, 0xc06eae36U, 0x3f6d52c9U, + 0x72720084U, 0x21f6d7d7U, 0x38a890ceU, 0x7cfd818aU, + 0x5f154aa9U, 0x6e690798U, 0xbd4df04bU, 0x68ec849eU, + 0x108a9ae6U, 0xf918e10fU, 0x29fcd5dfU, 0xbe8d3348U, + 0xa3d67555U, 0x322210c4U, 0x021e1cf4U, 0x5b104badU, + 0x8ab43e7cU, 0xdfb56a29U, 0x0b545ffdU, 0x6a6c069cU, + 0x20b696d6U, 0x3e2d13c8U, 0xc12eef37U, 0xf7976001U, + 0xafd97659U, 0xfedd2308U, 0xeacc261cU, 0x1a001aecU, + 0xc6eb2d30U, 0xa413b752U, 0x75b7c283U, 0xa7d37451U, + 0xa2963454U, 0x9be07b6dU, 0x54df8ba2U, 0xb3c27145U, + 0x4f014eb9U, 0xf112e307U, 0x4984cdbfU, 0x74f78382U, + 0x97ef7861U, 0x6f294699U, 0xe90ce51fU, 0xe106e717U, + 0xf6d72100U, 0x134a59e5U, 0xe7836411U, 0xae993758U, + 0x559fcaa3U, 0xfad8220cU, 0xaa9c365cU, 0x9960f96fU, + 0x2b7c57ddU, 0xb808b04eU, 0x0a141efcU, 0xa016b656U, + 0x223614d4U, 0x857bfe73U, 0xad59f45bU, 0x8ff17e79U, + 0x15cfdae3U, 0x6ce9859aU, 0x188098eeU, 0x9c25b96aU, + 0x76770180U, 0x4e410fb8U, 0xfd1de00bU, 0x34a793c2U, + 0x5a500aacU, 0xd6ff2920U, 0x1b405bedU, 0x9d65f86bU, + 0x2df9d4dbU, 0xdef52b28U, 0x8834bc7eU, 0xe84ca41eU, + 0x942fbb62U, 0x902aba66U, 0x4cc18dbaU, 0x64e38792U, + 0x174f58e1U, 0x4d81ccbbU, 0x9fe57a69U, 0x6b2c479dU, + 0xcfa16e39U, 0x565f09a0U, 0xd3ba6925U, 0xdc75a92aU, + 0x65a3c693U, 0x464b0db0U, 0x50da8aa6U, 0x24b397d2U, + 0x5d95c8abU, 0x61a6c797U, 0x48c48cbeU, 0x424e0cb4U, + 0x09d4ddffU, 0x263315d0U, 0xe503e613U, 0x035e5df5U, + 0xb7c77041U, 0x160f19e0U, 0xcc61ad3aU, 0xd7bf6821U, + 0x956ffa63U, 0xf052a206U, 0x62660494U, 0x69acc59fU, + 0xc3ae6d35U, 0xb6873140U, 0xf3926105U, 0xe3866515U, + 0x075b5cf1U, 0x843bbf72U, 0x7f3d4289U, 0x08949cfeU, + 0x11cadbe7U, 0x7b38438dU, 0xfc5da10aU, 0xd870a82eU, + 0xb407b342U, 0xc7ab6c31U, 0xe6c32510U, 0x05dbdef3U, + 0x362711c0U, 0x9820b86eU, 0x3a2812ccU, 0x336251c5U, + 0x418ecfb7U, 0xe2c62414U, 0xd47fab22U, 0x92aa3864U, + 0xc924ed3fU, 0x525a08a4U, 0x148f9be2U, 0xa156f757U, + 0xc46baf32U, 0x9aa03a6cU, 0x5cd589aaU, 0xd930e92fU, + 0x7e7d0388U, 0x0e111ff8U, 0xc52bee33U, 0x009e9ef6U, + 0xe700e769U, 0xfe5ea070U, 0x1bc3d895U, 0x4788cfc9U, + 0x8f72fd01U, 0x3bebd0b5U, 0x48470fc6U, 0x62e587ecU, + 0xe4c0246aU, 0x66e086e8U, 0xecca2662U, 0xb744f339U, + 0x1c061a92U, 0x5399caddU, 0x0c121e82U, 0xa89f3726U, + 0x1009199eU, 0x217554afU, 0xd67caa58U, 0x652045ebU, + 0x140c189aU, 0x46c88ec8U, 0xac9a3622U, 0xb341f23dU, + 0x168c9a98U, 0xadda7723U, 0xf0d1217eU, 0x243014aaU, + 0x99e37a17U, 0xa610b628U, 0xa490342aU, 0xda73a954U, + 0xce62ac40U, 0xb5c4713bU, 0xfd9e6373U, 0x6faac5e1U, + 0xfa5ba174U, 0x03ddde8dU, 0xde76a850U, 0x551c49dbU, + 0x707101feU, 0xed8a6763U, 0x90a9391eU, 0xb1c1703fU, + 0x0bd7dc85U, 0x837dfe0dU, 0x0e929c80U, 0x356451bbU, + 0x2ffad5a1U, 0x72f183fcU, 0xcce22e42U, 0x1a839994U, + 0x9b63f815U, 0x9ca63a12U, 0x1fc6d991U, 0xea4fa564U, + 0xbe0eb030U, 0xc32dee4dU, 0xee4aa460U, 0x579ccbd9U, + 0x692f46e7U, 0x823dbf0cU, 0x404d0dceU, 0x26b096a8U, + 0xa1d5742fU, 0xa095352eU, 0x22b597acU, 0x4f82cdc1U, + 0x73b1c2fdU, 0x713140ffU, 0xe0c5256eU, 0x56dc8ad8U, + 0xb201b33cU, 0xd9b36a57U, 0x4c420ec2U, 0xd8f32b56U, + 0x27f0d7a9U, 0xaa1fb524U, 0x81fd7c0fU, 0x1e869890U, + 0x1d465b93U, 0x1149589fU, 0xba0bb134U, 0x76f482f8U, + 0x793b42f7U, 0x2d7a57a3U, 0xd73ceb59U, 0x9229bb1cU, + 0x5f96c9d1U, 0x13c9da9dU, 0x80bd3d0eU, 0x91e9781fU, + 0x7d3e43f3U, 0xe580656bU, 0xca67ad44U, 0x686f07e6U, + 0xc4e82c4aU, 0x2c3a16a2U, 0x84b83c0aU, 0xc5a86d4bU, + 0x316150bfU, 0xddb66b53U, 0xfb1be075U, 0x36a492b8U, + 0x283f17a6U, 0x342410baU, 0x4d024fc3U, 0x505909deU, + 0xb88b3336U, 0x382b13b6U, 0x5d164bd3U, 0xa215b72cU, + 0xef0ae561U, 0xbc8e3232U, 0xa5d0752bU, 0xe185646fU, + 0xc26daf4cU, 0xf311e27dU, 0x203515aeU, 0xf594617bU, + 0x8df27f03U, 0x646004eaU, 0xb484303aU, 0x23f5d6adU, + 0x3eae90b0U, 0xaf5af521U, 0x9f66f911U, 0xc668ae48U, + 0x17ccdb99U, 0x42cd8fccU, 0x962cba18U, 0xf714e379U, + 0xbdce7333U, 0xa355f62dU, 0x5c560ad2U, 0x6aef85e4U, + 0x32a193bcU, 0x63a5c6edU, 0x77b4c3f9U, 0x8778ff09U, + 0x5b93c8d5U, 0x396b52b7U, 0xe8cf2766U, 0x3aab91b4U, + 0x3feed1b1U, 0x06989e88U, 0xc9a76e47U, 0x2eba94a0U, + 0xd279ab5cU, 0x6c6a06e2U, 0xd4fc285aU, 0xe98f6667U, + 0x0a979d84U, 0xf251a37cU, 0x747400faU, 0x7c7e02f2U, + 0x6bafc4e5U, 0x8e32bc00U, 0x7afb81f4U, 0x33e1d2bdU, + 0xc8e72f46U, 0x67a0c7e9U, 0x37e4d3b9U, 0x04181c8aU, + 0xb604b238U, 0x257055abU, 0x976cfb19U, 0x3d6e53b3U, + 0xbf4ef131U, 0x18031b96U, 0x302111beU, 0x12899b9cU, + 0x88b73f06U, 0xf191607fU, 0x85f87d0bU, 0x015d5c8fU, + 0xeb0fe465U, 0xd339ea5dU, 0x606505eeU, 0xa9df7627U, + 0xc728ef49U, 0x4b87ccc5U, 0x8638be08U, 0x001d1d8eU, + 0xb081313eU, 0x438dcecdU, 0x154c599bU, 0x753441fbU, + 0x09575e87U, 0x0d525f83U, 0xd1b9685fU, 0xf99b6277U, + 0x8a37bd04U, 0xd0f9295eU, 0x029d9f8cU, 0xf654a278U, + 0x52d98bdcU, 0xcb27ec45U, 0x4ec28cc0U, 0x410d4ccfU, + 0xf8db2376U, 0xdb33e855U, 0xcda26f43U, 0xb9cb7237U, + 0xc0ed2d4eU, 0xfcde2272U, 0xd5bc695bU, 0xdf36e951U, + 0x94ac381aU, 0xbb4bf035U, 0x787b03f6U, 0x9e26b810U, + 0x2abf95a4U, 0x8b77fc05U, 0x511948dfU, 0x4ac78dc4U, + 0x08171f86U, 0x6d2a47e3U, 0xff1ee171U, 0xf4d4207aU, + 0x5ed688d0U, 0x2bffd4a5U, 0x6eea84e0U, 0x7efe80f0U, + 0x9a23b914U, 0x19435a97U, 0xe245a76cU, 0x95ec791bU, + 0x8cb23e02U, 0xe640a668U, 0x612544efU, 0x45084dcbU, + 0x297f56a7U, 0x5ad389d4U, 0x7bbbc0f5U, 0x98a33b16U, + 0xab5ff425U, 0x05585d8bU, 0xa750f729U, 0xae1ab420U, + 0xdcf62a52U, 0x7fbec1f1U, 0x49074ec7U, 0x0fd2dd81U, + 0x545c08daU, 0xcf22ed41U, 0x89f77e07U, 0x3c2e12b2U, + 0x59134ad7U, 0x07d8df89U, 0xc1ad6c4fU, 0x44480ccaU, + 0xe305e66dU, 0x9369fa1dU, 0x58530bd6U, 0x9de67b13U, + 0x2e3d139dU, 0x37635484U, 0xd2fe2c61U, 0x8eb53b3dU, + 0x464f09f5U, 0xf2d62441U, 0x817afb32U, 0xabd87318U, + 0x2dfdd09eU, 0xafdd721cU, 0x25f7d296U, 0x7e7907cdU, + 0xd53bee66U, 0x9aa43e29U, 0xc52fea76U, 0x61a2c3d2U, + 0xd934ed6aU, 0xe848a05bU, 0x1f415eacU, 0xac1db11fU, + 0xdd31ec6eU, 0x8ff57a3cU, 0x65a7c2d6U, 0x7a7c06c9U, + 0xdfb16e6cU, 0x64e783d7U, 0x39ecd58aU, 0xed0de05eU, + 0x50de8ee3U, 0x6f2d42dcU, 0x6dadc0deU, 0x134e5da0U, + 0x075f58b4U, 0x7cf985cfU, 0x34a39787U, 0xa6973115U, + 0x33665580U, 0xcae02a79U, 0x174b5ca4U, 0x9c21bd2fU, + 0xb94cf50aU, 0x24b79397U, 0x5994cdeaU, 0x78fc84cbU, + 0xc2ea2871U, 0x4a400af9U, 0xc7af6874U, 0xfc59a54fU, + 0xe6c72155U, 0xbbcc7708U, 0x05dfdab6U, 0xd3be6d60U, + 0x525e0ce1U, 0x559bcee6U, 0xd6fb2d65U, 0x23725190U, + 0x773344c4U, 0x0a101ab9U, 0x27775094U, 0x9ea13f2dU, + 0xa012b213U, 0x4b004bf8U, 0x8970f93aU, 0xef8d625cU, + 0x68e880dbU, 0x69a8c1daU, 0xeb886358U, 0x86bf3935U, + 0xba8c3609U, 0xb80cb40bU, 0x29f8d19aU, 0x9fe17e2cU, + 0x7b3c47c8U, 0x108e9ea3U, 0x857ffa36U, 0x11cedfa2U, + 0xeecd235dU, 0x632241d0U, 0x48c088fbU, 0xd7bb6c64U, + 0xd47baf67U, 0xd874ac6bU, 0x733645c0U, 0xbfc9760cU, + 0xb006b603U, 0xe447a357U, 0x1e011fadU, 0x5b144fe8U, + 0x96ab3d25U, 0xdaf42e69U, 0x4980c9faU, 0x58d48cebU, + 0xb403b707U, 0x2cbd919fU, 0x035a59b0U, 0xa152f312U, + 0x0dd5d8beU, 0xe507e256U, 0x4d85c8feU, 0x0c9599bfU, + 0xf85ca44bU, 0x148b9fa7U, 0x32261481U, 0xff99664cU, + 0xe102e352U, 0xfd19e44eU, 0x843fbb37U, 0x9964fd2aU, + 0x71b6c7c2U, 0xf116e742U, 0x942bbf27U, 0x6b2843d8U, + 0x26371195U, 0x75b3c6c6U, 0x6ced81dfU, 0x28b8909bU, + 0x0b505bb8U, 0x3a2c1689U, 0xe908e15aU, 0x3ca9958fU, + 0x44cf8bf7U, 0xad5df01eU, 0x7db9c4ceU, 0xeac82259U, + 0xf7936444U, 0x666701d5U, 0x565b0de5U, 0x0f555abcU, + 0xdef12f6dU, 0x8bf07b38U, 0x5f114eecU, 0x3e29178dU, + 0x74f387c7U, 0x6a6802d9U, 0x956bfe26U, 0xa3d27110U, + 0xfb9c6748U, 0xaa983219U, 0xbe89370dU, 0x4e450bfdU, + 0x92ae3c21U, 0xf056a643U, 0x21f2d392U, 0xf3966540U, + 0xf6d32545U, 0xcfa56a7cU, 0x009a9ab3U, 0xe7876054U, + 0x1b445fa8U, 0xa557f216U, 0x1dc1dcaeU, 0x20b29293U, + 0xc3aa6970U, 0x3b6c5788U, 0xbd49f40eU, 0xb543f606U, + 0xa2923011U, 0x470f48f4U, 0xb3c67500U, 0xfadc2649U, + 0x01dadbb2U, 0xae9d331dU, 0xfed9274dU, 0xcd25e87eU, + 0x7f3946ccU, 0xec4da15fU, 0x5e510fedU, 0xf453a747U, + 0x767305c5U, 0xd13eef62U, 0xf91ce54aU, 0xdbb46f68U, + 0x418acbf2U, 0x38ac948bU, 0x4cc589ffU, 0xc860a87bU, + 0x22321091U, 0x1a041ea9U, 0xa958f11aU, 0x60e282d3U, + 0x0e151bbdU, 0x82ba3831U, 0x4f054afcU, 0xc920e97aU, + 0x79bcc5caU, 0x8ab03a39U, 0xdc71ad6fU, 0xbc09b50fU, + 0xc06aaa73U, 0xc46fab77U, 0x18849cabU, 0x30a69683U, + 0x430a49f0U, 0x19c4ddaaU, 0xcba06b78U, 0x3f69568cU, + 0x9be47f28U, 0x021a18b1U, 0x87ff7834U, 0x8830b83bU, + 0x31e6d782U, 0x120e1ca1U, 0x049f9bb7U, 0x70f686c3U, + 0x09d0d9baU, 0x35e3d686U, 0x1c819dafU, 0x160b1da5U, + 0x5d91cceeU, 0x727604c1U, 0xb146f702U, 0x571b4ce4U, + 0xe3826150U, 0x424a08f1U, 0x9824bc2bU, 0x83fa7930U, + 0xc12aeb72U, 0xa417b317U, 0x36231585U, 0x3de9d48eU, + 0x97eb7c24U, 0xe2c22051U, 0xa7d77014U, 0xb7c37404U, + 0x531e4de0U, 0xd07eae63U, 0x2b785398U, 0x5cd18defU, + 0x458fcaf6U, 0x2f7d529cU, 0xa818b01bU, 0x8c35b93fU, + 0xe042a253U, 0x93ee7d20U, 0xb2863401U, 0x519ecfe2U, + 0x626200d1U, 0xcc65a97fU, 0x6e6d03ddU, 0x672740d4U, + 0x15cbdea6U, 0xb6833505U, 0x803aba33U, 0xc6ef2975U, + 0x9d61fc2eU, 0x061f19b5U, 0x40ca8af3U, 0xf513e646U, + 0x902ebe23U, 0xcee52b7dU, 0x089098bbU, 0x8d75f83eU, + 0x2a381299U, 0x5a540ee9U, 0x916eff22U, 0x54db8fe7U, + 0x346e5ad4U, 0x2d301dcdU, 0xc8ad6528U, 0x94e67274U, + 0x5c1c40bcU, 0xe8856d08U, 0x9b29b27bU, 0xb18b3a51U, + 0x37ae99d7U, 0xb58e3b55U, 0x3fa49bdfU, 0x642a4e84U, + 0xcf68a72fU, 0x80f77760U, 0xdf7ca33fU, 0x7bf18a9bU, + 0xc367a423U, 0xf21be912U, 0x051217e5U, 0xb64ef856U, + 0xc762a527U, 0x95a63375U, 0x7ff48b9fU, 0x602f4f80U, + 0xc5e22725U, 0x7eb4ca9eU, 0x23bf9cc3U, 0xf75ea917U, + 0x4a8dc7aaU, 0x757e0b95U, 0x77fe8997U, 0x091d14e9U, + 0x1d0c11fdU, 0x66aacc86U, 0x2ef0deceU, 0xbcc4785cU, + 0x29351cc9U, 0xd0b36330U, 0x0d1815edU, 0x8672f466U, + 0xa31fbc43U, 0x3ee4dadeU, 0x43c784a3U, 0x62afcd82U, + 0xd8b96138U, 0x501343b0U, 0xddfc213dU, 0xe60aec06U, + 0xfc94681cU, 0xa19f3e41U, 0x1f8c93ffU, 0xc9ed2429U, + 0x480d45a8U, 0x4fc887afU, 0xcca8642cU, 0x392118d9U, + 0x6d600d8dU, 0x104353f0U, 0x3d2419ddU, 0x84f27664U, + 0xba41fb5aU, 0x515302b1U, 0x9323b073U, 0xf5de2b15U, + 0x72bbc992U, 0x73fb8893U, 0xf1db2a11U, 0x9cec707cU, + 0xa0df7f40U, 0xa25ffd42U, 0x33ab98d3U, 0x85b23765U, + 0x616f0e81U, 0x0addd7eaU, 0x9f2cb37fU, 0x0b9d96ebU, + 0xf49e6a14U, 0x79710899U, 0x5293c1b2U, 0xcde8252dU, + 0xce28e62eU, 0xc227e522U, 0x69650c89U, 0xa59a3f45U, + 0xaa55ff4aU, 0xfe14ea1eU, 0x045256e4U, 0x414706a1U, + 0x8cf8746cU, 0xc0a76720U, 0x53d380b3U, 0x4287c5a2U, + 0xae50fe4eU, 0x36eed8d6U, 0x190910f9U, 0xbb01ba5bU, + 0x178691f7U, 0xff54ab1fU, 0x57d681b7U, 0x16c6d0f6U, + 0xe20fed02U, 0x0ed8d6eeU, 0x28755dc8U, 0xe5ca2f05U, + 0xfb51aa1bU, 0xe74aad07U, 0x9e6cf27eU, 0x8337b463U, + 0x6be58e8bU, 0xeb45ae0bU, 0x8e78f66eU, 0x717b0a91U, + 0x3c6458dcU, 0x6fe08f8fU, 0x76bec896U, 0x32ebd9d2U, + 0x110312f1U, 0x207f5fc0U, 0xf35ba813U, 0x26fadcc6U, + 0x5e9cc2beU, 0xb70eb957U, 0x67ea8d87U, 0xf09b6b10U, + 0xedc02d0dU, 0x7c34489cU, 0x4c0844acU, 0x150613f5U, + 0xc4a26624U, 0x91a33271U, 0x454207a5U, 0x247a5ec4U, + 0x6ea0ce8eU, 0x703b4b90U, 0x8f38b76fU, 0xb9813859U, + 0xe1cf2e01U, 0xb0cb7b50U, 0xa4da7e44U, 0x541642b4U, + 0x88fd7568U, 0xea05ef0aU, 0x3ba19adbU, 0xe9c52c09U, + 0xec806c0cU, 0xd5f62335U, 0x1ac9d3faU, 0xfdd4291dU, + 0x011716e1U, 0xbf04bb5fU, 0x079295e7U, 0x3ae1dbdaU, + 0xd9f92039U, 0x213f1ec1U, 0xa71abd47U, 0xaf10bf4fU, + 0xb8c17958U, 0x5d5c01bdU, 0xa9953c49U, 0xe08f6f00U, + 0x1b8992fbU, 0xb4ce7a54U, 0xe48a6e04U, 0xd776a137U, + 0x656a0f85U, 0xf61ee816U, 0x440246a4U, 0xee00ee0eU, + 0x6c204c8cU, 0xcb6da62bU, 0xe34fac03U, 0xc1e72621U, + 0x5bd982bbU, 0x22ffddc2U, 0x5696c0b6U, 0xd233e132U, + 0x386159d8U, 0x005757e0U, 0xb30bb853U, 0x7ab1cb9aU, + 0x144652f4U, 0x98e97178U, 0x555603b5U, 0xd373a033U, + 0x63ef8c83U, 0x90e37370U, 0xc622e426U, 0xa65afc46U, + 0xda39e33aU, 0xde3ce23eU, 0x02d7d5e2U, 0x2af5dfcaU, + 0x595900b9U, 0x039794e3U, 0xd1f32231U, 0x253a1fc5U, + 0x81b73661U, 0x184951f8U, 0x9dac317dU, 0x9263f172U, + 0x2bb59ecbU, 0x085d55e8U, 0x1eccd2feU, 0x6aa5cf8aU, + 0x138390f3U, 0x2fb09fcfU, 0x06d2d4e6U, 0x0c5854ecU, + 0x47c285a7U, 0x68254d88U, 0xab15be4bU, 0x4d4805adU, + 0xf9d12819U, 0x581941b8U, 0x8277f562U, 0x99a93079U, + 0xdb79a23bU, 0xbe44fa5eU, 0x2c705cccU, 0x27ba9dc7U, + 0x8db8356dU, 0xf8916918U, 0xbd84395dU, 0xad903d4dU, + 0x494d04a9U, 0xca2de72aU, 0x312b1ad1U, 0x4682c4a6U, + 0x5fdc83bfU, 0x352e1bd5U, 0xb24bf952U, 0x9666f076U, + 0xfa11eb1aU, 0x89bd3469U, 0xa8d57d48U, 0x4bcd86abU, + 0x78314998U, 0xd636e036U, 0x743e4a94U, 0x7d74099dU, + 0x0f9897efU, 0xacd07c4cU, 0x9a69f37aU, 0xdcbc603cU, + 0x8732b567U, 0x1c4c50fcU, 0x5a99c3baU, 0xef40af0fU, + 0x8a7df76aU, 0xd4b66234U, 0x12c3d1f2U, 0x9726b177U, + 0x306b5bd0U, 0x400747a0U, 0x8b3db66bU, 0x4e88c6aeU, + 0x3293a12fU, 0x2bcde636U, 0xce509ed3U, 0x921b898fU, + 0x5ae1bb47U, 0xee7896f3U, 0x9dd44980U, 0xb776c1aaU, + 0x3153622cU, 0xb373c0aeU, 0x39596024U, 0x62d7b57fU, + 0xc9955cd4U, 0x860a8c9bU, 0xd98158c4U, 0x7d0c7160U, + 0xc59a5fd8U, 0xf4e612e9U, 0x03efec1eU, 0xb0b303adU, + 0xc19f5edcU, 0x935bc88eU, 0x79097064U, 0x66d2b47bU, + 0xc31fdcdeU, 0x78493165U, 0x25426738U, 0xf1a352ecU, + 0x4c703c51U, 0x7383f06eU, 0x7103726cU, 0x0fe0ef12U, + 0x1bf1ea06U, 0x6057377dU, 0x280d2535U, 0xba3983a7U, + 0x2fc8e732U, 0xd64e98cbU, 0x0be5ee16U, 0x808f0f9dU, + 0xa5e247b8U, 0x38192125U, 0x453a7f58U, 0x64523679U, + 0xde449ac3U, 0x56eeb84bU, 0xdb01dac6U, 0xe0f717fdU, + 0xfa6993e7U, 0xa762c5baU, 0x19716804U, 0xcf10dfd2U, + 0x4ef0be53U, 0x49357c54U, 0xca559fd7U, 0x3fdce322U, + 0x6b9df676U, 0x16bea80bU, 0x3bd9e226U, 0x820f8d9fU, + 0xbcbc00a1U, 0x57aef94aU, 0x95de4b88U, 0xf323d0eeU, + 0x74463269U, 0x75067368U, 0xf726d1eaU, 0x9a118b87U, + 0xa62284bbU, 0xa4a206b9U, 0x35566328U, 0x834fcc9eU, + 0x6792f57aU, 0x0c202c11U, 0x99d14884U, 0x0d606d10U, + 0xf26391efU, 0x7f8cf362U, 0x546e3a49U, 0xcb15ded6U, + 0xc8d51dd5U, 0xc4da1ed9U, 0x6f98f772U, 0xa367c4beU, + 0xaca804b1U, 0xf8e911e5U, 0x02afad1fU, 0x47bafd5aU, + 0x8a058f97U, 0xc65a9cdbU, 0x552e7b48U, 0x447a3e59U, + 0xa8ad05b5U, 0x3013232dU, 0x1ff4eb02U, 0xbdfc41a0U, + 0x117b6a0cU, 0xf9a950e4U, 0x512b7a4cU, 0x103b2b0dU, + 0xe4f216f9U, 0x08252d15U, 0x2e88a633U, 0xe337d4feU, + 0xfdac51e0U, 0xe1b756fcU, 0x98910985U, 0x85ca4f98U, + 0x6d187570U, 0xedb855f0U, 0x88850d95U, 0x7786f16aU, + 0x3a99a327U, 0x691d7474U, 0x7043336dU, 0x34162229U, + 0x17fee90aU, 0x2682a43bU, 0xf5a653e8U, 0x2007273dU, + 0x58613945U, 0xb1f342acU, 0x6117767cU, 0xf66690ebU, + 0xeb3dd6f6U, 0x7ac9b367U, 0x4af5bf57U, 0x13fbe80eU, + 0xc25f9ddfU, 0x975ec98aU, 0x43bffc5eU, 0x2287a53fU, + 0x685d3575U, 0x76c6b06bU, 0x89c54c94U, 0xbf7cc3a2U, + 0xe732d5faU, 0xb63680abU, 0xa22785bfU, 0x52ebb94fU, + 0x8e008e93U, 0xecf814f1U, 0x3d5c6120U, 0xef38d7f2U, + 0xea7d97f7U, 0xd30bd8ceU, 0x1c342801U, 0xfb29d2e6U, + 0x07eaed1aU, 0xb9f940a4U, 0x016f6e1cU, 0x3c1c2021U, + 0xdf04dbc2U, 0x27c2e53aU, 0xa1e746bcU, 0xa9ed44b4U, + 0xbe3c82a3U, 0x5ba1fa46U, 0xaf68c7b2U, 0xe67294fbU, + 0x1d746900U, 0xb23381afU, 0xe27795ffU, 0xd18b5accU, + 0x6397f47eU, 0xf0e313edU, 0x42ffbd5fU, 0xe8fd15f5U, + 0x6addb777U, 0xcd905dd0U, 0xe5b257f8U, 0xc71adddaU, + 0x5d247940U, 0x24022639U, 0x506b3b4dU, 0xd4ce1ac9U, + 0x3e9ca223U, 0x06aaac1bU, 0xb5f643a8U, 0x7c4c3061U, + 0x12bba90fU, 0x9e148a83U, 0x53abf84eU, 0xd58e5bc8U, + 0x65127778U, 0x961e888bU, 0xc0df1fddU, 0xa0a707bdU, + 0xdcc418c1U, 0xd8c119c5U, 0x042a2e19U, 0x2c082431U, + 0x5fa4fb42U, 0x056a6f18U, 0xd70ed9caU, 0x23c7e43eU, + 0x874acd9aU, 0x1eb4aa03U, 0x9b51ca86U, 0x949e0a89U, + 0x2d486530U, 0x0ea0ae13U, 0x18312905U, 0x6c583471U, + 0x157e6b08U, 0x294d6434U, 0x002f2f1dU, 0x0aa5af17U, + 0x413f7e5cU, 0x6ed8b673U, 0xade845b0U, 0x4bb5fe56U, + 0xff2cd3e2U, 0x5ee4ba43U, 0x848a0e99U, 0x9f54cb82U, + 0xdd8459c0U, 0xb8b901a5U, 0x2a8da737U, 0x2147663cU, + 0x8b45ce96U, 0xfe6c92e3U, 0xbb79c2a6U, 0xab6dc6b6U, + 0x4fb0ff52U, 0xccd01cd1U, 0x37d6e12aU, 0x407f3f5dU, + 0x59217844U, 0x33d3e02eU, 0xb4b602a9U, 0x909b0b8dU, + 0xfcec10e1U, 0x8f40cf92U, 0xae2886b3U, 0x4d307d50U, + 0x7eccb263U, 0xd0cb1bcdU, 0x72c3b16fU, 0x7b89f266U, + 0x09656c14U, 0xaa2d87b7U, 0x9c940881U, 0xda419bc7U, + 0x81cf4e9cU, 0x1ab1ab07U, 0x5c643841U, 0xe9bd54f4U, + 0x8c800c91U, 0xd24b99cfU, 0x143e2a09U, 0x91db4a8cU, + 0x3696a02bU, 0x46fabc5bU, 0x8dc04d90U, 0x48753d55U, + 0x757b0e80U, 0x6c254999U, 0x89b8317cU, 0xd5f32620U, + 0x1d0914e8U, 0xa990395cU, 0xda3ce62fU, 0xf09e6e05U, + 0x76bbcd83U, 0xf49b6f01U, 0x7eb1cf8bU, 0x253f1ad0U, + 0x8e7df37bU, 0xc1e22334U, 0x9e69f76bU, 0x3ae4decfU, + 0x8272f077U, 0xb30ebd46U, 0x440743b1U, 0xf75bac02U, + 0x8677f173U, 0xd4b36721U, 0x3ee1dfcbU, 0x213a1bd4U, + 0x84f77371U, 0x3fa19ecaU, 0x62aac897U, 0xb64bfd43U, + 0x0b9893feU, 0x346b5fc1U, 0x36ebddc3U, 0x480840bdU, + 0x5c1945a9U, 0x27bf98d2U, 0x6fe58a9aU, 0xfdd12c08U, + 0x6820489dU, 0x91a63764U, 0x4c0d41b9U, 0xc767a032U, + 0xe20ae817U, 0x7ff18e8aU, 0x02d2d0f7U, 0x23ba99d6U, + 0x99ac356cU, 0x110617e4U, 0x9ce97569U, 0xa71fb852U, + 0xbd813c48U, 0xe08a6a15U, 0x5e99c7abU, 0x88f8707dU, + 0x091811fcU, 0x0eddd3fbU, 0x8dbd3078U, 0x78344c8dU, + 0x2c7559d9U, 0x515607a4U, 0x7c314d89U, 0xc5e72230U, + 0xfb54af0eU, 0x104656e5U, 0xd236e427U, 0xb4cb7f41U, + 0x33ae9dc6U, 0x32eedcc7U, 0xb0ce7e45U, 0xddf92428U, + 0xe1ca2b14U, 0xe34aa916U, 0x72becc87U, 0xc4a76331U, + 0x207a5ad5U, 0x4bc883beU, 0xde39e72bU, 0x4a88c2bfU, + 0xb58b3e40U, 0x38645ccdU, 0x138695e6U, 0x8cfd7179U, + 0x8f3db27aU, 0x8332b176U, 0x287058ddU, 0xe48f6b11U, + 0xeb40ab1eU, 0xbf01be4aU, 0x454702b0U, 0x005252f5U, + 0xcded2038U, 0x81b23374U, 0x12c6d4e7U, 0x039291f6U, + 0xef45aa1aU, 0x77fb8c82U, 0x581c44adU, 0xfa14ee0fU, + 0x5693c5a3U, 0xbe41ff4bU, 0x16c3d5e3U, 0x57d384a2U, + 0xa31ab956U, 0x4fcd82baU, 0x6960099cU, 0xa4df7b51U, + 0xba44fe4fU, 0xa65ff953U, 0xdf79a62aU, 0xc222e037U, + 0x2af0dadfU, 0xaa50fa5fU, 0xcf6da23aU, 0x306e5ec5U, + 0x7d710c88U, 0x2ef5dbdbU, 0x37ab9cc2U, 0x73fe8d86U, + 0x501646a5U, 0x616a0b94U, 0xb24efc47U, 0x67ef8892U, + 0x1f8996eaU, 0xf61bed03U, 0x26ffd9d3U, 0xb18e3f44U, + 0xacd57959U, 0x3d211cc8U, 0x0d1d10f8U, 0x541347a1U, + 0x85b73270U, 0xd0b66625U, 0x045753f1U, 0x656f0a90U, + 0x2fb59adaU, 0x312e1fc4U, 0xce2de33bU, 0xf8946c0dU, + 0xa0da7a55U, 0xf1de2f04U, 0xe5cf2a10U, 0x150316e0U, + 0xc9e8213cU, 0xab10bb5eU, 0x7ab4ce8fU, 0xa8d0785dU, + 0xad953858U, 0x94e37761U, 0x5bdc87aeU, 0xbcc17d49U, + 0x400242b5U, 0xfe11ef0bU, 0x4687c1b3U, 0x7bf48f8eU, + 0x98ec746dU, 0x602a4a95U, 0xe60fe913U, 0xee05eb1bU, + 0xf9d42d0cU, 0x1c4955e9U, 0xe880681dU, 0xa19a3b54U, + 0x5a9cc6afU, 0xf5db2e00U, 0xa59f3a50U, 0x9663f563U, + 0x247f5bd1U, 0xb70bbc42U, 0x051712f0U, 0xaf15ba5aU, + 0x2d3518d8U, 0x8a78f27fU, 0xa25af857U, 0x80f27275U, + 0x1accd6efU, 0x63ea8996U, 0x178394e2U, 0x9326b566U, + 0x79740d8cU, 0x414203b4U, 0xf21eec07U, 0x3ba49fceU, + 0x555306a0U, 0xd9fc252cU, 0x144357e1U, 0x9266f467U, + 0x22fad8d7U, 0xd1f62724U, 0x8737b072U, 0xe74fa812U, + 0x9b2cb76eU, 0x9f29b66aU, 0x43c281b6U, 0x6be08b9eU, + 0x184c54edU, 0x4282c0b7U, 0x90e67665U, 0x642f4b91U, + 0xc0a26235U, 0x595c05acU, 0xdcb96529U, 0xd376a526U, + 0x6aa0ca9fU, 0x494801bcU, 0x5fd986aaU, 0x2bb09bdeU, + 0x5296c4a7U, 0x6ea5cb9bU, 0x47c780b2U, 0x4d4d00b8U, + 0x06d7d1f3U, 0x293019dcU, 0xea00ea1fU, 0x0c5d51f9U, + 0xb8c47c4dU, 0x190c15ecU, 0xc362a136U, 0xd8bc642dU, + 0x9a6cf66fU, 0xff51ae0aU, 0x6d650898U, 0x66afc993U, + 0xccad6139U, 0xb9843d4cU, 0xfc916d09U, 0xec856919U, + 0x085850fdU, 0x8b38b37eU, 0x703e4e85U, 0x079790f2U, + 0x1ec9d7ebU, 0x743b4f81U, 0xf35ead06U, 0xd773a422U, + 0xbb04bf4eU, 0xc8a8603dU, 0xe9c0291cU, 0x0ad8d2ffU, + 0x39241dccU, 0x9723b462U, 0x352b1ec0U, 0x3c615dc9U, + 0x4e8dc3bbU, 0xedc52818U, 0xdb7ca72eU, 0x9da93468U, + 0xc627e133U, 0x5d5904a8U, 0x1b8c97eeU, 0xae55fb5bU, + 0xcb68a33eU, 0x95a33660U, 0x53d685a6U, 0xd633e523U, + 0x717e0f84U, 0x011213f4U, 0xca28e23fU, 0x0f9d92faU, + 0x316f5ed0U, 0x283119c9U, 0xcdac612cU, 0x91e77670U, + 0x591d44b8U, 0xed84690cU, 0x9e28b67fU, 0xb48a3e55U, + 0x32af9dd3U, 0xb08f3f51U, 0x3aa59fdbU, 0x612b4a80U, + 0xca69a32bU, 0x85f67364U, 0xda7da73bU, 0x7ef08e9fU, + 0xc666a027U, 0xf71aed16U, 0x001313e1U, 0xb34ffc52U, + 0xc263a123U, 0x90a73771U, 0x7af58f9bU, 0x652e4b84U, + 0xc0e32321U, 0x7bb5ce9aU, 0x26be98c7U, 0xf25fad13U, + 0x4f8cc3aeU, 0x707f0f91U, 0x72ff8d93U, 0x0c1c10edU, + 0x180d15f9U, 0x63abc882U, 0x2bf1dacaU, 0xb9c57c58U, + 0x2c3418cdU, 0xd5b26734U, 0x081911e9U, 0x8373f062U, + 0xa61eb847U, 0x3be5dedaU, 0x46c680a7U, 0x67aec986U, + 0xddb8653cU, 0x551247b4U, 0xd8fd2539U, 0xe30be802U, + 0xf9956c18U, 0xa49e3a45U, 0x1a8d97fbU, 0xccec202dU, + 0x4d0c41acU, 0x4ac983abU, 0xc9a96028U, 0x3c201cddU, + 0x68610989U, 0x154257f4U, 0x38251dd9U, 0x81f37260U, + 0xbf40ff5eU, 0x545206b5U, 0x9622b477U, 0xf0df2f11U, + 0x77bacd96U, 0x76fa8c97U, 0xf4da2e15U, 0x99ed7478U, + 0xa5de7b44U, 0xa75ef946U, 0x36aa9cd7U, 0x80b33361U, + 0x646e0a85U, 0x0fdcd3eeU, 0x9a2db77bU, 0x0e9c92efU, + 0xf19f6e10U, 0x7c700c9dU, 0x5792c5b6U, 0xc8e92129U, + 0xcb29e22aU, 0xc726e126U, 0x6c64088dU, 0xa09b3b41U, + 0xaf54fb4eU, 0xfb15ee1aU, 0x015352e0U, 0x444602a5U, + 0x89f97068U, 0xc5a66324U, 0x56d284b7U, 0x4786c1a6U, + 0xab51fa4aU, 0x33efdcd2U, 0x1c0814fdU, 0xbe00be5fU, + 0x128795f3U, 0xfa55af1bU, 0x52d785b3U, 0x13c7d4f2U, + 0xe70ee906U, 0x0bd9d2eaU, 0x2d7459ccU, 0xe0cb2b01U, + 0xfe50ae1fU, 0xe24ba903U, 0x9b6df67aU, 0x8636b067U, + 0x6ee48a8fU, 0xee44aa0fU, 0x8b79f26aU, 0x747a0e95U, + 0x39655cd8U, 0x6ae18b8bU, 0x73bfcc92U, 0x37eaddd6U, + 0x140216f5U, 0x257e5bc4U, 0xf65aac17U, 0x23fbd8c2U, + 0x5b9dc6baU, 0xb20fbd53U, 0x62eb8983U, 0xf59a6f14U, + 0xe8c12909U, 0x79354c98U, 0x490940a8U, 0x100717f1U, + 0xc1a36220U, 0x94a23675U, 0x404303a1U, 0x217b5ac0U, + 0x6ba1ca8aU, 0x753a4f94U, 0x8a39b36bU, 0xbc803c5dU, + 0xe4ce2a05U, 0xb5ca7f54U, 0xa1db7a40U, 0x511746b0U, + 0x8dfc716cU, 0xef04eb0eU, 0x3ea09edfU, 0xecc4280dU, + 0xe9816808U, 0xd0f72731U, 0x1fc8d7feU, 0xf8d52d19U, + 0x041612e5U, 0xba05bf5bU, 0x029391e3U, 0x3fe0dfdeU, + 0xdcf8243dU, 0x243e1ac5U, 0xa21bb943U, 0xaa11bb4bU, + 0xbdc07d5cU, 0x585d05b9U, 0xac94384dU, 0xe58e6b04U, + 0x1e8896ffU, 0xb1cf7e50U, 0xe18b6a00U, 0xd277a533U, + 0x606b0b81U, 0xf31fec12U, 0x410342a0U, 0xeb01ea0aU, + 0x69214888U, 0xce6ca22fU, 0xe64ea807U, 0xc4e62225U, + 0x5ed886bfU, 0x27fed9c6U, 0x5397c4b2U, 0xd732e536U, + 0x3d605ddcU, 0x055653e4U, 0xb60abc57U, 0x7fb0cf9eU, + 0x114756f0U, 0x9de8757cU, 0x505707b1U, 0xd672a437U, + 0x66ee8887U, 0x95e27774U, 0xc323e022U, 0xa35bf842U, + 0xdf38e73eU, 0xdb3de63aU, 0x07d6d1e6U, 0x2ff4dbceU, + 0x5c5804bdU, 0x069690e7U, 0xd4f22635U, 0x203b1bc1U, + 0x84b63265U, 0x1d4855fcU, 0x98ad3579U, 0x9762f576U, + 0x2eb49acfU, 0x0d5c51ecU, 0x1bcdd6faU, 0x6fa4cb8eU, + 0x168294f7U, 0x2ab19bcbU, 0x03d3d0e2U, 0x095950e8U, + 0x42c381a3U, 0x6d24498cU, 0xae14ba4fU, 0x484901a9U, + 0xfcd02c1dU, 0x5d1845bcU, 0x8776f166U, 0x9ca8347dU, + 0xde78a63fU, 0xbb45fe5aU, 0x297158c8U, 0x22bb99c3U, + 0x88b93169U, 0xfd906d1cU, 0xb8853d59U, 0xa8913949U, + 0x4c4c00adU, 0xcf2ce32eU, 0x342a1ed5U, 0x4383c0a2U, + 0x5add87bbU, 0x302f1fd1U, 0xb74afd56U, 0x9367f472U, + 0xff10ef1eU, 0x8cbc306dU, 0xadd4794cU, 0x4ecc82afU, + 0x7d304d9cU, 0xd337e432U, 0x713f4e90U, 0x78750d99U, + 0x0a9993ebU, 0xa9d17848U, 0x9f68f77eU, 0xd9bd6438U, + 0x8233b163U, 0x194d54f8U, 0x5f98c7beU, 0xea41ab0bU, + 0x8f7cf36eU, 0xd1b76630U, 0x17c2d5f6U, 0x9227b573U, + 0x356a5fd4U, 0x450643a4U, 0x8e3cb26fU, 0x4b89c2aaU, + 0xcda06de3U, 0xd4fe2afaU, 0x3163521fU, 0x6d284543U, + 0xa5d2778bU, 0x114b5a3fU, 0x62e7854cU, 0x48450d66U, + 0xce60aee0U, 0x4c400c62U, 0xc66aace8U, 0x9de479b3U, + 0x36a69018U, 0x79394057U, 0x26b29408U, 0x823fbdacU, + 0x3aa99314U, 0x0bd5de25U, 0xfcdc20d2U, 0x4f80cf61U, + 0x3eac9210U, 0x6c680442U, 0x863abca8U, 0x99e178b7U, + 0x3c2c1012U, 0x877afda9U, 0xda71abf4U, 0x0e909e20U, + 0xb343f09dU, 0x8cb03ca2U, 0x8e30bea0U, 0xf0d323deU, + 0xe4c226caU, 0x9f64fbb1U, 0xd73ee9f9U, 0x450a4f6bU, + 0xd0fb2bfeU, 0x297d5407U, 0xf4d622daU, 0x7fbcc351U, + 0x5ad18b74U, 0xc72aede9U, 0xba09b394U, 0x9b61fab5U, + 0x2177560fU, 0xa9dd7487U, 0x2432160aU, 0x1fc4db31U, + 0x055a5f2bU, 0x58510976U, 0xe642a4c8U, 0x3023131eU, + 0xb1c3729fU, 0xb606b098U, 0x3566531bU, 0xc0ef2feeU, + 0x94ae3abaU, 0xe98d64c7U, 0xc4ea2eeaU, 0x7d3c4153U, + 0x438fcc6dU, 0xa89d3586U, 0x6aed8744U, 0x0c101c22U, + 0x8b75fea5U, 0x8a35bfa4U, 0x08151d26U, 0x6522474bU, + 0x59114877U, 0x5b91ca75U, 0xca65afe4U, 0x7c7c0052U, + 0x98a139b6U, 0xf313e0ddU, 0x66e28448U, 0xf253a1dcU, + 0x0d505d23U, 0x80bf3faeU, 0xab5df685U, 0x3426121aU, + 0x37e6d119U, 0x3be9d215U, 0x90ab3bbeU, 0x5c540872U, + 0x539bc87dU, 0x07dadd29U, 0xfd9c61d3U, 0xb8893196U, + 0x7536435bU, 0x39695017U, 0xaa1db784U, 0xbb49f295U, + 0x579ec979U, 0xcf20efe1U, 0xe0c727ceU, 0x42cf8d6cU, + 0xee48a6c0U, 0x069a9c28U, 0xae18b680U, 0xef08e7c1U, + 0x1bc1da35U, 0xf716e1d9U, 0xd1bb6affU, 0x1c041832U, + 0x029f9d2cU, 0x1e849a30U, 0x67a2c549U, 0x7af98354U, + 0x922bb9bcU, 0x128b993cU, 0x77b6c159U, 0x88b53da6U, + 0xc5aa6febU, 0x962eb8b8U, 0x8f70ffa1U, 0xcb25eee5U, + 0xe8cd25c6U, 0xd9b168f7U, 0x0a959f24U, 0xdf34ebf1U, + 0xa752f589U, 0x4ec08e60U, 0x9e24bab0U, 0x09555c27U, + 0x140e1a3aU, 0x85fa7fabU, 0xb5c6739bU, 0xecc824c2U, + 0x3d6c5113U, 0x686d0546U, 0xbc8c3092U, 0xddb469f3U, + 0x976ef9b9U, 0x89f57ca7U, 0x76f68058U, 0x404f0f6eU, + 0x18011936U, 0x49054c67U, 0x5d144973U, 0xadd87583U, + 0x7133425fU, 0x13cbd83dU, 0xc26fadecU, 0x100b1b3eU, + 0x154e5b3bU, 0x2c381402U, 0xe307e4cdU, 0x041a1e2aU, + 0xf8d921d6U, 0x46ca8c68U, 0xfe5ca2d0U, 0xc32fecedU, + 0x2037170eU, 0xd8f129f6U, 0x5ed48a70U, 0x56de8878U, + 0x410f4e6fU, 0xa492368aU, 0x505b0b7eU, 0x19415837U, + 0xe247a5ccU, 0x4d004d63U, 0x1d445933U, 0x2eb89600U, + 0x9ca438b2U, 0x0fd0df21U, 0xbdcc7193U, 0x17ced939U, + 0x95ee7bbbU, 0x32a3911cU, 0x1a819b34U, 0x38291116U, + 0xa217b58cU, 0xdb31eaf5U, 0xaf58f781U, 0x2bfdd605U, + 0xc1af6eefU, 0xf99960d7U, 0x4ac58f64U, 0x837ffcadU, + 0xed8865c3U, 0x6127464fU, 0xac983482U, 0x2abd9704U, + 0x9a21bbb4U, 0x692d4447U, 0x3fecd311U, 0x5f94cb71U, + 0x23f7d40dU, 0x27f2d509U, 0xfb19e2d5U, 0xd33be8fdU, + 0xa097378eU, 0xfa59a3d4U, 0x283d1506U, 0xdcf428f2U, + 0x78790156U, 0xe18766cfU, 0x6462064aU, 0x6badc645U, + 0xd27ba9fcU, 0xf19362dfU, 0xe702e5c9U, 0x936bf8bdU, + 0xea4da7c4U, 0xd67ea8f8U, 0xff1ce3d1U, 0xf59663dbU, + 0xbe0cb290U, 0x91eb7abfU, 0x52db897cU, 0xb486329aU, + 0x001f1f2eU, 0xa1d7768fU, 0x7bb9c255U, 0x6067074eU, + 0x22b7950cU, 0x478acd69U, 0xd5be6bfbU, 0xde74aaf0U, + 0x7476025aU, 0x015f5e2fU, 0x444a0e6aU, 0x545e0a7aU, + 0xb083339eU, 0x33e3d01dU, 0xc8e52de6U, 0xbf4cf391U, + 0xa612b488U, 0xcce02ce2U, 0x4b85ce65U, 0x6fa8c741U, + 0x03dfdc2dU, 0x7073035eU, 0x511b4a7fU, 0xb203b19cU, + 0x81ff7eafU, 0x2ff8d701U, 0x8df07da3U, 0x84ba3eaaU, + 0xf656a0d8U, 0x551e4b7bU, 0x63a7c44dU, 0x2572570bU, + 0x7efc8250U, 0xe58267cbU, 0xa357f48dU, 0x168e9838U, + 0x73b3c05dU, 0x2d785503U, 0xeb0de6c5U, 0x6ee88640U, + 0xc9a56ce7U, 0xb9c97097U, 0x72f3815cU, 0xb746f199U, + 0xd10edf51U, 0xc8509848U, 0x2dcde0adU, 0x7186f7f1U, + 0xb97cc539U, 0x0de5e88dU, 0x7e4937feU, 0x54ebbfd4U, + 0xd2ce1c52U, 0x50eebed0U, 0xdac41e5aU, 0x814acb01U, + 0x2a0822aaU, 0x6597f2e5U, 0x3a1c26baU, 0x9e910f1eU, + 0x260721a6U, 0x177b6c97U, 0xe0729260U, 0x532e7dd3U, + 0x220220a2U, 0x70c6b6f0U, 0x9a940e1aU, 0x854fca05U, + 0x2082a2a0U, 0x9bd44f1bU, 0xc6df1946U, 0x123e2c92U, + 0xafed422fU, 0x901e8e10U, 0x929e0c12U, 0xec7d916cU, + 0xf86c9478U, 0x83ca4903U, 0xcb905b4bU, 0x59a4fdd9U, + 0xcc55994cU, 0x35d3e6b5U, 0xe8789068U, 0x631271e3U, + 0x467f39c6U, 0xdb845f5bU, 0xa6a70126U, 0x87cf4807U, + 0x3dd9e4bdU, 0xb573c635U, 0x389ca4b8U, 0x036a6983U, + 0x19f4ed99U, 0x44ffbbc4U, 0xfaec167aU, 0x2c8da1acU, + 0xad6dc02dU, 0xaaa8022aU, 0x29c8e1a9U, 0xdc419d5cU, + 0x88008808U, 0xf523d675U, 0xd8449c58U, 0x6192f3e1U, + 0x5f217edfU, 0xb4338734U, 0x764335f6U, 0x10beae90U, + 0x97db4c17U, 0x969b0d16U, 0x14bbaf94U, 0x798cf5f9U, + 0x45bffac5U, 0x473f78c7U, 0xd6cb1d56U, 0x60d2b2e0U, + 0x840f8b04U, 0xefbd526fU, 0x7a4c36faU, 0xeefd136eU, + 0x11feef91U, 0x9c118d1cU, 0xb7f34437U, 0x2888a0a8U, + 0x2b4863abU, 0x274760a7U, 0x8c05890cU, 0x40fabac0U, + 0x4f357acfU, 0x1b746f9bU, 0xe132d361U, 0xa4278324U, + 0x6998f1e9U, 0x25c7e2a5U, 0xb6b30536U, 0xa7e74027U, + 0x4b307bcbU, 0xd38e5d53U, 0xfc69957cU, 0x5e613fdeU, + 0xf2e61472U, 0x1a342e9aU, 0xb2b60432U, 0xf3a65573U, + 0x076f6887U, 0xebb8536bU, 0xcd15d84dU, 0x00aaaa80U, + 0x1e312f9eU, 0x022a2882U, 0x7b0c77fbU, 0x665731e6U, + 0x8e850b0eU, 0x0e252b8eU, 0x6b1873ebU, 0x941b8f14U, + 0xd904dd59U, 0x8a800a0aU, 0x93de4d13U, 0xd78b5c57U, + 0xf4639774U, 0xc51fda45U, 0x163b2d96U, 0xc39a5943U, + 0xbbfc473bU, 0x526e3cd2U, 0x828a0802U, 0x15fbee95U, + 0x08a0a888U, 0x9954cd19U, 0xa968c129U, 0xf0669670U, + 0x21c2e3a1U, 0x74c3b7f4U, 0xa0228220U, 0xc11adb41U, + 0x8bc04b0bU, 0x955bce15U, 0x6a5832eaU, 0x5ce1bddcU, + 0x04afab84U, 0x55abfed5U, 0x41bafbc1U, 0xb176c731U, + 0x6d9df0edU, 0x0f656a8fU, 0xdec11f5eU, 0x0ca5a98cU, + 0x09e0e989U, 0x3096a6b0U, 0xffa9567fU, 0x18b4ac98U, + 0xe4779364U, 0x5a643edaU, 0xe2f21062U, 0xdf815e5fU, + 0x3c99a5bcU, 0xc45f9b44U, 0x427a38c2U, 0x4a703acaU, + 0x5da1fcddU, 0xb83c8438U, 0x4cf5b9ccU, 0x05efea85U, + 0xfee9177eU, 0x51aeffd1U, 0x01eaeb81U, 0x321624b2U, + 0x800a8a00U, 0x137e6d93U, 0xa162c321U, 0x0b606b8bU, + 0x8940c909U, 0x2e0d23aeU, 0x062f2986U, 0x2487a3a4U, + 0xbeb9073eU, 0xc79f5847U, 0xb3f64533U, 0x375364b7U, + 0xdd01dc5dU, 0xe537d265U, 0x566b3dd6U, 0x9fd14e1fU, + 0xf126d771U, 0x7d89f4fdU, 0xb0368630U, 0x361325b6U, + 0x868f0906U, 0x7583f6f5U, 0x234261a3U, 0x433a79c3U, + 0x3f5966bfU, 0x3b5c67bbU, 0xe7b75067U, 0xcf955a4fU, + 0xbc39853cU, 0xe6f71166U, 0x3493a7b4U, 0xc05a9a40U, + 0x64d7b3e4U, 0xfd29d47dU, 0x78ccb4f8U, 0x770374f7U, + 0xced51b4eU, 0xed3dd06dU, 0xfbac577bU, 0x8fc54a0fU, + 0xf6e31576U, 0xcad01a4aU, 0xe3b25163U, 0xe938d169U, + 0xa2a20022U, 0x8d45c80dU, 0x4e753bceU, 0xa8288028U, + 0x1cb1ad9cU, 0xbd79c43dU, 0x671770e7U, 0x7cc9b5fcU, + 0x3e1927beU, 0x5b247fdbU, 0xc910d949U, 0xc2da1842U, + 0x68d8b0e8U, 0x1df1ec9dU, 0x58e4bcd8U, 0x48f0b8c8U, + 0xac2d812cU, 0x2f4d62afU, 0xd44b9f54U, 0xa3e24123U, + 0xbabc063aU, 0xd04e9e50U, 0x572b7cd7U, 0x730675f3U, + 0x1f716e9fU, 0x6cddb1ecU, 0x4db5f8cdU, 0xaead032eU, + 0x9d51cc1dU, 0x335665b3U, 0x915ecf11U, 0x98148c18U, + 0xeaf8126aU, 0x49b0f9c9U, 0x7f0976ffU, 0x39dce5b9U, + 0x625230e2U, 0xf92cd579U, 0xbff9463fU, 0x0a202a8aU, + 0x6f1d72efU, 0x31d6e7b1U, 0xf7a35477U, 0x724634f2U, + 0xd50bde55U, 0xa567c225U, 0x6e5d33eeU, 0xabe8432bU, + 0xa5e94cc2U, 0xbcb70bdbU, 0x592a733eU, 0x05616462U, + 0xcd9b56aaU, 0x79027b1eU, 0x0aaea46dU, 0x200c2c47U, + 0xa6298fc1U, 0x24092d43U, 0xae238dc9U, 0xf5ad5892U, + 0x5eefb139U, 0x11706176U, 0x4efbb529U, 0xea769c8dU, + 0x52e0b235U, 0x639cff04U, 0x949501f3U, 0x27c9ee40U, + 0x56e5b331U, 0x04212563U, 0xee739d89U, 0xf1a85996U, + 0x54653133U, 0xef33dc88U, 0xb2388ad5U, 0x66d9bf01U, + 0xdb0ad1bcU, 0xe4f91d83U, 0xe6799f81U, 0x989a02ffU, + 0x8c8b07ebU, 0xf72dda90U, 0xbf77c8d8U, 0x2d436e4aU, + 0xb8b20adfU, 0x41347526U, 0x9c9f03fbU, 0x17f5e270U, + 0x3298aa55U, 0xaf63ccc8U, 0xd24092b5U, 0xf328db94U, + 0x493e772eU, 0xc19455a6U, 0x4c7b372bU, 0x778dfa10U, + 0x6d137e0aU, 0x30182857U, 0x8e0b85e9U, 0x586a323fU, + 0xd98a53beU, 0xde4f91b9U, 0x5d2f723aU, 0xa8a60ecfU, + 0xfce71b9bU, 0x81c445e6U, 0xaca30fcbU, 0x15756072U, + 0x2bc6ed4cU, 0xc0d414a7U, 0x02a4a665U, 0x64593d03U, + 0xe33cdf84U, 0xe27c9e85U, 0x605c3c07U, 0x0d6b666aU, + 0x31586956U, 0x33d8eb54U, 0xa22c8ec5U, 0x14352173U, + 0xf0e81897U, 0x9b5ac1fcU, 0x0eaba569U, 0x9a1a80fdU, + 0x65197c02U, 0xe8f61e8fU, 0xc314d7a4U, 0x5c6f333bU, + 0x5faff038U, 0x53a0f334U, 0xf8e21a9fU, 0x341d2953U, + 0x3bd2e95cU, 0x6f93fc08U, 0x95d540f2U, 0xd0c010b7U, + 0x1d7f627aU, 0x51207136U, 0xc25496a5U, 0xd300d3b4U, + 0x3fd7e858U, 0xa769cec0U, 0x888e06efU, 0x2a86ac4dU, + 0x860187e1U, 0x6ed3bd09U, 0xc65197a1U, 0x8741c6e0U, + 0x7388fb14U, 0x9f5fc0f8U, 0xb9f24bdeU, 0x744d3913U, + 0x6ad6bc0dU, 0x76cdbb11U, 0x0febe468U, 0x12b0a275U, + 0xfa62989dU, 0x7ac2b81dU, 0x1fffe078U, 0xe0fc1c87U, + 0xade34ecaU, 0xfe679999U, 0xe739de80U, 0xa36ccfc4U, + 0x808404e7U, 0xb1f849d6U, 0x62dcbe05U, 0xb77dcad0U, + 0xcf1bd4a8U, 0x2689af41U, 0xf66d9b91U, 0x611c7d06U, + 0x7c473b1bU, 0xedb35e8aU, 0xdd8f52baU, 0x848105e3U, + 0x55257032U, 0x00242467U, 0xd4c511b3U, 0xb5fd48d2U, + 0xff27d898U, 0xe1bc5d86U, 0x1ebfa179U, 0x28062e4fU, + 0x70483817U, 0x214c6d46U, 0x355d6852U, 0xc59154a2U, + 0x197a637eU, 0x7b82f91cU, 0xaa268ccdU, 0x78423a1fU, + 0x7d077a1aU, 0x44713523U, 0x8b4ec5ecU, 0x6c533f0bU, + 0x909000f7U, 0x2e83ad49U, 0x961583f1U, 0xab66cdccU, + 0x487e362fU, 0xb0b808d7U, 0x369dab51U, 0x3e97a959U, + 0x29466f4eU, 0xccdb17abU, 0x38122a5fU, 0x71087916U, + 0x8a0e84edU, 0x25496c42U, 0x750d7812U, 0x46f1b721U, + 0xf4ed1993U, 0x6799fe00U, 0xd58550b2U, 0x7f87f818U, + 0xfda75a9aU, 0x5aeab03dU, 0x72c8ba15U, 0x50603037U, + 0xca5e94adU, 0xb378cbd4U, 0xc711d6a0U, 0x43b4f724U, + 0xa9e64fceU, 0x91d041f6U, 0x228cae45U, 0xeb36dd8cU, + 0x85c144e2U, 0x096e676eU, 0xc4d115a3U, 0x42f4b625U, + 0xf2689a95U, 0x01646566U, 0x57a5f230U, 0x37ddea50U, + 0x4bbef52cU, 0x4fbbf428U, 0x9350c3f4U, 0xbb72c9dcU, + 0xc8de16afU, 0x921082f5U, 0x40743427U, 0xb4bd09d3U, + 0x10302077U, 0x89ce47eeU, 0x0c2b276bU, 0x03e4e764U, + 0xba3288ddU, 0x99da43feU, 0x8f4bc4e8U, 0xfb22d99cU, + 0x820486e5U, 0xbe3789d9U, 0x9755c2f0U, 0x9ddf42faU, + 0xd64593b1U, 0xf9a25b9eU, 0x3a92a85dU, 0xdccf13bbU, + 0x68563e0fU, 0xc99e57aeU, 0x13f0e374U, 0x082e266fU, + 0x4afeb42dU, 0x2fc3ec48U, 0xbdf74adaU, 0xb63d8bd1U, + 0x1c3f237bU, 0x69167f0eU, 0x2c032f4bU, 0x3c172b5bU, + 0xd8ca12bfU, 0x5baaf13cU, 0xa0ac0cc7U, 0xd705d2b0U, + 0xce5b95a9U, 0xa4a90dc3U, 0x23ccef44U, 0x07e1e660U, + 0x6b96fd0cU, 0x183a227fU, 0x39526b5eU, 0xda4a90bdU, + 0xe9b65f8eU, 0x47b1f620U, 0xe5b95c82U, 0xecf31f8bU, + 0x9e1f81f9U, 0x3d576a5aU, 0x0beee56cU, 0x4d3b762aU, + 0x16b5a371U, 0x8dcb46eaU, 0xcb1ed5acU, 0x7ec7b919U, + 0x1bfae17cU, 0x45317422U, 0x8344c7e4U, 0x06a1a761U, + 0xa1ec4dc6U, 0xd18051b6U, 0x1abaa07dU, 0xdf0fd0b8U, + 0xb947fe70U, 0xa019b969U, 0x4584c18cU, 0x19cfd6d0U, + 0xd135e418U, 0x65acc9acU, 0x160016dfU, 0x3ca29ef5U, + 0xba873d73U, 0x38a79ff1U, 0xb28d3f7bU, 0xe903ea20U, + 0x4241038bU, 0x0dded3c4U, 0x5255079bU, 0xf6d82e3fU, + 0x4e4e0087U, 0x7f324db6U, 0x883bb341U, 0x3b675cf2U, + 0x4a4b0183U, 0x188f97d1U, 0xf2dd2f3bU, 0xed06eb24U, + 0x48cb8381U, 0xf39d6e3aU, 0xae963867U, 0x7a770db3U, + 0xc7a4630eU, 0xf857af31U, 0xfad72d33U, 0x8434b04dU, + 0x9025b559U, 0xeb836822U, 0xa3d97a6aU, 0x31eddcf8U, + 0xa41cb86dU, 0x5d9ac794U, 0x8031b149U, 0x0b5b50c2U, + 0x2e3618e7U, 0xb3cd7e7aU, 0xceee2007U, 0xef866926U, + 0x5590c59cU, 0xdd3ae714U, 0x50d58599U, 0x6b2348a2U, + 0x71bdccb8U, 0x2cb69ae5U, 0x92a5375bU, 0x44c4808dU, + 0xc524e10cU, 0xc2e1230bU, 0x4181c088U, 0xb408bc7dU, + 0xe049a929U, 0x9d6af754U, 0xb00dbd79U, 0x09dbd2c0U, + 0x37685ffeU, 0xdc7aa615U, 0x1e0a14d7U, 0x78f78fb1U, + 0xff926d36U, 0xfed22c37U, 0x7cf28eb5U, 0x11c5d4d8U, + 0x2df6dbe4U, 0x2f7659e6U, 0xbe823c77U, 0x089b93c1U, + 0xec46aa25U, 0x87f4734eU, 0x120517dbU, 0x86b4324fU, + 0x79b7ceb0U, 0xf458ac3dU, 0xdfba6516U, 0x40c18189U, + 0x4301428aU, 0x4f0e4186U, 0xe44ca82dU, 0x28b39be1U, + 0x277c5beeU, 0x733d4ebaU, 0x897bf240U, 0xcc6ea205U, + 0x01d1d0c8U, 0x4d8ec384U, 0xdefa2417U, 0xcfae6106U, + 0x23795aeaU, 0xbbc77c72U, 0x9420b45dU, 0x36281effU, + 0x9aaf3553U, 0x727d0fbbU, 0xdaff2513U, 0x9bef7452U, + 0x6f2649a6U, 0x83f1724aU, 0xa55cf96cU, 0x68e38ba1U, + 0x76780ebfU, 0x6a6309a3U, 0x134556daU, 0x0e1e10c7U, + 0xe6cc2a2fU, 0x666c0aafU, 0x035152caU, 0xfc52ae35U, + 0xb14dfc78U, 0xe2c92b2bU, 0xfb976c32U, 0xbfc27d76U, + 0x9c2ab655U, 0xad56fb64U, 0x7e720cb7U, 0xabd37862U, + 0xd3b5661aU, 0x3a271df3U, 0xeac32923U, 0x7db2cfb4U, + 0x60e989a9U, 0xf11dec38U, 0xc121e008U, 0x982fb751U, + 0x498bc280U, 0x1c8a96d5U, 0xc86ba301U, 0xa953fa60U, + 0xe3896a2aU, 0xfd12ef34U, 0x021113cbU, 0x34a89cfdU, + 0x6ce68aa5U, 0x3de2dff4U, 0x29f3dae0U, 0xd93fe610U, + 0x05d4d1ccU, 0x672c4baeU, 0xb6883e7fU, 0x64ec88adU, + 0x61a9c8a8U, 0x58df8791U, 0x97e0775eU, 0x70fd8db9U, + 0x8c3eb245U, 0x322d1ffbU, 0x8abb3143U, 0xb7c87f7eU, + 0x54d0849dU, 0xac16ba65U, 0x2a3319e3U, 0x22391bebU, + 0x35e8ddfcU, 0xd075a519U, 0x24bc98edU, 0x6da6cba4U, + 0x96a0365fU, 0x39e7def0U, 0x69a3caa0U, 0x5a5f0593U, + 0xe843ab21U, 0x7b374cb2U, 0xc92be200U, 0x63294aaaU, + 0xe109e828U, 0x4644028fU, 0x6e6608a7U, 0x4cce8285U, + 0xd6f0261fU, 0xafd67966U, 0xdbbf6412U, 0x5f1a4596U, + 0xb548fd7cU, 0x8d7ef344U, 0x3e221cf7U, 0xf7986f3eU, + 0x996ff650U, 0x15c0d5dcU, 0xd87fa711U, 0x5e5a0497U, + 0xeec62827U, 0x1dcad7d4U, 0x4b0b4082U, 0x2b7358e2U, + 0x5710479eU, 0x5315469aU, 0x8ffe7146U, 0xa7dc7b6eU, + 0xd470a41dU, 0x8ebe3047U, 0x5cda8695U, 0xa813bb61U, + 0x0c9e92c5U, 0x9560f55cU, 0x108595d9U, 0x1f4a55d6U, + 0xa69c3a6fU, 0x8574f14cU, 0x93e5765aU, 0xe78c6b2eU, + 0x9eaa3457U, 0xa2993b6bU, 0x8bfb7042U, 0x8171f048U, + 0xcaeb2103U, 0xe50ce92cU, 0x263c1aefU, 0xc061a109U, + 0x74f88cbdU, 0xd530e51cU, 0x0f5e51c6U, 0x148094ddU, + 0x5650069fU, 0x336d5efaU, 0xa159f868U, 0xaa933963U, + 0x009191c9U, 0x75b8cdbcU, 0x30ad9df9U, 0x20b999e9U, + 0xc464a00dU, 0x4704438eU, 0xbc02be75U, 0xcbab6002U, + 0xd2f5271bU, 0xb807bf71U, 0x3f625df6U, 0x1b4f54d2U, + 0x77384fbeU, 0x049490cdU, 0x25fcd9ecU, 0xc6e4220fU, + 0xf518ed3cU, 0x5b1f4492U, 0xf917ee30U, 0xf05dad39U, + 0x82b1334bU, 0x21f9d8e8U, 0x174057deU, 0x5195c498U, + 0x0a1b11c3U, 0x9165f458U, 0xd7b0671eU, 0x62690babU, + 0x075453ceU, 0x599fc690U, 0x9fea7556U, 0x1a0f15d3U, + 0xbd42ff74U, 0xcd2ee304U, 0x061412cfU, 0xc3a1620aU, + 0xbbef54daU, 0xa2b113c3U, 0x472c6b26U, 0x1b677c7aU, + 0xd39d4eb2U, 0x67046306U, 0x14a8bc75U, 0x3e0a345fU, + 0xb82f97d9U, 0x3a0f355bU, 0xb02595d1U, 0xebab408aU, + 0x40e9a921U, 0x0f76796eU, 0x50fdad31U, 0xf4708495U, + 0x4ce6aa2dU, 0x7d9ae71cU, 0x8a9319ebU, 0x39cff658U, + 0x48e3ab29U, 0x1a273d7bU, 0xf0758591U, 0xefae418eU, + 0x4a63292bU, 0xf135c490U, 0xac3e92cdU, 0x78dfa719U, + 0xc50cc9a4U, 0xfaff059bU, 0xf87f8799U, 0x869c1ae7U, + 0x928d1ff3U, 0xe92bc288U, 0xa171d0c0U, 0x33457652U, + 0xa6b412c7U, 0x5f326d3eU, 0x82991be3U, 0x09f3fa68U, + 0x2c9eb24dU, 0xb165d4d0U, 0xcc468aadU, 0xed2ec38cU, + 0x57386f36U, 0xdf924dbeU, 0x527d2f33U, 0x698be208U, + 0x73156612U, 0x2e1e304fU, 0x900d9df1U, 0x466c2a27U, + 0xc78c4ba6U, 0xc04989a1U, 0x43296a22U, 0xb6a016d7U, + 0xe2e10383U, 0x9fc25dfeU, 0xb2a517d3U, 0x0b73786aU, + 0x35c0f554U, 0xded20cbfU, 0x1ca2be7dU, 0x7a5f251bU, + 0xfd3ac79cU, 0xfc7a869dU, 0x7e5a241fU, 0x136d7e72U, + 0x2f5e714eU, 0x2ddef34cU, 0xbc2a96ddU, 0x0a33396bU, + 0xeeee008fU, 0x855cd9e4U, 0x10adbd71U, 0x841c98e5U, + 0x7b1f641aU, 0xf6f00697U, 0xdd12cfbcU, 0x42692b23U, + 0x41a9e820U, 0x4da6eb2cU, 0xe6e40287U, 0x2a1b314bU, + 0x25d4f144U, 0x7195e410U, 0x8bd358eaU, 0xcec608afU, + 0x03797a62U, 0x4f26692eU, 0xdc528ebdU, 0xcd06cbacU, + 0x21d1f040U, 0xb96fd6d8U, 0x96881ef7U, 0x3480b455U, + 0x98079ff9U, 0x70d5a511U, 0xd8578fb9U, 0x9947def8U, + 0x6d8ee30cU, 0x8159d8e0U, 0xa7f453c6U, 0x6a4b210bU, + 0x74d0a415U, 0x68cba309U, 0x11edfc70U, 0x0cb6ba6dU, + 0xe4648085U, 0x64c4a005U, 0x01f9f860U, 0xfefa049fU, + 0xb3e556d2U, 0xe0618181U, 0xf93fc698U, 0xbd6ad7dcU, + 0x9e821cffU, 0xaffe51ceU, 0x7cdaa61dU, 0xa97bd2c8U, + 0xd11dccb0U, 0x388fb759U, 0xe86b8389U, 0x7f1a651eU, + 0x62412303U, 0xf3b54692U, 0xc3894aa2U, 0x9a871dfbU, + 0x4b23682aU, 0x1e223c7fU, 0xcac309abU, 0xabfb50caU, + 0xe121c080U, 0xffba459eU, 0x00b9b961U, 0x36003657U, + 0x6e4e200fU, 0x3f4a755eU, 0x2b5b704aU, 0xdb974cbaU, + 0x077c7b66U, 0x6584e104U, 0xb42094d5U, 0x66442207U, + 0x63016202U, 0x5a772d3bU, 0x9548ddf4U, 0x72552713U, + 0x8e9618efU, 0x3085b551U, 0x88139be9U, 0xb560d5d4U, + 0x56782e37U, 0xaebe10cfU, 0x289bb349U, 0x2091b141U, + 0x37407756U, 0xd2dd0fb3U, 0x26143247U, 0x6f0e610eU, + 0x94089cf5U, 0x3b4f745aU, 0x6b0b600aU, 0x58f7af39U, + 0xeaeb018bU, 0x799fe618U, 0xcb8348aaU, 0x6181e000U, + 0xe3a14282U, 0x44eca825U, 0x6ccea20dU, 0x4e66282fU, + 0xd4588cb5U, 0xad7ed3ccU, 0xd917ceb8U, 0x5db2ef3cU, + 0xb7e057d6U, 0x8fd659eeU, 0x3c8ab65dU, 0xf530c594U, + 0x9bc75cfaU, 0x17687f76U, 0xdad70dbbU, 0x5cf2ae3dU, + 0xec6e828dU, 0x1f627d7eU, 0x49a3ea28U, 0x29dbf248U, + 0x55b8ed34U, 0x51bdec30U, 0x8d56dbecU, 0xa574d1c4U, + 0xd6d80eb7U, 0x8c169aedU, 0x5e722c3fU, 0xaabb11cbU, + 0x0e36386fU, 0x97c85ff6U, 0x122d3f73U, 0x1de2ff7cU, + 0xa43490c5U, 0x87dc5be6U, 0x914ddcf0U, 0xe524c184U, + 0x9c029efdU, 0xa03191c1U, 0x8953dae8U, 0x83d95ae2U, + 0xc8438ba9U, 0xe7a44386U, 0x2494b045U, 0xc2c90ba3U, + 0x76502617U, 0xd7984fb6U, 0x0df6fb6cU, 0x16283e77U, + 0x54f8ac35U, 0x31c5f450U, 0xa3f152c2U, 0xa83b93c9U, + 0x02393b63U, 0x77106716U, 0x32053753U, 0x22113343U, + 0xc6cc0aa7U, 0x45ace924U, 0xbeaa14dfU, 0xc903caa8U, + 0xd05d8db1U, 0xbaaf15dbU, 0x3dcaf75cU, 0x19e7fe78U, + 0x7590e514U, 0x063c3a67U, 0x27547346U, 0xc44c88a5U, + 0xf7b04796U, 0x59b7ee38U, 0xfbbf449aU, 0xf2f50793U, + 0x801999e1U, 0x23517242U, 0x15e8fd74U, 0x533d6e32U, + 0x08b3bb69U, 0x93cd5ef2U, 0xd518cdb4U, 0x60c1a101U, + 0x05fcf964U, 0x5b376c3aU, 0x9d42dffcU, 0x18a7bf79U, + 0xbfea55deU, 0xcf8649aeU, 0x04bcb865U, 0xc109c8a0U, + 0x9b4dd658U, 0x82139141U, 0x678ee9a4U, 0x3bc5fef8U, + 0xf33fcc30U, 0x47a6e184U, 0x340a3ef7U, 0x1ea8b6ddU, + 0x988d155bU, 0x1aadb7d9U, 0x90871753U, 0xcb09c208U, + 0x604b2ba3U, 0x2fd4fbecU, 0x705f2fb3U, 0xd4d20617U, + 0x6c4428afU, 0x5d38659eU, 0xaa319b69U, 0x196d74daU, + 0x684129abU, 0x3a85bff9U, 0xd0d70713U, 0xcf0cc30cU, + 0x6ac1aba9U, 0xd1974612U, 0x8c9c104fU, 0x587d259bU, + 0xe5ae4b26U, 0xda5d8719U, 0xd8dd051bU, 0xa63e9865U, + 0xb22f9d71U, 0xc989400aU, 0x81d35242U, 0x13e7f4d0U, + 0x86169045U, 0x7f90efbcU, 0xa23b9961U, 0x295178eaU, + 0x0c3c30cfU, 0x91c75652U, 0xece4082fU, 0xcd8c410eU, + 0x779aedb4U, 0xff30cf3cU, 0x72dfadb1U, 0x4929608aU, + 0x53b7e490U, 0x0ebcb2cdU, 0xb0af1f73U, 0x66cea8a5U, + 0xe72ec924U, 0xe0eb0b23U, 0x638be8a0U, 0x96029455U, + 0xc2438101U, 0xbf60df7cU, 0x92079551U, 0x2bd1fae8U, + 0x156277d6U, 0xfe708e3dU, 0x3c003cffU, 0x5afda799U, + 0xdd98451eU, 0xdcd8041fU, 0x5ef8a69dU, 0x33cffcf0U, + 0x0ffcf3ccU, 0x0d7c71ceU, 0x9c88145fU, 0x2a91bbe9U, + 0xce4c820dU, 0xa5fe5b66U, 0x300f3ff3U, 0xa4be1a67U, + 0x5bbde698U, 0xd6528415U, 0xfdb04d3eU, 0x62cba9a1U, + 0x610b6aa2U, 0x6d0469aeU, 0xc6468005U, 0x0ab9b3c9U, + 0x057673c6U, 0x51376692U, 0xab71da68U, 0xee648a2dU, + 0x23dbf8e0U, 0x6f84ebacU, 0xfcf00c3fU, 0xeda4492eU, + 0x017372c2U, 0x99cd545aU, 0xb62a9c75U, 0x142236d7U, + 0xb8a51d7bU, 0x50772793U, 0xf8f50d3bU, 0xb9e55c7aU, + 0x4d2c618eU, 0xa1fb5a62U, 0x8756d144U, 0x4ae9a389U, + 0x54722697U, 0x4869218bU, 0x314f7ef2U, 0x2c1438efU, + 0xc4c60207U, 0x44662287U, 0x215b7ae2U, 0xde58861dU, + 0x9347d450U, 0xc0c30303U, 0xd99d441aU, 0x9dc8555eU, + 0xbe209e7dU, 0x8f5cd34cU, 0x5c78249fU, 0x89d9504aU, + 0xf1bf4e32U, 0x182d35dbU, 0xc8c9010bU, 0x5fb8e79cU, + 0x42e3a181U, 0xd317c410U, 0xe32bc820U, 0xba259f79U, + 0x6b81eaa8U, 0x3e80befdU, 0xea618b29U, 0x8b59d248U, + 0xc1834202U, 0xdf18c71cU, 0x201b3be3U, 0x16a2b4d5U, + 0x4eeca28dU, 0x1fe8f7dcU, 0x0bf9f2c8U, 0xfb35ce38U, + 0x27def9e4U, 0x45266386U, 0x94821657U, 0x46e6a085U, + 0x43a3e080U, 0x7ad5afb9U, 0xb5ea5f76U, 0x52f7a591U, + 0xae349a6dU, 0x102737d3U, 0xa8b1196bU, 0x95c25756U, + 0x76daacb5U, 0x8e1c924dU, 0x083931cbU, 0x003333c3U, + 0x17e2f5d4U, 0xf27f8d31U, 0x06b6b0c5U, 0x4face38cU, + 0xb4aa1e77U, 0x1bedf6d8U, 0x4ba9e288U, 0x78552dbbU, + 0xca498309U, 0x593d649aU, 0xeb21ca28U, 0x41236282U, + 0xc303c000U, 0x644e2aa7U, 0x4c6c208fU, 0x6ec4aaadU, + 0xf4fa0e37U, 0x8ddc514eU, 0xf9b54c3aU, 0x7d106dbeU, + 0x9742d554U, 0xaf74db6cU, 0x1c2834dfU, 0xd5924716U, + 0xbb65de78U, 0x37cafdf4U, 0xfa758f39U, 0x7c502cbfU, + 0xcccc000fU, 0x3fc0fffcU, 0x690168aaU, 0x097970caU, + 0x751a6fb6U, 0x711f6eb2U, 0xadf4596eU, 0x85d65346U, + 0xf67a8c35U, 0xacb4186fU, 0x7ed0aebdU, 0x8a199349U, + 0x2e94baedU, 0xb76add74U, 0x328fbdf1U, 0x3d407dfeU, + 0x84961247U, 0xa77ed964U, 0xb1ef5e72U, 0xc5864306U, + 0xbca01c7fU, 0x80931343U, 0xa9f1586aU, 0xa37bd860U, + 0xe8e1092bU, 0xc706c104U, 0x043632c7U, 0xe26b8921U, + 0x56f2a495U, 0xf73acd34U, 0x2d5479eeU, 0x368abcf5U, + 0x745a2eb7U, 0x116776d2U, 0x8353d040U, 0x8899114bU, + 0x229bb9e1U, 0x57b2e594U, 0x12a7b5d1U, 0x02b3b1c1U, + 0xe66e8825U, 0x650e6ba6U, 0x9e08965dU, 0xe9a1482aU, + 0xf0ff0f33U, 0x9a0d9759U, 0x1d6875deU, 0x39457cfaU, + 0x55326796U, 0x269eb8e5U, 0x07f6f1c4U, 0xe4ee0a27U, + 0xd712c514U, 0x79156cbaU, 0xdb1dc618U, 0xd2578511U, + 0xa0bb1b63U, 0x03f3f0c0U, 0x354a7ff6U, 0x739fecb0U, + 0x281139ebU, 0xb36fdc70U, 0xf5ba4f36U, 0x40632383U, + 0x255e7be6U, 0x7b95eeb8U, 0xbde05d7eU, 0x38053dfbU, + 0x9f48d75cU, 0xef24cb2cU, 0x241e3ae7U, 0xe1ab4a22U, + 0xd6a771ffU, 0xcff936e6U, 0x2a644e03U, 0x762f595fU, + 0xbed56b97U, 0x0a4c4623U, 0x79e09950U, 0x5342117aU, + 0xd567b2fcU, 0x5747107eU, 0xdd6db0f4U, 0x86e365afU, + 0x2da18c04U, 0x623e5c4bU, 0x3db58814U, 0x9938a1b0U, + 0x21ae8f08U, 0x10d2c239U, 0xe7db3cceU, 0x5487d37dU, + 0x25ab8e0cU, 0x776f185eU, 0x9d3da0b4U, 0x82e664abU, + 0x272b0c0eU, 0x9c7de1b5U, 0xc176b7e8U, 0x1597823cU, + 0xa844ec81U, 0x97b720beU, 0x9537a2bcU, 0xebd43fc2U, + 0xffc53ad6U, 0x8463e7adU, 0xcc39f5e5U, 0x5e0d5377U, + 0xcbfc37e2U, 0x327a481bU, 0xefd13ec6U, 0x64bbdf4dU, + 0x41d69768U, 0xdc2df1f5U, 0xa10eaf88U, 0x8066e6a9U, + 0x3a704a13U, 0xb2da689bU, 0x3f350a16U, 0x04c3c72dU, + 0x1e5d4337U, 0x4356156aU, 0xfd45b8d4U, 0x2b240f02U, + 0xaac46e83U, 0xad01ac84U, 0x2e614f07U, 0xdbe833f2U, + 0x8fa926a6U, 0xf28a78dbU, 0xdfed32f6U, 0x663b5d4fU, + 0x5888d071U, 0xb39a299aU, 0x71ea9b58U, 0x1717003eU, + 0x9072e2b9U, 0x9132a3b8U, 0x1312013aU, 0x7e255b57U, + 0x4216546bU, 0x4096d669U, 0xd162b3f8U, 0x677b1c4eU, + 0x83a625aaU, 0xe814fcc1U, 0x7de59854U, 0xe954bdc0U, + 0x1657413fU, 0x9bb823b2U, 0xb05aea99U, 0x2f210e06U, + 0x2ce1cd05U, 0x20eece09U, 0x8bac27a2U, 0x4753146eU, + 0x489cd461U, 0x1cddc135U, 0xe69b7dcfU, 0xa38e2d8aU, + 0x6e315f47U, 0x226e4c0bU, 0xb11aab98U, 0xa04eee89U, + 0x4c99d565U, 0xd427f3fdU, 0xfbc03bd2U, 0x59c89170U, + 0xf54fbadcU, 0x1d9d8034U, 0xb51faa9cU, 0xf40ffbddU, + 0x00c6c629U, 0xec11fdc5U, 0xcabc76e3U, 0x0703042eU, + 0x19988130U, 0x0583862cU, 0x7ca5d955U, 0x61fe9f48U, + 0x892ca5a0U, 0x098c8520U, 0x6cb1dd45U, 0x93b221baU, + 0xdead73f7U, 0x8d29a4a4U, 0x9477e3bdU, 0xd022f2f9U, + 0xf3ca39daU, 0xc2b674ebU, 0x11928338U, 0xc433f7edU, + 0xbc55e995U, 0x55c7927cU, 0x8523a6acU, 0x1252403bU, + 0x0f090626U, 0x9efd63b7U, 0xaec16f87U, 0xf7cf38deU, + 0x266b4d0fU, 0x736a195aU, 0xa78b2c8eU, 0xc6b375efU, + 0x8c69e5a5U, 0x92f260bbU, 0x6df19c44U, 0x5b481372U, + 0x0306052aU, 0x5202507bU, 0x4613556fU, 0xb6df699fU, + 0x6a345e43U, 0x08ccc421U, 0xd968b1f0U, 0x0b0c0722U, + 0x0e494727U, 0x373f081eU, 0xf800f8d1U, 0x1f1d0236U, + 0xe3de3dcaU, 0x5dcd9074U, 0xe55bbeccU, 0xd828f0f1U, + 0x3b300b12U, 0xc3f635eaU, 0x45d3966cU, 0x4dd99464U, + 0x5a085273U, 0xbf952a96U, 0x4b5c1762U, 0x0246442bU, + 0xf940b9d0U, 0x5607517fU, 0x0643452fU, 0x35bf8a1cU, + 0x87a324aeU, 0x14d7c33dU, 0xa6cb6d8fU, 0x0cc9c525U, + 0x8ee967a7U, 0x29a48d00U, 0x01868728U, 0x232e0d0aU, + 0xb910a990U, 0xc036f6e9U, 0xb45feb9dU, 0x30faca19U, + 0xdaa872f3U, 0xe29e7ccbU, 0x51c29378U, 0x9878e0b1U, + 0xf68f79dfU, 0x7a205a53U, 0xb79f289eU, 0x31ba8b18U, + 0x8126a7a8U, 0x722a585bU, 0x24ebcf0dU, 0x4493d76dU, + 0x38f0c811U, 0x3cf5c915U, 0xe01efec9U, 0xc83cf4e1U, + 0xbb902b92U, 0xe15ebfc8U, 0x333a091aU, 0xc7f334eeU, + 0x637e1d4aU, 0xfa807ad3U, 0x7f651a56U, 0x70aada59U, + 0xc97cb5e0U, 0xea947ec3U, 0xfc05f9d5U, 0x886ce4a1U, + 0xf14abbd8U, 0xcd79b4e4U, 0xe41bffcdU, 0xee917fc7U, + 0xa50bae8cU, 0x8aec66a3U, 0x49dc9560U, 0xaf812e86U, + 0x1b180332U, 0xbad06a93U, 0x60bede49U, 0x7b601b52U, + 0x39b08910U, 0x5c8dd175U, 0xceb977e7U, 0xc573b6ecU, + 0x6f711e46U, 0x1a584233U, 0x5f4d1276U, 0x4f591666U, + 0xab842f82U, 0x28e4cc01U, 0xd3e231faU, 0xa44bef8dU, + 0xbd15a894U, 0xd7e730feU, 0x5082d279U, 0x74afdb5dU, + 0x18d8c031U, 0x6b741f42U, 0x4a1c5663U, 0xa904ad80U, + 0x9af862b3U, 0x34ffcb1dU, 0x96f761bfU, 0x9fbd22b6U, + 0xed51bcc4U, 0x4e195767U, 0x78a0d851U, 0x3e754b17U, + 0x65fb9e4cU, 0xfe857bd7U, 0xb850e891U, 0x0d898424U, + 0x68b4dc41U, 0x367f491fU, 0xf00afad9U, 0x75ef9a5cU, + 0xd2a270fbU, 0xa2ce6c8bU, 0x69f49d40U, 0xac41ed85U, + 0xf4ad59d7U, 0xedf31eceU, 0x086e662bU, 0x54257177U, + 0x9cdf43bfU, 0x28466e0bU, 0x5beab178U, 0x71483952U, + 0xf76d9ad4U, 0x754d3856U, 0xff6798dcU, 0xa4e94d87U, + 0x0faba42cU, 0x40347463U, 0x1fbfa03cU, 0xbb328998U, + 0x03a4a720U, 0x32d8ea11U, 0xc5d114e6U, 0x768dfb55U, + 0x07a1a624U, 0x55653076U, 0xbf37889cU, 0xa0ec4c83U, + 0x05212426U, 0xbe77c99dU, 0xe37c9fc0U, 0x379daa14U, + 0x8a4ec4a9U, 0xb5bd0896U, 0xb73d8a94U, 0xc9de17eaU, + 0xddcf12feU, 0xa669cf85U, 0xee33ddcdU, 0x7c077b5fU, + 0xe9f61fcaU, 0x10706033U, 0xcddb16eeU, 0x46b1f765U, + 0x63dcbf40U, 0xfe27d9ddU, 0x830487a0U, 0xa26cce81U, + 0x187a623bU, 0x90d040b3U, 0x1d3f223eU, 0x26c9ef05U, + 0x3c576b1fU, 0x615c3d42U, 0xdf4f90fcU, 0x092e272aU, + 0x88ce46abU, 0x8f0b84acU, 0x0c6b672fU, 0xf9e21bdaU, + 0xada30e8eU, 0xd08050f3U, 0xfde71adeU, 0x44317567U, + 0x7a82f859U, 0x919001b2U, 0x53e0b370U, 0x351d2816U, + 0xb278ca91U, 0xb3388b90U, 0x31182912U, 0x5c2f737fU, + 0x601c7c43U, 0x629cfe41U, 0xf3689bd0U, 0x45713466U, + 0xa1ac0d82U, 0xca1ed4e9U, 0x5fefb07cU, 0xcb5e95e8U, + 0x345d6917U, 0xb9b20b9aU, 0x9250c2b1U, 0x0d2b262eU, + 0x0eebe52dU, 0x02e4e621U, 0xa9a60f8aU, 0x65593c46U, + 0x6a96fc49U, 0x3ed7e91dU, 0xc49155e7U, 0x818405a2U, + 0x4c3b776fU, 0x00646423U, 0x931083b0U, 0x8244c6a1U, + 0x6e93fd4dU, 0xf62ddbd5U, 0xd9ca13faU, 0x7bc2b958U, + 0xd74592f4U, 0x3f97a81cU, 0x971582b4U, 0xd605d3f5U, + 0x22ccee01U, 0xce1bd5edU, 0xe8b65ecbU, 0x25092c06U, + 0x3b92a918U, 0x2789ae04U, 0x5eaff17dU, 0x43f4b760U, + 0xab268d88U, 0x2b86ad08U, 0x4ebbf56dU, 0xb1b80992U, + 0xfca75bdfU, 0xaf238c8cU, 0xb67dcb95U, 0xf228dad1U, + 0xd1c011f2U, 0xe0bc5cc3U, 0x3398ab10U, 0xe639dfc5U, + 0x9e5fc1bdU, 0x77cdba54U, 0xa7298e84U, 0x30586813U, + 0x2d032e0eU, 0xbcf74b9fU, 0x8ccb47afU, 0xd5c510f6U, + 0x04616527U, 0x51603172U, 0x858104a6U, 0xe4b95dc7U, + 0xae63cd8dU, 0xb0f84893U, 0x4ffbb46cU, 0x79423b5aU, + 0x210c2d02U, 0x70087853U, 0x64197d47U, 0x94d541b7U, + 0x483e766bU, 0x2ac6ec09U, 0xfb6299d8U, 0x29062f0aU, + 0x2c436f0fU, 0x15352036U, 0xda0ad0f9U, 0x3d172a1eU, + 0xc1d415e2U, 0x7fc7b85cU, 0xc75196e4U, 0xfa22d8d9U, + 0x193a233aU, 0xe1fc1dc2U, 0x67d9be44U, 0x6fd3bc4cU, + 0x78027a5bU, 0x9d9f02beU, 0x69563f4aU, 0x204c6c03U, + 0xdb4a91f8U, 0x740d7957U, 0x24496d07U, 0x17b5a234U, + 0xa5a90c86U, 0x36ddeb15U, 0x84c145a7U, 0x2ec3ed0dU, + 0xace34f8fU, 0x0baea528U, 0x238caf00U, 0x01242522U, + 0x9b1a81b8U, 0xe23cdec1U, 0x9655c3b5U, 0x12f0e231U, + 0xf8a25adbU, 0xc09454e3U, 0x73c8bb50U, 0xba72c899U, + 0xd48551f7U, 0x582a727bU, 0x959500b6U, 0x13b0a330U, + 0xa32c8f80U, 0x50207073U, 0x06e1e725U, 0x6699ff45U, + 0x1afae039U, 0x1effe13dU, 0xc214d6e1U, 0xea36dcc9U, + 0x999a03baU, 0xc35497e0U, 0x11302132U, 0xe5f91cc6U, + 0x41743562U, 0xd88a52fbU, 0x5d6f327eU, 0x52a0f271U, + 0xeb769dc8U, 0xc89e56ebU, 0xde0fd1fdU, 0xaa66cc89U, + 0xd34093f0U, 0xef739cccU, 0xc611d7e5U, 0xcc9b57efU, + 0x870186a4U, 0xa8e64e8bU, 0x6bd6bd48U, 0x8d8b06aeU, + 0x39122b1aU, 0x98da42bbU, 0x42b4f661U, 0x596a337aU, + 0x1bbaa138U, 0x7e87f95dU, 0xecb35fcfU, 0xe7799ec4U, + 0x4d7b366eU, 0x38526a1bU, 0x7d473a5eU, 0x6d533e4eU, + 0x898e07aaU, 0x0aeee429U, 0xf1e819d2U, 0x8641c7a5U, + 0x9f1f80bcU, 0xf5ed18d6U, 0x7288fa51U, 0x56a5f375U, + 0x3ad2e819U, 0x497e376aU, 0x68167e4bU, 0x8b0e85a8U, + 0xb8f24a9bU, 0x16f5e335U, 0xb4fd4997U, 0xbdb70a9eU, + 0xcf5b94ecU, 0x6c137f4fU, 0x5aaaf079U, 0x1c7f633fU, + 0x47f1b664U, 0xdc8f53ffU, 0x9a5ac0b9U, 0x2f83ac0cU, + 0x4abef469U, 0x14756137U, 0xd200d2f1U, 0x57e5b274U, + 0xf0a858d3U, 0x80c444a3U, 0x4bfeb568U, 0x8e4bc5adU, + 0x5c277bf5U, 0x45793cecU, 0xa0e44409U, 0xfcaf5355U, + 0x3455619dU, 0x80cc4c29U, 0xf360935aU, 0xd9c21b70U, + 0x5fe7b8f6U, 0xddc71a74U, 0x57edbafeU, 0x0c636fa5U, + 0xa721860eU, 0xe8be5641U, 0xb735821eU, 0x13b8abbaU, + 0xab2e8502U, 0x9a52c833U, 0x6d5b36c4U, 0xde07d977U, + 0xaf2b8406U, 0xfdef1254U, 0x17bdaabeU, 0x08666ea1U, + 0xadab0604U, 0x16fdebbfU, 0x4bf6bde2U, 0x9f178836U, + 0x22c4e68bU, 0x1d372ab4U, 0x1fb7a8b6U, 0x615435c8U, + 0x754530dcU, 0x0ee3eda7U, 0x46b9ffefU, 0xd48d597dU, + 0x417c3de8U, 0xb8fa4211U, 0x655134ccU, 0xee3bd547U, + 0xcb569d62U, 0x56adfbffU, 0x2b8ea582U, 0x0ae6eca3U, + 0xb0f04019U, 0x385a6291U, 0xb5b5001cU, 0x8e43cd27U, + 0x94dd493dU, 0xc9d61f60U, 0x77c5b2deU, 0xa1a40508U, + 0x20446489U, 0x2781a68eU, 0xa4e1450dU, 0x516839f8U, + 0x05292cacU, 0x780a72d1U, 0x556d38fcU, 0xecbb5745U, + 0xd208da7bU, 0x391a2390U, 0xfb6a9152U, 0x9d970a34U, + 0x1af2e8b3U, 0x1bb2a9b2U, 0x99920b30U, 0xf4a5515dU, + 0xc8965e61U, 0xca16dc63U, 0x5be2b9f2U, 0xedfb1644U, + 0x09262fa0U, 0x6294f6cbU, 0xf765925eU, 0x63d4b7caU, + 0x9cd74b35U, 0x113829b8U, 0x3adae093U, 0xa5a1040cU, + 0xa661c70fU, 0xaa6ec403U, 0x012c2da8U, 0xcdd31e64U, + 0xc21cde6bU, 0x965dcb3fU, 0x6c1b77c5U, 0x290e2780U, + 0xe4b1554dU, 0xa8ee4601U, 0x3b9aa192U, 0x2acee483U, + 0xc619df6fU, 0x5ea7f9f7U, 0x714031d8U, 0xd3489b7aU, + 0x7fcfb0d6U, 0x971d8a3eU, 0x3f9fa096U, 0x7e8ff1d7U, + 0x8a46cc23U, 0x6691f7cfU, 0x403c7ce9U, 0x8d830e24U, + 0x93188b3aU, 0x8f038c26U, 0xf625d35fU, 0xeb7e9542U, + 0x03acafaaU, 0x830c8f2aU, 0xe631d74fU, 0x19322bb0U, + 0x542d79fdU, 0x07a9aeaeU, 0x1ef7e9b7U, 0x5aa2f8f3U, + 0x794a33d0U, 0x48367ee1U, 0x9b128932U, 0x4eb3fde7U, + 0x36d5e39fU, 0xdf479876U, 0x0fa3aca6U, 0x98d24a31U, + 0x85890c2cU, 0x147d69bdU, 0x2441658dU, 0x7d4f32d4U, + 0xaceb4705U, 0xf9ea1350U, 0x2d0b2684U, 0x4c337fe5U, + 0x06e9efafU, 0x18726ab1U, 0xe771964eU, 0xd1c81978U, + 0x89860f20U, 0xd8825a71U, 0xcc935f65U, 0x3c5f6395U, + 0xe0b45449U, 0x824cce2bU, 0x53e8bbfaU, 0x818c0d28U, + 0x84c94d2dU, 0xbdbf0214U, 0x7280f2dbU, 0x959d083cU, + 0x695e37c0U, 0xd74d9a7eU, 0x6fdbb4c6U, 0x52a8fafbU, + 0xb1b00118U, 0x49763fe0U, 0xcf539c66U, 0xc7599e6eU, + 0xd0885879U, 0x3515209cU, 0xc1dc1d68U, 0x88c64e21U, + 0x73c0b3daU, 0xdc875b75U, 0x8cc34f25U, 0xbf3f8016U, + 0x0d232ea4U, 0x9e57c937U, 0x2c4b6785U, 0x8649cf2fU, + 0x04696dadU, 0xa324870aU, 0x8b068d22U, 0xa9ae0700U, + 0x3390a39aU, 0x4ab6fce3U, 0x3edfe197U, 0xba7ac013U, + 0x502878f9U, 0x681e76c1U, 0xdb429972U, 0x12f8eabbU, + 0x7c0f73d5U, 0xf0a05059U, 0x3d1f2294U, 0xbb3a8112U, + 0x0ba6ada2U, 0xf8aa5251U, 0xae6bc507U, 0xce13dd67U, + 0xb270c21bU, 0xb675c31fU, 0x6a9ef4c3U, 0x42bcfeebU, + 0x31102198U, 0x6bdeb5c2U, 0xb9ba0310U, 0x4d733ee4U, + 0xe9fe1740U, 0x700070d9U, 0xf5e5105cU, 0xfa2ad053U, + 0x43fcbfeaU, 0x601474c9U, 0x7685f3dfU, 0x02eceeabU, + 0x7bcab1d2U, 0x47f9beeeU, 0x6e9bf5c7U, 0x641175cdU, + 0x2f8ba486U, 0x006c6ca9U, 0xc35c9f6aU, 0x2501248cU, + 0x91980938U, 0x30506099U, 0xea3ed443U, 0xf1e01158U, + 0xb330831aU, 0xd60ddb7fU, 0x44397dedU, 0x4ff3bce6U, + 0xe5f1144cU, 0x90d84839U, 0xd5cd187cU, 0xc5d91c6cU, + 0x21042588U, 0xa264c60bU, 0x59623bf0U, 0x2ecbe587U, + 0x3795a29eU, 0x5d673af4U, 0xda02d873U, 0xfe2fd157U, + 0x9258ca3bU, 0xe1f41548U, 0xc09c5c69U, 0x2384a78aU, + 0x107868b9U, 0xbe7fc117U, 0x1c776bb5U, 0x153d28bcU, + 0x67d1b6ceU, 0xc4995d6dU, 0xf220d25bU, 0xb4f5411dU, + 0xef7b9446U, 0x740571ddU, 0x32d0e29bU, 0x87098e2eU, + 0xe234d64bU, 0xbcff4315U, 0x7a8af0d3U, 0xff6f9056U, + 0x58227af1U, 0x284e6681U, 0xe374974aU, 0x26c1e78fU, + 0x6283e16fU, 0x7bdda676U, 0x9e40de93U, 0xc20bc9cfU, + 0x0af1fb07U, 0xbe68d6b3U, 0xcdc409c0U, 0xe76681eaU, + 0x6143226cU, 0xe36380eeU, 0x69492064U, 0x32c7f53fU, + 0x99851c94U, 0xd61accdbU, 0x89911884U, 0x2d1c3120U, + 0x958a1f98U, 0xa4f652a9U, 0x53ffac5eU, 0xe0a343edU, + 0x918f1e9cU, 0xc34b88ceU, 0x29193024U, 0x36c2f43bU, + 0x930f9c9eU, 0x28597125U, 0x75522778U, 0xa1b312acU, + 0x1c607c11U, 0x2393b02eU, 0x2113322cU, 0x5ff0af52U, + 0x4be1aa46U, 0x3047773dU, 0x781d6575U, 0xea29c3e7U, + 0x7fd8a772U, 0x865ed88bU, 0x5bf5ae56U, 0xd09f4fddU, + 0xf5f207f8U, 0x68096165U, 0x152a3f18U, 0x34427639U, + 0x8e54da83U, 0x06fef80bU, 0x8b119a86U, 0xb0e757bdU, + 0xaa79d3a7U, 0xf77285faU, 0x49612844U, 0x9f009f92U, + 0x1ee0fe13U, 0x19253c14U, 0x9a45df97U, 0x6fcca362U, + 0x3b8db636U, 0x46aee84bU, 0x6bc9a266U, 0xd21fcddfU, + 0xecac40e1U, 0x07beb90aU, 0xc5ce0bc8U, 0xa33390aeU, + 0x24567229U, 0x25163328U, 0xa73691aaU, 0xca01cbc7U, + 0xf632c4fbU, 0xf4b246f9U, 0x65462368U, 0xd35f8cdeU, + 0x3782b53aU, 0x5c306c51U, 0xc9c108c4U, 0x5d702d50U, + 0xa273d1afU, 0x2f9cb322U, 0x047e7a09U, 0x9b059e96U, + 0x98c55d95U, 0x94ca5e99U, 0x3f88b732U, 0xf37784feU, + 0xfcb844f1U, 0xa8f951a5U, 0x52bfed5fU, 0x17aabd1aU, + 0xda15cfd7U, 0x964adc9bU, 0x053e3b08U, 0x146a7e19U, + 0xf8bd45f5U, 0x6003636dU, 0x4fe4ab42U, 0xedec01e0U, + 0x416b2a4cU, 0xa9b910a4U, 0x013b3a0cU, 0x402b6b4dU, + 0xb4e256b9U, 0x58356d55U, 0x7e98e673U, 0xb32794beU, + 0xadbc11a0U, 0xb1a716bcU, 0xc88149c5U, 0xd5da0fd8U, + 0x3d083530U, 0xbda815b0U, 0xd8954dd5U, 0x2796b12aU, + 0x6a89e367U, 0x390d3434U, 0x2053732dU, 0x64066269U, + 0x47eea94aU, 0x7692e47bU, 0xa5b613a8U, 0x7017677dU, + 0x08717905U, 0xe1e302ecU, 0x3107363cU, 0xa676d0abU, + 0xbb2d96b6U, 0x2ad9f327U, 0x1ae5ff17U, 0x43eba84eU, + 0x924fdd9fU, 0xc74e89caU, 0x13afbc1eU, 0x7297e57fU, + 0x384d7535U, 0x26d6f02bU, 0xd9d50cd4U, 0xef6c83e2U, + 0xb72295baU, 0xe626c0ebU, 0xf237c5ffU, 0x02fbf90fU, + 0xde10ced3U, 0xbce854b1U, 0x6d4c2160U, 0xbf2897b2U, + 0xba6dd7b7U, 0x831b988eU, 0x4c246841U, 0xab3992a6U, + 0x57faad5aU, 0xe9e900e4U, 0x517f2e5cU, 0x6c0c6061U, + 0x8f149b82U, 0x77d2a57aU, 0xf1f706fcU, 0xf9fd04f4U, + 0xee2cc2e3U, 0x0bb1ba06U, 0xff7887f2U, 0xb662d4bbU, + 0x4d642940U, 0xe223c1efU, 0xb267d5bfU, 0x819b1a8cU, + 0x3387b43eU, 0xa0f353adU, 0x12effd1fU, 0xb8ed55b5U, + 0x3acdf737U, 0x9d801d90U, 0xb5a217b8U, 0x970a9d9aU, + 0x0d343900U, 0x74126679U, 0x007b7b0dU, 0x84de5a89U, + 0x6e8ce263U, 0x56baec5bU, 0xe5e603e8U, 0x2c5c7021U, + 0x42abe94fU, 0xce04cac3U, 0x03bbb80eU, 0x859e1b88U, + 0x35023738U, 0xc60ec8cbU, 0x90cf5f9dU, 0xf0b747fdU, + 0x8cd45881U, 0x88d15985U, 0x543a6e59U, 0x7c186471U, + 0x0fb4bb02U, 0x557a2f58U, 0x871e998aU, 0x73d7a47eU, + 0xd75a8ddaU, 0x4ea4ea43U, 0xcb418ac6U, 0xc48e4ac9U, + 0x7d582570U, 0x5eb0ee53U, 0x48216945U, 0x3c487431U, + 0x456e2b48U, 0x795d2474U, 0x503f6f5dU, 0x5ab5ef57U, + 0x112f3e1cU, 0x3ec8f633U, 0xfdf805f0U, 0x1ba5be16U, + 0xaf3c93a2U, 0x0ef4fa03U, 0xd49a4ed9U, 0xcf448bc2U, + 0x8d941980U, 0xe8a941e5U, 0x7a9de777U, 0x7157267cU, + 0xdb558ed6U, 0xae7cd2a3U, 0xeb6982e6U, 0xfb7d86f6U, + 0x1fa0bf12U, 0x9cc05c91U, 0x67c6a16aU, 0x106f7f1dU, + 0x09313804U, 0x63c3a06eU, 0xe4a642e9U, 0xc08b4bcdU, + 0xacfc50a1U, 0xdf508fd2U, 0xfe38c6f3U, 0x1d203d10U, + 0x2edcf223U, 0x80db5b8dU, 0x22d3f12fU, 0x2b99b226U, + 0x59752c54U, 0xfa3dc7f7U, 0xcc8448c1U, 0x8a51db87U, + 0xd1df0edcU, 0x4aa1eb47U, 0x0c747801U, 0xb9ad14b4U, + 0xdc904cd1U, 0x825bd98fU, 0x442e6a49U, 0xc1cb0accU, + 0x6686e06bU, 0x16eafc1bU, 0xddd00dd0U, 0x18657d15U, + 0x44dc9816U, 0x5d82df0fU, 0xb81fa7eaU, 0xe454b0b6U, + 0x2cae827eU, 0x9837afcaU, 0xeb9b70b9U, 0xc139f893U, + 0x471c5b15U, 0xc53cf997U, 0x4f16591dU, 0x14988c46U, + 0xbfda65edU, 0xf045b5a2U, 0xafce61fdU, 0x0b434859U, + 0xb3d566e1U, 0x82a92bd0U, 0x75a0d527U, 0xc6fc3a94U, + 0xb7d067e5U, 0xe514f1b7U, 0x0f46495dU, 0x109d8d42U, + 0xb550e5e7U, 0x0e06085cU, 0x530d5e01U, 0x87ec6bd5U, + 0x3a3f0568U, 0x05ccc957U, 0x074c4b55U, 0x79afd62bU, + 0x6dbed33fU, 0x16180e44U, 0x5e421c0cU, 0xcc76ba9eU, + 0x5987de0bU, 0xa001a1f2U, 0x7daad72fU, 0xf6c036a4U, + 0xd3ad7e81U, 0x4e56181cU, 0x33754661U, 0x121d0f40U, + 0xa80ba3faU, 0x20a18172U, 0xad4ee3ffU, 0x96b82ec4U, + 0x8c26aadeU, 0xd12dfc83U, 0x6f3e513dU, 0xb95fe6ebU, + 0x38bf876aU, 0x3f7a456dU, 0xbc1aa6eeU, 0x4993da1bU, + 0x1dd2cf4fU, 0x60f19132U, 0x4d96db1fU, 0xf440b4a6U, + 0xcaf33998U, 0x21e1c073U, 0xe39172b1U, 0x856ce9d7U, + 0x02090b50U, 0x03494a51U, 0x8169e8d3U, 0xec5eb2beU, + 0xd06dbd82U, 0xd2ed3f80U, 0x43195a11U, 0xf500f5a7U, + 0x11ddcc43U, 0x7a6f1528U, 0xef9e71bdU, 0x7b2f5429U, + 0x842ca8d6U, 0x09c3ca5bU, 0x22210370U, 0xbd5ae7efU, + 0xbe9a24ecU, 0xb29527e0U, 0x19d7ce4bU, 0xd528fd87U, + 0xdae73d88U, 0x8ea628dcU, 0x74e09426U, 0x31f5c463U, + 0xfc4ab6aeU, 0xb015a5e2U, 0x23614271U, 0x32350760U, + 0xdee23c8cU, 0x465c1a14U, 0x69bbd23bU, 0xcbb37899U, + 0x67345335U, 0x8fe669ddU, 0x27644375U, 0x66741234U, + 0x92bd2fc0U, 0x7e6a142cU, 0x58c79f0aU, 0x9578edc7U, + 0x8be368d9U, 0x97f86fc5U, 0xeede30bcU, 0xf38576a1U, + 0x1b574c49U, 0x9bf76cc9U, 0xfeca34acU, 0x01c9c853U, + 0x4cd69a1eU, 0x1f524d4dU, 0x060c0a54U, 0x42591b10U, + 0x61b1d033U, 0x50cd9d02U, 0x83e96ad1U, 0x56481e04U, + 0x2e2e007cU, 0xc7bc7b95U, 0x17584f45U, 0x8029a9d2U, + 0x9d72efcfU, 0x0c868a5eU, 0x3cba866eU, 0x65b4d137U, + 0xb410a4e6U, 0xe111f0b3U, 0x35f0c567U, 0x54c89c06U, + 0x1e120c4cU, 0x00898952U, 0xff8a75adU, 0xc933fa9bU, + 0x917decc3U, 0xc079b992U, 0xd468bc86U, 0x24a48076U, + 0xf84fb7aaU, 0x9ab72dc8U, 0x4b135819U, 0x9977eecbU, + 0x9c32aeceU, 0xa544e1f7U, 0x6a7b1138U, 0x8d66ebdfU, + 0x71a5d423U, 0xcfb6799dU, 0x77205725U, 0x4a531918U, + 0xa94be2fbU, 0x518ddc03U, 0xd7a87f85U, 0xdfa27d8dU, + 0xc873bb9aU, 0x2deec37fU, 0xd927fe8bU, 0x903dadc2U, + 0x6b3b5039U, 0xc47cb896U, 0x9438acc6U, 0xa7c463f5U, + 0x15d8cd47U, 0x86ac2ad4U, 0x34b08466U, 0x9eb22cccU, + 0x1c928e4eU, 0xbbdf64e9U, 0x93fd6ec1U, 0xb155e4e3U, + 0x2b6b4079U, 0x524d1f00U, 0x26240274U, 0xa28123f0U, + 0x48d39b1aU, 0x70e59522U, 0xc3b97a91U, 0x0a030958U, + 0x64f49036U, 0xe85bb3baU, 0x25e4c177U, 0xa3c162f1U, + 0x135d4e41U, 0xe051b1b2U, 0xb69026e4U, 0xd6e83e84U, + 0xaa8b21f8U, 0xae8e20fcU, 0x72651720U, 0x5a471d08U, + 0x29ebc27bU, 0x73255621U, 0xa141e0f3U, 0x5588dd07U, + 0xf105f4a3U, 0x68fb933aU, 0xed1ef3bfU, 0xe2d133b0U, + 0x5b075c09U, 0x78ef972aU, 0x6e7e103cU, 0x1a170d48U, + 0x63315231U, 0x5f025d0dU, 0x76601624U, 0x7cea962eU, + 0x37704765U, 0x18978f4aU, 0xdba77c89U, 0x3dfac76fU, + 0x8963eadbU, 0x28ab837aU, 0xf2c537a0U, 0xe91bf2bbU, + 0xabcb60f9U, 0xcef6389cU, 0x5cc29e0eU, 0x57085f05U, + 0xfd0af7afU, 0x8823abdaU, 0xcd36fb9fU, 0xdd22ff8fU, + 0x39ffc66bU, 0xba9f25e8U, 0x4199d813U, 0x36300664U, + 0x2f6e417dU, 0x459cd917U, 0xc2f93b90U, 0xe6d432b4U, + 0x8aa329d8U, 0xf90ff6abU, 0xd867bf8aU, 0x3b7f4469U, + 0x08838b5aU, 0xa68422f4U, 0x048c8856U, 0x0dc6cb5fU, + 0x7f2a552dU, 0xdc62be8eU, 0xeadb31b8U, 0xac0ea2feU, + 0xf78077a5U, 0x6cfe923eU, 0x2a2b0178U, 0x9ff26dcdU, + 0xfacf35a8U, 0xa404a0f6U, 0x62711330U, 0xe79473b5U, + 0x40d99912U, 0x30b58562U, 0xfb8f74a9U, 0x3e3a046cU, + 0x2dc1ec62U, 0x349fab7bU, 0xd102d39eU, 0x8d49c4c2U, + 0x45b3f60aU, 0xf12adbbeU, 0x828604cdU, 0xa8248ce7U, + 0x2e012f61U, 0xac218de3U, 0x260b2d69U, 0x7d85f832U, + 0xd6c71199U, 0x9958c1d6U, 0xc6d31589U, 0x625e3c2dU, + 0xdac81295U, 0xebb45fa4U, 0x1cbda153U, 0xafe14ee0U, + 0xdecd1391U, 0x8c0985c3U, 0x665b3d29U, 0x7980f936U, + 0xdc4d9193U, 0x671b7c28U, 0x3a102a75U, 0xeef11fa1U, + 0x5322711cU, 0x6cd1bd23U, 0x6e513f21U, 0x10b2a25fU, + 0x04a3a74bU, 0x7f057a30U, 0x375f6878U, 0xa56bceeaU, + 0x309aaa7fU, 0xc91cd586U, 0x14b7a35bU, 0x9fdd42d0U, + 0xbab00af5U, 0x274b6c68U, 0x5a683215U, 0x7b007b34U, + 0xc116d78eU, 0x49bcf506U, 0xc453978bU, 0xffa55ab0U, + 0xe53bdeaaU, 0xb83088f7U, 0x06232549U, 0xd042929fU, + 0x51a2f31eU, 0x56673119U, 0xd507d29aU, 0x208eae6fU, + 0x74cfbb3bU, 0x09ece546U, 0x248baf6bU, 0x9d5dc0d2U, + 0xa3ee4decU, 0x48fcb407U, 0x8a8c06c5U, 0xec719da3U, + 0x6b147f24U, 0x6a543e25U, 0xe8749ca7U, 0x8543c6caU, + 0xb970c9f6U, 0xbbf04bf4U, 0x2a042e65U, 0x9c1d81d3U, + 0x78c0b837U, 0x1372615cU, 0x868305c9U, 0x1232205dU, + 0xed31dca2U, 0x60debe2fU, 0x4b3c7704U, 0xd447939bU, + 0xd7875098U, 0xdb885394U, 0x70caba3fU, 0xbc3589f3U, + 0xb3fa49fcU, 0xe7bb5ca8U, 0x1dfde052U, 0x58e8b017U, + 0x9557c2daU, 0xd908d196U, 0x4a7c3605U, 0x5b287314U, + 0xb7ff48f8U, 0x2f416e60U, 0x00a6a64fU, 0xa2ae0cedU, + 0x0e292741U, 0xe6fb1da9U, 0x4e793701U, 0x0f696640U, + 0xfba05bb4U, 0x17776058U, 0x31daeb7eU, 0xfc6599b3U, + 0xe2fe1cadU, 0xfee51bb1U, 0x87c344c8U, 0x9a9802d5U, + 0x724a383dU, 0xf2ea18bdU, 0x97d740d8U, 0x68d4bc27U, + 0x25cbee6aU, 0x764f3939U, 0x6f117e20U, 0x2b446f64U, + 0x08aca447U, 0x39d0e976U, 0xeaf41ea5U, 0x3f556a70U, + 0x47337408U, 0xaea10fe1U, 0x7e453b31U, 0xe934dda6U, + 0xf46f9bbbU, 0x659bfe2aU, 0x55a7f21aU, 0x0ca9a543U, + 0xdd0dd092U, 0x880c84c7U, 0x5cedb113U, 0x3dd5e872U, + 0x770f7838U, 0x6994fd26U, 0x969701d9U, 0xa02e8eefU, + 0xf86098b7U, 0xa964cde6U, 0xbd75c8f2U, 0x4db9f402U, + 0x9152c3deU, 0xf3aa59bcU, 0x220e2c6dU, 0xf06a9abfU, + 0xf52fdabaU, 0xcc599583U, 0x0366654cU, 0xe47b9fabU, + 0x18b8a057U, 0xa6ab0de9U, 0x1e3d2351U, 0x234e6d6cU, + 0xc056968fU, 0x3890a877U, 0xbeb50bf1U, 0xb6bf09f9U, + 0xa16ecfeeU, 0x44f3b70bU, 0xb03a8affU, 0xf920d9b6U, + 0x0226244dU, 0xad61cce2U, 0xfd25d8b2U, 0xced91781U, + 0x7cc5b933U, 0xefb15ea0U, 0x5dadf012U, 0xf7af58b8U, + 0x758ffa3aU, 0xd2c2109dU, 0xfae01ab5U, 0xd8489097U, + 0x4276340dU, 0x3b506b74U, 0x4f397600U, 0xcb9c5784U, + 0x21ceef6eU, 0x19f8e156U, 0xaaa40ee5U, 0x631e7d2cU, + 0x0de9e442U, 0x8146c7ceU, 0x4cf9b503U, 0xcadc1685U, + 0x7a403a35U, 0x894cc5c6U, 0xdf8d5290U, 0xbff54af0U, + 0xc396558cU, 0xc7935488U, 0x1b786354U, 0x335a697cU, + 0x40f6b60fU, 0x1a382255U, 0xc85c9487U, 0x3c95a973U, + 0x981880d7U, 0x01e6e74eU, 0x840387cbU, 0x8bcc47c4U, + 0x321a287dU, 0x11f2e35eU, 0x07636448U, 0x730a793cU, + 0x0a2c2645U, 0x361f2979U, 0x1f7d6250U, 0x15f7e25aU, + 0x5e6d3311U, 0x718afb3eU, 0xb2ba08fdU, 0x54e7b31bU, + 0xe07e9eafU, 0x41b6f70eU, 0x9bd843d4U, 0x800686cfU, + 0xc2d6148dU, 0xa7eb4ce8U, 0x35dfea7aU, 0x3e152b71U, + 0x941783dbU, 0xe13edfaeU, 0xa42b8febU, 0xb43f8bfbU, + 0x50e2b21fU, 0xd382519cU, 0x2884ac67U, 0x5f2d7210U, + 0x46733509U, 0x2c81ad63U, 0xabe44fe4U, 0x8fc946c0U, + 0xe3be5dacU, 0x901282dfU, 0xb17acbfeU, 0x5262301dU, + 0x619eff2eU, 0xcf995680U, 0x6d91fc22U, 0x64dbbf2bU, + 0x16372159U, 0xb57fcafaU, 0x83c645ccU, 0xc513d68aU, + 0x9e9d03d1U, 0x05e3e64aU, 0x4336750cU, 0xf6ef19b9U, + 0x93d241dcU, 0xcd19d482U, 0x0b6c6744U, 0x8e8907c1U, + 0x29c4ed66U, 0x59a8f116U, 0x929200ddU, 0x57277018U, + 0x88e068e6U, 0x91be2fffU, 0x7423571aU, 0x28684046U, + 0xe092728eU, 0x540b5f3aU, 0x27a78049U, 0x0d050863U, + 0x8b20abe5U, 0x09000967U, 0x832aa9edU, 0xd8a47cb6U, + 0x73e6951dU, 0x3c794552U, 0x63f2910dU, 0xc77fb8a9U, + 0x7fe99611U, 0x4e95db20U, 0xb99c25d7U, 0x0ac0ca64U, + 0x7bec9715U, 0x29280147U, 0xc37ab9adU, 0xdca17db2U, + 0x796c1517U, 0xc23af8acU, 0x9f31aef1U, 0x4bd09b25U, + 0xf603f598U, 0xc9f039a7U, 0xcb70bba5U, 0xb59326dbU, + 0xa18223cfU, 0xda24feb4U, 0x927eecfcU, 0x004a4a6eU, + 0x95bb2efbU, 0x6c3d5102U, 0xb19627dfU, 0x3afcc654U, + 0x1f918e71U, 0x826ae8ecU, 0xff49b691U, 0xde21ffb0U, + 0x6437530aU, 0xec9d7182U, 0x6172130fU, 0x5a84de34U, + 0x401a5a2eU, 0x1d110c73U, 0xa302a1cdU, 0x7563161bU, + 0xf483779aU, 0xf346b59dU, 0x7026561eU, 0x85af2aebU, + 0xd1ee3fbfU, 0xaccd61c2U, 0x81aa2befU, 0x387c4456U, + 0x06cfc968U, 0xeddd3083U, 0x2fad8241U, 0x49501927U, + 0xce35fba0U, 0xcf75baa1U, 0x4d551823U, 0x2062424eU, + 0x1c514d72U, 0x1ed1cf70U, 0x8f25aae1U, 0x393c0557U, + 0xdde13cb3U, 0xb653e5d8U, 0x23a2814dU, 0xb713a4d9U, + 0x48105826U, 0xc5ff3aabU, 0xee1df380U, 0x7166171fU, + 0x72a6d41cU, 0x7ea9d710U, 0xd5eb3ebbU, 0x19140d77U, + 0x16dbcd78U, 0x429ad82cU, 0xb8dc64d6U, 0xfdc93493U, + 0x3076465eU, 0x7c295512U, 0xef5db281U, 0xfe09f790U, + 0x12decc7cU, 0x8a60eae4U, 0xa58722cbU, 0x078f8869U, + 0xab08a3c5U, 0x43da992dU, 0xeb58b385U, 0xaa48e2c4U, + 0x5e81df30U, 0xb256e4dcU, 0x94fb6ffaU, 0x59441d37U, + 0x47df9829U, 0x5bc49f35U, 0x22e2c04cU, 0x3fb98651U, + 0xd76bbcb9U, 0x57cb9c39U, 0x32f6c45cU, 0xcdf538a3U, + 0x80ea6aeeU, 0xd36ebdbdU, 0xca30faa4U, 0x8e65ebe0U, + 0xad8d20c3U, 0x9cf16df2U, 0x4fd59a21U, 0x9a74eef4U, + 0xe212f08cU, 0x0b808b65U, 0xdb64bfb5U, 0x4c155922U, + 0x514e1f3fU, 0xc0ba7aaeU, 0xf086769eU, 0xa98821c7U, + 0x782c5416U, 0x2d2d0043U, 0xf9cc3597U, 0x98f46cf6U, + 0xd22efcbcU, 0xccb579a2U, 0x33b6855dU, 0x050f0a6bU, + 0x5d411c33U, 0x0c454962U, 0x18544c76U, 0xe8987086U, + 0x3473475aU, 0x568bdd38U, 0x872fa8e9U, 0x554b1e3bU, + 0x500e5e3eU, 0x69781107U, 0xa647e1c8U, 0x415a1b2fU, + 0xbd9924d3U, 0x038a896dU, 0xbb1ca7d5U, 0x866fe9e8U, + 0x6577120bU, 0x9db12cf3U, 0x1b948f75U, 0x139e8d7dU, + 0x044f4b6aU, 0xe1d2338fU, 0x151b0e7bU, 0x5c015d32U, + 0xa707a0c9U, 0x08404866U, 0x58045c36U, 0x6bf89305U, + 0xd9e43db7U, 0x4a90da24U, 0xf88c7496U, 0x528edc3cU, + 0xd0ae7ebeU, 0x77e39419U, 0x5fc19e31U, 0x7d691413U, + 0xe757b089U, 0x9e71eff0U, 0xea18f284U, 0x6ebdd300U, + 0x84ef6beaU, 0xbcd965d2U, 0x0f858a61U, 0xc63ff9a8U, + 0xa8c860c6U, 0x2467434aU, 0xe9d83187U, 0x6ffd9201U, + 0xdf61beb1U, 0x2c6d4142U, 0x7aacd614U, 0x1ad4ce74U, + 0x66b7d108U, 0x62b2d00cU, 0xbe59e7d0U, 0x967bedf8U, + 0xe5d7328bU, 0xbf19a6d1U, 0x6d7d1003U, 0x99b42df7U, + 0x3d390453U, 0xa4c763caU, 0x2122034fU, 0x2eedc340U, + 0x973bacf9U, 0xb4d367daU, 0xa242e0ccU, 0xd62bfdb8U, + 0xaf0da2c1U, 0x933eadfdU, 0xba5ce6d4U, 0xb0d666deU, + 0xfb4cb795U, 0xd4ab7fbaU, 0x179b8c79U, 0xf1c6379fU, + 0x455f1a2bU, 0xe497738aU, 0x3ef9c750U, 0x2527024bU, + 0x67f79009U, 0x02cac86cU, 0x90fe6efeU, 0x9b34aff5U, + 0x3136075fU, 0x441f5b2aU, 0x010a0b6fU, 0x111e0f7fU, + 0xf5c3369bU, 0x76a3d518U, 0x8da528e3U, 0xfa0cf694U, + 0xe352b18dU, 0x89a029e7U, 0x0ec5cb60U, 0x2ae8c244U, + 0x469fd928U, 0x3533065bU, 0x145b4f7aU, 0xf743b499U, + 0xc4bf7baaU, 0x6ab8d204U, 0xc8b078a6U, 0xc1fa3bafU, + 0xb316a5ddU, 0x105e4e7eU, 0x26e7c148U, 0x6032520eU, + 0x3bbc8755U, 0xa0c262ceU, 0xe617f188U, 0x53ce9d3dU, + 0x36f3c558U, 0x68385006U, 0xae4de3c0U, 0x2ba88345U, + 0x8ce569e2U, 0xfc897592U, 0x37b38459U, 0xf206f49cU, + 0xda58820cU, 0xc306c515U, 0x269bbdf0U, 0x7ad0aaacU, + 0xb22a9864U, 0x06b3b5d0U, 0x751f6aa3U, 0x5fbde289U, + 0xd998410fU, 0x5bb8e38dU, 0xd1924307U, 0x8a1c965cU, + 0x215e7ff7U, 0x6ec1afb8U, 0x314a7be7U, 0x95c75243U, + 0x2d517cfbU, 0x1c2d31caU, 0xeb24cf3dU, 0x5878208eU, + 0x29547dffU, 0x7b90ebadU, 0x91c25347U, 0x8e199758U, + 0x2bd4fffdU, 0x90821246U, 0xcd89441bU, 0x196871cfU, + 0xa4bb1f72U, 0x9b48d34dU, 0x99c8514fU, 0xe72bcc31U, + 0xf33ac925U, 0x889c145eU, 0xc0c60616U, 0x52f2a084U, + 0xc703c411U, 0x3e85bbe8U, 0xe32ecd35U, 0x68442cbeU, + 0x4d29649bU, 0xd0d20206U, 0xadf15c7bU, 0x8c99155aU, + 0x368fb9e0U, 0xbe259b68U, 0x33caf9e5U, 0x083c34deU, + 0x12a2b0c4U, 0x4fa9e699U, 0xf1ba4b27U, 0x27dbfcf1U, + 0xa63b9d70U, 0xa1fe5f77U, 0x229ebcf4U, 0xd717c001U, + 0x8356d555U, 0xfe758b28U, 0xd312c105U, 0x6ac4aebcU, + 0x54772382U, 0xbf65da69U, 0x7d1568abU, 0x1be8f3cdU, + 0x9c8d114aU, 0x9dcd504bU, 0x1fedf2c9U, 0x72daa8a4U, + 0x4ee9a798U, 0x4c69259aU, 0xdd9d400bU, 0x6b84efbdU, + 0x8f59d659U, 0xe4eb0f32U, 0x711a6ba7U, 0xe5ab4e33U, + 0x1aa8b2ccU, 0x9747d041U, 0xbca5196aU, 0x23defdf5U, + 0x201e3ef6U, 0x2c113dfaU, 0x8753d451U, 0x4bace79dU, + 0x44632792U, 0x102232c6U, 0xea648e3cU, 0xaf71de79U, + 0x62ceacb4U, 0x2e91bff8U, 0xbde5586bU, 0xacb11d7aU, + 0x40662696U, 0xd8d8000eU, 0xf73fc821U, 0x55376283U, + 0xf9b0492fU, 0x116273c7U, 0xb9e0596fU, 0xf8f0082eU, + 0x0c3935daU, 0xe0ee0e36U, 0xc6438510U, 0x0bfcf7ddU, + 0x156772c3U, 0x097c75dfU, 0x705a2aa6U, 0x6d016cbbU, + 0x85d35653U, 0x057376d3U, 0x604e2eb6U, 0x9f4dd249U, + 0xd2528004U, 0x81d65757U, 0x9888104eU, 0xdcdd010aU, + 0xff35ca29U, 0xce498718U, 0x1d6d70cbU, 0xc8cc041eU, + 0xb0aa1a66U, 0x5938618fU, 0x89dc555fU, 0x1eadb3c8U, + 0x03f6f5d5U, 0x92029044U, 0xa23e9c74U, 0xfb30cb2dU, + 0x2a94befcU, 0x7f95eaa9U, 0xab74df7dU, 0xca4c861cU, + 0x80961656U, 0x9e0d9348U, 0x610e6fb7U, 0x57b7e081U, + 0x0ff9f6d9U, 0x5efda388U, 0x4aeca69cU, 0xba209a6cU, + 0x66cbadb0U, 0x043337d2U, 0xd5974203U, 0x07f3f4d1U, + 0x02b6b4d4U, 0x3bc0fbedU, 0xf4ff0b22U, 0x13e2f1c5U, + 0xef21ce39U, 0x51326387U, 0xe9a44d3fU, 0xd4d70302U, + 0x37cff8e1U, 0xcf09c619U, 0x492c659fU, 0x41266797U, + 0x56f7a180U, 0xb36ad965U, 0x47a3e491U, 0x0eb9b7d8U, + 0xf5bf4a23U, 0x5af8a28cU, 0x0abcb6dcU, 0x394079efU, + 0x8b5cd75dU, 0x182830ceU, 0xaa349e7cU, 0x003636d6U, + 0x82169454U, 0x255b7ef3U, 0x0d7974dbU, 0x2fd1fef9U, + 0xb5ef5a63U, 0xccc9051aU, 0xb8a0186eU, 0x3c0539eaU, + 0xd6578100U, 0xee618f38U, 0x5d3d608bU, 0x94871342U, + 0xfa708a2cU, 0x76dfa9a0U, 0xbb60db6dU, 0x3d4578ebU, + 0x8dd9545bU, 0x7ed5aba8U, 0x28143cfeU, 0x486c249eU, + 0x340f3be2U, 0x300a3ae6U, 0xece10d3aU, 0xc4c30712U, + 0xb76fd861U, 0xeda14c3bU, 0x3fc5fae9U, 0xcb0cc71dU, + 0x6f81eeb9U, 0xf67f8920U, 0x739ae9a5U, 0x7c5529aaU, + 0xc5834613U, 0xe66b8d30U, 0xf0fa0a26U, 0x84931752U, + 0xfdb5482bU, 0xc1864717U, 0xe8e40c3eU, 0xe26e8c34U, + 0xa9f45d7fU, 0x86139550U, 0x45236693U, 0xa37edd75U, + 0x17e7f0c1U, 0xb62f9960U, 0x6c412dbaU, 0x779fe8a1U, + 0x354f7ae3U, 0x50722286U, 0xc2468414U, 0xc98c451fU, + 0x638eedb5U, 0x16a7b1c0U, 0x53b2e185U, 0x43a6e595U, + 0xa77bdc71U, 0x241b3ff2U, 0xdf1dc209U, 0xa8b41c7eU, + 0xb1ea5b67U, 0xdb18c30dU, 0x5c7d218aU, 0x785028aeU, + 0x142733c2U, 0x678becb1U, 0x46e3a590U, 0xa5fb5e73U, + 0x96079140U, 0x380038eeU, 0x9a08924cU, 0x9342d145U, + 0xe1ae4f37U, 0x42e6a494U, 0x745f2ba2U, 0x328ab8e4U, + 0x69046dbfU, 0xf27a8824U, 0xb4af1b62U, 0x017677d7U, + 0x644b2fb2U, 0x3a80baecU, 0xfcf5092aU, 0x791069afU, + 0xde5d8308U, 0xae319f78U, 0x650b6eb3U, 0xa0be1e76U, + 0xec56ba34U, 0xf508fd2dU, 0x109585c8U, 0x4cde9294U, + 0x8424a05cU, 0x30bd8de8U, 0x4311529bU, 0x69b3dab1U, + 0xef967937U, 0x6db6dbb5U, 0xe79c7b3fU, 0xbc12ae64U, + 0x175047cfU, 0x58cf9780U, 0x074443dfU, 0xa3c96a7bU, + 0x1b5f44c3U, 0x2a2309f2U, 0xdd2af705U, 0x6e7618b6U, + 0x1f5a45c7U, 0x4d9ed395U, 0xa7cc6b7fU, 0xb817af60U, + 0x1ddac7c5U, 0xa68c2a7eU, 0xfb877c23U, 0x2f6649f7U, + 0x92b5274aU, 0xad46eb75U, 0xafc66977U, 0xd125f409U, + 0xc534f11dU, 0xbe922c66U, 0xf6c83e2eU, 0x64fc98bcU, + 0xf10dfc29U, 0x088b83d0U, 0xd520f50dU, 0x5e4a1486U, + 0x7b275ca3U, 0xe6dc3a3eU, 0x9bff6443U, 0xba972d62U, + 0x008181d8U, 0x882ba350U, 0x05c4c1ddU, 0x3e320ce6U, + 0x24ac88fcU, 0x79a7dea1U, 0xc7b4731fU, 0x11d5c4c9U, + 0x9035a548U, 0x97f0674fU, 0x149084ccU, 0xe119f839U, + 0xb558ed6dU, 0xc87bb310U, 0xe51cf93dU, 0x5cca9684U, + 0x62791bbaU, 0x896be251U, 0x4b1b5093U, 0x2de6cbf5U, + 0xaa832972U, 0xabc36873U, 0x29e3caf1U, 0x44d4909cU, + 0x78e79fa0U, 0x7a671da2U, 0xeb937833U, 0x5d8ad785U, + 0xb957ee61U, 0xd2e5370aU, 0x4714539fU, 0xd3a5760bU, + 0x2ca68af4U, 0xa149e879U, 0x8aab2152U, 0x15d0c5cdU, + 0x161006ceU, 0x1a1f05c2U, 0xb15dec69U, 0x7da2dfa5U, + 0x726d1faaU, 0x262c0afeU, 0xdc6ab604U, 0x997fe641U, + 0x54c0948cU, 0x189f87c0U, 0x8beb6053U, 0x9abf2542U, + 0x76681eaeU, 0xeed63836U, 0xc131f019U, 0x63395abbU, + 0xcfbe7117U, 0x276c4bffU, 0x8fee6157U, 0xcefe3016U, + 0x3a370de2U, 0xd6e0360eU, 0xf04dbd28U, 0x3df2cfe5U, + 0x23694afbU, 0x3f724de7U, 0x4654129eU, 0x5b0f5483U, + 0xb3dd6e6bU, 0x337d4eebU, 0x5640168eU, 0xa943ea71U, + 0xe45cb83cU, 0xb7d86f6fU, 0xae862876U, 0xead33932U, + 0xc93bf211U, 0xf847bf20U, 0x2b6348f3U, 0xfec23c26U, + 0x86a4225eU, 0x6f3659b7U, 0xbfd26d67U, 0x28a38bf0U, + 0x35f8cdedU, 0xa40ca87cU, 0x9430a44cU, 0xcd3ef315U, + 0x1c9a86c4U, 0x499bd291U, 0x9d7ae745U, 0xfc42be24U, + 0xb6982e6eU, 0xa803ab70U, 0x5700578fU, 0x61b9d8b9U, + 0x39f7cee1U, 0x68f39bb0U, 0x7ce29ea4U, 0x8c2ea254U, + 0x50c59588U, 0x323d0feaU, 0xe3997a3bU, 0x31fdcce9U, + 0x34b88cecU, 0x0dcec3d5U, 0xc2f1331aU, 0x25ecc9fdU, + 0xd92ff601U, 0x673c5bbfU, 0xdfaa7507U, 0xe2d93b3aU, + 0x01c1c0d9U, 0xf907fe21U, 0x7f225da7U, 0x77285fafU, + 0x60f999b8U, 0x8564e15dU, 0x71addca9U, 0x38b78fe0U, + 0xc3b1721bU, 0x6cf69ab4U, 0x3cb28ee4U, 0x0f4e41d7U, + 0xbd52ef65U, 0x2e2608f6U, 0x9c3aa644U, 0x36380eeeU, + 0xb418ac6cU, 0x135546cbU, 0x3b774ce3U, 0x19dfc6c1U, + 0x83e1625bU, 0xfac73d22U, 0x8eae2056U, 0x0a0b01d2U, + 0xe059b938U, 0xd86fb700U, 0x6b3358b3U, 0xa2892b7aU, + 0xcc7eb214U, 0x40d19198U, 0x8d6ee355U, 0x0b4b40d3U, + 0xbbd76c63U, 0x48db9390U, 0x1e1a04c6U, 0x7e621ca6U, + 0x020103daU, 0x060402deU, 0xdaef3502U, 0xf2cd3f2aU, + 0x8161e059U, 0xdbaf7403U, 0x09cbc2d1U, 0xfd02ff25U, + 0x598fd681U, 0xc071b118U, 0x4594d19dU, 0x4a5b1192U, + 0xf38d7e2bU, 0xd065b508U, 0xc6f4321eU, 0xb29d2f6aU, + 0xcbbb7013U, 0xf7887f2fU, 0xdeea3406U, 0xd460b40cU, + 0x9ffa6547U, 0xb01dad68U, 0x732d5eabU, 0x9570e54dU, + 0x21e9c8f9U, 0x8021a158U, 0x5a4f1582U, 0x4191d099U, + 0x034142dbU, 0x667c1abeU, 0xf448bc2cU, 0xff827d27U, + 0x5580d58dU, 0x20a989f8U, 0x65bcd9bdU, 0x75a8ddadU, + 0x9175e449U, 0x121507caU, 0xe913fa31U, 0x9eba2446U, + 0x87e4635fU, 0xed16fb35U, 0x6a7319b2U, 0x4e5e1096U, + 0x22290bfaU, 0x5185d489U, 0x70ed9da8U, 0x93f5664bU, + 0xa009a978U, 0x0e0e00d6U, 0xac06aa74U, 0xa54ce97dU, + 0xd7a0770fU, 0x74e89cacU, 0x4251139aU, 0x048480dcU, + 0x5f0a5587U, 0xc474b01cU, 0x82a1235aU, 0x37784fefU, + 0x5245178aU, 0x0c8e82d4U, 0xcafb3112U, 0x4f1e5197U, + 0xe853bb30U, 0x983fa740U, 0x5305568bU, 0x96b0264eU, + 0xb0b90987U, 0xa9e74e9eU, 0x4c7a367bU, 0x10312127U, + 0xd8cb13efU, 0x6c523e5bU, 0x1ffee128U, 0x355c6902U, + 0xb379ca84U, 0x31596806U, 0xbb73c88cU, 0xe0fd1dd7U, + 0x4bbff47cU, 0x04202433U, 0x5babf06cU, 0xff26d9c8U, + 0x47b0f770U, 0x76ccba41U, 0x81c544b6U, 0x3299ab05U, + 0x43b5f674U, 0x11716026U, 0xfb23d8ccU, 0xe4f81cd3U, + 0x41357476U, 0xfa6399cdU, 0xa768cf90U, 0x7389fa44U, + 0xce5a94f9U, 0xf1a958c6U, 0xf329dac4U, 0x8dca47baU, + 0x99db42aeU, 0xe27d9fd5U, 0xaa278d9dU, 0x38132b0fU, + 0xade24f9aU, 0x54643063U, 0x89cf46beU, 0x02a5a735U, + 0x27c8ef10U, 0xba33898dU, 0xc710d7f0U, 0xe6789ed1U, + 0x5c6e326bU, 0xd4c410e3U, 0x592b726eU, 0x62ddbf55U, + 0x78433b4fU, 0x25486d12U, 0x9b5bc0acU, 0x4d3a777aU, + 0xccda16fbU, 0xcb1fd4fcU, 0x487f377fU, 0xbdf64b8aU, + 0xe9b75edeU, 0x949400a3U, 0xb9f34a8eU, 0x00252537U, + 0x3e96a809U, 0xd58451e2U, 0x17f4e320U, 0x71097846U, + 0xf66c9ac1U, 0xf72cdbc0U, 0x750c7942U, 0x183b232fU, + 0x24082c13U, 0x2688ae11U, 0xb77ccb80U, 0x01656436U, + 0xe5b85dd2U, 0x8e0a84b9U, 0x1bfbe02cU, 0x8f4ac5b8U, + 0x70493947U, 0xfda65bcaU, 0xd64492e1U, 0x493f767eU, + 0x4affb57dU, 0x46f0b671U, 0xedb25fdaU, 0x214d6c16U, + 0x2e82ac19U, 0x7ac3b94dU, 0x808505b7U, 0xc59055f2U, + 0x082f273fU, 0x44703473U, 0xd704d3e0U, 0xc65096f1U, + 0x2a87ad1dU, 0xb2398b85U, 0x9dde43aaU, 0x3fd6e908U, + 0x9351c2a4U, 0x7b83f84cU, 0xd301d2e4U, 0x921183a5U, + 0x66d8be51U, 0x8a0f85bdU, 0xaca20e9bU, 0x611d7c56U, + 0x7f86f948U, 0x639dfe54U, 0x1abba12dU, 0x07e0e730U, + 0xef32ddd8U, 0x6f92fd58U, 0x0aafa53dU, 0xf5ac59c2U, + 0xb8b30b8fU, 0xeb37dcdcU, 0xf2699bc5U, 0xb63c8a81U, + 0x95d441a2U, 0xa4a80c93U, 0x778cfb40U, 0xa22d8f95U, + 0xda4b91edU, 0x33d9ea04U, 0xe33dded4U, 0x744c3843U, + 0x69177e5eU, 0xf8e31bcfU, 0xc8df17ffU, 0x91d140a6U, + 0x40753577U, 0x15746122U, 0xc19554f6U, 0xa0ad0d97U, + 0xea779dddU, 0xf4ec18c3U, 0x0befe43cU, 0x3d566b0aU, + 0x65187d52U, 0x341c2803U, 0x200d2d17U, 0xd0c111e7U, + 0x0c2a263bU, 0x6ed2bc59U, 0xbf76c988U, 0x6d127f5aU, + 0x68573f5fU, 0x51217066U, 0x9e1e80a9U, 0x79037a4eU, + 0x85c045b2U, 0x3bd3e80cU, 0x8345c6b4U, 0xbe368889U, + 0x5d2e736aU, 0xa5e84d92U, 0x23cdee14U, 0x2bc7ec1cU, + 0x3c162a0bU, 0xd98b52eeU, 0x2d426f1aU, 0x64583c53U, + 0x9f5ec1a8U, 0x30192907U, 0x605d3d57U, 0x53a1f264U, + 0xe1bd5cd6U, 0x72c9bb45U, 0xc0d515f7U, 0x6ad7bd5dU, + 0xe8f71fdfU, 0x4fbaf578U, 0x6798ff50U, 0x45307572U, + 0xdf0ed1e8U, 0xa6288e91U, 0xd24193e5U, 0x56e4b261U, + 0xbcb60a8bU, 0x848004b3U, 0x37dceb00U, 0xfe6698c9U, + 0x909101a7U, 0x1c3e222bU, 0xd18150e6U, 0x57a4f360U, + 0xe738dfd0U, 0x14342023U, 0x42f5b775U, 0x228daf15U, + 0x5eeeb069U, 0x5aebb16dU, 0x860086b1U, 0xae228c99U, + 0xdd8e53eaU, 0x8740c7b0U, 0x55247162U, 0xa1ed4c96U, + 0x05606532U, 0x9c9e02abU, 0x197b622eU, 0x16b4a221U, + 0xaf62cd98U, 0x8c8a06bbU, 0x9a1b81adU, 0xee729cd9U, + 0x9754c3a0U, 0xab67cc9cU, 0x820587b5U, 0x888f07bfU, + 0xc315d6f4U, 0xecf21edbU, 0x2fc2ed18U, 0xc99f56feU, + 0x7d067b4aU, 0xdcce12ebU, 0x06a0a631U, 0x1d7e632aU, + 0x5faef168U, 0x3a93a90dU, 0xa8a70f9fU, 0xa36dce94U, + 0x096f663eU, 0x7c463a4bU, 0x39536a0eU, 0x29476e1eU, + 0xcd9a57faU, 0x4efab479U, 0xb5fc4982U, 0xc25597f5U, + 0xdb0bd0ecU, 0xb1f94886U, 0x369caa01U, 0x12b1a325U, + 0x7ec6b849U, 0x0d6a673aU, 0x2c022e1bU, 0xcf1ad5f8U, + 0xfce61acbU, 0x52e1b365U, 0xf0e919c7U, 0xf9a35aceU, + 0x8b4fc4bcU, 0x28072f1fU, 0x1ebea029U, 0x586b336fU, + 0x03e5e634U, 0x989b03afU, 0xde4e90e9U, 0x6b97fc5cU, + 0x0eaaa439U, 0x50613167U, 0x961482a1U, 0x13f1e224U, + 0xb4bc0883U, 0xc4d014f3U, 0x0feae538U, 0xca5f95fdU, + 0x0acac04eU, 0x13948757U, 0xf609ffb2U, 0xaa42e8eeU, + 0x62b8da26U, 0xd621f792U, 0xa58d28e1U, 0x8f2fa0cbU, + 0x090a034dU, 0x8b2aa1cfU, 0x01000145U, 0x5a8ed41eU, + 0xf1cc3db5U, 0xbe53edfaU, 0xe1d839a5U, 0x45551001U, + 0xfdc33eb9U, 0xccbf7388U, 0x3bb68d7fU, 0x88ea62ccU, + 0xf9c63fbdU, 0xab02a9efU, 0x41501105U, 0x5e8bd51aU, + 0xfb46bdbfU, 0x40105004U, 0x1d1b0659U, 0xc9fa338dU, + 0x74295d30U, 0x4bda910fU, 0x495a130dU, 0x37b98e73U, + 0x23a88b67U, 0x580e561cU, 0x10544454U, 0x8260e2c6U, + 0x17918653U, 0xee17f9aaU, 0x33bc8f77U, 0xb8d66efcU, + 0x9dbb26d9U, 0x00404044U, 0x7d631e39U, 0x5c0b5718U, + 0xe61dfba2U, 0x6eb7d92aU, 0xe358bba7U, 0xd8ae769cU, + 0xc230f286U, 0x9f3ba4dbU, 0x21280965U, 0xf749beb3U, + 0x76a9df32U, 0x716c1d35U, 0xf20cfeb6U, 0x07858243U, + 0x53c49717U, 0x2ee7c96aU, 0x03808347U, 0xba56ecfeU, + 0x84e561c0U, 0x6ff7982bU, 0xad872ae9U, 0xcb7ab18fU, + 0x4c1f5308U, 0x4d5f1209U, 0xcf7fb08bU, 0xa248eae6U, + 0x9e7be5daU, 0x9cfb67d8U, 0x0d0f0249U, 0xbb16adffU, + 0x5fcb941bU, 0x34794d70U, 0xa18829e5U, 0x35390c71U, + 0xca3af08eU, 0x47d59203U, 0x6c375b28U, 0xf34cbfb7U, + 0xf08c7cb4U, 0xfc837fb8U, 0x57c19613U, 0x9b3ea5dfU, + 0x94f165d0U, 0xc0b07084U, 0x3af6cc7eU, 0x7fe39c3bU, + 0xb25ceef6U, 0xfe03fdbaU, 0x6d771a29U, 0x7c235f38U, + 0x90f464d4U, 0x084a424cU, 0x27ad8a63U, 0x85a520c1U, + 0x29220b6dU, 0xc1f03185U, 0x69721b2dU, 0x28624a6cU, + 0xdcab7798U, 0x307c4c74U, 0x16d1c752U, 0xdb6eb59fU, + 0xc5f53081U, 0xd9ee379dU, 0xa0c868e4U, 0xbd932ef9U, + 0x55411411U, 0xd5e13491U, 0xb0dc6cf4U, 0x4fdf900bU, + 0x02c0c246U, 0x51441515U, 0x481a520cU, 0x0c4f4348U, + 0x2fa7886bU, 0x1edbc55aU, 0xcdff3289U, 0x185e465cU, + 0x60385824U, 0x89aa23cdU, 0x594e171dU, 0xce3ff18aU, + 0xd364b797U, 0x4290d206U, 0x72acde36U, 0x2ba2896fU, + 0xfa06fcbeU, 0xaf07a8ebU, 0x7be69d3fU, 0x1adec45eU, + 0x50045414U, 0x4e9fd10aU, 0xb19c2df5U, 0x8725a2c3U, + 0xdf6bb49bU, 0x8e6fe1caU, 0x9a7ee4deU, 0x6ab2d82eU, + 0xb659eff2U, 0xd4a17590U, 0x05050041U, 0xd761b693U, + 0xd224f696U, 0xeb52b9afU, 0x246d4960U, 0xc370b387U, + 0x3fb38c7bU, 0x81a021c5U, 0x39360f7dU, 0x04454140U, + 0xe75dbaa3U, 0x1f9b845bU, 0x99be27ddU, 0x91b425d5U, + 0x8665e3c2U, 0x63f89b27U, 0x9731a6d3U, 0xde2bf59aU, + 0x252d0861U, 0x8a6ae0ceU, 0xda2ef49eU, 0xe9d23badU, + 0x5bce951fU, 0xc8ba728cU, 0x7aa6dc3eU, 0xd0a47494U, + 0x5284d616U, 0xf5c93cb1U, 0xddeb3699U, 0xff43bcbbU, + 0x657d1821U, 0x1c5b4758U, 0x68325a2cU, 0xec977ba8U, + 0x06c5c342U, 0x3ef3cd7aU, 0x8daf22c9U, 0x44155100U, + 0x2ae2c86eU, 0xa64debe2U, 0x6bf2992fU, 0xedd73aa9U, + 0x5d4b1619U, 0xae47e9eaU, 0xf8867ebcU, 0x98fe66dcU, + 0xe49d79a0U, 0xe09878a4U, 0x3c734f78U, 0x14514550U, + 0x67fd9a23U, 0x3d330e79U, 0xef57b8abU, 0x1b9e855fU, + 0xbf13acfbU, 0x26edcb62U, 0xa308abe7U, 0xacc76be8U, + 0x15110451U, 0x36f9cf72U, 0x20684864U, 0x54015510U, + 0x2d270a69U, 0x11140555U, 0x38764e7cU, 0x32fcce76U, + 0x79661f3dU, 0x5681d712U, 0x95b124d1U, 0x73ec9f37U, + 0xc775b283U, 0x66bddb22U, 0xbcd36ff8U, 0xa70daae3U, + 0xe5dd38a1U, 0x80e060c4U, 0x12d4c656U, 0x191e075dU, + 0xb31caff7U, 0xc635f382U, 0x8320a3c7U, 0x9334a7d7U, + 0x77e99e33U, 0xf4897db0U, 0x0f8f804bU, 0x78265e3cU, + 0x61781925U, 0x0b8a814fU, 0x8cef63c8U, 0xa8c26aecU, + 0xc4b57180U, 0xb719aef3U, 0x9671e7d2U, 0x75691c31U, + 0x4695d302U, 0xe8927aacU, 0x4a9ad00eU, 0x43d09307U, + 0x313c0d75U, 0x9274e6d6U, 0xa4cd69e0U, 0xe218faa6U, + 0xb9962ffdU, 0x22e8ca66U, 0x643d5920U, 0xd1e43595U, + 0xb4d96df0U, 0xea12f8aeU, 0x2c674b68U, 0xa9822bedU, + 0x0ecfc14aU, 0x7ea3dd3aU, 0xb5992cf1U, 0x702c5c34U, + 0xfd53ae20U, 0xe40de939U, 0x019091dcU, 0x5ddb8680U, + 0x9521b448U, 0x21b899fcU, 0x5214468fU, 0x78b6cea5U, + 0xfe936d23U, 0x7cb3cfa1U, 0xf6996f2bU, 0xad17ba70U, + 0x065553dbU, 0x49ca8394U, 0x164157cbU, 0xb2cc7e6fU, + 0x0a5a50d7U, 0x3b261de6U, 0xcc2fe311U, 0x7f730ca2U, + 0x0e5f51d3U, 0x5c9bc781U, 0xb6c97f6bU, 0xa912bb74U, + 0x0cdfd3d1U, 0xb7893e6aU, 0xea826837U, 0x3e635de3U, + 0x83b0335eU, 0xbc43ff61U, 0xbec37d63U, 0xc020e01dU, + 0xd431e509U, 0xaf973872U, 0xe7cd2a3aU, 0x75f98ca8U, + 0xe008e83dU, 0x198e97c4U, 0xc425e119U, 0x4f4f0092U, + 0x6a2248b7U, 0xf7d92e2aU, 0x8afa7057U, 0xab923976U, + 0x118495ccU, 0x992eb744U, 0x14c1d5c9U, 0x2f3718f2U, + 0x35a99ce8U, 0x68a2cab5U, 0xd6b1670bU, 0x00d0d0ddU, + 0x8130b15cU, 0x86f5735bU, 0x059590d8U, 0xf01cec2dU, + 0xa45df979U, 0xd97ea704U, 0xf419ed29U, 0x4dcf8290U, + 0x737c0faeU, 0x986ef645U, 0x5a1e4487U, 0x3ce3dfe1U, + 0xbb863d66U, 0xbac67c67U, 0x38e6dee5U, 0x55d18488U, + 0x69e28bb4U, 0x6b6209b6U, 0xfa966c27U, 0x4c8fc391U, + 0xa852fa75U, 0xc3e0231eU, 0x5611478bU, 0xc2a0621fU, + 0x3da39ee0U, 0xb04cfc6dU, 0x9bae3546U, 0x04d5d1d9U, + 0x071512daU, 0x0b1a11d6U, 0xa058f87dU, 0x6ca7cbb1U, + 0x63680bbeU, 0x37291eeaU, 0xcd6fa210U, 0x887af255U, + 0x45c58098U, 0x099a93d4U, 0x9aee7447U, 0x8bba3156U, + 0x676d0abaU, 0xffd32c22U, 0xd034e40dU, 0x723c4eafU, + 0xdebb6503U, 0x36695febU, 0x9eeb7543U, 0xdffb2402U, + 0x2b3219f6U, 0xc7e5221aU, 0xe148a93cU, 0x2cf7dbf1U, + 0x326c5eefU, 0x2e7759f3U, 0x5751068aU, 0x4a0a4097U, + 0xa2d87a7fU, 0x22785affU, 0x4745029aU, 0xb846fe65U, + 0xf559ac28U, 0xa6dd7b7bU, 0xbf833c62U, 0xfbd62d26U, + 0xd83ee605U, 0xe942ab34U, 0x3a665ce7U, 0xefc72832U, + 0x97a1364aU, 0x7e334da3U, 0xaed77973U, 0x39a69fe4U, + 0x24fdd9f9U, 0xb509bc68U, 0x8535b058U, 0xdc3be701U, + 0x0d9f92d0U, 0x589ec685U, 0x8c7ff351U, 0xed47aa30U, + 0xa79d3a7aU, 0xb906bf64U, 0x4605439bU, 0x70bcccadU, + 0x28f2daf5U, 0x79f68fa4U, 0x6de78ab0U, 0x9d2bb640U, + 0x41c0819cU, 0x23381bfeU, 0xf29c6e2fU, 0x20f8d8fdU, + 0x25bd98f8U, 0x1ccbd7c1U, 0xd3f4270eU, 0x34e9dde9U, + 0xc82ae215U, 0x76394fabU, 0xceaf6113U, 0xf3dc2f2eU, + 0x10c4d4cdU, 0xe802ea35U, 0x6e2749b3U, 0x662d4bbbU, + 0x71fc8dacU, 0x9461f549U, 0x60a8c8bdU, 0x29b29bf4U, + 0xd2b4660fU, 0x7df38ea0U, 0x2db79af0U, 0x1e4b55c3U, + 0xac57fb71U, 0x3f231ce2U, 0x8d3fb250U, 0x273d1afaU, + 0xa51db878U, 0x025052dfU, 0x2a7258f7U, 0x08dad2d5U, + 0x92e4764fU, 0xebc22936U, 0x9fab3442U, 0x1b0e15c6U, + 0xf15cad2cU, 0xc96aa314U, 0x7a364ca7U, 0xb38c3f6eU, + 0xdd7ba600U, 0x51d4858cU, 0x9c6bf741U, 0x1a4e54c7U, + 0xaad27877U, 0x59de8784U, 0x0f1f10d2U, 0x6f6708b2U, + 0x130417ceU, 0x170116caU, 0xcbea2116U, 0xe3c82b3eU, + 0x9064f44dU, 0xcaaa6017U, 0x18ced6c5U, 0xec07eb31U, + 0x488ac295U, 0xd174a50cU, 0x5491c589U, 0x5b5e0586U, + 0xe2886a3fU, 0xc160a11cU, 0xd7f1260aU, 0xa3983b7eU, + 0xdabe6407U, 0xe68d6b3bU, 0xcfef2012U, 0xc565a018U, + 0x8eff7153U, 0xa118b97cU, 0x62284abfU, 0x8475f159U, + 0x30ecdcedU, 0x9124b54cU, 0x4b4a0196U, 0x5094c48dU, + 0x124456cfU, 0x77790eaaU, 0xe54da838U, 0xee876933U, + 0x4485c199U, 0x31ac9decU, 0x74b9cda9U, 0x64adc9b9U, + 0x8070f05dU, 0x031013deU, 0xf816ee25U, 0x8fbf3052U, + 0x96e1774bU, 0xfc13ef21U, 0x7b760da6U, 0x5f5b0482U, + 0x332c1feeU, 0x4080c09dU, 0x61e889bcU, 0x82f0725fU, + 0xb10cbd6cU, 0x1f0b14c2U, 0xbd03be60U, 0xb449fd69U, + 0xc6a5631bU, 0x65ed88b8U, 0x5354078eU, 0x158194c8U, + 0x4e0f4193U, 0xd571a408U, 0x93a4374eU, 0x267d5bfbU, + 0x4340039eU, 0x1d8b96c0U, 0xdbfe2506U, 0x5e1b4583U, + 0xf956af24U, 0x893ab354U, 0x4200429fU, 0x87b5325aU, + 0x527022acU, 0x4b2e65b5U, 0xaeb31d50U, 0xf2f80a0cU, + 0x3a0238c4U, 0x8e9b1570U, 0xfd37ca03U, 0xd7954229U, + 0x51b0e1afU, 0xd390432dU, 0x59bae3a7U, 0x023436fcU, + 0xa976df57U, 0xe6e90f18U, 0xb962db47U, 0x1deff2e3U, + 0xa579dc5bU, 0x9405916aU, 0x630c6f9dU, 0xd050802eU, + 0xa17cdd5fU, 0xf3b84b0dU, 0x19eaf3e7U, 0x063137f8U, + 0xa3fc5f5dU, 0x18aab2e6U, 0x45a1e4bbU, 0x9140d16fU, + 0x2c93bfd2U, 0x136073edU, 0x11e0f1efU, 0x6f036c91U, + 0x7b126985U, 0x00b4b4feU, 0x48eea6b6U, 0xdada0024U, + 0x4f2b64b1U, 0xb6ad1b48U, 0x6b066d95U, 0xe06c8c1eU, + 0xc501c43bU, 0x58faa2a6U, 0x25d9fcdbU, 0x04b1b5faU, + 0xbea71940U, 0x360d3bc8U, 0xbbe25945U, 0x8014947eU, + 0x9a8a1064U, 0xc7814639U, 0x7992eb87U, 0xaff35c51U, + 0x2e133dd0U, 0x29d6ffd7U, 0xaab61c54U, 0x5f3f60a1U, + 0x0b7e75f5U, 0x765d2b88U, 0x5b3a61a5U, 0xe2ec0e1cU, + 0xdc5f8322U, 0x374d7ac9U, 0xf53dc80bU, 0x93c0536dU, + 0x14a5b1eaU, 0x15e5f0ebU, 0x97c55269U, 0xfaf20804U, + 0xc6c10738U, 0xc441853aU, 0x55b5e0abU, 0xe3ac4f1dU, + 0x077176f9U, 0x6cc3af92U, 0xf932cb07U, 0x6d83ee93U, + 0x9280126cU, 0x1f6f70e1U, 0x348db9caU, 0xabf65d55U, + 0xa8369e56U, 0xa4399d5aU, 0x0f7b74f1U, 0xc384473dU, + 0xcc4b8732U, 0x980a9266U, 0x624c2e9cU, 0x27597ed9U, + 0xeae60c14U, 0xa6b91f58U, 0x35cdf8cbU, 0x2499bddaU, + 0xc84e8636U, 0x50f0a0aeU, 0x7f176881U, 0xdd1fc223U, + 0x7198e98fU, 0x994ad367U, 0x31c8f9cfU, 0x70d8a88eU, + 0x8411957aU, 0x68c6ae96U, 0x4e6b25b0U, 0x83d4577dU, + 0x9d4fd263U, 0x8154d57fU, 0xf8728a06U, 0xe529cc1bU, + 0x0dfbf6f3U, 0x8d5bd673U, 0xe8668e16U, 0x176572e9U, + 0x5a7a20a4U, 0x09fef7f7U, 0x10a0b0eeU, 0x54f5a1aaU, + 0x771d6a89U, 0x466127b8U, 0x9545d06bU, 0x40e4a4beU, + 0x3882bac6U, 0xd110c12fU, 0x01f4f5ffU, 0x96851368U, + 0x8bde5575U, 0x1a2a30e4U, 0x2a163cd4U, 0x73186b8dU, + 0xa2bc1e5cU, 0xf7bd4a09U, 0x235c7fddU, 0x426426bcU, + 0x08beb6f6U, 0x162533e8U, 0xe926cf17U, 0xdf9f4021U, + 0x87d15679U, 0xd6d50328U, 0xc2c4063cU, 0x32083accU, + 0xeee30d10U, 0x8c1b9772U, 0x5dbfe2a3U, 0x8fdb5471U, + 0x8a9e1474U, 0xb3e85b4dU, 0x7cd7ab82U, 0x9bca5165U, + 0x67096e99U, 0xd91ac327U, 0x618ced9fU, 0x5cffa3a2U, + 0xbfe75841U, 0x472166b9U, 0xc104c53fU, 0xc90ec737U, + 0xdedf0120U, 0x3b4279c5U, 0xcf8b4431U, 0x86911778U, + 0x7d97ea83U, 0xd2d0022cU, 0x8294167cU, 0xb168d94fU, + 0x037477fdU, 0x9000906eU, 0x221c3edcU, 0x881e9676U, + 0x0a3e34f4U, 0xad73de53U, 0x8551d47bU, 0xa7f95e59U, + 0x3dc7fac3U, 0x44e1a5baU, 0x3088b8ceU, 0xb42d994aU, + 0x5e7f21a0U, 0x66492f98U, 0xd515c02bU, 0x1cafb3e2U, + 0x72582a8cU, 0xfef70900U, 0x33487bcdU, 0xb56dd84bU, + 0x05f1f4fbU, 0xf6fd0b08U, 0xa03c9c5eU, 0xc044843eU, + 0xbc279b42U, 0xb8229a46U, 0x64c9ad9aU, 0x4ceba7b2U, + 0x3f4778c1U, 0x6589ec9bU, 0xb7ed5a49U, 0x432467bdU, + 0xe7a94e19U, 0x7e572980U, 0xfbb24905U, 0xf47d890aU, + 0x4dabe6b3U, 0x6e432d90U, 0x78d2aa86U, 0x0cbbb7f2U, + 0x759de88bU, 0x49aee7b7U, 0x60ccac9eU, 0x6a462c94U, + 0x21dcfddfU, 0x0e3b35f0U, 0xcd0bc633U, 0x2b567dd5U, + 0x9fcf5061U, 0x3e0739c0U, 0xe4698d1aU, 0xffb74801U, + 0xbd67da43U, 0xd85a8226U, 0x4a6e24b4U, 0x41a4e5bfU, + 0xeba64d15U, 0x9e8f1160U, 0xdb9a4125U, 0xcb8e4535U, + 0x2f537cd1U, 0xac339f52U, 0x573562a9U, 0x209cbcdeU, + 0x39c2fbc7U, 0x533063adU, 0xd455812aU, 0xf078880eU, + 0x9c0f9362U, 0xefa34c11U, 0xcecb0530U, 0x2dd3fed3U, + 0x1e2f31e0U, 0xb028984eU, 0x122032ecU, 0x1b6a71e5U, + 0x6986ef97U, 0xcace0434U, 0xfc778b02U, 0xbaa21844U, + 0xe12ccd1fU, 0x7a522884U, 0x3c87bbc2U, 0x895ed777U, + 0xec638f12U, 0xb2a81a4cU, 0x74dda98aU, 0xf138c90fU, + 0x567523a8U, 0x26193fd8U, 0xed23ce13U, 0x2896bed6U, + 0xed02ef61U, 0xf45ca878U, 0x11c1d09dU, 0x4d8ac7c1U, + 0x8570f509U, 0x31e9d8bdU, 0x424507ceU, 0x68e78fe4U, + 0xeec22c62U, 0x6ce28ee0U, 0xe6c82e6aU, 0xbd46fb31U, + 0x1604129aU, 0x599bc2d5U, 0x0610168aU, 0xa29d3f2eU, + 0x1a0b1196U, 0x2b775ca7U, 0xdc7ea250U, 0x6f224de3U, + 0x1e0e1092U, 0x4cca86c0U, 0xa6983e2aU, 0xb943fa35U, + 0x1c8e9290U, 0xa7d87f2bU, 0xfad32976U, 0x2e321ca2U, + 0x93e1721fU, 0xac12be20U, 0xae923c22U, 0xd071a15cU, + 0xc460a448U, 0xbfc67933U, 0xf79c6b7bU, 0x65a8cde9U, + 0xf059a97cU, 0x09dfd685U, 0xd474a058U, 0x5f1e41d3U, + 0x7a7309f6U, 0xe7886f6bU, 0x9aab3116U, 0xbbc37837U, + 0x01d5d48dU, 0x897ff605U, 0x04909488U, 0x3f6659b3U, + 0x25f8dda9U, 0x78f38bf4U, 0xc6e0264aU, 0x1081919cU, + 0x9161f01dU, 0x96a4321aU, 0x15c4d199U, 0xe04dad6cU, + 0xb40cb838U, 0xc92fe645U, 0xe448ac68U, 0x5d9ec3d1U, + 0x632d4eefU, 0x883fb704U, 0x4a4f05c6U, 0x2cb29ea0U, + 0xabd77c27U, 0xaa973d26U, 0x28b79fa4U, 0x4580c5c9U, + 0x79b3caf5U, 0x7b3348f7U, 0xeac72d66U, 0x5cde82d0U, + 0xb803bb34U, 0xd3b1625fU, 0x464006caU, 0xd2f1235eU, + 0x2df2dfa1U, 0xa01dbd2cU, 0x8bff7407U, 0x14849098U, + 0x1744539bU, 0x1b4b5097U, 0xb009b93cU, 0x7cf68af0U, + 0x73394affU, 0x27785fabU, 0xdd3ee351U, 0x982bb314U, + 0x5594c1d9U, 0x19cbd295U, 0x8abf3506U, 0x9beb7017U, + 0x773c4bfbU, 0xef826d63U, 0xc065a54cU, 0x626d0feeU, + 0xceea2442U, 0x26381eaaU, 0x8eba3402U, 0xcfaa6543U, + 0x3b6358b7U, 0xd7b4635bU, 0xf119e87dU, 0x3ca69ab0U, + 0x223d1faeU, 0x3e2618b2U, 0x470047cbU, 0x5a5b01d6U, + 0xb2893b3eU, 0x32291bbeU, 0x571443dbU, 0xa817bf24U, + 0xe508ed69U, 0xb68c3a3aU, 0xafd27d23U, 0xeb876c67U, + 0xc86fa744U, 0xf913ea75U, 0x2a371da6U, 0xff966973U, + 0x87f0770bU, 0x6e620ce2U, 0xbe863832U, 0x29f7dea5U, + 0x34ac98b8U, 0xa558fd29U, 0x9564f119U, 0xcc6aa640U, + 0x1dced391U, 0x48cf87c4U, 0x9c2eb210U, 0xfd16eb71U, + 0xb7cc7b3bU, 0xa957fe25U, 0x565402daU, 0x60ed8decU, + 0x38a39bb4U, 0x69a7cee5U, 0x7db6cbf1U, 0x8d7af701U, + 0x5191c0ddU, 0x33695abfU, 0xe2cd2f6eU, 0x30a999bcU, + 0x35ecd9b9U, 0x0c9a9680U, 0xc3a5664fU, 0x24b89ca8U, + 0xd87ba354U, 0x66680eeaU, 0xdefe2052U, 0xe38d6e6fU, + 0x0095958cU, 0xf853ab74U, 0x7e7608f2U, 0x767c0afaU, + 0x61adccedU, 0x8430b408U, 0x70f989fcU, 0x39e3dab5U, + 0xc2e5274eU, 0x6da2cfe1U, 0x3de6dbb1U, 0x0e1a1482U, + 0xbc06ba30U, 0x2f725da3U, 0x9d6ef311U, 0x376c5bbbU, + 0xb54cf939U, 0x1201139eU, 0x3a2319b6U, 0x188b9394U, + 0x82b5370eU, 0xfb936877U, 0x8ffa7503U, 0x0b5f5487U, + 0xe10dec6dU, 0xd93be255U, 0x6a670de6U, 0xa3dd7e2fU, + 0xcd2ae741U, 0x4185c4cdU, 0x8c3ab600U, 0x0a1f1586U, + 0xba833936U, 0x498fc6c5U, 0x1f4e5193U, 0x7f3649f3U, + 0x0355568fU, 0x0750578bU, 0xdbbb6057U, 0xf3996a7fU, + 0x8035b50cU, 0xdafb2156U, 0x089f9784U, 0xfc56aa70U, + 0x58db83d4U, 0xc125e44dU, 0x44c084c8U, 0x4b0f44c7U, + 0xf2d92b7eU, 0xd131e05dU, 0xc7a0674bU, 0xb3c97a3fU, + 0xcaef2546U, 0xf6dc2a7aU, 0xdfbe6153U, 0xd534e159U, + 0x9eae3012U, 0xb149f83dU, 0x72790bfeU, 0x9424b018U, + 0x20bd9dacU, 0x8175f40dU, 0x5b1b40d7U, 0x40c585ccU, + 0x0215178eU, 0x67284febU, 0xf51ce979U, 0xfed62872U, + 0x54d480d8U, 0x21fddcadU, 0x64e88ce8U, 0x74fc88f8U, + 0x9021b11cU, 0x1341529fU, 0xe847af64U, 0x9fee7113U, + 0x86b0360aU, 0xec42ae60U, 0x6b274ce7U, 0x4f0a45c3U, + 0x237d5eafU, 0x50d181dcU, 0x71b9c8fdU, 0x92a1331eU, + 0xa15dfc2dU, 0x0f5a5583U, 0xad52ff21U, 0xa418bc28U, + 0xd6f4225aU, 0x75bcc9f9U, 0x430546cfU, 0x05d0d589U, + 0x5e5e00d2U, 0xc520e549U, 0x83f5760fU, 0x362c1abaU, + 0x531142dfU, 0x0ddad781U, 0xcbaf6447U, 0x4e4a04c2U, + 0xe907ee65U, 0x996bf215U, 0x525103deU, 0x97e4731bU, + 0xc8a169e7U, 0xd1ff2efeU, 0x3462561bU, 0x68294147U, + 0xa0d3738fU, 0x144a5e3bU, 0x67e68148U, 0x4d440962U, + 0xcb61aae4U, 0x49410866U, 0xc36ba8ecU, 0x98e57db7U, + 0x33a7941cU, 0x7c384453U, 0x23b3900cU, 0x873eb9a8U, + 0x3fa89710U, 0x0ed4da21U, 0xf9dd24d6U, 0x4a81cb65U, + 0x3bad9614U, 0x69690046U, 0x833bb8acU, 0x9ce07cb3U, + 0x392d1416U, 0x827bf9adU, 0xdf70aff0U, 0x0b919a24U, + 0xb642f499U, 0x89b138a6U, 0x8b31baa4U, 0xf5d227daU, + 0xe1c322ceU, 0x9a65ffb5U, 0xd23fedfdU, 0x400b4b6fU, + 0xd5fa2ffaU, 0x2c7c5003U, 0xf1d726deU, 0x7abdc755U, + 0x5fd08f70U, 0xc22be9edU, 0xbf08b790U, 0x9e60feb1U, + 0x2476520bU, 0xacdc7083U, 0x2133120eU, 0x1ac5df35U, + 0x005b5b2fU, 0x5d500d72U, 0xe343a0ccU, 0x3522171aU, + 0xb4c2769bU, 0xb307b49cU, 0x3067571fU, 0xc5ee2beaU, + 0x91af3ebeU, 0xec8c60c3U, 0xc1eb2aeeU, 0x783d4557U, + 0x468ec869U, 0xad9c3182U, 0x6fec8340U, 0x09111826U, + 0x8e74faa1U, 0x8f34bba0U, 0x0d141922U, 0x6023434fU, + 0x5c104c73U, 0x5e90ce71U, 0xcf64abe0U, 0x797d0456U, + 0x9da03db2U, 0xf612e4d9U, 0x63e3804cU, 0xf752a5d8U, + 0x08515927U, 0x85be3baaU, 0xae5cf281U, 0x3127161eU, + 0x32e7d51dU, 0x3ee8d611U, 0x95aa3fbaU, 0x59550c76U, + 0x569acc79U, 0x02dbd92dU, 0xf89d65d7U, 0xbd883592U, + 0x7037475fU, 0x3c685413U, 0xaf1cb380U, 0xbe48f691U, + 0x529fcd7dU, 0xca21ebe5U, 0xe5c623caU, 0x47ce8968U, + 0xeb49a2c4U, 0x039b982cU, 0xab19b284U, 0xea09e3c5U, + 0x1ec0de31U, 0xf217e5ddU, 0xd4ba6efbU, 0x19051c36U, + 0x079e9928U, 0x1b859e34U, 0x62a3c14dU, 0x7ff88750U, + 0x972abdb8U, 0x178a9d38U, 0x72b7c55dU, 0x8db439a2U, + 0xc0ab6befU, 0x932fbcbcU, 0x8a71fba5U, 0xce24eae1U, + 0xedcc21c2U, 0xdcb06cf3U, 0x0f949b20U, 0xda35eff5U, + 0xa253f18dU, 0x4bc18a64U, 0x9b25beb4U, 0x0c545823U, + 0x110f1e3eU, 0x80fb7bafU, 0xb0c7779fU, 0xe9c920c6U, + 0x386d5517U, 0x6d6c0142U, 0xb98d3496U, 0xd8b56df7U, + 0x926ffdbdU, 0x8cf478a3U, 0x73f7845cU, 0x454e0b6aU, + 0x1d001d32U, 0x4c044863U, 0x58154d77U, 0xa8d97187U, + 0x7432465bU, 0x16cadc39U, 0xc76ea9e8U, 0x150a1f3aU, + 0x104f5f3fU, 0x29391006U, 0xe606e0c9U, 0x011b1a2eU, + 0xfdd825d2U, 0x43cb886cU, 0xfb5da6d4U, 0xc62ee8e9U, + 0x2536130aU, 0xddf02df2U, 0x5bd58e74U, 0x53df8c7cU, + 0x440e4a6bU, 0xa193328eU, 0x555a0f7aU, 0x1c405c33U, + 0xe746a1c8U, 0x48014967U, 0x18455d37U, 0x2bb99204U, + 0x99a53cb6U, 0x0ad1db25U, 0xb8cd7597U, 0x12cfdd3dU, + 0x90ef7fbfU, 0x37a29518U, 0x1f809f30U, 0x3d281512U, + 0xa716b188U, 0xde30eef1U, 0xaa59f385U, 0x2efcd201U, + 0xc4ae6aebU, 0xfc9864d3U, 0x4fc48b60U, 0x867ef8a9U, + 0xe88961c7U, 0x6426424bU, 0xa9993086U, 0x2fbc9300U, + 0x9f20bfb0U, 0x6c2c4043U, 0x3aedd715U, 0x5a95cf75U, + 0x26f6d009U, 0x22f3d10dU, 0xfe18e6d1U, 0xd63aecf9U, + 0xa596338aU, 0xff58a7d0U, 0x2d3c1102U, 0xd9f52cf6U, + 0x7d780552U, 0xe48662cbU, 0x6163024eU, 0x6eacc241U, + 0xd77aadf8U, 0xf49266dbU, 0xe203e1cdU, 0x966afcb9U, + 0xef4ca3c0U, 0xd37facfcU, 0xfa1de7d5U, 0xf09767dfU, + 0xbb0db694U, 0x94ea7ebbU, 0x57da8d78U, 0xb187369eU, + 0x051e1b2aU, 0xa4d6728bU, 0x7eb8c651U, 0x6566034aU, + 0x27b69108U, 0x428bc96dU, 0xd0bf6fffU, 0xdb75aef4U, + 0x7177065eU, 0x045e5a2bU, 0x414b0a6eU, 0x515f0e7eU, + 0xb582379aU, 0x36e2d419U, 0xcde429e2U, 0xba4df795U, + 0xa313b08cU, 0xc9e128e6U, 0x4e84ca61U, 0x6aa9c345U, + 0x06ded829U, 0x7572075aU, 0x541a4e7bU, 0xb702b598U, + 0x84fe7aabU, 0x2af9d305U, 0x88f179a7U, 0x81bb3aaeU, + 0xf357a4dcU, 0x501f4f7fU, 0x66a6c049U, 0x2073530fU, + 0x7bfd8654U, 0xe08363cfU, 0xa656f089U, 0x138f9c3cU, + 0x76b2c459U, 0x28795107U, 0xee0ce2c1U, 0x6be98244U, + 0xcca468e3U, 0xbcc87493U, 0x77f28558U, 0xb247f59dU, + 0x548dd957U, 0x4dd39e4eU, 0xa84ee6abU, 0xf405f1f7U, + 0x3cffc33fU, 0x8866ee8bU, 0xfbca31f8U, 0xd168b9d2U, + 0x574d1a54U, 0xd56db8d6U, 0x5f47185cU, 0x04c9cd07U, + 0xaf8b24acU, 0xe014f4e3U, 0xbf9f20bcU, 0x1b120918U, + 0xa38427a0U, 0x92f86a91U, 0x65f19466U, 0xd6ad7bd5U, + 0xa78126a4U, 0xf545b0f6U, 0x1f17081cU, 0x00cccc03U, + 0xa501a4a6U, 0x1e57491dU, 0x435c1f40U, 0x97bd2a94U, + 0x2a6e4429U, 0x159d8816U, 0x171d0a14U, 0x69fe976aU, + 0x7def927eU, 0x06494f05U, 0x4e135d4dU, 0xdc27fbdfU, + 0x49d69f4aU, 0xb050e0b3U, 0x6dfb966eU, 0xe69177e5U, + 0xc3fc3fc0U, 0x5e07595dU, 0x23240720U, 0x024c4e01U, + 0xb85ae2bbU, 0x30f0c033U, 0xbd1fa2beU, 0x86e96f85U, + 0x9c77eb9fU, 0xc17cbdc2U, 0x7f6f107cU, 0xa90ea7aaU, + 0x28eec62bU, 0x2f2b042cU, 0xac4be7afU, 0x59c29b5aU, + 0x0d838e0eU, 0x70a0d073U, 0x5dc79a5eU, 0xe411f5e7U, + 0xdaa278d9U, 0x31b08132U, 0xf3c033f0U, 0x953da896U, + 0x12584a11U, 0x13180b10U, 0x9138a992U, 0xfc0ff3ffU, + 0xc03cfcc3U, 0xc2bc7ec1U, 0x53481b50U, 0xe551b4e6U, + 0x018c8d02U, 0x6a3e5469U, 0xffcf30fcU, 0x6b7e1568U, + 0x947de997U, 0x19928b1aU, 0x32704231U, 0xad0ba6aeU, + 0xaecb65adU, 0xa2c466a1U, 0x09868f0aU, 0xc579bcc6U, + 0xcab67cc9U, 0x9ef7699dU, 0x64b1d567U, 0x21a48522U, + 0xec1bf7efU, 0xa044e4a3U, 0x33300330U, 0x22644621U, + 0xceb37dcdU, 0x560d5b55U, 0x79ea937aU, 0xdbe239d8U, + 0x77651274U, 0x9fb7289cU, 0x37350234U, 0x76255375U, + 0x82ec6e81U, 0x6e3b556dU, 0x4896de4bU, 0x8529ac86U, + 0x9bb22998U, 0x87a92e84U, 0xfe8f71fdU, 0xe3d437e0U, + 0x0b060d08U, 0x8ba62d88U, 0xee9b75edU, 0x11988912U, + 0x5c87db5fU, 0x0f030c0cU, 0x165d4b15U, 0x52085a51U, + 0x71e09172U, 0x409cdc43U, 0x93b82b90U, 0x46195f45U, + 0x3e7f413dU, 0xd7ed3ad4U, 0x07090e04U, 0x9078e893U, + 0x8d23ae8eU, 0x1cd7cb1fU, 0x2cebc72fU, 0x75e59076U, + 0xa441e5a7U, 0xf140b1f2U, 0x25a18426U, 0x4499dd47U, + 0x0e434d0dU, 0x10d8c813U, 0xefdb34ecU, 0xd962bbdaU, + 0x812cad82U, 0xd028f8d3U, 0xc439fdc7U, 0x34f5c137U, + 0xe81ef6ebU, 0x8ae66c89U, 0x5b421958U, 0x8926af8aU, + 0x8c63ef8fU, 0xb515a0b6U, 0x7a2a5079U, 0x9d37aa9eU, + 0x61f49562U, 0xdfe738dcU, 0x67711664U, 0x5a025859U, + 0xb91aa3baU, 0x41dc9d42U, 0xc7f93ec4U, 0xcff33cccU, + 0xd822fadbU, 0x3dbf823eU, 0xc976bfcaU, 0x806cec83U, + 0x7b6a1178U, 0xd42df9d7U, 0x8469ed87U, 0xb79522b4U, + 0x05898c06U, 0x96fd6b95U, 0x24e1c527U, 0x8ee36d8dU, + 0x0cc3cf0fU, 0xab8e25a8U, 0x83ac2f80U, 0xa104a5a2U, + 0x3b3a0138U, 0x421c5e41U, 0x36754335U, 0xb2d062b1U, + 0x5882da5bU, 0x60b4d463U, 0xd3e83bd0U, 0x1a524819U, + 0x74a5d177U, 0xf80af2fbU, 0x35b58036U, 0xb39023b0U, + 0x030c0f00U, 0xf000f0f3U, 0xa6c167a5U, 0xc6b97fc5U, + 0xbada60b9U, 0xbedf61bdU, 0x62345661U, 0x4a165c49U, + 0x39ba833aU, 0x63741760U, 0xb110a1b2U, 0x45d99c46U, + 0xe154b5e2U, 0x78aad27bU, 0xfd4fb2feU, 0xf28072f1U, + 0x4b561d48U, 0x68bed66bU, 0x7e2f517dU, 0x0a464c09U, + 0x73601370U, 0x4f531c4cU, 0x66315765U, 0x6cbbd76fU, + 0x27210624U, 0x08c6ce0bU, 0xcbf63dc8U, 0x2dab862eU, + 0x9932ab9aU, 0x38fac23bU, 0xe29476e1U, 0xf94ab3faU, + 0xbb9a21b8U, 0xdea779ddU, 0x4c93df4fU, 0x47591e44U, + 0xed5bb6eeU, 0x9872ea9bU, 0xdd67badeU, 0xcd73beceU, + 0x29ae872aU, 0xaace64a9U, 0x51c89952U, 0x26614725U, + 0x3f3f003cU, 0x55cd9856U, 0xd2a87ad1U, 0xf68573f5U, + 0x9af26899U, 0xe95eb7eaU, 0xc836fecbU, 0x2b2e0528U, + 0x18d2ca1bU, 0xb6d563b5U, 0x14ddc917U, 0x1d978a1eU, + 0x6f7b146cU, 0xcc33ffcfU, 0xfa8a70f9U, 0xbc5fe3bfU, + 0xe7d136e4U, 0x7cafd37fU, 0x3a7a4039U, 0x8fa32c8cU, + 0xea9e74e9U, 0xb455e1b7U, 0x72205271U, 0xf7c532f4U, + 0x5088d853U, 0x20e4c423U, 0xebde35e8U, 0x2e6b452dU, + 0x58722aa4U, 0x412c6dbdU, 0xa4b11558U, 0xf8fa0204U, + 0x300030ccU, 0x84991d78U, 0xf735c20bU, 0xdd974a21U, + 0x5bb2e9a7U, 0xd9924b25U, 0x53b8ebafU, 0x08363ef4U, + 0xa374d75fU, 0xeceb0710U, 0xb360d34fU, 0x17edfaebU, + 0xaf7bd453U, 0x9e079962U, 0x690e6795U, 0xda528826U, + 0xab7ed557U, 0xf9ba4305U, 0x13e8fbefU, 0x0c333ff0U, + 0xa9fe5755U, 0x12a8baeeU, 0x4fa3ecb3U, 0x9b42d967U, + 0x2691b7daU, 0x19627be5U, 0x1be2f9e7U, 0x65016499U, + 0x7110618dU, 0x0ab6bcf6U, 0x42ecaebeU, 0xd0d8082cU, + 0x45296cb9U, 0xbcaf1340U, 0x6104659dU, 0xea6e8416U, + 0xcf03cc33U, 0x52f8aaaeU, 0x2fdbf4d3U, 0x0eb3bdf2U, + 0xb4a51148U, 0x3c0f33c0U, 0xb1e0514dU, 0x8a169c76U, + 0x9088186cU, 0xcd834e31U, 0x7390e38fU, 0xa5f15459U, + 0x241135d8U, 0x23d4f7dfU, 0xa0b4145cU, 0x553d68a9U, + 0x017c7dfdU, 0x7c5f2380U, 0x513869adU, 0xe8ee0614U, + 0xd65d8b2aU, 0x3d4f72c1U, 0xff3fc003U, 0x99c25b65U, + 0x1ea7b9e2U, 0x1fe7f8e3U, 0x9dc75a61U, 0xf0f0000cU, + 0xccc30f30U, 0xce438d32U, 0x5fb7e8a3U, 0xe9ae4715U, + 0x0d737ef1U, 0x66c1a79aU, 0xf330c30fU, 0x6781e69bU, + 0x98821a64U, 0x156d78e9U, 0x3e8fb1c2U, 0xa1f4555dU, + 0xa234965eU, 0xae3b9552U, 0x05797cf9U, 0xc9864f35U, + 0xc6498f3aU, 0x92089a6eU, 0x684e2694U, 0x2d5b76d1U, + 0xe0e4041cU, 0xacbb1750U, 0x3fcff0c3U, 0x2e9bb5d2U, + 0xc24c8e3eU, 0x5af2a8a6U, 0x75156089U, 0xd71dca2bU, + 0x7b9ae187U, 0x9348db6fU, 0x3bcaf1c7U, 0x7adaa086U, + 0x8e139d72U, 0x62c4a69eU, 0x44692db8U, 0x89d65f75U, + 0x974dda6bU, 0x8b56dd77U, 0xf270820eU, 0xef2bc413U, + 0x07f9fefbU, 0x8759de7bU, 0xe264861eU, 0x1d677ae1U, + 0x507828acU, 0x03fcffffU, 0x1aa2b8e6U, 0x5ef7a9a2U, + 0x7d1f6281U, 0x4c632fb0U, 0x9f47d863U, 0x4ae6acb6U, + 0x3280b2ceU, 0xdb12c927U, 0x0bf6fdf7U, 0x9c871b60U, + 0x81dc5d7dU, 0x102838ecU, 0x201434dcU, 0x791a6385U, + 0xa8be1654U, 0xfdbf4201U, 0x295e77d5U, 0x48662eb4U, + 0x02bcbefeU, 0x1c273be0U, 0xe324c71fU, 0xd59d4829U, + 0x8dd35e71U, 0xdcd70b20U, 0xc8c60e34U, 0x380a32c4U, + 0xe4e10518U, 0x86199f7aU, 0x57bdeaabU, 0x85d95c79U, + 0x809c1c7cU, 0xb9ea5345U, 0x76d5a38aU, 0x91c8596dU, + 0x6d0b6691U, 0xd318cb2fU, 0x6b8ee597U, 0x56fdabaaU, + 0xb5e55049U, 0x4d236eb1U, 0xcb06cd37U, 0xc30ccf3fU, + 0xd4dd0928U, 0x314071cdU, 0xc5894c39U, 0x8c931f70U, + 0x7795e28bU, 0xd8d20a24U, 0x88961e74U, 0xbb6ad147U, + 0x09767ff5U, 0x9a029866U, 0x281e36d4U, 0x821c9e7eU, + 0x003c3cfcU, 0xa771d65bU, 0x8f53dc73U, 0xadfb5651U, + 0x37c5f2cbU, 0x4ee3adb2U, 0x3a8ab0c6U, 0xbe2f9142U, + 0x547d29a8U, 0x6c4b2790U, 0xdf17c823U, 0x16adbbeaU, + 0x785a2284U, 0xf4f50108U, 0x394a73c5U, 0xbf6fd043U, + 0x0ff3fcf3U, 0xfcff0300U, 0xaa3e9456U, 0xca468c36U, + 0xb625934aU, 0xb220924eU, 0x6ecba592U, 0x46e9afbaU, + 0x354570c9U, 0x6f8be493U, 0xbdef5241U, 0x49266fb5U, + 0xedab4611U, 0x74552188U, 0xf1b0410dU, 0xfe7f8102U, + 0x47a9eebbU, 0x64412598U, 0x72d0a28eU, 0x06b9bffaU, + 0x7f9fe083U, 0x43acefbfU, 0x6acea496U, 0x6044249cU, + 0x2bdef5d7U, 0x04393df8U, 0xc709ce3bU, 0x215475ddU, + 0x95cd5869U, 0x340531c8U, 0xee6b8512U, 0xf5b54009U, + 0xb765d24bU, 0xd2588a2eU, 0x406c2cbcU, 0x4ba6edb7U, + 0xe1a4451dU, 0x948d1968U, 0xd198492dU, 0xc18c4d3dU, + 0x255174d9U, 0xa631975aU, 0x5d376aa1U, 0x2a9eb4d6U, + 0x33c0f3cfU, 0x59326ba5U, 0xde578922U, 0xfa7a8006U, + 0x960d9b6aU, 0xe5a14419U, 0xc4c90d38U, 0x27d1f6dbU, + 0x142d39e8U, 0xba2a9046U, 0x18223ae4U, 0x116879edU, + 0x6384e79fU, 0xc0cc0c3cU, 0xf675830aU, 0xb0a0104cU, + 0xeb2ec517U, 0x7050208cU, 0x3685b3caU, 0x835cdf7fU, + 0xe661871aU, 0xb8aa1244U, 0x7edfa182U, 0xfb3ac107U, + 0x5c772ba0U, 0x2c1b37d0U, 0xe721c61bU, 0x2294b6deU, + 0x99e57cf2U, 0x80bb3bebU, 0x6526430eU, 0x396d5452U, + 0xf197669aU, 0x450e4b2eU, 0x36a2945dU, 0x1c001c77U, + 0x9a25bff1U, 0x18051d73U, 0x922fbdf9U, 0xc9a168a2U, + 0x62e38109U, 0x2d7c5146U, 0x72f78519U, 0xd67aacbdU, + 0x6eec8205U, 0x5f90cf34U, 0xa89931c3U, 0x1bc5de70U, + 0x6ae98301U, 0x382d1553U, 0xd27fadb9U, 0xcda469a6U, + 0x68690103U, 0xd33fecb8U, 0x8e34bae5U, 0x5ad58f31U, + 0xe706e18cU, 0xd8f52db3U, 0xda75afb1U, 0xa49632cfU, + 0xb08737dbU, 0xcb21eaa0U, 0x837bf8e8U, 0x114f5e7aU, + 0x84be3aefU, 0x7d384516U, 0xa09333cbU, 0x2bf9d240U, + 0x0e949a65U, 0x936ffcf8U, 0xee4ca285U, 0xcf24eba4U, + 0x7532471eU, 0xfd986596U, 0x7077071bU, 0x4b81ca20U, + 0x511f4e3aU, 0x0c141867U, 0xb207b5d9U, 0x6466020fU, + 0xe586638eU, 0xe243a189U, 0x6123420aU, 0x94aa3effU, + 0xc0eb2babU, 0xbdc875d6U, 0x90af3ffbU, 0x29795042U, + 0x17cadd7cU, 0xfcd82497U, 0x3ea89655U, 0x58550d33U, + 0xdf30efb4U, 0xde70aeb5U, 0x5c500c37U, 0x3167565aU, + 0x0d545966U, 0x0fd4db64U, 0x9e20bef5U, 0x28391143U, + 0xcce428a7U, 0xa756f1ccU, 0x32a79559U, 0xa616b0cdU, + 0x59154c32U, 0xd4fa2ebfU, 0xff18e794U, 0x6063030bU, + 0x63a3c008U, 0x6facc304U, 0xc4ee2aafU, 0x08111963U, + 0x07ded96cU, 0x539fcc38U, 0xa9d970c2U, 0xeccc2087U, + 0x2173524aU, 0x6d2c4106U, 0xfe58a695U, 0xef0ce384U, + 0x03dbd868U, 0x9b65fef0U, 0xb48236dfU, 0x168a9c7dU, + 0xba0db7d1U, 0x52df8d39U, 0xfa5da791U, 0xbb4df6d0U, + 0x4f84cb24U, 0xa353f0c8U, 0x85fe7beeU, 0x48410923U, + 0x56da8c3dU, 0x4ac18b21U, 0x33e7d458U, 0x2ebc9245U, + 0xc66ea8adU, 0x46ce882dU, 0x23f3d048U, 0xdcf02cb7U, + 0x91ef7efaU, 0xc26ba9a9U, 0xdb35eeb0U, 0x9f60fff4U, + 0xbc8834d7U, 0x8df479e6U, 0x5ed08e35U, 0x8b71fae0U, + 0xf317e498U, 0x1a859f71U, 0xca61aba1U, 0x5d104d36U, + 0x404b0b2bU, 0xd1bf6ebaU, 0xe183628aU, 0xb88d35d3U, + 0x69294002U, 0x3c281457U, 0xe8c92183U, 0x89f178e2U, + 0xc32be8a8U, 0xddb06db6U, 0x22b39149U, 0x140a1e7fU, + 0x4c440827U, 0x1d405d76U, 0x09515862U, 0xf99d6492U, + 0x2576534eU, 0x478ec92cU, 0x962abcfdU, 0x444e0a2fU, + 0x410b4a2aU, 0x787d0513U, 0xb742f5dcU, 0x505f0f3bU, + 0xac9c30c7U, 0x128f9d79U, 0xaa19b3c1U, 0x976afdfcU, + 0x7472061fU, 0x8cb438e7U, 0x0a919b61U, 0x029b9969U, + 0x154a5f7eU, 0xf0d7279bU, 0x041e1a6fU, 0x4d044926U, + 0xb602b4ddU, 0x19455c72U, 0x49014822U, 0x7afd8711U, + 0xc8e129a3U, 0x5b95ce30U, 0xe9896082U, 0x438bc828U, + 0xc1ab6aaaU, 0x66e6800dU, 0x4ec48a25U, 0x6c6c0007U, + 0xf652a49dU, 0x8f74fbe4U, 0xfb1de690U, 0x7fb8c714U, + 0x95ea7ffeU, 0xaddc71c6U, 0x1e809e75U, 0xd73aedbcU, + 0xb9cd74d2U, 0x3562575eU, 0xf8dd2593U, 0x7ef88615U, + 0xce64aaa5U, 0x3d685556U, 0x6ba9c200U, 0x0bd1da60U, + 0x77b2c51cU, 0x73b7c418U, 0xaf5cf3c4U, 0x877ef9ecU, + 0xf4d2269fU, 0xae1cb2c5U, 0x7c780417U, 0x88b139e3U, + 0x2c3c1047U, 0xb5c277deU, 0x3027175bU, 0x3fe8d754U, + 0x863eb8edU, 0xa5d673ceU, 0xb347f4d8U, 0xc72ee9acU, + 0xbe08b6d5U, 0x823bb9e9U, 0xab59f2c0U, 0xa1d372caU, + 0xea49a381U, 0xc5ae6baeU, 0x069e986dU, 0xe0c3238bU, + 0x545a0e3fU, 0xf592679eU, 0x2ffcd344U, 0x3422165fU, + 0x76f2841dU, 0x13cfdc78U, 0x81fb7aeaU, 0x8a31bbe1U, + 0x2033134bU, 0x551a4f3eU, 0x100f1f7bU, 0x001b1b6bU, + 0xe4c6228fU, 0x67a6c10cU, 0x9ca03cf7U, 0xeb09e280U, + 0xf257a599U, 0x98a53df3U, 0x1fc0df74U, 0x3bedd650U, + 0x579acd3cU, 0x2436124fU, 0x055e5b6eU, 0xe646a08dU, + 0xd5ba6fbeU, 0x7bbdc610U, 0xd9b56cb2U, 0xd0ff2fbbU, + 0xa213b1c9U, 0x015b5a6aU, 0x37e2d55cU, 0x7137461aU, + 0x2ab99341U, 0xb1c776daU, 0xf712e59cU, 0x42cb8929U, + 0x27f6d14cU, 0x793d4412U, 0xbf48f7d4U, 0x3aad9751U, + 0x9de07df6U, 0xed8c6186U, 0x26b6904dU, 0xe303e088U, + 0xe1fd1c92U, 0xf8a35b8bU, 0x1d3e236eU, 0x41753432U, + 0x898f06faU, 0x3d162b4eU, 0x4ebaf43dU, 0x64187c17U, + 0xe23ddf91U, 0x601d7d13U, 0xea37dd99U, 0xb1b908c2U, + 0x1afbe169U, 0x55643126U, 0x0aefe579U, 0xae62ccddU, + 0x16f4e265U, 0x2788af54U, 0xd08151a3U, 0x63ddbe10U, + 0x12f1e361U, 0x40357533U, 0xaa67cdd9U, 0xb5bc09c6U, + 0x10716163U, 0xab278cd8U, 0xf62cda85U, 0x22cdef51U, + 0x9f1e81ecU, 0xa0ed4dd3U, 0xa26dcfd1U, 0xdc8e52afU, + 0xc89f57bbU, 0xb3398ac0U, 0xfb639888U, 0x69573e1aU, + 0xfca65a8fU, 0x05202576U, 0xd88b53abU, 0x53e1b220U, + 0x768cfa05U, 0xeb779c98U, 0x9654c2e5U, 0xb73c8bc4U, + 0x0d2a277eU, 0x858005f6U, 0x086f677bU, 0x3399aa40U, + 0x29072e5aU, 0x740c7807U, 0xca1fd5b9U, 0x1c7e626fU, + 0x9d9e03eeU, 0x9a5bc1e9U, 0x193b226aU, 0xecb25e9fU, + 0xb8f34bcbU, 0xc5d015b6U, 0xe8b75f9bU, 0x51613022U, + 0x6fd2bd1cU, 0x84c044f7U, 0x46b0f635U, 0x204d6d53U, + 0xa7288fd4U, 0xa668ced5U, 0x24486c57U, 0x497f363aU, + 0x754c3906U, 0x77ccbb04U, 0xe638de95U, 0x50217123U, + 0xb4fc48c7U, 0xdf4e91acU, 0x4abff539U, 0xde0ed0adU, + 0x210d2c52U, 0xace24edfU, 0x870087f4U, 0x187b636bU, + 0x1bbba068U, 0x17b4a364U, 0xbcf64acfU, 0x70097903U, + 0x7fc6b90cU, 0x2b87ac58U, 0xd1c110a2U, 0x94d440e7U, + 0x596b322aU, 0x15342166U, 0x8640c6f5U, 0x971483e4U, + 0x7bc3b808U, 0xe37d9e90U, 0xcc9a56bfU, 0x6e92fc1dU, + 0xc215d7b1U, 0x2ac7ed59U, 0x8245c7f1U, 0xc35596b0U, + 0x379cab44U, 0xdb4b90a8U, 0xfde61b8eU, 0x30596943U, + 0x2ec2ec5dU, 0x32d9eb41U, 0x4bffb438U, 0x56a4f225U, + 0xbe76c8cdU, 0x3ed6e84dU, 0x5bebb028U, 0xa4e84cd7U, + 0xe9f71e9aU, 0xba73c9c9U, 0xa32d8ed0U, 0xe7789f94U, + 0xc49054b7U, 0xf5ec1986U, 0x26c8ee55U, 0xf3699a80U, + 0x8b0f84f8U, 0x629dff11U, 0xb279cbc1U, 0x25082d56U, + 0x38536b4bU, 0xa9a70edaU, 0x999b02eaU, 0xc09555b3U, + 0x11312062U, 0x44307437U, 0x90d141e3U, 0xf1e91882U, + 0xbb3388c8U, 0xa5a80dd6U, 0x5aabf129U, 0x6c127e1fU, + 0x345c6847U, 0x65583d16U, 0x71493802U, 0x818504f2U, + 0x5d6e332eU, 0x3f96a94cU, 0xee32dc9dU, 0x3c566a4fU, + 0x39132a4aU, 0x00656573U, 0xcf5a95bcU, 0x28476f5bU, + 0xd48450a7U, 0x6a97fd19U, 0xd201d3a1U, 0xef729d9cU, + 0x0c6a667fU, 0xf4ac5887U, 0x7289fb01U, 0x7a83f909U, + 0x6d523f1eU, 0x88cf47fbU, 0x7c067a0fU, 0x351c2946U, + 0xce1ad4bdU, 0x615d3c12U, 0x31192842U, 0x02e5e771U, + 0xb0f949c3U, 0x238dae50U, 0x919100e2U, 0x3b93a848U, + 0xb9b30acaU, 0x1efee06dU, 0x36dcea45U, 0x14746067U, + 0x8e4ac4fdU, 0xf76c9b84U, 0x830586f0U, 0x07a0a774U, + 0xedf21f9eU, 0xd5c411a6U, 0x6698fe15U, 0xaf228ddcU, + 0xc1d514b2U, 0x4d7a373eU, 0x80c545f3U, 0x06e0e675U, + 0xb67ccac5U, 0x45703536U, 0x13b1a260U, 0x73c9ba00U, + 0x0faaa57cU, 0x0bafa478U, 0xd74493a4U, 0xff66998cU, + 0x8cca46ffU, 0xd604d2a5U, 0x04606477U, 0xf0a95983U, + 0x54247027U, 0xcdda17beU, 0x483f773bU, 0x47f0b734U, + 0xfe26d88dU, 0xddce13aeU, 0xcb5f94b8U, 0xbf3689ccU, + 0xc610d6b5U, 0xfa23d989U, 0xd34192a0U, 0xd9cb12aaU, + 0x9251c3e1U, 0xbdb60bceU, 0x7e86f80dU, 0x98db43ebU, + 0x2c426e5fU, 0x8d8a07feU, 0x57e4b324U, 0x4c3a763fU, + 0x0eeae47dU, 0x6bd7bc18U, 0xf9e31a8aU, 0xf229db81U, + 0x582b732bU, 0x2d022f5eU, 0x68177f1bU, 0x78037b0bU, + 0x9cde42efU, 0x1fbea16cU, 0xe4b85c97U, 0x931182e0U, + 0x8a4fc5f9U, 0xe0bd5d93U, 0x67d8bf14U, 0x43f5b630U, + 0x2f82ad5cU, 0x5c2e722fU, 0x7d463b0eU, 0x9e5ec0edU, + 0xada20fdeU, 0x03a5a670U, 0xa1ad0cd2U, 0xa8e74fdbU, + 0xda0bd1a9U, 0x79433a0aU, 0x4ffab53cU, 0x092f267aU, + 0x52a1f321U, 0xc9df16baU, 0x8f0a85fcU, 0x3ad3e949U, + 0x5feeb12cU, 0x01252472U, 0xc75097b4U, 0x42b5f731U, + 0xe5f81d96U, 0x959401e6U, 0x5eaef02dU, 0x9b1b80e8U, + 0x82e260eeU, 0x9bbc27f7U, 0x7e215f12U, 0x226a484eU, + 0xea907a86U, 0x5e095732U, 0x2da58841U, 0x0707006bU, + 0x8122a3edU, 0x0302016fU, 0x8928a1e5U, 0xd2a674beU, + 0x79e49d15U, 0x367b4d5aU, 0x69f09905U, 0xcd7db0a1U, + 0x75eb9e19U, 0x4497d328U, 0xb39e2ddfU, 0x00c2c26cU, + 0x71ee9f1dU, 0x232a094fU, 0xc978b1a5U, 0xd6a375baU, + 0x736e1d1fU, 0xc838f0a4U, 0x9533a6f9U, 0x41d2932dU, + 0xfc01fd90U, 0xc3f231afU, 0xc172b3adU, 0xbf912ed3U, + 0xab802bc7U, 0xd026f6bcU, 0x987ce4f4U, 0x0a484266U, + 0x9fb926f3U, 0x663f590aU, 0xbb942fd7U, 0x30fece5cU, + 0x15938679U, 0x8868e0e4U, 0xf54bbe99U, 0xd423f7b8U, + 0x6e355b02U, 0xe69f798aU, 0x6b701b07U, 0x5086d63cU, + 0x4a185226U, 0x1713047bU, 0xa900a9c5U, 0x7f611e13U, + 0xfe817f92U, 0xf944bd95U, 0x7a245e16U, 0x8fad22e3U, + 0xdbec37b7U, 0xa6cf69caU, 0x8ba823e7U, 0x327e4c5eU, + 0x0ccdc160U, 0xe7df388bU, 0x25af8a49U, 0x4352112fU, + 0xc437f3a8U, 0xc577b2a9U, 0x4757102bU, 0x2a604a46U, + 0x1653457aU, 0x14d3c778U, 0x8527a2e9U, 0x333e0d5fU, + 0xd7e334bbU, 0xbc51edd0U, 0x29a08945U, 0xbd11acd1U, + 0x4212502eU, 0xcffd32a3U, 0xe41ffb88U, 0x7b641f17U, + 0x78a4dc14U, 0x74abdf18U, 0xdfe936b3U, 0x1316057fU, + 0x1cd9c570U, 0x4898d024U, 0xb2de6cdeU, 0xf7cb3c9bU, + 0x3a744e56U, 0x762b5d1aU, 0xe55fba89U, 0xf40bff98U, + 0x18dcc474U, 0x8062e2ecU, 0xaf852ac3U, 0x0d8d8061U, + 0xa10aabcdU, 0x49d89125U, 0xe15abb8dU, 0xa04aeaccU, + 0x5483d738U, 0xb854ecd4U, 0x9ef967f2U, 0x5346153fU, + 0x4ddd9021U, 0x51c6973dU, 0x28e0c844U, 0x35bb8e59U, + 0xdd69b4b1U, 0x5dc99431U, 0x38f4cc54U, 0xc7f730abU, + 0x8ae862e6U, 0xd96cb5b5U, 0xc032f2acU, 0x8467e3e8U, + 0xa78f28cbU, 0x96f365faU, 0x45d79229U, 0x9076e6fcU, + 0xe810f884U, 0x0182836dU, 0xd166b7bdU, 0x4617512aU, + 0x5b4c1737U, 0xcab872a6U, 0xfa847e96U, 0xa38a29cfU, + 0x722e5c1eU, 0x272f084bU, 0xf3ce3d9fU, 0x92f664feU, + 0xd82cf4b4U, 0xc6b771aaU, 0x39b48d55U, 0x0f0d0263U, + 0x5743143bU, 0x0647416aU, 0x1256447eU, 0xe29a788eU, + 0x3e714f52U, 0x5c89d530U, 0x8d2da0e1U, 0x5f491633U, + 0x5a0c5636U, 0x637a190fU, 0xac45e9c0U, 0x4b581327U, + 0xb79b2cdbU, 0x09888165U, 0xb11eafddU, 0x8c6de1e0U, + 0x6f751a03U, 0x97b324fbU, 0x1196877dU, 0x199c8575U, + 0x0e4d4362U, 0xebd03b87U, 0x1f190673U, 0x5603553aU, + 0xad05a8c1U, 0x0242406eU, 0x5206543eU, 0x61fa9b0dU, + 0xd3e635bfU, 0x4092d22cU, 0xf28e7c9eU, 0x588cd434U, + 0xdaac76b6U, 0x7de19c11U, 0x55c39639U, 0x776b1c1bU, + 0xed55b881U, 0x9473e7f8U, 0xe01afa8cU, 0x64bfdb08U, + 0x8eed63e2U, 0xb6db6ddaU, 0x05878269U, 0xcc3df1a0U, + 0xa2ca68ceU, 0x2e654b42U, 0xe3da398fU, 0x65ff9a09U, + 0xd563b6b9U, 0x266f494aU, 0x70aede1cU, 0x10d6c67cU, + 0x6cb5d900U, 0x68b0d804U, 0xb45befd8U, 0x9c79e5f0U, + 0xefd53a83U, 0xb51baed9U, 0x677f180bU, 0x93b625ffU, + 0x373b0c5bU, 0xaec56bc2U, 0x2b200b47U, 0x24efcb48U, + 0x9d39a4f1U, 0xbed16fd2U, 0xa840e8c4U, 0xdc29f5b0U, + 0xa50faac9U, 0x993ca5f5U, 0xb05eeedcU, 0xbad46ed6U, + 0xf14ebf9dU, 0xdea977b2U, 0x1d998471U, 0xfbc43f97U, + 0x4f5d1223U, 0xee957b82U, 0x34fbcf58U, 0x2f250a43U, + 0x6df59801U, 0x08c8c064U, 0x9afc66f6U, 0x9136a7fdU, + 0x3b340f57U, 0x4e1d5322U, 0x0b080367U, 0x1b1c0777U, + 0xffc13e93U, 0x7ca1dd10U, 0x87a720ebU, 0xf00efe9cU, + 0xe950b985U, 0x83a221efU, 0x04c7c368U, 0x20eaca4cU, + 0x4c9dd120U, 0x3f310e53U, 0x1e594772U, 0xfd41bc91U, + 0xcebd73a2U, 0x60bada0cU, 0xc2b270aeU, 0xcbf833a7U, + 0xb914add5U, 0x1a5c4676U, 0x2ce5c940U, 0x6a305a06U, + 0x31be8f5dU, 0xaac06ac6U, 0xec15f980U, 0x59cc9535U, + 0x3cf1cd50U, 0x623a580eU, 0xa44febc8U, 0x21aa8b4dU, + 0x86e761eaU, 0xf68b7d9aU, 0x3db18c51U, 0xf804fc94U, + 0x87e364eaU, 0x9ebd23f3U, 0x7b205b16U, 0x276b4c4aU, + 0xef917e82U, 0x5b085336U, 0x28a48c45U, 0x0206046fU, + 0x8423a7e9U, 0x0603056bU, 0x8c29a5e1U, 0xd7a770baU, + 0x7ce59911U, 0x337a495eU, 0x6cf19d01U, 0xc87cb4a5U, + 0x70ea9a1dU, 0x4196d72cU, 0xb69f29dbU, 0x05c3c668U, + 0x74ef9b19U, 0x262b0d4bU, 0xcc79b5a1U, 0xd3a271beU, + 0x766f191bU, 0xcd39f4a0U, 0x9032a2fdU, 0x44d39729U, + 0xf900f994U, 0xc6f335abU, 0xc473b7a9U, 0xba902ad7U, + 0xae812fc3U, 0xd527f2b8U, 0x9d7de0f0U, 0x0f494662U, + 0x9ab822f7U, 0x633e5d0eU, 0xbe952bd3U, 0x35ffca58U, + 0x1092827dU, 0x8d69e4e0U, 0xf04aba9dU, 0xd122f3bcU, + 0x6b345f06U, 0xe39e7d8eU, 0x6e711f03U, 0x5587d238U, + 0x4f195622U, 0x1212007fU, 0xac01adc1U, 0x7a601a17U, + 0xfb807b96U, 0xfc45b991U, 0x7f255a12U, 0x8aac26e7U, + 0xdeed33b3U, 0xa3ce6dceU, 0x8ea927e3U, 0x377f485aU, + 0x09ccc564U, 0xe2de3c8fU, 0x20ae8e4dU, 0x4653152bU, + 0xc136f7acU, 0xc076b6adU, 0x4256142fU, 0x2f614e42U, + 0x1352417eU, 0x11d2c37cU, 0x8026a6edU, 0x363f095bU, + 0xd2e230bfU, 0xb950e9d4U, 0x2ca18d41U, 0xb810a8d5U, + 0x4713542aU, 0xcafc36a7U, 0xe11eff8cU, 0x7e651b13U, + 0x7da5d810U, 0x71aadb1cU, 0xdae832b7U, 0x1617017bU, + 0x19d8c174U, 0x4d99d420U, 0xb7df68daU, 0xf2ca389fU, + 0x3f754a52U, 0x732a591eU, 0xe05ebe8dU, 0xf10afb9cU, + 0x1dddc070U, 0x8563e6e8U, 0xaa842ec7U, 0x088c8465U, + 0xa40bafc9U, 0x4cd99521U, 0xe45bbf89U, 0xa54beec8U, + 0x5182d33cU, 0xbd55e8d0U, 0x9bf863f6U, 0x5647113bU, + 0x48dc9425U, 0x54c79339U, 0x2de1cc40U, 0x30ba8a5dU, + 0xd868b0b5U, 0x58c89035U, 0x3df5c850U, 0xc2f634afU, + 0x8fe966e2U, 0xdc6db1b1U, 0xc533f6a8U, 0x8166e7ecU, + 0xa28e2ccfU, 0x93f261feU, 0x40d6962dU, 0x9577e2f8U, + 0xed11fc80U, 0x04838769U, 0xd467b3b9U, 0x4316552eU, + 0x5e4d1333U, 0xcfb976a2U, 0xff857a92U, 0xa68b2dcbU, + 0x772f581aU, 0x222e0c4fU, 0xf6cf399bU, 0x97f760faU, + 0xdd2df0b0U, 0xc3b675aeU, 0x3cb58951U, 0x0a0c0667U, + 0x5242103fU, 0x0346456eU, 0x1757407aU, 0xe79b7c8aU, + 0x3b704b56U, 0x5988d134U, 0x882ca4e5U, 0x5a481237U, + 0x5f0d5232U, 0x667b1d0bU, 0xa944edc4U, 0x4e591723U, + 0xb29a28dfU, 0x0c898561U, 0xb41fabd9U, 0x896ce5e4U, + 0x6a741e07U, 0x92b220ffU, 0x14978379U, 0x1c9d8171U, + 0x0b4c4766U, 0xeed13f83U, 0x1a180277U, 0x5302513eU, + 0xa804acc5U, 0x0743446aU, 0x5707503aU, 0x64fb9f09U, + 0xd6e731bbU, 0x4593d628U, 0xf78f789aU, 0x5d8dd030U, + 0xdfad72b2U, 0x78e09815U, 0x50c2923dU, 0x726a181fU, + 0xe854bc85U, 0x9172e3fcU, 0xe51bfe88U, 0x61bedf0cU, + 0x8bec67e6U, 0xb3da69deU, 0x0086866dU, 0xc93cf5a4U, + 0xa7cb6ccaU, 0x2b644f46U, 0xe6db3d8bU, 0x60fe9e0dU, + 0xd062b2bdU, 0x236e4d4eU, 0x75afda18U, 0x15d7c278U, + 0x69b4dd04U, 0x6db1dc00U, 0xb15aebdcU, 0x9978e1f4U, + 0xead43e87U, 0xb01aaaddU, 0x627e1c0fU, 0x96b721fbU, + 0x323a085fU, 0xabc46fc6U, 0x2e210f43U, 0x21eecf4cU, + 0x9838a0f5U, 0xbbd06bd6U, 0xad41ecc0U, 0xd928f1b4U, + 0xa00eaecdU, 0x9c3da1f1U, 0xb55fead8U, 0xbfd56ad2U, + 0xf44fbb99U, 0xdba873b6U, 0x18988075U, 0xfec53b93U, + 0x4a5c1627U, 0xeb947f86U, 0x31facb5cU, 0x2a240e47U, + 0x68f49c05U, 0x0dc9c460U, 0x9ffd62f2U, 0x9437a3f9U, + 0x3e350b53U, 0x4b1c5726U, 0x0e090763U, 0x1e1d0373U, + 0xfac03a97U, 0x79a0d914U, 0x82a624efU, 0xf50ffa98U, + 0xec51bd81U, 0x86a325ebU, 0x01c6c76cU, 0x25ebce48U, + 0x499cd524U, 0x3a300a57U, 0x1b584376U, 0xf840b895U, + 0xcbbc77a6U, 0x65bbde08U, 0xc7b374aaU, 0xcef937a3U, + 0xbc15a9d1U, 0x1f5d4272U, 0x29e4cd44U, 0x6f315e02U, + 0x34bf8b59U, 0xafc16ec2U, 0xe914fd84U, 0x5ccd9131U, + 0x39f0c954U, 0x673b5c0aU, 0xa14eefccU, 0x24ab8f49U, + 0x83e665eeU, 0xf38a799eU, 0x38b08855U, 0xfd05f890U, + 0x6cd4b836U, 0x758aff2fU, 0x901787caU, 0xcc5c9096U, + 0x04a6a25eU, 0xb03f8feaU, 0xc3935099U, 0xe931d8b3U, + 0x6f147b35U, 0xed34d9b7U, 0x671e793dU, 0x3c90ac66U, + 0x97d245cdU, 0xd84d9582U, 0x87c641ddU, 0x234b6879U, + 0x9bdd46c1U, 0xaaa10bf0U, 0x5da8f507U, 0xeef41ab4U, + 0x9fd847c5U, 0xcd1cd197U, 0x274e697dU, 0x3895ad62U, + 0x9d58c5c7U, 0x260e287cU, 0x7b057e21U, 0xafe44bf5U, + 0x12372548U, 0x2dc4e977U, 0x2f446b75U, 0x51a7f60bU, + 0x45b6f31fU, 0x3e102e64U, 0x764a3c2cU, 0xe47e9abeU, + 0x718ffe2bU, 0x880981d2U, 0x55a2f70fU, 0xdec81684U, + 0xfba55ea1U, 0x665e383cU, 0x1b7d6641U, 0x3a152f60U, + 0x800383daU, 0x08a9a152U, 0x8546c3dfU, 0xbeb00ee4U, + 0xa42e8afeU, 0xf925dca3U, 0x4736711dU, 0x9157c6cbU, + 0x10b7a74aU, 0x1772654dU, 0x941286ceU, 0x619bfa3bU, + 0x35daef6fU, 0x48f9b112U, 0x659efb3fU, 0xdc489486U, + 0xe2fb19b8U, 0x09e9e053U, 0xcb995291U, 0xad64c9f7U, + 0x2a012b70U, 0x2b416a71U, 0xa961c8f3U, 0xc456929eU, + 0xf8659da2U, 0xfae51fa0U, 0x6b117a31U, 0xdd08d587U, + 0x39d5ec63U, 0x52673508U, 0xc796519dU, 0x53277409U, + 0xac2488f6U, 0x21cbea7bU, 0x0a292350U, 0x9552c7cfU, + 0x969204ccU, 0x9a9d07c0U, 0x31dfee6bU, 0xfd20dda7U, + 0xf2ef1da8U, 0xa6ae08fcU, 0x5ce8b406U, 0x19fde443U, + 0xd442968eU, 0x981d85c2U, 0x0b696251U, 0x1a3d2740U, + 0xf6ea1cacU, 0x6e543a34U, 0x41b3f21bU, 0xe3bb58b9U, + 0x4f3c7315U, 0xa7ee49fdU, 0x0f6c6355U, 0x4e7c3214U, + 0xbab50fe0U, 0x5662340cU, 0x70cfbf2aU, 0xbd70cde7U, + 0xa3eb48f9U, 0xbff04fe5U, 0xc6d6109cU, 0xdb8d5681U, + 0x335f6c69U, 0xb3ff4ce9U, 0xd6c2148cU, 0x29c1e873U, + 0x64deba3eU, 0x375a6d6dU, 0x2e042a74U, 0x6a513b30U, + 0x49b9f013U, 0x78c5bd22U, 0xabe14af1U, 0x7e403e24U, + 0x0626205cU, 0xefb45bb5U, 0x3f506f65U, 0xa82189f2U, + 0xb57acfefU, 0x248eaa7eU, 0x14b2a64eU, 0x4dbcf117U, + 0x9c1884c6U, 0xc919d093U, 0x1df8e547U, 0x7cc0bc26U, + 0x361a2c6cU, 0x2881a972U, 0xd782558dU, 0xe13bdabbU, + 0xb975cce3U, 0xe87199b2U, 0xfc609ca6U, 0x0caca056U, + 0xd047978aU, 0xb2bf0de8U, 0x631b7839U, 0xb17fceebU, + 0xb43a8eeeU, 0x8d4cc1d7U, 0x42733118U, 0xa56ecbffU, + 0x59adf403U, 0xe7be59bdU, 0x5f287705U, 0x625b3938U, + 0x8143c2dbU, 0x7985fc23U, 0xffa05fa5U, 0xf7aa5dadU, + 0xe07b9bbaU, 0x05e6e35fU, 0xf12fdeabU, 0xb8358de2U, + 0x43337019U, 0xec7498b6U, 0xbc308ce6U, 0x8fcc43d5U, + 0x3dd0ed67U, 0xaea40af4U, 0x1cb8a446U, 0xb6ba0cecU, + 0x349aae6eU, 0x93d744c9U, 0xbbf54ee1U, 0x995dc4c3U, + 0x03636059U, 0x7a453f20U, 0x0e2c2254U, 0x8a8903d0U, + 0x60dbbb3aU, 0x58edb502U, 0xebb15ab1U, 0x220b2978U, + 0x4cfcb016U, 0xc053939aU, 0x0dece157U, 0x8bc942d1U, + 0x3b556e61U, 0xc8599192U, 0x9e9806c4U, 0xfee01ea4U, + 0x828301d8U, 0x868600dcU, 0x5a6d3700U, 0x724f3d28U, + 0x01e3e25bU, 0x5b2d7601U, 0x8949c0d3U, 0x7d80fd27U, + 0xd90dd483U, 0x40f3b31aU, 0xc516d39fU, 0xcad91390U, + 0x730f7c29U, 0x50e7b70aU, 0x4676301cU, 0x321f2d68U, + 0x4b397211U, 0x770a7d2dU, 0x5e683604U, 0x54e2b60eU, + 0x1f786745U, 0x309faf6aU, 0xf3af5ca9U, 0x15f2e74fU, + 0xa16bcafbU, 0x00a3a35aU, 0xdacd1780U, 0xc113d29bU, + 0x83c340d9U, 0xe6fe18bcU, 0x74cabe2eU, 0x7f007f25U, + 0xd502d78fU, 0xa02b8bfaU, 0xe53edbbfU, 0xf52adfafU, + 0x11f7e64bU, 0x929705c8U, 0x6991f833U, 0x1e382644U, + 0x0766615dU, 0x6d94f937U, 0xeaf11bb0U, 0xcedc1294U, + 0xa2ab09f8U, 0xd107d68bU, 0xf06f9faaU, 0x13776449U, + 0x208bab7aU, 0x8e8c02d4U, 0x2c84a876U, 0x25ceeb7fU, + 0x5722750dU, 0xf46a9eaeU, 0xc2d31198U, 0x840682deU, + 0xdf885785U, 0x44f6b21eU, 0x02232158U, 0xb7fa4dedU, + 0xd2c71588U, 0x8c0c80d6U, 0x4a793310U, 0xcf9c5395U, + 0x68d1b932U, 0x18bda542U, 0xd3875489U, 0x1632244cU, + 0x4ede901eU, 0x5780d707U, 0xb21dafe2U, 0xee56b8beU, + 0x26ac8a76U, 0x9235a7c2U, 0xe19978b1U, 0xcb3bf09bU, + 0x4d1e531dU, 0xcf3ef19fU, 0x45145115U, 0x1e9a844eU, + 0xb5d86de5U, 0xfa47bdaaU, 0xa5cc69f5U, 0x01414051U, + 0xb9d76ee9U, 0x88ab23d8U, 0x7fa2dd2fU, 0xccfe329cU, + 0xbdd26fedU, 0xef16f9bfU, 0x05444155U, 0x1a9f854aU, + 0xbf52edefU, 0x04040054U, 0x590f5609U, 0x8dee63ddU, + 0x303d0d60U, 0x0fcec15fU, 0x0d4e435dU, 0x73adde23U, + 0x67bcdb37U, 0x1c1a064cU, 0x54401404U, 0xc674b296U, + 0x5385d603U, 0xaa03a9faU, 0x77a8df27U, 0xfcc23eacU, + 0xd9af7689U, 0x44541014U, 0x39774e69U, 0x181f0748U, + 0xa209abf2U, 0x2aa3897aU, 0xa74cebf7U, 0x9cba26ccU, + 0x8624a2d6U, 0xdb2ff48bU, 0x653c5935U, 0xb35deee3U, + 0x32bd8f62U, 0x35784d65U, 0xb618aee6U, 0x4391d213U, + 0x17d0c747U, 0x6af3993aU, 0x4794d317U, 0xfe42bcaeU, + 0xc0f13190U, 0x2be3c87bU, 0xe9937ab9U, 0x8f6ee1dfU, + 0x080b0358U, 0x094b4259U, 0x8b6be0dbU, 0xe65cbab6U, + 0xda6fb58aU, 0xd8ef3788U, 0x491b5219U, 0xff02fdafU, + 0x1bdfc44bU, 0x706d1d20U, 0xe59c79b5U, 0x712d5c21U, + 0x8e2ea0deU, 0x03c1c253U, 0x28230b78U, 0xb758efe7U, + 0xb4982ce4U, 0xb8972fe8U, 0x13d5c643U, 0xdf2af58fU, + 0xd0e53580U, 0x84a420d4U, 0x7ee29c2eU, 0x3bf7cc6bU, + 0xf648bea6U, 0xba17adeaU, 0x29634a79U, 0x38370f68U, + 0xd4e03484U, 0x4c5e121cU, 0x63b9da33U, 0xc1b17091U, + 0x6d365b3dU, 0x85e461d5U, 0x2d664b7dU, 0x6c761a3cU, + 0x98bf27c8U, 0x74681c24U, 0x52c59702U, 0x9f7ae5cfU, + 0x81e160d1U, 0x9dfa67cdU, 0xe4dc38b4U, 0xf9877ea9U, + 0x11554441U, 0x91f564c1U, 0xf4c83ca4U, 0x0bcbc05bU, + 0x46d49216U, 0x15504545U, 0x0c0e025cU, 0x485b1318U, + 0x6bb3d83bU, 0x5acf950aU, 0x89eb62d9U, 0x5c4a160cU, + 0x242c0874U, 0xcdbe739dU, 0x1d5a474dU, 0x8a2ba1daU, + 0x9770e7c7U, 0x06848256U, 0x36b88e66U, 0x6fb6d93fU, + 0xbe12aceeU, 0xeb13f8bbU, 0x3ff2cd6fU, 0x5eca940eU, + 0x14100444U, 0x0a8b815aU, 0xf5887da5U, 0xc331f293U, + 0x9b7fe4cbU, 0xca7bb19aU, 0xde6ab48eU, 0x2ea6887eU, + 0xf24dbfa2U, 0x90b525c0U, 0x41115011U, 0x9375e6c3U, + 0x9630a6c6U, 0xaf46e9ffU, 0x60791930U, 0x8764e3d7U, + 0x7ba7dc2bU, 0xc5b47195U, 0x7d225f2dU, 0x40511110U, + 0xa349eaf3U, 0x5b8fd40bU, 0xddaa778dU, 0xd5a07585U, + 0xc271b392U, 0x27eccb77U, 0xd325f683U, 0x9a3fa5caU, + 0x61395831U, 0xce7eb09eU, 0x9e3aa4ceU, 0xadc66bfdU, + 0x1fdac54fU, 0x8cae22dcU, 0x3eb28c6eU, 0x94b024c4U, + 0x16908646U, 0xb1dd6ce1U, 0x99ff66c9U, 0xbb57ecebU, + 0x21694871U, 0x584f1708U, 0x2c260a7cU, 0xa8832bf8U, + 0x42d19312U, 0x7ae79d2aU, 0xc9bb7299U, 0x00010150U, + 0x6ef6983eU, 0xe259bbb2U, 0x2fe6c97fU, 0xa9c36af9U, + 0x195f4649U, 0xea53b9baU, 0xbc922eecU, 0xdcea368cU, + 0xa08929f0U, 0xa48c28f4U, 0x78671f28U, 0x50451500U, + 0x23e9ca73U, 0x79275e29U, 0xab43e8fbU, 0x5f8ad50fU, + 0xfb07fcabU, 0x62f99b32U, 0xe71cfbb7U, 0xe8d33bb8U, + 0x51055401U, 0x72ed9f22U, 0x647c1834U, 0x10150540U, + 0x69335a39U, 0x55005505U, 0x7c621e2cU, 0x76e89e26U, + 0x3d724f6dU, 0x12958742U, 0xd1a57481U, 0x37f8cf67U, + 0x8361e2d3U, 0x22a98b72U, 0xf8c73fa8U, 0xe319fab3U, + 0xa1c968f1U, 0xc4f43094U, 0x56c09606U, 0x5d0a570dU, + 0xf708ffa7U, 0x8221a3d2U, 0xc734f397U, 0xd720f787U, + 0x33fdce63U, 0xb09d2de0U, 0x4b9bd01bU, 0x3c320e6cU, + 0x256c4975U, 0x4f9ed11fU, 0xc8fb3398U, 0xecd63abcU, + 0x80a121d0U, 0xf30dfea3U, 0xd265b782U, 0x317d4c61U, + 0x02818352U, 0xac862afcU, 0x0e8e805eU, 0x07c4c357U, + 0x75285d25U, 0xd660b686U, 0xe0d939b0U, 0xa60caaf6U, + 0xfd827fadU, 0x66fc9a36U, 0x20290970U, 0x95f065c5U, + 0xf0cd3da0U, 0xae06a8feU, 0x68731b38U, 0xed967bbdU, + 0x4adb911aU, 0x3ab78d6aU, 0xf18d7ca1U, 0x34380c64U, + 0xe201e36dU, 0xfb5fa474U, 0x1ec2dc91U, 0x4289cbcdU, + 0x8a73f905U, 0x3eead4b1U, 0x4d460bc2U, 0x67e483e8U, + 0xe1c1206eU, 0x63e182ecU, 0xe9cb2266U, 0xb245f73dU, + 0x19071e96U, 0x5698ced9U, 0x09131a86U, 0xad9e3322U, + 0x15081d9aU, 0x247450abU, 0xd37dae5cU, 0x602141efU, + 0x110d1c9eU, 0x43c98accU, 0xa99b3226U, 0xb640f639U, + 0x138d9e9cU, 0xa8db7327U, 0xf5d0257aU, 0x213110aeU, + 0x9ce27e13U, 0xa311b22cU, 0xa191302eU, 0xdf72ad50U, + 0xcb63a844U, 0xb0c5753fU, 0xf89f6777U, 0x6aabc1e5U, + 0xff5aa570U, 0x06dcda89U, 0xdb77ac54U, 0x501d4ddfU, + 0x757005faU, 0xe88b6367U, 0x95a83d1aU, 0xb4c0743bU, + 0x0ed6d881U, 0x867cfa09U, 0x0b939884U, 0x306555bfU, + 0x2afbd1a5U, 0x77f087f8U, 0xc9e32a46U, 0x1f829d90U, + 0x9e62fc11U, 0x99a73e16U, 0x1ac7dd95U, 0xef4ea160U, + 0xbb0fb434U, 0xc62cea49U, 0xeb4ba064U, 0x529dcfddU, + 0x6c2e42e3U, 0x873cbb08U, 0x454c09caU, 0x23b192acU, + 0xa4d4702bU, 0xa594312aU, 0x27b493a8U, 0x4a83c9c5U, + 0x76b0c6f9U, 0x743044fbU, 0xe5c4216aU, 0x53dd8edcU, + 0xb700b738U, 0xdcb26e53U, 0x49430ac6U, 0xddf22f52U, + 0x22f1d3adU, 0xaf1eb120U, 0x84fc780bU, 0x1b879c94U, + 0x18475f97U, 0x14485c9bU, 0xbf0ab530U, 0x73f586fcU, + 0x7c3a46f3U, 0x287b53a7U, 0xd23def5dU, 0x9728bf18U, + 0x5a97cdd5U, 0x16c8de99U, 0x85bc390aU, 0x94e87c1bU, + 0x783f47f7U, 0xe081616fU, 0xcf66a940U, 0x6d6e03e2U, + 0xc1e9284eU, 0x293b12a6U, 0x81b9380eU, 0xc0a9694fU, + 0x346054bbU, 0xd8b76f57U, 0xfe1ae471U, 0x33a596bcU, + 0x2d3e13a2U, 0x312514beU, 0x48034bc7U, 0x55580ddaU, + 0xbd8a3732U, 0x3d2a17b2U, 0x58174fd7U, 0xa714b328U, + 0xea0be165U, 0xb98f3636U, 0xa0d1712fU, 0xe484606bU, + 0xc76cab48U, 0xf610e679U, 0x253411aaU, 0xf095657fU, + 0x88f37b07U, 0x616100eeU, 0xb185343eU, 0x26f4d2a9U, + 0x3baf94b4U, 0xaa5bf125U, 0x9a67fd15U, 0xc369aa4cU, + 0x12cddf9dU, 0x47cc8bc8U, 0x932dbe1cU, 0xf215e77dU, + 0xb8cf7737U, 0xa654f229U, 0x59570ed6U, 0x6fee81e0U, + 0x37a097b8U, 0x66a4c2e9U, 0x72b5c7fdU, 0x8279fb0dU, + 0x5e92ccd1U, 0x3c6a56b3U, 0xedce2362U, 0x3faa95b0U, + 0x3aefd5b5U, 0x03999a8cU, 0xcca66a43U, 0x2bbb90a4U, + 0xd778af58U, 0x696b02e6U, 0xd1fd2c5eU, 0xec8e6263U, + 0x0f969980U, 0xf750a778U, 0x717504feU, 0x797f06f6U, + 0x6eaec0e1U, 0x8b33b804U, 0x7ffa85f0U, 0x36e0d6b9U, + 0xcde62b42U, 0x62a1c3edU, 0x32e5d7bdU, 0x0119188eU, + 0xb305b63cU, 0x207151afU, 0x926dff1dU, 0x386f57b7U, + 0xba4ff535U, 0x1d021f92U, 0x352015baU, 0x17889f98U, + 0x8db63b02U, 0xf490647bU, 0x80f9790fU, 0x045c588bU, + 0xee0ee061U, 0xd638ee59U, 0x656401eaU, 0xacde7223U, + 0xc229eb4dU, 0x4e86c8c1U, 0x8339ba0cU, 0x051c198aU, + 0xb580353aU, 0x468ccac9U, 0x104d5d9fU, 0x703545ffU, + 0x0c565a83U, 0x08535b87U, 0xd4b86c5bU, 0xfc9a6673U, + 0x8f36b900U, 0xd5f82d5aU, 0x079c9b88U, 0xf355a67cU, + 0x57d88fd8U, 0xce26e841U, 0x4bc388c4U, 0x440c48cbU, + 0xfdda2772U, 0xde32ec51U, 0xc8a36b47U, 0xbcca7633U, + 0xc5ec294aU, 0xf9df2676U, 0xd0bd6d5fU, 0xda37ed55U, + 0x91ad3c1eU, 0xbe4af431U, 0x7d7a07f2U, 0x9b27bc14U, + 0x2fbe91a0U, 0x8e76f801U, 0x54184cdbU, 0x4fc689c0U, + 0x0d161b82U, 0x682b43e7U, 0xfa1fe575U, 0xf1d5247eU, + 0x5bd78cd4U, 0x2efed0a1U, 0x6beb80e4U, 0x7bff84f4U, + 0x9f22bd10U, 0x1c425e93U, 0xe744a368U, 0x90ed7d1fU, + 0x89b33a06U, 0xe341a26cU, 0x642440ebU, 0x400949cfU, + 0x2c7e52a3U, 0x5fd28dd0U, 0x7ebac4f1U, 0x9da23f12U, + 0xae5ef021U, 0x0059598fU, 0xa251f32dU, 0xab1bb024U, + 0xd9f72e56U, 0x7abfc5f5U, 0x4c064ac3U, 0x0ad3d985U, + 0x515d0cdeU, 0xca23e945U, 0x8cf67a03U, 0x392f16b6U, + 0x5c124ed3U, 0x02d9db8dU, 0xc4ac684bU, 0x414908ceU, + 0xe604e269U, 0x9668fe19U, 0x5d520fd2U, 0x98e77f17U, + 0x2c95b937U, 0x35cbfe2eU, 0xd05686cbU, 0x8c1d9197U, + 0x44e7a35fU, 0xf07e8eebU, 0x83d25198U, 0xa970d9b2U, + 0x2f557a34U, 0xad75d8b6U, 0x275f783cU, 0x7cd1ad67U, + 0xd79344ccU, 0x980c9483U, 0xc78740dcU, 0x630a6978U, + 0xdb9c47c0U, 0xeae00af1U, 0x1de9f406U, 0xaeb51bb5U, + 0xdf9946c4U, 0x8d5dd096U, 0x670f687cU, 0x78d4ac63U, + 0xdd19c4c6U, 0x664f297dU, 0x3b447f20U, 0xefa54af4U, + 0x52762449U, 0x6d85e876U, 0x6f056a74U, 0x11e6f70aU, + 0x05f7f21eU, 0x7e512f65U, 0x360b3d2dU, 0xa43f9bbfU, + 0x31ceff2aU, 0xc84880d3U, 0x15e3f60eU, 0x9e891785U, + 0xbbe45fa0U, 0x261f393dU, 0x5b3c6740U, 0x7a542e61U, + 0xc04282dbU, 0x48e8a053U, 0xc507c2deU, 0xfef10fe5U, + 0xe46f8bffU, 0xb964dda2U, 0x0777701cU, 0xd116c7caU, + 0x50f6a64bU, 0x5733644cU, 0xd45387cfU, 0x21dafb3aU, + 0x759bee6eU, 0x08b8b013U, 0x25dffa3eU, 0x9c099587U, + 0xa2ba18b9U, 0x49a8e152U, 0x8bd85390U, 0xed25c8f6U, + 0x6a402a71U, 0x6b006b70U, 0xe920c9f2U, 0x8417939fU, + 0xb8249ca3U, 0xbaa41ea1U, 0x2b507b30U, 0x9d49d486U, + 0x7994ed62U, 0x12263409U, 0x87d7509cU, 0x13667508U, + 0xec6589f7U, 0x618aeb7aU, 0x4a682251U, 0xd513c6ceU, + 0xd6d305cdU, 0xdadc06c1U, 0x719eef6aU, 0xbd61dca6U, + 0xb2ae1ca9U, 0xe6ef09fdU, 0x1ca9b507U, 0x59bce542U, + 0x9403978fU, 0xd85c84c3U, 0x4b286350U, 0x5a7c2641U, + 0xb6ab1dadU, 0x2e153b35U, 0x01f2f31aU, 0xa3fa59b8U, + 0x0f7d7214U, 0xe7af48fcU, 0x4f2d6254U, 0x0e3d3315U, + 0xfaf40ee1U, 0x1623350dU, 0x308ebe2bU, 0xfd31cce6U, + 0xe3aa49f8U, 0xffb14ee4U, 0x8697119dU, 0x9bcc5780U, + 0x731e6d68U, 0xf3be4de8U, 0x9683158dU, 0x6980e972U, + 0x249fbb3fU, 0x771b6c6cU, 0x6e452b75U, 0x2a103a31U, + 0x09f8f112U, 0x3884bc23U, 0xeba04bf0U, 0x3e013f25U, + 0x4667215dU, 0xaff55ab4U, 0x7f116e64U, 0xe86088f3U, + 0xf53bceeeU, 0x64cfab7fU, 0x54f3a74fU, 0x0dfdf016U, + 0xdc5985c7U, 0x8958d192U, 0x5db9e446U, 0x3c81bd27U, + 0x765b2d6dU, 0x68c0a873U, 0x97c3548cU, 0xa17adbbaU, + 0xf934cde2U, 0xa83098b3U, 0xbc219da7U, 0x4ceda157U, + 0x9006968bU, 0xf2fe0ce9U, 0x235a7938U, 0xf13ecfeaU, + 0xf47b8fefU, 0xcd0dc0d6U, 0x02323019U, 0xe52fcafeU, + 0x19ecf502U, 0xa7ff58bcU, 0x1f697604U, 0x221a3839U, + 0xc102c3daU, 0x39c4fd22U, 0xbfe15ea4U, 0xb7eb5cacU, + 0xa03a9abbU, 0x45a7e25eU, 0xb16edfaaU, 0xf8748ce3U, + 0x03727118U, 0xac3599b7U, 0xfc718de7U, 0xcf8d42d4U, + 0x7d91ec66U, 0xeee50bf5U, 0x5cf9a547U, 0xf6fb0dedU, + 0x74dbaf6fU, 0xd39645c8U, 0xfbb44fe0U, 0xd91cc5c2U, + 0x43226158U, 0x3a043e21U, 0x4e6d2355U, 0xcac802d1U, + 0x209aba3bU, 0x18acb403U, 0xabf05bb0U, 0x624a2879U, + 0x0cbdb117U, 0x8012929bU, 0x4dade056U, 0xcb8843d0U, + 0x7b146f60U, 0x88189093U, 0xded907c5U, 0xbea11fa5U, + 0xc2c200d9U, 0xc6c701ddU, 0x1a2c3601U, 0x320e3c29U, + 0x41a2e35aU, 0x1b6c7700U, 0xc908c1d2U, 0x3dc1fc26U, + 0x994cd582U, 0x00b2b21bU, 0x8557d29eU, 0x8a981291U, + 0x334e7d28U, 0x10a6b60bU, 0x0637311dU, 0x725e2c69U, + 0x0b787310U, 0x374b7c2cU, 0x1e293705U, 0x14a3b70fU, + 0x5f396644U, 0x70deae6bU, 0xb3ee5da8U, 0x55b3e64eU, + 0xe12acbfaU, 0x40e2a25bU, 0x9a8c1681U, 0x8152d39aU, + 0xc38241d8U, 0xa6bf19bdU, 0x348bbf2fU, 0x3f417e24U, + 0x9543d68eU, 0xe06a8afbU, 0xa57fdabeU, 0xb56bdeaeU, + 0x51b6e74aU, 0xd2d604c9U, 0x29d0f932U, 0x5e792745U, + 0x4727605cU, 0x2dd5f836U, 0xaab01ab1U, 0x8e9d1395U, + 0xe2ea08f9U, 0x9146d78aU, 0xb02e9eabU, 0x53366548U, + 0x60caaa7bU, 0xcecd03d5U, 0x6cc5a977U, 0x658fea7eU, + 0x1763740cU, 0xb42b9fafU, 0x82921099U, 0xc44783dfU, + 0x9fc95684U, 0x04b7b31fU, 0x42622059U, 0xf7bb4cecU, + 0x92861489U, 0xcc4d81d7U, 0x0a383211U, 0x8fdd5294U, + 0x2890b833U, 0x58fca443U, 0x93c65588U, 0x5673254dU, + 0x48236be5U, 0x517d2cfcU, 0xb4e05419U, 0xe8ab4345U, + 0x2051718dU, 0x94c85c39U, 0xe764834aU, 0xcdc60b60U, + 0x4be3a8e6U, 0xc9c30a64U, 0x43e9aaeeU, 0x18677fb5U, + 0xb325961eU, 0xfcba4651U, 0xa331920eU, 0x07bcbbaaU, + 0xbf2a9512U, 0x8e56d823U, 0x795f26d4U, 0xca03c967U, + 0xbb2f9416U, 0xe9eb0244U, 0x03b9baaeU, 0x1c627eb1U, + 0xb9af1614U, 0x02f9fbafU, 0x5ff2adf2U, 0x8b139826U, + 0x36c0f69bU, 0x09333aa4U, 0x0bb3b8a6U, 0x755025d8U, + 0x614120ccU, 0x1ae7fdb7U, 0x52bdefffU, 0xc089496dU, + 0x55782df8U, 0xacfe5201U, 0x715524dcU, 0xfa3fc557U, + 0xdf528d72U, 0x42a9ebefU, 0x3f8ab592U, 0x1ee2fcb3U, + 0xa4f45009U, 0x2c5e7281U, 0xa1b1100cU, 0x9a47dd37U, + 0x80d9592dU, 0xddd20f70U, 0x63c1a2ceU, 0xb5a01518U, + 0x34407499U, 0x3385b69eU, 0xb0e5551dU, 0x456c29e8U, + 0x112d3cbcU, 0x6c0e62c1U, 0x416928ecU, 0xf8bf4755U, + 0xc60cca6bU, 0x2d1e3380U, 0xef6e8142U, 0x89931a24U, + 0x0ef6f8a3U, 0x0fb6b9a2U, 0x8d961b20U, 0xe0a1414dU, + 0xdc924e71U, 0xde12cc73U, 0x4fe6a9e2U, 0xf9ff0654U, + 0x1d223fb0U, 0x7690e6dbU, 0xe361824eU, 0x77d0a7daU, + 0x88d35b25U, 0x053c39a8U, 0x2edef083U, 0xb1a5141cU, + 0xb265d71fU, 0xbe6ad413U, 0x15283db8U, 0xd9d70e74U, + 0xd618ce7bU, 0x8259db2fU, 0x781f67d5U, 0x3d0a3790U, + 0xf0b5455dU, 0xbcea5611U, 0x2f9eb182U, 0x3ecaf493U, + 0xd21dcf7fU, 0x4aa3e9e7U, 0x654421c8U, 0xc74c8b6aU, + 0x6bcba0c6U, 0x83199a2eU, 0x2b9bb086U, 0x6a8be1c7U, + 0x9e42dc33U, 0x7295e7dfU, 0x54386cf9U, 0x99871e34U, + 0x871c9b2aU, 0x9b079c36U, 0xe221c34fU, 0xff7a8552U, + 0x17a8bfbaU, 0x97089f3aU, 0xf235c75fU, 0x0d363ba0U, + 0x402969edU, 0x13adbebeU, 0x0af3f9a7U, 0x4ea6e8e3U, + 0x6d4e23c0U, 0x5c326ef1U, 0x8f169922U, 0x5ab7edf7U, + 0x22d1f38fU, 0xcb438866U, 0x1ba7bcb6U, 0x8cd65a21U, + 0x918d1c3cU, 0x007979adU, 0x3045759dU, 0x694b22c4U, + 0xb8ef5715U, 0xedee0340U, 0x390f3694U, 0x58376ff5U, + 0x12edffbfU, 0x0c767aa1U, 0xf375865eU, 0xc5cc0968U, + 0x9d821f30U, 0xcc864a61U, 0xd8974f75U, 0x285b7385U, + 0xf4b04459U, 0x9648de3bU, 0x47ecabeaU, 0x95881d38U, + 0x90cd5d3dU, 0xa9bb1204U, 0x6684e2cbU, 0x8199182cU, + 0x7d5a27d0U, 0xc3498a6eU, 0x7bdfa4d6U, 0x46aceaebU, + 0xa5b41108U, 0x5d722ff0U, 0xdb578c76U, 0xd35d8e7eU, + 0xc48c4869U, 0x2111308cU, 0xd5d80d78U, 0x9cc25e31U, + 0x67c4a3caU, 0xc8834b65U, 0x98c75f35U, 0xab3b9006U, + 0x19273eb4U, 0x8a53d927U, 0x384f7795U, 0x924ddf3fU, + 0x106d7dbdU, 0xb720971aU, 0x9f029d32U, 0xbdaa1710U, + 0x2794b38aU, 0x5eb2ecf3U, 0x2adbf187U, 0xae7ed003U, + 0x442c68e9U, 0x7c1a66d1U, 0xcf468962U, 0x06fcfaabU, + 0x680b63c5U, 0xe4a44049U, 0x291b3284U, 0xaf3e9102U, + 0x1fa2bdb2U, 0xecae4241U, 0xba6fd517U, 0xda17cd77U, + 0xa674d20bU, 0xa271d30fU, 0x7e9ae4d3U, 0x56b8eefbU, + 0x25143188U, 0x7fdaa5d2U, 0xadbe1300U, 0x59772ef4U, + 0xfdfa0750U, 0x640460c9U, 0xe1e1004cU, 0xee2ec043U, + 0x57f8affaU, 0x741064d9U, 0x6281e3cfU, 0x16e8febbU, + 0x6fcea1c2U, 0x53fdaefeU, 0x7a9fe5d7U, 0x701565ddU, + 0x3b8fb496U, 0x14687cb9U, 0xd7588f7aU, 0x3105349cU, + 0x859c1928U, 0x24547089U, 0xfe3ac453U, 0xe5e40148U, + 0xa734930aU, 0xc209cb6fU, 0x503d6dfdU, 0x5bf7acf6U, + 0xf1f5045cU, 0x84dc5829U, 0xc1c9086cU, 0xd1dd0c7cU, + 0x35003598U, 0xb660d61bU, 0x4d662be0U, 0x3acff597U, + 0x2391b28eU, 0x49632ae4U, 0xce06c863U, 0xea2bc147U, + 0x865cda2bU, 0xf5f00558U, 0xd4984c79U, 0x3780b79aU, + 0x047c78a9U, 0xaa7bd107U, 0x08737ba5U, 0x013938acU, + 0x73d5a6deU, 0xd09d4d7dU, 0xe624c24bU, 0xa0f1510dU, + 0xfb7f8456U, 0x600161cdU, 0x26d4f28bU, 0x930d9e3eU, + 0xf630c65bU, 0xa8fb5305U, 0x6e8ee0c3U, 0xeb6b8046U, + 0x4c266ae1U, 0x3c4a7691U, 0xf770875aU, 0x32c5f79fU, + 0x811e9f11U, 0x9840d808U, 0x7ddda0edU, 0x2196b7b1U, + 0xe96c8579U, 0x5df5a8cdU, 0x2e5977beU, 0x04fbff94U, + 0x82de5c12U, 0x00fefe90U, 0x8ad45e1aU, 0xd15a8b41U, + 0x7a1862eaU, 0x3587b2a5U, 0x6a0c66faU, 0xce814f5eU, + 0x761761e6U, 0x476b2cd7U, 0xb062d220U, 0x033e3d93U, + 0x721260e2U, 0x20d6f6b0U, 0xca844e5aU, 0xd55f8a45U, + 0x7092e2e0U, 0xcbc40f5bU, 0x96cf5906U, 0x422e6cd2U, + 0xfffd026fU, 0xc00ece50U, 0xc28e4c52U, 0xbc6dd12cU, + 0xa87cd438U, 0xd3da0943U, 0x9b801b0bU, 0x09b4bd99U, + 0x9c45d90cU, 0x65c3a6f5U, 0xb868d028U, 0x330231a3U, + 0x166f7986U, 0x8b941f1bU, 0xf6b74166U, 0xd7df0847U, + 0x6dc9a4fdU, 0xe5638675U, 0x688ce4f8U, 0x537a29c3U, + 0x49e4add9U, 0x14effb84U, 0xaafc563aU, 0x7c9de1ecU, + 0xfd7d806dU, 0xfab8426aU, 0x79d8a1e9U, 0x8c51dd1cU, + 0xd810c848U, 0xa5339635U, 0x8854dc18U, 0x3182b3a1U, + 0x0f313e9fU, 0xe423c774U, 0x265375b6U, 0x40aeeed0U, + 0xc7cb0c57U, 0xc68b4d56U, 0x44abefd4U, 0x299cb5b9U, + 0x15afba85U, 0x172f3887U, 0x86db5d16U, 0x30c2f2a0U, + 0xd41fcb44U, 0xbfad122fU, 0x2a5c76baU, 0xbeed532eU, + 0x41eeafd1U, 0xcc01cd5cU, 0xe7e30477U, 0x7898e0e8U, + 0x7b5823ebU, 0x775720e7U, 0xdc15c94cU, 0x10eafa80U, + 0x1f253a8fU, 0x4b642fdbU, 0xb1229321U, 0xf437c364U, + 0x3988b1a9U, 0x75d7a2e5U, 0xe6a34576U, 0xf7f70067U, + 0x1b203b8bU, 0x839e1d13U, 0xac79d53cU, 0x0e717f9eU, + 0xa2f65432U, 0x4a246edaU, 0xe2a64472U, 0xa3b61533U, + 0x577f28c7U, 0xbba8132bU, 0x9d05980dU, 0x50baeac0U, + 0x4e216fdeU, 0x523a68c2U, 0x2b1c37bbU, 0x364771a6U, + 0xde954b4eU, 0x5e356bceU, 0x3b0833abU, 0xc40bcf54U, + 0x89149d19U, 0xda904a4aU, 0xc3ce0d53U, 0x879b1c17U, + 0xa473d734U, 0x950f9a05U, 0x462b6dd6U, 0x938a1903U, + 0xebec077bU, 0x027e7c92U, 0xd29a4842U, 0x45ebaed5U, + 0x58b0e8c8U, 0xc9448d59U, 0xf9788169U, 0xa076d630U, + 0x71d2a3e1U, 0x24d3f7b4U, 0xf032c260U, 0x910a9b01U, + 0xdbd00b4bU, 0xc54b8e55U, 0x3a4872aaU, 0x0cf1fd9cU, + 0x54bfebc4U, 0x05bbbe95U, 0x11aabb81U, 0xe1668771U, + 0x3d8db0adU, 0x5f752acfU, 0x8ed15f1eU, 0x5cb5e9ccU, + 0x59f0a9c9U, 0x6086e6f0U, 0xafb9163fU, 0x48a4ecd8U, + 0xb467d324U, 0x0a747e9aU, 0xb2e25022U, 0x8f911e1fU, + 0x6c89e5fcU, 0x944fdb04U, 0x126a7882U, 0x1a607a8aU, + 0x0db1bc9dU, 0xe82cc478U, 0x1ce5f98cU, 0x55ffaac5U, + 0xaef9573eU, 0x01bebf91U, 0x51faabc1U, 0x620664f2U, + 0xd01aca40U, 0x436e2dd3U, 0xf1728361U, 0x5b702bcbU, + 0xd9508949U, 0x7e1d63eeU, 0x563f69c6U, 0x7497e3e4U, + 0xeea9477eU, 0x978f1807U, 0xe3e60573U, 0x674324f7U, + 0x8d119c1dU, 0xb5279225U, 0x067b7d96U, 0xcfc10e5fU, + 0xa1369731U, 0x2d99b4bdU, 0xe026c670U, 0x660365f6U, + 0xd69f4946U, 0x2593b6b5U, 0x735221e3U, 0x132a3983U, + 0x6f4926ffU, 0x6b4c27fbU, 0xb7a71027U, 0x9f851a0fU, + 0xec29c57cU, 0xb6e75126U, 0x6483e7f4U, 0x904ada00U, + 0x34c7f3a4U, 0xad39943dU, 0x28dcf4b8U, 0x271334b7U, + 0x9ec55b0eU, 0xbd2d902dU, 0xabbc173bU, 0xdfd50a4fU, + 0xa6f35536U, 0x9ac05a0aU, 0xb3a21123U, 0xb9289129U, + 0xf2b24062U, 0xdd55884dU, 0x1e657b8eU, 0xf838c068U, + 0x4ca1eddcU, 0xed69847dU, 0x370730a7U, 0x2cd9f5bcU, + 0x6e0967feU, 0x0b343f9bU, 0x99009909U, 0x92ca5802U, + 0x38c8f0a8U, 0x4de1acddU, 0x08f4fc98U, 0x18e0f888U, + 0xfc3dc16cU, 0x7f5d22efU, 0x845bdf14U, 0xf3f20163U, + 0xeaac467aU, 0x805ede10U, 0x073b3c97U, 0x231635b3U, + 0x4f612edfU, 0x3ccdf1acU, 0x1da5b88dU, 0xfebd436eU, + 0xcd418c5dU, 0x634625f3U, 0xc14e8f51U, 0xc804cc58U, + 0xbae8522aU, 0x19a0b989U, 0x2f1936bfU, 0x69cca5f9U, + 0x324270a2U, 0xa93c9539U, 0xefe9067fU, 0x5a306acaU, + 0x3f0d32afU, 0x61c6a7f1U, 0xa7b31437U, 0x225674b2U, + 0x851b9e15U, 0xf5778265U, 0x3e4d73aeU, 0xfbf8036bU, + 0x0c373bb5U, 0x15697cacU, 0xf0f40449U, 0xacbf1315U, + 0x644521ddU, 0xd0dc0c69U, 0xa370d31aU, 0x89d25b30U, + 0x0ff7f8b6U, 0x8dd75a34U, 0x07fdfabeU, 0x5c732fe5U, + 0xf731c64eU, 0xb8ae1601U, 0xe725c25eU, 0x43a8ebfaU, + 0xfb3ec542U, 0xca428873U, 0x3d4b7684U, 0x8e179937U, + 0xff3bc446U, 0xadff5214U, 0x47adeafeU, 0x58762ee1U, + 0xfdbb4644U, 0x46edabffU, 0x1be6fda2U, 0xcf07c876U, + 0x72d4a6cbU, 0x4d276af4U, 0x4fa7e8f6U, 0x31447588U, + 0x2555709cU, 0x5ef3ade7U, 0x16a9bfafU, 0x849d193dU, + 0x116c7da8U, 0xe8ea0251U, 0x3541748cU, 0xbe2b9507U, + 0x9b46dd22U, 0x06bdbbbfU, 0x7b9ee5c2U, 0x5af6ace3U, + 0xe0e00059U, 0x684a22d1U, 0xe5a5405cU, 0xde538d67U, + 0xc4cd097dU, 0x99c65f20U, 0x27d5f29eU, 0xf1b44548U, + 0x705424c9U, 0x7791e6ceU, 0xf4f1054dU, 0x017879b8U, + 0x55396cecU, 0x281a3291U, 0x057d78bcU, 0xbcab1705U, + 0x82189a3bU, 0x690a63d0U, 0xab7ad112U, 0xcd874a74U, + 0x4ae2a8f3U, 0x4ba2e9f2U, 0xc9824b70U, 0xa4b5111dU, + 0x98861e21U, 0x9a069c23U, 0x0bf2f9b2U, 0xbdeb5604U, + 0x59366fe0U, 0x3284b68bU, 0xa775d21eU, 0x33c4f78aU, + 0xccc70b75U, 0x412869f8U, 0x6acaa0d3U, 0xf5b1444cU, + 0xf671874fU, 0xfa7e8443U, 0x513c6de8U, 0x9dc35e24U, + 0x920c9e2bU, 0xc64d8b7fU, 0x3c0b3785U, 0x791e67c0U, + 0xb4a1150dU, 0xf8fe0641U, 0x6b8ae1d2U, 0x7adea4c3U, + 0x96099f2fU, 0x0eb7b9b7U, 0x21507198U, 0x8358db3aU, + 0x2fdff096U, 0xc70dca7eU, 0x6f8fe0d6U, 0x2e9fb197U, + 0xda568c63U, 0x3681b78fU, 0x102c3ca9U, 0xdd934e64U, + 0xc308cb7aU, 0xdf13cc66U, 0xa635931fU, 0xbb6ed502U, + 0x53bcefeaU, 0xd31ccf6aU, 0xb621970fU, 0x49226bf0U, + 0x043d39bdU, 0x57b9eeeeU, 0x4ee7a9f7U, 0x0ab2b8b3U, + 0x295a7390U, 0x18263ea1U, 0xcb02c972U, 0x1ea3bda7U, + 0x66c5a3dfU, 0x8f57d836U, 0x5fb3ece6U, 0xc8c20a71U, + 0xd5994c6cU, 0x446d29fdU, 0x745125cdU, 0x2d5f7294U, + 0xfcfb0745U, 0xa9fa5310U, 0x7d1b66c4U, 0x1c233fa5U, + 0x56f9afefU, 0x48622af1U, 0xb761d60eU, 0x81d85938U, + 0xd9964f60U, 0x88921a31U, 0x9c831f25U, 0x6c4f23d5U, + 0xb0a41409U, 0xd25c8e6bU, 0x03f8fbbaU, 0xd19c4d68U, + 0xd4d90d6dU, 0xedaf4254U, 0x2290b29bU, 0xc58d487cU, + 0x394e7780U, 0x875dda3eU, 0x3fcbf486U, 0x02b8babbU, + 0xe1a04158U, 0x19667fa0U, 0x9f43dc26U, 0x9749de2eU, + 0x80981839U, 0x650560dcU, 0x91cc5d28U, 0xd8d60e61U, + 0x23d0f39aU, 0x8c971b35U, 0xdcd30f65U, 0xef2fc056U, + 0x5d336ee4U, 0xce478977U, 0x7c5b27c5U, 0xd6598f6fU, + 0x54792dedU, 0xf334c74aU, 0xdb16cd62U, 0xf9be4740U, + 0x6380e3daU, 0x1aa6bca3U, 0x6ecfa1d7U, 0xea6a8053U, + 0x003838b9U, 0x380e3681U, 0x8b52d932U, 0x42e8aafbU, + 0x2c1f3395U, 0xa0b01019U, 0x6d0f62d4U, 0xeb2ac152U, + 0x5bb6ede2U, 0xa8ba1211U, 0xfe7b8547U, 0x9e039d27U, + 0xe260825bU, 0xe665835fU, 0x3a8eb483U, 0x12acbeabU, + 0x610061d8U, 0x3bcef582U, 0xe9aa4350U, 0x1d637ea4U, + 0xb9ee5700U, 0x20103099U, 0xa5f5501cU, 0xaa3a9013U, + 0x13ecffaaU, 0x30043489U, 0x2695b39fU, 0x52fcaeebU, + 0x2bdaf192U, 0x17e9feaeU, 0x3e8bb587U, 0x3401358dU, + 0x7f9be4c6U, 0x507c2ce9U, 0x934cdf2aU, 0x751164ccU, + 0xc1884978U, 0x604020d9U, 0xba2e9403U, 0xa1f05118U, + 0xe320c35aU, 0x861d9b3fU, 0x14293dadU, 0x1fe3fca6U, + 0xb5e1540cU, 0xc0c80879U, 0x85dd583cU, 0x95c95c2cU, + 0x711465c8U, 0xf274864bU, 0x09727bb0U, 0x7edba5c7U, + 0x6785e2deU, 0x0d777ab4U, 0x8a129833U, 0xae3f9117U, + 0xc2488a7bU, 0xb1e45508U, 0x908c1c29U, 0x7394e7caU, + 0x406828f9U, 0xee6f8157U, 0x4c672bf5U, 0x452d68fcU, + 0x37c1f68eU, 0x94891d2dU, 0xa230921bU, 0xe4e5015dU, + 0xbf6bd406U, 0x2415319dU, 0x62c0a2dbU, 0xd719ce6eU, + 0xb224960bU, 0xecef0355U, 0x2a9ab093U, 0xaf7fd016U, + 0x08323ab1U, 0x785e26c1U, 0xb364d70aU, 0x76d1a7cfU, + 0xf250a22cU, 0xeb0ee535U, 0x0e939dd0U, 0x52d88a8cU, + 0x9a22b844U, 0x2ebb95f0U, 0x5d174a83U, 0x77b5c2a9U, + 0xf190612fU, 0x73b0c3adU, 0xf99a6327U, 0xa214b67cU, + 0x09565fd7U, 0x46c98f98U, 0x19425bc7U, 0xbdcf7263U, + 0x05595cdbU, 0x342511eaU, 0xc32cef1dU, 0x707000aeU, + 0x015c5ddfU, 0x5398cb8dU, 0xb9ca7367U, 0xa611b778U, + 0x03dcdfddU, 0xb88a3266U, 0xe581643bU, 0x316051efU, + 0x8cb33f52U, 0xb340f36dU, 0xb1c0716fU, 0xcf23ec11U, + 0xdb32e905U, 0xa094347eU, 0xe8ce2636U, 0x7afa80a4U, + 0xef0be431U, 0x168d9bc8U, 0xcb26ed15U, 0x404c0c9eU, + 0x652144bbU, 0xf8da2226U, 0x85f97c5bU, 0xa491357aU, + 0x1e8799c0U, 0x962dbb48U, 0x1bc2d9c5U, 0x203414feU, + 0x3aaa90e4U, 0x67a1c6b9U, 0xd9b26b07U, 0x0fd3dcd1U, + 0x8e33bd50U, 0x89f67f57U, 0x0a969cd4U, 0xff1fe021U, + 0xab5ef575U, 0xd67dab08U, 0xfb1ae125U, 0x42cc8e9cU, + 0x7c7f03a2U, 0x976dfa49U, 0x551d488bU, 0x33e0d3edU, + 0xb485316aU, 0xb5c5706bU, 0x37e5d2e9U, 0x5ad28884U, + 0x66e187b8U, 0x646105baU, 0xf595602bU, 0x438ccf9dU, + 0xa751f679U, 0xcce32f12U, 0x59124b87U, 0xcda36e13U, + 0x32a092ecU, 0xbf4ff061U, 0x94ad394aU, 0x0bd6ddd5U, + 0x08161ed6U, 0x04191ddaU, 0xaf5bf471U, 0x63a4c7bdU, + 0x6c6b07b2U, 0x382a12e6U, 0xc26cae1cU, 0x8779fe59U, + 0x4ac68c94U, 0x06999fd8U, 0x95ed784bU, 0x84b93d5aU, + 0x686e06b6U, 0xf0d0202eU, 0xdf37e801U, 0x7d3f42a3U, + 0xd1b8690fU, 0x396a53e7U, 0x91e8794fU, 0xd0f8280eU, + 0x243115faU, 0xc8e62e16U, 0xee4ba530U, 0x23f4d7fdU, + 0x3d6f52e3U, 0x217455ffU, 0x58520a86U, 0x45094c9bU, + 0xaddb7673U, 0x2d7b56f3U, 0x48460e96U, 0xb745f269U, + 0xfa5aa024U, 0xa9de7777U, 0xb080306eU, 0xf4d5212aU, + 0xd73dea09U, 0xe641a738U, 0x356550ebU, 0xe0c4243eU, + 0x98a23a46U, 0x713041afU, 0xa1d4757fU, 0x36a593e8U, + 0x2bfed5f5U, 0xba0ab064U, 0x8a36bc54U, 0xd338eb0dU, + 0x029c9edcU, 0x579dca89U, 0x837cff5dU, 0xe244a63cU, + 0xa89e3676U, 0xb605b368U, 0x49064f97U, 0x7fbfc0a1U, + 0x27f1d6f9U, 0x76f583a8U, 0x62e486bcU, 0x9228ba4cU, + 0x4ec38d90U, 0x2c3b17f2U, 0xfd9f6223U, 0x2ffbd4f1U, + 0x2abe94f4U, 0x13c8dbcdU, 0xdcf72b02U, 0x3bead1e5U, + 0xc729ee19U, 0x793a43a7U, 0xc1ac6d1fU, 0xfcdf2322U, + 0x1fc7d8c1U, 0xe701e639U, 0x612445bfU, 0x692e47b7U, + 0x7eff81a0U, 0x9b62f945U, 0x6fabc4b1U, 0x26b197f8U, + 0xddb76a03U, 0x72f082acU, 0x22b496fcU, 0x114859cfU, + 0xa354f77dU, 0x302010eeU, 0x823cbe5cU, 0x283e16f6U, + 0xaa1eb474U, 0x0d535ed3U, 0x257154fbU, 0x07d9ded9U, + 0x9de77a43U, 0xe4c1253aU, 0x90a8384eU, 0x140d19caU, + 0xfe5fa120U, 0xc669af18U, 0x753540abU, 0xbc8f3362U, + 0xd278aa0cU, 0x5ed78980U, 0x9368fb4dU, 0x154d58cbU, + 0xa5d1747bU, 0x56dd8b88U, 0x001c1cdeU, 0x606404beU, + 0x1c071bc2U, 0x18021ac6U, 0xc4e92d1aU, 0xeccb2732U, + 0x9f67f841U, 0xc5a96c1bU, 0x17cddac9U, 0xe304e73dU, + 0x4789ce99U, 0xde77a900U, 0x5b92c985U, 0x545d098aU, + 0xed8b6633U, 0xce63ad10U, 0xd8f22a06U, 0xac9b3772U, + 0xd5bd680bU, 0xe98e6737U, 0xc0ec2c1eU, 0xca66ac14U, + 0x81fc7d5fU, 0xae1bb570U, 0x6d2b46b3U, 0x8b76fd55U, + 0x3fefd0e1U, 0x9e27b940U, 0x44490d9aU, 0x5f97c881U, + 0x1d475ac3U, 0x787a02a6U, 0xea4ea434U, 0xe184653fU, + 0x4b86cd95U, 0x3eaf91e0U, 0x7bbac1a5U, 0x6baec5b5U, + 0x8f73fc51U, 0x0c131fd2U, 0xf715e229U, 0x80bc3c5eU, + 0x99e27b47U, 0xf310e32dU, 0x747501aaU, 0x5058088eU, + 0x3c2f13e2U, 0x4f83cc91U, 0x6eeb85b0U, 0x8df37e53U, + 0xbe0fb160U, 0x100818ceU, 0xb200b26cU, 0xbb4af165U, + 0xc9a66f17U, 0x6aee84b4U, 0x5c570b82U, 0x1a8298c4U, + 0x410c4d9fU, 0xda72a804U, 0x9ca73b42U, 0x297e57f7U, + 0x4c430f92U, 0x12889accU, 0xd4fd290aU, 0x5118498fU, + 0xf655a328U, 0x8639bf58U, 0x4d034e93U, 0x88b63e56U, + 0x173027a9U, 0x0e6e60b0U, 0xebf31855U, 0xb7b80f09U, + 0x7f423dc1U, 0xcbdb1075U, 0xb877cf06U, 0x92d5472cU, + 0x14f0e4aaU, 0x96d04628U, 0x1cfae6a2U, 0x477433f9U, + 0xec36da52U, 0xa3a90a1dU, 0xfc22de42U, 0x58aff7e6U, + 0xe039d95eU, 0xd145946fU, 0x264c6a98U, 0x9510852bU, + 0xe43cd85aU, 0xb6f84e08U, 0x5caaf6e2U, 0x437132fdU, + 0xe6bc5a58U, 0x5deab7e3U, 0x00e1e1beU, 0xd400d46aU, + 0x69d3bad7U, 0x562076e8U, 0x54a0f4eaU, 0x2a436994U, + 0x3e526c80U, 0x45f4b1fbU, 0x0daea3b3U, 0x9f9a0521U, + 0x0a6b61b4U, 0xf3ed1e4dU, 0x2e466890U, 0xa52c891bU, + 0x8041c13eU, 0x1dbaa7a3U, 0x6099f9deU, 0x41f1b0ffU, + 0xfbe71c45U, 0x734d3ecdU, 0xfea25c40U, 0xc554917bU, + 0xdfca1561U, 0x82c1433cU, 0x3cd2ee82U, 0xeab35954U, + 0x6b5338d5U, 0x6c96fad2U, 0xeff61951U, 0x1a7f65a4U, + 0x4e3e70f0U, 0x331d2e8dU, 0x1e7a64a0U, 0xa7ac0b19U, + 0x991f8627U, 0x720d7fccU, 0xb07dcd0eU, 0xd6805668U, + 0x51e5b4efU, 0x50a5f5eeU, 0xd285576cU, 0xbfb20d01U, + 0x8381023dU, 0x8101803fU, 0x10f5e5aeU, 0xa6ec4a18U, + 0x423173fcU, 0x2983aa97U, 0xbc72ce02U, 0x28c3eb96U, + 0xd7c01769U, 0x5a2f75e4U, 0x71cdbccfU, 0xeeb65850U, + 0xed769b53U, 0xe179985fU, 0x4a3b71f4U, 0x86c44238U, + 0x890b8237U, 0xdd4a9763U, 0x270c2b99U, 0x62197bdcU, + 0xafa60911U, 0xe3f91a5dU, 0x708dfdceU, 0x61d9b8dfU, + 0x8d0e8333U, 0x15b0a5abU, 0x3a576d84U, 0x985fc726U, + 0x34d8ec8aU, 0xdc0ad662U, 0x7488fccaU, 0x3598ad8bU, + 0xc151907fU, 0x2d86ab93U, 0x0b2b20b5U, 0xc6945278U, + 0xd80fd766U, 0xc414d07aU, 0xbd328f03U, 0xa069c91eU, + 0x48bbf3f6U, 0xc81bd376U, 0xad268b13U, 0x522577ecU, + 0x1f3a25a1U, 0x4cbef2f2U, 0x55e0b5ebU, 0x11b5a4afU, + 0x325d6f8cU, 0x032122bdU, 0xd005d56eU, 0x05a4a1bbU, + 0x7dc2bfc3U, 0x9450c42aU, 0x44b4f0faU, 0xd3c5166dU, + 0xce9e5070U, 0x5f6a35e1U, 0x6f5639d1U, 0x36586e88U, + 0xe7fc1b59U, 0xb2fd4f0cU, 0x661c7ad8U, 0x072423b9U, + 0x4dfeb3f3U, 0x536536edU, 0xac66ca12U, 0x9adf4524U, + 0xc291537cU, 0x9395062dU, 0x87840339U, 0x77483fc9U, + 0xaba30815U, 0xc95b9277U, 0x18ffe7a6U, 0xca9b5174U, + 0xcfde1171U, 0xf6a85e48U, 0x3997ae87U, 0xde8a5460U, + 0x22496b9cU, 0x9c5ac622U, 0x24cce89aU, 0x19bfa6a7U, + 0xfaa75d44U, 0x026163bcU, 0x8444c03aU, 0x8c4ec232U, + 0x9b9f0425U, 0x7e027cc0U, 0x8acb4134U, 0xc3d1127dU, + 0x38d7ef86U, 0x97900729U, 0xc7d41379U, 0xf428dc4aU, + 0x463472f8U, 0xd540956bU, 0x675c3bd9U, 0xcd5e9373U, + 0x4f7e31f1U, 0xe833db56U, 0xc011d17eU, 0xe2b95b5cU, + 0x7887ffc6U, 0x01a1a0bfU, 0x75c8bdcbU, 0xf16d9c4fU, + 0x1b3f24a5U, 0x23092a9dU, 0x9055c52eU, 0x59efb6e7U, + 0x37182f89U, 0xbbb70c05U, 0x76087ec8U, 0xf02ddd4eU, + 0x40b1f1feU, 0xb3bd0e0dU, 0xe57c995bU, 0x8504813bU, + 0xf9679e47U, 0xfd629f43U, 0x2189a89fU, 0x09aba2b7U, + 0x7a077dc4U, 0x20c9e99eU, 0xf2ad5f4cU, 0x066462b8U, + 0xa2e94b1cU, 0x3b172c85U, 0xbef24c00U, 0xb13d8c0fU, + 0x08ebe3b6U, 0x2b032895U, 0x3d92af83U, 0x49fbb2f7U, + 0x30dded8eU, 0x0ceee2b2U, 0x258ca99bU, 0x2f062991U, + 0x649cf8daU, 0x4b7b30f5U, 0x884bc336U, 0x6e1678d0U, + 0xda8f5564U, 0x7b473cc5U, 0xa129881fU, 0xbaf74d04U, + 0xf827df46U, 0x9d1a8723U, 0x0f2e21b1U, 0x04e4e0baU, + 0xaee64810U, 0xdbcf1465U, 0x9eda4420U, 0x8ece4030U, + 0x6a1379d4U, 0xe9739a57U, 0x127567acU, 0x65dcb9dbU, + 0x7c82fec2U, 0x167066a8U, 0x9115842fU, 0xb5388d0bU, + 0xd94f9667U, 0xaae34914U, 0x8b8b0035U, 0x6893fbd6U, + 0x5b6f34e5U, 0xf5689d4bU, 0x576037e9U, 0x5e2a74e0U, + 0x2cc6ea92U, 0x8f8e0131U, 0xb9378e07U, 0xffe21d41U, + 0xa46cc81aU, 0x3f122d81U, 0x79c7bec7U, 0xcc1ed272U, + 0xa9238a17U, 0xf7e81f49U, 0x319dac8fU, 0xb478cc0aU, + 0x133526adU, 0x63593addU, 0xa863cb16U, 0x6dd6bbd3U, + 0xd8f028a6U, 0xc1ae6fbfU, 0x2433175aU, 0x78780006U, + 0xb08232ceU, 0x041b1f7aU, 0x77b7c009U, 0x5d154823U, + 0xdb30eba5U, 0x59104927U, 0xd33ae9adU, 0x88b43cf6U, + 0x23f6d55dU, 0x6c690512U, 0x33e2d14dU, 0x976ff8e9U, + 0x2ff9d651U, 0x1e859b60U, 0xe98c6597U, 0x5ad08a24U, + 0x2bfcd755U, 0x79384107U, 0x936af9edU, 0x8cb13df2U, + 0x297c5557U, 0x922ab8ecU, 0xcf21eeb1U, 0x1bc0db65U, + 0xa613b5d8U, 0x99e079e7U, 0x9b60fbe5U, 0xe583669bU, + 0xf192638fU, 0x8a34bef4U, 0xc26eacbcU, 0x505a0a2eU, + 0xc5ab6ebbU, 0x3c2d1142U, 0xe186679fU, 0x6aec8614U, + 0x4f81ce31U, 0xd27aa8acU, 0xaf59f6d1U, 0x8e31bff0U, + 0x3427134aU, 0xbc8d31c2U, 0x3162534fU, 0x0a949e74U, + 0x100a1a6eU, 0x4d014c33U, 0xf312e18dU, 0x2573565bU, + 0xa49337daU, 0xa356f5ddU, 0x2036165eU, 0xd5bf6aabU, + 0x81fe7fffU, 0xfcdd2182U, 0xd1ba6bafU, 0x686c0416U, + 0x56df8928U, 0xbdcd70c3U, 0x7fbdc201U, 0x19405967U, + 0x9e25bbe0U, 0x9f65fae1U, 0x1d455863U, 0x7072020eU, + 0x4c410d32U, 0x4ec18f30U, 0xdf35eaa1U, 0x692c4517U, + 0x8df17cf3U, 0xe643a598U, 0x73b2c10dU, 0xe703e499U, + 0x18001866U, 0x95ef7aebU, 0xbe0db3c0U, 0x2176575fU, + 0x22b6945cU, 0x2eb99750U, 0x85fb7efbU, 0x49044d37U, + 0x46cb8d38U, 0x128a986cU, 0xe8cc2496U, 0xadd974d3U, + 0x6066061eU, 0x2c391552U, 0xbf4df2c1U, 0xae19b7d0U, + 0x42ce8c3cU, 0xda70aaa4U, 0xf597628bU, 0x579fc829U, + 0xfb18e385U, 0x13cad96dU, 0xbb48f3c5U, 0xfa58a284U, + 0x0e919f70U, 0xe246a49cU, 0xc4eb2fbaU, 0x09545d77U, + 0x17cfd869U, 0x0bd4df75U, 0x72f2800cU, 0x6fa9c611U, + 0x877bfcf9U, 0x07dbdc79U, 0x62e6841cU, 0x9de578e3U, + 0xd0fa2aaeU, 0x837efdfdU, 0x9a20bae4U, 0xde75aba0U, + 0xfd9d6083U, 0xcce12db2U, 0x1fc5da61U, 0xca64aeb4U, + 0xb202b0ccU, 0x5b90cb25U, 0x8b74fff5U, 0x1c051962U, + 0x015e5f7fU, 0x90aa3aeeU, 0xa09636deU, 0xf9986187U, + 0x283c1456U, 0x7d3d4003U, 0xa9dc75d7U, 0xc8e42cb6U, + 0x823ebcfcU, 0x9ca539e2U, 0x63a6c51dU, 0x551f4a2bU, + 0x0d515c73U, 0x5c550922U, 0x48440c36U, 0xb88830c6U, + 0x6463071aU, 0x069b9d78U, 0xd73fe8a9U, 0x055b5e7bU, + 0x001e1e7eU, 0x39685147U, 0xf657a188U, 0x114a5b6fU, + 0xed896493U, 0x539ac92dU, 0xeb0ce795U, 0xd67fa9a8U, + 0x3567524bU, 0xcda16cb3U, 0x4b84cf35U, 0x438ecd3dU, + 0x545f0b2aU, 0xb1c273cfU, 0x450b4e3bU, 0x0c111d72U, + 0xf717e089U, 0x58500826U, 0x08141c76U, 0x3be8d345U, + 0x89f47df7U, 0x1a809a64U, 0xa89c34d6U, 0x029e9c7cU, + 0x80be3efeU, 0x27f3d459U, 0x0fd1de71U, 0x2d795453U, + 0xb747f0c9U, 0xce61afb0U, 0xba08b2c4U, 0x3ead9340U, + 0xd4ff2baaU, 0xecc92592U, 0x5f95ca21U, 0x962fb9e8U, + 0xf8d82086U, 0x7477030aU, 0xb9c871c7U, 0x3fedd241U, + 0x8f71fef1U, 0x7c7d0102U, 0x2abc9654U, 0x4ac48e34U, + 0x36a79148U, 0x32a2904cU, 0xee49a790U, 0xc66badb8U, + 0xb5c772cbU, 0xef09e691U, 0x3d6d5043U, 0xc9a46db7U, + 0x6d294413U, 0xf4d7238aU, 0x7132430fU, 0x7efd8300U, + 0xc72becb9U, 0xe4c3279aU, 0xf252a08cU, 0x863bbdf8U, + 0xff1de281U, 0xc32eedbdU, 0xea4ca694U, 0xe0c6269eU, + 0xab5cf7d5U, 0x84bb3ffaU, 0x478bcc39U, 0xa1d677dfU, + 0x154f5a6bU, 0xb48733caU, 0x6ee98710U, 0x7537420bU, + 0x37e7d049U, 0x52da882cU, 0xc0ee2ebeU, 0xcb24efb5U, + 0x6126471fU, 0x140f1b6aU, 0x511a4b2fU, 0x410e4f3fU, + 0xa5d376dbU, 0x26b39558U, 0xddb568a3U, 0xaa1cb6d4U, + 0xb342f1cdU, 0xd9b069a7U, 0x5ed58b20U, 0x7af88204U, + 0x168f9968U, 0x6523461bU, 0x444b0f3aU, 0xa753f4d9U, + 0x94af3beaU, 0x3aa89244U, 0x98a038e6U, 0x91ea7befU, + 0xe306e59dU, 0x404e0e3eU, 0x76f78108U, 0x3022124eU, + 0x6bacc715U, 0xf0d2228eU, 0xb607b1c8U, 0x03dedd7dU, + 0x66e38518U, 0x38281046U, 0xfe5da380U, 0x7bb8c305U, + 0xdcf529a2U, 0xac9935d2U, 0x67a3c419U, 0xa216b4dcU, + 0x0e9f911fU, 0x17c1d606U, 0xf25caee3U, 0xae17b9bfU, + 0x66ed8b77U, 0xd274a6c3U, 0xa1d879b0U, 0x8b7af19aU, + 0x0d5f521cU, 0x8f7ff09eU, 0x05555014U, 0x5edb854fU, + 0xf5996ce4U, 0xba06bcabU, 0xe58d68f4U, 0x41004150U, + 0xf9966fe8U, 0xc8ea22d9U, 0x3fe3dc2eU, 0x8cbf339dU, + 0xfd936eecU, 0xaf57f8beU, 0x45054054U, 0x5ade844bU, + 0xff13eceeU, 0x44450155U, 0x194e5708U, 0xcdaf62dcU, + 0x707c0c61U, 0x4f8fc05eU, 0x4d0f425cU, 0x33ecdf22U, + 0x27fdda36U, 0x5c5b074dU, 0x14011505U, 0x8635b397U, + 0x13c4d702U, 0xea42a8fbU, 0x37e9de26U, 0xbc833fadU, + 0x99ee7788U, 0x04151115U, 0x79364f68U, 0x585e0649U, + 0xe248aaf3U, 0x6ae2887bU, 0xe70deaf6U, 0xdcfb27cdU, + 0xc665a3d7U, 0x9b6ef58aU, 0x257d5834U, 0xf31cefe2U, + 0x72fc8e63U, 0x75394c64U, 0xf659afe7U, 0x03d0d312U, + 0x5791c646U, 0x2ab2983bU, 0x07d5d216U, 0xbe03bdafU, + 0x80b03091U, 0x6ba2c97aU, 0xa9d27bb8U, 0xcf2fe0deU, + 0x484a0259U, 0x490a4358U, 0xcb2ae1daU, 0xa61dbbb7U, + 0x9a2eb48bU, 0x98ae3689U, 0x095a5318U, 0xbf43fcaeU, + 0x5b9ec54aU, 0x302c1c21U, 0xa5dd78b4U, 0x316c5d20U, + 0xce6fa1dfU, 0x4380c352U, 0x68620a79U, 0xf719eee6U, + 0xf4d92de5U, 0xf8d62ee9U, 0x5394c742U, 0x9f6bf48eU, + 0x90a43481U, 0xc4e521d5U, 0x3ea39d2fU, 0x7bb6cd6aU, + 0xb609bfa7U, 0xfa56acebU, 0x69224b78U, 0x78760e69U, + 0x94a13585U, 0x0c1f131dU, 0x23f8db32U, 0x81f07190U, + 0x2d775a3cU, 0xc5a560d4U, 0x6d274a7cU, 0x2c371b3dU, + 0xd8fe26c9U, 0x34291d25U, 0x12849603U, 0xdf3be4ceU, + 0xc1a061d0U, 0xddbb66ccU, 0xa49d39b5U, 0xb9c67fa8U, + 0x51144540U, 0xd1b465c0U, 0xb4893da5U, 0x4b8ac15aU, + 0x06959317U, 0x55114444U, 0x4c4f035dU, 0x081a1219U, + 0x2bf2d93aU, 0x1a8e940bU, 0xc9aa63d8U, 0x1c0b170dU, + 0x646d0975U, 0x8dff729cU, 0x5d1b464cU, 0xca6aa0dbU, + 0xd731e6c6U, 0x46c58357U, 0x76f98f67U, 0x2ff7d83eU, + 0xfe53adefU, 0xab52f9baU, 0x7fb3cc6eU, 0x1e8b950fU, + 0x54510545U, 0x4aca805bU, 0xb5c97ca4U, 0x8370f392U, + 0xdb3ee5caU, 0x8a3ab09bU, 0x9e2bb58fU, 0x6ee7897fU, + 0xb20cbea3U, 0xd0f424c1U, 0x01505110U, 0xd334e7c2U, + 0xd671a7c7U, 0xef07e8feU, 0x20381831U, 0xc725e2d6U, + 0x3be6dd2aU, 0x85f57094U, 0x3d635e2cU, 0x00101011U, + 0xe308ebf2U, 0x1bced50aU, 0x9deb768cU, 0x95e17484U, + 0x8230b293U, 0x67adca76U, 0x9364f782U, 0xda7ea4cbU, + 0x21785930U, 0x8e3fb19fU, 0xde7ba5cfU, 0xed876afcU, + 0x5f9bc44eU, 0xccef23ddU, 0x7ef38d6fU, 0xd4f125c5U, + 0x56d18747U, 0xf19c6de0U, 0xd9be67c8U, 0xfb16edeaU, + 0x61284970U, 0x180e1609U, 0x6c670b7dU, 0xe8c22af9U, + 0x02909213U, 0x3aa69c2bU, 0x89fa7398U, 0x40400051U, + 0x2eb7993fU, 0xa218bab3U, 0x6fa7c87eU, 0xe9826bf8U, + 0x591e4748U, 0xaa12b8bbU, 0xfcd32fedU, 0x9cab378dU, + 0xe0c828f1U, 0xe4cd29f5U, 0x38261e29U, 0x10041401U, + 0x63a8cb72U, 0x39665f28U, 0xeb02e9faU, 0x1fcbd40eU, + 0xbb46fdaaU, 0x22b89a33U, 0xa75dfab6U, 0xa8923ab9U, + 0x11445500U, 0x32ac9e23U, 0x243d1935U, 0x50540441U, + 0x29725b38U, 0x15415404U, 0x3c231f2dU, 0x36a99f27U, + 0x7d334e6cU, 0x52d48643U, 0x91e47580U, 0x77b9ce66U, + 0xc320e3d2U, 0x62e88a73U, 0xb8863ea9U, 0xa358fbb2U, + 0xe18869f0U, 0x84b53195U, 0x16819707U, 0x1d4b560cU, + 0xb749fea6U, 0xc260a2d3U, 0x8775f296U, 0x9761f686U, + 0x73bccf62U, 0xf0dc2ce1U, 0x0bdad11aU, 0x7c730f6dU, + 0x652d4874U, 0x0fdfd01eU, 0x88ba3299U, 0xac973bbdU, + 0xc0e020d1U, 0xb34cffa2U, 0x9224b683U, 0x713c4d60U, + 0x42c08253U, 0xecc72bfdU, 0x4ecf815fU, 0x4785c256U, + 0x35695c24U, 0x9621b787U, 0xa09838b1U, 0xe64dabf7U, + 0xbdc37eacU, 0x26bd9b37U, 0x60680871U, 0xd5b164c4U, + 0xb08c3ca1U, 0xee47a9ffU, 0x28321a39U, 0xadd77abcU, + 0x0a9a901bU, 0x7af68c6bU, 0xb1cc7da0U, 0x74790d65U, + 0xe654b23cU, 0xff0af525U, 0x1a978dc0U, 0x46dc9a9cU, + 0x8e26a854U, 0x3abf85e0U, 0x49135a93U, 0x63b1d2b9U, + 0xe594713fU, 0x67b4d3bdU, 0xed9e7337U, 0xb610a66cU, + 0x1d524fc7U, 0x52cd9f88U, 0x0d464bd7U, 0xa9cb6273U, + 0x115d4ccbU, 0x202101faU, 0xd728ff0dU, 0x647410beU, + 0x15584dcfU, 0x479cdb9dU, 0xadce6377U, 0xb215a768U, + 0x17d8cfcdU, 0xac8e2276U, 0xf185742bU, 0x256441ffU, + 0x98b72f42U, 0xa744e37dU, 0xa5c4617fU, 0xdb27fc01U, + 0xcf36f915U, 0xb490246eU, 0xfcca3626U, 0x6efe90b4U, + 0xfb0ff421U, 0x02898bd8U, 0xdf22fd05U, 0x54481c8eU, + 0x712554abU, 0xecde3236U, 0x91fd6c4bU, 0xb095256aU, + 0x0a8389d0U, 0x8229ab58U, 0x0fc6c9d5U, 0x343004eeU, + 0x2eae80f4U, 0x73a5d6a9U, 0xcdb67b17U, 0x1bd7ccc1U, + 0x9a37ad40U, 0x9df26f47U, 0x1e928cc4U, 0xeb1bf031U, + 0xbf5ae565U, 0xc279bb18U, 0xef1ef135U, 0x56c89e8cU, + 0x687b13b2U, 0x8369ea59U, 0x4119589bU, 0x27e4c3fdU, + 0xa081217aU, 0xa1c1607bU, 0x23e1c2f9U, 0x4ed69894U, + 0x72e597a8U, 0x706515aaU, 0xe191703bU, 0x5788df8dU, + 0xb355e669U, 0xd8e73f02U, 0x4d165b97U, 0xd9a77e03U, + 0x26a482fcU, 0xab4be071U, 0x80a9295aU, 0x1fd2cdc5U, + 0x1c120ec6U, 0x101d0dcaU, 0xbb5fe461U, 0x77a0d7adU, + 0x786f17a2U, 0x2c2e02f6U, 0xd668be0cU, 0x937dee49U, + 0x5ec29c84U, 0x129d8fc8U, 0x81e9685bU, 0x90bd2d4aU, + 0x7c6a16a6U, 0xe4d4303eU, 0xcb33f811U, 0x693b52b3U, + 0xc5bc791fU, 0x2d6e43f7U, 0x85ec695fU, 0xc4fc381eU, + 0x303505eaU, 0xdce23e06U, 0xfa4fb520U, 0x37f0c7edU, + 0x296b42f3U, 0x357045efU, 0x4c561a96U, 0x510d5c8bU, + 0xb9df6663U, 0x397f46e3U, 0x5c421e86U, 0xa341e279U, + 0xee5eb034U, 0xbdda6767U, 0xa484207eU, 0xe0d1313aU, + 0xc339fa19U, 0xf245b728U, 0x216140fbU, 0xf4c0342eU, + 0x8ca62a56U, 0x653451bfU, 0xb5d0656fU, 0x22a183f8U, + 0x3ffac5e5U, 0xae0ea074U, 0x9e32ac44U, 0xc73cfb1dU, + 0x16988eccU, 0x4399da99U, 0x9778ef4dU, 0xf640b62cU, + 0xbc9a2666U, 0xa201a378U, 0x5d025f87U, 0x6bbbd0b1U, + 0x33f5c6e9U, 0x62f193b8U, 0x76e096acU, 0x862caa5cU, + 0x5ac79d80U, 0x383f07e2U, 0xe99b7233U, 0x3bffc4e1U, + 0x3eba84e4U, 0x07cccbddU, 0xc8f33b12U, 0x2feec1f5U, + 0xd32dfe09U, 0x6d3e53b7U, 0xd5a87d0fU, 0xe8db3332U, + 0x0bc3c8d1U, 0xf305f629U, 0x752055afU, 0x7d2a57a7U, + 0x6afb91b0U, 0x8f66e955U, 0x7bafd4a1U, 0x32b587e8U, + 0xc9b37a13U, 0x66f492bcU, 0x36b086ecU, 0x054c49dfU, + 0xb750e76dU, 0x242400feU, 0x9638ae4cU, 0x3c3a06e6U, + 0xbe1aa464U, 0x19574ec3U, 0x317544ebU, 0x13ddcec9U, + 0x89e36a53U, 0xf0c5352aU, 0x84ac285eU, 0x000909daU, + 0xea5bb130U, 0xd26dbf08U, 0x613150bbU, 0xa88b2372U, + 0xc67cba1cU, 0x4ad39990U, 0x876ceb5dU, 0x014948dbU, + 0xb1d5646bU, 0x42d99b98U, 0x14180cceU, 0x746014aeU, + 0x08030bd2U, 0x0c060ad6U, 0xd0ed3d0aU, 0xf8cf3722U, + 0x8b63e851U, 0xd1ad7c0bU, 0x03c9cad9U, 0xf700f72dU, + 0x538dde89U, 0xca73b910U, 0x4f96d995U, 0x4059199aU, + 0xf98f7623U, 0xda67bd00U, 0xccf63a16U, 0xb89f2762U, + 0xc1b9781bU, 0xfd8a7727U, 0xd4e83c0eU, 0xde62bc04U, + 0x95f86d4fU, 0xba1fa560U, 0x792f56a3U, 0x9f72ed45U, + 0x2bebc0f1U, 0x8a23a950U, 0x504d1d8aU, 0x4b93d891U, + 0x09434ad3U, 0x6c7e12b6U, 0xfe4ab424U, 0xf580752fU, + 0x5f82dd85U, 0x2aab81f0U, 0x6fbed1b5U, 0x7faad5a5U, + 0x9b77ec41U, 0x18170fc2U, 0xe311f239U, 0x94b82c4eU, + 0x8de66b57U, 0xe714f33dU, 0x607111baU, 0x445c189eU, + 0x282b03f2U, 0x5b87dc81U, 0x7aef95a0U, 0x99f76e43U, + 0xaa0ba170U, 0x040c08deU, 0xa604a27cU, 0xaf4ee175U, + 0xdda27f07U, 0x7eea94a4U, 0x48531b92U, 0x0e8688d4U, + 0x55085d8fU, 0xce76b814U, 0x88a32b52U, 0x3d7a47e7U, + 0x58471f82U, 0x068c8adcU, 0xc0f9391aU, 0x451c599fU, + 0xe251b338U, 0x923daf48U, 0x59075e83U, 0x9cb22e46U, + 0x77d3a42aU, 0x6e8de333U, 0x8b109bd6U, 0xd75b8c8aU, + 0x1fa1be42U, 0xab3893f6U, 0xd8944c85U, 0xf236c4afU, + 0x74136729U, 0xf633c5abU, 0x7c196521U, 0x2797b07aU, + 0x8cd559d1U, 0xc34a899eU, 0x9cc15dc1U, 0x384c7465U, + 0x80da5addU, 0xb1a617ecU, 0x46afe91bU, 0xf5f306a8U, + 0x84df5bd9U, 0xd61bcd8bU, 0x3c497561U, 0x2392b17eU, + 0x865fd9dbU, 0x3d093460U, 0x6002623dU, 0xb4e357e9U, + 0x09303954U, 0x36c3f56bU, 0x34437769U, 0x4aa0ea17U, + 0x5eb1ef03U, 0x25173278U, 0x6d4d2030U, 0xff7986a2U, + 0x6a88e237U, 0x930e9dceU, 0x4ea5eb13U, 0xc5cf0a98U, + 0xe0a242bdU, 0x7d592420U, 0x007a7a5dU, 0x2112337cU, + 0x9b049fc6U, 0x13aebd4eU, 0x9e41dfc3U, 0xa5b712f8U, + 0xbf2996e2U, 0xe222c0bfU, 0x5c316d01U, 0x8a50dad7U, + 0x0bb0bb56U, 0x0c757951U, 0x8f159ad2U, 0x7a9ce627U, + 0x2eddf373U, 0x53fead0eU, 0x7e99e723U, 0xc74f889aU, + 0xf9fc05a4U, 0x12eefc4fU, 0xd09e4e8dU, 0xb663d5ebU, + 0x3106376cU, 0x3046766dU, 0xb266d4efU, 0xdf518e82U, + 0xe36281beU, 0xe1e203bcU, 0x7016662dU, 0xc60fc99bU, + 0x22d2f07fU, 0x49602914U, 0xdc914d81U, 0x48206815U, + 0xb72394eaU, 0x3accf667U, 0x112e3f4cU, 0x8e55dbd3U, + 0x8d9518d0U, 0x819a1bdcU, 0x2ad8f277U, 0xe627c1bbU, + 0xe9e801b4U, 0xbda914e0U, 0x47efa81aU, 0x02faf85fU, + 0xcf458a92U, 0x831a99deU, 0x106e7e4dU, 0x013a3b5cU, + 0xeded00b0U, 0x75532628U, 0x5ab4ee07U, 0xf8bc44a5U, + 0x543b6f09U, 0xbce955e1U, 0x146b7f49U, 0x557b2e08U, + 0xa1b213fcU, 0x4d652810U, 0x6bc8a336U, 0xa677d1fbU, + 0xb8ec54e5U, 0xa4f753f9U, 0xddd10c80U, 0xc08a4a9dU, + 0x28587075U, 0xa8f850f5U, 0xcdc50890U, 0x32c6f46fU, + 0x7fd9a622U, 0x2c5d7171U, 0x35033668U, 0x7156272cU, + 0x52beec0fU, 0x63c2a13eU, 0xb0e656edU, 0x65472238U, + 0x1d213c40U, 0xf4b347a9U, 0x24577379U, 0xb32695eeU, + 0xae7dd3f3U, 0x3f89b662U, 0x0fb5ba52U, 0x56bbed0bU, + 0x871f98daU, 0xd21ecc8fU, 0x06fff95bU, 0x67c7a03aU, + 0x2d1d3070U, 0x3386b56eU, 0xcc854991U, 0xfa3cc6a7U, + 0xa272d0ffU, 0xf37685aeU, 0xe76780baU, 0x17abbc4aU, + 0xcb408b96U, 0xa9b811f4U, 0x781c6425U, 0xaa78d2f7U, + 0xaf3d92f2U, 0x964bddcbU, 0x59742d04U, 0xbe69d7e3U, + 0x42aae81fU, 0xfcb945a1U, 0x442f6b19U, 0x795c2524U, + 0x9a44dec7U, 0x6282e03fU, 0xe4a743b9U, 0xecad41b1U, + 0xfb7c87a6U, 0x1ee1ff43U, 0xea28c2b7U, 0xa33291feU, + 0x58346c05U, 0xf77384aaU, 0xa73790faU, 0x94cb5fc9U, + 0x26d7f17bU, 0xb5a316e8U, 0x07bfb85aU, 0xadbd10f0U, + 0x2f9db272U, 0x88d058d5U, 0xa0f252fdU, 0x825ad8dfU, + 0x18647c45U, 0x6142233cU, 0x152b3e48U, 0x918e1fccU, + 0x7bdca726U, 0x43eaa91eU, 0xf0b646adU, 0x390c3564U, + 0x57fbac0aU, 0xdb548f86U, 0x16ebfd4bU, 0x90ce5ecdU, + 0x2052727dU, 0xd35e8d8eU, 0x859f1ad8U, 0xe5e702b8U, + 0x99841dc4U, 0x9d811cc0U, 0x416a2b1cU, 0x69482134U, + 0x1ae4fe47U, 0x402a6a1dU, 0x924edccfU, 0x6687e13bU, + 0xc20ac89fU, 0x5bf4af06U, 0xde11cf83U, 0xd1de0f8cU, + 0x68086035U, 0x4be0ab16U, 0x5d712c00U, 0x29183174U, + 0x503e6e0dU, 0x6c0d6131U, 0x456f2a18U, 0x4fe5aa12U, + 0x047f7b59U, 0x2b98b376U, 0xe8a840b5U, 0x0ef5fb53U, + 0xba6cd6e7U, 0x1ba4bf46U, 0xc1ca0b9cU, 0xda14ce87U, + 0x98c45cc5U, 0xfdf904a0U, 0x6fcda232U, 0x64076339U, + 0xce05cb93U, 0xbb2c97e6U, 0xfe39c7a3U, 0xee2dc3b3U, + 0x0af0fa57U, 0x899019d4U, 0x7296e42fU, 0x053f3a58U, + 0x1c617d41U, 0x7693e52bU, 0xf1f607acU, 0xd5db0e88U, + 0xb9ac15e4U, 0xca00ca97U, 0xeb6883b6U, 0x08707855U, + 0x3b8cb766U, 0x958b1ec8U, 0x3783b46aU, 0x3ec9f763U, + 0x4c256911U, 0xef6d82b2U, 0xd9d40d84U, 0x9f019ec2U, + 0xc48f4b99U, 0x5ff1ae02U, 0x19243d44U, 0xacfd51f1U, + 0xc9c00994U, 0x970b9ccaU, 0x517e2f0cU, 0xd49b4f89U, + 0x73d6a52eU, 0x03bab95eU, 0xc8804895U, 0x0d353850U, + 0x1eced05eU, 0x07909747U, 0xe20defa2U, 0xbe46f8feU, + 0x76bcca36U, 0xc225e782U, 0xb18938f1U, 0x9b2bb0dbU, + 0x1d0e135dU, 0x9f2eb1dfU, 0x15041155U, 0x4e8ac40eU, + 0xe5c82da5U, 0xaa57fdeaU, 0xf5dc29b5U, 0x51510011U, + 0xe9c72ea9U, 0xd8bb6398U, 0x2fb29d6fU, 0x9cee72dcU, + 0xedc22fadU, 0xbf06b9ffU, 0x55540115U, 0x4a8fc50aU, + 0xef42adafU, 0x54144014U, 0x091f1649U, 0xddfe239dU, + 0x602d4d20U, 0x5fde811fU, 0x5d5e031dU, 0x23bd9e63U, + 0x37ac9b77U, 0x4c0a460cU, 0x04505444U, 0x9664f2d6U, + 0x03959643U, 0xfa13e9baU, 0x27b89f67U, 0xacd27eecU, + 0x89bf36c9U, 0x14445054U, 0x69670e29U, 0x480f4708U, + 0xf219ebb2U, 0x7ab3c93aU, 0xf75cabb7U, 0xccaa668cU, + 0xd634e296U, 0x8b3fb4cbU, 0x352c1975U, 0xe34daea3U, + 0x62adcf22U, 0x65680d25U, 0xe608eea6U, 0x13819253U, + 0x47c08707U, 0x3ae3d97aU, 0x17849357U, 0xae52fceeU, + 0x90e171d0U, 0x7bf3883bU, 0xb9833af9U, 0xdf7ea19fU, + 0x581b4318U, 0x595b0219U, 0xdb7ba09bU, 0xb64cfaf6U, + 0x8a7ff5caU, 0x88ff77c8U, 0x190b1259U, 0xaf12bdefU, + 0x4bcf840bU, 0x207d5d60U, 0xb58c39f5U, 0x213d1c61U, + 0xde3ee09eU, 0x53d18213U, 0x78334b38U, 0xe748afa7U, + 0xe4886ca4U, 0xe8876fa8U, 0x43c58603U, 0x8f3ab5cfU, + 0x80f575c0U, 0xd4b46094U, 0x2ef2dc6eU, 0x6be78c2bU, + 0xa658fee6U, 0xea07edaaU, 0x79730a39U, 0x68274f28U, + 0x84f074c4U, 0x1c4e525cU, 0x33a99a73U, 0x91a130d1U, + 0x3d261b7dU, 0xd5f42195U, 0x7d760b3dU, 0x3c665a7cU, + 0xc8af6788U, 0x24785c64U, 0x02d5d742U, 0xcf6aa58fU, + 0xd1f12091U, 0xcdea278dU, 0xb4cc78f4U, 0xa9973ee9U, + 0x41450401U, 0xc1e52481U, 0xa4d87ce4U, 0x5bdb801bU, + 0x16c4d256U, 0x45400505U, 0x5c1e421cU, 0x184b5358U, + 0x3ba3987bU, 0x0adfd54aU, 0xd9fb2299U, 0x0c5a564cU, + 0x743c4834U, 0x9dae33ddU, 0x4d4a070dU, 0xda3be19aU, + 0xc760a787U, 0x5694c216U, 0x66a8ce26U, 0x3fa6997fU, + 0xee02ecaeU, 0xbb03b8fbU, 0x6fe28d2fU, 0x0edad44eU, + 0x44004404U, 0x5a9bc11aU, 0xa5983de5U, 0x9321b2d3U, + 0xcb6fa48bU, 0x9a6bf1daU, 0x8e7af4ceU, 0x7eb6c83eU, + 0xa25dffe2U, 0xc0a56580U, 0x11011051U, 0xc365a683U, + 0xc620e686U, 0xff56a9bfU, 0x30695970U, 0xd774a397U, + 0x2bb79c6bU, 0x95a431d5U, 0x2d321f6dU, 0x10415150U, + 0xf359aab3U, 0x0b9f944bU, 0x8dba37cdU, 0x85b035c5U, + 0x9261f3d2U, 0x77fc8b37U, 0x8335b6c3U, 0xca2fe58aU, + 0x31291871U, 0x9e6ef0deU, 0xce2ae48eU, 0xfdd62bbdU, + 0x4fca850fU, 0xdcbe629cU, 0x6ea2cc2eU, 0xc4a06484U, + 0x4680c606U, 0xe1cd2ca1U, 0xc9ef2689U, 0xeb47acabU, + 0x71790831U, 0x085f5748U, 0x7c364a3cU, 0xf8936bb8U, + 0x12c1d352U, 0x2af7dd6aU, 0x99ab32d9U, 0x50114110U, + 0x3ee6d87eU, 0xb249fbf2U, 0x7ff6893fU, 0xf9d32ab9U, + 0x494f0609U, 0xba43f9faU, 0xec826eacU, 0x8cfa76ccU, + 0xf09969b0U, 0xf49c68b4U, 0x28775f68U, 0x00555540U, + 0x73f98a33U, 0x29371e69U, 0xfb53a8bbU, 0x0f9a954fU, + 0xab17bcebU, 0x32e9db72U, 0xb70cbbf7U, 0xb8c37bf8U, + 0x01151441U, 0x22fddf62U, 0x346c5874U, 0x40054500U, + 0x39231a79U, 0x05101545U, 0x2c725e6cU, 0x26f8de66U, + 0x6d620f2dU, 0x4285c702U, 0x81b534c1U, 0x67e88f27U, + 0xd371a293U, 0x72b9cb32U, 0xa8d77fe8U, 0xb309baf3U, + 0xf1d928b1U, 0x94e470d4U, 0x06d0d646U, 0x0d1a174dU, + 0xa718bfe7U, 0xd231e392U, 0x9724b3d7U, 0x8730b7c7U, + 0x63ed8e23U, 0xe08d6da0U, 0x1b8b905bU, 0x6c224e2cU, + 0x757c0935U, 0x1f8e915fU, 0x98eb73d8U, 0xbcc67afcU, + 0xd0b16190U, 0xa31dbee3U, 0x8275f7c2U, 0x616d0c21U, + 0x5291c312U, 0xfc966abcU, 0x5e9ec01eU, 0x57d48317U, + 0x25381d65U, 0x8670f6c6U, 0xb0c979f0U, 0xf61ceab6U, + 0xad923fedU, 0x36ecda76U, 0x70394930U, 0xc5e02585U, + 0xa0dd7de0U, 0xfe16e8beU, 0x38635b78U, 0xbd863bfdU, + 0x1acbd15aU, 0x6aa7cd2aU, 0xa19d3ce1U, 0x64284c24U, + 0x3891a927U, 0x21cfee3eU, 0xc45296dbU, 0x98198187U, + 0x50e3b34fU, 0xe47a9efbU, 0x97d64188U, 0xbd74c9a2U, + 0x3b516a24U, 0xb971c8a6U, 0x335b682cU, 0x68d5bd77U, + 0xc39754dcU, 0x8c088493U, 0xd38350ccU, 0x770e7968U, + 0xcf9857d0U, 0xfee41ae1U, 0x09ede416U, 0xbab10ba5U, + 0xcb9d56d4U, 0x9959c086U, 0x730b786cU, 0x6cd0bc73U, + 0xc91dd4d6U, 0x724b396dU, 0x2f406f30U, 0xfba15ae4U, + 0x46723459U, 0x7981f866U, 0x7b017a64U, 0x05e2e71aU, + 0x11f3e20eU, 0x6a553f75U, 0x220f2d3dU, 0xb03b8bafU, + 0x25caef3aU, 0xdc4c90c3U, 0x01e7e61eU, 0x8a8d0795U, + 0xafe04fb0U, 0x321b292dU, 0x4f387750U, 0x6e503e71U, + 0xd44692cbU, 0x5cecb043U, 0xd103d2ceU, 0xeaf51ff5U, + 0xf06b9befU, 0xad60cdb2U, 0x1373600cU, 0xc512d7daU, + 0x44f2b65bU, 0x4337745cU, 0xc05797dfU, 0x35deeb2aU, + 0x619ffe7eU, 0x1cbca003U, 0x31dbea2eU, 0x880d8597U, + 0xb6be08a9U, 0x5dacf142U, 0x9fdc4380U, 0xf921d8e6U, + 0x7e443a61U, 0x7f047b60U, 0xfd24d9e2U, 0x9013838fU, + 0xac208cb3U, 0xaea00eb1U, 0x3f546b20U, 0x894dc496U, + 0x6d90fd72U, 0x06222419U, 0x93d3408cU, 0x07626518U, + 0xf86199e7U, 0x758efb6aU, 0x5e6c3241U, 0xc117d6deU, + 0xc2d715ddU, 0xced816d1U, 0x659aff7aU, 0xa965ccb6U, + 0xa6aa0cb9U, 0xf2eb19edU, 0x08ada517U, 0x4db8f552U, + 0x8007879fU, 0xcc5894d3U, 0x5f2c7340U, 0x4e783651U, + 0xa2af0dbdU, 0x3a112b25U, 0x15f6e30aU, 0xb7fe49a8U, + 0x1b796204U, 0xf3ab58ecU, 0x5b297244U, 0x1a392305U, + 0xeef01ef1U, 0x0227251dU, 0x248aae3bU, 0xe935dcf6U, + 0xf7ae59e8U, 0xebb55ef4U, 0x9293018dU, 0x8fc84790U, + 0x671a7d78U, 0xe7ba5df8U, 0x8287059dU, 0x7d84f962U, + 0x309bab2fU, 0x631f7c7cU, 0x7a413b65U, 0x3e142a21U, + 0x1dfce102U, 0x2c80ac33U, 0xffa45be0U, 0x2a052f35U, + 0x5263314dU, 0xbbf14aa4U, 0x6b157e74U, 0xfc6498e3U, + 0xe13fdefeU, 0x70cbbb6fU, 0x40f7b75fU, 0x19f9e006U, + 0xc85d95d7U, 0x9d5cc182U, 0x49bdf456U, 0x2885ad37U, + 0x625f3d7dU, 0x7cc4b863U, 0x83c7449cU, 0xb57ecbaaU, + 0xed30ddf2U, 0xbc3488a3U, 0xa8258db7U, 0x58e9b147U, + 0x8402869bU, 0xe6fa1cf9U, 0x375e6928U, 0xe53adffaU, + 0xe07f9fffU, 0xd909d0c6U, 0x16362009U, 0xf12bdaeeU, + 0x0de8e512U, 0xb3fb48acU, 0x0b6d6614U, 0x361e2829U, + 0xd506d3caU, 0x2dc0ed32U, 0xabe54eb4U, 0xa3ef4cbcU, + 0xb43e8aabU, 0x51a3f24eU, 0xa56acfbaU, 0xec709cf3U, + 0x17766108U, 0xb83189a7U, 0xe8759df7U, 0xdb8952c4U, + 0x6995fc76U, 0xfae11be5U, 0x48fdb557U, 0xe2ff1dfdU, + 0x60dfbf7fU, 0xc79255d8U, 0xefb05ff0U, 0xcd18d5d2U, + 0x57267148U, 0x2e002e31U, 0x5a693345U, 0xdecc12c1U, + 0x349eaa2bU, 0x0ca8a413U, 0xbff44ba0U, 0x764e3869U, + 0x18b9a107U, 0x9416828bU, 0x59a9f046U, 0xdf8c53c0U, + 0x6f107f70U, 0x9c1c8083U, 0xcadd17d5U, 0xaaa50fb5U, + 0xd6c610c9U, 0xd2c311cdU, 0x0e282611U, 0x260a2c39U, + 0x55a6f34aU, 0x0f686710U, 0xdd0cd1c2U, 0x29c5ec36U, + 0x8d48c592U, 0x14b6a20bU, 0x9153c28eU, 0x9e9c0281U, + 0x274a6d38U, 0x04a2a61bU, 0x1233210dU, 0x665a3c79U, + 0x1f7c6300U, 0x234f6c3cU, 0x0a2d2715U, 0x00a7a71fU, + 0x4b3d7654U, 0x64dabe7bU, 0xa7ea4db8U, 0x41b7f65eU, + 0xf52edbeaU, 0x54e6b24bU, 0x8e880691U, 0x9556c38aU, + 0xd78651c8U, 0xb2bb09adU, 0x208faf3fU, 0x2b456e34U, + 0x8147c69eU, 0xf46e9aebU, 0xb17bcaaeU, 0xa16fcebeU, + 0x45b2f75aU, 0xc6d214d9U, 0x3dd4e922U, 0x4a7d3755U, + 0x5323704cU, 0x39d1e826U, 0xbeb40aa1U, 0x9a990385U, + 0xf6ee18e9U, 0x8542c79aU, 0xa42a8ebbU, 0x47327558U, + 0x74ceba6bU, 0xdac913c5U, 0x78c1b967U, 0x718bfa6eU, + 0x0367641cU, 0xa02f8fbfU, 0x96960089U, 0xd04393cfU, + 0x8bcd4694U, 0x10b3a30fU, 0x56663049U, 0xe3bf5cfcU, + 0x86820499U, 0xd84991c7U, 0x1e3c2201U, 0x9bd94284U, + 0x3c94a823U, 0x4cf8b453U, 0x87c24598U, 0x4277355dU, + 0x0b9e951bU, 0x12c0d202U, 0xf75daae7U, 0xab16bdbbU, + 0x63ec8f73U, 0xd775a2c7U, 0xa4d97db4U, 0x8e7bf59eU, + 0x085e5618U, 0x8a7ef49aU, 0x00545410U, 0x5bda814bU, + 0xf09868e0U, 0xbf07b8afU, 0xe08c6cf0U, 0x44014554U, + 0xfc976becU, 0xcdeb26ddU, 0x3ae2d82aU, 0x89be3799U, + 0xf8926ae8U, 0xaa56fcbaU, 0x40044450U, 0x5fdf804fU, + 0xfa12e8eaU, 0x41440551U, 0x1c4f530cU, 0xc8ae66d8U, + 0x757d0865U, 0x4a8ec45aU, 0x480e4658U, 0x36eddb26U, + 0x22fcde32U, 0x595a0349U, 0x11001101U, 0x8334b793U, + 0x16c5d306U, 0xef43acffU, 0x32e8da22U, 0xb9823ba9U, + 0x9cef738cU, 0x01141511U, 0x7c374b6cU, 0x5d5f024dU, + 0xe749aef7U, 0x6fe38c7fU, 0xe20ceef2U, 0xd9fa23c9U, + 0xc364a7d3U, 0x9e6ff18eU, 0x207c5c30U, 0xf61debe6U, + 0x77fd8a67U, 0x70384860U, 0xf358abe3U, 0x06d1d716U, + 0x5290c242U, 0x2fb39c3fU, 0x02d4d612U, 0xbb02b9abU, + 0x85b13495U, 0x6ea3cd7eU, 0xacd37fbcU, 0xca2ee4daU, + 0x4d4b065dU, 0x4c0b475cU, 0xce2be5deU, 0xa31cbfb3U, + 0x9f2fb08fU, 0x9daf328dU, 0x0c5b571cU, 0xba42f8aaU, + 0x5e9fc14eU, 0x352d1825U, 0xa0dc7cb0U, 0x346d5924U, + 0xcb6ea5dbU, 0x4681c756U, 0x6d630e7dU, 0xf218eae2U, + 0xf1d829e1U, 0xfdd72aedU, 0x5695c346U, 0x9a6af08aU, + 0x95a53085U, 0xc1e425d1U, 0x3ba2992bU, 0x7eb7c96eU, + 0xb308bba3U, 0xff57a8efU, 0x6c234f7cU, 0x7d770a6dU, + 0x91a03181U, 0x091e1719U, 0x26f9df36U, 0x84f17594U, + 0x28765e38U, 0xc0a464d0U, 0x68264e78U, 0x29361f39U, + 0xddff22cdU, 0x31281921U, 0x17859207U, 0xda3ae0caU, + 0xc4a165d4U, 0xd8ba62c8U, 0xa19c3db1U, 0xbcc77bacU, + 0x54154144U, 0xd4b561c4U, 0xb18839a1U, 0x4e8bc55eU, + 0x03949713U, 0x50104040U, 0x494e0759U, 0x0d1b161dU, + 0x2ef3dd3eU, 0x1f8f900fU, 0xccab67dcU, 0x190a1309U, + 0x616c0d71U, 0x88fe7698U, 0x581a4248U, 0xcf6ba4dfU, + 0xd230e2c2U, 0x43c48753U, 0x73f88b63U, 0x2af6dc3aU, + 0xfb52a9ebU, 0xae53fdbeU, 0x7ab2c86aU, 0x1b8a910bU, + 0x51500141U, 0x4fcb845fU, 0xb0c878a0U, 0x8671f796U, + 0xde3fe1ceU, 0x8f3bb49fU, 0x9b2ab18bU, 0x6be68d7bU, + 0xb70dbaa7U, 0xd5f520c5U, 0x04515514U, 0xd635e3c6U, + 0xd370a3c3U, 0xea06ecfaU, 0x25391c35U, 0xc224e6d2U, + 0x3ee7d92eU, 0x80f47490U, 0x38625a28U, 0x05111415U, + 0xe609eff6U, 0x1ecfd10eU, 0x98ea7288U, 0x90e07080U, + 0x8731b697U, 0x62acce72U, 0x9665f386U, 0xdf7fa0cfU, + 0x24795d34U, 0x8b3eb59bU, 0xdb7aa1cbU, 0xe8866ef8U, + 0x5a9ac04aU, 0xc9ee27d9U, 0x7bf2896bU, 0xd1f021c1U, + 0x53d08343U, 0xf49d69e4U, 0xdcbf63ccU, 0xfe17e9eeU, + 0x64294d74U, 0x1d0f120dU, 0x69660f79U, 0xedc32efdU, + 0x07919617U, 0x3fa7982fU, 0x8cfb779cU, 0x45410455U, + 0x2bb69d3bU, 0xa719beb7U, 0x6aa6cc7aU, 0xec836ffcU, + 0x5c1f434cU, 0xaf13bcbfU, 0xf9d22be9U, 0x99aa3389U, + 0xe5c92cf5U, 0xe1cc2df1U, 0x3d271a2dU, 0x15051005U, + 0x66a9cf76U, 0x3c675b2cU, 0xee03edfeU, 0x1acad00aU, + 0xbe47f9aeU, 0x27b99e37U, 0xa25cfeb2U, 0xad933ebdU, + 0x14455104U, 0x37ad9a27U, 0x213c1d31U, 0x55550045U, + 0x2c735f3cU, 0x10405000U, 0x39221b29U, 0x33a89b23U, + 0x78324a68U, 0x57d58247U, 0x94e57184U, 0x72b8ca62U, + 0xc621e7d6U, 0x67e98e77U, 0xbd873aadU, 0xa659ffb6U, + 0xe4896df4U, 0x81b43591U, 0x13809303U, 0x184a5208U, + 0xb248faa2U, 0xc761a6d7U, 0x8274f692U, 0x9260f282U, + 0x76bdcb66U, 0xf5dd28e5U, 0x0edbd51eU, 0x79720b69U, + 0x602c4c70U, 0x0aded41aU, 0x8dbb369dU, 0xa9963fb9U, + 0xc5e124d5U, 0xb64dfba6U, 0x9725b287U, 0x743d4964U, + 0x47c18657U, 0xe9c62ff9U, 0x4bce855bU, 0x4284c652U, + 0x30685820U, 0x9320b383U, 0xa5993cb5U, 0xe34caff3U, + 0xb8c27aa8U, 0x23bc9f33U, 0x65690c75U, 0xd0b060c0U, + 0xb58d38a5U, 0xeb46adfbU, 0x2d331e3dU, 0xa8d67eb8U, + 0x0f9b941fU, 0x7ff7886fU, 0xb4cd79a4U, 0x71780961U, + 0x69d5bc32U, 0x708bfb2bU, 0x951683ceU, 0xc95d9492U, + 0x01a7a65aU, 0xb53e8beeU, 0xc692549dU, 0xec30dcb7U, + 0x6a157f31U, 0xe835ddb3U, 0x621f7d39U, 0x3991a862U, + 0x92d341c9U, 0xdd4c9186U, 0x82c745d9U, 0x264a6c7dU, + 0x9edc42c5U, 0xafa00ff4U, 0x58a9f103U, 0xebf51eb0U, + 0x9ad943c1U, 0xc81dd593U, 0x224f6d79U, 0x3d94a966U, + 0x9859c1c3U, 0x230f2c78U, 0x7e047a25U, 0xaae54ff1U, + 0x1736214cU, 0x28c5ed73U, 0x2a456f71U, 0x54a6f20fU, + 0x40b7f71bU, 0x3b112a60U, 0x734b3828U, 0xe17f9ebaU, + 0x748efa2fU, 0x8d0885d6U, 0x50a3f30bU, 0xdbc91280U, + 0xfea45aa5U, 0x635f3c38U, 0x1e7c6245U, 0x3f142b64U, + 0x850287deU, 0x0da8a556U, 0x8047c7dbU, 0xbbb10ae0U, + 0xa12f8efaU, 0xfc24d8a7U, 0x42377519U, 0x9456c2cfU, + 0x15b6a34eU, 0x12736149U, 0x911382caU, 0x649afe3fU, + 0x30dbeb6bU, 0x4df8b516U, 0x609fff3bU, 0xd9499082U, + 0xe7fa1dbcU, 0x0ce8e457U, 0xce985695U, 0xa865cdf3U, + 0x2f002f74U, 0x2e406e75U, 0xac60ccf7U, 0xc157969aU, + 0xfd6499a6U, 0xffe41ba4U, 0x6e107e35U, 0xd809d183U, + 0x3cd4e867U, 0x5766310cU, 0xc2975599U, 0x5626700dU, + 0xa9258cf2U, 0x24caee7fU, 0x0f282754U, 0x9053c3cbU, + 0x939300c8U, 0x9f9c03c4U, 0x34deea6fU, 0xf821d9a3U, + 0xf7ee19acU, 0xa3af0cf8U, 0x59e9b002U, 0x1cfce047U, + 0xd143928aU, 0x9d1c81c6U, 0x0e686655U, 0x1f3c2344U, + 0xf3eb18a8U, 0x6b553e30U, 0x44b2f61fU, 0xe6ba5cbdU, + 0x4a3d7711U, 0xa2ef4df9U, 0x0a6d6751U, 0x4b7d3610U, + 0xbfb40be4U, 0x53633008U, 0x75cebb2eU, 0xb871c9e3U, + 0xa6ea4cfdU, 0xbaf14be1U, 0xc3d71498U, 0xde8c5285U, + 0x365e686dU, 0xb6fe48edU, 0xd3c31088U, 0x2cc0ec77U, + 0x61dfbe3aU, 0x325b6969U, 0x2b052e70U, 0x6f503f34U, + 0x4cb8f417U, 0x7dc4b926U, 0xaee04ef5U, 0x7b413a20U, + 0x03272458U, 0xeab55fb1U, 0x3a516b61U, 0xad208df6U, + 0xb07bcbebU, 0x218fae7aU, 0x11b3a24aU, 0x48bdf513U, + 0x991980c2U, 0xcc18d497U, 0x18f9e143U, 0x79c1b822U, + 0x331b2868U, 0x2d80ad76U, 0xd2835189U, 0xe43adebfU, + 0xbc74c8e7U, 0xed709db6U, 0xf96198a2U, 0x09ada452U, + 0xd546938eU, 0xb7be09ecU, 0x661a7c3dU, 0xb47ecaefU, + 0xb13b8aeaU, 0x884dc5d3U, 0x4772351cU, 0xa06fcffbU, + 0x5cacf007U, 0xe2bf5db9U, 0x5a297301U, 0x675a3d3cU, + 0x8442c6dfU, 0x7c84f827U, 0xfaa15ba1U, 0xf2ab59a9U, + 0xe57a9fbeU, 0x00e7e75bU, 0xf42edaafU, 0xbd3489e6U, + 0x4632741dU, 0xe9759cb2U, 0xb93188e2U, 0x8acd47d1U, + 0x38d1e963U, 0xaba50ef0U, 0x19b9a042U, 0xb3bb08e8U, + 0x319baa6aU, 0x96d640cdU, 0xbef44ae5U, 0x9c5cc0c7U, + 0x0662645dU, 0x7f443b24U, 0x0b2d2650U, 0x8f8807d4U, + 0x65dabf3eU, 0x5decb106U, 0xeeb05eb5U, 0x270a2d7cU, + 0x49fdb412U, 0xc552979eU, 0x08ede553U, 0x8ec846d5U, + 0x3e546a65U, 0xcd589596U, 0x9b9902c0U, 0xfbe11aa0U, + 0x878205dcU, 0x838704d8U, 0x5f6c3304U, 0x774e392cU, + 0x04e2e65fU, 0x5e2c7205U, 0x8c48c4d7U, 0x7881f923U, + 0xdc0cd087U, 0x45f2b71eU, 0xc017d79bU, 0xcfd81794U, + 0x760e782dU, 0x55e6b30eU, 0x43773418U, 0x371e296cU, + 0x4e387615U, 0x720b7929U, 0x5b693200U, 0x51e3b20aU, + 0x1a796341U, 0x359eab6eU, 0xf6ae58adU, 0x10f3e34bU, + 0xa46aceffU, 0x05a2a75eU, 0xdfcc1384U, 0xc412d69fU, + 0x86c244ddU, 0xe3ff1cb8U, 0x71cbba2aU, 0x7a017b21U, + 0xd003d38bU, 0xa52a8ffeU, 0xe03fdfbbU, 0xf02bdbabU, + 0x14f6e24fU, 0x979601ccU, 0x6c90fc37U, 0x1b392240U, + 0x02676559U, 0x6895fd33U, 0xeff01fb4U, 0xcbdd1690U, + 0xa7aa0dfcU, 0xd406d28fU, 0xf56e9baeU, 0x1676604dU, + 0x258aaf7eU, 0x8b8d06d0U, 0x2985ac72U, 0x20cfef7bU, + 0x52237109U, 0xf16b9aaaU, 0xc7d2159cU, 0x810786daU, + 0xda895381U, 0x41f7b61aU, 0x0722255cU, 0xb2fb49e9U, + 0xd7c6118cU, 0x890d84d2U, 0x4f783714U, 0xca9d5791U, + 0x6dd0bd36U, 0x1dbca146U, 0xd686508dU, 0x13332048U, + 0xe355b638U, 0xfa0bf121U, 0x1f9689c4U, 0x43dd9e98U, + 0x8b27ac50U, 0x3fbe81e4U, 0x4c125e97U, 0x66b0d6bdU, + 0xe095753bU, 0x62b5d7b9U, 0xe89f7733U, 0xb311a268U, + 0x18534bc3U, 0x57cc9b8cU, 0x08474fd3U, 0xacca6677U, + 0x145c48cfU, 0x252005feU, 0xd229fb09U, 0x617514baU, + 0x105949cbU, 0x429ddf99U, 0xa8cf6773U, 0xb714a36cU, + 0x12d9cbc9U, 0xa98f2672U, 0xf484702fU, 0x206545fbU, + 0x9db62b46U, 0xa245e779U, 0xa0c5657bU, 0xde26f805U, + 0xca37fd11U, 0xb191206aU, 0xf9cb3222U, 0x6bff94b0U, + 0xfe0ef025U, 0x07888fdcU, 0xda23f901U, 0x5149188aU, + 0x742450afU, 0xe9df3632U, 0x94fc684fU, 0xb594216eU, + 0x0f828dd4U, 0x8728af5cU, 0x0ac7cdd1U, 0x313100eaU, + 0x2baf84f0U, 0x76a4d2adU, 0xc8b77f13U, 0x1ed6c8c5U, + 0x9f36a944U, 0x98f36b43U, 0x1b9388c0U, 0xee1af435U, + 0xba5be161U, 0xc778bf1cU, 0xea1ff531U, 0x53c99a88U, + 0x6d7a17b6U, 0x8668ee5dU, 0x44185c9fU, 0x22e5c7f9U, + 0xa580257eU, 0xa4c0647fU, 0x26e0c6fdU, 0x4bd79c90U, + 0x77e493acU, 0x756411aeU, 0xe490743fU, 0x5289db89U, + 0xb654e26dU, 0xdde63b06U, 0x48175f93U, 0xdca67a07U, + 0x23a586f8U, 0xae4ae475U, 0x85a82d5eU, 0x1ad3c9c1U, + 0x19130ac2U, 0x151c09ceU, 0xbe5ee065U, 0x72a1d3a9U, + 0x7d6e13a6U, 0x292f06f2U, 0xd369ba08U, 0x967cea4dU, + 0x5bc39880U, 0x179c8bccU, 0x84e86c5fU, 0x95bc294eU, + 0x796b12a2U, 0xe1d5343aU, 0xce32fc15U, 0x6c3a56b7U, + 0xc0bd7d1bU, 0x286f47f3U, 0x80ed6d5bU, 0xc1fd3c1aU, + 0x353401eeU, 0xd9e33a02U, 0xff4eb124U, 0x32f1c3e9U, + 0x2c6a46f7U, 0x307141ebU, 0x49571e92U, 0x540c588fU, + 0xbcde6267U, 0x3c7e42e7U, 0x59431a82U, 0xa640e67dU, + 0xeb5fb430U, 0xb8db6363U, 0xa185247aU, 0xe5d0353eU, + 0xc638fe1dU, 0xf744b32cU, 0x246044ffU, 0xf1c1302aU, + 0x89a72e52U, 0x603555bbU, 0xb0d1616bU, 0x27a087fcU, + 0x3afbc1e1U, 0xab0fa470U, 0x9b33a840U, 0xc23dff19U, + 0x13998ac8U, 0x4698de9dU, 0x9279eb49U, 0xf341b228U, + 0xb99b2262U, 0xa700a77cU, 0x58035b83U, 0x6ebad4b5U, + 0x36f4c2edU, 0x67f097bcU, 0x73e192a8U, 0x832dae58U, + 0x5fc69984U, 0x3d3e03e6U, 0xec9a7637U, 0x3efec0e5U, + 0x3bbb80e0U, 0x02cdcfd9U, 0xcdf23f16U, 0x2aefc5f1U, + 0xd62cfa0dU, 0x683f57b3U, 0xd0a9790bU, 0xedda3736U, + 0x0ec2ccd5U, 0xf604f22dU, 0x702151abU, 0x782b53a3U, + 0x6ffa95b4U, 0x8a67ed51U, 0x7eaed0a5U, 0x37b483ecU, + 0xccb27e17U, 0x63f596b8U, 0x33b182e8U, 0x004d4ddbU, + 0xb251e369U, 0x212504faU, 0x9339aa48U, 0x393b02e2U, + 0xbb1ba060U, 0x1c564ac7U, 0x347440efU, 0x16dccacdU, + 0x8ce26e57U, 0xf5c4312eU, 0x81ad2c5aU, 0x05080ddeU, + 0xef5ab534U, 0xd76cbb0cU, 0x643054bfU, 0xad8a2776U, + 0xc37dbe18U, 0x4fd29d94U, 0x826def59U, 0x04484cdfU, + 0xb4d4606fU, 0x47d89f9cU, 0x111908caU, 0x716110aaU, + 0x0d020fd6U, 0x09070ed2U, 0xd5ec390eU, 0xfdce3326U, + 0x8e62ec55U, 0xd4ac780fU, 0x06c8ceddU, 0xf201f329U, + 0x568cda8dU, 0xcf72bd14U, 0x4a97dd91U, 0x45581d9eU, + 0xfc8e7227U, 0xdf66b904U, 0xc9f73e12U, 0xbd9e2366U, + 0xc4b87c1fU, 0xf88b7323U, 0xd1e9380aU, 0xdb63b800U, + 0x90f9694bU, 0xbf1ea164U, 0x7c2e52a7U, 0x9a73e941U, + 0x2eeac4f5U, 0x8f22ad54U, 0x554c198eU, 0x4e92dc95U, + 0x0c424ed7U, 0x697f16b2U, 0xfb4bb020U, 0xf081712bU, + 0x5a83d981U, 0x2faa85f4U, 0x6abfd5b1U, 0x7aabd1a1U, + 0x9e76e845U, 0x1d160bc6U, 0xe610f63dU, 0x91b9284aU, + 0x88e76f53U, 0xe215f739U, 0x657015beU, 0x415d1c9aU, + 0x2d2a07f6U, 0x5e86d885U, 0x7fee91a4U, 0x9cf66a47U, + 0xaf0aa574U, 0x010d0cdaU, 0xa305a678U, 0xaa4fe571U, + 0xd8a37b03U, 0x7beb90a0U, 0x4d521f96U, 0x0b878cd0U, + 0x5009598bU, 0xcb77bc10U, 0x8da22f56U, 0x387b43e3U, + 0x5d461b86U, 0x038d8ed8U, 0xc5f83d1eU, 0x401d5d9bU, + 0xe750b73cU, 0x973cab4cU, 0x5c065a87U, 0x99b32a42U, + 0x7984fd73U, 0x60daba6aU, 0x8547c28fU, 0xd90cd5d3U, + 0x11f6e71bU, 0xa56fcaafU, 0xd6c315dcU, 0xfc619df6U, + 0x7a443e70U, 0xf8649cf2U, 0x724e3c78U, 0x29c0e923U, + 0x82820088U, 0xcd1dd0c7U, 0x92960498U, 0x361b2d3cU, + 0x8e8d0384U, 0xbff14eb5U, 0x48f8b042U, 0xfba45ff1U, + 0x8a880280U, 0xd84c94d2U, 0x321e2c38U, 0x2dc5e827U, + 0x88088082U, 0x335e6d39U, 0x6e553b64U, 0xbab40eb0U, + 0x0767600dU, 0x3894ac32U, 0x3a142e30U, 0x44f7b34eU, + 0x50e6b65aU, 0x2b406b21U, 0x631a7969U, 0xf12edffbU, + 0x64dfbb6eU, 0x9d59c497U, 0x40f2b24aU, 0xcb9853c1U, + 0xeef51be4U, 0x730e7d79U, 0x0e2d2304U, 0x2f456a25U, + 0x9553c69fU, 0x1df9e417U, 0x9016869aU, 0xabe04ba1U, + 0xb17ecfbbU, 0xec7599e6U, 0x52663458U, 0x8407838eU, + 0x05e7e20fU, 0x02222008U, 0x8142c38bU, 0x74cbbf7eU, + 0x208aaa2aU, 0x5da9f457U, 0x70cebe7aU, 0xc918d1c3U, + 0xf7ab5cfdU, 0x1cb9a516U, 0xdec917d4U, 0xb8348cb2U, + 0x3f516e35U, 0x3e112f34U, 0xbc318db6U, 0xd106d7dbU, + 0xed35d8e7U, 0xefb55ae5U, 0x7e413f74U, 0xc85890c2U, + 0x2c85a926U, 0x4737704dU, 0xd2c614d8U, 0x4677314cU, + 0xb974cdb3U, 0x349baf3eU, 0x1f796615U, 0x8002828aU, + 0x83c24189U, 0x8fcd4285U, 0x248fab2eU, 0xe87098e2U, + 0xe7bf58edU, 0xb3fe4db9U, 0x49b8f143U, 0x0cada106U, + 0xc112d3cbU, 0x8d4dc087U, 0x1e392714U, 0x0f6d6205U, + 0xe3ba59e9U, 0x7b047f71U, 0x54e3b75eU, 0xf6eb1dfcU, + 0x5a6c3650U, 0xb2be0cb8U, 0x1a3c2610U, 0x5b2c7751U, + 0xafe54aa5U, 0x43327149U, 0x659ffa6fU, 0xa82088a2U, + 0xb6bb0dbcU, 0xaaa00aa0U, 0xd38655d9U, 0xcedd13c4U, + 0x260f292cU, 0xa6af09acU, 0xc39251c9U, 0x3c91ad36U, + 0x718eff7bU, 0x220a2828U, 0x3b546f31U, 0x7f017e75U, + 0x5ce9b556U, 0x6d95f867U, 0xbeb10fb4U, 0x6b107b61U, + 0x13766519U, 0xfae41ef0U, 0x2a002a20U, 0xbd71ccb7U, + 0xa02a8aaaU, 0x31deef3bU, 0x01e2e30bU, 0x58ecb452U, + 0x8948c183U, 0xdc4995d6U, 0x08a8a002U, 0x6990f963U, + 0x234a6929U, 0x3dd1ec37U, 0xc2d210c8U, 0xf46b9ffeU, + 0xac2589a6U, 0xfd21dcf7U, 0xe930d9e3U, 0x19fce513U, + 0xc517d2cfU, 0xa7ef48adU, 0x764b3d7cU, 0xa42f8baeU, + 0xa16acbabU, 0x981c8492U, 0x5723745dU, 0xb03e8ebaU, + 0x4cfdb146U, 0xf2ee1cf8U, 0x4a783240U, 0x770b7c7dU, + 0x9413879eU, 0x6cd5b966U, 0xeaf01ae0U, 0xe2fa18e8U, + 0xf52bdeffU, 0x10b6a61aU, 0xe47f9beeU, 0xad65c8a7U, + 0x5663355cU, 0xf924ddf3U, 0xa960c9a3U, 0x9a9c0690U, + 0x2880a822U, 0xbbf44fb1U, 0x09e8e103U, 0xa3ea49a9U, + 0x21caeb2bU, 0x8687018cU, 0xaea50ba4U, 0x8c0d8186U, + 0x1633251cU, 0x6f157a65U, 0x1b7c6711U, 0x9fd94695U, + 0x758bfe7fU, 0x4dbdf047U, 0xfee11ff4U, 0x375b6c3dU, + 0x59acf553U, 0xd503d6dfU, 0x18bca412U, 0x9e990794U, + 0x2e052b24U, 0xdd09d4d7U, 0x8bc84381U, 0xebb05be1U, + 0x97d3449dU, 0x93d64599U, 0x4f3d7245U, 0x671f786dU, + 0x14b3a71eU, 0x4e7d3344U, 0x9c198596U, 0x68d0b862U, + 0xcc5d91c6U, 0x55a3f65fU, 0xd04696daU, 0xdf8956d5U, + 0x665f396cU, 0x45b7f24fU, 0x53267559U, 0x274f682dU, + 0x5e693754U, 0x625a3868U, 0x4b387341U, 0x41b2f34bU, + 0x0a282200U, 0x25cfea2fU, 0xe6ff19ecU, 0x00a2a20aU, + 0xb43b8fbeU, 0x15f3e61fU, 0xcf9d52c5U, 0xd44397deU, + 0x9693059cU, 0xf3ae5df9U, 0x619afb6bU, 0x6a503a60U, + 0xc05292caU, 0xb57bcebfU, 0xf06e9efaU, 0xe07a9aeaU, + 0x04a7a30eU, 0x87c7408dU, 0x7cc1bd76U, 0x0b686301U, + 0x12362418U, 0x78c4bc72U, 0xffa15ef5U, 0xdb8c57d1U, + 0xb7fb4cbdU, 0xc45793ceU, 0xe53fdaefU, 0x0627210cU, + 0x35dbee3fU, 0x9bdc4791U, 0x39d4ed33U, 0x309eae3aU, + 0x42723048U, 0xe13adbebU, 0xd78354ddU, 0x9156c79bU, + 0xcad812c0U, 0x51a6f75bU, 0x1773641dU, 0xa2aa08a8U, + 0xc79750cdU, 0x995cc593U, 0x5f297655U, 0xdacc16d0U, + 0x7d81fc77U, 0x0dede007U, 0xc6d711ccU, 0x03626109U, + 0x9e4cd25cU, 0x87129545U, 0x628feda0U, 0x3ec4fafcU, + 0xf63ec834U, 0x42a7e580U, 0x310b3af3U, 0x1ba9b2d9U, + 0x9d8c115fU, 0x1facb3ddU, 0x95861357U, 0xce08c60cU, + 0x654a2fa7U, 0x2ad5ffe8U, 0x755e2bb7U, 0xd1d30213U, + 0x69452cabU, 0x5839619aU, 0xaf309f6dU, 0x1c6c70deU, + 0x6d402dafU, 0x3f84bbfdU, 0xd5d60317U, 0xca0dc708U, + 0x6fc0afadU, 0xd4964216U, 0x899d144bU, 0x5d7c219fU, + 0xe0af4f22U, 0xdf5c831dU, 0xdddc011fU, 0xa33f9c61U, + 0xb72e9975U, 0xcc88440eU, 0x84d25646U, 0x16e6f0d4U, + 0x83179441U, 0x7a91ebb8U, 0xa73a9d65U, 0x2c507ceeU, + 0x093d34cbU, 0x94c65256U, 0xe9e50c2bU, 0xc88d450aU, + 0x729be9b0U, 0xfa31cb38U, 0x77dea9b5U, 0x4c28648eU, + 0x56b6e094U, 0x0bbdb6c9U, 0xb5ae1b77U, 0x63cfaca1U, + 0xe22fcd20U, 0xe5ea0f27U, 0x668aeca4U, 0x93039051U, + 0xc7428505U, 0xba61db78U, 0x97069155U, 0x2ed0feecU, + 0x106373d2U, 0xfb718a39U, 0x390138fbU, 0x5ffca39dU, + 0xd899411aU, 0xd9d9001bU, 0x5bf9a299U, 0x36cef8f4U, + 0x0afdf7c8U, 0x087d75caU, 0x9989105bU, 0x2f90bfedU, + 0xcb4d8609U, 0xa0ff5f62U, 0x350e3bf7U, 0xa1bf1e63U, + 0x5ebce29cU, 0xd3538011U, 0xf8b1493aU, 0x67caada5U, + 0x640a6ea6U, 0x68056daaU, 0xc3478401U, 0x0fb8b7cdU, + 0x007777c2U, 0x54366296U, 0xae70de6cU, 0xeb658e29U, + 0x26dafce4U, 0x6a85efa8U, 0xf9f1083bU, 0xe8a54d2aU, + 0x047276c6U, 0x9ccc505eU, 0xb32b9871U, 0x112332d3U, + 0xbda4197fU, 0x55762397U, 0xfdf4093fU, 0xbce4587eU, + 0x482d658aU, 0xa4fa5e66U, 0x8257d540U, 0x4fe8a78dU, + 0x51732293U, 0x4d68258fU, 0x344e7af6U, 0x29153cebU, + 0xc1c70603U, 0x41672683U, 0x245a7ee6U, 0xdb598219U, + 0x9646d054U, 0xc5c20707U, 0xdc9c401eU, 0x98c9515aU, + 0xbb219a79U, 0x8a5dd748U, 0x5979209bU, 0x8cd8544eU, + 0xf4be4a36U, 0x1d2c31dfU, 0xcdc8050fU, 0x5ab9e398U, + 0x47e2a585U, 0xd616c014U, 0xe62acc24U, 0xbf249b7dU, + 0x6e80eeacU, 0x3b81baf9U, 0xef608f2dU, 0x8e58d64cU, + 0xc4824606U, 0xda19c318U, 0x251a3fe7U, 0x13a3b0d1U, + 0x4beda689U, 0x1ae9f3d8U, 0x0ef8f6ccU, 0xfe34ca3cU, + 0x22dffde0U, 0x40276782U, 0x91831253U, 0x43e7a481U, + 0x46a2e484U, 0x7fd4abbdU, 0xb0eb5b72U, 0x57f6a195U, + 0xab359e69U, 0x152633d7U, 0xadb01d6fU, 0x90c35352U, + 0x73dba8b1U, 0x8b1d9649U, 0x0d3835cfU, 0x053237c7U, + 0x12e3f1d0U, 0xf77e8935U, 0x03b7b4c1U, 0x4aade788U, + 0xb1ab1a73U, 0x1eecf2dcU, 0x4ea8e68cU, 0x7d5429bfU, + 0xcf48870dU, 0x5c3c609eU, 0xee20ce2cU, 0x44226686U, + 0xc602c404U, 0x614f2ea3U, 0x496d248bU, 0x6bc5aea9U, + 0xf1fb0a33U, 0x88dd554aU, 0xfcb4483eU, 0x781169baU, + 0x9243d150U, 0xaa75df68U, 0x192930dbU, 0xd0934312U, + 0xbe64da7cU, 0x32cbf9f0U, 0xff748b3dU, 0x795128bbU, + 0xc9cd040bU, 0x3ac1fbf8U, 0x6c006caeU, 0x0c7874ceU, + 0x701b6bb2U, 0x741e6ab6U, 0xa8f55d6aU, 0x80d75742U, + 0xf37b8831U, 0xa9b51c6bU, 0x7bd1aab9U, 0x8f18974dU, + 0x2b95bee9U, 0xb26bd970U, 0x378eb9f5U, 0x384179faU, + 0x81971643U, 0xa27fdd60U, 0xb4ee5a76U, 0xc0874702U, + 0xb9a1187bU, 0x85921747U, 0xacf05c6eU, 0xa67adc64U, + 0xede00d2fU, 0xc207c500U, 0x013736c3U, 0xe76a8d25U, + 0x53f3a091U, 0xf23bc930U, 0x28557deaU, 0x338bb8f1U, + 0x715b2ab3U, 0x146672d6U, 0x8652d444U, 0x8d98154fU, + 0x279abde5U, 0x52b3e190U, 0x17a6b1d5U, 0x07b2b5c5U, + 0xe36f8c21U, 0x600f6fa2U, 0x9b099259U, 0xeca04c2eU, + 0xf5fe0b37U, 0x9f0c935dU, 0x186971daU, 0x3c4478feU, + 0x50336392U, 0x239fbce1U, 0x02f7f5c0U, 0xe1ef0e23U, + 0xd213c110U, 0x7c1468beU, 0xde1cc21cU, 0xd7568115U, + 0xa5ba1f67U, 0x06f2f4c4U, 0x304b7bf2U, 0x769ee8b4U, + 0x2d103defU, 0xb66ed874U, 0xf0bb4b32U, 0x45622787U, + 0x205f7fe2U, 0x7e94eabcU, 0xb8e1597aU, 0x3d0439ffU, + 0x9a49d358U, 0xea25cf28U, 0x211f3ee3U, 0xe4aa4e26U, + 0xaebf119fU, 0xb7e15686U, 0x527c2e63U, 0x0e37393fU, + 0xc6cd0bf7U, 0x72542643U, 0x01f8f930U, 0x2b5a711aU, + 0xad7fd29cU, 0x2f5f701eU, 0xa575d094U, 0xfefb05cfU, + 0x55b9ec64U, 0x1a263c2bU, 0x45ade874U, 0xe120c1d0U, + 0x59b6ef68U, 0x68caa259U, 0x9fc35caeU, 0x2c9fb31dU, + 0x5db3ee6cU, 0x0f77783eU, 0xe525c0d4U, 0xfafe04cbU, + 0x5f336c6eU, 0xe46581d5U, 0xb96ed788U, 0x6d8fe25cU, + 0xd05c8ce1U, 0xefaf40deU, 0xed2fc2dcU, 0x93cc5fa2U, + 0x87dd5ab6U, 0xfc7b87cdU, 0xb4219585U, 0x26153317U, + 0xb3e45782U, 0x4a62287bU, 0x97c95ea6U, 0x1ca3bf2dU, + 0x39cef708U, 0xa4359195U, 0xd916cfe8U, 0xf87e86c9U, + 0x42682a73U, 0xcac208fbU, 0x472d6a76U, 0x7cdba74dU, + 0x66452357U, 0x3b4e750aU, 0x855dd8b4U, 0x533c6f62U, + 0xd2dc0ee3U, 0xd519cce4U, 0x56792f67U, 0xa3f05392U, + 0xf7b146c6U, 0x8a9218bbU, 0xa7f55296U, 0x1e233d2fU, + 0x2090b011U, 0xcb8249faU, 0x09f2fb38U, 0x6f0f605eU, + 0xe86a82d9U, 0xe92ac3d8U, 0x6b0a615aU, 0x063d3b37U, + 0x3a0e340bU, 0x388eb609U, 0xa97ad398U, 0x1f637c2eU, + 0xfbbe45caU, 0x900c9ca1U, 0x05fdf834U, 0x914cdda0U, + 0x6e4f215fU, 0xe3a043d2U, 0xc8428af9U, 0x57396e66U, + 0x54f9ad65U, 0x58f6ae69U, 0xf3b447c2U, 0x3f4b740eU, + 0x3084b401U, 0x64c5a155U, 0x9e831dafU, 0xdb964deaU, + 0x16293f27U, 0x5a762c6bU, 0xc902cbf8U, 0xd8568ee9U, + 0x3481b505U, 0xac3f939dU, 0x83d85bb2U, 0x21d0f110U, + 0x8d57dabcU, 0x6585e054U, 0xcd07cafcU, 0x8c179bbdU, + 0x78dea649U, 0x94099da5U, 0xb2a41683U, 0x7f1b644eU, + 0x6180e150U, 0x7d9be64cU, 0x04bdb935U, 0x19e6ff28U, + 0xf134c5c0U, 0x7194e540U, 0x14a9bd25U, 0xebaa41daU, + 0xa6b51397U, 0xf531c4c4U, 0xec6f83ddU, 0xa83a9299U, + 0x8bd259baU, 0xbaae148bU, 0x698ae358U, 0xbc2b978dU, + 0xc44d89f5U, 0x2ddff21cU, 0xfd3bc6ccU, 0x6a4a205bU, + 0x77116646U, 0xe6e503d7U, 0xd6d90fe7U, 0x8fd758beU, + 0x5e732d6fU, 0x0b72793aU, 0xdf934ceeU, 0xbeab158fU, + 0xf47185c5U, 0xeaea00dbU, 0x15e9fc24U, 0x23507312U, + 0x7b1e654aU, 0x2a1a301bU, 0x3e0b350fU, 0xcec709ffU, + 0x122c3e23U, 0x70d4a441U, 0xa170d190U, 0x73146742U, + 0x76512747U, 0x4f27687eU, 0x801898b1U, 0x67056256U, + 0x9bc65daaU, 0x25d5f014U, 0x9d43deacU, 0xa0309091U, + 0x43286b72U, 0xbbee558aU, 0x3dcbf60cU, 0x35c1f404U, + 0x22103213U, 0xc78d4af6U, 0x33447702U, 0x7a5e244bU, + 0x8158d9b0U, 0x2e1f311fU, 0x7e5b254fU, 0x4da7ea7cU, + 0xffbb44ceU, 0x6ccfa35dU, 0xded30defU, 0x74d1a545U, + 0xf6f107c7U, 0x51bced60U, 0x799ee748U, 0x5b366d6aU, + 0xc108c9f0U, 0xb82e9689U, 0xcc478bfdU, 0x48e2aa79U, + 0xa2b01293U, 0x9a861cabU, 0x29daf318U, 0xe06080d1U, + 0x8e9719bfU, 0x02383a33U, 0xcf8748feU, 0x49a2eb78U, + 0xf93ec7c8U, 0x0a32383bU, 0x5cf3af6dU, 0x3c8bb70dU, + 0x40e8a871U, 0x44eda975U, 0x98069ea9U, 0xb0249481U, + 0xc3884bf2U, 0x9946dfa8U, 0x4b22697aU, 0xbfeb548eU, + 0x1b667d2aU, 0x82981ab3U, 0x077d7a36U, 0x08b2ba39U, + 0xb164d580U, 0x928c1ea3U, 0x841d99b5U, 0xf07484c1U, + 0x8952dbb8U, 0xb561d484U, 0x9c039fadU, 0x96891fa7U, + 0xdd13ceecU, 0xf2f406c3U, 0x31c4f500U, 0xd7994ee6U, + 0x63006352U, 0xc2c80af3U, 0x18a6be29U, 0x03787b32U, + 0x41a8e970U, 0x2495b115U, 0xb6a11787U, 0xbd6bd68cU, + 0x17697e26U, 0x62402253U, 0x27557216U, 0x37417606U, + 0xd39c4fe2U, 0x50fcac61U, 0xabfa519aU, 0xdc538fedU, + 0xc50dc8f4U, 0xafff509eU, 0x289ab219U, 0x0cb7bb3dU, + 0x60c0a051U, 0x136c7f22U, 0x32043603U, 0xd11ccde0U, + 0xe2e002d3U, 0x4ce7ab7dU, 0xeeef01dfU, 0xe7a542d6U, + 0x9549dca4U, 0x36013707U, 0x00b8b831U, 0x466d2b77U, + 0x1de3fe2cU, 0x869d1bb7U, 0xc04888f1U, 0x7591e444U, + 0x10acbc21U, 0x4e67297fU, 0x88129ab9U, 0x0df7fa3cU, + 0xaaba109bU, 0xdad60cebU, 0x11ecfd20U, 0xd4598de5U, + 0xf304f779U, 0xea5ab060U, 0x0fc7c885U, 0x538cdfd9U, + 0x9b76ed11U, 0x2fefc0a5U, 0x5c431fd6U, 0x76e197fcU, + 0xf0c4347aU, 0x72e496f8U, 0xf8ce3672U, 0xa340e329U, + 0x08020a82U, 0x479ddacdU, 0x18160e92U, 0xbc9b2736U, + 0x040d098eU, 0x357144bfU, 0xc278ba48U, 0x712455fbU, + 0x0008088aU, 0x52cc9ed8U, 0xb89e2632U, 0xa745e22dU, + 0x02888a88U, 0xb9de6733U, 0xe4d5316eU, 0x303404baU, + 0x8de76a07U, 0xb214a638U, 0xb094243aU, 0xce77b944U, + 0xda66bc50U, 0xa1c0612bU, 0xe99a7363U, 0x7baed5f1U, + 0xee5fb164U, 0x17d9ce9dU, 0xca72b840U, 0x411859cbU, + 0x647511eeU, 0xf98e7773U, 0x84ad290eU, 0xa5c5602fU, + 0x1fd3cc95U, 0x9779ee1dU, 0x1a968c90U, 0x216041abU, + 0x3bfec5b1U, 0x66f593ecU, 0xd8e63e52U, 0x0e878984U, + 0x8f67e805U, 0x88a22a02U, 0x0bc2c981U, 0xfe4bb574U, + 0xaa0aa020U, 0xd729fe5dU, 0xfa4eb470U, 0x4398dbc9U, + 0x7d2b56f7U, 0x9639af1cU, 0x54491ddeU, 0x32b486b8U, + 0xb5d1643fU, 0xb491253eU, 0x36b187bcU, 0x5b86ddd1U, + 0x67b5d2edU, 0x653550efU, 0xf4c1357eU, 0x42d89ac8U, + 0xa605a32cU, 0xcdb77a47U, 0x58461ed2U, 0xccf73b46U, + 0x33f4c7b9U, 0xbe1ba534U, 0x95f96c1fU, 0x0a828880U, + 0x09424b83U, 0x054d488fU, 0xae0fa124U, 0x62f092e8U, + 0x6d3f52e7U, 0x397e47b3U, 0xc338fb49U, 0x862dab0cU, + 0x4b92d9c1U, 0x07cdca8dU, 0x94b92d1eU, 0x85ed680fU, + 0x693a53e3U, 0xf184757bU, 0xde63bd54U, 0x7c6b17f6U, + 0xd0ec3c5aU, 0x383e06b2U, 0x90bc2c1aU, 0xd1ac7d5bU, + 0x256540afU, 0xc9b27b43U, 0xef1ff065U, 0x22a082a8U, + 0x3c3b07b6U, 0x202000aaU, 0x59065fd3U, 0x445d19ceU, + 0xac8f2326U, 0x2c2f03a6U, 0x49125bc3U, 0xb611a73cU, + 0xfb0ef571U, 0xa88a2222U, 0xb1d4653bU, 0xf581747fU, + 0xd669bf5cU, 0xe715f26dU, 0x343105beU, 0xe190716bU, + 0x99f66f13U, 0x706414faU, 0xa080202aU, 0x37f1c6bdU, + 0x2aaa80a0U, 0xbb5ee531U, 0x8b62e901U, 0xd26cbe58U, + 0x03c8cb89U, 0x56c99fdcU, 0x8228aa08U, 0xe310f369U, + 0xa9ca6323U, 0xb751e63dU, 0x48521ac2U, 0x7eeb95f4U, + 0x26a583acU, 0x77a1d6fdU, 0x63b0d3e9U, 0x937cef19U, + 0x4f97d8c5U, 0x2d6f42a7U, 0xfccb3776U, 0x2eaf81a4U, + 0x2beac1a1U, 0x129c8e98U, 0xdda37e57U, 0x3abe84b0U, + 0xc67dbb4cU, 0x786e16f2U, 0xc0f8384aU, 0xfd8b7677U, + 0x1e938d94U, 0xe655b36cU, 0x607010eaU, 0x687a12e2U, + 0x7fabd4f5U, 0x9a36ac10U, 0x6eff91e4U, 0x27e5c2adU, + 0xdce33f56U, 0x73a4d7f9U, 0x23e0c3a9U, 0x101c0c9aU, + 0xa200a228U, 0x317445bbU, 0x8368eb09U, 0x296a43a3U, + 0xab4ae121U, 0x0c070b86U, 0x242501aeU, 0x068d8b8cU, + 0x9cb32f16U, 0xe595706fU, 0x91fc6d1bU, 0x15594c9fU, + 0xff0bf475U, 0xc73dfa4dU, 0x746115feU, 0xbddb6637U, + 0xd32cff59U, 0x5f83dcd5U, 0x923cae18U, 0x14190d9eU, + 0xa485212eU, 0x5789deddU, 0x0148498bU, 0x613051ebU, + 0x1d534e97U, 0x19564f93U, 0xc5bd784fU, 0xed9f7267U, + 0x9e33ad14U, 0xc4fd394eU, 0x16998f9cU, 0xe250b268U, + 0x46dd9bccU, 0xdf23fc55U, 0x5ac69cd0U, 0x55095cdfU, + 0xecdf3366U, 0xcf37f845U, 0xd9a67f53U, 0xadcf6227U, + 0xd4e93d5eU, 0xe8da3262U, 0xc1b8794bU, 0xcb32f941U, + 0x80a8280aU, 0xaf4fe025U, 0x6c7f13e6U, 0x8a22a800U, + 0x3ebb85b4U, 0x9f73ec15U, 0x451d58cfU, 0x5ec39dd4U, + 0x1c130f96U, 0x792e57f3U, 0xeb1af161U, 0xe0d0306aU, + 0x4ad298c0U, 0x3ffbc4b5U, 0x7aee94f0U, 0x6afa90e0U, + 0x8e27a904U, 0x0d474a87U, 0xf641b77cU, 0x81e8690bU, + 0x98b62e12U, 0xf244b678U, 0x752154ffU, 0x510c5ddbU, + 0x3d7b46b7U, 0x4ed799c4U, 0x6fbfd0e5U, 0x8ca72b06U, + 0xbf5be435U, 0x115c4d9bU, 0xb354e739U, 0xba1ea430U, + 0xc8f23a42U, 0x6bbad1e1U, 0x5d035ed7U, 0x1bd6cd91U, + 0x405818caU, 0xdb26fd51U, 0x9df36e17U, 0x282a02a2U, + 0x4d175ac7U, 0x13dccf99U, 0xd5a97c5fU, 0x504c1cdaU, + 0xf701f67dU, 0x876dea0dU, 0x4c571bc6U, 0x89e26b03U, + 0x6a2943cdU, 0x737704d4U, 0x96ea7c31U, 0xcaa16b6dU, + 0x025b59a5U, 0xb6c27411U, 0xc56eab62U, 0xefcc2348U, + 0x69e980ceU, 0xebc9224cU, 0x61e382c6U, 0x3a6d579dU, + 0x912fbe36U, 0xdeb06e79U, 0x813bba26U, 0x25b69382U, + 0x9d20bd3aU, 0xac5cf00bU, 0x5b550efcU, 0xe809e14fU, + 0x9925bc3eU, 0xcbe12a6cU, 0x21b39286U, 0x3e685699U, + 0x9ba53e3cU, 0x20f3d387U, 0x7df885daU, 0xa919b00eU, + 0x14cadeb3U, 0x2b39128cU, 0x29b9908eU, 0x575a0df0U, + 0x434b08e4U, 0x38edd59fU, 0x70b7c7d7U, 0xe2836145U, + 0x777205d0U, 0x8ef47a29U, 0x535f0cf4U, 0xd835ed7fU, + 0xfd58a55aU, 0x60a3c3c7U, 0x1d809dbaU, 0x3ce8d49bU, + 0x86fe7821U, 0x0e545aa9U, 0x83bb3824U, 0xb84df51fU, + 0xa2d37105U, 0xffd82758U, 0x41cb8ae6U, 0x97aa3d30U, + 0x164a5cb1U, 0x118f9eb6U, 0x92ef7d35U, 0x676601c0U, + 0x33271494U, 0x4e044ae9U, 0x636300c4U, 0xdab56f7dU, + 0xe406e243U, 0x0f141ba8U, 0xcd64a96aU, 0xab99320cU, + 0x2cfcd08bU, 0x2dbc918aU, 0xaf9c3308U, 0xc2ab6965U, + 0xfe986659U, 0xfc18e45bU, 0x6dec81caU, 0xdbf52e7cU, + 0x3f281798U, 0x549acef3U, 0xc16baa66U, 0x55da8ff2U, + 0xaad9730dU, 0x27361180U, 0x0cd4d8abU, 0x93af3c34U, + 0x906fff37U, 0x9c60fc3bU, 0x37221590U, 0xfbdd265cU, + 0xf412e653U, 0xa053f307U, 0x5a154ffdU, 0x1f001fb8U, + 0xd2bf6d75U, 0x9ee07e39U, 0x0d9499aaU, 0x1cc0dcbbU, + 0xf017e757U, 0x68a9c1cfU, 0x474e09e0U, 0xe546a342U, + 0x49c188eeU, 0xa113b206U, 0x099198aeU, 0x4881c9efU, + 0xbc48f41bU, 0x509fcff7U, 0x763244d1U, 0xbb8d361cU, + 0xa516b302U, 0xb90db41eU, 0xc02beb67U, 0xdd70ad7aU, + 0x35a29792U, 0xb502b712U, 0xd03fef77U, 0x2f3c1388U, + 0x622341c5U, 0x31a79696U, 0x28f9d18fU, 0x6cacc0cbU, + 0x4f440be8U, 0x7e3846d9U, 0xad1cb10aU, 0x78bdc5dfU, + 0x00dbdba7U, 0xe949a04eU, 0x39ad949eU, 0xaedc7209U, + 0xb3873414U, 0x22735185U, 0x124f5db5U, 0x4b410aecU, + 0x9ae57f3dU, 0xcfe42b68U, 0x1b051ebcU, 0x7a3d47ddU, + 0x30e7d797U, 0x2e7c5289U, 0xd17fae76U, 0xe7c62140U, + 0xbf883718U, 0xee8c6249U, 0xfa9d675dU, 0x0a515badU, + 0xd6ba6c71U, 0xb442f613U, 0x65e683c2U, 0xb7823510U, + 0xb2c77515U, 0x8bb13a2cU, 0x448ecae3U, 0xa3933004U, + 0x5f500ff8U, 0xe143a246U, 0x59d58cfeU, 0x64a6c2c3U, + 0x87be3920U, 0x7f7807d8U, 0xf95da45eU, 0xf157a656U, + 0xe6866041U, 0x031b18a4U, 0xf7d22550U, 0xbec87619U, + 0x45ce8be2U, 0xea89634dU, 0xbacd771dU, 0x8931b82eU, + 0x3b2d169cU, 0xa859f10fU, 0x1a455fbdU, 0xb047f717U, + 0x32675595U, 0x952abf32U, 0xbd08b51aU, 0x9fa03f38U, + 0x059e9ba2U, 0x7cb8c4dbU, 0x08d1d9afU, 0x8c74f82bU, + 0x662640c1U, 0x5e104ef9U, 0xed4ca14aU, 0x24f6d283U, + 0x4a014bedU, 0xc6ae6861U, 0x0b111aacU, 0x8d34b92aU, + 0x3da8959aU, 0xcea46a69U, 0x9865fd3fU, 0xf81de55fU, + 0x847efa23U, 0x807bfb27U, 0x5c90ccfbU, 0x74b2c6d3U, + 0x071e19a0U, 0x5dd08dfaU, 0x8fb43b28U, 0x7b7d06dcU, + 0xdff02f78U, 0x460e48e1U, 0xc3eb2864U, 0xcc24e86bU, + 0x75f287d2U, 0x561a4cf1U, 0x408bcbe7U, 0x34e2d693U, + 0x4dc489eaU, 0x71f786d6U, 0x5895cdffU, 0x521f4df5U, + 0x19859cbeU, 0x36625491U, 0xf552a752U, 0x130f1cb4U, + 0xa7963100U, 0x065e58a1U, 0xdc30ec7bU, 0xc7ee2960U, + 0x853ebb22U, 0xe003e347U, 0x723745d5U, 0x79fd84deU, + 0xd3ff2c74U, 0xa6d67001U, 0xe3c32044U, 0xf3d72454U, + 0x170a1db0U, 0x946afe33U, 0x6f6c03c8U, 0x18c5ddbfU, + 0x019b9aa6U, 0x6b6902ccU, 0xec0ce04bU, 0xc821e96fU, + 0xa456f203U, 0xd7fa2d70U, 0xf6926451U, 0x158a9fb2U, + 0x26765081U, 0x8871f92fU, 0x2a79538dU, 0x23331084U, + 0x51df8ef6U, 0xf2976555U, 0xc42eea63U, 0x82fb7925U, + 0xd975ac7eU, 0x420b49e5U, 0x04dedaa3U, 0xb107b616U, + 0xd43aee73U, 0x8af17b2dU, 0x4c84c8ebU, 0xc961a86eU, + 0x6e2c42c9U, 0x1e405eb9U, 0xd57aaf72U, 0x10cfdfb7U, + 0xa240e26cU, 0xbb1ea575U, 0x5e83dd90U, 0x02c8caccU, + 0xca32f804U, 0x7eabd5b0U, 0x0d070ac3U, 0x27a582e9U, + 0xa180216fU, 0x23a083edU, 0xa98a2367U, 0xf204f63cU, + 0x59461f97U, 0x16d9cfd8U, 0x49521b87U, 0xeddf3223U, + 0x55491c9bU, 0x643551aaU, 0x933caf5dU, 0x206040eeU, + 0x514c1d9fU, 0x03888bcdU, 0xe9da3327U, 0xf601f738U, + 0x53cc9f9dU, 0xe89a7226U, 0xb591247bU, 0x617011afU, + 0xdca37f12U, 0xe350b32dU, 0xe1d0312fU, 0x9f33ac51U, + 0x8b22a945U, 0xf084743eU, 0xb8de6676U, 0x2aeac0e4U, + 0xbf1ba471U, 0x469ddb88U, 0x9b36ad55U, 0x105c4cdeU, + 0x353104fbU, 0xa8ca6266U, 0xd5e93c1bU, 0xf481753aU, + 0x4e97d980U, 0xc63dfb08U, 0x4bd29985U, 0x702454beU, + 0x6abad0a4U, 0x37b186f9U, 0x89a22b47U, 0x5fc39c91U, + 0xde23fd10U, 0xd9e63f17U, 0x5a86dc94U, 0xaf0fa061U, + 0xfb4eb535U, 0x866deb48U, 0xab0aa165U, 0x12dccedcU, + 0x2c6f43e2U, 0xc77dba09U, 0x050d08cbU, 0x63f093adU, + 0xe495712aU, 0xe5d5302bU, 0x67f592a9U, 0x0ac2c8c4U, + 0x36f1c7f8U, 0x347145faU, 0xa585206bU, 0x139c8fddU, + 0xf741b639U, 0x9cf36f52U, 0x09020bc7U, 0x9db32e53U, + 0x62b0d2acU, 0xef5fb021U, 0xc4bd790aU, 0x5bc69d95U, + 0x58065e96U, 0x54095d9aU, 0xff4bb431U, 0x33b487fdU, + 0x3c7b47f2U, 0x683a52a6U, 0x927cee5cU, 0xd769be19U, + 0x1ad6ccd4U, 0x5689df98U, 0xc5fd380bU, 0xd4a97d1aU, + 0x387e46f6U, 0xa0c0606eU, 0x8f27a841U, 0x2d2f02e3U, + 0x81a8294fU, 0x697a13a7U, 0xc1f8390fU, 0x80e8684eU, + 0x742155baU, 0x98f66e56U, 0xbe5be570U, 0x73e497bdU, + 0x6d7f12a3U, 0x716415bfU, 0x08424ac6U, 0x15190cdbU, + 0xfdcb3633U, 0x7d6b16b3U, 0x18564ed6U, 0xe755b229U, + 0xaa4ae064U, 0xf9ce3737U, 0xe090702eU, 0xa4c5616aU, + 0x872daa49U, 0xb651e778U, 0x657510abU, 0xb0d4647eU, + 0xc8b27a06U, 0x212001efU, 0xf1c4353fU, 0x66b5d3a8U, + 0x7bee95b5U, 0xea1af024U, 0xda26fc14U, 0x8328ab4dU, + 0x528cde9cU, 0x078d8ac9U, 0xd36cbf1dU, 0xb254e67cU, + 0xf88e7636U, 0xe615f328U, 0x19160fd7U, 0x2faf80e1U, + 0x77e196b9U, 0x26e5c3e8U, 0x32f4c6fcU, 0xc238fa0cU, + 0x1ed3cdd0U, 0x7c2b57b2U, 0xad8f2263U, 0x7feb94b1U, + 0x7aaed4b4U, 0x43d89b8dU, 0x8ce76b42U, 0x6bfa91a5U, + 0x9739ae59U, 0x292a03e7U, 0x91bc2d5fU, 0xaccf6362U, + 0x4fd79881U, 0xb711a679U, 0x313405ffU, 0x393e07f7U, + 0x2eefc1e0U, 0xcb72b905U, 0x3fbb84f1U, 0x76a1d7b8U, + 0x8da72a43U, 0x22e0c2ecU, 0x72a4d6bcU, 0x4158198fU, + 0xf344b73dU, 0x603050aeU, 0xd22cfe1cU, 0x782e56b6U, + 0xfa0ef434U, 0x5d431e93U, 0x756114bbU, 0x57c99e99U, + 0xcdf73a03U, 0xb4d1657aU, 0xc0b8780eU, 0x441d598aU, + 0xae4fe160U, 0x9679ef58U, 0x252500ebU, 0xec9f7322U, + 0x8268ea4cU, 0x0ec7c9c0U, 0xc378bb0dU, 0x455d188bU, + 0xf5c1343bU, 0x06cdcbc8U, 0x500c5c9eU, 0x307444feU, + 0x4c175b82U, 0x48125a86U, 0x94f96d5aU, 0xbcdb6772U, + 0xcf77b801U, 0x95b92c5bU, 0x47dd9a89U, 0xb314a77dU, + 0x17998ed9U, 0x8e67e940U, 0x0b8289c5U, 0x044d49caU, + 0xbd9b2673U, 0x9e73ed50U, 0x88e26a46U, 0xfc8b7732U, + 0x85ad284bU, 0xb99e2777U, 0x90fc6c5eU, 0x9a76ec54U, + 0xd1ec3d1fU, 0xfe0bf530U, 0x3d3b06f3U, 0xdb66bd15U, + 0x6fff90a1U, 0xce37f900U, 0x14594ddaU, 0x0f8788c1U, + 0x4d571a83U, 0x286a42e6U, 0xba5ee474U, 0xb194257fU, + 0x1b968dd5U, 0x6ebfd1a0U, 0x2baa81e5U, 0x3bbe85f5U, + 0xdf63bc11U, 0x5c035f92U, 0xa705a269U, 0xd0ac7c1eU, + 0xc9f23b07U, 0xa300a36dU, 0x246541eaU, 0x004848ceU, + 0x6c3f53a2U, 0x1f938cd1U, 0x3efbc5f0U, 0xdde33e13U, + 0xee1ff120U, 0x4018588eU, 0xe210f22cU, 0xeb5ab125U, + 0x99b62f57U, 0x3afec4f4U, 0x0c474bc2U, 0x4a92d884U, + 0x111c0ddfU, 0x8a62e844U, 0xccb77b02U, 0x796e17b7U, + 0x1c534fd2U, 0x4298da8cU, 0x84ed694aU, 0x010809cfU, + 0xa645e368U, 0xd629ff18U, 0x1d130ed3U, 0xd8a67e16U, + 0xccf438b6U, 0xd5aa7fafU, 0x3037074aU, 0x6c7c1016U, + 0xa48622deU, 0x101f0f6aU, 0x63b3d019U, 0x49115833U, + 0xcf34fbb5U, 0x4d145937U, 0xc73ef9bdU, 0x9cb02ce6U, + 0x37f2c54dU, 0x786d1502U, 0x27e6c15dU, 0x836be8f9U, + 0x3bfdc641U, 0x0a818b70U, 0xfd887587U, 0x4ed49a34U, + 0x3ff8c745U, 0x6d3c5117U, 0x876ee9fdU, 0x98b52de2U, + 0x3d784547U, 0x862ea8fcU, 0xdb25fea1U, 0x0fc4cb75U, + 0xb217a5c8U, 0x8de469f7U, 0x8f64ebf5U, 0xf187768bU, + 0xe596739fU, 0x9e30aee4U, 0xd66abcacU, 0x445e1a3eU, + 0xd1af7eabU, 0x28290152U, 0xf582778fU, 0x7ee89604U, + 0x5b85de21U, 0xc67eb8bcU, 0xbb5de6c1U, 0x9a35afe0U, + 0x2023035aU, 0xa88921d2U, 0x2566435fU, 0x1e908e64U, + 0x040e0a7eU, 0x59055c23U, 0xe716f19dU, 0x3177464bU, + 0xb09727caU, 0xb752e5cdU, 0x3432064eU, 0xc1bb7abbU, + 0x95fa6fefU, 0xe8d93192U, 0xc5be7bbfU, 0x7c681406U, + 0x42db9938U, 0xa9c960d3U, 0x6bb9d211U, 0x0d444977U, + 0x8a21abf0U, 0x8b61eaf1U, 0x09414873U, 0x6476121eU, + 0x58451d22U, 0x5ac59f20U, 0xcb31fab1U, 0x7d285507U, + 0x99f56ce3U, 0xf247b588U, 0x67b6d11dU, 0xf307f489U, + 0x0c040876U, 0x81eb6afbU, 0xaa09a3d0U, 0x3572474fU, + 0x36b2844cU, 0x3abd8740U, 0x91ff6eebU, 0x5d005d27U, + 0x52cf9d28U, 0x068e887cU, 0xfcc83486U, 0xb9dd64c3U, + 0x7462160eU, 0x383d0542U, 0xab49e2d1U, 0xba1da7c0U, + 0x56ca9c2cU, 0xce74bab4U, 0xe193729bU, 0x439bd839U, + 0xef1cf395U, 0x07cec97dU, 0xaf4ce3d5U, 0xee5cb294U, + 0x1a958f60U, 0xf642b48cU, 0xd0ef3faaU, 0x1d504d67U, + 0x03cbc879U, 0x1fd0cf65U, 0x66f6901cU, 0x7badd601U, + 0x937fece9U, 0x13dfcc69U, 0x76e2940cU, 0x89e168f3U, + 0xc4fe3abeU, 0x977aededU, 0x8e24aaf4U, 0xca71bbb0U, + 0xe9997093U, 0xd8e53da2U, 0x0bc1ca71U, 0xde60bea4U, + 0xa606a0dcU, 0x4f94db35U, 0x9f70efe5U, 0x08010972U, + 0x155a4f6fU, 0x84ae2afeU, 0xb49226ceU, 0xed9c7197U, + 0x3c380446U, 0x69395013U, 0xbdd865c7U, 0xdce03ca6U, + 0x963aacecU, 0x88a129f2U, 0x77a2d50dU, 0x411b5a3bU, + 0x19554c63U, 0x48511932U, 0x5c401c26U, 0xac8c20d6U, + 0x7067170aU, 0x129f8d68U, 0xc33bf8b9U, 0x115f4e6bU, + 0x141a0e6eU, 0x2d6c4157U, 0xe253b198U, 0x054e4b7fU, + 0xf98d7483U, 0x479ed93dU, 0xff08f785U, 0xc27bb9b8U, + 0x2163425bU, 0xd9a57ca3U, 0x5f80df25U, 0x578add2dU, + 0x405b1b3aU, 0xa5c663dfU, 0x510f5e2bU, 0x18150d62U, + 0xe313f099U, 0x4c541836U, 0x1c100c66U, 0x2fecc355U, + 0x9df06de7U, 0x0e848a74U, 0xbc9824c6U, 0x169a8c6cU, + 0x94ba2eeeU, 0x33f7c449U, 0x1bd5ce61U, 0x397d4443U, + 0xa343e0d9U, 0xda65bfa0U, 0xae0ca2d4U, 0x2aa98350U, + 0xc0fb3bbaU, 0xf8cd3582U, 0x4b91da31U, 0x822ba9f8U, + 0xecdc3096U, 0x6073131aU, 0xadcc61d7U, 0x2be9c251U, + 0x9b75eee1U, 0x68791112U, 0x3eb88644U, 0x5ec09e24U, + 0x22a38158U, 0x26a6805cU, 0xfa4db780U, 0xd26fbda8U, + 0xa1c362dbU, 0xfb0df681U, 0x29694053U, 0xdda07da7U, + 0x792d5403U, 0xe0d3339aU, 0x6536531fU, 0x6af99310U, + 0xd32ffca9U, 0xf0c7378aU, 0xe656b09cU, 0x923fade8U, + 0xeb19f291U, 0xd72afdadU, 0xfe48b684U, 0xf4c2368eU, + 0xbf58e7c5U, 0x90bf2feaU, 0x538fdc29U, 0xb5d267cfU, + 0x014b4a7bU, 0xa08323daU, 0x7aed9700U, 0x6133521bU, + 0x23e3c059U, 0x46de983cU, 0xd4ea3eaeU, 0xdf20ffa5U, + 0x7522570fU, 0x000b0b7aU, 0x451e5b3fU, 0x550a5f2fU, + 0xb1d766cbU, 0x32b78548U, 0xc9b178b3U, 0xbe18a6c4U, + 0xa746e1ddU, 0xcdb479b7U, 0x4ad19b30U, 0x6efc9214U, + 0x028b8978U, 0x7127560bU, 0x504f1f2aU, 0xb357e4c9U, + 0x80ab2bfaU, 0x2eac8254U, 0x8ca428f6U, 0x85ee6bffU, + 0xf702f58dU, 0x544a1e2eU, 0x62f39118U, 0x2426025eU, + 0x7fa8d705U, 0xe4d6329eU, 0xa203a1d8U, 0x17dacd6dU, + 0x72e79508U, 0x2c2c0056U, 0xea59b390U, 0x6fbcd315U, + 0xc8f139b2U, 0xb89d25c2U, 0x73a7d409U, 0xb612a4ccU, + 0x123123adU, 0x0b6f64b4U, 0xeef21c51U, 0xb2b90b0dU, + 0x7a4339c5U, 0xceda1471U, 0xbd76cb02U, 0x97d44328U, + 0x11f1e0aeU, 0x93d1422cU, 0x19fbe2a6U, 0x427537fdU, + 0xe937de56U, 0xa6a80e19U, 0xf923da46U, 0x5daef3e2U, + 0xe538dd5aU, 0xd444906bU, 0x234d6e9cU, 0x9011812fU, + 0xe13ddc5eU, 0xb3f94a0cU, 0x59abf2e6U, 0x467036f9U, + 0xe3bd5e5cU, 0x58ebb3e7U, 0x05e0e5baU, 0xd101d06eU, + 0x6cd2bed3U, 0x532172ecU, 0x51a1f0eeU, 0x2f426d90U, + 0x3b536884U, 0x40f5b5ffU, 0x08afa7b7U, 0x9a9b0125U, + 0x0f6a65b0U, 0xf6ec1a49U, 0x2b476c94U, 0xa02d8d1fU, + 0x8540c53aU, 0x18bba3a7U, 0x6598fddaU, 0x44f0b4fbU, + 0xfee61841U, 0x764c3ac9U, 0xfba35844U, 0xc055957fU, + 0xdacb1165U, 0x87c04738U, 0x39d3ea86U, 0xefb25d50U, + 0x6e523cd1U, 0x6997fed6U, 0xeaf71d55U, 0x1f7e61a0U, + 0x4b3f74f4U, 0x361c2a89U, 0x1b7b60a4U, 0xa2ad0f1dU, + 0x9c1e8223U, 0x770c7bc8U, 0xb57cc90aU, 0xd381526cU, + 0x54e4b0ebU, 0x55a4f1eaU, 0xd7845368U, 0xbab30905U, + 0x86800639U, 0x8400843bU, 0x15f4e1aaU, 0xa3ed4e1cU, + 0x473077f8U, 0x2c82ae93U, 0xb973ca06U, 0x2dc2ef92U, + 0xd2c1136dU, 0x5f2e71e0U, 0x74ccb8cbU, 0xebb75c54U, + 0xe8779f57U, 0xe4789c5bU, 0x4f3a75f0U, 0x83c5463cU, + 0x8c0a8633U, 0xd84b9367U, 0x220d2f9dU, 0x67187fd8U, + 0xaaa70d15U, 0xe6f81e59U, 0x758cf9caU, 0x64d8bcdbU, + 0x880f8737U, 0x10b1a1afU, 0x3f566980U, 0x9d5ec322U, + 0x31d9e88eU, 0xd90bd266U, 0x7189f8ceU, 0x3099a98fU, + 0xc450947bU, 0x2887af97U, 0x0e2a24b1U, 0xc395567cU, + 0xdd0ed362U, 0xc115d47eU, 0xb8338b07U, 0xa568cd1aU, + 0x4dbaf7f2U, 0xcd1ad772U, 0xa8278f17U, 0x572473e8U, + 0x1a3b21a5U, 0x49bff6f6U, 0x50e1b1efU, 0x14b4a0abU, + 0x375c6b88U, 0x062026b9U, 0xd504d16aU, 0x00a5a5bfU, + 0x78c3bbc7U, 0x9151c02eU, 0x41b5f4feU, 0xd6c41269U, + 0xcb9f5474U, 0x5a6b31e5U, 0x6a573dd5U, 0x33596a8cU, + 0xe2fd1f5dU, 0xb7fc4b08U, 0x631d7edcU, 0x022527bdU, + 0x48ffb7f7U, 0x566432e9U, 0xa967ce16U, 0x9fde4120U, + 0xc7905778U, 0x96940229U, 0x8285073dU, 0x72493bcdU, + 0xaea20c11U, 0xcc5a9673U, 0x1dfee3a2U, 0xcf9a5570U, + 0xcadf1575U, 0xf3a95a4cU, 0x3c96aa83U, 0xdb8b5064U, + 0x27486f98U, 0x995bc226U, 0x21cdec9eU, 0x1cbea2a3U, + 0xffa65940U, 0x076067b8U, 0x8145c43eU, 0x894fc636U, + 0x9e9e0021U, 0x7b0378c4U, 0x8fca4530U, 0xc6d01679U, + 0x3dd6eb82U, 0x9291032dU, 0xc2d5177dU, 0xf129d84eU, + 0x433576fcU, 0xd041916fU, 0x625d3fddU, 0xc85f9777U, + 0x4a7f35f5U, 0xed32df52U, 0xc510d57aU, 0xe7b85f58U, + 0x7d86fbc2U, 0x04a0a4bbU, 0x70c9b9cfU, 0xf46c984bU, + 0x1e3e20a1U, 0x26082e99U, 0x9554c12aU, 0x5ceeb2e3U, + 0x32192b8dU, 0xbeb60801U, 0x73097accU, 0xf52cd94aU, + 0x45b0f5faU, 0xb6bc0a09U, 0xe07d9d5fU, 0x8005853fU, + 0xfc669a43U, 0xf8639b47U, 0x2488ac9bU, 0x0caaa6b3U, + 0x7f0679c0U, 0x25c8ed9aU, 0xf7ac5b48U, 0x036566bcU, + 0xa7e84f18U, 0x3e162881U, 0xbbf34804U, 0xb43c880bU, + 0x0deae7b2U, 0x2e022c91U, 0x3893ab87U, 0x4cfab6f3U, + 0x35dce98aU, 0x09efe6b6U, 0x208dad9fU, 0x2a072d95U, + 0x619dfcdeU, 0x4e7a34f1U, 0x8d4ac732U, 0x6b177cd4U, + 0xdf8e5160U, 0x7e4638c1U, 0xa4288c1bU, 0xbff64900U, + 0xfd26db42U, 0x981b8327U, 0x0a2f25b5U, 0x01e5e4beU, + 0xabe74c14U, 0xdece1061U, 0x9bdb4024U, 0x8bcf4434U, + 0x6f127dd0U, 0xec729e53U, 0x177463a8U, 0x60ddbddfU, + 0x7983fac6U, 0x137162acU, 0x9414802bU, 0xb039890fU, + 0xdc4e9263U, 0xafe24d10U, 0x8e8a0431U, 0x6d92ffd2U, + 0x5e6e30e1U, 0xf069994fU, 0x526133edU, 0x5b2b70e4U, + 0x29c7ee96U, 0x8a8f0535U, 0xbc368a03U, 0xfae31945U, + 0xa16dcc1eU, 0x3a132985U, 0x7cc6bac3U, 0xc91fd676U, + 0xac228e13U, 0xf2e91b4dU, 0x349ca88bU, 0xb179c80eU, + 0x163422a9U, 0x66583ed9U, 0xad62cf12U, 0x68d7bfd7U, + 0xc2a361efU, 0xdbfd26f6U, 0x3e605e13U, 0x622b494fU, + 0xaad17b87U, 0x1e485633U, 0x6de48940U, 0x4746016aU, + 0xc163a2ecU, 0x4343006eU, 0xc969a0e4U, 0x92e775bfU, + 0x39a59c14U, 0x763a4c5bU, 0x29b19804U, 0x8d3cb1a0U, + 0x35aa9f18U, 0x04d6d229U, 0xf3df2cdeU, 0x4083c36dU, + 0x31af9e1cU, 0x636b084eU, 0x8939b0a4U, 0x96e274bbU, + 0x332f1c1eU, 0x8879f1a5U, 0xd572a7f8U, 0x0193922cU, + 0xbc40fc91U, 0x83b330aeU, 0x8133b2acU, 0xffd02fd2U, + 0xebc12ac6U, 0x9067f7bdU, 0xd83de5f5U, 0x4a094367U, + 0xdff827f2U, 0x267e580bU, 0xfbd52ed6U, 0x70bfcf5dU, + 0x55d28778U, 0xc829e1e5U, 0xb50abf98U, 0x9462f6b9U, + 0x2e745a03U, 0xa6de788bU, 0x2b311a06U, 0x10c7d73dU, + 0x0a595327U, 0x5752057aU, 0xe941a8c4U, 0x3f201f12U, + 0xbec07e93U, 0xb905bc94U, 0x3a655f17U, 0xcfec23e2U, + 0x9bad36b6U, 0xe68e68cbU, 0xcbe922e6U, 0x723f4d5fU, + 0x4c8cc061U, 0xa79e398aU, 0x65ee8b48U, 0x0313102eU, + 0x8476f2a9U, 0x8536b3a8U, 0x0716112aU, 0x6a214b47U, + 0x5612447bU, 0x5492c679U, 0xc566a3e8U, 0x737f0c5eU, + 0x97a235baU, 0xfc10ecd1U, 0x69e18844U, 0xfd50add0U, + 0x0253512fU, 0x8fbc33a2U, 0xa45efa89U, 0x3b251e16U, + 0x38e5dd15U, 0x34eade19U, 0x9fa837b2U, 0x5357047eU, + 0x5c98c471U, 0x08d9d125U, 0xf29f6ddfU, 0xb78a3d9aU, + 0x7a354f57U, 0x366a5c1bU, 0xa51ebb88U, 0xb44afe99U, + 0x589dc575U, 0xc023e3edU, 0xefc42bc2U, 0x4dcc8160U, + 0xe14baaccU, 0x09999024U, 0xa11bba8cU, 0xe00bebcdU, + 0x14c2d639U, 0xf815edd5U, 0xdeb866f3U, 0x1307143eU, + 0x0d9c9120U, 0x1187963cU, 0x68a1c945U, 0x75fa8f58U, + 0x9d28b5b0U, 0x1d889530U, 0x78b5cd55U, 0x87b631aaU, + 0xcaa963e7U, 0x992db4b4U, 0x8073f3adU, 0xc426e2e9U, + 0xe7ce29caU, 0xd6b264fbU, 0x05969328U, 0xd037e7fdU, + 0xa851f985U, 0x41c3826cU, 0x9127b6bcU, 0x0656502bU, + 0x1b0d1636U, 0x8af973a7U, 0xbac57f97U, 0xe3cb28ceU, + 0x326f5d1fU, 0x676e094aU, 0xb38f3c9eU, 0xd2b765ffU, + 0x986df5b5U, 0x86f670abU, 0x79f58c54U, 0x4f4c0362U, + 0x1702153aU, 0x4606406bU, 0x5217457fU, 0xa2db798fU, + 0x7e304e53U, 0x1cc8d431U, 0xcd6ca1e0U, 0x1f081732U, + 0x1a4d5737U, 0x233b180eU, 0xec04e8c1U, 0x0b191226U, + 0xf7da2ddaU, 0x49c98064U, 0xf15faedcU, 0xcc2ce0e1U, + 0x2f341b02U, 0xd7f225faU, 0x51d7867cU, 0x59dd8474U, + 0x4e0c4263U, 0xab913a86U, 0x5f580772U, 0x1642543bU, + 0xed44a9c0U, 0x4203416fU, 0x1247553fU, 0x21bb9a0cU, + 0x93a734beU, 0x00d3d32dU, 0xb2cf7d9fU, 0x18cdd535U, + 0x9aed77b7U, 0x3da09d10U, 0x15829738U, 0x372a1d1aU, + 0xad14b980U, 0xd432e6f9U, 0xa05bfb8dU, 0x24feda09U, + 0xceac62e3U, 0xf69a6cdbU, 0x45c68368U, 0x8c7cf0a1U, + 0xe28b69cfU, 0x6e244a43U, 0xa39b388eU, 0x25be9b08U, + 0x9522b7b8U, 0x662e484bU, 0x30efdf1dU, 0x5097c77dU, + 0x2cf4d801U, 0x28f1d905U, 0xf41aeed9U, 0xdc38e4f1U, + 0xaf943b82U, 0xf55aafd8U, 0x273e190aU, 0xd3f724feU, + 0x777a0d5aU, 0xee846ac3U, 0x6b610a46U, 0x64aeca49U, + 0xdd78a5f0U, 0xfe906ed3U, 0xe801e9c5U, 0x9c68f4b1U, + 0xe54eabc8U, 0xd97da4f4U, 0xf01fefddU, 0xfa956fd7U, + 0xb10fbe9cU, 0x9ee876b3U, 0x5dd88570U, 0xbb853e96U, + 0x0f1c1322U, 0xaed47a83U, 0x74bace59U, 0x6f640b42U, + 0x2db49900U, 0x4889c165U, 0xdabd67f7U, 0xd177a6fcU, + 0x7b750e56U, 0x0e5c5223U, 0x4b490266U, 0x5b5d0676U, + 0xbf803f92U, 0x3ce0dc11U, 0xc7e621eaU, 0xb04fff9dU, + 0xa911b884U, 0xc3e320eeU, 0x4486c269U, 0x60abcb4dU, + 0x0cdcd021U, 0x7f700f52U, 0x5e184673U, 0xbd00bd90U, + 0x8efc72a3U, 0x20fbdb0dU, 0x82f371afU, 0x8bb932a6U, + 0xf955acd4U, 0x5a1d4777U, 0x6ca4c841U, 0x2a715b07U, + 0x71ff8e5cU, 0xea816bc7U, 0xac54f881U, 0x198d9434U, + 0x7cb0cc51U, 0x227b590fU, 0xe40eeac9U, 0x61eb8a4cU, + 0xc6a660ebU, 0xb6ca7c9bU, 0x7df08d50U, 0xb845fd95U, + 0xfffb048aU, 0xe6a54393U, 0x03383b76U, 0x5f732c2aU, + 0x97891ee2U, 0x23103356U, 0x50bcec25U, 0x7a1e640fU, + 0xfc3bc789U, 0x7e1b650bU, 0xf431c581U, 0xafbf10daU, + 0x04fdf971U, 0x4b62293eU, 0x14e9fd61U, 0xb064d4c5U, + 0x08f2fa7dU, 0x398eb74cU, 0xce8749bbU, 0x7ddba608U, + 0x0cf7fb79U, 0x5e336d2bU, 0xb461d5c1U, 0xabba11deU, + 0x0e77797bU, 0xb52194c0U, 0xe82ac29dU, 0x3ccbf749U, + 0x811899f4U, 0xbeeb55cbU, 0xbc6bd7c9U, 0xc2884ab7U, + 0xd6994fa3U, 0xad3f92d8U, 0xe5658090U, 0x77512602U, + 0xe2a04297U, 0x1b263d6eU, 0xc68d4bb3U, 0x4de7aa38U, + 0x688ae21dU, 0xf5718480U, 0x8852dafdU, 0xa93a93dcU, + 0x132c3f66U, 0x9b861deeU, 0x16697f63U, 0x2d9fb258U, + 0x37013642U, 0x6a0a601fU, 0xd419cda1U, 0x02787a77U, + 0x83981bf6U, 0x845dd9f1U, 0x073d3a72U, 0xf2b44687U, + 0xa6f553d3U, 0xdbd60daeU, 0xf6b14783U, 0x4f67283aU, + 0x71d4a504U, 0x9ac65cefU, 0x58b6ee2dU, 0x3e4b754bU, + 0xb92e97ccU, 0xb86ed6cdU, 0x3a4e744fU, 0x57792e22U, + 0x6b4a211eU, 0x69caa31cU, 0xf83ec68dU, 0x4e27693bU, + 0xaafa50dfU, 0xc14889b4U, 0x54b9ed21U, 0xc008c8b5U, + 0x3f0b344aU, 0xb2e456c7U, 0x99069fecU, 0x067d7b73U, + 0x05bdb870U, 0x09b2bb7cU, 0xa2f052d7U, 0x6e0f611bU, + 0x61c0a114U, 0x3581b440U, 0xcfc708baU, 0x8ad258ffU, + 0x476d2a32U, 0x0b32397eU, 0x9846deedU, 0x89129bfcU, + 0x65c5a010U, 0xfd7b8688U, 0xd29c4ea7U, 0x7094e405U, + 0xdc13cfa9U, 0x34c1f541U, 0x9c43dfe9U, 0xdd538ea8U, + 0x299ab35cU, 0xc54d88b0U, 0xe3e00396U, 0x2e5f715bU, + 0x30c4f445U, 0x2cdff359U, 0x55f9ac20U, 0x48a2ea3dU, + 0xa070d0d5U, 0x20d0f055U, 0x45eda830U, 0xbaee54cfU, + 0xf7f10682U, 0xa475d1d1U, 0xbd2b96c8U, 0xf97e878cU, + 0xda964cafU, 0xebea019eU, 0x38cef64dU, 0xed6f8298U, + 0x95099ce0U, 0x7c9be709U, 0xac7fd3d9U, 0x3b0e354eU, + 0x26557353U, 0xb7a116c2U, 0x879d1af2U, 0xde934dabU, + 0x0f37387aU, 0x5a366c2fU, 0x8ed759fbU, 0xefef009aU, + 0xa53590d0U, 0xbbae15ceU, 0x44ade931U, 0x72146607U, + 0x2a5a705fU, 0x7b5e250eU, 0x6f4f201aU, 0x9f831ceaU, + 0x43682b36U, 0x2190b154U, 0xf034c485U, 0x22507257U, + 0x27153252U, 0x1e637d6bU, 0xd15c8da4U, 0x36417743U, + 0xca8248bfU, 0x7491e501U, 0xcc07cbb9U, 0xf1748584U, + 0x126c7e67U, 0xeaaa409fU, 0x6c8fe319U, 0x6485e111U, + 0x73542706U, 0x96c95fe3U, 0x62006217U, 0x2b1a315eU, + 0xd01ccca5U, 0x7f5b240aU, 0x2f1f305aU, 0x1ce3ff69U, + 0xaeff51dbU, 0x3d8bb648U, 0x8f9718faU, 0x2595b050U, + 0xa7b512d2U, 0x00f8f875U, 0x28daf25dU, 0x0a72787fU, + 0x904cdce5U, 0xe96a839cU, 0x9d039ee8U, 0x19a6bf6cU, + 0xf3f40786U, 0xcbc209beU, 0x789ee60dU, 0xb12495c4U, + 0xdfd30caaU, 0x537c2f26U, 0x9ec35debU, 0x18e6fe6dU, + 0xa87ad2ddU, 0x5b762d2eU, 0x0db7ba78U, 0x6dcfa218U, + 0x11acbd64U, 0x15a9bc60U, 0xc9428bbcU, 0xe1608194U, + 0x92cc5ee7U, 0xc802cabdU, 0x1a667c6fU, 0xeeaf419bU, + 0x4a22683fU, 0xd3dc0fa6U, 0x56396f23U, 0x59f6af2cU, + 0xe020c095U, 0xc3c80bb6U, 0xd5598ca0U, 0xa13091d4U, + 0xd816ceadU, 0xe425c191U, 0xcd478ab8U, 0xc7cd0ab2U, + 0x8c57dbf9U, 0xa3b013d6U, 0x6080e015U, 0x86dd5bf3U, + 0x32447647U, 0x938c1fe6U, 0x49e2ab3cU, 0x523c6e27U, + 0x10ecfc65U, 0x75d1a400U, 0xe7e50292U, 0xec2fc399U, + 0x462d6b33U, 0x33043746U, 0x76116703U, 0x66056313U, + 0x82d85af7U, 0x01b8b974U, 0xfabe448fU, 0x8d179af8U, + 0x9449dde1U, 0xfebb458bU, 0x79dea70cU, 0x5df3ae28U, + 0x3184b544U, 0x42286a37U, 0x63402316U, 0x8058d8f5U, + 0xb3a417c6U, 0x1da3be68U, 0xbfab14caU, 0xb6e157c3U, + 0xc40dc9b1U, 0x67452212U, 0x51fcad24U, 0x17293e62U, + 0x4ca7eb39U, 0xd7d90ea2U, 0x910c9de4U, 0x24d5f151U, + 0x41e8a934U, 0x1f233c6aU, 0xd9568facU, 0x5cb3ef29U, + 0xfbfe058eU, 0x8b9219feU, 0x40a8e835U, 0x851d98f0U, + 0xcb5d9618U, 0xd203d101U, 0x379ea9e4U, 0x6bd5beb8U, + 0xa32f8c70U, 0x17b6a1c4U, 0x641a7eb7U, 0x4eb8f69dU, + 0xc89d551bU, 0x4abdf799U, 0xc0975713U, 0x9b198248U, + 0x305b6be3U, 0x7fc4bbacU, 0x204f6ff3U, 0x84c24657U, + 0x3c5468efU, 0x0d2825deU, 0xfa21db29U, 0x497d349aU, + 0x385169ebU, 0x6a95ffb9U, 0x80c74753U, 0x9f1c834cU, + 0x3ad1ebe9U, 0x81870652U, 0xdc8c500fU, 0x086d65dbU, + 0xb5be0b66U, 0x8a4dc759U, 0x88cd455bU, 0xf62ed825U, + 0xe23fdd31U, 0x9999004aU, 0xd1c31202U, 0x43f7b490U, + 0xd606d005U, 0x2f80affcU, 0xf22bd921U, 0x794138aaU, + 0x5c2c708fU, 0xc1d71612U, 0xbcf4486fU, 0x9d9c014eU, + 0x278aadf4U, 0xaf208f7cU, 0x22cfedf1U, 0x193920caU, + 0x03a7a4d0U, 0x5eacf28dU, 0xe0bf5f33U, 0x36dee8e5U, + 0xb73e8964U, 0xb0fb4b63U, 0x339ba8e0U, 0xc612d415U, + 0x9253c141U, 0xef709f3cU, 0xc217d511U, 0x7bc1baa8U, + 0x45723796U, 0xae60ce7dU, 0x6c107cbfU, 0x0aede7d9U, + 0x8d88055eU, 0x8cc8445fU, 0x0ee8e6ddU, 0x63dfbcb0U, + 0x5fecb38cU, 0x5d6c318eU, 0xcc98541fU, 0x7a81fba9U, + 0x9e5cc24dU, 0xf5ee1b26U, 0x601f7fb3U, 0xf4ae5a27U, + 0x0bada6d8U, 0x8642c455U, 0xada00d7eU, 0x32dbe9e1U, + 0x311b2ae2U, 0x3d1429eeU, 0x9656c045U, 0x5aa9f389U, + 0x55663386U, 0x012726d2U, 0xfb619a28U, 0xbe74ca6dU, + 0x73cbb8a0U, 0x3f94abecU, 0xace04c7fU, 0xbdb4096eU, + 0x51633282U, 0xc9dd141aU, 0xe63adc35U, 0x44327697U, + 0xe8b55d3bU, 0x006767d3U, 0xa8e54d7bU, 0xe9f51c3aU, + 0x1d3c21ceU, 0xf1eb1a22U, 0xd7469104U, 0x1af9e3c9U, + 0x046266d7U, 0x187961cbU, 0x615f3eb2U, 0x7c0478afU, + 0x94d64247U, 0x147662c7U, 0x714b3aa2U, 0x8e48c65dU, + 0xc3579410U, 0x90d34343U, 0x898d045aU, 0xcdd8151eU, + 0xee30de3dU, 0xdf4c930cU, 0x0c6864dfU, 0xd9c9100aU, + 0xa1af0e72U, 0x483d759bU, 0x98d9414bU, 0x0fa8a7dcU, + 0x12f3e1c1U, 0x83078450U, 0xb33b8860U, 0xea35df39U, + 0x3b91aae8U, 0x6e90febdU, 0xba71cb69U, 0xdb499208U, + 0x91930242U, 0x8f08875cU, 0x700b7ba3U, 0x46b2f495U, + 0x1efce2cdU, 0x4ff8b79cU, 0x5be9b288U, 0xab258e78U, + 0x77ceb9a4U, 0x153623c6U, 0xc4925617U, 0x16f6e0c5U, + 0x13b3a0c0U, 0x2ac5eff9U, 0xe5fa1f36U, 0x02e7e5d1U, + 0xfe24da2dU, 0x40377793U, 0xf8a1592bU, 0xc5d21716U, + 0x26caecf5U, 0xde0cd20dU, 0x5829718bU, 0x50237383U, + 0x47f2b594U, 0xa26fcd71U, 0x56a6f085U, 0x1fbca3ccU, + 0xe4ba5e37U, 0x4bfdb698U, 0x1bb9a2c8U, 0x28456dfbU, + 0x9a59c349U, 0x092d24daU, 0xbb318a68U, 0x113322c2U, + 0x93138040U, 0x345e6ae7U, 0x1c7c60cfU, 0x3ed4eaedU, + 0xa4ea4e77U, 0xddcc110eU, 0xa9a50c7aU, 0x2d002dfeU, + 0xc7529514U, 0xff649b2cU, 0x4c38749fU, 0x85820756U, + 0xeb759e38U, 0x67dabdb4U, 0xaa65cf79U, 0x2c406cffU, + 0x9cdc404fU, 0x6fd0bfbcU, 0x391128eaU, 0x5969308aU, + 0x250a2ff6U, 0x210f2ef2U, 0xfde4192eU, 0xd5c61306U, + 0xa66acc75U, 0xfca4582fU, 0x2ec0eefdU, 0xda09d309U, + 0x7e84faadU, 0xe77a9d34U, 0x629ffdb1U, 0x6d503dbeU, + 0xd4865207U, 0xf76e9924U, 0xe1ff1e32U, 0x95960346U, + 0xecb05c3fU, 0xd0835303U, 0xf9e1182aU, 0xf36b9820U, + 0xb8f1496bU, 0x97168144U, 0x54267287U, 0xb27bc961U, + 0x06e2e4d5U, 0xa72a8d74U, 0x7d4439aeU, 0x669afcb5U, + 0x244a6ef7U, 0x41773692U, 0xd3439000U, 0xd889510bU, + 0x728bf9a1U, 0x07a2a5d4U, 0x42b7f591U, 0x52a3f181U, + 0xb67ec865U, 0x351e2be6U, 0xce18d61dU, 0xb9b1086aU, + 0xa0ef4f73U, 0xca1dd719U, 0x4d78359eU, 0x69553cbaU, + 0x052227d6U, 0x768ef8a5U, 0x57e6b184U, 0xb4fe4a67U, + 0x87028554U, 0x29052cfaU, 0x8b0d8658U, 0x8247c551U, + 0xf0ab5b23U, 0x53e3b080U, 0x655a3fb6U, 0x238facf0U, + 0x780179abU, 0xe37f9c30U, 0xa5aa0f76U, 0x107363c3U, + 0x754e3ba6U, 0x2b85aef8U, 0xedf01d3eU, 0x68157dbbU, + 0xcf58971cU, 0xbf348b6cU, 0x740e7aa7U, 0xb1bb0a62U, + 0x019c9d13U, 0x18c2da0aU, 0xfd5fa2efU, 0xa114b5b3U, + 0x69ee877bU, 0xdd77aacfU, 0xaedb75bcU, 0x8479fd96U, + 0x025c5e10U, 0x807cfc92U, 0x0a565c18U, 0x51d88943U, + 0xfa9a60e8U, 0xb505b0a7U, 0xea8e64f8U, 0x4e034d5cU, + 0xf69563e4U, 0xc7e92ed5U, 0x30e0d022U, 0x83bc3f91U, + 0xf29062e0U, 0xa054f4b2U, 0x4a064c58U, 0x55dd8847U, + 0xf010e0e2U, 0x4b460d59U, 0x164d5b04U, 0xc2ac6ed0U, + 0x7f7f006dU, 0x408ccc52U, 0x420c4e50U, 0x3cefd32eU, + 0x28fed63aU, 0x53580b41U, 0x1b021909U, 0x8936bf9bU, + 0x1cc7db0eU, 0xe541a4f7U, 0x38ead22aU, 0xb38033a1U, + 0x96ed7b84U, 0x0b161d19U, 0x76354364U, 0x575d0a45U, + 0xed4ba6ffU, 0x65e18477U, 0xe80ee6faU, 0xd3f82bc1U, + 0xc966afdbU, 0x946df986U, 0x2a7e5438U, 0xfc1fe3eeU, + 0x7dff826fU, 0x7a3a4068U, 0xf95aa3ebU, 0x0cd3df1eU, + 0x5892ca4aU, 0x25b19437U, 0x08d6de1aU, 0xb100b1a3U, + 0x8fb33c9dU, 0x64a1c576U, 0xa6d177b4U, 0xc02cecd2U, + 0x47490e55U, 0x46094f54U, 0xc429edd6U, 0xa91eb7bbU, + 0x952db887U, 0x97ad3a85U, 0x06595f14U, 0xb040f0a2U, + 0x549dc946U, 0x3f2f102dU, 0xaade74b8U, 0x3e6f512cU, + 0xc16cadd3U, 0x4c83cf5eU, 0x67610675U, 0xf81ae2eaU, + 0xfbda21e9U, 0xf7d522e5U, 0x5c97cb4eU, 0x9068f882U, + 0x9fa7388dU, 0xcbe62dd9U, 0x31a09123U, 0x74b5c166U, + 0xb90ab3abU, 0xf555a0e7U, 0x66214774U, 0x77750265U, + 0x9ba23989U, 0x031c1f11U, 0x2cfbd73eU, 0x8ef37d9cU, + 0x22745630U, 0xcaa66cd8U, 0x62244670U, 0x23341731U, + 0xd7fd2ac5U, 0x3b2a1129U, 0x1d879a0fU, 0xd038e8c2U, + 0xcea36ddcU, 0xd2b86ac0U, 0xab9e35b9U, 0xb6c573a4U, + 0x5e17494cU, 0xdeb769ccU, 0xbb8a31a9U, 0x4489cd56U, + 0x09969f1bU, 0x5a124848U, 0x434c0f51U, 0x07191e15U, + 0x24f1d536U, 0x158d9807U, 0xc6a96fd4U, 0x13081b01U, + 0x6b6e0579U, 0x82fc7e90U, 0x52184a40U, 0xc569acd7U, + 0xd832eacaU, 0x49c68f5bU, 0x79fa836bU, 0x20f4d432U, + 0xf150a1e3U, 0xa451f5b6U, 0x70b0c062U, 0x11889903U, + 0x5b520949U, 0x45c98c57U, 0xbaca70a8U, 0x8c73ff9eU, + 0xd43de9c6U, 0x8539bc97U, 0x9128b983U, 0x61e48573U, + 0xbd0fb2afU, 0xdff728cdU, 0x0e535d1cU, 0xdc37ebceU, + 0xd972abcbU, 0xe004e4f2U, 0x2f3b143dU, 0xc826eedaU, + 0x34e5d126U, 0x8af67c98U, 0x32605220U, 0x0f131c1dU, + 0xec0be7feU, 0x14cdd906U, 0x92e87a80U, 0x9ae27888U, + 0x8d33be9fU, 0x68aec67aU, 0x9c67fb8eU, 0xd57da8c7U, + 0x2e7b553cU, 0x813cbd93U, 0xd178a9c3U, 0xe28466f0U, + 0x5098c842U, 0xc3ec2fd1U, 0x71f08163U, 0xdbf229c9U, + 0x59d28b4bU, 0xfe9f61ecU, 0xd6bd6bc4U, 0xf415e1e6U, + 0x6e2b457cU, 0x170d1a05U, 0x63640771U, 0xe7c126f5U, + 0x0d939e1fU, 0x35a59027U, 0x86f97f94U, 0x4f430c5dU, + 0x21b49533U, 0xad1bb6bfU, 0x60a4c472U, 0xe68167f4U, + 0x561d4b44U, 0xa511b4b7U, 0xf3d023e1U, 0x93a83b81U, + 0xefcb24fdU, 0xebce25f9U, 0x37251225U, 0x1f07180dU, + 0x6cabc77eU, 0x36655324U, 0xe401e5f6U, 0x10c8d802U, + 0xb445f1a6U, 0x2dbb963fU, 0xa85ef6baU, 0xa79136b5U, + 0x1e47590cU, 0x3daf922fU, 0x2b3e1539U, 0x5f57084dU, + 0x26715734U, 0x1a425808U, 0x33201321U, 0x39aa932bU, + 0x72304260U, 0x5dd78a4fU, 0x9ee7798cU, 0x78bac26aU, + 0xcc23efdeU, 0x6deb867fU, 0xb78532a5U, 0xac5bf7beU, + 0xee8b65fcU, 0x8bb63d99U, 0x19829b0bU, 0x12485a00U, + 0xb84af2aaU, 0xcd63aedfU, 0x8876fe9aU, 0x9862fa8aU, + 0x7cbfc36eU, 0xffdf20edU, 0x04d9dd16U, 0x73700361U, + 0x6a2e4478U, 0x00dcdc12U, 0x87b93e95U, 0xa39437b1U, + 0xcfe32cddU, 0xbc4ff3aeU, 0x9d27ba8fU, 0x7e3f416cU, + 0x4dc38e5fU, 0xe3c427f1U, 0x41cc8d53U, 0x4886ce5aU, + 0x3a6a5028U, 0x9922bb8bU, 0xaf9b34bdU, 0xe94ea7fbU, + 0xb2c072a0U, 0x29be973bU, 0x6f6b047dU, 0xdab268c8U, + 0xbf8f30adU, 0xe144a5f3U, 0x27311635U, 0xa2d476b0U, + 0x05999c17U, 0x75f58067U, 0xbecf71acU, 0x7b7a0169U, + 0x033437b9U, 0x1a6a70a0U, 0xfff70845U, 0xa3bc1f19U, + 0x6b462dd1U, 0xdfdf0065U, 0xac73df16U, 0x86d1573cU, + 0x00f4f4baU, 0x82d45638U, 0x08fef6b2U, 0x537023e9U, + 0xf832ca42U, 0xb7ad1a0dU, 0xe826ce52U, 0x4cabe7f6U, + 0xf43dc94eU, 0xc541847fU, 0x32487a88U, 0x8114953bU, + 0xf038c84aU, 0xa2fc5e18U, 0x48aee6f2U, 0x577522edU, + 0xf2b84a48U, 0x49eea7f3U, 0x14e5f1aeU, 0xc004c47aU, + 0x7dd7aac7U, 0x422466f8U, 0x40a4e4faU, 0x3e477984U, + 0x2a567c90U, 0x51f0a1ebU, 0x19aab3a3U, 0x8b9e1531U, + 0x1e6f71a4U, 0xe7e90e5dU, 0x3a427880U, 0xb128990bU, + 0x9445d12eU, 0x09beb7b3U, 0x749de9ceU, 0x55f5a0efU, + 0xefe30c55U, 0x67492eddU, 0xeaa64c50U, 0xd150816bU, + 0xcbce0571U, 0x96c5532cU, 0x28d6fe92U, 0xfeb74944U, + 0x7f5728c5U, 0x7892eac2U, 0xfbf20941U, 0x0e7b75b4U, + 0x5a3a60e0U, 0x27193e9dU, 0x0a7e74b0U, 0xb3a81b09U, + 0x8d1b9637U, 0x66096fdcU, 0xa479dd1eU, 0xc2844678U, + 0x45e1a4ffU, 0x44a1e5feU, 0xc681477cU, 0xabb61d11U, + 0x9785122dU, 0x9505902fU, 0x04f1f5beU, 0xb2e85a08U, + 0x563563ecU, 0x3d87ba87U, 0xa876de12U, 0x3cc7fb86U, + 0xc3c40779U, 0x4e2b65f4U, 0x65c9acdfU, 0xfab24840U, + 0xf9728b43U, 0xf57d884fU, 0x5e3f61e4U, 0x92c05228U, + 0x9d0f9227U, 0xc94e8773U, 0x33083b89U, 0x761d6bccU, + 0xbba21901U, 0xf7fd0a4dU, 0x6489eddeU, 0x75dda8cfU, + 0x990a9323U, 0x01b4b5bbU, 0x2e537d94U, 0x8c5bd736U, + 0x20dcfc9aU, 0xc80ec672U, 0x608cecdaU, 0x219cbd9bU, + 0xd555806fU, 0x3982bb83U, 0x1f2f30a5U, 0xd2904268U, + 0xcc0bc776U, 0xd010c06aU, 0xa9369f13U, 0xb46dd90eU, + 0x5cbfe3e6U, 0xdc1fc366U, 0xb9229b03U, 0x462167fcU, + 0x0b3e35b1U, 0x58bae2e2U, 0x41e4a5fbU, 0x05b1b4bfU, + 0x26597f9cU, 0x172532adU, 0xc401c57eU, 0x11a0b1abU, + 0x69c6afd3U, 0x8054d43aU, 0x50b0e0eaU, 0xc7c1067dU, + 0xda9a4060U, 0x4b6e25f1U, 0x7b5229c1U, 0x225c7e98U, + 0xf3f80b49U, 0xa6f95f1cU, 0x72186ac8U, 0x132033a9U, + 0x59faa3e3U, 0x476126fdU, 0xb862da02U, 0x8edb5534U, + 0xd695436cU, 0x8791163dU, 0x93801329U, 0x634c2fd9U, + 0xbfa71805U, 0xdd5f8267U, 0x0cfbf7b6U, 0xde9f4164U, + 0xdbda0161U, 0xe2ac4e58U, 0x2d93be97U, 0xca8e4470U, + 0x364d7b8cU, 0x885ed632U, 0x30c8f88aU, 0x0dbbb6b7U, + 0xeea34d54U, 0x166573acU, 0x9040d02aU, 0x984ad222U, + 0x8f9b1435U, 0x6a066cd0U, 0x9ecf5124U, 0xd7d5026dU, + 0x2cd3ff96U, 0x83941739U, 0xd3d00369U, 0xe02ccc5aU, + 0x523062e8U, 0xc144857bU, 0x73582bc9U, 0xd95a8363U, + 0x5b7a21e1U, 0xfc37cb46U, 0xd415c16eU, 0xf6bd4b4cU, + 0x6c83efd6U, 0x15a5b0afU, 0x61ccaddbU, 0xe5698c5fU, + 0x0f3b34b5U, 0x370d3a8dU, 0x8451d53eU, 0x4deba6f7U, + 0x231c3f99U, 0xafb31c15U, 0x620c6ed8U, 0xe429cd5eU, + 0x54b5e1eeU, 0xa7b91e1dU, 0xf178894bU, 0x9100912bU, + 0xed638e57U, 0xe9668f53U, 0x358db88fU, 0x1dafb2a7U, + 0x6e036dd4U, 0x34cdf98eU, 0xe6a94f5cU, 0x126072a8U, + 0xb6ed5b0cU, 0x2f133c95U, 0xaaf65c10U, 0xa5399c1fU, + 0x1ceff3a6U, 0x3f073885U, 0x2996bf93U, 0x5dffa2e7U, + 0x24d9fd9eU, 0x18eaf2a2U, 0x3188b98bU, 0x3b023981U, + 0x7098e8caU, 0x5f7f20e5U, 0x9c4fd326U, 0x7a1268c0U, + 0xce8b4574U, 0x6f432cd5U, 0xb52d980fU, 0xaef35d14U, + 0xec23cf56U, 0x891e9733U, 0x1b2a31a1U, 0x10e0f0aaU, + 0xbae25800U, 0xcfcb0475U, 0x8ade5430U, 0x9aca5020U, + 0x7e1769c4U, 0xfd778a47U, 0x067177bcU, 0x71d8a9cbU, + 0x6886eed2U, 0x027476b8U, 0x8511943fU, 0xa13c9d1bU, + 0xcd4b8677U, 0xbee75904U, 0x9f8f1025U, 0x7c97ebc6U, + 0x4f6b24f5U, 0xe16c8d5bU, 0x436427f9U, 0x4a2e64f0U, + 0x38c2fa82U, 0x9b8a1121U, 0xad339e17U, 0xebe60d51U, + 0xb068d80aU, 0x2b163d91U, 0x6dc3aed7U, 0xd81ac262U, + 0xbd279a07U, 0xe3ec0f59U, 0x2599bc9fU, 0xa07cdc1aU, + 0x073136bdU, 0x775d2acdU, 0xbc67db06U, 0x79d2abc3U, + 0x2a6842ccU, 0x333605d5U, 0xd6ab7d30U, 0x8ae06a6cU, + 0x421a58a4U, 0xf6837510U, 0x852faa63U, 0xaf8d2249U, + 0x29a881cfU, 0xab88234dU, 0x21a283c7U, 0x7a2c569cU, + 0xd16ebf37U, 0x9ef16f78U, 0xc17abb27U, 0x65f79283U, + 0xdd61bc3bU, 0xec1df10aU, 0x1b140ffdU, 0xa848e04eU, + 0xd964bd3fU, 0x8ba02b6dU, 0x61f29387U, 0x7e295798U, + 0xdbe43f3dU, 0x60b2d286U, 0x3db984dbU, 0xe958b10fU, + 0x548bdfb2U, 0x6b78138dU, 0x69f8918fU, 0x171b0cf1U, + 0x030a09e5U, 0x78acd49eU, 0x30f6c6d6U, 0xa2c26044U, + 0x373304d1U, 0xceb57b28U, 0x131e0df5U, 0x9874ec7eU, + 0xbd19a45bU, 0x20e2c2c6U, 0x5dc19cbbU, 0x7ca9d59aU, + 0xc6bf7920U, 0x4e155ba8U, 0xc3fa3925U, 0xf80cf41eU, + 0xe2927004U, 0xbf992659U, 0x018a8be7U, 0xd7eb3c31U, + 0x560b5db0U, 0x51ce9fb7U, 0xd2ae7c34U, 0x272700c1U, + 0x73661595U, 0x0e454be8U, 0x232201c5U, 0x9af46e7cU, + 0xa447e342U, 0x4f551aa9U, 0x8d25a86bU, 0xebd8330dU, + 0x6cbdd18aU, 0x6dfd908bU, 0xefdd3209U, 0x82ea6864U, + 0xbed96758U, 0xbc59e55aU, 0x2dad80cbU, 0x9bb42f7dU, + 0x7f691699U, 0x14dbcff2U, 0x812aab67U, 0x159b8ef3U, + 0xea98720cU, 0x67771081U, 0x4c95d9aaU, 0xd3ee3d35U, + 0xd02efe36U, 0xdc21fd3aU, 0x77631491U, 0xbb9c275dU, + 0xb453e752U, 0xe012f206U, 0x1a544efcU, 0x5f411eb9U, + 0x92fe6c74U, 0xdea17f38U, 0x4dd598abU, 0x5c81ddbaU, + 0xb056e656U, 0x28e8c0ceU, 0x070f08e1U, 0xa507a243U, + 0x098089efU, 0xe152b307U, 0x49d099afU, 0x08c0c8eeU, + 0xfc09f51aU, 0x10decef6U, 0x367345d0U, 0xfbcc371dU, + 0xe557b203U, 0xf94cb51fU, 0x806aea66U, 0x9d31ac7bU, + 0x75e39693U, 0xf543b613U, 0x907eee76U, 0x6f7d1289U, + 0x226240c4U, 0x71e69797U, 0x68b8d08eU, 0x2cedc1caU, + 0x0f050ae9U, 0x3e7947d8U, 0xed5db00bU, 0x38fcc4deU, + 0x409adaa6U, 0xa908a14fU, 0x79ec959fU, 0xee9d7308U, + 0xf3c63515U, 0x62325084U, 0x520e5cb4U, 0x0b000bedU, + 0xdaa47e3cU, 0x8fa52a69U, 0x5b441fbdU, 0x3a7c46dcU, + 0x70a6d696U, 0x6e3d5388U, 0x913eaf77U, 0xa7872041U, + 0xffc93619U, 0xaecd6348U, 0xbadc665cU, 0x4a105aacU, + 0x96fb6d70U, 0xf403f712U, 0x25a782c3U, 0xf7c33411U, + 0xf2867414U, 0xcbf03b2dU, 0x04cfcbe2U, 0xe3d23105U, + 0x1f110ef9U, 0xa102a347U, 0x19948dffU, 0x24e7c3c2U, + 0xc7ff3821U, 0x3f3906d9U, 0xb91ca55fU, 0xb116a757U, + 0xa6c76140U, 0x435a19a5U, 0xb7932451U, 0xfe897718U, + 0x058f8ae3U, 0xaac8624cU, 0xfa8c761cU, 0xc970b92fU, + 0x7b6c179dU, 0xe818f00eU, 0x5a045ebcU, 0xf006f616U, + 0x72265494U, 0xd56bbe33U, 0xfd49b41bU, 0xdfe13e39U, + 0x45df9aa3U, 0x3cf9c5daU, 0x4890d8aeU, 0xcc35f92aU, + 0x266741c0U, 0x1e514ff8U, 0xad0da04bU, 0x64b7d382U, + 0x0a404aecU, 0x86ef6960U, 0x4b501badU, 0xcd75b82bU, + 0x7de9949bU, 0x8ee56b68U, 0xd824fc3eU, 0xb85ce45eU, + 0xc43ffb22U, 0xc03afa26U, 0x1cd1cdfaU, 0x34f3c7d2U, + 0x475f18a1U, 0x1d918cfbU, 0xcff53a29U, 0x3b3c07ddU, + 0x9fb12e79U, 0x064f49e0U, 0x83aa2965U, 0x8c65e96aU, + 0x35b386d3U, 0x165b4df0U, 0x00cacae6U, 0x74a3d792U, + 0x0d8588ebU, 0x31b687d7U, 0x18d4ccfeU, 0x125e4cf4U, + 0x59c49dbfU, 0x76235590U, 0xb513a653U, 0x534e1db5U, + 0xe7d73001U, 0x461f59a0U, 0x9c71ed7aU, 0x87af2861U, + 0xc57fba23U, 0xa042e246U, 0x327644d4U, 0x39bc85dfU, + 0x93be2d75U, 0xe6977100U, 0xa3822145U, 0xb3962555U, + 0x574b1cb1U, 0xd42bff32U, 0x2f2d02c9U, 0x5884dcbeU, + 0x41da9ba7U, 0x2b2803cdU, 0xac4de14aU, 0x8860e86eU, + 0xe417f302U, 0x97bb2c71U, 0xb6d36550U, 0x55cb9eb3U, + 0x66375180U, 0xc830f82eU, 0x6a38528cU, 0x63721185U, + 0x119e8ff7U, 0xb2d66454U, 0x846feb62U, 0xc2ba7824U, + 0x9934ad7fU, 0x024a48e4U, 0x449fdba2U, 0xf146b717U, + 0x947bef72U, 0xcab07a2cU, 0x0cc5c9eaU, 0x8920a96fU, + 0x2e6d43c8U, 0x5e015fb8U, 0x953bae73U, 0x508edeb6U, + 0x3f380789U, 0x26664090U, 0xc3fb3875U, 0x9fb02f29U, + 0x574a1de1U, 0xe3d33055U, 0x907fef26U, 0xbadd670cU, + 0x3cf8c48aU, 0xbed86608U, 0x34f2c682U, 0x6f7c13d9U, + 0xc43efa72U, 0x8ba12a3dU, 0xd42afe62U, 0x70a7d7c6U, + 0xc831f97eU, 0xf94db44fU, 0x0e444ab8U, 0xbd18a50bU, + 0xcc34f87aU, 0x9ef06e28U, 0x74a2d6c2U, 0x6b7912ddU, + 0xceb47a78U, 0x75e297c3U, 0x28e9c19eU, 0xfc08f44aU, + 0x41db9af7U, 0x7e2856c8U, 0x7ca8d4caU, 0x024b49b4U, + 0x165a4ca0U, 0x6dfc91dbU, 0x25a68393U, 0xb7922501U, + 0x22634194U, 0xdbe53e6dU, 0x064e48b0U, 0x8d24a93bU, + 0xa849e11eU, 0x35b28783U, 0x4891d9feU, 0x69f990dfU, + 0xd3ef3c65U, 0x5b451eedU, 0xd6aa7c60U, 0xed5cb15bU, + 0xf7c23541U, 0xaac9631cU, 0x14dacea2U, 0xc2bb7974U, + 0x435b18f5U, 0x449edaf2U, 0xc7fe3971U, 0x32774584U, + 0x663650d0U, 0x1b150eadU, 0x36724480U, 0x8fa42b39U, + 0xb117a607U, 0x5a055fecU, 0x9875ed2eU, 0xfe887648U, + 0x79ed94cfU, 0x78add5ceU, 0xfa8d774cU, 0x97ba2d21U, + 0xab89221dU, 0xa909a01fU, 0x38fdc58eU, 0x8ee46a38U, + 0x6a3953dcU, 0x018b8ab7U, 0x947aee22U, 0x00cbcbb6U, + 0xffc83749U, 0x722755c4U, 0x59c59cefU, 0xc6be7870U, + 0xc57ebb73U, 0xc971b87fU, 0x623351d4U, 0xaecc6218U, + 0xa103a217U, 0xf542b743U, 0x0f040bb9U, 0x4a115bfcU, + 0x87ae2931U, 0xcbf13a7dU, 0x5885ddeeU, 0x49d198ffU, + 0xa506a313U, 0x3db8858bU, 0x125f4da4U, 0xb057e706U, + 0x1cd0ccaaU, 0xf402f642U, 0x5c80dceaU, 0x1d908dabU, + 0xe959b05fU, 0x058e8bb3U, 0x23230095U, 0xee9c7258U, + 0xf007f746U, 0xec1cf05aU, 0x953aaf23U, 0x8861e93eU, + 0x60b3d3d6U, 0xe013f356U, 0x852eab33U, 0x7a2d57ccU, + 0x37320581U, 0x64b6d2d2U, 0x7de895cbU, 0x39bd848fU, + 0x1a554facU, 0x2b29029dU, 0xf80df54eU, 0x2dac819bU, + 0x55ca9fe3U, 0xbc58e40aU, 0x6cbcd0daU, 0xfbcd364dU, + 0xe6967050U, 0x776215c1U, 0x475e19f1U, 0x1e504ea8U, + 0xcff43b79U, 0x9af56f2cU, 0x4e145af8U, 0x2f2c0399U, + 0x65f693d3U, 0x7b6d16cdU, 0x846eea32U, 0xb2d76504U, + 0xea99735cU, 0xbb9d260dU, 0xaf8c2319U, 0x5f401fe9U, + 0x83ab2835U, 0xe153b257U, 0x30f7c786U, 0xe2937154U, + 0xe7d63151U, 0xdea07e68U, 0x119f8ea7U, 0xf6827440U, + 0x0a414bbcU, 0xb452e602U, 0x0cc4c8baU, 0x31b78687U, + 0xd2af7d64U, 0x2a69439cU, 0xac4ce01aU, 0xa446e212U, + 0xb3972405U, 0x560a5ce0U, 0xa2c36114U, 0xebd9325dU, + 0x10dfcfa6U, 0xbf982709U, 0xefdc3359U, 0xdc20fc6aU, + 0x6e3c52d8U, 0xfd48b54bU, 0x4f541bf9U, 0xe556b353U, + 0x677611d1U, 0xc03bfb76U, 0xe819f15eU, 0xcab17b7cU, + 0x508fdfe6U, 0x29a9809fU, 0x5dc09debU, 0xd965bc6fU, + 0x33370485U, 0x0b010abdU, 0xb85de50eU, 0x71e796c7U, + 0x1f100fa9U, 0x93bf2c25U, 0x5e005ee8U, 0xd825fd6eU, + 0x68b9d1deU, 0x9bb52e2dU, 0xcd74b97bU, 0xad0ca11bU, + 0xd16fbe67U, 0xd56abf63U, 0x098188bfU, 0x21a38297U, + 0x520f5de4U, 0x08c1c9beU, 0xdaa57f6cU, 0x2e6c4298U, + 0x8ae16b3cU, 0x131f0ca5U, 0x96fa6c20U, 0x9935ac2fU, + 0x20e3c396U, 0x030b08b5U, 0x159a8fa3U, 0x61f392d7U, + 0x18d5cdaeU, 0x24e6c292U, 0x0d8489bbU, 0x070e09b1U, + 0x4c94d8faU, 0x637310d5U, 0xa043e316U, 0x461e58f0U, + 0xf2877544U, 0x534f1ce5U, 0x8921a83fU, 0x92ff6d24U, + 0xd02fff66U, 0xb512a703U, 0x27260191U, 0x2cecc09aU, + 0x86ee6830U, 0xf3c73445U, 0xb6d26400U, 0xa6c66010U, + 0x421b59f4U, 0xc17bba77U, 0x3a7d478cU, 0x4dd499fbU, + 0x548adee2U, 0x3e784688U, 0xb91da40fU, 0x9d30ad2bU, + 0xf147b647U, 0x82eb6934U, 0xa3832015U, 0x409bdbf6U, + 0x736714c5U, 0xdd60bd6bU, 0x7f6817c9U, 0x762254c0U, + 0x04cecab2U, 0xa7862111U, 0x913fae27U, 0xd7ea3d61U, + 0x8c64e83aU, 0x171a0da1U, 0x51cf9ee7U, 0xe416f252U, + 0x812baa37U, 0xdfe03f69U, 0x19958cafU, 0x9c70ec2aU, + 0x3b3d068dU, 0x4b511afdU, 0x806beb36U, 0x45de9bf3U, + 0x2b3c1799U, 0x32625080U, 0xd7ff2865U, 0x8bb43f39U, + 0x434e0df1U, 0xf7d72045U, 0x847bff36U, 0xaed9771cU, + 0x28fcd49aU, 0xaadc7618U, 0x20f6d692U, 0x7b7803c9U, + 0xd03aea62U, 0x9fa53a2dU, 0xc02eee72U, 0x64a3c7d6U, + 0xdc35e96eU, 0xed49a45fU, 0x1a405aa8U, 0xa91cb51bU, + 0xd830e86aU, 0x8af47e38U, 0x60a6c6d2U, 0x7f7d02cdU, + 0xdab06a68U, 0x61e687d3U, 0x3cedd18eU, 0xe80ce45aU, + 0x55df8ae7U, 0x6a2c46d8U, 0x68acc4daU, 0x164f59a4U, + 0x025e5cb0U, 0x79f881cbU, 0x31a29383U, 0xa3963511U, + 0x36675184U, 0xcfe12e7dU, 0x124a58a0U, 0x9920b92bU, + 0xbc4df10eU, 0x21b69793U, 0x5c95c9eeU, 0x7dfd80cfU, + 0xc7eb2c75U, 0x4f410efdU, 0xc2ae6c70U, 0xf958a14bU, + 0xe3c62551U, 0xbecd730cU, 0x00dedeb2U, 0xd6bf6964U, + 0x575f08e5U, 0x509acae2U, 0xd3fa2961U, 0x26735594U, + 0x723240c0U, 0x0f111ebdU, 0x22765490U, 0x9ba03b29U, + 0xa513b617U, 0x4e014ffcU, 0x8c71fd3eU, 0xea8c6658U, + 0x6de984dfU, 0x6ca9c5deU, 0xee89675cU, 0x83be3d31U, + 0xbf8d320dU, 0xbd0db00fU, 0x2cf9d59eU, 0x9ae07a28U, + 0x7e3d43ccU, 0x158f9aa7U, 0x807efe32U, 0x14cfdba6U, + 0xebcc2759U, 0x662345d4U, 0x4dc18cffU, 0xd2ba6860U, + 0xd17aab63U, 0xdd75a86fU, 0x763741c4U, 0xbac87208U, + 0xb507b207U, 0xe146a753U, 0x1b001ba9U, 0x5e154becU, + 0x93aa3921U, 0xdff52a6dU, 0x4c81cdfeU, 0x5dd588efU, + 0xb102b303U, 0x29bc959bU, 0x065b5db4U, 0xa453f716U, + 0x08d4dcbaU, 0xe006e652U, 0x4884ccfaU, 0x09949dbbU, + 0xfd5da04fU, 0x118a9ba3U, 0x37271085U, 0xfa986248U, + 0xe403e756U, 0xf818e04aU, 0x813ebf33U, 0x9c65f92eU, + 0x74b7c3c6U, 0xf417e346U, 0x912abb23U, 0x6e2947dcU, + 0x23361591U, 0x70b2c2c2U, 0x69ec85dbU, 0x2db9949fU, + 0x0e515fbcU, 0x3f2d128dU, 0xec09e55eU, 0x39a8918bU, + 0x41ce8ff3U, 0xa85cf41aU, 0x78b8c0caU, 0xefc9265dU, + 0xf2926040U, 0x636605d1U, 0x535a09e1U, 0x0a545eb8U, + 0xdbf02b69U, 0x8ef17f3cU, 0x5a104ae8U, 0x3b281389U, + 0x71f283c3U, 0x6f6906ddU, 0x906afa22U, 0xa6d37514U, + 0xfe9d634cU, 0xaf99361dU, 0xbb883309U, 0x4b440ff9U, + 0x97af3825U, 0xf557a247U, 0x24f3d796U, 0xf6976144U, + 0xf3d22141U, 0xcaa46e78U, 0x059b9eb7U, 0xe2866450U, + 0x1e455bacU, 0xa056f612U, 0x18c0d8aaU, 0x25b39697U, + 0xc6ab6d74U, 0x3e6d538cU, 0xb848f00aU, 0xb042f202U, + 0xa7933415U, 0x420e4cf0U, 0xb6c77104U, 0xffdd224dU, + 0x04dbdfb6U, 0xab9c3719U, 0xfbd82349U, 0xc824ec7aU, + 0x7a3842c8U, 0xe94ca55bU, 0x5b500be9U, 0xf152a343U, + 0x737201c1U, 0xd43feb66U, 0xfc1de14eU, 0xdeb56b6cU, + 0x448bcff6U, 0x3dad908fU, 0x49c48dfbU, 0xcd61ac7fU, + 0x27331495U, 0x1f051aadU, 0xac59f51eU, 0x65e386d7U, + 0x0b141fb9U, 0x87bb3c35U, 0x4a044ef8U, 0xcc21ed7eU, + 0x7cbdc1ceU, 0x8fb13e3dU, 0xd970a96bU, 0xb908b10bU, + 0xc56bae77U, 0xc16eaf73U, 0x1d8598afU, 0x35a79287U, + 0x460b4df4U, 0x1cc5d9aeU, 0xcea16f7cU, 0x3a685288U, + 0x9ee57b2cU, 0x071b1cb5U, 0x82fe7c30U, 0x8d31bc3fU, + 0x34e7d386U, 0x170f18a5U, 0x019e9fb3U, 0x75f782c7U, + 0x0cd1ddbeU, 0x30e2d282U, 0x198099abU, 0x130a19a1U, + 0x5890c8eaU, 0x777700c5U, 0xb447f306U, 0x521a48e0U, + 0xe6836554U, 0x474b0cf5U, 0x9d25b82fU, 0x86fb7d34U, + 0xc42bef76U, 0xa116b713U, 0x33221181U, 0x38e8d08aU, + 0x92ea7820U, 0xe7c32455U, 0xa2d67410U, 0xb2c27000U, + 0x561f49e4U, 0xd57faa67U, 0x2e79579cU, 0x59d089ebU, + 0x408ecef2U, 0x2a7c5698U, 0xad19b41fU, 0x8934bd3bU, + 0xe543a657U, 0x96ef7924U, 0xb7873005U, 0x549fcbe6U, + 0x676304d5U, 0xc964ad7bU, 0x6b6c07d9U, 0x622644d0U, + 0x10cadaa2U, 0xb3823101U, 0x853bbe37U, 0xc3ee2d71U, + 0x9860f82aU, 0x031e1db1U, 0x45cb8ef7U, 0xf012e242U, + 0x952fba27U, 0xcbe42f79U, 0x0d919cbfU, 0x8874fc3aU, + 0x2f39169dU, 0x5f550aedU, 0x946ffb26U, 0x51da8be3U, + 0xf605f37dU, 0xef5bb464U, 0x0ac6cc81U, 0x568ddbddU, + 0x9e77e915U, 0x2aeec4a1U, 0x59421bd2U, 0x73e093f8U, + 0xf5c5307eU, 0x77e592fcU, 0xfdcf3276U, 0xa641e72dU, + 0x0d030e86U, 0x429cdec9U, 0x1d170a96U, 0xb99a2332U, + 0x010c0d8aU, 0x307040bbU, 0xc779be4cU, 0x742551ffU, + 0x05090c8eU, 0x57cd9adcU, 0xbd9f2236U, 0xa244e629U, + 0x07898e8cU, 0xbcdf6337U, 0xe1d4356aU, 0x353500beU, + 0x88e66e03U, 0xb715a23cU, 0xb595203eU, 0xcb76bd40U, + 0xdf67b854U, 0xa4c1652fU, 0xec9b7767U, 0x7eafd1f5U, + 0xeb5eb560U, 0x12d8ca99U, 0xcf73bc44U, 0x44195dcfU, + 0x617415eaU, 0xfc8f7377U, 0x81ac2d0aU, 0xa0c4642bU, + 0x1ad2c891U, 0x9278ea19U, 0x1f978894U, 0x246145afU, + 0x3effc1b5U, 0x63f497e8U, 0xdde73a56U, 0x0b868d80U, + 0x8a66ec01U, 0x8da32e06U, 0x0ec3cd85U, 0xfb4ab170U, + 0xaf0ba424U, 0xd228fa59U, 0xff4fb074U, 0x4699dfcdU, + 0x782a52f3U, 0x9338ab18U, 0x514819daU, 0x37b582bcU, + 0xb0d0603bU, 0xb190213aU, 0x33b083b8U, 0x5e87d9d5U, + 0x62b4d6e9U, 0x603454ebU, 0xf1c0317aU, 0x47d99eccU, + 0xa304a728U, 0xc8b67e43U, 0x5d471ad6U, 0xc9f63f42U, + 0x36f5c3bdU, 0xbb1aa130U, 0x90f8681bU, 0x0f838c84U, + 0x0c434f87U, 0x004c4c8bU, 0xab0ea520U, 0x67f196ecU, + 0x683e56e3U, 0x3c7f43b7U, 0xc639ff4dU, 0x832caf08U, + 0x4e93ddc5U, 0x02ccce89U, 0x91b8291aU, 0x80ec6c0bU, + 0x6c3b57e7U, 0xf485717fU, 0xdb62b950U, 0x796a13f2U, + 0xd5ed385eU, 0x3d3f02b6U, 0x95bd281eU, 0xd4ad795fU, + 0x206444abU, 0xccb37f47U, 0xea1ef461U, 0x27a186acU, + 0x393a03b2U, 0x252104aeU, 0x5c075bd7U, 0x415c1dcaU, + 0xa98e2722U, 0x292e07a2U, 0x4c135fc7U, 0xb310a338U, + 0xfe0ff175U, 0xad8b2626U, 0xb4d5613fU, 0xf080707bU, + 0xd368bb58U, 0xe214f669U, 0x313001baU, 0xe491756fU, + 0x9cf76b17U, 0x756510feU, 0xa581242eU, 0x32f0c2b9U, + 0x2fab84a4U, 0xbe5fe135U, 0x8e63ed05U, 0xd76dba5cU, + 0x06c9cf8dU, 0x53c89bd8U, 0x8729ae0cU, 0xe611f76dU, + 0xaccb6727U, 0xb250e239U, 0x4d531ec6U, 0x7bea91f0U, + 0x23a487a8U, 0x72a0d2f9U, 0x66b1d7edU, 0x967deb1dU, + 0x4a96dcc1U, 0x286e46a3U, 0xf9ca3372U, 0x2bae85a0U, + 0x2eebc5a5U, 0x179d8a9cU, 0xd8a27a53U, 0x3fbf80b4U, + 0xc37cbf48U, 0x7d6f12f6U, 0xc5f93c4eU, 0xf88a7273U, + 0x1b928990U, 0xe354b768U, 0x657114eeU, 0x6d7b16e6U, + 0x7aaad0f1U, 0x9f37a814U, 0x6bfe95e0U, 0x22e4c6a9U, + 0xd9e23b52U, 0x76a5d3fdU, 0x26e1c7adU, 0x151d089eU, + 0xa701a62cU, 0x347541bfU, 0x8669ef0dU, 0x2c6b47a7U, + 0xae4be525U, 0x09060f82U, 0x212405aaU, 0x038c8f88U, + 0x99b22b12U, 0xe094746bU, 0x94fd691fU, 0x1058489bU, + 0xfa0af071U, 0xc23cfe49U, 0x716011faU, 0xb8da6233U, + 0xd62dfb5dU, 0x5a82d8d1U, 0x973daa1cU, 0x1118099aU, + 0xa184252aU, 0x5288dad9U, 0x04494d8fU, 0x643155efU, + 0x18524a93U, 0x1c574b97U, 0xc0bc7c4bU, 0xe89e7663U, + 0x9b32a910U, 0xc1fc3d4aU, 0x13988b98U, 0xe751b66cU, + 0x43dc9fc8U, 0xda22f851U, 0x5fc798d4U, 0x500858dbU, + 0xe9de3762U, 0xca36fc41U, 0xdca77b57U, 0xa8ce6623U, + 0xd1e8395aU, 0xeddb3666U, 0xc4b97d4fU, 0xce33fd45U, + 0x85a92c0eU, 0xaa4ee421U, 0x697e17e2U, 0x8f23ac04U, + 0x3bba81b0U, 0x9a72e811U, 0x401c5ccbU, 0x5bc299d0U, + 0x19120b92U, 0x7c2f53f7U, 0xee1bf565U, 0xe5d1346eU, + 0x4fd39cc4U, 0x3afac0b1U, 0x7fef90f4U, 0x6ffb94e4U, + 0x8b26ad00U, 0x08464e83U, 0xf340b378U, 0x84e96d0fU, + 0x9db72a16U, 0xf745b27cU, 0x702050fbU, 0x540d59dfU, + 0x387a42b3U, 0x4bd69dc0U, 0x6abed4e1U, 0x89a62f02U, + 0xba5ae031U, 0x145d499fU, 0xb655e33dU, 0xbf1fa034U, + 0xcdf33e46U, 0x6ebbd5e5U, 0x58025ad3U, 0x1ed7c995U, + 0x45591cceU, 0xde27f955U, 0x98f26a13U, 0x2d2b06a6U, + 0x48165ec3U, 0x16ddcb9dU, 0xd0a8785bU, 0x554d18deU, + 0xf200f279U, 0x826cee09U, 0x49561fc2U, 0x8ce36f07U, + 0x96e670feU, 0x8fb837e7U, 0x6a254f02U, 0x366e585eU, + 0xfe946a96U, 0x4a0d4722U, 0x39a19851U, 0x1303107bU, + 0x9526b3fdU, 0x1706117fU, 0x9d2cb1f5U, 0xc6a264aeU, + 0x6de08d05U, 0x227f5d4aU, 0x7df48915U, 0xd979a0b1U, + 0x61ef8e09U, 0x5093c338U, 0xa79a3dcfU, 0x14c6d27cU, + 0x65ea8f0dU, 0x372e195fU, 0xdd7ca1b5U, 0xc2a765aaU, + 0x676a0d0fU, 0xdc3ce0b4U, 0x8137b6e9U, 0x55d6833dU, + 0xe805ed80U, 0xd7f621bfU, 0xd576a3bdU, 0xab953ec3U, + 0xbf843bd7U, 0xc422e6acU, 0x8c78f4e4U, 0x1e4c5276U, + 0x8bbd36e3U, 0x723b491aU, 0xaf903fc7U, 0x24fade4cU, + 0x01979669U, 0x9c6cf0f4U, 0xe14fae89U, 0xc027e7a8U, + 0x7a314b12U, 0xf29b699aU, 0x7f740b17U, 0x4482c62cU, + 0x5e1c4236U, 0x0317146bU, 0xbd04b9d5U, 0x6b650e03U, + 0xea856f82U, 0xed40ad85U, 0x6e204e06U, 0x9ba932f3U, + 0xcfe827a7U, 0xb2cb79daU, 0x9fac33f7U, 0x267a5c4eU, + 0x18c9d170U, 0xf3db289bU, 0x31ab9a59U, 0x5756013fU, + 0xd033e3b8U, 0xd173a2b9U, 0x5353003bU, 0x3e645a56U, + 0x0257556aU, 0x00d7d768U, 0x9123b2f9U, 0x273a1d4fU, + 0xc3e724abU, 0xa855fdc0U, 0x3da49955U, 0xa915bcc1U, + 0x5616403eU, 0xdbf922b3U, 0xf01beb98U, 0x6f600f07U, + 0x6ca0cc04U, 0x60afcf08U, 0xcbed26a3U, 0x0712156fU, + 0x08ddd560U, 0x5c9cc034U, 0xa6da7cceU, 0xe3cf2c8bU, + 0x2e705e46U, 0x622f4d0aU, 0xf15baa99U, 0xe00fef88U, + 0x0cd8d464U, 0x9466f2fcU, 0xbb813ad3U, 0x19899071U, + 0xb50ebbddU, 0x5ddc8135U, 0xf55eab9dU, 0xb44efadcU, + 0x4087c728U, 0xac50fcc4U, 0x8afd77e2U, 0x4742052fU, + 0x59d98031U, 0x45c2872dU, 0x3ce4d854U, 0x21bf9e49U, + 0xc96da4a1U, 0x49cd8421U, 0x2cf0dc44U, 0xd3f320bbU, + 0x9eec72f6U, 0xcd68a5a5U, 0xd436e2bcU, 0x9063f3f8U, + 0xb38b38dbU, 0x82f775eaU, 0x51d38239U, 0x8472f6ecU, + 0xfc14e894U, 0x1586937dU, 0xc562a7adU, 0x5213413aU, + 0x4f480727U, 0xdebc62b6U, 0xee806e86U, 0xb78e39dfU, + 0x662a4c0eU, 0x332b185bU, 0xe7ca2d8fU, 0x86f274eeU, + 0xcc28e4a4U, 0xd2b361baU, 0x2db09d45U, 0x1b091273U, + 0x4347042bU, 0x1243517aU, 0x0652546eU, 0xf69e689eU, + 0x2a755f42U, 0x488dc520U, 0x9929b0f1U, 0x4b4d0623U, + 0x4e084626U, 0x777e091fU, 0xb841f9d0U, 0x5f5c0337U, + 0xa39f3ccbU, 0x1d8c9175U, 0xa51abfcdU, 0x9869f1f0U, + 0x7b710a13U, 0x83b734ebU, 0x0592976dU, 0x0d989565U, + 0x1a495372U, 0xffd42b97U, 0x0b1d1663U, 0x4207452aU, + 0xb901b8d1U, 0x1646507eU, 0x4602442eU, 0x75fe8b1dU, + 0xc7e225afU, 0x5496c23cU, 0xe68a6c8eU, 0x4c88c424U, + 0xcea866a6U, 0x69e58c01U, 0x41c78629U, 0x636f0c0bU, + 0xf951a891U, 0x8077f7e8U, 0xf41eea9cU, 0x70bbcb18U, + 0x9ae973f2U, 0xa2df7dcaU, 0x11839279U, 0xd839e1b0U, + 0xb6ce78deU, 0x3a615b52U, 0xf7de299fU, 0x71fb8a19U, + 0xc167a6a9U, 0x326b595aU, 0x64aace0cU, 0x04d2d66cU, + 0x78b1c910U, 0x7cb4c814U, 0xa05fffc8U, 0x887df5e0U, + 0xfbd12a93U, 0xa11fbec9U, 0x737b081bU, 0x87b235efU, + 0x233f1c4bU, 0xbac17bd2U, 0x3f241b57U, 0x30ebdb58U, + 0x893db4e1U, 0xaad57fc2U, 0xbc44f8d4U, 0xc82de5a0U, + 0xb10bbad9U, 0x8d38b5e5U, 0xa45afeccU, 0xaed07ec6U, + 0xe54aaf8dU, 0xcaad67a2U, 0x099d9461U, 0xefc02f87U, + 0x5b590233U, 0xfa916b92U, 0x20ffdf48U, 0x3b211a53U, + 0x79f18811U, 0x1cccd074U, 0x8ef876e6U, 0x8532b7edU, + 0x2f301f47U, 0x5a194332U, 0x1f0c1377U, 0x0f181767U, + 0xebc52e83U, 0x68a5cd00U, 0x93a330fbU, 0xe40aee8cU, + 0xfd54a995U, 0x97a631ffU, 0x10c3d378U, 0x34eeda5cU, + 0x5899c130U, 0x2b351e43U, 0x0a5d5762U, 0xe945ac81U, + 0xdab963b2U, 0x74beca1cU, 0xd6b660beU, 0xdffc23b7U, + 0xad10bdc5U, 0x0e585666U, 0x38e1d950U, 0x7e344a16U, + 0x25ba9f4dU, 0xbec47ad6U, 0xf811e990U, 0x4dc88525U, + 0x28f5dd40U, 0x763e481eU, 0xb04bfbd8U, 0x35ae9b5dU, + 0x92e371faU, 0xe28f6d8aU, 0x29b59c41U, 0xec00ec84U, + 0x901b8b05U, 0x8945cc1cU, 0x6cd8b4f9U, 0x3093a3a5U, + 0xf869916dU, 0x4cf0bcd9U, 0x3f5c63aaU, 0x15feeb80U, + 0x93db4806U, 0x11fbea84U, 0x9bd14a0eU, 0xc05f9f55U, + 0x6b1d76feU, 0x2482a6b1U, 0x7b0972eeU, 0xdf845b4aU, + 0x671275f2U, 0x566e38c3U, 0xa167c634U, 0x123b2987U, + 0x631774f6U, 0x31d3e2a4U, 0xdb815a4eU, 0xc45a9e51U, + 0x6197f6f4U, 0xdac11b4fU, 0x87ca4d12U, 0x532b78c6U, + 0xeef8167bU, 0xd10bda44U, 0xd38b5846U, 0xad68c538U, + 0xb979c02cU, 0xc2df1d57U, 0x8a850f1fU, 0x18b1a98dU, + 0x8d40cd18U, 0x74c6b2e1U, 0xa96dc43cU, 0x220725b7U, + 0x076a6d92U, 0x9a910b0fU, 0xe7b25572U, 0xc6da1c53U, + 0x7cccb0e9U, 0xf4669261U, 0x7989f0ecU, 0x427f3dd7U, + 0x58e1b9cdU, 0x05eaef90U, 0xbbf9422eU, 0x6d98f5f8U, + 0xec789479U, 0xebbd567eU, 0x68ddb5fdU, 0x9d54c908U, + 0xc915dc5cU, 0xb4368221U, 0x9951c80cU, 0x2087a7b5U, + 0x1e342a8bU, 0xf526d360U, 0x375661a2U, 0x51abfac4U, + 0xd6ce1843U, 0xd78e5942U, 0x55aefbc0U, 0x3899a1adU, + 0x04aaae91U, 0x062a2c93U, 0x97de4902U, 0x21c7e6b4U, + 0xc51adf50U, 0xaea8063bU, 0x3b5962aeU, 0xafe8473aU, + 0x50ebbbc5U, 0xdd04d948U, 0xf6e61063U, 0x699df4fcU, + 0x6a5d37ffU, 0x665234f3U, 0xcd10dd58U, 0x01efee94U, + 0x0e202e9bU, 0x5a613bcfU, 0xa0278735U, 0xe532d770U, + 0x288da5bdU, 0x64d2b6f1U, 0xf7a65162U, 0xe6f21473U, + 0x0a252f9fU, 0x929b0907U, 0xbd7cc128U, 0x1f746b8aU, + 0xb3f34026U, 0x5b217aceU, 0xf3a35066U, 0xb2b30127U, + 0x467a3cd3U, 0xaaad073fU, 0x8c008c19U, 0x41bffed4U, + 0x5f247bcaU, 0x433f7cd6U, 0x3a1923afU, 0x274265b2U, + 0xcf905f5aU, 0x4f307fdaU, 0x2a0d27bfU, 0xd50edb40U, + 0x9811890dU, 0xcb955e5eU, 0xd2cb1947U, 0x969e0803U, + 0xb576c320U, 0x840a8e11U, 0x572e79c2U, 0x828f0d17U, + 0xfae9136fU, 0x137b6886U, 0xc39f5c56U, 0x54eebac1U, + 0x49b5fcdcU, 0xd841994dU, 0xe87d957dU, 0xb173c224U, + 0x60d7b7f5U, 0x35d6e3a0U, 0xe137d674U, 0x800f8f15U, + 0xcad51f5fU, 0xd44e9a41U, 0x2b4d66beU, 0x1df4e988U, + 0x45baffd0U, 0x14beaa81U, 0x00afaf95U, 0xf0639365U, + 0x2c88a4b9U, 0x4e703edbU, 0x9fd44b0aU, 0x4db0fdd8U, + 0x48f5bdddU, 0x7183f2e4U, 0xbebc022bU, 0x59a1f8ccU, + 0xa562c730U, 0x1b716a8eU, 0xa3e74436U, 0x9e940a0bU, + 0x7d8cf1e8U, 0x854acf10U, 0x036f6c96U, 0x0b656e9eU, + 0x1cb4a889U, 0xf929d06cU, 0x0de0ed98U, 0x44fabed1U, + 0xbffc432aU, 0x10bbab85U, 0x40ffbfd5U, 0x730370e6U, + 0xc11fde54U, 0x526b39c7U, 0xe0779775U, 0x4a753fdfU, + 0xc8559d5dU, 0x6f1877faU, 0x473a7dd2U, 0x6592f7f0U, + 0xffac536aU, 0x868a0c13U, 0xf2e31167U, 0x764630e3U, + 0x9c148809U, 0xa4228631U, 0x177e6982U, 0xdec41a4bU, + 0xb0338325U, 0x3c9ca0a9U, 0xf123d264U, 0x770671e2U, + 0xc79a5d52U, 0x3496a2a1U, 0x625735f7U, 0x022f2d97U, + 0x7e4c32ebU, 0x7a4933efU, 0xa6a20433U, 0x8e800e1bU, + 0xfd2cd168U, 0xa7e24532U, 0x7586f3e0U, 0x814fce14U, + 0x25c2e7b0U, 0xbc3c8029U, 0x39d9e0acU, 0x361620a3U, + 0x8fc04f1aU, 0xac288439U, 0xbab9032fU, 0xced01e5bU, + 0xb7f64122U, 0x8bc54e1eU, 0xa2a70537U, 0xa82d853dU, + 0xe3b75476U, 0xcc509c59U, 0x0f606f9aU, 0xe93dd47cU, + 0x5da4f9c8U, 0xfc6c9069U, 0x260224b3U, 0x3ddce1a8U, + 0x7f0c73eaU, 0x1a312b8fU, 0x88058d1dU, 0x83cf4c16U, + 0x29cde4bcU, 0x5ce4b8c9U, 0x19f1e88cU, 0x09e5ec9cU, + 0xed38d578U, 0x6e5836fbU, 0x955ecb00U, 0xe2f71577U, + 0xfba9526eU, 0x915bca04U, 0x163e2883U, 0x321321a7U, + 0x5e643acbU, 0x2dc8e5b8U, 0x0ca0ac99U, 0xefb8577aU, + 0xdc449849U, 0x724331e7U, 0xd04b9b45U, 0xd901d84cU, + 0xabed463eU, 0x08a5ad9dU, 0x3e1c22abU, 0x78c9b1edU, + 0x234764b6U, 0xb839812dU, 0xfeec126bU, 0x4b357edeU, + 0x2e0826bbU, 0x70c3b3e5U, 0xb6b60023U, 0x335360a6U, + 0x941e8a01U, 0xe4729671U, 0x2f4867baU, 0xeafd177fU, + 0x39c5fc72U, 0x209bbb6bU, 0xc506c38eU, 0x994dd4d2U, + 0x51b7e61aU, 0xe52ecbaeU, 0x968214ddU, 0xbc209cf7U, + 0x3a053f71U, 0xb8259df3U, 0x320f3d79U, 0x6981e822U, + 0xc2c30189U, 0x8d5cd1c6U, 0xd2d70599U, 0x765a2c3dU, + 0xcecc0285U, 0xffb04fb4U, 0x08b9b143U, 0xbbe55ef0U, + 0xcac90381U, 0x980d95d3U, 0x725f2d39U, 0x6d84e926U, + 0xc8498183U, 0x731f6c38U, 0x2e143a65U, 0xfaf50fb1U, + 0x4726610cU, 0x78d5ad33U, 0x7a552f31U, 0x04b6b24fU, + 0x10a7b75bU, 0x6b016a20U, 0x235b7868U, 0xb16fdefaU, + 0x249eba6fU, 0xdd18c596U, 0x00b3b34bU, 0x8bd952c0U, + 0xaeb41ae5U, 0x334f7c78U, 0x4e6c2205U, 0x6f046b24U, + 0xd512c79eU, 0x5db8e516U, 0xd057879bU, 0xeba14aa0U, + 0xf13fcebaU, 0xac3498e7U, 0x12273559U, 0xc446828fU, + 0x45a6e30eU, 0x42632109U, 0xc103c28aU, 0x348abe7fU, + 0x60cbab2bU, 0x1de8f556U, 0x308fbf7bU, 0x8959d0c2U, + 0xb7ea5dfcU, 0x5cf8a417U, 0x9e8816d5U, 0xf8758db3U, + 0x7f106f34U, 0x7e502e35U, 0xfc708cb7U, 0x9147d6daU, + 0xad74d9e6U, 0xaff45be4U, 0x3e003e75U, 0x881991c3U, + 0x6cc4a827U, 0x0776714cU, 0x928715d9U, 0x0636304dU, + 0xf935ccb2U, 0x74daae3fU, 0x5f386714U, 0xc043838bU, + 0xc3834088U, 0xcf8c4384U, 0x64ceaa2fU, 0xa83199e3U, + 0xa7fe59ecU, 0xf3bf4cb8U, 0x09f9f042U, 0x4ceca007U, + 0x8153d2caU, 0xcd0cc186U, 0x5e782615U, 0x4f2c6304U, + 0xa3fb58e8U, 0x3b457e70U, 0x14a2b65fU, 0xb6aa1cfdU, + 0x1a2d3751U, 0xf2ff0db9U, 0x5a7d2711U, 0x1b6d7650U, + 0xefa44ba4U, 0x03737048U, 0x25defb6eU, 0xe86189a3U, + 0xf6fa0cbdU, 0xeae10ba1U, 0x93c754d8U, 0x8e9c12c5U, + 0x664e282dU, 0xe6ee08adU, 0x83d350c8U, 0x7cd0ac37U, + 0x31cffe7aU, 0x624b2929U, 0x7b156e30U, 0x3f407f74U, + 0x1ca8b457U, 0x2dd4f966U, 0xfef00eb5U, 0x2b517a60U, + 0x53376418U, 0xbaa51ff1U, 0x6a412b21U, 0xfd30cdb6U, + 0xe06b8babU, 0x719fee3aU, 0x41a3e20aU, 0x18adb553U, + 0xc909c082U, 0x9c0894d7U, 0x48e9a103U, 0x29d1f862U, + 0x630b6828U, 0x7d90ed36U, 0x829311c9U, 0xb42a9effU, + 0xec6488a7U, 0xbd60ddf6U, 0xa971d8e2U, 0x59bde412U, + 0x8556d3ceU, 0xe7ae49acU, 0x360a3c7dU, 0xe46e8aafU, + 0xe12bcaaaU, 0xd85d8593U, 0x1762755cU, 0xf07f8fbbU, + 0x0cbcb047U, 0xb2af1df9U, 0x0a393341U, 0x374a7d7cU, + 0xd452869fU, 0x2c94b867U, 0xaab11be1U, 0xa2bb19e9U, + 0xb56adffeU, 0x50f7a71bU, 0xa43e9aefU, 0xed24c9a6U, + 0x1622345dU, 0xb965dcf2U, 0xe921c8a2U, 0xdadd0791U, + 0x68c1a923U, 0xfbb54eb0U, 0x49a9e002U, 0xe3ab48a8U, + 0x618bea2aU, 0xc6c6008dU, 0xeee40aa5U, 0xcc4c8087U, + 0x5672241dU, 0x2f547b64U, 0x5b3d6610U, 0xdf984794U, + 0x35caff7eU, 0x0dfcf146U, 0xbea01ef5U, 0x771a6d3cU, + 0x19edf452U, 0x9542d7deU, 0x58fda513U, 0xded80695U, + 0x6e442a25U, 0x9d48d5d6U, 0xcb894280U, 0xabf15ae0U, + 0xd792459cU, 0xd3974498U, 0x0f7c7344U, 0x275e796cU, + 0x54f2a61fU, 0x0e3c3245U, 0xdc588497U, 0x2891b963U, + 0x8c1c90c7U, 0x15e2f75eU, 0x900797dbU, 0x9fc857d4U, + 0x261e386dU, 0x05f6f34eU, 0x13677458U, 0x670e692cU, + 0x1e283655U, 0x221b3969U, 0x0b797240U, 0x01f3f24aU, + 0x4a692301U, 0x658eeb2eU, 0xa6be18edU, 0x40e3a30bU, + 0xf47a8ebfU, 0x55b2e71eU, 0x8fdc53c4U, 0x940296dfU, + 0xd6d2049dU, 0xb3ef5cf8U, 0x21dbfa6aU, 0x2a113b61U, + 0x801393cbU, 0xf53acfbeU, 0xb02f9ffbU, 0xa03b9bebU, + 0x44e6a20fU, 0xc786418cU, 0x3c80bc77U, 0x4b296200U, + 0x52772519U, 0x3885bd73U, 0xbfe05ff4U, 0x9bcd56d0U, + 0xf7ba4dbcU, 0x841692cfU, 0xa57edbeeU, 0x4666200dU, + 0x759aef3eU, 0xdb9d4690U, 0x7995ec32U, 0x70dfaf3bU, + 0x02333149U, 0xa17bdaeaU, 0x97c255dcU, 0xd117c69aU, + 0x8a9913c1U, 0x11e7f65aU, 0x5732651cU, 0xe2eb09a9U, + 0x87d651ccU, 0xd91dc492U, 0x1f687754U, 0x9a8d17d1U, + 0x3dc0fd76U, 0x4dace106U, 0x869610cdU, 0x43236008U, + 0x6782e56bU, 0x7edca272U, 0x9b41da97U, 0xc70acdcbU, + 0x0ff0ff03U, 0xbb69d2b7U, 0xc8c50dc4U, 0xe26785eeU, + 0x64422668U, 0xe66284eaU, 0x6c482460U, 0x37c6f13bU, + 0x9c841890U, 0xd31bc8dfU, 0x8c901c80U, 0x281d3524U, + 0x908b1b9cU, 0xa1f756adU, 0x56fea85aU, 0xe5a247e9U, + 0x948e1a98U, 0xc64a8ccaU, 0x2c183420U, 0x33c3f03fU, + 0x960e989aU, 0x2d587521U, 0x7053237cU, 0xa4b216a8U, + 0x19617815U, 0x2692b42aU, 0x24123628U, 0x5af1ab56U, + 0x4ee0ae42U, 0x35467339U, 0x7d1c6171U, 0xef28c7e3U, + 0x7ad9a376U, 0x835fdc8fU, 0x5ef4aa52U, 0xd59e4bd9U, + 0xf0f303fcU, 0x6d086561U, 0x102b3b1cU, 0x3143723dU, + 0x8b55de87U, 0x03fffc0fU, 0x8e109e82U, 0xb5e653b9U, + 0xaf78d7a3U, 0xf27381feU, 0x4c602c40U, 0x9a019b96U, + 0x1be1fa17U, 0x1c243810U, 0x9f44db93U, 0x6acda766U, + 0x3e8cb232U, 0x43afec4fU, 0x6ec8a662U, 0xd71ec9dbU, + 0xe9ad44e5U, 0x02bfbd0eU, 0xc0cf0fccU, 0xa63294aaU, + 0x2157762dU, 0x2017372cU, 0xa23795aeU, 0xcf00cfc3U, + 0xf333c0ffU, 0xf1b342fdU, 0x6047276cU, 0xd65e88daU, + 0x3283b13eU, 0x59316855U, 0xccc00cc0U, 0x58712954U, + 0xa772d5abU, 0x2a9db726U, 0x017f7e0dU, 0x9e049a92U, + 0x9dc45991U, 0x91cb5a9dU, 0x3a89b336U, 0xf67680faU, + 0xf9b940f5U, 0xadf855a1U, 0x57bee95bU, 0x12abb91eU, + 0xdf14cbd3U, 0x934bd89fU, 0x003f3f0cU, 0x116b7a1dU, + 0xfdbc41f1U, 0x65026769U, 0x4ae5af46U, 0xe8ed05e4U, + 0x446a2e48U, 0xacb814a0U, 0x043a3e08U, 0x452a6f49U, + 0xb1e352bdU, 0x5d346951U, 0x7b99e277U, 0xb62690baU, + 0xa8bd15a4U, 0xb4a612b8U, 0xcd804dc1U, 0xd0db0bdcU, + 0x38093134U, 0xb8a911b4U, 0xdd9449d1U, 0x2297b52eU, + 0x6f88e763U, 0x3c0c3030U, 0x25527729U, 0x6107666dU, + 0x42efad4eU, 0x7393e07fU, 0xa0b717acU, 0x75166379U, + 0x0d707d01U, 0xe4e206e8U, 0x34063238U, 0xa377d4afU, + 0xbe2c92b2U, 0x2fd8f723U, 0x1fe4fb13U, 0x46eaac4aU, + 0x974ed99bU, 0xc24f8dceU, 0x16aeb81aU, 0x7796e17bU, + 0x3d4c7131U, 0x23d7f42fU, 0xdcd408d0U, 0xea6d87e6U, + 0xb22391beU, 0xe327c4efU, 0xf736c1fbU, 0x07fafd0bU, + 0xdb11cad7U, 0xb9e950b5U, 0x684d2564U, 0xba2993b6U, + 0xbf6cd3b3U, 0x861a9c8aU, 0x49256c45U, 0xae3896a2U, + 0x52fba95eU, 0xece804e0U, 0x547e2a58U, 0x690d6465U, + 0x8a159f86U, 0x72d3a17eU, 0xf4f602f8U, 0xfcfc00f0U, + 0xeb2dc6e7U, 0x0eb0be02U, 0xfa7983f6U, 0xb363d0bfU, + 0x48652d44U, 0xe722c5ebU, 0xb766d1bbU, 0x849a1e88U, + 0x3686b03aU, 0xa5f257a9U, 0x17eef91bU, 0xbdec51b1U, + 0x3fccf333U, 0x98811994U, 0xb0a313bcU, 0x920b999eU, + 0x08353d04U, 0x7113627dU, 0x057a7f09U, 0x81df5e8dU, + 0x6b8de667U, 0x53bbe85fU, 0xe0e707ecU, 0x295d7425U, + 0x47aaed4bU, 0xcb05cec7U, 0x06babc0aU, 0x809f1f8cU, + 0x3003333cU, 0xc30fcccfU, 0x95ce5b99U, 0xf5b643f9U, + 0x89d55c85U, 0x8dd05d81U, 0x513b6a5dU, 0x79196075U, + 0x0ab5bf06U, 0x507b2b5cU, 0x821f9d8eU, 0x76d6a07aU, + 0xd25b89deU, 0x4ba5ee47U, 0xce408ec2U, 0xc18f4ecdU, + 0x78592174U, 0x5bb1ea57U, 0x4d206d41U, 0x39497035U, + 0x406f2f4cU, 0x7c5c2070U, 0x553e6b59U, 0x5fb4eb53U, + 0x142e3a18U, 0x3bc9f237U, 0xf8f901f4U, 0x1ea4ba12U, + 0xaa3d97a6U, 0x0bf5fe07U, 0xd19b4addU, 0xca458fc6U, + 0x88951d84U, 0xeda845e1U, 0x7f9ce373U, 0x74562278U, + 0xde548ad2U, 0xab7dd6a7U, 0xee6886e2U, 0xfe7c82f2U, + 0x1aa1bb16U, 0x99c15895U, 0x62c7a56eU, 0x156e7b19U, + 0x0c303c00U, 0x66c2a46aU, 0xe1a746edU, 0xc58a4fc9U, + 0xa9fd54a5U, 0xda518bd6U, 0xfb39c2f7U, 0x18213914U, + 0x2bddf627U, 0x85da5f89U, 0x27d2f52bU, 0x2e98b622U, + 0x5c742850U, 0xff3cc3f3U, 0xc9854cc5U, 0x8f50df83U, + 0xd4de0ad8U, 0x4fa0ef43U, 0x09757c05U, 0xbcac10b0U, + 0xd99148d5U, 0x875add8bU, 0x412f6e4dU, 0xc4ca0ec8U, + 0x6387e46fU, 0x13ebf81fU, 0xd8d109d4U, 0x1d647911U, + 0x951a8f01U, 0x8c44c818U, 0x69d9b0fdU, 0x3592a7a1U, + 0xfd689569U, 0x49f1b8ddU, 0x3a5d67aeU, 0x10ffef84U, + 0x96da4c02U, 0x14faee80U, 0x9ed04e0aU, 0xc55e9b51U, + 0x6e1c72faU, 0x2183a2b5U, 0x7e0876eaU, 0xda855f4eU, + 0x621371f6U, 0x536f3cc7U, 0xa466c230U, 0x173a2d83U, + 0x661670f2U, 0x34d2e6a0U, 0xde805e4aU, 0xc15b9a55U, + 0x6496f2f0U, 0xdfc01f4bU, 0x82cb4916U, 0x562a7cc2U, + 0xebf9127fU, 0xd40ade40U, 0xd68a5c42U, 0xa869c13cU, + 0xbc78c428U, 0xc7de1953U, 0x8f840b1bU, 0x1db0ad89U, + 0x8841c91cU, 0x71c7b6e5U, 0xac6cc038U, 0x270621b3U, + 0x026b6996U, 0x9f900f0bU, 0xe2b35176U, 0xc3db1857U, + 0x79cdb4edU, 0xf1679665U, 0x7c88f4e8U, 0x477e39d3U, + 0x5de0bdc9U, 0x00ebeb94U, 0xbef8462aU, 0x6899f1fcU, + 0xe979907dU, 0xeebc527aU, 0x6ddcb1f9U, 0x9855cd0cU, + 0xcc14d858U, 0xb1378625U, 0x9c50cc08U, 0x2586a3b1U, + 0x1b352e8fU, 0xf027d764U, 0x325765a6U, 0x54aafec0U, + 0xd3cf1c47U, 0xd28f5d46U, 0x50afffc4U, 0x3d98a5a9U, + 0x01abaa95U, 0x032b2897U, 0x92df4d06U, 0x24c6e2b0U, + 0xc01bdb54U, 0xaba9023fU, 0x3e5866aaU, 0xaae9433eU, + 0x55eabfc1U, 0xd805dd4cU, 0xf3e71467U, 0x6c9cf0f8U, + 0x6f5c33fbU, 0x635330f7U, 0xc811d95cU, 0x04eeea90U, + 0x0b212a9fU, 0x5f603fcbU, 0xa5268331U, 0xe033d374U, + 0x2d8ca1b9U, 0x61d3b2f5U, 0xf2a75566U, 0xe3f31077U, + 0x0f242b9bU, 0x979a0d03U, 0xb87dc52cU, 0x1a756f8eU, + 0xb6f24422U, 0x5e207ecaU, 0xf6a25462U, 0xb7b20523U, + 0x437b38d7U, 0xafac033bU, 0x8901881dU, 0x44befad0U, + 0x5a257fceU, 0x463e78d2U, 0x3f1827abU, 0x224361b6U, + 0xca915b5eU, 0x4a317bdeU, 0x2f0c23bbU, 0xd00fdf44U, + 0x9d108d09U, 0xce945a5aU, 0xd7ca1d43U, 0x939f0c07U, + 0xb077c724U, 0x810b8a15U, 0x522f7dc6U, 0x878e0913U, + 0xffe8176bU, 0x167a6c82U, 0xc69e5852U, 0x51efbec5U, + 0x4cb4f8d8U, 0xdd409d49U, 0xed7c9179U, 0xb472c620U, + 0x65d6b3f1U, 0x30d7e7a4U, 0xe436d270U, 0x850e8b11U, + 0xcfd41b5bU, 0xd14f9e45U, 0x2e4c62baU, 0x18f5ed8cU, + 0x40bbfbd4U, 0x11bfae85U, 0x05aeab91U, 0xf5629761U, + 0x2989a0bdU, 0x4b713adfU, 0x9ad54f0eU, 0x48b1f9dcU, + 0x4df4b9d9U, 0x7482f6e0U, 0xbbbd062fU, 0x5ca0fcc8U, + 0xa063c334U, 0x1e706e8aU, 0xa6e64032U, 0x9b950e0fU, + 0x788df5ecU, 0x804bcb14U, 0x066e6892U, 0x0e646a9aU, + 0x19b5ac8dU, 0xfc28d468U, 0x08e1e99cU, 0x41fbbad5U, + 0xbafd472eU, 0x15baaf81U, 0x45febbd1U, 0x760274e2U, + 0xc41eda50U, 0x576a3dc3U, 0xe5769371U, 0x4f743bdbU, + 0xcd549959U, 0x6a1973feU, 0x423b79d6U, 0x6093f3f4U, + 0xfaad576eU, 0x838b0817U, 0xf7e21563U, 0x734734e7U, + 0x99158c0dU, 0xa1238235U, 0x127f6d86U, 0xdbc51e4fU, + 0xb5328721U, 0x399da4adU, 0xf422d660U, 0x720775e6U, + 0xc29b5956U, 0x3197a6a5U, 0x675631f3U, 0x072e2993U, + 0x7b4d36efU, 0x7f4837ebU, 0xa3a30037U, 0x8b810a1fU, + 0xf82dd56cU, 0xa2e34136U, 0x7087f7e4U, 0x844eca10U, + 0x20c3e3b4U, 0xb93d842dU, 0x3cd8e4a8U, 0x331724a7U, + 0x8ac14b1eU, 0xa929803dU, 0xbfb8072bU, 0xcbd11a5fU, + 0xb2f74526U, 0x8ec44a1aU, 0xa7a60133U, 0xad2c8139U, + 0xe6b65072U, 0xc951985dU, 0x0a616b9eU, 0xec3cd078U, + 0x58a5fdccU, 0xf96d946dU, 0x230320b7U, 0x38dde5acU, + 0x7a0d77eeU, 0x1f302f8bU, 0x8d048919U, 0x86ce4812U, + 0x2ccce0b8U, 0x59e5bccdU, 0x1cf0ec88U, 0x0ce4e898U, + 0xe839d17cU, 0x6b5932ffU, 0x905fcf04U, 0xe7f61173U, + 0xfea8566aU, 0x945ace00U, 0x133f2c87U, 0x371225a3U, + 0x5b653ecfU, 0x28c9e1bcU, 0x09a1a89dU, 0xeab9537eU, + 0xd9459c4dU, 0x774235e3U, 0xd54a9f41U, 0xdc00dc48U, + 0xaeec423aU, 0x0da4a999U, 0x3b1d26afU, 0x7dc8b5e9U, + 0x264660b2U, 0xbd388529U, 0xfbed166fU, 0x4e347adaU, + 0x2b0922bfU, 0x75c2b7e1U, 0xb3b70427U, 0x365264a2U, + 0x911f8e05U, 0xe1739275U, 0x2a4963beU, 0xeffc137bU, + 0xf0f80886U, 0xe9a64f9fU, 0x0c3b377aU, 0x50702026U, + 0x988a12eeU, 0x2c133f5aU, 0x5fbfe029U, 0x751d6803U, + 0xf338cb85U, 0x71186907U, 0xfb32c98dU, 0xa0bc1cd6U, + 0x0bfef57dU, 0x44612532U, 0x1beaf16dU, 0xbf67d8c9U, + 0x07f1f671U, 0x368dbb40U, 0xc18445b7U, 0x72d8aa04U, + 0x03f4f775U, 0x51306127U, 0xbb62d9cdU, 0xa4b91dd2U, + 0x01747577U, 0xba2298ccU, 0xe729ce91U, 0x33c8fb45U, + 0x8e1b95f8U, 0xb1e859c7U, 0xb368dbc5U, 0xcd8b46bbU, + 0xd99a43afU, 0xa23c9ed4U, 0xea668c9cU, 0x78522a0eU, + 0xeda34e9bU, 0x14253162U, 0xc98e47bfU, 0x42e4a634U, + 0x6789ee11U, 0xfa72888cU, 0x8751d6f1U, 0xa6399fd0U, + 0x1c2f336aU, 0x948511e2U, 0x196a736fU, 0x229cbe54U, + 0x38023a4eU, 0x65096c13U, 0xdb1ac1adU, 0x0d7b767bU, + 0x8c9b17faU, 0x8b5ed5fdU, 0x083e367eU, 0xfdb74a8bU, + 0xa9f65fdfU, 0xd4d501a2U, 0xf9b24b8fU, 0x40642436U, + 0x7ed7a908U, 0x95c550e3U, 0x57b5e221U, 0x31487947U, + 0xb62d9bc0U, 0xb76ddac1U, 0x354d7843U, 0x587a222eU, + 0x64492d12U, 0x66c9af10U, 0xf73dca81U, 0x41246537U, + 0xa5f95cd3U, 0xce4b85b8U, 0x5bbae12dU, 0xcf0bc4b9U, + 0x30083846U, 0xbde75acbU, 0x960593e0U, 0x097e777fU, + 0x0abeb47cU, 0x06b1b770U, 0xadf35edbU, 0x610c6d17U, + 0x6ec3ad18U, 0x3a82b84cU, 0xc0c404b6U, 0x85d154f3U, + 0x486e263eU, 0x04313572U, 0x9745d2e1U, 0x861197f0U, + 0x6ac6ac1cU, 0xf2788a84U, 0xdd9f42abU, 0x7f97e809U, + 0xd310c3a5U, 0x3bc2f94dU, 0x9340d3e5U, 0xd25082a4U, + 0x2699bf50U, 0xca4e84bcU, 0xece30f9aU, 0x215c7d57U, + 0x3fc7f849U, 0x23dcff55U, 0x5afaa02cU, 0x47a1e631U, + 0xaf73dcd9U, 0x2fd3fc59U, 0x4aeea43cU, 0xb5ed58c3U, + 0xf8f20a8eU, 0xab76ddddU, 0xb2289ac4U, 0xf67d8b80U, + 0xd59540a3U, 0xe4e90d92U, 0x37cdfa41U, 0xe26c8e94U, + 0x9a0a90ecU, 0x7398eb05U, 0xa37cdfd5U, 0x340d3942U, + 0x29567f5fU, 0xb8a21aceU, 0x889e16feU, 0xd19041a7U, + 0x00343476U, 0x55356023U, 0x81d455f7U, 0xe0ec0c96U, + 0xaa369cdcU, 0xb4ad19c2U, 0x4baee53dU, 0x7d176a0bU, + 0x25597c53U, 0x745d2902U, 0x604c2c16U, 0x908010e6U, + 0x4c6b273aU, 0x2e93bd58U, 0xff37c889U, 0x2d537e5bU, + 0x28163e5eU, 0x11607167U, 0xde5f81a8U, 0x39427b4fU, + 0xc58144b3U, 0x7b92e90dU, 0xc304c7b5U, 0xfe778988U, + 0x1d6f726bU, 0xe5a94c93U, 0x638cef15U, 0x6b86ed1dU, + 0x7c572b0aU, 0x99ca53efU, 0x6d036e1bU, 0x24193d52U, + 0xdf1fc0a9U, 0x70582806U, 0x201c3c56U, 0x13e0f365U, + 0xa1fc5dd7U, 0x3288ba44U, 0x809414f6U, 0x2a96bc5cU, + 0xa8b61edeU, 0x0ffbf479U, 0x27d9fe51U, 0x05717473U, + 0x9f4fd0e9U, 0xe6698f90U, 0x920092e4U, 0x16a5b360U, + 0xfcf70b8aU, 0xc4c105b2U, 0x779dea01U, 0xbe2799c8U, + 0xd0d000a6U, 0x5c7f232aU, 0x91c051e7U, 0x17e5f261U, + 0xa779ded1U, 0x54752122U, 0x02b4b674U, 0x62ccae14U, + 0x1eafb168U, 0x1aaab06cU, 0xc64187b0U, 0xee638d98U, + 0x9dcf52ebU, 0xc701c6b1U, 0x15657063U, 0xe1ac4d97U, + 0x45216433U, 0xdcdf03aaU, 0x593a632fU, 0x56f5a320U, + 0xef23cc99U, 0xcccb07baU, 0xda5a80acU, 0xae339dd8U, + 0xd715c2a1U, 0xeb26cd9dU, 0xc24486b4U, 0xc8ce06beU, + 0x8354d7f5U, 0xacb31fdaU, 0x6f83ec19U, 0x89de57ffU, + 0x3d477a4bU, 0x9c8f13eaU, 0x46e1a730U, 0x5d3f622bU, + 0x1feff069U, 0x7ad2a80cU, 0xe8e60e9eU, 0xe32ccf95U, + 0x492e673fU, 0x3c073b4aU, 0x79126b0fU, 0x69066f1fU, + 0x8ddb56fbU, 0x0ebbb578U, 0xf5bd4883U, 0x821496f4U, + 0x9b4ad1edU, 0xf1b84987U, 0x76ddab00U, 0x52f0a224U, + 0x3e87b948U, 0x4d2b663bU, 0x6c432f1aU, 0x8f5bd4f9U, + 0xbca71bcaU, 0x12a0b264U, 0xb0a818c6U, 0xb9e25bcfU, + 0xcb0ec5bdU, 0x68462e1eU, 0x5effa128U, 0x182a326eU, + 0x43a4e735U, 0xd8da02aeU, 0x9e0f91e8U, 0x2bd6fd5dU, + 0x4eeba538U, 0x10203066U, 0xd65583a0U, 0x53b0e325U, + 0xf4fd0982U, 0x849115f2U, 0x4fabe439U, 0x8a1e94fcU, + 0xddf12ca2U, 0xc4af6bbbU, 0x2132135eU, 0x7d790402U, + 0xb58336caU, 0x011a1b7eU, 0x72b6c40dU, 0x58144c27U, + 0xde31efa1U, 0x5c114d23U, 0xd63beda9U, 0x8db538f2U, + 0x26f7d159U, 0x69680116U, 0x36e3d549U, 0x926efcedU, + 0x2af8d255U, 0x1b849f64U, 0xec8d6193U, 0x5fd18e20U, + 0x2efdd351U, 0x7c394503U, 0x966bfde9U, 0x89b039f6U, + 0x2c7d5153U, 0x972bbce8U, 0xca20eab5U, 0x1ec1df61U, + 0xa312b1dcU, 0x9ce17de3U, 0x9e61ffe1U, 0xe082629fU, + 0xf493678bU, 0x8f35baf0U, 0xc76fa8b8U, 0x555b0e2aU, + 0xc0aa6abfU, 0x392c1546U, 0xe487639bU, 0x6fed8210U, + 0x4a80ca35U, 0xd77baca8U, 0xaa58f2d5U, 0x8b30bbf4U, + 0x3126174eU, 0xb98c35c6U, 0x3463574bU, 0x0f959a70U, + 0x150b1e6aU, 0x48004837U, 0xf613e589U, 0x2072525fU, + 0xa19233deU, 0xa657f1d9U, 0x2537125aU, 0xd0be6eafU, + 0x84ff7bfbU, 0xf9dc2586U, 0xd4bb6fabU, 0x6d6d0012U, + 0x53de8d2cU, 0xb8cc74c7U, 0x7abcc605U, 0x1c415d63U, + 0x9b24bfe4U, 0x9a64fee5U, 0x18445c67U, 0x7573060aU, + 0x49400936U, 0x4bc08b34U, 0xda34eea5U, 0x6c2d4113U, + 0x88f078f7U, 0xe342a19cU, 0x76b3c509U, 0xe202e09dU, + 0x1d011c62U, 0x90ee7eefU, 0xbb0cb7c4U, 0x2477535bU, + 0x27b79058U, 0x2bb89354U, 0x80fa7affU, 0x4c054933U, + 0x43ca893cU, 0x178b9c68U, 0xedcd2092U, 0xa8d870d7U, + 0x6567021aU, 0x29381156U, 0xba4cf6c5U, 0xab18b3d4U, + 0x47cf8838U, 0xdf71aea0U, 0xf096668fU, 0x529ecc2dU, + 0xfe19e781U, 0x16cbdd69U, 0xbe49f7c1U, 0xff59a680U, + 0x0b909b74U, 0xe747a098U, 0xc1ea2bbeU, 0x0c555973U, + 0x12cedc6dU, 0x0ed5db71U, 0x77f38408U, 0x6aa8c215U, + 0x827af8fdU, 0x02dad87dU, 0x67e78018U, 0x98e47ce7U, + 0xd5fb2eaaU, 0x867ff9f9U, 0x9f21bee0U, 0xdb74afa4U, + 0xf89c6487U, 0xc9e029b6U, 0x1ac4de65U, 0xcf65aab0U, + 0xb703b4c8U, 0x5e91cf21U, 0x8e75fbf1U, 0x19041d66U, + 0x045f5b7bU, 0x95ab3eeaU, 0xa59732daU, 0xfc996583U, + 0x2d3d1052U, 0x783c4407U, 0xacdd71d3U, 0xcde528b2U, + 0x873fb8f8U, 0x99a43de6U, 0x66a7c119U, 0x501e4e2fU, + 0x08505877U, 0x59540d26U, 0x4d450832U, 0xbd8934c2U, + 0x6162031eU, 0x039a997cU, 0xd23eecadU, 0x005a5a7fU, + 0x051f1a7aU, 0x3c695543U, 0xf356a58cU, 0x144b5f6bU, + 0xe8886097U, 0x569bcd29U, 0xee0de391U, 0xd37eadacU, + 0x3066564fU, 0xc8a068b7U, 0x4e85cb31U, 0x468fc939U, + 0x515e0f2eU, 0xb4c377cbU, 0x400a4a3fU, 0x09101976U, + 0xf216e48dU, 0x5d510c22U, 0x0d151872U, 0x3ee9d741U, + 0x8cf579f3U, 0x1f819e60U, 0xad9d30d2U, 0x079f9878U, + 0x85bf3afaU, 0x22f2d05dU, 0x0ad0da75U, 0x28785057U, + 0xb246f4cdU, 0xcb60abb4U, 0xbf09b6c0U, 0x3bac9744U, + 0xd1fe2faeU, 0xe9c82196U, 0x5a94ce25U, 0x932ebdecU, + 0xfdd92482U, 0x7176070eU, 0xbcc975c3U, 0x3aecd645U, + 0x8a70faf5U, 0x797c0506U, 0x2fbd9250U, 0x4fc58a30U, + 0x33a6954cU, 0x37a39448U, 0xeb48a394U, 0xc36aa9bcU, + 0xb0c676cfU, 0xea08e295U, 0x386c5447U, 0xcca569b3U, + 0x68284017U, 0xf1d6278eU, 0x7433470bU, 0x7bfc8704U, + 0xc22ae8bdU, 0xe1c2239eU, 0xf753a488U, 0x833ab9fcU, + 0xfa1ce685U, 0xc62fe9b9U, 0xef4da290U, 0xe5c7229aU, + 0xae5df3d1U, 0x81ba3bfeU, 0x428ac83dU, 0xa4d773dbU, + 0x104e5e6fU, 0xb18637ceU, 0x6be88314U, 0x7036460fU, + 0x32e6d44dU, 0x57db8c28U, 0xc5ef2abaU, 0xce25ebb1U, + 0x6427431bU, 0x110e1f6eU, 0x541b4f2bU, 0x440f4b3bU, + 0xa0d272dfU, 0x23b2915cU, 0xd8b46ca7U, 0xaf1db2d0U, + 0xb643f5c9U, 0xdcb16da3U, 0x5bd48f24U, 0x7ff98600U, + 0x138e9d6cU, 0x6022421fU, 0x414a0b3eU, 0xa252f0ddU, + 0x91ae3feeU, 0x3fa99640U, 0x9da13ce2U, 0x94eb7febU, + 0xe607e199U, 0x454f0a3aU, 0x73f6850cU, 0x3523164aU, + 0x6eadc311U, 0xf5d3268aU, 0xb306b5ccU, 0x06dfd979U, + 0x63e2811cU, 0x3d291442U, 0xfb5ca784U, 0x7eb9c701U, + 0xd9f42da6U, 0xa99831d6U, 0x62a2c01dU, 0xa717b0d8U, + 0xaaea40ceU, 0xb3b407d7U, 0x56297f32U, 0x0a62686eU, + 0xc2985aa6U, 0x76017712U, 0x05ada861U, 0x2f0f204bU, + 0xa92a83cdU, 0x2b0a214fU, 0xa12081c5U, 0xfaae549eU, + 0x51ecbd35U, 0x1e736d7aU, 0x41f8b925U, 0xe5759081U, + 0x5de3be39U, 0x6c9ff308U, 0x9b960dffU, 0x28cae24cU, + 0x59e6bf3dU, 0x0b22296fU, 0xe1709185U, 0xfeab559aU, + 0x5b663d3fU, 0xe030d084U, 0xbd3b86d9U, 0x69dab30dU, + 0xd409ddb0U, 0xebfa118fU, 0xe97a938dU, 0x97990ef3U, + 0x83880be7U, 0xf82ed69cU, 0xb074c4d4U, 0x22406246U, + 0xb7b106d3U, 0x4e37792aU, 0x939c0ff7U, 0x18f6ee7cU, + 0x3d9ba659U, 0xa060c0c4U, 0xdd439eb9U, 0xfc2bd798U, + 0x463d7b22U, 0xce9759aaU, 0x43783b27U, 0x788ef61cU, + 0x62107206U, 0x3f1b245bU, 0x810889e5U, 0x57693e33U, + 0xd6895fb2U, 0xd14c9db5U, 0x522c7e36U, 0xa7a502c3U, + 0xf3e41797U, 0x8ec749eaU, 0xa3a003c7U, 0x1a766c7eU, + 0x24c5e140U, 0xcfd718abU, 0x0da7aa69U, 0x6b5a310fU, + 0xec3fd388U, 0xed7f9289U, 0x6f5f300bU, 0x02686a66U, + 0x3e5b655aU, 0x3cdbe758U, 0xad2f82c9U, 0x1b362d7fU, + 0xffeb149bU, 0x9459cdf0U, 0x01a8a965U, 0x95198cf1U, + 0x6a1a700eU, 0xe7f51283U, 0xcc17dba8U, 0x536c3f37U, + 0x50acfc34U, 0x5ca3ff38U, 0xf7e11693U, 0x3b1e255fU, + 0x34d1e550U, 0x6090f004U, 0x9ad64cfeU, 0xdfc31cbbU, + 0x127c6e76U, 0x5e237d3aU, 0xcd579aa9U, 0xdc03dfb8U, + 0x30d4e454U, 0xa86ac2ccU, 0x878d0ae3U, 0x2585a041U, + 0x89028bedU, 0x61d0b105U, 0xc9529badU, 0x8842caecU, + 0x7c8bf718U, 0x905cccf4U, 0xb6f147d2U, 0x7b4e351fU, + 0x65d5b001U, 0x79ceb71dU, 0x00e8e864U, 0x1db3ae79U, + 0xf5619491U, 0x75c1b411U, 0x10fcec74U, 0xefff108bU, + 0xa2e042c6U, 0xf1649595U, 0xe83ad28cU, 0xac6fc3c8U, + 0x8f8708ebU, 0xbefb45daU, 0x6ddfb209U, 0xb87ec6dcU, + 0xc018d8a4U, 0x298aa34dU, 0xf96e979dU, 0x6e1f710aU, + 0x73443717U, 0xe2b05286U, 0xd28c5eb6U, 0x8b8209efU, + 0x5a267c3eU, 0x0f27286bU, 0xdbc61dbfU, 0xbafe44deU, + 0xf024d494U, 0xeebf518aU, 0x11bcad75U, 0x27052243U, + 0x7f4b341bU, 0x2e4f614aU, 0x3a5e645eU, 0xca9258aeU, + 0x16796f72U, 0x7481f510U, 0xa52580c1U, 0x77413613U, + 0x72047616U, 0x4b72392fU, 0x844dc9e0U, 0x63503307U, + 0x9f930cfbU, 0x2180a145U, 0x99168ffdU, 0xa465c1c0U, + 0x477d3a23U, 0xbfbb04dbU, 0x399ea75dU, 0x3194a555U, + 0x26456342U, 0xc3d81ba7U, 0x37112653U, 0x7e0b751aU, + 0x850d88e1U, 0x2a4a604eU, 0x7a0e741eU, 0x49f2bb2dU, + 0xfbee159fU, 0x689af20cU, 0xda865cbeU, 0x7084f414U, + 0xf2a45696U, 0x55e9bc31U, 0x7dcbb619U, 0x5f633c3bU, + 0xc55d98a1U, 0xbc7bc7d8U, 0xc812daacU, 0x4cb7fb28U, + 0xa6e543c2U, 0x9ed34dfaU, 0x2d8fa249U, 0xe435d180U, + 0x8ac248eeU, 0x066d6b62U, 0xcbd219afU, 0x4df7ba29U, + 0xfd6b9699U, 0x0e67696aU, 0x58a6fe3cU, 0x38dee65cU, + 0x44bdf920U, 0x40b8f824U, 0x9c53cff8U, 0xb471c5d0U, + 0xc7dd1aa3U, 0x9d138ef9U, 0x4f77382bU, 0xbbbe05dfU, + 0x1f332c7bU, 0x86cd4be2U, 0x03282b67U, 0x0ce7eb68U, + 0xb53184d1U, 0x96d94ff2U, 0x8048c8e4U, 0xf421d590U, + 0x8d078ae9U, 0xb13485d5U, 0x9856cefcU, 0x92dc4ef6U, + 0xd9469fbdU, 0xf6a15792U, 0x3591a451U, 0xd3cc1fb7U, + 0x67553203U, 0xc69d5ba2U, 0x1cf3ef78U, 0x072d2a63U, + 0x45fdb821U, 0x20c0e044U, 0xb2f446d6U, 0xb93e87ddU, + 0x133c2f77U, 0x66157302U, 0x23002347U, 0x33142757U, + 0xd7c91eb3U, 0x54a9fd30U, 0xafaf00cbU, 0xd806debcU, + 0xc15899a5U, 0xabaa01cfU, 0x2ccfe348U, 0x08e2ea6cU, + 0x6495f100U, 0x17392e73U, 0x36516752U, 0xd5499cb1U, + 0xe6b55382U, 0x48b2fa2cU, 0xeaba508eU, 0xe3f01387U, + 0x911c8df5U, 0x32546656U, 0x04ede960U, 0x42387a26U, + 0x19b6af7dU, 0x82c84ae6U, 0xc41dd9a0U, 0x71c4b515U, + 0x14f9ed70U, 0x4a32782eU, 0x8c47cbe8U, 0x09a2ab6dU, + 0xaeef41caU, 0xde835dbaU, 0x15b9ac71U, 0xd00cdcb4U, + 0x063533bdU, 0x1f6b74a4U, 0xfaf60c41U, 0xa6bd1b1dU, + 0x6e4729d5U, 0xdade0461U, 0xa972db12U, 0x83d05338U, + 0x05f5f0beU, 0x87d5523cU, 0x0dfff2b6U, 0x567127edU, + 0xfd33ce46U, 0xb2ac1e09U, 0xed27ca56U, 0x49aae3f2U, + 0xf13ccd4aU, 0xc040807bU, 0x37497e8cU, 0x8415913fU, + 0xf539cc4eU, 0xa7fd5a1cU, 0x4dafe2f6U, 0x527426e9U, + 0xf7b94e4cU, 0x4cefa3f7U, 0x11e4f5aaU, 0xc505c07eU, + 0x78d6aec3U, 0x472562fcU, 0x45a5e0feU, 0x3b467d80U, + 0x2f577894U, 0x54f1a5efU, 0x1cabb7a7U, 0x8e9f1135U, + 0x1b6e75a0U, 0xe2e80a59U, 0x3f437c84U, 0xb4299d0fU, + 0x9144d52aU, 0x0cbfb3b7U, 0x719cedcaU, 0x50f4a4ebU, + 0xeae20851U, 0x62482ad9U, 0xefa74854U, 0xd451856fU, + 0xcecf0175U, 0x93c45728U, 0x2dd7fa96U, 0xfbb64d40U, + 0x7a562cc1U, 0x7d93eec6U, 0xfef30d45U, 0x0b7a71b0U, + 0x5f3b64e4U, 0x22183a99U, 0x0f7f70b4U, 0xb6a91f0dU, + 0x881a9233U, 0x63086bd8U, 0xa178d91aU, 0xc785427cU, + 0x40e0a0fbU, 0x41a0e1faU, 0xc3804378U, 0xaeb71915U, + 0x92841629U, 0x9004942bU, 0x01f0f1baU, 0xb7e95e0cU, + 0x533467e8U, 0x3886be83U, 0xad77da16U, 0x39c6ff82U, + 0xc6c5037dU, 0x4b2a61f0U, 0x60c8a8dbU, 0xffb34c44U, + 0xfc738f47U, 0xf07c8c4bU, 0x5b3e65e0U, 0x97c1562cU, + 0x980e9623U, 0xcc4f8377U, 0x36093f8dU, 0x731c6fc8U, + 0xbea31d05U, 0xf2fc0e49U, 0x6188e9daU, 0x70dcaccbU, + 0x9c0b9727U, 0x04b5b1bfU, 0x2b527990U, 0x895ad332U, + 0x25ddf89eU, 0xcd0fc276U, 0x658de8deU, 0x249db99fU, + 0xd054846bU, 0x3c83bf87U, 0x1a2e34a1U, 0xd791466cU, + 0xc90ac372U, 0xd511c46eU, 0xac379b17U, 0xb16cdd0aU, + 0x59bee7e2U, 0xd91ec762U, 0xbc239f07U, 0x432063f8U, + 0x0e3f31b5U, 0x5dbbe6e6U, 0x44e5a1ffU, 0x00b0b0bbU, + 0x23587b98U, 0x122436a9U, 0xc100c17aU, 0x14a1b5afU, + 0x6cc7abd7U, 0x8555d03eU, 0x55b1e4eeU, 0xc2c00279U, + 0xdf9b4464U, 0x4e6f21f5U, 0x7e532dc5U, 0x275d7a9cU, + 0xf6f90f4dU, 0xa3f85b18U, 0x77196eccU, 0x162137adU, + 0x5cfba7e7U, 0x426022f9U, 0xbd63de06U, 0x8bda5130U, + 0xd3944768U, 0x82901239U, 0x9681172dU, 0x664d2bddU, + 0xbaa61c01U, 0xd85e8663U, 0x09faf3b2U, 0xdb9e4560U, + 0xdedb0565U, 0xe7ad4a5cU, 0x2892ba93U, 0xcf8f4074U, + 0x334c7f88U, 0x8d5fd236U, 0x35c9fc8eU, 0x08bab2b3U, + 0xeba24950U, 0x136477a8U, 0x9541d42eU, 0x9d4bd626U, + 0x8a9a1031U, 0x6f0768d4U, 0x9bce5520U, 0xd2d40669U, + 0x29d2fb92U, 0x8695133dU, 0xd6d1076dU, 0xe52dc85eU, + 0x573166ecU, 0xc445817fU, 0x76592fcdU, 0xdc5b8767U, + 0x5e7b25e5U, 0xf936cf42U, 0xd114c56aU, 0xf3bc4f48U, + 0x6982ebd2U, 0x10a4b4abU, 0x64cda9dfU, 0xe068885bU, + 0x0a3a30b1U, 0x320c3e89U, 0x8150d13aU, 0x48eaa2f3U, + 0x261d3b9dU, 0xaab21811U, 0x670d6adcU, 0xe128c95aU, + 0x51b4e5eaU, 0xa2b81a19U, 0xf4798d4fU, 0x9401952fU, + 0xe8628a53U, 0xec678b57U, 0x308cbc8bU, 0x18aeb6a3U, + 0x6b0269d0U, 0x31ccfd8aU, 0xe3a84b58U, 0x176176acU, + 0xb3ec5f08U, 0x2a123891U, 0xaff75814U, 0xa038981bU, + 0x19eef7a2U, 0x3a063c81U, 0x2c97bb97U, 0x58fea6e3U, + 0x21d8f99aU, 0x1debf6a6U, 0x3489bd8fU, 0x3e033d85U, + 0x7599ecceU, 0x5a7e24e1U, 0x994ed722U, 0x7f136cc4U, + 0xcb8a4170U, 0x6a4228d1U, 0xb02c9c0bU, 0xabf25910U, + 0xe922cb52U, 0x8c1f9337U, 0x1e2b35a5U, 0x15e1f4aeU, + 0xbfe35c04U, 0xcaca0071U, 0x8fdf5034U, 0x9fcb5424U, + 0x7b166dc0U, 0xf8768e43U, 0x037073b8U, 0x74d9adcfU, + 0x6d87ead6U, 0x077572bcU, 0x8010903bU, 0xa43d991fU, + 0xc84a8273U, 0xbbe65d00U, 0x9a8e1421U, 0x7996efc2U, + 0x4a6a20f1U, 0xe46d895fU, 0x466523fdU, 0x4f2f60f4U, + 0x3dc3fe86U, 0x9e8b1525U, 0xa8329a13U, 0xeee70955U, + 0xb569dc0eU, 0x2e173995U, 0x68c2aad3U, 0xdd1bc666U, + 0xb8269e03U, 0xe6ed0b5dU, 0x2098b89bU, 0xa57dd81eU, + 0x023032b9U, 0x725c2ec9U, 0xb966df02U, 0x7cd3afc7U, + 0x6e7c129cU, 0x77225585U, 0x92bf2d60U, 0xcef43a3cU, + 0x060e08f4U, 0xb2972540U, 0xc13bfa33U, 0xeb997219U, + 0x6dbcd19fU, 0xef9c731dU, 0x65b6d397U, 0x3e3806ccU, + 0x957aef67U, 0xdae53f28U, 0x856eeb77U, 0x21e3c2d3U, + 0x9975ec6bU, 0xa809a15aU, 0x5f005fadU, 0xec5cb01eU, + 0x9d70ed6fU, 0xcfb47b3dU, 0x25e6c3d7U, 0x3a3d07c8U, + 0x9ff06f6dU, 0x24a682d6U, 0x79add48bU, 0xad4ce15fU, + 0x109f8fe2U, 0x2f6c43ddU, 0x2decc1dfU, 0x530f5ca1U, + 0x471e59b5U, 0x3cb884ceU, 0x74e29686U, 0xe6d63014U, + 0x73275481U, 0x8aa12b78U, 0x570a5da5U, 0xdc60bc2eU, + 0xf90df40bU, 0x64f69296U, 0x19d5ccebU, 0x38bd85caU, + 0x82ab2970U, 0x0a010bf8U, 0x87ee6975U, 0xbc18a44eU, + 0xa6862054U, 0xfb8d7609U, 0x459edbb7U, 0x93ff6c61U, + 0x121f0de0U, 0x15dacfe7U, 0x96ba2c64U, 0x63335091U, + 0x377245c5U, 0x4a511bb8U, 0x67365195U, 0xdee03e2cU, + 0xe053b312U, 0x0b414af9U, 0xc931f83bU, 0xafcc635dU, + 0x28a981daU, 0x29e9c0dbU, 0xabc96259U, 0xc6fe3834U, + 0xfacd3708U, 0xf84db50aU, 0x69b9d09bU, 0xdfa07f2dU, + 0x3b7d46c9U, 0x50cf9fa2U, 0xc53efb37U, 0x518fdea3U, + 0xae8c225cU, 0x236340d1U, 0x088189faU, 0x97fa6d65U, + 0x943aae66U, 0x9835ad6aU, 0x337744c1U, 0xff88770dU, + 0xf047b702U, 0xa406a256U, 0x5e401eacU, 0x1b554ee9U, + 0xd6ea3c24U, 0x9ab52f68U, 0x09c1c8fbU, 0x18958deaU, + 0xf442b606U, 0x6cfc909eU, 0x431b58b1U, 0xe113f213U, + 0x4d94d9bfU, 0xa546e357U, 0x0dc4c9ffU, 0x4cd498beU, + 0xb81da54aU, 0x54ca9ea6U, 0x72671580U, 0xbfd8674dU, + 0xa143e253U, 0xbd58e54fU, 0xc47eba36U, 0xd925fc2bU, + 0x31f7c6c3U, 0xb157e643U, 0xd46abe26U, 0x2b6942d9U, + 0x66761094U, 0x35f2c7c7U, 0x2cac80deU, 0x68f9919aU, + 0x4b115ab9U, 0x7a6d1788U, 0xa949e05bU, 0x7ce8948eU, + 0x048e8af6U, 0xed1cf11fU, 0x3df8c5cfU, 0xaa892358U, + 0xb7d26545U, 0x262600d4U, 0x161a0ce4U, 0x4f145bbdU, + 0x9eb02e6cU, 0xcbb17a39U, 0x1f504fedU, 0x7e68168cU, + 0x34b286c6U, 0x2a2903d8U, 0xd52aff27U, 0xe3937011U, + 0xbbdd6649U, 0xead93318U, 0xfec8360cU, 0x0e040afcU, + 0xd2ef3d20U, 0xb017a742U, 0x61b3d293U, 0xb3d76441U, + 0xb6922444U, 0x8fe46b7dU, 0x40db9bb2U, 0xa7c66155U, + 0x5b055ea9U, 0xe516f317U, 0x5d80ddafU, 0x60f39392U, + 0x83eb6871U, 0x7b2d5689U, 0xfd08f50fU, 0xf502f707U, + 0xe2d33110U, 0x074e49f5U, 0xf3877401U, 0xba9d2748U, + 0x419bdab3U, 0xeedc321cU, 0xbe98264cU, 0x8d64e97fU, + 0x3f7847cdU, 0xac0ca05eU, 0x1e100eecU, 0xb412a646U, + 0x363204c4U, 0x917fee63U, 0xb95de44bU, 0x9bf56e69U, + 0x01cbcaf3U, 0x78ed958aU, 0x0c8488feU, 0x8821a97aU, + 0x62731190U, 0x5a451fa8U, 0xe919f01bU, 0x20a383d2U, + 0x4e541abcU, 0xc2fb3930U, 0x0f444bfdU, 0x8961e87bU, + 0x39fdc4cbU, 0xcaf13b38U, 0x9c30ac6eU, 0xfc48b40eU, + 0x802bab72U, 0x842eaa76U, 0x58c59daaU, 0x70e79782U, + 0x034b48f1U, 0x5985dcabU, 0x8be16a79U, 0x7f28578dU, + 0xdba57e29U, 0x425b19b0U, 0xc7be7935U, 0xc871b93aU, + 0x71a7d683U, 0x524f1da0U, 0x44de9ab6U, 0x30b787c2U, + 0x4991d8bbU, 0x75a2d787U, 0x5cc09caeU, 0x564a1ca4U, + 0x1dd0cdefU, 0x323705c0U, 0xf107f603U, 0x175a4de5U, + 0xa3c36051U, 0x020b09f0U, 0xd865bd2aU, 0xc3bb7831U, + 0x816bea73U, 0xe456b216U, 0x76621484U, 0x7da8d58fU, + 0xd7aa7d25U, 0xa2832150U, 0xe7967115U, 0xf7827505U, + 0x135f4ce1U, 0x903faf62U, 0x6b395299U, 0x1c908ceeU, + 0x05cecbf7U, 0x6f3c539dU, 0xe859b11aU, 0xcc74b83eU, + 0xa003a352U, 0xd3af7c21U, 0xf2c73500U, 0x11dfcee3U, + 0x222301d0U, 0x8c24a87eU, 0x2e2c02dcU, 0x276641d5U, + 0x558adfa7U, 0xf6c23404U, 0xc07bbb32U, 0x86ae2874U, + 0xdd20fd2fU, 0x465e18b4U, 0x008b8bf2U, 0xb552e747U, + 0xd06fbf22U, 0x8ea42a7cU, 0x48d199baU, 0xcd34f93fU, + 0x6a791398U, 0x1a150fe8U, 0xd12ffe23U, 0x149a8ee6U, + 0x7687f17fU, 0x6fd9b666U, 0x8a44ce83U, 0xd60fd9dfU, + 0x1ef5eb17U, 0xaa6cc6a3U, 0xd9c019d0U, 0xf36291faU, + 0x7547327cU, 0xf76790feU, 0x7d4d3074U, 0x26c3e52fU, + 0x8d810c84U, 0xc21edccbU, 0x9d950894U, 0x39182130U, + 0x818e0f88U, 0xb0f242b9U, 0x47fbbc4eU, 0xf4a753fdU, + 0x858b0e8cU, 0xd74f98deU, 0x3d1d2034U, 0x22c6e42bU, + 0x870b8c8eU, 0x3c5d6135U, 0x61563768U, 0xb5b702bcU, + 0x08646c01U, 0x3797a03eU, 0x3517223cU, 0x4bf4bf42U, + 0x5fe5ba56U, 0x2443672dU, 0x6c197565U, 0xfe2dd3f7U, + 0x6bdcb762U, 0x925ac89bU, 0x4ff1be46U, 0xc49b5fcdU, + 0xe1f617e8U, 0x7c0d7175U, 0x012e2f08U, 0x20466629U, + 0x9a50ca93U, 0x12fae81bU, 0x9f158a96U, 0xa4e347adU, + 0xbe7dc3b7U, 0xe37695eaU, 0x5d653854U, 0x8b048f82U, + 0x0ae4ee03U, 0x0d212c04U, 0x8e41cf87U, 0x7bc8b372U, + 0x2f89a626U, 0x52aaf85bU, 0x7fcdb276U, 0xc61bddcfU, + 0xf8a850f1U, 0x13baa91aU, 0xd1ca1bd8U, 0xb73780beU, + 0x30526239U, 0x31122338U, 0xb33281baU, 0xde05dbd7U, + 0xe236d4ebU, 0xe0b656e9U, 0x71423378U, 0xc75b9cceU, + 0x2386a52aU, 0x48347c41U, 0xddc518d4U, 0x49743d40U, + 0xb677c1bfU, 0x3b98a332U, 0x107a6a19U, 0x8f018e86U, + 0x8cc14d85U, 0x80ce4e89U, 0x2b8ca722U, 0xe77394eeU, + 0xe8bc54e1U, 0xbcfd41b5U, 0x46bbfd4fU, 0x03aead0aU, + 0xce11dfc7U, 0x824ecc8bU, 0x113a2b18U, 0x006e6e09U, + 0xecb955e5U, 0x7407737dU, 0x5be0bb52U, 0xf9e811f0U, + 0x556f3a5cU, 0xbdbd00b4U, 0x153f2a1cU, 0x542f7b5dU, + 0xa0e646a9U, 0x4c317d45U, 0x6a9cf663U, 0xa72384aeU, + 0xb9b801b0U, 0xa5a306acU, 0xdc8559d5U, 0xc1de1fc8U, + 0x290c2520U, 0xa9ac05a0U, 0xcc915dc5U, 0x3392a13aU, + 0x7e8df377U, 0x2d092424U, 0x3457633dU, 0x70027279U, + 0x53eab95aU, 0x6296f46bU, 0xb1b203b8U, 0x6413776dU, + 0x1c756915U, 0xf5e712fcU, 0x2503262cU, 0xb272c0bbU, + 0xaf2986a6U, 0x3edde337U, 0x0ee1ef07U, 0x57efb85eU, + 0x864bcd8fU, 0xd34a99daU, 0x07abac0eU, 0x6693f56fU, + 0x2c496525U, 0x32d2e03bU, 0xcdd11cc4U, 0xfb6893f2U, + 0xa32685aaU, 0xf222d0fbU, 0xe633d5efU, 0x16ffe91fU, + 0xca14dec3U, 0xa8ec44a1U, 0x79483170U, 0xab2c87a2U, + 0xae69c7a7U, 0x971f889eU, 0x58207851U, 0xbf3d82b6U, + 0x43febd4aU, 0xfded10f4U, 0x457b3e4cU, 0x78087071U, + 0x9b108b92U, 0x63d6b56aU, 0xe5f316ecU, 0xedf914e4U, + 0xfa28d2f3U, 0x1fb5aa16U, 0xeb7c97e2U, 0xa266c4abU, + 0x59603950U, 0xf627d1ffU, 0xa663c5afU, 0x959f0a9cU, + 0x2783a42eU, 0xb4f743bdU, 0x06ebed0fU, 0xace945a5U, + 0x2ec9e727U, 0x89840d80U, 0xa1a607a8U, 0x830e8d8aU, + 0x19302910U, 0x60167669U, 0x147f6b1dU, 0x90da4a99U, + 0x7a88f273U, 0x42befc4bU, 0xf1e213f8U, 0x38586031U, + 0x56aff95fU, 0xda00dad3U, 0x17bfa81eU, 0x919a0b98U, + 0x21062728U, 0xd20ad8dbU, 0x84cb4f8dU, 0xe4b357edU, + 0x98d04891U, 0x9cd54995U, 0x403e7e49U, 0x681c7461U, + 0x1bb0ab12U, 0x417e3f48U, 0x931a899aU, 0x67d3b46eU, + 0xc35e9dcaU, 0x5aa0fa53U, 0xdf459ad6U, 0xd08a5ad9U, + 0x695c3560U, 0x4ab4fe43U, 0x5c257955U, 0x284c6421U, + 0x516a3b58U, 0x6d593464U, 0x443b7f4dU, 0x4eb1ff47U, + 0x052b2e0cU, 0x2acce623U, 0xe9fc15e0U, 0x0fa1ae06U, + 0xbb3883b2U, 0x1af0ea13U, 0xc09e5ec9U, 0xdb409bd2U, + 0x99900990U, 0xfcad51f5U, 0x6e99f767U, 0x6553366cU, + 0xcf519ec6U, 0xba78c2b3U, 0xff6d92f6U, 0xef7996e6U, + 0x0ba4af02U, 0x88c44c81U, 0x73c2b17aU, 0x046b6f0dU, + 0x1d352814U, 0x77c7b07eU, 0xf0a252f9U, 0xd48f5bddU, + 0xb8f840b1U, 0xcb549fc2U, 0xea3cd6e3U, 0x09242d00U, + 0x3ad8e233U, 0x94df4b9dU, 0x36d7e13fU, 0x3f9da236U, + 0x4d713c44U, 0xee39d7e7U, 0xd88058d1U, 0x9e55cb97U, + 0xc5db1eccU, 0x5ea5fb57U, 0x18706811U, 0xada904a4U, + 0xc8945cc1U, 0x965fc99fU, 0x502a7a59U, 0xd5cf1adcU, + 0x7282f07bU, 0x02eeec0bU, 0xc9d41dc0U, 0x0c616d05U, + 0x8a48c24cU, 0x93168555U, 0x768bfdb0U, 0x2ac0eaecU, + 0xe23ad824U, 0x56a3f590U, 0x250f2ae3U, 0x0fada2c9U, + 0x8988014fU, 0x0ba8a3cdU, 0x81820347U, 0xda0cd61cU, + 0x714e3fb7U, 0x3ed1eff8U, 0x615a3ba7U, 0xc5d71203U, + 0x7d413cbbU, 0x4c3d718aU, 0xbb348f7dU, 0x086860ceU, + 0x79443dbfU, 0x2b80abedU, 0xc1d21307U, 0xde09d718U, + 0x7bc4bfbdU, 0xc0925206U, 0x9d99045bU, 0x4978318fU, + 0xf4ab5f32U, 0xcb58930dU, 0xc9d8110fU, 0xb73b8c71U, + 0xa32a8965U, 0xd88c541eU, 0x90d64656U, 0x02e2e0c4U, + 0x97138451U, 0x6e95fba8U, 0xb33e8d75U, 0x38546cfeU, + 0x1d3924dbU, 0x80c24246U, 0xfde11c3bU, 0xdc89551aU, + 0x669ff9a0U, 0xee35db28U, 0x63dab9a5U, 0x582c749eU, + 0x42b2f084U, 0x1fb9a6d9U, 0xa1aa0b67U, 0x77cbbcb1U, + 0xf62bdd30U, 0xf1ee1f37U, 0x728efcb4U, 0x87078041U, + 0xd3469515U, 0xae65cb68U, 0x83028145U, 0x3ad4eefcU, + 0x046763c2U, 0xef759a29U, 0x2d0528ebU, 0x4bf8b38dU, + 0xcc9d510aU, 0xcddd100bU, 0x4ffdb289U, 0x22cae8e4U, + 0x1ef9e7d8U, 0x1c7965daU, 0x8d8d004bU, 0x3b94affdU, + 0xdf499619U, 0xb4fb4f72U, 0x210a2be7U, 0xb5bb0e73U, + 0x4ab8f28cU, 0xc7579001U, 0xecb5592aU, 0x73cebdb5U, + 0x700e7eb6U, 0x7c017dbaU, 0xd7439411U, 0x1bbca7ddU, + 0x147367d2U, 0x40327286U, 0xba74ce7cU, 0xff619e39U, + 0x32deecf4U, 0x7e81ffb8U, 0xedf5182bU, 0xfca15d3aU, + 0x107666d6U, 0x88c8404eU, 0xa72f8861U, 0x052722c3U, + 0xa9a0096fU, 0x41723387U, 0xe9f0192fU, 0xa8e0486eU, + 0x5c29759aU, 0xb0fe4e76U, 0x9653c550U, 0x5becb79dU, + 0x45773283U, 0x596c359fU, 0x204a6ae6U, 0x3d112cfbU, + 0xd5c31613U, 0x55633693U, 0x305e6ef6U, 0xcf5d9209U, + 0x8242c044U, 0xd1c61717U, 0xc898500eU, 0x8ccd414aU, + 0xaf258a69U, 0x9e59c758U, 0x4d7d308bU, 0x98dc445eU, + 0xe0ba5a26U, 0x092821cfU, 0xd9cc151fU, 0x4ebdf388U, + 0x53e6b595U, 0xc212d004U, 0xf22edc34U, 0xab208b6dU, + 0x7a84febcU, 0x2f85aae9U, 0xfb649f3dU, 0x9a5cc65cU, + 0xd0865616U, 0xce1dd308U, 0x311e2ff7U, 0x07a7a0c1U, + 0x5fe9b699U, 0x0eede3c8U, 0x1afce6dcU, 0xea30da2cU, + 0x36dbedf0U, 0x54237792U, 0x85870243U, 0x57e3b491U, + 0x52a6f494U, 0x6bd0bbadU, 0xa4ef4b62U, 0x43f2b185U, + 0xbf318e79U, 0x012223c7U, 0xb9b40d7fU, 0x84c74342U, + 0x67dfb8a1U, 0x9f198659U, 0x193c25dfU, 0x113627d7U, + 0x06e7e1c0U, 0xe37a9925U, 0x17b3a4d1U, 0x5ea9f798U, + 0xa5af0a63U, 0x0ae8e2ccU, 0x5aacf69cU, 0x695039afU, + 0xdb4c971dU, 0x4838708eU, 0xfa24de3cU, 0x50267696U, + 0xd206d414U, 0x754b3eb3U, 0x5d69349bU, 0x7fc1beb9U, + 0xe5ff1a23U, 0x9cd9455aU, 0xe8b0582eU, 0x6c1579aaU, + 0x8647c140U, 0xbe71cf78U, 0x0d2d20cbU, 0xc4975302U, + 0xaa60ca6cU, 0x26cfe9e0U, 0xeb709b2dU, 0x6d5538abU, + 0xddc9141bU, 0x2ec5ebe8U, 0x78047cbeU, 0x187c64deU, + 0x641f7ba2U, 0x601a7aa6U, 0xbcf14d7aU, 0x94d34752U, + 0xe77f9821U, 0xbdb10c7bU, 0x6fd5baa9U, 0x9b1c875dU, + 0x3f91aef9U, 0xa66fc960U, 0x238aa9e5U, 0x2c4569eaU, + 0x95930653U, 0xb67bcd70U, 0xa0ea4a66U, 0xd4835712U, + 0xada5086bU, 0x91960757U, 0xb8f44c7eU, 0xb27ecc74U, + 0xf9e41d3fU, 0xd603d510U, 0x153326d3U, 0xf36e9d35U, + 0x47f7b081U, 0xe63fd920U, 0x3c516dfaU, 0x278fa8e1U, + 0x655f3aa3U, 0x006262c6U, 0x9256c454U, 0x999c055fU, + 0x339eadf5U, 0x46b7f180U, 0x03a2a1c5U, 0x13b6a5d5U, + 0xf76b9c31U, 0x740b7fb2U, 0x8f0d8249U, 0xf8a45c3eU, + 0xe1fa1b27U, 0x8b08834dU, 0x0c6d61caU, 0x284068eeU, + 0x44377382U, 0x379bacf1U, 0x16f3e5d0U, 0xf5eb1e33U, + 0xc617d100U, 0x681078aeU, 0xca18d20cU, 0xc3529105U, + 0xb1be0f77U, 0x12f6e4d4U, 0x244f6be2U, 0x629af8a4U, + 0x39142dffU, 0xa26ac864U, 0xe4bf5b22U, 0x51663797U, + 0x345b6ff2U, 0x6a90faacU, 0xace5496aU, 0x290029efU, + 0x8e4dc348U, 0xfe21df38U, 0x351b2ef3U, 0xf0ae5e36U, + 0x8de16ce2U, 0x94bf2bfbU, 0x7122531eU, 0x2d694442U, + 0xe593768aU, 0x510a5b3eU, 0x22a6844dU, 0x08040c67U, + 0x8e21afe1U, 0x0c010d63U, 0x862bade9U, 0xdda578b2U, + 0x76e79119U, 0x39784156U, 0x66f39509U, 0xc27ebcadU, + 0x7ae89215U, 0x4b94df24U, 0xbc9d21d3U, 0x0fc1ce60U, + 0x7eed9311U, 0x2c290543U, 0xc67bbda9U, 0xd9a079b6U, + 0x7c6d1113U, 0xc73bfca8U, 0x9a30aaf5U, 0x4ed19f21U, + 0xf302f19cU, 0xccf13da3U, 0xce71bfa1U, 0xb09222dfU, + 0xa48327cbU, 0xdf25fab0U, 0x977fe8f8U, 0x054b4e6aU, + 0x90ba2affU, 0x693c5506U, 0xb49723dbU, 0x3ffdc250U, + 0x1a908a75U, 0x876bece8U, 0xfa48b295U, 0xdb20fbb4U, + 0x6136570eU, 0xe99c7586U, 0x6473170bU, 0x5f85da30U, + 0x451b5e2aU, 0x18100877U, 0xa603a5c9U, 0x7062121fU, + 0xf182739eU, 0xf647b199U, 0x7527521aU, 0x80ae2eefU, + 0xd4ef3bbbU, 0xa9cc65c6U, 0x84ab2febU, 0x3d7d4052U, + 0x03cecd6cU, 0xe8dc3487U, 0x2aac8645U, 0x4c511d23U, + 0xcb34ffa4U, 0xca74bea5U, 0x48541c27U, 0x2563464aU, + 0x19504976U, 0x1bd0cb74U, 0x8a24aee5U, 0x3c3d0153U, + 0xd8e038b7U, 0xb352e1dcU, 0x26a38549U, 0xb212a0ddU, + 0x4d115c22U, 0xc0fe3eafU, 0xeb1cf784U, 0x7467131bU, + 0x77a7d018U, 0x7ba8d314U, 0xd0ea3abfU, 0x1c150973U, + 0x13dac97cU, 0x479bdc28U, 0xbddd60d2U, 0xf8c83097U, + 0x3577425aU, 0x79285116U, 0xea5cb685U, 0xfb08f394U, + 0x17dfc878U, 0x8f61eee0U, 0xa08626cfU, 0x028e8c6dU, + 0xae09a7c1U, 0x46db9d29U, 0xee59b781U, 0xaf49e6c0U, + 0x5b80db34U, 0xb757e0d8U, 0x91fa6bfeU, 0x5c451933U, + 0x42de9c2dU, 0x5ec59b31U, 0x27e3c448U, 0x3ab88255U, + 0xd26ab8bdU, 0x52ca983dU, 0x37f7c058U, 0xc8f43ca7U, + 0x85eb6eeaU, 0xd66fb9b9U, 0xcf31fea0U, 0x8b64efe4U, + 0xa88c24c7U, 0x99f069f6U, 0x4ad49e25U, 0x9f75eaf0U, + 0xe713f488U, 0x0e818f61U, 0xde65bbb1U, 0x49145d26U, + 0x544f1b3bU, 0xc5bb7eaaU, 0xf587729aU, 0xac8925c3U, + 0x7d2d5012U, 0x282c0447U, 0xfccd3193U, 0x9df568f2U, + 0xd72ff8b8U, 0xc9b47da6U, 0x36b78159U, 0x000e0e6fU, + 0x58401837U, 0x09444d66U, 0x1d554872U, 0xed997482U, + 0x3172435eU, 0x538ad93cU, 0x822eacedU, 0x504a1a3fU, + 0x550f5a3aU, 0x6c791503U, 0xa346e5ccU, 0x445b1f2bU, + 0xb89820d7U, 0x068b8d69U, 0xbe1da3d1U, 0x836eedecU, + 0x6076160fU, 0x98b028f7U, 0x1e958b71U, 0x169f8979U, + 0x014e4f6eU, 0xe4d3378bU, 0x101a0a7fU, 0x59005936U, + 0xa206a4cdU, 0x0d414c62U, 0x5d055832U, 0x6ef99701U, + 0xdce539b3U, 0x4f91de20U, 0xfd8d7092U, 0x578fd838U, + 0xd5af7abaU, 0x72e2901dU, 0x5ac09a35U, 0x78681017U, + 0xe256b48dU, 0x9b70ebf4U, 0xef19f680U, 0x6bbcd704U, + 0x81ee6feeU, 0xb9d861d6U, 0x0a848e65U, 0xc33efdacU, + 0xadc964c2U, 0x2166474eU, 0xecd93583U, 0x6afc9605U, + 0xda60bab5U, 0x296c4546U, 0x7fadd210U, 0x1fd5ca70U, + 0x63b6d50cU, 0x67b3d408U, 0xbb58e3d4U, 0x937ae9fcU, + 0xe0d6368fU, 0xba18a2d5U, 0x687c1407U, 0x9cb529f3U, + 0x38380057U, 0xa1c667ceU, 0x2423074bU, 0x2becc744U, + 0x923aa8fdU, 0xb1d263deU, 0xa743e4c8U, 0xd32af9bcU, + 0xaa0ca6c5U, 0x963fa9f9U, 0xbf5de2d0U, 0xb5d762daU, + 0xfe4db391U, 0xd1aa7bbeU, 0x129a887dU, 0xf4c7339bU, + 0x405e1e2fU, 0xe196778eU, 0x3bf8c354U, 0x2026064fU, + 0x62f6940dU, 0x07cbcc68U, 0x95ff6afaU, 0x9e35abf1U, + 0x3437035bU, 0x411e5f2eU, 0x040b0f6bU, 0x141f0b7bU, + 0xf0c2329fU, 0x73a2d11cU, 0x88a42ce7U, 0xff0df290U, + 0xe653b589U, 0x8ca12de3U, 0x0bc4cf64U, 0x2fe9c640U, + 0x439edd2cU, 0x3032025fU, 0x115a4b7eU, 0xf242b09dU, + 0xc1be7faeU, 0x6fb9d600U, 0xcdb17ca2U, 0xc4fb3fabU, + 0xb617a1d9U, 0x155f4a7aU, 0x23e6c54cU, 0x6533560aU, + 0x3ebd8351U, 0xa5c366caU, 0xe316f58cU, 0x56cf9939U, + 0x33f2c15cU, 0x6d395402U, 0xab4ce7c4U, 0x2ea98741U, + 0x89e46de6U, 0xf9887196U, 0x32b2805dU, 0xf707f098U, + 0x854bce40U, 0x9c158959U, 0x7988f1bcU, 0x25c3e6e0U, + 0xed39d428U, 0x59a0f99cU, 0x2a0c26efU, 0x00aeaec5U, + 0x868b0d43U, 0x04abafc1U, 0x8e810f4bU, 0xd50fda10U, + 0x7e4d33bbU, 0x31d2e3f4U, 0x6e5937abU, 0xcad41e0fU, + 0x724230b7U, 0x433e7d86U, 0xb4378371U, 0x076b6cc2U, + 0x764731b3U, 0x2483a7e1U, 0xced11f0bU, 0xd10adb14U, + 0x74c7b3b1U, 0xcf915e0aU, 0x929a0857U, 0x467b3d83U, + 0xfba8533eU, 0xc45b9f01U, 0xc6db1d03U, 0xb838807dU, + 0xac298569U, 0xd78f5812U, 0x9fd54a5aU, 0x0de1ecc8U, + 0x9810885dU, 0x6196f7a4U, 0xbc3d8179U, 0x375760f2U, + 0x123a28d7U, 0x8fc14e4aU, 0xf2e21037U, 0xd38a5916U, + 0x699cf5acU, 0xe136d724U, 0x6cd9b5a9U, 0x572f7892U, + 0x4db1fc88U, 0x10baaad5U, 0xaea9076bU, 0x78c8b0bdU, + 0xf928d13cU, 0xfeed133bU, 0x7d8df0b8U, 0x88048c4dU, + 0xdc459919U, 0xa166c764U, 0x8c018d49U, 0x35d7e2f0U, + 0x0b646fceU, 0xe0769625U, 0x220624e7U, 0x44fbbf81U, + 0xc39e5d06U, 0xc2de1c07U, 0x40febe85U, 0x2dc9e4e8U, + 0x11faebd4U, 0x137a69d6U, 0x828e0c47U, 0x3497a3f1U, + 0xd04a9a15U, 0xbbf8437eU, 0x2e0927ebU, 0xbab8027fU, + 0x45bbfe80U, 0xc8549c0dU, 0xe3b65526U, 0x7ccdb1b9U, + 0x7f0d72baU, 0x730271b6U, 0xd840981dU, 0x14bfabd1U, + 0x1b706bdeU, 0x4f317e8aU, 0xb577c270U, 0xf0629235U, + 0x3ddde0f8U, 0x7182f3b4U, 0xe2f61427U, 0xf3a25136U, + 0x1f756adaU, 0x87cb4c42U, 0xa82c846dU, 0x0a242ecfU, + 0xa6a30563U, 0x4e713f8bU, 0xe6f31523U, 0xa7e34462U, + 0x532a7996U, 0xbffd427aU, 0x9950c95cU, 0x54efbb91U, + 0x4a743e8fU, 0x566f3993U, 0x2f4966eaU, 0x321220f7U, + 0xdac01a1fU, 0x5a603a9fU, 0x3f5d62faU, 0xc05e9e05U, + 0x8d41cc48U, 0xdec51b1bU, 0xc79b5c02U, 0x83ce4d46U, + 0xa0268665U, 0x915acb54U, 0x427e3c87U, 0x97df4852U, + 0xefb9562aU, 0x062b2dc3U, 0xd6cf1913U, 0x41beff84U, + 0x5ce5b999U, 0xcd11dc08U, 0xfd2dd038U, 0xa4238761U, + 0x7587f2b0U, 0x2086a6e5U, 0xf4679331U, 0x955fca50U, + 0xdf855a1aU, 0xc11edf04U, 0x3e1d23fbU, 0x08a4accdU, + 0x50eaba95U, 0x01eeefc4U, 0x15ffead0U, 0xe533d620U, + 0x39d8e1fcU, 0x5b207b9eU, 0x8a840e4fU, 0x58e0b89dU, + 0x5da5f898U, 0x64d3b7a1U, 0xabec476eU, 0x4cf1bd89U, + 0xb0328275U, 0x0e212fcbU, 0xb6b70173U, 0x8bc44f4eU, + 0x68dcb4adU, 0x901a8a55U, 0x163f29d3U, 0x1e352bdbU, + 0x09e4edccU, 0xec799529U, 0x18b0a8ddU, 0x51aafb94U, + 0xaaac066fU, 0x05ebeec0U, 0x55affa90U, 0x665335a3U, + 0xd44f9b11U, 0x473b7c82U, 0xf527d230U, 0x5f257a9aU, + 0xdd05d818U, 0x7a4832bfU, 0x526a3897U, 0x70c2b2b5U, + 0xeafc162fU, 0x93da4956U, 0xe7b35422U, 0x631675a6U, + 0x8944cd4cU, 0xb172c374U, 0x022e2cc7U, 0xcb945f0eU, + 0xa563c660U, 0x29cce5ecU, 0xe4739721U, 0x625634a7U, + 0xd2ca1817U, 0x21c6e7e4U, 0x770770b2U, 0x177f68d2U, + 0x6b1c77aeU, 0x6f1976aaU, 0xb3f24176U, 0x9bd04b5eU, + 0xe87c942dU, 0xb2b20077U, 0x60d6b6a5U, 0x941f8b51U, + 0x3092a2f5U, 0xa96cc56cU, 0x2c89a5e9U, 0x234665e6U, + 0x9a900a5fU, 0xb978c17cU, 0xafe9466aU, 0xdb805b1eU, + 0xa2a60467U, 0x9e950b5bU, 0xb7f74072U, 0xbd7dc078U, + 0xf6e71133U, 0xd900d91cU, 0x1a302adfU, 0xfc6d9139U, + 0x48f4bc8dU, 0xe93cd52cU, 0x335261f6U, 0x288ca4edU, + 0x6a5c36afU, 0x0f616ecaU, 0x9d55c858U, 0x969f0953U, + 0x3c9da1f9U, 0x49b4fd8cU, 0x0ca1adc9U, 0x1cb5a9d9U, + 0xf868903dU, 0x7b0873beU, 0x800e8e45U, 0xf7a75032U, + 0xeef9172bU, 0x840b8f41U, 0x036e6dc6U, 0x274364e2U, + 0x4b347f8eU, 0x3898a0fdU, 0x19f0e9dcU, 0xfae8123fU, + 0xc914dd0cU, 0x671374a2U, 0xc51bde00U, 0xcc519d09U, + 0xbebd037bU, 0x1df5e8d8U, 0x2b4c67eeU, 0x6d99f4a8U, + 0x361721f3U, 0xad69c468U, 0xebbc572eU, 0x5e653b9bU, + 0x3b5863feU, 0x6593f6a0U, 0xa3e64566U, 0x260325e3U, + 0x814ecf44U, 0xf122d334U, 0x3a1822ffU, 0xffad523aU, + 0xcf08c749U, 0xd6568050U, 0x33cbf8b5U, 0x6f80efe9U, + 0xa77add21U, 0x13e3f095U, 0x604f2fe6U, 0x4aeda7ccU, + 0xccc8044aU, 0x4ee8a6c8U, 0xc4c20642U, 0x9f4cd319U, + 0x340e3ab2U, 0x7b91eafdU, 0x241a3ea2U, 0x80971706U, + 0x380139beU, 0x097d748fU, 0xfe748a78U, 0x4d2865cbU, + 0x3c0438baU, 0x6ec0aee8U, 0x84921602U, 0x9b49d21dU, + 0x3e84bab8U, 0x85d25703U, 0xd8d9015eU, 0x0c38348aU, + 0xb1eb5a37U, 0x8e189608U, 0x8c98140aU, 0xf27b8974U, + 0xe66a8c60U, 0x9dcc511bU, 0xd5964353U, 0x47a2e5c1U, + 0xd2538154U, 0x2bd5feadU, 0xf67e8870U, 0x7d1469fbU, + 0x587921deU, 0xc5824743U, 0xb8a1193eU, 0x99c9501fU, + 0x23dffca5U, 0xab75de2dU, 0x269abca0U, 0x1d6c719bU, + 0x07f2f581U, 0x5af9a3dcU, 0xe4ea0e62U, 0x328bb9b4U, + 0xb36bd835U, 0xb4ae1a32U, 0x37cef9b1U, 0xc2478544U, + 0x96069010U, 0xeb25ce6dU, 0xc6428440U, 0x7f94ebf9U, + 0x412766c7U, 0xaa359f2cU, 0x68452deeU, 0x0eb8b688U, + 0x89dd540fU, 0x889d150eU, 0x0abdb78cU, 0x678aede1U, + 0x5bb9e2ddU, 0x593960dfU, 0xc8cd054eU, 0x7ed4aaf8U, + 0x9a09931cU, 0xf1bb4a77U, 0x644a2ee2U, 0xf0fb0b76U, + 0x0ff8f789U, 0x82179504U, 0xa9f55c2fU, 0x368eb8b0U, + 0x354e7bb3U, 0x394178bfU, 0x92039114U, 0x5efca2d8U, + 0x513362d7U, 0x05727783U, 0xff34cb79U, 0xba219b3cU, + 0x779ee9f1U, 0x3bc1fabdU, 0xa8b51d2eU, 0xb9e1583fU, + 0x553663d3U, 0xcd88454bU, 0xe26f8d64U, 0x406727c6U, + 0xece00c6aU, 0x04323682U, 0xacb01c2aU, 0xeda04d6bU, + 0x1969709fU, 0xf5be4b73U, 0xd313c055U, 0x1eacb298U, + 0x00373786U, 0x1c2c309aU, 0x650a6fe3U, 0x785129feU, + 0x90831316U, 0x10233396U, 0x751e6bf3U, 0x8a1d970cU, + 0xc702c541U, 0x94861212U, 0x8dd8550bU, 0xc98d444fU, + 0xea658f6cU, 0xdb19c25dU, 0x083d358eU, 0xdd9c415bU, + 0xa5fa5f23U, 0x4c6824caU, 0x9c8c101aU, 0x0bfdf68dU, + 0x16a6b090U, 0x8752d501U, 0xb76ed931U, 0xee608e68U, + 0x3fc4fbb9U, 0x6ac5afecU, 0xbe249a38U, 0xdf1cc359U, + 0x95c65313U, 0x8b5dd60dU, 0x745e2af2U, 0x42e7a5c4U, + 0x1aa9b39cU, 0x4bade6cdU, 0x5fbce3d9U, 0xaf70df29U, + 0x739be8f5U, 0x11637297U, 0xc0c70746U, 0x12a3b194U, + 0x17e6f191U, 0x2e90bea8U, 0xe1af4e67U, 0x06b2b480U, + 0xfa718b7cU, 0x446226c2U, 0xfcf4087aU, 0xc1874647U, + 0x229fbda4U, 0xda59835cU, 0x5c7c20daU, 0x547622d2U, + 0x43a7e4c5U, 0xa63a9c20U, 0x52f3a1d4U, 0x1be9f29dU, + 0xe0ef0f66U, 0x4fa8e7c9U, 0x1fecf399U, 0x2c103caaU, + 0x9e0c9218U, 0x0d78758bU, 0xbf64db39U, 0x15667393U, + 0x9746d111U, 0x300b3bb6U, 0x1829319eU, 0x3a81bbbcU, + 0xa0bf1f26U, 0xd999405fU, 0xadf05d2bU, 0x29557cafU, + 0xc307c445U, 0xfb31ca7dU, 0x486d25ceU, 0x81d75607U, + 0xef20cf69U, 0x638fece5U, 0xae309e28U, 0x28153daeU, + 0x9889111eU, 0x6b85eeedU, 0x3d4479bbU, 0x5d3c61dbU, + 0x215f7ea7U, 0x255a7fa3U, 0xf9b1487fU, 0xd1934257U, + 0xa23f9d24U, 0xf8f1097eU, 0x2a95bfacU, 0xde5c8258U, + 0x7ad1abfcU, 0xe32fcc65U, 0x66caace0U, 0x69056cefU, + 0xd0d30356U, 0xf33bc875U, 0xe5aa4f63U, 0x91c35217U, + 0xe8e50d6eU, 0xd4d60252U, 0xfdb4497bU, 0xf73ec971U, + 0xbca4183aU, 0x9343d015U, 0x507323d6U, 0xb62e9830U, + 0x02b7b584U, 0xa37fdc25U, 0x791168ffU, 0x62cfade4U, + 0x201f3fa6U, 0x452267c3U, 0xd716c151U, 0xdcdc005aU, + 0x76dea8f0U, 0x03f7f485U, 0x46e2a4c0U, 0x56f6a0d0U, + 0xb22b9934U, 0x314b7ab7U, 0xca4d874cU, 0xbde4593bU, + 0xa4ba1e22U, 0xce488648U, 0x492d64cfU, 0x6d006debU, + 0x01777687U, 0x72dba9f4U, 0x53b3e0d5U, 0xb0ab1b36U, + 0x8357d405U, 0x2d507dabU, 0x8f58d709U, 0x86129400U, + 0xf4fe0a72U, 0x57b6e1d1U, 0x610f6ee7U, 0x27dafda1U, + 0x7c5428faU, 0xe72acd61U, 0xa1ff5e27U, 0x14263292U, + 0x711b6af7U, 0x2fd0ffa9U, 0xe9a54c6fU, 0x6c402ceaU, + 0xcb0dc64dU, 0xbb61da3dU, 0x705b2bf6U, 0xb5ee5b33U, + 0x2396b53bU, 0x3ac8f222U, 0xdf558ac7U, 0x831e9d9bU, + 0x4be4af53U, 0xff7d82e7U, 0x8cd15d94U, 0xa673d5beU, + 0x20567638U, 0xa276d4baU, 0x285c7430U, 0x73d2a16bU, + 0xd89048c0U, 0x970f988fU, 0xc8844cd0U, 0x6c096574U, + 0xd49f4bccU, 0xe5e306fdU, 0x12eaf80aU, 0xa1b617b9U, + 0xd09a4ac8U, 0x825edc9aU, 0x680c6470U, 0x77d7a06fU, + 0xd21ac8caU, 0x694c2571U, 0x3447732cU, 0xe0a646f8U, + 0x5d752845U, 0x6286e47aU, 0x60066678U, 0x1ee5fb06U, + 0x0af4fe12U, 0x71522369U, 0x39083121U, 0xab3c97b3U, + 0x3ecdf326U, 0xc74b8cdfU, 0x1ae0fa02U, 0x918a1b89U, + 0xb4e753acU, 0x291c3531U, 0x543f6b4cU, 0x7557226dU, + 0xcf418ed7U, 0x47ebac5fU, 0xca04ced2U, 0xf1f203e9U, + 0xeb6c87f3U, 0xb667d1aeU, 0x08747c10U, 0xde15cbc6U, + 0x5ff5aa47U, 0x58306840U, 0xdb508bc3U, 0x2ed9f736U, + 0x7a98e262U, 0x07bbbc1fU, 0x2adcf632U, 0x930a998bU, + 0xadb914b5U, 0x46abed5eU, 0x84db5f9cU, 0xe226c4faU, + 0x6543267dU, 0x6403677cU, 0xe623c5feU, 0x8b149f93U, + 0xb72790afU, 0xb5a712adU, 0x2453773cU, 0x924ad88aU, + 0x7697e16eU, 0x1d253805U, 0x88d45c90U, 0x1c657904U, + 0xe36685fbU, 0x6e89e776U, 0x456b2e5dU, 0xda10cac2U, + 0xd9d009c1U, 0xd5df0acdU, 0x7e9de366U, 0xb262d0aaU, + 0xbdad10a5U, 0xe9ec05f1U, 0x13aab90bU, 0x56bfe94eU, + 0x9b009b83U, 0xd75f88cfU, 0x442b6f5cU, 0x557f2a4dU, + 0xb9a811a1U, 0x21163739U, 0x0ef1ff16U, 0xacf955b4U, + 0x007e7e18U, 0xe8ac44f0U, 0x402e6e58U, 0x013e3f19U, + 0xf5f702edU, 0x19203901U, 0x3f8db227U, 0xf232c0eaU, + 0xeca945f4U, 0xf0b242e8U, 0x89941d91U, 0x94cf5b8cU, + 0x7c1d6164U, 0xfcbd41e4U, 0x99801981U, 0x6683e57eU, + 0x2b9cb733U, 0x78186060U, 0x61462779U, 0x2513363dU, + 0x06fbfd1eU, 0x3787b02fU, 0xe4a347fcU, 0x31023329U, + 0x49642d51U, 0xa0f656b8U, 0x70126268U, 0xe76384ffU, + 0xfa38c2e2U, 0x6bcca773U, 0x5bf0ab43U, 0x02fefc1aU, + 0xd35a89cbU, 0x865bdd9eU, 0x52bae84aU, 0x3382b12bU, + 0x79582161U, 0x67c3a47fU, 0x98c05880U, 0xae79d7b6U, + 0xf637c1eeU, 0xa73394bfU, 0xb32291abU, 0x43eead5bU, + 0x9f059a87U, 0xfdfd00e5U, 0x2c597534U, 0xfe3dc3e6U, + 0xfb7883e3U, 0xc20eccdaU, 0x0d313c15U, 0xea2cc6f2U, + 0x16eff90eU, 0xa8fc54b0U, 0x106a7a08U, 0x2d193435U, + 0xce01cfd6U, 0x36c7f12eU, 0xb0e252a8U, 0xb8e850a0U, + 0xaf3996b7U, 0x4aa4ee52U, 0xbe6dd3a6U, 0xf77780efU, + 0x0c717d14U, 0xa33695bbU, 0xf37281ebU, 0xc08e4ed8U, + 0x7292e06aU, 0xe1e607f9U, 0x53faa94bU, 0xf9f801e1U, + 0x7bd8a363U, 0xdc9549c4U, 0xf4b743ecU, 0xd61fc9ceU, + 0x4c216d54U, 0x3507322dU, 0x416e2f59U, 0xc5cb0eddU, + 0x2f99b637U, 0x17afb80fU, 0xa4f357bcU, 0x6d492475U, + 0x03bebd1bU, 0x8f119e97U, 0x42aeec5aU, 0xc48b4fdcU, + 0x7417636cU, 0x871b9c9fU, 0xd1da0bc9U, 0xb1a213a9U, + 0xcdc10cd5U, 0xc9c40dd1U, 0x152f3a0dU, 0x3d0d3025U, + 0x4ea1ef56U, 0x146f7b0cU, 0xc60bcddeU, 0x32c2f02aU, + 0x964fd98eU, 0x0fb1be17U, 0x8a54de92U, 0x859b1e9dU, + 0x3c4d7124U, 0x1fa5ba07U, 0x09343d11U, 0x7d5d2065U, + 0x047b7f1cU, 0x38487020U, 0x112a3b09U, 0x1ba0bb03U, + 0x503a6a48U, 0x7fdda267U, 0xbced51a4U, 0x5ab0ea42U, + 0xee29c7f6U, 0x4fe1ae57U, 0x958f1a8dU, 0x8e51df96U, + 0xcc814dd4U, 0xa9bc15b1U, 0x3b88b323U, 0x30427228U, + 0x9a40da82U, 0xef6986f7U, 0xaa7cd6b2U, 0xba68d2a2U, + 0x5eb5eb46U, 0xddd508c5U, 0x26d3f53eU, 0x517a2b49U, + 0x48246c50U, 0x22d6f43aU, 0xa5b316bdU, 0x819e1f99U, + 0xede904f5U, 0x9e45db86U, 0xbf2d92a7U, 0x5c356944U, + 0x6fc9a677U, 0xc1ce0fd9U, 0x63c6a57bU, 0x6a8ce672U, + 0x18607800U, 0xbb2893a3U, 0x8d911c95U, 0xcb448fd3U, + 0x90ca5a88U, 0x0bb4bf13U, 0x4d612c55U, 0xf8b840e0U, + 0x9d851885U, 0xc34e8ddbU, 0x053b3e1dU, 0x80de5e98U, + 0x2793b43fU, 0x57ffa84fU, 0x9cc55984U, 0x59702941U, + 0x6b7d1698U, 0x72235181U, 0x97be2964U, 0xcbf53e38U, + 0x030f0cf0U, 0xb7962144U, 0xc43afe37U, 0xee98761dU, + 0x68bdd59bU, 0xea9d7719U, 0x60b7d793U, 0x3b3902c8U, + 0x907beb63U, 0xdfe43b2cU, 0x806fef73U, 0x24e2c6d7U, + 0x9c74e86fU, 0xad08a55eU, 0x5a015ba9U, 0xe95db41aU, + 0x9871e96bU, 0xcab57f39U, 0x20e7c7d3U, 0x3f3c03ccU, + 0x9af16b69U, 0x21a786d2U, 0x7cacd08fU, 0xa84de55bU, + 0x159e8be6U, 0x2a6d47d9U, 0x28edc5dbU, 0x560e58a5U, + 0x421f5db1U, 0x39b980caU, 0x71e39282U, 0xe3d73410U, + 0x76265085U, 0x8fa02f7cU, 0x520b59a1U, 0xd961b82aU, + 0xfc0cf00fU, 0x61f79692U, 0x1cd4c8efU, 0x3dbc81ceU, + 0x87aa2d74U, 0x0f000ffcU, 0x82ef6d71U, 0xb919a04aU, + 0xa3872450U, 0xfe8c720dU, 0x409fdfb3U, 0x96fe6865U, + 0x171e09e4U, 0x10dbcbe3U, 0x93bb2860U, 0x66325495U, + 0x327341c1U, 0x4f501fbcU, 0x62375591U, 0xdbe13a28U, + 0xe552b716U, 0x0e404efdU, 0xcc30fc3fU, 0xaacd6759U, + 0x2da885deU, 0x2ce8c4dfU, 0xaec8665dU, 0xc3ff3c30U, + 0xffcc330cU, 0xfd4cb10eU, 0x6cb8d49fU, 0xdaa17b29U, + 0x3e7c42cdU, 0x55ce9ba6U, 0xc03fff33U, 0x548edaa7U, + 0xab8d2658U, 0x266244d5U, 0x0d808dfeU, 0x92fb6961U, + 0x913baa62U, 0x9d34a96eU, 0x367640c5U, 0xfa897309U, + 0xf546b306U, 0xa107a652U, 0x5b411aa8U, 0x1e544aedU, + 0xd3eb3820U, 0x9fb42b6cU, 0x0cc0ccffU, 0x1d9489eeU, + 0xf143b202U, 0x69fd949aU, 0x461a5cb5U, 0xe412f617U, + 0x4895ddbbU, 0xa047e753U, 0x08c5cdfbU, 0x49d59cbaU, + 0xbd1ca14eU, 0x51cb9aa2U, 0x77661184U, 0xbad96349U, + 0xa442e657U, 0xb859e14bU, 0xc17fbe32U, 0xdc24f82fU, + 0x34f6c2c7U, 0xb456e247U, 0xd16bba22U, 0x2e6846ddU, + 0x63771490U, 0x30f3c3c3U, 0x29ad84daU, 0x6df8959eU, + 0x4e105ebdU, 0x7f6c138cU, 0xac48e45fU, 0x79e9908aU, + 0x018f8ef2U, 0xe81df51bU, 0x38f9c1cbU, 0xaf88275cU, + 0xb2d36141U, 0x232704d0U, 0x131b08e0U, 0x4a155fb9U, + 0x9bb12a68U, 0xceb07e3dU, 0x1a514be9U, 0x7b691288U, + 0x31b382c2U, 0x2f2807dcU, 0xd02bfb23U, 0xe6927415U, + 0xbedc624dU, 0xefd8371cU, 0xfbc93208U, 0x0b050ef8U, + 0xd7ee3924U, 0xb516a346U, 0x64b2d697U, 0xb6d66045U, + 0xb3932040U, 0x8ae56f79U, 0x45da9fb6U, 0xa2c76551U, + 0x5e045aadU, 0xe017f713U, 0x5881d9abU, 0x65f29796U, + 0x86ea6c75U, 0x7e2c528dU, 0xf809f10bU, 0xf003f303U, + 0xe7d23514U, 0x024f4df1U, 0xf6867005U, 0xbf9c234cU, + 0x449adeb7U, 0xebdd3618U, 0xbb992248U, 0x8865ed7bU, + 0x3a7943c9U, 0xa90da45aU, 0x1b110ae8U, 0xb113a242U, + 0x333300c0U, 0x947eea67U, 0xbc5ce04fU, 0x9ef46a6dU, + 0x04cacef7U, 0x7dec918eU, 0x09858cfaU, 0x8d20ad7eU, + 0x67721594U, 0x5f441bacU, 0xec18f41fU, 0x25a287d6U, + 0x4b551eb8U, 0xc7fa3d34U, 0x0a454ff9U, 0x8c60ec7fU, + 0x3cfcc0cfU, 0xcff03f3cU, 0x9931a86aU, 0xf949b00aU, + 0x852aaf76U, 0x812fae72U, 0x5dc499aeU, 0x75e69386U, + 0x064a4cf5U, 0x5c84d8afU, 0x8ee06e7dU, 0x7a295389U, + 0xdea47a2dU, 0x475a1db4U, 0xc2bf7d31U, 0xcd70bd3eU, + 0x74a6d287U, 0x574e19a4U, 0x41df9eb2U, 0x35b683c6U, + 0x4c90dcbfU, 0x70a3d383U, 0x59c198aaU, 0x534b18a0U, + 0x18d1c9ebU, 0x373601c4U, 0xf406f207U, 0x125b49e1U, + 0xa6c26455U, 0x070a0df4U, 0xdd64b92eU, 0xc6ba7c35U, + 0x846aee77U, 0xe157b612U, 0x73631080U, 0x78a9d18bU, + 0xd2ab7921U, 0xa7822554U, 0xe2977511U, 0xf2837101U, + 0x165e48e5U, 0x953eab66U, 0x6e38569dU, 0x199188eaU, + 0x00cfcff3U, 0x6a3d5799U, 0xed58b51eU, 0xc975bc3aU, + 0xa502a756U, 0xd6ae7825U, 0xf7c63104U, 0x14decae7U, + 0x272205d4U, 0x8925ac7aU, 0x2b2d06d8U, 0x226745d1U, + 0x508bdba3U, 0xf3c33000U, 0xc57abf36U, 0x83af2c70U, + 0xd821f92bU, 0x435f1cb0U, 0x058a8ff6U, 0xb053e343U, + 0xd56ebb26U, 0x8ba52e78U, 0x4dd09dbeU, 0xc835fd3bU, + 0x6f78179cU, 0x1f140becU, 0xd42efa27U, 0x119b8ae2U, + 0xd2f220aeU, 0xcbac67b7U, 0x2e311f52U, 0x727a080eU, + 0xba803ac6U, 0x0e191772U, 0x7db5c801U, 0x5717402bU, + 0xd132e3adU, 0x5312412fU, 0xd938e1a5U, 0x82b634feU, + 0x29f4dd55U, 0x666b0d1aU, 0x39e0d945U, 0x9d6df0e1U, + 0x25fbde59U, 0x14879368U, 0xe38e6d9fU, 0x50d2822cU, + 0x21fedf5dU, 0x733a490fU, 0x9968f1e5U, 0x86b335faU, + 0x237e5d5fU, 0x9828b0e4U, 0xc523e6b9U, 0x11c2d36dU, + 0xac11bdd0U, 0x93e271efU, 0x9162f3edU, 0xef816e93U, + 0xfb906b87U, 0x8036b6fcU, 0xc86ca4b4U, 0x5a580226U, + 0xcfa966b3U, 0x362f194aU, 0xeb846f97U, 0x60ee8e1cU, + 0x4583c639U, 0xd878a0a4U, 0xa55bfed9U, 0x8433b7f8U, + 0x3e251b42U, 0xb68f39caU, 0x3b605b47U, 0x0096967cU, + 0x1a081266U, 0x4703443bU, 0xf910e985U, 0x2f715e53U, + 0xae913fd2U, 0xa954fdd5U, 0x2a341e56U, 0xdfbd62a3U, + 0x8bfc77f7U, 0xf6df298aU, 0xdbb863a7U, 0x626e0c1eU, + 0x5cdd8120U, 0xb7cf78cbU, 0x75bfca09U, 0x1342516fU, + 0x9427b3e8U, 0x9567f2e9U, 0x1747506bU, 0x7a700a06U, + 0x4643053aU, 0x44c38738U, 0xd537e2a9U, 0x632e4d1fU, + 0x87f374fbU, 0xec41ad90U, 0x79b0c905U, 0xed01ec91U, + 0x1202106eU, 0x9fed72e3U, 0xb40fbbc8U, 0x2b745f57U, + 0x28b49c54U, 0x24bb9f58U, 0x8ff976f3U, 0x4306453fU, + 0x4cc98530U, 0x18889064U, 0xe2ce2c9eU, 0xa7db7cdbU, + 0x6a640e16U, 0x263b1d5aU, 0xb54ffac9U, 0xa41bbfd8U, + 0x48cc8434U, 0xd072a2acU, 0xff956a83U, 0x5d9dc021U, + 0xf11aeb8dU, 0x19c8d165U, 0xb14afbcdU, 0xf05aaa8cU, + 0x04939778U, 0xe844ac94U, 0xcee927b2U, 0x0356557fU, + 0x1dcdd061U, 0x01d6d77dU, 0x78f08804U, 0x65abce19U, + 0x8d79f4f1U, 0x0dd9d471U, 0x68e48c14U, 0x97e770ebU, + 0xdaf822a6U, 0x897cf5f5U, 0x9022b2ecU, 0xd477a3a8U, + 0xf79f688bU, 0xc6e325baU, 0x15c7d269U, 0xc066a6bcU, + 0xb800b8c4U, 0x5192c32dU, 0x8176f7fdU, 0x1607116aU, + 0x0b5c5777U, 0x9aa832e6U, 0xaa943ed6U, 0xf39a698fU, + 0x223e1c5eU, 0x773f480bU, 0xa3de7ddfU, 0xc2e624beU, + 0x883cb4f4U, 0x96a731eaU, 0x69a4cd15U, 0x5f1d4223U, + 0x0753547bU, 0x5657012aU, 0x4246043eU, 0xb28a38ceU, + 0x6e610f12U, 0x0c999570U, 0xdd3de0a1U, 0x0f595673U, + 0x0a1c1676U, 0x336a594fU, 0xfc55a980U, 0x1b485367U, + 0xe78b6c9bU, 0x5998c125U, 0xe10eef9dU, 0xdc7da1a0U, + 0x3f655a43U, 0xc7a364bbU, 0x4186c73dU, 0x498cc535U, + 0x5e5d0322U, 0xbbc07bc7U, 0x4f094633U, 0x0613157aU, + 0xfd15e881U, 0x5252002eU, 0x0216147eU, 0x31eadb4dU, + 0x83f675ffU, 0x1082926cU, 0xa29e3cdeU, 0x089c9474U, + 0x8abc36f6U, 0x2df1dc51U, 0x05d3d679U, 0x277b5c5bU, + 0xbd45f8c1U, 0xc463a7b8U, 0xb00abaccU, 0x34af9b48U, + 0xdefd23a2U, 0xe6cb2d9aU, 0x5597c229U, 0x9c2db1e0U, + 0xf2da288eU, 0x7e750b02U, 0xb3ca79cfU, 0x35efda49U, + 0x8573f6f9U, 0x767f090aU, 0x20be9e5cU, 0x40c6863cU, + 0x3ca59940U, 0x38a09844U, 0xe44baf98U, 0xcc69a5b0U, + 0xbfc57ac3U, 0xe50bee99U, 0x376f584bU, 0xc3a665bfU, + 0x672b4c1bU, 0xfed52b82U, 0x7b304b07U, 0x74ff8b08U, + 0xcd29e4b1U, 0xeec12f92U, 0xf850a884U, 0x8c39b5f0U, + 0xf51fea89U, 0xc92ce5b5U, 0xe04eae9cU, 0xeac42e96U, + 0xa15effddU, 0x8eb937f2U, 0x4d89c431U, 0xabd47fd7U, + 0x1f4d5263U, 0xbe853bc2U, 0x64eb8f18U, 0x7f354a03U, + 0x3de5d841U, 0x58d88024U, 0xcaec26b6U, 0xc126e7bdU, + 0x6b244f17U, 0x1e0d1362U, 0x5b184327U, 0x4b0c4737U, + 0xafd17ed3U, 0x2cb19d50U, 0xd7b760abU, 0xa01ebedcU, + 0xb940f9c5U, 0xd3b261afU, 0x54d78328U, 0x70fa8a0cU, + 0x1c8d9160U, 0x6f214e13U, 0x4e490732U, 0xad51fcd1U, + 0x9ead33e2U, 0x30aa9a4cU, 0x92a230eeU, 0x9be873e7U, + 0xe904ed95U, 0x4a4c0636U, 0x7cf58900U, 0x3a201a46U, + 0x61aecf1dU, 0xfad02a86U, 0xbc05b9c0U, 0x09dcd575U, + 0x6ce18d10U, 0x322a184eU, 0xf45fab88U, 0x71bacb0dU, + 0xd6f721aaU, 0xa69b3ddaU, 0x6da1cc11U, 0xa814bcd4U, + 0x076166e8U, 0x1e3f21f1U, 0xfba25914U, 0xa7e94e48U, + 0x6f137c80U, 0xdb8a5134U, 0xa8268e47U, 0x8284066dU, + 0x04a1a5ebU, 0x86810769U, 0x0caba7e3U, 0x572572b8U, + 0xfc679b13U, 0xb3f84b5cU, 0xec739f03U, 0x48feb6a7U, + 0xf068981fU, 0xc114d52eU, 0x361d2bd9U, 0x8541c46aU, + 0xf46d991bU, 0xa6a90f49U, 0x4cfbb7a3U, 0x532073bcU, + 0xf6ed1b19U, 0x4dbbf6a2U, 0x10b0a0ffU, 0xc451952bU, + 0x7982fb96U, 0x467137a9U, 0x44f1b5abU, 0x3a1228d5U, + 0x2e032dc1U, 0x55a5f0baU, 0x1dffe2f2U, 0x8fcb4460U, + 0x1a3a20f5U, 0xe3bc5f0cU, 0x3e1729d1U, 0xb57dc85aU, + 0x9010807fU, 0x0debe6e2U, 0x70c8b89fU, 0x51a0f1beU, + 0xebb65d04U, 0x631c7f8cU, 0xeef31d01U, 0xd505d03aU, + 0xcf9b5420U, 0x9290027dU, 0x2c83afc3U, 0xfae21815U, + 0x7b027994U, 0x7cc7bb93U, 0xffa75810U, 0x0a2e24e5U, + 0x5e6f31b1U, 0x234c6fccU, 0x0e2b25e1U, 0xb7fd4a58U, + 0x894ec766U, 0x625c3e8dU, 0xa02c8c4fU, 0xc6d11729U, + 0x41b4f5aeU, 0x40f4b4afU, 0xc2d4162dU, 0xafe34c40U, + 0x93d0437cU, 0x9150c17eU, 0x00a4a4efU, 0xb6bd0b59U, + 0x526032bdU, 0x39d2ebd6U, 0xac238f43U, 0x3892aad7U, + 0xc7915628U, 0x4a7e34a5U, 0x619cfd8eU, 0xfee71911U, + 0xfd27da12U, 0xf128d91eU, 0x5a6a30b5U, 0x96950379U, + 0x995ac376U, 0xcd1bd622U, 0x375d6ad8U, 0x72483a9dU, + 0xbff74850U, 0xf3a85b1cU, 0x60dcbc8fU, 0x7188f99eU, + 0x9d5fc272U, 0x05e1e4eaU, 0x2a062cc5U, 0x880e8667U, + 0x2489adcbU, 0xcc5b9723U, 0x64d9bd8bU, 0x25c9eccaU, + 0xd100d13eU, 0x3dd7ead2U, 0x1b7a61f4U, 0xd6c51339U, + 0xc85e9627U, 0xd445913bU, 0xad63ce42U, 0xb038885fU, + 0x58eab2b7U, 0xd84a9237U, 0xbd77ca52U, 0x427436adU, + 0x0f6b64e0U, 0x5cefb3b3U, 0x45b1f4aaU, 0x01e4e5eeU, + 0x220c2ecdU, 0x137063fcU, 0xc054942fU, 0x15f5e0faU, + 0x6d93fe82U, 0x8401856bU, 0x54e5b1bbU, 0xc394572cU, + 0xdecf1131U, 0x4f3b74a0U, 0x7f077890U, 0x26092fc9U, + 0xf7ad5a18U, 0xa2ac0e4dU, 0x764d3b99U, 0x177562f8U, + 0x5daff2b2U, 0x433477acU, 0xbc378b53U, 0x8a8e0465U, + 0xd2c0123dU, 0x83c4476cU, 0x97d54278U, 0x67197e88U, + 0xbbf24954U, 0xd90ad336U, 0x08aea6e7U, 0xdaca1035U, + 0xdf8f5030U, 0xe6f91f09U, 0x29c6efc6U, 0xcedb1521U, + 0x32182addU, 0x8c0b8763U, 0x349da9dbU, 0x09eee7e6U, + 0xeaf61c05U, 0x123022fdU, 0x9415817bU, 0x9c1f8373U, + 0x8bce4564U, 0x6e533d81U, 0x9a9a0075U, 0xd380533cU, + 0x2886aec7U, 0x87c14668U, 0xd7855238U, 0xe4799d0bU, + 0x566533b9U, 0xc511d42aU, 0x770d7a98U, 0xdd0fd232U, + 0x5f2f70b0U, 0xf8629a17U, 0xd040903fU, 0xf2e81a1dU, + 0x68d6be87U, 0x11f0e1feU, 0x6599fc8aU, 0xe13cdd0eU, + 0x0b6e65e4U, 0x33586bdcU, 0x8004846fU, 0x49bef7a6U, + 0x27496ec8U, 0xabe64d44U, 0x66593f89U, 0xe07c9c0fU, + 0x50e0b0bfU, 0xa3ec4f4cU, 0xf52dd81aU, 0x9555c07aU, + 0xe936df06U, 0xed33de02U, 0x31d8e9deU, 0x19fae3f6U, + 0x6a563c85U, 0x3098a8dfU, 0xe2fc1e0dU, 0x163523f9U, + 0xb2b80a5dU, 0x2b466dc4U, 0xaea30d41U, 0xa16ccd4eU, + 0x18baa2f7U, 0x3b5269d4U, 0x2dc3eec2U, 0x59aaf3b6U, + 0x208caccfU, 0x1cbfa3f3U, 0x35dde8daU, 0x3f5768d0U, + 0x74cdb99bU, 0x5b2a71b4U, 0x981a8277U, 0x7e473991U, + 0xcade1425U, 0x6b167d84U, 0xb178c95eU, 0xaaa60c45U, + 0xe8769e07U, 0x8d4bc662U, 0x1f7f60f0U, 0x14b5a1fbU, + 0xbeb70951U, 0xcb9e5524U, 0x8e8b0561U, 0x9e9f0171U, + 0x7a423895U, 0xf922db16U, 0x022426edU, 0x758df89aU, + 0x6cd3bf83U, 0x062127e9U, 0x8144c56eU, 0xa569cc4aU, + 0xc91ed726U, 0xbab20855U, 0x9bda4174U, 0x78c2ba97U, + 0x4b3e75a4U, 0xe539dc0aU, 0x473176a8U, 0x4e7b35a1U, + 0x3c97abd3U, 0x9fdf4070U, 0xa966cf46U, 0xefb35c00U, + 0xb43d895bU, 0x2f436cc0U, 0x6996ff86U, 0xdc4f9333U, + 0xb972cb56U, 0xe7b95e08U, 0x21ccedceU, 0xa4298d4bU, + 0x036467ecU, 0x73087b9cU, 0xb8328a57U, 0x7d87fa92U, + 0x89b43db3U, 0x90ea7aaaU, 0x7577024fU, 0x293c1513U, + 0xe1c627dbU, 0x555f0a6fU, 0x26f3d51cU, 0x0c515d36U, + 0x8a74feb0U, 0x08545c32U, 0x827efcb8U, 0xd9f029e3U, + 0x72b2c048U, 0x3d2d1007U, 0x62a6c458U, 0xc62bedfcU, + 0x7ebdc344U, 0x4fc18e75U, 0xb8c87082U, 0x0b949f31U, + 0x7ab8c240U, 0x287c5412U, 0xc22eecf8U, 0xddf528e7U, + 0x78384042U, 0xc36eadf9U, 0x9e65fba4U, 0x4a84ce70U, + 0xf757a0cdU, 0xc8a46cf2U, 0xca24eef0U, 0xb4c7738eU, + 0xa0d6769aU, 0xdb70abe1U, 0x932ab9a9U, 0x011e1f3bU, + 0x94ef7baeU, 0x6d690457U, 0xb0c2728aU, 0x3ba89301U, + 0x1ec5db24U, 0x833ebdb9U, 0xfe1de3c4U, 0xdf75aae5U, + 0x6563065fU, 0xedc924d7U, 0x6026465aU, 0x5bd08b61U, + 0x414e0f7bU, 0x1c455926U, 0xa256f498U, 0x7437434eU, + 0xf5d722cfU, 0xf212e0c8U, 0x7172034bU, 0x84fb7fbeU, + 0xd0ba6aeaU, 0xad993497U, 0x80fe7ebaU, 0x39281103U, + 0x079b9c3dU, 0xec8965d6U, 0x2ef9d714U, 0x48044c72U, + 0xcf61aef5U, 0xce21eff4U, 0x4c014d76U, 0x2136171bU, + 0x1d051827U, 0x1f859a25U, 0x8e71ffb4U, 0x38685002U, + 0xdcb569e6U, 0xb707b08dU, 0x22f6d418U, 0xb647f18cU, + 0x49440d73U, 0xc4ab6ffeU, 0xef49a6d5U, 0x7032424aU, + 0x73f28149U, 0x7ffd8245U, 0xd4bf6beeU, 0x18405822U, + 0x178f982dU, 0x43ce8d79U, 0xb9883183U, 0xfc9d61c6U, + 0x3122130bU, 0x7d7d0047U, 0xee09e7d4U, 0xff5da2c5U, + 0x138a9929U, 0x8b34bfb1U, 0xa4d3779eU, 0x06dbdd3cU, + 0xaa5cf690U, 0x428ecc78U, 0xea0ce6d0U, 0xab1cb791U, + 0x5fd58a65U, 0xb302b189U, 0x95af3aafU, 0x58104862U, + 0x468bcd7cU, 0x5a90ca60U, 0x23b69519U, 0x3eedd304U, + 0xd63fe9ecU, 0x569fc96cU, 0x33a29109U, 0xcca16df6U, + 0x81be3fbbU, 0xd23ae8e8U, 0xcb64aff1U, 0x8f31beb5U, + 0xacd97596U, 0x9da538a7U, 0x4e81cf74U, 0x9b20bba1U, + 0xe346a5d9U, 0x0ad4de30U, 0xda30eae0U, 0x4d410c77U, + 0x501a4a6aU, 0xc1ee2ffbU, 0xf1d223cbU, 0xa8dc7492U, + 0x79780143U, 0x2c795516U, 0xf89860c2U, 0x99a039a3U, + 0xd37aa9e9U, 0xcde12cf7U, 0x32e2d008U, 0x045b5f3eU, + 0x5c154966U, 0x0d111c37U, 0x19001923U, 0xe9cc25d3U, + 0x3527120fU, 0x57df886dU, 0x867bfdbcU, 0x541f4b6eU, + 0x515a0b6bU, 0x682c4452U, 0xa713b49dU, 0x400e4e7aU, + 0xbccd7186U, 0x02dedc38U, 0xba48f280U, 0x873bbcbdU, + 0x6423475eU, 0x9ce579a6U, 0x1ac0da20U, 0x12cad828U, + 0x051b1e3fU, 0xe08666daU, 0x144f5b2eU, 0x5d550867U, + 0xa653f59cU, 0x09141d33U, 0x59500963U, 0x6aacc650U, + 0xd8b068e2U, 0x4bc48f71U, 0xf9d821c3U, 0x53da8969U, + 0xd1fa2bebU, 0x76b7c14cU, 0x5e95cb64U, 0x7c3d4146U, + 0xe603e5dcU, 0x9f25baa5U, 0xeb4ca7d1U, 0x6fe98655U, + 0x85bb3ebfU, 0xbd8d3087U, 0x0ed1df34U, 0xc76bacfdU, + 0xa99c3593U, 0x2533161fU, 0xe88c64d2U, 0x6ea9c754U, + 0xde35ebe4U, 0x2d391417U, 0x7bf88341U, 0x1b809b21U, + 0x67e3845dU, 0x63e68559U, 0xbf0db285U, 0x972fb8adU, + 0xe48367deU, 0xbe4df384U, 0x6c294556U, 0x98e078a2U, + 0x3c6d5106U, 0xa593369fU, 0x2076561aU, 0x2fb99615U, + 0x966ff9acU, 0xb587328fU, 0xa316b599U, 0xd77fa8edU, + 0xae59f794U, 0x926af8a8U, 0xbb08b381U, 0xb182338bU, + 0xfa18e2c0U, 0xd5ff2aefU, 0x16cfd92cU, 0xf09262caU, + 0x440b4f7eU, 0xe5c326dfU, 0x3fad9205U, 0x2473571eU, + 0x66a3c55cU, 0x039e9d39U, 0x91aa3babU, 0x9a60faa0U, + 0x3062520aU, 0x454b0e7fU, 0x005e5e3aU, 0x104a5a2aU, + 0xf49763ceU, 0x77f7804dU, 0x8cf17db6U, 0xfb58a3c1U, + 0xe206e4d8U, 0x88f47cb2U, 0x0f919e35U, 0x2bbc9711U, + 0x47cb8c7dU, 0x3467530eU, 0x150f1a2fU, 0xf617e1ccU, + 0xc5eb2effU, 0x6bec8751U, 0xc9e42df3U, 0xc0ae6efaU, + 0xb242f088U, 0x110a1b2bU, 0x27b3941dU, 0x6166075bU, + 0x3ae8d200U, 0xa196379bU, 0xe743a4ddU, 0x529ac868U, + 0x37a7900dU, 0x696c0553U, 0xaf19b695U, 0x2afcd610U, + 0x8db13cb7U, 0xfddd20c7U, 0x36e7d10cU, 0xf352a1c9U, + 0xf751a628U, 0xee0fe131U, 0x0b9299d4U, 0x57d98e88U, + 0x9f23bc40U, 0x2bba91f4U, 0x58164e87U, 0x72b4c6adU, + 0xf491652bU, 0x76b1c7a9U, 0xfc9b6723U, 0xa715b278U, + 0x0c575bd3U, 0x43c88b9cU, 0x1c435fc3U, 0xb8ce7667U, + 0x005858dfU, 0x312415eeU, 0xc62deb19U, 0x757104aaU, + 0x045d59dbU, 0x5699cf89U, 0xbccb7763U, 0xa310b37cU, + 0x06dddbd9U, 0xbd8b3662U, 0xe080603fU, 0x346155ebU, + 0x89b23b56U, 0xb641f769U, 0xb4c1756bU, 0xca22e815U, + 0xde33ed01U, 0xa595307aU, 0xedcf2232U, 0x7ffb84a0U, + 0xea0ae035U, 0x138c9fccU, 0xce27e911U, 0x454d089aU, + 0x602040bfU, 0xfddb2622U, 0x80f8785fU, 0xa190317eU, + 0x1b869dc4U, 0x932cbf4cU, 0x1ec3ddc1U, 0x253510faU, + 0x3fab94e0U, 0x62a0c2bdU, 0xdcb36f03U, 0x0ad2d8d5U, + 0x8b32b954U, 0x8cf77b53U, 0x0f9798d0U, 0xfa1ee425U, + 0xae5ff171U, 0xd37caf0cU, 0xfe1be521U, 0x47cd8a98U, + 0x797e07a6U, 0x926cfe4dU, 0x501c4c8fU, 0x36e1d7e9U, + 0xb184356eU, 0xb0c4746fU, 0x32e4d6edU, 0x5fd38c80U, + 0x63e083bcU, 0x616001beU, 0xf094642fU, 0x468dcb99U, + 0xa250f27dU, 0xc9e22b16U, 0x5c134f83U, 0xc8a26a17U, + 0x37a196e8U, 0xba4ef465U, 0x91ac3d4eU, 0x0ed7d9d1U, + 0x0d171ad2U, 0x011819deU, 0xaa5af075U, 0x66a5c3b9U, + 0x696a03b6U, 0x3d2b16e2U, 0xc76daa18U, 0x8278fa5dU, + 0x4fc78890U, 0x03989bdcU, 0x90ec7c4fU, 0x81b8395eU, + 0x6d6f02b2U, 0xf5d1242aU, 0xda36ec05U, 0x783e46a7U, + 0xd4b96d0bU, 0x3c6b57e3U, 0x94e97d4bU, 0xd5f92c0aU, + 0x213011feU, 0xcde72a12U, 0xeb4aa134U, 0x26f5d3f9U, + 0x386e56e7U, 0x247551fbU, 0x5d530e82U, 0x4008489fU, + 0xa8da7277U, 0x287a52f7U, 0x4d470a92U, 0xb244f66dU, + 0xff5ba420U, 0xacdf7373U, 0xb581346aU, 0xf1d4252eU, + 0xd23cee0dU, 0xe340a33cU, 0x306454efU, 0xe5c5203aU, + 0x9da33e42U, 0x743145abU, 0xa4d5717bU, 0x33a497ecU, + 0x2effd1f1U, 0xbf0bb460U, 0x8f37b850U, 0xd639ef09U, + 0x079d9ad8U, 0x529cce8dU, 0x867dfb59U, 0xe745a238U, + 0xad9f3272U, 0xb304b76cU, 0x4c074b93U, 0x7abec4a5U, + 0x22f0d2fdU, 0x73f487acU, 0x67e582b8U, 0x9729be48U, + 0x4bc28994U, 0x293a13f6U, 0xf89e6627U, 0x2afad0f5U, + 0x2fbf90f0U, 0x16c9dfc9U, 0xd9f62f06U, 0x3eebd5e1U, + 0xc228ea1dU, 0x7c3b47a3U, 0xc4ad691bU, 0xf9de2726U, + 0x1ac6dcc5U, 0xe200e23dU, 0x642541bbU, 0x6c2f43b3U, + 0x7bfe85a4U, 0x9e63fd41U, 0x6aaac0b5U, 0x23b093fcU, + 0xd8b66e07U, 0x77f186a8U, 0x27b592f8U, 0x14495dcbU, + 0xa655f379U, 0x352114eaU, 0x873dba58U, 0x2d3f12f2U, + 0xaf1fb070U, 0x08525ad7U, 0x207050ffU, 0x02d8daddU, + 0x98e67e47U, 0xe1c0213eU, 0x95a93c4aU, 0x110c1dceU, + 0xfb5ea524U, 0xc368ab1cU, 0x703444afU, 0xb98e3766U, + 0xd779ae08U, 0x5bd68d84U, 0x9669ff49U, 0x104c5ccfU, + 0xa0d0707fU, 0x53dc8f8cU, 0x051d18daU, 0x656500baU, + 0x19061fc6U, 0x1d031ec2U, 0xc1e8291eU, 0xe9ca2336U, + 0x9a66fc45U, 0xc0a8681fU, 0x12ccdecdU, 0xe605e339U, + 0x4288ca9dU, 0xdb76ad04U, 0x5e93cd81U, 0x515c0d8eU, + 0xe88a6237U, 0xcb62a914U, 0xddf32e02U, 0xa99a3376U, + 0xd0bc6c0fU, 0xec8f6333U, 0xc5ed281aU, 0xcf67a810U, + 0x84fd795bU, 0xab1ab174U, 0x682a42b7U, 0x8e77f951U, + 0x3aeed4e5U, 0x9b26bd44U, 0x4148099eU, 0x5a96cc85U, + 0x18465ec7U, 0x7d7b06a2U, 0xef4fa030U, 0xe485613bU, + 0x4e87c991U, 0x3bae95e4U, 0x7ebbc5a1U, 0x6eafc1b1U, + 0x8a72f855U, 0x09121bd6U, 0xf214e62dU, 0x85bd385aU, + 0x9ce37f43U, 0xf611e729U, 0x717405aeU, 0x55590c8aU, + 0x392e17e6U, 0x4a82c895U, 0x6bea81b4U, 0x88f27a57U, + 0xbb0eb564U, 0x15091ccaU, 0xb701b668U, 0xbe4bf561U, + 0xcca76b13U, 0x6fef80b0U, 0x59560f86U, 0x1f839cc0U, + 0x440d499bU, 0xdf73ac00U, 0x99a63f46U, 0x2c7f53f3U, + 0x49420b96U, 0x17899ec8U, 0xd1fc2d0eU, 0x54194d8bU, + 0xf354a72cU, 0x8338bb5cU, 0x48024a97U, 0x8db73a52U, + 0x22c2e06eU, 0x3b9ca777U, 0xde01df92U, 0x824ac8ceU, + 0x4ab0fa06U, 0xfe29d7b2U, 0x8d8508c1U, 0xa72780ebU, + 0x2102236dU, 0xa32281efU, 0x29082165U, 0x7286f43eU, + 0xd9c41d95U, 0x965bcddaU, 0xc9d01985U, 0x6d5d3021U, + 0xd5cb1e99U, 0xe4b753a8U, 0x13bead5fU, 0xa0e242ecU, + 0xd1ce1f9dU, 0x830a89cfU, 0x69583125U, 0x7683f53aU, + 0xd34e9d9fU, 0x68187024U, 0x35132679U, 0xe1f213adU, + 0x5c217d10U, 0x63d2b12fU, 0x6152332dU, 0x1fb1ae53U, + 0x0ba0ab47U, 0x7006763cU, 0x385c6474U, 0xaa68c2e6U, + 0x3f99a673U, 0xc61fd98aU, 0x1bb4af57U, 0x90de4edcU, + 0xb5b306f9U, 0x28486064U, 0x556b3e19U, 0x74037738U, + 0xce15db82U, 0x46bff90aU, 0xcb509b87U, 0xf0a656bcU, + 0xea38d2a6U, 0xb73384fbU, 0x09202945U, 0xdf419e93U, + 0x5ea1ff12U, 0x59643d15U, 0xda04de96U, 0x2f8da263U, + 0x7bccb737U, 0x06efe94aU, 0x2b88a367U, 0x925eccdeU, + 0xaced41e0U, 0x47ffb80bU, 0x858f0ac9U, 0xe37291afU, + 0x64177328U, 0x65573229U, 0xe77790abU, 0x8a40cac6U, + 0xb673c5faU, 0xb4f347f8U, 0x25072269U, 0x931e8ddfU, + 0x77c3b43bU, 0x1c716d50U, 0x898009c5U, 0x1d312c51U, + 0xe232d0aeU, 0x6fddb223U, 0x443f7b08U, 0xdb449f97U, + 0xd8845c94U, 0xd48b5f98U, 0x7fc9b633U, 0xb33685ffU, + 0xbcf945f0U, 0xe8b850a4U, 0x12feec5eU, 0x57ebbc1bU, + 0x9a54ced6U, 0xd60bdd9aU, 0x457f3a09U, 0x542b7f18U, + 0xb8fc44f4U, 0x2042626cU, 0x0fa5aa43U, 0xadad00e1U, + 0x012a2b4dU, 0xe9f811a5U, 0x417a3b0dU, 0x006a6a4cU, + 0xf4a357b8U, 0x18746c54U, 0x3ed9e772U, 0xf36695bfU, + 0xedfd10a1U, 0xf1e617bdU, 0x88c048c4U, 0x959b0ed9U, + 0x7d493431U, 0xfde914b1U, 0x98d44cd4U, 0x67d7b02bU, + 0x2ac8e266U, 0x794c3535U, 0x6012722cU, 0x24476368U, + 0x07afa84bU, 0x36d3e57aU, 0xe5f712a9U, 0x3056667cU, + 0x48307804U, 0xa1a203edU, 0x7146373dU, 0xe637d1aaU, + 0xfb6c97b7U, 0x6a98f226U, 0x5aa4fe16U, 0x03aaa94fU, + 0xd20edc9eU, 0x870f88cbU, 0x53eebd1fU, 0x32d6e47eU, + 0x780c7434U, 0x6697f12aU, 0x99940dd5U, 0xaf2d82e3U, + 0xf76394bbU, 0xa667c1eaU, 0xb276c4feU, 0x42baf80eU, + 0x9e51cfd2U, 0xfca955b0U, 0x2d0d2061U, 0xff6996b3U, + 0xfa2cd6b6U, 0xc35a998fU, 0x0c656940U, 0xeb7893a7U, + 0x17bbac5bU, 0xa9a801e5U, 0x113e2f5dU, 0x2c4d6160U, + 0xcf559a83U, 0x3793a47bU, 0xb1b607fdU, 0xb9bc05f5U, + 0xae6dc3e2U, 0x4bf0bb07U, 0xbf3986f3U, 0xf623d5baU, + 0x0d252841U, 0xa262c0eeU, 0xf226d4beU, 0xc1da1b8dU, + 0x73c6b53fU, 0xe0b252acU, 0x52aefc1eU, 0xf8ac54b4U, + 0x7a8cf636U, 0xddc11c91U, 0xf5e316b9U, 0xd74b9c9bU, + 0x4d753801U, 0x34536778U, 0x403a7a0cU, 0xc49f5b88U, + 0x2ecde362U, 0x16fbed5aU, 0xa5a702e9U, 0x6c1d7120U, + 0x02eae84eU, 0x8e45cbc2U, 0x43fab90fU, 0xc5df1a89U, + 0x75433639U, 0x864fc9caU, 0xd08e5e9cU, 0xb0f646fcU, + 0xcc955980U, 0xc8905884U, 0x147b6f58U, 0x3c596570U, + 0x4ff5ba03U, 0x153b2e59U, 0xc75f988bU, 0x3396a57fU, + 0x971b8cdbU, 0x0ee5eb42U, 0x8b008bc7U, 0x84cf4bc8U, + 0x3d192471U, 0x1ef1ef52U, 0x08606844U, 0x7c097530U, + 0x052f2a49U, 0x391c2575U, 0x107e6e5cU, 0x1af4ee56U, + 0x516e3f1dU, 0x7e89f732U, 0xbdb904f1U, 0x5be4bf17U, + 0xef7d92a3U, 0x4eb5fb02U, 0x94db4fd8U, 0x8f058ac3U, + 0xcdd51881U, 0xa8e840e4U, 0x3adce676U, 0x3116277dU, + 0x9b148fd7U, 0xee3dd3a2U, 0xab2883e7U, 0xbb3c87f7U, + 0x5fe1be13U, 0xdc815d90U, 0x2787a06bU, 0x502e7e1cU, + 0x49703905U, 0x2382a16fU, 0xa4e743e8U, 0x80ca4accU, + 0xecbd51a0U, 0x9f118ed3U, 0xbe79c7f2U, 0x5d613c11U, + 0x6e9df322U, 0xc09a5a8cU, 0x6292f02eU, 0x6bd8b327U, + 0x19342d55U, 0xba7cc6f6U, 0x8cc549c0U, 0xca10da86U, + 0x919e0fddU, 0x0ae0ea46U, 0x4c357900U, 0xf9ec15b5U, + 0x9cd14dd0U, 0xc21ad88eU, 0x046f6b48U, 0x818a0bcdU, + 0x26c7e16aU, 0x56abfd1aU, 0x9d910cd1U, 0x58247c14U, + 0xfbae55dbU, 0xe2f012c2U, 0x076d6a27U, 0x5b267d7bU, + 0x93dc4fb3U, 0x27456207U, 0x54e9bd74U, 0x7e4b355eU, + 0xf86e96d8U, 0x7a4e345aU, 0xf06494d0U, 0xabea418bU, + 0x00a8a820U, 0x4f37786fU, 0x10bcac30U, 0xb4318594U, + 0x0ca7ab2cU, 0x3ddbe61dU, 0xcad218eaU, 0x798ef759U, + 0x08a2aa28U, 0x5a663c7aU, 0xb0348490U, 0xafef408fU, + 0x0a22282aU, 0xb174c591U, 0xec7f93ccU, 0x389ea618U, + 0x854dc8a5U, 0xbabe049aU, 0xb83e8698U, 0xc6dd1be6U, + 0xd2cc1ef2U, 0xa96ac389U, 0xe130d1c1U, 0x73047753U, + 0xe6f513c6U, 0x1f736c3fU, 0xc2d81ae2U, 0x49b2fb69U, + 0x6cdfb34cU, 0xf124d5d1U, 0x8c078bacU, 0xad6fc28dU, + 0x17796e37U, 0x9fd34cbfU, 0x123c2e32U, 0x29cae309U, + 0x33546713U, 0x6e5f314eU, 0xd04c9cf0U, 0x062d2b26U, + 0x87cd4aa7U, 0x800888a0U, 0x03686b23U, 0xf6e117d6U, + 0xa2a00282U, 0xdf835cffU, 0xf2e416d2U, 0x4b32796bU, + 0x7581f455U, 0x9e930dbeU, 0x5ce3bf7cU, 0x3a1e241aU, + 0xbd7bc69dU, 0xbc3b879cU, 0x3e1b251eU, 0x532c7f73U, + 0x6f1f704fU, 0x6d9ff24dU, 0xfc6b97dcU, 0x4a72386aU, + 0xaeaf018eU, 0xc51dd8e5U, 0x50ecbc70U, 0xc45d99e4U, + 0x3b5e651bU, 0xb6b10796U, 0x9d53cebdU, 0x02282a22U, + 0x01e8e921U, 0x0de7ea2dU, 0xa6a50386U, 0x6a5a304aU, + 0x6595f045U, 0x31d4e511U, 0xcb9259ebU, 0x8e8709aeU, + 0x43387b63U, 0x0f67682fU, 0x9c138fbcU, 0x8d47caadU, + 0x6190f141U, 0xf92ed7d9U, 0xd6c91ff6U, 0x74c1b554U, + 0xd8469ef8U, 0x3094a410U, 0x98168eb8U, 0xd906dff9U, + 0x2dcfe20dU, 0xc118d9e1U, 0xe7b552c7U, 0x2a0a200aU, + 0x3491a514U, 0x288aa208U, 0x51acfd71U, 0x4cf7bb6cU, + 0xa4258184U, 0x2485a104U, 0x41b8f961U, 0xbebb059eU, + 0xf3a457d3U, 0xa0208080U, 0xb97ec799U, 0xfd2bd6ddU, + 0xdec31dfeU, 0xefbf50cfU, 0x3c9ba71cU, 0xe93ad3c9U, + 0x915ccdb1U, 0x78ceb658U, 0xa82a8288U, 0x3f5b641fU, + 0x22002202U, 0xb3f44793U, 0x83c84ba3U, 0xdac61cfaU, + 0x0b62692bU, 0x5e633d7eU, 0x8a8208aaU, 0xebba51cbU, + 0xa160c181U, 0xbffb449fU, 0x40f8b860U, 0x76413756U, + 0x2e0f210eU, 0x7f0b745fU, 0x6b1a714bU, 0x9bd64dbbU, + 0x473d7a67U, 0x25c5e005U, 0xf46195d4U, 0x26052306U, + 0x23406303U, 0x1a362c3aU, 0xd509dcf5U, 0x32142612U, + 0xced719eeU, 0x70c4b450U, 0xc8529ae8U, 0xf521d4d5U, + 0x16392f36U, 0xeeff11ceU, 0x68dab248U, 0x60d0b040U, + 0x77017657U, 0x929c0eb2U, 0x66553346U, 0x2f4f600fU, + 0xd4499df4U, 0x7b0e755bU, 0x2b4a610bU, 0x18b6ae38U, + 0xaaaa008aU, 0x39dee719U, 0x8bc249abU, 0x21c0e101U, + 0xa3e04383U, 0x04ada924U, 0x2c8fa30cU, 0x0e27292eU, + 0x94198db4U, 0xed3fd2cdU, 0x9956cfb9U, 0x1df3ee3dU, + 0xf7a156d7U, 0xcf9758efU, 0x7ccbb75cU, 0xb571c495U, + 0xdb865dfbU, 0x57297e77U, 0x9a960cbaU, 0x1cb3af3cU, + 0xac2f838cU, 0x5f237c7fU, 0x09e2eb29U, 0x699af349U, + 0x15f9ec35U, 0x11fced31U, 0xcd17daedU, 0xe535d0c5U, + 0x96990fb6U, 0xcc579becU, 0x1e332d3eU, 0xeafa10caU, + 0x4e77396eU, 0xd7895ef7U, 0x526c3e72U, 0x5da3fe7dU, + 0xe47591c4U, 0xc79d5ae7U, 0xd10cddf1U, 0xa565c085U, + 0xdc439ffcU, 0xe07090c0U, 0xc912dbe9U, 0xc3985be3U, + 0x88028aa8U, 0xa7e54287U, 0x64d5b144U, 0x82880aa2U, + 0x36112716U, 0x97d94eb7U, 0x4db7fa6dU, 0x56693f76U, + 0x14b9ad34U, 0x7184f551U, 0xe3b053c3U, 0xe87a92c8U, + 0x42783a62U, 0x37516617U, 0x72443652U, 0x62503242U, + 0x868d0ba6U, 0x05ede825U, 0xfeeb15deU, 0x8942cba9U, + 0x901c8cb0U, 0xfaee14daU, 0x7d8bf65dU, 0x59a6ff79U, + 0x35d1e415U, 0x467d3b66U, 0x67157247U, 0x840d89a4U, + 0xb7f14697U, 0x19f6ef39U, 0xbbfe459bU, 0xb2b40692U, + 0xc05898e0U, 0x63107343U, 0x55a9fc75U, 0x137c6f33U, + 0x48f2ba68U, 0xd38c5ff3U, 0x9559ccb5U, 0x2080a000U, + 0x45bdf865U, 0x1b766d3bU, 0xdd03defdU, 0x58e6be78U, + 0xffab54dfU, 0x8fc748afU, 0x44fdb964U, 0x8148c9a1U, + 0xc6f630beU, 0xdfa877a7U, 0x3a350f42U, 0x667e181eU, + 0xae842ad6U, 0x1a1d0762U, 0x69b1d811U, 0x4313503bU, + 0xc536f3bdU, 0x4716513fU, 0xcd3cf1b5U, 0x96b224eeU, + 0x3df0cd45U, 0x726f1d0aU, 0x2de4c955U, 0x8969e0f1U, + 0x31ffce49U, 0x00838378U, 0xf78a7d8fU, 0x44d6923cU, + 0x35facf4dU, 0x673e591fU, 0x8d6ce1f5U, 0x92b725eaU, + 0x377a4d4fU, 0x8c2ca0f4U, 0xd127f6a9U, 0x05c6c37dU, + 0xb815adc0U, 0x87e661ffU, 0x8566e3fdU, 0xfb857e83U, + 0xef947b97U, 0x9432a6ecU, 0xdc68b4a4U, 0x4e5c1236U, + 0xdbad76a3U, 0x222b095aU, 0xff807f87U, 0x74ea9e0cU, + 0x5187d629U, 0xcc7cb0b4U, 0xb15feec9U, 0x9037a7e8U, + 0x2a210b52U, 0xa28b29daU, 0x2f644b57U, 0x1492866cU, + 0x0e0c0276U, 0x5307542bU, 0xed14f995U, 0x3b754e43U, + 0xba952fc2U, 0xbd50edc5U, 0x3e300e46U, 0xcbb972b3U, + 0x9ff867e7U, 0xe2db399aU, 0xcfbc73b7U, 0x766a1c0eU, + 0x48d99130U, 0xa3cb68dbU, 0x61bbda19U, 0x0746417fU, + 0x8023a3f8U, 0x8163e2f9U, 0x0343407bU, 0x6e741a16U, + 0x5247152aU, 0x50c79728U, 0xc133f2b9U, 0x772a5d0fU, + 0x93f764ebU, 0xf845bd80U, 0x6db4d915U, 0xf905fc81U, + 0x0606007eU, 0x8be962f3U, 0xa00babd8U, 0x3f704f47U, + 0x3cb08c44U, 0x30bf8f48U, 0x9bfd66e3U, 0x5702552fU, + 0x58cd9520U, 0x0c8c8074U, 0xf6ca3c8eU, 0xb3df6ccbU, + 0x7e601e06U, 0x323f0d4aU, 0xa14bead9U, 0xb01fafc8U, + 0x5cc89424U, 0xc476b2bcU, 0xeb917a93U, 0x4999d031U, + 0xe51efb9dU, 0x0dccc175U, 0xa54eebddU, 0xe45eba9cU, + 0x10978768U, 0xfc40bc84U, 0xdaed37a2U, 0x1752456fU, + 0x09c9c071U, 0x15d2c76dU, 0x6cf49814U, 0x71afde09U, + 0x997de4e1U, 0x19ddc461U, 0x7ce09c04U, 0x83e360fbU, + 0xcefc32b6U, 0x9d78e5e5U, 0x8426a2fcU, 0xc073b3b8U, + 0xe39b789bU, 0xd2e735aaU, 0x01c3c279U, 0xd462b6acU, + 0xac04a8d4U, 0x4596d33dU, 0x9572e7edU, 0x0203017aU, + 0x1f584767U, 0x8eac22f6U, 0xbe902ec6U, 0xe79e799fU, + 0x363a0c4eU, 0x633b581bU, 0xb7da6dcfU, 0xd6e234aeU, + 0x9c38a4e4U, 0x82a321faU, 0x7da0dd05U, 0x4b195233U, + 0x1357446bU, 0x4253113aU, 0x5642142eU, 0xa68e28deU, + 0x7a651f02U, 0x189d8560U, 0xc939f0b1U, 0x1b5d4663U, + 0x1e180666U, 0x276e495fU, 0xe851b990U, 0x0f4c4377U, + 0xf38f7c8bU, 0x4d9cd135U, 0xf50aff8dU, 0xc879b1b0U, + 0x2b614a53U, 0xd3a774abU, 0x5582d72dU, 0x5d88d525U, + 0x4a591332U, 0xafc46bd7U, 0x5b0d5623U, 0x1217056aU, + 0xe911f891U, 0x4656103eU, 0x1612046eU, 0x25eecb5dU, + 0x97f265efU, 0x0486827cU, 0xb69a2cceU, 0x1c988464U, + 0x9eb826e6U, 0x39f5cc41U, 0x11d7c669U, 0x337f4c4bU, + 0xa941e8d1U, 0xd067b7a8U, 0xa40eaadcU, 0x20ab8b58U, + 0xcaf933b2U, 0xf2cf3d8aU, 0x4193d239U, 0x8829a1f0U, + 0xe6de389eU, 0x6a711b12U, 0xa7ce69dfU, 0x21ebca59U, + 0x9177e6e9U, 0x627b191aU, 0x34ba8e4cU, 0x54c2962cU, + 0x28a18950U, 0x2ca48854U, 0xf04fbf88U, 0xd86db5a0U, + 0xabc16ad3U, 0xf10ffe89U, 0x236b485bU, 0xd7a275afU, + 0x732f5c0bU, 0xead13b92U, 0x6f345b17U, 0x60fb9b18U, + 0xd92df4a1U, 0xfac53f82U, 0xec54b894U, 0x983da5e0U, + 0xe11bfa99U, 0xdd28f5a5U, 0xf44abe8cU, 0xfec03e86U, + 0xb55aefcdU, 0x9abd27e2U, 0x598dd421U, 0xbfd06fc7U, + 0x0b494273U, 0xaa812bd2U, 0x70ef9f08U, 0x6b315a13U, + 0x29e1c851U, 0x4cdc9034U, 0xdee836a6U, 0xd522f7adU, + 0x7f205f07U, 0x0a090372U, 0x4f1c5337U, 0x5f085727U, + 0xbbd56ec3U, 0x38b58d40U, 0xc3b370bbU, 0xb41aaeccU, + 0xad44e9d5U, 0xc7b671bfU, 0x40d39338U, 0x64fe9a1cU, + 0x08898170U, 0x7b255e03U, 0x5a4d1722U, 0xb955ecc1U, + 0x8aa923f2U, 0x24ae8a5cU, 0x86a620feU, 0x8fec63f7U, + 0xfd00fd85U, 0x5e481626U, 0x68f19910U, 0x2e240a56U, + 0x75aadf0dU, 0xeed43a96U, 0xa801a9d0U, 0x1dd8c565U, + 0x78e59d00U, 0x262e085eU, 0xe05bbb98U, 0x65bedb1dU, + 0xc2f331baU, 0xb29f2dcaU, 0x79a5dc01U, 0xbc10acc4U, + 0x0d636ee0U, 0x143d29f9U, 0xf1a0511cU, 0xadeb4640U, + 0x65117488U, 0xd188593cU, 0xa224864fU, 0x88860e65U, + 0x0ea3ade3U, 0x8c830f61U, 0x06a9afebU, 0x5d277ab0U, + 0xf665931bU, 0xb9fa4354U, 0xe671970bU, 0x42fcbeafU, + 0xfa6a9017U, 0xcb16dd26U, 0x3c1f23d1U, 0x8f43cc62U, + 0xfe6f9113U, 0xacab0741U, 0x46f9bfabU, 0x59227bb4U, + 0xfcef1311U, 0x47b9feaaU, 0x1ab2a8f7U, 0xce539d23U, + 0x7380f39eU, 0x4c733fa1U, 0x4ef3bda3U, 0x301020ddU, + 0x240125c9U, 0x5fa7f8b2U, 0x17fdeafaU, 0x85c94c68U, + 0x103828fdU, 0xe9be5704U, 0x341521d9U, 0xbf7fc052U, + 0x9a128877U, 0x07e9eeeaU, 0x7acab097U, 0x5ba2f9b6U, + 0xe1b4550cU, 0x691e7784U, 0xe4f11509U, 0xdf07d832U, + 0xc5995c28U, 0x98920a75U, 0x2681a7cbU, 0xf0e0101dU, + 0x7100719cU, 0x76c5b39bU, 0xf5a55018U, 0x002c2cedU, + 0x546d39b9U, 0x294e67c4U, 0x04292de9U, 0xbdff4250U, + 0x834ccf6eU, 0x685e3685U, 0xaa2e8447U, 0xccd31f21U, + 0x4bb6fda6U, 0x4af6bca7U, 0xc8d61e25U, 0xa5e14448U, + 0x99d24b74U, 0x9b52c976U, 0x0aa6ace7U, 0xbcbf0351U, + 0x58623ab5U, 0x33d0e3deU, 0xa621874bU, 0x3290a2dfU, + 0xcd935e20U, 0x407c3cadU, 0x6b9ef586U, 0xf4e51119U, + 0xf725d21aU, 0xfb2ad116U, 0x506838bdU, 0x9c970b71U, + 0x9358cb7eU, 0xc719de2aU, 0x3d5f62d0U, 0x784a3295U, + 0xb5f54058U, 0xf9aa5314U, 0x6adeb487U, 0x7b8af196U, + 0x975dca7aU, 0x0fe3ece2U, 0x200424cdU, 0x820c8e6fU, + 0x2e8ba5c3U, 0xc6599f2bU, 0x6edbb583U, 0x2fcbe4c2U, + 0xdb02d936U, 0x37d5e2daU, 0x117869fcU, 0xdcc71b31U, + 0xc25c9e2fU, 0xde479933U, 0xa761c64aU, 0xba3a8057U, + 0x52e8babfU, 0xd2489a3fU, 0xb775c25aU, 0x48763ea5U, + 0x05696ce8U, 0x56edbbbbU, 0x4fb3fca2U, 0x0be6ede6U, + 0x280e26c5U, 0x19726bf4U, 0xca569c27U, 0x1ff7e8f2U, + 0x6791f68aU, 0x8e038d63U, 0x5ee7b9b3U, 0xc9965f24U, + 0xd4cd1939U, 0x45397ca8U, 0x75057098U, 0x2c0b27c1U, + 0xfdaf5210U, 0xa8ae0645U, 0x7c4f3391U, 0x1d776af0U, + 0x57adfabaU, 0x49367fa4U, 0xb635835bU, 0x808c0c6dU, + 0xd8c21a35U, 0x89c64f64U, 0x9dd74a70U, 0x6d1b7680U, + 0xb1f0415cU, 0xd308db3eU, 0x02acaeefU, 0xd0c8183dU, + 0xd58d5838U, 0xecfb1701U, 0x23c4e7ceU, 0xc4d91d29U, + 0x381a22d5U, 0x86098f6bU, 0x3e9fa1d3U, 0x03ecefeeU, + 0xe0f4140dU, 0x18322af5U, 0x9e178973U, 0x961d8b7bU, + 0x81cc4d6cU, 0x64513589U, 0x9098087dU, 0xd9825b34U, + 0x2284a6cfU, 0x8dc34e60U, 0xdd875a30U, 0xee7b9503U, + 0x5c673bb1U, 0xcf13dc22U, 0x7d0f7290U, 0xd70dda3aU, + 0x552d78b8U, 0xf260921fU, 0xda429837U, 0xf8ea1215U, + 0x62d4b68fU, 0x1bf2e9f6U, 0x6f9bf482U, 0xeb3ed506U, + 0x016c6decU, 0x395a63d4U, 0x8a068c67U, 0x43bcffaeU, + 0x2d4b66c0U, 0xa1e4454cU, 0x6c5b3781U, 0xea7e9407U, + 0x5ae2b8b7U, 0xa9ee4744U, 0xff2fd012U, 0x9f57c872U, + 0xe334d70eU, 0xe731d60aU, 0x3bdae1d6U, 0x13f8ebfeU, + 0x6054348dU, 0x3a9aa0d7U, 0xe8fe1605U, 0x1c372bf1U, + 0xb8ba0255U, 0x214465ccU, 0xa4a10549U, 0xab6ec546U, + 0x12b8aaffU, 0x315061dcU, 0x27c1e6caU, 0x53a8fbbeU, + 0x2a8ea4c7U, 0x16bdabfbU, 0x3fdfe0d2U, 0x355560d8U, + 0x7ecfb193U, 0x512879bcU, 0x92188a7fU, 0x74453199U, + 0xc0dc1c2dU, 0x6114758cU, 0xbb7ac156U, 0xa0a4044dU, + 0xe274960fU, 0x8749ce6aU, 0x157d68f8U, 0x1eb7a9f3U, + 0xb4b50159U, 0xc19c5d2cU, 0x84890d69U, 0x949d0979U, + 0x7040309dU, 0xf320d31eU, 0x08262ee5U, 0x7f8ff092U, + 0x66d1b78bU, 0x0c232fe1U, 0x8b46cd66U, 0xaf6bc442U, + 0xc31cdf2eU, 0xb0b0005dU, 0x91d8497cU, 0x72c0b29fU, + 0x413c7dacU, 0xef3bd402U, 0x4d337ea0U, 0x44793da9U, + 0x3695a3dbU, 0x95dd4878U, 0xa364c74eU, 0xe5b15408U, + 0xbe3f8153U, 0x254164c8U, 0x6394f78eU, 0xd64d9b3bU, + 0xb370c35eU, 0xedbb5600U, 0x2bcee5c6U, 0xae2b8543U, + 0x09666fe4U, 0x790a7394U, 0xb230825fU, 0x7785f29aU, + 0x78d0a826U, 0x618eef3fU, 0x841397daU, 0xd8588086U, + 0x10a2b24eU, 0xa43b9ffaU, 0xd7974089U, 0xfd35c8a3U, + 0x7b106b25U, 0xf930c9a7U, 0x731a692dU, 0x2894bc76U, + 0x83d655ddU, 0xcc498592U, 0x93c251cdU, 0x374f7869U, + 0x8fd956d1U, 0xbea51be0U, 0x49ace517U, 0xfaf00aa4U, + 0x8bdc57d5U, 0xd918c187U, 0x334a796dU, 0x2c91bd72U, + 0x895cd5d7U, 0x320a386cU, 0x6f016e31U, 0xbbe05be5U, + 0x06333558U, 0x39c0f967U, 0x3b407b65U, 0x45a3e61bU, + 0x51b2e30fU, 0x2a143e74U, 0x624e2c3cU, 0xf07a8aaeU, + 0x658bee3bU, 0x9c0d91c2U, 0x41a6e71fU, 0xcacc0694U, + 0xefa14eb1U, 0x725a282cU, 0x0f797651U, 0x2e113f70U, + 0x940793caU, 0x1cadb142U, 0x9142d3cfU, 0xaab41ef4U, + 0xb02a9aeeU, 0xed21ccb3U, 0x5332610dU, 0x8553d6dbU, + 0x04b3b75aU, 0x0376755dU, 0x801696deU, 0x759fea2bU, + 0x21deff7fU, 0x5cfda102U, 0x719aeb2fU, 0xc84c8496U, + 0xf6ff09a8U, 0x1dedf043U, 0xdf9d4281U, 0xb960d9e7U, + 0x3e053b60U, 0x3f457a61U, 0xbd65d8e3U, 0xd052828eU, + 0xec618db2U, 0xeee10fb0U, 0x7f156a21U, 0xc90cc597U, + 0x2dd1fc73U, 0x46632518U, 0xd392418dU, 0x47236419U, + 0xb82098e6U, 0x35cffa6bU, 0x1e2d3340U, 0x8156d7dfU, + 0x829614dcU, 0x8e9917d0U, 0x25dbfe7bU, 0xe924cdb7U, + 0xe6eb0db8U, 0xb2aa18ecU, 0x48eca416U, 0x0df9f453U, + 0xc046869eU, 0x8c1995d2U, 0x1f6d7241U, 0x0e393750U, + 0xe2ee0cbcU, 0x7a502a24U, 0x55b7e20bU, 0xf7bf48a9U, + 0x5b386305U, 0xb3ea59edU, 0x1b687345U, 0x5a782204U, + 0xaeb11ff0U, 0x4266241cU, 0x64cbaf3aU, 0xa974ddf7U, + 0xb7ef58e9U, 0xabf45ff5U, 0xd2d2008cU, 0xcf894691U, + 0x275b7c79U, 0xa7fb5cf9U, 0xc2c6049cU, 0x3dc5f863U, + 0x70daaa2eU, 0x235e7d7dU, 0x3a003a64U, 0x7e552b20U, + 0x5dbde003U, 0x6cc1ad32U, 0xbfe55ae1U, 0x6a442e34U, + 0x1222304cU, 0xfbb04ba5U, 0x2b547f75U, 0xbc2599e2U, + 0xa17edfffU, 0x308aba6eU, 0x00b6b65eU, 0x59b8e107U, + 0x881c94d6U, 0xdd1dc083U, 0x09fcf557U, 0x68c4ac36U, + 0x221e3c7cU, 0x3c85b962U, 0xc386459dU, 0xf53fcaabU, + 0xad71dcf3U, 0xfc7589a2U, 0xe8648cb6U, 0x18a8b046U, + 0xc443879aU, 0xa6bb1df8U, 0x771f6829U, 0xa57bdefbU, + 0xa03e9efeU, 0x9948d1c7U, 0x56772108U, 0xb16adbefU, + 0x4da9e413U, 0xf3ba49adU, 0x4b2c6715U, 0x765f2928U, + 0x9547d2cbU, 0x6d81ec33U, 0xeba44fb5U, 0xe3ae4dbdU, + 0xf47f8baaU, 0x11e2f34fU, 0xe52bcebbU, 0xac319df2U, + 0x57376009U, 0xf87088a6U, 0xa8349cf6U, 0x9bc853c5U, + 0x29d4fd77U, 0xbaa01ae4U, 0x08bcb456U, 0xa2be1cfcU, + 0x209ebe7eU, 0x87d354d9U, 0xaff15ef1U, 0x8d59d4d3U, + 0x17677049U, 0x6e412f30U, 0x1a283244U, 0x9e8d13c0U, + 0x74dfab2aU, 0x4ce9a512U, 0xffb54aa1U, 0x360f3968U, + 0x58f8a006U, 0xd457838aU, 0x19e8f147U, 0x9fcd52c1U, + 0x2f517e71U, 0xdc5d8182U, 0x8a9c16d4U, 0xeae40eb4U, + 0x968711c8U, 0x928210ccU, 0x4e692710U, 0x664b2d38U, + 0x15e7f24bU, 0x4f296611U, 0x9d4dd0c3U, 0x6984ed37U, + 0xcd09c493U, 0x54f7a30aU, 0xd112c38fU, 0xdedd0380U, + 0x670b6c39U, 0x44e3a71aU, 0x5272200cU, 0x261b3d78U, + 0x5f3d6201U, 0x630e6d3dU, 0x4a6c2614U, 0x40e6a61eU, + 0x0b7c7755U, 0x249bbf7aU, 0xe7ab4cb9U, 0x01f6f75fU, + 0xb56fdaebU, 0x14a7b34aU, 0xcec90790U, 0xd517c28bU, + 0x97c750c9U, 0xf2fa08acU, 0x60ceae3eU, 0x6b046f35U, + 0xc106c79fU, 0xb42f9beaU, 0xf13acbafU, 0xe12ecfbfU, + 0x05f3f65bU, 0x869315d8U, 0x7d95e823U, 0x0a3c3654U, + 0x1362714dU, 0x7990e927U, 0xfef50ba0U, 0xdad80284U, + 0xb6af19e8U, 0xc503c69bU, 0xe46b8fbaU, 0x07737459U, + 0x348fbb6aU, 0x9a8812c4U, 0x3880b866U, 0x31cafb6fU, + 0x4326651dU, 0xe06e8ebeU, 0xd6d70188U, 0x900292ceU, + 0xcb8c4795U, 0x50f2a20eU, 0x16273148U, 0xa3fe5dfdU, + 0xc6c30598U, 0x980890c6U, 0x5e7d2300U, 0xdb984385U, + 0x7cd5a922U, 0x0cb9b552U, 0xc7834499U, 0x0236345cU, + 0x9db02da3U, 0x84ee6abaU, 0x6173125fU, 0x3d380503U, + 0xf5c237cbU, 0x415b1a7fU, 0x32f7c50cU, 0x18554d26U, + 0x9e70eea0U, 0x1c504c22U, 0x967aeca8U, 0xcdf439f3U, + 0x66b6d058U, 0x29290017U, 0x76a2d448U, 0xd22ffdecU, + 0x6ab9d354U, 0x5bc59e65U, 0xaccc6092U, 0x1f908f21U, + 0x6ebcd250U, 0x3c784402U, 0xd62afce8U, 0xc9f138f7U, + 0x6c3c5052U, 0xd76abde9U, 0x8a61ebb4U, 0x5e80de60U, + 0xe353b0ddU, 0xdca07ce2U, 0xde20fee0U, 0xa0c3639eU, + 0xb4d2668aU, 0xcf74bbf1U, 0x872ea9b9U, 0x151a0f2bU, + 0x80eb6bbeU, 0x796d1447U, 0xa4c6629aU, 0x2fac8311U, + 0x0ac1cb34U, 0x973aada9U, 0xea19f3d4U, 0xcb71baf5U, + 0x7167164fU, 0xf9cd34c7U, 0x7422564aU, 0x4fd49b71U, + 0x554a1f6bU, 0x08414936U, 0xb652e488U, 0x6033535eU, + 0xe1d332dfU, 0xe616f0d8U, 0x6576135bU, 0x90ff6faeU, + 0xc4be7afaU, 0xb99d2487U, 0x94fa6eaaU, 0x2d2c0113U, + 0x139f8c2dU, 0xf88d75c6U, 0x3afdc704U, 0x5c005c62U, + 0xdb65bee5U, 0xda25ffe4U, 0x58055d66U, 0x3532070bU, + 0x09010837U, 0x0b818a35U, 0x9a75efa4U, 0x2c6c4012U, + 0xc8b179f6U, 0xa303a09dU, 0x36f2c408U, 0xa243e19cU, + 0x5d401d63U, 0xd0af7feeU, 0xfb4db6c5U, 0x6436525aU, + 0x67f69159U, 0x6bf99255U, 0xc0bb7bfeU, 0x0c444832U, + 0x038b883dU, 0x57ca9d69U, 0xad8c2193U, 0xe89971d6U, + 0x2526031bU, 0x69791057U, 0xfa0df7c4U, 0xeb59b2d5U, + 0x078e8939U, 0x9f30afa1U, 0xb0d7678eU, 0x12dfcd2cU, + 0xbe58e680U, 0x568adc68U, 0xfe08f6c0U, 0xbf18a781U, + 0x4bd19a75U, 0xa706a199U, 0x81ab2abfU, 0x4c145872U, + 0x528fdd6cU, 0x4e94da70U, 0x37b28509U, 0x2ae9c314U, + 0xc23bf9fcU, 0x429bd97cU, 0x27a68119U, 0xd8a57de6U, + 0x95ba2fabU, 0xc63ef8f8U, 0xdf60bfe1U, 0x9b35aea5U, + 0xb8dd6586U, 0x89a128b7U, 0x5a85df64U, 0x8f24abb1U, + 0xf742b5c9U, 0x1ed0ce20U, 0xce34faf0U, 0x59451c67U, + 0x441e5a7aU, 0xd5ea3febU, 0xe5d633dbU, 0xbcd86482U, + 0x6d7c1153U, 0x387d4506U, 0xec9c70d2U, 0x8da429b3U, + 0xc77eb9f9U, 0xd9e53ce7U, 0x26e6c018U, 0x105f4f2eU, + 0x48115976U, 0x19150c27U, 0x0d040933U, 0xfdc835c3U, + 0x2123021fU, 0x43db987dU, 0x927fedacU, 0x401b5b7eU, + 0x455e1b7bU, 0x7c285442U, 0xb317a48dU, 0x540a5e6aU, + 0xa8c96196U, 0x16dacc28U, 0xae4ce290U, 0x933facadU, + 0x7027574eU, 0x88e169b6U, 0x0ec4ca30U, 0x06cec838U, + 0x111f0e2fU, 0xf48276caU, 0x004b4b3eU, 0x49511877U, + 0xb257e58cU, 0x1d100d23U, 0x4d541973U, 0x7ea8d640U, + 0xccb478f2U, 0x5fc09f61U, 0xeddc31d3U, 0x47de9979U, + 0xc5fe3bfbU, 0x62b3d15cU, 0x4a91db74U, 0x68395156U, + 0xf207f5ccU, 0x8b21aab5U, 0xff48b7c1U, 0x7bed9645U, + 0x91bf2eafU, 0xa9892097U, 0x1ad5cf24U, 0xd36fbcedU, + 0xbd982583U, 0x3137060fU, 0xfc8874c2U, 0x7aadd744U, + 0xca31fbf4U, 0x393d0407U, 0x6ffc9351U, 0x0f848b31U, + 0x73e7944dU, 0x77e29549U, 0xab09a295U, 0x832ba8bdU, + 0xf08777ceU, 0xaa49e394U, 0x782d5546U, 0x8ce468b2U, + 0x28694116U, 0xb197268fU, 0x3472460aU, 0x3bbd8605U, + 0x826be9bcU, 0xa183229fU, 0xb712a589U, 0xc37bb8fdU, + 0xba5de784U, 0x866ee8b8U, 0xaf0ca391U, 0xa586239bU, + 0xee1cf2d0U, 0xc1fb3affU, 0x02cbc93cU, 0xe49672daU, + 0x500f5f6eU, 0xf1c736cfU, 0x2ba98215U, 0x3077470eU, + 0x72a7d54cU, 0x179a8d29U, 0x85ae2bbbU, 0x8e64eab0U, + 0x2466421aU, 0x514f1e6fU, 0x145a4e2aU, 0x044e4a3aU, + 0xe09373deU, 0x63f3905dU, 0x98f56da6U, 0xef5cb3d1U, + 0xf602f4c8U, 0x9cf06ca2U, 0x1b958e25U, 0x3fb88701U, + 0x53cf9c6dU, 0x2063431eU, 0x010b0a3fU, 0xe213f1dcU, + 0xd1ef3eefU, 0x7fe89741U, 0xdde03de3U, 0xd4aa7eeaU, + 0xa646e098U, 0x050e0b3bU, 0x33b7840dU, 0x7562174bU, + 0x2eecc210U, 0xb592278bU, 0xf347b4cdU, 0x469ed878U, + 0x23a3801dU, 0x7d681543U, 0xbb1da685U, 0x3ef8c600U, + 0x99b52ca7U, 0xe9d930d7U, 0x22e3c11cU, 0xe756b1d9U, + 0xd05a8a04U, 0xc904cd1dU, 0x2c99b5f8U, 0x70d2a2a4U, + 0xb828906cU, 0x0cb1bdd8U, 0x7f1d62abU, 0x55bfea81U, + 0xd39a4907U, 0x51baeb85U, 0xdb904b0fU, 0x801e9e54U, + 0x2b5c77ffU, 0x64c3a7b0U, 0x3b4873efU, 0x9fc55a4bU, + 0x275374f3U, 0x162f39c2U, 0xe126c735U, 0x527a2886U, + 0x235675f7U, 0x7192e3a5U, 0x9bc05b4fU, 0x841b9f50U, + 0x21d6f7f5U, 0x9a801a4eU, 0xc78b4c13U, 0x136a79c7U, + 0xaeb9177aU, 0x914adb45U, 0x93ca5947U, 0xed29c439U, + 0xf938c12dU, 0x829e1c56U, 0xcac40e1eU, 0x58f0a88cU, + 0xcd01cc19U, 0x3487b3e0U, 0xe92cc53dU, 0x624624b6U, + 0x472b6c93U, 0xdad00a0eU, 0xa7f35473U, 0x869b1d52U, + 0x3c8db1e8U, 0xb4279360U, 0x39c8f1edU, 0x023e3cd6U, + 0x18a0b8ccU, 0x45abee91U, 0xfbb8432fU, 0x2dd9f4f9U, + 0xac399578U, 0xabfc577fU, 0x289cb4fcU, 0xdd15c809U, + 0x8954dd5dU, 0xf4778320U, 0xd910c90dU, 0x60c6a6b4U, + 0x5e752b8aU, 0xb567d261U, 0x771760a3U, 0x11eafbc5U, + 0x968f1942U, 0x97cf5843U, 0x15effac1U, 0x78d8a0acU, + 0x44ebaf90U, 0x466b2d92U, 0xd79f4803U, 0x6186e7b5U, + 0x855bde51U, 0xeee9073aU, 0x7b1863afU, 0xefa9463bU, + 0x10aabac4U, 0x9d45d849U, 0xb6a71162U, 0x29dcf5fdU, + 0x2a1c36feU, 0x261335f2U, 0x8d51dc59U, 0x41aeef95U, + 0x4e612f9aU, 0x1a203aceU, 0xe0668634U, 0xa573d671U, + 0x68cca4bcU, 0x2493b7f0U, 0xb7e75063U, 0xa6b31572U, + 0x4a642e9eU, 0xd2da0806U, 0xfd3dc029U, 0x5f356a8bU, + 0xf3b24127U, 0x1b607bcfU, 0xb3e25167U, 0xf2f20026U, + 0x063b3dd2U, 0xeaec063eU, 0xcc418d18U, 0x01feffd5U, + 0x1f657acbU, 0x037e7dd7U, 0x7a5822aeU, 0x670364b3U, + 0x8fd15e5bU, 0x0f717edbU, 0x6a4c26beU, 0x954fda41U, + 0xd850880cU, 0x8bd45f5fU, 0x928a1846U, 0xd6df0902U, + 0xf537c221U, 0xc44b8f10U, 0x176f78c3U, 0xc2ce0c16U, + 0xbaa8126eU, 0x533a6987U, 0x83de5d57U, 0x14afbbc0U, + 0x09f4fdddU, 0x9800984cU, 0xa83c947cU, 0xf132c325U, + 0x2096b6f4U, 0x7597e2a1U, 0xa176d775U, 0xc04e8e14U, + 0x8a941e5eU, 0x940f9b40U, 0x6b0c67bfU, 0x5db5e889U, + 0x05fbfed1U, 0x54ffab80U, 0x40eeae94U, 0xb0229264U, + 0x6cc9a5b8U, 0x0e313fdaU, 0xdf954a0bU, 0x0df1fcd9U, + 0x08b4bcdcU, 0x31c2f3e5U, 0xfefd032aU, 0x19e0f9cdU, + 0xe523c631U, 0x5b306b8fU, 0xe3a64537U, 0xded50b0aU, + 0x3dcdf0e9U, 0xc50bce11U, 0x432e6d97U, 0x4b246f9fU, + 0x5cf5a988U, 0xb968d16dU, 0x4da1ec99U, 0x04bbbfd0U, + 0xffbd422bU, 0x50faaa84U, 0x00bebed4U, 0x334271e7U, + 0x815edf55U, 0x122a38c6U, 0xa0369674U, 0x0a343edeU, + 0x88149c5cU, 0x2f5976fbU, 0x077b7cd3U, 0x25d3f6f1U, + 0xbfed526bU, 0xc6cb0d12U, 0xb2a21066U, 0x360731e2U, + 0xdc558908U, 0xe4638730U, 0x573f6883U, 0x9e851b4aU, + 0xf0728224U, 0x7cdda1a8U, 0xb162d365U, 0x374770e3U, + 0x87db5c53U, 0x74d7a3a0U, 0x221634f6U, 0x426e2c96U, + 0x3e0d33eaU, 0x3a0832eeU, 0xe6e30532U, 0xcec10f1aU, + 0xbd6dd069U, 0xe7a34433U, 0x35c7f2e1U, 0xc10ecf15U, + 0x6583e6b1U, 0xfc7d8128U, 0x7998e1adU, 0x765721a2U, + 0xcf814e1bU, 0xec698538U, 0xfaf8022eU, 0x8e911f5aU, + 0xf7b74023U, 0xcb844f1fU, 0xe2e60436U, 0xe86c843cU, + 0xa3f65577U, 0x8c119d58U, 0x4f216e9bU, 0xa97cd57dU, + 0x1de5f8c9U, 0xbc2d9168U, 0x664325b2U, 0x7d9de0a9U, + 0x3f4d72ebU, 0x5a702a8eU, 0xc8448c1cU, 0xc38e4d17U, + 0x698ce5bdU, 0x1ca5b9c8U, 0x59b0e98dU, 0x49a4ed9dU, + 0xad79d479U, 0x2e1937faU, 0xd51fca01U, 0xa2b61476U, + 0xbbe8536fU, 0xd11acb05U, 0x567f2982U, 0x725220a6U, + 0x1e253bcaU, 0x6d89e4b9U, 0x4ce1ad98U, 0xaff9567bU, + 0x9c059948U, 0x320230e6U, 0x900a9a44U, 0x9940d94dU, + 0xebac473fU, 0x48e4ac9cU, 0x7e5d23aaU, 0x3888b0ecU, + 0x630665b7U, 0xf878802cU, 0xbead136aU, 0x0b747fdfU, + 0x6e4927baU, 0x3082b2e4U, 0xf6f70122U, 0x731261a7U, + 0xd45f8b00U, 0xa4339770U, 0x6f0966bbU, 0xaabc167eU, + 0xbc46fa74U, 0xa518bd6dU, 0x4085c588U, 0x1cced2d4U, + 0xd434e01cU, 0x60adcda8U, 0x130112dbU, 0x39a39af1U, + 0xbf863977U, 0x3da69bf5U, 0xb78c3b7fU, 0xec02ee24U, + 0x4740078fU, 0x08dfd7c0U, 0x5754039fU, 0xf3d92a3bU, + 0x4b4f0483U, 0x7a3349b2U, 0x8d3ab745U, 0x3e6658f6U, + 0x4f4a0587U, 0x1d8e93d5U, 0xf7dc2b3fU, 0xe807ef20U, + 0x4dca8785U, 0xf69c6a3eU, 0xab973c63U, 0x7f7609b7U, + 0xc2a5670aU, 0xfd56ab35U, 0xffd62937U, 0x8135b449U, + 0x9524b15dU, 0xee826c26U, 0xa6d87e6eU, 0x34ecd8fcU, + 0xa11dbc69U, 0x589bc390U, 0x8530b54dU, 0x0e5a54c6U, + 0x2b371ce3U, 0xb6cc7a7eU, 0xcbef2403U, 0xea876d22U, + 0x5091c198U, 0xd83be310U, 0x55d4819dU, 0x6e224ca6U, + 0x74bcc8bcU, 0x29b79ee1U, 0x97a4335fU, 0x41c58489U, + 0xc025e508U, 0xc7e0270fU, 0x4480c48cU, 0xb109b879U, + 0xe548ad2dU, 0x986bf350U, 0xb50cb97dU, 0x0cdad6c4U, + 0x32695bfaU, 0xd97ba211U, 0x1b0b10d3U, 0x7df68bb5U, + 0xfa936932U, 0xfbd32833U, 0x79f38ab1U, 0x14c4d0dcU, + 0x28f7dfe0U, 0x2a775de2U, 0xbb833873U, 0x0d9a97c5U, + 0xe947ae21U, 0x82f5774aU, 0x170413dfU, 0x83b5364bU, + 0x7cb6cab4U, 0xf159a839U, 0xdabb6112U, 0x45c0858dU, + 0x4600468eU, 0x4a0f4582U, 0xe14dac29U, 0x2db29fe5U, + 0x227d5feaU, 0x763c4abeU, 0x8c7af644U, 0xc96fa601U, + 0x04d0d4ccU, 0x488fc780U, 0xdbfb2013U, 0xcaaf6502U, + 0x26785eeeU, 0xbec67876U, 0x9121b059U, 0x33291afbU, + 0x9fae3157U, 0x777c0bbfU, 0xdffe2117U, 0x9eee7056U, + 0x6a274da2U, 0x86f0764eU, 0xa05dfd68U, 0x6de28fa5U, + 0x73790abbU, 0x6f620da7U, 0x164452deU, 0x0b1f14c3U, + 0xe3cd2e2bU, 0x636d0eabU, 0x065056ceU, 0xf953aa31U, + 0xb44cf87cU, 0xe7c82f2fU, 0xfe966836U, 0xbac37972U, + 0x992bb251U, 0xa857ff60U, 0x7b7308b3U, 0xaed27c66U, + 0xd6b4621eU, 0x3f2619f7U, 0xefc22d27U, 0x78b3cbb0U, + 0x65e88dadU, 0xf41ce83cU, 0xc420e40cU, 0x9d2eb355U, + 0x4c8ac684U, 0x198b92d1U, 0xcd6aa705U, 0xac52fe64U, + 0xe6886e2eU, 0xf813eb30U, 0x071017cfU, 0x31a998f9U, + 0x69e78ea1U, 0x38e3dbf0U, 0x2cf2dee4U, 0xdc3ee214U, + 0x00d5d5c8U, 0x622d4faaU, 0xb3893a7bU, 0x61ed8ca9U, + 0x64a8ccacU, 0x5dde8395U, 0x92e1735aU, 0x75fc89bdU, + 0x893fb641U, 0x372c1bffU, 0x8fba3547U, 0xb2c97b7aU, + 0x51d18099U, 0xa917be61U, 0x2f321de7U, 0x27381fefU, + 0x30e9d9f8U, 0xd574a11dU, 0x21bd9ce9U, 0x68a7cfa0U, + 0x93a1325bU, 0x3ce6daf4U, 0x6ca2cea4U, 0x5f5e0197U, + 0xed42af25U, 0x7e3648b6U, 0xcc2ae604U, 0x66284eaeU, + 0xe408ec2cU, 0x4345068bU, 0x6b670ca3U, 0x49cf8681U, + 0xd3f1221bU, 0xaad77d62U, 0xdebe6016U, 0x5a1b4192U, + 0xb049f978U, 0x887ff740U, 0x3b2318f3U, 0xf2996b3aU, + 0x9c6ef254U, 0x10c1d1d8U, 0xdd7ea315U, 0x5b5b0093U, + 0xebc72c23U, 0x18cbd3d0U, 0x4e0a4486U, 0x2e725ce6U, + 0x5211439aU, 0x5614429eU, 0x8aff7542U, 0xa2dd7f6aU, + 0xd171a019U, 0x8bbf3443U, 0x59db8291U, 0xad12bf65U, + 0x099f96c1U, 0x9061f158U, 0x158491ddU, 0x1a4b51d2U, + 0xa39d3e6bU, 0x8075f548U, 0x96e4725eU, 0xe28d6f2aU, + 0x9bab3053U, 0xa7983f6fU, 0x8efa7446U, 0x8470f44cU, + 0xcfea2507U, 0xe00ded28U, 0x233d1eebU, 0xc560a50dU, + 0x71f988b9U, 0xd031e118U, 0x0a5f55c2U, 0x118190d9U, + 0x5351029bU, 0x366c5afeU, 0xa458fc6cU, 0xaf923d67U, + 0x059095cdU, 0x70b9c9b8U, 0x35ac99fdU, 0x25b89dedU, + 0xc165a409U, 0x4205478aU, 0xb903ba71U, 0xceaa6406U, + 0xd7f4231fU, 0xbd06bb75U, 0x3a6359f2U, 0x1e4e50d6U, + 0x72394bbaU, 0x019594c9U, 0x20fddde8U, 0xc3e5260bU, + 0xf019e938U, 0x5e1e4096U, 0xfc16ea34U, 0xf55ca93dU, + 0x87b0374fU, 0x24f8dcecU, 0x124153daU, 0x5494c09cU, + 0x0f1a15c7U, 0x9464f05cU, 0xd2b1631aU, 0x67680fafU, + 0x025557caU, 0x5c9ec294U, 0x9aeb7152U, 0x1f0e11d7U, + 0xb843fb70U, 0xc82fe700U, 0x031516cbU, 0xc6a0660eU, + 0x86b731bfU, 0x9fe976a6U, 0x7a740e43U, 0x263f191fU, + 0xeec52bd7U, 0x5a5c0663U, 0x29f0d910U, 0x0352513aU, + 0x8577f2bcU, 0x0757503eU, 0x8d7df0b4U, 0xd6f325efU, + 0x7db1cc44U, 0x322e1c0bU, 0x6da5c854U, 0xc928e1f0U, + 0x71becf48U, 0x40c28279U, 0xb7cb7c8eU, 0x0497933dU, + 0x75bbce4cU, 0x277f581eU, 0xcd2de0f4U, 0xd2f624ebU, + 0x773b4c4eU, 0xcc6da1f5U, 0x9166f7a8U, 0x4587c27cU, + 0xf854acc1U, 0xc7a760feU, 0xc527e2fcU, 0xbbc47f82U, + 0xafd57a96U, 0xd473a7edU, 0x9c29b5a5U, 0x0e1d1337U, + 0x9bec77a2U, 0x626a085bU, 0xbfc17e86U, 0x34ab9f0dU, + 0x11c6d728U, 0x8c3db1b5U, 0xf11eefc8U, 0xd076a6e9U, + 0x6a600a53U, 0xe2ca28dbU, 0x6f254a56U, 0x54d3876dU, + 0x4e4d0377U, 0x1346552aU, 0xad55f894U, 0x7b344f42U, + 0xfad42ec3U, 0xfd11ecc4U, 0x7e710f47U, 0x8bf873b2U, + 0xdfb966e6U, 0xa29a389bU, 0x8ffd72b6U, 0x362b1d0fU, + 0x08989031U, 0xe38a69daU, 0x21fadb18U, 0x4707407eU, + 0xc062a2f9U, 0xc122e3f8U, 0x4302417aU, 0x2e351b17U, + 0x1206142bU, 0x10869629U, 0x8172f3b8U, 0x376b5c0eU, + 0xd3b665eaU, 0xb804bc81U, 0x2df5d814U, 0xb944fd80U, + 0x4647017fU, 0xcba863f2U, 0xe04aaad9U, 0x7f314e46U, + 0x7cf18d45U, 0x70fe8e49U, 0xdbbc67e2U, 0x1743542eU, + 0x188c9421U, 0x4ccd8175U, 0xb68b3d8fU, 0xf39e6dcaU, + 0x3e211f07U, 0x727e0c4bU, 0xe10aebd8U, 0xf05eaec9U, + 0x1c899525U, 0x8437b3bdU, 0xabd07b92U, 0x09d8d130U, + 0xa55ffa9cU, 0x4d8dc074U, 0xe50feadcU, 0xa41fbb9dU, + 0x50d68669U, 0xbc01bd85U, 0x9aac36a3U, 0x5713446eU, + 0x4988c170U, 0x5593c66cU, 0x2cb59915U, 0x31eedf08U, + 0xd93ce5e0U, 0x599cc560U, 0x3ca19d05U, 0xc3a261faU, + 0x8ebd33b7U, 0xdd39e4e4U, 0xc467a3fdU, 0x8032b2b9U, + 0xa3da799aU, 0x92a634abU, 0x4182c378U, 0x9423b7adU, + 0xec45a9d5U, 0x05d7d23cU, 0xd533e6ecU, 0x4242007bU, + 0x5f194666U, 0xceed23f7U, 0xfed12fc7U, 0xa7df789eU, + 0x767b0d4fU, 0x237a591aU, 0xf79b6cceU, 0x96a335afU, + 0xdc79a5e5U, 0xc2e220fbU, 0x3de1dc04U, 0x0b585332U, + 0x5316456aU, 0x0212103bU, 0x1603152fU, 0xe6cf29dfU, + 0x3a241e03U, 0x58dc8461U, 0x8978f1b0U, 0x5b1c4762U, + 0x5e590767U, 0x672f485eU, 0xa810b891U, 0x4f0d4276U, + 0xb3ce7d8aU, 0x0dddd034U, 0xb54bfe8cU, 0x8838b0b1U, + 0x6b204b52U, 0x93e675aaU, 0x15c3d62cU, 0x1dc9d424U, + 0x0a181233U, 0xef856ad6U, 0x1b4c5722U, 0x5256046bU, + 0xa950f990U, 0x0617113fU, 0x5653056fU, 0x65afca5cU, + 0xd7b364eeU, 0x44c7837dU, 0xf6db2dcfU, 0x5cd98565U, + 0xdef927e7U, 0x79b4cd40U, 0x5196c768U, 0x733e4d4aU, + 0xe900e9d0U, 0x9026b6a9U, 0xe44fabddU, 0x60ea8a59U, + 0x8ab832b3U, 0xb28e3c8bU, 0x01d2d338U, 0xc868a0f1U, + 0xa69f399fU, 0x2a301a13U, 0xe78f68deU, 0x61aacb58U, + 0xd136e7e8U, 0x223a181bU, 0x74fb8f4dU, 0x1483972dU, + 0x68e08851U, 0x6ce58955U, 0xb00ebe89U, 0x982cb4a1U, + 0xeb806bd2U, 0xb14eff88U, 0x632a495aU, 0x97e374aeU, + 0x336e5d0aU, 0xaa903a93U, 0x2f755a16U, 0x20ba9a19U, + 0x996cf5a0U, 0xba843e83U, 0xac15b995U, 0xd87ca4e1U, + 0xa15afb98U, 0x9d69f4a4U, 0xb40bbf8dU, 0xbe813f87U, + 0xf51beeccU, 0xdafc26e3U, 0x19ccd520U, 0xff916ec6U, + 0x4b084372U, 0xeac02ad3U, 0x30ae9e09U, 0x2b705b12U, + 0x69a0c950U, 0x0c9d9135U, 0x9ea937a7U, 0x9563f6acU, + 0x3f615e06U, 0x4a480273U, 0x0f5d5236U, 0x1f495626U, + 0xfb946fc2U, 0x78f48c41U, 0x83f271baU, 0xf45bafcdU, + 0xed05e8d4U, 0x87f770beU, 0x00929239U, 0x24bf9b1dU, + 0x48c88071U, 0x3b645f02U, 0x1a0c1623U, 0xf914edc0U, + 0xcae822f3U, 0x64ef8b5dU, 0xc6e721ffU, 0xcfad62f6U, + 0xbd41fc84U, 0x1e091727U, 0x28b09811U, 0x6e650b57U, + 0x35ebde0cU, 0xae953b97U, 0xe840a8d1U, 0x5d99c464U, + 0x38a49c01U, 0x666f095fU, 0xa01aba99U, 0x25ffda1cU, + 0x82b230bbU, 0xf2de2ccbU, 0x39e4dd00U, 0xfc51adc5U, + 0x33c7f47aU, 0x2a99b363U, 0xcf04cb86U, 0x934fdcdaU, + 0x5bb5ee12U, 0xef2cc3a6U, 0x9c801cd5U, 0xb62294ffU, + 0x30073779U, 0xb22795fbU, 0x380d3571U, 0x6383e02aU, + 0xc8c10981U, 0x875ed9ceU, 0xd8d50d91U, 0x7c582435U, + 0xc4ce0a8dU, 0xf5b247bcU, 0x02bbb94bU, 0xb1e756f8U, + 0xc0cb0b89U, 0x920f9ddbU, 0x785d2531U, 0x6786e12eU, + 0xc24b898bU, 0x791d6430U, 0x2416326dU, 0xf0f707b9U, + 0x4d246904U, 0x72d7a53bU, 0x70572739U, 0x0eb4ba47U, + 0x1aa5bf53U, 0x61036228U, 0x29597060U, 0xbb6dd6f2U, + 0x2e9cb267U, 0xd71acd9eU, 0x0ab1bb43U, 0x81db5ac8U, + 0xa4b612edU, 0x394d7470U, 0x446e2a0dU, 0x6506632cU, + 0xdf10cf96U, 0x57baed1eU, 0xda558f93U, 0xe1a342a8U, + 0xfb3dc6b2U, 0xa63690efU, 0x18253d51U, 0xce448a87U, + 0x4fa4eb06U, 0x48612901U, 0xcb01ca82U, 0x3e88b677U, + 0x6ac9a323U, 0x17eafd5eU, 0x3a8db773U, 0x835bd8caU, + 0xbde855f4U, 0x56faac1fU, 0x948a1eddU, 0xf27785bbU, + 0x7512673cU, 0x7452263dU, 0xf67284bfU, 0x9b45ded2U, + 0xa776d1eeU, 0xa5f653ecU, 0x3402367dU, 0x821b99cbU, + 0x66c6a02fU, 0x0d747944U, 0x98851dd1U, 0x0c343845U, + 0xf337c4baU, 0x7ed8a637U, 0x553a6f1cU, 0xca418b83U, + 0xc9814880U, 0xc58e4b8cU, 0x6ecca227U, 0xa23391ebU, + 0xadfc51e4U, 0xf9bd44b0U, 0x03fbf84aU, 0x46eea80fU, + 0x8b51dac2U, 0xc70ec98eU, 0x547a2e1dU, 0x452e6b0cU, + 0xa9f950e0U, 0x31477678U, 0x1ea0be57U, 0xbca814f5U, + 0x102f3f59U, 0xf8fd05b1U, 0x507f2f19U, 0x116f7e58U, + 0xe5a643acU, 0x09717840U, 0x2fdcf366U, 0xe26381abU, + 0xfcf804b5U, 0xe0e303a9U, 0x99c55cd0U, 0x849e1acdU, + 0x6c4c2025U, 0xecec00a5U, 0x89d158c0U, 0x76d2a43fU, + 0x3bcdf672U, 0x68492121U, 0x71176638U, 0x3542777cU, + 0x16aabc5fU, 0x27d6f16eU, 0xf4f206bdU, 0x21537268U, + 0x59356c10U, 0xb0a717f9U, 0x60432329U, 0xf732c5beU, + 0xea6983a3U, 0x7b9de632U, 0x4ba1ea02U, 0x12afbd5bU, + 0xc30bc88aU, 0x960a9cdfU, 0x42eba90bU, 0x23d3f06aU, + 0x69096020U, 0x7792e53eU, 0x889119c1U, 0xbe2896f7U, + 0xe66680afU, 0xb762d5feU, 0xa373d0eaU, 0x53bfec1aU, + 0x8f54dbc6U, 0xedac41a4U, 0x3c083475U, 0xee6c82a7U, + 0xeb29c2a2U, 0xd25f8d9bU, 0x1d607d54U, 0xfa7d87b3U, + 0x06beb84fU, 0xb8ad15f1U, 0x003b3b49U, 0x3d487574U, + 0xde508e97U, 0x2696b06fU, 0xa0b313e9U, 0xa8b911e1U, + 0xbf68d7f6U, 0x5af5af13U, 0xae3c92e7U, 0xe726c1aeU, + 0x1c203c55U, 0xb367d4faU, 0xe323c0aaU, 0xd0df0f99U, + 0x62c3a12bU, 0xf1b746b8U, 0x43abe80aU, 0xe9a940a0U, + 0x6b89e222U, 0xccc40885U, 0xe4e602adU, 0xc64e888fU, + 0x5c702c15U, 0x2556736cU, 0x513f6e18U, 0xd59a4f9cU, + 0x3fc8f776U, 0x07fef94eU, 0xb4a216fdU, 0x7d186534U, + 0x13effc5aU, 0x9f40dfd6U, 0x52ffad1bU, 0xd4da0e9dU, + 0x6446222dU, 0x974adddeU, 0xc18b4a88U, 0xa1f352e8U, + 0xdd904d94U, 0xd9954c90U, 0x057e7b4cU, 0x2d5c7164U, + 0x5ef0ae17U, 0x043e3a4dU, 0xd65a8c9fU, 0x2293b16bU, + 0x861e98cfU, 0x1fe0ff56U, 0x9a059fd3U, 0x95ca5fdcU, + 0x2c1c3065U, 0x0ff4fb46U, 0x19657c50U, 0x6d0c6124U, + 0x142a3e5dU, 0x28193161U, 0x017b7a48U, 0x0bf1fa42U, + 0x406b2b09U, 0x6f8ce326U, 0xacbc10e5U, 0x4ae1ab03U, + 0xfe7886b7U, 0x5fb0ef16U, 0x85de5bccU, 0x9e009ed7U, + 0xdcd00c95U, 0xb9ed54f0U, 0x2bd9f262U, 0x20133369U, + 0x8a119bc3U, 0xff38c7b6U, 0xba2d97f3U, 0xaa3993e3U, + 0x4ee4aa07U, 0xcd844984U, 0x3682b47fU, 0x412b6a08U, + 0x58752d11U, 0x3287b57bU, 0xb5e257fcU, 0x91cf5ed8U, + 0xfdb845b4U, 0x8e149ac7U, 0xaf7cd3e6U, 0x4c642805U, + 0x7f98e736U, 0xd19f4e98U, 0x7397e43aU, 0x7adda733U, + 0x08313941U, 0xab79d2e2U, 0x9dc05dd4U, 0xdb15ce92U, + 0x809b1bc9U, 0x1be5fe52U, 0x5d306d14U, 0xe8e901a1U, + 0x8dd459c4U, 0xd31fcc9aU, 0x156a7f5cU, 0x908f1fd9U, + 0x37c2f57eU, 0x47aee90eU, 0x8c9418c5U, 0x49216800U, +}; diff --git a/src/sm4_enc.c b/src/sm4_enc.c new file mode 100644 index 00000000..990a0eec --- /dev/null +++ b/src/sm4_enc.c @@ -0,0 +1,133 @@ +/* ==================================================================== + * Copyright (c) 2014 - 2017 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + * ==================================================================== + */ + +#include +#include "bswap.h" +#include "rotate.h" +#include "sm4_lcl.h" + + +#define L32(x) \ + ((x) ^ \ + ROL32((x), 2) ^ \ + ROL32((x), 10) ^ \ + ROL32((x), 18) ^ \ + ROL32((x), 24)) + +#define ROUND_SBOX(x0, x1, x2, x3, x4, i) \ + x4 = x1 ^ x2 ^ x3 ^ *(rk + i); \ + x4 = S32(x4); \ + x4 = x0 ^ L32(x4) + +#define ROUND_TBOX(x0, x1, x2, x3, x4, i) \ + x4 = x1 ^ x2 ^ x3 ^ *(rk + i); \ + t0 = ROL32(SM4_T[(uint8_t)x4], 8); \ + x4 >>= 8; \ + x0 ^= t0; \ + t0 = ROL32(SM4_T[(uint8_t)x4], 16); \ + x4 >>= 8; \ + x0 ^= t0; \ + t0 = ROL32(SM4_T[(uint8_t)x4], 24); \ + x4 >>= 8; \ + x0 ^= t0; \ + t1 = SM4_T[x4]; \ + x4 = x0 ^ t1 + +#define ROUND_DBOX(x0, x1, x2, x3, x4, i) \ + x4 = x1 ^ x2 ^ x3 ^ *(rk + i); \ + x4 = x0 ^ SM4_D[(uint16_t)(x4 >> 16)] ^ \ + ROL32(SM4_D[(uint16_t)x4], 16) + +#define ROUND ROUND_TBOX + + +void sm4_encrypt(const SM4_KEY *key, const unsigned char in[16], unsigned char out[16]) +{ + const uint32_t *rk = key->rk; + uint32_t x0, x1, x2, x3, x4; + uint32_t t0, t1; + + x0 = GETU32(in ); + x1 = GETU32(in + 4); + x2 = GETU32(in + 8); + x3 = GETU32(in + 12); + ROUNDS(x0, x1, x2, x3, x4); + PUTU32(out , x0); + PUTU32(out + 4, x4); + PUTU32(out + 8, x3); + PUTU32(out + 12, x2); +} + +/* caller make sure counter not overflow */ +void sm4_ctr32_encrypt_blocks(const unsigned char *in, unsigned char *out, + size_t blocks, const SM4_KEY *key, const unsigned char iv[16]) +{ + const uint32_t *rk = key->rk; + unsigned int c0 = GETU32(iv ); + unsigned int c1 = GETU32(iv + 4); + unsigned int c2 = GETU32(iv + 8); + unsigned int c3 = GETU32(iv + 12); + uint32_t x0, x1, x2, x3, x4; + uint32_t t0, t1; + + while (blocks--) { + x0 = c0; + x1 = c1; + x2 = c2; + x3 = c3; + ROUNDS(x0, x1, x2, x3, x4); + PUTU32(out , GETU32(in ) ^ x0); + PUTU32(out + 4, GETU32(in + 4) ^ x4); + PUTU32(out + 8, GETU32(in + 8) ^ x3); + PUTU32(out + 12, GETU32(in + 12) ^ x2); + in += 16; + out += 16; + c3++; + } +} diff --git a/src/sm4_lcl.h b/src/sm4_lcl.h new file mode 100644 index 00000000..ee78508d --- /dev/null +++ b/src/sm4_lcl.h @@ -0,0 +1,99 @@ +/* ==================================================================== + * Copyright (c) 2014 - 2019 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + * ==================================================================== + */ + +#ifndef GMSSL_SM4_LCL_H +#define GMSSL_SM4_LCL_H + +#include + +extern const uint8_t SM4_S[256]; +extern const uint32_t SM4_T[256]; +extern const uint32_t SM4_D[65536]; + +#define S32(A) \ + ((SM4_S[((A) >> 24) ] << 24) ^ \ + (SM4_S[((A) >> 16) & 0xff] << 16) ^ \ + (SM4_S[((A) >> 8) & 0xff] << 8) ^ \ + (SM4_S[((A)) & 0xff])) + +#define ROUNDS(x0, x1, x2, x3, x4) \ + ROUND(x0, x1, x2, x3, x4, 0); \ + ROUND(x1, x2, x3, x4, x0, 1); \ + ROUND(x2, x3, x4, x0, x1, 2); \ + ROUND(x3, x4, x0, x1, x2, 3); \ + ROUND(x4, x0, x1, x2, x3, 4); \ + ROUND(x0, x1, x2, x3, x4, 5); \ + ROUND(x1, x2, x3, x4, x0, 6); \ + ROUND(x2, x3, x4, x0, x1, 7); \ + ROUND(x3, x4, x0, x1, x2, 8); \ + ROUND(x4, x0, x1, x2, x3, 9); \ + ROUND(x0, x1, x2, x3, x4, 10); \ + ROUND(x1, x2, x3, x4, x0, 11); \ + ROUND(x2, x3, x4, x0, x1, 12); \ + ROUND(x3, x4, x0, x1, x2, 13); \ + ROUND(x4, x0, x1, x2, x3, 14); \ + ROUND(x0, x1, x2, x3, x4, 15); \ + ROUND(x1, x2, x3, x4, x0, 16); \ + ROUND(x2, x3, x4, x0, x1, 17); \ + ROUND(x3, x4, x0, x1, x2, 18); \ + ROUND(x4, x0, x1, x2, x3, 19); \ + ROUND(x0, x1, x2, x3, x4, 20); \ + ROUND(x1, x2, x3, x4, x0, 21); \ + ROUND(x2, x3, x4, x0, x1, 22); \ + ROUND(x3, x4, x0, x1, x2, 23); \ + ROUND(x4, x0, x1, x2, x3, 24); \ + ROUND(x0, x1, x2, x3, x4, 25); \ + ROUND(x1, x2, x3, x4, x0, 26); \ + ROUND(x2, x3, x4, x0, x1, 27); \ + ROUND(x3, x4, x0, x1, x2, 28); \ + ROUND(x4, x0, x1, x2, x3, 29); \ + ROUND(x0, x1, x2, x3, x4, 30); \ + ROUND(x1, x2, x3, x4, x0, 31) + +#endif diff --git a/src/sm4_setkey.c b/src/sm4_setkey.c new file mode 100644 index 00000000..e2751132 --- /dev/null +++ b/src/sm4_setkey.c @@ -0,0 +1,119 @@ +/* ==================================================================== + * Copyright (c) 2014 - 2019 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + * ==================================================================== + */ + +#include +#include "bswap.h" +#include "rotate.h" +#include "sm4_lcl.h" + +static uint32_t FK[4] = { + 0xa3b1bac6, 0x56aa3350, 0x677d9197, 0xb27022dc, +}; + +static uint32_t CK[32] = { + 0x00070e15, 0x1c232a31, 0x383f464d, 0x545b6269, + 0x70777e85, 0x8c939aa1, 0xa8afb6bd, 0xc4cbd2d9, + 0xe0e7eef5, 0xfc030a11, 0x181f262d, 0x343b4249, + 0x50575e65, 0x6c737a81, 0x888f969d, 0xa4abb2b9, + 0xc0c7ced5, 0xdce3eaf1, 0xf8ff060d, 0x141b2229, + 0x30373e45, 0x4c535a61, 0x686f767d, 0x848b9299, + 0xa0a7aeb5, 0xbcc3cad1, 0xd8dfe6ed, 0xf4fb0209, + 0x10171e25, 0x2c333a41, 0x484f565d, 0x646b7279, +}; + +#define L32_(x) \ + ((x) ^ \ + ROL32((x), 13) ^ \ + ROL32((x), 23)) + +#define ENC_ROUND(x0, x1, x2, x3, x4, i) \ + x4 = x1 ^ x2 ^ x3 ^ *(CK + i); \ + x4 = S32(x4); \ + x4 = x0 ^ L32_(x4); \ + *(rk + i) = x4 + +#define DEC_ROUND(x0, x1, x2, x3, x4, i) \ + x4 = x1 ^ x2 ^ x3 ^ *(CK + i); \ + x4 = S32(x4); \ + x4 = x0 ^ L32_(x4); \ + *(rk + 31 - i) = x4 + +void sm4_set_encrypt_key(SM4_KEY *key, const unsigned char user_key[16]) +{ + uint32_t *rk = key->rk; + uint32_t x0, x1, x2, x3, x4; + + x0 = GETU32(user_key ) ^ FK[0]; + x1 = GETU32(user_key + 4) ^ FK[1]; + x2 = GETU32(user_key + 8) ^ FK[2]; + x3 = GETU32(user_key + 12) ^ FK[3]; + +#define ROUND ENC_ROUND + ROUNDS(x0, x1, x2, x3, x4); +#undef ROUND + + x0 = x1 = x2 = x3 = x4 = 0; +} + +void sm4_set_decrypt_key(SM4_KEY *key, const unsigned char user_key[16]) +{ + uint32_t *rk = key->rk; + uint32_t x0, x1, x2, x3, x4; + + x0 = GETU32(user_key ) ^ FK[0]; + x1 = GETU32(user_key + 4) ^ FK[1]; + x2 = GETU32(user_key + 8) ^ FK[2]; + x3 = GETU32(user_key + 12) ^ FK[3]; + +#define ROUND DEC_ROUND + ROUNDS(x0, x1, x2, x3, x4); +#undef ROUND + + x0 = x1 = x2 = x3 = x4 = 0; +} diff --git a/src/sm9_keygen.c b/src/sm9_keygen.c new file mode 100644 index 00000000..510ee1f0 --- /dev/null +++ b/src/sm9_keygen.c @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2014 - 2020 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + + + +int sm9_hash1(bignum_t r, const char *id, size_t idlen, uint8_t hid) +{ + bignum_t h; + SM3_CTX ctx1; + SM3_CTX ctx2; + + uint8_t prefix[1] = {0x01}; + uint8_t ct1[4] = {0x00, 0x00, 0x00, 0x01}; + uint8_t ct2[4] = {0x00, 0x00, 0x00, 0x02}; + uint8_t buf[64]; + + sm3_init(&ctx1); + sm3_update(&ctx1, prefix, sizeof(prefix)); + sm3_update(&ctx1, id, idlen); + sm3_update(&ctx1, &hid, 1); + + memcpy(&ctx2, &ctx1, sizeof(SM3_CTX)); + + sm3_update(&ctx1, ct1, sizeof(ct1)); + sm3_update(&ctx2, ct2, sizeof(ct2)); + sm3_finish(&ctx1, buf); + sm3_finish(&ctx2, buf + 32); + + +} diff --git a/src/sm9_math.c b/src/sm9_math.c new file mode 100644 index 00000000..92600f77 --- /dev/null +++ b/src/sm9_math.c @@ -0,0 +1,2032 @@ +/* + * Copyright (c) 2014 - 2020 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + +#include +#include +#include +#include +#include +#include +#include "endian.h" + +typedef uint64_t bn_t[8]; +typedef bn_t fp_t; +typedef bn_t fn_t; +typedef uint64_t barrett_bn_t[9]; +typedef fp_t fp2_t[2]; +typedef fp2_t fp4_t[2]; +typedef fp4_t fp12_t[3]; + + +static const bn_t ZERO = {0,0,0,0,0,0,0,0}; +static const bn_t ONE = {1,0,0,0,0,0,0,0}; +static const bn_t TWO = {2,0,0,0,0,0,0,0}; +static const bn_t FIVE = {5,0,0,0,0,0,0,0}; + +// p = b640000002a3a6f1d603ab4ff58ec74521f2934b1a7aeedbe56f9b27e351457d +// n = b640000002a3a6f1d603ab4ff58ec74449f2934b18ea8beee56ee19cd69ecf25 +// mu = 2^512 // p = 167980e0beb5759a655f73aebdcd1312af2665f6d1e36081c71188f90d5c22146 +static const bn_t SM9_P = {0xe351457d, 0xe56f9b27, 0x1a7aeedb, 0x21f2934b, 0xf58ec745, 0xd603ab4f, 0x02a3a6f1, 0xb6400000}; +static const bn_t SM9_P_MINUS_ONE = {0xe351457c, 0xe56f9b27, 0x1a7aeedb, 0x21f2934b, 0xf58ec745, 0xd603ab4f, 0x02a3a6f1, 0xb6400000}; +static const bn_t SM9_N = {0xd69ecf25, 0xe56ee19c, 0x18ea8bee, 0x49f2934b, 0xf58ec744, 0xd603ab4f, 0x02a3a6f1, 0xb6400000}; +static const bn_t SM9_MU = {0xd5c22146, 0x71188f90, 0x1e36081c, 0xf2665f6d, 0xdcd1312a, 0x55f73aeb, 0xeb5759a6, 0x167980e0b}; + +typedef struct { + fp_t X; + fp_t Y; + fp_t Z; +} point_t; + +// P1.X 0x93DE051D62BF718FF5ED0704487D01D6E1E4086909DC3280E8C4E4817C66DDDD +// P1.Y 0x21FE8DDA4F21E607631065125C395BBC1C1C00CBFA6024350C464CD70A3EA616 +static const point_t _SM9_P1 = { + {0x7c66dddd, 0xe8c4e481, 0x09dc3280, 0xe1e40869, 0x487d01d6, 0xf5ed0704, 0x62bf718f, 0x93de051d}, + {0x0a3ea616, 0x0c464cd7, 0xfa602435, 0x1c1c00cb, 0x5c395bbc, 0x63106512, 0x4f21e607, 0x21fe8dda}, + {1,0,0,0,0,0,0,0} +}; +static const point_t *SM9_P1 = &_SM9_P1; + +typedef struct { + fp2_t X; + fp2_t Y; + fp2_t Z; +} twist_point_t; + +/* + X : [0x3722755292130b08d2aab97fd34ec120ee265948d19c17abf9b7213baf82d65bn, + 0x85aef3d078640c98597b6027b441a01ff1dd2c190f5e93c454806c11d8806141n], + Y : [0xa7cf28d519be3da65f3170153d278ff247efba98a71a08116215bba5c999a7c7n, + 0x17509b092e845c1266ba0d262cbee6ed0736a96fa347c8bd856dc76b84ebeb96n], + Z : [1n, 0n], +*/ +static const twist_point_t _SM9_P2 = { + {{0xAF82D65B, 0xF9B7213B, 0xD19C17AB, 0xEE265948, 0xD34EC120, 0xD2AAB97F, 0x92130B08, 0x37227552}, + {0xD8806141, 0x54806C11, 0x0F5E93C4, 0xF1DD2C19, 0xB441A01F, 0x597B6027, 0x78640C98, 0x85AEF3D0}}, + {{0xC999A7C7, 0x6215BBA5, 0xA71A0811, 0x47EFBA98, 0x3D278FF2, 0x5F317015, 0x19BE3DA6, 0xA7CF28D5}, + {0x84EBEB96, 0x856DC76B, 0xA347C8BD, 0x0736A96F, 0x2CBEE6ED, 0x66BA0D26, 0x2E845C12, 0x17509B09}}, + {{1,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0}}, +}; +static const twist_point_t *SM9_P2 = &_SM9_P2; + +#define bn_init(r) memset((r),0,sizeof(bn_t)) +#define bn_clean(r) memset((r),0,sizeof(bn_t)) +#define bn_set_zero(r) memset((r),0,sizeof(bn_t)) +#define bn_set_one(r) memcpy((r),&ONE,sizeof(bn_t)) +#define bn_copy(r,a) memcpy((r),(a),sizeof(bn_t)) +#define bn_is_zero(a) (memcmp((a),&ZERO, sizeof(bn_t)) == 0) +#define bn_is_one(a) (memcmp((a),&ONE, sizeof(bn_t)) == 0) + +static void bn_to_bytes(const bn_t a, uint8_t out[32]) +{ + int i; + for (i = 7; i >= 0; i--) { + PUTU32(out, (uint32_t)a[i]); + out += sizeof(uint32_t); + } +} + +static void bn_from_bytes(bn_t r, const uint8_t in[32]) +{ + int i; + for (i = 7; i >= 0; i--) { + r[i] = GETU32(in); + in += sizeof(uint32_t); + } +} + +static int bn_from_hex(bn_t r, const char hex[65]) +{ + uint8_t buf[32]; + if (hex2bin(hex, 64, buf) < 0) { + return -1; + } + bn_from_bytes(r, buf); + return 0; +} + +static void bn_to_hex(const bn_t a, char hex[65]) +{ + int i; + for (i = 7; i >= 0; i--) { + (void)sprintf(hex, "%08x", (uint32_t)a[i]); + hex += 8; + } + hex[64] = '0'; +} + +static void print_bn(const char *prefix, const bn_t a) +{ + char hex[65]; + bn_to_hex(a, hex); + printf("%s\n%s\n", prefix, hex); +} + +static void bn_to_bits(const bn_t a, char bits[256]) +{ + int i, j; + for (i = 7; i >= 0; i--) { + uint32_t w = a[i]; + for (j = 0; j < 32; j++) { + *bits++ = (w & 0x80000000) ? '1' : '0'; + w <<= 1; + } + } +} + +static int bn_cmp(const bn_t a, const bn_t b) +{ + int i; + for (i = 7; i >= 0; i--) { + if (a[i] > b[i]) + return 1; + if (a[i] < b[i]) + return -1; + } + return 0; +} + +static int bn_equ_hex(const bn_t a, const char *hex) +{ + bn_t b; + bn_from_hex(b, hex); + return (bn_cmp(a, b) == 0); +} + +static void bn_set_word(bn_t r, uint32_t a) +{ + bn_set_zero(r); + r[0] = a; +} + +static void bn_add(bn_t r, const bn_t a, const bn_t b) +{ + int i; + r[0] = a[0] + b[0]; + for (i = 1; i < 8; i++) { + r[i] = a[i] + b[i] + (r[i-1] >> 32); + } + for (i = 0; i < 7; i++) { + r[i] &= 0xffffffff; + } +} + +static void bn_sub(bn_t ret, const bn_t a, const bn_t b) +{ + int i; + bn_t r; + r[0] = ((uint64_t)1 << 32) + a[0] - b[0]; + for (i = 1; i < 7; i++) { + r[i] = 0xffffffff + a[i] - b[i] + (r[i - 1] >> 32); + r[i - 1] &= 0xffffffff; + } + r[i] = a[i] - b[i] + (r[i - 1] >> 32) - 1; + r[i - 1] &= 0xffffffff; + bn_copy(ret, r); +} + +static void bn_rand_range(bn_t r, const bn_t range) +{ + FILE *fp; + uint8_t buf[256]; + + fp = fopen("/dev/urandom", "rb"); + do { + fread(buf, 1, 256, fp); + bn_from_bytes(r, buf); + } while (bn_cmp(r, range) >= 0); + fclose(fp); +} + +#define fp_init(a) bn_init(a) +#define fp_clean(a) bn_clean(a) +#define fp_is_zero(a) bn_is_zero(a) +#define fp_is_one(a) bn_is_one(a) +#define fp_set_zero(a) bn_set_zero(a) +#define fp_set_one(a) bn_set_one(a) +#define fp_from_hex(a,s) bn_from_hex((a),(s)) +#define fp_to_hex(a,s) bn_to_hex((a),(s)) +#define fp_copy(r,a) bn_copy((r),(a)) + +static int fp_equ(const fp_t a, const fp_t b) +{ + int i; + for (i = 0; i < 8; i++) { + if (a[i] != b[i]) + return 0; + } + return 1; +} + +static void fp_add(fp_t r, const fp_t a, const fp_t b) +{ + bn_add(r, a, b); + if (bn_cmp(r, SM9_P) >= 0) + return bn_sub(r, r, SM9_P); +} + +static void fp_sub(fp_t r, const fp_t a, const fp_t b) +{ + if (bn_cmp(a, b) >= 0) { + bn_sub(r, a, b); + } else { + bn_t t; + bn_sub(t, SM9_P, b); + bn_add(r, t, a); + } +} + +static void fp_dbl(fp_t r, const fp_t a) +{ + fp_add(r, a, a); +} + +static void fp_tri(fp_t r, const fp_t a) +{ + fp_t t; + fp_dbl(t, a); + fp_add(r, t, a); +} + +static void fp_div2(fp_t r, const fp_t a) +{ + int i; + bn_copy(r, a); + if (r[0] & 0x01) { + bn_add(r, r, SM9_P); + } + for (i = 0; i < 7; i++) { + r[i] = (r[i] >> 1) | ((r[i + 1] & 0x01) << 31); + } + r[i] >>= 1; +} + +static void fp_neg(fp_t r, const fp_t a) +{ + if (bn_is_zero(a)) { + bn_copy(r, a); + } else { + bn_sub(r, SM9_P, a); + } +} + +static int barrett_bn_cmp(const barrett_bn_t a, const barrett_bn_t b) +{ + int i; + for (i = 8; i >= 0; i--) { + if (a[i] > b[i]) + return 1; + if (a[i] < b[i]) + return -1; + } + return 0; +} + +static void barrett_bn_add(barrett_bn_t r, const barrett_bn_t a, const barrett_bn_t b) +{ + int i; + r[0] = a[0] + b[0]; + for (i = 1; i < 9; i++) { + r[i] = a[i] + b[i] + (r[i-1] >> 32); + } + for (i = 0; i < 8; i++) { + r[i] &= 0xffffffff; + } +} + +static void barrett_bn_sub(barrett_bn_t ret, const barrett_bn_t a, const barrett_bn_t b) +{ + barrett_bn_t r; + int i; + r[0] = ((uint64_t)1 << 32) + a[0] - b[0]; + for (i = 1; i < 8; i++) { + r[i] = 0xffffffff + a[i] - b[i] + (r[i - 1] >> 32); + r[i - 1] &= 0xffffffff; + } + r[i] = a[i] - b[i] + (r[i - 1] >> 32) - 1; + r[i - 1] &= 0xffffffff; + for (i = 0; i < 9; i++) { + ret[i] = r[i]; + } +} + +static void fp_mul(fp_t r, const fp_t a, const fp_t b) +{ + uint64_t s[17]; + barrett_bn_t zh, zl, q; + uint64_t w; + int i, j; + + /* z = a * b */ + for (i = 0; i < 8; i++) { + s[i] = 0; + } + for (i = 0; i < 8; i++) { + w = 0; + for (j = 0; j < 8; j++) { + w += s[i + j] + a[i] * b[j]; + s[i + j] = w & 0xffffffff; + w >>= 32; + } + s[i + 8] = w; + } + + /* zl = z mod (2^32)^9 = z[0..8] + * zh = z // (2^32)^7 = z[7..15] */ + for (i = 0; i < 9; i++) { + zl[i] = s[i]; + zh[i] = s[7 + i]; + } + + /* q = zh * mu // (2^32)^9 */ + for (i = 0; i < 9; i++) { + s[i] = 0; + } + for (i = 0; i < 9; i++) { + w = 0; + for (j = 0; j < 8; j++) { + w += s[i + j] + zh[i] * SM9_MU[j]; + s[i + j] = w & 0xffffffff; + w >>= 32; + } + s[i + 8] = w; + } + for (i = 0; i < 8; i++) { + q[i] = s[9 + i]; + } + + /* q = q * n mod (2^32)^9 */ + for (i = 0; i < 8; i++) { + s[i] = 0; + } + for (i = 0; i < 8; i++) { + w = 0; + for (j = 0; j < 8; j++) { + w += s[i + j] + q[i] * SM9_N[j]; + s[i + j] = w & 0xffffffff; + w >>= 32; + } + s[i + 8] = w; + } + for (i = 0; i < 9; i++) { + q[i] = s[i]; + } + + /* r = zl - q (mod (2^32)^9) */ + + if (barrett_bn_cmp(zl, q)) { + barrett_bn_sub(zl, zl, q); + } else { + barrett_bn_t c = {0,0,0,0,0,0,0,0,0x100000000}; + barrett_bn_sub(q, c, q); + barrett_bn_add(zl, q, zl); + + } + + for (i = 0; i < 8; i++) { + r[i] = zl[i]; + } + r[7] += zl[8] << 32; + + /* while r >= p do: r = r - n */ + while (bn_cmp(r, SM9_N) >= 0) { + bn_sub(r, r, SM9_N); + } +} + +static void fp_sqr(fp_t r, const fp_t a) +{ + fp_mul(r, a, a); +} + +static void fp_pow(fp_t r, const fp_t a, const bn_t e) +{ + fp_t t; + uint32_t w; + int i, j; + + assert(bn_cmp(e, SM9_P_MINUS_ONE) < 0); + + bn_set_one(t); + for (i = 7; i >= 0; i--) { + w = (uint32_t)e[i]; + for (j = 0; j < 32; j++) { + fp_sqr(t, t); + if (w & 0x80000000) + fp_mul(t, t, a); + w <<= 1; + } + } + bn_copy(r, t); +} + +static void fp_inv(fp_t r, const fp_t a) +{ + fp_t e; + bn_sub(e, SM9_P, TWO); + fp_pow(r, a, e); +} + + + +static void fn_add(fn_t r, const fn_t a, const fn_t b) +{ + +} + +static void fn_sub(fn_t r, const fn_t a, const fn_t b) +{ + +} + +static void fn_neg(fn_t r, const fn_t a) +{ +} + +static void fn_inv(fn_t r, const fn_t a) +{ + +} + +static const fp2_t FP2_ZERO = {{0,0,0,0,0,0,0,0},{0,0,0,0,0,0,0,0}}; +static const fp2_t FP2_ONE = {{1,0,0,0,0,0,0,0},{0,0,0,0,0,0,0,0}}; +static const fp2_t FP2_U = {{0,0,0,0,0,0,0,0},{1,0,0,0,0,0,0,0}}; +static const fp2_t FP2_5U = {{0,0,0,0,0,0,0,0},{5,0,0,0,0,0,0,0}}; + + + +#define fp2_init(a) memset((a), 0, sizeof(fp2_t)) +#define fp2_clean(a) memset((a), 0, sizeof(fp2_t)) +#define fp2_is_zero(a) (memcmp((a), &FP2_ZERO, sizeof(fp2_t)) == 0) +#define fp2_is_one(a) (memcmp((a), &FP2_ONE, sizeof(fp2_t)) == 0) +#define fp2_copy(r,a) memcpy((r), (a), sizeof(fp2_t)) +#define fp2_equ(a,b) (memcmp((a),(b),sizeof(fp2_t)) == 0) + +static void fp2_from_hex(fp2_t r, const char hex[65 * 2]) +{ + fp_from_hex(r[1], hex); + fp_from_hex(r[0], hex + 65); +} + +static void fp2_to_hex(const fp2_t a, char hex[65 * 2]) +{ + fp_to_hex(a[1], hex); + hex[64] = '\n'; + fp_to_hex(a[0], hex + 65); +} + +static void fp2_print(const char *prefix, const fp2_t a) +{ + char hex[65 * 2]; + fp2_to_hex(a, hex); + printf("%s\n%s\n", prefix, hex); +} + +#define fp2_set_zero(a) memset((a), 0, sizeof(fp2_t)) +#define fp2_set_one(a) memcpy((a), &FP2_ONE, sizeof(fp2_t)) + +static void fp2_set_fp(fp2_t r, const fp_t a) +{ + fp_copy(r[0], a); + fp_set_zero(r[1]); +} + +#define fp2_set_u(a) memcpy((a), &FP2_U, sizeof(fp2_t)) + +static void fp2_set(fp2_t r, const fp_t a0, const fp_t a1) +{ + fp_copy(r[0], a0); + fp_copy(r[1], a1); +} + +static void fp2_add(fp2_t r, const fp2_t a, const fp2_t b) +{ + fp_add(r[0], a[0], b[0]); + fp_add(r[1], a[1], b[1]); +} + +static void fp2_dbl(fp2_t r, const fp2_t a) +{ + fp_dbl(r[0], a[0]); + fp_dbl(r[1], a[1]); +} + +static void fp2_tri(fp2_t r, const fp2_t a) +{ + fp_tri(r[0], a[0]); + fp_tri(r[1], a[1]); +} + +static void fp2_sub(fp2_t r, const fp2_t a, const fp2_t b) +{ + fp_sub(r[0], a[0], b[0]); + fp_sub(r[1], a[1], b[1]); +} + +static void fp2_neg(fp2_t r, const fp2_t a) +{ + fp_neg(r[0], a[0]); + fp_neg(r[1], a[1]); +} + +static void fp2_mul(fp2_t r, const fp2_t a, const fp2_t b) +{ + fp_t r0, r1, t; + + // r0 = a0 * b0 - 2 * a1 * b1 + fp_mul(r0, a[0], b[0]); + fp_mul(t, a[1], b[1]); + fp_dbl(t, t); + fp_sub(r0, r0, t); + + // r1 = a0 * b1 + a1 * b0 + fp_mul(r1, a[0], b[1]); + fp_mul(t, a[1], b[0]); + fp_add(r1, r1, t); + + fp_copy(r[0], r0); + fp_copy(r[1], r1); +} + +static void fp2_mul_u(fp2_t r, const fp2_t a, const fp2_t b) +{ + fp_t r0, r1, t; + + // r0 = -2 * (a0 * b1 + a1 * b0) + fp_mul(r0, a[0], b[1]); + fp_mul(t, a[1], b[0]); + fp_add(r0, r0, t); + fp_dbl(r0, r0); + fp_neg(r0, r0); + + // r1 = a0 * b0 - 2 * a1 * b1 + fp_mul(r1, a[0], b[0]); + fp_mul(t, a[1], b[1]); + fp_dbl(t, t); + fp_sub(r1, r1, t); + + fp_copy(r[0], r0); + fp_copy(r[1], r1); +} + +static void fp2_mul_fp(fp2_t r, const fp2_t a, const fp_t k) +{ + fp_mul(r[0], a[0], k); + fp_mul(r[1], a[1], k); +} + +static void fp2_sqr(fp2_t r, const fp2_t a) +{ + fp_t r0, r1, t; + + // a0^2 - 2 * a1^2 + fp_sqr(r0, a[0]); + fp_sqr(t, a[1]); + fp_dbl(t, t); + fp_sub(r0, r0, t); + + // r1 = 2 * a0 * a1 + fp_mul(r1, a[0], a[1]); + fp_dbl(r1, r1); + + bn_copy(r[0], r0); + bn_copy(r[1], r1); +} + +static void fp2_sqr_u(fp2_t r, const fp2_t a) +{ + fp_t r0, r1, t; + + // r0 = -4 * a0 * a1 + fp_mul(r0, a[0], a[1]); + fp_dbl(r0, r0); + fp_dbl(r0, r0); + fp_neg(r0, r0); + + // r1 = a0^2 - 2 * a1^2 + fp_sqr(r1, a[0]); + fp_sqr(t, a[1]); + fp_dbl(t, t); + fp_sub(r1, r1, t); + + fp_copy(r[0], r0); + fp_copy(r[1], r1); + +} + +static void fp2_inv(fp2_t r, const fp2_t a) +{ + if (fp_is_zero(a[0])) { + // r0 = 0 + fp_set_zero(r[0]); + // r1 = -(2 * a1)^-1 + fp_dbl(r[1], a[1]); + fp_inv(r[1], r[1]); + fp_neg(r[1], r[1]); + + } else if (fp_is_zero(a[1])) { + /* r1 = 0 */ + fp_set_zero(r[1]); + /* r0 = a0^-1 */ + fp_inv(r[0], a[0]); + + } else { + fp_t k, t; + + // k = (a[0]^2 + 2 * a[1]^2)^-1 + fp_sqr(k, a[0]); + fp_sqr(t, a[1]); + fp_dbl(t, t); + fp_add(k, k, t); + fp_inv(k, k); + + // r[0] = a[0] * k + fp_mul(r[0], a[0], k); + + // r[1] = -a[1] * k + fp_mul(r[1], a[1], k); + fp_neg(r[1], r[1]); + } +} + +static void fp2_div(fp2_t r, const fp2_t a, const fp2_t b) +{ + fp2_t t; + fp2_inv(t, b); + fp2_mul(r, a, t); +} + +static void fp2_div2(fp2_t r, const fp2_t a) +{ + fp_div2(r[0], a[0]); + fp_div2(r[1], a[1]); +} + +static const fp4_t FP4_ZERO = {{{0,0,0,0,0,0,0,0},{0,0,0,0,0,0,0,0}}, {{0,0,0,0,0,0,0,0},{0,0,0,0,0,0,0,0}}}; +static const fp4_t FP4_ONE = {{{1,0,0,0,0,0,0,0},{0,0,0,0,0,0,0,0}}, {{0,0,0,0,0,0,0,0},{0,0,0,0,0,0,0,0}}}; +static const fp4_t FP4_U = {{{0,0,0,0,0,0,0,0},{1,0,0,0,0,0,0,0}}, {{0,0,0,0,0,0,0,0},{0,0,0,0,0,0,0,0}}}; +static const fp4_t FP4_V = {{{0,0,0,0,0,0,0,0},{0,0,0,0,0,0,0,0}}, {{1,0,0,0,0,0,0,0},{0,0,0,0,0,0,0,0}}}; + +#define fp4_init(r) memcpy((r), &FP4_ZERO, sizeof(fp4_t)) +#define fp4_clean(r) memcpy((r), &FP4_ZERO, sizeof(fp4_t)) +#define fp4_set_zero(r) memcpy((r), &FP4_ZERO, sizeof(fp4_t)) +#define fp4_set_one(r) memcpy((r), &FP4_ONE, sizeof(fp4_t)) +#define fp4_is_zero(a) (memcmp((a), &FP4_ZERO, sizeof(fp4_t)) == 0) +#define fp4_is_one(a) (memcmp((a), &FP4_ONE, sizeof(fp4_t)) == 0) +#define fp4_equ(a,b) (memcmp((a), (b), sizeof(fp4_t)) == 0) +#define fp4_copy(r,a) memcpy((r), (a), sizeof(fp4_t)) + + + +static void fp4_from_hex(fp4_t r, const char hex[65 * 4]) +{ + fp2_from_hex(r[1], hex); + fp2_from_hex(r[0], hex + 65 * 2); +} + +static void fp4_to_hex(const fp4_t a, char hex[65 * 4]) +{ + fp2_to_hex(a[1], hex); + hex[65 + 64] = '\n'; + fp2_to_hex(a[0], hex + 65 * 2); +} + +static void fp4_set_fp(fp4_t r, const fp_t a) +{ + fp2_set_fp(r[0], a); + fp2_set_zero(r[1]); +} + +static void fp4_set_fp2(fp4_t r, const fp2_t a) +{ + fp2_copy(r[0], a); + fp2_set_zero(r[1]); +} + +static void fp4_set(fp4_t r, const fp2_t a0, const fp2_t a1) +{ + fp2_copy(r[0], a0); + fp2_copy(r[1], a1); +} + +/* +static void fp4_set_one(fp4_t r) +{ + fp2_set_one(r[0]); + fp2_set_zero(r[1]); +} +*/ + +static void fp4_set_u(fp4_t r) +{ + fp2_set_u(r[0]); + fp2_set_zero(r[1]); +} + +static void fp4_set_v(fp4_t r) +{ + fp2_set_zero(r[0]); + fp2_set_one(r[1]); +} + +static void fp4_add(fp4_t r, const fp4_t a, const fp4_t b) +{ + fp2_add(r[0], a[0], b[0]); + fp2_add(r[1], a[1], b[1]); +} + +static void fp4_dbl(fp4_t r, const fp4_t a) +{ + fp2_dbl(r[0], a[0]); + fp2_dbl(r[1], a[1]); +} + +static void fp4_sub(fp4_t r, const fp4_t a, const fp4_t b) +{ + fp2_sub(r[0], a[0], b[0]); + fp2_sub(r[1], a[1], b[1]); +} + +static void fp4_neg(fp4_t r, const fp4_t a) +{ + fp2_neg(r[0], a[0]); + fp2_neg(r[1], a[1]); +} + +static void fp4_mul(fp4_t r, const fp4_t a, const fp4_t b) +{ + fp2_t r0, r1, t; + + fp2_mul(r0, a[0], b[0]); + fp2_mul_u(t, a[1], b[1]); + fp2_add(r0, r0, t); + + fp2_mul(r1, a[0], b[1]); + fp2_mul(t, a[1], b[0]); + fp2_add(r1, r1, t); + + fp2_copy(r[0], r0); + fp2_copy(r[1], r1); +} + +static void fp4_mul_fp(fp4_t r, const fp4_t a, const fp_t k) +{ + fp2_mul_fp(r[0], a[0], k); + fp2_mul_fp(r[1], a[1], k); +} + +static void fp4_mul_fp2(fp4_t r, const fp4_t a, const fp2_t b0) +{ + fp2_mul(r[0], a[0], b0); + fp2_mul(r[1], a[1], b0); +} + +static void fp4_mul_v(fp4_t r, const fp4_t a, const fp4_t b) +{ + fp2_t r0, r1, t; + + fp2_mul_u(r0, a[0], b[1]); + fp2_mul_u(t, a[1], b[0]); + fp2_add(r0, r0, t); + + fp2_mul(r1, a[0], b[0]); + fp2_mul_u(t, a[1], b[1]); + fp2_add(r1, r1, t); + + fp2_copy(r[0], r0); + fp2_copy(r[1], r1); +} + +static void fp4_sqr(fp4_t r, const fp4_t a) +{ + fp2_t r0, r1, t; + + fp2_sqr(r0, a[0]); + fp2_sqr_u(t, a[1]); + fp2_add(r0, r0, t); + + fp2_mul(r1, a[0], a[1]); + fp2_dbl(r1, r1); + fp2_copy(r[0], r0); + fp2_copy(r[1], r1); +} + +static void fp4_sqr_v(fp4_t r, const fp4_t a) +{ + fp2_t r0, r1, t; + + fp2_mul_u(t, a[0], a[1]); + fp2_dbl(r0, t); + + fp2_sqr(r1, a[0]); + fp2_sqr_u(t, a[1]); + fp2_add(r1, r1, t); + + fp2_copy(r[0], r0); + fp2_copy(r[1], r1); +} + +static void fp4_inv(fp4_t r, const fp4_t a) +{ + fp2_t r0, r1, k; + + fp2_sqr_u(k, a[1]); + fp2_sqr(r0, a[0]); + fp2_sub(k, k, r0); + fp2_inv(k, k); + + fp2_mul(r0, a[0], k); + fp2_neg(r0, r0); + + fp2_mul(r1, a[1], k); + + fp2_copy(r[0], r0); + fp2_copy(r[1], r1); +} + + +#define fp12_init(r) memset((r), 0, sizeof(fp12_t)) +#define fp12_clean(r) memset((r), 0, sizeof(fp12_t)) +#define fp12_set_zero(r) memset((r), 0, sizeof(fp12_t)) +#define fp12_copy(r, a) memcpy((r), (a), sizeof(fp12_t)) + +static void fp12_set_one(fp12_t r) +{ + fp4_set_one(r[0]); + fp4_set_zero(r[1]); + fp4_set_zero(r[2]); +} + +static int fp12_is_one(const fp12_t a) +{ + return fp4_is_one(a[0]) + && fp4_is_zero(a[1]) + && fp4_is_zero(a[2]); +} + +static int fp12_is_zero(const fp12_t a) +{ + return fp4_is_zero(a[0]) + && fp4_is_zero(a[1]) + && fp4_is_zero(a[2]); +} + +static void fp12_from_hex(fp12_t r, const char hex[65 * 12]) +{ + fp4_from_hex(r[2], hex); + fp4_from_hex(r[1], hex + 65 * 4); + fp4_from_hex(r[0], hex + 65 * 8); +} + +static void fp12_to_hex(const fp12_t a, char hex[65 * 12]) +{ + fp4_to_hex(a[2], hex); + hex[65 * 4 - 1] = '\n'; + fp4_to_hex(a[1], hex + 65 * 4); + hex[65 * 8 - 1] = '\n'; + fp4_to_hex(a[0], hex + 65 * 8); +} + +static void fp12_print(const char *prefix, const fp12_t a) +{ + char hex[65 * 12]; + fp12_to_hex(a, hex); + printf("%s\n%s\n", prefix, hex); +} + +static void fp12_set(fp12_t r, const fp4_t a0, const fp4_t a1, const fp4_t a2) +{ + fp4_copy(r[0], a0); + fp4_copy(r[1], a1); + fp4_copy(r[2], a2); +} + +static void fp12_set_fp(fp12_t r, const fp_t a) +{ + fp4_set_fp(r[0], a); + fp4_set_zero(r[1]); + fp4_set_zero(r[2]); +} + +static void fp12_set_fp2(fp12_t r, const fp2_t a) +{ + fp4_set_fp2(r[0], a); + fp4_set_zero(r[1]); + fp4_set_zero(r[2]); +} + +static void fp12_set_fp4(fp12_t r, const fp4_t a) +{ + fp4_copy(r[0], a); + fp4_set_zero(r[1]); + fp4_set_zero(r[2]); +} + +static void fp12_set_u(fp12_t r) +{ + fp4_set_u(r[0]); + fp4_set_zero(r[1]); + fp4_set_zero(r[2]); +} + +static void fp12_set_v(fp12_t r) +{ + fp4_set_v(r[0]); + fp4_set_zero(r[1]); + fp4_set_zero(r[2]); +} + +static void fp12_set_w(fp12_t r) +{ + fp4_set_zero(r[0]); + fp4_set_one(r[1]); + fp4_set_zero(r[2]); +} + +static void fp12_set_w_sqr(fp12_t r) +{ + fp4_set_zero(r[0]); + fp4_set_zero(r[1]); + fp4_set_one(r[2]); +} + +static int fp12_equ(const fp12_t a, const fp12_t b) +{ + return fp4_equ(a[0], b[0]) + && fp4_equ(a[1], b[1]) + && fp4_equ(a[2], b[2]); +} + +static void fp12_add(fp12_t r, const fp12_t a, const fp12_t b) +{ + fp4_add(r[0], a[0], b[0]); + fp4_add(r[1], a[1], b[1]); + fp4_add(r[2], a[2], b[2]); +} + +static void fp12_dbl(fp12_t r, const fp12_t a) +{ + fp4_dbl(r[0], a[0]); + fp4_dbl(r[1], a[1]); + fp4_dbl(r[2], a[2]); +} + +static void fp12_tri(fp12_t r, const fp12_t a) +{ + fp12_t t; + fp12_dbl(t, a); + fp12_add(r, t, a); +} + +static void fp12_sub(fp12_t r, const fp12_t a, const fp12_t b) +{ + fp4_sub(r[0], a[0], b[0]); + fp4_sub(r[1], a[1], b[1]); + fp4_sub(r[2], a[2], b[2]); +} + +static void fp12_neg(fp12_t r, const fp12_t a) +{ + fp4_neg(r[0], a[0]); + fp4_neg(r[1], a[1]); + fp4_neg(r[2], a[2]); +} + +static void fp12_mul(fp12_t r, const fp12_t a, const fp12_t b) +{ + fp4_t r0, r1, r2, t; + + fp4_mul(r0, a[0], b[0]); + fp4_mul_v(t, a[1], b[2]); + fp4_add(r0, r0, t); + fp4_mul_v(t, a[2], b[1]); + fp4_add(r0, r0, t); + + fp4_mul(r1, a[0], b[1]); + fp4_mul(t, a[1], b[0]); + fp4_add(r1, r1, t); + fp4_mul_v(t, a[2], b[2]); + fp4_add(r1, r1, t); + + fp4_mul(r2, a[0], b[2]); + fp4_mul(t, a[1], b[1]); + fp4_add(r2, r2, t); + fp4_mul(t, a[2], b[0]); + fp4_add(r2, r2, t); + + fp4_copy(r[0], r0); + fp4_copy(r[1], r1); + fp4_copy(r[2], r2); +} + +static void fp12_sqr(fp12_t r, const fp12_t a) +{ + fp4_t r0, r1, r2, t; + + fp4_sqr(r0, a[0]); + fp4_mul_v(t, a[1], a[2]); + fp4_dbl(t, t); + fp4_add(r0, r0, t); + + fp4_mul(r1, a[0], a[1]); + fp4_dbl(r1, r1); + fp4_sqr_v(t, a[2]); + fp4_add(r1, r1, t); + + fp4_mul(r2, a[0], a[2]); + fp4_dbl(r2, r2); + fp4_sqr(t, a[1]); + fp4_add(r2, r2, t); + + fp4_copy(r[0], r0); + fp4_copy(r[1], r1); + fp4_copy(r[2], r2); +} + +static void fp12_inv(fp12_t r, const fp12_t a) +{ + if (fp4_is_zero(a[2])) { + fp4_t k, t; + + fp4_sqr(k, a[0]); + fp4_mul(k, k, a[0]); + fp4_sqr_v(t, a[1]); + fp4_mul(t, t, a[1]); + fp4_add(k, k, t); + fp4_inv(k, k); + + fp4_sqr(r[2], a[1]); + fp4_mul(r[2], r[2], k); + + fp4_mul(r[1], a[0], a[1]); + fp4_mul(r[1], r[1], k); + fp4_neg(r[1], r[1]); + + fp4_sqr(r[0], a[0]); + fp4_mul(r[0], r[0], k); + + } else { + fp4_t t0, t1, t2, t3; + + fp4_sqr(t0, a[1]); + fp4_mul(t1, a[0], a[2]); + fp4_sub(t0, t0, t1); + + fp4_mul(t1, a[0], a[1]); + fp4_sqr_v(t2, a[2]); + fp4_sub(t1, t1, t2); + + fp4_sqr(t2, a[0]); + fp4_mul_v(t3, a[1], a[2]); + fp4_sub(t2, t2, t3); + + fp4_sqr(t3, t1); + fp4_mul(r[0], t0, t2); + fp4_sub(t3, t3, r[0]); + fp4_inv(t3, t3); + fp4_mul(t3, a[2], t3); + + fp4_mul(r[0], t2, t3); + + fp4_mul(r[1], t1, t3); + fp4_neg(r[1], r[1]); + + fp4_mul(r[2], t0, t3); + } +} + +static void fp12_pow(fp12_t r, const fp12_t a, const bn_t k) +{ + char kbits[257]; + fp12_t t; + int i; + + assert(bn_cmp(k, SM9_P_MINUS_ONE) < 0); + fp12_set_zero(t); + + bn_to_bits(k, kbits); + fp12_copy(t, a); + for (i = 1; i < 256; i++) { + fp12_sqr(t, t); + if (kbits[i] == '1') { + fp12_mul(t, t, a); + } + } + fp12_copy(r, t); +} + +static void fp2_conjugate(fp2_t r, const fp2_t a) +{ + fp_copy(r[0], a[0]); + fp_neg (r[1], a[1]); + +} + +static void fp2_frobenius(fp2_t r, const fp2_t a) +{ + return fp2_conjugate(r, a); +} + +// beta = 0x6c648de5dc0a3f2cf55acc93ee0baf159f9d411806dc5177f5b21fd3da24d011 +// alpha1 = 0x3f23ea58e5720bdb843c6cfa9c08674947c5c86e0ddd04eda91d8354377b698b +// alpha2 = 0xf300000002a3a6f2780272354f8b78f4d5fc11967be65334 +// alpha3 = 0x6c648de5dc0a3f2cf55acc93ee0baf159f9d411806dc5177f5b21fd3da24d011 +// alpha4 = 0xf300000002a3a6f2780272354f8b78f4d5fc11967be65333 +// alpha5 = 0x2d40a38cf6983351711e5f99520347cc57d778a9f8ff4c8a4c949c7fa2a96686 +static const fp2_t SM9_BETA = {{0xda24d011, 0xf5b21fd3, 0x06dc5177, 0x9f9d4118, 0xee0baf15, 0xf55acc93, 0xdc0a3f2c, 0x6c648de5}, {0}}; +static const fp_t SM9_ALPHA1 = {0x377b698b, 0xa91d8354, 0x0ddd04ed, 0x47c5c86e, 0x9c086749, 0x843c6cfa, 0xe5720bdb, 0x3f23ea58}; +static const fp_t SM9_ALPHA2 = {0x7be65334, 0xd5fc1196, 0x4f8b78f4, 0x78027235, 0x02a3a6f2, 0xf3000000, 0x0, 0x0 }; +static const fp_t SM9_ALPHA3 = {0xda24d011, 0xf5b21fd3, 0x06dc5177, 0x9f9d4118, 0xee0baf15, 0xf55acc93, 0xdc0a3f2c, 0x6c648de5}; +static const fp_t SM9_ALPHA4 = {0x7be65333, 0xd5fc1196, 0x4f8b78f4, 0x78027235, 0x02a3a6f2, 0xf3000000, 0x0, 0x0 }; +static const fp_t SM9_ALPHA5 = {0xa2a96686, 0x4c949c7f, 0xf8ff4c8a, 0x57d778a9, 0x520347cc, 0x711e5f99, 0xf6983351, 0x2d40a38c}; + + +static void fp4_frobenius(fp4_t r, const fp4_t a) +{ + fp2_conjugate(r[0], a[0]); + fp2_conjugate(r[1], a[1]); + fp2_mul(r[1], r[1], SM9_BETA); +} + +static void fp4_conjugate(fp4_t r, const fp4_t a) +{ + fp2_copy(r[0], a[0]); + fp2_neg(r[1], a[1]); +} + +static void fp4_frobenius2(fp4_t r, const fp4_t a) +{ + return fp4_conjugate(r, a); +} + +static void fp4_frobenius3(fp4_t r, const fp4_t a) +{ + fp2_conjugate(r[0], a[0]); + fp2_conjugate(r[1], a[1]); + fp2_mul(r[1], r[1], SM9_BETA); + fp2_neg(r[1], r[1]); +} + +static void fp12_frobenius(fp12_t r, const fp12_t x) +{ + const fp2_t *xa = x[0]; + const fp2_t *xb = x[1]; + const fp2_t *xc = x[2]; + fp4_t ra; + fp4_t rb; + fp4_t rc; + + fp2_conjugate(ra[0], xa[0]); + fp2_conjugate(ra[1], xa[1]); + fp2_mul_fp(ra[1], ra[1], SM9_ALPHA3); + + fp2_conjugate(rb[0], xb[0]); + fp2_mul_fp(rb[0], rb[0], SM9_ALPHA1); + fp2_conjugate(rb[1], xb[1]); + fp2_mul_fp(rb[1], rb[1], SM9_ALPHA4); + + fp2_conjugate(rc[0], xc[0]); + fp2_mul_fp(rc[0], rc[0], SM9_ALPHA2); + fp2_conjugate(rc[1], xc[1]); + fp2_mul_fp(rc[1], rc[1], SM9_ALPHA5); + + fp12_set(r, ra, rb, rc); +} + +static void fp12_frobenius2(fp12_t r, const fp12_t x) +{ + fp4_t a; + fp4_t b; + fp4_t c; + + fp4_conjugate(a, x[0]); + fp4_conjugate(b, x[1]); + fp4_mul_fp(b, b, SM9_ALPHA2); + fp4_conjugate(c, x[2]); + fp4_mul_fp(c, c, SM9_ALPHA4); + + fp4_copy(r[0], a); + fp4_copy(r[1], b); + fp4_copy(r[2], c); +} + +static void fp12_frobenius3(fp12_t r, const fp12_t x) +{ + const fp2_t *xa = x[0]; + const fp2_t *xb = x[1]; + const fp2_t *xc = x[2]; + fp4_t ra; + fp4_t rb; + fp4_t rc; + + fp2_conjugate(ra[0], xa[0]); + fp2_conjugate(ra[1], xa[1]); + fp2_mul(ra[1], ra[1], SM9_BETA); + fp2_neg(ra[1], ra[1]); + + fp2_conjugate(rb[0], xb[0]); + fp2_mul(rb[0], rb[0], SM9_BETA); + fp2_conjugate(rb[1], xb[1]); + + fp2_conjugate(rc[0], xc[0]); + fp2_neg(rc[0], rc[0]); + fp2_conjugate(rc[1], xc[1]); + fp2_mul(rc[1], rc[1], SM9_BETA); + + fp4_copy(r[0], ra); + fp4_copy(r[1], rb); + fp4_copy(r[2], rc); +} + +static void fp12_frobenius6(fp12_t r, const fp12_t x) +{ + fp4_t a; + fp4_t b; + fp4_t c; + + fp4_copy(a, x[0]); + fp4_copy(b, x[1]); + fp4_copy(c, x[2]); + + fp4_conjugate(a, a); + fp4_conjugate(b, b); + fp4_neg(b, b); + fp4_conjugate(c, c); + + fp4_copy(r[0], a); + fp4_copy(r[1], b); + fp4_copy(r[2], c); +} + + +static void point_init(point_t *R) +{ + fp_set_zero(R->X); + fp_set_zero(R->Y); + fp_set_one(R->Z); +} + +static void point_from_hex(point_t *R, const char hex[65 * 2]) +{ + bn_from_hex(R->X, hex); + bn_from_hex(R->Y, hex + 65); + bn_set_one(R->Z); +} + +#define point_copy(R, P) memcpy((R), (P), sizeof(point_t)) + +static int point_is_at_infinity(const point_t *P) { + return fp_is_zero(P->X); +} + +static void point_set_infinity(point_t *R) { + fp_set_one(R->X); + fp_set_one(R->Y); + fp_set_zero(R->Z); +} + +static void point_get_xy(const point_t *P, fp_t x, fp_t y) +{ + fp_t z_inv; + + assert(!fp_is_zero(P->Z)); + + if (fp_is_one(P->Z)) { + fp_copy(x, P->X); + fp_copy(y, P->Y); + } + + fp_inv(z_inv, P->Z); + if (y) + fp_mul(y, P->Y, z_inv); + fp_sqr(z_inv, z_inv); + fp_mul(x, P->X, z_inv); + if (y) + fp_mul(y, y, z_inv); +} + +static int point_equ(const point_t *P, const point_t *Q) +{ + fp_t t1, t2, t3, t4; + fp_sqr(t1, P->Z); + fp_sqr(t2, Q->Z); + fp_mul(t3, P->X, t2); + fp_mul(t4, Q->X, t1); + if (!fp_equ(t3, t4)) { + return 0; + } + fp_mul(t1, t1, P->Z); + fp_mul(t2, t2, Q->Z); + fp_mul(t3, P->Y, t2); + fp_mul(t4, Q->Y, t1); + return fp_equ(t3, t4); +} + +static int point_is_on_curve(const point_t *P) +{ + fp_t t0, t1, t2; + if (fp_is_one(P->Z)) { + fp_sqr(t0, P->Y); + fp_sqr(t1, P->X); + fp_mul(t1, t1, P->X); + fp_add(t1, t1, FIVE); + } else { + fp_sqr(t0, P->X); + fp_mul(t0, t0, P->X); + fp_sqr(t1, P->Z); + fp_sqr(t2, t1); + fp_mul(t1, t1, t2); + fp_mul(t1, t1, FIVE); + fp_add(t1, t0, t1); + fp_sqr(t0, P->Y); + } + return fp_equ(t0, t1); +} + +static void point_dbl(point_t *R, const point_t *P) +{ + const uint64_t *X1 = P->X; + const uint64_t *Y1 = P->Y; + const uint64_t *Z1 = P->Z; + fp_t X3, Y3, Z3, T1, T2, T3; + + if (point_is_at_infinity(P)) { + point_copy(R, P); + return; + } + + fp_sqr(T2, X1); + fp_tri(T2, T2); + fp_dbl(Y3, Y1); + fp_mul(Z3, Y3, Z1); + fp_sqr(Y3, Y3); + fp_mul(T3, Y3, X1); + fp_sqr(Y3, Y3); + fp_div2(Y3, Y3); + fp_sqr(X3, T2); + fp_dbl(T1, T3); + fp_sub(X3, X3, T1); + fp_sub(T1, T3, X3); + fp_mul(T1, T1, T2); + fp_sub(Y3, T1, Y3); + + fp_copy(R->X, X3); + fp_copy(R->Y, Y3); + fp_copy(R->Z, Z3); +} + +static void point_add(point_t *R, const point_t *P, const point_t *Q) +{ + const uint64_t *X1 = P->X; + const uint64_t *Y1 = P->Y; + const uint64_t *Z1 = P->Z; + const uint64_t *x2 = Q->X; + const uint64_t *y2 = Q->Y; + fp_t X3, Y3, Z3, T1, T2, T3, T4; + + if (point_is_at_infinity(Q)) { + point_copy(R, P); + return; + } + if (point_is_at_infinity(P)) { + point_copy(R, Q); + return; + } + + fp_sqr(T1, Z1); + fp_mul(T2, T1, Z1); + fp_mul(T1, T1, x2); + fp_mul(T2, T2, y2); + fp_sub(T1, T1, X1); + fp_sub(T2, T2, Y1); + + if (fp_is_zero(T1)) { + if (fp_is_zero(T2)) { + point_dbl(R, Q); + return; + } else { + point_set_infinity(R); + return; + } + } + + fp_mul(Z3, Z1, T1); + fp_sqr(T3, T1); + fp_mul(T4, T3, T1); + fp_mul(T3, T3, X1); + fp_dbl(T1, T3); + fp_sqr(X3, T2); + fp_sub(X3, X3, T1); + fp_sub(X3, X3, T4); + fp_sub(T3, T3, X3); + fp_mul(T3, T3, T2); + fp_mul(T4, T4, Y1); + fp_sub(Y3, T3, T4); + + fp_copy(R->X, X3); + fp_copy(R->Y, Y3); + fp_copy(R->Z, Z3); +} + +static void point_neg(point_t *R, const point_t *P) +{ + fp_copy(R->X, P->X); + fp_neg(R->Y, P->Y); + fp_copy(R->Z, P->Z); +} + +static void point_sub(point_t *R, const point_t *P, const point_t *Q) +{ + point_t _T, *T = &_T; + point_neg(T, Q); + point_add(R, P, T); +} + +static void point_mul(point_t *R, const bn_t k, const point_t *P) +{ + char kbits[257]; + point_t _Q, *Q = &_Q; + int i; + + bn_to_bits(k, kbits); + for (i = 0; i < 256; i++) { + point_dbl(Q, Q); + if (kbits[i] == '1') { + point_add(Q, Q, P); + } + } + point_copy(R, Q); +} + +static void point_mul_generator(point_t *R, const bn_t k) +{ + point_mul(R, k, SM9_P1); +} + + +static void twist_point_from_hex(twist_point_t *R, const char hex[65 * 4]) +{ + fp2_from_hex(R->X, hex); + fp2_from_hex(R->Y, hex + 65 * 2); + fp2_set_one(R->Z); +} + +#define twist_point_copy(R, P) memcpy((R), (P), sizeof(twist_point_t)) + +static int twist_point_is_at_infinity(const twist_point_t *P) +{ + return fp2_is_zero(P->Z); +} + +static void twist_point_set_infinity(twist_point_t *R) +{ + fp2_set_one(R->X); + fp2_set_one(R->Y); + fp2_set_zero(R->Z); +} + +static void twist_point_get_xy(const twist_point_t *P, fp2_t x, fp2_t y) +{ + fp2_t z_inv; + + assert(!fp2_is_zero(P->Z)); + + if (fp2_is_one(P->Z)) { + fp2_copy(x, P->X); + fp2_copy(y, P->Y); + } + + fp2_inv(z_inv, P->Z); + if (y) + fp2_mul(y, P->Y, z_inv); + fp2_sqr(z_inv, z_inv); + fp2_mul(x, P->X, z_inv); + if (y) + fp2_mul(y, y, z_inv); +} + + + + + + + +static int twist_point_equ(const twist_point_t *P, const twist_point_t *Q) +{ + fp2_t t1, t2, t3, t4; + + fp2_sqr(t1, P->Z); + fp2_sqr(t2, Q->Z); + fp2_mul(t3, P->X, t2); + fp2_mul(t4, Q->X, t1); + if (!fp2_equ(t3, t4)) { + return 0; + } + fp2_mul(t1, t1, P->Z); + fp2_mul(t2, t2, Q->Z); + fp2_mul(t3, P->Y, t2); + fp2_mul(t4, Q->Y, t1); + return fp2_equ(t3, t4); +} + +static int twist_point_is_on_curve(const twist_point_t *P) +{ + fp2_t t0, t1, t2; + + if (fp2_is_one(P->Z)) { + fp2_sqr(t0, P->Y); + fp2_sqr(t1, P->X); + fp2_mul(t1, t1, P->X); + fp2_add(t1, t1, FP2_5U); + + } else { + fp2_sqr(t0, P->X); + fp2_mul(t0, t0, P->X); + fp2_sqr(t1, P->Z); + fp2_sqr(t2, t1); + fp2_mul(t1, t1, t2); + fp2_mul(t1, t1, FP2_5U); + fp2_add(t1, t0, t1); + fp2_sqr(t0, P->Y); + } + + return fp2_equ(t0, t1); +} + +static void twist_point_neg(twist_point_t *R, const twist_point_t *P) +{ + fp2_copy(R->X, P->X); + fp2_neg(R->Y, P->Y); + fp2_copy(R->Z, P->Z); +} + +static void twist_point_dbl(twist_point_t *R, const twist_point_t *P) +{ + const fp_t *X1 = P->X; + const fp_t *Y1 = P->Y; + const fp_t *Z1 = P->Z; + fp2_t X3, Y3, Z3, T1, T2, T3; + + if (twist_point_is_at_infinity(P)) { + twist_point_copy(R, P); + return; + } + fp2_sqr(T2, X1); + fp2_tri(T2, T2); + fp2_dbl(Y3, Y1); + fp2_mul(Z3, Y3, Z1); + fp2_sqr(Y3, Y3); + fp2_mul(T3, Y3, X1); + fp2_sqr(Y3, Y3); + fp2_div2(Y3, Y3); + fp2_sqr(X3, T2); + fp2_dbl(T1, T3); + fp2_sub(X3, X3, T1); + fp2_sub(T1, T3, X3); + fp2_mul(T1, T1, T2); + fp2_sub(Y3, T1, Y3); + + fp2_copy(R->X, X3); + fp2_copy(R->Y, Y3); + fp2_copy(R->Z, Z3); +} + +static void twist_point_add(twist_point_t *R, const twist_point_t *P, const twist_point_t *Q) +{ + const fp_t *X1 = P->X; + const fp_t *Y1 = P->Y; + const fp_t *Z1 = P->Z; + const fp_t *x2 = Q->X; + const fp_t *y2 = Q->Y; + fp2_t X3, Y3, Z3, T1, T2, T3, T4; + + if (twist_point_is_at_infinity(Q)) { + twist_point_copy(R, P); + return; + } + if (twist_point_is_at_infinity(P)) { + twist_point_copy(R, Q); + return; + } + + fp2_sqr(T1, Z1); + fp2_mul(T2, T1, Z1); + fp2_mul(T1, T1, x2); + fp2_mul(T2, T2, y2); + fp2_sub(T1, T1, X1); + fp2_sub(T2, T2, Y1); + if (fp2_is_zero(T1)) { + if (fp2_is_zero(T2)) { + twist_point_dbl(R, Q); + return; + } else { + twist_point_set_infinity(R); + return; + } + } + fp2_mul(Z3, Z1, T1); + fp2_sqr(T3, T1); + fp2_mul(T4, T3, T1); + fp2_mul(T3, T3, X1); + fp2_dbl(T1, T3); + fp2_sqr(X3, T2); + fp2_sub(X3, X3, T1); + fp2_sub(X3, X3, T4); + fp2_sub(T3, T3, X3); + fp2_mul(T3, T3, T2); + fp2_mul(T4, T4, Y1); + fp2_sub(Y3, T3, T4); + + fp2_copy(R->X, X3); + fp2_copy(R->Y, Y3); + fp2_copy(R->Z, Z3); +} + +static void twist_point_sub(twist_point_t *R, const twist_point_t *P, const twist_point_t *Q) +{ + twist_point_t _T, *T = &_T; + twist_point_neg(T, Q); + twist_point_add(R, P, T); +} + +static void twist_point_add_full(twist_point_t *R, const twist_point_t *P, const twist_point_t *Q) +{ + const fp_t *X1 = P->X; + const fp_t *Y1 = P->Y; + const fp_t *Z1 = P->Z; + const fp_t *X2 = Q->X; + const fp_t *Y2 = Q->Y; + const fp_t *Z2 = Q->Z; + fp2_t T1, T2, T3, T4, T5, T6, T7, T8; + + if (twist_point_is_at_infinity(Q)) { + twist_point_copy(R, P); + return; + } + if (twist_point_is_at_infinity(P)) { + twist_point_copy(R, Q); + return; + } + + fp2_sqr(T1, Z1); + fp2_sqr(T2, Z2); + fp2_mul(T3, X2, T1); + fp2_mul(T4, X1, T2); + fp2_add(T5, T3, T4); + fp2_sub(T3, T3, T4); + fp2_mul(T1, T1, Z1); + fp2_mul(T1, T1, Y2); + fp2_mul(T2, T2, Z2); + fp2_mul(T2, T2, Y1); + fp2_add(T6, T1, T2); + fp2_sub(T1, T1, T2); + + if (fp2_is_zero(T1) && fp2_is_zero(T3)) { + return twist_point_dbl(R, P); + } + if (fp2_is_zero(T1) && fp2_is_zero(T6)) { + return twist_point_set_infinity(R); + } + + fp2_sqr(T6, T1); + fp2_mul(T7, T3, Z1); + fp2_mul(T7, T7, Z2); + fp2_sqr(T8, T3); + fp2_mul(T5, T5, T8); + fp2_mul(T3, T3, T8); + fp2_mul(T4, T4, T8); + fp2_sub(T6, T6, T5); + fp2_sub(T4, T4, T6); + fp2_mul(T1, T1, T4); + fp2_mul(T2, T2, T3); + fp2_sub(T1, T1, T2); + + fp2_copy(R->X, T6); + fp2_copy(R->Y, T1); + fp2_copy(R->Z, T7); +} + +static void twist_point_mul(twist_point_t *R, const bn_t k, const twist_point_t *P) +{ + twist_point_t _Q, *Q = &_Q; + char kbits[256]; + int i; + + bn_to_bits(k, kbits); + for (i = 0; i < 256; i++) { + twist_point_dbl(Q, Q); + if (kbits[i] == '1') { + twist_point_add(Q, Q, P); + } + } + twist_point_copy(R, Q); +} + +static void twist_point_mul_G(twist_point_t *R, const bn_t k) +{ + twist_point_mul(R, k, SM9_P2); +} + +static void eval_g_tangent(fp12_t num, fp12_t den, const twist_point_t *P, const point_t *Q) +{ + const fp_t *XP = P->X; + const fp_t *YP = P->Y; + const fp_t *ZP = P->Z; + const uint64_t *xQ = Q->X; + const uint64_t *yQ = Q->Y; + + fp_t *a0 = num[0][0]; + fp_t *a1 = num[0][1]; + fp_t *a4 = num[2][0]; + fp_t *b1 = den[0][1]; + + fp2_t t0; + fp2_t t1; + fp2_t t2; + + + fp12_set_zero(num); + fp12_set_zero(den); + + fp2_sqr(t0, ZP); + fp2_mul(t1, t0, ZP); + fp2_mul(b1, t1, YP); + + fp2_mul_fp(t2, b1, yQ); + fp2_neg(a1, t2); + + fp2_sqr(t1, XP); + fp2_mul(t0, t0, t1); + fp2_mul_fp(t0, t0, xQ); + fp2_tri(t0, t0); + fp2_div2(a4, t0); + + fp2_mul(t1, t1, XP); + fp2_tri(t1, t1); + fp2_div2(t1, t1); + fp2_sqr(t0, YP); + fp2_sub(a0, t0, t1); +} + +static void eval_g_line(fp12_t num, fp12_t den, const twist_point_t *T, const twist_point_t *P, const point_t *Q) +{ + const fp_t *XT = T->X; + const fp_t *YT = T->Y; + const fp_t *ZT = T->Z; + const fp_t *XP = P->X; + const fp_t *YP = P->Y; + const fp_t *ZP = P->Z; + const uint64_t *xQ = Q->X; + const uint64_t *yQ = Q->Y; + + fp_t *a0 = num[0][0]; + fp_t *a1 = num[0][1]; + fp_t *a4 = num[2][0]; + fp_t *b1 = den[0][1]; + + fp2_t T0, T1, T2, T3, T4; + + + fp12_set_zero(num); + fp12_set_zero(den); + + fp2_sqr(T0, ZP); + fp2_mul(T1, T0, XT); + fp2_mul(T0, T0, ZP); + fp2_sqr(T2, ZT); + fp2_mul(T3, T2, XP); + fp2_mul(T2, T2, ZT); + fp2_mul(T2, T2, YP); + fp2_sub(T1, T1, T3); + fp2_mul(T1, T1, ZT); + fp2_mul(T1, T1, ZP); + fp2_mul(T4, T1, T0); + fp2_copy(b1, T4); + fp2_mul(T1, T1, YP); + fp2_mul(T3, T0, YT); + fp2_sub(T3, T3, T2); + fp2_mul(T0, T0, T3); + fp2_mul_fp(T0, T0, xQ); + fp2_copy(a4, T0); + fp2_mul(T3, T3, XP); + fp2_mul(T3, T3, ZP); + fp2_sub(T1, T1, T3); + fp2_copy(a0, T1); + fp2_mul_fp(T2, T4, yQ); + fp2_neg(T2, T2); + fp2_copy(a1, T2); +} + +static void twist_point_pi1(twist_point_t *R, const twist_point_t *P) +{ + //const c = 0x3f23ea58e5720bdb843c6cfa9c08674947c5c86e0ddd04eda91d8354377b698bn; + const fp_t c = { + 0x377b698b, 0xa91d8354, 0x0ddd04ed, 0x47c5c86e, + 0x9c086749, 0x843c6cfa, 0xe5720bdb, 0x3f23ea58, + }; + fp2_conjugate(R->X, P->X); + fp2_conjugate(R->Y, P->Y); + fp2_conjugate(R->Z, P->Z); + fp2_mul_fp(R->Z, R->Z, c); + +} + +static void twist_point_pi2(twist_point_t *R, const twist_point_t *P) +{ + //c = 0xf300000002a3a6f2780272354f8b78f4d5fc11967be65334 + const fp_t c = { + 0x7be65334, 0xd5fc1196, 0x4f8b78f4, 0x78027235, + 0x02a3a6f2, 0xf3000000, 0, 0, + }; + fp2_copy(R->X, P->X); + fp2_copy(R->Y, P->Y); + fp2_mul_fp(R->Z, P->Z, c); +} + +static void twist_point_neg_pi2(twist_point_t *R, const twist_point_t *P) +{ + // c = 0xf300000002a3a6f2780272354f8b78f4d5fc11967be65334 + const fp_t c = { + 0x7be65334, 0xd5fc1196, 0x4f8b78f4, 0x78027235, + 0x02a3a6f2, 0xf3000000, 0, 0, + }; + fp2_copy(R->X, P->X); + fp2_neg(R->Y, P->Y); + fp2_mul_fp(R->Z, P->Z, c); +} + + +static void final_exponent_hard_part(fp12_t r, const fp12_t f) +{ + // a2 = 0xd8000000019062ed0000b98b0cb27659 + // a3 = 0x2400000000215d941 + const bn_t a2 = {0xcb27659, 0x0000b98b, 0x019062ed, 0xd8000000, 0, 0, 0, 0}; + const bn_t a3 = {0x215d941, 0x40000000, 0x2, 0, 0, 0, 0, 0}; + const bn_t nine = {9,0,0,0,0,0,0,0}; + fp12_t t0, t1, t2, t3; + + fp12_pow(t0, f, a3); + fp12_inv(t0, t0); + fp12_frobenius(t1, t0); + fp12_mul(t1, t0, t1); + + fp12_mul(t0, t0, t1); + fp12_frobenius(t2, f); + fp12_mul(t3, t2, f); + fp12_pow(t3, t3, nine); + + fp12_mul(t0, t0, t3); + fp12_sqr(t3, f); + fp12_sqr(t3, t3); + fp12_mul(t0, t0, t3); + fp12_sqr(t2, t2); + fp12_mul(t2, t2, t1); + fp12_frobenius2(t1, f); + fp12_mul(t1, t1, t2); + + fp12_pow(t2, t1, a2); + fp12_mul(t0, t2, t0); + fp12_frobenius3(t1, f); + fp12_mul(t1, t1, t0); + + fp12_copy(r, t1); +} + +static void final_exponent(fp12_t r, const fp12_t f) +{ + fp12_t t0; + fp12_t t1; + + fp12_frobenius6(t0, f); + fp12_inv(t1, f); + fp12_mul(t0, t0, t1); + fp12_frobenius2(t1, t0); + fp12_mul(t0, t0, t1); + final_exponent_hard_part(t0, t0); + + fp12_copy(r, t0); +} + +static void sm9_pairing(fp12_t r, const twist_point_t *Q, const point_t *P) { + const char *abits = "00100000000000000000000000000000000000010000101011101100100111110"; + + twist_point_t _T, *T = &_T; + twist_point_t _Q1, *Q1 = &_Q1; + twist_point_t _Q2, *Q2 = &_Q2; + + fp12_t f_num; + fp12_t f_den; + fp12_t g_num; + fp12_t g_den; + int i; + + twist_point_copy(T, Q); + + fp12_set_one(f_num); + fp12_set_one(f_den); + + for (i = 0; i < strlen(abits); i++) { + + fp12_sqr(f_num, f_num); + fp12_sqr(f_den, f_den); + eval_g_tangent(g_num, g_den, T, P); + fp12_mul(f_num, f_num, g_num); + fp12_mul(f_den, f_den, g_den); + + twist_point_dbl(T, T); + + if (abits[i] == '1') { + eval_g_line(g_num, g_den, T, Q, P); + fp12_mul(f_num, f_num, g_num); + fp12_mul(f_den, f_den, g_den); + twist_point_add(T, T, Q); + } + } + + twist_point_pi1(Q1, Q); + twist_point_neg_pi2(Q2, Q); + + eval_g_line(g_num, g_den, T, Q1, P); + fp12_mul(f_num, f_num, g_num); + fp12_mul(f_den, f_den, g_den); + twist_point_add_full(T, T, Q1); + + eval_g_line(g_num, g_den, T, Q2, P); + fp12_mul(f_num, f_num, g_num); + fp12_mul(f_den, f_den, g_den); + twist_point_add_full(T, T, Q2); + + fp12_inv(f_den, f_den); + fp12_mul(r, f_num, f_den); + + final_exponent(r, r); +} + +#if 0 +static void pairing_test() { + + let r = fp12_new(); + const char g[] = + "aab9f06a4eeba4323a7833db202e4e35639d93fa3305af73f0f071d7d284fcfb\n", + "84b87422330d7936eaba1109fa5a7a7181ee16f2438b0aeb2f38fd5f7554e57a\n", + "4c744e69c4a2e1c8ed72f796d151a17ce2325b943260fc460b9f73cb57c9014b\n", + "b3129a75d31d17194675a1bc56947920898fbf390a5bf5d931ce6cbb3340f66d\n", + "93634f44fa13af76169f3cc8fbea880adaff8475d5fd28a75deb83c44362b439\n", + "1604a3fcfa9783e667ce9fcb1062c2a5c6685c316dda62de0548baa6ba30038b\n", + "5a1ae172102efd95df7338dbc577c66d8d6c15e0a0158c7507228efb078f42a6\n", + "67e0e0c2eed7a6993dce28fe9aa2ef56834307860839677f96685f2b44d0911f\n", + "a01f2c8bee81769609462c69c96aa923fd863e209d3ce26dd889b55e2e3873db\n", + "38bffe40a22d529a0c66124b2c308dac9229912656f62b4facfced408e02380f\n", + "28b3404a61908f5d6198815c99af1990c8af38655930058c28c21bb539ce0000\n", + "4e378fb5561cd0668f906b731ac58fee25738edf09cadc7a29c0abc0177aea6d\n"; + + + sm9_pairing(r, SM9_Ppubs, SM9_P1); + console.log("test pairing: ", fp12_equ(r, fp12_from_hex(g))); +} + +#endif diff --git a/src/sm9_sign.c b/src/sm9_sign.c new file mode 100644 index 00000000..fd74f766 --- /dev/null +++ b/src/sm9_sign.c @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2014 - 2020 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + +int sm9_sign_setup(SM9_SIGN_MASTER_KEY *msk) +{ + + // rand ks in [1, N-1] + fn_rand(ks); + + // Ppubs = ks * P2 + twist_point_mul_generator(Ppubs, ks); +} + + + +int sm9_sign_keygen(SM9_SIGN_MASTER_KEY *msk, const char *id, size_t idlen, SM9_POINT *ds) +{ + +} + + +int sm9_sign_init(SM3_CTX *ctx) +{ + uint8_t prefix[1] = {0x02}; + if (!ctx) { + return -1; + } + + sm3_init(ctx); + sm3_update(ctx, prefix, sizeof(prefix)); + return 0; +} + +int sm9_sign_update(SM3_CTX *ctx, const uint8_t *data, size_t datalen) +{ + sm3_update(ctx, data, datalen); + return 1; +} + +int sm9_sign_finish(SM3_CTX *ctx, SM9_SIGNATURE *sig) +{ + + fp12_t g; + + sm9_pairing(g, SM9_P1, Ppubs); + + fn_rand(r); + + fp12_pow(w, g, r); + + + fn_sub(l, r, h); + if (fn_is_zero(l)) { + } + + + point_mul(S, l, ds); + +} + +int sm9_verify_init(SM9_SIGN_CTX *ctx) +{ + sm3_init(&ctx->sm3_ctx); + sm3_update(&ctx->sm3_ctx, SM9_HASH1_PREFIX, sizeof(SM9_HASH1_PREFIX)); + return 0; +} + +int sm9_verify_update(SM9_SIGN_CTX *ctx, const uint8_t *data, size_t datalen) +{ + sm3_update(&ctx->sm3_ctx, data, datalen); +} + +int sm9_verify_finish(SM9_SIGN_CTX *ctx, const char *id, size_t idlen, const SM9_SIGNATURE *sig) +{ + + if (bn_is_zero(h) || bn_cmp(h, SM9_N) >= 0) { + } + + if (!point_is_on_curve(S)) { + } + + sm9_pairing(g, SM9_P1, Ppubs); + + fp12_pow(t, g, h); + + + sm9_hash1(h1, id, idlen); + + twist_point_mul_generator(P, h1); + twist_point_add(P, P, Ppubs); + pairing(u, S, P); +} + + diff --git a/src/tlcp.c b/src/tlcp.c new file mode 100644 index 00000000..3d995b23 --- /dev/null +++ b/src/tlcp.c @@ -0,0 +1,936 @@ +/* + * Copyright (c) 2021 - 2021 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +static const int tlcp_ciphers[] = { TLCP_cipher_ecc_sm4_cbc_sm3 }; +static const size_t tlcp_ciphers_count = sizeof(tlcp_ciphers)/sizeof(tlcp_ciphers[0]); + + +int tlcp_record_set_handshake_server_key_exchange_pke(uint8_t *record, size_t *recordlen, + const uint8_t *sig, size_t siglen) +{ + int type = TLS_handshake_server_key_exchange; + uint8_t *p = record + 5 + 4; + size_t hslen = 0; + + if (!record || !recordlen + || !sig || !siglen || siglen > 2048) { + error_print(); + return -1; + } + if (record[1] != TLCP_VERSION_MAJOR || record[2] != TLCP_VERSION_MINOR) { + error_print(); + return -1; + } + tls_array_to_bytes(sig, siglen, &p, &hslen); + tls_record_set_handshake(record, recordlen, type, NULL, hslen); + return 1; +} + +int tlcp_record_get_handshake_server_key_exchange_pke(const uint8_t *record, + uint8_t *sig, size_t *siglen) +{ + int type; + const uint8_t *p; + size_t len; + + if (!record || !sig || !siglen) { + error_print(); + return -1; + } + + if (tls_record_get_handshake(record, &type, &p, &len) != 1) { + error_print(); + return -1; + } + if (type != TLS_handshake_server_key_exchange) { + error_print(); + return -1; + } + if (record[1] != TLCP_VERSION_MAJOR || record[2] != TLCP_VERSION_MINOR) { + error_print(); + return -1; + } + /* + if (tls_uint16array_copy_from_bytes(sig, siglen, *siglen, &p, &len) != 1 + || len > 0) { + error_print(); + return -1; + } + */ + // FIXME: check *siglen >= len + memcpy(sig, p, len); + *siglen = len; + return 1; +} + +int tlcp_certificate_chain_verify(const uint8_t *data, size_t datalen, FILE *ca_certs_fp, int depth) +{ + const uint8_t *certs; + size_t certslen; + const uint8_t *der; + size_t derlen; + X509_CERTIFICATE sign_cert; + X509_CERTIFICATE enc_cert; + X509_CERTIFICATE ca_cert; + + if (tls_uint24array_from_bytes(&certs, &certslen, &data, &datalen) != 1 + || datalen > 0) { + error_print(); + return -1; + } + if (tls_uint24array_from_bytes(&der, &derlen, &certs, &certslen) != 1 + || x509_certificate_from_der(&sign_cert, &der, &derlen) != 1 + || derlen > 0) { + error_print(); + return -1; + } + if (tls_uint24array_from_bytes(&der, &derlen, &certs, &certslen) != 1 + || x509_certificate_from_der(&enc_cert, &der, &derlen) != 1 + || derlen > 0) { + error_print(); + return -1; + } + if (x509_name_equ(&sign_cert.tbs_certificate.issuer, + &enc_cert.tbs_certificate.issuer) != 1) { + error_print(); + return -1; + } + + if (certslen) { + const uint8_t *chain = certs; + size_t chainlen = certslen; + if (tls_uint24array_from_bytes(&der, &derlen, &certs, &certslen) != 1 + || x509_certificate_from_der(&ca_cert, &der, &derlen) != 1 + || derlen > 0) { + error_print(); + return -1; + } + if (x509_certificate_verify_by_certificate(&sign_cert, &ca_cert) != 1 + || x509_certificate_verify_by_certificate(&enc_cert, &ca_cert) != 1) { + error_print(); + return -1; + } + if (tls_certificate_chain_verify(chain, chainlen, ca_certs_fp, depth - 1) != 1) { + error_print(); + return -1; + } + } else { + if (x509_certificate_from_pem_by_name(&ca_cert, ca_certs_fp, &sign_cert.tbs_certificate.issuer) != 1 + || x509_certificate_verify_by_certificate(&sign_cert, &ca_cert) != 1) { + error_print(); + return -1; + } + if (x509_certificate_from_pem_by_name(&ca_cert, ca_certs_fp, &enc_cert.tbs_certificate.issuer) != 1 + || x509_certificate_verify_by_certificate(&enc_cert, &ca_cert) != 1) { + error_print(); + return -1; + } + } + return 1; +} + +int tlcp_connect(TLS_CONNECT *conn, const char *hostname, int port, + FILE *ca_certs_fp, FILE *client_certs_fp, const SM2_KEY *client_sign_key) +{ + uint8_t record[1600]; + size_t recordlen; + uint8_t finished[256]; + size_t finishedlen; + int type; + const uint8_t *data; + size_t datalen; + + uint8_t client_random[32]; + uint8_t server_random[32]; + const uint8_t *server_enc_cert; + size_t server_enc_cert_len; + SM2_KEY server_enc_key; + SM2_KEY server_sign_key; + SM2_SIGN_CTX verify_ctx; // for server_key_exchange signature verification + SM2_SIGN_CTX sign_ctx; // for certificate_verify signature generation + uint8_t sig[TLS_MAX_SIGNATURE_SIZE]; + size_t siglen = sizeof(sig); + uint8_t pre_master_secret[48]; + uint8_t enced_pre_master_secret[256]; + size_t enced_pre_master_secret_len; + SM3_CTX sm3_ctx; + SM3_CTX tmp_sm3_ctx; + uint8_t sm3_hash[32]; + uint8_t verify_data[12]; + uint8_t local_verify_data[12]; + + struct sockaddr_in server; + server.sin_addr.s_addr = inet_addr(hostname); + server.sin_family = AF_INET; + server.sin_port = htons(port); + if ((conn->sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + error_print(); + return -1; + } + if (connect(conn->sock, (struct sockaddr *)&server , sizeof(server)) < 0) { + error_print(); + return -1; + } + + conn->is_client = 1; + + sm3_init(&sm3_ctx); + if (client_sign_key) + sm2_sign_init(&sign_ctx, client_sign_key, SM2_DEFAULT_ID); + tls_record_set_version(record, TLS_version_tlcp); + tls_record_set_version(finished, TLS_version_tlcp); + + tls_trace(">>>> ClientHello\n"); + tls_random_generate(client_random); + if (tls_record_set_handshake_client_hello(record, &recordlen, + TLS_version_tlcp, client_random, NULL, 0, + tlcp_ciphers, tlcp_ciphers_count, NULL, 0) != 1) { + error_print(); + return -1; + } + tls_record_print(stderr, record, recordlen, 0, 0); + if (tls_record_send(record, recordlen, conn->sock) != 1) { + error_print(); + return -1; + } + sm3_update(&sm3_ctx, record + 5, recordlen - 5); + if (client_sign_key) + sm2_sign_update(&sign_ctx, record + 5, recordlen - 5); + + tls_trace("<<<< ServerHello\n"); + if (tls_record_recv(record, &recordlen, conn->sock) != 1 + || tls_record_version(record) != TLS_version_tlcp) { + error_print(); + return -1; + } + tls_record_print(stderr, record, recordlen, 0, 0); + if (tls_record_get_handshake_server_hello(record, + &conn->version, server_random, conn->session_id, &conn->session_id_len, + &conn->cipher_suite, NULL, 0) != 1) { + error_print(); + return -1; + } + if (conn->version != TLS_version_tlcp) { + error_print(); + return -1; + } + if (tls_cipher_suite_in_list(conn->cipher_suite, tlcp_ciphers, tlcp_ciphers_count) != 1) { + error_print(); + return -1; + } + sm3_update(&sm3_ctx, record + 5, recordlen - 5); + if (client_sign_key) + sm2_sign_update(&sign_ctx, record + 5, recordlen - 5); + + tls_trace("<<<< ServerCertificate\n"); + if (tls_record_recv(record, &recordlen, conn->sock) != 1 + || tls_record_version(record) != TLS_version_tlcp) { + error_print(); + return -1; + } + tls_record_print(stderr, record, recordlen, 0, 0); + if (tls_record_get_handshake_certificate(record, + conn->server_certs, &conn->server_certs_len) != 1) { + error_print(); + return -1; + } + if (tlcp_certificate_chain_verify(conn->server_certs, conn->server_certs_len, ca_certs_fp, 5) != 1) { + error_print(); + return -1; + } + if (tls_certificate_get_public_keys(conn->server_certs, conn->server_certs_len, + &server_sign_key, &server_enc_key) != 1) { + error_print(); + return -1; + } + sm3_update(&sm3_ctx, record + 5, recordlen - 5); + if (client_sign_key) + sm2_sign_update(&sign_ctx, record + 5, recordlen - 5); + + tls_trace("<<<< ServerKeyExchange\n"); + if (tls_record_recv(record, &recordlen, conn->sock) != 1 + || tls_record_version(record) != TLS_version_tlcp) { + error_print(); + return -1; + } + tls_record_print(stderr, record, recordlen, conn->cipher_suite << 8, 0); + if (tlcp_record_get_handshake_server_key_exchange_pke(record, sig, &siglen) != 1) { + error_print(); + return -1; + } + sm3_update(&sm3_ctx, record + 5, recordlen - 5); + if (client_sign_key) + sm2_sign_update(&sign_ctx, record + 5, recordlen - 5); + + tls_trace("++++ process ServerKeyExchange\n"); + if (tls_certificate_get_second(conn->server_certs, conn->server_certs_len, + &server_enc_cert, &server_enc_cert_len) != 1) { + error_print(); + return -1; + } + if (sm2_verify_init(&verify_ctx, &server_sign_key, SM2_DEFAULT_ID) != 1 + || sm2_verify_update(&verify_ctx, client_random, 32) != 1 + || sm2_verify_update(&verify_ctx, server_random, 32) != 1 + || sm2_verify_update(&verify_ctx, server_enc_cert, server_enc_cert_len) != 1) { + error_print(); + return -1; + } + if ( sm2_verify_finish(&verify_ctx, sig, siglen) != 1) { + error_print("ServerKeyExchange signature verification failure"); + return -1; + } + + if (tls_record_recv(record, &recordlen, conn->sock) != 1 + || tls_record_version(record) != TLS_version_tlcp + || tls_record_get_handshake(record, &type, &data, &datalen) != 1) { + error_print(); + return -1; + } + if (type == TLS_handshake_certificate_request) { + tls_trace("<<<< CertificateRequest\n"); + int cert_types[TLS_MAX_CERTIFICATE_TYPES]; + size_t cert_types_count;; + uint8_t ca_names[TLS_MAX_CA_NAMES_SIZE]; + size_t ca_names_len; + if (tls_record_get_handshake_certificate_request(record, + cert_types, &cert_types_count, + ca_names, &ca_names_len) != 1) { + error_print(); + return -1; + } + tls_record_print(stderr, record, recordlen, 0, 0); + sm3_update(&sm3_ctx, record + 5, recordlen - 5); + if (client_sign_key) + sm2_sign_update(&sign_ctx, record + 5, recordlen - 5); + + if (tls_record_recv(record, &recordlen, conn->sock) != 1 + || tls_record_version(record) != TLS_version_tlcp) { + error_print(); + return -1; + } + } else { + memset(&sign_ctx, 0, sizeof(SM2_SIGN_CTX)); + client_sign_key = NULL; + } + tls_trace("<<<< ServerHelloDone\n"); + tls_record_print(stderr, record, recordlen, 0, 0); + if (tls_record_get_handshake_server_hello_done(record) != 1) { + error_print(); + return -1; + } + sm3_update(&sm3_ctx, record + 5, recordlen - 5); + if (client_sign_key) { + sm2_sign_update(&sign_ctx, record + 5, recordlen - 5); + + tls_trace(">>>> ClientCertificate\n"); + if (tls_record_set_handshake_certificate_from_pem(record, &recordlen, client_certs_fp) != 1) { + error_print(); + return -1; + } + tls_record_print(stderr, record, recordlen, 0, 0); + if (tls_record_send(record, recordlen, conn->sock) != 1) { + error_print(); + return -1; + } + sm3_update(&sm3_ctx, record + 5, recordlen - 5); + sm2_sign_update(&sign_ctx, record + 5, recordlen - 5); + } + + tls_trace("++++ generate secrets\n"); + if (tls_pre_master_secret_generate(pre_master_secret, TLS_version_tlcp) != 1 + || tls_prf(pre_master_secret, 48, "master secret", + client_random, 32, server_random, 32, + 48, conn->master_secret) != 1 + || tls_prf(conn->master_secret, 48, "key expansion", + server_random, 32, client_random, 32, + 96, conn->key_block) != 1) { + error_print(); + return -1; + } + sm3_hmac_init(&conn->client_write_mac_ctx, conn->key_block, 32); + sm3_hmac_init(&conn->server_write_mac_ctx, conn->key_block + 32, 32); + sm4_set_encrypt_key(&conn->client_write_enc_key, conn->key_block + 64); + sm4_set_decrypt_key(&conn->server_write_enc_key, conn->key_block + 80); + format_bytes(stderr, 0, 0, "pre_master_secret : ", pre_master_secret, 48); + format_bytes(stderr, 0, 0, "master_secret : ", conn->master_secret, 48); + format_bytes(stderr, 0, 0, "client_write_mac_key : ", conn->key_block, 32); + format_bytes(stderr, 0, 0, "server_write_mac_key : ", conn->key_block + 32, 32); + format_bytes(stderr, 0, 0, "client_write_enc_key : ", conn->key_block + 64, 16); + format_bytes(stderr, 0, 0, "server_write_enc_key : ", conn->key_block + 80, 16); + format_print(stderr, 0, 0, "\n"); + + tls_trace(">>>> ClientKeyExchange\n"); + if (sm2_encrypt(&server_enc_key, pre_master_secret, 48, + enced_pre_master_secret, &enced_pre_master_secret_len) != 1) { + error_print(); + return -1; + } + if (tls_record_set_handshake_client_key_exchange_pke(record, &recordlen, + enced_pre_master_secret, enced_pre_master_secret_len) != 1) { + error_print(); + return -1; + } + tls_record_print(stderr, record, recordlen, conn->cipher_suite << 8, 0); + if (tls_record_send(record, recordlen, conn->sock) != 1) { + error_print(); + return -1; + } + sm3_update(&sm3_ctx, record + 5, recordlen - 5); + if (client_sign_key) + sm2_sign_update(&sign_ctx, record + 5, recordlen - 5); + + if (client_sign_key) { + tls_trace(">>>> CertificateVerify\n"); + sm2_sign_finish(&sign_ctx, sig, &siglen); + if (tls_record_set_handshake_certificate_verify(record, &recordlen, sig, siglen) != 1) { + error_print(); + return -1; + } + tls_record_print(stderr, record, recordlen, 0, 0); + if (tls_record_send(record, recordlen, conn->sock) != 1) { + error_print(); + return -1; + } + sm3_update(&sm3_ctx, record + 5, recordlen - 5); + } + + tls_trace(">>>> [ChangeCipherSpec]\n"); + if (tls_record_set_change_cipher_spec(record, &recordlen) !=1) { + error_print(); + return -1; + } + if (tls_record_send(record, recordlen, conn->sock) != 1) { + error_print(); + return -1; + } + tls_record_print(stderr, record, recordlen, 0, 0); + + tls_trace(">>>> Finished\n"); + memcpy(&tmp_sm3_ctx, &sm3_ctx, sizeof(sm3_ctx)); + sm3_finish(&tmp_sm3_ctx, sm3_hash); + + if (tls_prf(conn->master_secret, 48, "client finished", + sm3_hash, 32, NULL, 0, + sizeof(verify_data), verify_data) != 1) { + error_print(); + return -1; + } + if (tls_record_set_handshake_finished(finished, &finishedlen, verify_data) != 1) { + error_print(); + return -1; + } + tls_record_print(stderr, finished, finishedlen, 0, 0); + sm3_update(&sm3_ctx, finished + 5, finishedlen - 5); + + if (tls_record_encrypt(&conn->client_write_mac_ctx, &conn->client_write_enc_key, + conn->client_seq_num, finished, finishedlen, record, &recordlen) != 1) { + error_print(); + return -1; + } + tls_seq_num_incr(conn->client_seq_num); + if (tls_record_send(record, recordlen, conn->sock) != 1) { + error_print(); + return -1; + } + + tls_trace("<<<< [ChangeCipherSpec]\n"); + if (tls_record_recv(record, &recordlen, conn->sock) != 1 + || tls_record_version(record) != TLS_version_tlcp) { + error_print(); + return -1; + } + if (tls_record_get_change_cipher_spec(record) != 1) { + error_print(); + return -1; + } + tls_record_print(stderr, record, recordlen, 0, 0); + + tls_trace("<<<< Finished\n"); + if (tls_record_recv(record, &recordlen, conn->sock) != 1 + || tls_record_version(record) != TLS_version_tlcp) { + error_print(); + return -1; + } + if (tls_record_decrypt(&conn->server_write_mac_ctx, &conn->server_write_enc_key, + conn->server_seq_num, record, recordlen, finished, &finishedlen) != 1) { + error_print(); + return -1; + } + tls_record_print(stderr, finished, finishedlen, 0, 0); + tls_seq_num_incr(conn->server_seq_num); + if (tls_record_get_handshake_finished(finished, verify_data) != 1) { + error_print(); + return -1; + } + sm3_finish(&sm3_ctx, sm3_hash); + if (tls_prf(conn->master_secret, 48, "server finished", + sm3_hash, 32, NULL, 0, + sizeof(local_verify_data), local_verify_data) != 1) { + error_print(); + return -1; + } + if (memcmp(local_verify_data, verify_data, 12) != 0) { + error_print("server_finished.verify_data verification failure"); + return -1; + } + + tls_trace("++++ Connection established\n"); + return 1; +} + +int tlcp_accept(TLS_CONNECT *conn, int port, + FILE *certs_fp, const SM2_KEY *server_sign_key, const SM2_KEY *server_enc_key, + FILE *client_cacerts_fp, uint8_t *handshakes_buf, size_t handshakes_buflen) +{ + uint8_t *handshakes = handshakes_buf; + size_t handshakeslen = 0; + uint8_t record[TLS_MAX_RECORD_SIZE]; + size_t recordlen; + uint8_t finished[256]; + size_t finishedlen = sizeof(finished); + + uint8_t client_random[32]; + uint8_t server_random[32]; + uint8_t session_id[32]; + size_t session_id_len; + int client_ciphers[12] = {0}; + size_t client_ciphers_count = sizeof(client_ciphers)/sizeof(client_ciphers[0]); + const uint8_t *server_enc_cert; + size_t server_enc_certlen; + SM2_KEY client_sign_key; + SM2_SIGN_CTX sign_ctx; + uint8_t sig[TLS_MAX_SIGNATURE_SIZE]; + size_t siglen = sizeof(sig); + uint8_t enced_pms[256]; + size_t enced_pms_len = sizeof(enced_pms); + uint8_t pre_master_secret[48]; + size_t pre_master_secret_len = 48; + SM3_CTX sm3_ctx; + SM3_CTX tmp_sm3_ctx; + uint8_t sm3_hash[32]; + uint8_t verify_data[12]; + uint8_t local_verify_data[12]; + size_t i; + + int sock; + struct sockaddr_in server_addr; + struct sockaddr_in client_addr; + socklen_t client_addrlen; + + if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + error_print(); + return -1; + } + server_addr.sin_family = AF_INET; + server_addr.sin_addr.s_addr = INADDR_ANY; + server_addr.sin_port = htons(port); + + if (bind(sock, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) { + error_print(); + return -1; + } + + error_print("start listen ..."); + listen(sock, 5); + + memset(conn, 0, sizeof(*conn)); + + + + client_addrlen = sizeof(client_addr); + if ((conn->sock = accept(sock, (struct sockaddr *)&client_addr, &client_addrlen)) < 0) { + error_print(); + return -1; + } + + error_print("connected\n"); + + + + sm3_init(&sm3_ctx); + + tls_trace("<<<< ClientHello\n"); + if (tls_record_recv(record, &recordlen, conn->sock) != 1 + || tls_record_version(record) != TLS_version_tlcp) { + error_print(); + return -1; + } + tls_record_print(stderr, record, recordlen, 0, 0); + if (tls_record_get_handshake_client_hello(record, + &conn->version, client_random, session_id, &session_id_len, + client_ciphers, &client_ciphers_count, NULL, 0) != 1) { + error_print(); + return -1; + } + if (conn->version != TLS_version_tlcp) { + error_print(); + return -1; + } + for (i = 0; i < tlcp_ciphers_count; i++) { + if (tls_cipher_suite_in_list(tlcp_ciphers[i], client_ciphers, client_ciphers_count) == 1) { + conn->cipher_suite = tlcp_ciphers[i]; + break; + } + } + if (conn->cipher_suite == 0) { + error_print("no common cipher_suite"); + return -1; + } + sm3_update(&sm3_ctx, record + 5, recordlen - 5); + if (handshakes) { + memcpy(handshakes, record + 5, recordlen - 5); + handshakes += recordlen - 5; + handshakeslen += recordlen - 5; + } + + tls_trace(">>>> ServerHello\n"); + tls_random_generate(server_random); + if (tls_record_set_handshake_server_hello(record, &recordlen, + TLS_version_tlcp, server_random, NULL, 0, + conn->cipher_suite, NULL, 0) != 1) { + error_print(); + return -1; + } + tls_record_print(stderr, record, recordlen, 0, 0); + if (tls_record_send(record, recordlen, conn->sock) != 1) { + error_print(); + return -1; + } + sm3_update(&sm3_ctx, record + 5, recordlen - 5); + if (handshakes) { + memcpy(handshakes, record + 5, recordlen - 5); + handshakes += recordlen - 5; + handshakeslen += recordlen - 5; + } + + tls_trace(">>>> ServerCertificate\n"); + if (tls_record_set_handshake_certificate_from_pem(record, &recordlen, certs_fp) != 1) { + error_print(); + return -1; + } + tls_record_print(stderr, record, recordlen, 0, 0); + if (tls_record_send(record, recordlen, conn->sock) != 1) { + error_print(); + return -1; + } + if (tls_record_get_handshake_certificate(record, conn->server_certs, &conn->server_certs_len) != 1 + || tls_certificate_get_second(conn->server_certs, conn->server_certs_len, + &server_enc_cert, &server_enc_certlen) != 1) { + error_print(); + return -1; + } + sm3_update(&sm3_ctx, record + 5, recordlen - 5); + if (handshakes) { + memcpy(handshakes, record + 5, recordlen - 5); + handshakes += recordlen - 5; + handshakeslen += recordlen - 5; + } + + tls_trace(">>>> ServerKeyExchange\n"); + if (sm2_sign_init(&sign_ctx, server_sign_key, SM2_DEFAULT_ID) != 1 + || sm2_sign_update(&sign_ctx, client_random, 32) != 1 + || sm2_sign_update(&sign_ctx, server_random, 32) != 1 + || sm2_sign_update(&sign_ctx, server_enc_cert, server_enc_certlen) != 1 + || sm2_sign_finish(&sign_ctx, sig, &siglen) != 1) { + error_print(); + return -1; + } + if (tlcp_record_set_handshake_server_key_exchange_pke(record, &recordlen, sig, siglen) != 1) { + error_print(); + return -1; + } + tls_record_print(stderr, record, recordlen, conn->cipher_suite << 8, 0); + if (tls_record_send(record, recordlen, conn->sock) != 1) { + error_print(); + return -1; + } + sm3_update(&sm3_ctx, record + 5, recordlen - 5); + if (handshakes) { + memcpy(handshakes, record + 5, recordlen - 5); + handshakes += recordlen - 5; + handshakeslen += recordlen - 5; + } + + if (client_cacerts_fp) { + tls_trace(">>>> CertificateRequest\n"); + const int cert_types[] = { TLS_cert_type_ecdsa_sign, }; + uint8_t ca_names[TLS_MAX_CA_NAMES_SIZE] = {0}; + size_t cert_types_count = sizeof(cert_types)/sizeof(cert_types[0]); + size_t ca_names_len = 0; + if (tls_record_set_handshake_certificate_request(record, &recordlen, + cert_types, cert_types_count, + ca_names, ca_names_len) != 1) { + error_print(); + return -1; + } + tls_record_print(stderr, record, recordlen, 0, 0); + + if (tls_record_send(record, recordlen, conn->sock) != 1) { + error_print(); + return -1; + } + sm3_update(&sm3_ctx, record + 5, recordlen - 5); + if (handshakes) { + memcpy(handshakes, record + 5, recordlen - 5); + handshakes += recordlen - 5; + handshakeslen += recordlen - 5; + } + } + + tls_trace(">>>> ServerHelloDone\n"); + if (tls_record_set_handshake_server_hello_done(record, &recordlen) != 1) { + error_print(); + return -1; + } + tls_record_print(stderr, record, recordlen, 0, 0); + if (tls_record_send(record, recordlen, conn->sock) != 1) { + error_print(); + return -1; + } + sm3_update(&sm3_ctx, record + 5, recordlen - 5); + if (handshakes) { + memcpy(handshakes, record + 5, recordlen - 5); + handshakes += recordlen - 5; + handshakeslen += recordlen - 5; + } + + if (handshakes) { + tls_trace("<<<< ClientCertificate\n"); + if (tls_record_recv(record, &recordlen, conn->sock) != 1 + || tls_record_version(record) != TLS_version_tlcp) { + error_print(); + return -1; + } + tls_record_print(stderr, record, recordlen, 0, 0); + if (tls_record_get_handshake_certificate(record, + conn->client_certs, &conn->client_certs_len) != 1) { + error_print(); + return -1; + } + // FIXME: verify client's certificate with ca certs + if (tls_certificate_get_public_keys(conn->client_certs, conn->client_certs_len, + &client_sign_key, NULL) != 1) { + error_print(); + return -1; + } + sm3_update(&sm3_ctx, record + 5, recordlen - 5); + memcpy(handshakes, record + 5, recordlen - 5); + handshakes += recordlen - 5; + handshakeslen += recordlen - 5; + } + + tls_trace("<<<< ClientKeyExchange\n"); + if (tls_record_recv(record, &recordlen, conn->sock) != 1 + || tls_record_version(record) != TLS_version_tlcp) { + error_print(); + return -1; + } + tls_record_print(stderr, record, recordlen, conn->cipher_suite << 8, 0); + if (tls_record_get_handshake_client_key_exchange_pke(record, enced_pms, &enced_pms_len) != 1) { + error_print(); + return -1; + } + sm3_update(&sm3_ctx, record + 5, recordlen - 5); + if (handshakes) { + memcpy(handshakes, record + 5, recordlen - 5); + handshakes += recordlen - 5; + handshakeslen += recordlen - 5; + } + if (sm2_decrypt(server_enc_key, enced_pms, enced_pms_len, + pre_master_secret, &pre_master_secret_len) != 1) { + error_print(); + return -1; + } + + if (handshakes) { + tls_trace("<<<< CertificateVerify\n"); + if (tls_record_recv(record, &recordlen, conn->sock) != 1 + || tls_record_version(record) != TLS_version_tlcp) { + error_print(); + return -1; + } + tls_record_print(stderr, record, recordlen, 0, 0); + if (tls_record_get_handshake_certificate_verify(record, sig, &siglen) != 1) { + error_print(); + return -1; + } + sm3_update(&sm3_ctx, record + 5, recordlen - 5); + sm2_verify_init(&sign_ctx, &client_sign_key, SM2_DEFAULT_ID); + sm2_verify_update(&sign_ctx, handshakes_buf, handshakeslen); + if (sm2_verify_finish(&sign_ctx, sig, siglen) != 1) { + error_print(); + return -1; + } + } + + tls_trace("++++ generate secrets\n"); + if (tls_prf(pre_master_secret, 48, "master secret", + client_random, 32, server_random, 32, + 48, conn->master_secret) != 1) { + error_print(); + return -1; + } + if (tls_prf(conn->master_secret, 48, "key expansion", + server_random, 32, client_random, 32, + 96, conn->key_block) != 1) { + error_print(); + return -1; + } + sm3_hmac_init(&conn->client_write_mac_ctx, conn->key_block, 32); + sm3_hmac_init(&conn->server_write_mac_ctx, conn->key_block + 32, 32); + sm4_set_decrypt_key(&conn->client_write_enc_key, conn->key_block + 64); + sm4_set_encrypt_key(&conn->server_write_enc_key, conn->key_block + 80); + format_bytes(stderr, 0, 0, "pre_master_secret : ", pre_master_secret, 48); + format_bytes(stderr, 0, 0, "master_secret : ", conn->master_secret, 48); + format_bytes(stderr, 0, 0, "client_write_mac_key : ", conn->key_block, 32); + format_bytes(stderr, 0, 0, "server_write_mac_key : ", conn->key_block + 32, 32); + format_bytes(stderr, 0, 0, "client_write_enc_key : ", conn->key_block + 64, 16); + format_bytes(stderr, 0, 0, "server_write_enc_key : ", conn->key_block + 80, 16); + format_print(stderr, 0, 0, "\n"); + + + tls_trace("<<<< [ChangeCipherSpec]\n"); + if (tls_record_recv(record, &recordlen, conn->sock) != 1 + || tls_record_version(record) != TLS_version_tlcp) { + error_print(); + return -1; + } + tls_record_print(stderr, record, recordlen, 0, 0); + if (tls_record_get_change_cipher_spec(record) != 1) { + error_print(); + return -1; + } + + tls_trace("<<<< ClientFinished\n"); + if (tls_record_recv(record, &recordlen, conn->sock) != 1 + || tls_record_version(record) != TLS_version_tlcp) { + error_print(); + return -1; + } + if (tls_record_decrypt(&conn->client_write_mac_ctx, &conn->client_write_enc_key, + conn->client_seq_num, record, recordlen, finished, &finishedlen) != 1) { + error_print(); + return -1; + } + tls_seq_num_incr(conn->client_seq_num); + if (tls_record_get_handshake_finished(finished, verify_data) != 1) { + error_print(); + return -1; + } + tls_record_print(stderr, finished, finishedlen, 0, 0); + memcpy(&tmp_sm3_ctx, &sm3_ctx, sizeof(SM3_CTX)); + sm3_update(&sm3_ctx, finished + 5, finishedlen - 5); + + sm3_finish(&tmp_sm3_ctx, sm3_hash); + if (tls_prf(conn->master_secret, 48, "client finished", sm3_hash, 32, NULL, 0, + 12, local_verify_data) != 1) { + error_print(); + return -1; + } + if (memcmp(local_verify_data, verify_data, 12) != 0) { + error_print("client_finished.verify_data verification failure"); + return -1; + } + + tls_trace(">>>> [ChangeCipherSpec]\n"); + if (tls_record_set_change_cipher_spec(record, &recordlen) != 1) { + error_print(); + return -1; + } + tls_record_print(stderr, record, recordlen, 0, 0); + if (tls_record_send(record, recordlen, conn->sock) != 1) { + error_print(); + return -1; + } + + tls_trace(">>>> ServerFinished\n"); + sm3_finish(&sm3_ctx, sm3_hash); + if (tls_prf(conn->master_secret, 48, "server finished", sm3_hash, 32, NULL, 0, + 12, verify_data) != 1) { + error_print(); + return -1; + } + if (tls_record_set_handshake_finished(finished, &finishedlen, verify_data) != 1) { + error_print(); + return -1; + } + tls_record_print(stderr, finished, finishedlen, 0, 0); + if (tls_record_encrypt(&conn->server_write_mac_ctx, &conn->server_write_enc_key, + conn->server_seq_num, finished, finishedlen, record, &recordlen) != 1) { + error_print(); + return -1; + } + tls_seq_num_incr(conn->server_seq_num); + if (tls_record_send(record, recordlen, conn->sock) != 1) { + error_print(); + return -1; + } + + tls_trace("Connection Established!\n\n"); + return 1; +} diff --git a/src/tls.c b/src/tls.c new file mode 100644 index 00000000..4c266691 --- /dev/null +++ b/src/tls.c @@ -0,0 +1,1361 @@ +/* + * Copyright (c) 2021 - 2021 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +void tls_uint8_to_bytes(uint8_t a, uint8_t **out, size_t *outlen) +{ + if (out) { + *(*out)++ = a; + } + (*outlen)++; +} + +void tls_uint16_to_bytes(uint16_t a, uint8_t **out, size_t *outlen) +{ + if (out) { + *(*out)++ = (uint8_t)(a >> 8); + *(*out)++ = (uint8_t)a; + } + *outlen += 2; +} + +void tls_uint24_to_bytes(uint24_t a, uint8_t **out, size_t *outlen) +{ + if (out) { + *(*out)++ = (uint8_t)(a >> 16); + *(*out)++ = (uint8_t)(a >> 8); + *(*out)++ = (uint8_t)(a); + } + (*outlen) += 3; +} + +void tls_uint32_to_bytes(uint32_t a, uint8_t **out, size_t *outlen) +{ + if (out) { + *(*out)++ = (uint8_t)(a >> 24); + *(*out)++ = (uint8_t)(a >> 16); + *(*out)++ = (uint8_t)(a >> 8); + *(*out)++ = (uint8_t)(a ); + } + (*outlen) += 4; +} + +void tls_array_to_bytes(const uint8_t *data, size_t datalen, uint8_t **out, size_t *outlen) +{ + if (out) { + memcpy(*out, data, datalen); + *out += datalen; + } + *outlen += datalen; +} + +void tls_uint8array_to_bytes(const uint8_t *data, size_t datalen, uint8_t **out, size_t *outlen) +{ + tls_uint8_to_bytes((uint8_t)datalen, out, outlen); + tls_array_to_bytes(data, datalen, out, outlen); +} + +void tls_uint16array_to_bytes(const uint8_t *data, size_t datalen, uint8_t **out, size_t *outlen) +{ + tls_uint16_to_bytes((uint16_t)datalen, out, outlen); + tls_array_to_bytes(data, datalen, out, outlen); +} + +void tls_uint24array_to_bytes(const uint8_t *data, size_t datalen, uint8_t **out, size_t *outlen) +{ + tls_uint24_to_bytes((uint24_t)datalen, out, outlen); + tls_array_to_bytes(data, datalen, out, outlen); +} + +int tls_uint8_from_bytes(uint8_t *a, const uint8_t **in, size_t *inlen) +{ + if (*inlen < 1) { + error_print(); + return -1; + } + *a = *(*in)++; + (*inlen)--; + return 1; +} + +int tls_uint16_from_bytes(uint16_t *a, const uint8_t **in, size_t *inlen) +{ + if (*inlen < 2) { + error_print(); + return -1; + } + *a = *(*in)++; + *a <<= 8; + *a |= *(*in)++; + *inlen -= 2; + return 1; +} + +int tls_uint24_from_bytes(uint24_t *a, const uint8_t **in, size_t *inlen) +{ + if (*inlen < 3) { + error_print(); + return -1; + } + *a = *(*in)++; + *a <<= 8; + *a |= *(*in)++; + *a <<= 8; + *a |= *(*in)++; + *inlen -= 3; + return 1; +} + +int tls_uint32_from_bytes(uint32_t *a, const uint8_t **in, size_t *inlen) +{ + if (*inlen < 4) { + error_print(); + return -1; + } + *a = *(*in)++; + *a <<= 8; + *a |= *(*in)++; + *a <<= 8; + *a |= *(*in)++; + *a <<= 8; + *a |= *(*in)++; + *inlen -= 4; + return 1; +} + +int tls_array_from_bytes(const uint8_t **data, size_t datalen, const uint8_t **in, size_t *inlen) +{ + if (*inlen < datalen) { + error_print(); + return -1; + } + *data = *in; + *in += datalen; + *inlen -= datalen; + return 1; +} + +int tls_array_copy_from_bytes(uint8_t *data, size_t datalen, const uint8_t **in, size_t *inlen) +{ + int ret; + const uint8_t *p; + if (tls_array_from_bytes(&p, datalen, in, inlen) != 1) { + error_print(); + return -1; + } + memcpy(data, p, datalen); + return 1; +} + +int tls_uint8array_from_bytes(const uint8_t **data, size_t *datalen, const uint8_t **in, size_t *inlen) +{ + uint8_t len; + if (tls_uint8_from_bytes(&len, in, inlen) != 1 + || tls_array_from_bytes(data, len, in, inlen) != 1) { + error_print(); + return -1; + } + *datalen = len; + return 1; +} + +int tls_uint8array_copy_from_bytes(uint8_t *data, size_t *datalen, size_t maxlen, const uint8_t **in, size_t *inlen) +{ + const uint8_t *p; + if (tls_uint8array_from_bytes(&p, datalen, in, inlen) != 1) { + error_print(); + return -1; + } + if (*datalen > maxlen) { + error_print(); + return -1; + } + memcpy(data, p, *datalen); + return 1; +} + +int tls_uint16array_from_bytes(const uint8_t **data, size_t *datalen, const uint8_t **in, size_t *inlen) +{ + uint16_t len; + if (tls_uint16_from_bytes(&len, in, inlen) != 1 + || tls_array_from_bytes(data, len, in, inlen) != 1) { + error_print(); + return -1; + } + *datalen = len; + return 1; +} + +int tls_uint16array_copy_from_bytes(uint8_t *data, size_t *datalen, size_t maxlen, const uint8_t **in, size_t *inlen) +{ + const uint8_t *p; + if (tls_uint16array_from_bytes(&p, datalen, in, inlen) != 1) { + error_print(); + return -1; + } + if (*datalen > maxlen) { + error_print(); + return -1; + } + memcpy(data, p, *datalen); + return 1; +} + +int tls_uint24array_from_bytes(const uint8_t **data, size_t *datalen, const uint8_t **in, size_t *inlen) +{ + uint24_t len; + if (tls_uint24_from_bytes(&len, in, inlen) != 1 + || tls_array_from_bytes(data, len, in, inlen) != 1) { + error_print(); + return -1; + } + *datalen = len; + return 1; +} + +int tls_uint24array_copy_from_bytes(uint8_t *data, size_t *datalen, size_t maxlen, const uint8_t **in, size_t *inlen) +{ + const uint8_t *p; + if (tls_uint24array_from_bytes(&p, datalen, in, inlen) != 1) { + error_print(); + return -1; + } + if (*datalen > maxlen) { + error_print(); + return -1; + } + memcpy(data, p, *datalen); + return 1; +} + + + + + +int tls_record_set_version(uint8_t *record, int version) +{ + if (!tls_version_text(version)) { + error_print(); + return -1; + } + record[1] = version >> 8; + record[2] = version; + return 1; +} + +int tls_record_version(const uint8_t *record) +{ + int version = ((int)record[1] << 8) | record[2]; + return version; +} + +// +int tls_record_length(const uint8_t *record) +{ + int ret; + ret = ((uint16_t)record[3] << 8) | record[4]; + return ret; +} + + +// 这个函数应该是处理的,这个函数是不应该用的,通常我们在加密的时候,header ,明文数据是分离的,但是输出的record是一个 +int tls_record_encrypt(const SM3_HMAC_CTX *hmac_ctx, const SM4_KEY *cbc_key, + const uint8_t seq_num[8], const uint8_t *in, size_t inlen, + uint8_t *out, size_t *outlen) +{ + if (tls_cbc_encrypt(hmac_ctx, cbc_key, seq_num, in, + in + 5, inlen - 5, + out + 5, outlen) != 1) { + error_print(); + return -1; + } + + out[0] = in[0]; + out[1] = in[1]; + out[2] = in[2]; + out[3] = (*outlen) >> 8; + out[4] = (*outlen); + (*outlen) += 5; + return 1; +} + +int tls_record_decrypt(const SM3_HMAC_CTX *hmac_ctx, const SM4_KEY *cbc_key, + const uint8_t seq_num[8], const uint8_t *in, size_t inlen, + uint8_t *out, size_t *outlen) +{ + if (tls_cbc_decrypt(hmac_ctx, cbc_key, seq_num, in, + in + 5, inlen - 5, + out + 5, outlen) != 1) { + error_print(); + return -1; + } + + out[0] = in[0]; + out[1] = in[1]; + out[2] = in[2]; + out[3] = (*outlen) >> 8; + out[4] = (*outlen); + (*outlen) += 5; + + return 1; +} + +// handshake types + +int tls_random_generate(uint8_t random[32]) +{ + uint32_t gmt_unix_time = (uint32_t)time(NULL); + uint8_t *p = random; + size_t len = 0; + tls_uint32_to_bytes(gmt_unix_time, &p, &len); + rand_bytes(random + 4, 28); + return 1; +} + + +int tls_pre_master_secret_generate(uint8_t pre_master_secret[48], int version) +{ + if (!tls_version_text(version)) { + error_print(); + return -1; + } + pre_master_secret[0] = version >> 8; + pre_master_secret[1] = version; + if (rand_bytes(pre_master_secret + 2, 46) != 1) { + error_print(); + return -1; + } + return 1; +} + + + + + +// handshakes + +int tls_record_set_handshake(uint8_t *record, size_t *recordlen, + int type, const uint8_t *data, size_t datalen) +{ + size_t handshakelen; + + if (!record || !recordlen) { + error_print(); + return -1; + } + if (datalen > (1 << 14) - 4) { + error_print("gmssl does not support handshake longer than record"); + return -1; + } + handshakelen = 4 + datalen; + record[0] = TLS_record_handshake; + record[3] = handshakelen >> 8; + record[4] = handshakelen; + record[5] = type; + record[6] = datalen >> 16; + record[7] = datalen >> 8; + record[8] = datalen; + if (data) { + memcpy(record + 5 + 4, data, datalen); + } + *recordlen = 5 + handshakelen; + return 1; +} + +int tls_record_get_handshake(const uint8_t *record, + int *type, const uint8_t **data, size_t *datalen) +{ + size_t record_datalen; + + + if (!record || !type || !data || !datalen) { + error_print(); + return -1; + } + if (record[0] != TLS_record_handshake) { + error_print(); + return -1; + } + // 我们应该假定这个record是正确的,不再检查长度之类 + record_datalen = (size_t)record[3] << 8 | record[4]; + if (record_datalen > TLS_RECORD_MAX_PLAINDATA_SIZE + || record_datalen < 4) { + error_print(); + return -1; + } + if (!tls_handshake_type_name(record[5])) { + error_print(); + return -1; + } + + *type = record[5]; + *datalen = ((size_t)record[6] << 16) | ((size_t)record[7] << 8) | record[8]; // FIXME:检查长度 + *data = record + 5 + 4; + return 1; +} + +// handshake messages + +int tls_record_set_handshake_client_hello(uint8_t *record, size_t *recordlen, + int version, const uint8_t random[32], + const uint8_t *session_id, size_t session_id_len, + const int *cipher_suites, size_t cipher_suites_count, + const uint8_t *exts, size_t exts_len) +{ + uint8_t type = TLS_handshake_client_hello; + uint8_t *p = record + 5 + 4; + size_t len = 0; + + if (!record || !recordlen || !random + || (!session_id && session_id_len) || session_id_len > 32 + || !cipher_suites || !cipher_suites_count || cipher_suites_count > 64 + || (!exts && exts_len) || exts_len > 512) { + error_print(); + return -1; + } + if (!tls_version_text(version)) { + error_print(); + return -1; + } + + tls_uint16_to_bytes((uint16_t)version, &p, &len); + tls_array_to_bytes(random, 32, &p, &len); + tls_uint8array_to_bytes(session_id, session_id_len, &p, &len); + tls_uint16_to_bytes(cipher_suites_count * 2, &p, &len); + while (cipher_suites_count--) { + tls_uint16_to_bytes((uint16_t)*cipher_suites, &p, &len); + cipher_suites++; + } + tls_uint8_to_bytes(1, &p, &len); + tls_uint8_to_bytes((uint8_t)TLS_compression_null, &p, &len); + if (exts) { + if (version < TLS_version_tls12) { + error_print(); + return -1; + } + tls_uint16array_to_bytes(exts, exts_len, &p, &len); + } + if (tls_record_set_handshake(record, recordlen, type, NULL, len) != 1) { + error_print(); + return -1; + } + return 1; +} + +int tls_record_get_handshake_client_hello(const uint8_t *record, + int *version, uint8_t random[32], uint8_t *session_id, size_t *session_id_len, + int *cipher_suites, size_t *cipher_suites_count, + uint8_t *exts, size_t *exts_len) +{ + int type; + const uint8_t *p; + size_t len; + const uint8_t *ciphers; + size_t ciphers_len; + const uint8_t *comp_meths; + size_t comp_meths_len; + + if (!record || !random || !session_id || !session_id_len + || !cipher_suites || !cipher_suites_count || (exts && !exts_len) + || record[0] != TLS_record_handshake) { + error_print(); + return -1; + } + if (tls_record_get_handshake(record, &type, &p, &len) != 1 + || type != TLS_handshake_client_hello) { + error_print(); + return -1; + } + *version = 0; + if (tls_uint16_from_bytes((uint16_t *)version, &p, &len) != 1 + || tls_array_copy_from_bytes(random, 32, &p, &len) != 1 + || tls_uint8array_copy_from_bytes(session_id, session_id_len, 32, &p, &len) != 1 + || tls_uint16array_from_bytes(&ciphers, &ciphers_len, &p, &len) != 1 + || tls_uint8array_from_bytes(&comp_meths, &comp_meths_len, &p, &len) != 1) { + error_print(); + return -1; + } + if (ciphers_len % 2) { + error_print(); + return -1; + } + *cipher_suites_count = 0; + while (ciphers_len) { + uint16_t cipher_suite; + tls_uint16_from_bytes(&cipher_suite, &ciphers, &ciphers_len); + if (!tls_cipher_suite_name(cipher_suite)) { + error_print(); + return -1; + } + *cipher_suites++ = cipher_suite; + (*cipher_suites_count)++; + } + if (len > 0) { + if (*version < TLS_version_tls12) { + error_print(); + return -1; + } + if (!exts) { + error_print(); + return -1; + } + if (tls_uint16array_copy_from_bytes(exts, exts_len, TLS_MAX_EXTENSIONS_SIZE, &p, &len) != 1 + || len > 0) { + error_print(); + return -1; + } + } + return 1; +} + + +int tls_record_set_handshake_server_hello(uint8_t *record, size_t *recordlen, + int version, const uint8_t random[32], + const uint8_t *session_id, size_t session_id_len, int cipher_suite, + const uint8_t *exts, size_t exts_len) +{ + uint8_t type = TLS_handshake_server_hello; + uint8_t *p = record + 5 + 4; + size_t len = 0; + + if (!record || !recordlen || !tls_version_text(version) || !random + || (!session_id && session_id_len) || session_id_len > 32 + || (!exts && exts_len) || exts_len > 512) { + error_print(); + return -1; + } + if (record[0] != TLS_record_handshake + || !tls_version_text(version) + || !tls_cipher_suite_name(cipher_suite) + || version < tls_record_version(record)) { + error_print(); + return -1; + } + tls_uint16_to_bytes((uint16_t)version, &p, &len); + tls_array_to_bytes(random, 32, &p, &len); + tls_uint8array_to_bytes(session_id, session_id_len, &p, &len); + tls_uint16_to_bytes((uint16_t)cipher_suite, &p, &len); + tls_uint8_to_bytes((uint8_t)TLS_compression_null, &p, &len); + if (exts) { + if (version < TLS_version_tls12) { + error_print(); + return -1; + } + tls_uint16array_to_bytes(exts, exts_len, &p, &len); + } + if (tls_record_set_handshake(record, recordlen, type, NULL, len) != 1) { + error_print(); + return -1; + } + return 1; +} + +int tls_record_get_handshake_server_hello(const uint8_t *record, + int *version, uint8_t random[32], uint8_t *session_id, size_t *session_id_len, + int *cipher_suite, uint8_t *exts, size_t *exts_len) +{ + int type; + const uint8_t *p; + size_t len; + uint8_t comp_meth; + + if (!record || !version || !random || !session_id || !session_id_len + || !cipher_suite || (exts && !exts_len)) { + error_print(); + return -1; + } + if (record[0] != TLS_record_handshake) { + error_print(); + return -1; + } + if (tls_record_get_handshake(record, &type, &p, &len) != 1) { + error_print(); + return -1; + } + if (type != TLS_handshake_server_hello) { + error_print(); + return -1; + } + *version = 0; + *cipher_suite = 0; + if (tls_uint16_from_bytes((uint16_t *)version, &p, &len) != 1 + || tls_array_copy_from_bytes(random, 32, &p, &len) != 1 + || tls_uint8array_copy_from_bytes(session_id, session_id_len, 32, &p, &len) != 1 + || tls_uint16_from_bytes((uint16_t *)cipher_suite, &p, &len) != 1 + || tls_uint8_from_bytes(&comp_meth, &p, &len) != 1) { + error_print(); + return -1; + } + if (!tls_version_text(*version)) { + error_print(); + return -1; + } + if (*version < tls_record_version(record)) { + error_print(); + return -1; + } + if (!tls_cipher_suite_name(*cipher_suite)) { + error_print("unknown server cipher_suite 0x%04x", *cipher_suite); + return -1; + } + if (comp_meth != TLS_compression_null) { + error_print(); + return -1; + } + if (len > 0) { + if (tls_record_version(record) < TLS_version_tls12) { + error_print("warning: should not have extentions"); + return -1; + } + // FIXME: 用 tls_extensions_from_bytes() 解析 + if (tls_uint16array_copy_from_bytes(exts, exts_len, TLS_MAX_EXTENSIONS_SIZE, &p, &len) != 1 + || len > 0) { + error_print(); + return -1; + } + } + return 1; +} + + + +int tls_record_set_handshake_certificate(uint8_t *record, size_t *recordlen, + const uint8_t *data, size_t datalen) +{ + int type = TLS_handshake_certificate; + const uint8_t *cp = data; + size_t len = datalen; + const uint8_t *certs; + size_t certslen; + + if (!record || !recordlen + || !data || datalen <= 3 || datalen > 65535) { + error_print(); + return -1; + } + if (tls_uint24array_from_bytes(&certs, &certslen, &cp, &len) != 1 + || len > 0) { + error_print(); + return -1; + } + // FIXME: check certificate + if (!certslen) { + error_print(); + return -1; + } + tls_record_set_handshake(record, recordlen, type, data, datalen); + return 1; +} + +int tls_record_set_handshake_certificate_from_pem(uint8_t *record, size_t *recordlen, FILE *fp) +{ + int type = TLS_handshake_certificate; + uint8_t *data = record + 5 + 4; + uint8_t *certs = data + 3; + size_t datalen, certslen = 0; + + for (;;) { + int ret; + X509_CERTIFICATE cert; + uint8_t der[1024]; + const uint8_t *cp = der; + size_t derlen; + + if ((ret = pem_read(fp, "CERTIFICATE", der, &derlen)) < 0) { + error_print(); + return -1; + } else if (ret == 0) { + break; + } + tls_uint24array_to_bytes(der, derlen, &certs, &certslen); + if (x509_certificate_from_der(&cert, &cp, &derlen) != 1 + || derlen > 0) { + error_print(); + return -1; + } + //x509_certificate_print(stderr, &cert, 0, 0); + } + datalen = certslen; + tls_uint24_to_bytes((uint24_t)certslen, &data, &datalen); + tls_record_set_handshake(record, recordlen, type, NULL, datalen); + return 1; +} + +int tls_record_get_handshake_certificate(const uint8_t *record, uint8_t *data, size_t *datalen) +{ + int type; + const uint8_t *cp; + + if (tls_record_get_handshake(record, &type, &cp, datalen) != 1) { + error_print(); + return -1; + } + if (type != TLS_handshake_certificate) { + error_print(); + return -1; + } + memcpy(data, cp, *datalen); + return 1; +} + +int tls_certificate_get_subject_names(const uint8_t *certs, size_t certslen, uint8_t *names, size_t *nameslen) +{ + *nameslen = 0; + const uint8_t *der; + size_t derlen; + + while (certslen > 0) { + X509_CERTIFICATE cert; + + if (tls_uint24array_from_bytes(&der, &derlen, &certs, &certslen) != 1) { + error_print(); + return -1; + } + if (x509_certificate_from_der(&cert, &der, &derlen) != 1) { + error_print(); + return -1; + } + if (derlen > 0) { + error_print(); + return -1; + } + if (x509_name_to_der(&cert.tbs_certificate.subject, &names, nameslen) != 1) { + error_print(); + return -1; + } + } + return 1; +} + +int tls_certificate_get_first(const uint8_t *data, size_t datalen, const uint8_t **cert, size_t *certlen) +{ + const uint8_t *certs; + size_t certslen; + if (tls_uint24array_from_bytes(&certs, &certslen, &data, &datalen) != 1 + || datalen > 0 + || tls_uint24array_from_bytes(cert, certlen, &certs, &certslen) != 1) { + error_print(); + return -1; + } + *cert -= 3; + *certlen += 3; + return 1; +} + +int tls_certificate_get_second(const uint8_t *data, size_t datalen, const uint8_t **cert, size_t *certlen) +{ + const uint8_t *certs; + size_t certslen; + if (tls_uint24array_from_bytes(&certs, &certslen, &data, &datalen) != 1 + || datalen > 0 + || tls_uint24array_from_bytes(cert, certlen, &certs, &certslen) != 1 + || tls_uint24array_from_bytes(cert, certlen, &certs, &certslen) != 1) { + error_print(); + return -1; + } + *cert -= 3; + *certlen += 3; + return 1; +} + +int tls_certificate_get_public_keys(const uint8_t *data, size_t datalen, + SM2_KEY *sign_key, SM2_KEY *enc_key) +{ + X509_CERTIFICATE x509; + const uint8_t *cert; + const uint8_t *der; + size_t certlen, derlen; + + if (!data || !datalen || !sign_key) { + error_print(); + return -1; + } + if (tls_certificate_get_first(data, datalen, &cert, &certlen) != 1 + || tls_uint24array_from_bytes(&der, &derlen, &cert, &certlen) != 1 + || certlen > 0 + || x509_certificate_from_der(&x509, &der, &derlen) != 1 + || derlen > 0) { + error_print(); + return -1; + } + memcpy(sign_key, &x509.tbs_certificate.subject_public_key_info.sm2_key, sizeof(SM2_KEY)); + if (enc_key) { + if (tls_certificate_get_second(data, datalen, &cert, &certlen) != 1 + || tls_uint24array_from_bytes(&der, &derlen, &cert, &certlen) != 1 + || certlen > 0 + || x509_certificate_from_der(&x509, &der, &derlen) != 1 + || derlen > 0) { + error_print(); + return -1; + } + memcpy(enc_key, &x509.tbs_certificate.subject_public_key_info.sm2_key, sizeof(SM2_KEY)); + } + return 1; +} + + + +int tls_certificate_chain_verify(const uint8_t *certs, size_t certslen, FILE *ca_certs_fp, int depth) +{ + X509_CERTIFICATE cert; + X509_CERTIFICATE cacert; + const uint8_t *der; + size_t derlen; + if (tls_uint24array_from_bytes(&der, &derlen, &certs, &certslen) != 1) { + error_print(); + return -1; + } + if (x509_certificate_from_der(&cert, &der, &derlen) != 1 + || derlen > 0) { + error_print(); + return -1; + } + while (certslen > 0) { + if (tls_uint24array_from_bytes(&der, &derlen, &certs, &certslen) != 1 + || x509_certificate_from_der(&cacert, &der, &derlen) != 1 + || derlen > 0) { + error_print(); + return -1; + } + if (x509_certificate_verify_by_certificate(&cert, &cacert) != 1) { + error_print(); + return -1; + } + memcpy(&cert, &cacert, sizeof(X509_CERTIFICATE)); + } + if (x509_certificate_from_pem_by_name(&cacert, ca_certs_fp, &cert.tbs_certificate.issuer) != 1 + || x509_certificate_verify_by_certificate(&cert, &cacert) != 1) { + error_print(); + return -1; + } + return 1; +} + + +int tls_record_set_handshake_certificate_request(uint8_t *record, size_t *recordlen, + const int *cert_types, size_t cert_types_count, + const uint8_t *ca_names, size_t ca_names_len) +{ + int type = TLS_handshake_certificate_request; + uint8_t *p = record + 5 + 4; + size_t len = 0; + + if (!record || !recordlen + || !cert_types || !cert_types_count || cert_types_count > TLS_MAX_CERTIFICATE_TYPES + || (!ca_names && ca_names_len) || ca_names_len > TLS_MAX_CA_NAMES_SIZE) { + error_print(); + return -1; + } + tls_uint8_to_bytes((uint8_t)cert_types_count, &p, &len); + while (cert_types_count--) { + tls_uint8_to_bytes((uint8_t)(*cert_types), &p, &len); + cert_types++; + } + tls_uint16array_to_bytes(ca_names, ca_names_len, &p, &len); + tls_record_set_handshake(record, recordlen, type, NULL, len); + return 1; +} + +int tls_record_get_handshake_certificate_request(const uint8_t *record, + int *cert_types, size_t *cert_types_count, + uint8_t *ca_names, size_t *ca_names_len) +{ + int type; + const uint8_t *cp; + size_t len; + const uint8_t *types; + size_t count; + + if (!record + || !cert_types || !cert_types_count || !ca_names || !ca_names_len + || record[0] != TLS_record_handshake) { + error_print(); + return -1; + } + if (tls_record_get_handshake(record, &type, &cp, &len) != 1 + || tls_uint8array_from_bytes(&types, &count, &cp, &len) != 1 + || tls_uint16array_copy_from_bytes(ca_names, ca_names_len, TLS_MAX_CA_NAMES_SIZE, &cp, &len) != 1 + || len > 0) { + error_print(); + return -1; + } + if (count > TLS_MAX_CERTIFICATE_TYPES) { + error_print(); + return -1; + } + while (count--) { + *cert_types++ = *types++; + } + return 1; +} + +int tls_record_set_handshake_server_hello_done(uint8_t *record, size_t *recordlen) +{ + int type = TLS_handshake_server_hello_done; + if (!record || !recordlen) { + error_print(); + return -1; + } + tls_record_set_handshake(record, recordlen, type, NULL, 0); + return 1; +} + +int tls_record_get_handshake_server_hello_done(const uint8_t *record) +{ + int type; + const uint8_t *p; + size_t len; + + if (!record) { + error_print(); + return -1; + } + if (tls_record_get_handshake(record, &type, &p, &len) != 1 + || type != TLS_handshake_server_hello_done + || len != 0) { + error_print(); + return -1; + } + return 1; +} + +int tls_record_set_handshake_client_key_exchange_pke(uint8_t *record, size_t *recordlen, + const uint8_t *enced_pms, size_t enced_pms_len) +{ + int type = TLS_handshake_client_key_exchange; + uint8_t *p = record + 5 + 4; + size_t len = 0; + if (!record || !recordlen + || !enced_pms || !enced_pms_len || enced_pms_len > 65535) { + error_print(); + return -1; + } + tls_uint16array_to_bytes(enced_pms, enced_pms_len, &p, &len); + tls_record_set_handshake(record, recordlen, type, NULL, len); + return 1; +} + +int tls_record_get_handshake_client_key_exchange_pke(const uint8_t *record, + uint8_t *enced_pms, size_t *enced_pms_len) +{ + int type; + const uint8_t *p; + size_t len; + + if (!record || !enced_pms || !enced_pms_len + || record[0] != TLS_record_handshake) { + error_print(); + return -1; + } + if (tls_record_get_handshake(record, &type, &p, &len) != 1 + || type != TLS_handshake_client_key_exchange) { + error_print(); + return -1; + } + if (tls_uint16array_copy_from_bytes(enced_pms, enced_pms_len, *enced_pms_len, &p, &len) != 1 + || len > 0) { + error_print(); + return -1; + } + return 1; +} + + +int tls_record_set_handshake_certificate_verify(uint8_t *record, size_t *recordlen, + const uint8_t *sig, size_t siglen) +{ + int type = TLS_handshake_certificate_verify; + tls_record_set_handshake(record, recordlen, type, sig, siglen); + return 1; +} + +int tls_record_get_handshake_certificate_verify(const uint8_t *record, + uint8_t *sig, size_t *siglen) +{ + int type; + const uint8_t *p; + size_t len ; + + if (tls_record_get_handshake(record, &type, &p, &len) != 1 + || type != TLS_handshake_certificate_verify) { + error_print(); + return -1; + } + memcpy(sig, p, len); + *siglen = len; + return 1; +} + +int tls_record_set_handshake_finished(uint8_t *record, size_t *recordlen, + const uint8_t verify_data[12]) +{ + int type = TLS_handshake_finished; + if (!record || !recordlen || !verify_data) { + error_print(); + return -1; + } + tls_record_set_handshake(record, recordlen, type, verify_data, 12); + return 1; +} + +int tls_record_get_handshake_finished(const uint8_t *record, uint8_t verify_data[12]) +{ + int type; + const uint8_t *p; + size_t len; + + if (tls_record_get_handshake(record, &type, &p, &len) != 1) { + error_print(); + return -1; + } + if (len != 12) { + error_print(); + return -1; + } + memcpy(verify_data, p, 12); + return 1; +} + +// alert protocol + + +int tls_record_set_alert(uint8_t *record, size_t *recordlen, + int alert_level, + int alert_description) +{ + if (!record || !recordlen + || !tls_alert_level_name(alert_level) + || !tls_alert_description_text(alert_description)) { + error_print(); + return -1; + } + record[0] = TLS_record_alert; + record[3] = 0; // length + record[4] = 2; // length + record[5] = (uint8_t)alert_level; + record[6] = (uint8_t)alert_description; + *recordlen = 7; + return 1; +} + +int tls_record_get_alert(const uint8_t *record, + int *alert_level, + int *alert_description) +{ + if (!record || !alert_level || !alert_description) { + error_print(); + return -1; + } + if (record[0] != TLS_record_alert) { + error_print(); + return -1; + } + if (record[3] != 0 || record[4] != 2) { + error_print(); + return -1; + } + *alert_level = record[5]; + *alert_description = record[6]; + if (!tls_alert_level_name(*alert_level)) { + error_print(); + return -1; + } + if (!tls_alert_description_text(*alert_description)) { + error_print("warning"); + return -1; + } + return 1; +} + + +// change_cipher_spec protocol + + +int tls_record_set_change_cipher_spec(uint8_t *record, size_t *recordlen) +{ + if (!record || !recordlen) { + error_print(); + return -1; + } + record[0] = TLS_record_change_cipher_spec; + record[3] = 0; + record[4] = 1; + record[5] = TLS_change_cipher_spec; + *recordlen = 6; + return 1; +} + +int tls_record_get_change_cipher_spec(const uint8_t *record) +{ + if (!record) { + error_print(); + return -1; + } + if (record[0] != TLS_record_change_cipher_spec) { + error_print(); + return -1; + } + if (record[3] != 0 || record[4] != 1) { + error_print(); + return -1; + } + if (record[5] != TLS_change_cipher_spec) { + error_print("unknown ChangeCipherSpec value %d", record[5]); + return -1; + } + return 1; +} + +int tls_record_set_application_data(uint8_t *record, size_t *recordlen, + const uint8_t *data, size_t datalen) +{ + record[0] = TLS_record_application_data; + record[3] = (datalen >> 8) & 0xff; + record[4] = datalen & 0xff; + memcpy(record + 5, data, datalen); + *recordlen = 5 + datalen; + return 1; +} + +int tls_record_get_application_data(uint8_t *record, + const uint8_t **data, size_t *datalen) +{ + if (record[0] != TLS_record_application_data) { + error_print(); + return -1; + } + *datalen = ((size_t)record[3] << 8) | record[4]; + *data = record + 5; + return 1; +} + + +int tls_cipher_suite_in_list(int cipher, const int *list, size_t list_count) +{ + size_t i; + for (i = 0; i < list_count; i++) { + if (cipher == list[i]) { + return 1; + } + } + return 0; +} + +int tls_record_send(const uint8_t *record, size_t recordlen, int sock) +{ + ssize_t r; + if (recordlen < 5 + || recordlen - 5 != (((size_t)record[3] << 8) | record[4])) { + error_print(); + return -1; + } + if ((r = send(sock, record, recordlen, 0)) < 0) { + error_print(); + return -1; + } else if (r != recordlen) { + error_print(); + return -1; + } + return 1; +} + +int tls_record_recv(uint8_t *record, size_t *recordlen, int sock) +{ + ssize_t r; + int type; + size_t len; + + if ((r = recv(sock, record, 5, 0)) < 0) { + error_print(); + return -1; + } else if (r != 5) { + // FIXME: 如果对方已经中断连接,那么我们要判断这个错误吗? + error_print(); + perror(""); // 否则打印ioctl错误 + return -1; + } + + if (!tls_record_type_name(record[0])) { + error_print("invalid record type: %d\n", record[0]); + return -1; + } + if (!tls_version_text(tls_record_version(record))) { + error_print("invalid record version: %d.%d\n", record[1], record[2]); + return -1; + } + len = (size_t)record[3] << 8 | record[4]; + *recordlen = 5 + len; + if (len) { + if ((r = recv(sock, record + 5, len, 0)) < 0) { + error_print(); + return -1; + } else if (r != len) { + error_print(); + return -1; + } + } + + if (record[0] == TLS_record_alert) { + tls_record_print(stderr, record, *recordlen, 0, 0); + } + return 1; +} + +int tls_seq_num_incr(uint8_t seq_num[8]) +{ + int i; + for (i = 7; i > 0; i--) { + seq_num[i]++; + if (seq_num[i]) break; + } + // FIXME: 检查溢出 + return 1; +} + +int tls_compression_methods_has_null_compression(const uint8_t *meths, size_t methslen) +{ + if (!meths || !methslen) { + error_print(); + return -1; + } + while (methslen--) { + if (*meths++ == TLS_compression_null) { + return 1; + } + } + return -1; +} + +// FIXME: 设定支持的最大输入长度 +int tls_send(TLS_CONNECT *conn, const uint8_t *data, size_t datalen) +{ + const SM3_HMAC_CTX *hmac_ctx; + const SM4_KEY *enc_key; + uint8_t *seq_num; + uint8_t mrec[1600]; + uint8_t crec[1600]; + size_t mlen = sizeof(mrec); + size_t clen = sizeof(crec); + + // FIXME: 检查datalen的长度 + + if (conn->is_client) { + hmac_ctx = &conn->client_write_mac_ctx; + enc_key = &conn->client_write_enc_key; + seq_num = conn->client_seq_num; + } else { + hmac_ctx = &conn->server_write_mac_ctx; + enc_key = &conn->server_write_enc_key; + seq_num = conn->server_seq_num; + } + + tls_trace(">>>> ApplicationData\n"); + if (tls_record_set_version(mrec, conn->version) != 1 + || tls_record_set_application_data(mrec, &mlen, data, datalen) != 1 + || tls_record_encrypt(hmac_ctx, enc_key, seq_num, mrec, mlen, crec, &clen) != 1 + || tls_seq_num_incr(seq_num) != 1 + || tls_record_send(crec, clen, conn->sock) != 1) { + error_print(); + return -1; + } + (void)tls_record_print(stderr, crec, clen, 0, 0); + return 1; +} + +int tls_recv(TLS_CONNECT *conn, uint8_t *data, size_t *datalen) +{ + const SM3_HMAC_CTX *hmac_ctx; + const SM4_KEY *dec_key; + uint8_t *seq_num; + uint8_t mrec[1600]; + uint8_t crec[1600]; + size_t mlen = sizeof(mrec); + size_t clen = sizeof(crec); + + if (conn->is_client) { + hmac_ctx = &conn->server_write_mac_ctx; + dec_key = &conn->server_write_enc_key; + seq_num = conn->server_seq_num; + } else { + hmac_ctx = &conn->client_write_mac_ctx; + dec_key = &conn->client_write_enc_key; + seq_num = conn->client_seq_num; + } + + tls_trace("<<<< ApplicationData\n"); + if (tls_record_recv(crec, &clen, conn->sock) != 1 + // FIXME: 检查版本号 + || tls_record_decrypt(hmac_ctx, dec_key, seq_num, crec, clen, mrec, &mlen) != 1 + || tls_seq_num_incr(seq_num) != 1) { + error_print(); + return -1; + } + (void)tls_record_print(stderr, mrec, mlen, 0, 0); + memcpy(data, mrec + 5, mlen - 5); + *datalen = mlen - 5; + return 1; +} diff --git a/src/tls12.c b/src/tls12.c new file mode 100644 index 00000000..6cda97ce --- /dev/null +++ b/src/tls12.c @@ -0,0 +1,971 @@ +/* + * Copyright (c) 2021 - 2021 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + + + +static const int tls12_ciphers[] = { + GMSSL_cipher_ecdhe_sm2_with_sm4_sm3, +}; + +static const size_t tls12_ciphers_count = sizeof(tls12_ciphers)/sizeof(tls12_ciphers[0]); + +static const uint8_t tls12_exts[] = { + /* supported_groups */ 0x00,0x0A, 0x00,0x04, 0x00,0x02, 0x00,30,//0x29, // curveSM2 + /* ec_point_formats */ 0x00,0x0B, 0x00,0x02, 0x01, 0x00, // uncompressed + /* signature_algors */ 0x00,0x0D, 0x00,0x04, 0x00,0x02, 0x07,0x07,//0x08, // sm2sig_sm3 +}; + +/* +int tls_server_extensions_check(const uint8_t *exts, size_t extslen) +{ + return -1; +} + +int tls_construct_server_extensions(const uint8_t *client_exts, size_t client_exts_len, + uint8_t *server_exts, size_t *server_exts_len) +{ + uint16_t type; + const uint8_t *p; + size_t len; + + while (client_exts_len) { + if (tls_uint16_from_bytes(&ext_type, &client_exts, &client_exts_len) != 1 + || tls_uint16array_from_bytes(&ext_data, &ext_datalen, &client_exts, &client_exts_len) != 1) { + error_print(); + return -1; + } + } +} +*/ + +int tls_record_set_handshake_server_key_exchange_ecdhe(uint8_t *record, size_t *recordlen, + int curve, const SM2_POINT *point, const uint8_t *sig, size_t siglen) +{ + int type = TLS_handshake_server_key_exchange; + uint8_t *server_ecdh_params = record + 9; + uint8_t *p = server_ecdh_params + 69; + size_t len = 69; + + if (!record || !recordlen || !tls_named_curve_name(curve) || !point + || !sig || !siglen || siglen > TLS_MAX_SIGNATURE_SIZE) { + error_print(); + return -1; + } + server_ecdh_params[0] = TLS_curve_type_named_curve; + server_ecdh_params[1] = curve >> 8; + server_ecdh_params[2] = curve; + server_ecdh_params[3] = 65; + sm2_point_to_uncompressed_octets(point, server_ecdh_params + 4); + tls_uint16_to_bytes(TLS_sig_sm2sig_sm3, &p, &len); + tls_uint16array_to_bytes(sig, siglen, &p, &len); + tls_record_set_handshake(record, recordlen, type, NULL, len); + return 1; +} + +int tls_record_get_handshake_server_key_exchange_ecdhe(const uint8_t *record, + int *curve, SM2_POINT *point, uint8_t *sig, size_t *siglen) +{ + int type; + const uint8_t *p; + size_t len; + uint8_t curve_type; + const uint8_t *octets; + size_t octetslen; + uint16_t sig_alg; + + if (!record || !curve || !point || !sig || !siglen) { + error_print(); + return -1; + } + if (tls_record_get_handshake(record, &type, &p, &len) != 1 + || type != TLS_handshake_server_key_exchange) { + error_print(); + return -1; + } + *curve = 0; + if (tls_uint8_from_bytes(&curve_type, &p, &len) != 1 + || tls_uint16_from_bytes((uint16_t *)curve, &p, &len) != 1 + || tls_uint8array_from_bytes(&octets, &octetslen, &p, &len) != 1 + || tls_uint16_from_bytes(&sig_alg, &p, &len) != 1 + || tls_uint16array_copy_from_bytes(sig, siglen, TLS_MAX_SIGNATURE_SIZE, &p, &len) != 1 + || len > 0) { + error_print(); + return -1; + } + if (curve_type != TLS_curve_type_named_curve + || *curve != TLS_curve_sm2p256v1 + || octetslen != 65 + || sm2_point_from_octets(point, octets, octetslen) != 1) { + error_print(); + return -1; + } + if (sig_alg != TLS_sig_sm2sig_sm3) { + error_print(); + return -1; + } + return 1; +} + +int tls_record_set_handshake_client_key_exchange_ecdhe(uint8_t *record, size_t *recordlen, + const SM2_POINT *point) +{ + int type = TLS_handshake_client_key_exchange; + record[9] = 65; + sm2_point_to_uncompressed_octets(point, record + 9 + 1); + tls_record_set_handshake(record, recordlen, type, NULL, 1 + 65); + return 1; +} + +int tls_record_get_handshake_client_key_exchange_ecdhe(const uint8_t *record, SM2_POINT *point) +{ + int type; + const uint8_t *p; + size_t len; + const uint8_t *octets; + size_t octetslen; + + if (tls_record_get_handshake(record, &type, &p, &len) != 1 + || type != TLS_handshake_client_key_exchange) { + error_print(); + return -1; + } + if (tls_uint8array_from_bytes(&octets, &octetslen, &p, &len) != 1 + || len > 0) { + error_print(); + return -1; + } + if (octetslen != 65 + || sm2_point_from_octets(point, octets, octetslen) != 1) { + error_print(); + return -1; + } + return 1; +} + +int tls12_record_recv(uint8_t *record, size_t *recordlen, int sock) +{ + if (tls_record_recv(record, recordlen, sock) != 1) { + error_print(); + return -1; + } + if (tls_record_version(record) != TLS_version_tls12) { + error_print(); + return -1; + } + return 1; +} + +int tls12_connect(TLS_CONNECT *conn, const char *hostname, int port, + FILE *ca_certs_fp, FILE *client_certs_fp, const SM2_KEY *client_sign_key) +{ + uint8_t *record = conn->record; + size_t recordlen; + uint8_t finished[256]; + size_t finishedlen; + + int type; + const uint8_t *data; + size_t datalen; + + uint8_t client_random[32]; + uint8_t server_random[32]; + uint8_t exts[TLS_MAX_EXTENSIONS_SIZE]; + size_t exts_len; + + SM2_KEY server_sign_key; + SM2_SIGN_CTX verify_ctx; + SM2_SIGN_CTX sign_ctx; // for certificate_verify signature generation + uint8_t sig[TLS_MAX_SIGNATURE_SIZE]; + size_t siglen = sizeof(sig); + + + int curve; + SM2_KEY client_ecdh; + SM2_POINT server_ecdh_public; + + uint8_t pre_master_secret[64]; + + SM3_CTX sm3_ctx; + SM3_CTX tmp_sm3_ctx; + uint8_t sm3_hash[32]; + uint8_t verify_data[12]; + uint8_t local_verify_data[12]; + + struct sockaddr_in server; + server.sin_addr.s_addr = inet_addr(hostname); + server.sin_family = AF_INET; + server.sin_port = htons(port); + + + sm3_init(&sm3_ctx); + if (client_sign_key) + sm2_sign_init(&sign_ctx, client_sign_key, SM2_DEFAULT_ID); + tls_record_set_version(record, TLS_version_tls1); + tls_record_set_version(finished, TLS_version_tls12); + + + + if ((conn->sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + error_print(); + return -1; + } + + + if (connect(conn->sock, (struct sockaddr *)&server , sizeof(server)) < 0) { + error_print(); + return -1; + } + + conn->is_client = 1; + + + tls_trace(">>>> ClientHello\n"); + tls_random_generate(client_random); + if (tls_record_set_handshake_client_hello(record, &recordlen, + TLS_version_tls12, client_random, NULL, 0, + tls12_ciphers, tls12_ciphers_count, tls12_exts, sizeof(tls12_exts)) != 1) { + error_print(); + return -1; + } + tls_record_print(stderr, record, recordlen, 0, 0); + if (tls_record_send(record, recordlen, conn->sock) != 1) { + error_print(); + return -1; + } + sm3_update(&sm3_ctx, record + 5, recordlen - 5); + if (client_sign_key) + sm2_sign_update(&sign_ctx, record + 5, recordlen - 5); + + tls_trace("<<<< ServerHello\n"); + if (tls12_record_recv(record, &recordlen, conn->sock) != 1) { + error_print(); + return -1; + } + tls_record_print(stderr, record, recordlen, 0, 0); + if (tls_record_get_handshake_server_hello(record, + &conn->version, server_random, conn->session_id, &conn->session_id_len, + &conn->cipher_suite, exts, &exts_len) != 1) { + error_print(); + return -1; + } + if (conn->version != TLS_version_tls12) { + error_print(); + return -1; + } + if (tls_cipher_suite_in_list(conn->cipher_suite, tls12_ciphers, tls12_ciphers_count) != 1) { + error_print(); + return -1; + } + // FIXME: check extensions + sm3_update(&sm3_ctx, record + 5, recordlen - 5); + if (client_sign_key) + sm2_sign_update(&sign_ctx, record + 5, recordlen - 5); + + tls_trace("<<<< ServerCertificate\n"); + if (tls12_record_recv(record, &recordlen, conn->sock) != 1) { + error_print(); + return -1; + } + tls_record_print(stderr, record, recordlen, 0, 0); + if (tls_record_get_handshake_certificate(record, conn->server_certs, &conn->server_certs_len) != 1) { + error_print(); + return -1; + } + + /* + // FIXME: review cert chain verification + if (tls_certificate_chain_verify(conn->server_certs, conn->server_certs_len, ca_certs_fp, 5) != 1) { + error_print(); + return -1; + } + */ + if (tls_certificate_get_public_keys(conn->server_certs, conn->server_certs_len, + &server_sign_key, NULL) != 1) { + error_print(); + return -1; + } + sm3_update(&sm3_ctx, record + 5, recordlen - 5); + if (client_sign_key) + sm2_sign_update(&sign_ctx, record + 5, recordlen - 5); + + tls_trace("<<<< ServerKeyExchange\n"); + if (tls12_record_recv(record, &recordlen, conn->sock) != 1) { + error_print(); + return -1; + } + tls_record_print(stderr, record, recordlen, conn->cipher_suite << 8, 0); + sm3_update(&sm3_ctx, record + 5, recordlen - 5); + if (client_sign_key) + sm2_sign_update(&sign_ctx, record + 5, recordlen - 5); + + if (tls_record_get_handshake_server_key_exchange_ecdhe(record, &curve, &server_ecdh_public, sig, &siglen) != 1) { + error_print(); + return -1; + } + if (curve != TLS_curve_sm2p256v1) { + error_print(); + return -1; + } + if (tls_verify_server_ecdh_params(&server_sign_key, + client_random, server_random, curve, &server_ecdh_public, sig, siglen) != 1) { + error_print(); + return -1; + } + + tls_trace("++++ generate secrets\n"); + sm2_keygen(&client_ecdh); + sm2_ecdh(&client_ecdh, &server_ecdh_public, &server_ecdh_public); + memcpy(pre_master_secret, &server_ecdh_public, 32); + + + tls_prf(pre_master_secret, 32, "master secret", + client_random, 32, + server_random, 32, + 48, conn->master_secret); + tls_prf(conn->master_secret, 48, "key expansion", + server_random, 32, + client_random, 32, + 96, conn->key_block); + sm3_hmac_init(&conn->client_write_mac_ctx, conn->key_block, 32); + sm3_hmac_init(&conn->server_write_mac_ctx, conn->key_block + 32, 32); + sm4_set_encrypt_key(&conn->client_write_enc_key, conn->key_block + 64); + sm4_set_decrypt_key(&conn->server_write_enc_key, conn->key_block + 80); + tls_secrets_print(stderr, pre_master_secret, 32, client_random, server_random, + conn->master_secret, conn->key_block, 96, 0, 0); + + + if (tls12_record_recv(record, &recordlen, conn->sock) != 1) { + error_print(); + return -1; + } + tls_record_print(stderr, record, recordlen, 0, 0); + if (tls_record_get_handshake(record, &type, &data, &datalen) != 1) { + error_print(); + return -1; + } + if (type == TLS_handshake_certificate_request) { + tls_trace("<<<< CertificateRequest\n"); + int cert_types[TLS_MAX_CERTIFICATE_TYPES]; + size_t cert_types_count;; + uint8_t ca_names[TLS_MAX_CA_NAMES_SIZE]; + size_t ca_names_len; + if (tls_record_get_handshake_certificate_request(record, + cert_types, &cert_types_count, + ca_names, &ca_names_len) != 1) { + error_print(); + return -1; + } + sm3_update(&sm3_ctx, record + 5, recordlen - 5); + if (client_sign_key) + sm2_sign_update(&sign_ctx, record + 5, recordlen - 5); + + if (tls_record_recv(record, &recordlen, conn->sock) != 1) { + error_print(); + return -1; + } + } else { + memset(&sign_ctx, 0, sizeof(SM2_SIGN_CTX)); + client_sign_key = NULL; + } + tls_trace("<<<< ServerHelloDone\n"); + tls_record_print(stderr, record, recordlen, 0, 0); + if (tls_record_get_handshake_server_hello_done(record) != 1) { + error_print(); + return -1; + } + sm3_update(&sm3_ctx, record + 5, recordlen - 5); + + + if (client_sign_key) { + sm2_sign_update(&sign_ctx, record + 5, recordlen - 5); + + tls_trace(">>>> ClientCertificate\n"); + if (tls_record_set_handshake_certificate_from_pem(record, &recordlen, client_certs_fp) != 1) { + error_print(); + return -1; + } + tls_record_print(stderr, record, recordlen, 0, 0); + if (tls_record_send(record, recordlen, conn->sock) != 1) { + error_print(); + return -1; + } + sm3_update(&sm3_ctx, record + 5, recordlen - 5); + sm2_sign_update(&sign_ctx, record + 5, recordlen - 5); + } + + + tls_trace(">>>> ClientKeyExchange\n"); + + + // 客户端的临时公钥 + if (tls_record_set_handshake_client_key_exchange_ecdhe(record, &recordlen, + &client_ecdh.public_key) != 1) { + error_print(); + return -1; + } + tls_record_print(stderr, record, recordlen, conn->cipher_suite << 8, 0); + if (tls_record_send(record, recordlen, conn->sock) != 1) { + error_print(); + return -1; + } + sm3_update(&sm3_ctx, record + 5, recordlen - 5); + if (client_sign_key) + sm2_sign_update(&sign_ctx, record + 5, recordlen - 5); + + if (client_sign_key) { + tls_trace(">>>> CertificateVerify\n"); + sm2_sign_finish(&sign_ctx, sig, &siglen); + if (tls_record_set_handshake_certificate_verify(record, &recordlen, sig, siglen) != 1) { + error_print(); + return -1; + } + tls_record_print(stderr, record, recordlen, 0, 0); + if (tls_record_send(record, recordlen, conn->sock) != 1) { + error_print(); + return -1; + } + sm3_update(&sm3_ctx, record + 5, recordlen - 5); + } + + tls_trace(">>>> [ChangeCipherSpec]\n"); + if (tls_record_set_change_cipher_spec(record, &recordlen) !=1) { + error_print(); + return -1; + } + if (tls_record_send(record, recordlen, conn->sock) != 1) { + error_print(); + return -1; + } + tls_record_print(stderr, record, recordlen, 0, 0); + + tls_trace(">>>> Finished\n"); + memcpy(&tmp_sm3_ctx, &sm3_ctx, sizeof(sm3_ctx)); + sm3_finish(&tmp_sm3_ctx, sm3_hash); + + tls_prf(conn->master_secret, 48, "client finished", + sm3_hash, 32, NULL, 0, + sizeof(verify_data), verify_data); + if (tls_record_set_handshake_finished(finished, &finishedlen, verify_data) != 1) { + error_print(); + return -1; + } + tls_record_print(stderr, finished, finishedlen, 0, 0); + sm3_update(&sm3_ctx, finished + 5, finishedlen - 5); + + if (tls_record_encrypt(&conn->client_write_mac_ctx, &conn->client_write_enc_key, + conn->client_seq_num, finished, finishedlen, record, &recordlen) != 1) { + error_print(); + return -1; + } + tls_seq_num_incr(conn->client_seq_num); + if (tls_record_send(record, recordlen, conn->sock) != 1) { + error_print(); + return -1; + } + + tls_trace("<<<< [ChangeCipherSpec]\n"); + if (tls12_record_recv(record, &recordlen, conn->sock) != 1) { + error_print(); + return -1; + } + tls_record_print(stderr, record, recordlen, 0, 0); + if (tls_record_get_change_cipher_spec(record) != 1) { + error_print(); + return -1; + } + + tls_trace("<<<< Finished\n"); + if (tls12_record_recv(record, &recordlen, conn->sock) != 1) { + error_print(); + return -1; + } + if (tls_record_decrypt(&conn->server_write_mac_ctx, &conn->server_write_enc_key, + conn->server_seq_num, record, recordlen, finished, &finishedlen) != 1) { + error_print(); + return -1; + } + tls_record_print(stderr, finished, finishedlen, 0, 0); + tls_seq_num_incr(conn->server_seq_num); + if (tls_record_get_handshake_finished(finished, verify_data) != 1) { + error_print(); + return -1; + } + sm3_finish(&sm3_ctx, sm3_hash); + tls_prf(conn->master_secret, 48, "server finished", + sm3_hash, 32, NULL, 0, + 12, local_verify_data); + if (memcmp(local_verify_data, verify_data, 12) != 0) { + error_print("server_finished.verify_data verification failure"); + return -1; + } + + tls_trace("++++ Connection established\n"); + return 1; +} + +// 实际上我们需要好几个比较大的buffer +// 一个是记录的buffer +// 还有就是server端需要一个握手buffer + + +int tls12_accept(TLS_CONNECT *conn, int port, + FILE *server_certs_fp, const SM2_KEY *server_sign_key, + FILE *client_cacerts_fp, uint8_t *handshakes_buf, size_t handshakes_buflen) +{ + uint8_t *handshakes = handshakes_buf; + size_t handshakeslen = 0; + uint8_t *record = conn->record; + size_t recordlen; + uint8_t finished[256]; + size_t finishedlen = sizeof(finished); + + uint8_t client_random[32]; + uint8_t server_random[32]; + uint8_t session_id[32]; + size_t session_id_len; + int client_ciphers[12] = {0}; + size_t client_ciphers_count = sizeof(client_ciphers)/sizeof(client_ciphers[0]); + uint8_t exts[TLS_MAX_EXTENSIONS_SIZE]; + size_t exts_len; + + SM2_KEY client_sign_key; + SM2_KEY server_ecdh; + SM2_POINT client_ecdh_public; + SM2_SIGN_CTX sign_ctx; + uint8_t sig[TLS_MAX_SIGNATURE_SIZE]; + size_t siglen = sizeof(sig); + uint8_t pre_master_secret[64]; + SM3_CTX sm3_ctx; + SM3_CTX tmp_sm3_ctx; + uint8_t sm3_hash[32]; + uint8_t verify_data[12]; + uint8_t local_verify_data[12]; + size_t i; + + int sock; + struct sockaddr_in server_addr; + struct sockaddr_in client_addr; + socklen_t client_addrlen; + + if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + error_print(); + return -1; + } + server_addr.sin_family = AF_INET; + server_addr.sin_addr.s_addr = INADDR_ANY; + server_addr.sin_port = htons(port); + + if (bind(sock, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) { + error_print(); + return -1; + } + + error_print("start listen ..."); + listen(sock, 5); + + memset(conn, 0, sizeof(*conn)); + + + + client_addrlen = sizeof(client_addr); + if ((conn->sock = accept(sock, (struct sockaddr *)&client_addr, &client_addrlen)) < 0) { + error_print(); + return -1; + } + + error_print("connected\n"); + + + + + sm3_init(&sm3_ctx); + + tls_trace("<<<< ClientHello\n"); + if (tls_record_recv(record, &recordlen, conn->sock) != 1) { + error_print(); + return -1; + } + tls_record_print(stderr, record, recordlen, 0, 0); + if (tls_record_version(record) != TLS_version_tls1 + && tls_record_version(record) != TLS_version_tls12) { + error_print(); + return -1; + } + if (tls_record_get_handshake_client_hello(record, + &conn->version, client_random, session_id, &session_id_len, + client_ciphers, &client_ciphers_count, exts, &exts_len) != 1) { + error_print(); + return -1; + } + if (conn->version != TLS_version_tls12) { + error_print(); + return -1; + } + for (i = 0; i < tls12_ciphers_count; i++) { + if (tls_cipher_suite_in_list(tls12_ciphers[i], client_ciphers, client_ciphers_count) == 1) { + conn->cipher_suite = tls12_ciphers[i]; + break; + } + } + if (conn->cipher_suite == 0) { + error_print("no common cipher_suite"); + return -1; + } + sm3_update(&sm3_ctx, record + 5, recordlen - 5); + tls_array_to_bytes(record + 5, recordlen - 5, &handshakes, &handshakeslen); + if (handshakes) { + /* + memcpy(handshakes, record + 5, recordlen - 5); + handshakes += recordlen - 5; + handshakeslen += recordlen - 5; + */ + } + + tls_trace(">>>> ServerHello\n"); + tls_random_generate(server_random); + tls_record_set_version(record, conn->version); + if (tls_record_set_handshake_server_hello(record, &recordlen, + conn->version, server_random, NULL, 0, + conn->cipher_suite, exts, exts_len) != 1) { + error_print(); + return -1; + } + tls_record_print(stderr, record, recordlen, 0, 0); + if (tls_record_send(record, recordlen, conn->sock) != 1) { + error_print(); + return -1; + } + sm3_update(&sm3_ctx, record + 5, recordlen - 5); + if (handshakes) { + memcpy(handshakes, record + 5, recordlen - 5); + handshakes += recordlen - 5; + handshakeslen += recordlen - 5; + } + + tls_trace(">>>> ServerCertificate\n"); + if (tls_record_set_handshake_certificate_from_pem(record, &recordlen, server_certs_fp) != 1) { + error_print(); + return -1; + } + tls_record_print(stderr, record, recordlen, 0, 0); + if (tls_record_send(record, recordlen, conn->sock) != 1) { + error_print(); + return -1; + } + if (tls_record_get_handshake_certificate(record, conn->server_certs, &conn->server_certs_len) != 1) { + error_print(); + return -1; + } + sm3_update(&sm3_ctx, record + 5, recordlen - 5); + tls_array_to_bytes(record + 5, recordlen - 5, &handshakes, &handshakeslen); + if (handshakes) { + /* + memcpy(handshakes, record + 5, recordlen - 5); + handshakes += recordlen - 5; + handshakeslen += recordlen - 5; + */ + } + + tls_trace(">>>> ServerKeyExchange\n"); + sm2_keygen(&server_ecdh); + if (tls_sign_server_ecdh_params(server_sign_key, + client_random, server_random, + TLS_curve_sm2p256v1, &server_ecdh.public_key, sig, &siglen) != 1) { + error_print(); + return -1; + } + if (tls_record_set_handshake_server_key_exchange_ecdhe(record, &recordlen, + TLS_curve_sm2p256v1, &server_ecdh.public_key, sig, siglen) != 1) { + error_print(); + return -1; + } + tls_record_print(stderr, record, recordlen, conn->cipher_suite << 8, 0); + if (tls_record_send(record, recordlen, conn->sock) != 1) { + error_print(); + return -1; + } + sm3_update(&sm3_ctx, record + 5, recordlen - 5); + tls_array_to_bytes(record + 5, recordlen - 5, &handshakes, &handshakeslen); + if (handshakes) { + /* + memcpy(handshakes, record + 5, recordlen - 5); + handshakes += recordlen - 5; + handshakeslen += recordlen - 5; + */ + } + + if (client_cacerts_fp) { + tls_trace(">>>> CertificateRequest\n"); + const int cert_types[] = { TLS_cert_type_ecdsa_sign, }; + uint8_t ca_names[TLS_MAX_CA_NAMES_SIZE] = {0}; + size_t cert_types_count = sizeof(cert_types)/sizeof(cert_types[0]); + size_t ca_names_len = 0; + if (tls_record_set_handshake_certificate_request(record, &recordlen, + cert_types, cert_types_count, + ca_names, ca_names_len) != 1) { + error_print(); + return -1; + } + tls_record_print(stderr, record, recordlen, 0, 0); + if (tls_record_send(record, recordlen, conn->sock) != 1) { + error_print(); + return -1; + } + sm3_update(&sm3_ctx, record + 5, recordlen - 5); + tls_array_to_bytes(record + 5, recordlen - 5, &handshakes, &handshakeslen); + if (handshakes) { + /* + memcpy(handshakes, record + 5, recordlen - 5); + handshakes += recordlen - 5; + handshakeslen += recordlen - 5; + */ + } + } + + tls_trace(">>>> ServerHelloDone\n"); + if (tls_record_set_handshake_server_hello_done(record, &recordlen) != 1) { + error_print(); + return -1; + } + tls_record_print(stderr, record, recordlen, 0, 0); + if (tls_record_send(record, recordlen, conn->sock) != 1) { + error_print(); + return -1; + } + sm3_update(&sm3_ctx, record + 5, recordlen - 5); + tls_array_to_bytes(record + 5, recordlen - 5, &handshakes, &handshakeslen); + if (handshakes) { + /* + memcpy(handshakes, record + 5, recordlen - 5); + handshakes += recordlen - 5; + handshakeslen += recordlen - 5; + */ + } + + if (handshakes) { + tls_trace("<<<< ClientCertificate\n"); + if (tls12_record_recv(record, &recordlen, conn->sock) != 1) { + error_print(); + return -1; + } + tls_record_print(stderr, record, recordlen, 0, 0); + if (tls_record_version(record) != TLS_version_tls12) { + error_print(); + return -1; + } + if (tls_record_get_handshake_certificate(record, + conn->client_certs, &conn->client_certs_len) != 1) { + error_print(); + return -1; + } + // FIXME: verify client's certificate with ca certs + if (tls_certificate_get_public_keys(conn->client_certs, conn->client_certs_len, + &client_sign_key, NULL) != 1) { + error_print(); + return -1; + } + sm3_update(&sm3_ctx, record + 5, recordlen - 5); + tls_array_to_bytes(record + 5, recordlen - 5, &handshakes, &handshakeslen); + /* + memcpy(handshakes, record + 5, recordlen - 5); + handshakes += recordlen - 5; + handshakeslen += recordlen - 5; + */ + } + + tls_trace("<<<< ClientKeyExchange\n"); + if (tls12_record_recv(record, &recordlen, conn->sock) != 1) { + error_print(); + return -1; + } + tls_record_print(stderr, record, recordlen, conn->cipher_suite << 8, 0); + if (tls_record_get_handshake_client_key_exchange_ecdhe(record, &client_ecdh_public) != 1) { + error_print(); + return -1; + } + sm3_update(&sm3_ctx, record + 5, recordlen - 5); + tls_array_to_bytes(record + 5, recordlen - 5, &handshakes, &handshakeslen); + if (handshakes) { + /* + memcpy(handshakes, record + 5, recordlen - 5); + handshakes += recordlen - 5; + handshakeslen += recordlen - 5; + */ + } + + tls_trace("++++ generate secrets\n"); + sm2_ecdh(&server_ecdh, &client_ecdh_public, (SM2_POINT *)pre_master_secret); + tls_prf(pre_master_secret, 32, "master secret", + client_random, 32, server_random, 32, + 48, conn->master_secret); + tls_prf(conn->master_secret, 48, "key expansion", + server_random, 32, client_random, 32, + 96, conn->key_block); + sm3_hmac_init(&conn->client_write_mac_ctx, conn->key_block, 32); + sm3_hmac_init(&conn->server_write_mac_ctx, conn->key_block + 32, 32); + sm4_set_decrypt_key(&conn->client_write_enc_key, conn->key_block + 64); + sm4_set_encrypt_key(&conn->server_write_enc_key, conn->key_block + 80); + tls_secrets_print(stderr, pre_master_secret, 32, client_random, server_random, + conn->master_secret, conn->key_block, 96, 0, 0); + + + if (handshakes) { + tls_trace("<<<< CertificateVerify\n"); + if (tls_record_recv(record, &recordlen, conn->sock) != 1 + || tls_record_version(record) != TLS_version_tls12) { + error_print(); + return -1; + } + tls_record_print(stderr, record, recordlen, 0, 0); + if (tls_record_get_handshake_certificate_verify(record, sig, &siglen) != 1) { + error_print(); + return -1; + } + sm3_update(&sm3_ctx, record + 5, recordlen - 5); + sm2_verify_init(&sign_ctx, &client_sign_key, SM2_DEFAULT_ID); + sm2_verify_update(&sign_ctx, handshakes_buf, handshakeslen); + if (sm2_verify_finish(&sign_ctx, sig, siglen) != 1) { + error_print(); + return -1; + } + } + + tls_trace("<<<< [ChangeCipherSpec]\n"); + if (tls12_record_recv(record, &recordlen, conn->sock) != 1) { + error_print(); + return -1; + } + tls_record_print(stderr, record, recordlen, 0, 0); + if (tls_record_get_change_cipher_spec(record) != 1) { + error_print(); + return -1; + } + + tls_trace("<<<< ClientFinished\n"); + if (tls12_record_recv(record, &recordlen, conn->sock) != 1) { + error_print(); + return -1; + } + if (tls_record_decrypt(&conn->client_write_mac_ctx, &conn->client_write_enc_key, + conn->client_seq_num, record, recordlen, finished, &finishedlen) != 1) { + error_print(); + return -1; + } + tls_seq_num_incr(conn->client_seq_num); + if (tls_record_get_handshake_finished(finished, verify_data) != 1) { + error_print(); + return -1; + } + tls_record_print(stderr, finished, finishedlen, 0, 0); + memcpy(&tmp_sm3_ctx, &sm3_ctx, sizeof(SM3_CTX)); + sm3_update(&sm3_ctx, finished + 5, finishedlen - 5); + + sm3_finish(&tmp_sm3_ctx, sm3_hash); + tls_prf(conn->master_secret, 48, "client finished", + sm3_hash, 32, NULL, 0, + 12, local_verify_data); + if (memcmp(local_verify_data, verify_data, 12) != 0) { + error_print("client_finished.verify_data verification failure"); + return -1; + } + + tls_trace(">>>> [ChangeCipherSpec]\n"); + if (tls_record_set_change_cipher_spec(record, &recordlen) != 1) { + error_print(); + return -1; + } + tls_record_print(stderr, record, recordlen, 0, 0); + if (tls_record_send(record, recordlen, conn->sock) != 1) { + error_print(); + return -1; + } + + tls_trace(">>>> ServerFinished\n"); + sm3_finish(&sm3_ctx, sm3_hash); + tls_prf(conn->master_secret, 48, "server finished", + sm3_hash, 32, NULL, 0, + 12, verify_data); + if (tls_record_set_handshake_finished(finished, &finishedlen, verify_data) != 1) { + error_print(); + return -1; + } + tls_record_print(stderr, finished, finishedlen, 0, 0); + if (tls_record_encrypt(&conn->server_write_mac_ctx, &conn->server_write_enc_key, + conn->server_seq_num, finished, finishedlen, record, &recordlen) != 1) { + error_print(); + return -1; + } + tls_seq_num_incr(conn->server_seq_num); + if (tls_record_send(record, recordlen, conn->sock) != 1) { + error_print(); + return -1; + } + + tls_trace("Connection Established!\n\n"); + return 1; +} diff --git a/src/tls13.c b/src/tls13.c new file mode 100644 index 00000000..17455477 --- /dev/null +++ b/src/tls13.c @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2021 - 2021 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + + + + + + diff --git a/src/tls_cipher.c b/src/tls_cipher.c new file mode 100644 index 00000000..7609969f --- /dev/null +++ b/src/tls_cipher.c @@ -0,0 +1,283 @@ +/* + * Copyright (c) 2021 - 2021 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +int tls_prf(const uint8_t *secret, size_t secretlen, const char *label, + const uint8_t *seed, size_t seedlen, + const uint8_t *more, size_t morelen, + size_t outlen, uint8_t *out) +{ + SM3_HMAC_CTX inited_hmac_ctx; + SM3_HMAC_CTX hmac_ctx; + uint8_t A[32]; + uint8_t hmac[32]; + size_t len; + + if (!secret || !secretlen || !label || !seed || !seedlen + || (!more && morelen) || !outlen || !out) { + error_print(); + return -1; + } + + sm3_hmac_init(&inited_hmac_ctx, secret, secretlen); + + memcpy(&hmac_ctx, &inited_hmac_ctx, sizeof(SM3_HMAC_CTX)); + sm3_hmac_update(&hmac_ctx, (uint8_t *)label, strlen(label)); + sm3_hmac_update(&hmac_ctx, seed, seedlen); + sm3_hmac_update(&hmac_ctx, more, morelen); + sm3_hmac_finish(&hmac_ctx, A); + + memcpy(&hmac_ctx, &inited_hmac_ctx, sizeof(SM3_HMAC_CTX)); + sm3_hmac_update(&hmac_ctx, A, sizeof(A)); + sm3_hmac_update(&hmac_ctx, (uint8_t *)label, strlen(label)); + sm3_hmac_update(&hmac_ctx, seed, seedlen); + sm3_hmac_update(&hmac_ctx, more, morelen); + sm3_hmac_finish(&hmac_ctx, hmac); + + len = outlen < sizeof(hmac) ? outlen : sizeof(hmac); + memcpy(out, hmac, len); + out += len; + outlen -= len; + + while (outlen) { + memcpy(&hmac_ctx, &inited_hmac_ctx, sizeof(SM3_HMAC_CTX)); + sm3_hmac_update(&hmac_ctx, A, sizeof(A)); + sm3_hmac_finish(&hmac_ctx, A); + + memcpy(&hmac_ctx, &inited_hmac_ctx, sizeof(SM3_HMAC_CTX)); + sm3_hmac_update(&hmac_ctx, A, sizeof(A)); + sm3_hmac_update(&hmac_ctx, (uint8_t *)label, strlen(label)); + sm3_hmac_update(&hmac_ctx, seed, seedlen); + sm3_hmac_update(&hmac_ctx, more, morelen); + sm3_hmac_finish(&hmac_ctx, hmac); + + len = outlen < sizeof(hmac) ? outlen : sizeof(hmac); + memcpy(out, hmac, len); + out += len; + outlen -= len; + } + return 1; +} + +int tls_cbc_encrypt(const SM3_HMAC_CTX *inited_hmac_ctx, const SM4_KEY *enc_key, + const uint8_t seq_num[8], const uint8_t header[5], + const uint8_t *in, size_t inlen, uint8_t *out, size_t *outlen) +{ + SM3_HMAC_CTX hmac_ctx; + uint8_t last_blocks[32 + 16] = {0}; + uint8_t *mac, *padding, *iv; + int rem, padding_len; + int i; + + if (!inited_hmac_ctx || !enc_key || !seq_num || !header || (!in && inlen) || !out || !outlen) { + error_print(); + return -1; + } + if (inlen > (1 << 14)) { + error_print("invalid tls record data length %zu\n", inlen); + return -1; + } + + rem = (inlen + 32) % 16; + memcpy(last_blocks, in + inlen - rem, rem); + mac = last_blocks + rem; + + memcpy(&hmac_ctx, inited_hmac_ctx, sizeof(SM3_HMAC_CTX)); + sm3_hmac_update(&hmac_ctx, seq_num, 8); + sm3_hmac_update(&hmac_ctx, header, 5); + sm3_hmac_update(&hmac_ctx, in, inlen); + sm3_hmac_finish(&hmac_ctx, mac); + + padding = mac + 32; + padding_len = 16 - rem - 1; + for (i = 0; i <= padding_len; i++) { + padding[i] = padding_len; + } + + iv = out; + if (rand_bytes(iv, 16) != 1) { + error_print(); + return -1; + } + out += 16; + + if (inlen >= 16) { + sm4_cbc_encrypt(enc_key, iv, in, inlen/16, out); + out += inlen - rem; + iv = out - 16; + } + sm4_cbc_encrypt(enc_key, iv, last_blocks, sizeof(last_blocks)/16, out); + *outlen = 16 + inlen - rem + sizeof(last_blocks); + return 1; +} + +int tls_cbc_decrypt(const SM3_HMAC_CTX *inited_hmac_ctx, const SM4_KEY *dec_key, + const uint8_t seq_num[8], const uint8_t enced_header[5], + const uint8_t *in, size_t inlen, uint8_t *out, size_t *outlen) +{ + SM3_HMAC_CTX hmac_ctx; + const uint8_t *iv; + const uint8_t *padding; + const uint8_t *mac; + uint8_t header[5]; + int padding_len; + int i; + + if (!inited_hmac_ctx || !dec_key || !seq_num || !enced_header || !in || !inlen || !out || !outlen) { + error_print(); + return -1; + } + if (inlen % 16 + || inlen < (16 + 0 + 32 + 16) // iv + data + mac + padding + || inlen > (16 + (1<<14) + 32 + 256)) { + error_print("invalid tls cbc ciphertext length %zu\n", inlen); + return -1; + } + + iv = in; + in += 16; + inlen -= 16; + + sm4_cbc_decrypt(dec_key, iv, in, inlen/16, out); + + padding_len = out[inlen - 1]; + padding = out + inlen - padding_len - 1; + if (padding < out + 32) { + error_print(); + return -1; + } + for (i = 0; i < padding_len; i++) { + if (padding[i] != padding_len) { + error_print("tls ciphertext cbc-padding check failure"); + return -1; + } + } + + *outlen = inlen - 32 - padding_len - 1; + header[0] = enced_header[0]; + header[1] = enced_header[1]; + header[2] = enced_header[2]; + header[3] = (*outlen) >> 8; + header[4] = (*outlen); + mac = padding - 32; + + memcpy(&hmac_ctx, inited_hmac_ctx, sizeof(SM3_HMAC_CTX)); + sm3_hmac_update(&hmac_ctx, seq_num, 8); + sm3_hmac_update(&hmac_ctx, header, 5); + sm3_hmac_update(&hmac_ctx, out, *outlen); + if (sm3_hmac_finish_and_verify(&hmac_ctx, mac) != 1) { + error_print("tls ciphertext mac check failure"); + return -1; + } + return 1; +} + +int tls_sign_server_ecdh_params(const SM2_KEY *server_sign_key, + const uint8_t client_random[32], const uint8_t server_random[32], + int curve, const SM2_POINT *point, uint8_t *sig, size_t *siglen) +{ + uint8_t server_ecdh_params[69]; + SM2_SIGN_CTX sign_ctx; + + if (!server_sign_key || !client_random || !server_random + || curve != TLS_curve_sm2p256v1 || !point || !sig || !siglen) { + error_print(); + return -1; + } + server_ecdh_params[0] = TLS_curve_type_named_curve; + server_ecdh_params[1] = curve >> 8; + server_ecdh_params[2] = curve; + server_ecdh_params[3] = 65; + sm2_point_to_uncompressed_octets(point, server_ecdh_params + 4); + + sm2_sign_init(&sign_ctx, server_sign_key, SM2_DEFAULT_ID); + sm2_sign_update(&sign_ctx, client_random, 32); + sm2_sign_update(&sign_ctx, server_random, 32); + sm2_sign_update(&sign_ctx, server_ecdh_params, 69); + sm2_sign_finish(&sign_ctx, sig, siglen); + return 1; +} + +int tls_verify_server_ecdh_params(const SM2_KEY *server_sign_key, + const uint8_t client_random[32], const uint8_t server_random[32], + int curve, const SM2_POINT *point, const uint8_t *sig, size_t siglen) +{ + int ret; + uint8_t server_ecdh_params[69]; + SM2_SIGN_CTX verify_ctx; + + if (!server_sign_key || !client_random || !server_random + || curve != TLS_curve_sm2p256v1 || !point || !sig || !siglen + || siglen > TLS_MAX_SIGNATURE_SIZE) { + error_print(); + return -1; + } + server_ecdh_params[0] = TLS_curve_type_named_curve; + server_ecdh_params[1] = curve >> 8; + server_ecdh_params[2] = curve; + server_ecdh_params[3] = 65; + sm2_point_to_uncompressed_octets(point, server_ecdh_params + 4); + + sm2_verify_init(&verify_ctx, server_sign_key, SM2_DEFAULT_ID); + sm2_verify_update(&verify_ctx, client_random, 32); + sm2_verify_update(&verify_ctx, server_random, 32); + sm2_verify_update(&verify_ctx, server_ecdh_params, 69); + ret = sm2_verify_finish(&verify_ctx, sig, siglen); + if (ret != 1) error_print(); + return ret; +} diff --git a/src/tls_trace.c b/src/tls_trace.c new file mode 100644 index 00000000..52a4926d --- /dev/null +++ b/src/tls_trace.c @@ -0,0 +1,927 @@ +/* + * Copyright (c) 2021 - 2021 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + + +const char *tls_record_type_name(int type) +{ + switch (type) { + case TLS_record_change_cipher_spec: return "ChangeCipherSpec"; + case TLS_record_alert: return "Alert"; + case TLS_record_handshake: return "Handshake"; + case TLS_record_application_data: return "ApplicationData"; + } + return NULL; +} + +const char *tls_version_text(int version) +{ + switch(version) { + case TLS_version_tlcp: return "TLCP"; + case TLS_version_ssl2: return "SSL 2.0"; + case TLS_version_ssl3: return "SSL 3.0"; + case TLS_version_tls1: return "TLS 1.0"; + case TLS_version_tls11: return "TLS 1.1"; + case TLS_version_tls12: return "TLS 1.2"; + case TLS_version_tls13: return "TLS 1.3"; + case TLS_version_dtls1: return "DTLS 1.0"; + case TLS_version_dtls12: return "DTLS 1.2"; + } + return NULL; +} + +const char *tls_cipher_suite_name(int cipher) +{ + switch (cipher) { + case TLCP_cipher_ecdhe_sm4_cbc_sm3: return "TLCP_ECDHE_SM4_CBC_SM3"; + case TLCP_cipher_ecdhe_sm4_gcm_sm3: return "TLCP_ECDHE_SM4_GCM_SM3"; + case TLCP_cipher_ecc_sm4_cbc_sm3: return "TLCP_ECC_SM4_CBC_SM3"; + case TLCP_cipher_ecc_sm4_gcm_sm3: return "TLCP_ECC_SM4_GCM_SM3"; + case TLCP_cipher_ibsdh_sm4_cbc_sm3: return "TLCP_IBSDH_SM4_CBC_SM3"; + case TLCP_cipher_ibsdh_sm4_gcm_sm3: return "TLCP_IBSDH_SM4_GCM_SM3"; + case TLCP_cipher_ibc_sm4_cbc_sm3: return "TLCP_IBC_SM4_CBC_SM3"; + case TLCP_cipher_ibc_sm4_gcm_sm3: return "TLCP_IBC_SM4_GCM_SM3"; + case TLCP_cipher_rsa_sm4_cbc_sm3: return "TLCP_RSA_SM4_CBC_SM3"; + case TLCP_cipher_rsa_sm4_gcm_sm3: return "TLCP_RSA_SM4_GCM_SM3"; + case TLCP_cipher_rsa_sm4_cbc_sha256: return "TLCP_RSA_SM4_CBC_SHA256"; + case TLCP_cipher_rsa_sm4_gcm_sha256: return "TLCP_RSA_SM4_GCM_SHA256"; + case GMSSL_cipher_ecdhe_sm2_with_sm4_sm3: return "GMSSL_ECDHE_SM2_WITH_SM4_SM3"; + case GMSSL_cipher_ecdhe_sm2_with_sm4_gcm_sm3: return "GMSSL_ECDHE_SM2_WITH_SM4_GCM_SM3"; + case GMSSL_cipher_ecdhe_sm2_with_sm4_ccm_sm3: return "GMSSL_ECDHE_SM2_WITH_SM4_CCM_SM3"; + case GMSSL_cipher_ecdhe_sm2_with_zuc_sm3: return "GMSSL_ECDHE_SM2_WITH_ZUC_SM3"; + case TLS_cipher_empty_renegotiation_info_scsv: return "TLS_EMPTY_RENEGOTIATION_INFO_SCSV"; + } + return NULL; +} + +const char *tls_compression_method_name(int meth) +{ + switch (meth) { + case 0: return "no_compression"; + } + return NULL; +} + +const char *tls_extension_name(int ext) +{ + switch (ext) { + case TLS_extension_server_name: return "server_name"; + case TLS_extension_max_fragment_length: return "max_fragment_length"; + case TLS_extension_client_certificate_url: return "client_certificate_url"; + case TLS_extension_trusted_ca_keys: return "trusted_ca_keys"; + case TLS_extension_truncated_hmac: return "truncated_hmac"; + case TLS_extension_status_request: return "status_request"; + case TLS_extension_user_mapping: return "user_mapping"; + case TLS_extension_client_authz: return "client_authz"; + case TLS_extension_server_authz: return "server_authz"; + case TLS_extension_cert_type: return "cert_type"; + case TLS_extension_supported_groups: return "supported_groups"; + case TLS_extension_ec_point_formats: return "ec_point_formats"; + case TLS_extension_srp: return "srp"; + case TLS_extension_signature_algorithms: return "signature_algorithms"; + case TLS_extension_use_srtp: return "use_srtp"; + case TLS_extension_heartbeat: return "heartbeat"; + case TLS_extension_application_layer_protocol_negotiation: return "application_layer_protocol_negotiation"; + case TLS_extension_status_request_v2: return "status_request_v2"; + case TLS_extension_signed_certificate_timestamp: return "signed_certificate_timestamp"; + case TLS_extension_client_certificate_type: return "client_certificate_type"; + case TLS_extension_server_certificate_type: return "server_certificate_type"; + case TLS_extension_padding: return "padding"; + case TLS_extension_encrypt_then_mac: return "encrypt_then_mac"; + case TLS_extension_extended_master_secret: return "extended_master_secret"; + case TLS_extension_token_binding: return "token_binding"; + case TLS_extension_cached_info: return "cached_info"; + case TLS_extension_tls_lts: return "tls_lts"; + case TLS_extension_compress_certificate: return "compress_certificate"; + case TLS_extension_record_size_limit: return "record_size_limit"; + case TLS_extension_pwd_protect: return "pwd_protect"; + case TLS_extension_pwd_clear: return "pwd_clear"; + case TLS_extension_password_salt: return "password_salt"; + case TLS_extension_ticket_pinning: return "ticket_pinning"; + case TLS_extension_tls_cert_with_extern_psk: return "tls_cert_with_extern_psk"; + case TLS_extension_delegated_credentials: return "delegated_credentials"; + case TLS_extension_session_ticket: return "session_ticket"; + case TLS_extension_TLMSP: return "TLMSP"; + case TLS_extension_TLMSP_proxying: return "TLMSP_proxying"; + case TLS_extension_TLMSP_delegate: return "TLMSP_delegate"; + case TLS_extension_supported_ekt_ciphers: return "supported_ekt_ciphers"; + case TLS_extension_pre_shared_key: return "pre_shared_key"; + case TLS_extension_early_data: return "early_data"; + case TLS_extension_supported_versions: return "supported_versions"; + case TLS_extension_cookie: return "cookie"; + case TLS_extension_psk_key_exchange_modes: return "psk_key_exchange_modes"; + case TLS_extension_certificate_authorities: return "certificate_authorities"; + case TLS_extension_oid_filters: return "oid_filters"; + case TLS_extension_post_handshake_auth: return "post_handshake_auth"; + case TLS_extension_signature_algorithms_cert: return "signature_algorithms_cert"; + case TLS_extension_key_share: return "key_share"; + case TLS_extension_transparency_info: return "transparency_info"; + case TLS_extension_connection_id: return "connection_id"; + case TLS_extension_external_id_hash: return "external_id_hash"; + case TLS_extension_external_session_id: return "external_session_id"; + case TLS_extension_quic_transport_parameters: return "quic_transport_parameters"; + case TLS_extension_ticket_request: return "ticket_request"; + case TLS_extension_renegotiation_info: return "renegotiation_info"; + }; + return NULL; +} + +const char *tls_cert_type_name(int type) +{ + switch (type) { + case TLS_cert_type_rsa_sign: return "rsa_sign"; + case TLS_cert_type_dss_sign: return "dss_sign"; + case TLS_cert_type_rsa_fixed_dh: return "rsa_fixed_dh"; + case TLS_cert_type_dss_fixed_dh: return "dss_fixed_dh"; + case TLS_cert_type_rsa_ephemeral_dh_RESERVED: return "rsa_ephemeral_dh_RESERVED"; + case TLS_cert_type_dss_ephemeral_dh_RESERVED: return "dss_ephemeral_dh_RESERVED"; + case TLS_cert_type_fortezza_dms_RESERVED: return "fortezza_dms_RESERVED"; + case TLS_cert_type_ecdsa_sign: return "ecdsa_sign"; + case TLS_cert_type_rsa_fixed_ecdh: return "rsa_fixed_ecdh_DEPRECATED"; + case TLS_cert_type_ecdsa_fixed_ecdh: return "ecdsa_fixed_ecdh_DEPRECATED"; + case TLS_cert_type_gost_sign256: return "gost_sign256"; + case TLS_cert_type_gost_sign512: return "gost_sign512"; + case TLS_cert_type_ibc_params: return "ibc_params"; + } + return NULL; +} + +const char *tls_handshake_type_name(int type) +{ + switch (type) { + case TLS_handshake_hello_request: return "HelloRequest"; + case TLS_handshake_client_hello: return "ClientHello"; + case TLS_handshake_server_hello: return "ServerHello"; + case TLS_handshake_certificate: return "Certificate"; + case TLS_handshake_server_key_exchange: return "ServerKeyExchange"; + case TLS_handshake_certificate_request: return "CertificateRequest"; + case TLS_handshake_server_hello_done: return "ServerHelloDone"; + case TLS_handshake_certificate_verify: return "CertificateRequest"; + case TLS_handshake_client_key_exchange: return "ClientKeyExchange"; + case TLS_handshake_finished: return "Finished"; + } + return NULL; +} + +const char *tls_alert_level_name(int level) +{ + switch (level) { + case TLS_alert_level_warning: return "warning"; + case TLS_alert_level_fatal: return "fatal"; + } + error_print("unknown alert level %d", level); + return NULL; +} + +const char *tls_alert_description_text(int description) +{ + switch (description) { + case TLS_alert_close_notify: return "close_notify"; + case TLS_alert_unexpected_message: return "unexpected_message"; + case TLS_alert_bad_record_mac: return "bad_record_mac"; + case TLS_alert_decryption_failed: return "decryption_failed"; + case TLS_alert_record_overflow: return "record_overflow"; + case TLS_alert_decompression_failure: return "decompression_failure"; + case TLS_alert_handshake_failure: return "handshake_failure"; + case TLS_alert_no_certificate: return "no_certificate_RESERVED"; + case TLS_alert_bad_certificate: return "bad_certificate"; + case TLS_alert_unsupported_certificate: return "unsupported_certificate"; + case TLS_alert_certificate_revoked: return "certificate_revoked"; + case TLS_alert_certificate_expired: return "certificate_expired"; + case TLS_alert_certificate_unknown: return "certificate_unknown"; + case TLS_alert_illegal_parameter: return "illegal_parameter"; + case TLS_alert_unknown_ca: return "unknown_ca"; + case TLS_alert_access_denied: return "access_denied"; + case TLS_alert_decode_error: return "decode_error"; + case TLS_alert_decrypt_error: return "decrypt_error"; + case TLS_alert_export_restriction: return "export_restriction_RESERVED"; + case TLS_alert_protocol_version: return "protocol_version"; + case TLS_alert_insufficient_security: return "insufficient_security"; + case TLS_alert_internal_error: return "internal_error"; + case TLS_alert_user_canceled: return "user_canceled"; + case TLS_alert_no_renegotiation: return "no_renegotiation"; + case TLS_alert_unsupported_site2site: return "unsupported_site2site"; + case TLS_alert_no_area: return "no_area"; + case TLS_alert_unsupported_areatype: return "unsupported_areatype"; + case TLS_alert_bad_ibcparam: return "bad_ibcparam"; + case TLS_alert_unsupported_ibcparam: return "unsupported_ibcparam"; + case TLS_alert_identity_need: return "identity_need"; + } + error_print("unknown alert description %d", description); + return NULL; +} + +const char *tls_change_cipher_spec_text(int change_cipher_spec) +{ + switch (change_cipher_spec) { + case TLS_change_cipher_spec: return "change_cipher_spec"; + } + return NULL; +} + +const char *tls_ec_point_format_name(int format) +{ + switch (format) { + case TLS_point_uncompressed: return "uncompressed"; + case TLS_point_ansix962_compressed_prime: return "compressed_prime"; + case TLS_point_ansix962_compressed_char2: return "compressed_char2"; + } + return NULL; +} + +const char *tls_curve_type_name(int type) +{ + switch (type) { + case TLS_curve_type_explicit_prime: return "explicit_prime"; + case TLS_curve_type_explicit_char2: return "explicit_char2"; + case TLS_curve_type_named_curve: return "named_curve"; + } + return NULL; +} + +const char *tls_named_curve_name(int curve) +{ + switch (curve) { + case TLS_curve_secp256k1: return "secp256k1"; + case TLS_curve_secp256r1: return "secp256r1"; + case TLS_curve_secp384r1: return "secp384r1"; + case TLS_curve_secp521r1: return "secp521r1"; + case TLS_curve_brainpoolp256r1: return "brainpoolp256r1"; + case TLS_curve_brainpoolp384r1: return "brainpoolp384r1"; + case TLS_curve_brainpoolp512r1: return "brainpoolp512r1"; + case TLS_curve_x25519: return "x25519"; + case TLS_curve_x448: return "x448"; + case TLS_curve_brainpoolp256r1tls13: return "brainpoolp256r1tls13"; + case TLS_curve_brainpoolp384r1tls13: return "brainpoolp384r1tls13"; + case TLS_curve_brainpoolp512r1tls13: return "brainpoolp512r1tls13"; + case TLS_curve_sm2p256v1: return "sm2p256v1"; + } + return NULL; +} + +const char *tls_signature_scheme_name(int scheme) +{ + switch (scheme) { + case TLS_sig_rsa_pkcs1_sha1: return "rsa_pkcs1_sha1"; + case TLS_sig_ecdsa_sha1: return "ecdsa_sha1"; + case TLS_sig_rsa_pkcs1_sha256: return "rsa_pkcs1_sha256"; + case TLS_sig_ecdsa_secp256r1_sha256: return "ecdsa_secp256r1_sha256"; + case TLS_sig_rsa_pkcs1_sha256_legacy: return "rsa_pkcs1_sha256_legacy"; + case TLS_sig_rsa_pkcs1_sha384: return "rsa_pkcs1_sha384"; + case TLS_sig_ecdsa_secp384r1_sha384: return "ecdsa_secp384r1_sha384"; + case TLS_sig_rsa_pkcs1_sha384_legacy: return "rsa_pkcs1_sha384_legacy"; + case TLS_sig_rsa_pkcs1_sha512: return "rsa_pkcs1_sha512"; + case TLS_sig_ecdsa_secp521r1_sha512: return "ecdsa_secp521r1_sha512"; + case TLS_sig_rsa_pkcs1_sha512_legacy: return "rsa_pkcs1_sha512_legacy"; + case TLS_sig_sm2sig_sm3: return "sm2sig_sm3"; + case TLS_sig_rsa_pss_rsae_sha256: return "rsa_pss_rsae_sha256"; + case TLS_sig_rsa_pss_rsae_sha384: return "rsa_pss_rsae_sha384"; + case TLS_sig_rsa_pss_rsae_sha512: return "rsa_pss_rsae_sha512"; + case TLS_sig_ed25519: return "ed25519"; + case TLS_sig_ed448: return "ed448"; + case TLS_sig_rsa_pss_pss_sha256: return "rsa_pss_pss_sha256"; + case TLS_sig_rsa_pss_pss_sha384: return "rsa_pss_pss_sha384"; + case TLS_sig_rsa_pss_pss_sha512: return "rsa_pss_pss_sha512"; + case TLS_sig_ecdsa_brainpoolP256r1tls13_sha256: return "ecdsa_brainpoolP256r1tls13_sha256"; + case TLS_sig_ecdsa_brainpoolP384r1tls13_sha384: return "ecdsa_brainpoolP384r1tls13_sha384"; + case TLS_sig_ecdsa_brainpoolP512r1tls13_sha512: return "ecdsa_brainpoolP512r1tls13_sha512"; + } + return NULL; +} + +int tls_random_print(FILE *fp, const uint8_t random[32], int format, int indent) +{ + int i; + time_t gmt_unix_time = 0; + const uint8_t *cp = random; + size_t len = 4; + + tls_uint32_from_bytes((uint32_t *)&gmt_unix_time, &cp, &len); + format_print(fp, format, indent, "Random\n"); + indent += 4; + format_print(fp, format, indent, "gmt_unix_time : %s", ctime(&gmt_unix_time)); + format_bytes(fp, format, indent, "random : ", random + 4, 28); + return 1; +} + +int tls_pre_master_secret_print(FILE *fp, const uint8_t pre_master_secret[48], int format, int indent) +{ + int version = ((int)pre_master_secret[0] << 8) | pre_master_secret[1]; + format_print(fp, format, indent, "PreMasterSecret\n"); + indent += 4; + format_print(fp, format, indent, "version : %s\n", tls_version_text(version)); + format_bytes(fp, format, indent, "pre_master_secret : ", pre_master_secret, 48); + return 1; +} + +int tls_extension_print(FILE *fp, int type, const uint8_t *data, size_t datalen, int format, int indent) +{ + const uint8_t *p; + size_t len; + + format_print(fp, format, indent, "%s (%d)\n", tls_extension_name(type), type); + indent += 4; + + switch (type) { + case TLS_extension_supported_groups: + if (tls_uint16array_from_bytes(&p, &len, &data, &datalen) != 1 + || datalen + || len % 2) { + error_print(); + return -1; + } + while (len) { + uint16_t curve; + tls_uint16_from_bytes(&curve, &p, &len); + format_print(fp, format, indent, "%s (0x%04x)\n", + tls_named_curve_name(curve), curve); + } + break; + case TLS_extension_ec_point_formats: + if (tls_uint8array_from_bytes(&p, &len, &data, &datalen) != 1 + || datalen) { + error_print(); + return -1; + } + while (len) { + uint8_t point_form; + tls_uint8_from_bytes(&point_form, &p, &len); + format_print(fp, format, indent, "%s (%d)\n", + tls_ec_point_format_name(point_form), point_form); + } + break; + case TLS_extension_signature_algorithms: + if (tls_uint16array_from_bytes(&p, &len, &data, &datalen) != 1 + || datalen + || len % 2) { + error_print(); + return -1; + } + while (len) { + uint16_t sig_alg; + tls_uint16_from_bytes(&sig_alg, &p, &len); + format_print(fp, format, indent, "%s (0x%04x)\n", + tls_signature_scheme_name(sig_alg), sig_alg); + } + break; + default: + format_bytes(fp, format, indent, "raw_data : ", data, datalen); + } + return 1; +} + +int tls_extensions_print(FILE *fp, const uint8_t *exts, size_t extslen, int format, int indent) +{ + uint16_t ext_type; + const uint8_t *ext_data; + size_t ext_datalen; + + format_print(fp, format, indent, "Extensions\n"); + indent += 4; + while (extslen > 0) { + if (tls_uint16_from_bytes(&ext_type, &exts, &extslen) != 1 + || tls_uint16array_from_bytes(&ext_data, &ext_datalen, &exts, &extslen) != 1) { + error_print(); + return -1; + } + if (tls_extension_print(fp, ext_type, ext_data, ext_datalen, format, indent) != 1) { + error_print(); + return -1; + } + } + return 1; +} + +int tls_client_hello_print(FILE *fp, const uint8_t *data, size_t datalen, int format, int indent) +{ + int ret = -1; + uint16_t version; + const uint8_t *random; + const uint8_t *session_id; + const uint8_t *cipher_suites; + const uint8_t *comp_meths; + const uint8_t *exts; + size_t session_id_len, cipher_suites_len, comp_meths_len, exts_len; + size_t i; + + format_print(fp, format, indent, "ClientHello\n"); indent += 4; + if (tls_uint16_from_bytes((uint16_t *)&version, &data, &datalen) != 1) goto end; + format_print(fp, format, indent, "Version : %s (%d.%d)\n", + tls_version_text(version), version >> 8, version & 0xff); + if (tls_array_from_bytes(&random, 32, &data, &datalen) != 1) goto end; + tls_random_print(fp, random, format, indent); + if (tls_uint8array_from_bytes(&session_id, &session_id_len, &data, &datalen) != 1) goto end; + format_bytes(fp, format, indent, "SessionID : ", session_id, session_id_len); + if (tls_uint16array_from_bytes(&cipher_suites, &cipher_suites_len, &data, &datalen) != 1) goto end; + format_print(fp, format, indent, "CipherSuites\n"); + while (cipher_suites_len >= 2) { + uint16_t cipher; + if (tls_uint16_from_bytes(&cipher, &cipher_suites, &cipher_suites_len) != 1) goto end; + format_print(fp, format, indent + 4, "%s (0x%04x)\n", + tls_cipher_suite_name(cipher), cipher); + } + if (cipher_suites_len) { + error_print(); + return -1; + } + if (tls_uint8array_from_bytes(&comp_meths, &comp_meths_len, &data, &datalen) != 1) goto end; + format_print(fp, format, indent, "CompressionMethods\n"); + for (i = 0; i < comp_meths_len; i++) { + format_print(fp, format, indent + 4, "%s (%d)\n", + tls_compression_method_name(comp_meths[i]), comp_meths[i]); + } + if (datalen > 0) { + if (tls_uint16array_from_bytes(&exts, &exts_len, &data, &datalen) != 1) goto end; + tls_extensions_print(fp, exts, exts_len, format, indent); + } + if (datalen > 0) { + error_print(); + return -1; + } + ret = 1; +end: + return ret; +} + +int tls_server_hello_print(FILE *fp, const uint8_t *data, size_t datalen, int format, int indent) +{ + int ret = -1; + uint16_t version; + const uint8_t *random; + const uint8_t *session_id; + uint16_t cipher_suite; + uint8_t comp_meth; + const uint8_t *exts; + size_t session_id_len, cipher_suites_len, comp_meths_len, exts_len; + size_t i; + + format_print(fp, format, indent, "ServerHello\n"); indent += 4; + if (tls_uint16_from_bytes(&version, &data, &datalen) != 1) goto bad; + format_print(fp, format, indent, "Version : %s (%d.%d)\n", + tls_version_text(version), version >> 8, version & 0xff); + if (tls_array_from_bytes(&random, 32, &data, &datalen) != 1) goto bad; + tls_random_print(fp, random, format, indent); + if (tls_uint8array_from_bytes(&session_id, &session_id_len, &data, &datalen) != 1) goto bad; + format_bytes(fp, format, indent, "SessionID : ", session_id, session_id_len); + if (tls_uint16_from_bytes(&cipher_suite, &data, &datalen) != 1) goto bad; + format_print(fp, format, indent, "CipherSuite : %s (0x%04x)\n", + tls_cipher_suite_name(cipher_suite), cipher_suite); + if (tls_uint8_from_bytes(&comp_meth, &data, &datalen) != 1) goto bad; + format_print(fp, format, indent, "CompressionMethod : %s (%d)\n", + tls_compression_method_name(comp_meth), comp_meth); + if (datalen > 0) { + if (tls_uint16array_from_bytes(&exts, &exts_len, &data, &datalen) != 1) goto bad; + format_bytes(fp, format, indent, "Extensions : ", exts, exts_len); // FIXME: extensions_print + } + return 1; +bad: + error_print(); + return -1; +} + +int tls_certificate_print(FILE *fp, const uint8_t *data, size_t datalen, int format, int indent) +{ + int ret; + const uint8_t *certs; + size_t certslen; + const uint8_t *der; + size_t derlen; + + if (tls_uint24array_from_bytes(&certs, &certslen, &data, &datalen) != 1 + || datalen > 0) { + error_print(); + return -1; + } + while (certslen > 0) { + X509_CERTIFICATE cert; + if (tls_uint24array_from_bytes(&der, &derlen, &certs, &certslen) != 1) { + error_print(); + return -1; + } + if (x509_certificate_from_der(&cert, &der, &derlen) != 1) { + error_print(); + return -1; + } + if (derlen > 0) { + error_print(); + return -1; + } + (void)x509_certificate_print(fp, &cert, format, indent); + (void)x509_certificate_to_pem(&cert, fp); + } + return 1; +} + +int tlcp_server_key_exchange_pke_print(FILE *fp, const uint8_t *data, size_t datalen, int format, int indent) +{ + const uint8_t *sig = data; + size_t siglen = datalen; + /* + if (tls_uint16array_from_bytes(&sig, &siglen, &data, &datalen) != 1 + || datalen > 0) { + error_print(); + } + */ + format_print(fp, format, indent, "ServerKeyExchange:\n"); + indent += 4; + format_bytes(fp, format, indent, "signature : ", sig, siglen); + return 1; +} + +int tls_server_key_exchange_ecdhe_print(FILE *fp, const uint8_t *data, size_t datalen, + int format, int indent) +{ + uint8_t curve_type; + uint16_t curve; + const uint8_t *octets; + size_t octetslen; + uint16_t sig_alg; + const uint8_t *sig; + size_t siglen; + + format_print(fp, format, indent, "ServerKeyExchange\n"); + indent += 4; + format_print(fp, format, indent, "ServerECDHParams\n"); + format_print(fp, format, indent + 4, "curve_params\n"); + if (tls_uint8_from_bytes(&curve_type, &data, &datalen) != 1) { + error_print(); + return -1; + } + format_print(fp, format, indent + 8, "curve_type : %s (%d)\n", + tls_curve_type_name(curve_type), curve_type); + if (tls_uint16_from_bytes(&curve, &data, &datalen) != 1) { + error_print(); + return -1; + } + format_print(fp, format, indent + 8, "named_curve : %s (04%04x)\n", + tls_named_curve_name(curve), curve); + if (tls_uint8array_from_bytes(&octets, &octetslen, &data, &datalen) != 1) { + error_print(); + return -1; + } + format_bytes(fp, format, indent + 4, "point : ", octets, octetslen); + if (tls_uint16_from_bytes(&sig_alg, &data, &datalen) != 1) { + error_print(); + return -1; + } + format_print(fp, format, indent, "SignatureScheme : %s (04%04x)\n", + tls_signature_scheme_name(sig_alg), sig_alg); + if (tls_uint16array_from_bytes(&sig, &siglen, &data, &datalen) != 1) { + error_print(); + return -1; + } + format_bytes(fp, format, indent, "Siganture : ", sig, siglen); + if (datalen > 0) { + error_print(); + return -1; + } + return 1; +} + +int tls_server_key_exchange_print(FILE *fp, const uint8_t *data, size_t datalen, int format, int indent) +{ + int cipher_suite = (format >> 8) & 0xffff; + switch (cipher_suite) { + case TLCP_cipher_ecc_sm4_cbc_sm3: + case TLCP_cipher_ecc_sm4_gcm_sm3: + if (tlcp_server_key_exchange_pke_print(fp, data, datalen, format, indent) != 1) { + error_print(); + return -1; + } + break; + case TLCP_cipher_ecdhe_sm4_cbc_sm3: + case TLCP_cipher_ecdhe_sm4_gcm_sm3: + case GMSSL_cipher_ecdhe_sm2_with_sm4_sm3: + case GMSSL_cipher_ecdhe_sm2_with_sm4_gcm_sm3: + case GMSSL_cipher_ecdhe_sm2_with_sm4_ccm_sm3: + if (tls_server_key_exchange_ecdhe_print(fp, data, datalen, format, indent) != 1) { + error_print(); + return -1; + } + break; + default: + error_print(); + return -1; + } + return 1; +} + +int tls_certificate_request_print(FILE *fp, const uint8_t *data, size_t datalen, int format, int indent) +{ + const uint8_t *cert_types; + const uint8_t *ca_names; + size_t cert_types_len, ca_names_len, i; + + format_print(fp, format, indent, "CertificateRequest\n"); indent += 4; + if (tls_uint8array_from_bytes(&cert_types, &cert_types_len, &data, &datalen) != 1) goto bad; + format_print(fp, format, indent, "cert_types\n"); + while (cert_types_len--) { + format_print(fp, format, indent + 4, "%s\n", tls_cert_type_name(*cert_types++)); + } + if (tls_uint16array_from_bytes(&ca_names, &ca_names_len, &data, &datalen) != 1) goto bad; + format_bytes(fp, format, indent, "CAnames : ", ca_names, ca_names_len); + return 1; +bad: + error_print(); + return -1; +} + +int tls_server_hello_done_print(FILE *fp, const uint8_t *data, size_t datalen, int format, int indent) +{ + if (datalen > 0) { + error_print(); + return -1; + } + return 1; +} + +int tls_client_key_exchange_pke_print(FILE *fp, const uint8_t *data, size_t datalen, int format, int indent) +{ + const uint8_t *enced_pms; + size_t enced_pms_len; + + if (tls_uint16array_from_bytes(&enced_pms, &enced_pms_len, &data, &datalen) != 1) { + error_print(); + return -1; + } + format_bytes(fp, format, indent, "EncryptedPreMasterSecret : ", enced_pms, enced_pms_len); + return 1; +} + +int tls_client_key_exchange_ecdhe_print(FILE *fp, const uint8_t *data, size_t datalen, + int format, int indent) +{ + const uint8_t *octets; + size_t octetslen; + + format_print(fp, format, indent, "ClientKeyExchange\n"); + indent += 4; + if (tls_uint8array_from_bytes(&octets, &octetslen, &data, &datalen) != 1) { + error_print(); + return -1; + } + format_bytes(fp, format, indent, "ecdh_Yc : ", octets, octetslen); + if (datalen > 0) { + error_print(); + return -1; + } + return 1; +} + +int tls_client_key_exchange_print(FILE *fp, const uint8_t *data, size_t datalen, int format, int indent) +{ + int cipher_suite = (format >> 8) & 0xffff; + switch (cipher_suite) { + case TLCP_cipher_ecc_sm4_cbc_sm3: + case TLCP_cipher_ecc_sm4_gcm_sm3: + if (tls_client_key_exchange_pke_print(fp, data, datalen, format, indent) != 1) { + error_print(); + return -1; + } + break; + case TLCP_cipher_ecdhe_sm4_cbc_sm3: + case TLCP_cipher_ecdhe_sm4_gcm_sm3: + case GMSSL_cipher_ecdhe_sm2_with_sm4_sm3: + case GMSSL_cipher_ecdhe_sm2_with_sm4_gcm_sm3: + case GMSSL_cipher_ecdhe_sm2_with_sm4_ccm_sm3: + if (tls_client_key_exchange_ecdhe_print(fp, data, datalen, format, indent) != 1) { + error_print(); + return -1; + } + break; + default: + error_print(); + return -1; + } + return 1; +} + +int tls_certificate_verify_print(FILE *fp, const uint8_t *data, size_t datalen, int format, int indent) +{ + format_print(fp, format, indent, "CertificateVerify :\n"); + format_bytes(fp, format, indent + 4, "Signature : ", data, datalen); + return 1; +} + +int tls_finished_print(FILE *fp, const uint8_t *data, size_t datalen, int format, int indent) +{ + format_print(fp, format, indent, "Finished\n"); + indent += 4; + format_bytes(fp, format, indent, "verify_data : ", data, datalen); + return 1; +} + +int tls_handshake_print(FILE *fp, const uint8_t *handshake, size_t handshakelen, int format, int indent) +{ + const uint8_t *cp = handshake; + int type; + const uint8_t *data; + size_t datalen = 0; + + format_print(fp, format, indent, "Handshake\n"); + indent += 4; + + if (tls_uint8_from_bytes((uint8_t *)&type, &cp, &handshakelen) != 1) { + error_print(); + return -1; + } + format_print(fp, format, indent, "Type : %s (%d)\n", tls_handshake_type_name(type), type); + if (tls_uint24_from_bytes((uint24_t *)&datalen, &cp, &handshakelen) != 1) { + error_print(); + return -1; + } + format_print(fp, format, indent, "Length : %zu\n", datalen); + + if (tls_array_from_bytes(&data, datalen, &cp, &handshakelen) != 1) { + error_print(); + return -1; + } + switch (type) { + case TLS_handshake_client_hello: + if (tls_client_hello_print(fp, data, datalen, format, indent) != 1) + { error_print(); return -1; } break; + case TLS_handshake_server_hello: + if (tls_server_hello_print(fp, data, datalen, format, indent) != 1) + { error_print(); return -1; } break; + case TLS_handshake_certificate: + if (tls_certificate_print(fp, data, datalen, format, indent) != 1) + { error_print(); return -1; } break; + case TLS_handshake_server_key_exchange: + if (tls_server_key_exchange_print(fp, data, datalen, format, indent) != 1) + { error_print(); return -1; } break; + case TLS_handshake_certificate_request: + if (tls_certificate_request_print(fp, data, datalen, format, indent) != 1) + { error_print(); return -1; } break; + case TLS_handshake_server_hello_done: + if (tls_server_hello_done_print(fp, data, datalen, format, indent) != 1) + { error_print(); return -1; } break; + case TLS_handshake_client_key_exchange: + if (tls_client_key_exchange_print(fp, data, datalen, format, indent) != 1) + { error_print(); return -1; } break; + case TLS_handshake_certificate_verify: + if (tls_certificate_verify_print(fp, data, datalen, format, indent) != 1) + { error_print(); return -1; } break; + case TLS_handshake_finished: + if (tls_finished_print(fp, data, datalen, format, indent) != 1) + { error_print(); return -1; } break; + default: + error_print(); + return -1; + } + return 1; +} + +int tls_alert_print(FILE *fp, const uint8_t *data, size_t datalen, int format, int indent) +{ + if (datalen != 2) { + error_print(); + return -1; + } + format_print(fp, format, indent, "Alert :\n"); + indent += 4; + format_print(fp, format, indent, "Level : %s (%d)\n", tls_alert_level_name(data[0]), data[0]); + format_print(fp, format, indent, "Reason : %s (%d)\n", tls_alert_description_text(data[1]), data[1]); + return 1; +} + +int tls_change_cipher_spec_print(FILE *fp, const uint8_t *data, size_t datalen, int format, int indent) +{ + if (datalen != 1) { + error_print(); + return -1; + } + format_print(fp, format, indent, "ChangeCipherSpec\n"); + indent += 4; + format_print(fp, format, indent, "type : %s (%d)\n", tls_change_cipher_spec_text(data[0]), data[0]); + return 1; +} + +int tls_application_data_print(FILE *fp, const uint8_t *data, size_t datalen, int format, int indent) +{ + format_bytes(fp, format, indent, "ApplicationData : ", data, datalen); + return 1; +} + +int tls_record_print(FILE *fp, const uint8_t *record, size_t recordlen, int format, int indent) +{ + const uint8_t *data; + size_t datalen; + int version; + + if (!fp || !record || recordlen < 5) { + error_print(); + return -1; + } + version = tls_record_version(record); + format_print(fp, format, indent, "Record\n"); indent += 4; + format_print(fp, format, indent, "ContentType : %s (%d)\n", tls_record_type_name(record[0]), record[0]); + format_print(fp, format, indent, "Version : %s (%d.%d)\n", tls_version_text(version), version >> 8, version & 0xff); + format_print(fp, format, indent, "Length : %d\n", tls_record_length(record)); + + data = record + 5; + datalen = recordlen - 5; + + switch (record[0]) { + case TLS_record_handshake: + if (tls_handshake_print(fp, data, datalen, format, indent) != 1) { + error_print(); + return -1; + } + break; + case TLS_record_alert: + if (tls_alert_print(fp, data, datalen, format, indent) != 1) { + error_print(); + return -1; + } + break; + case TLS_record_change_cipher_spec: + if (tls_change_cipher_spec_print(fp, data, datalen, format, indent) != 1) { + error_print(); + return -1; + } + break; + case TLS_record_application_data: + if (tls_application_data_print(fp, data, datalen, format, indent) != 1) { + error_print(); + return -1; + } + break; + default: + error_print(); + return -1; + } + fprintf(fp, "\n"); + return 1; +} + +int tls_secrets_print(FILE *fp, + const uint8_t *pre_master_secret, size_t pre_master_secret_len, + const uint8_t client_random[32], const uint8_t server_random[32], + const uint8_t master_secret[48], + const uint8_t *key_block, size_t key_block_len, + int format, int indent) +{ + format_bytes(stderr, format, indent, "pre_master_secret : ", pre_master_secret, pre_master_secret_len); + format_bytes(stderr, format, indent, "client_random : ", client_random, 32); + format_bytes(stderr, format, indent, "server_random : ", server_random, 32); + format_bytes(stderr, format, indent, "master_secret : ", master_secret, 48); + format_bytes(stderr, format, indent, "client_write_mac_key : ", key_block, 32); + format_bytes(stderr, format, indent, "server_write_mac_key : ", key_block + 32, 32); + format_bytes(stderr, format, indent, "client_write_enc_key : ", key_block + 64, 16); + format_bytes(stderr, format, indent, "server_write_enc_key : ", key_block + 80, 16); + format_print(stderr, format, indent, "\n"); + return 1; +} diff --git a/src/x509_algor.c b/src/x509_algor.c new file mode 100644 index 00000000..40fc580a --- /dev/null +++ b/src/x509_algor.c @@ -0,0 +1,361 @@ +/* + * Copyright (c) 2021 - 2021 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + +#include +#include +#include +#include +#include +#include + + +static const uint32_t DER_sm3[] = {1, 2, 156, 10197, 1, 401}; +static const uint32_t DER_md5[] = {1, 2, 840, 113549, 2, 5}; +static const uint32_t DER_sha1[] = {1, 3, 14, 3, 2, 26}; +static const uint32_t DER_sha256[] = {2, 16, 840, 1, 101, 3, 4, 2, 1}; +static const uint32_t DER_sha384[] = {2, 16, 840, 1, 101, 3, 4, 2, 2}; +static const uint32_t DER_sha512[] = {2, 16, 840, 1, 101, 3, 4, 2, 3}; +static const uint32_t DER_sha224[] = {2, 16, 840, 1, 101, 3, 4, 2, 4}; + +static struct { + int oid; + char *name; + const uint32_t *nodes; + size_t nodes_count; +} digest_table[] = { + { OID_sm3, "sm3", DER_sm3, sizeof(DER_sm3)/sizeof(int) }, + { OID_md5, "md5", DER_md5, sizeof(DER_md5)/sizeof(int) }, + { OID_sha1, "sha1", DER_sha1, sizeof(DER_sha1)/sizeof(int) }, + { OID_sha224, "sha224", DER_sha224, sizeof(DER_sha224)/sizeof(int) }, + { OID_sha256, "sha256", DER_sha256, sizeof(DER_sha256)/sizeof(int) }, + { OID_sha384, "sha384", DER_sha384, sizeof(DER_sha384)/sizeof(int) }, + { OID_sha512, "sha512", DER_sha512, sizeof(DER_sha512)/sizeof(int) }, +}; + +const char *x509_digest_algor_name(int oid) +{ + int i; + for (i = 0; i < sizeof(digest_table)/sizeof(digest_table[0]); i++) { + if (oid == digest_table[i].oid) { + return digest_table[i].name; + } + } + return NULL; +} + +int x509_digest_algor_to_der(int oid, uint8_t **out, size_t *outlen) +{ + size_t len; + + if (oid != OID_sm3) { + error_print(); + return -1; + } + if (asn1_object_identifier_to_der(oid, NULL, 0, NULL, &len) != 1 + || asn1_sequence_header_to_der(len, out, outlen) != 1 + || asn1_object_identifier_to_der(oid, NULL, 0, out, outlen) != 1) { + error_print(); + return -1; + } + return 1; +} + +int x509_digest_algor_from_der(int *oid, uint32_t *nodes, size_t *nodes_count, + const uint8_t **in, size_t *inlen) +{ + int ret; + const uint8_t *data; + size_t datalen; + + if ((ret = asn1_sequence_from_der(&data, &datalen, in, inlen)) != 1) { + if (ret < 0) error_print(); + return -1; + } + if (asn1_object_identifier_from_der(oid, nodes, nodes_count, &data, &datalen) != 1) { + error_print(); + return -1; + } + if (*oid != OID_undef && *oid != OID_sm3) { + error_print(); + return -1; + } + if (datalen) { + error_print(); + return -1; + } + return 1; +} + + +static uint32_t sm4_cbc_nodes[] = { 1, 2, 156, 10197, 1, 104, 2 }; +static size_t sm4_cbc_nodes_count = sizeof(sm4_cbc_nodes)/sizeof(sm4_cbc_nodes[0]); + + +int x509_encryption_algor_to_der(int cipher, const uint8_t *iv, size_t ivlen, + uint8_t **out, size_t *outlen) +{ + size_t len = 0; + + if (cipher != OID_sm4_cbc || ivlen != 16) { + error_print(); + return -1; + } + if (asn1_object_identifier_to_der(OID_undef, sm4_cbc_nodes, sm4_cbc_nodes_count, NULL, &len) != 1 + || asn1_octet_string_to_der(iv, ivlen, NULL, &len) != 1 + || asn1_sequence_header_to_der(len, out, outlen) != 1 + || asn1_object_identifier_to_der(OID_undef, sm4_cbc_nodes, sm4_cbc_nodes_count, out, outlen) != 1 + || asn1_octet_string_to_der(iv, ivlen, out, outlen) != 1) { + error_print(); + return -1; + } + return 1; +} + +int x509_encryption_algor_from_der(int *cipher, + const uint8_t **iv, size_t *ivlen, + const uint8_t **in, size_t *inlen) +{ + int ret; + const uint8_t *data; + size_t datalen; + uint32_t nodes[32]; + size_t nodes_count; + + if ((ret = asn1_sequence_from_der(&data, &datalen, in, inlen)) != 1) { + if (ret < 0) error_print(); + return ret; + } + if (asn1_object_identifier_from_der(cipher, nodes, &nodes_count, &data, &datalen) != 1 + || asn1_octet_string_from_der(iv, ivlen, &data, &datalen) != 1 + || datalen > 0) { + error_print(); + return -1; + } + if (*cipher == OID_undef) { + if (nodes_count == sm4_cbc_nodes_count + && memcmp(nodes, sm4_cbc_nodes, sizeof(sm4_cbc_nodes)) == 0) { + *cipher = OID_sm4_cbc; + } else { + size_t i; + error_print("unknown cipher oid :"); + for (i = 0; i < nodes_count; i++) { + fprintf(stderr, " %d", nodes[i]); + } + fprintf(stderr, "\n"); + return -1; + } + } + + // FIXME: 检查ivlen + return 1; +} + +int x509_signature_algor_to_der(int oid, uint8_t **out, size_t *outlen) +{ + size_t len = 0; + int has_null_obj = 0; + + switch (oid) { + // ECDSA/SM2 parameters MUST be omitted + //case OID_ecdsa_with_sha1: + //case OID_ecdsa_with_sha224 + //case OID_ecdsa_with_sha256: + //case OID_ecdsa_with_sha384: + //case OID_ecdsa_with_sha512: + case OID_sm2sign_with_sm3: + has_null_obj = 0; + break; + // RSA parameters MUST be ASN1_NULL + //case OID_sha1WithRSAEncryption: + //case OID_sha224WithRSAEncryption: + //case OID_sha256WithRSAEncryption: + //case OID_sha384WithRSAEncryption: + //case OID_sha512WithRSAEncryption: + case OID_rsasign_with_sm3: + has_null_obj = 1; + break; + default: + error_print(); + return -1; + } + + if (asn1_object_identifier_to_der(oid, NULL, 0, NULL, &len) != 1) { + error_print(); + return -1; + } + + if (has_null_obj) { + if (asn1_null_to_der(NULL, &len) != 1) { + error_print(); + return -1; + } + } + + if (asn1_sequence_header_to_der(len, out, outlen) != 1 + || asn1_object_identifier_to_der(oid, NULL, 0, out, outlen) != 1) { + error_print(); + return -1; + } + + if (has_null_obj) { + if (asn1_null_to_der(out, outlen) != 1) { + error_print(); + return -1; + } + } + + return 1; +} + +int x509_signature_algor_from_der(int *oid, const uint8_t **in, size_t *inlen) +{ + int ret; + const uint8_t *data; + size_t datalen; + uint32_t nodes[32]; + size_t nodes_count; + int has_null_obj; + + if ((ret = asn1_sequence_from_der(&data, &datalen, in, inlen)) != 1) { + return ret; + } + if (asn1_object_identifier_from_der(oid, nodes, &nodes_count, &data, &datalen) != 1) { + error_print(); + return -1; + } + if ((has_null_obj = asn1_null_from_der(&data, &datalen)) < 0) { + error_print(); + return -1; + } + if (datalen > 0) { + error_print("datalen = %zu", datalen); + error_print(); + return -1; + } + + switch (*oid) { + //case OID_ecdsa_with_sha1: + //case OID_ecdsa_with_sha224 + //case OID_ecdsa_with_sha256: + //case OID_ecdsa_with_sha384: + //case OID_ecdsa_with_sha512: + case OID_sm2sign_with_sm3: + if (has_null_obj) { + fprintf(stderr, "WARN: %s %d: AlgorithmIdentifier.parameters SHOULD be omitted for ECDSA/SM2\n", __FILE__, __LINE__); + } + break; + //case OID_sha1WithRSAEncryption: + //case OID_sha224WithRSAEncryption: + //case OID_sha256WithRSAEncryption: + //case OID_sha384WithRSAEncryption: + //case OID_sha512WithRSAEncryption: + case OID_rsasign_with_sm3: + if (!has_null_obj) { + fprintf(stderr, "WARN: %s %d\n: parameters SHOULD be NULL object for RSA", __FILE__, __LINE__); + } + break; + default: + // print unknown OID nodes + error_print(); + return -1; + } + + return 1; +} + + +const uint32_t DER_sm2encrypt[] = {1,2,156,10197,1,301,2}; + +int x509_public_key_encryption_algor_to_der(int algor, uint8_t **out, size_t *outlen) +{ + size_t len = 0; + + if (asn1_object_identifier_to_der(OID_undef, DER_sm2encrypt, + sizeof(DER_sm2encrypt)/sizeof(DER_sm2encrypt[0]), NULL, &len) != 1 + || asn1_sequence_header_to_der(len, out, outlen) != 1 + || asn1_object_identifier_to_der(OID_undef, DER_sm2encrypt, + sizeof(DER_sm2encrypt)/sizeof(DER_sm2encrypt[0]), out, outlen) != 1) { + error_print(); + return -1; + } + return 1; +} + +int x509_public_key_encryption_algor_from_der(int *algor, uint32_t *nodes, size_t *nodes_count, + const uint8_t *params, size_t *params_len, + const uint8_t **in, size_t *inlen) +{ + int ret; + const uint8_t *data; + size_t datalen; + + if ((ret = asn1_sequence_from_der(&data, &datalen, in, inlen)) != 1) { + if (ret < 0) error_print(); + return ret; + } + if (asn1_object_identifier_from_der(algor, nodes, nodes_count, &data, &datalen) != 1) { + error_print(); + return -1; + } + // FIXME: 我们需要一个读取完整obj的函数 + return 1; +} + + + + + + + + + + + + + + diff --git a/src/x509_asn1.c b/src/x509_asn1.c new file mode 100644 index 00000000..7f5d8328 --- /dev/null +++ b/src/x509_asn1.c @@ -0,0 +1,1377 @@ +/* + * Copyright (c) 2014 - 2020 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +const char *x509_version_name(int version) +{ + switch (version) { + case X509_version_v1: return "v1"; + case X509_version_v2: return "v2"; + case X509_version_v3: return "v3"; + default: return ""; + } +} + +int x509_version_to_der(int version, uint8_t **out, size_t *outlen) +{ + size_t len = 0; + switch (version) { + case X509_version_v1: + return 0; + case X509_version_v2: + case X509_version_v3: + break; + default: + error_print("invalid version"); + return -1; + } + if (asn1_int_to_der(version, NULL, &len) != 1 + || asn1_explicit_header_to_der(0, len, out, outlen) != 1 + || asn1_int_to_der(version, out, outlen) != 1) { + error_print(); + return -1; + } + return 1; +} + +int x509_version_from_der(int *version, const uint8_t **in, size_t *inlen) +{ + int ret; + const uint8_t *data; + size_t datalen; + + if ((ret = asn1_explicit_from_der(0, &data, &datalen, in, inlen)) < 0) { + error_print(); + return -1; + } else if (ret == 0) { + *version = X509_version_v1; + return 1; + } + + if (asn1_int_from_der(version, &data, &datalen) != 1 + || datalen > 0) { + error_print(); + return -1; + } + switch (*version) { + case X509_version_v1: + error_print("warning: version v1 should not be encoded"); + break; + case X509_version_v2: + case X509_version_v3: + break; + default: + error_print(); + return -1; + } + return 1; +} + + +/* + from RFC 5280 section 4.1.2.5 + + CAs conforming to this profile MUST always encode certificate + validity dates through the year 2049 as UTCTime; certificate validity + dates in 2050 or later MUST be encoded as GeneralizedTime. + Conforming applications MUST be able to process validity dates that + are encoded in either UTCTime or GeneralizedTime. + + To indicate that a certificate has no well-defined expiration date, + the notAfter SHOULD be assigned the GeneralizedTime value of + 99991231235959Z. +*/ + +int x509_validity_set_days(X509_VALIDITY *a, time_t not_before, int days) +{ + struct tm tm_val; + if (!a || not_before < 0 || days < 1 || days > 3650) { + return 0; + } + a->not_before = not_before; + gmtime_r(¬_before, &tm_val); + tm_val.tm_mday += days; + a->not_after = mktime(&tm_val); + + return 1; +} + +int x509_time_to_der(time_t a, uint8_t **out, size_t *outlen) +{ + int ret; + struct tm tm_val; + + gmtime_r(&a, &tm_val); + if (tm_val.tm_year < 2050 - 1900) { + ret = asn1_utc_time_to_der(a, out, outlen); + } else { + ret = asn1_generalized_time_to_der(a, out, outlen); + } + + if (ret != 1) { + error_print(); + } + return ret; +} + +int x509_time_from_der(time_t *a, const uint8_t **in, size_t *inlen) +{ + int ret; + if (!a || !in || !(*in) || !inlen) { + error_print(); + return -1; + } + if ((ret = asn1_utc_time_from_der(a, in, inlen)) == 0) { + ret = asn1_generalized_time_from_der(a, in, inlen); + } + return ret; +} + +int x509_validity_to_der(const X509_VALIDITY *a, uint8_t **out, size_t *outlen) +{ + size_t len = 0; + if (x509_time_to_der(a->not_before, NULL, &len) != 1 + || x509_time_to_der(a->not_after, NULL, &len) != 1 + || asn1_sequence_header_to_der(len, out, outlen) != 1 + || x509_time_to_der(a->not_before, out, outlen) != 1 + || x509_time_to_der(a->not_after, out, outlen) != 1) { + error_print(); + return -1; + } + return 1; +} + +int x509_validity_from_der(X509_VALIDITY *a, const uint8_t **in, size_t *inlen) +{ + int ret; + const uint8_t *data; + size_t datalen; + + if (!a || !in || !(*in) || !inlen) { + error_print(); + return -1; + } + + if ((ret = asn1_sequence_from_der(&data, &datalen, in, inlen)) != 1) { + if (ret < 0) error_print(); + return ret; + } + if (x509_time_from_der(&a->not_before, &data, &datalen) != 1 + || x509_time_from_der(&a->not_after, &data, &datalen) != 1 + || datalen > 0) { + error_print(); + return -1; + } + if (a->not_before >= a->not_after) { + error_print(); + return -1; + } + return 1; +} + +int x509_validity_print(FILE *fp, const X509_VALIDITY *validity, int format, int indent) +{ + format_print(fp, format, indent, "NotBefore : %s", ctime(&validity->not_before)); + format_print(fp, format, indent, "NotAfter : %s", ctime(&validity->not_after)); + return 1; +} + + + +int x509_directory_string_to_der(int tag, const char *a, size_t alen, uint8_t **out, size_t *outlen) +{ + int ret = 0; + + switch (tag) { + case ASN1_TAG_TeletexString: + case ASN1_TAG_PrintableString: + case ASN1_TAG_UniversalString: + case ASN1_TAG_UTF8String: + if (strlen(a) != alen) { + error_print(); + return -1; + } + } + + switch (tag) { + case ASN1_TAG_PrintableString: + ret = asn1_printable_string_to_der(a, out, outlen); + break; + case ASN1_TAG_UTF8String: + ret = asn1_utf8_string_to_der(a, out, outlen); + break; + case ASN1_TAG_TeletexString: + case ASN1_TAG_UniversalString: + case ASN1_TAG_BMPString: + error_print("not implemented"); + return -1; + default: + error_print("invalid tag"); + return -1; + } + + if (ret < 0) { + error_print(); + return -1; + } + return ret; +} + + +int x509_directory_string_from_der(int *tag, const char **a, size_t *alen, const uint8_t **in, size_t *inlen) +{ + int ret; + + if ((ret = asn1_any_type_from_der(tag, (const uint8_t **)a, alen, in, inlen)) != 1) { + if (ret < 0) error_print(); + return ret; + } + switch (*tag) { + case ASN1_TAG_PrintableString: + case ASN1_TAG_UTF8String: + case ASN1_TAG_TeletexString: + case ASN1_TAG_UniversalString: + // FIXME: check no zero in string + break; + case ASN1_TAG_BMPString: + break; + default: + error_print("DirectoryString tag = %d\n", *tag); + return -1; + } + return 1; +} + +static const struct { + int oid; + int is_printable_string_only; + int minlen; + int maxlen; +} x509_rdns[] = { + { OID_at_countryName, 1, 2, 2 }, + { OID_at_stateOrProvinceName, 0, 1, X509_ub_state_name }, + { OID_at_localityName, 0, 1, X509_ub_locality_name }, + { OID_at_organizationName, 0, 1, X509_ub_state_name }, + { OID_at_organizationalUnitName, 0, 1, X509_ub_organizational_unit_name }, + { OID_at_organizationName, 0, 1, X509_ub_organization_name }, + { OID_at_commonName, 0, 1, X509_ub_common_name }, + { OID_at_serialNumber, 1, 1, X509_ub_serial_number }, + { OID_at_dnQualifier, 1, 1, 64 }, // max length unspecified in RFC 5280 + { OID_at_title, 0, 1, X509_ub_title }, + { OID_at_surname, 0, 1, X509_ub_name }, + { OID_at_givenName, 0, 1, X509_ub_name }, + { OID_at_initials, 0, 1, X509_ub_name }, + { OID_at_generationQualifier, 0, 1, X509_ub_name }, + { OID_at_pseudonym, 0, 1, X509_ub_pseudonym }, +}; + +static int x509_rdn_check(int oid, int tag, const char *str, int len) +{ + int i; + for (i = 0; i < sizeof(x509_rdns)/sizeof(x509_rdns[0]); i++) { + if (oid == x509_rdns[i].oid) { + switch (tag) { + case ASN1_TAG_PrintableString: + case ASN1_TAG_UTF8String: + case ASN1_TAG_TeletexString: + case ASN1_TAG_UniversalString: + case ASN1_TAG_BMPString: + break; + default: + error_print("tag = %d\n", tag); + return -1; + } + if (x509_rdns[i].is_printable_string_only && tag != ASN1_TAG_PrintableString) { + error_print(); + return -1; + } + if (len < x509_rdns[i].minlen || len > x509_rdns[i].maxlen) { + error_print(); + return -1; + } + } + } + return 1; +} + + +int x509_name_add_rdn_ex(X509_NAME *a, int oid, int tag, const char *str, size_t len) +{ + int i; + + if (a->count >= 8) { + return -1; + } + for (i = 0; i < a->count; i++) { + if (oid == a->oids[i]) { + error_print(); + return -1; + } + } + + if (x509_rdn_check(oid, tag, str, len) != 1) { + error_print(); + return -1; + } + + switch (oid) { + case OID_at_countryName: + memcpy(a->country, str, len); + break; + case OID_at_stateOrProvinceName: + memcpy(a->state_or_province, str, len); + break; + case OID_at_localityName: + memcpy(a->locality, str, len); + break; + case OID_at_organizationName: + memcpy(a->org, str, len); + break; + case OID_at_organizationalUnitName: + memcpy(a->org_unit, str, len); + break; + case OID_at_commonName: + memcpy(a->common_name, str, len); + break; + case OID_at_serialNumber: + memcpy(a->serial_number, str, len); + break; + case OID_at_dnQualifier: + memcpy(a->dn_qualifier, str, len); + break; + default: + error_print(); + return -1; + } + + a->oids[a->count] = oid; + a->tags[a->count] = tag; + a->count++; + + return 1; +} + +// 这个函数可能是有问题的,因为RDN可能是bmp string,因此这里应该给一个长度 +int x509_rdn_to_der(int oid, int tag, const char *str, uint8_t **out, size_t *outlen) +{ + size_t len = 0, seqlen = 0; + + if (asn1_object_identifier_to_der(oid, NULL, 0, NULL, &len) != 1 + || x509_directory_string_to_der(tag, str, strlen(str), NULL, &len) != 1 + || asn1_sequence_header_to_der(len, NULL, &seqlen) != 1) { + error_print(); + return -1; + } + seqlen += len; + if (asn1_set_header_to_der(seqlen, out, outlen) != 1 + || asn1_sequence_header_to_der(len, out, outlen) != 1 + || asn1_object_identifier_to_der(oid, NULL, 0, out, outlen) != 1 + || x509_directory_string_to_der(tag, str, strlen(str), out, outlen) != 1) { + error_print(); + return -1; + } + return 1; +} + +int x509_rdn_from_der(int *oid, int *tag, const char **str, size_t *slen, const uint8_t **in, size_t *inlen) +{ + int ret; + const uint8_t *seq, *data; + size_t seqlen = 0, datalen = 0; + uint32_t nodes[32]; + size_t nodes_count; + + if ((ret = asn1_set_from_der(&seq, &seqlen, in, inlen)) != 1) { + error_print(); + return ret; + } + if (asn1_sequence_from_der(&data, &datalen, &seq, &seqlen) != 1 + || seqlen > 0) { + error_print(); + return -1; + } + + if (asn1_object_identifier_from_der(oid, nodes, &nodes_count, &data, &datalen) != 1) { + error_print(); + return -1; + } + if (x509_directory_string_from_der(tag, str, slen, &data, &datalen) != 1) { + error_print(); + return -1; + } + if (datalen > 0) { + error_print(); + return -1; + } + if (x509_rdn_check(*oid, *tag, *str, *slen) != 1) { + error_print(); + return -1; + } + return 1; +} + +int x509_name_from_der(X509_NAME *a, const uint8_t **in, size_t *inlen) +{ + int ret; + const uint8_t *data; + size_t datalen; + + memset(a, 0, sizeof(X509_NAME)); + if ((ret = asn1_sequence_from_der(&data, &datalen, in, inlen)) <= 0) { + error_print(); + return ret; + } + while (datalen) { + int oid, tag; + const char *str; + size_t len; + if (x509_rdn_from_der(&oid, &tag, &str, &len, &data, &datalen) != 1 + || x509_name_add_rdn_ex(a, oid, tag, str, len) != 1) { + error_print(); + return -1; + } + } + return 1; +} + +const char *x509_name_rdn(const X509_NAME *name, int oid) +{ + switch (oid) { + case OID_at_countryName: + return name->country; + case OID_at_stateOrProvinceName: + return name->state_or_province; + case OID_at_localityName: + return name->locality; + case OID_at_organizationName: + return name->org; + case OID_at_organizationalUnitName: + return name->org_unit; + case OID_at_commonName: + return name->common_name; + case OID_at_serialNumber: + return name->serial_number; + case OID_at_dnQualifier: + return name->dn_qualifier; + } + error_print("unsupported X509 NAME OID %d\n", oid); + return NULL; +} + +int x509_name_print(FILE *fp, const X509_NAME *name, int format, int indent) +{ + int i; + for (i = 0; i < name->count; i++) { + format_print(fp, format, indent, "%s : %s\n", + asn1_object_identifier_name(name->oids[i]), + //asn1_tag_name(name->tags[i]), + x509_name_rdn(name, name->oids[i])); + } + return 1; +} + +int x509_name_equ(const X509_NAME *a, const X509_NAME *b) +{ + uint8_t abuf[256]; + uint8_t bbuf[256]; + uint8_t *ap = abuf; + uint8_t *bp = bbuf; + size_t alen = 0, blen = 0; + + x509_name_to_der(a, &ap, &alen); + x509_name_to_der(b, &bp, &blen); + if (alen == blen && memcmp(abuf, bbuf, alen) == 0) { + return 1; + } else return 0; +} + +int x509_name_to_der(const X509_NAME *a, uint8_t **out, size_t *outlen) +{ + size_t len = 0; + int oid, tag, i; + + // 在前面的循环中把输出字符串的指针做赋值,这样不需要重复这个循环 + + for (i = 0; i < a->count; i++) { + oid = a->oids[i]; + tag = a->tags[i]; + + switch (oid) { + case OID_at_countryName: + x509_rdn_to_der(oid, tag, a->country, NULL, &len); + break; + case OID_at_stateOrProvinceName: + x509_rdn_to_der(oid, tag, a->state_or_province, NULL, &len); + break; + case OID_at_localityName: + x509_rdn_to_der(oid, tag, a->locality, NULL, &len); + break; + case OID_at_organizationName: + x509_rdn_to_der(oid, tag, a->org, NULL, &len); + break; + case OID_at_organizationalUnitName: + x509_rdn_to_der(oid, tag, a->org_unit, NULL, &len); + break; + case OID_at_commonName: + x509_rdn_to_der(oid, tag, a->common_name, NULL, &len); + break; + case OID_at_serialNumber: + x509_rdn_to_der(oid, tag, a->serial_number, NULL, &len); + break; + case OID_at_dnQualifier: + x509_rdn_to_der(oid, tag, a->dn_qualifier, NULL, &len); + break; + default: + error_print(); + return -1; + } + } + asn1_sequence_header_to_der(len, out, outlen); + for (i = 0; i < a->count; i++) { + oid = a->oids[i]; + tag = a->tags[i]; + + switch (oid) { + case OID_at_countryName: + x509_rdn_to_der(oid, tag, a->country, out, outlen); + break; + case OID_at_stateOrProvinceName: + x509_rdn_to_der(oid, tag, a->state_or_province, out, outlen); + break; + case OID_at_localityName: + x509_rdn_to_der(oid, tag, a->locality, out, outlen); + break; + case OID_at_organizationName: + x509_rdn_to_der(oid, tag, a->org, out, outlen); + break; + case OID_at_organizationalUnitName: + x509_rdn_to_der(oid, tag, a->org_unit, out, outlen); + break; + case OID_at_commonName: + x509_rdn_to_der(oid, tag, a->common_name, out, outlen); + break; + case OID_at_serialNumber: + x509_rdn_to_der(oid, tag, a->serial_number, out, outlen); + break; + case OID_at_dnQualifier: + x509_rdn_to_der(oid, tag, a->dn_qualifier, out, outlen); + break; + default: + error_print(); + return -1; + } + } + return 1; +} + +int x509_public_key_info_set_sm2(X509_PUBLIC_KEY_INFO *a, const SM2_KEY *sm2_key) +{ + if (!a || !sm2_key) { + error_print(); + return -1; + } + memset(a, 0, sizeof(X509_PUBLIC_KEY_INFO)); + a->algor_oid = OID_x9_62_ecPublicKey; + a->curve_oid = OID_sm2; + sm2_set_public_key(&a->sm2_key, (uint8_t *)&sm2_key->public_key); + return 1; +} + +int x509_public_key_info_to_der(const X509_PUBLIC_KEY_INFO *a, uint8_t **out, size_t *outlen) +{ + if (sm2_public_key_info_to_der(&a->sm2_key, out, outlen) != 1) { + error_print(); + return -1; + } + return 1; +} + +int x509_public_key_info_from_der(X509_PUBLIC_KEY_INFO *a, const uint8_t **in, size_t *inlen) +{ + int ret; + if ((ret = sm2_public_key_info_from_der(&a->sm2_key, in, inlen)) != 1) { + if (ret < 0) error_print(); + return ret; + } + a->algor_oid = OID_x9_62_ecPublicKey; + a->curve_oid = OID_sm2; + return 1; +} + +int x509_public_key_info_print(FILE *fp, const X509_PUBLIC_KEY_INFO *a, int format, int indent) +{ + format_print(fp, format, indent, "Algorithm : %s\n", asn1_object_identifier_name(a->algor_oid)); + format_print(fp, format, indent, "Parameters : %s\n", asn1_object_identifier_name(a->curve_oid)); + format_print(fp, format, indent, "PublicKey\n"); + sm2_point_print(fp, &a->sm2_key.public_key, format, indent + 4); + return 1; +} + + +// X.509 扩展的OID实际上在OID模块中并没有,我们应该在这个模块中独立给出 + + + +// DER_id_ce[] = 0x55,0x1D, + +static const uint8_t DER_x509_ce[] = { 0x55, 0x1d }; + + +static const struct { + int der; + int oid; + char *name; +} ce_oids[] = { + { 35, OID_ce_authorityKeyIdentifier, "AuthorityKeyIdentifier" }, + { 14, OID_ce_subjectKeyIdentifier, "SubjectKeyIdentifier" }, + { 15, OID_ce_keyUsage, "KeyUsage" }, + { 32, OID_ce_certificatePolicies, "CertificatePolicies" }, + { 33, OID_ce_policyMappings, "PolicyMappings" }, + { 17, OID_ce_subjectAltName, "SubjectAltName" }, + { 18, OID_ce_issuerAltName, "IssuerAltName" }, + { 9, OID_ce_subjectDirectoryAttributes, "SubjectDirectoryAttributes" }, + { 19, OID_ce_basicConstraints, "BasicConstraints" }, + { 30, OID_ce_nameConstraints, "NameConstraints" }, + { 36, OID_ce_policyConstraints, "PolicyConstraints" }, + { 37, OID_ce_extKeyUsage, "ExtKeyUsage" }, + { 31, OID_ce_crlDistributionPoints, "CRLDistributionPoints" }, + { 54, OID_ce_inhibitAnyPolicy, "InhibitAnyPolicy" }, + { 46, OID_ce_freshestCRL, "FreshestCRL" }, +}; + +const char *x509_extension_oid_name(int oid) +{ + int i; + for (i = 0; i < sizeof(ce_oids)/sizeof(ce_oids[0]); i++) { + if (oid == ce_oids[i].oid) { + return ce_oids[i].name; + } + } + return NULL; +} + +int x509_extension_oid_to_der(int oid, uint8_t **out, size_t *outlen) +{ + uint8_t octets[3] = { 0x55, 0x1d, 0 }; + int i; + + for (i = 0; i < sizeof(ce_oids)/sizeof(ce_oids[0]); i++) { + if (oid == ce_oids[i].oid) { + octets[2] = ce_oids[i].der; + } + } + if (octets[2] == 0) { + return -1; + } + asn1_tag_to_der(ASN1_TAG_OBJECT_IDENTIFIER, out, outlen); + asn1_length_to_der(sizeof(octets), out, outlen); + asn1_data_to_der(octets, sizeof(octets), out, outlen); + return 1; +} + +/* +应该首先对OID进行基本的解析,判断正确性,并获得nodes用于显示 +然后可以根据应用场景对octets进行解析,以获得name +*/ +int x509_extension_oid_from_der(int *oid, uint32_t *nodes, size_t *nodes_count, const uint8_t **pin, size_t *pinlen) +{ + int ret; + size_t len; + const uint8_t *octets; + int i; + const uint8_t *in = *pin; + size_t inlen = *pinlen; + + if ((ret = asn1_object_identifier_from_der(oid, nodes, nodes_count, pin, pinlen)) != 1) { + if (ret < 0) error_print(); + return ret; + } + if ((ret = asn1_tag_from_der(ASN1_TAG_OBJECT_IDENTIFIER, &in, &inlen)) != 1) { + if (ret < 0) error_print(); + return ret; + } + if (asn1_length_from_der(&len, &in, &inlen) != 1 + || asn1_data_from_der(&octets, len, &in, &inlen) != 1) { + error_print(); + return -1; + } + if (len == 3 && octets[0] == 0x55 && octets[1] == 0x1d) { + for (i = 0; i < sizeof(ce_oids)/sizeof(ce_oids[0]); i++) { + if (octets[2] == ce_oids[i].der) { + *oid = ce_oids[i].oid; + return 1; + } + } + } + return ret; +} + +// out != NULL 时,data 不可以为 NULL +int x509_extension_to_der(int oid, int is_critical, const uint8_t *data, size_t datalen, + uint8_t **out, size_t *outlen) +{ + size_t len = 0; + if (x509_extension_oid_to_der(oid, NULL, &len) != 1 + || (is_critical >= 0 && asn1_boolean_to_der(is_critical, NULL, &len) != 1) + || asn1_octet_string_to_der(data, datalen, NULL, &len) != 1 + || asn1_sequence_header_to_der(len, out, outlen) != 1 + || x509_extension_oid_to_der(oid, out, outlen) != 1 + || (is_critical >= 0 && asn1_boolean_to_der(is_critical, out, outlen) != 1) + || asn1_octet_string_to_der(data, datalen, out, outlen) != 1) { + error_print(); + return -1; + } + return 1; +} + +int x509_extension_from_der(int *oid, uint32_t *nodes, size_t *nodes_count, + int *is_critical, const uint8_t **data, size_t *datalen, + const uint8_t **in, size_t *inlen) +{ + int ret; + const uint8_t *seq; + size_t seqlen; + + if ((ret = asn1_sequence_from_der(&seq, &seqlen, in, inlen)) != 1) { + return ret; + } + + *is_critical = ASN1_FALSE; + if (x509_extension_oid_from_der(oid, nodes, nodes_count, &seq, &seqlen) != 1 // FIXME: 这里检查OID应该是从一个子集里面检索 + || asn1_boolean_from_der(is_critical, &seq, &seqlen) < 0 + || asn1_octet_string_from_der(data, datalen, &seq, &seqlen) != 1 + || seqlen > 0) { + error_print(); + return -1; + } + if (*datalen <= 0) { + error_print(); + return -1; + } + return 1; +} + +int x509_extension_print(FILE *fp, int oid, const uint32_t *nodes, size_t nodes_count, + int is_critical, const uint8_t *data, size_t datalen, + int format, int indent) +{ + const char *ext_name = x509_extension_oid_name(oid); + if (!ext_name) { + ext_name = "Unknown Extension"; + } + format_print(fp, format, indent, "%s (", ext_name); + while (nodes_count-- > 1) { + fprintf(fp, "%d.", *nodes++); + } + fprintf(fp, "%d)\n", *nodes); + indent += 4; + + if (is_critical >= 0) { + format_print(fp, format, indent, "crtical: %s\n", is_critical ? "true" : "false"); + } + + switch (oid) { + case OID_ce_authorityKeyIdentifier: return x509_authority_key_identifier_print(fp, data, datalen, format, indent); + case OID_ce_basicConstraints: return x509_basic_constraints_print(fp, data, datalen, format, indent); + case OID_ce_keyUsage: return x509_key_usage_print(fp, data, datalen, format, indent); + case OID_ce_subjectKeyIdentifier: return x509_subject_key_identifier_print(fp, data, datalen, format, indent); + default: + format_bytes(fp, format, indent, "extnValue : ", data, datalen); + } + return 1; +} + +int x509_extensions_print(FILE *fp, const X509_EXTENSIONS *a, int format, int indent) +{ + int ret; + int oid; + uint32_t nodes[32]; + size_t nodes_count; + int is_critical; + const uint8_t *data; + size_t datalen; + const uint8_t *next = a->data; + + format_print(fp, format, indent, "Extensions\n"); indent += 4; + for (;;) { + if ((ret = x509_extensions_get_next_item(a, &next, + &oid, nodes, &nodes_count, &is_critical, &data, &datalen)) != 1) { + if (ret < 0) error_print(); + return ret; + } + x509_extension_print(fp, oid, nodes, nodes_count, is_critical, data, datalen, format, indent); + } + return 1; +} + +int x509_extensions_to_der(const X509_EXTENSIONS *a, uint8_t **out, size_t *outlen) +{ + size_t len = 0; + asn1_sequence_to_der(a->data, a->datalen, NULL, &len); + asn1_explicit_header_to_der(3, len, out, outlen); + asn1_sequence_to_der(a->data, a->datalen, out, outlen); + return 1; +} + +int x509_extensions_from_der(X509_EXTENSIONS *a, const uint8_t **in, size_t *inlen) +{ + int ret; + const uint8_t *data; + size_t datalen; + + if ((ret = asn1_explicit_from_der(3, &data, &datalen, in, inlen)) != 1) { + if (ret < 0) error_print(); + return ret; + } + if (asn1_sequence_copy_from_der(512, a->data, &a->datalen, &data, &datalen) != 1 + || datalen > 0) { + error_print(); + return -1; + } + // FIXME:检查extensions的格式是否正确 + return 1; +} + +int x509_extensions_add_item(X509_EXTENSIONS *a, + int oid, int is_critical, const uint8_t *data, size_t datalen) +{ + uint8_t *p = a->data + a->datalen; + size_t len = 0; + if (x509_extension_to_der(oid, is_critical, data, datalen, &p, &len) != 1) { + error_print(); + return -1; + } + a->datalen += len; + return 1; +} + +int x509_extensions_get_next_item(const X509_EXTENSIONS *a, const uint8_t **next, + int *oid, uint32_t *nodes, size_t *nodes_count, + int *is_critical, const uint8_t **data, size_t *datalen) +{ + int ret; + size_t len = a->datalen; // FIXME: len赋值不对 + if ((ret = x509_extension_from_der(oid, nodes, nodes_count, is_critical, data, datalen, next, &len)) != 1) { + if (ret < 0) error_print(); + return ret; + } + return 1; +} + +int x509_certificate_add_extension(X509_CERTIFICATE *a, int oid, int is_critical, + const uint8_t *data, size_t datalen) +{ + if (x509_extensions_add_item(&a->tbs_certificate.extensions, oid, is_critical, data, datalen) != 1) { + error_print(); + return -1; + } + return 1; +} + +int x509_certificate_get_extension_from_oid(const X509_CERTIFICATE *a, int oid, + int *is_critical, const uint8_t **data, size_t *datalen) +{ + int ret; + const X509_EXTENSIONS *ext; + const uint8_t *next = NULL; + int rid; + uint32_t nodes[16]; + size_t nodes_count; + + for (;;) { + if ((ret = x509_extensions_get_next_item(&a->tbs_certificate.extensions, &next, + &rid, nodes, &nodes_count, is_critical, data, datalen)) != 1) { + if (ret < 0) error_print(); + return ret; + } + if (rid == oid) { + return 1; + } + } + return 0; +} + +// 这里用来打印的到底是解析后的内容,还是解析之前的DER呢? +// 而且这个打印函数应该能够支持所有类型的打印 + +int x509_tbs_certificate_to_der(const X509_TBS_CERTIFICATE *a, uint8_t **out, size_t *outlen) +{ + size_t len = 0; + + if (x509_version_to_der(a->version, NULL, &len) != 1 + || asn1_integer_to_der(a->serial_number, a->serial_number_len, NULL, &len) != 1 + || x509_signature_algor_to_der(a->signature_algor, NULL, &len) != 1 + || x509_name_to_der(&a->issuer, NULL, &len) != 1 + || x509_validity_to_der(&a->validity, NULL, &len) != 1 + || x509_name_to_der(&a->subject, NULL, &len) != 1 + || x509_public_key_info_to_der(&a->subject_public_key_info, NULL, &len) != 1 + || asn1_implicit_bit_string_to_der(1, a->issuer_unique_id, a->issuer_unique_id_len * 8, NULL, &len) < 0 + || asn1_implicit_bit_string_to_der(2, a->subject_unique_id, a->subject_unique_id_len * 8, NULL, &len) <0 + || x509_extensions_to_der(&a->extensions, NULL, &len) < 0) { + error_print(); + return -1; + } + if (asn1_sequence_header_to_der(len, out, outlen) != 1 + || x509_version_to_der(a->version, out, outlen) != 1 + || asn1_integer_to_der(a->serial_number, a->serial_number_len, out, outlen) != 1 + || x509_signature_algor_to_der(a->signature_algor, out, outlen) != 1 + || x509_name_to_der(&a->issuer, out, outlen) != 1 + || x509_validity_to_der(&a->validity, out, outlen) != 1 + || x509_name_to_der(&a->subject, out, outlen) != 1 + || x509_public_key_info_to_der(&a->subject_public_key_info, out, outlen) != 1 + || asn1_implicit_bit_string_to_der(1, a->issuer_unique_id, a->issuer_unique_id_len * 8, out, outlen) < 0 + || asn1_implicit_bit_string_to_der(2, a->subject_unique_id, a->subject_unique_id_len * 8, out, outlen) < 0 + || x509_extensions_to_der(&a->extensions, out, outlen) < 0) { + error_print(); + return -1; + } + + return 1; +} + +int x509_tbs_certificate_from_der(X509_TBS_CERTIFICATE *a, const uint8_t **in, size_t *inlen) +{ + int is_ver, is_ext; + const uint8_t *ver, *exts; + size_t verlen, extslen; + + int ret; + const uint8_t *data; + size_t datalen; + const uint8_t *serial_number; + const uint8_t *issuer_unique_id = NULL; + const uint8_t *subject_unique_id = NULL; + + if ((ret = asn1_sequence_from_der(&data, &datalen, in, inlen)) != 1) { + if (ret < 0) error_print(); + return ret; + } + if (x509_version_from_der(&a->version, &data, &datalen) != 1 + || asn1_integer_from_der(&serial_number, &a->serial_number_len, &data, &datalen) != 1 + || x509_signature_algor_from_der(&a->signature_algor, &data, &datalen) != 1 + || x509_name_from_der(&a->issuer, &data, &datalen) != 1 + || x509_validity_from_der(&a->validity, &data, &datalen) != 1 + || x509_name_from_der(&a->subject, &data, &datalen) != 1 + || x509_public_key_info_from_der(&a->subject_public_key_info, &data, &datalen) != 1 + || asn1_implicit_bit_string_from_der(1, &issuer_unique_id, &a->issuer_unique_id_len, &data, &datalen) < 0 + || asn1_implicit_bit_string_from_der(2, &subject_unique_id, &a->subject_unique_id_len, &data, &datalen) < 0 + || (is_ext = x509_extensions_from_der(&a->extensions, &data, &datalen)) < 0 + || datalen > 0) { + error_print(); + if (datalen > 0) error_print("datalen = %zu\n", datalen); + return -1; + } + + if (a->serial_number_len > 20 + || a->issuer_unique_id_len > 64 + || a->subject_unique_id_len > 64) { + error_print(); + return -1; + } + // FIXME: 这几个都应该用copy的方式 + memcpy(a->serial_number, serial_number, a->serial_number_len); + if (issuer_unique_id) { + memcpy(a->issuer_unique_id, issuer_unique_id, a->issuer_unique_id_len); + } + if (subject_unique_id) { + memcpy(a->subject_unique_id, subject_unique_id, a->subject_unique_id_len); + } + + return 1; +} + +int x509_certificate_to_der(const X509_CERTIFICATE *a, uint8_t **out, size_t *outlen) +{ + size_t len = 0; + if (x509_tbs_certificate_to_der(&a->tbs_certificate, NULL, &len) != 1 + || x509_signature_algor_to_der(a->signature_algor, NULL, &len) != 1 + || asn1_bit_string_to_der(a->signature, a->signature_len * 8, NULL, &len) != 1 + || asn1_sequence_header_to_der(len, out, outlen) != 1 + || x509_tbs_certificate_to_der(&a->tbs_certificate, out, outlen) != 1 + || x509_signature_algor_to_der(a->signature_algor, out, outlen) != 1 + || asn1_bit_string_to_der(a->signature, a->signature_len * 8, out, outlen) != 1) { + error_print(); + return -1; + } + return 1; +} + +int x509_certificate_to_pem(const X509_CERTIFICATE *a, FILE *fp) +{ + uint8_t buf[1024]; + uint8_t *p = buf; + size_t len = 0; + + if (x509_certificate_to_der(a, &p, &len) != 1) { + error_print(); + return -1; + } + if (pem_write(fp, "CERTIFICATE", buf, len) <= 0) { + error_print(); + return -1; + } + return 1; +} + +int x509_certificate_from_der(X509_CERTIFICATE *a, const uint8_t **in, size_t *inlen) +{ + int ret; + const uint8_t *data; + size_t datalen; + const uint8_t *sig; + size_t sig_nbits; + + if ((ret = asn1_sequence_from_der(&data, &datalen, in, inlen)) != 1) { + if (ret < 0) error_print(); + return ret; + } + memset(a, 0, sizeof(X509_CERTIFICATE)); + if (x509_tbs_certificate_from_der(&a->tbs_certificate, &data, &datalen) != 1 + || x509_signature_algor_from_der(&a->signature_algor, &data, &datalen) != 1 + || asn1_bit_string_from_der(&sig, &sig_nbits, &data, &datalen) != 1 + || datalen > 0) { + error_print(); + return -1; + } + a->signature_len = (sig_nbits + 7)/8; + memcpy(a->signature, sig, a->signature_len); + return 1; +} + +int x509_certificate_from_pem(X509_CERTIFICATE *a, FILE *fp) +{ + int ret; + uint8_t buf[1024]; + const uint8_t *cp = buf; + size_t len; + + if ((ret = pem_read(fp, "CERTIFICATE", buf, &len)) != 1) { + if (ret < 0) error_print(); + return ret; + } + if (x509_certificate_from_der(a, &cp, &len) != 1 + || len > 0) { + error_print(); + return -1; + } + return 1; +} + +int x509_certificate_print(FILE *fp, const X509_CERTIFICATE *a, int format, int indent) +{ + const X509_TBS_CERTIFICATE *tbs = &a->tbs_certificate; + size_t i; + + format_print(fp, format, indent, "Certificate\n"); + indent += 4; + format_print(fp, format, indent, "Version : %s (%d)\n", x509_version_name(tbs->version), tbs->version); + format_bytes(fp, format, indent, "SerialNumber : ", tbs->serial_number, tbs->serial_number_len); + format_print(fp, format, indent, "SigantureAlgorithm : %s\n", asn1_object_identifier_name(tbs->signature_algor)); + format_print(fp, format, indent, "Issuer\n"); + x509_name_print(fp, &tbs->issuer, format, indent + 4); + format_print(fp, format, indent, "Validity\n"); + x509_validity_print(fp, &tbs->validity, format, indent + 4); + format_print(fp, format, indent, "Subject\n"); + x509_name_print(fp, &tbs->subject, format, indent + 4); + format_print(fp, format, indent, "SubjectPublicKeyInfo\n"); + x509_public_key_info_print(fp, &tbs->subject_public_key_info, format, indent + 4); + format_print(fp, format, indent, "SigantureAlgorithm : %s\n", asn1_object_identifier_name(a->signature_algor)); + format_bytes(fp, format, indent, "Signature : ", a->signature, a->signature_len); + x509_extensions_print(fp, &a->tbs_certificate.extensions, format, indent); + return 1; +} + +int x509_signature_to_der(const uint8_t *a, size_t alen, uint8_t **out, size_t *outlen) +{ + if (asn1_bit_string_to_der(a, alen * 8, out, outlen) != 1) { + error_print(); + return -1; + } + return 1; +} + +int x509_signature_copy_from_der(size_t maxlen, uint8_t *a, size_t *alen, const uint8_t **in, size_t *inlen) +{ + int ret; + const uint8_t *bits; + size_t nbits; + + if ((ret = asn1_bit_string_from_der(&bits, &nbits, in, inlen)) != 1) { + if (ret < 0) error_print(); + return ret; + } + if (nbits % 8 != 0) { + error_print(); + return -1; + } + *alen = nbits / 8; + if (*alen > maxlen) { + error_print(); + return -1; + } + memcpy(a, bits, *alen); + return 1; +} + + + +/* +from RFC 2986 + +CertificationRequest ::= SEQUENCE { + certificationRequestInfo CertificationRequestInfo, + signatureAlgorithm AlgorithmIdentifier, + signature BIT STRING +} + +CertificationRequestInfo ::= SEQUENCE { + version INTEGER { v1(0) }, + subject Name, + subjectPKInfo SubjectPublicKeyInfo, + attributes [0] IMPLICIT SET OF Attribute +} +*/ + +int x509_cert_request_set_sm2(X509_CERT_REQUEST *a, const X509_NAME *subject, const SM2_KEY *sm2_key) +{ + memset(a, 0, sizeof(*a)); + a->req_info.version = X509_version_v1; + a->req_info.subject = *subject; + if (x509_public_key_info_set_sm2(&a->req_info.subject_public_key_info, sm2_key) != 1) { + error_print(); + return -1; + } + return 1; +} + +int x509_cert_request_info_to_der(const X509_CERT_REQUEST_INFO *a, uint8_t **out, size_t *outlen) +{ + size_t len = 0; + if (asn1_int_to_der(a->version, NULL, &len) != 1 + || x509_name_to_der(&a->subject, NULL, &len) != 1 + || x509_public_key_info_to_der(&a->subject_public_key_info, NULL, &len) != 1 + || asn1_sequence_header_to_der(len, out, outlen) != 1 + || asn1_int_to_der(a->version, out, outlen) != 1 + || x509_name_to_der(&a->subject, out, outlen) != 1 + || x509_public_key_info_to_der(&a->subject_public_key_info, out, outlen) != 1) { + error_print(); + return -1; + } + return 1; +} + +int x509_cert_request_info_from_der(X509_CERT_REQUEST_INFO *a, const uint8_t **in, size_t *inlen) +{ + int ret; + const uint8_t *data; + size_t datalen; + const uint8_t *attrs; + size_t attrslen; + + if ((ret = asn1_sequence_from_der(&data, &datalen, in, inlen)) != 1) { + if (ret < 0) error_print(); + return ret; + } + if (asn1_int_from_der(&a->version, &data, &datalen) != 1 + || x509_name_from_der(&a->subject, &data, &datalen) != 1 + || x509_public_key_info_from_der(&a->subject_public_key_info, &data, &datalen) != 1 + || asn1_implicit_from_der(0, &attrs, &attrslen, &data, &datalen) < 0 + || datalen > 0) { + error_print(); + return -1; + } + return 1; +} + +int x509_cert_request_to_der(const X509_CERT_REQUEST *a, uint8_t **out, size_t *outlen) +{ + size_t len = 0; + if (x509_cert_request_info_to_der(&a->req_info, NULL, &len) != 1 + || x509_signature_algor_to_der(a->signature_algor, NULL, &len) != 1 + || x509_signature_to_der(a->signature, a->signature_len, NULL, &len) != 1 + || asn1_sequence_header_to_der(len, out, outlen) != 1 + || x509_cert_request_info_to_der(&a->req_info, out, outlen) != 1 + || x509_signature_algor_to_der(a->signature_algor, out, outlen) != 1 + || x509_signature_to_der(a->signature, a->signature_len, out, outlen) != 1) { + error_print(); + return -1; + } + return 1; +} + +int x509_cert_request_from_der(X509_CERT_REQUEST *a, const uint8_t **in, size_t *inlen) +{ + int ret; + const uint8_t *data; + size_t datalen; + const uint8_t *sig; + size_t siglen; + + if ((ret = asn1_sequence_from_der(&data, &datalen, in, inlen)) != 1) { + if (ret < 0) error_print(); + return ret; + } + if (x509_cert_request_info_from_der(&a->req_info, &data, &datalen) != 1 + || x509_signature_algor_from_der(&a->signature_algor, &data, &datalen) != 1 + || x509_signature_copy_from_der(128, a->signature, &a->signature_len, &data, &datalen) != 1 + || datalen > 0) { + error_print(); + return -1; + } + a->signature_len = siglen * 8; + memcpy(a->signature, sig, a->signature_len); + return 1; +} + +int x509_cert_request_to_pem(const X509_CERT_REQUEST *a, FILE *fp) +{ + uint8_t buf[512]; + uint8_t *p = buf; + size_t len = 0; + + if (x509_cert_request_to_der(a, &p, &len) != 1) { + error_print(); + return -1; + } + if (pem_write(fp, "CERTIFICATE REQUEST", buf, len) <= 0) { + error_print(); + return -1; + } + return 1; +} + +int x509_cert_request_from_pem(X509_CERT_REQUEST *a, FILE *fp) +{ + uint8_t buf[512]; + const uint8_t *cp = buf; + size_t len; + + if (pem_read(fp, "CERTIFICATE REQUEST", buf, &len) != 1) { + error_print(); + return -1; + } + if (x509_cert_request_from_der(a, &cp, &len) != 1 + || len > 0) { + error_print(); + return -1; + } + return 1; +} + +int x509_cert_request_print(FILE *fp, const X509_CERT_REQUEST *a, int format, int indent) +{ + size_t i; + fprintf(fp, "version = %s\n", x509_version_name(a->req_info.version)); + x509_name_print(fp, &a->req_info.subject, 0, 0); + x509_public_key_info_print(fp, &a->req_info.subject_public_key_info, 0, 0); + fprintf(fp, "SignatureAlgorithm = %s\n", asn1_object_identifier_name(a->signature_algor)); + fprintf(fp, "Signature = "); + for (i = 0; i < a->signature_len; i++) { + fprintf(fp, "%02x", a->signature[i]); + } + fprintf(fp, "\n"); + return 1; +} + +int x509_cert_request_sign_sm2(X509_CERT_REQUEST *a, const SM2_KEY *sm2_key) +{ + SM2_SIGN_CTX ctx; + uint8_t tbs[1024]; + uint8_t *p = tbs; + size_t tbslen = 0; + + a->signature_algor = OID_sm2sign_with_sm3; + if (x509_cert_request_info_to_der(&a->req_info, &p, &tbslen) != 1) { + error_print(); + return -1; + } + if (sm2_sign_init(&ctx, sm2_key, SM2_DEFAULT_ID) != 1 + || sm2_sign_update(&ctx, tbs, tbslen) != 1 + || sm2_sign_finish(&ctx, a->signature, &a->signature_len) != 1) { + error_print(); + return -1; + } + return 1; +} + +int x509_cert_request_verify(const X509_CERT_REQUEST *a) +{ + int ret; + const SM2_KEY *sm2_key; + SM2_SIGN_CTX ctx; + uint8_t tbs[1024]; + uint8_t *p = tbs; + size_t tbslen = 0; + + if (x509_cert_request_info_to_der(&a->req_info, &p, &tbslen) != 1) { + error_print(); + return -1; + } + + sm2_key = &a->req_info.subject_public_key_info.sm2_key; + + if (sm2_verify_init(&ctx, sm2_key, SM2_DEFAULT_ID) != 1 + || sm2_verify_update(&ctx, tbs, tbslen) != 1 + || (ret = sm2_verify_finish(&ctx, a->signature, a->signature_len)) < 0) { + error_print(); + return -1; + } + return ret; +} diff --git a/src/x509_crl.c b/src/x509_crl.c new file mode 100644 index 00000000..7df0902f --- /dev/null +++ b/src/x509_crl.c @@ -0,0 +1,463 @@ +/* + * Copyright (c) 2021 - 2021 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + +#include +#include +#include +#include + + +const char *crl_reason_text(int reason) +{ + switch (reason) { + case X509_cr_unspecified: return "unspecified"; + case X509_cr_key_compromise: return "keyCompromise"; + case X509_cr_ca_compromise: return "cACompromise"; + case X509_cr_affiliation_changed: return "affiliationChanged"; + case X509_cr_superseded: return "superseded"; + case X509_cr_cessation_of_operation: return "cessationOfOperation"; + case X509_cr_certificate_hold: return "certificateHold"; + case X509_cr_remove_from_crl: return "removeFromCRL"; + case X509_cr_privilege_withdrawn: return "privilegeWithdrawn"; + case X509_cr_aa_compromise: return "aACompromise"; + } + return NULL; +} + + 84 typedef struct { + 85 uint8_t serial_number[20]; + 86 size_t serial_number_len; + 87 time_t revoke_date; + 88 CRL_EXTENSIONS crlEntryExtensions; + 89 } CRL_REVOKED_CERT; + + +int crl_revoked_cert_to_der(const CRL_REVOKED_CERT *a, uint8_t **out, size_t *outlen) +{ + size_t len = 0; + if (asn1_integer_to_der(a->serial_number, a->serial_number_len, NULL, &len) != 1 + || x509_time_to_der(a->revoke_date, NULL, &len) != 1 + || x509_extension_to_der(a->exts, NULL, &len) != 1 + || asn1_sequence_header_to_der(len, out, outlen) != 1 + || asn1_integer_to_der(a->serial_number, a->serial_number_len, out, outlen) != 1 + || x509_time_to_der(a->revoke_date, out, outlen) != 1 + || x509_extension_to_der(a->exts, out, outlen) != 1) { + error_print(); + return -1; + } + return 1; +} + +int crl_revoked_cert_from_der(CRL_REVOKED_CERT *a, const uint8_t **in, size_t *inlen) +{ + int ret; + const uint8_t *data; + size_t datalen; + + if ((ret = asn1_sequence_from_der(&data, &datalen, in, inlen)) != 1) { + if (ret < 0) error_print(); + return ret; + } + if (asn1_integer_from_der(a->serial_number, &a->serial_number_len, &data, &datalen) != 1 + || x509_time_from_der(&a->revoke_date, &data, &datalen) != 1 + || x509_extensions_from_der(&a->exts, &data, &datalen) != 1 + || datalen) { + error_print(); + return -1; + } + return 1; +} + +int crl_revoked_cert_print(FILE *fp, const CRL_REVOKED_CERT *a, int format, int indent) +{ + + return 1; +} + +int crl_tbs_cert_list_to_der(const CRL_TBS_CERT_LIST *a, uint8_t **out, size_t *outlen) +{ + size_t len = 0; + if (asn1_int_to_der(a->version, NULL, &len) != 1 + || x509_algorithm_id_to_der(a->signature_algor, NULL, &len) != 1 + || x509_name_to_der(&a->issuer, NULL, &len) != 1 + || x509_time_to_der(a->this_update, NULL, &len) != 1 + || x509_time_to_der(a->next_update, NULL, &len) != 1 + || asn1_sequence_header_to_der(len, out, outlen) != 1 + || asn1_int_to_der(a->version, out, outlen) != 1 + || x509_algorithm_id_to_der(a->signature_algor, out, outlen) != 1 + || x509_name_to_der(&a->issuer, out, outlen) != 1 + || x509_time_to_der(a->next_update, out, outlen) != 1) { + error_print(); + return -1; + } + return 1; +} + +int crl_tbs_cert_list_from_der(CRL_TBS_CERT_LIST *a, const uint8_t **in, size_t *inlen) +{ + int ret; + const uint8_t *data; + size_t datalen; + + if ((ret = asn1_sequence_from_der(&data, &datalen, in, inlen)) != 1) { + if (ret < 0) error_print(); + return ret; + } + if (asn1_int_from_der(&a->version, &data, &datalen) != 1 + || x509_algorithm_id_from_der(&a->signature_algor, &data, &datalen) != 1 + || x509_name_from_der(&a->issuer, &data, &datalen) != 1 + || x509_time_from_der(&a->this_update, &data, &datalen) != 1 + || x509_time_from_der(&a->next_update, &data, &datalen) != 1) { + error_print(); + return -1; + } +} + +int x509_cert_list_to_der(const X509_CERT_LIST *a, uint8_t **out, size_t *outlen) +{ + size_t len = 0; + if (x509_tbs_cert_list_to_der(&a->tbs_cert_list, NULL, &len) != 1 + || x509_signature_algor_to_der(a->signature_algor, NULL, &len) != 1 + || asn1_bit_string_to_der(a->signature, a->signature_len, NULL, &len) != 1 + || asn1_sequence_header_to_der(len, out, outlen) != 1 + || x509_tbs_cert_list_to_der(&a->tbs_cert_list, out, outlen) != 1 + || x509_signature_algor_to_der(a->signature_algor, out, outlen) != 1 + || asn1_bit_string_to_der(a->signature, a->signature_len, out, outlen) != 1) { + error_print(); + return -1; + } + return 1; +} + +int x509_cert_list_from_der(X509_CERT_LIST *a, const uint8_t **in, size_t *inlen) +{ + int ret; + const uint8_t *data; + size_t datalen; + const uint8_t *sig; + + if ((ret = asn1_sequence_from_der(&data, &datalen, in, inlen)) != 1) { + if (ret < 0) + error_print(); + return ret; + } + if (x509_tbs_cert_list_from_der(&a->tbs_cert_list, in, inlen) != 1 + || x509_signature_algor_from_der(&a->signature_algor, in, inlen) != 1 + || asn1_bit_string_from_der(&sig, &a->signature_len, in, inlen) != 1 + || a->signature_len <= 0 + || a->signature_len >= X509_MAX_SIGNATURE_SIZE) { + error_print(); + return -1; + } + + memcpy(a->signature, sig, a->signature_len); + return 1; +} + + +static const int X509_CRLExtensionOIDs[7] = { + OID_id_ce_authorityKeyIdentifier, + OID_id_ce_issuerAltName, + OID_id_ce_cRLNumber, + OID_id_ce_deltaCRLIndicator, + OID_id_ce_issuingDistributionPoint, + OID_id_ce_freshestCRL, + OID_pe_authorityInfoAccess, +}; + + + +void X509_CRLExtensionValue_to_der(const X509_CRLExtensionValue *a, int type, uint8_t **out, size_t *outlen) +{ + switch (type) { + case OID_id_ce_authorityKeyIdentifier: AuthorityKeyIdentifier_to_der(&a->u.authorityKeyIdentifier, out, outlen); break; + case OID_id_ce_issuerAltName: X509_GeneralNames_to_der(&a->u.issuerAltName, out, outlen); break; + case OID_id_ce_cRLNumber: ASN1_INTEGER_to_der(&a->u.cRLNumber, out, outlen); break; + case OID_id_ce_deltaCRLIndicator: ASN1_INTEGER_to_der(&a->u.deltaCRLIndicator, out, outlen); + case OID_id_ce_issuingDistributionPoint: X509_IssuingDistributionPoint_to_der(&a->u.issuingDistributionPoint, out, outlen); + case OID_id_ce_freshestCRL: X509_CRLDistributionPoints_to_der(&a->u.freshestCRL, out, outlen); + case OID_pe_authorityInfoAccess: X509_AuthorityInfoAccessSyntax_to_der(&a->u.authorityInfoAccess, out, outlen); + } +} + +int X509_CRLExtensionValue_from_der(X509_CRLExtensionValue *a, int type, const uint8_t **in, size_t *inlen) +{ + switch (type) { + case OID_id_ce_authorityKeyIdentifier: return AuthorityKeyIdentifier_from_der(&a->u.authorityKeyIdentifier, in, inlen); + case OID_id_ce_issuerAltName: return X509_GeneralNames_from_der(&a->u.issuerAltName, in, inlen); + case OID_id_ce_cRLNumber: return ASN1_INTEGER_from_der(&a->u.cRLNumber, in, inlen); + case OID_id_ce_deltaCRLIndicator: return ASN1_INTEGER_from_der(&a->u.deltaCRLIndicator, in, inlen); + case OID_id_ce_issuingDistributionPoint: return X509_IssuingDistributionPoint_from_der(&a->u.issuingDistributionPoint, in, inlen); + case OID_id_ce_freshestCRL: return X509_CRLDistributionPoints_from_der(&a->u.freshestCRL, in, inlen); + case OID_pe_authorityInfoAccess: return X509_AuthorityInfoAccessSyntax_from_der(&a->u.authorityInfoAccess, in, inlen); + } +} + + + +void X509_CRLExtension_to_der(const X509_CRLExtension *a, uint8_t **out, size_t *outlen) +{ + ASN1_SEQUENCE_tag_length_to_der((ASN1_SEQUENCE *)a, out, outlen); + ASN1_OBJECT_IDENTIFIER_to_der(&a->extnID, out, outlen); + ASN1_BOOLEAN_to_der(&a->critical, out, outlen); + ASN1_OCTET_STRING_tag_length_to_der(&a->extnValue, out, outlen); + X509_CRLExtensionValue_to_der(&a->extnValue_data, out, outlen); +} + +int X509_CRLExtension_from_der(X509_CRLExtension *a, const uint8_t **in, size_t *inlen) +{ + int ret; + const uint8_t *data; + size_t length; + + if ((ret = ASN1_SEQUENCE_from_der((ASN1_SEQUENCE *)a, in, inlen)) <= 0) { + return ret; + } + data = ((ASN1_SEQUENCE *)a)->data; + length = ((ASN1_SEQUENCE *)a)->length; + if (ASN1_OBJECT_IDENTIFIER_from_der(&a->extnID, &data, &length) <= 0 + || ASN1_BOOLEAN_from_der(&a->critical, &data, &length) < 0 + || ASN1_OCTET_STRING_from_der(&a->extnValue, &data, &length) <= 0 + || length > 0) { + return -1; + } + data = a->extnValue.data; + length = a->extnValue.length; + if (X509_CRLExtensionValue_from_der(&a->extnValue_data, &data, &length) < 0 + || length > 0) { + return -1; + } + + return 1; +} + + + + + +void X509_CRLExtensions_add(X509_CRLExtensions *a, const X509_CRLExtension *value) +{ + size_t length = ((ASN1_SEQUENCE *)a)->length; + assert(a->count < 16); + X509_CRLExtension_copy(&a->values[a->count], value); + X509_CRLExtension_to_der(&a->values[a->count], NULL, &length); + ASN1_SEQUENCE_set((ASN1_SEQUENCE *)a, NULL, length); + a->count++; +} + +void X509_CRLExtensions_to_der(const X509_CRLExtensions *a, uint8_t **out, size_t *outlen) +{ + int i; + ASN1_SEQUENCE_tag_length_to_der((ASN1_SEQUENCE *)a, out, outlen); + for (i = 0; i < a->count; i++) { + X509_CRLExtension_to_der(&a->value[i], out, outlen); + } +} + +int X509_CRLExtensions_from_der(X509_CRLExtensions *a, const uint8_t **in, size_t *inlen) +{ + int ret; + const uint8_t *data; + size_t length; + + if ((ret = ASN1_SEQUENCE_from_der((ASN1_SEQUENCE *)a, in, inlen)) <= 0) { + return ret; + } + data = ((ASN1_SEQUENCE *)a)->data; + length = ((ASN1_SEQUENCE *)a)->length; + while (length > 0) { + if (a->count >= 16 + || X509_CRLExtension_from_der(&a->values[a->count], &data, &length) <= 0) { + return -1; + } + } + return 1; +} + + + + +// 5.2.5. Issuing Distribution Point +/* +-- issuing distribution point extension OID and syntax + +id-ce-issuingDistributionPoint OBJECT IDENTIFIER ::= { id-ce 28 } + +IssuingDistributionPoint ::= SEQUENCE { + distributionPoint [0] IMPLICIT DistributionPointName OPTIONAL, + onlyContainsUserCerts [1] IMPLICIT BOOLEAN DEFAULT FALSE, + onlyContainsCACerts [2] IMPLICIT BOOLEAN DEFAULT FALSE, + onlySomeReasons [3] IMPLICIT ReasonFlags OPTIONAL, + indirectCRL [4] IMPLICIT BOOLEAN DEFAULT FALSE, + onlyContainsAttributeCerts [5] IMPLICIT BOOLEAN DEFAULT FALSE } + -- at most one of onlyContainsUserCerts, onlyContainsCACerts, + -- and onlyContainsAttributeCerts may be set to TRUE. +*/ + + + + + + + + + + +void X509_CRLEntryExtension_to_der(const X509_CRLEntryExtension *a, uint8_t **out, size_t *outlen) +{ + ASN1_SEQUENCE_tag_length_to_der((ASN1_SEQUENCE *)a, out, outlen); + ASN1_OBJECT_IDENTIFIER_to_der(&a->extnID, out, outlen); + ASN1_BOOLEAN_to_der(&a->critical, out, outlen); + ASN1_OCTET_STRING_tag_length_to_der(&a->extnValue, out, outlen); + X509_CRLEntryExtensionValue_to_der(&a->extnValue_data, out, outlen); +} + +int X509_CRLEntryExtension_from_der(X509_CRLEntryExtension *a, const uint8_t **in, size_t *inlen) +{ + int ret; + const uint8_t *data; + size_t length; + + if ((ret = ASN1_SEQUENCE_from_der((ASN1_SEQUENCE *)a, in, inlen)) <= 0) { + return ret; + } + data = ((ASN1_SEQUENCE *)a)->data; + length = ((ASN1_SEQUENCE *)a)->length; + if (ASN1_OBJECT_IDENTIFIER_from_der(&a->extnID, &data, &length) <= 0 + || ASN1_BOOLEAN_from_der(&a->critical, &data, &length) < 0 + || ASN1_OCTET_STRING_from_der(&a->extnValue, &data, &length) <= 0 + || length > 0) { + return -1; + } + data = a->extnValue.data; + length = a->extnValue.length; + if (X509_CRLEntryExtensionValue_from_der(&a->extnValue_data, &data, &length) < 0 + || length > 0) { + return -1; + } + + return 1; +} + + + + +// CRL Entry Extensions +//*********************************************************************************************************** + +static const int X509_CRLEntryExtensionOIDs[3] = { + OID_id_ce_cRLReasons, + OID_id_ce_invalidityDate, + OID_id_ce_certificateIssuer, +}; + + + +void X509_CRLEntryExtensionValue_to_der(const X509_CRLEntryExtensionValue *a, int type, uint8_t **out, size_t *outlen) +{ + switch (type) { + case OID_id_ce_cRLReasons: ASN1_ENUMERATED_to_der(&a->u.reasonCode, out, outlen); break; + case OID_id_ce_invalidityDate: X509_GeneralizedTime_to_der(&a->u.invalidityDate, out, outlen); break; + case OID_id_ce_certificateIssuer: X509_GeneralNames_to_der(&a->u.certificateIssuer, out, outlen); break; + } +} + +int X509_CRLEntryExtensionValue_from_der(X509_CRLEntryExtensionValue *a, int type, const uint8_t **in, size_t *inlen) +{ + switch (type) { + case OID_id_ce_cRLReasons: return ASN1_ENUMERATED_to_der(&a->u.reasonCode, in, inlen); + case OID_id_ce_invalidityDate: return X509_GeneralizedTime_to_der(&a->u.invalidityDate, in, inlen); + case OID_id_ce_certificateIssuer: return X509_GeneralNames_to_der(&a->u.certificateIssuer, in, inlen); + } +} + +void X509_CRLEntryExtensions_add(X509_CRLEntryExtensions *a, const X509_CRLEntryExtension *value) +{ + size_t length = ((ASN1_SEQUENCE *)a)->length; + assert(a->count < 16); + X509_CRLEntryExtension_copy(&a->values[a->count], value); + X509_CRLEntryExtension_to_der(&a->values[a->count], NULL, &length); + ASN1_SEQUENCE_set((ASN1_SEQUENCE *)a, NULL, length); + a->count++; +} + +void X509_CRLEntryExtensions_to_der(const X509_CRLEntryExtensions *a, uint8_t **out, size_t *outlen) +{ + int i; + ASN1_SEQUENCE_tag_length_to_der((ASN1_SEQUENCE *)a, out, outlen); + for (i = 0; i < a->count; i++) { + X509_CRLEntryExtension_to_der(&a->value[i], out, outlen); + } +} + +int X509_CRLEntryExtensions_from_der(X509_CRLExtensions *a, const uint8_t **in, size_t *inlen) +{ + int ret; + const uint8_t *data; + size_t length; + + if ((ret = ASN1_SEQUENCE_from_der((ASN1_SEQUENCE *)a, in, inlen)) <= 0) { + return ret; + } + data = ((ASN1_SEQUENCE *)a)->data; + length = ((ASN1_SEQUENCE *)a)->length; + while (length > 0) { + if (a->count >= 16 + || X509_CRLEntryExtension_from_der(&a->values[a->count], &data, &length) <= 0) { + return -1; + } + } + return 1; +} + + + + + + + diff --git a/src/x509_ext.c b/src/x509_ext.c new file mode 100644 index 00000000..51e7ad16 --- /dev/null +++ b/src/x509_ext.c @@ -0,0 +1,2533 @@ +/* + * Copyright (c) 2014 - 2020 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + + +/* +首先应该完成一些重要的证书扩展 + + +BasicConstraints: + + CA证书必须包含这个扩展(但是如果证书是v1版本的,那么不支持扩展,我们直接不支持V1证书的验证) + 这个扩展中包含depth值,在验证证书链是必须检查depth是否正确 + +KeyUsage + + CA证书如果包含这个扩展,那么应该设置 CertificateSigner, CRLSigner + SSL终端证书需要这个扩展吗? + +ExtKeyUsage + + SSL终端证书应该包含serverAuth, clientAuth + RFC 5480要求这个扩展只能被用于终端证书,但是有些中间CA证书也包含了这个扩展 + +*/ + + +/* +BEGIN SEQUENCE OF + + X509_GENERAL_NAMES + X509_POLICY_QUALIFIER_INFOS + X509_CERTIFICATE_POLICIES + X509_POLICY_MAPPINGS + X509_ATTRIBUTES + X509_GENERAL_SUBTREES + X509_CRL_DISTRIBUTION_POINTS + +这些类型 to_der 还是 implicit to der 都比较简单,只要调用 type_to_der 就可以了 +但是这些类型 from_der 就不一样,必须还要检查输入的长度,如果输入的长度超过了buffer空间,就只能返回错误了 + + +*/ + + + +////////////////////////////////////////////////////////////////////////////////////////// +// x509_[type_name]_[to|from]_der +////////////////////////////////////////////////////////////////////////////////////////// + +/* +int x509_general_names_from_der_ex(int tag, X509_GENERAL_NAMES *a, const uint8_t **in, size_t *inlen) +{ + int ret; + const uint8_t *data; + size_t datalen; + + if ((ret = asn1_constructed_from_der_ex(tag, &data, &datalen, in, inlen)) != 1) { + if (ret < 0) error_print(); + return ret; + } + if (datalen > 256) { + error_print(); + return -1; + } + memcpy(a->data, data, datalen); + a->datalen = datalen; + return 1; +} + +int x509_general_names_from_der(X509_GENERAL_NAMES *a, const uint8_t **in, size_t *inlen) +{ + return x509_general_names_from_der_ex(ASN1_TAG_SEQUENCE, a, in, inlen); +} + +int x509_implicit_general_names_from_der(int index, X509_GENERAL_NAMES *a, const uint8_t **in, size_t *inlen) +{ + return x509_general_names_from_der_ex(ASN1_TAG_EXPLICIT(index), a, in, inlen); +} + +int x509_certificate_policies_to_der(const X509_CERTIFICATE_POLICIES *a, uint8_t **out, size_t *outlen) +{ + return asn1_sequence_to_der(a->data, a->datalen, out, outlen); +} + +int x509_certificate_policies_from_der(X509_CERTIFICATE_POLICIES *a, const uint8_t **in, size_t *inlen) +{ + int ret; + const uint8_t *data; + size_t datalen; + + if ((ret = asn1_sequence_from_der(&data, &datalen, in, inlen)) != 1) { + if (ret < 0) error_print(); + return ret; + } + if (datalen > 128) { + error_print(); + return -1; + } + memcpy(a->data, data, datalen); + a->datalen = datalen; + return 1; +} + + + + +int x509_policy_qualifier_infos_to_der(const X509_POLICY_QUALIFIER_INFOS *a, uint8_t **out, size_t *outlen) +{ + return asn1_sequence_to_der(a->data, a->datalen, out, outlen); +} + +int x509_policy_qualifier_infos_from_der(X509_POLICY_QUALIFIER_INFOS *a, const uint8_t **in, size_t *inlen) +{ + int ret; + const uint8_t *data; + size_t datalen; + + if ((ret = asn1_sequence_from_der(&data, &datalen, in, inlen)) != 1) { + if (ret < 0) error_print(); + return ret; + } + if (datalen > 256) { + error_print(); + return -1; + } + memcpy(a->data, data, datalen); + a->datalen = datalen; + return 1; +} + + + + +int x509_certificate_policies_to_der(const X509_CERTIFICATE_POLICIES *a, uint8_t **out, size_t *outlen) +{ + return asn1_sequence_to_der(a->data, a->datalen, out, outlen); +} + +int x509_certificate_policies_from_der(X509_CERTIFICATE_POLICIES *a, const uint8_t **in, size_t *inlen) +{ + int ret + const uint8_t *data; + size_t datalen; + + if ((ret = asn1_sequence_from_der(&data, &datalen, in, inlen)) != 1) { + if (ret < 0) error_print(); + return ret; + } + if (datalen > 1024) { + error_print(); + return -1; + } + memcpy(a->data, data, datalen); + a->datalen = datalen; + return 1; +} + +int x509_policy_mappings_to_der(const X509_POLICY_MAPPINGS *a, uint8_t **out, size_t *outlen) +{ + return asn1_sequence_to_der(a->data, a->datalen, out, outlen); +} + +int x509_policy_mappings_from_der(X509_POLICY_MAPPINGS *a, const uint8_t **in, size_t *inlen) +{ + int ret; + const uint8_t *data; + size_t datalen; + + if ((ret = asn1_sequence_from_der(&data, &datalen, in, inlen)) != 1) { + if (ret < 0) error_print(); + return ret; + } + if (datalen > 1024) { + error_print(); + return -1; + } + memcpy(a->data, data, datalen); + a->datalen = datalen; + return 1; +} + +int x509_attributess_to_der(const X509_ATTRIBUTES *a, uint8_t **out, size_t *outlen) +{ + asn1_sequence_to_der(a->data, a->datalen, out, outlen); + return 1; +} + +int x509_attributes_from_der(X509_ATTRIBUTES *a, const uint8_t **in, size_t *inlen) +{ + int ret; + const uint8_t *data; + size_t datalen; + + if ((ret = asn1_sequence_from_der(&data, &datalen, in, inlen)) != 1) { + if (ret < 0) error_print(); + return ret; + } + if (datalen > 128) { + error_print(); + return -1; + } + memcpy(a->data, data, datalen); + a->datalen = datalen; + return 1; +} + + +int x509_general_subtrees_to_der(const X509_GENERAL_SUBTREES *a, uint8_t **out, size_t *outlen) +{ + return asn1_sequence_to_der(a->data, a->datalen, out, outlen); +} + +int x509_general_subtrees_from_der(X509_GENERAL_SUBTREES *a, const uint8_t **in, size_t *inlen) +{ + int ret; + const uint8_t *data; + size_t datalen; + + if ((ret = asn1_sequence_from_der(&data, &datalen, in, inlen)) != 1) { + if (ret < 0) error_print(); + return ret; + } + if (datalen > 128) { + error_print(); + return -1; + } + memcpy(a->data, data, datalen); + a->datalen = datalen; + return 1; +} + + + +*/ + + +static const struct { + uint8_t der; + int oid; + char *name; + char *text; +} x509_kp[] = { + { 1, OID_kp_serverAuth, "serverAuth", "TLS WWW server authentication" }, + { 2, OID_kp_clientAuth, "clientAuth", "TLS WWW client authentication" }, + { 3, OID_kp_codeSigning, "codeSigning", "Signing of downloadable executable code" }, + { 4, OID_kp_emailProtection, "emailProtection", "Email protection" }, + { 8, OID_kp_timeStamping, "timeStamping", "Binding the hash of an object to a time" }, + { 9, OID_kp_OCSPSigning, "OCSPSigning", "Signing OCSP responses" }, +}; + +int x509_key_purpose_from_name(int *oid, const char *name) +{ + int i; + for (i = 0; i < sizeof(x509_kp)/sizeof(x509_kp[0]); i++) { + if (strcmp(name, x509_kp[i].name) == 0) { + *oid = x509_kp[i].oid; + return 1; + } + } + error_print(); + return -1; +} + +const char *x509_key_purpose_name(int oid) +{ + int i; + for (i = 0; i < sizeof(x509_kp)/sizeof(x509_kp[0]); i++) { + if (oid == x509_kp[i].oid) { + return x509_kp[i].name; + } + } + return NULL; +} + +const char *x509_key_purpose_text(int oid) +{ + int i; + for (i = 0; i < sizeof(x509_kp)/sizeof(x509_kp[0]); i++) { + if (oid == x509_kp[i].oid) { + return x509_kp[i].text; + } + } + return NULL; +} + +int x509_key_purpose_to_der(int oid, uint8_t **out, size_t *outlen) +{ + uint8_t der[] = { 0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x00 }; + int i; + for (i = 0; i < sizeof(x509_kp)/sizeof(x509_kp[0]); i++) { + if (oid == x509_kp[i].oid) { + der[sizeof(der) - 1] = x509_kp[i].der; + if (asn1_type_to_der(ASN1_TAG_OBJECT_IDENTIFIER, der, sizeof(der), out, outlen) != 1) { + error_print(); + return -1; + } + return 1; + } + } + error_print("unknown key purpose oid %d", oid); + return -1; + +} + +int x509_key_purpose_from_der(int *oid, const uint8_t **in, size_t *inlen) +{ + const uint8_t der[] = { 0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x00 }; + const uint8_t *data; + size_t datalen; + int ret, i; + + if ((ret = asn1_type_from_der(ASN1_TAG_OBJECT_IDENTIFIER, &data, &datalen, in, inlen)) != 1) { + if (ret < 0) error_print(); + return ret; + } + if (datalen != sizeof(der) || memcmp(data, der, sizeof(der)-1) != 0) { + error_print(); + return -1; + } + for (i = 0; i < sizeof(x509_kp)/sizeof(x509_kp[0]); i++) { + if (data[datalen-1] == x509_kp[i].der) { + *oid = x509_kp[i].oid; + return 1; + } + } + // 这种情况下应该把这个值打印出来 + error_print("unknown ExtKeyUsage OID"); + return -1; +} + +int x509_ext_key_usage_to_der(const int *oids, size_t oids_count, uint8_t **out, size_t *outlen) +{ + size_t len = 0; + size_t i; + for (i = 0; i < oids_count; i++) { + x509_key_purpose_to_der(oids[i], NULL, &len); + } + asn1_sequence_header_to_der(len, out, outlen); + for (i = 0; i < oids_count; i++) { + x509_key_purpose_to_der(oids[i], out, outlen); + } + return 1; +} + +int x509_ext_key_usage_from_der(int *oids, size_t *oids_count, const uint8_t **in, size_t *inlen) +{ + int ret; + const uint8_t *data; + size_t datalen; + + if ((ret = asn1_sequence_from_der(&data, &datalen, in, inlen)) != 1) { + if (ret < 0) error_print(); + return ret; + } + *oids_count = 0; + while (datalen) { + if (x509_key_purpose_from_der(oids, &data, &datalen) != 1) { + error_print(); + return -1; + } + oids++; + (*oids_count)++; + } + return 1; +} + + + + +int x509_crl_distribution_points_to_der(const X509_CRL_DISTRIBUTION_POINTS *a, uint8_t **out, size_t *outlen) +{ + return asn1_sequence_to_der(a->data, a->datalen, out, outlen); +} + +int x509_crl_distribution_points_from_der(X509_CRL_DISTRIBUTION_POINTS *a, const uint8_t **in, size_t *inlen) +{ + int ret; + const uint8_t *data; + size_t datalen; + if ((ret = asn1_sequence_from_der(&data, &datalen, in, inlen)) != 1) { + if (ret < 0) error_print(); + return ret; + } + if (datalen > 128) { + error_print(); + return -1; + } + memcpy(a->data, data, datalen); + a->datalen = datalen; + return 1; +} + + + + + + + + + + + +// x509_[type_name]_add_item + +int x509_general_names_add_item(X509_GENERAL_NAMES *a, + int choice, const uint8_t *data, size_t datalen) +{ + uint8_t *p = a->data + a->datalen; + size_t len = 0; + if (x509_general_name_to_der(choice, data, datalen, &p, &len) != 1) { + error_print(); + return -1; + } + a->datalen += len; + return 1; +} + +int x509_policy_qualifier_infos_add_item(X509_POLICY_QUALIFIER_INFOS *a, + int oid, const uint8_t *qualifier, size_t qualifier_len) +{ + uint8_t *p = a->data + a->datalen; + size_t len = 0; + if (x509_policy_qualifier_info_to_der(oid, qualifier, qualifier_len, &p, &len) != 1) { + error_print(); + return -1; + } + a->datalen += len; + return 1; +} + +int x509_certificate_policies_add_item(X509_CERTIFICATE_POLICIES *a, + int oid, const uint32_t *nodes, size_t nodes_count, + const X509_POLICY_QUALIFIER_INFOS *qualifiers) +{ + uint8_t *p = a->data + a->datalen; + size_t len = 0; + if (x509_policy_information_to_der(oid, nodes, nodes_count, qualifiers, &p, &len) != 1) { + error_print(); + return -1; + } + a->datalen += len; + return 1; +} + +int x509_policy_mappings_add_item(X509_POLICY_MAPPINGS *a, + int issuer_policy_oid, const uint32_t *issuer_policy_nodes, size_t issuer_policy_nodes_count, + int subject_policy_oid, const uint32_t *subject_policy_nodes, size_t subject_policy_nodes_count) +{ + uint8_t *p = a->data + a->datalen; + size_t len = 0; + if (x509_policy_mapping_to_der( + issuer_policy_oid, issuer_policy_nodes, issuer_policy_nodes_count, + subject_policy_oid, subject_policy_nodes, subject_policy_nodes_count, + &p, &len) != 1) { + error_print(); + return -1; + } + a->datalen += len; + return 1; +} + +int x509_attributes_add_item(X509_ATTRIBUTES *a, + int oid, const uint32_t *nodes, size_t nodes_count, + const uint8_t *values, size_t valueslen) +{ + uint8_t *p = a->data + a->datalen; + size_t len = 0; + if (x509_attribute_to_der(oid, nodes, nodes_count, values, valueslen, &p, &len) != 1) { + error_print(); + return -1; + } + a->datalen += len; + return 1; +} + +int x509_general_subtrees_add_item(X509_GENERAL_SUBTREES *a, + int base_choise, const uint8_t *base_data, size_t base_datalen, + int minimum, + int maximum) +{ + uint8_t *p = a->data + a->datalen; + size_t len = 0; + if (x509_general_subtree_to_der(base_choise, base_data, base_datalen, minimum, maximum, &p, &len) != 1) { + error_print(); + return -1; + } + a->datalen += len; + return 1; +} + +int x509_crl_distribution_points_add_item(X509_CRL_DISTRIBUTION_POINTS *a, + const X509_DISTRIBUTION_POINT_NAME *dist_point_name, + int reason_bits, + const X509_GENERAL_NAMES *crl_issuer) +{ + uint8_t *p = a->data + a->datalen; + size_t len = 0; + if (x509_distribution_point_to_der(dist_point_name, reason_bits, crl_issuer, &p, &len) != 1) { + error_print(); + return -1; + } + a->datalen += len; + return 1; +} + + +////////////////////////////////////////////////////////////////////////////////////////// +// x509_[type_name]_get_next_item +// *next == NULL 表示从头开始 +// 应该吧公共代码提取为一个公共函数 +////////////////////////////////////////////////////////////////////////////////////////// + + +int x509_general_names_get_next_item(const X509_GENERAL_NAMES *a, const uint8_t **next, + int *choice, const uint8_t **data, size_t *datalen) +{ + int ret; + const uint8_t *value; + size_t valuelen; + if ((ret = asn1_sequence_of_get_next_item((ASN1_SEQUENCE_OF *)a, next, &value, &valuelen)) != 1) { + if (ret < 0) error_print(); + return ret; + } + ret = x509_general_name_from_der(choice, data, datalen, &value, &valuelen); + if (ret < 0) error_print(); + return ret; +} + +int x509_policy_qualifier_infos_get_next_item(const X509_POLICY_QUALIFIER_INFOS *a, const uint8_t **next, + int *oid, const uint8_t **qualifier, size_t *qualifier_len) +{ + int ret; + const uint8_t *value; + size_t valuelen; + if ((ret = asn1_sequence_of_get_next_item((ASN1_SEQUENCE_OF *)a, next, &value, &valuelen)) != 1) { + if (ret < 0) error_print(); + return ret; + } + ret = x509_policy_qualifier_info_from_der(oid, qualifier, qualifier_len, &value, &valuelen); + if (ret < 0) error_print(); + return ret; +} + +int x509_certificate_policies_get_next_item(const X509_CERTIFICATE_POLICIES *a, const uint8_t **next, + int *oid, const uint32_t *nodes, size_t *nodes_count, + X509_POLICY_QUALIFIER_INFOS *qualifiers) +{ + int ret; + const uint8_t *value; + size_t valuelen; + /* + if ((ret = asn1_sequence_of_get_next_item((ASN1_SEQUENCE_OF *)a, next, &value, &valuelen)) != 1) { + if (ret < 0) error_print(); + return ret; + } + ret = x509_certificate_policy_from_der(oid, nodes, nodes_count, qualifiers, qualifiers_len, &value, &valuelen); + if (ret < 0) error_print(); + */ + return ret; +} + +int x509_policy_mappings_get_next_item(const X509_POLICY_MAPPINGS *a, const uint8_t **next, + uint32_t *issuer_policy_nodes, size_t *issuer_policy_nodes_count, + uint32_t *subject_policy_nodes, size_t *subject_policy_nodes_count) +{ + int ret; + const uint8_t *value; + size_t valuelen; + if ((ret = asn1_sequence_of_get_next_item((ASN1_SEQUENCE_OF *)a, next, &value, &valuelen)) != 1) { + if (ret < 0) error_print(); + return ret; + } + /* + ret = x509_policy_mapping_from_der( + issuer_policy_nodes, issuer_policy_nodes_count, + subject_policy_nodes, subject_policy_nodes_count, + &value, &valuelen); + */ + if (ret < 0) error_print(); + return ret; +} + +int x509_attributes_get_next_item(const X509_ATTRIBUTES *a, const uint8_t **next, + int *oid, uint32_t *nodes, size_t *nodes_count, + const uint8_t **data, size_t *datalen) +{ + int ret; + const uint8_t *value; + size_t valuelen; + if ((ret = asn1_sequence_of_get_next_item((ASN1_SEQUENCE_OF *)a, next, &value, &valuelen)) != 1) { + if (ret < 0) error_print(); + return ret; + } + ret = x509_attribute_from_der(oid, nodes, nodes_count, data, datalen, &value, &valuelen); + if (ret < 0) error_print(); + return ret; +} + +int x509_general_subtrees_get_next_item(const X509_GENERAL_SUBTREES *a, const uint8_t **next, + int *base_choise, const uint8_t **base_data, size_t *base_datalen, + int *minimum, + int *maximum) +{ + int ret; + const uint8_t *value; + size_t valuelen; + if ((ret = asn1_sequence_of_get_next_item((ASN1_SEQUENCE_OF *)a, next, &value, &valuelen)) != 1) { + if (ret < 0) error_print(); + return ret; + } + ret = x509_general_subtree_from_der( + base_choise, base_data, base_datalen, + minimum, maximum, + &value, &valuelen); + if (ret < 0) error_print(); + return ret; +} + +int x509_crl_distribution_points_get_next_item(const X509_CRL_DISTRIBUTION_POINTS *a, + const uint8_t **next, + X509_DISTRIBUTION_POINT_NAME *distribution_point, + int *reasons, + X509_GENERAL_NAMES *crl_issuer) +{ + int ret; + const uint8_t *value; + size_t valuelen; + if ((ret = asn1_sequence_of_get_next_item((ASN1_SEQUENCE_OF *)a, next, &value, &valuelen)) != 1) { + if (ret < 0) error_print(); + return ret; + } + ret = x509_distribution_point_from_der(distribution_point, reasons, crl_issuer, &value, &valuelen); + if (ret < 0) error_print(); + return ret; +} + +// END SEQUENCE OF + + + +/* + DisplayText CHOICE Universal + Name SEQUENCE OF + OtherName SEQUENCE + EDIPartyName SEQUENCE + GeneralName CHOICE + GeneralNames SEQUENCE OF + AuthorityKeyIdentifier SEQUENCE + CertificatePolicies SEQUENCE OF + PolicyInformation + UserNotice +*/ + +/* +DisplayText ::= CHOICE { IA5String, VisibleString, BMPString, UTF8String } + +*/ +int x509_display_text_to_der(int tag, const char *text, size_t textlen, uint8_t **out, size_t *outlen) +{ + int ret; + switch (tag) { + case ASN1_TAG_IA5String: + case ASN1_TAG_VisibleString: + case ASN1_TAG_UTF8String: + if (strlen(text) != textlen) { + error_print(); + return -1; + } + break; + case ASN1_TAG_BMPString: + break; + default: + error_print(); + return -1; + } + ret = asn1_type_to_der(tag, (const uint8_t *)text, textlen, out, outlen); + if (ret < 0) error_print(); + return ret; +} + +int x509_display_text_from_der(int *tag, const char **text, size_t *textlen, const uint8_t **in, size_t *inlen) +{ + int ret; + + if ((ret = asn1_any_type_from_der(tag, (const uint8_t **)text, textlen, in, inlen)) != 1) { + if (ret < 0) error_print(); + return ret; + } + switch (*tag) { + case ASN1_TAG_IA5String: + case ASN1_TAG_VisibleString: + case ASN1_TAG_UTF8String: + if (strlen(*text) != *textlen) { + error_print(); + return -1; + } + break; + case ASN1_TAG_BMPString: + break; + default: + error_print(); + return -1; + } + return 1; +} + +/* +EDIPartyName ::= SEQUENCE { + nameAssigner [0] EXPLICIT DirectoryString OPTIONAL, + partyName [1] EXPLICIT DirectoryString } + + DirectoryString 是 CHOICE 类型,因此必须为 EXPLICIT Tag +*/ +int x509_edi_party_name_to_der( + int assigner_tag, const char *assigner, size_t assigner_len, + int party_name_tag, const char *party_name, size_t party_name_len, + uint8_t **out, size_t *outlen) +{ + size_t sublen0; + size_t sublen1; + size_t len = 0; + if ((assigner && x509_directory_string_to_der(assigner_tag, assigner, assigner_len, NULL, &sublen0) != 1) + || (assigner && asn1_explicit_to_der(0, NULL, sublen0, NULL, &len) != 1) + || x509_directory_string_to_der(party_name_tag, party_name, party_name_len, NULL, &sublen1) != 1 + || asn1_explicit_to_der(1, NULL, sublen1, NULL, &len) != 1 + || asn1_sequence_header_to_der(len, out, outlen) != 1 + || (assigner && asn1_explicit_header_to_der(0, sublen0, out, outlen) != 1) + || (assigner && x509_directory_string_to_der(assigner_tag, assigner, assigner_len, out, outlen) != 1) + || asn1_explicit_header_to_der(1, sublen1, out, outlen) != 1 + || x509_directory_string_to_der(party_name_tag, party_name, party_name_len, out, outlen) != 1) { + error_print(); + return -1; + } + return 1; +} + +int x509_edi_party_name_from_der(int *assigner_tag, const char **assigner, size_t *assigner_len, + int *party_name_tag, const char **party_name, size_t *party_name_len, + const uint8_t **in, size_t *inlen) +{ + int ret; + const uint8_t *data, *subdata0; + size_t datalen; + const uint8_t *exp0, *exp1; + size_t explen0, explen1; + + if ((ret = asn1_sequence_from_der(&data, &datalen, in, inlen)) != 1) { + if (ret < 0) error_print(); + return ret; + } + if (asn1_explicit_from_der(0, &exp0, &explen0, &data, &datalen) < 0 + || asn1_explicit_from_der(1, &exp1, &explen1, &data, &datalen) != 1 + || datalen > 0) { + error_print(); + return -1; + } + if ((exp0 && x509_directory_string_from_der(assigner_tag, assigner, assigner_len, &exp0, &explen0) != 1) + || x509_directory_string_from_der(party_name_tag, party_name, party_name_len, &exp1, &explen1) != 1) { + error_print(); + return -1; + } + return -1; +} + +/* +OtherName ::= SEQUENCE { + type-id OBJECT IDENTIFIER, + value [0] EXPLICIT ANY DEFINED BY type-id +} +*/ +int x509_other_name_to_der(int oid, const uint32_t *nodes, size_t nodes_count, + const uint8_t *value, size_t valuelen, + uint8_t **out, size_t *outlen) +{ + size_t len = 0; + if (asn1_object_identifier_to_der(oid, nodes, nodes_count, NULL, &len) != 1 + || asn1_explicit_to_der(0, value, valuelen, NULL, &len) != 1 + || asn1_sequence_header_to_der(len, out, outlen) != 1 + || asn1_object_identifier_to_der(oid, nodes, nodes_count, out, outlen) != 1 + || asn1_explicit_to_der(0, value, valuelen, out, outlen) != 1) { + error_print(); + return -1; + } + return 1; +} + +int x509_other_name_from_der(int *oid, uint32_t *nodes, size_t *nodes_count, + const uint8_t **value, size_t *valuelen, const uint8_t **in, size_t *inlen) +{ + int ret; + const uint8_t *data; + size_t datalen; + if ((ret = asn1_sequence_from_der(&data, &datalen, in, inlen)) != 1) { + if (ret < 0) error_print(); + return ret; + } + if (asn1_object_identifier_from_der(oid, nodes, nodes_count, &data, &datalen) != 1 + || asn1_explicit_from_der(0, value, valuelen, &data, &datalen) != 1 + || datalen > 0) { + error_print(); + return -1; + } + return 1; +} + +/* +GeneralName ::= CHOICE { + otherName [0] IMPLICIT OtherName, + rfc822Name [1] IMPLICIT IA5String, + dNSName [2] IMPLICIT IA5String, + x400Address [3] IMPLICIT ORAddress, + directoryName [4] IMPLICIT Name, + ediPartyName [5] IMPLICIT EDIPartyName, + uniformResourceIdentifier [6] IMPLICIT IA5String, + iPAddress [7] IMPLICIT OCTET STRING, + registeredID [8] IMPLICIT OBJECT IDENTIFIER } + + 这个类型非常讨厌,IMPLICT类型导致影响了的Tag,看来所有的类型都需要为Tag的修改做准备 + + 当 choice 为基本类型时,输入为类型的值数据 + 当 choice 为 SEQUENCE 时,输入为该 SEQUENCE 的TLV DER编码 + + 由于X509_NAME是一个存储类型,因此也污染了这个CHOICE +*/ +int x509_general_name_to_der(int choice, const uint8_t *data, size_t datalen, uint8_t **out, size_t *outlen) +{ + uint8_t *tag = *out; + switch (choice) { + case X509_gn_rfc822Name: + case X509_gn_dnsName: + case X509_gn_uniformResourceIdentifier: + if (strlen((char *)data) != datalen) { + error_print(); + return -1; + } + case X509_gn_ipAddress: + asn1_type_to_der(ASN1_TAG_IMPLICIT(choice), data, datalen, out, outlen); + break; + + case X509_gn_otherName: + case X509_gn_x400Address: + case X509_gn_directoryName: + case X509_gn_ediPartyName: + case X509_gn_registeredID: + asn1_data_to_der(data, datalen, out, outlen); + *tag = ASN1_TAG_IMPLICIT(choice); + break; + + default: + error_print(); + return -1; + } + return 1; +} + +int x509_general_name_from_der(int *choice, const uint8_t **data, size_t *datalen, const uint8_t **in, size_t *inlen) +{ + return -1; +} + + + + + + + + +int x509_authority_key_identifier_to_der( + const uint8_t *keyid, size_t keyid_len, + const X509_GENERAL_NAMES *issuer, + const uint8_t *serial_number, size_t serial_number_len, + uint8_t **out, size_t *outlen) +{ + size_t len = 0; + + asn1_implicit_octet_string_to_der(0, keyid, keyid_len, NULL, &len); + x509_implicit_general_names_to_der(1, issuer, NULL, &len); + asn1_implicit_integer_to_der(2, serial_number, serial_number_len, NULL, &len); + asn1_sequence_header_to_der(len, out, outlen); + asn1_implicit_octet_string_to_der(0, keyid, keyid_len, out, outlen); + x509_implicit_general_names_to_der(1, issuer, out, outlen); + asn1_implicit_integer_to_der(2, serial_number, serial_number_len, out, outlen); + return 1; +} + +int x509_authority_key_identifier_from_der( + const uint8_t **keyid, size_t *keyid_len, + X509_GENERAL_NAMES *issuer, + const uint8_t **serial_number, size_t *serial_number_len, + const uint8_t **in, size_t *inlen) +{ + int ret; + const uint8_t *data; + size_t datalen; + + if ((ret = asn1_sequence_from_der(&data, &datalen, in, inlen)) != 1) { + if (ret < 0) error_print(); + return ret; + } + + if (asn1_implicit_octet_string_from_der(0, keyid, keyid_len, in, inlen) < 0 + || x509_implicit_general_names_from_der(1, issuer, in, inlen) < 0 + || asn1_implicit_integer_from_der(2, serial_number, serial_number_len, in, inlen) < 0 + || datalen > 0) { + error_print(); + return -1; + } + return 1; +} + +int x509_authority_key_identifier_print(FILE *fp, const uint8_t *data, size_t datalen, int format, int indent) +{ + int ret; + const uint8_t *p; + size_t len; + const uint8_t *keyid; + size_t keyidlen; + X509_GENERAL_NAMES issuer; + const uint8_t *serial; + size_t seriallen; + + if (asn1_sequence_from_der(&p, &len, &data, &datalen) != 1 + || datalen) { + error_print(); + return -1; + } + if ((ret = asn1_implicit_octet_string_from_der(0, &keyid, &keyidlen, &p, &len)) < 0) { + error_print(); + return -1; + } else if (ret) { + format_bytes(fp, format, indent, "KeyIdentifier : ", keyid, keyidlen); + } + if ((ret = x509_implicit_general_names_from_der(1, &issuer, &p, &len)) < 0) { + error_print(); + return -1; + } else if (ret) { + format_print(fp, format, indent, "AuthorityCertIssuer\n"); + //x509_general_names_print(fp, &issuer, format, indent + 4); + } + if ((ret = asn1_implicit_integer_from_der(2, &serial, &seriallen, &p, &len)) < 0) { + error_print(); + return -1; + } else if (ret) { + format_bytes(fp, format, indent, "AuthorityCertSerialNumber : ", serial, seriallen); + } + if (len) { + error_print(); + return -1; + } + return 1; +} + + + + + + + + + + + + + +/* +3 +KeyUsage ::= BIT STRING { + digitalSignature (0), + nonRepudiation (1), -- recent editions of X.509 have + -- renamed this bit to contentCommitment + keyEncipherment (2), + dataEncipherment (3), + keyAgreement (4), + keyCertSign (5), + cRLSign (6), + encipherOnly (7), + decipherOnly (8) } +*/ + + + + +/* +4 CertificatePolicies ::= SEQUENCE SIZE (1..MAX) OF PolicyInformation + + +看来这是一个非常复杂的扩展,可能很难通过简单的接口去设置。 +我应该把这个设为一个独立的对象,在设置的时候,直接提供这个对象的DER +在解析的时候,可以有独立的函数将其解析成文本之类的可能更好 + +虽然这个扩展很复杂,但是我们的主要需求就是能够解析并转化为可显示的字符串 +*/ + + + + + + + + + + + + + + + +/* +NoticeReference ::= SEQUENCE { + organization DisplayText, + noticeNumbers SEQUENCE OF INTEGER +} +*/ +int x509_notice_reference_to_der( + int organization_tag, const char *organization, size_t organization_len, + const int *notice_numbers, size_t notice_numbers_count, + uint8_t **out, size_t *outlen) +{ + size_t sublen, len; + size_t i; + + x509_display_text_to_der(organization_tag, organization, organization_len, NULL, &len); + for (i = 0; i < notice_numbers_count; i++) { + asn1_int_to_der(notice_numbers[i], NULL, &len); + } + asn1_sequence_to_der(NULL, sublen, NULL, &len); + + asn1_sequence_header_to_der(len, out, outlen); + x509_display_text_to_der(organization_tag, organization, organization_len, out, outlen); + asn1_sequence_header_to_der(sublen, out, outlen); + for (i = 0; i < notice_numbers_count; i++) { + asn1_int_to_der(notice_numbers[i], out, outlen); + } + return -1; +} + +int x509_notice_reference_from_der( + int *organization_tag, const char **organization, size_t *organization_len, + int *notice_numbers, size_t *notice_numbers_count, + const uint8_t **in, size_t *inlen) +{ + const uint8_t *data, *subdata; + size_t datalen = 0, subdatalen = 0; + int ret; + + if ((ret = asn1_sequence_from_der(&data, &datalen, in, inlen)) != 1) { + if (ret < 0) error_print(); + return ret; + } + + if (x509_display_text_from_der(organization_tag, organization, organization_len, &data, &datalen) != 1 + || asn1_sequence_from_der(&subdata, &subdatalen, &data, &datalen) != 1 + || datalen > 0 + || subdatalen <= 0) { + error_print(); + return -1; + } + + *notice_numbers_count = 0; + while (subdatalen) { + if (asn1_int_from_der(notice_numbers, &subdata, &subdatalen) != 1) { + error_print(); + return -1; + } + (*notice_numbers_count)++; + } + + return 1; +} + + +/* +UserNotice ::= SEQUENCE { + noticeRef NoticeReference OPTIONAL, + explicitText DisplayText OPTIONAL } +*/ +int x509_user_notice_to_der( + const uint8_t *notice_ref_der, size_t notice_ref_der_len, + int explicit_text_tag, const char *explicit_text, size_t explicit_text_len, + uint8_t **out, size_t *outlen) +{ + size_t len = 0; + asn1_data_to_der(notice_ref_der, notice_ref_der_len, NULL, &len); + x509_display_text_to_der(explicit_text_tag, explicit_text, explicit_text_len, NULL, &len); + + asn1_sequence_header_to_der(len, out, outlen); + asn1_data_to_der(notice_ref_der, notice_ref_der_len, out, outlen); + x509_display_text_to_der(explicit_text_tag, explicit_text, explicit_text_len, out, outlen); + + return -1; +} + +int x509_user_notice_from_der( + const uint8_t **notice_ref_der, size_t *notice_ref_der_len, + int *explicit_text_tag, const char **explicit_text, size_t *explicit_text_len, + const uint8_t **in, size_t *inlen) +{ + int ret; + const uint8_t *data; + size_t datalen; + const uint8_t *subdata; + size_t subdatalen; + + + if ((ret = asn1_sequence_from_der(&data, &datalen, in, inlen)) != 1) { + if (ret < 0) error_print(); + return ret; + } + + *notice_ref_der = data; + asn1_sequence_from_der(&subdata, &subdatalen, &data, &datalen); + *notice_ref_der_len = data - (*notice_ref_der); + x509_display_text_from_der(explicit_text_tag, explicit_text, explicit_text_len, in, inlen); + + return -1; +} + + +/* +PolicyQualifierInfo ::= SEQUENCE { + policyQualifierId OBJECT IDENTIFIER ( id-qt-cps | id-qt-unotice ), + qualifier ANY DEFINED BY policyQualifierId } + +当policyQualifierId == id-qt-cps 时,qualifier为CPSuri,否则为UserNotice + + Qualifier ::= CHOICE { + cPSuri IA5String, + userNotice UserNotice } + +*/ +int x509_policy_qualifier_info_to_der(int oid, + const uint8_t *qualifier, size_t qualifier_len, uint8_t **out, size_t *outlen) +{ + size_t len = 0; + asn1_object_identifier_to_der(oid, NULL, 0, NULL, &len); + switch (oid) { + case OID_qt_cps: + asn1_ia5_string_to_der((char *)qualifier, NULL, &len); + break; + case OID_qt_unotice: + asn1_data_to_der(qualifier, qualifier_len, NULL, &len); + break; + } + + asn1_sequence_header_to_der(len, out, outlen); + asn1_object_identifier_to_der(oid, NULL, 0, out, outlen); + switch (oid) { + case OID_qt_cps: + asn1_ia5_string_to_der((char *)qualifier, out, &len); + break; + case OID_qt_unotice: + asn1_data_to_der(qualifier, qualifier_len, out, &len); + break; + } + + return 1; +} + +int x509_policy_qualifier_info_from_der(int *oid, const uint8_t **qualifier, size_t *qualifier_len, const uint8_t **in, size_t *inlen) +{ + int ret; + const uint8_t *data; + size_t datalen; + uint32_t nodes[16]; + size_t nodes_count; + + if ((ret = asn1_sequence_from_der(&data, &datalen, in, inlen)) != 1) { + if (ret < 0) error_print(); + return ret; + } + if (asn1_object_identifier_from_der(oid, nodes, &nodes_count, &data, &datalen) != 1) { + error_print(); + return -1; + } + + switch (*oid) { + case OID_qt_cps: + asn1_ia5_string_from_der((const char **)qualifier, qualifier_len, &data, &datalen); + break; + case OID_qt_unotice: + *qualifier_len = datalen; + asn1_data_from_der(qualifier, *qualifier_len, &data, &datalen); + break; + } + + return -1; +} + +/* +PolicyInformation ::= SEQUENCE { + policyIdentifier OBJECT IDENTIFIER, + -- 由CA定义的,RFC 5280中仅规定为一个可选的OID anyPolicy + policyQualifiers SEQUENCE SIZE (1..MAX) OF PolicyQualifierInfo OPTIONAL + -- 必须为这个准备一个独立的类型 +} +*/ + +int x509_policy_information_to_der( + int oid, const uint32_t *nodes, size_t nodes_count, + const X509_POLICY_QUALIFIER_INFOS *qualifiers, + uint8_t **out, size_t *outlen) +{ + size_t len = 0; + asn1_object_identifier_to_der(oid, nodes, nodes_count, NULL, &len); + x509_policy_qualifier_infos_to_der(qualifiers, NULL, &len); + asn1_sequence_header_to_der(len, out, outlen); + asn1_object_identifier_to_der(oid, nodes, nodes_count, out, outlen); + x509_policy_qualifier_infos_to_der(qualifiers, out, outlen); + + return 1; +} + +int x509_policy_information_from_der( + int *oid, uint32_t *nodes, size_t *nodes_count, + X509_POLICY_QUALIFIER_INFOS *qualifiers, + const uint8_t **in, size_t *inlen) +{ + int ret; + const uint8_t *data; + size_t datalen; + + if ((ret = asn1_sequence_from_der(&data, &datalen, in, inlen)) != 1) { + if (ret < 0) error_print(); + return ret; + } + if (asn1_object_identifier_from_der(oid, nodes, nodes_count, &data, &datalen) != 1 + || x509_policy_qualifier_infos_from_der(qualifiers, &data, &datalen) != 1 + || datalen > 0) { + error_print(); + return -1; + } + return 1; +} + + +/* +CertificatePolicies ::= SEQUENCE SIZE (1..MAX) OF PolicyInformation +*/ + + + + + + + +// 这个扩展的数据是一个SEQUENCE OF SEQUENCE,应该统一考虑一下如何处理SEQUENCE OF 这样的返回值 +// 一种是提供一个数组,每个数组是一个SEQUENCE +// 还是只返回这个SEQUENCE OF的数据? + + +/* +5 + +PolicyMappings ::= SEQUENCE SIZE (1..MAX) OF SEQUENCE { + issuerDomainPolicy CertPolicyId, + subjectDomainPolicy CertPolicyId } + +CertPolicyId ::= OBJECT IDENTIFIER + +This extension MAY be supported by CAs and/or applications. + Conforming CAs SHOULD mark this extension as critical. + +这个也是SEQUENCE OF SEQUENCE +在设置的时候给出数组实际上不太方便 +*/ + + + +int x509_policy_mapping_to_der( + int issuer_policy_oid, const uint32_t *issuer_policy_nodes, size_t issuer_policy_nodes_count, + int subject_policy_oid, const uint32_t *subject_policy_nodes, size_t subject_policy_nodes_count, + uint8_t **out, size_t *outlen) +{ + size_t len = 0; + if (asn1_object_identifier_to_der(issuer_policy_oid, issuer_policy_nodes, issuer_policy_nodes_count, NULL, &len) != 1 + || asn1_object_identifier_to_der(subject_policy_oid, subject_policy_nodes, subject_policy_nodes_count, NULL, &len) != 1 + || asn1_sequence_header_to_der(len, out, outlen) != 1 + || asn1_object_identifier_to_der(issuer_policy_oid, issuer_policy_nodes, issuer_policy_nodes_count, out, outlen) != 1 + || asn1_object_identifier_to_der(subject_policy_oid, subject_policy_nodes, subject_policy_nodes_count, out, outlen) != 1) { + error_print(); + return -1; + } + return 1; +} + +int x509_policy_mapping_from_der( + int *issuer_policy_oid, uint32_t *issuer_policy_nodes, size_t *issuer_policy_nodes_count, + int *subject_policy_oid, uint32_t *subject_policy_nodes, size_t *subject_policy_nodes_count, + const uint8_t **in, size_t *inlen) +{ + int ret; + const uint8_t *data; + size_t datalen; + if ((ret = asn1_sequence_from_der(&data, &datalen, in, inlen)) != 1) { + if (ret < 0) error_print(); + return ret; + } + if (asn1_object_identifier_from_der(issuer_policy_oid, issuer_policy_nodes, issuer_policy_nodes_count, &data, &datalen) != 1 + || asn1_object_identifier_from_der(subject_policy_oid, subject_policy_nodes, subject_policy_nodes_count, &data, &datalen) != 1 + || datalen > 0) { + error_print(); + return -1; + } + return 1; +} + + + +/* + ## 6 + + SubjectAltName ::= GeneralNames + +GeneralNames 也是 SEQUENCE OF SEQUENCE +*/ + + + +/* +7 +IssuerAltName ::= GeneralNames +*/ + + + + +/* +8 +SubjectDirectoryAttributes ::= SEQUENCE SIZE (1..MAX) OF Attribute + +Attribute ::= SEQUENCE { + type OBJECT IDENTIFIER, + values SET OF AttributeValue + -- values的类型是SET OF ! +} +AttributeValue ::= ANY +*/ + +int x509_attribute_to_der( + int oid, const uint32_t *nodes, size_t nodes_count, + const uint8_t *values, size_t valueslen, + uint8_t **out, size_t *outlen) +{ + size_t len = 0; + + asn1_object_identifier_to_der(oid, nodes, nodes_count, NULL, &len); + asn1_set_to_der(values, valueslen, NULL, &len); + asn1_sequence_header_to_der(len, out, outlen); + asn1_object_identifier_to_der(oid, nodes, nodes_count, out, outlen); + asn1_set_to_der(values, valueslen, out, outlen); + return 1; +} + +int x509_attribute_from_der( + int *oid, uint32_t *nodes, size_t *nodes_count, + const uint8_t **values, size_t *valueslen, + const uint8_t **in, size_t *inlen) +{ + int ret; + const uint8_t *data; + size_t datalen; + + if ((ret = asn1_sequence_from_der(&data, &datalen, in, inlen)) != 1) { + if (ret < 0) error_print(); + return ret; + } + if (asn1_object_identifier_from_der(oid, nodes, nodes_count, &data, &datalen) != 1 + || asn1_set_from_der(values, valueslen, &data, &datalen) != 1 + || datalen > 0) { + error_print(); + return -1; + } + return 1; +} + + +/* + +9 + + BasicConstraints ::= SEQUENCE { + cA BOOLEAN DEFAULT FALSE, + pathLenConstraint INTEGER (0..MAX) OPTIONAL } + + FIXME: 从这个类型看起来,一个 SEQUENCE 中的数据可能是空的 + 但是问题是,如果这两个元素都没有内容,那么这个扩展就完全没有必要提供了! + + + 如果一个证书是CA证书,那么必须包含这个扩展 + + 没有为这个扩展建立一个独立的对象,这是因为在 x509_certificate_set_ 系列函数中 + 如果有一个独立的对象,那么会增加接口的复杂度。 + +一般来说在完成了证书的解析后,证书对象中有所有的扩展列表,有了扩展的OID,但是这些扩展的内容还没有解析 +现在还不太确定到底在什么时候需要获取某个证书扩展的内容,以及以何种方式获取 +可能还要等到验证证书链的时候才能定下来 + +*/ + + + + + +int x509_basic_constraints_to_der(int is_ca_cert, // 必须设置为 0 或 1,如果设为 0 那么不编码 + int cert_chain_maxlen, // -1 means omitted,FIXME: 应该设置一个最大值 + uint8_t **out, size_t *outlen) +{ + size_t len = 0; + if (is_ca_cert) { + if (asn1_boolean_to_der(ASN1_TRUE, NULL, &len) != 1) { + error_print(); + return -1; + } + } + if (cert_chain_maxlen >= 0) { + if (asn1_int_to_der((uint32_t)cert_chain_maxlen, NULL, &len) != 1) { + error_print(); + return -1; + } + } + asn1_sequence_header_to_der(len, out, outlen); + if (is_ca_cert) { + if (asn1_boolean_to_der(ASN1_TRUE, out, outlen) != 1) { + error_print(); + return -1; + } + } + if (cert_chain_maxlen >= 0) { + if (asn1_int_to_der((uint32_t)cert_chain_maxlen, out, outlen) != 1) { + error_print(); + return -1; + } + } + return 1; +} + +// 解码的时候如果 is_ca_cert 没有,那么会强制设置为0,因此从本函数无法知道 is_ca_cert 是否被编码 +// 如果 cert_chain_maxlen 没有编码,那么这个值会被强制设置为 -1 +int x509_basic_constraints_from_der(int *is_ca_cert, int *cert_chain_maxlen, const uint8_t **in, size_t *inlen) +{ + int ret; + const uint8_t *data; + size_t datalen; + int maxlen; + + if ((ret = asn1_sequence_from_der(&data, &datalen, in, inlen)) != 1) { + return ret; + } + + if ((ret = asn1_boolean_from_der(is_ca_cert, &data, &datalen)) < 0) { + error_print(); + return -1; + } else if (ret == 0) { + *is_ca_cert = -1; + } + + if ((ret = asn1_int_from_der(&maxlen, &data, &datalen)) < 0 + || datalen > 0) { + error_print(); + return -1; + } else if (ret == 0) { + *cert_chain_maxlen = -1; + } else { + if (maxlen > 6) { + error_print(); + return -1; + } + *cert_chain_maxlen = (int)maxlen; + } + return 1; +} + +int x509_basic_constraints_print(FILE *fp, const uint8_t *data, size_t datalen, int format, int indent) +{ + int is_ca_cert; + int cert_chain_maxlen; + + if (x509_basic_constraints_from_der(&is_ca_cert, &cert_chain_maxlen, &data, &datalen) != 1) { + error_print(); + return -1; + } + if (datalen) { + error_print(); + return -1; + } + if (is_ca_cert >= 0) { + fprintf(fp, "cA : %s\n", is_ca_cert ? "true" : "false"); + } + if (cert_chain_maxlen >= 0) { + fprintf(fp, "pathLenConstraint : %d\n", cert_chain_maxlen); + } + return 1; +} + + + + + + + + + +/* +10 +GeneralSubtrees ::= SEQUENCE SIZE (1..MAX) OF GeneralSubtree + +GeneralSubtree ::= SEQUENCE { + base GeneralName, + minimum [0] IMPLICIT INTEGER (0..MAX) DEFAULT 0, + maximum [1] IMPLICIT INTEGER (0..MAX) OPTIONAL } + + + 这里还是要用到GeneralName,这个类型非常难处理 + + 如果比较难构造,是否我们目前只支持解析,不支持构造呢? + + + 这个比较复杂的是其中的两个元素都是SEQUENCE OF SEQUENCE, + 这意味着我们必须对这种常见的形式给出一个统一的解析方案 + +*/ + + + +int x509_general_subtree_to_der( + int base_choise, const uint8_t *base_data, size_t base_datalen, + int minimum, + int maximum, + uint8_t **out, size_t *outlen) +{ + size_t len = 0; + + x509_general_name_to_der(base_choise, base_data, base_datalen, NULL, &len); + asn1_implicit_int_to_der(0, minimum, NULL, &len); + asn1_implicit_int_to_der(1, maximum, NULL, &len); + + asn1_sequence_header_to_der(len, out, outlen); + + x509_general_name_to_der(base_choise, base_data, base_datalen, out, outlen); + asn1_implicit_int_to_der(0, minimum, out, outlen); + asn1_implicit_int_to_der(1, maximum, out, outlen); + + return 1; +} + +int x509_general_subtree_from_der( + int *base_choice, const uint8_t **base_data, size_t *base_datalen, + int *minimum, + int *maximum, + const uint8_t **in, size_t *inlen) +{ + int ret; + const uint8_t *data; + size_t datalen; + + if ((ret = asn1_sequence_from_der(&data, &datalen, in, inlen)) != 1) { + if (ret < 0) error_print(); + return ret; + } + if (x509_general_name_from_der(base_choice, base_data, base_datalen, &data, &datalen) != 1 + || asn1_implicit_int_from_der(0, minimum, &data, &datalen) < 0 + || asn1_implicit_int_from_der(1, maximum, &data, &datalen) < 0 + || datalen > 0) { + error_print(); + return ret; + } + + return 1; +} + +/* +NameConstraints ::= SEQUENCE { + permittedSubtrees [0] GeneralSubtrees OPTIONAL, + excludedSubtrees [1] GeneralSubtrees OPTIONAL } +*/ +int x509_name_constraints_to_der( + const X509_GENERAL_SUBTREES *permitted_subtrees, + const X509_GENERAL_SUBTREES *excluded_subtrees, + uint8_t **out, size_t *outlen) +{ + size_t len = 0; + + x509_general_subtrees_to_der(permitted_subtrees, NULL, &len); + x509_general_subtrees_to_der(excluded_subtrees, NULL, &len); + + asn1_sequence_header_to_der(len, out, outlen); + x509_general_subtrees_to_der(permitted_subtrees, out, outlen); + x509_general_subtrees_to_der(excluded_subtrees, out, outlen); + + return 1; +} + +int x509_name_constraints_from_der( + X509_GENERAL_SUBTREES *permitted_subtrees, + X509_GENERAL_SUBTREES *excluded_subtrees, + const uint8_t **in, size_t *inlen) +{ + int ret; + const uint8_t *data; + size_t datalen; + + + if ((ret = asn1_sequence_from_der(&data, &datalen, in, inlen)) != 1) { + if (ret < 0) error_print(); + return ret; + } + + if (x509_general_subtrees_from_der(permitted_subtrees, &data, &datalen) < 0 + || x509_general_subtrees_from_der(excluded_subtrees, &data, &datalen) < 0 + || datalen > 0) { + error_print(); + return -1; + } + + return 1; +} + + +/* +11 +PolicyConstraints ::= SEQUENCE { + requireExplicitPolicy [0] IMPLICIT INTEGER (0..MAX) OPTIONAL, + inhibitPolicyMapping [1] IMPLICIT INTEGER (0..MAX) OPTIONAL +} + +Conforming CAs MUST mark this extension as critical. +*/ +int x509_policy_constraints_to_der(int require_explicit_policy, int inhibit_policy_mapping, uint8_t **out, size_t *outlen) +{ + size_t len = 0; + + asn1_implicit_int_to_der(0, require_explicit_policy, NULL, &len); + asn1_implicit_int_to_der(1, inhibit_policy_mapping, NULL, &len); + + asn1_sequence_header_to_der(len, out, outlen); + + asn1_implicit_int_to_der(0, require_explicit_policy, out, outlen); + asn1_implicit_int_to_der(1, inhibit_policy_mapping, out, outlen); + + return 1; +} + +int x509_policy_constraints_from_der(int *require_explicit_policy, int *inhibit_policy_mapping, const uint8_t **in, size_t *inlen) +{ + int ret; + const uint8_t *data; + size_t datalen; + + if ((ret = asn1_sequence_from_der(&data, &datalen, in, inlen)) != 1) { + if (ret < 0) error_print(); + return ret; + } + + if (asn1_implicit_int_from_der(0, require_explicit_policy, &data, &datalen) < 0 + || asn1_implicit_int_from_der(1, inhibit_policy_mapping, &data, &datalen) < 0 + || datalen > 0) { + error_print(); + return -1; + } + + + return 1; +} + + + + +/* +12 +ExtKeyUsageSyntax ::= SEQUENCE SIZE (1..MAX) OF OBJECT IDENTIFIER + + ExtKeyUsage OIDs: + + OID_kp_serverAuth, + OID_kp_clientAuth, + OID_kp_codeSigning, + OID_kp_emailProtection, + OID_kp_timeStamping, + OID_kp_OCSPSigning, + + +这里的问题是,有可能出现新的OID,比如微软定义的或者Google定义的 +所以在解码的时候不能假定所有的OID都是已知的 + +但是在设置的时候应该只能设置已知的OID + +解析的时候不可能只用oid来承接了,必须用带buffer的来承接 +*/ + + + +/* + +实际上我现在没有一个统一的方法去处理CHOICE类型的设置和解析 +首先是否要给一个CHOICE类型设置一个新的对象,按照我们的设置,如果设置的话,就需要这个对象能够承载内部数据 + + +13 + + CRLDistributionPoints ::= SEQUENCE SIZE (1..MAX) OF DistributionPoint + + ReasonFlags ::= BIT STRING { + unused (0), + keyCompromise (1), + cACompromise (2), + affiliationChanged (3), + superseded (4), + cessationOfOperation (5), + certificateHold (6), + privilegeWithdrawn (7), + aACompromise (8) } + +*/ + + +/* +DistributionPointName ::= CHOICE { + fullName [0] IMPLICIT GeneralNames, + nameRelativeToCRLIssuer [1] IMPLICIT RelativeDistinguishedName } + + GeneralNames 类型为 SEQUENCE OF + RelativeDistinguishedName 类型为 SET OF + 因此需要为 DistributionPointName 建立一个新类型 + + 这两个类型实际上都是 SEQUENCE OF/SET OF + + 因为GeneralNames是一个类型,因此污染了X509_CRL_DISTRIBUTION_POINT_NAME + + +*/ + +int x509_distribution_point_name_to_der(const X509_DISTRIBUTION_POINT_NAME *a, uint8_t **out, size_t *outlen) +{ + + return 1; +} + +int x509_distribution_point_name_from_der(X509_DISTRIBUTION_POINT_NAME *a, const uint8_t **in, size_t *inlen) +{ + return 1; +} + +int x509_distribution_point_to_der( // DistributionPoint + const X509_DISTRIBUTION_POINT_NAME *dist_point_name, // [0] EXPLICIT OPTIONAL + int reason_bits, // [1] IMPLICIT OPTIONAL + const X509_GENERAL_NAMES *crl_issuer, // [2] IMPLICIT OPTIONAL + uint8_t **out, size_t *outlen) +{ + size_t len = 0; + size_t sublen = 0; + + //x509_distribution_point_name_to_der(dist_point_name, NULL, &sublen); + asn1_explicit_to_der(0, NULL, sublen, NULL, &len); + asn1_implicit_bits_to_der(1, reason_bits, NULL, &len); + x509_implicit_general_names_to_der(2, crl_issuer, NULL, &len); + + asn1_sequence_header_to_der(len, out, outlen); + asn1_explicit_header_to_der(0, sublen, out, outlen); + x509_distribution_point_name_to_der(dist_point_name, out, outlen); + asn1_implicit_bits_to_der(1, reason_bits, out, outlen); + x509_implicit_general_names_to_der(2, crl_issuer, out, outlen); + + return 1; +} + +int x509_distribution_point_from_der( + X509_DISTRIBUTION_POINT_NAME *dist_point_name, + int *reason_bits, + X509_GENERAL_NAMES *crl_issuer, + const uint8_t **in, size_t *inlen) +{ + int ret; + const uint8_t *data; + size_t datalen; + const uint8_t *subdata; + size_t subdatalen; + + if ((ret = asn1_sequence_from_der(&data, &datalen, in, inlen)) != 1) { + if (ret < 0) error_print(); + return ret; + } + + if (asn1_explicit_from_der(0, &subdata, &subdatalen, &data, &datalen) < 0 + || x509_distribution_point_name_from_der(dist_point_name, &subdata, &subdatalen) != 1 + || subdatalen > 0 + //|| asn1_implicit_bit_string_from_der(1, reason_bits, &data, &datalen) < 0 + || x509_implicit_general_names_from_der(2, crl_issuer, &data, &datalen) < 0 + || datalen > 0) { + error_print(); + return -1; + } + + return 1; +} + +/* + + CRLDistributionPoints ::= SEQUENCE SIZE (1..MAX) OF DistributionPoint + +*/ + + + + + +/* +14 +InhibitAnyPolicy ::= INTEGER (0..MAX) + +Conforming CAs MUST mark this extension as critical. +*/ + + + +/* +15 +FreshestCRL ::= CRLDistributionPoints +MUST be marked as non-critical by conforming CAs. +*/ + + + + + + + + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Public APIs +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + +struct { + int oid; + int is_critical; + int tag; +} x509_exts[] = { + { OID_ce_authorityKeyIdentifier, 1, ASN1_TAG_SEQUENCE }, + { OID_ce_subjectKeyIdentifier, 1, ASN1_TAG_OCTET_STRING }, + { OID_ce_keyUsage, 1, ASN1_TAG_BIT_STRING }, + { OID_ce_certificatePolicies, 1, ASN1_TAG_SEQUENCE }, + { OID_ce_policyMappings, 1, ASN1_TAG_SEQUENCE }, + { OID_ce_subjectAltName, 1, ASN1_TAG_SEQUENCE }, + { OID_ce_issuerAltName, 1, ASN1_TAG_SEQUENCE }, + { OID_ce_subjectDirectoryAttributes, 1, ASN1_TAG_SEQUENCE }, + { OID_ce_basicConstraints, 1, ASN1_TAG_SEQUENCE }, + { OID_ce_nameConstraints, 1, ASN1_TAG_SEQUENCE }, + { OID_ce_policyConstraints, 1, ASN1_TAG_SEQUENCE }, + { OID_ce_extKeyUsage, 1, ASN1_TAG_SEQUENCE }, + { OID_ce_crlDistributionPoints, 1, ASN1_TAG_SEQUENCE }, + { OID_ce_inhibitAnyPolicy, 1, ASN1_TAG_INTEGER }, + { OID_ce_freshestCRL, 1, ASN1_TAG_SEQUENCE }, +}; + + + + +int x509_certificate_set_authority_key_identifier(X509_CERTIFICATE *cert, + int is_critical, + const uint8_t *keyid, size_t keyid_len, + const X509_GENERAL_NAMES *issuer, + const uint8_t *serial_number, size_t serial_number_len) +{ + int oid = OID_ce_authorityKeyIdentifier; + uint8_t data[1024]; + uint8_t *p = data; + size_t datalen = 0; + + if (x509_authority_key_identifier_to_der(keyid, keyid_len, issuer, serial_number, serial_number_len, &p, &datalen) != 1 + || x509_certificate_add_extension(cert, oid, is_critical, data, datalen) != 1) { + error_print(); + return -1; + } + return 1; +} + +int x509_certificate_set_subject_key_identifier(X509_CERTIFICATE *cert, + int is_critical, + const uint8_t *keyid, size_t keyid_len) +{ + int oid = OID_ce_subjectKeyIdentifier; + uint8_t data[1024]; + uint8_t *p = data; + size_t datalen = 0; + + if (asn1_octet_string_to_der(keyid, keyid_len, &p, &datalen) != 1 + || x509_certificate_add_extension(cert, oid, is_critical, data, datalen) != 1) { + error_print(); + return -1; + } + return 1; +} + +int x509_certificate_generate_subject_key_identifier(X509_CERTIFICATE *cert, int is_critical) +{ + uint8_t keyid[32]; + sm2_public_key_digest(&cert->tbs_certificate.subject_public_key_info.sm2_key, keyid); + x509_certificate_set_subject_key_identifier(cert, is_critical, keyid, sizeof(keyid)); + return 1; +} + +int x509_subject_key_identifier_print(FILE *fp, const uint8_t *data, size_t datalen, int format, int indent) +{ + const uint8_t *keyid; + size_t keyidlen; + if (asn1_octet_string_from_der(&keyid, &keyidlen, &data, &datalen) != 1 + || datalen) { + error_print(); + return -1; + } + format_bytes(fp, format, indent, "", keyid, keyidlen); + return 1; +} + +int x509_certificate_set_key_usage(X509_CERTIFICATE *cert, + int is_critical, + int usages) +{ + int oid = OID_ce_keyUsage; + uint8_t data[32]; + uint8_t *p = data; + size_t datalen = 0; + +/* + if (//asn1_bits_to_der(usages, &p, &datalen) != 1 + || x509_certificate_add_extension(cert, oid, is_critical, data, datalen) != 1) { + error_print(); + return -1; + } +*/ + return 1; +} + +int x509_certificate_set_certificate_policies(X509_CERTIFICATE *cert, + int is_critical, + const X509_CERTIFICATE_POLICIES *policies) +{ + int oid = OID_ce_certificatePolicies; + uint8_t data[1024]; + uint8_t *p = data; + size_t datalen = 0; + + if (x509_certificate_policies_to_der(policies, &p, &datalen) != 1 + || x509_certificate_add_extension(cert, oid, is_critical, data, datalen) != 1) { + error_print(); + return -1; + } + return 1; +} + +int x509_certificate_set_policy_mappings(X509_CERTIFICATE *cert, + int is_critical, + const X509_POLICY_MAPPINGS *mappings) +{ + int oid = OID_ce_policyMappings; + uint8_t data[1024]; + uint8_t *p = data; + size_t datalen = 0; + + if (x509_policy_mappings_to_der(mappings, &p, &datalen) != 1 + || x509_certificate_add_extension(cert, oid, is_critical, data, datalen) != 1) { + error_print(); + return -1; + } + return 1; +} + +int x509_certificate_set_subject_alt_name(X509_CERTIFICATE *cert, + int is_critical, + const X509_GENERAL_NAMES *name) +{ + int oid = OID_ce_subjectAltName; + uint8_t data[1024]; + uint8_t *p = data; + size_t datalen = 0; + + if (x509_general_names_to_der(name, &p, &datalen) != 1 + || x509_certificate_add_extension(cert, oid, is_critical, data, datalen) != 1) { + error_print(); + return -1; + } + return 1; +} + +int x509_certificate_set_issuer_alt_name(X509_CERTIFICATE *cert, + int is_critical, + const X509_GENERAL_NAMES *name) +{ + int oid = OID_ce_issuerAltName; + uint8_t data[1024]; + uint8_t *p = data; + size_t datalen = 0; + + if (x509_general_names_to_der(name, &p, &datalen) != 1 + || x509_certificate_add_extension(cert, oid, is_critical, data, datalen) != 1) { + error_print(); + return -1; + } + return 1; +} + +int x509_certificate_set_subject_directory_attributes(X509_CERTIFICATE *cert, + int is_critical, + const X509_ATTRIBUTES *attrs) +{ + int oid = OID_ce_subjectDirectoryAttributes; + uint8_t data[1024]; + uint8_t *p = data; + size_t datalen = 0; + + if (x509_attributes_to_der(attrs, &p, &datalen) != 1 + || x509_certificate_add_extension(cert, oid, is_critical, data, datalen) != 1) { + error_print(); + return -1; + } + return 1; +} + +int x509_certificate_set_basic_constraints(X509_CERTIFICATE *cert, + int is_critical, + int is_ca_cert, + int cert_chain_maxlen) +{ + int oid = OID_ce_basicConstraints; + uint8_t data[1024]; + uint8_t *p = data; + size_t datalen = 0; + + if (x509_basic_constraints_to_der(is_ca_cert, cert_chain_maxlen, &p, &datalen) != 1 + || x509_certificate_add_extension(cert, oid, is_critical, data, datalen) != 1) { + error_print(); + return -1; + } + return 1; +} + +int x509_certificate_set_name_constraints(X509_CERTIFICATE *cert, + int is_critical, + const X509_GENERAL_SUBTREES *permitted_subtrees, + const X509_GENERAL_SUBTREES *excluded_subtrees) +{ + int oid = OID_ce_nameConstraints; + uint8_t data[1024]; + uint8_t *p = data; + size_t datalen = 0; + + if (x509_name_constraints_to_der(permitted_subtrees, excluded_subtrees, &p, &datalen) != 1 + || x509_certificate_add_extension(cert, oid, is_critical, data, datalen) != 1) { + error_print(); + return -1; + } + return 1; +} + +int x509_certificate_set_policy_constraints(X509_CERTIFICATE *cert, + int is_critical, + int require_explicit_policy, + int inhibit_policy_mapping) +{ + int oid = OID_ce_policyConstraints; + uint8_t data[1024]; + uint8_t *p = data; + size_t datalen = 0; + + if (x509_policy_constraints_to_der(require_explicit_policy, inhibit_policy_mapping, &p, &datalen) != 1 + || x509_certificate_add_extension(cert, oid, is_critical, data, datalen) != 1) { + error_print(); + return -1; + } + return 1; +} + +int x509_certificate_set_ext_key_usage(X509_CERTIFICATE *cert, + int is_critical, + const int *key_purpose_oids, size_t key_purpose_oids_count) +{ + int oid = OID_ce_extKeyUsage; + uint8_t data[1024]; + uint8_t *p = data; + size_t datalen = 0; + + if (x509_ext_key_usage_to_der(key_purpose_oids, key_purpose_oids_count, &p, &datalen) != 1 + || x509_certificate_add_extension(cert, oid, is_critical, data, datalen) != 1) { + error_print(); + return -1; + } + return 1; +} + +int x509_certificate_set_crl_distribution_points(X509_CERTIFICATE *cert, + int is_critical, + const X509_CRL_DISTRIBUTION_POINTS *crl_dist_points) +{ + int oid = OID_ce_crlDistributionPoints; + uint8_t data[1024]; + uint8_t *p = data; + size_t datalen = 0; + + if (x509_crl_distribution_points_to_der(crl_dist_points, &p, &datalen) != 1 + || x509_certificate_add_extension(cert, oid, is_critical, data, datalen) != 1) { + error_print(); + return -1; + } + return 1; +} + +int x509_certificate_set_inhibit_any_policy(X509_CERTIFICATE *cert, + int is_critical, + int skip_certs) +{ + int oid = OID_ce_inhibitAnyPolicy; + uint8_t data[16]; + uint8_t *p = data; + size_t datalen = 0; + + if (asn1_int_to_der(skip_certs, &p, &datalen) != 1 + || x509_certificate_add_extension(cert, oid, is_critical, data, datalen) != 1) { + error_print(); + return -1; + } + return 1; +} + +int x509_certificate_set_freshest_crl(X509_CERTIFICATE *cert, + int is_critical, + const X509_CRL_DISTRIBUTION_POINTS *crl_dist_points) +{ + int oid = OID_ce_freshestCRL; + uint8_t data[1024]; + uint8_t *p = data; + size_t datalen = 0; + + if (x509_crl_distribution_points_to_der(crl_dist_points, &p, &datalen) != 1 + || x509_certificate_add_extension(cert, oid, is_critical, data, datalen) != 1) { + error_print(); + return -1; + } + return 1; +} + +// x509_certificate_get_[extension_name] +// return values: +// ret == 0 no such extension +// ret < 0 error +// ret == 1 ok + + +int x509_certificate_get_authority_key_identifier(const X509_CERTIFICATE *cert, + int *is_critical, + const uint8_t **keyid, size_t *keyid_len, + X509_GENERAL_NAMES *issuer, + const uint8_t **serial_number, size_t *serial_number_len) +{ + int oid = OID_ce_authorityKeyIdentifier; + int ret; + const uint8_t *data; + size_t datalen; + + if ((ret = x509_certificate_get_extension_from_oid(cert, oid, is_critical, &data, &datalen)) != 1) { + if (ret < 0) error_print(); + return ret; + } + if (x509_authority_key_identifier_from_der(keyid, keyid_len, issuer, serial_number, serial_number_len, &data, &datalen) != 1 + || datalen > 0) { + error_print(); + return -1; + } + return 1; +} + +int x509_certificate_get_subject_key_identifier(const X509_CERTIFICATE *cert, + int *is_critical, + const uint8_t **keyid, size_t *keyid_len) +{ + int oid = OID_ce_subjectKeyIdentifier; + int ret; + const uint8_t *data; + size_t datalen; + + if ((ret = x509_certificate_get_extension_from_oid(cert, oid, is_critical, &data, &datalen)) != 1) { + if (ret < 0) error_print(); + return ret; + } + if (asn1_octet_string_from_der(keyid, keyid_len, &data, &datalen) != 1 + || datalen > 0) { + error_print(); + return -1; + } + if (*keyid_len <= 0) { + error_print(); + return -1; + } + return 1; +} + +int x509_certificate_get_key_usage(const X509_CERTIFICATE *cert, + int *is_critical, + int *usage_bits) +{ + int oid = OID_ce_keyUsage; + int ret; + const uint8_t *data; + size_t datalen; + + if ((ret = x509_certificate_get_extension_from_oid(cert, oid, is_critical, &data, &datalen)) != 1) { + if (ret < 0) error_print(); + return ret; + } + if (asn1_bits_from_der(usage_bits, &data, &datalen) != 1 + || datalen > 0) { + error_print(); + return -1; + } + // 应该检查一下bits对不对 + return 1; +} + + +#if 0 + 983 /* + 984 3 + 985 KeyUsage ::= BIT STRING { + 986 digitalSignature (0), + 987 nonRepudiation (1), -- recent editions of X.509 have + 988 -- renamed this bit to contentCommitment + 989 keyEncipherment (2), + 990 dataEncipherment (3), + 991 keyAgreement (4), + 992 keyCertSign (5), + 993 cRLSign (6), + 994 encipherOnly (7), + 995 decipherOnly (8) } + 996 */ + +#endif + + +int x509_key_usage_print(FILE *fp, const uint8_t *data, size_t datalen, int format, int indent) +{ + int usage; + if (asn1_bits_from_der(&usage, &data, &datalen) != 1) { + error_print(); + return -1; + } + format_print(fp, format, indent, "%s", usage == 0 ? "(null)" : ""); + if (usage & (1 << X509_ku_digital_signature)) fprintf(fp, "DigitalSignature, "); + if (usage & (1 << X509_ku_non_repudiation)) fprintf(fp, "NonRepudiation, "); + if (usage & (1 << X509_ku_key_encipherment)) fprintf(fp, "KeyEncipherment, "); + if (usage & (1 << X509_ku_data_encipherment)) fprintf(fp, "DataEncipherment, "); + if (usage & (1 << X509_ku_key_agreement)) fprintf(fp, "KeyAgreement, "); + if (usage & (1 << X509_ku_key_cert_sign)) fprintf(fp, "KeyCertSign, "); + if (usage & (1 << X509_ku_crl_sign)) fprintf(fp, "CRLSign, "); + if (usage & (1 << X509_ku_encipher_only)) fprintf(fp, "EncipherOnly, "); + if (usage & (1 << X509_ku_decipher_only)) fprintf(fp, "DecipherOnly, "); + // FIXME: more bits ? + fprintf(fp, "\n"); + + if (datalen) { + error_print(); + return -1; + } + return 1; +} + +int x509_certificate_get_certificate_policies(const X509_CERTIFICATE *cert, + int *is_critical, + X509_CERTIFICATE_POLICIES *policies) +{ + int oid = OID_ce_certificatePolicies; + int ret; + const uint8_t *data; + size_t datalen; + + if ((ret = x509_certificate_get_extension_from_oid(cert, oid, is_critical, &data, &datalen)) != 1) { + if (ret < 0) error_print(); + return ret; + } + if (x509_certificate_policies_from_der(policies, &data, &datalen) != 1 + || datalen > 0) { + error_print(); + return -1; + } + return 1; +} + +int x509_certificate_get_policy_mappings(const X509_CERTIFICATE *cert, + int *is_critical, + X509_POLICY_MAPPINGS *mappings) +{ + int oid = OID_ce_policyMappings; + int ret; + const uint8_t *data; + size_t datalen; + + if ((ret = x509_certificate_get_extension_from_oid(cert, oid, is_critical, &data, &datalen)) != 1) { + if (ret < 0) error_print(); + return ret; + } + if (x509_policy_mappings_from_der(mappings, &data, &datalen) != 1 + || datalen > 0) { + error_print(); + return -1; + } + return 1; +} + +int x509_certificate_get_subject_directory_attributes(const X509_CERTIFICATE *cert, + int *is_critical, + X509_ATTRIBUTES *attrs) +{ + int oid = OID_ce_subjectDirectoryAttributes; + int ret; + const uint8_t *data; + size_t datalen; + + if ((ret = x509_certificate_get_extension_from_oid(cert, oid, is_critical, &data, &datalen)) != 1) { + if (ret < 0) error_print(); + return ret; + } + if (x509_attributes_from_der(attrs, &data, &datalen) != 1 + || datalen > 0) { + error_print(); + return -1; + } + return 1; +} + +int x509_certificate_get_basic_constraints(const X509_CERTIFICATE *cert, + int *is_critical, + int *is_ca_cert, + int *cert_chain_maxlen) +{ + int oid = OID_ce_basicConstraints; + int ret; + const uint8_t *data; + size_t datalen; + + if ((ret = x509_certificate_get_extension_from_oid(cert, oid, is_critical, &data, &datalen)) != 1) { + if (ret < 0) error_print(); + return ret; + } + if (x509_basic_constraints_from_der(is_ca_cert, cert_chain_maxlen, &data, &datalen) != 1 + || datalen > 0) { + error_print(); + return -1; + } + return 1; +} + +int x509_certificate_get_name_constraints(X509_CERTIFICATE *cert, + int *is_critical, + X509_GENERAL_SUBTREES *permitted_subtrees, + X509_GENERAL_SUBTREES *excluded_subtrees) +{ + int oid = OID_ce_nameConstraints; + int ret; + const uint8_t *data; + size_t datalen; + + if ((ret = x509_certificate_get_extension_from_oid(cert, oid, is_critical, &data, &datalen)) != 1) { + if (ret < 0) error_print(); + return ret; + } + if (x509_name_constraints_from_der(permitted_subtrees, excluded_subtrees, &data, &datalen) != 1 + || datalen > 0) { + error_print(); + return -1; + } + return 1; +} + +int x509_certificate_get_policy_constraints(const X509_CERTIFICATE *cert, + int *is_critical, + int *requireExplicitPolicy, + int *inhibitPolicyMapping) +{ + int oid = OID_ce_policyConstraints; + int ret; + const uint8_t *data; + size_t datalen; + + if ((ret = x509_certificate_get_extension_from_oid(cert, oid, is_critical, &data, &datalen)) != 1) { + if (ret < 0) error_print(); + return ret; + } + if (x509_policy_constraints_from_der(requireExplicitPolicy, inhibitPolicyMapping, &data, &datalen) != 1 + || datalen > 0) { + error_print(); + } + return 1; +} + +int x509_certificate_get_ext_key_usage(const X509_CERTIFICATE *cert, + int *is_critical, + int *key_purposes, size_t *key_purposes_count) +{ + int oid = OID_ce_extKeyUsage; + int ret; + const uint8_t *data; + size_t datalen; + + if ((ret = x509_certificate_get_extension_from_oid(cert, oid, is_critical, &data, &datalen)) != 1) { + if (ret < 0) error_print(); + return ret; + } + if (x509_ext_key_usage_from_der(key_purposes, key_purposes_count, &data, &datalen) != 1 + || datalen > 0) { + error_print(); + return -1; + } + return 1; +} + +int x509_certificate_get_crl_distribution_points(const X509_CERTIFICATE *cert, + int *is_critical, + X509_CRL_DISTRIBUTION_POINTS *crl_dist_points) +{ + int oid = OID_ce_crlDistributionPoints; + int ret; + const uint8_t *data; + size_t datalen; + + if ((ret = x509_certificate_get_extension_from_oid(cert, oid, is_critical, &data, &datalen)) != 1) { + if (ret < 0) error_print(); + return ret; + } + if (x509_crl_distribution_points_from_der(crl_dist_points, &data, &datalen) != 1 + || datalen > 0) { + error_print(); + return -1; + } + return 1; +} + +int x509_certificate_get_inhibit_any_policy(const X509_CERTIFICATE *cert, + int *is_critical, + int *skip_certs) +{ + int oid = OID_ce_inhibitAnyPolicy; + int ret; + const uint8_t *data; + size_t datalen; + + if ((ret = x509_certificate_get_extension_from_oid(cert, oid, is_critical, &data, &datalen)) != 1) { + if (ret < 0) error_print(); + return ret; + } + if (asn1_int_from_der(skip_certs, &data, &datalen) != 1 + || datalen > 0) { + error_print(); + return -1; + } + return 1; +} + +int x509_certificate_get_freshest_crl(const X509_CERTIFICATE *cert, + int *is_critical, + X509_CRL_DISTRIBUTION_POINTS *crl_dist_points) +{ + int oid = OID_ce_freshestCRL; + int ret; + const uint8_t *data; + size_t datalen; + + if ((ret = x509_certificate_get_extension_from_oid(cert, oid, is_critical, &data, &datalen)) != 1) { + if (ret < 0) error_print(); + return ret; + } + if (x509_crl_distribution_points_from_der(crl_dist_points, &data, &datalen) != 1 + || datalen > 0) { + error_print(); + return -1; + } + return 1; +} diff --git a/src/x509_lib.c b/src/x509_lib.c new file mode 100644 index 00000000..18b43482 --- /dev/null +++ b/src/x509_lib.c @@ -0,0 +1,240 @@ +/* + * Copyright (c) 2014 - 2020 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + +/* +应用应该只调用这个文件中实现的接口 + +*/ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + + +int x509_certificate_set_version(X509_CERTIFICATE *cert, int version) +{ + if (version < X509_version_v1 || version > X509_version_v3) { + error_print(); + return -1; + } + cert->tbs_certificate.version = version; + return 1; +} + +int x509_certificate_set_serial_number(X509_CERTIFICATE *cert, const uint8_t *sn, size_t snlen) +{ + if (!cert || !sn || snlen <= 0 || snlen > 20) { + error_print(); + return -1; + } + memcpy(cert->tbs_certificate.serial_number, sn, snlen); + cert->tbs_certificate.serial_number_len = snlen; + return 1; +} + +int x509_certificate_set_signature_algor_sm2(X509_CERTIFICATE *cert) +{ + cert->tbs_certificate.signature_algor = OID_sm2sign_with_sm3; + cert->signature_algor = OID_sm2sign_with_sm3; + return 1; +} + +int x509_certificate_set_issuer(X509_CERTIFICATE *cert, const X509_NAME *name) +{ + memcpy(&cert->tbs_certificate.issuer, name, sizeof(X509_NAME)); + return 1; +} + +int x509_certificate_set_subject(X509_CERTIFICATE *cert, const X509_NAME *name) +{ + memcpy(&cert->tbs_certificate.subject, name, sizeof(X509_NAME)); + return 1; +} + +int x509_certificate_set_validity(X509_CERTIFICATE *cert, time_t not_before, int days) +{ + if (x509_validity_set_days(&cert->tbs_certificate.validity, not_before, days) != 1) { + error_print(); + return -1; + } + return 1; +} + +int x509_certificate_set_signature_algor(X509_CERTIFICATE *cert, int oid) +{ + cert->tbs_certificate.signature_algor = oid; + return 1; +} + +int x509_certificate_set_subject_public_key_info_sm2(X509_CERTIFICATE *cert, const SM2_KEY *sm2_key) +{ + X509_PUBLIC_KEY_INFO *pkey_info = &cert->tbs_certificate.subject_public_key_info; + x509_public_key_info_set_sm2(pkey_info, sm2_key); + return 1; +} + +int x509_certificate_set_issuer_unique_id(X509_CERTIFICATE *cert, const uint8_t *id, size_t idlen) +{ + memcpy(cert->tbs_certificate.issuer_unique_id, id, idlen); + cert->tbs_certificate.issuer_unique_id_len = idlen; + return 1; +} + +int x509_certificate_set_subject_unique_id(X509_CERTIFICATE *cert, const uint8_t *id, size_t idlen) +{ + memcpy(cert->tbs_certificate.subject_unique_id, id, idlen); + cert->tbs_certificate.subject_unique_id_len = idlen; + return 1; +} + +int x509_certificate_set_issuer_unique_id_from_public_key_sm2(X509_CERTIFICATE *cert, const SM2_KEY *sm2_key) +{ + uint8_t uniq_id[32]; + sm2_public_key_digest(sm2_key, uniq_id); + x509_certificate_set_issuer_unique_id(cert, uniq_id, sizeof(uniq_id)); + return 1; +} + +int x509_certificate_set_subject_unique_id_from_public_key_sm2(X509_CERTIFICATE *cert, const SM2_KEY *sm2_key) +{ + uint8_t uniq_id[32]; + sm2_public_key_digest(sm2_key, uniq_id); + x509_certificate_set_subject_unique_id(cert, uniq_id, sizeof(uniq_id)); + return 1; +} + + +int x509_certificate_sign_sm2(X509_CERTIFICATE *cert, const SM2_KEY *key) +{ + SM2_SIGN_CTX ctx; + uint8_t buf[1024]; + uint8_t *p = buf; + size_t len = 0; + + cert->signature_algor = OID_sm2sign_with_sm3; + x509_tbs_certificate_to_der(&cert->tbs_certificate, &p, &len); + if (sm2_sign_init(&ctx, key, SM2_DEFAULT_ID) != 1 + || sm2_sign_update(&ctx, buf, len) != 1 + || sm2_sign_finish(&ctx, cert->signature, &cert->signature_len) != 1) { + error_print(); + return -1; + } + + memset(&ctx, 0, sizeof(ctx)); + return 1; +} + +// 这个公钥应该是根据issuer name从签名的CA证书中取得的 +int x509_certificate_verify_sm2(const X509_CERTIFICATE *cert, const SM2_KEY *sm2_key) +{ + SM2_SIGN_CTX ctx; + uint8_t buf[1024]; + uint8_t *p = buf; + size_t len = 0; + + x509_tbs_certificate_to_der(&cert->tbs_certificate, &p, &len); + if (sm2_verify_init(&ctx, sm2_key, SM2_DEFAULT_ID) != 1 + || sm2_verify_update(&ctx, buf, len) != 1 + || sm2_verify_finish(&ctx, cert->signature, cert->signature_len) != 1) { + return -1; + } + + memset(&ctx, 0, sizeof(ctx)); + return 1; +} + +int x509_certificate_get_public_key_sm2(const X509_CERTIFICATE *cert, SM2_KEY *sm2_key) +{ + *sm2_key = cert->tbs_certificate.subject_public_key_info.sm2_key; + return 1; +} + + +int x509_certificate_verify_by_certificate(const X509_CERTIFICATE *cert, const X509_CERTIFICATE *cacert) +{ + int ret; + SM2_KEY ca_pubkey; + + if (x509_name_equ(&cert->tbs_certificate.issuer, &cacert->tbs_certificate.subject) != 1) { + error_print(); + return -1; + } + if (x509_certificate_get_public_key(cacert, &ca_pubkey) != 1) { + error_print(); + return -1; + } + if ((ret = x509_certificate_verify(cert, &ca_pubkey)) < 0) { + error_print(); + return -1; + } + return ret; +} + +int x509_certificate_from_pem_by_name(X509_CERTIFICATE *cert, FILE *fp, const X509_NAME *issuer) +{ + int ret; + for (;;) { + if ((ret = x509_certificate_from_pem(cert, fp)) != 1) { + if (ret < 0) error_print(); + return ret; + } + if (x509_name_equ(&cert->tbs_certificate.subject, issuer) == 1) { + return 1; + } + } + return 0; +} diff --git a/src/zuc_core.c b/src/zuc_core.c new file mode 100644 index 00000000..727b5e10 --- /dev/null +++ b/src/zuc_core.c @@ -0,0 +1,601 @@ +/* + * Copyright (c) 2015 - 2021 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + +#include +#include +#include +#include "bswap.h" + +static const ZUC_UINT15 KD[16] = { + 0x44D7,0x26BC,0x626B,0x135E,0x5789,0x35E2,0x7135,0x09AF, + 0x4D78,0x2F13,0x6BC4,0x1AF1,0x5E26,0x3C4D,0x789A,0x47AC, +}; + +static const uint8_t S0[256] = { + 0x3e,0x72,0x5b,0x47,0xca,0xe0,0x00,0x33,0x04,0xd1,0x54,0x98,0x09,0xb9,0x6d,0xcb, + 0x7b,0x1b,0xf9,0x32,0xaf,0x9d,0x6a,0xa5,0xb8,0x2d,0xfc,0x1d,0x08,0x53,0x03,0x90, + 0x4d,0x4e,0x84,0x99,0xe4,0xce,0xd9,0x91,0xdd,0xb6,0x85,0x48,0x8b,0x29,0x6e,0xac, + 0xcd,0xc1,0xf8,0x1e,0x73,0x43,0x69,0xc6,0xb5,0xbd,0xfd,0x39,0x63,0x20,0xd4,0x38, + 0x76,0x7d,0xb2,0xa7,0xcf,0xed,0x57,0xc5,0xf3,0x2c,0xbb,0x14,0x21,0x06,0x55,0x9b, + 0xe3,0xef,0x5e,0x31,0x4f,0x7f,0x5a,0xa4,0x0d,0x82,0x51,0x49,0x5f,0xba,0x58,0x1c, + 0x4a,0x16,0xd5,0x17,0xa8,0x92,0x24,0x1f,0x8c,0xff,0xd8,0xae,0x2e,0x01,0xd3,0xad, + 0x3b,0x4b,0xda,0x46,0xeb,0xc9,0xde,0x9a,0x8f,0x87,0xd7,0x3a,0x80,0x6f,0x2f,0xc8, + 0xb1,0xb4,0x37,0xf7,0x0a,0x22,0x13,0x28,0x7c,0xcc,0x3c,0x89,0xc7,0xc3,0x96,0x56, + 0x07,0xbf,0x7e,0xf0,0x0b,0x2b,0x97,0x52,0x35,0x41,0x79,0x61,0xa6,0x4c,0x10,0xfe, + 0xbc,0x26,0x95,0x88,0x8a,0xb0,0xa3,0xfb,0xc0,0x18,0x94,0xf2,0xe1,0xe5,0xe9,0x5d, + 0xd0,0xdc,0x11,0x66,0x64,0x5c,0xec,0x59,0x42,0x75,0x12,0xf5,0x74,0x9c,0xaa,0x23, + 0x0e,0x86,0xab,0xbe,0x2a,0x02,0xe7,0x67,0xe6,0x44,0xa2,0x6c,0xc2,0x93,0x9f,0xf1, + 0xf6,0xfa,0x36,0xd2,0x50,0x68,0x9e,0x62,0x71,0x15,0x3d,0xd6,0x40,0xc4,0xe2,0x0f, + 0x8e,0x83,0x77,0x6b,0x25,0x05,0x3f,0x0c,0x30,0xea,0x70,0xb7,0xa1,0xe8,0xa9,0x65, + 0x8d,0x27,0x1a,0xdb,0x81,0xb3,0xa0,0xf4,0x45,0x7a,0x19,0xdf,0xee,0x78,0x34,0x60, +}; + +static const uint8_t S1[256] = { + 0x55,0xc2,0x63,0x71,0x3b,0xc8,0x47,0x86,0x9f,0x3c,0xda,0x5b,0x29,0xaa,0xfd,0x77, + 0x8c,0xc5,0x94,0x0c,0xa6,0x1a,0x13,0x00,0xe3,0xa8,0x16,0x72,0x40,0xf9,0xf8,0x42, + 0x44,0x26,0x68,0x96,0x81,0xd9,0x45,0x3e,0x10,0x76,0xc6,0xa7,0x8b,0x39,0x43,0xe1, + 0x3a,0xb5,0x56,0x2a,0xc0,0x6d,0xb3,0x05,0x22,0x66,0xbf,0xdc,0x0b,0xfa,0x62,0x48, + 0xdd,0x20,0x11,0x06,0x36,0xc9,0xc1,0xcf,0xf6,0x27,0x52,0xbb,0x69,0xf5,0xd4,0x87, + 0x7f,0x84,0x4c,0xd2,0x9c,0x57,0xa4,0xbc,0x4f,0x9a,0xdf,0xfe,0xd6,0x8d,0x7a,0xeb, + 0x2b,0x53,0xd8,0x5c,0xa1,0x14,0x17,0xfb,0x23,0xd5,0x7d,0x30,0x67,0x73,0x08,0x09, + 0xee,0xb7,0x70,0x3f,0x61,0xb2,0x19,0x8e,0x4e,0xe5,0x4b,0x93,0x8f,0x5d,0xdb,0xa9, + 0xad,0xf1,0xae,0x2e,0xcb,0x0d,0xfc,0xf4,0x2d,0x46,0x6e,0x1d,0x97,0xe8,0xd1,0xe9, + 0x4d,0x37,0xa5,0x75,0x5e,0x83,0x9e,0xab,0x82,0x9d,0xb9,0x1c,0xe0,0xcd,0x49,0x89, + 0x01,0xb6,0xbd,0x58,0x24,0xa2,0x5f,0x38,0x78,0x99,0x15,0x90,0x50,0xb8,0x95,0xe4, + 0xd0,0x91,0xc7,0xce,0xed,0x0f,0xb4,0x6f,0xa0,0xcc,0xf0,0x02,0x4a,0x79,0xc3,0xde, + 0xa3,0xef,0xea,0x51,0xe6,0x6b,0x18,0xec,0x1b,0x2c,0x80,0xf7,0x74,0xe7,0xff,0x21, + 0x5a,0x6a,0x54,0x1e,0x41,0x31,0x92,0x35,0xc4,0x33,0x07,0x0a,0xba,0x7e,0x0e,0x34, + 0x88,0xb1,0x98,0x7c,0xf3,0x3d,0x60,0x6c,0x7b,0xca,0xd3,0x1f,0x32,0x65,0x04,0x28, + 0x64,0xbe,0x85,0x9b,0x2f,0x59,0x8a,0xd7,0xb0,0x25,0xac,0xaf,0x12,0x03,0xe2,0xf2, +}; + + +#define ADD31(a,b) a += (b); a = (a & 0x7fffffff) + (a >> 31) +#define ROT31(a,k) ((((a) << (k)) | ((a) >> (31 - (k)))) & 0x7FFFFFFF) +#define ROT32(a,k) (((a) << (k)) | ((a) >> (32 - (k)))) + +#define L1(X) \ + ((X) ^ \ + ROT32((X), 2) ^ \ + ROT32((X), 10) ^ \ + ROT32((X), 18) ^ \ + ROT32((X), 24)) + +#define L2(X) \ + ((X) ^ \ + ROT32((X), 8) ^ \ + ROT32((X), 14) ^ \ + ROT32((X), 22) ^ \ + ROT32((X), 30)) + +#define LFSRWithInitialisationMode(u) \ + V = LFSR[0]; \ + ADD31(V, ROT31(LFSR[0], 8)); \ + ADD31(V, ROT31(LFSR[4], 20)); \ + ADD31(V, ROT31(LFSR[10], 21)); \ + ADD31(V, ROT31(LFSR[13], 17)); \ + ADD31(V, ROT31(LFSR[15], 15)); \ + ADD31(V, (u)); \ + {int j; for (j=0; j<15;j++) LFSR[j]=LFSR[j+1];} \ + LFSR[15] = V + +#define LFSRWithWorkMode() \ + { \ + int j; \ + uint64_t a = LFSR[0]; \ + a += ((uint64_t)LFSR[0]) << 8; \ + a += ((uint64_t)LFSR[4]) << 20; \ + a += ((uint64_t)LFSR[10]) << 21; \ + a += ((uint64_t)LFSR[13]) << 17; \ + a += ((uint64_t)LFSR[15]) << 15; \ + a = (a & 0x7fffffff) + (a >> 31); \ + V = (a & 0x7fffffff) + (a >> 31); \ + for (j = 0; j < 15; j++) \ + LFSR[j] = LFSR[j+1]; \ + LFSR[15] = V; \ + } + +#define BitReconstruction2(X1,X2) \ + X1 = ((LFSR[11] & 0xFFFF) << 16) | (LFSR[9] >> 15); \ + X2 = ((LFSR[7] & 0xFFFF) << 16) | (LFSR[5] >> 15) + +#define BitReconstruction3(X0,X1,X2) \ + X0 = ((LFSR[15] & 0x7FFF8000) << 1) | (LFSR[14] & 0xFFFF); \ + BitReconstruction2(X1,X2) + +#define BitReconstruction4(X0,X1,X2,X3) \ + BitReconstruction3(X0,X1,X2); \ + X3 = ((LFSR[2] & 0xFFFF) << 16) | (LFSR[0] >> 15) + + +#define MAKEU31(k,d,iv) \ + (((uint32_t)(k) << 23) | \ + ((uint32_t)(d) << 8) | \ + (uint32_t)(iv)) + +#define MAKEU32(a, b, c, d) \ + (((uint32_t)(a) << 24) | \ + ((uint32_t)(b) << 16) | \ + ((uint32_t)(c) << 8) | \ + ((uint32_t)(d))) + +#define F_(X1,X2) \ + W1 = R1 + X1; \ + W2 = R2 ^ X2; \ + U = L1((W1 << 16) | (W2 >> 16)); \ + V = L2((W2 << 16) | (W1 >> 16)); \ + R1 = MAKEU32( S0[U >> 24], \ + S1[(U >> 16) & 0xFF], \ + S0[(U >> 8) & 0xFF], \ + S1[U & 0xFF]); \ + R2 = MAKEU32( S0[V >> 24], \ + S1[(V >> 16) & 0xFF], \ + S0[(V >> 8) & 0xFF], \ + S1[V & 0xFF]) + +#define F(X0,X1,X2) \ + (X0 ^ R1) + R2; \ + F_(X1, X2) + +void zuc_set_key(ZUC_KEY *key, const unsigned char *user_key, const unsigned char *iv) +{ + ZUC_UINT31 *LFSR = key->LFSR; + uint32_t R1, R2; + uint32_t X0, X1, X2; + uint32_t W, W1, W2, U, V; + int i; + + for (i = 0; i < 16; i++) { + LFSR[i] = MAKEU31(user_key[i], KD[i], iv[i]); + } + + R1 = 0; + R2 = 0; + + for (i = 0; i < 32; i++) { + BitReconstruction3(X0, X1, X2); + W = F(X0, X1, X2); + LFSRWithInitialisationMode(W >> 1); + } + + BitReconstruction2(X1, X2); + F_(X1, X2); + LFSRWithWorkMode(); + + key->R1 = R1; + key->R2 = R2; +} + +uint32_t zuc_generate_keyword(ZUC_KEY *key) +{ + ZUC_UINT31 *LFSR = key->LFSR; + uint32_t R1 = key->R1; + uint32_t R2 = key->R2; + uint32_t X0, X1, X2, X3; + uint32_t W1, W2, U, V; + uint32_t Z; + + BitReconstruction4(X0, X1, X2, X3); + Z = X3 ^ F(X0, X1, X2); + LFSRWithWorkMode(); + + key->R1 = R1; + key->R2 = R2; + + return Z; +} + +void zuc_generate_keystream(ZUC_KEY *key, size_t nwords, uint32_t *keystream) +{ + ZUC_UINT31 *LFSR = key->LFSR; + uint32_t R1 = key->R1; + uint32_t R2 = key->R2; + uint32_t X0, X1, X2, X3; + uint32_t W1, W2, U, V; + size_t i; + + for (i = 0; i < nwords; i ++) { + BitReconstruction4(X0, X1, X2, X3); + keystream[i] = X3 ^ F(X0, X1, X2); + LFSRWithWorkMode(); + } + + key->R1 = R1; + key->R2 = R2; +} + +void zuc_mac_init(ZUC_MAC_CTX *ctx, const unsigned char key[16], const unsigned char iv[16]) +{ + memset(ctx, 0, sizeof(*ctx)); + zuc_set_key((ZUC_KEY *)ctx, key, iv); + ctx->K0 = zuc_generate_keyword((ZUC_KEY *)ctx); +} + +void zuc_mac_update(ZUC_MAC_CTX *ctx, const unsigned char *data, size_t len) +{ + ZUC_UINT32 T = ctx->T; + ZUC_UINT32 K0 = ctx->K0; + ZUC_UINT32 K1, M; + ZUC_UINT31 *LFSR = ctx->LFSR; + ZUC_UINT32 R1 = ctx->R1; + ZUC_UINT32 R2 = ctx->R2; + ZUC_UINT32 X0, X1, X2, X3; + ZUC_UINT32 W1, W2, U, V; + size_t i; + + if (!data || !len) { + return; + } + + if (ctx->buflen) { + size_t num = sizeof(ctx->buf) - ctx->buflen; + if (len < num) { + memcpy(ctx->buf + ctx->buflen, data, len); + ctx->buflen += len; + return; + } + + memcpy(ctx->buf + ctx->buflen, data, num); + M = GETU32(ctx->buf); + ctx->buflen = 0; + + BitReconstruction4(X0, X1, X2, X3); + K1 = X3 ^ F(X0, X1, X2); + LFSRWithWorkMode(); + + for (i = 0; i < 32; i++) { + if (M & 0x80000000) { + T ^= K0; + } + M <<= 1; + K0 = (K0 << 1) | (K1 >> 31); + K1 <<= 1; + } + + data += num; + len -= num; + } + + while (len >= 4) { + M = GETU32(data); + + BitReconstruction4(X0, X1, X2, X3); + K1 = X3 ^ F(X0, X1, X2); + LFSRWithWorkMode(); + + for (i = 0; i < 32; i++) { + if (M & 0x80000000) { + T ^= K0; + } + M <<= 1; + K0 = (K0 << 1) | (K1 >> 31); + K1 <<= 1; + } + + data += 4; + len -= 4; + } + + if (len) { + memcpy(ctx->buf, data, len); + ctx->buflen = len; + } + ctx->R1 = R1; + ctx->R2 = R2; + ctx->K0 = K0; + ctx->T = T; +} + +void zuc_mac_finish(ZUC_MAC_CTX *ctx, const unsigned char *data, size_t nbits, unsigned char mac[4]) +{ + ZUC_UINT32 T = ctx->T; + ZUC_UINT32 K0 = ctx->K0; + ZUC_UINT32 K1, M; + ZUC_UINT31 *LFSR = ctx->LFSR; + ZUC_UINT32 R1 = ctx->R1; + ZUC_UINT32 R2 = ctx->R2; + ZUC_UINT32 X0, X1, X2, X3; + ZUC_UINT32 W1, W2, U, V; + size_t i; + + + if (!data) + nbits = 0; + + if (nbits >= 8) { + zuc_mac_update(ctx, data, nbits/8); + data += nbits/8; + nbits %= 8; + } + + T = ctx->T; + K0 = ctx->K0; + LFSR = ctx->LFSR; + R1 = ctx->R1; + R2 = ctx->R2; + + + if (nbits) + ctx->buf[ctx->buflen] = *data; + + if (ctx->buflen || nbits) { + M = GETU32(ctx->buf); + BitReconstruction4(X0, X1, X2, X3); + K1 = X3 ^ F(X0, X1, X2); + LFSRWithWorkMode(); + + for (i = 0; i < ctx->buflen * 8 + nbits; i++) { + if (M & 0x80000000) { + T ^= K0; + } + M <<= 1; + K0 = (K0 << 1) | (K1 >> 31); + K1 <<= 1; + } + } + + T ^= K0; + + BitReconstruction4(X0, X1, X2, X3); + K1 = X3 ^ F(X0, X1, X2); + LFSRWithWorkMode(); + T ^= K1; + + ctx->T = T; + PUTU32(mac, T); +} + +typedef unsigned char ZUC_UINT7; + +static const ZUC_UINT7 ZUC256_D[][16] = { + {0x22,0x2F,0x24,0x2A,0x6D,0x40,0x40,0x40, + 0x40,0x40,0x40,0x40,0x40,0x52,0x10,0x30}, + {0x22,0x2F,0x25,0x2A,0x6D,0x40,0x40,0x40, + 0x40,0x40,0x40,0x40,0x40,0x52,0x10,0x30}, + {0x23,0x2F,0x24,0x2A,0x6D,0x40,0x40,0x40, + 0x40,0x40,0x40,0x40,0x40,0x52,0x10,0x30}, + {0x23,0x2F,0x25,0x2A,0x6D,0x40,0x40,0x40, + 0x40,0x40,0x40,0x40,0x40,0x52,0x10,0x30}, +}; + +#define ZUC256_MAKEU31(a,b,c,d) \ + (((uint32_t)(a) << 23) | \ + ((uint32_t)(b) << 16) | \ + ((uint32_t)(c) << 8) | \ + (uint32_t)(d)) + + +static void zuc256_set_mac_key(ZUC_KEY *key, const unsigned char K[32], + const unsigned char IV[23], int macbits) +{ + ZUC_UINT31 *LFSR = key->LFSR; + uint32_t R1, R2; + uint32_t X0, X1, X2; + uint32_t W, W1, W2, U, V; + const ZUC_UINT7 *D; + int i; + + ZUC_UINT6 IV17 = IV[17] >> 2; + ZUC_UINT6 IV18 = ((IV[17] & 0x3) << 4) | (IV[18] >> 4); + ZUC_UINT6 IV19 = ((IV[18] & 0xf) << 2) | (IV[19] >> 6); + ZUC_UINT6 IV20 = IV[19] & 0x3f; + ZUC_UINT6 IV21 = IV[20] >> 2; + ZUC_UINT6 IV22 = ((IV[20] & 0x3) << 4) | (IV[21] >> 4); + ZUC_UINT6 IV23 = ((IV[21] & 0xf) << 2) | (IV[22] >> 6); + ZUC_UINT6 IV24 = IV[22] & 0x3f; + + D = macbits/32 < 3 ? ZUC256_D[macbits/32] : ZUC256_D[3]; + LFSR[0] = ZUC256_MAKEU31(K[0], D[0], K[21], K[16]); + LFSR[1] = ZUC256_MAKEU31(K[1], D[1], K[22], K[17]); + LFSR[2] = ZUC256_MAKEU31(K[2], D[2], K[23], K[18]); + LFSR[3] = ZUC256_MAKEU31(K[3], D[3], K[24], K[19]); + LFSR[4] = ZUC256_MAKEU31(K[4], D[4], K[25], K[20]); + LFSR[5] = ZUC256_MAKEU31(IV[0], (D[5] | IV17), K[5], K[26]); + LFSR[6] = ZUC256_MAKEU31(IV[1], (D[6] | IV18), K[6], K[27]); + LFSR[7] = ZUC256_MAKEU31(IV[10], (D[7] | IV19), K[7], IV[2]); + LFSR[8] = ZUC256_MAKEU31(K[8], (D[8] | IV20), IV[3], IV[11]); + LFSR[9] = ZUC256_MAKEU31(K[9], (D[9] | IV21), IV[12], IV[4]); + LFSR[10] = ZUC256_MAKEU31(IV[5], (D[10] | IV22), K[10], K[28]); + LFSR[11] = ZUC256_MAKEU31(K[11], (D[11] | IV23), IV[6], IV[13]); + LFSR[12] = ZUC256_MAKEU31(K[12], (D[12] | IV24), IV[7], IV[14]); + LFSR[13] = ZUC256_MAKEU31(K[13], D[13], IV[15], IV[8]); + LFSR[14] = ZUC256_MAKEU31(K[14], (D[14] | (K[31] >> 4)), IV[16], IV[9]); + LFSR[15] = ZUC256_MAKEU31(K[15], (D[15] | (K[31] & 0x0F)), K[30], K[29]); + + R1 = 0; + R2 = 0; + + for (i = 0; i < 32; i++) { + BitReconstruction3(X0, X1, X2); + W = F(X0, X1, X2); + LFSRWithInitialisationMode(W >> 1); + } + + BitReconstruction2(X1, X2); + F_(X1, X2); + LFSRWithWorkMode(); + + key->R1 = R1; + key->R2 = R2; +} + +void zuc256_set_key(ZUC_KEY *key, const unsigned char K[32], + const unsigned char IV[23]) +{ + zuc256_set_mac_key(key, K, IV, 0); +} + +void zuc256_mac_init(ZUC256_MAC_CTX *ctx, const unsigned char key[32], + const unsigned char iv[23], int macbits) +{ + if (macbits < 32) + macbits = 32; + else if (macbits > 64) + macbits = 128; + memset(ctx, 0, sizeof(*ctx)); + zuc256_set_mac_key((ZUC256_KEY *)ctx, key, iv, macbits); + zuc256_generate_keystream((ZUC256_KEY *)ctx, macbits/32, ctx->T); + zuc256_generate_keystream((ZUC256_KEY *)ctx, macbits/32, ctx->K0); + ctx->macbits = (macbits/32) * 32; +} + +void zuc256_mac_update(ZUC256_MAC_CTX *ctx, const unsigned char *data, size_t len) +{ + ZUC_UINT32 K1, M; + size_t n = ctx->macbits / 32; + size_t i, j; + + if (!data || !len) { + return; + } + + if (ctx->buflen) { + size_t num = sizeof(ctx->buf) - ctx->buflen; + if (len < num) { + memcpy(ctx->buf + ctx->buflen, data, len); + ctx->buflen += len; + return; + } + + memcpy(ctx->buf + ctx->buflen, data, num); + M = GETU32(ctx->buf); + ctx->buflen = 0; + + K1 = zuc256_generate_keyword((ZUC256_KEY *)ctx); + + for (i = 0; i < 32; i++) { + if (M & 0x80000000) { + for (j = 0; j < n; j++) { + ctx->T[j] ^= ctx->K0[j]; + } + } + M <<= 1; + for (j = 0; j < n - 1; j++) { + ctx->K0[j] = (ctx->K0[j] << 1) | (ctx->K0[j + 1] >> 31); + } + ctx->K0[j] = (ctx->K0[j] << 1) | (K1 >> 31); + K1 <<= 1; + } + + data += num; + len -= num; + } + + while (len >= 4) { + M = GETU32(data); + K1 = zuc256_generate_keyword((ZUC256_KEY *)ctx); + + for (i = 0; i < 32; i++) { + if (M & 0x80000000) { + for (j = 0; j < n; j++) { + ctx->T[j] ^= ctx->K0[j]; + } + } + M <<= 1; + for (j = 0; j < n - 1; j++) { + ctx->K0[j] = (ctx->K0[j] << 1) | (ctx->K0[j + 1] >> 31); + } + ctx->K0[j] = (ctx->K0[j] << 1) | (K1 >> 31); + K1 <<= 1; + } + + data += 4; + len -= 4; + } + + if (len) { + memcpy(ctx->buf, data, len); + ctx->buflen = len; + } +} + +void zuc256_mac_finish(ZUC256_MAC_CTX *ctx, const unsigned char *data, size_t nbits, unsigned char *mac) +{ + ZUC_UINT32 K1, M; + size_t n = ctx->macbits/32; + size_t i, j; + + + if (!data) + nbits = 0; + + if (nbits >= 8) { + zuc256_mac_update(ctx, data, nbits/8); + data += nbits/8; + nbits %= 8; + } + + if (nbits) + ctx->buf[ctx->buflen] = *data; + + if (ctx->buflen || nbits) { + M = GETU32(ctx->buf); + K1 = zuc256_generate_keyword((ZUC256_KEY *)ctx); + + + for (i = 0; i < ctx->buflen * 8 + nbits; i++) { + if (M & 0x80000000) { + for (j = 0; j < n; j++) { + ctx->T[j] ^= ctx->K0[j]; + } + } + M <<= 1; + for (j = 0; j < n - 1; j++) { + ctx->K0[j] = (ctx->K0[j] << 1) | (ctx->K0[j + 1] >> 31); + } + ctx->K0[j] = (ctx->K0[j] << 1) | (K1 >> 31); + K1 <<= 1; + } + } + + for (j = 0; j < n; j++) { + ctx->T[j] ^= ctx->K0[j]; + PUTU32(mac, ctx->T[j]); + mac += 4; + } +} diff --git a/src/zuc_eea.c b/src/zuc_eea.c new file mode 100644 index 00000000..9677639b --- /dev/null +++ b/src/zuc_eea.c @@ -0,0 +1,82 @@ +/* ==================================================================== + * Copyright (c) 2015 - 2019 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + * ==================================================================== + */ + +#include +#include + +static void zuc_set_eea_key(ZUC_KEY *key, const unsigned char user_key[16], + ZUC_UINT32 count, ZUC_UINT5 bearer, ZUC_BIT direction) +{ + unsigned char iv[16] = {0}; + iv[0] = iv[8] = count >> 24; + iv[1] = iv[9] = count >> 16; + iv[2] = iv[10] = count >> 8; + iv[3] = iv[11] = count; + iv[4] = iv[12] = ((bearer << 1) | (direction & 1)) << 2; + zuc_set_key(key, user_key, iv); +} + +void zuc_eea_encrypt(const ZUC_UINT32 *in, ZUC_UINT32 *out, size_t nbits, + const unsigned char key[16], ZUC_UINT32 count, ZUC_UINT5 bearer, + ZUC_BIT direction) +{ + ZUC_KEY zuc_key; + size_t nwords = (nbits + 31)/32; + size_t i; + + zuc_set_eea_key(&zuc_key, key, count, bearer, direction); + zuc_generate_keystream(&zuc_key, nwords, out); + for (i = 0; i < nwords; i++) { + out[i] ^= in[i]; + } + + if (nbits % 32 != 0) { + out[nwords - 1] |= (0xffffffff << (32 - (nbits%32))); + } +} diff --git a/src/zuc_eia.c b/src/zuc_eia.c new file mode 100644 index 00000000..3cac624b --- /dev/null +++ b/src/zuc_eia.c @@ -0,0 +1,159 @@ +/* ==================================================================== + * Copyright (c) 2015 - 2019 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + * ==================================================================== + */ + +#include +#include +#include +#include "bswap.h" + +static void zuc_set_eia_iv(unsigned char iv[16], ZUC_UINT32 count, ZUC_UINT5 bearer, + ZUC_BIT direction) +{ + memset(iv, 0, 16); + iv[0] = count >> 24; + iv[1] = iv[9] = count >> 16; + iv[2] = iv[10] = count >> 8; + iv[3] = iv[11] = count; + iv[4] = iv[12] = bearer << 3; + iv[8] = iv[0] ^ (direction << 7); + iv[14] = (direction << 7); +} + +#if 1 +ZUC_UINT32 zuc_eia_generate_mac(const ZUC_UINT32 *data, size_t nbits, + const unsigned char key[16], ZUC_UINT32 count, ZUC_UINT5 bearer, + ZUC_BIT direction) +{ + ZUC_MAC_CTX ctx; + unsigned char iv[16]; + unsigned char mac[4]; + zuc_set_eia_iv(iv, count, bearer, direction); + zuc_mac_init(&ctx, key, iv); + zuc_mac_finish(&ctx, (unsigned char *)data, nbits, mac); + return GETU32(mac); +} +#else + +#define ZUC_MAC_BUF_WORDS 64 + +#define GET_WORD(p, i) ((i) % 32) \ + ? ((*((ZUC_UINT32 *)(p) + (i)/32) << ((i) % 32)) \ + | (*((ZUC_UINT32 *)(p) + (i)/32 + 1) >> (32 - ((i) % 32)))) \ + : *((ZUC_UINT32 *)(p) + (i)/32) + +#define GET_BIT(p, i) \ + (((*((ZUC_UINT32 *)(p) + (i)/32)) & (1 << (31 - ((i) % 32)))) ? 1 : 0) + +ZUC_UINT32 ZUC_eia_generate_mac(const ZUC_UINT32 *data, size_t nbits, + const unsigned char user_key[16], ZUC_UINT32 count, ZUC_UINT5 bearer, + ZUC_BIT direction) +{ + ZUC_UINT32 T = 0; + ZUC_KEY key; + unsigned char iv[16]; + ZUC_UINT32 buf[ZUC_MAC_BUF_WORDS + 2]; + size_t nwords = (nbits + 31)/32; + size_t i; + size_t num = ZUC_MAC_BUF_WORDS; + + + ZUC_set_eia_iv(iv, count, bearer, direction); + ZUC_set_key(&key, user_key, iv); + + if (nwords <= ZUC_MAC_BUF_WORDS) { + ZUC_generate_keystream(&key, nwords + 2, buf); + for (i = 0; i < nbits; i++) { + if (GET_BIT(data, i)) { + T ^= GET_WORD(buf, i); + } + } + T ^= GET_WORD(buf, i); + T ^= buf[nwords + 1]; + return T; + + } else { + + ZUC_generate_keystream(&key, ZUC_MAC_BUF_WORDS + 1, buf); + for (i = 0; i < ZUC_MAC_BUF_WORDS * 32; i++) { + if (GET_BIT(data, i)) { + T ^= GET_WORD(buf, i); + } + } + data += ZUC_MAC_BUF_WORDS; + nwords -= ZUC_MAC_BUF_WORDS; + nbits -= ZUC_MAC_BUF_WORDS * 32; + } + + while (nwords > ZUC_MAC_BUF_WORDS) { + buf[0] = buf[ZUC_MAC_BUF_WORDS]; + ZUC_generate_keystream(&key, ZUC_MAC_BUF_WORDS, buf + 1); + for (i = 0; i < ZUC_MAC_BUF_WORDS * 32; i ++) { + if (GET_BIT(data, i)) { + T ^= GET_WORD(buf, i); + } + } + data += num; + nwords -= num; + nbits -= ZUC_MAC_BUF_WORDS * 32; + } + + buf[0] = buf[ZUC_MAC_BUF_WORDS]; + ZUC_generate_keystream(&key, nwords + 1, buf + 1); + for (i = 0; i < nbits; i++) { + if (GET_BIT(data, i)) { + T ^= GET_WORD(buf, i); + } + } + + T ^= GET_WORD(buf, i); + T ^= buf[nwords + 1]; + + return T; +} +#endif diff --git a/tests/aestest.c b/tests/aestest.c new file mode 100644 index 00000000..09992441 --- /dev/null +++ b/tests/aestest.c @@ -0,0 +1,187 @@ +/* + * Copyright (c) 2014 - 2020 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + + +#include +#include +#include +#include + +int main(void) +{ + int err = 0; + AES_KEY aes_key; + int i; + + /* test 1 */ + uint8_t key128[16] = { + 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, + 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c, + }; + uint32_t rk128[4 * 11] = { + 0x2b7e1516, 0x28aed2a6, 0xabf71588, 0x09cf4f3c, + 0xa0fafe17, 0x88542cb1, 0x23a33939, 0x2a6c7605, + 0xf2c295f2, 0x7a96b943, 0x5935807a, 0x7359f67f, + 0x3d80477d, 0x4716fe3e, 0x1e237e44, 0x6d7a883b, + 0xef44a541, 0xa8525b7f, 0xb671253b, 0xdb0bad00, + 0xd4d1c6f8, 0x7c839d87, 0xcaf2b8bc, 0x11f915bc, + 0x6d88a37a, 0x110b3efd, 0xdbf98641, 0xca0093fd, + 0x4e54f70e, 0x5f5fc9f3, 0x84a64fb2, 0x4ea6dc4f, + 0xead27321, 0xb58dbad2, 0x312bf560, 0x7f8d292f, + 0xac7766f3, 0x19fadc21, 0x28d12941, 0x575c006e, + 0xd014f9a8, 0xc9ee2589, 0xe13f0cc8, 0xb6630ca6, + }; + + /* test 2 */ + uint8_t key192[24] = { + 0x8e, 0x73, 0xb0, 0xf7, 0xda, 0x0e, 0x64, 0x52, + 0xc8, 0x10, 0xf3, 0x2b, 0x80, 0x90, 0x79, 0xe5, + 0x62, 0xf8, 0xea, 0xd2, 0x52, 0x2c, 0x6b, 0x7b, + }; + uint32_t rk192[4 * 13] = { + 0x8e73b0f7, 0xda0e6452, 0xc810f32b, 0x809079e5, + 0x62f8ead2, 0x522c6b7b, 0xfe0c91f7, 0x2402f5a5, + 0xec12068e, 0x6c827f6b, 0x0e7a95b9, 0x5c56fec2, + 0x4db7b4bd, 0x69b54118, 0x85a74796, 0xe92538fd, + 0xe75fad44, 0xbb095386, 0x485af057, 0x21efb14f, + 0xa448f6d9, 0x4d6dce24, 0xaa326360, 0x113b30e6, + 0xa25e7ed5, 0x83b1cf9a, 0x27f93943, 0x6a94f767, + 0xc0a69407, 0xd19da4e1, 0xec1786eb, 0x6fa64971, + 0x485f7032, 0x22cb8755, 0xe26d1352, 0x33f0b7b3, + 0x40beeb28, 0x2f18a259, 0x6747d26b, 0x458c553e, + 0xa7e1466c, 0x9411f1df, 0x821f750a, 0xad07d753, + 0xca400538, 0x8fcc5006, 0x282d166a, 0xbc3ce7b5, + 0xe98ba06f, 0x448c773c, 0x8ecc7204, 0x01002202, + }; + + /* test 3 */ + uint8_t key256[32] = { + 0x60, 0x3d, 0xeb, 0x10, 0x15, 0xca, 0x71, 0xbe, + 0x2b, 0x73, 0xae, 0xf0, 0x85, 0x7d, 0x77, 0x81, + 0x1f, 0x35, 0x2c, 0x07, 0x3b, 0x61, 0x08, 0xd7, + 0x2d, 0x98, 0x10, 0xa3, 0x09, 0x14, 0xdf, 0xf4, + }; + uint32_t rk256[4 * 15] = { + 0x603deb10, 0x15ca71be, 0x2b73aef0, 0x857d7781, + 0x1f352c07, 0x3b6108d7, 0x2d9810a3, 0x0914dff4, + 0x9ba35411, 0x8e6925af, 0xa51a8b5f, 0x2067fcde, + 0xa8b09c1a, 0x93d194cd, 0xbe49846e, 0xb75d5b9a, + 0xd59aecb8, 0x5bf3c917, 0xfee94248, 0xde8ebe96, + 0xb5a9328a, 0x2678a647, 0x98312229, 0x2f6c79b3, + 0x812c81ad, 0xdadf48ba, 0x24360af2, 0xfab8b464, + 0x98c5bfc9, 0xbebd198e, 0x268c3ba7, 0x09e04214, + 0x68007bac, 0xb2df3316, 0x96e939e4, 0x6c518d80, + 0xc814e204, 0x76a9fb8a, 0x5025c02d, 0x59c58239, + 0xde136967, 0x6ccc5a71, 0xfa256395, 0x9674ee15, + 0x5886ca5d, 0x2e2f31d7, 0x7e0af1fa, 0x27cf73c3, + 0x749c47ab, 0x18501dda, 0xe2757e4f, 0x7401905a, + 0xcafaaae3, 0xe4d59b34, 0x9adf6ace, 0xbd10190d, + 0xfe4890d1, 0xe6188d0b, 0x046df344, 0x706c631e, + }; + + /* test 4 */ + unsigned char in1[16] = { + 0x32, 0x43, 0xf6, 0xa8, 0x88, 0x5a, 0x30, 0x8d, + 0x31, 0x31, 0x98, 0xa2, 0xe0, 0x37, 0x07, 0x34, + }; + unsigned char out1[16] = { + 0x39, 0x25, 0x84, 0x1d, 0x02, 0xdc, 0x09, 0xfb, + 0xdc, 0x11, 0x85, 0x97, 0x19, 0x6a, 0x0b, 0x32, + }; + + unsigned char buf[16] = {0}; + + printf("aes test 1 "); + aes_set_encrypt_key(&aes_key, key128, sizeof(key128)); + if (memcmp(&aes_key, rk128, sizeof(rk128)) != 0) { + printf("failed\n"); + err++; + } else { + printf("ok\n"); + } + + printf("aes test 2 "); + aes_set_encrypt_key(&aes_key, key192, sizeof(key192)); + if (memcmp(&aes_key, rk192, sizeof(rk192)) != 0) { + printf("failed\n"); + err++; + } else { + printf("ok\n"); + } + + printf("aes test 3 "); + aes_set_encrypt_key(&aes_key, key256, sizeof(key256)); + if (memcmp(&aes_key, rk256, sizeof(rk256)) != 0) { + printf("failed\n"); + err++; + } else { + printf("ok\n"); + } + + printf("aes test 4 "); + aes_set_encrypt_key(&aes_key, key128, sizeof(key128)); + aes_encrypt(&aes_key, in1, buf); + if (memcmp(buf, out1, sizeof(out1)) != 0) { + printf("failed\n"); + err++; + } else { + printf("ok\n"); + } + + printf("aes test 5 "); + aes_set_decrypt_key(&aes_key, key128, sizeof(key128)); + aes_decrypt(&aes_key, buf, buf); + if (memcmp(buf, in1, sizeof(in1)) != 0) { + printf("failed\n"); + err++; + } else { + printf("ok\n"); + } + + return 0; +} diff --git a/tests/asn1test.c b/tests/asn1test.c new file mode 100644 index 00000000..f5f030bb --- /dev/null +++ b/tests/asn1test.c @@ -0,0 +1,568 @@ +/* + * Copyright (c) 2014 - 2021 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + +#include +#include +#include +#include +#include +#include + +#define BOOL_1 0 +#define BOOL_2 1 + +#define INT_1 "\x00" +#define INT_2 "\x7f" +#define INT_3 "\x80" +#define INT_4 "\xff\xf0" + +#define BITS_1 "\xff\xf0" +#define BITS_1_LEN 12 + +#define OCTETS_1 "\x12\x34\x45\x56" + +static void print_buf(const uint8_t *a, size_t len) +{ + size_t i; + for (i = 0; i < len; i++) { + printf("%02x ", a[i]); + } + printf("\n"); +} + +static void print_integer(const uint8_t *a, size_t alen) +{ + size_t i; + printf("integer = "); + for (i = 0; i < alen; i++) { + printf("%02x", a[i]); + } + printf("\n"); +} + +static void print_bits(const uint8_t *bits, size_t nbits) +{ + size_t i; + printf("bits (%zu) = ", nbits); + for (i = 0; i < (nbits + 7)/8; i++) { + printf("%02x", bits[i]); + } + printf("\n"); +} + +static void print_octets(const uint8_t *o, size_t olen) +{ + size_t i; + printf("octets (%zu) = ", olen); + for (i = 0; i < olen; i++) { + printf("%02x", o[i]); + } + printf("\n"); +} + +static int test_asn1_tag(void) +{ + int i = 0; + for (i = 0; i < 32; i++) { + printf("%s\n", asn1_tag_name(i)); + } + return 0; +} + +static int test_asn1_length(void) +{ + int err = 0; + size_t tests[] = {5, 127, 128, 256, 65537, 1<<23, (size_t)1<<31, }; + size_t val; + uint8_t buf[1024] = {0}; + uint8_t *p = buf; + const uint8_t *cp = buf; + size_t len = 0; + size_t left = ((size_t)1 << 32); + size_t i; + int rv; + + printf("%s\n", __FUNCTION__); + for (i = 0; i < sizeof(tests)/sizeof(tests[0]); i++) { + printf("%zu ", tests[i]); + } + printf("\n"); + for (i = 0; i < sizeof(tests)/sizeof(tests[0]); i++) { + asn1_length_to_der(tests[i], &p, &len); + print_buf(buf, len); + } + for (i = 0; i < sizeof(tests)/sizeof(tests[0]); i++) { + rv = asn1_length_from_der(&val, &cp, &left); + assert(rv > 0); + if (val != tests[i]) { + error_print("error decoding %zu-th length: get %zu, should be %zu", i, val, tests[i]); + err++; + } + } + + printf("\n"); + return err; +} + +static int test_asn1_boolean(void) +{ + int err = 0; + int tests[] = {0, 1}; + int val; + uint8_t buf[1024] = {0}; + uint8_t *p = buf; + const uint8_t *cp = buf; + size_t len = 0; + size_t left = sizeof(buf); + size_t i; + int rv; + + printf("%s\n", __FUNCTION__); + for (i = 0; i < sizeof(tests)/sizeof(tests[0]); i++) { + printf("%d ", tests[i]); + } + printf("\n"); + for (i = 0; i < sizeof(tests)/sizeof(tests[0]); i++) { + asn1_boolean_to_der(tests[i], &p, &len); + print_buf(buf, len); + } + for (i = 0; i < sizeof(tests)/sizeof(tests[0]); i++) { + rv = asn1_boolean_from_der(&val, &cp, &left); + assert(rv > 0); + if (val != tests[i]) { + error_print("error decoding %zu-th: get %d, should be %d", i, val, tests[i]); + err++; + } + } + + printf("\n"); + return err; +} + +static int test_asn1_integer(void) +{ + int err = 0; + int tests[] = {1, 127, 128, 65535, 65537, 1<<23, 1<<30, /* 0, -1 */ }; + int val; + uint8_t buf[1024] = {0}; + uint8_t *p = buf; + const uint8_t *cp = buf; + size_t len = 0; + size_t left = sizeof(buf); + size_t i; + int rv; + + printf("%s\n", __FUNCTION__); + for (i = 0; i < sizeof(tests)/sizeof(tests[0]); i++) { + printf("%d ", tests[i]); + } + printf("\n"); + for (i = 0; i < sizeof(tests)/sizeof(tests[0]); i++) { + asn1_int_to_der(tests[i], &p, &len); + print_buf(buf, len); + } + for (i = 0; i < sizeof(tests)/sizeof(tests[0]); i++) { + rv = asn1_int_from_der(&val, &cp, &left); + assert(rv > 0); + if (val != tests[i]) { + error_print("error decoding %zu-th: get %d, should be %d", i, val, tests[i]); + err++; + } + } + + printf("\n"); + return err; +} + +static int test_asn1_bit_string(void) +{ + int err = 0; + int tests[] = {1, 0xfe, 0xff, 0xffff, 0xfffff }; + int val; + uint8_t buf[1024] = {0}; + uint8_t *p = buf; + const uint8_t *cp = buf; + size_t len = 0; + size_t left = sizeof(buf); + size_t i; + int rv; + + printf("%s\n", __FUNCTION__); + for (i = 0; i < sizeof(tests)/sizeof(tests[0]); i++) { + printf("%d ", tests[i]); + } + printf("\n"); + for (i = 0; i < sizeof(tests)/sizeof(tests[0]); i++) { + asn1_bits_to_der(tests[i], &p, &len); + print_buf(buf, len); + } + for (i = 0; i < sizeof(tests)/sizeof(tests[0]); i++) { + rv = asn1_bits_from_der(&val, &cp, &left); + assert(rv > 0); + if (val != tests[i]) { + error_print("error decoding %zu-th: get %d, should be %d", i, val, tests[i]); + err++; + } + } + + printf("\n"); + return err; +} + +static int test_asn1_null(void) +{ + int err = 0; + int tests[6]; + uint8_t buf[1024] = {0}; + uint8_t *p = buf; + const uint8_t *cp = buf; + size_t len = 0; + size_t left = sizeof(buf); + size_t i; + int rv; + + printf("%s\n", __FUNCTION__); + for (i = 0; i < sizeof(tests)/sizeof(tests[0]); i++) { + printf("null "); + } + printf("\n"); + for (i = 0; i < sizeof(tests)/sizeof(tests[0]); i++) { + asn1_null_to_der(&p, &len); + print_buf(buf, len); + } + for (i = 0; i < sizeof(tests)/sizeof(tests[0]); i++) { + rv = asn1_null_from_der(&cp, &left); + assert(rv > 0); + } + + printf("\n"); + return err; +} + +static int test_asn1_object_identifier(void) +{ + int err = 0; + int tests[] = {1, 2, 3, 4, 5, 6}; + int val; + uint32_t nodes[32]; + size_t nodes_count; + uint8_t buf[1024] = {0}; + uint8_t *p = buf; + const uint8_t *cp = buf; + size_t len = 0; + size_t left = sizeof(buf); + size_t i; + int rv; + + printf("%s\n", __FUNCTION__); + for (i = 0; i < sizeof(tests)/sizeof(tests[0]); i++) { + printf("%d ", tests[i]); + } + printf("\n"); + for (i = 0; i < sizeof(tests)/sizeof(tests[0]); i++) { + asn1_object_identifier_to_der(tests[i], NULL, 0, &p, &len); + print_buf(buf, len); + } + for (i = 0; i < sizeof(tests)/sizeof(tests[0]); i++) { + rv = asn1_object_identifier_from_der(&val, nodes, &nodes_count, &cp, &left); + assert(rv > 0); + if (val != tests[i]) { + error_print("error decoding %zu-th: get %d, should be %d", i, val, tests[i]); + err++; + } + printf("%s\n", asn1_object_identifier_name(val)); + } + + printf("\n"); + return err; +} + +static int test_asn1_printable_string(void) +{ + int err = 0; + char *tests[] = {"hello", "world", "Just do it!"}; + const char *val; + size_t vallen; + uint32_t nodes[32]; + size_t nodes_count; + uint8_t buf[1024] = {0}; + uint8_t *p = buf; + const uint8_t *cp = buf; + size_t len = 0; + size_t left = sizeof(buf); + size_t i; + int rv; + + printf("%s\n", __FUNCTION__); + for (i = 0; i < sizeof(tests)/sizeof(tests[0]); i++) { + printf("%s\n", tests[i]); + } + for (i = 0; i < sizeof(tests)/sizeof(tests[0]); i++) { + asn1_printable_string_to_der(tests[i], &p, &len); + print_buf(buf, len); + } + for (i = 0; i < sizeof(tests)/sizeof(tests[0]); i++) { + char str[256] = {0}; + rv = asn1_printable_string_from_der(&val, &vallen, &cp, &left); + assert(rv > 0); + memcpy(str, val, vallen); + + if (strcmp(str, tests[i]) != 0) { + error_print("error decoding %zu-th: get %s, should be %s", i, str, tests[i]); + err++; + } + printf("%s\n", str); + } + + printf("\n"); + return err; +} + +static int test_asn1_utf8_string(void) +{ + int err = 0; + char *tests[] = {"hello", "world", "Just do it!"}; + const char *val; + size_t vallen; + uint32_t nodes[32]; + size_t nodes_count; + uint8_t buf[1024] = {0}; + uint8_t *p = buf; + const uint8_t *cp = buf; + size_t len = 0; + size_t left = sizeof(buf); + size_t i; + int rv; + + printf("%s\n", __FUNCTION__); + for (i = 0; i < sizeof(tests)/sizeof(tests[0]); i++) { + printf("%s\n", tests[i]); + } + for (i = 0; i < sizeof(tests)/sizeof(tests[0]); i++) { + asn1_utf8_string_to_der(tests[i], &p, &len); + print_buf(buf, len); + } + for (i = 0; i < sizeof(tests)/sizeof(tests[0]); i++) { + char str[256] = {0}; + rv = asn1_utf8_string_from_der(&val, &vallen, &cp, &left); + assert(rv > 0); + memcpy(str, val, vallen); + + if (strcmp(str, tests[i]) != 0) { + error_print("error decoding %zu-th: get %s, should be %s", i, str, tests[i]); + err++; + } + printf("%s\n", str); + } + + printf("\n"); + return err; +} + +static int test_asn1_ia5_string(void) +{ + int err = 0; + char *tests[] = {"hello", "world", "Just do it!"}; + const char *val; + size_t vallen; + uint32_t nodes[32]; + size_t nodes_count; + uint8_t buf[1024] = {0}; + uint8_t *p = buf; + const uint8_t *cp = buf; + size_t len = 0; + size_t left = sizeof(buf); + size_t i; + int rv; + + printf("%s\n", __FUNCTION__); + for (i = 0; i < sizeof(tests)/sizeof(tests[0]); i++) { + printf("%s\n", tests[i]); + } + for (i = 0; i < sizeof(tests)/sizeof(tests[0]); i++) { + asn1_ia5_string_to_der(tests[i], &p, &len); + print_buf(buf, len); + } + for (i = 0; i < sizeof(tests)/sizeof(tests[0]); i++) { + char str[256] = {0}; + rv = asn1_ia5_string_from_der(&val, &vallen, &cp, &left); + assert(rv > 0); + memcpy(str, val, vallen); + + if (strcmp(str, tests[i]) != 0) { + error_print("error decoding %zu-th: get %s, should be %s", i, str, tests[i]); + err++; + } + printf("%s\n", str); + } + + printf("\n"); + return err; +} + +static int test_time(void) +{ + time_t tval = 0; + printf("%s", ctime(&tval)); + time(&tval); + printf("%s", ctime(&tval)); + printf("%016llx\n", (uint64_t)tval); + + + return 0; +} + +static int test_asn1_utc_time(void) +{ + int err = 0; + time_t tests[] = {0, 0, 1<<30 }; + time_t val; + uint8_t buf[1024] = {0}; + uint8_t *p = buf; + const uint8_t *cp = buf; + size_t len = 0; + size_t left = sizeof(buf); + size_t i; + int rv; + + time(&tests[0]); + + printf("%s\n", __FUNCTION__); + for (i = 0; i < sizeof(tests)/sizeof(tests[0]); i++) { + printf("%s", ctime(&tests[i])); + } + for (i = 0; i < sizeof(tests)/sizeof(tests[0]); i++) { + asn1_utc_time_to_der(tests[i], &p, &len); + print_buf(buf, len); + } + for (i = 0; i < sizeof(tests)/sizeof(tests[0]); i++) { + rv = asn1_utc_time_from_der(&val, &cp, &left); + assert(rv > 0); + if (val != tests[i]) { + error_print("error decoding %zu-th: get %zu, should be %zu", i, val, tests[i]); + err++; + } + printf("%s", ctime(&val)); + } + + printf("\n"); + return err; +} + +static int test_asn1_generalized_time(void) +{ + int err = 0; + time_t tests[] = {0, 1<<30}; + time_t val; + uint8_t buf[1024] = {0}; + uint8_t *p = buf; + const uint8_t *cp = buf; + size_t len = 0; + size_t left = sizeof(buf); + size_t i; + int rv; + + time(&tests[0]); + + printf("%s\n", __FUNCTION__); + for (i = 0; i < sizeof(tests)/sizeof(tests[0]); i++) { + printf("%s", ctime(&tests[i])); + } + for (i = 0; i < sizeof(tests)/sizeof(tests[0]); i++) { + asn1_generalized_time_to_der(tests[i], &p, &len); + print_buf(buf, len); + } + + + for (i = 0; i < sizeof(tests)/sizeof(tests[0]); i++) { + rv = asn1_generalized_time_from_der(&val, &cp, &left); + assert(rv > 0); + if (val != tests[i]) { + error_print("error decoding %zu-th: get %zu, should be %zu", i, val, tests[i]); + err++; + } + printf("%s", ctime(&val)); + } + + printf("\n"); + return err; +} + + + + + + + + + + + + + + + + +int main(void) +{ + int err = 0; + err += test_asn1_tag(); + err += test_asn1_length(); + err += test_asn1_boolean(); + err += test_asn1_integer(); + //err += test_asn1_bit_string(); + err += test_asn1_null(); + err += test_asn1_object_identifier(); + err += test_asn1_printable_string(); + err += test_asn1_utf8_string(); + err += test_asn1_ia5_string(); + err += test_asn1_utc_time(); + err += test_asn1_generalized_time(); + + return err; +} diff --git a/tests/base64test.c b/tests/base64test.c new file mode 100644 index 00000000..97b0c69a --- /dev/null +++ b/tests/base64test.c @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2014 - 2021 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + + +#include +#include +#include +#include +#include + +int test_base64(void) +{ + uint8_t bin1[50]; + uint8_t bin2[100]; + uint8_t bin3[200]; + uint8_t buf1[8000] = {0}; + uint8_t buf2[8000] = {0}; + + int err = 0; + BASE64_CTX ctx; + uint8_t *p; + int len; + + memset(bin1, 0x01, sizeof(bin1)); + memset(bin2, 0xA5, sizeof(bin2)); + memset(bin3, 0xff, sizeof(bin3)); + + + p = buf1; + base64_encode_init(&ctx); + base64_encode_update(&ctx, bin1, sizeof(bin1), p, &len); p += len; + base64_encode_update(&ctx, bin2, sizeof(bin2), p, &len); p += len; + base64_encode_update(&ctx, bin3, sizeof(bin3), p, &len); p += len; + base64_encode_finish(&ctx, p, &len); p += len; + len = (int)(p - buf1); + printf("%s\n", buf1); + + + p = buf2; + base64_decode_init(&ctx); + base64_decode_update(&ctx, buf1, len, p, &len); p += len; + base64_decode_finish(&ctx, p, &len); p += len; + len = (int)(p - buf2); + + printf("len = %d\n", len); + print_der(buf2, len); + printf("\n"); + + return err; +} + +int main(void) +{ + test_base64(); + return 0; +} + + + + + + + + + diff --git a/tests/block_ciphertest.c b/tests/block_ciphertest.c new file mode 100644 index 00000000..2887386f --- /dev/null +++ b/tests/block_ciphertest.c @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2014 - 2020 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + +#include +#include +#include +#include + + +int block_cipher_sm4_test(void) +{ + static char *iv_hex[] = { + "A9993E364706816ABA3E25717850C26C9CD0D89D", + "A9993E364706816ABA3E25717850C26C9CD0D89D", + }; + + // 提供256比特的密钥长度 + static char *key_hex[] = { + }; + + static char *plaintext_hex[] = { + }; + + static char *ciphertext_hex[] = { + }; + + const BLOCK_CIPEHR *cipher; + BLOCK_CIPHER_KEY cipher_key; + uint8_t key[32]; + uint8_t iv[16]; + uint8_t plaintext[16 * 3]; + uint8_t ciphertext[16 * 4]; + uint8_t buf[16 * 4]; + + for (i = 0; i < NUM_TESTS; i++) { + hex2bin(key_hex, strlen(key_hex), key); + hex2bin(iv_hex, strlen(iv_hex), iv); + hex2bin(plaintext_hex, strlen(plaintext_hex), plaintext); + hex2bin(ciphertext_hex, strlen(ciphertext_hex), ciphertext); + + block_cipher_set_encrypt_key(&cipher_key, cipher, key, 16, iv); + block_cipher_cbc_encrypt(&cipher_key, iv, plaintext, 3, buf); + + if (memcmp(buf, 16 * 3, ciphertext) != 0) { + } + } + + return 0; +} diff --git a/tests/chacha20test.c b/tests/chacha20test.c new file mode 100644 index 00000000..3a61a5fd --- /dev/null +++ b/tests/chacha20test.c @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2014 - 2020 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + + +#include +#include +#include +#include + + +int main(void) +{ + int e = 0, i; + const unsigned char key[] = { + 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, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + }; + const unsigned char nonce[] = { + 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x4a, + 0x00, 0x00, 0x00, 0x00, + }; + uint32_t counter = 1; + const unsigned char testdata[] = { + 0x10, 0xf1, 0xe7, 0xe4, 0xd1, 0x3b, 0x59, 0x15, + 0x50, 0x0f, 0xdd, 0x1f, 0xa3, 0x20, 0x71, 0xc4, + 0xc7, 0xd1, 0xf4, 0xc7, 0x33, 0xc0, 0x68, 0x03, + 0x04, 0x22, 0xaa, 0x9a, 0xc3, 0xd4, 0x6c, 0x4e, + 0xd2, 0x82, 0x64, 0x46, 0x07, 0x9f, 0xaa, 0x09, + 0x14, 0xc2, 0xd7, 0x05, 0xd9, 0x8b, 0x02, 0xa2, + 0xb5, 0x12, 0x9c, 0xd1, 0xde, 0x16, 0x4e, 0xb9, + 0xcb, 0xd0, 0x83, 0xe8, 0xa2, 0x50, 0x3c, 0x4e, + }; + unsigned char buf[64]; + + CHACHA20_STATE state; + chacha20_set_key(&state, key, nonce, counter); + chacha20_generate_keystream(&state, 1, buf); + + if (memcmp(buf, testdata, sizeof(testdata)) != 0) { + printf("chacha20 test 1 failed\n"); + } else { + printf("chacha20 test 1 ok\n"); + } + + return 0; +} + diff --git a/tests/cmstest.c b/tests/cmstest.c new file mode 100644 index 00000000..9680a8a3 --- /dev/null +++ b/tests/cmstest.c @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2021 - 2021 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +static int test_cms_data(void) +{ + uint8_t data[20]; + uint8_t content_info[512]; + size_t content_info_len = sizeof(content_info); + size_t len = 0; + int i; + + memset(data, 'A', sizeof(data)); + + cms_content_info_set_data(content_info, &content_info_len, data, sizeof(data)); + cms_content_info_print(stdout, content_info, content_info_len, 0, 0); + return 1; +} + +static int test_cms_sign(void) +{ + SM2_KEY sign_key; + X509_CERTIFICATE sign_cert; + uint8_t data[20]; + uint8_t content_info[1024]; + size_t content_info_len = 0; + + FILE *key_fp = fopen("sign_key.pem", "r"); + FILE *cert_fp = fopen("sign_cert.pem", "r"); + + if (sm2_private_key_from_pem(&sign_key, key_fp) != 1) { + error_print(); + return -1; + } + if (x509_certificate_from_pem(&sign_cert, cert_fp) != 1) { + error_print(); + return -1; + } + if (cms_sign(&sign_key, &sign_cert, 1, CMS_data, data, 20, NULL, NULL, 0, content_info, &content_info_len) != 1) { + error_print(); + return -1; + } + cms_content_info_print(stdout, content_info, content_info_len, 0, 0); + + return 1; +} + + +int main(void) +{ + test_cms_data(); + test_cms_sign(); + return 0; +} diff --git a/tests/destest.c b/tests/destest.c new file mode 100644 index 00000000..3dec6bbb --- /dev/null +++ b/tests/destest.c @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2014 - 2020 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + + +#include +#include +#include +#include + + +int main(int argc, char **argv) +{ + return 0; +} + diff --git a/tests/digesttest.c b/tests/digesttest.c new file mode 100644 index 00000000..4c5068b1 --- /dev/null +++ b/tests/digesttest.c @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2014 - 2020 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + + +#include +#include +#include +#include + +const char *digests[] = { + "md5", + "sha1", + "sm3", + "sha224", + "sha256", + "sha384", + "sha512", + "sha512-224", + "sha512-256", +}; + +int main(void) +{ + uint8_t dgst[64]; + size_t dgstlen; + size_t i, j; + + for (i = 0; i < sizeof(digests)/sizeof(digests[0]); i++) { + const DIGEST *algor = digest_from_name(digests[i]); + digest(algor, (uint8_t *)"abc", 3, dgst, &dgstlen); + + printf("%s (%zu) ", digests[i], dgstlen); + for (j = 0; j < dgstlen; j++) { + printf("%02x", dgst[j]); + } + printf("\n"); + } + + return 0; +} diff --git a/tests/gcmtest.c b/tests/gcmtest.c new file mode 100644 index 00000000..4f48f1e0 --- /dev/null +++ b/tests/gcmtest.c @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2014 - 2020 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + +#include +#include +#include +#include + + +struct { + char *K; + char *P; + char *IV; + char *C; + char *T; +} gcm_tests[] = { + /* test 1 */ + { + "00000000000000000000000000000000", + "", + "000000000000000000000000", + "", + "58e2fccefa7e3061367f1d57a4e7455a", + }, + /* test 2 */ + { + "00000000000000000000000000000000", + "00000000000000000000000000000000", + "000000000000000000000000", + "0388dace60b6a392f328c2b971b2fe78", + "ab6e47d42cec13bdf53a67b21257bddf", + }, +} + +int main(void) +{ + int err = 0; + GCM_CTX ctx; + uint8_t *key = NULL; + uint8_t *iv = NULL; + uint8_t *p = NULL; + uint8_t *c = NULL; + uint8_t *tag = NULL; + size_t keylen, ivlen, plen, clen, taglen, len, i; + + for (i = 0; i < sizeof(gcm_tests)/sizeof(gcm_tests[0]); i++) { + + key = OPENSSL_hexstr2buf(gcm_tests[i].K, &keylen); + iv = OPENSSL_hexstr2buf(gcm_tests[i].IV, &ivlen); + p = OPENSSL_hexstr2buf(gcm_tests[i].P, &plen); + c = OPENSSL_hexstr2buf(gcm_tests[i].C, &clen); + tag = OPENSSL_hexstr2buf(gcm_tests[i].T, &taglen); + buf = malloc(plen); + + gcm_init(&ctx, taglen, key, keylen, iv, ivlen, aad, aadlen); + gcm_update(&ctx, p, plen, buf, &len); + if (!gcm_finish_verify(&ctx, tag, taglen)) { + printf("gcm test %zu failed\n", i+1); + err++; + } else { + printf("gcm test %zu ok\n", i+1); + } + + free(key); + free(iv); + free(p); + free(c); + free(tag); + free(buf); + } + + return err; +} diff --git a/tests/gf128test.c b/tests/gf128test.c new file mode 100644 index 00000000..c850737c --- /dev/null +++ b/tests/gf128test.c @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2014 - 2021 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + +#include +#include +#include +#include +#include +#include "internal/gf128.h" + + +static gf128_t gf128_from_hex(const char *s) +{ + uint8_t bin[16]; + assert(strlen(s) == 32); + hex2bin(s, strlen(s), bin); + return gf128_from_bytes(bin); +} + +static int gf128_equ_hex(gf128_t a, const char *s) +{ + uint8_t bin1[16]; + uint8_t bin2[16]; + assert(strlen(s) == 32); + hex2bin(s, strlen(s), bin1); + gf128_to_bytes(a, bin2); + return memcmp(bin1, bin2, sizeof(bin1)) == 0; +} + +int main(void) +{ + gf128_t zero = gf128_from_hex("00000000000000000000000000000000"); + gf128_t one = gf128_from_hex("00000000000000000000000000000001"); + gf128_t ones = gf128_from_hex("11111111111111111111111111111111"); + gf128_t a = gf128_from_hex("de300f9301a499a965f8bf677e99e80d"); + gf128_t b = gf128_from_hex("14b267838ec9ef1bb7b5ce8c19e34bc6"); + gf128_t r; + + + + + + + + + + return 0; +} diff --git a/tests/hash_drbgtest.c b/tests/hash_drbgtest.c new file mode 100644 index 00000000..6b50f966 --- /dev/null +++ b/tests/hash_drbgtest.c @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2014 - 2020 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + +#include +#include +#include +#include +#include +#include + + +#define EntropyInput "212956390783381dbfc6362dd0da9a09" +#define Nonce "5280987fc5e27a49" +#define PersonalizationString "" +#define AdditionalInput "" +#define V0 "02b84eba8121ca090b6b66d3371609eaf76405a5c2807d80035c1a13dfed5aa18e536af599a7b3c68b2c56240ed11997f4048910d84604" +#define C0 "a677e4921587563eebe55d1b25e59c3f3d200bc61aaee665e7a6858c2857c45dba4bce8182252962ae86de491046a5e3450eec44938a0a" + +#define AdditionalInput1 "" +#define EntropyInputPR1 "2edb396eeb8960f77943c2a59075a786" +#define V1 "f9afadfbbf2c3d1004f9baca38be247342e5fbb83281915d5de18beb963712a344e89bb0e6b925a7bbc32eadb8b441efc1fa0c649df42a" +#define C1 "1d41cbbd634909e4761c232fcfd6a6c2edf0a7f4d3d3c164f74a88955f355efce2d86c1e9fa897b7005ef9d4d3a51bf4fc0b805ab896c9" + + +int main(void) +{ + HASH_DRBG drbg; + + unsigned char *entropy = NULL; + unsigned char *nonce = NULL; + unsigned char *personalstr = NULL; + unsigned char *v = NULL; + unsigned char *c = NULL; + size_t entropy_len, nonce_len, personalstr_len, vlen, clen; + + + unsigned char *entropy_pr1 = NULL; + size_t entropy_pr1len; + + unsigned char out[640/8]; + + entropy = OPENSSL_hexstr2buf(EntropyInput, &entropy_len); + nonce = OPENSSL_hexstr2buf(Nonce, &nonce_len); + personalstr = OPENSSL_hexstr2buf(PersonalizationString, &personalstr_len); + v = OPENSSL_hexstr2buf(V0, &vlen); + c = OPENSSL_hexstr2buf(C0, &clen); + + entropy_pr1 = OPENSSL_hexstr2buf(EntropyInputPR1, &entropy_pr1len); + + + hash_drbg_init(&drbg, DIGEST_sha1(), + entropy, entropy_len, + nonce, nonce_len, + personalstr, personalstr_len); + + printf("sha1_drbg test 1 "); + if (drbg.seedlen != vlen + || memcmp(drbg.V, v, vlen) != 0 + || memcmp(drbg.C, c, clen) != 0 + || drbg.reseed_counter != 1) { + printf("failed\n"); + } else { + printf("ok\n"); + } + + unsigned char *pr1 = NULL; + unsigned char *pr2 = NULL; + size_t pr1_len, pr2_len; + + pr1 = OPENSSL_hexstr2buf("2edb396eeb8960f77943c2a59075a786", &pr1_len); + pr2 = OPENSSL_hexstr2buf("30b565b63a5012676940d3ef17d9e996", &pr2_len); + + hash_drbg_reseed(&drbg, pr1, pr1_len, NULL, 0); + hash_drbg_generate(&drbg, NULL, 0, 640/8, out); + + hash_drbg_reseed(&drbg, pr2, pr2_len, NULL, 0); + hash_drbg_generate(&drbg, NULL, 0, 640/8, out); + + int i; + for (i = 0; i < sizeof(out); i++) { + printf("%02x", out[i]); + } + printf("\n"); + + return 0; +} diff --git a/tests/hkdftest.c b/tests/hkdftest.c new file mode 100644 index 00000000..480d6e9d --- /dev/null +++ b/tests/hkdftest.c @@ -0,0 +1,252 @@ +/* + * Copyright (c) 2021 - 2021 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + +#include +#include +#include +#include +#include +#include + +static struct { + char *algor; + char *ikm; + char *salt; + char *info; + int L; + char *prk; + char *okm; +} hkdf_tests[] = { + { + // test 1 + "sha256", + "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", + "000102030405060708090a0b0c", + "f0f1f2f3f4f5f6f7f8f9", + 42, + "077709362c2e32df0ddc3f0dc47bba63" + "90b6c73bb50f9c3122ec844ad7c2b3e5", + "3cb25f25faacd57a90434f64d0362f2a" + "2d2d0a90cf1a5a4c5db02d56ecc4c5bf" + "34007208d5b887185865", + }, + { + // test 2 + "sha256", + "000102030405060708090a0b0c0d0e0f" + "101112131415161718191a1b1c1d1e1f" + "202122232425262728292a2b2c2d2e2f" + "303132333435363738393a3b3c3d3e3f" + "404142434445464748494a4b4c4d4e4f", + "606162636465666768696a6b6c6d6e6f" + "707172737475767778797a7b7c7d7e7f" + "808182838485868788898a8b8c8d8e8f" + "909192939495969798999a9b9c9d9e9f" + "a0a1a2a3a4a5a6a7a8a9aaabacadaeaf", + "b0b1b2b3b4b5b6b7b8b9babbbcbdbebf" + "c0c1c2c3c4c5c6c7c8c9cacbcccdcecf" + "d0d1d2d3d4d5d6d7d8d9dadbdcdddedf" + "e0e1e2e3e4e5e6e7e8e9eaebecedeeef" + "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + 82, + "06a6b88c5853361a06104c9ceb35b45c" + "ef760014904671014a193f40c15fc244", + "b11e398dc80327a1c8e7f78c596a4934" + "4f012eda2d4efad8a050cc4c19afa97c" + "59045a99cac7827271cb41c65e590e09" + "da3275600c2f09b8367793a9aca3db71" + "cc30c58179ec3e87c14c01d5c1f3434f" + "1d87", + }, + { + // test 3 + "sha256", + "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", + "", + "", + 42, + "19ef24a32c717b167f33a91d6f648bdf" + "96596776afdb6377ac434c1c293ccb04", + "8da4e775a563c18f715f802a063c5a31" + "b8a11f5c5ee1879ec3454e5f3c738d2d" + "9d201395faa4b61a96c8", + }, + { + // test 4 + "sha1", + "0b0b0b0b0b0b0b0b0b0b0b", + "000102030405060708090a0b0c", + "f0f1f2f3f4f5f6f7f8f9", + 42, + "9b6c18c432a7bf8f0e71c8eb88f4b30baa2ba243", + "085a01ea1b10f36933068b56efa5ad81" + "a4f14b822f5b091568a9cdd4f155fda2" + "c22e422478d305f3f896", + }, + { + // test 5 + "sha1", + "000102030405060708090a0b0c0d0e0f" + "101112131415161718191a1b1c1d1e1f" + "202122232425262728292a2b2c2d2e2f" + "303132333435363738393a3b3c3d3e3f" + "404142434445464748494a4b4c4d4e4f", + "606162636465666768696a6b6c6d6e6f" + "707172737475767778797a7b7c7d7e7f" + "808182838485868788898a8b8c8d8e8f" + "909192939495969798999a9b9c9d9e9f" + "a0a1a2a3a4a5a6a7a8a9aaabacadaeaf", + "b0b1b2b3b4b5b6b7b8b9babbbcbdbebf" + "c0c1c2c3c4c5c6c7c8c9cacbcccdcecf" + "d0d1d2d3d4d5d6d7d8d9dadbdcdddedf" + "e0e1e2e3e4e5e6e7e8e9eaebecedeeef" + "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + 82, + "8adae09a2a307059478d309b26c4115a224cfaf6", + "0bd770a74d1160f7c9f12cd5912a06eb" + "ff6adcae899d92191fe4305673ba2ffe" + "8fa3f1a4e5ad79f3f334b3b202b2173c" + "486ea37ce3d397ed034c7f9dfeb15c5e" + "927336d0441f4c4300e2cff0d0900b52" + "d3b4", + }, + { + // test 6 + "sha1", + "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", + "", + "", + 42, + "da8c8a73c7fa77288ec6f5e7c297786aa0d32d01", + "0ac1af7002b3d761d1e55298da9d0506" + "b9ae52057220a306e07b6b87e8df21d0" + "ea00033de03984d34918" + }, + { + // test 7 + "sha1", + "0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c", + "", + "", + 42, + "2adccada18779e7c2077ad2eb19d3f3e731385dd", + "2c91117204d745f3500d636a62f64f0a" + "b3bae548aa53d423b0d1f27ebba6f5e5" + "673a081d70cce7acfc48", + }, +}; + +int test_hkdf(void) +{ + int i; + const DIGEST *digest; + uint8_t ikm[512]; + uint8_t salt[512]; + uint8_t info[512]; + uint8_t prk[512]; + uint8_t okm[512]; + size_t ikmlen, saltlen, infolen, prklen, okmlen; + size_t L; + uint8_t buf[512]; + size_t buflen; + + for (i = 0; i < sizeof(hkdf_tests)/sizeof(hkdf_tests[0]); i++) { + + digest = digest_from_name(hkdf_tests[i].algor); + hex2bin(hkdf_tests[i].ikm, strlen(hkdf_tests[i].ikm), ikm); + hex2bin(hkdf_tests[i].salt, strlen(hkdf_tests[i].salt), salt); + hex2bin(hkdf_tests[i].info, strlen(hkdf_tests[i].info), info); + hex2bin(hkdf_tests[i].prk, strlen(hkdf_tests[i].prk), prk); + hex2bin(hkdf_tests[i].okm, strlen(hkdf_tests[i].okm), okm); + ikmlen = strlen(hkdf_tests[i].ikm)/2; + saltlen = strlen(hkdf_tests[i].salt)/2; + infolen = strlen(hkdf_tests[i].info)/2; + prklen = strlen(hkdf_tests[i].prk)/2; + okmlen = strlen(hkdf_tests[i].okm)/2; + L = hkdf_tests[i].L; + + printf("test %d\n", i + 1); + format_print(stdout, 0, 0, "Hash = %s\n", digest_name(digest)); + format_bytes(stdout, 0, 0, "IKM = ", ikm, ikmlen); + format_bytes(stdout, 0, 0, "salt = ", salt, saltlen); + format_bytes(stdout, 0, 0, "info = ", info, infolen); + format_print(stdout, 0, 0, "L = %zu\n", L); + + if (hkdf_extract(digest, salt, saltlen, ikm, ikmlen, buf, &buflen) != 1) { + error_print(); + return -1; + } + format_bytes(stdout, 0, 0, "PRK = ", buf, buflen); + format_bytes(stdout, 0, 0, " = ", prk, prklen); + if (buflen != prklen || memcmp(buf, prk, prklen) != 0) { + error_print(); + return -1; + } + + if (hkdf_expand(digest, prk, prklen, info, infolen, L, buf) != 1) { + error_print(); + return -1; + } + format_bytes(stdout, 0, 0, "OKM = ", buf, L); + format_bytes(stdout, 0, 0, " = ", okm, okmlen); + if (L != okmlen || memcmp(buf, okm, okmlen) != 0) { + error_print(); + return -1; + } + + printf("\n"); + + } + return 1; +} + +int main(void) +{ + test_hkdf(); + return 0; +} diff --git a/tests/hmactest.c b/tests/hmactest.c new file mode 100644 index 00000000..a16ef276 --- /dev/null +++ b/tests/hmactest.c @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2014 - 2018 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + +#include +#include +#include +#include +#include + + +// FIXME: md5, sha1, sm3 test vectors + + +struct { + char *key; + char *data; + char *hmac_sha224; + char *hmac_sha256; + char *hmac_sha384; + char *hmac_sha512; +} hmac_tests[] = { + + // rfc 4231 test vectors + { + "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b" + "0b0b0b0b", + "4869205468657265", + "896fb1128abbdf196832107cd49df33f" + "47b4b1169912ba4f53684b22", + "b0344c61d8db38535ca8afceaf0bf12b" + "881dc200c9833da726e9376c2e32cff7", + "afd03944d84895626b0825f4ab46907f" + "15f9dadbe4101ec682aa034c7cebc59c" + "faea9ea9076ede7f4af152e8b2fa9cb6", + "87aa7cdea5ef619d4ff0b4241a1d6cb0" + "2379f4e2ce4ec2787ad0b30545e17cde" + "daa833b7d6b8a702038b274eaea3f4e4" + "be9d914eeb61f1702e696c203a126854", + }, + { + "4a656665", + "7768617420646f2079612077616e7420" + "666f72206e6f7468696e673f", + "a30e01098bc6dbbf45690f3a7e9e6d0f" + "8bbea2a39e6148008fd05e44", + "5bdcc146bf60754e6a042426089575c7" + "5a003f089d2739839dec58b964ec3843", + "af45d2e376484031617f78d2b58a6b1b" + "9c7ef464f5a01b47e42ec3736322445e" + "8e2240ca5e69e2c78b3239ecfab21649", + "164b7a7bfcf819e2e395fbe73b56e0a3" + "87bd64222e831fd610270cd7ea250554" + "9758bf75c05a994a6d034f65f8f0e6fd" + "caeab1a34d4a6b4b636e070a38bce737", + }, + { + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaa", + "dddddddddddddddddddddddddddddddd" + "dddddddddddddddddddddddddddddddd" + "dddddddddddddddddddddddddddddddd" + "dddd", + "7fb3cb3588c6c1f6ffa9694d7d6ad264" + "9365b0c1f65d69d1ec8333ea", + "773ea91e36800e46854db8ebd09181a7" + "2959098b3ef8c122d9635514ced565fe", + "88062608d3e6ad8a0aa2ace014c8a86f" + "0aa635d947ac9febe83ef4e55966144b" + "2a5ab39dc13814b94e3ab6e101a34f27", + "fa73b0089d56a284efb0f0756c890be9" + "b1b5dbdd8ee81a3655f83e33b2279d39" + "bf3e848279a722c806b485a47e67c807" + "b946a337bee8942674278859e13292fb", + }, +}; + +int test_hmac(const DIGEST *digest, const char *key_hex, const char *data_hex, const char *hmac_hex) +{ + HMAC_CTX ctx; + uint8_t key[strlen(key_hex)/2]; + uint8_t data[strlen(data_hex)/2]; + uint8_t hmac[strlen(hmac_hex)/2]; + uint8_t buf[64]; + size_t len; + + hex2bin(key_hex, strlen(key_hex), key); + hex2bin(data_hex, strlen(data_hex), data); + hex2bin(hmac_hex, strlen(hmac_hex), hmac); + + hmac_init(&ctx, digest, key, sizeof(key)); + hmac_update(&ctx, data, sizeof(data)); + hmac_finish(&ctx, buf, &len); + + if (len != sizeof(hmac) || memcmp(buf, hmac, sizeof(hmac)) != 0) { + printf("failed\n"); + return 0; + } + printf("ok\n"); + return 1; +} + +int main(void) +{ + int i; + for (i = 0; i < sizeof(hmac_tests)/sizeof(hmac_tests[0]); i++) { + test_hmac(DIGEST_sha224(), hmac_tests[i].key, hmac_tests[i].data, hmac_tests[i].hmac_sha224); + test_hmac(DIGEST_sha256(), hmac_tests[i].key, hmac_tests[i].data, hmac_tests[i].hmac_sha256); + test_hmac(DIGEST_sha384(), hmac_tests[i].key, hmac_tests[i].data, hmac_tests[i].hmac_sha384); + test_hmac(DIGEST_sha512(), hmac_tests[i].key, hmac_tests[i].data, hmac_tests[i].hmac_sha512); + }; + + return 0; +}; diff --git a/tests/md5test.c b/tests/md5test.c new file mode 100644 index 00000000..07171c39 --- /dev/null +++ b/tests/md5test.c @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2014 - 2020 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + + +#include +#include +#include +#include +#include + +static char *teststr[] = { + "", + "a", + "abc", + "message digest", + "abcdefghijklmnopqrstuvwxyz", + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", + "12345678901234567890123456789012345678901234567890123456789012345678901234567890", +}; + +static char *dgsthex[] = { + "d41d8cd98f00b204e9800998ecf8427e", + "0cc175b9c0f1b6a831c399e269772661", + "900150983cd24fb0d6963f7d28e17f72", + "f96b697d7cb7938d525a2f31aaf161d0", + "c3fcd3d76192e4007dfb496cca67e13b", + "d174ab98d277d9f5a5611c2c9f419d9f", + "57edf4a22be3c955ac49da2e2107b67a", +}; + +int main(int argc, char **argv) +{ + int err = 0; + char *p; + unsigned char *dgstbuf = NULL; + size_t dgstbuflen; + unsigned char dgst[16]; + size_t i; + + for (i = 0; i < sizeof(teststr)/sizeof(teststr[0]); i++) { + if (!(dgstbuf = OPENSSL_hexstr2buf(dgsthex[i], &dgstbuflen))) { + goto end; + } + + md5_digest((unsigned char *)teststr[i], strlen(teststr[i]), dgst); + + if (memcmp(dgstbuf, dgst, sizeof(dgst)) != 0) { + int n; + printf("error calculating MD5 on %s\n", teststr[i]); + printf(" digest(corret) = "); + for (n = 0; n < sizeof(dgst); n++) { + printf("%02X", dgst[n]); + } + printf("\n"); + printf(" digest(error) = %s\n", dgsthex[i]); + err++; + } else { + printf("md5 test %lu ok\n", i+1); + } + + free(dgstbuf); + dgstbuf = NULL; + } + +end: + if (dgstbuf) free(dgstbuf); + return err; +} diff --git a/tests/oidtest.c b/tests/oidtest.c new file mode 100644 index 00000000..7b6bdfdc --- /dev/null +++ b/tests/oidtest.c @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2014 - 2020 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + +#include +#include +#include +#include +#include +#include + +int main(void) +{ +// test_asn1_oid(); + + test_asn1_object_identifier(); + return 1; +} diff --git a/tests/pbkdf2test.c b/tests/pbkdf2test.c new file mode 100644 index 00000000..aedcef63 --- /dev/null +++ b/tests/pbkdf2test.c @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2014 - 2020 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + + +#include +#include +#include +#include +#include + + + +struct { + char *pass; + char *salt; + int iter; + int dklen; + char *dk; +} pbkdf2_hmac_sha1_tests[] = { + + // rfc 6070 test vectors for pbkdf2-hmac-sha1 + { + "password", + "salt", + 1, + 20, + "0c60c80f961f0e71f3a9b524af6012062fe037a6", + }, + { + "password", + "salt", + 2, + 20, + "ea6c014dc72d6f8ccd1ed92ace1d41f0d8de8957", + }, + { + "password", + "salt", + 4096, + 20, + "4b007901b765489abead49d926f721d065a429c1", + }, + { + "password", + "salt", + 16777216, + 20, + "eefe3d61cd4da4e4e9945b3d6ba2158c2634e984", + }, + { + "passwordPASSWORDpassword", + "saltSALTsaltSALTsaltSALTsaltSALTsalt", + 4096, + 25, + "3d2eec4fe41c849b80c8d83662c0e44a8b291a964cf2f07038", + }, +}; + + +void test(void) +{ + HMAC_CTX ctx; + uint8_t iter[4] = {0, 0, 0, 1}; + uint8_t mac[20]; + size_t len; + int i; + + hmac_init(&ctx, DIGEST_sha1(), (uint8_t *)"password", 8); + hmac_update(&ctx, (uint8_t *)"salt", 4); + hmac_update(&ctx, iter, 4); + hmac_finish(&ctx, mac, &len); + + for (i = 1; i < 4096; i++) { + uint8_t buf[20]; + memset(&ctx, 0, sizeof(HMAC_CTX)); + hmac_init(&ctx, DIGEST_sha1(), (uint8_t *)"password", 8); + hmac_update(&ctx, mac, len); + hmac_finish(&ctx, buf, &len); + int j; + for (j = 0; j < len; j++) { + mac[j] ^= buf[j]; + } + } + + + for (i = 0; i < len; i++) { + printf("%02x", mac[i]); + } + printf("\n"); +} + +int main(void) +{ + int i; + uint8_t key[64]; + uint8_t buf[64]; + size_t len; + + for (i = 0; i < sizeof(pbkdf2_hmac_sha1_tests)/sizeof(pbkdf2_hmac_sha1_tests[0]); i++) { + hex2bin(pbkdf2_hmac_sha1_tests[i].dk, strlen(pbkdf2_hmac_sha1_tests[i].dk), buf); + + pbkdf2_genkey(DIGEST_sha1(), + pbkdf2_hmac_sha1_tests[i].pass, strlen(pbkdf2_hmac_sha1_tests[i].pass), + (uint8_t *)pbkdf2_hmac_sha1_tests[i].salt, strlen(pbkdf2_hmac_sha1_tests[i].salt), + pbkdf2_hmac_sha1_tests[i].iter, pbkdf2_hmac_sha1_tests[i].dklen, key); + + if (memcmp(key, buf, pbkdf2_hmac_sha1_tests[i].dklen) != 0) { + printf("%d failed\n", i); + } else { + printf("%d ok\n", i); + } + } + + return 0; +} diff --git a/tests/pkcs8test.c b/tests/pkcs8test.c new file mode 100644 index 00000000..76affca9 --- /dev/null +++ b/tests/pkcs8test.c @@ -0,0 +1,318 @@ +/* + * Copyright (c) 2021 - 2021 The GmSSL 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. + * +sm2_enced_private_key_info_from_der * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + +#include +#include +#include +#include +#include +#include +#include + + +static int test_pbkdf2_params(void) +{ + int err = 0; + uint8_t salt[8] = {0}; + const uint8_t *psalt; + size_t saltlen; + int iter = 65536; + int keylen; + int prf = OID_hmac_sm3; + uint8_t buf[128]; + uint8_t *p = buf; + const uint8_t *cp = buf; + size_t len = 0; + + keylen = -1; + if (pbkdf2_params_to_der(salt, sizeof(salt), iter, keylen, prf, &p, &len) != 1) { + error_print(); + err++; + goto end; + } + if (pbkdf2_params_from_der(&psalt, &saltlen, &iter, &keylen, &prf, &cp, &len) != 1 + || len > 0) { + error_print(); + err++; + goto end; + } + + keylen = 16; + if (pbkdf2_params_to_der(salt, sizeof(salt), iter, keylen, prf, &p, &len) != 1) { + error_print(); + err++; + goto end; + } + if (pbkdf2_params_from_der(&psalt, &saltlen, &iter, &keylen, &prf, &cp, &len) != 1 + || len > 0) { + error_print(); + err++; + goto end; + } + printf("%s : ok\n", __func__); +end: + return err; +} + +static int test_pbkdf2_algor(void) +{ + int err = 0; + uint8_t salt[8] = {0}; + const uint8_t *psalt; + size_t saltlen; + int iter = 65536; + int keylen; + int prf = OID_hmac_sm3; + uint8_t buf[128]; + uint8_t *p = buf; + const uint8_t *cp = buf; + size_t len = 0; + + keylen = -1; + if (pbkdf2_algor_to_der(salt, sizeof(salt), iter, keylen, prf, &p, &len) != 1) { + error_print(); + err++; + goto end; + } + if (pbkdf2_algor_from_der(&psalt, &saltlen, &iter, &keylen, &prf, &cp, &len) != 1 + || len > 0) { + error_print(); + err++; + goto end; + } + printf("%s : ok\n", __func__); +end: + return err; +} + + +static int test_pbes2_enc_algor(void) +{ + int err = 0; + int cipher = OID_sm4_cbc; + uint8_t iv[16] = {1}; + const uint8_t *piv; + size_t ivlen; + uint8_t buf[128]; + uint8_t *p = buf; + const uint8_t *cp = buf; + size_t len = 0; + + if (pbes2_enc_algor_to_der(OID_sm4_cbc, iv, sizeof(iv), &p, &len) != 1) { + error_print(); + err++; + goto end; + } + if (pbes2_enc_algor_from_der(&cipher, &piv, &ivlen, &cp, &len) != 1 + || len > 0) { + error_print(); + err++; + goto end; + } + printf("%s : ok\n", __func__); +end: + return err; +} + +static int test_pbes2_params(void) +{ + int err = 0; + uint8_t salt[8] = {0}; + const uint8_t *psalt; + size_t saltlen; + int iter = 65536; + int prf = OID_hmac_sm3; + int cipher = OID_sm4_cbc; + uint8_t iv[16]; + const uint8_t *piv; + size_t ivlen; + uint8_t buf[256]; + uint8_t *p = buf; + const uint8_t *cp = buf; + size_t len = 0; + + if (pbes2_params_to_der(salt, sizeof(salt), iter, prf, cipher, iv, sizeof(iv), &p, &len) != 1) { + error_print(); + err++; + goto end; + } + if (pbes2_params_from_der(&psalt, &saltlen, &iter, &prf, &cipher, &piv, &ivlen, &cp, &len) != 1 + || len > 0) { + error_print(); + err++; + goto end; + } + printf("%s : ok\n", __func__); +end: + return err; +} + +static int test_pbes2_algor(void) +{ + int err = 0; + uint8_t salt[8] = {0}; + const uint8_t *psalt; + size_t saltlen; + int iter = 65536; + int prf = OID_hmac_sm3; + int cipher = OID_sm4_cbc; + uint8_t iv[16]; + const uint8_t *piv; + size_t ivlen; + uint8_t buf[256]; + uint8_t *p = buf; + const uint8_t *cp = buf; + size_t len = 0; + + if (pbes2_algor_to_der(salt, sizeof(salt), iter, prf, cipher, iv, sizeof(iv), &p, &len) != 1) { + error_print(); + err++; + goto end; + } + if (pbes2_algor_from_der(&psalt, &saltlen, &iter, &prf, &cipher, &piv, &ivlen, &cp, &len) != 1 + || len > 0) { + error_print(); + err++; + goto end; + } + printf("%s : ok\n", __func__); +end: + return err; +} + +static int test_pkcs8_enced_private_key_info(void) +{ + int err = 0; + uint8_t salt[8] = {0}; + const uint8_t *psalt; + size_t saltlen; + int iter = 65536; + int prf = OID_hmac_sm3; + int cipher = OID_sm4_cbc; + uint8_t iv[16]; + const uint8_t *piv; + size_t ivlen; + uint8_t enced[128]; + const uint8_t *penced; + size_t encedlen; + uint8_t buf[256]; + uint8_t *p = buf; + const uint8_t *cp = buf; + size_t len = 0; + + if (pkcs8_enced_private_key_info_to_der(salt, sizeof(salt), iter, prf, cipher, iv, sizeof(iv), + enced, sizeof(enced), &p, &len) != 1) { + error_print(); + err++; + goto end; + } + if (pkcs8_enced_private_key_info_from_der(&psalt, &saltlen, &iter, &prf, &cipher, &piv, &ivlen, + &penced, &encedlen, &cp, &len) != 1 + || len > 0) { + error_print(); + err++; + goto end; + } + printf("%s : ok\n", __func__); +end: + return err; +} + +static int test_pkcs8(void) +{ + int err = 0; + SM2_KEY sm2_key; + SM2_KEY sm2_buf; + const uint8_t *attrs; + size_t attrslen; + uint8_t buf[1024]; + uint8_t *p = buf; + const uint8_t *cp = buf; + size_t len = 0; + + sm2_keygen(&sm2_key); + memcpy(&sm2_buf, &sm2_key, sizeof(sm2_key)); + //sm2_key_print(stdout, &sm2_key, 0, 0); + + if (sm2_enced_private_key_info_to_der(&sm2_key, "passowrd", &p, &len) != 1) { + error_print(); + err++; + goto end; + } + + memset(&sm2_key, 0, sizeof(sm2_key)); + if (sm2_enced_private_key_info_from_der(&sm2_key, &attrs, &attrslen, "password", &cp, &len) != 1 + || len > 0) { + error_print(); + err++; + goto end; + } + //sm2_key_print(stdout, &sm2_key, 0, 0); + + if (memcmp(&sm2_key, &sm2_buf, sizeof(sm2_key)) != 0) { + error_print(); + err++; + goto end; + } + printf("%s : ok\n", __func__); +end: + return err; +} + +int main(void) +{ + int err = 0; + err += test_pbkdf2_params(); + err += test_pbkdf2_algor(); + err += test_pbes2_enc_algor(); + err += test_pbes2_params(); + err += test_pbes2_algor(); + err += test_pkcs8_enced_private_key_info(); + err += test_pkcs8(); + return err; +} diff --git a/tests/rc4test.c b/tests/rc4test.c new file mode 100644 index 00000000..a3077090 --- /dev/null +++ b/tests/rc4test.c @@ -0,0 +1,427 @@ +/* + * Copyright (c) 2014 - 2020 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + + +#include +#include +#include +#include + + +/* tests from RFC 6229 Test Vectors for the Stream Cipher RC4 */ + +unsigned char key1[] = { + 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, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, +}; + +unsigned char key2[] = { + 0x1a, 0xda, 0x31, 0xd5, 0xcf, 0x68, 0x82, 0x21, + 0xc1, 0x09, 0x16, 0x39, 0x08, 0xeb, 0xe5, 0x1d, + 0xeb, 0xb4, 0x62, 0x27, 0xc6, 0xcc, 0x8b, 0x37, + 0x64, 0x19, 0x10, 0x83, 0x32, 0x22, 0x77, 0x2a, +}; + +int keybits[] = { + 40, + 56, + 64, + 80, + 128, + 192, + 256, +}; + +int testindex[] = { + 0, + 16, + 240, + 256, + 496, + 512, + 752, + 768, + 1008, + 1024, + 1520, + 1536, + 2032, + 2048, + 3056, + 3072, + 4080, + 4096, +}; + +unsigned char testdata1[][16 * 18] = { + { + 0xb2, 0x39, 0x63, 0x05, 0xf0, 0x3d, 0xc0, 0x27, 0xcc, 0xc3, 0x52, 0x4a, 0x0a, 0x11, 0x18, 0xa8, + 0x69, 0x82, 0x94, 0x4f, 0x18, 0xfc, 0x82, 0xd5, 0x89, 0xc4, 0x03, 0xa4, 0x7a, 0x0d, 0x09, 0x19, + 0x28, 0xcb, 0x11, 0x32, 0xc9, 0x6c, 0xe2, 0x86, 0x42, 0x1d, 0xca, 0xad, 0xb8, 0xb6, 0x9e, 0xae, + 0x1c, 0xfc, 0xf6, 0x2b, 0x03, 0xed, 0xdb, 0x64, 0x1d, 0x77, 0xdf, 0xcf, 0x7f, 0x8d, 0x8c, 0x93, + 0x42, 0xb7, 0xd0, 0xcd, 0xd9, 0x18, 0xa8, 0xa3, 0x3d, 0xd5, 0x17, 0x81, 0xc8, 0x1f, 0x40, 0x41, + 0x64, 0x59, 0x84, 0x44, 0x32, 0xa7, 0xda, 0x92, 0x3c, 0xfb, 0x3e, 0xb4, 0x98, 0x06, 0x61, 0xf6, + 0xec, 0x10, 0x32, 0x7b, 0xde, 0x2b, 0xee, 0xfd, 0x18, 0xf9, 0x27, 0x76, 0x80, 0x45, 0x7e, 0x22, + 0xeb, 0x62, 0x63, 0x8d, 0x4f, 0x0b, 0xa1, 0xfe, 0x9f, 0xca, 0x20, 0xe0, 0x5b, 0xf8, 0xff, 0x2b, + 0x45, 0x12, 0x90, 0x48, 0xe6, 0xa0, 0xed, 0x0b, 0x56, 0xb4, 0x90, 0x33, 0x8f, 0x07, 0x8d, 0xa5, + 0x30, 0xab, 0xbc, 0xc7, 0xc2, 0x0b, 0x01, 0x60, 0x9f, 0x23, 0xee, 0x2d, 0x5f, 0x6b, 0xb7, 0xdf, + 0x32, 0x94, 0xf7, 0x44, 0xd8, 0xf9, 0x79, 0x05, 0x07, 0xe7, 0x0f, 0x62, 0xe5, 0xbb, 0xce, 0xea, + 0xd8, 0x72, 0x9d, 0xb4, 0x18, 0x82, 0x25, 0x9b, 0xee, 0x4f, 0x82, 0x53, 0x25, 0xf5, 0xa1, 0x30, + 0x1e, 0xb1, 0x4a, 0x0c, 0x13, 0xb3, 0xbf, 0x47, 0xfa, 0x2a, 0x0b, 0xa9, 0x3a, 0xd4, 0x5b, 0x8b, + 0xcc, 0x58, 0x2f, 0x8b, 0xa9, 0xf2, 0x65, 0xe2, 0xb1, 0xbe, 0x91, 0x12, 0xe9, 0x75, 0xd2, 0xd7, + 0xf2, 0xe3, 0x0f, 0x9b, 0xd1, 0x02, 0xec, 0xbf, 0x75, 0xaa, 0xad, 0xe9, 0xbc, 0x35, 0xc4, 0x3c, + 0xec, 0x0e, 0x11, 0xc4, 0x79, 0xdc, 0x32, 0x9d, 0xc8, 0xda, 0x79, 0x68, 0xfe, 0x96, 0x56, 0x81, + 0x06, 0x83, 0x26, 0xa2, 0x11, 0x84, 0x16, 0xd2, 0x1f, 0x9d, 0x04, 0xb2, 0xcd, 0x1c, 0xa0, 0x50, + 0xff, 0x25, 0xb5, 0x89, 0x95, 0x99, 0x67, 0x07, 0xe5, 0x1f, 0xbd, 0xf0, 0x8b, 0x34, 0xd8, 0x75, + }, + { + 0x29, 0x3f, 0x02, 0xd4, 0x7f, 0x37, 0xc9, 0xb6, 0x33, 0xf2, 0xaf, 0x52, 0x85, 0xfe, 0xb4, 0x6b, + 0xe6, 0x20, 0xf1, 0x39, 0x0d, 0x19, 0xbd, 0x84, 0xe2, 0xe0, 0xfd, 0x75, 0x20, 0x31, 0xaf, 0xc1, + 0x91, 0x4f, 0x02, 0x53, 0x1c, 0x92, 0x18, 0x81, 0x0d, 0xf6, 0x0f, 0x67, 0xe3, 0x38, 0x15, 0x4c, + 0xd0, 0xfd, 0xb5, 0x83, 0x07, 0x3c, 0xe8, 0x5a, 0xb8, 0x39, 0x17, 0x74, 0x0e, 0xc0, 0x11, 0xd5, + 0x75, 0xf8, 0x14, 0x11, 0xe8, 0x71, 0xcf, 0xfa, 0x70, 0xb9, 0x0c, 0x74, 0xc5, 0x92, 0xe4, 0x54, + 0x0b, 0xb8, 0x72, 0x02, 0x93, 0x8d, 0xad, 0x60, 0x9e, 0x87, 0xa5, 0xa1, 0xb0, 0x79, 0xe5, 0xe4, + 0xc2, 0x91, 0x12, 0x46, 0xb6, 0x12, 0xe7, 0xe7, 0xb9, 0x03, 0xdf, 0xed, 0xa1, 0xda, 0xd8, 0x66, + 0x32, 0x82, 0x8f, 0x91, 0x50, 0x2b, 0x62, 0x91, 0x36, 0x8d, 0xe8, 0x08, 0x1d, 0xe3, 0x6f, 0xc2, + 0xf3, 0xb9, 0xa7, 0xe3, 0xb2, 0x97, 0xbf, 0x9a, 0xd8, 0x04, 0x51, 0x2f, 0x90, 0x63, 0xef, 0xf1, + 0x8e, 0xcb, 0x67, 0xa9, 0xba, 0x1f, 0x55, 0xa5, 0xa0, 0x67, 0xe2, 0xb0, 0x26, 0xa3, 0x67, 0x6f, + 0xd2, 0xaa, 0x90, 0x2b, 0xd4, 0x2d, 0x0d, 0x7c, 0xfd, 0x34, 0x0c, 0xd4, 0x58, 0x10, 0x52, 0x9f, + 0x78, 0xb2, 0x72, 0xc9, 0x6e, 0x42, 0xea, 0xb4, 0xc6, 0x0b, 0xd9, 0x14, 0xe3, 0x9d, 0x06, 0xe3, + 0xf4, 0x33, 0x2f, 0xd3, 0x1a, 0x07, 0x93, 0x96, 0xee, 0x3c, 0xee, 0x3f, 0x2a, 0x4f, 0xf0, 0x49, + 0x05, 0x45, 0x97, 0x81, 0xd4, 0x1f, 0xda, 0x7f, 0x30, 0xc1, 0xbe, 0x7e, 0x12, 0x46, 0xc6, 0x23, + 0xad, 0xfd, 0x38, 0x68, 0xb8, 0xe5, 0x14, 0x85, 0xd5, 0xe6, 0x10, 0x01, 0x7e, 0x3d, 0xd6, 0x09, + 0xad, 0x26, 0x58, 0x1c, 0x0c, 0x5b, 0xe4, 0x5f, 0x4c, 0xea, 0x01, 0xdb, 0x2f, 0x38, 0x05, 0xd5, + 0xf3, 0x17, 0x2c, 0xef, 0xfc, 0x3b, 0x3d, 0x99, 0x7c, 0x85, 0xcc, 0xd5, 0xaf, 0x1a, 0x95, 0x0c, + 0xe7, 0x4b, 0x0b, 0x97, 0x31, 0x22, 0x7f, 0xd3, 0x7c, 0x0e, 0xc0, 0x8a, 0x47, 0xdd, 0xd8, 0xb8, + }, + { + 0x97, 0xab, 0x8a, 0x1b, 0xf0, 0xaf, 0xb9, 0x61, 0x32, 0xf2, 0xf6, 0x72, 0x58, 0xda, 0x15, 0xa8, + 0x82, 0x63, 0xef, 0xdb, 0x45, 0xc4, 0xa1, 0x86, 0x84, 0xef, 0x87, 0xe6, 0xb1, 0x9e, 0x5b, 0x09, + 0x96, 0x36, 0xeb, 0xc9, 0x84, 0x19, 0x26, 0xf4, 0xf7, 0xd1, 0xf3, 0x62, 0xbd, 0xdf, 0x6e, 0x18, + 0xd0, 0xa9, 0x90, 0xff, 0x2c, 0x05, 0xfe, 0xf5, 0xb9, 0x03, 0x73, 0xc9, 0xff, 0x4b, 0x87, 0x0a, + 0x73, 0x23, 0x9f, 0x1d, 0xb7, 0xf4, 0x1d, 0x80, 0xb6, 0x43, 0xc0, 0xc5, 0x25, 0x18, 0xec, 0x63, + 0x16, 0x3b, 0x31, 0x99, 0x23, 0xa6, 0xbd, 0xb4, 0x52, 0x7c, 0x62, 0x61, 0x26, 0x70, 0x3c, 0x0f, + 0x49, 0xd6, 0xc8, 0xaf, 0x0f, 0x97, 0x14, 0x4a, 0x87, 0xdf, 0x21, 0xd9, 0x14, 0x72, 0xf9, 0x66, + 0x44, 0x17, 0x3a, 0x10, 0x3b, 0x66, 0x16, 0xc5, 0xd5, 0xad, 0x1c, 0xee, 0x40, 0xc8, 0x63, 0xd0, + 0x27, 0x3c, 0x9c, 0x4b, 0x27, 0xf3, 0x22, 0xe4, 0xe7, 0x16, 0xef, 0x53, 0xa4, 0x7d, 0xe7, 0xa4, + 0xc6, 0xd0, 0xe7, 0xb2, 0x26, 0x25, 0x9f, 0xa9, 0x02, 0x34, 0x90, 0xb2, 0x61, 0x67, 0xad, 0x1d, + 0x1f, 0xe8, 0x98, 0x67, 0x13, 0xf0, 0x7c, 0x3d, 0x9a, 0xe1, 0xc1, 0x63, 0xff, 0x8c, 0xf9, 0xd3, + 0x83, 0x69, 0xe1, 0xa9, 0x65, 0x61, 0x0b, 0xe8, 0x87, 0xfb, 0xd0, 0xc7, 0x91, 0x62, 0xaa, 0xfb, + 0x0a, 0x01, 0x27, 0xab, 0xb4, 0x44, 0x84, 0xb9, 0xfb, 0xef, 0x5a, 0xbc, 0xae, 0x1b, 0x57, 0x9f, + 0xc2, 0xcd, 0xad, 0xc6, 0x40, 0x2e, 0x8e, 0xe8, 0x66, 0xe1, 0xf3, 0x7b, 0xdb, 0x47, 0xe4, 0x2c, + 0x26, 0xb5, 0x1e, 0xa3, 0x7d, 0xf8, 0xe1, 0xd6, 0xf7, 0x6f, 0xc3, 0xb6, 0x6a, 0x74, 0x29, 0xb3, + 0xbc, 0x76, 0x83, 0x20, 0x5d, 0x4f, 0x44, 0x3d, 0xc1, 0xf2, 0x9d, 0xda, 0x33, 0x15, 0xc8, 0x7b, + 0xd5, 0xfa, 0x5a, 0x34, 0x69, 0xd2, 0x9a, 0xaa, 0xf8, 0x3d, 0x23, 0x58, 0x9d, 0xb8, 0xc8, 0x5b, + 0x3f, 0xb4, 0x6e, 0x2c, 0x8f, 0x0f, 0x06, 0x8e, 0xdc, 0xe8, 0xcd, 0xcd, 0x7d, 0xfc, 0x58, 0x62, + }, + { + 0xed, 0xe3, 0xb0, 0x46, 0x43, 0xe5, 0x86, 0xcc, 0x90, 0x7d, 0xc2, 0x18, 0x51, 0x70, 0x99, 0x02, + 0x03, 0x51, 0x6b, 0xa7, 0x8f, 0x41, 0x3b, 0xeb, 0x22, 0x3a, 0xa5, 0xd4, 0xd2, 0xdf, 0x67, 0x11, + 0x3c, 0xfd, 0x6c, 0xb5, 0x8e, 0xe0, 0xfd, 0xde, 0x64, 0x01, 0x76, 0xad, 0x00, 0x00, 0x04, 0x4d, + 0x48, 0x53, 0x2b, 0x21, 0xfb, 0x60, 0x79, 0xc9, 0x11, 0x4c, 0x0f, 0xfd, 0x9c, 0x04, 0xa1, 0xad, + 0x3e, 0x8c, 0xea, 0x98, 0x01, 0x71, 0x09, 0x97, 0x90, 0x84, 0xb1, 0xef, 0x92, 0xf9, 0x9d, 0x86, + 0xe2, 0x0f, 0xb4, 0x9b, 0xdb, 0x33, 0x7e, 0xe4, 0x8b, 0x8d, 0x8d, 0xc0, 0xf4, 0xaf, 0xef, 0xfe, + 0x5c, 0x25, 0x21, 0xea, 0xcd, 0x79, 0x66, 0xf1, 0x5e, 0x05, 0x65, 0x44, 0xbe, 0xa0, 0xd3, 0x15, + 0xe0, 0x67, 0xa7, 0x03, 0x19, 0x31, 0xa2, 0x46, 0xa6, 0xc3, 0x87, 0x5d, 0x2f, 0x67, 0x8a, 0xcb, + 0xa6, 0x4f, 0x70, 0xaf, 0x88, 0xae, 0x56, 0xb6, 0xf8, 0x75, 0x81, 0xc0, 0xe2, 0x3e, 0x6b, 0x08, + 0xf4, 0x49, 0x03, 0x1d, 0xe3, 0x12, 0x81, 0x4e, 0xc6, 0xf3, 0x19, 0x29, 0x1f, 0x4a, 0x05, 0x16, + 0xbd, 0xae, 0x85, 0x92, 0x4b, 0x3c, 0xb1, 0xd0, 0xa2, 0xe3, 0x3a, 0x30, 0xc6, 0xd7, 0x95, 0x99, + 0x8a, 0x0f, 0xed, 0xdb, 0xac, 0x86, 0x5a, 0x09, 0xbc, 0xd1, 0x27, 0xfb, 0x56, 0x2e, 0xd6, 0x0a, + 0xb5, 0x5a, 0x0a, 0x5b, 0x51, 0xa1, 0x2a, 0x8b, 0xe3, 0x48, 0x99, 0xc3, 0xe0, 0x47, 0x51, 0x1a, + 0xd9, 0xa0, 0x9c, 0xea, 0x3c, 0xe7, 0x5f, 0xe3, 0x96, 0x98, 0x07, 0x03, 0x17, 0xa7, 0x13, 0x39, + 0x55, 0x22, 0x25, 0xed, 0x11, 0x77, 0xf4, 0x45, 0x84, 0xac, 0x8c, 0xfa, 0x6c, 0x4e, 0xb5, 0xfc, + 0x7e, 0x82, 0xcb, 0xab, 0xfc, 0x95, 0x38, 0x1b, 0x08, 0x09, 0x98, 0x44, 0x21, 0x29, 0xc2, 0xf8, + 0x1f, 0x13, 0x5e, 0xd1, 0x4c, 0xe6, 0x0a, 0x91, 0x36, 0x9d, 0x23, 0x22, 0xbe, 0xf2, 0x5e, 0x3c, + 0x08, 0xb6, 0xbe, 0x45, 0x12, 0x4a, 0x43, 0xe2, 0xeb, 0x77, 0x95, 0x3f, 0x84, 0xdc, 0x85, 0x53, + }, + { + 0x9a, 0xc7, 0xcc, 0x9a, 0x60, 0x9d, 0x1e, 0xf7, 0xb2, 0x93, 0x28, 0x99, 0xcd, 0xe4, 0x1b, 0x97, + 0x52, 0x48, 0xc4, 0x95, 0x90, 0x14, 0x12, 0x6a, 0x6e, 0x8a, 0x84, 0xf1, 0x1d, 0x1a, 0x9e, 0x1c, + 0x06, 0x59, 0x02, 0xe4, 0xb6, 0x20, 0xf6, 0xcc, 0x36, 0xc8, 0x58, 0x9f, 0x66, 0x43, 0x2f, 0x2b, + 0xd3, 0x9d, 0x56, 0x6b, 0xc6, 0xbc, 0xe3, 0x01, 0x07, 0x68, 0x15, 0x15, 0x49, 0xf3, 0x87, 0x3f, + 0xb6, 0xd1, 0xe6, 0xc4, 0xa5, 0xe4, 0x77, 0x1c, 0xad, 0x79, 0x53, 0x8d, 0xf2, 0x95, 0xfb, 0x11, + 0xc6, 0x8c, 0x1d, 0x5c, 0x55, 0x9a, 0x97, 0x41, 0x23, 0xdf, 0x1d, 0xbc, 0x52, 0xa4, 0x3b, 0x89, + 0xc5, 0xec, 0xf8, 0x8d, 0xe8, 0x97, 0xfd, 0x57, 0xfe, 0xd3, 0x01, 0x70, 0x1b, 0x82, 0xa2, 0x59, + 0xec, 0xcb, 0xe1, 0x3d, 0xe1, 0xfc, 0xc9, 0x1c, 0x11, 0xa0, 0xb2, 0x6c, 0x0b, 0xc8, 0xfa, 0x4d, + 0xe7, 0xa7, 0x25, 0x74, 0xf8, 0x78, 0x2a, 0xe2, 0x6a, 0xab, 0xcf, 0x9e, 0xbc, 0xd6, 0x60, 0x65, + 0xbd, 0xf0, 0x32, 0x4e, 0x60, 0x83, 0xdc, 0xc6, 0xd3, 0xce, 0xdd, 0x3c, 0xa8, 0xc5, 0x3c, 0x16, + 0xb4, 0x01, 0x10, 0xc4, 0x19, 0x0b, 0x56, 0x22, 0xa9, 0x61, 0x16, 0xb0, 0x01, 0x7e, 0xd2, 0x97, + 0xff, 0xa0, 0xb5, 0x14, 0x64, 0x7e, 0xc0, 0x4f, 0x63, 0x06, 0xb8, 0x92, 0xae, 0x66, 0x11, 0x81, + 0xd0, 0x3d, 0x1b, 0xc0, 0x3c, 0xd3, 0x3d, 0x70, 0xdf, 0xf9, 0xfa, 0x5d, 0x71, 0x96, 0x3e, 0xbd, + 0x8a, 0x44, 0x12, 0x64, 0x11, 0xea, 0xa7, 0x8b, 0xd5, 0x1e, 0x8d, 0x87, 0xa8, 0x87, 0x9b, 0xf5, + 0xfa, 0xbe, 0xb7, 0x60, 0x28, 0xad, 0xe2, 0xd0, 0xe4, 0x87, 0x22, 0xe4, 0x6c, 0x46, 0x15, 0xa3, + 0xc0, 0x5d, 0x88, 0xab, 0xd5, 0x03, 0x57, 0xf9, 0x35, 0xa6, 0x3c, 0x59, 0xee, 0x53, 0x76, 0x23, + 0xff, 0x38, 0x26, 0x5c, 0x16, 0x42, 0xc1, 0xab, 0xe8, 0xd3, 0xc2, 0xfe, 0x5e, 0x57, 0x2b, 0xf8, + 0xa3, 0x6a, 0x4c, 0x30, 0x1a, 0xe8, 0xac, 0x13, 0x61, 0x0c, 0xcb, 0xc1, 0x22, 0x56, 0xca, 0xcc, + }, + { + 0x05, 0x95, 0xe5, 0x7f, 0xe5, 0xf0, 0xbb, 0x3c, 0x70, 0x6e, 0xda, 0xc8, 0xa4, 0xb2, 0xdb, 0x11, + 0xdf, 0xde, 0x31, 0x34, 0x4a, 0x1a, 0xf7, 0x69, 0xc7, 0x4f, 0x07, 0x0a, 0xee, 0x9e, 0x23, 0x26, + 0xb0, 0x6b, 0x9b, 0x1e, 0x19, 0x5d, 0x13, 0xd8, 0xf4, 0xa7, 0x99, 0x5c, 0x45, 0x53, 0xac, 0x05, + 0x6b, 0xd2, 0x37, 0x8e, 0xc3, 0x41, 0xc9, 0xa4, 0x2f, 0x37, 0xba, 0x79, 0xf8, 0x8a, 0x32, 0xff, + 0xe7, 0x0b, 0xce, 0x1d, 0xf7, 0x64, 0x5a, 0xdb, 0x5d, 0x2c, 0x41, 0x30, 0x21, 0x5c, 0x35, 0x22, + 0x9a, 0x57, 0x30, 0xc7, 0xfc, 0xb4, 0xc9, 0xaf, 0x51, 0xff, 0xda, 0x89, 0xc7, 0xf1, 0xad, 0x22, + 0x04, 0x85, 0x05, 0x5f, 0xd4, 0xf6, 0xf0, 0xd9, 0x63, 0xef, 0x5a, 0xb9, 0xa5, 0x47, 0x69, 0x82, + 0x59, 0x1f, 0xc6, 0x6b, 0xcd, 0xa1, 0x0e, 0x45, 0x2b, 0x03, 0xd4, 0x55, 0x1f, 0x6b, 0x62, 0xac, + 0x27, 0x53, 0xcc, 0x83, 0x98, 0x8a, 0xfa, 0x3e, 0x16, 0x88, 0xa1, 0xd3, 0xb4, 0x2c, 0x9a, 0x02, + 0x93, 0x61, 0x0d, 0x52, 0x3d, 0x1d, 0x3f, 0x00, 0x62, 0xb3, 0xc2, 0xa3, 0xbb, 0xc7, 0xc7, 0xf0, + 0x96, 0xc2, 0x48, 0x61, 0x0a, 0xad, 0xed, 0xfe, 0xaf, 0x89, 0x78, 0xc0, 0x3d, 0xe8, 0x20, 0x5a, + 0x0e, 0x31, 0x7b, 0x3d, 0x1c, 0x73, 0xb9, 0xe9, 0xa4, 0x68, 0x8f, 0x29, 0x6d, 0x13, 0x3a, 0x19, + 0xbd, 0xf0, 0xe6, 0xc3, 0xcc, 0xa5, 0xb5, 0xb9, 0xd5, 0x33, 0xb6, 0x9c, 0x56, 0xad, 0xa1, 0x20, + 0x88, 0xa2, 0x18, 0xb6, 0xe2, 0xec, 0xe1, 0xe6, 0x24, 0x6d, 0x44, 0xc7, 0x59, 0xd1, 0x9b, 0x10, + 0x68, 0x66, 0x39, 0x7e, 0x95, 0xc1, 0x40, 0x53, 0x4f, 0x94, 0x26, 0x34, 0x21, 0x00, 0x6e, 0x40, + 0x32, 0xcb, 0x0a, 0x1e, 0x95, 0x42, 0xc6, 0xb3, 0xb8, 0xb3, 0x98, 0xab, 0xc3, 0xb0, 0xf1, 0xd5, + 0x29, 0xa0, 0xb8, 0xae, 0xd5, 0x4a, 0x13, 0x23, 0x24, 0xc6, 0x2e, 0x42, 0x3f, 0x54, 0xb4, 0xc8, + 0x3c, 0xb0, 0xf3, 0xb5, 0x02, 0x0a, 0x98, 0xb8, 0x2a, 0xf9, 0xfe, 0x15, 0x44, 0x84, 0xa1, 0x68, + }, + { + 0xea, 0xa6, 0xbd, 0x25, 0x88, 0x0b, 0xf9, 0x3d, 0x3f, 0x5d, 0x1e, 0x4c, 0xa2, 0x61, 0x1d, 0x91, + 0xcf, 0xa4, 0x5c, 0x9f, 0x7e, 0x71, 0x4b, 0x54, 0xbd, 0xfa, 0x80, 0x02, 0x7c, 0xb1, 0x43, 0x80, + 0x11, 0x4a, 0xe3, 0x44, 0xde, 0xd7, 0x1b, 0x35, 0xf2, 0xe6, 0x0f, 0xeb, 0xad, 0x72, 0x7f, 0xd8, + 0x02, 0xe1, 0xe7, 0x05, 0x6b, 0x0f, 0x62, 0x39, 0x00, 0x49, 0x64, 0x22, 0x94, 0x3e, 0x97, 0xb6, + 0x91, 0xcb, 0x93, 0xc7, 0x87, 0x96, 0x4e, 0x10, 0xd9, 0x52, 0x7d, 0x99, 0x9c, 0x6f, 0x93, 0x6b, + 0x49, 0xb1, 0x8b, 0x42, 0xf8, 0xe8, 0x36, 0x7c, 0xbe, 0xb5, 0xef, 0x10, 0x4b, 0xa1, 0xc7, 0xcd, + 0x87, 0x08, 0x4b, 0x3b, 0xa7, 0x00, 0xba, 0xde, 0x95, 0x56, 0x10, 0x67, 0x27, 0x45, 0xb3, 0x74, + 0xe7, 0xa7, 0xb9, 0xe9, 0xec, 0x54, 0x0d, 0x5f, 0xf4, 0x3b, 0xdb, 0x12, 0x79, 0x2d, 0x1b, 0x35, + 0xc7, 0x99, 0xb5, 0x96, 0x73, 0x8f, 0x6b, 0x01, 0x8c, 0x76, 0xc7, 0x4b, 0x17, 0x59, 0xbd, 0x90, + 0x7f, 0xec, 0x5b, 0xfd, 0x9f, 0x9b, 0x89, 0xce, 0x65, 0x48, 0x30, 0x90, 0x92, 0xd7, 0xe9, 0x58, + 0x40, 0xf2, 0x50, 0xb2, 0x6d, 0x1f, 0x09, 0x6a, 0x4a, 0xfd, 0x4c, 0x34, 0x0a, 0x58, 0x88, 0x15, + 0x3e, 0x34, 0x13, 0x5c, 0x79, 0xdb, 0x01, 0x02, 0x00, 0x76, 0x76, 0x51, 0xcf, 0x26, 0x30, 0x73, + 0xf6, 0x56, 0xab, 0xcc, 0xf8, 0x8d, 0xd8, 0x27, 0x02, 0x7b, 0x2c, 0xe9, 0x17, 0xd4, 0x64, 0xec, + 0x18, 0xb6, 0x25, 0x03, 0xbf, 0xbc, 0x07, 0x7f, 0xba, 0xbb, 0x98, 0xf2, 0x0d, 0x98, 0xab, 0x34, + 0x8a, 0xed, 0x95, 0xee, 0x5b, 0x0d, 0xcb, 0xfb, 0xef, 0x4e, 0xb2, 0x1d, 0x3a, 0x3f, 0x52, 0xf9, + 0x62, 0x5a, 0x1a, 0xb0, 0x0e, 0xe3, 0x9a, 0x53, 0x27, 0x34, 0x6b, 0xdd, 0xb0, 0x1a, 0x9c, 0x18, + 0xa1, 0x3a, 0x7c, 0x79, 0xc7, 0xe1, 0x19, 0xb5, 0xab, 0x02, 0x96, 0xab, 0x28, 0xc3, 0x00, 0xb9, + 0xf3, 0xe4, 0xc0, 0xa2, 0xe0, 0x2d, 0x1d, 0x01, 0xf7, 0xf0, 0xa7, 0x46, 0x18, 0xaf, 0x2b, 0x48, + }, +}; + +unsigned char testdata2[][16 * 18] = { + { + 0x80, 0xad, 0x97, 0xbd, 0xc9, 0x73, 0xdf, 0x8a, 0x2e, 0x87, 0x9e, 0x92, 0xa4, 0x97, 0xef, 0xda, + 0x20, 0xf0, 0x60, 0xc2, 0xf2, 0xe5, 0x12, 0x65, 0x01, 0xd3, 0xd4, 0xfe, 0xa1, 0x0d, 0x5f, 0xc0, + 0xfa, 0xa1, 0x48, 0xe9, 0x90, 0x46, 0x18, 0x1f, 0xec, 0x6b, 0x20, 0x85, 0xf3, 0xb2, 0x0e, 0xd9, + 0xf0, 0xda, 0xf5, 0xba, 0xb3, 0xd5, 0x96, 0x83, 0x98, 0x57, 0x84, 0x6f, 0x73, 0xfb, 0xfe, 0x5a, + 0x1c, 0x7e, 0x2f, 0xc4, 0x63, 0x92, 0x32, 0xfe, 0x29, 0x75, 0x84, 0xb2, 0x96, 0x99, 0x6b, 0xc8, + 0x3d, 0xb9, 0xb2, 0x49, 0x40, 0x6c, 0xc8, 0xed, 0xff, 0xac, 0x55, 0xcc, 0xd3, 0x22, 0xba, 0x12, + 0xe4, 0xf9, 0xf7, 0xe0, 0x06, 0x61, 0x54, 0xbb, 0xd1, 0x25, 0xb7, 0x45, 0x56, 0x9b, 0xc8, 0x97, + 0x75, 0xd5, 0xef, 0x26, 0x2b, 0x44, 0xc4, 0x1a, 0x9c, 0xf6, 0x3a, 0xe1, 0x45, 0x68, 0xe1, 0xb9, + 0x6d, 0xa4, 0x53, 0xdb, 0xf8, 0x1e, 0x82, 0x33, 0x4a, 0x3d, 0x88, 0x66, 0xcb, 0x50, 0xa1, 0xe3, + 0x78, 0x28, 0xd0, 0x74, 0x11, 0x9c, 0xab, 0x5c, 0x22, 0xb2, 0x94, 0xd7, 0xa9, 0xbf, 0xa0, 0xbb, + 0xad, 0xb8, 0x9c, 0xea, 0x9a, 0x15, 0xfb, 0xe6, 0x17, 0x29, 0x5b, 0xd0, 0x4b, 0x8c, 0xa0, 0x5c, + 0x62, 0x51, 0xd8, 0x7f, 0xd4, 0xaa, 0xae, 0x9a, 0x7e, 0x4a, 0xd5, 0xc2, 0x17, 0xd3, 0xf3, 0x00, + 0xe7, 0x11, 0x9b, 0xd6, 0xdd, 0x9b, 0x22, 0xaf, 0xe8, 0xf8, 0x95, 0x85, 0x43, 0x28, 0x81, 0xe2, + 0x78, 0x5b, 0x60, 0xfd, 0x7e, 0xc4, 0xe9, 0xfc, 0xb6, 0x54, 0x5f, 0x35, 0x0d, 0x66, 0x0f, 0xab, + 0xaf, 0xec, 0xc0, 0x37, 0xfd, 0xb7, 0xb0, 0x83, 0x8e, 0xb3, 0xd7, 0x0b, 0xcd, 0x26, 0x83, 0x82, + 0xdb, 0xc1, 0xa7, 0xb4, 0x9d, 0x57, 0x35, 0x8c, 0xc9, 0xfa, 0x6d, 0x61, 0xd7, 0x3b, 0x7c, 0xf0, + 0x63, 0x49, 0xd1, 0x26, 0xa3, 0x7a, 0xfc, 0xba, 0x89, 0x79, 0x4f, 0x98, 0x04, 0x91, 0x4f, 0xdc, + 0xbf, 0x42, 0xc3, 0x01, 0x8c, 0x2f, 0x7c, 0x66, 0xbf, 0xde, 0x52, 0x49, 0x75, 0x76, 0x81, 0x15, + }, + { + 0xbc, 0x92, 0x22, 0xdb, 0xd3, 0x27, 0x4d, 0x8f, 0xc6, 0x6d, 0x14, 0xcc, 0xbd, 0xa6, 0x69, 0x0b, + 0x7a, 0xe6, 0x27, 0x41, 0x0c, 0x9a, 0x2b, 0xe6, 0x93, 0xdf, 0x5b, 0xb7, 0x48, 0x5a, 0x63, 0xe3, + 0x3f, 0x09, 0x31, 0xaa, 0x03, 0xde, 0xfb, 0x30, 0x0f, 0x06, 0x01, 0x03, 0x82, 0x6f, 0x2a, 0x64, + 0xbe, 0xaa, 0x9e, 0xc8, 0xd5, 0x9b, 0xb6, 0x81, 0x29, 0xf3, 0x02, 0x7c, 0x96, 0x36, 0x11, 0x81, + 0x74, 0xe0, 0x4d, 0xb4, 0x6d, 0x28, 0x64, 0x8d, 0x7d, 0xee, 0x8a, 0x00, 0x64, 0xb0, 0x6c, 0xfe, + 0x9b, 0x5e, 0x81, 0xc6, 0x2f, 0xe0, 0x23, 0xc5, 0x5b, 0xe4, 0x2f, 0x87, 0xbb, 0xf9, 0x32, 0xb8, + 0xce, 0x17, 0x8f, 0xc1, 0x82, 0x6e, 0xfe, 0xcb, 0xc1, 0x82, 0xf5, 0x79, 0x99, 0xa4, 0x61, 0x40, + 0x8b, 0xdf, 0x55, 0xcd, 0x55, 0x06, 0x1c, 0x06, 0xdb, 0xa6, 0xbe, 0x11, 0xde, 0x4a, 0x57, 0x8a, + 0x62, 0x6f, 0x5f, 0x4d, 0xce, 0x65, 0x25, 0x01, 0xf3, 0x08, 0x7d, 0x39, 0xc9, 0x2c, 0xc3, 0x49, + 0x42, 0xda, 0xac, 0x6a, 0x8f, 0x9a, 0xb9, 0xa7, 0xfd, 0x13, 0x7c, 0x60, 0x37, 0x82, 0x56, 0x82, + 0xcc, 0x03, 0xfd, 0xb7, 0x91, 0x92, 0xa2, 0x07, 0x31, 0x2f, 0x53, 0xf5, 0xd4, 0xdc, 0x33, 0xd9, + 0xf7, 0x0f, 0x14, 0x12, 0x2a, 0x1c, 0x98, 0xa3, 0x15, 0x5d, 0x28, 0xb8, 0xa0, 0xa8, 0xa4, 0x1d, + 0x2a, 0x3a, 0x30, 0x7a, 0xb2, 0x70, 0x8a, 0x9c, 0x00, 0xfe, 0x0b, 0x42, 0xf9, 0xc2, 0xd6, 0xa1, + 0x86, 0x26, 0x17, 0x62, 0x7d, 0x22, 0x61, 0xea, 0xb0, 0xb1, 0x24, 0x65, 0x97, 0xca, 0x0a, 0xe9, + 0x55, 0xf8, 0x77, 0xce, 0x4f, 0x2e, 0x1d, 0xdb, 0xbf, 0x8e, 0x13, 0xe2, 0xcd, 0xe0, 0xfd, 0xc8, + 0x1b, 0x15, 0x56, 0xcb, 0x93, 0x5f, 0x17, 0x33, 0x37, 0x70, 0x5f, 0xbb, 0x5d, 0x50, 0x1f, 0xc1, + 0xec, 0xd0, 0xe9, 0x66, 0x02, 0xbe, 0x7f, 0x8d, 0x50, 0x92, 0x81, 0x6c, 0xcc, 0xf2, 0xc2, 0xe9, + 0x02, 0x78, 0x81, 0xfa, 0xb4, 0x99, 0x3a, 0x1c, 0x26, 0x20, 0x24, 0xa9, 0x4f, 0xff, 0x3f, 0x61, + }, + { + 0xbb, 0xf6, 0x09, 0xde, 0x94, 0x13, 0x17, 0x2d, 0x07, 0x66, 0x0c, 0xb6, 0x80, 0x71, 0x69, 0x26, + 0x46, 0x10, 0x1a, 0x6d, 0xab, 0x43, 0x11, 0x5d, 0x6c, 0x52, 0x2b, 0x4f, 0xe9, 0x36, 0x04, 0xa9, + 0xcb, 0xe1, 0xff, 0xf2, 0x1c, 0x96, 0xf3, 0xee, 0xf6, 0x1e, 0x8f, 0xe0, 0x54, 0x2c, 0xbd, 0xf0, + 0x34, 0x79, 0x38, 0xbf, 0xfa, 0x40, 0x09, 0xc5, 0x12, 0xcf, 0xb4, 0x03, 0x4b, 0x0d, 0xd1, 0xa7, + 0x78, 0x67, 0xa7, 0x86, 0xd0, 0x0a, 0x71, 0x47, 0x90, 0x4d, 0x76, 0xdd, 0xf1, 0xe5, 0x20, 0xe3, + 0x8d, 0x3e, 0x9e, 0x1c, 0xae, 0xfc, 0xcc, 0xb3, 0xfb, 0xf8, 0xd1, 0x8f, 0x64, 0x12, 0x0b, 0x32, + 0x94, 0x23, 0x37, 0xf8, 0xfd, 0x76, 0xf0, 0xfa, 0xe8, 0xc5, 0x2d, 0x79, 0x54, 0x81, 0x06, 0x72, + 0xb8, 0x54, 0x8c, 0x10, 0xf5, 0x16, 0x67, 0xf6, 0xe6, 0x0e, 0x18, 0x2f, 0xa1, 0x9b, 0x30, 0xf7, + 0x02, 0x11, 0xc7, 0xc6, 0x19, 0x0c, 0x9e, 0xfd, 0x12, 0x37, 0xc3, 0x4c, 0x8f, 0x2e, 0x06, 0xc4, + 0xbd, 0xa6, 0x4f, 0x65, 0x27, 0x6d, 0x2a, 0xac, 0xb8, 0xf9, 0x02, 0x12, 0x20, 0x3a, 0x80, 0x8e, + 0xbd, 0x38, 0x20, 0xf7, 0x32, 0xff, 0xb5, 0x3e, 0xc1, 0x93, 0xe7, 0x9d, 0x33, 0xe2, 0x7c, 0x73, + 0xd0, 0x16, 0x86, 0x16, 0x86, 0x19, 0x07, 0xd4, 0x82, 0xe3, 0x6c, 0xda, 0xc8, 0xcf, 0x57, 0x49, + 0x97, 0xb0, 0xf0, 0xf2, 0x24, 0xb2, 0xd2, 0x31, 0x71, 0x14, 0x80, 0x8f, 0xb0, 0x3a, 0xf7, 0xa0, + 0xe5, 0x96, 0x16, 0xe4, 0x69, 0x78, 0x79, 0x39, 0xa0, 0x63, 0xce, 0xea, 0x9a, 0xf9, 0x56, 0xd1, + 0xc4, 0x7e, 0x0d, 0xc1, 0x66, 0x09, 0x19, 0xc1, 0x11, 0x01, 0x20, 0x8f, 0x9e, 0x69, 0xaa, 0x1f, + 0x5a, 0xe4, 0xf1, 0x28, 0x96, 0xb8, 0x37, 0x9a, 0x2a, 0xad, 0x89, 0xb5, 0xb5, 0x53, 0xd6, 0xb0, + 0x6b, 0x6b, 0x09, 0x8d, 0x0c, 0x29, 0x3b, 0xc2, 0x99, 0x3d, 0x80, 0xbf, 0x05, 0x18, 0xb6, 0xd9, + 0x81, 0x70, 0xcc, 0x3c, 0xcd, 0x92, 0xa6, 0x98, 0x62, 0x1b, 0x93, 0x9d, 0xd3, 0x8f, 0xe7, 0xb9, + }, + { + 0xab, 0x65, 0xc2, 0x6e, 0xdd, 0xb2, 0x87, 0x60, 0x0d, 0xb2, 0xfd, 0xa1, 0x0d, 0x1e, 0x60, 0x5c, + 0xbb, 0x75, 0x90, 0x10, 0xc2, 0x96, 0x58, 0xf2, 0xc7, 0x2d, 0x93, 0xa2, 0xd1, 0x6d, 0x29, 0x30, + 0xb9, 0x01, 0xe8, 0x03, 0x6e, 0xd1, 0xc3, 0x83, 0xcd, 0x3c, 0x4c, 0x4d, 0xd0, 0xa6, 0xab, 0x05, + 0x3d, 0x25, 0xce, 0x49, 0x22, 0x92, 0x4c, 0x55, 0xf0, 0x64, 0x94, 0x33, 0x53, 0xd7, 0x8a, 0x6c, + 0x12, 0xc1, 0xaa, 0x44, 0xbb, 0xf8, 0x7e, 0x75, 0xe6, 0x11, 0xf6, 0x9b, 0x2c, 0x38, 0xf4, 0x9b, + 0x28, 0xf2, 0xb3, 0x43, 0x4b, 0x65, 0xc0, 0x98, 0x77, 0x47, 0x00, 0x44, 0xc6, 0xea, 0x17, 0x0d, + 0xbd, 0x9e, 0xf8, 0x22, 0xde, 0x52, 0x88, 0x19, 0x61, 0x34, 0xcf, 0x8a, 0xf7, 0x83, 0x93, 0x04, + 0x67, 0x55, 0x9c, 0x23, 0xf0, 0x52, 0x15, 0x84, 0x70, 0xa2, 0x96, 0xf7, 0x25, 0x73, 0x5a, 0x32, + 0x8b, 0xab, 0x26, 0xfb, 0xc2, 0xc1, 0x2b, 0x0f, 0x13, 0xe2, 0xab, 0x18, 0x5e, 0xab, 0xf2, 0x41, + 0x31, 0x18, 0x5a, 0x6d, 0x69, 0x6f, 0x0c, 0xfa, 0x9b, 0x42, 0x80, 0x8b, 0x38, 0xe1, 0x32, 0xa2, + 0x56, 0x4d, 0x3d, 0xae, 0x18, 0x3c, 0x52, 0x34, 0xc8, 0xaf, 0x1e, 0x51, 0x06, 0x1c, 0x44, 0xb5, + 0x3c, 0x07, 0x78, 0xa7, 0xb5, 0xf7, 0x2d, 0x3c, 0x23, 0xa3, 0x13, 0x5c, 0x7d, 0x67, 0xb9, 0xf4, + 0xf3, 0x43, 0x69, 0x89, 0x0f, 0xcf, 0x16, 0xfb, 0x51, 0x7d, 0xca, 0xae, 0x44, 0x63, 0xb2, 0xdd, + 0x02, 0xf3, 0x1c, 0x81, 0xe8, 0x20, 0x07, 0x31, 0xb8, 0x99, 0xb0, 0x28, 0xe7, 0x91, 0xbf, 0xa7, + 0x72, 0xda, 0x64, 0x62, 0x83, 0x22, 0x8c, 0x14, 0x30, 0x08, 0x53, 0x70, 0x17, 0x95, 0x61, 0x6f, + 0x4e, 0x0a, 0x8c, 0x6f, 0x79, 0x34, 0xa7, 0x88, 0xe2, 0x26, 0x5e, 0x81, 0xd6, 0xd0, 0xc8, 0xf4, + 0x43, 0x8d, 0xd5, 0xea, 0xfe, 0xa0, 0x11, 0x1b, 0x6f, 0x36, 0xb4, 0xb9, 0x38, 0xda, 0x2a, 0x68, + 0x5f, 0x6b, 0xfc, 0x73, 0x81, 0x58, 0x74, 0xd9, 0x71, 0x00, 0xf0, 0x86, 0x97, 0x93, 0x57, 0xd8, + }, + { + 0x72, 0x0c, 0x94, 0xb6, 0x3e, 0xdf, 0x44, 0xe1, 0x31, 0xd9, 0x50, 0xca, 0x21, 0x1a, 0x5a, 0x30, + 0xc3, 0x66, 0xfd, 0xea, 0xcf, 0x9c, 0xa8, 0x04, 0x36, 0xbe, 0x7c, 0x35, 0x84, 0x24, 0xd2, 0x0b, + 0xb3, 0x39, 0x4a, 0x40, 0xaa, 0xbf, 0x75, 0xcb, 0xa4, 0x22, 0x82, 0xef, 0x25, 0xa0, 0x05, 0x9f, + 0x48, 0x47, 0xd8, 0x1d, 0xa4, 0x94, 0x2d, 0xbc, 0x24, 0x9d, 0xef, 0xc4, 0x8c, 0x92, 0x2b, 0x9f, + 0x08, 0x12, 0x8c, 0x46, 0x9f, 0x27, 0x53, 0x42, 0xad, 0xda, 0x20, 0x2b, 0x2b, 0x58, 0xda, 0x95, + 0x97, 0x0d, 0xac, 0xef, 0x40, 0xad, 0x98, 0x72, 0x3b, 0xac, 0x5d, 0x69, 0x55, 0xb8, 0x17, 0x61, + 0x3c, 0xb8, 0x99, 0x93, 0xb0, 0x7b, 0x0c, 0xed, 0x93, 0xde, 0x13, 0xd2, 0xa1, 0x10, 0x13, 0xac, + 0xef, 0x2d, 0x67, 0x6f, 0x15, 0x45, 0xc2, 0xc1, 0x3d, 0xc6, 0x80, 0xa0, 0x2f, 0x4a, 0xdb, 0xfe, + 0xb6, 0x05, 0x95, 0x51, 0x4f, 0x24, 0xbc, 0x9f, 0xe5, 0x22, 0xa6, 0xca, 0xd7, 0x39, 0x36, 0x44, + 0xb5, 0x15, 0xa8, 0xc5, 0x01, 0x17, 0x54, 0xf5, 0x90, 0x03, 0x05, 0x8b, 0xdb, 0x81, 0x51, 0x4e, + 0x3c, 0x70, 0x04, 0x7e, 0x8c, 0xbc, 0x03, 0x8e, 0x3b, 0x98, 0x20, 0xdb, 0x60, 0x1d, 0xa4, 0x95, + 0x11, 0x75, 0xda, 0x6e, 0xe7, 0x56, 0xde, 0x46, 0xa5, 0x3e, 0x2b, 0x07, 0x56, 0x60, 0xb7, 0x70, + 0x00, 0xa5, 0x42, 0xbb, 0xa0, 0x21, 0x11, 0xcc, 0x2c, 0x65, 0xb3, 0x8e, 0xbd, 0xba, 0x58, 0x7e, + 0x58, 0x65, 0xfd, 0xbb, 0x5b, 0x48, 0x06, 0x41, 0x04, 0xe8, 0x30, 0xb3, 0x80, 0xf2, 0xae, 0xde, + 0x34, 0xb2, 0x1a, 0xd2, 0xad, 0x44, 0xe9, 0x99, 0xdb, 0x2d, 0x7f, 0x08, 0x63, 0xf0, 0xd9, 0xb6, + 0x84, 0xa9, 0x21, 0x8f, 0xc3, 0x6e, 0x8a, 0x5f, 0x2c, 0xcf, 0xbe, 0xae, 0x53, 0xa2, 0x7d, 0x25, + 0xa2, 0x22, 0x1a, 0x11, 0xb8, 0x33, 0xcc, 0xb4, 0x98, 0xa5, 0x95, 0x40, 0xf0, 0x54, 0x5f, 0x4a, + 0x5b, 0xbe, 0xb4, 0x78, 0x7d, 0x59, 0xe5, 0x37, 0x3f, 0xdb, 0xea, 0x6c, 0x6f, 0x75, 0xc2, 0x9b, + }, + { + 0x54, 0xb6, 0x4e, 0x6b, 0x5a, 0x20, 0xb5, 0xe2, 0xec, 0x84, 0x59, 0x3d, 0xc7, 0x98, 0x9d, 0xa7, + 0xc1, 0x35, 0xee, 0xe2, 0x37, 0xa8, 0x54, 0x65, 0xff, 0x97, 0xdc, 0x03, 0x92, 0x4f, 0x45, 0xce, + 0xcf, 0xcc, 0x92, 0x2f, 0xb4, 0xa1, 0x4a, 0xb4, 0x5d, 0x61, 0x75, 0xaa, 0xbb, 0xf2, 0xd2, 0x01, + 0x83, 0x7b, 0x87, 0xe2, 0xa4, 0x46, 0xad, 0x0e, 0xf7, 0x98, 0xac, 0xd0, 0x2b, 0x94, 0x12, 0x4f, + 0x17, 0xa6, 0xdb, 0xd6, 0x64, 0x92, 0x6a, 0x06, 0x36, 0xb3, 0xf4, 0xc3, 0x7a, 0x4f, 0x46, 0x94, + 0x4a, 0x5f, 0x9f, 0x26, 0xae, 0xee, 0xd4, 0xd4, 0xa2, 0x5f, 0x63, 0x2d, 0x30, 0x52, 0x33, 0xd9, + 0x80, 0xa3, 0xd0, 0x1e, 0xf0, 0x0c, 0x8e, 0x9a, 0x42, 0x09, 0xc1, 0x7f, 0x4e, 0xeb, 0x35, 0x8c, + 0xd1, 0x5e, 0x7d, 0x5f, 0xfa, 0xaa, 0xbc, 0x02, 0x07, 0xbf, 0x20, 0x0a, 0x11, 0x77, 0x93, 0xa2, + 0x34, 0x96, 0x82, 0xbf, 0x58, 0x8e, 0xaa, 0x52, 0xd0, 0xaa, 0x15, 0x60, 0x34, 0x6a, 0xea, 0xfa, + 0xf5, 0x85, 0x4c, 0xdb, 0x76, 0xc8, 0x89, 0xe3, 0xad, 0x63, 0x35, 0x4e, 0x5f, 0x72, 0x75, 0xe3, + 0x53, 0x2c, 0x7c, 0xec, 0xcb, 0x39, 0xdf, 0x32, 0x36, 0x31, 0x84, 0x05, 0xa4, 0xb1, 0x27, 0x9c, + 0xba, 0xef, 0xe6, 0xd9, 0xce, 0xb6, 0x51, 0x84, 0x22, 0x60, 0xe0, 0xd1, 0xe0, 0x5e, 0x3b, 0x90, + 0xe8, 0x2d, 0x8c, 0x6d, 0xb5, 0x4e, 0x3c, 0x63, 0x3f, 0x58, 0x1c, 0x95, 0x2b, 0xa0, 0x42, 0x07, + 0x4b, 0x16, 0xe5, 0x0a, 0xbd, 0x38, 0x1b, 0xd7, 0x09, 0x00, 0xa9, 0xcd, 0x9a, 0x62, 0xcb, 0x23, + 0x36, 0x82, 0xee, 0x33, 0xbd, 0x14, 0x8b, 0xd9, 0xf5, 0x86, 0x56, 0xcd, 0x8f, 0x30, 0xd9, 0xfb, + 0x1e, 0x5a, 0x0b, 0x84, 0x75, 0x04, 0x5d, 0x9b, 0x20, 0xb2, 0x62, 0x86, 0x24, 0xed, 0xfd, 0x9e, + 0x63, 0xed, 0xd6, 0x84, 0xfb, 0x82, 0x62, 0x82, 0xfe, 0x52, 0x8f, 0x9c, 0x0e, 0x92, 0x37, 0xbc, + 0xe4, 0xdd, 0x2e, 0x98, 0xd6, 0x96, 0x0f, 0xae, 0x0b, 0x43, 0x54, 0x54, 0x56, 0x74, 0x33, 0x91, + }, + { + 0xdd, 0x5b, 0xcb, 0x00, 0x18, 0xe9, 0x22, 0xd4, 0x94, 0x75, 0x9d, 0x7c, 0x39, 0x5d, 0x02, 0xd3, + 0xc8, 0x44, 0x6f, 0x8f, 0x77, 0xab, 0xf7, 0x37, 0x68, 0x53, 0x53, 0xeb, 0x89, 0xa1, 0xc9, 0xeb, + 0xaf, 0x3e, 0x30, 0xf9, 0xc0, 0x95, 0x04, 0x59, 0x38, 0x15, 0x15, 0x75, 0xc3, 0xfb, 0x90, 0x98, + 0xf8, 0xcb, 0x62, 0x74, 0xdb, 0x99, 0xb8, 0x0b, 0x1d, 0x20, 0x12, 0xa9, 0x8e, 0xd4, 0x8f, 0x0e, + 0x25, 0xc3, 0x00, 0x5a, 0x1c, 0xb8, 0x5d, 0xe0, 0x76, 0x25, 0x98, 0x39, 0xab, 0x71, 0x98, 0xab, + 0x9d, 0xcb, 0xc1, 0x83, 0xe8, 0xcb, 0x99, 0x4b, 0x72, 0x7b, 0x75, 0xbe, 0x31, 0x80, 0x76, 0x9c, + 0xa1, 0xd3, 0x07, 0x8d, 0xfa, 0x91, 0x69, 0x50, 0x3e, 0xd9, 0xd4, 0x49, 0x1d, 0xee, 0x4e, 0xb2, + 0x85, 0x14, 0xa5, 0x49, 0x58, 0x58, 0x09, 0x6f, 0x59, 0x6e, 0x4b, 0xcd, 0x66, 0xb1, 0x06, 0x65, + 0x5f, 0x40, 0xd5, 0x9e, 0xc1, 0xb0, 0x3b, 0x33, 0x73, 0x8e, 0xfa, 0x60, 0xb2, 0x25, 0x5d, 0x31, + 0x34, 0x77, 0xc7, 0xf7, 0x64, 0xa4, 0x1b, 0xac, 0xef, 0xf9, 0x0b, 0xf1, 0x4f, 0x92, 0xb7, 0xcc, + 0xac, 0x4e, 0x95, 0x36, 0x8d, 0x99, 0xb9, 0xeb, 0x78, 0xb8, 0xda, 0x8f, 0x81, 0xff, 0xa7, 0x95, + 0x8c, 0x3c, 0x13, 0xf8, 0xc2, 0x38, 0x8b, 0xb7, 0x3f, 0x38, 0x57, 0x6e, 0x65, 0xb7, 0xc4, 0x46, + 0x13, 0xc4, 0xb9, 0xc1, 0xdf, 0xb6, 0x65, 0x79, 0xed, 0xdd, 0x8a, 0x28, 0x0b, 0x9f, 0x73, 0x16, + 0xdd, 0xd2, 0x78, 0x20, 0x55, 0x01, 0x26, 0x69, 0x8e, 0xfa, 0xad, 0xc6, 0x4b, 0x64, 0xf6, 0x6e, + 0xf0, 0x8f, 0x2e, 0x66, 0xd2, 0x8e, 0xd1, 0x43, 0xf3, 0xa2, 0x37, 0xcf, 0x9d, 0xe7, 0x35, 0x59, + 0x9e, 0xa3, 0x6c, 0x52, 0x55, 0x31, 0xb8, 0x80, 0xba, 0x12, 0x43, 0x34, 0xf5, 0x7b, 0x0b, 0x70, + 0xd5, 0xa3, 0x9e, 0x3d, 0xfc, 0xc5, 0x02, 0x80, 0xba, 0xc4, 0xa6, 0xb5, 0xaa, 0x0d, 0xca, 0x7d, + 0x37, 0x0b, 0x1c, 0x1f, 0xe6, 0x55, 0x91, 0x6d, 0x97, 0xfd, 0x0d, 0x47, 0xca, 0x1d, 0x72, 0xb8, + }, +}; + +int main(void) +{ + int err = 0; + RC4_STATE state; + unsigned char buf[4096 + 16]; + size_t i, j; + + for (i = 0; i < sizeof(keybits)/sizeof(keybits[0]); i++) { + int e = 0; + rc4_set_key(&state, key1, keybits[i]/8); + rc4_generate_keystream(&state, sizeof(buf), buf); + for (j = 0; j < sizeof(testindex)/sizeof(testindex[0]); j++) { + if (memcmp(buf + testindex[j], &testdata1[i][j * 16], 16) != 0) { + e++; + } + } + fprintf(stderr, "rc4 test 1.%zu %s\n", i+1, e ? "failed" : "ok"); + if (e) { + err++; + } + } + + for (i = 0; i < sizeof(keybits)/sizeof(keybits[0]); i++) { + int e = 0; + rc4_set_key(&state, key2 + sizeof(key2) - keybits[i]/8, keybits[i]/8); + rc4_generate_keystream(&state, sizeof(buf), buf); + for (j = 0; j < sizeof(testindex)/sizeof(testindex[0]); j++) { + if (memcmp(buf + testindex[j], &testdata2[i][j * 16], 16) != 0) { + e++; + } + } + fprintf(stderr, "rc4 test 2.%zu %s\n", i+1, e ? "failed" : "ok"); + if (e) { + err++; + } + } + + return err; +} diff --git a/tests/sha1test.c b/tests/sha1test.c new file mode 100644 index 00000000..b3fe25dd --- /dev/null +++ b/tests/sha1test.c @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2014 - 2020 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + +#include +#include +#include +#include +#include + + +static char *teststr[] = { + "abc", + "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", + "a", + "0123456701234567012345670123456701234567012345670123456701234567", +}; + +static size_t testcnt[] = { + 1, + 1, + 1000000, + 10, +}; + +static char *dgsthex[] = { + "A9993E364706816ABA3E25717850C26C9CD0D89D", + "84983E441C3BD26EBAAE4AA1F95129E5E54670F1", + "34AA973CD4C4DAA4F61EEB2BDBAD27316534016F", + "DEA356A2CDDD90C7A7ECEDC5EBB563934F460452", +}; + +int main(void) +{ + int err = 0; + SHA1_CTX ctx; + unsigned char dgst[20]; + unsigned char *dgstbuf = NULL; + size_t i, j; + + for (i = 0; i < sizeof(teststr)/sizeof(teststr[0]); i++) { + + if (!(dgstbuf = OPENSSL_hexstr2buf(dgsthex[i], NULL))) { + goto end; + } + + sha1_init(&ctx); + for (j = 0; j < testcnt[i]; j++) { + sha1_update(&ctx, (unsigned char *)teststr[i], strlen(teststr[i])); + } + sha1_finish(&ctx, dgst); + + if (memcmp(dgstbuf, dgst, sizeof(dgst)) != 0) { + printf("sha1 test %lu failed\n", i+1); + printf("%s\n", dgsthex[i]); + for (j = 0; j < sizeof(dgst); j++) { + printf("%02X", dgst[j]); + } + printf("\n"); + err++; + } else { + printf("sha1 test %lu ok\n", i+1); + } + + free(dgstbuf); + dgstbuf = NULL; + } + +end: + if (dgstbuf) free(dgstbuf); + return err; +} diff --git a/tests/sha224test.c b/tests/sha224test.c new file mode 100644 index 00000000..ff9c6c54 --- /dev/null +++ b/tests/sha224test.c @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2014 - 2020 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + +#include +#include +#include +#include +#include + + +#define TEST1 "abc" +#define TEST2 "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" +#define TEST3 "a" +#define TEST4 "0123456701234567012345670123456701234567012345670123456701234567" +#define TEST5 "\x07" +#define TEST6 "\x18\x80\x40\x05\xdd\x4f\xbd\x15\x56\x29\x9d\x6f\x9d\x93\xdf\x62" +#define TEST7 \ + "\x55\xb2\x10\x07\x9c\x61\xb5\x3a\xdd\x52\x06\x22\xd1\xac\x97\xd5" \ + "\xcd\xbe\x8c\xb3\x3a\xa0\xae\x34\x45\x17\xbe\xe4\xd7\xba\x09\xab" \ + "\xc8\x53\x3c\x52\x50\x88\x7a\x43\xbe\xbb\xac\x90\x6c\x2e\x18\x37" \ + "\xf2\x6b\x36\xa5\x9a\xe3\xbe\x78\x14\xd5\x06\x89\x6b\x71\x8b\x2a" \ + "\x38\x3e\xcd\xac\x16\xb9\x61\x25\x55\x3f\x41\x6f\xf3\x2c\x66\x74" \ + "\xc7\x45\x99\xa9\x00\x53\x86\xd9\xce\x11\x12\x24\x5f\x48\xee\x47" \ + "\x0d\x39\x6c\x1e\xd6\x3b\x92\x67\x0c\xa5\x6e\xc8\x4d\xee\xa8\x14" \ + "\xb6\x13\x5e\xca\x54\x39\x2b\xde\xdb\x94\x89\xbc\x9b\x87\x5a\x8b" \ + "\xaf\x0d\xc1\xae\x78\x57\x36\x91\x4a\xb7\xda\xa2\x64\xbc\x07\x9d" \ + "\x26\x9f\x2c\x0d\x7e\xdd\xd8\x10\xa4\x26\x14\x5a\x07\x76\xf6\x7c" \ + "\x87\x82\x73" + + +#define DGST1 "23097D223405D8228642A477BDA255B32AADBCE4BDA0B3F7E36C9DA7" +#define DGST2 "75388B16512776CC5DBA5DA1FD890150B0C6455CB4F58B1952522525" +#define DGST3 "20794655980C91D8BBB4C1EA97618A4BF03F42581948B2EE4EE7AD67" +#define DGST4 "567F69F168CD7844E65259CE658FE7AADFA25216E68ECA0EB7AB8262" +#define DGST5 "00ECD5F138422B8AD74C9799FD826C531BAD2FCABC7450BEE2AA8C2A" +#define DGST6 "DF90D78AA78821C99B40BA4C966921ACCD8FFB1E98AC388E56191DB1" +#define DGST7 "0B31894EC8937AD9B91BDFBCBA294D9ADEFAA18E09305E9F20D5C3A4" + +struct { + char *data; + size_t length; + size_t count; + char *dgsthex; +} tests[7] = { + {TEST1, sizeof(TEST1) - 1, 1, DGST1}, + {TEST2, sizeof(TEST2) - 1, 1, DGST2}, + {TEST3, sizeof(TEST3) - 1, 1000000, DGST3}, + {TEST4, sizeof(TEST4) - 1, 10, DGST4}, + {TEST5, sizeof(TEST5) - 1, 1, DGST5}, + {TEST6, sizeof(TEST6) - 1, 1, DGST6}, + {TEST7, sizeof(TEST7) - 1, 1, DGST7}, +}; + +int main(int argc, char **argv) +{ + int err = 0; + SHA224_CTX ctx; + unsigned char dgst[SHA224_DIGEST_SIZE]; + unsigned char *dgstbuf = NULL; + size_t i, j; + + for (i = 0; i < 7; i++) { + + if (!(dgstbuf = OPENSSL_hexstr2buf(tests[i].dgsthex, NULL))) { + goto end; + } + + sha224_init(&ctx); + for (j = 0; j < tests[i].count; j++) { + sha224_update(&ctx, (unsigned char *)tests[i].data, tests[i].length); + } + sha224_finish(&ctx, dgst); + + if (memcmp(dgstbuf, dgst, sizeof(dgst)) != 0) { + printf("sha224 test %lu failed\n", i+1); + printf("%s\n", tests[i].dgsthex); + for (j = 0; j < sizeof(dgst); j++) { + printf("%02X", dgst[j]); + } + printf("\n"); + err++; + } else { + printf("sha224 test %lu ok\n", i+1); + } + + free(dgstbuf); + dgstbuf = NULL; + } + +end: + if (dgstbuf) free(dgstbuf); + return err; +} diff --git a/tests/sha256test.c b/tests/sha256test.c new file mode 100644 index 00000000..621b5136 --- /dev/null +++ b/tests/sha256test.c @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2014 - 2020 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + + +#include +#include +#include +#include +#include + + +#define TEST1 "abc" +#define TEST2 "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" +#define TEST3 "a" +#define TEST4 "0123456701234567012345670123456701234567012345670123456701234567" +#define TEST5 "\x19" +#define TEST6 "\xe3\xd7\x25\x70\xdc\xdd\x78\x7c\xe3\x88\x7a\xb2\xcd\x68\x46\x52" +#define TEST7 "\x83\x26\x75\x4e\x22\x77\x37\x2f\x4f\xc1\x2b\x20\x52\x7a\xfe\xf0" \ + "\x4d\x8a\x05\x69\x71\xb1\x1a\xd5\x71\x23\xa7\xc1\x37\x76\x00\x00" \ + "\xd7\xbe\xf6\xf3\xc1\xf7\xa9\x08\x3a\xa3\x9d\x81\x0d\xb3\x10\x77" \ + "\x7d\xab\x8b\x1e\x7f\x02\xb8\x4a\x26\xc7\x73\x32\x5f\x8b\x23\x74" \ + "\xde\x7a\x4b\x5a\x58\xcb\x5c\x5c\xf3\x5b\xce\xe6\xfb\x94\x6e\x5b" \ + "\xd6\x94\xfa\x59\x3a\x8b\xeb\x3f\x9d\x65\x92\xec\xed\xaa\x66\xca" \ + "\x82\xa2\x9d\x0c\x51\xbc\xf9\x33\x62\x30\xe5\xd7\x84\xe4\xc0\xa4" \ + "\x3f\x8d\x79\xa3\x0a\x16\x5c\xba\xbe\x45\x2b\x77\x4b\x9c\x71\x09" \ + "\xa9\x7d\x13\x8f\x12\x92\x28\x96\x6f\x6c\x0a\xdc\x10\x6a\xad\x5a" \ + "\x9f\xdd\x30\x82\x57\x69\xb2\xc6\x71\xaf\x67\x59\xdf\x28\xeb\x39" \ + "\x3d\x54\xd6" + +#define DGST1 "BA7816BF8F01CFEA414140DE5DAE2223B00361A396177A9CB410FF61F20015AD" +#define DGST2 "248D6A61D20638B8E5C026930C3E6039A33CE45964FF2167F6ECEDD419DB06C1" +#define DGST3 "CDC76E5C9914FB9281A1C7E284D73E67F1809A48A497200E046D39CCC7112CD0" +#define DGST4 "594847328451BDFA85056225462CC1D867D877FB388DF0CE35F25AB5562BFBB5" +#define DGST5 "68AA2E2EE5DFF96E3355E6C7EE373E3D6A4E17F75F9518D843709C0C9BC3E3D4" +#define DGST6 "175EE69B02BA9B58E2B0A5FD13819CEA573F3940A94F825128CF4209BEABB4E8" +#define DGST7 "97DBCA7DF46D62C8A422C941DD7E835B8AD3361763F7E9B2D95F4F0DA6E1CCBC" + +struct { + char *data; + size_t length; + size_t count; + char *dgsthex; +} tests[7] = { + {TEST1, sizeof(TEST1) - 1, 1, DGST1}, + {TEST2, sizeof(TEST2) - 1, 1, DGST2}, + {TEST3, sizeof(TEST3) - 1, 1000000, DGST3}, + {TEST4, sizeof(TEST4) - 1, 10, DGST4}, + {TEST5, sizeof(TEST5) - 1, 1, DGST5}, + {TEST6, sizeof(TEST6) - 1, 1, DGST6}, + {TEST7, sizeof(TEST7) - 1, 1, DGST7}, +}; + +int main(int argc, char **argv) +{ + int err = 0; + SHA256_CTX ctx; + unsigned char dgst[SHA256_DIGEST_SIZE]; + unsigned char *dgstbuf = NULL; + size_t i, j; + + for (i = 0; i < 7; i++) { + + if (!(dgstbuf = OPENSSL_hexstr2buf(tests[i].dgsthex, NULL))) { + goto end; + } + + sha256_init(&ctx); + for (j = 0; j < tests[i].count; j++) { + sha256_update(&ctx, (unsigned char *)tests[i].data, tests[i].length); + } + sha256_finish(&ctx, dgst); + + if (memcmp(dgstbuf, dgst, sizeof(dgst)) != 0) { + printf("sha256 test %lu failed\n", i+1); + printf("%s\n", tests[i].dgsthex); + for (j = 0; j < sizeof(dgst); j++) { + printf("%02X", dgst[j]); + } + printf("\n"); + err++; + } else { + printf("sha256 test %lu ok\n", i+1); + } + + free(dgstbuf); + dgstbuf = NULL; + } + +end: + if (dgstbuf) free(dgstbuf); + return err; +} diff --git a/tests/sha384test.c b/tests/sha384test.c new file mode 100644 index 00000000..1f57954e --- /dev/null +++ b/tests/sha384test.c @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2014 - 2020 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + + +#include +#include +#include +#include +#include + + +#define TEST1 "abc" +#define TEST2 "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn" \ + "hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu" +#define TEST3 "a" +#define TEST4 "0123456701234567012345670123456701234567012345670123456701234567" +#define TEST5 "\xb9" +#define TEST6 "\xa4\x1c\x49\x77\x79\xc0\x37\x5f\xf1\x0a\x7f\x4e\x08\x59\x17\x39" +#define TEST7 "\x39\x96\x69\xe2\x8f\x6b\x9c\x6d\xbc\xbb\x69\x12\xec\x10\xff\xcf" \ + "\x74\x79\x03\x49\xb7\xdc\x8f\xbe\x4a\x8e\x7b\x3b\x56\x21\xdb\x0f" \ + "\x3e\x7d\xc8\x7f\x82\x32\x64\xbb\xe4\x0d\x18\x11\xc9\xea\x20\x61" \ + "\xe1\xc8\x4a\xd1\x0a\x23\xfa\xc1\x72\x7e\x72\x02\xfc\x3f\x50\x42" \ + "\xe6\xbf\x58\xcb\xa8\xa2\x74\x6e\x1f\x64\xf9\xb9\xea\x35\x2c\x71" \ + "\x15\x07\x05\x3c\xf4\xe5\x33\x9d\x52\x86\x5f\x25\xcc\x22\xb5\xe8" \ + "\x77\x84\xa1\x2f\xc9\x61\xd6\x6c\xb6\xe8\x95\x73\x19\x9a\x2c\xe6" \ + "\x56\x5c\xbd\xf1\x3d\xca\x40\x38\x32\xcf\xcb\x0e\x8b\x72\x11\xe8" \ + "\x3a\xf3\x2a\x11\xac\x17\x92\x9f\xf1\xc0\x73\xa5\x1c\xc0\x27\xaa" \ + "\xed\xef\xf8\x5a\xad\x7c\x2b\x7c\x5a\x80\x3e\x24\x04\xd9\x6d\x2a" \ + "\x77\x35\x7b\xda\x1a\x6d\xae\xed\x17\x15\x1c\xb9\xbc\x51\x25\xa4" \ + "\x22\xe9\x41\xde\x0c\xa0\xfc\x50\x11\xc2\x3e\xcf\xfe\xfd\xd0\x96" \ + "\x76\x71\x1c\xf3\xdb\x0a\x34\x40\x72\x0e\x16\x15\xc1\xf2\x2f\xbc" \ + "\x3c\x72\x1d\xe5\x21\xe1\xb9\x9b\xa1\xbd\x55\x77\x40\x86\x42\x14" \ + "\x7e\xd0\x96" + +#define DGST1 "CB00753F45A35E8BB5A03D699AC65007272C32AB0EDED1631A8B605A43FF5BED8086072BA1E7CC2358BAECA134C825A7" +#define DGST2 "09330C33F71147E83D192FC782CD1B4753111B173B3B05D22FA08086E3B0F712FCC7C71A557E2DB966C3E9FA91746039" +#define DGST3 "9D0E1809716474CB086E834E310A4A1CED149E9C00F248527972CEC5704C2A5B07B8B3DC38ECC4EBAE97DDD87F3D8985" +#define DGST4 "2FC64A4F500DDB6828F6A3430B8DD72A368EB7F3A8322A70BC84275B9C0B3AB00D27A5CC3C2D224AA6B61A0D79FB4596" +#define DGST5 "BC8089A19007C0B14195F4ECC74094FEC64F01F90929282C2FB392881578208AD466828B1C6C283D2722CF0AD1AB6938" +#define DGST6 "C9A68443A005812256B8EC76B00516F0DBB74FAB26D665913F194B6FFB0E91EA9967566B58109CBC675CC208E4C823F7" +#define DGST7 "4F440DB1E6EDD2899FA335F09515AA025EE177A79F4B4AAF38E42B5C4DE660F5DE8FB2A5B2FBD2A3CBFFD20CFF1288C0" + + +struct { + char *data; + size_t length; + size_t count; + char *dgsthex; +} tests[7] = { + {TEST1, sizeof(TEST1) - 1, 1, DGST1}, + {TEST2, sizeof(TEST2) - 1, 1, DGST2}, + {TEST3, sizeof(TEST3) - 1, 1000000, DGST3}, + {TEST4, sizeof(TEST4) - 1, 10, DGST4}, + {TEST5, sizeof(TEST5) - 1, 1, DGST5}, + {TEST6, sizeof(TEST6) - 1, 1, DGST6}, + {TEST7, sizeof(TEST7) - 1, 1, DGST7}, +}; + +int main(void) +{ + int err = 0; + SHA384_CTX ctx; + unsigned char dgst[SHA384_DIGEST_SIZE]; + unsigned char *dgstbuf = NULL; + size_t i, j; + + for (i = 0; i < 7; i++) { + + if (!(dgstbuf = OPENSSL_hexstr2buf(tests[i].dgsthex, NULL))) { + goto end; + } + + sha384_init(&ctx); + for (j = 0; j < tests[i].count; j++) { + sha384_update(&ctx, (unsigned char *)tests[i].data, tests[i].length); + } + sha384_finish(&ctx, dgst); + + if (memcmp(dgstbuf, dgst, sizeof(dgst)) != 0) { + printf("sha384 test %lu failed\n", i+1); + printf("%s\n", tests[i].dgsthex); + for (j = 0; j < sizeof(dgst); j++) { + printf("%02x", dgst[j]); + } + printf("\n"); + err++; + } else { + printf("sha384 test %lu ok\n", i+1); + } + + free(dgstbuf); + dgstbuf = NULL; + } + +end: + if (dgstbuf) free(dgstbuf); + return err; +} diff --git a/tests/sha512test.c b/tests/sha512test.c new file mode 100644 index 00000000..c1767be4 --- /dev/null +++ b/tests/sha512test.c @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2014 - 2020 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + + +#include +#include +#include +#include +#include + + +#define TEST1 "abc" +#define TEST2 "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn" \ + "hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu" +#define TEST3 "a" +#define TEST4 "0123456701234567012345670123456701234567012345670123456701234567" +#define TEST5 "\xD0" +#define TEST6 "\x8d\x4e\x3c\x0e\x38\x89\x19\x14\x91\x81\x6e\x9d\x98\xbf\xf0\xa0" +#define TEST7 \ + "\xa5\x5f\x20\xc4\x11\xaa\xd1\x32\x80\x7a\x50\x2d\x65\x82\x4e\x31" \ + "\xa2\x30\x54\x32\xaa\x3d\x06\xd3\xe2\x82\xa8\xd8\x4e\x0d\xe1\xde" \ + "\x69\x74\xbf\x49\x54\x69\xfc\x7f\x33\x8f\x80\x54\xd5\x8c\x26\xc4" \ + "\x93\x60\xc3\xe8\x7a\xf5\x65\x23\xac\xf6\xd8\x9d\x03\xe5\x6f\xf2" \ + "\xf8\x68\x00\x2b\xc3\xe4\x31\xed\xc4\x4d\xf2\xf0\x22\x3d\x4b\xb3" \ + "\xb2\x43\x58\x6e\x1a\x7d\x92\x49\x36\x69\x4f\xcb\xba\xf8\x8d\x95" \ + "\x19\xe4\xeb\x50\xa6\x44\xf8\xe4\xf9\x5e\xb0\xea\x95\xbc\x44\x65" \ + "\xc8\x82\x1a\xac\xd2\xfe\x15\xab\x49\x81\x16\x4b\xbb\x6d\xc3\x2f" \ + "\x96\x90\x87\xa1\x45\xb0\xd9\xcc\x9c\x67\xc2\x2b\x76\x32\x99\x41" \ + "\x9c\xc4\x12\x8b\xe9\xa0\x77\xb3\xac\xe6\x34\x06\x4e\x6d\x99\x28" \ + "\x35\x13\xdc\x06\xe7\x51\x5d\x0d\x73\x13\x2e\x9a\x0d\xc6\xd3\xb1" \ + "\xf8\xb2\x46\xf1\xa9\x8a\x3f\xc7\x29\x41\xb1\xe3\xbb\x20\x98\xe8" \ + "\xbf\x16\xf2\x68\xd6\x4f\x0b\x0f\x47\x07\xfe\x1e\xa1\xa1\x79\x1b" \ + "\xa2\xf3\xc0\xc7\x58\xe5\xf5\x51\x86\x3a\x96\xc9\x49\xad\x47\xd7" \ + "\xfb\x40\xd2" + +#define DGST1 "DDAF35A193617ABACC417349AE20413112E6FA4E89A97EA20A9EEEE64B55D39A2192992A274FC1A836BA3C23A3FEEBBD454D4423643CE80E2A9AC94FA54CA49F" +#define DGST2 "8E959B75DAE313DA8CF4F72814FC143F8F7779C6EB9F7FA17299AEADB6889018501D289E4900F7E4331B99DEC4B5433AC7D329EEB6DD26545E96E55B874BE909" +#define DGST3 "E718483D0CE769644E2E42C7BC15B4638E1F98B13B2044285632A803AFA973EBDE0FF244877EA60A4CB0432CE577C31BEB009C5C2C49AA2E4EADB217AD8CC09B" +#define DGST4 "89D05BA632C699C31231DED4FFC127D5A894DAD412C0E024DB872D1ABD2BA8141A0F85072A9BE1E2AA04CF33C765CB510813A39CD5A84C4ACAA64D3F3FB7BAE9" +#define DGST5 "9992202938E882E73E20F6B69E68A0A7149090423D93C81BAB3F21678D4ACEEEE50E4E8CAFADA4C85A54EA8306826C4AD6E74CECE9631BFA8A549B4AB3FBBA15" +#define DGST6 "CB0B67A4B8712CD73C9AABC0B199E9269B20844AFB75ACBDD1C153C9828924C3DDEDAAFE669C5FDD0BC66F630F6773988213EB1B16F517AD0DE4B2F0C95C90F8" +#define DGST7 "C665BEFB36DA189D78822D10528CBF3B12B3EEF726039909C1A16A270D48719377966B957A878E720584779A62825C18DA26415E49A7176A894E7510FD1451F5" + + +struct { + char *data; + size_t length; + size_t count; + char *dgsthex; +} tests[7] = { + {TEST1, sizeof(TEST1) - 1, 1, DGST1}, + {TEST2, sizeof(TEST2) - 1, 1, DGST2}, + {TEST3, sizeof(TEST3) - 1, 1000000, DGST3}, + {TEST4, sizeof(TEST4) - 1, 10, DGST4}, + {TEST5, sizeof(TEST5) - 1, 1, DGST5}, + {TEST6, sizeof(TEST6) - 1, 1, DGST6}, + {TEST7, sizeof(TEST7) - 1, 1, DGST7}, +}; + +int main(void) +{ + int err = 0; + SHA512_CTX ctx; + unsigned char dgst[SHA512_DIGEST_SIZE]; + unsigned char *dgstbuf = NULL; + size_t i, j; + + for (i = 0; i < 7; i++) { + + if (!(dgstbuf = OPENSSL_hexstr2buf(tests[i].dgsthex, NULL))) { + goto end; + } + + sha512_init(&ctx); + for (j = 0; j < tests[i].count; j++) { + sha512_update(&ctx, (unsigned char *)tests[i].data, tests[i].length); + } + sha512_finish(&ctx, dgst); + + if (memcmp(dgstbuf, dgst, sizeof(dgst)) != 0) { + printf("sha512 test %lu failed\n", i+1); + printf("%s\n", tests[i].dgsthex); + for (j = 0; j < sizeof(dgst); j++) { + printf("%02x", dgst[j]); + } + printf("\n"); + err++; + } else { + printf("sha512 test %lu ok\n", i+1); + } + + free(dgstbuf); + dgstbuf = NULL; + } + +end: + if (dgstbuf) free(dgstbuf); + return err; +} diff --git a/tests/sm2asn1test.c b/tests/sm2asn1test.c new file mode 100644 index 00000000..c041940c --- /dev/null +++ b/tests/sm2asn1test.c @@ -0,0 +1,180 @@ +/* + * Copyright (c) 2021 - 2021 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + +#include +#include +#include +#include +#include +#include + + +static int test_sm2_point_octets(void) +{ + int err = 0; + SM2_KEY sm2_key; + SM2_POINT point; + uint8_t buf[65]; + int i; + + // compress + for (i = 0; i < 8; i++) { + uint8_t buf[33]; + sm2_keygen(&sm2_key); + sm2_point_to_compressed_octets(&sm2_key.public_key, buf); + if (sm2_point_from_octets(&point, buf, sizeof(buf)) != 1) { + error_print(); + err++; + break; + } + if (memcmp(&sm2_key.public_key, &point, sizeof(SM2_POINT)) != 0) { + error_print(); + err++; + break; + } + } + + // uncompress + for (i = 0; i < 8; i++) { + uint8_t buf[65]; + sm2_keygen(&sm2_key); + sm2_point_to_uncompressed_octets(&sm2_key.public_key, buf); + if (sm2_point_from_octets(&point, buf, sizeof(buf)) != 1) { + error_print(); + err++; + break; + } + if (memcmp(&sm2_key.public_key, &point, sizeof(SM2_POINT)) != 0) { + error_print(); + err++; + break; + } + } + + printf("%s : %s\n", __func__, err ? "failed" : "ok"); + return err; +} + +static int test_sm2_private_key(void) +{ + int err = 0; + SM2_KEY sm2_key; + SM2_KEY sm2_tmp; + uint8_t buf[256]; + uint8_t *p = buf; + const uint8_t *cp = buf; + size_t len = 0; + + + sm2_keygen(&sm2_key); + + if (sm2_private_key_to_der(&sm2_key, &p, &len) != 1) { + error_print(); + err++; + goto end; + } + if (sm2_private_key_from_der(&sm2_tmp, &cp, &len) != 1 + || len > 0) { + error_print(); + err++; + goto end; + } + if (memcmp(&sm2_tmp, &sm2_key, sizeof(SM2_KEY)) != 0) { + error_print(); + err++; + goto end; + } + + printf("%s : ok\n", __func__); +end: + return err; +} + +static int test_sm2_public_key_info(void) +{ + int err = 0; + SM2_KEY sm2_key; + SM2_KEY sm2_tmp; + uint8_t buf[256]; + uint8_t *p = buf; + const uint8_t *cp = buf; + size_t len = 0; + + sm2_keygen(&sm2_key); + + if (sm2_public_key_info_to_der(&sm2_key, &p, &len) != 1) { + error_print(); + err++; + goto end; + } + if (sm2_public_key_info_from_der(&sm2_tmp, &cp, &len) != 1 + || len > 0) { + error_print(); + err++; + goto end; + } + if (memcmp(&sm2_key.public_key, &sm2_tmp.public_key, sizeof(SM2_POINT)) != 0) { + error_print(); + err++; + goto end; + } + printf("%s : ok\n", __func__); +end: + return err; +} + + + +int main(void) +{ + test_sm2_point_octets(); + test_sm2_private_key(); + test_sm2_public_key_info(); + return 0; +} + diff --git a/tests/sm2test.c b/tests/sm2test.c new file mode 100644 index 00000000..90389d99 --- /dev/null +++ b/tests/sm2test.c @@ -0,0 +1,163 @@ +/* + * Copyright (c) 2014 - 2020 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + +#include +#include +#include +#include + + +// SM2还需要大量的测试覆盖 +/* +void sm2_point_to_compressed_octets(const SM2_POINT *P, uint8_t out[33]); +void sm2_point_to_uncompressed_octets(const SM2_POINT *P, uint8_t out[65]); +int sm2_point_from_octets(SM2_POINT *P, const uint8_t *in, size_t inlen); +int sm2_point_from_x(SM2_POINT *P, const uint8_t x[32]); +int sm2_point_from_xy(SM2_POINT *P, const uint8_t x[32], const uint8_t y[32]); +int sm2_point_is_on_curve(const SM2_POINT *P); +*/ + +static int test_sm2_point(void) +{ + SM2_POINT P; + uint8_t k[32] = {0}; + uint8_t buf[65] = {0}; + int i; + + k[31] = 2; + + printf("k = "); for (i = 0; i < 32; i++) printf("%02x", k[i]); printf("\n"); + + sm2_point_mul_generator(&P, k); + + printf("k * G :\n"); + sm2_point_print(stdout, &P, 0, 2); + + sm2_point_to_compressed_octets(&P, buf); + for (i = 0; i < 33; i++) printf("%02x", buf[i]); printf("\n"); + + memset(buf, 0, sizeof(buf)); + sm2_point_to_uncompressed_octets(&P, buf); + for (i = 0; i < 65; i++) printf("%02x", buf[i]); printf("\n"); + + memset(&P, 0, sizeof(SM2_POINT)); + /* + i = sm2_point_from_x(&P, buf + 1); + printf("sm2_point_from_x: %d\n", i); + */ + + sm2_point_from_octets(&P, buf, 65); + + i = sm2_point_is_on_curve(&P); + printf("point_is_on_curve: %d\n", i); + + return 1; +} + + +static int test_sm2_do_encrypt(void) +{ + SM2_KEY key; + uint8_t plaintext[] = "Hello World!"; + uint8_t cipherbuf[SM2_CIPHERTEXT_SIZE(sizeof(plaintext))] = {0}; + SM2_CIPHERTEXT *ciphertext = (SM2_CIPHERTEXT *)cipherbuf; + uint8_t plainbuf[sizeof(cipherbuf)] = {0}; + size_t plainlen = 0; + int r = 0; + + sm2_keygen(&key); + + sm2_do_encrypt(&key, plaintext, sizeof(plaintext), ciphertext); + + printf("ciphertext:\n"); + sm2_ciphertext_print(stdout, ciphertext, 0, 2); + + sm2_do_decrypt(&key, ciphertext, plainbuf, &plainlen); + + printf("plaintext = %s\n", (char *)plainbuf); + return r; +} + +static int test_sm2_sign(void) +{ + SM2_KEY key; + SM2_SIGN_CTX ctx; + uint8_t msg[] = "Hello World!"; + uint8_t sig[128] = {0}; + size_t siglen = sizeof(sig); + int i; + int r; + + sm2_keygen(&key); + sm2_key_print(stdout, &key, 0, 0); + + sm2_sign_init(&ctx, &key, SM2_DEFAULT_ID); + sm2_sign_update(&ctx, msg, sizeof(msg)); + sm2_sign_finish(&ctx, sig, &siglen); + + printf("signature:\n"); + sm2_print_signature(stdout, sig, siglen, 0, 2); + + sm2_verify_init(&ctx, &key, SM2_DEFAULT_ID); + sm2_verify_update(&ctx, msg, sizeof(msg)); + r = sm2_verify_finish(&ctx, sig, siglen); + printf("verify %s\n", r > 0 ? "success" : "failed"); + + return 0; +} + +int main(void) +{ + sm2_algo_selftest(); + + //test_sm2_point(); + //test_sm2_sign(); + test_sm2_do_encrypt(); + + return 0; +} diff --git a/tests/sm3test.c b/tests/sm3test.c new file mode 100644 index 00000000..a2785812 --- /dev/null +++ b/tests/sm3test.c @@ -0,0 +1,219 @@ +/* ==================================================================== + * Copyright (c) 2014 - 2017 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + * ==================================================================== + */ + +#include +#include +#include +#include +#include + +static char *testhex[] = { + /* 0 "abc" */ + "616263", + /* 1 "abcd" 16 times */ + "6162636461626364616263646162636461626364616263646162636461626364" + "6162636461626364616263646162636461626364616263646162636461626364", + /* 2 p.57 ZA */ + "0090" + "414C494345313233405941484F4F2E434F4D" + "787968B4FA32C3FD2417842E73BBFEFF2F3C848B6831D7E0EC65228B3937E498" + "63E4C6D3B23B0C849CF84241484BFE48F61D59A5B16BA06E6E12D1DA27C5249A" + "421DEBD61B62EAB6746434EBC3CC315E32220B3BADD50BDC4C4E6C147FEDD43D" + "0680512BCBB42C07D47349D2153B70C4E5D7FDFCBFA36EA1A85841B9E46E09A2" + "0AE4C7798AA0F119471BEE11825BE46202BB79E2A5844495E97C04FF4DF2548A" + "7C0240F88F1CD4E16352A73C17B7F16F07353E53A176D684A9FE0C6BB798E857", + /* 3 p.59 ZA */ + "0090" + "414C494345313233405941484F4F2E434F4D" + "000000000000000000000000000000000000000000000000000000000000000000" + "00E78BCD09746C202378A7E72B12BCE00266B9627ECB0B5A25367AD1AD4CC6242B" + "00CDB9CA7F1E6B0441F658343F4B10297C0EF9B6491082400A62E7A7485735FADD" + "013DE74DA65951C4D76DC89220D5F7777A611B1C38BAE260B175951DC8060C2B3E" + "0165961645281A8626607B917F657D7E9382F1EA5CD931F40F6627F357542653B2" + "01686522130D590FB8DE635D8FCA715CC6BF3D05BEF3F75DA5D543454448166612", + /* 4 p.72 ZA */ + "0090" + "414C494345313233405941484F4F2E434F4D" + "787968B4FA32C3FD2417842E73BBFEFF2F3C848B6831D7E0EC65228B3937E498" + "63E4C6D3B23B0C849CF84241484BFE48F61D59A5B16BA06E6E12D1DA27C5249A" + "421DEBD61B62EAB6746434EBC3CC315E32220B3BADD50BDC4C4E6C147FEDD43D" + "0680512BCBB42C07D47349D2153B70C4E5D7FDFCBFA36EA1A85841B9E46E09A2" + "3099093BF3C137D8FCBBCDF4A2AE50F3B0F216C3122D79425FE03A45DBFE1655" + "3DF79E8DAC1CF0ECBAA2F2B49D51A4B387F2EFAF482339086A27A8E05BAED98B", + /* 5 p.72 ZB */ + "0088" + "42494C4C343536405941484F4F2E434F4D" + "787968B4FA32C3FD2417842E73BBFEFF2F3C848B6831D7E0EC65228B3937E498" + "63E4C6D3B23B0C849CF84241484BFE48F61D59A5B16BA06E6E12D1DA27C5249A" + "421DEBD61B62EAB6746434EBC3CC315E32220B3BADD50BDC4C4E6C147FEDD43D" + "0680512BCBB42C07D47349D2153B70C4E5D7FDFCBFA36EA1A85841B9E46E09A2" + "245493D446C38D8CC0F118374690E7DF633A8A4BFB3329B5ECE604B2B4F37F43" + "53C0869F4B9E17773DE68FEC45E14904E0DEA45BF6CECF9918C85EA047C60A4C", + /* 6 p.75 ZA */ + "0090" + "414C494345313233405941484F4F2E434F4D" + "000000000000000000000000000000000000000000000000000000000000000000" + "00E78BCD09746C202378A7E72B12BCE00266B9627ECB0B5A25367AD1AD4CC6242B" + "00CDB9CA7F1E6B0441F658343F4B10297C0EF9B6491082400A62E7A7485735FADD" + "013DE74DA65951C4D76DC89220D5F7777A611B1C38BAE260B175951DC8060C2B3E" + "008E3BDB2E11F9193388F1F901CCC857BF49CFC065FB38B9069CAAE6D5AFC3592F" + "004555122AAC0075F42E0A8BBD2C0665C789120DF19D77B4E3EE4712F598040415", + /* 7 p.76 ZB */ + "0088" + "42494C4C343536405941484F4F2E434F4D" + "000000000000000000000000000000000000000000000000000000000000000000" + "00E78BCD09746C202378A7E72B12BCE00266B9627ECB0B5A25367AD1AD4CC6242B" + "00CDB9CA7F1E6B0441F658343F4B10297C0EF9B6491082400A62E7A7485735FADD" + "013DE74DA65951C4D76DC89220D5F7777A611B1C38BAE260B175951DC8060C2B3E" + "0034297DD83AB14D5B393B6712F32B2F2E938D4690B095424B89DA880C52D4A7D9" + "0199BBF11AC95A0EA34BBD00CA50B93EC24ACB68335D20BA5DCFE3B33BDBD2B62D", + /* 8 TopsecCA cert ZA */ + "0080" + "31323334353637383132333435363738" + "FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC" + "28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93" + "32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7" + "BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0" + "D69C2F1EEC3BFB6B95B30C28085C77B125D77A9C39525D8190768F37D6B205B5" + "89DCD316BBE7D89A9DC21917F17799E698531F5E6E3E10BD31370B259C3F81C3", + /* 9 */ + "4D38D2958CA7FD2CFAE3AF04486959CF92C8EF48E8B83A05C112E739D5F181D0" + "3082020CA003020102020900" + "AF28725D98D33143300C06082A811CCF" + "550183750500307D310B300906035504" + "060C02636E310B300906035504080C02" + "626A310B300906035504070C02626A31" + "0F300D060355040A0C06746F70736563" + "310F300D060355040B0C06746F707365" + "633111300F06035504030C08546F7073" + "65634341311F301D06092A864886F70D" + "0109010C10626A40746F707365632E63" + "6F6D2E636E301E170D31323036323430" + "37353433395A170D3332303632303037" + "353433395A307D310B30090603550406" + "0C02636E310B300906035504080C0262" + "6A310B300906035504070C02626A310F" + "300D060355040A0C06746F7073656331" + "0F300D060355040B0C06746F70736563" + "3111300F06035504030C08546F707365" + "634341311F301D06092A864886F70D01" + "09010C10626A40746F707365632E636F" + "6D2E636E3059301306072A8648CE3D02" + "0106082A811CCF5501822D03420004D6" + "9C2F1EEC3BFB6B95B30C28085C77B125" + "D77A9C39525D8190768F37D6B205B589" + "DCD316BBE7D89A9DC21917F17799E698" + "531F5E6E3E10BD31370B259C3F81C3A3" + "733071300F0603551D130101FF040530" + "030101FF301D0603551D0E041604148E" + "5D90347858BAAAD870D8BDFBA6A85E7B" + "563B64301F0603551D23041830168014" + "8E5D90347858BAAAD870D8BDFBA6A85E" + "7B563B64300B0603551D0F0404030201" + "06301106096086480186F84201010404" + "03020057", +}; + +static char *dgsthex[] = { + "66c7f0f462eeedd9d1f2d46bdc10e4e24167c4875cf2f7a2297da02b8f4ba8e0", + "debe9ff92275b8a138604889c18e5a4d6fdb70e5387e5765293dcba39c0c5732", + "F4A38489E32B45B6F876E3AC2168CA392362DC8F23459C1D1146FC3DBFB7BC9A", + "26352AF82EC19F207BBC6F9474E11E90CE0F7DDACE03B27F801817E897A81FD5", + "E4D1D0C3CA4C7F11BC8FF8CB3F4C02A78F108FA098E51A668487240F75E20F31", + "6B4B6D0E276691BD4A11BF72F4FB501AE309FDACB72FA6CC336E6656119ABD67", + "329c2f6030cc7e0ca3af6c97b76243ca250338ad3d3dc3a8b322d1cfdf98c2b7", + /*"ECF0080215977B2E5D6D61B98A99442F03E8803DC39E349F8DCA5621A9ACDF2B",*/ + "557BAD30E183559AEEC3B2256E1C7C11F870D22B165D015ACF9465B09B87B527", + "4D38D2958CA7FD2CFAE3AF04486959CF92C8EF48E8B83A05C112E739D5F181D0", + "C3B02E500A8B60B77DEDCF6F4C11BEF8D56E5CDE708C72065654FD7B2167915A", +}; + +int main(int argc, char **argv) +{ + int err = 0; + char *p; + unsigned char *testbuf = NULL; + unsigned char *dgstbuf = NULL; + size_t testbuflen, dgstbuflen; + unsigned char dgst[32]; + size_t i; + + for (i = 0; i < sizeof(testhex)/sizeof(testhex[0]); i++) { + if (!(testbuf = OPENSSL_hexstr2buf(testhex[i], &testbuflen)) + || !(dgstbuf = OPENSSL_hexstr2buf(dgsthex[i], &dgstbuflen))) { + goto end; + } + + sm3_digest(testbuf, testbuflen, dgst); + + if (memcmp(dgstbuf, dgst, sizeof(dgst)) != 0) { + int n; + printf("error calculating SM3 on %s\n", testhex[i]); + printf(" digest(corret) = "); + for (n = 0; n < sizeof(dgst); n++) { + printf("%02X", dgst[n]); + } + printf("\n"); + printf(" digest(error) = %s\n", dgsthex[i]); + err++; + } else { + printf("sm3 test %lu ok\n", i+1); + } + + free(testbuf); + free(dgstbuf); + testbuf = NULL; + dgstbuf = NULL; + } + +end: + if (testbuf) free(testbuf); + if (dgstbuf) free(dgstbuf); + return err; +} diff --git a/tests/sm4cbctest.c b/tests/sm4cbctest.c new file mode 100644 index 00000000..96d4e856 --- /dev/null +++ b/tests/sm4cbctest.c @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2014 - 2021 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + +#include +#include +#include +#include +#include + +static int test_sm4_cbc(void) +{ + SM4_KEY sm4_key; + uint8_t key[16] = {0}; + uint8_t iv[16]; + + uint8_t buf1[2] = {0}; + uint8_t buf2[32] = {0}; + uint8_t buf3[47] = {0}; + uint8_t buf4[96] = {0}; + uint8_t buf5[96]; + int i; + + sm4_set_encrypt_key(&sm4_key, key); + sm4_cbc_encrypt(&sm4_key, iv, buf2, 2, buf4); + + for (i = 0; i < 32; i++) { + printf("%02x", buf4[i]); + } + printf("\n"); + return 1; +} + +static int test_sm4_cbc_padding(void) +{ + SM4_KEY enc_key; + SM4_KEY dec_key; + uint8_t key[16] = {0}; + uint8_t iv[16] = {0}; + uint8_t in[64]; + uint8_t out[128]; + uint8_t buf[128]; + size_t len1, len2, i; + + for (i = 0; i < sizeof(in); i++) { + in[i] = i; + } + + sm4_set_encrypt_key(&enc_key, key); + sm4_set_decrypt_key(&dec_key, key); + + sm4_cbc_padding_encrypt(&enc_key, iv, in, 33, out, &len1); + printf("c = (%zu) ", len1); for (i = 0; i < len1; i++) printf("%02x", out[i]); printf("\n"); + + sm4_cbc_padding_decrypt(&dec_key, iv, out, len1, buf, &len2); + printf("m = (%zu) ", len2); for (i = 0; i < len2; i++) printf("%02x", buf[i]); printf("\n"); + + + return 1; +} + + + +int main(void) +{ + test_sm4_cbc(); + test_sm4_cbc_padding(); + return 1; +} diff --git a/tests/sm4test.c b/tests/sm4test.c new file mode 100644 index 00000000..16567ca8 --- /dev/null +++ b/tests/sm4test.c @@ -0,0 +1,311 @@ +/* + * Copyright (c) 2014 - 2021 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + +#include +#include +#include +#include + +# ifdef SM4_AVX2 +void sm4_avx2_ecb_encrypt_blocks(const unsigned char *in, + unsigned char *out, size_t blocks, const SM4_KEY *key); +void sm4_avx2_ctr32_encrypt_blocks(const unsigned char *in, + unsigned char *out, size_t blocks, const SM4_KEY *key, + const unsigned char iv[16]); +# endif + +static int test_ecb(int avx) +{ + SM4_KEY key; + unsigned char user_key[16] = {0}; + /* 2 rounds avx-512 and 2 rounds x86 */ + unsigned char in[(16 * 2 + 2) * 16] = {0}; + unsigned char out1[sizeof(in)] = {0}; + unsigned char out2[sizeof(in)] = {0}; + int i; + + for (i = 0; i < sizeof(user_key); i++) { + user_key[i] = (unsigned char)i; + } + for (i = 0; i < sizeof(in); i++) { + in[i] = (unsigned char)i; + } + /* + RAND_bytes(user_key, sizeof(user_key)); + RAND_bytes(in, sizeof(in)); + */ + + sm4_set_encrypt_key(&key, user_key); + for (i = 0; i < sizeof(in)/SM4_BLOCK_SIZE; i++) { + sm4_encrypt(&key, in + 16*i, out1 + 16*i); + } + + switch (avx) { +# ifdef SM4_AVX2 + case 2: + sm4_avx2_ecb_encrypt_blocks(in, out2, sizeof(in)/SM4_BLOCK_SIZE, &key); + break; +# endif + default: + printf("avx shuold be in {2}\n"); + return 0; + } + + if (memcmp(out1, out2, sizeof(out1)) != 0) { + return 0; + } + return 1; +} + +static void xor_block(unsigned char *out, const unsigned char *in) +{ + int i; + for (i = 0; i < 16; i++) { + out[i] ^= in[i]; + } +} + +static int test_ctr32(int avx) +{ + SM4_KEY key; + unsigned char user_key[16] = {0}; + unsigned char iv[16] = {0}; + unsigned char ctr1[16]; + unsigned char ctr2[16]; + /* 2 rounds avx-512 and 2 rounds x86 */ + unsigned char in[(16 * 2 + 2) * 16] = {0}; + unsigned char out1[sizeof(in)]; + unsigned char out2[sizeof(in)]; + int i; + + /* + RAND_bytes(user_key, sizeof(user_key)); + RAND_bytes(iv, sizeof(iv) - 1); + RAND_bytes(in, sizeof(in)); + */ + + sm4_set_encrypt_key(&key, user_key); + memcpy(ctr1, iv, sizeof(iv)); + memcpy(ctr2, iv, sizeof(iv)); + + for (i = 0; i < sizeof(in)/16; i++) { + sm4_encrypt(&key, ctr1, out1 + 16 * i); + xor_block(out1 + 16 * i, in + 16 * i); + ctr1[15]++; + } + + switch (avx) { +# ifdef SM4_AVX2 + case 2: + sm4_avx2_ctr32_encrypt_blocks(in, out2, sizeof(in)/16, &key, ctr2); + break; +# endif + case 0: + // do we need this? + //sm4_ctr32_encrypt_blocks(in, out2, sizeof(in)/16, &key, ctr2); + break; + default: + printf("avx should be in {0, 2}\n"); + return 0; + } + + if (memcmp(out1, out2, sizeof(out1)) != 0) { + return 0; + } + return 1; +} + + +/* +static int test_ede(void) +{ + SM4_KEY key; + sm4_ede_key_t ede_key; + unsigned char user_key[48]; + unsigned char in[16]; + unsigned char out1[16]; + unsigned char out2[16]; + + RAND_bytes(in, sizeof(in)); + + RAND_bytes(user_key, 16); + memcpy(user_key + 16, user_key, 16); + memcpy(user_key + 32, user_key, 16); + sm4_set_encrypt_key(&key, user_key); + sm4_encrypt(in, out1, &key); + sm4_ede_set_encrypt_key(&ede_key, user_key); + sm4_ede_encrypt(in, out2, &ede_key); + if (memcmp(out1, out2, 16) != 0) { + return 0; + } + + RAND_bytes(user_key, sizeof(user_key)); + sm4_ede_set_encrypt_key(&ede_key, user_key); + sm4_ede_encrypt(in, out1, &ede_key); + sm4_ede_set_decrypt_key(&ede_key, user_key); + sm4_ede_decrypt(out1, out2, &ede_key); + if (memcmp(in, out2, 16) != 0) { + return 0; + } + + return 1; +} +*/ + +int main(int argc, char **argv) +{ + int err = 0; + int i; + SM4_KEY key; + unsigned char buf[16]; + + unsigned char user_key[16] = { + 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, + 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, + }; + + uint32_t rk[32] = { + 0xf12186f9, 0x41662b61, 0x5a6ab19a, 0x7ba92077, + 0x367360f4, 0x776a0c61, 0xb6bb89b3, 0x24763151, + 0xa520307c, 0xb7584dbd, 0xc30753ed, 0x7ee55b57, + 0x6988608c, 0x30d895b7, 0x44ba14af, 0x104495a1, + 0xd120b428, 0x73b55fa3, 0xcc874966, 0x92244439, + 0xe89e641f, 0x98ca015a, 0xc7159060, 0x99e1fd2e, + 0xb79bd80c, 0x1d2115b0, 0x0e228aeb, 0xf1780c81, + 0x428d3654, 0x62293496, 0x01cf72e5, 0x9124a012, + }; + + unsigned char plaintext[16] = { + 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, + 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, + }; + + unsigned char ciphertext1[16] = { + 0x68, 0x1e, 0xdf, 0x34, 0xd2, 0x06, 0x96, 0x5e, + 0x86, 0xb3, 0xe9, 0x4f, 0x53, 0x6e, 0x42, 0x46, + }; + + unsigned char ciphertext2[16] = { + 0x59, 0x52, 0x98, 0xc7, 0xc6, 0xfd, 0x27, 0x1f, + 0x04, 0x02, 0xf8, 0x04, 0xc3, 0x3d, 0x3f, 0x66, + }; + + /* test key scheduling */ + sm4_set_encrypt_key(&key, user_key); + + if (memcmp(key.rk, rk, sizeof(rk)) != 0) { + printf("sm4 key scheduling not passed!\n"); + err++; + goto end; + } + printf("sm4 key scheduling passed!\n"); + + /* test encrypt once */ + sm4_encrypt(&key, plaintext, buf); + + if (memcmp(buf, ciphertext1, sizeof(ciphertext1)) != 0) { + printf("sm4 encrypt not pass!\n"); + err++; + goto end; + } + printf("sm4 encrypt pass!\n"); + + /* test encrypt 1000000 times */ + memcpy(buf, plaintext, sizeof(plaintext)); + for (i = 0; i < 1000000; i++) { + sm4_encrypt(&key, buf, buf); + } + + if (memcmp(buf, ciphertext2, sizeof(ciphertext2)) != 0) { + printf("sm4 encrypt 1000000 times not pass!\n"); + err++; + goto end; + } + printf("sm4 encrypt 1000000 times pass!\n"); + + /* test ctr32 */ + if (!test_ctr32(0)) { + printf("sm4 ctr32 not pass!\n"); + err++; + } else + printf("sm4 ctr32 pass!\n"); + + /* test ede */ +/* + if (!test_ede()) { + printf("sm4 ede not pass!\n"); + err++; + } else + printf("sm4 ede pass!\n"); +*/ + + +# ifdef SM4_AVX2 + /* test ecb in avx2 */ + if (!test_ecb(2)) { + printf("sm4 ecb in avx2 not pass!\n"); + err++; + } else + printf("sm4 ecb in avx2 pass!\n"); + + /* test ctr32 in avx2 */ + if (!test_ctr32(2)) { + printf("sm4 ctr32 in avx2 not pass!\n"); + err++; + } else + printf("sm4 ctr32 in avx2 pass!\n"); +# endif + + if (err == 0) + printf("sm4 all test vectors pass!\n"); + else +end: + printf("some test vector failed\n"); + + return err; +} diff --git a/tests/tlstest.c b/tests/tlstest.c new file mode 100644 index 00000000..8bf40ce2 --- /dev/null +++ b/tests/tlstest.c @@ -0,0 +1,353 @@ +/* + * Copyright (c) 2021 - 2021 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int test_tls_encode(void) +{ + uint8_t a1 = 200; + uint16_t a2 = 30000; + uint24_t a3 = 4000000; + uint32_t a4 = 4000000000; + uint8_t data[] = {1, 2, 3, 4, 5, 6, 7, 8}; + + uint8_t r1; + uint16_t r2; + uint24_t r3; + uint32_t r4; + const uint8_t *pdata; + size_t datalen; + + uint8_t buf[256]; + uint8_t *p = buf; + const uint8_t *cp = buf; + size_t len = 0; + + tls_uint8_to_bytes(a1, &p, &len); + tls_uint16_to_bytes(a2, &p, &len); + tls_uint24_to_bytes(a3, &p, &len); + tls_uint32_to_bytes(a4, &p, &len); + tls_uint8array_to_bytes(data, 5, &p, &len); + tls_uint16array_to_bytes(data, 6, &p, &len); + tls_uint24array_to_bytes(data, 7, &p, &len); + + if (tls_uint8_from_bytes(&r1, &cp, &len) != 1 || r1 != a1 + || tls_uint16_from_bytes(&r2, &cp, &len) != 1 || r2 != a2 + || tls_uint24_from_bytes(&r3, &cp, &len) != 1 || r3 != a3 + || tls_uint32_from_bytes(&r4, &cp, &len) != 1 || r4 != a4 + || tls_uint8array_from_bytes(&pdata, &datalen, &cp, &len) != 1 || datalen != 5 || memcmp(pdata, data, 5) != 0 + || tls_uint16array_from_bytes(&pdata, &datalen, &cp, &len) != 1 || datalen != 6 || memcmp(pdata, data, 6) != 0 + || tls_uint24array_from_bytes(&pdata, &datalen, &cp, &len) != 1 || datalen != 7 || memcmp(pdata, data, 7) != 0 + || len > 0) { + error_print(); + return 1; + } + + return 0; +} + +static int test_tls_cbc(void) +{ + uint8_t key[32]; + SM3_HMAC_CTX hmac_ctx; + SM4_KEY sm4_key; + uint8_t seq_num[8] = { 0,0,0,0,0,0,0,1 }; + uint8_t header[5]; + uint8_t in[] = "hello world"; + uint8_t out[256]; + uint8_t buf[256] = {0}; + size_t len; + size_t buflen; + + sm3_hmac_init(&hmac_ctx, key, 32); + sm4_set_encrypt_key(&sm4_key, key); + + tls_cbc_encrypt(&hmac_ctx, &sm4_key, seq_num, header, in, sizeof(in), out, &len); + + printf("%zu\n", len); + print_der(out, len); + printf("\n"); + + sm3_hmac_init(&hmac_ctx, key, 32); + sm4_set_decrypt_key(&sm4_key, key); + + tls_cbc_decrypt(&hmac_ctx, &sm4_key, seq_num, header, out, len, buf, &buflen); + + printf("%s\n", buf); + + + return 1; +} + +static int test_tls_random(void) +{ + uint8_t random[32]; + tls_random_generate(random); + tls_random_print(stdout, random, 0, 0); + return 0; +} + +static int test_tls_client_hello(void) +{ + uint8_t record[512]; + size_t recordlen = 0; + + int version = TLS_version_tlcp; + uint8_t random[32]; + uint16_t cipher_suites[] = { + TLCP_cipher_ecc_sm4_cbc_sm3, + TLCP_cipher_ecc_sm4_gcm_sm3, + TLCP_cipher_ecdhe_sm4_cbc_sm3, + TLCP_cipher_ecdhe_sm4_gcm_sm3, + TLCP_cipher_ibsdh_sm4_cbc_sm3, + TLCP_cipher_ibsdh_sm4_gcm_sm3, + TLCP_cipher_ibc_sm4_cbc_sm3, + TLCP_cipher_ibc_sm4_gcm_sm3, + TLCP_cipher_rsa_sm4_cbc_sm3, + TLCP_cipher_rsa_sm4_gcm_sm3, + TLCP_cipher_rsa_sm4_cbc_sha256, + TLCP_cipher_rsa_sm4_gcm_sha256, + }; + uint8_t comp_meths[] = {0}; + + tls_record_set_handshake_client_hello(record, &recordlen, + version, + random, + NULL, 0, + cipher_suites, sizeof(cipher_suites)/2, + NULL, 0); + + tls_client_hello_print(stdout, record + 5 + 4, recordlen - 5 -4, 0, 4); + return 0; +} + +static int test_tls_server_hello(void) +{ + uint8_t record[512]; + size_t recordlen = 0; + + + uint8_t version[2] = {1,1}; + uint8_t random[32]; + uint16_t cipher_suite = TLCP_cipher_ecdhe_sm4_cbc_sm3; + uint8_t comp_meth = 0; + + tls_record_set_handshake_server_hello(record, &recordlen, + version, + random, + NULL, 0, + cipher_suite, + comp_meth, + NULL, 0); + + tls_server_hello_print(stdout, record + 5 + 4, recordlen - 5 -4, 0, 0); + + return 0; +} + +static int test_tls_certificate(void) +{ + uint8_t record[1024]; + size_t recordlen = 0; + FILE *fp = NULL; + + if (!(fp = fopen("cacerts.pem", "r"))) { + error_print(); + return -1; + } + if (tls_record_set_handshake_certificate_from_pem(record, &recordlen, fp) != 1) { + error_print(); + return -1; + } + tls_certificate_print(stdout, record + 9, recordlen - 9, 0, 0); + return 0; +} + +static int test_tls_server_key_exchange(void) +{ + uint8_t record[1024]; + size_t recordlen = 0; + const uint8_t version[] = {1,1}; + uint8_t sig[77]; + size_t siglen; + + tls_record_set_version(record, version); + if (tlcp_record_set_handshake_server_key_exchange_pke(record, &recordlen, sig, sizeof(sig)) != 1) { + error_print(); + return -1; + } + if (tlcp_record_get_handshake_server_key_exchange_pke(record, sig, &siglen) != 1) { + error_print(); + return -1; + } + tls_server_key_exchange_print(stdout, sig, siglen, 0, 0); + return 1; +} + +static int test_tls_certificate_verify(void) +{ + uint8_t record[1024]; + size_t recordlen = 0; + const uint8_t version[] = {1,1}; + uint8_t sig[77]; + size_t siglen; + + tls_record_set_version(record, version); + if (tls_record_set_handshake_certificate_verify(record, &recordlen, sig, sizeof(sig)) != 1) { + error_print(); + return -1; + } + if (tls_record_get_handshake_certificate_verify(record, sig, &siglen) != 1) { + error_print(); + return -1; + } + tls_certificate_verify_print(stdout, sig, siglen, 0, 0); + return 1; +} + +static int test_tls_finished(void) +{ + uint8_t record[1024]; + size_t recordlen = 0; + uint8_t verify_data[12]; + + if (tls_record_set_handshake_finished(record, &recordlen, verify_data) != 1) { + error_print(); + return -1; + } + if (tls_record_get_handshake_finished(record, verify_data) != 1) { + error_print(); + return -1; + } + tls_finished_print(stdout, verify_data, 12, 0, 0); + return 1; +} + +static int test_tls_alert(void) +{ + uint8_t record[1024]; + size_t recordlen = 0; + int level; + int reason; + + if (tls_record_set_alert(record, &recordlen, TLS_alert_level_fatal, TLS_alert_close_notify) != 1) { + error_print(); + return -1; + } + if (tls_record_get_alert(record, &level, &reason) != 1) { + error_print(); + return -1; + } + tls_alert_print(stdout, record + 5, recordlen - 5, 0, 0); + return 1; +} + +static int test_tls_change_cipher_spec(void) +{ + uint8_t record[1024]; + size_t recordlen = 0; + + if (tls_record_set_change_cipher_spec(record, &recordlen) != 1) { + error_print(); + return -1; + } + if (tls_record_get_change_cipher_spec(record) != 1) { + error_print(); + return -1; + } + tls_change_cipher_spec_print(stdout, record + 5, recordlen - 5, 0, 0); + return 1; +} + +static int test_tls_application_data(void) +{ + uint8_t record[1024]; + size_t recordlen = 0; + uint8_t data[88]; + const uint8_t *p; + size_t len; + + if (tls_record_set_application_data(record, &recordlen, data, sizeof(data)) != 1) { + error_print(); + return -1; + } + if (tls_record_get_application_data(record, &p, &len) != 1) { + error_print(); + return -1; + } + tls_application_data_print(stdout, p, len, 0, 0); + return 1; +} + +int main(void) +{ + int err = 0; + err += test_tls_encode(); + err += test_tls_cbc(); + err += test_tls_random(); + err += test_tls_client_hello(); + err += test_tls_server_hello(); + err += test_tls_certificate(); + err += test_tls_server_key_exchange(); + err += test_tls_certificate_verify(); + err += test_tls_finished(); + err += test_tls_alert(); + err += test_tls_change_cipher_spec(); + err += test_tls_application_data(); + return 0; +} + diff --git a/tests/u128test.c b/tests/u128test.c new file mode 100644 index 00000000..fa2b22e9 --- /dev/null +++ b/tests/u128test.c @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2014 - 2020 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + +#include +#include +#include + +int main(void) +{ + __uint128_t a = 0; + uint64_t al = 1; + uint64_t ah = 1; + + a = ((__uint128_t)ah << 64) | al; + + return (int)a; +} diff --git a/tests/x509test.c b/tests/x509test.c new file mode 100644 index 00000000..5951fa1e --- /dev/null +++ b/tests/x509test.c @@ -0,0 +1,328 @@ +/* + * Copyright (c) 2014 - 2021 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + +#include +#include +#include +#include +#include +#include +#include + + +static int test_x509_validity(void) +{ + int err = 0; + X509_VALIDITY validity; + uint8_t buf[64] = {0}; + const uint8_t *cp = buf; + uint8_t *p = buf; + size_t len = 0; + size_t i; + + printf("%s\n", __FUNCTION__); + memset(&validity, 0, sizeof(X509_VALIDITY)); + + x509_validity_set_days(&validity, time(NULL), 365 * 10); + x509_validity_to_der(&validity, &p, &len); + print_der(buf, len); + printf("\n"); + + memset(&validity, 0, sizeof(X509_VALIDITY)); + x509_validity_from_der(&validity, &cp, &len); + x509_validity_print(stdout, &validity, 0, 0); + + printf("\n"); + return err; +} + +static int test_x509_name(void) +{ + int err = 0; + X509_NAME name; + uint8_t buf[1024]; + const uint8_t *cp = buf; + uint8_t *p = buf; + size_t len = 0; + + printf("%s\n", __FUNCTION__); + + memset(&name, 0, sizeof(X509_NAME)); + x509_name_add_rdn(&name, OID_at_countryName, ASN1_TAG_PrintableString, "CN"); + x509_name_add_rdn(&name, OID_at_stateOrProvinceName, ASN1_TAG_PrintableString, "Beijing"); + x509_name_add_rdn(&name, OID_at_organizationName, ASN1_TAG_PrintableString, "PKU"); + x509_name_add_rdn(&name, OID_at_organizationalUnitName, ASN1_TAG_PrintableString, "CS"); + x509_name_add_rdn(&name, OID_at_commonName, ASN1_TAG_PrintableString, "infosec"); + + if (x509_name_to_der(&name, &p, &len) != 1) { + error_print(); + err++; + goto end; + } + print_der(buf, len); + printf("\n"); + + if (x509_name_from_der(&name, &cp, &len) != 1 + || len > 0) { + error_print(); + err++; + goto end; + } + x509_name_print(stdout, &name, 0, 0); + +end: + printf("\n"); + return err; +} + +static int test_x509_signature_algor(int oid) +{ + int err = 0; + int tests[] = {OID_sm2sign_with_sm3, OID_rsasign_with_sm3}; + int val; + uint8_t buf[128]; + const uint8_t *cp = buf; + uint8_t *p = buf; + size_t len = 0; + size_t i; + + printf("%s\n", __FUNCTION__); + for (i = 0; i < sizeof(tests)/sizeof(tests[0]); i++) { + printf("%s\n", asn1_object_identifier_name(tests[i])); + } + for (i = 0; i < sizeof(tests)/sizeof(tests[0]); i++) { + if (x509_signature_algor_to_der(tests[i], &p, &len) != 1) { + error_print(); + err++; + goto end; + } + print_der(buf, len); + printf("\n"); + } + for (i = 0; i < sizeof(tests)/sizeof(tests[0]); i++) { + if (x509_signature_algor_from_der(&val, &cp, &len) != 1) { + error_print(); + err++; + goto end; + } + if (val != tests[i]) { + error_print(); + err++; + goto end; + } + printf("%s\n", asn1_object_identifier_name(tests[i])); + } + +end: + printf("\n"); + return err; +} + +static int test_x509_public_key_info(void) +{ + int err = 0; + SM2_KEY key; + X509_PUBLIC_KEY_INFO pkey_info; + uint8_t buf[256]; + const uint8_t *cp = buf; + uint8_t *p = buf; + size_t len = 0; + + printf("%s\n", __FUNCTION__); + + sm2_keygen(&key); + x509_public_key_info_set_sm2(&pkey_info, &key); + + if (x509_public_key_info_to_der(&pkey_info, &p, &len) != 1) { + error_print(); + return -1; + } + print_der(buf, len); + printf("\n"); + + if (x509_public_key_info_from_der(&pkey_info, &cp, &len) != 1 + || len > 0) { + error_print(); + return -1; + } + + x509_public_key_info_print(stdout, &pkey_info, 0, 0); + + printf("\n"); + return err; +} + +static int test_x509_certificate(void) +{ + int err = 0; + X509_CERTIFICATE _cert, *cert = &_cert; + int rv; + int version = X509_version_v3; + uint8_t sn[12]; + X509_NAME issuer; + X509_NAME subject; + time_t not_before; + + SM2_KEY key; + + uint8_t buf[2048] = {0}; + uint8_t *p = buf; + const uint8_t *cp = buf; + size_t len = 0; + + printf("%s\n", __FUNCTION__); + + memset(cert, 0, sizeof(X509_CERTIFICATE)); + + rand_bytes(sn, sizeof(sn)); + + memset(&issuer, 0, sizeof(X509_NAME)); + // add_rdn 应该用一个ex来支持长度 + x509_name_add_rdn(&issuer, OID_at_countryName, ASN1_TAG_PrintableString, "CN"); + x509_name_add_rdn(&issuer, OID_at_stateOrProvinceName, ASN1_TAG_PrintableString, "Beijing"); + x509_name_add_rdn(&issuer, OID_at_organizationName, ASN1_TAG_PrintableString, "PKU"); + x509_name_add_rdn(&issuer, OID_at_organizationalUnitName, ASN1_TAG_PrintableString, "CS"); + x509_name_add_rdn(&issuer, OID_at_commonName, ASN1_TAG_PrintableString, "CA"); + + memset(&subject, 0, sizeof(X509_NAME)); + x509_name_add_rdn(&subject, OID_at_countryName, ASN1_TAG_PrintableString, "CN"); + x509_name_add_rdn(&subject, OID_at_stateOrProvinceName, ASN1_TAG_PrintableString, "Beijing"); + x509_name_add_rdn(&subject, OID_at_organizationName, ASN1_TAG_PrintableString, "PKU"); + x509_name_add_rdn(&subject, OID_at_organizationalUnitName, ASN1_TAG_PrintableString, "CS"); + x509_name_add_rdn(&subject, OID_at_commonName, ASN1_TAG_PrintableString, "infosec"); + + time(¬_before); + + rv = x509_certificate_set_version(cert, version); + rv = x509_certificate_set_serial_number(cert, sn, sizeof(sn)); + rv = x509_certificate_set_signature_algor(cert, OID_sm2sign_with_sm3); // 这个不是应该在设置公钥的时候一起设置吗? + rv = x509_certificate_set_issuer(cert, &issuer); + rv = x509_certificate_set_subject(cert, &subject); + rv = x509_certificate_set_validity(cert, not_before, 365); + + sm2_keygen(&key); + rv = x509_certificate_set_subject_public_key_info_sm2(cert, &key); + + + rv = x509_certificate_generate_subject_key_identifier(cert, 1); + + + rv = x509_certificate_sign_sm2(cert, &key); + + rv = x509_certificate_to_der(cert, &p, &len); + print_der(buf, len); + printf("\n"); + + memset(cert, 0, sizeof(X509_CERTIFICATE)); + x509_certificate_from_der(cert, &cp, &len); + + x509_certificate_print(stdout, cert, 0, 0); + + + return 0; +} + +static int test_x509_cert_request(void) +{ + int err = 0; + X509_CERT_REQUEST req; + X509_NAME subject; + SM2_KEY keypair; + uint8_t buf[256]; + uint8_t *p = buf; + const uint8_t *cp = buf; + size_t len = 0; + + printf("%s : \n", __func__); + + memset(&subject, 0, sizeof(X509_NAME)); + x509_name_add_rdn(&subject, OID_at_countryName, ASN1_TAG_PrintableString, "CN"); + x509_name_add_rdn(&subject, OID_at_stateOrProvinceName, ASN1_TAG_PrintableString, "Beijing"); + x509_name_add_rdn(&subject, OID_at_organizationName, ASN1_TAG_PrintableString, "PKU"); + x509_name_add_rdn(&subject, OID_at_organizationalUnitName, ASN1_TAG_PrintableString, "CS"); + x509_name_add_rdn(&subject, OID_at_commonName, ASN1_TAG_PrintableString, "infosec"); + + sm2_keygen(&keypair); + + if (x509_cert_request_set_sm2(&req, &subject, &keypair) != 1 + || x509_cert_request_sign_sm2(&req, &keypair) != 1 + || x509_cert_request_to_der(&req, &p, &len) != 1) { + error_print(); + err++; + goto end; + } + print_der(buf, len); + printf("\n"); + + memset(&req, 0, sizeof(req)); + if (x509_cert_request_from_der(&req, &cp, &len) != 1) { + error_print(); + err++; + goto end; + } + + x509_cert_request_print(stdout, &req, 0, 0); + +end: + return err; +} + + +int main(void) +{ + int err = 0; + //err += test_x509_validity(); + err += test_x509_signature_algor(OID_sm2sign_with_sm3); + err += test_x509_signature_algor(OID_rsasign_with_sm3); + err += test_x509_name(); + err += test_x509_public_key_info(); + err += test_x509_certificate(); + err += test_x509_cert_request(); + //test_x509_extensions(); + return 1; +} diff --git a/tests/zuctest.c b/tests/zuctest.c new file mode 100644 index 00000000..4b05da74 --- /dev/null +++ b/tests/zuctest.c @@ -0,0 +1,522 @@ +/* ==================================================================== + * Copyright (c) 2014 - 2018 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + * ==================================================================== + */ + +#include +#include +#include +#include + + +static void bswap_buf(uint32_t *buf, size_t nwords) +{ + size_t i; + for (i = 0; i < nwords; i++) { + uint32_t a = buf[i]; + buf[i] = (a >> 24) | ((a >> 8) & 0xff00) | + ((a << 8) & 0xff0000) | (a << 24); + } +} + +int zuc_test(void) +{ + int err = 0; + int i; + + unsigned char key[][16] = { + {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, + {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff}, + {0x3d,0x4c,0x4b,0xe9,0x6a,0x82,0xfd,0xae,0xb5,0x8f,0x64,0x1d,0xb1,0x7b,0x45,0x5b}, + }; + unsigned char iv[][16] = { + {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, + {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff}, + {0x84,0x31,0x9a,0xa8,0xde,0x69,0x15,0xca,0x1f,0x6b,0xda,0x6b,0xfb,0xd8,0xc7,0x66}, + }; + uint32_t ciphertext[][2] = { + {0x27bede74, 0x018082da}, + {0x0657cfa0, 0x7096398b}, + {0x14f1c272, 0x3279c419}, + }; + + for (i = 0; i < 3; i++) { + ZUC_KEY zuc = {{0}}; + uint32_t buf[3] = {0}; + zuc_set_key(&zuc, key[i], iv[i]); + zuc_generate_keystream(&zuc, 2, buf); + if (buf[0] != ciphertext[i][0] || buf[1] != ciphertext[i][1]) { + fprintf(stderr, "error generating ZUC key stream on test vector %d\n", i); + err++; + } else { + fprintf(stderr, "zuc test %d ok\n", i); + } + } + + return err; +} + +/* test vector from GM/T 0001.2-2012 */ +static int zuc_eea_test(void) +{ + int err = 0; + unsigned char key[][16] = { + {0x17, 0x3d, 0x14, 0xba, 0x50, 0x03, 0x73, 0x1d, + 0x7a, 0x60, 0x04, 0x94, 0x70, 0xf0, 0x0a, 0x29}, + {0xe5, 0xbd, 0x3e, 0xa0, 0xeb, 0x55, 0xad, 0xe8, + 0x66, 0xc6, 0xac, 0x58, 0xbd, 0x54, 0x30, 0x2a}, + {0xe1, 0x3f, 0xed, 0x21, 0xb4, 0x6e, 0x4e, 0x7e, + 0xc3, 0x12, 0x53, 0xb2, 0xbb, 0x17, 0xb3, 0xe0}, + }; + ZUC_UINT32 count[] = {0x66035492, 0x56823, 0x2738cdaa}; + ZUC_UINT5 bearer[] = {0x0f, 0x18, 0x1a}; + ZUC_BIT direction[] = {0, 1, 0}; + ZUC_UINT32 ibs0[] = { + 0x6cf65340, 0x735552ab, 0x0c9752fa, 0x6f9025fe, + 0x0bd675d9, 0x005875b2, 0x00000000, + }; + ZUC_UINT32 ibs1[] = { + 0x14a8ef69, 0x3d678507, 0xbbe7270a, 0x7f67ff50, + 0x06c3525b, 0x9807e467, 0xc4e56000, 0xba338f5d, + 0x42955903, 0x67518222, 0x46c80d3b, 0x38f07f4b, + 0xe2d8ff58, 0x05f51322, 0x29bde93b, 0xbbdcaf38, + 0x2bf1ee97, 0x2fbf9977, 0xbada8945, 0x847a2a6c, + 0x9ad34a66, 0x7554e04d, 0x1f7fa2c3, 0x3241bd8f, + 0x01ba220d, + }; + ZUC_UINT32 ibs2[] = { + 0x8d74e20d, 0x54894e06, 0xd3cb13cb, 0x3933065e, + 0x8674be62, 0xadb1c72b, 0x3a646965, 0xab63cb7b, + 0x7854dfdc, 0x27e84929, 0xf49c64b8, 0x72a490b1, + 0x3f957b64, 0x827e71f4, 0x1fbd4269, 0xa42c97f8, + 0x24537027, 0xf86e9f4a, 0xd82d1df4, 0x51690fdd, + 0x98b6d03f, 0x3a0ebe3a, 0x312d6b84, 0x0ba5a182, + 0x0b2a2c97, 0x09c090d2, 0x45ed267c, 0xf845ae41, + 0xfa975d33, 0x33ac3009, 0xfd40eba9, 0xeb5b8857, + 0x14b768b6, 0x97138baf, 0x21380eca, 0x49f644d4, + 0x8689e421, 0x5760b906, 0x739f0d2b, 0x3f091133, + 0xca15d981, 0xcbe401ba, 0xf72d05ac, 0xe05cccb2, + 0xd297f4ef, 0x6a5f58d9, 0x1246cfa7, 0x7215b892, + 0xab441d52, 0x78452795, 0xccb7f5d7, 0x9057a1c4, + 0xf77f80d4, 0x6db2033c, 0xb79bedf8, 0xe60551ce, + 0x10c667f6, 0x2a97abaf, 0xabbcd677, 0x2018df96, + 0xa282ea73, 0x7ce2cb33, 0x1211f60d, 0x5354ce78, + 0xf9918d9c, 0x206ca042, 0xc9b62387, 0xdd709604, + 0xa50af16d, 0x8d35a890, 0x6be484cf, 0x2e74a928, + 0x99403643, 0x53249b27, 0xb4c9ae29, 0xeddfc7da, + 0x6418791a, 0x4e7baa06, 0x60fa6451, 0x1f2d685c, + 0xc3a5ff70, 0xe0d2b742, 0x92e3b8a0, 0xcd6b04b1, + 0xc790b8ea, 0xd2703708, 0x540dea2f, 0xc09c3da7, + 0x70f65449, 0xc84d817a, 0x4f551055, 0xe19ab850, + 0x18a0028b, 0x71a144d9, 0x6791e9a3, 0x57793350, + 0x4eee0060, 0x340c69d2, 0x74e1bf9d, 0x805dcbcc, + 0x1a6faa97, 0x6800b6ff, 0x2b671dc4, 0x63652fa8, + 0xa33ee509, 0x74c1c21b, 0xe01eabb2, 0x16743026, + 0x9d72ee51, 0x1c9dde30, 0x797c9a25, 0xd86ce74f, + 0x5b961be5, 0xfdfb6807, 0x814039e7, 0x137636bd, + 0x1d7fa9e0, 0x9efd2007, 0x505906a5, 0xac45dfde, + 0xed7757bb, 0xee745749, 0xc2963335, 0x0bee0ea6, + 0xf409df45, 0x80160000, + }; + ZUC_UINT32 obs0[] = { + 0xa6c85fc6, 0x6afb8533, 0xaafc2518, 0xdfe78494, + 0x0ee1e4b0, 0x30238cc8, 0x00000000, + }; + ZUC_UINT32 obs1[] = { + 0x131d43e0, 0xdea1be5c, 0x5a1bfd97, 0x1d852cbf, + 0x712d7b4f, 0x57961fea, 0x3208afa8, 0xbca433f4, + 0x56ad09c7, 0x417e58bc, 0x69cf8866, 0xd1353f74, + 0x865e8078, 0x1d202dfb, 0x3ecff7fc, 0xbc3b190f, + 0xe82a204e, 0xd0e350fc, 0x0f6f2613, 0xb2f2bca6, + 0xdf5a473a, 0x57a4a00d, 0x985ebad8, 0x80d6f238, + 0x64a07b01, + }; + ZUC_UINT32 obs2[] = { + 0x94eaa4aa, 0x30a57137, 0xddf09b97, 0xb25618a2, + 0x0a13e2f1, 0x0fa5bf81, 0x61a879cc, 0x2ae797a6, + 0xb4cf2d9d, 0xf31debb9, 0x905ccfec, 0x97de605d, + 0x21c61ab8, 0x531b7f3c, 0x9da5f039, 0x31f8a064, + 0x2de48211, 0xf5f52ffe, 0xa10f392a, 0x04766998, + 0x5da454a2, 0x8f080961, 0xa6c2b62d, 0xaa17f33c, + 0xd60a4971, 0xf48d2d90, 0x9394a55f, 0x48117ace, + 0x43d708e6, 0xb77d3dc4, 0x6d8bc017, 0xd4d1abb7, + 0x7b7428c0, 0x42b06f2f, 0x99d8d07c, 0x9879d996, + 0x00127a31, 0x985f1099, 0xbbd7d6c1, 0x519ede8f, + 0x5eeb4a61, 0x0b349ac0, 0x1ea23506, 0x91756bd1, + 0x05c974a5, 0x3eddb35d, 0x1d4100b0, 0x12e522ab, + 0x41f4c5f2, 0xfde76b59, 0xcb8b96d8, 0x85cfe408, + 0x0d1328a0, 0xd636cc0e, 0xdc05800b, 0x76acca8f, + 0xef672084, 0xd1f52a8b, 0xbd8e0993, 0x320992c7, + 0xffbae17c, 0x408441e0, 0xee883fc8, 0xa8b05e22, + 0xf5ff7f8d, 0x1b48c74c, 0x468c467a, 0x028f09fd, + 0x7ce91109, 0xa570a2d5, 0xc4d5f4fa, 0x18c5dd3e, + 0x4562afe2, 0x4ef77190, 0x1f59af64, 0x5898acef, + 0x088abae0, 0x7e92d52e, 0xb2de5504, 0x5bb1b7c4, + 0x164ef2d7, 0xa6cac15e, 0xeb926d7e, 0xa2f08b66, + 0xe1f759f3, 0xaee44614, 0x725aa3c7, 0x482b3084, + 0x4c143ff8, 0x7b53f1e5, 0x83c50125, 0x7dddd096, + 0xb81268da, 0xa303f172, 0x34c23335, 0x41f0bb8e, + 0x190648c5, 0x807c866d, 0x71932286, 0x09adb948, + 0x686f7de2, 0x94a802cc, 0x38f7fe52, 0x08f5ea31, + 0x96d0167b, 0x9bdd02f0, 0xd2a5221c, 0xa508f893, + 0xaf5c4b4b, 0xb9f4f520, 0xfd84289b, 0x3dbe7e61, + 0x497a7e2a, 0x584037ea, 0x637b6981, 0x127174af, + 0x57b471df, 0x4b2768fd, 0x79c1540f, 0xb3edf2ea, + 0x22cb69be, 0xc0cf8d93, 0x3d9c6fdd, 0x645e8505, + 0x91cca3d6, 0x2c0cc000, + }; + ZUC_UINT32 *ibs[] = {ibs0, ibs1, ibs2}; + ZUC_UINT32 *obs[] = {obs0, obs1, obs2}; + size_t bits[] = {0xc1, 0x320, 0xfb3}; + ZUC_UINT32 buf[sizeof(obs2)/4]; + size_t i; + + for (i = 0; i < sizeof(key)/sizeof(key[i]); i++) { + zuc_eea_encrypt(ibs[i], buf, bits[i], key[i], count[i], bearer[i], direction[i]); + if (memcmp(buf, obs[i], (bits[i] + 31)/32) != 0) { + printf("zuc eea test %zu failed\n", i); + err++; + } else { + printf("zuc eea test %zu ok\n", i); + } + } + + return err; +} + +/* test vector from GM/T 0001.3-2012 */ +static int zuc_eia_test(void) +{ + int err = 0; + unsigned char key[][16] = { + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0xc9, 0xe6, 0xce, 0xc4, 0x60, 0x7c, 0x72, 0xdb, + 0x00, 0x0a, 0xef, 0xa8, 0x83, 0x85, 0xab, 0x0a}, + {0x6b, 0x8b, 0x08, 0xee, 0x79, 0xe0, 0xb5, 0x98, + 0x2d, 0x6d, 0x12, 0x8e, 0xa9, 0xf2, 0x20, 0xcb}, + }; + ZUC_UINT32 count[] = {0, 0xa94059daU, 0x561eb2ddU}; + ZUC_UINT5 bearer[] = {0, 0x0a, 0x1c}; + ZUC_BIT direction[] = {0, 1, 0}; + ZUC_UINT32 mesg0[] = {0}; + ZUC_UINT32 mesg1[] = { + 0x983b41d4, 0x7d780c9e, 0x1ad11d7e, 0xb70391b1, + 0xde0b35da, 0x2dc62f83, 0xe7b78d63, 0x06ca0ea0, + 0x7e941b7b, 0xe91348f9, 0xfcb170e2, 0x217fecd9, + 0x7f9f68ad, 0xb16e5d7d, 0x21e569d2, 0x80ed775c, + 0xebde3f40, 0x93c53881, 0x00000000, + }; + ZUC_UINT32 mesg2[] = { + 0x5bad7247, 0x10ba1c56, 0xd5a315f8, 0xd40f6e09, + 0x3780be8e, 0x8de07b69, 0x92432018, 0xe08ed96a, + 0x5734af8b, 0xad8a575d, 0x3a1f162f, 0x85045cc7, + 0x70925571, 0xd9f5b94e, 0x454a77c1, 0x6e72936b, + 0xf016ae15, 0x7499f054, 0x3b5d52ca, 0xa6dbeab6, + 0x97d2bb73, 0xe41b8075, 0xdce79b4b, 0x86044f66, + 0x1d4485a5, 0x43dd7860, 0x6e0419e8, 0x059859d3, + 0xcb2b67ce, 0x0977603f, 0x81ff839e, 0x33185954, + 0x4cfbc8d0, 0x0fef1a4c, 0x8510fb54, 0x7d6b06c6, + 0x11ef44f1, 0xbce107cf, 0xa45a06aa, 0xb360152b, + 0x28dc1ebe, 0x6f7fe09b, 0x0516f9a5, 0xb02a1bd8, + 0x4bb0181e, 0x2e89e19b, 0xd8125930, 0xd178682f, + 0x3862dc51, 0xb636f04e, 0x720c47c3, 0xce51ad70, + 0xd94b9b22, 0x55fbae90, 0x6549f499, 0xf8c6d399, + 0x47ed5e5d, 0xf8e2def1, 0x13253e7b, 0x08d0a76b, + 0x6bfc68c8, 0x12f375c7, 0x9b8fe5fd, 0x85976aa6, + 0xd46b4a23, 0x39d8ae51, 0x47f680fb, 0xe70f978b, + 0x38effd7b, 0x2f7866a2, 0x2554e193, 0xa94e98a6, + 0x8b74bd25, 0xbb2b3f5f, 0xb0a5fd59, 0x887f9ab6, + 0x8159b717, 0x8d5b7b67, 0x7cb546bf, 0x41eadca2, + 0x16fc1085, 0x0128f8bd, 0xef5c8d89, 0xf96afa4f, + 0xa8b54885, 0x565ed838, 0xa950fee5, 0xf1c3b0a4, + 0xf6fb71e5, 0x4dfd169e, 0x82cecc72, 0x66c850e6, + 0x7c5ef0ba, 0x960f5214, 0x060e71eb, 0x172a75fc, + 0x1486835c, 0xbea65344, 0x65b055c9, 0x6a72e410, + 0x52241823, 0x25d83041, 0x4b40214d, 0xaa8091d2, + 0xe0fb010a, 0xe15c6de9, 0x0850973b, 0xdf1e423b, + 0xe148a237, 0xb87a0c9f, 0x34d4b476, 0x05b803d7, + 0x43a86a90, 0x399a4af3, 0x96d3a120, 0x0a62f3d9, + 0x507962e8, 0xe5bee6d3, 0xda2bb3f7, 0x237664ac, + 0x7a292823, 0x900bc635, 0x03b29e80, 0xd63f6067, + 0xbf8e1716, 0xac25beba, 0x350deb62, 0xa99fe031, + 0x85eb4f69, 0x937ecd38, 0x7941fda5, 0x44ba67db, + 0x09117749, 0x38b01827, 0xbcc69c92, 0xb3f772a9, + 0xd2859ef0, 0x03398b1f, 0x6bbad7b5, 0x74f7989a, + 0x1d10b2df, 0x798e0dbf, 0x30d65874, 0x64d24878, + 0xcd00c0ea, 0xee8a1a0c, 0xc753a279, 0x79e11b41, + 0xdb1de3d5, 0x038afaf4, 0x9f5c682c, 0x3748d8a3, + 0xa9ec54e6, 0xa371275f, 0x1683510f, 0x8e4f9093, + 0x8f9ab6e1, 0x34c2cfdf, 0x4841cba8, 0x8e0cff2b, + 0x0bcc8e6a, 0xdcb71109, 0xb5198fec, 0xf1bb7e5c, + 0x531aca50, 0xa56a8a3b, 0x6de59862, 0xd41fa113, + 0xd9cd9578, 0x08f08571, 0xd9a4bb79, 0x2af271f6, + 0xcc6dbb8d, 0xc7ec36e3, 0x6be1ed30, 0x8164c31c, + 0x7c0afc54, 0x1c000000, + }; + ZUC_UINT32 *mesg[] = {mesg0, mesg1, mesg2}; + size_t bits[] = {1, 0x241, 0x1626}; + ZUC_UINT32 mac[] = {0xc8a9595eU, 0xfae8ff0bU, 0x0ca12792U}; + size_t i; + + bswap_buf(mesg0, sizeof(mesg0)/sizeof(mesg0[0])); + bswap_buf(mesg1, sizeof(mesg1)/sizeof(mesg1[0])); + bswap_buf(mesg2, sizeof(mesg2)/sizeof(mesg2[0])); + + for (i = 0; i < sizeof(key)/sizeof(key[0]); i++) { + ZUC_UINT32 T; + T = zuc_eia_generate_mac(mesg[i], bits[i], key[i], + count[i], bearer[i], direction[i]); + if (T != mac[i]) { + printf("zuc eia test %zu failed\n", i); + err++; + } else { + printf("zuc eia test %zu ok\n", i); + } + } + + return err; +} + +/* from ZUC256 draft */ +int zuc256_test(void) +{ + int err = 0; + int i; + + unsigned char key[][32] = { + {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, + {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff} + }; + unsigned char iv[][23] = { + {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00}, + {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff}, + }; + uint32_t ciphertext[][20] = { + {0x58d03ad6,0x2e032ce2,0xdafc683a,0x39bdcb03,0x52a2bc67, + 0xf1b7de74,0x163ce3a1,0x01ef5558,0x9639d75b,0x95fa681b, + 0x7f090df7,0x56391ccc,0x903b7612,0x744d544c,0x17bc3fad, + 0x8b163b08,0x21787c0b,0x97775bb8,0x4943c6bb,0xe8ad8afd}, + {0x3356cbae,0xd1a1c18b,0x6baa4ffe,0x343f777c,0x9e15128f, + 0x251ab65b,0x949f7b26,0xef7157f2,0x96dd2fa9,0xdf95e3ee, + 0x7a5be02e,0xc32ba585,0x505af316,0xc2f9ded2,0x7cdbd935, + 0xe441ce11,0x15fd0a80,0xbb7aef67,0x68989416,0xb8fac8c2} + }; + + for (i = 0; i < sizeof(key)/sizeof(key[0]); i++) { + ZUC_KEY zuc_key; + uint32_t buf[20] = {0}; + + zuc256_set_key(&zuc_key, key[i], iv[i]); + zuc_generate_keystream(&zuc_key, 20, buf); + + if (memcmp(buf, ciphertext[i], 20) != 0) { + printf("zuc256 test %d failed\n", i); + err++; + } else { + printf("zuc256 test %d ok\n", i); + } + } + + return err; +} + +int zuc256_mac_test(void) +{ + int err = 0; + unsigned char key[][32] = { + {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, + {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, + {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff}, + {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff} + }; + unsigned char iv[][23] = { + {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00}, + {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00}, + {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff}, + {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff,0xff,0xff,0xff}, + }; + unsigned char msg[][50] = { + /* 400 zero bits */ + {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, + /* 4000 bits */ + {0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11, + 0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11, + 0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11, + 0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11, + 0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11}, + /* 400 zero bits */ + {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, + /* 4000 bits */ + {0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11, + 0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11, + 0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11, + 0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11, + 0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11}, + }; + unsigned int msg_num[] = { + 1, + 10, + 1, + 10 + }; + unsigned int tag32[][1] = { + {0x9b972a74}, + {0x8754f5cf}, + {0x1f3079b4}, + {0x5c7c8b88}, + }; + unsigned int tag64[][2] = { + {0x673e5499,0x0034d38c}, + {0x130dc225,0xe72240cc}, + {0x8c71394d,0x39957725}, + {0xea1dee54,0x4bb6223b}, + }; + unsigned int tag128[][4] = { + {0xd85e54bb,0xcb960096,0x7084c952,0xa1654b26}, + {0xdf1e8307,0xb31cc62b,0xeca1ac6f,0x8190c22f}, + {0xa35bb274,0xb567c48b,0x28319f11,0x1af34fbd}, + {0x3a83b554,0xbe408ca5,0x494124ed,0x9d473205}, + }; + int i, j; + + bswap_buf((uint32_t *)tag32, sizeof(tag32)/4); + bswap_buf((uint32_t *)tag64, sizeof(tag64)/4); + bswap_buf((uint32_t *)tag128, sizeof(tag128)/4); + + for (i = 0; i < 4; i++) { + ZUC256_MAC_CTX ctx; + unsigned char mac[16]; + + zuc256_mac_init(&ctx, key[i], iv[i], 32); + for (j = 0; j < msg_num[i]; j++) { + zuc256_mac_update(&ctx, msg[i], 50); + } + zuc256_mac_finish(&ctx, NULL, 0, mac); + if (memcmp(mac, tag32[i], 4) != 0) { + printf("zuc256 mac test %d 32-bit failed\n", i); + err++; + } else { + printf("zuc256 mac test %d 32-bit ok\n", i); + } + + zuc256_mac_init(&ctx, key[i], iv[i], 64); + for (j = 0; j < msg_num[i]; j++) { + zuc256_mac_update(&ctx, msg[i], 50); + } + zuc256_mac_finish(&ctx, NULL, 0, mac); + if (memcmp(mac, tag64[i], 8) != 0) { + printf("zuc256 mac test %d 64-bit failed\n", i); + err++; + } else { + printf("zuc256 mac test %d 64-bit ok\n", i); + } + + zuc256_mac_init(&ctx, key[i], iv[i], 128); + for (j = 0; j < msg_num[i]; j++) { + zuc256_mac_update(&ctx, msg[i], 50); + } + zuc256_mac_finish(&ctx, NULL, 0, mac); + if (memcmp(mac, tag128[i], 16) != 0) { + printf("zuc256 mac test %d 128-bit failed\n", i); + err++; + } else { + printf("zuc256 mac test %d 128-bit ok\n", i); + } + } + + return err; +} + +int main(void) +{ + int err = 0; + err += zuc_test(); + err += zuc_eea_test(); + err += zuc_eia_test(); + err += zuc256_test(); + err += zuc256_mac_test(); + return err; +} diff --git a/tools/README.md b/tools/README.md new file mode 100644 index 00000000..105c62bd --- /dev/null +++ b/tools/README.md @@ -0,0 +1,3 @@ +# Command Line Tools + + diff --git a/tools/certgen.c b/tools/certgen.c new file mode 100644 index 00000000..7a5b425c --- /dev/null +++ b/tools/certgen.c @@ -0,0 +1,278 @@ +/* + * Copyright (c) 2021 - 2021 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/* +from RFC 2253 + +String X.500 AttributeType +------------------------------ +CN commonName +L localityName +ST stateOrProvinceName +O organizationName +OU organizationalUnitName +C countryName +STREET streetAddress +DC domainComponent +UID userid +*/ + +void print_usage(const char *prog) +{ + printf("Usage: %s command [options] ...\n", prog); + printf("\n"); + printf("Options:\n"); + printf(" -C country name\n"); + printf(" -O orgnization name\n"); + printf(" -OU orgnizational unit name\n"); + printf(" -CN common name\n"); + printf(" -L locality name\n"); + printf(" -ST state of province name\n"); + printf(" -days validity days\n"); + printf(" -keyfile private key file\n"); +} + +int main(int argc, char **argv) +{ + int ret = -1; + char *prog = basename(argv[0]); + char *country = NULL; + char *state = NULL; + char *org = NULL; + char *org_unit = NULL; + char *common_name = NULL; + char *keyfile = NULL; + int days = 0; + + FILE *keyfp = NULL; + + X509_CERTIFICATE cert; + + char *pass; + + uint8_t serial[12]; + X509_NAME name; + time_t not_before; + SM2_KEY sm2_key; // 这个应该是从文件中读取的! + uint8_t uniq_id[32]; + + uint8_t buf[1024]; + const uint8_t *cp = buf; + uint8_t *p = buf; + size_t len = 0; + + + + int kp[] = { + OID_kp_serverAuth, + OID_kp_clientAuth, + OID_kp_codeSigning, + OID_kp_emailProtection, + OID_kp_timeStamping, + OID_kp_OCSPSigning, + }; + + + if (argc < 2) { + print_usage(prog); + return 0; + } + + argc--; + argv++; + while (argc >= 1) { + if (!strcmp(*argv, "-help")) { + print_usage(prog); + return 0; + + } else if (!strcmp(*argv, "-CN")) { + if (--argc < 1) goto bad; + common_name = *(++argv); + + } else if (!strcmp(*argv, "-O")) { + if (--argc < 1) goto bad; + org = *(++argv); + + } else if (!strcmp(*argv, "-OU")) { + if (--argc < 1) goto bad; + org_unit = *(++argv); + + } else if (!strcmp(*argv, "-C")) { + if (--argc < 1) goto bad; + country = *(++argv); + + } else if (!strcmp(*argv, "-ST")) { + if (--argc < 1) goto bad; + state = *(++argv); + + } else if (!strcmp(*argv, "-keyfile")) { + if (--argc < 1) goto bad; + keyfile = *(++argv); + + } else if (!strcmp(*argv, "-days")) { + if (--argc < 1) goto bad; + days = atoi(*(++argv)); + + } else { + print_usage(prog); + return 0; + break; + } + + argc--; + argv++; + } + + if (days <= 0 && !keyfile) { + goto bad; + } + + if (!(keyfp = fopen(keyfile, "r"))) { + goto bad; + } + + pass = getpass("Password : "); + if (sm2_enced_private_key_info_from_pem(&sm2_key, pass, keyfp) != 1) { + error_print(); + goto end; + } + + + rand_bytes(serial, sizeof(serial)); + + + + memset(&name, 0, sizeof(name)); + + + + if (country) { + if (x509_name_set_country(&name, country) != 1) { + error_print(); + goto end; + } + } + if (state) { + if (x509_name_set_state_or_province(&name, state) != 1) { + error_print(); + goto end; + } + } + if (org) { + if (x509_name_set_organization(&name, org) != 1) { + error_print(); + goto end; + } + } + if (org_unit) { + if (x509_name_set_organizational_unit(&name, org_unit) != 1) { + error_print(); + goto end; + } + } + if (!common_name) { + error_print(); + goto end; + } else { + if (x509_name_set_common_name(&name, common_name) != 1) { + error_print(); + goto end; + } + } + + time(¬_before); + + + memset(&cert, 0, sizeof(cert)); + x509_certificate_set_version(&cert, X509_version_v3); + x509_certificate_set_serial_number(&cert, serial, sizeof(serial)); + x509_certificate_set_signature_algor(&cert, OID_sm2sign_with_sm3); + x509_certificate_set_issuer(&cert, &name); + x509_certificate_set_subject(&cert, &name); + x509_certificate_set_validity(&cert, not_before, days); + x509_certificate_set_subject_public_key_info_sm2(&cert, &sm2_key); + x509_certificate_set_issuer_unique_id_from_public_key(&cert, &sm2_key); + x509_certificate_set_subject_unique_id_from_public_key(&cert, &sm2_key); + + x509_certificate_set_basic_constraints(&cert, ASN1_TRUE, ASN1_TRUE, 6); + + x509_certificate_set_ext_key_usage(&cert, ASN1_TRUE, kp, sizeof(kp)/sizeof(kp[0])); + + x509_certificate_generate_subject_key_identifier(&cert, ASN1_TRUE); + + x509_certificate_set_inhibit_any_policy(&cert, ASN1_TRUE, 20); + + + + x509_certificate_set_policy_constraints(&cert, ASN1_FALSE, 5, 5); + + + + + x509_certificate_sign_sm2(&cert, &sm2_key); + x509_certificate_to_pem(&cert, stdout); + ret = 0; + goto end; + +bad: + fprintf(stderr, "%s: commands should not be used together\n", prog); + +end: + return ret; +} diff --git a/tools/certverify.c b/tools/certverify.c new file mode 100644 index 00000000..d1fecd94 --- /dev/null +++ b/tools/certverify.c @@ -0,0 +1,194 @@ +/* + * Copyright (c) 2021 - 2021 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +static int verify_cert(const X509_CERTIFICATE *cert, const X509_CERTIFICATE *cacert) +{ + int ret; + SM2_KEY ca_pubkey; + + if (x509_name_equ(&cert->tbs_certificate.issuer, &cacert->tbs_certificate.subject) != 1) { + error_print(); + return -1; + } + if (x509_certificate_get_public_key(cacert, &ca_pubkey) != 1) { + error_print(); + return -1; + } + if ((ret = x509_certificate_verify(cert, &ca_pubkey)) < 0) { + error_print(); + return -1; + } + return ret; +} + +static int find_cacert(X509_CERTIFICATE *cacert, FILE *fp, const X509_NAME *issuer) +{ + int ret; + for (;;) { + if ((ret = x509_certificate_from_pem(cacert, fp)) != 1) { + if (ret < 0) error_print(); + return ret; + } + if (x509_name_equ(&cacert->tbs_certificate.subject, issuer) == 1) { + return 1; + } + } + return 0; +} + + +void print_usage(const char *prog) +{ + printf("Usage: %s command [options] ...\n", prog); + printf("\n"); + printf("Options:\n"); + printf(" -cert PKCS #10 certificate request file\n"); + printf(" -cacert CA certificate file\n"); +} + +int main(int argc, char **argv) +{ + int ret = -1; + char *prog = basename(argv[0]); + char *certfile = NULL; + char *cacertfile = NULL; + FILE *certfp = NULL; + FILE *cacertfp = NULL; + + X509_CERTIFICATE cert1; + X509_CERTIFICATE cert2; + X509_CERTIFICATE *cert = &cert1; + X509_CERTIFICATE *cacert = &cert2; + X509_CERTIFICATE *tmpcert; + + SM2_KEY ca_pubkey; + + argc--; + argv++; + while (argc >= 1) { + if (!strcmp(*argv, "-help")) { + print_usage(prog); + return 0; + + } else if (!strcmp(*argv, "-cert")) { + if (--argc < 1) goto bad; + certfile = *(++argv); + if (!(certfp = fopen(certfile, "r"))) { + error_print(); + return -1; + } + } else if (!strcmp(*argv, "-cacert")) { + if (--argc < 1) goto bad; + cacertfile = *(++argv); + if (!(cacertfp = fopen(cacertfile, "r"))) { + error_print(); + return -1; + } + } else { + print_usage(prog); + return 0; + break; + } + + argc--; + argv++; + } + + if (!certfp || !cacertfp) { + print_usage(prog); + return -1; + } + + if (x509_certificate_from_pem(cert, certfp) != 1) { + error_print(); + return -1; + } + for (;;) { + if ((ret = x509_certificate_from_pem(cacert, certfp)) != 1) { + if (ret < 0) error_print(); + break; + } + if (verify_cert(cert, cacert) != 1) { + error_print(); + return -1; + } + tmpcert = cacert; + cert = cacert; + cacert = tmpcert; + } + + if (find_cacert(cacert, cacertfp, &cert->tbs_certificate.issuer) != 1) { + error_print(); + return -1; + } + if ((ret = verify_cert(cert, cacert)) < 0) { + error_print(); + return -1; + } + printf("Verification %s\n", ret ? "success" : "failure"); + + ret = 0; + goto end; + +bad: + fprintf(stderr, "%s: commands should not be used together\n", prog); + +end: + return ret; +} diff --git a/tools/certview.c b/tools/certview.c new file mode 100644 index 00000000..fe163abe --- /dev/null +++ b/tools/certview.c @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2020 - 2021 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + +#include +#include +#include +#include +#include +#include + + +int main(void) +{ + X509_CERTIFICATE cert; + for (;;) { + int ret = x509_certificate_from_pem(&cert, stdin); + if (ret < 0) { + error_print(); + return -1; + } + if (ret == 0) { + goto end; + } + fprintf(stdout, "Certificate\n"); + x509_certificate_print(stdout, &cert, 0, 0); + x509_certificate_to_pem(&cert, stdout); + fprintf(stdout, "\n"); + } +end: + return 0; +} diff --git a/tools/digest.c b/tools/digest.c new file mode 100644 index 00000000..3c0d19d5 --- /dev/null +++ b/tools/digest.c @@ -0,0 +1,226 @@ +/* + * Copyright (c) 2020 - 2021 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + +#include +#include +#include +#include +#include +#include + +#define FORMAT_HEX 1 +#define FORMAT_BIN 2 + + +void print_usage(FILE *out, const char *prog) +{ + fprintf(out, "Usage: %s command [options] ...\n", prog); + fprintf(out, "\n"); + fprintf(out, "Commands:\n"); + fprintf(out, " -help print the usage message\n"); + fprintf(out, " -sm3 use SM3\n"); + fprintf(out, " -md5 use MD5\n"); + fprintf(out, " -sha1 use SHA-1\n"); + fprintf(out, " -sha224 use SHA-224\n"); + fprintf(out, " -sha256 use SHA-256\n"); + fprintf(out, " -sha384 use SHA-384\n"); + fprintf(out, " -sha512 use SHA-512\n"); + fprintf(out, " -hex generate hex output\n"); + fprintf(out, " -binary generate binary output\n"); + fprintf(out, " -out file set output filename\n"); +} + +int main(int argc, char **argv) +{ + int ret = -1; + char *prog = basename(argv[0]); + int help = 0; + const DIGEST *digest = NULL; + int format = FORMAT_HEX; + char *infile = NULL; + char *outfile = NULL; + FILE *in = stdin; + FILE *out = stdout; + + DIGEST_CTX ctx; + unsigned char dgst[64]; + unsigned char buf[4096]; + size_t len; + size_t dgstlen, i; + + argc--; + argv++; + while (argc >= 1) { + if (!strcmp(*argv, "-help")) { + print_usage(stdout, prog); + goto end; + + } else if (!strcmp(*argv, "-sm3")) { + if (digest) goto bad; + digest = DIGEST_sm3(); + + } else if (!strcmp(*argv, "-md5")) { + if (digest) goto bad; + digest = DIGEST_md5(); + + } else if (!strcmp(*argv, "-sha1")) { + if (digest) goto bad; + digest = DIGEST_sha1(); + + } else if (!strcmp(*argv, "-sha224")) { + if (digest) goto bad; + digest = DIGEST_sha224(); + + } else if (!strcmp(*argv, "-sha256")) { + if (digest) goto bad; + digest = DIGEST_sha256(); + + } else if (!strcmp(*argv, "-sha384")) { + if (digest) goto bad; + digest = DIGEST_sha384(); + + } else if (!strcmp(*argv, "-sha512")) { + if (digest) goto bad; + digest = DIGEST_sha512(); + + } else if (!strcmp(*argv, "-hex")) { + format = FORMAT_HEX; + + } else if (!strcmp(*argv, "-binary")) { + format = FORMAT_BIN; + + } else if (!strcmp(*argv, "-out")) { + if (--argc < 1) goto bad; + outfile = *(++argv); + } else { + break; + } + + argc--; + argv++; + } + + if (!digest) { + fprintf(stderr, "%s: digest algorithm not speicified\n", prog); + fprintf(stderr, "usage: %s -[sm2|sha224|sha256|sha384|sha512] ...\n", prog); + return 1; + } + + if (outfile) { + if (!(out = fopen(outfile, "wb"))) { + fprintf(stderr, "%s: can not open %s\n", prog, outfile); + return 1; + } + } + + digest_ctx_init(&ctx); + + if (!argc) { + if (!digest_init(&ctx, digest)) { + goto end; + } + while ((len = fread(buf, 1, sizeof(buf), stdin)) > 0) { + if (!digest_update(&ctx, buf, len)) { + goto end; + } + } + if (!digest_finish(&ctx, dgst, &len)) { + goto end; + } + + if (format == FORMAT_BIN) { + fwrite(dgst, 1, len, out); + } else { + for (i = 0; i < len; i++) { + printf("%02x", dgst[i]); + } + printf("\n"); + } + + ret = 0; + goto end; + } + + // 多个输出文件,输出文件名和二进制输出有冲突 + + while (argc > 0) { + infile = *argv++; + if (!(in = fopen(infile, "rb"))) { + fprintf(stderr, "%s: can not open input file %s\n", prog, infile); + goto end; + } + + if (!digest_init(&ctx, digest)) { + goto end; + } + while ((len = fread(buf, 1, sizeof(buf), in)) > 0) { + if (!digest_update(&ctx, buf, len)) { + goto end; + } + } + fclose(in); + if (!digest_finish(&ctx, dgst, &dgstlen)) { + goto end; + } + + for (i = 0; i < dgstlen; i++) { + printf("%02x", dgst[i]); + } + printf(" %s\n", infile); + argc--; + } + ret = 0; + goto end; + +bad: + fprintf(stderr, "%s: commands should not be used together\n", prog); +end: + digest_ctx_cleanup(&ctx); + fclose(out); + return ret; +} diff --git a/tools/hmac.c b/tools/hmac.c new file mode 100644 index 00000000..1284ea64 --- /dev/null +++ b/tools/hmac.c @@ -0,0 +1,199 @@ +/* + * Copyright (c) 2020 - 2021 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + +#include +#include +#include +#include +#include +#include + +#define FORMAT_HEX 1 +#define FORMAT_BIN 2 + + +void print_usage(FILE *out, const char *prog) +{ + fprintf(out, "Usage: %s command [options] ...\n", prog); + fprintf(out, "\n"); + fprintf(out, "Commands:\n"); + fprintf(out, " -help print the usage message\n"); + fprintf(out, " -digest algor print the usage message\n"); + fprintf(out, " -key hex set the key in hex\n"); + fprintf(out, " -hex generate hex output\n"); + fprintf(out, " -binary generate binary output\n"); + fprintf(out, " -out file set output filename\n"); +} + +int main(int argc, char **argv) +{ + int ret = -1; + char *prog = basename(argv[0]); + int help = 0; + const DIGEST *digest = NULL; + int format = FORMAT_HEX; + char *infile = NULL; + char *outfile = NULL; + FILE *in = stdin; + FILE *out = stdout; + + DIGEST_CTX ctx; + unsigned char dgst[64]; + unsigned char buf[4096]; + size_t len; + size_t dgstlen, i; + + argc--; + argv++; + while (argc >= 1) { + if (!strcmp(*argv, "-help")) { + print_usage(stdout, prog); + goto end; + + } else if (!strcmp(*argv, "-digest")) { + if (--argc < 1) goto bad; + algor = *(++argv); + + } else if (!strcmp(*argv, "-key")) { + if (--argc < 1) goto bad; + algor = *(++argv); + + } else if (!strcmp(*argv, "-hex")) { + format = FORMAT_HEX; + + } else if (!strcmp(*argv, "-binary")) { + format = FORMAT_BIN; + + } else if (!strcmp(*argv, "-out")) { + if (--argc < 1) goto bad; + outfile = *(++argv); + + } else { + break; + } + + argc--; + argv++; + } + + if (!algor) { + } + + if (outfile) { + if (!(out = fopen(outfile, "wb"))) { + fprintf(stderr, "%s: can not open %s\n", prog, outfile); + return 1; + } + } + + digest_ctx_init(&ctx); + + if (!argc) { + if (!digest_init(&ctx, digest)) { + goto end; + } + while ((len = fread(buf, 1, sizeof(buf), stdin)) > 0) { + if (!digest_update(&ctx, buf, len)) { + goto end; + } + } + if (!digest_finish(&ctx, dgst, &len)) { + goto end; + } + + if (format == FORMAT_BIN) { + fwrite(dgst, 1, len, out); + } else { + for (i = 0; i < len; i++) { + printf("%02x", dgst[i]); + } + printf("\n"); + } + + ret = 0; + goto end; + } + + // 多个输出文件,输出文件名和二进制输出有冲突 + + while (argc > 0) { + infile = *argv++; + if (!(in = fopen(infile, "rb"))) { + fprintf(stderr, "%s: can not open input file %s\n", prog, infile); + goto end; + } + + if (!digest_init(&ctx, digest)) { + goto end; + } + while ((len = fread(buf, 1, sizeof(buf), in)) > 0) { + if (!digest_update(&ctx, buf, len)) { + goto end; + } + } + fclose(in); + if (!digest_finish(&ctx, dgst, &dgstlen)) { + goto end; + } + + for (i = 0; i < dgstlen; i++) { + printf("%02x", dgst[i]); + } + printf(" %s\n", infile); + argc--; + } + ret = 0; + goto end; + +bad: + fprintf(stderr, "%s: commands should not be used together\n", prog); +end: + digest_ctx_cleanup(&ctx); + fclose(out); + return ret; +} diff --git a/tools/oid.c b/tools/oid.c new file mode 100644 index 00000000..b9907e48 --- /dev/null +++ b/tools/oid.c @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2020 - 2021 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + +#include +#include +#include +#include +#include + + +// 对OID的几种类型进行转换 +// name, oid int值,DER编码 -oid 112 -name -der +// 这里我们要做类型转换 + +/* + +oid -name secp256k1 +secp256k1 : 1.2.3.4 : 030201220308 : hello world + + +*/ + +void print_usage(FILE *out, const char *prog) +{ + fprintf(out, "Usage: %s command [options] ...\n", prog); + fprintf(out, "\n"); + fprintf(out, "Commands:\n"); + fprintf(out, " -help print the usage message\n"); + fprintf(out, " -name oid name string\n"); + fprintf(out, " -oid oid value\n"); + fprintf(out, " -der oid der encoding in hex\n"); +} + + +int oid_vec_to_der(const unsigned int *oid, size_t oidlen, uint8_t *out, size_t *outlen) +{ + if (oidlen < 2) { + return -1; + } + + *out++ = oid[0] * 40 + oid[1]; + oidlen -= 2; + *outlen++; + + while (oidlen > 0) { + id (*oid < 128) { + *out++ = (uint8_t)(*oid); + } else { + *out++ = 0x80 & ((uint8_t)(*oid >> 8) << 1); + *out++ = 0x80 | (uint8_t)(*oid); + } + oid++; + oidlen--; + } + +} + +int main(int argc, char **argv) +{ + int ret = -1; + char *prog = basename(argv[0]); + int help = 0; + + argc--; + argv++; + while (argc >= 0) { + } +} diff --git a/tools/pkcs8gen.c b/tools/pkcs8gen.c new file mode 100644 index 00000000..80841f27 --- /dev/null +++ b/tools/pkcs8gen.c @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2021 - 2021 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +int main(void) +{ + SM2_KEY key; + char *pass = NULL; + char passbuf[64] = {0}; + + pass = getpass("Encryption Password : "); + strncpy(passbuf, pass, sizeof(passbuf)); + pass = getpass("Encryption Password (Again) : "); + if (strcmp(passbuf, pass) != 0) { + fprintf(stderr, "error: passwords not match\n"); + return -1; + } + + sm2_keygen(&key); + sm2_enced_private_key_info_to_pem(&key, pass, stdout); + + return 0; +} diff --git a/tools/pkcs8view.c b/tools/pkcs8view.c new file mode 100644 index 00000000..50e45bfe --- /dev/null +++ b/tools/pkcs8view.c @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2020 - 2021 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int main(void) +{ + SM2_KEY key; + const char *pass = NULL; + + pass = getpass("Password : "); + if (sm2_enced_private_key_info_from_pem(&key, pass, stdin) != 1) { + error_print(); + return -1; + } + sm2_key_print(stdout, &key, 0, 0); + sm2_public_key_info_to_pem(&key, stdout); + return 0; +} diff --git a/tools/reqgen.c b/tools/reqgen.c new file mode 100644 index 00000000..5ce4951c --- /dev/null +++ b/tools/reqgen.c @@ -0,0 +1,217 @@ +/* + * Copyright (c) 2021 - 2021 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +void print_usage(const char *prog) +{ + printf("Usage: %s command [options] ...\n", prog); + printf("\n"); + printf("Options:\n"); + printf(" -C country name\n"); + printf(" -O orgnization name\n"); + printf(" -OU orgnizational unit name\n"); + printf(" -CN common name\n"); + printf(" -L locality name\n"); + printf(" -ST state of province name\n"); + printf("\n"); + printf(" -days validity days\n"); + printf(" -keyfile private key file\n"); +} + +int main(int argc, char **argv) +{ + int ret = -1; + char *prog = basename(argv[0]); + char *country = NULL; + char *state = NULL; + char *org = NULL; + char *org_unit = NULL; + char *common_name = NULL; + char *keyfile = NULL; + int days = 0; + + FILE *keyfp = NULL; + + X509_CERT_REQUEST req; + + + char *pass; + + X509_NAME name; + SM2_KEY sm2_key; // 这个应该是从文件中读取的! + + + if (argc < 2) { + print_usage(prog); + return 0; + } + + argc--; + argv++; + while (argc >= 1) { + if (!strcmp(*argv, "-help")) { + print_usage(prog); + return 0; + + } else if (!strcmp(*argv, "-CN")) { + if (--argc < 1) goto bad; + common_name = *(++argv); + + } else if (!strcmp(*argv, "-O")) { + if (--argc < 1) goto bad; + org = *(++argv); + + } else if (!strcmp(*argv, "-OU")) { + if (--argc < 1) goto bad; + org_unit = *(++argv); + + } else if (!strcmp(*argv, "-C")) { + if (--argc < 1) goto bad; + country = *(++argv); + + } else if (!strcmp(*argv, "-ST")) { + if (--argc < 1) goto bad; + state = *(++argv); + + } else if (!strcmp(*argv, "-keyfile")) { + if (--argc < 1) goto bad; + keyfile = *(++argv); + + } else if (!strcmp(*argv, "-days")) { + if (--argc < 1) goto bad; + days = atoi(*(++argv)); + + } else { + print_usage(prog); + return 0; + break; + } + + argc--; + argv++; + } + + if (days <= 0 && !keyfile) { + goto bad; + } + + if (!(keyfp = fopen(keyfile, "r"))) { + goto bad; + } + + pass = getpass("Password : "); + if (sm2_enced_private_key_info_from_pem(&sm2_key, pass, keyfp) != 1) { + error_print(); + goto end; + } + + + + memset(&name, 0, sizeof(name)); + + + + if (country) { + if (x509_name_set_country(&name, country) != 1) { + error_print(); + goto end; + } + } + if (state) { + if (x509_name_set_state_or_province(&name, state) != 1) { + error_print(); + goto end; + } + } + if (org) { + if (x509_name_set_organization(&name, org) != 1) { + error_print(); + goto end; + } + } + if (org_unit) { + if (x509_name_set_organizational_unit(&name, org_unit) != 1) { + error_print(); + goto end; + } + } + if (!common_name) { + error_print(); + goto end; + } else { + if (x509_name_set_common_name(&name, common_name) != 1) { + error_print(); + goto end; + } + } + + + memset(&req, 0, sizeof(req)); + x509_cert_request_set(&req, &name, &sm2_key); + x509_cert_request_sign(&req, &sm2_key); + + x509_cert_request_to_pem(&req, stdout); + ret = 0; + goto end; + +bad: + fprintf(stderr, "%s: commands should not be used together\n", prog); + +end: + return ret; +} diff --git a/tools/reqsign.c b/tools/reqsign.c new file mode 100644 index 00000000..67aeef38 --- /dev/null +++ b/tools/reqsign.c @@ -0,0 +1,225 @@ +/* + * Copyright (c) 2021 - 2021 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + + +void print_usage(const char *prog) +{ + printf("Usage: %s command [options] ...\n", prog); + printf("\n"); + printf("Options:\n"); + printf(" -req PKCS #10 certificate request file\n"); + printf(" -cacert CA certificate file\n"); + printf(" -keyfile private key of cacert\n"); +} + +int main(int argc, char **argv) +{ + int ret = -1; + char *prog = basename(argv[0]); + char *keyfile = NULL; + + FILE *keyfp = NULL; + + X509_CERTIFICATE cert; + + char *pass; + + uint8_t serial[12]; + X509_NAME name; + time_t not_before; + SM2_KEY sm2_key; // 这个应该是从文件中读取的! + uint8_t uniq_id[32]; + + uint8_t buf[1024]; + const uint8_t *cp = buf; + uint8_t *p = buf; + size_t len = 0; + + if (argc < 2) { + print_usage(prog); + return 0; + } + + argc--; + argv++; + while (argc >= 1) { + if (!strcmp(*argv, "-help")) { + print_usage(prog); + return 0; + + } else if (!strcmp(*argv, "-CN")) { + if (--argc < 1) goto bad; + common_name = *(++argv); + + } else if (!strcmp(*argv, "-O")) { + if (--argc < 1) goto bad; + org = *(++argv); + + } else if (!strcmp(*argv, "-OU")) { + if (--argc < 1) goto bad; + org_unit = *(++argv); + + } else if (!strcmp(*argv, "-C")) { + if (--argc < 1) goto bad; + country = *(++argv); + + } else if (!strcmp(*argv, "-ST")) { + if (--argc < 1) goto bad; + state = *(++argv); + + } else if (!strcmp(*argv, "-keyfile")) { + if (--argc < 1) goto bad; + keyfile = *(++argv); + + } else if (!strcmp(*argv, "-days")) { + if (--argc < 1) goto bad; + days = atoi(*(++argv)); + + } else { + print_usage(prog); + return 0; + break; + } + + argc--; + argv++; + } + + if (days <= 0 && !keyfile) { + goto bad; + } + + if (!(keyfp = fopen(keyfile, "r"))) { + goto bad; + } + + pass = getpass("Password : "); + if (sm2_enced_private_key_info_from_pem(&sm2_key, pass, keyfp) != 1) { + error_print(); + goto end; + } + + + rand_bytes(serial, sizeof(serial)); + + + + memset(&name, 0, sizeof(name)); + + + + if (country) { + if (x509_name_set_country(&name, country) != 1) { + error_print(); + goto end; + } + } + if (state) { + if (x509_name_set_state_or_province(&name, state) != 1) { + error_print(); + goto end; + } + } + if (org) { + if (x509_name_set_organization(&name, org) != 1) { + error_print(); + goto end; + } + } + if (org_unit) { + if (x509_name_set_organizational_unit(&name, org_unit) != 1) { + error_print(); + goto end; + } + } + if (!common_name) { + error_print(); + goto end; + } else { + if (x509_name_set_common_name(&name, common_name) != 1) { + error_print(); + goto end; + } + } + + time(¬_before); + + + memset(&cert, 0, sizeof(cert)); + x509_certificate_set_version(&cert, X509_version_v3); + x509_certificate_set_serial_number(&cert, serial, sizeof(serial)); + x509_certificate_set_signature_algor(&cert, OID_sm2sign_with_sm3); + x509_certificate_set_issuer(&cert, &name); + x509_certificate_set_subject(&cert, &name); + x509_certificate_set_validity(&cert, not_before, days); + x509_certificate_set_subject_public_key_info_sm2(&cert, &sm2_key); + x509_certificate_set_issuer_unique_id(&cert, uniq_id, sizeof(uniq_id)); + x509_certificate_set_subject_unique_id(&cert, uniq_id, sizeof(uniq_id)); + x509_certificate_sign_sm2(&cert, &sm2_key); + + x509_certificate_to_pem(&cert, stdout); + ret = 0; + goto end; + +bad: + fprintf(stderr, "%s: commands should not be used together\n", prog); + +end: + return ret; +} diff --git a/tools/sdfutil.c b/tools/sdfutil.c new file mode 100644 index 00000000..2847b7f5 --- /dev/null +++ b/tools/sdfutil.c @@ -0,0 +1,349 @@ +/* + * Copyright (c) 2014 - 2021 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + + +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include "apps.h" + + +# define OP_NONE 0 +# define OP_PRINTDEVINFO 1 +# define OP_PRINTSM2SIGN 2 +# define OP_PRINTSM2ENC 3 +# define OP_PRINTRSASIGN 4 +# define OP_PRINTRSAENC 5 +# define OP_ACCESSKEY 6 +# define OP_IMPORTOBJ 7 +# define OP_EXPORTOBJ 8 +# define OP_DELOBJ 9 + +OPTIONS sdf_options[] = { + {"help", OPT_HELP, '-', "Display this summary"}, + {"lib", OPT_LIB, 's', "Vendor's SDF dynamic library"}, + {"vendor", OPT_VENDOR, 's', "Vendor name"}, + {"printdevinfo", OPT_PRINTDEVINFO, '-', "Print device information"}, + {"printsm2sign", OPT_PRINTSM2SIGN, 's', "Print SM2 signing key with key index"}, + {"printsm2enc", OPT_PRINTSM2ENC, 's', "Print SM2 encryption key with key index"}, + {"printrsasign", OPT_PRINTRSASIGN, 's', "Print RSA signing key with key index"}, + {"printrsaenc", OPT_PRINTRSAENC, 's', "Print RSA encryption key with key index"}, + {"accesskey", OPT_ACCESSKEY, 's', "Access private key with the key index number"}, + {"pass", OPT_PASS, 's', "Passphrase source for accessing private key"}, + {"importobj", OPT_IMPORTOBJ, 's', "Import data object into device"}, + {"exportobj", OPT_EXPORTOBJ, 's', "Export data object from device"}, + {"delobj", OPT_DELOBJ, 's', "Delete data object from device"}, + {"in", OPT_IN, '<', "File to be imported from"}, + {"out", OPT_OUT, '>', "File to be exported to"}, + {NULL} +}; + +int sdf_main(int argc, char **argv) +{ + int ret = 1; + char *infile = NULL, *outfile = NULL, *prog; + char *objname = NULL, *passarg = NULL, *pass = NULL; + BIO *in = NULL, *out = NULL; + char *lib = NULL, *vendor = NULL; + unsigned char *buf = NULL; + unsigned int ulen; + int len, key_idx = -1; + OPTION_CHOICE o; + int op = OP_NONE; + void *hDev = NULL; + void *hSession = NULL; + + prog = opt_init(argc, argv, sdf_options); + while ((o = opt_next()) != OPT_EOF) { + switch (o) { + case OPT_EOF: + case OPT_ERR: +opthelp: + BIO_printf(bio_err, "%s: Use -help for summary.\n", prog); + goto end; + case OPT_HELP: + opt_help(sdf_options); + ret = 0; + goto end; + case OPT_LIB: + lib = opt_arg(); + break; + case OPT_VENDOR: + vendor = opt_arg(); + break; + case OPT_PRINTDEVINFO: + if (op) + goto opthelp; + op = OP_PRINTDEVINFO; + break; + case OPT_PRINTSM2SIGN: + if (op) + goto opthelp; + op = OP_PRINTSM2SIGN; + key_idx = atoi(opt_arg()); + break; + case OPT_PRINTSM2ENC: + if (op) + goto opthelp; + op = OP_PRINTSM2ENC; + key_idx = atoi(opt_arg()); + break; + case OPT_PRINTRSASIGN: + if (op) + goto opthelp; + op = OP_PRINTRSASIGN; + key_idx = atoi(opt_arg()); + break; + case OPT_PRINTRSAENC: + if (op) + goto opthelp; + op = OP_PRINTRSAENC; + key_idx = atoi(opt_arg()); + break; + case OPT_ACCESSKEY: + key_idx = atoi(opt_arg()); + break; + case OPT_PASS: + passarg = opt_arg(); + break; + case OPT_IMPORTOBJ: + if (op) + goto opthelp; + op = OP_IMPORTOBJ; + objname = opt_arg(); + break; + case OPT_EXPORTOBJ: + if (op) + goto opthelp; + op = OP_EXPORTOBJ; + objname = opt_arg(); + break; + case OPT_DELOBJ: + if (op) + goto opthelp; + op = OP_DELOBJ; + objname = opt_arg(); + break; + case OPT_IN: + infile = opt_arg(); + break; + case OPT_OUT: + outfile = opt_arg(); + break; + } + } + argc = opt_num_rest(); + if (argc != 0) + goto opthelp; + + if (!lib) { + BIO_printf(bio_err, "Option '-lib' required\n"); +x509 goto opthelp; + } + if (SDF_LoadLibrary(lib, vendor) != SDR_OK) { + ERR_print_errors(bio_err); + goto end; + } + + if (op == OP_NONE) { + ret = 0; + goto end; + } + + if (SDF_OpenDevice(&hDev) != SDR_OK + || SDF_OpenSession(hDev, &hSession) != SDR_OK) { + ERR_print_errors(bio_err); + goto end; + } + + switch (op) { + case OP_PRINTDEVINFO: + case OP_PRINTSM2SIGN: + case OP_PRINTSM2ENC: + case OP_PRINTRSASIGN: + case OP_PRINTRSAENC: + if (!(out = bio_open_default(outfile, 'w', FORMAT_TEXT))) { + goto opthelp; + } + break; + } + + switch (op) { + case OP_PRINTSM2SIGN: + case OP_PRINTSM2ENC: + case OP_PRINTRSASIGN: + case OP_PRINTRSAENC: + case OP_ACCESSKEY: + if (key_idx < SDF_MIN_KEY_INDEX || key_idx > SDF_MAX_KEY_INDEX) { + BIO_printf(bio_err, "Invalid key index\n"); + goto end; + } + break; + } + + if (op == OP_PRINTDEVINFO) { + DEVICEINFO devInfo; + if (SDF_GetDeviceInfo(hSession, &devInfo) != SDR_OK + || SDF_PrintDeviceInfo(out, &devInfo) != SDR_OK) { + ERR_print_errors(bio_err); + goto end; + } + + } else if (op == OP_PRINTSM2SIGN || op == OP_PRINTSM2ENC) { + ECCrefPublicKey publicKey; + if (op == OP_PRINTSM2SIGN) { + if (SDF_ExportSignPublicKey_ECC(hSession, + key_idx, &publicKey) != SDR_OK) { + ERR_print_errors(bio_err); + goto end; + } + BIO_puts(out, "SM2 Signing Public Key:\n"); + } else { + if (SDF_ExportEncPublicKey_ECC(hSession, + key_idx, &publicKey) != SDR_OK) { + ERR_print_errors(bio_err); + goto end; + } + BIO_puts(out, "SM2 Encryption Public Key:\n"); + } + if (SDF_PrintECCPublicKey(out, &publicKey) != SDR_OK) { + ERR_print_errors(bio_err); + goto end; + } + + } else if (op == OP_PRINTRSASIGN || op == OP_PRINTRSAENC) { + RSArefPublicKey publicKey; + if (op == OP_PRINTRSASIGN) { + if (SDF_ExportSignPublicKey_RSA(hSession, + key_idx, &publicKey) != SDR_OK) { + ERR_print_errors(bio_err); + goto end; + } + BIO_puts(out, "RSA Signing Public Key:\n"); + } else { + if (SDF_ExportEncPublicKey_RSA(hSession, + key_idx, &publicKey) != SDR_OK) { + ERR_print_errors(bio_err); + goto end; + } + BIO_puts(out, "RSA Encryption Public Key:\n"); + } + if (SDF_PrintRSAPublicKey(out, &publicKey) != SDR_OK) { + ERR_print_errors(bio_err); + goto end; + } + + } else if (op == OP_ACCESSKEY) { + if (!app_passwd(passarg, NULL, &pass, NULL)) { + BIO_printf(bio_err, "Error getting password\n"); + goto end; + } + if (SDF_GetPrivateKeyAccessRight(hSession, (unsigned int)key_idx, + (unsigned char *)pass, strlen(pass)) != SDR_OK) { + OPENSSL_cleanse(pass, sizeof(pass)); + return 0; + } + (void)SDF_ReleasePrivateKeyAccessRight(hSession, (unsigned int)key_idx); + BIO_printf(bio_err, "Access private key %d success\n", key_idx); + + } else if (op == OP_IMPORTOBJ) { + if (!(in = bio_open_default(infile, 'r', FORMAT_BINARY))) { + goto opthelp; + } + if ((len = bio_to_mem(&buf, SDF_MAX_FILE_SIZE, in)) < 0) { + BIO_printf(bio_err, "Error reading data object content\n"); + goto end; + } + if (SDF_CreateFile(hSession, (unsigned char *)objname, strlen(objname), len) != SDR_OK + || SDF_WriteFile(hSession, (unsigned char *)objname, strlen(objname), 0, len, buf) != SDR_OK) { + ERR_print_errors(bio_err); + goto end; + } + BIO_printf(bio_err, "Object '%s' (%d bytes) created\n", objname, len); + + } else if (op == OP_EXPORTOBJ) { + if (!(out = bio_open_default(outfile, 'w', FORMAT_BINARY))) { + goto opthelp; + } + if (!(buf = OPENSSL_zalloc(SDF_MAX_FILE_SIZE)) + || SDF_ReadFile(hSession, (unsigned char *)objname, strlen(objname), 0, &ulen, buf) != SDR_OK + || BIO_write(out, buf, ulen) != ulen) { + ERR_print_errors(bio_err); + goto end; + } + BIO_printf(bio_err, "Object '%s' (%u bytes) exported\n", objname, ulen); + + } else if (op == OP_DELOBJ) { + if (SDF_DeleteFile(hSession, (unsigned char *)objname, strlen(objname)) != SDR_OK) { + ERR_print_errors(bio_err); + goto end; + } + BIO_printf(bio_err, "Object '%s' deleted\n", objname); + + } else { + goto end; + } + + ret = 0; + +end: + BIO_free(in); + BIO_free(out); + OPENSSL_free(buf); + OPENSSL_free(pass); + if (hSession) (void)SDF_CloseSession(hSession); + if (hDev) (void)SDF_CloseDevice(hDev); + if (lib) SDF_UnloadLibrary(); + return ret; +} diff --git a/tools/skfutil.c b/tools/skfutil.c new file mode 100644 index 00000000..2468dc12 --- /dev/null +++ b/tools/skfutil.c @@ -0,0 +1,1484 @@ +/* ==================================================================== + * Copyright (c) 2014 - 2019 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + * ==================================================================== + */ + +#include +#ifdef OPENSSL_NO_SKF +NON_EMPTY_TRANSLATION_UNIT +#else + +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include "apps.h" + + +# define OP_NONE 0 +# define OP_LISTDEVS 1 +# define OP_DEVINFO 2 +# define OP_NEWAUTHKEY 3 +# define OP_LABEL 4 +# define OP_TRANSMIT 5 +# define OP_LISTAPPS 6 +# define OP_NEWAPP 7 +# define OP_DELAPP 8 +# define OP_CHANGEPASS 9 +# define OP_UNBLOCK 10 +# define OP_LISTOBJS 11 +# define OP_IMPORTOBJ 12 +# define OP_EXPORTOBJ 13 +# define OP_DELOBJ 14 +# define OP_LISTCONTAINERS 15 +# define OP_NEWCONTAINER 16 +# define OP_DELCONTAINER 17 +# define OP_IMPORTENCKEY 18 +# define OP_EXPORTSIGNKEY 19 +# define OP_EXPORTENCKEY 20 +# define OP_PRINTKEYS 21 +# define OP_IMPORTCERT 22 +# define OP_EXPORTSIGNCERT 23 +# define OP_EXPORTENCCERT 24 + +typedef enum OPTION_choice { + OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, + OPT_LIB, OPT_VENDOR, OPT_LISTDEVS, OPT_DEV, OPT_DEVINFO, OPT_LABEL, + OPT_TRANSMIT, OPT_AUTHKEY, OPT_NEWAUTHKEY, OPT_LISTAPPS, OPT_NEWAPP, + OPT_DELAPP, OPT_APP, OPT_CHANGEPASS, OPT_PASS, OPT_ADMIN, OPT_ADMINPASS, + OPT_NEWPASS, OPT_UNBLOCK, OPT_LISTOBJS, OPT_IMPORTOBJ, OPT_EXPORTOBJ, + OPT_DELOBJ, OPT_OBJ, OPT_LISTCONTAINERS, OPT_NEWCONTAINER, OPT_ALGORITHM, + OPT_DELCONTAINER, OPT_CONTAINER, OPT_IMPORTENCKEY, OPT_KEYPASS, + OPT_EXPORTSIGNKEY, OPT_EXPORTENCKEY, OPT_PRINTKEYS, + OPT_IMPORTCERT, OPT_EXPORTSIGNCERT, OPT_EXPORTENCCERT, + OPT_IN, OPT_OUT, OPT_INFORM, OPT_OUTFORM, +} OPTION_CHOICE; + +OPTIONS skf_options[] = { + {"help", OPT_HELP, '-', "Display this summary"}, + {"lib", OPT_LIB, 's', "Vendor's SKF dynamic library"}, + {"vendor", OPT_VENDOR, 's', "Vendor name"}, + {"listdevs", OPT_LISTDEVS, '-', "List installed devices"}, + {"dev", OPT_DEV, 's', "Device name"}, + {"devinfo", OPT_DEVINFO, '-', "Print device information"}, + {"label", OPT_LABEL, 's', "Set new device label"}, + {"transmit", OPT_TRANSMIT, 's', "Transmit raw data packet"}, + {"authkey", OPT_AUTHKEY, 's', "Device authentication key in Hex"}, + {"newauthkey", OPT_NEWAUTHKEY, 's', "Set new device authentication key in Hex"}, + {"listapps", OPT_LISTAPPS, '-', "List applications"}, + {"newapp", OPT_NEWAPP, 's', "Create a new application with name"}, + {"delapp", OPT_DELAPP, 's', "Delete an applicaiton by name"}, + {"app", OPT_APP, 's', "Application name"}, + {"changepass", OPT_CHANGEPASS, '-', "Change application user or admin passw-phrase"}, + {"admin", OPT_ADMIN, '-', "Open application as administrator"}, + {"pass", OPT_PASS, 's', "Application user or admin pass-phrase source"}, + {"newpass", OPT_NEWPASS, 's', "Application user or admin new ass-phrase source"}, + {"adminpass", OPT_ADMINPASS, 's', "Application admin pass-phrase source"}, + {"unblock", OPT_UNBLOCK, '-', "Unblock application user pass-phrase"}, + {"listobjs", OPT_LISTOBJS, '-', "List data objects"}, + {"importobj", OPT_IMPORTOBJ, 's', "Import data object with name"}, + {"exportobj", OPT_EXPORTOBJ, 's', "Export data object by name"}, + {"delobj", OPT_DELOBJ, 's', "Delete data object by name"}, + {"obj", OPT_OBJ, 's', "Data object name"}, + {"listcontainers", OPT_LISTCONTAINERS, '-', "List containers"}, + {"newcontainer", OPT_NEWCONTAINER, 's', "Create container with name"}, + {"algorithm", OPT_ALGORITHM, 's', "Container public key algorithm - SM2 or RSA"}, + {"delcontainer", OPT_DELCONTAINER, 's', "Delete container by name"}, + {"container", OPT_CONTAINER, 's', "Container name"}, + {"importenckey", OPT_IMPORTENCKEY, '-', "Import encryption private key into container"}, + {"keypass", OPT_KEYPASS, 's', "Private key encryption pass-phrase"}, + {"exportsignkey", OPT_EXPORTSIGNKEY, '-', "Export signing public key from container"}, + {"exportenckey", OPT_EXPORTENCKEY, '-', "Export encryption public key from container"}, + {"printkeys", OPT_PRINTKEYS, '-', "Print public keys in container"}, + {"importcert", OPT_IMPORTCERT, '-', "Import certificate into container"}, + {"exportsigncert", OPT_EXPORTSIGNCERT, '-', "Export signing certificate from container"}, + {"exportenccert", OPT_EXPORTENCCERT, '-', "Export encryption certificate from container"}, + {"in", OPT_IN, '<', "File to be imported from"}, + {"out", OPT_OUT, '>', "File to be exported to"}, + {"inform", OPT_INFORM, 'f', "Input format - DER or PEM"}, + {"outform", OPT_OUTFORM, 'F', "Output format - DER or PEM"}, + {NULL} +}; + +static int skf_listdevs(BIO *out) +{ + int ret = 0; + BOOL bPresent = TRUE; + char *nameList = NULL; + ULONG nameListLen; + const char *name; + int i; + + if (SKF_EnumDev(bPresent, NULL, &nameListLen) != SAR_OK + || !(nameList = OPENSSL_zalloc(nameListLen)) + || SKF_EnumDev(bPresent, (LPSTR)nameList, &nameListLen) != SAR_OK) { + ERR_print_errors(bio_err); + goto end; + } + for (name = nameList, i = 0; *name; name += strlen(name) + 1, i++) { + (void)BIO_printf(out, " Device %d : %s\n", i, name); + } + + ret = 1; +end: + OPENSSL_free(nameList); + return ret; +} + +static int skf_devinfo(const char *devname, BIO *out) +{ + int ret = 0; + DEVHANDLE hDev = NULL; + ULONG devState; + LPSTR devStateName; + DEVINFO devInfo = {{0,0}}; + + if (SKF_GetDevState((LPSTR)devname, &devState) != SAR_OK + || SKF_GetDevStateName(devState, &devStateName) != SAR_OK + || SKF_ConnectDev((LPSTR)devname, &hDev) != SAR_OK + || SKF_GetDevInfo(hDev, &devInfo) != SAR_OK) { + ERR_print_errors(bio_err); + goto end; + } + + (void)BIO_printf(out, "Device %s :\n", devname); + (void)BIO_printf(out, " %-16s : %s\n", "Device State", (char *)devStateName); + (void)SKF_PrintDevInfo(out, &devInfo); + (void)BIO_puts(out, "\n"); + ret = 1; + +end: + if (hDev && SKF_DisConnectDev(hDev) != SAR_OK) { + ERR_print_errors(bio_err); + ret = 0; + } + return ret; +} + +static int skf_label(const char *devname, const char *label) +{ + int ret = 0; + DEVHANDLE hDev = NULL; + ULONG ulTimeOut = 0xffffffff; + + if (SKF_ConnectDev((LPSTR)devname, &hDev) != SAR_OK + || SKF_LockDev(hDev, ulTimeOut) != SAR_OK + || SKF_SetLabel(hDev, (LPSTR)label) != SAR_OK) { + ERR_print_errors(bio_err); + goto end; + } + ret = 1; +end: + if (hDev && SKF_DisConnectDev(hDev) != SAR_OK) { + ERR_print_errors(bio_err); + ret = 0; + } + return ret; +} + +static int skf_transmit(const char *devName, const char *cmd, BIO *out) +{ + int ret = 0; + BYTE *inbuf = NULL; + long inlen; + DEVHANDLE hDev = NULL; + BYTE outbuf[256]; + ULONG outlen = sizeof(outbuf); + + if (!(inbuf = OPENSSL_hexstr2buf(cmd, &inlen)) + || SKF_ConnectDev((LPSTR)devName, &hDev) != SAR_OK + || SKF_Transmit(hDev, inbuf, (ULONG)inlen, outbuf, &outlen) != SAR_OK + || BIO_write(out, outbuf, (int)outlen) != outlen) { + ERR_print_errors(bio_err); + goto end; + } + ret = 1; +end: + OPENSSL_free(inbuf); + if (hDev && SKF_DisConnectDev(hDev) != SAR_OK) { + ERR_print_errors(bio_err); + ret = 0; + } + return ret; +} + +static int skf_opendev(const char *devname, const char *authkeyhex, + DEVINFO *devInfo, DEVHANDLE *phDev) +{ + int ret = 0; + unsigned char *authKey = NULL; + long len; + + if (!(authKey = OPENSSL_hexstr2buf(authkeyhex, &len))) { + BIO_printf(bio_err, "Error on parsing authentication key\n"); + ERR_print_errors(bio_err); + return 0; + } + if (len != 16) { + BIO_printf(bio_err, "Invlaid authentication key length\n"); + goto end; + } + if (SKF_OpenDevice((LPSTR)devname, authKey, devInfo, phDev) != SAR_OK) { + BIO_printf(bio_err, "Error on opening device\n"); + ERR_print_errors(bio_err); + goto end; + } + ret = 1; + +end: + OPENSSL_clear_free(authKey, len); + return ret; +} + +static int skf_newauthkey(DEVHANDLE hDev, const char *authkeyhex) +{ + int ret = 0; + unsigned char *authKey = NULL; + long len; + + if (!(authKey = OPENSSL_hexstr2buf(authkeyhex, &len))) { + BIO_printf(bio_err, "Error on parsing new authentication key\n"); + ERR_print_errors(bio_err); + return 0; + } + if (len != 16) { + BIO_printf(bio_err, "Invalid new authentication key legnth\n"); + goto end; + } + if (SKF_ChangeDevAuthKey(hDev, authKey, len) != SAR_OK) { + BIO_printf(bio_err, "Error on changing authentication key\n"); + ERR_print_errors(bio_err); + goto end; + } + ret = 1; + +end: + OPENSSL_clear_free(authKey, len); + return ret; +} + +static int skf_listapps(DEVHANDLE hDev, BIO *out) +{ + int ret = 0; + HAPPLICATION hApp = NULL; + char *nameList = NULL; + ULONG nameListLen; + const char *name; + int i; + + if (SKF_EnumApplication(hDev, NULL, &nameListLen) != SAR_OK) { + ERR_print_errors(bio_err); + return 0; + } + if (nameListLen <= 1) { + BIO_printf(out, "No application found\n"); + return 1; + } + if (!(nameList = OPENSSL_zalloc(nameListLen))) { + ERR_print_errors(bio_err); + return 0; + } + if (SKF_EnumApplication(hDev, (LPSTR)nameList, &nameListLen) != SAR_OK) { + ERR_print_errors(bio_err); + goto end; + } + + for (name = nameList, i = 0; *name; name += strlen(name) + 1, i++) { + ULONG adminMaxRetry; + ULONG adminMinRetry; + ULONG userMaxRetry; + ULONG userMinRetry; + BOOL adminDefaultPin, userDefaultPin; + + if (SKF_OpenApplication(hDev, (LPSTR)name, &hApp) != SAR_OK) { + ERR_print_errors(bio_err); + goto end; + } + + if (SKF_GetPINInfo(hApp, ADMIN_TYPE, &adminMaxRetry, + &adminMinRetry, &adminDefaultPin) != SAR_OK) { + ERR_print_errors(bio_err); + goto end; + } + if (SKF_GetPINInfo(hApp, USER_TYPE, &userMaxRetry, + &userMinRetry, &userDefaultPin) != SAR_OK) { + ERR_print_errors(bio_err); + goto end; + } + if (SKF_CloseApplication(hApp) != SAR_OK) { + ERR_print_errors(bio_err); + goto end; + } + hApp = NULL; + + (void)BIO_printf(out, "Application %d:\n", i); + (void)BIO_printf(out, " %-16s : %s\n", "ApplicationName", name); + (void)BIO_printf(out, " %-16s : %u\n", "AdminPinMaxRetry", adminMaxRetry); + (void)BIO_printf(out, " %-16s : %u\n", "AdminPinMinRetry", adminMinRetry); + (void)BIO_printf(out, " %-16s : %s\n", "AdminDefaultPin", adminDefaultPin ? "True" : "False"); + (void)BIO_printf(out, " %-16s : %u\n", "UserPinMaxRetry", userMaxRetry); + (void)BIO_printf(out, " %-16s : %u\n", "UserPinMinRetry", userMinRetry); + (void)BIO_printf(out, " %-16s : %s\n", "UserDefaultPin", userDefaultPin ? "True" : "False"); + (void)BIO_puts(out, "\n"); + } + + ret = 1; + +end: + if (hApp && SKF_CloseApplication(hApp) != SAR_OK) { + ERR_print_errors(bio_err); + ret = 0; + } + return ret; +} + +static int skf_newapp(DEVHANDLE hDev, const char *appname, const char *pass, const char *adminpass) +{ + int ret = 0; + CHAR *szAdminPin = NULL; + CHAR *szUserPin = NULL; + HAPPLICATION hApp = NULL; + ULONG skf_app_rights = SECURE_ANYONE_ACCOUNT; + + if (!app_passwd(pass, adminpass, (char **)&szUserPin, (char **)&szAdminPin)) { + BIO_printf(bio_err, "No application found\n"); + goto end; + } + + if (!pass) { + int len = 64; + if (!(szUserPin = OPENSSL_zalloc(len)) + || EVP_read_pw_string((char *)szUserPin, len, "User PIN > ", 1) < 0) { + ERR_print_errors(bio_err); + goto end; + } + } + + if (!adminpass) { + int len = 64; + if (!(szAdminPin = OPENSSL_zalloc(len)) + || EVP_read_pw_string((char *)szAdminPin, len, "Admin PIN > ", 1) < 0) { + ERR_print_errors(bio_err); + goto end; + } + } + + if (SKF_CreateApplication(hDev, (LPSTR)appname, + szAdminPin, SKF_DEFAULT_ADMIN_PIN_RETRY_COUNT, + szUserPin, SKF_DEFAULT_USER_PIN_RETRY_COUNT, + skf_app_rights, &hApp) != SAR_OK) { + ERR_print_errors(bio_err); + goto end; + } + + BIO_printf(bio_err, "Application '%s' created\n", appname); + ret = 1; + +end: + OPENSSL_clear_free(szUserPin, strlen((char *)szUserPin)); + OPENSSL_clear_free(szAdminPin, strlen((char *)szAdminPin)); + if (hApp && SKF_CloseApplication(hApp) != SAR_OK) { + ERR_print_errors(bio_err); + ret = 0; + } + return ret; +} + +static int skf_delapp(DEVHANDLE hDev, const char *appname) +{ + if (SKF_DeleteApplication(hDev, (LPSTR)appname) != SAR_OK) { + ERR_print_errors(bio_err); + return 0; + } + return 1; +} + +static int skf_changepass(DEVHANDLE hDev, const char *appname, + int admin, const char *pass, const char *newpass) +{ + int ret = 0; + HAPPLICATION hApp = NULL; + ULONG ulPINType = admin ? ADMIN_TYPE : USER_TYPE; + CHAR *szOldPin = NULL; + CHAR *szNewPin = NULL; + ULONG ulRetryCount = 0; + + if (SKF_OpenApplication(hDev, (LPSTR)appname, &hApp) != SAR_OK) { + ERR_print_errors(bio_err); + goto end; + } + + if (!pass || !newpass) { + int len = 64; + if (!(szOldPin = OPENSSL_zalloc(len)) + || !(szNewPin = OPENSSL_zalloc(len)) + || EVP_read_pw_string((char *)szOldPin, len, "Old PIN > ", 0) < 0 + || EVP_read_pw_string((char *)szNewPin, len, "New PIN > ", 0) < 0) { + ERR_print_errors(bio_err); + goto end; + } + } + + if (!app_passwd(pass, newpass, (char **)&szOldPin, (char **)&szNewPin)) { + BIO_puts(bio_err, "Error getting password\n"); + return 0; + } + + if (SKF_ChangePIN(hApp, ulPINType, szOldPin, szNewPin, + &ulRetryCount) != SAR_OK) { + BIO_printf(bio_err, "Retry Count = %u\n", ulRetryCount); + ERR_print_errors(bio_err); + goto end; + } + + ret = 1; +end: + OPENSSL_clear_free(szOldPin, sizeof(szOldPin)); + OPENSSL_clear_free(szNewPin, sizeof(szNewPin)); + if (hApp && SKF_CloseApplication(hApp) != SAR_OK) { + ERR_print_errors(bio_err); + ret = 0; + } + return ret; +} + +static int skf_unblock(DEVHANDLE hDev, const char *appname, + const char *adminpassarg, const char *userpassarg) +{ + int ret = 0; + HAPPLICATION hApp = NULL; + CHAR *szAdminPin = NULL; + CHAR *szNewUserPin = NULL; + ULONG ulRetryCount = 0; + + if (SKF_OpenApplication(hDev, (LPSTR)appname, &hApp) != SAR_OK) { + ERR_print_errors(bio_err); + return 0; + } + if (!adminpassarg) { + int len = 64; + if (!(szAdminPin = OPENSSL_zalloc(len)) + || EVP_read_pw_string((char *)szAdminPin, len, "Admin PIN > ", 0) < 0) { + ERR_print_errors(bio_err); + goto end; + } + } else { + if (!app_passwd(adminpassarg, NULL, (char **)&szAdminPin, NULL)) { + BIO_puts(bio_err, "Error getting password\n"); + goto end; + } + } + + if (!userpassarg) { + int len = 64; + if (!(szNewUserPin = OPENSSL_zalloc(len)) + || EVP_read_pw_string((char *)szNewUserPin, len, "New User PIN > ", 0) < 0) { + ERR_print_errors(bio_err); + goto end; + } + } else { + if (!app_passwd(userpassarg, NULL, (char **)&szNewUserPin, NULL)) { + BIO_puts(bio_err, "Error getting password\n"); + goto end; + } + } + + if (SKF_UnblockPIN(hApp, szAdminPin, szNewUserPin, &ulRetryCount) != SAR_OK) { + BIO_printf(bio_err, "Invalid admin PIN, retry count = %u\n", ulRetryCount); + ERR_print_errors(bio_err); + goto end; + } + ret = 1; +end: + OPENSSL_clear_free(szAdminPin, strlen((char *)szAdminPin)); + OPENSSL_clear_free(szNewUserPin, strlen((char *)szNewUserPin)); + if (hApp && SKF_CloseApplication(hApp) != SAR_OK) { + ERR_print_errors(bio_err); + ret = 0; + } + return ret; +} + +static int skf_openapp(DEVHANDLE hDev, const char *name, int admin, + const char *passarg, HAPPLICATION *phApp) +{ + int ret = 0; + HAPPLICATION hApp = NULL; + CHAR *szPin = NULL; + ULONG numRetry; + ULONG user_type = admin ? ADMIN_TYPE : USER_TYPE; + + if (SKF_OpenApplication(hDev, (LPSTR)name, &hApp) != SAR_OK) { + ERR_print_errors(bio_err); + return 0; + } + + if (passarg) { + if (!app_passwd(passarg, NULL, (char **)&szPin, NULL)) { + BIO_printf(bio_err, "Error on reading password\n"); + goto end; + } + } else { + int len = 64; + if (!(szPin = OPENSSL_zalloc(len)) + || EVP_read_pw_string((char *)szPin, len, "PIN >", 0) < 0) { + ERR_print_errors(bio_err); + goto end; + } + } + + if (SKF_VerifyPIN(hApp, user_type, szPin, &numRetry) != SAR_OK) { + BIO_printf(bio_err, "Invalid %s PIN, retry count = %u\n", + admin ? "admin" : "user", numRetry); + ERR_print_errors(bio_err); + goto end; + } + *phApp = hApp; + hApp = NULL; + ret = 1; + +end: + + OPENSSL_clear_free(szPin, strlen((char *)szPin)); + if (hApp && SKF_CloseApplication(hApp) != SAR_OK) { + ERR_print_errors(bio_err); + ret = 0; + } + return ret; +} + +static int skf_listobjs(HAPPLICATION hApp, BIO *out) +{ + int ret = 0; + char *nameList = NULL; + ULONG nameListLen; + const char *name; + int i; + + if (SKF_EnumFiles(hApp, NULL, &nameListLen) != SAR_OK) { + ERR_print_errors(bio_err); + return 0; + } + + if (!(nameList = OPENSSL_malloc(nameListLen))) { + ERR_print_errors(bio_err); + return 0; + } + + if (SKF_EnumFiles(hApp, (LPSTR)nameList, &nameListLen) != SAR_OK) { + ERR_print_errors(bio_err); + goto end; + } + + for (name = nameList, i = 0; *name; name += strlen(name) + 1, i++) { + FILEATTRIBUTE fileInfo; + + if (SKF_GetFileInfo(hApp, (LPSTR)name, &fileInfo) != SAR_OK) { + ERR_print_errors(bio_err); + goto end; + } + + BIO_printf(out, "Object %d:\n", i); + BIO_printf(out, " %-16s : %s\n", "Object Name", (char *)&(fileInfo.FileName)); + BIO_printf(out, " %-16s : %u\n", "Object Size", fileInfo.FileSize); + BIO_printf(out, " %-16s : %08X\n", "Read Rights", fileInfo.ReadRights); + BIO_printf(out, " %-16s : %08X\n", "Write Rights", fileInfo.WriteRights); + BIO_puts(out, "\n"); + } + + ret = 1; + +end: + OPENSSL_free(nameList); + return ret; +} + +static int skf_importobj(HAPPLICATION happ, const char *objname, int admin, const char *infile) +{ + int ret = 0; + BIO *in = NULL; + ULONG ulReadRights = SECURE_ANYONE_ACCOUNT; + ULONG ulWriteRights = SECURE_USER_ACCOUNT; + unsigned char *buf = NULL; + int len = SKF_MAX_FILE_SIZE; + + if (admin) { + ulWriteRights = SECURE_ADM_ACCOUNT; + } + + if (!(in = bio_open_default(infile, 'r', FORMAT_BINARY))) { + goto end; + } + if ((len = bio_to_mem(&buf, SKF_MAX_FILE_SIZE, in)) <= 0) { + goto end; + } + + if (SKF_CreateFile(happ, (LPSTR)objname, len, + ulReadRights, ulWriteRights) != SAR_OK) { + ERR_print_errors(bio_err); + goto end; + } + + if (SKF_WriteFile(happ, (LPSTR)objname, 0, buf, len) != SAR_OK) { + ERR_print_errors(bio_err); + goto end; + } + + BIO_printf(bio_err, "Object '%s' (%u bytes) created\n", objname, len); + ret = 1; + +end: + OPENSSL_free(buf); + return ret; +} + +static int skf_exportobj(HAPPLICATION hApp, const char *objname, BIO *out) +{ + int ret = 0; + FILEATTRIBUTE fileInfo; + unsigned char *buf = NULL; + ULONG ulen = SKF_MAX_FILE_SIZE; + int len; + + if (SKF_GetFileInfo(hApp, (LPSTR)objname, &fileInfo) != SAR_OK + || !(buf = OPENSSL_malloc(fileInfo.FileSize)) + || SKF_ReadFile(hApp, (LPSTR)objname, 0, fileInfo.FileSize, buf, &ulen) != SAR_OK) { + ERR_print_errors(bio_err); + goto end; + } + + if (ulen != fileInfo.FileSize) { + BIO_printf(bio_err, "Error on reading object\n"); + goto end; + } + + if ((len = BIO_write(out, buf, (int)ulen)) != (int)ulen) { + ERR_print_errors(bio_err); + goto end; + } + (void)BIO_printf(bio_err, "%d bytes exportd\n", len); + + ret = 1; + +end: + OPENSSL_free(buf); + return ret; +} + +static int skf_delobj(HAPPLICATION hApp, const char *objname) +{ + if (SKF_DeleteFile(hApp, (LPSTR)objname) != SAR_OK) { + ERR_print_errors(bio_err); + return 0; + } + return 1; +} + +static int skf_listcontainers(HAPPLICATION hApp, BIO *out) +{ + int ret = 0; + HCONTAINER hContainer = NULL; + char *nameList = NULL; + ULONG nameListLen; + const char *name; + int i; + + if (SKF_EnumContainer(hApp, NULL, &nameListLen) != SAR_OK) { + ERR_print_errors(bio_err); + return 0; + } + if (!nameListLen) { + (void)BIO_puts(bio_err, "No container found\n"); + return 1; + } + if (!(nameList = OPENSSL_malloc(nameListLen))) { + ERR_print_errors(bio_err); + return 0; + } + if (SKF_EnumContainer(hApp, (LPSTR)nameList, &nameListLen) != SAR_OK) { + ERR_print_errors(bio_err); + goto end; + } + + for (name = nameList, i = 0; *name; name += strlen(name) + 1, i++) { + ULONG containerType; + LPSTR containerTypeName; + + if (SKF_OpenContainer(hApp, (LPSTR)name, &hContainer) != SAR_OK) { + ERR_print_errors(bio_err); + goto end; + } + if (SKF_GetContainerType(hContainer, &containerType) != SAR_OK) { + ERR_print_errors(bio_err); + goto end; + } + if (SKF_GetContainerTypeName(containerType, &containerTypeName) != SAR_OK) { + ERR_print_errors(bio_err); + goto end; + } + if (SKF_CloseContainer(hContainer) != SAR_OK) { + ERR_print_errors(bio_err); + goto end; + } + hContainer = NULL; + + (void)BIO_printf(out, " Container %d : %s (%s)\n", + i, name, (char *)containerTypeName); + } + + ret = 1; + +end: + if (hContainer && SKF_CloseContainer(hContainer) != SAR_OK) { + ERR_print_errors(bio_err); + ret = 0; + } + return ret; +} + +static int skf_newcontainer(HAPPLICATION hApp, const char *name, const char *algor) +{ + int ret = 0; + HCONTAINER hContainer = NULL; + + if (SKF_CreateContainer(hApp, (LPSTR)name, &hContainer) != SAR_OK) { + ERR_print_errors(bio_err); + return 0; + } + (void)BIO_printf(bio_err, "Container '%s' created\n", name); + + if (strcmp(algor, "SM2") == 0 || strcmp(algor, "sm2") == 0) { + ECCPUBLICKEYBLOB publicKey = {0, {0}, {0}}; + if (SKF_GenECCKeyPair(hContainer, SGD_SM2_1, &publicKey) != SAR_OK) { + ERR_print_errors(bio_err); + goto end; + } + + (void)BIO_printf(bio_err, "SM2 signing key pair generated\n"); + (void)BIO_printf(bio_err, "SM2 Signing Public Key:\n"); + if (SKF_PrintECCPublicKey(bio_err, &publicKey) != SAR_OK) { + ERR_print_errors(bio_err); + goto end; + } + + } else if (strcmp(algor, "RSA") == 0 || strcmp(algor, "rsa")) { + RSAPUBLICKEYBLOB publicKey = {0, 0, {0}, {0}}; + if (SKF_GenRSAKeyPair(hContainer, SGD_RSA, &publicKey) != SAR_OK) { + ERR_print_errors(bio_err); + goto end; + } + + (void)BIO_printf(bio_err, "RSA signing key pair generated\n"); + (void)BIO_printf(bio_err, "RSA Signing Public Key:\n"); + if (SKF_PrintRSAPublicKey(bio_err, &publicKey) != SAR_OK) { + ERR_print_errors(bio_err); + goto end; + } + + } else { + (void)BIO_printf(bio_err, "Invalid container type\n"); + goto end; + } + + ret = 1; + +end: + if (hContainer && SKF_CloseContainer(hContainer) != SAR_OK) { + ERR_print_errors(bio_err); + ret = 0; + } + return ret; +} + +static int skf_delcontainer(HAPPLICATION hApp, const char *containername) +{ + if (SKF_DeleteContainer(hApp, (LPSTR)containername) != SAR_OK) { + ERR_print_errors(bio_err); + return 0; + } + return 1; +} + +static int skf_importenckey(DEVHANDLE hDev, HCONTAINER hContainer, DEVINFO *devInfo, + const char *infile, int informat, const char *passarg) +{ + int ret = 0; + EVP_PKEY *pkey = NULL; + + if (!(pkey = load_key(infile, informat, 0, passarg, NULL, "Private Key"))) { + BIO_printf(bio_err, "Error on reading private key\n"); + return 0; + } + if (SKF_ImportPrivateKey(hDev, hContainer, pkey, devInfo->DevAuthAlgId) != SAR_OK) { + BIO_printf(bio_err, "Error on importing private key\n"); + ERR_print_errors(bio_err); + goto end; + } + ret = 1; +end: + EVP_PKEY_free(pkey); + return ret; +} + +static int skf_exportkey(HCONTAINER hContainer, BOOL bSign, int outformat, BIO *out) +{ + int ret = 0; + EVP_PKEY *pkey = NULL; + + if (SKF_ExportEVPPublicKey(hContainer, bSign, &pkey) != SAR_OK) { + BIO_printf(bio_err, "Error on exporting public key\n"); + ERR_print_errors(bio_err); + return 0; + } + + if (outformat == FORMAT_ASN1) + ret = i2d_PUBKEY_bio(out, pkey); + else if (outformat == FORMAT_PEM) + ret = PEM_write_bio_PUBKEY(out, pkey); + else { + BIO_printf(bio_err, "bad output format specified for outfile\n"); + goto end; + } + if (!ret) { + BIO_printf(bio_err, "Unable to write certificate\n"); + ERR_print_errors(bio_err); + goto end; + } + +end: + EVP_PKEY_free(pkey); + return ret; +} + +static int skf_printkeys(HCONTAINER hContainer, BIO *out) +{ + int ret = 1; + ULONG containerType; + SKF_PUBLICKEYBLOB publicKey; + ULONG len = sizeof(SKF_PUBLICKEYBLOB); + + if (SKF_GetContainerType(hContainer, &containerType) != SAR_OK) { + ERR_print_errors(bio_err); + return 0; + } + if (containerType == SKF_CONTAINER_TYPE_UNDEF) { + BIO_printf(bio_err, "Container not initialized\n"); + return 0; + } + + memset(&publicKey, 0, sizeof(publicKey)); + if (SKF_ExportPublicKey(hContainer, SGD_TRUE, (BYTE *)&publicKey, &len) == SAR_OK) { + if (containerType == SKF_CONTAINER_TYPE_ECC) { + BIO_puts(out, "SM2 signing public key:\n"); + if (SKF_PrintECCPublicKey(out, + (ECCPUBLICKEYBLOB *)&publicKey) != SAR_OK) { + ERR_print_errors(bio_err); + ret = 0; + } + } else { + BIO_puts(out, "RSA signing public key:\n"); + if (SKF_PrintRSAPublicKey(out, + (RSAPUBLICKEYBLOB *)&publicKey) != SAR_OK) { + ERR_print_errors(bio_err); + ret = 0; + } + } + } else { + ERR_print_errors(bio_err); + ret = 0; + } + + memset(&publicKey, 0, sizeof(publicKey)); + if (SKF_ExportPublicKey(hContainer, SGD_FALSE, (BYTE *)&publicKey, &len) == SAR_OK) { + if (containerType == SKF_CONTAINER_TYPE_ECC) { + BIO_puts(out, "SM2 encryption public key:\n"); + if (SKF_PrintECCPublicKey(out, + (ECCPUBLICKEYBLOB *)&publicKey) != SAR_OK) { + ERR_print_errors(bio_err); + ret = 0; + } + } else { + BIO_puts(out, "RSA encryption public key:\n"); + if (SKF_PrintRSAPublicKey(out, + (RSAPUBLICKEYBLOB *)&publicKey) != SAR_OK) { + ERR_print_errors(bio_err); + ret = 0; + } + } + } else { + ERR_print_errors(bio_err); + ret = 0; + } + + return ret; +} + +static int skf_importcert(HCONTAINER hContainer, const char *infile, int informat) +{ + int ret = 0; + X509 *x509 = NULL; + + if (!(x509 = load_cert(infile, informat, "Certificate"))) { + BIO_printf(bio_err, "Load certificate failure\n"); + ERR_print_errors(bio_err); + return 0; + } + if (SKF_ImportX509CertificateByKeyUsage(hContainer, x509) != SAR_OK) { + BIO_printf(bio_err, "Error on importing certificate\n"); + ERR_print_errors(bio_err); + goto end; + } + ret = 1; + +end: + X509_free(x509); + return ret; +} + +static int skf_exportcert(HCONTAINER hContainer, BOOL bSign, int outform, BIO *out) +{ + int ret = 0; + X509 *x509 = NULL; + + if (SKF_ExportX509Certificate(hContainer, bSign, &x509) != SAR_OK) { + BIO_printf(bio_err, "Error on exporing certificate\n"); + ERR_print_errors(bio_err); + return 0; + } + if (outform == FORMAT_ASN1) + ret = i2d_X509_bio(out, x509); + else if (outform == FORMAT_PEM) + ret = PEM_write_bio_X509(out, x509); + else { + BIO_printf(bio_err, "bad output format specified for outfile\n"); + goto end; + } + if (!ret) { + BIO_printf(bio_err, "Unable to write certificate\n"); + ERR_print_errors(bio_err); + goto end; + } + ret = 1; + +end: + X509_free(x509); + return ret; +} + +int skf_main(int argc, char **argv) +{ + int ret = 0; + char *infile = NULL, *outfile = NULL, *prog; + BIO *out = NULL; + OPTION_CHOICE o; + int informat = FORMAT_PEM, outformat = FORMAT_UNDEF; + char *lib = NULL, *vendor = NULL, *label = NULL; + char *authkey = NULL, *newauthkey = NULL; + char *devname = NULL, *appname = NULL, *containername = NULL, *objname = NULL; + char *passarg = NULL, *adminpassarg = NULL, *newpassarg = NULL; + char *keypassarg = NULL; + + int op = OP_NONE; + int admin = 0; + char *algor = "SM2"; + + char *transmit_cmd = NULL; + + DEVINFO devInfo = {{0,0}}; + DEVHANDLE hdev = NULL; + HAPPLICATION happ = NULL; + HCONTAINER hcontainer = NULL; + + prog = opt_init(argc, argv, skf_options); + while ((o = opt_next()) != OPT_EOF) { + switch (o) { + case OPT_EOF: + case OPT_ERR: +opthelp: + BIO_printf(bio_err, "%s: Use -help for summary.\n", prog); + goto end; + case OPT_HELP: + opt_help(skf_options); + ret = 0; + goto end; + case OPT_LIB: + lib = opt_arg(); + break; + case OPT_VENDOR: + vendor = opt_arg(); + break; + case OPT_LISTDEVS: + if (op) + goto opthelp; + op = OP_LISTDEVS; + break; + case OPT_DEV: + devname = opt_arg(); + break; + case OPT_DEVINFO: + if (op) + goto opthelp; + op = OP_DEVINFO; + break; + case OPT_LABEL: + if (op) + goto opthelp; + op = OP_LABEL; + label = opt_arg(); + break; + case OPT_AUTHKEY: + authkey = opt_arg(); + break; + case OPT_NEWAUTHKEY: + if (op) + goto opthelp; + op = OP_NEWAUTHKEY; + newauthkey = opt_arg(); + break; + case OPT_TRANSMIT: + if (op) + goto opthelp; + op = OP_TRANSMIT; + transmit_cmd = opt_arg(); + break; + case OPT_LISTAPPS: + if (op) + goto opthelp; + op = OP_LISTAPPS; + break; + case OPT_NEWAPP: + if (op) + goto opthelp; + op = OP_NEWAPP; + appname = opt_arg(); + break; + case OPT_DELAPP: + if (op) + goto opthelp; + op = OP_DELAPP; + appname = opt_arg(); + break; + case OPT_APP: + appname = opt_arg(); + break; + case OPT_CHANGEPASS: + if (op) + goto opthelp; + op = OP_CHANGEPASS; + break; + case OPT_PASS: + passarg = opt_arg(); + break; + case OPT_ADMIN: + admin = 1; + break; + case OPT_ADMINPASS: + adminpassarg = opt_arg(); + break; + case OPT_NEWPASS: + newpassarg = opt_arg(); + break; + case OPT_UNBLOCK: + if (op) + goto opthelp; + op = OP_UNBLOCK; + break; + case OPT_LISTOBJS: + if (op) + goto opthelp; + op = OP_LISTOBJS; + break; + case OPT_IMPORTOBJ: + if (op) + goto opthelp; + op = OP_IMPORTOBJ; + objname = opt_arg(); + break; + case OPT_EXPORTOBJ: + if (op) + goto opthelp; + op = OP_EXPORTOBJ; + objname = opt_arg(); + break; + case OPT_DELOBJ: + if (op) + goto opthelp; + op = OP_DELOBJ; + objname = opt_arg(); + break; + case OPT_OBJ: + objname = opt_arg(); + break; + case OPT_LISTCONTAINERS: + if (op) + goto opthelp; + op = OP_LISTCONTAINERS; + break; + case OPT_NEWCONTAINER: + if (op) + goto opthelp; + op = OP_NEWCONTAINER; + containername = opt_arg(); + break; + case OPT_ALGORITHM: + algor = opt_arg(); + break; + case OPT_DELCONTAINER: + if (op) + goto opthelp; + op = OP_DELCONTAINER; + containername = opt_arg(); + break; + case OPT_CONTAINER: + containername = opt_arg(); + break; + case OPT_IMPORTENCKEY: + if (op) + goto opthelp; + op = OP_IMPORTENCKEY; + break; + case OPT_KEYPASS: + keypassarg = opt_arg(); + break; + case OPT_EXPORTSIGNKEY: + if (op) + goto opthelp; + op = OP_EXPORTSIGNKEY; + break; + case OPT_EXPORTENCKEY: + if (op) + goto opthelp; + op = OP_EXPORTENCKEY; + break; + case OPT_PRINTKEYS: + if (op) + goto opthelp; + op = OP_PRINTKEYS; + break; + case OPT_IMPORTCERT: + if (op) + goto opthelp; + op = OP_IMPORTCERT; + break; + case OPT_EXPORTSIGNCERT: + if (op) + goto opthelp; + op = OP_EXPORTSIGNCERT; + break; + case OPT_EXPORTENCCERT: + if (op) + goto opthelp; + op = OP_EXPORTENCCERT; + break; + case OPT_IN: + infile = opt_arg(); + break; + case OPT_OUT: + outfile = opt_arg(); + break; + case OPT_INFORM: + if (!opt_format(opt_arg(), OPT_FMT_ANY, &informat)) + goto opthelp; + break; + case OPT_OUTFORM: + if (!opt_format(opt_arg(), OPT_FMT_ANY, &outformat)) + goto opthelp; + break; + } + } + argc = opt_num_rest(); + if (argc != 0) + goto opthelp; + + if (!lib) { + BIO_printf(bio_err, "Option `-lib' not specified\n"); + goto opthelp; + } + if (SKF_LoadLibrary((LPSTR)lib, (LPSTR)vendor) != SAR_OK) { + ERR_print_errors(bio_err); + goto end; + } + + /* prepare output bio */ + switch (op) { + case OP_LISTDEVS: + case OP_DEVINFO: + case OP_LISTAPPS: + case OP_LISTOBJS: + case OP_LISTCONTAINERS: + case OP_PRINTKEYS: + if (outformat == FORMAT_UNDEF) { + outformat = FORMAT_TEXT; + } + if (outformat != FORMAT_TEXT) { + BIO_printf(bio_err, "Invalid outform option\n"); + goto opthelp; + } + break; + case OP_EXPORTOBJ: + if (outformat == FORMAT_UNDEF) + outformat = FORMAT_BINARY; + if (outformat != FORMAT_BINARY) { + BIO_printf(bio_err, "Invalid outform option\n"); + goto opthelp; + } + break; + default: + if (outformat != FORMAT_UNDEF) { + BIO_printf(bio_err, "Invalid outform option\n"); + goto opthelp; + } + } + if (!(out = bio_open_default(outfile, 'w', outformat))) { + goto end; + } + + /* without devname */ + switch (op) { + case OP_NONE: + ret = 1; + goto end; + case OP_LISTDEVS: + ret = skf_listdevs(out); + goto end; + } + + /* without opendev */ + if (!devname) { + BIO_printf(bio_err, "Error: `-dev` not specified\n"); + goto opthelp; + } + + switch (op) { + case OP_DEVINFO: + ret = skf_devinfo(devname, out); + goto end; + case OP_LABEL: + ret = skf_label(devname, label); + if (ret) + BIO_printf(bio_err, "Device label changed to %s\n", label); + goto end; + case OP_TRANSMIT: + ret = skf_transmit(devname, transmit_cmd, out); + if (ret) + BIO_printf(bio_err, "Tranmist finished\n"); + goto end; + } + + /* opendev */ + if (!authkey) { + BIO_printf(bio_err, "Authentication key not specified\n"); + goto opthelp; + } + if (!skf_opendev(devname, authkey, &devInfo, &hdev)) { + goto end; + } + + /* without appname */ + switch (op) { + case OP_NEWAUTHKEY: + ret = skf_newauthkey(hdev, newauthkey); + if (ret) + BIO_puts(bio_err, "Device authentication key changed\n"); + goto end; + case OP_LISTAPPS: + ret = skf_listapps(hdev, out); + goto end; + } + + /* without openapp */ + if (!appname) { + BIO_printf(bio_err, "No application name\n"); + goto opthelp; + } + + switch (op) { + case OP_NEWAPP: + ret = skf_newapp(hdev, appname, passarg, adminpassarg); + if (ret) + BIO_printf(bio_err, "Application %s created\n", appname); + goto end; + case OP_DELAPP: + ret = skf_delapp(hdev, appname); + if (ret) + BIO_printf(bio_err, "Application %s deleted\n", appname); + goto end; + case OP_CHANGEPASS: + if (adminpassarg) { + admin = 1; + passarg = adminpassarg; + } + ret = skf_changepass(hdev, appname, admin, passarg, newpassarg); + if (ret) + BIO_printf(bio_err, "Application %s %s PIN changed\n", + appname, admin ? "administrator" : "user"); + goto end; + case OP_UNBLOCK: + if (admin && passarg && !adminpassarg) + adminpassarg = passarg; + ret = skf_unblock(hdev, appname, adminpassarg, newpassarg); + if (ret) + BIO_printf(bio_err, + "Application %s user PIN unblocked\n", appname); + goto end; + } + + /* open app */ + if (adminpassarg) { + admin = 1; + passarg = adminpassarg; + } + if (!skf_openapp(hdev, appname, admin, passarg, &happ)) { + goto end; + } + /* + BIO_printf(bio_err, "Application %s opened by %s\n", appname, + admin ? "administractor" : "user"); + */ + + switch (op) { + case OP_LISTOBJS: + BIO_printf(bio_err, "Application %s Objects:\n", appname); + ret = skf_listobjs(happ, out); + goto end; + case OP_LISTCONTAINERS: + BIO_printf(bio_err, "Application %s Containers:\n", appname); + ret = skf_listcontainers(happ, out); + goto end; + } + + /* with objname */ + if ((op == OP_IMPORTOBJ || op == OP_EXPORTOBJ || op == OP_DELOBJ) && !objname) { + BIO_printf(bio_err, "Data object name is not given\n"); + goto opthelp; + } + switch (op) { + case OP_IMPORTOBJ: + ret = skf_importobj(happ, objname, admin, infile); + if (ret) + BIO_printf(bio_err, "Object %s imported\n", objname); + goto end; + case OP_EXPORTOBJ: + ret = skf_exportobj(happ, objname, out); + if (ret) + BIO_printf(bio_err, "Object %s exported\n", objname); + goto end; + case OP_DELOBJ: + ret = skf_delobj(happ, objname); + if (ret) + BIO_printf(bio_err, "Object %s deleted\n", objname); + goto end; + } + + if (!containername) { + BIO_printf(bio_err, "No container name is given\n"); + goto opthelp; + } + switch (op) { + case OP_NEWCONTAINER: + ret = skf_newcontainer(happ, containername, algor); + if (ret) + BIO_printf(bio_err, "Container %s created\n", containername); + goto end; + case OP_DELCONTAINER: + ret = skf_delcontainer(happ, containername); + if (ret) + BIO_printf(bio_err, "Container %s deleted\n", containername); + goto end; + } + + if (SKF_OpenContainer(happ, (LPSTR)containername, &hcontainer) != SAR_OK) { + BIO_printf(bio_err, "Error on open container %s\n", containername); + ERR_print_errors(bio_err); + goto end; + } + switch (op) { + case OP_IMPORTENCKEY: + ret = skf_importenckey(hdev, hcontainer, &devInfo, infile, informat, keypassarg); + if (ret) + BIO_printf(bio_err, "Private key imported to container %s\n", containername); + break; + case OP_EXPORTSIGNKEY: + ret = skf_exportkey(hcontainer, SGD_TRUE, outformat, out); + break; + case OP_EXPORTENCKEY: + ret = skf_exportkey(hcontainer, SGD_FALSE, outformat, out); + break; + case OP_PRINTKEYS: + ret = skf_printkeys(hcontainer, out); + break; + case OP_IMPORTCERT: + ret = skf_importcert(hcontainer, infile, informat); + if (ret) + BIO_printf(bio_err, "Certificate imported to container %s\n", containername); + break; + case OP_EXPORTSIGNCERT: + ret = skf_exportcert(hcontainer, SGD_TRUE, outformat, out); + break; + case OP_EXPORTENCCERT: + ret = skf_exportcert(hcontainer, SGD_FALSE, outformat, out); + break; + } + + if (ret) + ret = 0; + else + ret = 1; + +end: + if (hcontainer) SKF_CloseContainer(hcontainer); + if (happ) SKF_CloseApplication(happ); + if (hdev) SKF_DisConnectDev(hdev); + return ret; +} +#endif diff --git a/tools/sm2decrypt.c b/tools/sm2decrypt.c new file mode 100644 index 00000000..5acdbf1e --- /dev/null +++ b/tools/sm2decrypt.c @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2021 - 2021 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +int main(int argc, char **argv) +{ + char *prog = basename(argv[0]); + const char *keyfile = NULL; + FILE *keyfp = NULL; + const char *pass = NULL; + SM2_KEY key; + char hexbuf[SM2_MAX_CIPHERTEXT_SIZE * 2]; + uint8_t inbuf[SM2_MAX_CIPHERTEXT_SIZE * 2]; + uint8_t outbuf[SM2_MAX_CIPHERTEXT_SIZE]; + size_t hexlen, inlen, outlen; + + if (argc < 2) { +bad: + fprintf(stderr, "%s : error options\n", prog); +help: + fprintf(stderr, "usage: %s -key key.pem [-id str] < file\n", prog); + return 1; + } + + argc--; + argv++; + while (argc > 1) { + if (!strcmp(*argv, "-help")) { + goto help; + } else if (!strcmp(*argv, "-key")) { + if (--argc < 1) goto bad; + keyfile = *(++argv); + } else { + goto help; + } + argc--; + argv++; + } + + if (!keyfile) { + error_print(); + return -1; + } + if (!(keyfp = fopen(keyfile, "r"))) { + error_print(); + return -1; + } + pass = getpass("Encryption Password : "); + if (sm2_enced_private_key_info_from_pem(&key, pass, keyfp) != 1) { + error_print("private key decryption failure"); + return -1; + } + if ((hexlen = fread(hexbuf, 1, sizeof(hexbuf), stdin)) <= 0) { + error_print(); + return -1; + } + if (hex2bin(hexbuf, hexlen, inbuf) != 1) { + error_print(); + return -1; + } + if (sm2_decrypt(&key, inbuf, hexlen/2, outbuf, &outlen) != 1) { + error_print(); + return -1; + } + fwrite(outbuf, 1, outlen, stdout); + return 0; + +} diff --git a/tools/sm2encrypt.c b/tools/sm2encrypt.c new file mode 100644 index 00000000..802b5af5 --- /dev/null +++ b/tools/sm2encrypt.c @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2021 - 2021 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +int main(int argc, char **argv) +{ + int ret; + char *prog = basename(argv[0]); + const char *keyfile = NULL; + const char *certfile = NULL; + FILE *keyfp = NULL; + FILE *certfp = NULL; + X509_CERTIFICATE cert; + SM2_KEY key; + uint8_t inbuf[SM2_MAX_PLAINTEXT_SIZE]; + ssize_t inlen; + uint8_t outbuf[SM2_MAX_CIPHERTEXT_SIZE]; + size_t outlen = sizeof(outbuf); + + if (argc < 2) { +bad: + fprintf(stderr, "%s : error options\n", prog); +help: + fprintf(stderr, "usage:\n"); + fprintf(stderr, " %s -pubkey key.pem < file\n", prog); + fprintf(stderr, " %s -cert cert.pem < file\n", prog); + fprintf(stderr, "\n"); + return 1; + } + + argc--; + argv++; + while (argc > 1) { + if (!strcmp(*argv, "-help")) { + goto help; + } else if (!strcmp(*argv, "-pubkey")) { + if (--argc < 1) goto bad; + keyfile = *(++argv); + } else if (!strcmp(*argv, "-cert")) { + if (--argc < 1) goto bad; + certfile = *(++argv); + } else { + goto help; + } + argc--; + argv++; + } + + if ((!keyfile && !certfile) || (keyfile && certfile)) { + error_print(); + return -1; + } + if (keyfile) { + if (!(keyfp = fopen(keyfile, "r"))) { + error_print(); + return -1; + } + if (sm2_public_key_info_from_pem(&key, keyfp) != 1) { + error_print(); + return -1; + } + } else { + if (!(certfp = fopen(certfile, "r"))) { + error_print(); + return -1; + } + if (x509_certificate_from_pem(&cert, certfp) != 1) { + error_print(); + return -1; + } + if (x509_certificate_get_public_key(&cert, &key) != 1) { + error_print(); + return -1; + } + } + + if ((inlen = read(STDIN_FILENO, inbuf, sizeof(inbuf))) <= 0) { + error_print(); + return -1; + } + if (sm2_encrypt(&key, inbuf, inlen, outbuf, &outlen) != 1) { + error_print(); + return -1; + } + format_bytes(stdout, 0, 0, "", outbuf, outlen); + return 1; +} diff --git a/tools/sm2gen.c b/tools/sm2gen.c new file mode 100644 index 00000000..147c3ce0 --- /dev/null +++ b/tools/sm2gen.c @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2021 - 2021 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + +#include +#include +#include +#include +#include +#include +#include + +int main(void) +{ + SM2_KEY key; + + if (sm2_keygen(&key) != 1) { + error_print(); + return -1; + } + if (sm2_private_key_to_pem(&key, stdout) != 1) { + error_print(); + return -1; + } + return 0; +} diff --git a/tools/sm2pub.c b/tools/sm2pub.c new file mode 100644 index 00000000..6a99aaf9 --- /dev/null +++ b/tools/sm2pub.c @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2021 - 2021 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +// 输入一个PKCS #8 加密格式的私钥,输出一个EC公钥 + + +int main(void) +{ + SM2_KEY key; + char *pass = NULL; + char passbuf[64] = {0}; + + pass = getpass("Encryption Password : "); + strncpy(passbuf, pass, sizeof(passbuf)); + pass = getpass("Encryption Password (Again) : "); + if (strcmp(passbuf, pass) != 0) { + fprintf(stderr, "error: passwords not match\n"); + return -1; + } + + sm2_keygen(&key); + sm2_enced_private_key_info_to_pem(&key, pass, stdout); + + return 0; +} diff --git a/tools/sm2sign.c b/tools/sm2sign.c new file mode 100644 index 00000000..0891f57c --- /dev/null +++ b/tools/sm2sign.c @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2021 - 2021 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +// echo data | sm2sign -id "Alice" -keyfile sm2.pem +// echo data | sm2verify -id "Alice" -keyfile sm2pub.pem -certfile a -cacertfile b + + + + +int main(int argc, char **argv) +{ + char *prog = basename(argv[0]); + const char *id = SM2_DEFAULT_ID; + const char *keyfile = NULL; + FILE *keyfp = NULL; + const char *pass = NULL; + SM2_KEY key; + SM2_SIGN_CTX sign_ctx; + uint8_t buf[4096]; + ssize_t len; + uint8_t sig[SM2_MAX_SIGNATURE_SIZE]; + size_t siglen; + + if (argc < 2) { +bad: + fprintf(stderr, "%s : error options\n", prog); +help: + fprintf(stderr, "usage: %s -key key.pem [-id str] < file\n", prog); + return 1; + } + + argc--; + argv++; + while (argc > 1) { + if (!strcmp(*argv, "-help")) { + goto help; + } else if (!strcmp(*argv, "-id")) { + if (--argc < 1) goto bad; + id = *(++argv); + } else if (!strcmp(*argv, "-key")) { + if (--argc < 1) goto bad; + keyfile = *(++argv); + } else { + goto help; + } + argc--; + argv++; + } + + if (!keyfile) { + error_print(); + return -1; + } + if (!(keyfp = fopen(keyfile, "r"))) { + error_print(); + return -1; + } + pass = getpass("Encryption Password : "); + if (sm2_enced_private_key_info_from_pem(&key, pass, keyfp) != 1) { + error_print("private key decryption failure"); + return -1; + } + + sm2_sign_init(&sign_ctx, &key, id); + while ((len = read(STDIN_FILENO, buf, sizeof(buf))) > 0) { + sm2_sign_update(&sign_ctx, buf, len); + } + sm2_sign_finish(&sign_ctx, sig, &siglen); + format_bytes(stdout, 0, 0, "", sig, siglen); + return 0; + +} diff --git a/tools/sm2verify.c b/tools/sm2verify.c new file mode 100644 index 00000000..c3098dc7 --- /dev/null +++ b/tools/sm2verify.c @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2021 - 2021 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +int main(int argc, char **argv) +{ + int ret; + char *prog = basename(argv[0]); + const char *sig_hex = NULL; + const char *id = SM2_DEFAULT_ID; + const char *keyfile = NULL; + const char *certfile = NULL; + FILE *keyfp = NULL; + FILE *certfp = NULL; + X509_CERTIFICATE cert; + SM2_KEY key; + SM2_SIGN_CTX verify_ctx; + uint8_t buf[4096]; + ssize_t len; + uint8_t sig[SM2_MAX_SIGNATURE_SIZE]; + size_t siglen; + + if (argc < 2) { +bad: + fprintf(stderr, "%s : error options\n", prog); +help: + fprintf(stderr, "usage:\n"); + fprintf(stderr, " %s -sig hex -pubkey key.pem [-id str] < file\n", prog); + fprintf(stderr, " %s -sig hex -cert cert.pem [-id str] < file\n", prog); + fprintf(stderr, "\n"); + return 1; + } + + argc--; + argv++; + while (argc > 1) { + if (!strcmp(*argv, "-help")) { + goto help; + } else if (!strcmp(*argv, "-id")) { + if (--argc < 1) goto bad; + id = *(++argv); + } else if (!strcmp(*argv, "-pubkey")) { + if (--argc < 1) goto bad; + keyfile = *(++argv); + } else if (!strcmp(*argv, "-sig")) { + if (--argc < 1) goto bad; + sig_hex = *(++argv); + } else if (!strcmp(*argv, "-cert")) { + if (--argc < 1) goto bad; + certfile = *(++argv); + } else { + goto help; + } + argc--; + argv++; + } + + if (!sig_hex || (!keyfile && !certfile) || (keyfile && certfile)) { + error_print(); + return -1; + } + if (strlen(sig_hex) > SM2_MAX_SIGNATURE_SIZE * 2 || strlen(sig_hex) % 2) { + error_print(); + return -1; + } + if (hex2bin(sig_hex, strlen(sig_hex), sig) != 1) { + error_print(); + return -1; + } + siglen = strlen(sig_hex)/2; + + if (keyfile) { + if (!(keyfp = fopen(keyfile, "r"))) { + error_print(); + return -1; + } + if (sm2_public_key_info_from_pem(&key, keyfp) != 1) { + error_print(); + return -1; + } + } else { + if (!(certfp = fopen(certfile, "r"))) { + error_print(); + return -1; + } + if (x509_certificate_from_pem(&cert, certfp) != 1) { + error_print(); + return -1; + } + if (x509_certificate_get_public_key(&cert, &key) != 1) { + error_print(); + return -1; + } + } + + sm2_verify_init(&verify_ctx, &key, id); + while ((len = read(STDIN_FILENO, buf, sizeof(buf))) > 0) { + sm2_verify_update(&verify_ctx, buf, len); + } + if ((ret = sm2_verify_finish(&verify_ctx, sig, siglen)) < 0) { + error_print(); + return -1; + } + fprintf(stdout, "verify : %s\n", ret == 1 ? "success" : "failure"); + return ret == 1 ? 0 : -1; + + return 1; +} diff --git a/tools/sm2view.c b/tools/sm2view.c new file mode 100644 index 00000000..fa136442 --- /dev/null +++ b/tools/sm2view.c @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2020 - 2021 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + +#include +#include +#include +#include +#include +#include + +int main(void) +{ + SM2_KEY key; + + if (sm2_private_key_from_pem(&key, stdin) != 1) { + error_print(); + return -1; + } + sm2_key_print(stdout, &key, 0, 0); + sm2_public_key_info_to_pem(&key, stdout); + return 0; +} diff --git a/tools/sm3sum.c b/tools/sm3sum.c new file mode 100644 index 00000000..63b8440c --- /dev/null +++ b/tools/sm3sum.c @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2014 - 2021 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + +#include +#include +#include +#include +#include +#include + + +int main(int argc, char **argv) +{ + char *prog = basename(argv[0]); + SM3_CTX ctx; + uint8_t dgst[32]; + uint8_t buf[4096]; + ssize_t len; + int i; + + if (argc > 1) { + fprintf(stderr, "usage: echo -n \"abc\" | %s\n", prog); + fprintf(stderr, " %s < path/to/file\n", prog); + return 0; + } + + sm3_init(&ctx); + while ((len = read(STDIN_FILENO, buf, sizeof(buf))) > 0) { + sm3_update(&ctx, buf, len); + } + sm3_finish(&ctx, dgst); + + for (i = 0; i < sizeof(dgst); i++) { + printf("%02x", dgst[i]); + } + printf("\n"); + return 0; +} diff --git a/tools/sm4speed.c b/tools/sm4speed.c new file mode 100644 index 00000000..6ac9e976 --- /dev/null +++ b/tools/sm4speed.c @@ -0,0 +1,86 @@ +/* ==================================================================== + * Copyright (c) 2014 - 2017 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + * ==================================================================== + */ + + +#include +#include +#include +#include +#include +#include + + +int main(int argc, char **argv) +{ + SM4_KEY sm4_key; + unsigned char user_key[16] = { + 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, + 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, + }; + size_t buflen = SM4_BLOCK_SIZE * 8 * 3 * 1000 * 1000; + unsigned char *buf = NULL; + unsigned char *p; + int i; + + + if (!(buf = (unsigned char *)malloc(buflen))) { + fprintf(stderr, "malloc failed\n"); + return -1; + } + + sm4_set_encrypt_key(&sm4_key, user_key); + + #pragma omp parallel for + for (i = 0, p = buf; i < buflen/(SM4_BLOCK_SIZE * 16); i++, p += SM4_BLOCK_SIZE * 16) { + sm4_encrypt_16blocks(&sms4_key, p, p); + } + + return 0; +} + diff --git a/tools/tlcp_client.c b/tools/tlcp_client.c new file mode 100644 index 00000000..283980a6 --- /dev/null +++ b/tools/tlcp_client.c @@ -0,0 +1,196 @@ +/* + * Copyright (c) 2021 - 2021 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + +#include +#include +#include +#include +#include +#include +#include + + +const char *http_get = + "GET / HTTP/1.1\r\n" + "Hostname: aaa\r\n" + "\r\n\r\n"; + +void print_usage(const char *prog) +{ + printf("Usage: %s [options]\n", prog); + printf(" -host \n"); + printf(" -port \n"); + printf(" -cacerts \n"); + printf(" -cert \n"); + printf(" -key \n"); +} + +int main(int argc , char *argv[]) +{ + int ret = -1; + char *prog = basename(argv[0]); + char *host = NULL; + int port = 443; + TLS_CONNECT conn; + char buf[100] = {0}; + size_t len = sizeof(buf); + + + char *cacertsfile = NULL; + char *certfile = NULL; + char *keyfile = NULL; + + FILE *cacertsfp = NULL; + FILE *certfp = NULL; + FILE *keyfp = NULL; + SM2_KEY sign_key; + + + if (argc < 2) { + print_usage(prog); + return 0; + } + + argc--; + argv++; + while (argc >= 1) { + if (!strcmp(*argv, "-help")) { + print_usage(prog); + return 0; + + } else if (!strcmp(*argv, "-host")) { + if (--argc < 1) goto bad; + host = *(++argv); + + } else if (!strcmp(*argv, "-port")) { + if (--argc < 1) goto bad; + port = atoi(*(++argv)); + + } else if (!strcmp(*argv, "-cacerts")) { + if (--argc < 1) goto bad; + cacertsfile = *(++argv); + + } else if (!strcmp(*argv, "-cert")) { + if (--argc < 1) goto bad; + certfile = *(++argv); + + } else if (!strcmp(*argv, "-key")) { + if (--argc < 1) goto bad; + keyfile = *(++argv); + + } else { + print_usage(prog); + return 0; + } + argc--; + argv++; + } + + if (!host || !certfile || !keyfile) { + print_usage(prog); + return -1; + } + + if (cacertsfile) { + if (!(cacertsfp = fopen(cacertsfile, "r"))) { + error_print(); + return -1; + } + } + if (certfile) { + if (!(certfp = fopen(certfile, "r"))) { + error_print(); + return -1; + } + } + if (keyfile) { + if (!(keyfp = fopen(keyfile, "r"))) { + error_print(); + return -1; + } + if (sm2_private_key_from_pem(&sign_key, keyfp) != 1) { + error_print(); + return -1; + } + } + + memset(&conn, 0, sizeof(conn)); + + if (tlcp_connect(&conn, host, port, cacertsfp, certfp, &sign_key) != 1) { + error_print(); + return -1; + } + + + // 这个client 发收了一个消息就结束了 + if (tls_send(&conn, (uint8_t *)"12345\n", 6) != 1) { + error_print(); + return -1; + } + + for (;;) { + memset(buf, 0, sizeof(buf)); + len = sizeof(buf); + if (tls_recv(&conn, (uint8_t *)buf, &len) != 1) { + error_print(); + return -1; + } + if (len > 0) { + printf("%s\n", buf); + break; + } + } + + return 1; +bad: + fprintf(stderr, "%s: command error\n", prog); + + return 0; +} + + diff --git a/tools/tlcp_server.c b/tools/tlcp_server.c new file mode 100644 index 00000000..8917857d --- /dev/null +++ b/tools/tlcp_server.c @@ -0,0 +1,194 @@ +/* + * Copyright (c) 2021 - 2021 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + + +void print_usage(const char *prog) +{ + printf("Usage: %s [options]\n", prog); + printf(" -port \n"); + printf(" -cert \n"); + printf(" -signkey \n"); + printf(" -enckey \n"); +} + + + +int main(int argc , char *argv[]) +{ + int ret = -1; + char *prog = basename(argv[0]); + int port = 443; + char *certfile = NULL; + char *signkeyfile = NULL; + char *enckeyfile = NULL; + FILE *certfp = NULL; + FILE *signkeyfp = NULL; + FILE *enckeyfp = NULL; + SM2_KEY signkey; + SM2_KEY enckey; + + uint8_t verify_buf[4096]; + + + TLS_CONNECT conn; + char buf[1600] = {0}; + size_t len = sizeof(buf); + + if (argc < 2) { + print_usage(prog); + return 0; + } + + argc--; + argv++; + while (argc >= 1) { + if (!strcmp(*argv, "-help")) { + print_usage(prog); + return 0; + + } else if (!strcmp(*argv, "-port")) { + if (--argc < 1) goto bad; + port = atoi(*(++argv)); + + } else if (!strcmp(*argv, "-cert")) { + if (--argc < 1) goto bad; + certfile = *(++argv); + + } else if (!strcmp(*argv, "-signkey")) { + if (--argc < 1) goto bad; + signkeyfile = *(++argv); + + } else if (!strcmp(*argv, "-enckey")) { + if (--argc < 1) goto bad; + enckeyfile = *(++argv); + + } else { + print_usage(prog); + return 0; + } + argc--; + argv++; + } + + if (!certfile || !signkeyfile || !enckeyfile) { + print_usage(prog); + return -1; + } + + if (!(certfp = fopen(certfile, "r"))) { + error_print(); + return -1; + } + + + if (!(signkeyfp = fopen(signkeyfile, "r"))) { + error_print(); + return -1; + } + if (sm2_private_key_from_pem(&signkey, signkeyfp) != 1) { + error_print(); + return -1; + } + + if (!(enckeyfp = fopen(enckeyfile, "r"))) { + error_print(); + return -1; + } + if (sm2_private_key_from_pem(&enckey, enckeyfp) != 1) { + error_print(); + return -1; + } + + memset(&conn, 0, sizeof(conn)); + if (tlcp_accept(&conn, port, certfp, &signkey, &enckey, + certfp, verify_buf, 4096) != 1) { + error_print(); + return -1; + } + + // 我要做一个反射的服务器,接收到用户的输入之后,再反射回去 + for (;;) { + + // 接收一个消息 + // 按道理说第二次执行的时候是不可能成功的了,因此客户端没有数据发过来 + do { + len = sizeof(buf); + if (tls_recv(&conn, (uint8_t *)buf, &len) != 1) { + error_print(); + return -1; + } + } while (!len); + + + // 把这个消息再发回去 + if (tls_send(&conn, (uint8_t *)buf, len) != 1) { + error_print(); + return -1; + } + + fprintf(stderr, "-----------------\n\n\n\n\n\n"); + + } + + + + return 1; +bad: + fprintf(stderr, "%s: command error\n", prog); + + return 0; +} diff --git a/tools/tls12_client.c b/tools/tls12_client.c new file mode 100644 index 00000000..bcbe5e5a --- /dev/null +++ b/tools/tls12_client.c @@ -0,0 +1,194 @@ +/* + * Copyright (c) 2021 - 2021 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + +#include +#include +#include +#include +#include +#include +#include + + +const char *http_get = + "GET / HTTP/1.1\r\n" + "Hostname: aaa\r\n" + "\r\n\r\n"; + +void print_usage(const char *prog) +{ + printf("Usage: %s [options]\n", prog); + printf(" -host \n"); + printf(" -port \n"); + printf(" -cacerts \n"); + printf(" -cert \n"); + printf(" -key \n"); +} + +int main(int argc , char *argv[]) +{ + int ret = -1; + char *prog = basename(argv[0]); + char *host = NULL; + int port = 443; + TLS_CONNECT conn; + char buf[100] = {0}; + size_t len = sizeof(buf); + + char *cacertsfile = NULL; + char *certfile = NULL; + char *keyfile = NULL; + + FILE *cacertsfp = NULL; + FILE *certfp = NULL; + FILE *keyfp = NULL; + SM2_KEY sign_key; + + + if (argc < 2) { + print_usage(prog); + return 0; + } + + argc--; + argv++; + while (argc >= 1) { + if (!strcmp(*argv, "-help")) { + print_usage(prog); + return 0; + + } else if (!strcmp(*argv, "-host")) { + if (--argc < 1) goto bad; + host = *(++argv); + + } else if (!strcmp(*argv, "-port")) { + if (--argc < 1) goto bad; + port = atoi(*(++argv)); + + } else if (!strcmp(*argv, "-cacerts")) { + if (--argc < 1) goto bad; + cacertsfile = *(++argv); + + } else if (!strcmp(*argv, "-cert")) { + if (--argc < 1) goto bad; + certfile = *(++argv); + + } else if (!strcmp(*argv, "-key")) { + if (--argc < 1) goto bad; + keyfile = *(++argv); + + } else { + print_usage(prog); + return 0; + } + argc--; + argv++; + } + + if (!host || !certfile || !keyfile) { + print_usage(prog); + return -1; + } + + if (cacertsfile) { + if (!(cacertsfp = fopen(cacertsfile, "r"))) { + error_print(); + return -1; + } + } + if (certfile) { + if (!(certfp = fopen(certfile, "r"))) { + error_print(); + return -1; + } + } + if (keyfile) { + if (!(keyfp = fopen(keyfile, "r"))) { + error_print(); + return -1; + } + if (sm2_private_key_from_pem(&sign_key, keyfp) != 1) { + error_print(); + return -1; + } + } + + memset(&conn, 0, sizeof(conn)); + + if (tls12_connect(&conn, host, port, cacertsfp, certfp, &sign_key) != 1) { + error_print(); + return -1; + } + + // 这个client 发收了一个消息就结束了 + if (tls_send(&conn, (uint8_t *)"12345\n", 6) != 1) { + error_print(); + return -1; + } + + for (;;) { + memset(buf, 0, sizeof(buf)); + len = sizeof(buf); + if (tls_recv(&conn, (uint8_t *)buf, &len) != 1) { + error_print(); + return -1; + } + if (len > 0) { + printf("%s\n", buf); + break; + } + } + + return 1; +bad: + fprintf(stderr, "%s: command error\n", prog); + + return 0; +} + + diff --git a/tools/tls12_server.c b/tools/tls12_server.c new file mode 100644 index 00000000..348452c0 --- /dev/null +++ b/tools/tls12_server.c @@ -0,0 +1,175 @@ +/* + * Copyright (c) 2021 - 2021 The GmSSL 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 GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL 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 GmSSL 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + + +void print_usage(const char *prog) +{ + printf("Usage: %s [options]\n", prog); + printf(" -port \n"); + printf(" -cert \n"); + printf(" -signkey \n"); +} + +int main(int argc , char *argv[]) +{ + int ret = -1; + char *prog = basename(argv[0]); + int port = 443; + char *certfile = NULL; + char *signkeyfile = NULL; + FILE *certfp = NULL; + FILE *signkeyfp = NULL; + SM2_KEY signkey; + + uint8_t verify_buf[4096]; + + + TLS_CONNECT conn; + char buf[1600] = {0}; + size_t len = sizeof(buf); + + if (argc < 2) { + print_usage(prog); + return 0; + } + + argc--; + argv++; + while (argc >= 1) { + if (!strcmp(*argv, "-help")) { + print_usage(prog); + return 0; + + } else if (!strcmp(*argv, "-port")) { + if (--argc < 1) goto bad; + port = atoi(*(++argv)); + + } else if (!strcmp(*argv, "-cert")) { + if (--argc < 1) goto bad; + certfile = *(++argv); + + } else if (!strcmp(*argv, "-signkey")) { + if (--argc < 1) goto bad; + signkeyfile = *(++argv); + + } else { + print_usage(prog); + return 0; + } + argc--; + argv++; + } + + if (!certfile || !signkeyfile) { + print_usage(prog); + return -1; + } + + if (!(certfp = fopen(certfile, "r"))) { + error_print(); + return -1; + } + + + if (!(signkeyfp = fopen(signkeyfile, "r"))) { + error_print(); + return -1; + } + if (sm2_private_key_from_pem(&signkey, signkeyfp) != 1) { + error_print(); + return -1; + } + + memset(&conn, 0, sizeof(conn)); + if (tls12_accept(&conn, port, certfp, &signkey, + certfp, verify_buf, 4096) != 1) { + error_print(); + return -1; + } + + // 我要做一个反射的服务器,接收到用户的输入之后,再反射回去 + for (;;) { + + // 接收一个消息 + // 按道理说第二次执行的时候是不可能成功的了,因此客户端没有数据发过来 + do { + len = sizeof(buf); + if (tls_recv(&conn, (uint8_t *)buf, &len) != 1) { + error_print(); + return -1; + } + } while (!len); + + + // 把这个消息再发回去 + if (tls_send(&conn, (uint8_t *)buf, len) != 1) { + error_print(); + return -1; + } + + fprintf(stderr, "-----------------\n\n\n\n\n\n"); + + } + + + + return 1; +bad: + fprintf(stderr, "%s: command error\n", prog); + + return 0; +}