]> pd.if.org Git - zpackage/commitdiff
commit files needed for zpm-fetchurl
authorNathan Wagner <nw@hydaspes.if.org>
Sun, 10 Feb 2019 11:46:48 +0000 (11:46 +0000)
committerNathan Wagner <nw@hydaspes.if.org>
Sun, 10 Feb 2019 11:46:48 +0000 (11:46 +0000)
These can be trimmed down later.

555 files changed:
Makefile
crypto/base64.c [new file with mode: 0644]
crypto/buffer.c [new file with mode: 0644]
crypto/buffer.h [new file with mode: 0644]
crypto/chacha.c [new file with mode: 0644]
crypto/chacha.h [new file with mode: 0644]
crypto/cipher_supported.c [new file with mode: 0644]
crypto/forward.c [new file with mode: 0644]
crypto/handshake.c [new file with mode: 0644]
crypto/hash.c [new file with mode: 0644]
crypto/hkdf.c [new file with mode: 0644]
crypto/hmac_message.c [new file with mode: 0644]
crypto/packet_update.c [new file with mode: 0644]
crypto/parse_client_hello.c [new file with mode: 0644]
crypto/parse_message.c [new file with mode: 0644]
crypto/pem.c [new file with mode: 0644]
crypto/ref10/base.c [new file with mode: 0644]
crypto/ref10/fe.h [new file with mode: 0644]
crypto/ref10/fe_0.c [new file with mode: 0644]
crypto/ref10/fe_1.c [new file with mode: 0644]
crypto/ref10/fe_add.c [new file with mode: 0644]
crypto/ref10/fe_copy.c [new file with mode: 0644]
crypto/ref10/fe_cswap.c [new file with mode: 0644]
crypto/ref10/fe_frombytes.c [new file with mode: 0644]
crypto/ref10/fe_invert.c [new file with mode: 0644]
crypto/ref10/fe_mul.c [new file with mode: 0644]
crypto/ref10/fe_mul121666.c [new file with mode: 0644]
crypto/ref10/fe_sq.c [new file with mode: 0644]
crypto/ref10/fe_sub.c [new file with mode: 0644]
crypto/ref10/fe_tobytes.c [new file with mode: 0644]
crypto/ref10/scalarmult.c [new file with mode: 0644]
crypto/tlse.c [new file with mode: 0644]
libtomcrypt/src/ciphers/aes/aes.c [new file with mode: 0644]
libtomcrypt/src/ciphers/aes/aes_tab.c [new file with mode: 0644]
libtomcrypt/src/ciphers/anubis.c [new file with mode: 0644]
libtomcrypt/src/ciphers/blowfish.c [new file with mode: 0644]
libtomcrypt/src/ciphers/camellia.c [new file with mode: 0644]
libtomcrypt/src/ciphers/cast5.c [new file with mode: 0644]
libtomcrypt/src/ciphers/des.c [new file with mode: 0644]
libtomcrypt/src/ciphers/kasumi.c [new file with mode: 0644]
libtomcrypt/src/ciphers/khazad.c [new file with mode: 0644]
libtomcrypt/src/ciphers/kseed.c [new file with mode: 0644]
libtomcrypt/src/ciphers/multi2.c [new file with mode: 0644]
libtomcrypt/src/ciphers/noekeon.c [new file with mode: 0644]
libtomcrypt/src/ciphers/rc2.c [new file with mode: 0644]
libtomcrypt/src/ciphers/rc5.c [new file with mode: 0644]
libtomcrypt/src/ciphers/rc6.c [new file with mode: 0644]
libtomcrypt/src/ciphers/safer/safer.c [new file with mode: 0644]
libtomcrypt/src/ciphers/safer/safer_tab.c [new file with mode: 0644]
libtomcrypt/src/ciphers/safer/saferp.c [new file with mode: 0644]
libtomcrypt/src/ciphers/skipjack.c [new file with mode: 0644]
libtomcrypt/src/ciphers/twofish/twofish.c [new file with mode: 0644]
libtomcrypt/src/ciphers/twofish/twofish_tab.c [new file with mode: 0644]
libtomcrypt/src/ciphers/xtea.c [new file with mode: 0644]
libtomcrypt/src/encauth/ccm/ccm_add_aad.c [new file with mode: 0644]
libtomcrypt/src/encauth/ccm/ccm_add_nonce.c [new file with mode: 0644]
libtomcrypt/src/encauth/ccm/ccm_done.c [new file with mode: 0644]
libtomcrypt/src/encauth/ccm/ccm_init.c [new file with mode: 0644]
libtomcrypt/src/encauth/ccm/ccm_memory.c [new file with mode: 0644]
libtomcrypt/src/encauth/ccm/ccm_process.c [new file with mode: 0644]
libtomcrypt/src/encauth/ccm/ccm_reset.c [new file with mode: 0644]
libtomcrypt/src/encauth/ccm/ccm_test.c [new file with mode: 0644]
libtomcrypt/src/encauth/chachapoly/chacha20poly1305_add_aad.c [new file with mode: 0644]
libtomcrypt/src/encauth/chachapoly/chacha20poly1305_decrypt.c [new file with mode: 0644]
libtomcrypt/src/encauth/chachapoly/chacha20poly1305_done.c [new file with mode: 0644]
libtomcrypt/src/encauth/chachapoly/chacha20poly1305_encrypt.c [new file with mode: 0644]
libtomcrypt/src/encauth/chachapoly/chacha20poly1305_init.c [new file with mode: 0644]
libtomcrypt/src/encauth/chachapoly/chacha20poly1305_memory.c [new file with mode: 0644]
libtomcrypt/src/encauth/chachapoly/chacha20poly1305_setiv.c [new file with mode: 0644]
libtomcrypt/src/encauth/chachapoly/chacha20poly1305_setiv_rfc7905.c [new file with mode: 0644]
libtomcrypt/src/encauth/chachapoly/chacha20poly1305_test.c [new file with mode: 0644]
libtomcrypt/src/encauth/eax/eax_addheader.c [new file with mode: 0644]
libtomcrypt/src/encauth/eax/eax_decrypt.c [new file with mode: 0644]
libtomcrypt/src/encauth/eax/eax_decrypt_verify_memory.c [new file with mode: 0644]
libtomcrypt/src/encauth/eax/eax_done.c [new file with mode: 0644]
libtomcrypt/src/encauth/eax/eax_encrypt.c [new file with mode: 0644]
libtomcrypt/src/encauth/eax/eax_encrypt_authenticate_memory.c [new file with mode: 0644]
libtomcrypt/src/encauth/eax/eax_init.c [new file with mode: 0644]
libtomcrypt/src/encauth/eax/eax_test.c [new file with mode: 0644]
libtomcrypt/src/encauth/gcm/gcm_add_aad.c [new file with mode: 0644]
libtomcrypt/src/encauth/gcm/gcm_add_iv.c [new file with mode: 0644]
libtomcrypt/src/encauth/gcm/gcm_done.c [new file with mode: 0644]
libtomcrypt/src/encauth/gcm/gcm_gf_mult.c [new file with mode: 0644]
libtomcrypt/src/encauth/gcm/gcm_init.c [new file with mode: 0644]
libtomcrypt/src/encauth/gcm/gcm_memory.c [new file with mode: 0644]
libtomcrypt/src/encauth/gcm/gcm_mult_h.c [new file with mode: 0644]
libtomcrypt/src/encauth/gcm/gcm_process.c [new file with mode: 0644]
libtomcrypt/src/encauth/gcm/gcm_reset.c [new file with mode: 0644]
libtomcrypt/src/encauth/gcm/gcm_test.c [new file with mode: 0644]
libtomcrypt/src/encauth/ocb/ocb_decrypt.c [new file with mode: 0644]
libtomcrypt/src/encauth/ocb/ocb_decrypt_verify_memory.c [new file with mode: 0644]
libtomcrypt/src/encauth/ocb/ocb_done_decrypt.c [new file with mode: 0644]
libtomcrypt/src/encauth/ocb/ocb_done_encrypt.c [new file with mode: 0644]
libtomcrypt/src/encauth/ocb/ocb_encrypt.c [new file with mode: 0644]
libtomcrypt/src/encauth/ocb/ocb_encrypt_authenticate_memory.c [new file with mode: 0644]
libtomcrypt/src/encauth/ocb/ocb_init.c [new file with mode: 0644]
libtomcrypt/src/encauth/ocb/ocb_ntz.c [new file with mode: 0644]
libtomcrypt/src/encauth/ocb/ocb_shift_xor.c [new file with mode: 0644]
libtomcrypt/src/encauth/ocb/ocb_test.c [new file with mode: 0644]
libtomcrypt/src/encauth/ocb/s_ocb_done.c [new file with mode: 0644]
libtomcrypt/src/encauth/ocb3/ocb3_add_aad.c [new file with mode: 0644]
libtomcrypt/src/encauth/ocb3/ocb3_decrypt.c [new file with mode: 0644]
libtomcrypt/src/encauth/ocb3/ocb3_decrypt_last.c [new file with mode: 0644]
libtomcrypt/src/encauth/ocb3/ocb3_decrypt_verify_memory.c [new file with mode: 0644]
libtomcrypt/src/encauth/ocb3/ocb3_done.c [new file with mode: 0644]
libtomcrypt/src/encauth/ocb3/ocb3_encrypt.c [new file with mode: 0644]
libtomcrypt/src/encauth/ocb3/ocb3_encrypt_authenticate_memory.c [new file with mode: 0644]
libtomcrypt/src/encauth/ocb3/ocb3_encrypt_last.c [new file with mode: 0644]
libtomcrypt/src/encauth/ocb3/ocb3_init.c [new file with mode: 0644]
libtomcrypt/src/encauth/ocb3/ocb3_int_ntz.c [new file with mode: 0644]
libtomcrypt/src/encauth/ocb3/ocb3_int_xor_blocks.c [new file with mode: 0644]
libtomcrypt/src/encauth/ocb3/ocb3_test.c [new file with mode: 0644]
libtomcrypt/src/hashes/blake2b.c [new file with mode: 0644]
libtomcrypt/src/hashes/blake2s.c [new file with mode: 0644]
libtomcrypt/src/hashes/chc/chc.c [new file with mode: 0644]
libtomcrypt/src/hashes/helper/hash_file.c [new file with mode: 0644]
libtomcrypt/src/hashes/helper/hash_filehandle.c [new file with mode: 0644]
libtomcrypt/src/hashes/helper/hash_memory.c [new file with mode: 0644]
libtomcrypt/src/hashes/helper/hash_memory_multi.c [new file with mode: 0644]
libtomcrypt/src/hashes/md2.c [new file with mode: 0644]
libtomcrypt/src/hashes/md4.c [new file with mode: 0644]
libtomcrypt/src/hashes/md5.c [new file with mode: 0644]
libtomcrypt/src/hashes/rmd128.c [new file with mode: 0644]
libtomcrypt/src/hashes/rmd160.c [new file with mode: 0644]
libtomcrypt/src/hashes/rmd256.c [new file with mode: 0644]
libtomcrypt/src/hashes/rmd320.c [new file with mode: 0644]
libtomcrypt/src/hashes/sha1.c [new file with mode: 0644]
libtomcrypt/src/hashes/sha2/sha224.c [new file with mode: 0644]
libtomcrypt/src/hashes/sha2/sha256.c [new file with mode: 0644]
libtomcrypt/src/hashes/sha2/sha384.c [new file with mode: 0644]
libtomcrypt/src/hashes/sha2/sha512.c [new file with mode: 0644]
libtomcrypt/src/hashes/sha2/sha512_224.c [new file with mode: 0644]
libtomcrypt/src/hashes/sha2/sha512_256.c [new file with mode: 0644]
libtomcrypt/src/hashes/sha3.c [new file with mode: 0644]
libtomcrypt/src/hashes/sha3_test.c [new file with mode: 0644]
libtomcrypt/src/hashes/tiger.c [new file with mode: 0644]
libtomcrypt/src/hashes/whirl/whirl.c [new file with mode: 0644]
libtomcrypt/src/hashes/whirl/whirltab.c [new file with mode: 0644]
libtomcrypt/src/headers/tomcrypt.h [new file with mode: 0644]
libtomcrypt/src/headers/tomcrypt_argchk.h [new file with mode: 0644]
libtomcrypt/src/headers/tomcrypt_cfg.h [new file with mode: 0644]
libtomcrypt/src/headers/tomcrypt_cipher.h [new file with mode: 0644]
libtomcrypt/src/headers/tomcrypt_custom.h [new file with mode: 0644]
libtomcrypt/src/headers/tomcrypt_hash.h [new file with mode: 0644]
libtomcrypt/src/headers/tomcrypt_mac.h [new file with mode: 0644]
libtomcrypt/src/headers/tomcrypt_macros.h [new file with mode: 0644]
libtomcrypt/src/headers/tomcrypt_math.h [new file with mode: 0644]
libtomcrypt/src/headers/tomcrypt_misc.h [new file with mode: 0644]
libtomcrypt/src/headers/tomcrypt_pk.h [new file with mode: 0644]
libtomcrypt/src/headers/tomcrypt_pkcs.h [new file with mode: 0644]
libtomcrypt/src/headers/tomcrypt_prng.h [new file with mode: 0644]
libtomcrypt/src/mac/blake2/blake2bmac.c [new file with mode: 0644]
libtomcrypt/src/mac/blake2/blake2bmac_file.c [new file with mode: 0644]
libtomcrypt/src/mac/blake2/blake2bmac_memory.c [new file with mode: 0644]
libtomcrypt/src/mac/blake2/blake2bmac_memory_multi.c [new file with mode: 0644]
libtomcrypt/src/mac/blake2/blake2bmac_test.c [new file with mode: 0644]
libtomcrypt/src/mac/blake2/blake2smac.c [new file with mode: 0644]
libtomcrypt/src/mac/blake2/blake2smac_file.c [new file with mode: 0644]
libtomcrypt/src/mac/blake2/blake2smac_memory.c [new file with mode: 0644]
libtomcrypt/src/mac/blake2/blake2smac_memory_multi.c [new file with mode: 0644]
libtomcrypt/src/mac/blake2/blake2smac_test.c [new file with mode: 0644]
libtomcrypt/src/mac/f9/f9_done.c [new file with mode: 0644]
libtomcrypt/src/mac/f9/f9_file.c [new file with mode: 0644]
libtomcrypt/src/mac/f9/f9_init.c [new file with mode: 0644]
libtomcrypt/src/mac/f9/f9_memory.c [new file with mode: 0644]
libtomcrypt/src/mac/f9/f9_memory_multi.c [new file with mode: 0644]
libtomcrypt/src/mac/f9/f9_process.c [new file with mode: 0644]
libtomcrypt/src/mac/f9/f9_test.c [new file with mode: 0644]
libtomcrypt/src/mac/hmac/hmac_done.c [new file with mode: 0644]
libtomcrypt/src/mac/hmac/hmac_file.c [new file with mode: 0644]
libtomcrypt/src/mac/hmac/hmac_init.c [new file with mode: 0644]
libtomcrypt/src/mac/hmac/hmac_memory.c [new file with mode: 0644]
libtomcrypt/src/mac/hmac/hmac_memory_multi.c [new file with mode: 0644]
libtomcrypt/src/mac/hmac/hmac_process.c [new file with mode: 0644]
libtomcrypt/src/mac/hmac/hmac_test.c [new file with mode: 0644]
libtomcrypt/src/mac/omac/omac_done.c [new file with mode: 0644]
libtomcrypt/src/mac/omac/omac_file.c [new file with mode: 0644]
libtomcrypt/src/mac/omac/omac_init.c [new file with mode: 0644]
libtomcrypt/src/mac/omac/omac_memory.c [new file with mode: 0644]
libtomcrypt/src/mac/omac/omac_memory_multi.c [new file with mode: 0644]
libtomcrypt/src/mac/omac/omac_process.c [new file with mode: 0644]
libtomcrypt/src/mac/omac/omac_test.c [new file with mode: 0644]
libtomcrypt/src/mac/pelican/pelican.c [new file with mode: 0644]
libtomcrypt/src/mac/pelican/pelican_memory.c [new file with mode: 0644]
libtomcrypt/src/mac/pelican/pelican_test.c [new file with mode: 0644]
libtomcrypt/src/mac/pmac/pmac_done.c [new file with mode: 0644]
libtomcrypt/src/mac/pmac/pmac_file.c [new file with mode: 0644]
libtomcrypt/src/mac/pmac/pmac_init.c [new file with mode: 0644]
libtomcrypt/src/mac/pmac/pmac_memory.c [new file with mode: 0644]
libtomcrypt/src/mac/pmac/pmac_memory_multi.c [new file with mode: 0644]
libtomcrypt/src/mac/pmac/pmac_ntz.c [new file with mode: 0644]
libtomcrypt/src/mac/pmac/pmac_process.c [new file with mode: 0644]
libtomcrypt/src/mac/pmac/pmac_shift_xor.c [new file with mode: 0644]
libtomcrypt/src/mac/pmac/pmac_test.c [new file with mode: 0644]
libtomcrypt/src/mac/poly1305/poly1305.c [new file with mode: 0644]
libtomcrypt/src/mac/poly1305/poly1305_file.c [new file with mode: 0644]
libtomcrypt/src/mac/poly1305/poly1305_memory.c [new file with mode: 0644]
libtomcrypt/src/mac/poly1305/poly1305_memory_multi.c [new file with mode: 0644]
libtomcrypt/src/mac/poly1305/poly1305_test.c [new file with mode: 0644]
libtomcrypt/src/mac/xcbc/xcbc_done.c [new file with mode: 0644]
libtomcrypt/src/mac/xcbc/xcbc_file.c [new file with mode: 0644]
libtomcrypt/src/mac/xcbc/xcbc_init.c [new file with mode: 0644]
libtomcrypt/src/mac/xcbc/xcbc_memory.c [new file with mode: 0644]
libtomcrypt/src/mac/xcbc/xcbc_memory_multi.c [new file with mode: 0644]
libtomcrypt/src/mac/xcbc/xcbc_process.c [new file with mode: 0644]
libtomcrypt/src/mac/xcbc/xcbc_test.c [new file with mode: 0644]
libtomcrypt/src/math/fp/ltc_ecc_fp_mulmod.c [new file with mode: 0644]
libtomcrypt/src/math/gmp_desc.c [new file with mode: 0644]
libtomcrypt/src/math/ltm_desc.c [new file with mode: 0644]
libtomcrypt/src/math/multi.c [new file with mode: 0644]
libtomcrypt/src/math/radix_to_bin.c [new file with mode: 0644]
libtomcrypt/src/math/rand_bn.c [new file with mode: 0644]
libtomcrypt/src/math/rand_prime.c [new file with mode: 0644]
libtomcrypt/src/math/tfm_desc.c [new file with mode: 0644]
libtomcrypt/src/misc/adler32.c [new file with mode: 0644]
libtomcrypt/src/misc/base64/base64_decode.c [new file with mode: 0644]
libtomcrypt/src/misc/base64/base64_encode.c [new file with mode: 0644]
libtomcrypt/src/misc/burn_stack.c [new file with mode: 0644]
libtomcrypt/src/misc/compare_testvector.c [new file with mode: 0644]
libtomcrypt/src/misc/crc32.c [new file with mode: 0644]
libtomcrypt/src/misc/crypt/crypt.c [new file with mode: 0644]
libtomcrypt/src/misc/crypt/crypt_argchk.c [new file with mode: 0644]
libtomcrypt/src/misc/crypt/crypt_cipher_descriptor.c [new file with mode: 0644]
libtomcrypt/src/misc/crypt/crypt_cipher_is_valid.c [new file with mode: 0644]
libtomcrypt/src/misc/crypt/crypt_constants.c [new file with mode: 0644]
libtomcrypt/src/misc/crypt/crypt_find_cipher.c [new file with mode: 0644]
libtomcrypt/src/misc/crypt/crypt_find_cipher_any.c [new file with mode: 0644]
libtomcrypt/src/misc/crypt/crypt_find_cipher_id.c [new file with mode: 0644]
libtomcrypt/src/misc/crypt/crypt_find_hash.c [new file with mode: 0644]
libtomcrypt/src/misc/crypt/crypt_find_hash_any.c [new file with mode: 0644]
libtomcrypt/src/misc/crypt/crypt_find_hash_id.c [new file with mode: 0644]
libtomcrypt/src/misc/crypt/crypt_find_hash_oid.c [new file with mode: 0644]
libtomcrypt/src/misc/crypt/crypt_find_prng.c [new file with mode: 0644]
libtomcrypt/src/misc/crypt/crypt_fsa.c [new file with mode: 0644]
libtomcrypt/src/misc/crypt/crypt_hash_descriptor.c [new file with mode: 0644]
libtomcrypt/src/misc/crypt/crypt_hash_is_valid.c [new file with mode: 0644]
libtomcrypt/src/misc/crypt/crypt_inits.c [new file with mode: 0644]
libtomcrypt/src/misc/crypt/crypt_ltc_mp_descriptor.c [new file with mode: 0644]
libtomcrypt/src/misc/crypt/crypt_prng_descriptor.c [new file with mode: 0644]
libtomcrypt/src/misc/crypt/crypt_prng_is_valid.c [new file with mode: 0644]
libtomcrypt/src/misc/crypt/crypt_prng_rng_descriptor.c [new file with mode: 0644]
libtomcrypt/src/misc/crypt/crypt_register_all_ciphers.c [new file with mode: 0644]
libtomcrypt/src/misc/crypt/crypt_register_all_hashes.c [new file with mode: 0644]
libtomcrypt/src/misc/crypt/crypt_register_all_prngs.c [new file with mode: 0644]
libtomcrypt/src/misc/crypt/crypt_register_cipher.c [new file with mode: 0644]
libtomcrypt/src/misc/crypt/crypt_register_hash.c [new file with mode: 0644]
libtomcrypt/src/misc/crypt/crypt_register_prng.c [new file with mode: 0644]
libtomcrypt/src/misc/crypt/crypt_sizes.c [new file with mode: 0644]
libtomcrypt/src/misc/crypt/crypt_unregister_cipher.c [new file with mode: 0644]
libtomcrypt/src/misc/crypt/crypt_unregister_hash.c [new file with mode: 0644]
libtomcrypt/src/misc/crypt/crypt_unregister_prng.c [new file with mode: 0644]
libtomcrypt/src/misc/error_to_string.c [new file with mode: 0644]
libtomcrypt/src/misc/hkdf/hkdf.c [new file with mode: 0644]
libtomcrypt/src/misc/hkdf/hkdf_test.c [new file with mode: 0644]
libtomcrypt/src/misc/mem_neq.c [new file with mode: 0644]
libtomcrypt/src/misc/pk_get_oid.c [new file with mode: 0644]
libtomcrypt/src/misc/pkcs5/pkcs_5_1.c [new file with mode: 0644]
libtomcrypt/src/misc/pkcs5/pkcs_5_2.c [new file with mode: 0644]
libtomcrypt/src/misc/pkcs5/pkcs_5_test.c [new file with mode: 0644]
libtomcrypt/src/misc/zeromem.c [new file with mode: 0644]
libtomcrypt/src/modes/cbc/cbc_decrypt.c [new file with mode: 0644]
libtomcrypt/src/modes/cbc/cbc_done.c [new file with mode: 0644]
libtomcrypt/src/modes/cbc/cbc_encrypt.c [new file with mode: 0644]
libtomcrypt/src/modes/cbc/cbc_getiv.c [new file with mode: 0644]
libtomcrypt/src/modes/cbc/cbc_setiv.c [new file with mode: 0644]
libtomcrypt/src/modes/cbc/cbc_start.c [new file with mode: 0644]
libtomcrypt/src/modes/cfb/cfb_decrypt.c [new file with mode: 0644]
libtomcrypt/src/modes/cfb/cfb_done.c [new file with mode: 0644]
libtomcrypt/src/modes/cfb/cfb_encrypt.c [new file with mode: 0644]
libtomcrypt/src/modes/cfb/cfb_getiv.c [new file with mode: 0644]
libtomcrypt/src/modes/cfb/cfb_setiv.c [new file with mode: 0644]
libtomcrypt/src/modes/cfb/cfb_start.c [new file with mode: 0644]
libtomcrypt/src/modes/ctr/ctr_decrypt.c [new file with mode: 0644]
libtomcrypt/src/modes/ctr/ctr_done.c [new file with mode: 0644]
libtomcrypt/src/modes/ctr/ctr_encrypt.c [new file with mode: 0644]
libtomcrypt/src/modes/ctr/ctr_getiv.c [new file with mode: 0644]
libtomcrypt/src/modes/ctr/ctr_setiv.c [new file with mode: 0644]
libtomcrypt/src/modes/ctr/ctr_start.c [new file with mode: 0644]
libtomcrypt/src/modes/ctr/ctr_test.c [new file with mode: 0644]
libtomcrypt/src/modes/ecb/ecb_decrypt.c [new file with mode: 0644]
libtomcrypt/src/modes/ecb/ecb_done.c [new file with mode: 0644]
libtomcrypt/src/modes/ecb/ecb_encrypt.c [new file with mode: 0644]
libtomcrypt/src/modes/ecb/ecb_start.c [new file with mode: 0644]
libtomcrypt/src/modes/f8/f8_decrypt.c [new file with mode: 0644]
libtomcrypt/src/modes/f8/f8_done.c [new file with mode: 0644]
libtomcrypt/src/modes/f8/f8_encrypt.c [new file with mode: 0644]
libtomcrypt/src/modes/f8/f8_getiv.c [new file with mode: 0644]
libtomcrypt/src/modes/f8/f8_setiv.c [new file with mode: 0644]
libtomcrypt/src/modes/f8/f8_start.c [new file with mode: 0644]
libtomcrypt/src/modes/f8/f8_test_mode.c [new file with mode: 0644]
libtomcrypt/src/modes/lrw/lrw_decrypt.c [new file with mode: 0644]
libtomcrypt/src/modes/lrw/lrw_done.c [new file with mode: 0644]
libtomcrypt/src/modes/lrw/lrw_encrypt.c [new file with mode: 0644]
libtomcrypt/src/modes/lrw/lrw_getiv.c [new file with mode: 0644]
libtomcrypt/src/modes/lrw/lrw_process.c [new file with mode: 0644]
libtomcrypt/src/modes/lrw/lrw_setiv.c [new file with mode: 0644]
libtomcrypt/src/modes/lrw/lrw_start.c [new file with mode: 0644]
libtomcrypt/src/modes/lrw/lrw_test.c [new file with mode: 0644]
libtomcrypt/src/modes/ofb/ofb_decrypt.c [new file with mode: 0644]
libtomcrypt/src/modes/ofb/ofb_done.c [new file with mode: 0644]
libtomcrypt/src/modes/ofb/ofb_encrypt.c [new file with mode: 0644]
libtomcrypt/src/modes/ofb/ofb_getiv.c [new file with mode: 0644]
libtomcrypt/src/modes/ofb/ofb_setiv.c [new file with mode: 0644]
libtomcrypt/src/modes/ofb/ofb_start.c [new file with mode: 0644]
libtomcrypt/src/modes/xts/xts_decrypt.c [new file with mode: 0644]
libtomcrypt/src/modes/xts/xts_done.c [new file with mode: 0644]
libtomcrypt/src/modes/xts/xts_encrypt.c [new file with mode: 0644]
libtomcrypt/src/modes/xts/xts_init.c [new file with mode: 0644]
libtomcrypt/src/modes/xts/xts_mult_x.c [new file with mode: 0644]
libtomcrypt/src/modes/xts/xts_test.c [new file with mode: 0644]
libtomcrypt/src/pk/asn1/der/bit/der_decode_bit_string.c [new file with mode: 0644]
libtomcrypt/src/pk/asn1/der/bit/der_decode_raw_bit_string.c [new file with mode: 0644]
libtomcrypt/src/pk/asn1/der/bit/der_encode_bit_string.c [new file with mode: 0644]
libtomcrypt/src/pk/asn1/der/bit/der_encode_raw_bit_string.c [new file with mode: 0644]
libtomcrypt/src/pk/asn1/der/bit/der_length_bit_string.c [new file with mode: 0644]
libtomcrypt/src/pk/asn1/der/boolean/der_decode_boolean.c [new file with mode: 0644]
libtomcrypt/src/pk/asn1/der/boolean/der_encode_boolean.c [new file with mode: 0644]
libtomcrypt/src/pk/asn1/der/boolean/der_length_boolean.c [new file with mode: 0644]
libtomcrypt/src/pk/asn1/der/choice/der_decode_choice.c [new file with mode: 0644]
libtomcrypt/src/pk/asn1/der/generalizedtime/der_decode_generalizedtime.c [new file with mode: 0644]
libtomcrypt/src/pk/asn1/der/generalizedtime/der_encode_generalizedtime.c [new file with mode: 0644]
libtomcrypt/src/pk/asn1/der/generalizedtime/der_length_generalizedtime.c [new file with mode: 0644]
libtomcrypt/src/pk/asn1/der/ia5/der_decode_ia5_string.c [new file with mode: 0644]
libtomcrypt/src/pk/asn1/der/ia5/der_encode_ia5_string.c [new file with mode: 0644]
libtomcrypt/src/pk/asn1/der/ia5/der_length_ia5_string.c [new file with mode: 0644]
libtomcrypt/src/pk/asn1/der/integer/der_decode_integer.c [new file with mode: 0644]
libtomcrypt/src/pk/asn1/der/integer/der_encode_integer.c [new file with mode: 0644]
libtomcrypt/src/pk/asn1/der/integer/der_length_integer.c [new file with mode: 0644]
libtomcrypt/src/pk/asn1/der/object_identifier/der_decode_object_identifier.c [new file with mode: 0644]
libtomcrypt/src/pk/asn1/der/object_identifier/der_encode_object_identifier.c [new file with mode: 0644]
libtomcrypt/src/pk/asn1/der/object_identifier/der_length_object_identifier.c [new file with mode: 0644]
libtomcrypt/src/pk/asn1/der/octet/der_decode_octet_string.c [new file with mode: 0644]
libtomcrypt/src/pk/asn1/der/octet/der_encode_octet_string.c [new file with mode: 0644]
libtomcrypt/src/pk/asn1/der/octet/der_length_octet_string.c [new file with mode: 0644]
libtomcrypt/src/pk/asn1/der/printable_string/der_decode_printable_string.c [new file with mode: 0644]
libtomcrypt/src/pk/asn1/der/printable_string/der_encode_printable_string.c [new file with mode: 0644]
libtomcrypt/src/pk/asn1/der/printable_string/der_length_printable_string.c [new file with mode: 0644]
libtomcrypt/src/pk/asn1/der/sequence/der_decode_sequence_ex.c [new file with mode: 0644]
libtomcrypt/src/pk/asn1/der/sequence/der_decode_sequence_flexi.c [new file with mode: 0644]
libtomcrypt/src/pk/asn1/der/sequence/der_decode_sequence_multi.c [new file with mode: 0644]
libtomcrypt/src/pk/asn1/der/sequence/der_decode_subject_public_key_info.c [new file with mode: 0644]
libtomcrypt/src/pk/asn1/der/sequence/der_encode_sequence_ex.c [new file with mode: 0644]
libtomcrypt/src/pk/asn1/der/sequence/der_encode_sequence_multi.c [new file with mode: 0644]
libtomcrypt/src/pk/asn1/der/sequence/der_encode_subject_public_key_info.c [new file with mode: 0644]
libtomcrypt/src/pk/asn1/der/sequence/der_length_sequence.c [new file with mode: 0644]
libtomcrypt/src/pk/asn1/der/sequence/der_sequence_free.c [new file with mode: 0644]
libtomcrypt/src/pk/asn1/der/sequence/der_sequence_shrink.c [new file with mode: 0644]
libtomcrypt/src/pk/asn1/der/set/der_encode_set.c [new file with mode: 0644]
libtomcrypt/src/pk/asn1/der/set/der_encode_setof.c [new file with mode: 0644]
libtomcrypt/src/pk/asn1/der/short_integer/der_decode_short_integer.c [new file with mode: 0644]
libtomcrypt/src/pk/asn1/der/short_integer/der_encode_short_integer.c [new file with mode: 0644]
libtomcrypt/src/pk/asn1/der/short_integer/der_length_short_integer.c [new file with mode: 0644]
libtomcrypt/src/pk/asn1/der/teletex_string/der_decode_teletex_string.c [new file with mode: 0644]
libtomcrypt/src/pk/asn1/der/teletex_string/der_length_teletex_string.c [new file with mode: 0644]
libtomcrypt/src/pk/asn1/der/utctime/der_decode_utctime.c [new file with mode: 0644]
libtomcrypt/src/pk/asn1/der/utctime/der_encode_utctime.c [new file with mode: 0644]
libtomcrypt/src/pk/asn1/der/utctime/der_length_utctime.c [new file with mode: 0644]
libtomcrypt/src/pk/asn1/der/utf8/der_decode_utf8_string.c [new file with mode: 0644]
libtomcrypt/src/pk/asn1/der/utf8/der_encode_utf8_string.c [new file with mode: 0644]
libtomcrypt/src/pk/asn1/der/utf8/der_length_utf8_string.c [new file with mode: 0644]
libtomcrypt/src/pk/dh/dh.c [new file with mode: 0644]
libtomcrypt/src/pk/dh/dh_check_pubkey.c [new file with mode: 0644]
libtomcrypt/src/pk/dh/dh_export.c [new file with mode: 0644]
libtomcrypt/src/pk/dh/dh_export_key.c [new file with mode: 0644]
libtomcrypt/src/pk/dh/dh_free.c [new file with mode: 0644]
libtomcrypt/src/pk/dh/dh_generate_key.c [new file with mode: 0644]
libtomcrypt/src/pk/dh/dh_import.c [new file with mode: 0644]
libtomcrypt/src/pk/dh/dh_set.c [new file with mode: 0644]
libtomcrypt/src/pk/dh/dh_set_pg_dhparam.c [new file with mode: 0644]
libtomcrypt/src/pk/dh/dh_shared_secret.c [new file with mode: 0644]
libtomcrypt/src/pk/dsa/dsa_decrypt_key.c [new file with mode: 0644]
libtomcrypt/src/pk/dsa/dsa_encrypt_key.c [new file with mode: 0644]
libtomcrypt/src/pk/dsa/dsa_export.c [new file with mode: 0644]
libtomcrypt/src/pk/dsa/dsa_free.c [new file with mode: 0644]
libtomcrypt/src/pk/dsa/dsa_generate_key.c [new file with mode: 0644]
libtomcrypt/src/pk/dsa/dsa_generate_pqg.c [new file with mode: 0644]
libtomcrypt/src/pk/dsa/dsa_import.c [new file with mode: 0644]
libtomcrypt/src/pk/dsa/dsa_make_key.c [new file with mode: 0644]
libtomcrypt/src/pk/dsa/dsa_set.c [new file with mode: 0644]
libtomcrypt/src/pk/dsa/dsa_set_pqg_dsaparam.c [new file with mode: 0644]
libtomcrypt/src/pk/dsa/dsa_shared_secret.c [new file with mode: 0644]
libtomcrypt/src/pk/dsa/dsa_sign_hash.c [new file with mode: 0644]
libtomcrypt/src/pk/dsa/dsa_verify_hash.c [new file with mode: 0644]
libtomcrypt/src/pk/dsa/dsa_verify_key.c [new file with mode: 0644]
libtomcrypt/src/pk/ecc/ecc.c [new file with mode: 0644]
libtomcrypt/src/pk/ecc/ecc_ansi_x963_export.c [new file with mode: 0644]
libtomcrypt/src/pk/ecc/ecc_ansi_x963_import.c [new file with mode: 0644]
libtomcrypt/src/pk/ecc/ecc_decrypt_key.c [new file with mode: 0644]
libtomcrypt/src/pk/ecc/ecc_encrypt_key.c [new file with mode: 0644]
libtomcrypt/src/pk/ecc/ecc_export.c [new file with mode: 0644]
libtomcrypt/src/pk/ecc/ecc_free.c [new file with mode: 0644]
libtomcrypt/src/pk/ecc/ecc_get_size.c [new file with mode: 0644]
libtomcrypt/src/pk/ecc/ecc_import.c [new file with mode: 0644]
libtomcrypt/src/pk/ecc/ecc_make_key.c [new file with mode: 0644]
libtomcrypt/src/pk/ecc/ecc_shared_secret.c [new file with mode: 0644]
libtomcrypt/src/pk/ecc/ecc_sign_hash.c [new file with mode: 0644]
libtomcrypt/src/pk/ecc/ecc_sizes.c [new file with mode: 0644]
libtomcrypt/src/pk/ecc/ecc_test.c [new file with mode: 0644]
libtomcrypt/src/pk/ecc/ecc_verify_hash.c [new file with mode: 0644]
libtomcrypt/src/pk/ecc/ltc_ecc_is_valid_idx.c [new file with mode: 0644]
libtomcrypt/src/pk/ecc/ltc_ecc_map.c [new file with mode: 0644]
libtomcrypt/src/pk/ecc/ltc_ecc_mul2add.c [new file with mode: 0644]
libtomcrypt/src/pk/ecc/ltc_ecc_mulmod.c [new file with mode: 0644]
libtomcrypt/src/pk/ecc/ltc_ecc_mulmod_timing.c [new file with mode: 0644]
libtomcrypt/src/pk/ecc/ltc_ecc_points.c [new file with mode: 0644]
libtomcrypt/src/pk/ecc/ltc_ecc_projective_add_point.c [new file with mode: 0644]
libtomcrypt/src/pk/ecc/ltc_ecc_projective_dbl_point.c [new file with mode: 0644]
libtomcrypt/src/pk/katja/katja_decrypt_key.c [new file with mode: 0644]
libtomcrypt/src/pk/katja/katja_encrypt_key.c [new file with mode: 0644]
libtomcrypt/src/pk/katja/katja_export.c [new file with mode: 0644]
libtomcrypt/src/pk/katja/katja_exptmod.c [new file with mode: 0644]
libtomcrypt/src/pk/katja/katja_free.c [new file with mode: 0644]
libtomcrypt/src/pk/katja/katja_import.c [new file with mode: 0644]
libtomcrypt/src/pk/katja/katja_make_key.c [new file with mode: 0644]
libtomcrypt/src/pk/pkcs1/pkcs_1_i2osp.c [new file with mode: 0644]
libtomcrypt/src/pk/pkcs1/pkcs_1_mgf1.c [new file with mode: 0644]
libtomcrypt/src/pk/pkcs1/pkcs_1_oaep_decode.c [new file with mode: 0644]
libtomcrypt/src/pk/pkcs1/pkcs_1_oaep_encode.c [new file with mode: 0644]
libtomcrypt/src/pk/pkcs1/pkcs_1_os2ip.c [new file with mode: 0644]
libtomcrypt/src/pk/pkcs1/pkcs_1_pss_decode.c [new file with mode: 0644]
libtomcrypt/src/pk/pkcs1/pkcs_1_pss_encode.c [new file with mode: 0644]
libtomcrypt/src/pk/pkcs1/pkcs_1_v1_5_decode.c [new file with mode: 0644]
libtomcrypt/src/pk/pkcs1/pkcs_1_v1_5_encode.c [new file with mode: 0644]
libtomcrypt/src/pk/rsa/rsa_decrypt_key.c [new file with mode: 0644]
libtomcrypt/src/pk/rsa/rsa_encrypt_key.c [new file with mode: 0644]
libtomcrypt/src/pk/rsa/rsa_export.c [new file with mode: 0644]
libtomcrypt/src/pk/rsa/rsa_exptmod.c [new file with mode: 0644]
libtomcrypt/src/pk/rsa/rsa_free.c [new file with mode: 0644]
libtomcrypt/src/pk/rsa/rsa_get_size.c [new file with mode: 0644]
libtomcrypt/src/pk/rsa/rsa_import.c [new file with mode: 0644]
libtomcrypt/src/pk/rsa/rsa_import_pkcs8.c [new file with mode: 0644]
libtomcrypt/src/pk/rsa/rsa_import_x509.c [new file with mode: 0644]
libtomcrypt/src/pk/rsa/rsa_make_key.c [new file with mode: 0644]
libtomcrypt/src/pk/rsa/rsa_set.c [new file with mode: 0644]
libtomcrypt/src/pk/rsa/rsa_sign_hash.c [new file with mode: 0644]
libtomcrypt/src/pk/rsa/rsa_sign_saltlen_get.c [new file with mode: 0644]
libtomcrypt/src/pk/rsa/rsa_verify_hash.c [new file with mode: 0644]
libtomcrypt/src/prngs/chacha20.c [new file with mode: 0644]
libtomcrypt/src/prngs/fortuna.c [new file with mode: 0644]
libtomcrypt/src/prngs/rc4.c [new file with mode: 0644]
libtomcrypt/src/prngs/rng_get_bytes.c [new file with mode: 0644]
libtomcrypt/src/prngs/rng_make_prng.c [new file with mode: 0644]
libtomcrypt/src/prngs/sober128.c [new file with mode: 0644]
libtomcrypt/src/prngs/sprng.c [new file with mode: 0644]
libtomcrypt/src/prngs/yarrow.c [new file with mode: 0644]
libtomcrypt/src/stream/chacha/chacha_crypt.c [new file with mode: 0644]
libtomcrypt/src/stream/chacha/chacha_done.c [new file with mode: 0644]
libtomcrypt/src/stream/chacha/chacha_ivctr32.c [new file with mode: 0644]
libtomcrypt/src/stream/chacha/chacha_ivctr64.c [new file with mode: 0644]
libtomcrypt/src/stream/chacha/chacha_keystream.c [new file with mode: 0644]
libtomcrypt/src/stream/chacha/chacha_setup.c [new file with mode: 0644]
libtomcrypt/src/stream/chacha/chacha_test.c [new file with mode: 0644]
libtomcrypt/src/stream/rc4/rc4_stream.c [new file with mode: 0644]
libtomcrypt/src/stream/rc4/rc4_test.c [new file with mode: 0644]
libtomcrypt/src/stream/sober128/sober128_stream.c [new file with mode: 0644]
libtomcrypt/src/stream/sober128/sober128_test.c [new file with mode: 0644]
libtomcrypt/src/stream/sober128/sober128tab.c [new file with mode: 0644]
tomsfastmath/src/addsub/fp_add.c [new file with mode: 0644]
tomsfastmath/src/addsub/fp_add_d.c [new file with mode: 0644]
tomsfastmath/src/addsub/fp_addmod.c [new file with mode: 0644]
tomsfastmath/src/addsub/fp_cmp.c [new file with mode: 0644]
tomsfastmath/src/addsub/fp_cmp_d.c [new file with mode: 0644]
tomsfastmath/src/addsub/fp_cmp_mag.c [new file with mode: 0644]
tomsfastmath/src/addsub/fp_sub.c [new file with mode: 0644]
tomsfastmath/src/addsub/fp_sub_d.c [new file with mode: 0644]
tomsfastmath/src/addsub/fp_submod.c [new file with mode: 0644]
tomsfastmath/src/addsub/s_fp_add.c [new file with mode: 0644]
tomsfastmath/src/addsub/s_fp_sub.c [new file with mode: 0644]
tomsfastmath/src/bin/fp_radix_size.c [new file with mode: 0644]
tomsfastmath/src/bin/fp_read_radix.c [new file with mode: 0644]
tomsfastmath/src/bin/fp_read_signed_bin.c [new file with mode: 0644]
tomsfastmath/src/bin/fp_read_unsigned_bin.c [new file with mode: 0644]
tomsfastmath/src/bin/fp_reverse.c [new file with mode: 0644]
tomsfastmath/src/bin/fp_s_rmap.c [new file with mode: 0644]
tomsfastmath/src/bin/fp_signed_bin_size.c [new file with mode: 0644]
tomsfastmath/src/bin/fp_to_signed_bin.c [new file with mode: 0644]
tomsfastmath/src/bin/fp_to_unsigned_bin.c [new file with mode: 0644]
tomsfastmath/src/bin/fp_toradix.c [new file with mode: 0644]
tomsfastmath/src/bin/fp_toradix_n.c [new file with mode: 0644]
tomsfastmath/src/bin/fp_unsigned_bin_size.c [new file with mode: 0644]
tomsfastmath/src/bit/fp_cnt_lsb.c [new file with mode: 0644]
tomsfastmath/src/bit/fp_count_bits.c [new file with mode: 0644]
tomsfastmath/src/bit/fp_div_2.c [new file with mode: 0644]
tomsfastmath/src/bit/fp_div_2d.c [new file with mode: 0644]
tomsfastmath/src/bit/fp_lshd.c [new file with mode: 0644]
tomsfastmath/src/bit/fp_mod_2d.c [new file with mode: 0644]
tomsfastmath/src/bit/fp_rshd.c [new file with mode: 0644]
tomsfastmath/src/divide/fp_div.c [new file with mode: 0644]
tomsfastmath/src/divide/fp_div_d.c [new file with mode: 0644]
tomsfastmath/src/divide/fp_mod.c [new file with mode: 0644]
tomsfastmath/src/divide/fp_mod_d.c [new file with mode: 0644]
tomsfastmath/src/exptmod/fp_2expt.c [new file with mode: 0644]
tomsfastmath/src/exptmod/fp_exptmod.c [new file with mode: 0644]
tomsfastmath/src/generators/comba_mont_gen.c [new file with mode: 0644]
tomsfastmath/src/generators/comba_mult_gen.c [new file with mode: 0644]
tomsfastmath/src/generators/comba_mult_smallgen.c [new file with mode: 0644]
tomsfastmath/src/generators/comba_sqr_gen.c [new file with mode: 0644]
tomsfastmath/src/generators/comba_sqr_smallgen.c [new file with mode: 0644]
tomsfastmath/src/headers/tfm.h [new file with mode: 0644]
tomsfastmath/src/headers/tfm_private.h [new file with mode: 0644]
tomsfastmath/src/misc/fp_ident.c [new file with mode: 0644]
tomsfastmath/src/misc/fp_rand.c [new file with mode: 0644]
tomsfastmath/src/misc/fp_set.c [new file with mode: 0644]
tomsfastmath/src/mont/fp_montgomery_calc_normalization.c [new file with mode: 0644]
tomsfastmath/src/mont/fp_montgomery_reduce.c [new file with mode: 0644]
tomsfastmath/src/mont/fp_montgomery_setup.c [new file with mode: 0644]
tomsfastmath/src/mul/fp_mul.c [new file with mode: 0644]
tomsfastmath/src/mul/fp_mul_2.c [new file with mode: 0644]
tomsfastmath/src/mul/fp_mul_2d.c [new file with mode: 0644]
tomsfastmath/src/mul/fp_mul_comba.c [new file with mode: 0644]
tomsfastmath/src/mul/fp_mul_comba_12.c [new file with mode: 0644]
tomsfastmath/src/mul/fp_mul_comba_17.c [new file with mode: 0644]
tomsfastmath/src/mul/fp_mul_comba_20.c [new file with mode: 0644]
tomsfastmath/src/mul/fp_mul_comba_24.c [new file with mode: 0644]
tomsfastmath/src/mul/fp_mul_comba_28.c [new file with mode: 0644]
tomsfastmath/src/mul/fp_mul_comba_3.c [new file with mode: 0644]
tomsfastmath/src/mul/fp_mul_comba_32.c [new file with mode: 0644]
tomsfastmath/src/mul/fp_mul_comba_4.c [new file with mode: 0644]
tomsfastmath/src/mul/fp_mul_comba_48.c [new file with mode: 0644]
tomsfastmath/src/mul/fp_mul_comba_6.c [new file with mode: 0644]
tomsfastmath/src/mul/fp_mul_comba_64.c [new file with mode: 0644]
tomsfastmath/src/mul/fp_mul_comba_7.c [new file with mode: 0644]
tomsfastmath/src/mul/fp_mul_comba_8.c [new file with mode: 0644]
tomsfastmath/src/mul/fp_mul_comba_9.c [new file with mode: 0644]
tomsfastmath/src/mul/fp_mul_comba_small_set.c [new file with mode: 0644]
tomsfastmath/src/mul/fp_mul_d.c [new file with mode: 0644]
tomsfastmath/src/mul/fp_mulmod.c [new file with mode: 0644]
tomsfastmath/src/numtheory/fp_gcd.c [new file with mode: 0644]
tomsfastmath/src/numtheory/fp_invmod.c [new file with mode: 0644]
tomsfastmath/src/numtheory/fp_isprime.c [new file with mode: 0644]
tomsfastmath/src/numtheory/fp_isprime_ex.c [new file with mode: 0644]
tomsfastmath/src/numtheory/fp_lcm.c [new file with mode: 0644]
tomsfastmath/src/numtheory/fp_prime_miller_rabin.c [new file with mode: 0644]
tomsfastmath/src/numtheory/fp_prime_random_ex.c [new file with mode: 0644]
tomsfastmath/src/sqr/fp_sqr.c [new file with mode: 0644]
tomsfastmath/src/sqr/fp_sqr_comba.c [new file with mode: 0644]
tomsfastmath/src/sqr/fp_sqr_comba_12.c [new file with mode: 0644]
tomsfastmath/src/sqr/fp_sqr_comba_17.c [new file with mode: 0644]
tomsfastmath/src/sqr/fp_sqr_comba_20.c [new file with mode: 0644]
tomsfastmath/src/sqr/fp_sqr_comba_24.c [new file with mode: 0644]
tomsfastmath/src/sqr/fp_sqr_comba_28.c [new file with mode: 0644]
tomsfastmath/src/sqr/fp_sqr_comba_3.c [new file with mode: 0644]
tomsfastmath/src/sqr/fp_sqr_comba_32.c [new file with mode: 0644]
tomsfastmath/src/sqr/fp_sqr_comba_4.c [new file with mode: 0644]
tomsfastmath/src/sqr/fp_sqr_comba_48.c [new file with mode: 0644]
tomsfastmath/src/sqr/fp_sqr_comba_6.c [new file with mode: 0644]
tomsfastmath/src/sqr/fp_sqr_comba_64.c [new file with mode: 0644]
tomsfastmath/src/sqr/fp_sqr_comba_7.c [new file with mode: 0644]
tomsfastmath/src/sqr/fp_sqr_comba_8.c [new file with mode: 0644]
tomsfastmath/src/sqr/fp_sqr_comba_9.c [new file with mode: 0644]
tomsfastmath/src/sqr/fp_sqr_comba_generic.c [new file with mode: 0644]
tomsfastmath/src/sqr/fp_sqr_comba_small_set.c [new file with mode: 0644]
tomsfastmath/src/sqr/fp_sqrmod.c [new file with mode: 0644]
zpm-fetchurl.c [new file with mode: 0644]
zpm-repo

index 5ffd76bac2b5d4a4f30a1acd2d63eee87f2589ba..5b677ca0356baa9eb73860836f9a30ccc6f70867 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -31,7 +31,7 @@ curdir=$(shell pwd)
 ZPKGBIN=zpm-addfile zpm-extract zpm-init zpm-vercmp zpm-stat zpm-hash \
        zpm-findpkg zpm-shell zpm-soneed zpm-foreach-path zpm-parse \
        zpm-script zpm-soname zpm-syncfs zpm-packagehash zpm-verify \
-       zpm-elftype zpm-quote zpm-note zpm-search zpm-add
+       zpm-elftype zpm-quote zpm-note zpm-search zpm-add zpm-fetchurl
 
 SCRIPTS=zpm zpm-install zpm-merge zpm-list zpm-preserve zpm-test zpm-log \
        zpm-contents zpm-uninstall zpm-pathmod zpm-rmpackage zpm-newpackage \
@@ -227,7 +227,7 @@ scalarmult.o
 
 TLSOBJ= tlse.o x25519.o chacha.o base64.o pem.o forward.o handshake.o \
        buffer.o parse_client_hello.o parse_message.o cipher_supported.o \
-       packet_update.o hmac_message.o hkdf.o hash.o
+       packet_update.o hmac_message.o hkdf.o hash.o cipher_name.o
 
 crypto/x25519.o: $(addprefix crypto/ref10/, $(X255OBJ))
        ld -o $@ -r $+
@@ -753,9 +753,15 @@ libtomcrypt/%.o: CFLAGS+=-DTFM_DESC -Isrc/headers -Itomsfastmath/src/headers -DA
 ltc.o: $(addprefix libtomcrypt/src/, $(LTCOBJ))
        ld -o $@ -r $+
 
-zpm-fetchurl.o: CFLAGS+=-DTFM_DESC -Isrc/headers -Itomsfastmath/src/headers -DARGTYPE=4 -DLTC_NO_ASM -DTFM_NO_ASM -Ilibtomcrypt/src/headers -DLTC_SOURCE -Icrypto
+crypto/rfc3986.c: crypto/rfc3986.re
+       re2c --input custom --tags -o $@ $<
 
-zpm-fetchurl: ltc.o tls.o tfm.o zpm-fetchurl.o crypto/https.o
+rfc3986: rfc3986.c
+       $(CC) -Wall -W -Wextra -Werror -o $@ $+
+
+zpm-fetchurl.o: CFLAGS+=-DTFM_DESC -Isrc/headers -Itomsfastmath/src/headers -DARGTYPE=4 -DLTC_NO_ASM -DTFM_NO_ASM -Ilibtomcrypt/src/headers -DLTC_SOURCE -Icrypto -Wno-pointer-sign -DDEBUG
+
+zpm-fetchurl: ltc.o tls.o tfm.o zpm-fetchurl.o crypto/https.o crypto/rfc3986.o
 
 testddg: zpm-fetchurl
        ./zpm-fetchurl duckduckgo.com 443 /
diff --git a/crypto/base64.c b/crypto/base64.c
new file mode 100644 (file)
index 0000000..1b944f4
--- /dev/null
@@ -0,0 +1,82 @@
+#define _POSIX_C_SOURCE 200809L
+
+#include <stdint.h>
+#include <stdlib.h>
+
+#define WHITESPACE 64
+#define EQUALS     65
+#define INVALID    66
+
+static const unsigned char d[] = {
+       66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 64, 66, 66, 66, 66, 66, 66,
+           66, 66, 66, 66, 66, 66, 66, 66,
+       66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66,
+           66, 62, 66, 66, 66, 63, 52, 53,
+       54, 55, 56, 57, 58, 59, 60, 61, 66, 66, 66, 65, 66, 66, 66, 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, 66,
+           66, 66, 66, 66, 66, 26, 27, 28,
+       29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45,
+           46, 47, 48, 49, 50, 51, 66, 66,
+       66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66,
+           66, 66, 66, 66, 66, 66, 66, 66,
+       66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66,
+           66, 66, 66, 66, 66, 66, 66, 66,
+       66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66,
+           66, 66, 66, 66, 66, 66, 66, 66,
+       66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66,
+           66, 66, 66, 66, 66, 66, 66, 66,
+       66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66,
+           66, 66, 66, 66, 66, 66, 66, 66,
+       66, 66, 66, 66, 66, 66
+};
+
+int base64decode(const char *in, size_t inLen, unsigned char *out,
+                size_t *outLen) {
+       const char *end = in + inLen;
+       char iter = 0;
+       uint32_t buf = 0;
+       size_t len = 0;
+
+       while (in < end) {
+               unsigned char c = d[(int)(*in++)];
+
+               switch (c) {
+               case WHITESPACE:
+                       continue;       /* skip whitespace */
+               case INVALID:
+                       return 0;       /* invalid input, return error */
+               case EQUALS:    /* pad character, end of data */
+                       in = end;
+                       continue;
+               default:
+                       buf = buf << 6 | c;
+                       iter++; // increment the number of iteration
+                       /* If the buffer is full, split it into bytes */
+                       if (iter == 4) {
+                               if ((len += 3) > *outLen)
+                                       return 0;       /* buffer overflow */
+                               *(out++) = (buf >> 16) & 255;
+                               *(out++) = (buf >> 8) & 255;
+                               *(out++) = buf & 255;
+                               buf = 0;
+                               iter = 0;
+
+                       }
+               }
+       }
+
+       if (iter == 3) {
+               if ((len += 2) > *outLen)
+                       return 0;       /* buffer overflow */
+               *(out++) = (buf >> 10) & 255;
+               *(out++) = (buf >> 2) & 255;
+       } else if (iter == 2) {
+               if (++len > *outLen)
+                       return 0;       /* buffer overflow */
+               *(out++) = (buf >> 4) & 255;
+       }
+
+       *outLen = len;          /* modify to reflect the actual output size */
+       return 1;
+}
diff --git a/crypto/buffer.c b/crypto/buffer.c
new file mode 100644 (file)
index 0000000..a65c21e
--- /dev/null
@@ -0,0 +1,257 @@
+#define _POSIX_C_SOURCE 200809L
+
+#include <string.h>
+#include <errno.h>
+
+#include "tlse.h"
+#include "buffer.h"
+
+void tls_buffer_init(struct tls_buffer *buffer, size_t initial) {
+       buffer->buffer = 0;
+       buffer->len = 0;
+       buffer->size = 0;
+       buffer->error = 0;
+       if (initial) {
+               errno = 0;
+               buffer->buffer = malloc(initial);
+               if (buffer->buffer) {
+                       memset(buffer->buffer, 0, initial);
+                       buffer->size = initial;
+               } else {
+                       buffer->error = errno;
+               }
+       }
+}
+
+void tls_buffer_compact(struct tls_buffer *b) {
+       void *new;
+
+       if (b->error || b->size == b->len) {
+               return;
+       }
+
+       errno = 0;
+       new = realloc(b->buffer, b->len);
+
+       if (new == NULL) {
+               b->error = errno;
+               return;
+       }
+
+       b->buffer = new;
+       return;
+}
+
+/* makes sure there's at least need bytes free */
+void tls_buffer_expand(struct tls_buffer *buf, size_t need) {
+       size_t want;
+
+       if (buf->error) {
+               return;
+       }
+
+       want = buf->len + need;
+
+       if (want <= buf->size) {
+               return;
+       }
+
+       errno = 0;
+       char *new = realloc(buf->buffer, want);
+       if (new) {
+               buf->buffer = new;
+               buf->size = want;
+               memset(buf->buffer + buf->len, 0, buf->size - buf->len);
+       } else {
+               buf->error = errno;
+       }
+}
+
+void tls_buffer_free(struct tls_buffer *buffer) {
+       /* TODO only zero out memory if it's "secure" buffer */
+       if (buffer->buffer && buffer->len) {
+               memset(buffer->buffer, 0, buffer->len);
+       }
+       free(buffer->buffer);
+       tls_buffer_init(buffer, 0);
+}
+
+void tls_buffer_set(struct tls_buffer *buffer, int ch) {
+       /* TODO only zero out memory if it's "secure" buffer */
+       if (buffer->buffer && buffer->size) {
+               memset(buffer->buffer, ch, buffer->size);
+       }
+}
+
+void tls_buffer_append(struct tls_buffer *buffer, const unsigned char *bytes, size_t n) {
+       tls_buffer_expand(buffer, n);
+
+       if (buffer->error || !bytes) {
+               return;
+       }
+
+       memcpy(buffer->buffer + buffer->len, bytes, n);
+       buffer->len += n;
+}
+
+void tls_buffer_append16(struct tls_buffer *buffer, uint16_t n) {
+       tls_buffer_expand(buffer, 2);
+
+       if (buffer->error) {
+               return;
+       }
+
+       buffer->buffer[buffer->len++] = (n >> 8) & 0xff;
+       buffer->buffer[buffer->len++] = n & 0xff;
+}
+
+void tls_buffer_append24(struct tls_buffer *buffer, uint32_t n) {
+       tls_buffer_expand(buffer, 3);
+
+       if (buffer->error) {
+               return;
+       }
+
+       buffer->buffer[buffer->len++] = (n >> 16) & 0xff;
+       buffer->buffer[buffer->len++] = (n >> 8) & 0xff;
+       buffer->buffer[buffer->len++] = n & 0xff;
+}
+
+void tls_buffer_append_byte(struct tls_buffer *buffer, uint8_t n) {
+       tls_buffer_expand(buffer, 1);
+
+       if (buffer->error) {
+               return;
+       }
+
+       buffer->buffer[buffer->len++] = n & 0xff;
+}
+
+void tls_buffer_write16(struct tls_buffer *buffer, uint16_t n, size_t at) {
+       if (at+2 > buffer->size) {
+               tls_buffer_expand(buffer, at+2 - buffer->size);
+       }
+
+       if (buffer->error) {
+               return;
+       }
+
+       buffer->buffer[at] = (n >> 8) & 0xff;
+       buffer->buffer[at+1] = n & 0xff;
+
+       if (at+2 > buffer->len) {
+               buffer->len = at + 2;
+       }
+}
+
+uint16_t tls_buffer_read16(struct tls_buffer *buffer, size_t at) {
+       uint16_t res = 0;
+
+       if (buffer->error || at+2 < buffer->len) {
+               return 0;
+       }
+
+       res = (buffer->buffer[at] << 8) + buffer->buffer[at+1];
+       return res;
+}
+
+uint64_t tls_buffer_readbe(struct tls_buffer *buffer, int bytes, size_t at) {
+       uint16_t res = 0;
+       int i;
+
+       if (buffer->error || at+bytes < buffer->len) {
+               return 0;
+       }
+
+       for (i=0; i<bytes; i++) {
+               res <<= 8;
+               res += buffer->buffer[at+i];
+       }
+
+       return res;
+}
+
+void tls_buffer_writebe(struct tls_buffer *buffer, int bytes, size_t at, uint64_t val) {
+       int i;
+       if (at+bytes > buffer->size) {
+               tls_buffer_expand(buffer, at+bytes - buffer->size);
+       }
+
+       if (buffer->error) {
+               return;
+       }
+
+       for (i=bytes-1; i>=0; i--) {
+               buffer->buffer[at+i] = val & 0xff;
+               val >>= 8;
+       }
+
+       return;
+}
+
+
+void tls_buffer_shift(struct tls_buffer *buffer, size_t n) {
+       if (buffer->error) {
+               return;
+       }
+
+       if (buffer->len < n) {
+               n = buffer->len;
+       }
+
+       if (n) {
+               memmove(buffer->buffer, buffer->buffer + n, buffer->len - n);
+               memset(buffer->buffer + buffer->len - n, 0, n);
+#if 0
+               fprintf(stderr, "memmove(%p, %p, %zu)\n", buffer->buffer,
+                               buffer->buffer+n, buffer->len - n);
+               fprintf(stderr, "memset(%p, %d, %zu)\n", buffer->buffer+n,
+                               0, n);
+#endif
+
+               buffer->len -= n;
+       }
+}
+
+/* make room at the beginning */
+void tls_buffer_unshift(struct tls_buffer *buffer, size_t n) {
+       tls_buffer_expand(buffer, n);
+
+       if (buffer->error) {
+               return;
+       }
+
+       memmove(buffer->buffer + n, buffer->buffer, n);
+       memset(buffer->buffer, 0, n);
+}
+
+#if 0
+uint32_t tls_buffer_next3(struct tls_buffer_reader *rb) {
+       uint32_t r;
+
+       r = tls_buffer_readbe(rb, 3, rb->cursor);
+       rb->cursor += 3;
+       return r;
+}
+
+uint16_t tls_buffer_next2(struct tls_buffer_reader *rb) {
+       uint16_t r;
+
+       r = tls_buffer_readbe(rb, 2, rb->cursor);
+       rb->cursor += 2;
+       return r;
+}
+
+uint8_t tls_buffer_next(struct tls_buffer_reader *rb) {
+       uint16_t r;
+
+       r = tls_buffer_readbe(rb, 2, rb->cursor);
+       rb->cursor += 2;
+
+}
+
+void tls_buffer_nextn(struct tls_buffer_reader *rb, unsigned char *b, size_t n) {
+       tls_buffer_read(rb, b, n, rb->cursor);
+       rb->cursor += n;
+}
+#endif
diff --git a/crypto/buffer.h b/crypto/buffer.h
new file mode 100644 (file)
index 0000000..ad37f67
--- /dev/null
@@ -0,0 +1,50 @@
+#ifndef TLS_BUFFER_H_
+#define TLS_BUFFER_H_ 1
+
+#include <stdint.h>
+#include <string.h>
+#include <errno.h>
+
+/* flags:
+ * 0x1 secure: zero memory when used
+ * 0x2 fixed: buffer doesn't belong to you, and size says how big it is
+ * 0x4 
+ */
+struct tls_buffer {
+       char *buffer;
+       size_t len;
+       size_t size;
+       int32_t error;
+       uint32_t flags;
+};
+
+struct tls_buffer_reader {
+       struct tls_buffer b;
+       size_t cursor;
+};
+
+uint32_t tls_buffer_next3(struct tls_buffer_reader *rb);
+uint16_t tls_buffer_next2(struct tls_buffer_reader *rb);
+uint8_t tls_buffer_next(struct tls_buffer_reader *rb);
+void tls_buffer_nextn(struct tls_buffer_reader *rb, unsigned char *b, size_t n);
+
+void tls_buffer_init(struct tls_buffer *b, size_t initial); 
+
+/* makes sure there's at least need bytes free */
+void tls_buffer_expand(struct tls_buffer *b, size_t need);
+void tls_buffer_free(struct tls_buffer *b);
+void tls_buffer_set(struct tls_buffer *buffer, int ch);
+void tls_buffer_compact(struct tls_buffer *b);
+void tls_buffer_append(struct tls_buffer *b, const unsigned char *bytes, size_t n);
+void tls_buffer_append16(struct tls_buffer *b, uint16_t n);
+void tls_buffer_append24(struct tls_buffer *b, uint32_t n);
+void tls_buffer_append_byte(struct tls_buffer *b, uint8_t n);
+void tls_buffer_shift(struct tls_buffer *b, size_t n);
+void tls_buffer_write16(struct tls_buffer *b, uint16_t n, size_t at);
+void tls_buffer_writebe(struct tls_buffer *b, int bytes, size_t at, uint64_t val);
+uint64_t tls_buffer_readbe(struct tls_buffer *b, int bytes, size_t at);
+
+/* make room at the beginning */
+void tls_buffer_unshift(struct tls_buffer *b, size_t n);
+
+#endif
diff --git a/crypto/chacha.c b/crypto/chacha.c
new file mode 100644 (file)
index 0000000..50d9c7e
--- /dev/null
@@ -0,0 +1,676 @@
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "chacha.h"
+
+typedef unsigned char u8;
+typedef unsigned int u32;
+
+typedef struct chacha_ctx chacha_ctx;
+
+#define U8C(v) (v##U)
+#define U32C(v) (v##U)
+
+#define U8V(v) ((u8)(v) & U8C(0xFF))
+#define U32V(v) ((u32)(v) & U32C(0xFFFFFFFF))
+
+#define ROTL32(v, n) \
+  (U32V((v) << (n)) | ((v) >> (32 - (n))))
+
+#define U8TO32_LITTLE(p) \
+  (((u32)((p)[0])) | \
+   ((u32)((p)[1]) <<  8) | \
+   ((u32)((p)[2]) << 16) | \
+   ((u32)((p)[3]) << 24))
+
+#define U32TO8_LITTLE(p, v) \
+  do { \
+    (p)[0] = U8V((v)); \
+    (p)[1] = U8V((v) >>  8); \
+    (p)[2] = U8V((v) >> 16); \
+    (p)[3] = U8V((v) >> 24); \
+  } while (0)
+
+#define ROTATE(v,c) (ROTL32(v,c))
+#define XOR(v,w) ((v) ^ (w))
+#define PLUS(v,w) (U32V((v) + (w)))
+#define PLUSONE(v) (PLUS((v),1))
+
+#define QUARTERROUND(a,b,c,d) \
+  a = PLUS(a,b); d = ROTATE(XOR(d,a),16); \
+  c = PLUS(c,d); b = ROTATE(XOR(b,c),12); \
+  a = PLUS(a,b); d = ROTATE(XOR(d,a), 8); \
+  c = PLUS(c,d); b = ROTATE(XOR(b,c), 7);
+
+static const char sigma[] = "expand 32-byte k";
+static const char tau[] = "expand 16-byte k";
+
+void chacha_keysetup(chacha_ctx * x, const u8 * k, u32 kbits) {
+       const char *constants;
+
+       x->input[4] = U8TO32_LITTLE(k + 0);
+       x->input[5] = U8TO32_LITTLE(k + 4);
+       x->input[6] = U8TO32_LITTLE(k + 8);
+       x->input[7] = U8TO32_LITTLE(k + 12);
+       if (kbits == 256) {     /* recommended */
+               k += 16;
+               constants = sigma;
+       } else {                /* kbits == 128 */
+               constants = tau;
+       }
+       x->input[8] = U8TO32_LITTLE(k + 0);
+       x->input[9] = U8TO32_LITTLE(k + 4);
+       x->input[10] = U8TO32_LITTLE(k + 8);
+       x->input[11] = U8TO32_LITTLE(k + 12);
+       x->input[0] = U8TO32_LITTLE(constants + 0);
+       x->input[1] = U8TO32_LITTLE(constants + 4);
+       x->input[2] = U8TO32_LITTLE(constants + 8);
+       x->input[3] = U8TO32_LITTLE(constants + 12);
+}
+
+void chacha_key(chacha_ctx * x, u8 * k) {
+       U32TO8_LITTLE(k, x->input[4]);
+       U32TO8_LITTLE(k + 4, x->input[5]);
+       U32TO8_LITTLE(k + 8, x->input[6]);
+       U32TO8_LITTLE(k + 12, x->input[7]);
+
+       U32TO8_LITTLE(k + 16, x->input[8]);
+       U32TO8_LITTLE(k + 20, x->input[9]);
+       U32TO8_LITTLE(k + 24, x->input[10]);
+       U32TO8_LITTLE(k + 28, x->input[11]);
+}
+
+void chacha_nonce(chacha_ctx * x, u8 * nonce) {
+       U32TO8_LITTLE(nonce + 0, x->input[13]);
+       U32TO8_LITTLE(nonce + 4, x->input[14]);
+       U32TO8_LITTLE(nonce + 8, x->input[15]);
+}
+
+void chacha_ivsetup(chacha_ctx * x, const u8 * iv, const u8 * counter) {
+       x->input[12] =
+           counter == NULL ? 0 : U8TO32_LITTLE(counter + 0);
+       x->input[13] =
+           counter == NULL ? 0 : U8TO32_LITTLE(counter + 4);
+       if (iv) {
+               x->input[14] = U8TO32_LITTLE(iv + 0);
+               x->input[15] = U8TO32_LITTLE(iv + 4);
+       }
+}
+
+void chacha_ivsetup_96bitnonce(chacha_ctx * x, const u8 * iv,
+                              const u8 * counter) {
+       x->input[12] =
+           counter == NULL ? 0 : U8TO32_LITTLE(counter + 0);
+       if (iv) {
+               x->input[13] = U8TO32_LITTLE(iv + 0);
+               x->input[14] = U8TO32_LITTLE(iv + 4);
+               x->input[15] = U8TO32_LITTLE(iv + 8);
+       }
+}
+
+void chacha_ivupdate(chacha_ctx * x, const uint8_t * iv,
+                    const uint8_t * aad, const uint8_t * counter) {
+       x->input[12] =
+           counter == NULL ? 0 : U8TO32_LITTLE(counter + 0);
+       x->input[13] = U8TO32_LITTLE(iv + 0);
+       x->input[14] =
+           U8TO32_LITTLE(iv +
+                                      4) ^
+           U8TO32_LITTLE(aad);
+       x->input[15] =
+           U8TO32_LITTLE(iv +
+                                      8) ^ U8TO32_LITTLE(aad
+                                                                      +
+                                                                      4);
+}
+
+void chacha_encrypt_bytes(chacha_ctx * x, const u8 * m, u8 * c, u32 bytes) {
+       u32 i;
+       u32 x0, x1, x2, x3, x4, x5, x6, x7;
+       u32 x8, x9, x10, x11, x12, x13, x14, x15;
+       u32 j0, j1, j2, j3, j4, j5, j6, j7;
+       u32 j8, j9, j10, j11, j12, j13, j14, j15;
+       u8 *ctarget = NULL;
+       u8 tmp[64];
+
+       if (!bytes) {
+               return;
+       }
+
+       j0 = x->input[0];
+       j1 = x->input[1];
+       j2 = x->input[2];
+       j3 = x->input[3];
+       j4 = x->input[4];
+       j5 = x->input[5];
+       j6 = x->input[6];
+       j7 = x->input[7];
+       j8 = x->input[8];
+       j9 = x->input[9];
+       j10 = x->input[10];
+       j11 = x->input[11];
+       j12 = x->input[12];
+       j13 = x->input[13];
+       j14 = x->input[14];
+       j15 = x->input[15];
+
+       for (;;) {
+               if (bytes < 64) {
+                       for (i = 0; i < bytes; ++i) {
+                               tmp[i] = m[i];
+                       }
+                       m = tmp;
+                       ctarget = c;
+                       c = tmp;
+               }
+               x0 = j0;
+               x1 = j1;
+               x2 = j2;
+               x3 = j3;
+               x4 = j4;
+               x5 = j5;
+               x6 = j6;
+               x7 = j7;
+               x8 = j8;
+               x9 = j9;
+               x10 = j10;
+               x11 = j11;
+               x12 = j12;
+               x13 = j13;
+               x14 = j14;
+               x15 = j15;
+               for (i = 20; i > 0; i -= 2) {
+                       QUARTERROUND(x0, x4, x8, x12)
+                           QUARTERROUND(x1, x5, x9, x13)
+                           QUARTERROUND(x2, x6, x10, x14)
+                           QUARTERROUND(x3, x7, x11, x15)
+                           QUARTERROUND(x0, x5, x10, x15)
+                           QUARTERROUND(x1, x6, x11, x12)
+                           QUARTERROUND(x2, x7, x8, x13)
+                           QUARTERROUND(x3, x4, x9, x14)
+               }
+               x0 = PLUS(x0, j0);
+               x1 = PLUS(x1, j1);
+               x2 = PLUS(x2, j2);
+               x3 = PLUS(x3, j3);
+               x4 = PLUS(x4, j4);
+               x5 = PLUS(x5, j5);
+               x6 = PLUS(x6, j6);
+               x7 = PLUS(x7, j7);
+               x8 = PLUS(x8, j8);
+               x9 = PLUS(x9, j9);
+               x10 = PLUS(x10, j10);
+               x11 = PLUS(x11, j11);
+               x12 = PLUS(x12, j12);
+               x13 = PLUS(x13, j13);
+               x14 = PLUS(x14, j14);
+               x15 = PLUS(x15, j15);
+
+               if (bytes < 64) {
+                       U32TO8_LITTLE(x->ks + 0, x0);
+                       U32TO8_LITTLE(x->ks + 4, x1);
+                       U32TO8_LITTLE(x->ks + 8, x2);
+                       U32TO8_LITTLE(x->ks + 12, x3);
+                       U32TO8_LITTLE(x->ks + 16, x4);
+                       U32TO8_LITTLE(x->ks + 20, x5);
+                       U32TO8_LITTLE(x->ks + 24, x6);
+                       U32TO8_LITTLE(x->ks + 28, x7);
+                       U32TO8_LITTLE(x->ks + 32, x8);
+                       U32TO8_LITTLE(x->ks + 36, x9);
+                       U32TO8_LITTLE(x->ks + 40, x10);
+                       U32TO8_LITTLE(x->ks + 44, x11);
+                       U32TO8_LITTLE(x->ks + 48, x12);
+                       U32TO8_LITTLE(x->ks + 52, x13);
+                       U32TO8_LITTLE(x->ks + 56, x14);
+                       U32TO8_LITTLE(x->ks + 60, x15);
+               }
+
+               x0 = XOR(x0, U8TO32_LITTLE(m + 0));
+               x1 = XOR(x1, U8TO32_LITTLE(m + 4));
+               x2 = XOR(x2, U8TO32_LITTLE(m + 8));
+               x3 = XOR(x3, U8TO32_LITTLE(m + 12));
+               x4 = XOR(x4, U8TO32_LITTLE(m + 16));
+               x5 = XOR(x5, U8TO32_LITTLE(m + 20));
+               x6 = XOR(x6, U8TO32_LITTLE(m + 24));
+               x7 = XOR(x7, U8TO32_LITTLE(m + 28));
+               x8 = XOR(x8, U8TO32_LITTLE(m + 32));
+               x9 = XOR(x9, U8TO32_LITTLE(m + 36));
+               x10 = XOR(x10, U8TO32_LITTLE(m + 40));
+               x11 = XOR(x11, U8TO32_LITTLE(m + 44));
+               x12 = XOR(x12, U8TO32_LITTLE(m + 48));
+               x13 = XOR(x13, U8TO32_LITTLE(m + 52));
+               x14 = XOR(x14, U8TO32_LITTLE(m + 56));
+               x15 = XOR(x15, U8TO32_LITTLE(m + 60));
+
+               j12 = PLUSONE(j12);
+               if (!j12) {
+                       j13 = PLUSONE(j13);
+                       /*
+                        * Stopping at 2^70 bytes per nonce is the user's
+                        * responsibility.
+                        */
+               }
+
+               U32TO8_LITTLE(c + 0, x0);
+               U32TO8_LITTLE(c + 4, x1);
+               U32TO8_LITTLE(c + 8, x2);
+               U32TO8_LITTLE(c + 12, x3);
+               U32TO8_LITTLE(c + 16, x4);
+               U32TO8_LITTLE(c + 20, x5);
+               U32TO8_LITTLE(c + 24, x6);
+               U32TO8_LITTLE(c + 28, x7);
+               U32TO8_LITTLE(c + 32, x8);
+               U32TO8_LITTLE(c + 36, x9);
+               U32TO8_LITTLE(c + 40, x10);
+               U32TO8_LITTLE(c + 44, x11);
+               U32TO8_LITTLE(c + 48, x12);
+               U32TO8_LITTLE(c + 52, x13);
+               U32TO8_LITTLE(c + 56, x14);
+               U32TO8_LITTLE(c + 60, x15);
+
+               if (bytes <= 64) {
+                       if (bytes < 64) {
+                               for (i = 0; i < bytes; ++i)
+                                       ctarget[i] = c[i];
+                       }
+                       x->input[12] = j12;
+                       x->input[13] = j13;
+                       x->unused = 64 - bytes;
+                       return;
+               }
+               bytes -= 64;
+               c += 64;
+               m += 64;
+       }
+}
+
+void chacha20_block(chacha_ctx * x, unsigned char *c, int len) {
+       int i;
+
+       unsigned int state[16];
+       for (i = 0; i < 16; i++)
+               state[i] = x->input[i];
+       for (i = 20; i > 0; i -= 2) {
+               QUARTERROUND(state[0], state[4], state[8], state[12])
+                   QUARTERROUND(state[1], state[5], state[9], state[13])
+                   QUARTERROUND(state[2], state[6], state[10], state[14])
+                   QUARTERROUND(state[3], state[7], state[11], state[15])
+                   QUARTERROUND(state[0], state[5], state[10], state[15])
+                   QUARTERROUND(state[1], state[6], state[11], state[12])
+                   QUARTERROUND(state[2], state[7], state[8], state[13])
+                   QUARTERROUND(state[3], state[4], state[9], state[14])
+       }
+
+       for (i = 0; i < 16; i++)
+               x->input[i] = PLUS(x->input[i], state[i]);
+
+       for (i = 0; i < len; i += 4) {
+               U32TO8_LITTLE(c + i, x->input[i / 4]);
+       }
+}
+
+int poly1305_generate_key(unsigned char *key256, unsigned char *nonce,
+                         unsigned int noncelen, unsigned char *poly_key,
+                         unsigned int counter) {
+       struct chacha_ctx ctx;
+       uint64_t ctr;
+       memset(&ctx, 0, sizeof(ctx));
+       chacha_keysetup(&ctx, key256, 256);
+       switch (noncelen) {
+       case 8:
+               ctr = counter;
+               chacha_ivsetup(&ctx, nonce, (unsigned char *) &ctr);
+               break;
+       case 12:
+               chacha_ivsetup_96bitnonce(&ctx, nonce,
+                                         (unsigned char *) &counter);
+               break;
+       default:
+               return -1;
+       }
+       chacha20_block(&ctx, poly_key, POLY1305_KEYLEN);
+       return 0;
+}
+
+/* interpret four 8 bit unsigned integers as a 32 bit unsigned integer in
+ * little endian */
+static unsigned long U8TO32(const unsigned char *p) {
+       return
+           (((unsigned long) (p[0] & 0xff)) |
+            ((unsigned long) (p[1] & 0xff) << 8) |
+            ((unsigned long) (p[2] & 0xff) << 16) |
+            ((unsigned long) (p[3] & 0xff) << 24));
+}
+
+/* store a 32 bit unsigned integer as four 8 bit unsigned integers in little
+ * endian */
+static void U32TO8(unsigned char *p, unsigned long v) {
+       p[0] = (v) & 0xff;
+       p[1] = (v >> 8) & 0xff;
+       p[2] = (v >> 16) & 0xff;
+       p[3] = (v >> 24) & 0xff;
+}
+
+void tls_poly1305_init(struct poly1305_context *ctx,
+                               const unsigned char key[32]) {
+       struct poly1305_context *st = (struct poly1305_context *) ctx;
+
+       /* r &= 0xffffffc0ffffffc0ffffffc0fffffff */
+       st->r[0] = (U8TO32(&key[0])) & 0x3ffffff;
+       st->r[1] = (U8TO32(&key[3]) >> 2) & 0x3ffff03;
+       st->r[2] = (U8TO32(&key[6]) >> 4) & 0x3ffc0ff;
+       st->r[3] = (U8TO32(&key[9]) >> 6) & 0x3f03fff;
+       st->r[4] = (U8TO32(&key[12]) >> 8) & 0x00fffff;
+
+       /* h = 0 */
+       st->h[0] = 0;
+       st->h[1] = 0;
+       st->h[2] = 0;
+       st->h[3] = 0;
+       st->h[4] = 0;
+
+       /* save pad for later */
+       st->pad[0] = U8TO32(&key[16]);
+       st->pad[1] = U8TO32(&key[20]);
+       st->pad[2] = U8TO32(&key[24]);
+       st->pad[3] = U8TO32(&key[28]);
+
+       st->leftover = 0;
+       st->final = 0;
+}
+
+void tls_poly1305_blocks(struct poly1305_context *st, const unsigned char *m,
+               size_t bytes) {
+       const unsigned long hibit = (st->final) ? 0 : (1UL << 24);      /* 1 << 128 */
+       unsigned long r0, r1, r2, r3, r4;
+       unsigned long s1, s2, s3, s4;
+       unsigned long h0, h1, h2, h3, h4;
+       unsigned long long d0, d1, d2, d3, d4;
+       unsigned long c;
+
+       r0 = st->r[0];
+       r1 = st->r[1];
+       r2 = st->r[2];
+       r3 = st->r[3];
+       r4 = st->r[4];
+
+       s1 = r1 * 5;
+       s2 = r2 * 5;
+       s3 = r3 * 5;
+       s4 = r4 * 5;
+
+       h0 = st->h[0];
+       h1 = st->h[1];
+       h2 = st->h[2];
+       h3 = st->h[3];
+       h4 = st->h[4];
+
+       while (bytes >= POLY1305_BLOCK_SIZE) {
+               /* h += m[i] */
+               h0 += (U8TO32(m + 0)) & 0x3ffffff;
+               h1 += (U8TO32(m + 3) >> 2) & 0x3ffffff;
+               h2 += (U8TO32(m + 6) >> 4) & 0x3ffffff;
+               h3 += (U8TO32(m + 9) >> 6) & 0x3ffffff;
+               h4 += (U8TO32(m + 12) >> 8) | hibit;
+
+               /* h *= r */
+               d0 = ((unsigned long long) h0 * r0) +
+                   ((unsigned long long) h1 * s4) +
+                   ((unsigned long long) h2 * s3) +
+                   ((unsigned long long) h3 * s2) +
+                   ((unsigned long long) h4 * s1);
+               d1 = ((unsigned long long) h0 * r1) +
+                   ((unsigned long long) h1 * r0) +
+                   ((unsigned long long) h2 * s4) +
+                   ((unsigned long long) h3 * s3) +
+                   ((unsigned long long) h4 * s2);
+               d2 = ((unsigned long long) h0 * r2) +
+                   ((unsigned long long) h1 * r1) +
+                   ((unsigned long long) h2 * r0) +
+                   ((unsigned long long) h3 * s4) +
+                   ((unsigned long long) h4 * s3);
+               d3 = ((unsigned long long) h0 * r3) +
+                   ((unsigned long long) h1 * r2) +
+                   ((unsigned long long) h2 * r1) +
+                   ((unsigned long long) h3 * r0) +
+                   ((unsigned long long) h4 * s4);
+               d4 = ((unsigned long long) h0 * r4) +
+                   ((unsigned long long) h1 * r3) +
+                   ((unsigned long long) h2 * r2) +
+                   ((unsigned long long) h3 * r1) +
+                   ((unsigned long long) h4 * r0);
+
+               /* (partial) h %= p */
+               c = (unsigned long) (d0 >> 26);
+               h0 = (unsigned long) d0 & 0x3ffffff;
+               d1 += c;
+               c = (unsigned long) (d1 >> 26);
+               h1 = (unsigned long) d1 & 0x3ffffff;
+               d2 += c;
+               c = (unsigned long) (d2 >> 26);
+               h2 = (unsigned long) d2 & 0x3ffffff;
+               d3 += c;
+               c = (unsigned long) (d3 >> 26);
+               h3 = (unsigned long) d3 & 0x3ffffff;
+               d4 += c;
+               c = (unsigned long) (d4 >> 26);
+               h4 = (unsigned long) d4 & 0x3ffffff;
+               h0 += c * 5;
+               c = (h0 >> 26);
+               h0 = h0 & 0x3ffffff;
+               h1 += c;
+
+               m += POLY1305_BLOCK_SIZE;
+               bytes -= POLY1305_BLOCK_SIZE;
+       }
+
+       st->h[0] = h0;
+       st->h[1] = h1;
+       st->h[2] = h2;
+       st->h[3] = h3;
+       st->h[4] = h4;
+}
+
+void tls_poly1305_finish(struct poly1305_context *ctx, unsigned char mac[16]) {
+       size_t i;
+       struct poly1305_context *st = (struct poly1305_context *) ctx;
+       unsigned long h0, h1, h2, h3, h4, c;
+       unsigned long g0, g1, g2, g3, g4;
+       unsigned long long f;
+       unsigned long mask;
+
+       /* process the remaining block */
+       if (st->leftover) {
+               i = st->leftover;
+               st->buffer[i++] = 1;
+               for (; i < POLY1305_BLOCK_SIZE; i++)
+                       st->buffer[i] = 0;
+               st->final = 1;
+               tls_poly1305_blocks(st, st->buffer, POLY1305_BLOCK_SIZE);
+       }
+
+       /* fully carry h */
+       h0 = st->h[0];
+       h1 = st->h[1];
+       h2 = st->h[2];
+       h3 = st->h[3];
+       h4 = st->h[4];
+
+       c = h1 >> 26;
+       h1 = h1 & 0x3ffffff;
+       h2 += c;
+       c = h2 >> 26;
+       h2 = h2 & 0x3ffffff;
+       h3 += c;
+       c = h3 >> 26;
+       h3 = h3 & 0x3ffffff;
+       h4 += c;
+       c = h4 >> 26;
+       h4 = h4 & 0x3ffffff;
+       h0 += c * 5;
+       c = h0 >> 26;
+       h0 = h0 & 0x3ffffff;
+       h1 += c;
+
+       /* compute h + -p */
+       g0 = h0 + 5;
+       c = g0 >> 26;
+       g0 &= 0x3ffffff;
+       g1 = h1 + c;
+       c = g1 >> 26;
+       g1 &= 0x3ffffff;
+       g2 = h2 + c;
+       c = g2 >> 26;
+       g2 &= 0x3ffffff;
+       g3 = h3 + c;
+       c = g3 >> 26;
+       g3 &= 0x3ffffff;
+       g4 = h4 + c - (1UL << 26);
+
+       /* select h if h < p, or h + -p if h >= p */
+       mask = (g4 >> ((sizeof(unsigned long) * 8) - 1)) - 1;
+       g0 &= mask;
+       g1 &= mask;
+       g2 &= mask;
+       g3 &= mask;
+       g4 &= mask;
+       mask = ~mask;
+       h0 = (h0 & mask) | g0;
+       h1 = (h1 & mask) | g1;
+       h2 = (h2 & mask) | g2;
+       h3 = (h3 & mask) | g3;
+       h4 = (h4 & mask) | g4;
+
+       /* h = h % (2^128) */
+       h0 = ((h0) | (h1 << 26)) & 0xffffffff;
+       h1 = ((h1 >> 6) | (h2 << 20)) & 0xffffffff;
+       h2 = ((h2 >> 12) | (h3 << 14)) & 0xffffffff;
+       h3 = ((h3 >> 18) | (h4 << 8)) & 0xffffffff;
+
+       /* mac = (h + pad) % (2^128) */
+       f = (unsigned long long) h0 + st->pad[0];
+       h0 = (unsigned long) f;
+       f = (unsigned long long) h1 + st->pad[1] + (f >> 32);
+       h1 = (unsigned long) f;
+       f = (unsigned long long) h2 + st->pad[2] + (f >> 32);
+       h2 = (unsigned long) f;
+       f = (unsigned long long) h3 + st->pad[3] + (f >> 32);
+       h3 = (unsigned long) f;
+
+       U32TO8(mac + 0, h0);
+       U32TO8(mac + 4, h1);
+       U32TO8(mac + 8, h2);
+       U32TO8(mac + 12, h3);
+
+       /* zero out the state */
+       st->h[0] = 0;
+       st->h[1] = 0;
+       st->h[2] = 0;
+       st->h[3] = 0;
+       st->h[4] = 0;
+       st->r[0] = 0;
+       st->r[1] = 0;
+       st->r[2] = 0;
+       st->r[3] = 0;
+       st->r[4] = 0;
+       st->pad[0] = 0;
+       st->pad[1] = 0;
+       st->pad[2] = 0;
+       st->pad[3] = 0;
+}
+
+void tls_poly1305_update(struct poly1305_context *ctx, const unsigned char *m,
+               size_t bytes) {
+       struct poly1305_context *st = (struct poly1305_context *) ctx;
+       size_t i;
+       /* handle leftover */
+       if (st->leftover) {
+               size_t want = (POLY1305_BLOCK_SIZE - st->leftover);
+               if (want > bytes)
+                       want = bytes;
+               for (i = 0; i < want; i++)
+                       st->buffer[st->leftover + i] = m[i];
+               bytes -= want;
+               m += want;
+               st->leftover += want;
+               if (st->leftover < POLY1305_BLOCK_SIZE)
+                       return;
+               tls_poly1305_blocks(st, st->buffer, POLY1305_BLOCK_SIZE);
+               st->leftover = 0;
+       }
+
+       /* process full blocks */
+       if (bytes >= POLY1305_BLOCK_SIZE) {
+               size_t want = (bytes & ~(POLY1305_BLOCK_SIZE - 1));
+               tls_poly1305_blocks(st, m, want);
+               m += want;
+               bytes -= want;
+       }
+
+       /* store leftover */
+       if (bytes) {
+               for (i = 0; i < bytes; i++)
+                       st->buffer[st->leftover + i] = m[i];
+               st->leftover += bytes;
+       }
+}
+
+int poly1305_verify(const unsigned char mac1[16],
+                   const unsigned char mac2[16]) {
+       size_t i;
+       unsigned int dif = 0;
+       for (i = 0; i < 16; i++)
+               dif |= (mac1[i] ^ mac2[i]);
+       dif = (dif - 1) >> ((sizeof(unsigned int) * 8) - 1);
+       return (dif & 1);
+}
+
+void chacha20_poly1305_key(struct chacha_ctx *ctx,
+                          unsigned char *poly1305_key) {
+       unsigned char key[32];
+       unsigned char nonce[12];
+       chacha_key(ctx, key);
+       chacha_nonce(ctx, nonce);
+       poly1305_generate_key(key, nonce, sizeof(nonce), poly1305_key, 0);
+}
+
+static unsigned char zeropad[] =
+    { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+
+int chacha20_poly1305_aead(struct chacha_ctx *ctx, unsigned char *pt,
+                          unsigned int len, unsigned char *aad,
+                          unsigned int aad_len, unsigned char *poly_key,
+                          unsigned char *out) {
+       if (aad_len > POLY1305_MAX_AAD) {
+               return -1;
+       }
+
+       unsigned int counter = 1;
+       chacha_ivsetup_96bitnonce(ctx, NULL, (unsigned char *) &counter);
+       chacha_encrypt_bytes(ctx, pt, out, len);
+
+       struct poly1305_context aead_ctx;
+       tls_poly1305_init(&aead_ctx, poly_key);
+       tls_poly1305_update(&aead_ctx, aad, aad_len);
+       int rem = aad_len % 16;
+       if (rem) {
+               tls_poly1305_update(&aead_ctx, zeropad, 16 - rem);
+       }
+       tls_poly1305_update(&aead_ctx, out, len);
+       rem = len % 16;
+       if (rem) {
+               tls_poly1305_update(&aead_ctx, zeropad, 16 - rem);
+       }
+
+       unsigned char trail[16];
+       U32TO8(&trail[0], aad_len);
+       *(int *) &trail[4] = 0;
+       U32TO8(&trail[8], len);
+       *(int *) &trail[12] = 0;
+
+       tls_poly1305_update(&aead_ctx, trail, 16);
+       tls_poly1305_finish(&aead_ctx, out + len);
+
+       return len + POLY1305_TAGLEN;
+}
diff --git a/crypto/chacha.h b/crypto/chacha.h
new file mode 100644 (file)
index 0000000..3186982
--- /dev/null
@@ -0,0 +1,55 @@
+#ifndef CHACHA_H_
+#define CHACHA_H_ 1
+
+#include <stdint.h>
+
+#define TLS_CHACHA20_IV_LENGTH    12
+
+/* ChaCha20 implementation by D. J. Bernstein
+ * Public domain.
+ */
+
+#define CHACHA_MINKEYLEN    16
+#define CHACHA_NONCELEN     8
+#define CHACHA_NONCELEN_96  12
+#define CHACHA_CTRLEN       8
+#define CHACHA_CTRLEN_96    4
+#define CHACHA_STATELEN     (CHACHA_NONCELEN+CHACHA_CTRLEN)
+#define CHACHA_BLOCKLEN     64
+
+#define POLY1305_MAX_AAD    32
+#define POLY1305_KEYLEN     32
+#define POLY1305_TAGLEN     16
+
+#define POLY1305_BLOCK_SIZE 16
+
+struct chacha_ctx {
+       uint32_t input[16];
+       uint8_t ks[CHACHA_BLOCKLEN];
+       uint8_t unused;
+};
+
+/* 17 + sizeof(size_t) + 14*sizeof(unsigned long) */
+struct poly1305_context {
+    unsigned long r[5];
+    unsigned long h[5];
+    unsigned long pad[4];
+    size_t leftover;
+    unsigned char buffer[POLY1305_BLOCK_SIZE];
+    unsigned char final;
+};
+
+void chacha_keysetup(struct chacha_ctx *x, const unsigned char *k, unsigned int kbits);
+void chacha_ivsetup(struct chacha_ctx *x, const unsigned char *iv, const unsigned char *ctr);
+void chacha_ivsetup_96bitnonce(struct chacha_ctx *x, const unsigned char *iv, const unsigned char *ctr);
+void chacha_encrypt_bytes(struct chacha_ctx *x, const unsigned char *m, unsigned char *c, unsigned int bytes);
+int poly1305_generate_key(unsigned char *key256, unsigned char *nonce, unsigned int noncelen, unsigned char *poly_key, unsigned int counter);
+void chacha_ivupdate(struct chacha_ctx *x, const uint8_t *iv, const uint8_t *aad, const uint8_t *counter);
+void chacha20_poly1305_key(struct chacha_ctx *ctx, unsigned char *poly1305_key);
+int chacha20_poly1305_aead(struct chacha_ctx *ctx,  unsigned char *pt, unsigned int len, unsigned char *aad, unsigned int aad_len, unsigned char *poly_key, unsigned char *out);
+void tls_poly1305_init(struct poly1305_context *ctx, const unsigned char key[32]);
+void tls_poly1305_update(struct poly1305_context *ctx, const unsigned char *m, size_t bytes);
+void tls_poly1305_finish(struct poly1305_context *ctx, unsigned char mac[16]);
+
+
+#endif
diff --git a/crypto/cipher_supported.c b/crypto/cipher_supported.c
new file mode 100644 (file)
index 0000000..9b17cbf
--- /dev/null
@@ -0,0 +1,65 @@
+#include "tlse.h"
+
+int tls_cipher_supported(struct TLSContext *context, unsigned short cipher) {
+       if (!context) {
+               return 0;
+       }
+
+       switch (cipher) {
+               case TLS_AES_128_GCM_SHA256:
+               case TLS_AES_256_GCM_SHA384:
+               case TLS_CHACHA20_POLY1305_SHA256:
+                       if (context->tlsver == TLS_VERSION13) {
+                               return 1;
+                       }
+                       return 0;
+               case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA:
+               case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA:
+                       if (context && ((context->certificates
+                                                       && context->certificates_count
+                                                       && context->ec_private_key)
+                                               || !context->is_server)) {
+                               return 1;
+                       }
+                       return 0;
+               case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256:
+               case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384:
+               case TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:
+               case TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:
+               case TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256:
+                       if (context->tlsver == TLS_VERSION12) {
+                               if (context && ((context->certificates
+                                                               && context->certificates_count
+                                                               && context->ec_private_key)
+                                                       || !context->is_server)) {
+                                       return 1;
+                               }
+                       }
+                       return 0;
+               case TLS_DHE_RSA_WITH_AES_128_CBC_SHA:
+               case TLS_DHE_RSA_WITH_AES_256_CBC_SHA:
+               case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA:
+               case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA:
+               case TLS_RSA_WITH_AES_128_CBC_SHA:
+               case TLS_RSA_WITH_AES_256_CBC_SHA:
+                       return 1;
+               case TLS_DHE_RSA_WITH_AES_128_CBC_SHA256:
+               case TLS_DHE_RSA_WITH_AES_256_CBC_SHA256:
+               case TLS_DHE_RSA_WITH_AES_128_GCM_SHA256:
+               case TLS_DHE_RSA_WITH_AES_256_GCM_SHA384:
+               case TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256:
+               case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256:
+               case TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384:
+               case TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
+               case TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
+               case TLS_RSA_WITH_AES_128_GCM_SHA256:
+               case TLS_RSA_WITH_AES_128_CBC_SHA256:
+               case TLS_RSA_WITH_AES_256_CBC_SHA256:
+               case TLS_RSA_WITH_AES_256_GCM_SHA384:
+                       if (context->tlsver == TLS_VERSION12) {
+                               return 1;
+                       }
+                       return 0;
+       }
+       return 0;
+}
diff --git a/crypto/forward.c b/crypto/forward.c
new file mode 100644 (file)
index 0000000..81f5d49
--- /dev/null
@@ -0,0 +1,564 @@
+#include "tlse.h"
+
+#define mp_init(a)                           ltc_mp.init(a)
+#define mp_init_multi                        ltc_init_multi
+#define mp_clear(a)                          ltc_mp.deinit(a)
+#define mp_clear_multi                       ltc_deinit_multi
+#define mp_count_bits(a)                     ltc_mp.count_bits(a)
+#define mp_read_radix(a, b, c)               ltc_mp.read_radix(a, b, c)
+#define mp_unsigned_bin_size(a)              ltc_mp.unsigned_size(a)
+#define mp_to_unsigned_bin(a, b)             ltc_mp.unsigned_write(a, b)
+#define mp_read_unsigned_bin(a, b, c)        ltc_mp.unsigned_read(a, b, c)
+#define mp_exptmod(a, b, c, d)               ltc_mp.exptmod(a, b, c, d)
+#define mp_add(a, b, c)                      ltc_mp.add(a, b, c)
+#define mp_mul(a, b, c)                      ltc_mp.mul(a, b, c)
+#define mp_cmp(a, b)                         ltc_mp.compare(a, b)
+#define mp_cmp_d(a, b)                       ltc_mp.compare_d(a, b)
+#define mp_sqr(a, b)                         ltc_mp.sqr(a, b)
+#define mp_mod(a, b, c)                      ltc_mp.mpdiv(a, b, NULL, c)
+#define mp_sub(a, b, c)                      ltc_mp.sub(a, b, c)
+#define mp_set(a, b)                         ltc_mp.set_int(a, b)
+
+struct DHKey ffdhe2048 = {
+       0x0100,
+       NULL,
+       NULL,
+       (void *)
+           "FFFFFFFFFFFFFFFFADF85458A2BB4A9AAFDC5620273D3CF1D8B9C583CE2D3695A9E13641146433FBCC939DCE249B3EF97D2FE363630C75D8F681B202AEC4617AD3DF1ED5D5FD65612433F51F5F066ED0856365553DED1AF3B557135E7F57C935984F0C70E0E68B77E2A689DAF3EFE8721DF158A136ADE73530ACCA4F483A797ABC0AB182B324FB61D108A94BB2C8E3FBB96ADAB760D7F4681D4F42A3DE394DF4AE56EDE76372BB190B07A7C8EE0A6D709E02FCE1CDF7E2ECC03404CD28342F619172FE9CE98583FF8E4F1232EEF28183C3FE3B1B4C6FAD733BB5FCBC2EC22005C58EF1837D1683B2C6F34A26C1B2EFFA886B423861285C97FFFFFFFFFFFFFFFF",
+       (void *)
+       "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002"
+};
+
+struct DHKey ffdhe3072 = {
+       0x0101,
+       NULL,
+       NULL,
+       (void *)
+           "FFFFFFFFFFFFFFFFADF85458A2BB4A9AAFDC5620273D3CF1D8B9C583CE2D3695A9E13641146433FBCC939DCE249B3EF97D2FE363630C75D8F681B202AEC4617AD3DF1ED5D5FD65612433F51F5F066ED0856365553DED1AF3B557135E7F57C935984F0C70E0E68B77E2A689DAF3EFE8721DF158A136ADE73530ACCA4F483A797ABC0AB182B324FB61D108A94BB2C8E3FBB96ADAB760D7F4681D4F42A3DE394DF4AE56EDE76372BB190B07A7C8EE0A6D709E02FCE1CDF7E2ECC03404CD28342F619172FE9CE98583FF8E4F1232EEF28183C3FE3B1B4C6FAD733BB5FCBC2EC22005C58EF1837D1683B2C6F34A26C1B2EFFA886B4238611FCFDCDE355B3B6519035BBC34F4DEF99C023861B46FC9D6E6C9077AD91D2691F7F7EE598CB0FAC186D91CAEFE130985139270B4130C93BC437944F4FD4452E2D74DD364F2E21E71F54BFF5CAE82AB9C9DF69EE86D2BC522363A0DABC521979B0DEADA1DBF9A42D5C4484E0ABCD06BFA53DDEF3C1B20EE3FD59D7C25E41D2B66C62E37FFFFFFFFFFFFFFFF",
+       (void *)
+       "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002"
+};
+
+struct DHKey ffdhe4096 = {
+       0x0102,
+       NULL,
+       NULL,
+       (void *)
+           "FFFFFFFFFFFFFFFFADF85458A2BB4A9AAFDC5620273D3CF1D8B9C583CE2D3695A9E13641146433FBCC939DCE249B3EF97D2FE363630C75D8F681B202AEC4617AD3DF1ED5D5FD65612433F51F5F066ED0856365553DED1AF3B557135E7F57C935984F0C70E0E68B77E2A689DAF3EFE8721DF158A136ADE73530ACCA4F483A797ABC0AB182B324FB61D108A94BB2C8E3FBB96ADAB760D7F4681D4F42A3DE394DF4AE56EDE76372BB190B07A7C8EE0A6D709E02FCE1CDF7E2ECC03404CD28342F619172FE9CE98583FF8E4F1232EEF28183C3FE3B1B4C6FAD733BB5FCBC2EC22005C58EF1837D1683B2C6F34A26C1B2EFFA886B4238611FCFDCDE355B3B6519035BBC34F4DEF99C023861B46FC9D6E6C9077AD91D2691F7F7EE598CB0FAC186D91CAEFE130985139270B4130C93BC437944F4FD4452E2D74DD364F2E21E71F54BFF5CAE82AB9C9DF69EE86D2BC522363A0DABC521979B0DEADA1DBF9A42D5C4484E0ABCD06BFA53DDEF3C1B20EE3FD59D7C25E41D2B669E1EF16E6F52C3164DF4FB7930E9E4E58857B6AC7D5F42D69F6D187763CF1D5503400487F55BA57E31CC7A7135C886EFB4318AED6A1E012D9E6832A907600A918130C46DC778F971AD0038092999A333CB8B7A1A1DB93D7140003C2A4ECEA9F98D0ACC0A8291CDCEC97DCF8EC9B55A7F88A46B4DB5A851F44182E1C68A007E5E655F6AFFFFFFFFFFFFFFFF",
+       (void *)
+       "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002"
+};
+
+struct DHKey ffdhe6144 = {
+       0x0103,
+       NULL,
+       NULL,
+       (void *)
+           "FFFFFFFFFFFFFFFFADF85458A2BB4A9AAFDC5620273D3CF1D8B9C583CE2D3695A9E13641146433FBCC939DCE249B3EF97D2FE363630C75D8F681B202AEC4617AD3DF1ED5D5FD65612433F51F5F066ED0856365553DED1AF3B557135E7F57C935984F0C70E0E68B77E2A689DAF3EFE8721DF158A136ADE73530ACCA4F483A797ABC0AB182B324FB61D108A94BB2C8E3FBB96ADAB760D7F4681D4F42A3DE394DF4AE56EDE76372BB190B07A7C8EE0A6D709E02FCE1CDF7E2ECC03404CD28342F619172FE9CE98583FF8E4F1232EEF28183C3FE3B1B4C6FAD733BB5FCBC2EC22005C58EF1837D1683B2C6F34A26C1B2EFFA886B4238611FCFDCDE355B3B6519035BBC34F4DEF99C023861B46FC9D6E6C9077AD91D2691F7F7EE598CB0FAC186D91CAEFE130985139270B4130C93BC437944F4FD4452E2D74DD364F2E21E71F54BFF5CAE82AB9C9DF69EE86D2BC522363A0DABC521979B0DEADA1DBF9A42D5C4484E0ABCD06BFA53DDEF3C1B20EE3FD59D7C25E41D2B669E1EF16E6F52C3164DF4FB7930E9E4E58857B6AC7D5F42D69F6D187763CF1D5503400487F55BA57E31CC7A7135C886EFB4318AED6A1E012D9E6832A907600A918130C46DC778F971AD0038092999A333CB8B7A1A1DB93D7140003C2A4ECEA9F98D0ACC0A8291CDCEC97DCF8EC9B55A7F88A46B4DB5A851F44182E1C68A007E5E0DD9020BFD64B645036C7A4E677D2C38532A3A23BA4442CAF53EA63BB454329B7624C8917BDD64B1C0FD4CB38E8C334C701C3ACDAD0657FCCFEC719B1F5C3E4E46041F388147FB4CFDB477A52471F7A9A96910B855322EDB6340D8A00EF092350511E30ABEC1FFF9E3A26E7FB29F8C183023C3587E38DA0077D9B4763E4E4B94B2BBC194C6651E77CAF992EEAAC0232A281BF6B3A739C1226116820AE8DB5847A67CBEF9C9091B462D538CD72B03746AE77F5E62292C311562A846505DC82DB854338AE49F5235C95B91178CCF2DD5CACEF403EC9D1810C6272B045B3B71F9DC6B80D63FDD4A8E9ADB1E6962A69526D43161C1A41D570D7938DAD4A40E329CD0E40E65FFFFFFFFFFFFFFFF",
+       (void *)
+       "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002"
+};
+
+struct DHKey ffdhe8192 = {
+       0x0104,
+       NULL,
+       NULL,
+       (void *)
+           "FFFFFFFFFFFFFFFFADF85458A2BB4A9AAFDC5620273D3CF1D8B9C583CE2D3695A9E13641146433FBCC939DCE249B3EF97D2FE363630C75D8F681B202AEC4617AD3DF1ED5D5FD65612433F51F5F066ED0856365553DED1AF3B557135E7F57C935984F0C70E0E68B77E2A689DAF3EFE8721DF158A136ADE73530ACCA4F483A797ABC0AB182B324FB61D108A94BB2C8E3FBB96ADAB760D7F4681D4F42A3DE394DF4AE56EDE76372BB190B07A7C8EE0A6D709E02FCE1CDF7E2ECC03404CD28342F619172FE9CE98583FF8E4F1232EEF28183C3FE3B1B4C6FAD733BB5FCBC2EC22005C58EF1837D1683B2C6F34A26C1B2EFFA886B4238611FCFDCDE355B3B6519035BBC34F4DEF99C023861B46FC9D6E6C9077AD91D2691F7F7EE598CB0FAC186D91CAEFE130985139270B4130C93BC437944F4FD4452E2D74DD364F2E21E71F54BFF5CAE82AB9C9DF69EE86D2BC522363A0DABC521979B0DEADA1DBF9A42D5C4484E0ABCD06BFA53DDEF3C1B20EE3FD59D7C25E41D2B669E1EF16E6F52C3164DF4FB7930E9E4E58857B6AC7D5F42D69F6D187763CF1D5503400487F55BA57E31CC7A7135C886EFB4318AED6A1E012D9E6832A907600A918130C46DC778F971AD0038092999A333CB8B7A1A1DB93D7140003C2A4ECEA9F98D0ACC0A8291CDCEC97DCF8EC9B55A7F88A46B4DB5A851F44182E1C68A007E5E0DD9020BFD64B645036C7A4E677D2C38532A3A23BA4442CAF53EA63BB454329B7624C8917BDD64B1C0FD4CB38E8C334C701C3ACDAD0657FCCFEC719B1F5C3E4E46041F388147FB4CFDB477A52471F7A9A96910B855322EDB6340D8A00EF092350511E30ABEC1FFF9E3A26E7FB29F8C183023C3587E38DA0077D9B4763E4E4B94B2BBC194C6651E77CAF992EEAAC0232A281BF6B3A739C1226116820AE8DB5847A67CBEF9C9091B462D538CD72B03746AE77F5E62292C311562A846505DC82DB854338AE49F5235C95B91178CCF2DD5CACEF403EC9D1810C6272B045B3B71F9DC6B80D63FDD4A8E9ADB1E6962A69526D43161C1A41D570D7938DAD4A40E329CCFF46AAA36AD004CF600C8381E425A31D951AE64FDB23FCEC9509D43687FEB69EDD1CC5E0B8CC3BDF64B10EF86B63142A3AB8829555B2F747C932665CB2C0F1CC01BD70229388839D2AF05E454504AC78B7582822846C0BA35C35F5C59160CC046FD8251541FC68C9C86B022BB7099876A460E7451A8A93109703FEE1C217E6C3826E52C51AA691E0E423CFC99E9E31650C1217B624816CDAD9A95F9D5B8019488D9C0A0A1FE3075A577E23183F81D4A3F2FA4571EFC8CE0BA8A4FE8B6855DFE72B0A66EDED2FBABFBE58A30FAFABE1C5D71A87E2F741EF8C1FE86FEA6BBFDE530677F0D97D11D49F7A8443D0822E506A9F4614E011E2A94838FF88CD68C8BB7C5C6424CFFFFFFFFFFFFFFFF",
+       (void *)
+       "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002"
+};
+
+struct ECCCurveParameters secp192r1 = {
+       24,
+       19,
+       "secp192r1",
+       "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF",     /* P */
+       "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFC",     /* A */
+       "64210519E59C80E70FA7E9AB72243049FEB8DEECC146B9B1",     /* B */
+       "188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF1012",     /* Gx */
+       "07192B95FFC8DA78631011ED6B24CDD573F977A11E794811",     /* Gy */
+       "FFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D22831"      /* order (n) */
+               , { 0 }
+};
+
+
+struct ECCCurveParameters secp224r1 = {
+       28,
+       21,
+       "secp224r1",
+       "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000001",     /* P */
+       "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFE",     /* A */
+       "B4050A850C04B3ABF54132565044B0B7D7BFD8BA270B39432355FFB4",     /* B */
+       "B70E0CBD6BB4BF7F321390B94A03C1D356C21122343280D6115C1D21",     /* Gx */
+       "BD376388B5F723FB4C22DFE6CD4375A05A07476444D5819985007E34",     /* Gy */
+       "FFFFFFFFFFFFFFFFFFFFFFFFFFFF16A2E0B8F03E13DD29455C5C2A3D"      /* order (n) */
+               , { 0 }
+};
+
+struct ECCCurveParameters secp224k1 = {
+       28,
+       20,
+       "secp224k1",
+       "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFE56D",     /* P */
+       "00000000000000000000000000000000000000000000000000000000",     /* A */
+       "00000000000000000000000000000000000000000000000000000005",     /* B */
+       "A1455B334DF099DF30FC28A169A467E9E47075A90F7E650EB6B7A45C",     /* Gx */
+       "7E089FED7FBA344282CAFBD6F7E319F7C0B0BD59E2CA4BDB556D61A5",     /* Gy */
+               /* order (n) */
+       "0000000000000000000000000001DCE8D2EC6184CAF0A971769FB1F7",
+       { 0 }
+};
+
+struct ECCCurveParameters secp256r1 = {
+       32,
+       23,
+       "secp256r1",
+       "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF",     /* P */
+       "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC",     /* A */
+       "5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B",     /* B */
+       "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296",     /* Gx */
+       "4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5",     /* Gy */
+       "FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551",
+       { 0 }
+};
+
+struct ECCCurveParameters secp256k1 = {
+       32,
+       22,
+       "secp256k1",
+       "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F",     /* P */
+       "0000000000000000000000000000000000000000000000000000000000000000",     /* A */
+       "0000000000000000000000000000000000000000000000000000000000000007",     /* B */
+       "79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798",     /* Gx */
+       "483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8",     /* Gy */
+       /* order (n) */
+       "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141",
+       { 0 }
+};
+
+struct ECCCurveParameters secp384r1 = {
+       48,
+       24,
+       "secp384r1",
+       "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFF",
+       "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFC",
+       "B3312FA7E23EE7E4988E056BE3F82D19181D9C6EFE8141120314088F5013875AC656398D8A2ED19D2A85C8EDD3EC2AEF",
+       "AA87CA22BE8B05378EB1C71EF320AD746E1D3B628BA79B9859F741E082542A385502F25DBF55296C3A545E3872760AB7",
+       "3617DE4A96262C6F5D9E98BF9292DC29F8F41DBD289A147CE9DA3113B5F0B8C00A60B1CE1D7E819D7A431D7C90EA0E5F",
+       "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973", 
+       { 0 }
+};
+
+struct ECCCurveParameters secp521r1 = {
+       66,
+       25,
+       "secp521r1",
+       "01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF",
+       "01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC",
+       "0051953EB9618E1C9A1F929A21A0B68540EEA2DA725B99B315F3B8B489918EF109E156193951EC7E937B1652C0BD3BB1BF073573DF883D2C34F1EF451FD46B503F00",
+       "00C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66",
+       "011839296A789A3BC0045C8A5FB42C7D1BD998F54449579B446817AFBD17273E662C97EE72995EF42640C550B9013FAD0761353C7086A272C24088BE94769FD16650",
+       "01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA51868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E91386409",
+       { 0 }
+
+};
+
+/* dummy */
+struct ECCCurveParameters curve25519 = {
+       32,
+       29,
+       "x25519",
+       "7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFED",
+       "0000000000000000000000000000000000000000000000000000000000076D06",
+       "0000000000000000000000000000000000000000000000000000000000000000",
+       "0000000000000000000000000000000000000000000000000000000000000009",
+       "20AE19A1B8A086B4E01EDD2C7748D14C923D4D7E6D7C61B229E9C5A27ECED3D9",
+       "1000000000000000000000000000000014DEF9DEA2F79CD65812631A5CF5D3ED",
+       { 0 }
+};
+
+struct ECCCurveParameters *const tls_ecc_default_curve = &secp256r1;
+
+static void init_curve(struct ECCCurveParameters *curve) {
+       curve->dp.size = curve->size;
+       curve->dp.name = (char *) curve->name;
+       curve->dp.B = (char *) curve->B;
+       curve->dp.prime = (char *) curve->P;
+       curve->dp.Gx = (char *) curve->Gx;
+       curve->dp.Gy = (char *) curve->Gy;
+       curve->dp.order = (char *) curve->order;
+}
+
+void tls_ecc_init_curves() {
+       init_curve(&secp192r1);
+       init_curve(&secp224r1);
+       init_curve(&secp224k1);
+       init_curve(&secp256r1);
+       init_curve(&secp256k1);
+       init_curve(&secp384r1);
+       init_curve(&secp521r1);
+}
+
+#if 1
+static int l_dh_shared_secret(struct DHKey *private_key, struct DHKey *public_key,
+                                 unsigned char *out,
+                                 unsigned long *outlen) {
+       void *tmp;
+       unsigned long x;
+       int err;
+
+       if ((!private_key) || (!public_key) || (!out) || (!outlen))
+               return TLS_GENERIC_ERROR;
+
+       /* compute y^x mod p */
+       if ((err = mp_init(&tmp)) != CRYPT_OK)
+               return err;
+
+       if ((err =
+            mp_exptmod(public_key->y, private_key->x, private_key->p,
+                       tmp)) != CRYPT_OK) {
+               mp_clear(tmp);
+               return err;
+       }
+
+       x = (unsigned long) mp_unsigned_bin_size(tmp);
+       if (*outlen < x) {
+               err = CRYPT_BUFFER_OVERFLOW;
+               mp_clear(tmp);
+               return err;
+       }
+
+       if ((err = mp_to_unsigned_bin(tmp, out)) != CRYPT_OK) {
+               mp_clear(tmp);
+               return err;
+       }
+       *outlen = x;
+       mp_clear(tmp);
+       return 0;
+}
+#endif
+
+unsigned char *tls_decrypt_dhe(struct TLSContext *context, const unsigned char
+               *buffer, unsigned int len, unsigned int *size, int clear_key) {
+       *size = 0;
+       if ((!len) || (!context) || (!context->dhe)) {
+               DEBUG_PRINT("No private DHE key set\n");
+               return NULL;
+       }
+
+       unsigned long out_size = len;
+       void *Yc = NULL;
+
+       if (mp_init(&Yc)) {
+               DEBUG_PRINT("ERROR CREATING Yc\n");
+               return NULL;
+       }
+       if (mp_read_unsigned_bin(Yc, (unsigned char *) buffer, len)) {
+               DEBUG_PRINT("ERROR LOADING DHE Yc\n");
+               mp_clear(Yc);
+               return NULL;
+       }
+
+       unsigned char *out = malloc(len);
+       struct DHKey client_key;
+       memset(&client_key, 0, sizeof client_key);
+
+       client_key.p = context->dhe->p;
+       client_key.g = context->dhe->g;
+       client_key.y = Yc;
+       
+       /* TODO use dh_shared_secret from tomcrypt */
+       int err = l_dh_shared_secret(context->dhe, &client_key, out, &out_size);
+       /* don't delete p and g */
+       client_key.p = NULL;
+       client_key.g = NULL;
+       tls_dh_clear_key(&client_key);
+       /* not needing the dhe key anymore */
+
+       if (clear_key) {
+               tls_dhe_free(context);
+       }
+
+       if (err) {
+               DEBUG_PRINT("DHE DECRYPT ERROR %i\n", err);
+               free(out);
+               return NULL;
+       }
+       DEBUG_PRINT("OUT_SIZE: %lu\n", out_size);
+       DEBUG_DUMP_HEX_LABEL("DHE", out, out_size);
+       *size = (unsigned int) out_size;
+       return out;
+}
+
+unsigned char *tls_decrypt_ecc_dhe(struct TLSContext *context, const unsigned
+               char *buffer, unsigned int len, unsigned int *size, int
+               clear_key) {
+       *size = 0;
+       if (!len || !context || !context->ecc_dhe) {
+               DEBUG_PRINT("No private ECC DHE key set\n");
+               return NULL;
+       }
+
+       const struct ECCCurveParameters *curve;
+       if (context->curve) {
+               curve = context->curve;
+       } else {
+               curve = tls_ecc_default_curve;
+       }
+
+       ltc_ecc_set_type *dp = (ltc_ecc_set_type *) & curve->dp;
+
+       ecc_key client_key;
+       memset(&client_key, 0, sizeof(client_key));
+       if (ecc_ansi_x963_import_ex(buffer, len, &client_key, dp)) {
+               DEBUG_PRINT("Error importing ECC DHE key\n");
+               return NULL;
+       }
+       unsigned char *out = malloc(len);
+       unsigned long out_size = len;
+
+       int err = ecc_shared_secret(context->ecc_dhe, &client_key, out,
+                                   &out_size);
+       ecc_free(&client_key);
+       if (clear_key) {
+               tls_ecc_dhe_free(context);
+       }
+       if (err) {
+               DEBUG_PRINT("ECC DHE DECRYPT ERROR %i\n", err);
+               free(out);
+               return NULL;
+       }
+       DEBUG_PRINT("OUT_SIZE: %lu\n", out_size);
+       DEBUG_DUMP_HEX_LABEL("ECC DHE", out, out_size);
+       *size = (unsigned int) out_size;
+       return out;
+}
+
+const struct ECCCurveParameters *tls_set_curve(struct TLSContext *context, const struct
+                                              ECCCurveParameters *curve) {
+       if (!context->is_server)
+               return NULL;
+       const struct ECCCurveParameters *old_curve = context->curve;
+       context->curve = curve;
+       return old_curve;
+}
+
+void tls_dhe_free(struct TLSContext *context) {
+       if (context->dhe) {
+               tls_dh_clear_key(context->dhe);
+               free(context->dhe);
+               context->dhe = NULL;
+       }
+}
+
+void tls_dhe_create(struct TLSContext *context) {
+       tls_dhe_free(context);
+       context->dhe = malloc(sizeof(struct DHKey));
+       if (context->dhe)
+               memset(context->dhe, 0, sizeof(struct DHKey));
+}
+
+void tls_ecc_dhe_free(struct TLSContext *context) {
+       if (context->ecc_dhe) {
+               ecc_free(context->ecc_dhe);
+               free(context->ecc_dhe);
+               context->ecc_dhe = NULL;
+       }
+}
+
+void tls_ecc_dhe_create(struct TLSContext *context) {
+       tls_ecc_dhe_free(context);
+       context->ecc_dhe = malloc(sizeof(ecc_key));
+       memset(context->ecc_dhe, 0, sizeof(ecc_key));
+}
+
+int tls_set_default_dhe_pg(struct TLSContext *context,
+                          const char *p_hex_str, const char *g_hex_str) {
+       if (!context || context->is_child || !context->is_server || !p_hex_str
+                       || !g_hex_str)
+               return 0;
+
+       free(context->default_dhe_p);
+       free(context->default_dhe_g);
+
+       context->default_dhe_p = NULL;
+       context->default_dhe_g = NULL;
+
+       int p_len = strlen(p_hex_str);
+       int g_len = strlen(g_hex_str);
+       if (p_len <= 0 || g_len <= 0) {
+               return 0;
+       }
+       context->default_dhe_p = malloc(p_len + 1);
+       if (!context->default_dhe_p) {
+               return 0;
+       }
+       context->default_dhe_g = malloc(g_len + 1);
+       if (!context->default_dhe_g) {
+               return 0;
+       }
+
+       memcpy(context->default_dhe_p, p_hex_str, p_len);
+       context->default_dhe_p[p_len] = 0;
+
+       memcpy(context->default_dhe_g, g_hex_str, g_len);
+       context->default_dhe_g[g_len] = 0;
+       return 1;
+}
+
+int tls_dh_export_Y(unsigned char *Ybuf, unsigned long *Ylen,
+                            struct DHKey *key) {
+       unsigned long len;
+
+       if (Ybuf == NULL || Ylen == NULL || key == NULL) {
+               return TLS_GENERIC_ERROR;
+       }
+
+       len = mp_unsigned_bin_size(key->y);
+       if (len > *Ylen) {
+               return TLS_GENERIC_ERROR;
+       }
+
+       *Ylen = len;
+       return 0;
+}
+
+int tls_dh_export_pqY(unsigned char *pbuf, unsigned long *plen,
+                              unsigned char *gbuf, unsigned long *glen,
+                              unsigned char *Ybuf, unsigned long *Ylen,
+                              struct DHKey *key) {
+       unsigned long len;
+       int err;
+
+       if (pbuf == NULL || plen == NULL || gbuf == NULL || glen == NULL ||
+                       Ybuf == NULL || Ylen == NULL || key == NULL) {
+               return TLS_GENERIC_ERROR;
+       }
+
+       len = mp_unsigned_bin_size(key->y);
+       if (len > *Ylen) {
+               return TLS_GENERIC_ERROR;
+       }
+
+       if ((err = mp_to_unsigned_bin(key->y, Ybuf)) != CRYPT_OK) {
+               return err;
+       }
+
+       *Ylen = len;
+
+       len = mp_unsigned_bin_size(key->p);
+       if (len > *plen) {
+               return TLS_GENERIC_ERROR;
+       }
+
+       if ((err = mp_to_unsigned_bin(key->p, pbuf)) != CRYPT_OK) {
+               return err;
+       }
+
+       *plen = len;
+
+       len = mp_unsigned_bin_size(key->g);
+       if (len > *glen) {
+               return TLS_GENERIC_ERROR;
+       }
+
+       if ((err = mp_to_unsigned_bin(key->g, gbuf)) != CRYPT_OK)
+               return err;
+
+       *glen = len;
+
+       return 0;
+}
+
+void tls_dh_clear_key(struct DHKey *key) {
+       mp_clear_multi(key->g, key->p, key->x, key->y, NULL);
+       key->g = NULL;
+       key->p = NULL;
+       key->x = NULL;
+       key->y = NULL;
+}
+
+int tls_dh_make_key(int keysize, struct DHKey *key, const char *pbuf,
+                            const char *gbuf, int pbuf_len, int gbuf_len) 
+{
+       unsigned char *buf;
+       int err;
+       if (!key) {
+               return TLS_GENERIC_ERROR;
+       }
+
+       static prng_state prng;
+       int wprng = find_prng("sprng");
+       if ((err = prng_is_valid(wprng)) != CRYPT_OK) {
+               return err;
+       }
+
+       buf = malloc(keysize);
+       if (!buf) {
+               return TLS_NO_MEMORY;
+       }
+
+       if (rng_make_prng(keysize, wprng, &prng, NULL) != CRYPT_OK) {
+               free(buf);
+               return TLS_GENERIC_ERROR;
+       }
+
+       if (prng_descriptor[wprng].read(buf, keysize, &prng) != (unsigned long)
+                       keysize) {
+               free(buf);
+               return TLS_GENERIC_ERROR;
+       }
+
+       if ((err = mp_init_multi(&key->g, &key->p, &key->x, &key->y, NULL)) !=
+                       CRYPT_OK) {
+               free(buf);
+
+               return TLS_GENERIC_ERROR;
+       }
+
+       if (gbuf_len <= 0) {
+               if ((err = mp_read_radix(key->g, gbuf, 16)) != CRYPT_OK) {
+                       free(buf);
+                       tls_dh_clear_key(key);
+                       return TLS_GENERIC_ERROR;
+               }
+       } else {
+               if ((err = mp_read_unsigned_bin(key->g, (unsigned char *) gbuf,
+                                               gbuf_len)) != CRYPT_OK) {
+                       free(buf);
+                       tls_dh_clear_key(key);
+                       return TLS_GENERIC_ERROR;
+               }
+       }
+
+       if (pbuf_len <= 0) {
+               if ((err = mp_read_radix(key->p, pbuf, 16)) != CRYPT_OK) {
+                       free(buf);
+                       tls_dh_clear_key(key);
+                       return TLS_GENERIC_ERROR;
+               }
+       } else {
+               if ((err = mp_read_unsigned_bin(key->p, (unsigned char *) pbuf,
+                                         pbuf_len)) != CRYPT_OK) {
+                       free(buf);
+                       tls_dh_clear_key(key);
+                       return TLS_GENERIC_ERROR;
+               }
+       }
+
+       if ((err = mp_read_unsigned_bin(key->x, buf, keysize)) != CRYPT_OK) {
+               free(buf);
+               tls_dh_clear_key(key);
+               return TLS_GENERIC_ERROR;
+       }
+
+       if ((err = mp_exptmod(key->g, key->x, key->p, key->y)) != CRYPT_OK) {
+               free(buf);
+               tls_dh_clear_key(key);
+               return TLS_GENERIC_ERROR;
+       }
+
+       free(buf);
+       return 0;
+}
diff --git a/crypto/handshake.c b/crypto/handshake.c
new file mode 100644 (file)
index 0000000..30eb788
--- /dev/null
@@ -0,0 +1,1080 @@
+#define _POSIX_C_SOURCE 200809L
+
+#include <arpa/inet.h>
+
+#include "tlse.h"
+#include "buffer.h"
+
+#define TLS12_FLAG 0x01
+#define TLS13_FLAG 0x03
+
+static unsigned char *encrypt_rsa(struct TLSContext *context,
+                                       const unsigned char *buffer,
+                                       unsigned int len,
+                                       unsigned int *size) {
+       *size = 0;
+       if (!len || !context || !context->certificates
+           || !context->certificates_count
+           || !context->certificates[0]
+           || !context->certificates[0]->der_bytes
+           || !context->certificates[0]->der_len) {
+               DEBUG_PRINT("No certificate set\n");
+               return NULL;
+       }
+       rsa_key key;
+       int err;
+       err = rsa_import(context->certificates[0]->der_bytes,
+                       context->certificates[0]->der_len, &key);
+
+       if (err) {
+               DEBUG_PRINT("Error importing RSA certificate (code: %i)\n",
+                           err);
+               return NULL;
+       }
+       unsigned long out_size = TLS_MAX_RSA_KEY;
+       unsigned char *out = malloc(out_size);
+       int hash_idx = find_hash("sha256");
+       int prng_idx = find_prng("sprng");
+       err = rsa_encrypt_key_ex(buffer, len, out, &out_size, (unsigned char *)
+                       "Concept", 7, NULL, prng_idx, hash_idx,
+                       LTC_PKCS_1_V1_5, &key);
+       rsa_free(&key);
+       if (err || !out_size) {
+               free(out);
+               return NULL;
+       }
+       *size = (unsigned int) out_size;
+       return out;
+}
+
+
+void add_supported_versions(struct tls_buffer *buf, int versions) {
+       size_t size;
+       char version12[] = { 0x00, 0x2b, 0x00, 0x03, 0x02, 0x03, 0x03 };
+       char version13[] = { 0x00, 0x2b, 0x00, 0x03, 0x02, 0x03, 0x04 };
+       char both[] = { 0x00, 0x2b, 0x00, 0x05, 0x04, 0x03, 0x04, 0x03, 0x03 };
+       char *use;
+
+       switch (versions) {
+               case 1:
+                       use = version12;
+                       size = sizeof version12;
+                       break;
+               case 2:
+                       use = version13;
+                       size = sizeof version13;
+                       break;
+               case 3:
+                       use = both;
+                       size = sizeof both;
+                       break;
+       }
+
+       tls_buffer_append(buf, use, size);
+}
+
+static void add_sni_extension(struct tls_buffer *buf, char *sni) {
+       size_t len;
+
+       if (!buf || !sni) {
+               return;
+       }
+
+       len = strlen(sni);
+
+       /* server name extension id = 0x00 0x00 */
+       tls_buffer_append16(buf, 0x0000);
+       /* length of server name extension */
+       tls_buffer_append16(buf, len + 5);
+       /* length of first entry */
+       tls_buffer_append16(buf, len + 3);
+       /* DNS hostname */
+       tls_buffer_append_byte(buf, 0x00);
+       /* length of entry */
+       tls_buffer_append16(buf, len);
+       /* actual server name indication */
+       tls_buffer_append(buf, sni, len);
+
+}
+
+
+/*
+00 20 - 0x20 (32) bytes of cipher suite data
+
+
+*/
+
+static void add_cipher_suites(struct tls_buffer *buf, int suites) {
+       /* the five TLS 1.3 cipher suites in B.4 of rfc 8446 */
+       /* chacha20 preferred */
+       unsigned char tls_13_suites[] = {
+               0x13, 0x03, 0x13, 0x01, 0x13, 0x02, 0x13, 0x04, 0x13, 0x04
+       };
+       unsigned char tls_12_suites[] = {
+               0xcc, 0xa9, 0xc0, 0x2b, 0xc0, 0x23, 0xcc, 0xa8, 0xc0, 0x2f,
+               0xc0, 0x27, 0x00, 0x9e, 0x00, 0x6b, 0x00, 0x67, 0xcc, 0xaa
+               };
+
+       size_t len = 0;
+
+       if (suites & 1) {
+               len += sizeof tls_12_suites;
+       }
+       
+       if (suites & 2) {
+               len += sizeof tls_13_suites;
+       }
+
+       tls_buffer_expand(buf, len + 2);
+       tls_buffer_append16(buf, len);
+       /* if we're including 1.3 ciphers, put them first so they're preferred
+        */
+       if (suites & 2) {
+               tls_buffer_append(buf, tls_13_suites, sizeof tls_13_suites);
+       }
+       if (suites & 1) {
+               tls_buffer_append(buf, tls_12_suites, sizeof tls_12_suites);
+       }
+}
+
+void add_signed_certificate_timestamp_extension(struct tls_buffer *buf) {
+       char sct[] = { 0x00, 0x12, 0x00, 0x00 }; /* sct id and zero bytes */
+       tls_buffer_append(buf, sct, sizeof sct);
+}
+
+/*
+ * 00 05 - assigned value for extension "status request"
+ * 00 05 - 0x5 (5) bytes of "status request" extension data follows
+ * 01 - assigned value for "certificate status type: OCSP"
+ * 00 00 - 0x0 (0) bytes of responderID information
+ * 00 00 - 0x0 (0) bytes of request extension information 
+ */
+void add_status_request_extension(struct tls_buffer *buf) {
+       char sr[] = { 0x00, 0x05, 0x00, 0x05, 0x01, 0x00, 0x00, 0x00, 0x00 };
+       tls_buffer_append(buf, sr, sizeof sr);
+}
+
+void add_supported_groups_extension(struct tls_buffer *buf) {
+       /* supported groups */
+       /* this specifies the curves */
+       unsigned char groups[] = {
+               /* extension id and size in bytes */
+               0x00, 0x0a, 0x00, 0x08,
+               /* six bytes of groups */
+               0x00, 0x06,
+#if 0
+               /* x25519, */
+               0x00, 0x1d,
+#endif
+               /* secp256r1, secp384r1, secp521r1 */
+               0x00, 0x17, 0x00, 0x18, 0x00, 0x19
+       };
+       tls_buffer_append(buf, groups, sizeof groups);
+}
+
+/*
+ * 00 0b - assigned value for extension "EC points format"
+ * 00 02 - 0x2 (2) bytes of "EC points format" extension data follows
+ * 01 - 0x1 (1) bytes of data are in the supported formats list
+ * 00 - assigned value for uncompressed form 
+ */
+void add_ec_point_formats_extension(struct tls_buffer *buf) {
+       char formats[] = { 0x00, 0x0b, 0x00, 0x02, 0x01, 0x00 };
+       tls_buffer_append(buf, formats, sizeof formats);
+}
+
+void add_signature_algorithms_extension(struct tls_buffer *buf) {
+       char algorithms[] = {
+               0x00, 0x0d, 0x00, 0x0e, 0x00, 0x0c, /* id and lengths */
+               0x04, 0x01, /* RSA/PKCS1/SHA256 */
+               0x04, 0x03, /* ECDSA/SECP256r1/SHA256 */
+               0x05, 0x01, /* RSA/PKCS1/SHA386 */
+               0x05, 0x03, /* ECDSA/SECP384r1/SHA384 */
+               0x06, 0x01, /* RSA/PKCS1/SHA512 */
+               0x06, 0x03 /* ECDSA/SECP521r1/SHA512 */
+       };
+#if 0
+       /* TODO x25519 ? */
+       char tls13algs[] = {
+               0x04, 0x03,
+               0x08, 0x04, /* RSA-PSS-RSAE-SHA256 */
+               0x04, 0x01,
+               0x05, 0x03,
+               0x08, 0x05, /* RSA-PSS-RSAE-SHA384 */
+               0x05, 0x01,
+               0x08, 0x06, /* RSA-PSS-RSAE-SHA512 */
+               0x06, 0x01
+                       /* and 0x02, 0x01 for RSA-PKCS1-SHA1 */
+
+       };
+#endif
+
+       tls_buffer_append(buf, algorithms, sizeof algorithms);
+}
+
+static void add_renegotiation_info_extension(struct tls_buffer *buf) {
+               /* two bytes id, and one byte of zero bytes of info */
+       char info[] = { 0xff, 0x01, 0x00, 0x01, 0x00 };
+
+       tls_buffer_append(buf, info, sizeof info);
+}
+
+/*
+ * 00 33 - assigned value for extension "Key Share"
+ * 00 26 - 0x26 (38) bytes of "Key Share" extension data follows
+ * 00 24 - 0x24 (36) bytes of key share data follows
+ * 00 1d - assigned value for x25519 (key exchange via curve25519)
+ * 00 20 - 0x20 (32) bytes of public key follows
+ * 35 80 ... 62 54 - public key from the step "Client Key Exchange Generation" 
+ */
+static void add_key_share_extension(struct tls_buffer *buf, struct TLSContext
+               *ctx) {
+       char kseid[] = { 0x00, 0x33, 0x00, 0x26, 0x00, 0x24, 0x00, 0x1d, 0x00,
+               0x20 };
+       char bogus_key[32] = { 0 };
+
+       if (!ctx) {
+               return;
+       }
+
+       /* TODO figure out where the client key share is */
+       tls_buffer_append(buf, kseid, sizeof kseid);
+       tls_buffer_append(buf, bogus_key, sizeof bogus_key);
+}
+
+/*
+ * 00 2d - assigned value for extension "PSK Key Exchange Modes"
+ * 00 02 - 0x2 (2) bytes of "PSK Key Exchange Modes" extension data follows
+ * 01 - 0x1 (1) bytes of exchange modes follow
+ * 01 - assigned value for "PSK with (EC)DHE key establishment" 
+ *
+ * we don't actually pre-share keys here, so ignored, but we'll send it
+ * anyway
+ */
+/* TODO probably need to get these from the context */
+static void add_pks_key_exchanges_modes_extension(struct tls_buffer *buf) {
+       char psk[] = { 0x00, 0x2d, 0x00, 0x02, 0x01, 0x01 };
+
+       tls_buffer_append(buf, psk, sizeof psk);
+}
+
+static void set_handshake_header(char *buf, int type, size_t length) {
+       buf[0] = type & 0xff;
+       buf[1] = (length >> 16) & 0xff;
+       buf[2] = (length >> 8) & 0xff;
+       buf[3] = (length >> 0) & 0xff;
+}
+
+int tls_client_hello(struct TLSContext *ctx, struct tls_buffer *hello) {
+       size_t hello_offset = hello->len;
+
+       /* make room for the handshake header */
+       tls_buffer_expand(hello, 4);
+       hello->len += 4;
+
+       /* actual client hello structure follows */
+
+       tls_buffer_append(hello, "\x03\x03", 2); /* legacy_version */
+       /* random not set up yet */
+       //tls_random(ctx->local_random, 32);
+       tls_buffer_append(hello, ctx->local_random, 32); /* client random */
+       tls_buffer_append(hello, "\0", 1); /* legacy_session_id */
+       /* alternatively, append a 32 (0x20) and 32 random bytes as a bogus
+        * session id */
+
+       /*
+        * cipher suites
+        * TODO need a way to only use v1.3
+        */
+       int suites = TLS12_FLAG; /* always use v1.2 suites */
+
+       if (ctx->tlsver == TLS_VERSION13) {
+               suites |= TLS13_FLAG;
+       }
+       add_cipher_suites(hello, suites);
+
+               /* legacy_compression_methods */
+       tls_buffer_append(hello, "\1\0", 2);
+       
+       /* 
+        * extensions
+        * TODO I don't think the extension order matters, so the code below
+        * can be simplified by putting all the extensions together by version
+        */
+       size_t extensions_start = hello->len;
+       /* first two bytes are length of extensions, so make room to fill them
+        * in once we know the size
+        */
+       tls_buffer_append(hello, "\0\0", 2);
+
+       /* TODO need to track which extensions we're sending:
+        * "If a client receives an extension type in ServerHello that it did
+        * not request in the associated ClientHello, it MUST abort the
+        * handshake with an unsupported_extension fatal alert."
+        */
+       add_sni_extension(hello, ctx->sni); /* server name indicator */
+
+#if 0
+       /* TODO not sure why 1.3 doesn't need or want this */
+       /* TODO duckduckgo.com seems to fail with this one */
+       if (ctx->tlsver == TLS_VERSION12) {
+               add_status_request_extension(hello);
+       }
+#endif
+
+       add_supported_groups_extension(hello);
+
+       /* v1.2 only, points are fixed in v1.3 */
+       if (ctx->tlsver == TLS_VERSION12) {
+               add_ec_point_formats_extension(hello);
+       }
+
+       add_signature_algorithms_extension(hello);
+
+       if (ctx->tlsver == TLS_VERSION13) {
+               add_key_share_extension(hello, ctx);
+               add_pks_key_exchanges_modes_extension(hello);
+       }
+
+       /* v1.2 only, 1.3 doesn't support renegotiation
+        * and doesn't seem to need cert ts
+        */
+       if (ctx->tlsver == TLS_VERSION12) {
+               add_renegotiation_info_extension(hello);
+               add_signed_certificate_timestamp_extension(hello);
+       }
+
+       if (ctx->tlsver == TLS_VERSION13) {
+               /* supported versions is mandatory in V1.3 */
+               /* 1 v1.2 only, 2 = v1.3 only, 3 = both */
+               /* TODO need a context flag to allow fallback to v1.2 */
+               /* could probably pass this in v1.2 and the server
+                * would ignore it */
+               add_supported_versions(hello, 3);
+       }
+
+       /* set the extensions length */
+       size_t extensions_length = hello->len - extensions_start - 2;
+       tls_buffer_write16(hello, extensions_length, extensions_start);
+
+       /* fill in the handshake header */
+       size_t hello_length = hello->len - hello_offset - 4;
+       set_handshake_header(hello->buffer+hello_offset, client_hello,
+                       hello_length);
+
+       tls_buffer_compact(hello);
+       return hello->error;
+}
+
+#if 0
+void pbytes(unsigned char *b, size_t len, char *label) {
+       size_t i;
+
+       fprintf(stderr, "%s (%zu bytes)\n", label ? label : "dumping", len);
+
+       for (i=0; i<len; i++) {
+               fprintf(stderr, "%s%02x%s",
+                               i % 20 ? " " : "",
+                               b[i],
+                               (i+1) % 20 ? "" : "\n"
+                      );
+       }
+       if (i%20) {
+               fprintf(stderr, "\n");
+       }
+}
+#endif
+
+struct TLSPacket *tls_build_client_hello(struct TLSContext *context) {
+       if (context->connection_status == 4) {
+               unsigned char header[4] = { 0xFE, 0, 0, 0 };
+               unsigned char hash[TLS_MAX_SHA_SIZE];
+               static unsigned char sha256_helloretryrequest[] =
+                   { 0xCF, 0x21, 0xAD, 0x74, 0xE5, 0x9A, 0x61, 0x11, 0xBE,
+                       0x1D, 0x8C, 0x02, 0x1E, 0x65, 0xB8, 0x91, 0xC2,
+                       0xA2, 0x11, 0x16, 0x7A, 0xBB, 0x8C, 0x5E, 0x07,
+                       0x9E, 0x09, 0xE2, 0xC8, 0xA8, 0x33, 0x9C
+               };
+               fprintf(stderr, "got hello retry request\n");
+               memcpy(context->local_random, sha256_helloretryrequest, 32);
+               int hash_len = tls_done_hash(context, hash);
+               header[3] = (unsigned char) hash_len;
+               tls_update_hash(context, header, sizeof header);
+               tls_update_hash(context, hash, hash_len);
+       } else if (context->tlsver != TLS_VERSION13) {
+               //fprintf(stderr, "creating local_random\n");
+               if (!tls_random(context->local_random, TLS_SERVER_RANDOM_SIZE)) {
+                       return NULL;
+               }
+       }
+
+       struct tls_buffer shadow;
+       char record_header[] = { 0x16, 0x03, 0x03, 0x00, 0x00 };
+
+       tls_buffer_init(&shadow, 106);
+       tls_buffer_append(&shadow, record_header, sizeof record_header);
+       tls_client_hello(context, &shadow);
+       tls_buffer_writebe(&shadow, 3, 6, shadow.len - 9);
+
+       if (shadow.error) {
+               tls_buffer_free(&shadow);
+               return NULL;
+       }
+
+       struct TLSPacket *packet = malloc(sizeof *packet);
+
+       if (!packet) {
+               return NULL;
+       }
+
+       free(packet->buf);
+       packet->buf = shadow.buffer;
+       packet->len = shadow.len;
+       packet->size = shadow.size;
+       packet->payload_pos = 0;
+       packet->broken = 0;
+       packet->context = context;
+
+       tls_packet_update(packet);
+
+       return packet;
+}
+
+int tls_send_client_hello(struct TLSContext *ctx) {
+       return ctx ? 1 : 0;
+}
+
+struct TLSPacket *tls_build_hello(struct TLSContext *context,
+                                 int tls13_downgrade) {
+       if (context->connection_status == 4) {
+               unsigned char header[4] = { 0xFE, 0, 0, 0 };
+               unsigned char hash[TLS_MAX_SHA_SIZE];
+               static unsigned char sha256_helloretryrequest[] =
+                   { 0xCF, 0x21, 0xAD, 0x74, 0xE5, 0x9A, 0x61, 0x11, 0xBE,
+                       0x1D, 0x8C, 0x02, 0x1E, 0x65, 0xB8, 0x91, 0xC2,
+                       0xA2, 0x11, 0x16, 0x7A, 0xBB, 0x8C, 0x5E, 0x07,
+                       0x9E, 0x09, 0xE2, 0xC8, 0xA8, 0x33, 0x9C
+               };
+               fprintf(stderr, "got hello retry request\n");
+               memcpy(context->local_random, sha256_helloretryrequest, 32);
+               int hash_len = tls_done_hash(context, hash);
+               header[3] = (unsigned char) hash_len;
+               tls_update_hash(context, header, sizeof header);
+               tls_update_hash(context, hash, hash_len);
+       } else if (!context->is_server || context->tlsver != TLS_VERSION13) {
+               fprintf(stderr, "creating local_random\n");
+               if (!tls_random(context->local_random, TLS_SERVER_RANDOM_SIZE)) {
+                       return NULL;
+               }
+       }
+
+       if (context->is_server && tls13_downgrade) {
+               if (tls13_downgrade == TLS_V12 || tls13_downgrade == DTLS_V12)
+               {
+                       memcpy(context->local_random +
+                              TLS_SERVER_RANDOM_SIZE - 8, "DOWNGRD\x01",
+                              8);
+               } else {
+                       memcpy(context->local_random +
+                              TLS_SERVER_RANDOM_SIZE - 8, "DOWNGRD\x00",
+                              8);
+               }
+       }
+
+       if (!context->is_server) {
+               struct tls_buffer shadow;
+               char record_header[] = { 0x16, 0x03, 0x03, 0x00, 0x00 };
+
+               tls_buffer_init(&shadow, 106);
+               tls_buffer_append(&shadow, record_header, sizeof record_header);
+               tls_client_hello(context, &shadow);
+               tls_buffer_writebe(&shadow, 3, 6, shadow.len - 9);
+
+               if (shadow.error) {
+                       tls_buffer_free(&shadow);
+                       return NULL;
+               }
+
+               struct TLSPacket *packet = malloc(sizeof *packet);
+
+               if (!packet) {
+                       return NULL;
+               }
+
+               free(packet->buf);
+               packet->buf = shadow.buffer;
+               packet->len = shadow.len;
+               packet->size = shadow.size;
+               packet->payload_pos = 0;
+               packet->broken = 0;
+               packet->context = context;
+
+               tls_packet_update(packet);
+
+               fprintf(stderr, "returning packet\n");
+               return packet;
+       }
+
+       /* context must be server from here on out */
+
+       unsigned short packet_version = context->version;
+       unsigned short version = context->version;
+
+       if (context->version == TLS_V13) {
+               version = TLS_V12;
+       } else if (context->version == DTLS_V13) {
+               version = DTLS_V12;
+       }
+
+       struct TLSPacket *packet =
+               tls_create_packet(context, TLS_HANDSHAKE, packet_version, 0);
+
+       /* hello */
+       tls_packet_uint8(packet, server_hello);
+
+       tls_packet_uint24(packet, 0);
+
+       int start_len = packet->len;
+       tls_packet_uint16(packet, version);
+
+       tls_packet_append(packet, context->local_random,
+                       TLS_SERVER_RANDOM_SIZE);
+
+       /* session size, always 0, we don't support sessions */
+       tls_packet_uint8(packet, 0);
+
+       int extension_len = 0;
+       int alpn_len = 0;
+       int alpn_negotiated_len = 0;
+       unsigned char shared_key[TLS_MAX_RSA_KEY];
+       unsigned long shared_key_len = TLS_MAX_RSA_KEY;
+       unsigned short shared_key_short = 0;
+       int selected_group = 0;
+       if (context->tlsver == TLS_VERSION13) {
+               if (context->curve == &curve25519) {
+                       extension_len += 8 + 32;
+                       shared_key_short = (unsigned short) 32;
+                       if (context->finished_key) {
+                               memcpy(shared_key,
+                                               context->
+                                               finished_key, 32);
+                               free(context->finished_key);
+                               context->finished_key = NULL;
+                       }
+                       selected_group = context->curve->iana;
+                       /* make context->curve NULL (x25519 is a different implementation) */
+                       context->curve = NULL;
+               } else if (context->ecc_dhe) {
+                       if (ecc_ansi_x963_export
+                                       (context->ecc_dhe, shared_key,
+                                        &shared_key_len)) {
+                               DEBUG_PRINT
+                                       ("Error exporting ECC DHE key\n");
+                               tls_destroy_packet(packet);
+                               tls_alert(context, 1, internal_error);
+                               return NULL;
+                       }
+                       tls_ecc_dhe_free(context);
+                       extension_len += 8 + shared_key_len;
+                       shared_key_short =
+                               (uint16_t)shared_key_len;
+                       if (context->curve) {
+                               selected_group =
+                                       context->curve->iana;
+                       }
+               } else if (context->dhe) {
+                       selected_group = context->dhe->iana;
+                       tls_dh_export_Y(shared_key,
+                                       &shared_key_len,
+                                       context->dhe);
+                       tls_dhe_free(context);
+                       extension_len += 8 + shared_key_len;
+                       shared_key_short = shared_key_len;
+               }
+
+               extension_len += 6;
+       }
+
+       if (context->negotiated_alpn && context->tlsver != TLS_VERSION13) {
+               alpn_negotiated_len = strlen(context->negotiated_alpn);
+               alpn_len = alpn_negotiated_len + 1;
+               extension_len += alpn_len + 6;
+       }
+
+       /* ciphers */
+       /* fallback ... this should never happen */
+       if (!context->cipher) {
+               context->cipher = TLS_DHE_RSA_WITH_AES_128_CBC_SHA;
+       }
+
+       tls_packet_uint16(packet, context->cipher);
+       /* no compression */
+       tls_packet_uint8(packet, 0);
+
+       if (context->tlsver == TLS_VERSION13) {
+               /* supported versions */
+               tls_packet_uint16(packet, 0x2B);
+
+               tls_packet_uint16(packet, 2);
+               if (context->version == TLS_V13) {
+                       tls_packet_uint16(packet,
+                                       context-> tls13_version ?
+                                       context-> tls13_version :
+                                       TLS_V13);
+               } else {
+                       tls_packet_uint16(packet, context->version);
+               }
+
+               if (context->connection_status == 4) {
+                       /* fallback to the mandatory secp256r1 */
+                       tls_packet_uint16(packet, 0x33);
+                       tls_packet_uint16(packet, 2);
+                       tls_packet_uint16(packet, (uint16_t) secp256r1.iana);
+               }
+
+               if (shared_key_short && selected_group) {
+                       /* key share */
+                       tls_packet_uint16(packet, 0x33);
+                       tls_packet_uint16(packet, shared_key_short + 4);
+                       tls_packet_uint16(packet, selected_group);
+                       tls_packet_uint16(packet, shared_key_short);
+                       tls_packet_append(packet, (unsigned char *) shared_key,
+                                       shared_key_short);
+               }
+       }
+
+       if (!packet->broken && packet->buf) {
+               tls_set_packet_length(packet, packet->len - start_len);
+       }
+
+       tls_packet_update(packet);
+
+       return packet;
+}
+
+struct TLSPacket *tls_buffer_packet(struct tls_buffer *b, struct TLSContext *c) {
+       struct TLSPacket *p = 0;
+
+       if (b && c) {
+               p = tls_create_packet(c, TLS_HANDSHAKE, c->version, 0);
+
+               if (p) {
+                       free(p->buf);
+                       p->buf = b->buffer;
+                       p->size = b->size;
+                       p->len = b->len;
+                       p->payload_pos = 0;
+                       p->broken = 0;
+                       p->context = c;
+               } else {
+                       tls_buffer_free(b);
+               }
+       }
+
+       return p;
+}
+
+static void append_dhe(struct TLSContext *ctx, struct tls_buffer *buf) {
+       unsigned char dh_Ys[0xFFF];
+       unsigned char dh_p[0xFFF];
+       unsigned char dh_g[0xFFF];
+       unsigned long dh_p_len = sizeof dh_p;
+       unsigned long dh_g_len = sizeof dh_g;
+       unsigned long dh_Ys_len = sizeof dh_Ys;
+
+       if (tls_dh_export_pqY(dh_p, &dh_p_len, dh_g, &dh_g_len, dh_Ys,
+                               &dh_Ys_len, ctx->dhe)) {
+               DEBUG_PRINT("ERROR EXPORTING DHE KEY %p\n", ctx->dhe);
+               buf->error = 1;
+               tls_dhe_free(ctx);
+               return;
+       }
+
+       tls_dhe_free(ctx);
+
+       DEBUG_DUMP_HEX_LABEL("Yc", dh_Ys, dh_Ys_len);
+
+       tls_buffer_append24(buf, dh_Ys_len + 2);
+
+       tls_buffer_append16(buf, dh_Ys_len);
+       tls_buffer_append(buf, dh_Ys, dh_Ys_len);
+}
+
+static void append_ecdhe(struct TLSContext *ctx, struct tls_buffer *buf) {
+       unsigned char out[TLS_MAX_RSA_KEY];
+       unsigned long out_len = TLS_MAX_RSA_KEY;
+
+       //fprintf(stderr, "ecc dhe\n");
+
+       if (ecc_ansi_x963_export(ctx->ecc_dhe, out, &out_len)) {
+               DEBUG_PRINT("Error exporting ECC key\n");
+               buf->error = 1;
+       }
+
+       tls_ecc_dhe_free(ctx);
+
+       tls_buffer_append_byte(buf, 0x10);
+       tls_buffer_append24(buf, out_len + 1);
+
+       tls_buffer_append_byte(buf, out_len);
+       tls_buffer_append(buf, out, out_len);
+}
+
+static void set_record_size(struct tls_buffer *b) {
+       uint16_t size;
+
+       size = b->len - 5;
+       tls_buffer_write16(b, size, 3);
+}
+
+struct TLSPacket *tls_client_key_exchange(struct TLSContext *context) {
+       struct tls_buffer cke;
+       struct TLSPacket *p;
+
+       tls_buffer_init(&cke, 42);
+       tls_buffer_append_byte(&cke, 0x16);
+       tls_buffer_append16(&cke, 0x0303);
+       tls_buffer_append16(&cke, 0); /* record size placeholder */
+
+       if (context->ecc_dhe) {
+               append_ecdhe(context, &cke);
+       } else {
+               append_dhe(context, &cke);
+       }
+       set_record_size(&cke);
+
+       p = tls_buffer_packet(&cke, context);
+
+       tls_compute_key(context, 48);
+       context->connection_status = 2;
+       tls_packet_update(p);
+
+       return p;
+}
+
+static int tls_build_random(struct TLSPacket *packet) {
+       int res = 0;
+       unsigned char rand_bytes[48];
+       int bytes = 48;
+
+       if (!tls_random(rand_bytes, bytes)) {
+               return TLS_GENERIC_ERROR;
+       }
+
+       /* max supported version */
+       if (packet->context->is_server) {
+               *(unsigned short *) rand_bytes =
+                   htons(packet->context->version);
+       } else {
+               *(unsigned short *) rand_bytes = htons(TLS_V12);
+       }
+
+       /* DEBUG_DUMP_HEX_LABEL("PREMASTER KEY", rand_bytes, bytes); */
+
+       free(packet->context->premaster_key);
+
+       packet->context->premaster_key = malloc(bytes);
+       if (!packet->context->premaster_key) {
+               return TLS_NO_MEMORY;
+       }
+
+       packet->context->premaster_key_len = bytes;
+       memcpy(packet->context->premaster_key, rand_bytes,
+              packet->context->premaster_key_len);
+
+       unsigned int out_len;
+
+       unsigned char *random = encrypt_rsa(packet->context,
+                       packet->context->premaster_key,
+                       packet->context->premaster_key_len, &out_len);
+
+       tls_compute_key(packet->context, bytes);
+       if (random && out_len > 2) {
+               tls_packet_uint24(packet, out_len + 2);
+               tls_packet_uint16(packet, out_len);
+               tls_packet_append(packet, random, out_len);
+       } else {
+               res = TLS_GENERIC_ERROR;
+       }
+
+       free(random);
+
+       if (res) {
+               return res;
+       }
+
+       return out_len + 2;
+}
+
+void tls_send_client_key_exchange(struct TLSContext *context) {
+       struct TLSPacket *packet;
+
+       int ephemeral = tls_cipher_is_ephemeral(context);
+
+       if (ephemeral && context->premaster_key && context->premaster_key_len) {
+               //fprintf(stderr, "YYYY\n");
+               packet = tls_client_key_exchange(context);
+               tls_queue_packet(packet);
+               return;
+               if (ephemeral == 1) {
+                       /* dhe */
+               } else if (context->ecc_dhe) {
+                       /* ecc dhe */
+               }
+       } else {
+               /* TODO should never happen, should always require
+                * either DHE or ECC DHE */
+               fprintf(stderr, "ZZZZ build random\n");
+               return;
+               packet = tls_create_packet(context, TLS_HANDSHAKE, context->version, 0);
+               tls_packet_uint8(packet, 0x10);
+               tls_build_random(packet);
+       }
+       context->connection_status = 2;
+       tls_packet_update(packet);
+       tls_queue_packet(packet);
+       return;
+}
+
+static uint32_t get24(const unsigned char *buf) {
+       return (*buf << 16) + (*(buf+1) << 8) + *(buf+2);
+}
+
+static uint16_t get16(const unsigned char *buf) {
+       return (*(buf) << 8) + *(buf+1);
+}
+
+int tls_hello_complete(const unsigned char *buf, size_t len) {
+       size_t more;
+
+       if (len < 3) {
+               return 0;
+       }
+
+       more = get16(buf);
+       if (more > len - 3) {
+               fprintf(stderr, "%s:%d\n", __func__, __LINE__);
+               fprintf(stderr, "have %zu, want %zu\n", len, more);
+               return 0;
+       }
+       return 1;
+}
+
+int tls_parse_server_hello(struct TLSContext *ctx, const unsigned char *buf, size_t len) {
+       size_t i = 0;
+       size_t more = 0;
+
+       if (ctx->connection_status != 0 && ctx->connection_status != 4) {
+               return TLS_UNEXPECTED_MESSAGE;
+       }
+
+       if (!tls_hello_complete(buf, len)) {
+               return TLS_NEED_MORE_DATA;
+       }
+
+       /* 3 bytes server hello data size */
+       more = get24(buf+i);
+       i+=3;
+       /* TODO check size reported vs actual */
+
+       /* two bytes server version */
+       uint16_t server_ver = get16(buf+i);
+       i+=2;
+       if (server_ver != ctx->version) {
+               /* TODO allow (or not) downgrade to v1.2 */
+               return TLS_UNEXPECTED_MESSAGE;
+       }
+
+       /* 32 bytes server random */
+       memcpy(ctx->remote_random, buf+i, 32);
+       i+=32;
+
+       /* 1 byte of session id length */
+       uint8_t session_len = *(buf+i);
+       i+=1;
+
+       char *session_id;
+       /* possible session id bytes */
+       /* TODO skip? we don't actually use session ids */
+       if (session_len) {
+               session_id = malloc(session_len);
+               if (!session_id) {
+                       return 0;
+               }
+
+               memcpy(session_id, buf+i, session_len);
+       }
+       i+=session_len;
+
+       /* two bytes cipher suite selected */
+       ctx->cipher = get16(buf+i);
+       i+=2;
+       if (!tls_cipher_supported(ctx, ctx->cipher)) {
+               ctx->cipher = 0;
+               DEBUG_PRINT("NO CIPHER SUPPORTED\n");
+               return TLS_NO_COMMON_CIPHER;
+       }
+
+       /* one byte compression method */
+       uint8_t compression_method = *(buf+i);
+       i++;
+       if (compression_method != 0) {
+               return 0;
+       }
+
+       if (i > 0 && ctx->connection_status != 4) {
+               ctx->connection_status = 1;
+       }
+
+       if (i+2 > len) {
+               /* no extensions */
+               return 0;
+       }
+
+       /* two bytes extensions length */
+       uint16_t extensions_length = get16(buf+i);
+       i+=2;
+
+       if (extensions_length + i != len) {
+               /* mismatch */
+               return 0;
+       }
+
+       /* extensions */
+       while (i+5 <= len) {
+               int etype = get16(buf+i);
+               i+=2;
+
+               /* TODO check that extension type is in the list of
+                * extensions we sent, if not, abort with
+                * unsupported_extension fatal alert
+                */
+               uint16_t elen = get16(buf+i);
+               i+=2;
+               if (elen == 0) {
+                       continue;
+               }
+               if (i+elen > len) {
+                       return TLS_BROKEN_PACKET;
+               }
+
+               uint16_t sni_len;
+               uint16_t alpn_len;
+               const unsigned char *alpn;
+               unsigned char alpn_size;
+               int alpn_pos = 0;
+               uint16_t group_len, iana_n;
+               int j = i;
+               int selected = 0;
+
+               switch (etype) {
+                       case 0x0000:
+                               sni_len = get16(buf+i);
+                               if (sni_len) {
+                                       ctx->sni = malloc(sni_len + 1);
+                                       memcpy(ctx->sni, buf+i+2, sni_len);
+                                       ctx->sni[sni_len] = 0;
+                               }
+                               break;
+                       case 0x000a: /* supported groups */
+                               fprintf(stderr, "supported groups\n");
+                               /* supported groups */
+                               if (i+2 > len) {
+                                       return TLS_BROKEN_PACKET;
+                               }
+
+                               group_len = get16(buf+i);
+                               for (j = i; i < i + group_len+2; i+=2) {
+                                       iana_n = get16(buf+j);
+                                       switch (iana_n) {
+                                               case 23:
+                                                       ctx->curve = &secp256r1;
+                                                       selected = 1;
+                                                       break;
+                                               case 24:
+                                                       ctx->curve = &secp384r1;
+                                                       selected = 1;
+                                                       break;
+                                               case 29:
+                                                       ctx->curve = &curve25519;
+                                                       selected = 1;
+                                                       break;
+                                               case 25:
+                                                       ctx->curve = &secp521r1;
+                                                       selected = 1;
+                                                       break;
+                                       }
+                               }
+                               /* if ctx->curve */
+                               if (selected) {
+                                       fprintf(stderr, "SELECTED CURVE %s\n",
+                                                ctx->curve->name);
+                               }
+                       case 0x0010:
+                               if (!ctx->alpn || ctx->alpn_count == 0) {
+                                       break;
+                               }
+                               if (i+2 > len) {
+                                       return TLS_BROKEN_PACKET;
+                               }
+
+                               alpn_len = get16(buf+i);
+
+                               if (alpn_len == 0 || alpn_len > elen - 2) {
+                                       /* TODO broken */
+                                       break;
+                               }
+                               /* a server's alpn list "must contain exactly
+                                * one "ProtocolName"
+                                */
+                               alpn_size = buf[i + 2];
+                               alpn = buf + i + 3;
+                               if (i + alpn_size + 3 < len) {
+                                       break;
+                               }
+
+                               if (!tls_alpn_contains(ctx, (char *)alpn, alpn_size)) {
+                                       break;
+                               }
+                               free(ctx->negotiated_alpn);
+                               ctx->negotiated_alpn = malloc(alpn_size + 1);
+                               if (ctx->negotiated_alpn) {
+                                       memcpy(ctx->negotiated_alpn,
+                                                       &alpn[alpn_pos],
+                                                       alpn_size);
+                                       ctx->negotiated_alpn[alpn_size] = 0;
+                               }
+                               break;
+                       case 0xff01: /* renegotiation info */
+                               //fprintf(stderr, "renegotiation info\n");
+                               /* ignore, we don't support renegotiation */
+                               break;
+                       case 0x0033: /* key share */
+                               /* TODO parse key share */
+                               fprintf(stderr, "key share info\n");
+                               break;
+                       case 0x000b:
+                               /* signature algorithms */
+                               break;
+                       case 0x002b: /* supported versions */
+                               /* should be two bytes of 0x00 0x02
+                                * indicating two bytes of server version
+                                * then 0x03 0x04 for v1.3
+                                */
+                               fprintf(stderr, "supported versions\n");
+                               break;
+                       default:
+                               fprintf(stderr, "unknown extension %04x\n", etype);
+                               break;
+               }
+               i+=elen;
+       }
+
+#if 0
+       if (ctx->connection_status != 4) {
+               ctx->connection_status = 1;
+       }
+#endif
+
+       return 1;
+}
diff --git a/crypto/hash.c b/crypto/hash.c
new file mode 100644 (file)
index 0000000..c045de6
--- /dev/null
@@ -0,0 +1,108 @@
+#define _POSIX_C_SOURCE 200809L
+
+#include "tlse.h"
+
+void tls_destroy_hash(struct TLSContext *context) {
+       if (context) {
+               context->hs_index = -1;
+       }
+       return;
+}
+
+static void create_hash(struct TLSContext *context) {
+       int index;
+
+       if (!context) {
+               return;
+       }
+
+       int hash_size = tls_mac_length(context);
+
+       if (hash_size == TLS_SHA384_MAC_SIZE) {
+               index = find_hash("sha384");
+       } else {
+               index = find_hash("sha256");
+       }
+       context->hs_index = index;
+       context->handshake_init = hash_descriptor[index].init;
+       context->handshake_process = hash_descriptor[index].process;
+       context->handshake_done = hash_descriptor[index].done;
+
+       context->handshake_init(&context->hs_hash);
+       context->hs_created = 1;
+}
+
+int tls_update_hash(struct TLSContext *context, const unsigned char *in,
+               unsigned int len) {
+       if (!context) {
+               return 0;
+       }
+
+       if (!len) {
+               return 0;
+       }
+
+       if (!context->hs_created) {
+               create_hash(context);
+       }
+
+       context->handshake_process(&context->hs_hash, in, len);
+
+       if (context->request_client_certificate) {
+               tls_buffer_append(&context->cached_handshake, in, len);
+       }
+       return 0;
+}
+
+int tls_done_hash(struct TLSContext *context, unsigned char *hout) {
+       if (!context) {
+               return 0;
+       }
+
+       if (!context->hs_created) {
+               return 0;
+       }
+
+       if (hout) {
+               context->handshake_done(&context->hs_hash, hout);
+       }
+       /* TODO zero memory? */
+       context->hs_created = 0;
+
+       tls_buffer_free(&context->cached_handshake);
+       return tls_mac_length(context);
+}
+
+int tls_get_hash_idx(struct TLSContext *context) {
+       if (!context) {
+               return -1;
+       }
+
+       switch (tls_mac_length(context)) {
+               case TLS_SHA256_MAC_SIZE:
+                       return find_hash("sha256");
+               case TLS_SHA384_MAC_SIZE:
+                       return find_hash("sha384");
+               case TLS_SHA1_MAC_SIZE:
+                       return find_hash("sha1");
+       }
+       return -1;
+}
+
+int tls_get_hash(struct TLSContext *context, unsigned char *hout) {
+       hash_state prec;
+
+       if (!context) {
+               return 0;
+       }
+
+       if (!context->hs_created) {
+               return 0;
+       }
+
+       prec = context->hs_hash;
+
+       context->handshake_done(&prec, hout);
+
+       return tls_mac_length(context);
+}
diff --git a/crypto/hkdf.c b/crypto/hkdf.c
new file mode 100644 (file)
index 0000000..4c601bc
--- /dev/null
@@ -0,0 +1,133 @@
+#define _POSIX_C_SOURCE 200809L
+
+#include <fcntl.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <time.h>
+
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <unistd.h>
+
+#include <errno.h>
+
+#include <tomcrypt.h>
+#include "tlse.h"
+
+int tls_hkdf_extract(unsigned int mac_length,
+                             unsigned char *output, unsigned int outlen,
+                             const unsigned char *salt,
+                             unsigned int salt_len,
+                             const unsigned char *ikm,
+                             unsigned char ikm_len) {
+       int hash_idx;
+       unsigned long dlen = outlen;
+       unsigned char dummy_label[1] = { 0 };
+
+       if (!salt || salt_len == 0) {
+               salt_len = 1;
+               salt = dummy_label;
+       }
+
+       if (mac_length == TLS_SHA384_MAC_SIZE) {
+               hash_idx = find_hash("sha384");
+               dlen = mac_length;
+       } else {
+               hash_idx = find_hash("sha256");
+       }
+
+       hmac_memory(hash_idx, salt, salt_len, ikm, ikm_len, output, &dlen);
+       return dlen;
+}
+
+static int make_hkdf_label(const char *label, unsigned char label_len,
+                           const unsigned char *data,
+                           unsigned char data_len,
+                           unsigned char *hkdflabel,
+                           unsigned short length, const char *prefix) {
+       int prefix_len;
+       *(unsigned short *) &hkdflabel[0] = htons(length);
+
+       if (prefix) {
+               prefix_len = strlen(prefix);
+               memcpy(&hkdflabel[3], prefix, prefix_len);
+       } else {
+               memcpy(&hkdflabel[3], "tls13 ", 6);
+               prefix_len = 6;
+       }
+
+       hkdflabel[2] = (unsigned char) prefix_len + label_len;
+
+       memcpy(&hkdflabel[3 + prefix_len], label, label_len);
+
+       hkdflabel[3 + prefix_len + label_len] = data_len;
+
+       if (data_len) {
+               memcpy(&hkdflabel[4 + prefix_len + label_len], data,
+                      data_len);
+       }
+
+       return 4 + prefix_len + label_len + data_len;
+}
+
+void tls_hkdf_expand(unsigned int mac_length,
+                             unsigned char *output, unsigned int outlen,
+                             const unsigned char *secret,
+                             unsigned int secret_len,
+                             const unsigned char *info,
+                             unsigned char info_len) {
+       unsigned char digest_out[TLS_MAX_HASH_LEN];
+       unsigned long dlen = 32;
+       int hash_idx;
+       unsigned int i;
+       unsigned char i2 = 0;
+       unsigned int idx = 0;
+       hmac_state hmac;
+       unsigned int copylen;
+
+       if (mac_length == TLS_SHA384_MAC_SIZE) {
+               hash_idx = find_hash("sha384");
+               dlen = mac_length;
+       } else {
+               hash_idx = find_hash("sha256");
+       }
+
+       while (outlen) {
+               hmac_init(&hmac, hash_idx, secret, secret_len);
+               if (i2) {
+                       hmac_process(&hmac, digest_out, dlen);
+               }
+               if (info && info_len) {
+                       hmac_process(&hmac, info, info_len);
+               }
+               i2++;
+               hmac_process(&hmac, &i2, 1);
+               hmac_done(&hmac, digest_out, &dlen);
+
+               copylen = outlen;
+               if (copylen > dlen) {
+                       copylen = (unsigned int) dlen;
+               }
+
+               for (i = 0; i < copylen; i++) {
+                       output[idx++] = digest_out[i];
+                       outlen--;
+               }
+       }
+}
+
+void tls_hkdf_expand_label(unsigned int mac_length, unsigned char *output,
+               unsigned int outlen, const unsigned char *secret, unsigned int
+               secret_len, const char *label, unsigned char label_len, const
+               unsigned char *data, unsigned char data_len) {
+       unsigned char hkdf_label[512];
+       int len = make_hkdf_label(label, label_len, data, data_len, hkdf_label,
+                       outlen, NULL);
+       tls_hkdf_expand(mac_length, output, outlen, secret, secret_len,
+                       hkdf_label, len);
+}
diff --git a/crypto/hmac_message.c b/crypto/hmac_message.c
new file mode 100644 (file)
index 0000000..5f7249e
--- /dev/null
@@ -0,0 +1,69 @@
+#define _POSIX_C_SOURCE 200809L
+
+#include <arpa/inet.h>
+
+#include "tlse.h"
+
+#ifndef htonll
+#define htonll(x) ((1==htonl(1)) ? (x) : ((uint64_t)htonl((x) & 0xFFFFFFFF) << 32) | htonl((x) >> 32))
+#endif
+
+#ifndef ntohll
+#define ntohll(x) ((1==ntohl(1)) ? (x) : ((uint64_t)ntohl((x) & 0xFFFFFFFF) << 32) | ntohl((x) >> 32))
+#endif
+
+unsigned int tls_hmac_message(unsigned char local,
+                              struct TLSContext *context,
+                              const unsigned char *buf,
+                              int buf_len,
+                              const unsigned char *buf2,
+                              int buf_len2, unsigned char *out,
+                              unsigned int outlen
+                              ) {
+       hmac_state hash;
+       int hash_idx;
+
+       int mac_size = outlen;
+
+       if (mac_size == TLS_SHA1_MAC_SIZE) {
+               hash_idx = find_hash("sha1");
+       } else if (mac_size == TLS_SHA384_MAC_SIZE) {
+               hash_idx = find_hash("sha384");
+       } else {
+               hash_idx = find_hash("sha256");
+       }
+
+       if (hmac_init(&hash, hash_idx,
+            local ? context->crypto.ctx_local_mac.local_mac : context->
+            crypto.ctx_remote_mac.remote_mac, mac_size)) {
+               return 0;
+       }
+
+       uint64_t sn;
+       if (local) {
+               sn = htonll(context->local_sequence_number);
+       } else {
+               sn = htonll(context->remote_sequence_number);
+       }
+
+       if (hmac_process(&hash, (unsigned char *)&sn, sizeof sn)) {
+               return 0;
+       }
+
+       if (hmac_process(&hash, buf, buf_len)) {
+               return 0;
+       }
+
+       if (buf2 && buf_len2) {
+               if (hmac_process(&hash, buf2, buf_len2)) {
+                       return 0;
+               }
+       }
+       unsigned long ref_outlen = outlen;
+       if (hmac_done(&hash, out, &ref_outlen)) {
+               return 0;
+       }
+
+       return (unsigned int)ref_outlen;
+}
+
diff --git a/crypto/packet_update.c b/crypto/packet_update.c
new file mode 100644 (file)
index 0000000..d3ec520
--- /dev/null
@@ -0,0 +1,276 @@
+#define _POSIX_C_SOURCE 200809L
+
+#include <arpa/inet.h>
+
+#include "tlse.h"
+
+#ifndef htonll
+#define htonll(x) ((1==htonl(1)) ? (x) : ((uint64_t)htonl((x) & 0xFFFFFFFF) << 32) | htonl((x) >> 32))
+#endif
+
+#ifndef ntohll
+#define ntohll(x) ((1==ntohl(1)) ? (x) : ((uint64_t)ntohl((x) & 0xFFFFFFFF) << 32) | ntohl((x) >> 32))
+#endif
+
+static int crypto_encrypt(struct TLSContext *context, unsigned char *buf,
+               unsigned char *ct, unsigned int len) {
+       if (context->crypto.created == 1) {
+               return cbc_encrypt(buf, ct, len,
+                                  &context->crypto.ctx_local.aes_local);
+       }
+
+       memset(ct, 0, len);
+       return TLS_GENERIC_ERROR;
+}
+
+static int packet_encrypt(struct TLSPacket *packet) {
+       int header_size = 5;
+       int block_size = TLS_AES_BLOCK_SIZE;
+       int mac_size = 0;
+       unsigned int length = 0;
+       unsigned char padding = 0;
+       //unsigned int pt_length = packet->len - header_size;
+       struct TLSContext *context = packet->context;
+
+       mac_size = tls_mac_length(packet->context);
+       length = packet->len - header_size + TLS_AES_IV_LENGTH + mac_size;
+
+       padding = block_size - length % block_size;
+       length += padding;
+       unsigned char *buf = malloc(length);
+       if (buf) {
+               unsigned char *ct = malloc(length + header_size);
+               if (ct) {
+                       unsigned int buf_pos = 0;
+                       memcpy(ct, packet->buf, header_size - 2);
+                       *(unsigned short *)&ct[header_size - 2] = htons(length);
+                       tls_random(buf, TLS_AES_IV_LENGTH);
+                       buf_pos += TLS_AES_IV_LENGTH;
+                       /* copy payload */
+                       memcpy(buf + buf_pos, packet-> buf + header_size, packet->len - header_size);
+                       buf_pos += packet->len - header_size;
+
+                       tls_hmac_message(1, context,
+                                       packet->buf,
+                                       packet->len, NULL, 0,
+                                       buf + buf_pos,
+                                       mac_size);
+                       buf_pos += mac_size;
+
+                       memset(buf + buf_pos, padding - 1, padding);
+                       buf_pos += padding;
+
+                       crypto_encrypt(context, buf, ct + header_size, length);
+                       free(packet->buf);
+                       packet->buf = ct;
+                       packet->len = length + header_size;
+                       packet->size = packet->len;
+               } else {
+                       /* invalidate packet */
+                       memset (packet->buf, 0, packet-> len);
+               }
+               free(buf);
+       } else {
+               /* invalidate packet */
+               memset(packet->buf, 0, packet->len);
+       }
+
+       return 1;
+}
+
+static void put16(unsigned char *at, uint16_t val) {
+       at[0] = val >> 8;
+       at[1] = val & 0xff;
+}
+
+void tls_packet_update(struct TLSPacket *packet) {
+       struct TLSContext *context;
+       unsigned int header_size = 5;
+       int footer_size = 0;
+       uint16_t real_packet_len;
+       uint64_t lsn;
+       int mac_size = 0;
+       unsigned int length = 0;
+       int context_is_v13 = 0;
+       struct tls_buffer ciphertext;
+
+       if (!packet || packet->broken) {
+               return;
+       }
+
+       if (packet->context && packet->context->tlsver == TLS_VERSION13
+                       && packet->context->cipher_spec_set
+                       && packet->context->crypto.created) {
+               /* type */
+               tls_packet_uint8(packet, packet->buf[0]);
+               /* no padding
+                * tls_packet_uint8(packet, 0);
+                */
+               footer_size = 1;
+       }
+
+       real_packet_len = packet->len - header_size;
+
+       put16(packet->buf + 3, real_packet_len);
+
+       if (!packet->context) {
+               return;
+       }
+
+       context = packet->context;
+       lsn = context->local_sequence_number;
+
+       if (context->tlsver == TLS_VERSION13) {
+               context_is_v13 = 1;
+       }
+
+       if (packet->buf[0] == TLS_CHANGE_CIPHER) {
+               context->local_sequence_number++;
+               return;
+       }
+
+       /* If this is a handshake message, update the handshake hash */
+       if (packet->buf[0] == TLS_HANDSHAKE && packet->len > header_size) {
+               unsigned char handshake_type = packet->buf[header_size];
+               if (handshake_type != 0x00 && handshake_type != 0x03) {
+                       tls_update_hash(context, packet->buf + header_size,
+                                       real_packet_len -
+                                       footer_size);
+               }
+       }
+
+       if (!context->cipher_spec_set || !context->crypto.created) {
+               context->local_sequence_number++;
+               return;
+       }
+
+       unsigned int pt_length = real_packet_len;
+
+       if (context->crypto.created == 1) {
+       } else if (context->crypto.created == 3) {
+               mac_size = POLY1305_TAGLEN;
+               length = real_packet_len + mac_size;
+       } else {
+               mac_size = TLS_GCM_TAG_LEN;
+               length = real_packet_len + 8 + mac_size;
+       }
+
+       if (context->crypto.created == 1) {
+               packet_encrypt(packet); 
+               context->local_sequence_number++;
+               return;
+       }
+
+       if (context->crypto.created < 1) {
+               /* invalidate packet */
+               memset(packet->buf, 0, packet->len);
+               context->local_sequence_number++;
+               return;
+       }
+
+       /* + 1 = type */
+       int ct_size = length + header_size + 12 + TLS_MAX_TAG_LEN + 1;
+       tls_buffer_init(&ciphertext, ct_size);
+
+       if (ciphertext.error) {
+               /* invalidate packet */
+               memset(packet->buf, 0, packet->len);
+               context->local_sequence_number++;
+               return;
+       }
+
+       /* AEAD */
+       /* sequence number (8 bytes) */
+       /* content type (1 byte) */
+       /* version (2 bytes) */
+       /* length (2 bytes) */
+       unsigned char aad[13];
+       int aad_size = sizeof(aad);
+       unsigned char *sequence = aad;
+       if (context_is_v13) {
+               aad[0] = TLS_APPLICATION_DATA;
+               aad[1] = packet->buf[1];
+               aad[2] = packet->buf[2];
+               if (packet->context->crypto.created == 3) {
+                       put16(aad+3, real_packet_len + POLY1305_TAGLEN);
+               } else {
+                       put16(aad+3, real_packet_len + TLS_GCM_TAG_LEN);
+               }
+               aad_size = 5;
+               sequence = aad + 5;
+
+               *((uint64_t *) (aad+5)) = htonll(lsn);
+
+       } else {
+               *((uint64_t *) aad) = htonll(lsn);
+               aad[8] = packet->buf[0];
+               aad[9] = packet->buf[1];
+               aad[10] = packet->buf[2];
+               put16(aad+11, packet->len - header_size);
+       }
+
+       ciphertext.len = header_size;
+
+       if (context->crypto.created == 3) {
+               int size;
+               unsigned int counter = 1;
+               unsigned char poly1305_key[POLY1305_KEYLEN];
+               chacha_ivupdate(&context->crypto.ctx_local.chacha_local,
+                               context->crypto.ctx_local_mac.local_aead_iv,
+                               sequence, (uint8_t *) &counter);
+               chacha20_poly1305_key(&context->crypto.ctx_local.chacha_local,
+                               poly1305_key);
+               size =
+                       chacha20_poly1305_aead(&context->crypto.ctx_local.chacha_local,
+                                       packet->buf + header_size, pt_length,
+                                       aad, aad_size, poly1305_key,
+                                       ciphertext.buffer + ciphertext.len);
+               ciphertext.len += size;
+       } else {
+               unsigned char iv [TLS_13_AES_GCM_IV_LENGTH];
+               if (context_is_v13) {
+                       memcpy(iv, context->crypto.ctx_local_mac.local_iv,
+                                       TLS_13_AES_GCM_IV_LENGTH);
+                       int i;
+                       int offset = TLS_13_AES_GCM_IV_LENGTH - 8;
+                       for (i = 0; i < 8; i++)
+                               iv[offset + i] = context->crypto.ctx_local_mac.local_iv[offset + i] ^ sequence[i];
+               } else {
+                       memcpy(iv, context->crypto.ctx_local_mac.local_aead_iv,
+                                       TLS_AES_GCM_IV_LENGTH);
+                       tls_random(iv + TLS_AES_GCM_IV_LENGTH, 8);
+                       tls_buffer_append(&ciphertext,
+                                       iv+TLS_AES_GCM_IV_LENGTH, 8);
+               }
+
+               gcm_state *localgcm;
+               localgcm = &context->crypto.ctx_local.aes_gcm_local;
+
+               gcm_reset(localgcm);
+               gcm_add_iv(localgcm, iv, 12);
+               gcm_add_aad(localgcm, aad, aad_size);
+               gcm_process(localgcm, packet->buf + header_size, pt_length,
+                               ciphertext.buffer+ciphertext.len, GCM_ENCRYPT);
+               ciphertext.len += pt_length;
+
+               unsigned long taglen = TLS_GCM_TAG_LEN;
+               gcm_done(localgcm, ciphertext.buffer+ciphertext.len, &taglen);
+               ciphertext.len += taglen;
+       }
+
+       if (context_is_v13) {
+               ciphertext.buffer[0] = TLS_APPLICATION_DATA;
+               tls_buffer_write16(&ciphertext, TLS_V12, 1);
+       } else {
+               memcpy(ciphertext.buffer, packet->buf, header_size - 2);
+       }
+
+       tls_buffer_write16(&ciphertext, ciphertext.len - header_size, header_size - 2);
+
+       free(packet->buf);
+       packet->buf = ciphertext.buffer;
+       packet->len = ciphertext.len;
+       packet->size = ciphertext.size;
+
+       context->local_sequence_number++;
+}
diff --git a/crypto/parse_client_hello.c b/crypto/parse_client_hello.c
new file mode 100644 (file)
index 0000000..ab16506
--- /dev/null
@@ -0,0 +1,507 @@
+#define _POSIX_C_SOURCE 200809L
+
+#include <fcntl.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+
+#include "tlse.h"
+#include "chacha.h"
+#include "buffer.h"
+
+static int tls_cipher_is_fs(struct TLSContext *context, unsigned short cipher) {
+       if (!context) {
+               return 0;
+       }
+
+       if (context->tlsver == TLS_VERSION13) {
+               switch (cipher) {
+                       case TLS_AES_128_GCM_SHA256:
+                       case TLS_AES_256_GCM_SHA384:
+                       case TLS_CHACHA20_POLY1305_SHA256:
+                               return 1;
+               }
+               return 0;
+       }
+
+       switch (cipher) {
+               case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA:
+               case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA:
+               case TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256:
+                       if (context && context->certificates
+                                       && context->certificates_count
+                                       && context->ec_private_key) {
+                               return 1;
+                       }
+                       return 0;
+               case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256:
+               case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384:
+               case TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:
+               case TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:
+                       if (context->version == TLS_V12
+                                       || context->version == DTLS_V12) {
+                               if (context && context->certificates
+                                               && context->certificates_count
+                                               && context->ec_private_key) {
+                                       return 1;
+                               }
+                       }
+               return 0;
+       case TLS_DHE_RSA_WITH_AES_128_CBC_SHA:
+       case TLS_DHE_RSA_WITH_AES_256_CBC_SHA:
+       case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA:
+       case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA:
+               return 1;
+       case TLS_DHE_RSA_WITH_AES_128_CBC_SHA256:
+       case TLS_DHE_RSA_WITH_AES_256_CBC_SHA256:
+       case TLS_DHE_RSA_WITH_AES_128_GCM_SHA256:
+       case TLS_DHE_RSA_WITH_AES_256_GCM_SHA384:
+       case TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256:
+       case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256:
+       case TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384:
+       case TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
+       case TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
+               if (context->tlsver == TLS_VERSION12) {
+                       return 1;
+               }
+               break;
+       }
+       return 0;
+}
+
+static uint16_t get16(const unsigned char *buf) {
+       uint16_t res;
+
+       res = ((*buf) << 8) + (*(buf+1));
+       return res;
+}
+
+int tls_choose_cipher(struct TLSContext *context, const unsigned char *buf,
+                     int buf_len, int *scsv_set) {
+       int i;
+       if (scsv_set) {
+               *scsv_set = 0;
+       }
+       if (!context) {
+               return 0;
+       }
+       int selected_cipher = TLS_NO_COMMON_CIPHER;
+
+       if (selected_cipher == TLS_NO_COMMON_CIPHER) {
+               for (i = 0; i < buf_len; i += 2) {
+                       uint16_t cipher = get16(&buf[i]);
+                       if (tls_cipher_is_fs(context, cipher)) {
+                               selected_cipher = cipher;
+                               break;
+                       }
+               }
+       }
+
+       for (i = 0; i < buf_len; i += 2) {
+               uint16_t cipher = get16(&buf[i]);
+               if (cipher == TLS_FALLBACK_SCSV) {
+                       if (scsv_set) {
+                               *scsv_set = 1;
+                       }
+                       if (selected_cipher != TLS_NO_COMMON_CIPHER) {
+                               break;
+                       }
+               }
+       }
+       return selected_cipher;
+}
+
+int tls_parse_client_hello(struct TLSContext *context,
+               const unsigned char *buf, int buf_len,
+               unsigned int *write_packets) {
+       *write_packets = 0;
+       if (context->connection_status != 0 && context->connection_status != 4) {
+               DEBUG_PRINT("UNEXPECTED HELLO MESSAGE\n");
+               return TLS_UNEXPECTED_MESSAGE;
+       }
+
+       int res = 0;
+       int downgraded = 0;
+
+       int hello_min_size = TLS_CLIENT_HELLO_MINSIZE;
+
+       if (buf_len < hello_min_size) {
+               return TLS_NEED_MORE_DATA;
+       }
+
+       /* big endian */
+       int bytes_to_follow = buf[0] * 0x10000 + buf[1] * 0x100 + buf[2];
+       res += 3;
+       if (buf_len - res < bytes_to_follow) {
+               return TLS_NEED_MORE_DATA;
+       }
+
+       if (buf_len - res < 2) {
+               return TLS_NEED_MORE_DATA;
+       }
+
+       unsigned short version = get16(&buf[res]);
+
+       res += 2;
+       if (!tls_supported_version(version)) {
+               return TLS_NOT_SAFE;
+       }
+       DEBUG_PRINT("VERSION REQUIRED BY REMOTE %x, VERSION NOW %x\n",
+                       (int) version, (int) context->version);
+       memcpy(context->remote_random, &buf[res], TLS_CLIENT_RANDOM_SIZE);
+       res += TLS_CLIENT_RANDOM_SIZE;
+
+       unsigned char session_len = buf[res++];
+       if (buf_len - res < session_len) return TLS_NEED_MORE_DATA;
+
+       if (session_len && session_len <= TLS_MAX_SESSION_ID) {
+               memcpy(context->session, &buf[res], session_len);
+               context->session_size = session_len;
+               DEBUG_DUMP_HEX_LABEL("REMOTE SESSION ID: ",
+                               context->session,
+                               context->session_size);
+       } else {
+               context->session_size = 0;
+       }
+       res += session_len;
+
+       const unsigned char *cipher_buffer = NULL;
+       unsigned short cipher_len = 0;
+       int scsv_set = 0;
+       if (context->is_server) {
+               if (buf_len - res < 2) {
+                       return TLS_NEED_MORE_DATA;
+               }
+
+               cipher_len = get16(&buf[res]);
+               res += 2;
+               if (buf_len - res < cipher_len) return TLS_NEED_MORE_DATA;
+               /* faster than cipher_len % 2 */
+               /* TODO unlikely, let the compiler worry about it */
+               if (cipher_len & 1) {
+                       return TLS_BROKEN_PACKET;
+               }
+
+               cipher_buffer = &buf[res];
+               res += cipher_len;
+
+               if (buf_len - res < 1) {
+                       return TLS_NEED_MORE_DATA;
+               }
+
+               unsigned char compression_list_size = buf[res++];
+               if (buf_len - res < compression_list_size) {
+                       return TLS_NEED_MORE_DATA;
+               }
+               /* no compression support */
+               res += compression_list_size;
+       } else {
+               /* client */
+               if (buf_len - res < 2) {
+                       return TLS_NEED_MORE_DATA;
+               }
+
+               unsigned short cipher = get16(&buf[res]);
+               res += 2;
+               context->cipher = cipher;
+               if (!tls_cipher_supported(context, cipher)) {
+                       context->cipher = 0;
+                       DEBUG_PRINT("NO CIPHER SUPPORTED\n");
+                       return TLS_NO_COMMON_CIPHER;
+               }
+               DEBUG_PRINT("CIPHER: %s\n", tls_cipher_name(context));
+               if (buf_len - res < 1) return TLS_NEED_MORE_DATA;
+               unsigned char compression = buf[res++];
+               if (compression != 0) {
+                       DEBUG_PRINT("COMPRESSION NOT SUPPORTED\n");
+                       return TLS_COMPRESSION_NOT_SUPPORTED;
+               }
+       }
+
+       if (res > 0) {
+               if (context->is_server) {
+                       *write_packets = 2;
+               }
+               if (context->connection_status != 4) {
+                       context->connection_status = 1;
+               }
+       }
+
+
+       if (res > 2) {
+               res += 2;
+       }
+       const unsigned char *key_share = NULL;
+       unsigned short key_size = 0;
+       while (buf_len - res >= 4) {
+               /* have extensions */
+               unsigned short extension_type = get16(&buf[res]);
+               res += 2;
+               unsigned short extension_len = get16(&buf[res]);
+               res += 2;
+               DEBUG_PRINT("Extension: 0x0%x (%i), len: %i\n",
+                           (int) extension_type, (int) extension_type,
+                           (int) extension_len);
+               if (extension_len) {
+                       /* SNI extension */
+                       if (buf_len - res < extension_len) {
+                               return TLS_NEED_MORE_DATA;
+                       }
+                       if (extension_type == 0x00) {
+                               /* unsigned char sni_type = buf[res + 2]; */
+                               uint16_t sni_host_len = get16(&buf[res+3]);
+                               if (buf_len - res - 5 < sni_host_len) {
+                                       return TLS_NEED_MORE_DATA;
+                               }
+
+                               if (sni_host_len) {
+                                       free(context->sni);
+                                       context->sni = malloc(sni_host_len + 1);
+                                       if (context->sni) {
+                                               memcpy(context->sni,
+                                                               &buf[res + 5],
+                                                               sni_host_len);
+                                               context->sni[sni_host_len] = 0;
+                                               DEBUG_PRINT("SNI HOST INDICATOR: [%s]\n", context->sni);
+                                       }
+                               }
+                       } else if (extension_type == 0x0A) {
+                               /* supported groups */
+                               if (buf_len - res > 2) {
+                                       uint16_t group_len = get16(&buf[res]);
+                                       if (buf_len - res >= group_len + 2) {
+                                               DEBUG_DUMP_HEX_LABEL
+                                                   ("SUPPORTED GROUPS",
+                                                    &buf[res + 2],
+                                                    group_len);
+                                               int i;
+                                               int selected = 0;
+                                               for (i = 0; i < group_len;
+                                                    i += 2) {
+                                                       uint16_t iana_n = get16(&buf[res + 2 + i]);
+                                                       switch (iana_n) {
+                                                       case 23:
+                                                               context->
+                                                                   curve =
+                                                                   &secp256r1;
+                                                               selected =
+                                                                   1;
+                                                               break;
+                                                       case 24:
+                                                               context->
+                                                                   curve =
+                                                                   &secp384r1;
+                                                               selected =
+                                                                   1;
+                                                               break;
+#if 0
+                                                               /* needs different implementation */
+                                                               case 29:
+                                                               context->curve = &curve25519;
+                                                               selected = 1;
+                                                               break;
+#endif
+#if 0
+                                                               /* do not use it anymore */
+                                                               case 25:
+                                                               context->curve = &secp521r1;
+                                                               selected = 1;
+                                                               break;
+#endif
+                                                       }
+                                                       if (selected) {
+                                                               DEBUG_PRINT
+                                                                   ("SELECTED CURVE %s\n",
+                                                                    context->
+                                                                    curve->
+                                                                    name);
+                                                               break;
+                                                       }
+                                               }
+                                       }
+                               }
+                       } else
+                               if (extension_type == 0x10 && context->alpn &&
+                                               context->alpn_count) {
+                               if (buf_len - res > 2) {
+                                       uint16_t alpn_len = get16(&buf[res]);
+                                       if (alpn_len && alpn_len <=
+                                                       extension_len - 2) {
+                                               unsigned char *alpn =
+                                                   (unsigned char *)
+                                                   &buf[res + 2];
+                                               int alpn_pos = 0;
+                                               while (alpn_pos < alpn_len) {
+                                                       unsigned char
+                                                        alpn_size =
+                                                           alpn
+                                                           [alpn_pos++];
+                                                       if (alpn_size +
+                                                           alpn_pos >=
+                                                           extension_len)
+                                                               break;
+                                                       if ((alpn_size)
+                                                           &&
+                                                           (tls_alpn_contains
+                                                            (context,
+                                                             (char *)
+                                                             &alpn
+                                                             [alpn_pos],
+                                                             alpn_size)))
+                                                       {
+                                                               free
+                                                                   (context->
+                                                                    negotiated_alpn);
+                                                               context->
+                                                                   negotiated_alpn
+                                                                   =
+                                                                   malloc
+                                                                   (alpn_size
+                                                                    + 1);
+                                                               if (context->negotiated_alpn) {
+                                                                       memcpy
+                                                                           (context->
+                                                                            negotiated_alpn,
+                                                                            &alpn
+                                                                            [alpn_pos],
+                                                                            alpn_size);
+                                                                       context->
+                                                                           negotiated_alpn
+                                                                           [alpn_size]
+                                                                           =
+                                                                           0;
+                                                                       DEBUG_PRINT
+                                                                           ("NEGOTIATED ALPN: %s\n",
+                                                                            context->
+                                                                            negotiated_alpn);
+                                                               }
+                                                               break;
+                                                       }
+                                                       alpn_pos +=
+                                                           alpn_size;
+                                                       /* ServerHello contains just one alpn */
+                                                       if (!context->
+                                                           is_server)
+                                                               break;
+                                               }
+                                       }
+                               }
+                       } else if (extension_type == 0x0D) {
+                               /* supported signatures */
+                               DEBUG_DUMP_HEX_LABEL
+                                   ("SUPPORTED SIGNATURES", &buf[res],
+                                    extension_len);
+                       } else if (extension_type == 0x0B) {
+                               /* supported point formats */
+                               DEBUG_DUMP_HEX_LABEL
+                                   ("SUPPORTED POINT FORMATS", &buf[res],
+                                    extension_len);
+                       }
+                       else if (extension_type == 0x2B) {
+                               /* supported versions */
+                               if ((buf[res] == extension_len - 1)
+                                   && (extension_len > 4)) {
+                                       DEBUG_DUMP_HEX_LABEL
+                                           ("SUPPORTED VERSIONS",
+                                            &buf[res], extension_len);
+                                       /* tls 1.3 draft version 28 */
+                                       int i;
+                                       int limit = (int) buf[res];
+                                       if (limit == extension_len - 1) {
+                                               limit--;
+                                               for (i = 1; i < limit;
+                                                    i += 2) {
+                                                       if ((get16(&buf[res + i]) == 0x7F1C)
+                                                           ||
+                                                           (get16(&buf[res + i]) == TLS_V13)) {
+                                                               context->
+                                                                   version
+                                                                   =
+                                                                   TLS_V13;
+                                                               context->
+                                                                   tls13_version
+                                                                   =
+                                                                   get16(&buf[res + i]);
+                                                               DEBUG_PRINT
+                                                                   ("TLS 1.3 SUPPORTED\n");
+                                                               break;
+                                                       }
+                                               }
+                                       }
+                               }
+                       } else if (extension_type == 0x2A) {
+                               /* early data */
+                               DEBUG_DUMP_HEX_LABEL
+                                   ("EXTENSION, EARLY DATA", &buf[res],
+                                    extension_len);
+                       } else if (extension_type == 0x29) {
+                               /* pre shared key */
+                               DEBUG_DUMP_HEX_LABEL
+                                   ("EXTENSION, PRE SHARED KEY",
+                                    &buf[res], extension_len);
+                       } else if (extension_type == 0x33) {
+                               /* key share */
+                               key_size = get16(&buf[res]);
+                               if (key_size > extension_len - 2) {
+                                       DEBUG_PRINT("BROKEN KEY SHARE\n");
+                                       return TLS_BROKEN_PACKET;
+                               }
+                               DEBUG_DUMP_HEX_LABEL
+                                   ("EXTENSION, KEY SHARE", &buf[res],
+                                    extension_len);
+                               key_share = &buf[res + 2];
+                       } else if (extension_type == 0x0D) {
+                               /* signature algorithms */
+                               DEBUG_DUMP_HEX_LABEL
+                                   ("EXTENSION, SIGNATURE ALGORITHMS",
+                                    &buf[res], extension_len);
+                       } else if (extension_type == 0x2D) {
+                               /* psk key exchange modes */
+                               DEBUG_DUMP_HEX_LABEL
+                                   ("EXTENSION, PSK KEY EXCHANGE MODES",
+                                    &buf[res], extension_len);
+                       }
+                       res += extension_len;
+               }
+       }
+
+       if (buf_len != res) {
+               return TLS_NEED_MORE_DATA;
+       }
+
+       if (context->is_server && cipher_buffer && cipher_len) {
+               int cipher =
+                   tls_choose_cipher(context, cipher_buffer, cipher_len,
+                                     &scsv_set);
+               if (cipher < 0) {
+                       DEBUG_PRINT("NO COMMON CIPHERS\n");
+                       return cipher;
+               }
+               if (downgraded && scsv_set) {
+                       DEBUG_PRINT("NO DOWNGRADE (SCSV SET)\n");
+                       tls_alert(context, 1, inappropriate_fallback);
+                       context->critical_error = 1;
+                       return TLS_NOT_SAFE;
+               }
+               context->cipher = cipher;
+       }
+       if (key_share && key_size && context->tlsver == TLS_VERSION13) {
+               int key_share_err =
+                   tls_parse_key_share(context, key_share, key_size);
+               if (key_share_err) {
+                       /* request hello retry */
+                       if (context->connection_status != 4) {
+                               *write_packets = 5;
+                               context->hs_messages[1] = 0;
+                               context->connection_status = 4;
+                               return res;
+                       } else
+                               return key_share_err;
+               }
+               /* we have key share */
+               context->connection_status = 3;
+       }
+       return res;
+}
diff --git a/crypto/parse_message.c b/crypto/parse_message.c
new file mode 100644 (file)
index 0000000..e4e7b15
--- /dev/null
@@ -0,0 +1,562 @@
+#define _POSIX_C_SOURCE 200809L
+
+#include <fcntl.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <time.h>
+
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <unistd.h>
+
+#include <errno.h>
+
+#include <tomcrypt.h>
+
+#include "buffer.h"
+#include "tlse.h"
+
+#ifndef htonll
+#define htonll(x) ((1==htonl(1)) ? (x) : ((uint64_t)htonl((x) & 0xFFFFFFFF) << 32) | htonl((x) >> 32))
+#endif
+
+#ifndef ntohll
+#define ntohll(x) ((1==ntohl(1)) ? (x) : ((uint64_t)ntohl((x) & 0xFFFFFFFF) << 32) | ntohl((x) >> 32))
+#endif
+
+static uint16_t get16(const unsigned char *buf) {
+       uint16_t res;
+
+       res = ((*buf) << 8) + (*(buf+1));
+       return res;
+}
+
+static int tls_microsleep(unsigned int microseconds) {
+       struct timespec ts;
+       struct timespec rem;
+       int rv;
+
+       ts.tv_sec = (time_t) (microseconds / 1000000L);
+       ts.tv_nsec = (long) (((long) microseconds % 1000000L) * 1000L);
+
+       errno = 0;
+       while ((rv = nanosleep(&ts, &rem)) == -1) {
+               if (errno != EINTR) {
+                       return rv;
+               }
+               ts = rem;
+       }
+       return rv;
+}
+
+/* TODO this is biased unless limit is a power of 2 */
+static unsigned int random_int(int limit) {
+       unsigned int res = 0;
+       tls_random((unsigned char *) &res, sizeof(int));
+       if (limit) {
+               res %= limit;
+       }
+       return res;
+}
+
+static int random_sleep(long max) {
+       return tls_microsleep(random_int(max));
+}
+
+static void U32TO8(unsigned char *p, unsigned long v) {
+       p[0] = (v) & 0xff;
+       p[1] = (v >> 8) & 0xff;
+       p[2] = (v >> 16) & 0xff;
+       p[3] = (v >> 24) & 0xff;
+}
+
+static int decrypt_aes_gcm(struct TLSContext *context, uint16_t length, int
+               header_size, const unsigned char *ptr, const unsigned char
+               *buf, int buf_len, struct tls_buffer *pt_buffer) {
+       int delta = 8;
+       int pt_length;
+       unsigned char iv[TLS_13_AES_GCM_IV_LENGTH];
+       unsigned char aad[16];
+       int aad_size = sizeof(aad);
+       unsigned char *sequence = aad;
+
+       gcm_state *remote_gcm;
+       remote_gcm = &context->crypto.ctx_remote.aes_gcm_remote;
+
+       gcm_reset(remote_gcm);
+
+       /* set up the aad */
+       if (context->tlsver == TLS_VERSION13) {
+               aad[0] = TLS_APPLICATION_DATA;
+               aad[1] = 0x03;
+               aad[2] = 0x03;
+               *((unsigned short *) &aad[3]) =
+                       htons(buf_len - header_size);
+               aad_size = 5;
+               sequence = aad + 5;
+               *((uint64_t *) sequence) =
+                       htonll(context->remote_sequence_number);
+               memcpy(iv, context->crypto.ctx_remote_mac.remote_iv,
+                               TLS_13_AES_GCM_IV_LENGTH);
+               int i;
+               int offset = TLS_13_AES_GCM_IV_LENGTH - 8;
+               for (i = 0; i < 8; i++) {
+                       iv[offset + i] =
+                               context->crypto.ctx_remote_mac.remote_iv[offset +
+                               i] ^ sequence[i];
+               }
+               pt_length = buf_len - header_size - TLS_GCM_TAG_LEN;
+               delta = 0;
+       } else {
+               aad_size = 13;
+               pt_length = length - 8 - TLS_GCM_TAG_LEN;
+
+               /* build aad and iv */
+               *((uint64_t *) aad) = htonll(context->remote_sequence_number);
+               aad[8] = buf[0];
+               aad[9] = buf[1];
+               aad[10] = buf[2];
+
+               memcpy(iv, context->crypto.ctx_remote_mac.remote_aead_iv, 4);
+               memcpy(iv + 4, buf + header_size, 8);
+               *((unsigned short *) &aad[11]) = htons(pt_length);
+       }
+
+       if (pt_length < 0) {
+               DEBUG_PRINT("Invalid packet length");
+               return TLS_BROKEN_PACKET;
+       }
+       DEBUG_DUMP_HEX_LABEL("aad", aad, aad_size);
+       DEBUG_DUMP_HEX_LABEL("aad iv", iv, 12);
+
+       /* I think we do all of this even if they fail to avoid timing
+        * attacks
+        */
+       int res0 = gcm_add_iv(&context->crypto.ctx_remote.aes_gcm_remote, iv, 12);
+       int res1 = gcm_add_aad(&context->crypto.ctx_remote.aes_gcm_remote, aad, aad_size);
+
+       DEBUG_PRINT("PT SIZE: %i\n", pt_length);
+
+       /* TODO we might want to expand this buffer before we call this
+        * function */
+       tls_buffer_expand(pt_buffer, pt_length);
+
+       int res2 = gcm_process(&context->crypto.ctx_remote.
+                       aes_gcm_remote, pt_buffer->buffer,
+                       pt_length,
+                       (char *)buf + header_size + delta,
+                       GCM_DECRYPT);
+       pt_buffer->len = pt_length;
+
+       unsigned char tag[32];
+       unsigned long taglen = 32;
+       int res3 = gcm_done(&context->crypto.ctx_remote.aes_gcm_remote,
+                       tag, &taglen);
+
+       if (res0 || res1 || res2 || res3 || taglen != TLS_GCM_TAG_LEN) {
+               DEBUG_PRINT
+                       ("ERROR: gcm_add_iv: %i, gcm_add_aad: %i, gcm_process: %i, gcm_done: %i\n",
+                        res0, res1, res2, res3);
+               return TLS_BROKEN_PACKET;
+       }
+
+       DEBUG_DUMP_HEX_LABEL("decrypted1", pt_buffer->buffer, pt_length);
+       DEBUG_DUMP_HEX_LABEL("tag", tag, taglen);
+
+       /* check tag */
+       if (memcmp(buf + header_size + delta + pt_length, tag, taglen)) {
+               DEBUG_PRINT("INTEGRITY CHECK FAILED (msg length %i)\n",
+                               pt_length);
+               DEBUG_DUMP_HEX_LABEL("TAG RECEIVED",
+                               buf + header_size + delta + pt_length,
+                               taglen);
+               DEBUG_DUMP_HEX_LABEL("TAG COMPUTED", tag, taglen);
+               tls_alert(context, 1, bad_record_mac);
+               return TLS_INTEGRITY_FAILED;
+       }
+       ptr = pt_buffer->buffer;
+       length = pt_length;
+
+       return 0;
+}
+
+static int decrypt_chacha_poly1305(struct TLSContext *context, uint16_t length,
+               int header_size, const unsigned char *ptr, const unsigned char
+               *buf, int buf_len, struct tls_buffer *pt_buffer) {
+
+       unsigned char aad[16];
+       int aad_size = sizeof(aad);
+       unsigned char *sequence = aad;
+
+       int pt_length = length - POLY1305_TAGLEN;
+       unsigned int counter = 1;
+       unsigned char poly1305_key[POLY1305_KEYLEN];
+       unsigned char trail[16];
+       unsigned char mac_tag[POLY1305_TAGLEN];
+
+       aad_size = 16;
+       if (pt_length < 0) {
+               DEBUG_PRINT("Invalid packet length");
+               return TLS_BROKEN_PACKET;
+       }
+
+       /* set up add */
+       if (context->tlsver == TLS_VERSION13) {
+               aad[0] = TLS_APPLICATION_DATA;
+               aad[1] = 0x03;
+               aad[2] = 0x03;
+               *((unsigned short *) &aad[3]) =
+                       htons(buf_len - header_size);
+               aad_size = 5;
+               sequence = aad + 5;
+               *((uint64_t *) sequence) =
+                       htonll(context->remote_sequence_number);
+       } else {
+               *((uint64_t *) aad) =
+                       htonll(context->remote_sequence_number);
+               aad[8] = buf[0];
+               aad[9] = buf[1];
+               aad[10] = buf[2];
+               *((unsigned short *) &aad[11]) = htons(pt_length);
+               aad[13] = 0;
+               aad[14] = 0;
+               aad[15] = 0;
+       }
+
+       tls_buffer_expand(pt_buffer, pt_length);
+       chacha_ivupdate(&context->crypto.ctx_remote.chacha_remote,
+                       context->crypto.ctx_remote_mac.remote_aead_iv,
+                       sequence, (unsigned char *) &counter);
+
+       chacha_encrypt_bytes(&context->crypto.ctx_remote.chacha_remote,
+                       buf + header_size, pt_buffer->buffer, pt_length);
+
+       DEBUG_DUMP_HEX_LABEL("decrypted2", pt_buffer->buffer, pt_length);
+       ptr = pt_buffer->buffer;
+       length = pt_length;
+
+       chacha20_poly1305_key(&context->crypto.ctx_remote.chacha_remote,
+                       poly1305_key);
+
+       struct poly1305_context ctx;
+       tls_poly1305_init(&ctx, poly1305_key);
+       tls_poly1305_update(&ctx, aad, aad_size);
+
+       static unsigned char zeropad[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0,
+               0, 0, 0, 0, 0, 0 };
+
+       int rem = aad_size % 16;
+       if (rem) {
+               tls_poly1305_update(&ctx, zeropad, 16 - rem);
+       }
+       tls_poly1305_update(&ctx, buf + header_size, pt_length);
+
+       rem = pt_length % 16;
+       if (rem) {
+               tls_poly1305_update(&ctx, zeropad, 16 - rem);
+       }
+
+       U32TO8(&trail[0], aad_size == 5 ? 5 : 13);
+       *(int *) &trail[4] = 0;
+       U32TO8(&trail[8], pt_length);
+       *(int *) &trail[12] = 0;
+
+       tls_poly1305_update(&ctx, trail, 16);
+       tls_poly1305_finish(&ctx, mac_tag);
+       if (memcmp(mac_tag, buf + header_size + pt_length,
+                               POLY1305_TAGLEN)) {
+               DEBUG_PRINT
+                       ("INTEGRITY CHECK FAILED (msg length %i)\n",
+                        length);
+               DEBUG_DUMP_HEX_LABEL("POLY1305 TAG RECEIVED",
+                               buf + header_size + pt_length,
+                               POLY1305_TAGLEN);
+               DEBUG_DUMP_HEX_LABEL("POLY1305 TAG COMPUTED",
+                               mac_tag, POLY1305_TAGLEN);
+
+               tls_alert(context, 1, bad_record_mac);
+               return TLS_INTEGRITY_FAILED;
+       }
+
+       pt_buffer->len = pt_length;
+
+       return 0;
+}
+
+static int decrypt_other(struct TLSContext *context, uint16_t length, int
+               header_size, const unsigned char *ptr, const unsigned char
+               *buf, struct tls_buffer *pt_buffer) {
+       int err;
+
+       err = cbc_decrypt(buf+header_size, pt_buffer->buffer, length,
+                       &context->crypto.ctx_remote.aes_remote);
+       if (err) {
+               DEBUG_PRINT("Decryption error %i\n", (int) err);
+               return TLS_BROKEN_PACKET;
+       }
+       unsigned char padding_byte = pt_buffer->buffer[length - 1];
+       unsigned char padding = padding_byte + 1;
+
+       /* poodle check */
+       int padding_index = length - padding;
+       if (padding_index > 0) {
+               int i;
+               int limit = length - 1;
+               for (i = length - padding; i < limit; i++) {
+                       if (pt_buffer->buffer[i] != padding_byte) {
+                               DEBUG_PRINT
+                                       ("BROKEN PACKET (POODLE ?)\n");
+                               tls_alert(context, 1, decrypt_error);
+                               return TLS_BROKEN_PACKET;
+                       }
+               }
+       }
+
+       unsigned int decrypted_length = length;
+       if (padding < decrypted_length) {
+               decrypted_length -= padding;
+               pt_buffer->len -= padding;
+       }
+
+       DEBUG_DUMP_HEX_LABEL("decrypted3", pt_buffer->buffer, decrypted_length);
+       ptr = pt_buffer->buffer;
+
+       if (decrypted_length > TLS_AES_IV_LENGTH) {
+               decrypted_length -= TLS_AES_IV_LENGTH;
+               ptr += TLS_AES_IV_LENGTH;
+               tls_buffer_shift(pt_buffer, TLS_AES_IV_LENGTH);
+       }
+       length = decrypted_length;
+
+       unsigned int mac_size = tls_mac_length(context);
+       if (length < mac_size || !mac_size) {
+               DEBUG_PRINT("BROKEN PACKET\n");
+               tls_alert(context, 1, decrypt_error);
+               return TLS_BROKEN_PACKET;
+       }
+
+       length -= mac_size;
+       pt_buffer->len -= mac_size;
+
+       const unsigned char *message_hmac = &ptr[length];
+       unsigned char hmac_out[TLS_MAX_MAC_SIZE];
+       unsigned char temp_buf[5];
+       memcpy(temp_buf, buf, 3);
+       *(unsigned short *) &temp_buf[3] = htons(length);
+       unsigned int hmac_out_len = tls_hmac_message(0, context, temp_buf, 5,
+                       ptr, length, hmac_out, mac_size);
+       if (hmac_out_len != mac_size
+                       || memcmp(message_hmac, hmac_out, mac_size)) {
+               DEBUG_PRINT("INTEGRITY CHECK FAILED (msg length %i)\n",
+                               length);
+               DEBUG_DUMP_HEX_LABEL("HMAC RECEIVED", message_hmac, mac_size);
+               DEBUG_DUMP_HEX_LABEL("HMAC COMPUTED", hmac_out, hmac_out_len);
+
+               tls_alert(context, 1, bad_record_mac);
+
+               return TLS_INTEGRITY_FAILED;
+       }
+
+       return 0;
+}
+
+static int decrypt_payload(struct TLSContext *context,
+               uint16_t length,
+               int header_size,
+               const unsigned char *ptr,
+               const unsigned char *buf,
+               int buf_len,
+               struct tls_buffer *pt_buffer
+               ) {
+
+       if (context->crypto.created == 2) {
+               return decrypt_aes_gcm(context, length, header_size, ptr, buf,
+                               buf_len, pt_buffer);
+       } else if (context->crypto.created == 3) {
+               return decrypt_chacha_poly1305(context, length, header_size,
+                               ptr, buf, buf_len, pt_buffer);
+       } else if (context->crypto.created == 1) {
+               return decrypt_other(context, length, header_size, ptr, buf,
+                               pt_buffer);
+       } else {
+               tls_buffer_free(pt_buffer);
+               return TLS_BROKEN_PACKET;
+       }
+
+       return 0;
+}
+
+int tls_parse_message(struct TLSContext *context, unsigned char *buf,
+                     int buf_len) {
+       uint8_t type = *buf;
+       uint16_t version; /* a struct of two uint8 per the rfc, but
+                            we encode it as a uint16_t */
+       uint16_t length;
+       int buf_pos = 0;
+       int res = 5;
+       int payload_res = 0;
+       const unsigned char *ptr = 0;
+       /* TODO probably make this buffer part of the context,
+        * and just zero it out instead of malloc and free
+        */
+       struct tls_buffer pt;
+
+       int header_size = res;
+
+       if (buf_len < res) {
+               return TLS_NEED_MORE_DATA;
+       }
+
+       type = *buf;
+       buf_pos += 1;
+       version = get16(&buf[buf_pos]);
+       buf_pos += 2;
+
+       if (!tls_supported_version(version)) {
+               return TLS_NOT_SAFE;
+       }
+
+       length = get16(&buf[buf_pos]);
+       buf_pos += 2;
+
+       ptr = buf + buf_pos;
+
+       DEBUG_PRINT("Message type: %0x, length: %i\n", (int)type, (int)length);
+
+       /* this buffer can go out of scope */
+       tls_buffer_init(&pt, 0);
+
+       if (context->cipher_spec_set && type != TLS_CHANGE_CIPHER) {
+               /* Need to decrypt payload */
+               DEBUG_DUMP_HEX_LABEL("encrypted", &buf[header_size], length);
+
+               if (!context->crypto.created) {
+                       DEBUG_PRINT("Encryption context not created\n");
+                       random_sleep(TLS_MAX_ERROR_SLEEP_uS);
+                       return TLS_BROKEN_PACKET;
+               }
+
+               int rv = decrypt_payload(context, length, header_size, ptr,
+                               buf, buf_len, &pt);
+
+               if (rv != 0) {
+                       tls_buffer_free(&pt);
+                       random_sleep(TLS_MAX_ERROR_SLEEP_uS);
+                       return rv;
+               }
+
+               if (pt.error) {
+                       tls_buffer_free(&pt);
+                       random_sleep(TLS_MAX_ERROR_SLEEP_uS);
+                       return TLS_NO_MEMORY;
+               }
+
+               ptr = pt.buffer;
+               length = pt.len;
+       }
+
+       context->remote_sequence_number++;
+
+       if (context->tlsver == TLS_VERSION13) {
+               /*(context->connection_status == 2) && */
+               if (type == TLS_APPLICATION_DATA && context->crypto.created) {
+                       do {
+                               length--;
+                               type = ptr[length];
+                       } while (!type);
+               }
+       }
+
+       /* TODO for v1.3 encrypted handshake messages will show up
+        * as application data, so we need to re-compute the record
+        * type, that may be what the above is doing
+        */
+
+       switch (type) {
+               /* application data */
+               case TLS_APPLICATION_DATA:
+                       if (context->connection_status != TLS_CONNECTED) {
+                               DEBUG_PRINT
+                                       ("UNEXPECTED APPLICATION DATA MESSAGE\n");
+                               payload_res = TLS_UNEXPECTED_MESSAGE;
+                               tls_alert(context, 1, unexpected_message);
+                               break;
+                       }
+                       DEBUG_PRINT
+                               ("APPLICATION DATA MESSAGE (TLS VERSION: %x):\n",
+                                (int) context->version);
+                       DEBUG_DUMP(ptr, length);
+                       DEBUG_PRINT("\n");
+                       tls_buffer_append(&context->application_buffer, ptr, length);
+                       if (context->application_buffer.error) {
+                               payload_res =  TLS_NO_MEMORY;
+                       }
+                       break;
+                       /* handshake */
+               case TLS_HANDSHAKE:
+                       DEBUG_PRINT("HANDSHAKE MESSAGE\n");
+                       payload_res = tls_parse_payload(context, ptr, length);
+                       break;
+                       /* change cipher spec */
+               case TLS_CHANGE_CIPHER:
+                       if (context->connection_status != 2) {
+                               if (context->connection_status == 4) {
+                                       DEBUG_PRINT
+                                               ("IGNORING CHANGE CIPHER SPEC MESSAGE (HELLO RETRY REQUEST)\n");
+                                       break;
+                               }
+                               DEBUG_PRINT
+                                       ("UNEXPECTED CHANGE CIPHER SPEC MESSAGE (%i)\n",
+                                        context->connection_status);
+                               tls_alert(context, 1, unexpected_message);
+                               payload_res = TLS_UNEXPECTED_MESSAGE;
+                       } else {
+                               DEBUG_PRINT("CHANGE CIPHER SPEC MESSAGE\n");
+                               context->cipher_spec_set = 1;
+                               /* reset sequence numbers */
+                               context->remote_sequence_number = 0;
+                       }
+                       break;
+                       /* alert */
+               case TLS_ALERT:
+                       DEBUG_PRINT("ALERT MESSAGE\n");
+                       if (length >= 2) {
+                               DEBUG_PRINT("ALERT MESSAGE ...\n");
+                               DEBUG_DUMP_HEX(ptr, length);
+                               int level = ptr[0];
+                               int code = ptr[1];
+                               DEBUG_PRINT("level = %d, code = %d\n",
+                                               level, code);
+                               if (level == TLS_ALERT_CRITICAL) {
+                                       context->critical_error = 1;
+                                       res = TLS_ERROR_ALERT;
+                               }
+                               context->error_code = code;
+                       } else {
+                               DEBUG_PRINT("ALERT MESSAGE short\n");
+                       }
+
+                       break;
+               default:
+                       DEBUG_PRINT("UNKNOWN MESSAGE TYPE: %x\n", (int)type);
+                       payload_res =  TLS_NOT_UNDERSTOOD;
+                       break;
+       }
+
+       tls_buffer_free(&pt);
+
+       if (payload_res < 0) {
+               return payload_res;
+       }
+
+       if (res > 0) {
+               return header_size + length;
+       }
+
+       return res;
+}
diff --git a/crypto/pem.c b/crypto/pem.c
new file mode 100644 (file)
index 0000000..7d273f9
--- /dev/null
@@ -0,0 +1,368 @@
+#define _POSIX_C_SOURCE 200809L
+
+#include <stdio.h>
+#include <unistd.h>
+
+#include "tlse.h"
+
+struct pem_loc {
+       size_t start;
+       size_t len;
+       size_t end;
+};
+
+#if 0
+static const unsigned char *find_mem(const char *needle, size_t nlen,
+               const unsigned char *haystack, size_t hlen,
+               size_t *offset) {
+       size_t i;
+       const unsigned char *res = 0;
+
+       /* can't be found if it's longer */
+       if (nlen > hlen) {
+               return NULL;
+       }
+
+       /* empty string at beginning */
+       if (nlen == 0) {
+               *offset = 0;
+               return haystack;
+       }
+
+       for (i=0; i<hlen; i++) {
+               if (nlen + i > hlen) {
+                       /* can't match any more */
+                       break;
+               }
+               /* check for first byte */
+               if (needle[0] == haystack[i]) {
+                       if (memcmp(needle, haystack+i, nlen) == 0) {
+                               res = haystack+i;
+                               if (offset) {
+                                       *offset = i;
+                               }
+                               break;
+                       }
+               }
+       }
+       return res;
+}
+#endif
+
+#if 0
+/* fills in a struct pem_loc with offsets from in to the start
+ * of a pem, and one past the end, and the length of the pem data
+ */
+static const unsigned char *next_pem(const unsigned char *in, size_t len, struct pem_loc *pem) {
+       size_t i;
+       const unsigned char *next;
+
+       next = find_mem("BEGIN CERT", 10, in, len, &i);
+       if (!next) {
+               return NULL;
+       }
+
+       while (i<len && in[i] != '\n') {
+               i++;
+       }
+       if (i >= len) {
+               return NULL;
+       }
+       i++;
+       pem->start = i;
+
+       /* look for terminating line */
+       next = find_mem("END CERT", 8, in+pem->start, len, &i);
+       if (!next) {
+               return NULL;
+       }
+       i += pem->start;
+       pem->end = i;
+
+       /* find prev newline */
+       while (in[i] != '\n') {
+               i--;
+       }
+       pem->len = i - pem->start;
+       i += pem->start;
+
+       /* skip over the terminating line */
+       while (pem->end < len && in[pem->end] != '\n') {
+               pem->end++;
+       }
+#if 0
+       fprintf(stderr, "found cert:\n");
+       write(2, in+pem->start, pem->len);
+       write(2, in+pem->start+pem->len, pem->end-pem->start-pem->len+1);
+#endif
+
+       return in + pem->start;
+}
+#endif
+
+unsigned char *uudecode(const unsigned char *in, size_t len, size_t *outlen) {
+       size_t need = len/4 * 3 + 1;
+       unsigned char *out;
+
+       out = malloc(need);
+       if (out) {
+               base64decode((const char *)in, len, out, &need);
+               if (outlen) {
+                       *outlen = need;
+               }
+       }
+       return out;
+}
+
+unsigned char *tls_pem_decode(const unsigned char *data_in,
+                             unsigned int input_length, int cert_index,
+                             unsigned int *output_len) {
+       unsigned int i;
+       size_t alloc_len = input_length / 4 * 3;
+       unsigned char *output = malloc(alloc_len);
+       *output_len = 0;
+       if (!output)
+               return NULL;
+       unsigned int start_at = 0;
+       unsigned int idx = 0;
+
+       for (i = 0; i < input_length; i++) {
+               if ((data_in[i] == '\n') || (data_in[i] == '\r'))
+                       continue;
+
+               if (data_in[i] != '-') {
+                       /* read entire line */
+                       while ((i < input_length) && (data_in[i] != '\n'))
+                               i++;
+                       continue;
+               }
+
+               if (data_in[i] == '-') {
+                       unsigned int end_idx = i;
+                       /* read until end of line */
+                       while ((i < input_length) && (data_in[i] != '\n'))
+                               i++;
+                       if (start_at) {
+                               if (cert_index > 0) {
+                                       cert_index--;
+                                       start_at = 0;
+                               } else {
+                                           base64decode((const char
+                                                                *)
+                                                               &data_in
+                                                               [start_at],
+                                                               end_idx -
+                                                               start_at,
+                                                               output,
+                                                               &alloc_len);
+                                           idx = alloc_len;
+                                       break;
+                               }
+                       } else
+                               start_at = i + 1;
+               }
+       }
+       *output_len = idx;
+       if (!idx) {
+               free(output);
+               return NULL;
+       }
+       return output;
+}
+
+#if 0
+int load_cert_list(struct TLSContext *tls, const unsigned char *buf, size_t
+               bufsize, struct TLSCertificate **certs, int flags) {
+       struct pem_loc loc = { 0 };
+       struct TLSCertificate *cert = 0;
+       const unsigned char *pem = buf;
+       int count = 0;
+
+       while (bufsize > 0) {
+               if (bufsize <= loc.end) {
+                       break;
+               }
+               bufsize -= loc.end;
+
+               //fprintf(stderr, "checking %zu bytes at %p\n", remaining, pem);
+               pem = next_pem(pem, bufsize, &loc);
+               if (!pem) {
+                       break;
+               }
+               cert = asn1_parse(tls, buf+loc.start, loc.len, 0);
+               if (!cert) {
+                       continue;
+               }
+#ifdef TLS_X509_V1_SUPPORT
+               if (cert->version != 2 && cert->version != 0)
+#else
+               if (cert->version != 2)
+#endif
+               {
+                       free(cert);
+                       cert = 0;
+               }
+               count++;
+
+               //fprintf(stderr, "found length %zu pem starting at %zu taking %zu bytes\n",
+                               //loc.len,
+                               //loc.start,
+                               //loc.end);
+       }
+       return 0;
+}
+#endif
+
+int add_to_list(struct TLSCertificate ***list, int *len,
+               struct TLSCertificate *cert) {
+       void *new;
+
+       new = TLS_REALLOC(*list, (*len+1) * sizeof *list);
+       if (new) {
+               *list = new;
+               (*list)[(*len)++] = cert;
+       } else {
+               return 0;
+       }
+       return *len;
+}
+
+int tls_load_certificates(struct TLSContext *tls,
+                         const unsigned char *pem, int size) {
+       if (!tls)
+               return TLS_GENERIC_ERROR;
+
+       unsigned int len;
+       int idx = 0;
+       do {
+               unsigned char *data =
+                   tls_pem_decode(pem, size, idx++, &len);
+               if ((!data) || (!len))
+                       break;
+               struct TLSCertificate *cert =
+                   asn1_parse(tls, data, len, 0);
+               if (cert) {
+                       if ((cert->version == 2)
+#ifdef TLS_X509_V1_SUPPORT
+                           || (cert->version == 0)
+#endif
+                           ) {
+
+                               free(cert->der_bytes);
+                               cert->der_bytes = data;
+                               cert->der_len = len;
+                               data = NULL;
+                               if (cert->priv) {
+                                       DEBUG_PRINT
+                                           ("WARNING - parse error (private key encountered in certificate)\n");
+                                       free(cert->priv);
+                                       cert->priv = NULL;
+                                       cert->priv_len = 0;
+                               }
+                               add_to_list(&tls->certificates, &tls->certificates_count, cert);
+
+                       } else {
+                               DEBUG_PRINT
+                                   ("WARNING - certificate version error (v%d)\n",
+                                    (int) cert->version);
+                               tls_destroy_certificate(cert);
+                       }
+               }
+               free(data);
+       } while (1);
+       return tls->certificates_count;
+}
+
+int tls_load_private_key(struct TLSContext *tls,
+                        const unsigned char *pem_buffer, int pem_size) {
+       if (!tls)
+               return TLS_GENERIC_ERROR;
+
+       unsigned int len;
+       int idx = 0;
+       do {
+               unsigned char *data =
+                   tls_pem_decode(pem_buffer, pem_size, idx++, &len);
+               if ((!data) || (!len))
+                       break;
+               struct TLSCertificate *cert =
+                   asn1_parse(tls, data, len, -1);
+               if (cert) {
+                       if (!cert->der_len) {
+                               free(cert->der_bytes);
+                               cert->der_bytes = data;
+                               cert->der_len = len;
+                       } else {
+                               free(data);
+                       }
+                       if ((cert) && (cert->priv) && (cert->priv_len)) {
+#ifdef TLS_ECDSA_SUPPORTED
+                               if (cert->ec_algorithm) {
+                                       DEBUG_PRINT
+                                           ("Loaded ECC private key\n");
+                                       if (tls->ec_private_key)
+                                               tls_destroy_certificate
+                                                   (tls->ec_private_key);
+                                       tls->ec_private_key = cert;
+                                       return 1;
+                               } else
+#endif
+                               {
+                                       DEBUG_PRINT
+                                           ("Loaded private key\n");
+                                       if (tls->private_key)
+                                               tls_destroy_certificate
+                                                   (tls->private_key);
+                                       tls->private_key = cert;
+                                       return 1;
+                               }
+                       }
+                       tls_destroy_certificate(cert);
+               } else
+                       free(data);
+       } while (1);
+       return 0;
+}
+
+int tls_load_root_certificates(struct TLSContext *tls,
+                              const unsigned char *pem_buffer,
+                              int pem_size) {
+       if (!tls)
+               return -1;
+
+       unsigned int len;
+       int idx = 0;
+
+       do {
+               unsigned char *data =
+                   tls_pem_decode(pem_buffer, pem_size, idx++, &len);
+               if ((!data) || (!len))
+                       break;
+               struct TLSCertificate *cert =
+                   asn1_parse(NULL, data, len, 0);
+               if (cert) {
+                       if (cert->version == 2) {
+                               if (cert->priv) {
+                                       DEBUG_PRINT
+                                           ("WARNING - parse error (private key encountered in certificate)\n");
+                                       free(cert->priv);
+                                       cert->priv = NULL;
+                                       cert->priv_len = 0;
+                               }
+                               add_to_list(&tls->root_certificates,
+                                               &tls->root_count,
+                                               cert);
+                               DEBUG_PRINT("Loaded certificate: %d\n",
+                                           tls->root_count);
+                       } else {
+                               DEBUG_PRINT
+                                   ("WARNING - certificate version error (v%d)\n",
+                                    (int) cert->version);
+                               tls_destroy_certificate(cert);
+                       }
+               }
+               free(data);
+       } while (1);
+       return tls->root_count;
+}
+
diff --git a/crypto/ref10/base.c b/crypto/ref10/base.c
new file mode 100644 (file)
index 0000000..a97314a
--- /dev/null
@@ -0,0 +1,6 @@
+#include "fe.h"
+static const unsigned char basepoint[32] = {9};
+
+int crypto_scalarmult_base(unsigned char *q, const unsigned char *n) {
+       return x25519(q,n,basepoint);
+}
diff --git a/crypto/ref10/fe.h b/crypto/ref10/fe.h
new file mode 100644 (file)
index 0000000..eaa5e66
--- /dev/null
@@ -0,0 +1,30 @@
+#ifndef FE_H
+#define FE_H
+
+#include <stdint.h>
+
+/*
+fe means field element.
+Here the field is \Z/(2^255-19).
+An element t, entries t[0]...t[9], represents the integer
+t[0]+2^26 t[1]+2^51 t[2]+2^77 t[3]+2^102 t[4]+...+2^230 t[9].
+Bounds on each t[i] vary depending on context.
+*/
+int x25519(unsigned char *q, const unsigned char *n, const unsigned char *p);
+
+void fe_frombytes(int32_t fe[10], const unsigned char *);
+void fe_tobytes(unsigned char *, int32_t fe[10]);
+
+void fe_copy(int32_t dest[10], int32_t src[10]);
+void fe_0(int32_t fe[10]);
+void fe_1(int32_t fe[10]);
+void fe_cswap(int32_t a[10], int32_t b[10], unsigned int);
+
+void fe_add(int32_t dest[10], int32_t a[10], int32_t b[10]);
+void fe_sub(int32_t dest[10], int32_t a[10], int32_t b[10]);
+void fe_mul(int32_t dest[10], int32_t a[10], int32_t b[10]);
+void fe_sq(int32_t dest[10], int32_t a[10]);
+void fe_mul121666(int32_t dest[10], int32_t a[10]);
+void fe_invert(int32_t dest[10], int32_t a[10]);
+
+#endif
diff --git a/crypto/ref10/fe_0.c b/crypto/ref10/fe_0.c
new file mode 100644 (file)
index 0000000..a814e94
--- /dev/null
@@ -0,0 +1,18 @@
+#include <stdint.h>
+
+/*
+h = 0
+*/
+
+void fe_0(int32_t h[10]) {
+       h[0] = 0;
+       h[1] = 0;
+       h[2] = 0;
+       h[3] = 0;
+       h[4] = 0;
+       h[5] = 0;
+       h[6] = 0;
+       h[7] = 0;
+       h[8] = 0;
+       h[9] = 0;
+}
diff --git a/crypto/ref10/fe_1.c b/crypto/ref10/fe_1.c
new file mode 100644 (file)
index 0000000..4c1f4df
--- /dev/null
@@ -0,0 +1,14 @@
+#include <stdint.h>
+
+void fe_1(int32_t h[10]) {
+       h[0] = 1;
+       h[1] = 0;
+       h[2] = 0;
+       h[3] = 0;
+       h[4] = 0;
+       h[5] = 0;
+       h[6] = 0;
+       h[7] = 0;
+       h[8] = 0;
+       h[9] = 0;
+}
diff --git a/crypto/ref10/fe_add.c b/crypto/ref10/fe_add.c
new file mode 100644 (file)
index 0000000..4882509
--- /dev/null
@@ -0,0 +1,58 @@
+#define _POSIX_C_SOURCE 200109L
+
+#include <stdint.h>
+
+/*
+h = f + g
+Can overlap h with f or g.
+
+Preconditions:
+   |f| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
+   |g| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
+
+Postconditions:
+   |h| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
+*/
+
+void fe_add(int32_t h[10], int32_t f[10], int32_t g[10]) {
+       int32_t f0 = f[0];
+       int32_t f1 = f[1];
+       int32_t f2 = f[2];
+       int32_t f3 = f[3];
+       int32_t f4 = f[4];
+       int32_t f5 = f[5];
+       int32_t f6 = f[6];
+       int32_t f7 = f[7];
+       int32_t f8 = f[8];
+       int32_t f9 = f[9];
+       int32_t g0 = g[0];
+       int32_t g1 = g[1];
+       int32_t g2 = g[2];
+       int32_t g3 = g[3];
+       int32_t g4 = g[4];
+       int32_t g5 = g[5];
+       int32_t g6 = g[6];
+       int32_t g7 = g[7];
+       int32_t g8 = g[8];
+       int32_t g9 = g[9];
+       int32_t h0 = f0 + g0;
+       int32_t h1 = f1 + g1;
+       int32_t h2 = f2 + g2;
+       int32_t h3 = f3 + g3;
+       int32_t h4 = f4 + g4;
+       int32_t h5 = f5 + g5;
+       int32_t h6 = f6 + g6;
+       int32_t h7 = f7 + g7;
+       int32_t h8 = f8 + g8;
+       int32_t h9 = f9 + g9;
+       h[0] = h0;
+       h[1] = h1;
+       h[2] = h2;
+       h[3] = h3;
+       h[4] = h4;
+       h[5] = h5;
+       h[6] = h6;
+       h[7] = h7;
+       h[8] = h8;
+       h[9] = h9;
+}
diff --git a/crypto/ref10/fe_copy.c b/crypto/ref10/fe_copy.c
new file mode 100644 (file)
index 0000000..072b1b7
--- /dev/null
@@ -0,0 +1,28 @@
+#include <stdint.h>
+
+/*
+h = f
+*/
+
+void fe_copy(int32_t h[10], int32_t f[10]) {
+       int32_t f0 = f[0];
+       int32_t f1 = f[1];
+       int32_t f2 = f[2];
+       int32_t f3 = f[3];
+       int32_t f4 = f[4];
+       int32_t f5 = f[5];
+       int32_t f6 = f[6];
+       int32_t f7 = f[7];
+       int32_t f8 = f[8];
+       int32_t f9 = f[9];
+       h[0] = f0;
+       h[1] = f1;
+       h[2] = f2;
+       h[3] = f3;
+       h[4] = f4;
+       h[5] = f5;
+       h[6] = f6;
+       h[7] = f7;
+       h[8] = f8;
+       h[9] = f9;
+}
diff --git a/crypto/ref10/fe_cswap.c b/crypto/ref10/fe_cswap.c
new file mode 100644 (file)
index 0000000..242d3fc
--- /dev/null
@@ -0,0 +1,72 @@
+#include <stdint.h>
+
+/*
+Replace (f,g) with (g,f) if b == 1;
+replace (f,g) with (f,g) if b == 0.
+
+Preconditions: b in {0,1}.
+*/
+
+void fe_cswap(int32_t f[10], int32_t g[10], unsigned int b) {
+       int32_t f0 = f[0];
+       int32_t f1 = f[1];
+       int32_t f2 = f[2];
+       int32_t f3 = f[3];
+       int32_t f4 = f[4];
+       int32_t f5 = f[5];
+       int32_t f6 = f[6];
+       int32_t f7 = f[7];
+       int32_t f8 = f[8];
+       int32_t f9 = f[9];
+       int32_t g0 = g[0];
+       int32_t g1 = g[1];
+       int32_t g2 = g[2];
+       int32_t g3 = g[3];
+       int32_t g4 = g[4];
+       int32_t g5 = g[5];
+       int32_t g6 = g[6];
+       int32_t g7 = g[7];
+       int32_t g8 = g[8];
+       int32_t g9 = g[9];
+       int32_t x0 = f0 ^ g0;
+       int32_t x1 = f1 ^ g1;
+       int32_t x2 = f2 ^ g2;
+       int32_t x3 = f3 ^ g3;
+       int32_t x4 = f4 ^ g4;
+       int32_t x5 = f5 ^ g5;
+       int32_t x6 = f6 ^ g6;
+       int32_t x7 = f7 ^ g7;
+       int32_t x8 = f8 ^ g8;
+       int32_t x9 = f9 ^ g9;
+       b = -b;
+       x0 &= b;
+       x1 &= b;
+       x2 &= b;
+       x3 &= b;
+       x4 &= b;
+       x5 &= b;
+       x6 &= b;
+       x7 &= b;
+       x8 &= b;
+       x9 &= b;
+       f[0] = f0 ^ x0;
+       f[1] = f1 ^ x1;
+       f[2] = f2 ^ x2;
+       f[3] = f3 ^ x3;
+       f[4] = f4 ^ x4;
+       f[5] = f5 ^ x5;
+       f[6] = f6 ^ x6;
+       f[7] = f7 ^ x7;
+       f[8] = f8 ^ x8;
+       f[9] = f9 ^ x9;
+       g[0] = g0 ^ x0;
+       g[1] = g1 ^ x1;
+       g[2] = g2 ^ x2;
+       g[3] = g3 ^ x3;
+       g[4] = g4 ^ x4;
+       g[5] = g5 ^ x5;
+       g[6] = g6 ^ x6;
+       g[7] = g7 ^ x7;
+       g[8] = g8 ^ x8;
+       g[9] = g9 ^ x9;
+}
diff --git a/crypto/ref10/fe_frombytes.c b/crypto/ref10/fe_frombytes.c
new file mode 100644 (file)
index 0000000..550f4de
--- /dev/null
@@ -0,0 +1,64 @@
+#include <stdint.h>
+
+static uint64_t load_3(const unsigned char *in) {
+       uint64_t result;
+       result = (uint64_t) in[0];
+       result |= ((uint64_t) in[1]) << 8;
+       result |= ((uint64_t) in[2]) << 16;
+       return result;
+}
+
+static uint64_t load_4(const unsigned char *in) {
+       uint64_t result;
+       result = (uint64_t) in[0];
+       result |= ((uint64_t) in[1]) << 8;
+       result |= ((uint64_t) in[2]) << 16;
+       result |= ((uint64_t) in[3]) << 24;
+       return result;
+}
+
+void fe_frombytes(uint32_t h[10], const unsigned char *s) {
+       int64_t h0 = load_4(s);
+       int64_t h1 = load_3(s + 4) << 6;
+       int64_t h2 = load_3(s + 7) << 5;
+       int64_t h3 = load_3(s + 10) << 3;
+       int64_t h4 = load_3(s + 13) << 2;
+       int64_t h5 = load_4(s + 16);
+       int64_t h6 = load_3(s + 20) << 7;
+       int64_t h7 = load_3(s + 23) << 5;
+       int64_t h8 = load_3(s + 26) << 4;
+       int64_t h9 = (load_3(s + 29) & 8388607) << 2;
+       int64_t carry0;
+       int64_t carry1;
+       int64_t carry2;
+       int64_t carry3;
+       int64_t carry4;
+       int64_t carry5;
+       int64_t carry6;
+       int64_t carry7;
+       int64_t carry8;
+       int64_t carry9;
+
+       carry9 = (h9 + (int64_t) (1<<24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25;
+       carry1 = (h1 + (int64_t) (1<<24)) >> 25; h2 += carry1; h1 -= carry1 << 25;
+       carry3 = (h3 + (int64_t) (1<<24)) >> 25; h4 += carry3; h3 -= carry3 << 25;
+       carry5 = (h5 + (int64_t) (1<<24)) >> 25; h6 += carry5; h5 -= carry5 << 25;
+       carry7 = (h7 + (int64_t) (1<<24)) >> 25; h8 += carry7; h7 -= carry7 << 25;
+
+       carry0 = (h0 + (int64_t) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26;
+       carry2 = (h2 + (int64_t) (1<<25)) >> 26; h3 += carry2; h2 -= carry2 << 26;
+       carry4 = (h4 + (int64_t) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26;
+       carry6 = (h6 + (int64_t) (1<<25)) >> 26; h7 += carry6; h6 -= carry6 << 26;
+       carry8 = (h8 + (int64_t) (1<<25)) >> 26; h9 += carry8; h8 -= carry8 << 26;
+
+       h[0] = h0;
+       h[1] = h1;
+       h[2] = h2;
+       h[3] = h3;
+       h[4] = h4;
+       h[5] = h5;
+       h[6] = h6;
+       h[7] = h7;
+       h[8] = h8;
+       h[9] = h9;
+}
diff --git a/crypto/ref10/fe_invert.c b/crypto/ref10/fe_invert.c
new file mode 100644 (file)
index 0000000..ee46ce8
--- /dev/null
@@ -0,0 +1,79 @@
+#include <stdint.h>
+
+#include "fe.h"
+
+void fe_invert(int32_t out[10], int32_t z[10]) {
+       int32_t t0[10];
+       int32_t t1[10];
+       int32_t t2[10];
+       int32_t t3[10];
+       int i;
+
+       /* qhasm: z2 = z1^2^1 */
+       fe_sq(t0,z); for (i = 1;i < 1;++i) fe_sq(t0,t0);
+
+       /* qhasm: z8 = z2^2^2 */
+       fe_sq(t1,t0); for (i = 1;i < 2;++i) fe_sq(t1,t1);
+
+       /* qhasm: z9 = z1*z8 */
+       fe_mul(t1,z,t1);
+
+       /* qhasm: z11 = z2*z9 */
+       fe_mul(t0,t0,t1);
+
+       /* qhasm: z22 = z11^2^1 */
+       fe_sq(t2,t0); for (i = 1;i < 1;++i) fe_sq(t2,t2);
+
+       /* qhasm: z_5_0 = z9*z22 */
+       fe_mul(t1,t1,t2);
+
+       /* qhasm: z_10_5 = z_5_0^2^5 */
+       fe_sq(t2,t1); for (i = 1;i < 5;++i) fe_sq(t2,t2);
+
+       /* qhasm: z_10_0 = z_10_5*z_5_0 */
+       fe_mul(t1,t2,t1);
+
+       /* qhasm: z_20_10 = z_10_0^2^10 */
+       fe_sq(t2,t1); for (i = 1;i < 10;++i) fe_sq(t2,t2);
+
+       /* qhasm: z_20_0 = z_20_10*z_10_0 */
+       fe_mul(t2,t2,t1);
+
+       /* qhasm: z_40_20 = z_20_0^2^20 */
+       fe_sq(t3,t2); for (i = 1;i < 20;++i) fe_sq(t3,t3);
+
+       /* qhasm: z_40_0 = z_40_20*z_20_0 */
+       fe_mul(t2,t3,t2);
+
+       /* qhasm: z_50_10 = z_40_0^2^10 */
+       fe_sq(t2,t2); for (i = 1;i < 10;++i) fe_sq(t2,t2);
+
+       /* qhasm: z_50_0 = z_50_10*z_10_0 */
+       fe_mul(t1,t2,t1);
+
+       /* qhasm: z_100_50 = z_50_0^2^50 */
+       fe_sq(t2,t1); for (i = 1;i < 50;++i) fe_sq(t2,t2);
+
+       /* qhasm: z_100_0 = z_100_50*z_50_0 */
+       fe_mul(t2,t2,t1);
+
+       /* qhasm: z_200_100 = z_100_0^2^100 */
+       fe_sq(t3,t2); for (i = 1;i < 100;++i) fe_sq(t3,t3);
+
+       /* qhasm: z_200_0 = z_200_100*z_100_0 */
+       fe_mul(t2,t3,t2);
+
+       /* qhasm: z_250_50 = z_200_0^2^50 */
+       fe_sq(t2,t2); for (i = 1;i < 50;++i) fe_sq(t2,t2);
+
+       /* qhasm: z_250_0 = z_250_50*z_50_0 */
+       fe_mul(t1,t2,t1);
+
+       /* qhasm: z_255_5 = z_250_0^2^5 */
+       fe_sq(t1,t1); for (i = 1;i < 5;++i) fe_sq(t1,t1);
+
+       /* qhasm: z_255_21 = z_255_5*z11 */
+       fe_mul(out,t1,t0);
+
+       return;
+}
diff --git a/crypto/ref10/fe_mul.c b/crypto/ref10/fe_mul.c
new file mode 100644 (file)
index 0000000..15d32d0
--- /dev/null
@@ -0,0 +1,251 @@
+#include <stdint.h>
+
+/*
+h = f * g
+Can overlap h with f or g.
+
+Preconditions:
+   |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
+   |g| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
+
+Postconditions:
+   |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
+*/
+
+/*
+Notes on implementation strategy:
+
+Using schoolbook multiplication.
+Karatsuba would save a little in some cost models.
+
+Most multiplications by 2 and 19 are 32-bit precomputations;
+cheaper than 64-bit postcomputations.
+
+There is one remaining multiplication by 19 in the carry chain;
+one *19 precomputation can be merged into this,
+but the resulting data flow is considerably less clean.
+
+There are 12 carries below.
+10 of them are 2-way parallelizable and vectorizable.
+Can get away with 11 carries, but then data flow is much deeper.
+
+With tighter constraints on inputs can squeeze carries into int32.
+*/
+
+void fe_mul(int32_t h[10], int32_t f[10], int32_t g[10]) {
+       int32_t f0 = f[0];
+       int32_t f1 = f[1];
+       int32_t f2 = f[2];
+       int32_t f3 = f[3];
+       int32_t f4 = f[4];
+       int32_t f5 = f[5];
+       int32_t f6 = f[6];
+       int32_t f7 = f[7];
+       int32_t f8 = f[8];
+       int32_t f9 = f[9];
+       int32_t g0 = g[0];
+       int32_t g1 = g[1];
+       int32_t g2 = g[2];
+       int32_t g3 = g[3];
+       int32_t g4 = g[4];
+       int32_t g5 = g[5];
+       int32_t g6 = g[6];
+       int32_t g7 = g[7];
+       int32_t g8 = g[8];
+       int32_t g9 = g[9];
+       int32_t g1_19 = 19 * g1; /* 1.4*2^29 */
+       int32_t g2_19 = 19 * g2; /* 1.4*2^30; still ok */
+       int32_t g3_19 = 19 * g3;
+       int32_t g4_19 = 19 * g4;
+       int32_t g5_19 = 19 * g5;
+       int32_t g6_19 = 19 * g6;
+       int32_t g7_19 = 19 * g7;
+       int32_t g8_19 = 19 * g8;
+       int32_t g9_19 = 19 * g9;
+       int32_t f1_2 = 2 * f1;
+       int32_t f3_2 = 2 * f3;
+       int32_t f5_2 = 2 * f5;
+       int32_t f7_2 = 2 * f7;
+       int32_t f9_2 = 2 * f9;
+       int64_t f0g0    = f0   * (int64_t) g0;
+       int64_t f0g1    = f0   * (int64_t) g1;
+       int64_t f0g2    = f0   * (int64_t) g2;
+       int64_t f0g3    = f0   * (int64_t) g3;
+       int64_t f0g4    = f0   * (int64_t) g4;
+       int64_t f0g5    = f0   * (int64_t) g5;
+       int64_t f0g6    = f0   * (int64_t) g6;
+       int64_t f0g7    = f0   * (int64_t) g7;
+       int64_t f0g8    = f0   * (int64_t) g8;
+       int64_t f0g9    = f0   * (int64_t) g9;
+       int64_t f1g0    = f1   * (int64_t) g0;
+       int64_t f1g1_2  = f1_2 * (int64_t) g1;
+       int64_t f1g2    = f1   * (int64_t) g2;
+       int64_t f1g3_2  = f1_2 * (int64_t) g3;
+       int64_t f1g4    = f1   * (int64_t) g4;
+       int64_t f1g5_2  = f1_2 * (int64_t) g5;
+       int64_t f1g6    = f1   * (int64_t) g6;
+       int64_t f1g7_2  = f1_2 * (int64_t) g7;
+       int64_t f1g8    = f1   * (int64_t) g8;
+       int64_t f1g9_38 = f1_2 * (int64_t) g9_19;
+       int64_t f2g0    = f2   * (int64_t) g0;
+       int64_t f2g1    = f2   * (int64_t) g1;
+       int64_t f2g2    = f2   * (int64_t) g2;
+       int64_t f2g3    = f2   * (int64_t) g3;
+       int64_t f2g4    = f2   * (int64_t) g4;
+       int64_t f2g5    = f2   * (int64_t) g5;
+       int64_t f2g6    = f2   * (int64_t) g6;
+       int64_t f2g7    = f2   * (int64_t) g7;
+       int64_t f2g8_19 = f2   * (int64_t) g8_19;
+       int64_t f2g9_19 = f2   * (int64_t) g9_19;
+       int64_t f3g0    = f3   * (int64_t) g0;
+       int64_t f3g1_2  = f3_2 * (int64_t) g1;
+       int64_t f3g2    = f3   * (int64_t) g2;
+       int64_t f3g3_2  = f3_2 * (int64_t) g3;
+       int64_t f3g4    = f3   * (int64_t) g4;
+       int64_t f3g5_2  = f3_2 * (int64_t) g5;
+       int64_t f3g6    = f3   * (int64_t) g6;
+       int64_t f3g7_38 = f3_2 * (int64_t) g7_19;
+       int64_t f3g8_19 = f3   * (int64_t) g8_19;
+       int64_t f3g9_38 = f3_2 * (int64_t) g9_19;
+       int64_t f4g0    = f4   * (int64_t) g0;
+       int64_t f4g1    = f4   * (int64_t) g1;
+       int64_t f4g2    = f4   * (int64_t) g2;
+       int64_t f4g3    = f4   * (int64_t) g3;
+       int64_t f4g4    = f4   * (int64_t) g4;
+       int64_t f4g5    = f4   * (int64_t) g5;
+       int64_t f4g6_19 = f4   * (int64_t) g6_19;
+       int64_t f4g7_19 = f4   * (int64_t) g7_19;
+       int64_t f4g8_19 = f4   * (int64_t) g8_19;
+       int64_t f4g9_19 = f4   * (int64_t) g9_19;
+       int64_t f5g0    = f5   * (int64_t) g0;
+       int64_t f5g1_2  = f5_2 * (int64_t) g1;
+       int64_t f5g2    = f5   * (int64_t) g2;
+       int64_t f5g3_2  = f5_2 * (int64_t) g3;
+       int64_t f5g4    = f5   * (int64_t) g4;
+       int64_t f5g5_38 = f5_2 * (int64_t) g5_19;
+       int64_t f5g6_19 = f5   * (int64_t) g6_19;
+       int64_t f5g7_38 = f5_2 * (int64_t) g7_19;
+       int64_t f5g8_19 = f5   * (int64_t) g8_19;
+       int64_t f5g9_38 = f5_2 * (int64_t) g9_19;
+       int64_t f6g0    = f6   * (int64_t) g0;
+       int64_t f6g1    = f6   * (int64_t) g1;
+       int64_t f6g2    = f6   * (int64_t) g2;
+       int64_t f6g3    = f6   * (int64_t) g3;
+       int64_t f6g4_19 = f6   * (int64_t) g4_19;
+       int64_t f6g5_19 = f6   * (int64_t) g5_19;
+       int64_t f6g6_19 = f6   * (int64_t) g6_19;
+       int64_t f6g7_19 = f6   * (int64_t) g7_19;
+       int64_t f6g8_19 = f6   * (int64_t) g8_19;
+       int64_t f6g9_19 = f6   * (int64_t) g9_19;
+       int64_t f7g0    = f7   * (int64_t) g0;
+       int64_t f7g1_2  = f7_2 * (int64_t) g1;
+       int64_t f7g2    = f7   * (int64_t) g2;
+       int64_t f7g3_38 = f7_2 * (int64_t) g3_19;
+       int64_t f7g4_19 = f7   * (int64_t) g4_19;
+       int64_t f7g5_38 = f7_2 * (int64_t) g5_19;
+       int64_t f7g6_19 = f7   * (int64_t) g6_19;
+       int64_t f7g7_38 = f7_2 * (int64_t) g7_19;
+       int64_t f7g8_19 = f7   * (int64_t) g8_19;
+       int64_t f7g9_38 = f7_2 * (int64_t) g9_19;
+       int64_t f8g0    = f8   * (int64_t) g0;
+       int64_t f8g1    = f8   * (int64_t) g1;
+       int64_t f8g2_19 = f8   * (int64_t) g2_19;
+       int64_t f8g3_19 = f8   * (int64_t) g3_19;
+       int64_t f8g4_19 = f8   * (int64_t) g4_19;
+       int64_t f8g5_19 = f8   * (int64_t) g5_19;
+       int64_t f8g6_19 = f8   * (int64_t) g6_19;
+       int64_t f8g7_19 = f8   * (int64_t) g7_19;
+       int64_t f8g8_19 = f8   * (int64_t) g8_19;
+       int64_t f8g9_19 = f8   * (int64_t) g9_19;
+       int64_t f9g0    = f9   * (int64_t) g0;
+       int64_t f9g1_38 = f9_2 * (int64_t) g1_19;
+       int64_t f9g2_19 = f9   * (int64_t) g2_19;
+       int64_t f9g3_38 = f9_2 * (int64_t) g3_19;
+       int64_t f9g4_19 = f9   * (int64_t) g4_19;
+       int64_t f9g5_38 = f9_2 * (int64_t) g5_19;
+       int64_t f9g6_19 = f9   * (int64_t) g6_19;
+       int64_t f9g7_38 = f9_2 * (int64_t) g7_19;
+       int64_t f9g8_19 = f9   * (int64_t) g8_19;
+       int64_t f9g9_38 = f9_2 * (int64_t) g9_19;
+       int64_t h0 = f0g0+f1g9_38+f2g8_19+f3g7_38+f4g6_19+f5g5_38+f6g4_19+f7g3_38+f8g2_19+f9g1_38;
+       int64_t h1 = f0g1+f1g0   +f2g9_19+f3g8_19+f4g7_19+f5g6_19+f6g5_19+f7g4_19+f8g3_19+f9g2_19;
+       int64_t h2 = f0g2+f1g1_2 +f2g0   +f3g9_38+f4g8_19+f5g7_38+f6g6_19+f7g5_38+f8g4_19+f9g3_38;
+       int64_t h3 = f0g3+f1g2   +f2g1   +f3g0   +f4g9_19+f5g8_19+f6g7_19+f7g6_19+f8g5_19+f9g4_19;
+       int64_t h4 = f0g4+f1g3_2 +f2g2   +f3g1_2 +f4g0   +f5g9_38+f6g8_19+f7g7_38+f8g6_19+f9g5_38;
+       int64_t h5 = f0g5+f1g4   +f2g3   +f3g2   +f4g1   +f5g0   +f6g9_19+f7g8_19+f8g7_19+f9g6_19;
+       int64_t h6 = f0g6+f1g5_2 +f2g4   +f3g3_2 +f4g2   +f5g1_2 +f6g0   +f7g9_38+f8g8_19+f9g7_38;
+       int64_t h7 = f0g7+f1g6   +f2g5   +f3g4   +f4g3   +f5g2   +f6g1   +f7g0   +f8g9_19+f9g8_19;
+       int64_t h8 = f0g8+f1g7_2 +f2g6   +f3g5_2 +f4g4   +f5g3_2 +f6g2   +f7g1_2 +f8g0   +f9g9_38;
+       int64_t h9 = f0g9+f1g8   +f2g7   +f3g6   +f4g5   +f5g4   +f6g3   +f7g2   +f8g1   +f9g0   ;
+       int64_t carry0;
+       int64_t carry1;
+       int64_t carry2;
+       int64_t carry3;
+       int64_t carry4;
+       int64_t carry5;
+       int64_t carry6;
+       int64_t carry7;
+       int64_t carry8;
+       int64_t carry9;
+
+       /*
+          |h0| <= (1.1*1.1*2^52*(1+19+19+19+19)+1.1*1.1*2^50*(38+38+38+38+38))
+          i.e. |h0| <= 1.2*2^59; narrower ranges for h2, h4, h6, h8
+          |h1| <= (1.1*1.1*2^51*(1+1+19+19+19+19+19+19+19+19))
+          i.e. |h1| <= 1.5*2^58; narrower ranges for h3, h5, h7, h9
+          */
+
+       carry0 = (h0 + (int64_t) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26;
+       carry4 = (h4 + (int64_t) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26;
+       /* |h0| <= 2^25 */
+       /* |h4| <= 2^25 */
+       /* |h1| <= 1.51*2^58 */
+       /* |h5| <= 1.51*2^58 */
+
+       carry1 = (h1 + (int64_t) (1<<24)) >> 25; h2 += carry1; h1 -= carry1 << 25;
+       carry5 = (h5 + (int64_t) (1<<24)) >> 25; h6 += carry5; h5 -= carry5 << 25;
+       /* |h1| <= 2^24; from now on fits into int32 */
+       /* |h5| <= 2^24; from now on fits into int32 */
+       /* |h2| <= 1.21*2^59 */
+       /* |h6| <= 1.21*2^59 */
+
+       carry2 = (h2 + (int64_t) (1<<25)) >> 26; h3 += carry2; h2 -= carry2 << 26;
+       carry6 = (h6 + (int64_t) (1<<25)) >> 26; h7 += carry6; h6 -= carry6 << 26;
+       /* |h2| <= 2^25; from now on fits into int32 unchanged */
+       /* |h6| <= 2^25; from now on fits into int32 unchanged */
+       /* |h3| <= 1.51*2^58 */
+       /* |h7| <= 1.51*2^58 */
+
+       carry3 = (h3 + (int64_t) (1<<24)) >> 25; h4 += carry3; h3 -= carry3 << 25;
+       carry7 = (h7 + (int64_t) (1<<24)) >> 25; h8 += carry7; h7 -= carry7 << 25;
+       /* |h3| <= 2^24; from now on fits into int32 unchanged */
+       /* |h7| <= 2^24; from now on fits into int32 unchanged */
+       /* |h4| <= 1.52*2^33 */
+       /* |h8| <= 1.52*2^33 */
+
+       carry4 = (h4 + (int64_t) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26;
+       carry8 = (h8 + (int64_t) (1<<25)) >> 26; h9 += carry8; h8 -= carry8 << 26;
+       /* |h4| <= 2^25; from now on fits into int32 unchanged */
+       /* |h8| <= 2^25; from now on fits into int32 unchanged */
+       /* |h5| <= 1.01*2^24 */
+       /* |h9| <= 1.51*2^58 */
+
+       carry9 = (h9 + (int64_t) (1<<24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25;
+       /* |h9| <= 2^24; from now on fits into int32 unchanged */
+       /* |h0| <= 1.8*2^37 */
+
+       carry0 = (h0 + (int64_t) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26;
+       /* |h0| <= 2^25; from now on fits into int32 unchanged */
+       /* |h1| <= 1.01*2^24 */
+
+       h[0] = h0;
+       h[1] = h1;
+       h[2] = h2;
+       h[3] = h3;
+       h[4] = h4;
+       h[5] = h5;
+       h[6] = h6;
+       h[7] = h7;
+       h[8] = h8;
+       h[9] = h9;
+}
diff --git a/crypto/ref10/fe_mul121666.c b/crypto/ref10/fe_mul121666.c
new file mode 100644 (file)
index 0000000..ae96853
--- /dev/null
@@ -0,0 +1,68 @@
+#include <stdint.h>
+
+/*
+h = f * 121666
+Can overlap h with f.
+
+Preconditions:
+   |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
+
+Postconditions:
+   |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
+*/
+
+void fe_mul121666(int32_t h[10], int32_t f[10]) {
+       int32_t f0 = f[0];
+       int32_t f1 = f[1];
+       int32_t f2 = f[2];
+       int32_t f3 = f[3];
+       int32_t f4 = f[4];
+       int32_t f5 = f[5];
+       int32_t f6 = f[6];
+       int32_t f7 = f[7];
+       int32_t f8 = f[8];
+       int32_t f9 = f[9];
+       int64_t h0 = f0 * (int64_t) 121666;
+       int64_t h1 = f1 * (int64_t) 121666;
+       int64_t h2 = f2 * (int64_t) 121666;
+       int64_t h3 = f3 * (int64_t) 121666;
+       int64_t h4 = f4 * (int64_t) 121666;
+       int64_t h5 = f5 * (int64_t) 121666;
+       int64_t h6 = f6 * (int64_t) 121666;
+       int64_t h7 = f7 * (int64_t) 121666;
+       int64_t h8 = f8 * (int64_t) 121666;
+       int64_t h9 = f9 * (int64_t) 121666;
+       int64_t carry0;
+       int64_t carry1;
+       int64_t carry2;
+       int64_t carry3;
+       int64_t carry4;
+       int64_t carry5;
+       int64_t carry6;
+       int64_t carry7;
+       int64_t carry8;
+       int64_t carry9;
+
+       carry9 = (h9 + (int64_t) (1<<24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25;
+       carry1 = (h1 + (int64_t) (1<<24)) >> 25; h2 += carry1; h1 -= carry1 << 25;
+       carry3 = (h3 + (int64_t) (1<<24)) >> 25; h4 += carry3; h3 -= carry3 << 25;
+       carry5 = (h5 + (int64_t) (1<<24)) >> 25; h6 += carry5; h5 -= carry5 << 25;
+       carry7 = (h7 + (int64_t) (1<<24)) >> 25; h8 += carry7; h7 -= carry7 << 25;
+
+       carry0 = (h0 + (int64_t) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26;
+       carry2 = (h2 + (int64_t) (1<<25)) >> 26; h3 += carry2; h2 -= carry2 << 26;
+       carry4 = (h4 + (int64_t) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26;
+       carry6 = (h6 + (int64_t) (1<<25)) >> 26; h7 += carry6; h6 -= carry6 << 26;
+       carry8 = (h8 + (int64_t) (1<<25)) >> 26; h9 += carry8; h8 -= carry8 << 26;
+
+       h[0] = h0;
+       h[1] = h1;
+       h[2] = h2;
+       h[3] = h3;
+       h[4] = h4;
+       h[5] = h5;
+       h[6] = h6;
+       h[7] = h7;
+       h[8] = h8;
+       h[9] = h9;
+}
diff --git a/crypto/ref10/fe_sq.c b/crypto/ref10/fe_sq.c
new file mode 100644 (file)
index 0000000..aef97e4
--- /dev/null
@@ -0,0 +1,147 @@
+#include <stdint.h>
+
+/*
+h = f * f
+Can overlap h with f.
+
+Preconditions:
+   |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
+
+Postconditions:
+   |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
+*/
+
+/*
+See fe_mul.c for discussion of implementation strategy.
+*/
+
+void fe_sq(int32_t h[10], int32_t f[10]) {
+       int32_t f0 = f[0];
+       int32_t f1 = f[1];
+       int32_t f2 = f[2];
+       int32_t f3 = f[3];
+       int32_t f4 = f[4];
+       int32_t f5 = f[5];
+       int32_t f6 = f[6];
+       int32_t f7 = f[7];
+       int32_t f8 = f[8];
+       int32_t f9 = f[9];
+       int32_t f0_2 = 2 * f0;
+       int32_t f1_2 = 2 * f1;
+       int32_t f2_2 = 2 * f2;
+       int32_t f3_2 = 2 * f3;
+       int32_t f4_2 = 2 * f4;
+       int32_t f5_2 = 2 * f5;
+       int32_t f6_2 = 2 * f6;
+       int32_t f7_2 = 2 * f7;
+       int32_t f5_38 = 38 * f5; /* 1.31*2^30 */
+       int32_t f6_19 = 19 * f6; /* 1.31*2^30 */
+       int32_t f7_38 = 38 * f7; /* 1.31*2^30 */
+       int32_t f8_19 = 19 * f8; /* 1.31*2^30 */
+       int32_t f9_38 = 38 * f9; /* 1.31*2^30 */
+       int64_t f0f0    = f0   * (int64_t) f0;
+       int64_t f0f1_2  = f0_2 * (int64_t) f1;
+       int64_t f0f2_2  = f0_2 * (int64_t) f2;
+       int64_t f0f3_2  = f0_2 * (int64_t) f3;
+       int64_t f0f4_2  = f0_2 * (int64_t) f4;
+       int64_t f0f5_2  = f0_2 * (int64_t) f5;
+       int64_t f0f6_2  = f0_2 * (int64_t) f6;
+       int64_t f0f7_2  = f0_2 * (int64_t) f7;
+       int64_t f0f8_2  = f0_2 * (int64_t) f8;
+       int64_t f0f9_2  = f0_2 * (int64_t) f9;
+       int64_t f1f1_2  = f1_2 * (int64_t) f1;
+       int64_t f1f2_2  = f1_2 * (int64_t) f2;
+       int64_t f1f3_4  = f1_2 * (int64_t) f3_2;
+       int64_t f1f4_2  = f1_2 * (int64_t) f4;
+       int64_t f1f5_4  = f1_2 * (int64_t) f5_2;
+       int64_t f1f6_2  = f1_2 * (int64_t) f6;
+       int64_t f1f7_4  = f1_2 * (int64_t) f7_2;
+       int64_t f1f8_2  = f1_2 * (int64_t) f8;
+       int64_t f1f9_76 = f1_2 * (int64_t) f9_38;
+       int64_t f2f2    = f2   * (int64_t) f2;
+       int64_t f2f3_2  = f2_2 * (int64_t) f3;
+       int64_t f2f4_2  = f2_2 * (int64_t) f4;
+       int64_t f2f5_2  = f2_2 * (int64_t) f5;
+       int64_t f2f6_2  = f2_2 * (int64_t) f6;
+       int64_t f2f7_2  = f2_2 * (int64_t) f7;
+       int64_t f2f8_38 = f2_2 * (int64_t) f8_19;
+       int64_t f2f9_38 = f2   * (int64_t) f9_38;
+       int64_t f3f3_2  = f3_2 * (int64_t) f3;
+       int64_t f3f4_2  = f3_2 * (int64_t) f4;
+       int64_t f3f5_4  = f3_2 * (int64_t) f5_2;
+       int64_t f3f6_2  = f3_2 * (int64_t) f6;
+       int64_t f3f7_76 = f3_2 * (int64_t) f7_38;
+       int64_t f3f8_38 = f3_2 * (int64_t) f8_19;
+       int64_t f3f9_76 = f3_2 * (int64_t) f9_38;
+       int64_t f4f4    = f4   * (int64_t) f4;
+       int64_t f4f5_2  = f4_2 * (int64_t) f5;
+       int64_t f4f6_38 = f4_2 * (int64_t) f6_19;
+       int64_t f4f7_38 = f4   * (int64_t) f7_38;
+       int64_t f4f8_38 = f4_2 * (int64_t) f8_19;
+       int64_t f4f9_38 = f4   * (int64_t) f9_38;
+       int64_t f5f5_38 = f5   * (int64_t) f5_38;
+       int64_t f5f6_38 = f5_2 * (int64_t) f6_19;
+       int64_t f5f7_76 = f5_2 * (int64_t) f7_38;
+       int64_t f5f8_38 = f5_2 * (int64_t) f8_19;
+       int64_t f5f9_76 = f5_2 * (int64_t) f9_38;
+       int64_t f6f6_19 = f6   * (int64_t) f6_19;
+       int64_t f6f7_38 = f6   * (int64_t) f7_38;
+       int64_t f6f8_38 = f6_2 * (int64_t) f8_19;
+       int64_t f6f9_38 = f6   * (int64_t) f9_38;
+       int64_t f7f7_38 = f7   * (int64_t) f7_38;
+       int64_t f7f8_38 = f7_2 * (int64_t) f8_19;
+       int64_t f7f9_76 = f7_2 * (int64_t) f9_38;
+       int64_t f8f8_19 = f8   * (int64_t) f8_19;
+       int64_t f8f9_38 = f8   * (int64_t) f9_38;
+       int64_t f9f9_38 = f9   * (int64_t) f9_38;
+       int64_t h0 = f0f0  +f1f9_76+f2f8_38+f3f7_76+f4f6_38+f5f5_38;
+       int64_t h1 = f0f1_2+f2f9_38+f3f8_38+f4f7_38+f5f6_38;
+       int64_t h2 = f0f2_2+f1f1_2 +f3f9_76+f4f8_38+f5f7_76+f6f6_19;
+       int64_t h3 = f0f3_2+f1f2_2 +f4f9_38+f5f8_38+f6f7_38;
+       int64_t h4 = f0f4_2+f1f3_4 +f2f2   +f5f9_76+f6f8_38+f7f7_38;
+       int64_t h5 = f0f5_2+f1f4_2 +f2f3_2 +f6f9_38+f7f8_38;
+       int64_t h6 = f0f6_2+f1f5_4 +f2f4_2 +f3f3_2 +f7f9_76+f8f8_19;
+       int64_t h7 = f0f7_2+f1f6_2 +f2f5_2 +f3f4_2 +f8f9_38;
+       int64_t h8 = f0f8_2+f1f7_4 +f2f6_2 +f3f5_4 +f4f4   +f9f9_38;
+       int64_t h9 = f0f9_2+f1f8_2 +f2f7_2 +f3f6_2 +f4f5_2;
+       int64_t carry0;
+       int64_t carry1;
+       int64_t carry2;
+       int64_t carry3;
+       int64_t carry4;
+       int64_t carry5;
+       int64_t carry6;
+       int64_t carry7;
+       int64_t carry8;
+       int64_t carry9;
+
+       carry0 = (h0 + (int64_t) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26;
+       carry4 = (h4 + (int64_t) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26;
+
+       carry1 = (h1 + (int64_t) (1<<24)) >> 25; h2 += carry1; h1 -= carry1 << 25;
+       carry5 = (h5 + (int64_t) (1<<24)) >> 25; h6 += carry5; h5 -= carry5 << 25;
+
+       carry2 = (h2 + (int64_t) (1<<25)) >> 26; h3 += carry2; h2 -= carry2 << 26;
+       carry6 = (h6 + (int64_t) (1<<25)) >> 26; h7 += carry6; h6 -= carry6 << 26;
+
+       carry3 = (h3 + (int64_t) (1<<24)) >> 25; h4 += carry3; h3 -= carry3 << 25;
+       carry7 = (h7 + (int64_t) (1<<24)) >> 25; h8 += carry7; h7 -= carry7 << 25;
+
+       carry4 = (h4 + (int64_t) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26;
+       carry8 = (h8 + (int64_t) (1<<25)) >> 26; h9 += carry8; h8 -= carry8 << 26;
+
+       carry9 = (h9 + (int64_t) (1<<24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25;
+
+       carry0 = (h0 + (int64_t) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26;
+
+       h[0] = h0;
+       h[1] = h1;
+       h[2] = h2;
+       h[3] = h3;
+       h[4] = h4;
+       h[5] = h5;
+       h[6] = h6;
+       h[7] = h7;
+       h[8] = h8;
+       h[9] = h9;
+}
diff --git a/crypto/ref10/fe_sub.c b/crypto/ref10/fe_sub.c
new file mode 100644 (file)
index 0000000..2ad3512
--- /dev/null
@@ -0,0 +1,56 @@
+#include <stdint.h>
+
+/*
+h = f - g
+Can overlap h with f or g.
+
+Preconditions:
+   |f| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
+   |g| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
+
+Postconditions:
+   |h| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
+*/
+
+void fe_sub(int32_t h[10], int32_t f[10], int32_t g[10]) {
+       int32_t f0 = f[0];
+       int32_t f1 = f[1];
+       int32_t f2 = f[2];
+       int32_t f3 = f[3];
+       int32_t f4 = f[4];
+       int32_t f5 = f[5];
+       int32_t f6 = f[6];
+       int32_t f7 = f[7];
+       int32_t f8 = f[8];
+       int32_t f9 = f[9];
+       int32_t g0 = g[0];
+       int32_t g1 = g[1];
+       int32_t g2 = g[2];
+       int32_t g3 = g[3];
+       int32_t g4 = g[4];
+       int32_t g5 = g[5];
+       int32_t g6 = g[6];
+       int32_t g7 = g[7];
+       int32_t g8 = g[8];
+       int32_t g9 = g[9];
+       int32_t h0 = f0 - g0;
+       int32_t h1 = f1 - g1;
+       int32_t h2 = f2 - g2;
+       int32_t h3 = f3 - g3;
+       int32_t h4 = f4 - g4;
+       int32_t h5 = f5 - g5;
+       int32_t h6 = f6 - g6;
+       int32_t h7 = f7 - g7;
+       int32_t h8 = f8 - g8;
+       int32_t h9 = f9 - g9;
+       h[0] = h0;
+       h[1] = h1;
+       h[2] = h2;
+       h[3] = h3;
+       h[4] = h4;
+       h[5] = h5;
+       h[6] = h6;
+       h[7] = h7;
+       h[8] = h8;
+       h[9] = h9;
+}
diff --git a/crypto/ref10/fe_tobytes.c b/crypto/ref10/fe_tobytes.c
new file mode 100644 (file)
index 0000000..8548383
--- /dev/null
@@ -0,0 +1,118 @@
+#include <stdint.h>
+
+/*
+Preconditions:
+  |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
+
+Write p=2^255-19; q=floor(h/p).
+Basic claim: q = floor(2^(-255)(h + 19 2^(-25)h9 + 2^(-1))).
+
+Proof:
+  Have |h|<=p so |q|<=1 so |19^2 2^(-255) q|<1/4.
+  Also have |h-2^230 h9|<2^230 so |19 2^(-255)(h-2^230 h9)|<1/4.
+
+  Write y=2^(-1)-19^2 2^(-255)q-19 2^(-255)(h-2^230 h9).
+  Then 0<y<1.
+
+  Write r=h-pq.
+  Have 0<=r<=p-1=2^255-20.
+  Thus 0<=r+19(2^-255)r<r+19(2^-255)2^255<=2^255-1.
+
+  Write x=r+19(2^-255)r+y.
+  Then 0<x<2^255 so floor(2^(-255)x) = 0 so floor(q+2^(-255)x) = q.
+
+  Have q+2^(-255)x = 2^(-255)(h + 19 2^(-25) h9 + 2^(-1))
+  so floor(2^(-255)(h + 19 2^(-25) h9 + 2^(-1))) = q.
+*/
+
+void fe_tobytes(unsigned char *s, int32_t h[10]) {
+       int32_t h0 = h[0];
+       int32_t h1 = h[1];
+       int32_t h2 = h[2];
+       int32_t h3 = h[3];
+       int32_t h4 = h[4];
+       int32_t h5 = h[5];
+       int32_t h6 = h[6];
+       int32_t h7 = h[7];
+       int32_t h8 = h[8];
+       int32_t h9 = h[9];
+       int32_t q;
+       int32_t carry0;
+       int32_t carry1;
+       int32_t carry2;
+       int32_t carry3;
+       int32_t carry4;
+       int32_t carry5;
+       int32_t carry6;
+       int32_t carry7;
+       int32_t carry8;
+       int32_t carry9;
+
+       q = (19 * h9 + (((int32_t) 1) << 24)) >> 25;
+       q = (h0 + q) >> 26;
+       q = (h1 + q) >> 25;
+       q = (h2 + q) >> 26;
+       q = (h3 + q) >> 25;
+       q = (h4 + q) >> 26;
+       q = (h5 + q) >> 25;
+       q = (h6 + q) >> 26;
+       q = (h7 + q) >> 25;
+       q = (h8 + q) >> 26;
+       q = (h9 + q) >> 25;
+
+       /* Goal: Output h-(2^255-19)q, which is between 0 and 2^255-20. */
+       h0 += 19 * q;
+       /* Goal: Output h-2^255 q, which is between 0 and 2^255-20. */
+
+       carry0 = h0 >> 26; h1 += carry0; h0 -= carry0 << 26;
+       carry1 = h1 >> 25; h2 += carry1; h1 -= carry1 << 25;
+       carry2 = h2 >> 26; h3 += carry2; h2 -= carry2 << 26;
+       carry3 = h3 >> 25; h4 += carry3; h3 -= carry3 << 25;
+       carry4 = h4 >> 26; h5 += carry4; h4 -= carry4 << 26;
+       carry5 = h5 >> 25; h6 += carry5; h5 -= carry5 << 25;
+       carry6 = h6 >> 26; h7 += carry6; h6 -= carry6 << 26;
+       carry7 = h7 >> 25; h8 += carry7; h7 -= carry7 << 25;
+       carry8 = h8 >> 26; h9 += carry8; h8 -= carry8 << 26;
+       carry9 = h9 >> 25;               h9 -= carry9 << 25;
+       /* h10 = carry9 */
+
+       /*
+Goal: Output h0+...+2^255 h10-2^255 q, which is between 0 and 2^255-20.
+Have h0+...+2^230 h9 between 0 and 2^255-1;
+evidently 2^255 h10-2^255 q = 0.
+Goal: Output h0+...+2^230 h9.
+*/
+
+       s[0] = h0 >> 0;
+       s[1] = h0 >> 8;
+       s[2] = h0 >> 16;
+       s[3] = (h0 >> 24) | (h1 << 2);
+       s[4] = h1 >> 6;
+       s[5] = h1 >> 14;
+       s[6] = (h1 >> 22) | (h2 << 3);
+       s[7] = h2 >> 5;
+       s[8] = h2 >> 13;
+       s[9] = (h2 >> 21) | (h3 << 5);
+       s[10] = h3 >> 3;
+       s[11] = h3 >> 11;
+       s[12] = (h3 >> 19) | (h4 << 6);
+       s[13] = h4 >> 2;
+       s[14] = h4 >> 10;
+       s[15] = h4 >> 18;
+       s[16] = h5 >> 0;
+       s[17] = h5 >> 8;
+       s[18] = h5 >> 16;
+       s[19] = (h5 >> 24) | (h6 << 1);
+       s[20] = h6 >> 7;
+       s[21] = h6 >> 15;
+       s[22] = (h6 >> 23) | (h7 << 3);
+       s[23] = h7 >> 5;
+       s[24] = h7 >> 13;
+       s[25] = (h7 >> 21) | (h8 << 4);
+       s[26] = h8 >> 4;
+       s[27] = h8 >> 12;
+       s[28] = (h8 >> 20) | (h9 << 6);
+       s[29] = h9 >> 2;
+       s[30] = h9 >> 10;
+       s[31] = h9 >> 18;
+}
diff --git a/crypto/ref10/scalarmult.c b/crypto/ref10/scalarmult.c
new file mode 100644 (file)
index 0000000..a6bc632
--- /dev/null
@@ -0,0 +1,65 @@
+#include <stdint.h>
+#include "fe.h"
+
+int x25519(unsigned char *q, const unsigned char *n, const unsigned
+               char *p) {
+       unsigned char e[32];
+       unsigned int i;
+       int32_t x1[10];
+       int32_t x2[10];
+       int32_t z2[10];
+       int32_t x3[10];
+       int32_t z3[10];
+       int32_t tmp0[10];
+       int32_t tmp1[10];
+       int pos;
+       unsigned int swap;
+       unsigned int b;
+
+       for (i = 0;i < 32;++i) e[i] = n[i];
+       e[0] &= 248;
+       e[31] &= 127;
+       e[31] |= 64;
+       fe_frombytes(x1,p);
+       fe_1(x2);
+       fe_0(z2);
+       fe_copy(x3,x1);
+       fe_1(z3);
+
+       swap = 0;
+       for (pos = 254;pos >= 0;--pos) {
+               b = e[pos / 8] >> (pos & 7);
+               b &= 1;
+               swap ^= b;
+               fe_cswap(x2,x3,swap);
+               fe_cswap(z2,z3,swap);
+               swap = b;
+
+               fe_sub(tmp0,x3,z3); /* qhasm: D = X3-Z3 */
+               fe_sub(tmp1,x2,z2); /* qhasm: B = X2-Z2 */
+               fe_add(x2,x2,z2); /* qhasm: A = X2+Z2 */
+               fe_add(z2,x3,z3); /* qhasm: C = X3+Z3 */
+               fe_mul(z3,tmp0,x2); /* qhasm: DA = D*A */
+               fe_mul(z2,z2,tmp1); /* qhasm: CB = C*B */
+               fe_sq(tmp0,tmp1); /* qhasm: BB = B^2 */
+               fe_sq(tmp1,x2); /* qhasm: AA = A^2 */
+               fe_add(x3,z3,z2); /* qhasm: t0 = DA+CB */
+               /* qhasm: assign x3 to t0 */
+               fe_sub(z2,z3,z2); /* qhasm: t1 = DA-CB */
+               fe_mul(x2,tmp1,tmp0); /* qhasm: X4 = AA*BB */
+               fe_sub(tmp1,tmp1,tmp0); /* qhasm: E = AA-BB */
+               fe_sq(z2,z2); /* qhasm: t2 = t1^2 */
+               fe_mul121666(z3,tmp1); /* qhasm: t3 = a24*E */
+               fe_sq(x3,x3); /* qhasm: X5 = t0^2 */
+               fe_add(tmp0,tmp0,z3); /* qhasm: t4 = BB+t3 */
+               fe_mul(z3,x1,z2); /* qhasm: Z5 = X1*t2 */
+               fe_mul(z2,tmp1,tmp0); /* qhasm: Z4 = E*t4 */
+       }
+       fe_cswap(x2,x3,swap);
+       fe_cswap(z2,z3,swap);
+
+       fe_invert(z2,z2);
+       fe_mul(x2,x2,z2);
+       fe_tobytes(q,x2);
+       return 0;
+}
diff --git a/crypto/tlse.c b/crypto/tlse.c
new file mode 100644 (file)
index 0000000..5f5f047
--- /dev/null
@@ -0,0 +1,5705 @@
+#define _POSIX_C_SOURCE 200809L
+
+#include <fcntl.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <time.h>
+
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <unistd.h>
+
+#include <errno.h>
+
+#include "tomcrypt.h"
+
+#define mp_init(a)                           ltc_mp.init(a)
+#define mp_init_multi                        ltc_init_multi
+#define mp_clear(a)                          ltc_mp.deinit(a)
+#define mp_clear_multi                       ltc_deinit_multi
+#define mp_count_bits(a)                     ltc_mp.count_bits(a)
+#define mp_read_radix(a, b, c)               ltc_mp.read_radix(a, b, c)
+#define mp_unsigned_bin_size(a)              ltc_mp.unsigned_size(a)
+#define mp_to_unsigned_bin(a, b)             ltc_mp.unsigned_write(a, b)
+#define mp_read_unsigned_bin(a, b, c)        ltc_mp.unsigned_read(a, b, c)
+#define mp_exptmod(a, b, c, d)               ltc_mp.exptmod(a, b, c, d)
+#define mp_add(a, b, c)                      ltc_mp.add(a, b, c)
+#define mp_mul(a, b, c)                      ltc_mp.mul(a, b, c)
+#define mp_cmp(a, b)                         ltc_mp.compare(a, b)
+#define mp_cmp_d(a, b)                       ltc_mp.compare_d(a, b)
+#define mp_sqr(a, b)                         ltc_mp.sqr(a, b)
+#define mp_mod(a, b, c)                      ltc_mp.mpdiv(a, b, NULL, c)
+#define mp_sub(a, b, c)                      ltc_mp.sub(a, b, c)
+#define mp_set(a, b)                         ltc_mp.set_int(a, b)
+
+#if (CRYPT <= 0x0117)
+#define LTC_PKCS_1_EMSA LTC_LTC_PKCS_1_EMSA
+#define LTC_PKCS_1_V1_5 LTC_LTC_PKCS_1_V1_5
+#define LTC_PKCS_1_PSS LTC_LTC_PKCS_1_PSS
+#endif
+
+#include "tlse.h"
+#include "chacha.h"
+#include "buffer.h"
+
+#define TLS_DH_DEFAULT_P            "87A8E61DB4B6663CFFBBD19C651959998CEEF608660DD0F25D2CEED4435E3B00E00DF8F1D61957D4FAF7DF4561B2AA3016C3D91134096FAA3BF4296D830E9A7C209E0C6497517ABD5A8A9D306BCF67ED91F9E6725B4758C022E0B1EF4275BF7B6C5BFC11D45F9088B941F54EB1E59BB8BC39A0BF12307F5C4FDB70C581B23F76B63ACAE1CAA6B7902D52526735488A0EF13C6D9A51BFA4AB3AD8347796524D8EF6A167B5A41825D967E144E5140564251CCACB83E6B486F6B3CA3F7971506026C0B857F689962856DED4010ABD0BE621C3A3960A54E710C375F26375D7014103A4B54330C198AF126116D2276E11715F693877FAD7EF09CADB094AE91E1A1597"
+#define TLS_DH_DEFAULT_G            "3FB32C9B73134D0B2E77506660EDBD484CA7B18F21EF205407F4793A1A0BA12510DBC15077BE463FFF4FED4AAC0BB555BE3A6C1B0C6B47B1BC3773BF7E8C6F62901228F8C28CBB18A55AE31341000A650196F931C77A57F2DDF463E5E9EC144B777DE62AAAB8A8628AC376D282D6ED3864E67982428EBC831D14348F6F2F9193B5045AF2767164E1DFC967C1FB3F2E55A4BD1BFFE83B9C80D052B985D182EA0ADB2A3B7313D3FE14C8484B1E052588B9B7D2BBD2DF016199ECD06E1557CD0915B3353BBB64E0EC377FD028370DF92B52C7891428CDC67EB6184B523D1DB246C32F63078490F00EF8D647D148D47954515E2327CFEF98C582664B4C0F6CC41659"
+#define TLS_DHE_KEY_SIZE          2048
+
+#ifndef htonll
+#define htonll(x) ((1==htonl(1)) ? (x) : ((uint64_t)htonl((x) & 0xFFFFFFFF) << 32) | htonl((x) >> 32))
+#endif
+
+#ifndef ntohll
+#define ntohll(x) ((1==ntohl(1)) ? (x) : ((uint64_t)ntohl((x) & 0xFFFFFFFF) << 32) | ntohl((x) >> 32))
+#endif
+
+#define CHECK_HANDSHAKE_STATE(context, n, limit)  { if (context->hs_messages[n] >= limit) { DEBUG_PRINT("* UNEXPECTED MESSAGE (%i)\n", (int)n); payload_res = TLS_UNEXPECTED_MESSAGE; break; } context->hs_messages[n]++; }
+
+typedef enum {
+       KEA_dhe_dss,
+       KEA_dhe_rsa,
+       KEA_dh_anon,
+       KEA_rsa,
+       KEA_dh_dss,
+       KEA_dh_rsa,
+       KEA_ec_diffie_hellman
+} KeyExchangeAlgorithm;
+
+typedef enum {
+       rsa_sign = 1,
+       dss_sign = 2,
+       rsa_fixed_dh = 3,
+       dss_fixed_dh = 4,
+       rsa_ephemeral_dh_RESERVED = 5,
+       dss_ephemeral_dh_RESERVED = 6,
+       fortezza_dms_RESERVED = 20,
+       ecdsa_sign = 64,
+       rsa_fixed_ecdh = 65,
+       ecdsa_fixed_ecdh = 66
+} TLSClientCertificateType;
+
+typedef enum {
+       none = 0,
+       md5 = 1,
+       sha1 = 2,
+       sha224 = 3,
+       sha256 = 4,
+       sha384 = 5,
+       sha512 = 6,
+       _md5_sha1 = 255
+} TLSHashAlgorithm;
+
+typedef enum {
+       anonymous = 0,
+       rsa = 1,
+       dsa = 2,
+       ecdsa = 3
+} TLSSignatureAlgorithm;
+
+struct OID_chain {
+       void *top;
+       unsigned char *oid;
+};
+
+typedef ssize_t (*tls_recv_func)(int sockfd, void *buf, size_t len,
+                                int flags);
+typedef ssize_t (*tls_send_func)(int sockfd, const void *buf, size_t len,
+                                int flags);
+
+static const unsigned int version_id[] = { 1, 1, 1, 0 };
+static const unsigned int pk_id[] = { 1, 1, 7, 0 };
+static const unsigned int serial_id[] = { 1, 1, 2, 1, 0 };
+static const unsigned int issurer_id[] = { 1, 1, 4, 0 };
+static const unsigned int owner_id[] = { 1, 1, 6, 0 };
+static const unsigned int validity_id[] = { 1, 1, 5, 0 };
+static const unsigned int algorithm_id[] = { 1, 1, 3, 0 };
+static const unsigned int sign_id[] = { 1, 3, 2, 1, 0 };
+static const unsigned int sign_id2[] = { 1, 3, 2, 2, 0 };
+static const unsigned int priv_id[] = { 1, 4, 0 };
+static const unsigned int priv_der_id[] = { 1, 3, 1, 0 };
+static const unsigned int ecc_priv_id[] = { 1, 2, 0 };
+
+static const unsigned char country_oid[] = { 0x55, 0x04, 0x06, 0x00 };
+static const unsigned char state_oid[] = { 0x55, 0x04, 0x08, 0x00 };
+static const unsigned char location_oid[] = { 0x55, 0x04, 0x07, 0x00 };
+static const unsigned char entity_oid[] = { 0x55, 0x04, 0x0A, 0x00 };
+static const unsigned char subject_oid[] = { 0x55, 0x04, 0x03, 0x00 };
+static const unsigned char san_oid[] = { 0x55, 0x1D, 0x11, 0x00 };
+static const unsigned char ocsp_oid[] =
+    { 0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x00 };
+
+static const unsigned char TLS_RSA_SIGN_RSA_OID[] =
+    { 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01, 0x00 };
+static const unsigned char TLS_RSA_SIGN_MD5_OID[] =
+    { 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x04, 0x00 };
+static const unsigned char TLS_RSA_SIGN_SHA1_OID[] =
+    { 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x05, 0x00 };
+static const unsigned char TLS_RSA_SIGN_SHA256_OID[] =
+    { 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0B, 0x00 };
+static const unsigned char TLS_RSA_SIGN_SHA384_OID[] =
+    { 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0C, 0x00 };
+static const unsigned char TLS_RSA_SIGN_SHA512_OID[] =
+    { 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0D, 0x00 };
+
+#if 0
+static const unsigned char TLS_ECDSA_SIGN_SHA1_OID[] = {0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04, 0x01, 0x05, 0x00, 0x00};
+static const unsigned char TLS_ECDSA_SIGN_SHA224_OID[] = {0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04, 0x03, 0x01, 0x05, 0x00, 0x00};
+static const unsigned char TLS_ECDSA_SIGN_SHA256_OID[] = {0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04, 0x03, 0x02, 0x05, 0x00, 0x00};
+static const unsigned char TLS_ECDSA_SIGN_SHA384_OID[] = {0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04, 0x03, 0x03, 0x05, 0x00, 0x00};
+static const unsigned char TLS_ECDSA_SIGN_SHA512_OID[] = {0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04, 0x03, 0x04, 0x05, 0x00, 0x00};
+#endif
+
+static const unsigned char TLS_EC_PUBLIC_KEY_OID[] =
+    { 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01, 0x00 };
+
+static const unsigned char TLS_EC_prime192v1_OID[] =
+    { 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x01, 0x00 };
+static const unsigned char TLS_EC_prime192v2_OID[] =
+    { 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x02, 0x00 };
+static const unsigned char TLS_EC_prime192v3_OID[] =
+    { 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x03, 0x00 };
+static const unsigned char TLS_EC_prime239v1_OID[] =
+    { 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x04, 0x00 };
+static const unsigned char TLS_EC_prime239v2_OID[] =
+    { 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x05, 0x00 };
+static const unsigned char TLS_EC_prime239v3_OID[] =
+    { 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x06, 0x00 };
+static const unsigned char TLS_EC_prime256v1_OID[] =
+    { 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07, 0x00 };
+
+#define TLS_EC_secp256r1_OID    TLS_EC_prime256v1_OID
+static const unsigned char TLS_EC_secp224r1_OID[] =
+    { 0x2B, 0x81, 0x04, 0x00, 0x21, 0x00 };
+static const unsigned char TLS_EC_secp384r1_OID[] =
+    { 0x2B, 0x81, 0x04, 0x00, 0x22, 0x00 };
+static const unsigned char TLS_EC_secp521r1_OID[] =
+    { 0x2B, 0x81, 0x04, 0x00, 0x23, 0x00 };
+
+int tls_random(unsigned char *key, int len);
+void tls_destroy_packet(struct TLSPacket *packet);
+struct TLSPacket *tls_build_hello(struct TLSContext *context,
+                                 int tls13_downgrade);
+
+/* not supported */
+#if 0
+static unsigned char TLS_DSA_SIGN_SHA1_OID[] = {0x2A, 0x86, 0x52, 0xCE, 0x38, 0x04, 0x03, 0x00};
+#endif
+
+static uint16_t get16(const unsigned char *buf) {
+       uint16_t res;
+
+       res = ((*buf) << 8) + (*(buf+1));
+       return res;
+}
+
+static uint32_t get24(const unsigned char *buf) {
+       uint32_t res;
+
+       res = (buf[0] << 16) + (buf[1] << 8) + buf[2];
+       return res;
+}
+
+size_t tls_queue_packet(struct TLSPacket *packet) {
+       if (!packet) {
+               return -1;
+       }
+
+       struct TLSContext *context = packet->context;
+
+       if (!context) {
+               return -1;
+       }
+
+       tls_buffer_append(&context->output_buffer, packet->buf, packet->len);
+       tls_destroy_packet(packet);
+       return context->output_buffer.len;
+}
+
+static void tls_send_change_cipher_spec(struct TLSContext *context) {
+       struct TLSPacket *packet =
+           tls_create_packet(context, TLS_CHANGE_CIPHER, context->version,
+                             64);
+       tls_packet_uint8(packet, 1);
+       tls_packet_update(packet);
+       context->local_sequence_number = 0;
+       tls_queue_packet(packet);
+       return;
+}
+
+static void tls_send_encrypted_extensions(struct TLSContext *context) {
+       struct TLSPacket *packet =
+           tls_create_packet(context, TLS_HANDSHAKE, context->version, 3);
+       tls_packet_uint8(packet, 0x08);
+
+       if (context->negotiated_alpn) {
+               int alpn_negotiated_len = strlen(context->negotiated_alpn);
+               int alpn_len = alpn_negotiated_len + 1;
+
+               tls_packet_uint24(packet, alpn_len + 8);
+               tls_packet_uint16(packet, alpn_len + 6);
+               tls_packet_uint16(packet, 0x10);
+               tls_packet_uint16(packet, alpn_len + 2);
+               tls_packet_uint16(packet, alpn_len);
+
+               tls_packet_uint8(packet, alpn_negotiated_len);
+               tls_packet_append(packet, (unsigned char *) context->
+                               negotiated_alpn, alpn_negotiated_len);
+       } else {
+               tls_packet_uint24(packet, 2);
+               tls_packet_uint16(packet, 0);
+       }
+       tls_packet_update(packet);
+       tls_queue_packet(packet);
+       return;
+}
+
+static void tls_send_done(struct TLSContext *context) {
+       struct TLSPacket *packet =
+           tls_create_packet(context, TLS_HANDSHAKE, context->version, 0);
+       tls_packet_uint8(packet, 0x0E);
+       tls_packet_uint24(packet, 0);
+       tls_packet_update(packet);
+       tls_queue_packet(packet);
+       return;
+}
+
+static void tls_send_certificate(struct TLSContext *context) {
+       int i;
+       unsigned int all_certificate_size = 0;
+       int certificates_count;
+       struct TLSCertificate **certificates;
+
+       if (context->is_server) {
+               certificates_count = context->certificates_count;
+               certificates = context->certificates;
+       } else {
+               certificates_count = context->client_certificates_count;
+               certificates = context->client_certificates;
+       }
+
+       int delta = 3;
+       if (context->tlsver == TLS_VERSION13) {
+               delta = 5;
+       }
+
+       int is_ecdsa = tls_is_ecdsa(context);
+       /* TODO can do one loop and test for ecdsa inside loop */
+       if (is_ecdsa) {
+               for (i = 0; i < certificates_count; i++) {
+                       struct TLSCertificate *cert = certificates[i];
+                       if (cert && cert->der_len && cert->ec_algorithm) {
+                               all_certificate_size += cert->der_len + delta;
+                       }
+               }
+       } else {
+               for (i = 0; i < certificates_count; i++) {
+                       struct TLSCertificate *cert = certificates[i];
+                       if (cert && cert->der_len && !cert->ec_algorithm) {
+                               all_certificate_size += cert->der_len + delta;
+                       }
+               }
+       }
+
+       for (i = 0; i < certificates_count; i++) {
+               struct TLSCertificate *cert = certificates[i];
+               if (cert && cert->der_len) {
+                       all_certificate_size += cert->der_len + delta;
+               }
+       }
+
+       if (!all_certificate_size) {
+               DEBUG_PRINT("NO CERTIFICATE SET\n");
+       }
+
+       struct TLSPacket *packet = tls_create_packet(context, TLS_HANDSHAKE,
+                       context->version, 0);
+       tls_packet_uint8(packet, 0x0B);
+
+       if (all_certificate_size) {
+               /* context */
+               if (context->tlsver == TLS_VERSION13) {
+                       tls_packet_uint24(packet, all_certificate_size + 4);
+                       tls_packet_uint8(packet, 0);
+               } else {
+                       tls_packet_uint24(packet, all_certificate_size + 3);
+               }
+
+               tls_packet_uint24(packet, all_certificate_size);
+
+               for (i = 0; i < certificates_count; i++) {
+                       struct TLSCertificate *cert = certificates[i];
+                       if (cert && cert->der_len) {
+                               /* is RSA certificate ? */
+                               if (is_ecdsa && !cert->ec_algorithm) {
+                                       continue;
+                               }
+                               /* is ECC certificate ? */
+                               if (!is_ecdsa && cert->ec_algorithm) {
+                                       continue;
+                               }
+                               /* 2 times -> one certificate */
+                               tls_packet_uint24(packet, cert->der_len);
+                               tls_packet_append(packet, cert->der_bytes,
+                                                 cert->der_len);
+                               /* extension */
+                               if (context->tlsver == TLS_VERSION13) {
+                                       tls_packet_uint16(packet, 0);
+                               }
+                       }
+               }
+       } else {
+               tls_packet_uint24(packet, all_certificate_size);
+               if (context->tlsver == TLS_VERSION13) {
+                       tls_packet_uint8(packet, 0);
+               }
+
+       }
+       tls_packet_update(packet);
+       tls_queue_packet(packet);
+       return;
+}
+
+int tls_supported_version(uint16_t ver) {
+       switch (ver) {
+               case TLS_V12:
+               case TLS_V13:
+                       break;
+               default:
+                       DEBUG_PRINT("UNSUPPORTED TLS VERSION %x\n", (int)ver);
+                       return 0;
+       }
+       return 1;
+}
+
+void tls_set_packet_length(struct TLSPacket *packet, uint32_t length) {
+       int offset = packet->payload_pos;
+       packet->buf[offset] = (length >> 16) & 0xff;
+       packet->buf[offset+1] = (length >> 8) & 0xff;
+       packet->buf[offset+2] = (length >> 0) & 0xff;
+}
+
+static void tls_init() {
+       static int loaded = 0;
+       if (loaded) {
+               return;
+       }
+
+       DEBUG_PRINT("Initializing dependencies\n");
+       loaded = 1;
+#ifdef LTM_DESC
+       ltc_mp = ltm_desc;
+#else
+#ifdef TFM_DESC
+       ltc_mp = tfm_desc;
+#endif
+#endif
+       /* TODO remove these */
+       register_hash(&md5_desc);
+       register_hash(&sha1_desc); 
+
+       register_hash(&sha256_desc);
+       register_hash(&sha384_desc);
+       register_hash(&sha512_desc);
+
+       register_prng(&sprng_desc);
+
+       register_cipher(&aes_desc);
+
+       tls_ecc_init_curves();
+}
+
+static unsigned char *decrypt_rsa(struct TLSContext *context,
+                                       const unsigned char *buffer,
+                                       unsigned int len,
+                                       unsigned int *size) {
+       *size = 0;
+       if (!len || !context || !context->private_key
+           || !context->private_key->der_bytes
+           || !context->private_key->der_len) {
+               DEBUG_PRINT("No private key set\n");
+               return NULL;
+       }
+       rsa_key key;
+       int err;
+       err = rsa_import(context->private_key->der_bytes,
+                       context->private_key->der_len, &key);
+
+       if (err) {
+               DEBUG_PRINT("Error importing RSA key (code: %i)\n", err);
+               return NULL;
+       }
+
+       unsigned char *out = malloc(len);
+       unsigned long out_size = len;
+       int hash_idx = find_hash("sha256");
+       int res = 0;
+       err = rsa_decrypt_key_ex(buffer, len, out, &out_size, (unsigned char *)
+                       "Concept", 7, hash_idx, LTC_PKCS_1_V1_5, &res, &key);
+       rsa_free(&key);
+
+       if (err || !out_size) {
+               DEBUG_PRINT("RSA DECRYPT ERROR\n");
+               free(out);
+               return NULL;
+       }
+       *size = (unsigned int) out_size;
+       return out;
+}
+
+static int verify_rsa(struct TLSContext *context, unsigned int hash_type, const
+               unsigned char *buffer, unsigned int len, const unsigned char
+               *message, unsigned long message_len) {
+       rsa_key key;
+       int err;
+
+       if (len == 0) {
+               return TLS_GENERIC_ERROR;
+       }
+
+       struct TLSCertificate **cert;
+       int count;
+
+       if (context->is_server) {
+               cert = context->client_certificates;
+               count = context->client_certificates_count;
+       } else {
+               cert = context->certificates;
+               count = context->certificates_count;
+       }
+
+       if (count == 0 || !cert) {
+               return TLS_GENERIC_ERROR;
+       }
+
+       err = rsa_import(cert[0]->der_bytes, cert[0]->der_len, &key);
+
+       if (err) {
+               DEBUG_PRINT("Error importing RSA certificate (code: %i)\n",
+                           err);
+               return TLS_GENERIC_ERROR;
+       }
+       int hash_idx = -1;
+       unsigned char hash[TLS_MAX_HASH_LEN];
+       unsigned long hash_len;
+       hash_len = (unsigned long)sizeof hash;
+
+       switch (hash_type) {
+               case md5:
+                       hash_idx = find_hash("md5");
+                       break;
+               case sha1:
+                       hash_idx = find_hash("sha1");
+                       break;
+               case sha256:
+                       hash_idx = find_hash("sha256");
+                       break;
+               case sha384:
+                       hash_idx = find_hash("sha384");
+                       break;
+               case sha512:
+                       hash_idx = find_hash("sha512");
+                       break;
+       }
+       err = hash_memory(hash_idx, message, message_len, hash, &hash_len);
+       if (hash_idx < 0 || err) {
+               DEBUG_PRINT("Unsupported hash type: %i\n", hash_type);
+               return TLS_GENERIC_ERROR;
+       }
+       int rsa_stat = 0;
+       if (context->tlsver == TLS_VERSION13) {
+               err = rsa_verify_hash_ex(buffer, len, hash, hash_len,
+                               LTC_PKCS_1_PSS, hash_idx, 0, &rsa_stat, &key);
+       } else {
+               err = rsa_verify_hash_ex(buffer, len, hash, hash_len,
+                               LTC_PKCS_1_V1_5, hash_idx, 0, &rsa_stat, &key);
+       }
+       rsa_free(&key);
+       if (err) {
+               return 0;
+       }
+       return rsa_stat;
+}
+
+static int sign_rsa(struct TLSContext *context, unsigned int hash_type, const
+               unsigned char *message, unsigned int message_len, unsigned char
+               *out, unsigned long *outlen) {
+       rsa_key key;
+       int err;
+       int hash_index = -1;
+       unsigned char hash[TLS_MAX_HASH_LEN];
+       unsigned long hash_len = 0;
+       //hash_state state;
+
+       if (!outlen || !context || !out || !context->private_key
+           || !context->private_key->der_bytes
+           || !context->private_key->der_len) {
+               DEBUG_PRINT("No private key set\n");
+               return TLS_GENERIC_ERROR;
+       }
+
+       err = rsa_import(context->private_key->der_bytes,
+                       context->private_key->der_len, &key);
+
+       if (err) {
+               DEBUG_PRINT("Error %d importing RSA certificate", err);
+               return TLS_GENERIC_ERROR;
+       }
+
+       switch (hash_type) {
+               case sha1:
+                       hash_index = find_hash("sha1");
+                       hash_len = 20;
+                       break;
+               case sha256:
+                       hash_index = find_hash("sha256");
+                       hash_len = 32;
+                       break;
+               case sha384:
+                       hash_index = find_hash("sha384");
+                       hash_len = 48;
+                       break;
+               case sha512:
+                       hash_index = find_hash("sha512");
+                       hash_len = 64;
+                       break;
+               case md5:
+               case _md5_sha1:
+                       hash_index = find_hash("md5");
+                       hash_len = 16;
+                       break;
+       }
+
+       if (hash_index < 0 || err) {
+               DEBUG_PRINT("Unsupported hash type: %i\n", hash_type);
+               return TLS_GENERIC_ERROR;
+       }
+
+       hash_memory(hash_index, message, message_len, hash, &hash_len);
+
+       if (hash_type == _md5_sha1) {
+               unsigned long hlen = 20;
+               hash_index = find_hash("sha1");
+               hash_memory(hash_index, message, message_len, hash+16, &hlen);
+               hash_len += hlen;
+       }
+
+       //err = hash_memory(hash_idx, message, message_len, hash, &hash_len);
+
+       if (context->tlsver == TLS_VERSION13) {
+               err = rsa_sign_hash_ex(hash, hash_len, out, outlen,
+                               LTC_PKCS_1_PSS, NULL, find_prng("sprng"),
+                               hash_index, hash_type == sha256 ? 32 : 48, &key);
+       } else {
+               err = rsa_sign_hash_ex(hash, hash_len, out, outlen,
+                               LTC_PKCS_1_V1_5, NULL, find_prng("sprng"),
+                               hash_index, 0, &key);
+       }
+
+       rsa_free(&key);
+       if (err) {
+               return 0;
+       }
+
+       return 1;
+}
+
+static int tls_is_point(ecc_key * key) {
+       void *prime, *b, *t1, *t2;
+       int err;
+
+       if ((err = mp_init_multi(&prime, &b, &t1, &t2, NULL)) != CRYPT_OK) {
+               return err;
+       }
+
+       /* load prime and b */
+       if ((err = mp_read_radix(prime, key->dp->prime, 16)) != CRYPT_OK) {
+               goto error;
+       }
+       if ((err = mp_read_radix(b, key->dp->B, 16)) != CRYPT_OK) {
+               goto error;
+       }
+
+       /* compute y^2 */
+       if ((err = mp_sqr(key->pubkey.y, t1)) != CRYPT_OK) {
+               goto error;
+       }
+
+       /* compute x^3 */
+       if ((err = mp_sqr(key->pubkey.x, t2)) != CRYPT_OK) {
+               goto error;
+       }
+       if ((err = mp_mod(t2, prime, t2)) != CRYPT_OK) {
+               goto error;
+       }
+       if ((err = mp_mul(key->pubkey.x, t2, t2)) != CRYPT_OK) {
+               goto error;
+       }
+
+       /* compute y^2 - x^3 */
+       if ((err = mp_sub(t1, t2, t1)) != CRYPT_OK) {
+               goto error;
+       }
+
+       /* compute y^2 - x^3 + 3x */
+       if ((err = mp_add(t1, key->pubkey.x, t1)) != CRYPT_OK) {
+               goto error;
+       }
+       if ((err = mp_add(t1, key->pubkey.x, t1)) != CRYPT_OK) {
+               goto error;
+       }
+       if ((err = mp_add(t1, key->pubkey.x, t1)) != CRYPT_OK) {
+               goto error;
+       }
+       if ((err = mp_mod(t1, prime, t1)) != CRYPT_OK) {
+               goto error;
+       }
+       while (mp_cmp_d(t1, 0) == LTC_MP_LT) {
+               if ((err = mp_add(t1, prime, t1)) != CRYPT_OK) {
+                       goto error;
+               }
+       }
+       while (mp_cmp(t1, prime) != LTC_MP_LT) {
+               if ((err = mp_sub(t1, prime, t1)) != CRYPT_OK) {
+                       goto error;
+               }
+       }
+
+       /* compare to b */
+       if (mp_cmp(t1, b) != LTC_MP_EQ) {
+               err = CRYPT_INVALID_PACKET;
+       } else {
+               err = CRYPT_OK;
+       }
+
+      error:
+       mp_clear_multi(prime, b, t1, t2, NULL);
+       return err;
+}
+
+static int tls_ecc_import_key(const unsigned char *private_key,
+                               int private_len,
+                               const unsigned char *public_key,
+                               int public_len, ecc_key *key,
+                               const ltc_ecc_set_type *dp) {
+       int err;
+
+       if (!key || !ltc_mp.name) {
+               return CRYPT_MEM;
+       }
+
+       key->type = PK_PRIVATE;
+
+       if (mp_init_multi
+           (&key->pubkey.x, &key->pubkey.y, &key->pubkey.z, &key->k,
+            NULL) != CRYPT_OK)
+               return CRYPT_MEM;
+
+       if (public_len && !public_key[0]) {
+               public_key++;
+               public_len--;
+       }
+       if ((err = mp_read_unsigned_bin(key->pubkey.x,
+                                 (unsigned char *) public_key + 1,
+                                 (public_len - 1) >> 1)) != CRYPT_OK) {
+               mp_clear_multi(key->pubkey.x, key->pubkey.y, key->pubkey.z,
+                              key->k, NULL);
+               return err;
+       }
+
+       if ((err = mp_read_unsigned_bin(key->pubkey.y,
+                                 (unsigned char *) public_key + 1 +
+                                 ((public_len - 1) >> 1),
+                                 (public_len - 1) >> 1)) != CRYPT_OK) {
+               mp_clear_multi(key->pubkey.x, key->pubkey.y, key->pubkey.z,
+                              key->k, NULL);
+               return err;
+       }
+
+       if ((err =
+            mp_read_unsigned_bin(key->k, (unsigned char *) private_key,
+                                 private_len)) != CRYPT_OK) {
+               mp_clear_multi(key->pubkey.x, key->pubkey.y, key->pubkey.z,
+                              key->k, NULL);
+               return err;
+       }
+
+       key->idx = -1;
+       key->dp = dp;
+
+       /* set z */
+       if ((err = mp_set(key->pubkey.z, 1)) != CRYPT_OK) {
+               mp_clear_multi(key->pubkey.x, key->pubkey.y, key->pubkey.z,
+                              key->k, NULL);
+               return err;
+       }
+
+       /* is it a point on the curve?  */
+       if ((err = tls_is_point(key)) != CRYPT_OK) {
+               DEBUG_PRINT("KEY IS NOT ON CURVE\n");
+               mp_clear_multi(key->pubkey.x, key->pubkey.y, key->pubkey.z,
+                              key->k, NULL);
+               return err;
+       }
+
+       /* we're good */
+       return CRYPT_OK;
+}
+
+static int sign_ecdsa(struct TLSContext *context,
+                           unsigned int hash_type,
+                           const unsigned char *message,
+                           unsigned int message_len, unsigned char *out,
+                           unsigned long *outlen) {
+       if (!outlen || !context || !out || !outlen
+           || !context->ec_private_key
+           || !context->ec_private_key->priv
+           || !context->ec_private_key->priv_len
+           || !context->ec_private_key->pk
+           || !context->ec_private_key->pk_len) {
+               DEBUG_PRINT("No private ECDSA key set\n");
+               return TLS_GENERIC_ERROR;
+       }
+
+       const struct ECCCurveParameters *curve = NULL;
+
+       switch (context->ec_private_key->ec_algorithm) {
+               case 19:
+                       curve = &secp192r1;
+                       break;
+               case 20:
+                       curve = &secp224k1;
+                       break;
+               case 21:
+                       curve = &secp224r1;
+                       break;
+               case 22:
+                       curve = &secp256k1;
+                       break;
+               case 23:
+                       curve = &secp256r1;
+                       break;
+               case 24:
+                       curve = &secp384r1;
+                       break;
+               case 25:
+                       curve = &secp521r1;
+                       break;
+               default:
+                       DEBUG_PRINT("UNSUPPORTED CURVE\n");
+       }
+
+       if (!curve) {
+               return TLS_GENERIC_ERROR;
+       }
+
+       ecc_key key;
+       int err;
+
+       ltc_ecc_set_type *dp = (ltc_ecc_set_type *)&curve->dp;
+
+       /* broken ... fix this */
+       err = tls_ecc_import_key(context->ec_private_key->priv,
+                       context->ec_private_key->priv_len,
+                       context->ec_private_key->pk,
+                       context->ec_private_key->pk_len, &key, dp);
+
+       if (err) {
+               DEBUG_PRINT("Error importing ECC certificate (code: %i)\n",
+                           (int) err);
+               return TLS_GENERIC_ERROR;
+       }
+
+       unsigned char hash[TLS_MAX_HASH_LEN];
+       unsigned long hash_len = 0;
+       int hash_index;
+
+       switch (hash_type) {
+               case sha1:
+                       hash_index = find_hash("sha1");
+                       hash_len = 20;
+                       break;
+               case sha256:
+                       hash_index = find_hash("sha256");
+                       hash_len = 32;
+                       break;
+               case sha384:
+                       hash_index = find_hash("sha384");
+                       hash_len = 48;
+                       break;
+               case sha512:
+                       hash_index = find_hash("sha512");
+                       hash_len = 64;
+                       break;
+               case md5:
+               case _md5_sha1:
+                       hash_index = find_hash("md5");
+                       hash_len = 16;
+                       break;
+       }
+
+       hash_memory(hash_index, message, message_len, hash, &hash_len);
+
+       if (hash_type == _md5_sha1) {
+               unsigned long hlen = 20;
+               hash_index = find_hash("sha1");
+               hash_memory(hash_index, message, message_len, hash+16, &hlen);
+               hash_len += hlen;
+       }
+
+       if (err) {
+               DEBUG_PRINT("Unsupported hash type: %i\n", hash_type);
+               return TLS_GENERIC_ERROR;
+       }
+       /* "Let z be the Ln leftmost bits of e, where Ln is the bit length of
+        * the group order n." */
+       if ((int)hash_len > curve->size) {
+               hash_len = curve->size;
+       }
+       err = ecc_sign_hash(hash, hash_len, out, outlen, NULL,
+                       find_prng("sprng"), &key);
+       DEBUG_DUMP_HEX_LABEL("ECC SIGNATURE", out, *outlen);
+       ecc_free(&key);
+
+       return err ? 0 : 1;
+}
+
+static void tls_send_certificate_verify(struct TLSContext *context) {
+       struct TLSPacket *packet =
+           tls_create_packet(context, TLS_HANDSHAKE, context->version, 0);
+       /* certificate verify */
+       tls_packet_uint8(packet, 0x0F);
+       tls_packet_uint24(packet, 0);
+
+       unsigned char out[TLS_MAX_RSA_KEY];
+       unsigned long out_len = TLS_MAX_RSA_KEY;
+
+       unsigned char signing_data[TLS_MAX_HASH_SIZE + 98];
+       int signing_data_len;
+
+       /* first 64 bytes to 0x20 (32) */
+       memset(signing_data, 0x20, 64);
+       /* context string 33 bytes */
+       if (context->is_server) {
+               memcpy(signing_data + 64, "TLS 1.3, server CertificateVerify",
+                               33);
+       } else {
+               memcpy(signing_data + 64, "TLS 1.3, client CertificateVerify",
+                               33);
+       }
+       /* a single 0 byte separator */
+       signing_data[97] = 0;
+       signing_data_len = 98;
+
+       signing_data_len += tls_get_hash(context, signing_data + 98);
+       DEBUG_DUMP_HEX_LABEL("verify data", signing_data, signing_data_len);
+       int hash_algorithm = sha256;
+       if (tls_is_ecdsa(context)) {
+               switch (context->ec_private_key->ec_algorithm) {
+                       case 23:
+                               /* secp256r1 + sha256 */
+                               tls_packet_uint16(packet, 0x0403);
+                               break;
+                       case 24:
+                               /* secp384r1 + sha384 */
+                               tls_packet_uint16(packet, 0x0503);
+                               hash_algorithm = sha384;
+                               break;
+                       case 25:
+                               /* secp521r1 + sha512 */
+                               tls_packet_uint16(packet, 0x0603);
+                               hash_algorithm = sha512;
+                               break;
+                       default:
+                               DEBUG_PRINT("UNSUPPORTED CURVE (SIGNING)\n");
+                               packet->broken = 1;
+                               /* TODO error */
+                               return;
+               }
+       } else {
+               tls_packet_uint16(packet, 0x0804);
+       }
+
+       int packet_size = 2;
+
+       if (tls_is_ecdsa(context)) {
+               if (sign_ecdsa(context, hash_algorithm, signing_data,
+                                       signing_data_len, out, &out_len) == 1)
+               {
+                       DEBUG_PRINT
+                           ("ECDSA signing OK! (ECDSA, length %lu)\n",
+                            out_len);
+                       tls_packet_uint16(packet, out_len);
+                       tls_packet_append(packet, out, out_len);
+                       packet_size += out_len + 2;
+               }
+       } else if (sign_rsa(context, hash_algorithm, signing_data,
+                               signing_data_len, out, &out_len) == 1) {
+               DEBUG_PRINT("RSA signing OK! (length %lu)\n", out_len);
+               tls_packet_uint16(packet, out_len);
+               tls_packet_append(packet, out, out_len);
+               packet_size += out_len + 2;
+       }
+
+       tls_set_packet_length(packet, packet_size);
+
+       tls_packet_update(packet);
+       tls_queue_packet(packet);
+       return;
+}
+
+static int tls_ecc_import_pk(const unsigned char *public_key,
+                              int public_len, ecc_key * key,
+                              const ltc_ecc_set_type * dp) {
+       int err;
+
+       if (!key || !ltc_mp.name) {
+               return CRYPT_MEM;
+       }
+
+       key->type = PK_PUBLIC;
+
+       if (mp_init_multi(&key->pubkey.x, &key->pubkey.y, &key->pubkey.z,
+                               &key->k, NULL) != CRYPT_OK) {
+               return CRYPT_MEM;
+       }
+
+       if (public_len && !public_key[0]) {
+               public_key++;
+               public_len--;
+       }
+       if ((err = mp_read_unsigned_bin(key->pubkey.x,
+                                 (unsigned char *) public_key + 1,
+                                 (public_len - 1) >> 1)) != CRYPT_OK) {
+               mp_clear_multi(key->pubkey.x, key->pubkey.y, key->pubkey.z,
+                              key->k, NULL);
+               return err;
+       }
+
+       if ((err = mp_read_unsigned_bin(key->pubkey.y,
+                                 (unsigned char *) public_key + 1 +
+                                 ((public_len - 1) >> 1),
+                                 (public_len - 1) >> 1)) != CRYPT_OK) {
+               mp_clear_multi(key->pubkey.x, key->pubkey.y, key->pubkey.z,
+                              key->k, NULL);
+               return err;
+       }
+
+       key->idx = -1;
+       key->dp = dp;
+
+       /* set z */
+       if ((err = mp_set(key->pubkey.z, 1)) != CRYPT_OK) {
+               mp_clear_multi(key->pubkey.x, key->pubkey.y, key->pubkey.z,
+                              key->k, NULL);
+               return err;
+       }
+
+       /* is it a point on the curve?  */
+       if ((err = tls_is_point(key)) != CRYPT_OK) {
+               DEBUG_PRINT("KEY IS NOT ON CURVE\n");
+               mp_clear_multi(key->pubkey.x, key->pubkey.y, key->pubkey.z,
+                              key->k, NULL);
+               return err;
+       }
+
+       /* we're good */
+       return CRYPT_OK;
+}
+
+static int tls_verify_ecdsa(struct TLSContext *context,
+                             unsigned int hash_type,
+                             const unsigned char *buffer,
+                             unsigned int len,
+                             const unsigned char *message,
+                             unsigned int message_len,
+                             const struct ECCCurveParameters *curve_hint) 
+{
+       ecc_key key;
+       int err;
+
+       if (!curve_hint) {
+               curve_hint = context->curve;
+       }
+
+       if (len == 0) {
+               return TLS_GENERIC_ERROR;
+       }
+
+       struct TLSCertificate **cert;
+       int count;
+
+       if (context->is_server) {
+               cert = context->client_certificates;
+               count = context->client_certificates_count;
+       } else {
+               cert = context->certificates;
+               count = context->certificates_count;
+       }
+
+       if (count == 0 || !cert || !cert[0] || !cert[0]->pk ||
+                       !cert[0]->pk_len) {
+               return TLS_GENERIC_ERROR;
+       }
+
+       err = tls_ecc_import_pk(cert[0]->pk, cert[0]->pk_len, &key,
+                       (ltc_ecc_set_type *)&curve_hint->dp);
+
+       if (err) {
+               DEBUG_PRINT("Error importing ECC certificate (code: %i)", err);
+               return TLS_GENERIC_ERROR;
+       }
+
+       int hash_idx = -1;
+       unsigned char hash[TLS_MAX_HASH_LEN];
+       unsigned long hash_len = 0;
+
+       switch (hash_type) {
+               case md5:
+                       hash_idx = find_hash("md5");
+                       hash_len = 16;
+                       break;
+               case sha1:
+                       hash_idx = find_hash("sha1");
+                       hash_len = 20;
+                       break;
+               case sha256:
+                       hash_idx = find_hash("sha256");
+                       hash_len = 32;
+                       break;
+               case sha384:
+                       hash_idx = find_hash("sha384");
+                       hash_len = 48;
+                       break;
+               case sha512:
+                       hash_idx = find_hash("sha512");
+                       hash_len = 64;
+                       break;
+       }
+
+       err = hash_memory(hash_idx, message, message_len, hash, &hash_len);
+
+       if (hash_idx < 0 || err) {
+               DEBUG_PRINT("Unsupported hash type: %i\n", hash_type);
+               return TLS_GENERIC_ERROR;
+       }
+
+       int ecc_stat = 0;
+       err = ecc_verify_hash(buffer, len, hash, hash_len, &ecc_stat, &key);
+       ecc_free(&key);
+       if (err) {
+               return 0;
+       }
+       return ecc_stat;
+}
+
+static void prf_helper(int hash_idx, unsigned long dlen,
+                            unsigned char *output, unsigned int outlen,
+                            const unsigned char *secret,
+                            const unsigned int secret_len,
+                            const unsigned char *label,
+                            unsigned int label_len, unsigned char *seed,
+                            unsigned int seed_len, unsigned char *seed_b,
+                            unsigned int seed_b_len) {
+       unsigned char digest_out0[TLS_MAX_HASH_LEN];
+       unsigned char digest_out1[TLS_MAX_HASH_LEN];
+       unsigned int i;
+       hmac_state hmac;
+
+       hmac_init(&hmac, hash_idx, secret, secret_len);
+       hmac_process(&hmac, label, label_len);
+
+       hmac_process(&hmac, seed, seed_len);
+       if (seed_b && seed_b_len) {
+               hmac_process(&hmac, seed_b, seed_b_len);
+       }
+       hmac_done(&hmac, digest_out0, &dlen);
+       int idx = 0;
+       while (outlen) {
+               hmac_init(&hmac, hash_idx, secret, secret_len);
+               hmac_process(&hmac, digest_out0, dlen);
+               hmac_process(&hmac, label, label_len);
+               hmac_process(&hmac, seed, seed_len);
+               if (seed_b && seed_b_len) {
+                       hmac_process(&hmac, seed_b, seed_b_len);
+               }
+               hmac_done(&hmac, digest_out1, &dlen);
+
+               unsigned int copylen = outlen;
+               if (copylen > dlen) {
+                       copylen = dlen;
+               }
+
+               for (i = 0; i < copylen; i++) {
+                       output[idx++] ^= digest_out1[i];
+                       outlen--;
+               }
+
+               if (!outlen) {
+                       break;
+               }
+
+               hmac_init(&hmac, hash_idx, secret, secret_len);
+               hmac_process(&hmac, digest_out0, dlen);
+               hmac_done(&hmac, digest_out0, &dlen);
+       }
+}
+
+static void tls_prf(struct TLSContext *context,
+                     unsigned char *output, unsigned int outlen,
+                     const unsigned char *secret,
+                     const unsigned int secret_len,
+                     const unsigned char *label, unsigned int label_len,
+                     unsigned char *seed, unsigned int seed_len,
+                     unsigned char *seed_b, unsigned int seed_b_len) {
+       if (!secret || !secret_len) {
+               DEBUG_PRINT("NULL SECRET\n");
+               return;
+       }
+
+       /* TODO I don't think this is right, wouldn't use md5 for tls v1.3 */
+       if (context->version != TLS_V12) {
+               int md5_hash_idx = find_hash("md5");
+               int sha1_hash_idx = find_hash("sha1");
+               int half_secret = (secret_len + 1) / 2;
+
+               memset(output, 0, outlen);
+               prf_helper(md5_hash_idx, 16, output, outlen, secret,
+                               half_secret, label, label_len, seed, seed_len,
+                               seed_b, seed_b_len);
+               prf_helper(sha1_hash_idx, 20, output, outlen, secret +
+                               (secret_len - half_secret), secret_len -
+                               half_secret, label, label_len, seed, seed_len,
+                               seed_b, seed_b_len);
+       } else {
+               /* sha256_hmac */
+               unsigned char digest_out0[TLS_MAX_HASH_LEN];
+               unsigned char digest_out1[TLS_MAX_HASH_LEN];
+               unsigned long dlen = 32;
+               int hash_idx;
+               unsigned int mac_length = tls_mac_length(context);
+
+               if (mac_length == TLS_SHA384_MAC_SIZE) {
+                       hash_idx = find_hash("sha384");
+                       dlen = mac_length;
+               } else {
+                       hash_idx = find_hash("sha256");
+               }
+
+               unsigned int i;
+
+               hmac_state hmac;
+               hmac_init(&hmac, hash_idx, secret, secret_len);
+               hmac_process(&hmac, label, label_len);
+               hmac_process(&hmac, seed, seed_len);
+               if (seed_b && seed_b_len) {
+                       hmac_process(&hmac, seed_b, seed_b_len);
+               }
+               hmac_done(&hmac, digest_out0, &dlen);
+
+               int idx = 0;
+               while (outlen) {
+                       hmac_init(&hmac, hash_idx, secret, secret_len);
+                       hmac_process(&hmac, digest_out0, dlen);
+                       hmac_process(&hmac, label, label_len);
+                       hmac_process(&hmac, seed, seed_len);
+                       if (seed_b && seed_b_len) {
+                               hmac_process(&hmac, seed_b, seed_b_len);
+                       }
+                       hmac_done(&hmac, digest_out1, &dlen);
+
+                       unsigned int copylen = outlen;
+                       if (copylen > dlen) {
+                               copylen = (unsigned int) dlen;
+                       }
+
+                       for (i = 0; i < copylen; i++) {
+                               output[idx++] = digest_out1[i];
+                               outlen--;
+                       }
+
+                       if (!outlen) {
+                               break;
+                       }
+
+                       hmac_init(&hmac, hash_idx, secret, secret_len);
+                       hmac_process(&hmac, digest_out0, dlen);
+                       hmac_done(&hmac, digest_out0, &dlen);
+               }
+       }
+}
+
+static void tls_send_finished(struct TLSContext *context) {
+       struct TLSPacket *packet =
+           tls_create_packet(context, TLS_HANDSHAKE, context->version,
+                             TLS_MIN_FINISHED_OPAQUE_LEN + 64);
+       tls_packet_uint8(packet, 0x14);
+
+       if (context->tlsver == TLS_VERSION13) {
+               tls_packet_uint24(packet, tls_mac_length(context));
+       } else {
+               tls_packet_uint24(packet, TLS_MIN_FINISHED_OPAQUE_LEN);
+       }
+
+       /* verify */
+       unsigned char hash[TLS_MAX_HASH_SIZE];
+       unsigned long out_size = TLS_MIN_FINISHED_OPAQUE_LEN;
+       unsigned char out[TLS_MAX_HASH_SIZE];
+       unsigned int hash_len;
+
+       int context_is_v13 = 0;
+
+       if (packet->context->tlsver == TLS_VERSION13) {
+               context_is_v13 = 1;
+       }
+
+       /* server verifies client's message */
+       if (context->is_server) {
+               if (context_is_v13) {
+                       hash_len = tls_get_hash(context, hash);
+                       if (!context->finished_key || !hash_len) {
+                               DEBUG_PRINT
+                                   ("NO FINISHED KEY COMPUTED OR NO HANDSHAKE HASH\n");
+
+                               /* TODO probably need to terminate */
+                               tls_destroy_packet(packet);
+                               return;
+                       }
+
+                       DEBUG_DUMP_HEX_LABEL("HS HASH", hash, hash_len);
+                       DEBUG_DUMP_HEX_LABEL("HS FINISH",
+                                            context->finished_key,
+                                            hash_len);
+
+                       out_size = hash_len;
+                       hmac_state hmac;
+                       hmac_init(&hmac, tls_get_hash_idx(context),
+                                       context->finished_key, hash_len);
+                       hmac_process(&hmac, hash, hash_len);
+                       hmac_done(&hmac, out, &out_size);
+               } else {
+                       hash_len = tls_done_hash(context, hash);
+                       tls_prf(context, out,
+                                        TLS_MIN_FINISHED_OPAQUE_LEN,
+                                        context->master_key,
+                                        context->master_key_len,
+                                        (unsigned char *)
+                                        "server finished", 15, hash,
+                                        hash_len, NULL, 0);
+                       tls_destroy_hash(context);
+               }
+       } else {
+               /* client */
+               hash_len = tls_get_hash(context, hash);
+               tls_prf(context, out, TLS_MIN_FINISHED_OPAQUE_LEN,
+                                context->master_key,
+                                context->master_key_len,
+                                (unsigned char *) "client finished", 15,
+                                hash, hash_len, NULL, 0);
+       }
+
+       tls_packet_append(packet, out, out_size);
+       tls_packet_update(packet);
+       DEBUG_DUMP_HEX_LABEL("VERIFY DATA", out, out_size);
+       tls_queue_packet(packet);
+       return;
+}
+
+static int tls_key_length(struct TLSContext *context) {
+       switch (context->cipher) {
+               case TLS_RSA_WITH_AES_128_CBC_SHA:
+               case TLS_RSA_WITH_AES_128_CBC_SHA256:
+               case TLS_RSA_WITH_AES_128_GCM_SHA256:
+               case TLS_DHE_RSA_WITH_AES_128_CBC_SHA:
+               case TLS_DHE_RSA_WITH_AES_128_CBC_SHA256:
+               case TLS_DHE_RSA_WITH_AES_128_GCM_SHA256:
+               case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA:
+               case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256:
+               case TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256:
+               case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA:
+               case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256:
+               case TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:
+               case TLS_AES_128_GCM_SHA256:
+                       return 16;
+               case TLS_RSA_WITH_AES_256_CBC_SHA:
+               case TLS_RSA_WITH_AES_256_CBC_SHA256:
+               case TLS_RSA_WITH_AES_256_GCM_SHA384:
+               case TLS_DHE_RSA_WITH_AES_256_CBC_SHA:
+               case TLS_DHE_RSA_WITH_AES_256_CBC_SHA256:
+               case TLS_DHE_RSA_WITH_AES_256_GCM_SHA384:
+               case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA:
+               case TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384:
+               case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA:
+               case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384:
+               case TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:
+               case TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
+               case TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256:
+               case TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
+               case TLS_AES_256_GCM_SHA384:
+               case TLS_CHACHA20_POLY1305_SHA256:
+                       return 32;
+       }
+       return 0;
+}
+
+/* 0 is none, 1 is GCM?, 2 is chacha */
+int tls_is_aead(struct TLSContext *context) {
+       switch (context->cipher) {
+               case TLS_RSA_WITH_AES_128_GCM_SHA256:
+               case TLS_RSA_WITH_AES_256_GCM_SHA384:
+               case TLS_DHE_RSA_WITH_AES_128_GCM_SHA256:
+               case TLS_DHE_RSA_WITH_AES_256_GCM_SHA384:
+               case TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256:
+               case TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384:
+               case TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:
+               case TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:
+               case TLS_AES_128_GCM_SHA256:
+               case TLS_AES_256_GCM_SHA384:
+                       return 1;
+               case TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
+               case TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256:
+               case TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
+               case TLS_CHACHA20_POLY1305_SHA256:
+                       return 2;
+       }
+       return 0;
+}
+
+int tls_mac_length(struct TLSContext *context) {
+       switch (context->cipher) {
+               case TLS_RSA_WITH_AES_128_CBC_SHA:
+               case TLS_RSA_WITH_AES_256_CBC_SHA:
+               case TLS_DHE_RSA_WITH_AES_128_CBC_SHA:
+               case TLS_DHE_RSA_WITH_AES_256_CBC_SHA:
+               case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA:
+               case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA:
+               case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA:
+               case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA:
+                       return TLS_SHA1_MAC_SIZE;
+               case TLS_RSA_WITH_AES_128_CBC_SHA256:
+               case TLS_RSA_WITH_AES_256_CBC_SHA256:
+               case TLS_RSA_WITH_AES_128_GCM_SHA256:
+               case TLS_DHE_RSA_WITH_AES_128_CBC_SHA256:
+               case TLS_DHE_RSA_WITH_AES_256_CBC_SHA256:
+               case TLS_DHE_RSA_WITH_AES_128_GCM_SHA256:
+               case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256:
+               case TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256:
+               case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256:
+               case TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:
+               case TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
+               case TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256:
+               case TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
+               case TLS_AES_128_GCM_SHA256:
+               case TLS_CHACHA20_POLY1305_SHA256:
+               case TLS_AES_128_CCM_SHA256:
+               case TLS_AES_128_CCM_8_SHA256:
+                       return TLS_SHA256_MAC_SIZE;
+               case TLS_RSA_WITH_AES_256_GCM_SHA384:
+               case TLS_DHE_RSA_WITH_AES_256_GCM_SHA384:
+               case TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384:
+               case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384:
+               case TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:
+               case TLS_AES_256_GCM_SHA384:
+                       return TLS_SHA384_MAC_SIZE;
+       }
+       return 0;
+}
+
+int _private_tls13_key(struct TLSContext *context, int handshake) {
+       int key_length = tls_key_length(context);
+       int mac_length = tls_mac_length(context);
+
+       if (!context->premaster_key || !context->premaster_key_len) {
+               return 0;
+       }
+
+       if (!key_length || !mac_length) {
+               DEBUG_PRINT
+                   ("KEY EXPANSION FAILED, KEY LENGTH: %i, MAC LENGTH: %i\n",
+                    key_length, mac_length);
+               return 0;
+       }
+
+       unsigned char *clientkey = NULL;
+       unsigned char *serverkey = NULL;
+       unsigned char *clientiv = NULL;
+       unsigned char *serveriv = NULL;
+       int is_aead = tls_is_aead(context);
+
+       unsigned char local_keybuffer[TLS_V13_MAX_KEY_SIZE];
+       unsigned char local_ivbuffer[TLS_V13_MAX_IV_SIZE];
+       unsigned char remote_keybuffer[TLS_V13_MAX_KEY_SIZE];
+       unsigned char remote_ivbuffer[TLS_V13_MAX_IV_SIZE];
+
+       unsigned char prk[TLS_MAX_HASH_SIZE];
+       unsigned char hash[TLS_MAX_HASH_SIZE];
+       static unsigned char earlysecret[TLS_MAX_HASH_SIZE];
+
+       const char *server_key = "s ap traffic";
+       const char *client_key = "c ap traffic";
+       if (handshake) {
+               server_key = "s hs traffic";
+               client_key = "c hs traffic";
+       }
+
+       unsigned char salt[TLS_MAX_HASH_SIZE];
+
+       hash_state md;
+       /* TODO what is the point of this ? */
+       if (mac_length == TLS_SHA384_MAC_SIZE) {
+               sha384_init(&md);
+               sha384_done(&md, hash);
+       } else {
+               sha256_init(&md);
+               sha256_done(&md, hash);
+       }
+       /* extract secret "early" */
+       if (context->master_key && context->master_key_len && !handshake) {
+               DEBUG_DUMP_HEX_LABEL("USING PREVIOUS SECRET",
+                                    context->master_key,
+                                    context->master_key_len);
+               tls_hkdf_expand_label(mac_length, salt, mac_length,
+                               context->master_key, context->master_key_len,
+                               "derived", 7, hash, mac_length);
+               DEBUG_DUMP_HEX_LABEL("salt", salt, mac_length);
+               tls_hkdf_extract(mac_length, prk, mac_length, salt, mac_length,
+                               earlysecret, mac_length);
+       } else {
+               tls_hkdf_extract(mac_length, prk, mac_length, NULL, 0,
+                               earlysecret, mac_length);
+               /* derive secret for handshake "tls13 derived": */
+               DEBUG_DUMP_HEX_LABEL("null hash", hash, mac_length);
+               tls_hkdf_expand_label(mac_length, salt, mac_length, prk,
+                               mac_length, "derived", 7, hash, mac_length);
+               /* extract secret "handshake": */
+               DEBUG_DUMP_HEX_LABEL("salt", salt, mac_length);
+               tls_hkdf_extract(mac_length, prk, mac_length,
+                                         salt, mac_length,
+                                         context->premaster_key,
+                                         context->premaster_key_len);
+       }
+
+       if (!is_aead) {
+               DEBUG_PRINT("KEY EXPANSION FAILED, NON AEAD CIPHER\n");
+               return 0;
+       }
+
+       unsigned char secret[TLS_MAX_MAC_SIZE];
+       unsigned char hs_secret[TLS_MAX_HASH_SIZE];
+
+       int hash_size;
+       if (handshake) {
+               hash_size = tls_get_hash(context, hash);
+       } else {
+               hash_size = tls_done_hash(context, hash);
+       }
+
+       DEBUG_DUMP_HEX_LABEL("messages hash", hash, hash_size);
+
+       if (context->is_server) {
+               tls_hkdf_expand_label(mac_length, hs_secret, mac_length, prk,
+                               mac_length, server_key, 12, context->
+                               server_finished_hash ?  context->
+                               server_finished_hash : hash, hash_size);
+               DEBUG_DUMP_HEX_LABEL(server_key, hs_secret, mac_length);
+               serverkey = local_keybuffer;
+               serveriv = local_ivbuffer;
+               clientkey = remote_keybuffer;
+               clientiv = remote_ivbuffer;
+       } else {
+               tls_hkdf_expand_label(mac_length, hs_secret,
+                                              mac_length, prk, mac_length,
+                                              client_key, 12,
+                                              context->
+                                              server_finished_hash ?
+                                              context->
+                                              server_finished_hash : hash,
+                                              hash_size);
+               serverkey = remote_keybuffer;
+               serveriv = remote_ivbuffer;
+               clientkey = local_keybuffer;
+               clientiv = local_ivbuffer;
+       }
+
+       int iv_length = TLS_13_AES_GCM_IV_LENGTH;
+       if (is_aead == 2) {
+               iv_length = TLS_CHACHA20_IV_LENGTH;
+       }
+
+       tls_hkdf_expand_label(mac_length, local_keybuffer, key_length,
+                       hs_secret, mac_length, "key", 3, NULL, 0);
+       tls_hkdf_expand_label(mac_length, local_ivbuffer, iv_length, hs_secret,
+                       mac_length, "iv", 2, NULL, 0);
+
+       tls_hkdf_expand_label(mac_length, secret,
+                       mac_length, prk, mac_length,
+                       context->is_server ? client_key : server_key,
+                       12,
+                       context->server_finished_hash ?
+                       context->server_finished_hash :
+                       hash,
+                       hash_size);
+
+       tls_hkdf_expand_label(mac_length, remote_keybuffer, key_length, secret,
+                       mac_length, "key", 3, NULL, 0);
+       tls_hkdf_expand_label(mac_length, remote_ivbuffer, iv_length, secret,
+                       mac_length, "iv", 2, NULL, 0);
+
+       DEBUG_DUMP_HEX_LABEL("CLIENT KEY", clientkey, key_length);
+       DEBUG_DUMP_HEX_LABEL("CLIENT IV", clientiv, iv_length);
+       DEBUG_DUMP_HEX_LABEL("SERVER KEY", serverkey, key_length);
+       DEBUG_DUMP_HEX_LABEL("SERVER IV", serveriv, iv_length);
+       free(context->finished_key);
+       free(context->remote_finished_key);
+
+       if (handshake) {
+               context->finished_key = malloc(mac_length);
+               context->remote_finished_key = malloc(mac_length);
+
+               if (context->finished_key) {
+                       tls_hkdf_expand_label(mac_length,
+                                       context->finished_key, mac_length,
+                                       hs_secret, mac_length, "finished", 8,
+                                       NULL, 0);
+                       DEBUG_DUMP_HEX_LABEL("FINISHED", context->finished_key,
+                                       mac_length);
+               }
+
+               if (context->remote_finished_key) {
+                       tls_hkdf_expand_label(mac_length,
+                                       context->remote_finished_key,
+                                       mac_length, secret, mac_length,
+                                       "finished", 8, NULL, 0);
+                       DEBUG_DUMP_HEX_LABEL("FINISHED", context->finished_key,
+                                       mac_length);
+               }
+       } else {
+               context->finished_key = NULL;
+               context->remote_finished_key = NULL;
+               free(context->server_finished_hash);
+               context->server_finished_hash = NULL;
+       }
+
+       if (context->is_server) {
+               if (is_aead == 2) {
+                       memcpy(context->crypto.ctx_remote_mac.remote_nonce,
+                                       clientiv, iv_length);
+                       memcpy(context->crypto.ctx_local_mac.local_nonce,
+                                       serveriv, iv_length);
+               } else if (is_aead) {
+                       memcpy(context->crypto.ctx_remote_mac.remote_iv,
+                                       clientiv, iv_length);
+                       memcpy(context->crypto.ctx_local_mac.local_iv,
+                                       serveriv, iv_length);
+               }
+               if (tls_crypto_create(context, key_length,
+                                       serverkey, serveriv, clientkey,
+                                       clientiv)) {
+                       return 0;
+               }
+       } else {
+               if (is_aead == 2) {
+                       memcpy(context->crypto.ctx_local_mac.local_nonce,
+                              clientiv, iv_length);
+                       memcpy(context->crypto.ctx_remote_mac.remote_nonce,
+                              serveriv, iv_length);
+               } else if (is_aead) {
+                       memcpy(context->crypto.ctx_local_mac.local_iv,
+                                       clientiv, iv_length);
+                       memcpy(context->crypto.ctx_remote_mac.remote_iv,
+                                       serveriv, iv_length);
+               }
+
+               if (tls_crypto_create(context, key_length,
+                                       clientkey, clientiv, serverkey,
+                                       serveriv)) {
+                       return 0;
+               }
+       }
+
+       context->crypto.created = 1 + is_aead;
+
+       free(context->master_key);
+       context->master_key = malloc(mac_length);
+       if (context->master_key) {
+               memcpy(context->master_key, prk, mac_length);
+               context->master_key_len = mac_length;
+       }
+       context->local_sequence_number = 0;
+       context->remote_sequence_number = 0;
+
+       /*
+        * extract client_mac_key(mac_key_length)
+        * extract server_mac_key(mac_key_length)
+        * extract client_key(enc_key_length)
+        * extract server_key(enc_key_length)
+        * extract client_iv(fixed_iv_lengh)
+        * extract server_iv(fixed_iv_length)
+        */
+       return 1;
+}
+
+static int tls_expand_key(struct TLSContext *context) {
+       unsigned char key[TLS_MAX_KEY_EXPANSION_SIZE];
+       if (context->tlsver == TLS_VERSION13) {
+               return 0;
+       }
+
+       if (!context->master_key || !context->master_key_len) {
+               return 0;
+       }
+
+       int key_length = tls_key_length(context);
+       int mac_length = tls_mac_length(context);
+
+       if (!key_length || !mac_length) {
+               DEBUG_PRINT
+                   ("KEY EXPANSION FAILED, KEY LENGTH: %i, MAC LENGTH: %i\n",
+                    key_length, mac_length);
+               return 0;
+       }
+       unsigned char *clientkey = NULL;
+       unsigned char *serverkey = NULL;
+       unsigned char *clientiv = NULL;
+       unsigned char *serveriv = NULL;
+       int iv_length = TLS_AES_IV_LENGTH;
+       int is_aead = tls_is_aead(context);
+
+       if (context->is_server) {
+               tls_prf(context, key, sizeof(key),
+                                context->master_key, context->master_key_len,
+                                (unsigned char *) "key expansion", 13,
+                                context->local_random, TLS_SERVER_RANDOM_SIZE,
+                                context->remote_random,
+                                TLS_CLIENT_RANDOM_SIZE);
+       } else {
+               tls_prf(context, key, sizeof(key),
+                                context->master_key,
+                                context->master_key_len,
+                                (unsigned char *) "key expansion", 13,
+                                context->remote_random,
+                                TLS_SERVER_RANDOM_SIZE,
+                                context->local_random,
+                                TLS_CLIENT_RANDOM_SIZE);
+       }
+
+       DEBUG_DUMP_HEX_LABEL("LOCAL RANDOM ", context->local_random,
+                            TLS_SERVER_RANDOM_SIZE);
+       DEBUG_DUMP_HEX_LABEL("REMOTE RANDOM", context->remote_random,
+                            TLS_CLIENT_RANDOM_SIZE);
+       DEBUG_PRINT("\n=========== EXPANSION ===========\n");
+       DEBUG_DUMP_HEX(key, TLS_MAX_KEY_EXPANSION_SIZE);
+       DEBUG_PRINT("\n");
+
+       int pos = 0;
+       if (is_aead == 2) {
+               iv_length = TLS_CHACHA20_IV_LENGTH;
+       } else {
+               if (is_aead) {
+                       iv_length = TLS_AES_GCM_IV_LENGTH;
+               } else {
+                       if (context->is_server) {
+                               memcpy(context->crypto.ctx_remote_mac.remote_mac,
+                                               &key[pos], mac_length);
+                               pos += mac_length;
+                               memcpy(context->crypto.ctx_local_mac.local_mac,
+                                               &key[pos], mac_length);
+                               pos += mac_length;
+                       } else {
+                               memcpy(context->crypto.ctx_local_mac.local_mac,
+                                               &key[pos], mac_length);
+                               pos += mac_length;
+                               memcpy(context->crypto.ctx_remote_mac.remote_mac,
+                                               &key[pos], mac_length);
+                               pos += mac_length;
+                       }
+               }
+       }
+
+       clientkey = &key[pos];
+       pos += key_length;
+       serverkey = &key[pos];
+       pos += key_length;
+       clientiv = &key[pos];
+       pos += iv_length;
+       serveriv = &key[pos];
+       pos += iv_length;
+       DEBUG_PRINT("EXPANSION %i/%i\n", (int) pos,
+                       (int) TLS_MAX_KEY_EXPANSION_SIZE);
+       DEBUG_DUMP_HEX_LABEL("CLIENT KEY", clientkey, key_length);
+       DEBUG_DUMP_HEX_LABEL("CLIENT IV", clientiv, iv_length);
+       DEBUG_DUMP_HEX_LABEL("CLIENT MAC KEY",
+                       context->is_server ? context->crypto.
+                       ctx_remote_mac.remote_mac : context->
+                       crypto.ctx_local_mac.local_mac,
+                       mac_length);
+       DEBUG_DUMP_HEX_LABEL("SERVER KEY", serverkey, key_length);
+       DEBUG_DUMP_HEX_LABEL("SERVER IV", serveriv, iv_length);
+       DEBUG_DUMP_HEX_LABEL("SERVER MAC KEY",
+                       context->is_server ? context->crypto.
+                       ctx_local_mac.local_mac : context->crypto.
+                       ctx_remote_mac.remote_mac, mac_length);
+       if (context->is_server) {
+               if (is_aead == 2) {
+                       memcpy(context->crypto.ctx_remote_mac.remote_nonce,
+                                       clientiv, iv_length);
+                       memcpy(context->crypto.ctx_local_mac.local_nonce,
+                                       serveriv, iv_length);
+               } else {
+                       if (is_aead) {
+                               memcpy(context->crypto.ctx_remote_mac.
+                                               remote_aead_iv, clientiv, iv_length);
+                               memcpy(context->crypto.ctx_local_mac.local_aead_iv,
+                                               serveriv, iv_length);
+                       }
+               }
+
+               if (tls_crypto_create(context, key_length,
+                                       serverkey, serveriv, clientkey,
+                                       clientiv)) {
+                       return 0;
+               }
+       } else {
+               if (is_aead == 2) {
+                       memcpy(context->crypto.ctx_local_mac.local_nonce,
+                                       clientiv, iv_length);
+                       memcpy(context->crypto.ctx_remote_mac.remote_nonce,
+                                       serveriv, iv_length);
+               } else {
+                       if (is_aead) {
+                               memcpy(context->crypto.ctx_local_mac.local_aead_iv,
+                                               clientiv, iv_length);
+                               memcpy(context->crypto.ctx_remote_mac.
+                                               remote_aead_iv, serveriv, iv_length);
+                       }
+               }
+
+               if (tls_crypto_create(context, key_length,
+                                       clientkey, clientiv, serverkey,
+                                       serveriv)) {
+                       return 0;
+               }
+       }
+
+       /*
+        * extract client_mac_key(mac_key_length)
+        * extract server_mac_key(mac_key_length)
+        * extract client_key(enc_key_length)
+        * extract server_key(enc_key_length)
+        * extract client_iv(fixed_iv_lengh)
+        * extract server_iv(fixed_iv_length)
+        */
+       return 1;
+}
+
+int tls_compute_key(struct TLSContext *context, unsigned int key_len) {
+       if (context->tlsver == TLS_VERSION13) {
+               return 0;
+       }
+
+       if (!context->premaster_key || !context->premaster_key_len
+           || key_len < 48) {
+               DEBUG_PRINT("CANNOT COMPUTE MASTER SECRET\n");
+               return 0;
+       }
+
+       unsigned char master_secret_label[] = "master secret";
+#ifdef TLS_CHECK_PREMASTER_KEY
+       if (!tls_cipher_is_ephemeral(context)) {
+               uint16_t version = get16(context->premaster_key);
+               /* this check is not true for DHE/ECDHE ciphers */
+               if (context->version > version) {
+                       DEBUG_PRINT("Mismatch protocol version 0x(%x)\n",
+                                   version);
+                       return 0;
+               }
+       }
+#endif
+       free(context->master_key);
+       context->master_key_len = 0;
+       context->master_key = NULL;
+
+       context->master_key = malloc(key_len);
+       if (!context->master_key) {
+               return 0;
+       }
+
+       context->master_key_len = key_len;
+       if (context->is_server) {
+               tls_prf(context,
+                               context->master_key,
+                               context->master_key_len,
+                               context->premaster_key,
+                               context->premaster_key_len,
+                               master_secret_label, 13,
+                               context->remote_random,
+                               TLS_CLIENT_RANDOM_SIZE,
+                               context->local_random,
+                               TLS_SERVER_RANDOM_SIZE);
+       } else {
+               tls_prf(context,
+                               context->master_key,
+                               context->master_key_len,
+                               context->premaster_key,
+                               context->premaster_key_len,
+                               master_secret_label, 13,
+                               context->local_random,
+                               TLS_CLIENT_RANDOM_SIZE,
+                               context->remote_random,
+                               TLS_SERVER_RANDOM_SIZE);
+       }
+       free(context->premaster_key);
+       context->premaster_key = NULL;
+       context->premaster_key_len = 0;
+       DEBUG_PRINT("\n=========== Master key ===========\n");
+       DEBUG_DUMP_HEX(context->master_key,
+                       context->master_key_len);
+       DEBUG_PRINT("\n");
+       tls_expand_key(context);
+       return 1;
+}
+
+int _is_oid(const unsigned char *oid, const unsigned char *compare_to,
+           int compare_to_len) {
+       int i = 0;
+       while ((oid[i]) && (i < compare_to_len)) {
+               if (oid[i] != compare_to[i])
+                       return 0;
+
+               i++;
+       }
+       return 1;
+}
+
+int _is_oid2(const unsigned char *oid, const unsigned char *compare_to,
+            int compare_to_len, int oid_len) {
+       int i = 0;
+       if (oid_len < compare_to_len) {
+               compare_to_len = oid_len;
+       }
+
+       while (i < compare_to_len) {
+               if (oid[i] != compare_to[i]) {
+                       return 0;
+               }
+
+               i++;
+       }
+       return 1;
+}
+
+struct TLSCertificate *tls_create_certificate() {
+       struct TLSCertificate zero = { 0 };
+       struct TLSCertificate *cert = malloc(sizeof *cert);
+       if (cert) {
+               *cert = zero;
+       }
+       cert->not_before[0] = 0;
+       cert->not_after[0] = 0;
+
+       return cert;
+}
+
+int tls_certificate_valid_subject_name(const unsigned char *cert_subject,
+                                      const char *subject) {
+       /* no subjects ... */
+       if ((!cert_subject || !cert_subject[0]) && (!subject || !subject[0])) {
+               return 0;
+       }
+
+       if (!subject || !subject[0]) {
+               return bad_certificate;
+       }
+
+       if (!cert_subject || !cert_subject[0]) {
+               return bad_certificate;
+       }
+
+       /* exact match */
+       if (!strcmp((const char *) cert_subject, subject)) {
+               return 0;
+       }
+
+       const char *wildcard = strchr((const char *) cert_subject, '*');
+       if (wildcard) {
+               /* 6.4.3 (1) The client SHOULD NOT attempt to match a presented
+                * identifier in which the wildcard character comprises a label
+                * other than the left-most label
+                */
+               if (!wildcard[1]) {
+                       /* subject is [*]
+                        * or
+                        * subject is [something*] .. invalid
+                        */
+                       return bad_certificate;
+               }
+               wildcard++;
+               const char *match = strstr(subject, wildcard);
+               if ((!match) && (wildcard[0] == '.')) {
+                       /* check *.domain.com against domain.com */
+                       wildcard++;
+                       if (!strcasecmp(subject, wildcard))
+                               return 0;
+               }
+               if (match) {
+                       unsigned long offset = (unsigned long) match -
+                               (unsigned long) subject;
+                       if (offset) {
+                               /* check for foo.*.domain.com against *.domain.com (invalid) */
+                               if (memchr(subject, '.', offset))
+                                       return bad_certificate;
+                       }
+                       /* check if exact match */
+                       if (!strcasecmp(match, wildcard)) {
+                               return 0;
+                       }
+               }
+       }
+
+       return bad_certificate;
+}
+
+int tls_certificate_valid_subject(struct TLSCertificate *cert,
+                                 const char *subject) {
+       int i;
+       if (!cert) {
+               return certificate_unknown;
+       }
+
+       int err = tls_certificate_valid_subject_name(cert->subject, subject);
+       if (err && cert->san) {
+               for (i = 0; i < cert->san_length; i++) {
+                       err = tls_certificate_valid_subject_name(cert->san[i],
+                                       subject);
+                       if (!err) {
+                               return err;
+                       }
+               }
+       }
+       return err;
+}
+
+int tls_certificate_is_valid(struct TLSCertificate *cert) {
+       if (!cert) {
+               return certificate_unknown;
+       }
+
+       char ts[16]; /* YYYYMMDDHHMMSSZ */
+       time_t t = time(NULL);
+       struct tm *utc = gmtime(&t);
+
+       if (utc) {
+               strftime(ts, sizeof ts, "%Y%m%d%H%M%SZ", utc);
+
+               if (strcmp(cert->not_before, ts) > 0) {
+                       DEBUG_PRINT
+                           ("Certificate is not yet valid, now: %s (validity: %s - %s)\n",
+                            ts, cert->not_before, cert->not_after);
+                       return certificate_expired;
+               }
+
+               if (strcmp(cert->not_after, ts) < 0) {
+                       DEBUG_PRINT
+                           ("Expired certificate, now: %s (validity: %s - %s)\n",
+                            ts, cert->not_before, cert->not_after);
+                       return certificate_expired;
+               }
+               DEBUG_PRINT("Valid certificate, now: %s (validity: %s - %s)\n",
+                               ts, cert->not_before,
+                               cert->not_after);
+       }
+       return 0;
+}
+
+void tls_certificate_set_copy(unsigned char **member,
+                             const unsigned char *val, int len) {
+       if (!member) {
+               return;
+       }
+
+       free(*member);
+
+       if (len) {
+               *member = malloc(len + 1);
+               if (*member) {
+                       memcpy(*member, val, len);
+                       (*member)[len] = 0;
+               }
+       } else {
+               *member = NULL;
+       }
+}
+
+void tls_certificate_set_copy_date(unsigned char *member,
+                                  const unsigned char *val, int len) {
+
+       if (len > 4) {
+               if (val[0] >= '5') {
+                       member[0] = '1';
+                       member[1] = '9';
+               } else {
+                       member[0] = '2';
+                       member[1] = '0';
+               }
+               memcpy(member + 2, val, len);
+               member[len] = 0;
+       } else {
+               member[0] = 0;
+       }
+}
+
+void tls_certificate_set_key(struct TLSCertificate *cert,
+                            const unsigned char *val, int len) {
+       if (!val[0] && len % 2) {
+               val++;
+               len--;
+       }
+       tls_certificate_set_copy(&cert->pk, val, len);
+       if (cert->pk) {
+               cert->pk_len = len;
+       }
+}
+
+void tls_certificate_set_priv(struct TLSCertificate *cert,
+                             const unsigned char *val, int len) {
+       tls_certificate_set_copy(&cert->priv, val, len);
+       if (cert->priv) {
+               cert->priv_len = len;
+       }
+}
+
+void tls_certificate_set_sign_key(struct TLSCertificate *cert,
+                                 const unsigned char *val, int len) {
+       if (!val[0] && len % 2) {
+               val++;
+               len--;
+       }
+       tls_certificate_set_copy(&cert->sign_key, val, len);
+       if (cert->sign_key) {
+               cert->sign_len = len;
+       }
+}
+
+void tls_certificate_set_exponent(struct TLSCertificate *cert,
+                                 const unsigned char *val, int len) {
+       tls_certificate_set_copy(&cert->exponent, val, len);
+       if (cert->exponent) {
+               cert->exponent_len = len;
+       }
+}
+
+void tls_certificate_set_serial(struct TLSCertificate *cert,
+                               const unsigned char *val, int len) {
+       tls_certificate_set_copy(&cert->serial_number, val, len);
+       if (cert->serial_number) {
+               cert->serial_len = len;
+       }
+}
+
+void tls_certificate_set_algorithm(unsigned int *algorithm,
+                                  const unsigned char *val, int len) {
+       if (len == 7 && _is_oid(val, TLS_EC_PUBLIC_KEY_OID, 7)) {
+               *algorithm = TLS_EC_PUBLIC_KEY;
+               return;
+       }
+
+       if (len == 8) {
+               if (_is_oid(val, TLS_EC_prime192v1_OID, len)) {
+                       *algorithm = TLS_EC_prime192v1;
+                       return;
+               }
+               if (_is_oid(val, TLS_EC_prime192v2_OID, len)) {
+                       *algorithm = TLS_EC_prime192v2;
+                       return;
+               }
+               if (_is_oid(val, TLS_EC_prime192v3_OID, len)) {
+                       *algorithm = TLS_EC_prime192v3;
+                       return;
+               }
+               if (_is_oid(val, TLS_EC_prime239v1_OID, len)) {
+                       *algorithm = TLS_EC_prime239v1;
+                       return;
+               }
+               if (_is_oid(val, TLS_EC_prime239v2_OID, len)) {
+                       *algorithm = TLS_EC_prime239v2;
+                       return;
+               }
+               if (_is_oid(val, TLS_EC_prime239v3_OID, len)) {
+                       *algorithm = TLS_EC_prime239v3;
+                       return;
+               }
+               if (_is_oid(val, TLS_EC_prime256v1_OID, len)) {
+                       *algorithm = TLS_EC_prime256v1;
+                       return;
+               }
+       }
+       if (len == 5) {
+               if (_is_oid2
+                   (val, TLS_EC_secp224r1_OID, len,
+                    sizeof(TLS_EC_secp224r1_OID) - 1)) {
+                       *algorithm = TLS_EC_secp224r1;
+                       return;
+               }
+               if (_is_oid2
+                   (val, TLS_EC_secp384r1_OID, len,
+                    sizeof(TLS_EC_secp384r1_OID) - 1)) {
+                       *algorithm = TLS_EC_secp384r1;
+                       return;
+               }
+               if (_is_oid2
+                   (val, TLS_EC_secp521r1_OID, len,
+                    sizeof(TLS_EC_secp521r1_OID) - 1)) {
+                       *algorithm = TLS_EC_secp521r1;
+                       return;
+               }
+       }
+       if (len != 9) {
+               return;
+       }
+
+       if (_is_oid(val, TLS_RSA_SIGN_SHA256_OID, 9)) {
+               *algorithm = TLS_RSA_SIGN_SHA256;
+               return;
+       }
+
+       if (_is_oid(val, TLS_RSA_SIGN_RSA_OID, 9)) {
+               *algorithm = TLS_RSA_SIGN_RSA;
+               return;
+       }
+
+       if (_is_oid(val, TLS_RSA_SIGN_SHA1_OID, 9)) {
+               *algorithm = TLS_RSA_SIGN_SHA1;
+               return;
+       }
+
+       if (_is_oid(val, TLS_RSA_SIGN_SHA512_OID, 9)) {
+               *algorithm = TLS_RSA_SIGN_SHA512;
+               return;
+       }
+
+       if (_is_oid(val, TLS_RSA_SIGN_SHA384_OID, 9)) {
+               *algorithm = TLS_RSA_SIGN_SHA384;
+               return;
+       }
+
+       if (_is_oid(val, TLS_RSA_SIGN_MD5_OID, 9)) {
+               *algorithm = TLS_RSA_SIGN_MD5;
+               return;
+       }
+}
+
+void tls_destroy_certificate(struct TLSCertificate *cert) {
+       if (cert) {
+               int i;
+               free(cert->exponent);
+               free(cert->pk);
+               free(cert->issuer_country);
+               free(cert->issuer_state);
+               free(cert->issuer_location);
+               free(cert->issuer_entity);
+               free(cert->issuer_subject);
+               free(cert->country);
+               free(cert->state);
+               free(cert->location);
+               free(cert->subject);
+               for (i = 0; i < cert->san_length; i++) {
+                       free(cert->san[i]);
+               }
+               free(cert->san);
+               free(cert->ocsp);
+               free(cert->serial_number);
+               free(cert->entity);
+               cert->not_before[0] = 0;
+               cert->not_after[0] = 0;
+               free(cert->sign_key);
+               free(cert->priv);
+               free(cert->der_bytes);
+               free(cert->bytes);
+               free(cert->fingerprint);
+               free(cert);
+       }
+}
+
+struct TLSPacket *tls_create_packet(struct TLSContext *context,
+                                   unsigned char type,
+                                   unsigned short version,
+                                   int payload_size_hint) {
+       struct TLSPacket *packet = malloc(sizeof *packet);
+       if (!packet) {
+               return NULL;
+       }
+       packet->broken = 0;
+       if (payload_size_hint > 0) {
+               packet->size = payload_size_hint + 10;
+       } else {
+               packet->size = TLS_BLOB_INCREMENT;
+       }
+       packet->buf = malloc(packet->size);
+       memset(packet->buf, 0, packet->size);
+       packet->context = context;
+       if (!packet->buf) {
+               free(packet);
+               return NULL;
+       }
+       if (context) {
+               packet->payload_pos = 6;
+               packet->len = packet->payload_pos - 1;
+       } else {
+               packet->len = 5;
+       }
+       packet->buf[0] = type;
+
+       /* big endian protocol version */
+       packet->buf[1] = version >> 8; 
+       packet->buf[2] = version & 0xff;
+       if (version == TLS_V13) {
+               packet->buf[2] = 0x04;
+       }
+
+       return packet;
+}
+
+void tls_destroy_packet(struct TLSPacket *packet) {
+       if (packet) {
+               if (packet->buf) {
+                       free(packet->buf);
+               }
+               free(packet);
+       }
+}
+
+int tls_crypto_create(struct TLSContext *context, int key_length,
+                              unsigned char *localkey,
+                              unsigned char *localiv,
+                              unsigned char *remotekey,
+                              unsigned char *remoteiv) {
+       if (context->crypto.created) {
+               if (context->crypto.created == 1) {
+                       cbc_done(&context->crypto.ctx_remote.aes_remote);
+                       cbc_done(&context->crypto.ctx_local.aes_local);
+               } else {
+                       if (context->crypto.created == 2) {
+                               unsigned char dummy_buffer[32];
+                               unsigned long tag_len = 0;
+                               gcm_done(&context->crypto.ctx_remote.
+                                        aes_gcm_remote, dummy_buffer,
+                                        &tag_len);
+                               gcm_done(&context->crypto.ctx_local.
+                                        aes_gcm_local, dummy_buffer,
+                                        &tag_len);
+                       }
+               }
+               context->crypto.created = 0;
+       }
+       int is_aead = tls_is_aead(context);
+       int cipherID = find_cipher("aes");
+       DEBUG_PRINT("Using cipher ID: %x\n", (int) context->cipher);
+       if (is_aead == 2) {
+               unsigned int counter = 1;
+
+               chacha_keysetup(&context->crypto.ctx_local.chacha_local,
+                               localkey, key_length * 8);
+               chacha_ivsetup_96bitnonce(&context->crypto.ctx_local.
+                                         chacha_local, localiv,
+                                         (unsigned char *) &counter);
+
+               chacha_keysetup(&context->crypto.ctx_remote.chacha_remote,
+                               remotekey, key_length * 8);
+               chacha_ivsetup_96bitnonce(&context->crypto.ctx_remote.
+                                         chacha_remote, remoteiv,
+                                         (unsigned char *) &counter);
+
+               context->crypto.created = 3;
+       } else {
+               if (is_aead) {
+                       int res1 =
+                               gcm_init(&context->crypto.ctx_local.aes_gcm_local,
+                                               cipherID, localkey, key_length);
+                       int res2 =
+                               gcm_init(&context->crypto.ctx_remote.aes_gcm_remote,
+                                               cipherID, remotekey, key_length);
+
+                       if (res1 || res2) {
+                               return TLS_GENERIC_ERROR;
+                       }
+                       context->crypto.created = 2;
+               } else {
+                       int res1 =
+                               cbc_start(cipherID, localiv, localkey, key_length, 0,
+                                               &context->crypto.ctx_local.aes_local);
+                       int res2 =
+                               cbc_start(cipherID, remoteiv, remotekey, key_length, 0,
+                                               &context->crypto.ctx_remote.aes_remote);
+
+                       if (res1 || res2) {
+                               return TLS_GENERIC_ERROR;
+                       }
+                       context->crypto.created = 1;
+               }
+       }
+       return 0;
+}
+
+static void tls_crypto_done(struct TLSContext *context) {
+       unsigned char dummy_buffer[32];
+       unsigned long tag_len = 0;
+
+       switch (context->crypto.created) {
+               case 1:
+                       cbc_done(&context->crypto.ctx_remote.aes_remote);
+                       cbc_done(&context->crypto.ctx_local.aes_local);
+                       break;
+               case 2:
+                       gcm_done(&context->crypto.ctx_remote.aes_gcm_remote,
+                                       dummy_buffer, &tag_len);
+                       gcm_done(&context->crypto.ctx_local.aes_gcm_local,
+                                       dummy_buffer, &tag_len);
+                       break;
+       }
+       context->crypto.created = 0;
+}
+
+int tls_packet_append(struct TLSPacket *packet, const unsigned char *buf,
+                     unsigned int len) {
+       void *new;
+
+       if (!packet || packet->broken) {
+               return -1;
+       }
+
+       if (!len) {
+               return 0;
+       }
+
+       unsigned int new_len = packet->len + len;
+
+       if (new_len > packet->size) {
+               packet->size = (new_len / TLS_BLOB_INCREMENT + 1) *
+                       TLS_BLOB_INCREMENT;
+               new = TLS_REALLOC(packet->buf, packet->size);
+               if (new) {
+                       packet->buf = new;
+               } else {
+                       free(packet->buf);
+                       packet->size = 0;
+                       packet->len = 0;
+                       packet->broken = 1;
+                       return -1;
+               }
+       }
+       memcpy(packet->buf + packet->len, buf, len);
+       packet->len = new_len;
+       return new_len;
+}
+
+int tls_packet_uint8(struct TLSPacket *packet, unsigned char i) {
+       return tls_packet_append(packet, &i, 1);
+}
+
+int tls_packet_uint16(struct TLSPacket *packet, unsigned short i) {
+       unsigned short ni = htons(i);
+       return tls_packet_append(packet, (unsigned char *) &ni, 2);
+}
+
+int tls_packet_uint32(struct TLSPacket *packet, unsigned int i) {
+       unsigned int ni = htonl(i);
+       return tls_packet_append(packet, (unsigned char *) &ni, 4);
+}
+
+int tls_packet_uint24(struct TLSPacket *packet, unsigned int i) {
+       unsigned char buf[3];
+       buf[0] = (i >> 16) & 0xff;
+       buf[1] = (i >> 8) & 0xff;
+       buf[2] = (i >> 0) & 0xff;
+
+       return tls_packet_append(packet, buf, 3);
+}
+
+int tls_random(unsigned char *key, int len) {
+#ifdef __APPLE__
+       for (int i = 0; i < len; i++) {
+               unsigned int v = arc4random() % 0x100;
+               key[i] = (char) v;
+       }
+       return 1;
+#else
+       /* TODO use open and read */
+       FILE *fp = fopen("/dev/urandom", "r");
+       if (fp) {
+               int key_len = fread(key, 1, len, fp);
+               fclose(fp);
+               if (key_len == len)
+                       return 1;
+       }
+#endif
+       return 0;
+}
+
+int tls_established(struct TLSContext *context) {
+       if (context) {
+               if (context->critical_error) {
+                       return -1;
+               }
+
+               if (context->connection_status == TLS_CONNECTED) {
+                       return 1;
+               }
+       }
+       return 0;
+}
+
+void tls_read_clear(struct TLSContext *context) {
+       if (context) {
+              tls_buffer_free(&context->application_buffer); 
+       }
+}
+
+struct TLSContext *tls_create_context(int is_server, unsigned short version) {
+       struct TLSContext zero = {0};
+       uint16_t ver = 0;
+       struct TLSContext *context = 0;
+
+       if (version == TLS_V13 && !is_server) {
+               /* TLS 1.3 clients not supported */
+               return NULL;
+       }
+
+       tls_init();
+       switch (version) {
+               case TLS_V13:
+               case TLS_V12:
+                       context = malloc(sizeof *context);
+                       break;
+               default:
+                       return NULL;
+       }
+
+       ver = version - 0x0201;
+
+       if (context) {
+               *context = zero;
+               context->is_server = is_server;
+               context->version = version;
+               context->tlsver = ver;
+               context->hs_index = -1;
+               /* set up output buffer */
+               tls_buffer_init(&context->output_buffer, 0);
+               tls_buffer_init(&context->input_buffer, 0);
+               tls_buffer_init(&context->cached_handshake, 0);
+               tls_buffer_init(&context->application_buffer, 0);
+       }
+       return context;
+}
+
+struct TLSContext *tls_accept(struct TLSContext *context) {
+       if (!context || !context->is_server) {
+               return NULL;
+       }
+
+       struct TLSContext *child = malloc(sizeof *child);
+       if (child) {
+               memset(child, 0, sizeof(struct TLSContext));
+               child->is_server = 1;
+               child->is_child = 1;
+               child->version = context->version;
+               child->certificates = context->certificates;
+               child->certificates_count = context->certificates_count;
+               child->private_key = context->private_key;
+               child->ec_private_key = context->ec_private_key;
+               child->root_certificates = context->root_certificates;
+               child->root_count = context->root_count;
+               child->default_dhe_p = context->default_dhe_p;
+               child->default_dhe_g = context->default_dhe_g;
+               child->curve = context->curve;
+               child->alpn = context->alpn;
+               child->alpn_count = context->alpn_count;
+       }
+       return child;
+}
+
+int tls_add_alpn(struct TLSContext *context, const char *alpn) {
+       void *new;
+
+       if (!context || !alpn || !alpn[0]
+           || (context->is_server && context->is_child)) {
+               return TLS_GENERIC_ERROR;
+       }
+
+       int len = strlen(alpn);
+       if (tls_alpn_contains(context, alpn, len)) {
+               return 0;
+       }
+
+       new = TLS_REALLOC(context->alpn, (context->alpn_count + 1) *
+                       sizeof(char *));
+       if (new) {
+               context->alpn = new;
+       } else {
+               free(context->alpn);
+               context->alpn = 0;
+               context->alpn_count = 0;
+               return TLS_NO_MEMORY;
+       }
+       char *alpn_ref = malloc(len + 1);
+       context->alpn[context->alpn_count] = alpn_ref;
+       if (alpn_ref) {
+               memcpy(alpn_ref, alpn, len);
+               alpn_ref[len] = 0;
+               context->alpn_count++;
+       } else {
+               return TLS_NO_MEMORY;
+       }
+       return 0;
+}
+
+int tls_alpn_contains(struct TLSContext *context, const char *alpn,
+                     unsigned char alpn_size) {
+       int i;
+
+       if (!context || !alpn || !alpn_size || !context->alpn) {
+               return 0;
+       }
+
+       for (i = 0; i < context->alpn_count; i++) {
+               const char *alpn_local = context->alpn[i];
+               if (alpn_local) {
+                       int len = strlen(alpn_local);
+                       if (alpn_size == len) {
+                               if (!memcmp(alpn_local, alpn, alpn_size)) {
+                                       return 1;
+                               }
+                       }
+               }
+       }
+
+       return 0;
+}
+
+void tls_destroy_context(struct TLSContext *context) {
+       int i;
+
+       if (!context) {
+               return;
+       }
+
+       if (!context->is_child) {
+               if (context->certificates) {
+                       for (i = 0; i < context->certificates_count; i++) {
+                               tls_destroy_certificate(context->
+                                                       certificates[i]);
+                       }
+               }
+               if (context->root_certificates) {
+                       for (i = 0; i < context->root_count; i++) {
+                               tls_destroy_certificate(context->
+                                                       root_certificates[i]);
+                       }
+                       free(context->root_certificates);
+                       context->root_certificates = NULL;
+               }
+               if (context->private_key) {
+                       tls_destroy_certificate(context->private_key);
+               }
+               if (context->ec_private_key) {
+                       tls_destroy_certificate(context->ec_private_key);
+               }
+               free(context->certificates);
+               free(context->default_dhe_p);
+               free(context->default_dhe_g);
+               if (context->alpn) {
+                       for (i = 0; i < context->alpn_count; i++) {
+                               free(context->alpn[i]);
+                       }
+                       free(context->alpn);
+               }
+       }
+
+       if (context->client_certificates) {
+               for (i = 0; i < context->client_certificates_count; i++) {
+                       tls_destroy_certificate(context->
+                                               client_certificates[i]);
+               }
+               free(context->client_certificates);
+       }
+
+       context->client_certificates = NULL;
+       free(context->master_key);
+       free(context->premaster_key);
+
+       if (context->crypto.created) {
+               tls_crypto_done(context);
+       }
+
+       tls_done_hash(context, NULL);
+       tls_destroy_hash(context);
+
+       tls_buffer_free(&context->output_buffer);
+       tls_buffer_free(&context->input_buffer);
+       tls_buffer_free(&context->application_buffer);
+       tls_buffer_free(&context->cached_handshake);
+       //free(context->cached_handshake);
+
+       free(context->sni);
+       tls_dhe_free(context);
+       tls_ecc_dhe_free(context);
+       free(context->negotiated_alpn);
+       free(context->finished_key);
+       free(context->remote_finished_key);
+       free(context->server_finished_hash);
+       free(context);
+}
+
+int tls_cipher_is_ephemeral(struct TLSContext *context) {
+       if (!context) {
+               return 0;
+       }
+
+       switch (context->cipher) {
+               case TLS_DHE_RSA_WITH_AES_128_CBC_SHA:
+               case TLS_DHE_RSA_WITH_AES_256_CBC_SHA:
+               case TLS_DHE_RSA_WITH_AES_128_CBC_SHA256:
+               case TLS_DHE_RSA_WITH_AES_256_CBC_SHA256:
+               case TLS_DHE_RSA_WITH_AES_128_GCM_SHA256:
+               case TLS_DHE_RSA_WITH_AES_256_GCM_SHA384:
+               case TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
+                       return 1;
+               case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA:
+               case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA:
+               case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256:
+               case TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256:
+               case TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384:
+               case TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
+               case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA:
+               case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA:
+               case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256:
+               case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384:
+               case TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:
+               case TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:
+               case TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256:
+                       return 2;
+               case TLS_AES_128_GCM_SHA256:
+               case TLS_CHACHA20_POLY1305_SHA256:
+               case TLS_AES_128_CCM_SHA256:
+               case TLS_AES_128_CCM_8_SHA256:
+               case TLS_AES_256_GCM_SHA384:
+                       if (context->dhe) {
+                               return 1;
+                       }
+                       return 2;
+       }
+       return 0;
+}
+
+int tls_is_ecdsa(struct TLSContext *context) {
+       if (!context) {
+               return 0;
+       }
+
+       switch (context->cipher) {
+               case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA:
+               case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA:
+               case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256:
+               case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384:
+               case TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:
+               case TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:
+               case TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256:
+                       return 1;
+       }
+
+       if (context->ec_private_key) {
+               return 1;
+       }
+
+       return 0;
+}
+
+static void tls_send_server_key_exchange(struct TLSContext *context,
+                                               int method) {
+       if (!context->is_server) {
+               DEBUG_PRINT
+                   ("CANNOT BUILD SERVER KEY EXCHANGE MESSAGE FOR CLIENTS\n");
+               return;
+       }
+
+       struct TLSPacket *packet =
+           tls_create_packet(context, TLS_HANDSHAKE, context->version, 0);
+       tls_packet_uint8(packet, 0x0C);
+       unsigned char dummy[3];
+       tls_packet_append(packet, dummy, 3);
+       int start_len = packet->len;
+
+       if (method == KEA_dhe_rsa) {
+               tls_dhe_create(context);
+
+               const char *default_dhe_p = context->default_dhe_p;
+               const char *default_dhe_g = context->default_dhe_g;
+               int key_size;
+               if (!default_dhe_p || !default_dhe_g) {
+                       default_dhe_p = TLS_DH_DEFAULT_P;
+                       default_dhe_g = TLS_DH_DEFAULT_G;
+                       key_size = TLS_DHE_KEY_SIZE / 8;
+               } else {
+                       key_size = strlen(default_dhe_p);
+               }
+               if (tls_dh_make_key(key_size, context->dhe, default_dhe_p,
+                                       default_dhe_g, 0, 0)) {
+                       DEBUG_PRINT("ERROR CREATING DHE KEY\n");
+                       free(packet);
+                       free(context->dhe);
+                       context->dhe = NULL;
+                       /* TODO set error */
+                       return;
+               }
+
+               unsigned char dh_Ys[0xFFF];
+               unsigned char dh_p[0xFFF];
+               unsigned char dh_g[0xFFF];
+               unsigned long dh_p_len = sizeof(dh_p);
+               unsigned long dh_g_len = sizeof(dh_g);
+               unsigned long dh_Ys_len = sizeof(dh_Ys);
+
+               if (tls_dh_export_pqY
+                   (dh_p, &dh_p_len, dh_g, &dh_g_len, dh_Ys, &dh_Ys_len,
+                    context->dhe)) {
+                       DEBUG_PRINT("ERROR EXPORTING DHE KEY\n");
+                       free(packet);
+                       /* TODO set error */
+                       return;
+               }
+
+               DEBUG_PRINT("LEN: %lu (%lu, %lu)\n", dh_Ys_len, dh_p_len,
+                           dh_g_len);
+               DEBUG_DUMP_HEX_LABEL("DHE PK", dh_Ys, dh_Ys_len);
+               DEBUG_DUMP_HEX_LABEL("DHE P", dh_p, dh_p_len);
+               DEBUG_DUMP_HEX_LABEL("DHE G", dh_g, dh_g_len);
+
+               tls_packet_uint16(packet, dh_p_len);
+               tls_packet_append(packet, dh_p, dh_p_len);
+
+               tls_packet_uint16(packet, dh_g_len);
+               tls_packet_append(packet, dh_g, dh_g_len);
+
+               tls_packet_uint16(packet, dh_Ys_len);
+               tls_packet_append(packet, dh_Ys, dh_Ys_len);
+               /* dh_p */
+               /* dh_g */
+               /* dh_Ys */
+       } else if (method == KEA_ec_diffie_hellman) {
+               /* 3 = named curve */
+               if (!context->curve) {
+                       context->curve = tls_ecc_default_curve;
+               }
+               tls_packet_uint8(packet, 3);
+               tls_packet_uint16(packet, context->curve->iana);
+               tls_ecc_dhe_create(context);
+
+               ltc_ecc_set_type *dp =
+                   (ltc_ecc_set_type *) & context->curve->dp;
+
+               if (ecc_make_key_ex(NULL, find_prng("sprng"), context->ecc_dhe,
+                                       dp)) {
+                       free(context->ecc_dhe);
+                       context->ecc_dhe = NULL;
+                       DEBUG_PRINT("Error generating ECC key\n");
+                       free(packet);
+                       /* TODO set error */
+                       return;
+               }
+               unsigned char out[TLS_MAX_RSA_KEY];
+               unsigned long out_len = TLS_MAX_RSA_KEY;
+               if (ecc_ansi_x963_export(context->ecc_dhe, out, &out_len)) {
+                       DEBUG_PRINT("Error exporting ECC key\n");
+                       free(packet);
+                       /* TODO abort */
+                       return; 
+               }
+               tls_packet_uint8(packet, out_len);
+               tls_packet_append(packet, out, out_len);
+       } else {
+               /* TODO abort */
+               free(packet);
+               DEBUG_PRINT("Unsupported ephemeral method: %i\n", method);
+               return;
+       }
+
+       /* signature */
+       unsigned int params_len = packet->len - start_len;
+       unsigned int message_len =
+           params_len + TLS_CLIENT_RANDOM_SIZE + TLS_SERVER_RANDOM_SIZE;
+       unsigned char *message = malloc(message_len);
+       if (message) {
+               unsigned char out[TLS_MAX_RSA_KEY];
+               unsigned long out_len = TLS_MAX_RSA_KEY;
+
+               int hash_algorithm;
+
+               hash_algorithm = sha256;
+
+               if (tls_is_ecdsa(context)) {
+                       hash_algorithm = sha512;
+                       tls_packet_uint8(packet, hash_algorithm);
+                       tls_packet_uint8(packet, ecdsa);
+               } else {
+                       tls_packet_uint8(packet, hash_algorithm);
+                       tls_packet_uint8(packet, rsa_sign);
+               }
+
+               memcpy(message, context->remote_random,
+                               TLS_CLIENT_RANDOM_SIZE);
+               memcpy(message + TLS_CLIENT_RANDOM_SIZE, context->local_random,
+                               TLS_SERVER_RANDOM_SIZE);
+               memcpy(message + TLS_CLIENT_RANDOM_SIZE +
+                               TLS_SERVER_RANDOM_SIZE, packet->buf +
+                               start_len, params_len);
+               if (tls_is_ecdsa(context)) {
+                       if (sign_ecdsa(context, hash_algorithm, message,
+                                               message_len, out, &out_len) ==
+                                       1) {
+                               DEBUG_PRINT
+                                   ("Signing OK! (ECDSA, length %lu)\n",
+                                    out_len);
+                               tls_packet_uint16(packet, out_len);
+                               tls_packet_append(packet, out, out_len);
+                       }
+               } else
+               if (sign_rsa(context, hash_algorithm, message, message_len,
+                                       out, &out_len) == 1) {
+                       DEBUG_PRINT("Signing OK! (length %lu)\n", out_len);
+                       tls_packet_uint16(packet, out_len);
+                       tls_packet_append(packet, out, out_len);
+               }
+               free(message);
+       }
+       if (!packet->broken && packet->buf) {
+               tls_set_packet_length(packet, packet->len - start_len);
+       }
+       tls_packet_update(packet);
+       tls_queue_packet(packet);
+       return;
+}
+
+#if 0
+void _private_tls_set_session_id(struct TLSContext *context) {
+       if (context->tlsver == TLS_VERSION13
+                       && context->session_size == TLS_MAX_SESSION_ID) {
+               return;
+       }
+
+       if (tls_random(context->session, TLS_MAX_SESSION_ID)) {
+               context->session_size = TLS_MAX_SESSION_ID;
+       } else {
+               context->session_size = 0;
+       }
+}
+#endif
+
+struct TLSPacket *tls_certificate_request(struct TLSContext *context) {
+       if (!context || !context->is_server) {
+               return NULL;
+       }
+
+       unsigned short packet_version = context->version;
+       struct TLSPacket *packet =
+           tls_create_packet(context, TLS_HANDSHAKE, packet_version, 0);
+
+       if (!packet) {
+               return NULL;
+       }
+
+       /* cert request and size placeholder */
+       unsigned char dummy[] = { 0x0d, 0, 0, 0 };
+       tls_packet_append(packet, dummy, sizeof dummy);
+
+       int start_len = packet->len;
+
+       if (context->tlsver == TLS_VERSION13) {
+               /* certificate request context */
+               tls_packet_uint8(packet, 0);
+               /* extensions */
+               tls_packet_uint16(packet, 18);
+               /* signature algorithms */
+               tls_packet_uint16(packet, 0x0D);
+               tls_packet_uint16(packet, 14);
+               tls_packet_uint16(packet, 12);
+#if 0
+               rsa_pkcs1_sha256
+                       tls_packet_uint16(packet, 0x0401);
+               rsa_pkcs1_sha384
+                       tls_packet_uint16(packet, 0x0501);
+               rsa_pkcs1_sha512
+                       tls_packet_uint16(packet, 0x0601);
+#endif
+
+               /* ecdsa_secp256r1_sha256 */
+               tls_packet_uint16(packet, 0x0403);
+               /* ecdsa_secp384r1_sha384 */
+               tls_packet_uint16(packet, 0x0503);
+               /* ecdsa_secp521r1_sha512 */
+               tls_packet_uint16(packet, 0x0604);
+               /* rsa_pss_rsae_sha256 */
+               tls_packet_uint16(packet, 0x0804);
+               /* rsa_pss_rsae_sha384 */
+               tls_packet_uint16(packet, 0x0805);
+               /* rsa_pss_rsae_sha512 */
+               tls_packet_uint16(packet, 0x0806);
+       } else {
+               tls_packet_uint8(packet, 1);
+               tls_packet_uint8(packet, rsa_sign);
+               if (context->version == TLS_V12) {
+                       /* 10 pairs or 2 bytes */
+                       tls_packet_uint16(packet, 10);
+                       tls_packet_uint8(packet, sha256);
+                       tls_packet_uint8(packet, rsa);
+                       tls_packet_uint8(packet, sha1);
+                       tls_packet_uint8(packet, rsa);
+                       tls_packet_uint8(packet, sha384);
+                       tls_packet_uint8(packet, rsa);
+                       tls_packet_uint8(packet, sha512);
+                       tls_packet_uint8(packet, rsa);
+                       tls_packet_uint8(packet, md5);
+                       tls_packet_uint8(packet, rsa);
+               }
+               /* no DistinguishedName yet */
+               tls_packet_uint16(packet, 0);
+       }
+       if (!packet->broken) {
+               tls_set_packet_length(packet, packet->len - start_len);
+       }
+       tls_packet_update(packet);
+       return packet;
+}
+
+int tls_parse_key_share(struct TLSContext *context, const unsigned char *buf,
+               int buf_len) {
+       int i = 0;
+       struct ECCCurveParameters *curve = 0;
+       struct DHKey *dhkey = 0;
+       int dhe_key_size = 0;
+       const unsigned char *buffer = NULL;
+       unsigned char *out2;
+       unsigned long out_size;
+       uint16_t key_size;
+
+       while (buf_len >= 4) {
+               uint16_t named_group = get16(&buf[i]);
+               i += 2;
+               buf_len -= 2;
+
+               key_size = get16(&buf[i]);
+               i += 2;
+               buf_len -= 2;
+
+               if (key_size > buf_len) {
+                       return TLS_BROKEN_PACKET;
+               }
+
+               switch (named_group) {
+                       case 0x0017:
+                               curve = &secp256r1;
+                               buffer = &buf[i];
+                               DEBUG_PRINT("KEY SHARE => secp256r1\n");
+                               buf_len = 0;
+                               continue;
+                       case 0x0018:
+                               /* secp384r1 */
+                               curve = &secp384r1;
+                               buffer = &buf[i];
+                               DEBUG_PRINT("KEY SHARE => secp384r1\n");
+                               buf_len = 0;
+                               continue;
+                       case 0x0019:
+                               /* secp521r1 */
+                               break;
+                       case 0x001D:
+                               /* x25519 */
+                               if (key_size != 32) {
+                                       DEBUG_PRINT
+                                               ("INVALID x25519 KEY SIZE (%i)\n",
+                                                key_size);
+                                       continue;
+                               }
+                               curve = &curve25519;
+                               buffer = &buf[i];
+                               DEBUG_PRINT("KEY SHARE => x25519\n");
+                               buf_len = 0;
+                               continue;
+                               break;
+
+                       case 0x001E:
+                               /* x448 */
+                               break;
+                       case 0x0100:
+                               dhkey = &ffdhe2048;
+                               dhe_key_size = 2048;
+                               break;
+                       case 0x0101:
+                               dhkey = &ffdhe3072;
+                               dhe_key_size = 3072;
+                               break;
+                       case 0x0102:
+                               dhkey = &ffdhe4096;
+                               dhe_key_size = 4096;
+                               break;
+                       case 0x0103:
+                               dhkey = &ffdhe6144;
+                               dhe_key_size = 6144;
+                               break;
+                       case 0x0104:
+                               dhkey = &ffdhe8192;
+                               dhe_key_size = 8192;
+                               break;
+               }
+               i += key_size;
+               buf_len -= key_size;
+       }
+
+       if (curve) {
+               context->curve = curve;
+
+               if (curve == &curve25519) {
+                       if (!tls_random(context->local_random,
+                            TLS_SERVER_RANDOM_SIZE)) {
+                               return TLS_GENERIC_ERROR;
+                       }
+
+                       unsigned char secret[32];
+                       static const unsigned char basepoint[32] = { 9 };
+
+                       tls_random(secret, 32);
+
+                       secret[0] &= 248;
+                       secret[31] &= 127;
+                       secret[31] |= 64;
+
+                       /* use finished key to store public key */
+                       free(context->finished_key);
+                       context->finished_key = malloc(32);
+                       if (!context->finished_key) {
+                               return TLS_GENERIC_ERROR;
+                       }
+
+                       x25519(context->finished_key, secret, basepoint);
+
+                       free(context->premaster_key);
+                       context->premaster_key = malloc(32);
+
+                       if (!context->premaster_key) {
+                               return TLS_GENERIC_ERROR;
+                       }
+
+                       x25519(context->premaster_key, secret, buffer);
+                       context->premaster_key_len = 32;
+
+                       return 0;
+               }
+
+               tls_ecc_dhe_create(context);
+               ltc_ecc_set_type *dp = (ltc_ecc_set_type *)&context->curve->dp;
+
+               if (ecc_make_key_ex(NULL, find_prng("sprng"), context->ecc_dhe,
+                                       dp)) {
+                       free(context->ecc_dhe);
+                       context->ecc_dhe = NULL;
+                       DEBUG_PRINT("Error generating ECC DHE key\n");
+                       return TLS_GENERIC_ERROR;
+               }
+
+               if (!tls_random(context->local_random, TLS_SERVER_RANDOM_SIZE)) {
+                       return TLS_GENERIC_ERROR;
+               }
+
+               ecc_key client_key;
+               memset(&client_key, 0, sizeof client_key);
+               if (ecc_ansi_x963_import_ex
+                   (buffer, key_size, &client_key, dp)) {
+                       DEBUG_PRINT("Error importing ECC DHE key\n");
+                       return TLS_GENERIC_ERROR;
+               }
+               out2 = malloc(key_size);
+               out_size = key_size;
+
+               int err = ecc_shared_secret(context->ecc_dhe, &client_key,
+                               out2, &out_size);
+               ecc_free(&client_key);
+
+               if (err) {
+                       DEBUG_PRINT("ECC DHE DECRYPT ERROR %i\n", err);
+                       free(out2);
+                       return TLS_GENERIC_ERROR;
+               }
+
+               DEBUG_PRINT("OUT_SIZE: %lu\n", out_size);
+               DEBUG_DUMP_HEX_LABEL("ECC DHE", out2, out_size);
+
+               free(context->premaster_key);
+               context->premaster_key = out2;
+               context->premaster_key_len = out_size;
+               return 0;
+       } else if (dhkey) {
+               tls_dhe_create(context);
+               if (!tls_random(context->local_random, TLS_SERVER_RANDOM_SIZE))
+               {
+                       return TLS_GENERIC_ERROR;
+               }
+
+               if (tls_dh_make_key(dhe_key_size / 8, context->dhe,
+                    (const char *)dhkey->p, (const char *)dhkey->g, 0, 0)) {
+                       free(context->dhe);
+                       context->dhe = NULL;
+                       DEBUG_PRINT("Error generating DHE key\n");
+                       return TLS_GENERIC_ERROR;
+               }
+
+               unsigned int dhe_out_size;
+               out2 = tls_decrypt_dhe(context, buffer, key_size,
+                               &dhe_out_size, 0);
+               if (!out2) {
+                       DEBUG_PRINT("Error generating DHE shared key\n");
+                       return TLS_GENERIC_ERROR;
+               }
+
+               free(context->premaster_key);
+               context->premaster_key = out2;
+               context->premaster_key_len = dhe_out_size;
+               if (context->dhe) {
+                       context->dhe->iana = dhkey->iana;
+               }
+               return 0;
+       }
+       DEBUG_PRINT("NO COMMON KEY SHARE SUPPORTED\n");
+       return TLS_NO_COMMON_CIPHER;
+}
+
+int tls_parse_certificate(struct TLSContext *context,
+                         const unsigned char *buf, int buf_len,
+                         int is_client) {
+       int res = 0;
+       if (buf_len < 3) {
+               return TLS_NEED_MORE_DATA;
+       }
+
+       int size = get24(buf);
+
+       /* not enough data, so just consume all of it */
+       if (size <= 4) {
+               return 3 + size;
+       }
+
+       res += 3; /* skip over the size field */
+
+       if (context->tlsver == TLS_VERSION13) {
+               int context_size = buf[res];
+               res++;
+               /* must be 0 */
+               if (context_size) {
+                       res += context_size;
+               }
+       }
+
+       if (buf_len - res < size) {
+               return TLS_NEED_MORE_DATA;
+       }
+
+       int idx = 0;
+       int valid_certificate = 0;
+       while (size > 0) {
+               idx++;
+               if (buf_len - res < 3) {
+                       return TLS_NEED_MORE_DATA;
+               }
+               int certificate_size = get24(buf+res);
+               res += 3;
+               if (buf_len - res < certificate_size) {
+                       return TLS_NEED_MORE_DATA;
+               }
+               /* load chain */
+               int certificates_in_chain = 0;
+               int res2 = res;
+               unsigned int remaining = certificate_size;
+               do {
+                       if (remaining <= 3) {
+                               break;
+                       }
+                       certificates_in_chain++;
+                       unsigned int certificate_size2 = get24(buf+res2);
+                       res2 += 3;
+                       remaining -= 3;
+                       if (certificate_size2 > remaining) {
+                               DEBUG_PRINT
+                                   ("Invalid certificate size (%i from %i bytes remaining)\n",
+                                    certificate_size2, remaining);
+                               break;
+                       }
+                       remaining -= certificate_size2;
+
+                       struct TLSCertificate *cert = asn1_parse(context,
+                                                                &buf
+                                                                [res2],
+                                                                certificate_size2,
+                                                                is_client);
+                       if (cert) {
+                               if (certificate_size2) {
+                                       cert->bytes =
+                                           malloc(certificate_size2);
+                                       if (cert->bytes) {
+                                               cert->len =
+                                                   certificate_size2;
+                                               memcpy(cert->bytes,
+                                                      &buf[res2],
+                                                      certificate_size2);
+                                       }
+                               }
+                               /* valid certificate */
+                               if (is_client) {
+                                       void *new;
+                                       valid_certificate = 1;
+
+                                       new =
+                                           TLS_REALLOC(context->
+                                                       client_certificates,
+                                                       (context->
+                                                        client_certificates_count
+                                                        +
+                                                        1) *
+                                                       sizeof(struct
+                                                              TLSCertificate
+                                                              *));
+
+                                       if (!new) {
+                                               free(context->
+                                                        client_certificates);
+                                               context->
+                                                   client_certificates =
+                                                   0;
+                                               return TLS_NO_MEMORY;
+                                       }
+
+                                       context->client_certificates = new;
+                                       context->
+                                           client_certificates
+                                           [context->client_certificates_count]
+                                           = cert;
+                                       context->
+                                           client_certificates_count++;
+                               } else {
+                                       void *new;
+                                       new =
+                                           TLS_REALLOC(context->
+                                                       certificates,
+                                                       (context->
+                                                        certificates_count
+                                                        +
+                                                        1) *
+                                                       sizeof(struct
+                                                              TLSCertificate
+                                                              *));
+                                       if (!new) {
+                                               free(context->
+                                                        certificates);
+                                               context->certificates = 0;
+                                               return TLS_NO_MEMORY;
+                                       }
+                                       context->certificates = new;
+                                       context->certificates[context->
+                                                             certificates_count]
+                                           = cert;
+                                       context->certificates_count++;
+                                       if ((cert->pk) || (cert->priv))
+                                               valid_certificate = 1;
+                                       else if (!context->is_server)
+                                               valid_certificate = 1;
+                               }
+                       }
+                       res2 += certificate_size2;
+                       /* extension */
+                       if (context->tlsver == TLS_VERSION13) {
+                               if (remaining >= 2) {
+                                       /* ignore extensions */
+                                       remaining -= 2;
+                                       uint16_t size = get16(&buf[res2]);
+                                       if (size && size >= remaining) {
+                                               res2 += size;
+                                               remaining -= size;
+                                       }
+                               }
+                       }
+               } while (remaining > 0);
+               if (remaining) {
+                       DEBUG_PRINT("Extra %i bytes after certificate\n",
+                                   remaining);
+               }
+               size -= certificate_size + 3;
+               res += certificate_size;
+       }
+       if (!valid_certificate) {
+               return TLS_UNSUPPORTED_CERTIFICATE;
+       }
+       if (res != buf_len) {
+               DEBUG_PRINT("Warning: %i bytes read from %i byte buffer\n",
+                           (int) res, (int) buf_len);
+       }
+       return res;
+}
+
+static int parse_dh( const unsigned char *buf, int buf_len, const unsigned char
+               **out, int *out_size) {
+       int res = 0;
+       *out = NULL;
+       *out_size = 0;
+       if (buf_len < 2) {
+               return TLS_NEED_MORE_DATA;
+       }
+       uint16_t size = get16(buf);
+       res += 2;
+       if (buf_len - res < size) {
+               return TLS_NEED_MORE_DATA;
+       }
+       DEBUG_DUMP_HEX(&buf[res], size);
+       *out = &buf[res];
+       *out_size = size;
+       res += size;
+       return res;
+}
+
+static int tls_parse_random(struct TLSContext *context,
+                             const unsigned char *buf, int buf_len) {
+       int res = 0;
+       int ephemeral = tls_cipher_is_ephemeral(context);
+       uint16_t size;
+       if (ephemeral == 2) {
+               if (buf_len < 1) {
+                       return TLS_NEED_MORE_DATA;
+               }
+               size = buf[0];
+               res += 1;
+       } else {
+               if (buf_len < 2) {
+                       return TLS_NEED_MORE_DATA;
+               }
+               size = get16(buf);
+               res += 2;
+       }
+
+       if (buf_len - res < size) {
+               return TLS_NEED_MORE_DATA;
+       }
+       unsigned int out_len = 0;
+       unsigned char *random = NULL;
+       switch (ephemeral) {
+               case 1:
+                       random = tls_decrypt_dhe(context, &buf[res], size, &out_len,
+                                       1);
+                       break;
+               case 2:
+                       random = tls_decrypt_ecc_dhe(context, &buf[res], size,
+                                       &out_len, 1);
+                       break;
+               default:
+                       random = decrypt_rsa(context, &buf[res], size,
+                                       &out_len);
+       }
+
+       if (random && out_len > 2) {
+               /* *(unsigned short *)&random[0] = htons(context->version); */
+               DEBUG_DUMP_HEX_LABEL("PRE MASTER KEY", random, out_len);
+               free(context->premaster_key);
+               context->premaster_key = random;
+               context->premaster_key_len = out_len;
+               tls_compute_key(context, 48);
+       } else {
+               free(random);
+               return 0;
+       }
+       res += size;
+       return res;
+}
+
+static const unsigned char *parse_signature(const unsigned char *buf, int
+               buf_len, int *hash_algorithm, int *sign_algorithm, int
+               *sig_size, int *offset) {
+       int res = 0;
+       if (buf_len < 2) {
+               return NULL;
+       }
+       *hash_algorithm = _md5_sha1;
+       *sign_algorithm = rsa_sign;
+       *sig_size = 0;
+       *hash_algorithm = buf[res];
+       res++;
+       *sign_algorithm = buf[res];
+       res++;
+       uint16_t size = get16(&buf[res]);
+       res += 2;
+       if (buf_len - res < size) {
+               return NULL;
+       }
+       DEBUG_DUMP_HEX(&buf[res], size);
+       *sig_size = size;
+       *offset = res + size;
+       return &buf[res];
+}
+
+int tls_parse_server_key_exchange(struct TLSContext *context,
+                                 const unsigned char *buf, int buf_len) {
+       int res = 0;
+       int dh_res = 0;
+       if (buf_len < 3) {
+               return TLS_NEED_MORE_DATA;
+       }
+       int size = get24(buf);
+       res += 3;
+       const unsigned char *packet_ref = buf + res;
+       if (buf_len - res < size) {
+               return TLS_NEED_MORE_DATA;
+       }
+
+       if (!size) {
+               return res;
+       }
+
+       unsigned char has_ds_params = 0;
+       int key_size = 0;
+       const struct ECCCurveParameters *curve = NULL;
+       const unsigned char *pk_key = NULL;
+       int ephemeral = tls_cipher_is_ephemeral(context);
+       if (ephemeral) {
+               if (ephemeral == 1) {
+                       has_ds_params = 1;
+               } else {
+                       if (buf[res++] != 3) {
+                               /* named curve */
+                               /* any other method is not supported */
+                               return 0;
+                       }
+                       if (buf_len - res < 3) {
+                               return TLS_NEED_MORE_DATA;
+                       }
+                       int iana_n = get16(&buf[res]);
+                       res += 2;
+                       key_size = buf[res];
+                       res++;
+                       if (buf_len - res < key_size) {
+                               return TLS_NEED_MORE_DATA;
+                       }
+                       DEBUG_PRINT("IANA CURVE NUMBER: %i\n", iana_n);
+                       switch (iana_n) {
+                               case 19:
+                                       curve = &secp192r1;
+                                       break;
+                               case 20:
+                                       curve = &secp224k1;
+                                       break;
+                               case 21:
+                                       curve = &secp224r1;
+                                       break;
+                               case 22:
+                                       curve = &secp256k1;
+                                       break;
+                               case 23:
+                                       curve = &secp256r1;
+                                       break;
+                               case 24:
+                                       curve = &secp384r1;
+                                       break;
+                               case 25:
+                                       curve = &secp521r1;
+                                       break;
+                               default:
+                                       DEBUG_PRINT("UNSUPPORTED CURVE\n");
+                                       return TLS_GENERIC_ERROR;
+                       }
+                       pk_key = &buf[res];
+                       res += key_size;
+                       context->curve = curve;
+               }
+       }
+
+       const unsigned char *dh_p = NULL;
+       int dh_p_len = 0;
+       const unsigned char *dh_g = NULL;
+       int dh_g_len = 0;
+       const unsigned char *dh_Ys = NULL;
+       int dh_Ys_len = 0;
+
+       if (has_ds_params) {
+               DEBUG_PRINT("          dh_p: ");
+               dh_res = parse_dh(&buf[res], buf_len - res, &dh_p, &dh_p_len);
+               if (dh_res <= 0) {
+                       return TLS_BROKEN_PACKET;
+               }
+               res += dh_res;
+               DEBUG_PRINT("\n");
+
+               DEBUG_PRINT("          dh_q: ");
+               dh_res = parse_dh(&buf[res], buf_len - res, &dh_g, &dh_g_len);
+               if (dh_res <= 0) {
+                       return TLS_BROKEN_PACKET;
+               }
+               res += dh_res;
+               DEBUG_PRINT("\n");
+
+               DEBUG_PRINT("          dh_Ys: ");
+               dh_res = parse_dh(&buf[res], buf_len - res, &dh_Ys,
+                               &dh_Ys_len);
+               if (dh_res <= 0) {
+                       return TLS_BROKEN_PACKET;
+               }
+               res += dh_res;
+               DEBUG_PRINT("\n");
+       }
+       int sign_size;
+       int hash_algorithm;
+       int sign_algorithm;
+       int packet_size = res - 3;
+       int offset = 0;
+       DEBUG_PRINT("          SIGNATURE (%i/%i/%i): ", packet_size,
+                   dh_res, key_size);
+       const unsigned char *signature =
+           parse_signature(&buf[res], buf_len - res, &hash_algorithm,
+                           &sign_algorithm, &sign_size, &offset);
+       DEBUG_PRINT("\n");
+       if (sign_size <= 0 || !signature) {
+               return TLS_BROKEN_PACKET;
+       }
+       res += offset;
+       /* check signature */
+       unsigned int message_len =
+           packet_size + TLS_CLIENT_RANDOM_SIZE + TLS_SERVER_RANDOM_SIZE;
+       unsigned char *message = malloc(message_len);
+       if (message) {
+               memcpy(message, context->local_random, TLS_CLIENT_RANDOM_SIZE);
+               memcpy(message + TLS_CLIENT_RANDOM_SIZE,
+                      context->remote_random, TLS_SERVER_RANDOM_SIZE);
+               memcpy(message + TLS_CLIENT_RANDOM_SIZE +
+                      TLS_SERVER_RANDOM_SIZE, packet_ref, packet_size);
+               if (tls_is_ecdsa(context)) {
+                       if (tls_verify_ecdsa
+                           (context, hash_algorithm, signature, sign_size,
+                            message, message_len, NULL) != 1) {
+                               DEBUG_PRINT
+                                   ("ECC Server signature FAILED!\n");
+                               free(message);
+                               return TLS_BROKEN_PACKET;
+                       }
+               } else
+               {
+                       if (verify_rsa(context, hash_algorithm, signature,
+                                               sign_size, message,
+                                               message_len) != 1) {
+                               DEBUG_PRINT("Server signature FAILED!\n");
+                               free(message);
+                               return TLS_BROKEN_PACKET;
+                       }
+               }
+               free(message);
+       }
+
+       if (buf_len - res) {
+               DEBUG_PRINT("EXTRA %i BYTES AT THE END OF MESSAGE\n",
+                           buf_len - res);
+               DEBUG_DUMP_HEX(&buf[res], buf_len - res);
+               DEBUG_PRINT("\n");
+       }
+
+       if (ephemeral == 1) {
+               tls_dhe_create(context);
+               DEBUG_DUMP_HEX_LABEL("DHP", dh_p, dh_p_len);
+               DEBUG_DUMP_HEX_LABEL("DHG", dh_g, dh_g_len);
+               int dhe_key_size = dh_p_len;
+               if (dh_g_len > dh_p_len) {
+                       dhe_key_size = dh_g_len;
+               }
+
+               if (tls_dh_make_key(dhe_key_size, context->dhe, (const char *)
+                                       dh_p, (const char *) dh_g, dh_p_len,
+                                       dh_g_len)) {
+                       DEBUG_PRINT("ERROR CREATING DHE KEY\n");
+                       free(context->dhe);
+                       context->dhe = NULL;
+                       return TLS_GENERIC_ERROR;
+               }
+
+               unsigned int dh_key_size = 0;
+               unsigned char *key = tls_decrypt_dhe(context, dh_Ys, dh_Ys_len,
+                               &dh_key_size, 0);
+               DEBUG_DUMP_HEX_LABEL("DH COMMON SECRET", key, dh_key_size);
+               if (key && dh_key_size) {
+                       free(context->premaster_key);
+                       context->premaster_key = key;
+                       context->premaster_key_len = dh_key_size;
+               }
+       } else if (ephemeral == 2 && curve && pk_key && key_size) {
+               tls_ecc_dhe_create(context);
+
+               ltc_ecc_set_type *dp = (ltc_ecc_set_type *) & curve->dp;
+               if (ecc_make_key_ex
+                   (NULL, find_prng("sprng"), context->ecc_dhe, dp)) {
+                       free(context->ecc_dhe);
+                       context->ecc_dhe = NULL;
+                       DEBUG_PRINT("Error generating ECC key\n");
+                       return TLS_GENERIC_ERROR;
+               }
+
+               free(context->premaster_key);
+               context->premaster_key_len = 0;
+
+               unsigned int out_len = 0;
+               context->premaster_key =
+                   tls_decrypt_ecc_dhe(context, pk_key, key_size,
+                                                &out_len, 0);
+               if (context->premaster_key) {
+                       context->premaster_key_len = out_len;
+               }
+       }
+
+       return res;
+}
+
+int tls_parse_client_key_exchange(struct TLSContext *context,
+                                 const unsigned char *buf, int buf_len) {
+       if (context->connection_status != 1) {
+               DEBUG_PRINT
+                   ("UNEXPECTED CLIENT KEY EXCHANGE MESSAGE (connections status: %i)\n",
+                    (int) context->connection_status);
+               return TLS_UNEXPECTED_MESSAGE;
+       }
+
+       int res = 0;
+       int dh_res = 0;
+       if (buf_len < 3) {
+               return TLS_NEED_MORE_DATA;
+       }
+       int size = get24(buf);
+       res += 3;
+
+       if (buf_len - res < size) {
+               return TLS_NEED_MORE_DATA;
+       }
+
+       if (!size) {
+               return res;
+       }
+
+       dh_res = tls_parse_random(context, &buf[res], size);
+       if (dh_res <= 0) {
+               DEBUG_PRINT("broken key\n");
+               return TLS_BROKEN_PACKET;
+       }
+       DEBUG_PRINT("\n");
+
+       res += size;
+       context->connection_status = 2;
+       return res;
+}
+
+static int tls_parse_server_hello_done(const unsigned char *buf, int buf_len) {
+       int res = 0;
+       if (buf_len < 3) {
+               return TLS_NEED_MORE_DATA;
+       }
+       int size = get24(buf);
+       res += 3;
+
+       if (buf_len - res < size) {
+               return TLS_NEED_MORE_DATA;
+       }
+
+       res += size;
+       return res;
+}
+
+int tls_parse_finished(struct TLSContext *context,
+                      const unsigned char *buf, int buf_len,
+                      unsigned int *write_packets) {
+       if (context->connection_status < 2
+           || context->connection_status == TLS_CONNECTED) {
+               DEBUG_PRINT("UNEXPECTED FINISHED MESSAGE\n");
+               return TLS_UNEXPECTED_MESSAGE;
+       }
+
+       int res = 0;
+       *write_packets = 0;
+       if (buf_len < 3) {
+               return TLS_NEED_MORE_DATA;
+       }
+       int size = get24(buf);
+       res += 3;
+
+       if (size < TLS_MIN_FINISHED_OPAQUE_LEN) {
+               DEBUG_PRINT("Invalid finished packet size: %i\n", size);
+               return TLS_BROKEN_PACKET;
+       }
+
+       if (buf_len - res < size) {
+               return TLS_NEED_MORE_DATA;
+       }
+
+       unsigned char hash[TLS_MAX_SHA_SIZE];
+       unsigned int hash_len = tls_get_hash(context, hash);
+
+       if (context->tlsver == TLS_VERSION13) {
+               unsigned char hash_out[TLS_MAX_SHA_SIZE];
+               unsigned long out_size = TLS_MAX_SHA_SIZE;
+               if (!context->remote_finished_key || !hash_len) {
+                       DEBUG_PRINT
+                           ("NO FINISHED KEY COMPUTED OR NO HANDSHAKE HASH\n");
+                       return TLS_NOT_VERIFIED;
+               }
+
+               DEBUG_DUMP_HEX_LABEL("HS HASH", hash, hash_len);
+               DEBUG_DUMP_HEX_LABEL("HS FINISH", context->remote_finished_key,
+                               hash_len);
+
+               out_size = hash_len;
+               hmac_state hmac;
+               hmac_init(&hmac, tls_get_hash_idx(context),
+                         context->remote_finished_key, hash_len);
+               hmac_process(&hmac, hash, hash_len);
+               hmac_done(&hmac, hash_out, &out_size);
+
+               if (size != (int)out_size || memcmp(hash_out, &buf[res], size)) {
+                       DEBUG_PRINT
+                           ("Finished validation error (sequence number, local: %i, remote: %i)\n",
+                            (int) context->local_sequence_number,
+                            (int) context->remote_sequence_number);
+                       DEBUG_DUMP_HEX_LABEL("FINISHED OPAQUE", &buf[res],
+                                            size);
+                       DEBUG_DUMP_HEX_LABEL("VERIFY", hash_out, out_size);
+                       return TLS_NOT_VERIFIED;
+               }
+               if (context->is_server) {
+                       context->connection_status = TLS_CONNECTED;
+                       res += size;
+                       _private_tls13_key(context, 0);
+                       context->local_sequence_number = 0;
+                       context->remote_sequence_number = 0;
+                       return res;
+               }
+               /* TODO client verify */
+       } else {
+               /* verify */
+               unsigned char *out = malloc(size);
+               if (!out) {
+                       DEBUG_PRINT("Error in malloc (%i bytes)\n",
+                                   (int) size);
+                       return TLS_NO_MEMORY;
+               }
+
+               /* server verifies client's message */
+               if (context->is_server) {
+                       tls_prf(context, out, size,
+                                        context->master_key,
+                                        context->master_key_len,
+                                        (unsigned char *)
+                                        "client finished", 15, hash,
+                                        hash_len, NULL, 0);
+               } else {
+                       tls_prf(context, out, size,
+                                        context->master_key,
+                                        context->master_key_len,
+                                        (unsigned char *)
+                                        "server finished", 15, hash,
+                                        hash_len, NULL, 0);
+               }
+
+               if (memcmp(out, &buf[res], size)) {
+                       free(out);
+                       DEBUG_PRINT
+                           ("Finished validation error (sequence number, local: %i, remote: %i)\n",
+                            (int) context->local_sequence_number,
+                            (int) context->remote_sequence_number);
+                       DEBUG_DUMP_HEX_LABEL("FINISHED OPAQUE", &buf[res],
+                                            size);
+                       DEBUG_DUMP_HEX_LABEL("VERIFY", out, size);
+                       return TLS_NOT_VERIFIED;
+               }
+               free(out);
+       }
+
+       if (context->is_server) {
+               *write_packets = 3;
+       } else {
+               context->connection_status = TLS_CONNECTED;
+       }
+
+       // fprintf(stderr, "set conn status = %d\n", context->connection_status);
+
+       res += size;
+       return res;
+}
+
+int tls_parse_verify_tls13(struct TLSContext *context,
+                          const unsigned char *buf, int buf_len) {
+       if (buf_len < 7) {
+               return TLS_NEED_MORE_DATA;
+       }
+       int size = get24(buf);
+
+       if (size < 2) {
+               return buf_len;
+       }
+
+       unsigned char signing_data[TLS_MAX_HASH_SIZE + 98];
+       int signing_data_len;
+
+       /* first 64 bytes to 0x20 (32) */
+       memset(signing_data, 0x20, 64);
+       /* context string 33 bytes */
+       if (context->is_server) {
+               memcpy(signing_data + 64,
+                      "TLS 1.3, server CertificateVerify", 33);
+       } else {
+               memcpy(signing_data + 64,
+                      "TLS 1.3, client CertificateVerify", 33);
+       }
+
+       /* a single 0 byte separator */
+       signing_data[97] = 0;
+       signing_data_len = 98;
+
+       signing_data_len += tls_get_hash(context, signing_data + 98);
+       DEBUG_DUMP_HEX_LABEL("signature data", signing_data, signing_data_len);
+       uint16_t signature = get16(&buf[3]);
+       uint16_t signature_size = get16(&buf[5]);
+       int valid = 0;
+       if (buf_len < size + 7) {
+               return TLS_NEED_MORE_DATA;
+       }
+       switch (signature) {
+               case 0x0403:
+                       /* secp256r1 + sha256 */
+                       valid =
+                               tls_verify_ecdsa(context, sha256, buf + 7,
+                                               signature_size, signing_data,
+                                               signing_data_len,
+                                               &secp256r1);
+                       break;
+               case 0x0503:
+                       /* secp384r1 + sha384 */
+                       valid = tls_verify_ecdsa(context, sha384, buf + 7,
+                                       signature_size, signing_data,
+                                       signing_data_len, &secp384r1);
+                       break;
+               case 0x0603:
+                       /* secp521r1 + sha512 */
+                       valid = tls_verify_ecdsa(context, sha512, buf + 7,
+                                       signature_size, signing_data,
+                                       signing_data_len, &secp521r1);
+                       break;
+               case 0x0804:
+                       valid = verify_rsa(context, sha256, buf + 7,
+                                       signature_size, signing_data,
+                                       signing_data_len);
+                       break;
+               default:
+                       DEBUG_PRINT("Unsupported signature: %x\n",
+                                       (int) signature);
+                       return TLS_UNSUPPORTED_CERTIFICATE;
+       }
+       if (valid != 1) {
+               DEBUG_PRINT("Signature FAILED!\n");
+               return TLS_DECRYPTION_FAILED;
+       }
+       return buf_len;
+}
+
+int tls_parse_verify(struct TLSContext *context, const unsigned char *buf,
+                    int buf_len) {
+       if (context->tlsver == TLS_VERSION13) {
+               return tls_parse_verify_tls13(context, buf, buf_len);
+       }
+
+       if (buf_len < 7) {
+               return TLS_BAD_CERTIFICATE;
+       }
+
+       int bytes_to_follow = get24(buf);
+
+       if (buf_len - 3 < bytes_to_follow) {
+               return TLS_BAD_CERTIFICATE;
+       }
+
+       int res = -1;
+
+       unsigned int hash = buf[3];
+       unsigned int algorithm = buf[4];
+       if (algorithm != rsa) {
+               return TLS_UNSUPPORTED_CERTIFICATE;
+       }
+       uint16_t size = get16(&buf[5]);
+       if (bytes_to_follow - 4 < size) {
+               return TLS_BAD_CERTIFICATE;
+       }
+       DEBUG_PRINT("ALGORITHM %i/%i (%i)\n", hash, algorithm, (int) size);
+       DEBUG_DUMP_HEX_LABEL("VERIFY", &buf[7], bytes_to_follow - 7);
+
+       res = verify_rsa(context, hash, &buf[7], size,
+                       context->cached_handshake.buffer,
+                       context->cached_handshake.len);
+
+       tls_buffer_free(&context->cached_handshake);
+       if (res == 1) {
+               DEBUG_PRINT("Signature OK\n");
+               context->client_verified = 1;
+       } else {
+               DEBUG_PRINT("Signature FAILED\n");
+               context->client_verified = 0;
+       }
+       return 1;
+}
+
+/* TODO This is actually a parse a handshake message */
+int tls_parse_payload(struct TLSContext *context, const unsigned char *buf,
+                     int buf_len) {
+       int orig_len = buf_len;
+
+       
+       if (context->connection_status == TLS_CONNECTED) {
+               if (context->version == TLS_V13) {
+                       tls_alert(context, 1, unexpected_message);
+               } else {
+                       tls_alert(context, 0, no_renegotiation_RESERVED);
+               }
+
+               return 1;
+       }
+
+       while (buf_len >= 4 && !context->critical_error) {
+               int payload_res = 0;
+               //unsigned char update_hash = 1;
+               unsigned char type = buf[0];
+               unsigned int write_packets = 0;
+               int certificate_verify_alert = no_error;
+               int payload_size = get24(buf+1) + 3;
+               if (buf_len < payload_size + 1) {
+                       return TLS_NEED_MORE_DATA;
+               }
+               switch (type) {
+                       case 0x00:
+                               /* hello request */
+                               CHECK_HANDSHAKE_STATE(context, 0, 1);
+                               DEBUG_PRINT
+                                       (" => HELLO REQUEST (RENEGOTIATION?)\n");
+                               if (context->is_server) {
+                                       payload_res = TLS_UNEXPECTED_MESSAGE;
+                               } else {
+                                       if (context->connection_status == TLS_CONNECTED) {
+                                               /* renegotiation */
+                                               payload_res = TLS_NO_RENEGOTIATION;
+                                       } else {
+                                               payload_res = TLS_UNEXPECTED_MESSAGE;
+                                       }
+                               }
+                               /* no payload */
+                               break;
+                       case 0x01:
+                               /* client hello */
+                               CHECK_HANDSHAKE_STATE(context, 1, 1);
+                               DEBUG_PRINT(" => CLIENT HELLO\n");
+                               if (context->is_server) {
+                                       payload_res =
+                                               tls_parse_client_hello(context,
+                                                               buf + 1,
+                                                               payload_size,
+                                                               &write_packets);
+                               } else {
+                                       payload_res = TLS_UNEXPECTED_MESSAGE;
+                               }
+                               break;
+                       case 0x02:
+                               /* server hello */
+                               CHECK_HANDSHAKE_STATE(context, 2, 1);
+                               DEBUG_PRINT(" => SERVER HELLO\n");
+                               if (context->is_server) {
+                                       payload_res = TLS_UNEXPECTED_MESSAGE;
+                               } else {
+                                       write_packets = 0;
+                                       payload_res = tls_parse_server_hello(context, buf + 1, payload_size);
+                               }
+                               break;
+                       case 0x03:
+                               /* hello verify request */
+                               DEBUG_PRINT(" => VERIFY REQUEST\n");
+                               CHECK_HANDSHAKE_STATE(context, 3, 1);
+                               payload_res = TLS_UNEXPECTED_MESSAGE;
+                               break;
+                       case 0x0B:
+                               /* certificate */
+                               CHECK_HANDSHAKE_STATE(context, 4, 1);
+                               DEBUG_PRINT(" => CERTIFICATE\n");
+                               if (context->tlsver == TLS_VERSION13) {
+                                       if (context->connection_status == 2) {
+                                               payload_res =
+                                                       tls_parse_certificate(context,
+                                                                       buf + 1,
+                                                                       payload_size,
+                                                                       context->
+                                                                       is_server);
+                                               if (context->is_server) {
+                                                       if (context->certificate_verify && context->client_certificates_count) {
+                                                               certificate_verify_alert
+                                                                       =
+                                                                       context->certificate_verify(context,
+                                                                        context->client_certificates,
+                                                                        context->client_certificates_count);
+                                                       }
+                                                       /* empty certificates are permitted for client */
+                                                       if (payload_res <= 0) {
+                                                               payload_res = 1;
+                                                       }
+                                               }
+                                       } else
+                                               payload_res =
+                                                       TLS_UNEXPECTED_MESSAGE;
+                               } else
+                                       if (context->connection_status == 1) {
+                                               if (context->is_server) {
+                                                       /* client certificate */
+                                                       payload_res =
+                                                               tls_parse_certificate(context,
+                                                                               buf + 1,
+                                                                               payload_size,
+                                                                               1);
+                                                       if (context->certificate_verify && context->client_certificates_count) {
+                                                               certificate_verify_alert =
+                                                                       context->certificate_verify
+                                                                       (context,
+                                                                        context->
+                                                                        client_certificates,
+                                                                        context->
+                                                                        client_certificates_count);
+                                                       }
+                                                       /* empty certificates are permitted for client */
+                                                       if (payload_res <= 0)
+                                                               payload_res = 1;
+                                               } else {
+                                                       payload_res =
+                                                               tls_parse_certificate(context,
+                                                                               buf + 1,
+                                                                               payload_size,
+                                                                               0);
+                                                       if (certificate_verify && context->certificates_count) {
+                                                               certificate_verify_alert =
+                                                                       context->certificate_verify
+                                                                       (context,
+                                                                        context->certificates,
+                                                                        context->
+                                                                        certificates_count);
+                                                       }
+                                               }
+                                       } else {
+                                               payload_res = TLS_UNEXPECTED_MESSAGE;
+                                       }
+                               break;
+                       case 0x0C:
+                               /* server key exchange */
+                               CHECK_HANDSHAKE_STATE(context, 5, 1);
+                               DEBUG_PRINT(" => SERVER KEY EXCHANGE\n");
+                               if (context->is_server) {
+                                       payload_res = TLS_UNEXPECTED_MESSAGE;
+                               } else {
+                                       payload_res =
+                                               tls_parse_server_key_exchange(context,
+                                                               buf + 1,
+                                                               payload_size);
+                               }
+                               break;
+                       case 0x0D:
+                               /* certificate request */
+                               CHECK_HANDSHAKE_STATE(context, 6, 1);
+                               /* server to client */
+                               if (context->is_server) {
+                                       payload_res = TLS_UNEXPECTED_MESSAGE;
+                               } else {
+                                       context->client_verified = 2;
+                               }
+                               DEBUG_PRINT(" => CERTIFICATE REQUEST\n");
+                               break;
+                       case 0x0E:
+                               /* server hello done */
+                               CHECK_HANDSHAKE_STATE(context, 7, 1);
+                               DEBUG_PRINT(" => SERVER HELLO DONE\n");
+                               if (context->is_server) {
+                                       payload_res = TLS_UNEXPECTED_MESSAGE;
+                               } else {
+                                       payload_res =
+                                               tls_parse_server_hello_done(
+                                                               buf + 1,
+                                                               payload_size);
+                                       if (payload_res > 0) {
+                                               write_packets = 1;
+                                       }
+                               }
+                               break;
+                       case 0x0F:
+                               /* certificate verify */
+                               CHECK_HANDSHAKE_STATE(context, 8, 1);
+                               DEBUG_PRINT(" => CERTIFICATE VERIFY\n");
+                               if (context->connection_status == 2) {
+                                       payload_res =
+                                               tls_parse_verify(context, buf + 1,
+                                                               payload_size);
+                               } else {
+                                       payload_res = TLS_UNEXPECTED_MESSAGE;
+                               }
+                               break;
+                       case 0x10:
+                               /* client key exchange */
+                               CHECK_HANDSHAKE_STATE(context, 9, 1);
+                               DEBUG_PRINT(" => CLIENT KEY EXCHANGE\n");
+                               if (context->is_server) {
+                                       payload_res =
+                                               tls_parse_client_key_exchange(context,
+                                                               buf + 1,
+                                                               payload_size);
+                               } else {
+                                       payload_res = TLS_UNEXPECTED_MESSAGE;
+                               }
+                               break;
+                       case 0x14:
+                               /* finished */
+                               tls_buffer_free(&context->cached_handshake);
+                               CHECK_HANDSHAKE_STATE(context, 10, 1);
+                               DEBUG_PRINT(" => FINISHED\n");
+                               payload_res = tls_parse_finished(context,
+                                               buf + 1, payload_size,
+                                               &write_packets);
+                               if (payload_res > 0) {
+                                       memset(context->hs_messages, 0,
+                                                       sizeof(context->hs_messages));
+                               }
+                               break;
+                       default:
+                               DEBUG_PRINT
+                                       (" => NOT UNDERSTOOD PAYLOAD TYPE: %x\n",
+                                        (int) type);
+                               return TLS_NOT_UNDERSTOOD;
+               }
+
+               //if (type != 0x00 && update_hash) {
+               if (type != 0x00) {
+                       tls_update_hash(context, buf, payload_size + 1);
+               }
+
+               if (certificate_verify_alert != no_error) {
+                       tls_alert(context, 1, certificate_verify_alert);
+                       context->critical_error = 1;
+               }
+
+               if (payload_res < 0) {
+                       switch (payload_res) {
+                               case TLS_UNEXPECTED_MESSAGE:
+                                       tls_alert(context, 1, unexpected_message);
+                                       break;
+                               case TLS_COMPRESSION_NOT_SUPPORTED:
+                                       tls_alert(context, 1, decompression_failure_RESERVED);
+                                       break;
+                               case TLS_BROKEN_PACKET:
+                                       tls_alert(context, 1, decode_error);
+                                       break;
+                               case TLS_NO_MEMORY:
+                                       tls_alert(context, 1, internal_error);
+                                       break;
+                               case TLS_NOT_VERIFIED:
+                                       tls_alert(context, 1, bad_record_mac);
+                                       break;
+                               case TLS_BAD_CERTIFICATE:
+                                       if (context->is_server) {
+                                               /* bad client certificate, continue */
+                                               tls_alert(context, 0, bad_certificate);
+                                               payload_res = 0;
+                                       } else {
+                                               tls_alert(context, 1, bad_certificate);
+                                       }
+                                       break;
+                               case TLS_UNSUPPORTED_CERTIFICATE:
+                                       tls_alert(context, 1, unsupported_certificate);
+                                       break;
+                               case TLS_NO_COMMON_CIPHER:
+                                       tls_alert(context, 1, insufficient_security);
+                                       break;
+                               case TLS_NOT_UNDERSTOOD:
+                                       tls_alert(context, 1, internal_error);
+                                       break;
+                               case TLS_NO_RENEGOTIATION:
+                                       tls_alert(context, 0, no_renegotiation_RESERVED);
+                                       payload_res = 0;
+                                       break;
+                               case TLS_DECRYPTION_FAILED:
+                                       tls_alert(context, 1, decryption_failed_RESERVED);
+                                       break;
+                       }
+                       if (payload_res < 0) {
+                               return payload_res;
+                       }
+               }
+
+               if (certificate_verify_alert != no_error) {
+                       payload_res = TLS_BAD_CERTIFICATE;
+               }
+
+               /* except renegotiation */
+               struct TLSPacket *pkt;
+               switch (write_packets) {
+                       case 1:
+                               if (context->client_verified == 2) {
+                                       DEBUG_PRINT("<= Building CERTIFICATE \n");
+                                       tls_send_certificate(context);
+                                       context->client_verified = 0;
+                               }
+
+                               /* client handshake */
+                               tls_send_client_key_exchange(context);
+                               tls_send_change_cipher_spec(context);
+
+                               context->cipher_spec_set = 1;
+                               context->local_sequence_number = 0;
+
+                               tls_send_finished(context);
+
+                               context->cipher_spec_set = 0;
+                               break;
+                       case 2:
+                               /* server handshake */
+                               DEBUG_PRINT("<= SENDING SERVER HELLO\n");
+                               if (context->connection_status == 3) {
+                                       context->connection_status = 2;
+                                       tls_queue_packet
+                                               (tls_build_hello(context, 0));
+                                       tls_send_change_cipher_spec(context);
+                                       _private_tls13_key(context, 1);
+                                       context->cipher_spec_set = 1;
+                                       DEBUG_PRINT
+                                               ("<= SENDING ENCRYPTED EXTENSIONS\n");
+                                       tls_send_encrypted_extensions(context);
+
+                                       if (context->request_client_certificate) {
+                                               DEBUG_PRINT
+                                                       ("<= SENDING CERTIFICATE REQUEST\n");
+                                               tls_queue_packet
+                                                       (tls_certificate_request
+                                                        (context));
+                                       }
+
+                                       tls_send_certificate(context);
+
+                                       tls_send_certificate_verify(context);
+
+                                       tls_send_finished(context);
+
+                                       /* new key */
+                                       free(context->server_finished_hash);
+
+                                       context->server_finished_hash =
+                                               malloc(tls_mac_length(context));
+
+                                       if (context->server_finished_hash) {
+                                               tls_get_hash(context,
+                                                               context->server_finished_hash);
+                                       }
+
+                                       break;
+                               }
+                               tls_queue_packet(tls_build_hello(context, 0));
+                               DEBUG_PRINT("<= SENDING CERTIFICATE\n");
+                               tls_send_certificate(context);
+
+                               int ephemeral_cipher =
+                                       tls_cipher_is_ephemeral(context);
+                               if (ephemeral_cipher) {
+                                       DEBUG_PRINT
+                                               ("<= SENDING EPHEMERAL DH KEY\n");
+                                       tls_send_server_key_exchange(context,
+                                                       ephemeral_cipher == 1 ?
+                                                       KEA_dhe_rsa :
+                                                       KEA_ec_diffie_hellman);
+                               }
+                               if (context->request_client_certificate) {
+                                       DEBUG_PRINT
+                                               ("<= SENDING CERTIFICATE REQUEST\n");
+                                       tls_queue_packet
+                                               (tls_certificate_request
+                                                (context));
+                               }
+                               tls_send_done(context);
+                               break;
+                       case 3:
+                               /* finished */
+                               tls_send_change_cipher_spec(context);
+                               tls_send_finished(context);
+                               context->connection_status = TLS_CONNECTED;
+                               break;
+                       case 4:
+                               /* dtls only */
+                               /* TODO error */
+                               break;
+                       case 5:
+                               /* hello retry request */
+                               DEBUG_PRINT("<= SENDING HELLO RETRY REQUEST\n");
+                               pkt = tls_build_hello(context, 0);
+                               tls_queue_packet(pkt);
+                               break;
+               }
+               payload_size++;
+               buf += payload_size;
+               buf_len -= payload_size;
+       }
+       return orig_len;
+}
+
+unsigned int asn1_get_len(const unsigned char *buffer, int buf_len,
+                         unsigned int *octets) {
+       *octets = 0;
+
+       if (buf_len < 1) {
+               return 0;
+       }
+
+       unsigned char size = buffer[0];
+       int i;
+       if (size & 0x80) {
+               *octets = size & 0x7F;
+               if ((int) *octets > buf_len - 1) {
+                       return 0;
+               }
+               /* max 32 bits */
+               unsigned int ref_octets = *octets;
+               if (*octets > 4) {
+                       ref_octets = 4;
+               }
+               if ((int) *octets > buf_len - 1) {
+                       return 0;
+               }
+               unsigned int long_size = 0;
+               unsigned int coef = 1;
+
+               for (i = ref_octets; i > 0; i--) {
+                       long_size += buffer[i] * coef;
+                       coef *= 0x100;
+               }
+               ++*octets;
+               return long_size;
+       }
+       ++*octets;
+       return size;
+}
+
+void print_index(const unsigned int *fields) {
+       int i = 0;
+       while (fields[i]) {
+               if (i) {
+                       DEBUG_PRINT(".");
+               }
+               DEBUG_PRINT("%i", fields[i]);
+               i++;
+       }
+       while (i < 6) {
+               DEBUG_PRINT("  ");
+               i++;
+       }
+}
+
+int _is_field(const unsigned int *fields, const unsigned int *prefix) {
+       int i = 0;
+       while (prefix[i]) {
+               if (fields[i] != prefix[i]) {
+                       return 0;
+               }
+               i++;
+       }
+       return 1;
+}
+
+static int tls_hash_len(int algorithm) {
+       switch (algorithm) {
+               case TLS_RSA_SIGN_MD5:
+                       return 16;
+               case TLS_RSA_SIGN_SHA1:
+                       return 20;
+               case TLS_RSA_SIGN_SHA256:
+                       return 32;
+               case TLS_RSA_SIGN_SHA384:
+                       return 48;
+               case TLS_RSA_SIGN_SHA512:
+                       return 64;
+       }
+       return 0;
+}
+
+static unsigned char *tls_compute_hash(int algorithm, const unsigned char
+               *message, unsigned int message_len) {
+       unsigned char *hash = NULL;
+       int err;
+       int hash_index = -1;
+       unsigned long hash_len = 0;
+
+       if (!message || !message_len) {
+               return hash;
+       }
+
+       switch (algorithm) {
+               case TLS_RSA_SIGN_MD5:
+                       DEBUG_PRINT("SIGN MD5\n");
+                       hash_index = find_hash("md5");
+                       hash_len = 16;
+                       break;
+               case TLS_RSA_SIGN_SHA1:
+                       DEBUG_PRINT("SIGN SHA1\n");
+                       hash_index = find_hash("sha1");
+                       hash_len = 20;
+                       break;
+               case TLS_RSA_SIGN_SHA256:
+                       DEBUG_PRINT("SIGN SHA256\n");
+                       hash_index = find_hash("sha256");
+                       hash_len = 32;
+                       break;
+               case TLS_RSA_SIGN_SHA384:
+                       DEBUG_PRINT("SIGN SHA384\n");
+                       hash_index = find_hash("sha384");
+                       hash_len = 48;
+                       break;
+               case TLS_RSA_SIGN_SHA512:
+                       DEBUG_PRINT("SIGN SHA512\n");
+                       hash_index = find_hash("sha512");
+                       hash_len = 64;
+                       break;
+               default:
+                       DEBUG_PRINT("UNKNOWN SIGNATURE ALGORITHM\n");
+                       return NULL;
+                       break;
+       }
+
+       hash = malloc(hash_len);
+       if (!hash) {
+               return NULL;
+       }
+
+       err = hash_memory(hash_index, message, message_len, hash, &hash_len);
+       if (err) {
+               return NULL;
+       }
+       return hash;
+}
+
+int tls_certificate_verify_signature(struct TLSCertificate *cert,
+                                    struct TLSCertificate *parent) {
+       if (!cert || !parent || !cert->sign_key
+           || !cert->fingerprint || !cert->sign_len
+           || !parent->der_bytes || !parent->der_len) {
+               DEBUG_PRINT("CANNOT VERIFY SIGNATURE ");
+               if (!cert) {
+                       DEBUG_PRINT("!cert ");
+               } else {
+                       if (!cert->sign_key) {
+                               DEBUG_PRINT("!cert->sign_key ");
+                       }
+                       if (!cert->fingerprint) {
+                               DEBUG_PRINT("!cert->fingerprint ");
+                       }
+                       if (!cert->sign_len) {
+                               DEBUG_PRINT("!cert->sign_len ");
+                       }
+               }
+
+               if (!parent) {
+                       DEBUG_PRINT("!parent ");
+               } else {
+                       if (!parent->der_bytes) {
+                               DEBUG_PRINT("!parent->der_bytes ");
+                       }
+                       if (!parent->der_len) {
+                               DEBUG_PRINT("!parent->der_len ");
+                       }
+               }
+               DEBUG_PRINT("\n");
+
+               return 0;
+       }
+       DEBUG_PRINT("checking alg\n");
+       int hash_len = tls_hash_len(cert->algorithm);
+       if (hash_len <= 0) {
+               return 0;
+       }
+
+       int hash_index;
+       switch (cert->algorithm) {
+               case TLS_RSA_SIGN_MD5:
+                       hash_index = find_hash("md5");
+                       break;
+               case TLS_RSA_SIGN_SHA1:
+                       hash_index = find_hash("sha1");
+                       break;
+               case TLS_RSA_SIGN_SHA256:
+                       hash_index = find_hash("sha256");
+                       break;
+               case TLS_RSA_SIGN_SHA384:
+                       hash_index = find_hash("sha384");
+                       break;
+               case TLS_RSA_SIGN_SHA512:
+                       hash_index = find_hash("sha512");
+                       break;
+               default:
+                       DEBUG_PRINT("UNKNOWN SIGNATURE ALGORITHM\n");
+                       return 0;
+       }
+
+       rsa_key key;
+       DEBUG_PRINTLN("rsa_import(%p, %d, %p)\n", parent->der_bytes,
+                     parent->der_len, &key);
+       int err = rsa_import(parent->der_bytes, parent->der_len, &key);
+       if (err) {
+               DEBUG_PRINTLN
+                   ("Error importing RSA certificate (code: %i)\n", err);
+               DEBUG_PRINT("Message: %s\n", error_to_string(err));
+               DEBUG_DUMP_HEX_LABEL("CERTIFICATE", parent->der_bytes,
+                                    parent->der_len);
+               return 0;
+       }
+       int rsa_stat = 0;
+       unsigned char *signature = cert->sign_key;
+       int signature_len = cert->sign_len;
+       if (!signature[0]) {
+               signature++;
+               signature_len--;
+       }
+
+       err = rsa_verify_hash_ex(signature, signature_len, cert->fingerprint,
+                       hash_len, LTC_PKCS_1_V1_5, hash_index, 0, &rsa_stat,
+                       &key);
+
+       rsa_free(&key);
+       if (err) {
+               DEBUG_PRINT("HASH VERIFY ERROR %i\n", err);
+               return 0;
+       }
+       DEBUG_PRINT("CERTIFICATE VALIDATION: %i\n", rsa_stat);
+       return rsa_stat;
+}
+
+int tls_certificate_chain_is_valid(struct TLSCertificate **certificates,
+                                  int len) {
+       if (!certificates || !len) {
+               return bad_certificate;
+       }
+
+       int i;
+       DEBUG_PRINT("verifying %i length cert chain\n", len);
+       len--;
+
+       /* expired certificate or not yet valid ? */
+       if (tls_certificate_is_valid(certificates[0])) {
+               return bad_certificate;
+       }
+
+       /* check */
+       for (i = 0; i < len; i++) {
+               /* certificate in chain is expired ? */
+               if (tls_certificate_is_valid(certificates[i + 1])) {
+                       return bad_certificate;
+               }
+
+               if (!tls_certificate_verify_signature(certificates[i],
+                                       certificates[i + 1])) {
+                       DEBUG_PRINT
+                           ("tls_certificate_verify_signature certs[%d], certs[%d+1] failed\n",
+                            i, i);
+                       return bad_certificate;
+               }
+
+       }
+       return 0;
+}
+
+int tls_certificate_chain_is_valid_root(struct TLSContext *context, struct
+               TLSCertificate **certificates, int len) {
+       int i, j;
+
+       if (!certificates || !len || !context->root_certificates
+           || !context->root_count) {
+               return bad_certificate;
+       }
+       for (i = 0; i < len; i++) {
+               for (j = 0; j < context->root_count; j++) {
+                       /* check if root certificate expired */
+                       if (tls_certificate_is_valid
+                           (context->root_certificates[j])) {
+                               continue;
+                       }
+                       /* if any root validates any certificate in the chain,
+                        * then is root validated */
+                       if (tls_certificate_verify_signature(certificates[i],
+                                               context->root_certificates[j]))
+                       {
+                               return 0;
+                       }
+               }
+       }
+       return bad_certificate;
+}
+
+int _private_is_oid(struct OID_chain *ref_chain,
+                   const unsigned char *looked_oid, int looked_oid_len) {
+       while (ref_chain) {
+               if (ref_chain->oid) {
+                       if (_is_oid2
+                           (ref_chain->oid, looked_oid, 16,
+                            looked_oid_len)) {
+                               return 1;
+                       }
+               }
+               ref_chain = (struct OID_chain *) ref_chain->top;
+       }
+       return 0;
+}
+
+int _private_asn1_parse(struct TLSContext *context,
+                       struct TLSCertificate *cert,
+                       const unsigned char *buffer, int size, int level,
+                       unsigned int *fields, unsigned char *has_key,
+                       int client_cert, unsigned char *top_oid,
+                       struct OID_chain *chain) {
+       struct OID_chain local_chain;
+       DEBUG_INDEX(fields);
+       DEBUG_PRINT("\n");
+       local_chain.top = chain;
+       int pos = 0;
+       /* X.690 */
+       int idx = 0;
+       unsigned char oid[16];
+       memset(oid, 0, 16);
+       local_chain.oid = oid;
+       if (has_key) {
+               *has_key = 0;
+       }
+       unsigned char local_has_key = 0;
+       const unsigned char *cert_data = NULL;
+       unsigned int cert_len = 0;
+       while (pos < size) {
+               unsigned int start_pos = pos;
+               if (size - pos < 2) {
+                       return TLS_NEED_MORE_DATA;
+               }
+               unsigned char first = buffer[pos++];
+               unsigned char type = first & 0x1F;
+               unsigned char constructed = first & 0x20;
+               unsigned char element_class = first >> 6;
+               int octets = 0;
+               unsigned int temp;
+               idx++;
+               if (level <= TLS_ASN1_MAXLEVEL) {
+                       fields[level - 1] = idx;
+               }
+               DEBUG_INDEX(fields);
+               DEBUG_PRINT("\n");
+               int length = asn1_get_len((unsigned char *) &buffer[pos], size
+                               - pos, &octets);
+               DEBUG_PRINT("asn1_get_len = %u\n", length);
+               if ((octets > 4) || (octets > size - pos)) {
+                       DEBUG_PRINT
+                           ("CANNOT READ CERTIFICATE octets = %d, size = %d pos = %d, size - pos = %d\n",
+                            octets, size, pos, size - pos);
+                       return pos;
+               }
+               pos += octets;
+
+               if (size - pos < length) {
+                       return TLS_NEED_MORE_DATA;
+               }
+
+               /*DEBUG_PRINT("FIRST: %x => %x (%i)\n", (int)first, (int)type, length); */
+               /* sequence */
+               /*DEBUG_PRINT("%2i: ", level); */
+#ifdef DEBUG
+               DEBUG_INDEX(fields);
+               int i1;
+               for (i1 = 1; i1 < level; i1++) {
+                       DEBUG_PRINT("  ");
+               }
+#endif
+
+               if (length && constructed) {
+                       switch (type) {
+                               case 0x03:
+                                       DEBUG_PRINT("CONSTRUCTED BITSTREAM\n");
+                                       break;
+                               case 0x10:
+                               DEBUG_PRINT("SEQUENCE\n");
+                               if ((level == 2) && (idx == 1)) {
+                                       cert_len =
+                                           length + (pos - start_pos);
+                                       cert_data = &buffer[start_pos];
+                               }
+                               /* private key on server or public key on client */
+                               if (!cert->version
+                                   && (_is_field(fields, priv_der_id))) {
+                                       free(cert->der_bytes);
+                                       temp = length + (pos - start_pos);
+                                       cert->der_bytes = malloc(temp);
+                                       if (cert->der_bytes) {
+                                               memcpy(cert->der_bytes,
+                                                      &buffer[start_pos],
+                                                      temp);
+                                               cert->der_len = temp;
+                                       } else
+                                               cert->der_len = 0;
+                               }
+                               break;
+                       case 0x11:
+                               DEBUG_PRINT("EMBEDDED PDV\n");
+                               break;
+                       case 0x00:
+                               if (element_class == 0x02) {
+                                       DEBUG_PRINT("CONTEXT-SPECIFIC\n");
+                                       break;
+                               }
+                       default:
+                               DEBUG_PRINT("CONSTRUCT TYPE %02X\n",(int)type);
+                       }
+
+                       local_has_key = 0;
+                       _private_asn1_parse(context, cert, &buffer[pos],
+                                           length, level + 1, fields,
+                                           &local_has_key, client_cert,
+                                           top_oid, &local_chain);
+                       if (((local_has_key && context
+                             && (!context->is_server || client_cert))
+                            || !context)
+                           && (_is_field(fields, pk_id))) {
+                               free(cert->der_bytes);
+                               temp = length + (pos - start_pos);
+                               cert->der_bytes = malloc(temp);
+                               if (cert->der_bytes) {
+                                       memcpy(cert->der_bytes,
+                                              &buffer[start_pos], temp);
+                                       cert->der_len = temp;
+                               } else {
+                                       cert->der_len = 0;
+                               }
+                       }
+               } else {
+                       switch (type) {
+                       case 0x00:
+                               /* end of content */
+                               DEBUG_PRINT("END OF CONTENT\n");
+                               return pos;
+                               break;
+                       case 0x01:
+                               /* boolean */
+                               temp = buffer[pos];
+                               DEBUG_PRINT("BOOLEAN: %i\n", temp);
+                               break;
+                       case 0x02:
+                               /* integer */
+                               if (_is_field(fields, pk_id)) {
+                                       if (has_key) {
+                                               *has_key = 1;
+                                       }
+
+                                       if (idx == 1) {
+                                               tls_certificate_set_key
+                                                   (cert, &buffer[pos],
+                                                    length);
+                                       } else if (idx == 2) {
+                                               tls_certificate_set_exponent
+                                                   (cert, &buffer[pos],
+                                                    length);
+                                       }
+                               } else if (_is_field(fields, serial_id)) {
+                                       tls_certificate_set_serial(cert,
+                                                                  &buffer
+                                                                  [pos],
+                                                                  length);
+                               }
+
+                               if (_is_field(fields, version_id)) {
+                                       if (length == 1) {
+                                               cert->version =
+                                                   buffer[pos];
+                                       }
+#ifdef TLS_X509_V1_SUPPORT
+                                       else {
+                                               cert->version = 0;
+                                       }
+                                       idx++;
+#endif
+                               }
+                               if (level >= 2) {
+                                       unsigned int fields_temp[3];
+                                       fields_temp[0] = fields[level - 2];
+                                       fields_temp[1] = fields[level - 1];
+                                       fields_temp[2] = 0;
+                                       if (_is_field
+                                           (fields_temp, priv_id)) {
+                                               tls_certificate_set_priv
+                                                   (cert, &buffer[pos],
+                                                    length);
+                                       }
+                               }
+                               DEBUG_PRINT("INTEGER(%i): ", length);
+                               DEBUG_DUMP_HEX(&buffer[pos], length);
+                               if ((chain) && (length > 2)) {
+                                       if (_private_is_oid
+                                           (chain, san_oid,
+                                            sizeof(san_oid) - 1)) {
+                                               void *new;
+
+                                               new =
+                                                   TLS_REALLOC(cert->san,
+                                                               sizeof
+                                                               (unsigned
+                                                                char *) *
+                                                               (cert->
+                                                                san_length
+                                                                + 1));
+                                               if (new) {
+                                                       cert->san = new;
+                                                       cert->san[cert->
+                                                                 san_length]
+                                                           = NULL;
+                                                       tls_certificate_set_copy
+                                                           (&cert->
+                                                            san[cert->
+                                                                san_length],
+                                                            &buffer[pos],
+                                                            length);
+                                                       DEBUG_PRINT
+                                                           (" => SUBJECT ALTERNATIVE NAME: %s",
+                                                            cert->
+                                                            san[cert->
+                                                                san_length]);
+                                                       cert->san_length++;
+                                               } else {
+                                                       free(cert->
+                                                                san);
+                                                       cert->san = 0;
+                                                       cert->san_length =
+                                                           0;
+                                               }
+                                       }
+                               }
+                               DEBUG_PRINT("\n");
+                               break;
+                       case 0x03:
+                               if (_is_field(fields, pk_id)) {
+                                       if (has_key)
+                                               *has_key = 1;
+                               }
+                               /* bitstream */
+                               DEBUG_PRINT("BITSTREAM(%i): ", length);
+                               DEBUG_DUMP_HEX(&buffer[pos], length);
+                               DEBUG_PRINT("\n");
+                               if (_is_field(fields, sign_id)
+                                   || _is_field(fields, sign_id2)) {
+                                       DEBUG_PRINT("set sign key\n");
+                                       tls_certificate_set_sign_key(cert,
+                                                                    &buffer
+                                                                    [pos],
+                                                                    length);
+                               } else if (cert->ec_algorithm
+                                          && (_is_field(fields, pk_id))) {
+                                       tls_certificate_set_key(cert,
+                                                               &buffer
+                                                               [pos],
+                                                               length);
+                               } else {
+                                       if (buffer[pos] == 0x00
+                                           && length > 256) {
+                                               _private_asn1_parse
+                                                   (context, cert,
+                                                    &buffer[pos] + 1,
+                                                    length - 1, level + 1,
+                                                    fields,
+                                                    &local_has_key,
+                                                    client_cert, top_oid,
+                                                    &local_chain);
+                                       } else {
+                                               _private_asn1_parse
+                                                   (context, cert,
+                                                    &buffer[pos], length,
+                                                    level + 1, fields,
+                                                    &local_has_key,
+                                                    client_cert, top_oid,
+                                                    &local_chain);
+                                       }
+
+                                       if (top_oid) {
+                                               if (_is_oid2
+                                                   (top_oid,
+                                                    TLS_EC_prime256v1_OID,
+                                                    sizeof(oid),
+                                                    sizeof
+                                                    (TLS_EC_prime256v1) -
+                                                    1)) {
+                                                       cert->
+                                                           ec_algorithm =
+                                                           secp256r1.iana;
+                                               } else
+                                                   if (_is_oid2
+                                                       (top_oid,
+                                                        TLS_EC_secp224r1_OID,
+                                                        sizeof(oid),
+                                                        sizeof
+                                                        (TLS_EC_secp224r1_OID)
+                                                        - 1)) {
+                                                       cert->
+                                                           ec_algorithm =
+                                                           secp224r1.iana;
+                                               } else
+                                                   if (_is_oid2
+                                                       (top_oid,
+                                                        TLS_EC_secp384r1_OID,
+                                                        sizeof(oid),
+                                                        sizeof
+                                                        (TLS_EC_secp384r1_OID)
+                                                        - 1)) {
+                                                       cert->
+                                                           ec_algorithm =
+                                                           secp384r1.iana;
+                                               } else
+                                                   if (_is_oid2
+                                                       (top_oid,
+                                                        TLS_EC_secp521r1_OID,
+                                                        sizeof(oid),
+                                                        sizeof
+                                                        (TLS_EC_secp521r1_OID)
+                                                        - 1)) {
+                                                       cert->
+                                                           ec_algorithm =
+                                                           secp521r1.iana;
+                                               }
+                                               if ((cert->ec_algorithm)
+                                                   && (!cert->pk))
+                                                       tls_certificate_set_key
+                                                           (cert,
+                                                            &buffer[pos],
+                                                            length);
+                                       }
+                               }
+                               break;
+                       case 0x04:
+                               if (top_oid && _is_field(fields, ecc_priv_id)
+                                               && !cert->priv) {
+                                       DEBUG_PRINT("BINARY STRING(%i): ",
+                                                   length);
+                                       DEBUG_DUMP_HEX(&buffer[pos],
+                                                      length);
+                                       DEBUG_PRINT("\n");
+                                       tls_certificate_set_priv(cert,
+                                                                &buffer
+                                                                [pos],
+                                                                length);
+                               } else {
+                                       _private_asn1_parse(context, cert,
+                                                           &buffer[pos],
+                                                           length,
+                                                           level + 1,
+                                                           fields,
+                                                           &local_has_key,
+                                                           client_cert,
+                                                           top_oid,
+                                                           &local_chain);
+                               }
+                               break;
+                       case 0x05:
+                               DEBUG_PRINT("NULL\n");
+                               break;
+                       case 0x06:
+                               /* object identifier */
+                               if (_is_field(fields, pk_id)) {
+                                       if (length == 8 || length == 5) {
+                                               tls_certificate_set_algorithm
+                                                   (&cert->ec_algorithm,
+                                                    &buffer[pos], length);
+                                       } else {
+                                               tls_certificate_set_algorithm
+                                                   (&cert->key_algorithm,
+                                                    &buffer[pos], length);
+                                       }
+                               }
+                               if (_is_field(fields, algorithm_id))
+                                       tls_certificate_set_algorithm
+                                           (&cert->algorithm,
+                                            &buffer[pos], length);
+
+                               DEBUG_PRINT("OBJECT IDENTIFIER(%i): ", length);
+                               DEBUG_DUMP_HEX(&buffer[pos], length);
+                               DEBUG_PRINT("\n");
+                               /* check previous oid */
+                               if (_is_oid2
+                                   (oid, ocsp_oid, 16,
+                                    sizeof(ocsp_oid) - 1))
+                                       tls_certificate_set_copy(&cert->ocsp,
+                                                                &buffer[pos],
+                                                                length);
+
+                               if (length < 16) {
+                                       memcpy(oid, &buffer[pos], length);
+                               } else {
+                                       memcpy(oid, &buffer[pos], 16);
+                               }
+                               if (top_oid)
+                                       memcpy(top_oid, oid, 16);
+                               break;
+                       case 0x09:
+                               DEBUG_PRINT("REAL NUMBER(%i): ", length);
+                               DEBUG_DUMP_HEX(&buffer[pos], length);
+                               DEBUG_PRINT("\n");
+                               break;
+                       case 0x17:
+                               /* utc time */
+                               DEBUG_PRINT("UTC TIME: [");
+                               DEBUG_DUMP(&buffer[pos], length);
+                               DEBUG_PRINT("]\n");
+
+                               if (_is_field(fields, validity_id)) {
+                                       if (idx == 1) {
+                                               tls_certificate_set_copy_date
+                                                   (cert->not_before,
+                                                    &buffer[pos], length);
+                                       } else {
+                                               tls_certificate_set_copy_date
+                                                   (cert->not_after,
+                                                    &buffer[pos], length);
+                                       }
+                               }
+                               break;
+                       case 0x18:
+                               /* generalized time */
+                               DEBUG_PRINT("GENERALIZED TIME: [");
+                               DEBUG_DUMP(&buffer[pos], length);
+                               DEBUG_PRINT("]\n");
+                               break;
+                       case 0x13:
+                               /* printable string */
+                       case 0x0C:
+                       case 0x14:
+                       case 0x15:
+                       case 0x16:
+                       case 0x19:
+                       case 0x1A:
+                       case 0x1B:
+                       case 0x1C:
+                       case 0x1D:
+                       case 0x1E:
+                               if (_is_field(fields, issurer_id)) {
+                                       if (_is_oid(oid, country_oid, 3)) {
+                                               tls_certificate_set_copy
+                                                   (&cert->issuer_country,
+                                                    &buffer[pos], length);
+                                       } else if (_is_oid
+                                                (oid, state_oid, 3)) {
+                                               tls_certificate_set_copy
+                                                   (&cert->issuer_state,
+                                                    &buffer[pos], length);
+                                       } else if (_is_oid
+                                                (oid, location_oid, 3)) {
+                                               tls_certificate_set_copy
+                                                   (&cert->
+                                                    issuer_location,
+                                                    &buffer[pos], length);
+                                       } else if (_is_oid
+                                                (oid, entity_oid, 3)) {
+                                               tls_certificate_set_copy
+                                                   (&cert->issuer_entity,
+                                                    &buffer[pos], length);
+                                       } else if (_is_oid
+                                                (oid, subject_oid, 3)) {
+                                               tls_certificate_set_copy
+                                                   (&cert->issuer_subject,
+                                                    &buffer[pos], length);
+                                       }
+                               } else if (_is_field(fields, owner_id)) {
+                                       if (_is_oid(oid, country_oid, 3)) {
+                                               tls_certificate_set_copy
+                                                   (&cert->country,
+                                                    &buffer[pos], length);
+                                       } else if (_is_oid
+                                                (oid, state_oid, 3)) {
+                                               tls_certificate_set_copy
+                                                   (&cert->state,
+                                                    &buffer[pos], length);
+                                       } else if (_is_oid
+                                                (oid, location_oid, 3)) {
+                                               tls_certificate_set_copy
+                                                   (&cert->location,
+                                                    &buffer[pos], length);
+                                       } else if (_is_oid
+                                                (oid, entity_oid, 3)) {
+                                               tls_certificate_set_copy
+                                                   (&cert->entity,
+                                                    &buffer[pos], length);
+                                       } else if (_is_oid
+                                                (oid, subject_oid, 3)) {
+                                               tls_certificate_set_copy
+                                                   (&cert->subject,
+                                                    &buffer[pos], length);
+                                       }
+                               }
+                               DEBUG_PRINT("STR: [");
+                               DEBUG_DUMP(&buffer[pos], length);
+                               DEBUG_PRINT("]\n");
+                               break;
+                       case 0x10:
+                               DEBUG_PRINT("EMPTY SEQUENCE\n");
+                               break;
+                       case 0xA:
+                               DEBUG_PRINT("ENUMERATED(%i): ", length);
+                               DEBUG_DUMP_HEX(&buffer[pos], length);
+                               DEBUG_PRINT("\n");
+                               break;
+                       default:
+                               DEBUG_PRINT("========> NOT SUPPORTED %x\n",
+                                           (int) type);
+                               /* not supported / needed */
+                               break;
+                       }
+               }
+               pos += length;
+       }
+
+       if (level == 2 && cert->sign_key && cert->sign_len
+           && cert_len && cert_data) {
+               free(cert->fingerprint);
+               cert->fingerprint = tls_compute_hash(cert->algorithm,
+                               cert_data, cert_len);
+#ifdef DEBUG
+               if (cert->fingerprint) {
+                       DEBUG_DUMP_HEX_LABEL("FINGERPRINT",
+                                            cert->fingerprint,
+                                            tls_hash_len(cert->algorithm));
+               }
+#endif
+       }
+       return pos;
+}
+
+struct TLSCertificate *asn1_parse(struct TLSContext *context,
+                                 const unsigned char *buffer, int size,
+                                 int client_cert) {
+       unsigned int fields[TLS_ASN1_MAXLEVEL] = { 0 };
+
+       struct TLSCertificate *cert = tls_create_certificate();
+
+       if (cert) {
+               if (client_cert < 0) {
+                       client_cert = 0;
+                       /* private key */
+                       unsigned char top_oid[16];
+                       memset(top_oid, 0, sizeof(top_oid));
+                       _private_asn1_parse(context, cert, buffer, size, 1,
+                                           fields, NULL, client_cert,
+                                           top_oid, NULL);
+               } else {
+                       _private_asn1_parse(context, cert, buffer, size, 1,
+                                           fields, NULL, client_cert,
+                                           NULL, NULL);
+               }
+       }
+       return cert;
+}
+
+int tls_clear_certificates(struct TLSContext *tls) {
+       int i;
+
+       if (!tls || !tls->is_server || tls->is_child) {
+               return TLS_GENERIC_ERROR;
+       }
+
+       if (tls->root_certificates) {
+               for (i = 0; i < tls->root_count; i++) {
+                       tls_destroy_certificate(tls->root_certificates[i]);
+               }
+       }
+       tls->root_certificates = NULL;
+       tls->root_count = 0;
+
+       if (tls->private_key) {
+               tls_destroy_certificate(tls->private_key);
+       }
+       tls->private_key = NULL;
+       if (tls->ec_private_key) {
+               tls_destroy_certificate(tls->ec_private_key);
+       }
+       tls->ec_private_key = NULL;
+       free(tls->certificates);
+       tls->certificates = NULL;
+       tls->certificates_count = 0;
+       return 0;
+}
+
+/* This is just a wrapper around parse message so we don't
+ * call read more often than necessary.  IOW, if there's
+ * more than one record in the input buffer, process them all
+ */
+int tls_consume_stream(struct TLSContext *context) {
+       if (!context) {
+               return TLS_GENERIC_ERROR;
+       }
+
+       if (context->critical_error) {
+               return TLS_BROKEN_CONNECTION;
+       }
+
+       size_t tls_buffer_len = context->input_buffer.len;
+       unsigned char *buffer = context->input_buffer.buffer;
+
+       unsigned int index = 0;
+       int err_flag = 0;
+
+       int tls_header_size;
+       int tls_size_offset;
+
+       tls_size_offset = 3;
+       tls_header_size = 5;
+
+       while (tls_buffer_len >= 5) {
+               uint16_t length;
+
+               length = get16(buffer + index + tls_size_offset)
+                   + tls_header_size;
+
+               if (length > tls_buffer_len) {
+                       /* record not complete */
+                       break;
+               }
+
+               /* This is the only place tls_parse_message is called */
+               int consumed = tls_parse_message(context, buffer+index, length);
+               if (consumed < 0) {
+                       err_flag = consumed;
+                       break;
+               }
+               index += length;
+               tls_buffer_len -= length;
+               if (context->critical_error) {
+                       err_flag = TLS_BROKEN_CONNECTION;
+                       break;
+               }
+       }
+
+       if (err_flag || context->input_buffer.error) {
+               if (!context->critical_error) {
+                       context->critical_error = 1;
+               }
+               DEBUG_PRINT("ERROR IN CONSUME: %i\n", err_flag);
+               tls_buffer_free(&context->input_buffer);
+               return err_flag;
+       }
+       tls_buffer_shift(&context->input_buffer, index);
+       return index;
+}
+
+void tls_close_notify(struct TLSContext *context) {
+       if (!context || context->critical_error) {
+               return;
+       }
+       context->critical_error = 1;
+       DEBUG_PRINT("CLOSE\n");
+       tls_alert(context, 0, close_notify);
+}
+
+void tls_alert(struct TLSContext *context, int critical, int code) {
+       if (!context) {
+               return;
+       }
+
+       struct TLSPacket *packet = tls_create_packet(context, TLS_ALERT,
+                       context->version, 0);
+       tls_packet_uint8(packet, critical ? TLS_ALERT_CRITICAL :
+                       TLS_ALERT_WARNING);
+
+       tls_packet_uint8(packet, code);
+       tls_packet_update(packet);
+
+       if (critical) {
+               context->critical_error = 1;
+       }
+
+       tls_queue_packet(packet);
+}
+
+int tls_is_broken(struct TLSContext *context) {
+       if (!context || context->critical_error) {
+               return 1;
+       }
+       return 0;
+}
+
+/* TODO I don't see that this ever gets cleared */
+int tls_request_client_certificate(struct TLSContext *context) {
+       if (!context || !context->is_server) {
+               return 0;
+       }
+
+       context->request_client_certificate = 1;
+       return 1;
+}
+
+int tls_client_verified(struct TLSContext *context) {
+       if (!context || context->critical_error) {
+               return 0;
+       }
+
+       return context->client_verified == 1;
+}
+
+int tls_sni_set(struct TLSContext *context, const char *sni) {
+       if (!context || context->is_server || context->critical_error
+           || context->connection_status != 0) {
+               return 0;
+       }
+
+       free(context->sni);
+       errno = 0;
+       context->sni = sni ? strdup(sni) : 0;
+       return context->sni ? 1 : 0;
+}
+
+int tls_default_verify(struct TLSContext *context,
+                      struct TLSCertificate **certificate_chain, int len) 
+{
+       int i;
+       int err;
+
+       if (certificate_chain) {
+               for (i = 0; i < len; i++) {
+                       struct TLSCertificate *certificate =
+                           certificate_chain[i];
+                       /* check validity date */
+                       err = tls_certificate_is_valid(certificate);
+                       if (err) {
+                               return err;
+                       }
+               }
+       }
+       /* check if chain is valid */
+       err = tls_certificate_chain_is_valid(certificate_chain, len);
+       if (err) {
+               return err;
+       }
+
+       /* check certificate subject */
+       if (!context->is_server && context->sni && len > 0
+           && certificate_chain) {
+               err = tls_certificate_valid_subject(certificate_chain[0],
+                               context->sni);
+               if (err) {
+                       return err;
+               }
+       }
+
+       err = tls_certificate_chain_is_valid_root(context, certificate_chain,
+                                               len);
+       if (err) {
+               return err;
+       }
+
+       DEBUG_PRINT("Certificate OK\n");
+       return no_error;
+}
+
+ssize_t tls_fsync(struct TLSContext *context) {
+       size_t buflen = 0;
+       size_t offset = 0;
+       ssize_t send_res = 0;
+       int fd;
+       unsigned char *buffer;
+       tls_send_func write_cb = NULL;
+
+       if (!context) {
+               return 0;
+       }
+
+       fd = context->fd;
+       if (fd < 0) {
+               return -1;
+       }
+
+       buffer = context->output_buffer.buffer;
+       buflen = context->output_buffer.len;
+
+       if (context->send) {
+               write_cb = context->send;
+       } else {
+               write_cb = send;
+       }
+
+       while (buflen > 0) {
+               ssize_t res;
+               errno = 0;
+               res = write_cb(fd, buffer+offset, buflen, 0);
+               if (res <= 0) {
+                       perror("send error");
+                       send_res = res;
+                       break;
+               }
+               buflen -= res;
+               offset += res;
+               send_res += res;
+       }
+       DEBUG_PRINT("sent %zd bytes\n", send_res);
+       context->output_buffer.len = 0;
+       return send_res;
+}
+
+void tls_free(struct TLSContext *context) {
+       if (context) {
+               free(context->user_data);
+               tls_destroy_context(context);
+       }
+}
+
+int tls_set_fd(struct TLSContext *context, int socket) {
+       if (!context) {
+               return TLS_GENERIC_ERROR;
+       }
+       context->fd = socket;
+       return 0;
+}
+
+int tls_load_root_file(struct TLSContext *context, const char *pem_filename) {
+       int fd;
+       struct stat st;
+       void *addr;
+
+       if (!context) {
+               return -1;
+       }
+
+       int count = -1;
+
+       fd = open(pem_filename, O_RDONLY);
+       if (fd == -1) {
+               return -1;
+       }
+
+       if (fstat(fd, &st) == -1) {
+               close(fd);
+               return -1;
+       }
+
+       addr = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+       if (addr == MAP_FAILED) {
+               close(fd);
+               return -1;
+       }
+
+       count = tls_load_root_certificates(context, addr, st.st_size);
+       munmap(addr, st.st_size);
+       close(fd);
+
+       return count;
+}
+
+void tls_set_verify(struct TLSContext *tls, tls_validation_function vfunc) {
+       if (tls) {
+               tls->certificate_verify = vfunc;
+       }
+}
+
+static ssize_t tls_safe_read(struct TLSContext *tls) {
+       tls_recv_func read_cb;
+       char buffer[8192];
+       ssize_t bytes;
+
+       if (!tls || tls->fd <= 0) {
+               return TLS_GENERIC_ERROR;
+       }
+
+       if (tls->recv) {
+               read_cb = tls->recv;
+       } else {
+               read_cb = recv;
+       }
+
+       errno = 0;
+       bytes = read_cb(tls->fd, buffer, sizeof buffer, 0);
+       if (bytes > 0) {
+               tls_buffer_append(&tls->input_buffer, buffer, bytes);
+       }
+
+       return bytes;
+}
+
+/* I think this is the server handshake */
+int SSL_accept(struct TLSContext *context) {
+       ssize_t read_size = 0;
+
+       if (!context || context->fd <= 0) {
+               return TLS_GENERIC_ERROR;
+       }
+
+       if (tls_established(context)) {
+               return 1;
+       }
+
+       /* accept */
+       while ((read_size = tls_safe_read(context)) > 0) {
+               if (tls_consume_stream(context) >= 0) {
+                       ssize_t res = tls_fsync(context);
+                       if (res < 0) {
+                               return res;
+                       }
+               }
+               if (tls_established(context)) {
+                       return 1;
+               }
+       }
+       if (read_size <= 0) {
+               return TLS_BROKEN_CONNECTION;
+       }
+       return 0;
+}
+
+/* TODO this is really do the handshake */
+int tls_connect(struct TLSContext *context) {
+       int res;
+       ssize_t read_size;
+
+       if (!context || context->fd <= 0 || context->critical_error) {
+               return TLS_GENERIC_ERROR;
+       }
+
+       if (context->is_server) {
+               return TLS_UNEXPECTED_MESSAGE;
+       }
+
+       res = tls_queue_packet(tls_build_client_hello(context));
+
+       if (res < 0) {
+               return res;
+       }
+
+       res = tls_fsync(context);
+       if (res < 0) {
+               return res;
+       }
+
+       while ((read_size = tls_safe_read(context)) > 0) {
+               if ((res = tls_consume_stream(context)) >= 0) {
+                       res = tls_fsync(context);
+                       if (res < 0) {
+                               return res;
+                       }
+               }
+               if (tls_established(context)) {
+                       return 1;
+               }
+               if (context->critical_error) {
+                       return TLS_GENERIC_ERROR;
+               }
+       }
+       return read_size;
+}
+
+int tls_shutdown(struct TLSContext *tls) {
+       if (!tls || tls->fd <= 0) {
+               return TLS_GENERIC_ERROR;
+       }
+
+       tls_close_notify(tls);
+       return 0;
+}
+
+/* TODO configure for maximum packet data length
+ * max is 2^14 - 5 byte header - 32 byte mac - padding which depends
+ * on the cipher (up to 255 bytes I think).
+ */
+ssize_t tls_write(struct TLSContext *context, const void *buf, size_t count) {
+       if (!context) {
+               return TLS_GENERIC_ERROR;
+       }
+       if (context->connection_status != TLS_CONNECTED) {
+               return TLS_UNEXPECTED_MESSAGE;
+       }
+       if (count > TLS_MAXTLS_APP_SIZE) {
+               count = TLS_MAXTLS_APP_SIZE;
+       }
+
+       if (!buf || !count) {
+               return 0;
+       }
+
+       struct TLSPacket *packet = tls_create_packet(context,
+                       TLS_APPLICATION_DATA, context->version, count);
+       tls_packet_append(packet, buf, count);
+       tls_packet_update(packet);
+
+       tls_queue_packet(packet);
+       /* TODO think about this.  context->sync with O_NONBLOCK might be a
+        * problem
+        */
+       if (context->sync) {
+               ssize_t res;
+               res = tls_fsync(context);
+               if (res == -1) {
+                       return res;
+               }
+       }
+       return count;
+}
+
+static ssize_t tls_readbuf(struct TLSContext *tls, void *buf, size_t count) {
+       if (count > tls->application_buffer.len) {
+               count = tls->application_buffer.len;
+       }
+
+       if (count > 0) {
+               /* TODO should have a buffer read and shift */
+               memcpy(buf, tls->application_buffer.buffer, count);
+               tls_buffer_shift(&tls->application_buffer, count);
+       }
+
+       return count;
+}
+
+ssize_t tls_read(struct TLSContext *context, void *buf, size_t count) {
+       if (!context) {
+               return TLS_GENERIC_ERROR;
+       }
+
+       if (context->application_buffer.len) {
+               return tls_readbuf(context, buf, count);
+       }
+
+       if (context->fd <= 0 || context->critical_error) {
+               return TLS_GENERIC_ERROR;
+       }
+
+       if (tls_established(context) != 1) {
+               return TLS_GENERIC_ERROR;
+       }
+
+       if (context->application_buffer.len == 0 && !context->critical_error) {
+               /* attempt to fill buffer, unless we're already in an error
+                * state
+                */
+               ssize_t read_size;
+
+               while ((read_size = tls_safe_read(context)) > 0) {
+                       if (tls_consume_stream(context) > 0) {
+                               tls_fsync(context);
+                               break;
+                       }
+                       if (context->critical_error
+                           && !context->application_buffer.len) {
+                               /* if there's a critical error, don't bail if
+                                * we managed to get some data
+                                */
+                               return TLS_GENERIC_ERROR;
+                       }
+               }
+
+               if (read_size <= 0 && context->application_buffer.len == 0) {
+                       /* can return errors as for read(2) */
+                       return read_size;
+               }
+       }
+
+       return tls_readbuf(context, buf, count);
+}
diff --git a/libtomcrypt/src/ciphers/aes/aes.c b/libtomcrypt/src/ciphers/aes/aes.c
new file mode 100644 (file)
index 0000000..5c1dcd1
--- /dev/null
@@ -0,0 +1,743 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+/* AES implementation by Tom St Denis
+ *
+ * Derived from the Public Domain source code by
+
+---
+  * rijndael-alg-fst.c
+  *
+  * @version 3.0 (December 2000)
+  *
+  * Optimised ANSI C code for the Rijndael cipher (now AES)
+  *
+  * @author Vincent Rijmen <vincent.rijmen@esat.kuleuven.ac.be>
+  * @author Antoon Bosselaers <antoon.bosselaers@esat.kuleuven.ac.be>
+  * @author Paulo Barreto <paulo.barreto@terra.com.br>
+---
+ */
+/**
+  @file aes.c
+  Implementation of AES
+*/
+
+#include "tomcrypt.h"
+
+#ifdef LTC_RIJNDAEL
+
+#ifndef ENCRYPT_ONLY
+
+#define SETUP    rijndael_setup
+#define ECB_ENC  rijndael_ecb_encrypt
+#define ECB_DEC  rijndael_ecb_decrypt
+#define ECB_DONE rijndael_done
+#define ECB_TEST rijndael_test
+#define ECB_KS   rijndael_keysize
+
+const struct ltc_cipher_descriptor rijndael_desc =
+{
+    "rijndael",
+    6,
+    16, 32, 16, 10,
+    SETUP, ECB_ENC, ECB_DEC, ECB_TEST, ECB_DONE, ECB_KS,
+    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
+};
+
+const struct ltc_cipher_descriptor aes_desc =
+{
+    "aes",
+    6,
+    16, 32, 16, 10,
+    SETUP, ECB_ENC, ECB_DEC, ECB_TEST, ECB_DONE, ECB_KS,
+    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
+};
+
+#else
+
+#define SETUP    rijndael_enc_setup
+#define ECB_ENC  rijndael_enc_ecb_encrypt
+#define ECB_KS   rijndael_enc_keysize
+#define ECB_DONE rijndael_enc_done
+
+const struct ltc_cipher_descriptor rijndael_enc_desc =
+{
+    "rijndael",
+    6,
+    16, 32, 16, 10,
+    SETUP, ECB_ENC, NULL, NULL, ECB_DONE, ECB_KS,
+    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
+};
+
+const struct ltc_cipher_descriptor aes_enc_desc =
+{
+    "aes",
+    6,
+    16, 32, 16, 10,
+    SETUP, ECB_ENC, NULL, NULL, ECB_DONE, ECB_KS,
+    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
+};
+
+#endif
+
+#define __LTC_AES_TAB_C__
+#include "aes_tab.c"
+
+static ulong32 setup_mix(ulong32 temp)
+{
+   return (Te4_3[byte(temp, 2)]) ^
+          (Te4_2[byte(temp, 1)]) ^
+          (Te4_1[byte(temp, 0)]) ^
+          (Te4_0[byte(temp, 3)]);
+}
+
+#ifndef ENCRYPT_ONLY
+#ifdef LTC_SMALL_CODE
+static ulong32 setup_mix2(ulong32 temp)
+{
+   return Td0(255 & Te4[byte(temp, 3)]) ^
+          Td1(255 & Te4[byte(temp, 2)]) ^
+          Td2(255 & Te4[byte(temp, 1)]) ^
+          Td3(255 & Te4[byte(temp, 0)]);
+}
+#endif
+#endif
+
+ /**
+    Initialize the AES (Rijndael) block cipher
+    @param key The symmetric key you wish to pass
+    @param keylen The key length in bytes
+    @param num_rounds The number of rounds desired (0 for default)
+    @param skey The key in as scheduled by this function.
+    @return CRYPT_OK if successful
+ */
+int SETUP(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey)
+{
+    int i;
+    ulong32 temp, *rk;
+#ifndef ENCRYPT_ONLY
+    ulong32 *rrk;
+#endif
+    LTC_ARGCHK(key  != NULL);
+    LTC_ARGCHK(skey != NULL);
+
+    if (keylen != 16 && keylen != 24 && keylen != 32) {
+       return CRYPT_INVALID_KEYSIZE;
+    }
+
+    if (num_rounds != 0 && num_rounds != (10 + ((keylen/8)-2)*2)) {
+       return CRYPT_INVALID_ROUNDS;
+    }
+
+    skey->rijndael.Nr = 10 + ((keylen/8)-2)*2;
+
+    /* setup the forward key */
+    i                 = 0;
+    rk                = skey->rijndael.eK;
+    LOAD32H(rk[0], key     );
+    LOAD32H(rk[1], key +  4);
+    LOAD32H(rk[2], key +  8);
+    LOAD32H(rk[3], key + 12);
+    if (keylen == 16) {
+        for (;;) {
+            temp  = rk[3];
+            rk[4] = rk[0] ^ setup_mix(temp) ^ rcon[i];
+            rk[5] = rk[1] ^ rk[4];
+            rk[6] = rk[2] ^ rk[5];
+            rk[7] = rk[3] ^ rk[6];
+            if (++i == 10) {
+               break;
+            }
+            rk += 4;
+        }
+    } else if (keylen == 24) {
+        LOAD32H(rk[4], key + 16);
+        LOAD32H(rk[5], key + 20);
+        for (;;) {
+        #ifdef _MSC_VER
+            temp = skey->rijndael.eK[rk - skey->rijndael.eK + 5];
+        #else
+            temp = rk[5];
+        #endif
+            rk[ 6] = rk[ 0] ^ setup_mix(temp) ^ rcon[i];
+            rk[ 7] = rk[ 1] ^ rk[ 6];
+            rk[ 8] = rk[ 2] ^ rk[ 7];
+            rk[ 9] = rk[ 3] ^ rk[ 8];
+            if (++i == 8) {
+                break;
+            }
+            rk[10] = rk[ 4] ^ rk[ 9];
+            rk[11] = rk[ 5] ^ rk[10];
+            rk += 6;
+        }
+    } else if (keylen == 32) {
+        LOAD32H(rk[4], key + 16);
+        LOAD32H(rk[5], key + 20);
+        LOAD32H(rk[6], key + 24);
+        LOAD32H(rk[7], key + 28);
+        for (;;) {
+        #ifdef _MSC_VER
+            temp = skey->rijndael.eK[rk - skey->rijndael.eK + 7];
+        #else
+            temp = rk[7];
+        #endif
+            rk[ 8] = rk[ 0] ^ setup_mix(temp) ^ rcon[i];
+            rk[ 9] = rk[ 1] ^ rk[ 8];
+            rk[10] = rk[ 2] ^ rk[ 9];
+            rk[11] = rk[ 3] ^ rk[10];
+            if (++i == 7) {
+                break;
+            }
+            temp = rk[11];
+            rk[12] = rk[ 4] ^ setup_mix(RORc(temp, 8));
+            rk[13] = rk[ 5] ^ rk[12];
+            rk[14] = rk[ 6] ^ rk[13];
+            rk[15] = rk[ 7] ^ rk[14];
+            rk += 8;
+        }
+    } else {
+       /* this can't happen */
+       /* coverity[dead_error_line] */
+       return CRYPT_ERROR;
+    }
+
+#ifndef ENCRYPT_ONLY
+    /* setup the inverse key now */
+    rk   = skey->rijndael.dK;
+    rrk  = skey->rijndael.eK + (28 + keylen) - 4;
+
+    /* apply the inverse MixColumn transform to all round keys but the first and the last: */
+    /* copy first */
+    *rk++ = *rrk++;
+    *rk++ = *rrk++;
+    *rk++ = *rrk++;
+    *rk   = *rrk;
+    rk -= 3; rrk -= 3;
+
+    for (i = 1; i < skey->rijndael.Nr; i++) {
+        rrk -= 4;
+        rk  += 4;
+    #ifdef LTC_SMALL_CODE
+        temp = rrk[0];
+        rk[0] = setup_mix2(temp);
+        temp = rrk[1];
+        rk[1] = setup_mix2(temp);
+        temp = rrk[2];
+        rk[2] = setup_mix2(temp);
+        temp = rrk[3];
+        rk[3] = setup_mix2(temp);
+     #else
+        temp = rrk[0];
+        rk[0] =
+            Tks0[byte(temp, 3)] ^
+            Tks1[byte(temp, 2)] ^
+            Tks2[byte(temp, 1)] ^
+            Tks3[byte(temp, 0)];
+        temp = rrk[1];
+        rk[1] =
+            Tks0[byte(temp, 3)] ^
+            Tks1[byte(temp, 2)] ^
+            Tks2[byte(temp, 1)] ^
+            Tks3[byte(temp, 0)];
+        temp = rrk[2];
+        rk[2] =
+            Tks0[byte(temp, 3)] ^
+            Tks1[byte(temp, 2)] ^
+            Tks2[byte(temp, 1)] ^
+            Tks3[byte(temp, 0)];
+        temp = rrk[3];
+        rk[3] =
+            Tks0[byte(temp, 3)] ^
+            Tks1[byte(temp, 2)] ^
+            Tks2[byte(temp, 1)] ^
+            Tks3[byte(temp, 0)];
+      #endif
+
+    }
+
+    /* copy last */
+    rrk -= 4;
+    rk  += 4;
+    *rk++ = *rrk++;
+    *rk++ = *rrk++;
+    *rk++ = *rrk++;
+    *rk   = *rrk;
+#endif /* ENCRYPT_ONLY */
+
+    return CRYPT_OK;
+}
+
+/**
+  Encrypts a block of text with AES
+  @param pt The input plaintext (16 bytes)
+  @param ct The output ciphertext (16 bytes)
+  @param skey The key as scheduled
+  @return CRYPT_OK if successful
+*/
+#ifdef LTC_CLEAN_STACK
+static int _rijndael_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey)
+#else
+int ECB_ENC(const unsigned char *pt, unsigned char *ct, symmetric_key *skey)
+#endif
+{
+    ulong32 s0, s1, s2, s3, t0, t1, t2, t3, *rk;
+    int Nr, r;
+
+    LTC_ARGCHK(pt != NULL);
+    LTC_ARGCHK(ct != NULL);
+    LTC_ARGCHK(skey != NULL);
+
+    Nr = skey->rijndael.Nr;
+    rk = skey->rijndael.eK;
+
+    /*
+     * map byte array block to cipher state
+     * and add initial round key:
+     */
+    LOAD32H(s0, pt      ); s0 ^= rk[0];
+    LOAD32H(s1, pt  +  4); s1 ^= rk[1];
+    LOAD32H(s2, pt  +  8); s2 ^= rk[2];
+    LOAD32H(s3, pt  + 12); s3 ^= rk[3];
+
+#ifdef LTC_SMALL_CODE
+
+    for (r = 0; ; r++) {
+        rk += 4;
+        t0 =
+            Te0(byte(s0, 3)) ^
+            Te1(byte(s1, 2)) ^
+            Te2(byte(s2, 1)) ^
+            Te3(byte(s3, 0)) ^
+            rk[0];
+        t1 =
+            Te0(byte(s1, 3)) ^
+            Te1(byte(s2, 2)) ^
+            Te2(byte(s3, 1)) ^
+            Te3(byte(s0, 0)) ^
+            rk[1];
+        t2 =
+            Te0(byte(s2, 3)) ^
+            Te1(byte(s3, 2)) ^
+            Te2(byte(s0, 1)) ^
+            Te3(byte(s1, 0)) ^
+            rk[2];
+        t3 =
+            Te0(byte(s3, 3)) ^
+            Te1(byte(s0, 2)) ^
+            Te2(byte(s1, 1)) ^
+            Te3(byte(s2, 0)) ^
+            rk[3];
+        if (r == Nr-2) {
+           break;
+        }
+        s0 = t0; s1 = t1; s2 = t2; s3 = t3;
+    }
+    rk += 4;
+
+#else
+
+    /*
+     * Nr - 1 full rounds:
+     */
+    r = Nr >> 1;
+    for (;;) {
+        t0 =
+            Te0(byte(s0, 3)) ^
+            Te1(byte(s1, 2)) ^
+            Te2(byte(s2, 1)) ^
+            Te3(byte(s3, 0)) ^
+            rk[4];
+        t1 =
+            Te0(byte(s1, 3)) ^
+            Te1(byte(s2, 2)) ^
+            Te2(byte(s3, 1)) ^
+            Te3(byte(s0, 0)) ^
+            rk[5];
+        t2 =
+            Te0(byte(s2, 3)) ^
+            Te1(byte(s3, 2)) ^
+            Te2(byte(s0, 1)) ^
+            Te3(byte(s1, 0)) ^
+            rk[6];
+        t3 =
+            Te0(byte(s3, 3)) ^
+            Te1(byte(s0, 2)) ^
+            Te2(byte(s1, 1)) ^
+            Te3(byte(s2, 0)) ^
+            rk[7];
+
+        rk += 8;
+        if (--r == 0) {
+            break;
+        }
+
+        s0 =
+            Te0(byte(t0, 3)) ^
+            Te1(byte(t1, 2)) ^
+            Te2(byte(t2, 1)) ^
+            Te3(byte(t3, 0)) ^
+            rk[0];
+        s1 =
+            Te0(byte(t1, 3)) ^
+            Te1(byte(t2, 2)) ^
+            Te2(byte(t3, 1)) ^
+            Te3(byte(t0, 0)) ^
+            rk[1];
+        s2 =
+            Te0(byte(t2, 3)) ^
+            Te1(byte(t3, 2)) ^
+            Te2(byte(t0, 1)) ^
+            Te3(byte(t1, 0)) ^
+            rk[2];
+        s3 =
+            Te0(byte(t3, 3)) ^
+            Te1(byte(t0, 2)) ^
+            Te2(byte(t1, 1)) ^
+            Te3(byte(t2, 0)) ^
+            rk[3];
+    }
+
+#endif
+
+    /*
+     * apply last round and
+     * map cipher state to byte array block:
+     */
+    s0 =
+        (Te4_3[byte(t0, 3)]) ^
+        (Te4_2[byte(t1, 2)]) ^
+        (Te4_1[byte(t2, 1)]) ^
+        (Te4_0[byte(t3, 0)]) ^
+        rk[0];
+    STORE32H(s0, ct);
+    s1 =
+        (Te4_3[byte(t1, 3)]) ^
+        (Te4_2[byte(t2, 2)]) ^
+        (Te4_1[byte(t3, 1)]) ^
+        (Te4_0[byte(t0, 0)]) ^
+        rk[1];
+    STORE32H(s1, ct+4);
+    s2 =
+        (Te4_3[byte(t2, 3)]) ^
+        (Te4_2[byte(t3, 2)]) ^
+        (Te4_1[byte(t0, 1)]) ^
+        (Te4_0[byte(t1, 0)]) ^
+        rk[2];
+    STORE32H(s2, ct+8);
+    s3 =
+        (Te4_3[byte(t3, 3)]) ^
+        (Te4_2[byte(t0, 2)]) ^
+        (Te4_1[byte(t1, 1)]) ^
+        (Te4_0[byte(t2, 0)]) ^
+        rk[3];
+    STORE32H(s3, ct+12);
+
+    return CRYPT_OK;
+}
+
+#ifdef LTC_CLEAN_STACK
+int ECB_ENC(const unsigned char *pt, unsigned char *ct, symmetric_key *skey)
+{
+   int err = _rijndael_ecb_encrypt(pt, ct, skey);
+   burn_stack(sizeof(unsigned long)*8 + sizeof(unsigned long*) + sizeof(int)*2);
+   return err;
+}
+#endif
+
+#ifndef ENCRYPT_ONLY
+
+/**
+  Decrypts a block of text with AES
+  @param ct The input ciphertext (16 bytes)
+  @param pt The output plaintext (16 bytes)
+  @param skey The key as scheduled
+  @return CRYPT_OK if successful
+*/
+#ifdef LTC_CLEAN_STACK
+static int _rijndael_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey)
+#else
+int ECB_DEC(const unsigned char *ct, unsigned char *pt, symmetric_key *skey)
+#endif
+{
+    ulong32 s0, s1, s2, s3, t0, t1, t2, t3, *rk;
+    int Nr, r;
+
+    LTC_ARGCHK(pt != NULL);
+    LTC_ARGCHK(ct != NULL);
+    LTC_ARGCHK(skey != NULL);
+
+    Nr = skey->rijndael.Nr;
+    rk = skey->rijndael.dK;
+
+    /*
+     * map byte array block to cipher state
+     * and add initial round key:
+     */
+    LOAD32H(s0, ct      ); s0 ^= rk[0];
+    LOAD32H(s1, ct  +  4); s1 ^= rk[1];
+    LOAD32H(s2, ct  +  8); s2 ^= rk[2];
+    LOAD32H(s3, ct  + 12); s3 ^= rk[3];
+
+#ifdef LTC_SMALL_CODE
+    for (r = 0; ; r++) {
+        rk += 4;
+        t0 =
+            Td0(byte(s0, 3)) ^
+            Td1(byte(s3, 2)) ^
+            Td2(byte(s2, 1)) ^
+            Td3(byte(s1, 0)) ^
+            rk[0];
+        t1 =
+            Td0(byte(s1, 3)) ^
+            Td1(byte(s0, 2)) ^
+            Td2(byte(s3, 1)) ^
+            Td3(byte(s2, 0)) ^
+            rk[1];
+        t2 =
+            Td0(byte(s2, 3)) ^
+            Td1(byte(s1, 2)) ^
+            Td2(byte(s0, 1)) ^
+            Td3(byte(s3, 0)) ^
+            rk[2];
+        t3 =
+            Td0(byte(s3, 3)) ^
+            Td1(byte(s2, 2)) ^
+            Td2(byte(s1, 1)) ^
+            Td3(byte(s0, 0)) ^
+            rk[3];
+        if (r == Nr-2) {
+           break;
+        }
+        s0 = t0; s1 = t1; s2 = t2; s3 = t3;
+    }
+    rk += 4;
+
+#else
+
+    /*
+     * Nr - 1 full rounds:
+     */
+    r = Nr >> 1;
+    for (;;) {
+
+        t0 =
+            Td0(byte(s0, 3)) ^
+            Td1(byte(s3, 2)) ^
+            Td2(byte(s2, 1)) ^
+            Td3(byte(s1, 0)) ^
+            rk[4];
+        t1 =
+            Td0(byte(s1, 3)) ^
+            Td1(byte(s0, 2)) ^
+            Td2(byte(s3, 1)) ^
+            Td3(byte(s2, 0)) ^
+            rk[5];
+        t2 =
+            Td0(byte(s2, 3)) ^
+            Td1(byte(s1, 2)) ^
+            Td2(byte(s0, 1)) ^
+            Td3(byte(s3, 0)) ^
+            rk[6];
+        t3 =
+            Td0(byte(s3, 3)) ^
+            Td1(byte(s2, 2)) ^
+            Td2(byte(s1, 1)) ^
+            Td3(byte(s0, 0)) ^
+            rk[7];
+
+        rk += 8;
+        if (--r == 0) {
+            break;
+        }
+
+
+        s0 =
+            Td0(byte(t0, 3)) ^
+            Td1(byte(t3, 2)) ^
+            Td2(byte(t2, 1)) ^
+            Td3(byte(t1, 0)) ^
+            rk[0];
+        s1 =
+            Td0(byte(t1, 3)) ^
+            Td1(byte(t0, 2)) ^
+            Td2(byte(t3, 1)) ^
+            Td3(byte(t2, 0)) ^
+            rk[1];
+        s2 =
+            Td0(byte(t2, 3)) ^
+            Td1(byte(t1, 2)) ^
+            Td2(byte(t0, 1)) ^
+            Td3(byte(t3, 0)) ^
+            rk[2];
+        s3 =
+            Td0(byte(t3, 3)) ^
+            Td1(byte(t2, 2)) ^
+            Td2(byte(t1, 1)) ^
+            Td3(byte(t0, 0)) ^
+            rk[3];
+    }
+#endif
+
+    /*
+     * apply last round and
+     * map cipher state to byte array block:
+     */
+    s0 =
+        (Td4[byte(t0, 3)] & 0xff000000) ^
+        (Td4[byte(t3, 2)] & 0x00ff0000) ^
+        (Td4[byte(t2, 1)] & 0x0000ff00) ^
+        (Td4[byte(t1, 0)] & 0x000000ff) ^
+        rk[0];
+    STORE32H(s0, pt);
+    s1 =
+        (Td4[byte(t1, 3)] & 0xff000000) ^
+        (Td4[byte(t0, 2)] & 0x00ff0000) ^
+        (Td4[byte(t3, 1)] & 0x0000ff00) ^
+        (Td4[byte(t2, 0)] & 0x000000ff) ^
+        rk[1];
+    STORE32H(s1, pt+4);
+    s2 =
+        (Td4[byte(t2, 3)] & 0xff000000) ^
+        (Td4[byte(t1, 2)] & 0x00ff0000) ^
+        (Td4[byte(t0, 1)] & 0x0000ff00) ^
+        (Td4[byte(t3, 0)] & 0x000000ff) ^
+        rk[2];
+    STORE32H(s2, pt+8);
+    s3 =
+        (Td4[byte(t3, 3)] & 0xff000000) ^
+        (Td4[byte(t2, 2)] & 0x00ff0000) ^
+        (Td4[byte(t1, 1)] & 0x0000ff00) ^
+        (Td4[byte(t0, 0)] & 0x000000ff) ^
+        rk[3];
+    STORE32H(s3, pt+12);
+
+    return CRYPT_OK;
+}
+
+
+#ifdef LTC_CLEAN_STACK
+int ECB_DEC(const unsigned char *ct, unsigned char *pt, symmetric_key *skey)
+{
+   int err = _rijndael_ecb_decrypt(ct, pt, skey);
+   burn_stack(sizeof(unsigned long)*8 + sizeof(unsigned long*) + sizeof(int)*2);
+   return err;
+}
+#endif
+
+/**
+  Performs a self-test of the AES block cipher
+  @return CRYPT_OK if functional, CRYPT_NOP if self-test has been disabled
+*/
+int ECB_TEST(void)
+{
+ #ifndef LTC_TEST
+    return CRYPT_NOP;
+ #else
+ int err;
+ static const struct {
+     int keylen;
+     unsigned char key[32], pt[16], ct[16];
+ } tests[] = {
+    { 16,
+      { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+        0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f },
+      { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
+        0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff },
+      { 0x69, 0xc4, 0xe0, 0xd8, 0x6a, 0x7b, 0x04, 0x30,
+        0xd8, 0xcd, 0xb7, 0x80, 0x70, 0xb4, 0xc5, 0x5a }
+    }, {
+      24,
+      { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+        0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+        0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17 },
+      { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
+        0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff },
+      { 0xdd, 0xa9, 0x7c, 0xa4, 0x86, 0x4c, 0xdf, 0xe0,
+        0x6e, 0xaf, 0x70, 0xa0, 0xec, 0x0d, 0x71, 0x91 }
+    }, {
+      32,
+      { 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 },
+      { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
+        0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff },
+      { 0x8e, 0xa2, 0xb7, 0xca, 0x51, 0x67, 0x45, 0xbf,
+        0xea, 0xfc, 0x49, 0x90, 0x4b, 0x49, 0x60, 0x89 }
+    }
+ };
+
+  symmetric_key key;
+  unsigned char tmp[2][16];
+  int i, y;
+
+  for (i = 0; i < (int)(sizeof(tests)/sizeof(tests[0])); i++) {
+    zeromem(&key, sizeof(key));
+    if ((err = rijndael_setup(tests[i].key, tests[i].keylen, 0, &key)) != CRYPT_OK) {
+       return err;
+    }
+
+    rijndael_ecb_encrypt(tests[i].pt, tmp[0], &key);
+    rijndael_ecb_decrypt(tmp[0], tmp[1], &key);
+    if (compare_testvector(tmp[0], 16, tests[i].ct, 16, "AES Encrypt", i) ||
+          compare_testvector(tmp[1], 16, tests[i].pt, 16, "AES Decrypt", i)) {
+        return CRYPT_FAIL_TESTVECTOR;
+    }
+
+    /* now see if we can encrypt all zero bytes 1000 times, decrypt and come back where we started */
+    for (y = 0; y < 16; y++) tmp[0][y] = 0;
+    for (y = 0; y < 1000; y++) rijndael_ecb_encrypt(tmp[0], tmp[0], &key);
+    for (y = 0; y < 1000; y++) rijndael_ecb_decrypt(tmp[0], tmp[0], &key);
+    for (y = 0; y < 16; y++) if (tmp[0][y] != 0) return CRYPT_FAIL_TESTVECTOR;
+  }
+  return CRYPT_OK;
+ #endif
+}
+
+#endif /* ENCRYPT_ONLY */
+
+
+/** Terminate the context
+   @param skey    The scheduled key
+*/
+void ECB_DONE(symmetric_key *skey)
+{
+  LTC_UNUSED_PARAM(skey);
+}
+
+
+/**
+  Gets suitable key size
+  @param keysize [in/out] The length of the recommended key (in bytes).  This function will store the suitable size back in this variable.
+  @return CRYPT_OK if the input key size is acceptable.
+*/
+int ECB_KS(int *keysize)
+{
+   LTC_ARGCHK(keysize != NULL);
+
+   if (*keysize < 16)
+      return CRYPT_INVALID_KEYSIZE;
+   if (*keysize < 24) {
+      *keysize = 16;
+      return CRYPT_OK;
+   } else if (*keysize < 32) {
+      *keysize = 24;
+      return CRYPT_OK;
+   } else {
+      *keysize = 32;
+      return CRYPT_OK;
+   }
+}
+
+#endif
+
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/ciphers/aes/aes_tab.c b/libtomcrypt/src/ciphers/aes/aes_tab.c
new file mode 100644 (file)
index 0000000..b15596e
--- /dev/null
@@ -0,0 +1,1032 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+/* The precomputed tables for AES */
+/*
+Te0[x] = S [x].[02, 01, 01, 03];
+Te1[x] = S [x].[03, 02, 01, 01];
+Te2[x] = S [x].[01, 03, 02, 01];
+Te3[x] = S [x].[01, 01, 03, 02];
+Te4[x] = S [x].[01, 01, 01, 01];
+
+Td0[x] = Si[x].[0e, 09, 0d, 0b];
+Td1[x] = Si[x].[0b, 0e, 09, 0d];
+Td2[x] = Si[x].[0d, 0b, 0e, 09];
+Td3[x] = Si[x].[09, 0d, 0b, 0e];
+Td4[x] = Si[x].[01, 01, 01, 01];
+*/
+
+#ifdef __LTC_AES_TAB_C__
+
+/**
+  @file aes_tab.c
+  AES tables
+*/
+static const ulong32 TE0[256] = {
+    0xc66363a5UL, 0xf87c7c84UL, 0xee777799UL, 0xf67b7b8dUL,
+    0xfff2f20dUL, 0xd66b6bbdUL, 0xde6f6fb1UL, 0x91c5c554UL,
+    0x60303050UL, 0x02010103UL, 0xce6767a9UL, 0x562b2b7dUL,
+    0xe7fefe19UL, 0xb5d7d762UL, 0x4dababe6UL, 0xec76769aUL,
+    0x8fcaca45UL, 0x1f82829dUL, 0x89c9c940UL, 0xfa7d7d87UL,
+    0xeffafa15UL, 0xb25959ebUL, 0x8e4747c9UL, 0xfbf0f00bUL,
+    0x41adadecUL, 0xb3d4d467UL, 0x5fa2a2fdUL, 0x45afafeaUL,
+    0x239c9cbfUL, 0x53a4a4f7UL, 0xe4727296UL, 0x9bc0c05bUL,
+    0x75b7b7c2UL, 0xe1fdfd1cUL, 0x3d9393aeUL, 0x4c26266aUL,
+    0x6c36365aUL, 0x7e3f3f41UL, 0xf5f7f702UL, 0x83cccc4fUL,
+    0x6834345cUL, 0x51a5a5f4UL, 0xd1e5e534UL, 0xf9f1f108UL,
+    0xe2717193UL, 0xabd8d873UL, 0x62313153UL, 0x2a15153fUL,
+    0x0804040cUL, 0x95c7c752UL, 0x46232365UL, 0x9dc3c35eUL,
+    0x30181828UL, 0x379696a1UL, 0x0a05050fUL, 0x2f9a9ab5UL,
+    0x0e070709UL, 0x24121236UL, 0x1b80809bUL, 0xdfe2e23dUL,
+    0xcdebeb26UL, 0x4e272769UL, 0x7fb2b2cdUL, 0xea75759fUL,
+    0x1209091bUL, 0x1d83839eUL, 0x582c2c74UL, 0x341a1a2eUL,
+    0x361b1b2dUL, 0xdc6e6eb2UL, 0xb45a5aeeUL, 0x5ba0a0fbUL,
+    0xa45252f6UL, 0x763b3b4dUL, 0xb7d6d661UL, 0x7db3b3ceUL,
+    0x5229297bUL, 0xdde3e33eUL, 0x5e2f2f71UL, 0x13848497UL,
+    0xa65353f5UL, 0xb9d1d168UL, 0x00000000UL, 0xc1eded2cUL,
+    0x40202060UL, 0xe3fcfc1fUL, 0x79b1b1c8UL, 0xb65b5bedUL,
+    0xd46a6abeUL, 0x8dcbcb46UL, 0x67bebed9UL, 0x7239394bUL,
+    0x944a4adeUL, 0x984c4cd4UL, 0xb05858e8UL, 0x85cfcf4aUL,
+    0xbbd0d06bUL, 0xc5efef2aUL, 0x4faaaae5UL, 0xedfbfb16UL,
+    0x864343c5UL, 0x9a4d4dd7UL, 0x66333355UL, 0x11858594UL,
+    0x8a4545cfUL, 0xe9f9f910UL, 0x04020206UL, 0xfe7f7f81UL,
+    0xa05050f0UL, 0x783c3c44UL, 0x259f9fbaUL, 0x4ba8a8e3UL,
+    0xa25151f3UL, 0x5da3a3feUL, 0x804040c0UL, 0x058f8f8aUL,
+    0x3f9292adUL, 0x219d9dbcUL, 0x70383848UL, 0xf1f5f504UL,
+    0x63bcbcdfUL, 0x77b6b6c1UL, 0xafdada75UL, 0x42212163UL,
+    0x20101030UL, 0xe5ffff1aUL, 0xfdf3f30eUL, 0xbfd2d26dUL,
+    0x81cdcd4cUL, 0x180c0c14UL, 0x26131335UL, 0xc3ecec2fUL,
+    0xbe5f5fe1UL, 0x359797a2UL, 0x884444ccUL, 0x2e171739UL,
+    0x93c4c457UL, 0x55a7a7f2UL, 0xfc7e7e82UL, 0x7a3d3d47UL,
+    0xc86464acUL, 0xba5d5de7UL, 0x3219192bUL, 0xe6737395UL,
+    0xc06060a0UL, 0x19818198UL, 0x9e4f4fd1UL, 0xa3dcdc7fUL,
+    0x44222266UL, 0x542a2a7eUL, 0x3b9090abUL, 0x0b888883UL,
+    0x8c4646caUL, 0xc7eeee29UL, 0x6bb8b8d3UL, 0x2814143cUL,
+    0xa7dede79UL, 0xbc5e5ee2UL, 0x160b0b1dUL, 0xaddbdb76UL,
+    0xdbe0e03bUL, 0x64323256UL, 0x743a3a4eUL, 0x140a0a1eUL,
+    0x924949dbUL, 0x0c06060aUL, 0x4824246cUL, 0xb85c5ce4UL,
+    0x9fc2c25dUL, 0xbdd3d36eUL, 0x43acacefUL, 0xc46262a6UL,
+    0x399191a8UL, 0x319595a4UL, 0xd3e4e437UL, 0xf279798bUL,
+    0xd5e7e732UL, 0x8bc8c843UL, 0x6e373759UL, 0xda6d6db7UL,
+    0x018d8d8cUL, 0xb1d5d564UL, 0x9c4e4ed2UL, 0x49a9a9e0UL,
+    0xd86c6cb4UL, 0xac5656faUL, 0xf3f4f407UL, 0xcfeaea25UL,
+    0xca6565afUL, 0xf47a7a8eUL, 0x47aeaee9UL, 0x10080818UL,
+    0x6fbabad5UL, 0xf0787888UL, 0x4a25256fUL, 0x5c2e2e72UL,
+    0x381c1c24UL, 0x57a6a6f1UL, 0x73b4b4c7UL, 0x97c6c651UL,
+    0xcbe8e823UL, 0xa1dddd7cUL, 0xe874749cUL, 0x3e1f1f21UL,
+    0x964b4bddUL, 0x61bdbddcUL, 0x0d8b8b86UL, 0x0f8a8a85UL,
+    0xe0707090UL, 0x7c3e3e42UL, 0x71b5b5c4UL, 0xcc6666aaUL,
+    0x904848d8UL, 0x06030305UL, 0xf7f6f601UL, 0x1c0e0e12UL,
+    0xc26161a3UL, 0x6a35355fUL, 0xae5757f9UL, 0x69b9b9d0UL,
+    0x17868691UL, 0x99c1c158UL, 0x3a1d1d27UL, 0x279e9eb9UL,
+    0xd9e1e138UL, 0xebf8f813UL, 0x2b9898b3UL, 0x22111133UL,
+    0xd26969bbUL, 0xa9d9d970UL, 0x078e8e89UL, 0x339494a7UL,
+    0x2d9b9bb6UL, 0x3c1e1e22UL, 0x15878792UL, 0xc9e9e920UL,
+    0x87cece49UL, 0xaa5555ffUL, 0x50282878UL, 0xa5dfdf7aUL,
+    0x038c8c8fUL, 0x59a1a1f8UL, 0x09898980UL, 0x1a0d0d17UL,
+    0x65bfbfdaUL, 0xd7e6e631UL, 0x844242c6UL, 0xd06868b8UL,
+    0x824141c3UL, 0x299999b0UL, 0x5a2d2d77UL, 0x1e0f0f11UL,
+    0x7bb0b0cbUL, 0xa85454fcUL, 0x6dbbbbd6UL, 0x2c16163aUL,
+};
+
+#if !defined(PELI_TAB) && defined(LTC_SMALL_CODE)
+static const ulong32 Te4[256] = {
+    0x63636363UL, 0x7c7c7c7cUL, 0x77777777UL, 0x7b7b7b7bUL,
+    0xf2f2f2f2UL, 0x6b6b6b6bUL, 0x6f6f6f6fUL, 0xc5c5c5c5UL,
+    0x30303030UL, 0x01010101UL, 0x67676767UL, 0x2b2b2b2bUL,
+    0xfefefefeUL, 0xd7d7d7d7UL, 0xababababUL, 0x76767676UL,
+    0xcacacacaUL, 0x82828282UL, 0xc9c9c9c9UL, 0x7d7d7d7dUL,
+    0xfafafafaUL, 0x59595959UL, 0x47474747UL, 0xf0f0f0f0UL,
+    0xadadadadUL, 0xd4d4d4d4UL, 0xa2a2a2a2UL, 0xafafafafUL,
+    0x9c9c9c9cUL, 0xa4a4a4a4UL, 0x72727272UL, 0xc0c0c0c0UL,
+    0xb7b7b7b7UL, 0xfdfdfdfdUL, 0x93939393UL, 0x26262626UL,
+    0x36363636UL, 0x3f3f3f3fUL, 0xf7f7f7f7UL, 0xccccccccUL,
+    0x34343434UL, 0xa5a5a5a5UL, 0xe5e5e5e5UL, 0xf1f1f1f1UL,
+    0x71717171UL, 0xd8d8d8d8UL, 0x31313131UL, 0x15151515UL,
+    0x04040404UL, 0xc7c7c7c7UL, 0x23232323UL, 0xc3c3c3c3UL,
+    0x18181818UL, 0x96969696UL, 0x05050505UL, 0x9a9a9a9aUL,
+    0x07070707UL, 0x12121212UL, 0x80808080UL, 0xe2e2e2e2UL,
+    0xebebebebUL, 0x27272727UL, 0xb2b2b2b2UL, 0x75757575UL,
+    0x09090909UL, 0x83838383UL, 0x2c2c2c2cUL, 0x1a1a1a1aUL,
+    0x1b1b1b1bUL, 0x6e6e6e6eUL, 0x5a5a5a5aUL, 0xa0a0a0a0UL,
+    0x52525252UL, 0x3b3b3b3bUL, 0xd6d6d6d6UL, 0xb3b3b3b3UL,
+    0x29292929UL, 0xe3e3e3e3UL, 0x2f2f2f2fUL, 0x84848484UL,
+    0x53535353UL, 0xd1d1d1d1UL, 0x00000000UL, 0xededededUL,
+    0x20202020UL, 0xfcfcfcfcUL, 0xb1b1b1b1UL, 0x5b5b5b5bUL,
+    0x6a6a6a6aUL, 0xcbcbcbcbUL, 0xbebebebeUL, 0x39393939UL,
+    0x4a4a4a4aUL, 0x4c4c4c4cUL, 0x58585858UL, 0xcfcfcfcfUL,
+    0xd0d0d0d0UL, 0xefefefefUL, 0xaaaaaaaaUL, 0xfbfbfbfbUL,
+    0x43434343UL, 0x4d4d4d4dUL, 0x33333333UL, 0x85858585UL,
+    0x45454545UL, 0xf9f9f9f9UL, 0x02020202UL, 0x7f7f7f7fUL,
+    0x50505050UL, 0x3c3c3c3cUL, 0x9f9f9f9fUL, 0xa8a8a8a8UL,
+    0x51515151UL, 0xa3a3a3a3UL, 0x40404040UL, 0x8f8f8f8fUL,
+    0x92929292UL, 0x9d9d9d9dUL, 0x38383838UL, 0xf5f5f5f5UL,
+    0xbcbcbcbcUL, 0xb6b6b6b6UL, 0xdadadadaUL, 0x21212121UL,
+    0x10101010UL, 0xffffffffUL, 0xf3f3f3f3UL, 0xd2d2d2d2UL,
+    0xcdcdcdcdUL, 0x0c0c0c0cUL, 0x13131313UL, 0xececececUL,
+    0x5f5f5f5fUL, 0x97979797UL, 0x44444444UL, 0x17171717UL,
+    0xc4c4c4c4UL, 0xa7a7a7a7UL, 0x7e7e7e7eUL, 0x3d3d3d3dUL,
+    0x64646464UL, 0x5d5d5d5dUL, 0x19191919UL, 0x73737373UL,
+    0x60606060UL, 0x81818181UL, 0x4f4f4f4fUL, 0xdcdcdcdcUL,
+    0x22222222UL, 0x2a2a2a2aUL, 0x90909090UL, 0x88888888UL,
+    0x46464646UL, 0xeeeeeeeeUL, 0xb8b8b8b8UL, 0x14141414UL,
+    0xdedededeUL, 0x5e5e5e5eUL, 0x0b0b0b0bUL, 0xdbdbdbdbUL,
+    0xe0e0e0e0UL, 0x32323232UL, 0x3a3a3a3aUL, 0x0a0a0a0aUL,
+    0x49494949UL, 0x06060606UL, 0x24242424UL, 0x5c5c5c5cUL,
+    0xc2c2c2c2UL, 0xd3d3d3d3UL, 0xacacacacUL, 0x62626262UL,
+    0x91919191UL, 0x95959595UL, 0xe4e4e4e4UL, 0x79797979UL,
+    0xe7e7e7e7UL, 0xc8c8c8c8UL, 0x37373737UL, 0x6d6d6d6dUL,
+    0x8d8d8d8dUL, 0xd5d5d5d5UL, 0x4e4e4e4eUL, 0xa9a9a9a9UL,
+    0x6c6c6c6cUL, 0x56565656UL, 0xf4f4f4f4UL, 0xeaeaeaeaUL,
+    0x65656565UL, 0x7a7a7a7aUL, 0xaeaeaeaeUL, 0x08080808UL,
+    0xbabababaUL, 0x78787878UL, 0x25252525UL, 0x2e2e2e2eUL,
+    0x1c1c1c1cUL, 0xa6a6a6a6UL, 0xb4b4b4b4UL, 0xc6c6c6c6UL,
+    0xe8e8e8e8UL, 0xddddddddUL, 0x74747474UL, 0x1f1f1f1fUL,
+    0x4b4b4b4bUL, 0xbdbdbdbdUL, 0x8b8b8b8bUL, 0x8a8a8a8aUL,
+    0x70707070UL, 0x3e3e3e3eUL, 0xb5b5b5b5UL, 0x66666666UL,
+    0x48484848UL, 0x03030303UL, 0xf6f6f6f6UL, 0x0e0e0e0eUL,
+    0x61616161UL, 0x35353535UL, 0x57575757UL, 0xb9b9b9b9UL,
+    0x86868686UL, 0xc1c1c1c1UL, 0x1d1d1d1dUL, 0x9e9e9e9eUL,
+    0xe1e1e1e1UL, 0xf8f8f8f8UL, 0x98989898UL, 0x11111111UL,
+    0x69696969UL, 0xd9d9d9d9UL, 0x8e8e8e8eUL, 0x94949494UL,
+    0x9b9b9b9bUL, 0x1e1e1e1eUL, 0x87878787UL, 0xe9e9e9e9UL,
+    0xcecececeUL, 0x55555555UL, 0x28282828UL, 0xdfdfdfdfUL,
+    0x8c8c8c8cUL, 0xa1a1a1a1UL, 0x89898989UL, 0x0d0d0d0dUL,
+    0xbfbfbfbfUL, 0xe6e6e6e6UL, 0x42424242UL, 0x68686868UL,
+    0x41414141UL, 0x99999999UL, 0x2d2d2d2dUL, 0x0f0f0f0fUL,
+    0xb0b0b0b0UL, 0x54545454UL, 0xbbbbbbbbUL, 0x16161616UL,
+};
+#endif
+
+#ifndef ENCRYPT_ONLY
+
+static const ulong32 TD0[256] = {
+    0x51f4a750UL, 0x7e416553UL, 0x1a17a4c3UL, 0x3a275e96UL,
+    0x3bab6bcbUL, 0x1f9d45f1UL, 0xacfa58abUL, 0x4be30393UL,
+    0x2030fa55UL, 0xad766df6UL, 0x88cc7691UL, 0xf5024c25UL,
+    0x4fe5d7fcUL, 0xc52acbd7UL, 0x26354480UL, 0xb562a38fUL,
+    0xdeb15a49UL, 0x25ba1b67UL, 0x45ea0e98UL, 0x5dfec0e1UL,
+    0xc32f7502UL, 0x814cf012UL, 0x8d4697a3UL, 0x6bd3f9c6UL,
+    0x038f5fe7UL, 0x15929c95UL, 0xbf6d7aebUL, 0x955259daUL,
+    0xd4be832dUL, 0x587421d3UL, 0x49e06929UL, 0x8ec9c844UL,
+    0x75c2896aUL, 0xf48e7978UL, 0x99583e6bUL, 0x27b971ddUL,
+    0xbee14fb6UL, 0xf088ad17UL, 0xc920ac66UL, 0x7dce3ab4UL,
+    0x63df4a18UL, 0xe51a3182UL, 0x97513360UL, 0x62537f45UL,
+    0xb16477e0UL, 0xbb6bae84UL, 0xfe81a01cUL, 0xf9082b94UL,
+    0x70486858UL, 0x8f45fd19UL, 0x94de6c87UL, 0x527bf8b7UL,
+    0xab73d323UL, 0x724b02e2UL, 0xe31f8f57UL, 0x6655ab2aUL,
+    0xb2eb2807UL, 0x2fb5c203UL, 0x86c57b9aUL, 0xd33708a5UL,
+    0x302887f2UL, 0x23bfa5b2UL, 0x02036abaUL, 0xed16825cUL,
+    0x8acf1c2bUL, 0xa779b492UL, 0xf307f2f0UL, 0x4e69e2a1UL,
+    0x65daf4cdUL, 0x0605bed5UL, 0xd134621fUL, 0xc4a6fe8aUL,
+    0x342e539dUL, 0xa2f355a0UL, 0x058ae132UL, 0xa4f6eb75UL,
+    0x0b83ec39UL, 0x4060efaaUL, 0x5e719f06UL, 0xbd6e1051UL,
+    0x3e218af9UL, 0x96dd063dUL, 0xdd3e05aeUL, 0x4de6bd46UL,
+    0x91548db5UL, 0x71c45d05UL, 0x0406d46fUL, 0x605015ffUL,
+    0x1998fb24UL, 0xd6bde997UL, 0x894043ccUL, 0x67d99e77UL,
+    0xb0e842bdUL, 0x07898b88UL, 0xe7195b38UL, 0x79c8eedbUL,
+    0xa17c0a47UL, 0x7c420fe9UL, 0xf8841ec9UL, 0x00000000UL,
+    0x09808683UL, 0x322bed48UL, 0x1e1170acUL, 0x6c5a724eUL,
+    0xfd0efffbUL, 0x0f853856UL, 0x3daed51eUL, 0x362d3927UL,
+    0x0a0fd964UL, 0x685ca621UL, 0x9b5b54d1UL, 0x24362e3aUL,
+    0x0c0a67b1UL, 0x9357e70fUL, 0xb4ee96d2UL, 0x1b9b919eUL,
+    0x80c0c54fUL, 0x61dc20a2UL, 0x5a774b69UL, 0x1c121a16UL,
+    0xe293ba0aUL, 0xc0a02ae5UL, 0x3c22e043UL, 0x121b171dUL,
+    0x0e090d0bUL, 0xf28bc7adUL, 0x2db6a8b9UL, 0x141ea9c8UL,
+    0x57f11985UL, 0xaf75074cUL, 0xee99ddbbUL, 0xa37f60fdUL,
+    0xf701269fUL, 0x5c72f5bcUL, 0x44663bc5UL, 0x5bfb7e34UL,
+    0x8b432976UL, 0xcb23c6dcUL, 0xb6edfc68UL, 0xb8e4f163UL,
+    0xd731dccaUL, 0x42638510UL, 0x13972240UL, 0x84c61120UL,
+    0x854a247dUL, 0xd2bb3df8UL, 0xaef93211UL, 0xc729a16dUL,
+    0x1d9e2f4bUL, 0xdcb230f3UL, 0x0d8652ecUL, 0x77c1e3d0UL,
+    0x2bb3166cUL, 0xa970b999UL, 0x119448faUL, 0x47e96422UL,
+    0xa8fc8cc4UL, 0xa0f03f1aUL, 0x567d2cd8UL, 0x223390efUL,
+    0x87494ec7UL, 0xd938d1c1UL, 0x8ccaa2feUL, 0x98d40b36UL,
+    0xa6f581cfUL, 0xa57ade28UL, 0xdab78e26UL, 0x3fadbfa4UL,
+    0x2c3a9de4UL, 0x5078920dUL, 0x6a5fcc9bUL, 0x547e4662UL,
+    0xf68d13c2UL, 0x90d8b8e8UL, 0x2e39f75eUL, 0x82c3aff5UL,
+    0x9f5d80beUL, 0x69d0937cUL, 0x6fd52da9UL, 0xcf2512b3UL,
+    0xc8ac993bUL, 0x10187da7UL, 0xe89c636eUL, 0xdb3bbb7bUL,
+    0xcd267809UL, 0x6e5918f4UL, 0xec9ab701UL, 0x834f9aa8UL,
+    0xe6956e65UL, 0xaaffe67eUL, 0x21bccf08UL, 0xef15e8e6UL,
+    0xbae79bd9UL, 0x4a6f36ceUL, 0xea9f09d4UL, 0x29b07cd6UL,
+    0x31a4b2afUL, 0x2a3f2331UL, 0xc6a59430UL, 0x35a266c0UL,
+    0x744ebc37UL, 0xfc82caa6UL, 0xe090d0b0UL, 0x33a7d815UL,
+    0xf104984aUL, 0x41ecdaf7UL, 0x7fcd500eUL, 0x1791f62fUL,
+    0x764dd68dUL, 0x43efb04dUL, 0xccaa4d54UL, 0xe49604dfUL,
+    0x9ed1b5e3UL, 0x4c6a881bUL, 0xc12c1fb8UL, 0x4665517fUL,
+    0x9d5eea04UL, 0x018c355dUL, 0xfa877473UL, 0xfb0b412eUL,
+    0xb3671d5aUL, 0x92dbd252UL, 0xe9105633UL, 0x6dd64713UL,
+    0x9ad7618cUL, 0x37a10c7aUL, 0x59f8148eUL, 0xeb133c89UL,
+    0xcea927eeUL, 0xb761c935UL, 0xe11ce5edUL, 0x7a47b13cUL,
+    0x9cd2df59UL, 0x55f2733fUL, 0x1814ce79UL, 0x73c737bfUL,
+    0x53f7cdeaUL, 0x5ffdaa5bUL, 0xdf3d6f14UL, 0x7844db86UL,
+    0xcaaff381UL, 0xb968c43eUL, 0x3824342cUL, 0xc2a3405fUL,
+    0x161dc372UL, 0xbce2250cUL, 0x283c498bUL, 0xff0d9541UL,
+    0x39a80171UL, 0x080cb3deUL, 0xd8b4e49cUL, 0x6456c190UL,
+    0x7bcb8461UL, 0xd532b670UL, 0x486c5c74UL, 0xd0b85742UL,
+};
+
+static const ulong32 Td4[256] = {
+    0x52525252UL, 0x09090909UL, 0x6a6a6a6aUL, 0xd5d5d5d5UL,
+    0x30303030UL, 0x36363636UL, 0xa5a5a5a5UL, 0x38383838UL,
+    0xbfbfbfbfUL, 0x40404040UL, 0xa3a3a3a3UL, 0x9e9e9e9eUL,
+    0x81818181UL, 0xf3f3f3f3UL, 0xd7d7d7d7UL, 0xfbfbfbfbUL,
+    0x7c7c7c7cUL, 0xe3e3e3e3UL, 0x39393939UL, 0x82828282UL,
+    0x9b9b9b9bUL, 0x2f2f2f2fUL, 0xffffffffUL, 0x87878787UL,
+    0x34343434UL, 0x8e8e8e8eUL, 0x43434343UL, 0x44444444UL,
+    0xc4c4c4c4UL, 0xdedededeUL, 0xe9e9e9e9UL, 0xcbcbcbcbUL,
+    0x54545454UL, 0x7b7b7b7bUL, 0x94949494UL, 0x32323232UL,
+    0xa6a6a6a6UL, 0xc2c2c2c2UL, 0x23232323UL, 0x3d3d3d3dUL,
+    0xeeeeeeeeUL, 0x4c4c4c4cUL, 0x95959595UL, 0x0b0b0b0bUL,
+    0x42424242UL, 0xfafafafaUL, 0xc3c3c3c3UL, 0x4e4e4e4eUL,
+    0x08080808UL, 0x2e2e2e2eUL, 0xa1a1a1a1UL, 0x66666666UL,
+    0x28282828UL, 0xd9d9d9d9UL, 0x24242424UL, 0xb2b2b2b2UL,
+    0x76767676UL, 0x5b5b5b5bUL, 0xa2a2a2a2UL, 0x49494949UL,
+    0x6d6d6d6dUL, 0x8b8b8b8bUL, 0xd1d1d1d1UL, 0x25252525UL,
+    0x72727272UL, 0xf8f8f8f8UL, 0xf6f6f6f6UL, 0x64646464UL,
+    0x86868686UL, 0x68686868UL, 0x98989898UL, 0x16161616UL,
+    0xd4d4d4d4UL, 0xa4a4a4a4UL, 0x5c5c5c5cUL, 0xccccccccUL,
+    0x5d5d5d5dUL, 0x65656565UL, 0xb6b6b6b6UL, 0x92929292UL,
+    0x6c6c6c6cUL, 0x70707070UL, 0x48484848UL, 0x50505050UL,
+    0xfdfdfdfdUL, 0xededededUL, 0xb9b9b9b9UL, 0xdadadadaUL,
+    0x5e5e5e5eUL, 0x15151515UL, 0x46464646UL, 0x57575757UL,
+    0xa7a7a7a7UL, 0x8d8d8d8dUL, 0x9d9d9d9dUL, 0x84848484UL,
+    0x90909090UL, 0xd8d8d8d8UL, 0xababababUL, 0x00000000UL,
+    0x8c8c8c8cUL, 0xbcbcbcbcUL, 0xd3d3d3d3UL, 0x0a0a0a0aUL,
+    0xf7f7f7f7UL, 0xe4e4e4e4UL, 0x58585858UL, 0x05050505UL,
+    0xb8b8b8b8UL, 0xb3b3b3b3UL, 0x45454545UL, 0x06060606UL,
+    0xd0d0d0d0UL, 0x2c2c2c2cUL, 0x1e1e1e1eUL, 0x8f8f8f8fUL,
+    0xcacacacaUL, 0x3f3f3f3fUL, 0x0f0f0f0fUL, 0x02020202UL,
+    0xc1c1c1c1UL, 0xafafafafUL, 0xbdbdbdbdUL, 0x03030303UL,
+    0x01010101UL, 0x13131313UL, 0x8a8a8a8aUL, 0x6b6b6b6bUL,
+    0x3a3a3a3aUL, 0x91919191UL, 0x11111111UL, 0x41414141UL,
+    0x4f4f4f4fUL, 0x67676767UL, 0xdcdcdcdcUL, 0xeaeaeaeaUL,
+    0x97979797UL, 0xf2f2f2f2UL, 0xcfcfcfcfUL, 0xcecececeUL,
+    0xf0f0f0f0UL, 0xb4b4b4b4UL, 0xe6e6e6e6UL, 0x73737373UL,
+    0x96969696UL, 0xacacacacUL, 0x74747474UL, 0x22222222UL,
+    0xe7e7e7e7UL, 0xadadadadUL, 0x35353535UL, 0x85858585UL,
+    0xe2e2e2e2UL, 0xf9f9f9f9UL, 0x37373737UL, 0xe8e8e8e8UL,
+    0x1c1c1c1cUL, 0x75757575UL, 0xdfdfdfdfUL, 0x6e6e6e6eUL,
+    0x47474747UL, 0xf1f1f1f1UL, 0x1a1a1a1aUL, 0x71717171UL,
+    0x1d1d1d1dUL, 0x29292929UL, 0xc5c5c5c5UL, 0x89898989UL,
+    0x6f6f6f6fUL, 0xb7b7b7b7UL, 0x62626262UL, 0x0e0e0e0eUL,
+    0xaaaaaaaaUL, 0x18181818UL, 0xbebebebeUL, 0x1b1b1b1bUL,
+    0xfcfcfcfcUL, 0x56565656UL, 0x3e3e3e3eUL, 0x4b4b4b4bUL,
+    0xc6c6c6c6UL, 0xd2d2d2d2UL, 0x79797979UL, 0x20202020UL,
+    0x9a9a9a9aUL, 0xdbdbdbdbUL, 0xc0c0c0c0UL, 0xfefefefeUL,
+    0x78787878UL, 0xcdcdcdcdUL, 0x5a5a5a5aUL, 0xf4f4f4f4UL,
+    0x1f1f1f1fUL, 0xddddddddUL, 0xa8a8a8a8UL, 0x33333333UL,
+    0x88888888UL, 0x07070707UL, 0xc7c7c7c7UL, 0x31313131UL,
+    0xb1b1b1b1UL, 0x12121212UL, 0x10101010UL, 0x59595959UL,
+    0x27272727UL, 0x80808080UL, 0xececececUL, 0x5f5f5f5fUL,
+    0x60606060UL, 0x51515151UL, 0x7f7f7f7fUL, 0xa9a9a9a9UL,
+    0x19191919UL, 0xb5b5b5b5UL, 0x4a4a4a4aUL, 0x0d0d0d0dUL,
+    0x2d2d2d2dUL, 0xe5e5e5e5UL, 0x7a7a7a7aUL, 0x9f9f9f9fUL,
+    0x93939393UL, 0xc9c9c9c9UL, 0x9c9c9c9cUL, 0xefefefefUL,
+    0xa0a0a0a0UL, 0xe0e0e0e0UL, 0x3b3b3b3bUL, 0x4d4d4d4dUL,
+    0xaeaeaeaeUL, 0x2a2a2a2aUL, 0xf5f5f5f5UL, 0xb0b0b0b0UL,
+    0xc8c8c8c8UL, 0xebebebebUL, 0xbbbbbbbbUL, 0x3c3c3c3cUL,
+    0x83838383UL, 0x53535353UL, 0x99999999UL, 0x61616161UL,
+    0x17171717UL, 0x2b2b2b2bUL, 0x04040404UL, 0x7e7e7e7eUL,
+    0xbabababaUL, 0x77777777UL, 0xd6d6d6d6UL, 0x26262626UL,
+    0xe1e1e1e1UL, 0x69696969UL, 0x14141414UL, 0x63636363UL,
+    0x55555555UL, 0x21212121UL, 0x0c0c0c0cUL, 0x7d7d7d7dUL,
+};
+
+#endif /* ENCRYPT_ONLY */
+
+#ifdef LTC_SMALL_CODE
+
+#define Te0(x) TE0[x]
+#define Te1(x) RORc(TE0[x], 8)
+#define Te2(x) RORc(TE0[x], 16)
+#define Te3(x) RORc(TE0[x], 24)
+
+#define Td0(x) TD0[x]
+#define Td1(x) RORc(TD0[x], 8)
+#define Td2(x) RORc(TD0[x], 16)
+#define Td3(x) RORc(TD0[x], 24)
+
+#define Te4_0 0x000000FF & Te4
+#define Te4_1 0x0000FF00 & Te4
+#define Te4_2 0x00FF0000 & Te4
+#define Te4_3 0xFF000000 & Te4
+
+#else
+
+#define Te0(x) TE0[x]
+#define Te1(x) TE1[x]
+#define Te2(x) TE2[x]
+#define Te3(x) TE3[x]
+
+#define Td0(x) TD0[x]
+#define Td1(x) TD1[x]
+#define Td2(x) TD2[x]
+#define Td3(x) TD3[x]
+
+static const ulong32 TE1[256] = {
+    0xa5c66363UL, 0x84f87c7cUL, 0x99ee7777UL, 0x8df67b7bUL,
+    0x0dfff2f2UL, 0xbdd66b6bUL, 0xb1de6f6fUL, 0x5491c5c5UL,
+    0x50603030UL, 0x03020101UL, 0xa9ce6767UL, 0x7d562b2bUL,
+    0x19e7fefeUL, 0x62b5d7d7UL, 0xe64dababUL, 0x9aec7676UL,
+    0x458fcacaUL, 0x9d1f8282UL, 0x4089c9c9UL, 0x87fa7d7dUL,
+    0x15effafaUL, 0xebb25959UL, 0xc98e4747UL, 0x0bfbf0f0UL,
+    0xec41adadUL, 0x67b3d4d4UL, 0xfd5fa2a2UL, 0xea45afafUL,
+    0xbf239c9cUL, 0xf753a4a4UL, 0x96e47272UL, 0x5b9bc0c0UL,
+    0xc275b7b7UL, 0x1ce1fdfdUL, 0xae3d9393UL, 0x6a4c2626UL,
+    0x5a6c3636UL, 0x417e3f3fUL, 0x02f5f7f7UL, 0x4f83ccccUL,
+    0x5c683434UL, 0xf451a5a5UL, 0x34d1e5e5UL, 0x08f9f1f1UL,
+    0x93e27171UL, 0x73abd8d8UL, 0x53623131UL, 0x3f2a1515UL,
+    0x0c080404UL, 0x5295c7c7UL, 0x65462323UL, 0x5e9dc3c3UL,
+    0x28301818UL, 0xa1379696UL, 0x0f0a0505UL, 0xb52f9a9aUL,
+    0x090e0707UL, 0x36241212UL, 0x9b1b8080UL, 0x3ddfe2e2UL,
+    0x26cdebebUL, 0x694e2727UL, 0xcd7fb2b2UL, 0x9fea7575UL,
+    0x1b120909UL, 0x9e1d8383UL, 0x74582c2cUL, 0x2e341a1aUL,
+    0x2d361b1bUL, 0xb2dc6e6eUL, 0xeeb45a5aUL, 0xfb5ba0a0UL,
+    0xf6a45252UL, 0x4d763b3bUL, 0x61b7d6d6UL, 0xce7db3b3UL,
+    0x7b522929UL, 0x3edde3e3UL, 0x715e2f2fUL, 0x97138484UL,
+    0xf5a65353UL, 0x68b9d1d1UL, 0x00000000UL, 0x2cc1ededUL,
+    0x60402020UL, 0x1fe3fcfcUL, 0xc879b1b1UL, 0xedb65b5bUL,
+    0xbed46a6aUL, 0x468dcbcbUL, 0xd967bebeUL, 0x4b723939UL,
+    0xde944a4aUL, 0xd4984c4cUL, 0xe8b05858UL, 0x4a85cfcfUL,
+    0x6bbbd0d0UL, 0x2ac5efefUL, 0xe54faaaaUL, 0x16edfbfbUL,
+    0xc5864343UL, 0xd79a4d4dUL, 0x55663333UL, 0x94118585UL,
+    0xcf8a4545UL, 0x10e9f9f9UL, 0x06040202UL, 0x81fe7f7fUL,
+    0xf0a05050UL, 0x44783c3cUL, 0xba259f9fUL, 0xe34ba8a8UL,
+    0xf3a25151UL, 0xfe5da3a3UL, 0xc0804040UL, 0x8a058f8fUL,
+    0xad3f9292UL, 0xbc219d9dUL, 0x48703838UL, 0x04f1f5f5UL,
+    0xdf63bcbcUL, 0xc177b6b6UL, 0x75afdadaUL, 0x63422121UL,
+    0x30201010UL, 0x1ae5ffffUL, 0x0efdf3f3UL, 0x6dbfd2d2UL,
+    0x4c81cdcdUL, 0x14180c0cUL, 0x35261313UL, 0x2fc3ececUL,
+    0xe1be5f5fUL, 0xa2359797UL, 0xcc884444UL, 0x392e1717UL,
+    0x5793c4c4UL, 0xf255a7a7UL, 0x82fc7e7eUL, 0x477a3d3dUL,
+    0xacc86464UL, 0xe7ba5d5dUL, 0x2b321919UL, 0x95e67373UL,
+    0xa0c06060UL, 0x98198181UL, 0xd19e4f4fUL, 0x7fa3dcdcUL,
+    0x66442222UL, 0x7e542a2aUL, 0xab3b9090UL, 0x830b8888UL,
+    0xca8c4646UL, 0x29c7eeeeUL, 0xd36bb8b8UL, 0x3c281414UL,
+    0x79a7dedeUL, 0xe2bc5e5eUL, 0x1d160b0bUL, 0x76addbdbUL,
+    0x3bdbe0e0UL, 0x56643232UL, 0x4e743a3aUL, 0x1e140a0aUL,
+    0xdb924949UL, 0x0a0c0606UL, 0x6c482424UL, 0xe4b85c5cUL,
+    0x5d9fc2c2UL, 0x6ebdd3d3UL, 0xef43acacUL, 0xa6c46262UL,
+    0xa8399191UL, 0xa4319595UL, 0x37d3e4e4UL, 0x8bf27979UL,
+    0x32d5e7e7UL, 0x438bc8c8UL, 0x596e3737UL, 0xb7da6d6dUL,
+    0x8c018d8dUL, 0x64b1d5d5UL, 0xd29c4e4eUL, 0xe049a9a9UL,
+    0xb4d86c6cUL, 0xfaac5656UL, 0x07f3f4f4UL, 0x25cfeaeaUL,
+    0xafca6565UL, 0x8ef47a7aUL, 0xe947aeaeUL, 0x18100808UL,
+    0xd56fbabaUL, 0x88f07878UL, 0x6f4a2525UL, 0x725c2e2eUL,
+    0x24381c1cUL, 0xf157a6a6UL, 0xc773b4b4UL, 0x5197c6c6UL,
+    0x23cbe8e8UL, 0x7ca1ddddUL, 0x9ce87474UL, 0x213e1f1fUL,
+    0xdd964b4bUL, 0xdc61bdbdUL, 0x860d8b8bUL, 0x850f8a8aUL,
+    0x90e07070UL, 0x427c3e3eUL, 0xc471b5b5UL, 0xaacc6666UL,
+    0xd8904848UL, 0x05060303UL, 0x01f7f6f6UL, 0x121c0e0eUL,
+    0xa3c26161UL, 0x5f6a3535UL, 0xf9ae5757UL, 0xd069b9b9UL,
+    0x91178686UL, 0x5899c1c1UL, 0x273a1d1dUL, 0xb9279e9eUL,
+    0x38d9e1e1UL, 0x13ebf8f8UL, 0xb32b9898UL, 0x33221111UL,
+    0xbbd26969UL, 0x70a9d9d9UL, 0x89078e8eUL, 0xa7339494UL,
+    0xb62d9b9bUL, 0x223c1e1eUL, 0x92158787UL, 0x20c9e9e9UL,
+    0x4987ceceUL, 0xffaa5555UL, 0x78502828UL, 0x7aa5dfdfUL,
+    0x8f038c8cUL, 0xf859a1a1UL, 0x80098989UL, 0x171a0d0dUL,
+    0xda65bfbfUL, 0x31d7e6e6UL, 0xc6844242UL, 0xb8d06868UL,
+    0xc3824141UL, 0xb0299999UL, 0x775a2d2dUL, 0x111e0f0fUL,
+    0xcb7bb0b0UL, 0xfca85454UL, 0xd66dbbbbUL, 0x3a2c1616UL,
+};
+static const ulong32 TE2[256] = {
+    0x63a5c663UL, 0x7c84f87cUL, 0x7799ee77UL, 0x7b8df67bUL,
+    0xf20dfff2UL, 0x6bbdd66bUL, 0x6fb1de6fUL, 0xc55491c5UL,
+    0x30506030UL, 0x01030201UL, 0x67a9ce67UL, 0x2b7d562bUL,
+    0xfe19e7feUL, 0xd762b5d7UL, 0xabe64dabUL, 0x769aec76UL,
+    0xca458fcaUL, 0x829d1f82UL, 0xc94089c9UL, 0x7d87fa7dUL,
+    0xfa15effaUL, 0x59ebb259UL, 0x47c98e47UL, 0xf00bfbf0UL,
+    0xadec41adUL, 0xd467b3d4UL, 0xa2fd5fa2UL, 0xafea45afUL,
+    0x9cbf239cUL, 0xa4f753a4UL, 0x7296e472UL, 0xc05b9bc0UL,
+    0xb7c275b7UL, 0xfd1ce1fdUL, 0x93ae3d93UL, 0x266a4c26UL,
+    0x365a6c36UL, 0x3f417e3fUL, 0xf702f5f7UL, 0xcc4f83ccUL,
+    0x345c6834UL, 0xa5f451a5UL, 0xe534d1e5UL, 0xf108f9f1UL,
+    0x7193e271UL, 0xd873abd8UL, 0x31536231UL, 0x153f2a15UL,
+    0x040c0804UL, 0xc75295c7UL, 0x23654623UL, 0xc35e9dc3UL,
+    0x18283018UL, 0x96a13796UL, 0x050f0a05UL, 0x9ab52f9aUL,
+    0x07090e07UL, 0x12362412UL, 0x809b1b80UL, 0xe23ddfe2UL,
+    0xeb26cdebUL, 0x27694e27UL, 0xb2cd7fb2UL, 0x759fea75UL,
+    0x091b1209UL, 0x839e1d83UL, 0x2c74582cUL, 0x1a2e341aUL,
+    0x1b2d361bUL, 0x6eb2dc6eUL, 0x5aeeb45aUL, 0xa0fb5ba0UL,
+    0x52f6a452UL, 0x3b4d763bUL, 0xd661b7d6UL, 0xb3ce7db3UL,
+    0x297b5229UL, 0xe33edde3UL, 0x2f715e2fUL, 0x84971384UL,
+    0x53f5a653UL, 0xd168b9d1UL, 0x00000000UL, 0xed2cc1edUL,
+    0x20604020UL, 0xfc1fe3fcUL, 0xb1c879b1UL, 0x5bedb65bUL,
+    0x6abed46aUL, 0xcb468dcbUL, 0xbed967beUL, 0x394b7239UL,
+    0x4ade944aUL, 0x4cd4984cUL, 0x58e8b058UL, 0xcf4a85cfUL,
+    0xd06bbbd0UL, 0xef2ac5efUL, 0xaae54faaUL, 0xfb16edfbUL,
+    0x43c58643UL, 0x4dd79a4dUL, 0x33556633UL, 0x85941185UL,
+    0x45cf8a45UL, 0xf910e9f9UL, 0x02060402UL, 0x7f81fe7fUL,
+    0x50f0a050UL, 0x3c44783cUL, 0x9fba259fUL, 0xa8e34ba8UL,
+    0x51f3a251UL, 0xa3fe5da3UL, 0x40c08040UL, 0x8f8a058fUL,
+    0x92ad3f92UL, 0x9dbc219dUL, 0x38487038UL, 0xf504f1f5UL,
+    0xbcdf63bcUL, 0xb6c177b6UL, 0xda75afdaUL, 0x21634221UL,
+    0x10302010UL, 0xff1ae5ffUL, 0xf30efdf3UL, 0xd26dbfd2UL,
+    0xcd4c81cdUL, 0x0c14180cUL, 0x13352613UL, 0xec2fc3ecUL,
+    0x5fe1be5fUL, 0x97a23597UL, 0x44cc8844UL, 0x17392e17UL,
+    0xc45793c4UL, 0xa7f255a7UL, 0x7e82fc7eUL, 0x3d477a3dUL,
+    0x64acc864UL, 0x5de7ba5dUL, 0x192b3219UL, 0x7395e673UL,
+    0x60a0c060UL, 0x81981981UL, 0x4fd19e4fUL, 0xdc7fa3dcUL,
+    0x22664422UL, 0x2a7e542aUL, 0x90ab3b90UL, 0x88830b88UL,
+    0x46ca8c46UL, 0xee29c7eeUL, 0xb8d36bb8UL, 0x143c2814UL,
+    0xde79a7deUL, 0x5ee2bc5eUL, 0x0b1d160bUL, 0xdb76addbUL,
+    0xe03bdbe0UL, 0x32566432UL, 0x3a4e743aUL, 0x0a1e140aUL,
+    0x49db9249UL, 0x060a0c06UL, 0x246c4824UL, 0x5ce4b85cUL,
+    0xc25d9fc2UL, 0xd36ebdd3UL, 0xacef43acUL, 0x62a6c462UL,
+    0x91a83991UL, 0x95a43195UL, 0xe437d3e4UL, 0x798bf279UL,
+    0xe732d5e7UL, 0xc8438bc8UL, 0x37596e37UL, 0x6db7da6dUL,
+    0x8d8c018dUL, 0xd564b1d5UL, 0x4ed29c4eUL, 0xa9e049a9UL,
+    0x6cb4d86cUL, 0x56faac56UL, 0xf407f3f4UL, 0xea25cfeaUL,
+    0x65afca65UL, 0x7a8ef47aUL, 0xaee947aeUL, 0x08181008UL,
+    0xbad56fbaUL, 0x7888f078UL, 0x256f4a25UL, 0x2e725c2eUL,
+    0x1c24381cUL, 0xa6f157a6UL, 0xb4c773b4UL, 0xc65197c6UL,
+    0xe823cbe8UL, 0xdd7ca1ddUL, 0x749ce874UL, 0x1f213e1fUL,
+    0x4bdd964bUL, 0xbddc61bdUL, 0x8b860d8bUL, 0x8a850f8aUL,
+    0x7090e070UL, 0x3e427c3eUL, 0xb5c471b5UL, 0x66aacc66UL,
+    0x48d89048UL, 0x03050603UL, 0xf601f7f6UL, 0x0e121c0eUL,
+    0x61a3c261UL, 0x355f6a35UL, 0x57f9ae57UL, 0xb9d069b9UL,
+    0x86911786UL, 0xc15899c1UL, 0x1d273a1dUL, 0x9eb9279eUL,
+    0xe138d9e1UL, 0xf813ebf8UL, 0x98b32b98UL, 0x11332211UL,
+    0x69bbd269UL, 0xd970a9d9UL, 0x8e89078eUL, 0x94a73394UL,
+    0x9bb62d9bUL, 0x1e223c1eUL, 0x87921587UL, 0xe920c9e9UL,
+    0xce4987ceUL, 0x55ffaa55UL, 0x28785028UL, 0xdf7aa5dfUL,
+    0x8c8f038cUL, 0xa1f859a1UL, 0x89800989UL, 0x0d171a0dUL,
+    0xbfda65bfUL, 0xe631d7e6UL, 0x42c68442UL, 0x68b8d068UL,
+    0x41c38241UL, 0x99b02999UL, 0x2d775a2dUL, 0x0f111e0fUL,
+    0xb0cb7bb0UL, 0x54fca854UL, 0xbbd66dbbUL, 0x163a2c16UL,
+};
+static const ulong32 TE3[256] = {
+
+    0x6363a5c6UL, 0x7c7c84f8UL, 0x777799eeUL, 0x7b7b8df6UL,
+    0xf2f20dffUL, 0x6b6bbdd6UL, 0x6f6fb1deUL, 0xc5c55491UL,
+    0x30305060UL, 0x01010302UL, 0x6767a9ceUL, 0x2b2b7d56UL,
+    0xfefe19e7UL, 0xd7d762b5UL, 0xababe64dUL, 0x76769aecUL,
+    0xcaca458fUL, 0x82829d1fUL, 0xc9c94089UL, 0x7d7d87faUL,
+    0xfafa15efUL, 0x5959ebb2UL, 0x4747c98eUL, 0xf0f00bfbUL,
+    0xadadec41UL, 0xd4d467b3UL, 0xa2a2fd5fUL, 0xafafea45UL,
+    0x9c9cbf23UL, 0xa4a4f753UL, 0x727296e4UL, 0xc0c05b9bUL,
+    0xb7b7c275UL, 0xfdfd1ce1UL, 0x9393ae3dUL, 0x26266a4cUL,
+    0x36365a6cUL, 0x3f3f417eUL, 0xf7f702f5UL, 0xcccc4f83UL,
+    0x34345c68UL, 0xa5a5f451UL, 0xe5e534d1UL, 0xf1f108f9UL,
+    0x717193e2UL, 0xd8d873abUL, 0x31315362UL, 0x15153f2aUL,
+    0x04040c08UL, 0xc7c75295UL, 0x23236546UL, 0xc3c35e9dUL,
+    0x18182830UL, 0x9696a137UL, 0x05050f0aUL, 0x9a9ab52fUL,
+    0x0707090eUL, 0x12123624UL, 0x80809b1bUL, 0xe2e23ddfUL,
+    0xebeb26cdUL, 0x2727694eUL, 0xb2b2cd7fUL, 0x75759feaUL,
+    0x09091b12UL, 0x83839e1dUL, 0x2c2c7458UL, 0x1a1a2e34UL,
+    0x1b1b2d36UL, 0x6e6eb2dcUL, 0x5a5aeeb4UL, 0xa0a0fb5bUL,
+    0x5252f6a4UL, 0x3b3b4d76UL, 0xd6d661b7UL, 0xb3b3ce7dUL,
+    0x29297b52UL, 0xe3e33eddUL, 0x2f2f715eUL, 0x84849713UL,
+    0x5353f5a6UL, 0xd1d168b9UL, 0x00000000UL, 0xeded2cc1UL,
+    0x20206040UL, 0xfcfc1fe3UL, 0xb1b1c879UL, 0x5b5bedb6UL,
+    0x6a6abed4UL, 0xcbcb468dUL, 0xbebed967UL, 0x39394b72UL,
+    0x4a4ade94UL, 0x4c4cd498UL, 0x5858e8b0UL, 0xcfcf4a85UL,
+    0xd0d06bbbUL, 0xefef2ac5UL, 0xaaaae54fUL, 0xfbfb16edUL,
+    0x4343c586UL, 0x4d4dd79aUL, 0x33335566UL, 0x85859411UL,
+    0x4545cf8aUL, 0xf9f910e9UL, 0x02020604UL, 0x7f7f81feUL,
+    0x5050f0a0UL, 0x3c3c4478UL, 0x9f9fba25UL, 0xa8a8e34bUL,
+    0x5151f3a2UL, 0xa3a3fe5dUL, 0x4040c080UL, 0x8f8f8a05UL,
+    0x9292ad3fUL, 0x9d9dbc21UL, 0x38384870UL, 0xf5f504f1UL,
+    0xbcbcdf63UL, 0xb6b6c177UL, 0xdada75afUL, 0x21216342UL,
+    0x10103020UL, 0xffff1ae5UL, 0xf3f30efdUL, 0xd2d26dbfUL,
+    0xcdcd4c81UL, 0x0c0c1418UL, 0x13133526UL, 0xecec2fc3UL,
+    0x5f5fe1beUL, 0x9797a235UL, 0x4444cc88UL, 0x1717392eUL,
+    0xc4c45793UL, 0xa7a7f255UL, 0x7e7e82fcUL, 0x3d3d477aUL,
+    0x6464acc8UL, 0x5d5de7baUL, 0x19192b32UL, 0x737395e6UL,
+    0x6060a0c0UL, 0x81819819UL, 0x4f4fd19eUL, 0xdcdc7fa3UL,
+    0x22226644UL, 0x2a2a7e54UL, 0x9090ab3bUL, 0x8888830bUL,
+    0x4646ca8cUL, 0xeeee29c7UL, 0xb8b8d36bUL, 0x14143c28UL,
+    0xdede79a7UL, 0x5e5ee2bcUL, 0x0b0b1d16UL, 0xdbdb76adUL,
+    0xe0e03bdbUL, 0x32325664UL, 0x3a3a4e74UL, 0x0a0a1e14UL,
+    0x4949db92UL, 0x06060a0cUL, 0x24246c48UL, 0x5c5ce4b8UL,
+    0xc2c25d9fUL, 0xd3d36ebdUL, 0xacacef43UL, 0x6262a6c4UL,
+    0x9191a839UL, 0x9595a431UL, 0xe4e437d3UL, 0x79798bf2UL,
+    0xe7e732d5UL, 0xc8c8438bUL, 0x3737596eUL, 0x6d6db7daUL,
+    0x8d8d8c01UL, 0xd5d564b1UL, 0x4e4ed29cUL, 0xa9a9e049UL,
+    0x6c6cb4d8UL, 0x5656faacUL, 0xf4f407f3UL, 0xeaea25cfUL,
+    0x6565afcaUL, 0x7a7a8ef4UL, 0xaeaee947UL, 0x08081810UL,
+    0xbabad56fUL, 0x787888f0UL, 0x25256f4aUL, 0x2e2e725cUL,
+    0x1c1c2438UL, 0xa6a6f157UL, 0xb4b4c773UL, 0xc6c65197UL,
+    0xe8e823cbUL, 0xdddd7ca1UL, 0x74749ce8UL, 0x1f1f213eUL,
+    0x4b4bdd96UL, 0xbdbddc61UL, 0x8b8b860dUL, 0x8a8a850fUL,
+    0x707090e0UL, 0x3e3e427cUL, 0xb5b5c471UL, 0x6666aaccUL,
+    0x4848d890UL, 0x03030506UL, 0xf6f601f7UL, 0x0e0e121cUL,
+    0x6161a3c2UL, 0x35355f6aUL, 0x5757f9aeUL, 0xb9b9d069UL,
+    0x86869117UL, 0xc1c15899UL, 0x1d1d273aUL, 0x9e9eb927UL,
+    0xe1e138d9UL, 0xf8f813ebUL, 0x9898b32bUL, 0x11113322UL,
+    0x6969bbd2UL, 0xd9d970a9UL, 0x8e8e8907UL, 0x9494a733UL,
+    0x9b9bb62dUL, 0x1e1e223cUL, 0x87879215UL, 0xe9e920c9UL,
+    0xcece4987UL, 0x5555ffaaUL, 0x28287850UL, 0xdfdf7aa5UL,
+    0x8c8c8f03UL, 0xa1a1f859UL, 0x89898009UL, 0x0d0d171aUL,
+    0xbfbfda65UL, 0xe6e631d7UL, 0x4242c684UL, 0x6868b8d0UL,
+    0x4141c382UL, 0x9999b029UL, 0x2d2d775aUL, 0x0f0f111eUL,
+    0xb0b0cb7bUL, 0x5454fca8UL, 0xbbbbd66dUL, 0x16163a2cUL,
+};
+
+#ifndef PELI_TAB
+static const ulong32 Te4_0[] = {
+0x00000063UL, 0x0000007cUL, 0x00000077UL, 0x0000007bUL, 0x000000f2UL, 0x0000006bUL, 0x0000006fUL, 0x000000c5UL,
+0x00000030UL, 0x00000001UL, 0x00000067UL, 0x0000002bUL, 0x000000feUL, 0x000000d7UL, 0x000000abUL, 0x00000076UL,
+0x000000caUL, 0x00000082UL, 0x000000c9UL, 0x0000007dUL, 0x000000faUL, 0x00000059UL, 0x00000047UL, 0x000000f0UL,
+0x000000adUL, 0x000000d4UL, 0x000000a2UL, 0x000000afUL, 0x0000009cUL, 0x000000a4UL, 0x00000072UL, 0x000000c0UL,
+0x000000b7UL, 0x000000fdUL, 0x00000093UL, 0x00000026UL, 0x00000036UL, 0x0000003fUL, 0x000000f7UL, 0x000000ccUL,
+0x00000034UL, 0x000000a5UL, 0x000000e5UL, 0x000000f1UL, 0x00000071UL, 0x000000d8UL, 0x00000031UL, 0x00000015UL,
+0x00000004UL, 0x000000c7UL, 0x00000023UL, 0x000000c3UL, 0x00000018UL, 0x00000096UL, 0x00000005UL, 0x0000009aUL,
+0x00000007UL, 0x00000012UL, 0x00000080UL, 0x000000e2UL, 0x000000ebUL, 0x00000027UL, 0x000000b2UL, 0x00000075UL,
+0x00000009UL, 0x00000083UL, 0x0000002cUL, 0x0000001aUL, 0x0000001bUL, 0x0000006eUL, 0x0000005aUL, 0x000000a0UL,
+0x00000052UL, 0x0000003bUL, 0x000000d6UL, 0x000000b3UL, 0x00000029UL, 0x000000e3UL, 0x0000002fUL, 0x00000084UL,
+0x00000053UL, 0x000000d1UL, 0x00000000UL, 0x000000edUL, 0x00000020UL, 0x000000fcUL, 0x000000b1UL, 0x0000005bUL,
+0x0000006aUL, 0x000000cbUL, 0x000000beUL, 0x00000039UL, 0x0000004aUL, 0x0000004cUL, 0x00000058UL, 0x000000cfUL,
+0x000000d0UL, 0x000000efUL, 0x000000aaUL, 0x000000fbUL, 0x00000043UL, 0x0000004dUL, 0x00000033UL, 0x00000085UL,
+0x00000045UL, 0x000000f9UL, 0x00000002UL, 0x0000007fUL, 0x00000050UL, 0x0000003cUL, 0x0000009fUL, 0x000000a8UL,
+0x00000051UL, 0x000000a3UL, 0x00000040UL, 0x0000008fUL, 0x00000092UL, 0x0000009dUL, 0x00000038UL, 0x000000f5UL,
+0x000000bcUL, 0x000000b6UL, 0x000000daUL, 0x00000021UL, 0x00000010UL, 0x000000ffUL, 0x000000f3UL, 0x000000d2UL,
+0x000000cdUL, 0x0000000cUL, 0x00000013UL, 0x000000ecUL, 0x0000005fUL, 0x00000097UL, 0x00000044UL, 0x00000017UL,
+0x000000c4UL, 0x000000a7UL, 0x0000007eUL, 0x0000003dUL, 0x00000064UL, 0x0000005dUL, 0x00000019UL, 0x00000073UL,
+0x00000060UL, 0x00000081UL, 0x0000004fUL, 0x000000dcUL, 0x00000022UL, 0x0000002aUL, 0x00000090UL, 0x00000088UL,
+0x00000046UL, 0x000000eeUL, 0x000000b8UL, 0x00000014UL, 0x000000deUL, 0x0000005eUL, 0x0000000bUL, 0x000000dbUL,
+0x000000e0UL, 0x00000032UL, 0x0000003aUL, 0x0000000aUL, 0x00000049UL, 0x00000006UL, 0x00000024UL, 0x0000005cUL,
+0x000000c2UL, 0x000000d3UL, 0x000000acUL, 0x00000062UL, 0x00000091UL, 0x00000095UL, 0x000000e4UL, 0x00000079UL,
+0x000000e7UL, 0x000000c8UL, 0x00000037UL, 0x0000006dUL, 0x0000008dUL, 0x000000d5UL, 0x0000004eUL, 0x000000a9UL,
+0x0000006cUL, 0x00000056UL, 0x000000f4UL, 0x000000eaUL, 0x00000065UL, 0x0000007aUL, 0x000000aeUL, 0x00000008UL,
+0x000000baUL, 0x00000078UL, 0x00000025UL, 0x0000002eUL, 0x0000001cUL, 0x000000a6UL, 0x000000b4UL, 0x000000c6UL,
+0x000000e8UL, 0x000000ddUL, 0x00000074UL, 0x0000001fUL, 0x0000004bUL, 0x000000bdUL, 0x0000008bUL, 0x0000008aUL,
+0x00000070UL, 0x0000003eUL, 0x000000b5UL, 0x00000066UL, 0x00000048UL, 0x00000003UL, 0x000000f6UL, 0x0000000eUL,
+0x00000061UL, 0x00000035UL, 0x00000057UL, 0x000000b9UL, 0x00000086UL, 0x000000c1UL, 0x0000001dUL, 0x0000009eUL,
+0x000000e1UL, 0x000000f8UL, 0x00000098UL, 0x00000011UL, 0x00000069UL, 0x000000d9UL, 0x0000008eUL, 0x00000094UL,
+0x0000009bUL, 0x0000001eUL, 0x00000087UL, 0x000000e9UL, 0x000000ceUL, 0x00000055UL, 0x00000028UL, 0x000000dfUL,
+0x0000008cUL, 0x000000a1UL, 0x00000089UL, 0x0000000dUL, 0x000000bfUL, 0x000000e6UL, 0x00000042UL, 0x00000068UL,
+0x00000041UL, 0x00000099UL, 0x0000002dUL, 0x0000000fUL, 0x000000b0UL, 0x00000054UL, 0x000000bbUL, 0x00000016UL
+};
+
+static const ulong32 Te4_1[] = {
+0x00006300UL, 0x00007c00UL, 0x00007700UL, 0x00007b00UL, 0x0000f200UL, 0x00006b00UL, 0x00006f00UL, 0x0000c500UL,
+0x00003000UL, 0x00000100UL, 0x00006700UL, 0x00002b00UL, 0x0000fe00UL, 0x0000d700UL, 0x0000ab00UL, 0x00007600UL,
+0x0000ca00UL, 0x00008200UL, 0x0000c900UL, 0x00007d00UL, 0x0000fa00UL, 0x00005900UL, 0x00004700UL, 0x0000f000UL,
+0x0000ad00UL, 0x0000d400UL, 0x0000a200UL, 0x0000af00UL, 0x00009c00UL, 0x0000a400UL, 0x00007200UL, 0x0000c000UL,
+0x0000b700UL, 0x0000fd00UL, 0x00009300UL, 0x00002600UL, 0x00003600UL, 0x00003f00UL, 0x0000f700UL, 0x0000cc00UL,
+0x00003400UL, 0x0000a500UL, 0x0000e500UL, 0x0000f100UL, 0x00007100UL, 0x0000d800UL, 0x00003100UL, 0x00001500UL,
+0x00000400UL, 0x0000c700UL, 0x00002300UL, 0x0000c300UL, 0x00001800UL, 0x00009600UL, 0x00000500UL, 0x00009a00UL,
+0x00000700UL, 0x00001200UL, 0x00008000UL, 0x0000e200UL, 0x0000eb00UL, 0x00002700UL, 0x0000b200UL, 0x00007500UL,
+0x00000900UL, 0x00008300UL, 0x00002c00UL, 0x00001a00UL, 0x00001b00UL, 0x00006e00UL, 0x00005a00UL, 0x0000a000UL,
+0x00005200UL, 0x00003b00UL, 0x0000d600UL, 0x0000b300UL, 0x00002900UL, 0x0000e300UL, 0x00002f00UL, 0x00008400UL,
+0x00005300UL, 0x0000d100UL, 0x00000000UL, 0x0000ed00UL, 0x00002000UL, 0x0000fc00UL, 0x0000b100UL, 0x00005b00UL,
+0x00006a00UL, 0x0000cb00UL, 0x0000be00UL, 0x00003900UL, 0x00004a00UL, 0x00004c00UL, 0x00005800UL, 0x0000cf00UL,
+0x0000d000UL, 0x0000ef00UL, 0x0000aa00UL, 0x0000fb00UL, 0x00004300UL, 0x00004d00UL, 0x00003300UL, 0x00008500UL,
+0x00004500UL, 0x0000f900UL, 0x00000200UL, 0x00007f00UL, 0x00005000UL, 0x00003c00UL, 0x00009f00UL, 0x0000a800UL,
+0x00005100UL, 0x0000a300UL, 0x00004000UL, 0x00008f00UL, 0x00009200UL, 0x00009d00UL, 0x00003800UL, 0x0000f500UL,
+0x0000bc00UL, 0x0000b600UL, 0x0000da00UL, 0x00002100UL, 0x00001000UL, 0x0000ff00UL, 0x0000f300UL, 0x0000d200UL,
+0x0000cd00UL, 0x00000c00UL, 0x00001300UL, 0x0000ec00UL, 0x00005f00UL, 0x00009700UL, 0x00004400UL, 0x00001700UL,
+0x0000c400UL, 0x0000a700UL, 0x00007e00UL, 0x00003d00UL, 0x00006400UL, 0x00005d00UL, 0x00001900UL, 0x00007300UL,
+0x00006000UL, 0x00008100UL, 0x00004f00UL, 0x0000dc00UL, 0x00002200UL, 0x00002a00UL, 0x00009000UL, 0x00008800UL,
+0x00004600UL, 0x0000ee00UL, 0x0000b800UL, 0x00001400UL, 0x0000de00UL, 0x00005e00UL, 0x00000b00UL, 0x0000db00UL,
+0x0000e000UL, 0x00003200UL, 0x00003a00UL, 0x00000a00UL, 0x00004900UL, 0x00000600UL, 0x00002400UL, 0x00005c00UL,
+0x0000c200UL, 0x0000d300UL, 0x0000ac00UL, 0x00006200UL, 0x00009100UL, 0x00009500UL, 0x0000e400UL, 0x00007900UL,
+0x0000e700UL, 0x0000c800UL, 0x00003700UL, 0x00006d00UL, 0x00008d00UL, 0x0000d500UL, 0x00004e00UL, 0x0000a900UL,
+0x00006c00UL, 0x00005600UL, 0x0000f400UL, 0x0000ea00UL, 0x00006500UL, 0x00007a00UL, 0x0000ae00UL, 0x00000800UL,
+0x0000ba00UL, 0x00007800UL, 0x00002500UL, 0x00002e00UL, 0x00001c00UL, 0x0000a600UL, 0x0000b400UL, 0x0000c600UL,
+0x0000e800UL, 0x0000dd00UL, 0x00007400UL, 0x00001f00UL, 0x00004b00UL, 0x0000bd00UL, 0x00008b00UL, 0x00008a00UL,
+0x00007000UL, 0x00003e00UL, 0x0000b500UL, 0x00006600UL, 0x00004800UL, 0x00000300UL, 0x0000f600UL, 0x00000e00UL,
+0x00006100UL, 0x00003500UL, 0x00005700UL, 0x0000b900UL, 0x00008600UL, 0x0000c100UL, 0x00001d00UL, 0x00009e00UL,
+0x0000e100UL, 0x0000f800UL, 0x00009800UL, 0x00001100UL, 0x00006900UL, 0x0000d900UL, 0x00008e00UL, 0x00009400UL,
+0x00009b00UL, 0x00001e00UL, 0x00008700UL, 0x0000e900UL, 0x0000ce00UL, 0x00005500UL, 0x00002800UL, 0x0000df00UL,
+0x00008c00UL, 0x0000a100UL, 0x00008900UL, 0x00000d00UL, 0x0000bf00UL, 0x0000e600UL, 0x00004200UL, 0x00006800UL,
+0x00004100UL, 0x00009900UL, 0x00002d00UL, 0x00000f00UL, 0x0000b000UL, 0x00005400UL, 0x0000bb00UL, 0x00001600UL
+};
+
+static const ulong32 Te4_2[] = {
+0x00630000UL, 0x007c0000UL, 0x00770000UL, 0x007b0000UL, 0x00f20000UL, 0x006b0000UL, 0x006f0000UL, 0x00c50000UL,
+0x00300000UL, 0x00010000UL, 0x00670000UL, 0x002b0000UL, 0x00fe0000UL, 0x00d70000UL, 0x00ab0000UL, 0x00760000UL,
+0x00ca0000UL, 0x00820000UL, 0x00c90000UL, 0x007d0000UL, 0x00fa0000UL, 0x00590000UL, 0x00470000UL, 0x00f00000UL,
+0x00ad0000UL, 0x00d40000UL, 0x00a20000UL, 0x00af0000UL, 0x009c0000UL, 0x00a40000UL, 0x00720000UL, 0x00c00000UL,
+0x00b70000UL, 0x00fd0000UL, 0x00930000UL, 0x00260000UL, 0x00360000UL, 0x003f0000UL, 0x00f70000UL, 0x00cc0000UL,
+0x00340000UL, 0x00a50000UL, 0x00e50000UL, 0x00f10000UL, 0x00710000UL, 0x00d80000UL, 0x00310000UL, 0x00150000UL,
+0x00040000UL, 0x00c70000UL, 0x00230000UL, 0x00c30000UL, 0x00180000UL, 0x00960000UL, 0x00050000UL, 0x009a0000UL,
+0x00070000UL, 0x00120000UL, 0x00800000UL, 0x00e20000UL, 0x00eb0000UL, 0x00270000UL, 0x00b20000UL, 0x00750000UL,
+0x00090000UL, 0x00830000UL, 0x002c0000UL, 0x001a0000UL, 0x001b0000UL, 0x006e0000UL, 0x005a0000UL, 0x00a00000UL,
+0x00520000UL, 0x003b0000UL, 0x00d60000UL, 0x00b30000UL, 0x00290000UL, 0x00e30000UL, 0x002f0000UL, 0x00840000UL,
+0x00530000UL, 0x00d10000UL, 0x00000000UL, 0x00ed0000UL, 0x00200000UL, 0x00fc0000UL, 0x00b10000UL, 0x005b0000UL,
+0x006a0000UL, 0x00cb0000UL, 0x00be0000UL, 0x00390000UL, 0x004a0000UL, 0x004c0000UL, 0x00580000UL, 0x00cf0000UL,
+0x00d00000UL, 0x00ef0000UL, 0x00aa0000UL, 0x00fb0000UL, 0x00430000UL, 0x004d0000UL, 0x00330000UL, 0x00850000UL,
+0x00450000UL, 0x00f90000UL, 0x00020000UL, 0x007f0000UL, 0x00500000UL, 0x003c0000UL, 0x009f0000UL, 0x00a80000UL,
+0x00510000UL, 0x00a30000UL, 0x00400000UL, 0x008f0000UL, 0x00920000UL, 0x009d0000UL, 0x00380000UL, 0x00f50000UL,
+0x00bc0000UL, 0x00b60000UL, 0x00da0000UL, 0x00210000UL, 0x00100000UL, 0x00ff0000UL, 0x00f30000UL, 0x00d20000UL,
+0x00cd0000UL, 0x000c0000UL, 0x00130000UL, 0x00ec0000UL, 0x005f0000UL, 0x00970000UL, 0x00440000UL, 0x00170000UL,
+0x00c40000UL, 0x00a70000UL, 0x007e0000UL, 0x003d0000UL, 0x00640000UL, 0x005d0000UL, 0x00190000UL, 0x00730000UL,
+0x00600000UL, 0x00810000UL, 0x004f0000UL, 0x00dc0000UL, 0x00220000UL, 0x002a0000UL, 0x00900000UL, 0x00880000UL,
+0x00460000UL, 0x00ee0000UL, 0x00b80000UL, 0x00140000UL, 0x00de0000UL, 0x005e0000UL, 0x000b0000UL, 0x00db0000UL,
+0x00e00000UL, 0x00320000UL, 0x003a0000UL, 0x000a0000UL, 0x00490000UL, 0x00060000UL, 0x00240000UL, 0x005c0000UL,
+0x00c20000UL, 0x00d30000UL, 0x00ac0000UL, 0x00620000UL, 0x00910000UL, 0x00950000UL, 0x00e40000UL, 0x00790000UL,
+0x00e70000UL, 0x00c80000UL, 0x00370000UL, 0x006d0000UL, 0x008d0000UL, 0x00d50000UL, 0x004e0000UL, 0x00a90000UL,
+0x006c0000UL, 0x00560000UL, 0x00f40000UL, 0x00ea0000UL, 0x00650000UL, 0x007a0000UL, 0x00ae0000UL, 0x00080000UL,
+0x00ba0000UL, 0x00780000UL, 0x00250000UL, 0x002e0000UL, 0x001c0000UL, 0x00a60000UL, 0x00b40000UL, 0x00c60000UL,
+0x00e80000UL, 0x00dd0000UL, 0x00740000UL, 0x001f0000UL, 0x004b0000UL, 0x00bd0000UL, 0x008b0000UL, 0x008a0000UL,
+0x00700000UL, 0x003e0000UL, 0x00b50000UL, 0x00660000UL, 0x00480000UL, 0x00030000UL, 0x00f60000UL, 0x000e0000UL,
+0x00610000UL, 0x00350000UL, 0x00570000UL, 0x00b90000UL, 0x00860000UL, 0x00c10000UL, 0x001d0000UL, 0x009e0000UL,
+0x00e10000UL, 0x00f80000UL, 0x00980000UL, 0x00110000UL, 0x00690000UL, 0x00d90000UL, 0x008e0000UL, 0x00940000UL,
+0x009b0000UL, 0x001e0000UL, 0x00870000UL, 0x00e90000UL, 0x00ce0000UL, 0x00550000UL, 0x00280000UL, 0x00df0000UL,
+0x008c0000UL, 0x00a10000UL, 0x00890000UL, 0x000d0000UL, 0x00bf0000UL, 0x00e60000UL, 0x00420000UL, 0x00680000UL,
+0x00410000UL, 0x00990000UL, 0x002d0000UL, 0x000f0000UL, 0x00b00000UL, 0x00540000UL, 0x00bb0000UL, 0x00160000UL
+};
+
+static const ulong32 Te4_3[] = {
+0x63000000UL, 0x7c000000UL, 0x77000000UL, 0x7b000000UL, 0xf2000000UL, 0x6b000000UL, 0x6f000000UL, 0xc5000000UL,
+0x30000000UL, 0x01000000UL, 0x67000000UL, 0x2b000000UL, 0xfe000000UL, 0xd7000000UL, 0xab000000UL, 0x76000000UL,
+0xca000000UL, 0x82000000UL, 0xc9000000UL, 0x7d000000UL, 0xfa000000UL, 0x59000000UL, 0x47000000UL, 0xf0000000UL,
+0xad000000UL, 0xd4000000UL, 0xa2000000UL, 0xaf000000UL, 0x9c000000UL, 0xa4000000UL, 0x72000000UL, 0xc0000000UL,
+0xb7000000UL, 0xfd000000UL, 0x93000000UL, 0x26000000UL, 0x36000000UL, 0x3f000000UL, 0xf7000000UL, 0xcc000000UL,
+0x34000000UL, 0xa5000000UL, 0xe5000000UL, 0xf1000000UL, 0x71000000UL, 0xd8000000UL, 0x31000000UL, 0x15000000UL,
+0x04000000UL, 0xc7000000UL, 0x23000000UL, 0xc3000000UL, 0x18000000UL, 0x96000000UL, 0x05000000UL, 0x9a000000UL,
+0x07000000UL, 0x12000000UL, 0x80000000UL, 0xe2000000UL, 0xeb000000UL, 0x27000000UL, 0xb2000000UL, 0x75000000UL,
+0x09000000UL, 0x83000000UL, 0x2c000000UL, 0x1a000000UL, 0x1b000000UL, 0x6e000000UL, 0x5a000000UL, 0xa0000000UL,
+0x52000000UL, 0x3b000000UL, 0xd6000000UL, 0xb3000000UL, 0x29000000UL, 0xe3000000UL, 0x2f000000UL, 0x84000000UL,
+0x53000000UL, 0xd1000000UL, 0x00000000UL, 0xed000000UL, 0x20000000UL, 0xfc000000UL, 0xb1000000UL, 0x5b000000UL,
+0x6a000000UL, 0xcb000000UL, 0xbe000000UL, 0x39000000UL, 0x4a000000UL, 0x4c000000UL, 0x58000000UL, 0xcf000000UL,
+0xd0000000UL, 0xef000000UL, 0xaa000000UL, 0xfb000000UL, 0x43000000UL, 0x4d000000UL, 0x33000000UL, 0x85000000UL,
+0x45000000UL, 0xf9000000UL, 0x02000000UL, 0x7f000000UL, 0x50000000UL, 0x3c000000UL, 0x9f000000UL, 0xa8000000UL,
+0x51000000UL, 0xa3000000UL, 0x40000000UL, 0x8f000000UL, 0x92000000UL, 0x9d000000UL, 0x38000000UL, 0xf5000000UL,
+0xbc000000UL, 0xb6000000UL, 0xda000000UL, 0x21000000UL, 0x10000000UL, 0xff000000UL, 0xf3000000UL, 0xd2000000UL,
+0xcd000000UL, 0x0c000000UL, 0x13000000UL, 0xec000000UL, 0x5f000000UL, 0x97000000UL, 0x44000000UL, 0x17000000UL,
+0xc4000000UL, 0xa7000000UL, 0x7e000000UL, 0x3d000000UL, 0x64000000UL, 0x5d000000UL, 0x19000000UL, 0x73000000UL,
+0x60000000UL, 0x81000000UL, 0x4f000000UL, 0xdc000000UL, 0x22000000UL, 0x2a000000UL, 0x90000000UL, 0x88000000UL,
+0x46000000UL, 0xee000000UL, 0xb8000000UL, 0x14000000UL, 0xde000000UL, 0x5e000000UL, 0x0b000000UL, 0xdb000000UL,
+0xe0000000UL, 0x32000000UL, 0x3a000000UL, 0x0a000000UL, 0x49000000UL, 0x06000000UL, 0x24000000UL, 0x5c000000UL,
+0xc2000000UL, 0xd3000000UL, 0xac000000UL, 0x62000000UL, 0x91000000UL, 0x95000000UL, 0xe4000000UL, 0x79000000UL,
+0xe7000000UL, 0xc8000000UL, 0x37000000UL, 0x6d000000UL, 0x8d000000UL, 0xd5000000UL, 0x4e000000UL, 0xa9000000UL,
+0x6c000000UL, 0x56000000UL, 0xf4000000UL, 0xea000000UL, 0x65000000UL, 0x7a000000UL, 0xae000000UL, 0x08000000UL,
+0xba000000UL, 0x78000000UL, 0x25000000UL, 0x2e000000UL, 0x1c000000UL, 0xa6000000UL, 0xb4000000UL, 0xc6000000UL,
+0xe8000000UL, 0xdd000000UL, 0x74000000UL, 0x1f000000UL, 0x4b000000UL, 0xbd000000UL, 0x8b000000UL, 0x8a000000UL,
+0x70000000UL, 0x3e000000UL, 0xb5000000UL, 0x66000000UL, 0x48000000UL, 0x03000000UL, 0xf6000000UL, 0x0e000000UL,
+0x61000000UL, 0x35000000UL, 0x57000000UL, 0xb9000000UL, 0x86000000UL, 0xc1000000UL, 0x1d000000UL, 0x9e000000UL,
+0xe1000000UL, 0xf8000000UL, 0x98000000UL, 0x11000000UL, 0x69000000UL, 0xd9000000UL, 0x8e000000UL, 0x94000000UL,
+0x9b000000UL, 0x1e000000UL, 0x87000000UL, 0xe9000000UL, 0xce000000UL, 0x55000000UL, 0x28000000UL, 0xdf000000UL,
+0x8c000000UL, 0xa1000000UL, 0x89000000UL, 0x0d000000UL, 0xbf000000UL, 0xe6000000UL, 0x42000000UL, 0x68000000UL,
+0x41000000UL, 0x99000000UL, 0x2d000000UL, 0x0f000000UL, 0xb0000000UL, 0x54000000UL, 0xbb000000UL, 0x16000000UL
+};
+#endif /* pelimac */
+
+#ifndef ENCRYPT_ONLY
+
+static const ulong32 TD1[256] = {
+    0x5051f4a7UL, 0x537e4165UL, 0xc31a17a4UL, 0x963a275eUL,
+    0xcb3bab6bUL, 0xf11f9d45UL, 0xabacfa58UL, 0x934be303UL,
+    0x552030faUL, 0xf6ad766dUL, 0x9188cc76UL, 0x25f5024cUL,
+    0xfc4fe5d7UL, 0xd7c52acbUL, 0x80263544UL, 0x8fb562a3UL,
+    0x49deb15aUL, 0x6725ba1bUL, 0x9845ea0eUL, 0xe15dfec0UL,
+    0x02c32f75UL, 0x12814cf0UL, 0xa38d4697UL, 0xc66bd3f9UL,
+    0xe7038f5fUL, 0x9515929cUL, 0xebbf6d7aUL, 0xda955259UL,
+    0x2dd4be83UL, 0xd3587421UL, 0x2949e069UL, 0x448ec9c8UL,
+    0x6a75c289UL, 0x78f48e79UL, 0x6b99583eUL, 0xdd27b971UL,
+    0xb6bee14fUL, 0x17f088adUL, 0x66c920acUL, 0xb47dce3aUL,
+    0x1863df4aUL, 0x82e51a31UL, 0x60975133UL, 0x4562537fUL,
+    0xe0b16477UL, 0x84bb6baeUL, 0x1cfe81a0UL, 0x94f9082bUL,
+    0x58704868UL, 0x198f45fdUL, 0x8794de6cUL, 0xb7527bf8UL,
+    0x23ab73d3UL, 0xe2724b02UL, 0x57e31f8fUL, 0x2a6655abUL,
+    0x07b2eb28UL, 0x032fb5c2UL, 0x9a86c57bUL, 0xa5d33708UL,
+    0xf2302887UL, 0xb223bfa5UL, 0xba02036aUL, 0x5ced1682UL,
+    0x2b8acf1cUL, 0x92a779b4UL, 0xf0f307f2UL, 0xa14e69e2UL,
+    0xcd65daf4UL, 0xd50605beUL, 0x1fd13462UL, 0x8ac4a6feUL,
+    0x9d342e53UL, 0xa0a2f355UL, 0x32058ae1UL, 0x75a4f6ebUL,
+    0x390b83ecUL, 0xaa4060efUL, 0x065e719fUL, 0x51bd6e10UL,
+    0xf93e218aUL, 0x3d96dd06UL, 0xaedd3e05UL, 0x464de6bdUL,
+    0xb591548dUL, 0x0571c45dUL, 0x6f0406d4UL, 0xff605015UL,
+    0x241998fbUL, 0x97d6bde9UL, 0xcc894043UL, 0x7767d99eUL,
+    0xbdb0e842UL, 0x8807898bUL, 0x38e7195bUL, 0xdb79c8eeUL,
+    0x47a17c0aUL, 0xe97c420fUL, 0xc9f8841eUL, 0x00000000UL,
+    0x83098086UL, 0x48322bedUL, 0xac1e1170UL, 0x4e6c5a72UL,
+    0xfbfd0effUL, 0x560f8538UL, 0x1e3daed5UL, 0x27362d39UL,
+    0x640a0fd9UL, 0x21685ca6UL, 0xd19b5b54UL, 0x3a24362eUL,
+    0xb10c0a67UL, 0x0f9357e7UL, 0xd2b4ee96UL, 0x9e1b9b91UL,
+    0x4f80c0c5UL, 0xa261dc20UL, 0x695a774bUL, 0x161c121aUL,
+    0x0ae293baUL, 0xe5c0a02aUL, 0x433c22e0UL, 0x1d121b17UL,
+    0x0b0e090dUL, 0xadf28bc7UL, 0xb92db6a8UL, 0xc8141ea9UL,
+    0x8557f119UL, 0x4caf7507UL, 0xbbee99ddUL, 0xfda37f60UL,
+    0x9ff70126UL, 0xbc5c72f5UL, 0xc544663bUL, 0x345bfb7eUL,
+    0x768b4329UL, 0xdccb23c6UL, 0x68b6edfcUL, 0x63b8e4f1UL,
+    0xcad731dcUL, 0x10426385UL, 0x40139722UL, 0x2084c611UL,
+    0x7d854a24UL, 0xf8d2bb3dUL, 0x11aef932UL, 0x6dc729a1UL,
+    0x4b1d9e2fUL, 0xf3dcb230UL, 0xec0d8652UL, 0xd077c1e3UL,
+    0x6c2bb316UL, 0x99a970b9UL, 0xfa119448UL, 0x2247e964UL,
+    0xc4a8fc8cUL, 0x1aa0f03fUL, 0xd8567d2cUL, 0xef223390UL,
+    0xc787494eUL, 0xc1d938d1UL, 0xfe8ccaa2UL, 0x3698d40bUL,
+    0xcfa6f581UL, 0x28a57adeUL, 0x26dab78eUL, 0xa43fadbfUL,
+    0xe42c3a9dUL, 0x0d507892UL, 0x9b6a5fccUL, 0x62547e46UL,
+    0xc2f68d13UL, 0xe890d8b8UL, 0x5e2e39f7UL, 0xf582c3afUL,
+    0xbe9f5d80UL, 0x7c69d093UL, 0xa96fd52dUL, 0xb3cf2512UL,
+    0x3bc8ac99UL, 0xa710187dUL, 0x6ee89c63UL, 0x7bdb3bbbUL,
+    0x09cd2678UL, 0xf46e5918UL, 0x01ec9ab7UL, 0xa8834f9aUL,
+    0x65e6956eUL, 0x7eaaffe6UL, 0x0821bccfUL, 0xe6ef15e8UL,
+    0xd9bae79bUL, 0xce4a6f36UL, 0xd4ea9f09UL, 0xd629b07cUL,
+    0xaf31a4b2UL, 0x312a3f23UL, 0x30c6a594UL, 0xc035a266UL,
+    0x37744ebcUL, 0xa6fc82caUL, 0xb0e090d0UL, 0x1533a7d8UL,
+    0x4af10498UL, 0xf741ecdaUL, 0x0e7fcd50UL, 0x2f1791f6UL,
+    0x8d764dd6UL, 0x4d43efb0UL, 0x54ccaa4dUL, 0xdfe49604UL,
+    0xe39ed1b5UL, 0x1b4c6a88UL, 0xb8c12c1fUL, 0x7f466551UL,
+    0x049d5eeaUL, 0x5d018c35UL, 0x73fa8774UL, 0x2efb0b41UL,
+    0x5ab3671dUL, 0x5292dbd2UL, 0x33e91056UL, 0x136dd647UL,
+    0x8c9ad761UL, 0x7a37a10cUL, 0x8e59f814UL, 0x89eb133cUL,
+    0xeecea927UL, 0x35b761c9UL, 0xede11ce5UL, 0x3c7a47b1UL,
+    0x599cd2dfUL, 0x3f55f273UL, 0x791814ceUL, 0xbf73c737UL,
+    0xea53f7cdUL, 0x5b5ffdaaUL, 0x14df3d6fUL, 0x867844dbUL,
+    0x81caaff3UL, 0x3eb968c4UL, 0x2c382434UL, 0x5fc2a340UL,
+    0x72161dc3UL, 0x0cbce225UL, 0x8b283c49UL, 0x41ff0d95UL,
+    0x7139a801UL, 0xde080cb3UL, 0x9cd8b4e4UL, 0x906456c1UL,
+    0x617bcb84UL, 0x70d532b6UL, 0x74486c5cUL, 0x42d0b857UL,
+};
+static const ulong32 TD2[256] = {
+    0xa75051f4UL, 0x65537e41UL, 0xa4c31a17UL, 0x5e963a27UL,
+    0x6bcb3babUL, 0x45f11f9dUL, 0x58abacfaUL, 0x03934be3UL,
+    0xfa552030UL, 0x6df6ad76UL, 0x769188ccUL, 0x4c25f502UL,
+    0xd7fc4fe5UL, 0xcbd7c52aUL, 0x44802635UL, 0xa38fb562UL,
+    0x5a49deb1UL, 0x1b6725baUL, 0x0e9845eaUL, 0xc0e15dfeUL,
+    0x7502c32fUL, 0xf012814cUL, 0x97a38d46UL, 0xf9c66bd3UL,
+    0x5fe7038fUL, 0x9c951592UL, 0x7aebbf6dUL, 0x59da9552UL,
+    0x832dd4beUL, 0x21d35874UL, 0x692949e0UL, 0xc8448ec9UL,
+    0x896a75c2UL, 0x7978f48eUL, 0x3e6b9958UL, 0x71dd27b9UL,
+    0x4fb6bee1UL, 0xad17f088UL, 0xac66c920UL, 0x3ab47dceUL,
+    0x4a1863dfUL, 0x3182e51aUL, 0x33609751UL, 0x7f456253UL,
+    0x77e0b164UL, 0xae84bb6bUL, 0xa01cfe81UL, 0x2b94f908UL,
+    0x68587048UL, 0xfd198f45UL, 0x6c8794deUL, 0xf8b7527bUL,
+    0xd323ab73UL, 0x02e2724bUL, 0x8f57e31fUL, 0xab2a6655UL,
+    0x2807b2ebUL, 0xc2032fb5UL, 0x7b9a86c5UL, 0x08a5d337UL,
+    0x87f23028UL, 0xa5b223bfUL, 0x6aba0203UL, 0x825ced16UL,
+    0x1c2b8acfUL, 0xb492a779UL, 0xf2f0f307UL, 0xe2a14e69UL,
+    0xf4cd65daUL, 0xbed50605UL, 0x621fd134UL, 0xfe8ac4a6UL,
+    0x539d342eUL, 0x55a0a2f3UL, 0xe132058aUL, 0xeb75a4f6UL,
+    0xec390b83UL, 0xefaa4060UL, 0x9f065e71UL, 0x1051bd6eUL,
+    0x8af93e21UL, 0x063d96ddUL, 0x05aedd3eUL, 0xbd464de6UL,
+    0x8db59154UL, 0x5d0571c4UL, 0xd46f0406UL, 0x15ff6050UL,
+    0xfb241998UL, 0xe997d6bdUL, 0x43cc8940UL, 0x9e7767d9UL,
+    0x42bdb0e8UL, 0x8b880789UL, 0x5b38e719UL, 0xeedb79c8UL,
+    0x0a47a17cUL, 0x0fe97c42UL, 0x1ec9f884UL, 0x00000000UL,
+    0x86830980UL, 0xed48322bUL, 0x70ac1e11UL, 0x724e6c5aUL,
+    0xfffbfd0eUL, 0x38560f85UL, 0xd51e3daeUL, 0x3927362dUL,
+    0xd9640a0fUL, 0xa621685cUL, 0x54d19b5bUL, 0x2e3a2436UL,
+    0x67b10c0aUL, 0xe70f9357UL, 0x96d2b4eeUL, 0x919e1b9bUL,
+    0xc54f80c0UL, 0x20a261dcUL, 0x4b695a77UL, 0x1a161c12UL,
+    0xba0ae293UL, 0x2ae5c0a0UL, 0xe0433c22UL, 0x171d121bUL,
+    0x0d0b0e09UL, 0xc7adf28bUL, 0xa8b92db6UL, 0xa9c8141eUL,
+    0x198557f1UL, 0x074caf75UL, 0xddbbee99UL, 0x60fda37fUL,
+    0x269ff701UL, 0xf5bc5c72UL, 0x3bc54466UL, 0x7e345bfbUL,
+    0x29768b43UL, 0xc6dccb23UL, 0xfc68b6edUL, 0xf163b8e4UL,
+    0xdccad731UL, 0x85104263UL, 0x22401397UL, 0x112084c6UL,
+    0x247d854aUL, 0x3df8d2bbUL, 0x3211aef9UL, 0xa16dc729UL,
+    0x2f4b1d9eUL, 0x30f3dcb2UL, 0x52ec0d86UL, 0xe3d077c1UL,
+    0x166c2bb3UL, 0xb999a970UL, 0x48fa1194UL, 0x642247e9UL,
+    0x8cc4a8fcUL, 0x3f1aa0f0UL, 0x2cd8567dUL, 0x90ef2233UL,
+    0x4ec78749UL, 0xd1c1d938UL, 0xa2fe8ccaUL, 0x0b3698d4UL,
+    0x81cfa6f5UL, 0xde28a57aUL, 0x8e26dab7UL, 0xbfa43fadUL,
+    0x9de42c3aUL, 0x920d5078UL, 0xcc9b6a5fUL, 0x4662547eUL,
+    0x13c2f68dUL, 0xb8e890d8UL, 0xf75e2e39UL, 0xaff582c3UL,
+    0x80be9f5dUL, 0x937c69d0UL, 0x2da96fd5UL, 0x12b3cf25UL,
+    0x993bc8acUL, 0x7da71018UL, 0x636ee89cUL, 0xbb7bdb3bUL,
+    0x7809cd26UL, 0x18f46e59UL, 0xb701ec9aUL, 0x9aa8834fUL,
+    0x6e65e695UL, 0xe67eaaffUL, 0xcf0821bcUL, 0xe8e6ef15UL,
+    0x9bd9bae7UL, 0x36ce4a6fUL, 0x09d4ea9fUL, 0x7cd629b0UL,
+    0xb2af31a4UL, 0x23312a3fUL, 0x9430c6a5UL, 0x66c035a2UL,
+    0xbc37744eUL, 0xcaa6fc82UL, 0xd0b0e090UL, 0xd81533a7UL,
+    0x984af104UL, 0xdaf741ecUL, 0x500e7fcdUL, 0xf62f1791UL,
+    0xd68d764dUL, 0xb04d43efUL, 0x4d54ccaaUL, 0x04dfe496UL,
+    0xb5e39ed1UL, 0x881b4c6aUL, 0x1fb8c12cUL, 0x517f4665UL,
+    0xea049d5eUL, 0x355d018cUL, 0x7473fa87UL, 0x412efb0bUL,
+    0x1d5ab367UL, 0xd25292dbUL, 0x5633e910UL, 0x47136dd6UL,
+    0x618c9ad7UL, 0x0c7a37a1UL, 0x148e59f8UL, 0x3c89eb13UL,
+    0x27eecea9UL, 0xc935b761UL, 0xe5ede11cUL, 0xb13c7a47UL,
+    0xdf599cd2UL, 0x733f55f2UL, 0xce791814UL, 0x37bf73c7UL,
+    0xcdea53f7UL, 0xaa5b5ffdUL, 0x6f14df3dUL, 0xdb867844UL,
+    0xf381caafUL, 0xc43eb968UL, 0x342c3824UL, 0x405fc2a3UL,
+    0xc372161dUL, 0x250cbce2UL, 0x498b283cUL, 0x9541ff0dUL,
+    0x017139a8UL, 0xb3de080cUL, 0xe49cd8b4UL, 0xc1906456UL,
+    0x84617bcbUL, 0xb670d532UL, 0x5c74486cUL, 0x5742d0b8UL,
+};
+static const ulong32 TD3[256] = {
+    0xf4a75051UL, 0x4165537eUL, 0x17a4c31aUL, 0x275e963aUL,
+    0xab6bcb3bUL, 0x9d45f11fUL, 0xfa58abacUL, 0xe303934bUL,
+    0x30fa5520UL, 0x766df6adUL, 0xcc769188UL, 0x024c25f5UL,
+    0xe5d7fc4fUL, 0x2acbd7c5UL, 0x35448026UL, 0x62a38fb5UL,
+    0xb15a49deUL, 0xba1b6725UL, 0xea0e9845UL, 0xfec0e15dUL,
+    0x2f7502c3UL, 0x4cf01281UL, 0x4697a38dUL, 0xd3f9c66bUL,
+    0x8f5fe703UL, 0x929c9515UL, 0x6d7aebbfUL, 0x5259da95UL,
+    0xbe832dd4UL, 0x7421d358UL, 0xe0692949UL, 0xc9c8448eUL,
+    0xc2896a75UL, 0x8e7978f4UL, 0x583e6b99UL, 0xb971dd27UL,
+    0xe14fb6beUL, 0x88ad17f0UL, 0x20ac66c9UL, 0xce3ab47dUL,
+    0xdf4a1863UL, 0x1a3182e5UL, 0x51336097UL, 0x537f4562UL,
+    0x6477e0b1UL, 0x6bae84bbUL, 0x81a01cfeUL, 0x082b94f9UL,
+    0x48685870UL, 0x45fd198fUL, 0xde6c8794UL, 0x7bf8b752UL,
+    0x73d323abUL, 0x4b02e272UL, 0x1f8f57e3UL, 0x55ab2a66UL,
+    0xeb2807b2UL, 0xb5c2032fUL, 0xc57b9a86UL, 0x3708a5d3UL,
+    0x2887f230UL, 0xbfa5b223UL, 0x036aba02UL, 0x16825cedUL,
+    0xcf1c2b8aUL, 0x79b492a7UL, 0x07f2f0f3UL, 0x69e2a14eUL,
+    0xdaf4cd65UL, 0x05bed506UL, 0x34621fd1UL, 0xa6fe8ac4UL,
+    0x2e539d34UL, 0xf355a0a2UL, 0x8ae13205UL, 0xf6eb75a4UL,
+    0x83ec390bUL, 0x60efaa40UL, 0x719f065eUL, 0x6e1051bdUL,
+    0x218af93eUL, 0xdd063d96UL, 0x3e05aeddUL, 0xe6bd464dUL,
+    0x548db591UL, 0xc45d0571UL, 0x06d46f04UL, 0x5015ff60UL,
+    0x98fb2419UL, 0xbde997d6UL, 0x4043cc89UL, 0xd99e7767UL,
+    0xe842bdb0UL, 0x898b8807UL, 0x195b38e7UL, 0xc8eedb79UL,
+    0x7c0a47a1UL, 0x420fe97cUL, 0x841ec9f8UL, 0x00000000UL,
+    0x80868309UL, 0x2bed4832UL, 0x1170ac1eUL, 0x5a724e6cUL,
+    0x0efffbfdUL, 0x8538560fUL, 0xaed51e3dUL, 0x2d392736UL,
+    0x0fd9640aUL, 0x5ca62168UL, 0x5b54d19bUL, 0x362e3a24UL,
+    0x0a67b10cUL, 0x57e70f93UL, 0xee96d2b4UL, 0x9b919e1bUL,
+    0xc0c54f80UL, 0xdc20a261UL, 0x774b695aUL, 0x121a161cUL,
+    0x93ba0ae2UL, 0xa02ae5c0UL, 0x22e0433cUL, 0x1b171d12UL,
+    0x090d0b0eUL, 0x8bc7adf2UL, 0xb6a8b92dUL, 0x1ea9c814UL,
+    0xf1198557UL, 0x75074cafUL, 0x99ddbbeeUL, 0x7f60fda3UL,
+    0x01269ff7UL, 0x72f5bc5cUL, 0x663bc544UL, 0xfb7e345bUL,
+    0x4329768bUL, 0x23c6dccbUL, 0xedfc68b6UL, 0xe4f163b8UL,
+    0x31dccad7UL, 0x63851042UL, 0x97224013UL, 0xc6112084UL,
+    0x4a247d85UL, 0xbb3df8d2UL, 0xf93211aeUL, 0x29a16dc7UL,
+    0x9e2f4b1dUL, 0xb230f3dcUL, 0x8652ec0dUL, 0xc1e3d077UL,
+    0xb3166c2bUL, 0x70b999a9UL, 0x9448fa11UL, 0xe9642247UL,
+    0xfc8cc4a8UL, 0xf03f1aa0UL, 0x7d2cd856UL, 0x3390ef22UL,
+    0x494ec787UL, 0x38d1c1d9UL, 0xcaa2fe8cUL, 0xd40b3698UL,
+    0xf581cfa6UL, 0x7ade28a5UL, 0xb78e26daUL, 0xadbfa43fUL,
+    0x3a9de42cUL, 0x78920d50UL, 0x5fcc9b6aUL, 0x7e466254UL,
+    0x8d13c2f6UL, 0xd8b8e890UL, 0x39f75e2eUL, 0xc3aff582UL,
+    0x5d80be9fUL, 0xd0937c69UL, 0xd52da96fUL, 0x2512b3cfUL,
+    0xac993bc8UL, 0x187da710UL, 0x9c636ee8UL, 0x3bbb7bdbUL,
+    0x267809cdUL, 0x5918f46eUL, 0x9ab701ecUL, 0x4f9aa883UL,
+    0x956e65e6UL, 0xffe67eaaUL, 0xbccf0821UL, 0x15e8e6efUL,
+    0xe79bd9baUL, 0x6f36ce4aUL, 0x9f09d4eaUL, 0xb07cd629UL,
+    0xa4b2af31UL, 0x3f23312aUL, 0xa59430c6UL, 0xa266c035UL,
+    0x4ebc3774UL, 0x82caa6fcUL, 0x90d0b0e0UL, 0xa7d81533UL,
+    0x04984af1UL, 0xecdaf741UL, 0xcd500e7fUL, 0x91f62f17UL,
+    0x4dd68d76UL, 0xefb04d43UL, 0xaa4d54ccUL, 0x9604dfe4UL,
+    0xd1b5e39eUL, 0x6a881b4cUL, 0x2c1fb8c1UL, 0x65517f46UL,
+    0x5eea049dUL, 0x8c355d01UL, 0x877473faUL, 0x0b412efbUL,
+    0x671d5ab3UL, 0xdbd25292UL, 0x105633e9UL, 0xd647136dUL,
+    0xd7618c9aUL, 0xa10c7a37UL, 0xf8148e59UL, 0x133c89ebUL,
+    0xa927eeceUL, 0x61c935b7UL, 0x1ce5ede1UL, 0x47b13c7aUL,
+    0xd2df599cUL, 0xf2733f55UL, 0x14ce7918UL, 0xc737bf73UL,
+    0xf7cdea53UL, 0xfdaa5b5fUL, 0x3d6f14dfUL, 0x44db8678UL,
+    0xaff381caUL, 0x68c43eb9UL, 0x24342c38UL, 0xa3405fc2UL,
+    0x1dc37216UL, 0xe2250cbcUL, 0x3c498b28UL, 0x0d9541ffUL,
+    0xa8017139UL, 0x0cb3de08UL, 0xb4e49cd8UL, 0x56c19064UL,
+    0xcb84617bUL, 0x32b670d5UL, 0x6c5c7448UL, 0xb85742d0UL,
+};
+
+static const ulong32 Tks0[] = {
+0x00000000UL, 0x0e090d0bUL, 0x1c121a16UL, 0x121b171dUL, 0x3824342cUL, 0x362d3927UL, 0x24362e3aUL, 0x2a3f2331UL,
+0x70486858UL, 0x7e416553UL, 0x6c5a724eUL, 0x62537f45UL, 0x486c5c74UL, 0x4665517fUL, 0x547e4662UL, 0x5a774b69UL,
+0xe090d0b0UL, 0xee99ddbbUL, 0xfc82caa6UL, 0xf28bc7adUL, 0xd8b4e49cUL, 0xd6bde997UL, 0xc4a6fe8aUL, 0xcaaff381UL,
+0x90d8b8e8UL, 0x9ed1b5e3UL, 0x8ccaa2feUL, 0x82c3aff5UL, 0xa8fc8cc4UL, 0xa6f581cfUL, 0xb4ee96d2UL, 0xbae79bd9UL,
+0xdb3bbb7bUL, 0xd532b670UL, 0xc729a16dUL, 0xc920ac66UL, 0xe31f8f57UL, 0xed16825cUL, 0xff0d9541UL, 0xf104984aUL,
+0xab73d323UL, 0xa57ade28UL, 0xb761c935UL, 0xb968c43eUL, 0x9357e70fUL, 0x9d5eea04UL, 0x8f45fd19UL, 0x814cf012UL,
+0x3bab6bcbUL, 0x35a266c0UL, 0x27b971ddUL, 0x29b07cd6UL, 0x038f5fe7UL, 0x0d8652ecUL, 0x1f9d45f1UL, 0x119448faUL,
+0x4be30393UL, 0x45ea0e98UL, 0x57f11985UL, 0x59f8148eUL, 0x73c737bfUL, 0x7dce3ab4UL, 0x6fd52da9UL, 0x61dc20a2UL,
+0xad766df6UL, 0xa37f60fdUL, 0xb16477e0UL, 0xbf6d7aebUL, 0x955259daUL, 0x9b5b54d1UL, 0x894043ccUL, 0x87494ec7UL,
+0xdd3e05aeUL, 0xd33708a5UL, 0xc12c1fb8UL, 0xcf2512b3UL, 0xe51a3182UL, 0xeb133c89UL, 0xf9082b94UL, 0xf701269fUL,
+0x4de6bd46UL, 0x43efb04dUL, 0x51f4a750UL, 0x5ffdaa5bUL, 0x75c2896aUL, 0x7bcb8461UL, 0x69d0937cUL, 0x67d99e77UL,
+0x3daed51eUL, 0x33a7d815UL, 0x21bccf08UL, 0x2fb5c203UL, 0x058ae132UL, 0x0b83ec39UL, 0x1998fb24UL, 0x1791f62fUL,
+0x764dd68dUL, 0x7844db86UL, 0x6a5fcc9bUL, 0x6456c190UL, 0x4e69e2a1UL, 0x4060efaaUL, 0x527bf8b7UL, 0x5c72f5bcUL,
+0x0605bed5UL, 0x080cb3deUL, 0x1a17a4c3UL, 0x141ea9c8UL, 0x3e218af9UL, 0x302887f2UL, 0x223390efUL, 0x2c3a9de4UL,
+0x96dd063dUL, 0x98d40b36UL, 0x8acf1c2bUL, 0x84c61120UL, 0xaef93211UL, 0xa0f03f1aUL, 0xb2eb2807UL, 0xbce2250cUL,
+0xe6956e65UL, 0xe89c636eUL, 0xfa877473UL, 0xf48e7978UL, 0xdeb15a49UL, 0xd0b85742UL, 0xc2a3405fUL, 0xccaa4d54UL,
+0x41ecdaf7UL, 0x4fe5d7fcUL, 0x5dfec0e1UL, 0x53f7cdeaUL, 0x79c8eedbUL, 0x77c1e3d0UL, 0x65daf4cdUL, 0x6bd3f9c6UL,
+0x31a4b2afUL, 0x3fadbfa4UL, 0x2db6a8b9UL, 0x23bfa5b2UL, 0x09808683UL, 0x07898b88UL, 0x15929c95UL, 0x1b9b919eUL,
+0xa17c0a47UL, 0xaf75074cUL, 0xbd6e1051UL, 0xb3671d5aUL, 0x99583e6bUL, 0x97513360UL, 0x854a247dUL, 0x8b432976UL,
+0xd134621fUL, 0xdf3d6f14UL, 0xcd267809UL, 0xc32f7502UL, 0xe9105633UL, 0xe7195b38UL, 0xf5024c25UL, 0xfb0b412eUL,
+0x9ad7618cUL, 0x94de6c87UL, 0x86c57b9aUL, 0x88cc7691UL, 0xa2f355a0UL, 0xacfa58abUL, 0xbee14fb6UL, 0xb0e842bdUL,
+0xea9f09d4UL, 0xe49604dfUL, 0xf68d13c2UL, 0xf8841ec9UL, 0xd2bb3df8UL, 0xdcb230f3UL, 0xcea927eeUL, 0xc0a02ae5UL,
+0x7a47b13cUL, 0x744ebc37UL, 0x6655ab2aUL, 0x685ca621UL, 0x42638510UL, 0x4c6a881bUL, 0x5e719f06UL, 0x5078920dUL,
+0x0a0fd964UL, 0x0406d46fUL, 0x161dc372UL, 0x1814ce79UL, 0x322bed48UL, 0x3c22e043UL, 0x2e39f75eUL, 0x2030fa55UL,
+0xec9ab701UL, 0xe293ba0aUL, 0xf088ad17UL, 0xfe81a01cUL, 0xd4be832dUL, 0xdab78e26UL, 0xc8ac993bUL, 0xc6a59430UL,
+0x9cd2df59UL, 0x92dbd252UL, 0x80c0c54fUL, 0x8ec9c844UL, 0xa4f6eb75UL, 0xaaffe67eUL, 0xb8e4f163UL, 0xb6edfc68UL,
+0x0c0a67b1UL, 0x02036abaUL, 0x10187da7UL, 0x1e1170acUL, 0x342e539dUL, 0x3a275e96UL, 0x283c498bUL, 0x26354480UL,
+0x7c420fe9UL, 0x724b02e2UL, 0x605015ffUL, 0x6e5918f4UL, 0x44663bc5UL, 0x4a6f36ceUL, 0x587421d3UL, 0x567d2cd8UL,
+0x37a10c7aUL, 0x39a80171UL, 0x2bb3166cUL, 0x25ba1b67UL, 0x0f853856UL, 0x018c355dUL, 0x13972240UL, 0x1d9e2f4bUL,
+0x47e96422UL, 0x49e06929UL, 0x5bfb7e34UL, 0x55f2733fUL, 0x7fcd500eUL, 0x71c45d05UL, 0x63df4a18UL, 0x6dd64713UL,
+0xd731dccaUL, 0xd938d1c1UL, 0xcb23c6dcUL, 0xc52acbd7UL, 0xef15e8e6UL, 0xe11ce5edUL, 0xf307f2f0UL, 0xfd0efffbUL,
+0xa779b492UL, 0xa970b999UL, 0xbb6bae84UL, 0xb562a38fUL, 0x9f5d80beUL, 0x91548db5UL, 0x834f9aa8UL, 0x8d4697a3UL
+};
+
+static const ulong32 Tks1[] = {
+0x00000000UL, 0x0b0e090dUL, 0x161c121aUL, 0x1d121b17UL, 0x2c382434UL, 0x27362d39UL, 0x3a24362eUL, 0x312a3f23UL,
+0x58704868UL, 0x537e4165UL, 0x4e6c5a72UL, 0x4562537fUL, 0x74486c5cUL, 0x7f466551UL, 0x62547e46UL, 0x695a774bUL,
+0xb0e090d0UL, 0xbbee99ddUL, 0xa6fc82caUL, 0xadf28bc7UL, 0x9cd8b4e4UL, 0x97d6bde9UL, 0x8ac4a6feUL, 0x81caaff3UL,
+0xe890d8b8UL, 0xe39ed1b5UL, 0xfe8ccaa2UL, 0xf582c3afUL, 0xc4a8fc8cUL, 0xcfa6f581UL, 0xd2b4ee96UL, 0xd9bae79bUL,
+0x7bdb3bbbUL, 0x70d532b6UL, 0x6dc729a1UL, 0x66c920acUL, 0x57e31f8fUL, 0x5ced1682UL, 0x41ff0d95UL, 0x4af10498UL,
+0x23ab73d3UL, 0x28a57adeUL, 0x35b761c9UL, 0x3eb968c4UL, 0x0f9357e7UL, 0x049d5eeaUL, 0x198f45fdUL, 0x12814cf0UL,
+0xcb3bab6bUL, 0xc035a266UL, 0xdd27b971UL, 0xd629b07cUL, 0xe7038f5fUL, 0xec0d8652UL, 0xf11f9d45UL, 0xfa119448UL,
+0x934be303UL, 0x9845ea0eUL, 0x8557f119UL, 0x8e59f814UL, 0xbf73c737UL, 0xb47dce3aUL, 0xa96fd52dUL, 0xa261dc20UL,
+0xf6ad766dUL, 0xfda37f60UL, 0xe0b16477UL, 0xebbf6d7aUL, 0xda955259UL, 0xd19b5b54UL, 0xcc894043UL, 0xc787494eUL,
+0xaedd3e05UL, 0xa5d33708UL, 0xb8c12c1fUL, 0xb3cf2512UL, 0x82e51a31UL, 0x89eb133cUL, 0x94f9082bUL, 0x9ff70126UL,
+0x464de6bdUL, 0x4d43efb0UL, 0x5051f4a7UL, 0x5b5ffdaaUL, 0x6a75c289UL, 0x617bcb84UL, 0x7c69d093UL, 0x7767d99eUL,
+0x1e3daed5UL, 0x1533a7d8UL, 0x0821bccfUL, 0x032fb5c2UL, 0x32058ae1UL, 0x390b83ecUL, 0x241998fbUL, 0x2f1791f6UL,
+0x8d764dd6UL, 0x867844dbUL, 0x9b6a5fccUL, 0x906456c1UL, 0xa14e69e2UL, 0xaa4060efUL, 0xb7527bf8UL, 0xbc5c72f5UL,
+0xd50605beUL, 0xde080cb3UL, 0xc31a17a4UL, 0xc8141ea9UL, 0xf93e218aUL, 0xf2302887UL, 0xef223390UL, 0xe42c3a9dUL,
+0x3d96dd06UL, 0x3698d40bUL, 0x2b8acf1cUL, 0x2084c611UL, 0x11aef932UL, 0x1aa0f03fUL, 0x07b2eb28UL, 0x0cbce225UL,
+0x65e6956eUL, 0x6ee89c63UL, 0x73fa8774UL, 0x78f48e79UL, 0x49deb15aUL, 0x42d0b857UL, 0x5fc2a340UL, 0x54ccaa4dUL,
+0xf741ecdaUL, 0xfc4fe5d7UL, 0xe15dfec0UL, 0xea53f7cdUL, 0xdb79c8eeUL, 0xd077c1e3UL, 0xcd65daf4UL, 0xc66bd3f9UL,
+0xaf31a4b2UL, 0xa43fadbfUL, 0xb92db6a8UL, 0xb223bfa5UL, 0x83098086UL, 0x8807898bUL, 0x9515929cUL, 0x9e1b9b91UL,
+0x47a17c0aUL, 0x4caf7507UL, 0x51bd6e10UL, 0x5ab3671dUL, 0x6b99583eUL, 0x60975133UL, 0x7d854a24UL, 0x768b4329UL,
+0x1fd13462UL, 0x14df3d6fUL, 0x09cd2678UL, 0x02c32f75UL, 0x33e91056UL, 0x38e7195bUL, 0x25f5024cUL, 0x2efb0b41UL,
+0x8c9ad761UL, 0x8794de6cUL, 0x9a86c57bUL, 0x9188cc76UL, 0xa0a2f355UL, 0xabacfa58UL, 0xb6bee14fUL, 0xbdb0e842UL,
+0xd4ea9f09UL, 0xdfe49604UL, 0xc2f68d13UL, 0xc9f8841eUL, 0xf8d2bb3dUL, 0xf3dcb230UL, 0xeecea927UL, 0xe5c0a02aUL,
+0x3c7a47b1UL, 0x37744ebcUL, 0x2a6655abUL, 0x21685ca6UL, 0x10426385UL, 0x1b4c6a88UL, 0x065e719fUL, 0x0d507892UL,
+0x640a0fd9UL, 0x6f0406d4UL, 0x72161dc3UL, 0x791814ceUL, 0x48322bedUL, 0x433c22e0UL, 0x5e2e39f7UL, 0x552030faUL,
+0x01ec9ab7UL, 0x0ae293baUL, 0x17f088adUL, 0x1cfe81a0UL, 0x2dd4be83UL, 0x26dab78eUL, 0x3bc8ac99UL, 0x30c6a594UL,
+0x599cd2dfUL, 0x5292dbd2UL, 0x4f80c0c5UL, 0x448ec9c8UL, 0x75a4f6ebUL, 0x7eaaffe6UL, 0x63b8e4f1UL, 0x68b6edfcUL,
+0xb10c0a67UL, 0xba02036aUL, 0xa710187dUL, 0xac1e1170UL, 0x9d342e53UL, 0x963a275eUL, 0x8b283c49UL, 0x80263544UL,
+0xe97c420fUL, 0xe2724b02UL, 0xff605015UL, 0xf46e5918UL, 0xc544663bUL, 0xce4a6f36UL, 0xd3587421UL, 0xd8567d2cUL,
+0x7a37a10cUL, 0x7139a801UL, 0x6c2bb316UL, 0x6725ba1bUL, 0x560f8538UL, 0x5d018c35UL, 0x40139722UL, 0x4b1d9e2fUL,
+0x2247e964UL, 0x2949e069UL, 0x345bfb7eUL, 0x3f55f273UL, 0x0e7fcd50UL, 0x0571c45dUL, 0x1863df4aUL, 0x136dd647UL,
+0xcad731dcUL, 0xc1d938d1UL, 0xdccb23c6UL, 0xd7c52acbUL, 0xe6ef15e8UL, 0xede11ce5UL, 0xf0f307f2UL, 0xfbfd0effUL,
+0x92a779b4UL, 0x99a970b9UL, 0x84bb6baeUL, 0x8fb562a3UL, 0xbe9f5d80UL, 0xb591548dUL, 0xa8834f9aUL, 0xa38d4697UL
+};
+
+static const ulong32 Tks2[] = {
+0x00000000UL, 0x0d0b0e09UL, 0x1a161c12UL, 0x171d121bUL, 0x342c3824UL, 0x3927362dUL, 0x2e3a2436UL, 0x23312a3fUL,
+0x68587048UL, 0x65537e41UL, 0x724e6c5aUL, 0x7f456253UL, 0x5c74486cUL, 0x517f4665UL, 0x4662547eUL, 0x4b695a77UL,
+0xd0b0e090UL, 0xddbbee99UL, 0xcaa6fc82UL, 0xc7adf28bUL, 0xe49cd8b4UL, 0xe997d6bdUL, 0xfe8ac4a6UL, 0xf381caafUL,
+0xb8e890d8UL, 0xb5e39ed1UL, 0xa2fe8ccaUL, 0xaff582c3UL, 0x8cc4a8fcUL, 0x81cfa6f5UL, 0x96d2b4eeUL, 0x9bd9bae7UL,
+0xbb7bdb3bUL, 0xb670d532UL, 0xa16dc729UL, 0xac66c920UL, 0x8f57e31fUL, 0x825ced16UL, 0x9541ff0dUL, 0x984af104UL,
+0xd323ab73UL, 0xde28a57aUL, 0xc935b761UL, 0xc43eb968UL, 0xe70f9357UL, 0xea049d5eUL, 0xfd198f45UL, 0xf012814cUL,
+0x6bcb3babUL, 0x66c035a2UL, 0x71dd27b9UL, 0x7cd629b0UL, 0x5fe7038fUL, 0x52ec0d86UL, 0x45f11f9dUL, 0x48fa1194UL,
+0x03934be3UL, 0x0e9845eaUL, 0x198557f1UL, 0x148e59f8UL, 0x37bf73c7UL, 0x3ab47dceUL, 0x2da96fd5UL, 0x20a261dcUL,
+0x6df6ad76UL, 0x60fda37fUL, 0x77e0b164UL, 0x7aebbf6dUL, 0x59da9552UL, 0x54d19b5bUL, 0x43cc8940UL, 0x4ec78749UL,
+0x05aedd3eUL, 0x08a5d337UL, 0x1fb8c12cUL, 0x12b3cf25UL, 0x3182e51aUL, 0x3c89eb13UL, 0x2b94f908UL, 0x269ff701UL,
+0xbd464de6UL, 0xb04d43efUL, 0xa75051f4UL, 0xaa5b5ffdUL, 0x896a75c2UL, 0x84617bcbUL, 0x937c69d0UL, 0x9e7767d9UL,
+0xd51e3daeUL, 0xd81533a7UL, 0xcf0821bcUL, 0xc2032fb5UL, 0xe132058aUL, 0xec390b83UL, 0xfb241998UL, 0xf62f1791UL,
+0xd68d764dUL, 0xdb867844UL, 0xcc9b6a5fUL, 0xc1906456UL, 0xe2a14e69UL, 0xefaa4060UL, 0xf8b7527bUL, 0xf5bc5c72UL,
+0xbed50605UL, 0xb3de080cUL, 0xa4c31a17UL, 0xa9c8141eUL, 0x8af93e21UL, 0x87f23028UL, 0x90ef2233UL, 0x9de42c3aUL,
+0x063d96ddUL, 0x0b3698d4UL, 0x1c2b8acfUL, 0x112084c6UL, 0x3211aef9UL, 0x3f1aa0f0UL, 0x2807b2ebUL, 0x250cbce2UL,
+0x6e65e695UL, 0x636ee89cUL, 0x7473fa87UL, 0x7978f48eUL, 0x5a49deb1UL, 0x5742d0b8UL, 0x405fc2a3UL, 0x4d54ccaaUL,
+0xdaf741ecUL, 0xd7fc4fe5UL, 0xc0e15dfeUL, 0xcdea53f7UL, 0xeedb79c8UL, 0xe3d077c1UL, 0xf4cd65daUL, 0xf9c66bd3UL,
+0xb2af31a4UL, 0xbfa43fadUL, 0xa8b92db6UL, 0xa5b223bfUL, 0x86830980UL, 0x8b880789UL, 0x9c951592UL, 0x919e1b9bUL,
+0x0a47a17cUL, 0x074caf75UL, 0x1051bd6eUL, 0x1d5ab367UL, 0x3e6b9958UL, 0x33609751UL, 0x247d854aUL, 0x29768b43UL,
+0x621fd134UL, 0x6f14df3dUL, 0x7809cd26UL, 0x7502c32fUL, 0x5633e910UL, 0x5b38e719UL, 0x4c25f502UL, 0x412efb0bUL,
+0x618c9ad7UL, 0x6c8794deUL, 0x7b9a86c5UL, 0x769188ccUL, 0x55a0a2f3UL, 0x58abacfaUL, 0x4fb6bee1UL, 0x42bdb0e8UL,
+0x09d4ea9fUL, 0x04dfe496UL, 0x13c2f68dUL, 0x1ec9f884UL, 0x3df8d2bbUL, 0x30f3dcb2UL, 0x27eecea9UL, 0x2ae5c0a0UL,
+0xb13c7a47UL, 0xbc37744eUL, 0xab2a6655UL, 0xa621685cUL, 0x85104263UL, 0x881b4c6aUL, 0x9f065e71UL, 0x920d5078UL,
+0xd9640a0fUL, 0xd46f0406UL, 0xc372161dUL, 0xce791814UL, 0xed48322bUL, 0xe0433c22UL, 0xf75e2e39UL, 0xfa552030UL,
+0xb701ec9aUL, 0xba0ae293UL, 0xad17f088UL, 0xa01cfe81UL, 0x832dd4beUL, 0x8e26dab7UL, 0x993bc8acUL, 0x9430c6a5UL,
+0xdf599cd2UL, 0xd25292dbUL, 0xc54f80c0UL, 0xc8448ec9UL, 0xeb75a4f6UL, 0xe67eaaffUL, 0xf163b8e4UL, 0xfc68b6edUL,
+0x67b10c0aUL, 0x6aba0203UL, 0x7da71018UL, 0x70ac1e11UL, 0x539d342eUL, 0x5e963a27UL, 0x498b283cUL, 0x44802635UL,
+0x0fe97c42UL, 0x02e2724bUL, 0x15ff6050UL, 0x18f46e59UL, 0x3bc54466UL, 0x36ce4a6fUL, 0x21d35874UL, 0x2cd8567dUL,
+0x0c7a37a1UL, 0x017139a8UL, 0x166c2bb3UL, 0x1b6725baUL, 0x38560f85UL, 0x355d018cUL, 0x22401397UL, 0x2f4b1d9eUL,
+0x642247e9UL, 0x692949e0UL, 0x7e345bfbUL, 0x733f55f2UL, 0x500e7fcdUL, 0x5d0571c4UL, 0x4a1863dfUL, 0x47136dd6UL,
+0xdccad731UL, 0xd1c1d938UL, 0xc6dccb23UL, 0xcbd7c52aUL, 0xe8e6ef15UL, 0xe5ede11cUL, 0xf2f0f307UL, 0xfffbfd0eUL,
+0xb492a779UL, 0xb999a970UL, 0xae84bb6bUL, 0xa38fb562UL, 0x80be9f5dUL, 0x8db59154UL, 0x9aa8834fUL, 0x97a38d46UL
+};
+
+static const ulong32 Tks3[] = {
+0x00000000UL, 0x090d0b0eUL, 0x121a161cUL, 0x1b171d12UL, 0x24342c38UL, 0x2d392736UL, 0x362e3a24UL, 0x3f23312aUL,
+0x48685870UL, 0x4165537eUL, 0x5a724e6cUL, 0x537f4562UL, 0x6c5c7448UL, 0x65517f46UL, 0x7e466254UL, 0x774b695aUL,
+0x90d0b0e0UL, 0x99ddbbeeUL, 0x82caa6fcUL, 0x8bc7adf2UL, 0xb4e49cd8UL, 0xbde997d6UL, 0xa6fe8ac4UL, 0xaff381caUL,
+0xd8b8e890UL, 0xd1b5e39eUL, 0xcaa2fe8cUL, 0xc3aff582UL, 0xfc8cc4a8UL, 0xf581cfa6UL, 0xee96d2b4UL, 0xe79bd9baUL,
+0x3bbb7bdbUL, 0x32b670d5UL, 0x29a16dc7UL, 0x20ac66c9UL, 0x1f8f57e3UL, 0x16825cedUL, 0x0d9541ffUL, 0x04984af1UL,
+0x73d323abUL, 0x7ade28a5UL, 0x61c935b7UL, 0x68c43eb9UL, 0x57e70f93UL, 0x5eea049dUL, 0x45fd198fUL, 0x4cf01281UL,
+0xab6bcb3bUL, 0xa266c035UL, 0xb971dd27UL, 0xb07cd629UL, 0x8f5fe703UL, 0x8652ec0dUL, 0x9d45f11fUL, 0x9448fa11UL,
+0xe303934bUL, 0xea0e9845UL, 0xf1198557UL, 0xf8148e59UL, 0xc737bf73UL, 0xce3ab47dUL, 0xd52da96fUL, 0xdc20a261UL,
+0x766df6adUL, 0x7f60fda3UL, 0x6477e0b1UL, 0x6d7aebbfUL, 0x5259da95UL, 0x5b54d19bUL, 0x4043cc89UL, 0x494ec787UL,
+0x3e05aeddUL, 0x3708a5d3UL, 0x2c1fb8c1UL, 0x2512b3cfUL, 0x1a3182e5UL, 0x133c89ebUL, 0x082b94f9UL, 0x01269ff7UL,
+0xe6bd464dUL, 0xefb04d43UL, 0xf4a75051UL, 0xfdaa5b5fUL, 0xc2896a75UL, 0xcb84617bUL, 0xd0937c69UL, 0xd99e7767UL,
+0xaed51e3dUL, 0xa7d81533UL, 0xbccf0821UL, 0xb5c2032fUL, 0x8ae13205UL, 0x83ec390bUL, 0x98fb2419UL, 0x91f62f17UL,
+0x4dd68d76UL, 0x44db8678UL, 0x5fcc9b6aUL, 0x56c19064UL, 0x69e2a14eUL, 0x60efaa40UL, 0x7bf8b752UL, 0x72f5bc5cUL,
+0x05bed506UL, 0x0cb3de08UL, 0x17a4c31aUL, 0x1ea9c814UL, 0x218af93eUL, 0x2887f230UL, 0x3390ef22UL, 0x3a9de42cUL,
+0xdd063d96UL, 0xd40b3698UL, 0xcf1c2b8aUL, 0xc6112084UL, 0xf93211aeUL, 0xf03f1aa0UL, 0xeb2807b2UL, 0xe2250cbcUL,
+0x956e65e6UL, 0x9c636ee8UL, 0x877473faUL, 0x8e7978f4UL, 0xb15a49deUL, 0xb85742d0UL, 0xa3405fc2UL, 0xaa4d54ccUL,
+0xecdaf741UL, 0xe5d7fc4fUL, 0xfec0e15dUL, 0xf7cdea53UL, 0xc8eedb79UL, 0xc1e3d077UL, 0xdaf4cd65UL, 0xd3f9c66bUL,
+0xa4b2af31UL, 0xadbfa43fUL, 0xb6a8b92dUL, 0xbfa5b223UL, 0x80868309UL, 0x898b8807UL, 0x929c9515UL, 0x9b919e1bUL,
+0x7c0a47a1UL, 0x75074cafUL, 0x6e1051bdUL, 0x671d5ab3UL, 0x583e6b99UL, 0x51336097UL, 0x4a247d85UL, 0x4329768bUL,
+0x34621fd1UL, 0x3d6f14dfUL, 0x267809cdUL, 0x2f7502c3UL, 0x105633e9UL, 0x195b38e7UL, 0x024c25f5UL, 0x0b412efbUL,
+0xd7618c9aUL, 0xde6c8794UL, 0xc57b9a86UL, 0xcc769188UL, 0xf355a0a2UL, 0xfa58abacUL, 0xe14fb6beUL, 0xe842bdb0UL,
+0x9f09d4eaUL, 0x9604dfe4UL, 0x8d13c2f6UL, 0x841ec9f8UL, 0xbb3df8d2UL, 0xb230f3dcUL, 0xa927eeceUL, 0xa02ae5c0UL,
+0x47b13c7aUL, 0x4ebc3774UL, 0x55ab2a66UL, 0x5ca62168UL, 0x63851042UL, 0x6a881b4cUL, 0x719f065eUL, 0x78920d50UL,
+0x0fd9640aUL, 0x06d46f04UL, 0x1dc37216UL, 0x14ce7918UL, 0x2bed4832UL, 0x22e0433cUL, 0x39f75e2eUL, 0x30fa5520UL,
+0x9ab701ecUL, 0x93ba0ae2UL, 0x88ad17f0UL, 0x81a01cfeUL, 0xbe832dd4UL, 0xb78e26daUL, 0xac993bc8UL, 0xa59430c6UL,
+0xd2df599cUL, 0xdbd25292UL, 0xc0c54f80UL, 0xc9c8448eUL, 0xf6eb75a4UL, 0xffe67eaaUL, 0xe4f163b8UL, 0xedfc68b6UL,
+0x0a67b10cUL, 0x036aba02UL, 0x187da710UL, 0x1170ac1eUL, 0x2e539d34UL, 0x275e963aUL, 0x3c498b28UL, 0x35448026UL,
+0x420fe97cUL, 0x4b02e272UL, 0x5015ff60UL, 0x5918f46eUL, 0x663bc544UL, 0x6f36ce4aUL, 0x7421d358UL, 0x7d2cd856UL,
+0xa10c7a37UL, 0xa8017139UL, 0xb3166c2bUL, 0xba1b6725UL, 0x8538560fUL, 0x8c355d01UL, 0x97224013UL, 0x9e2f4b1dUL,
+0xe9642247UL, 0xe0692949UL, 0xfb7e345bUL, 0xf2733f55UL, 0xcd500e7fUL, 0xc45d0571UL, 0xdf4a1863UL, 0xd647136dUL,
+0x31dccad7UL, 0x38d1c1d9UL, 0x23c6dccbUL, 0x2acbd7c5UL, 0x15e8e6efUL, 0x1ce5ede1UL, 0x07f2f0f3UL, 0x0efffbfdUL,
+0x79b492a7UL, 0x70b999a9UL, 0x6bae84bbUL, 0x62a38fb5UL, 0x5d80be9fUL, 0x548db591UL, 0x4f9aa883UL, 0x4697a38dUL
+};
+
+#endif /* ENCRYPT_ONLY */
+
+#endif /* SMALL CODE */
+
+#ifndef PELI_TAB
+static const ulong32 rcon[] = {
+    0x01000000UL, 0x02000000UL, 0x04000000UL, 0x08000000UL,
+    0x10000000UL, 0x20000000UL, 0x40000000UL, 0x80000000UL,
+    0x1B000000UL, 0x36000000UL, /* for 128-bit blocks, Rijndael never uses more than 10 rcon values */
+};
+#endif
+
+#endif /* __LTC_AES_TAB_C__ */
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/ciphers/anubis.c b/libtomcrypt/src/ciphers/anubis.c
new file mode 100644 (file)
index 0000000..a28c7e1
--- /dev/null
@@ -0,0 +1,1558 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+/**
+  @file anubis.c
+  Anubis implementation derived from public domain source
+  Authors: Paulo S.L.M. Barreto and Vincent Rijmen.
+*/
+
+#include "tomcrypt.h"
+
+#ifdef LTC_ANUBIS
+
+const struct ltc_cipher_descriptor anubis_desc = {
+   "anubis",
+   19,
+   16, 40, 16, 12,
+   &anubis_setup,
+   &anubis_ecb_encrypt,
+   &anubis_ecb_decrypt,
+   &anubis_test,
+   &anubis_done,
+   &anubis_keysize,
+   NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
+};
+
+#define MIN_N           4
+#define MAX_N           10
+#define MIN_ROUNDS      (8 + MIN_N)
+#define MAX_ROUNDS      (8 + MAX_N)
+#define MIN_KEYSIZEB    (4*MIN_N)
+#define MAX_KEYSIZEB    (4*MAX_N)
+#define BLOCKSIZE       128
+#define BLOCKSIZEB      (BLOCKSIZE/8)
+
+
+/*
+ * Though Anubis is endianness-neutral, the encryption tables are listed
+ * in BIG-ENDIAN format, which is adopted throughout this implementation
+ * (but little-endian notation would be equally suitable if consistently
+ * employed).
+ */
+#if defined(LTC_ANUBIS_TWEAK)
+
+static const ulong32 T0[256] = {
+    0xba69d2bbU, 0x54a84de5U, 0x2f5ebce2U, 0x74e8cd25U,
+    0x53a651f7U, 0xd3bb6bd0U, 0xd2b96fd6U, 0x4d9a29b3U,
+    0x50a05dfdU, 0xac458acfU, 0x8d070e09U, 0xbf63c6a5U,
+    0x70e0dd3dU, 0x52a455f1U, 0x9a29527bU, 0x4c982db5U,
+    0xeac98f46U, 0xd5b773c4U, 0x97336655U, 0xd1bf63dcU,
+    0x3366ccaaU, 0x51a259fbU, 0x5bb671c7U, 0xa651a2f3U,
+    0xdea15ffeU, 0x48903dadU, 0xa84d9ad7U, 0x992f5e71U,
+    0xdbab4be0U, 0x3264c8acU, 0xb773e695U, 0xfce5d732U,
+    0xe3dbab70U, 0x9e214263U, 0x913f7e41U, 0x9b2b567dU,
+    0xe2d9af76U, 0xbb6bd6bdU, 0x4182199bU, 0x6edca579U,
+    0xa557aef9U, 0xcb8b0b80U, 0x6bd6b167U, 0x95376e59U,
+    0xa15fbee1U, 0xf3fbeb10U, 0xb17ffe81U, 0x0204080cU,
+    0xcc851792U, 0xc49537a2U, 0x1d3a744eU, 0x14285078U,
+    0xc39b2bb0U, 0x63c69157U, 0xdaa94fe6U, 0x5dba69d3U,
+    0x5fbe61dfU, 0xdca557f2U, 0x7dfae913U, 0xcd871394U,
+    0x7ffee11fU, 0x5ab475c1U, 0x6cd8ad75U, 0x5cb86dd5U,
+    0xf7f3fb08U, 0x264c98d4U, 0xffe3db38U, 0xedc79354U,
+    0xe8cd874aU, 0x9d274e69U, 0x6fdea17fU, 0x8e010203U,
+    0x19326456U, 0xa05dbae7U, 0xf0fde71aU, 0x890f1e11U,
+    0x0f1e3c22U, 0x070e1c12U, 0xaf4386c5U, 0xfbebcb20U,
+    0x08102030U, 0x152a547eU, 0x0d1a342eU, 0x04081018U,
+    0x01020406U, 0x64c88d45U, 0xdfa35bf8U, 0x76ecc529U,
+    0x79f2f90bU, 0xdda753f4U, 0x3d7af48eU, 0x162c5874U,
+    0x3f7efc82U, 0x376edcb2U, 0x6ddaa973U, 0x3870e090U,
+    0xb96fdeb1U, 0x73e6d137U, 0xe9cf834cU, 0x356ad4beU,
+    0x55aa49e3U, 0x71e2d93bU, 0x7bf6f107U, 0x8c050a0fU,
+    0x72e4d531U, 0x880d1a17U, 0xf6f1ff0eU, 0x2a54a8fcU,
+    0x3e7cf884U, 0x5ebc65d9U, 0x274e9cd2U, 0x468c0589U,
+    0x0c183028U, 0x65ca8943U, 0x68d0bd6dU, 0x61c2995bU,
+    0x03060c0aU, 0xc19f23bcU, 0x57ae41efU, 0xd6b17fceU,
+    0xd9af43ecU, 0x58b07dcdU, 0xd8ad47eaU, 0x66cc8549U,
+    0xd7b37bc8U, 0x3a74e89cU, 0xc88d078aU, 0x3c78f088U,
+    0xfae9cf26U, 0x96316253U, 0xa753a6f5U, 0x982d5a77U,
+    0xecc59752U, 0xb86ddab7U, 0xc7933ba8U, 0xae4182c3U,
+    0x69d2b96bU, 0x4b9631a7U, 0xab4b96ddU, 0xa94f9ed1U,
+    0x67ce814fU, 0x0a14283cU, 0x478e018fU, 0xf2f9ef16U,
+    0xb577ee99U, 0x224488ccU, 0xe5d7b364U, 0xeec19f5eU,
+    0xbe61c2a3U, 0x2b56acfaU, 0x811f3e21U, 0x1224486cU,
+    0x831b362dU, 0x1b366c5aU, 0x0e1c3824U, 0x23468ccaU,
+    0xf5f7f304U, 0x458a0983U, 0x214284c6U, 0xce811f9eU,
+    0x499239abU, 0x2c58b0e8U, 0xf9efc32cU, 0xe6d1bf6eU,
+    0xb671e293U, 0x2850a0f0U, 0x172e5c72U, 0x8219322bU,
+    0x1a34685cU, 0x8b0b161dU, 0xfee1df3eU, 0x8a09121bU,
+    0x09122436U, 0xc98f038cU, 0x87132635U, 0x4e9c25b9U,
+    0xe1dfa37cU, 0x2e5cb8e4U, 0xe4d5b762U, 0xe0dda77aU,
+    0xebcb8b40U, 0x903d7a47U, 0xa455aaffU, 0x1e3c7844U,
+    0x85172e39U, 0x60c09d5dU, 0x00000000U, 0x254a94deU,
+    0xf4f5f702U, 0xf1ffe31cU, 0x94356a5fU, 0x0b162c3aU,
+    0xe7d3bb68U, 0x75eac923U, 0xefc39b58U, 0x3468d0b8U,
+    0x3162c4a6U, 0xd4b577c2U, 0xd0bd67daU, 0x86112233U,
+    0x7efce519U, 0xad478ec9U, 0xfde7d334U, 0x2952a4f6U,
+    0x3060c0a0U, 0x3b76ec9aU, 0x9f234665U, 0xf8edc72aU,
+    0xc6913faeU, 0x13264c6aU, 0x060c1814U, 0x050a141eU,
+    0xc59733a4U, 0x11224466U, 0x77eec12fU, 0x7cf8ed15U,
+    0x7af4f501U, 0x78f0fd0dU, 0x366cd8b4U, 0x1c387048U,
+    0x3972e496U, 0x59b279cbU, 0x18306050U, 0x56ac45e9U,
+    0xb37bf68dU, 0xb07dfa87U, 0x244890d8U, 0x204080c0U,
+    0xb279f28bU, 0x9239724bU, 0xa35bb6edU, 0xc09d27baU,
+    0x44880d85U, 0x62c49551U, 0x10204060U, 0xb475ea9fU,
+    0x84152a3fU, 0x43861197U, 0x933b764dU, 0xc2992fb6U,
+    0x4a9435a1U, 0xbd67cea9U, 0x8f030605U, 0x2d5ab4eeU,
+    0xbc65caafU, 0x9c254a6fU, 0x6ad4b561U, 0x40801d9dU,
+    0xcf831b98U, 0xa259b2ebU, 0x801d3a27U, 0x4f9e21bfU,
+    0x1f3e7c42U, 0xca890f86U, 0xaa4992dbU, 0x42841591U,
+};
+
+static const ulong32 T1[256] = {
+    0x69babbd2U, 0xa854e54dU, 0x5e2fe2bcU, 0xe87425cdU,
+    0xa653f751U, 0xbbd3d06bU, 0xb9d2d66fU, 0x9a4db329U,
+    0xa050fd5dU, 0x45accf8aU, 0x078d090eU, 0x63bfa5c6U,
+    0xe0703dddU, 0xa452f155U, 0x299a7b52U, 0x984cb52dU,
+    0xc9ea468fU, 0xb7d5c473U, 0x33975566U, 0xbfd1dc63U,
+    0x6633aaccU, 0xa251fb59U, 0xb65bc771U, 0x51a6f3a2U,
+    0xa1defe5fU, 0x9048ad3dU, 0x4da8d79aU, 0x2f99715eU,
+    0xabdbe04bU, 0x6432acc8U, 0x73b795e6U, 0xe5fc32d7U,
+    0xdbe370abU, 0x219e6342U, 0x3f91417eU, 0x2b9b7d56U,
+    0xd9e276afU, 0x6bbbbdd6U, 0x82419b19U, 0xdc6e79a5U,
+    0x57a5f9aeU, 0x8bcb800bU, 0xd66b67b1U, 0x3795596eU,
+    0x5fa1e1beU, 0xfbf310ebU, 0x7fb181feU, 0x04020c08U,
+    0x85cc9217U, 0x95c4a237U, 0x3a1d4e74U, 0x28147850U,
+    0x9bc3b02bU, 0xc6635791U, 0xa9dae64fU, 0xba5dd369U,
+    0xbe5fdf61U, 0xa5dcf257U, 0xfa7d13e9U, 0x87cd9413U,
+    0xfe7f1fe1U, 0xb45ac175U, 0xd86c75adU, 0xb85cd56dU,
+    0xf3f708fbU, 0x4c26d498U, 0xe3ff38dbU, 0xc7ed5493U,
+    0xcde84a87U, 0x279d694eU, 0xde6f7fa1U, 0x018e0302U,
+    0x32195664U, 0x5da0e7baU, 0xfdf01ae7U, 0x0f89111eU,
+    0x1e0f223cU, 0x0e07121cU, 0x43afc586U, 0xebfb20cbU,
+    0x10083020U, 0x2a157e54U, 0x1a0d2e34U, 0x08041810U,
+    0x02010604U, 0xc864458dU, 0xa3dff85bU, 0xec7629c5U,
+    0xf2790bf9U, 0xa7ddf453U, 0x7a3d8ef4U, 0x2c167458U,
+    0x7e3f82fcU, 0x6e37b2dcU, 0xda6d73a9U, 0x703890e0U,
+    0x6fb9b1deU, 0xe67337d1U, 0xcfe94c83U, 0x6a35bed4U,
+    0xaa55e349U, 0xe2713bd9U, 0xf67b07f1U, 0x058c0f0aU,
+    0xe47231d5U, 0x0d88171aU, 0xf1f60effU, 0x542afca8U,
+    0x7c3e84f8U, 0xbc5ed965U, 0x4e27d29cU, 0x8c468905U,
+    0x180c2830U, 0xca654389U, 0xd0686dbdU, 0xc2615b99U,
+    0x06030a0cU, 0x9fc1bc23U, 0xae57ef41U, 0xb1d6ce7fU,
+    0xafd9ec43U, 0xb058cd7dU, 0xadd8ea47U, 0xcc664985U,
+    0xb3d7c87bU, 0x743a9ce8U, 0x8dc88a07U, 0x783c88f0U,
+    0xe9fa26cfU, 0x31965362U, 0x53a7f5a6U, 0x2d98775aU,
+    0xc5ec5297U, 0x6db8b7daU, 0x93c7a83bU, 0x41aec382U,
+    0xd2696bb9U, 0x964ba731U, 0x4babdd96U, 0x4fa9d19eU,
+    0xce674f81U, 0x140a3c28U, 0x8e478f01U, 0xf9f216efU,
+    0x77b599eeU, 0x4422cc88U, 0xd7e564b3U, 0xc1ee5e9fU,
+    0x61bea3c2U, 0x562bfaacU, 0x1f81213eU, 0x24126c48U,
+    0x1b832d36U, 0x361b5a6cU, 0x1c0e2438U, 0x4623ca8cU,
+    0xf7f504f3U, 0x8a458309U, 0x4221c684U, 0x81ce9e1fU,
+    0x9249ab39U, 0x582ce8b0U, 0xeff92cc3U, 0xd1e66ebfU,
+    0x71b693e2U, 0x5028f0a0U, 0x2e17725cU, 0x19822b32U,
+    0x341a5c68U, 0x0b8b1d16U, 0xe1fe3edfU, 0x098a1b12U,
+    0x12093624U, 0x8fc98c03U, 0x13873526U, 0x9c4eb925U,
+    0xdfe17ca3U, 0x5c2ee4b8U, 0xd5e462b7U, 0xdde07aa7U,
+    0xcbeb408bU, 0x3d90477aU, 0x55a4ffaaU, 0x3c1e4478U,
+    0x1785392eU, 0xc0605d9dU, 0x00000000U, 0x4a25de94U,
+    0xf5f402f7U, 0xfff11ce3U, 0x35945f6aU, 0x160b3a2cU,
+    0xd3e768bbU, 0xea7523c9U, 0xc3ef589bU, 0x6834b8d0U,
+    0x6231a6c4U, 0xb5d4c277U, 0xbdd0da67U, 0x11863322U,
+    0xfc7e19e5U, 0x47adc98eU, 0xe7fd34d3U, 0x5229f6a4U,
+    0x6030a0c0U, 0x763b9aecU, 0x239f6546U, 0xedf82ac7U,
+    0x91c6ae3fU, 0x26136a4cU, 0x0c061418U, 0x0a051e14U,
+    0x97c5a433U, 0x22116644U, 0xee772fc1U, 0xf87c15edU,
+    0xf47a01f5U, 0xf0780dfdU, 0x6c36b4d8U, 0x381c4870U,
+    0x723996e4U, 0xb259cb79U, 0x30185060U, 0xac56e945U,
+    0x7bb38df6U, 0x7db087faU, 0x4824d890U, 0x4020c080U,
+    0x79b28bf2U, 0x39924b72U, 0x5ba3edb6U, 0x9dc0ba27U,
+    0x8844850dU, 0xc4625195U, 0x20106040U, 0x75b49feaU,
+    0x15843f2aU, 0x86439711U, 0x3b934d76U, 0x99c2b62fU,
+    0x944aa135U, 0x67bda9ceU, 0x038f0506U, 0x5a2deeb4U,
+    0x65bcafcaU, 0x259c6f4aU, 0xd46a61b5U, 0x80409d1dU,
+    0x83cf981bU, 0x59a2ebb2U, 0x1d80273aU, 0x9e4fbf21U,
+    0x3e1f427cU, 0x89ca860fU, 0x49aadb92U, 0x84429115U,
+};
+
+static const ulong32 T2[256] = {
+    0xd2bbba69U, 0x4de554a8U, 0xbce22f5eU, 0xcd2574e8U,
+    0x51f753a6U, 0x6bd0d3bbU, 0x6fd6d2b9U, 0x29b34d9aU,
+    0x5dfd50a0U, 0x8acfac45U, 0x0e098d07U, 0xc6a5bf63U,
+    0xdd3d70e0U, 0x55f152a4U, 0x527b9a29U, 0x2db54c98U,
+    0x8f46eac9U, 0x73c4d5b7U, 0x66559733U, 0x63dcd1bfU,
+    0xccaa3366U, 0x59fb51a2U, 0x71c75bb6U, 0xa2f3a651U,
+    0x5ffedea1U, 0x3dad4890U, 0x9ad7a84dU, 0x5e71992fU,
+    0x4be0dbabU, 0xc8ac3264U, 0xe695b773U, 0xd732fce5U,
+    0xab70e3dbU, 0x42639e21U, 0x7e41913fU, 0x567d9b2bU,
+    0xaf76e2d9U, 0xd6bdbb6bU, 0x199b4182U, 0xa5796edcU,
+    0xaef9a557U, 0x0b80cb8bU, 0xb1676bd6U, 0x6e599537U,
+    0xbee1a15fU, 0xeb10f3fbU, 0xfe81b17fU, 0x080c0204U,
+    0x1792cc85U, 0x37a2c495U, 0x744e1d3aU, 0x50781428U,
+    0x2bb0c39bU, 0x915763c6U, 0x4fe6daa9U, 0x69d35dbaU,
+    0x61df5fbeU, 0x57f2dca5U, 0xe9137dfaU, 0x1394cd87U,
+    0xe11f7ffeU, 0x75c15ab4U, 0xad756cd8U, 0x6dd55cb8U,
+    0xfb08f7f3U, 0x98d4264cU, 0xdb38ffe3U, 0x9354edc7U,
+    0x874ae8cdU, 0x4e699d27U, 0xa17f6fdeU, 0x02038e01U,
+    0x64561932U, 0xbae7a05dU, 0xe71af0fdU, 0x1e11890fU,
+    0x3c220f1eU, 0x1c12070eU, 0x86c5af43U, 0xcb20fbebU,
+    0x20300810U, 0x547e152aU, 0x342e0d1aU, 0x10180408U,
+    0x04060102U, 0x8d4564c8U, 0x5bf8dfa3U, 0xc52976ecU,
+    0xf90b79f2U, 0x53f4dda7U, 0xf48e3d7aU, 0x5874162cU,
+    0xfc823f7eU, 0xdcb2376eU, 0xa9736ddaU, 0xe0903870U,
+    0xdeb1b96fU, 0xd13773e6U, 0x834ce9cfU, 0xd4be356aU,
+    0x49e355aaU, 0xd93b71e2U, 0xf1077bf6U, 0x0a0f8c05U,
+    0xd53172e4U, 0x1a17880dU, 0xff0ef6f1U, 0xa8fc2a54U,
+    0xf8843e7cU, 0x65d95ebcU, 0x9cd2274eU, 0x0589468cU,
+    0x30280c18U, 0x894365caU, 0xbd6d68d0U, 0x995b61c2U,
+    0x0c0a0306U, 0x23bcc19fU, 0x41ef57aeU, 0x7fced6b1U,
+    0x43ecd9afU, 0x7dcd58b0U, 0x47ead8adU, 0x854966ccU,
+    0x7bc8d7b3U, 0xe89c3a74U, 0x078ac88dU, 0xf0883c78U,
+    0xcf26fae9U, 0x62539631U, 0xa6f5a753U, 0x5a77982dU,
+    0x9752ecc5U, 0xdab7b86dU, 0x3ba8c793U, 0x82c3ae41U,
+    0xb96b69d2U, 0x31a74b96U, 0x96ddab4bU, 0x9ed1a94fU,
+    0x814f67ceU, 0x283c0a14U, 0x018f478eU, 0xef16f2f9U,
+    0xee99b577U, 0x88cc2244U, 0xb364e5d7U, 0x9f5eeec1U,
+    0xc2a3be61U, 0xacfa2b56U, 0x3e21811fU, 0x486c1224U,
+    0x362d831bU, 0x6c5a1b36U, 0x38240e1cU, 0x8cca2346U,
+    0xf304f5f7U, 0x0983458aU, 0x84c62142U, 0x1f9ece81U,
+    0x39ab4992U, 0xb0e82c58U, 0xc32cf9efU, 0xbf6ee6d1U,
+    0xe293b671U, 0xa0f02850U, 0x5c72172eU, 0x322b8219U,
+    0x685c1a34U, 0x161d8b0bU, 0xdf3efee1U, 0x121b8a09U,
+    0x24360912U, 0x038cc98fU, 0x26358713U, 0x25b94e9cU,
+    0xa37ce1dfU, 0xb8e42e5cU, 0xb762e4d5U, 0xa77ae0ddU,
+    0x8b40ebcbU, 0x7a47903dU, 0xaaffa455U, 0x78441e3cU,
+    0x2e398517U, 0x9d5d60c0U, 0x00000000U, 0x94de254aU,
+    0xf702f4f5U, 0xe31cf1ffU, 0x6a5f9435U, 0x2c3a0b16U,
+    0xbb68e7d3U, 0xc92375eaU, 0x9b58efc3U, 0xd0b83468U,
+    0xc4a63162U, 0x77c2d4b5U, 0x67dad0bdU, 0x22338611U,
+    0xe5197efcU, 0x8ec9ad47U, 0xd334fde7U, 0xa4f62952U,
+    0xc0a03060U, 0xec9a3b76U, 0x46659f23U, 0xc72af8edU,
+    0x3faec691U, 0x4c6a1326U, 0x1814060cU, 0x141e050aU,
+    0x33a4c597U, 0x44661122U, 0xc12f77eeU, 0xed157cf8U,
+    0xf5017af4U, 0xfd0d78f0U, 0xd8b4366cU, 0x70481c38U,
+    0xe4963972U, 0x79cb59b2U, 0x60501830U, 0x45e956acU,
+    0xf68db37bU, 0xfa87b07dU, 0x90d82448U, 0x80c02040U,
+    0xf28bb279U, 0x724b9239U, 0xb6eda35bU, 0x27bac09dU,
+    0x0d854488U, 0x955162c4U, 0x40601020U, 0xea9fb475U,
+    0x2a3f8415U, 0x11974386U, 0x764d933bU, 0x2fb6c299U,
+    0x35a14a94U, 0xcea9bd67U, 0x06058f03U, 0xb4ee2d5aU,
+    0xcaafbc65U, 0x4a6f9c25U, 0xb5616ad4U, 0x1d9d4080U,
+    0x1b98cf83U, 0xb2eba259U, 0x3a27801dU, 0x21bf4f9eU,
+    0x7c421f3eU, 0x0f86ca89U, 0x92dbaa49U, 0x15914284U,
+};
+
+static const ulong32 T3[256] = {
+    0xbbd269baU, 0xe54da854U, 0xe2bc5e2fU, 0x25cde874U,
+    0xf751a653U, 0xd06bbbd3U, 0xd66fb9d2U, 0xb3299a4dU,
+    0xfd5da050U, 0xcf8a45acU, 0x090e078dU, 0xa5c663bfU,
+    0x3ddde070U, 0xf155a452U, 0x7b52299aU, 0xb52d984cU,
+    0x468fc9eaU, 0xc473b7d5U, 0x55663397U, 0xdc63bfd1U,
+    0xaacc6633U, 0xfb59a251U, 0xc771b65bU, 0xf3a251a6U,
+    0xfe5fa1deU, 0xad3d9048U, 0xd79a4da8U, 0x715e2f99U,
+    0xe04babdbU, 0xacc86432U, 0x95e673b7U, 0x32d7e5fcU,
+    0x70abdbe3U, 0x6342219eU, 0x417e3f91U, 0x7d562b9bU,
+    0x76afd9e2U, 0xbdd66bbbU, 0x9b198241U, 0x79a5dc6eU,
+    0xf9ae57a5U, 0x800b8bcbU, 0x67b1d66bU, 0x596e3795U,
+    0xe1be5fa1U, 0x10ebfbf3U, 0x81fe7fb1U, 0x0c080402U,
+    0x921785ccU, 0xa23795c4U, 0x4e743a1dU, 0x78502814U,
+    0xb02b9bc3U, 0x5791c663U, 0xe64fa9daU, 0xd369ba5dU,
+    0xdf61be5fU, 0xf257a5dcU, 0x13e9fa7dU, 0x941387cdU,
+    0x1fe1fe7fU, 0xc175b45aU, 0x75add86cU, 0xd56db85cU,
+    0x08fbf3f7U, 0xd4984c26U, 0x38dbe3ffU, 0x5493c7edU,
+    0x4a87cde8U, 0x694e279dU, 0x7fa1de6fU, 0x0302018eU,
+    0x56643219U, 0xe7ba5da0U, 0x1ae7fdf0U, 0x111e0f89U,
+    0x223c1e0fU, 0x121c0e07U, 0xc58643afU, 0x20cbebfbU,
+    0x30201008U, 0x7e542a15U, 0x2e341a0dU, 0x18100804U,
+    0x06040201U, 0x458dc864U, 0xf85ba3dfU, 0x29c5ec76U,
+    0x0bf9f279U, 0xf453a7ddU, 0x8ef47a3dU, 0x74582c16U,
+    0x82fc7e3fU, 0xb2dc6e37U, 0x73a9da6dU, 0x90e07038U,
+    0xb1de6fb9U, 0x37d1e673U, 0x4c83cfe9U, 0xbed46a35U,
+    0xe349aa55U, 0x3bd9e271U, 0x07f1f67bU, 0x0f0a058cU,
+    0x31d5e472U, 0x171a0d88U, 0x0efff1f6U, 0xfca8542aU,
+    0x84f87c3eU, 0xd965bc5eU, 0xd29c4e27U, 0x89058c46U,
+    0x2830180cU, 0x4389ca65U, 0x6dbdd068U, 0x5b99c261U,
+    0x0a0c0603U, 0xbc239fc1U, 0xef41ae57U, 0xce7fb1d6U,
+    0xec43afd9U, 0xcd7db058U, 0xea47add8U, 0x4985cc66U,
+    0xc87bb3d7U, 0x9ce8743aU, 0x8a078dc8U, 0x88f0783cU,
+    0x26cfe9faU, 0x53623196U, 0xf5a653a7U, 0x775a2d98U,
+    0x5297c5ecU, 0xb7da6db8U, 0xa83b93c7U, 0xc38241aeU,
+    0x6bb9d269U, 0xa731964bU, 0xdd964babU, 0xd19e4fa9U,
+    0x4f81ce67U, 0x3c28140aU, 0x8f018e47U, 0x16eff9f2U,
+    0x99ee77b5U, 0xcc884422U, 0x64b3d7e5U, 0x5e9fc1eeU,
+    0xa3c261beU, 0xfaac562bU, 0x213e1f81U, 0x6c482412U,
+    0x2d361b83U, 0x5a6c361bU, 0x24381c0eU, 0xca8c4623U,
+    0x04f3f7f5U, 0x83098a45U, 0xc6844221U, 0x9e1f81ceU,
+    0xab399249U, 0xe8b0582cU, 0x2cc3eff9U, 0x6ebfd1e6U,
+    0x93e271b6U, 0xf0a05028U, 0x725c2e17U, 0x2b321982U,
+    0x5c68341aU, 0x1d160b8bU, 0x3edfe1feU, 0x1b12098aU,
+    0x36241209U, 0x8c038fc9U, 0x35261387U, 0xb9259c4eU,
+    0x7ca3dfe1U, 0xe4b85c2eU, 0x62b7d5e4U, 0x7aa7dde0U,
+    0x408bcbebU, 0x477a3d90U, 0xffaa55a4U, 0x44783c1eU,
+    0x392e1785U, 0x5d9dc060U, 0x00000000U, 0xde944a25U,
+    0x02f7f5f4U, 0x1ce3fff1U, 0x5f6a3594U, 0x3a2c160bU,
+    0x68bbd3e7U, 0x23c9ea75U, 0x589bc3efU, 0xb8d06834U,
+    0xa6c46231U, 0xc277b5d4U, 0xda67bdd0U, 0x33221186U,
+    0x19e5fc7eU, 0xc98e47adU, 0x34d3e7fdU, 0xf6a45229U,
+    0xa0c06030U, 0x9aec763bU, 0x6546239fU, 0x2ac7edf8U,
+    0xae3f91c6U, 0x6a4c2613U, 0x14180c06U, 0x1e140a05U,
+    0xa43397c5U, 0x66442211U, 0x2fc1ee77U, 0x15edf87cU,
+    0x01f5f47aU, 0x0dfdf078U, 0xb4d86c36U, 0x4870381cU,
+    0x96e47239U, 0xcb79b259U, 0x50603018U, 0xe945ac56U,
+    0x8df67bb3U, 0x87fa7db0U, 0xd8904824U, 0xc0804020U,
+    0x8bf279b2U, 0x4b723992U, 0xedb65ba3U, 0xba279dc0U,
+    0x850d8844U, 0x5195c462U, 0x60402010U, 0x9fea75b4U,
+    0x3f2a1584U, 0x97118643U, 0x4d763b93U, 0xb62f99c2U,
+    0xa135944aU, 0xa9ce67bdU, 0x0506038fU, 0xeeb45a2dU,
+    0xafca65bcU, 0x6f4a259cU, 0x61b5d46aU, 0x9d1d8040U,
+    0x981b83cfU, 0xebb259a2U, 0x273a1d80U, 0xbf219e4fU,
+    0x427c3e1fU, 0x860f89caU, 0xdb9249aaU, 0x91158442U,
+};
+
+static const ulong32 T4[256] = {
+    0xbabababaU, 0x54545454U, 0x2f2f2f2fU, 0x74747474U,
+    0x53535353U, 0xd3d3d3d3U, 0xd2d2d2d2U, 0x4d4d4d4dU,
+    0x50505050U, 0xacacacacU, 0x8d8d8d8dU, 0xbfbfbfbfU,
+    0x70707070U, 0x52525252U, 0x9a9a9a9aU, 0x4c4c4c4cU,
+    0xeaeaeaeaU, 0xd5d5d5d5U, 0x97979797U, 0xd1d1d1d1U,
+    0x33333333U, 0x51515151U, 0x5b5b5b5bU, 0xa6a6a6a6U,
+    0xdedededeU, 0x48484848U, 0xa8a8a8a8U, 0x99999999U,
+    0xdbdbdbdbU, 0x32323232U, 0xb7b7b7b7U, 0xfcfcfcfcU,
+    0xe3e3e3e3U, 0x9e9e9e9eU, 0x91919191U, 0x9b9b9b9bU,
+    0xe2e2e2e2U, 0xbbbbbbbbU, 0x41414141U, 0x6e6e6e6eU,
+    0xa5a5a5a5U, 0xcbcbcbcbU, 0x6b6b6b6bU, 0x95959595U,
+    0xa1a1a1a1U, 0xf3f3f3f3U, 0xb1b1b1b1U, 0x02020202U,
+    0xccccccccU, 0xc4c4c4c4U, 0x1d1d1d1dU, 0x14141414U,
+    0xc3c3c3c3U, 0x63636363U, 0xdadadadaU, 0x5d5d5d5dU,
+    0x5f5f5f5fU, 0xdcdcdcdcU, 0x7d7d7d7dU, 0xcdcdcdcdU,
+    0x7f7f7f7fU, 0x5a5a5a5aU, 0x6c6c6c6cU, 0x5c5c5c5cU,
+    0xf7f7f7f7U, 0x26262626U, 0xffffffffU, 0xededededU,
+    0xe8e8e8e8U, 0x9d9d9d9dU, 0x6f6f6f6fU, 0x8e8e8e8eU,
+    0x19191919U, 0xa0a0a0a0U, 0xf0f0f0f0U, 0x89898989U,
+    0x0f0f0f0fU, 0x07070707U, 0xafafafafU, 0xfbfbfbfbU,
+    0x08080808U, 0x15151515U, 0x0d0d0d0dU, 0x04040404U,
+    0x01010101U, 0x64646464U, 0xdfdfdfdfU, 0x76767676U,
+    0x79797979U, 0xddddddddU, 0x3d3d3d3dU, 0x16161616U,
+    0x3f3f3f3fU, 0x37373737U, 0x6d6d6d6dU, 0x38383838U,
+    0xb9b9b9b9U, 0x73737373U, 0xe9e9e9e9U, 0x35353535U,
+    0x55555555U, 0x71717171U, 0x7b7b7b7bU, 0x8c8c8c8cU,
+    0x72727272U, 0x88888888U, 0xf6f6f6f6U, 0x2a2a2a2aU,
+    0x3e3e3e3eU, 0x5e5e5e5eU, 0x27272727U, 0x46464646U,
+    0x0c0c0c0cU, 0x65656565U, 0x68686868U, 0x61616161U,
+    0x03030303U, 0xc1c1c1c1U, 0x57575757U, 0xd6d6d6d6U,
+    0xd9d9d9d9U, 0x58585858U, 0xd8d8d8d8U, 0x66666666U,
+    0xd7d7d7d7U, 0x3a3a3a3aU, 0xc8c8c8c8U, 0x3c3c3c3cU,
+    0xfafafafaU, 0x96969696U, 0xa7a7a7a7U, 0x98989898U,
+    0xececececU, 0xb8b8b8b8U, 0xc7c7c7c7U, 0xaeaeaeaeU,
+    0x69696969U, 0x4b4b4b4bU, 0xababababU, 0xa9a9a9a9U,
+    0x67676767U, 0x0a0a0a0aU, 0x47474747U, 0xf2f2f2f2U,
+    0xb5b5b5b5U, 0x22222222U, 0xe5e5e5e5U, 0xeeeeeeeeU,
+    0xbebebebeU, 0x2b2b2b2bU, 0x81818181U, 0x12121212U,
+    0x83838383U, 0x1b1b1b1bU, 0x0e0e0e0eU, 0x23232323U,
+    0xf5f5f5f5U, 0x45454545U, 0x21212121U, 0xcecececeU,
+    0x49494949U, 0x2c2c2c2cU, 0xf9f9f9f9U, 0xe6e6e6e6U,
+    0xb6b6b6b6U, 0x28282828U, 0x17171717U, 0x82828282U,
+    0x1a1a1a1aU, 0x8b8b8b8bU, 0xfefefefeU, 0x8a8a8a8aU,
+    0x09090909U, 0xc9c9c9c9U, 0x87878787U, 0x4e4e4e4eU,
+    0xe1e1e1e1U, 0x2e2e2e2eU, 0xe4e4e4e4U, 0xe0e0e0e0U,
+    0xebebebebU, 0x90909090U, 0xa4a4a4a4U, 0x1e1e1e1eU,
+    0x85858585U, 0x60606060U, 0x00000000U, 0x25252525U,
+    0xf4f4f4f4U, 0xf1f1f1f1U, 0x94949494U, 0x0b0b0b0bU,
+    0xe7e7e7e7U, 0x75757575U, 0xefefefefU, 0x34343434U,
+    0x31313131U, 0xd4d4d4d4U, 0xd0d0d0d0U, 0x86868686U,
+    0x7e7e7e7eU, 0xadadadadU, 0xfdfdfdfdU, 0x29292929U,
+    0x30303030U, 0x3b3b3b3bU, 0x9f9f9f9fU, 0xf8f8f8f8U,
+    0xc6c6c6c6U, 0x13131313U, 0x06060606U, 0x05050505U,
+    0xc5c5c5c5U, 0x11111111U, 0x77777777U, 0x7c7c7c7cU,
+    0x7a7a7a7aU, 0x78787878U, 0x36363636U, 0x1c1c1c1cU,
+    0x39393939U, 0x59595959U, 0x18181818U, 0x56565656U,
+    0xb3b3b3b3U, 0xb0b0b0b0U, 0x24242424U, 0x20202020U,
+    0xb2b2b2b2U, 0x92929292U, 0xa3a3a3a3U, 0xc0c0c0c0U,
+    0x44444444U, 0x62626262U, 0x10101010U, 0xb4b4b4b4U,
+    0x84848484U, 0x43434343U, 0x93939393U, 0xc2c2c2c2U,
+    0x4a4a4a4aU, 0xbdbdbdbdU, 0x8f8f8f8fU, 0x2d2d2d2dU,
+    0xbcbcbcbcU, 0x9c9c9c9cU, 0x6a6a6a6aU, 0x40404040U,
+    0xcfcfcfcfU, 0xa2a2a2a2U, 0x80808080U, 0x4f4f4f4fU,
+    0x1f1f1f1fU, 0xcacacacaU, 0xaaaaaaaaU, 0x42424242U,
+};
+
+static const ulong32 T5[256] = {
+    0x00000000U, 0x01020608U, 0x02040c10U, 0x03060a18U,
+    0x04081820U, 0x050a1e28U, 0x060c1430U, 0x070e1238U,
+    0x08103040U, 0x09123648U, 0x0a143c50U, 0x0b163a58U,
+    0x0c182860U, 0x0d1a2e68U, 0x0e1c2470U, 0x0f1e2278U,
+    0x10206080U, 0x11226688U, 0x12246c90U, 0x13266a98U,
+    0x142878a0U, 0x152a7ea8U, 0x162c74b0U, 0x172e72b8U,
+    0x183050c0U, 0x193256c8U, 0x1a345cd0U, 0x1b365ad8U,
+    0x1c3848e0U, 0x1d3a4ee8U, 0x1e3c44f0U, 0x1f3e42f8U,
+    0x2040c01dU, 0x2142c615U, 0x2244cc0dU, 0x2346ca05U,
+    0x2448d83dU, 0x254ade35U, 0x264cd42dU, 0x274ed225U,
+    0x2850f05dU, 0x2952f655U, 0x2a54fc4dU, 0x2b56fa45U,
+    0x2c58e87dU, 0x2d5aee75U, 0x2e5ce46dU, 0x2f5ee265U,
+    0x3060a09dU, 0x3162a695U, 0x3264ac8dU, 0x3366aa85U,
+    0x3468b8bdU, 0x356abeb5U, 0x366cb4adU, 0x376eb2a5U,
+    0x387090ddU, 0x397296d5U, 0x3a749ccdU, 0x3b769ac5U,
+    0x3c7888fdU, 0x3d7a8ef5U, 0x3e7c84edU, 0x3f7e82e5U,
+    0x40809d3aU, 0x41829b32U, 0x4284912aU, 0x43869722U,
+    0x4488851aU, 0x458a8312U, 0x468c890aU, 0x478e8f02U,
+    0x4890ad7aU, 0x4992ab72U, 0x4a94a16aU, 0x4b96a762U,
+    0x4c98b55aU, 0x4d9ab352U, 0x4e9cb94aU, 0x4f9ebf42U,
+    0x50a0fdbaU, 0x51a2fbb2U, 0x52a4f1aaU, 0x53a6f7a2U,
+    0x54a8e59aU, 0x55aae392U, 0x56ace98aU, 0x57aeef82U,
+    0x58b0cdfaU, 0x59b2cbf2U, 0x5ab4c1eaU, 0x5bb6c7e2U,
+    0x5cb8d5daU, 0x5dbad3d2U, 0x5ebcd9caU, 0x5fbedfc2U,
+    0x60c05d27U, 0x61c25b2fU, 0x62c45137U, 0x63c6573fU,
+    0x64c84507U, 0x65ca430fU, 0x66cc4917U, 0x67ce4f1fU,
+    0x68d06d67U, 0x69d26b6fU, 0x6ad46177U, 0x6bd6677fU,
+    0x6cd87547U, 0x6dda734fU, 0x6edc7957U, 0x6fde7f5fU,
+    0x70e03da7U, 0x71e23bafU, 0x72e431b7U, 0x73e637bfU,
+    0x74e82587U, 0x75ea238fU, 0x76ec2997U, 0x77ee2f9fU,
+    0x78f00de7U, 0x79f20befU, 0x7af401f7U, 0x7bf607ffU,
+    0x7cf815c7U, 0x7dfa13cfU, 0x7efc19d7U, 0x7ffe1fdfU,
+    0x801d2774U, 0x811f217cU, 0x82192b64U, 0x831b2d6cU,
+    0x84153f54U, 0x8517395cU, 0x86113344U, 0x8713354cU,
+    0x880d1734U, 0x890f113cU, 0x8a091b24U, 0x8b0b1d2cU,
+    0x8c050f14U, 0x8d07091cU, 0x8e010304U, 0x8f03050cU,
+    0x903d47f4U, 0x913f41fcU, 0x92394be4U, 0x933b4decU,
+    0x94355fd4U, 0x953759dcU, 0x963153c4U, 0x973355ccU,
+    0x982d77b4U, 0x992f71bcU, 0x9a297ba4U, 0x9b2b7dacU,
+    0x9c256f94U, 0x9d27699cU, 0x9e216384U, 0x9f23658cU,
+    0xa05de769U, 0xa15fe161U, 0xa259eb79U, 0xa35bed71U,
+    0xa455ff49U, 0xa557f941U, 0xa651f359U, 0xa753f551U,
+    0xa84dd729U, 0xa94fd121U, 0xaa49db39U, 0xab4bdd31U,
+    0xac45cf09U, 0xad47c901U, 0xae41c319U, 0xaf43c511U,
+    0xb07d87e9U, 0xb17f81e1U, 0xb2798bf9U, 0xb37b8df1U,
+    0xb4759fc9U, 0xb57799c1U, 0xb67193d9U, 0xb77395d1U,
+    0xb86db7a9U, 0xb96fb1a1U, 0xba69bbb9U, 0xbb6bbdb1U,
+    0xbc65af89U, 0xbd67a981U, 0xbe61a399U, 0xbf63a591U,
+    0xc09dba4eU, 0xc19fbc46U, 0xc299b65eU, 0xc39bb056U,
+    0xc495a26eU, 0xc597a466U, 0xc691ae7eU, 0xc793a876U,
+    0xc88d8a0eU, 0xc98f8c06U, 0xca89861eU, 0xcb8b8016U,
+    0xcc85922eU, 0xcd879426U, 0xce819e3eU, 0xcf839836U,
+    0xd0bddaceU, 0xd1bfdcc6U, 0xd2b9d6deU, 0xd3bbd0d6U,
+    0xd4b5c2eeU, 0xd5b7c4e6U, 0xd6b1cefeU, 0xd7b3c8f6U,
+    0xd8adea8eU, 0xd9afec86U, 0xdaa9e69eU, 0xdbabe096U,
+    0xdca5f2aeU, 0xdda7f4a6U, 0xdea1febeU, 0xdfa3f8b6U,
+    0xe0dd7a53U, 0xe1df7c5bU, 0xe2d97643U, 0xe3db704bU,
+    0xe4d56273U, 0xe5d7647bU, 0xe6d16e63U, 0xe7d3686bU,
+    0xe8cd4a13U, 0xe9cf4c1bU, 0xeac94603U, 0xebcb400bU,
+    0xecc55233U, 0xedc7543bU, 0xeec15e23U, 0xefc3582bU,
+    0xf0fd1ad3U, 0xf1ff1cdbU, 0xf2f916c3U, 0xf3fb10cbU,
+    0xf4f502f3U, 0xf5f704fbU, 0xf6f10ee3U, 0xf7f308ebU,
+    0xf8ed2a93U, 0xf9ef2c9bU, 0xfae92683U, 0xfbeb208bU,
+    0xfce532b3U, 0xfde734bbU, 0xfee13ea3U, 0xffe338abU,
+};
+
+/**
+ * The round constants.
+ */
+static const ulong32 rc[] = {
+    0xba542f74U, 0x53d3d24dU, 0x50ac8dbfU, 0x70529a4cU,
+    0xead597d1U, 0x33515ba6U, 0xde48a899U, 0xdb32b7fcU,
+    0xe39e919bU, 0xe2bb416eU, 0xa5cb6b95U, 0xa1f3b102U,
+    0xccc41d14U, 0xc363da5dU, 0x5fdc7dcdU, 0x7f5a6c5cU,
+    0xf726ffedU, 0xe89d6f8eU, 0x19a0f089U,
+};
+
+
+
+#else
+
+
+static const ulong32 T0[256] = {
+    0xa753a6f5U, 0xd3bb6bd0U, 0xe6d1bf6eU, 0x71e2d93bU,
+    0xd0bd67daU, 0xac458acfU, 0x4d9a29b3U, 0x79f2f90bU,
+    0x3a74e89cU, 0xc98f038cU, 0x913f7e41U, 0xfce5d732U,
+    0x1e3c7844U, 0x478e018fU, 0x54a84de5U, 0xbd67cea9U,
+    0x8c050a0fU, 0xa557aef9U, 0x7af4f501U, 0xfbebcb20U,
+    0x63c69157U, 0xb86ddab7U, 0xdda753f4U, 0xd4b577c2U,
+    0xe5d7b364U, 0xb37bf68dU, 0xc59733a4U, 0xbe61c2a3U,
+    0xa94f9ed1U, 0x880d1a17U, 0x0c183028U, 0xa259b2ebU,
+    0x3972e496U, 0xdfa35bf8U, 0x2952a4f6U, 0xdaa94fe6U,
+    0x2b56acfaU, 0xa84d9ad7U, 0xcb8b0b80U, 0x4c982db5U,
+    0x4b9631a7U, 0x224488ccU, 0xaa4992dbU, 0x244890d8U,
+    0x4182199bU, 0x70e0dd3dU, 0xa651a2f3U, 0xf9efc32cU,
+    0x5ab475c1U, 0xe2d9af76U, 0xb07dfa87U, 0x366cd8b4U,
+    0x7dfae913U, 0xe4d5b762U, 0x3366ccaaU, 0xffe3db38U,
+    0x60c09d5dU, 0x204080c0U, 0x08102030U, 0x8b0b161dU,
+    0x5ebc65d9U, 0xab4b96ddU, 0x7ffee11fU, 0x78f0fd0dU,
+    0x7cf8ed15U, 0x2c58b0e8U, 0x57ae41efU, 0xd2b96fd6U,
+    0xdca557f2U, 0x6ddaa973U, 0x7efce519U, 0x0d1a342eU,
+    0x53a651f7U, 0x94356a5fU, 0xc39b2bb0U, 0x2850a0f0U,
+    0x274e9cd2U, 0x060c1814U, 0x5fbe61dfU, 0xad478ec9U,
+    0x67ce814fU, 0x5cb86dd5U, 0x55aa49e3U, 0x48903dadU,
+    0x0e1c3824U, 0x52a455f1U, 0xeac98f46U, 0x42841591U,
+    0x5bb671c7U, 0x5dba69d3U, 0x3060c0a0U, 0x58b07dcdU,
+    0x51a259fbU, 0x59b279cbU, 0x3c78f088U, 0x4e9c25b9U,
+    0x3870e090U, 0x8a09121bU, 0x72e4d531U, 0x14285078U,
+    0xe7d3bb68U, 0xc6913faeU, 0xdea15ffeU, 0x50a05dfdU,
+    0x8e010203U, 0x9239724bU, 0xd1bf63dcU, 0x77eec12fU,
+    0x933b764dU, 0x458a0983U, 0x9a29527bU, 0xce811f9eU,
+    0x2d5ab4eeU, 0x03060c0aU, 0x62c49551U, 0xb671e293U,
+    0xb96fdeb1U, 0xbf63c6a5U, 0x96316253U, 0x6bd6b167U,
+    0x3f7efc82U, 0x070e1c12U, 0x1224486cU, 0xae4182c3U,
+    0x40801d9dU, 0x3468d0b8U, 0x468c0589U, 0x3e7cf884U,
+    0xdbab4be0U, 0xcf831b98U, 0xecc59752U, 0xcc851792U,
+    0xc19f23bcU, 0xa15fbee1U, 0xc09d27baU, 0xd6b17fceU,
+    0x1d3a744eU, 0xf4f5f702U, 0x61c2995bU, 0x3b76ec9aU,
+    0x10204060U, 0xd8ad47eaU, 0x68d0bd6dU, 0xa05dbae7U,
+    0xb17ffe81U, 0x0a14283cU, 0x69d2b96bU, 0x6cd8ad75U,
+    0x499239abU, 0xfae9cf26U, 0x76ecc529U, 0xc49537a2U,
+    0x9e214263U, 0x9b2b567dU, 0x6edca579U, 0x992f5e71U,
+    0xc2992fb6U, 0xb773e695U, 0x982d5a77U, 0xbc65caafU,
+    0x8f030605U, 0x85172e39U, 0x1f3e7c42U, 0xb475ea9fU,
+    0xf8edc72aU, 0x11224466U, 0x2e5cb8e4U, 0x00000000U,
+    0x254a94deU, 0x1c387048U, 0x2a54a8fcU, 0x3d7af48eU,
+    0x050a141eU, 0x4f9e21bfU, 0x7bf6f107U, 0xb279f28bU,
+    0x3264c8acU, 0x903d7a47U, 0xaf4386c5U, 0x19326456U,
+    0xa35bb6edU, 0xf7f3fb08U, 0x73e6d137U, 0x9d274e69U,
+    0x152a547eU, 0x74e8cd25U, 0xeec19f5eU, 0xca890f86U,
+    0x9f234665U, 0x0f1e3c22U, 0x1b366c5aU, 0x75eac923U,
+    0x86112233U, 0x84152a3fU, 0x9c254a6fU, 0x4a9435a1U,
+    0x97336655U, 0x1a34685cU, 0x65ca8943U, 0xf6f1ff0eU,
+    0xedc79354U, 0x09122436U, 0xbb6bd6bdU, 0x264c98d4U,
+    0x831b362dU, 0xebcb8b40U, 0x6fdea17fU, 0x811f3e21U,
+    0x04081018U, 0x6ad4b561U, 0x43861197U, 0x01020406U,
+    0x172e5c72U, 0xe1dfa37cU, 0x87132635U, 0xf5f7f304U,
+    0x8d070e09U, 0xe3dbab70U, 0x23468ccaU, 0x801d3a27U,
+    0x44880d85U, 0x162c5874U, 0x66cc8549U, 0x214284c6U,
+    0xfee1df3eU, 0xd5b773c4U, 0x3162c4a6U, 0xd9af43ecU,
+    0x356ad4beU, 0x18306050U, 0x0204080cU, 0x64c88d45U,
+    0xf2f9ef16U, 0xf1ffe31cU, 0x56ac45e9U, 0xcd871394U,
+    0x8219322bU, 0xc88d078aU, 0xba69d2bbU, 0xf0fde71aU,
+    0xefc39b58U, 0xe9cf834cU, 0xe8cd874aU, 0xfde7d334U,
+    0x890f1e11U, 0xd7b37bc8U, 0xc7933ba8U, 0xb577ee99U,
+    0xa455aaffU, 0x2f5ebce2U, 0x95376e59U, 0x13264c6aU,
+    0x0b162c3aU, 0xf3fbeb10U, 0xe0dda77aU, 0x376edcb2U,
+};
+
+static const ulong32 T1[256] = {
+    0x53a7f5a6U, 0xbbd3d06bU, 0xd1e66ebfU, 0xe2713bd9U,
+    0xbdd0da67U, 0x45accf8aU, 0x9a4db329U, 0xf2790bf9U,
+    0x743a9ce8U, 0x8fc98c03U, 0x3f91417eU, 0xe5fc32d7U,
+    0x3c1e4478U, 0x8e478f01U, 0xa854e54dU, 0x67bda9ceU,
+    0x058c0f0aU, 0x57a5f9aeU, 0xf47a01f5U, 0xebfb20cbU,
+    0xc6635791U, 0x6db8b7daU, 0xa7ddf453U, 0xb5d4c277U,
+    0xd7e564b3U, 0x7bb38df6U, 0x97c5a433U, 0x61bea3c2U,
+    0x4fa9d19eU, 0x0d88171aU, 0x180c2830U, 0x59a2ebb2U,
+    0x723996e4U, 0xa3dff85bU, 0x5229f6a4U, 0xa9dae64fU,
+    0x562bfaacU, 0x4da8d79aU, 0x8bcb800bU, 0x984cb52dU,
+    0x964ba731U, 0x4422cc88U, 0x49aadb92U, 0x4824d890U,
+    0x82419b19U, 0xe0703dddU, 0x51a6f3a2U, 0xeff92cc3U,
+    0xb45ac175U, 0xd9e276afU, 0x7db087faU, 0x6c36b4d8U,
+    0xfa7d13e9U, 0xd5e462b7U, 0x6633aaccU, 0xe3ff38dbU,
+    0xc0605d9dU, 0x4020c080U, 0x10083020U, 0x0b8b1d16U,
+    0xbc5ed965U, 0x4babdd96U, 0xfe7f1fe1U, 0xf0780dfdU,
+    0xf87c15edU, 0x582ce8b0U, 0xae57ef41U, 0xb9d2d66fU,
+    0xa5dcf257U, 0xda6d73a9U, 0xfc7e19e5U, 0x1a0d2e34U,
+    0xa653f751U, 0x35945f6aU, 0x9bc3b02bU, 0x5028f0a0U,
+    0x4e27d29cU, 0x0c061418U, 0xbe5fdf61U, 0x47adc98eU,
+    0xce674f81U, 0xb85cd56dU, 0xaa55e349U, 0x9048ad3dU,
+    0x1c0e2438U, 0xa452f155U, 0xc9ea468fU, 0x84429115U,
+    0xb65bc771U, 0xba5dd369U, 0x6030a0c0U, 0xb058cd7dU,
+    0xa251fb59U, 0xb259cb79U, 0x783c88f0U, 0x9c4eb925U,
+    0x703890e0U, 0x098a1b12U, 0xe47231d5U, 0x28147850U,
+    0xd3e768bbU, 0x91c6ae3fU, 0xa1defe5fU, 0xa050fd5dU,
+    0x018e0302U, 0x39924b72U, 0xbfd1dc63U, 0xee772fc1U,
+    0x3b934d76U, 0x8a458309U, 0x299a7b52U, 0x81ce9e1fU,
+    0x5a2deeb4U, 0x06030a0cU, 0xc4625195U, 0x71b693e2U,
+    0x6fb9b1deU, 0x63bfa5c6U, 0x31965362U, 0xd66b67b1U,
+    0x7e3f82fcU, 0x0e07121cU, 0x24126c48U, 0x41aec382U,
+    0x80409d1dU, 0x6834b8d0U, 0x8c468905U, 0x7c3e84f8U,
+    0xabdbe04bU, 0x83cf981bU, 0xc5ec5297U, 0x85cc9217U,
+    0x9fc1bc23U, 0x5fa1e1beU, 0x9dc0ba27U, 0xb1d6ce7fU,
+    0x3a1d4e74U, 0xf5f402f7U, 0xc2615b99U, 0x763b9aecU,
+    0x20106040U, 0xadd8ea47U, 0xd0686dbdU, 0x5da0e7baU,
+    0x7fb181feU, 0x140a3c28U, 0xd2696bb9U, 0xd86c75adU,
+    0x9249ab39U, 0xe9fa26cfU, 0xec7629c5U, 0x95c4a237U,
+    0x219e6342U, 0x2b9b7d56U, 0xdc6e79a5U, 0x2f99715eU,
+    0x99c2b62fU, 0x73b795e6U, 0x2d98775aU, 0x65bcafcaU,
+    0x038f0506U, 0x1785392eU, 0x3e1f427cU, 0x75b49feaU,
+    0xedf82ac7U, 0x22116644U, 0x5c2ee4b8U, 0x00000000U,
+    0x4a25de94U, 0x381c4870U, 0x542afca8U, 0x7a3d8ef4U,
+    0x0a051e14U, 0x9e4fbf21U, 0xf67b07f1U, 0x79b28bf2U,
+    0x6432acc8U, 0x3d90477aU, 0x43afc586U, 0x32195664U,
+    0x5ba3edb6U, 0xf3f708fbU, 0xe67337d1U, 0x279d694eU,
+    0x2a157e54U, 0xe87425cdU, 0xc1ee5e9fU, 0x89ca860fU,
+    0x239f6546U, 0x1e0f223cU, 0x361b5a6cU, 0xea7523c9U,
+    0x11863322U, 0x15843f2aU, 0x259c6f4aU, 0x944aa135U,
+    0x33975566U, 0x341a5c68U, 0xca654389U, 0xf1f60effU,
+    0xc7ed5493U, 0x12093624U, 0x6bbbbdd6U, 0x4c26d498U,
+    0x1b832d36U, 0xcbeb408bU, 0xde6f7fa1U, 0x1f81213eU,
+    0x08041810U, 0xd46a61b5U, 0x86439711U, 0x02010604U,
+    0x2e17725cU, 0xdfe17ca3U, 0x13873526U, 0xf7f504f3U,
+    0x078d090eU, 0xdbe370abU, 0x4623ca8cU, 0x1d80273aU,
+    0x8844850dU, 0x2c167458U, 0xcc664985U, 0x4221c684U,
+    0xe1fe3edfU, 0xb7d5c473U, 0x6231a6c4U, 0xafd9ec43U,
+    0x6a35bed4U, 0x30185060U, 0x04020c08U, 0xc864458dU,
+    0xf9f216efU, 0xfff11ce3U, 0xac56e945U, 0x87cd9413U,
+    0x19822b32U, 0x8dc88a07U, 0x69babbd2U, 0xfdf01ae7U,
+    0xc3ef589bU, 0xcfe94c83U, 0xcde84a87U, 0xe7fd34d3U,
+    0x0f89111eU, 0xb3d7c87bU, 0x93c7a83bU, 0x77b599eeU,
+    0x55a4ffaaU, 0x5e2fe2bcU, 0x3795596eU, 0x26136a4cU,
+    0x160b3a2cU, 0xfbf310ebU, 0xdde07aa7U, 0x6e37b2dcU,
+};
+
+static const ulong32 T2[256] = {
+    0xa6f5a753U, 0x6bd0d3bbU, 0xbf6ee6d1U, 0xd93b71e2U,
+    0x67dad0bdU, 0x8acfac45U, 0x29b34d9aU, 0xf90b79f2U,
+    0xe89c3a74U, 0x038cc98fU, 0x7e41913fU, 0xd732fce5U,
+    0x78441e3cU, 0x018f478eU, 0x4de554a8U, 0xcea9bd67U,
+    0x0a0f8c05U, 0xaef9a557U, 0xf5017af4U, 0xcb20fbebU,
+    0x915763c6U, 0xdab7b86dU, 0x53f4dda7U, 0x77c2d4b5U,
+    0xb364e5d7U, 0xf68db37bU, 0x33a4c597U, 0xc2a3be61U,
+    0x9ed1a94fU, 0x1a17880dU, 0x30280c18U, 0xb2eba259U,
+    0xe4963972U, 0x5bf8dfa3U, 0xa4f62952U, 0x4fe6daa9U,
+    0xacfa2b56U, 0x9ad7a84dU, 0x0b80cb8bU, 0x2db54c98U,
+    0x31a74b96U, 0x88cc2244U, 0x92dbaa49U, 0x90d82448U,
+    0x199b4182U, 0xdd3d70e0U, 0xa2f3a651U, 0xc32cf9efU,
+    0x75c15ab4U, 0xaf76e2d9U, 0xfa87b07dU, 0xd8b4366cU,
+    0xe9137dfaU, 0xb762e4d5U, 0xccaa3366U, 0xdb38ffe3U,
+    0x9d5d60c0U, 0x80c02040U, 0x20300810U, 0x161d8b0bU,
+    0x65d95ebcU, 0x96ddab4bU, 0xe11f7ffeU, 0xfd0d78f0U,
+    0xed157cf8U, 0xb0e82c58U, 0x41ef57aeU, 0x6fd6d2b9U,
+    0x57f2dca5U, 0xa9736ddaU, 0xe5197efcU, 0x342e0d1aU,
+    0x51f753a6U, 0x6a5f9435U, 0x2bb0c39bU, 0xa0f02850U,
+    0x9cd2274eU, 0x1814060cU, 0x61df5fbeU, 0x8ec9ad47U,
+    0x814f67ceU, 0x6dd55cb8U, 0x49e355aaU, 0x3dad4890U,
+    0x38240e1cU, 0x55f152a4U, 0x8f46eac9U, 0x15914284U,
+    0x71c75bb6U, 0x69d35dbaU, 0xc0a03060U, 0x7dcd58b0U,
+    0x59fb51a2U, 0x79cb59b2U, 0xf0883c78U, 0x25b94e9cU,
+    0xe0903870U, 0x121b8a09U, 0xd53172e4U, 0x50781428U,
+    0xbb68e7d3U, 0x3faec691U, 0x5ffedea1U, 0x5dfd50a0U,
+    0x02038e01U, 0x724b9239U, 0x63dcd1bfU, 0xc12f77eeU,
+    0x764d933bU, 0x0983458aU, 0x527b9a29U, 0x1f9ece81U,
+    0xb4ee2d5aU, 0x0c0a0306U, 0x955162c4U, 0xe293b671U,
+    0xdeb1b96fU, 0xc6a5bf63U, 0x62539631U, 0xb1676bd6U,
+    0xfc823f7eU, 0x1c12070eU, 0x486c1224U, 0x82c3ae41U,
+    0x1d9d4080U, 0xd0b83468U, 0x0589468cU, 0xf8843e7cU,
+    0x4be0dbabU, 0x1b98cf83U, 0x9752ecc5U, 0x1792cc85U,
+    0x23bcc19fU, 0xbee1a15fU, 0x27bac09dU, 0x7fced6b1U,
+    0x744e1d3aU, 0xf702f4f5U, 0x995b61c2U, 0xec9a3b76U,
+    0x40601020U, 0x47ead8adU, 0xbd6d68d0U, 0xbae7a05dU,
+    0xfe81b17fU, 0x283c0a14U, 0xb96b69d2U, 0xad756cd8U,
+    0x39ab4992U, 0xcf26fae9U, 0xc52976ecU, 0x37a2c495U,
+    0x42639e21U, 0x567d9b2bU, 0xa5796edcU, 0x5e71992fU,
+    0x2fb6c299U, 0xe695b773U, 0x5a77982dU, 0xcaafbc65U,
+    0x06058f03U, 0x2e398517U, 0x7c421f3eU, 0xea9fb475U,
+    0xc72af8edU, 0x44661122U, 0xb8e42e5cU, 0x00000000U,
+    0x94de254aU, 0x70481c38U, 0xa8fc2a54U, 0xf48e3d7aU,
+    0x141e050aU, 0x21bf4f9eU, 0xf1077bf6U, 0xf28bb279U,
+    0xc8ac3264U, 0x7a47903dU, 0x86c5af43U, 0x64561932U,
+    0xb6eda35bU, 0xfb08f7f3U, 0xd13773e6U, 0x4e699d27U,
+    0x547e152aU, 0xcd2574e8U, 0x9f5eeec1U, 0x0f86ca89U,
+    0x46659f23U, 0x3c220f1eU, 0x6c5a1b36U, 0xc92375eaU,
+    0x22338611U, 0x2a3f8415U, 0x4a6f9c25U, 0x35a14a94U,
+    0x66559733U, 0x685c1a34U, 0x894365caU, 0xff0ef6f1U,
+    0x9354edc7U, 0x24360912U, 0xd6bdbb6bU, 0x98d4264cU,
+    0x362d831bU, 0x8b40ebcbU, 0xa17f6fdeU, 0x3e21811fU,
+    0x10180408U, 0xb5616ad4U, 0x11974386U, 0x04060102U,
+    0x5c72172eU, 0xa37ce1dfU, 0x26358713U, 0xf304f5f7U,
+    0x0e098d07U, 0xab70e3dbU, 0x8cca2346U, 0x3a27801dU,
+    0x0d854488U, 0x5874162cU, 0x854966ccU, 0x84c62142U,
+    0xdf3efee1U, 0x73c4d5b7U, 0xc4a63162U, 0x43ecd9afU,
+    0xd4be356aU, 0x60501830U, 0x080c0204U, 0x8d4564c8U,
+    0xef16f2f9U, 0xe31cf1ffU, 0x45e956acU, 0x1394cd87U,
+    0x322b8219U, 0x078ac88dU, 0xd2bbba69U, 0xe71af0fdU,
+    0x9b58efc3U, 0x834ce9cfU, 0x874ae8cdU, 0xd334fde7U,
+    0x1e11890fU, 0x7bc8d7b3U, 0x3ba8c793U, 0xee99b577U,
+    0xaaffa455U, 0xbce22f5eU, 0x6e599537U, 0x4c6a1326U,
+    0x2c3a0b16U, 0xeb10f3fbU, 0xa77ae0ddU, 0xdcb2376eU,
+};
+
+static const ulong32 T3[256] = {
+    0xf5a653a7U, 0xd06bbbd3U, 0x6ebfd1e6U, 0x3bd9e271U,
+    0xda67bdd0U, 0xcf8a45acU, 0xb3299a4dU, 0x0bf9f279U,
+    0x9ce8743aU, 0x8c038fc9U, 0x417e3f91U, 0x32d7e5fcU,
+    0x44783c1eU, 0x8f018e47U, 0xe54da854U, 0xa9ce67bdU,
+    0x0f0a058cU, 0xf9ae57a5U, 0x01f5f47aU, 0x20cbebfbU,
+    0x5791c663U, 0xb7da6db8U, 0xf453a7ddU, 0xc277b5d4U,
+    0x64b3d7e5U, 0x8df67bb3U, 0xa43397c5U, 0xa3c261beU,
+    0xd19e4fa9U, 0x171a0d88U, 0x2830180cU, 0xebb259a2U,
+    0x96e47239U, 0xf85ba3dfU, 0xf6a45229U, 0xe64fa9daU,
+    0xfaac562bU, 0xd79a4da8U, 0x800b8bcbU, 0xb52d984cU,
+    0xa731964bU, 0xcc884422U, 0xdb9249aaU, 0xd8904824U,
+    0x9b198241U, 0x3ddde070U, 0xf3a251a6U, 0x2cc3eff9U,
+    0xc175b45aU, 0x76afd9e2U, 0x87fa7db0U, 0xb4d86c36U,
+    0x13e9fa7dU, 0x62b7d5e4U, 0xaacc6633U, 0x38dbe3ffU,
+    0x5d9dc060U, 0xc0804020U, 0x30201008U, 0x1d160b8bU,
+    0xd965bc5eU, 0xdd964babU, 0x1fe1fe7fU, 0x0dfdf078U,
+    0x15edf87cU, 0xe8b0582cU, 0xef41ae57U, 0xd66fb9d2U,
+    0xf257a5dcU, 0x73a9da6dU, 0x19e5fc7eU, 0x2e341a0dU,
+    0xf751a653U, 0x5f6a3594U, 0xb02b9bc3U, 0xf0a05028U,
+    0xd29c4e27U, 0x14180c06U, 0xdf61be5fU, 0xc98e47adU,
+    0x4f81ce67U, 0xd56db85cU, 0xe349aa55U, 0xad3d9048U,
+    0x24381c0eU, 0xf155a452U, 0x468fc9eaU, 0x91158442U,
+    0xc771b65bU, 0xd369ba5dU, 0xa0c06030U, 0xcd7db058U,
+    0xfb59a251U, 0xcb79b259U, 0x88f0783cU, 0xb9259c4eU,
+    0x90e07038U, 0x1b12098aU, 0x31d5e472U, 0x78502814U,
+    0x68bbd3e7U, 0xae3f91c6U, 0xfe5fa1deU, 0xfd5da050U,
+    0x0302018eU, 0x4b723992U, 0xdc63bfd1U, 0x2fc1ee77U,
+    0x4d763b93U, 0x83098a45U, 0x7b52299aU, 0x9e1f81ceU,
+    0xeeb45a2dU, 0x0a0c0603U, 0x5195c462U, 0x93e271b6U,
+    0xb1de6fb9U, 0xa5c663bfU, 0x53623196U, 0x67b1d66bU,
+    0x82fc7e3fU, 0x121c0e07U, 0x6c482412U, 0xc38241aeU,
+    0x9d1d8040U, 0xb8d06834U, 0x89058c46U, 0x84f87c3eU,
+    0xe04babdbU, 0x981b83cfU, 0x5297c5ecU, 0x921785ccU,
+    0xbc239fc1U, 0xe1be5fa1U, 0xba279dc0U, 0xce7fb1d6U,
+    0x4e743a1dU, 0x02f7f5f4U, 0x5b99c261U, 0x9aec763bU,
+    0x60402010U, 0xea47add8U, 0x6dbdd068U, 0xe7ba5da0U,
+    0x81fe7fb1U, 0x3c28140aU, 0x6bb9d269U, 0x75add86cU,
+    0xab399249U, 0x26cfe9faU, 0x29c5ec76U, 0xa23795c4U,
+    0x6342219eU, 0x7d562b9bU, 0x79a5dc6eU, 0x715e2f99U,
+    0xb62f99c2U, 0x95e673b7U, 0x775a2d98U, 0xafca65bcU,
+    0x0506038fU, 0x392e1785U, 0x427c3e1fU, 0x9fea75b4U,
+    0x2ac7edf8U, 0x66442211U, 0xe4b85c2eU, 0x00000000U,
+    0xde944a25U, 0x4870381cU, 0xfca8542aU, 0x8ef47a3dU,
+    0x1e140a05U, 0xbf219e4fU, 0x07f1f67bU, 0x8bf279b2U,
+    0xacc86432U, 0x477a3d90U, 0xc58643afU, 0x56643219U,
+    0xedb65ba3U, 0x08fbf3f7U, 0x37d1e673U, 0x694e279dU,
+    0x7e542a15U, 0x25cde874U, 0x5e9fc1eeU, 0x860f89caU,
+    0x6546239fU, 0x223c1e0fU, 0x5a6c361bU, 0x23c9ea75U,
+    0x33221186U, 0x3f2a1584U, 0x6f4a259cU, 0xa135944aU,
+    0x55663397U, 0x5c68341aU, 0x4389ca65U, 0x0efff1f6U,
+    0x5493c7edU, 0x36241209U, 0xbdd66bbbU, 0xd4984c26U,
+    0x2d361b83U, 0x408bcbebU, 0x7fa1de6fU, 0x213e1f81U,
+    0x18100804U, 0x61b5d46aU, 0x97118643U, 0x06040201U,
+    0x725c2e17U, 0x7ca3dfe1U, 0x35261387U, 0x04f3f7f5U,
+    0x090e078dU, 0x70abdbe3U, 0xca8c4623U, 0x273a1d80U,
+    0x850d8844U, 0x74582c16U, 0x4985cc66U, 0xc6844221U,
+    0x3edfe1feU, 0xc473b7d5U, 0xa6c46231U, 0xec43afd9U,
+    0xbed46a35U, 0x50603018U, 0x0c080402U, 0x458dc864U,
+    0x16eff9f2U, 0x1ce3fff1U, 0xe945ac56U, 0x941387cdU,
+    0x2b321982U, 0x8a078dc8U, 0xbbd269baU, 0x1ae7fdf0U,
+    0x589bc3efU, 0x4c83cfe9U, 0x4a87cde8U, 0x34d3e7fdU,
+    0x111e0f89U, 0xc87bb3d7U, 0xa83b93c7U, 0x99ee77b5U,
+    0xffaa55a4U, 0xe2bc5e2fU, 0x596e3795U, 0x6a4c2613U,
+    0x3a2c160bU, 0x10ebfbf3U, 0x7aa7dde0U, 0xb2dc6e37U,
+};
+
+static const ulong32 T4[256] = {
+    0xa7a7a7a7U, 0xd3d3d3d3U, 0xe6e6e6e6U, 0x71717171U,
+    0xd0d0d0d0U, 0xacacacacU, 0x4d4d4d4dU, 0x79797979U,
+    0x3a3a3a3aU, 0xc9c9c9c9U, 0x91919191U, 0xfcfcfcfcU,
+    0x1e1e1e1eU, 0x47474747U, 0x54545454U, 0xbdbdbdbdU,
+    0x8c8c8c8cU, 0xa5a5a5a5U, 0x7a7a7a7aU, 0xfbfbfbfbU,
+    0x63636363U, 0xb8b8b8b8U, 0xddddddddU, 0xd4d4d4d4U,
+    0xe5e5e5e5U, 0xb3b3b3b3U, 0xc5c5c5c5U, 0xbebebebeU,
+    0xa9a9a9a9U, 0x88888888U, 0x0c0c0c0cU, 0xa2a2a2a2U,
+    0x39393939U, 0xdfdfdfdfU, 0x29292929U, 0xdadadadaU,
+    0x2b2b2b2bU, 0xa8a8a8a8U, 0xcbcbcbcbU, 0x4c4c4c4cU,
+    0x4b4b4b4bU, 0x22222222U, 0xaaaaaaaaU, 0x24242424U,
+    0x41414141U, 0x70707070U, 0xa6a6a6a6U, 0xf9f9f9f9U,
+    0x5a5a5a5aU, 0xe2e2e2e2U, 0xb0b0b0b0U, 0x36363636U,
+    0x7d7d7d7dU, 0xe4e4e4e4U, 0x33333333U, 0xffffffffU,
+    0x60606060U, 0x20202020U, 0x08080808U, 0x8b8b8b8bU,
+    0x5e5e5e5eU, 0xababababU, 0x7f7f7f7fU, 0x78787878U,
+    0x7c7c7c7cU, 0x2c2c2c2cU, 0x57575757U, 0xd2d2d2d2U,
+    0xdcdcdcdcU, 0x6d6d6d6dU, 0x7e7e7e7eU, 0x0d0d0d0dU,
+    0x53535353U, 0x94949494U, 0xc3c3c3c3U, 0x28282828U,
+    0x27272727U, 0x06060606U, 0x5f5f5f5fU, 0xadadadadU,
+    0x67676767U, 0x5c5c5c5cU, 0x55555555U, 0x48484848U,
+    0x0e0e0e0eU, 0x52525252U, 0xeaeaeaeaU, 0x42424242U,
+    0x5b5b5b5bU, 0x5d5d5d5dU, 0x30303030U, 0x58585858U,
+    0x51515151U, 0x59595959U, 0x3c3c3c3cU, 0x4e4e4e4eU,
+    0x38383838U, 0x8a8a8a8aU, 0x72727272U, 0x14141414U,
+    0xe7e7e7e7U, 0xc6c6c6c6U, 0xdedededeU, 0x50505050U,
+    0x8e8e8e8eU, 0x92929292U, 0xd1d1d1d1U, 0x77777777U,
+    0x93939393U, 0x45454545U, 0x9a9a9a9aU, 0xcecececeU,
+    0x2d2d2d2dU, 0x03030303U, 0x62626262U, 0xb6b6b6b6U,
+    0xb9b9b9b9U, 0xbfbfbfbfU, 0x96969696U, 0x6b6b6b6bU,
+    0x3f3f3f3fU, 0x07070707U, 0x12121212U, 0xaeaeaeaeU,
+    0x40404040U, 0x34343434U, 0x46464646U, 0x3e3e3e3eU,
+    0xdbdbdbdbU, 0xcfcfcfcfU, 0xececececU, 0xccccccccU,
+    0xc1c1c1c1U, 0xa1a1a1a1U, 0xc0c0c0c0U, 0xd6d6d6d6U,
+    0x1d1d1d1dU, 0xf4f4f4f4U, 0x61616161U, 0x3b3b3b3bU,
+    0x10101010U, 0xd8d8d8d8U, 0x68686868U, 0xa0a0a0a0U,
+    0xb1b1b1b1U, 0x0a0a0a0aU, 0x69696969U, 0x6c6c6c6cU,
+    0x49494949U, 0xfafafafaU, 0x76767676U, 0xc4c4c4c4U,
+    0x9e9e9e9eU, 0x9b9b9b9bU, 0x6e6e6e6eU, 0x99999999U,
+    0xc2c2c2c2U, 0xb7b7b7b7U, 0x98989898U, 0xbcbcbcbcU,
+    0x8f8f8f8fU, 0x85858585U, 0x1f1f1f1fU, 0xb4b4b4b4U,
+    0xf8f8f8f8U, 0x11111111U, 0x2e2e2e2eU, 0x00000000U,
+    0x25252525U, 0x1c1c1c1cU, 0x2a2a2a2aU, 0x3d3d3d3dU,
+    0x05050505U, 0x4f4f4f4fU, 0x7b7b7b7bU, 0xb2b2b2b2U,
+    0x32323232U, 0x90909090U, 0xafafafafU, 0x19191919U,
+    0xa3a3a3a3U, 0xf7f7f7f7U, 0x73737373U, 0x9d9d9d9dU,
+    0x15151515U, 0x74747474U, 0xeeeeeeeeU, 0xcacacacaU,
+    0x9f9f9f9fU, 0x0f0f0f0fU, 0x1b1b1b1bU, 0x75757575U,
+    0x86868686U, 0x84848484U, 0x9c9c9c9cU, 0x4a4a4a4aU,
+    0x97979797U, 0x1a1a1a1aU, 0x65656565U, 0xf6f6f6f6U,
+    0xededededU, 0x09090909U, 0xbbbbbbbbU, 0x26262626U,
+    0x83838383U, 0xebebebebU, 0x6f6f6f6fU, 0x81818181U,
+    0x04040404U, 0x6a6a6a6aU, 0x43434343U, 0x01010101U,
+    0x17171717U, 0xe1e1e1e1U, 0x87878787U, 0xf5f5f5f5U,
+    0x8d8d8d8dU, 0xe3e3e3e3U, 0x23232323U, 0x80808080U,
+    0x44444444U, 0x16161616U, 0x66666666U, 0x21212121U,
+    0xfefefefeU, 0xd5d5d5d5U, 0x31313131U, 0xd9d9d9d9U,
+    0x35353535U, 0x18181818U, 0x02020202U, 0x64646464U,
+    0xf2f2f2f2U, 0xf1f1f1f1U, 0x56565656U, 0xcdcdcdcdU,
+    0x82828282U, 0xc8c8c8c8U, 0xbabababaU, 0xf0f0f0f0U,
+    0xefefefefU, 0xe9e9e9e9U, 0xe8e8e8e8U, 0xfdfdfdfdU,
+    0x89898989U, 0xd7d7d7d7U, 0xc7c7c7c7U, 0xb5b5b5b5U,
+    0xa4a4a4a4U, 0x2f2f2f2fU, 0x95959595U, 0x13131313U,
+    0x0b0b0b0bU, 0xf3f3f3f3U, 0xe0e0e0e0U, 0x37373737U,
+};
+
+static const ulong32 T5[256] = {
+    0x00000000U, 0x01020608U, 0x02040c10U, 0x03060a18U,
+    0x04081820U, 0x050a1e28U, 0x060c1430U, 0x070e1238U,
+    0x08103040U, 0x09123648U, 0x0a143c50U, 0x0b163a58U,
+    0x0c182860U, 0x0d1a2e68U, 0x0e1c2470U, 0x0f1e2278U,
+    0x10206080U, 0x11226688U, 0x12246c90U, 0x13266a98U,
+    0x142878a0U, 0x152a7ea8U, 0x162c74b0U, 0x172e72b8U,
+    0x183050c0U, 0x193256c8U, 0x1a345cd0U, 0x1b365ad8U,
+    0x1c3848e0U, 0x1d3a4ee8U, 0x1e3c44f0U, 0x1f3e42f8U,
+    0x2040c01dU, 0x2142c615U, 0x2244cc0dU, 0x2346ca05U,
+    0x2448d83dU, 0x254ade35U, 0x264cd42dU, 0x274ed225U,
+    0x2850f05dU, 0x2952f655U, 0x2a54fc4dU, 0x2b56fa45U,
+    0x2c58e87dU, 0x2d5aee75U, 0x2e5ce46dU, 0x2f5ee265U,
+    0x3060a09dU, 0x3162a695U, 0x3264ac8dU, 0x3366aa85U,
+    0x3468b8bdU, 0x356abeb5U, 0x366cb4adU, 0x376eb2a5U,
+    0x387090ddU, 0x397296d5U, 0x3a749ccdU, 0x3b769ac5U,
+    0x3c7888fdU, 0x3d7a8ef5U, 0x3e7c84edU, 0x3f7e82e5U,
+    0x40809d3aU, 0x41829b32U, 0x4284912aU, 0x43869722U,
+    0x4488851aU, 0x458a8312U, 0x468c890aU, 0x478e8f02U,
+    0x4890ad7aU, 0x4992ab72U, 0x4a94a16aU, 0x4b96a762U,
+    0x4c98b55aU, 0x4d9ab352U, 0x4e9cb94aU, 0x4f9ebf42U,
+    0x50a0fdbaU, 0x51a2fbb2U, 0x52a4f1aaU, 0x53a6f7a2U,
+    0x54a8e59aU, 0x55aae392U, 0x56ace98aU, 0x57aeef82U,
+    0x58b0cdfaU, 0x59b2cbf2U, 0x5ab4c1eaU, 0x5bb6c7e2U,
+    0x5cb8d5daU, 0x5dbad3d2U, 0x5ebcd9caU, 0x5fbedfc2U,
+    0x60c05d27U, 0x61c25b2fU, 0x62c45137U, 0x63c6573fU,
+    0x64c84507U, 0x65ca430fU, 0x66cc4917U, 0x67ce4f1fU,
+    0x68d06d67U, 0x69d26b6fU, 0x6ad46177U, 0x6bd6677fU,
+    0x6cd87547U, 0x6dda734fU, 0x6edc7957U, 0x6fde7f5fU,
+    0x70e03da7U, 0x71e23bafU, 0x72e431b7U, 0x73e637bfU,
+    0x74e82587U, 0x75ea238fU, 0x76ec2997U, 0x77ee2f9fU,
+    0x78f00de7U, 0x79f20befU, 0x7af401f7U, 0x7bf607ffU,
+    0x7cf815c7U, 0x7dfa13cfU, 0x7efc19d7U, 0x7ffe1fdfU,
+    0x801d2774U, 0x811f217cU, 0x82192b64U, 0x831b2d6cU,
+    0x84153f54U, 0x8517395cU, 0x86113344U, 0x8713354cU,
+    0x880d1734U, 0x890f113cU, 0x8a091b24U, 0x8b0b1d2cU,
+    0x8c050f14U, 0x8d07091cU, 0x8e010304U, 0x8f03050cU,
+    0x903d47f4U, 0x913f41fcU, 0x92394be4U, 0x933b4decU,
+    0x94355fd4U, 0x953759dcU, 0x963153c4U, 0x973355ccU,
+    0x982d77b4U, 0x992f71bcU, 0x9a297ba4U, 0x9b2b7dacU,
+    0x9c256f94U, 0x9d27699cU, 0x9e216384U, 0x9f23658cU,
+    0xa05de769U, 0xa15fe161U, 0xa259eb79U, 0xa35bed71U,
+    0xa455ff49U, 0xa557f941U, 0xa651f359U, 0xa753f551U,
+    0xa84dd729U, 0xa94fd121U, 0xaa49db39U, 0xab4bdd31U,
+    0xac45cf09U, 0xad47c901U, 0xae41c319U, 0xaf43c511U,
+    0xb07d87e9U, 0xb17f81e1U, 0xb2798bf9U, 0xb37b8df1U,
+    0xb4759fc9U, 0xb57799c1U, 0xb67193d9U, 0xb77395d1U,
+    0xb86db7a9U, 0xb96fb1a1U, 0xba69bbb9U, 0xbb6bbdb1U,
+    0xbc65af89U, 0xbd67a981U, 0xbe61a399U, 0xbf63a591U,
+    0xc09dba4eU, 0xc19fbc46U, 0xc299b65eU, 0xc39bb056U,
+    0xc495a26eU, 0xc597a466U, 0xc691ae7eU, 0xc793a876U,
+    0xc88d8a0eU, 0xc98f8c06U, 0xca89861eU, 0xcb8b8016U,
+    0xcc85922eU, 0xcd879426U, 0xce819e3eU, 0xcf839836U,
+    0xd0bddaceU, 0xd1bfdcc6U, 0xd2b9d6deU, 0xd3bbd0d6U,
+    0xd4b5c2eeU, 0xd5b7c4e6U, 0xd6b1cefeU, 0xd7b3c8f6U,
+    0xd8adea8eU, 0xd9afec86U, 0xdaa9e69eU, 0xdbabe096U,
+    0xdca5f2aeU, 0xdda7f4a6U, 0xdea1febeU, 0xdfa3f8b6U,
+    0xe0dd7a53U, 0xe1df7c5bU, 0xe2d97643U, 0xe3db704bU,
+    0xe4d56273U, 0xe5d7647bU, 0xe6d16e63U, 0xe7d3686bU,
+    0xe8cd4a13U, 0xe9cf4c1bU, 0xeac94603U, 0xebcb400bU,
+    0xecc55233U, 0xedc7543bU, 0xeec15e23U, 0xefc3582bU,
+    0xf0fd1ad3U, 0xf1ff1cdbU, 0xf2f916c3U, 0xf3fb10cbU,
+    0xf4f502f3U, 0xf5f704fbU, 0xf6f10ee3U, 0xf7f308ebU,
+    0xf8ed2a93U, 0xf9ef2c9bU, 0xfae92683U, 0xfbeb208bU,
+    0xfce532b3U, 0xfde734bbU, 0xfee13ea3U, 0xffe338abU,
+};
+
+/**
+ * The round constants.
+ */
+static const ulong32 rc[] = {
+   0xa7d3e671U, 0xd0ac4d79U, 0x3ac991fcU, 0x1e4754bdU,
+   0x8ca57afbU, 0x63b8ddd4U, 0xe5b3c5beU, 0xa9880ca2U,
+   0x39df29daU, 0x2ba8cb4cU, 0x4b22aa24U, 0x4170a6f9U,
+   0x5ae2b036U, 0x7de433ffU, 0x6020088bU, 0x5eab7f78U,
+   0x7c2c57d2U, 0xdc6d7e0dU, 0x5394c328U,
+};
+
+#endif
+
+ /**
+    Initialize the Anubis block cipher
+    @param key The symmetric key you wish to pass
+    @param keylen The key length in bytes
+    @param num_rounds The number of rounds desired (0 for default)
+    @param skey The key in as scheduled by this function.
+    @return CRYPT_OK if successful
+ */
+#ifdef LTC_CLEAN_STACK
+static int _anubis_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey)
+#else
+int  anubis_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey)
+#endif
+{
+   int N, R, i, pos, r;
+   ulong32 kappa[MAX_N];
+   ulong32 inter[MAX_N] = { 0 }; /* initialize as all zeroes */
+   ulong32 v, K0, K1, K2, K3;
+
+   LTC_ARGCHK(key  != NULL);
+   LTC_ARGCHK(skey != NULL);
+
+   /* Valid sizes (in bytes) are 16, 20, 24, 28, 32, 36, and 40. */
+   if ((keylen & 3) || (keylen < 16) || (keylen > 40)) {
+      return CRYPT_INVALID_KEYSIZE;
+   }
+   skey->anubis.keyBits = keylen*8;
+
+   /*
+    * determine the N length parameter:
+    * (N.B. it is assumed that the key length is valid!)
+    */
+   N = skey->anubis.keyBits >> 5;
+
+   /*
+    * determine number of rounds from key size:
+    */
+   skey->anubis.R = R = 8 + N;
+
+   if (num_rounds != 0 && num_rounds != skey->anubis.R) {
+      return CRYPT_INVALID_ROUNDS;
+   }
+
+   /*
+   * map cipher key to initial key state (mu):
+   */
+   for (i = 0, pos = 0; i < N; i++, pos += 4) {
+      kappa[i] =
+         (((ulong32)key[pos    ]) << 24) ^
+         (((ulong32)key[pos + 1]) << 16) ^
+         (((ulong32)key[pos + 2]) <<  8) ^
+         (((ulong32)key[pos + 3])      );
+   }
+
+   /*
+    * generate R + 1 round keys:
+    */
+   for (r = 0; r <= R; r++) {
+      /*
+       * generate r-th round key K^r:
+       */
+      K0 = T4[(kappa[N - 1] >> 24) & 0xff];
+      K1 = T4[(kappa[N - 1] >> 16) & 0xff];
+      K2 = T4[(kappa[N - 1] >>  8) & 0xff];
+      K3 = T4[(kappa[N - 1]      ) & 0xff];
+      for (i = N - 2; i >= 0; i--) {
+         K0 = T4[(kappa[i] >> 24)  & 0xff] ^
+            (T5[(K0 >> 24) & 0xff] & 0xff000000U) ^
+            (T5[(K0 >> 16) & 0xff] & 0x00ff0000U) ^
+            (T5[(K0 >>  8) & 0xff] & 0x0000ff00U) ^
+            (T5[(K0      ) & 0xff] & 0x000000ffU);
+         K1 = T4[(kappa[i] >> 16) & 0xff] ^
+            (T5[(K1 >> 24) & 0xff] & 0xff000000U) ^
+            (T5[(K1 >> 16) & 0xff] & 0x00ff0000U) ^
+            (T5[(K1 >>  8) & 0xff] & 0x0000ff00U) ^
+            (T5[(K1      ) & 0xff] & 0x000000ffU);
+         K2 = T4[(kappa[i] >>  8) & 0xff] ^
+            (T5[(K2 >> 24) & 0xff] & 0xff000000U) ^
+            (T5[(K2 >> 16) & 0xff] & 0x00ff0000U) ^
+            (T5[(K2 >>  8) & 0xff] & 0x0000ff00U) ^
+            (T5[(K2      ) & 0xff] & 0x000000ffU);
+         K3 = T4[(kappa[i]      ) & 0xff] ^
+            (T5[(K3 >> 24) & 0xff] & 0xff000000U) ^
+            (T5[(K3 >> 16) & 0xff] & 0x00ff0000U) ^
+            (T5[(K3 >>  8) & 0xff] & 0x0000ff00U) ^
+            (T5[(K3      ) & 0xff] & 0x000000ffU);
+      }
+      /*
+      -- this is the code to use with the large U tables:
+      K0 = K1 = K2 = K3 = 0;
+      for (i = 0; i < N; i++) {
+         K0 ^= U[i][(kappa[i] >> 24) & 0xff];
+         K1 ^= U[i][(kappa[i] >> 16) & 0xff];
+         K2 ^= U[i][(kappa[i] >>  8) & 0xff];
+         K3 ^= U[i][(kappa[i]      ) & 0xff];
+      }
+      */
+      skey->anubis.roundKeyEnc[r][0] = K0;
+      skey->anubis.roundKeyEnc[r][1] = K1;
+      skey->anubis.roundKeyEnc[r][2] = K2;
+      skey->anubis.roundKeyEnc[r][3] = K3;
+
+      /*
+       * compute kappa^{r+1} from kappa^r:
+       */
+      if (r == R) {
+         break;
+      }
+      for (i = 0; i < N; i++) {
+         int j = i;
+         inter[i]  = T0[(kappa[j--] >> 24) & 0xff]; if (j < 0) j = N - 1;
+         inter[i] ^= T1[(kappa[j--] >> 16) & 0xff]; if (j < 0) j = N - 1;
+         inter[i] ^= T2[(kappa[j--] >>  8) & 0xff]; if (j < 0) j = N - 1;
+         inter[i] ^= T3[(kappa[j  ]      ) & 0xff];
+      }
+      kappa[0] = inter[0] ^ rc[r];
+      for (i = 1; i < N; i++) {
+         kappa[i] = inter[i];
+      }
+   }
+
+   /*
+    * generate inverse key schedule: K'^0 = K^R, K'^R = K^0, K'^r = theta(K^{R-r}):
+    */
+   for (i = 0; i < 4; i++) {
+      skey->anubis.roundKeyDec[0][i] = skey->anubis.roundKeyEnc[R][i];
+      skey->anubis.roundKeyDec[R][i] = skey->anubis.roundKeyEnc[0][i];
+   }
+   for (r = 1; r < R; r++) {
+      for (i = 0; i < 4; i++) {
+         v = skey->anubis.roundKeyEnc[R - r][i];
+         skey->anubis.roundKeyDec[r][i] =
+            T0[T4[(v >> 24) & 0xff] & 0xff] ^
+            T1[T4[(v >> 16) & 0xff] & 0xff] ^
+            T2[T4[(v >>  8) & 0xff] & 0xff] ^
+            T3[T4[(v      ) & 0xff] & 0xff];
+      }
+   }
+
+   return CRYPT_OK;
+}
+
+#ifdef LTC_CLEAN_STACK
+int  anubis_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey)
+{
+  int err;
+  err = _anubis_setup(key, keylen, num_rounds, skey);
+  burn_stack(sizeof(int) * 5 + sizeof(ulong32) * (MAX_N + MAX_N + 5));
+  return err;
+}
+#endif
+
+
+static void anubis_crypt(const unsigned char *plaintext, unsigned char *ciphertext,
+                         ulong32 roundKey[18 + 1][4], int R) {
+   int i, pos, r;
+   ulong32 state[4];
+   ulong32 inter[4];
+
+    /*
+    * map plaintext block to cipher state (mu)
+    * and add initial round key (sigma[K^0]):
+    */
+    for (i = 0, pos = 0; i < 4; i++, pos += 4) {
+      state[i] =
+         (((ulong32)plaintext[pos    ]) << 24) ^
+         (((ulong32)plaintext[pos + 1]) << 16) ^
+         (((ulong32)plaintext[pos + 2]) <<  8) ^
+         (((ulong32)plaintext[pos + 3])      ) ^
+         roundKey[0][i];
+    }
+
+    /*
+     * R - 1 full rounds:
+     */
+    for (r = 1; r < R; r++) {
+      inter[0] =
+         T0[(state[0] >> 24) & 0xff] ^
+         T1[(state[1] >> 24) & 0xff] ^
+         T2[(state[2] >> 24) & 0xff] ^
+         T3[(state[3] >> 24) & 0xff] ^
+         roundKey[r][0];
+      inter[1] =
+         T0[(state[0] >> 16) & 0xff] ^
+         T1[(state[1] >> 16) & 0xff] ^
+         T2[(state[2] >> 16) & 0xff] ^
+         T3[(state[3] >> 16) & 0xff] ^
+         roundKey[r][1];
+      inter[2] =
+         T0[(state[0] >>  8) & 0xff] ^
+         T1[(state[1] >>  8) & 0xff] ^
+         T2[(state[2] >>  8) & 0xff] ^
+         T3[(state[3] >>  8) & 0xff] ^
+         roundKey[r][2];
+      inter[3] =
+         T0[(state[0]      ) & 0xff] ^
+         T1[(state[1]      ) & 0xff] ^
+         T2[(state[2]      ) & 0xff] ^
+         T3[(state[3]      ) & 0xff] ^
+         roundKey[r][3];
+      state[0] = inter[0];
+      state[1] = inter[1];
+      state[2] = inter[2];
+      state[3] = inter[3];
+    }
+
+    /*
+    * last round:
+    */
+   inter[0] =
+      (T0[(state[0] >> 24) & 0xff] & 0xff000000U) ^
+      (T1[(state[1] >> 24) & 0xff] & 0x00ff0000U) ^
+      (T2[(state[2] >> 24) & 0xff] & 0x0000ff00U) ^
+      (T3[(state[3] >> 24) & 0xff] & 0x000000ffU) ^
+      roundKey[R][0];
+   inter[1] =
+      (T0[(state[0] >> 16) & 0xff] & 0xff000000U) ^
+      (T1[(state[1] >> 16) & 0xff] & 0x00ff0000U) ^
+      (T2[(state[2] >> 16) & 0xff] & 0x0000ff00U) ^
+      (T3[(state[3] >> 16) & 0xff] & 0x000000ffU) ^
+      roundKey[R][1];
+   inter[2] =
+      (T0[(state[0] >>  8) & 0xff] & 0xff000000U) ^
+      (T1[(state[1] >>  8) & 0xff] & 0x00ff0000U) ^
+      (T2[(state[2] >>  8) & 0xff] & 0x0000ff00U) ^
+      (T3[(state[3] >>  8) & 0xff] & 0x000000ffU) ^
+      roundKey[R][2];
+   inter[3] =
+      (T0[(state[0]      ) & 0xff] & 0xff000000U) ^
+      (T1[(state[1]      ) & 0xff] & 0x00ff0000U) ^
+      (T2[(state[2]      ) & 0xff] & 0x0000ff00U) ^
+      (T3[(state[3]      ) & 0xff] & 0x000000ffU) ^
+      roundKey[R][3];
+
+   /*
+    * map cipher state to ciphertext block (mu^{-1}):
+    */
+    for (i = 0, pos = 0; i < 4; i++, pos += 4) {
+        ulong32 w = inter[i];
+        ciphertext[pos    ] = (unsigned char)(w >> 24);
+        ciphertext[pos + 1] = (unsigned char)(w >> 16);
+        ciphertext[pos + 2] = (unsigned char)(w >>  8);
+        ciphertext[pos + 3] = (unsigned char)(w      );
+    }
+}
+
+/**
+  Encrypts a block of text with Anubis
+  @param pt The input plaintext (16 bytes)
+  @param ct The output ciphertext (16 bytes)
+  @param skey The key as scheduled
+  @return CRYPT_OK if successful
+*/
+int anubis_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey)
+{
+   LTC_ARGCHK(pt   != NULL);
+   LTC_ARGCHK(ct   != NULL);
+   LTC_ARGCHK(skey != NULL);
+   anubis_crypt(pt, ct, skey->anubis.roundKeyEnc, skey->anubis.R);
+   return CRYPT_OK;
+}
+
+/**
+  Decrypts a block of text with Anubis
+  @param ct The input ciphertext (16 bytes)
+  @param pt The output plaintext (16 bytes)
+  @param skey The key as scheduled
+  @return CRYPT_OK if successful
+*/
+int anubis_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey)
+{
+   LTC_ARGCHK(pt   != NULL);
+   LTC_ARGCHK(ct   != NULL);
+   LTC_ARGCHK(skey != NULL);
+   anubis_crypt(ct, pt, skey->anubis.roundKeyDec, skey->anubis.R);
+   return CRYPT_OK;
+}
+
+/**
+  Performs a self-test of the Anubis block cipher
+  @return CRYPT_OK if functional, CRYPT_NOP if self-test has been disabled
+*/
+int anubis_test(void)
+{
+#if !defined(LTC_TEST)
+  return CRYPT_NOP;
+#else
+  static const struct test {
+     int keylen;
+     unsigned char pt[16], ct[16], key[40];
+  } tests[] = {
+#ifndef LTC_ANUBIS_TWEAK
+  /**** ORIGINAL LTC_ANUBIS ****/
+  /* 128 bit keys */
+{
+   16,
+   { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+   { 0xF0, 0x68, 0x60, 0xFC, 0x67, 0x30, 0xE8, 0x18,
+     0xF1, 0x32, 0xC7, 0x8A, 0xF4, 0x13, 0x2A, 0xFE },
+   { 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
+}, {
+   16,
+   { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+   { 0xA8, 0x66, 0x84, 0x80, 0x07, 0x74, 0x5C, 0x89,
+     0xFC, 0x5E, 0xB5, 0xBA, 0xD4, 0xFE, 0x32, 0x6D },
+   { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }
+},
+
+   /* 160-bit keys */
+{
+   20,
+   { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+   { 0xBD, 0x5E, 0x32, 0xBE, 0x51, 0x67, 0xA8, 0xE2,
+     0x72, 0xD7, 0x95, 0x0F, 0x83, 0xC6, 0x8C, 0x31 },
+   { 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00 }
+}, {
+   20,
+   { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+   { 0x4C, 0x1F, 0x86, 0x2E, 0x11, 0xEB, 0xCE, 0xEB,
+     0xFE, 0xB9, 0x73, 0xC9, 0xDF, 0xEF, 0x7A, 0xDB },
+   { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x01 }
+},
+
+  /* 192-bit keys */
+{
+   24,
+   { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+   { 0x17, 0xAC, 0x57, 0x44, 0x9D, 0x59, 0x61, 0x66,
+     0xD0, 0xC7, 0x9E, 0x04, 0x7C, 0xC7, 0x58, 0xF0 },
+   { 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
+}, {
+   24,
+   { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+   { 0x71, 0x52, 0xB4, 0xEB, 0x1D, 0xAA, 0x36, 0xFD,
+     0x57, 0x14, 0x5F, 0x57, 0x04, 0x9F, 0x70, 0x74 },
+   { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }
+},
+
+  /* 224-bit keys */
+{
+   28,
+   { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+   { 0xA2, 0xF0, 0xA6, 0xB9, 0x17, 0x93, 0x2A, 0x3B,
+     0xEF, 0x08, 0xE8, 0x7A, 0x58, 0xD6, 0xF8, 0x53 },
+   { 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 }
+}, {
+   28,
+   { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+   { 0xF0, 0xCA, 0xFC, 0x78, 0x8B, 0x4B, 0x4E, 0x53,
+     0x8B, 0xC4, 0x32, 0x6A, 0xF5, 0xB9, 0x1B, 0x5F },
+   { 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, 0x01 }
+},
+
+  /* 256-bit keys */
+{
+   32,
+   { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+   { 0xE0, 0x86, 0xAC, 0x45, 0x6B, 0x3C, 0xE5, 0x13,
+     0xED, 0xF5, 0xDF, 0xDD, 0xD6, 0x3B, 0x71, 0x93 },
+   { 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 }
+}, {
+   32,
+   { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+   { 0x50, 0x01, 0xB9, 0xF5, 0x21, 0xC1, 0xC1, 0x29,
+     0x00, 0xD5, 0xEC, 0x98, 0x2B, 0x9E, 0xE8, 0x21 },
+   { 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, 0x01 }
+},
+
+  /* 288-bit keys */
+{
+   36,
+   { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+   { 0xE8, 0xF4, 0xAF, 0x2B, 0x21, 0xA0, 0x87, 0x9B,
+     0x41, 0x95, 0xB9, 0x71, 0x75, 0x79, 0x04, 0x7C },
+   { 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 }
+}, {
+   36,
+   { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+   { 0xE6, 0xA6, 0xA5, 0xBC, 0x8B, 0x63, 0x6F, 0xE2,
+     0xBD, 0xA7, 0xA7, 0x53, 0xAB, 0x40, 0x22, 0xE0 },
+   { 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, 0x01 }
+},
+
+  /* 320-bit keys */
+{
+   40,
+   { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+   { 0x17, 0x04, 0xD7, 0x2C, 0xC6, 0x85, 0x76, 0x02,
+     0x4B, 0xCC, 0x39, 0x80, 0xD8, 0x22, 0xEA, 0xA4 },
+   { 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 }
+}, {
+   40,
+   { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+   { 0x7A, 0x41, 0xE6, 0x7D, 0x4F, 0xD8, 0x64, 0xF0,
+     0x44, 0xA8, 0x3C, 0x73, 0x81, 0x7E, 0x53, 0xD8 },
+   { 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, 0x01 }
+}
+#else
+  /**** Tweaked LTC_ANUBIS ****/
+  /* 128 bit keys */
+{
+   16,
+   { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+   { 0xB8, 0x35, 0xBD, 0xC3, 0x34, 0x82, 0x9D, 0x83,
+     0x71, 0xBF, 0xA3, 0x71, 0xE4, 0xB3, 0xC4, 0xFD },
+   { 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
+}, {
+   16,
+   { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+   { 0xE6, 0x14, 0x1E, 0xAF, 0xEB, 0xE0, 0x59, 0x3C,
+     0x48, 0xE1, 0xCD, 0xF2, 0x1B, 0xBA, 0xA1, 0x89 },
+   { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }
+},
+
+   /* 160-bit keys */
+{
+   20,
+   { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+   { 0x97, 0x59, 0x79, 0x4B, 0x5C, 0xA0, 0x70, 0x73,
+     0x24, 0xEF, 0xB3, 0x58, 0x67, 0xCA, 0xD4, 0xB3 },
+   { 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00 }
+}, {
+   20,
+   { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+   { 0xB8, 0x0D, 0xFB, 0x9B, 0xE4, 0xA1, 0x58, 0x87,
+     0xB3, 0x76, 0xD5, 0x02, 0x18, 0x95, 0xC1, 0x2E },
+   { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x01 }
+},
+
+  /* 192-bit keys */
+{
+   24,
+   { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+   { 0x7D, 0x62, 0x3B, 0x52, 0xC7, 0x4C, 0x64, 0xD8,
+     0xEB, 0xC7, 0x2D, 0x57, 0x97, 0x85, 0x43, 0x8F },
+   { 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
+}, {
+   24,
+   { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+   { 0xB1, 0x0A, 0x59, 0xDD, 0x5D, 0x5D, 0x8D, 0x67,
+     0xEC, 0xEE, 0x4A, 0xC4, 0xBE, 0x4F, 0xA8, 0x4F },
+   { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }
+},
+
+  /* 224-bit keys */
+{
+   28,
+   { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+   { 0x68, 0x9E, 0x05, 0x94, 0x6A, 0x94, 0x43, 0x8F,
+     0xE7, 0x8E, 0x37, 0x3D, 0x24, 0x97, 0x92, 0xF5 },
+   { 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 }
+}, {
+   28,
+   { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+   { 0xDD, 0xB7, 0xB0, 0xB4, 0xE9, 0xB4, 0x9B, 0x9C,
+     0x38, 0x20, 0x25, 0x0B, 0x47, 0xC2, 0x1F, 0x89 },
+   { 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, 0x01 }
+},
+
+  /* 256-bit keys */
+{
+   32,
+   { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+   { 0x96, 0x00, 0xF0, 0x76, 0x91, 0x69, 0x29, 0x87,
+     0xF5, 0xE5, 0x97, 0xDB, 0xDB, 0xAF, 0x1B, 0x0A },
+   { 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 }
+}, {
+   32,
+   { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+   { 0x69, 0x9C, 0xAF, 0xDD, 0x94, 0xC7, 0xBC, 0x60,
+     0x44, 0xFE, 0x02, 0x05, 0x8A, 0x6E, 0xEF, 0xBD },
+   { 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, 0x01 }
+},
+
+  /* 288-bit keys */
+{
+   36,
+   { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+   { 0x0F, 0xC7, 0xA2, 0xC0, 0x11, 0x17, 0xAC, 0x43,
+     0x52, 0x5E, 0xDF, 0x6C, 0xF3, 0x96, 0x33, 0x6C },
+   { 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 }
+}, {
+   36,
+   { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+   { 0xAD, 0x08, 0x4F, 0xED, 0x55, 0xA6, 0x94, 0x3E,
+     0x7E, 0x5E, 0xED, 0x05, 0xA1, 0x9D, 0x41, 0xB4 },
+   { 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, 0x01 }
+},
+
+  /* 320-bit keys */
+{
+   40,
+   { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+   { 0xFE, 0xE2, 0x0E, 0x2A, 0x9D, 0xC5, 0x83, 0xBA,
+     0xA3, 0xA6, 0xD6, 0xA6, 0xF2, 0xE8, 0x06, 0xA5 },
+   { 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 }
+}, {
+   40,
+   { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+   { 0x86, 0x3D, 0xCC, 0x4A, 0x60, 0x34, 0x9C, 0x28,
+     0xA7, 0xDA, 0xA4, 0x3B, 0x0A, 0xD7, 0xFD, 0xC7 },
+   { 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, 0x01 }
+}
+#endif
+};
+   int x, y;
+   unsigned char buf[2][16];
+   symmetric_key skey;
+
+   for (x = 0; x < (int)(sizeof(tests)/sizeof(tests[0])); x++) {
+       anubis_setup(tests[x].key, tests[x].keylen, 0, &skey);
+       anubis_ecb_encrypt(tests[x].pt, buf[0], &skey);
+       anubis_ecb_decrypt(buf[0], buf[1], &skey);
+       if (compare_testvector(buf[0], 16, tests[x].ct, 16, "Anubis Encrypt", x) ||
+             compare_testvector(buf[1], 16, tests[x].pt, 16, "Anubis Decrypt", x)) {
+          return CRYPT_FAIL_TESTVECTOR;
+       }
+
+       for (y = 0; y < 1000; y++) anubis_ecb_encrypt(buf[0], buf[0], &skey);
+       for (y = 0; y < 1000; y++) anubis_ecb_decrypt(buf[0], buf[0], &skey);
+       if (compare_testvector(buf[0], 16, tests[x].ct, 16, "Anubis 1000", 1000)) {
+          return CRYPT_FAIL_TESTVECTOR;
+       }
+
+   }
+   return CRYPT_OK;
+#endif
+}
+
+/** Terminate the context
+   @param skey    The scheduled key
+*/
+void anubis_done(symmetric_key *skey)
+{
+  LTC_UNUSED_PARAM(skey);
+}
+
+/**
+  Gets suitable key size
+  @param keysize [in/out] The length of the recommended key (in bytes).  This function will store the suitable size back in this variable.
+  @return CRYPT_OK if the input key size is acceptable.
+*/
+int anubis_keysize(int *keysize)
+{
+   LTC_ARGCHK(keysize != NULL);
+   if (*keysize >= 40) {
+      *keysize = 40;
+   } else if (*keysize >= 36) {
+      *keysize = 36;
+   } else if (*keysize >= 32) {
+      *keysize = 32;
+   } else if (*keysize >= 28) {
+      *keysize = 28;
+   } else if (*keysize >= 24) {
+      *keysize = 24;
+   } else if (*keysize >= 20) {
+      *keysize = 20;
+   } else if (*keysize >= 16) {
+      *keysize = 16;
+   } else {
+      return CRYPT_INVALID_KEYSIZE;
+   }
+   return CRYPT_OK;
+}
+
+#endif
+
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/ciphers/blowfish.c b/libtomcrypt/src/ciphers/blowfish.c
new file mode 100644 (file)
index 0000000..a1945ae
--- /dev/null
@@ -0,0 +1,594 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+/**
+  @file blowfish.c
+  Implementation of the Blowfish block cipher, Tom St Denis
+*/
+#include "tomcrypt.h"
+
+#ifdef LTC_BLOWFISH
+
+const struct ltc_cipher_descriptor blowfish_desc =
+{
+    "blowfish",
+    0,
+    8, 56, 8, 16,
+    &blowfish_setup,
+    &blowfish_ecb_encrypt,
+    &blowfish_ecb_decrypt,
+    &blowfish_test,
+    &blowfish_done,
+    &blowfish_keysize,
+    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
+};
+
+static const ulong32 ORIG_P[16 + 2] = {
+        0x243F6A88UL, 0x85A308D3UL, 0x13198A2EUL, 0x03707344UL,
+        0xA4093822UL, 0x299F31D0UL, 0x082EFA98UL, 0xEC4E6C89UL,
+        0x452821E6UL, 0x38D01377UL, 0xBE5466CFUL, 0x34E90C6CUL,
+        0xC0AC29B7UL, 0xC97C50DDUL, 0x3F84D5B5UL, 0xB5470917UL,
+        0x9216D5D9UL, 0x8979FB1BUL
+};
+
+static const ulong32 ORIG_S[4][256] = {
+    {   0xD1310BA6UL, 0x98DFB5ACUL, 0x2FFD72DBUL, 0xD01ADFB7UL,
+        0xB8E1AFEDUL, 0x6A267E96UL, 0xBA7C9045UL, 0xF12C7F99UL,
+        0x24A19947UL, 0xB3916CF7UL, 0x0801F2E2UL, 0x858EFC16UL,
+        0x636920D8UL, 0x71574E69UL, 0xA458FEA3UL, 0xF4933D7EUL,
+        0x0D95748FUL, 0x728EB658UL, 0x718BCD58UL, 0x82154AEEUL,
+        0x7B54A41DUL, 0xC25A59B5UL, 0x9C30D539UL, 0x2AF26013UL,
+        0xC5D1B023UL, 0x286085F0UL, 0xCA417918UL, 0xB8DB38EFUL,
+        0x8E79DCB0UL, 0x603A180EUL, 0x6C9E0E8BUL, 0xB01E8A3EUL,
+        0xD71577C1UL, 0xBD314B27UL, 0x78AF2FDAUL, 0x55605C60UL,
+        0xE65525F3UL, 0xAA55AB94UL, 0x57489862UL, 0x63E81440UL,
+        0x55CA396AUL, 0x2AAB10B6UL, 0xB4CC5C34UL, 0x1141E8CEUL,
+        0xA15486AFUL, 0x7C72E993UL, 0xB3EE1411UL, 0x636FBC2AUL,
+        0x2BA9C55DUL, 0x741831F6UL, 0xCE5C3E16UL, 0x9B87931EUL,
+        0xAFD6BA33UL, 0x6C24CF5CUL, 0x7A325381UL, 0x28958677UL,
+        0x3B8F4898UL, 0x6B4BB9AFUL, 0xC4BFE81BUL, 0x66282193UL,
+        0x61D809CCUL, 0xFB21A991UL, 0x487CAC60UL, 0x5DEC8032UL,
+        0xEF845D5DUL, 0xE98575B1UL, 0xDC262302UL, 0xEB651B88UL,
+        0x23893E81UL, 0xD396ACC5UL, 0x0F6D6FF3UL, 0x83F44239UL,
+        0x2E0B4482UL, 0xA4842004UL, 0x69C8F04AUL, 0x9E1F9B5EUL,
+        0x21C66842UL, 0xF6E96C9AUL, 0x670C9C61UL, 0xABD388F0UL,
+        0x6A51A0D2UL, 0xD8542F68UL, 0x960FA728UL, 0xAB5133A3UL,
+        0x6EEF0B6CUL, 0x137A3BE4UL, 0xBA3BF050UL, 0x7EFB2A98UL,
+        0xA1F1651DUL, 0x39AF0176UL, 0x66CA593EUL, 0x82430E88UL,
+        0x8CEE8619UL, 0x456F9FB4UL, 0x7D84A5C3UL, 0x3B8B5EBEUL,
+        0xE06F75D8UL, 0x85C12073UL, 0x401A449FUL, 0x56C16AA6UL,
+        0x4ED3AA62UL, 0x363F7706UL, 0x1BFEDF72UL, 0x429B023DUL,
+        0x37D0D724UL, 0xD00A1248UL, 0xDB0FEAD3UL, 0x49F1C09BUL,
+        0x075372C9UL, 0x80991B7BUL, 0x25D479D8UL, 0xF6E8DEF7UL,
+        0xE3FE501AUL, 0xB6794C3BUL, 0x976CE0BDUL, 0x04C006BAUL,
+        0xC1A94FB6UL, 0x409F60C4UL, 0x5E5C9EC2UL, 0x196A2463UL,
+        0x68FB6FAFUL, 0x3E6C53B5UL, 0x1339B2EBUL, 0x3B52EC6FUL,
+        0x6DFC511FUL, 0x9B30952CUL, 0xCC814544UL, 0xAF5EBD09UL,
+        0xBEE3D004UL, 0xDE334AFDUL, 0x660F2807UL, 0x192E4BB3UL,
+        0xC0CBA857UL, 0x45C8740FUL, 0xD20B5F39UL, 0xB9D3FBDBUL,
+        0x5579C0BDUL, 0x1A60320AUL, 0xD6A100C6UL, 0x402C7279UL,
+        0x679F25FEUL, 0xFB1FA3CCUL, 0x8EA5E9F8UL, 0xDB3222F8UL,
+        0x3C7516DFUL, 0xFD616B15UL, 0x2F501EC8UL, 0xAD0552ABUL,
+        0x323DB5FAUL, 0xFD238760UL, 0x53317B48UL, 0x3E00DF82UL,
+        0x9E5C57BBUL, 0xCA6F8CA0UL, 0x1A87562EUL, 0xDF1769DBUL,
+        0xD542A8F6UL, 0x287EFFC3UL, 0xAC6732C6UL, 0x8C4F5573UL,
+        0x695B27B0UL, 0xBBCA58C8UL, 0xE1FFA35DUL, 0xB8F011A0UL,
+        0x10FA3D98UL, 0xFD2183B8UL, 0x4AFCB56CUL, 0x2DD1D35BUL,
+        0x9A53E479UL, 0xB6F84565UL, 0xD28E49BCUL, 0x4BFB9790UL,
+        0xE1DDF2DAUL, 0xA4CB7E33UL, 0x62FB1341UL, 0xCEE4C6E8UL,
+        0xEF20CADAUL, 0x36774C01UL, 0xD07E9EFEUL, 0x2BF11FB4UL,
+        0x95DBDA4DUL, 0xAE909198UL, 0xEAAD8E71UL, 0x6B93D5A0UL,
+        0xD08ED1D0UL, 0xAFC725E0UL, 0x8E3C5B2FUL, 0x8E7594B7UL,
+        0x8FF6E2FBUL, 0xF2122B64UL, 0x8888B812UL, 0x900DF01CUL,
+        0x4FAD5EA0UL, 0x688FC31CUL, 0xD1CFF191UL, 0xB3A8C1ADUL,
+        0x2F2F2218UL, 0xBE0E1777UL, 0xEA752DFEUL, 0x8B021FA1UL,
+        0xE5A0CC0FUL, 0xB56F74E8UL, 0x18ACF3D6UL, 0xCE89E299UL,
+        0xB4A84FE0UL, 0xFD13E0B7UL, 0x7CC43B81UL, 0xD2ADA8D9UL,
+        0x165FA266UL, 0x80957705UL, 0x93CC7314UL, 0x211A1477UL,
+        0xE6AD2065UL, 0x77B5FA86UL, 0xC75442F5UL, 0xFB9D35CFUL,
+        0xEBCDAF0CUL, 0x7B3E89A0UL, 0xD6411BD3UL, 0xAE1E7E49UL,
+        0x00250E2DUL, 0x2071B35EUL, 0x226800BBUL, 0x57B8E0AFUL,
+        0x2464369BUL, 0xF009B91EUL, 0x5563911DUL, 0x59DFA6AAUL,
+        0x78C14389UL, 0xD95A537FUL, 0x207D5BA2UL, 0x02E5B9C5UL,
+        0x83260376UL, 0x6295CFA9UL, 0x11C81968UL, 0x4E734A41UL,
+        0xB3472DCAUL, 0x7B14A94AUL, 0x1B510052UL, 0x9A532915UL,
+        0xD60F573FUL, 0xBC9BC6E4UL, 0x2B60A476UL, 0x81E67400UL,
+        0x08BA6FB5UL, 0x571BE91FUL, 0xF296EC6BUL, 0x2A0DD915UL,
+        0xB6636521UL, 0xE7B9F9B6UL, 0xFF34052EUL, 0xC5855664UL,
+        0x53B02D5DUL, 0xA99F8FA1UL, 0x08BA4799UL, 0x6E85076AUL   },
+    {   0x4B7A70E9UL, 0xB5B32944UL, 0xDB75092EUL, 0xC4192623UL,
+        0xAD6EA6B0UL, 0x49A7DF7DUL, 0x9CEE60B8UL, 0x8FEDB266UL,
+        0xECAA8C71UL, 0x699A17FFUL, 0x5664526CUL, 0xC2B19EE1UL,
+        0x193602A5UL, 0x75094C29UL, 0xA0591340UL, 0xE4183A3EUL,
+        0x3F54989AUL, 0x5B429D65UL, 0x6B8FE4D6UL, 0x99F73FD6UL,
+        0xA1D29C07UL, 0xEFE830F5UL, 0x4D2D38E6UL, 0xF0255DC1UL,
+        0x4CDD2086UL, 0x8470EB26UL, 0x6382E9C6UL, 0x021ECC5EUL,
+        0x09686B3FUL, 0x3EBAEFC9UL, 0x3C971814UL, 0x6B6A70A1UL,
+        0x687F3584UL, 0x52A0E286UL, 0xB79C5305UL, 0xAA500737UL,
+        0x3E07841CUL, 0x7FDEAE5CUL, 0x8E7D44ECUL, 0x5716F2B8UL,
+        0xB03ADA37UL, 0xF0500C0DUL, 0xF01C1F04UL, 0x0200B3FFUL,
+        0xAE0CF51AUL, 0x3CB574B2UL, 0x25837A58UL, 0xDC0921BDUL,
+        0xD19113F9UL, 0x7CA92FF6UL, 0x94324773UL, 0x22F54701UL,
+        0x3AE5E581UL, 0x37C2DADCUL, 0xC8B57634UL, 0x9AF3DDA7UL,
+        0xA9446146UL, 0x0FD0030EUL, 0xECC8C73EUL, 0xA4751E41UL,
+        0xE238CD99UL, 0x3BEA0E2FUL, 0x3280BBA1UL, 0x183EB331UL,
+        0x4E548B38UL, 0x4F6DB908UL, 0x6F420D03UL, 0xF60A04BFUL,
+        0x2CB81290UL, 0x24977C79UL, 0x5679B072UL, 0xBCAF89AFUL,
+        0xDE9A771FUL, 0xD9930810UL, 0xB38BAE12UL, 0xDCCF3F2EUL,
+        0x5512721FUL, 0x2E6B7124UL, 0x501ADDE6UL, 0x9F84CD87UL,
+        0x7A584718UL, 0x7408DA17UL, 0xBC9F9ABCUL, 0xE94B7D8CUL,
+        0xEC7AEC3AUL, 0xDB851DFAUL, 0x63094366UL, 0xC464C3D2UL,
+        0xEF1C1847UL, 0x3215D908UL, 0xDD433B37UL, 0x24C2BA16UL,
+        0x12A14D43UL, 0x2A65C451UL, 0x50940002UL, 0x133AE4DDUL,
+        0x71DFF89EUL, 0x10314E55UL, 0x81AC77D6UL, 0x5F11199BUL,
+        0x043556F1UL, 0xD7A3C76BUL, 0x3C11183BUL, 0x5924A509UL,
+        0xF28FE6EDUL, 0x97F1FBFAUL, 0x9EBABF2CUL, 0x1E153C6EUL,
+        0x86E34570UL, 0xEAE96FB1UL, 0x860E5E0AUL, 0x5A3E2AB3UL,
+        0x771FE71CUL, 0x4E3D06FAUL, 0x2965DCB9UL, 0x99E71D0FUL,
+        0x803E89D6UL, 0x5266C825UL, 0x2E4CC978UL, 0x9C10B36AUL,
+        0xC6150EBAUL, 0x94E2EA78UL, 0xA5FC3C53UL, 0x1E0A2DF4UL,
+        0xF2F74EA7UL, 0x361D2B3DUL, 0x1939260FUL, 0x19C27960UL,
+        0x5223A708UL, 0xF71312B6UL, 0xEBADFE6EUL, 0xEAC31F66UL,
+        0xE3BC4595UL, 0xA67BC883UL, 0xB17F37D1UL, 0x018CFF28UL,
+        0xC332DDEFUL, 0xBE6C5AA5UL, 0x65582185UL, 0x68AB9802UL,
+        0xEECEA50FUL, 0xDB2F953BUL, 0x2AEF7DADUL, 0x5B6E2F84UL,
+        0x1521B628UL, 0x29076170UL, 0xECDD4775UL, 0x619F1510UL,
+        0x13CCA830UL, 0xEB61BD96UL, 0x0334FE1EUL, 0xAA0363CFUL,
+        0xB5735C90UL, 0x4C70A239UL, 0xD59E9E0BUL, 0xCBAADE14UL,
+        0xEECC86BCUL, 0x60622CA7UL, 0x9CAB5CABUL, 0xB2F3846EUL,
+        0x648B1EAFUL, 0x19BDF0CAUL, 0xA02369B9UL, 0x655ABB50UL,
+        0x40685A32UL, 0x3C2AB4B3UL, 0x319EE9D5UL, 0xC021B8F7UL,
+        0x9B540B19UL, 0x875FA099UL, 0x95F7997EUL, 0x623D7DA8UL,
+        0xF837889AUL, 0x97E32D77UL, 0x11ED935FUL, 0x16681281UL,
+        0x0E358829UL, 0xC7E61FD6UL, 0x96DEDFA1UL, 0x7858BA99UL,
+        0x57F584A5UL, 0x1B227263UL, 0x9B83C3FFUL, 0x1AC24696UL,
+        0xCDB30AEBUL, 0x532E3054UL, 0x8FD948E4UL, 0x6DBC3128UL,
+        0x58EBF2EFUL, 0x34C6FFEAUL, 0xFE28ED61UL, 0xEE7C3C73UL,
+        0x5D4A14D9UL, 0xE864B7E3UL, 0x42105D14UL, 0x203E13E0UL,
+        0x45EEE2B6UL, 0xA3AAABEAUL, 0xDB6C4F15UL, 0xFACB4FD0UL,
+        0xC742F442UL, 0xEF6ABBB5UL, 0x654F3B1DUL, 0x41CD2105UL,
+        0xD81E799EUL, 0x86854DC7UL, 0xE44B476AUL, 0x3D816250UL,
+        0xCF62A1F2UL, 0x5B8D2646UL, 0xFC8883A0UL, 0xC1C7B6A3UL,
+        0x7F1524C3UL, 0x69CB7492UL, 0x47848A0BUL, 0x5692B285UL,
+        0x095BBF00UL, 0xAD19489DUL, 0x1462B174UL, 0x23820E00UL,
+        0x58428D2AUL, 0x0C55F5EAUL, 0x1DADF43EUL, 0x233F7061UL,
+        0x3372F092UL, 0x8D937E41UL, 0xD65FECF1UL, 0x6C223BDBUL,
+        0x7CDE3759UL, 0xCBEE7460UL, 0x4085F2A7UL, 0xCE77326EUL,
+        0xA6078084UL, 0x19F8509EUL, 0xE8EFD855UL, 0x61D99735UL,
+        0xA969A7AAUL, 0xC50C06C2UL, 0x5A04ABFCUL, 0x800BCADCUL,
+        0x9E447A2EUL, 0xC3453484UL, 0xFDD56705UL, 0x0E1E9EC9UL,
+        0xDB73DBD3UL, 0x105588CDUL, 0x675FDA79UL, 0xE3674340UL,
+        0xC5C43465UL, 0x713E38D8UL, 0x3D28F89EUL, 0xF16DFF20UL,
+        0x153E21E7UL, 0x8FB03D4AUL, 0xE6E39F2BUL, 0xDB83ADF7UL   },
+    {   0xE93D5A68UL, 0x948140F7UL, 0xF64C261CUL, 0x94692934UL,
+        0x411520F7UL, 0x7602D4F7UL, 0xBCF46B2EUL, 0xD4A20068UL,
+        0xD4082471UL, 0x3320F46AUL, 0x43B7D4B7UL, 0x500061AFUL,
+        0x1E39F62EUL, 0x97244546UL, 0x14214F74UL, 0xBF8B8840UL,
+        0x4D95FC1DUL, 0x96B591AFUL, 0x70F4DDD3UL, 0x66A02F45UL,
+        0xBFBC09ECUL, 0x03BD9785UL, 0x7FAC6DD0UL, 0x31CB8504UL,
+        0x96EB27B3UL, 0x55FD3941UL, 0xDA2547E6UL, 0xABCA0A9AUL,
+        0x28507825UL, 0x530429F4UL, 0x0A2C86DAUL, 0xE9B66DFBUL,
+        0x68DC1462UL, 0xD7486900UL, 0x680EC0A4UL, 0x27A18DEEUL,
+        0x4F3FFEA2UL, 0xE887AD8CUL, 0xB58CE006UL, 0x7AF4D6B6UL,
+        0xAACE1E7CUL, 0xD3375FECUL, 0xCE78A399UL, 0x406B2A42UL,
+        0x20FE9E35UL, 0xD9F385B9UL, 0xEE39D7ABUL, 0x3B124E8BUL,
+        0x1DC9FAF7UL, 0x4B6D1856UL, 0x26A36631UL, 0xEAE397B2UL,
+        0x3A6EFA74UL, 0xDD5B4332UL, 0x6841E7F7UL, 0xCA7820FBUL,
+        0xFB0AF54EUL, 0xD8FEB397UL, 0x454056ACUL, 0xBA489527UL,
+        0x55533A3AUL, 0x20838D87UL, 0xFE6BA9B7UL, 0xD096954BUL,
+        0x55A867BCUL, 0xA1159A58UL, 0xCCA92963UL, 0x99E1DB33UL,
+        0xA62A4A56UL, 0x3F3125F9UL, 0x5EF47E1CUL, 0x9029317CUL,
+        0xFDF8E802UL, 0x04272F70UL, 0x80BB155CUL, 0x05282CE3UL,
+        0x95C11548UL, 0xE4C66D22UL, 0x48C1133FUL, 0xC70F86DCUL,
+        0x07F9C9EEUL, 0x41041F0FUL, 0x404779A4UL, 0x5D886E17UL,
+        0x325F51EBUL, 0xD59BC0D1UL, 0xF2BCC18FUL, 0x41113564UL,
+        0x257B7834UL, 0x602A9C60UL, 0xDFF8E8A3UL, 0x1F636C1BUL,
+        0x0E12B4C2UL, 0x02E1329EUL, 0xAF664FD1UL, 0xCAD18115UL,
+        0x6B2395E0UL, 0x333E92E1UL, 0x3B240B62UL, 0xEEBEB922UL,
+        0x85B2A20EUL, 0xE6BA0D99UL, 0xDE720C8CUL, 0x2DA2F728UL,
+        0xD0127845UL, 0x95B794FDUL, 0x647D0862UL, 0xE7CCF5F0UL,
+        0x5449A36FUL, 0x877D48FAUL, 0xC39DFD27UL, 0xF33E8D1EUL,
+        0x0A476341UL, 0x992EFF74UL, 0x3A6F6EABUL, 0xF4F8FD37UL,
+        0xA812DC60UL, 0xA1EBDDF8UL, 0x991BE14CUL, 0xDB6E6B0DUL,
+        0xC67B5510UL, 0x6D672C37UL, 0x2765D43BUL, 0xDCD0E804UL,
+        0xF1290DC7UL, 0xCC00FFA3UL, 0xB5390F92UL, 0x690FED0BUL,
+        0x667B9FFBUL, 0xCEDB7D9CUL, 0xA091CF0BUL, 0xD9155EA3UL,
+        0xBB132F88UL, 0x515BAD24UL, 0x7B9479BFUL, 0x763BD6EBUL,
+        0x37392EB3UL, 0xCC115979UL, 0x8026E297UL, 0xF42E312DUL,
+        0x6842ADA7UL, 0xC66A2B3BUL, 0x12754CCCUL, 0x782EF11CUL,
+        0x6A124237UL, 0xB79251E7UL, 0x06A1BBE6UL, 0x4BFB6350UL,
+        0x1A6B1018UL, 0x11CAEDFAUL, 0x3D25BDD8UL, 0xE2E1C3C9UL,
+        0x44421659UL, 0x0A121386UL, 0xD90CEC6EUL, 0xD5ABEA2AUL,
+        0x64AF674EUL, 0xDA86A85FUL, 0xBEBFE988UL, 0x64E4C3FEUL,
+        0x9DBC8057UL, 0xF0F7C086UL, 0x60787BF8UL, 0x6003604DUL,
+        0xD1FD8346UL, 0xF6381FB0UL, 0x7745AE04UL, 0xD736FCCCUL,
+        0x83426B33UL, 0xF01EAB71UL, 0xB0804187UL, 0x3C005E5FUL,
+        0x77A057BEUL, 0xBDE8AE24UL, 0x55464299UL, 0xBF582E61UL,
+        0x4E58F48FUL, 0xF2DDFDA2UL, 0xF474EF38UL, 0x8789BDC2UL,
+        0x5366F9C3UL, 0xC8B38E74UL, 0xB475F255UL, 0x46FCD9B9UL,
+        0x7AEB2661UL, 0x8B1DDF84UL, 0x846A0E79UL, 0x915F95E2UL,
+        0x466E598EUL, 0x20B45770UL, 0x8CD55591UL, 0xC902DE4CUL,
+        0xB90BACE1UL, 0xBB8205D0UL, 0x11A86248UL, 0x7574A99EUL,
+        0xB77F19B6UL, 0xE0A9DC09UL, 0x662D09A1UL, 0xC4324633UL,
+        0xE85A1F02UL, 0x09F0BE8CUL, 0x4A99A025UL, 0x1D6EFE10UL,
+        0x1AB93D1DUL, 0x0BA5A4DFUL, 0xA186F20FUL, 0x2868F169UL,
+        0xDCB7DA83UL, 0x573906FEUL, 0xA1E2CE9BUL, 0x4FCD7F52UL,
+        0x50115E01UL, 0xA70683FAUL, 0xA002B5C4UL, 0x0DE6D027UL,
+        0x9AF88C27UL, 0x773F8641UL, 0xC3604C06UL, 0x61A806B5UL,
+        0xF0177A28UL, 0xC0F586E0UL, 0x006058AAUL, 0x30DC7D62UL,
+        0x11E69ED7UL, 0x2338EA63UL, 0x53C2DD94UL, 0xC2C21634UL,
+        0xBBCBEE56UL, 0x90BCB6DEUL, 0xEBFC7DA1UL, 0xCE591D76UL,
+        0x6F05E409UL, 0x4B7C0188UL, 0x39720A3DUL, 0x7C927C24UL,
+        0x86E3725FUL, 0x724D9DB9UL, 0x1AC15BB4UL, 0xD39EB8FCUL,
+        0xED545578UL, 0x08FCA5B5UL, 0xD83D7CD3UL, 0x4DAD0FC4UL,
+        0x1E50EF5EUL, 0xB161E6F8UL, 0xA28514D9UL, 0x6C51133CUL,
+        0x6FD5C7E7UL, 0x56E14EC4UL, 0x362ABFCEUL, 0xDDC6C837UL,
+        0xD79A3234UL, 0x92638212UL, 0x670EFA8EUL, 0x406000E0UL  },
+    {   0x3A39CE37UL, 0xD3FAF5CFUL, 0xABC27737UL, 0x5AC52D1BUL,
+        0x5CB0679EUL, 0x4FA33742UL, 0xD3822740UL, 0x99BC9BBEUL,
+        0xD5118E9DUL, 0xBF0F7315UL, 0xD62D1C7EUL, 0xC700C47BUL,
+        0xB78C1B6BUL, 0x21A19045UL, 0xB26EB1BEUL, 0x6A366EB4UL,
+        0x5748AB2FUL, 0xBC946E79UL, 0xC6A376D2UL, 0x6549C2C8UL,
+        0x530FF8EEUL, 0x468DDE7DUL, 0xD5730A1DUL, 0x4CD04DC6UL,
+        0x2939BBDBUL, 0xA9BA4650UL, 0xAC9526E8UL, 0xBE5EE304UL,
+        0xA1FAD5F0UL, 0x6A2D519AUL, 0x63EF8CE2UL, 0x9A86EE22UL,
+        0xC089C2B8UL, 0x43242EF6UL, 0xA51E03AAUL, 0x9CF2D0A4UL,
+        0x83C061BAUL, 0x9BE96A4DUL, 0x8FE51550UL, 0xBA645BD6UL,
+        0x2826A2F9UL, 0xA73A3AE1UL, 0x4BA99586UL, 0xEF5562E9UL,
+        0xC72FEFD3UL, 0xF752F7DAUL, 0x3F046F69UL, 0x77FA0A59UL,
+        0x80E4A915UL, 0x87B08601UL, 0x9B09E6ADUL, 0x3B3EE593UL,
+        0xE990FD5AUL, 0x9E34D797UL, 0x2CF0B7D9UL, 0x022B8B51UL,
+        0x96D5AC3AUL, 0x017DA67DUL, 0xD1CF3ED6UL, 0x7C7D2D28UL,
+        0x1F9F25CFUL, 0xADF2B89BUL, 0x5AD6B472UL, 0x5A88F54CUL,
+        0xE029AC71UL, 0xE019A5E6UL, 0x47B0ACFDUL, 0xED93FA9BUL,
+        0xE8D3C48DUL, 0x283B57CCUL, 0xF8D56629UL, 0x79132E28UL,
+        0x785F0191UL, 0xED756055UL, 0xF7960E44UL, 0xE3D35E8CUL,
+        0x15056DD4UL, 0x88F46DBAUL, 0x03A16125UL, 0x0564F0BDUL,
+        0xC3EB9E15UL, 0x3C9057A2UL, 0x97271AECUL, 0xA93A072AUL,
+        0x1B3F6D9BUL, 0x1E6321F5UL, 0xF59C66FBUL, 0x26DCF319UL,
+        0x7533D928UL, 0xB155FDF5UL, 0x03563482UL, 0x8ABA3CBBUL,
+        0x28517711UL, 0xC20AD9F8UL, 0xABCC5167UL, 0xCCAD925FUL,
+        0x4DE81751UL, 0x3830DC8EUL, 0x379D5862UL, 0x9320F991UL,
+        0xEA7A90C2UL, 0xFB3E7BCEUL, 0x5121CE64UL, 0x774FBE32UL,
+        0xA8B6E37EUL, 0xC3293D46UL, 0x48DE5369UL, 0x6413E680UL,
+        0xA2AE0810UL, 0xDD6DB224UL, 0x69852DFDUL, 0x09072166UL,
+        0xB39A460AUL, 0x6445C0DDUL, 0x586CDECFUL, 0x1C20C8AEUL,
+        0x5BBEF7DDUL, 0x1B588D40UL, 0xCCD2017FUL, 0x6BB4E3BBUL,
+        0xDDA26A7EUL, 0x3A59FF45UL, 0x3E350A44UL, 0xBCB4CDD5UL,
+        0x72EACEA8UL, 0xFA6484BBUL, 0x8D6612AEUL, 0xBF3C6F47UL,
+        0xD29BE463UL, 0x542F5D9EUL, 0xAEC2771BUL, 0xF64E6370UL,
+        0x740E0D8DUL, 0xE75B1357UL, 0xF8721671UL, 0xAF537D5DUL,
+        0x4040CB08UL, 0x4EB4E2CCUL, 0x34D2466AUL, 0x0115AF84UL,
+        0xE1B00428UL, 0x95983A1DUL, 0x06B89FB4UL, 0xCE6EA048UL,
+        0x6F3F3B82UL, 0x3520AB82UL, 0x011A1D4BUL, 0x277227F8UL,
+        0x611560B1UL, 0xE7933FDCUL, 0xBB3A792BUL, 0x344525BDUL,
+        0xA08839E1UL, 0x51CE794BUL, 0x2F32C9B7UL, 0xA01FBAC9UL,
+        0xE01CC87EUL, 0xBCC7D1F6UL, 0xCF0111C3UL, 0xA1E8AAC7UL,
+        0x1A908749UL, 0xD44FBD9AUL, 0xD0DADECBUL, 0xD50ADA38UL,
+        0x0339C32AUL, 0xC6913667UL, 0x8DF9317CUL, 0xE0B12B4FUL,
+        0xF79E59B7UL, 0x43F5BB3AUL, 0xF2D519FFUL, 0x27D9459CUL,
+        0xBF97222CUL, 0x15E6FC2AUL, 0x0F91FC71UL, 0x9B941525UL,
+        0xFAE59361UL, 0xCEB69CEBUL, 0xC2A86459UL, 0x12BAA8D1UL,
+        0xB6C1075EUL, 0xE3056A0CUL, 0x10D25065UL, 0xCB03A442UL,
+        0xE0EC6E0EUL, 0x1698DB3BUL, 0x4C98A0BEUL, 0x3278E964UL,
+        0x9F1F9532UL, 0xE0D392DFUL, 0xD3A0342BUL, 0x8971F21EUL,
+        0x1B0A7441UL, 0x4BA3348CUL, 0xC5BE7120UL, 0xC37632D8UL,
+        0xDF359F8DUL, 0x9B992F2EUL, 0xE60B6F47UL, 0x0FE3F11DUL,
+        0xE54CDA54UL, 0x1EDAD891UL, 0xCE6279CFUL, 0xCD3E7E6FUL,
+        0x1618B166UL, 0xFD2C1D05UL, 0x848FD2C5UL, 0xF6FB2299UL,
+        0xF523F357UL, 0xA6327623UL, 0x93A83531UL, 0x56CCCD02UL,
+        0xACF08162UL, 0x5A75EBB5UL, 0x6E163697UL, 0x88D273CCUL,
+        0xDE966292UL, 0x81B949D0UL, 0x4C50901BUL, 0x71C65614UL,
+        0xE6C6C7BDUL, 0x327A140AUL, 0x45E1D006UL, 0xC3F27B9AUL,
+        0xC9AA53FDUL, 0x62A80F00UL, 0xBB25BFE2UL, 0x35BDD2F6UL,
+        0x71126905UL, 0xB2040222UL, 0xB6CBCF7CUL, 0xCD769C2BUL,
+        0x53113EC0UL, 0x1640E3D3UL, 0x38ABBD60UL, 0x2547ADF0UL,
+        0xBA38209CUL, 0xF746CE76UL, 0x77AFA1C5UL, 0x20756060UL,
+        0x85CBFE4EUL, 0x8AE88DD8UL, 0x7AAAF9B0UL, 0x4CF9AA7EUL,
+        0x1948C25CUL, 0x02FB8A8CUL, 0x01C36AE4UL, 0xD6EBE1F9UL,
+        0x90D4F869UL, 0xA65CDEA0UL, 0x3F09252DUL, 0xC208E69FUL,
+        0xB74E6132UL, 0xCE77E25BUL, 0x578FDFE3UL, 0x3AC372E6UL  }
+};
+
+ /**
+    Initialize the Blowfish block cipher
+    @param key The symmetric key you wish to pass
+    @param keylen The key length in bytes
+    @param num_rounds The number of rounds desired (0 for default)
+    @param skey The key in as scheduled by this function.
+    @return CRYPT_OK if successful
+ */
+int blowfish_setup(const unsigned char *key, int keylen, int num_rounds,
+                   symmetric_key *skey)
+{
+   ulong32 x, y, z, A;
+   unsigned char B[8];
+
+   LTC_ARGCHK(key != NULL);
+   LTC_ARGCHK(skey != NULL);
+
+   /* check key length */
+   if (keylen < 8 || keylen > 56) {
+      return CRYPT_INVALID_KEYSIZE;
+   }
+
+   /* check rounds */
+   if (num_rounds != 0 && num_rounds != 16) {
+      return CRYPT_INVALID_ROUNDS;
+   }
+
+   /* load in key bytes (Supplied by David Hopwood) */
+   for (x = y = 0; x < 18; x++) {
+       A = 0;
+       for (z = 0; z < 4; z++) {
+           A = (A << 8) | ((ulong32)key[y++] & 255);
+           if (y == (ulong32)keylen) {
+              y = 0;
+           }
+       }
+       skey->blowfish.K[x] = ORIG_P[x] ^ A;
+   }
+
+   /* copy sboxes */
+   for (x = 0; x < 4; x++) {
+       for (y = 0; y < 256; y++) {
+           skey->blowfish.S[x][y] = ORIG_S[x][y];
+       }
+   }
+
+   /* encrypt K array */
+   for (x = 0; x < 8; x++) {
+       B[x] = 0;
+   }
+
+   for (x = 0; x < 18; x += 2) {
+       /* encrypt it */
+       blowfish_ecb_encrypt(B, B, skey);
+       /* copy it */
+       LOAD32H(skey->blowfish.K[x], &B[0]);
+       LOAD32H(skey->blowfish.K[x+1], &B[4]);
+   }
+
+   /* encrypt S array */
+   for (x = 0; x < 4; x++) {
+       for (y = 0; y < 256; y += 2) {
+          /* encrypt it */
+          blowfish_ecb_encrypt(B, B, skey);
+          /* copy it */
+          LOAD32H(skey->blowfish.S[x][y], &B[0]);
+          LOAD32H(skey->blowfish.S[x][y+1], &B[4]);
+       }
+   }
+
+#ifdef LTC_CLEAN_STACK
+   zeromem(B, sizeof(B));
+#endif
+
+   return CRYPT_OK;
+}
+
+#ifndef __GNUC__
+#define F(x) ((S1[byte(x,3)] + S2[byte(x,2)]) ^ S3[byte(x,1)]) + S4[byte(x,0)]
+#else
+#define F(x) ((skey->blowfish.S[0][byte(x,3)] + skey->blowfish.S[1][byte(x,2)]) ^ skey->blowfish.S[2][byte(x,1)]) + skey->blowfish.S[3][byte(x,0)]
+#endif
+
+/**
+  Encrypts a block of text with Blowfish
+  @param pt The input plaintext (8 bytes)
+  @param ct The output ciphertext (8 bytes)
+  @param skey The key as scheduled
+  @return CRYPT_OK if successful
+*/
+#ifdef LTC_CLEAN_STACK
+static int _blowfish_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey)
+#else
+int blowfish_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey)
+#endif
+{
+   ulong32 L, R;
+   int r;
+#ifndef __GNUC__
+   ulong32 *S1, *S2, *S3, *S4;
+#endif
+
+    LTC_ARGCHK(pt   != NULL);
+    LTC_ARGCHK(ct   != NULL);
+    LTC_ARGCHK(skey != NULL);
+
+#ifndef __GNUC__
+    S1 = skey->blowfish.S[0];
+    S2 = skey->blowfish.S[1];
+    S3 = skey->blowfish.S[2];
+    S4 = skey->blowfish.S[3];
+#endif
+
+   /* load it */
+   LOAD32H(L, &pt[0]);
+   LOAD32H(R, &pt[4]);
+
+   /* do 16 rounds */
+   for (r = 0; r < 16; ) {
+      L ^= skey->blowfish.K[r++];  R ^= F(L);
+      R ^= skey->blowfish.K[r++];  L ^= F(R);
+      L ^= skey->blowfish.K[r++];  R ^= F(L);
+      R ^= skey->blowfish.K[r++];  L ^= F(R);
+   }
+
+   /* last keying */
+   R ^= skey->blowfish.K[17];
+   L ^= skey->blowfish.K[16];
+
+   /* store */
+   STORE32H(R, &ct[0]);
+   STORE32H(L, &ct[4]);
+
+   return CRYPT_OK;
+}
+
+#ifdef LTC_CLEAN_STACK
+int blowfish_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey)
+{
+    int err = _blowfish_ecb_encrypt(pt, ct, skey);
+    burn_stack(sizeof(ulong32) * 2 + sizeof(int));
+    return err;
+}
+#endif
+
+/**
+  Decrypts a block of text with Blowfish
+  @param ct The input ciphertext (8 bytes)
+  @param pt The output plaintext (8 bytes)
+  @param skey The key as scheduled
+  @return CRYPT_OK if successful
+*/
+#ifdef LTC_CLEAN_STACK
+static int _blowfish_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey)
+#else
+int blowfish_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey)
+#endif
+{
+   ulong32 L, R;
+   int r;
+#ifndef __GNUC__
+   ulong32 *S1, *S2, *S3, *S4;
+#endif
+
+    LTC_ARGCHK(pt   != NULL);
+    LTC_ARGCHK(ct   != NULL);
+    LTC_ARGCHK(skey != NULL);
+
+#ifndef __GNUC__
+    S1 = skey->blowfish.S[0];
+    S2 = skey->blowfish.S[1];
+    S3 = skey->blowfish.S[2];
+    S4 = skey->blowfish.S[3];
+#endif
+
+   /* load it */
+   LOAD32H(R, &ct[0]);
+   LOAD32H(L, &ct[4]);
+
+   /* undo last keying */
+   R ^= skey->blowfish.K[17];
+   L ^= skey->blowfish.K[16];
+
+   /* do 16 rounds */
+   for (r = 15; r > 0; ) {
+      L ^= F(R); R ^= skey->blowfish.K[r--];
+      R ^= F(L); L ^= skey->blowfish.K[r--];
+      L ^= F(R); R ^= skey->blowfish.K[r--];
+      R ^= F(L); L ^= skey->blowfish.K[r--];
+   }
+
+   /* store */
+   STORE32H(L, &pt[0]);
+   STORE32H(R, &pt[4]);
+   return CRYPT_OK;
+}
+
+#ifdef LTC_CLEAN_STACK
+int blowfish_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey)
+{
+    int err = _blowfish_ecb_decrypt(ct, pt, skey);
+    burn_stack(sizeof(ulong32) * 2 + sizeof(int));
+    return err;
+}
+#endif
+
+
+/**
+  Performs a self-test of the Blowfish block cipher
+  @return CRYPT_OK if functional, CRYPT_NOP if self-test has been disabled
+*/
+int blowfish_test(void)
+{
+ #ifndef LTC_TEST
+    return CRYPT_NOP;
+ #else
+   int err;
+   symmetric_key key;
+   static const struct {
+          unsigned char key[8], pt[8], ct[8];
+   } tests[] = {
+       {
+           { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+           { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+           { 0x4E, 0xF9, 0x97, 0x45, 0x61, 0x98, 0xDD, 0x78}
+       },
+       {
+           { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
+           { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
+           { 0x51, 0x86, 0x6F, 0xD5, 0xB8, 0x5E, 0xCB, 0x8A}
+       },
+       {
+           { 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+           { 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01},
+           { 0x7D, 0x85, 0x6F, 0x9A, 0x61, 0x30, 0x63, 0xF2}
+       }
+   };
+   unsigned char tmp[2][8];
+   int x, y;
+
+   for (x = 0; x < (int)(sizeof(tests) / sizeof(tests[0])); x++) {
+      /* setup key */
+      if ((err = blowfish_setup(tests[x].key, 8, 16, &key)) != CRYPT_OK) {
+         return err;
+      }
+
+      /* encrypt and decrypt */
+      blowfish_ecb_encrypt(tests[x].pt, tmp[0], &key);
+      blowfish_ecb_decrypt(tmp[0], tmp[1], &key);
+
+      /* compare */
+      if ((compare_testvector(tmp[0], 8, tests[x].ct, 8, "Blowfish Encrypt", x) != 0) ||
+            (compare_testvector(tmp[1], 8, tests[x].pt, 8, "Blowfish Decrypt", x) != 0)) {
+         return CRYPT_FAIL_TESTVECTOR;
+      }
+
+      /* now see if we can encrypt all zero bytes 1000 times, decrypt and come back where we started */
+      for (y = 0; y < 8; y++) tmp[0][y] = 0;
+      for (y = 0; y < 1000; y++) blowfish_ecb_encrypt(tmp[0], tmp[0], &key);
+      for (y = 0; y < 1000; y++) blowfish_ecb_decrypt(tmp[0], tmp[0], &key);
+      for (y = 0; y < 8; y++) if (tmp[0][y] != 0) return CRYPT_FAIL_TESTVECTOR;
+   }
+   return CRYPT_OK;
+ #endif
+}
+
+/** Terminate the context
+   @param skey    The scheduled key
+*/
+void blowfish_done(symmetric_key *skey)
+{
+  LTC_UNUSED_PARAM(skey);
+}
+
+/**
+  Gets suitable key size
+  @param keysize [in/out] The length of the recommended key (in bytes).  This function will store the suitable size back in this variable.
+  @return CRYPT_OK if the input key size is acceptable.
+*/
+int blowfish_keysize(int *keysize)
+{
+   LTC_ARGCHK(keysize != NULL);
+
+   if (*keysize < 8) {
+      return CRYPT_INVALID_KEYSIZE;
+   } else if (*keysize > 56) {
+      *keysize = 56;
+   }
+   return CRYPT_OK;
+}
+
+#endif
+
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/ciphers/camellia.c b/libtomcrypt/src/ciphers/camellia.c
new file mode 100644 (file)
index 0000000..0a75087
--- /dev/null
@@ -0,0 +1,726 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+/**
+  @file camellia.c
+  Implementation by Tom St Denis of Elliptic Semiconductor
+*/
+
+#include "tomcrypt.h"
+
+#ifdef LTC_CAMELLIA
+
+const struct ltc_cipher_descriptor camellia_desc = {
+   "camellia",
+   23,
+   16, 32, 16, 18,
+   &camellia_setup,
+   &camellia_ecb_encrypt,
+   &camellia_ecb_decrypt,
+   &camellia_test,
+   &camellia_done,
+   &camellia_keysize,
+   NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
+};
+
+static const ulong32 SP1110[] = {
+0x70707000, 0x82828200, 0x2c2c2c00, 0xececec00, 0xb3b3b300, 0x27272700, 0xc0c0c000, 0xe5e5e500,
+0xe4e4e400, 0x85858500, 0x57575700, 0x35353500, 0xeaeaea00, 0x0c0c0c00, 0xaeaeae00, 0x41414100,
+0x23232300, 0xefefef00, 0x6b6b6b00, 0x93939300, 0x45454500, 0x19191900, 0xa5a5a500, 0x21212100,
+0xededed00, 0x0e0e0e00, 0x4f4f4f00, 0x4e4e4e00, 0x1d1d1d00, 0x65656500, 0x92929200, 0xbdbdbd00,
+0x86868600, 0xb8b8b800, 0xafafaf00, 0x8f8f8f00, 0x7c7c7c00, 0xebebeb00, 0x1f1f1f00, 0xcecece00,
+0x3e3e3e00, 0x30303000, 0xdcdcdc00, 0x5f5f5f00, 0x5e5e5e00, 0xc5c5c500, 0x0b0b0b00, 0x1a1a1a00,
+0xa6a6a600, 0xe1e1e100, 0x39393900, 0xcacaca00, 0xd5d5d500, 0x47474700, 0x5d5d5d00, 0x3d3d3d00,
+0xd9d9d900, 0x01010100, 0x5a5a5a00, 0xd6d6d600, 0x51515100, 0x56565600, 0x6c6c6c00, 0x4d4d4d00,
+0x8b8b8b00, 0x0d0d0d00, 0x9a9a9a00, 0x66666600, 0xfbfbfb00, 0xcccccc00, 0xb0b0b000, 0x2d2d2d00,
+0x74747400, 0x12121200, 0x2b2b2b00, 0x20202000, 0xf0f0f000, 0xb1b1b100, 0x84848400, 0x99999900,
+0xdfdfdf00, 0x4c4c4c00, 0xcbcbcb00, 0xc2c2c200, 0x34343400, 0x7e7e7e00, 0x76767600, 0x05050500,
+0x6d6d6d00, 0xb7b7b700, 0xa9a9a900, 0x31313100, 0xd1d1d100, 0x17171700, 0x04040400, 0xd7d7d700,
+0x14141400, 0x58585800, 0x3a3a3a00, 0x61616100, 0xdedede00, 0x1b1b1b00, 0x11111100, 0x1c1c1c00,
+0x32323200, 0x0f0f0f00, 0x9c9c9c00, 0x16161600, 0x53535300, 0x18181800, 0xf2f2f200, 0x22222200,
+0xfefefe00, 0x44444400, 0xcfcfcf00, 0xb2b2b200, 0xc3c3c300, 0xb5b5b500, 0x7a7a7a00, 0x91919100,
+0x24242400, 0x08080800, 0xe8e8e800, 0xa8a8a800, 0x60606000, 0xfcfcfc00, 0x69696900, 0x50505000,
+0xaaaaaa00, 0xd0d0d000, 0xa0a0a000, 0x7d7d7d00, 0xa1a1a100, 0x89898900, 0x62626200, 0x97979700,
+0x54545400, 0x5b5b5b00, 0x1e1e1e00, 0x95959500, 0xe0e0e000, 0xffffff00, 0x64646400, 0xd2d2d200,
+0x10101000, 0xc4c4c400, 0x00000000, 0x48484800, 0xa3a3a300, 0xf7f7f700, 0x75757500, 0xdbdbdb00,
+0x8a8a8a00, 0x03030300, 0xe6e6e600, 0xdadada00, 0x09090900, 0x3f3f3f00, 0xdddddd00, 0x94949400,
+0x87878700, 0x5c5c5c00, 0x83838300, 0x02020200, 0xcdcdcd00, 0x4a4a4a00, 0x90909000, 0x33333300,
+0x73737300, 0x67676700, 0xf6f6f600, 0xf3f3f300, 0x9d9d9d00, 0x7f7f7f00, 0xbfbfbf00, 0xe2e2e200,
+0x52525200, 0x9b9b9b00, 0xd8d8d800, 0x26262600, 0xc8c8c800, 0x37373700, 0xc6c6c600, 0x3b3b3b00,
+0x81818100, 0x96969600, 0x6f6f6f00, 0x4b4b4b00, 0x13131300, 0xbebebe00, 0x63636300, 0x2e2e2e00,
+0xe9e9e900, 0x79797900, 0xa7a7a700, 0x8c8c8c00, 0x9f9f9f00, 0x6e6e6e00, 0xbcbcbc00, 0x8e8e8e00,
+0x29292900, 0xf5f5f500, 0xf9f9f900, 0xb6b6b600, 0x2f2f2f00, 0xfdfdfd00, 0xb4b4b400, 0x59595900,
+0x78787800, 0x98989800, 0x06060600, 0x6a6a6a00, 0xe7e7e700, 0x46464600, 0x71717100, 0xbababa00,
+0xd4d4d400, 0x25252500, 0xababab00, 0x42424200, 0x88888800, 0xa2a2a200, 0x8d8d8d00, 0xfafafa00,
+0x72727200, 0x07070700, 0xb9b9b900, 0x55555500, 0xf8f8f800, 0xeeeeee00, 0xacacac00, 0x0a0a0a00,
+0x36363600, 0x49494900, 0x2a2a2a00, 0x68686800, 0x3c3c3c00, 0x38383800, 0xf1f1f100, 0xa4a4a400,
+0x40404000, 0x28282800, 0xd3d3d300, 0x7b7b7b00, 0xbbbbbb00, 0xc9c9c900, 0x43434300, 0xc1c1c100,
+0x15151500, 0xe3e3e300, 0xadadad00, 0xf4f4f400, 0x77777700, 0xc7c7c700, 0x80808000, 0x9e9e9e00,
+};
+
+static const ulong32 SP0222[] = {
+0x00e0e0e0, 0x00050505, 0x00585858, 0x00d9d9d9, 0x00676767, 0x004e4e4e, 0x00818181, 0x00cbcbcb,
+0x00c9c9c9, 0x000b0b0b, 0x00aeaeae, 0x006a6a6a, 0x00d5d5d5, 0x00181818, 0x005d5d5d, 0x00828282,
+0x00464646, 0x00dfdfdf, 0x00d6d6d6, 0x00272727, 0x008a8a8a, 0x00323232, 0x004b4b4b, 0x00424242,
+0x00dbdbdb, 0x001c1c1c, 0x009e9e9e, 0x009c9c9c, 0x003a3a3a, 0x00cacaca, 0x00252525, 0x007b7b7b,
+0x000d0d0d, 0x00717171, 0x005f5f5f, 0x001f1f1f, 0x00f8f8f8, 0x00d7d7d7, 0x003e3e3e, 0x009d9d9d,
+0x007c7c7c, 0x00606060, 0x00b9b9b9, 0x00bebebe, 0x00bcbcbc, 0x008b8b8b, 0x00161616, 0x00343434,
+0x004d4d4d, 0x00c3c3c3, 0x00727272, 0x00959595, 0x00ababab, 0x008e8e8e, 0x00bababa, 0x007a7a7a,
+0x00b3b3b3, 0x00020202, 0x00b4b4b4, 0x00adadad, 0x00a2a2a2, 0x00acacac, 0x00d8d8d8, 0x009a9a9a,
+0x00171717, 0x001a1a1a, 0x00353535, 0x00cccccc, 0x00f7f7f7, 0x00999999, 0x00616161, 0x005a5a5a,
+0x00e8e8e8, 0x00242424, 0x00565656, 0x00404040, 0x00e1e1e1, 0x00636363, 0x00090909, 0x00333333,
+0x00bfbfbf, 0x00989898, 0x00979797, 0x00858585, 0x00686868, 0x00fcfcfc, 0x00ececec, 0x000a0a0a,
+0x00dadada, 0x006f6f6f, 0x00535353, 0x00626262, 0x00a3a3a3, 0x002e2e2e, 0x00080808, 0x00afafaf,
+0x00282828, 0x00b0b0b0, 0x00747474, 0x00c2c2c2, 0x00bdbdbd, 0x00363636, 0x00222222, 0x00383838,
+0x00646464, 0x001e1e1e, 0x00393939, 0x002c2c2c, 0x00a6a6a6, 0x00303030, 0x00e5e5e5, 0x00444444,
+0x00fdfdfd, 0x00888888, 0x009f9f9f, 0x00656565, 0x00878787, 0x006b6b6b, 0x00f4f4f4, 0x00232323,
+0x00484848, 0x00101010, 0x00d1d1d1, 0x00515151, 0x00c0c0c0, 0x00f9f9f9, 0x00d2d2d2, 0x00a0a0a0,
+0x00555555, 0x00a1a1a1, 0x00414141, 0x00fafafa, 0x00434343, 0x00131313, 0x00c4c4c4, 0x002f2f2f,
+0x00a8a8a8, 0x00b6b6b6, 0x003c3c3c, 0x002b2b2b, 0x00c1c1c1, 0x00ffffff, 0x00c8c8c8, 0x00a5a5a5,
+0x00202020, 0x00898989, 0x00000000, 0x00909090, 0x00474747, 0x00efefef, 0x00eaeaea, 0x00b7b7b7,
+0x00151515, 0x00060606, 0x00cdcdcd, 0x00b5b5b5, 0x00121212, 0x007e7e7e, 0x00bbbbbb, 0x00292929,
+0x000f0f0f, 0x00b8b8b8, 0x00070707, 0x00040404, 0x009b9b9b, 0x00949494, 0x00212121, 0x00666666,
+0x00e6e6e6, 0x00cecece, 0x00ededed, 0x00e7e7e7, 0x003b3b3b, 0x00fefefe, 0x007f7f7f, 0x00c5c5c5,
+0x00a4a4a4, 0x00373737, 0x00b1b1b1, 0x004c4c4c, 0x00919191, 0x006e6e6e, 0x008d8d8d, 0x00767676,
+0x00030303, 0x002d2d2d, 0x00dedede, 0x00969696, 0x00262626, 0x007d7d7d, 0x00c6c6c6, 0x005c5c5c,
+0x00d3d3d3, 0x00f2f2f2, 0x004f4f4f, 0x00191919, 0x003f3f3f, 0x00dcdcdc, 0x00797979, 0x001d1d1d,
+0x00525252, 0x00ebebeb, 0x00f3f3f3, 0x006d6d6d, 0x005e5e5e, 0x00fbfbfb, 0x00696969, 0x00b2b2b2,
+0x00f0f0f0, 0x00313131, 0x000c0c0c, 0x00d4d4d4, 0x00cfcfcf, 0x008c8c8c, 0x00e2e2e2, 0x00757575,
+0x00a9a9a9, 0x004a4a4a, 0x00575757, 0x00848484, 0x00111111, 0x00454545, 0x001b1b1b, 0x00f5f5f5,
+0x00e4e4e4, 0x000e0e0e, 0x00737373, 0x00aaaaaa, 0x00f1f1f1, 0x00dddddd, 0x00595959, 0x00141414,
+0x006c6c6c, 0x00929292, 0x00545454, 0x00d0d0d0, 0x00787878, 0x00707070, 0x00e3e3e3, 0x00494949,
+0x00808080, 0x00505050, 0x00a7a7a7, 0x00f6f6f6, 0x00777777, 0x00939393, 0x00868686, 0x00838383,
+0x002a2a2a, 0x00c7c7c7, 0x005b5b5b, 0x00e9e9e9, 0x00eeeeee, 0x008f8f8f, 0x00010101, 0x003d3d3d,
+};
+
+static const ulong32 SP3033[] = {
+0x38003838, 0x41004141, 0x16001616, 0x76007676, 0xd900d9d9, 0x93009393, 0x60006060, 0xf200f2f2,
+0x72007272, 0xc200c2c2, 0xab00abab, 0x9a009a9a, 0x75007575, 0x06000606, 0x57005757, 0xa000a0a0,
+0x91009191, 0xf700f7f7, 0xb500b5b5, 0xc900c9c9, 0xa200a2a2, 0x8c008c8c, 0xd200d2d2, 0x90009090,
+0xf600f6f6, 0x07000707, 0xa700a7a7, 0x27002727, 0x8e008e8e, 0xb200b2b2, 0x49004949, 0xde00dede,
+0x43004343, 0x5c005c5c, 0xd700d7d7, 0xc700c7c7, 0x3e003e3e, 0xf500f5f5, 0x8f008f8f, 0x67006767,
+0x1f001f1f, 0x18001818, 0x6e006e6e, 0xaf00afaf, 0x2f002f2f, 0xe200e2e2, 0x85008585, 0x0d000d0d,
+0x53005353, 0xf000f0f0, 0x9c009c9c, 0x65006565, 0xea00eaea, 0xa300a3a3, 0xae00aeae, 0x9e009e9e,
+0xec00ecec, 0x80008080, 0x2d002d2d, 0x6b006b6b, 0xa800a8a8, 0x2b002b2b, 0x36003636, 0xa600a6a6,
+0xc500c5c5, 0x86008686, 0x4d004d4d, 0x33003333, 0xfd00fdfd, 0x66006666, 0x58005858, 0x96009696,
+0x3a003a3a, 0x09000909, 0x95009595, 0x10001010, 0x78007878, 0xd800d8d8, 0x42004242, 0xcc00cccc,
+0xef00efef, 0x26002626, 0xe500e5e5, 0x61006161, 0x1a001a1a, 0x3f003f3f, 0x3b003b3b, 0x82008282,
+0xb600b6b6, 0xdb00dbdb, 0xd400d4d4, 0x98009898, 0xe800e8e8, 0x8b008b8b, 0x02000202, 0xeb00ebeb,
+0x0a000a0a, 0x2c002c2c, 0x1d001d1d, 0xb000b0b0, 0x6f006f6f, 0x8d008d8d, 0x88008888, 0x0e000e0e,
+0x19001919, 0x87008787, 0x4e004e4e, 0x0b000b0b, 0xa900a9a9, 0x0c000c0c, 0x79007979, 0x11001111,
+0x7f007f7f, 0x22002222, 0xe700e7e7, 0x59005959, 0xe100e1e1, 0xda00dada, 0x3d003d3d, 0xc800c8c8,
+0x12001212, 0x04000404, 0x74007474, 0x54005454, 0x30003030, 0x7e007e7e, 0xb400b4b4, 0x28002828,
+0x55005555, 0x68006868, 0x50005050, 0xbe00bebe, 0xd000d0d0, 0xc400c4c4, 0x31003131, 0xcb00cbcb,
+0x2a002a2a, 0xad00adad, 0x0f000f0f, 0xca00caca, 0x70007070, 0xff00ffff, 0x32003232, 0x69006969,
+0x08000808, 0x62006262, 0x00000000, 0x24002424, 0xd100d1d1, 0xfb00fbfb, 0xba00baba, 0xed00eded,
+0x45004545, 0x81008181, 0x73007373, 0x6d006d6d, 0x84008484, 0x9f009f9f, 0xee00eeee, 0x4a004a4a,
+0xc300c3c3, 0x2e002e2e, 0xc100c1c1, 0x01000101, 0xe600e6e6, 0x25002525, 0x48004848, 0x99009999,
+0xb900b9b9, 0xb300b3b3, 0x7b007b7b, 0xf900f9f9, 0xce00cece, 0xbf00bfbf, 0xdf00dfdf, 0x71007171,
+0x29002929, 0xcd00cdcd, 0x6c006c6c, 0x13001313, 0x64006464, 0x9b009b9b, 0x63006363, 0x9d009d9d,
+0xc000c0c0, 0x4b004b4b, 0xb700b7b7, 0xa500a5a5, 0x89008989, 0x5f005f5f, 0xb100b1b1, 0x17001717,
+0xf400f4f4, 0xbc00bcbc, 0xd300d3d3, 0x46004646, 0xcf00cfcf, 0x37003737, 0x5e005e5e, 0x47004747,
+0x94009494, 0xfa00fafa, 0xfc00fcfc, 0x5b005b5b, 0x97009797, 0xfe00fefe, 0x5a005a5a, 0xac00acac,
+0x3c003c3c, 0x4c004c4c, 0x03000303, 0x35003535, 0xf300f3f3, 0x23002323, 0xb800b8b8, 0x5d005d5d,
+0x6a006a6a, 0x92009292, 0xd500d5d5, 0x21002121, 0x44004444, 0x51005151, 0xc600c6c6, 0x7d007d7d,
+0x39003939, 0x83008383, 0xdc00dcdc, 0xaa00aaaa, 0x7c007c7c, 0x77007777, 0x56005656, 0x05000505,
+0x1b001b1b, 0xa400a4a4, 0x15001515, 0x34003434, 0x1e001e1e, 0x1c001c1c, 0xf800f8f8, 0x52005252,
+0x20002020, 0x14001414, 0xe900e9e9, 0xbd00bdbd, 0xdd00dddd, 0xe400e4e4, 0xa100a1a1, 0xe000e0e0,
+0x8a008a8a, 0xf100f1f1, 0xd600d6d6, 0x7a007a7a, 0xbb00bbbb, 0xe300e3e3, 0x40004040, 0x4f004f4f,
+};
+
+static const ulong32 SP4404[] = {
+0x70700070, 0x2c2c002c, 0xb3b300b3, 0xc0c000c0, 0xe4e400e4, 0x57570057, 0xeaea00ea, 0xaeae00ae,
+0x23230023, 0x6b6b006b, 0x45450045, 0xa5a500a5, 0xeded00ed, 0x4f4f004f, 0x1d1d001d, 0x92920092,
+0x86860086, 0xafaf00af, 0x7c7c007c, 0x1f1f001f, 0x3e3e003e, 0xdcdc00dc, 0x5e5e005e, 0x0b0b000b,
+0xa6a600a6, 0x39390039, 0xd5d500d5, 0x5d5d005d, 0xd9d900d9, 0x5a5a005a, 0x51510051, 0x6c6c006c,
+0x8b8b008b, 0x9a9a009a, 0xfbfb00fb, 0xb0b000b0, 0x74740074, 0x2b2b002b, 0xf0f000f0, 0x84840084,
+0xdfdf00df, 0xcbcb00cb, 0x34340034, 0x76760076, 0x6d6d006d, 0xa9a900a9, 0xd1d100d1, 0x04040004,
+0x14140014, 0x3a3a003a, 0xdede00de, 0x11110011, 0x32320032, 0x9c9c009c, 0x53530053, 0xf2f200f2,
+0xfefe00fe, 0xcfcf00cf, 0xc3c300c3, 0x7a7a007a, 0x24240024, 0xe8e800e8, 0x60600060, 0x69690069,
+0xaaaa00aa, 0xa0a000a0, 0xa1a100a1, 0x62620062, 0x54540054, 0x1e1e001e, 0xe0e000e0, 0x64640064,
+0x10100010, 0x00000000, 0xa3a300a3, 0x75750075, 0x8a8a008a, 0xe6e600e6, 0x09090009, 0xdddd00dd,
+0x87870087, 0x83830083, 0xcdcd00cd, 0x90900090, 0x73730073, 0xf6f600f6, 0x9d9d009d, 0xbfbf00bf,
+0x52520052, 0xd8d800d8, 0xc8c800c8, 0xc6c600c6, 0x81810081, 0x6f6f006f, 0x13130013, 0x63630063,
+0xe9e900e9, 0xa7a700a7, 0x9f9f009f, 0xbcbc00bc, 0x29290029, 0xf9f900f9, 0x2f2f002f, 0xb4b400b4,
+0x78780078, 0x06060006, 0xe7e700e7, 0x71710071, 0xd4d400d4, 0xabab00ab, 0x88880088, 0x8d8d008d,
+0x72720072, 0xb9b900b9, 0xf8f800f8, 0xacac00ac, 0x36360036, 0x2a2a002a, 0x3c3c003c, 0xf1f100f1,
+0x40400040, 0xd3d300d3, 0xbbbb00bb, 0x43430043, 0x15150015, 0xadad00ad, 0x77770077, 0x80800080,
+0x82820082, 0xecec00ec, 0x27270027, 0xe5e500e5, 0x85850085, 0x35350035, 0x0c0c000c, 0x41410041,
+0xefef00ef, 0x93930093, 0x19190019, 0x21210021, 0x0e0e000e, 0x4e4e004e, 0x65650065, 0xbdbd00bd,
+0xb8b800b8, 0x8f8f008f, 0xebeb00eb, 0xcece00ce, 0x30300030, 0x5f5f005f, 0xc5c500c5, 0x1a1a001a,
+0xe1e100e1, 0xcaca00ca, 0x47470047, 0x3d3d003d, 0x01010001, 0xd6d600d6, 0x56560056, 0x4d4d004d,
+0x0d0d000d, 0x66660066, 0xcccc00cc, 0x2d2d002d, 0x12120012, 0x20200020, 0xb1b100b1, 0x99990099,
+0x4c4c004c, 0xc2c200c2, 0x7e7e007e, 0x05050005, 0xb7b700b7, 0x31310031, 0x17170017, 0xd7d700d7,
+0x58580058, 0x61610061, 0x1b1b001b, 0x1c1c001c, 0x0f0f000f, 0x16160016, 0x18180018, 0x22220022,
+0x44440044, 0xb2b200b2, 0xb5b500b5, 0x91910091, 0x08080008, 0xa8a800a8, 0xfcfc00fc, 0x50500050,
+0xd0d000d0, 0x7d7d007d, 0x89890089, 0x97970097, 0x5b5b005b, 0x95950095, 0xffff00ff, 0xd2d200d2,
+0xc4c400c4, 0x48480048, 0xf7f700f7, 0xdbdb00db, 0x03030003, 0xdada00da, 0x3f3f003f, 0x94940094,
+0x5c5c005c, 0x02020002, 0x4a4a004a, 0x33330033, 0x67670067, 0xf3f300f3, 0x7f7f007f, 0xe2e200e2,
+0x9b9b009b, 0x26260026, 0x37370037, 0x3b3b003b, 0x96960096, 0x4b4b004b, 0xbebe00be, 0x2e2e002e,
+0x79790079, 0x8c8c008c, 0x6e6e006e, 0x8e8e008e, 0xf5f500f5, 0xb6b600b6, 0xfdfd00fd, 0x59590059,
+0x98980098, 0x6a6a006a, 0x46460046, 0xbaba00ba, 0x25250025, 0x42420042, 0xa2a200a2, 0xfafa00fa,
+0x07070007, 0x55550055, 0xeeee00ee, 0x0a0a000a, 0x49490049, 0x68680068, 0x38380038, 0xa4a400a4,
+0x28280028, 0x7b7b007b, 0xc9c900c9, 0xc1c100c1, 0xe3e300e3, 0xf4f400f4, 0xc7c700c7, 0x9e9e009e,
+};
+
+static const ulong64 key_sigma[] = {
+   CONST64(0xA09E667F3BCC908B),
+   CONST64(0xB67AE8584CAA73B2),
+   CONST64(0xC6EF372FE94F82BE),
+   CONST64(0x54FF53A5F1D36F1C),
+   CONST64(0x10E527FADE682D1D),
+   CONST64(0xB05688C2B3E6C1FD)
+};
+
+static ulong64 F(ulong64 x)
+{
+   ulong32 D, U;
+
+#define loc(i) ((8-i)*8)
+
+   D = SP1110[(x >> loc(8)) & 0xFF] ^ SP0222[(x >> loc(5)) & 0xFF] ^ SP3033[(x >> loc(6)) & 0xFF] ^ SP4404[(x >> loc(7)) & 0xFF];
+   U = SP1110[(x >> loc(1)) & 0xFF] ^ SP0222[(x >> loc(2)) & 0xFF] ^ SP3033[(x >> loc(3)) & 0xFF] ^ SP4404[(x >> loc(4)) & 0xFF];
+
+   D ^= U;
+   U = D ^ RORc(U, 8);
+
+   return ((ulong64)U) | (((ulong64)D) << CONST64(32));
+}
+
+static void rot_128(unsigned char *in, unsigned count, unsigned char *out)
+{
+   unsigned x, w, b;
+
+   w = count >> 3;
+   b = count & 7;
+
+   for (x = 0; x < 16; x++) {
+      out[x] = (in[(x+w)&15] << b) | (in[(x+w+1)&15] >> (8 - b));
+   }
+}
+
+int camellia_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey)
+{
+   unsigned char T[48], kA[16], kB[16], kR[16], kL[16];
+   int           x;
+   ulong64       A, B;
+
+   LTC_ARGCHK(key  != NULL);
+   LTC_ARGCHK(skey != NULL);
+
+   /* Valid sizes (in bytes) are 16, 24, 32 */
+   if (keylen != 16 && keylen != 24 && keylen != 32) {
+      return CRYPT_INVALID_KEYSIZE;
+   }
+
+   /* number of rounds */
+   skey->camellia.R = (keylen == 16) ? 18 : 24;
+
+   if (num_rounds != 0 && num_rounds != skey->camellia.R) {
+      return CRYPT_INVALID_ROUNDS;
+   }
+
+   /* expand key */
+   if (keylen == 16) {
+      for (x = 0; x < 16; x++) {
+          T[x]      = key[x];
+          T[x + 16] = 0;
+      }
+   } else if (keylen == 24) {
+      for (x = 0; x < 24; x++) {
+          T[x]      = key[x];
+      }
+      for (x = 24; x < 32; x++) {
+          T[x]      = key[x-8] ^ 0xFF;
+      }
+   } else {
+      for (x = 0; x < 32; x++) {
+          T[x]      = key[x];
+      }
+   }
+
+   for (x = 0; x < 16; x++) {
+      kL[x] = T[x];
+      kR[x] = T[x + 16];
+   }
+
+   for (x = 32; x < 48; x++) {
+      T[x] = T[x - 32] ^ T[x - 16];
+   }
+
+   /* first two rounds */
+   LOAD64H(A, T+32); LOAD64H(B, T+40);
+   B ^= F(A ^ key_sigma[0]);
+   A ^= F(B ^ key_sigma[1]);
+   STORE64H(A, T+32); STORE64H(B, T+40);
+
+   /* xor kL in */
+   for (x = 0; x < 16; x++) { T[x+32] ^= kL[x]; }
+
+   /* next two rounds */
+   LOAD64H(A, T+32); LOAD64H(B, T+40);
+   B ^= F(A ^ key_sigma[2]);
+   A ^= F(B ^ key_sigma[3]);
+   STORE64H(A, T+32); STORE64H(B, T+40);
+
+   /* grab KA */
+   for (x = 0; x < 16; x++) { kA[x] = T[x+32]; }
+
+   /* xor kR in */
+   for (x = 0; x < 16; x++) { T[x+32] ^= kR[x]; }
+
+   if (keylen == 16) {
+      /* grab whitening keys kw1 and kw2 */
+      LOAD64H(skey->camellia.kw[0], kL);
+      LOAD64H(skey->camellia.kw[1], kL+8);
+
+      /* k1-k2 */
+      LOAD64H(skey->camellia.k[0], kA);
+      LOAD64H(skey->camellia.k[1], kA+8);
+
+      /* rotate kL by 15, k3/k4 */
+      rot_128(kL, 15, T+32);
+      LOAD64H(skey->camellia.k[2], T+32);
+      LOAD64H(skey->camellia.k[3], T+40);
+
+      /* rotate kA by 15, k5/k6 */
+      rot_128(kA, 15, T+32);
+      LOAD64H(skey->camellia.k[4], T+32);
+      LOAD64H(skey->camellia.k[5], T+40);
+
+      /* rotate kA by 30, kl1, kl2 */
+      rot_128(kA, 30, T+32);
+      LOAD64H(skey->camellia.kl[0], T+32);
+      LOAD64H(skey->camellia.kl[1], T+40);
+
+      /* rotate kL by 45, k7/k8 */
+      rot_128(kL, 45, T+32);
+      LOAD64H(skey->camellia.k[6], T+32);
+      LOAD64H(skey->camellia.k[7], T+40);
+
+      /* rotate kA by 45, k9/k10 */
+      rot_128(kA, 45, T+32);
+      LOAD64H(skey->camellia.k[8], T+32);
+      rot_128(kL, 60, T+32);
+      LOAD64H(skey->camellia.k[9], T+40);
+
+      /* rotate kA by 60, k11/k12 */
+      rot_128(kA, 60, T+32);
+      LOAD64H(skey->camellia.k[10], T+32);
+      LOAD64H(skey->camellia.k[11], T+40);
+
+      /* rotate kL by 77, kl3, kl4 */
+      rot_128(kL, 77, T+32);
+      LOAD64H(skey->camellia.kl[2], T+32);
+      LOAD64H(skey->camellia.kl[3], T+40);
+
+      /* rotate kL by 94, k13/k14 */
+      rot_128(kL, 94, T+32);
+      LOAD64H(skey->camellia.k[12], T+32);
+      LOAD64H(skey->camellia.k[13], T+40);
+
+      /* rotate kA by 94, k15/k16 */
+      rot_128(kA, 94, T+32);
+      LOAD64H(skey->camellia.k[14], T+32);
+      LOAD64H(skey->camellia.k[15], T+40);
+
+      /* rotate kL by 111, k17/k18 */
+      rot_128(kL, 111, T+32);
+      LOAD64H(skey->camellia.k[16], T+32);
+      LOAD64H(skey->camellia.k[17], T+40);
+
+      /* rotate kA by 111, kw3/kw4 */
+      rot_128(kA, 111, T+32);
+      LOAD64H(skey->camellia.kw[2], T+32);
+      LOAD64H(skey->camellia.kw[3], T+40);
+   } else {
+      /* last two rounds */
+      LOAD64H(A, T+32); LOAD64H(B, T+40);
+      B ^= F(A ^ key_sigma[4]);
+      A ^= F(B ^ key_sigma[5]);
+      STORE64H(A, T+32); STORE64H(B, T+40);
+
+      /* grab kB */
+      for (x = 0; x < 16; x++) { kB[x] = T[x+32]; }
+
+      /* kw1/2 from kL*/
+      LOAD64H(skey->camellia.kw[0], kL);
+      LOAD64H(skey->camellia.kw[1], kL+8);
+
+      /* k1/k2 = kB */
+      LOAD64H(skey->camellia.k[0], kB);
+      LOAD64H(skey->camellia.k[1], kB+8);
+
+      /* k3/k4 = kR by 15 */
+      rot_128(kR, 15, T+32);
+      LOAD64H(skey->camellia.k[2], T+32);
+      LOAD64H(skey->camellia.k[3], T+40);
+
+      /* k5/k7 = kA by 15 */
+      rot_128(kA, 15, T+32);
+      LOAD64H(skey->camellia.k[4], T+32);
+      LOAD64H(skey->camellia.k[5], T+40);
+
+      /* kl1/2 = kR by 30 */
+      rot_128(kR, 30, T+32);
+      LOAD64H(skey->camellia.kl[0], T+32);
+      LOAD64H(skey->camellia.kl[1], T+40);
+
+      /* k7/k8 = kB by 30 */
+      rot_128(kB, 30, T+32);
+      LOAD64H(skey->camellia.k[6], T+32);
+      LOAD64H(skey->camellia.k[7], T+40);
+
+      /* k9/k10 = kL by 45 */
+      rot_128(kL, 45, T+32);
+      LOAD64H(skey->camellia.k[8], T+32);
+      LOAD64H(skey->camellia.k[9], T+40);
+
+      /* k11/k12 = kA by 45 */
+      rot_128(kA, 45, T+32);
+      LOAD64H(skey->camellia.k[10], T+32);
+      LOAD64H(skey->camellia.k[11], T+40);
+
+      /* kl3/4 = kL by 60 */
+      rot_128(kL, 60, T+32);
+      LOAD64H(skey->camellia.kl[2], T+32);
+      LOAD64H(skey->camellia.kl[3], T+40);
+
+      /* k13/k14 = kR by 60 */
+      rot_128(kR, 60, T+32);
+      LOAD64H(skey->camellia.k[12], T+32);
+      LOAD64H(skey->camellia.k[13], T+40);
+
+      /* k15/k16 = kB by 15 */
+      rot_128(kB, 60, T+32);
+      LOAD64H(skey->camellia.k[14], T+32);
+      LOAD64H(skey->camellia.k[15], T+40);
+
+      /* k17/k18 = kL by 77 */
+      rot_128(kL, 77, T+32);
+      LOAD64H(skey->camellia.k[16], T+32);
+      LOAD64H(skey->camellia.k[17], T+40);
+
+      /* kl5/6 = kA by 77  */
+      rot_128(kA, 77, T+32);
+      LOAD64H(skey->camellia.kl[4], T+32);
+      LOAD64H(skey->camellia.kl[5], T+40);
+
+      /* k19/k20 = kR by 94 */
+      rot_128(kR, 94, T+32);
+      LOAD64H(skey->camellia.k[18], T+32);
+      LOAD64H(skey->camellia.k[19], T+40);
+
+      /* k21/k22 = kA by 94 */
+      rot_128(kA, 94, T+32);
+      LOAD64H(skey->camellia.k[20], T+32);
+      LOAD64H(skey->camellia.k[21], T+40);
+
+      /* k23/k24 = kL by 111 */
+      rot_128(kL, 111, T+32);
+      LOAD64H(skey->camellia.k[22], T+32);
+      LOAD64H(skey->camellia.k[23], T+40);
+
+      /* kw2/kw3 = kB by 111 */
+      rot_128(kB, 111, T+32);
+      LOAD64H(skey->camellia.kw[2], T+32);
+      LOAD64H(skey->camellia.kw[3], T+40);
+   }
+
+   return CRYPT_OK;
+}
+
+int camellia_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey)
+{
+   ulong64 L, R;
+   ulong32 a, b;
+
+   LOAD64H(L, pt+0); LOAD64H(R, pt+8);
+   L ^= skey->camellia.kw[0];
+   R ^= skey->camellia.kw[1];
+
+   /* first 6 rounds */
+   R ^= F(L ^ skey->camellia.k[0]);
+   L ^= F(R ^ skey->camellia.k[1]);
+   R ^= F(L ^ skey->camellia.k[2]);
+   L ^= F(R ^ skey->camellia.k[3]);
+   R ^= F(L ^ skey->camellia.k[4]);
+   L ^= F(R ^ skey->camellia.k[5]);
+
+   /* FL */
+   a = (ulong32)(L >> 32);
+   b = (ulong32)(L & 0xFFFFFFFFUL);
+   b ^= ROL((a & (ulong32)(skey->camellia.kl[0] >> 32)), 1);
+   a ^= b | (skey->camellia.kl[0] & 0xFFFFFFFFU);
+   L = (((ulong64)a) << 32) | b;
+
+   /* FL^-1 */
+   a = (ulong32)(R >> 32);
+   b = (ulong32)(R & 0xFFFFFFFFUL);
+   a ^= b | (skey->camellia.kl[1] & 0xFFFFFFFFU);
+   b ^= ROL((a & (ulong32)(skey->camellia.kl[1] >> 32)), 1);
+   R = (((ulong64)a) << 32) | b;
+
+   /* second 6 rounds */
+   R ^= F(L ^ skey->camellia.k[6]);
+   L ^= F(R ^ skey->camellia.k[7]);
+   R ^= F(L ^ skey->camellia.k[8]);
+   L ^= F(R ^ skey->camellia.k[9]);
+   R ^= F(L ^ skey->camellia.k[10]);
+   L ^= F(R ^ skey->camellia.k[11]);
+
+   /* FL */
+   a = (ulong32)(L >> 32);
+   b = (ulong32)(L & 0xFFFFFFFFUL);
+   b ^= ROL((a & (ulong32)(skey->camellia.kl[2] >> 32)), 1);
+   a ^= b | (skey->camellia.kl[2] & 0xFFFFFFFFU);
+   L = (((ulong64)a) << 32) | b;
+
+   /* FL^-1 */
+   a = (ulong32)(R >> 32);
+   b = (ulong32)(R & 0xFFFFFFFFUL);
+   a ^= b | (skey->camellia.kl[3] & 0xFFFFFFFFU);
+   b ^= ROL((a & (ulong32)(skey->camellia.kl[3] >> 32)), 1);
+   R = (((ulong64)a) << 32) | b;
+
+   /* third 6 rounds */
+   R ^= F(L ^ skey->camellia.k[12]);
+   L ^= F(R ^ skey->camellia.k[13]);
+   R ^= F(L ^ skey->camellia.k[14]);
+   L ^= F(R ^ skey->camellia.k[15]);
+   R ^= F(L ^ skey->camellia.k[16]);
+   L ^= F(R ^ skey->camellia.k[17]);
+
+   /* next FL */
+   if (skey->camellia.R == 24) {
+      /* FL */
+      a = (ulong32)(L >> 32);
+      b = (ulong32)(L & 0xFFFFFFFFUL);
+      b ^= ROL((a & (ulong32)(skey->camellia.kl[4] >> 32)), 1);
+      a ^= b | (skey->camellia.kl[4] & 0xFFFFFFFFU);
+      L = (((ulong64)a) << 32) | b;
+
+      /* FL^-1 */
+      a = (ulong32)(R >> 32);
+      b = (ulong32)(R & 0xFFFFFFFFUL);
+      a ^= b | (skey->camellia.kl[5] & 0xFFFFFFFFU);
+      b ^= ROL((a & (ulong32)(skey->camellia.kl[5] >> 32)), 1);
+      R = (((ulong64)a) << 32) | b;
+
+      /* fourth 6 rounds */
+      R ^= F(L ^ skey->camellia.k[18]);
+      L ^= F(R ^ skey->camellia.k[19]);
+      R ^= F(L ^ skey->camellia.k[20]);
+      L ^= F(R ^ skey->camellia.k[21]);
+      R ^= F(L ^ skey->camellia.k[22]);
+      L ^= F(R ^ skey->camellia.k[23]);
+   }
+
+   L ^= skey->camellia.kw[3];
+   R ^= skey->camellia.kw[2];
+
+   STORE64H(R, ct+0); STORE64H(L, ct+8);
+
+   return CRYPT_OK;
+}
+
+int camellia_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey)
+{
+   ulong64 L, R;
+   ulong32 a, b;
+
+   LOAD64H(R, ct+0); LOAD64H(L, ct+8);
+   L ^= skey->camellia.kw[3];
+   R ^= skey->camellia.kw[2];
+
+   /* next FL */
+   if (skey->camellia.R == 24) {
+      /* fourth 6 rounds */
+      L ^= F(R ^ skey->camellia.k[23]);
+      R ^= F(L ^ skey->camellia.k[22]);
+      L ^= F(R ^ skey->camellia.k[21]);
+      R ^= F(L ^ skey->camellia.k[20]);
+      L ^= F(R ^ skey->camellia.k[19]);
+      R ^= F(L ^ skey->camellia.k[18]);
+
+      /* FL */
+      a = (ulong32)(L >> 32);
+      b = (ulong32)(L & 0xFFFFFFFFUL);
+      a ^= b | (skey->camellia.kl[4] & 0xFFFFFFFFU);
+      b ^= ROL((a & (ulong32)(skey->camellia.kl[4] >> 32)), 1);
+      L = (((ulong64)a) << 32) | b;
+
+      /* FL^-1 */
+      a = (ulong32)(R >> 32);
+      b = (ulong32)(R & 0xFFFFFFFFUL);
+      b ^= ROL((a & (ulong32)(skey->camellia.kl[5] >> 32)), 1);
+      a ^= b | (skey->camellia.kl[5] & 0xFFFFFFFFU);
+      R = (((ulong64)a) << 32) | b;
+
+   }
+
+   /* third 6 rounds */
+   L ^= F(R ^ skey->camellia.k[17]);
+   R ^= F(L ^ skey->camellia.k[16]);
+   L ^= F(R ^ skey->camellia.k[15]);
+   R ^= F(L ^ skey->camellia.k[14]);
+   L ^= F(R ^ skey->camellia.k[13]);
+   R ^= F(L ^ skey->camellia.k[12]);
+
+   /* FL */
+   a = (ulong32)(L >> 32);
+   b = (ulong32)(L & 0xFFFFFFFFUL);
+   a ^= b | (skey->camellia.kl[2] & 0xFFFFFFFFU);
+   b ^= ROL((a & (ulong32)(skey->camellia.kl[2] >> 32)), 1);
+   L = (((ulong64)a) << 32) | b;
+
+   /* FL^-1 */
+   a = (ulong32)(R >> 32);
+   b = (ulong32)(R & 0xFFFFFFFFUL);
+   b ^= ROL((a & (ulong32)(skey->camellia.kl[3] >> 32)), 1);
+   a ^= b | (skey->camellia.kl[3] & 0xFFFFFFFFU);
+   R = (((ulong64)a) << 32) | b;
+
+   /* second 6 rounds */
+   L ^= F(R ^ skey->camellia.k[11]);
+   R ^= F(L ^ skey->camellia.k[10]);
+   L ^= F(R ^ skey->camellia.k[9]);
+   R ^= F(L ^ skey->camellia.k[8]);
+   L ^= F(R ^ skey->camellia.k[7]);
+   R ^= F(L ^ skey->camellia.k[6]);
+
+   /* FL */
+   a = (ulong32)(L >> 32);
+   b = (ulong32)(L & 0xFFFFFFFFUL);
+   a ^= b | (skey->camellia.kl[0] & 0xFFFFFFFFU);
+   b ^= ROL((a & (ulong32)(skey->camellia.kl[0] >> 32)), 1);
+   L = (((ulong64)a) << 32) | b;
+
+   /* FL^-1 */
+   a = (ulong32)(R >> 32);
+   b = (ulong32)(R & 0xFFFFFFFFUL);
+   b ^= ROL((a & (ulong32)(skey->camellia.kl[1] >> 32)), 1);
+   a ^= b | (skey->camellia.kl[1] & 0xFFFFFFFFU);
+   R = (((ulong64)a) << 32) | b;
+
+   /* first 6 rounds */
+   L ^= F(R ^ skey->camellia.k[5]);
+   R ^= F(L ^ skey->camellia.k[4]);
+   L ^= F(R ^ skey->camellia.k[3]);
+   R ^= F(L ^ skey->camellia.k[2]);
+   L ^= F(R ^ skey->camellia.k[1]);
+   R ^= F(L ^ skey->camellia.k[0]);
+
+   R ^= skey->camellia.kw[1];
+   L ^= skey->camellia.kw[0];
+
+   STORE64H(R, pt+8); STORE64H(L, pt+0);
+
+   return CRYPT_OK;
+}
+
+int camellia_test(void)
+{
+   static const struct {
+      int keylen;
+      unsigned char key[32], pt[16], ct[16];
+   } tests[] = {
+
+{
+   16,
+   { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
+     0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 },
+   { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
+     0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 },
+   { 0x67, 0x67, 0x31, 0x38, 0x54, 0x96, 0x69, 0x73,
+     0x08, 0x57, 0x06, 0x56, 0x48, 0xea, 0xbe, 0x43 }
+},
+
+{
+   24,
+   { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
+     0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10,
+     0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77 },
+   { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
+     0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 },
+   { 0xb4, 0x99, 0x34, 0x01, 0xb3, 0xe9, 0x96, 0xf8,
+     0x4e, 0xe5, 0xce, 0xe7, 0xd7, 0x9b, 0x09, 0xb9 }
+},
+
+
+{
+   32,
+   { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
+     0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10,
+     0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
+     0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff },
+   { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
+     0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 },
+   { 0x9a, 0xcc, 0x23, 0x7d, 0xff, 0x16, 0xd7, 0x6c,
+     0x20, 0xef, 0x7c, 0x91, 0x9e, 0x3a, 0x75, 0x09 }
+},
+
+{
+   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 },
+   { 0xF6, 0x9F, 0x24, 0x45, 0xDF, 0x4F, 0x9B, 0x17,
+     0xAD, 0x2B, 0x41, 0x7B, 0xE6, 0x6C, 0x37, 0x10 },
+   { 0x79, 0x60, 0x10, 0x9F, 0xB6, 0xDC, 0x42, 0x94,
+     0x7F, 0xCF, 0xE5, 0x9E, 0xA3, 0xC5, 0xEB, 0x6B  }
+}
+};
+   unsigned char buf[2][16];
+   symmetric_key skey;
+   int err;
+   unsigned int x;
+
+   for (x = 0; x < sizeof(tests)/sizeof(tests[0]); x++) {
+      zeromem(&skey, sizeof(skey));
+      if ((err = camellia_setup(tests[x].key, tests[x].keylen, 0, &skey)) != CRYPT_OK) {
+         return err;
+      }
+      if ((err = camellia_ecb_encrypt(tests[x].pt, buf[0], &skey)) != CRYPT_OK) {
+         camellia_done(&skey);
+         return err;
+      }
+      if ((err = camellia_ecb_decrypt(tests[x].ct, buf[1], &skey)) != CRYPT_OK) {
+         camellia_done(&skey);
+         return err;
+      }
+      camellia_done(&skey);
+      if (compare_testvector(tests[x].ct, 16, buf[0], 16, "Camellia Encrypt", x) ||
+            compare_testvector(tests[x].pt, 16, buf[1], 16, "Camellia Decrypt", x)) {
+         return CRYPT_FAIL_TESTVECTOR;
+      }
+   }
+   return CRYPT_OK;
+}
+
+void camellia_done(symmetric_key *skey)
+{
+  LTC_UNUSED_PARAM(skey);
+}
+
+int camellia_keysize(int *keysize)
+{
+   if (*keysize >= 32) { *keysize = 32; }
+   else if (*keysize >= 24) { *keysize = 24; }
+   else if (*keysize >= 16) { *keysize = 16; }
+   else return CRYPT_INVALID_KEYSIZE;
+   return CRYPT_OK;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/ciphers/cast5.c b/libtomcrypt/src/ciphers/cast5.c
new file mode 100644 (file)
index 0000000..43ca580
--- /dev/null
@@ -0,0 +1,720 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+ /**
+   @file cast5.c
+   Implementation of LTC_CAST5 (RFC 2144) by Tom St Denis
+ */
+#include "tomcrypt.h"
+
+#ifdef LTC_CAST5
+
+const struct ltc_cipher_descriptor cast5_desc = {
+   "cast5",
+   15,
+   5, 16, 8, 16,
+   &cast5_setup,
+   &cast5_ecb_encrypt,
+   &cast5_ecb_decrypt,
+   &cast5_test,
+   &cast5_done,
+   &cast5_keysize,
+   NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
+};
+
+static const ulong32 S1[256] = {
+0x30fb40d4UL, 0x9fa0ff0bUL, 0x6beccd2fUL, 0x3f258c7aUL, 0x1e213f2fUL, 0x9c004dd3UL,
+0x6003e540UL, 0xcf9fc949UL, 0xbfd4af27UL, 0x88bbbdb5UL, 0xe2034090UL, 0x98d09675UL,
+0x6e63a0e0UL, 0x15c361d2UL, 0xc2e7661dUL, 0x22d4ff8eUL, 0x28683b6fUL, 0xc07fd059UL,
+0xff2379c8UL, 0x775f50e2UL, 0x43c340d3UL, 0xdf2f8656UL, 0x887ca41aUL, 0xa2d2bd2dUL,
+0xa1c9e0d6UL, 0x346c4819UL, 0x61b76d87UL, 0x22540f2fUL, 0x2abe32e1UL, 0xaa54166bUL,
+0x22568e3aUL, 0xa2d341d0UL, 0x66db40c8UL, 0xa784392fUL, 0x004dff2fUL, 0x2db9d2deUL,
+0x97943facUL, 0x4a97c1d8UL, 0x527644b7UL, 0xb5f437a7UL, 0xb82cbaefUL, 0xd751d159UL,
+0x6ff7f0edUL, 0x5a097a1fUL, 0x827b68d0UL, 0x90ecf52eUL, 0x22b0c054UL, 0xbc8e5935UL,
+0x4b6d2f7fUL, 0x50bb64a2UL, 0xd2664910UL, 0xbee5812dUL, 0xb7332290UL, 0xe93b159fUL,
+0xb48ee411UL, 0x4bff345dUL, 0xfd45c240UL, 0xad31973fUL, 0xc4f6d02eUL, 0x55fc8165UL,
+0xd5b1caadUL, 0xa1ac2daeUL, 0xa2d4b76dUL, 0xc19b0c50UL, 0x882240f2UL, 0x0c6e4f38UL,
+0xa4e4bfd7UL, 0x4f5ba272UL, 0x564c1d2fUL, 0xc59c5319UL, 0xb949e354UL, 0xb04669feUL,
+0xb1b6ab8aUL, 0xc71358ddUL, 0x6385c545UL, 0x110f935dUL, 0x57538ad5UL, 0x6a390493UL,
+0xe63d37e0UL, 0x2a54f6b3UL, 0x3a787d5fUL, 0x6276a0b5UL, 0x19a6fcdfUL, 0x7a42206aUL,
+0x29f9d4d5UL, 0xf61b1891UL, 0xbb72275eUL, 0xaa508167UL, 0x38901091UL, 0xc6b505ebUL,
+0x84c7cb8cUL, 0x2ad75a0fUL, 0x874a1427UL, 0xa2d1936bUL, 0x2ad286afUL, 0xaa56d291UL,
+0xd7894360UL, 0x425c750dUL, 0x93b39e26UL, 0x187184c9UL, 0x6c00b32dUL, 0x73e2bb14UL,
+0xa0bebc3cUL, 0x54623779UL, 0x64459eabUL, 0x3f328b82UL, 0x7718cf82UL, 0x59a2cea6UL,
+0x04ee002eUL, 0x89fe78e6UL, 0x3fab0950UL, 0x325ff6c2UL, 0x81383f05UL, 0x6963c5c8UL,
+0x76cb5ad6UL, 0xd49974c9UL, 0xca180dcfUL, 0x380782d5UL, 0xc7fa5cf6UL, 0x8ac31511UL,
+0x35e79e13UL, 0x47da91d0UL, 0xf40f9086UL, 0xa7e2419eUL, 0x31366241UL, 0x051ef495UL,
+0xaa573b04UL, 0x4a805d8dUL, 0x548300d0UL, 0x00322a3cUL, 0xbf64cddfUL, 0xba57a68eUL,
+0x75c6372bUL, 0x50afd341UL, 0xa7c13275UL, 0x915a0bf5UL, 0x6b54bfabUL, 0x2b0b1426UL,
+0xab4cc9d7UL, 0x449ccd82UL, 0xf7fbf265UL, 0xab85c5f3UL, 0x1b55db94UL, 0xaad4e324UL,
+0xcfa4bd3fUL, 0x2deaa3e2UL, 0x9e204d02UL, 0xc8bd25acUL, 0xeadf55b3UL, 0xd5bd9e98UL,
+0xe31231b2UL, 0x2ad5ad6cUL, 0x954329deUL, 0xadbe4528UL, 0xd8710f69UL, 0xaa51c90fUL,
+0xaa786bf6UL, 0x22513f1eUL, 0xaa51a79bUL, 0x2ad344ccUL, 0x7b5a41f0UL, 0xd37cfbadUL,
+0x1b069505UL, 0x41ece491UL, 0xb4c332e6UL, 0x032268d4UL, 0xc9600accUL, 0xce387e6dUL,
+0xbf6bb16cUL, 0x6a70fb78UL, 0x0d03d9c9UL, 0xd4df39deUL, 0xe01063daUL, 0x4736f464UL,
+0x5ad328d8UL, 0xb347cc96UL, 0x75bb0fc3UL, 0x98511bfbUL, 0x4ffbcc35UL, 0xb58bcf6aUL,
+0xe11f0abcUL, 0xbfc5fe4aUL, 0xa70aec10UL, 0xac39570aUL, 0x3f04442fUL, 0x6188b153UL,
+0xe0397a2eUL, 0x5727cb79UL, 0x9ceb418fUL, 0x1cacd68dUL, 0x2ad37c96UL, 0x0175cb9dUL,
+0xc69dff09UL, 0xc75b65f0UL, 0xd9db40d8UL, 0xec0e7779UL, 0x4744ead4UL, 0xb11c3274UL,
+0xdd24cb9eUL, 0x7e1c54bdUL, 0xf01144f9UL, 0xd2240eb1UL, 0x9675b3fdUL, 0xa3ac3755UL,
+0xd47c27afUL, 0x51c85f4dUL, 0x56907596UL, 0xa5bb15e6UL, 0x580304f0UL, 0xca042cf1UL,
+0x011a37eaUL, 0x8dbfaadbUL, 0x35ba3e4aUL, 0x3526ffa0UL, 0xc37b4d09UL, 0xbc306ed9UL,
+0x98a52666UL, 0x5648f725UL, 0xff5e569dUL, 0x0ced63d0UL, 0x7c63b2cfUL, 0x700b45e1UL,
+0xd5ea50f1UL, 0x85a92872UL, 0xaf1fbda7UL, 0xd4234870UL, 0xa7870bf3UL, 0x2d3b4d79UL,
+0x42e04198UL, 0x0cd0ede7UL, 0x26470db8UL, 0xf881814cUL, 0x474d6ad7UL, 0x7c0c5e5cUL,
+0xd1231959UL, 0x381b7298UL, 0xf5d2f4dbUL, 0xab838653UL, 0x6e2f1e23UL, 0x83719c9eUL,
+0xbd91e046UL, 0x9a56456eUL, 0xdc39200cUL, 0x20c8c571UL, 0x962bda1cUL, 0xe1e696ffUL,
+0xb141ab08UL, 0x7cca89b9UL, 0x1a69e783UL, 0x02cc4843UL, 0xa2f7c579UL, 0x429ef47dUL,
+0x427b169cUL, 0x5ac9f049UL, 0xdd8f0f00UL, 0x5c8165bfUL};
+
+static const ulong32 S2[256] = {
+0x1f201094UL, 0xef0ba75bUL, 0x69e3cf7eUL, 0x393f4380UL, 0xfe61cf7aUL, 0xeec5207aUL,
+0x55889c94UL, 0x72fc0651UL, 0xada7ef79UL, 0x4e1d7235UL, 0xd55a63ceUL, 0xde0436baUL,
+0x99c430efUL, 0x5f0c0794UL, 0x18dcdb7dUL, 0xa1d6eff3UL, 0xa0b52f7bUL, 0x59e83605UL,
+0xee15b094UL, 0xe9ffd909UL, 0xdc440086UL, 0xef944459UL, 0xba83ccb3UL, 0xe0c3cdfbUL,
+0xd1da4181UL, 0x3b092ab1UL, 0xf997f1c1UL, 0xa5e6cf7bUL, 0x01420ddbUL, 0xe4e7ef5bUL,
+0x25a1ff41UL, 0xe180f806UL, 0x1fc41080UL, 0x179bee7aUL, 0xd37ac6a9UL, 0xfe5830a4UL,
+0x98de8b7fUL, 0x77e83f4eUL, 0x79929269UL, 0x24fa9f7bUL, 0xe113c85bUL, 0xacc40083UL,
+0xd7503525UL, 0xf7ea615fUL, 0x62143154UL, 0x0d554b63UL, 0x5d681121UL, 0xc866c359UL,
+0x3d63cf73UL, 0xcee234c0UL, 0xd4d87e87UL, 0x5c672b21UL, 0x071f6181UL, 0x39f7627fUL,
+0x361e3084UL, 0xe4eb573bUL, 0x602f64a4UL, 0xd63acd9cUL, 0x1bbc4635UL, 0x9e81032dUL,
+0x2701f50cUL, 0x99847ab4UL, 0xa0e3df79UL, 0xba6cf38cUL, 0x10843094UL, 0x2537a95eUL,
+0xf46f6ffeUL, 0xa1ff3b1fUL, 0x208cfb6aUL, 0x8f458c74UL, 0xd9e0a227UL, 0x4ec73a34UL,
+0xfc884f69UL, 0x3e4de8dfUL, 0xef0e0088UL, 0x3559648dUL, 0x8a45388cUL, 0x1d804366UL,
+0x721d9bfdUL, 0xa58684bbUL, 0xe8256333UL, 0x844e8212UL, 0x128d8098UL, 0xfed33fb4UL,
+0xce280ae1UL, 0x27e19ba5UL, 0xd5a6c252UL, 0xe49754bdUL, 0xc5d655ddUL, 0xeb667064UL,
+0x77840b4dUL, 0xa1b6a801UL, 0x84db26a9UL, 0xe0b56714UL, 0x21f043b7UL, 0xe5d05860UL,
+0x54f03084UL, 0x066ff472UL, 0xa31aa153UL, 0xdadc4755UL, 0xb5625dbfUL, 0x68561be6UL,
+0x83ca6b94UL, 0x2d6ed23bUL, 0xeccf01dbUL, 0xa6d3d0baUL, 0xb6803d5cUL, 0xaf77a709UL,
+0x33b4a34cUL, 0x397bc8d6UL, 0x5ee22b95UL, 0x5f0e5304UL, 0x81ed6f61UL, 0x20e74364UL,
+0xb45e1378UL, 0xde18639bUL, 0x881ca122UL, 0xb96726d1UL, 0x8049a7e8UL, 0x22b7da7bUL,
+0x5e552d25UL, 0x5272d237UL, 0x79d2951cUL, 0xc60d894cUL, 0x488cb402UL, 0x1ba4fe5bUL,
+0xa4b09f6bUL, 0x1ca815cfUL, 0xa20c3005UL, 0x8871df63UL, 0xb9de2fcbUL, 0x0cc6c9e9UL,
+0x0beeff53UL, 0xe3214517UL, 0xb4542835UL, 0x9f63293cUL, 0xee41e729UL, 0x6e1d2d7cUL,
+0x50045286UL, 0x1e6685f3UL, 0xf33401c6UL, 0x30a22c95UL, 0x31a70850UL, 0x60930f13UL,
+0x73f98417UL, 0xa1269859UL, 0xec645c44UL, 0x52c877a9UL, 0xcdff33a6UL, 0xa02b1741UL,
+0x7cbad9a2UL, 0x2180036fUL, 0x50d99c08UL, 0xcb3f4861UL, 0xc26bd765UL, 0x64a3f6abUL,
+0x80342676UL, 0x25a75e7bUL, 0xe4e6d1fcUL, 0x20c710e6UL, 0xcdf0b680UL, 0x17844d3bUL,
+0x31eef84dUL, 0x7e0824e4UL, 0x2ccb49ebUL, 0x846a3baeUL, 0x8ff77888UL, 0xee5d60f6UL,
+0x7af75673UL, 0x2fdd5cdbUL, 0xa11631c1UL, 0x30f66f43UL, 0xb3faec54UL, 0x157fd7faUL,
+0xef8579ccUL, 0xd152de58UL, 0xdb2ffd5eUL, 0x8f32ce19UL, 0x306af97aUL, 0x02f03ef8UL,
+0x99319ad5UL, 0xc242fa0fUL, 0xa7e3ebb0UL, 0xc68e4906UL, 0xb8da230cUL, 0x80823028UL,
+0xdcdef3c8UL, 0xd35fb171UL, 0x088a1bc8UL, 0xbec0c560UL, 0x61a3c9e8UL, 0xbca8f54dUL,
+0xc72feffaUL, 0x22822e99UL, 0x82c570b4UL, 0xd8d94e89UL, 0x8b1c34bcUL, 0x301e16e6UL,
+0x273be979UL, 0xb0ffeaa6UL, 0x61d9b8c6UL, 0x00b24869UL, 0xb7ffce3fUL, 0x08dc283bUL,
+0x43daf65aUL, 0xf7e19798UL, 0x7619b72fUL, 0x8f1c9ba4UL, 0xdc8637a0UL, 0x16a7d3b1UL,
+0x9fc393b7UL, 0xa7136eebUL, 0xc6bcc63eUL, 0x1a513742UL, 0xef6828bcUL, 0x520365d6UL,
+0x2d6a77abUL, 0x3527ed4bUL, 0x821fd216UL, 0x095c6e2eUL, 0xdb92f2fbUL, 0x5eea29cbUL,
+0x145892f5UL, 0x91584f7fUL, 0x5483697bUL, 0x2667a8ccUL, 0x85196048UL, 0x8c4baceaUL,
+0x833860d4UL, 0x0d23e0f9UL, 0x6c387e8aUL, 0x0ae6d249UL, 0xb284600cUL, 0xd835731dUL,
+0xdcb1c647UL, 0xac4c56eaUL, 0x3ebd81b3UL, 0x230eabb0UL, 0x6438bc87UL, 0xf0b5b1faUL,
+0x8f5ea2b3UL, 0xfc184642UL, 0x0a036b7aUL, 0x4fb089bdUL, 0x649da589UL, 0xa345415eUL,
+0x5c038323UL, 0x3e5d3bb9UL, 0x43d79572UL, 0x7e6dd07cUL, 0x06dfdf1eUL, 0x6c6cc4efUL,
+0x7160a539UL, 0x73bfbe70UL, 0x83877605UL, 0x4523ecf1UL};
+
+static const ulong32 S3[256] = {
+0x8defc240UL, 0x25fa5d9fUL, 0xeb903dbfUL, 0xe810c907UL, 0x47607fffUL, 0x369fe44bUL,
+0x8c1fc644UL, 0xaececa90UL, 0xbeb1f9bfUL, 0xeefbcaeaUL, 0xe8cf1950UL, 0x51df07aeUL,
+0x920e8806UL, 0xf0ad0548UL, 0xe13c8d83UL, 0x927010d5UL, 0x11107d9fUL, 0x07647db9UL,
+0xb2e3e4d4UL, 0x3d4f285eUL, 0xb9afa820UL, 0xfade82e0UL, 0xa067268bUL, 0x8272792eUL,
+0x553fb2c0UL, 0x489ae22bUL, 0xd4ef9794UL, 0x125e3fbcUL, 0x21fffceeUL, 0x825b1bfdUL,
+0x9255c5edUL, 0x1257a240UL, 0x4e1a8302UL, 0xbae07fffUL, 0x528246e7UL, 0x8e57140eUL,
+0x3373f7bfUL, 0x8c9f8188UL, 0xa6fc4ee8UL, 0xc982b5a5UL, 0xa8c01db7UL, 0x579fc264UL,
+0x67094f31UL, 0xf2bd3f5fUL, 0x40fff7c1UL, 0x1fb78dfcUL, 0x8e6bd2c1UL, 0x437be59bUL,
+0x99b03dbfUL, 0xb5dbc64bUL, 0x638dc0e6UL, 0x55819d99UL, 0xa197c81cUL, 0x4a012d6eUL,
+0xc5884a28UL, 0xccc36f71UL, 0xb843c213UL, 0x6c0743f1UL, 0x8309893cUL, 0x0feddd5fUL,
+0x2f7fe850UL, 0xd7c07f7eUL, 0x02507fbfUL, 0x5afb9a04UL, 0xa747d2d0UL, 0x1651192eUL,
+0xaf70bf3eUL, 0x58c31380UL, 0x5f98302eUL, 0x727cc3c4UL, 0x0a0fb402UL, 0x0f7fef82UL,
+0x8c96fdadUL, 0x5d2c2aaeUL, 0x8ee99a49UL, 0x50da88b8UL, 0x8427f4a0UL, 0x1eac5790UL,
+0x796fb449UL, 0x8252dc15UL, 0xefbd7d9bUL, 0xa672597dUL, 0xada840d8UL, 0x45f54504UL,
+0xfa5d7403UL, 0xe83ec305UL, 0x4f91751aUL, 0x925669c2UL, 0x23efe941UL, 0xa903f12eUL,
+0x60270df2UL, 0x0276e4b6UL, 0x94fd6574UL, 0x927985b2UL, 0x8276dbcbUL, 0x02778176UL,
+0xf8af918dUL, 0x4e48f79eUL, 0x8f616ddfUL, 0xe29d840eUL, 0x842f7d83UL, 0x340ce5c8UL,
+0x96bbb682UL, 0x93b4b148UL, 0xef303cabUL, 0x984faf28UL, 0x779faf9bUL, 0x92dc560dUL,
+0x224d1e20UL, 0x8437aa88UL, 0x7d29dc96UL, 0x2756d3dcUL, 0x8b907ceeUL, 0xb51fd240UL,
+0xe7c07ce3UL, 0xe566b4a1UL, 0xc3e9615eUL, 0x3cf8209dUL, 0x6094d1e3UL, 0xcd9ca341UL,
+0x5c76460eUL, 0x00ea983bUL, 0xd4d67881UL, 0xfd47572cUL, 0xf76cedd9UL, 0xbda8229cUL,
+0x127dadaaUL, 0x438a074eUL, 0x1f97c090UL, 0x081bdb8aUL, 0x93a07ebeUL, 0xb938ca15UL,
+0x97b03cffUL, 0x3dc2c0f8UL, 0x8d1ab2ecUL, 0x64380e51UL, 0x68cc7bfbUL, 0xd90f2788UL,
+0x12490181UL, 0x5de5ffd4UL, 0xdd7ef86aUL, 0x76a2e214UL, 0xb9a40368UL, 0x925d958fUL,
+0x4b39fffaUL, 0xba39aee9UL, 0xa4ffd30bUL, 0xfaf7933bUL, 0x6d498623UL, 0x193cbcfaUL,
+0x27627545UL, 0x825cf47aUL, 0x61bd8ba0UL, 0xd11e42d1UL, 0xcead04f4UL, 0x127ea392UL,
+0x10428db7UL, 0x8272a972UL, 0x9270c4a8UL, 0x127de50bUL, 0x285ba1c8UL, 0x3c62f44fUL,
+0x35c0eaa5UL, 0xe805d231UL, 0x428929fbUL, 0xb4fcdf82UL, 0x4fb66a53UL, 0x0e7dc15bUL,
+0x1f081fabUL, 0x108618aeUL, 0xfcfd086dUL, 0xf9ff2889UL, 0x694bcc11UL, 0x236a5caeUL,
+0x12deca4dUL, 0x2c3f8cc5UL, 0xd2d02dfeUL, 0xf8ef5896UL, 0xe4cf52daUL, 0x95155b67UL,
+0x494a488cUL, 0xb9b6a80cUL, 0x5c8f82bcUL, 0x89d36b45UL, 0x3a609437UL, 0xec00c9a9UL,
+0x44715253UL, 0x0a874b49UL, 0xd773bc40UL, 0x7c34671cUL, 0x02717ef6UL, 0x4feb5536UL,
+0xa2d02fffUL, 0xd2bf60c4UL, 0xd43f03c0UL, 0x50b4ef6dUL, 0x07478cd1UL, 0x006e1888UL,
+0xa2e53f55UL, 0xb9e6d4bcUL, 0xa2048016UL, 0x97573833UL, 0xd7207d67UL, 0xde0f8f3dUL,
+0x72f87b33UL, 0xabcc4f33UL, 0x7688c55dUL, 0x7b00a6b0UL, 0x947b0001UL, 0x570075d2UL,
+0xf9bb88f8UL, 0x8942019eUL, 0x4264a5ffUL, 0x856302e0UL, 0x72dbd92bUL, 0xee971b69UL,
+0x6ea22fdeUL, 0x5f08ae2bUL, 0xaf7a616dUL, 0xe5c98767UL, 0xcf1febd2UL, 0x61efc8c2UL,
+0xf1ac2571UL, 0xcc8239c2UL, 0x67214cb8UL, 0xb1e583d1UL, 0xb7dc3e62UL, 0x7f10bdceUL,
+0xf90a5c38UL, 0x0ff0443dUL, 0x606e6dc6UL, 0x60543a49UL, 0x5727c148UL, 0x2be98a1dUL,
+0x8ab41738UL, 0x20e1be24UL, 0xaf96da0fUL, 0x68458425UL, 0x99833be5UL, 0x600d457dUL,
+0x282f9350UL, 0x8334b362UL, 0xd91d1120UL, 0x2b6d8da0UL, 0x642b1e31UL, 0x9c305a00UL,
+0x52bce688UL, 0x1b03588aUL, 0xf7baefd5UL, 0x4142ed9cUL, 0xa4315c11UL, 0x83323ec5UL,
+0xdfef4636UL, 0xa133c501UL, 0xe9d3531cUL, 0xee353783UL};
+
+static const ulong32 S4[256] = {
+0x9db30420UL, 0x1fb6e9deUL, 0xa7be7befUL, 0xd273a298UL, 0x4a4f7bdbUL, 0x64ad8c57UL,
+0x85510443UL, 0xfa020ed1UL, 0x7e287affUL, 0xe60fb663UL, 0x095f35a1UL, 0x79ebf120UL,
+0xfd059d43UL, 0x6497b7b1UL, 0xf3641f63UL, 0x241e4adfUL, 0x28147f5fUL, 0x4fa2b8cdUL,
+0xc9430040UL, 0x0cc32220UL, 0xfdd30b30UL, 0xc0a5374fUL, 0x1d2d00d9UL, 0x24147b15UL,
+0xee4d111aUL, 0x0fca5167UL, 0x71ff904cUL, 0x2d195ffeUL, 0x1a05645fUL, 0x0c13fefeUL,
+0x081b08caUL, 0x05170121UL, 0x80530100UL, 0xe83e5efeUL, 0xac9af4f8UL, 0x7fe72701UL,
+0xd2b8ee5fUL, 0x06df4261UL, 0xbb9e9b8aUL, 0x7293ea25UL, 0xce84ffdfUL, 0xf5718801UL,
+0x3dd64b04UL, 0xa26f263bUL, 0x7ed48400UL, 0x547eebe6UL, 0x446d4ca0UL, 0x6cf3d6f5UL,
+0x2649abdfUL, 0xaea0c7f5UL, 0x36338cc1UL, 0x503f7e93UL, 0xd3772061UL, 0x11b638e1UL,
+0x72500e03UL, 0xf80eb2bbUL, 0xabe0502eUL, 0xec8d77deUL, 0x57971e81UL, 0xe14f6746UL,
+0xc9335400UL, 0x6920318fUL, 0x081dbb99UL, 0xffc304a5UL, 0x4d351805UL, 0x7f3d5ce3UL,
+0xa6c866c6UL, 0x5d5bcca9UL, 0xdaec6feaUL, 0x9f926f91UL, 0x9f46222fUL, 0x3991467dUL,
+0xa5bf6d8eUL, 0x1143c44fUL, 0x43958302UL, 0xd0214eebUL, 0x022083b8UL, 0x3fb6180cUL,
+0x18f8931eUL, 0x281658e6UL, 0x26486e3eUL, 0x8bd78a70UL, 0x7477e4c1UL, 0xb506e07cUL,
+0xf32d0a25UL, 0x79098b02UL, 0xe4eabb81UL, 0x28123b23UL, 0x69dead38UL, 0x1574ca16UL,
+0xdf871b62UL, 0x211c40b7UL, 0xa51a9ef9UL, 0x0014377bUL, 0x041e8ac8UL, 0x09114003UL,
+0xbd59e4d2UL, 0xe3d156d5UL, 0x4fe876d5UL, 0x2f91a340UL, 0x557be8deUL, 0x00eae4a7UL,
+0x0ce5c2ecUL, 0x4db4bba6UL, 0xe756bdffUL, 0xdd3369acUL, 0xec17b035UL, 0x06572327UL,
+0x99afc8b0UL, 0x56c8c391UL, 0x6b65811cUL, 0x5e146119UL, 0x6e85cb75UL, 0xbe07c002UL,
+0xc2325577UL, 0x893ff4ecUL, 0x5bbfc92dUL, 0xd0ec3b25UL, 0xb7801ab7UL, 0x8d6d3b24UL,
+0x20c763efUL, 0xc366a5fcUL, 0x9c382880UL, 0x0ace3205UL, 0xaac9548aUL, 0xeca1d7c7UL,
+0x041afa32UL, 0x1d16625aUL, 0x6701902cUL, 0x9b757a54UL, 0x31d477f7UL, 0x9126b031UL,
+0x36cc6fdbUL, 0xc70b8b46UL, 0xd9e66a48UL, 0x56e55a79UL, 0x026a4cebUL, 0x52437effUL,
+0x2f8f76b4UL, 0x0df980a5UL, 0x8674cde3UL, 0xedda04ebUL, 0x17a9be04UL, 0x2c18f4dfUL,
+0xb7747f9dUL, 0xab2af7b4UL, 0xefc34d20UL, 0x2e096b7cUL, 0x1741a254UL, 0xe5b6a035UL,
+0x213d42f6UL, 0x2c1c7c26UL, 0x61c2f50fUL, 0x6552daf9UL, 0xd2c231f8UL, 0x25130f69UL,
+0xd8167fa2UL, 0x0418f2c8UL, 0x001a96a6UL, 0x0d1526abUL, 0x63315c21UL, 0x5e0a72ecUL,
+0x49bafefdUL, 0x187908d9UL, 0x8d0dbd86UL, 0x311170a7UL, 0x3e9b640cUL, 0xcc3e10d7UL,
+0xd5cad3b6UL, 0x0caec388UL, 0xf73001e1UL, 0x6c728affUL, 0x71eae2a1UL, 0x1f9af36eUL,
+0xcfcbd12fUL, 0xc1de8417UL, 0xac07be6bUL, 0xcb44a1d8UL, 0x8b9b0f56UL, 0x013988c3UL,
+0xb1c52fcaUL, 0xb4be31cdUL, 0xd8782806UL, 0x12a3a4e2UL, 0x6f7de532UL, 0x58fd7eb6UL,
+0xd01ee900UL, 0x24adffc2UL, 0xf4990fc5UL, 0x9711aac5UL, 0x001d7b95UL, 0x82e5e7d2UL,
+0x109873f6UL, 0x00613096UL, 0xc32d9521UL, 0xada121ffUL, 0x29908415UL, 0x7fbb977fUL,
+0xaf9eb3dbUL, 0x29c9ed2aUL, 0x5ce2a465UL, 0xa730f32cUL, 0xd0aa3fe8UL, 0x8a5cc091UL,
+0xd49e2ce7UL, 0x0ce454a9UL, 0xd60acd86UL, 0x015f1919UL, 0x77079103UL, 0xdea03af6UL,
+0x78a8565eUL, 0xdee356dfUL, 0x21f05cbeUL, 0x8b75e387UL, 0xb3c50651UL, 0xb8a5c3efUL,
+0xd8eeb6d2UL, 0xe523be77UL, 0xc2154529UL, 0x2f69efdfUL, 0xafe67afbUL, 0xf470c4b2UL,
+0xf3e0eb5bUL, 0xd6cc9876UL, 0x39e4460cUL, 0x1fda8538UL, 0x1987832fUL, 0xca007367UL,
+0xa99144f8UL, 0x296b299eUL, 0x492fc295UL, 0x9266beabUL, 0xb5676e69UL, 0x9bd3dddaUL,
+0xdf7e052fUL, 0xdb25701cUL, 0x1b5e51eeUL, 0xf65324e6UL, 0x6afce36cUL, 0x0316cc04UL,
+0x8644213eUL, 0xb7dc59d0UL, 0x7965291fUL, 0xccd6fd43UL, 0x41823979UL, 0x932bcdf6UL,
+0xb657c34dUL, 0x4edfd282UL, 0x7ae5290cUL, 0x3cb9536bUL, 0x851e20feUL, 0x9833557eUL,
+0x13ecf0b0UL, 0xd3ffb372UL, 0x3f85c5c1UL, 0x0aef7ed2UL};
+
+static const ulong32 S5[256] = {
+0x7ec90c04UL, 0x2c6e74b9UL, 0x9b0e66dfUL, 0xa6337911UL, 0xb86a7fffUL, 0x1dd358f5UL,
+0x44dd9d44UL, 0x1731167fUL, 0x08fbf1faUL, 0xe7f511ccUL, 0xd2051b00UL, 0x735aba00UL,
+0x2ab722d8UL, 0x386381cbUL, 0xacf6243aUL, 0x69befd7aUL, 0xe6a2e77fUL, 0xf0c720cdUL,
+0xc4494816UL, 0xccf5c180UL, 0x38851640UL, 0x15b0a848UL, 0xe68b18cbUL, 0x4caadeffUL,
+0x5f480a01UL, 0x0412b2aaUL, 0x259814fcUL, 0x41d0efe2UL, 0x4e40b48dUL, 0x248eb6fbUL,
+0x8dba1cfeUL, 0x41a99b02UL, 0x1a550a04UL, 0xba8f65cbUL, 0x7251f4e7UL, 0x95a51725UL,
+0xc106ecd7UL, 0x97a5980aUL, 0xc539b9aaUL, 0x4d79fe6aUL, 0xf2f3f763UL, 0x68af8040UL,
+0xed0c9e56UL, 0x11b4958bUL, 0xe1eb5a88UL, 0x8709e6b0UL, 0xd7e07156UL, 0x4e29fea7UL,
+0x6366e52dUL, 0x02d1c000UL, 0xc4ac8e05UL, 0x9377f571UL, 0x0c05372aUL, 0x578535f2UL,
+0x2261be02UL, 0xd642a0c9UL, 0xdf13a280UL, 0x74b55bd2UL, 0x682199c0UL, 0xd421e5ecUL,
+0x53fb3ce8UL, 0xc8adedb3UL, 0x28a87fc9UL, 0x3d959981UL, 0x5c1ff900UL, 0xfe38d399UL,
+0x0c4eff0bUL, 0x062407eaUL, 0xaa2f4fb1UL, 0x4fb96976UL, 0x90c79505UL, 0xb0a8a774UL,
+0xef55a1ffUL, 0xe59ca2c2UL, 0xa6b62d27UL, 0xe66a4263UL, 0xdf65001fUL, 0x0ec50966UL,
+0xdfdd55bcUL, 0x29de0655UL, 0x911e739aUL, 0x17af8975UL, 0x32c7911cUL, 0x89f89468UL,
+0x0d01e980UL, 0x524755f4UL, 0x03b63cc9UL, 0x0cc844b2UL, 0xbcf3f0aaUL, 0x87ac36e9UL,
+0xe53a7426UL, 0x01b3d82bUL, 0x1a9e7449UL, 0x64ee2d7eUL, 0xcddbb1daUL, 0x01c94910UL,
+0xb868bf80UL, 0x0d26f3fdUL, 0x9342ede7UL, 0x04a5c284UL, 0x636737b6UL, 0x50f5b616UL,
+0xf24766e3UL, 0x8eca36c1UL, 0x136e05dbUL, 0xfef18391UL, 0xfb887a37UL, 0xd6e7f7d4UL,
+0xc7fb7dc9UL, 0x3063fcdfUL, 0xb6f589deUL, 0xec2941daUL, 0x26e46695UL, 0xb7566419UL,
+0xf654efc5UL, 0xd08d58b7UL, 0x48925401UL, 0xc1bacb7fUL, 0xe5ff550fUL, 0xb6083049UL,
+0x5bb5d0e8UL, 0x87d72e5aUL, 0xab6a6ee1UL, 0x223a66ceUL, 0xc62bf3cdUL, 0x9e0885f9UL,
+0x68cb3e47UL, 0x086c010fUL, 0xa21de820UL, 0xd18b69deUL, 0xf3f65777UL, 0xfa02c3f6UL,
+0x407edac3UL, 0xcbb3d550UL, 0x1793084dUL, 0xb0d70ebaUL, 0x0ab378d5UL, 0xd951fb0cUL,
+0xded7da56UL, 0x4124bbe4UL, 0x94ca0b56UL, 0x0f5755d1UL, 0xe0e1e56eUL, 0x6184b5beUL,
+0x580a249fUL, 0x94f74bc0UL, 0xe327888eUL, 0x9f7b5561UL, 0xc3dc0280UL, 0x05687715UL,
+0x646c6bd7UL, 0x44904db3UL, 0x66b4f0a3UL, 0xc0f1648aUL, 0x697ed5afUL, 0x49e92ff6UL,
+0x309e374fUL, 0x2cb6356aUL, 0x85808573UL, 0x4991f840UL, 0x76f0ae02UL, 0x083be84dUL,
+0x28421c9aUL, 0x44489406UL, 0x736e4cb8UL, 0xc1092910UL, 0x8bc95fc6UL, 0x7d869cf4UL,
+0x134f616fUL, 0x2e77118dUL, 0xb31b2be1UL, 0xaa90b472UL, 0x3ca5d717UL, 0x7d161bbaUL,
+0x9cad9010UL, 0xaf462ba2UL, 0x9fe459d2UL, 0x45d34559UL, 0xd9f2da13UL, 0xdbc65487UL,
+0xf3e4f94eUL, 0x176d486fUL, 0x097c13eaUL, 0x631da5c7UL, 0x445f7382UL, 0x175683f4UL,
+0xcdc66a97UL, 0x70be0288UL, 0xb3cdcf72UL, 0x6e5dd2f3UL, 0x20936079UL, 0x459b80a5UL,
+0xbe60e2dbUL, 0xa9c23101UL, 0xeba5315cUL, 0x224e42f2UL, 0x1c5c1572UL, 0xf6721b2cUL,
+0x1ad2fff3UL, 0x8c25404eUL, 0x324ed72fUL, 0x4067b7fdUL, 0x0523138eUL, 0x5ca3bc78UL,
+0xdc0fd66eUL, 0x75922283UL, 0x784d6b17UL, 0x58ebb16eUL, 0x44094f85UL, 0x3f481d87UL,
+0xfcfeae7bUL, 0x77b5ff76UL, 0x8c2302bfUL, 0xaaf47556UL, 0x5f46b02aUL, 0x2b092801UL,
+0x3d38f5f7UL, 0x0ca81f36UL, 0x52af4a8aUL, 0x66d5e7c0UL, 0xdf3b0874UL, 0x95055110UL,
+0x1b5ad7a8UL, 0xf61ed5adUL, 0x6cf6e479UL, 0x20758184UL, 0xd0cefa65UL, 0x88f7be58UL,
+0x4a046826UL, 0x0ff6f8f3UL, 0xa09c7f70UL, 0x5346aba0UL, 0x5ce96c28UL, 0xe176eda3UL,
+0x6bac307fUL, 0x376829d2UL, 0x85360fa9UL, 0x17e3fe2aUL, 0x24b79767UL, 0xf5a96b20UL,
+0xd6cd2595UL, 0x68ff1ebfUL, 0x7555442cUL, 0xf19f06beUL, 0xf9e0659aUL, 0xeeb9491dUL,
+0x34010718UL, 0xbb30cab8UL, 0xe822fe15UL, 0x88570983UL, 0x750e6249UL, 0xda627e55UL,
+0x5e76ffa8UL, 0xb1534546UL, 0x6d47de08UL, 0xefe9e7d4UL};
+
+static const ulong32 S6[256] = {
+0xf6fa8f9dUL, 0x2cac6ce1UL, 0x4ca34867UL, 0xe2337f7cUL, 0x95db08e7UL, 0x016843b4UL,
+0xeced5cbcUL, 0x325553acUL, 0xbf9f0960UL, 0xdfa1e2edUL, 0x83f0579dUL, 0x63ed86b9UL,
+0x1ab6a6b8UL, 0xde5ebe39UL, 0xf38ff732UL, 0x8989b138UL, 0x33f14961UL, 0xc01937bdUL,
+0xf506c6daUL, 0xe4625e7eUL, 0xa308ea99UL, 0x4e23e33cUL, 0x79cbd7ccUL, 0x48a14367UL,
+0xa3149619UL, 0xfec94bd5UL, 0xa114174aUL, 0xeaa01866UL, 0xa084db2dUL, 0x09a8486fUL,
+0xa888614aUL, 0x2900af98UL, 0x01665991UL, 0xe1992863UL, 0xc8f30c60UL, 0x2e78ef3cUL,
+0xd0d51932UL, 0xcf0fec14UL, 0xf7ca07d2UL, 0xd0a82072UL, 0xfd41197eUL, 0x9305a6b0UL,
+0xe86be3daUL, 0x74bed3cdUL, 0x372da53cUL, 0x4c7f4448UL, 0xdab5d440UL, 0x6dba0ec3UL,
+0x083919a7UL, 0x9fbaeed9UL, 0x49dbcfb0UL, 0x4e670c53UL, 0x5c3d9c01UL, 0x64bdb941UL,
+0x2c0e636aUL, 0xba7dd9cdUL, 0xea6f7388UL, 0xe70bc762UL, 0x35f29adbUL, 0x5c4cdd8dUL,
+0xf0d48d8cUL, 0xb88153e2UL, 0x08a19866UL, 0x1ae2eac8UL, 0x284caf89UL, 0xaa928223UL,
+0x9334be53UL, 0x3b3a21bfUL, 0x16434be3UL, 0x9aea3906UL, 0xefe8c36eUL, 0xf890cdd9UL,
+0x80226daeUL, 0xc340a4a3UL, 0xdf7e9c09UL, 0xa694a807UL, 0x5b7c5eccUL, 0x221db3a6UL,
+0x9a69a02fUL, 0x68818a54UL, 0xceb2296fUL, 0x53c0843aUL, 0xfe893655UL, 0x25bfe68aUL,
+0xb4628abcUL, 0xcf222ebfUL, 0x25ac6f48UL, 0xa9a99387UL, 0x53bddb65UL, 0xe76ffbe7UL,
+0xe967fd78UL, 0x0ba93563UL, 0x8e342bc1UL, 0xe8a11be9UL, 0x4980740dUL, 0xc8087dfcUL,
+0x8de4bf99UL, 0xa11101a0UL, 0x7fd37975UL, 0xda5a26c0UL, 0xe81f994fUL, 0x9528cd89UL,
+0xfd339fedUL, 0xb87834bfUL, 0x5f04456dUL, 0x22258698UL, 0xc9c4c83bUL, 0x2dc156beUL,
+0x4f628daaUL, 0x57f55ec5UL, 0xe2220abeUL, 0xd2916ebfUL, 0x4ec75b95UL, 0x24f2c3c0UL,
+0x42d15d99UL, 0xcd0d7fa0UL, 0x7b6e27ffUL, 0xa8dc8af0UL, 0x7345c106UL, 0xf41e232fUL,
+0x35162386UL, 0xe6ea8926UL, 0x3333b094UL, 0x157ec6f2UL, 0x372b74afUL, 0x692573e4UL,
+0xe9a9d848UL, 0xf3160289UL, 0x3a62ef1dUL, 0xa787e238UL, 0xf3a5f676UL, 0x74364853UL,
+0x20951063UL, 0x4576698dUL, 0xb6fad407UL, 0x592af950UL, 0x36f73523UL, 0x4cfb6e87UL,
+0x7da4cec0UL, 0x6c152daaUL, 0xcb0396a8UL, 0xc50dfe5dUL, 0xfcd707abUL, 0x0921c42fUL,
+0x89dff0bbUL, 0x5fe2be78UL, 0x448f4f33UL, 0x754613c9UL, 0x2b05d08dUL, 0x48b9d585UL,
+0xdc049441UL, 0xc8098f9bUL, 0x7dede786UL, 0xc39a3373UL, 0x42410005UL, 0x6a091751UL,
+0x0ef3c8a6UL, 0x890072d6UL, 0x28207682UL, 0xa9a9f7beUL, 0xbf32679dUL, 0xd45b5b75UL,
+0xb353fd00UL, 0xcbb0e358UL, 0x830f220aUL, 0x1f8fb214UL, 0xd372cf08UL, 0xcc3c4a13UL,
+0x8cf63166UL, 0x061c87beUL, 0x88c98f88UL, 0x6062e397UL, 0x47cf8e7aUL, 0xb6c85283UL,
+0x3cc2acfbUL, 0x3fc06976UL, 0x4e8f0252UL, 0x64d8314dUL, 0xda3870e3UL, 0x1e665459UL,
+0xc10908f0UL, 0x513021a5UL, 0x6c5b68b7UL, 0x822f8aa0UL, 0x3007cd3eUL, 0x74719eefUL,
+0xdc872681UL, 0x073340d4UL, 0x7e432fd9UL, 0x0c5ec241UL, 0x8809286cUL, 0xf592d891UL,
+0x08a930f6UL, 0x957ef305UL, 0xb7fbffbdUL, 0xc266e96fUL, 0x6fe4ac98UL, 0xb173ecc0UL,
+0xbc60b42aUL, 0x953498daUL, 0xfba1ae12UL, 0x2d4bd736UL, 0x0f25faabUL, 0xa4f3fcebUL,
+0xe2969123UL, 0x257f0c3dUL, 0x9348af49UL, 0x361400bcUL, 0xe8816f4aUL, 0x3814f200UL,
+0xa3f94043UL, 0x9c7a54c2UL, 0xbc704f57UL, 0xda41e7f9UL, 0xc25ad33aUL, 0x54f4a084UL,
+0xb17f5505UL, 0x59357cbeUL, 0xedbd15c8UL, 0x7f97c5abUL, 0xba5ac7b5UL, 0xb6f6deafUL,
+0x3a479c3aUL, 0x5302da25UL, 0x653d7e6aUL, 0x54268d49UL, 0x51a477eaUL, 0x5017d55bUL,
+0xd7d25d88UL, 0x44136c76UL, 0x0404a8c8UL, 0xb8e5a121UL, 0xb81a928aUL, 0x60ed5869UL,
+0x97c55b96UL, 0xeaec991bUL, 0x29935913UL, 0x01fdb7f1UL, 0x088e8dfaUL, 0x9ab6f6f5UL,
+0x3b4cbf9fUL, 0x4a5de3abUL, 0xe6051d35UL, 0xa0e1d855UL, 0xd36b4cf1UL, 0xf544edebUL,
+0xb0e93524UL, 0xbebb8fbdUL, 0xa2d762cfUL, 0x49c92f54UL, 0x38b5f331UL, 0x7128a454UL,
+0x48392905UL, 0xa65b1db8UL, 0x851c97bdUL, 0xd675cf2fUL};
+
+static const ulong32 S7[256] = {
+0x85e04019UL, 0x332bf567UL, 0x662dbfffUL, 0xcfc65693UL, 0x2a8d7f6fUL, 0xab9bc912UL,
+0xde6008a1UL, 0x2028da1fUL, 0x0227bce7UL, 0x4d642916UL, 0x18fac300UL, 0x50f18b82UL,
+0x2cb2cb11UL, 0xb232e75cUL, 0x4b3695f2UL, 0xb28707deUL, 0xa05fbcf6UL, 0xcd4181e9UL,
+0xe150210cUL, 0xe24ef1bdUL, 0xb168c381UL, 0xfde4e789UL, 0x5c79b0d8UL, 0x1e8bfd43UL,
+0x4d495001UL, 0x38be4341UL, 0x913cee1dUL, 0x92a79c3fUL, 0x089766beUL, 0xbaeeadf4UL,
+0x1286becfUL, 0xb6eacb19UL, 0x2660c200UL, 0x7565bde4UL, 0x64241f7aUL, 0x8248dca9UL,
+0xc3b3ad66UL, 0x28136086UL, 0x0bd8dfa8UL, 0x356d1cf2UL, 0x107789beUL, 0xb3b2e9ceUL,
+0x0502aa8fUL, 0x0bc0351eUL, 0x166bf52aUL, 0xeb12ff82UL, 0xe3486911UL, 0xd34d7516UL,
+0x4e7b3affUL, 0x5f43671bUL, 0x9cf6e037UL, 0x4981ac83UL, 0x334266ceUL, 0x8c9341b7UL,
+0xd0d854c0UL, 0xcb3a6c88UL, 0x47bc2829UL, 0x4725ba37UL, 0xa66ad22bUL, 0x7ad61f1eUL,
+0x0c5cbafaUL, 0x4437f107UL, 0xb6e79962UL, 0x42d2d816UL, 0x0a961288UL, 0xe1a5c06eUL,
+0x13749e67UL, 0x72fc081aUL, 0xb1d139f7UL, 0xf9583745UL, 0xcf19df58UL, 0xbec3f756UL,
+0xc06eba30UL, 0x07211b24UL, 0x45c28829UL, 0xc95e317fUL, 0xbc8ec511UL, 0x38bc46e9UL,
+0xc6e6fa14UL, 0xbae8584aUL, 0xad4ebc46UL, 0x468f508bUL, 0x7829435fUL, 0xf124183bUL,
+0x821dba9fUL, 0xaff60ff4UL, 0xea2c4e6dUL, 0x16e39264UL, 0x92544a8bUL, 0x009b4fc3UL,
+0xaba68cedUL, 0x9ac96f78UL, 0x06a5b79aUL, 0xb2856e6eUL, 0x1aec3ca9UL, 0xbe838688UL,
+0x0e0804e9UL, 0x55f1be56UL, 0xe7e5363bUL, 0xb3a1f25dUL, 0xf7debb85UL, 0x61fe033cUL,
+0x16746233UL, 0x3c034c28UL, 0xda6d0c74UL, 0x79aac56cUL, 0x3ce4e1adUL, 0x51f0c802UL,
+0x98f8f35aUL, 0x1626a49fUL, 0xeed82b29UL, 0x1d382fe3UL, 0x0c4fb99aUL, 0xbb325778UL,
+0x3ec6d97bUL, 0x6e77a6a9UL, 0xcb658b5cUL, 0xd45230c7UL, 0x2bd1408bUL, 0x60c03eb7UL,
+0xb9068d78UL, 0xa33754f4UL, 0xf430c87dUL, 0xc8a71302UL, 0xb96d8c32UL, 0xebd4e7beUL,
+0xbe8b9d2dUL, 0x7979fb06UL, 0xe7225308UL, 0x8b75cf77UL, 0x11ef8da4UL, 0xe083c858UL,
+0x8d6b786fUL, 0x5a6317a6UL, 0xfa5cf7a0UL, 0x5dda0033UL, 0xf28ebfb0UL, 0xf5b9c310UL,
+0xa0eac280UL, 0x08b9767aUL, 0xa3d9d2b0UL, 0x79d34217UL, 0x021a718dUL, 0x9ac6336aUL,
+0x2711fd60UL, 0x438050e3UL, 0x069908a8UL, 0x3d7fedc4UL, 0x826d2befUL, 0x4eeb8476UL,
+0x488dcf25UL, 0x36c9d566UL, 0x28e74e41UL, 0xc2610acaUL, 0x3d49a9cfUL, 0xbae3b9dfUL,
+0xb65f8de6UL, 0x92aeaf64UL, 0x3ac7d5e6UL, 0x9ea80509UL, 0xf22b017dUL, 0xa4173f70UL,
+0xdd1e16c3UL, 0x15e0d7f9UL, 0x50b1b887UL, 0x2b9f4fd5UL, 0x625aba82UL, 0x6a017962UL,
+0x2ec01b9cUL, 0x15488aa9UL, 0xd716e740UL, 0x40055a2cUL, 0x93d29a22UL, 0xe32dbf9aUL,
+0x058745b9UL, 0x3453dc1eUL, 0xd699296eUL, 0x496cff6fUL, 0x1c9f4986UL, 0xdfe2ed07UL,
+0xb87242d1UL, 0x19de7eaeUL, 0x053e561aUL, 0x15ad6f8cUL, 0x66626c1cUL, 0x7154c24cUL,
+0xea082b2aUL, 0x93eb2939UL, 0x17dcb0f0UL, 0x58d4f2aeUL, 0x9ea294fbUL, 0x52cf564cUL,
+0x9883fe66UL, 0x2ec40581UL, 0x763953c3UL, 0x01d6692eUL, 0xd3a0c108UL, 0xa1e7160eUL,
+0xe4f2dfa6UL, 0x693ed285UL, 0x74904698UL, 0x4c2b0eddUL, 0x4f757656UL, 0x5d393378UL,
+0xa132234fUL, 0x3d321c5dUL, 0xc3f5e194UL, 0x4b269301UL, 0xc79f022fUL, 0x3c997e7eUL,
+0x5e4f9504UL, 0x3ffafbbdUL, 0x76f7ad0eUL, 0x296693f4UL, 0x3d1fce6fUL, 0xc61e45beUL,
+0xd3b5ab34UL, 0xf72bf9b7UL, 0x1b0434c0UL, 0x4e72b567UL, 0x5592a33dUL, 0xb5229301UL,
+0xcfd2a87fUL, 0x60aeb767UL, 0x1814386bUL, 0x30bcc33dUL, 0x38a0c07dUL, 0xfd1606f2UL,
+0xc363519bUL, 0x589dd390UL, 0x5479f8e6UL, 0x1cb8d647UL, 0x97fd61a9UL, 0xea7759f4UL,
+0x2d57539dUL, 0x569a58cfUL, 0xe84e63adUL, 0x462e1b78UL, 0x6580f87eUL, 0xf3817914UL,
+0x91da55f4UL, 0x40a230f3UL, 0xd1988f35UL, 0xb6e318d2UL, 0x3ffa50bcUL, 0x3d40f021UL,
+0xc3c0bdaeUL, 0x4958c24cUL, 0x518f36b2UL, 0x84b1d370UL, 0x0fedce83UL, 0x878ddadaUL,
+0xf2a279c7UL, 0x94e01be8UL, 0x90716f4bUL, 0x954b8aa3UL};
+
+static const ulong32 S8[256] = {
+0xe216300dUL, 0xbbddfffcUL, 0xa7ebdabdUL, 0x35648095UL, 0x7789f8b7UL, 0xe6c1121bUL,
+0x0e241600UL, 0x052ce8b5UL, 0x11a9cfb0UL, 0xe5952f11UL, 0xece7990aUL, 0x9386d174UL,
+0x2a42931cUL, 0x76e38111UL, 0xb12def3aUL, 0x37ddddfcUL, 0xde9adeb1UL, 0x0a0cc32cUL,
+0xbe197029UL, 0x84a00940UL, 0xbb243a0fUL, 0xb4d137cfUL, 0xb44e79f0UL, 0x049eedfdUL,
+0x0b15a15dUL, 0x480d3168UL, 0x8bbbde5aUL, 0x669ded42UL, 0xc7ece831UL, 0x3f8f95e7UL,
+0x72df191bUL, 0x7580330dUL, 0x94074251UL, 0x5c7dcdfaUL, 0xabbe6d63UL, 0xaa402164UL,
+0xb301d40aUL, 0x02e7d1caUL, 0x53571daeUL, 0x7a3182a2UL, 0x12a8ddecUL, 0xfdaa335dUL,
+0x176f43e8UL, 0x71fb46d4UL, 0x38129022UL, 0xce949ad4UL, 0xb84769adUL, 0x965bd862UL,
+0x82f3d055UL, 0x66fb9767UL, 0x15b80b4eUL, 0x1d5b47a0UL, 0x4cfde06fUL, 0xc28ec4b8UL,
+0x57e8726eUL, 0x647a78fcUL, 0x99865d44UL, 0x608bd593UL, 0x6c200e03UL, 0x39dc5ff6UL,
+0x5d0b00a3UL, 0xae63aff2UL, 0x7e8bd632UL, 0x70108c0cUL, 0xbbd35049UL, 0x2998df04UL,
+0x980cf42aUL, 0x9b6df491UL, 0x9e7edd53UL, 0x06918548UL, 0x58cb7e07UL, 0x3b74ef2eUL,
+0x522fffb1UL, 0xd24708ccUL, 0x1c7e27cdUL, 0xa4eb215bUL, 0x3cf1d2e2UL, 0x19b47a38UL,
+0x424f7618UL, 0x35856039UL, 0x9d17dee7UL, 0x27eb35e6UL, 0xc9aff67bUL, 0x36baf5b8UL,
+0x09c467cdUL, 0xc18910b1UL, 0xe11dbf7bUL, 0x06cd1af8UL, 0x7170c608UL, 0x2d5e3354UL,
+0xd4de495aUL, 0x64c6d006UL, 0xbcc0c62cUL, 0x3dd00db3UL, 0x708f8f34UL, 0x77d51b42UL,
+0x264f620fUL, 0x24b8d2bfUL, 0x15c1b79eUL, 0x46a52564UL, 0xf8d7e54eUL, 0x3e378160UL,
+0x7895cda5UL, 0x859c15a5UL, 0xe6459788UL, 0xc37bc75fUL, 0xdb07ba0cUL, 0x0676a3abUL,
+0x7f229b1eUL, 0x31842e7bUL, 0x24259fd7UL, 0xf8bef472UL, 0x835ffcb8UL, 0x6df4c1f2UL,
+0x96f5b195UL, 0xfd0af0fcUL, 0xb0fe134cUL, 0xe2506d3dUL, 0x4f9b12eaUL, 0xf215f225UL,
+0xa223736fUL, 0x9fb4c428UL, 0x25d04979UL, 0x34c713f8UL, 0xc4618187UL, 0xea7a6e98UL,
+0x7cd16efcUL, 0x1436876cUL, 0xf1544107UL, 0xbedeee14UL, 0x56e9af27UL, 0xa04aa441UL,
+0x3cf7c899UL, 0x92ecbae6UL, 0xdd67016dUL, 0x151682ebUL, 0xa842eedfUL, 0xfdba60b4UL,
+0xf1907b75UL, 0x20e3030fUL, 0x24d8c29eUL, 0xe139673bUL, 0xefa63fb8UL, 0x71873054UL,
+0xb6f2cf3bUL, 0x9f326442UL, 0xcb15a4ccUL, 0xb01a4504UL, 0xf1e47d8dUL, 0x844a1be5UL,
+0xbae7dfdcUL, 0x42cbda70UL, 0xcd7dae0aUL, 0x57e85b7aUL, 0xd53f5af6UL, 0x20cf4d8cUL,
+0xcea4d428UL, 0x79d130a4UL, 0x3486ebfbUL, 0x33d3cddcUL, 0x77853b53UL, 0x37effcb5UL,
+0xc5068778UL, 0xe580b3e6UL, 0x4e68b8f4UL, 0xc5c8b37eUL, 0x0d809ea2UL, 0x398feb7cUL,
+0x132a4f94UL, 0x43b7950eUL, 0x2fee7d1cUL, 0x223613bdUL, 0xdd06caa2UL, 0x37df932bUL,
+0xc4248289UL, 0xacf3ebc3UL, 0x5715f6b7UL, 0xef3478ddUL, 0xf267616fUL, 0xc148cbe4UL,
+0x9052815eUL, 0x5e410fabUL, 0xb48a2465UL, 0x2eda7fa4UL, 0xe87b40e4UL, 0xe98ea084UL,
+0x5889e9e1UL, 0xefd390fcUL, 0xdd07d35bUL, 0xdb485694UL, 0x38d7e5b2UL, 0x57720101UL,
+0x730edebcUL, 0x5b643113UL, 0x94917e4fUL, 0x503c2fbaUL, 0x646f1282UL, 0x7523d24aUL,
+0xe0779695UL, 0xf9c17a8fUL, 0x7a5b2121UL, 0xd187b896UL, 0x29263a4dUL, 0xba510cdfUL,
+0x81f47c9fUL, 0xad1163edUL, 0xea7b5965UL, 0x1a00726eUL, 0x11403092UL, 0x00da6d77UL,
+0x4a0cdd61UL, 0xad1f4603UL, 0x605bdfb0UL, 0x9eedc364UL, 0x22ebe6a8UL, 0xcee7d28aUL,
+0xa0e736a0UL, 0x5564a6b9UL, 0x10853209UL, 0xc7eb8f37UL, 0x2de705caUL, 0x8951570fUL,
+0xdf09822bUL, 0xbd691a6cUL, 0xaa12e4f2UL, 0x87451c0fUL, 0xe0f6a27aUL, 0x3ada4819UL,
+0x4cf1764fUL, 0x0d771c2bUL, 0x67cdb156UL, 0x350d8384UL, 0x5938fa0fUL, 0x42399ef3UL,
+0x36997b07UL, 0x0e84093dUL, 0x4aa93e61UL, 0x8360d87bUL, 0x1fa98b0cUL, 0x1149382cUL,
+0xe97625a5UL, 0x0614d1b7UL, 0x0e25244bUL, 0x0c768347UL, 0x589e8d82UL, 0x0d2059d1UL,
+0xa466bb1eUL, 0xf8da0a82UL, 0x04f19130UL, 0xba6e4ec0UL, 0x99265164UL, 0x1ee7230dUL,
+0x50b2ad80UL, 0xeaee6801UL, 0x8db2a283UL, 0xea8bf59eUL};
+
+/* returns the i'th byte of a variable */
+#ifdef _MSC_VER
+   #define GB(x, i) ((unsigned char)((x[(15-i)>>2])>>(unsigned)(8*((15-i)&3))))
+#else
+   #define GB(x, i) (((x[(15-i)>>2])>>(unsigned)(8*((15-i)&3)))&255)
+#endif
+
+ /**
+    Initialize the LTC_CAST5 block cipher
+    @param key The symmetric key you wish to pass
+    @param keylen The key length in bytes
+    @param num_rounds The number of rounds desired (0 for default)
+    @param skey The key in as scheduled by this function.
+    @return CRYPT_OK if successful
+ */
+#ifdef LTC_CLEAN_STACK
+static int _cast5_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey)
+#else
+int cast5_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey)
+#endif
+{
+   ulong32 x[4], z[4];
+   unsigned char buf[16];
+   int y, i;
+
+   LTC_ARGCHK(key != NULL);
+   LTC_ARGCHK(skey != NULL);
+
+   if (num_rounds != 12 && num_rounds != 16 && num_rounds != 0) {
+      return CRYPT_INVALID_ROUNDS;
+   }
+
+   if (num_rounds == 12 && keylen > 10) {
+      return CRYPT_INVALID_ROUNDS;
+   }
+
+   if (keylen < 5 || keylen > 16) {
+      return CRYPT_INVALID_KEYSIZE;
+   }
+
+   /* extend the key as required */
+   zeromem(buf, sizeof(buf));
+   XMEMCPY(buf, key, (size_t)keylen);
+
+   /* load and start the awful looking network */
+   for (y = 0; y < 4; y++) {
+       LOAD32H(x[3-y],buf+4*y);
+   }
+
+   for (i = y = 0; y < 2; y++) {
+        z[3] = x[3] ^ S5[GB(x, 0xD)] ^ S6[GB(x, 0xF)] ^ S7[GB(x, 0xC)] ^ S8[GB(x, 0xE)] ^ S7[GB(x, 0x8)];
+        z[2] = x[1] ^ S5[GB(z, 0x0)] ^ S6[GB(z, 0x2)] ^ S7[GB(z, 0x1)] ^ S8[GB(z, 0x3)] ^ S8[GB(x, 0xA)];
+        z[1] = x[0] ^ S5[GB(z, 0x7)] ^ S6[GB(z, 0x6)] ^ S7[GB(z, 0x5)] ^ S8[GB(z, 0x4)] ^ S5[GB(x, 0x9)];
+        z[0] = x[2] ^ S5[GB(z, 0xA)] ^ S6[GB(z, 0x9)] ^ S7[GB(z, 0xb)] ^ S8[GB(z, 0x8)] ^ S6[GB(x, 0xB)];
+        skey->cast5.K[i++] = S5[GB(z, 0x8)] ^ S6[GB(z, 0x9)] ^ S7[GB(z, 0x7)] ^ S8[GB(z, 0x6)] ^ S5[GB(z, 0x2)];
+        skey->cast5.K[i++] = S5[GB(z, 0xA)] ^ S6[GB(z, 0xB)] ^ S7[GB(z, 0x5)] ^ S8[GB(z, 0x4)] ^ S6[GB(z, 0x6)];
+        skey->cast5.K[i++] = S5[GB(z, 0xC)] ^ S6[GB(z, 0xd)] ^ S7[GB(z, 0x3)] ^ S8[GB(z, 0x2)] ^ S7[GB(z, 0x9)];
+        skey->cast5.K[i++] = S5[GB(z, 0xE)] ^ S6[GB(z, 0xF)] ^ S7[GB(z, 0x1)] ^ S8[GB(z, 0x0)] ^ S8[GB(z, 0xc)];
+
+        x[3] = z[1] ^ S5[GB(z, 0x5)] ^ S6[GB(z, 0x7)] ^ S7[GB(z, 0x4)] ^ S8[GB(z, 0x6)] ^ S7[GB(z, 0x0)];
+        x[2] = z[3] ^ S5[GB(x, 0x0)] ^ S6[GB(x, 0x2)] ^ S7[GB(x, 0x1)] ^ S8[GB(x, 0x3)] ^ S8[GB(z, 0x2)];
+        x[1] = z[2] ^ S5[GB(x, 0x7)] ^ S6[GB(x, 0x6)] ^ S7[GB(x, 0x5)] ^ S8[GB(x, 0x4)] ^ S5[GB(z, 0x1)];
+        x[0] = z[0] ^ S5[GB(x, 0xA)] ^ S6[GB(x, 0x9)] ^ S7[GB(x, 0xb)] ^ S8[GB(x, 0x8)] ^ S6[GB(z, 0x3)];
+        skey->cast5.K[i++] = S5[GB(x, 0x3)] ^ S6[GB(x, 0x2)] ^ S7[GB(x, 0xc)] ^ S8[GB(x, 0xd)] ^ S5[GB(x, 0x8)];
+        skey->cast5.K[i++] = S5[GB(x, 0x1)] ^ S6[GB(x, 0x0)] ^ S7[GB(x, 0xe)] ^ S8[GB(x, 0xf)] ^ S6[GB(x, 0xd)];
+        skey->cast5.K[i++] = S5[GB(x, 0x7)] ^ S6[GB(x, 0x6)] ^ S7[GB(x, 0x8)] ^ S8[GB(x, 0x9)] ^ S7[GB(x, 0x3)];
+        skey->cast5.K[i++] = S5[GB(x, 0x5)] ^ S6[GB(x, 0x4)] ^ S7[GB(x, 0xa)] ^ S8[GB(x, 0xb)] ^ S8[GB(x, 0x7)];
+
+        /* second half */
+        z[3] = x[3] ^ S5[GB(x, 0xD)] ^ S6[GB(x, 0xF)] ^ S7[GB(x, 0xC)] ^ S8[GB(x, 0xE)] ^ S7[GB(x, 0x8)];
+        z[2] = x[1] ^ S5[GB(z, 0x0)] ^ S6[GB(z, 0x2)] ^ S7[GB(z, 0x1)] ^ S8[GB(z, 0x3)] ^ S8[GB(x, 0xA)];
+        z[1] = x[0] ^ S5[GB(z, 0x7)] ^ S6[GB(z, 0x6)] ^ S7[GB(z, 0x5)] ^ S8[GB(z, 0x4)] ^ S5[GB(x, 0x9)];
+        z[0] = x[2] ^ S5[GB(z, 0xA)] ^ S6[GB(z, 0x9)] ^ S7[GB(z, 0xb)] ^ S8[GB(z, 0x8)] ^ S6[GB(x, 0xB)];
+        skey->cast5.K[i++] = S5[GB(z, 0x3)] ^ S6[GB(z, 0x2)] ^ S7[GB(z, 0xc)] ^ S8[GB(z, 0xd)] ^ S5[GB(z, 0x9)];
+        skey->cast5.K[i++] = S5[GB(z, 0x1)] ^ S6[GB(z, 0x0)] ^ S7[GB(z, 0xe)] ^ S8[GB(z, 0xf)] ^ S6[GB(z, 0xc)];
+        skey->cast5.K[i++] = S5[GB(z, 0x7)] ^ S6[GB(z, 0x6)] ^ S7[GB(z, 0x8)] ^ S8[GB(z, 0x9)] ^ S7[GB(z, 0x2)];
+        skey->cast5.K[i++] = S5[GB(z, 0x5)] ^ S6[GB(z, 0x4)] ^ S7[GB(z, 0xa)] ^ S8[GB(z, 0xb)] ^ S8[GB(z, 0x6)];
+
+        x[3] = z[1] ^ S5[GB(z, 0x5)] ^ S6[GB(z, 0x7)] ^ S7[GB(z, 0x4)] ^ S8[GB(z, 0x6)] ^ S7[GB(z, 0x0)];
+        x[2] = z[3] ^ S5[GB(x, 0x0)] ^ S6[GB(x, 0x2)] ^ S7[GB(x, 0x1)] ^ S8[GB(x, 0x3)] ^ S8[GB(z, 0x2)];
+        x[1] = z[2] ^ S5[GB(x, 0x7)] ^ S6[GB(x, 0x6)] ^ S7[GB(x, 0x5)] ^ S8[GB(x, 0x4)] ^ S5[GB(z, 0x1)];
+        x[0] = z[0] ^ S5[GB(x, 0xA)] ^ S6[GB(x, 0x9)] ^ S7[GB(x, 0xb)] ^ S8[GB(x, 0x8)] ^ S6[GB(z, 0x3)];
+        skey->cast5.K[i++] = S5[GB(x, 0x8)] ^ S6[GB(x, 0x9)] ^ S7[GB(x, 0x7)] ^ S8[GB(x, 0x6)] ^ S5[GB(x, 0x3)];
+        skey->cast5.K[i++] = S5[GB(x, 0xa)] ^ S6[GB(x, 0xb)] ^ S7[GB(x, 0x5)] ^ S8[GB(x, 0x4)] ^ S6[GB(x, 0x7)];
+        skey->cast5.K[i++] = S5[GB(x, 0xc)] ^ S6[GB(x, 0xd)] ^ S7[GB(x, 0x3)] ^ S8[GB(x, 0x2)] ^ S7[GB(x, 0x8)];
+        skey->cast5.K[i++] = S5[GB(x, 0xe)] ^ S6[GB(x, 0xf)] ^ S7[GB(x, 0x1)] ^ S8[GB(x, 0x0)] ^ S8[GB(x, 0xd)];
+   }
+
+   skey->cast5.keylen = keylen;
+
+#ifdef LTC_CLEAN_STACK
+   zeromem(buf, sizeof(buf));
+   zeromem(x, sizeof(x));
+   zeromem(z, sizeof(z));
+#endif
+
+   return CRYPT_OK;
+}
+
+#ifdef LTC_CLEAN_STACK
+int cast5_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey)
+{
+   int z;
+   z = _cast5_setup(key, keylen, num_rounds, skey);
+   burn_stack(sizeof(ulong32)*8 + 16 + sizeof(int)*2);
+   return z;
+}
+#endif
+
+#ifdef _MSC_VER
+   #define INLINE __inline
+#else
+   #define INLINE
+#endif
+
+INLINE static ulong32 FI(ulong32 R, ulong32 Km, ulong32 Kr)
+{
+   ulong32 I;
+   I = (Km + R);
+   I = ROL(I, Kr);
+   return ((S1[byte(I, 3)] ^ S2[byte(I,2)]) - S3[byte(I,1)]) + S4[byte(I,0)];
+}
+
+INLINE static ulong32 FII(ulong32 R, ulong32 Km, ulong32 Kr)
+{
+   ulong32 I;
+   I = (Km ^ R);
+   I = ROL(I, Kr);
+   return ((S1[byte(I, 3)] - S2[byte(I,2)]) + S3[byte(I,1)]) ^ S4[byte(I,0)];
+}
+
+INLINE static ulong32 FIII(ulong32 R, ulong32 Km, ulong32 Kr)
+{
+   ulong32 I;
+   I = (Km - R);
+   I = ROL(I, Kr);
+   return ((S1[byte(I, 3)] + S2[byte(I,2)]) ^ S3[byte(I,1)]) - S4[byte(I,0)];
+}
+
+/**
+  Encrypts a block of text with LTC_CAST5
+  @param pt The input plaintext (8 bytes)
+  @param ct The output ciphertext (8 bytes)
+  @param skey The key as scheduled
+*/
+#ifdef LTC_CLEAN_STACK
+static int _cast5_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey)
+#else
+int cast5_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey)
+#endif
+{
+   ulong32 R, L;
+
+   LTC_ARGCHK(pt   != NULL);
+   LTC_ARGCHK(ct   != NULL);
+   LTC_ARGCHK(skey != NULL);
+
+   LOAD32H(L,&pt[0]);
+   LOAD32H(R,&pt[4]);
+   L ^= FI(R, skey->cast5.K[0], skey->cast5.K[16]);
+   R ^= FII(L, skey->cast5.K[1], skey->cast5.K[17]);
+   L ^= FIII(R, skey->cast5.K[2], skey->cast5.K[18]);
+   R ^= FI(L, skey->cast5.K[3], skey->cast5.K[19]);
+   L ^= FII(R, skey->cast5.K[4], skey->cast5.K[20]);
+   R ^= FIII(L, skey->cast5.K[5], skey->cast5.K[21]);
+   L ^= FI(R, skey->cast5.K[6], skey->cast5.K[22]);
+   R ^= FII(L, skey->cast5.K[7], skey->cast5.K[23]);
+   L ^= FIII(R, skey->cast5.K[8], skey->cast5.K[24]);
+   R ^= FI(L, skey->cast5.K[9], skey->cast5.K[25]);
+   L ^= FII(R, skey->cast5.K[10], skey->cast5.K[26]);
+   R ^= FIII(L, skey->cast5.K[11], skey->cast5.K[27]);
+   if (skey->cast5.keylen > 10) {
+      L ^= FI(R, skey->cast5.K[12], skey->cast5.K[28]);
+      R ^= FII(L, skey->cast5.K[13], skey->cast5.K[29]);
+      L ^= FIII(R, skey->cast5.K[14], skey->cast5.K[30]);
+      R ^= FI(L, skey->cast5.K[15], skey->cast5.K[31]);
+   }
+   STORE32H(R,&ct[0]);
+   STORE32H(L,&ct[4]);
+   return CRYPT_OK;
+}
+
+
+#ifdef LTC_CLEAN_STACK
+int cast5_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey)
+{
+   int err =_cast5_ecb_encrypt(pt,ct,skey);
+   burn_stack(sizeof(ulong32)*3);
+   return err;
+}
+#endif
+
+/**
+  Decrypts a block of text with LTC_CAST5
+  @param ct The input ciphertext (8 bytes)
+  @param pt The output plaintext (8 bytes)
+  @param skey The key as scheduled
+*/
+#ifdef LTC_CLEAN_STACK
+static int _cast5_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey)
+#else
+int cast5_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey)
+#endif
+{
+   ulong32 R, L;
+
+   LTC_ARGCHK(pt   != NULL);
+   LTC_ARGCHK(ct   != NULL);
+   LTC_ARGCHK(skey != NULL);
+
+   LOAD32H(R,&ct[0]);
+   LOAD32H(L,&ct[4]);
+   if (skey->cast5.keylen > 10) {
+      R ^= FI(L, skey->cast5.K[15], skey->cast5.K[31]);
+      L ^= FIII(R, skey->cast5.K[14], skey->cast5.K[30]);
+      R ^= FII(L, skey->cast5.K[13], skey->cast5.K[29]);
+      L ^= FI(R, skey->cast5.K[12], skey->cast5.K[28]);
+   }
+   R ^= FIII(L, skey->cast5.K[11], skey->cast5.K[27]);
+   L ^= FII(R, skey->cast5.K[10], skey->cast5.K[26]);
+   R ^= FI(L, skey->cast5.K[9], skey->cast5.K[25]);
+   L ^= FIII(R, skey->cast5.K[8], skey->cast5.K[24]);
+   R ^= FII(L, skey->cast5.K[7], skey->cast5.K[23]);
+   L ^= FI(R, skey->cast5.K[6], skey->cast5.K[22]);
+   R ^= FIII(L, skey->cast5.K[5], skey->cast5.K[21]);
+   L ^= FII(R, skey->cast5.K[4], skey->cast5.K[20]);
+   R ^= FI(L, skey->cast5.K[3], skey->cast5.K[19]);
+   L ^= FIII(R, skey->cast5.K[2], skey->cast5.K[18]);
+   R ^= FII(L, skey->cast5.K[1], skey->cast5.K[17]);
+   L ^= FI(R, skey->cast5.K[0], skey->cast5.K[16]);
+   STORE32H(L,&pt[0]);
+   STORE32H(R,&pt[4]);
+
+   return CRYPT_OK;
+}
+
+#ifdef LTC_CLEAN_STACK
+int cast5_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey)
+{
+   int err = _cast5_ecb_decrypt(ct,pt,skey);
+   burn_stack(sizeof(ulong32)*3);
+   return err;
+}
+#endif
+
+/**
+  Performs a self-test of the LTC_CAST5 block cipher
+  @return CRYPT_OK if functional, CRYPT_NOP if self-test has been disabled
+*/
+int cast5_test(void)
+{
+ #ifndef LTC_TEST
+    return CRYPT_NOP;
+ #else
+   static const struct {
+       int keylen;
+       unsigned char key[16];
+       unsigned char pt[8];
+       unsigned char ct[8];
+   } tests[] = {
+     { 16,
+       {0x01, 0x23, 0x45, 0x67, 0x12, 0x34, 0x56, 0x78, 0x23, 0x45, 0x67, 0x89, 0x34, 0x56, 0x78, 0x9A},
+       {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF},
+       {0x23, 0x8B, 0x4F, 0xE5, 0x84, 0x7E, 0x44, 0xB2}
+     },
+     { 10,
+       {0x01, 0x23, 0x45, 0x67, 0x12, 0x34, 0x56, 0x78, 0x23, 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+       {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF},
+       {0xEB, 0x6A, 0x71, 0x1A, 0x2C, 0x02, 0x27, 0x1B},
+     },
+     { 5,
+       {0x01, 0x23, 0x45, 0x67, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+       {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF},
+       {0x7A, 0xC8, 0x16, 0xD1, 0x6E, 0x9B, 0x30, 0x2E}
+     }
+   };
+   int i, y, err;
+   symmetric_key key;
+   unsigned char tmp[2][8];
+
+   for (i = 0; i < (int)(sizeof(tests) / sizeof(tests[0])); i++) {
+       if ((err = cast5_setup(tests[i].key, tests[i].keylen, 0, &key)) != CRYPT_OK) {
+          return err;
+       }
+       cast5_ecb_encrypt(tests[i].pt, tmp[0], &key);
+       cast5_ecb_decrypt(tmp[0], tmp[1], &key);
+       if ((compare_testvector(tmp[0], 8, tests[i].ct, 8, "CAST5 Encrypt", i) != 0) ||
+             (compare_testvector(tmp[1], 8, tests[i].pt, 8, "CAST5 Decrypt", i) != 0)) {
+          return CRYPT_FAIL_TESTVECTOR;
+       }
+      /* now see if we can encrypt all zero bytes 1000 times, decrypt and come back where we started */
+      for (y = 0; y < 8; y++) tmp[0][y] = 0;
+      for (y = 0; y < 1000; y++) cast5_ecb_encrypt(tmp[0], tmp[0], &key);
+      for (y = 0; y < 1000; y++) cast5_ecb_decrypt(tmp[0], tmp[0], &key);
+      for (y = 0; y < 8; y++) if (tmp[0][y] != 0) return CRYPT_FAIL_TESTVECTOR;
+
+   }
+   return CRYPT_OK;
+ #endif
+}
+
+/** Terminate the context
+   @param skey    The scheduled key
+*/
+void cast5_done(symmetric_key *skey)
+{
+  LTC_UNUSED_PARAM(skey);
+}
+
+/**
+  Gets suitable key size
+  @param keysize [in/out] The length of the recommended key (in bytes).  This function will store the suitable size back in this variable.
+  @return CRYPT_OK if the input key size is acceptable.
+*/
+int cast5_keysize(int *keysize)
+{
+   LTC_ARGCHK(keysize != NULL);
+   if (*keysize < 5) {
+      return CRYPT_INVALID_KEYSIZE;
+   } else if (*keysize > 16) {
+      *keysize = 16;
+   }
+   return CRYPT_OK;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/ciphers/des.c b/libtomcrypt/src/ciphers/des.c
new file mode 100644 (file)
index 0000000..f83c010
--- /dev/null
@@ -0,0 +1,2086 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file des.c
+  DES code submitted by Dobes Vandermeer
+*/
+
+#ifdef LTC_DES
+
+#define EN0 0
+#define DE1 1
+
+const struct ltc_cipher_descriptor des_desc =
+{
+    "des",
+    13,
+    8, 8, 8, 16,
+    &des_setup,
+    &des_ecb_encrypt,
+    &des_ecb_decrypt,
+    &des_test,
+    &des_done,
+    &des_keysize,
+    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
+};
+
+const struct ltc_cipher_descriptor des3_desc =
+{
+    "3des",
+    14,
+    16, 24, 8, 16,
+    &des3_setup,
+    &des3_ecb_encrypt,
+    &des3_ecb_decrypt,
+    &des3_test,
+    &des3_done,
+    &des3_keysize,
+    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
+};
+
+static const ulong32 bytebit[8] =
+{
+    0200, 0100, 040, 020, 010, 04, 02, 01
+};
+
+static const ulong32 bigbyte[24] =
+{
+    0x800000UL,  0x400000UL,  0x200000UL,  0x100000UL,
+    0x80000UL,   0x40000UL,   0x20000UL,   0x10000UL,
+    0x8000UL,    0x4000UL,    0x2000UL,    0x1000UL,
+    0x800UL,     0x400UL,     0x200UL,     0x100UL,
+    0x80UL,      0x40UL,      0x20UL,      0x10UL,
+    0x8UL,       0x4UL,       0x2UL,       0x1L
+};
+
+/* Use the key schedule specific in the standard (ANSI X3.92-1981) */
+
+static const unsigned char pc1[56] = {
+    56, 48, 40, 32, 24, 16,  8,  0, 57, 49, 41, 33, 25, 17,
+     9,  1, 58, 50, 42, 34, 26, 18, 10,  2, 59, 51, 43, 35,
+    62, 54, 46, 38, 30, 22, 14,  6, 61, 53, 45, 37, 29, 21,
+    13,  5, 60, 52, 44, 36, 28, 20, 12,  4, 27, 19, 11,  3
+};
+
+static const unsigned char totrot[16] = {
+    1,   2,  4,  6,
+    8,  10, 12, 14,
+    15, 17, 19, 21,
+    23, 25, 27, 28
+};
+
+static const unsigned char pc2[48] = {
+    13, 16, 10, 23,  0,  4,      2, 27, 14,  5, 20,  9,
+    22, 18, 11,  3, 25,  7,     15,  6, 26, 19, 12,  1,
+    40, 51, 30, 36, 46, 54,     29, 39, 50, 44, 32, 47,
+    43, 48, 38, 55, 33, 52,     45, 41, 49, 35, 28, 31
+};
+
+
+static const ulong32 SP1[64] =
+{
+    0x01010400UL, 0x00000000UL, 0x00010000UL, 0x01010404UL,
+    0x01010004UL, 0x00010404UL, 0x00000004UL, 0x00010000UL,
+    0x00000400UL, 0x01010400UL, 0x01010404UL, 0x00000400UL,
+    0x01000404UL, 0x01010004UL, 0x01000000UL, 0x00000004UL,
+    0x00000404UL, 0x01000400UL, 0x01000400UL, 0x00010400UL,
+    0x00010400UL, 0x01010000UL, 0x01010000UL, 0x01000404UL,
+    0x00010004UL, 0x01000004UL, 0x01000004UL, 0x00010004UL,
+    0x00000000UL, 0x00000404UL, 0x00010404UL, 0x01000000UL,
+    0x00010000UL, 0x01010404UL, 0x00000004UL, 0x01010000UL,
+    0x01010400UL, 0x01000000UL, 0x01000000UL, 0x00000400UL,
+    0x01010004UL, 0x00010000UL, 0x00010400UL, 0x01000004UL,
+    0x00000400UL, 0x00000004UL, 0x01000404UL, 0x00010404UL,
+    0x01010404UL, 0x00010004UL, 0x01010000UL, 0x01000404UL,
+    0x01000004UL, 0x00000404UL, 0x00010404UL, 0x01010400UL,
+    0x00000404UL, 0x01000400UL, 0x01000400UL, 0x00000000UL,
+    0x00010004UL, 0x00010400UL, 0x00000000UL, 0x01010004UL
+};
+
+static const ulong32 SP2[64] =
+{
+    0x80108020UL, 0x80008000UL, 0x00008000UL, 0x00108020UL,
+    0x00100000UL, 0x00000020UL, 0x80100020UL, 0x80008020UL,
+    0x80000020UL, 0x80108020UL, 0x80108000UL, 0x80000000UL,
+    0x80008000UL, 0x00100000UL, 0x00000020UL, 0x80100020UL,
+    0x00108000UL, 0x00100020UL, 0x80008020UL, 0x00000000UL,
+    0x80000000UL, 0x00008000UL, 0x00108020UL, 0x80100000UL,
+    0x00100020UL, 0x80000020UL, 0x00000000UL, 0x00108000UL,
+    0x00008020UL, 0x80108000UL, 0x80100000UL, 0x00008020UL,
+    0x00000000UL, 0x00108020UL, 0x80100020UL, 0x00100000UL,
+    0x80008020UL, 0x80100000UL, 0x80108000UL, 0x00008000UL,
+    0x80100000UL, 0x80008000UL, 0x00000020UL, 0x80108020UL,
+    0x00108020UL, 0x00000020UL, 0x00008000UL, 0x80000000UL,
+    0x00008020UL, 0x80108000UL, 0x00100000UL, 0x80000020UL,
+    0x00100020UL, 0x80008020UL, 0x80000020UL, 0x00100020UL,
+    0x00108000UL, 0x00000000UL, 0x80008000UL, 0x00008020UL,
+    0x80000000UL, 0x80100020UL, 0x80108020UL, 0x00108000UL
+};
+
+static const ulong32 SP3[64] =
+{
+    0x00000208UL, 0x08020200UL, 0x00000000UL, 0x08020008UL,
+    0x08000200UL, 0x00000000UL, 0x00020208UL, 0x08000200UL,
+    0x00020008UL, 0x08000008UL, 0x08000008UL, 0x00020000UL,
+    0x08020208UL, 0x00020008UL, 0x08020000UL, 0x00000208UL,
+    0x08000000UL, 0x00000008UL, 0x08020200UL, 0x00000200UL,
+    0x00020200UL, 0x08020000UL, 0x08020008UL, 0x00020208UL,
+    0x08000208UL, 0x00020200UL, 0x00020000UL, 0x08000208UL,
+    0x00000008UL, 0x08020208UL, 0x00000200UL, 0x08000000UL,
+    0x08020200UL, 0x08000000UL, 0x00020008UL, 0x00000208UL,
+    0x00020000UL, 0x08020200UL, 0x08000200UL, 0x00000000UL,
+    0x00000200UL, 0x00020008UL, 0x08020208UL, 0x08000200UL,
+    0x08000008UL, 0x00000200UL, 0x00000000UL, 0x08020008UL,
+    0x08000208UL, 0x00020000UL, 0x08000000UL, 0x08020208UL,
+    0x00000008UL, 0x00020208UL, 0x00020200UL, 0x08000008UL,
+    0x08020000UL, 0x08000208UL, 0x00000208UL, 0x08020000UL,
+    0x00020208UL, 0x00000008UL, 0x08020008UL, 0x00020200UL
+};
+
+static const ulong32 SP4[64] =
+{
+    0x00802001UL, 0x00002081UL, 0x00002081UL, 0x00000080UL,
+    0x00802080UL, 0x00800081UL, 0x00800001UL, 0x00002001UL,
+    0x00000000UL, 0x00802000UL, 0x00802000UL, 0x00802081UL,
+    0x00000081UL, 0x00000000UL, 0x00800080UL, 0x00800001UL,
+    0x00000001UL, 0x00002000UL, 0x00800000UL, 0x00802001UL,
+    0x00000080UL, 0x00800000UL, 0x00002001UL, 0x00002080UL,
+    0x00800081UL, 0x00000001UL, 0x00002080UL, 0x00800080UL,
+    0x00002000UL, 0x00802080UL, 0x00802081UL, 0x00000081UL,
+    0x00800080UL, 0x00800001UL, 0x00802000UL, 0x00802081UL,
+    0x00000081UL, 0x00000000UL, 0x00000000UL, 0x00802000UL,
+    0x00002080UL, 0x00800080UL, 0x00800081UL, 0x00000001UL,
+    0x00802001UL, 0x00002081UL, 0x00002081UL, 0x00000080UL,
+    0x00802081UL, 0x00000081UL, 0x00000001UL, 0x00002000UL,
+    0x00800001UL, 0x00002001UL, 0x00802080UL, 0x00800081UL,
+    0x00002001UL, 0x00002080UL, 0x00800000UL, 0x00802001UL,
+    0x00000080UL, 0x00800000UL, 0x00002000UL, 0x00802080UL
+};
+
+static const ulong32 SP5[64] =
+{
+    0x00000100UL, 0x02080100UL, 0x02080000UL, 0x42000100UL,
+    0x00080000UL, 0x00000100UL, 0x40000000UL, 0x02080000UL,
+    0x40080100UL, 0x00080000UL, 0x02000100UL, 0x40080100UL,
+    0x42000100UL, 0x42080000UL, 0x00080100UL, 0x40000000UL,
+    0x02000000UL, 0x40080000UL, 0x40080000UL, 0x00000000UL,
+    0x40000100UL, 0x42080100UL, 0x42080100UL, 0x02000100UL,
+    0x42080000UL, 0x40000100UL, 0x00000000UL, 0x42000000UL,
+    0x02080100UL, 0x02000000UL, 0x42000000UL, 0x00080100UL,
+    0x00080000UL, 0x42000100UL, 0x00000100UL, 0x02000000UL,
+    0x40000000UL, 0x02080000UL, 0x42000100UL, 0x40080100UL,
+    0x02000100UL, 0x40000000UL, 0x42080000UL, 0x02080100UL,
+    0x40080100UL, 0x00000100UL, 0x02000000UL, 0x42080000UL,
+    0x42080100UL, 0x00080100UL, 0x42000000UL, 0x42080100UL,
+    0x02080000UL, 0x00000000UL, 0x40080000UL, 0x42000000UL,
+    0x00080100UL, 0x02000100UL, 0x40000100UL, 0x00080000UL,
+    0x00000000UL, 0x40080000UL, 0x02080100UL, 0x40000100UL
+};
+
+static const ulong32 SP6[64] =
+{
+    0x20000010UL, 0x20400000UL, 0x00004000UL, 0x20404010UL,
+    0x20400000UL, 0x00000010UL, 0x20404010UL, 0x00400000UL,
+    0x20004000UL, 0x00404010UL, 0x00400000UL, 0x20000010UL,
+    0x00400010UL, 0x20004000UL, 0x20000000UL, 0x00004010UL,
+    0x00000000UL, 0x00400010UL, 0x20004010UL, 0x00004000UL,
+    0x00404000UL, 0x20004010UL, 0x00000010UL, 0x20400010UL,
+    0x20400010UL, 0x00000000UL, 0x00404010UL, 0x20404000UL,
+    0x00004010UL, 0x00404000UL, 0x20404000UL, 0x20000000UL,
+    0x20004000UL, 0x00000010UL, 0x20400010UL, 0x00404000UL,
+    0x20404010UL, 0x00400000UL, 0x00004010UL, 0x20000010UL,
+    0x00400000UL, 0x20004000UL, 0x20000000UL, 0x00004010UL,
+    0x20000010UL, 0x20404010UL, 0x00404000UL, 0x20400000UL,
+    0x00404010UL, 0x20404000UL, 0x00000000UL, 0x20400010UL,
+    0x00000010UL, 0x00004000UL, 0x20400000UL, 0x00404010UL,
+    0x00004000UL, 0x00400010UL, 0x20004010UL, 0x00000000UL,
+    0x20404000UL, 0x20000000UL, 0x00400010UL, 0x20004010UL
+};
+
+static const ulong32 SP7[64] =
+{
+    0x00200000UL, 0x04200002UL, 0x04000802UL, 0x00000000UL,
+    0x00000800UL, 0x04000802UL, 0x00200802UL, 0x04200800UL,
+    0x04200802UL, 0x00200000UL, 0x00000000UL, 0x04000002UL,
+    0x00000002UL, 0x04000000UL, 0x04200002UL, 0x00000802UL,
+    0x04000800UL, 0x00200802UL, 0x00200002UL, 0x04000800UL,
+    0x04000002UL, 0x04200000UL, 0x04200800UL, 0x00200002UL,
+    0x04200000UL, 0x00000800UL, 0x00000802UL, 0x04200802UL,
+    0x00200800UL, 0x00000002UL, 0x04000000UL, 0x00200800UL,
+    0x04000000UL, 0x00200800UL, 0x00200000UL, 0x04000802UL,
+    0x04000802UL, 0x04200002UL, 0x04200002UL, 0x00000002UL,
+    0x00200002UL, 0x04000000UL, 0x04000800UL, 0x00200000UL,
+    0x04200800UL, 0x00000802UL, 0x00200802UL, 0x04200800UL,
+    0x00000802UL, 0x04000002UL, 0x04200802UL, 0x04200000UL,
+    0x00200800UL, 0x00000000UL, 0x00000002UL, 0x04200802UL,
+    0x00000000UL, 0x00200802UL, 0x04200000UL, 0x00000800UL,
+    0x04000002UL, 0x04000800UL, 0x00000800UL, 0x00200002UL
+};
+
+static const ulong32 SP8[64] =
+{
+    0x10001040UL, 0x00001000UL, 0x00040000UL, 0x10041040UL,
+    0x10000000UL, 0x10001040UL, 0x00000040UL, 0x10000000UL,
+    0x00040040UL, 0x10040000UL, 0x10041040UL, 0x00041000UL,
+    0x10041000UL, 0x00041040UL, 0x00001000UL, 0x00000040UL,
+    0x10040000UL, 0x10000040UL, 0x10001000UL, 0x00001040UL,
+    0x00041000UL, 0x00040040UL, 0x10040040UL, 0x10041000UL,
+    0x00001040UL, 0x00000000UL, 0x00000000UL, 0x10040040UL,
+    0x10000040UL, 0x10001000UL, 0x00041040UL, 0x00040000UL,
+    0x00041040UL, 0x00040000UL, 0x10041000UL, 0x00001000UL,
+    0x00000040UL, 0x10040040UL, 0x00001000UL, 0x00041040UL,
+    0x10001000UL, 0x00000040UL, 0x10000040UL, 0x10040000UL,
+    0x10040040UL, 0x10000000UL, 0x00040000UL, 0x10001040UL,
+    0x00000000UL, 0x10041040UL, 0x00040040UL, 0x10000040UL,
+    0x10040000UL, 0x10001000UL, 0x10001040UL, 0x00000000UL,
+    0x10041040UL, 0x00041000UL, 0x00041000UL, 0x00001040UL,
+    0x00001040UL, 0x00040040UL, 0x10000000UL, 0x10041000UL
+};
+
+#ifndef LTC_SMALL_CODE
+
+static const ulong64 des_ip[8][256] = {
+
+{ CONST64(0x0000000000000000), CONST64(0x0000001000000000), CONST64(0x0000000000000010), CONST64(0x0000001000000010),
+  CONST64(0x0000100000000000), CONST64(0x0000101000000000), CONST64(0x0000100000000010), CONST64(0x0000101000000010),
+  CONST64(0x0000000000001000), CONST64(0x0000001000001000), CONST64(0x0000000000001010), CONST64(0x0000001000001010),
+  CONST64(0x0000100000001000), CONST64(0x0000101000001000), CONST64(0x0000100000001010), CONST64(0x0000101000001010),
+  CONST64(0x0010000000000000), CONST64(0x0010001000000000), CONST64(0x0010000000000010), CONST64(0x0010001000000010),
+  CONST64(0x0010100000000000), CONST64(0x0010101000000000), CONST64(0x0010100000000010), CONST64(0x0010101000000010),
+  CONST64(0x0010000000001000), CONST64(0x0010001000001000), CONST64(0x0010000000001010), CONST64(0x0010001000001010),
+  CONST64(0x0010100000001000), CONST64(0x0010101000001000), CONST64(0x0010100000001010), CONST64(0x0010101000001010),
+  CONST64(0x0000000000100000), CONST64(0x0000001000100000), CONST64(0x0000000000100010), CONST64(0x0000001000100010),
+  CONST64(0x0000100000100000), CONST64(0x0000101000100000), CONST64(0x0000100000100010), CONST64(0x0000101000100010),
+  CONST64(0x0000000000101000), CONST64(0x0000001000101000), CONST64(0x0000000000101010), CONST64(0x0000001000101010),
+  CONST64(0x0000100000101000), CONST64(0x0000101000101000), CONST64(0x0000100000101010), CONST64(0x0000101000101010),
+  CONST64(0x0010000000100000), CONST64(0x0010001000100000), CONST64(0x0010000000100010), CONST64(0x0010001000100010),
+  CONST64(0x0010100000100000), CONST64(0x0010101000100000), CONST64(0x0010100000100010), CONST64(0x0010101000100010),
+  CONST64(0x0010000000101000), CONST64(0x0010001000101000), CONST64(0x0010000000101010), CONST64(0x0010001000101010),
+  CONST64(0x0010100000101000), CONST64(0x0010101000101000), CONST64(0x0010100000101010), CONST64(0x0010101000101010),
+  CONST64(0x1000000000000000), CONST64(0x1000001000000000), CONST64(0x1000000000000010), CONST64(0x1000001000000010),
+  CONST64(0x1000100000000000), CONST64(0x1000101000000000), CONST64(0x1000100000000010), CONST64(0x1000101000000010),
+  CONST64(0x1000000000001000), CONST64(0x1000001000001000), CONST64(0x1000000000001010), CONST64(0x1000001000001010),
+  CONST64(0x1000100000001000), CONST64(0x1000101000001000), CONST64(0x1000100000001010), CONST64(0x1000101000001010),
+  CONST64(0x1010000000000000), CONST64(0x1010001000000000), CONST64(0x1010000000000010), CONST64(0x1010001000000010),
+  CONST64(0x1010100000000000), CONST64(0x1010101000000000), CONST64(0x1010100000000010), CONST64(0x1010101000000010),
+  CONST64(0x1010000000001000), CONST64(0x1010001000001000), CONST64(0x1010000000001010), CONST64(0x1010001000001010),
+  CONST64(0x1010100000001000), CONST64(0x1010101000001000), CONST64(0x1010100000001010), CONST64(0x1010101000001010),
+  CONST64(0x1000000000100000), CONST64(0x1000001000100000), CONST64(0x1000000000100010), CONST64(0x1000001000100010),
+  CONST64(0x1000100000100000), CONST64(0x1000101000100000), CONST64(0x1000100000100010), CONST64(0x1000101000100010),
+  CONST64(0x1000000000101000), CONST64(0x1000001000101000), CONST64(0x1000000000101010), CONST64(0x1000001000101010),
+  CONST64(0x1000100000101000), CONST64(0x1000101000101000), CONST64(0x1000100000101010), CONST64(0x1000101000101010),
+  CONST64(0x1010000000100000), CONST64(0x1010001000100000), CONST64(0x1010000000100010), CONST64(0x1010001000100010),
+  CONST64(0x1010100000100000), CONST64(0x1010101000100000), CONST64(0x1010100000100010), CONST64(0x1010101000100010),
+  CONST64(0x1010000000101000), CONST64(0x1010001000101000), CONST64(0x1010000000101010), CONST64(0x1010001000101010),
+  CONST64(0x1010100000101000), CONST64(0x1010101000101000), CONST64(0x1010100000101010), CONST64(0x1010101000101010),
+  CONST64(0x0000000010000000), CONST64(0x0000001010000000), CONST64(0x0000000010000010), CONST64(0x0000001010000010),
+  CONST64(0x0000100010000000), CONST64(0x0000101010000000), CONST64(0x0000100010000010), CONST64(0x0000101010000010),
+  CONST64(0x0000000010001000), CONST64(0x0000001010001000), CONST64(0x0000000010001010), CONST64(0x0000001010001010),
+  CONST64(0x0000100010001000), CONST64(0x0000101010001000), CONST64(0x0000100010001010), CONST64(0x0000101010001010),
+  CONST64(0x0010000010000000), CONST64(0x0010001010000000), CONST64(0x0010000010000010), CONST64(0x0010001010000010),
+  CONST64(0x0010100010000000), CONST64(0x0010101010000000), CONST64(0x0010100010000010), CONST64(0x0010101010000010),
+  CONST64(0x0010000010001000), CONST64(0x0010001010001000), CONST64(0x0010000010001010), CONST64(0x0010001010001010),
+  CONST64(0x0010100010001000), CONST64(0x0010101010001000), CONST64(0x0010100010001010), CONST64(0x0010101010001010),
+  CONST64(0x0000000010100000), CONST64(0x0000001010100000), CONST64(0x0000000010100010), CONST64(0x0000001010100010),
+  CONST64(0x0000100010100000), CONST64(0x0000101010100000), CONST64(0x0000100010100010), CONST64(0x0000101010100010),
+  CONST64(0x0000000010101000), CONST64(0x0000001010101000), CONST64(0x0000000010101010), CONST64(0x0000001010101010),
+  CONST64(0x0000100010101000), CONST64(0x0000101010101000), CONST64(0x0000100010101010), CONST64(0x0000101010101010),
+  CONST64(0x0010000010100000), CONST64(0x0010001010100000), CONST64(0x0010000010100010), CONST64(0x0010001010100010),
+  CONST64(0x0010100010100000), CONST64(0x0010101010100000), CONST64(0x0010100010100010), CONST64(0x0010101010100010),
+  CONST64(0x0010000010101000), CONST64(0x0010001010101000), CONST64(0x0010000010101010), CONST64(0x0010001010101010),
+  CONST64(0x0010100010101000), CONST64(0x0010101010101000), CONST64(0x0010100010101010), CONST64(0x0010101010101010),
+  CONST64(0x1000000010000000), CONST64(0x1000001010000000), CONST64(0x1000000010000010), CONST64(0x1000001010000010),
+  CONST64(0x1000100010000000), CONST64(0x1000101010000000), CONST64(0x1000100010000010), CONST64(0x1000101010000010),
+  CONST64(0x1000000010001000), CONST64(0x1000001010001000), CONST64(0x1000000010001010), CONST64(0x1000001010001010),
+  CONST64(0x1000100010001000), CONST64(0x1000101010001000), CONST64(0x1000100010001010), CONST64(0x1000101010001010),
+  CONST64(0x1010000010000000), CONST64(0x1010001010000000), CONST64(0x1010000010000010), CONST64(0x1010001010000010),
+  CONST64(0x1010100010000000), CONST64(0x1010101010000000), CONST64(0x1010100010000010), CONST64(0x1010101010000010),
+  CONST64(0x1010000010001000), CONST64(0x1010001010001000), CONST64(0x1010000010001010), CONST64(0x1010001010001010),
+  CONST64(0x1010100010001000), CONST64(0x1010101010001000), CONST64(0x1010100010001010), CONST64(0x1010101010001010),
+  CONST64(0x1000000010100000), CONST64(0x1000001010100000), CONST64(0x1000000010100010), CONST64(0x1000001010100010),
+  CONST64(0x1000100010100000), CONST64(0x1000101010100000), CONST64(0x1000100010100010), CONST64(0x1000101010100010),
+  CONST64(0x1000000010101000), CONST64(0x1000001010101000), CONST64(0x1000000010101010), CONST64(0x1000001010101010),
+  CONST64(0x1000100010101000), CONST64(0x1000101010101000), CONST64(0x1000100010101010), CONST64(0x1000101010101010),
+  CONST64(0x1010000010100000), CONST64(0x1010001010100000), CONST64(0x1010000010100010), CONST64(0x1010001010100010),
+  CONST64(0x1010100010100000), CONST64(0x1010101010100000), CONST64(0x1010100010100010), CONST64(0x1010101010100010),
+  CONST64(0x1010000010101000), CONST64(0x1010001010101000), CONST64(0x1010000010101010), CONST64(0x1010001010101010),
+  CONST64(0x1010100010101000), CONST64(0x1010101010101000), CONST64(0x1010100010101010), CONST64(0x1010101010101010)
+  },
+{ CONST64(0x0000000000000000), CONST64(0x0000000800000000), CONST64(0x0000000000000008), CONST64(0x0000000800000008),
+  CONST64(0x0000080000000000), CONST64(0x0000080800000000), CONST64(0x0000080000000008), CONST64(0x0000080800000008),
+  CONST64(0x0000000000000800), CONST64(0x0000000800000800), CONST64(0x0000000000000808), CONST64(0x0000000800000808),
+  CONST64(0x0000080000000800), CONST64(0x0000080800000800), CONST64(0x0000080000000808), CONST64(0x0000080800000808),
+  CONST64(0x0008000000000000), CONST64(0x0008000800000000), CONST64(0x0008000000000008), CONST64(0x0008000800000008),
+  CONST64(0x0008080000000000), CONST64(0x0008080800000000), CONST64(0x0008080000000008), CONST64(0x0008080800000008),
+  CONST64(0x0008000000000800), CONST64(0x0008000800000800), CONST64(0x0008000000000808), CONST64(0x0008000800000808),
+  CONST64(0x0008080000000800), CONST64(0x0008080800000800), CONST64(0x0008080000000808), CONST64(0x0008080800000808),
+  CONST64(0x0000000000080000), CONST64(0x0000000800080000), CONST64(0x0000000000080008), CONST64(0x0000000800080008),
+  CONST64(0x0000080000080000), CONST64(0x0000080800080000), CONST64(0x0000080000080008), CONST64(0x0000080800080008),
+  CONST64(0x0000000000080800), CONST64(0x0000000800080800), CONST64(0x0000000000080808), CONST64(0x0000000800080808),
+  CONST64(0x0000080000080800), CONST64(0x0000080800080800), CONST64(0x0000080000080808), CONST64(0x0000080800080808),
+  CONST64(0x0008000000080000), CONST64(0x0008000800080000), CONST64(0x0008000000080008), CONST64(0x0008000800080008),
+  CONST64(0x0008080000080000), CONST64(0x0008080800080000), CONST64(0x0008080000080008), CONST64(0x0008080800080008),
+  CONST64(0x0008000000080800), CONST64(0x0008000800080800), CONST64(0x0008000000080808), CONST64(0x0008000800080808),
+  CONST64(0x0008080000080800), CONST64(0x0008080800080800), CONST64(0x0008080000080808), CONST64(0x0008080800080808),
+  CONST64(0x0800000000000000), CONST64(0x0800000800000000), CONST64(0x0800000000000008), CONST64(0x0800000800000008),
+  CONST64(0x0800080000000000), CONST64(0x0800080800000000), CONST64(0x0800080000000008), CONST64(0x0800080800000008),
+  CONST64(0x0800000000000800), CONST64(0x0800000800000800), CONST64(0x0800000000000808), CONST64(0x0800000800000808),
+  CONST64(0x0800080000000800), CONST64(0x0800080800000800), CONST64(0x0800080000000808), CONST64(0x0800080800000808),
+  CONST64(0x0808000000000000), CONST64(0x0808000800000000), CONST64(0x0808000000000008), CONST64(0x0808000800000008),
+  CONST64(0x0808080000000000), CONST64(0x0808080800000000), CONST64(0x0808080000000008), CONST64(0x0808080800000008),
+  CONST64(0x0808000000000800), CONST64(0x0808000800000800), CONST64(0x0808000000000808), CONST64(0x0808000800000808),
+  CONST64(0x0808080000000800), CONST64(0x0808080800000800), CONST64(0x0808080000000808), CONST64(0x0808080800000808),
+  CONST64(0x0800000000080000), CONST64(0x0800000800080000), CONST64(0x0800000000080008), CONST64(0x0800000800080008),
+  CONST64(0x0800080000080000), CONST64(0x0800080800080000), CONST64(0x0800080000080008), CONST64(0x0800080800080008),
+  CONST64(0x0800000000080800), CONST64(0x0800000800080800), CONST64(0x0800000000080808), CONST64(0x0800000800080808),
+  CONST64(0x0800080000080800), CONST64(0x0800080800080800), CONST64(0x0800080000080808), CONST64(0x0800080800080808),
+  CONST64(0x0808000000080000), CONST64(0x0808000800080000), CONST64(0x0808000000080008), CONST64(0x0808000800080008),
+  CONST64(0x0808080000080000), CONST64(0x0808080800080000), CONST64(0x0808080000080008), CONST64(0x0808080800080008),
+  CONST64(0x0808000000080800), CONST64(0x0808000800080800), CONST64(0x0808000000080808), CONST64(0x0808000800080808),
+  CONST64(0x0808080000080800), CONST64(0x0808080800080800), CONST64(0x0808080000080808), CONST64(0x0808080800080808),
+  CONST64(0x0000000008000000), CONST64(0x0000000808000000), CONST64(0x0000000008000008), CONST64(0x0000000808000008),
+  CONST64(0x0000080008000000), CONST64(0x0000080808000000), CONST64(0x0000080008000008), CONST64(0x0000080808000008),
+  CONST64(0x0000000008000800), CONST64(0x0000000808000800), CONST64(0x0000000008000808), CONST64(0x0000000808000808),
+  CONST64(0x0000080008000800), CONST64(0x0000080808000800), CONST64(0x0000080008000808), CONST64(0x0000080808000808),
+  CONST64(0x0008000008000000), CONST64(0x0008000808000000), CONST64(0x0008000008000008), CONST64(0x0008000808000008),
+  CONST64(0x0008080008000000), CONST64(0x0008080808000000), CONST64(0x0008080008000008), CONST64(0x0008080808000008),
+  CONST64(0x0008000008000800), CONST64(0x0008000808000800), CONST64(0x0008000008000808), CONST64(0x0008000808000808),
+  CONST64(0x0008080008000800), CONST64(0x0008080808000800), CONST64(0x0008080008000808), CONST64(0x0008080808000808),
+  CONST64(0x0000000008080000), CONST64(0x0000000808080000), CONST64(0x0000000008080008), CONST64(0x0000000808080008),
+  CONST64(0x0000080008080000), CONST64(0x0000080808080000), CONST64(0x0000080008080008), CONST64(0x0000080808080008),
+  CONST64(0x0000000008080800), CONST64(0x0000000808080800), CONST64(0x0000000008080808), CONST64(0x0000000808080808),
+  CONST64(0x0000080008080800), CONST64(0x0000080808080800), CONST64(0x0000080008080808), CONST64(0x0000080808080808),
+  CONST64(0x0008000008080000), CONST64(0x0008000808080000), CONST64(0x0008000008080008), CONST64(0x0008000808080008),
+  CONST64(0x0008080008080000), CONST64(0x0008080808080000), CONST64(0x0008080008080008), CONST64(0x0008080808080008),
+  CONST64(0x0008000008080800), CONST64(0x0008000808080800), CONST64(0x0008000008080808), CONST64(0x0008000808080808),
+  CONST64(0x0008080008080800), CONST64(0x0008080808080800), CONST64(0x0008080008080808), CONST64(0x0008080808080808),
+  CONST64(0x0800000008000000), CONST64(0x0800000808000000), CONST64(0x0800000008000008), CONST64(0x0800000808000008),
+  CONST64(0x0800080008000000), CONST64(0x0800080808000000), CONST64(0x0800080008000008), CONST64(0x0800080808000008),
+  CONST64(0x0800000008000800), CONST64(0x0800000808000800), CONST64(0x0800000008000808), CONST64(0x0800000808000808),
+  CONST64(0x0800080008000800), CONST64(0x0800080808000800), CONST64(0x0800080008000808), CONST64(0x0800080808000808),
+  CONST64(0x0808000008000000), CONST64(0x0808000808000000), CONST64(0x0808000008000008), CONST64(0x0808000808000008),
+  CONST64(0x0808080008000000), CONST64(0x0808080808000000), CONST64(0x0808080008000008), CONST64(0x0808080808000008),
+  CONST64(0x0808000008000800), CONST64(0x0808000808000800), CONST64(0x0808000008000808), CONST64(0x0808000808000808),
+  CONST64(0x0808080008000800), CONST64(0x0808080808000800), CONST64(0x0808080008000808), CONST64(0x0808080808000808),
+  CONST64(0x0800000008080000), CONST64(0x0800000808080000), CONST64(0x0800000008080008), CONST64(0x0800000808080008),
+  CONST64(0x0800080008080000), CONST64(0x0800080808080000), CONST64(0x0800080008080008), CONST64(0x0800080808080008),
+  CONST64(0x0800000008080800), CONST64(0x0800000808080800), CONST64(0x0800000008080808), CONST64(0x0800000808080808),
+  CONST64(0x0800080008080800), CONST64(0x0800080808080800), CONST64(0x0800080008080808), CONST64(0x0800080808080808),
+  CONST64(0x0808000008080000), CONST64(0x0808000808080000), CONST64(0x0808000008080008), CONST64(0x0808000808080008),
+  CONST64(0x0808080008080000), CONST64(0x0808080808080000), CONST64(0x0808080008080008), CONST64(0x0808080808080008),
+  CONST64(0x0808000008080800), CONST64(0x0808000808080800), CONST64(0x0808000008080808), CONST64(0x0808000808080808),
+  CONST64(0x0808080008080800), CONST64(0x0808080808080800), CONST64(0x0808080008080808), CONST64(0x0808080808080808)
+  },
+{ CONST64(0x0000000000000000), CONST64(0x0000000400000000), CONST64(0x0000000000000004), CONST64(0x0000000400000004),
+  CONST64(0x0000040000000000), CONST64(0x0000040400000000), CONST64(0x0000040000000004), CONST64(0x0000040400000004),
+  CONST64(0x0000000000000400), CONST64(0x0000000400000400), CONST64(0x0000000000000404), CONST64(0x0000000400000404),
+  CONST64(0x0000040000000400), CONST64(0x0000040400000400), CONST64(0x0000040000000404), CONST64(0x0000040400000404),
+  CONST64(0x0004000000000000), CONST64(0x0004000400000000), CONST64(0x0004000000000004), CONST64(0x0004000400000004),
+  CONST64(0x0004040000000000), CONST64(0x0004040400000000), CONST64(0x0004040000000004), CONST64(0x0004040400000004),
+  CONST64(0x0004000000000400), CONST64(0x0004000400000400), CONST64(0x0004000000000404), CONST64(0x0004000400000404),
+  CONST64(0x0004040000000400), CONST64(0x0004040400000400), CONST64(0x0004040000000404), CONST64(0x0004040400000404),
+  CONST64(0x0000000000040000), CONST64(0x0000000400040000), CONST64(0x0000000000040004), CONST64(0x0000000400040004),
+  CONST64(0x0000040000040000), CONST64(0x0000040400040000), CONST64(0x0000040000040004), CONST64(0x0000040400040004),
+  CONST64(0x0000000000040400), CONST64(0x0000000400040400), CONST64(0x0000000000040404), CONST64(0x0000000400040404),
+  CONST64(0x0000040000040400), CONST64(0x0000040400040400), CONST64(0x0000040000040404), CONST64(0x0000040400040404),
+  CONST64(0x0004000000040000), CONST64(0x0004000400040000), CONST64(0x0004000000040004), CONST64(0x0004000400040004),
+  CONST64(0x0004040000040000), CONST64(0x0004040400040000), CONST64(0x0004040000040004), CONST64(0x0004040400040004),
+  CONST64(0x0004000000040400), CONST64(0x0004000400040400), CONST64(0x0004000000040404), CONST64(0x0004000400040404),
+  CONST64(0x0004040000040400), CONST64(0x0004040400040400), CONST64(0x0004040000040404), CONST64(0x0004040400040404),
+  CONST64(0x0400000000000000), CONST64(0x0400000400000000), CONST64(0x0400000000000004), CONST64(0x0400000400000004),
+  CONST64(0x0400040000000000), CONST64(0x0400040400000000), CONST64(0x0400040000000004), CONST64(0x0400040400000004),
+  CONST64(0x0400000000000400), CONST64(0x0400000400000400), CONST64(0x0400000000000404), CONST64(0x0400000400000404),
+  CONST64(0x0400040000000400), CONST64(0x0400040400000400), CONST64(0x0400040000000404), CONST64(0x0400040400000404),
+  CONST64(0x0404000000000000), CONST64(0x0404000400000000), CONST64(0x0404000000000004), CONST64(0x0404000400000004),
+  CONST64(0x0404040000000000), CONST64(0x0404040400000000), CONST64(0x0404040000000004), CONST64(0x0404040400000004),
+  CONST64(0x0404000000000400), CONST64(0x0404000400000400), CONST64(0x0404000000000404), CONST64(0x0404000400000404),
+  CONST64(0x0404040000000400), CONST64(0x0404040400000400), CONST64(0x0404040000000404), CONST64(0x0404040400000404),
+  CONST64(0x0400000000040000), CONST64(0x0400000400040000), CONST64(0x0400000000040004), CONST64(0x0400000400040004),
+  CONST64(0x0400040000040000), CONST64(0x0400040400040000), CONST64(0x0400040000040004), CONST64(0x0400040400040004),
+  CONST64(0x0400000000040400), CONST64(0x0400000400040400), CONST64(0x0400000000040404), CONST64(0x0400000400040404),
+  CONST64(0x0400040000040400), CONST64(0x0400040400040400), CONST64(0x0400040000040404), CONST64(0x0400040400040404),
+  CONST64(0x0404000000040000), CONST64(0x0404000400040000), CONST64(0x0404000000040004), CONST64(0x0404000400040004),
+  CONST64(0x0404040000040000), CONST64(0x0404040400040000), CONST64(0x0404040000040004), CONST64(0x0404040400040004),
+  CONST64(0x0404000000040400), CONST64(0x0404000400040400), CONST64(0x0404000000040404), CONST64(0x0404000400040404),
+  CONST64(0x0404040000040400), CONST64(0x0404040400040400), CONST64(0x0404040000040404), CONST64(0x0404040400040404),
+  CONST64(0x0000000004000000), CONST64(0x0000000404000000), CONST64(0x0000000004000004), CONST64(0x0000000404000004),
+  CONST64(0x0000040004000000), CONST64(0x0000040404000000), CONST64(0x0000040004000004), CONST64(0x0000040404000004),
+  CONST64(0x0000000004000400), CONST64(0x0000000404000400), CONST64(0x0000000004000404), CONST64(0x0000000404000404),
+  CONST64(0x0000040004000400), CONST64(0x0000040404000400), CONST64(0x0000040004000404), CONST64(0x0000040404000404),
+  CONST64(0x0004000004000000), CONST64(0x0004000404000000), CONST64(0x0004000004000004), CONST64(0x0004000404000004),
+  CONST64(0x0004040004000000), CONST64(0x0004040404000000), CONST64(0x0004040004000004), CONST64(0x0004040404000004),
+  CONST64(0x0004000004000400), CONST64(0x0004000404000400), CONST64(0x0004000004000404), CONST64(0x0004000404000404),
+  CONST64(0x0004040004000400), CONST64(0x0004040404000400), CONST64(0x0004040004000404), CONST64(0x0004040404000404),
+  CONST64(0x0000000004040000), CONST64(0x0000000404040000), CONST64(0x0000000004040004), CONST64(0x0000000404040004),
+  CONST64(0x0000040004040000), CONST64(0x0000040404040000), CONST64(0x0000040004040004), CONST64(0x0000040404040004),
+  CONST64(0x0000000004040400), CONST64(0x0000000404040400), CONST64(0x0000000004040404), CONST64(0x0000000404040404),
+  CONST64(0x0000040004040400), CONST64(0x0000040404040400), CONST64(0x0000040004040404), CONST64(0x0000040404040404),
+  CONST64(0x0004000004040000), CONST64(0x0004000404040000), CONST64(0x0004000004040004), CONST64(0x0004000404040004),
+  CONST64(0x0004040004040000), CONST64(0x0004040404040000), CONST64(0x0004040004040004), CONST64(0x0004040404040004),
+  CONST64(0x0004000004040400), CONST64(0x0004000404040400), CONST64(0x0004000004040404), CONST64(0x0004000404040404),
+  CONST64(0x0004040004040400), CONST64(0x0004040404040400), CONST64(0x0004040004040404), CONST64(0x0004040404040404),
+  CONST64(0x0400000004000000), CONST64(0x0400000404000000), CONST64(0x0400000004000004), CONST64(0x0400000404000004),
+  CONST64(0x0400040004000000), CONST64(0x0400040404000000), CONST64(0x0400040004000004), CONST64(0x0400040404000004),
+  CONST64(0x0400000004000400), CONST64(0x0400000404000400), CONST64(0x0400000004000404), CONST64(0x0400000404000404),
+  CONST64(0x0400040004000400), CONST64(0x0400040404000400), CONST64(0x0400040004000404), CONST64(0x0400040404000404),
+  CONST64(0x0404000004000000), CONST64(0x0404000404000000), CONST64(0x0404000004000004), CONST64(0x0404000404000004),
+  CONST64(0x0404040004000000), CONST64(0x0404040404000000), CONST64(0x0404040004000004), CONST64(0x0404040404000004),
+  CONST64(0x0404000004000400), CONST64(0x0404000404000400), CONST64(0x0404000004000404), CONST64(0x0404000404000404),
+  CONST64(0x0404040004000400), CONST64(0x0404040404000400), CONST64(0x0404040004000404), CONST64(0x0404040404000404),
+  CONST64(0x0400000004040000), CONST64(0x0400000404040000), CONST64(0x0400000004040004), CONST64(0x0400000404040004),
+  CONST64(0x0400040004040000), CONST64(0x0400040404040000), CONST64(0x0400040004040004), CONST64(0x0400040404040004),
+  CONST64(0x0400000004040400), CONST64(0x0400000404040400), CONST64(0x0400000004040404), CONST64(0x0400000404040404),
+  CONST64(0x0400040004040400), CONST64(0x0400040404040400), CONST64(0x0400040004040404), CONST64(0x0400040404040404),
+  CONST64(0x0404000004040000), CONST64(0x0404000404040000), CONST64(0x0404000004040004), CONST64(0x0404000404040004),
+  CONST64(0x0404040004040000), CONST64(0x0404040404040000), CONST64(0x0404040004040004), CONST64(0x0404040404040004),
+  CONST64(0x0404000004040400), CONST64(0x0404000404040400), CONST64(0x0404000004040404), CONST64(0x0404000404040404),
+  CONST64(0x0404040004040400), CONST64(0x0404040404040400), CONST64(0x0404040004040404), CONST64(0x0404040404040404)
+  },
+{ CONST64(0x0000000000000000), CONST64(0x0000000200000000), CONST64(0x0000000000000002), CONST64(0x0000000200000002),
+  CONST64(0x0000020000000000), CONST64(0x0000020200000000), CONST64(0x0000020000000002), CONST64(0x0000020200000002),
+  CONST64(0x0000000000000200), CONST64(0x0000000200000200), CONST64(0x0000000000000202), CONST64(0x0000000200000202),
+  CONST64(0x0000020000000200), CONST64(0x0000020200000200), CONST64(0x0000020000000202), CONST64(0x0000020200000202),
+  CONST64(0x0002000000000000), CONST64(0x0002000200000000), CONST64(0x0002000000000002), CONST64(0x0002000200000002),
+  CONST64(0x0002020000000000), CONST64(0x0002020200000000), CONST64(0x0002020000000002), CONST64(0x0002020200000002),
+  CONST64(0x0002000000000200), CONST64(0x0002000200000200), CONST64(0x0002000000000202), CONST64(0x0002000200000202),
+  CONST64(0x0002020000000200), CONST64(0x0002020200000200), CONST64(0x0002020000000202), CONST64(0x0002020200000202),
+  CONST64(0x0000000000020000), CONST64(0x0000000200020000), CONST64(0x0000000000020002), CONST64(0x0000000200020002),
+  CONST64(0x0000020000020000), CONST64(0x0000020200020000), CONST64(0x0000020000020002), CONST64(0x0000020200020002),
+  CONST64(0x0000000000020200), CONST64(0x0000000200020200), CONST64(0x0000000000020202), CONST64(0x0000000200020202),
+  CONST64(0x0000020000020200), CONST64(0x0000020200020200), CONST64(0x0000020000020202), CONST64(0x0000020200020202),
+  CONST64(0x0002000000020000), CONST64(0x0002000200020000), CONST64(0x0002000000020002), CONST64(0x0002000200020002),
+  CONST64(0x0002020000020000), CONST64(0x0002020200020000), CONST64(0x0002020000020002), CONST64(0x0002020200020002),
+  CONST64(0x0002000000020200), CONST64(0x0002000200020200), CONST64(0x0002000000020202), CONST64(0x0002000200020202),
+  CONST64(0x0002020000020200), CONST64(0x0002020200020200), CONST64(0x0002020000020202), CONST64(0x0002020200020202),
+  CONST64(0x0200000000000000), CONST64(0x0200000200000000), CONST64(0x0200000000000002), CONST64(0x0200000200000002),
+  CONST64(0x0200020000000000), CONST64(0x0200020200000000), CONST64(0x0200020000000002), CONST64(0x0200020200000002),
+  CONST64(0x0200000000000200), CONST64(0x0200000200000200), CONST64(0x0200000000000202), CONST64(0x0200000200000202),
+  CONST64(0x0200020000000200), CONST64(0x0200020200000200), CONST64(0x0200020000000202), CONST64(0x0200020200000202),
+  CONST64(0x0202000000000000), CONST64(0x0202000200000000), CONST64(0x0202000000000002), CONST64(0x0202000200000002),
+  CONST64(0x0202020000000000), CONST64(0x0202020200000000), CONST64(0x0202020000000002), CONST64(0x0202020200000002),
+  CONST64(0x0202000000000200), CONST64(0x0202000200000200), CONST64(0x0202000000000202), CONST64(0x0202000200000202),
+  CONST64(0x0202020000000200), CONST64(0x0202020200000200), CONST64(0x0202020000000202), CONST64(0x0202020200000202),
+  CONST64(0x0200000000020000), CONST64(0x0200000200020000), CONST64(0x0200000000020002), CONST64(0x0200000200020002),
+  CONST64(0x0200020000020000), CONST64(0x0200020200020000), CONST64(0x0200020000020002), CONST64(0x0200020200020002),
+  CONST64(0x0200000000020200), CONST64(0x0200000200020200), CONST64(0x0200000000020202), CONST64(0x0200000200020202),
+  CONST64(0x0200020000020200), CONST64(0x0200020200020200), CONST64(0x0200020000020202), CONST64(0x0200020200020202),
+  CONST64(0x0202000000020000), CONST64(0x0202000200020000), CONST64(0x0202000000020002), CONST64(0x0202000200020002),
+  CONST64(0x0202020000020000), CONST64(0x0202020200020000), CONST64(0x0202020000020002), CONST64(0x0202020200020002),
+  CONST64(0x0202000000020200), CONST64(0x0202000200020200), CONST64(0x0202000000020202), CONST64(0x0202000200020202),
+  CONST64(0x0202020000020200), CONST64(0x0202020200020200), CONST64(0x0202020000020202), CONST64(0x0202020200020202),
+  CONST64(0x0000000002000000), CONST64(0x0000000202000000), CONST64(0x0000000002000002), CONST64(0x0000000202000002),
+  CONST64(0x0000020002000000), CONST64(0x0000020202000000), CONST64(0x0000020002000002), CONST64(0x0000020202000002),
+  CONST64(0x0000000002000200), CONST64(0x0000000202000200), CONST64(0x0000000002000202), CONST64(0x0000000202000202),
+  CONST64(0x0000020002000200), CONST64(0x0000020202000200), CONST64(0x0000020002000202), CONST64(0x0000020202000202),
+  CONST64(0x0002000002000000), CONST64(0x0002000202000000), CONST64(0x0002000002000002), CONST64(0x0002000202000002),
+  CONST64(0x0002020002000000), CONST64(0x0002020202000000), CONST64(0x0002020002000002), CONST64(0x0002020202000002),
+  CONST64(0x0002000002000200), CONST64(0x0002000202000200), CONST64(0x0002000002000202), CONST64(0x0002000202000202),
+  CONST64(0x0002020002000200), CONST64(0x0002020202000200), CONST64(0x0002020002000202), CONST64(0x0002020202000202),
+  CONST64(0x0000000002020000), CONST64(0x0000000202020000), CONST64(0x0000000002020002), CONST64(0x0000000202020002),
+  CONST64(0x0000020002020000), CONST64(0x0000020202020000), CONST64(0x0000020002020002), CONST64(0x0000020202020002),
+  CONST64(0x0000000002020200), CONST64(0x0000000202020200), CONST64(0x0000000002020202), CONST64(0x0000000202020202),
+  CONST64(0x0000020002020200), CONST64(0x0000020202020200), CONST64(0x0000020002020202), CONST64(0x0000020202020202),
+  CONST64(0x0002000002020000), CONST64(0x0002000202020000), CONST64(0x0002000002020002), CONST64(0x0002000202020002),
+  CONST64(0x0002020002020000), CONST64(0x0002020202020000), CONST64(0x0002020002020002), CONST64(0x0002020202020002),
+  CONST64(0x0002000002020200), CONST64(0x0002000202020200), CONST64(0x0002000002020202), CONST64(0x0002000202020202),
+  CONST64(0x0002020002020200), CONST64(0x0002020202020200), CONST64(0x0002020002020202), CONST64(0x0002020202020202),
+  CONST64(0x0200000002000000), CONST64(0x0200000202000000), CONST64(0x0200000002000002), CONST64(0x0200000202000002),
+  CONST64(0x0200020002000000), CONST64(0x0200020202000000), CONST64(0x0200020002000002), CONST64(0x0200020202000002),
+  CONST64(0x0200000002000200), CONST64(0x0200000202000200), CONST64(0x0200000002000202), CONST64(0x0200000202000202),
+  CONST64(0x0200020002000200), CONST64(0x0200020202000200), CONST64(0x0200020002000202), CONST64(0x0200020202000202),
+  CONST64(0x0202000002000000), CONST64(0x0202000202000000), CONST64(0x0202000002000002), CONST64(0x0202000202000002),
+  CONST64(0x0202020002000000), CONST64(0x0202020202000000), CONST64(0x0202020002000002), CONST64(0x0202020202000002),
+  CONST64(0x0202000002000200), CONST64(0x0202000202000200), CONST64(0x0202000002000202), CONST64(0x0202000202000202),
+  CONST64(0x0202020002000200), CONST64(0x0202020202000200), CONST64(0x0202020002000202), CONST64(0x0202020202000202),
+  CONST64(0x0200000002020000), CONST64(0x0200000202020000), CONST64(0x0200000002020002), CONST64(0x0200000202020002),
+  CONST64(0x0200020002020000), CONST64(0x0200020202020000), CONST64(0x0200020002020002), CONST64(0x0200020202020002),
+  CONST64(0x0200000002020200), CONST64(0x0200000202020200), CONST64(0x0200000002020202), CONST64(0x0200000202020202),
+  CONST64(0x0200020002020200), CONST64(0x0200020202020200), CONST64(0x0200020002020202), CONST64(0x0200020202020202),
+  CONST64(0x0202000002020000), CONST64(0x0202000202020000), CONST64(0x0202000002020002), CONST64(0x0202000202020002),
+  CONST64(0x0202020002020000), CONST64(0x0202020202020000), CONST64(0x0202020002020002), CONST64(0x0202020202020002),
+  CONST64(0x0202000002020200), CONST64(0x0202000202020200), CONST64(0x0202000002020202), CONST64(0x0202000202020202),
+  CONST64(0x0202020002020200), CONST64(0x0202020202020200), CONST64(0x0202020002020202), CONST64(0x0202020202020202)
+  },
+{ CONST64(0x0000000000000000), CONST64(0x0000010000000000), CONST64(0x0000000000000100), CONST64(0x0000010000000100),
+  CONST64(0x0001000000000000), CONST64(0x0001010000000000), CONST64(0x0001000000000100), CONST64(0x0001010000000100),
+  CONST64(0x0000000000010000), CONST64(0x0000010000010000), CONST64(0x0000000000010100), CONST64(0x0000010000010100),
+  CONST64(0x0001000000010000), CONST64(0x0001010000010000), CONST64(0x0001000000010100), CONST64(0x0001010000010100),
+  CONST64(0x0100000000000000), CONST64(0x0100010000000000), CONST64(0x0100000000000100), CONST64(0x0100010000000100),
+  CONST64(0x0101000000000000), CONST64(0x0101010000000000), CONST64(0x0101000000000100), CONST64(0x0101010000000100),
+  CONST64(0x0100000000010000), CONST64(0x0100010000010000), CONST64(0x0100000000010100), CONST64(0x0100010000010100),
+  CONST64(0x0101000000010000), CONST64(0x0101010000010000), CONST64(0x0101000000010100), CONST64(0x0101010000010100),
+  CONST64(0x0000000001000000), CONST64(0x0000010001000000), CONST64(0x0000000001000100), CONST64(0x0000010001000100),
+  CONST64(0x0001000001000000), CONST64(0x0001010001000000), CONST64(0x0001000001000100), CONST64(0x0001010001000100),
+  CONST64(0x0000000001010000), CONST64(0x0000010001010000), CONST64(0x0000000001010100), CONST64(0x0000010001010100),
+  CONST64(0x0001000001010000), CONST64(0x0001010001010000), CONST64(0x0001000001010100), CONST64(0x0001010001010100),
+  CONST64(0x0100000001000000), CONST64(0x0100010001000000), CONST64(0x0100000001000100), CONST64(0x0100010001000100),
+  CONST64(0x0101000001000000), CONST64(0x0101010001000000), CONST64(0x0101000001000100), CONST64(0x0101010001000100),
+  CONST64(0x0100000001010000), CONST64(0x0100010001010000), CONST64(0x0100000001010100), CONST64(0x0100010001010100),
+  CONST64(0x0101000001010000), CONST64(0x0101010001010000), CONST64(0x0101000001010100), CONST64(0x0101010001010100),
+  CONST64(0x0000000100000000), CONST64(0x0000010100000000), CONST64(0x0000000100000100), CONST64(0x0000010100000100),
+  CONST64(0x0001000100000000), CONST64(0x0001010100000000), CONST64(0x0001000100000100), CONST64(0x0001010100000100),
+  CONST64(0x0000000100010000), CONST64(0x0000010100010000), CONST64(0x0000000100010100), CONST64(0x0000010100010100),
+  CONST64(0x0001000100010000), CONST64(0x0001010100010000), CONST64(0x0001000100010100), CONST64(0x0001010100010100),
+  CONST64(0x0100000100000000), CONST64(0x0100010100000000), CONST64(0x0100000100000100), CONST64(0x0100010100000100),
+  CONST64(0x0101000100000000), CONST64(0x0101010100000000), CONST64(0x0101000100000100), CONST64(0x0101010100000100),
+  CONST64(0x0100000100010000), CONST64(0x0100010100010000), CONST64(0x0100000100010100), CONST64(0x0100010100010100),
+  CONST64(0x0101000100010000), CONST64(0x0101010100010000), CONST64(0x0101000100010100), CONST64(0x0101010100010100),
+  CONST64(0x0000000101000000), CONST64(0x0000010101000000), CONST64(0x0000000101000100), CONST64(0x0000010101000100),
+  CONST64(0x0001000101000000), CONST64(0x0001010101000000), CONST64(0x0001000101000100), CONST64(0x0001010101000100),
+  CONST64(0x0000000101010000), CONST64(0x0000010101010000), CONST64(0x0000000101010100), CONST64(0x0000010101010100),
+  CONST64(0x0001000101010000), CONST64(0x0001010101010000), CONST64(0x0001000101010100), CONST64(0x0001010101010100),
+  CONST64(0x0100000101000000), CONST64(0x0100010101000000), CONST64(0x0100000101000100), CONST64(0x0100010101000100),
+  CONST64(0x0101000101000000), CONST64(0x0101010101000000), CONST64(0x0101000101000100), CONST64(0x0101010101000100),
+  CONST64(0x0100000101010000), CONST64(0x0100010101010000), CONST64(0x0100000101010100), CONST64(0x0100010101010100),
+  CONST64(0x0101000101010000), CONST64(0x0101010101010000), CONST64(0x0101000101010100), CONST64(0x0101010101010100),
+  CONST64(0x0000000000000001), CONST64(0x0000010000000001), CONST64(0x0000000000000101), CONST64(0x0000010000000101),
+  CONST64(0x0001000000000001), CONST64(0x0001010000000001), CONST64(0x0001000000000101), CONST64(0x0001010000000101),
+  CONST64(0x0000000000010001), CONST64(0x0000010000010001), CONST64(0x0000000000010101), CONST64(0x0000010000010101),
+  CONST64(0x0001000000010001), CONST64(0x0001010000010001), CONST64(0x0001000000010101), CONST64(0x0001010000010101),
+  CONST64(0x0100000000000001), CONST64(0x0100010000000001), CONST64(0x0100000000000101), CONST64(0x0100010000000101),
+  CONST64(0x0101000000000001), CONST64(0x0101010000000001), CONST64(0x0101000000000101), CONST64(0x0101010000000101),
+  CONST64(0x0100000000010001), CONST64(0x0100010000010001), CONST64(0x0100000000010101), CONST64(0x0100010000010101),
+  CONST64(0x0101000000010001), CONST64(0x0101010000010001), CONST64(0x0101000000010101), CONST64(0x0101010000010101),
+  CONST64(0x0000000001000001), CONST64(0x0000010001000001), CONST64(0x0000000001000101), CONST64(0x0000010001000101),
+  CONST64(0x0001000001000001), CONST64(0x0001010001000001), CONST64(0x0001000001000101), CONST64(0x0001010001000101),
+  CONST64(0x0000000001010001), CONST64(0x0000010001010001), CONST64(0x0000000001010101), CONST64(0x0000010001010101),
+  CONST64(0x0001000001010001), CONST64(0x0001010001010001), CONST64(0x0001000001010101), CONST64(0x0001010001010101),
+  CONST64(0x0100000001000001), CONST64(0x0100010001000001), CONST64(0x0100000001000101), CONST64(0x0100010001000101),
+  CONST64(0x0101000001000001), CONST64(0x0101010001000001), CONST64(0x0101000001000101), CONST64(0x0101010001000101),
+  CONST64(0x0100000001010001), CONST64(0x0100010001010001), CONST64(0x0100000001010101), CONST64(0x0100010001010101),
+  CONST64(0x0101000001010001), CONST64(0x0101010001010001), CONST64(0x0101000001010101), CONST64(0x0101010001010101),
+  CONST64(0x0000000100000001), CONST64(0x0000010100000001), CONST64(0x0000000100000101), CONST64(0x0000010100000101),
+  CONST64(0x0001000100000001), CONST64(0x0001010100000001), CONST64(0x0001000100000101), CONST64(0x0001010100000101),
+  CONST64(0x0000000100010001), CONST64(0x0000010100010001), CONST64(0x0000000100010101), CONST64(0x0000010100010101),
+  CONST64(0x0001000100010001), CONST64(0x0001010100010001), CONST64(0x0001000100010101), CONST64(0x0001010100010101),
+  CONST64(0x0100000100000001), CONST64(0x0100010100000001), CONST64(0x0100000100000101), CONST64(0x0100010100000101),
+  CONST64(0x0101000100000001), CONST64(0x0101010100000001), CONST64(0x0101000100000101), CONST64(0x0101010100000101),
+  CONST64(0x0100000100010001), CONST64(0x0100010100010001), CONST64(0x0100000100010101), CONST64(0x0100010100010101),
+  CONST64(0x0101000100010001), CONST64(0x0101010100010001), CONST64(0x0101000100010101), CONST64(0x0101010100010101),
+  CONST64(0x0000000101000001), CONST64(0x0000010101000001), CONST64(0x0000000101000101), CONST64(0x0000010101000101),
+  CONST64(0x0001000101000001), CONST64(0x0001010101000001), CONST64(0x0001000101000101), CONST64(0x0001010101000101),
+  CONST64(0x0000000101010001), CONST64(0x0000010101010001), CONST64(0x0000000101010101), CONST64(0x0000010101010101),
+  CONST64(0x0001000101010001), CONST64(0x0001010101010001), CONST64(0x0001000101010101), CONST64(0x0001010101010101),
+  CONST64(0x0100000101000001), CONST64(0x0100010101000001), CONST64(0x0100000101000101), CONST64(0x0100010101000101),
+  CONST64(0x0101000101000001), CONST64(0x0101010101000001), CONST64(0x0101000101000101), CONST64(0x0101010101000101),
+  CONST64(0x0100000101010001), CONST64(0x0100010101010001), CONST64(0x0100000101010101), CONST64(0x0100010101010101),
+  CONST64(0x0101000101010001), CONST64(0x0101010101010001), CONST64(0x0101000101010101), CONST64(0x0101010101010101)
+  },
+{ CONST64(0x0000000000000000), CONST64(0x0000008000000000), CONST64(0x0000000000000080), CONST64(0x0000008000000080),
+  CONST64(0x0000800000000000), CONST64(0x0000808000000000), CONST64(0x0000800000000080), CONST64(0x0000808000000080),
+  CONST64(0x0000000000008000), CONST64(0x0000008000008000), CONST64(0x0000000000008080), CONST64(0x0000008000008080),
+  CONST64(0x0000800000008000), CONST64(0x0000808000008000), CONST64(0x0000800000008080), CONST64(0x0000808000008080),
+  CONST64(0x0080000000000000), CONST64(0x0080008000000000), CONST64(0x0080000000000080), CONST64(0x0080008000000080),
+  CONST64(0x0080800000000000), CONST64(0x0080808000000000), CONST64(0x0080800000000080), CONST64(0x0080808000000080),
+  CONST64(0x0080000000008000), CONST64(0x0080008000008000), CONST64(0x0080000000008080), CONST64(0x0080008000008080),
+  CONST64(0x0080800000008000), CONST64(0x0080808000008000), CONST64(0x0080800000008080), CONST64(0x0080808000008080),
+  CONST64(0x0000000000800000), CONST64(0x0000008000800000), CONST64(0x0000000000800080), CONST64(0x0000008000800080),
+  CONST64(0x0000800000800000), CONST64(0x0000808000800000), CONST64(0x0000800000800080), CONST64(0x0000808000800080),
+  CONST64(0x0000000000808000), CONST64(0x0000008000808000), CONST64(0x0000000000808080), CONST64(0x0000008000808080),
+  CONST64(0x0000800000808000), CONST64(0x0000808000808000), CONST64(0x0000800000808080), CONST64(0x0000808000808080),
+  CONST64(0x0080000000800000), CONST64(0x0080008000800000), CONST64(0x0080000000800080), CONST64(0x0080008000800080),
+  CONST64(0x0080800000800000), CONST64(0x0080808000800000), CONST64(0x0080800000800080), CONST64(0x0080808000800080),
+  CONST64(0x0080000000808000), CONST64(0x0080008000808000), CONST64(0x0080000000808080), CONST64(0x0080008000808080),
+  CONST64(0x0080800000808000), CONST64(0x0080808000808000), CONST64(0x0080800000808080), CONST64(0x0080808000808080),
+  CONST64(0x8000000000000000), CONST64(0x8000008000000000), CONST64(0x8000000000000080), CONST64(0x8000008000000080),
+  CONST64(0x8000800000000000), CONST64(0x8000808000000000), CONST64(0x8000800000000080), CONST64(0x8000808000000080),
+  CONST64(0x8000000000008000), CONST64(0x8000008000008000), CONST64(0x8000000000008080), CONST64(0x8000008000008080),
+  CONST64(0x8000800000008000), CONST64(0x8000808000008000), CONST64(0x8000800000008080), CONST64(0x8000808000008080),
+  CONST64(0x8080000000000000), CONST64(0x8080008000000000), CONST64(0x8080000000000080), CONST64(0x8080008000000080),
+  CONST64(0x8080800000000000), CONST64(0x8080808000000000), CONST64(0x8080800000000080), CONST64(0x8080808000000080),
+  CONST64(0x8080000000008000), CONST64(0x8080008000008000), CONST64(0x8080000000008080), CONST64(0x8080008000008080),
+  CONST64(0x8080800000008000), CONST64(0x8080808000008000), CONST64(0x8080800000008080), CONST64(0x8080808000008080),
+  CONST64(0x8000000000800000), CONST64(0x8000008000800000), CONST64(0x8000000000800080), CONST64(0x8000008000800080),
+  CONST64(0x8000800000800000), CONST64(0x8000808000800000), CONST64(0x8000800000800080), CONST64(0x8000808000800080),
+  CONST64(0x8000000000808000), CONST64(0x8000008000808000), CONST64(0x8000000000808080), CONST64(0x8000008000808080),
+  CONST64(0x8000800000808000), CONST64(0x8000808000808000), CONST64(0x8000800000808080), CONST64(0x8000808000808080),
+  CONST64(0x8080000000800000), CONST64(0x8080008000800000), CONST64(0x8080000000800080), CONST64(0x8080008000800080),
+  CONST64(0x8080800000800000), CONST64(0x8080808000800000), CONST64(0x8080800000800080), CONST64(0x8080808000800080),
+  CONST64(0x8080000000808000), CONST64(0x8080008000808000), CONST64(0x8080000000808080), CONST64(0x8080008000808080),
+  CONST64(0x8080800000808000), CONST64(0x8080808000808000), CONST64(0x8080800000808080), CONST64(0x8080808000808080),
+  CONST64(0x0000000080000000), CONST64(0x0000008080000000), CONST64(0x0000000080000080), CONST64(0x0000008080000080),
+  CONST64(0x0000800080000000), CONST64(0x0000808080000000), CONST64(0x0000800080000080), CONST64(0x0000808080000080),
+  CONST64(0x0000000080008000), CONST64(0x0000008080008000), CONST64(0x0000000080008080), CONST64(0x0000008080008080),
+  CONST64(0x0000800080008000), CONST64(0x0000808080008000), CONST64(0x0000800080008080), CONST64(0x0000808080008080),
+  CONST64(0x0080000080000000), CONST64(0x0080008080000000), CONST64(0x0080000080000080), CONST64(0x0080008080000080),
+  CONST64(0x0080800080000000), CONST64(0x0080808080000000), CONST64(0x0080800080000080), CONST64(0x0080808080000080),
+  CONST64(0x0080000080008000), CONST64(0x0080008080008000), CONST64(0x0080000080008080), CONST64(0x0080008080008080),
+  CONST64(0x0080800080008000), CONST64(0x0080808080008000), CONST64(0x0080800080008080), CONST64(0x0080808080008080),
+  CONST64(0x0000000080800000), CONST64(0x0000008080800000), CONST64(0x0000000080800080), CONST64(0x0000008080800080),
+  CONST64(0x0000800080800000), CONST64(0x0000808080800000), CONST64(0x0000800080800080), CONST64(0x0000808080800080),
+  CONST64(0x0000000080808000), CONST64(0x0000008080808000), CONST64(0x0000000080808080), CONST64(0x0000008080808080),
+  CONST64(0x0000800080808000), CONST64(0x0000808080808000), CONST64(0x0000800080808080), CONST64(0x0000808080808080),
+  CONST64(0x0080000080800000), CONST64(0x0080008080800000), CONST64(0x0080000080800080), CONST64(0x0080008080800080),
+  CONST64(0x0080800080800000), CONST64(0x0080808080800000), CONST64(0x0080800080800080), CONST64(0x0080808080800080),
+  CONST64(0x0080000080808000), CONST64(0x0080008080808000), CONST64(0x0080000080808080), CONST64(0x0080008080808080),
+  CONST64(0x0080800080808000), CONST64(0x0080808080808000), CONST64(0x0080800080808080), CONST64(0x0080808080808080),
+  CONST64(0x8000000080000000), CONST64(0x8000008080000000), CONST64(0x8000000080000080), CONST64(0x8000008080000080),
+  CONST64(0x8000800080000000), CONST64(0x8000808080000000), CONST64(0x8000800080000080), CONST64(0x8000808080000080),
+  CONST64(0x8000000080008000), CONST64(0x8000008080008000), CONST64(0x8000000080008080), CONST64(0x8000008080008080),
+  CONST64(0x8000800080008000), CONST64(0x8000808080008000), CONST64(0x8000800080008080), CONST64(0x8000808080008080),
+  CONST64(0x8080000080000000), CONST64(0x8080008080000000), CONST64(0x8080000080000080), CONST64(0x8080008080000080),
+  CONST64(0x8080800080000000), CONST64(0x8080808080000000), CONST64(0x8080800080000080), CONST64(0x8080808080000080),
+  CONST64(0x8080000080008000), CONST64(0x8080008080008000), CONST64(0x8080000080008080), CONST64(0x8080008080008080),
+  CONST64(0x8080800080008000), CONST64(0x8080808080008000), CONST64(0x8080800080008080), CONST64(0x8080808080008080),
+  CONST64(0x8000000080800000), CONST64(0x8000008080800000), CONST64(0x8000000080800080), CONST64(0x8000008080800080),
+  CONST64(0x8000800080800000), CONST64(0x8000808080800000), CONST64(0x8000800080800080), CONST64(0x8000808080800080),
+  CONST64(0x8000000080808000), CONST64(0x8000008080808000), CONST64(0x8000000080808080), CONST64(0x8000008080808080),
+  CONST64(0x8000800080808000), CONST64(0x8000808080808000), CONST64(0x8000800080808080), CONST64(0x8000808080808080),
+  CONST64(0x8080000080800000), CONST64(0x8080008080800000), CONST64(0x8080000080800080), CONST64(0x8080008080800080),
+  CONST64(0x8080800080800000), CONST64(0x8080808080800000), CONST64(0x8080800080800080), CONST64(0x8080808080800080),
+  CONST64(0x8080000080808000), CONST64(0x8080008080808000), CONST64(0x8080000080808080), CONST64(0x8080008080808080),
+  CONST64(0x8080800080808000), CONST64(0x8080808080808000), CONST64(0x8080800080808080), CONST64(0x8080808080808080)
+  },
+{ CONST64(0x0000000000000000), CONST64(0x0000004000000000), CONST64(0x0000000000000040), CONST64(0x0000004000000040),
+  CONST64(0x0000400000000000), CONST64(0x0000404000000000), CONST64(0x0000400000000040), CONST64(0x0000404000000040),
+  CONST64(0x0000000000004000), CONST64(0x0000004000004000), CONST64(0x0000000000004040), CONST64(0x0000004000004040),
+  CONST64(0x0000400000004000), CONST64(0x0000404000004000), CONST64(0x0000400000004040), CONST64(0x0000404000004040),
+  CONST64(0x0040000000000000), CONST64(0x0040004000000000), CONST64(0x0040000000000040), CONST64(0x0040004000000040),
+  CONST64(0x0040400000000000), CONST64(0x0040404000000000), CONST64(0x0040400000000040), CONST64(0x0040404000000040),
+  CONST64(0x0040000000004000), CONST64(0x0040004000004000), CONST64(0x0040000000004040), CONST64(0x0040004000004040),
+  CONST64(0x0040400000004000), CONST64(0x0040404000004000), CONST64(0x0040400000004040), CONST64(0x0040404000004040),
+  CONST64(0x0000000000400000), CONST64(0x0000004000400000), CONST64(0x0000000000400040), CONST64(0x0000004000400040),
+  CONST64(0x0000400000400000), CONST64(0x0000404000400000), CONST64(0x0000400000400040), CONST64(0x0000404000400040),
+  CONST64(0x0000000000404000), CONST64(0x0000004000404000), CONST64(0x0000000000404040), CONST64(0x0000004000404040),
+  CONST64(0x0000400000404000), CONST64(0x0000404000404000), CONST64(0x0000400000404040), CONST64(0x0000404000404040),
+  CONST64(0x0040000000400000), CONST64(0x0040004000400000), CONST64(0x0040000000400040), CONST64(0x0040004000400040),
+  CONST64(0x0040400000400000), CONST64(0x0040404000400000), CONST64(0x0040400000400040), CONST64(0x0040404000400040),
+  CONST64(0x0040000000404000), CONST64(0x0040004000404000), CONST64(0x0040000000404040), CONST64(0x0040004000404040),
+  CONST64(0x0040400000404000), CONST64(0x0040404000404000), CONST64(0x0040400000404040), CONST64(0x0040404000404040),
+  CONST64(0x4000000000000000), CONST64(0x4000004000000000), CONST64(0x4000000000000040), CONST64(0x4000004000000040),
+  CONST64(0x4000400000000000), CONST64(0x4000404000000000), CONST64(0x4000400000000040), CONST64(0x4000404000000040),
+  CONST64(0x4000000000004000), CONST64(0x4000004000004000), CONST64(0x4000000000004040), CONST64(0x4000004000004040),
+  CONST64(0x4000400000004000), CONST64(0x4000404000004000), CONST64(0x4000400000004040), CONST64(0x4000404000004040),
+  CONST64(0x4040000000000000), CONST64(0x4040004000000000), CONST64(0x4040000000000040), CONST64(0x4040004000000040),
+  CONST64(0x4040400000000000), CONST64(0x4040404000000000), CONST64(0x4040400000000040), CONST64(0x4040404000000040),
+  CONST64(0x4040000000004000), CONST64(0x4040004000004000), CONST64(0x4040000000004040), CONST64(0x4040004000004040),
+  CONST64(0x4040400000004000), CONST64(0x4040404000004000), CONST64(0x4040400000004040), CONST64(0x4040404000004040),
+  CONST64(0x4000000000400000), CONST64(0x4000004000400000), CONST64(0x4000000000400040), CONST64(0x4000004000400040),
+  CONST64(0x4000400000400000), CONST64(0x4000404000400000), CONST64(0x4000400000400040), CONST64(0x4000404000400040),
+  CONST64(0x4000000000404000), CONST64(0x4000004000404000), CONST64(0x4000000000404040), CONST64(0x4000004000404040),
+  CONST64(0x4000400000404000), CONST64(0x4000404000404000), CONST64(0x4000400000404040), CONST64(0x4000404000404040),
+  CONST64(0x4040000000400000), CONST64(0x4040004000400000), CONST64(0x4040000000400040), CONST64(0x4040004000400040),
+  CONST64(0x4040400000400000), CONST64(0x4040404000400000), CONST64(0x4040400000400040), CONST64(0x4040404000400040),
+  CONST64(0x4040000000404000), CONST64(0x4040004000404000), CONST64(0x4040000000404040), CONST64(0x4040004000404040),
+  CONST64(0x4040400000404000), CONST64(0x4040404000404000), CONST64(0x4040400000404040), CONST64(0x4040404000404040),
+  CONST64(0x0000000040000000), CONST64(0x0000004040000000), CONST64(0x0000000040000040), CONST64(0x0000004040000040),
+  CONST64(0x0000400040000000), CONST64(0x0000404040000000), CONST64(0x0000400040000040), CONST64(0x0000404040000040),
+  CONST64(0x0000000040004000), CONST64(0x0000004040004000), CONST64(0x0000000040004040), CONST64(0x0000004040004040),
+  CONST64(0x0000400040004000), CONST64(0x0000404040004000), CONST64(0x0000400040004040), CONST64(0x0000404040004040),
+  CONST64(0x0040000040000000), CONST64(0x0040004040000000), CONST64(0x0040000040000040), CONST64(0x0040004040000040),
+  CONST64(0x0040400040000000), CONST64(0x0040404040000000), CONST64(0x0040400040000040), CONST64(0x0040404040000040),
+  CONST64(0x0040000040004000), CONST64(0x0040004040004000), CONST64(0x0040000040004040), CONST64(0x0040004040004040),
+  CONST64(0x0040400040004000), CONST64(0x0040404040004000), CONST64(0x0040400040004040), CONST64(0x0040404040004040),
+  CONST64(0x0000000040400000), CONST64(0x0000004040400000), CONST64(0x0000000040400040), CONST64(0x0000004040400040),
+  CONST64(0x0000400040400000), CONST64(0x0000404040400000), CONST64(0x0000400040400040), CONST64(0x0000404040400040),
+  CONST64(0x0000000040404000), CONST64(0x0000004040404000), CONST64(0x0000000040404040), CONST64(0x0000004040404040),
+  CONST64(0x0000400040404000), CONST64(0x0000404040404000), CONST64(0x0000400040404040), CONST64(0x0000404040404040),
+  CONST64(0x0040000040400000), CONST64(0x0040004040400000), CONST64(0x0040000040400040), CONST64(0x0040004040400040),
+  CONST64(0x0040400040400000), CONST64(0x0040404040400000), CONST64(0x0040400040400040), CONST64(0x0040404040400040),
+  CONST64(0x0040000040404000), CONST64(0x0040004040404000), CONST64(0x0040000040404040), CONST64(0x0040004040404040),
+  CONST64(0x0040400040404000), CONST64(0x0040404040404000), CONST64(0x0040400040404040), CONST64(0x0040404040404040),
+  CONST64(0x4000000040000000), CONST64(0x4000004040000000), CONST64(0x4000000040000040), CONST64(0x4000004040000040),
+  CONST64(0x4000400040000000), CONST64(0x4000404040000000), CONST64(0x4000400040000040), CONST64(0x4000404040000040),
+  CONST64(0x4000000040004000), CONST64(0x4000004040004000), CONST64(0x4000000040004040), CONST64(0x4000004040004040),
+  CONST64(0x4000400040004000), CONST64(0x4000404040004000), CONST64(0x4000400040004040), CONST64(0x4000404040004040),
+  CONST64(0x4040000040000000), CONST64(0x4040004040000000), CONST64(0x4040000040000040), CONST64(0x4040004040000040),
+  CONST64(0x4040400040000000), CONST64(0x4040404040000000), CONST64(0x4040400040000040), CONST64(0x4040404040000040),
+  CONST64(0x4040000040004000), CONST64(0x4040004040004000), CONST64(0x4040000040004040), CONST64(0x4040004040004040),
+  CONST64(0x4040400040004000), CONST64(0x4040404040004000), CONST64(0x4040400040004040), CONST64(0x4040404040004040),
+  CONST64(0x4000000040400000), CONST64(0x4000004040400000), CONST64(0x4000000040400040), CONST64(0x4000004040400040),
+  CONST64(0x4000400040400000), CONST64(0x4000404040400000), CONST64(0x4000400040400040), CONST64(0x4000404040400040),
+  CONST64(0x4000000040404000), CONST64(0x4000004040404000), CONST64(0x4000000040404040), CONST64(0x4000004040404040),
+  CONST64(0x4000400040404000), CONST64(0x4000404040404000), CONST64(0x4000400040404040), CONST64(0x4000404040404040),
+  CONST64(0x4040000040400000), CONST64(0x4040004040400000), CONST64(0x4040000040400040), CONST64(0x4040004040400040),
+  CONST64(0x4040400040400000), CONST64(0x4040404040400000), CONST64(0x4040400040400040), CONST64(0x4040404040400040),
+  CONST64(0x4040000040404000), CONST64(0x4040004040404000), CONST64(0x4040000040404040), CONST64(0x4040004040404040),
+  CONST64(0x4040400040404000), CONST64(0x4040404040404000), CONST64(0x4040400040404040), CONST64(0x4040404040404040)
+  },
+{ CONST64(0x0000000000000000), CONST64(0x0000002000000000), CONST64(0x0000000000000020), CONST64(0x0000002000000020),
+  CONST64(0x0000200000000000), CONST64(0x0000202000000000), CONST64(0x0000200000000020), CONST64(0x0000202000000020),
+  CONST64(0x0000000000002000), CONST64(0x0000002000002000), CONST64(0x0000000000002020), CONST64(0x0000002000002020),
+  CONST64(0x0000200000002000), CONST64(0x0000202000002000), CONST64(0x0000200000002020), CONST64(0x0000202000002020),
+  CONST64(0x0020000000000000), CONST64(0x0020002000000000), CONST64(0x0020000000000020), CONST64(0x0020002000000020),
+  CONST64(0x0020200000000000), CONST64(0x0020202000000000), CONST64(0x0020200000000020), CONST64(0x0020202000000020),
+  CONST64(0x0020000000002000), CONST64(0x0020002000002000), CONST64(0x0020000000002020), CONST64(0x0020002000002020),
+  CONST64(0x0020200000002000), CONST64(0x0020202000002000), CONST64(0x0020200000002020), CONST64(0x0020202000002020),
+  CONST64(0x0000000000200000), CONST64(0x0000002000200000), CONST64(0x0000000000200020), CONST64(0x0000002000200020),
+  CONST64(0x0000200000200000), CONST64(0x0000202000200000), CONST64(0x0000200000200020), CONST64(0x0000202000200020),
+  CONST64(0x0000000000202000), CONST64(0x0000002000202000), CONST64(0x0000000000202020), CONST64(0x0000002000202020),
+  CONST64(0x0000200000202000), CONST64(0x0000202000202000), CONST64(0x0000200000202020), CONST64(0x0000202000202020),
+  CONST64(0x0020000000200000), CONST64(0x0020002000200000), CONST64(0x0020000000200020), CONST64(0x0020002000200020),
+  CONST64(0x0020200000200000), CONST64(0x0020202000200000), CONST64(0x0020200000200020), CONST64(0x0020202000200020),
+  CONST64(0x0020000000202000), CONST64(0x0020002000202000), CONST64(0x0020000000202020), CONST64(0x0020002000202020),
+  CONST64(0x0020200000202000), CONST64(0x0020202000202000), CONST64(0x0020200000202020), CONST64(0x0020202000202020),
+  CONST64(0x2000000000000000), CONST64(0x2000002000000000), CONST64(0x2000000000000020), CONST64(0x2000002000000020),
+  CONST64(0x2000200000000000), CONST64(0x2000202000000000), CONST64(0x2000200000000020), CONST64(0x2000202000000020),
+  CONST64(0x2000000000002000), CONST64(0x2000002000002000), CONST64(0x2000000000002020), CONST64(0x2000002000002020),
+  CONST64(0x2000200000002000), CONST64(0x2000202000002000), CONST64(0x2000200000002020), CONST64(0x2000202000002020),
+  CONST64(0x2020000000000000), CONST64(0x2020002000000000), CONST64(0x2020000000000020), CONST64(0x2020002000000020),
+  CONST64(0x2020200000000000), CONST64(0x2020202000000000), CONST64(0x2020200000000020), CONST64(0x2020202000000020),
+  CONST64(0x2020000000002000), CONST64(0x2020002000002000), CONST64(0x2020000000002020), CONST64(0x2020002000002020),
+  CONST64(0x2020200000002000), CONST64(0x2020202000002000), CONST64(0x2020200000002020), CONST64(0x2020202000002020),
+  CONST64(0x2000000000200000), CONST64(0x2000002000200000), CONST64(0x2000000000200020), CONST64(0x2000002000200020),
+  CONST64(0x2000200000200000), CONST64(0x2000202000200000), CONST64(0x2000200000200020), CONST64(0x2000202000200020),
+  CONST64(0x2000000000202000), CONST64(0x2000002000202000), CONST64(0x2000000000202020), CONST64(0x2000002000202020),
+  CONST64(0x2000200000202000), CONST64(0x2000202000202000), CONST64(0x2000200000202020), CONST64(0x2000202000202020),
+  CONST64(0x2020000000200000), CONST64(0x2020002000200000), CONST64(0x2020000000200020), CONST64(0x2020002000200020),
+  CONST64(0x2020200000200000), CONST64(0x2020202000200000), CONST64(0x2020200000200020), CONST64(0x2020202000200020),
+  CONST64(0x2020000000202000), CONST64(0x2020002000202000), CONST64(0x2020000000202020), CONST64(0x2020002000202020),
+  CONST64(0x2020200000202000), CONST64(0x2020202000202000), CONST64(0x2020200000202020), CONST64(0x2020202000202020),
+  CONST64(0x0000000020000000), CONST64(0x0000002020000000), CONST64(0x0000000020000020), CONST64(0x0000002020000020),
+  CONST64(0x0000200020000000), CONST64(0x0000202020000000), CONST64(0x0000200020000020), CONST64(0x0000202020000020),
+  CONST64(0x0000000020002000), CONST64(0x0000002020002000), CONST64(0x0000000020002020), CONST64(0x0000002020002020),
+  CONST64(0x0000200020002000), CONST64(0x0000202020002000), CONST64(0x0000200020002020), CONST64(0x0000202020002020),
+  CONST64(0x0020000020000000), CONST64(0x0020002020000000), CONST64(0x0020000020000020), CONST64(0x0020002020000020),
+  CONST64(0x0020200020000000), CONST64(0x0020202020000000), CONST64(0x0020200020000020), CONST64(0x0020202020000020),
+  CONST64(0x0020000020002000), CONST64(0x0020002020002000), CONST64(0x0020000020002020), CONST64(0x0020002020002020),
+  CONST64(0x0020200020002000), CONST64(0x0020202020002000), CONST64(0x0020200020002020), CONST64(0x0020202020002020),
+  CONST64(0x0000000020200000), CONST64(0x0000002020200000), CONST64(0x0000000020200020), CONST64(0x0000002020200020),
+  CONST64(0x0000200020200000), CONST64(0x0000202020200000), CONST64(0x0000200020200020), CONST64(0x0000202020200020),
+  CONST64(0x0000000020202000), CONST64(0x0000002020202000), CONST64(0x0000000020202020), CONST64(0x0000002020202020),
+  CONST64(0x0000200020202000), CONST64(0x0000202020202000), CONST64(0x0000200020202020), CONST64(0x0000202020202020),
+  CONST64(0x0020000020200000), CONST64(0x0020002020200000), CONST64(0x0020000020200020), CONST64(0x0020002020200020),
+  CONST64(0x0020200020200000), CONST64(0x0020202020200000), CONST64(0x0020200020200020), CONST64(0x0020202020200020),
+  CONST64(0x0020000020202000), CONST64(0x0020002020202000), CONST64(0x0020000020202020), CONST64(0x0020002020202020),
+  CONST64(0x0020200020202000), CONST64(0x0020202020202000), CONST64(0x0020200020202020), CONST64(0x0020202020202020),
+  CONST64(0x2000000020000000), CONST64(0x2000002020000000), CONST64(0x2000000020000020), CONST64(0x2000002020000020),
+  CONST64(0x2000200020000000), CONST64(0x2000202020000000), CONST64(0x2000200020000020), CONST64(0x2000202020000020),
+  CONST64(0x2000000020002000), CONST64(0x2000002020002000), CONST64(0x2000000020002020), CONST64(0x2000002020002020),
+  CONST64(0x2000200020002000), CONST64(0x2000202020002000), CONST64(0x2000200020002020), CONST64(0x2000202020002020),
+  CONST64(0x2020000020000000), CONST64(0x2020002020000000), CONST64(0x2020000020000020), CONST64(0x2020002020000020),
+  CONST64(0x2020200020000000), CONST64(0x2020202020000000), CONST64(0x2020200020000020), CONST64(0x2020202020000020),
+  CONST64(0x2020000020002000), CONST64(0x2020002020002000), CONST64(0x2020000020002020), CONST64(0x2020002020002020),
+  CONST64(0x2020200020002000), CONST64(0x2020202020002000), CONST64(0x2020200020002020), CONST64(0x2020202020002020),
+  CONST64(0x2000000020200000), CONST64(0x2000002020200000), CONST64(0x2000000020200020), CONST64(0x2000002020200020),
+  CONST64(0x2000200020200000), CONST64(0x2000202020200000), CONST64(0x2000200020200020), CONST64(0x2000202020200020),
+  CONST64(0x2000000020202000), CONST64(0x2000002020202000), CONST64(0x2000000020202020), CONST64(0x2000002020202020),
+  CONST64(0x2000200020202000), CONST64(0x2000202020202000), CONST64(0x2000200020202020), CONST64(0x2000202020202020),
+  CONST64(0x2020000020200000), CONST64(0x2020002020200000), CONST64(0x2020000020200020), CONST64(0x2020002020200020),
+  CONST64(0x2020200020200000), CONST64(0x2020202020200000), CONST64(0x2020200020200020), CONST64(0x2020202020200020),
+  CONST64(0x2020000020202000), CONST64(0x2020002020202000), CONST64(0x2020000020202020), CONST64(0x2020002020202020),
+  CONST64(0x2020200020202000), CONST64(0x2020202020202000), CONST64(0x2020200020202020), CONST64(0x2020202020202020)
+  }};
+
+static const ulong64 des_fp[8][256] = {
+
+{ CONST64(0x0000000000000000), CONST64(0x0000008000000000), CONST64(0x0000000002000000), CONST64(0x0000008002000000),
+  CONST64(0x0000000000020000), CONST64(0x0000008000020000), CONST64(0x0000000002020000), CONST64(0x0000008002020000),
+  CONST64(0x0000000000000200), CONST64(0x0000008000000200), CONST64(0x0000000002000200), CONST64(0x0000008002000200),
+  CONST64(0x0000000000020200), CONST64(0x0000008000020200), CONST64(0x0000000002020200), CONST64(0x0000008002020200),
+  CONST64(0x0000000000000002), CONST64(0x0000008000000002), CONST64(0x0000000002000002), CONST64(0x0000008002000002),
+  CONST64(0x0000000000020002), CONST64(0x0000008000020002), CONST64(0x0000000002020002), CONST64(0x0000008002020002),
+  CONST64(0x0000000000000202), CONST64(0x0000008000000202), CONST64(0x0000000002000202), CONST64(0x0000008002000202),
+  CONST64(0x0000000000020202), CONST64(0x0000008000020202), CONST64(0x0000000002020202), CONST64(0x0000008002020202),
+  CONST64(0x0200000000000000), CONST64(0x0200008000000000), CONST64(0x0200000002000000), CONST64(0x0200008002000000),
+  CONST64(0x0200000000020000), CONST64(0x0200008000020000), CONST64(0x0200000002020000), CONST64(0x0200008002020000),
+  CONST64(0x0200000000000200), CONST64(0x0200008000000200), CONST64(0x0200000002000200), CONST64(0x0200008002000200),
+  CONST64(0x0200000000020200), CONST64(0x0200008000020200), CONST64(0x0200000002020200), CONST64(0x0200008002020200),
+  CONST64(0x0200000000000002), CONST64(0x0200008000000002), CONST64(0x0200000002000002), CONST64(0x0200008002000002),
+  CONST64(0x0200000000020002), CONST64(0x0200008000020002), CONST64(0x0200000002020002), CONST64(0x0200008002020002),
+  CONST64(0x0200000000000202), CONST64(0x0200008000000202), CONST64(0x0200000002000202), CONST64(0x0200008002000202),
+  CONST64(0x0200000000020202), CONST64(0x0200008000020202), CONST64(0x0200000002020202), CONST64(0x0200008002020202),
+  CONST64(0x0002000000000000), CONST64(0x0002008000000000), CONST64(0x0002000002000000), CONST64(0x0002008002000000),
+  CONST64(0x0002000000020000), CONST64(0x0002008000020000), CONST64(0x0002000002020000), CONST64(0x0002008002020000),
+  CONST64(0x0002000000000200), CONST64(0x0002008000000200), CONST64(0x0002000002000200), CONST64(0x0002008002000200),
+  CONST64(0x0002000000020200), CONST64(0x0002008000020200), CONST64(0x0002000002020200), CONST64(0x0002008002020200),
+  CONST64(0x0002000000000002), CONST64(0x0002008000000002), CONST64(0x0002000002000002), CONST64(0x0002008002000002),
+  CONST64(0x0002000000020002), CONST64(0x0002008000020002), CONST64(0x0002000002020002), CONST64(0x0002008002020002),
+  CONST64(0x0002000000000202), CONST64(0x0002008000000202), CONST64(0x0002000002000202), CONST64(0x0002008002000202),
+  CONST64(0x0002000000020202), CONST64(0x0002008000020202), CONST64(0x0002000002020202), CONST64(0x0002008002020202),
+  CONST64(0x0202000000000000), CONST64(0x0202008000000000), CONST64(0x0202000002000000), CONST64(0x0202008002000000),
+  CONST64(0x0202000000020000), CONST64(0x0202008000020000), CONST64(0x0202000002020000), CONST64(0x0202008002020000),
+  CONST64(0x0202000000000200), CONST64(0x0202008000000200), CONST64(0x0202000002000200), CONST64(0x0202008002000200),
+  CONST64(0x0202000000020200), CONST64(0x0202008000020200), CONST64(0x0202000002020200), CONST64(0x0202008002020200),
+  CONST64(0x0202000000000002), CONST64(0x0202008000000002), CONST64(0x0202000002000002), CONST64(0x0202008002000002),
+  CONST64(0x0202000000020002), CONST64(0x0202008000020002), CONST64(0x0202000002020002), CONST64(0x0202008002020002),
+  CONST64(0x0202000000000202), CONST64(0x0202008000000202), CONST64(0x0202000002000202), CONST64(0x0202008002000202),
+  CONST64(0x0202000000020202), CONST64(0x0202008000020202), CONST64(0x0202000002020202), CONST64(0x0202008002020202),
+  CONST64(0x0000020000000000), CONST64(0x0000028000000000), CONST64(0x0000020002000000), CONST64(0x0000028002000000),
+  CONST64(0x0000020000020000), CONST64(0x0000028000020000), CONST64(0x0000020002020000), CONST64(0x0000028002020000),
+  CONST64(0x0000020000000200), CONST64(0x0000028000000200), CONST64(0x0000020002000200), CONST64(0x0000028002000200),
+  CONST64(0x0000020000020200), CONST64(0x0000028000020200), CONST64(0x0000020002020200), CONST64(0x0000028002020200),
+  CONST64(0x0000020000000002), CONST64(0x0000028000000002), CONST64(0x0000020002000002), CONST64(0x0000028002000002),
+  CONST64(0x0000020000020002), CONST64(0x0000028000020002), CONST64(0x0000020002020002), CONST64(0x0000028002020002),
+  CONST64(0x0000020000000202), CONST64(0x0000028000000202), CONST64(0x0000020002000202), CONST64(0x0000028002000202),
+  CONST64(0x0000020000020202), CONST64(0x0000028000020202), CONST64(0x0000020002020202), CONST64(0x0000028002020202),
+  CONST64(0x0200020000000000), CONST64(0x0200028000000000), CONST64(0x0200020002000000), CONST64(0x0200028002000000),
+  CONST64(0x0200020000020000), CONST64(0x0200028000020000), CONST64(0x0200020002020000), CONST64(0x0200028002020000),
+  CONST64(0x0200020000000200), CONST64(0x0200028000000200), CONST64(0x0200020002000200), CONST64(0x0200028002000200),
+  CONST64(0x0200020000020200), CONST64(0x0200028000020200), CONST64(0x0200020002020200), CONST64(0x0200028002020200),
+  CONST64(0x0200020000000002), CONST64(0x0200028000000002), CONST64(0x0200020002000002), CONST64(0x0200028002000002),
+  CONST64(0x0200020000020002), CONST64(0x0200028000020002), CONST64(0x0200020002020002), CONST64(0x0200028002020002),
+  CONST64(0x0200020000000202), CONST64(0x0200028000000202), CONST64(0x0200020002000202), CONST64(0x0200028002000202),
+  CONST64(0x0200020000020202), CONST64(0x0200028000020202), CONST64(0x0200020002020202), CONST64(0x0200028002020202),
+  CONST64(0x0002020000000000), CONST64(0x0002028000000000), CONST64(0x0002020002000000), CONST64(0x0002028002000000),
+  CONST64(0x0002020000020000), CONST64(0x0002028000020000), CONST64(0x0002020002020000), CONST64(0x0002028002020000),
+  CONST64(0x0002020000000200), CONST64(0x0002028000000200), CONST64(0x0002020002000200), CONST64(0x0002028002000200),
+  CONST64(0x0002020000020200), CONST64(0x0002028000020200), CONST64(0x0002020002020200), CONST64(0x0002028002020200),
+  CONST64(0x0002020000000002), CONST64(0x0002028000000002), CONST64(0x0002020002000002), CONST64(0x0002028002000002),
+  CONST64(0x0002020000020002), CONST64(0x0002028000020002), CONST64(0x0002020002020002), CONST64(0x0002028002020002),
+  CONST64(0x0002020000000202), CONST64(0x0002028000000202), CONST64(0x0002020002000202), CONST64(0x0002028002000202),
+  CONST64(0x0002020000020202), CONST64(0x0002028000020202), CONST64(0x0002020002020202), CONST64(0x0002028002020202),
+  CONST64(0x0202020000000000), CONST64(0x0202028000000000), CONST64(0x0202020002000000), CONST64(0x0202028002000000),
+  CONST64(0x0202020000020000), CONST64(0x0202028000020000), CONST64(0x0202020002020000), CONST64(0x0202028002020000),
+  CONST64(0x0202020000000200), CONST64(0x0202028000000200), CONST64(0x0202020002000200), CONST64(0x0202028002000200),
+  CONST64(0x0202020000020200), CONST64(0x0202028000020200), CONST64(0x0202020002020200), CONST64(0x0202028002020200),
+  CONST64(0x0202020000000002), CONST64(0x0202028000000002), CONST64(0x0202020002000002), CONST64(0x0202028002000002),
+  CONST64(0x0202020000020002), CONST64(0x0202028000020002), CONST64(0x0202020002020002), CONST64(0x0202028002020002),
+  CONST64(0x0202020000000202), CONST64(0x0202028000000202), CONST64(0x0202020002000202), CONST64(0x0202028002000202),
+  CONST64(0x0202020000020202), CONST64(0x0202028000020202), CONST64(0x0202020002020202), CONST64(0x0202028002020202)
+  },
+{ CONST64(0x0000000000000000), CONST64(0x0000000200000000), CONST64(0x0000000008000000), CONST64(0x0000000208000000),
+  CONST64(0x0000000000080000), CONST64(0x0000000200080000), CONST64(0x0000000008080000), CONST64(0x0000000208080000),
+  CONST64(0x0000000000000800), CONST64(0x0000000200000800), CONST64(0x0000000008000800), CONST64(0x0000000208000800),
+  CONST64(0x0000000000080800), CONST64(0x0000000200080800), CONST64(0x0000000008080800), CONST64(0x0000000208080800),
+  CONST64(0x0000000000000008), CONST64(0x0000000200000008), CONST64(0x0000000008000008), CONST64(0x0000000208000008),
+  CONST64(0x0000000000080008), CONST64(0x0000000200080008), CONST64(0x0000000008080008), CONST64(0x0000000208080008),
+  CONST64(0x0000000000000808), CONST64(0x0000000200000808), CONST64(0x0000000008000808), CONST64(0x0000000208000808),
+  CONST64(0x0000000000080808), CONST64(0x0000000200080808), CONST64(0x0000000008080808), CONST64(0x0000000208080808),
+  CONST64(0x0800000000000000), CONST64(0x0800000200000000), CONST64(0x0800000008000000), CONST64(0x0800000208000000),
+  CONST64(0x0800000000080000), CONST64(0x0800000200080000), CONST64(0x0800000008080000), CONST64(0x0800000208080000),
+  CONST64(0x0800000000000800), CONST64(0x0800000200000800), CONST64(0x0800000008000800), CONST64(0x0800000208000800),
+  CONST64(0x0800000000080800), CONST64(0x0800000200080800), CONST64(0x0800000008080800), CONST64(0x0800000208080800),
+  CONST64(0x0800000000000008), CONST64(0x0800000200000008), CONST64(0x0800000008000008), CONST64(0x0800000208000008),
+  CONST64(0x0800000000080008), CONST64(0x0800000200080008), CONST64(0x0800000008080008), CONST64(0x0800000208080008),
+  CONST64(0x0800000000000808), CONST64(0x0800000200000808), CONST64(0x0800000008000808), CONST64(0x0800000208000808),
+  CONST64(0x0800000000080808), CONST64(0x0800000200080808), CONST64(0x0800000008080808), CONST64(0x0800000208080808),
+  CONST64(0x0008000000000000), CONST64(0x0008000200000000), CONST64(0x0008000008000000), CONST64(0x0008000208000000),
+  CONST64(0x0008000000080000), CONST64(0x0008000200080000), CONST64(0x0008000008080000), CONST64(0x0008000208080000),
+  CONST64(0x0008000000000800), CONST64(0x0008000200000800), CONST64(0x0008000008000800), CONST64(0x0008000208000800),
+  CONST64(0x0008000000080800), CONST64(0x0008000200080800), CONST64(0x0008000008080800), CONST64(0x0008000208080800),
+  CONST64(0x0008000000000008), CONST64(0x0008000200000008), CONST64(0x0008000008000008), CONST64(0x0008000208000008),
+  CONST64(0x0008000000080008), CONST64(0x0008000200080008), CONST64(0x0008000008080008), CONST64(0x0008000208080008),
+  CONST64(0x0008000000000808), CONST64(0x0008000200000808), CONST64(0x0008000008000808), CONST64(0x0008000208000808),
+  CONST64(0x0008000000080808), CONST64(0x0008000200080808), CONST64(0x0008000008080808), CONST64(0x0008000208080808),
+  CONST64(0x0808000000000000), CONST64(0x0808000200000000), CONST64(0x0808000008000000), CONST64(0x0808000208000000),
+  CONST64(0x0808000000080000), CONST64(0x0808000200080000), CONST64(0x0808000008080000), CONST64(0x0808000208080000),
+  CONST64(0x0808000000000800), CONST64(0x0808000200000800), CONST64(0x0808000008000800), CONST64(0x0808000208000800),
+  CONST64(0x0808000000080800), CONST64(0x0808000200080800), CONST64(0x0808000008080800), CONST64(0x0808000208080800),
+  CONST64(0x0808000000000008), CONST64(0x0808000200000008), CONST64(0x0808000008000008), CONST64(0x0808000208000008),
+  CONST64(0x0808000000080008), CONST64(0x0808000200080008), CONST64(0x0808000008080008), CONST64(0x0808000208080008),
+  CONST64(0x0808000000000808), CONST64(0x0808000200000808), CONST64(0x0808000008000808), CONST64(0x0808000208000808),
+  CONST64(0x0808000000080808), CONST64(0x0808000200080808), CONST64(0x0808000008080808), CONST64(0x0808000208080808),
+  CONST64(0x0000080000000000), CONST64(0x0000080200000000), CONST64(0x0000080008000000), CONST64(0x0000080208000000),
+  CONST64(0x0000080000080000), CONST64(0x0000080200080000), CONST64(0x0000080008080000), CONST64(0x0000080208080000),
+  CONST64(0x0000080000000800), CONST64(0x0000080200000800), CONST64(0x0000080008000800), CONST64(0x0000080208000800),
+  CONST64(0x0000080000080800), CONST64(0x0000080200080800), CONST64(0x0000080008080800), CONST64(0x0000080208080800),
+  CONST64(0x0000080000000008), CONST64(0x0000080200000008), CONST64(0x0000080008000008), CONST64(0x0000080208000008),
+  CONST64(0x0000080000080008), CONST64(0x0000080200080008), CONST64(0x0000080008080008), CONST64(0x0000080208080008),
+  CONST64(0x0000080000000808), CONST64(0x0000080200000808), CONST64(0x0000080008000808), CONST64(0x0000080208000808),
+  CONST64(0x0000080000080808), CONST64(0x0000080200080808), CONST64(0x0000080008080808), CONST64(0x0000080208080808),
+  CONST64(0x0800080000000000), CONST64(0x0800080200000000), CONST64(0x0800080008000000), CONST64(0x0800080208000000),
+  CONST64(0x0800080000080000), CONST64(0x0800080200080000), CONST64(0x0800080008080000), CONST64(0x0800080208080000),
+  CONST64(0x0800080000000800), CONST64(0x0800080200000800), CONST64(0x0800080008000800), CONST64(0x0800080208000800),
+  CONST64(0x0800080000080800), CONST64(0x0800080200080800), CONST64(0x0800080008080800), CONST64(0x0800080208080800),
+  CONST64(0x0800080000000008), CONST64(0x0800080200000008), CONST64(0x0800080008000008), CONST64(0x0800080208000008),
+  CONST64(0x0800080000080008), CONST64(0x0800080200080008), CONST64(0x0800080008080008), CONST64(0x0800080208080008),
+  CONST64(0x0800080000000808), CONST64(0x0800080200000808), CONST64(0x0800080008000808), CONST64(0x0800080208000808),
+  CONST64(0x0800080000080808), CONST64(0x0800080200080808), CONST64(0x0800080008080808), CONST64(0x0800080208080808),
+  CONST64(0x0008080000000000), CONST64(0x0008080200000000), CONST64(0x0008080008000000), CONST64(0x0008080208000000),
+  CONST64(0x0008080000080000), CONST64(0x0008080200080000), CONST64(0x0008080008080000), CONST64(0x0008080208080000),
+  CONST64(0x0008080000000800), CONST64(0x0008080200000800), CONST64(0x0008080008000800), CONST64(0x0008080208000800),
+  CONST64(0x0008080000080800), CONST64(0x0008080200080800), CONST64(0x0008080008080800), CONST64(0x0008080208080800),
+  CONST64(0x0008080000000008), CONST64(0x0008080200000008), CONST64(0x0008080008000008), CONST64(0x0008080208000008),
+  CONST64(0x0008080000080008), CONST64(0x0008080200080008), CONST64(0x0008080008080008), CONST64(0x0008080208080008),
+  CONST64(0x0008080000000808), CONST64(0x0008080200000808), CONST64(0x0008080008000808), CONST64(0x0008080208000808),
+  CONST64(0x0008080000080808), CONST64(0x0008080200080808), CONST64(0x0008080008080808), CONST64(0x0008080208080808),
+  CONST64(0x0808080000000000), CONST64(0x0808080200000000), CONST64(0x0808080008000000), CONST64(0x0808080208000000),
+  CONST64(0x0808080000080000), CONST64(0x0808080200080000), CONST64(0x0808080008080000), CONST64(0x0808080208080000),
+  CONST64(0x0808080000000800), CONST64(0x0808080200000800), CONST64(0x0808080008000800), CONST64(0x0808080208000800),
+  CONST64(0x0808080000080800), CONST64(0x0808080200080800), CONST64(0x0808080008080800), CONST64(0x0808080208080800),
+  CONST64(0x0808080000000008), CONST64(0x0808080200000008), CONST64(0x0808080008000008), CONST64(0x0808080208000008),
+  CONST64(0x0808080000080008), CONST64(0x0808080200080008), CONST64(0x0808080008080008), CONST64(0x0808080208080008),
+  CONST64(0x0808080000000808), CONST64(0x0808080200000808), CONST64(0x0808080008000808), CONST64(0x0808080208000808),
+  CONST64(0x0808080000080808), CONST64(0x0808080200080808), CONST64(0x0808080008080808), CONST64(0x0808080208080808)
+  },
+{ CONST64(0x0000000000000000), CONST64(0x0000000800000000), CONST64(0x0000000020000000), CONST64(0x0000000820000000),
+  CONST64(0x0000000000200000), CONST64(0x0000000800200000), CONST64(0x0000000020200000), CONST64(0x0000000820200000),
+  CONST64(0x0000000000002000), CONST64(0x0000000800002000), CONST64(0x0000000020002000), CONST64(0x0000000820002000),
+  CONST64(0x0000000000202000), CONST64(0x0000000800202000), CONST64(0x0000000020202000), CONST64(0x0000000820202000),
+  CONST64(0x0000000000000020), CONST64(0x0000000800000020), CONST64(0x0000000020000020), CONST64(0x0000000820000020),
+  CONST64(0x0000000000200020), CONST64(0x0000000800200020), CONST64(0x0000000020200020), CONST64(0x0000000820200020),
+  CONST64(0x0000000000002020), CONST64(0x0000000800002020), CONST64(0x0000000020002020), CONST64(0x0000000820002020),
+  CONST64(0x0000000000202020), CONST64(0x0000000800202020), CONST64(0x0000000020202020), CONST64(0x0000000820202020),
+  CONST64(0x2000000000000000), CONST64(0x2000000800000000), CONST64(0x2000000020000000), CONST64(0x2000000820000000),
+  CONST64(0x2000000000200000), CONST64(0x2000000800200000), CONST64(0x2000000020200000), CONST64(0x2000000820200000),
+  CONST64(0x2000000000002000), CONST64(0x2000000800002000), CONST64(0x2000000020002000), CONST64(0x2000000820002000),
+  CONST64(0x2000000000202000), CONST64(0x2000000800202000), CONST64(0x2000000020202000), CONST64(0x2000000820202000),
+  CONST64(0x2000000000000020), CONST64(0x2000000800000020), CONST64(0x2000000020000020), CONST64(0x2000000820000020),
+  CONST64(0x2000000000200020), CONST64(0x2000000800200020), CONST64(0x2000000020200020), CONST64(0x2000000820200020),
+  CONST64(0x2000000000002020), CONST64(0x2000000800002020), CONST64(0x2000000020002020), CONST64(0x2000000820002020),
+  CONST64(0x2000000000202020), CONST64(0x2000000800202020), CONST64(0x2000000020202020), CONST64(0x2000000820202020),
+  CONST64(0x0020000000000000), CONST64(0x0020000800000000), CONST64(0x0020000020000000), CONST64(0x0020000820000000),
+  CONST64(0x0020000000200000), CONST64(0x0020000800200000), CONST64(0x0020000020200000), CONST64(0x0020000820200000),
+  CONST64(0x0020000000002000), CONST64(0x0020000800002000), CONST64(0x0020000020002000), CONST64(0x0020000820002000),
+  CONST64(0x0020000000202000), CONST64(0x0020000800202000), CONST64(0x0020000020202000), CONST64(0x0020000820202000),
+  CONST64(0x0020000000000020), CONST64(0x0020000800000020), CONST64(0x0020000020000020), CONST64(0x0020000820000020),
+  CONST64(0x0020000000200020), CONST64(0x0020000800200020), CONST64(0x0020000020200020), CONST64(0x0020000820200020),
+  CONST64(0x0020000000002020), CONST64(0x0020000800002020), CONST64(0x0020000020002020), CONST64(0x0020000820002020),
+  CONST64(0x0020000000202020), CONST64(0x0020000800202020), CONST64(0x0020000020202020), CONST64(0x0020000820202020),
+  CONST64(0x2020000000000000), CONST64(0x2020000800000000), CONST64(0x2020000020000000), CONST64(0x2020000820000000),
+  CONST64(0x2020000000200000), CONST64(0x2020000800200000), CONST64(0x2020000020200000), CONST64(0x2020000820200000),
+  CONST64(0x2020000000002000), CONST64(0x2020000800002000), CONST64(0x2020000020002000), CONST64(0x2020000820002000),
+  CONST64(0x2020000000202000), CONST64(0x2020000800202000), CONST64(0x2020000020202000), CONST64(0x2020000820202000),
+  CONST64(0x2020000000000020), CONST64(0x2020000800000020), CONST64(0x2020000020000020), CONST64(0x2020000820000020),
+  CONST64(0x2020000000200020), CONST64(0x2020000800200020), CONST64(0x2020000020200020), CONST64(0x2020000820200020),
+  CONST64(0x2020000000002020), CONST64(0x2020000800002020), CONST64(0x2020000020002020), CONST64(0x2020000820002020),
+  CONST64(0x2020000000202020), CONST64(0x2020000800202020), CONST64(0x2020000020202020), CONST64(0x2020000820202020),
+  CONST64(0x0000200000000000), CONST64(0x0000200800000000), CONST64(0x0000200020000000), CONST64(0x0000200820000000),
+  CONST64(0x0000200000200000), CONST64(0x0000200800200000), CONST64(0x0000200020200000), CONST64(0x0000200820200000),
+  CONST64(0x0000200000002000), CONST64(0x0000200800002000), CONST64(0x0000200020002000), CONST64(0x0000200820002000),
+  CONST64(0x0000200000202000), CONST64(0x0000200800202000), CONST64(0x0000200020202000), CONST64(0x0000200820202000),
+  CONST64(0x0000200000000020), CONST64(0x0000200800000020), CONST64(0x0000200020000020), CONST64(0x0000200820000020),
+  CONST64(0x0000200000200020), CONST64(0x0000200800200020), CONST64(0x0000200020200020), CONST64(0x0000200820200020),
+  CONST64(0x0000200000002020), CONST64(0x0000200800002020), CONST64(0x0000200020002020), CONST64(0x0000200820002020),
+  CONST64(0x0000200000202020), CONST64(0x0000200800202020), CONST64(0x0000200020202020), CONST64(0x0000200820202020),
+  CONST64(0x2000200000000000), CONST64(0x2000200800000000), CONST64(0x2000200020000000), CONST64(0x2000200820000000),
+  CONST64(0x2000200000200000), CONST64(0x2000200800200000), CONST64(0x2000200020200000), CONST64(0x2000200820200000),
+  CONST64(0x2000200000002000), CONST64(0x2000200800002000), CONST64(0x2000200020002000), CONST64(0x2000200820002000),
+  CONST64(0x2000200000202000), CONST64(0x2000200800202000), CONST64(0x2000200020202000), CONST64(0x2000200820202000),
+  CONST64(0x2000200000000020), CONST64(0x2000200800000020), CONST64(0x2000200020000020), CONST64(0x2000200820000020),
+  CONST64(0x2000200000200020), CONST64(0x2000200800200020), CONST64(0x2000200020200020), CONST64(0x2000200820200020),
+  CONST64(0x2000200000002020), CONST64(0x2000200800002020), CONST64(0x2000200020002020), CONST64(0x2000200820002020),
+  CONST64(0x2000200000202020), CONST64(0x2000200800202020), CONST64(0x2000200020202020), CONST64(0x2000200820202020),
+  CONST64(0x0020200000000000), CONST64(0x0020200800000000), CONST64(0x0020200020000000), CONST64(0x0020200820000000),
+  CONST64(0x0020200000200000), CONST64(0x0020200800200000), CONST64(0x0020200020200000), CONST64(0x0020200820200000),
+  CONST64(0x0020200000002000), CONST64(0x0020200800002000), CONST64(0x0020200020002000), CONST64(0x0020200820002000),
+  CONST64(0x0020200000202000), CONST64(0x0020200800202000), CONST64(0x0020200020202000), CONST64(0x0020200820202000),
+  CONST64(0x0020200000000020), CONST64(0x0020200800000020), CONST64(0x0020200020000020), CONST64(0x0020200820000020),
+  CONST64(0x0020200000200020), CONST64(0x0020200800200020), CONST64(0x0020200020200020), CONST64(0x0020200820200020),
+  CONST64(0x0020200000002020), CONST64(0x0020200800002020), CONST64(0x0020200020002020), CONST64(0x0020200820002020),
+  CONST64(0x0020200000202020), CONST64(0x0020200800202020), CONST64(0x0020200020202020), CONST64(0x0020200820202020),
+  CONST64(0x2020200000000000), CONST64(0x2020200800000000), CONST64(0x2020200020000000), CONST64(0x2020200820000000),
+  CONST64(0x2020200000200000), CONST64(0x2020200800200000), CONST64(0x2020200020200000), CONST64(0x2020200820200000),
+  CONST64(0x2020200000002000), CONST64(0x2020200800002000), CONST64(0x2020200020002000), CONST64(0x2020200820002000),
+  CONST64(0x2020200000202000), CONST64(0x2020200800202000), CONST64(0x2020200020202000), CONST64(0x2020200820202000),
+  CONST64(0x2020200000000020), CONST64(0x2020200800000020), CONST64(0x2020200020000020), CONST64(0x2020200820000020),
+  CONST64(0x2020200000200020), CONST64(0x2020200800200020), CONST64(0x2020200020200020), CONST64(0x2020200820200020),
+  CONST64(0x2020200000002020), CONST64(0x2020200800002020), CONST64(0x2020200020002020), CONST64(0x2020200820002020),
+  CONST64(0x2020200000202020), CONST64(0x2020200800202020), CONST64(0x2020200020202020), CONST64(0x2020200820202020)
+  },
+{ CONST64(0x0000000000000000), CONST64(0x0000002000000000), CONST64(0x0000000080000000), CONST64(0x0000002080000000),
+  CONST64(0x0000000000800000), CONST64(0x0000002000800000), CONST64(0x0000000080800000), CONST64(0x0000002080800000),
+  CONST64(0x0000000000008000), CONST64(0x0000002000008000), CONST64(0x0000000080008000), CONST64(0x0000002080008000),
+  CONST64(0x0000000000808000), CONST64(0x0000002000808000), CONST64(0x0000000080808000), CONST64(0x0000002080808000),
+  CONST64(0x0000000000000080), CONST64(0x0000002000000080), CONST64(0x0000000080000080), CONST64(0x0000002080000080),
+  CONST64(0x0000000000800080), CONST64(0x0000002000800080), CONST64(0x0000000080800080), CONST64(0x0000002080800080),
+  CONST64(0x0000000000008080), CONST64(0x0000002000008080), CONST64(0x0000000080008080), CONST64(0x0000002080008080),
+  CONST64(0x0000000000808080), CONST64(0x0000002000808080), CONST64(0x0000000080808080), CONST64(0x0000002080808080),
+  CONST64(0x8000000000000000), CONST64(0x8000002000000000), CONST64(0x8000000080000000), CONST64(0x8000002080000000),
+  CONST64(0x8000000000800000), CONST64(0x8000002000800000), CONST64(0x8000000080800000), CONST64(0x8000002080800000),
+  CONST64(0x8000000000008000), CONST64(0x8000002000008000), CONST64(0x8000000080008000), CONST64(0x8000002080008000),
+  CONST64(0x8000000000808000), CONST64(0x8000002000808000), CONST64(0x8000000080808000), CONST64(0x8000002080808000),
+  CONST64(0x8000000000000080), CONST64(0x8000002000000080), CONST64(0x8000000080000080), CONST64(0x8000002080000080),
+  CONST64(0x8000000000800080), CONST64(0x8000002000800080), CONST64(0x8000000080800080), CONST64(0x8000002080800080),
+  CONST64(0x8000000000008080), CONST64(0x8000002000008080), CONST64(0x8000000080008080), CONST64(0x8000002080008080),
+  CONST64(0x8000000000808080), CONST64(0x8000002000808080), CONST64(0x8000000080808080), CONST64(0x8000002080808080),
+  CONST64(0x0080000000000000), CONST64(0x0080002000000000), CONST64(0x0080000080000000), CONST64(0x0080002080000000),
+  CONST64(0x0080000000800000), CONST64(0x0080002000800000), CONST64(0x0080000080800000), CONST64(0x0080002080800000),
+  CONST64(0x0080000000008000), CONST64(0x0080002000008000), CONST64(0x0080000080008000), CONST64(0x0080002080008000),
+  CONST64(0x0080000000808000), CONST64(0x0080002000808000), CONST64(0x0080000080808000), CONST64(0x0080002080808000),
+  CONST64(0x0080000000000080), CONST64(0x0080002000000080), CONST64(0x0080000080000080), CONST64(0x0080002080000080),
+  CONST64(0x0080000000800080), CONST64(0x0080002000800080), CONST64(0x0080000080800080), CONST64(0x0080002080800080),
+  CONST64(0x0080000000008080), CONST64(0x0080002000008080), CONST64(0x0080000080008080), CONST64(0x0080002080008080),
+  CONST64(0x0080000000808080), CONST64(0x0080002000808080), CONST64(0x0080000080808080), CONST64(0x0080002080808080),
+  CONST64(0x8080000000000000), CONST64(0x8080002000000000), CONST64(0x8080000080000000), CONST64(0x8080002080000000),
+  CONST64(0x8080000000800000), CONST64(0x8080002000800000), CONST64(0x8080000080800000), CONST64(0x8080002080800000),
+  CONST64(0x8080000000008000), CONST64(0x8080002000008000), CONST64(0x8080000080008000), CONST64(0x8080002080008000),
+  CONST64(0x8080000000808000), CONST64(0x8080002000808000), CONST64(0x8080000080808000), CONST64(0x8080002080808000),
+  CONST64(0x8080000000000080), CONST64(0x8080002000000080), CONST64(0x8080000080000080), CONST64(0x8080002080000080),
+  CONST64(0x8080000000800080), CONST64(0x8080002000800080), CONST64(0x8080000080800080), CONST64(0x8080002080800080),
+  CONST64(0x8080000000008080), CONST64(0x8080002000008080), CONST64(0x8080000080008080), CONST64(0x8080002080008080),
+  CONST64(0x8080000000808080), CONST64(0x8080002000808080), CONST64(0x8080000080808080), CONST64(0x8080002080808080),
+  CONST64(0x0000800000000000), CONST64(0x0000802000000000), CONST64(0x0000800080000000), CONST64(0x0000802080000000),
+  CONST64(0x0000800000800000), CONST64(0x0000802000800000), CONST64(0x0000800080800000), CONST64(0x0000802080800000),
+  CONST64(0x0000800000008000), CONST64(0x0000802000008000), CONST64(0x0000800080008000), CONST64(0x0000802080008000),
+  CONST64(0x0000800000808000), CONST64(0x0000802000808000), CONST64(0x0000800080808000), CONST64(0x0000802080808000),
+  CONST64(0x0000800000000080), CONST64(0x0000802000000080), CONST64(0x0000800080000080), CONST64(0x0000802080000080),
+  CONST64(0x0000800000800080), CONST64(0x0000802000800080), CONST64(0x0000800080800080), CONST64(0x0000802080800080),
+  CONST64(0x0000800000008080), CONST64(0x0000802000008080), CONST64(0x0000800080008080), CONST64(0x0000802080008080),
+  CONST64(0x0000800000808080), CONST64(0x0000802000808080), CONST64(0x0000800080808080), CONST64(0x0000802080808080),
+  CONST64(0x8000800000000000), CONST64(0x8000802000000000), CONST64(0x8000800080000000), CONST64(0x8000802080000000),
+  CONST64(0x8000800000800000), CONST64(0x8000802000800000), CONST64(0x8000800080800000), CONST64(0x8000802080800000),
+  CONST64(0x8000800000008000), CONST64(0x8000802000008000), CONST64(0x8000800080008000), CONST64(0x8000802080008000),
+  CONST64(0x8000800000808000), CONST64(0x8000802000808000), CONST64(0x8000800080808000), CONST64(0x8000802080808000),
+  CONST64(0x8000800000000080), CONST64(0x8000802000000080), CONST64(0x8000800080000080), CONST64(0x8000802080000080),
+  CONST64(0x8000800000800080), CONST64(0x8000802000800080), CONST64(0x8000800080800080), CONST64(0x8000802080800080),
+  CONST64(0x8000800000008080), CONST64(0x8000802000008080), CONST64(0x8000800080008080), CONST64(0x8000802080008080),
+  CONST64(0x8000800000808080), CONST64(0x8000802000808080), CONST64(0x8000800080808080), CONST64(0x8000802080808080),
+  CONST64(0x0080800000000000), CONST64(0x0080802000000000), CONST64(0x0080800080000000), CONST64(0x0080802080000000),
+  CONST64(0x0080800000800000), CONST64(0x0080802000800000), CONST64(0x0080800080800000), CONST64(0x0080802080800000),
+  CONST64(0x0080800000008000), CONST64(0x0080802000008000), CONST64(0x0080800080008000), CONST64(0x0080802080008000),
+  CONST64(0x0080800000808000), CONST64(0x0080802000808000), CONST64(0x0080800080808000), CONST64(0x0080802080808000),
+  CONST64(0x0080800000000080), CONST64(0x0080802000000080), CONST64(0x0080800080000080), CONST64(0x0080802080000080),
+  CONST64(0x0080800000800080), CONST64(0x0080802000800080), CONST64(0x0080800080800080), CONST64(0x0080802080800080),
+  CONST64(0x0080800000008080), CONST64(0x0080802000008080), CONST64(0x0080800080008080), CONST64(0x0080802080008080),
+  CONST64(0x0080800000808080), CONST64(0x0080802000808080), CONST64(0x0080800080808080), CONST64(0x0080802080808080),
+  CONST64(0x8080800000000000), CONST64(0x8080802000000000), CONST64(0x8080800080000000), CONST64(0x8080802080000000),
+  CONST64(0x8080800000800000), CONST64(0x8080802000800000), CONST64(0x8080800080800000), CONST64(0x8080802080800000),
+  CONST64(0x8080800000008000), CONST64(0x8080802000008000), CONST64(0x8080800080008000), CONST64(0x8080802080008000),
+  CONST64(0x8080800000808000), CONST64(0x8080802000808000), CONST64(0x8080800080808000), CONST64(0x8080802080808000),
+  CONST64(0x8080800000000080), CONST64(0x8080802000000080), CONST64(0x8080800080000080), CONST64(0x8080802080000080),
+  CONST64(0x8080800000800080), CONST64(0x8080802000800080), CONST64(0x8080800080800080), CONST64(0x8080802080800080),
+  CONST64(0x8080800000008080), CONST64(0x8080802000008080), CONST64(0x8080800080008080), CONST64(0x8080802080008080),
+  CONST64(0x8080800000808080), CONST64(0x8080802000808080), CONST64(0x8080800080808080), CONST64(0x8080802080808080)
+  },
+{ CONST64(0x0000000000000000), CONST64(0x0000004000000000), CONST64(0x0000000001000000), CONST64(0x0000004001000000),
+  CONST64(0x0000000000010000), CONST64(0x0000004000010000), CONST64(0x0000000001010000), CONST64(0x0000004001010000),
+  CONST64(0x0000000000000100), CONST64(0x0000004000000100), CONST64(0x0000000001000100), CONST64(0x0000004001000100),
+  CONST64(0x0000000000010100), CONST64(0x0000004000010100), CONST64(0x0000000001010100), CONST64(0x0000004001010100),
+  CONST64(0x0000000000000001), CONST64(0x0000004000000001), CONST64(0x0000000001000001), CONST64(0x0000004001000001),
+  CONST64(0x0000000000010001), CONST64(0x0000004000010001), CONST64(0x0000000001010001), CONST64(0x0000004001010001),
+  CONST64(0x0000000000000101), CONST64(0x0000004000000101), CONST64(0x0000000001000101), CONST64(0x0000004001000101),
+  CONST64(0x0000000000010101), CONST64(0x0000004000010101), CONST64(0x0000000001010101), CONST64(0x0000004001010101),
+  CONST64(0x0100000000000000), CONST64(0x0100004000000000), CONST64(0x0100000001000000), CONST64(0x0100004001000000),
+  CONST64(0x0100000000010000), CONST64(0x0100004000010000), CONST64(0x0100000001010000), CONST64(0x0100004001010000),
+  CONST64(0x0100000000000100), CONST64(0x0100004000000100), CONST64(0x0100000001000100), CONST64(0x0100004001000100),
+  CONST64(0x0100000000010100), CONST64(0x0100004000010100), CONST64(0x0100000001010100), CONST64(0x0100004001010100),
+  CONST64(0x0100000000000001), CONST64(0x0100004000000001), CONST64(0x0100000001000001), CONST64(0x0100004001000001),
+  CONST64(0x0100000000010001), CONST64(0x0100004000010001), CONST64(0x0100000001010001), CONST64(0x0100004001010001),
+  CONST64(0x0100000000000101), CONST64(0x0100004000000101), CONST64(0x0100000001000101), CONST64(0x0100004001000101),
+  CONST64(0x0100000000010101), CONST64(0x0100004000010101), CONST64(0x0100000001010101), CONST64(0x0100004001010101),
+  CONST64(0x0001000000000000), CONST64(0x0001004000000000), CONST64(0x0001000001000000), CONST64(0x0001004001000000),
+  CONST64(0x0001000000010000), CONST64(0x0001004000010000), CONST64(0x0001000001010000), CONST64(0x0001004001010000),
+  CONST64(0x0001000000000100), CONST64(0x0001004000000100), CONST64(0x0001000001000100), CONST64(0x0001004001000100),
+  CONST64(0x0001000000010100), CONST64(0x0001004000010100), CONST64(0x0001000001010100), CONST64(0x0001004001010100),
+  CONST64(0x0001000000000001), CONST64(0x0001004000000001), CONST64(0x0001000001000001), CONST64(0x0001004001000001),
+  CONST64(0x0001000000010001), CONST64(0x0001004000010001), CONST64(0x0001000001010001), CONST64(0x0001004001010001),
+  CONST64(0x0001000000000101), CONST64(0x0001004000000101), CONST64(0x0001000001000101), CONST64(0x0001004001000101),
+  CONST64(0x0001000000010101), CONST64(0x0001004000010101), CONST64(0x0001000001010101), CONST64(0x0001004001010101),
+  CONST64(0x0101000000000000), CONST64(0x0101004000000000), CONST64(0x0101000001000000), CONST64(0x0101004001000000),
+  CONST64(0x0101000000010000), CONST64(0x0101004000010000), CONST64(0x0101000001010000), CONST64(0x0101004001010000),
+  CONST64(0x0101000000000100), CONST64(0x0101004000000100), CONST64(0x0101000001000100), CONST64(0x0101004001000100),
+  CONST64(0x0101000000010100), CONST64(0x0101004000010100), CONST64(0x0101000001010100), CONST64(0x0101004001010100),
+  CONST64(0x0101000000000001), CONST64(0x0101004000000001), CONST64(0x0101000001000001), CONST64(0x0101004001000001),
+  CONST64(0x0101000000010001), CONST64(0x0101004000010001), CONST64(0x0101000001010001), CONST64(0x0101004001010001),
+  CONST64(0x0101000000000101), CONST64(0x0101004000000101), CONST64(0x0101000001000101), CONST64(0x0101004001000101),
+  CONST64(0x0101000000010101), CONST64(0x0101004000010101), CONST64(0x0101000001010101), CONST64(0x0101004001010101),
+  CONST64(0x0000010000000000), CONST64(0x0000014000000000), CONST64(0x0000010001000000), CONST64(0x0000014001000000),
+  CONST64(0x0000010000010000), CONST64(0x0000014000010000), CONST64(0x0000010001010000), CONST64(0x0000014001010000),
+  CONST64(0x0000010000000100), CONST64(0x0000014000000100), CONST64(0x0000010001000100), CONST64(0x0000014001000100),
+  CONST64(0x0000010000010100), CONST64(0x0000014000010100), CONST64(0x0000010001010100), CONST64(0x0000014001010100),
+  CONST64(0x0000010000000001), CONST64(0x0000014000000001), CONST64(0x0000010001000001), CONST64(0x0000014001000001),
+  CONST64(0x0000010000010001), CONST64(0x0000014000010001), CONST64(0x0000010001010001), CONST64(0x0000014001010001),
+  CONST64(0x0000010000000101), CONST64(0x0000014000000101), CONST64(0x0000010001000101), CONST64(0x0000014001000101),
+  CONST64(0x0000010000010101), CONST64(0x0000014000010101), CONST64(0x0000010001010101), CONST64(0x0000014001010101),
+  CONST64(0x0100010000000000), CONST64(0x0100014000000000), CONST64(0x0100010001000000), CONST64(0x0100014001000000),
+  CONST64(0x0100010000010000), CONST64(0x0100014000010000), CONST64(0x0100010001010000), CONST64(0x0100014001010000),
+  CONST64(0x0100010000000100), CONST64(0x0100014000000100), CONST64(0x0100010001000100), CONST64(0x0100014001000100),
+  CONST64(0x0100010000010100), CONST64(0x0100014000010100), CONST64(0x0100010001010100), CONST64(0x0100014001010100),
+  CONST64(0x0100010000000001), CONST64(0x0100014000000001), CONST64(0x0100010001000001), CONST64(0x0100014001000001),
+  CONST64(0x0100010000010001), CONST64(0x0100014000010001), CONST64(0x0100010001010001), CONST64(0x0100014001010001),
+  CONST64(0x0100010000000101), CONST64(0x0100014000000101), CONST64(0x0100010001000101), CONST64(0x0100014001000101),
+  CONST64(0x0100010000010101), CONST64(0x0100014000010101), CONST64(0x0100010001010101), CONST64(0x0100014001010101),
+  CONST64(0x0001010000000000), CONST64(0x0001014000000000), CONST64(0x0001010001000000), CONST64(0x0001014001000000),
+  CONST64(0x0001010000010000), CONST64(0x0001014000010000), CONST64(0x0001010001010000), CONST64(0x0001014001010000),
+  CONST64(0x0001010000000100), CONST64(0x0001014000000100), CONST64(0x0001010001000100), CONST64(0x0001014001000100),
+  CONST64(0x0001010000010100), CONST64(0x0001014000010100), CONST64(0x0001010001010100), CONST64(0x0001014001010100),
+  CONST64(0x0001010000000001), CONST64(0x0001014000000001), CONST64(0x0001010001000001), CONST64(0x0001014001000001),
+  CONST64(0x0001010000010001), CONST64(0x0001014000010001), CONST64(0x0001010001010001), CONST64(0x0001014001010001),
+  CONST64(0x0001010000000101), CONST64(0x0001014000000101), CONST64(0x0001010001000101), CONST64(0x0001014001000101),
+  CONST64(0x0001010000010101), CONST64(0x0001014000010101), CONST64(0x0001010001010101), CONST64(0x0001014001010101),
+  CONST64(0x0101010000000000), CONST64(0x0101014000000000), CONST64(0x0101010001000000), CONST64(0x0101014001000000),
+  CONST64(0x0101010000010000), CONST64(0x0101014000010000), CONST64(0x0101010001010000), CONST64(0x0101014001010000),
+  CONST64(0x0101010000000100), CONST64(0x0101014000000100), CONST64(0x0101010001000100), CONST64(0x0101014001000100),
+  CONST64(0x0101010000010100), CONST64(0x0101014000010100), CONST64(0x0101010001010100), CONST64(0x0101014001010100),
+  CONST64(0x0101010000000001), CONST64(0x0101014000000001), CONST64(0x0101010001000001), CONST64(0x0101014001000001),
+  CONST64(0x0101010000010001), CONST64(0x0101014000010001), CONST64(0x0101010001010001), CONST64(0x0101014001010001),
+  CONST64(0x0101010000000101), CONST64(0x0101014000000101), CONST64(0x0101010001000101), CONST64(0x0101014001000101),
+  CONST64(0x0101010000010101), CONST64(0x0101014000010101), CONST64(0x0101010001010101), CONST64(0x0101014001010101)
+  },
+{ CONST64(0x0000000000000000), CONST64(0x0000000100000000), CONST64(0x0000000004000000), CONST64(0x0000000104000000),
+  CONST64(0x0000000000040000), CONST64(0x0000000100040000), CONST64(0x0000000004040000), CONST64(0x0000000104040000),
+  CONST64(0x0000000000000400), CONST64(0x0000000100000400), CONST64(0x0000000004000400), CONST64(0x0000000104000400),
+  CONST64(0x0000000000040400), CONST64(0x0000000100040400), CONST64(0x0000000004040400), CONST64(0x0000000104040400),
+  CONST64(0x0000000000000004), CONST64(0x0000000100000004), CONST64(0x0000000004000004), CONST64(0x0000000104000004),
+  CONST64(0x0000000000040004), CONST64(0x0000000100040004), CONST64(0x0000000004040004), CONST64(0x0000000104040004),
+  CONST64(0x0000000000000404), CONST64(0x0000000100000404), CONST64(0x0000000004000404), CONST64(0x0000000104000404),
+  CONST64(0x0000000000040404), CONST64(0x0000000100040404), CONST64(0x0000000004040404), CONST64(0x0000000104040404),
+  CONST64(0x0400000000000000), CONST64(0x0400000100000000), CONST64(0x0400000004000000), CONST64(0x0400000104000000),
+  CONST64(0x0400000000040000), CONST64(0x0400000100040000), CONST64(0x0400000004040000), CONST64(0x0400000104040000),
+  CONST64(0x0400000000000400), CONST64(0x0400000100000400), CONST64(0x0400000004000400), CONST64(0x0400000104000400),
+  CONST64(0x0400000000040400), CONST64(0x0400000100040400), CONST64(0x0400000004040400), CONST64(0x0400000104040400),
+  CONST64(0x0400000000000004), CONST64(0x0400000100000004), CONST64(0x0400000004000004), CONST64(0x0400000104000004),
+  CONST64(0x0400000000040004), CONST64(0x0400000100040004), CONST64(0x0400000004040004), CONST64(0x0400000104040004),
+  CONST64(0x0400000000000404), CONST64(0x0400000100000404), CONST64(0x0400000004000404), CONST64(0x0400000104000404),
+  CONST64(0x0400000000040404), CONST64(0x0400000100040404), CONST64(0x0400000004040404), CONST64(0x0400000104040404),
+  CONST64(0x0004000000000000), CONST64(0x0004000100000000), CONST64(0x0004000004000000), CONST64(0x0004000104000000),
+  CONST64(0x0004000000040000), CONST64(0x0004000100040000), CONST64(0x0004000004040000), CONST64(0x0004000104040000),
+  CONST64(0x0004000000000400), CONST64(0x0004000100000400), CONST64(0x0004000004000400), CONST64(0x0004000104000400),
+  CONST64(0x0004000000040400), CONST64(0x0004000100040400), CONST64(0x0004000004040400), CONST64(0x0004000104040400),
+  CONST64(0x0004000000000004), CONST64(0x0004000100000004), CONST64(0x0004000004000004), CONST64(0x0004000104000004),
+  CONST64(0x0004000000040004), CONST64(0x0004000100040004), CONST64(0x0004000004040004), CONST64(0x0004000104040004),
+  CONST64(0x0004000000000404), CONST64(0x0004000100000404), CONST64(0x0004000004000404), CONST64(0x0004000104000404),
+  CONST64(0x0004000000040404), CONST64(0x0004000100040404), CONST64(0x0004000004040404), CONST64(0x0004000104040404),
+  CONST64(0x0404000000000000), CONST64(0x0404000100000000), CONST64(0x0404000004000000), CONST64(0x0404000104000000),
+  CONST64(0x0404000000040000), CONST64(0x0404000100040000), CONST64(0x0404000004040000), CONST64(0x0404000104040000),
+  CONST64(0x0404000000000400), CONST64(0x0404000100000400), CONST64(0x0404000004000400), CONST64(0x0404000104000400),
+  CONST64(0x0404000000040400), CONST64(0x0404000100040400), CONST64(0x0404000004040400), CONST64(0x0404000104040400),
+  CONST64(0x0404000000000004), CONST64(0x0404000100000004), CONST64(0x0404000004000004), CONST64(0x0404000104000004),
+  CONST64(0x0404000000040004), CONST64(0x0404000100040004), CONST64(0x0404000004040004), CONST64(0x0404000104040004),
+  CONST64(0x0404000000000404), CONST64(0x0404000100000404), CONST64(0x0404000004000404), CONST64(0x0404000104000404),
+  CONST64(0x0404000000040404), CONST64(0x0404000100040404), CONST64(0x0404000004040404), CONST64(0x0404000104040404),
+  CONST64(0x0000040000000000), CONST64(0x0000040100000000), CONST64(0x0000040004000000), CONST64(0x0000040104000000),
+  CONST64(0x0000040000040000), CONST64(0x0000040100040000), CONST64(0x0000040004040000), CONST64(0x0000040104040000),
+  CONST64(0x0000040000000400), CONST64(0x0000040100000400), CONST64(0x0000040004000400), CONST64(0x0000040104000400),
+  CONST64(0x0000040000040400), CONST64(0x0000040100040400), CONST64(0x0000040004040400), CONST64(0x0000040104040400),
+  CONST64(0x0000040000000004), CONST64(0x0000040100000004), CONST64(0x0000040004000004), CONST64(0x0000040104000004),
+  CONST64(0x0000040000040004), CONST64(0x0000040100040004), CONST64(0x0000040004040004), CONST64(0x0000040104040004),
+  CONST64(0x0000040000000404), CONST64(0x0000040100000404), CONST64(0x0000040004000404), CONST64(0x0000040104000404),
+  CONST64(0x0000040000040404), CONST64(0x0000040100040404), CONST64(0x0000040004040404), CONST64(0x0000040104040404),
+  CONST64(0x0400040000000000), CONST64(0x0400040100000000), CONST64(0x0400040004000000), CONST64(0x0400040104000000),
+  CONST64(0x0400040000040000), CONST64(0x0400040100040000), CONST64(0x0400040004040000), CONST64(0x0400040104040000),
+  CONST64(0x0400040000000400), CONST64(0x0400040100000400), CONST64(0x0400040004000400), CONST64(0x0400040104000400),
+  CONST64(0x0400040000040400), CONST64(0x0400040100040400), CONST64(0x0400040004040400), CONST64(0x0400040104040400),
+  CONST64(0x0400040000000004), CONST64(0x0400040100000004), CONST64(0x0400040004000004), CONST64(0x0400040104000004),
+  CONST64(0x0400040000040004), CONST64(0x0400040100040004), CONST64(0x0400040004040004), CONST64(0x0400040104040004),
+  CONST64(0x0400040000000404), CONST64(0x0400040100000404), CONST64(0x0400040004000404), CONST64(0x0400040104000404),
+  CONST64(0x0400040000040404), CONST64(0x0400040100040404), CONST64(0x0400040004040404), CONST64(0x0400040104040404),
+  CONST64(0x0004040000000000), CONST64(0x0004040100000000), CONST64(0x0004040004000000), CONST64(0x0004040104000000),
+  CONST64(0x0004040000040000), CONST64(0x0004040100040000), CONST64(0x0004040004040000), CONST64(0x0004040104040000),
+  CONST64(0x0004040000000400), CONST64(0x0004040100000400), CONST64(0x0004040004000400), CONST64(0x0004040104000400),
+  CONST64(0x0004040000040400), CONST64(0x0004040100040400), CONST64(0x0004040004040400), CONST64(0x0004040104040400),
+  CONST64(0x0004040000000004), CONST64(0x0004040100000004), CONST64(0x0004040004000004), CONST64(0x0004040104000004),
+  CONST64(0x0004040000040004), CONST64(0x0004040100040004), CONST64(0x0004040004040004), CONST64(0x0004040104040004),
+  CONST64(0x0004040000000404), CONST64(0x0004040100000404), CONST64(0x0004040004000404), CONST64(0x0004040104000404),
+  CONST64(0x0004040000040404), CONST64(0x0004040100040404), CONST64(0x0004040004040404), CONST64(0x0004040104040404),
+  CONST64(0x0404040000000000), CONST64(0x0404040100000000), CONST64(0x0404040004000000), CONST64(0x0404040104000000),
+  CONST64(0x0404040000040000), CONST64(0x0404040100040000), CONST64(0x0404040004040000), CONST64(0x0404040104040000),
+  CONST64(0x0404040000000400), CONST64(0x0404040100000400), CONST64(0x0404040004000400), CONST64(0x0404040104000400),
+  CONST64(0x0404040000040400), CONST64(0x0404040100040400), CONST64(0x0404040004040400), CONST64(0x0404040104040400),
+  CONST64(0x0404040000000004), CONST64(0x0404040100000004), CONST64(0x0404040004000004), CONST64(0x0404040104000004),
+  CONST64(0x0404040000040004), CONST64(0x0404040100040004), CONST64(0x0404040004040004), CONST64(0x0404040104040004),
+  CONST64(0x0404040000000404), CONST64(0x0404040100000404), CONST64(0x0404040004000404), CONST64(0x0404040104000404),
+  CONST64(0x0404040000040404), CONST64(0x0404040100040404), CONST64(0x0404040004040404), CONST64(0x0404040104040404)
+  },
+{ CONST64(0x0000000000000000), CONST64(0x0000000400000000), CONST64(0x0000000010000000), CONST64(0x0000000410000000),
+  CONST64(0x0000000000100000), CONST64(0x0000000400100000), CONST64(0x0000000010100000), CONST64(0x0000000410100000),
+  CONST64(0x0000000000001000), CONST64(0x0000000400001000), CONST64(0x0000000010001000), CONST64(0x0000000410001000),
+  CONST64(0x0000000000101000), CONST64(0x0000000400101000), CONST64(0x0000000010101000), CONST64(0x0000000410101000),
+  CONST64(0x0000000000000010), CONST64(0x0000000400000010), CONST64(0x0000000010000010), CONST64(0x0000000410000010),
+  CONST64(0x0000000000100010), CONST64(0x0000000400100010), CONST64(0x0000000010100010), CONST64(0x0000000410100010),
+  CONST64(0x0000000000001010), CONST64(0x0000000400001010), CONST64(0x0000000010001010), CONST64(0x0000000410001010),
+  CONST64(0x0000000000101010), CONST64(0x0000000400101010), CONST64(0x0000000010101010), CONST64(0x0000000410101010),
+  CONST64(0x1000000000000000), CONST64(0x1000000400000000), CONST64(0x1000000010000000), CONST64(0x1000000410000000),
+  CONST64(0x1000000000100000), CONST64(0x1000000400100000), CONST64(0x1000000010100000), CONST64(0x1000000410100000),
+  CONST64(0x1000000000001000), CONST64(0x1000000400001000), CONST64(0x1000000010001000), CONST64(0x1000000410001000),
+  CONST64(0x1000000000101000), CONST64(0x1000000400101000), CONST64(0x1000000010101000), CONST64(0x1000000410101000),
+  CONST64(0x1000000000000010), CONST64(0x1000000400000010), CONST64(0x1000000010000010), CONST64(0x1000000410000010),
+  CONST64(0x1000000000100010), CONST64(0x1000000400100010), CONST64(0x1000000010100010), CONST64(0x1000000410100010),
+  CONST64(0x1000000000001010), CONST64(0x1000000400001010), CONST64(0x1000000010001010), CONST64(0x1000000410001010),
+  CONST64(0x1000000000101010), CONST64(0x1000000400101010), CONST64(0x1000000010101010), CONST64(0x1000000410101010),
+  CONST64(0x0010000000000000), CONST64(0x0010000400000000), CONST64(0x0010000010000000), CONST64(0x0010000410000000),
+  CONST64(0x0010000000100000), CONST64(0x0010000400100000), CONST64(0x0010000010100000), CONST64(0x0010000410100000),
+  CONST64(0x0010000000001000), CONST64(0x0010000400001000), CONST64(0x0010000010001000), CONST64(0x0010000410001000),
+  CONST64(0x0010000000101000), CONST64(0x0010000400101000), CONST64(0x0010000010101000), CONST64(0x0010000410101000),
+  CONST64(0x0010000000000010), CONST64(0x0010000400000010), CONST64(0x0010000010000010), CONST64(0x0010000410000010),
+  CONST64(0x0010000000100010), CONST64(0x0010000400100010), CONST64(0x0010000010100010), CONST64(0x0010000410100010),
+  CONST64(0x0010000000001010), CONST64(0x0010000400001010), CONST64(0x0010000010001010), CONST64(0x0010000410001010),
+  CONST64(0x0010000000101010), CONST64(0x0010000400101010), CONST64(0x0010000010101010), CONST64(0x0010000410101010),
+  CONST64(0x1010000000000000), CONST64(0x1010000400000000), CONST64(0x1010000010000000), CONST64(0x1010000410000000),
+  CONST64(0x1010000000100000), CONST64(0x1010000400100000), CONST64(0x1010000010100000), CONST64(0x1010000410100000),
+  CONST64(0x1010000000001000), CONST64(0x1010000400001000), CONST64(0x1010000010001000), CONST64(0x1010000410001000),
+  CONST64(0x1010000000101000), CONST64(0x1010000400101000), CONST64(0x1010000010101000), CONST64(0x1010000410101000),
+  CONST64(0x1010000000000010), CONST64(0x1010000400000010), CONST64(0x1010000010000010), CONST64(0x1010000410000010),
+  CONST64(0x1010000000100010), CONST64(0x1010000400100010), CONST64(0x1010000010100010), CONST64(0x1010000410100010),
+  CONST64(0x1010000000001010), CONST64(0x1010000400001010), CONST64(0x1010000010001010), CONST64(0x1010000410001010),
+  CONST64(0x1010000000101010), CONST64(0x1010000400101010), CONST64(0x1010000010101010), CONST64(0x1010000410101010),
+  CONST64(0x0000100000000000), CONST64(0x0000100400000000), CONST64(0x0000100010000000), CONST64(0x0000100410000000),
+  CONST64(0x0000100000100000), CONST64(0x0000100400100000), CONST64(0x0000100010100000), CONST64(0x0000100410100000),
+  CONST64(0x0000100000001000), CONST64(0x0000100400001000), CONST64(0x0000100010001000), CONST64(0x0000100410001000),
+  CONST64(0x0000100000101000), CONST64(0x0000100400101000), CONST64(0x0000100010101000), CONST64(0x0000100410101000),
+  CONST64(0x0000100000000010), CONST64(0x0000100400000010), CONST64(0x0000100010000010), CONST64(0x0000100410000010),
+  CONST64(0x0000100000100010), CONST64(0x0000100400100010), CONST64(0x0000100010100010), CONST64(0x0000100410100010),
+  CONST64(0x0000100000001010), CONST64(0x0000100400001010), CONST64(0x0000100010001010), CONST64(0x0000100410001010),
+  CONST64(0x0000100000101010), CONST64(0x0000100400101010), CONST64(0x0000100010101010), CONST64(0x0000100410101010),
+  CONST64(0x1000100000000000), CONST64(0x1000100400000000), CONST64(0x1000100010000000), CONST64(0x1000100410000000),
+  CONST64(0x1000100000100000), CONST64(0x1000100400100000), CONST64(0x1000100010100000), CONST64(0x1000100410100000),
+  CONST64(0x1000100000001000), CONST64(0x1000100400001000), CONST64(0x1000100010001000), CONST64(0x1000100410001000),
+  CONST64(0x1000100000101000), CONST64(0x1000100400101000), CONST64(0x1000100010101000), CONST64(0x1000100410101000),
+  CONST64(0x1000100000000010), CONST64(0x1000100400000010), CONST64(0x1000100010000010), CONST64(0x1000100410000010),
+  CONST64(0x1000100000100010), CONST64(0x1000100400100010), CONST64(0x1000100010100010), CONST64(0x1000100410100010),
+  CONST64(0x1000100000001010), CONST64(0x1000100400001010), CONST64(0x1000100010001010), CONST64(0x1000100410001010),
+  CONST64(0x1000100000101010), CONST64(0x1000100400101010), CONST64(0x1000100010101010), CONST64(0x1000100410101010),
+  CONST64(0x0010100000000000), CONST64(0x0010100400000000), CONST64(0x0010100010000000), CONST64(0x0010100410000000),
+  CONST64(0x0010100000100000), CONST64(0x0010100400100000), CONST64(0x0010100010100000), CONST64(0x0010100410100000),
+  CONST64(0x0010100000001000), CONST64(0x0010100400001000), CONST64(0x0010100010001000), CONST64(0x0010100410001000),
+  CONST64(0x0010100000101000), CONST64(0x0010100400101000), CONST64(0x0010100010101000), CONST64(0x0010100410101000),
+  CONST64(0x0010100000000010), CONST64(0x0010100400000010), CONST64(0x0010100010000010), CONST64(0x0010100410000010),
+  CONST64(0x0010100000100010), CONST64(0x0010100400100010), CONST64(0x0010100010100010), CONST64(0x0010100410100010),
+  CONST64(0x0010100000001010), CONST64(0x0010100400001010), CONST64(0x0010100010001010), CONST64(0x0010100410001010),
+  CONST64(0x0010100000101010), CONST64(0x0010100400101010), CONST64(0x0010100010101010), CONST64(0x0010100410101010),
+  CONST64(0x1010100000000000), CONST64(0x1010100400000000), CONST64(0x1010100010000000), CONST64(0x1010100410000000),
+  CONST64(0x1010100000100000), CONST64(0x1010100400100000), CONST64(0x1010100010100000), CONST64(0x1010100410100000),
+  CONST64(0x1010100000001000), CONST64(0x1010100400001000), CONST64(0x1010100010001000), CONST64(0x1010100410001000),
+  CONST64(0x1010100000101000), CONST64(0x1010100400101000), CONST64(0x1010100010101000), CONST64(0x1010100410101000),
+  CONST64(0x1010100000000010), CONST64(0x1010100400000010), CONST64(0x1010100010000010), CONST64(0x1010100410000010),
+  CONST64(0x1010100000100010), CONST64(0x1010100400100010), CONST64(0x1010100010100010), CONST64(0x1010100410100010),
+  CONST64(0x1010100000001010), CONST64(0x1010100400001010), CONST64(0x1010100010001010), CONST64(0x1010100410001010),
+  CONST64(0x1010100000101010), CONST64(0x1010100400101010), CONST64(0x1010100010101010), CONST64(0x1010100410101010)
+  },
+{ CONST64(0x0000000000000000), CONST64(0x0000001000000000), CONST64(0x0000000040000000), CONST64(0x0000001040000000),
+  CONST64(0x0000000000400000), CONST64(0x0000001000400000), CONST64(0x0000000040400000), CONST64(0x0000001040400000),
+  CONST64(0x0000000000004000), CONST64(0x0000001000004000), CONST64(0x0000000040004000), CONST64(0x0000001040004000),
+  CONST64(0x0000000000404000), CONST64(0x0000001000404000), CONST64(0x0000000040404000), CONST64(0x0000001040404000),
+  CONST64(0x0000000000000040), CONST64(0x0000001000000040), CONST64(0x0000000040000040), CONST64(0x0000001040000040),
+  CONST64(0x0000000000400040), CONST64(0x0000001000400040), CONST64(0x0000000040400040), CONST64(0x0000001040400040),
+  CONST64(0x0000000000004040), CONST64(0x0000001000004040), CONST64(0x0000000040004040), CONST64(0x0000001040004040),
+  CONST64(0x0000000000404040), CONST64(0x0000001000404040), CONST64(0x0000000040404040), CONST64(0x0000001040404040),
+  CONST64(0x4000000000000000), CONST64(0x4000001000000000), CONST64(0x4000000040000000), CONST64(0x4000001040000000),
+  CONST64(0x4000000000400000), CONST64(0x4000001000400000), CONST64(0x4000000040400000), CONST64(0x4000001040400000),
+  CONST64(0x4000000000004000), CONST64(0x4000001000004000), CONST64(0x4000000040004000), CONST64(0x4000001040004000),
+  CONST64(0x4000000000404000), CONST64(0x4000001000404000), CONST64(0x4000000040404000), CONST64(0x4000001040404000),
+  CONST64(0x4000000000000040), CONST64(0x4000001000000040), CONST64(0x4000000040000040), CONST64(0x4000001040000040),
+  CONST64(0x4000000000400040), CONST64(0x4000001000400040), CONST64(0x4000000040400040), CONST64(0x4000001040400040),
+  CONST64(0x4000000000004040), CONST64(0x4000001000004040), CONST64(0x4000000040004040), CONST64(0x4000001040004040),
+  CONST64(0x4000000000404040), CONST64(0x4000001000404040), CONST64(0x4000000040404040), CONST64(0x4000001040404040),
+  CONST64(0x0040000000000000), CONST64(0x0040001000000000), CONST64(0x0040000040000000), CONST64(0x0040001040000000),
+  CONST64(0x0040000000400000), CONST64(0x0040001000400000), CONST64(0x0040000040400000), CONST64(0x0040001040400000),
+  CONST64(0x0040000000004000), CONST64(0x0040001000004000), CONST64(0x0040000040004000), CONST64(0x0040001040004000),
+  CONST64(0x0040000000404000), CONST64(0x0040001000404000), CONST64(0x0040000040404000), CONST64(0x0040001040404000),
+  CONST64(0x0040000000000040), CONST64(0x0040001000000040), CONST64(0x0040000040000040), CONST64(0x0040001040000040),
+  CONST64(0x0040000000400040), CONST64(0x0040001000400040), CONST64(0x0040000040400040), CONST64(0x0040001040400040),
+  CONST64(0x0040000000004040), CONST64(0x0040001000004040), CONST64(0x0040000040004040), CONST64(0x0040001040004040),
+  CONST64(0x0040000000404040), CONST64(0x0040001000404040), CONST64(0x0040000040404040), CONST64(0x0040001040404040),
+  CONST64(0x4040000000000000), CONST64(0x4040001000000000), CONST64(0x4040000040000000), CONST64(0x4040001040000000),
+  CONST64(0x4040000000400000), CONST64(0x4040001000400000), CONST64(0x4040000040400000), CONST64(0x4040001040400000),
+  CONST64(0x4040000000004000), CONST64(0x4040001000004000), CONST64(0x4040000040004000), CONST64(0x4040001040004000),
+  CONST64(0x4040000000404000), CONST64(0x4040001000404000), CONST64(0x4040000040404000), CONST64(0x4040001040404000),
+  CONST64(0x4040000000000040), CONST64(0x4040001000000040), CONST64(0x4040000040000040), CONST64(0x4040001040000040),
+  CONST64(0x4040000000400040), CONST64(0x4040001000400040), CONST64(0x4040000040400040), CONST64(0x4040001040400040),
+  CONST64(0x4040000000004040), CONST64(0x4040001000004040), CONST64(0x4040000040004040), CONST64(0x4040001040004040),
+  CONST64(0x4040000000404040), CONST64(0x4040001000404040), CONST64(0x4040000040404040), CONST64(0x4040001040404040),
+  CONST64(0x0000400000000000), CONST64(0x0000401000000000), CONST64(0x0000400040000000), CONST64(0x0000401040000000),
+  CONST64(0x0000400000400000), CONST64(0x0000401000400000), CONST64(0x0000400040400000), CONST64(0x0000401040400000),
+  CONST64(0x0000400000004000), CONST64(0x0000401000004000), CONST64(0x0000400040004000), CONST64(0x0000401040004000),
+  CONST64(0x0000400000404000), CONST64(0x0000401000404000), CONST64(0x0000400040404000), CONST64(0x0000401040404000),
+  CONST64(0x0000400000000040), CONST64(0x0000401000000040), CONST64(0x0000400040000040), CONST64(0x0000401040000040),
+  CONST64(0x0000400000400040), CONST64(0x0000401000400040), CONST64(0x0000400040400040), CONST64(0x0000401040400040),
+  CONST64(0x0000400000004040), CONST64(0x0000401000004040), CONST64(0x0000400040004040), CONST64(0x0000401040004040),
+  CONST64(0x0000400000404040), CONST64(0x0000401000404040), CONST64(0x0000400040404040), CONST64(0x0000401040404040),
+  CONST64(0x4000400000000000), CONST64(0x4000401000000000), CONST64(0x4000400040000000), CONST64(0x4000401040000000),
+  CONST64(0x4000400000400000), CONST64(0x4000401000400000), CONST64(0x4000400040400000), CONST64(0x4000401040400000),
+  CONST64(0x4000400000004000), CONST64(0x4000401000004000), CONST64(0x4000400040004000), CONST64(0x4000401040004000),
+  CONST64(0x4000400000404000), CONST64(0x4000401000404000), CONST64(0x4000400040404000), CONST64(0x4000401040404000),
+  CONST64(0x4000400000000040), CONST64(0x4000401000000040), CONST64(0x4000400040000040), CONST64(0x4000401040000040),
+  CONST64(0x4000400000400040), CONST64(0x4000401000400040), CONST64(0x4000400040400040), CONST64(0x4000401040400040),
+  CONST64(0x4000400000004040), CONST64(0x4000401000004040), CONST64(0x4000400040004040), CONST64(0x4000401040004040),
+  CONST64(0x4000400000404040), CONST64(0x4000401000404040), CONST64(0x4000400040404040), CONST64(0x4000401040404040),
+  CONST64(0x0040400000000000), CONST64(0x0040401000000000), CONST64(0x0040400040000000), CONST64(0x0040401040000000),
+  CONST64(0x0040400000400000), CONST64(0x0040401000400000), CONST64(0x0040400040400000), CONST64(0x0040401040400000),
+  CONST64(0x0040400000004000), CONST64(0x0040401000004000), CONST64(0x0040400040004000), CONST64(0x0040401040004000),
+  CONST64(0x0040400000404000), CONST64(0x0040401000404000), CONST64(0x0040400040404000), CONST64(0x0040401040404000),
+  CONST64(0x0040400000000040), CONST64(0x0040401000000040), CONST64(0x0040400040000040), CONST64(0x0040401040000040),
+  CONST64(0x0040400000400040), CONST64(0x0040401000400040), CONST64(0x0040400040400040), CONST64(0x0040401040400040),
+  CONST64(0x0040400000004040), CONST64(0x0040401000004040), CONST64(0x0040400040004040), CONST64(0x0040401040004040),
+  CONST64(0x0040400000404040), CONST64(0x0040401000404040), CONST64(0x0040400040404040), CONST64(0x0040401040404040),
+  CONST64(0x4040400000000000), CONST64(0x4040401000000000), CONST64(0x4040400040000000), CONST64(0x4040401040000000),
+  CONST64(0x4040400000400000), CONST64(0x4040401000400000), CONST64(0x4040400040400000), CONST64(0x4040401040400000),
+  CONST64(0x4040400000004000), CONST64(0x4040401000004000), CONST64(0x4040400040004000), CONST64(0x4040401040004000),
+  CONST64(0x4040400000404000), CONST64(0x4040401000404000), CONST64(0x4040400040404000), CONST64(0x4040401040404000),
+  CONST64(0x4040400000000040), CONST64(0x4040401000000040), CONST64(0x4040400040000040), CONST64(0x4040401040000040),
+  CONST64(0x4040400000400040), CONST64(0x4040401000400040), CONST64(0x4040400040400040), CONST64(0x4040401040400040),
+  CONST64(0x4040400000004040), CONST64(0x4040401000004040), CONST64(0x4040400040004040), CONST64(0x4040401040004040),
+  CONST64(0x4040400000404040), CONST64(0x4040401000404040), CONST64(0x4040400040404040), CONST64(0x4040401040404040)
+  }};
+
+#endif
+
+
+static void cookey(const ulong32 *raw1, ulong32 *keyout);
+
+#ifdef LTC_CLEAN_STACK
+static void _deskey(const unsigned char *key, short edf, ulong32 *keyout)
+#else
+static void deskey(const unsigned char *key, short edf, ulong32 *keyout)
+#endif
+{
+    ulong32 i, j, l, m, n, kn[32];
+    unsigned char pc1m[56], pcr[56];
+
+    for (j=0; j < 56; j++) {
+        l = (ulong32)pc1[j];
+        m = l & 7;
+        pc1m[j] = (unsigned char)((key[l >> 3U] & bytebit[m]) == bytebit[m] ? 1 : 0);
+    }
+
+    for (i=0; i < 16; i++) {
+        if (edf == DE1) {
+           m = (15 - i) << 1;
+        } else {
+           m = i << 1;
+        }
+        n = m + 1;
+        kn[m] = kn[n] = 0L;
+        for (j=0; j < 28; j++) {
+            l = j + (ulong32)totrot[i];
+            if (l < 28) {
+               pcr[j] = pc1m[l];
+            } else {
+               pcr[j] = pc1m[l - 28];
+            }
+        }
+        for (/*j = 28*/; j < 56; j++) {
+            l = j + (ulong32)totrot[i];
+            if (l < 56) {
+               pcr[j] = pc1m[l];
+            } else {
+               pcr[j] = pc1m[l - 28];
+            }
+        }
+        for (j=0; j < 24; j++)  {
+            if ((int)pcr[(int)pc2[j]] != 0) {
+               kn[m] |= bigbyte[j];
+            }
+            if ((int)pcr[(int)pc2[j+24]] != 0) {
+               kn[n] |= bigbyte[j];
+            }
+        }
+    }
+
+    cookey(kn, keyout);
+}
+
+#ifdef LTC_CLEAN_STACK
+static void deskey(const unsigned char *key, short edf, ulong32 *keyout)
+{
+   _deskey(key, edf, keyout);
+   burn_stack(sizeof(int)*5 + sizeof(ulong32)*32 + sizeof(unsigned char)*112);
+}
+#endif
+
+#ifdef LTC_CLEAN_STACK
+static void _cookey(const ulong32 *raw1, ulong32 *keyout)
+#else
+static void cookey(const ulong32 *raw1, ulong32 *keyout)
+#endif
+{
+    ulong32 *cook;
+    const ulong32 *raw0;
+    ulong32 dough[32];
+    int i;
+
+    cook = dough;
+    for(i=0; i < 16; i++, raw1++)
+    {
+        raw0 = raw1++;
+        *cook    = (*raw0 & 0x00fc0000L) << 6;
+        *cook   |= (*raw0 & 0x00000fc0L) << 10;
+        *cook   |= (*raw1 & 0x00fc0000L) >> 10;
+        *cook++ |= (*raw1 & 0x00000fc0L) >> 6;
+        *cook    = (*raw0 & 0x0003f000L) << 12;
+        *cook   |= (*raw0 & 0x0000003fL) << 16;
+        *cook   |= (*raw1 & 0x0003f000L) >> 4;
+        *cook++ |= (*raw1 & 0x0000003fL);
+    }
+
+    XMEMCPY(keyout, dough, sizeof(dough));
+}
+
+#ifdef LTC_CLEAN_STACK
+static void cookey(const ulong32 *raw1, ulong32 *keyout)
+{
+   _cookey(raw1, keyout);
+   burn_stack(sizeof(ulong32 *) * 2 + sizeof(ulong32)*32 + sizeof(int));
+}
+#endif
+
+#ifndef LTC_CLEAN_STACK
+static void desfunc(ulong32 *block, const ulong32 *keys)
+#else
+static void _desfunc(ulong32 *block, const ulong32 *keys)
+#endif
+{
+    ulong32 work, right, leftt;
+    int cur_round;
+
+    leftt = block[0];
+    right = block[1];
+
+#ifdef LTC_SMALL_CODE
+    work = ((leftt >> 4)  ^ right) & 0x0f0f0f0fL;
+    right ^= work;
+    leftt ^= (work << 4);
+
+    work = ((leftt >> 16) ^ right) & 0x0000ffffL;
+    right ^= work;
+    leftt ^= (work << 16);
+
+    work = ((right >> 2)  ^ leftt) & 0x33333333L;
+    leftt ^= work;
+    right ^= (work << 2);
+
+    work = ((right >> 8)  ^ leftt) & 0x00ff00ffL;
+    leftt ^= work;
+    right ^= (work << 8);
+
+    right = ROLc(right, 1);
+    work = (leftt ^ right) & 0xaaaaaaaaL;
+
+    leftt ^= work;
+    right ^= work;
+    leftt = ROLc(leftt, 1);
+#else
+   {
+      ulong64 tmp;
+      tmp = des_ip[0][byte(leftt, 0)] ^
+            des_ip[1][byte(leftt, 1)] ^
+            des_ip[2][byte(leftt, 2)] ^
+            des_ip[3][byte(leftt, 3)] ^
+            des_ip[4][byte(right, 0)] ^
+            des_ip[5][byte(right, 1)] ^
+            des_ip[6][byte(right, 2)] ^
+            des_ip[7][byte(right, 3)];
+      leftt = (ulong32)(tmp >> 32);
+      right = (ulong32)(tmp & 0xFFFFFFFFUL);
+   }
+#endif
+
+    for (cur_round = 0; cur_round < 8; cur_round++) {
+        work  = RORc(right, 4) ^ *keys++;
+        leftt ^= SP7[work        & 0x3fL]
+              ^  SP5[(work >>  8) & 0x3fL]
+              ^  SP3[(work >> 16) & 0x3fL]
+              ^  SP1[(work >> 24) & 0x3fL];
+        work  = right ^ *keys++;
+        leftt ^= SP8[ work        & 0x3fL]
+              ^  SP6[(work >>  8) & 0x3fL]
+              ^  SP4[(work >> 16) & 0x3fL]
+              ^  SP2[(work >> 24) & 0x3fL];
+
+        work = RORc(leftt, 4) ^ *keys++;
+        right ^= SP7[ work        & 0x3fL]
+              ^  SP5[(work >>  8) & 0x3fL]
+              ^  SP3[(work >> 16) & 0x3fL]
+              ^  SP1[(work >> 24) & 0x3fL];
+        work  = leftt ^ *keys++;
+        right ^= SP8[ work        & 0x3fL]
+              ^  SP6[(work >>  8) & 0x3fL]
+              ^  SP4[(work >> 16) & 0x3fL]
+              ^  SP2[(work >> 24) & 0x3fL];
+    }
+
+#ifdef LTC_SMALL_CODE
+    right = RORc(right, 1);
+    work = (leftt ^ right) & 0xaaaaaaaaL;
+    leftt ^= work;
+    right ^= work;
+    leftt = RORc(leftt, 1);
+    work = ((leftt >> 8) ^ right) & 0x00ff00ffL;
+    right ^= work;
+    leftt ^= (work << 8);
+    /* -- */
+    work = ((leftt >> 2) ^ right) & 0x33333333L;
+    right ^= work;
+    leftt ^= (work << 2);
+    work = ((right >> 16) ^ leftt) & 0x0000ffffL;
+    leftt ^= work;
+    right ^= (work << 16);
+    work = ((right >> 4) ^ leftt) & 0x0f0f0f0fL;
+    leftt ^= work;
+    right ^= (work << 4);
+#else
+   {
+      ulong64 tmp;
+      tmp = des_fp[0][byte(leftt, 0)] ^
+            des_fp[1][byte(leftt, 1)] ^
+            des_fp[2][byte(leftt, 2)] ^
+            des_fp[3][byte(leftt, 3)] ^
+            des_fp[4][byte(right, 0)] ^
+            des_fp[5][byte(right, 1)] ^
+            des_fp[6][byte(right, 2)] ^
+            des_fp[7][byte(right, 3)];
+      leftt = (ulong32)(tmp >> 32);
+      right = (ulong32)(tmp & 0xFFFFFFFFUL);
+   }
+#endif
+
+    block[0] = right;
+    block[1] = leftt;
+}
+
+#ifdef LTC_CLEAN_STACK
+static void desfunc(ulong32 *block, const ulong32 *keys)
+{
+   _desfunc(block, keys);
+   burn_stack(sizeof(ulong32) * 4 + sizeof(int));
+}
+#endif
+
+ /**
+    Initialize the LTC_DES block cipher
+    @param key The symmetric key you wish to pass
+    @param keylen The key length in bytes
+    @param num_rounds The number of rounds desired (0 for default)
+    @param skey The key in as scheduled by this function.
+    @return CRYPT_OK if successful
+ */
+int des_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey)
+{
+    LTC_ARGCHK(key != NULL);
+    LTC_ARGCHK(skey != NULL);
+
+    if (num_rounds != 0 && num_rounds != 16) {
+        return CRYPT_INVALID_ROUNDS;
+    }
+
+    if (keylen != 8) {
+        return CRYPT_INVALID_KEYSIZE;
+    }
+
+    deskey(key, EN0, skey->des.ek);
+    deskey(key, DE1, skey->des.dk);
+
+    return CRYPT_OK;
+}
+
+ /**
+    Initialize the 3LTC_DES-EDE block cipher
+    @param key The symmetric key you wish to pass
+    @param keylen The key length in bytes
+    @param num_rounds The number of rounds desired (0 for default)
+    @param skey The key in as scheduled by this function.
+    @return CRYPT_OK if successful
+ */
+int des3_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey)
+{
+    LTC_ARGCHK(key != NULL);
+    LTC_ARGCHK(skey != NULL);
+
+    if(num_rounds != 0 && num_rounds != 16) {
+        return CRYPT_INVALID_ROUNDS;
+    }
+
+    if (keylen != 24 && keylen != 16) {
+        return CRYPT_INVALID_KEYSIZE;
+    }
+
+    deskey(key,    EN0, skey->des3.ek[0]);
+    deskey(key+8,  DE1, skey->des3.ek[1]);
+    if (keylen == 24) {
+        deskey(key+16, EN0, skey->des3.ek[2]);
+    } else {
+        /* two-key 3DES: K3=K1 */
+        deskey(key, EN0, skey->des3.ek[2]);
+    }
+
+    deskey(key,    DE1, skey->des3.dk[2]);
+    deskey(key+8,  EN0, skey->des3.dk[1]);
+    if (keylen == 24) {
+        deskey(key+16, DE1, skey->des3.dk[0]);
+    } else {
+        /* two-key 3DES: K3=K1 */
+        deskey(key, DE1, skey->des3.dk[0]);
+    }
+
+    return CRYPT_OK;
+}
+
+/**
+  Encrypts a block of text with LTC_DES
+  @param pt The input plaintext (8 bytes)
+  @param ct The output ciphertext (8 bytes)
+  @param skey The key as scheduled
+  @return CRYPT_OK if successful
+*/
+int des_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey)
+{
+    ulong32 work[2];
+    LTC_ARGCHK(pt   != NULL);
+    LTC_ARGCHK(ct   != NULL);
+    LTC_ARGCHK(skey != NULL);
+    LOAD32H(work[0], pt+0);
+    LOAD32H(work[1], pt+4);
+    desfunc(work, skey->des.ek);
+    STORE32H(work[0],ct+0);
+    STORE32H(work[1],ct+4);
+    return CRYPT_OK;
+}
+
+/**
+  Decrypts a block of text with LTC_DES
+  @param ct The input ciphertext (8 bytes)
+  @param pt The output plaintext (8 bytes)
+  @param skey The key as scheduled
+  @return CRYPT_OK if successful
+*/
+int des_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey)
+{
+    ulong32 work[2];
+    LTC_ARGCHK(pt   != NULL);
+    LTC_ARGCHK(ct   != NULL);
+    LTC_ARGCHK(skey != NULL);
+    LOAD32H(work[0], ct+0);
+    LOAD32H(work[1], ct+4);
+    desfunc(work, skey->des.dk);
+    STORE32H(work[0],pt+0);
+    STORE32H(work[1],pt+4);
+    return CRYPT_OK;
+}
+
+/**
+  Encrypts a block of text with 3LTC_DES-EDE
+  @param pt The input plaintext (8 bytes)
+  @param ct The output ciphertext (8 bytes)
+  @param skey The key as scheduled
+  @return CRYPT_OK if successful
+*/
+int des3_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey)
+{
+    ulong32 work[2];
+
+    LTC_ARGCHK(pt   != NULL);
+    LTC_ARGCHK(ct   != NULL);
+    LTC_ARGCHK(skey != NULL);
+    LOAD32H(work[0], pt+0);
+    LOAD32H(work[1], pt+4);
+    desfunc(work, skey->des3.ek[0]);
+    desfunc(work, skey->des3.ek[1]);
+    desfunc(work, skey->des3.ek[2]);
+    STORE32H(work[0],ct+0);
+    STORE32H(work[1],ct+4);
+    return CRYPT_OK;
+}
+
+/**
+  Decrypts a block of text with 3LTC_DES-EDE
+  @param ct The input ciphertext (8 bytes)
+  @param pt The output plaintext (8 bytes)
+  @param skey The key as scheduled
+  @return CRYPT_OK if successful
+*/
+int des3_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey)
+{
+    ulong32 work[2];
+    LTC_ARGCHK(pt   != NULL);
+    LTC_ARGCHK(ct   != NULL);
+    LTC_ARGCHK(skey != NULL);
+    LOAD32H(work[0], ct+0);
+    LOAD32H(work[1], ct+4);
+    desfunc(work, skey->des3.dk[0]);
+    desfunc(work, skey->des3.dk[1]);
+    desfunc(work, skey->des3.dk[2]);
+    STORE32H(work[0],pt+0);
+    STORE32H(work[1],pt+4);
+    return CRYPT_OK;
+}
+
+/**
+  Performs a self-test of the LTC_DES block cipher
+  @return CRYPT_OK if functional, CRYPT_NOP if self-test has been disabled
+*/
+int des_test(void)
+{
+ #ifndef LTC_TEST
+    return CRYPT_NOP;
+ #else
+    int err;
+    static const struct des_test_case {
+        int num, mode; /* mode 1 = encrypt */
+        unsigned char key[8], txt[8], out[8];
+    } cases[] = {
+        { 1, 1,     { 0x10, 0x31, 0x6E, 0x02, 0x8C, 0x8F, 0x3B, 0x4A },
+                    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+                    { 0x82, 0xDC, 0xBA, 0xFB, 0xDE, 0xAB, 0x66, 0x02 } },
+        { 2, 1,     { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 },
+                    { 0x95, 0xF8, 0xA5, 0xE5, 0xDD, 0x31, 0xD9, 0x00 },
+                    { 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } },
+        { 3, 1,     { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 },
+                    { 0xDD, 0x7F, 0x12, 0x1C, 0xA5, 0x01, 0x56, 0x19 },
+                    { 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } },
+        { 4, 1,     { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 },
+                    { 0x2E, 0x86, 0x53, 0x10, 0x4F, 0x38, 0x34, 0xEA },
+                    { 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } },
+        { 5, 1,     { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 },
+                    { 0x4B, 0xD3, 0x88, 0xFF, 0x6C, 0xD8, 0x1D, 0x4F },
+                    { 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } },
+        { 6, 1,     { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 },
+                    { 0x20, 0xB9, 0xE7, 0x67, 0xB2, 0xFB, 0x14, 0x56 },
+                    { 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } },
+        { 7, 1,     { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 },
+                    { 0x55, 0x57, 0x93, 0x80, 0xD7, 0x71, 0x38, 0xEF },
+                    { 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } },
+        { 8, 1,     { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 },
+                    { 0x6C, 0xC5, 0xDE, 0xFA, 0xAF, 0x04, 0x51, 0x2F },
+                    { 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } },
+        { 9, 1,     { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 },
+                    { 0x0D, 0x9F, 0x27, 0x9B, 0xA5, 0xD8, 0x72, 0x60 },
+                    { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } },
+        {10, 1,     { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 },
+                    { 0xD9, 0x03, 0x1B, 0x02, 0x71, 0xBD, 0x5A, 0x0A },
+                    { 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } },
+
+        { 1, 0,     { 0x10, 0x31, 0x6E, 0x02, 0x8C, 0x8F, 0x3B, 0x4A },
+                    { 0x82, 0xDC, 0xBA, 0xFB, 0xDE, 0xAB, 0x66, 0x02 },
+                    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } },
+        { 2, 0,     { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 },
+                    { 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+                    { 0x95, 0xF8, 0xA5, 0xE5, 0xDD, 0x31, 0xD9, 0x00 } },
+        { 3, 0,     { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 },
+                    { 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+                    { 0xDD, 0x7F, 0x12, 0x1C, 0xA5, 0x01, 0x56, 0x19 } },
+        { 4, 0,     { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 },
+                    { 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+                    { 0x2E, 0x86, 0x53, 0x10, 0x4F, 0x38, 0x34, 0xEA } },
+        { 5, 0,     { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 },
+                    { 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+                    { 0x4B, 0xD3, 0x88, 0xFF, 0x6C, 0xD8, 0x1D, 0x4F } },
+        { 6, 0,     { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 },
+                    { 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+                    { 0x20, 0xB9, 0xE7, 0x67, 0xB2, 0xFB, 0x14, 0x56 } },
+        { 7, 0,     { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 },
+                    { 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+                    { 0x55, 0x57, 0x93, 0x80, 0xD7, 0x71, 0x38, 0xEF } },
+        { 8, 0,     { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 },
+                    { 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+                    { 0x6C, 0xC5, 0xDE, 0xFA, 0xAF, 0x04, 0x51, 0x2F } },
+        { 9, 0,     { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 },
+                    { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+                    { 0x0D, 0x9F, 0x27, 0x9B, 0xA5, 0xD8, 0x72, 0x60 } },
+        {10, 0,     { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 },
+                    { 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+                    { 0xD9, 0x03, 0x1B, 0x02, 0x71, 0xBD, 0x5A, 0x0A } },
+
+#ifdef LTC_TEST_EXT
+        { 0+11, 0,  { 0x80, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 },
+                    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+                    { 0x95, 0xA8, 0xD7, 0x28, 0x13, 0xDA, 0xA9, 0x4D } },
+        { 1+11, 0,  { 0x40, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 },
+                    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+                    { 0x0E, 0xEC, 0x14, 0x87, 0xDD, 0x8C, 0x26, 0xD5 } },
+        { 2+11, 0,  { 0x20, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 },
+                    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+                    { 0x7A, 0xD1, 0x6F, 0xFB, 0x79, 0xC4, 0x59, 0x26 } },
+        { 3+11, 0,  { 0x10, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 },
+                    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+                    { 0xD3, 0x74, 0x62, 0x94, 0xCA, 0x6A, 0x6C, 0xF3 } },
+        { 4+11, 0,  { 0x08, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 },
+                    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+                    { 0x80, 0x9F, 0x5F, 0x87, 0x3C, 0x1F, 0xD7, 0x61 } },
+        { 5+11, 0,  { 0x04, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 },
+                    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+                    { 0xC0, 0x2F, 0xAF, 0xFE, 0xC9, 0x89, 0xD1, 0xFC } },
+        { 6+11, 0,  { 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 },
+                    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+                    { 0x46, 0x15, 0xAA, 0x1D, 0x33, 0xE7, 0x2F, 0x10 } },
+        { 7+11, 0,  { 0x01, 0x80, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 },
+                    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+                    { 0x20, 0x55, 0x12, 0x33, 0x50, 0xC0, 0x08, 0x58 } },
+        { 8+11, 0,  { 0x01, 0x40, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 },
+                    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+                    { 0xDF, 0x3B, 0x99, 0xD6, 0x57, 0x73, 0x97, 0xC8 } },
+        { 9+11, 0,  { 0x01, 0x20, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 },
+                    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+                    { 0x31, 0xFE, 0x17, 0x36, 0x9B, 0x52, 0x88, 0xC9 } },
+        {10+11, 0,  { 0x01, 0x10, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 },
+                    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+                    { 0xDF, 0xDD, 0x3C, 0xC6, 0x4D, 0xAE, 0x16, 0x42 } },
+        {11+11, 0,  { 0x01, 0x08, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 },
+                    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+                    { 0x17, 0x8C, 0x83, 0xCE, 0x2B, 0x39, 0x9D, 0x94 } },
+        {12+11, 0,  { 0x01, 0x04, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 },
+                    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+                    { 0x50, 0xF6, 0x36, 0x32, 0x4A, 0x9B, 0x7F, 0x80 } },
+        {13+11, 0,  { 0x01, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 },
+                    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+                    { 0xA8, 0x46, 0x8E, 0xE3, 0xBC, 0x18, 0xF0, 0x6D } },
+        {14+11, 0,  { 0x01, 0x01, 0x80, 0x01, 0x01, 0x01, 0x01, 0x01 },
+                    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+                    { 0xA2, 0xDC, 0x9E, 0x92, 0xFD, 0x3C, 0xDE, 0x92 } },
+        {15+11, 0,  { 0x01, 0x01, 0x40, 0x01, 0x01, 0x01, 0x01, 0x01 },
+                    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+                    { 0xCA, 0xC0, 0x9F, 0x79, 0x7D, 0x03, 0x12, 0x87 } },
+        {16+11, 0,  { 0x01, 0x01, 0x20, 0x01, 0x01, 0x01, 0x01, 0x01 },
+                    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+                    { 0x90, 0xBA, 0x68, 0x0B, 0x22, 0xAE, 0xB5, 0x25 } },
+        {17+11, 0,  { 0x01, 0x01, 0x10, 0x01, 0x01, 0x01, 0x01, 0x01 },
+                    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+                    { 0xCE, 0x7A, 0x24, 0xF3, 0x50, 0xE2, 0x80, 0xB6 } },
+        {18+11, 0,  { 0x01, 0x01, 0x08, 0x01, 0x01, 0x01, 0x01, 0x01 },
+                    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+                    { 0x88, 0x2B, 0xFF, 0x0A, 0xA0, 0x1A, 0x0B, 0x87 } },
+        {19+11, 0,  { 0x01, 0x01, 0x04, 0x01, 0x01, 0x01, 0x01, 0x01 },
+                    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+                    { 0x25, 0x61, 0x02, 0x88, 0x92, 0x45, 0x11, 0xC2 } },
+        {20+11, 0,  { 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01 },
+                    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+                    { 0xC7, 0x15, 0x16, 0xC2, 0x9C, 0x75, 0xD1, 0x70 } },
+        {21+11, 0,  { 0x01, 0x01, 0x01, 0x80, 0x01, 0x01, 0x01, 0x01 },
+                    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+                    { 0x51, 0x99, 0xC2, 0x9A, 0x52, 0xC9, 0xF0, 0x59 } },
+        {22+11, 0,  { 0x01, 0x01, 0x01, 0x40, 0x01, 0x01, 0x01, 0x01 },
+                    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+                    { 0xC2, 0x2F, 0x0A, 0x29, 0x4A, 0x71, 0xF2, 0x9F } },
+        {23+11, 0,  { 0x01, 0x01, 0x01, 0x20, 0x01, 0x01, 0x01, 0x01 },
+                    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+                    { 0xEE, 0x37, 0x14, 0x83, 0x71, 0x4C, 0x02, 0xEA } },
+        {24+11, 0,  { 0x01, 0x01, 0x01, 0x10, 0x01, 0x01, 0x01, 0x01 },
+                    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+                    { 0xA8, 0x1F, 0xBD, 0x44, 0x8F, 0x9E, 0x52, 0x2F } },
+        {25+11, 0,  { 0x01, 0x01, 0x01, 0x08, 0x01, 0x01, 0x01, 0x01 },
+                    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+                    { 0x4F, 0x64, 0x4C, 0x92, 0xE1, 0x92, 0xDF, 0xED } },
+        {26+11, 0,  { 0x01, 0x01, 0x01, 0x04, 0x01, 0x01, 0x01, 0x01 },
+                    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+                    { 0x1A, 0xFA, 0x9A, 0x66, 0xA6, 0xDF, 0x92, 0xAE } },
+        {27+11, 0,  { 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x01 },
+                    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+                    { 0xB3, 0xC1, 0xCC, 0x71, 0x5C, 0xB8, 0x79, 0xD8 } },
+        {28+11, 0,  { 0x01, 0x01, 0x01, 0x01, 0x80, 0x01, 0x01, 0x01 },
+                    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+                    { 0x19, 0xD0, 0x32, 0xE6, 0x4A, 0xB0, 0xBD, 0x8B } },
+        {29+11, 0,  { 0x01, 0x01, 0x01, 0x01, 0x40, 0x01, 0x01, 0x01 },
+                    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+                    { 0x3C, 0xFA, 0xA7, 0xA7, 0xDC, 0x87, 0x20, 0xDC } },
+        {30+11, 0,  { 0x01, 0x01, 0x01, 0x01, 0x20, 0x01, 0x01, 0x01 },
+                    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+                    { 0xB7, 0x26, 0x5F, 0x7F, 0x44, 0x7A, 0xC6, 0xF3 } },
+        {31+11, 0,  { 0x01, 0x01, 0x01, 0x01, 0x10, 0x01, 0x01, 0x01 },
+                    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+                    { 0x9D, 0xB7, 0x3B, 0x3C, 0x0D, 0x16, 0x3F, 0x54 } },
+        {32+11, 0,  { 0x01, 0x01, 0x01, 0x01, 0x08, 0x01, 0x01, 0x01 },
+                    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+                    { 0x81, 0x81, 0xB6, 0x5B, 0xAB, 0xF4, 0xA9, 0x75 } },
+        {33+11, 0,  { 0x01, 0x01, 0x01, 0x01, 0x04, 0x01, 0x01, 0x01 },
+                    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+                    { 0x93, 0xC9, 0xB6, 0x40, 0x42, 0xEA, 0xA2, 0x40 } },
+        {34+11, 0,  { 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01 },
+                    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+                    { 0x55, 0x70, 0x53, 0x08, 0x29, 0x70, 0x55, 0x92 } },
+        {35+11, 0,  { 0x01, 0x01, 0x01, 0x01, 0x01, 0x80, 0x01, 0x01 },
+                    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+                    { 0x86, 0x38, 0x80, 0x9E, 0x87, 0x87, 0x87, 0xA0 } },
+        {36+11, 0,  { 0x01, 0x01, 0x01, 0x01, 0x01, 0x40, 0x01, 0x01 },
+                    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+                    { 0x41, 0xB9, 0xA7, 0x9A, 0xF7, 0x9A, 0xC2, 0x08 } },
+        {37+11, 0,  { 0x01, 0x01, 0x01, 0x01, 0x01, 0x20, 0x01, 0x01 },
+                    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+                    { 0x7A, 0x9B, 0xE4, 0x2F, 0x20, 0x09, 0xA8, 0x92 } },
+        {38+11, 0,  { 0x01, 0x01, 0x01, 0x01, 0x01, 0x10, 0x01, 0x01 },
+                    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+                    { 0x29, 0x03, 0x8D, 0x56, 0xBA, 0x6D, 0x27, 0x45 } },
+        {39+11, 0,  { 0x01, 0x01, 0x01, 0x01, 0x01, 0x08, 0x01, 0x01 },
+                    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+                    { 0x54, 0x95, 0xC6, 0xAB, 0xF1, 0xE5, 0xDF, 0x51 } },
+        {40+11, 0,  { 0x01, 0x01, 0x01, 0x01, 0x01, 0x04, 0x01, 0x01 },
+                    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+                    { 0xAE, 0x13, 0xDB, 0xD5, 0x61, 0x48, 0x89, 0x33 } },
+        {41+11, 0,  { 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01 },
+                    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+                    { 0x02, 0x4D, 0x1F, 0xFA, 0x89, 0x04, 0xE3, 0x89 } },
+        {42+11, 0,  { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x80, 0x01 },
+                    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+                    { 0xD1, 0x39, 0x97, 0x12, 0xF9, 0x9B, 0xF0, 0x2E } },
+        {43+11, 0,  { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x40, 0x01 },
+                    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+                    { 0x14, 0xC1, 0xD7, 0xC1, 0xCF, 0xFE, 0xC7, 0x9E } },
+        {44+11, 0,  { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x20, 0x01 },
+                    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+                    { 0x1D, 0xE5, 0x27, 0x9D, 0xAE, 0x3B, 0xED, 0x6F } },
+        {45+11, 0,  { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x10, 0x01 },
+                    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+                    { 0xE9, 0x41, 0xA3, 0x3F, 0x85, 0x50, 0x13, 0x03 } },
+        {46+11, 0,  { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x08, 0x01 },
+                    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+                    { 0xDA, 0x99, 0xDB, 0xBC, 0x9A, 0x03, 0xF3, 0x79 } },
+        {47+11, 0,  { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x04, 0x01 },
+                    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+                    { 0xB7, 0xFC, 0x92, 0xF9, 0x1D, 0x8E, 0x92, 0xE9 } },
+        {48+11, 0,  { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01 },
+                    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+                    { 0xAE, 0x8E, 0x5C, 0xAA, 0x3C, 0xA0, 0x4E, 0x85 } },
+        {49+11, 0,  { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x80 },
+                    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+                    { 0x9C, 0xC6, 0x2D, 0xF4, 0x3B, 0x6E, 0xED, 0x74 } },
+        {50+11, 0,  { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x40 },
+                    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+                    { 0xD8, 0x63, 0xDB, 0xB5, 0xC5, 0x9A, 0x91, 0xA0 } },
+        {51+11, 0,  { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x20 },
+                    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+                    { 0xA1, 0xAB, 0x21, 0x90, 0x54, 0x5B, 0x91, 0xD7 } },
+        {52+11, 0,  { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x10 },
+                    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+                    { 0x08, 0x75, 0x04, 0x1E, 0x64, 0xC5, 0x70, 0xF7 } },
+        {53+11, 0,  { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x08 },
+                    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+                    { 0x5A, 0x59, 0x45, 0x28, 0xBE, 0xBE, 0xF1, 0xCC } },
+        {54+11, 0,  { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x04 },
+                    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+                    { 0xFC, 0xDB, 0x32, 0x91, 0xDE, 0x21, 0xF0, 0xC0 } },
+        {55+11, 0,  { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02 },
+                    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+                    { 0x86, 0x9E, 0xFD, 0x7F, 0x9F, 0x26, 0x5A, 0x09 } },
+#endif /* LTC_TEST_EXT */
+
+        /*** more test cases you could add if you are not convinced (the above test cases aren't really too good):
+
+                key              plaintext        ciphertext
+                0000000000000000 0000000000000000 8CA64DE9C1B123A7
+                FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF 7359B2163E4EDC58
+                3000000000000000 1000000000000001 958E6E627A05557B
+                1111111111111111 1111111111111111 F40379AB9E0EC533
+                0123456789ABCDEF 1111111111111111 17668DFC7292532D
+                1111111111111111 0123456789ABCDEF 8A5AE1F81AB8F2DD
+                0000000000000000 0000000000000000 8CA64DE9C1B123A7
+                FEDCBA9876543210 0123456789ABCDEF ED39D950FA74BCC4
+                7CA110454A1A6E57 01A1D6D039776742 690F5B0D9A26939B
+                0131D9619DC1376E 5CD54CA83DEF57DA 7A389D10354BD271
+                07A1133E4A0B2686 0248D43806F67172 868EBB51CAB4599A
+                3849674C2602319E 51454B582DDF440A 7178876E01F19B2A
+                04B915BA43FEB5B6 42FD443059577FA2 AF37FB421F8C4095
+                0113B970FD34F2CE 059B5E0851CF143A 86A560F10EC6D85B
+                0170F175468FB5E6 0756D8E0774761D2 0CD3DA020021DC09
+                43297FAD38E373FE 762514B829BF486A EA676B2CB7DB2B7A
+                07A7137045DA2A16 3BDD119049372802 DFD64A815CAF1A0F
+                04689104C2FD3B2F 26955F6835AF609A 5C513C9C4886C088
+                37D06BB516CB7546 164D5E404F275232 0A2AEEAE3FF4AB77
+                1F08260D1AC2465E 6B056E18759F5CCA EF1BF03E5DFA575A
+                584023641ABA6176 004BD6EF09176062 88BF0DB6D70DEE56
+                025816164629B007 480D39006EE762F2 A1F9915541020B56
+                49793EBC79B3258F 437540C8698F3CFA 6FBF1CAFCFFD0556
+                4FB05E1515AB73A7 072D43A077075292 2F22E49BAB7CA1AC
+                49E95D6D4CA229BF 02FE55778117F12A 5A6B612CC26CCE4A
+                018310DC409B26D6 1D9D5C5018F728C2 5F4C038ED12B2E41
+                1C587F1C13924FEF 305532286D6F295A 63FAC0D034D9F793
+                0101010101010101 0123456789ABCDEF 617B3A0CE8F07100
+                1F1F1F1F0E0E0E0E 0123456789ABCDEF DB958605F8C8C606
+                E0FEE0FEF1FEF1FE 0123456789ABCDEF EDBFD1C66C29CCC7
+                0000000000000000 FFFFFFFFFFFFFFFF 355550B2150E2451
+                FFFFFFFFFFFFFFFF 0000000000000000 CAAAAF4DEAF1DBAE
+                0123456789ABCDEF 0000000000000000 D5D44FF720683D0D
+                FEDCBA9876543210 FFFFFFFFFFFFFFFF 2A2BB008DF97C2F2
+
+            http://www.ecs.soton.ac.uk/~prw99r/ez438/vectors.txt
+        ***/
+    };
+    int i, y;
+    unsigned char tmp[8];
+    symmetric_key des;
+
+    for(i=0; i < (int)(sizeof(cases)/sizeof(cases[0])); i++)
+    {
+        if ((err = des_setup(cases[i].key, 8, 0, &des)) != CRYPT_OK) {
+           return err;
+        }
+        if (cases[i].mode != 0) {
+           des_ecb_encrypt(cases[i].txt, tmp, &des);
+        } else {
+           des_ecb_decrypt(cases[i].txt, tmp, &des);
+        }
+
+        if (compare_testvector(cases[i].out, sizeof(tmp), tmp, sizeof(tmp), "DES", i) != 0) {
+           return CRYPT_FAIL_TESTVECTOR;
+        }
+
+        /* now see if we can encrypt all zero bytes 1000 times, decrypt and come back where we started */
+        for (y = 0; y < 8; y++) tmp[y] = 0;
+        for (y = 0; y < 1000; y++) des_ecb_encrypt(tmp, tmp, &des);
+        for (y = 0; y < 1000; y++) des_ecb_decrypt(tmp, tmp, &des);
+        for (y = 0; y < 8; y++) if (tmp[y] != 0) return CRYPT_FAIL_TESTVECTOR;
+    }
+
+    return CRYPT_OK;
+  #endif
+}
+
+int des3_test(void)
+{
+ #ifndef LTC_TEST
+    return CRYPT_NOP;
+ #else
+   unsigned char key[24], pt[8], ct[8], tmp[8];
+   symmetric_key skey;
+   int x, err;
+
+   if ((err = des_test()) != CRYPT_OK) {
+      return err;
+   }
+
+   for (x = 0; x < 8; x++) {
+       pt[x] = x;
+   }
+
+   for (x = 0; x < 24; x++) {
+       key[x] = x;
+   }
+
+   if ((err = des3_setup(key, 24, 0, &skey)) != CRYPT_OK) {
+      return err;
+   }
+
+   des3_ecb_encrypt(pt, ct, &skey);
+   des3_ecb_decrypt(ct, tmp, &skey);
+
+   if (compare_testvector(pt, 8, tmp, 8, "3DES", 0) != 0) {
+      return CRYPT_FAIL_TESTVECTOR;
+   }
+
+   return CRYPT_OK;
+ #endif
+}
+
+/** Terminate the context
+   @param skey    The scheduled key
+*/
+void des_done(symmetric_key *skey)
+{
+  LTC_UNUSED_PARAM(skey);
+}
+
+/** Terminate the context
+   @param skey    The scheduled key
+*/
+void des3_done(symmetric_key *skey)
+{
+  LTC_UNUSED_PARAM(skey);
+}
+
+
+/**
+  Gets suitable key size
+  @param keysize [in/out] The length of the recommended key (in bytes).  This function will store the suitable size back in this variable.
+  @return CRYPT_OK if the input key size is acceptable.
+*/
+int des_keysize(int *keysize)
+{
+    LTC_ARGCHK(keysize != NULL);
+    if(*keysize < 8) {
+        return CRYPT_INVALID_KEYSIZE;
+    }
+    *keysize = 8;
+    return CRYPT_OK;
+}
+
+/**
+  Gets suitable key size
+  @param keysize [in/out] The length of the recommended key (in bytes).  This function will store the suitable size back in this variable.
+  @return CRYPT_OK if the input key size is acceptable.
+*/
+int des3_keysize(int *keysize)
+{
+    LTC_ARGCHK(keysize != NULL);
+    if (*keysize < 16)
+       return CRYPT_INVALID_KEYSIZE;
+    if (*keysize < 24) {
+       *keysize = 16;
+       return CRYPT_OK;
+    }
+    *keysize = 24;
+    return CRYPT_OK;
+}
+
+#endif
+
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/ciphers/kasumi.c b/libtomcrypt/src/ciphers/kasumi.c
new file mode 100644 (file)
index 0000000..7c2add5
--- /dev/null
@@ -0,0 +1,318 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+/**
+  @file kasumi.c
+  Implementation of the 3GPP Kasumi block cipher
+  Derived from the 3GPP standard source code
+*/
+
+#include "tomcrypt.h"
+
+#ifdef LTC_KASUMI
+
+typedef unsigned u16;
+
+#define ROL16(x, y) ((((x)<<(y)) | ((x)>>(16-(y)))) & 0xFFFF)
+
+const struct ltc_cipher_descriptor kasumi_desc = {
+   "kasumi",
+   21,
+   16, 16, 8, 8,
+   &kasumi_setup,
+   &kasumi_ecb_encrypt,
+   &kasumi_ecb_decrypt,
+   &kasumi_test,
+   &kasumi_done,
+   &kasumi_keysize,
+   NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
+};
+
+static u16 FI( u16 in, u16 subkey )
+{
+   u16 nine, seven;
+   static const u16 S7[128] = {
+      54, 50, 62, 56, 22, 34, 94, 96, 38, 6, 63, 93, 2, 18,123, 33,
+      55,113, 39,114, 21, 67, 65, 12, 47, 73, 46, 27, 25,111,124, 81,
+      53, 9,121, 79, 52, 60, 58, 48,101,127, 40,120,104, 70, 71, 43,
+      20,122, 72, 61, 23,109, 13,100, 77, 1, 16, 7, 82, 10,105, 98,
+      117,116, 76, 11, 89,106, 0,125,118, 99, 86, 69, 30, 57,126, 87,
+      112, 51, 17, 5, 95, 14, 90, 84, 91, 8, 35,103, 32, 97, 28, 66,
+      102, 31, 26, 45, 75, 4, 85, 92, 37, 74, 80, 49, 68, 29,115, 44,
+      64,107,108, 24,110, 83, 36, 78, 42, 19, 15, 41, 88,119, 59, 3 };
+  static const u16 S9[512] = {
+      167,239,161,379,391,334, 9,338, 38,226, 48,358,452,385, 90,397,
+      183,253,147,331,415,340, 51,362,306,500,262, 82,216,159,356,177,
+      175,241,489, 37,206, 17, 0,333, 44,254,378, 58,143,220, 81,400,
+       95, 3,315,245, 54,235,218,405,472,264,172,494,371,290,399, 76,
+      165,197,395,121,257,480,423,212,240, 28,462,176,406,507,288,223,
+      501,407,249,265, 89,186,221,428,164, 74,440,196,458,421,350,163,
+      232,158,134,354, 13,250,491,142,191, 69,193,425,152,227,366,135,
+      344,300,276,242,437,320,113,278, 11,243, 87,317, 36, 93,496, 27,
+      487,446,482, 41, 68,156,457,131,326,403,339, 20, 39,115,442,124,
+      475,384,508, 53,112,170,479,151,126,169, 73,268,279,321,168,364,
+      363,292, 46,499,393,327,324, 24,456,267,157,460,488,426,309,229,
+      439,506,208,271,349,401,434,236, 16,209,359, 52, 56,120,199,277,
+      465,416,252,287,246, 6, 83,305,420,345,153,502, 65, 61,244,282,
+      173,222,418, 67,386,368,261,101,476,291,195,430, 49, 79,166,330,
+      280,383,373,128,382,408,155,495,367,388,274,107,459,417, 62,454,
+      132,225,203,316,234, 14,301, 91,503,286,424,211,347,307,140,374,
+       35,103,125,427, 19,214,453,146,498,314,444,230,256,329,198,285,
+       50,116, 78,410, 10,205,510,171,231, 45,139,467, 29, 86,505, 32,
+       72, 26,342,150,313,490,431,238,411,325,149,473, 40,119,174,355,
+      185,233,389, 71,448,273,372, 55,110,178,322, 12,469,392,369,190,
+        1,109,375,137,181, 88, 75,308,260,484, 98,272,370,275,412,111,
+      336,318, 4,504,492,259,304, 77,337,435, 21,357,303,332,483, 18,
+       47, 85, 25,497,474,289,100,269,296,478,270,106, 31,104,433, 84,
+      414,486,394, 96, 99,154,511,148,413,361,409,255,162,215,302,201,
+      266,351,343,144,441,365,108,298,251, 34,182,509,138,210,335,133,
+      311,352,328,141,396,346,123,319,450,281,429,228,443,481, 92,404,
+      485,422,248,297, 23,213,130,466, 22,217,283, 70,294,360,419,127,
+      312,377, 7,468,194, 2,117,295,463,258,224,447,247,187, 80,398,
+      284,353,105,390,299,471,470,184, 57,200,348, 63,204,188, 33,451,
+       97, 30,310,219, 94,160,129,493, 64,179,263,102,189,207,114,402,
+      438,477,387,122,192, 42,381, 5,145,118,180,449,293,323,136,380,
+       43, 66, 60,455,341,445,202,432, 8,237, 15,376,436,464, 59,461};
+
+  /* The sixteen bit input is split into two unequal halves, *
+   * nine bits and seven bits - as is the subkey            */
+
+  nine  = (u16)(in>>7)&0x1FF;
+  seven = (u16)(in&0x7F);
+
+  /* Now run the various operations */
+  nine   = (u16)(S9[nine] ^ seven);
+  seven  = (u16)(S7[seven] ^ (nine & 0x7F));
+  seven ^= (subkey>>9);
+  nine  ^= (subkey&0x1FF);
+  nine   = (u16)(S9[nine] ^ seven);
+  seven  = (u16)(S7[seven] ^ (nine & 0x7F));
+  return (u16)(seven<<9) + nine;
+}
+
+static ulong32 FO( ulong32 in, int round_no, symmetric_key *key)
+{
+   u16 left, right;
+
+  /* Split the input into two 16-bit words */
+  left = (u16)(in>>16);
+  right = (u16) in&0xFFFF;
+
+  /* Now apply the same basic transformation three times */
+  left ^= key->kasumi.KOi1[round_no];
+  left = FI( left, key->kasumi.KIi1[round_no] );
+  left ^= right;
+
+  right ^= key->kasumi.KOi2[round_no];
+  right = FI( right, key->kasumi.KIi2[round_no] );
+  right ^= left;
+
+  left ^= key->kasumi.KOi3[round_no];
+  left = FI( left, key->kasumi.KIi3[round_no] );
+  left ^= right;
+
+  return (((ulong32)right)<<16)+left;
+}
+
+static ulong32 FL( ulong32 in, int round_no, symmetric_key *key )
+{
+    u16 l, r, a, b;
+    /* split out the left and right halves */
+    l = (u16)(in>>16);
+    r = (u16)(in)&0xFFFF;
+    /* do the FL() operations           */
+    a = (u16) (l & key->kasumi.KLi1[round_no]);
+    r ^= ROL16(a,1);
+    b = (u16)(r | key->kasumi.KLi2[round_no]);
+    l ^= ROL16(b,1);
+    /* put the two halves back together */
+
+    return (((ulong32)l)<<16) + r;
+}
+
+int kasumi_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey)
+{
+    ulong32 left, right, temp;
+    int n;
+
+    LTC_ARGCHK(pt   != NULL);
+    LTC_ARGCHK(ct   != NULL);
+    LTC_ARGCHK(skey != NULL);
+
+    LOAD32H(left, pt);
+    LOAD32H(right, pt+4);
+
+    for (n = 0; n <= 7; ) {
+        temp = FL(left,  n,   skey);
+        temp = FO(temp,  n++, skey);
+        right ^= temp;
+        temp = FO(right, n,   skey);
+        temp = FL(temp,  n++, skey);
+        left ^= temp;
+    }
+
+    STORE32H(left, ct);
+    STORE32H(right, ct+4);
+
+    return CRYPT_OK;
+}
+
+int kasumi_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey)
+{
+    ulong32 left, right, temp;
+    int n;
+
+    LTC_ARGCHK(pt   != NULL);
+    LTC_ARGCHK(ct   != NULL);
+    LTC_ARGCHK(skey != NULL);
+
+    LOAD32H(left, ct);
+    LOAD32H(right, ct+4);
+
+    for (n = 7; n >= 0; ) {
+        temp = FO(right, n,   skey);
+        temp = FL(temp,  n--, skey);
+        left ^= temp;
+        temp = FL(left,  n,   skey);
+        temp = FO(temp,  n--, skey);
+        right ^= temp;
+    }
+
+    STORE32H(left, pt);
+    STORE32H(right, pt+4);
+
+    return CRYPT_OK;
+}
+
+int kasumi_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey)
+{
+    static const u16 C[8] = { 0x0123,0x4567,0x89AB,0xCDEF, 0xFEDC,0xBA98,0x7654,0x3210 };
+    u16 ukey[8], Kprime[8];
+    int n;
+
+    LTC_ARGCHK(key  != NULL);
+    LTC_ARGCHK(skey != NULL);
+
+    if (keylen != 16) {
+       return CRYPT_INVALID_KEYSIZE;
+    }
+
+    if (num_rounds != 0 && num_rounds != 8) {
+       return CRYPT_INVALID_ROUNDS;
+    }
+
+    /* Start by ensuring the subkeys are endian correct on a 16-bit basis */
+    for (n = 0; n < 8; n++ ) {
+        ukey[n] = (((u16)key[2*n]) << 8) | key[2*n+1];
+    }
+
+    /* Now build the K'[] keys */
+    for (n = 0; n < 8; n++) {
+        Kprime[n] = ukey[n] ^ C[n];
+    }
+
+    /* Finally construct the various sub keys */
+    for(n = 0; n < 8; n++) {
+        skey->kasumi.KLi1[n] = ROL16(ukey[n],1);
+        skey->kasumi.KLi2[n] = Kprime[(n+2)&0x7];
+        skey->kasumi.KOi1[n] = ROL16(ukey[(n+1)&0x7],5);
+        skey->kasumi.KOi2[n] = ROL16(ukey[(n+5)&0x7],8);
+        skey->kasumi.KOi3[n] = ROL16(ukey[(n+6)&0x7],13);
+        skey->kasumi.KIi1[n] = Kprime[(n+4)&0x7];
+        skey->kasumi.KIi2[n] = Kprime[(n+3)&0x7];
+        skey->kasumi.KIi3[n] = Kprime[(n+7)&0x7];
+    }
+
+    return CRYPT_OK;
+}
+
+void kasumi_done(symmetric_key *skey)
+{
+  LTC_UNUSED_PARAM(skey);
+}
+
+int kasumi_keysize(int *keysize)
+{
+   LTC_ARGCHK(keysize != NULL);
+   if (*keysize >= 16) {
+      *keysize = 16;
+      return CRYPT_OK;
+   } else {
+      return CRYPT_INVALID_KEYSIZE;
+   }
+}
+
+int kasumi_test(void)
+{
+#ifndef LTC_TEST
+   return CRYPT_NOP;
+#else
+   static const struct {
+      unsigned char key[16], pt[8], ct[8];
+   } tests[] = {
+
+{
+   { 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+   { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+   { 0x4B, 0x58, 0xA7, 0x71, 0xAF, 0xC7, 0xE5, 0xE8 }
+},
+
+{
+   { 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+   { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+   { 0x7E, 0xEF, 0x11, 0x3C, 0x95, 0xBB, 0x5A, 0x77 }
+},
+
+{
+   { 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+   { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+   { 0x5F, 0x14, 0x06, 0x86, 0xD7, 0xAD, 0x5A, 0x39 },
+},
+
+{
+   { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 },
+   { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+   { 0x2E, 0x14, 0x91, 0xCF, 0x70, 0xAA, 0x46, 0x5D }
+},
+
+{
+   { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00 },
+   { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+   { 0xB5, 0x45, 0x86, 0xF4, 0xAB, 0x9A, 0xE5, 0x46 }
+},
+
+};
+   unsigned char buf[2][8];
+   symmetric_key key;
+   int err, x;
+
+   for (x = 0; x < (int)(sizeof(tests)/sizeof(tests[0])); x++) {
+       if ((err = kasumi_setup(tests[x].key, 16, 0, &key)) != CRYPT_OK) {
+          return err;
+       }
+       if ((err = kasumi_ecb_encrypt(tests[x].pt, buf[0], &key)) != CRYPT_OK) {
+          return err;
+       }
+       if ((err = kasumi_ecb_decrypt(tests[x].ct, buf[1], &key)) != CRYPT_OK) {
+          return err;
+       }
+       if (compare_testvector(buf[1], 8, tests[x].pt, 8, "Kasumi Decrypt", x) ||
+             compare_testvector(buf[0], 8, tests[x].ct, 8, "Kasumi Encrypt", x)) {
+          return CRYPT_FAIL_TESTVECTOR;
+       }
+   }
+   return CRYPT_OK;
+#endif
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/ciphers/khazad.c b/libtomcrypt/src/ciphers/khazad.c
new file mode 100644 (file)
index 0000000..4d1f2ce
--- /dev/null
@@ -0,0 +1,855 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file khazad.c
+  Khazad implementation derived from public domain source
+  Authors: Paulo S.L.M. Barreto and Vincent Rijmen.
+*/
+
+#ifdef LTC_KHAZAD
+
+const struct ltc_cipher_descriptor khazad_desc = {
+   "khazad",
+   18,
+   16, 16, 8, 8,
+   &khazad_setup,
+   &khazad_ecb_encrypt,
+   &khazad_ecb_decrypt,
+   &khazad_test,
+   &khazad_done,
+   &khazad_keysize,
+   NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
+};
+
+#define R      8
+#define KEYSIZE      128
+#define KEYSIZEB   (KEYSIZE/8)
+#define BLOCKSIZE   64
+#define BLOCKSIZEB   (BLOCKSIZE/8)
+
+static const ulong64 T0[256] = {
+    CONST64(0xbad3d268bbb96a01), CONST64(0x54fc4d19e59a66b1), CONST64(0x2f71bc93e26514cd), CONST64(0x749ccdb925871b51),
+    CONST64(0x53f55102f7a257a4), CONST64(0xd3686bb8d0d6be03), CONST64(0xd26b6fbdd6deb504), CONST64(0x4dd72964b35285fe),
+    CONST64(0x50f05d0dfdba4aad), CONST64(0xace98a26cf09e063), CONST64(0x8d8a0e83091c9684), CONST64(0xbfdcc679a5914d1a),
+    CONST64(0x7090ddad3da7374d), CONST64(0x52f65507f1aa5ca3), CONST64(0x9ab352c87ba417e1), CONST64(0x4cd42d61b55a8ef9),
+    CONST64(0xea238f65460320ac), CONST64(0xd56273a6c4e68411), CONST64(0x97a466f155cc68c2), CONST64(0xd16e63b2dcc6a80d),
+    CONST64(0x3355ccffaa85d099), CONST64(0x51f35908fbb241aa), CONST64(0x5bed712ac7e20f9c), CONST64(0xa6f7a204f359ae55),
+    CONST64(0xde7f5f81febec120), CONST64(0x48d83d75ad7aa2e5), CONST64(0xa8e59a32d729cc7f), CONST64(0x99b65ec771bc0ae8),
+    CONST64(0xdb704b90e096e63b), CONST64(0x3256c8faac8ddb9e), CONST64(0xb7c4e65195d11522), CONST64(0xfc19d72b32b3aace),
+    CONST64(0xe338ab48704b7393), CONST64(0x9ebf42dc63843bfd), CONST64(0x91ae7eef41fc52d0), CONST64(0x9bb056cd7dac1ce6),
+    CONST64(0xe23baf4d76437894), CONST64(0xbbd0d66dbdb16106), CONST64(0x41c319589b32f1da), CONST64(0x6eb2a5cb7957e517),
+    CONST64(0xa5f2ae0bf941b35c), CONST64(0xcb400bc08016564b), CONST64(0x6bbdb1da677fc20c), CONST64(0x95a26efb59dc7ecc),
+    CONST64(0xa1febe1fe1619f40), CONST64(0xf308eb1810cbc3e3), CONST64(0xb1cefe4f81e12f30), CONST64(0x0206080a0c10160e),
+    CONST64(0xcc4917db922e675e), CONST64(0xc45137f3a26e3f66), CONST64(0x1d2774694ee8cf53), CONST64(0x143c504478a09c6c),
+    CONST64(0xc3582be8b0560e73), CONST64(0x63a591f2573f9a34), CONST64(0xda734f95e69eed3c), CONST64(0x5de76934d3d2358e),
+    CONST64(0x5fe1613edfc22380), CONST64(0xdc79578bf2aed72e), CONST64(0x7d87e99413cf486e), CONST64(0xcd4a13de94266c59),
+    CONST64(0x7f81e19e1fdf5e60), CONST64(0x5aee752fc1ea049b), CONST64(0x6cb4adc17547f319), CONST64(0x5ce46d31d5da3e89),
+    CONST64(0xf704fb0c08ebefff), CONST64(0x266a98bed42d47f2), CONST64(0xff1cdb2438abb7c7), CONST64(0xed2a937e543b11b9),
+    CONST64(0xe825876f4a1336a2), CONST64(0x9dba4ed3699c26f4), CONST64(0x6fb1a1ce7f5fee10), CONST64(0x8e8f028c03048b8d),
+    CONST64(0x192b647d56c8e34f), CONST64(0xa0fdba1ae7699447), CONST64(0xf00de7171ad3deea), CONST64(0x89861e97113cba98),
+    CONST64(0x0f113c332278692d), CONST64(0x07091c1b12383115), CONST64(0xafec8629c511fd6a), CONST64(0xfb10cb30208b9bdb),
+    CONST64(0x0818202830405838), CONST64(0x153f54417ea8976b), CONST64(0x0d1734392e687f23), CONST64(0x040c101418202c1c),
+    CONST64(0x0103040506080b07), CONST64(0x64ac8de94507ab21), CONST64(0xdf7c5b84f8b6ca27), CONST64(0x769ac5b329970d5f),
+    CONST64(0x798bf9800bef6472), CONST64(0xdd7a538ef4a6dc29), CONST64(0x3d47f4c98ef5b2b3), CONST64(0x163a584e74b08a62),
+    CONST64(0x3f41fcc382e5a4bd), CONST64(0x3759dcebb2a5fc85), CONST64(0x6db7a9c4734ff81e), CONST64(0x3848e0d890dd95a8),
+    CONST64(0xb9d6de67b1a17708), CONST64(0x7395d1a237bf2a44), CONST64(0xe926836a4c1b3da5), CONST64(0x355fd4e1beb5ea8b),
+    CONST64(0x55ff491ce3926db6), CONST64(0x7193d9a83baf3c4a), CONST64(0x7b8df18a07ff727c), CONST64(0x8c890a860f149d83),
+    CONST64(0x7296d5a731b72143), CONST64(0x88851a921734b19f), CONST64(0xf607ff090ee3e4f8), CONST64(0x2a7ea882fc4d33d6),
+    CONST64(0x3e42f8c684edafba), CONST64(0x5ee2653bd9ca2887), CONST64(0x27699cbbd2254cf5), CONST64(0x46ca0543890ac0cf),
+    CONST64(0x0c14303c28607424), CONST64(0x65af89ec430fa026), CONST64(0x68b8bdd56d67df05), CONST64(0x61a399f85b2f8c3a),
+    CONST64(0x03050c0f0a181d09), CONST64(0xc15e23e2bc46187d), CONST64(0x57f94116ef827bb8), CONST64(0xd6677fa9cefe9918),
+    CONST64(0xd976439aec86f035), CONST64(0x58e87d25cdfa1295), CONST64(0xd875479fea8efb32), CONST64(0x66aa85e34917bd2f),
+    CONST64(0xd7647bacc8f6921f), CONST64(0x3a4ee8d29ccd83a6), CONST64(0xc84507cf8a0e4b42), CONST64(0x3c44f0cc88fdb9b4),
+    CONST64(0xfa13cf35268390dc), CONST64(0x96a762f453c463c5), CONST64(0xa7f4a601f551a552), CONST64(0x98b55ac277b401ef),
+    CONST64(0xec29977b52331abe), CONST64(0xb8d5da62b7a97c0f), CONST64(0xc7543bfca876226f), CONST64(0xaeef822cc319f66d),
+    CONST64(0x69bbb9d06b6fd402), CONST64(0x4bdd317aa762bfec), CONST64(0xabe0963ddd31d176), CONST64(0xa9e69e37d121c778),
+    CONST64(0x67a981e64f1fb628), CONST64(0x0a1e28223c504e36), CONST64(0x47c901468f02cbc8), CONST64(0xf20bef1d16c3c8e4),
+    CONST64(0xb5c2ee5b99c1032c), CONST64(0x226688aacc0d6bee), CONST64(0xe532b356647b4981), CONST64(0xee2f9f715e230cb0),
+    CONST64(0xbedfc27ca399461d), CONST64(0x2b7dac87fa4538d1), CONST64(0x819e3ebf217ce2a0), CONST64(0x1236485a6c90a67e),
+    CONST64(0x839836b52d6cf4ae), CONST64(0x1b2d6c775ad8f541), CONST64(0x0e1238362470622a), CONST64(0x23658cafca0560e9),
+    CONST64(0xf502f30604fbf9f1), CONST64(0x45cf094c8312ddc6), CONST64(0x216384a5c61576e7), CONST64(0xce4f1fd19e3e7150),
+    CONST64(0x49db3970ab72a9e2), CONST64(0x2c74b09ce87d09c4), CONST64(0xf916c33a2c9b8dd5), CONST64(0xe637bf596e635488),
+    CONST64(0xb6c7e25493d91e25), CONST64(0x2878a088f05d25d8), CONST64(0x17395c4b72b88165), CONST64(0x829b32b02b64ffa9),
+    CONST64(0x1a2e68725cd0fe46), CONST64(0x8b80169d1d2cac96), CONST64(0xfe1fdf213ea3bcc0), CONST64(0x8a8312981b24a791),
+    CONST64(0x091b242d3648533f), CONST64(0xc94603ca8c064045), CONST64(0x879426a1354cd8b2), CONST64(0x4ed2256bb94a98f7),
+    CONST64(0xe13ea3427c5b659d), CONST64(0x2e72b896e46d1fca), CONST64(0xe431b75362734286), CONST64(0xe03da7477a536e9a),
+    CONST64(0xeb208b60400b2bab), CONST64(0x90ad7aea47f459d7), CONST64(0xa4f1aa0eff49b85b), CONST64(0x1e22786644f0d25a),
+    CONST64(0x85922eab395ccebc), CONST64(0x60a09dfd5d27873d), CONST64(0x0000000000000000), CONST64(0x256f94b1de355afb),
+    CONST64(0xf401f70302f3f2f6), CONST64(0xf10ee3121cdbd5ed), CONST64(0x94a16afe5fd475cb), CONST64(0x0b1d2c273a584531),
+    CONST64(0xe734bb5c686b5f8f), CONST64(0x759fc9bc238f1056), CONST64(0xef2c9b74582b07b7), CONST64(0x345cd0e4b8bde18c),
+    CONST64(0x3153c4f5a695c697), CONST64(0xd46177a3c2ee8f16), CONST64(0xd06d67b7dacea30a), CONST64(0x869722a43344d3b5),
+    CONST64(0x7e82e59b19d75567), CONST64(0xadea8e23c901eb64), CONST64(0xfd1ad32e34bba1c9), CONST64(0x297ba48df6552edf),
+    CONST64(0x3050c0f0a09dcd90), CONST64(0x3b4decd79ac588a1), CONST64(0x9fbc46d9658c30fa), CONST64(0xf815c73f2a9386d2),
+    CONST64(0xc6573ff9ae7e2968), CONST64(0x13354c5f6a98ad79), CONST64(0x060a181e14303a12), CONST64(0x050f14111e28271b),
+    CONST64(0xc55233f6a4663461), CONST64(0x113344556688bb77), CONST64(0x7799c1b62f9f0658), CONST64(0x7c84ed9115c74369),
+    CONST64(0x7a8ef58f01f7797b), CONST64(0x7888fd850de76f75), CONST64(0x365ad8eeb4adf782), CONST64(0x1c24706c48e0c454),
+    CONST64(0x394be4dd96d59eaf), CONST64(0x59eb7920cbf21992), CONST64(0x1828607850c0e848), CONST64(0x56fa4513e98a70bf),
+    CONST64(0xb3c8f6458df1393e), CONST64(0xb0cdfa4a87e92437), CONST64(0x246c90b4d83d51fc), CONST64(0x206080a0c01d7de0),
+    CONST64(0xb2cbf2408bf93239), CONST64(0x92ab72e04be44fd9), CONST64(0xa3f8b615ed71894e), CONST64(0xc05d27e7ba4e137a),
+    CONST64(0x44cc0d49851ad6c1), CONST64(0x62a695f751379133), CONST64(0x103040506080b070), CONST64(0xb4c1ea5e9fc9082b),
+    CONST64(0x84912aae3f54c5bb), CONST64(0x43c511529722e7d4), CONST64(0x93a876e54dec44de), CONST64(0xc25b2fedb65e0574),
+    CONST64(0x4ade357fa16ab4eb), CONST64(0xbddace73a9815b14), CONST64(0x8f8c0689050c808a), CONST64(0x2d77b499ee7502c3),
+    CONST64(0xbcd9ca76af895013), CONST64(0x9cb94ad66f942df3), CONST64(0x6abeb5df6177c90b), CONST64(0x40c01d5d9d3afadd),
+    CONST64(0xcf4c1bd498367a57), CONST64(0xa2fbb210eb798249), CONST64(0x809d3aba2774e9a7), CONST64(0x4fd1216ebf4293f0),
+    CONST64(0x1f217c6342f8d95d), CONST64(0xca430fc5861e5d4c), CONST64(0xaae39238db39da71), CONST64(0x42c61557912aecd3),
+};
+
+static const ulong64 T1[256] = {
+    CONST64(0xd3ba68d2b9bb016a), CONST64(0xfc54194d9ae5b166), CONST64(0x712f93bc65e2cd14), CONST64(0x9c74b9cd8725511b),
+    CONST64(0xf5530251a2f7a457), CONST64(0x68d3b86bd6d003be), CONST64(0x6bd2bd6fded604b5), CONST64(0xd74d642952b3fe85),
+    CONST64(0xf0500d5dbafdad4a), CONST64(0xe9ac268a09cf63e0), CONST64(0x8a8d830e1c098496), CONST64(0xdcbf79c691a51a4d),
+    CONST64(0x9070addda73d4d37), CONST64(0xf6520755aaf1a35c), CONST64(0xb39ac852a47be117), CONST64(0xd44c612d5ab5f98e),
+    CONST64(0x23ea658f0346ac20), CONST64(0x62d5a673e6c41184), CONST64(0xa497f166cc55c268), CONST64(0x6ed1b263c6dc0da8),
+    CONST64(0x5533ffcc85aa99d0), CONST64(0xf3510859b2fbaa41), CONST64(0xed5b2a71e2c79c0f), CONST64(0xf7a604a259f355ae),
+    CONST64(0x7fde815fbefe20c1), CONST64(0xd848753d7aade5a2), CONST64(0xe5a8329a29d77fcc), CONST64(0xb699c75ebc71e80a),
+    CONST64(0x70db904b96e03be6), CONST64(0x5632fac88dac9edb), CONST64(0xc4b751e6d1952215), CONST64(0x19fc2bd7b332ceaa),
+    CONST64(0x38e348ab4b709373), CONST64(0xbf9edc428463fd3b), CONST64(0xae91ef7efc41d052), CONST64(0xb09bcd56ac7de61c),
+    CONST64(0x3be24daf43769478), CONST64(0xd0bb6dd6b1bd0661), CONST64(0xc3415819329bdaf1), CONST64(0xb26ecba5577917e5),
+    CONST64(0xf2a50bae41f95cb3), CONST64(0x40cbc00b16804b56), CONST64(0xbd6bdab17f670cc2), CONST64(0xa295fb6edc59cc7e),
+    CONST64(0xfea11fbe61e1409f), CONST64(0x08f318ebcb10e3c3), CONST64(0xceb14ffee181302f), CONST64(0x06020a08100c0e16),
+    CONST64(0x49ccdb172e925e67), CONST64(0x51c4f3376ea2663f), CONST64(0x271d6974e84e53cf), CONST64(0x3c144450a0786c9c),
+    CONST64(0x58c3e82b56b0730e), CONST64(0xa563f2913f57349a), CONST64(0x73da954f9ee63ced), CONST64(0xe75d3469d2d38e35),
+    CONST64(0xe15f3e61c2df8023), CONST64(0x79dc8b57aef22ed7), CONST64(0x877d94e9cf136e48), CONST64(0x4acdde132694596c),
+    CONST64(0x817f9ee1df1f605e), CONST64(0xee5a2f75eac19b04), CONST64(0xb46cc1ad477519f3), CONST64(0xe45c316ddad5893e),
+    CONST64(0x04f70cfbeb08ffef), CONST64(0x6a26be982dd4f247), CONST64(0x1cff24dbab38c7b7), CONST64(0x2aed7e933b54b911),
+    CONST64(0x25e86f87134aa236), CONST64(0xba9dd34e9c69f426), CONST64(0xb16fcea15f7f10ee), CONST64(0x8f8e8c0204038d8b),
+    CONST64(0x2b197d64c8564fe3), CONST64(0xfda01aba69e74794), CONST64(0x0df017e7d31aeade), CONST64(0x8689971e3c1198ba),
+    CONST64(0x110f333c78222d69), CONST64(0x09071b1c38121531), CONST64(0xecaf298611c56afd), CONST64(0x10fb30cb8b20db9b),
+    CONST64(0x1808282040303858), CONST64(0x3f154154a87e6b97), CONST64(0x170d3934682e237f), CONST64(0x0c04141020181c2c),
+    CONST64(0x030105040806070b), CONST64(0xac64e98d074521ab), CONST64(0x7cdf845bb6f827ca), CONST64(0x9a76b3c597295f0d),
+    CONST64(0x8b7980f9ef0b7264), CONST64(0x7add8e53a6f429dc), CONST64(0x473dc9f4f58eb3b2), CONST64(0x3a164e58b074628a),
+    CONST64(0x413fc3fce582bda4), CONST64(0x5937ebdca5b285fc), CONST64(0xb76dc4a94f731ef8), CONST64(0x4838d8e0dd90a895),
+    CONST64(0xd6b967dea1b10877), CONST64(0x9573a2d1bf37442a), CONST64(0x26e96a831b4ca53d), CONST64(0x5f35e1d4b5be8bea),
+    CONST64(0xff551c4992e3b66d), CONST64(0x9371a8d9af3b4a3c), CONST64(0x8d7b8af1ff077c72), CONST64(0x898c860a140f839d),
+    CONST64(0x9672a7d5b7314321), CONST64(0x8588921a34179fb1), CONST64(0x07f609ffe30ef8e4), CONST64(0x7e2a82a84dfcd633),
+    CONST64(0x423ec6f8ed84baaf), CONST64(0xe25e3b65cad98728), CONST64(0x6927bb9c25d2f54c), CONST64(0xca4643050a89cfc0),
+    CONST64(0x140c3c3060282474), CONST64(0xaf65ec890f4326a0), CONST64(0xb868d5bd676d05df), CONST64(0xa361f8992f5b3a8c),
+    CONST64(0x05030f0c180a091d), CONST64(0x5ec1e22346bc7d18), CONST64(0xf957164182efb87b), CONST64(0x67d6a97ffece1899),
+    CONST64(0x76d99a4386ec35f0), CONST64(0xe858257dfacd9512), CONST64(0x75d89f478eea32fb), CONST64(0xaa66e38517492fbd),
+    CONST64(0x64d7ac7bf6c81f92), CONST64(0x4e3ad2e8cd9ca683), CONST64(0x45c8cf070e8a424b), CONST64(0x443cccf0fd88b4b9),
+    CONST64(0x13fa35cf8326dc90), CONST64(0xa796f462c453c563), CONST64(0xf4a701a651f552a5), CONST64(0xb598c25ab477ef01),
+    CONST64(0x29ec7b973352be1a), CONST64(0xd5b862daa9b70f7c), CONST64(0x54c7fc3b76a86f22), CONST64(0xefae2c8219c36df6),
+    CONST64(0xbb69d0b96f6b02d4), CONST64(0xdd4b7a3162a7ecbf), CONST64(0xe0ab3d9631dd76d1), CONST64(0xe6a9379e21d178c7),
+    CONST64(0xa967e6811f4f28b6), CONST64(0x1e0a2228503c364e), CONST64(0xc9474601028fc8cb), CONST64(0x0bf21defc316e4c8),
+    CONST64(0xc2b55beec1992c03), CONST64(0x6622aa880dccee6b), CONST64(0x32e556b37b648149), CONST64(0x2fee719f235eb00c),
+    CONST64(0xdfbe7cc299a31d46), CONST64(0x7d2b87ac45fad138), CONST64(0x9e81bf3e7c21a0e2), CONST64(0x36125a48906c7ea6),
+    CONST64(0x9883b5366c2daef4), CONST64(0x2d1b776cd85a41f5), CONST64(0x120e363870242a62), CONST64(0x6523af8c05cae960),
+    CONST64(0x02f506f3fb04f1f9), CONST64(0xcf454c091283c6dd), CONST64(0x6321a58415c6e776), CONST64(0x4fced11f3e9e5071),
+    CONST64(0xdb49703972abe2a9), CONST64(0x742c9cb07de8c409), CONST64(0x16f93ac39b2cd58d), CONST64(0x37e659bf636e8854),
+    CONST64(0xc7b654e2d993251e), CONST64(0x782888a05df0d825), CONST64(0x39174b5cb8726581), CONST64(0x9b82b032642ba9ff),
+    CONST64(0x2e1a7268d05c46fe), CONST64(0x808b9d162c1d96ac), CONST64(0x1ffe21dfa33ec0bc), CONST64(0x838a9812241b91a7),
+    CONST64(0x1b092d2448363f53), CONST64(0x46c9ca03068c4540), CONST64(0x9487a1264c35b2d8), CONST64(0xd24e6b254ab9f798),
+    CONST64(0x3ee142a35b7c9d65), CONST64(0x722e96b86de4ca1f), CONST64(0x31e453b773628642), CONST64(0x3de047a7537a9a6e),
+    CONST64(0x20eb608b0b40ab2b), CONST64(0xad90ea7af447d759), CONST64(0xf1a40eaa49ff5bb8), CONST64(0x221e6678f0445ad2),
+    CONST64(0x9285ab2e5c39bcce), CONST64(0xa060fd9d275d3d87), CONST64(0x0000000000000000), CONST64(0x6f25b19435defb5a),
+    CONST64(0x01f403f7f302f6f2), CONST64(0x0ef112e3db1cedd5), CONST64(0xa194fe6ad45fcb75), CONST64(0x1d0b272c583a3145),
+    CONST64(0x34e75cbb6b688f5f), CONST64(0x9f75bcc98f235610), CONST64(0x2cef749b2b58b707), CONST64(0x5c34e4d0bdb88ce1),
+    CONST64(0x5331f5c495a697c6), CONST64(0x61d4a377eec2168f), CONST64(0x6dd0b767ceda0aa3), CONST64(0x9786a4224433b5d3),
+    CONST64(0x827e9be5d7196755), CONST64(0xeaad238e01c964eb), CONST64(0x1afd2ed3bb34c9a1), CONST64(0x7b298da455f6df2e),
+    CONST64(0x5030f0c09da090cd), CONST64(0x4d3bd7ecc59aa188), CONST64(0xbc9fd9468c65fa30), CONST64(0x15f83fc7932ad286),
+    CONST64(0x57c6f93f7eae6829), CONST64(0x35135f4c986a79ad), CONST64(0x0a061e183014123a), CONST64(0x0f051114281e1b27),
+    CONST64(0x52c5f63366a46134), CONST64(0x33115544886677bb), CONST64(0x9977b6c19f2f5806), CONST64(0x847c91edc7156943),
+    CONST64(0x8e7a8ff5f7017b79), CONST64(0x887885fde70d756f), CONST64(0x5a36eed8adb482f7), CONST64(0x241c6c70e04854c4),
+    CONST64(0x4b39dde4d596af9e), CONST64(0xeb592079f2cb9219), CONST64(0x28187860c05048e8), CONST64(0xfa5613458ae9bf70),
+    CONST64(0xc8b345f6f18d3e39), CONST64(0xcdb04afae9873724), CONST64(0x6c24b4903dd8fc51), CONST64(0x6020a0801dc0e07d),
+    CONST64(0xcbb240f2f98b3932), CONST64(0xab92e072e44bd94f), CONST64(0xf8a315b671ed4e89), CONST64(0x5dc0e7274eba7a13),
+    CONST64(0xcc44490d1a85c1d6), CONST64(0xa662f79537513391), CONST64(0x30105040806070b0), CONST64(0xc1b45eeac99f2b08),
+    CONST64(0x9184ae2a543fbbc5), CONST64(0xc54352112297d4e7), CONST64(0xa893e576ec4dde44), CONST64(0x5bc2ed2f5eb67405),
+    CONST64(0xde4a7f356aa1ebb4), CONST64(0xdabd73ce81a9145b), CONST64(0x8c8f89060c058a80), CONST64(0x772d99b475eec302),
+    CONST64(0xd9bc76ca89af1350), CONST64(0xb99cd64a946ff32d), CONST64(0xbe6adfb577610bc9), CONST64(0xc0405d1d3a9dddfa),
+    CONST64(0x4ccfd41b3698577a), CONST64(0xfba210b279eb4982), CONST64(0x9d80ba3a7427a7e9), CONST64(0xd14f6e2142bff093),
+    CONST64(0x211f637cf8425dd9), CONST64(0x43cac50f1e864c5d), CONST64(0xe3aa389239db71da), CONST64(0xc64257152a91d3ec),
+};
+
+static const ulong64 T2[256] = {
+    CONST64(0xd268bad36a01bbb9), CONST64(0x4d1954fc66b1e59a), CONST64(0xbc932f7114cde265), CONST64(0xcdb9749c1b512587),
+    CONST64(0x510253f557a4f7a2), CONST64(0x6bb8d368be03d0d6), CONST64(0x6fbdd26bb504d6de), CONST64(0x29644dd785feb352),
+    CONST64(0x5d0d50f04aadfdba), CONST64(0x8a26ace9e063cf09), CONST64(0x0e838d8a9684091c), CONST64(0xc679bfdc4d1aa591),
+    CONST64(0xddad7090374d3da7), CONST64(0x550752f65ca3f1aa), CONST64(0x52c89ab317e17ba4), CONST64(0x2d614cd48ef9b55a),
+    CONST64(0x8f65ea2320ac4603), CONST64(0x73a6d5628411c4e6), CONST64(0x66f197a468c255cc), CONST64(0x63b2d16ea80ddcc6),
+    CONST64(0xccff3355d099aa85), CONST64(0x590851f341aafbb2), CONST64(0x712a5bed0f9cc7e2), CONST64(0xa204a6f7ae55f359),
+    CONST64(0x5f81de7fc120febe), CONST64(0x3d7548d8a2e5ad7a), CONST64(0x9a32a8e5cc7fd729), CONST64(0x5ec799b60ae871bc),
+    CONST64(0x4b90db70e63be096), CONST64(0xc8fa3256db9eac8d), CONST64(0xe651b7c4152295d1), CONST64(0xd72bfc19aace32b3),
+    CONST64(0xab48e3387393704b), CONST64(0x42dc9ebf3bfd6384), CONST64(0x7eef91ae52d041fc), CONST64(0x56cd9bb01ce67dac),
+    CONST64(0xaf4de23b78947643), CONST64(0xd66dbbd06106bdb1), CONST64(0x195841c3f1da9b32), CONST64(0xa5cb6eb2e5177957),
+    CONST64(0xae0ba5f2b35cf941), CONST64(0x0bc0cb40564b8016), CONST64(0xb1da6bbdc20c677f), CONST64(0x6efb95a27ecc59dc),
+    CONST64(0xbe1fa1fe9f40e161), CONST64(0xeb18f308c3e310cb), CONST64(0xfe4fb1ce2f3081e1), CONST64(0x080a0206160e0c10),
+    CONST64(0x17dbcc49675e922e), CONST64(0x37f3c4513f66a26e), CONST64(0x74691d27cf534ee8), CONST64(0x5044143c9c6c78a0),
+    CONST64(0x2be8c3580e73b056), CONST64(0x91f263a59a34573f), CONST64(0x4f95da73ed3ce69e), CONST64(0x69345de7358ed3d2),
+    CONST64(0x613e5fe12380dfc2), CONST64(0x578bdc79d72ef2ae), CONST64(0xe9947d87486e13cf), CONST64(0x13decd4a6c599426),
+    CONST64(0xe19e7f815e601fdf), CONST64(0x752f5aee049bc1ea), CONST64(0xadc16cb4f3197547), CONST64(0x6d315ce43e89d5da),
+    CONST64(0xfb0cf704efff08eb), CONST64(0x98be266a47f2d42d), CONST64(0xdb24ff1cb7c738ab), CONST64(0x937eed2a11b9543b),
+    CONST64(0x876fe82536a24a13), CONST64(0x4ed39dba26f4699c), CONST64(0xa1ce6fb1ee107f5f), CONST64(0x028c8e8f8b8d0304),
+    CONST64(0x647d192be34f56c8), CONST64(0xba1aa0fd9447e769), CONST64(0xe717f00ddeea1ad3), CONST64(0x1e978986ba98113c),
+    CONST64(0x3c330f11692d2278), CONST64(0x1c1b070931151238), CONST64(0x8629afecfd6ac511), CONST64(0xcb30fb109bdb208b),
+    CONST64(0x2028081858383040), CONST64(0x5441153f976b7ea8), CONST64(0x34390d177f232e68), CONST64(0x1014040c2c1c1820),
+    CONST64(0x040501030b070608), CONST64(0x8de964acab214507), CONST64(0x5b84df7cca27f8b6), CONST64(0xc5b3769a0d5f2997),
+    CONST64(0xf980798b64720bef), CONST64(0x538edd7adc29f4a6), CONST64(0xf4c93d47b2b38ef5), CONST64(0x584e163a8a6274b0),
+    CONST64(0xfcc33f41a4bd82e5), CONST64(0xdceb3759fc85b2a5), CONST64(0xa9c46db7f81e734f), CONST64(0xe0d8384895a890dd),
+    CONST64(0xde67b9d67708b1a1), CONST64(0xd1a273952a4437bf), CONST64(0x836ae9263da54c1b), CONST64(0xd4e1355fea8bbeb5),
+    CONST64(0x491c55ff6db6e392), CONST64(0xd9a871933c4a3baf), CONST64(0xf18a7b8d727c07ff), CONST64(0x0a868c899d830f14),
+    CONST64(0xd5a77296214331b7), CONST64(0x1a928885b19f1734), CONST64(0xff09f607e4f80ee3), CONST64(0xa8822a7e33d6fc4d),
+    CONST64(0xf8c63e42afba84ed), CONST64(0x653b5ee22887d9ca), CONST64(0x9cbb27694cf5d225), CONST64(0x054346cac0cf890a),
+    CONST64(0x303c0c1474242860), CONST64(0x89ec65afa026430f), CONST64(0xbdd568b8df056d67), CONST64(0x99f861a38c3a5b2f),
+    CONST64(0x0c0f03051d090a18), CONST64(0x23e2c15e187dbc46), CONST64(0x411657f97bb8ef82), CONST64(0x7fa9d6679918cefe),
+    CONST64(0x439ad976f035ec86), CONST64(0x7d2558e81295cdfa), CONST64(0x479fd875fb32ea8e), CONST64(0x85e366aabd2f4917),
+    CONST64(0x7bacd764921fc8f6), CONST64(0xe8d23a4e83a69ccd), CONST64(0x07cfc8454b428a0e), CONST64(0xf0cc3c44b9b488fd),
+    CONST64(0xcf35fa1390dc2683), CONST64(0x62f496a763c553c4), CONST64(0xa601a7f4a552f551), CONST64(0x5ac298b501ef77b4),
+    CONST64(0x977bec291abe5233), CONST64(0xda62b8d57c0fb7a9), CONST64(0x3bfcc754226fa876), CONST64(0x822caeeff66dc319),
+    CONST64(0xb9d069bbd4026b6f), CONST64(0x317a4bddbfeca762), CONST64(0x963dabe0d176dd31), CONST64(0x9e37a9e6c778d121),
+    CONST64(0x81e667a9b6284f1f), CONST64(0x28220a1e4e363c50), CONST64(0x014647c9cbc88f02), CONST64(0xef1df20bc8e416c3),
+    CONST64(0xee5bb5c2032c99c1), CONST64(0x88aa22666beecc0d), CONST64(0xb356e5324981647b), CONST64(0x9f71ee2f0cb05e23),
+    CONST64(0xc27cbedf461da399), CONST64(0xac872b7d38d1fa45), CONST64(0x3ebf819ee2a0217c), CONST64(0x485a1236a67e6c90),
+    CONST64(0x36b58398f4ae2d6c), CONST64(0x6c771b2df5415ad8), CONST64(0x38360e12622a2470), CONST64(0x8caf236560e9ca05),
+    CONST64(0xf306f502f9f104fb), CONST64(0x094c45cfddc68312), CONST64(0x84a5216376e7c615), CONST64(0x1fd1ce4f71509e3e),
+    CONST64(0x397049dba9e2ab72), CONST64(0xb09c2c7409c4e87d), CONST64(0xc33af9168dd52c9b), CONST64(0xbf59e63754886e63),
+    CONST64(0xe254b6c71e2593d9), CONST64(0xa088287825d8f05d), CONST64(0x5c4b1739816572b8), CONST64(0x32b0829bffa92b64),
+    CONST64(0x68721a2efe465cd0), CONST64(0x169d8b80ac961d2c), CONST64(0xdf21fe1fbcc03ea3), CONST64(0x12988a83a7911b24),
+    CONST64(0x242d091b533f3648), CONST64(0x03cac94640458c06), CONST64(0x26a18794d8b2354c), CONST64(0x256b4ed298f7b94a),
+    CONST64(0xa342e13e659d7c5b), CONST64(0xb8962e721fcae46d), CONST64(0xb753e43142866273), CONST64(0xa747e03d6e9a7a53),
+    CONST64(0x8b60eb202bab400b), CONST64(0x7aea90ad59d747f4), CONST64(0xaa0ea4f1b85bff49), CONST64(0x78661e22d25a44f0),
+    CONST64(0x2eab8592cebc395c), CONST64(0x9dfd60a0873d5d27), CONST64(0x0000000000000000), CONST64(0x94b1256f5afbde35),
+    CONST64(0xf703f401f2f602f3), CONST64(0xe312f10ed5ed1cdb), CONST64(0x6afe94a175cb5fd4), CONST64(0x2c270b1d45313a58),
+    CONST64(0xbb5ce7345f8f686b), CONST64(0xc9bc759f1056238f), CONST64(0x9b74ef2c07b7582b), CONST64(0xd0e4345ce18cb8bd),
+    CONST64(0xc4f53153c697a695), CONST64(0x77a3d4618f16c2ee), CONST64(0x67b7d06da30adace), CONST64(0x22a48697d3b53344),
+    CONST64(0xe59b7e82556719d7), CONST64(0x8e23adeaeb64c901), CONST64(0xd32efd1aa1c934bb), CONST64(0xa48d297b2edff655),
+    CONST64(0xc0f03050cd90a09d), CONST64(0xecd73b4d88a19ac5), CONST64(0x46d99fbc30fa658c), CONST64(0xc73ff81586d22a93),
+    CONST64(0x3ff9c6572968ae7e), CONST64(0x4c5f1335ad796a98), CONST64(0x181e060a3a121430), CONST64(0x1411050f271b1e28),
+    CONST64(0x33f6c5523461a466), CONST64(0x44551133bb776688), CONST64(0xc1b6779906582f9f), CONST64(0xed917c84436915c7),
+    CONST64(0xf58f7a8e797b01f7), CONST64(0xfd8578886f750de7), CONST64(0xd8ee365af782b4ad), CONST64(0x706c1c24c45448e0),
+    CONST64(0xe4dd394b9eaf96d5), CONST64(0x792059eb1992cbf2), CONST64(0x60781828e84850c0), CONST64(0x451356fa70bfe98a),
+    CONST64(0xf645b3c8393e8df1), CONST64(0xfa4ab0cd243787e9), CONST64(0x90b4246c51fcd83d), CONST64(0x80a020607de0c01d),
+    CONST64(0xf240b2cb32398bf9), CONST64(0x72e092ab4fd94be4), CONST64(0xb615a3f8894eed71), CONST64(0x27e7c05d137aba4e),
+    CONST64(0x0d4944ccd6c1851a), CONST64(0x95f762a691335137), CONST64(0x40501030b0706080), CONST64(0xea5eb4c1082b9fc9),
+    CONST64(0x2aae8491c5bb3f54), CONST64(0x115243c5e7d49722), CONST64(0x76e593a844de4dec), CONST64(0x2fedc25b0574b65e),
+    CONST64(0x357f4adeb4eba16a), CONST64(0xce73bdda5b14a981), CONST64(0x06898f8c808a050c), CONST64(0xb4992d7702c3ee75),
+    CONST64(0xca76bcd95013af89), CONST64(0x4ad69cb92df36f94), CONST64(0xb5df6abec90b6177), CONST64(0x1d5d40c0fadd9d3a),
+    CONST64(0x1bd4cf4c7a579836), CONST64(0xb210a2fb8249eb79), CONST64(0x3aba809de9a72774), CONST64(0x216e4fd193f0bf42),
+    CONST64(0x7c631f21d95d42f8), CONST64(0x0fc5ca435d4c861e), CONST64(0x9238aae3da71db39), CONST64(0x155742c6ecd3912a),
+};
+
+static const ulong64 T3[256] = {
+    CONST64(0x68d2d3ba016ab9bb), CONST64(0x194dfc54b1669ae5), CONST64(0x93bc712fcd1465e2), CONST64(0xb9cd9c74511b8725),
+    CONST64(0x0251f553a457a2f7), CONST64(0xb86b68d303bed6d0), CONST64(0xbd6f6bd204b5ded6), CONST64(0x6429d74dfe8552b3),
+    CONST64(0x0d5df050ad4abafd), CONST64(0x268ae9ac63e009cf), CONST64(0x830e8a8d84961c09), CONST64(0x79c6dcbf1a4d91a5),
+    CONST64(0xaddd90704d37a73d), CONST64(0x0755f652a35caaf1), CONST64(0xc852b39ae117a47b), CONST64(0x612dd44cf98e5ab5),
+    CONST64(0x658f23eaac200346), CONST64(0xa67362d51184e6c4), CONST64(0xf166a497c268cc55), CONST64(0xb2636ed10da8c6dc),
+    CONST64(0xffcc553399d085aa), CONST64(0x0859f351aa41b2fb), CONST64(0x2a71ed5b9c0fe2c7), CONST64(0x04a2f7a655ae59f3),
+    CONST64(0x815f7fde20c1befe), CONST64(0x753dd848e5a27aad), CONST64(0x329ae5a87fcc29d7), CONST64(0xc75eb699e80abc71),
+    CONST64(0x904b70db3be696e0), CONST64(0xfac856329edb8dac), CONST64(0x51e6c4b72215d195), CONST64(0x2bd719fcceaab332),
+    CONST64(0x48ab38e393734b70), CONST64(0xdc42bf9efd3b8463), CONST64(0xef7eae91d052fc41), CONST64(0xcd56b09be61cac7d),
+    CONST64(0x4daf3be294784376), CONST64(0x6dd6d0bb0661b1bd), CONST64(0x5819c341daf1329b), CONST64(0xcba5b26e17e55779),
+    CONST64(0x0baef2a55cb341f9), CONST64(0xc00b40cb4b561680), CONST64(0xdab1bd6b0cc27f67), CONST64(0xfb6ea295cc7edc59),
+    CONST64(0x1fbefea1409f61e1), CONST64(0x18eb08f3e3c3cb10), CONST64(0x4ffeceb1302fe181), CONST64(0x0a0806020e16100c),
+    CONST64(0xdb1749cc5e672e92), CONST64(0xf33751c4663f6ea2), CONST64(0x6974271d53cfe84e), CONST64(0x44503c146c9ca078),
+    CONST64(0xe82b58c3730e56b0), CONST64(0xf291a563349a3f57), CONST64(0x954f73da3ced9ee6), CONST64(0x3469e75d8e35d2d3),
+    CONST64(0x3e61e15f8023c2df), CONST64(0x8b5779dc2ed7aef2), CONST64(0x94e9877d6e48cf13), CONST64(0xde134acd596c2694),
+    CONST64(0x9ee1817f605edf1f), CONST64(0x2f75ee5a9b04eac1), CONST64(0xc1adb46c19f34775), CONST64(0x316de45c893edad5),
+    CONST64(0x0cfb04f7ffefeb08), CONST64(0xbe986a26f2472dd4), CONST64(0x24db1cffc7b7ab38), CONST64(0x7e932aedb9113b54),
+    CONST64(0x6f8725e8a236134a), CONST64(0xd34eba9df4269c69), CONST64(0xcea1b16f10ee5f7f), CONST64(0x8c028f8e8d8b0403),
+    CONST64(0x7d642b194fe3c856), CONST64(0x1abafda0479469e7), CONST64(0x17e70df0eaded31a), CONST64(0x971e868998ba3c11),
+    CONST64(0x333c110f2d697822), CONST64(0x1b1c090715313812), CONST64(0x2986ecaf6afd11c5), CONST64(0x30cb10fbdb9b8b20),
+    CONST64(0x2820180838584030), CONST64(0x41543f156b97a87e), CONST64(0x3934170d237f682e), CONST64(0x14100c041c2c2018),
+    CONST64(0x05040301070b0806), CONST64(0xe98dac6421ab0745), CONST64(0x845b7cdf27cab6f8), CONST64(0xb3c59a765f0d9729),
+    CONST64(0x80f98b797264ef0b), CONST64(0x8e537add29dca6f4), CONST64(0xc9f4473db3b2f58e), CONST64(0x4e583a16628ab074),
+    CONST64(0xc3fc413fbda4e582), CONST64(0xebdc593785fca5b2), CONST64(0xc4a9b76d1ef84f73), CONST64(0xd8e04838a895dd90),
+    CONST64(0x67ded6b90877a1b1), CONST64(0xa2d19573442abf37), CONST64(0x6a8326e9a53d1b4c), CONST64(0xe1d45f358beab5be),
+    CONST64(0x1c49ff55b66d92e3), CONST64(0xa8d993714a3caf3b), CONST64(0x8af18d7b7c72ff07), CONST64(0x860a898c839d140f),
+    CONST64(0xa7d596724321b731), CONST64(0x921a85889fb13417), CONST64(0x09ff07f6f8e4e30e), CONST64(0x82a87e2ad6334dfc),
+    CONST64(0xc6f8423ebaafed84), CONST64(0x3b65e25e8728cad9), CONST64(0xbb9c6927f54c25d2), CONST64(0x4305ca46cfc00a89),
+    CONST64(0x3c30140c24746028), CONST64(0xec89af6526a00f43), CONST64(0xd5bdb86805df676d), CONST64(0xf899a3613a8c2f5b),
+    CONST64(0x0f0c0503091d180a), CONST64(0xe2235ec17d1846bc), CONST64(0x1641f957b87b82ef), CONST64(0xa97f67d61899fece),
+    CONST64(0x9a4376d935f086ec), CONST64(0x257de8589512facd), CONST64(0x9f4775d832fb8eea), CONST64(0xe385aa662fbd1749),
+    CONST64(0xac7b64d71f92f6c8), CONST64(0xd2e84e3aa683cd9c), CONST64(0xcf0745c8424b0e8a), CONST64(0xccf0443cb4b9fd88),
+    CONST64(0x35cf13fadc908326), CONST64(0xf462a796c563c453), CONST64(0x01a6f4a752a551f5), CONST64(0xc25ab598ef01b477),
+    CONST64(0x7b9729ecbe1a3352), CONST64(0x62dad5b80f7ca9b7), CONST64(0xfc3b54c76f2276a8), CONST64(0x2c82efae6df619c3),
+    CONST64(0xd0b9bb6902d46f6b), CONST64(0x7a31dd4becbf62a7), CONST64(0x3d96e0ab76d131dd), CONST64(0x379ee6a978c721d1),
+    CONST64(0xe681a96728b61f4f), CONST64(0x22281e0a364e503c), CONST64(0x4601c947c8cb028f), CONST64(0x1def0bf2e4c8c316),
+    CONST64(0x5beec2b52c03c199), CONST64(0xaa886622ee6b0dcc), CONST64(0x56b332e581497b64), CONST64(0x719f2feeb00c235e),
+    CONST64(0x7cc2dfbe1d4699a3), CONST64(0x87ac7d2bd13845fa), CONST64(0xbf3e9e81a0e27c21), CONST64(0x5a4836127ea6906c),
+    CONST64(0xb5369883aef46c2d), CONST64(0x776c2d1b41f5d85a), CONST64(0x3638120e2a627024), CONST64(0xaf8c6523e96005ca),
+    CONST64(0x06f302f5f1f9fb04), CONST64(0x4c09cf45c6dd1283), CONST64(0xa5846321e77615c6), CONST64(0xd11f4fce50713e9e),
+    CONST64(0x7039db49e2a972ab), CONST64(0x9cb0742cc4097de8), CONST64(0x3ac316f9d58d9b2c), CONST64(0x59bf37e68854636e),
+    CONST64(0x54e2c7b6251ed993), CONST64(0x88a07828d8255df0), CONST64(0x4b5c39176581b872), CONST64(0xb0329b82a9ff642b),
+    CONST64(0x72682e1a46fed05c), CONST64(0x9d16808b96ac2c1d), CONST64(0x21df1ffec0bca33e), CONST64(0x9812838a91a7241b),
+    CONST64(0x2d241b093f534836), CONST64(0xca0346c94540068c), CONST64(0xa1269487b2d84c35), CONST64(0x6b25d24ef7984ab9),
+    CONST64(0x42a33ee19d655b7c), CONST64(0x96b8722eca1f6de4), CONST64(0x53b731e486427362), CONST64(0x47a73de09a6e537a),
+    CONST64(0x608b20ebab2b0b40), CONST64(0xea7aad90d759f447), CONST64(0x0eaaf1a45bb849ff), CONST64(0x6678221e5ad2f044),
+    CONST64(0xab2e9285bcce5c39), CONST64(0xfd9da0603d87275d), CONST64(0x0000000000000000), CONST64(0xb1946f25fb5a35de),
+    CONST64(0x03f701f4f6f2f302), CONST64(0x12e30ef1edd5db1c), CONST64(0xfe6aa194cb75d45f), CONST64(0x272c1d0b3145583a),
+    CONST64(0x5cbb34e78f5f6b68), CONST64(0xbcc99f7556108f23), CONST64(0x749b2cefb7072b58), CONST64(0xe4d05c348ce1bdb8),
+    CONST64(0xf5c4533197c695a6), CONST64(0xa37761d4168feec2), CONST64(0xb7676dd00aa3ceda), CONST64(0xa4229786b5d34433),
+    CONST64(0x9be5827e6755d719), CONST64(0x238eeaad64eb01c9), CONST64(0x2ed31afdc9a1bb34), CONST64(0x8da47b29df2e55f6),
+    CONST64(0xf0c0503090cd9da0), CONST64(0xd7ec4d3ba188c59a), CONST64(0xd946bc9ffa308c65), CONST64(0x3fc715f8d286932a),
+    CONST64(0xf93f57c668297eae), CONST64(0x5f4c351379ad986a), CONST64(0x1e180a06123a3014), CONST64(0x11140f051b27281e),
+    CONST64(0xf63352c5613466a4), CONST64(0x5544331177bb8866), CONST64(0xb6c1997758069f2f), CONST64(0x91ed847c6943c715),
+    CONST64(0x8ff58e7a7b79f701), CONST64(0x85fd8878756fe70d), CONST64(0xeed85a3682f7adb4), CONST64(0x6c70241c54c4e048),
+    CONST64(0xdde44b39af9ed596), CONST64(0x2079eb599219f2cb), CONST64(0x7860281848e8c050), CONST64(0x1345fa56bf708ae9),
+    CONST64(0x45f6c8b33e39f18d), CONST64(0x4afacdb03724e987), CONST64(0xb4906c24fc513dd8), CONST64(0xa0806020e07d1dc0),
+    CONST64(0x40f2cbb23932f98b), CONST64(0xe072ab92d94fe44b), CONST64(0x15b6f8a34e8971ed), CONST64(0xe7275dc07a134eba),
+    CONST64(0x490dcc44c1d61a85), CONST64(0xf795a66233913751), CONST64(0x5040301070b08060), CONST64(0x5eeac1b42b08c99f),
+    CONST64(0xae2a9184bbc5543f), CONST64(0x5211c543d4e72297), CONST64(0xe576a893de44ec4d), CONST64(0xed2f5bc274055eb6),
+    CONST64(0x7f35de4aebb46aa1), CONST64(0x73cedabd145b81a9), CONST64(0x89068c8f8a800c05), CONST64(0x99b4772dc30275ee),
+    CONST64(0x76cad9bc135089af), CONST64(0xd64ab99cf32d946f), CONST64(0xdfb5be6a0bc97761), CONST64(0x5d1dc040ddfa3a9d),
+    CONST64(0xd41b4ccf577a3698), CONST64(0x10b2fba2498279eb), CONST64(0xba3a9d80a7e97427), CONST64(0x6e21d14ff09342bf),
+    CONST64(0x637c211f5dd9f842), CONST64(0xc50f43ca4c5d1e86), CONST64(0x3892e3aa71da39db), CONST64(0x5715c642d3ec2a91),
+};
+
+static const ulong64 T4[256] = {
+    CONST64(0xbbb96a01bad3d268), CONST64(0xe59a66b154fc4d19), CONST64(0xe26514cd2f71bc93), CONST64(0x25871b51749ccdb9),
+    CONST64(0xf7a257a453f55102), CONST64(0xd0d6be03d3686bb8), CONST64(0xd6deb504d26b6fbd), CONST64(0xb35285fe4dd72964),
+    CONST64(0xfdba4aad50f05d0d), CONST64(0xcf09e063ace98a26), CONST64(0x091c96848d8a0e83), CONST64(0xa5914d1abfdcc679),
+    CONST64(0x3da7374d7090ddad), CONST64(0xf1aa5ca352f65507), CONST64(0x7ba417e19ab352c8), CONST64(0xb55a8ef94cd42d61),
+    CONST64(0x460320acea238f65), CONST64(0xc4e68411d56273a6), CONST64(0x55cc68c297a466f1), CONST64(0xdcc6a80dd16e63b2),
+    CONST64(0xaa85d0993355ccff), CONST64(0xfbb241aa51f35908), CONST64(0xc7e20f9c5bed712a), CONST64(0xf359ae55a6f7a204),
+    CONST64(0xfebec120de7f5f81), CONST64(0xad7aa2e548d83d75), CONST64(0xd729cc7fa8e59a32), CONST64(0x71bc0ae899b65ec7),
+    CONST64(0xe096e63bdb704b90), CONST64(0xac8ddb9e3256c8fa), CONST64(0x95d11522b7c4e651), CONST64(0x32b3aacefc19d72b),
+    CONST64(0x704b7393e338ab48), CONST64(0x63843bfd9ebf42dc), CONST64(0x41fc52d091ae7eef), CONST64(0x7dac1ce69bb056cd),
+    CONST64(0x76437894e23baf4d), CONST64(0xbdb16106bbd0d66d), CONST64(0x9b32f1da41c31958), CONST64(0x7957e5176eb2a5cb),
+    CONST64(0xf941b35ca5f2ae0b), CONST64(0x8016564bcb400bc0), CONST64(0x677fc20c6bbdb1da), CONST64(0x59dc7ecc95a26efb),
+    CONST64(0xe1619f40a1febe1f), CONST64(0x10cbc3e3f308eb18), CONST64(0x81e12f30b1cefe4f), CONST64(0x0c10160e0206080a),
+    CONST64(0x922e675ecc4917db), CONST64(0xa26e3f66c45137f3), CONST64(0x4ee8cf531d277469), CONST64(0x78a09c6c143c5044),
+    CONST64(0xb0560e73c3582be8), CONST64(0x573f9a3463a591f2), CONST64(0xe69eed3cda734f95), CONST64(0xd3d2358e5de76934),
+    CONST64(0xdfc223805fe1613e), CONST64(0xf2aed72edc79578b), CONST64(0x13cf486e7d87e994), CONST64(0x94266c59cd4a13de),
+    CONST64(0x1fdf5e607f81e19e), CONST64(0xc1ea049b5aee752f), CONST64(0x7547f3196cb4adc1), CONST64(0xd5da3e895ce46d31),
+    CONST64(0x08ebeffff704fb0c), CONST64(0xd42d47f2266a98be), CONST64(0x38abb7c7ff1cdb24), CONST64(0x543b11b9ed2a937e),
+    CONST64(0x4a1336a2e825876f), CONST64(0x699c26f49dba4ed3), CONST64(0x7f5fee106fb1a1ce), CONST64(0x03048b8d8e8f028c),
+    CONST64(0x56c8e34f192b647d), CONST64(0xe7699447a0fdba1a), CONST64(0x1ad3deeaf00de717), CONST64(0x113cba9889861e97),
+    CONST64(0x2278692d0f113c33), CONST64(0x1238311507091c1b), CONST64(0xc511fd6aafec8629), CONST64(0x208b9bdbfb10cb30),
+    CONST64(0x3040583808182028), CONST64(0x7ea8976b153f5441), CONST64(0x2e687f230d173439), CONST64(0x18202c1c040c1014),
+    CONST64(0x06080b0701030405), CONST64(0x4507ab2164ac8de9), CONST64(0xf8b6ca27df7c5b84), CONST64(0x29970d5f769ac5b3),
+    CONST64(0x0bef6472798bf980), CONST64(0xf4a6dc29dd7a538e), CONST64(0x8ef5b2b33d47f4c9), CONST64(0x74b08a62163a584e),
+    CONST64(0x82e5a4bd3f41fcc3), CONST64(0xb2a5fc853759dceb), CONST64(0x734ff81e6db7a9c4), CONST64(0x90dd95a83848e0d8),
+    CONST64(0xb1a17708b9d6de67), CONST64(0x37bf2a447395d1a2), CONST64(0x4c1b3da5e926836a), CONST64(0xbeb5ea8b355fd4e1),
+    CONST64(0xe3926db655ff491c), CONST64(0x3baf3c4a7193d9a8), CONST64(0x07ff727c7b8df18a), CONST64(0x0f149d838c890a86),
+    CONST64(0x31b721437296d5a7), CONST64(0x1734b19f88851a92), CONST64(0x0ee3e4f8f607ff09), CONST64(0xfc4d33d62a7ea882),
+    CONST64(0x84edafba3e42f8c6), CONST64(0xd9ca28875ee2653b), CONST64(0xd2254cf527699cbb), CONST64(0x890ac0cf46ca0543),
+    CONST64(0x286074240c14303c), CONST64(0x430fa02665af89ec), CONST64(0x6d67df0568b8bdd5), CONST64(0x5b2f8c3a61a399f8),
+    CONST64(0x0a181d0903050c0f), CONST64(0xbc46187dc15e23e2), CONST64(0xef827bb857f94116), CONST64(0xcefe9918d6677fa9),
+    CONST64(0xec86f035d976439a), CONST64(0xcdfa129558e87d25), CONST64(0xea8efb32d875479f), CONST64(0x4917bd2f66aa85e3),
+    CONST64(0xc8f6921fd7647bac), CONST64(0x9ccd83a63a4ee8d2), CONST64(0x8a0e4b42c84507cf), CONST64(0x88fdb9b43c44f0cc),
+    CONST64(0x268390dcfa13cf35), CONST64(0x53c463c596a762f4), CONST64(0xf551a552a7f4a601), CONST64(0x77b401ef98b55ac2),
+    CONST64(0x52331abeec29977b), CONST64(0xb7a97c0fb8d5da62), CONST64(0xa876226fc7543bfc), CONST64(0xc319f66daeef822c),
+    CONST64(0x6b6fd40269bbb9d0), CONST64(0xa762bfec4bdd317a), CONST64(0xdd31d176abe0963d), CONST64(0xd121c778a9e69e37),
+    CONST64(0x4f1fb62867a981e6), CONST64(0x3c504e360a1e2822), CONST64(0x8f02cbc847c90146), CONST64(0x16c3c8e4f20bef1d),
+    CONST64(0x99c1032cb5c2ee5b), CONST64(0xcc0d6bee226688aa), CONST64(0x647b4981e532b356), CONST64(0x5e230cb0ee2f9f71),
+    CONST64(0xa399461dbedfc27c), CONST64(0xfa4538d12b7dac87), CONST64(0x217ce2a0819e3ebf), CONST64(0x6c90a67e1236485a),
+    CONST64(0x2d6cf4ae839836b5), CONST64(0x5ad8f5411b2d6c77), CONST64(0x2470622a0e123836), CONST64(0xca0560e923658caf),
+    CONST64(0x04fbf9f1f502f306), CONST64(0x8312ddc645cf094c), CONST64(0xc61576e7216384a5), CONST64(0x9e3e7150ce4f1fd1),
+    CONST64(0xab72a9e249db3970), CONST64(0xe87d09c42c74b09c), CONST64(0x2c9b8dd5f916c33a), CONST64(0x6e635488e637bf59),
+    CONST64(0x93d91e25b6c7e254), CONST64(0xf05d25d82878a088), CONST64(0x72b8816517395c4b), CONST64(0x2b64ffa9829b32b0),
+    CONST64(0x5cd0fe461a2e6872), CONST64(0x1d2cac968b80169d), CONST64(0x3ea3bcc0fe1fdf21), CONST64(0x1b24a7918a831298),
+    CONST64(0x3648533f091b242d), CONST64(0x8c064045c94603ca), CONST64(0x354cd8b2879426a1), CONST64(0xb94a98f74ed2256b),
+    CONST64(0x7c5b659de13ea342), CONST64(0xe46d1fca2e72b896), CONST64(0x62734286e431b753), CONST64(0x7a536e9ae03da747),
+    CONST64(0x400b2babeb208b60), CONST64(0x47f459d790ad7aea), CONST64(0xff49b85ba4f1aa0e), CONST64(0x44f0d25a1e227866),
+    CONST64(0x395ccebc85922eab), CONST64(0x5d27873d60a09dfd), CONST64(0x0000000000000000), CONST64(0xde355afb256f94b1),
+    CONST64(0x02f3f2f6f401f703), CONST64(0x1cdbd5edf10ee312), CONST64(0x5fd475cb94a16afe), CONST64(0x3a5845310b1d2c27),
+    CONST64(0x686b5f8fe734bb5c), CONST64(0x238f1056759fc9bc), CONST64(0x582b07b7ef2c9b74), CONST64(0xb8bde18c345cd0e4),
+    CONST64(0xa695c6973153c4f5), CONST64(0xc2ee8f16d46177a3), CONST64(0xdacea30ad06d67b7), CONST64(0x3344d3b5869722a4),
+    CONST64(0x19d755677e82e59b), CONST64(0xc901eb64adea8e23), CONST64(0x34bba1c9fd1ad32e), CONST64(0xf6552edf297ba48d),
+    CONST64(0xa09dcd903050c0f0), CONST64(0x9ac588a13b4decd7), CONST64(0x658c30fa9fbc46d9), CONST64(0x2a9386d2f815c73f),
+    CONST64(0xae7e2968c6573ff9), CONST64(0x6a98ad7913354c5f), CONST64(0x14303a12060a181e), CONST64(0x1e28271b050f1411),
+    CONST64(0xa4663461c55233f6), CONST64(0x6688bb7711334455), CONST64(0x2f9f06587799c1b6), CONST64(0x15c743697c84ed91),
+    CONST64(0x01f7797b7a8ef58f), CONST64(0x0de76f757888fd85), CONST64(0xb4adf782365ad8ee), CONST64(0x48e0c4541c24706c),
+    CONST64(0x96d59eaf394be4dd), CONST64(0xcbf2199259eb7920), CONST64(0x50c0e84818286078), CONST64(0xe98a70bf56fa4513),
+    CONST64(0x8df1393eb3c8f645), CONST64(0x87e92437b0cdfa4a), CONST64(0xd83d51fc246c90b4), CONST64(0xc01d7de0206080a0),
+    CONST64(0x8bf93239b2cbf240), CONST64(0x4be44fd992ab72e0), CONST64(0xed71894ea3f8b615), CONST64(0xba4e137ac05d27e7),
+    CONST64(0x851ad6c144cc0d49), CONST64(0x5137913362a695f7), CONST64(0x6080b07010304050), CONST64(0x9fc9082bb4c1ea5e),
+    CONST64(0x3f54c5bb84912aae), CONST64(0x9722e7d443c51152), CONST64(0x4dec44de93a876e5), CONST64(0xb65e0574c25b2fed),
+    CONST64(0xa16ab4eb4ade357f), CONST64(0xa9815b14bddace73), CONST64(0x050c808a8f8c0689), CONST64(0xee7502c32d77b499),
+    CONST64(0xaf895013bcd9ca76), CONST64(0x6f942df39cb94ad6), CONST64(0x6177c90b6abeb5df), CONST64(0x9d3afadd40c01d5d),
+    CONST64(0x98367a57cf4c1bd4), CONST64(0xeb798249a2fbb210), CONST64(0x2774e9a7809d3aba), CONST64(0xbf4293f04fd1216e),
+    CONST64(0x42f8d95d1f217c63), CONST64(0x861e5d4cca430fc5), CONST64(0xdb39da71aae39238), CONST64(0x912aecd342c61557),
+};
+
+static const ulong64 T5[256] = {
+    CONST64(0xb9bb016ad3ba68d2), CONST64(0x9ae5b166fc54194d), CONST64(0x65e2cd14712f93bc), CONST64(0x8725511b9c74b9cd),
+    CONST64(0xa2f7a457f5530251), CONST64(0xd6d003be68d3b86b), CONST64(0xded604b56bd2bd6f), CONST64(0x52b3fe85d74d6429),
+    CONST64(0xbafdad4af0500d5d), CONST64(0x09cf63e0e9ac268a), CONST64(0x1c0984968a8d830e), CONST64(0x91a51a4ddcbf79c6),
+    CONST64(0xa73d4d379070addd), CONST64(0xaaf1a35cf6520755), CONST64(0xa47be117b39ac852), CONST64(0x5ab5f98ed44c612d),
+    CONST64(0x0346ac2023ea658f), CONST64(0xe6c4118462d5a673), CONST64(0xcc55c268a497f166), CONST64(0xc6dc0da86ed1b263),
+    CONST64(0x85aa99d05533ffcc), CONST64(0xb2fbaa41f3510859), CONST64(0xe2c79c0fed5b2a71), CONST64(0x59f355aef7a604a2),
+    CONST64(0xbefe20c17fde815f), CONST64(0x7aade5a2d848753d), CONST64(0x29d77fcce5a8329a), CONST64(0xbc71e80ab699c75e),
+    CONST64(0x96e03be670db904b), CONST64(0x8dac9edb5632fac8), CONST64(0xd1952215c4b751e6), CONST64(0xb332ceaa19fc2bd7),
+    CONST64(0x4b70937338e348ab), CONST64(0x8463fd3bbf9edc42), CONST64(0xfc41d052ae91ef7e), CONST64(0xac7de61cb09bcd56),
+    CONST64(0x437694783be24daf), CONST64(0xb1bd0661d0bb6dd6), CONST64(0x329bdaf1c3415819), CONST64(0x577917e5b26ecba5),
+    CONST64(0x41f95cb3f2a50bae), CONST64(0x16804b5640cbc00b), CONST64(0x7f670cc2bd6bdab1), CONST64(0xdc59cc7ea295fb6e),
+    CONST64(0x61e1409ffea11fbe), CONST64(0xcb10e3c308f318eb), CONST64(0xe181302fceb14ffe), CONST64(0x100c0e1606020a08),
+    CONST64(0x2e925e6749ccdb17), CONST64(0x6ea2663f51c4f337), CONST64(0xe84e53cf271d6974), CONST64(0xa0786c9c3c144450),
+    CONST64(0x56b0730e58c3e82b), CONST64(0x3f57349aa563f291), CONST64(0x9ee63ced73da954f), CONST64(0xd2d38e35e75d3469),
+    CONST64(0xc2df8023e15f3e61), CONST64(0xaef22ed779dc8b57), CONST64(0xcf136e48877d94e9), CONST64(0x2694596c4acdde13),
+    CONST64(0xdf1f605e817f9ee1), CONST64(0xeac19b04ee5a2f75), CONST64(0x477519f3b46cc1ad), CONST64(0xdad5893ee45c316d),
+    CONST64(0xeb08ffef04f70cfb), CONST64(0x2dd4f2476a26be98), CONST64(0xab38c7b71cff24db), CONST64(0x3b54b9112aed7e93),
+    CONST64(0x134aa23625e86f87), CONST64(0x9c69f426ba9dd34e), CONST64(0x5f7f10eeb16fcea1), CONST64(0x04038d8b8f8e8c02),
+    CONST64(0xc8564fe32b197d64), CONST64(0x69e74794fda01aba), CONST64(0xd31aeade0df017e7), CONST64(0x3c1198ba8689971e),
+    CONST64(0x78222d69110f333c), CONST64(0x3812153109071b1c), CONST64(0x11c56afdecaf2986), CONST64(0x8b20db9b10fb30cb),
+    CONST64(0x4030385818082820), CONST64(0xa87e6b973f154154), CONST64(0x682e237f170d3934), CONST64(0x20181c2c0c041410),
+    CONST64(0x0806070b03010504), CONST64(0x074521abac64e98d), CONST64(0xb6f827ca7cdf845b), CONST64(0x97295f0d9a76b3c5),
+    CONST64(0xef0b72648b7980f9), CONST64(0xa6f429dc7add8e53), CONST64(0xf58eb3b2473dc9f4), CONST64(0xb074628a3a164e58),
+    CONST64(0xe582bda4413fc3fc), CONST64(0xa5b285fc5937ebdc), CONST64(0x4f731ef8b76dc4a9), CONST64(0xdd90a8954838d8e0),
+    CONST64(0xa1b10877d6b967de), CONST64(0xbf37442a9573a2d1), CONST64(0x1b4ca53d26e96a83), CONST64(0xb5be8bea5f35e1d4),
+    CONST64(0x92e3b66dff551c49), CONST64(0xaf3b4a3c9371a8d9), CONST64(0xff077c728d7b8af1), CONST64(0x140f839d898c860a),
+    CONST64(0xb73143219672a7d5), CONST64(0x34179fb18588921a), CONST64(0xe30ef8e407f609ff), CONST64(0x4dfcd6337e2a82a8),
+    CONST64(0xed84baaf423ec6f8), CONST64(0xcad98728e25e3b65), CONST64(0x25d2f54c6927bb9c), CONST64(0x0a89cfc0ca464305),
+    CONST64(0x60282474140c3c30), CONST64(0x0f4326a0af65ec89), CONST64(0x676d05dfb868d5bd), CONST64(0x2f5b3a8ca361f899),
+    CONST64(0x180a091d05030f0c), CONST64(0x46bc7d185ec1e223), CONST64(0x82efb87bf9571641), CONST64(0xfece189967d6a97f),
+    CONST64(0x86ec35f076d99a43), CONST64(0xfacd9512e858257d), CONST64(0x8eea32fb75d89f47), CONST64(0x17492fbdaa66e385),
+    CONST64(0xf6c81f9264d7ac7b), CONST64(0xcd9ca6834e3ad2e8), CONST64(0x0e8a424b45c8cf07), CONST64(0xfd88b4b9443cccf0),
+    CONST64(0x8326dc9013fa35cf), CONST64(0xc453c563a796f462), CONST64(0x51f552a5f4a701a6), CONST64(0xb477ef01b598c25a),
+    CONST64(0x3352be1a29ec7b97), CONST64(0xa9b70f7cd5b862da), CONST64(0x76a86f2254c7fc3b), CONST64(0x19c36df6efae2c82),
+    CONST64(0x6f6b02d4bb69d0b9), CONST64(0x62a7ecbfdd4b7a31), CONST64(0x31dd76d1e0ab3d96), CONST64(0x21d178c7e6a9379e),
+    CONST64(0x1f4f28b6a967e681), CONST64(0x503c364e1e0a2228), CONST64(0x028fc8cbc9474601), CONST64(0xc316e4c80bf21def),
+    CONST64(0xc1992c03c2b55bee), CONST64(0x0dccee6b6622aa88), CONST64(0x7b64814932e556b3), CONST64(0x235eb00c2fee719f),
+    CONST64(0x99a31d46dfbe7cc2), CONST64(0x45fad1387d2b87ac), CONST64(0x7c21a0e29e81bf3e), CONST64(0x906c7ea636125a48),
+    CONST64(0x6c2daef49883b536), CONST64(0xd85a41f52d1b776c), CONST64(0x70242a62120e3638), CONST64(0x05cae9606523af8c),
+    CONST64(0xfb04f1f902f506f3), CONST64(0x1283c6ddcf454c09), CONST64(0x15c6e7766321a584), CONST64(0x3e9e50714fced11f),
+    CONST64(0x72abe2a9db497039), CONST64(0x7de8c409742c9cb0), CONST64(0x9b2cd58d16f93ac3), CONST64(0x636e885437e659bf),
+    CONST64(0xd993251ec7b654e2), CONST64(0x5df0d825782888a0), CONST64(0xb872658139174b5c), CONST64(0x642ba9ff9b82b032),
+    CONST64(0xd05c46fe2e1a7268), CONST64(0x2c1d96ac808b9d16), CONST64(0xa33ec0bc1ffe21df), CONST64(0x241b91a7838a9812),
+    CONST64(0x48363f531b092d24), CONST64(0x068c454046c9ca03), CONST64(0x4c35b2d89487a126), CONST64(0x4ab9f798d24e6b25),
+    CONST64(0x5b7c9d653ee142a3), CONST64(0x6de4ca1f722e96b8), CONST64(0x7362864231e453b7), CONST64(0x537a9a6e3de047a7),
+    CONST64(0x0b40ab2b20eb608b), CONST64(0xf447d759ad90ea7a), CONST64(0x49ff5bb8f1a40eaa), CONST64(0xf0445ad2221e6678),
+    CONST64(0x5c39bcce9285ab2e), CONST64(0x275d3d87a060fd9d), CONST64(0x0000000000000000), CONST64(0x35defb5a6f25b194),
+    CONST64(0xf302f6f201f403f7), CONST64(0xdb1cedd50ef112e3), CONST64(0xd45fcb75a194fe6a), CONST64(0x583a31451d0b272c),
+    CONST64(0x6b688f5f34e75cbb), CONST64(0x8f2356109f75bcc9), CONST64(0x2b58b7072cef749b), CONST64(0xbdb88ce15c34e4d0),
+    CONST64(0x95a697c65331f5c4), CONST64(0xeec2168f61d4a377), CONST64(0xceda0aa36dd0b767), CONST64(0x4433b5d39786a422),
+    CONST64(0xd7196755827e9be5), CONST64(0x01c964ebeaad238e), CONST64(0xbb34c9a11afd2ed3), CONST64(0x55f6df2e7b298da4),
+    CONST64(0x9da090cd5030f0c0), CONST64(0xc59aa1884d3bd7ec), CONST64(0x8c65fa30bc9fd946), CONST64(0x932ad28615f83fc7),
+    CONST64(0x7eae682957c6f93f), CONST64(0x986a79ad35135f4c), CONST64(0x3014123a0a061e18), CONST64(0x281e1b270f051114),
+    CONST64(0x66a4613452c5f633), CONST64(0x886677bb33115544), CONST64(0x9f2f58069977b6c1), CONST64(0xc7156943847c91ed),
+    CONST64(0xf7017b798e7a8ff5), CONST64(0xe70d756f887885fd), CONST64(0xadb482f75a36eed8), CONST64(0xe04854c4241c6c70),
+    CONST64(0xd596af9e4b39dde4), CONST64(0xf2cb9219eb592079), CONST64(0xc05048e828187860), CONST64(0x8ae9bf70fa561345),
+    CONST64(0xf18d3e39c8b345f6), CONST64(0xe9873724cdb04afa), CONST64(0x3dd8fc516c24b490), CONST64(0x1dc0e07d6020a080),
+    CONST64(0xf98b3932cbb240f2), CONST64(0xe44bd94fab92e072), CONST64(0x71ed4e89f8a315b6), CONST64(0x4eba7a135dc0e727),
+    CONST64(0x1a85c1d6cc44490d), CONST64(0x37513391a662f795), CONST64(0x806070b030105040), CONST64(0xc99f2b08c1b45eea),
+    CONST64(0x543fbbc59184ae2a), CONST64(0x2297d4e7c5435211), CONST64(0xec4dde44a893e576), CONST64(0x5eb674055bc2ed2f),
+    CONST64(0x6aa1ebb4de4a7f35), CONST64(0x81a9145bdabd73ce), CONST64(0x0c058a808c8f8906), CONST64(0x75eec302772d99b4),
+    CONST64(0x89af1350d9bc76ca), CONST64(0x946ff32db99cd64a), CONST64(0x77610bc9be6adfb5), CONST64(0x3a9dddfac0405d1d),
+    CONST64(0x3698577a4ccfd41b), CONST64(0x79eb4982fba210b2), CONST64(0x7427a7e99d80ba3a), CONST64(0x42bff093d14f6e21),
+    CONST64(0xf8425dd9211f637c), CONST64(0x1e864c5d43cac50f), CONST64(0x39db71dae3aa3892), CONST64(0x2a91d3ecc6425715),
+};
+
+static const ulong64 T6[256] = {
+    CONST64(0x6a01bbb9d268bad3), CONST64(0x66b1e59a4d1954fc), CONST64(0x14cde265bc932f71), CONST64(0x1b512587cdb9749c),
+    CONST64(0x57a4f7a2510253f5), CONST64(0xbe03d0d66bb8d368), CONST64(0xb504d6de6fbdd26b), CONST64(0x85feb35229644dd7),
+    CONST64(0x4aadfdba5d0d50f0), CONST64(0xe063cf098a26ace9), CONST64(0x9684091c0e838d8a), CONST64(0x4d1aa591c679bfdc),
+    CONST64(0x374d3da7ddad7090), CONST64(0x5ca3f1aa550752f6), CONST64(0x17e17ba452c89ab3), CONST64(0x8ef9b55a2d614cd4),
+    CONST64(0x20ac46038f65ea23), CONST64(0x8411c4e673a6d562), CONST64(0x68c255cc66f197a4), CONST64(0xa80ddcc663b2d16e),
+    CONST64(0xd099aa85ccff3355), CONST64(0x41aafbb2590851f3), CONST64(0x0f9cc7e2712a5bed), CONST64(0xae55f359a204a6f7),
+    CONST64(0xc120febe5f81de7f), CONST64(0xa2e5ad7a3d7548d8), CONST64(0xcc7fd7299a32a8e5), CONST64(0x0ae871bc5ec799b6),
+    CONST64(0xe63be0964b90db70), CONST64(0xdb9eac8dc8fa3256), CONST64(0x152295d1e651b7c4), CONST64(0xaace32b3d72bfc19),
+    CONST64(0x7393704bab48e338), CONST64(0x3bfd638442dc9ebf), CONST64(0x52d041fc7eef91ae), CONST64(0x1ce67dac56cd9bb0),
+    CONST64(0x78947643af4de23b), CONST64(0x6106bdb1d66dbbd0), CONST64(0xf1da9b32195841c3), CONST64(0xe5177957a5cb6eb2),
+    CONST64(0xb35cf941ae0ba5f2), CONST64(0x564b80160bc0cb40), CONST64(0xc20c677fb1da6bbd), CONST64(0x7ecc59dc6efb95a2),
+    CONST64(0x9f40e161be1fa1fe), CONST64(0xc3e310cbeb18f308), CONST64(0x2f3081e1fe4fb1ce), CONST64(0x160e0c10080a0206),
+    CONST64(0x675e922e17dbcc49), CONST64(0x3f66a26e37f3c451), CONST64(0xcf534ee874691d27), CONST64(0x9c6c78a05044143c),
+    CONST64(0x0e73b0562be8c358), CONST64(0x9a34573f91f263a5), CONST64(0xed3ce69e4f95da73), CONST64(0x358ed3d269345de7),
+    CONST64(0x2380dfc2613e5fe1), CONST64(0xd72ef2ae578bdc79), CONST64(0x486e13cfe9947d87), CONST64(0x6c59942613decd4a),
+    CONST64(0x5e601fdfe19e7f81), CONST64(0x049bc1ea752f5aee), CONST64(0xf3197547adc16cb4), CONST64(0x3e89d5da6d315ce4),
+    CONST64(0xefff08ebfb0cf704), CONST64(0x47f2d42d98be266a), CONST64(0xb7c738abdb24ff1c), CONST64(0x11b9543b937eed2a),
+    CONST64(0x36a24a13876fe825), CONST64(0x26f4699c4ed39dba), CONST64(0xee107f5fa1ce6fb1), CONST64(0x8b8d0304028c8e8f),
+    CONST64(0xe34f56c8647d192b), CONST64(0x9447e769ba1aa0fd), CONST64(0xdeea1ad3e717f00d), CONST64(0xba98113c1e978986),
+    CONST64(0x692d22783c330f11), CONST64(0x311512381c1b0709), CONST64(0xfd6ac5118629afec), CONST64(0x9bdb208bcb30fb10),
+    CONST64(0x5838304020280818), CONST64(0x976b7ea85441153f), CONST64(0x7f232e6834390d17), CONST64(0x2c1c18201014040c),
+    CONST64(0x0b07060804050103), CONST64(0xab2145078de964ac), CONST64(0xca27f8b65b84df7c), CONST64(0x0d5f2997c5b3769a),
+    CONST64(0x64720beff980798b), CONST64(0xdc29f4a6538edd7a), CONST64(0xb2b38ef5f4c93d47), CONST64(0x8a6274b0584e163a),
+    CONST64(0xa4bd82e5fcc33f41), CONST64(0xfc85b2a5dceb3759), CONST64(0xf81e734fa9c46db7), CONST64(0x95a890dde0d83848),
+    CONST64(0x7708b1a1de67b9d6), CONST64(0x2a4437bfd1a27395), CONST64(0x3da54c1b836ae926), CONST64(0xea8bbeb5d4e1355f),
+    CONST64(0x6db6e392491c55ff), CONST64(0x3c4a3bafd9a87193), CONST64(0x727c07fff18a7b8d), CONST64(0x9d830f140a868c89),
+    CONST64(0x214331b7d5a77296), CONST64(0xb19f17341a928885), CONST64(0xe4f80ee3ff09f607), CONST64(0x33d6fc4da8822a7e),
+    CONST64(0xafba84edf8c63e42), CONST64(0x2887d9ca653b5ee2), CONST64(0x4cf5d2259cbb2769), CONST64(0xc0cf890a054346ca),
+    CONST64(0x74242860303c0c14), CONST64(0xa026430f89ec65af), CONST64(0xdf056d67bdd568b8), CONST64(0x8c3a5b2f99f861a3),
+    CONST64(0x1d090a180c0f0305), CONST64(0x187dbc4623e2c15e), CONST64(0x7bb8ef82411657f9), CONST64(0x9918cefe7fa9d667),
+    CONST64(0xf035ec86439ad976), CONST64(0x1295cdfa7d2558e8), CONST64(0xfb32ea8e479fd875), CONST64(0xbd2f491785e366aa),
+    CONST64(0x921fc8f67bacd764), CONST64(0x83a69ccde8d23a4e), CONST64(0x4b428a0e07cfc845), CONST64(0xb9b488fdf0cc3c44),
+    CONST64(0x90dc2683cf35fa13), CONST64(0x63c553c462f496a7), CONST64(0xa552f551a601a7f4), CONST64(0x01ef77b45ac298b5),
+    CONST64(0x1abe5233977bec29), CONST64(0x7c0fb7a9da62b8d5), CONST64(0x226fa8763bfcc754), CONST64(0xf66dc319822caeef),
+    CONST64(0xd4026b6fb9d069bb), CONST64(0xbfeca762317a4bdd), CONST64(0xd176dd31963dabe0), CONST64(0xc778d1219e37a9e6),
+    CONST64(0xb6284f1f81e667a9), CONST64(0x4e363c5028220a1e), CONST64(0xcbc88f02014647c9), CONST64(0xc8e416c3ef1df20b),
+    CONST64(0x032c99c1ee5bb5c2), CONST64(0x6beecc0d88aa2266), CONST64(0x4981647bb356e532), CONST64(0x0cb05e239f71ee2f),
+    CONST64(0x461da399c27cbedf), CONST64(0x38d1fa45ac872b7d), CONST64(0xe2a0217c3ebf819e), CONST64(0xa67e6c90485a1236),
+    CONST64(0xf4ae2d6c36b58398), CONST64(0xf5415ad86c771b2d), CONST64(0x622a247038360e12), CONST64(0x60e9ca058caf2365),
+    CONST64(0xf9f104fbf306f502), CONST64(0xddc68312094c45cf), CONST64(0x76e7c61584a52163), CONST64(0x71509e3e1fd1ce4f),
+    CONST64(0xa9e2ab72397049db), CONST64(0x09c4e87db09c2c74), CONST64(0x8dd52c9bc33af916), CONST64(0x54886e63bf59e637),
+    CONST64(0x1e2593d9e254b6c7), CONST64(0x25d8f05da0882878), CONST64(0x816572b85c4b1739), CONST64(0xffa92b6432b0829b),
+    CONST64(0xfe465cd068721a2e), CONST64(0xac961d2c169d8b80), CONST64(0xbcc03ea3df21fe1f), CONST64(0xa7911b2412988a83),
+    CONST64(0x533f3648242d091b), CONST64(0x40458c0603cac946), CONST64(0xd8b2354c26a18794), CONST64(0x98f7b94a256b4ed2),
+    CONST64(0x659d7c5ba342e13e), CONST64(0x1fcae46db8962e72), CONST64(0x42866273b753e431), CONST64(0x6e9a7a53a747e03d),
+    CONST64(0x2bab400b8b60eb20), CONST64(0x59d747f47aea90ad), CONST64(0xb85bff49aa0ea4f1), CONST64(0xd25a44f078661e22),
+    CONST64(0xcebc395c2eab8592), CONST64(0x873d5d279dfd60a0), CONST64(0x0000000000000000), CONST64(0x5afbde3594b1256f),
+    CONST64(0xf2f602f3f703f401), CONST64(0xd5ed1cdbe312f10e), CONST64(0x75cb5fd46afe94a1), CONST64(0x45313a582c270b1d),
+    CONST64(0x5f8f686bbb5ce734), CONST64(0x1056238fc9bc759f), CONST64(0x07b7582b9b74ef2c), CONST64(0xe18cb8bdd0e4345c),
+    CONST64(0xc697a695c4f53153), CONST64(0x8f16c2ee77a3d461), CONST64(0xa30adace67b7d06d), CONST64(0xd3b5334422a48697),
+    CONST64(0x556719d7e59b7e82), CONST64(0xeb64c9018e23adea), CONST64(0xa1c934bbd32efd1a), CONST64(0x2edff655a48d297b),
+    CONST64(0xcd90a09dc0f03050), CONST64(0x88a19ac5ecd73b4d), CONST64(0x30fa658c46d99fbc), CONST64(0x86d22a93c73ff815),
+    CONST64(0x2968ae7e3ff9c657), CONST64(0xad796a984c5f1335), CONST64(0x3a121430181e060a), CONST64(0x271b1e281411050f),
+    CONST64(0x3461a46633f6c552), CONST64(0xbb77668844551133), CONST64(0x06582f9fc1b67799), CONST64(0x436915c7ed917c84),
+    CONST64(0x797b01f7f58f7a8e), CONST64(0x6f750de7fd857888), CONST64(0xf782b4add8ee365a), CONST64(0xc45448e0706c1c24),
+    CONST64(0x9eaf96d5e4dd394b), CONST64(0x1992cbf2792059eb), CONST64(0xe84850c060781828), CONST64(0x70bfe98a451356fa),
+    CONST64(0x393e8df1f645b3c8), CONST64(0x243787e9fa4ab0cd), CONST64(0x51fcd83d90b4246c), CONST64(0x7de0c01d80a02060),
+    CONST64(0x32398bf9f240b2cb), CONST64(0x4fd94be472e092ab), CONST64(0x894eed71b615a3f8), CONST64(0x137aba4e27e7c05d),
+    CONST64(0xd6c1851a0d4944cc), CONST64(0x9133513795f762a6), CONST64(0xb070608040501030), CONST64(0x082b9fc9ea5eb4c1),
+    CONST64(0xc5bb3f542aae8491), CONST64(0xe7d49722115243c5), CONST64(0x44de4dec76e593a8), CONST64(0x0574b65e2fedc25b),
+    CONST64(0xb4eba16a357f4ade), CONST64(0x5b14a981ce73bdda), CONST64(0x808a050c06898f8c), CONST64(0x02c3ee75b4992d77),
+    CONST64(0x5013af89ca76bcd9), CONST64(0x2df36f944ad69cb9), CONST64(0xc90b6177b5df6abe), CONST64(0xfadd9d3a1d5d40c0),
+    CONST64(0x7a5798361bd4cf4c), CONST64(0x8249eb79b210a2fb), CONST64(0xe9a727743aba809d), CONST64(0x93f0bf42216e4fd1),
+    CONST64(0xd95d42f87c631f21), CONST64(0x5d4c861e0fc5ca43), CONST64(0xda71db399238aae3), CONST64(0xecd3912a155742c6),
+};
+
+static const ulong64 T7[256] = {
+    CONST64(0x016ab9bb68d2d3ba), CONST64(0xb1669ae5194dfc54), CONST64(0xcd1465e293bc712f), CONST64(0x511b8725b9cd9c74),
+    CONST64(0xa457a2f70251f553), CONST64(0x03bed6d0b86b68d3), CONST64(0x04b5ded6bd6f6bd2), CONST64(0xfe8552b36429d74d),
+    CONST64(0xad4abafd0d5df050), CONST64(0x63e009cf268ae9ac), CONST64(0x84961c09830e8a8d), CONST64(0x1a4d91a579c6dcbf),
+    CONST64(0x4d37a73daddd9070), CONST64(0xa35caaf10755f652), CONST64(0xe117a47bc852b39a), CONST64(0xf98e5ab5612dd44c),
+    CONST64(0xac200346658f23ea), CONST64(0x1184e6c4a67362d5), CONST64(0xc268cc55f166a497), CONST64(0x0da8c6dcb2636ed1),
+    CONST64(0x99d085aaffcc5533), CONST64(0xaa41b2fb0859f351), CONST64(0x9c0fe2c72a71ed5b), CONST64(0x55ae59f304a2f7a6),
+    CONST64(0x20c1befe815f7fde), CONST64(0xe5a27aad753dd848), CONST64(0x7fcc29d7329ae5a8), CONST64(0xe80abc71c75eb699),
+    CONST64(0x3be696e0904b70db), CONST64(0x9edb8dacfac85632), CONST64(0x2215d19551e6c4b7), CONST64(0xceaab3322bd719fc),
+    CONST64(0x93734b7048ab38e3), CONST64(0xfd3b8463dc42bf9e), CONST64(0xd052fc41ef7eae91), CONST64(0xe61cac7dcd56b09b),
+    CONST64(0x947843764daf3be2), CONST64(0x0661b1bd6dd6d0bb), CONST64(0xdaf1329b5819c341), CONST64(0x17e55779cba5b26e),
+    CONST64(0x5cb341f90baef2a5), CONST64(0x4b561680c00b40cb), CONST64(0x0cc27f67dab1bd6b), CONST64(0xcc7edc59fb6ea295),
+    CONST64(0x409f61e11fbefea1), CONST64(0xe3c3cb1018eb08f3), CONST64(0x302fe1814ffeceb1), CONST64(0x0e16100c0a080602),
+    CONST64(0x5e672e92db1749cc), CONST64(0x663f6ea2f33751c4), CONST64(0x53cfe84e6974271d), CONST64(0x6c9ca07844503c14),
+    CONST64(0x730e56b0e82b58c3), CONST64(0x349a3f57f291a563), CONST64(0x3ced9ee6954f73da), CONST64(0x8e35d2d33469e75d),
+    CONST64(0x8023c2df3e61e15f), CONST64(0x2ed7aef28b5779dc), CONST64(0x6e48cf1394e9877d), CONST64(0x596c2694de134acd),
+    CONST64(0x605edf1f9ee1817f), CONST64(0x9b04eac12f75ee5a), CONST64(0x19f34775c1adb46c), CONST64(0x893edad5316de45c),
+    CONST64(0xffefeb080cfb04f7), CONST64(0xf2472dd4be986a26), CONST64(0xc7b7ab3824db1cff), CONST64(0xb9113b547e932aed),
+    CONST64(0xa236134a6f8725e8), CONST64(0xf4269c69d34eba9d), CONST64(0x10ee5f7fcea1b16f), CONST64(0x8d8b04038c028f8e),
+    CONST64(0x4fe3c8567d642b19), CONST64(0x479469e71abafda0), CONST64(0xeaded31a17e70df0), CONST64(0x98ba3c11971e8689),
+    CONST64(0x2d697822333c110f), CONST64(0x153138121b1c0907), CONST64(0x6afd11c52986ecaf), CONST64(0xdb9b8b2030cb10fb),
+    CONST64(0x3858403028201808), CONST64(0x6b97a87e41543f15), CONST64(0x237f682e3934170d), CONST64(0x1c2c201814100c04),
+    CONST64(0x070b080605040301), CONST64(0x21ab0745e98dac64), CONST64(0x27cab6f8845b7cdf), CONST64(0x5f0d9729b3c59a76),
+    CONST64(0x7264ef0b80f98b79), CONST64(0x29dca6f48e537add), CONST64(0xb3b2f58ec9f4473d), CONST64(0x628ab0744e583a16),
+    CONST64(0xbda4e582c3fc413f), CONST64(0x85fca5b2ebdc5937), CONST64(0x1ef84f73c4a9b76d), CONST64(0xa895dd90d8e04838),
+    CONST64(0x0877a1b167ded6b9), CONST64(0x442abf37a2d19573), CONST64(0xa53d1b4c6a8326e9), CONST64(0x8beab5bee1d45f35),
+    CONST64(0xb66d92e31c49ff55), CONST64(0x4a3caf3ba8d99371), CONST64(0x7c72ff078af18d7b), CONST64(0x839d140f860a898c),
+    CONST64(0x4321b731a7d59672), CONST64(0x9fb13417921a8588), CONST64(0xf8e4e30e09ff07f6), CONST64(0xd6334dfc82a87e2a),
+    CONST64(0xbaafed84c6f8423e), CONST64(0x8728cad93b65e25e), CONST64(0xf54c25d2bb9c6927), CONST64(0xcfc00a894305ca46),
+    CONST64(0x247460283c30140c), CONST64(0x26a00f43ec89af65), CONST64(0x05df676dd5bdb868), CONST64(0x3a8c2f5bf899a361),
+    CONST64(0x091d180a0f0c0503), CONST64(0x7d1846bce2235ec1), CONST64(0xb87b82ef1641f957), CONST64(0x1899fecea97f67d6),
+    CONST64(0x35f086ec9a4376d9), CONST64(0x9512facd257de858), CONST64(0x32fb8eea9f4775d8), CONST64(0x2fbd1749e385aa66),
+    CONST64(0x1f92f6c8ac7b64d7), CONST64(0xa683cd9cd2e84e3a), CONST64(0x424b0e8acf0745c8), CONST64(0xb4b9fd88ccf0443c),
+    CONST64(0xdc90832635cf13fa), CONST64(0xc563c453f462a796), CONST64(0x52a551f501a6f4a7), CONST64(0xef01b477c25ab598),
+    CONST64(0xbe1a33527b9729ec), CONST64(0x0f7ca9b762dad5b8), CONST64(0x6f2276a8fc3b54c7), CONST64(0x6df619c32c82efae),
+    CONST64(0x02d46f6bd0b9bb69), CONST64(0xecbf62a77a31dd4b), CONST64(0x76d131dd3d96e0ab), CONST64(0x78c721d1379ee6a9),
+    CONST64(0x28b61f4fe681a967), CONST64(0x364e503c22281e0a), CONST64(0xc8cb028f4601c947), CONST64(0xe4c8c3161def0bf2),
+    CONST64(0x2c03c1995beec2b5), CONST64(0xee6b0dccaa886622), CONST64(0x81497b6456b332e5), CONST64(0xb00c235e719f2fee),
+    CONST64(0x1d4699a37cc2dfbe), CONST64(0xd13845fa87ac7d2b), CONST64(0xa0e27c21bf3e9e81), CONST64(0x7ea6906c5a483612),
+    CONST64(0xaef46c2db5369883), CONST64(0x41f5d85a776c2d1b), CONST64(0x2a6270243638120e), CONST64(0xe96005caaf8c6523),
+    CONST64(0xf1f9fb0406f302f5), CONST64(0xc6dd12834c09cf45), CONST64(0xe77615c6a5846321), CONST64(0x50713e9ed11f4fce),
+    CONST64(0xe2a972ab7039db49), CONST64(0xc4097de89cb0742c), CONST64(0xd58d9b2c3ac316f9), CONST64(0x8854636e59bf37e6),
+    CONST64(0x251ed99354e2c7b6), CONST64(0xd8255df088a07828), CONST64(0x6581b8724b5c3917), CONST64(0xa9ff642bb0329b82),
+    CONST64(0x46fed05c72682e1a), CONST64(0x96ac2c1d9d16808b), CONST64(0xc0bca33e21df1ffe), CONST64(0x91a7241b9812838a),
+    CONST64(0x3f5348362d241b09), CONST64(0x4540068cca0346c9), CONST64(0xb2d84c35a1269487), CONST64(0xf7984ab96b25d24e),
+    CONST64(0x9d655b7c42a33ee1), CONST64(0xca1f6de496b8722e), CONST64(0x8642736253b731e4), CONST64(0x9a6e537a47a73de0),
+    CONST64(0xab2b0b40608b20eb), CONST64(0xd759f447ea7aad90), CONST64(0x5bb849ff0eaaf1a4), CONST64(0x5ad2f0446678221e),
+    CONST64(0xbcce5c39ab2e9285), CONST64(0x3d87275dfd9da060), CONST64(0x0000000000000000), CONST64(0xfb5a35deb1946f25),
+    CONST64(0xf6f2f30203f701f4), CONST64(0xedd5db1c12e30ef1), CONST64(0xcb75d45ffe6aa194), CONST64(0x3145583a272c1d0b),
+    CONST64(0x8f5f6b685cbb34e7), CONST64(0x56108f23bcc99f75), CONST64(0xb7072b58749b2cef), CONST64(0x8ce1bdb8e4d05c34),
+    CONST64(0x97c695a6f5c45331), CONST64(0x168feec2a37761d4), CONST64(0x0aa3cedab7676dd0), CONST64(0xb5d34433a4229786),
+    CONST64(0x6755d7199be5827e), CONST64(0x64eb01c9238eeaad), CONST64(0xc9a1bb342ed31afd), CONST64(0xdf2e55f68da47b29),
+    CONST64(0x90cd9da0f0c05030), CONST64(0xa188c59ad7ec4d3b), CONST64(0xfa308c65d946bc9f), CONST64(0xd286932a3fc715f8),
+    CONST64(0x68297eaef93f57c6), CONST64(0x79ad986a5f4c3513), CONST64(0x123a30141e180a06), CONST64(0x1b27281e11140f05),
+    CONST64(0x613466a4f63352c5), CONST64(0x77bb886655443311), CONST64(0x58069f2fb6c19977), CONST64(0x6943c71591ed847c),
+    CONST64(0x7b79f7018ff58e7a), CONST64(0x756fe70d85fd8878), CONST64(0x82f7adb4eed85a36), CONST64(0x54c4e0486c70241c),
+    CONST64(0xaf9ed596dde44b39), CONST64(0x9219f2cb2079eb59), CONST64(0x48e8c05078602818), CONST64(0xbf708ae91345fa56),
+    CONST64(0x3e39f18d45f6c8b3), CONST64(0x3724e9874afacdb0), CONST64(0xfc513dd8b4906c24), CONST64(0xe07d1dc0a0806020),
+    CONST64(0x3932f98b40f2cbb2), CONST64(0xd94fe44be072ab92), CONST64(0x4e8971ed15b6f8a3), CONST64(0x7a134ebae7275dc0),
+    CONST64(0xc1d61a85490dcc44), CONST64(0x33913751f795a662), CONST64(0x70b0806050403010), CONST64(0x2b08c99f5eeac1b4),
+    CONST64(0xbbc5543fae2a9184), CONST64(0xd4e722975211c543), CONST64(0xde44ec4de576a893), CONST64(0x74055eb6ed2f5bc2),
+    CONST64(0xebb46aa17f35de4a), CONST64(0x145b81a973cedabd), CONST64(0x8a800c0589068c8f), CONST64(0xc30275ee99b4772d),
+    CONST64(0x135089af76cad9bc), CONST64(0xf32d946fd64ab99c), CONST64(0x0bc97761dfb5be6a), CONST64(0xddfa3a9d5d1dc040),
+    CONST64(0x577a3698d41b4ccf), CONST64(0x498279eb10b2fba2), CONST64(0xa7e97427ba3a9d80), CONST64(0xf09342bf6e21d14f),
+    CONST64(0x5dd9f842637c211f), CONST64(0x4c5d1e86c50f43ca), CONST64(0x71da39db3892e3aa), CONST64(0xd3ec2a915715c642),
+};
+
+static const ulong64 c[R + 1] = {
+    CONST64(0xba542f7453d3d24d),
+    CONST64(0x50ac8dbf70529a4c),
+    CONST64(0xead597d133515ba6),
+    CONST64(0xde48a899db32b7fc),
+    CONST64(0xe39e919be2bb416e),
+    CONST64(0xa5cb6b95a1f3b102),
+    CONST64(0xccc41d14c363da5d),
+    CONST64(0x5fdc7dcd7f5a6c5c),
+    CONST64(0xf726ffede89d6f8e),
+};
+
+ /**
+    Initialize the Khazad block cipher
+    @param key The symmetric key you wish to pass
+    @param keylen The key length in bytes
+    @param num_rounds The number of rounds desired (0 for default)
+    @param skey The key in as scheduled by this function.
+    @return CRYPT_OK if successful
+ */
+int khazad_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey)
+{
+   int               r;
+   const ulong64    *S;
+   ulong64           K2, K1;
+
+   LTC_ARGCHK(key  != NULL);
+   LTC_ARGCHK(skey != NULL);
+   if (keylen != 16) {
+      return CRYPT_INVALID_KEYSIZE;
+   }
+   if (num_rounds != 8 && num_rounds != 0) {
+      return CRYPT_INVALID_ROUNDS;
+   }
+
+   /* use 7th table */
+   S = T7;
+
+    /*
+    * map unsigned char array cipher key to initial key state (mu):
+    */
+   K2 =
+      ((ulong64)key[ 0] << 56) ^
+      ((ulong64)key[ 1] << 48) ^
+      ((ulong64)key[ 2] << 40) ^
+      ((ulong64)key[ 3] << 32) ^
+      ((ulong64)key[ 4] << 24) ^
+      ((ulong64)key[ 5] << 16) ^
+      ((ulong64)key[ 6] <<  8) ^
+      ((ulong64)key[ 7]      );
+   K1 =
+      ((ulong64)key[ 8] << 56) ^
+      ((ulong64)key[ 9] << 48) ^
+      ((ulong64)key[10] << 40) ^
+      ((ulong64)key[11] << 32) ^
+      ((ulong64)key[12] << 24) ^
+      ((ulong64)key[13] << 16) ^
+      ((ulong64)key[14] <<  8) ^
+      ((ulong64)key[15]      );
+
+   /*
+    * compute the round keys:
+    */
+   for (r = 0; r <= R; r++) {
+      /*
+       * K[r] = rho(c[r], K1) ^ K2;
+       */
+      skey->khazad.roundKeyEnc[r] =
+         T0[(int)(K1 >> 56)       ] ^
+         T1[(int)(K1 >> 48) & 0xff] ^
+         T2[(int)(K1 >> 40) & 0xff] ^
+         T3[(int)(K1 >> 32) & 0xff] ^
+         T4[(int)(K1 >> 24) & 0xff] ^
+         T5[(int)(K1 >> 16) & 0xff] ^
+         T6[(int)(K1 >>  8) & 0xff] ^
+         T7[(int)(K1      ) & 0xff] ^
+         c[r] ^ K2;
+      K2 = K1; K1 = skey->khazad.roundKeyEnc[r];
+   }
+   /*
+    * compute the inverse key schedule:
+    * K'^0 = K^R, K'^R = K^0, K'^r = theta(K^{R-r})
+    */
+   skey->khazad.roundKeyDec[0] = skey->khazad.roundKeyEnc[R];
+   for (r = 1; r < R; r++) {
+      K1 = skey->khazad.roundKeyEnc[R - r];
+      skey->khazad.roundKeyDec[r] =
+         T0[(int)S[(int)(K1 >> 56)       ] & 0xff] ^
+         T1[(int)S[(int)(K1 >> 48) & 0xff] & 0xff] ^
+         T2[(int)S[(int)(K1 >> 40) & 0xff] & 0xff] ^
+         T3[(int)S[(int)(K1 >> 32) & 0xff] & 0xff] ^
+         T4[(int)S[(int)(K1 >> 24) & 0xff] & 0xff] ^
+         T5[(int)S[(int)(K1 >> 16) & 0xff] & 0xff] ^
+         T6[(int)S[(int)(K1 >>  8) & 0xff] & 0xff] ^
+         T7[(int)S[(int)(K1      ) & 0xff] & 0xff];
+   }
+   skey->khazad.roundKeyDec[R] = skey->khazad.roundKeyEnc[0];
+
+   return CRYPT_OK;
+}
+
+static void khazad_crypt(const unsigned char *plaintext, unsigned char *ciphertext,
+                         const ulong64       *roundKey) {
+   int     r;
+   ulong64 state;
+    /*
+    * map plaintext block to cipher state (mu)
+    * and add initial round key (sigma[K^0]):
+    */
+   state =
+      ((ulong64)plaintext[0] << 56) ^
+      ((ulong64)plaintext[1] << 48) ^
+      ((ulong64)plaintext[2] << 40) ^
+      ((ulong64)plaintext[3] << 32) ^
+      ((ulong64)plaintext[4] << 24) ^
+      ((ulong64)plaintext[5] << 16) ^
+      ((ulong64)plaintext[6] <<  8) ^
+      ((ulong64)plaintext[7]      ) ^
+      roundKey[0];
+
+    /*
+    * R - 1 full rounds:
+    */
+    for (r = 1; r < R; r++) {
+      state =
+         T0[(int)(state >> 56)       ] ^
+         T1[(int)(state >> 48) & 0xff] ^
+         T2[(int)(state >> 40) & 0xff] ^
+         T3[(int)(state >> 32) & 0xff] ^
+         T4[(int)(state >> 24) & 0xff] ^
+         T5[(int)(state >> 16) & 0xff] ^
+         T6[(int)(state >>  8) & 0xff] ^
+         T7[(int)(state      ) & 0xff] ^
+         roundKey[r];
+    }
+
+    /*
+    * last round:
+    */
+   state =
+      (T0[(int)(state >> 56)       ] & CONST64(0xff00000000000000)) ^
+      (T1[(int)(state >> 48) & 0xff] & CONST64(0x00ff000000000000)) ^
+      (T2[(int)(state >> 40) & 0xff] & CONST64(0x0000ff0000000000)) ^
+      (T3[(int)(state >> 32) & 0xff] & CONST64(0x000000ff00000000)) ^
+      (T4[(int)(state >> 24) & 0xff] & CONST64(0x00000000ff000000)) ^
+      (T5[(int)(state >> 16) & 0xff] & CONST64(0x0000000000ff0000)) ^
+      (T6[(int)(state >>  8) & 0xff] & CONST64(0x000000000000ff00)) ^
+      (T7[(int)(state      ) & 0xff] & CONST64(0x00000000000000ff)) ^
+      roundKey[R];
+
+   /*
+    * map cipher state to ciphertext block (mu^{-1}):
+    */
+   ciphertext[0] = (unsigned char)(state >> 56);
+   ciphertext[1] = (unsigned char)(state >> 48);
+   ciphertext[2] = (unsigned char)(state >> 40);
+   ciphertext[3] = (unsigned char)(state >> 32);
+   ciphertext[4] = (unsigned char)(state >> 24);
+   ciphertext[5] = (unsigned char)(state >> 16);
+   ciphertext[6] = (unsigned char)(state >>  8);
+   ciphertext[7] = (unsigned char)(state      );
+}
+
+/**
+  Encrypts a block of text with Khazad
+  @param pt The input plaintext (8 bytes)
+  @param ct The output ciphertext (8 bytes)
+  @param skey The key as scheduled
+  @return CRYPT_OK if successful
+*/
+int khazad_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey)
+{
+   LTC_ARGCHK(pt   != NULL);
+   LTC_ARGCHK(ct   != NULL);
+   LTC_ARGCHK(skey != NULL);
+   khazad_crypt(pt, ct, skey->khazad.roundKeyEnc);
+   return CRYPT_OK;
+}
+
+/**
+  Decrypts a block of text with Khazad
+  @param ct The input ciphertext (8 bytes)
+  @param pt The output plaintext (8 bytes)
+  @param skey The key as scheduled
+  @return CRYPT_OK if successful
+*/
+int khazad_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey)
+{
+   LTC_ARGCHK(pt   != NULL);
+   LTC_ARGCHK(ct   != NULL);
+   LTC_ARGCHK(skey != NULL);
+   khazad_crypt(ct, pt, skey->khazad.roundKeyDec);
+   return CRYPT_OK;
+}
+
+/**
+  Performs a self-test of the Khazad block cipher
+  @return CRYPT_OK if functional, CRYPT_NOP if self-test has been disabled
+*/
+int khazad_test(void)
+{
+#ifndef LTC_TEST
+  return CRYPT_NOP;
+#else
+  static const struct test {
+     unsigned char pt[8], ct[8], key[16];
+  } tests[] = {
+{
+   { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+   { 0x49, 0xA4, 0xCE, 0x32, 0xAC, 0x19, 0x0E, 0x3F },
+   { 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
+}, {
+   { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+   { 0x64, 0x5D, 0x77, 0x3E, 0x40, 0xAB, 0xDD, 0x53 },
+   { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }
+}, {
+   { 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+   { 0x9E, 0x39, 0x98, 0x64, 0xF7, 0x8E, 0xCA, 0x02 },
+   { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
+}, {
+   { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 },
+   { 0xA9, 0xDF, 0x3D, 0x2C, 0x64, 0xD3, 0xEA, 0x28 },
+   { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
+}
+};
+   int x, y;
+   unsigned char buf[2][8];
+   symmetric_key skey;
+
+   for (x = 0; x < (int)(sizeof(tests)/sizeof(tests[0])); x++) {
+       khazad_setup(tests[x].key, 16, 0, &skey);
+       khazad_ecb_encrypt(tests[x].pt, buf[0], &skey);
+       khazad_ecb_decrypt(buf[0], buf[1], &skey);
+       if (compare_testvector(buf[0], 8, tests[x].ct, 8, "Khazad Encrypt", x) ||
+             compare_testvector(buf[1], 8, tests[x].pt, 8, "Khazad Decrypt", x)) {
+          return CRYPT_FAIL_TESTVECTOR;
+       }
+
+       for (y = 0; y < 1000; y++) khazad_ecb_encrypt(buf[0], buf[0], &skey);
+       for (y = 0; y < 1000; y++) khazad_ecb_decrypt(buf[0], buf[0], &skey);
+       if (compare_testvector(buf[0], 8, tests[x].ct, 8, "Khazad 1000", 1000)) {
+          return CRYPT_FAIL_TESTVECTOR;
+       }
+
+   }
+   return CRYPT_OK;
+#endif
+}
+
+/** Terminate the context
+   @param skey    The scheduled key
+*/
+void khazad_done(symmetric_key *skey)
+{
+  LTC_UNUSED_PARAM(skey);
+}
+
+/**
+  Gets suitable key size
+  @param keysize [in/out] The length of the recommended key (in bytes).  This function will store the suitable size back in this variable.
+  @return CRYPT_OK if the input key size is acceptable.
+*/
+int khazad_keysize(int *keysize)
+{
+   LTC_ARGCHK(keysize != NULL);
+   if (*keysize >= 16) {
+      *keysize = 16;
+      return CRYPT_OK;
+   } else {
+      return CRYPT_INVALID_KEYSIZE;
+   }
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/ciphers/kseed.c b/libtomcrypt/src/ciphers/kseed.c
new file mode 100644 (file)
index 0000000..e12fdc7
--- /dev/null
@@ -0,0 +1,376 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+/**
+  @file kseed.c
+  seed implementation of SEED derived from RFC4269
+  Tom St Denis
+*/
+
+#include "tomcrypt.h"
+
+#ifdef LTC_KSEED
+
+const struct ltc_cipher_descriptor kseed_desc = {
+   "seed",
+   20,
+   16, 16, 16, 16,
+   &kseed_setup,
+   &kseed_ecb_encrypt,
+   &kseed_ecb_decrypt,
+   &kseed_test,
+   &kseed_done,
+   &kseed_keysize,
+   NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
+};
+
+static const ulong32 SS0[256] = {
+0x2989A1A8UL,0x05858184UL,0x16C6D2D4UL,0x13C3D3D0UL,0x14445054UL,0x1D0D111CUL,0x2C8CA0ACUL,0x25052124UL,
+0x1D4D515CUL,0x03434340UL,0x18081018UL,0x1E0E121CUL,0x11415150UL,0x3CCCF0FCUL,0x0ACAC2C8UL,0x23436360UL,
+0x28082028UL,0x04444044UL,0x20002020UL,0x1D8D919CUL,0x20C0E0E0UL,0x22C2E2E0UL,0x08C8C0C8UL,0x17071314UL,
+0x2585A1A4UL,0x0F8F838CUL,0x03030300UL,0x3B4B7378UL,0x3B8BB3B8UL,0x13031310UL,0x12C2D2D0UL,0x2ECEE2ECUL,
+0x30407070UL,0x0C8C808CUL,0x3F0F333CUL,0x2888A0A8UL,0x32023230UL,0x1DCDD1DCUL,0x36C6F2F4UL,0x34447074UL,
+0x2CCCE0ECUL,0x15859194UL,0x0B0B0308UL,0x17475354UL,0x1C4C505CUL,0x1B4B5358UL,0x3D8DB1BCUL,0x01010100UL,
+0x24042024UL,0x1C0C101CUL,0x33437370UL,0x18889098UL,0x10001010UL,0x0CCCC0CCUL,0x32C2F2F0UL,0x19C9D1D8UL,
+0x2C0C202CUL,0x27C7E3E4UL,0x32427270UL,0x03838380UL,0x1B8B9398UL,0x11C1D1D0UL,0x06868284UL,0x09C9C1C8UL,
+0x20406060UL,0x10405050UL,0x2383A3A0UL,0x2BCBE3E8UL,0x0D0D010CUL,0x3686B2B4UL,0x1E8E929CUL,0x0F4F434CUL,
+0x3787B3B4UL,0x1A4A5258UL,0x06C6C2C4UL,0x38487078UL,0x2686A2A4UL,0x12021210UL,0x2F8FA3ACUL,0x15C5D1D4UL,
+0x21416160UL,0x03C3C3C0UL,0x3484B0B4UL,0x01414140UL,0x12425250UL,0x3D4D717CUL,0x0D8D818CUL,0x08080008UL,
+0x1F0F131CUL,0x19899198UL,0x00000000UL,0x19091118UL,0x04040004UL,0x13435350UL,0x37C7F3F4UL,0x21C1E1E0UL,
+0x3DCDF1FCUL,0x36467274UL,0x2F0F232CUL,0x27072324UL,0x3080B0B0UL,0x0B8B8388UL,0x0E0E020CUL,0x2B8BA3A8UL,
+0x2282A2A0UL,0x2E4E626CUL,0x13839390UL,0x0D4D414CUL,0x29496168UL,0x3C4C707CUL,0x09090108UL,0x0A0A0208UL,
+0x3F8FB3BCUL,0x2FCFE3ECUL,0x33C3F3F0UL,0x05C5C1C4UL,0x07878384UL,0x14041014UL,0x3ECEF2FCUL,0x24446064UL,
+0x1ECED2DCUL,0x2E0E222CUL,0x0B4B4348UL,0x1A0A1218UL,0x06060204UL,0x21012120UL,0x2B4B6368UL,0x26466264UL,
+0x02020200UL,0x35C5F1F4UL,0x12829290UL,0x0A8A8288UL,0x0C0C000CUL,0x3383B3B0UL,0x3E4E727CUL,0x10C0D0D0UL,
+0x3A4A7278UL,0x07474344UL,0x16869294UL,0x25C5E1E4UL,0x26062224UL,0x00808080UL,0x2D8DA1ACUL,0x1FCFD3DCUL,
+0x2181A1A0UL,0x30003030UL,0x37073334UL,0x2E8EA2ACUL,0x36063234UL,0x15051114UL,0x22022220UL,0x38083038UL,
+0x34C4F0F4UL,0x2787A3A4UL,0x05454144UL,0x0C4C404CUL,0x01818180UL,0x29C9E1E8UL,0x04848084UL,0x17879394UL,
+0x35053134UL,0x0BCBC3C8UL,0x0ECEC2CCUL,0x3C0C303CUL,0x31417170UL,0x11011110UL,0x07C7C3C4UL,0x09898188UL,
+0x35457174UL,0x3BCBF3F8UL,0x1ACAD2D8UL,0x38C8F0F8UL,0x14849094UL,0x19495158UL,0x02828280UL,0x04C4C0C4UL,
+0x3FCFF3FCUL,0x09494148UL,0x39093138UL,0x27476364UL,0x00C0C0C0UL,0x0FCFC3CCUL,0x17C7D3D4UL,0x3888B0B8UL,
+0x0F0F030CUL,0x0E8E828CUL,0x02424240UL,0x23032320UL,0x11819190UL,0x2C4C606CUL,0x1BCBD3D8UL,0x2484A0A4UL,
+0x34043034UL,0x31C1F1F0UL,0x08484048UL,0x02C2C2C0UL,0x2F4F636CUL,0x3D0D313CUL,0x2D0D212CUL,0x00404040UL,
+0x3E8EB2BCUL,0x3E0E323CUL,0x3C8CB0BCUL,0x01C1C1C0UL,0x2A8AA2A8UL,0x3A8AB2B8UL,0x0E4E424CUL,0x15455154UL,
+0x3B0B3338UL,0x1CCCD0DCUL,0x28486068UL,0x3F4F737CUL,0x1C8C909CUL,0x18C8D0D8UL,0x0A4A4248UL,0x16465254UL,
+0x37477374UL,0x2080A0A0UL,0x2DCDE1ECUL,0x06464244UL,0x3585B1B4UL,0x2B0B2328UL,0x25456164UL,0x3ACAF2F8UL,
+0x23C3E3E0UL,0x3989B1B8UL,0x3181B1B0UL,0x1F8F939CUL,0x1E4E525CUL,0x39C9F1F8UL,0x26C6E2E4UL,0x3282B2B0UL,
+0x31013130UL,0x2ACAE2E8UL,0x2D4D616CUL,0x1F4F535CUL,0x24C4E0E4UL,0x30C0F0F0UL,0x0DCDC1CCUL,0x08888088UL,
+0x16061214UL,0x3A0A3238UL,0x18485058UL,0x14C4D0D4UL,0x22426260UL,0x29092128UL,0x07070304UL,0x33033330UL,
+0x28C8E0E8UL,0x1B0B1318UL,0x05050104UL,0x39497178UL,0x10809090UL,0x2A4A6268UL,0x2A0A2228UL,0x1A8A9298UL
+};
+
+static const ulong32 SS1[256] = {
+0x38380830UL,0xE828C8E0UL,0x2C2D0D21UL,0xA42686A2UL,0xCC0FCFC3UL,0xDC1ECED2UL,0xB03383B3UL,0xB83888B0UL,
+0xAC2F8FA3UL,0x60204060UL,0x54154551UL,0xC407C7C3UL,0x44044440UL,0x6C2F4F63UL,0x682B4B63UL,0x581B4B53UL,
+0xC003C3C3UL,0x60224262UL,0x30330333UL,0xB43585B1UL,0x28290921UL,0xA02080A0UL,0xE022C2E2UL,0xA42787A3UL,
+0xD013C3D3UL,0x90118191UL,0x10110111UL,0x04060602UL,0x1C1C0C10UL,0xBC3C8CB0UL,0x34360632UL,0x480B4B43UL,
+0xEC2FCFE3UL,0x88088880UL,0x6C2C4C60UL,0xA82888A0UL,0x14170713UL,0xC404C4C0UL,0x14160612UL,0xF434C4F0UL,
+0xC002C2C2UL,0x44054541UL,0xE021C1E1UL,0xD416C6D2UL,0x3C3F0F33UL,0x3C3D0D31UL,0x8C0E8E82UL,0x98188890UL,
+0x28280820UL,0x4C0E4E42UL,0xF436C6F2UL,0x3C3E0E32UL,0xA42585A1UL,0xF839C9F1UL,0x0C0D0D01UL,0xDC1FCFD3UL,
+0xD818C8D0UL,0x282B0B23UL,0x64264662UL,0x783A4A72UL,0x24270723UL,0x2C2F0F23UL,0xF031C1F1UL,0x70324272UL,
+0x40024242UL,0xD414C4D0UL,0x40014141UL,0xC000C0C0UL,0x70334373UL,0x64274763UL,0xAC2C8CA0UL,0x880B8B83UL,
+0xF437C7F3UL,0xAC2D8DA1UL,0x80008080UL,0x1C1F0F13UL,0xC80ACAC2UL,0x2C2C0C20UL,0xA82A8AA2UL,0x34340430UL,
+0xD012C2D2UL,0x080B0B03UL,0xEC2ECEE2UL,0xE829C9E1UL,0x5C1D4D51UL,0x94148490UL,0x18180810UL,0xF838C8F0UL,
+0x54174753UL,0xAC2E8EA2UL,0x08080800UL,0xC405C5C1UL,0x10130313UL,0xCC0DCDC1UL,0x84068682UL,0xB83989B1UL,
+0xFC3FCFF3UL,0x7C3D4D71UL,0xC001C1C1UL,0x30310131UL,0xF435C5F1UL,0x880A8A82UL,0x682A4A62UL,0xB03181B1UL,
+0xD011C1D1UL,0x20200020UL,0xD417C7D3UL,0x00020202UL,0x20220222UL,0x04040400UL,0x68284860UL,0x70314171UL,
+0x04070703UL,0xD81BCBD3UL,0x9C1D8D91UL,0x98198991UL,0x60214161UL,0xBC3E8EB2UL,0xE426C6E2UL,0x58194951UL,
+0xDC1DCDD1UL,0x50114151UL,0x90108090UL,0xDC1CCCD0UL,0x981A8A92UL,0xA02383A3UL,0xA82B8BA3UL,0xD010C0D0UL,
+0x80018181UL,0x0C0F0F03UL,0x44074743UL,0x181A0A12UL,0xE023C3E3UL,0xEC2CCCE0UL,0x8C0D8D81UL,0xBC3F8FB3UL,
+0x94168692UL,0x783B4B73UL,0x5C1C4C50UL,0xA02282A2UL,0xA02181A1UL,0x60234363UL,0x20230323UL,0x4C0D4D41UL,
+0xC808C8C0UL,0x9C1E8E92UL,0x9C1C8C90UL,0x383A0A32UL,0x0C0C0C00UL,0x2C2E0E22UL,0xB83A8AB2UL,0x6C2E4E62UL,
+0x9C1F8F93UL,0x581A4A52UL,0xF032C2F2UL,0x90128292UL,0xF033C3F3UL,0x48094941UL,0x78384870UL,0xCC0CCCC0UL,
+0x14150511UL,0xF83BCBF3UL,0x70304070UL,0x74354571UL,0x7C3F4F73UL,0x34350531UL,0x10100010UL,0x00030303UL,
+0x64244460UL,0x6C2D4D61UL,0xC406C6C2UL,0x74344470UL,0xD415C5D1UL,0xB43484B0UL,0xE82ACAE2UL,0x08090901UL,
+0x74364672UL,0x18190911UL,0xFC3ECEF2UL,0x40004040UL,0x10120212UL,0xE020C0E0UL,0xBC3D8DB1UL,0x04050501UL,
+0xF83ACAF2UL,0x00010101UL,0xF030C0F0UL,0x282A0A22UL,0x5C1E4E52UL,0xA82989A1UL,0x54164652UL,0x40034343UL,
+0x84058581UL,0x14140410UL,0x88098981UL,0x981B8B93UL,0xB03080B0UL,0xE425C5E1UL,0x48084840UL,0x78394971UL,
+0x94178793UL,0xFC3CCCF0UL,0x1C1E0E12UL,0x80028282UL,0x20210121UL,0x8C0C8C80UL,0x181B0B13UL,0x5C1F4F53UL,
+0x74374773UL,0x54144450UL,0xB03282B2UL,0x1C1D0D11UL,0x24250521UL,0x4C0F4F43UL,0x00000000UL,0x44064642UL,
+0xEC2DCDE1UL,0x58184850UL,0x50124252UL,0xE82BCBE3UL,0x7C3E4E72UL,0xD81ACAD2UL,0xC809C9C1UL,0xFC3DCDF1UL,
+0x30300030UL,0x94158591UL,0x64254561UL,0x3C3C0C30UL,0xB43686B2UL,0xE424C4E0UL,0xB83B8BB3UL,0x7C3C4C70UL,
+0x0C0E0E02UL,0x50104050UL,0x38390931UL,0x24260622UL,0x30320232UL,0x84048480UL,0x68294961UL,0x90138393UL,
+0x34370733UL,0xE427C7E3UL,0x24240420UL,0xA42484A0UL,0xC80BCBC3UL,0x50134353UL,0x080A0A02UL,0x84078783UL,
+0xD819C9D1UL,0x4C0C4C40UL,0x80038383UL,0x8C0F8F83UL,0xCC0ECEC2UL,0x383B0B33UL,0x480A4A42UL,0xB43787B3UL
+};
+
+static const ulong32 SS2[256] = {
+0xA1A82989UL,0x81840585UL,0xD2D416C6UL,0xD3D013C3UL,0x50541444UL,0x111C1D0DUL,0xA0AC2C8CUL,0x21242505UL,
+0x515C1D4DUL,0x43400343UL,0x10181808UL,0x121C1E0EUL,0x51501141UL,0xF0FC3CCCUL,0xC2C80ACAUL,0x63602343UL,
+0x20282808UL,0x40440444UL,0x20202000UL,0x919C1D8DUL,0xE0E020C0UL,0xE2E022C2UL,0xC0C808C8UL,0x13141707UL,
+0xA1A42585UL,0x838C0F8FUL,0x03000303UL,0x73783B4BUL,0xB3B83B8BUL,0x13101303UL,0xD2D012C2UL,0xE2EC2ECEUL,
+0x70703040UL,0x808C0C8CUL,0x333C3F0FUL,0xA0A82888UL,0x32303202UL,0xD1DC1DCDUL,0xF2F436C6UL,0x70743444UL,
+0xE0EC2CCCUL,0x91941585UL,0x03080B0BUL,0x53541747UL,0x505C1C4CUL,0x53581B4BUL,0xB1BC3D8DUL,0x01000101UL,
+0x20242404UL,0x101C1C0CUL,0x73703343UL,0x90981888UL,0x10101000UL,0xC0CC0CCCUL,0xF2F032C2UL,0xD1D819C9UL,
+0x202C2C0CUL,0xE3E427C7UL,0x72703242UL,0x83800383UL,0x93981B8BUL,0xD1D011C1UL,0x82840686UL,0xC1C809C9UL,
+0x60602040UL,0x50501040UL,0xA3A02383UL,0xE3E82BCBUL,0x010C0D0DUL,0xB2B43686UL,0x929C1E8EUL,0x434C0F4FUL,
+0xB3B43787UL,0x52581A4AUL,0xC2C406C6UL,0x70783848UL,0xA2A42686UL,0x12101202UL,0xA3AC2F8FUL,0xD1D415C5UL,
+0x61602141UL,0xC3C003C3UL,0xB0B43484UL,0x41400141UL,0x52501242UL,0x717C3D4DUL,0x818C0D8DUL,0x00080808UL,
+0x131C1F0FUL,0x91981989UL,0x00000000UL,0x11181909UL,0x00040404UL,0x53501343UL,0xF3F437C7UL,0xE1E021C1UL,
+0xF1FC3DCDUL,0x72743646UL,0x232C2F0FUL,0x23242707UL,0xB0B03080UL,0x83880B8BUL,0x020C0E0EUL,0xA3A82B8BUL,
+0xA2A02282UL,0x626C2E4EUL,0x93901383UL,0x414C0D4DUL,0x61682949UL,0x707C3C4CUL,0x01080909UL,0x02080A0AUL,
+0xB3BC3F8FUL,0xE3EC2FCFUL,0xF3F033C3UL,0xC1C405C5UL,0x83840787UL,0x10141404UL,0xF2FC3ECEUL,0x60642444UL,
+0xD2DC1ECEUL,0x222C2E0EUL,0x43480B4BUL,0x12181A0AUL,0x02040606UL,0x21202101UL,0x63682B4BUL,0x62642646UL,
+0x02000202UL,0xF1F435C5UL,0x92901282UL,0x82880A8AUL,0x000C0C0CUL,0xB3B03383UL,0x727C3E4EUL,0xD0D010C0UL,
+0x72783A4AUL,0x43440747UL,0x92941686UL,0xE1E425C5UL,0x22242606UL,0x80800080UL,0xA1AC2D8DUL,0xD3DC1FCFUL,
+0xA1A02181UL,0x30303000UL,0x33343707UL,0xA2AC2E8EUL,0x32343606UL,0x11141505UL,0x22202202UL,0x30383808UL,
+0xF0F434C4UL,0xA3A42787UL,0x41440545UL,0x404C0C4CUL,0x81800181UL,0xE1E829C9UL,0x80840484UL,0x93941787UL,
+0x31343505UL,0xC3C80BCBUL,0xC2CC0ECEUL,0x303C3C0CUL,0x71703141UL,0x11101101UL,0xC3C407C7UL,0x81880989UL,
+0x71743545UL,0xF3F83BCBUL,0xD2D81ACAUL,0xF0F838C8UL,0x90941484UL,0x51581949UL,0x82800282UL,0xC0C404C4UL,
+0xF3FC3FCFUL,0x41480949UL,0x31383909UL,0x63642747UL,0xC0C000C0UL,0xC3CC0FCFUL,0xD3D417C7UL,0xB0B83888UL,
+0x030C0F0FUL,0x828C0E8EUL,0x42400242UL,0x23202303UL,0x91901181UL,0x606C2C4CUL,0xD3D81BCBUL,0xA0A42484UL,
+0x30343404UL,0xF1F031C1UL,0x40480848UL,0xC2C002C2UL,0x636C2F4FUL,0x313C3D0DUL,0x212C2D0DUL,0x40400040UL,
+0xB2BC3E8EUL,0x323C3E0EUL,0xB0BC3C8CUL,0xC1C001C1UL,0xA2A82A8AUL,0xB2B83A8AUL,0x424C0E4EUL,0x51541545UL,
+0x33383B0BUL,0xD0DC1CCCUL,0x60682848UL,0x737C3F4FUL,0x909C1C8CUL,0xD0D818C8UL,0x42480A4AUL,0x52541646UL,
+0x73743747UL,0xA0A02080UL,0xE1EC2DCDUL,0x42440646UL,0xB1B43585UL,0x23282B0BUL,0x61642545UL,0xF2F83ACAUL,
+0xE3E023C3UL,0xB1B83989UL,0xB1B03181UL,0x939C1F8FUL,0x525C1E4EUL,0xF1F839C9UL,0xE2E426C6UL,0xB2B03282UL,
+0x31303101UL,0xE2E82ACAUL,0x616C2D4DUL,0x535C1F4FUL,0xE0E424C4UL,0xF0F030C0UL,0xC1CC0DCDUL,0x80880888UL,
+0x12141606UL,0x32383A0AUL,0x50581848UL,0xD0D414C4UL,0x62602242UL,0x21282909UL,0x03040707UL,0x33303303UL,
+0xE0E828C8UL,0x13181B0BUL,0x01040505UL,0x71783949UL,0x90901080UL,0x62682A4AUL,0x22282A0AUL,0x92981A8AUL
+};
+
+static const ulong32 SS3[256] = {
+0x08303838UL,0xC8E0E828UL,0x0D212C2DUL,0x86A2A426UL,0xCFC3CC0FUL,0xCED2DC1EUL,0x83B3B033UL,0x88B0B838UL,
+0x8FA3AC2FUL,0x40606020UL,0x45515415UL,0xC7C3C407UL,0x44404404UL,0x4F636C2FUL,0x4B63682BUL,0x4B53581BUL,
+0xC3C3C003UL,0x42626022UL,0x03333033UL,0x85B1B435UL,0x09212829UL,0x80A0A020UL,0xC2E2E022UL,0x87A3A427UL,
+0xC3D3D013UL,0x81919011UL,0x01111011UL,0x06020406UL,0x0C101C1CUL,0x8CB0BC3CUL,0x06323436UL,0x4B43480BUL,
+0xCFE3EC2FUL,0x88808808UL,0x4C606C2CUL,0x88A0A828UL,0x07131417UL,0xC4C0C404UL,0x06121416UL,0xC4F0F434UL,
+0xC2C2C002UL,0x45414405UL,0xC1E1E021UL,0xC6D2D416UL,0x0F333C3FUL,0x0D313C3DUL,0x8E828C0EUL,0x88909818UL,
+0x08202828UL,0x4E424C0EUL,0xC6F2F436UL,0x0E323C3EUL,0x85A1A425UL,0xC9F1F839UL,0x0D010C0DUL,0xCFD3DC1FUL,
+0xC8D0D818UL,0x0B23282BUL,0x46626426UL,0x4A72783AUL,0x07232427UL,0x0F232C2FUL,0xC1F1F031UL,0x42727032UL,
+0x42424002UL,0xC4D0D414UL,0x41414001UL,0xC0C0C000UL,0x43737033UL,0x47636427UL,0x8CA0AC2CUL,0x8B83880BUL,
+0xC7F3F437UL,0x8DA1AC2DUL,0x80808000UL,0x0F131C1FUL,0xCAC2C80AUL,0x0C202C2CUL,0x8AA2A82AUL,0x04303434UL,
+0xC2D2D012UL,0x0B03080BUL,0xCEE2EC2EUL,0xC9E1E829UL,0x4D515C1DUL,0x84909414UL,0x08101818UL,0xC8F0F838UL,
+0x47535417UL,0x8EA2AC2EUL,0x08000808UL,0xC5C1C405UL,0x03131013UL,0xCDC1CC0DUL,0x86828406UL,0x89B1B839UL,
+0xCFF3FC3FUL,0x4D717C3DUL,0xC1C1C001UL,0x01313031UL,0xC5F1F435UL,0x8A82880AUL,0x4A62682AUL,0x81B1B031UL,
+0xC1D1D011UL,0x00202020UL,0xC7D3D417UL,0x02020002UL,0x02222022UL,0x04000404UL,0x48606828UL,0x41717031UL,
+0x07030407UL,0xCBD3D81BUL,0x8D919C1DUL,0x89919819UL,0x41616021UL,0x8EB2BC3EUL,0xC6E2E426UL,0x49515819UL,
+0xCDD1DC1DUL,0x41515011UL,0x80909010UL,0xCCD0DC1CUL,0x8A92981AUL,0x83A3A023UL,0x8BA3A82BUL,0xC0D0D010UL,
+0x81818001UL,0x0F030C0FUL,0x47434407UL,0x0A12181AUL,0xC3E3E023UL,0xCCE0EC2CUL,0x8D818C0DUL,0x8FB3BC3FUL,
+0x86929416UL,0x4B73783BUL,0x4C505C1CUL,0x82A2A022UL,0x81A1A021UL,0x43636023UL,0x03232023UL,0x4D414C0DUL,
+0xC8C0C808UL,0x8E929C1EUL,0x8C909C1CUL,0x0A32383AUL,0x0C000C0CUL,0x0E222C2EUL,0x8AB2B83AUL,0x4E626C2EUL,
+0x8F939C1FUL,0x4A52581AUL,0xC2F2F032UL,0x82929012UL,0xC3F3F033UL,0x49414809UL,0x48707838UL,0xCCC0CC0CUL,
+0x05111415UL,0xCBF3F83BUL,0x40707030UL,0x45717435UL,0x4F737C3FUL,0x05313435UL,0x00101010UL,0x03030003UL,
+0x44606424UL,0x4D616C2DUL,0xC6C2C406UL,0x44707434UL,0xC5D1D415UL,0x84B0B434UL,0xCAE2E82AUL,0x09010809UL,
+0x46727436UL,0x09111819UL,0xCEF2FC3EUL,0x40404000UL,0x02121012UL,0xC0E0E020UL,0x8DB1BC3DUL,0x05010405UL,
+0xCAF2F83AUL,0x01010001UL,0xC0F0F030UL,0x0A22282AUL,0x4E525C1EUL,0x89A1A829UL,0x46525416UL,0x43434003UL,
+0x85818405UL,0x04101414UL,0x89818809UL,0x8B93981BUL,0x80B0B030UL,0xC5E1E425UL,0x48404808UL,0x49717839UL,
+0x87939417UL,0xCCF0FC3CUL,0x0E121C1EUL,0x82828002UL,0x01212021UL,0x8C808C0CUL,0x0B13181BUL,0x4F535C1FUL,
+0x47737437UL,0x44505414UL,0x82B2B032UL,0x0D111C1DUL,0x05212425UL,0x4F434C0FUL,0x00000000UL,0x46424406UL,
+0xCDE1EC2DUL,0x48505818UL,0x42525012UL,0xCBE3E82BUL,0x4E727C3EUL,0xCAD2D81AUL,0xC9C1C809UL,0xCDF1FC3DUL,
+0x00303030UL,0x85919415UL,0x45616425UL,0x0C303C3CUL,0x86B2B436UL,0xC4E0E424UL,0x8BB3B83BUL,0x4C707C3CUL,
+0x0E020C0EUL,0x40505010UL,0x09313839UL,0x06222426UL,0x02323032UL,0x84808404UL,0x49616829UL,0x83939013UL,
+0x07333437UL,0xC7E3E427UL,0x04202424UL,0x84A0A424UL,0xCBC3C80BUL,0x43535013UL,0x0A02080AUL,0x87838407UL,
+0xC9D1D819UL,0x4C404C0CUL,0x83838003UL,0x8F838C0FUL,0xCEC2CC0EUL,0x0B33383BUL,0x4A42480AUL,0x87B3B437UL
+};
+
+static const ulong32 KCi[16] = {
+0x9E3779B9,0x3C6EF373,
+0x78DDE6E6,0xF1BBCDCC,
+0xE3779B99,0xC6EF3733,
+0x8DDE6E67,0x1BBCDCCF,
+0x3779B99E,0x6EF3733C,
+0xDDE6E678,0xBBCDCCF1,
+0x779B99E3,0xEF3733C6,
+0xDE6E678D,0xBCDCCF1B
+};
+
+#define G(x) (SS3[((x)>>24)&255] ^ SS2[((x)>>16)&255] ^ SS1[((x)>>8)&255] ^ SS0[(x)&255])
+
+#define F(L1, L2, R1, R2, K1, K2) \
+   T2 = G((R1 ^ K1) ^ (R2 ^ K2)); \
+   T = G( G(T2 + (R1 ^ K1)) + T2); \
+   L2 ^= T; \
+   L1 ^= (T + G(T2 + (R1 ^ K1))); \
+
+ /**
+    Initialize the SEED block cipher
+    @param key The symmetric key you wish to pass
+    @param keylen The key length in bytes
+    @param num_rounds The number of rounds desired (0 for default)
+    @param skey The key in as scheduled by this function.
+    @return CRYPT_OK if successful
+ */
+int kseed_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey)
+{
+   int     i;
+   ulong32 tmp, k1, k2, k3, k4;
+
+   if (keylen != 16) {
+      return CRYPT_INVALID_KEYSIZE;
+   }
+
+   if (num_rounds != 16 && num_rounds != 0) {
+      return CRYPT_INVALID_ROUNDS;
+   }
+
+   /* load key */
+   LOAD32H(k1, key);
+   LOAD32H(k2, key+4);
+   LOAD32H(k3, key+8);
+   LOAD32H(k4, key+12);
+
+   for (i = 0; i < 16; i++) {
+      skey->kseed.K[2*i+0] = G(k1 + k3 - KCi[i]);
+      skey->kseed.K[2*i+1] = G(k2 - k4 + KCi[i]);
+      if (i&1) {
+         tmp = k3;
+         k3 = ((k3 << 8) | (k4 >> 24)) & 0xFFFFFFFF;
+         k4 = ((k4 << 8) | (tmp >> 24)) & 0xFFFFFFFF;
+      } else {
+         tmp = k1;
+         k1 = ((k1 >> 8) | (k2 << 24)) & 0xFFFFFFFF;
+         k2 = ((k2 >> 8) | (tmp << 24)) & 0xFFFFFFFF;
+      }
+      /* reverse keys for decrypt */
+      skey->kseed.dK[2*(15-i)+0] = skey->kseed.K[2*i+0];
+      skey->kseed.dK[2*(15-i)+1] = skey->kseed.K[2*i+1];
+   }
+
+   return CRYPT_OK;
+}
+
+static void rounds(ulong32 *P, ulong32 *K)
+{
+   ulong32 T, T2;
+   int     i;
+   for (i = 0; i < 16; i += 2) {
+     F(P[0], P[1], P[2], P[3], K[0], K[1]);
+     F(P[2], P[3], P[0], P[1], K[2], K[3]);
+     K += 4;
+   }
+}
+
+/**
+  Encrypts a block of text with SEED
+  @param pt The input plaintext (16 bytes)
+  @param ct The output ciphertext (16 bytes)
+  @param skey The key as scheduled
+  @return CRYPT_OK if successful
+*/
+int kseed_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey)
+{
+   ulong32 P[4];
+   LOAD32H(P[0], pt);
+   LOAD32H(P[1], pt+4);
+   LOAD32H(P[2], pt+8);
+   LOAD32H(P[3], pt+12);
+   rounds(P, skey->kseed.K);
+   STORE32H(P[2], ct);
+   STORE32H(P[3], ct+4);
+   STORE32H(P[0], ct+8);
+   STORE32H(P[1], ct+12);
+   return CRYPT_OK;
+}
+
+/**
+  Decrypts a block of text with SEED
+  @param ct The input ciphertext (16 bytes)
+  @param pt The output plaintext (16 bytes)
+  @param skey The key as scheduled
+  @return CRYPT_OK if successful
+*/
+int kseed_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey)
+{
+   ulong32 P[4];
+   LOAD32H(P[0], ct);
+   LOAD32H(P[1], ct+4);
+   LOAD32H(P[2], ct+8);
+   LOAD32H(P[3], ct+12);
+   rounds(P, skey->kseed.dK);
+   STORE32H(P[2], pt);
+   STORE32H(P[3], pt+4);
+   STORE32H(P[0], pt+8);
+   STORE32H(P[1], pt+12);
+   return CRYPT_OK;
+}
+
+/** Terminate the context
+   @param skey    The scheduled key
+*/
+void kseed_done(symmetric_key *skey)
+{
+  LTC_UNUSED_PARAM(skey);
+}
+
+/**
+  Performs a self-test of the SEED block cipher
+  @return CRYPT_OK if functional, CRYPT_NOP if self-test has been disabled
+*/
+int kseed_test(void)
+{
+#if !defined(LTC_TEST)
+  return CRYPT_NOP;
+#else
+  static const struct test {
+     unsigned char pt[16], ct[16], key[16];
+  } tests[] = {
+
+{
+  { 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F },
+  { 0x5E,0xBA,0xC6,0xE0,0x05,0x4E,0x16,0x68,0x19,0xAF,0xF1,0xCC,0x6D,0x34,0x6C,0xDB },
+  { 0 },
+},
+
+{
+  { 0 },
+  { 0xC1,0x1F,0x22,0xF2,0x01,0x40,0x50,0x50,0x84,0x48,0x35,0x97,0xE4,0x37,0x0F,0x43 },
+  { 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F },
+},
+
+{
+  { 0x83,0xA2,0xF8,0xA2,0x88,0x64,0x1F,0xB9,0xA4,0xE9,0xA5,0xCC,0x2F,0x13,0x1C,0x7D },
+  { 0xEE,0x54,0xD1,0x3E,0xBC,0xAE,0x70,0x6D,0x22,0x6B,0xC3,0x14,0x2C,0xD4,0x0D,0x4A },
+  { 0x47,0x06,0x48,0x08,0x51,0xE6,0x1B,0xE8,0x5D,0x74,0xBF,0xB3,0xFD,0x95,0x61,0x85 },
+},
+
+{
+  { 0xB4,0x1E,0x6B,0xE2,0xEB,0xA8,0x4A,0x14,0x8E,0x2E,0xED,0x84,0x59,0x3C,0x5E,0xC7 },
+  { 0x9B,0x9B,0x7B,0xFC,0xD1,0x81,0x3C,0xB9,0x5D,0x0B,0x36,0x18,0xF4,0x0F,0x51,0x22 },
+  { 0x28,0xDB,0xC3,0xBC,0x49,0xFF,0xD8,0x7D,0xCF,0xA5,0x09,0xB1,0x1D,0x42,0x2B,0xE7 },
+}
+};
+   int x;
+   unsigned char buf[2][16];
+   symmetric_key skey;
+
+   for (x = 0; x < (int)(sizeof(tests)/sizeof(tests[0])); x++) {
+       kseed_setup(tests[x].key, 16, 0, &skey);
+       kseed_ecb_encrypt(tests[x].pt, buf[0], &skey);
+       kseed_ecb_decrypt(buf[0], buf[1], &skey);
+       if (compare_testvector(buf[0], 16, tests[x].ct, 16, "KSEED Encrypt", x) ||
+             compare_testvector(buf[1], 16, tests[x].pt, 16, "KSEED Decrypt", x)) {
+          return CRYPT_FAIL_TESTVECTOR;
+       }
+   }
+   return CRYPT_OK;
+#endif
+}
+
+/**
+  Gets suitable key size
+  @param keysize [in/out] The length of the recommended key (in bytes).  This function will store the suitable size back in this variable.
+  @return CRYPT_OK if the input key size is acceptable.
+*/
+int kseed_keysize(int *keysize)
+{
+   LTC_ARGCHK(keysize != NULL);
+   if (*keysize >= 16) {
+      *keysize = 16;
+   } else {
+      return CRYPT_INVALID_KEYSIZE;
+   }
+   return CRYPT_OK;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/ciphers/multi2.c b/libtomcrypt/src/ciphers/multi2.c
new file mode 100644 (file)
index 0000000..86c1812
--- /dev/null
@@ -0,0 +1,319 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+/**
+  @file multi2.c
+  Multi-2 implementation (not public domain, hence the default disable)
+*/
+#include "tomcrypt.h"
+
+#ifdef LTC_MULTI2
+
+static void pi1(ulong32 *p)
+{
+   p[1] ^= p[0];
+}
+
+static void pi2(ulong32 *p, ulong32 *k)
+{
+   ulong32 t;
+   t = (p[1] + k[0]) & 0xFFFFFFFFUL;
+   t = (ROL(t, 1) + t - 1)  & 0xFFFFFFFFUL;
+   t = (ROL(t, 4) ^ t)  & 0xFFFFFFFFUL;
+   p[0] ^= t;
+}
+
+static void pi3(ulong32 *p, ulong32 *k)
+{
+   ulong32 t;
+   t = p[0] + k[1];
+   t = (ROL(t, 2) + t + 1)  & 0xFFFFFFFFUL;
+   t = (ROL(t, 8) ^ t)  & 0xFFFFFFFFUL;
+   t = (t + k[2])  & 0xFFFFFFFFUL;
+   t = (ROL(t, 1) - t)  & 0xFFFFFFFFUL;
+   t = ROL(t, 16) ^ (p[0] | t);
+   p[1] ^= t;
+}
+
+static void pi4(ulong32 *p, ulong32 *k)
+{
+   ulong32 t;
+   t = (p[1] + k[3])  & 0xFFFFFFFFUL;
+   t = (ROL(t, 2) + t + 1)  & 0xFFFFFFFFUL;
+   p[0] ^= t;
+}
+
+static void setup(ulong32 *dk, ulong32 *k, ulong32 *uk)
+{
+   int n, t;
+   ulong32 p[2];
+
+   p[0] = dk[0]; p[1] = dk[1];
+
+   t = 4;
+   n = 0;
+      pi1(p);
+      pi2(p, k);
+      uk[n++] = p[0];
+      pi3(p, k);
+      uk[n++] = p[1];
+      pi4(p, k);
+      uk[n++] = p[0];
+      pi1(p);
+      uk[n++] = p[1];
+      pi2(p, k+t);
+      uk[n++] = p[0];
+      pi3(p, k+t);
+      uk[n++] = p[1];
+      pi4(p, k+t);
+      uk[n++] = p[0];
+      pi1(p);
+      uk[n++] = p[1];
+}
+
+static void encrypt(ulong32 *p, int N, ulong32 *uk)
+{
+   int n, t;
+   for (t = n = 0; ; ) {
+      pi1(p); if (++n == N) break;
+      pi2(p, uk+t); if (++n == N) break;
+      pi3(p, uk+t); if (++n == N) break;
+      pi4(p, uk+t); if (++n == N) break;
+      t ^= 4;
+   }
+}
+
+static void decrypt(ulong32 *p, int N, ulong32 *uk)
+{
+   int n, t;
+   for (t = 4*(((N-1)>>2)&1), n = N; ;  ) {
+      switch (n<=4 ? n : ((n-1)%4)+1) {
+         case 4: pi4(p, uk+t); --n; /* FALLTHROUGH */
+         case 3: pi3(p, uk+t); --n; /* FALLTHROUGH */
+         case 2: pi2(p, uk+t); --n; /* FALLTHROUGH */
+         case 1: pi1(p); --n; break;
+         case 0: return;
+      }
+      t ^= 4;
+   }
+}
+
+const struct ltc_cipher_descriptor multi2_desc = {
+   "multi2",
+   22,
+   40, 40, 8, 128,
+   &multi2_setup,
+   &multi2_ecb_encrypt,
+   &multi2_ecb_decrypt,
+   &multi2_test,
+   &multi2_done,
+   &multi2_keysize,
+   NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
+};
+
+int  multi2_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey)
+{
+   ulong32 sk[8], dk[2];
+   int      x;
+
+   LTC_ARGCHK(key  != NULL);
+   LTC_ARGCHK(skey != NULL);
+
+   if (keylen != 40) return CRYPT_INVALID_KEYSIZE;
+   if (num_rounds == 0) num_rounds = 128;
+
+   skey->multi2.N = num_rounds;
+   for (x = 0; x < 8; x++) {
+       LOAD32H(sk[x], key + x*4);
+   }
+   LOAD32H(dk[0], key + 32);
+   LOAD32H(dk[1], key + 36);
+   setup(dk, sk, skey->multi2.uk);
+
+   zeromem(sk, sizeof(sk));
+   zeromem(dk, sizeof(dk));
+   return CRYPT_OK;
+}
+
+/**
+  Encrypts a block of text with multi2
+  @param pt The input plaintext (8 bytes)
+  @param ct The output ciphertext (8 bytes)
+  @param skey The key as scheduled
+  @return CRYPT_OK if successful
+*/
+int multi2_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey)
+{
+   ulong32 p[2];
+   LTC_ARGCHK(pt   != NULL);
+   LTC_ARGCHK(ct   != NULL);
+   LTC_ARGCHK(skey != NULL);
+   LOAD32H(p[0], pt);
+   LOAD32H(p[1], pt+4);
+   encrypt(p, skey->multi2.N, skey->multi2.uk);
+   STORE32H(p[0], ct);
+   STORE32H(p[1], ct+4);
+   return CRYPT_OK;
+}
+
+/**
+  Decrypts a block of text with multi2
+  @param ct The input ciphertext (8 bytes)
+  @param pt The output plaintext (8 bytes)
+  @param skey The key as scheduled
+  @return CRYPT_OK if successful
+*/
+int multi2_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey)
+{
+   ulong32 p[2];
+   LTC_ARGCHK(pt   != NULL);
+   LTC_ARGCHK(ct   != NULL);
+   LTC_ARGCHK(skey != NULL);
+   LOAD32H(p[0], ct);
+   LOAD32H(p[1], ct+4);
+   decrypt(p, skey->multi2.N, skey->multi2.uk);
+   STORE32H(p[0], pt);
+   STORE32H(p[1], pt+4);
+   return CRYPT_OK;
+}
+
+/**
+  Performs a self-test of the multi2 block cipher
+  @return CRYPT_OK if functional, CRYPT_NOP if self-test has been disabled
+*/
+int multi2_test(void)
+{
+   static const struct {
+      unsigned char key[40];
+      unsigned char pt[8], ct[8];
+      int           rounds;
+   } tests[] = {
+{
+   {
+      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,
+
+      0x01, 0x23, 0x45, 0x67,
+      0x89, 0xAB, 0xCD, 0xEF
+   },
+   {
+      0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x01,
+   },
+   {
+      0xf8, 0x94, 0x40, 0x84,
+      0x5e, 0x11, 0xcf, 0x89
+   },
+   128,
+},
+{
+   {
+      0x35, 0x91, 0x9d, 0x96,
+      0x07, 0x02, 0xe2, 0xce,
+      0x8d, 0x0b, 0x58, 0x3c,
+      0xc9, 0xc8, 0x9d, 0x59,
+      0xa2, 0xae, 0x96, 0x4e,
+      0x87, 0x82, 0x45, 0xed,
+      0x3f, 0x2e, 0x62, 0xd6,
+      0x36, 0x35, 0xd0, 0x67,
+
+      0xb1, 0x27, 0xb9, 0x06,
+      0xe7, 0x56, 0x22, 0x38,
+   },
+   {
+      0x1f, 0xb4, 0x60, 0x60,
+      0xd0, 0xb3, 0x4f, 0xa5
+   },
+   {
+      0xca, 0x84, 0xa9, 0x34,
+      0x75, 0xc8, 0x60, 0xe5
+   },
+   216,
+}
+};
+   unsigned char buf[8];
+   symmetric_key skey;
+   int err, x;
+
+   for (x = 1; x < (int)(sizeof(tests)/sizeof(tests[0])); x++) {
+      if ((err = multi2_setup(tests[x].key, 40, tests[x].rounds, &skey)) != CRYPT_OK) {
+         return err;
+      }
+      if ((err = multi2_ecb_encrypt(tests[x].pt, buf, &skey)) != CRYPT_OK) {
+         return err;
+      }
+
+      if (compare_testvector(buf, 8, tests[x].ct, 8, "Multi2 Encrypt", x)) {
+         return CRYPT_FAIL_TESTVECTOR;
+      }
+
+      if ((err = multi2_ecb_decrypt(buf, buf, &skey)) != CRYPT_OK) {
+         return err;
+      }
+      if (compare_testvector(buf, 8, tests[x].pt, 8, "Multi2 Decrypt", x)) {
+         return CRYPT_FAIL_TESTVECTOR;
+      }
+   }
+
+   for (x = 128; x < 256; ++x) {
+        unsigned char ct[8];
+
+        if ((err = multi2_setup(tests[0].key, 40, x, &skey)) != CRYPT_OK) {
+                return err;
+        }
+        if ((err = multi2_ecb_encrypt(tests[0].pt, ct, &skey)) != CRYPT_OK) {
+                return err;
+        }
+        if ((err = multi2_ecb_decrypt(ct, buf, &skey)) != CRYPT_OK) {
+                return err;
+        }
+        if (compare_testvector(buf, 8, tests[0].pt, 8, "Multi2 Rounds", x)) {
+                return CRYPT_FAIL_TESTVECTOR;
+        }
+   }
+
+   return CRYPT_OK;
+}
+
+/** Terminate the context
+   @param skey    The scheduled key
+*/
+void multi2_done(symmetric_key *skey)
+{
+  LTC_UNUSED_PARAM(skey);
+}
+
+/**
+  Gets suitable key size
+  @param keysize [in/out] The length of the recommended key (in bytes).  This function will store the suitable size back in this variable.
+  @return CRYPT_OK if the input key size is acceptable.
+*/
+int multi2_keysize(int *keysize)
+{
+   LTC_ARGCHK(keysize != NULL);
+   if (*keysize >= 40) {
+      *keysize = 40;
+   } else {
+      return CRYPT_INVALID_KEYSIZE;
+   }
+   return CRYPT_OK;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/ciphers/noekeon.c b/libtomcrypt/src/ciphers/noekeon.c
new file mode 100644 (file)
index 0000000..13720d1
--- /dev/null
@@ -0,0 +1,328 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+/**
+   @file noekeon.c
+   Implementation of the Noekeon block cipher by Tom St Denis
+*/
+#include "tomcrypt.h"
+
+#ifdef LTC_NOEKEON
+
+const struct ltc_cipher_descriptor noekeon_desc =
+{
+    "noekeon",
+    16,
+    16, 16, 16, 16,
+    &noekeon_setup,
+    &noekeon_ecb_encrypt,
+    &noekeon_ecb_decrypt,
+    &noekeon_test,
+    &noekeon_done,
+    &noekeon_keysize,
+    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
+};
+
+static const ulong32 RC[] = {
+   0x00000080UL, 0x0000001bUL, 0x00000036UL, 0x0000006cUL,
+   0x000000d8UL, 0x000000abUL, 0x0000004dUL, 0x0000009aUL,
+   0x0000002fUL, 0x0000005eUL, 0x000000bcUL, 0x00000063UL,
+   0x000000c6UL, 0x00000097UL, 0x00000035UL, 0x0000006aUL,
+   0x000000d4UL
+};
+
+#define kTHETA(a, b, c, d)                                 \
+    temp = a^c; temp = temp ^ ROLc(temp, 8) ^ RORc(temp, 8); \
+    b ^= temp; d ^= temp;                                  \
+    temp = b^d; temp = temp ^ ROLc(temp, 8) ^ RORc(temp, 8); \
+    a ^= temp; c ^= temp;
+
+#define THETA(k, a, b, c, d)                               \
+    temp = a^c; temp = temp ^ ROLc(temp, 8) ^ RORc(temp, 8); \
+    b ^= temp ^ k[1]; d ^= temp ^ k[3];                    \
+    temp = b^d; temp = temp ^ ROLc(temp, 8) ^ RORc(temp, 8); \
+    a ^= temp ^ k[0]; c ^= temp ^ k[2];
+
+#define GAMMA(a, b, c, d)     \
+    b ^= ~(d|c);              \
+    a ^= c&b;                 \
+    temp = d; d = a; a = temp;\
+    c ^= a ^ b ^ d;           \
+    b ^= ~(d|c);              \
+    a ^= c&b;
+
+#define PI1(a, b, c, d) \
+    b = ROLc(b, 1); c = ROLc(c, 5); d = ROLc(d, 2);
+
+#define PI2(a, b, c, d) \
+    b = RORc(b, 1); c = RORc(c, 5); d = RORc(d, 2);
+
+ /**
+    Initialize the Noekeon block cipher
+    @param key The symmetric key you wish to pass
+    @param keylen The key length in bytes
+    @param num_rounds The number of rounds desired (0 for default)
+    @param skey The key in as scheduled by this function.
+    @return CRYPT_OK if successful
+ */
+int noekeon_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey)
+{
+   ulong32 temp;
+
+   LTC_ARGCHK(key != NULL);
+   LTC_ARGCHK(skey != NULL);
+
+   if (keylen != 16) {
+      return CRYPT_INVALID_KEYSIZE;
+   }
+
+   if (num_rounds != 16 && num_rounds != 0) {
+      return CRYPT_INVALID_ROUNDS;
+   }
+
+   LOAD32H(skey->noekeon.K[0],&key[0]);
+   LOAD32H(skey->noekeon.K[1],&key[4]);
+   LOAD32H(skey->noekeon.K[2],&key[8]);
+   LOAD32H(skey->noekeon.K[3],&key[12]);
+
+   LOAD32H(skey->noekeon.dK[0],&key[0]);
+   LOAD32H(skey->noekeon.dK[1],&key[4]);
+   LOAD32H(skey->noekeon.dK[2],&key[8]);
+   LOAD32H(skey->noekeon.dK[3],&key[12]);
+
+   kTHETA(skey->noekeon.dK[0], skey->noekeon.dK[1], skey->noekeon.dK[2], skey->noekeon.dK[3]);
+
+   return CRYPT_OK;
+}
+
+/**
+  Encrypts a block of text with Noekeon
+  @param pt The input plaintext (16 bytes)
+  @param ct The output ciphertext (16 bytes)
+  @param skey The key as scheduled
+  @return CRYPT_OK if successful
+*/
+#ifdef LTC_CLEAN_STACK
+static int _noekeon_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey)
+#else
+int noekeon_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey)
+#endif
+{
+   ulong32 a,b,c,d,temp;
+   int r;
+
+   LTC_ARGCHK(skey != NULL);
+   LTC_ARGCHK(pt   != NULL);
+   LTC_ARGCHK(ct   != NULL);
+
+   LOAD32H(a,&pt[0]); LOAD32H(b,&pt[4]);
+   LOAD32H(c,&pt[8]); LOAD32H(d,&pt[12]);
+
+#define ROUND(i) \
+       a ^= RC[i]; \
+       THETA(skey->noekeon.K, a,b,c,d); \
+       PI1(a,b,c,d); \
+       GAMMA(a,b,c,d); \
+       PI2(a,b,c,d);
+
+   for (r = 0; r < 16; ++r) {
+       ROUND(r);
+   }
+
+#undef ROUND
+
+   a ^= RC[16];
+   THETA(skey->noekeon.K, a, b, c, d);
+
+   STORE32H(a,&ct[0]); STORE32H(b,&ct[4]);
+   STORE32H(c,&ct[8]); STORE32H(d,&ct[12]);
+
+   return CRYPT_OK;
+}
+
+#ifdef LTC_CLEAN_STACK
+int noekeon_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey)
+{
+   int err = _noekeon_ecb_encrypt(pt, ct, skey);
+   burn_stack(sizeof(ulong32) * 5 + sizeof(int));
+   return err;
+}
+#endif
+
+/**
+  Decrypts a block of text with Noekeon
+  @param ct The input ciphertext (16 bytes)
+  @param pt The output plaintext (16 bytes)
+  @param skey The key as scheduled
+  @return CRYPT_OK if successful
+*/
+#ifdef LTC_CLEAN_STACK
+static int _noekeon_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey)
+#else
+int noekeon_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey)
+#endif
+{
+   ulong32 a,b,c,d, temp;
+   int r;
+
+   LTC_ARGCHK(skey != NULL);
+   LTC_ARGCHK(pt   != NULL);
+   LTC_ARGCHK(ct   != NULL);
+
+   LOAD32H(a,&ct[0]); LOAD32H(b,&ct[4]);
+   LOAD32H(c,&ct[8]); LOAD32H(d,&ct[12]);
+
+
+#define ROUND(i) \
+       THETA(skey->noekeon.dK, a,b,c,d); \
+       a ^= RC[i]; \
+       PI1(a,b,c,d); \
+       GAMMA(a,b,c,d); \
+       PI2(a,b,c,d);
+
+   for (r = 16; r > 0; --r) {
+       ROUND(r);
+   }
+
+#undef ROUND
+
+   THETA(skey->noekeon.dK, a,b,c,d);
+   a ^= RC[0];
+   STORE32H(a,&pt[0]); STORE32H(b, &pt[4]);
+   STORE32H(c,&pt[8]); STORE32H(d, &pt[12]);
+   return CRYPT_OK;
+}
+
+#ifdef LTC_CLEAN_STACK
+int noekeon_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey)
+{
+   int err = _noekeon_ecb_decrypt(ct, pt, skey);
+   burn_stack(sizeof(ulong32) * 5 + sizeof(int));
+   return err;
+}
+#endif
+
+/**
+  Performs a self-test of the Noekeon block cipher
+  @return CRYPT_OK if functional, CRYPT_NOP if self-test has been disabled
+*/
+int noekeon_test(void)
+{
+ #ifndef LTC_TEST
+    return CRYPT_NOP;
+ #else
+ static const struct {
+     int keylen;
+     unsigned char key[16], pt[16], ct[16];
+ } tests[] = {
+   {
+      16,
+      { 0xAA, 0x3C, 0x8C, 0x86, 0xD9, 0x8B, 0xF8, 0xBE, 0x21, 0xE0, 0x36, 0x09, 0x78, 0xFB, 0xE4, 0x90 },
+      { 0xE4, 0x96, 0x6C, 0xD3, 0x13, 0xA0, 0x6C, 0xAF, 0xD0, 0x23, 0xC9, 0xFD, 0x45, 0x32, 0x23, 0x16 },
+      { 0xA6, 0xEC, 0xB8, 0xA8, 0x61, 0xFD, 0x62, 0xD9, 0x13, 0x02, 0xFE, 0x9E, 0x47, 0x01, 0x3F, 0xC3 }
+   },
+   {
+      16,
+      { 0xED, 0x43, 0xD1, 0x87, 0x21, 0x7E, 0xE0, 0x97, 0x3D, 0x76, 0xC3, 0x37, 0x2E, 0x7D, 0xAE, 0xD3 },
+      { 0xE3, 0x38, 0x32, 0xCC, 0xF2, 0x2F, 0x2F, 0x0A, 0x4A, 0x8B, 0x8F, 0x18, 0x12, 0x20, 0x17, 0xD3 },
+      { 0x94, 0xA5, 0xDF, 0xF5, 0xAE, 0x1C, 0xBB, 0x22, 0xAD, 0xEB, 0xA7, 0x0D, 0xB7, 0x82, 0x90, 0xA0 }
+   },
+   {
+      16,
+      { 0x6F, 0xDC, 0x23, 0x38, 0xF2, 0x10, 0xFB, 0xD3, 0xC1, 0x8C, 0x02, 0xF6, 0xB4, 0x6A, 0xD5, 0xA8 },
+      { 0xDB, 0x29, 0xED, 0xB5, 0x5F, 0xB3, 0x60, 0x3A, 0x92, 0xA8, 0xEB, 0x9C, 0x6D, 0x9D, 0x3E, 0x8F },
+      { 0x78, 0xF3, 0x6F, 0xF8, 0x9E, 0xBB, 0x8C, 0x6A, 0xE8, 0x10, 0xF7, 0x00, 0x22, 0x15, 0x30, 0x3D }
+   },
+   {
+      16,
+      { 0x2C, 0x0C, 0x02, 0xEF, 0x6B, 0xC4, 0xF2, 0x0B, 0x2E, 0xB9, 0xE0, 0xBF, 0xD9, 0x36, 0xC2, 0x4E },
+      { 0x84, 0xE2, 0xFE, 0x64, 0xB1, 0xB9, 0xFE, 0x76, 0xA8, 0x3F, 0x45, 0xC7, 0x40, 0x7A, 0xAF, 0xEE },
+      { 0x2A, 0x08, 0xD6, 0xA2, 0x1C, 0x63, 0x08, 0xB0, 0xF8, 0xBC, 0xB3, 0xA1, 0x66, 0xF7, 0xAE, 0xCF }
+   },
+   {
+      16,
+      { 0x6F, 0x30, 0xF8, 0x9F, 0xDA, 0x6E, 0xA0, 0x91, 0x04, 0x0F, 0x6C, 0x8B, 0x7D, 0xF7, 0x2A, 0x4B },
+      { 0x65, 0xB6, 0xA6, 0xD0, 0x42, 0x14, 0x08, 0x60, 0x34, 0x8D, 0x37, 0x2F, 0x01, 0xF0, 0x46, 0xBE },
+      { 0x66, 0xAC, 0x0B, 0x62, 0x1D, 0x68, 0x11, 0xF5, 0x27, 0xB1, 0x13, 0x5D, 0xF3, 0x2A, 0xE9, 0x18 }
+   },
+   {
+      16,
+      { 0xCA, 0xA4, 0x16, 0xB7, 0x1C, 0x92, 0x2E, 0xAD, 0xEB, 0xA7, 0xDB, 0x69, 0x92, 0xCB, 0x35, 0xEF },
+      { 0x81, 0x6F, 0x8E, 0x4D, 0x96, 0xC6, 0xB3, 0x67, 0x83, 0xF5, 0x63, 0xC7, 0x20, 0x6D, 0x40, 0x23 },
+      { 0x44, 0xF7, 0x63, 0x62, 0xF0, 0x43, 0xBB, 0x67, 0x4A, 0x75, 0x12, 0x42, 0x46, 0x29, 0x28, 0x19 }
+   },
+   {
+      16,
+      { 0x6B, 0xCF, 0x22, 0x2F, 0xE0, 0x1B, 0xB0, 0xAA, 0xD8, 0x3C, 0x91, 0x99, 0x18, 0xB2, 0x28, 0xE8 },
+      { 0x7C, 0x37, 0xC7, 0xD0, 0xAC, 0x92, 0x29, 0xF1, 0x60, 0x82, 0x93, 0x89, 0xAA, 0x61, 0xAA, 0xA9 },
+      { 0xE5, 0x89, 0x1B, 0xB3, 0xFE, 0x8B, 0x0C, 0xA1, 0xA6, 0xC7, 0xBE, 0x12, 0x73, 0x0F, 0xC1, 0x19 }
+   },
+   {
+      16,
+      { 0xE6, 0xD0, 0xF1, 0x03, 0x2E, 0xDE, 0x70, 0x8D, 0xD8, 0x9E, 0x36, 0x5C, 0x05, 0x52, 0xE7, 0x0D },
+      { 0xE2, 0x42, 0xE7, 0x92, 0x0E, 0xF7, 0x82, 0xA2, 0xB8, 0x21, 0x8D, 0x26, 0xBA, 0x2D, 0xE6, 0x32 },
+      { 0x1E, 0xDD, 0x75, 0x22, 0xB9, 0x36, 0x8A, 0x0F, 0x32, 0xFD, 0xD4, 0x48, 0x65, 0x12, 0x5A, 0x2F }
+   }
+ };
+ symmetric_key key;
+ unsigned char tmp[2][16];
+ int err, i, y;
+
+ for (i = 0; i < (int)(sizeof(tests)/sizeof(tests[0])); i++) {
+    zeromem(&key, sizeof(key));
+    if ((err = noekeon_setup(tests[i].key, tests[i].keylen, 0, &key)) != CRYPT_OK) {
+       return err;
+    }
+
+    noekeon_ecb_encrypt(tests[i].pt, tmp[0], &key);
+    noekeon_ecb_decrypt(tmp[0], tmp[1], &key);
+    if (compare_testvector(tmp[0], 16, tests[i].ct, 16, "Noekeon Encrypt", i) ||
+          compare_testvector(tmp[1], 16, tests[i].pt, 16, "Noekeon Decrypt", i)) {
+        return CRYPT_FAIL_TESTVECTOR;
+    }
+
+    /* now see if we can encrypt all zero bytes 1000 times, decrypt and come back where we started */
+    for (y = 0; y < 16; y++) tmp[0][y] = 0;
+    for (y = 0; y < 1000; y++) noekeon_ecb_encrypt(tmp[0], tmp[0], &key);
+    for (y = 0; y < 1000; y++) noekeon_ecb_decrypt(tmp[0], tmp[0], &key);
+    for (y = 0; y < 16; y++) if (tmp[0][y] != 0) return CRYPT_FAIL_TESTVECTOR;
+ }
+ return CRYPT_OK;
+ #endif
+}
+
+/** Terminate the context
+   @param skey    The scheduled key
+*/
+void noekeon_done(symmetric_key *skey)
+{
+  LTC_UNUSED_PARAM(skey);
+}
+
+/**
+  Gets suitable key size
+  @param keysize [in/out] The length of the recommended key (in bytes).  This function will store the suitable size back in this variable.
+  @return CRYPT_OK if the input key size is acceptable.
+*/
+int noekeon_keysize(int *keysize)
+{
+   LTC_ARGCHK(keysize != NULL);
+   if (*keysize < 16) {
+      return CRYPT_INVALID_KEYSIZE;
+   } else {
+      *keysize = 16;
+      return CRYPT_OK;
+   }
+}
+
+#endif
+
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/ciphers/rc2.c b/libtomcrypt/src/ciphers/rc2.c
new file mode 100644 (file)
index 0000000..ebd8f88
--- /dev/null
@@ -0,0 +1,417 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+/**********************************************************************\
+* To commemorate the 1996 RSA Data Security Conference, the following  *
+* code is released into the public domain by its author.  Prost!       *
+*                                                                      *
+* This cipher uses 16-bit words and little-endian byte ordering.       *
+* I wonder which processor it was optimized for?                       *
+*                                                                      *
+* Thanks to CodeView, SoftIce, and D86 for helping bring this code to  *
+* the public.                                                          *
+\**********************************************************************/
+#include "tomcrypt.h"
+
+/**
+  @file rc2.c
+  Implementation of RC2 with fixed effective key length of 64bits
+*/
+
+#ifdef LTC_RC2
+
+const struct ltc_cipher_descriptor rc2_desc = {
+   "rc2",
+   12, 8, 128, 8, 16,
+   &rc2_setup,
+   &rc2_ecb_encrypt,
+   &rc2_ecb_decrypt,
+   &rc2_test,
+   &rc2_done,
+   &rc2_keysize,
+   NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
+};
+
+/* 256-entry permutation table, probably derived somehow from pi */
+static const unsigned char permute[256] = {
+        217,120,249,196, 25,221,181,237, 40,233,253,121, 74,160,216,157,
+        198,126, 55,131, 43,118, 83,142, 98, 76,100,136, 68,139,251,162,
+         23,154, 89,245,135,179, 79, 19, 97, 69,109,141,  9,129,125, 50,
+        189,143, 64,235,134,183,123, 11,240,149, 33, 34, 92,107, 78,130,
+         84,214,101,147,206, 96,178, 28,115, 86,192, 20,167,140,241,220,
+         18,117,202, 31, 59,190,228,209, 66, 61,212, 48,163, 60,182, 38,
+        111,191, 14,218, 70,105,  7, 87, 39,242, 29,155,188,148, 67,  3,
+        248, 17,199,246,144,239, 62,231,  6,195,213, 47,200,102, 30,215,
+          8,232,234,222,128, 82,238,247,132,170,114,172, 53, 77,106, 42,
+        150, 26,210,113, 90, 21, 73,116, 75,159,208, 94,  4, 24,164,236,
+        194,224, 65,110, 15, 81,203,204, 36,145,175, 80,161,244,112, 57,
+        153,124, 58,133, 35,184,180,122,252,  2, 54, 91, 37, 85,151, 49,
+         45, 93,250,152,227,138,146,174,  5,223, 41, 16,103,108,186,201,
+        211,  0,230,207,225,158,168, 44, 99, 22,  1, 63, 88,226,137,169,
+         13, 56, 52, 27,171, 51,255,176,187, 72, 12, 95,185,177,205, 46,
+        197,243,219, 71,229,165,156,119, 10,166, 32,104,254,127,193,173
+};
+
+ /**
+    Initialize the RC2 block cipher
+    @param key The symmetric key you wish to pass
+    @param keylen The key length in bytes
+    @param bits The effective key length in bits
+    @param num_rounds The number of rounds desired (0 for default)
+    @param skey The key in as scheduled by this function.
+    @return CRYPT_OK if successful
+ */
+int rc2_setup_ex(const unsigned char *key, int keylen, int bits, int num_rounds, symmetric_key *skey)
+{
+   unsigned *xkey = skey->rc2.xkey;
+   unsigned char tmp[128];
+   unsigned T8, TM;
+   int i;
+
+   LTC_ARGCHK(key  != NULL);
+   LTC_ARGCHK(skey != NULL);
+
+   if (keylen == 0 || keylen > 128 || bits > 1024) {
+      return CRYPT_INVALID_KEYSIZE;
+   }
+   if (bits == 0) {
+      bits = 1024;
+   }
+
+   if (num_rounds != 0 && num_rounds != 16) {
+      return CRYPT_INVALID_ROUNDS;
+   }
+
+   for (i = 0; i < keylen; i++) {
+      tmp[i] = key[i] & 255;
+   }
+
+   /* Phase 1: Expand input key to 128 bytes */
+   if (keylen < 128) {
+      for (i = keylen; i < 128; i++) {
+         tmp[i] = permute[(tmp[i - 1] + tmp[i - keylen]) & 255];
+      }
+   }
+
+   /* Phase 2 - reduce effective key size to "bits" */
+   T8   = (unsigned)(bits+7)>>3;
+   TM   = (255 >> (unsigned)(7 & -bits));
+   tmp[128 - T8] = permute[tmp[128 - T8] & TM];
+   for (i = 127 - T8; i >= 0; i--) {
+      tmp[i] = permute[tmp[i + 1] ^ tmp[i + T8]];
+   }
+
+   /* Phase 3 - copy to xkey in little-endian order */
+   for (i = 0; i < 64; i++) {
+      xkey[i] =  (unsigned)tmp[2*i] + ((unsigned)tmp[2*i+1] << 8);
+   }
+
+#ifdef LTC_CLEAN_STACK
+   zeromem(tmp, sizeof(tmp));
+#endif
+
+   return CRYPT_OK;
+}
+
+/**
+   Initialize the RC2 block cipher
+
+     The effective key length is here always keylen * 8
+
+   @param key The symmetric key you wish to pass
+   @param keylen The key length in bytes
+   @param num_rounds The number of rounds desired (0 for default)
+   @param skey The key in as scheduled by this function.
+   @return CRYPT_OK if successful
+*/
+int rc2_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey)
+{
+   return rc2_setup_ex(key, keylen, keylen * 8, num_rounds, skey);
+}
+
+/**********************************************************************\
+* Encrypt an 8-byte block of plaintext using the given key.            *
+\**********************************************************************/
+/**
+  Encrypts a block of text with RC2
+  @param pt The input plaintext (8 bytes)
+  @param ct The output ciphertext (8 bytes)
+  @param skey The key as scheduled
+  @return CRYPT_OK if successful
+*/
+#ifdef LTC_CLEAN_STACK
+static int _rc2_ecb_encrypt( const unsigned char *pt,
+                            unsigned char *ct,
+                            symmetric_key *skey)
+#else
+int rc2_ecb_encrypt( const unsigned char *pt,
+                            unsigned char *ct,
+                            symmetric_key *skey)
+#endif
+{
+    unsigned *xkey;
+    unsigned x76, x54, x32, x10, i;
+
+    LTC_ARGCHK(pt  != NULL);
+    LTC_ARGCHK(ct != NULL);
+    LTC_ARGCHK(skey   != NULL);
+
+    xkey = skey->rc2.xkey;
+
+    x76 = ((unsigned)pt[7] << 8) + (unsigned)pt[6];
+    x54 = ((unsigned)pt[5] << 8) + (unsigned)pt[4];
+    x32 = ((unsigned)pt[3] << 8) + (unsigned)pt[2];
+    x10 = ((unsigned)pt[1] << 8) + (unsigned)pt[0];
+
+    for (i = 0; i < 16; i++) {
+        x10 = (x10 + (x32 & ~x76) + (x54 & x76) + xkey[4*i+0]) & 0xFFFF;
+        x10 = ((x10 << 1) | (x10 >> 15));
+
+        x32 = (x32 + (x54 & ~x10) + (x76 & x10) + xkey[4*i+1]) & 0xFFFF;
+        x32 = ((x32 << 2) | (x32 >> 14));
+
+        x54 = (x54 + (x76 & ~x32) + (x10 & x32) + xkey[4*i+2]) & 0xFFFF;
+        x54 = ((x54 << 3) | (x54 >> 13));
+
+        x76 = (x76 + (x10 & ~x54) + (x32 & x54) + xkey[4*i+3]) & 0xFFFF;
+        x76 = ((x76 << 5) | (x76 >> 11));
+
+        if (i == 4 || i == 10) {
+            x10 = (x10 + xkey[x76 & 63]) & 0xFFFF;
+            x32 = (x32 + xkey[x10 & 63]) & 0xFFFF;
+            x54 = (x54 + xkey[x32 & 63]) & 0xFFFF;
+            x76 = (x76 + xkey[x54 & 63]) & 0xFFFF;
+        }
+    }
+
+    ct[0] = (unsigned char)x10;
+    ct[1] = (unsigned char)(x10 >> 8);
+    ct[2] = (unsigned char)x32;
+    ct[3] = (unsigned char)(x32 >> 8);
+    ct[4] = (unsigned char)x54;
+    ct[5] = (unsigned char)(x54 >> 8);
+    ct[6] = (unsigned char)x76;
+    ct[7] = (unsigned char)(x76 >> 8);
+
+    return CRYPT_OK;
+}
+
+#ifdef LTC_CLEAN_STACK
+int rc2_ecb_encrypt( const unsigned char *pt,
+                            unsigned char *ct,
+                            symmetric_key *skey)
+{
+    int err = _rc2_ecb_encrypt(pt, ct, skey);
+    burn_stack(sizeof(unsigned *) + sizeof(unsigned) * 5);
+    return err;
+}
+#endif
+
+/**********************************************************************\
+* Decrypt an 8-byte block of ciphertext using the given key.           *
+\**********************************************************************/
+/**
+  Decrypts a block of text with RC2
+  @param ct The input ciphertext (8 bytes)
+  @param pt The output plaintext (8 bytes)
+  @param skey The key as scheduled
+  @return CRYPT_OK if successful
+*/
+#ifdef LTC_CLEAN_STACK
+static int _rc2_ecb_decrypt( const unsigned char *ct,
+                            unsigned char *pt,
+                            symmetric_key *skey)
+#else
+int rc2_ecb_decrypt( const unsigned char *ct,
+                            unsigned char *pt,
+                            symmetric_key *skey)
+#endif
+{
+    unsigned x76, x54, x32, x10;
+    unsigned *xkey;
+    int i;
+
+    LTC_ARGCHK(pt  != NULL);
+    LTC_ARGCHK(ct != NULL);
+    LTC_ARGCHK(skey   != NULL);
+
+    xkey = skey->rc2.xkey;
+
+    x76 = ((unsigned)ct[7] << 8) + (unsigned)ct[6];
+    x54 = ((unsigned)ct[5] << 8) + (unsigned)ct[4];
+    x32 = ((unsigned)ct[3] << 8) + (unsigned)ct[2];
+    x10 = ((unsigned)ct[1] << 8) + (unsigned)ct[0];
+
+    for (i = 15; i >= 0; i--) {
+        if (i == 4 || i == 10) {
+            x76 = (x76 - xkey[x54 & 63]) & 0xFFFF;
+            x54 = (x54 - xkey[x32 & 63]) & 0xFFFF;
+            x32 = (x32 - xkey[x10 & 63]) & 0xFFFF;
+            x10 = (x10 - xkey[x76 & 63]) & 0xFFFF;
+        }
+
+        x76 = ((x76 << 11) | (x76 >> 5));
+        x76 = (x76 - ((x10 & ~x54) + (x32 & x54) + xkey[4*i+3])) & 0xFFFF;
+
+        x54 = ((x54 << 13) | (x54 >> 3));
+        x54 = (x54 - ((x76 & ~x32) + (x10 & x32) + xkey[4*i+2])) & 0xFFFF;
+
+        x32 = ((x32 << 14) | (x32 >> 2));
+        x32 = (x32 - ((x54 & ~x10) + (x76 & x10) + xkey[4*i+1])) & 0xFFFF;
+
+        x10 = ((x10 << 15) | (x10 >> 1));
+        x10 = (x10 - ((x32 & ~x76) + (x54 & x76) + xkey[4*i+0])) & 0xFFFF;
+    }
+
+    pt[0] = (unsigned char)x10;
+    pt[1] = (unsigned char)(x10 >> 8);
+    pt[2] = (unsigned char)x32;
+    pt[3] = (unsigned char)(x32 >> 8);
+    pt[4] = (unsigned char)x54;
+    pt[5] = (unsigned char)(x54 >> 8);
+    pt[6] = (unsigned char)x76;
+    pt[7] = (unsigned char)(x76 >> 8);
+
+    return CRYPT_OK;
+}
+
+#ifdef LTC_CLEAN_STACK
+int rc2_ecb_decrypt( const unsigned char *ct,
+                            unsigned char *pt,
+                            symmetric_key *skey)
+{
+    int err = _rc2_ecb_decrypt(ct, pt, skey);
+    burn_stack(sizeof(unsigned *) + sizeof(unsigned) * 4 + sizeof(int));
+    return err;
+}
+#endif
+
+/**
+  Performs a self-test of the RC2 block cipher
+  @return CRYPT_OK if functional, CRYPT_NOP if self-test has been disabled
+*/
+int rc2_test(void)
+{
+ #ifndef LTC_TEST
+    return CRYPT_NOP;
+ #else
+   static const struct {
+        int keylen, bits;
+        unsigned char key[16], pt[8], ct[8];
+   } tests[] = {
+
+   { 8, 63,
+     { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+     { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+     { 0xeb, 0xb7, 0x73, 0xf9, 0x93, 0x27, 0x8e, 0xff }
+   },
+   { 8, 64,
+     { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+     { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
+     { 0x27, 0x8b, 0x27, 0xe4, 0x2e, 0x2f, 0x0d, 0x49 }
+   },
+   { 8, 64,
+     { 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+     { 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 },
+     { 0x30, 0x64, 0x9e, 0xdf, 0x9b, 0xe7, 0xd2, 0xc2 }
+   },
+   { 1, 64,
+     { 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+     { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+     { 0x61, 0xa8, 0xa2, 0x44, 0xad, 0xac, 0xcc, 0xf0 }
+   },
+   { 7, 64,
+     { 0x88, 0xbc, 0xa9, 0x0e, 0x90, 0x87, 0x5a, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+     { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+     { 0x6c, 0xcf, 0x43, 0x08, 0x97, 0x4c, 0x26, 0x7f }
+   },
+   { 16, 64,
+     { 0x88, 0xbc, 0xa9, 0x0e, 0x90, 0x87, 0x5a, 0x7f,
+       0x0f, 0x79, 0xc3, 0x84, 0x62, 0x7b, 0xaf, 0xb2 },
+     { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+     { 0x1a, 0x80, 0x7d, 0x27, 0x2b, 0xbe, 0x5d, 0xb1 }
+   },
+   { 16, 128,
+     { 0x88, 0xbc, 0xa9, 0x0e, 0x90, 0x87, 0x5a, 0x7f,
+       0x0f, 0x79, 0xc3, 0x84, 0x62, 0x7b, 0xaf, 0xb2 },
+     { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+     { 0x22, 0x69, 0x55, 0x2a, 0xb0, 0xf8, 0x5c, 0xa6 }
+   }
+  };
+    int x, y, err;
+    symmetric_key skey;
+    unsigned char tmp[2][8];
+
+    for (x = 0; x < (int)(sizeof(tests) / sizeof(tests[0])); x++) {
+        zeromem(tmp, sizeof(tmp));
+        if (tests[x].bits == (tests[x].keylen * 8)) {
+           if ((err = rc2_setup(tests[x].key, tests[x].keylen, 0, &skey)) != CRYPT_OK) {
+              return err;
+           }
+        }
+        else {
+           if ((err = rc2_setup_ex(tests[x].key, tests[x].keylen, tests[x].bits, 0, &skey)) != CRYPT_OK) {
+              return err;
+           }
+        }
+
+        rc2_ecb_encrypt(tests[x].pt, tmp[0], &skey);
+        rc2_ecb_decrypt(tmp[0], tmp[1], &skey);
+
+        if (compare_testvector(tmp[0], 8, tests[x].ct, 8, "RC2 CT", x) ||
+              compare_testvector(tmp[1], 8, tests[x].pt, 8, "RC2 PT", x)) {
+           return CRYPT_FAIL_TESTVECTOR;
+        }
+
+      /* now see if we can encrypt all zero bytes 1000 times, decrypt and come back where we started */
+      for (y = 0; y < 8; y++) tmp[0][y] = 0;
+      for (y = 0; y < 1000; y++) rc2_ecb_encrypt(tmp[0], tmp[0], &skey);
+      for (y = 0; y < 1000; y++) rc2_ecb_decrypt(tmp[0], tmp[0], &skey);
+      for (y = 0; y < 8; y++) if (tmp[0][y] != 0) return CRYPT_FAIL_TESTVECTOR;
+    }
+    return CRYPT_OK;
+   #endif
+}
+
+/** Terminate the context
+   @param skey    The scheduled key
+*/
+void rc2_done(symmetric_key *skey)
+{
+  LTC_UNUSED_PARAM(skey);
+}
+
+/**
+  Gets suitable key size
+  @param keysize [in/out] The length of the recommended key (in bytes).  This function will store the suitable size back in this variable.
+  @return CRYPT_OK if the input key size is acceptable.
+*/
+int rc2_keysize(int *keysize)
+{
+   LTC_ARGCHK(keysize != NULL);
+   if (*keysize < 1) {
+       return CRYPT_INVALID_KEYSIZE;
+   } else if (*keysize > 128) {
+       *keysize = 128;
+   }
+   return CRYPT_OK;
+}
+
+#endif
+
+
+
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/ciphers/rc5.c b/libtomcrypt/src/ciphers/rc5.c
new file mode 100644 (file)
index 0000000..bda537f
--- /dev/null
@@ -0,0 +1,322 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+/**
+   @file rc5.c
+   LTC_RC5 code by Tom St Denis
+*/
+
+#include "tomcrypt.h"
+
+#ifdef LTC_RC5
+
+const struct ltc_cipher_descriptor rc5_desc =
+{
+    "rc5",
+    2,
+    8, 128, 8, 12,
+    &rc5_setup,
+    &rc5_ecb_encrypt,
+    &rc5_ecb_decrypt,
+    &rc5_test,
+    &rc5_done,
+    &rc5_keysize,
+    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
+};
+
+static const ulong32 stab[50] = {
+0xb7e15163UL, 0x5618cb1cUL, 0xf45044d5UL, 0x9287be8eUL, 0x30bf3847UL, 0xcef6b200UL, 0x6d2e2bb9UL, 0x0b65a572UL,
+0xa99d1f2bUL, 0x47d498e4UL, 0xe60c129dUL, 0x84438c56UL, 0x227b060fUL, 0xc0b27fc8UL, 0x5ee9f981UL, 0xfd21733aUL,
+0x9b58ecf3UL, 0x399066acUL, 0xd7c7e065UL, 0x75ff5a1eUL, 0x1436d3d7UL, 0xb26e4d90UL, 0x50a5c749UL, 0xeedd4102UL,
+0x8d14babbUL, 0x2b4c3474UL, 0xc983ae2dUL, 0x67bb27e6UL, 0x05f2a19fUL, 0xa42a1b58UL, 0x42619511UL, 0xe0990ecaUL,
+0x7ed08883UL, 0x1d08023cUL, 0xbb3f7bf5UL, 0x5976f5aeUL, 0xf7ae6f67UL, 0x95e5e920UL, 0x341d62d9UL, 0xd254dc92UL,
+0x708c564bUL, 0x0ec3d004UL, 0xacfb49bdUL, 0x4b32c376UL, 0xe96a3d2fUL, 0x87a1b6e8UL, 0x25d930a1UL, 0xc410aa5aUL,
+0x62482413UL, 0x007f9dccUL
+};
+
+ /**
+    Initialize the LTC_RC5 block cipher
+    @param key The symmetric key you wish to pass
+    @param keylen The key length in bytes
+    @param num_rounds The number of rounds desired (0 for default)
+    @param skey The key in as scheduled by this function.
+    @return CRYPT_OK if successful
+ */
+#ifdef LTC_CLEAN_STACK
+static int _rc5_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey)
+#else
+int rc5_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey)
+#endif
+{
+    ulong32 L[64], *S, A, B, i, j, v, s, t, l;
+
+    LTC_ARGCHK(skey != NULL);
+    LTC_ARGCHK(key  != NULL);
+
+    /* test parameters */
+    if (num_rounds == 0) {
+       num_rounds = rc5_desc.default_rounds;
+    }
+
+    if (num_rounds < 12 || num_rounds > 24) {
+       return CRYPT_INVALID_ROUNDS;
+    }
+
+    /* key must be between 64 and 1024 bits */
+    if (keylen < 8 || keylen > 128) {
+       return CRYPT_INVALID_KEYSIZE;
+    }
+
+    skey->rc5.rounds = num_rounds;
+    S = skey->rc5.K;
+
+    /* copy the key into the L array */
+    for (A = i = j = 0; i < (ulong32)keylen; ) {
+        A = (A << 8) | ((ulong32)(key[i++] & 255));
+        if ((i & 3) == 0) {
+           L[j++] = BSWAP(A);
+           A = 0;
+        }
+    }
+
+    if ((keylen & 3) != 0) {
+       A <<= (ulong32)((8 * (4 - (keylen&3))));
+       L[j++] = BSWAP(A);
+    }
+
+    /* setup the S array */
+    t = (ulong32)(2 * (num_rounds + 1));
+    XMEMCPY(S, stab, t * sizeof(*S));
+
+    /* mix buffer */
+    s = 3 * MAX(t, j);
+    l = j;
+    for (A = B = i = j = v = 0; v < s; v++) {
+        A = S[i] = ROLc(S[i] + A + B, 3);
+        B = L[j] = ROL(L[j] + A + B, (A+B));
+        if (++i == t) { i = 0; }
+        if (++j == l) { j = 0; }
+    }
+    return CRYPT_OK;
+}
+
+#ifdef LTC_CLEAN_STACK
+int rc5_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey)
+{
+   int x;
+   x = _rc5_setup(key, keylen, num_rounds, skey);
+   burn_stack(sizeof(ulong32) * 122 + sizeof(int));
+   return x;
+}
+#endif
+
+/**
+  Encrypts a block of text with LTC_RC5
+  @param pt The input plaintext (8 bytes)
+  @param ct The output ciphertext (8 bytes)
+  @param skey The key as scheduled
+  @return CRYPT_OK if successful
+*/
+#ifdef LTC_CLEAN_STACK
+static int _rc5_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey)
+#else
+int rc5_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey)
+#endif
+{
+   ulong32 A, B, *K;
+   int r;
+   LTC_ARGCHK(skey != NULL);
+   LTC_ARGCHK(pt   != NULL);
+   LTC_ARGCHK(ct   != NULL);
+
+   LOAD32L(A, &pt[0]);
+   LOAD32L(B, &pt[4]);
+   A += skey->rc5.K[0];
+   B += skey->rc5.K[1];
+   K  = skey->rc5.K + 2;
+
+   if ((skey->rc5.rounds & 1) == 0) {
+      for (r = 0; r < skey->rc5.rounds; r += 2) {
+          A = ROL(A ^ B, B) + K[0];
+          B = ROL(B ^ A, A) + K[1];
+          A = ROL(A ^ B, B) + K[2];
+          B = ROL(B ^ A, A) + K[3];
+          K += 4;
+      }
+   } else {
+      for (r = 0; r < skey->rc5.rounds; r++) {
+          A = ROL(A ^ B, B) + K[0];
+          B = ROL(B ^ A, A) + K[1];
+          K += 2;
+      }
+   }
+   STORE32L(A, &ct[0]);
+   STORE32L(B, &ct[4]);
+
+   return CRYPT_OK;
+}
+
+#ifdef LTC_CLEAN_STACK
+int rc5_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey)
+{
+   int err = _rc5_ecb_encrypt(pt, ct, skey);
+   burn_stack(sizeof(ulong32) * 2 + sizeof(int));
+   return err;
+}
+#endif
+
+/**
+  Decrypts a block of text with LTC_RC5
+  @param ct The input ciphertext (8 bytes)
+  @param pt The output plaintext (8 bytes)
+  @param skey The key as scheduled
+  @return CRYPT_OK if successful
+*/
+#ifdef LTC_CLEAN_STACK
+static int _rc5_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey)
+#else
+int rc5_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey)
+#endif
+{
+   ulong32 A, B, *K;
+   int r;
+   LTC_ARGCHK(skey != NULL);
+   LTC_ARGCHK(pt   != NULL);
+   LTC_ARGCHK(ct   != NULL);
+
+   LOAD32L(A, &ct[0]);
+   LOAD32L(B, &ct[4]);
+   K = skey->rc5.K + (skey->rc5.rounds << 1);
+
+   if ((skey->rc5.rounds & 1) == 0) {
+       K -= 2;
+       for (r = skey->rc5.rounds - 1; r >= 0; r -= 2) {
+          B = ROR(B - K[3], A) ^ A;
+          A = ROR(A - K[2], B) ^ B;
+          B = ROR(B - K[1], A) ^ A;
+          A = ROR(A - K[0], B) ^ B;
+          K -= 4;
+        }
+   } else {
+      for (r = skey->rc5.rounds - 1; r >= 0; r--) {
+          B = ROR(B - K[1], A) ^ A;
+          A = ROR(A - K[0], B) ^ B;
+          K -= 2;
+      }
+   }
+   A -= skey->rc5.K[0];
+   B -= skey->rc5.K[1];
+   STORE32L(A, &pt[0]);
+   STORE32L(B, &pt[4]);
+
+   return CRYPT_OK;
+}
+
+#ifdef LTC_CLEAN_STACK
+int rc5_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey)
+{
+   int err = _rc5_ecb_decrypt(ct, pt, skey);
+   burn_stack(sizeof(ulong32) * 2 + sizeof(int));
+   return err;
+}
+#endif
+
+/**
+  Performs a self-test of the LTC_RC5 block cipher
+  @return CRYPT_OK if functional, CRYPT_NOP if self-test has been disabled
+*/
+int rc5_test(void)
+{
+ #ifndef LTC_TEST
+    return CRYPT_NOP;
+ #else
+   static const struct {
+       unsigned char key[16], pt[8], ct[8];
+   } tests[] = {
+   {
+       { 0x91, 0x5f, 0x46, 0x19, 0xbe, 0x41, 0xb2, 0x51,
+         0x63, 0x55, 0xa5, 0x01, 0x10, 0xa9, 0xce, 0x91 },
+       { 0x21, 0xa5, 0xdb, 0xee, 0x15, 0x4b, 0x8f, 0x6d },
+       { 0xf7, 0xc0, 0x13, 0xac, 0x5b, 0x2b, 0x89, 0x52 }
+   },
+   {
+       { 0x78, 0x33, 0x48, 0xe7, 0x5a, 0xeb, 0x0f, 0x2f,
+         0xd7, 0xb1, 0x69, 0xbb, 0x8d, 0xc1, 0x67, 0x87 },
+       { 0xF7, 0xC0, 0x13, 0xAC, 0x5B, 0x2B, 0x89, 0x52 },
+       { 0x2F, 0x42, 0xB3, 0xB7, 0x03, 0x69, 0xFC, 0x92 }
+   },
+   {
+       { 0xDC, 0x49, 0xdb, 0x13, 0x75, 0xa5, 0x58, 0x4f,
+         0x64, 0x85, 0xb4, 0x13, 0xb5, 0xf1, 0x2b, 0xaf },
+       { 0x2F, 0x42, 0xB3, 0xB7, 0x03, 0x69, 0xFC, 0x92 },
+       { 0x65, 0xc1, 0x78, 0xb2, 0x84, 0xd1, 0x97, 0xcc }
+   }
+   };
+   unsigned char tmp[2][8];
+   int x, y, err;
+   symmetric_key key;
+
+   for (x = 0; x < (int)(sizeof(tests) / sizeof(tests[0])); x++) {
+      /* setup key */
+      if ((err = rc5_setup(tests[x].key, 16, 12, &key)) != CRYPT_OK) {
+         return err;
+      }
+
+      /* encrypt and decrypt */
+      rc5_ecb_encrypt(tests[x].pt, tmp[0], &key);
+      rc5_ecb_decrypt(tmp[0], tmp[1], &key);
+
+      /* compare */
+      if (compare_testvector(tmp[0], 8, tests[x].ct, 8, "RC5 Encrypt", x) != 0 ||
+            compare_testvector(tmp[1], 8, tests[x].pt, 8, "RC5 Decrypt", x) != 0) {
+         return CRYPT_FAIL_TESTVECTOR;
+      }
+
+      /* now see if we can encrypt all zero bytes 1000 times, decrypt and come back where we started */
+      for (y = 0; y < 8; y++) tmp[0][y] = 0;
+      for (y = 0; y < 1000; y++) rc5_ecb_encrypt(tmp[0], tmp[0], &key);
+      for (y = 0; y < 1000; y++) rc5_ecb_decrypt(tmp[0], tmp[0], &key);
+      for (y = 0; y < 8; y++) if (tmp[0][y] != 0) return CRYPT_FAIL_TESTVECTOR;
+   }
+   return CRYPT_OK;
+  #endif
+}
+
+/** Terminate the context
+   @param skey    The scheduled key
+*/
+void rc5_done(symmetric_key *skey)
+{
+  LTC_UNUSED_PARAM(skey);
+}
+
+/**
+  Gets suitable key size
+  @param keysize [in/out] The length of the recommended key (in bytes).  This function will store the suitable size back in this variable.
+  @return CRYPT_OK if the input key size is acceptable.
+*/
+int rc5_keysize(int *keysize)
+{
+   LTC_ARGCHK(keysize != NULL);
+   if (*keysize < 8) {
+      return CRYPT_INVALID_KEYSIZE;
+   } else if (*keysize > 128) {
+      *keysize = 128;
+   }
+   return CRYPT_OK;
+}
+
+#endif
+
+
+
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/ciphers/rc6.c b/libtomcrypt/src/ciphers/rc6.c
new file mode 100644 (file)
index 0000000..56ca705
--- /dev/null
@@ -0,0 +1,331 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+/**
+   @file rc6.c
+   LTC_RC6 code by Tom St Denis
+*/
+#include "tomcrypt.h"
+
+#ifdef LTC_RC6
+
+const struct ltc_cipher_descriptor rc6_desc =
+{
+    "rc6",
+    3,
+    8, 128, 16, 20,
+    &rc6_setup,
+    &rc6_ecb_encrypt,
+    &rc6_ecb_decrypt,
+    &rc6_test,
+    &rc6_done,
+    &rc6_keysize,
+    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
+};
+
+static const ulong32 stab[44] = {
+0xb7e15163UL, 0x5618cb1cUL, 0xf45044d5UL, 0x9287be8eUL, 0x30bf3847UL, 0xcef6b200UL, 0x6d2e2bb9UL, 0x0b65a572UL,
+0xa99d1f2bUL, 0x47d498e4UL, 0xe60c129dUL, 0x84438c56UL, 0x227b060fUL, 0xc0b27fc8UL, 0x5ee9f981UL, 0xfd21733aUL,
+0x9b58ecf3UL, 0x399066acUL, 0xd7c7e065UL, 0x75ff5a1eUL, 0x1436d3d7UL, 0xb26e4d90UL, 0x50a5c749UL, 0xeedd4102UL,
+0x8d14babbUL, 0x2b4c3474UL, 0xc983ae2dUL, 0x67bb27e6UL, 0x05f2a19fUL, 0xa42a1b58UL, 0x42619511UL, 0xe0990ecaUL,
+0x7ed08883UL, 0x1d08023cUL, 0xbb3f7bf5UL, 0x5976f5aeUL, 0xf7ae6f67UL, 0x95e5e920UL, 0x341d62d9UL, 0xd254dc92UL,
+0x708c564bUL, 0x0ec3d004UL, 0xacfb49bdUL, 0x4b32c376UL };
+
+ /**
+    Initialize the LTC_RC6 block cipher
+    @param key The symmetric key you wish to pass
+    @param keylen The key length in bytes
+    @param num_rounds The number of rounds desired (0 for default)
+    @param skey The key in as scheduled by this function.
+    @return CRYPT_OK if successful
+ */
+#ifdef LTC_CLEAN_STACK
+static int _rc6_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey)
+#else
+int rc6_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey)
+#endif
+{
+    ulong32 L[64], S[50], A, B, i, j, v, s, l;
+
+    LTC_ARGCHK(key != NULL);
+    LTC_ARGCHK(skey != NULL);
+
+    /* test parameters */
+    if (num_rounds != 0 && num_rounds != 20) {
+       return CRYPT_INVALID_ROUNDS;
+    }
+
+    /* key must be between 64 and 1024 bits */
+    if (keylen < 8 || keylen > 128) {
+       return CRYPT_INVALID_KEYSIZE;
+    }
+
+    /* copy the key into the L array */
+    for (A = i = j = 0; i < (ulong32)keylen; ) {
+        A = (A << 8) | ((ulong32)(key[i++] & 255));
+        if (!(i & 3)) {
+           L[j++] = BSWAP(A);
+           A = 0;
+        }
+    }
+
+    /* handle odd sized keys */
+    if (keylen & 3) {
+       A <<= (8 * (4 - (keylen&3)));
+       L[j++] = BSWAP(A);
+    }
+
+    /* setup the S array */
+    XMEMCPY(S, stab, 44 * sizeof(stab[0]));
+
+    /* mix buffer */
+    s = 3 * MAX(44, j);
+    l = j;
+    for (A = B = i = j = v = 0; v < s; v++) {
+        A = S[i] = ROLc(S[i] + A + B, 3);
+        B = L[j] = ROL(L[j] + A + B, (A+B));
+        if (++i == 44) { i = 0; }
+        if (++j == l)  { j = 0; }
+    }
+
+    /* copy to key */
+    for (i = 0; i < 44; i++) {
+        skey->rc6.K[i] = S[i];
+    }
+    return CRYPT_OK;
+}
+
+#ifdef LTC_CLEAN_STACK
+int rc6_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey)
+{
+   int x;
+   x = _rc6_setup(key, keylen, num_rounds, skey);
+   burn_stack(sizeof(ulong32) * 122);
+   return x;
+}
+#endif
+
+/**
+  Encrypts a block of text with LTC_RC6
+  @param pt The input plaintext (16 bytes)
+  @param ct The output ciphertext (16 bytes)
+  @param skey The key as scheduled
+*/
+#ifdef LTC_CLEAN_STACK
+static int _rc6_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey)
+#else
+int rc6_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey)
+#endif
+{
+   ulong32 a,b,c,d,t,u, *K;
+   int r;
+
+   LTC_ARGCHK(skey != NULL);
+   LTC_ARGCHK(pt   != NULL);
+   LTC_ARGCHK(ct   != NULL);
+   LOAD32L(a,&pt[0]);LOAD32L(b,&pt[4]);LOAD32L(c,&pt[8]);LOAD32L(d,&pt[12]);
+
+   b += skey->rc6.K[0];
+   d += skey->rc6.K[1];
+
+#define RND(a,b,c,d) \
+       t = (b * (b + b + 1)); t = ROLc(t, 5); \
+       u = (d * (d + d + 1)); u = ROLc(u, 5); \
+       a = ROL(a^t,u) + K[0];                \
+       c = ROL(c^u,t) + K[1]; K += 2;
+
+   K = skey->rc6.K + 2;
+   for (r = 0; r < 20; r += 4) {
+       RND(a,b,c,d);
+       RND(b,c,d,a);
+       RND(c,d,a,b);
+       RND(d,a,b,c);
+   }
+
+#undef RND
+
+   a += skey->rc6.K[42];
+   c += skey->rc6.K[43];
+   STORE32L(a,&ct[0]);STORE32L(b,&ct[4]);STORE32L(c,&ct[8]);STORE32L(d,&ct[12]);
+   return CRYPT_OK;
+}
+
+#ifdef LTC_CLEAN_STACK
+int rc6_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey)
+{
+   int err = _rc6_ecb_encrypt(pt, ct, skey);
+   burn_stack(sizeof(ulong32) * 6 + sizeof(int));
+   return err;
+}
+#endif
+
+/**
+  Decrypts a block of text with LTC_RC6
+  @param ct The input ciphertext (16 bytes)
+  @param pt The output plaintext (16 bytes)
+  @param skey The key as scheduled
+*/
+#ifdef LTC_CLEAN_STACK
+static int _rc6_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey)
+#else
+int rc6_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey)
+#endif
+{
+   ulong32 a,b,c,d,t,u, *K;
+   int r;
+
+   LTC_ARGCHK(skey != NULL);
+   LTC_ARGCHK(pt   != NULL);
+   LTC_ARGCHK(ct   != NULL);
+
+   LOAD32L(a,&ct[0]);LOAD32L(b,&ct[4]);LOAD32L(c,&ct[8]);LOAD32L(d,&ct[12]);
+   a -= skey->rc6.K[42];
+   c -= skey->rc6.K[43];
+
+#define RND(a,b,c,d) \
+       t = (b * (b + b + 1)); t = ROLc(t, 5); \
+       u = (d * (d + d + 1)); u = ROLc(u, 5); \
+       c = ROR(c - K[1], t) ^ u; \
+       a = ROR(a - K[0], u) ^ t; K -= 2;
+
+   K = skey->rc6.K + 40;
+
+   for (r = 0; r < 20; r += 4) {
+       RND(d,a,b,c);
+       RND(c,d,a,b);
+       RND(b,c,d,a);
+       RND(a,b,c,d);
+   }
+
+#undef RND
+
+   b -= skey->rc6.K[0];
+   d -= skey->rc6.K[1];
+   STORE32L(a,&pt[0]);STORE32L(b,&pt[4]);STORE32L(c,&pt[8]);STORE32L(d,&pt[12]);
+
+   return CRYPT_OK;
+}
+
+#ifdef LTC_CLEAN_STACK
+int rc6_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey)
+{
+   int err = _rc6_ecb_decrypt(ct, pt, skey);
+   burn_stack(sizeof(ulong32) * 6 + sizeof(int));
+   return err;
+}
+#endif
+
+/**
+  Performs a self-test of the LTC_RC6 block cipher
+  @return CRYPT_OK if functional, CRYPT_NOP if self-test has been disabled
+*/
+int rc6_test(void)
+{
+ #ifndef LTC_TEST
+    return CRYPT_NOP;
+ #else
+   static const struct {
+       int keylen;
+       unsigned char key[32], pt[16], ct[16];
+   } tests[] = {
+   {
+       16,
+       { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
+         0x01, 0x12, 0x23, 0x34, 0x45, 0x56, 0x67, 0x78,
+         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+       { 0x02, 0x13, 0x24, 0x35, 0x46, 0x57, 0x68, 0x79,
+         0x8a, 0x9b, 0xac, 0xbd, 0xce, 0xdf, 0xe0, 0xf1 },
+       { 0x52, 0x4e, 0x19, 0x2f, 0x47, 0x15, 0xc6, 0x23,
+         0x1f, 0x51, 0xf6, 0x36, 0x7e, 0xa4, 0x3f, 0x18 }
+   },
+   {
+       24,
+       { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
+         0x01, 0x12, 0x23, 0x34, 0x45, 0x56, 0x67, 0x78,
+         0x89, 0x9a, 0xab, 0xbc, 0xcd, 0xde, 0xef, 0xf0,
+         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+       { 0x02, 0x13, 0x24, 0x35, 0x46, 0x57, 0x68, 0x79,
+         0x8a, 0x9b, 0xac, 0xbd, 0xce, 0xdf, 0xe0, 0xf1 },
+       { 0x68, 0x83, 0x29, 0xd0, 0x19, 0xe5, 0x05, 0x04,
+         0x1e, 0x52, 0xe9, 0x2a, 0xf9, 0x52, 0x91, 0xd4 }
+   },
+   {
+       32,
+       { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
+         0x01, 0x12, 0x23, 0x34, 0x45, 0x56, 0x67, 0x78,
+         0x89, 0x9a, 0xab, 0xbc, 0xcd, 0xde, 0xef, 0xf0,
+         0x10, 0x32, 0x54, 0x76, 0x98, 0xba, 0xdc, 0xfe },
+       { 0x02, 0x13, 0x24, 0x35, 0x46, 0x57, 0x68, 0x79,
+         0x8a, 0x9b, 0xac, 0xbd, 0xce, 0xdf, 0xe0, 0xf1 },
+       { 0xc8, 0x24, 0x18, 0x16, 0xf0, 0xd7, 0xe4, 0x89,
+         0x20, 0xad, 0x16, 0xa1, 0x67, 0x4e, 0x5d, 0x48 }
+   }
+   };
+   unsigned char tmp[2][16];
+   int x, y, err;
+   symmetric_key key;
+
+   for (x  = 0; x < (int)(sizeof(tests) / sizeof(tests[0])); x++) {
+      /* setup key */
+      if ((err = rc6_setup(tests[x].key, tests[x].keylen, 0, &key)) != CRYPT_OK) {
+         return err;
+      }
+
+      /* encrypt and decrypt */
+      rc6_ecb_encrypt(tests[x].pt, tmp[0], &key);
+      rc6_ecb_decrypt(tmp[0], tmp[1], &key);
+
+      /* compare */
+      if (compare_testvector(tmp[0], 16, tests[x].ct, 16, "RC6 Encrypt", x) ||
+            compare_testvector(tmp[1], 16, tests[x].pt, 16, "RC6 Decrypt", x)) {
+         return CRYPT_FAIL_TESTVECTOR;
+      }
+
+      /* now see if we can encrypt all zero bytes 1000 times, decrypt and come back where we started */
+      for (y = 0; y < 16; y++) tmp[0][y] = 0;
+      for (y = 0; y < 1000; y++) rc6_ecb_encrypt(tmp[0], tmp[0], &key);
+      for (y = 0; y < 1000; y++) rc6_ecb_decrypt(tmp[0], tmp[0], &key);
+      for (y = 0; y < 16; y++) if (tmp[0][y] != 0) return CRYPT_FAIL_TESTVECTOR;
+   }
+   return CRYPT_OK;
+  #endif
+}
+
+/** Terminate the context
+   @param skey    The scheduled key
+*/
+void rc6_done(symmetric_key *skey)
+{
+  LTC_UNUSED_PARAM(skey);
+}
+
+/**
+  Gets suitable key size
+  @param keysize [in/out] The length of the recommended key (in bytes).  This function will store the suitable size back in this variable.
+  @return CRYPT_OK if the input key size is acceptable.
+*/
+int rc6_keysize(int *keysize)
+{
+   LTC_ARGCHK(keysize != NULL);
+   if (*keysize < 8) {
+      return CRYPT_INVALID_KEYSIZE;
+   } else if (*keysize > 128) {
+      *keysize = 128;
+   }
+   return CRYPT_OK;
+}
+
+#endif /*LTC_RC6*/
+
+
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/ciphers/safer/safer.c b/libtomcrypt/src/ciphers/safer/safer.c
new file mode 100644 (file)
index 0000000..9eefcfb
--- /dev/null
@@ -0,0 +1,495 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+/*******************************************************************************
+*
+* FILE:           safer.c
+*
+* LTC_DESCRIPTION:    block-cipher algorithm LTC_SAFER (Secure And Fast Encryption
+*                 Routine) in its four versions: LTC_SAFER K-64, LTC_SAFER K-128,
+*                 LTC_SAFER SK-64 and LTC_SAFER SK-128.
+*
+* AUTHOR:         Richard De Moliner (demoliner@isi.ee.ethz.ch)
+*                 Signal and Information Processing Laboratory
+*                 Swiss Federal Institute of Technology
+*                 CH-8092 Zuerich, Switzerland
+*
+* DATE:           September 9, 1995
+*
+* CHANGE HISTORY:
+*
+*******************************************************************************/
+
+#include "tomcrypt.h"
+
+#ifdef LTC_SAFER
+
+#define __LTC_SAFER_TAB_C__
+#include "safer_tab.c"
+
+const struct ltc_cipher_descriptor safer_k64_desc = {
+   "safer-k64",
+   8, 8, 8, 8, LTC_SAFER_K64_DEFAULT_NOF_ROUNDS,
+   &safer_k64_setup,
+   &safer_ecb_encrypt,
+   &safer_ecb_decrypt,
+   &safer_k64_test,
+   &safer_done,
+   &safer_64_keysize,
+   NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
+   },
+
+   safer_sk64_desc = {
+   "safer-sk64",
+   9, 8, 8, 8, LTC_SAFER_SK64_DEFAULT_NOF_ROUNDS,
+   &safer_sk64_setup,
+   &safer_ecb_encrypt,
+   &safer_ecb_decrypt,
+   &safer_sk64_test,
+   &safer_done,
+   &safer_64_keysize,
+   NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
+   },
+
+   safer_k128_desc = {
+   "safer-k128",
+   10, 16, 16, 8, LTC_SAFER_K128_DEFAULT_NOF_ROUNDS,
+   &safer_k128_setup,
+   &safer_ecb_encrypt,
+   &safer_ecb_decrypt,
+   &safer_sk128_test,
+   &safer_done,
+   &safer_128_keysize,
+   NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
+   },
+
+   safer_sk128_desc = {
+   "safer-sk128",
+   11, 16, 16, 8, LTC_SAFER_SK128_DEFAULT_NOF_ROUNDS,
+   &safer_sk128_setup,
+   &safer_ecb_encrypt,
+   &safer_ecb_decrypt,
+   &safer_sk128_test,
+   &safer_done,
+   &safer_128_keysize,
+   NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
+   };
+
+/******************* Constants ************************************************/
+/* #define TAB_LEN      256  */
+
+/******************* Assertions ***********************************************/
+
+/******************* Macros ***************************************************/
+#define ROL8(x, n)   ((unsigned char)((unsigned int)(x) << (n)\
+                                     |(unsigned int)((x) & 0xFF) >> (8 - (n))))
+#define EXP(x)       safer_ebox[(x) & 0xFF]
+#define LOG(x)       safer_lbox[(x) & 0xFF]
+#define PHT(x, y)    { y += x; x += y; }
+#define IPHT(x, y)   { x -= y; y -= x; }
+
+/******************* Types ****************************************************/
+
+#ifdef LTC_CLEAN_STACK
+static void _Safer_Expand_Userkey(const unsigned char *userkey_1,
+                                 const unsigned char *userkey_2,
+                                 unsigned int nof_rounds,
+                                 int strengthened,
+                                 safer_key_t key)
+#else
+static void Safer_Expand_Userkey(const unsigned char *userkey_1,
+                                 const unsigned char *userkey_2,
+                                 unsigned int nof_rounds,
+                                 int strengthened,
+                                 safer_key_t key)
+#endif
+{   unsigned int i, j, k;
+    unsigned char ka[LTC_SAFER_BLOCK_LEN + 1];
+    unsigned char kb[LTC_SAFER_BLOCK_LEN + 1];
+
+    if (LTC_SAFER_MAX_NOF_ROUNDS < nof_rounds)
+        nof_rounds = LTC_SAFER_MAX_NOF_ROUNDS;
+    *key++ = (unsigned char)nof_rounds;
+    ka[LTC_SAFER_BLOCK_LEN] = (unsigned char)0;
+    kb[LTC_SAFER_BLOCK_LEN] = (unsigned char)0;
+    k = 0;
+    for (j = 0; j < LTC_SAFER_BLOCK_LEN; j++) {
+        ka[j] = ROL8(userkey_1[j], 5);
+        ka[LTC_SAFER_BLOCK_LEN] ^= ka[j];
+        kb[j] = *key++ = userkey_2[j];
+        kb[LTC_SAFER_BLOCK_LEN] ^= kb[j];
+    }
+    for (i = 1; i <= nof_rounds; i++) {
+        for (j = 0; j < LTC_SAFER_BLOCK_LEN + 1; j++) {
+            ka[j] = ROL8(ka[j], 6);
+            kb[j] = ROL8(kb[j], 6);
+        }
+        if (strengthened) {
+           k = 2 * i - 1;
+           while (k >= (LTC_SAFER_BLOCK_LEN + 1)) { k -= LTC_SAFER_BLOCK_LEN + 1; }
+        }
+        for (j = 0; j < LTC_SAFER_BLOCK_LEN; j++) {
+            if (strengthened) {
+                *key++ = (ka[k]
+                                + safer_ebox[(int)safer_ebox[(int)((18 * i + j + 1)&0xFF)]]) & 0xFF;
+                if (++k == (LTC_SAFER_BLOCK_LEN + 1)) { k = 0; }
+            } else {
+                *key++ = (ka[j] + safer_ebox[(int)safer_ebox[(int)((18 * i + j + 1)&0xFF)]]) & 0xFF;
+            }
+        }
+        if (strengthened) {
+           k = 2 * i;
+           while (k >= (LTC_SAFER_BLOCK_LEN + 1)) { k -= LTC_SAFER_BLOCK_LEN + 1; }
+        }
+        for (j = 0; j < LTC_SAFER_BLOCK_LEN; j++) {
+            if (strengthened) {
+                *key++ = (kb[k]
+                                + safer_ebox[(int)safer_ebox[(int)((18 * i + j + 10)&0xFF)]]) & 0xFF;
+                if (++k == (LTC_SAFER_BLOCK_LEN + 1)) { k = 0; }
+            } else {
+                *key++ = (kb[j] + safer_ebox[(int)safer_ebox[(int)((18 * i + j + 10)&0xFF)]]) & 0xFF;
+            }
+        }
+    }
+
+#ifdef LTC_CLEAN_STACK
+    zeromem(ka, sizeof(ka));
+    zeromem(kb, sizeof(kb));
+#endif
+}
+
+#ifdef LTC_CLEAN_STACK
+static void Safer_Expand_Userkey(const unsigned char *userkey_1,
+                                 const unsigned char *userkey_2,
+                                 unsigned int nof_rounds,
+                                 int strengthened,
+                                 safer_key_t key)
+{
+   _Safer_Expand_Userkey(userkey_1, userkey_2, nof_rounds, strengthened, key);
+   burn_stack(sizeof(unsigned char) * (2 * (LTC_SAFER_BLOCK_LEN + 1)) + sizeof(unsigned int)*2);
+}
+#endif
+
+int safer_k64_setup(const unsigned char *key, int keylen, int numrounds, symmetric_key *skey)
+{
+   LTC_ARGCHK(key != NULL);
+   LTC_ARGCHK(skey != NULL);
+
+   if (numrounds != 0 && (numrounds < 6 || numrounds > LTC_SAFER_MAX_NOF_ROUNDS)) {
+      return CRYPT_INVALID_ROUNDS;
+   }
+
+   if (keylen != 8) {
+      return CRYPT_INVALID_KEYSIZE;
+   }
+
+   Safer_Expand_Userkey(key, key, (unsigned int)(numrounds != 0 ?numrounds:LTC_SAFER_K64_DEFAULT_NOF_ROUNDS), 0, skey->safer.key);
+   return CRYPT_OK;
+}
+
+int safer_sk64_setup(const unsigned char *key, int keylen, int numrounds, symmetric_key *skey)
+{
+   LTC_ARGCHK(key != NULL);
+   LTC_ARGCHK(skey != NULL);
+
+   if (numrounds != 0 && (numrounds < 6 || numrounds > LTC_SAFER_MAX_NOF_ROUNDS)) {
+      return CRYPT_INVALID_ROUNDS;
+   }
+
+   if (keylen != 8) {
+      return CRYPT_INVALID_KEYSIZE;
+   }
+
+   Safer_Expand_Userkey(key, key, (unsigned int)(numrounds != 0 ?numrounds:LTC_SAFER_SK64_DEFAULT_NOF_ROUNDS), 1, skey->safer.key);
+   return CRYPT_OK;
+}
+
+int safer_k128_setup(const unsigned char *key, int keylen, int numrounds, symmetric_key *skey)
+{
+   LTC_ARGCHK(key != NULL);
+   LTC_ARGCHK(skey != NULL);
+
+   if (numrounds != 0 && (numrounds < 6 || numrounds > LTC_SAFER_MAX_NOF_ROUNDS)) {
+      return CRYPT_INVALID_ROUNDS;
+   }
+
+   if (keylen != 16) {
+      return CRYPT_INVALID_KEYSIZE;
+   }
+
+   Safer_Expand_Userkey(key, key+8, (unsigned int)(numrounds != 0 ?numrounds:LTC_SAFER_K128_DEFAULT_NOF_ROUNDS), 0, skey->safer.key);
+   return CRYPT_OK;
+}
+
+int safer_sk128_setup(const unsigned char *key, int keylen, int numrounds, symmetric_key *skey)
+{
+   LTC_ARGCHK(key != NULL);
+   LTC_ARGCHK(skey != NULL);
+
+   if (numrounds != 0 && (numrounds < 6 || numrounds > LTC_SAFER_MAX_NOF_ROUNDS)) {
+      return CRYPT_INVALID_ROUNDS;
+   }
+
+   if (keylen != 16) {
+      return CRYPT_INVALID_KEYSIZE;
+   }
+
+   Safer_Expand_Userkey(key, key+8, (unsigned int)(numrounds != 0?numrounds:LTC_SAFER_SK128_DEFAULT_NOF_ROUNDS), 1, skey->safer.key);
+   return CRYPT_OK;
+}
+
+#ifdef LTC_CLEAN_STACK
+static int _safer_ecb_encrypt(const unsigned char *block_in,
+                             unsigned char *block_out,
+                             symmetric_key *skey)
+#else
+int safer_ecb_encrypt(const unsigned char *block_in,
+                             unsigned char *block_out,
+                             symmetric_key *skey)
+#endif
+{   unsigned char a, b, c, d, e, f, g, h, t;
+    unsigned int round;
+    unsigned char *key;
+
+    LTC_ARGCHK(block_in != NULL);
+    LTC_ARGCHK(block_out != NULL);
+    LTC_ARGCHK(skey != NULL);
+
+    key = skey->safer.key;
+    a = block_in[0]; b = block_in[1]; c = block_in[2]; d = block_in[3];
+    e = block_in[4]; f = block_in[5]; g = block_in[6]; h = block_in[7];
+    if (LTC_SAFER_MAX_NOF_ROUNDS < (round = *key)) round = LTC_SAFER_MAX_NOF_ROUNDS;
+    while(round-- > 0)
+    {
+        a ^= *++key; b += *++key; c += *++key; d ^= *++key;
+        e ^= *++key; f += *++key; g += *++key; h ^= *++key;
+        a = EXP(a) + *++key; b = LOG(b) ^ *++key;
+        c = LOG(c) ^ *++key; d = EXP(d) + *++key;
+        e = EXP(e) + *++key; f = LOG(f) ^ *++key;
+        g = LOG(g) ^ *++key; h = EXP(h) + *++key;
+        PHT(a, b); PHT(c, d); PHT(e, f); PHT(g, h);
+        PHT(a, c); PHT(e, g); PHT(b, d); PHT(f, h);
+        PHT(a, e); PHT(b, f); PHT(c, g); PHT(d, h);
+        t = b; b = e; e = c; c = t; t = d; d = f; f = g; g = t;
+    }
+    a ^= *++key; b += *++key; c += *++key; d ^= *++key;
+    e ^= *++key; f += *++key; g += *++key; h ^= *++key;
+    block_out[0] = a & 0xFF; block_out[1] = b & 0xFF;
+    block_out[2] = c & 0xFF; block_out[3] = d & 0xFF;
+    block_out[4] = e & 0xFF; block_out[5] = f & 0xFF;
+    block_out[6] = g & 0xFF; block_out[7] = h & 0xFF;
+    return CRYPT_OK;
+}
+
+#ifdef LTC_CLEAN_STACK
+int safer_ecb_encrypt(const unsigned char *block_in,
+                             unsigned char *block_out,
+                             symmetric_key *skey)
+{
+    int err = _safer_ecb_encrypt(block_in, block_out, skey);
+    burn_stack(sizeof(unsigned char) * 9 + sizeof(unsigned int) + sizeof(unsigned char *));
+    return err;
+}
+#endif
+
+#ifdef LTC_CLEAN_STACK
+static int _safer_ecb_decrypt(const unsigned char *block_in,
+                             unsigned char *block_out,
+                             symmetric_key *skey)
+#else
+int safer_ecb_decrypt(const unsigned char *block_in,
+                             unsigned char *block_out,
+                             symmetric_key *skey)
+#endif
+{   unsigned char a, b, c, d, e, f, g, h, t;
+    unsigned int round;
+    unsigned char *key;
+
+    LTC_ARGCHK(block_in != NULL);
+    LTC_ARGCHK(block_out != NULL);
+    LTC_ARGCHK(skey != NULL);
+
+    key = skey->safer.key;
+    a = block_in[0]; b = block_in[1]; c = block_in[2]; d = block_in[3];
+    e = block_in[4]; f = block_in[5]; g = block_in[6]; h = block_in[7];
+    if (LTC_SAFER_MAX_NOF_ROUNDS < (round = *key)) round = LTC_SAFER_MAX_NOF_ROUNDS;
+    key += LTC_SAFER_BLOCK_LEN * (1 + 2 * round);
+    h ^= *key; g -= *--key; f -= *--key; e ^= *--key;
+    d ^= *--key; c -= *--key; b -= *--key; a ^= *--key;
+    while (round--)
+    {
+        t = e; e = b; b = c; c = t; t = f; f = d; d = g; g = t;
+        IPHT(a, e); IPHT(b, f); IPHT(c, g); IPHT(d, h);
+        IPHT(a, c); IPHT(e, g); IPHT(b, d); IPHT(f, h);
+        IPHT(a, b); IPHT(c, d); IPHT(e, f); IPHT(g, h);
+        h -= *--key; g ^= *--key; f ^= *--key; e -= *--key;
+        d -= *--key; c ^= *--key; b ^= *--key; a -= *--key;
+        h = LOG(h) ^ *--key; g = EXP(g) - *--key;
+        f = EXP(f) - *--key; e = LOG(e) ^ *--key;
+        d = LOG(d) ^ *--key; c = EXP(c) - *--key;
+        b = EXP(b) - *--key; a = LOG(a) ^ *--key;
+    }
+    block_out[0] = a & 0xFF; block_out[1] = b & 0xFF;
+    block_out[2] = c & 0xFF; block_out[3] = d & 0xFF;
+    block_out[4] = e & 0xFF; block_out[5] = f & 0xFF;
+    block_out[6] = g & 0xFF; block_out[7] = h & 0xFF;
+    return CRYPT_OK;
+}
+
+#ifdef LTC_CLEAN_STACK
+int safer_ecb_decrypt(const unsigned char *block_in,
+                             unsigned char *block_out,
+                             symmetric_key *skey)
+{
+    int err = _safer_ecb_decrypt(block_in, block_out, skey);
+    burn_stack(sizeof(unsigned char) * 9 + sizeof(unsigned int) + sizeof(unsigned char *));
+    return err;
+}
+#endif
+
+int safer_64_keysize(int *keysize)
+{
+   LTC_ARGCHK(keysize != NULL);
+   if (*keysize < 8) {
+      return CRYPT_INVALID_KEYSIZE;
+   } else {
+      *keysize = 8;
+      return CRYPT_OK;
+   }
+}
+
+int safer_128_keysize(int *keysize)
+{
+   LTC_ARGCHK(keysize != NULL);
+   if (*keysize < 16) {
+      return CRYPT_INVALID_KEYSIZE;
+   } else {
+      *keysize = 16;
+      return CRYPT_OK;
+   }
+}
+
+int safer_k64_test(void)
+{
+ #ifndef LTC_TEST
+    return CRYPT_NOP;
+ #else
+   static const unsigned char k64_pt[]  = { 1, 2, 3, 4, 5, 6, 7, 8 },
+                              k64_key[] = { 8, 7, 6, 5, 4, 3, 2, 1 },
+                              k64_ct[]  = { 200, 242, 156, 221, 135, 120, 62, 217 };
+
+   symmetric_key skey;
+   unsigned char buf[2][8];
+   int err;
+
+   /* test K64 */
+   if ((err = safer_k64_setup(k64_key, 8, 6, &skey)) != CRYPT_OK) {
+      return err;
+   }
+   safer_ecb_encrypt(k64_pt, buf[0], &skey);
+   safer_ecb_decrypt(buf[0], buf[1], &skey);
+
+   if (compare_testvector(buf[0], 8, k64_ct, 8, "Safer K64 Encrypt", 0) != 0 ||
+         compare_testvector(buf[1], 8, k64_pt, 8, "Safer K64 Decrypt", 0) != 0) {
+      return CRYPT_FAIL_TESTVECTOR;
+   }
+
+   return CRYPT_OK;
+ #endif
+}
+
+
+int safer_sk64_test(void)
+{
+ #ifndef LTC_TEST
+    return CRYPT_NOP;
+ #else
+   static const unsigned char sk64_pt[]  = { 1, 2, 3, 4, 5, 6, 7, 8 },
+                              sk64_key[] = { 1, 2, 3, 4, 5, 6, 7, 8 },
+                              sk64_ct[]  = { 95, 206, 155, 162, 5, 132, 56, 199 };
+
+   symmetric_key skey;
+   unsigned char buf[2][8];
+   int err, y;
+
+   /* test SK64 */
+   if ((err = safer_sk64_setup(sk64_key, 8, 6, &skey)) != CRYPT_OK) {
+      return err;
+   }
+
+   safer_ecb_encrypt(sk64_pt, buf[0], &skey);
+   safer_ecb_decrypt(buf[0], buf[1], &skey);
+
+   if (compare_testvector(buf[0], 8, sk64_ct, 8, "Safer SK64 Encrypt", 0) != 0 ||
+         compare_testvector(buf[1], 8, sk64_pt, 8, "Safer SK64 Decrypt", 0) != 0) {
+      return CRYPT_FAIL_TESTVECTOR;
+   }
+
+   /* now see if we can encrypt all zero bytes 1000 times, decrypt and come back where we started */
+   for (y = 0; y < 8; y++) buf[0][y] = 0;
+   for (y = 0; y < 1000; y++) safer_ecb_encrypt(buf[0], buf[0], &skey);
+   for (y = 0; y < 1000; y++) safer_ecb_decrypt(buf[0], buf[0], &skey);
+   for (y = 0; y < 8; y++) if (buf[0][y] != 0) return CRYPT_FAIL_TESTVECTOR;
+
+   return CRYPT_OK;
+  #endif
+}
+
+/** Terminate the context
+   @param skey    The scheduled key
+*/
+void safer_done(symmetric_key *skey)
+{
+  LTC_UNUSED_PARAM(skey);
+}
+
+int safer_sk128_test(void)
+{
+ #ifndef LTC_TEST
+    return CRYPT_NOP;
+ #else
+   static const unsigned char sk128_pt[]  = { 1, 2, 3, 4, 5, 6, 7, 8 },
+                              sk128_key[] = { 1, 2, 3, 4, 5, 6, 7, 8,
+                                              0, 0, 0, 0, 0, 0, 0, 0 },
+                              sk128_ct[]  = { 255, 120, 17, 228, 179, 167, 46, 113 };
+
+   symmetric_key skey;
+   unsigned char buf[2][8];
+   int err, y;
+
+   /* test SK128 */
+   if ((err = safer_sk128_setup(sk128_key, 16, 0, &skey)) != CRYPT_OK) {
+      return err;
+   }
+   safer_ecb_encrypt(sk128_pt, buf[0], &skey);
+   safer_ecb_decrypt(buf[0], buf[1], &skey);
+
+   if (compare_testvector(buf[0], 8, sk128_ct, 8, "Safer SK128 Encrypt", 0) != 0 ||
+         compare_testvector(buf[1], 8, sk128_pt, 8, "Safer SK128 Decrypt", 0) != 0) {
+      return CRYPT_FAIL_TESTVECTOR;
+   }
+
+   /* now see if we can encrypt all zero bytes 1000 times, decrypt and come back where we started */
+   for (y = 0; y < 8; y++) buf[0][y] = 0;
+   for (y = 0; y < 1000; y++) safer_ecb_encrypt(buf[0], buf[0], &skey);
+   for (y = 0; y < 1000; y++) safer_ecb_decrypt(buf[0], buf[0], &skey);
+   for (y = 0; y < 8; y++) if (buf[0][y] != 0) return CRYPT_FAIL_TESTVECTOR;
+
+   return CRYPT_OK;
+ #endif
+}
+
+#endif
+
+
+
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/ciphers/safer/safer_tab.c b/libtomcrypt/src/ciphers/safer/safer_tab.c
new file mode 100644 (file)
index 0000000..99962a0
--- /dev/null
@@ -0,0 +1,64 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+/**
+  @file safer_tab.c
+  Tables for LTC_SAFER block ciphers
+*/
+
+#ifdef __LTC_SAFER_TAB_C__
+
+/* This is the box defined by ebox[x] = 45^x mod 257.
+ * Its assumed that the value "256" corresponds to zero. */
+static const unsigned char safer_ebox[256] = {
+  1,  45, 226, 147, 190,  69,  21, 174, 120,   3, 135, 164, 184,  56, 207,  63,
+  8, 103,   9, 148, 235,  38, 168, 107, 189,  24,  52,  27, 187, 191, 114, 247,
+ 64,  53,  72, 156,  81,  47,  59,  85, 227, 192, 159, 216, 211, 243, 141, 177,
+255, 167,  62, 220, 134, 119, 215, 166,  17, 251, 244, 186, 146, 145, 100, 131,
+241,  51, 239, 218,  44, 181, 178,  43, 136, 209, 153, 203, 140, 132,  29,  20,
+129, 151, 113, 202,  95, 163, 139,  87,  60, 130, 196,  82,  92,  28, 232, 160,
+  4, 180, 133,  74, 246,  19,  84, 182, 223,  12,  26, 142, 222, 224,  57, 252,
+ 32, 155,  36,  78, 169, 152, 158, 171, 242,  96, 208, 108, 234, 250, 199, 217,
+  0, 212,  31, 110,  67, 188, 236,  83, 137, 254, 122,  93,  73, 201,  50, 194,
+249, 154, 248, 109,  22, 219,  89, 150,  68, 233, 205, 230,  70,  66, 143,  10,
+193, 204, 185, 101, 176, 210, 198, 172,  30,  65,  98,  41,  46,  14, 116,  80,
+  2,  90, 195,  37, 123, 138,  42,  91, 240,   6,  13,  71, 111, 112, 157, 126,
+ 16, 206,  18,  39, 213,  76,  79, 214, 121,  48, 104,  54, 117, 125, 228, 237,
+128, 106, 144,  55, 162,  94, 118, 170, 197, 127,  61, 175, 165, 229,  25,  97,
+253,  77, 124, 183,  11, 238, 173,  75,  34, 245, 231, 115,  35,  33, 200,   5,
+225, 102, 221, 179,  88, 105,  99,  86,  15, 161,  49, 149,  23,   7,  58,  40
+};
+
+/* This is the inverse of ebox or the base 45 logarithm */
+static const unsigned char safer_lbox[256] = {
+128,   0, 176,   9,  96, 239, 185, 253,  16,  18, 159, 228, 105, 186, 173, 248,
+192,  56, 194, 101,  79,   6, 148, 252,  25, 222, 106,  27,  93,  78, 168, 130,
+112, 237, 232, 236, 114, 179,  21, 195, 255, 171, 182,  71,  68,   1, 172,  37,
+201, 250, 142,  65,  26,  33, 203, 211,  13, 110, 254,  38,  88, 218,  50,  15,
+ 32, 169, 157, 132, 152,   5, 156, 187,  34, 140,  99, 231, 197, 225, 115, 198,
+175,  36,  91, 135, 102,  39, 247,  87, 244, 150, 177, 183,  92, 139, 213,  84,
+121, 223, 170, 246,  62, 163, 241,  17, 202, 245, 209,  23, 123, 147, 131, 188,
+189,  82,  30, 235, 174, 204, 214,  53,   8, 200, 138, 180, 226, 205, 191, 217,
+208,  80,  89,  63,  77,  98,  52,  10,  72, 136, 181,  86,  76,  46, 107, 158,
+210,  61,  60,   3,  19, 251, 151,  81, 117,  74, 145, 113,  35, 190, 118,  42,
+ 95, 249, 212,  85,  11, 220,  55,  49,  22, 116, 215, 119, 167, 230,   7, 219,
+164,  47,  70, 243,  97,  69, 103, 227,  12, 162,  59,  28, 133,  24,   4,  29,
+ 41, 160, 143, 178,  90, 216, 166, 126, 238, 141,  83,  75, 161, 154, 193,  14,
+122,  73, 165,  44, 129, 196, 199,  54,  43, 127,  67, 149,  51, 242, 108, 104,
+109, 240,   2,  40, 206, 221, 155, 234,  94, 153, 124,  20, 134, 207, 229,  66,
+184,  64, 120,  45,  58, 233, 100,  31, 146, 144, 125,  57, 111, 224, 137,  48
+};
+
+#endif /* __LTC_SAFER_TAB_C__ */
+
+
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/ciphers/safer/saferp.c b/libtomcrypt/src/ciphers/safer/saferp.c
new file mode 100644 (file)
index 0000000..116590f
--- /dev/null
@@ -0,0 +1,568 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+/**
+   @file saferp.c
+   LTC_SAFER+ Implementation by Tom St Denis
+*/
+#include "tomcrypt.h"
+
+#ifdef LTC_SAFERP
+
+#define __LTC_SAFER_TAB_C__
+#include "safer_tab.c"
+
+const struct ltc_cipher_descriptor saferp_desc =
+{
+    "safer+",
+    4,
+    16, 32, 16, 8,
+    &saferp_setup,
+    &saferp_ecb_encrypt,
+    &saferp_ecb_decrypt,
+    &saferp_test,
+    &saferp_done,
+    &saferp_keysize,
+    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
+};
+
+/* ROUND(b,i)
+ *
+ * This is one forward key application.  Note the basic form is
+ * key addition, substitution, key addition.  The safer_ebox and safer_lbox
+ * are the exponentiation box and logarithm boxes respectively.
+ * The value of 'i' is the current round number which allows this
+ * function to be unrolled massively.  Most of LTC_SAFER+'s speed
+ * comes from not having to compute indirect accesses into the
+ * array of 16 bytes b[0..15] which is the block of data
+*/
+
+#define ROUND(b, i) do {                                                                         \
+    b[0]  = (safer_ebox[(b[0] ^ skey->saferp.K[i][0]) & 255] + skey->saferp.K[i+1][0]) & 255;    \
+    b[1]  = safer_lbox[(b[1] + skey->saferp.K[i][1]) & 255] ^ skey->saferp.K[i+1][1];            \
+    b[2]  = safer_lbox[(b[2] + skey->saferp.K[i][2]) & 255] ^ skey->saferp.K[i+1][2];            \
+    b[3]  = (safer_ebox[(b[3] ^ skey->saferp.K[i][3]) & 255] + skey->saferp.K[i+1][3]) & 255;    \
+    b[4]  = (safer_ebox[(b[4] ^ skey->saferp.K[i][4]) & 255] + skey->saferp.K[i+1][4]) & 255;    \
+    b[5]  = safer_lbox[(b[5] + skey->saferp.K[i][5]) & 255] ^ skey->saferp.K[i+1][5];            \
+    b[6]  = safer_lbox[(b[6] + skey->saferp.K[i][6]) & 255] ^ skey->saferp.K[i+1][6];            \
+    b[7]  = (safer_ebox[(b[7] ^ skey->saferp.K[i][7]) & 255] + skey->saferp.K[i+1][7]) & 255;    \
+    b[8]  = (safer_ebox[(b[8] ^ skey->saferp.K[i][8]) & 255] + skey->saferp.K[i+1][8]) & 255;    \
+    b[9]  = safer_lbox[(b[9] + skey->saferp.K[i][9]) & 255] ^ skey->saferp.K[i+1][9];            \
+    b[10] = safer_lbox[(b[10] + skey->saferp.K[i][10]) & 255] ^ skey->saferp.K[i+1][10];         \
+    b[11] = (safer_ebox[(b[11] ^ skey->saferp.K[i][11]) & 255] + skey->saferp.K[i+1][11]) & 255; \
+    b[12] = (safer_ebox[(b[12] ^ skey->saferp.K[i][12]) & 255] + skey->saferp.K[i+1][12]) & 255; \
+    b[13] = safer_lbox[(b[13] + skey->saferp.K[i][13]) & 255] ^ skey->saferp.K[i+1][13];         \
+    b[14] = safer_lbox[(b[14] + skey->saferp.K[i][14]) & 255] ^ skey->saferp.K[i+1][14];         \
+    b[15] = (safer_ebox[(b[15] ^ skey->saferp.K[i][15]) & 255] + skey->saferp.K[i+1][15]) & 255; \
+} while (0)
+
+/* This is one inverse key application */
+#define iROUND(b, i) do {                                                                        \
+    b[0]  = safer_lbox[(b[0] - skey->saferp.K[i+1][0]) & 255] ^ skey->saferp.K[i][0];            \
+    b[1]  = (safer_ebox[(b[1] ^ skey->saferp.K[i+1][1]) & 255] - skey->saferp.K[i][1]) & 255;    \
+    b[2]  = (safer_ebox[(b[2] ^ skey->saferp.K[i+1][2]) & 255] - skey->saferp.K[i][2]) & 255;    \
+    b[3]  = safer_lbox[(b[3] - skey->saferp.K[i+1][3]) & 255] ^ skey->saferp.K[i][3];            \
+    b[4]  = safer_lbox[(b[4] - skey->saferp.K[i+1][4]) & 255] ^ skey->saferp.K[i][4];            \
+    b[5]  = (safer_ebox[(b[5] ^ skey->saferp.K[i+1][5]) & 255] - skey->saferp.K[i][5]) & 255;    \
+    b[6]  = (safer_ebox[(b[6] ^ skey->saferp.K[i+1][6]) & 255] - skey->saferp.K[i][6]) & 255;    \
+    b[7]  = safer_lbox[(b[7] - skey->saferp.K[i+1][7]) & 255] ^ skey->saferp.K[i][7];            \
+    b[8]  = safer_lbox[(b[8] - skey->saferp.K[i+1][8]) & 255] ^ skey->saferp.K[i][8];            \
+    b[9]  = (safer_ebox[(b[9] ^ skey->saferp.K[i+1][9]) & 255] - skey->saferp.K[i][9]) & 255;    \
+    b[10] = (safer_ebox[(b[10] ^ skey->saferp.K[i+1][10]) & 255] - skey->saferp.K[i][10]) & 255; \
+    b[11] = safer_lbox[(b[11] - skey->saferp.K[i+1][11]) & 255] ^ skey->saferp.K[i][11];         \
+    b[12] = safer_lbox[(b[12] - skey->saferp.K[i+1][12]) & 255] ^ skey->saferp.K[i][12];         \
+    b[13] = (safer_ebox[(b[13] ^ skey->saferp.K[i+1][13]) & 255] - skey->saferp.K[i][13]) & 255; \
+    b[14] = (safer_ebox[(b[14] ^ skey->saferp.K[i+1][14]) & 255] - skey->saferp.K[i][14]) & 255; \
+    b[15] = safer_lbox[(b[15] - skey->saferp.K[i+1][15]) & 255] ^ skey->saferp.K[i][15];         \
+} while (0)
+
+/* This is a forward single layer PHT transform.  */
+#define PHT(b) do {                                          \
+    b[0]  = (b[0] + (b[1] = (b[0] + b[1]) & 255)) & 255;     \
+    b[2]  = (b[2] + (b[3] = (b[3] + b[2]) & 255)) & 255;     \
+    b[4]  = (b[4] + (b[5] = (b[5] + b[4]) & 255)) & 255;     \
+    b[6]  = (b[6] + (b[7] = (b[7] + b[6]) & 255)) & 255;     \
+    b[8]  = (b[8] + (b[9] = (b[9] + b[8]) & 255)) & 255;     \
+    b[10] = (b[10] + (b[11] = (b[11] + b[10]) & 255)) & 255; \
+    b[12] = (b[12] + (b[13] = (b[13] + b[12]) & 255)) & 255; \
+    b[14] = (b[14] + (b[15] = (b[15] + b[14]) & 255)) & 255; \
+} while (0)
+
+/* This is an inverse single layer PHT transform */
+#define iPHT(b) do {                                          \
+    b[15] = (b[15] - (b[14] = (b[14] - b[15]) & 255)) & 255;  \
+    b[13] = (b[13] - (b[12] = (b[12] - b[13]) & 255)) & 255;  \
+    b[11] = (b[11] - (b[10] = (b[10] - b[11]) & 255)) & 255;  \
+    b[9]  = (b[9] - (b[8] = (b[8] - b[9]) & 255)) & 255;      \
+    b[7]  = (b[7] - (b[6] = (b[6] - b[7]) & 255)) & 255;      \
+    b[5]  = (b[5] - (b[4] = (b[4] - b[5]) & 255)) & 255;      \
+    b[3]  = (b[3] - (b[2] = (b[2] - b[3]) & 255)) & 255;      \
+    b[1]  = (b[1] - (b[0] = (b[0] - b[1]) & 255)) & 255;      \
+ } while (0)
+
+/* This is the "Armenian" Shuffle.  It takes the input from b and stores it in b2 */
+#define SHUF(b, b2) do {                                         \
+    b2[0] = b[8]; b2[1] = b[11]; b2[2] = b[12]; b2[3] = b[15];   \
+    b2[4] = b[2]; b2[5] = b[1]; b2[6] = b[6]; b2[7] = b[5];      \
+    b2[8] = b[10]; b2[9] = b[9]; b2[10] = b[14]; b2[11] = b[13]; \
+    b2[12] = b[0]; b2[13] = b[7]; b2[14] = b[4]; b2[15] = b[3];  \
+} while (0)
+
+/* This is the inverse shuffle.  It takes from b and gives to b2 */
+#define iSHUF(b, b2) do {                                          \
+    b2[0] = b[12]; b2[1] = b[5]; b2[2] = b[4]; b2[3] = b[15];      \
+    b2[4] = b[14]; b2[5] = b[7]; b2[6] = b[6]; b2[7] = b[13];      \
+    b2[8] = b[0]; b2[9] = b[9]; b2[10] = b[8]; b2[11] = b[1];      \
+    b2[12] = b[2]; b2[13] = b[11]; b2[14] = b[10]; b2[15] = b[3];  \
+} while (0)
+
+/* The complete forward Linear Transform layer.
+ * Note that alternating usage of b and b2.
+ * Each round of LT starts in 'b' and ends in 'b2'.
+ */
+#define LT(b, b2) do {        \
+    PHT(b);  SHUF(b, b2);     \
+    PHT(b2); SHUF(b2, b);     \
+    PHT(b);  SHUF(b, b2);     \
+    PHT(b2);                  \
+} while (0)
+
+/* This is the inverse linear transform layer.  */
+#define iLT(b, b2) do {       \
+    iPHT(b);                  \
+    iSHUF(b, b2); iPHT(b2);   \
+    iSHUF(b2, b); iPHT(b);    \
+    iSHUF(b, b2); iPHT(b2);   \
+} while (0)
+
+#ifdef LTC_SMALL_CODE
+
+static void _round(unsigned char *b, int i, symmetric_key *skey)
+{
+   ROUND(b, i);
+}
+
+static void _iround(unsigned char *b, int i, symmetric_key *skey)
+{
+   iROUND(b, i);
+}
+
+static void _lt(unsigned char *b, unsigned char *b2)
+{
+   LT(b, b2);
+}
+
+static void _ilt(unsigned char *b, unsigned char *b2)
+{
+   iLT(b, b2);
+}
+
+#undef ROUND
+#define ROUND(b, i) _round(b, i, skey)
+
+#undef iROUND
+#define iROUND(b, i) _iround(b, i, skey)
+
+#undef LT
+#define LT(b, b2) _lt(b, b2)
+
+#undef iLT
+#define iLT(b, b2) _ilt(b, b2)
+
+#endif
+
+/* These are the 33, 128-bit bias words for the key schedule */
+static const unsigned char safer_bias[33][16] = {
+{  70, 151, 177, 186, 163, 183,  16,  10, 197,  55, 179, 201,  90,  40, 172, 100},
+{ 236, 171, 170, 198, 103, 149,  88,  13, 248, 154, 246, 110, 102, 220,   5,  61},
+{ 138, 195, 216, 137, 106, 233,  54,  73,  67, 191, 235, 212, 150, 155, 104, 160},
+{  93,  87, 146,  31, 213, 113,  92, 187,  34, 193, 190, 123, 188, 153,  99, 148},
+{  42,  97, 184,  52,  50,  25, 253, 251,  23,  64, 230,  81,  29,  65,  68, 143},
+{ 221,   4, 128, 222, 231,  49, 214, 127,   1, 162, 247,  57, 218, 111,  35, 202},
+{  58, 208,  28, 209,  48,  62,  18, 161, 205,  15, 224, 168, 175, 130,  89,  44},
+{ 125, 173, 178, 239, 194, 135, 206, 117,   6,  19,   2, 144,  79,  46, 114,  51},
+{ 192, 141, 207, 169, 129, 226, 196,  39,  47, 108, 122, 159,  82, 225,  21,  56},
+{ 252,  32,  66, 199,   8, 228,   9,  85,  94, 140,  20, 118,  96, 255, 223, 215},
+{ 250,  11,  33,   0,  26, 249, 166, 185, 232, 158,  98,  76, 217, 145,  80, 210},
+{  24, 180,   7, 132, 234,  91, 164, 200,  14, 203,  72, 105,  75,  78, 156,  53},
+{  69,  77,  84, 229,  37,  60,  12,  74, 139,  63, 204, 167, 219, 107, 174, 244},
+{  45, 243, 124, 109, 157, 181,  38, 116, 242, 147,  83, 176, 240,  17, 237, 131},
+{ 182,   3,  22, 115,  59,  30, 142, 112, 189, 134,  27,  71, 126,  36,  86, 241},
+{ 136,  70, 151, 177, 186, 163, 183,  16,  10, 197,  55, 179, 201,  90,  40, 172},
+{ 220, 134, 119, 215, 166,  17, 251, 244, 186, 146, 145, 100, 131, 241,  51, 239},
+{  44, 181, 178,  43, 136, 209, 153, 203, 140, 132,  29,  20, 129, 151, 113, 202},
+{ 163, 139,  87,  60, 130, 196,  82,  92,  28, 232, 160,   4, 180, 133,  74, 246},
+{  84, 182, 223,  12,  26, 142, 222, 224,  57, 252,  32, 155,  36,  78, 169, 152},
+{ 171, 242,  96, 208, 108, 234, 250, 199, 217,   0, 212,  31, 110,  67, 188, 236},
+{ 137, 254, 122,  93,  73, 201,  50, 194, 249, 154, 248, 109,  22, 219,  89, 150},
+{ 233, 205, 230,  70,  66, 143,  10, 193, 204, 185, 101, 176, 210, 198, 172,  30},
+{  98,  41,  46,  14, 116,  80,   2,  90, 195,  37, 123, 138,  42,  91, 240,   6},
+{  71, 111, 112, 157, 126,  16, 206,  18,  39, 213,  76,  79, 214, 121,  48, 104},
+{ 117, 125, 228, 237, 128, 106, 144,  55, 162,  94, 118, 170, 197, 127,  61, 175},
+{ 229,  25,  97, 253,  77, 124, 183,  11, 238, 173,  75,  34, 245, 231, 115,  35},
+{ 200,   5, 225, 102, 221, 179,  88, 105,  99,  86,  15, 161,  49, 149,  23,   7},
+{  40,   1,  45, 226, 147, 190,  69,  21, 174, 120,   3, 135, 164, 184,  56, 207},
+{   8, 103,   9, 148, 235,  38, 168, 107, 189,  24,  52,  27, 187, 191, 114, 247},
+{  53,  72, 156,  81,  47,  59,  85, 227, 192, 159, 216, 211, 243, 141, 177, 255},
+{  62, 220, 134, 119, 215, 166,  17, 251, 244, 186, 146, 145, 100, 131, 241,  51}};
+
+ /**
+    Initialize the LTC_SAFER+ block cipher
+    @param key The symmetric key you wish to pass
+    @param keylen The key length in bytes
+    @param num_rounds The number of rounds desired (0 for default)
+    @param skey The key in as scheduled by this function.
+    @return CRYPT_OK if successful
+ */
+int saferp_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey)
+{
+   unsigned x, y, z;
+   unsigned char t[33];
+   static const int rounds[3] = { 8, 12, 16 };
+
+   LTC_ARGCHK(key  != NULL);
+   LTC_ARGCHK(skey != NULL);
+
+   /* check arguments */
+   if (keylen != 16 && keylen != 24 && keylen != 32) {
+      return CRYPT_INVALID_KEYSIZE;
+   }
+
+   /* Is the number of rounds valid?  Either use zero for default or
+    * 8,12,16 rounds for 16,24,32 byte keys
+    */
+   if (num_rounds != 0 && num_rounds != rounds[(keylen/8)-2]) {
+      return CRYPT_INVALID_ROUNDS;
+   }
+
+   /* 128 bit key version */
+   if (keylen == 16) {
+       /* copy key into t */
+       for (x = y = 0; x < 16; x++) {
+           t[x] = key[x];
+           y ^= key[x];
+       }
+       t[16] = y;
+
+       /* make round keys */
+       for (x = 0; x < 16; x++) {
+           skey->saferp.K[0][x] = t[x];
+       }
+
+       /* make the 16 other keys as a transformation of the first key */
+       for (x = 1; x < 17; x++) {
+           /* rotate 3 bits each */
+           for (y = 0; y < 17; y++) {
+               t[y] = ((t[y]<<3)|(t[y]>>5)) & 255;
+           }
+
+           /* select and add */
+           z = x;
+           for (y = 0; y < 16; y++) {
+               skey->saferp.K[x][y] = (t[z] + safer_bias[x-1][y]) & 255;
+               if (++z == 17) { z = 0; }
+           }
+       }
+       skey->saferp.rounds = 8;
+   } else if (keylen == 24) {
+       /* copy key into t */
+       for (x = y = 0; x < 24; x++) {
+           t[x] = key[x];
+           y ^= key[x];
+       }
+       t[24] = y;
+
+       /* make round keys */
+       for (x = 0; x < 16; x++) {
+           skey->saferp.K[0][x] = t[x];
+       }
+
+       for (x = 1; x < 25; x++) {
+           /* rotate 3 bits each */
+           for (y = 0; y < 25; y++) {
+               t[y] = ((t[y]<<3)|(t[y]>>5)) & 255;
+           }
+
+           /* select and add */
+           z = x;
+           for (y = 0; y < 16; y++) {
+               skey->saferp.K[x][y] = (t[z] + safer_bias[x-1][y]) & 255;
+               if (++z == 25) { z = 0; }
+           }
+       }
+       skey->saferp.rounds = 12;
+   } else {
+       /* copy key into t */
+       for (x = y = 0; x < 32; x++) {
+           t[x] = key[x];
+           y ^= key[x];
+       }
+       t[32] = y;
+
+       /* make round keys */
+       for (x = 0; x < 16; x++) {
+           skey->saferp.K[0][x] = t[x];
+       }
+
+       for (x = 1; x < 33; x++) {
+           /* rotate 3 bits each */
+           for (y = 0; y < 33; y++) {
+               t[y] = ((t[y]<<3)|(t[y]>>5)) & 255;
+           }
+
+           /* select and add */
+           z = x;
+           for (y = 0; y < 16; y++) {
+               skey->saferp.K[x][y] = (t[z] + safer_bias[x-1][y]) & 255;
+               if (++z == 33) { z = 0; }
+           }
+       }
+       skey->saferp.rounds = 16;
+   }
+#ifdef LTC_CLEAN_STACK
+   zeromem(t, sizeof(t));
+#endif
+   return CRYPT_OK;
+}
+
+/**
+  Encrypts a block of text with LTC_SAFER+
+  @param pt The input plaintext (16 bytes)
+  @param ct The output ciphertext (16 bytes)
+  @param skey The key as scheduled
+  @return CRYPT_OK if successful
+*/
+int saferp_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey)
+{
+   unsigned char b[16];
+   int x;
+
+   LTC_ARGCHK(pt   != NULL);
+   LTC_ARGCHK(ct   != NULL);
+   LTC_ARGCHK(skey != NULL);
+
+   /* do eight rounds */
+   for (x = 0; x < 16; x++) {
+       b[x] = pt[x];
+   }
+   ROUND(b,  0);  LT(b, ct);
+   ROUND(ct, 2);  LT(ct, b);
+   ROUND(b,  4);  LT(b, ct);
+   ROUND(ct, 6);  LT(ct, b);
+   ROUND(b,  8);  LT(b, ct);
+   ROUND(ct, 10); LT(ct, b);
+   ROUND(b,  12); LT(b, ct);
+   ROUND(ct, 14); LT(ct, b);
+   /* 192-bit key? */
+   if (skey->saferp.rounds > 8) {
+      ROUND(b, 16);  LT(b, ct);
+      ROUND(ct, 18); LT(ct, b);
+      ROUND(b, 20);  LT(b, ct);
+      ROUND(ct, 22); LT(ct, b);
+   }
+   /* 256-bit key? */
+   if (skey->saferp.rounds > 12) {
+      ROUND(b, 24);  LT(b, ct);
+      ROUND(ct, 26); LT(ct, b);
+      ROUND(b, 28);  LT(b, ct);
+      ROUND(ct, 30); LT(ct, b);
+   }
+   ct[0] = b[0] ^ skey->saferp.K[skey->saferp.rounds*2][0];
+   ct[1] = (b[1] + skey->saferp.K[skey->saferp.rounds*2][1]) & 255;
+   ct[2] = (b[2] + skey->saferp.K[skey->saferp.rounds*2][2]) & 255;
+   ct[3] = b[3] ^ skey->saferp.K[skey->saferp.rounds*2][3];
+   ct[4] = b[4] ^ skey->saferp.K[skey->saferp.rounds*2][4];
+   ct[5] = (b[5] + skey->saferp.K[skey->saferp.rounds*2][5]) & 255;
+   ct[6] = (b[6] + skey->saferp.K[skey->saferp.rounds*2][6]) & 255;
+   ct[7] = b[7] ^ skey->saferp.K[skey->saferp.rounds*2][7];
+   ct[8] = b[8] ^ skey->saferp.K[skey->saferp.rounds*2][8];
+   ct[9] = (b[9] + skey->saferp.K[skey->saferp.rounds*2][9]) & 255;
+   ct[10] = (b[10] + skey->saferp.K[skey->saferp.rounds*2][10]) & 255;
+   ct[11] = b[11] ^ skey->saferp.K[skey->saferp.rounds*2][11];
+   ct[12] = b[12] ^ skey->saferp.K[skey->saferp.rounds*2][12];
+   ct[13] = (b[13] + skey->saferp.K[skey->saferp.rounds*2][13]) & 255;
+   ct[14] = (b[14] + skey->saferp.K[skey->saferp.rounds*2][14]) & 255;
+   ct[15] = b[15] ^ skey->saferp.K[skey->saferp.rounds*2][15];
+#ifdef LTC_CLEAN_STACK
+   zeromem(b, sizeof(b));
+#endif
+   return CRYPT_OK;
+}
+
+/**
+  Decrypts a block of text with LTC_SAFER+
+  @param ct The input ciphertext (16 bytes)
+  @param pt The output plaintext (16 bytes)
+  @param skey The key as scheduled
+  @return CRYPT_OK if successful
+*/
+int saferp_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey)
+{
+   unsigned char b[16];
+   int x;
+
+   LTC_ARGCHK(pt   != NULL);
+   LTC_ARGCHK(ct   != NULL);
+   LTC_ARGCHK(skey != NULL);
+
+   /* do eight rounds */
+   b[0] = ct[0] ^ skey->saferp.K[skey->saferp.rounds*2][0];
+   b[1] = (ct[1] - skey->saferp.K[skey->saferp.rounds*2][1]) & 255;
+   b[2] = (ct[2] - skey->saferp.K[skey->saferp.rounds*2][2]) & 255;
+   b[3] = ct[3] ^ skey->saferp.K[skey->saferp.rounds*2][3];
+   b[4] = ct[4] ^ skey->saferp.K[skey->saferp.rounds*2][4];
+   b[5] = (ct[5] - skey->saferp.K[skey->saferp.rounds*2][5]) & 255;
+   b[6] = (ct[6] - skey->saferp.K[skey->saferp.rounds*2][6]) & 255;
+   b[7] = ct[7] ^ skey->saferp.K[skey->saferp.rounds*2][7];
+   b[8] = ct[8] ^ skey->saferp.K[skey->saferp.rounds*2][8];
+   b[9] = (ct[9] - skey->saferp.K[skey->saferp.rounds*2][9]) & 255;
+   b[10] = (ct[10] - skey->saferp.K[skey->saferp.rounds*2][10]) & 255;
+   b[11] = ct[11] ^ skey->saferp.K[skey->saferp.rounds*2][11];
+   b[12] = ct[12] ^ skey->saferp.K[skey->saferp.rounds*2][12];
+   b[13] = (ct[13] - skey->saferp.K[skey->saferp.rounds*2][13]) & 255;
+   b[14] = (ct[14] - skey->saferp.K[skey->saferp.rounds*2][14]) & 255;
+   b[15] = ct[15] ^ skey->saferp.K[skey->saferp.rounds*2][15];
+   /* 256-bit key? */
+   if (skey->saferp.rounds > 12) {
+      iLT(b, pt); iROUND(pt, 30);
+      iLT(pt, b); iROUND(b, 28);
+      iLT(b, pt); iROUND(pt, 26);
+      iLT(pt, b); iROUND(b, 24);
+   }
+   /* 192-bit key? */
+   if (skey->saferp.rounds > 8) {
+      iLT(b, pt); iROUND(pt, 22);
+      iLT(pt, b); iROUND(b, 20);
+      iLT(b, pt); iROUND(pt, 18);
+      iLT(pt, b); iROUND(b, 16);
+   }
+   iLT(b, pt); iROUND(pt, 14);
+   iLT(pt, b); iROUND(b, 12);
+   iLT(b, pt); iROUND(pt,10);
+   iLT(pt, b); iROUND(b, 8);
+   iLT(b, pt); iROUND(pt,6);
+   iLT(pt, b); iROUND(b, 4);
+   iLT(b, pt); iROUND(pt,2);
+   iLT(pt, b); iROUND(b, 0);
+   for (x = 0; x < 16; x++) {
+       pt[x] = b[x];
+   }
+#ifdef LTC_CLEAN_STACK
+   zeromem(b, sizeof(b));
+#endif
+   return CRYPT_OK;
+}
+
+/**
+  Performs a self-test of the LTC_SAFER+ block cipher
+  @return CRYPT_OK if functional, CRYPT_NOP if self-test has been disabled
+*/
+int saferp_test(void)
+{
+ #ifndef LTC_TEST
+    return CRYPT_NOP;
+ #else
+   static const struct {
+       int keylen;
+       unsigned char key[32], pt[16], ct[16];
+   } tests[] = {
+       {
+           16,
+           { 41, 35, 190, 132, 225, 108, 214, 174,
+             82, 144, 73, 241, 241, 187, 233, 235 },
+           { 179, 166, 219, 60, 135, 12, 62, 153,
+             36, 94, 13, 28, 6, 183, 71, 222 },
+           { 224, 31, 182, 10, 12, 255, 84, 70,
+             127, 13, 89, 249, 9, 57, 165, 220 }
+       }, {
+           24,
+           { 72, 211, 143, 117, 230, 217, 29, 42,
+             229, 192, 247, 43, 120, 129, 135, 68,
+             14, 95, 80, 0, 212, 97, 141, 190 },
+           { 123, 5, 21, 7, 59, 51, 130, 31,
+             24, 112, 146, 218, 100, 84, 206, 177 },
+           { 92, 136, 4, 63, 57, 95, 100, 0,
+             150, 130, 130, 16, 193, 111, 219, 133 }
+       }, {
+           32,
+           { 243, 168, 141, 254, 190, 242, 235, 113,
+             255, 160, 208, 59, 117, 6, 140, 126,
+             135, 120, 115, 77, 208, 190, 130, 190,
+             219, 194, 70, 65, 43, 140, 250, 48 },
+           { 127, 112, 240, 167, 84, 134, 50, 149,
+             170, 91, 104, 19, 11, 230, 252, 245 },
+           { 88, 11, 25, 36, 172, 229, 202, 213,
+             170, 65, 105, 153, 220, 104, 153, 138 }
+       }
+    };
+
+   unsigned char tmp[2][16];
+   symmetric_key skey;
+   int err, i, y;
+
+   for (i = 0; i < (int)(sizeof(tests) / sizeof(tests[0])); i++) {
+      if ((err = saferp_setup(tests[i].key, tests[i].keylen, 0, &skey)) != CRYPT_OK)  {
+         return err;
+      }
+      saferp_ecb_encrypt(tests[i].pt, tmp[0], &skey);
+      saferp_ecb_decrypt(tmp[0], tmp[1], &skey);
+
+      /* compare */
+      if (compare_testvector(tmp[0], 16, tests[i].ct, 16, "Safer+ Encrypt", i) ||
+            compare_testvector(tmp[1], 16, tests[i].pt, 16, "Safer+ Decrypt", i)) {
+         return CRYPT_FAIL_TESTVECTOR;
+      }
+
+      /* now see if we can encrypt all zero bytes 1000 times, decrypt and come back where we started */
+      for (y = 0; y < 16; y++) tmp[0][y] = 0;
+      for (y = 0; y < 1000; y++) saferp_ecb_encrypt(tmp[0], tmp[0], &skey);
+      for (y = 0; y < 1000; y++) saferp_ecb_decrypt(tmp[0], tmp[0], &skey);
+      for (y = 0; y < 16; y++) if (tmp[0][y] != 0) return CRYPT_FAIL_TESTVECTOR;
+   }
+
+   return CRYPT_OK;
+ #endif
+}
+
+/** Terminate the context
+   @param skey    The scheduled key
+*/
+void saferp_done(symmetric_key *skey)
+{
+  LTC_UNUSED_PARAM(skey);
+}
+
+/**
+  Gets suitable key size
+  @param keysize [in/out] The length of the recommended key (in bytes).  This function will store the suitable size back in this variable.
+  @return CRYPT_OK if the input key size is acceptable.
+*/
+int saferp_keysize(int *keysize)
+{
+   LTC_ARGCHK(keysize != NULL);
+
+   if (*keysize < 16)
+      return CRYPT_INVALID_KEYSIZE;
+   if (*keysize < 24) {
+      *keysize = 16;
+   } else if (*keysize < 32) {
+      *keysize = 24;
+   } else {
+      *keysize = 32;
+   }
+   return CRYPT_OK;
+}
+
+#endif
+
+
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/ciphers/skipjack.c b/libtomcrypt/src/ciphers/skipjack.c
new file mode 100644 (file)
index 0000000..d47f2d3
--- /dev/null
@@ -0,0 +1,343 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+/**
+  @file skipjack.c
+  Skipjack Implementation by Tom St Denis
+*/
+#include "tomcrypt.h"
+
+#ifdef LTC_SKIPJACK
+
+const struct ltc_cipher_descriptor skipjack_desc =
+{
+    "skipjack",
+    17,
+    10, 10, 8, 32,
+    &skipjack_setup,
+    &skipjack_ecb_encrypt,
+    &skipjack_ecb_decrypt,
+    &skipjack_test,
+    &skipjack_done,
+    &skipjack_keysize,
+    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
+};
+
+static const unsigned char sbox[256] = {
+   0xa3,0xd7,0x09,0x83,0xf8,0x48,0xf6,0xf4,0xb3,0x21,0x15,0x78,0x99,0xb1,0xaf,0xf9,
+   0xe7,0x2d,0x4d,0x8a,0xce,0x4c,0xca,0x2e,0x52,0x95,0xd9,0x1e,0x4e,0x38,0x44,0x28,
+   0x0a,0xdf,0x02,0xa0,0x17,0xf1,0x60,0x68,0x12,0xb7,0x7a,0xc3,0xe9,0xfa,0x3d,0x53,
+   0x96,0x84,0x6b,0xba,0xf2,0x63,0x9a,0x19,0x7c,0xae,0xe5,0xf5,0xf7,0x16,0x6a,0xa2,
+   0x39,0xb6,0x7b,0x0f,0xc1,0x93,0x81,0x1b,0xee,0xb4,0x1a,0xea,0xd0,0x91,0x2f,0xb8,
+   0x55,0xb9,0xda,0x85,0x3f,0x41,0xbf,0xe0,0x5a,0x58,0x80,0x5f,0x66,0x0b,0xd8,0x90,
+   0x35,0xd5,0xc0,0xa7,0x33,0x06,0x65,0x69,0x45,0x00,0x94,0x56,0x6d,0x98,0x9b,0x76,
+   0x97,0xfc,0xb2,0xc2,0xb0,0xfe,0xdb,0x20,0xe1,0xeb,0xd6,0xe4,0xdd,0x47,0x4a,0x1d,
+   0x42,0xed,0x9e,0x6e,0x49,0x3c,0xcd,0x43,0x27,0xd2,0x07,0xd4,0xde,0xc7,0x67,0x18,
+   0x89,0xcb,0x30,0x1f,0x8d,0xc6,0x8f,0xaa,0xc8,0x74,0xdc,0xc9,0x5d,0x5c,0x31,0xa4,
+   0x70,0x88,0x61,0x2c,0x9f,0x0d,0x2b,0x87,0x50,0x82,0x54,0x64,0x26,0x7d,0x03,0x40,
+   0x34,0x4b,0x1c,0x73,0xd1,0xc4,0xfd,0x3b,0xcc,0xfb,0x7f,0xab,0xe6,0x3e,0x5b,0xa5,
+   0xad,0x04,0x23,0x9c,0x14,0x51,0x22,0xf0,0x29,0x79,0x71,0x7e,0xff,0x8c,0x0e,0xe2,
+   0x0c,0xef,0xbc,0x72,0x75,0x6f,0x37,0xa1,0xec,0xd3,0x8e,0x62,0x8b,0x86,0x10,0xe8,
+   0x08,0x77,0x11,0xbe,0x92,0x4f,0x24,0xc5,0x32,0x36,0x9d,0xcf,0xf3,0xa6,0xbb,0xac,
+   0x5e,0x6c,0xa9,0x13,0x57,0x25,0xb5,0xe3,0xbd,0xa8,0x3a,0x01,0x05,0x59,0x2a,0x46
+};
+
+/* simple x + 1 (mod 10) in one step. */
+static const int keystep[] =  { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
+
+/* simple x - 1 (mod 10) in one step */
+static const int ikeystep[] = { 9, 0, 1, 2, 3, 4, 5, 6, 7, 8 };
+
+ /**
+    Initialize the Skipjack block cipher
+    @param key The symmetric key you wish to pass
+    @param keylen The key length in bytes
+    @param num_rounds The number of rounds desired (0 for default)
+    @param skey The key in as scheduled by this function.
+    @return CRYPT_OK if successful
+ */
+int skipjack_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey)
+{
+   int x;
+
+   LTC_ARGCHK(key  != NULL);
+   LTC_ARGCHK(skey != NULL);
+
+   if (keylen != 10) {
+      return CRYPT_INVALID_KEYSIZE;
+   }
+
+   if (num_rounds != 32 && num_rounds != 0) {
+      return CRYPT_INVALID_ROUNDS;
+   }
+
+   /* make sure the key is in range for platforms where CHAR_BIT != 8 */
+   for (x = 0; x < 10; x++) {
+       skey->skipjack.key[x] = key[x] & 255;
+   }
+
+   return CRYPT_OK;
+}
+
+#define RULE_A \
+   tmp = g_func(w1, &kp, skey->skipjack.key);      \
+   w1  = tmp ^ w4 ^ x;                            \
+   w4  = w3; w3 = w2;                             \
+   w2  = tmp;
+
+#define RULE_B \
+   tmp  = g_func(w1, &kp, skey->skipjack.key);     \
+   tmp1 = w4; w4  = w3;                           \
+   w3   = w1 ^ w2 ^ x;                            \
+   w1   = tmp1; w2 = tmp;
+
+#define RULE_A1 \
+   tmp = w1 ^ w2 ^ x;                             \
+   w1  = ig_func(w2, &kp, skey->skipjack.key);     \
+   w2  = w3; w3 = w4; w4 = tmp;
+
+#define RULE_B1 \
+   tmp = ig_func(w2, &kp, skey->skipjack.key);     \
+   w2  = tmp ^ w3 ^ x;                            \
+   w3  = w4; w4 = w1; w1 = tmp;
+
+static unsigned g_func(unsigned w, int *kp, unsigned char *key)
+{
+   unsigned char g1,g2;
+
+   g1 = (w >> 8) & 255; g2 = w & 255;
+   g1 ^= sbox[g2^key[*kp]]; *kp = keystep[*kp];
+   g2 ^= sbox[g1^key[*kp]]; *kp = keystep[*kp];
+   g1 ^= sbox[g2^key[*kp]]; *kp = keystep[*kp];
+   g2 ^= sbox[g1^key[*kp]]; *kp = keystep[*kp];
+   return ((unsigned)g1<<8)|(unsigned)g2;
+}
+
+static unsigned ig_func(unsigned w, int *kp, unsigned char *key)
+{
+   unsigned char g1,g2;
+
+   g1 = (w >> 8) & 255; g2 = w & 255;
+   *kp = ikeystep[*kp]; g2 ^= sbox[g1^key[*kp]];
+   *kp = ikeystep[*kp]; g1 ^= sbox[g2^key[*kp]];
+   *kp = ikeystep[*kp]; g2 ^= sbox[g1^key[*kp]];
+   *kp = ikeystep[*kp]; g1 ^= sbox[g2^key[*kp]];
+   return ((unsigned)g1<<8)|(unsigned)g2;
+}
+
+/**
+  Encrypts a block of text with Skipjack
+  @param pt The input plaintext (8 bytes)
+  @param ct The output ciphertext (8 bytes)
+  @param skey The key as scheduled
+  @return CRYPT_OK if successful
+*/
+#ifdef LTC_CLEAN_STACK
+static int _skipjack_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey)
+#else
+int skipjack_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey)
+#endif
+{
+   unsigned w1,w2,w3,w4,tmp,tmp1;
+   int x, kp;
+
+   LTC_ARGCHK(pt   != NULL);
+   LTC_ARGCHK(ct   != NULL);
+   LTC_ARGCHK(skey != NULL);
+
+   /* load block */
+   w1 = ((unsigned)pt[0]<<8)|pt[1];
+   w2 = ((unsigned)pt[2]<<8)|pt[3];
+   w3 = ((unsigned)pt[4]<<8)|pt[5];
+   w4 = ((unsigned)pt[6]<<8)|pt[7];
+
+   /* 8 rounds of RULE A */
+   for (x = 1, kp = 0; x < 9; x++) {
+       RULE_A;
+   }
+
+   /* 8 rounds of RULE B */
+   for (; x < 17; x++) {
+       RULE_B;
+   }
+
+   /* 8 rounds of RULE A */
+   for (; x < 25; x++) {
+       RULE_A;
+   }
+
+   /* 8 rounds of RULE B */
+   for (; x < 33; x++) {
+       RULE_B;
+   }
+
+   /* store block */
+   ct[0] = (w1>>8)&255; ct[1] = w1&255;
+   ct[2] = (w2>>8)&255; ct[3] = w2&255;
+   ct[4] = (w3>>8)&255; ct[5] = w3&255;
+   ct[6] = (w4>>8)&255; ct[7] = w4&255;
+
+   return CRYPT_OK;
+}
+
+#ifdef LTC_CLEAN_STACK
+int skipjack_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey)
+{
+   int err = _skipjack_ecb_encrypt(pt, ct, skey);
+   burn_stack(sizeof(unsigned) * 8 + sizeof(int) * 2);
+   return err;
+}
+#endif
+
+/**
+  Decrypts a block of text with Skipjack
+  @param ct The input ciphertext (8 bytes)
+  @param pt The output plaintext (8 bytes)
+  @param skey The key as scheduled
+  @return CRYPT_OK if successful
+*/
+#ifdef LTC_CLEAN_STACK
+static int _skipjack_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey)
+#else
+int skipjack_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey)
+#endif
+{
+   unsigned w1,w2,w3,w4,tmp;
+   int x, kp;
+
+   LTC_ARGCHK(pt   != NULL);
+   LTC_ARGCHK(ct   != NULL);
+   LTC_ARGCHK(skey != NULL);
+
+   /* load block */
+   w1 = ((unsigned)ct[0]<<8)|ct[1];
+   w2 = ((unsigned)ct[2]<<8)|ct[3];
+   w3 = ((unsigned)ct[4]<<8)|ct[5];
+   w4 = ((unsigned)ct[6]<<8)|ct[7];
+
+   /* 8 rounds of RULE B^-1
+
+      Note the value "kp = 8" comes from "kp = (32 * 4) mod 10" where 32*4 is 128 which mod 10 is 8
+    */
+   for (x = 32, kp = 8; x > 24; x--) {
+       RULE_B1;
+   }
+
+   /* 8 rounds of RULE A^-1 */
+   for (; x > 16; x--) {
+       RULE_A1;
+   }
+
+
+   /* 8 rounds of RULE B^-1 */
+   for (; x > 8; x--) {
+       RULE_B1;
+   }
+
+   /* 8 rounds of RULE A^-1 */
+   for (; x > 0; x--) {
+       RULE_A1;
+   }
+
+   /* store block */
+   pt[0] = (w1>>8)&255; pt[1] = w1&255;
+   pt[2] = (w2>>8)&255; pt[3] = w2&255;
+   pt[4] = (w3>>8)&255; pt[5] = w3&255;
+   pt[6] = (w4>>8)&255; pt[7] = w4&255;
+
+   return CRYPT_OK;
+}
+
+#ifdef LTC_CLEAN_STACK
+int skipjack_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey)
+{
+   int err = _skipjack_ecb_decrypt(ct, pt, skey);
+   burn_stack(sizeof(unsigned) * 7 + sizeof(int) * 2);
+   return err;
+}
+#endif
+
+/**
+  Performs a self-test of the Skipjack block cipher
+  @return CRYPT_OK if functional, CRYPT_NOP if self-test has been disabled
+*/
+int skipjack_test(void)
+{
+ #ifndef LTC_TEST
+    return CRYPT_NOP;
+ #else
+   static const struct {
+       unsigned char key[10], pt[8], ct[8];
+   } tests[] = {
+   {
+       { 0x00, 0x99, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11 },
+       { 0x33, 0x22, 0x11, 0x00, 0xdd, 0xcc, 0xbb, 0xaa },
+       { 0x25, 0x87, 0xca, 0xe2, 0x7a, 0x12, 0xd3, 0x00 }
+   }
+   };
+   unsigned char buf[2][8];
+   int x, y, err;
+   symmetric_key key;
+
+   for (x = 0; x < (int)(sizeof(tests) / sizeof(tests[0])); x++) {
+      /* setup key */
+      if ((err = skipjack_setup(tests[x].key, 10, 0, &key)) != CRYPT_OK) {
+         return err;
+      }
+
+      /* encrypt and decrypt */
+      skipjack_ecb_encrypt(tests[x].pt, buf[0], &key);
+      skipjack_ecb_decrypt(buf[0], buf[1], &key);
+
+      /* compare */
+      if (compare_testvector(buf[0], 8, tests[x].ct, 8, "Skipjack Encrypt", x) != 0 ||
+            compare_testvector(buf[1], 8, tests[x].pt, 8, "Skipjack Decrypt", x) != 0) {
+         return CRYPT_FAIL_TESTVECTOR;
+      }
+
+      /* now see if we can encrypt all zero bytes 1000 times, decrypt and come back where we started */
+      for (y = 0; y < 8; y++) buf[0][y] = 0;
+      for (y = 0; y < 1000; y++) skipjack_ecb_encrypt(buf[0], buf[0], &key);
+      for (y = 0; y < 1000; y++) skipjack_ecb_decrypt(buf[0], buf[0], &key);
+      for (y = 0; y < 8; y++) if (buf[0][y] != 0) return CRYPT_FAIL_TESTVECTOR;
+   }
+
+   return CRYPT_OK;
+  #endif
+}
+
+/** Terminate the context
+   @param skey    The scheduled key
+*/
+void skipjack_done(symmetric_key *skey)
+{
+  LTC_UNUSED_PARAM(skey);
+}
+
+/**
+  Gets suitable key size
+  @param keysize [in/out] The length of the recommended key (in bytes).  This function will store the suitable size back in this variable.
+  @return CRYPT_OK if the input key size is acceptable.
+*/
+int skipjack_keysize(int *keysize)
+{
+   LTC_ARGCHK(keysize != NULL);
+   if (*keysize < 10) {
+      return CRYPT_INVALID_KEYSIZE;
+   } else if (*keysize > 10) {
+      *keysize = 10;
+   }
+   return CRYPT_OK;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/ciphers/twofish/twofish.c b/libtomcrypt/src/ciphers/twofish/twofish.c
new file mode 100644 (file)
index 0000000..b1584d1
--- /dev/null
@@ -0,0 +1,711 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+ /**
+   @file twofish.c
+   Implementation of Twofish by Tom St Denis
+ */
+#include "tomcrypt.h"
+
+#ifdef LTC_TWOFISH
+
+/* first LTC_TWOFISH_ALL_TABLES must ensure LTC_TWOFISH_TABLES is defined */
+#ifdef LTC_TWOFISH_ALL_TABLES
+#ifndef LTC_TWOFISH_TABLES
+#define LTC_TWOFISH_TABLES
+#endif
+#endif
+
+const struct ltc_cipher_descriptor twofish_desc =
+{
+    "twofish",
+    7,
+    16, 32, 16, 16,
+    &twofish_setup,
+    &twofish_ecb_encrypt,
+    &twofish_ecb_decrypt,
+    &twofish_test,
+    &twofish_done,
+    &twofish_keysize,
+    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
+};
+
+/* the two polynomials */
+#define MDS_POLY          0x169
+#define RS_POLY           0x14D
+
+/* The 4x8 RS Linear Transform */
+static const unsigned char RS[4][8] = {
+    { 0x01, 0xA4, 0x55, 0x87, 0x5A, 0x58, 0xDB, 0x9E },
+    { 0xA4, 0x56, 0x82, 0xF3, 0X1E, 0XC6, 0X68, 0XE5 },
+    { 0X02, 0XA1, 0XFC, 0XC1, 0X47, 0XAE, 0X3D, 0X19 },
+    { 0XA4, 0X55, 0X87, 0X5A, 0X58, 0XDB, 0X9E, 0X03 }
+};
+
+#ifdef LTC_TWOFISH_SMALL
+/* sbox usage orderings */
+static const unsigned char qord[4][5] = {
+   { 1, 1, 0, 0, 1 },
+   { 0, 1, 1, 0, 0 },
+   { 0, 0, 0, 1, 1 },
+   { 1, 0, 1, 1, 0 }
+};
+#endif /* LTC_TWOFISH_SMALL */
+
+#ifdef LTC_TWOFISH_TABLES
+
+#define __LTC_TWOFISH_TAB_C__
+#include "twofish_tab.c"
+
+#define sbox(i, x) ((ulong32)SBOX[i][(x)&255])
+
+#else
+
+/* The Q-box tables */
+static const unsigned char qbox[2][4][16] = {
+{
+   { 0x8, 0x1, 0x7, 0xD, 0x6, 0xF, 0x3, 0x2, 0x0, 0xB, 0x5, 0x9, 0xE, 0xC, 0xA, 0x4 },
+   { 0xE, 0XC, 0XB, 0X8, 0X1, 0X2, 0X3, 0X5, 0XF, 0X4, 0XA, 0X6, 0X7, 0X0, 0X9, 0XD },
+   { 0XB, 0XA, 0X5, 0XE, 0X6, 0XD, 0X9, 0X0, 0XC, 0X8, 0XF, 0X3, 0X2, 0X4, 0X7, 0X1 },
+   { 0XD, 0X7, 0XF, 0X4, 0X1, 0X2, 0X6, 0XE, 0X9, 0XB, 0X3, 0X0, 0X8, 0X5, 0XC, 0XA }
+},
+{
+   { 0X2, 0X8, 0XB, 0XD, 0XF, 0X7, 0X6, 0XE, 0X3, 0X1, 0X9, 0X4, 0X0, 0XA, 0XC, 0X5 },
+   { 0X1, 0XE, 0X2, 0XB, 0X4, 0XC, 0X3, 0X7, 0X6, 0XD, 0XA, 0X5, 0XF, 0X9, 0X0, 0X8 },
+   { 0X4, 0XC, 0X7, 0X5, 0X1, 0X6, 0X9, 0XA, 0X0, 0XE, 0XD, 0X8, 0X2, 0XB, 0X3, 0XF },
+   { 0xB, 0X9, 0X5, 0X1, 0XC, 0X3, 0XD, 0XE, 0X6, 0X4, 0X7, 0XF, 0X2, 0X0, 0X8, 0XA }
+}
+};
+
+/* computes S_i[x] */
+#ifdef LTC_CLEAN_STACK
+static ulong32 _sbox(int i, ulong32 x)
+#else
+static ulong32 sbox(int i, ulong32 x)
+#endif
+{
+   unsigned char a0,b0,a1,b1,a2,b2,a3,b3,a4,b4,y;
+
+   /* a0,b0 = [x/16], x mod 16 */
+   a0 = (unsigned char)((x>>4)&15);
+   b0 = (unsigned char)((x)&15);
+
+   /* a1 = a0 ^ b0 */
+   a1 = a0 ^ b0;
+
+   /* b1 = a0 ^ ROR(b0, 1) ^ 8a0 */
+   b1 = (a0 ^ ((b0<<3)|(b0>>1)) ^ (a0<<3)) & 15;
+
+   /* a2,b2 = t0[a1], t1[b1] */
+   a2 = qbox[i][0][(int)a1];
+   b2 = qbox[i][1][(int)b1];
+
+   /* a3 = a2 ^ b2 */
+   a3 = a2 ^ b2;
+
+   /* b3 = a2 ^ ROR(b2, 1) ^ 8a2 */
+   b3 = (a2 ^ ((b2<<3)|(b2>>1)) ^ (a2<<3)) & 15;
+
+   /* a4,b4 = t2[a3], t3[b3] */
+   a4 = qbox[i][2][(int)a3];
+   b4 = qbox[i][3][(int)b3];
+
+   /* y = 16b4 + a4 */
+   y = (b4 << 4) + a4;
+
+   /* return result */
+   return (ulong32)y;
+}
+
+#ifdef LTC_CLEAN_STACK
+static ulong32 sbox(int i, ulong32 x)
+{
+   ulong32 y;
+   y = _sbox(i, x);
+   burn_stack(sizeof(unsigned char) * 11);
+   return y;
+}
+#endif /* LTC_CLEAN_STACK */
+
+#endif /* LTC_TWOFISH_TABLES */
+
+/* computes ab mod p */
+static ulong32 gf_mult(ulong32 a, ulong32 b, ulong32 p)
+{
+   ulong32 result, B[2], P[2];
+
+   P[1] = p;
+   B[1] = b;
+   result = P[0] = B[0] = 0;
+
+   /* unrolled branchless GF multiplier */
+   result ^= B[a&1]; a >>= 1;  B[1] = P[B[1]>>7] ^ (B[1] << 1);
+   result ^= B[a&1]; a >>= 1;  B[1] = P[B[1]>>7] ^ (B[1] << 1);
+   result ^= B[a&1]; a >>= 1;  B[1] = P[B[1]>>7] ^ (B[1] << 1);
+   result ^= B[a&1]; a >>= 1;  B[1] = P[B[1]>>7] ^ (B[1] << 1);
+   result ^= B[a&1]; a >>= 1;  B[1] = P[B[1]>>7] ^ (B[1] << 1);
+   result ^= B[a&1]; a >>= 1;  B[1] = P[B[1]>>7] ^ (B[1] << 1);
+   result ^= B[a&1]; a >>= 1;  B[1] = P[B[1]>>7] ^ (B[1] << 1);
+   result ^= B[a&1];
+
+   return result;
+}
+
+/* computes [y0 y1 y2 y3] = MDS . [x0] */
+#ifndef LTC_TWOFISH_TABLES
+static ulong32 mds_column_mult(unsigned char in, int col)
+{
+   ulong32 x01, x5B, xEF;
+
+   x01 = in;
+   x5B = gf_mult(in, 0x5B, MDS_POLY);
+   xEF = gf_mult(in, 0xEF, MDS_POLY);
+
+   switch (col) {
+       case 0:
+          return (x01 << 0 ) |
+                 (x5B << 8 ) |
+                 (xEF << 16) |
+                 (xEF << 24);
+       case 1:
+          return (xEF << 0 ) |
+                 (xEF << 8 ) |
+                 (x5B << 16) |
+                 (x01 << 24);
+       case 2:
+          return (x5B << 0 ) |
+                 (xEF << 8 ) |
+                 (x01 << 16) |
+                 (xEF << 24);
+       case 3:
+          return (x5B << 0 ) |
+                 (x01 << 8 ) |
+                 (xEF << 16) |
+                 (x5B << 24);
+   }
+   /* avoid warnings, we'd never get here normally but just to calm compiler warnings... */
+   return 0;
+}
+
+#else /* !LTC_TWOFISH_TABLES */
+
+#define mds_column_mult(x, i) mds_tab[i][x]
+
+#endif /* LTC_TWOFISH_TABLES */
+
+/* Computes [y0 y1 y2 y3] = MDS . [x0 x1 x2 x3] */
+static void mds_mult(const unsigned char *in, unsigned char *out)
+{
+  int x;
+  ulong32 tmp;
+  for (tmp = x = 0; x < 4; x++) {
+      tmp ^= mds_column_mult(in[x], x);
+  }
+  STORE32L(tmp, out);
+}
+
+#ifdef LTC_TWOFISH_ALL_TABLES
+/* computes [y0 y1 y2 y3] = RS . [x0 x1 x2 x3 x4 x5 x6 x7] */
+static void rs_mult(const unsigned char *in, unsigned char *out)
+{
+   ulong32 tmp;
+   tmp = rs_tab0[in[0]] ^ rs_tab1[in[1]] ^ rs_tab2[in[2]] ^ rs_tab3[in[3]] ^
+         rs_tab4[in[4]] ^ rs_tab5[in[5]] ^ rs_tab6[in[6]] ^ rs_tab7[in[7]];
+   STORE32L(tmp, out);
+}
+
+#else /* !LTC_TWOFISH_ALL_TABLES */
+
+/* computes [y0 y1 y2 y3] = RS . [x0 x1 x2 x3 x4 x5 x6 x7] */
+static void rs_mult(const unsigned char *in, unsigned char *out)
+{
+  int x, y;
+  for (x = 0; x < 4; x++) {
+      out[x] = 0;
+      for (y = 0; y < 8; y++) {
+          out[x] ^= gf_mult(in[y], RS[x][y], RS_POLY);
+      }
+  }
+}
+
+#endif
+
+/* computes h(x) */
+static void h_func(const unsigned char *in, unsigned char *out, unsigned char *M, int k, int offset)
+{
+  int x;
+  unsigned char y[4];
+  for (x = 0; x < 4; x++) {
+      y[x] = in[x];
+  }
+  switch (k) {
+     case 4:
+            y[0] = (unsigned char)(sbox(1, (ulong32)y[0]) ^ M[4 * (6 + offset) + 0]);
+            y[1] = (unsigned char)(sbox(0, (ulong32)y[1]) ^ M[4 * (6 + offset) + 1]);
+            y[2] = (unsigned char)(sbox(0, (ulong32)y[2]) ^ M[4 * (6 + offset) + 2]);
+            y[3] = (unsigned char)(sbox(1, (ulong32)y[3]) ^ M[4 * (6 + offset) + 3]);
+            /* FALLTHROUGH */
+     case 3:
+            y[0] = (unsigned char)(sbox(1, (ulong32)y[0]) ^ M[4 * (4 + offset) + 0]);
+            y[1] = (unsigned char)(sbox(1, (ulong32)y[1]) ^ M[4 * (4 + offset) + 1]);
+            y[2] = (unsigned char)(sbox(0, (ulong32)y[2]) ^ M[4 * (4 + offset) + 2]);
+            y[3] = (unsigned char)(sbox(0, (ulong32)y[3]) ^ M[4 * (4 + offset) + 3]);
+            /* FALLTHROUGH */
+     case 2:
+            y[0] = (unsigned char)(sbox(1, sbox(0, sbox(0, (ulong32)y[0]) ^ M[4 * (2 + offset) + 0]) ^ M[4 * (0 + offset) + 0]));
+            y[1] = (unsigned char)(sbox(0, sbox(0, sbox(1, (ulong32)y[1]) ^ M[4 * (2 + offset) + 1]) ^ M[4 * (0 + offset) + 1]));
+            y[2] = (unsigned char)(sbox(1, sbox(1, sbox(0, (ulong32)y[2]) ^ M[4 * (2 + offset) + 2]) ^ M[4 * (0 + offset) + 2]));
+            y[3] = (unsigned char)(sbox(0, sbox(1, sbox(1, (ulong32)y[3]) ^ M[4 * (2 + offset) + 3]) ^ M[4 * (0 + offset) + 3]));
+            /* FALLTHROUGH */
+  }
+  mds_mult(y, out);
+}
+
+#ifndef LTC_TWOFISH_SMALL
+
+/* for GCC we don't use pointer aliases */
+#if defined(__GNUC__)
+    #define S1 skey->twofish.S[0]
+    #define S2 skey->twofish.S[1]
+    #define S3 skey->twofish.S[2]
+    #define S4 skey->twofish.S[3]
+#endif
+
+/* the G function */
+#define g_func(x, dum)  (S1[byte(x,0)] ^ S2[byte(x,1)] ^ S3[byte(x,2)] ^ S4[byte(x,3)])
+#define g1_func(x, dum) (S2[byte(x,0)] ^ S3[byte(x,1)] ^ S4[byte(x,2)] ^ S1[byte(x,3)])
+
+#else
+
+#ifdef LTC_CLEAN_STACK
+static ulong32 _g_func(ulong32 x, symmetric_key *key)
+#else
+static ulong32 g_func(ulong32 x, symmetric_key *key)
+#endif
+{
+   unsigned char g, i, y, z;
+   ulong32 res;
+
+   res = 0;
+   for (y = 0; y < 4; y++) {
+       z = key->twofish.start;
+
+       /* do unkeyed substitution */
+       g = sbox(qord[y][z++], (x >> (8*y)) & 255);
+
+       /* first subkey */
+       i = 0;
+
+       /* do key mixing+sbox until z==5 */
+       while (z != 5) {
+          g = g ^ key->twofish.S[4*i++ + y];
+          g = sbox(qord[y][z++], g);
+       }
+
+       /* multiply g by a column of the MDS */
+       res ^= mds_column_mult(g, y);
+   }
+   return res;
+}
+
+#define g1_func(x, key) g_func(ROLc(x, 8), key)
+
+#ifdef LTC_CLEAN_STACK
+static ulong32 g_func(ulong32 x, symmetric_key *key)
+{
+    ulong32 y;
+    y = _g_func(x, key);
+    burn_stack(sizeof(unsigned char) * 4 + sizeof(ulong32));
+    return y;
+}
+#endif /* LTC_CLEAN_STACK */
+
+#endif /* LTC_TWOFISH_SMALL */
+
+ /**
+    Initialize the Twofish block cipher
+    @param key The symmetric key you wish to pass
+    @param keylen The key length in bytes
+    @param num_rounds The number of rounds desired (0 for default)
+    @param skey The key in as scheduled by this function.
+    @return CRYPT_OK if successful
+ */
+#ifdef LTC_CLEAN_STACK
+static int _twofish_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey)
+#else
+int twofish_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey)
+#endif
+{
+#ifndef LTC_TWOFISH_SMALL
+   unsigned char S[4*4], tmpx0, tmpx1;
+#endif
+   int k, x, y;
+   unsigned char tmp[4], tmp2[4], M[8*4];
+   ulong32 A, B;
+
+   LTC_ARGCHK(key  != NULL);
+   LTC_ARGCHK(skey != NULL);
+
+   /* invalid arguments? */
+   if (num_rounds != 16 && num_rounds != 0) {
+      return CRYPT_INVALID_ROUNDS;
+   }
+
+   if (keylen != 16 && keylen != 24 && keylen != 32) {
+      return CRYPT_INVALID_KEYSIZE;
+   }
+
+   /* k = keysize/64 [but since our keysize is in bytes...] */
+   k = keylen / 8;
+
+   /* copy the key into M */
+   for (x = 0; x < keylen; x++) {
+       M[x] = key[x] & 255;
+   }
+
+   /* create the S[..] words */
+#ifndef LTC_TWOFISH_SMALL
+   for (x = 0; x < k; x++) {
+       rs_mult(M+(x*8), S+(x*4));
+   }
+#else
+   for (x = 0; x < k; x++) {
+       rs_mult(M+(x*8), skey->twofish.S+(x*4));
+   }
+#endif
+
+   /* make subkeys */
+   for (x = 0; x < 20; x++) {
+       /* A = h(p * 2x, Me) */
+       for (y = 0; y < 4; y++) {
+           tmp[y] = x+x;
+       }
+       h_func(tmp, tmp2, M, k, 0);
+       LOAD32L(A, tmp2);
+
+       /* B = ROL(h(p * (2x + 1), Mo), 8) */
+       for (y = 0; y < 4; y++) {
+           tmp[y] = (unsigned char)(x+x+1);
+       }
+       h_func(tmp, tmp2, M, k, 1);
+       LOAD32L(B, tmp2);
+       B = ROLc(B, 8);
+
+       /* K[2i]   = A + B */
+       skey->twofish.K[x+x] = (A + B) & 0xFFFFFFFFUL;
+
+       /* K[2i+1] = (A + 2B) <<< 9 */
+       skey->twofish.K[x+x+1] = ROLc(B + B + A, 9);
+   }
+
+#ifndef LTC_TWOFISH_SMALL
+   /* make the sboxes (large ram variant) */
+   if (k == 2) {
+        for (x = 0; x < 256; x++) {
+           tmpx0 = (unsigned char)sbox(0, x);
+           tmpx1 = (unsigned char)sbox(1, x);
+           skey->twofish.S[0][x] = mds_column_mult(sbox(1, (sbox(0, tmpx0 ^ S[0]) ^ S[4])),0);
+           skey->twofish.S[1][x] = mds_column_mult(sbox(0, (sbox(0, tmpx1 ^ S[1]) ^ S[5])),1);
+           skey->twofish.S[2][x] = mds_column_mult(sbox(1, (sbox(1, tmpx0 ^ S[2]) ^ S[6])),2);
+           skey->twofish.S[3][x] = mds_column_mult(sbox(0, (sbox(1, tmpx1 ^ S[3]) ^ S[7])),3);
+        }
+   } else if (k == 3) {
+        for (x = 0; x < 256; x++) {
+           tmpx0 = (unsigned char)sbox(0, x);
+           tmpx1 = (unsigned char)sbox(1, x);
+           skey->twofish.S[0][x] = mds_column_mult(sbox(1, (sbox(0, sbox(0, tmpx1 ^ S[0]) ^ S[4]) ^ S[8])),0);
+           skey->twofish.S[1][x] = mds_column_mult(sbox(0, (sbox(0, sbox(1, tmpx1 ^ S[1]) ^ S[5]) ^ S[9])),1);
+           skey->twofish.S[2][x] = mds_column_mult(sbox(1, (sbox(1, sbox(0, tmpx0 ^ S[2]) ^ S[6]) ^ S[10])),2);
+           skey->twofish.S[3][x] = mds_column_mult(sbox(0, (sbox(1, sbox(1, tmpx0 ^ S[3]) ^ S[7]) ^ S[11])),3);
+        }
+   } else {
+        for (x = 0; x < 256; x++) {
+           tmpx0 = (unsigned char)sbox(0, x);
+           tmpx1 = (unsigned char)sbox(1, x);
+           skey->twofish.S[0][x] = mds_column_mult(sbox(1, (sbox(0, sbox(0, sbox(1, tmpx1 ^ S[0]) ^ S[4]) ^ S[8]) ^ S[12])),0);
+           skey->twofish.S[1][x] = mds_column_mult(sbox(0, (sbox(0, sbox(1, sbox(1, tmpx0 ^ S[1]) ^ S[5]) ^ S[9]) ^ S[13])),1);
+           skey->twofish.S[2][x] = mds_column_mult(sbox(1, (sbox(1, sbox(0, sbox(0, tmpx0 ^ S[2]) ^ S[6]) ^ S[10]) ^ S[14])),2);
+           skey->twofish.S[3][x] = mds_column_mult(sbox(0, (sbox(1, sbox(1, sbox(0, tmpx1 ^ S[3]) ^ S[7]) ^ S[11]) ^ S[15])),3);
+        }
+   }
+#else
+   /* where to start in the sbox layers */
+   /* small ram variant */
+   switch (k) {
+         case 4 : skey->twofish.start = 0; break;
+         case 3 : skey->twofish.start = 1; break;
+         default: skey->twofish.start = 2; break;
+   }
+#endif
+   return CRYPT_OK;
+}
+
+#ifdef LTC_CLEAN_STACK
+int twofish_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey)
+{
+   int x;
+   x = _twofish_setup(key, keylen, num_rounds, skey);
+   burn_stack(sizeof(int) * 7 + sizeof(unsigned char) * 56 + sizeof(ulong32) * 2);
+   return x;
+}
+#endif
+
+/**
+  Encrypts a block of text with Twofish
+  @param pt The input plaintext (16 bytes)
+  @param ct The output ciphertext (16 bytes)
+  @param skey The key as scheduled
+  @return CRYPT_OK if successful
+*/
+#ifdef LTC_CLEAN_STACK
+static int _twofish_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey)
+#else
+int twofish_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey)
+#endif
+{
+    ulong32 a,b,c,d,ta,tb,tc,td,t1,t2, *k;
+    int r;
+#if !defined(LTC_TWOFISH_SMALL) && !defined(__GNUC__)
+    ulong32 *S1, *S2, *S3, *S4;
+#endif
+
+    LTC_ARGCHK(pt   != NULL);
+    LTC_ARGCHK(ct   != NULL);
+    LTC_ARGCHK(skey != NULL);
+
+#if !defined(LTC_TWOFISH_SMALL) && !defined(__GNUC__)
+    S1 = skey->twofish.S[0];
+    S2 = skey->twofish.S[1];
+    S3 = skey->twofish.S[2];
+    S4 = skey->twofish.S[3];
+#endif
+
+    LOAD32L(a,&pt[0]); LOAD32L(b,&pt[4]);
+    LOAD32L(c,&pt[8]); LOAD32L(d,&pt[12]);
+    a ^= skey->twofish.K[0];
+    b ^= skey->twofish.K[1];
+    c ^= skey->twofish.K[2];
+    d ^= skey->twofish.K[3];
+
+    k  = skey->twofish.K + 8;
+    for (r = 8; r != 0; --r) {
+        t2 = g1_func(b, skey);
+        t1 = g_func(a, skey) + t2;
+        c  = RORc(c ^ (t1 + k[0]), 1);
+        d  = ROLc(d, 1) ^ (t2 + t1 + k[1]);
+
+        t2 = g1_func(d, skey);
+        t1 = g_func(c, skey) + t2;
+        a  = RORc(a ^ (t1 + k[2]), 1);
+        b  = ROLc(b, 1) ^ (t2 + t1 + k[3]);
+        k += 4;
+    }
+
+    /* output with "undo last swap" */
+    ta = c ^ skey->twofish.K[4];
+    tb = d ^ skey->twofish.K[5];
+    tc = a ^ skey->twofish.K[6];
+    td = b ^ skey->twofish.K[7];
+
+    /* store output */
+    STORE32L(ta,&ct[0]); STORE32L(tb,&ct[4]);
+    STORE32L(tc,&ct[8]); STORE32L(td,&ct[12]);
+
+    return CRYPT_OK;
+}
+
+#ifdef LTC_CLEAN_STACK
+int twofish_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey)
+{
+   int err = _twofish_ecb_encrypt(pt, ct, skey);
+   burn_stack(sizeof(ulong32) * 10 + sizeof(int));
+   return err;
+}
+#endif
+
+/**
+  Decrypts a block of text with Twofish
+  @param ct The input ciphertext (16 bytes)
+  @param pt The output plaintext (16 bytes)
+  @param skey The key as scheduled
+  @return CRYPT_OK if successful
+*/
+#ifdef LTC_CLEAN_STACK
+static int _twofish_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey)
+#else
+int twofish_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey)
+#endif
+{
+    ulong32 a,b,c,d,ta,tb,tc,td,t1,t2, *k;
+    int r;
+#if !defined(LTC_TWOFISH_SMALL) && !defined(__GNUC__)
+    ulong32 *S1, *S2, *S3, *S4;
+#endif
+
+    LTC_ARGCHK(pt   != NULL);
+    LTC_ARGCHK(ct   != NULL);
+    LTC_ARGCHK(skey != NULL);
+
+#if !defined(LTC_TWOFISH_SMALL) && !defined(__GNUC__)
+    S1 = skey->twofish.S[0];
+    S2 = skey->twofish.S[1];
+    S3 = skey->twofish.S[2];
+    S4 = skey->twofish.S[3];
+#endif
+
+    /* load input */
+    LOAD32L(ta,&ct[0]); LOAD32L(tb,&ct[4]);
+    LOAD32L(tc,&ct[8]); LOAD32L(td,&ct[12]);
+
+    /* undo undo final swap */
+    a = tc ^ skey->twofish.K[6];
+    b = td ^ skey->twofish.K[7];
+    c = ta ^ skey->twofish.K[4];
+    d = tb ^ skey->twofish.K[5];
+
+    k = skey->twofish.K + 36;
+    for (r = 8; r != 0; --r) {
+        t2 = g1_func(d, skey);
+        t1 = g_func(c, skey) + t2;
+        a = ROLc(a, 1) ^ (t1 + k[2]);
+        b = RORc(b ^ (t2 + t1 + k[3]), 1);
+
+        t2 = g1_func(b, skey);
+        t1 = g_func(a, skey) + t2;
+        c = ROLc(c, 1) ^ (t1 + k[0]);
+        d = RORc(d ^ (t2 +  t1 + k[1]), 1);
+        k -= 4;
+    }
+
+    /* pre-white */
+    a ^= skey->twofish.K[0];
+    b ^= skey->twofish.K[1];
+    c ^= skey->twofish.K[2];
+    d ^= skey->twofish.K[3];
+
+    /* store */
+    STORE32L(a, &pt[0]); STORE32L(b, &pt[4]);
+    STORE32L(c, &pt[8]); STORE32L(d, &pt[12]);
+    return CRYPT_OK;
+}
+
+#ifdef LTC_CLEAN_STACK
+int twofish_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey)
+{
+   int err =_twofish_ecb_decrypt(ct, pt, skey);
+   burn_stack(sizeof(ulong32) * 10 + sizeof(int));
+   return err;
+}
+#endif
+
+/**
+  Performs a self-test of the Twofish block cipher
+  @return CRYPT_OK if functional, CRYPT_NOP if self-test has been disabled
+*/
+int twofish_test(void)
+{
+ #ifndef LTC_TEST
+    return CRYPT_NOP;
+ #else
+ static const struct {
+     int keylen;
+     unsigned char key[32], pt[16], ct[16];
+ } tests[] = {
+   { 16,
+     { 0x9F, 0x58, 0x9F, 0x5C, 0xF6, 0x12, 0x2C, 0x32,
+       0xB6, 0xBF, 0xEC, 0x2F, 0x2A, 0xE8, 0xC3, 0x5A },
+     { 0xD4, 0x91, 0xDB, 0x16, 0xE7, 0xB1, 0xC3, 0x9E,
+       0x86, 0xCB, 0x08, 0x6B, 0x78, 0x9F, 0x54, 0x19 },
+     { 0x01, 0x9F, 0x98, 0x09, 0xDE, 0x17, 0x11, 0x85,
+       0x8F, 0xAA, 0xC3, 0xA3, 0xBA, 0x20, 0xFB, 0xC3 }
+   }, {
+     24,
+     { 0x88, 0xB2, 0xB2, 0x70, 0x6B, 0x10, 0x5E, 0x36,
+       0xB4, 0x46, 0xBB, 0x6D, 0x73, 0x1A, 0x1E, 0x88,
+       0xEF, 0xA7, 0x1F, 0x78, 0x89, 0x65, 0xBD, 0x44 },
+     { 0x39, 0xDA, 0x69, 0xD6, 0xBA, 0x49, 0x97, 0xD5,
+       0x85, 0xB6, 0xDC, 0x07, 0x3C, 0xA3, 0x41, 0xB2 },
+     { 0x18, 0x2B, 0x02, 0xD8, 0x14, 0x97, 0xEA, 0x45,
+       0xF9, 0xDA, 0xAC, 0xDC, 0x29, 0x19, 0x3A, 0x65 }
+   }, {
+     32,
+     { 0xD4, 0x3B, 0xB7, 0x55, 0x6E, 0xA3, 0x2E, 0x46,
+       0xF2, 0xA2, 0x82, 0xB7, 0xD4, 0x5B, 0x4E, 0x0D,
+       0x57, 0xFF, 0x73, 0x9D, 0x4D, 0xC9, 0x2C, 0x1B,
+       0xD7, 0xFC, 0x01, 0x70, 0x0C, 0xC8, 0x21, 0x6F },
+     { 0x90, 0xAF, 0xE9, 0x1B, 0xB2, 0x88, 0x54, 0x4F,
+       0x2C, 0x32, 0xDC, 0x23, 0x9B, 0x26, 0x35, 0xE6 },
+     { 0x6C, 0xB4, 0x56, 0x1C, 0x40, 0xBF, 0x0A, 0x97,
+       0x05, 0x93, 0x1C, 0xB6, 0xD4, 0x08, 0xE7, 0xFA }
+   }
+};
+
+
+  symmetric_key key;
+  unsigned char tmp[2][16];
+  int err, i, y;
+
+  for (i = 0; i < (int)(sizeof(tests)/sizeof(tests[0])); i++) {
+    if ((err = twofish_setup(tests[i].key, tests[i].keylen, 0, &key)) != CRYPT_OK) {
+       return err;
+    }
+    twofish_ecb_encrypt(tests[i].pt, tmp[0], &key);
+    twofish_ecb_decrypt(tmp[0], tmp[1], &key);
+    if (compare_testvector(tmp[0], 16, tests[i].ct, 16, "Twofish Encrypt", i) != 0 ||
+          compare_testvector(tmp[1], 16, tests[i].pt, 16, "Twofish Decrypt", i) != 0) {
+       return CRYPT_FAIL_TESTVECTOR;
+    }
+    /* now see if we can encrypt all zero bytes 1000 times, decrypt and come back where we started */
+    for (y = 0; y < 16; y++) tmp[0][y] = 0;
+    for (y = 0; y < 1000; y++) twofish_ecb_encrypt(tmp[0], tmp[0], &key);
+    for (y = 0; y < 1000; y++) twofish_ecb_decrypt(tmp[0], tmp[0], &key);
+    for (y = 0; y < 16; y++) if (tmp[0][y] != 0) return CRYPT_FAIL_TESTVECTOR;
+  }
+  return CRYPT_OK;
+#endif
+}
+
+/** Terminate the context
+   @param skey    The scheduled key
+*/
+void twofish_done(symmetric_key *skey)
+{
+  LTC_UNUSED_PARAM(skey);
+}
+
+/**
+  Gets suitable key size
+  @param keysize [in/out] The length of the recommended key (in bytes).  This function will store the suitable size back in this variable.
+  @return CRYPT_OK if the input key size is acceptable.
+*/
+int twofish_keysize(int *keysize)
+{
+   LTC_ARGCHK(keysize);
+   if (*keysize < 16)
+      return CRYPT_INVALID_KEYSIZE;
+   if (*keysize < 24) {
+      *keysize = 16;
+      return CRYPT_OK;
+   } else if (*keysize < 32) {
+      *keysize = 24;
+      return CRYPT_OK;
+   } else {
+      *keysize = 32;
+      return CRYPT_OK;
+   }
+}
+
+#endif
+
+
+
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/ciphers/twofish/twofish_tab.c b/libtomcrypt/src/ciphers/twofish/twofish_tab.c
new file mode 100644 (file)
index 0000000..b4135ab
--- /dev/null
@@ -0,0 +1,496 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+ /**
+    @file twofish_tab.c
+    Twofish tables, Tom St Denis
+ */
+#ifdef LTC_TWOFISH_TABLES
+#ifdef __LTC_TWOFISH_TAB_C__
+
+/* pre generated 8x8 tables from the four 4x4s */
+static const unsigned char SBOX[2][256] = {
+{
+ 0xa9, 0x67, 0xb3, 0xe8, 0x04, 0xfd, 0xa3, 0x76, 0x9a, 0x92,
+ 0x80, 0x78, 0xe4, 0xdd, 0xd1, 0x38, 0x0d, 0xc6, 0x35, 0x98,
+ 0x18, 0xf7, 0xec, 0x6c, 0x43, 0x75, 0x37, 0x26, 0xfa, 0x13,
+ 0x94, 0x48, 0xf2, 0xd0, 0x8b, 0x30, 0x84, 0x54, 0xdf, 0x23,
+ 0x19, 0x5b, 0x3d, 0x59, 0xf3, 0xae, 0xa2, 0x82, 0x63, 0x01,
+ 0x83, 0x2e, 0xd9, 0x51, 0x9b, 0x7c, 0xa6, 0xeb, 0xa5, 0xbe,
+ 0x16, 0x0c, 0xe3, 0x61, 0xc0, 0x8c, 0x3a, 0xf5, 0x73, 0x2c,
+ 0x25, 0x0b, 0xbb, 0x4e, 0x89, 0x6b, 0x53, 0x6a, 0xb4, 0xf1,
+ 0xe1, 0xe6, 0xbd, 0x45, 0xe2, 0xf4, 0xb6, 0x66, 0xcc, 0x95,
+ 0x03, 0x56, 0xd4, 0x1c, 0x1e, 0xd7, 0xfb, 0xc3, 0x8e, 0xb5,
+ 0xe9, 0xcf, 0xbf, 0xba, 0xea, 0x77, 0x39, 0xaf, 0x33, 0xc9,
+ 0x62, 0x71, 0x81, 0x79, 0x09, 0xad, 0x24, 0xcd, 0xf9, 0xd8,
+ 0xe5, 0xc5, 0xb9, 0x4d, 0x44, 0x08, 0x86, 0xe7, 0xa1, 0x1d,
+ 0xaa, 0xed, 0x06, 0x70, 0xb2, 0xd2, 0x41, 0x7b, 0xa0, 0x11,
+ 0x31, 0xc2, 0x27, 0x90, 0x20, 0xf6, 0x60, 0xff, 0x96, 0x5c,
+ 0xb1, 0xab, 0x9e, 0x9c, 0x52, 0x1b, 0x5f, 0x93, 0x0a, 0xef,
+ 0x91, 0x85, 0x49, 0xee, 0x2d, 0x4f, 0x8f, 0x3b, 0x47, 0x87,
+ 0x6d, 0x46, 0xd6, 0x3e, 0x69, 0x64, 0x2a, 0xce, 0xcb, 0x2f,
+ 0xfc, 0x97, 0x05, 0x7a, 0xac, 0x7f, 0xd5, 0x1a, 0x4b, 0x0e,
+ 0xa7, 0x5a, 0x28, 0x14, 0x3f, 0x29, 0x88, 0x3c, 0x4c, 0x02,
+ 0xb8, 0xda, 0xb0, 0x17, 0x55, 0x1f, 0x8a, 0x7d, 0x57, 0xc7,
+ 0x8d, 0x74, 0xb7, 0xc4, 0x9f, 0x72, 0x7e, 0x15, 0x22, 0x12,
+ 0x58, 0x07, 0x99, 0x34, 0x6e, 0x50, 0xde, 0x68, 0x65, 0xbc,
+ 0xdb, 0xf8, 0xc8, 0xa8, 0x2b, 0x40, 0xdc, 0xfe, 0x32, 0xa4,
+ 0xca, 0x10, 0x21, 0xf0, 0xd3, 0x5d, 0x0f, 0x00, 0x6f, 0x9d,
+ 0x36, 0x42, 0x4a, 0x5e, 0xc1, 0xe0},
+{
+ 0x75, 0xf3, 0xc6, 0xf4, 0xdb, 0x7b, 0xfb, 0xc8, 0x4a, 0xd3,
+ 0xe6, 0x6b, 0x45, 0x7d, 0xe8, 0x4b, 0xd6, 0x32, 0xd8, 0xfd,
+ 0x37, 0x71, 0xf1, 0xe1, 0x30, 0x0f, 0xf8, 0x1b, 0x87, 0xfa,
+ 0x06, 0x3f, 0x5e, 0xba, 0xae, 0x5b, 0x8a, 0x00, 0xbc, 0x9d,
+ 0x6d, 0xc1, 0xb1, 0x0e, 0x80, 0x5d, 0xd2, 0xd5, 0xa0, 0x84,
+ 0x07, 0x14, 0xb5, 0x90, 0x2c, 0xa3, 0xb2, 0x73, 0x4c, 0x54,
+ 0x92, 0x74, 0x36, 0x51, 0x38, 0xb0, 0xbd, 0x5a, 0xfc, 0x60,
+ 0x62, 0x96, 0x6c, 0x42, 0xf7, 0x10, 0x7c, 0x28, 0x27, 0x8c,
+ 0x13, 0x95, 0x9c, 0xc7, 0x24, 0x46, 0x3b, 0x70, 0xca, 0xe3,
+ 0x85, 0xcb, 0x11, 0xd0, 0x93, 0xb8, 0xa6, 0x83, 0x20, 0xff,
+ 0x9f, 0x77, 0xc3, 0xcc, 0x03, 0x6f, 0x08, 0xbf, 0x40, 0xe7,
+ 0x2b, 0xe2, 0x79, 0x0c, 0xaa, 0x82, 0x41, 0x3a, 0xea, 0xb9,
+ 0xe4, 0x9a, 0xa4, 0x97, 0x7e, 0xda, 0x7a, 0x17, 0x66, 0x94,
+ 0xa1, 0x1d, 0x3d, 0xf0, 0xde, 0xb3, 0x0b, 0x72, 0xa7, 0x1c,
+ 0xef, 0xd1, 0x53, 0x3e, 0x8f, 0x33, 0x26, 0x5f, 0xec, 0x76,
+ 0x2a, 0x49, 0x81, 0x88, 0xee, 0x21, 0xc4, 0x1a, 0xeb, 0xd9,
+ 0xc5, 0x39, 0x99, 0xcd, 0xad, 0x31, 0x8b, 0x01, 0x18, 0x23,
+ 0xdd, 0x1f, 0x4e, 0x2d, 0xf9, 0x48, 0x4f, 0xf2, 0x65, 0x8e,
+ 0x78, 0x5c, 0x58, 0x19, 0x8d, 0xe5, 0x98, 0x57, 0x67, 0x7f,
+ 0x05, 0x64, 0xaf, 0x63, 0xb6, 0xfe, 0xf5, 0xb7, 0x3c, 0xa5,
+ 0xce, 0xe9, 0x68, 0x44, 0xe0, 0x4d, 0x43, 0x69, 0x29, 0x2e,
+ 0xac, 0x15, 0x59, 0xa8, 0x0a, 0x9e, 0x6e, 0x47, 0xdf, 0x34,
+ 0x35, 0x6a, 0xcf, 0xdc, 0x22, 0xc9, 0xc0, 0x9b, 0x89, 0xd4,
+ 0xed, 0xab, 0x12, 0xa2, 0x0d, 0x52, 0xbb, 0x02, 0x2f, 0xa9,
+ 0xd7, 0x61, 0x1e, 0xb4, 0x50, 0x04, 0xf6, 0xc2, 0x16, 0x25,
+ 0x86, 0x56, 0x55, 0x09, 0xbe, 0x91}
+};
+
+/* the 4x4 MDS in a nicer format */
+static const ulong32 mds_tab[4][256] = {
+{
+0x00000000UL, 0xefef5b01UL, 0xb7b7b602UL, 0x5858ed03UL, 0x07070504UL, 0xe8e85e05UL, 0xb0b0b306UL, 0x5f5fe807UL,
+0x0e0e0a08UL, 0xe1e15109UL, 0xb9b9bc0aUL, 0x5656e70bUL, 0x09090f0cUL, 0xe6e6540dUL, 0xbebeb90eUL, 0x5151e20fUL,
+0x1c1c1410UL, 0xf3f34f11UL, 0xababa212UL, 0x4444f913UL, 0x1b1b1114UL, 0xf4f44a15UL, 0xacaca716UL, 0x4343fc17UL,
+0x12121e18UL, 0xfdfd4519UL, 0xa5a5a81aUL, 0x4a4af31bUL, 0x15151b1cUL, 0xfafa401dUL, 0xa2a2ad1eUL, 0x4d4df61fUL,
+0x38382820UL, 0xd7d77321UL, 0x8f8f9e22UL, 0x6060c523UL, 0x3f3f2d24UL, 0xd0d07625UL, 0x88889b26UL, 0x6767c027UL,
+0x36362228UL, 0xd9d97929UL, 0x8181942aUL, 0x6e6ecf2bUL, 0x3131272cUL, 0xdede7c2dUL, 0x8686912eUL, 0x6969ca2fUL,
+0x24243c30UL, 0xcbcb6731UL, 0x93938a32UL, 0x7c7cd133UL, 0x23233934UL, 0xcccc6235UL, 0x94948f36UL, 0x7b7bd437UL,
+0x2a2a3638UL, 0xc5c56d39UL, 0x9d9d803aUL, 0x7272db3bUL, 0x2d2d333cUL, 0xc2c2683dUL, 0x9a9a853eUL, 0x7575de3fUL,
+0x70705040UL, 0x9f9f0b41UL, 0xc7c7e642UL, 0x2828bd43UL, 0x77775544UL, 0x98980e45UL, 0xc0c0e346UL, 0x2f2fb847UL,
+0x7e7e5a48UL, 0x91910149UL, 0xc9c9ec4aUL, 0x2626b74bUL, 0x79795f4cUL, 0x9696044dUL, 0xcecee94eUL, 0x2121b24fUL,
+0x6c6c4450UL, 0x83831f51UL, 0xdbdbf252UL, 0x3434a953UL, 0x6b6b4154UL, 0x84841a55UL, 0xdcdcf756UL, 0x3333ac57UL,
+0x62624e58UL, 0x8d8d1559UL, 0xd5d5f85aUL, 0x3a3aa35bUL, 0x65654b5cUL, 0x8a8a105dUL, 0xd2d2fd5eUL, 0x3d3da65fUL,
+0x48487860UL, 0xa7a72361UL, 0xffffce62UL, 0x10109563UL, 0x4f4f7d64UL, 0xa0a02665UL, 0xf8f8cb66UL, 0x17179067UL,
+0x46467268UL, 0xa9a92969UL, 0xf1f1c46aUL, 0x1e1e9f6bUL, 0x4141776cUL, 0xaeae2c6dUL, 0xf6f6c16eUL, 0x19199a6fUL,
+0x54546c70UL, 0xbbbb3771UL, 0xe3e3da72UL, 0x0c0c8173UL, 0x53536974UL, 0xbcbc3275UL, 0xe4e4df76UL, 0x0b0b8477UL,
+0x5a5a6678UL, 0xb5b53d79UL, 0xededd07aUL, 0x02028b7bUL, 0x5d5d637cUL, 0xb2b2387dUL, 0xeaead57eUL, 0x05058e7fUL,
+0xe0e0a080UL, 0x0f0ffb81UL, 0x57571682UL, 0xb8b84d83UL, 0xe7e7a584UL, 0x0808fe85UL, 0x50501386UL, 0xbfbf4887UL,
+0xeeeeaa88UL, 0x0101f189UL, 0x59591c8aUL, 0xb6b6478bUL, 0xe9e9af8cUL, 0x0606f48dUL, 0x5e5e198eUL, 0xb1b1428fUL,
+0xfcfcb490UL, 0x1313ef91UL, 0x4b4b0292UL, 0xa4a45993UL, 0xfbfbb194UL, 0x1414ea95UL, 0x4c4c0796UL, 0xa3a35c97UL,
+0xf2f2be98UL, 0x1d1de599UL, 0x4545089aUL, 0xaaaa539bUL, 0xf5f5bb9cUL, 0x1a1ae09dUL, 0x42420d9eUL, 0xadad569fUL,
+0xd8d888a0UL, 0x3737d3a1UL, 0x6f6f3ea2UL, 0x808065a3UL, 0xdfdf8da4UL, 0x3030d6a5UL, 0x68683ba6UL, 0x878760a7UL,
+0xd6d682a8UL, 0x3939d9a9UL, 0x616134aaUL, 0x8e8e6fabUL, 0xd1d187acUL, 0x3e3edcadUL, 0x666631aeUL, 0x89896aafUL,
+0xc4c49cb0UL, 0x2b2bc7b1UL, 0x73732ab2UL, 0x9c9c71b3UL, 0xc3c399b4UL, 0x2c2cc2b5UL, 0x74742fb6UL, 0x9b9b74b7UL,
+0xcaca96b8UL, 0x2525cdb9UL, 0x7d7d20baUL, 0x92927bbbUL, 0xcdcd93bcUL, 0x2222c8bdUL, 0x7a7a25beUL, 0x95957ebfUL,
+0x9090f0c0UL, 0x7f7fabc1UL, 0x272746c2UL, 0xc8c81dc3UL, 0x9797f5c4UL, 0x7878aec5UL, 0x202043c6UL, 0xcfcf18c7UL,
+0x9e9efac8UL, 0x7171a1c9UL, 0x29294ccaUL, 0xc6c617cbUL, 0x9999ffccUL, 0x7676a4cdUL, 0x2e2e49ceUL, 0xc1c112cfUL,
+0x8c8ce4d0UL, 0x6363bfd1UL, 0x3b3b52d2UL, 0xd4d409d3UL, 0x8b8be1d4UL, 0x6464bad5UL, 0x3c3c57d6UL, 0xd3d30cd7UL,
+0x8282eed8UL, 0x6d6db5d9UL, 0x353558daUL, 0xdada03dbUL, 0x8585ebdcUL, 0x6a6ab0ddUL, 0x32325ddeUL, 0xdddd06dfUL,
+0xa8a8d8e0UL, 0x474783e1UL, 0x1f1f6ee2UL, 0xf0f035e3UL, 0xafafdde4UL, 0x404086e5UL, 0x18186be6UL, 0xf7f730e7UL,
+0xa6a6d2e8UL, 0x494989e9UL, 0x111164eaUL, 0xfefe3febUL, 0xa1a1d7ecUL, 0x4e4e8cedUL, 0x161661eeUL, 0xf9f93aefUL,
+0xb4b4ccf0UL, 0x5b5b97f1UL, 0x03037af2UL, 0xecec21f3UL, 0xb3b3c9f4UL, 0x5c5c92f5UL, 0x04047ff6UL, 0xebeb24f7UL,
+0xbabac6f8UL, 0x55559df9UL, 0x0d0d70faUL, 0xe2e22bfbUL, 0xbdbdc3fcUL, 0x525298fdUL, 0x0a0a75feUL, 0xe5e52effUL
+},
+{
+0x00000000UL, 0x015befefUL, 0x02b6b7b7UL, 0x03ed5858UL, 0x04050707UL, 0x055ee8e8UL, 0x06b3b0b0UL, 0x07e85f5fUL,
+0x080a0e0eUL, 0x0951e1e1UL, 0x0abcb9b9UL, 0x0be75656UL, 0x0c0f0909UL, 0x0d54e6e6UL, 0x0eb9bebeUL, 0x0fe25151UL,
+0x10141c1cUL, 0x114ff3f3UL, 0x12a2ababUL, 0x13f94444UL, 0x14111b1bUL, 0x154af4f4UL, 0x16a7acacUL, 0x17fc4343UL,
+0x181e1212UL, 0x1945fdfdUL, 0x1aa8a5a5UL, 0x1bf34a4aUL, 0x1c1b1515UL, 0x1d40fafaUL, 0x1eada2a2UL, 0x1ff64d4dUL,
+0x20283838UL, 0x2173d7d7UL, 0x229e8f8fUL, 0x23c56060UL, 0x242d3f3fUL, 0x2576d0d0UL, 0x269b8888UL, 0x27c06767UL,
+0x28223636UL, 0x2979d9d9UL, 0x2a948181UL, 0x2bcf6e6eUL, 0x2c273131UL, 0x2d7cdedeUL, 0x2e918686UL, 0x2fca6969UL,
+0x303c2424UL, 0x3167cbcbUL, 0x328a9393UL, 0x33d17c7cUL, 0x34392323UL, 0x3562ccccUL, 0x368f9494UL, 0x37d47b7bUL,
+0x38362a2aUL, 0x396dc5c5UL, 0x3a809d9dUL, 0x3bdb7272UL, 0x3c332d2dUL, 0x3d68c2c2UL, 0x3e859a9aUL, 0x3fde7575UL,
+0x40507070UL, 0x410b9f9fUL, 0x42e6c7c7UL, 0x43bd2828UL, 0x44557777UL, 0x450e9898UL, 0x46e3c0c0UL, 0x47b82f2fUL,
+0x485a7e7eUL, 0x49019191UL, 0x4aecc9c9UL, 0x4bb72626UL, 0x4c5f7979UL, 0x4d049696UL, 0x4ee9ceceUL, 0x4fb22121UL,
+0x50446c6cUL, 0x511f8383UL, 0x52f2dbdbUL, 0x53a93434UL, 0x54416b6bUL, 0x551a8484UL, 0x56f7dcdcUL, 0x57ac3333UL,
+0x584e6262UL, 0x59158d8dUL, 0x5af8d5d5UL, 0x5ba33a3aUL, 0x5c4b6565UL, 0x5d108a8aUL, 0x5efdd2d2UL, 0x5fa63d3dUL,
+0x60784848UL, 0x6123a7a7UL, 0x62ceffffUL, 0x63951010UL, 0x647d4f4fUL, 0x6526a0a0UL, 0x66cbf8f8UL, 0x67901717UL,
+0x68724646UL, 0x6929a9a9UL, 0x6ac4f1f1UL, 0x6b9f1e1eUL, 0x6c774141UL, 0x6d2caeaeUL, 0x6ec1f6f6UL, 0x6f9a1919UL,
+0x706c5454UL, 0x7137bbbbUL, 0x72dae3e3UL, 0x73810c0cUL, 0x74695353UL, 0x7532bcbcUL, 0x76dfe4e4UL, 0x77840b0bUL,
+0x78665a5aUL, 0x793db5b5UL, 0x7ad0ededUL, 0x7b8b0202UL, 0x7c635d5dUL, 0x7d38b2b2UL, 0x7ed5eaeaUL, 0x7f8e0505UL,
+0x80a0e0e0UL, 0x81fb0f0fUL, 0x82165757UL, 0x834db8b8UL, 0x84a5e7e7UL, 0x85fe0808UL, 0x86135050UL, 0x8748bfbfUL,
+0x88aaeeeeUL, 0x89f10101UL, 0x8a1c5959UL, 0x8b47b6b6UL, 0x8cafe9e9UL, 0x8df40606UL, 0x8e195e5eUL, 0x8f42b1b1UL,
+0x90b4fcfcUL, 0x91ef1313UL, 0x92024b4bUL, 0x9359a4a4UL, 0x94b1fbfbUL, 0x95ea1414UL, 0x96074c4cUL, 0x975ca3a3UL,
+0x98bef2f2UL, 0x99e51d1dUL, 0x9a084545UL, 0x9b53aaaaUL, 0x9cbbf5f5UL, 0x9de01a1aUL, 0x9e0d4242UL, 0x9f56adadUL,
+0xa088d8d8UL, 0xa1d33737UL, 0xa23e6f6fUL, 0xa3658080UL, 0xa48ddfdfUL, 0xa5d63030UL, 0xa63b6868UL, 0xa7608787UL,
+0xa882d6d6UL, 0xa9d93939UL, 0xaa346161UL, 0xab6f8e8eUL, 0xac87d1d1UL, 0xaddc3e3eUL, 0xae316666UL, 0xaf6a8989UL,
+0xb09cc4c4UL, 0xb1c72b2bUL, 0xb22a7373UL, 0xb3719c9cUL, 0xb499c3c3UL, 0xb5c22c2cUL, 0xb62f7474UL, 0xb7749b9bUL,
+0xb896cacaUL, 0xb9cd2525UL, 0xba207d7dUL, 0xbb7b9292UL, 0xbc93cdcdUL, 0xbdc82222UL, 0xbe257a7aUL, 0xbf7e9595UL,
+0xc0f09090UL, 0xc1ab7f7fUL, 0xc2462727UL, 0xc31dc8c8UL, 0xc4f59797UL, 0xc5ae7878UL, 0xc6432020UL, 0xc718cfcfUL,
+0xc8fa9e9eUL, 0xc9a17171UL, 0xca4c2929UL, 0xcb17c6c6UL, 0xccff9999UL, 0xcda47676UL, 0xce492e2eUL, 0xcf12c1c1UL,
+0xd0e48c8cUL, 0xd1bf6363UL, 0xd2523b3bUL, 0xd309d4d4UL, 0xd4e18b8bUL, 0xd5ba6464UL, 0xd6573c3cUL, 0xd70cd3d3UL,
+0xd8ee8282UL, 0xd9b56d6dUL, 0xda583535UL, 0xdb03dadaUL, 0xdceb8585UL, 0xddb06a6aUL, 0xde5d3232UL, 0xdf06ddddUL,
+0xe0d8a8a8UL, 0xe1834747UL, 0xe26e1f1fUL, 0xe335f0f0UL, 0xe4ddafafUL, 0xe5864040UL, 0xe66b1818UL, 0xe730f7f7UL,
+0xe8d2a6a6UL, 0xe9894949UL, 0xea641111UL, 0xeb3ffefeUL, 0xecd7a1a1UL, 0xed8c4e4eUL, 0xee611616UL, 0xef3af9f9UL,
+0xf0ccb4b4UL, 0xf1975b5bUL, 0xf27a0303UL, 0xf321ececUL, 0xf4c9b3b3UL, 0xf5925c5cUL, 0xf67f0404UL, 0xf724ebebUL,
+0xf8c6babaUL, 0xf99d5555UL, 0xfa700d0dUL, 0xfb2be2e2UL, 0xfcc3bdbdUL, 0xfd985252UL, 0xfe750a0aUL, 0xff2ee5e5UL
+},
+{
+0x00000000UL, 0xef01ef5bUL, 0xb702b7b6UL, 0x580358edUL, 0x07040705UL, 0xe805e85eUL, 0xb006b0b3UL, 0x5f075fe8UL,
+0x0e080e0aUL, 0xe109e151UL, 0xb90ab9bcUL, 0x560b56e7UL, 0x090c090fUL, 0xe60de654UL, 0xbe0ebeb9UL, 0x510f51e2UL,
+0x1c101c14UL, 0xf311f34fUL, 0xab12aba2UL, 0x441344f9UL, 0x1b141b11UL, 0xf415f44aUL, 0xac16aca7UL, 0x431743fcUL,
+0x1218121eUL, 0xfd19fd45UL, 0xa51aa5a8UL, 0x4a1b4af3UL, 0x151c151bUL, 0xfa1dfa40UL, 0xa21ea2adUL, 0x4d1f4df6UL,
+0x38203828UL, 0xd721d773UL, 0x8f228f9eUL, 0x602360c5UL, 0x3f243f2dUL, 0xd025d076UL, 0x8826889bUL, 0x672767c0UL,
+0x36283622UL, 0xd929d979UL, 0x812a8194UL, 0x6e2b6ecfUL, 0x312c3127UL, 0xde2dde7cUL, 0x862e8691UL, 0x692f69caUL,
+0x2430243cUL, 0xcb31cb67UL, 0x9332938aUL, 0x7c337cd1UL, 0x23342339UL, 0xcc35cc62UL, 0x9436948fUL, 0x7b377bd4UL,
+0x2a382a36UL, 0xc539c56dUL, 0x9d3a9d80UL, 0x723b72dbUL, 0x2d3c2d33UL, 0xc23dc268UL, 0x9a3e9a85UL, 0x753f75deUL,
+0x70407050UL, 0x9f419f0bUL, 0xc742c7e6UL, 0x284328bdUL, 0x77447755UL, 0x9845980eUL, 0xc046c0e3UL, 0x2f472fb8UL,
+0x7e487e5aUL, 0x91499101UL, 0xc94ac9ecUL, 0x264b26b7UL, 0x794c795fUL, 0x964d9604UL, 0xce4ecee9UL, 0x214f21b2UL,
+0x6c506c44UL, 0x8351831fUL, 0xdb52dbf2UL, 0x345334a9UL, 0x6b546b41UL, 0x8455841aUL, 0xdc56dcf7UL, 0x335733acUL,
+0x6258624eUL, 0x8d598d15UL, 0xd55ad5f8UL, 0x3a5b3aa3UL, 0x655c654bUL, 0x8a5d8a10UL, 0xd25ed2fdUL, 0x3d5f3da6UL,
+0x48604878UL, 0xa761a723UL, 0xff62ffceUL, 0x10631095UL, 0x4f644f7dUL, 0xa065a026UL, 0xf866f8cbUL, 0x17671790UL,
+0x46684672UL, 0xa969a929UL, 0xf16af1c4UL, 0x1e6b1e9fUL, 0x416c4177UL, 0xae6dae2cUL, 0xf66ef6c1UL, 0x196f199aUL,
+0x5470546cUL, 0xbb71bb37UL, 0xe372e3daUL, 0x0c730c81UL, 0x53745369UL, 0xbc75bc32UL, 0xe476e4dfUL, 0x0b770b84UL,
+0x5a785a66UL, 0xb579b53dUL, 0xed7aedd0UL, 0x027b028bUL, 0x5d7c5d63UL, 0xb27db238UL, 0xea7eead5UL, 0x057f058eUL,
+0xe080e0a0UL, 0x0f810ffbUL, 0x57825716UL, 0xb883b84dUL, 0xe784e7a5UL, 0x088508feUL, 0x50865013UL, 0xbf87bf48UL,
+0xee88eeaaUL, 0x018901f1UL, 0x598a591cUL, 0xb68bb647UL, 0xe98ce9afUL, 0x068d06f4UL, 0x5e8e5e19UL, 0xb18fb142UL,
+0xfc90fcb4UL, 0x139113efUL, 0x4b924b02UL, 0xa493a459UL, 0xfb94fbb1UL, 0x149514eaUL, 0x4c964c07UL, 0xa397a35cUL,
+0xf298f2beUL, 0x1d991de5UL, 0x459a4508UL, 0xaa9baa53UL, 0xf59cf5bbUL, 0x1a9d1ae0UL, 0x429e420dUL, 0xad9fad56UL,
+0xd8a0d888UL, 0x37a137d3UL, 0x6fa26f3eUL, 0x80a38065UL, 0xdfa4df8dUL, 0x30a530d6UL, 0x68a6683bUL, 0x87a78760UL,
+0xd6a8d682UL, 0x39a939d9UL, 0x61aa6134UL, 0x8eab8e6fUL, 0xd1acd187UL, 0x3ead3edcUL, 0x66ae6631UL, 0x89af896aUL,
+0xc4b0c49cUL, 0x2bb12bc7UL, 0x73b2732aUL, 0x9cb39c71UL, 0xc3b4c399UL, 0x2cb52cc2UL, 0x74b6742fUL, 0x9bb79b74UL,
+0xcab8ca96UL, 0x25b925cdUL, 0x7dba7d20UL, 0x92bb927bUL, 0xcdbccd93UL, 0x22bd22c8UL, 0x7abe7a25UL, 0x95bf957eUL,
+0x90c090f0UL, 0x7fc17fabUL, 0x27c22746UL, 0xc8c3c81dUL, 0x97c497f5UL, 0x78c578aeUL, 0x20c62043UL, 0xcfc7cf18UL,
+0x9ec89efaUL, 0x71c971a1UL, 0x29ca294cUL, 0xc6cbc617UL, 0x99cc99ffUL, 0x76cd76a4UL, 0x2ece2e49UL, 0xc1cfc112UL,
+0x8cd08ce4UL, 0x63d163bfUL, 0x3bd23b52UL, 0xd4d3d409UL, 0x8bd48be1UL, 0x64d564baUL, 0x3cd63c57UL, 0xd3d7d30cUL,
+0x82d882eeUL, 0x6dd96db5UL, 0x35da3558UL, 0xdadbda03UL, 0x85dc85ebUL, 0x6add6ab0UL, 0x32de325dUL, 0xdddfdd06UL,
+0xa8e0a8d8UL, 0x47e14783UL, 0x1fe21f6eUL, 0xf0e3f035UL, 0xafe4afddUL, 0x40e54086UL, 0x18e6186bUL, 0xf7e7f730UL,
+0xa6e8a6d2UL, 0x49e94989UL, 0x11ea1164UL, 0xfeebfe3fUL, 0xa1eca1d7UL, 0x4eed4e8cUL, 0x16ee1661UL, 0xf9eff93aUL,
+0xb4f0b4ccUL, 0x5bf15b97UL, 0x03f2037aUL, 0xecf3ec21UL, 0xb3f4b3c9UL, 0x5cf55c92UL, 0x04f6047fUL, 0xebf7eb24UL,
+0xbaf8bac6UL, 0x55f9559dUL, 0x0dfa0d70UL, 0xe2fbe22bUL, 0xbdfcbdc3UL, 0x52fd5298UL, 0x0afe0a75UL, 0xe5ffe52eUL
+},
+{
+0x00000000UL, 0x5bef015bUL, 0xb6b702b6UL, 0xed5803edUL, 0x05070405UL, 0x5ee8055eUL, 0xb3b006b3UL, 0xe85f07e8UL,
+0x0a0e080aUL, 0x51e10951UL, 0xbcb90abcUL, 0xe7560be7UL, 0x0f090c0fUL, 0x54e60d54UL, 0xb9be0eb9UL, 0xe2510fe2UL,
+0x141c1014UL, 0x4ff3114fUL, 0xa2ab12a2UL, 0xf94413f9UL, 0x111b1411UL, 0x4af4154aUL, 0xa7ac16a7UL, 0xfc4317fcUL,
+0x1e12181eUL, 0x45fd1945UL, 0xa8a51aa8UL, 0xf34a1bf3UL, 0x1b151c1bUL, 0x40fa1d40UL, 0xada21eadUL, 0xf64d1ff6UL,
+0x28382028UL, 0x73d72173UL, 0x9e8f229eUL, 0xc56023c5UL, 0x2d3f242dUL, 0x76d02576UL, 0x9b88269bUL, 0xc06727c0UL,
+0x22362822UL, 0x79d92979UL, 0x94812a94UL, 0xcf6e2bcfUL, 0x27312c27UL, 0x7cde2d7cUL, 0x91862e91UL, 0xca692fcaUL,
+0x3c24303cUL, 0x67cb3167UL, 0x8a93328aUL, 0xd17c33d1UL, 0x39233439UL, 0x62cc3562UL, 0x8f94368fUL, 0xd47b37d4UL,
+0x362a3836UL, 0x6dc5396dUL, 0x809d3a80UL, 0xdb723bdbUL, 0x332d3c33UL, 0x68c23d68UL, 0x859a3e85UL, 0xde753fdeUL,
+0x50704050UL, 0x0b9f410bUL, 0xe6c742e6UL, 0xbd2843bdUL, 0x55774455UL, 0x0e98450eUL, 0xe3c046e3UL, 0xb82f47b8UL,
+0x5a7e485aUL, 0x01914901UL, 0xecc94aecUL, 0xb7264bb7UL, 0x5f794c5fUL, 0x04964d04UL, 0xe9ce4ee9UL, 0xb2214fb2UL,
+0x446c5044UL, 0x1f83511fUL, 0xf2db52f2UL, 0xa93453a9UL, 0x416b5441UL, 0x1a84551aUL, 0xf7dc56f7UL, 0xac3357acUL,
+0x4e62584eUL, 0x158d5915UL, 0xf8d55af8UL, 0xa33a5ba3UL, 0x4b655c4bUL, 0x108a5d10UL, 0xfdd25efdUL, 0xa63d5fa6UL,
+0x78486078UL, 0x23a76123UL, 0xceff62ceUL, 0x95106395UL, 0x7d4f647dUL, 0x26a06526UL, 0xcbf866cbUL, 0x90176790UL,
+0x72466872UL, 0x29a96929UL, 0xc4f16ac4UL, 0x9f1e6b9fUL, 0x77416c77UL, 0x2cae6d2cUL, 0xc1f66ec1UL, 0x9a196f9aUL,
+0x6c54706cUL, 0x37bb7137UL, 0xdae372daUL, 0x810c7381UL, 0x69537469UL, 0x32bc7532UL, 0xdfe476dfUL, 0x840b7784UL,
+0x665a7866UL, 0x3db5793dUL, 0xd0ed7ad0UL, 0x8b027b8bUL, 0x635d7c63UL, 0x38b27d38UL, 0xd5ea7ed5UL, 0x8e057f8eUL,
+0xa0e080a0UL, 0xfb0f81fbUL, 0x16578216UL, 0x4db8834dUL, 0xa5e784a5UL, 0xfe0885feUL, 0x13508613UL, 0x48bf8748UL,
+0xaaee88aaUL, 0xf10189f1UL, 0x1c598a1cUL, 0x47b68b47UL, 0xafe98cafUL, 0xf4068df4UL, 0x195e8e19UL, 0x42b18f42UL,
+0xb4fc90b4UL, 0xef1391efUL, 0x024b9202UL, 0x59a49359UL, 0xb1fb94b1UL, 0xea1495eaUL, 0x074c9607UL, 0x5ca3975cUL,
+0xbef298beUL, 0xe51d99e5UL, 0x08459a08UL, 0x53aa9b53UL, 0xbbf59cbbUL, 0xe01a9de0UL, 0x0d429e0dUL, 0x56ad9f56UL,
+0x88d8a088UL, 0xd337a1d3UL, 0x3e6fa23eUL, 0x6580a365UL, 0x8ddfa48dUL, 0xd630a5d6UL, 0x3b68a63bUL, 0x6087a760UL,
+0x82d6a882UL, 0xd939a9d9UL, 0x3461aa34UL, 0x6f8eab6fUL, 0x87d1ac87UL, 0xdc3eaddcUL, 0x3166ae31UL, 0x6a89af6aUL,
+0x9cc4b09cUL, 0xc72bb1c7UL, 0x2a73b22aUL, 0x719cb371UL, 0x99c3b499UL, 0xc22cb5c2UL, 0x2f74b62fUL, 0x749bb774UL,
+0x96cab896UL, 0xcd25b9cdUL, 0x207dba20UL, 0x7b92bb7bUL, 0x93cdbc93UL, 0xc822bdc8UL, 0x257abe25UL, 0x7e95bf7eUL,
+0xf090c0f0UL, 0xab7fc1abUL, 0x4627c246UL, 0x1dc8c31dUL, 0xf597c4f5UL, 0xae78c5aeUL, 0x4320c643UL, 0x18cfc718UL,
+0xfa9ec8faUL, 0xa171c9a1UL, 0x4c29ca4cUL, 0x17c6cb17UL, 0xff99ccffUL, 0xa476cda4UL, 0x492ece49UL, 0x12c1cf12UL,
+0xe48cd0e4UL, 0xbf63d1bfUL, 0x523bd252UL, 0x09d4d309UL, 0xe18bd4e1UL, 0xba64d5baUL, 0x573cd657UL, 0x0cd3d70cUL,
+0xee82d8eeUL, 0xb56dd9b5UL, 0x5835da58UL, 0x03dadb03UL, 0xeb85dcebUL, 0xb06addb0UL, 0x5d32de5dUL, 0x06dddf06UL,
+0xd8a8e0d8UL, 0x8347e183UL, 0x6e1fe26eUL, 0x35f0e335UL, 0xddafe4ddUL, 0x8640e586UL, 0x6b18e66bUL, 0x30f7e730UL,
+0xd2a6e8d2UL, 0x8949e989UL, 0x6411ea64UL, 0x3ffeeb3fUL, 0xd7a1ecd7UL, 0x8c4eed8cUL, 0x6116ee61UL, 0x3af9ef3aUL,
+0xccb4f0ccUL, 0x975bf197UL, 0x7a03f27aUL, 0x21ecf321UL, 0xc9b3f4c9UL, 0x925cf592UL, 0x7f04f67fUL, 0x24ebf724UL,
+0xc6baf8c6UL, 0x9d55f99dUL, 0x700dfa70UL, 0x2be2fb2bUL, 0xc3bdfcc3UL, 0x9852fd98UL, 0x750afe75UL, 0x2ee5ff2eUL
+}};
+
+#ifdef LTC_TWOFISH_ALL_TABLES
+
+/* the 4x8 RS transform */
+static const ulong32 rs_tab0[256] = {
+0x00000000LU, 0xa402a401LU, 0x05040502LU, 0xa106a103LU, 0x0a080a04LU, 0xae0aae05LU, 0x0f0c0f06LU, 0xab0eab07LU,
+0x14101408LU, 0xb012b009LU, 0x1114110aLU, 0xb516b50bLU, 0x1e181e0cLU, 0xba1aba0dLU, 0x1b1c1b0eLU, 0xbf1ebf0fLU,
+0x28202810LU, 0x8c228c11LU, 0x2d242d12LU, 0x89268913LU, 0x22282214LU, 0x862a8615LU, 0x272c2716LU, 0x832e8317LU,
+0x3c303c18LU, 0x98329819LU, 0x3934391aLU, 0x9d369d1bLU, 0x3638361cLU, 0x923a921dLU, 0x333c331eLU, 0x973e971fLU,
+0x50405020LU, 0xf442f421LU, 0x55445522LU, 0xf146f123LU, 0x5a485a24LU, 0xfe4afe25LU, 0x5f4c5f26LU, 0xfb4efb27LU,
+0x44504428LU, 0xe052e029LU, 0x4154412aLU, 0xe556e52bLU, 0x4e584e2cLU, 0xea5aea2dLU, 0x4b5c4b2eLU, 0xef5eef2fLU,
+0x78607830LU, 0xdc62dc31LU, 0x7d647d32LU, 0xd966d933LU, 0x72687234LU, 0xd66ad635LU, 0x776c7736LU, 0xd36ed337LU,
+0x6c706c38LU, 0xc872c839LU, 0x6974693aLU, 0xcd76cd3bLU, 0x6678663cLU, 0xc27ac23dLU, 0x637c633eLU, 0xc77ec73fLU,
+0xa080a040LU, 0x04820441LU, 0xa584a542LU, 0x01860143LU, 0xaa88aa44LU, 0x0e8a0e45LU, 0xaf8caf46LU, 0x0b8e0b47LU,
+0xb490b448LU, 0x10921049LU, 0xb194b14aLU, 0x1596154bLU, 0xbe98be4cLU, 0x1a9a1a4dLU, 0xbb9cbb4eLU, 0x1f9e1f4fLU,
+0x88a08850LU, 0x2ca22c51LU, 0x8da48d52LU, 0x29a62953LU, 0x82a88254LU, 0x26aa2655LU, 0x87ac8756LU, 0x23ae2357LU,
+0x9cb09c58LU, 0x38b23859LU, 0x99b4995aLU, 0x3db63d5bLU, 0x96b8965cLU, 0x32ba325dLU, 0x93bc935eLU, 0x37be375fLU,
+0xf0c0f060LU, 0x54c25461LU, 0xf5c4f562LU, 0x51c65163LU, 0xfac8fa64LU, 0x5eca5e65LU, 0xffccff66LU, 0x5bce5b67LU,
+0xe4d0e468LU, 0x40d24069LU, 0xe1d4e16aLU, 0x45d6456bLU, 0xeed8ee6cLU, 0x4ada4a6dLU, 0xebdceb6eLU, 0x4fde4f6fLU,
+0xd8e0d870LU, 0x7ce27c71LU, 0xdde4dd72LU, 0x79e67973LU, 0xd2e8d274LU, 0x76ea7675LU, 0xd7ecd776LU, 0x73ee7377LU,
+0xccf0cc78LU, 0x68f26879LU, 0xc9f4c97aLU, 0x6df66d7bLU, 0xc6f8c67cLU, 0x62fa627dLU, 0xc3fcc37eLU, 0x67fe677fLU,
+0x0d4d0d80LU, 0xa94fa981LU, 0x08490882LU, 0xac4bac83LU, 0x07450784LU, 0xa347a385LU, 0x02410286LU, 0xa643a687LU,
+0x195d1988LU, 0xbd5fbd89LU, 0x1c591c8aLU, 0xb85bb88bLU, 0x1355138cLU, 0xb757b78dLU, 0x1651168eLU, 0xb253b28fLU,
+0x256d2590LU, 0x816f8191LU, 0x20692092LU, 0x846b8493LU, 0x2f652f94LU, 0x8b678b95LU, 0x2a612a96LU, 0x8e638e97LU,
+0x317d3198LU, 0x957f9599LU, 0x3479349aLU, 0x907b909bLU, 0x3b753b9cLU, 0x9f779f9dLU, 0x3e713e9eLU, 0x9a739a9fLU,
+0x5d0d5da0LU, 0xf90ff9a1LU, 0x580958a2LU, 0xfc0bfca3LU, 0x570557a4LU, 0xf307f3a5LU, 0x520152a6LU, 0xf603f6a7LU,
+0x491d49a8LU, 0xed1feda9LU, 0x4c194caaLU, 0xe81be8abLU, 0x431543acLU, 0xe717e7adLU, 0x461146aeLU, 0xe213e2afLU,
+0x752d75b0LU, 0xd12fd1b1LU, 0x702970b2LU, 0xd42bd4b3LU, 0x7f257fb4LU, 0xdb27dbb5LU, 0x7a217ab6LU, 0xde23deb7LU,
+0x613d61b8LU, 0xc53fc5b9LU, 0x643964baLU, 0xc03bc0bbLU, 0x6b356bbcLU, 0xcf37cfbdLU, 0x6e316ebeLU, 0xca33cabfLU,
+0xadcdadc0LU, 0x09cf09c1LU, 0xa8c9a8c2LU, 0x0ccb0cc3LU, 0xa7c5a7c4LU, 0x03c703c5LU, 0xa2c1a2c6LU, 0x06c306c7LU,
+0xb9ddb9c8LU, 0x1ddf1dc9LU, 0xbcd9bccaLU, 0x18db18cbLU, 0xb3d5b3ccLU, 0x17d717cdLU, 0xb6d1b6ceLU, 0x12d312cfLU,
+0x85ed85d0LU, 0x21ef21d1LU, 0x80e980d2LU, 0x24eb24d3LU, 0x8fe58fd4LU, 0x2be72bd5LU, 0x8ae18ad6LU, 0x2ee32ed7LU,
+0x91fd91d8LU, 0x35ff35d9LU, 0x94f994daLU, 0x30fb30dbLU, 0x9bf59bdcLU, 0x3ff73fddLU, 0x9ef19edeLU, 0x3af33adfLU,
+0xfd8dfde0LU, 0x598f59e1LU, 0xf889f8e2LU, 0x5c8b5ce3LU, 0xf785f7e4LU, 0x538753e5LU, 0xf281f2e6LU, 0x568356e7LU,
+0xe99de9e8LU, 0x4d9f4de9LU, 0xec99eceaLU, 0x489b48ebLU, 0xe395e3ecLU, 0x479747edLU, 0xe691e6eeLU, 0x429342efLU,
+0xd5add5f0LU, 0x71af71f1LU, 0xd0a9d0f2LU, 0x74ab74f3LU, 0xdfa5dff4LU, 0x7ba77bf5LU, 0xdaa1daf6LU, 0x7ea37ef7LU,
+0xc1bdc1f8LU, 0x65bf65f9LU, 0xc4b9c4faLU, 0x60bb60fbLU, 0xcbb5cbfcLU, 0x6fb76ffdLU, 0xceb1cefeLU, 0x6ab36affLU };
+
+static const ulong32 rs_tab1[256] = {
+0x00000000LU, 0x55a156a4LU, 0xaa0fac05LU, 0xffaefaa1LU, 0x191e150aLU, 0x4cbf43aeLU, 0xb311b90fLU, 0xe6b0efabLU,
+0x323c2a14LU, 0x679d7cb0LU, 0x98338611LU, 0xcd92d0b5LU, 0x2b223f1eLU, 0x7e8369baLU, 0x812d931bLU, 0xd48cc5bfLU,
+0x64785428LU, 0x31d9028cLU, 0xce77f82dLU, 0x9bd6ae89LU, 0x7d664122LU, 0x28c71786LU, 0xd769ed27LU, 0x82c8bb83LU,
+0x56447e3cLU, 0x03e52898LU, 0xfc4bd239LU, 0xa9ea849dLU, 0x4f5a6b36LU, 0x1afb3d92LU, 0xe555c733LU, 0xb0f49197LU,
+0xc8f0a850LU, 0x9d51fef4LU, 0x62ff0455LU, 0x375e52f1LU, 0xd1eebd5aLU, 0x844febfeLU, 0x7be1115fLU, 0x2e4047fbLU,
+0xfacc8244LU, 0xaf6dd4e0LU, 0x50c32e41LU, 0x056278e5LU, 0xe3d2974eLU, 0xb673c1eaLU, 0x49dd3b4bLU, 0x1c7c6defLU,
+0xac88fc78LU, 0xf929aadcLU, 0x0687507dLU, 0x532606d9LU, 0xb596e972LU, 0xe037bfd6LU, 0x1f994577LU, 0x4a3813d3LU,
+0x9eb4d66cLU, 0xcb1580c8LU, 0x34bb7a69LU, 0x611a2ccdLU, 0x87aac366LU, 0xd20b95c2LU, 0x2da56f63LU, 0x780439c7LU,
+0xddad1da0LU, 0x880c4b04LU, 0x77a2b1a5LU, 0x2203e701LU, 0xc4b308aaLU, 0x91125e0eLU, 0x6ebca4afLU, 0x3b1df20bLU,
+0xef9137b4LU, 0xba306110LU, 0x459e9bb1LU, 0x103fcd15LU, 0xf68f22beLU, 0xa32e741aLU, 0x5c808ebbLU, 0x0921d81fLU,
+0xb9d54988LU, 0xec741f2cLU, 0x13dae58dLU, 0x467bb329LU, 0xa0cb5c82LU, 0xf56a0a26LU, 0x0ac4f087LU, 0x5f65a623LU,
+0x8be9639cLU, 0xde483538LU, 0x21e6cf99LU, 0x7447993dLU, 0x92f77696LU, 0xc7562032LU, 0x38f8da93LU, 0x6d598c37LU,
+0x155db5f0LU, 0x40fce354LU, 0xbf5219f5LU, 0xeaf34f51LU, 0x0c43a0faLU, 0x59e2f65eLU, 0xa64c0cffLU, 0xf3ed5a5bLU,
+0x27619fe4LU, 0x72c0c940LU, 0x8d6e33e1LU, 0xd8cf6545LU, 0x3e7f8aeeLU, 0x6bdedc4aLU, 0x947026ebLU, 0xc1d1704fLU,
+0x7125e1d8LU, 0x2484b77cLU, 0xdb2a4dddLU, 0x8e8b1b79LU, 0x683bf4d2LU, 0x3d9aa276LU, 0xc23458d7LU, 0x97950e73LU,
+0x4319cbccLU, 0x16b89d68LU, 0xe91667c9LU, 0xbcb7316dLU, 0x5a07dec6LU, 0x0fa68862LU, 0xf00872c3LU, 0xa5a92467LU,
+0xf7173a0dLU, 0xa2b66ca9LU, 0x5d189608LU, 0x08b9c0acLU, 0xee092f07LU, 0xbba879a3LU, 0x44068302LU, 0x11a7d5a6LU,
+0xc52b1019LU, 0x908a46bdLU, 0x6f24bc1cLU, 0x3a85eab8LU, 0xdc350513LU, 0x899453b7LU, 0x763aa916LU, 0x239bffb2LU,
+0x936f6e25LU, 0xc6ce3881LU, 0x3960c220LU, 0x6cc19484LU, 0x8a717b2fLU, 0xdfd02d8bLU, 0x207ed72aLU, 0x75df818eLU,
+0xa1534431LU, 0xf4f21295LU, 0x0b5ce834LU, 0x5efdbe90LU, 0xb84d513bLU, 0xedec079fLU, 0x1242fd3eLU, 0x47e3ab9aLU,
+0x3fe7925dLU, 0x6a46c4f9LU, 0x95e83e58LU, 0xc04968fcLU, 0x26f98757LU, 0x7358d1f3LU, 0x8cf62b52LU, 0xd9577df6LU,
+0x0ddbb849LU, 0x587aeeedLU, 0xa7d4144cLU, 0xf27542e8LU, 0x14c5ad43LU, 0x4164fbe7LU, 0xbeca0146LU, 0xeb6b57e2LU,
+0x5b9fc675LU, 0x0e3e90d1LU, 0xf1906a70LU, 0xa4313cd4LU, 0x4281d37fLU, 0x172085dbLU, 0xe88e7f7aLU, 0xbd2f29deLU,
+0x69a3ec61LU, 0x3c02bac5LU, 0xc3ac4064LU, 0x960d16c0LU, 0x70bdf96bLU, 0x251cafcfLU, 0xdab2556eLU, 0x8f1303caLU,
+0x2aba27adLU, 0x7f1b7109LU, 0x80b58ba8LU, 0xd514dd0cLU, 0x33a432a7LU, 0x66056403LU, 0x99ab9ea2LU, 0xcc0ac806LU,
+0x18860db9LU, 0x4d275b1dLU, 0xb289a1bcLU, 0xe728f718LU, 0x019818b3LU, 0x54394e17LU, 0xab97b4b6LU, 0xfe36e212LU,
+0x4ec27385LU, 0x1b632521LU, 0xe4cddf80LU, 0xb16c8924LU, 0x57dc668fLU, 0x027d302bLU, 0xfdd3ca8aLU, 0xa8729c2eLU,
+0x7cfe5991LU, 0x295f0f35LU, 0xd6f1f594LU, 0x8350a330LU, 0x65e04c9bLU, 0x30411a3fLU, 0xcfefe09eLU, 0x9a4eb63aLU,
+0xe24a8ffdLU, 0xb7ebd959LU, 0x484523f8LU, 0x1de4755cLU, 0xfb549af7LU, 0xaef5cc53LU, 0x515b36f2LU, 0x04fa6056LU,
+0xd076a5e9LU, 0x85d7f34dLU, 0x7a7909ecLU, 0x2fd85f48LU, 0xc968b0e3LU, 0x9cc9e647LU, 0x63671ce6LU, 0x36c64a42LU,
+0x8632dbd5LU, 0xd3938d71LU, 0x2c3d77d0LU, 0x799c2174LU, 0x9f2ccedfLU, 0xca8d987bLU, 0x352362daLU, 0x6082347eLU,
+0xb40ef1c1LU, 0xe1afa765LU, 0x1e015dc4LU, 0x4ba00b60LU, 0xad10e4cbLU, 0xf8b1b26fLU, 0x071f48ceLU, 0x52be1e6aLU };
+
+static const ulong32 rs_tab2[256] = {
+0x00000000LU, 0x87fc8255LU, 0x43b549aaLU, 0xc449cbffLU, 0x86279219LU, 0x01db104cLU, 0xc592dbb3LU, 0x426e59e6LU,
+0x414e6932LU, 0xc6b2eb67LU, 0x02fb2098LU, 0x8507a2cdLU, 0xc769fb2bLU, 0x4095797eLU, 0x84dcb281LU, 0x032030d4LU,
+0x829cd264LU, 0x05605031LU, 0xc1299bceLU, 0x46d5199bLU, 0x04bb407dLU, 0x8347c228LU, 0x470e09d7LU, 0xc0f28b82LU,
+0xc3d2bb56LU, 0x442e3903LU, 0x8067f2fcLU, 0x079b70a9LU, 0x45f5294fLU, 0xc209ab1aLU, 0x064060e5LU, 0x81bce2b0LU,
+0x4975e9c8LU, 0xce896b9dLU, 0x0ac0a062LU, 0x8d3c2237LU, 0xcf527bd1LU, 0x48aef984LU, 0x8ce7327bLU, 0x0b1bb02eLU,
+0x083b80faLU, 0x8fc702afLU, 0x4b8ec950LU, 0xcc724b05LU, 0x8e1c12e3LU, 0x09e090b6LU, 0xcda95b49LU, 0x4a55d91cLU,
+0xcbe93bacLU, 0x4c15b9f9LU, 0x885c7206LU, 0x0fa0f053LU, 0x4dcea9b5LU, 0xca322be0LU, 0x0e7be01fLU, 0x8987624aLU,
+0x8aa7529eLU, 0x0d5bd0cbLU, 0xc9121b34LU, 0x4eee9961LU, 0x0c80c087LU, 0x8b7c42d2LU, 0x4f35892dLU, 0xc8c90b78LU,
+0x92ea9fddLU, 0x15161d88LU, 0xd15fd677LU, 0x56a35422LU, 0x14cd0dc4LU, 0x93318f91LU, 0x5778446eLU, 0xd084c63bLU,
+0xd3a4f6efLU, 0x545874baLU, 0x9011bf45LU, 0x17ed3d10LU, 0x558364f6LU, 0xd27fe6a3LU, 0x16362d5cLU, 0x91caaf09LU,
+0x10764db9LU, 0x978acfecLU, 0x53c30413LU, 0xd43f8646LU, 0x9651dfa0LU, 0x11ad5df5LU, 0xd5e4960aLU, 0x5218145fLU,
+0x5138248bLU, 0xd6c4a6deLU, 0x128d6d21LU, 0x9571ef74LU, 0xd71fb692LU, 0x50e334c7LU, 0x94aaff38LU, 0x13567d6dLU,
+0xdb9f7615LU, 0x5c63f440LU, 0x982a3fbfLU, 0x1fd6bdeaLU, 0x5db8e40cLU, 0xda446659LU, 0x1e0dada6LU, 0x99f12ff3LU,
+0x9ad11f27LU, 0x1d2d9d72LU, 0xd964568dLU, 0x5e98d4d8LU, 0x1cf68d3eLU, 0x9b0a0f6bLU, 0x5f43c494LU, 0xd8bf46c1LU,
+0x5903a471LU, 0xdeff2624LU, 0x1ab6eddbLU, 0x9d4a6f8eLU, 0xdf243668LU, 0x58d8b43dLU, 0x9c917fc2LU, 0x1b6dfd97LU,
+0x184dcd43LU, 0x9fb14f16LU, 0x5bf884e9LU, 0xdc0406bcLU, 0x9e6a5f5aLU, 0x1996dd0fLU, 0xdddf16f0LU, 0x5a2394a5LU,
+0x699973f7LU, 0xee65f1a2LU, 0x2a2c3a5dLU, 0xadd0b808LU, 0xefbee1eeLU, 0x684263bbLU, 0xac0ba844LU, 0x2bf72a11LU,
+0x28d71ac5LU, 0xaf2b9890LU, 0x6b62536fLU, 0xec9ed13aLU, 0xaef088dcLU, 0x290c0a89LU, 0xed45c176LU, 0x6ab94323LU,
+0xeb05a193LU, 0x6cf923c6LU, 0xa8b0e839LU, 0x2f4c6a6cLU, 0x6d22338aLU, 0xeadeb1dfLU, 0x2e977a20LU, 0xa96bf875LU,
+0xaa4bc8a1LU, 0x2db74af4LU, 0xe9fe810bLU, 0x6e02035eLU, 0x2c6c5ab8LU, 0xab90d8edLU, 0x6fd91312LU, 0xe8259147LU,
+0x20ec9a3fLU, 0xa710186aLU, 0x6359d395LU, 0xe4a551c0LU, 0xa6cb0826LU, 0x21378a73LU, 0xe57e418cLU, 0x6282c3d9LU,
+0x61a2f30dLU, 0xe65e7158LU, 0x2217baa7LU, 0xa5eb38f2LU, 0xe7856114LU, 0x6079e341LU, 0xa43028beLU, 0x23ccaaebLU,
+0xa270485bLU, 0x258cca0eLU, 0xe1c501f1LU, 0x663983a4LU, 0x2457da42LU, 0xa3ab5817LU, 0x67e293e8LU, 0xe01e11bdLU,
+0xe33e2169LU, 0x64c2a33cLU, 0xa08b68c3LU, 0x2777ea96LU, 0x6519b370LU, 0xe2e53125LU, 0x26acfadaLU, 0xa150788fLU,
+0xfb73ec2aLU, 0x7c8f6e7fLU, 0xb8c6a580LU, 0x3f3a27d5LU, 0x7d547e33LU, 0xfaa8fc66LU, 0x3ee13799LU, 0xb91db5ccLU,
+0xba3d8518LU, 0x3dc1074dLU, 0xf988ccb2LU, 0x7e744ee7LU, 0x3c1a1701LU, 0xbbe69554LU, 0x7faf5eabLU, 0xf853dcfeLU,
+0x79ef3e4eLU, 0xfe13bc1bLU, 0x3a5a77e4LU, 0xbda6f5b1LU, 0xffc8ac57LU, 0x78342e02LU, 0xbc7de5fdLU, 0x3b8167a8LU,
+0x38a1577cLU, 0xbf5dd529LU, 0x7b141ed6LU, 0xfce89c83LU, 0xbe86c565LU, 0x397a4730LU, 0xfd338ccfLU, 0x7acf0e9aLU,
+0xb20605e2LU, 0x35fa87b7LU, 0xf1b34c48LU, 0x764fce1dLU, 0x342197fbLU, 0xb3dd15aeLU, 0x7794de51LU, 0xf0685c04LU,
+0xf3486cd0LU, 0x74b4ee85LU, 0xb0fd257aLU, 0x3701a72fLU, 0x756ffec9LU, 0xf2937c9cLU, 0x36dab763LU, 0xb1263536LU,
+0x309ad786LU, 0xb76655d3LU, 0x732f9e2cLU, 0xf4d31c79LU, 0xb6bd459fLU, 0x3141c7caLU, 0xf5080c35LU, 0x72f48e60LU,
+0x71d4beb4LU, 0xf6283ce1LU, 0x3261f71eLU, 0xb59d754bLU, 0xf7f32cadLU, 0x700faef8LU, 0xb4466507LU, 0x33bae752LU };
+
+static const ulong32 rs_tab3[256] = {
+0x00000000LU, 0x5ac1f387LU, 0xb4cfab43LU, 0xee0e58c4LU, 0x25d31b86LU, 0x7f12e801LU, 0x911cb0c5LU, 0xcbdd4342LU,
+0x4aeb3641LU, 0x102ac5c6LU, 0xfe249d02LU, 0xa4e56e85LU, 0x6f382dc7LU, 0x35f9de40LU, 0xdbf78684LU, 0x81367503LU,
+0x949b6c82LU, 0xce5a9f05LU, 0x2054c7c1LU, 0x7a953446LU, 0xb1487704LU, 0xeb898483LU, 0x0587dc47LU, 0x5f462fc0LU,
+0xde705ac3LU, 0x84b1a944LU, 0x6abff180LU, 0x307e0207LU, 0xfba34145LU, 0xa162b2c2LU, 0x4f6cea06LU, 0x15ad1981LU,
+0x657bd849LU, 0x3fba2bceLU, 0xd1b4730aLU, 0x8b75808dLU, 0x40a8c3cfLU, 0x1a693048LU, 0xf467688cLU, 0xaea69b0bLU,
+0x2f90ee08LU, 0x75511d8fLU, 0x9b5f454bLU, 0xc19eb6ccLU, 0x0a43f58eLU, 0x50820609LU, 0xbe8c5ecdLU, 0xe44dad4aLU,
+0xf1e0b4cbLU, 0xab21474cLU, 0x452f1f88LU, 0x1feeec0fLU, 0xd433af4dLU, 0x8ef25ccaLU, 0x60fc040eLU, 0x3a3df789LU,
+0xbb0b828aLU, 0xe1ca710dLU, 0x0fc429c9LU, 0x5505da4eLU, 0x9ed8990cLU, 0xc4196a8bLU, 0x2a17324fLU, 0x70d6c1c8LU,
+0xcaf6fd92LU, 0x90370e15LU, 0x7e3956d1LU, 0x24f8a556LU, 0xef25e614LU, 0xb5e41593LU, 0x5bea4d57LU, 0x012bbed0LU,
+0x801dcbd3LU, 0xdadc3854LU, 0x34d26090LU, 0x6e139317LU, 0xa5ced055LU, 0xff0f23d2LU, 0x11017b16LU, 0x4bc08891LU,
+0x5e6d9110LU, 0x04ac6297LU, 0xeaa23a53LU, 0xb063c9d4LU, 0x7bbe8a96LU, 0x217f7911LU, 0xcf7121d5LU, 0x95b0d252LU,
+0x1486a751LU, 0x4e4754d6LU, 0xa0490c12LU, 0xfa88ff95LU, 0x3155bcd7LU, 0x6b944f50LU, 0x859a1794LU, 0xdf5be413LU,
+0xaf8d25dbLU, 0xf54cd65cLU, 0x1b428e98LU, 0x41837d1fLU, 0x8a5e3e5dLU, 0xd09fcddaLU, 0x3e91951eLU, 0x64506699LU,
+0xe566139aLU, 0xbfa7e01dLU, 0x51a9b8d9LU, 0x0b684b5eLU, 0xc0b5081cLU, 0x9a74fb9bLU, 0x747aa35fLU, 0x2ebb50d8LU,
+0x3b164959LU, 0x61d7badeLU, 0x8fd9e21aLU, 0xd518119dLU, 0x1ec552dfLU, 0x4404a158LU, 0xaa0af99cLU, 0xf0cb0a1bLU,
+0x71fd7f18LU, 0x2b3c8c9fLU, 0xc532d45bLU, 0x9ff327dcLU, 0x542e649eLU, 0x0eef9719LU, 0xe0e1cfddLU, 0xba203c5aLU,
+0xd9a1b769LU, 0x836044eeLU, 0x6d6e1c2aLU, 0x37afefadLU, 0xfc72acefLU, 0xa6b35f68LU, 0x48bd07acLU, 0x127cf42bLU,
+0x934a8128LU, 0xc98b72afLU, 0x27852a6bLU, 0x7d44d9ecLU, 0xb6999aaeLU, 0xec586929LU, 0x025631edLU, 0x5897c26aLU,
+0x4d3adbebLU, 0x17fb286cLU, 0xf9f570a8LU, 0xa334832fLU, 0x68e9c06dLU, 0x322833eaLU, 0xdc266b2eLU, 0x86e798a9LU,
+0x07d1edaaLU, 0x5d101e2dLU, 0xb31e46e9LU, 0xe9dfb56eLU, 0x2202f62cLU, 0x78c305abLU, 0x96cd5d6fLU, 0xcc0caee8LU,
+0xbcda6f20LU, 0xe61b9ca7LU, 0x0815c463LU, 0x52d437e4LU, 0x990974a6LU, 0xc3c88721LU, 0x2dc6dfe5LU, 0x77072c62LU,
+0xf6315961LU, 0xacf0aae6LU, 0x42fef222LU, 0x183f01a5LU, 0xd3e242e7LU, 0x8923b160LU, 0x672de9a4LU, 0x3dec1a23LU,
+0x284103a2LU, 0x7280f025LU, 0x9c8ea8e1LU, 0xc64f5b66LU, 0x0d921824LU, 0x5753eba3LU, 0xb95db367LU, 0xe39c40e0LU,
+0x62aa35e3LU, 0x386bc664LU, 0xd6659ea0LU, 0x8ca46d27LU, 0x47792e65LU, 0x1db8dde2LU, 0xf3b68526LU, 0xa97776a1LU,
+0x13574afbLU, 0x4996b97cLU, 0xa798e1b8LU, 0xfd59123fLU, 0x3684517dLU, 0x6c45a2faLU, 0x824bfa3eLU, 0xd88a09b9LU,
+0x59bc7cbaLU, 0x037d8f3dLU, 0xed73d7f9LU, 0xb7b2247eLU, 0x7c6f673cLU, 0x26ae94bbLU, 0xc8a0cc7fLU, 0x92613ff8LU,
+0x87cc2679LU, 0xdd0dd5feLU, 0x33038d3aLU, 0x69c27ebdLU, 0xa21f3dffLU, 0xf8dece78LU, 0x16d096bcLU, 0x4c11653bLU,
+0xcd271038LU, 0x97e6e3bfLU, 0x79e8bb7bLU, 0x232948fcLU, 0xe8f40bbeLU, 0xb235f839LU, 0x5c3ba0fdLU, 0x06fa537aLU,
+0x762c92b2LU, 0x2ced6135LU, 0xc2e339f1LU, 0x9822ca76LU, 0x53ff8934LU, 0x093e7ab3LU, 0xe7302277LU, 0xbdf1d1f0LU,
+0x3cc7a4f3LU, 0x66065774LU, 0x88080fb0LU, 0xd2c9fc37LU, 0x1914bf75LU, 0x43d54cf2LU, 0xaddb1436LU, 0xf71ae7b1LU,
+0xe2b7fe30LU, 0xb8760db7LU, 0x56785573LU, 0x0cb9a6f4LU, 0xc764e5b6LU, 0x9da51631LU, 0x73ab4ef5LU, 0x296abd72LU,
+0xa85cc871LU, 0xf29d3bf6LU, 0x1c936332LU, 0x465290b5LU, 0x8d8fd3f7LU, 0xd74e2070LU, 0x394078b4LU, 0x63818b33LU };
+
+static const ulong32 rs_tab4[256] = {
+0x00000000LU, 0x58471e5aLU, 0xb08e3cb4LU, 0xe8c922eeLU, 0x2d517825LU, 0x7516667fLU, 0x9ddf4491LU, 0xc5985acbLU,
+0x5aa2f04aLU, 0x02e5ee10LU, 0xea2cccfeLU, 0xb26bd2a4LU, 0x77f3886fLU, 0x2fb49635LU, 0xc77db4dbLU, 0x9f3aaa81LU,
+0xb409ad94LU, 0xec4eb3ceLU, 0x04879120LU, 0x5cc08f7aLU, 0x9958d5b1LU, 0xc11fcbebLU, 0x29d6e905LU, 0x7191f75fLU,
+0xeeab5ddeLU, 0xb6ec4384LU, 0x5e25616aLU, 0x06627f30LU, 0xc3fa25fbLU, 0x9bbd3ba1LU, 0x7374194fLU, 0x2b330715LU,
+0x25121765LU, 0x7d55093fLU, 0x959c2bd1LU, 0xcddb358bLU, 0x08436f40LU, 0x5004711aLU, 0xb8cd53f4LU, 0xe08a4daeLU,
+0x7fb0e72fLU, 0x27f7f975LU, 0xcf3edb9bLU, 0x9779c5c1LU, 0x52e19f0aLU, 0x0aa68150LU, 0xe26fa3beLU, 0xba28bde4LU,
+0x911bbaf1LU, 0xc95ca4abLU, 0x21958645LU, 0x79d2981fLU, 0xbc4ac2d4LU, 0xe40ddc8eLU, 0x0cc4fe60LU, 0x5483e03aLU,
+0xcbb94abbLU, 0x93fe54e1LU, 0x7b37760fLU, 0x23706855LU, 0xe6e8329eLU, 0xbeaf2cc4LU, 0x56660e2aLU, 0x0e211070LU,
+0x4a242ecaLU, 0x12633090LU, 0xfaaa127eLU, 0xa2ed0c24LU, 0x677556efLU, 0x3f3248b5LU, 0xd7fb6a5bLU, 0x8fbc7401LU,
+0x1086de80LU, 0x48c1c0daLU, 0xa008e234LU, 0xf84ffc6eLU, 0x3dd7a6a5LU, 0x6590b8ffLU, 0x8d599a11LU, 0xd51e844bLU,
+0xfe2d835eLU, 0xa66a9d04LU, 0x4ea3bfeaLU, 0x16e4a1b0LU, 0xd37cfb7bLU, 0x8b3be521LU, 0x63f2c7cfLU, 0x3bb5d995LU,
+0xa48f7314LU, 0xfcc86d4eLU, 0x14014fa0LU, 0x4c4651faLU, 0x89de0b31LU, 0xd199156bLU, 0x39503785LU, 0x611729dfLU,
+0x6f3639afLU, 0x377127f5LU, 0xdfb8051bLU, 0x87ff1b41LU, 0x4267418aLU, 0x1a205fd0LU, 0xf2e97d3eLU, 0xaaae6364LU,
+0x3594c9e5LU, 0x6dd3d7bfLU, 0x851af551LU, 0xdd5deb0bLU, 0x18c5b1c0LU, 0x4082af9aLU, 0xa84b8d74LU, 0xf00c932eLU,
+0xdb3f943bLU, 0x83788a61LU, 0x6bb1a88fLU, 0x33f6b6d5LU, 0xf66eec1eLU, 0xae29f244LU, 0x46e0d0aaLU, 0x1ea7cef0LU,
+0x819d6471LU, 0xd9da7a2bLU, 0x311358c5LU, 0x6954469fLU, 0xaccc1c54LU, 0xf48b020eLU, 0x1c4220e0LU, 0x44053ebaLU,
+0x94485cd9LU, 0xcc0f4283LU, 0x24c6606dLU, 0x7c817e37LU, 0xb91924fcLU, 0xe15e3aa6LU, 0x09971848LU, 0x51d00612LU,
+0xceeaac93LU, 0x96adb2c9LU, 0x7e649027LU, 0x26238e7dLU, 0xe3bbd4b6LU, 0xbbfccaecLU, 0x5335e802LU, 0x0b72f658LU,
+0x2041f14dLU, 0x7806ef17LU, 0x90cfcdf9LU, 0xc888d3a3LU, 0x0d108968LU, 0x55579732LU, 0xbd9eb5dcLU, 0xe5d9ab86LU,
+0x7ae30107LU, 0x22a41f5dLU, 0xca6d3db3LU, 0x922a23e9LU, 0x57b27922LU, 0x0ff56778LU, 0xe73c4596LU, 0xbf7b5bccLU,
+0xb15a4bbcLU, 0xe91d55e6LU, 0x01d47708LU, 0x59936952LU, 0x9c0b3399LU, 0xc44c2dc3LU, 0x2c850f2dLU, 0x74c21177LU,
+0xebf8bbf6LU, 0xb3bfa5acLU, 0x5b768742LU, 0x03319918LU, 0xc6a9c3d3LU, 0x9eeedd89LU, 0x7627ff67LU, 0x2e60e13dLU,
+0x0553e628LU, 0x5d14f872LU, 0xb5ddda9cLU, 0xed9ac4c6LU, 0x28029e0dLU, 0x70458057LU, 0x988ca2b9LU, 0xc0cbbce3LU,
+0x5ff11662LU, 0x07b60838LU, 0xef7f2ad6LU, 0xb738348cLU, 0x72a06e47LU, 0x2ae7701dLU, 0xc22e52f3LU, 0x9a694ca9LU,
+0xde6c7213LU, 0x862b6c49LU, 0x6ee24ea7LU, 0x36a550fdLU, 0xf33d0a36LU, 0xab7a146cLU, 0x43b33682LU, 0x1bf428d8LU,
+0x84ce8259LU, 0xdc899c03LU, 0x3440beedLU, 0x6c07a0b7LU, 0xa99ffa7cLU, 0xf1d8e426LU, 0x1911c6c8LU, 0x4156d892LU,
+0x6a65df87LU, 0x3222c1ddLU, 0xdaebe333LU, 0x82acfd69LU, 0x4734a7a2LU, 0x1f73b9f8LU, 0xf7ba9b16LU, 0xaffd854cLU,
+0x30c72fcdLU, 0x68803197LU, 0x80491379LU, 0xd80e0d23LU, 0x1d9657e8LU, 0x45d149b2LU, 0xad186b5cLU, 0xf55f7506LU,
+0xfb7e6576LU, 0xa3397b2cLU, 0x4bf059c2LU, 0x13b74798LU, 0xd62f1d53LU, 0x8e680309LU, 0x66a121e7LU, 0x3ee63fbdLU,
+0xa1dc953cLU, 0xf99b8b66LU, 0x1152a988LU, 0x4915b7d2LU, 0x8c8ded19LU, 0xd4caf343LU, 0x3c03d1adLU, 0x6444cff7LU,
+0x4f77c8e2LU, 0x1730d6b8LU, 0xfff9f456LU, 0xa7beea0cLU, 0x6226b0c7LU, 0x3a61ae9dLU, 0xd2a88c73LU, 0x8aef9229LU,
+0x15d538a8LU, 0x4d9226f2LU, 0xa55b041cLU, 0xfd1c1a46LU, 0x3884408dLU, 0x60c35ed7LU, 0x880a7c39LU, 0xd04d6263LU };
+
+static const ulong32 rs_tab5[256] = {
+0x00000000LU, 0xdbaec658LU, 0xfb11c1b0LU, 0x20bf07e8LU, 0xbb22cf2dLU, 0x608c0975LU, 0x40330e9dLU, 0x9b9dc8c5LU,
+0x3b44d35aLU, 0xe0ea1502LU, 0xc05512eaLU, 0x1bfbd4b2LU, 0x80661c77LU, 0x5bc8da2fLU, 0x7b77ddc7LU, 0xa0d91b9fLU,
+0x7688ebb4LU, 0xad262decLU, 0x8d992a04LU, 0x5637ec5cLU, 0xcdaa2499LU, 0x1604e2c1LU, 0x36bbe529LU, 0xed152371LU,
+0x4dcc38eeLU, 0x9662feb6LU, 0xb6ddf95eLU, 0x6d733f06LU, 0xf6eef7c3LU, 0x2d40319bLU, 0x0dff3673LU, 0xd651f02bLU,
+0xec5d9b25LU, 0x37f35d7dLU, 0x174c5a95LU, 0xcce29ccdLU, 0x577f5408LU, 0x8cd19250LU, 0xac6e95b8LU, 0x77c053e0LU,
+0xd719487fLU, 0x0cb78e27LU, 0x2c0889cfLU, 0xf7a64f97LU, 0x6c3b8752LU, 0xb795410aLU, 0x972a46e2LU, 0x4c8480baLU,
+0x9ad57091LU, 0x417bb6c9LU, 0x61c4b121LU, 0xba6a7779LU, 0x21f7bfbcLU, 0xfa5979e4LU, 0xdae67e0cLU, 0x0148b854LU,
+0xa191a3cbLU, 0x7a3f6593LU, 0x5a80627bLU, 0x812ea423LU, 0x1ab36ce6LU, 0xc11daabeLU, 0xe1a2ad56LU, 0x3a0c6b0eLU,
+0x95ba7b4aLU, 0x4e14bd12LU, 0x6eabbafaLU, 0xb5057ca2LU, 0x2e98b467LU, 0xf536723fLU, 0xd58975d7LU, 0x0e27b38fLU,
+0xaefea810LU, 0x75506e48LU, 0x55ef69a0LU, 0x8e41aff8LU, 0x15dc673dLU, 0xce72a165LU, 0xeecda68dLU, 0x356360d5LU,
+0xe33290feLU, 0x389c56a6LU, 0x1823514eLU, 0xc38d9716LU, 0x58105fd3LU, 0x83be998bLU, 0xa3019e63LU, 0x78af583bLU,
+0xd87643a4LU, 0x03d885fcLU, 0x23678214LU, 0xf8c9444cLU, 0x63548c89LU, 0xb8fa4ad1LU, 0x98454d39LU, 0x43eb8b61LU,
+0x79e7e06fLU, 0xa2492637LU, 0x82f621dfLU, 0x5958e787LU, 0xc2c52f42LU, 0x196be91aLU, 0x39d4eef2LU, 0xe27a28aaLU,
+0x42a33335LU, 0x990df56dLU, 0xb9b2f285LU, 0x621c34ddLU, 0xf981fc18LU, 0x222f3a40LU, 0x02903da8LU, 0xd93efbf0LU,
+0x0f6f0bdbLU, 0xd4c1cd83LU, 0xf47eca6bLU, 0x2fd00c33LU, 0xb44dc4f6LU, 0x6fe302aeLU, 0x4f5c0546LU, 0x94f2c31eLU,
+0x342bd881LU, 0xef851ed9LU, 0xcf3a1931LU, 0x1494df69LU, 0x8f0917acLU, 0x54a7d1f4LU, 0x7418d61cLU, 0xafb61044LU,
+0x6739f694LU, 0xbc9730ccLU, 0x9c283724LU, 0x4786f17cLU, 0xdc1b39b9LU, 0x07b5ffe1LU, 0x270af809LU, 0xfca43e51LU,
+0x5c7d25ceLU, 0x87d3e396LU, 0xa76ce47eLU, 0x7cc22226LU, 0xe75feae3LU, 0x3cf12cbbLU, 0x1c4e2b53LU, 0xc7e0ed0bLU,
+0x11b11d20LU, 0xca1fdb78LU, 0xeaa0dc90LU, 0x310e1ac8LU, 0xaa93d20dLU, 0x713d1455LU, 0x518213bdLU, 0x8a2cd5e5LU,
+0x2af5ce7aLU, 0xf15b0822LU, 0xd1e40fcaLU, 0x0a4ac992LU, 0x91d70157LU, 0x4a79c70fLU, 0x6ac6c0e7LU, 0xb16806bfLU,
+0x8b646db1LU, 0x50caabe9LU, 0x7075ac01LU, 0xabdb6a59LU, 0x3046a29cLU, 0xebe864c4LU, 0xcb57632cLU, 0x10f9a574LU,
+0xb020beebLU, 0x6b8e78b3LU, 0x4b317f5bLU, 0x909fb903LU, 0x0b0271c6LU, 0xd0acb79eLU, 0xf013b076LU, 0x2bbd762eLU,
+0xfdec8605LU, 0x2642405dLU, 0x06fd47b5LU, 0xdd5381edLU, 0x46ce4928LU, 0x9d608f70LU, 0xbddf8898LU, 0x66714ec0LU,
+0xc6a8555fLU, 0x1d069307LU, 0x3db994efLU, 0xe61752b7LU, 0x7d8a9a72LU, 0xa6245c2aLU, 0x869b5bc2LU, 0x5d359d9aLU,
+0xf2838ddeLU, 0x292d4b86LU, 0x09924c6eLU, 0xd23c8a36LU, 0x49a142f3LU, 0x920f84abLU, 0xb2b08343LU, 0x691e451bLU,
+0xc9c75e84LU, 0x126998dcLU, 0x32d69f34LU, 0xe978596cLU, 0x72e591a9LU, 0xa94b57f1LU, 0x89f45019LU, 0x525a9641LU,
+0x840b666aLU, 0x5fa5a032LU, 0x7f1aa7daLU, 0xa4b46182LU, 0x3f29a947LU, 0xe4876f1fLU, 0xc43868f7LU, 0x1f96aeafLU,
+0xbf4fb530LU, 0x64e17368LU, 0x445e7480LU, 0x9ff0b2d8LU, 0x046d7a1dLU, 0xdfc3bc45LU, 0xff7cbbadLU, 0x24d27df5LU,
+0x1ede16fbLU, 0xc570d0a3LU, 0xe5cfd74bLU, 0x3e611113LU, 0xa5fcd9d6LU, 0x7e521f8eLU, 0x5eed1866LU, 0x8543de3eLU,
+0x259ac5a1LU, 0xfe3403f9LU, 0xde8b0411LU, 0x0525c249LU, 0x9eb80a8cLU, 0x4516ccd4LU, 0x65a9cb3cLU, 0xbe070d64LU,
+0x6856fd4fLU, 0xb3f83b17LU, 0x93473cffLU, 0x48e9faa7LU, 0xd3743262LU, 0x08daf43aLU, 0x2865f3d2LU, 0xf3cb358aLU,
+0x53122e15LU, 0x88bce84dLU, 0xa803efa5LU, 0x73ad29fdLU, 0xe830e138LU, 0x339e2760LU, 0x13212088LU, 0xc88fe6d0LU };
+
+static const ulong32 rs_tab6[256] = {
+0x00000000LU, 0x9e3d68dbLU, 0x717ad0fbLU, 0xef47b820LU, 0xe2f4edbbLU, 0x7cc98560LU, 0x938e3d40LU, 0x0db3559bLU,
+0x89a5973bLU, 0x1798ffe0LU, 0xf8df47c0LU, 0x66e22f1bLU, 0x6b517a80LU, 0xf56c125bLU, 0x1a2baa7bLU, 0x8416c2a0LU,
+0x5f076376LU, 0xc13a0badLU, 0x2e7db38dLU, 0xb040db56LU, 0xbdf38ecdLU, 0x23cee616LU, 0xcc895e36LU, 0x52b436edLU,
+0xd6a2f44dLU, 0x489f9c96LU, 0xa7d824b6LU, 0x39e54c6dLU, 0x345619f6LU, 0xaa6b712dLU, 0x452cc90dLU, 0xdb11a1d6LU,
+0xbe0ec6ecLU, 0x2033ae37LU, 0xcf741617LU, 0x51497eccLU, 0x5cfa2b57LU, 0xc2c7438cLU, 0x2d80fbacLU, 0xb3bd9377LU,
+0x37ab51d7LU, 0xa996390cLU, 0x46d1812cLU, 0xd8ece9f7LU, 0xd55fbc6cLU, 0x4b62d4b7LU, 0xa4256c97LU, 0x3a18044cLU,
+0xe109a59aLU, 0x7f34cd41LU, 0x90737561LU, 0x0e4e1dbaLU, 0x03fd4821LU, 0x9dc020faLU, 0x728798daLU, 0xecbaf001LU,
+0x68ac32a1LU, 0xf6915a7aLU, 0x19d6e25aLU, 0x87eb8a81LU, 0x8a58df1aLU, 0x1465b7c1LU, 0xfb220fe1LU, 0x651f673aLU,
+0x311cc195LU, 0xaf21a94eLU, 0x4066116eLU, 0xde5b79b5LU, 0xd3e82c2eLU, 0x4dd544f5LU, 0xa292fcd5LU, 0x3caf940eLU,
+0xb8b956aeLU, 0x26843e75LU, 0xc9c38655LU, 0x57feee8eLU, 0x5a4dbb15LU, 0xc470d3ceLU, 0x2b376beeLU, 0xb50a0335LU,
+0x6e1ba2e3LU, 0xf026ca38LU, 0x1f617218LU, 0x815c1ac3LU, 0x8cef4f58LU, 0x12d22783LU, 0xfd959fa3LU, 0x63a8f778LU,
+0xe7be35d8LU, 0x79835d03LU, 0x96c4e523LU, 0x08f98df8LU, 0x054ad863LU, 0x9b77b0b8LU, 0x74300898LU, 0xea0d6043LU,
+0x8f120779LU, 0x112f6fa2LU, 0xfe68d782LU, 0x6055bf59LU, 0x6de6eac2LU, 0xf3db8219LU, 0x1c9c3a39LU, 0x82a152e2LU,
+0x06b79042LU, 0x988af899LU, 0x77cd40b9LU, 0xe9f02862LU, 0xe4437df9LU, 0x7a7e1522LU, 0x9539ad02LU, 0x0b04c5d9LU,
+0xd015640fLU, 0x4e280cd4LU, 0xa16fb4f4LU, 0x3f52dc2fLU, 0x32e189b4LU, 0xacdce16fLU, 0x439b594fLU, 0xdda63194LU,
+0x59b0f334LU, 0xc78d9befLU, 0x28ca23cfLU, 0xb6f74b14LU, 0xbb441e8fLU, 0x25797654LU, 0xca3ece74LU, 0x5403a6afLU,
+0x6238cf67LU, 0xfc05a7bcLU, 0x13421f9cLU, 0x8d7f7747LU, 0x80cc22dcLU, 0x1ef14a07LU, 0xf1b6f227LU, 0x6f8b9afcLU,
+0xeb9d585cLU, 0x75a03087LU, 0x9ae788a7LU, 0x04dae07cLU, 0x0969b5e7LU, 0x9754dd3cLU, 0x7813651cLU, 0xe62e0dc7LU,
+0x3d3fac11LU, 0xa302c4caLU, 0x4c457ceaLU, 0xd2781431LU, 0xdfcb41aaLU, 0x41f62971LU, 0xaeb19151LU, 0x308cf98aLU,
+0xb49a3b2aLU, 0x2aa753f1LU, 0xc5e0ebd1LU, 0x5bdd830aLU, 0x566ed691LU, 0xc853be4aLU, 0x2714066aLU, 0xb9296eb1LU,
+0xdc36098bLU, 0x420b6150LU, 0xad4cd970LU, 0x3371b1abLU, 0x3ec2e430LU, 0xa0ff8cebLU, 0x4fb834cbLU, 0xd1855c10LU,
+0x55939eb0LU, 0xcbaef66bLU, 0x24e94e4bLU, 0xbad42690LU, 0xb767730bLU, 0x295a1bd0LU, 0xc61da3f0LU, 0x5820cb2bLU,
+0x83316afdLU, 0x1d0c0226LU, 0xf24bba06LU, 0x6c76d2ddLU, 0x61c58746LU, 0xfff8ef9dLU, 0x10bf57bdLU, 0x8e823f66LU,
+0x0a94fdc6LU, 0x94a9951dLU, 0x7bee2d3dLU, 0xe5d345e6LU, 0xe860107dLU, 0x765d78a6LU, 0x991ac086LU, 0x0727a85dLU,
+0x53240ef2LU, 0xcd196629LU, 0x225ede09LU, 0xbc63b6d2LU, 0xb1d0e349LU, 0x2fed8b92LU, 0xc0aa33b2LU, 0x5e975b69LU,
+0xda8199c9LU, 0x44bcf112LU, 0xabfb4932LU, 0x35c621e9LU, 0x38757472LU, 0xa6481ca9LU, 0x490fa489LU, 0xd732cc52LU,
+0x0c236d84LU, 0x921e055fLU, 0x7d59bd7fLU, 0xe364d5a4LU, 0xeed7803fLU, 0x70eae8e4LU, 0x9fad50c4LU, 0x0190381fLU,
+0x8586fabfLU, 0x1bbb9264LU, 0xf4fc2a44LU, 0x6ac1429fLU, 0x67721704LU, 0xf94f7fdfLU, 0x1608c7ffLU, 0x8835af24LU,
+0xed2ac81eLU, 0x7317a0c5LU, 0x9c5018e5LU, 0x026d703eLU, 0x0fde25a5LU, 0x91e34d7eLU, 0x7ea4f55eLU, 0xe0999d85LU,
+0x648f5f25LU, 0xfab237feLU, 0x15f58fdeLU, 0x8bc8e705LU, 0x867bb29eLU, 0x1846da45LU, 0xf7016265LU, 0x693c0abeLU,
+0xb22dab68LU, 0x2c10c3b3LU, 0xc3577b93LU, 0x5d6a1348LU, 0x50d946d3LU, 0xcee42e08LU, 0x21a39628LU, 0xbf9efef3LU,
+0x3b883c53LU, 0xa5b55488LU, 0x4af2eca8LU, 0xd4cf8473LU, 0xd97cd1e8LU, 0x4741b933LU, 0xa8060113LU, 0x363b69c8LU };
+
+static const ulong32 rs_tab7[256] = {
+0x00000000LU, 0x0319e59eLU, 0x06328771LU, 0x052b62efLU, 0x0c6443e2LU, 0x0f7da67cLU, 0x0a56c493LU, 0x094f210dLU,
+0x18c88689LU, 0x1bd16317LU, 0x1efa01f8LU, 0x1de3e466LU, 0x14acc56bLU, 0x17b520f5LU, 0x129e421aLU, 0x1187a784LU,
+0x30dd415fLU, 0x33c4a4c1LU, 0x36efc62eLU, 0x35f623b0LU, 0x3cb902bdLU, 0x3fa0e723LU, 0x3a8b85ccLU, 0x39926052LU,
+0x2815c7d6LU, 0x2b0c2248LU, 0x2e2740a7LU, 0x2d3ea539LU, 0x24718434LU, 0x276861aaLU, 0x22430345LU, 0x215ae6dbLU,
+0x60f782beLU, 0x63ee6720LU, 0x66c505cfLU, 0x65dce051LU, 0x6c93c15cLU, 0x6f8a24c2LU, 0x6aa1462dLU, 0x69b8a3b3LU,
+0x783f0437LU, 0x7b26e1a9LU, 0x7e0d8346LU, 0x7d1466d8LU, 0x745b47d5LU, 0x7742a24bLU, 0x7269c0a4LU, 0x7170253aLU,
+0x502ac3e1LU, 0x5333267fLU, 0x56184490LU, 0x5501a10eLU, 0x5c4e8003LU, 0x5f57659dLU, 0x5a7c0772LU, 0x5965e2ecLU,
+0x48e24568LU, 0x4bfba0f6LU, 0x4ed0c219LU, 0x4dc92787LU, 0x4486068aLU, 0x479fe314LU, 0x42b481fbLU, 0x41ad6465LU,
+0xc0a34931LU, 0xc3baacafLU, 0xc691ce40LU, 0xc5882bdeLU, 0xccc70ad3LU, 0xcfdeef4dLU, 0xcaf58da2LU, 0xc9ec683cLU,
+0xd86bcfb8LU, 0xdb722a26LU, 0xde5948c9LU, 0xdd40ad57LU, 0xd40f8c5aLU, 0xd71669c4LU, 0xd23d0b2bLU, 0xd124eeb5LU,
+0xf07e086eLU, 0xf367edf0LU, 0xf64c8f1fLU, 0xf5556a81LU, 0xfc1a4b8cLU, 0xff03ae12LU, 0xfa28ccfdLU, 0xf9312963LU,
+0xe8b68ee7LU, 0xebaf6b79LU, 0xee840996LU, 0xed9dec08LU, 0xe4d2cd05LU, 0xe7cb289bLU, 0xe2e04a74LU, 0xe1f9afeaLU,
+0xa054cb8fLU, 0xa34d2e11LU, 0xa6664cfeLU, 0xa57fa960LU, 0xac30886dLU, 0xaf296df3LU, 0xaa020f1cLU, 0xa91bea82LU,
+0xb89c4d06LU, 0xbb85a898LU, 0xbeaeca77LU, 0xbdb72fe9LU, 0xb4f80ee4LU, 0xb7e1eb7aLU, 0xb2ca8995LU, 0xb1d36c0bLU,
+0x90898ad0LU, 0x93906f4eLU, 0x96bb0da1LU, 0x95a2e83fLU, 0x9cedc932LU, 0x9ff42cacLU, 0x9adf4e43LU, 0x99c6abddLU,
+0x88410c59LU, 0x8b58e9c7LU, 0x8e738b28LU, 0x8d6a6eb6LU, 0x84254fbbLU, 0x873caa25LU, 0x8217c8caLU, 0x810e2d54LU,
+0xcd0b9262LU, 0xce1277fcLU, 0xcb391513LU, 0xc820f08dLU, 0xc16fd180LU, 0xc276341eLU, 0xc75d56f1LU, 0xc444b36fLU,
+0xd5c314ebLU, 0xd6daf175LU, 0xd3f1939aLU, 0xd0e87604LU, 0xd9a75709LU, 0xdabeb297LU, 0xdf95d078LU, 0xdc8c35e6LU,
+0xfdd6d33dLU, 0xfecf36a3LU, 0xfbe4544cLU, 0xf8fdb1d2LU, 0xf1b290dfLU, 0xf2ab7541LU, 0xf78017aeLU, 0xf499f230LU,
+0xe51e55b4LU, 0xe607b02aLU, 0xe32cd2c5LU, 0xe035375bLU, 0xe97a1656LU, 0xea63f3c8LU, 0xef489127LU, 0xec5174b9LU,
+0xadfc10dcLU, 0xaee5f542LU, 0xabce97adLU, 0xa8d77233LU, 0xa198533eLU, 0xa281b6a0LU, 0xa7aad44fLU, 0xa4b331d1LU,
+0xb5349655LU, 0xb62d73cbLU, 0xb3061124LU, 0xb01ff4baLU, 0xb950d5b7LU, 0xba493029LU, 0xbf6252c6LU, 0xbc7bb758LU,
+0x9d215183LU, 0x9e38b41dLU, 0x9b13d6f2LU, 0x980a336cLU, 0x91451261LU, 0x925cf7ffLU, 0x97779510LU, 0x946e708eLU,
+0x85e9d70aLU, 0x86f03294LU, 0x83db507bLU, 0x80c2b5e5LU, 0x898d94e8LU, 0x8a947176LU, 0x8fbf1399LU, 0x8ca6f607LU,
+0x0da8db53LU, 0x0eb13ecdLU, 0x0b9a5c22LU, 0x0883b9bcLU, 0x01cc98b1LU, 0x02d57d2fLU, 0x07fe1fc0LU, 0x04e7fa5eLU,
+0x15605ddaLU, 0x1679b844LU, 0x1352daabLU, 0x104b3f35LU, 0x19041e38LU, 0x1a1dfba6LU, 0x1f369949LU, 0x1c2f7cd7LU,
+0x3d759a0cLU, 0x3e6c7f92LU, 0x3b471d7dLU, 0x385ef8e3LU, 0x3111d9eeLU, 0x32083c70LU, 0x37235e9fLU, 0x343abb01LU,
+0x25bd1c85LU, 0x26a4f91bLU, 0x238f9bf4LU, 0x20967e6aLU, 0x29d95f67LU, 0x2ac0baf9LU, 0x2febd816LU, 0x2cf23d88LU,
+0x6d5f59edLU, 0x6e46bc73LU, 0x6b6dde9cLU, 0x68743b02LU, 0x613b1a0fLU, 0x6222ff91LU, 0x67099d7eLU, 0x641078e0LU,
+0x7597df64LU, 0x768e3afaLU, 0x73a55815LU, 0x70bcbd8bLU, 0x79f39c86LU, 0x7aea7918LU, 0x7fc11bf7LU, 0x7cd8fe69LU,
+0x5d8218b2LU, 0x5e9bfd2cLU, 0x5bb09fc3LU, 0x58a97a5dLU, 0x51e65b50LU, 0x52ffbeceLU, 0x57d4dc21LU, 0x54cd39bfLU,
+0x454a9e3bLU, 0x46537ba5LU, 0x4378194aLU, 0x4061fcd4LU, 0x492eddd9LU, 0x4a373847LU, 0x4f1c5aa8LU, 0x4c05bf36LU };
+
+#endif /* LTC_TWOFISH_ALL_TABLES */
+
+#endif /* __LTC_TWOFISH_TAB_C__ */
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/ciphers/xtea.c b/libtomcrypt/src/ciphers/xtea.c
new file mode 100644 (file)
index 0000000..fe26f98
--- /dev/null
@@ -0,0 +1,261 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+/**
+  @file xtea.c
+  Implementation of LTC_XTEA, Tom St Denis
+*/
+#include "tomcrypt.h"
+
+#ifdef LTC_XTEA
+
+const struct ltc_cipher_descriptor xtea_desc =
+{
+    "xtea",
+    1,
+    16, 16, 8, 32,
+    &xtea_setup,
+    &xtea_ecb_encrypt,
+    &xtea_ecb_decrypt,
+    &xtea_test,
+    &xtea_done,
+    &xtea_keysize,
+    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
+};
+
+int xtea_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey)
+{
+   ulong32 x, sum, K[4];
+
+   LTC_ARGCHK(key != NULL);
+   LTC_ARGCHK(skey != NULL);
+
+   /* check arguments */
+   if (keylen != 16) {
+      return CRYPT_INVALID_KEYSIZE;
+   }
+
+   if (num_rounds != 0 && num_rounds != 32) {
+      return CRYPT_INVALID_ROUNDS;
+   }
+
+   /* load key */
+   LOAD32H(K[0], key+0);
+   LOAD32H(K[1], key+4);
+   LOAD32H(K[2], key+8);
+   LOAD32H(K[3], key+12);
+
+   for (x = sum = 0; x < 32; x++) {
+       skey->xtea.A[x] = (sum + K[sum&3]) & 0xFFFFFFFFUL;
+       sum = (sum + 0x9E3779B9UL) & 0xFFFFFFFFUL;
+       skey->xtea.B[x] = (sum + K[(sum>>11)&3]) & 0xFFFFFFFFUL;
+   }
+
+#ifdef LTC_CLEAN_STACK
+   zeromem(&K, sizeof(K));
+#endif
+
+   return CRYPT_OK;
+}
+
+/**
+  Encrypts a block of text with LTC_XTEA
+  @param pt The input plaintext (8 bytes)
+  @param ct The output ciphertext (8 bytes)
+  @param skey The key as scheduled
+  @return CRYPT_OK if successful
+*/
+int xtea_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey)
+{
+   ulong32 y, z;
+   int r;
+
+   LTC_ARGCHK(pt   != NULL);
+   LTC_ARGCHK(ct   != NULL);
+   LTC_ARGCHK(skey != NULL);
+
+   LOAD32H(y, &pt[0]);
+   LOAD32H(z, &pt[4]);
+   for (r = 0; r < 32; r += 4) {
+       y = (y + ((((z<<4)^(z>>5)) + z) ^ skey->xtea.A[r])) & 0xFFFFFFFFUL;
+       z = (z + ((((y<<4)^(y>>5)) + y) ^ skey->xtea.B[r])) & 0xFFFFFFFFUL;
+
+       y = (y + ((((z<<4)^(z>>5)) + z) ^ skey->xtea.A[r+1])) & 0xFFFFFFFFUL;
+       z = (z + ((((y<<4)^(y>>5)) + y) ^ skey->xtea.B[r+1])) & 0xFFFFFFFFUL;
+
+       y = (y + ((((z<<4)^(z>>5)) + z) ^ skey->xtea.A[r+2])) & 0xFFFFFFFFUL;
+       z = (z + ((((y<<4)^(y>>5)) + y) ^ skey->xtea.B[r+2])) & 0xFFFFFFFFUL;
+
+       y = (y + ((((z<<4)^(z>>5)) + z) ^ skey->xtea.A[r+3])) & 0xFFFFFFFFUL;
+       z = (z + ((((y<<4)^(y>>5)) + y) ^ skey->xtea.B[r+3])) & 0xFFFFFFFFUL;
+   }
+   STORE32H(y, &ct[0]);
+   STORE32H(z, &ct[4]);
+   return CRYPT_OK;
+}
+
+/**
+  Decrypts a block of text with LTC_XTEA
+  @param ct The input ciphertext (8 bytes)
+  @param pt The output plaintext (8 bytes)
+  @param skey The key as scheduled
+  @return CRYPT_OK if successful
+*/
+int xtea_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey)
+{
+   ulong32 y, z;
+   int r;
+
+   LTC_ARGCHK(pt   != NULL);
+   LTC_ARGCHK(ct   != NULL);
+   LTC_ARGCHK(skey != NULL);
+
+   LOAD32H(y, &ct[0]);
+   LOAD32H(z, &ct[4]);
+   for (r = 31; r >= 0; r -= 4) {
+       z = (z - ((((y<<4)^(y>>5)) + y) ^ skey->xtea.B[r])) & 0xFFFFFFFFUL;
+       y = (y - ((((z<<4)^(z>>5)) + z) ^ skey->xtea.A[r])) & 0xFFFFFFFFUL;
+
+       z = (z - ((((y<<4)^(y>>5)) + y) ^ skey->xtea.B[r-1])) & 0xFFFFFFFFUL;
+       y = (y - ((((z<<4)^(z>>5)) + z) ^ skey->xtea.A[r-1])) & 0xFFFFFFFFUL;
+
+       z = (z - ((((y<<4)^(y>>5)) + y) ^ skey->xtea.B[r-2])) & 0xFFFFFFFFUL;
+       y = (y - ((((z<<4)^(z>>5)) + z) ^ skey->xtea.A[r-2])) & 0xFFFFFFFFUL;
+
+       z = (z - ((((y<<4)^(y>>5)) + y) ^ skey->xtea.B[r-3])) & 0xFFFFFFFFUL;
+       y = (y - ((((z<<4)^(z>>5)) + z) ^ skey->xtea.A[r-3])) & 0xFFFFFFFFUL;
+   }
+   STORE32H(y, &pt[0]);
+   STORE32H(z, &pt[4]);
+   return CRYPT_OK;
+}
+
+/**
+  Performs a self-test of the LTC_XTEA block cipher
+  @return CRYPT_OK if functional, CRYPT_NOP if self-test has been disabled
+*/
+int xtea_test(void)
+{
+ #ifndef LTC_TEST
+    return CRYPT_NOP;
+ #else
+    static const struct {
+        unsigned char key[16], pt[8], ct[8];
+    } tests[] = {
+       {
+         { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+         { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+         { 0xde, 0xe9, 0xd4, 0xd8, 0xf7, 0x13, 0x1e, 0xd9 }
+       }, {
+         { 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02,
+           0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04 },
+         { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+         { 0xa5, 0x97, 0xab, 0x41, 0x76, 0x01, 0x4d, 0x72 }
+       }, {
+         { 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04,
+           0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06 },
+         { 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02 },
+         { 0xb1, 0xfd, 0x5d, 0xa9, 0xcc, 0x6d, 0xc9, 0xdc }
+       }, {
+         { 0x78, 0x69, 0x5a, 0x4b, 0x3c, 0x2d, 0x1e, 0x0f,
+           0xf0, 0xe1, 0xd2, 0xc3, 0xb4, 0xa5, 0x96, 0x87 },
+         { 0xf0, 0xe1, 0xd2, 0xc3, 0xb4, 0xa5, 0x96, 0x87 },
+         { 0x70, 0x4b, 0x31, 0x34, 0x47, 0x44, 0xdf, 0xab }
+       }, {
+         { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+           0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f },
+         { 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48 },
+         { 0x49, 0x7d, 0xf3, 0xd0, 0x72, 0x61, 0x2c, 0xb5 }
+       }, {
+         { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+           0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f },
+         { 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41 },
+         { 0xe7, 0x8f, 0x2d, 0x13, 0x74, 0x43, 0x41, 0xd8 }
+       }, {
+         { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+           0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f },
+         { 0x5a, 0x5b, 0x6e, 0x27, 0x89, 0x48, 0xd7, 0x7f },
+         { 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41 }
+       }, {
+         { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+         { 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48 },
+         { 0xa0, 0x39, 0x05, 0x89, 0xf8, 0xb8, 0xef, 0xa5 }
+       }, {
+         { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+         { 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41 },
+         { 0xed, 0x23, 0x37, 0x5a, 0x82, 0x1a, 0x8c, 0x2d }
+       }, {
+         { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+         { 0x70, 0xe1, 0x22, 0x5d, 0x6e, 0x4e, 0x76, 0x55 },
+         { 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41 }
+       }
+    };
+   unsigned char tmp[2][8];
+   symmetric_key skey;
+   int i, err, y;
+   for (i = 0; i < (int)(sizeof(tests)/sizeof(tests[0])); i++) {
+       zeromem(&skey, sizeof(skey));
+       if ((err = xtea_setup(tests[i].key, 16, 0, &skey)) != CRYPT_OK)  {
+          return err;
+       }
+       xtea_ecb_encrypt(tests[i].pt, tmp[0], &skey);
+       xtea_ecb_decrypt(tmp[0], tmp[1], &skey);
+
+       if (compare_testvector(tmp[0], 8, tests[i].ct, 8, "XTEA Encrypt", i) != 0 ||
+             compare_testvector(tmp[1], 8, tests[i].pt, 8, "XTEA Decrypt", i) != 0) {
+          return CRYPT_FAIL_TESTVECTOR;
+       }
+
+      /* now see if we can encrypt all zero bytes 1000 times, decrypt and come back where we started */
+      for (y = 0; y < 8; y++) tmp[0][y] = 0;
+      for (y = 0; y < 1000; y++) xtea_ecb_encrypt(tmp[0], tmp[0], &skey);
+      for (y = 0; y < 1000; y++) xtea_ecb_decrypt(tmp[0], tmp[0], &skey);
+      for (y = 0; y < 8; y++) if (tmp[0][y] != 0) return CRYPT_FAIL_TESTVECTOR;
+   } /* for */
+
+   return CRYPT_OK;
+ #endif
+}
+
+/** Terminate the context
+   @param skey    The scheduled key
+*/
+void xtea_done(symmetric_key *skey)
+{
+  LTC_UNUSED_PARAM(skey);
+}
+
+/**
+  Gets suitable key size
+  @param keysize [in/out] The length of the recommended key (in bytes).  This function will store the suitable size back in this variable.
+  @return CRYPT_OK if the input key size is acceptable.
+*/
+int xtea_keysize(int *keysize)
+{
+   LTC_ARGCHK(keysize != NULL);
+   if (*keysize < 16) {
+      return CRYPT_INVALID_KEYSIZE;
+   }
+   *keysize = 16;
+   return CRYPT_OK;
+}
+
+
+#endif
+
+
+
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/encauth/ccm/ccm_add_aad.c b/libtomcrypt/src/encauth/ccm/ccm_add_aad.c
new file mode 100644 (file)
index 0000000..9744c57
--- /dev/null
@@ -0,0 +1,63 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+#ifdef LTC_CCM_MODE
+
+/**
+  Add AAD to the CCM state
+  @param ccm       The CCM state
+  @param adata     The additional authentication data to add to the CCM state
+  @param adatalen  The length of the AAD data.
+  @return CRYPT_OK on success
+ */
+int ccm_add_aad(ccm_state *ccm,
+                const unsigned char *adata,  unsigned long adatalen)
+{
+   unsigned long y;
+   int            err;
+
+   LTC_ARGCHK(ccm   != NULL);
+   LTC_ARGCHK(adata != NULL);
+
+   if (ccm->aadlen < ccm->current_aadlen + adatalen) {
+      return CRYPT_INVALID_ARG;
+   }
+   ccm->current_aadlen += adatalen;
+
+   /* now add the data */
+   for (y = 0; y < adatalen; y++) {
+      if (ccm->x == 16) {
+         /* full block so let's encrypt it */
+         if ((err = cipher_descriptor[ccm->cipher].ecb_encrypt(ccm->PAD, ccm->PAD, &ccm->K)) != CRYPT_OK) {
+            return err;
+         }
+         ccm->x = 0;
+      }
+      ccm->PAD[ccm->x++] ^= adata[y];
+   }
+
+   /* remainder? */
+   if (ccm->aadlen == ccm->current_aadlen) {
+      if (ccm->x != 0) {
+         if ((err = cipher_descriptor[ccm->cipher].ecb_encrypt(ccm->PAD, ccm->PAD, &ccm->K)) != CRYPT_OK) {
+            return err;
+         }
+      }
+      ccm->x = 0;
+   }
+
+   return CRYPT_OK;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/encauth/ccm/ccm_add_nonce.c b/libtomcrypt/src/encauth/ccm/ccm_add_nonce.c
new file mode 100644 (file)
index 0000000..ceffb8e
--- /dev/null
@@ -0,0 +1,113 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+#ifdef LTC_CCM_MODE
+
+/**
+  Add nonce data to the CCM state
+  @param ccm       The CCM state
+  @param nonce     The nonce data to add
+  @param noncelen  The length of the nonce
+  @return CRYPT_OK on success
+ */
+int ccm_add_nonce(ccm_state *ccm,
+                  const unsigned char *nonce,     unsigned long noncelen)
+{
+   unsigned long x, y, len;
+   int           err;
+
+   LTC_ARGCHK(ccm   != NULL);
+   LTC_ARGCHK(nonce != NULL);
+
+   /* increase L to match the nonce len */
+   ccm->noncelen = (noncelen > 13) ? 13 : noncelen;
+   if ((15 - ccm->noncelen) > ccm->L) {
+      ccm->L = 15 - ccm->noncelen;
+   }
+
+   /* decrease noncelen to match L */
+   if ((ccm->noncelen + ccm->L) > 15) {
+      ccm->noncelen = 15 - ccm->L;
+   }
+
+   /* form B_0 == flags | Nonce N | l(m) */
+   x = 0;
+   ccm->PAD[x++] = (unsigned char)(((ccm->aadlen > 0) ? (1<<6) : 0) |
+                   (((ccm->taglen - 2)>>1)<<3)        |
+                   (ccm->L-1));
+
+   /* nonce */
+   for (y = 0; y < (16 - (ccm->L + 1)); y++) {
+      ccm->PAD[x++] = nonce[y];
+   }
+
+   /* store len */
+   len = ccm->ptlen;
+
+   /* shift len so the upper bytes of len are the contents of the length */
+   for (y = ccm->L; y < 4; y++) {
+      len <<= 8;
+   }
+
+   /* store l(m) (only store 32-bits) */
+   for (y = 0; ccm->L > 4 && (ccm->L-y)>4; y++) {
+      ccm->PAD[x++] = 0;
+   }
+   for (; y < ccm->L; y++) {
+      ccm->PAD[x++] = (unsigned char)((len >> 24) & 255);
+      len <<= 8;
+   }
+
+   /* encrypt PAD */
+   if ((err = cipher_descriptor[ccm->cipher].ecb_encrypt(ccm->PAD, ccm->PAD, &ccm->K)) != CRYPT_OK) {
+      return err;
+   }
+
+   /* handle header */
+   ccm->x = 0;
+   if (ccm->aadlen > 0) {
+      /* store length */
+      if (ccm->aadlen < ((1UL<<16) - (1UL<<8))) {
+         ccm->PAD[ccm->x++] ^= (ccm->aadlen>>8) & 255;
+         ccm->PAD[ccm->x++] ^= ccm->aadlen & 255;
+      } else {
+         ccm->PAD[ccm->x++] ^= 0xFF;
+         ccm->PAD[ccm->x++] ^= 0xFE;
+         ccm->PAD[ccm->x++] ^= (ccm->aadlen>>24) & 255;
+         ccm->PAD[ccm->x++] ^= (ccm->aadlen>>16) & 255;
+         ccm->PAD[ccm->x++] ^= (ccm->aadlen>>8) & 255;
+         ccm->PAD[ccm->x++] ^= ccm->aadlen & 255;
+      }
+   }
+
+   /* setup the ctr counter */
+   x = 0;
+
+   /* flags */
+   ccm->ctr[x++] = (unsigned char)ccm->L-1;
+
+   /* nonce */
+   for (y = 0; y < (16 - (ccm->L+1)); ++y) {
+      ccm->ctr[x++] = nonce[y];
+   }
+   /* offset */
+   while (x < 16) {
+      ccm->ctr[x++] = 0;
+   }
+
+   ccm->CTRlen = 16;
+   return CRYPT_OK;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/encauth/ccm/ccm_done.c b/libtomcrypt/src/encauth/ccm/ccm_done.c
new file mode 100644 (file)
index 0000000..797b7d9
--- /dev/null
@@ -0,0 +1,65 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+#ifdef LTC_CCM_MODE
+
+/**
+  Terminate a CCM stream
+  @param ccm     The CCM state
+  @param tag     [out] The destination for the MAC tag
+  @param taglen  [in/out]  The length of the MAC tag
+  @return CRYPT_OK on success
+ */
+int ccm_done(ccm_state *ccm,
+             unsigned char *tag,    unsigned long *taglen)
+{
+   unsigned long x, y;
+   int            err;
+
+   LTC_ARGCHK(ccm != NULL);
+
+   /* Check all data have been processed */
+   if (ccm->ptlen != ccm->current_ptlen) {
+      return CRYPT_ERROR;
+   }
+
+   LTC_ARGCHK(tag    != NULL);
+   LTC_ARGCHK(taglen != NULL);
+
+   if (ccm->x != 0) {
+      if ((err = cipher_descriptor[ccm->cipher].ecb_encrypt(ccm->PAD, ccm->PAD, &ccm->K)) != CRYPT_OK) {
+         return err;
+      }
+   }
+
+   /* setup CTR for the TAG (zero the count) */
+   for (y = 15; y > 15 - ccm->L; y--) {
+      ccm->ctr[y] = 0x00;
+   }
+   if ((err = cipher_descriptor[ccm->cipher].ecb_encrypt(ccm->ctr, ccm->CTRPAD, &ccm->K)) != CRYPT_OK) {
+      return err;
+   }
+
+   cipher_descriptor[ccm->cipher].done(&ccm->K);
+
+   /* store the TAG */
+   for (x = 0; x < 16 && x < *taglen; x++) {
+      tag[x] = ccm->PAD[x] ^ ccm->CTRPAD[x];
+   }
+   *taglen = x;
+
+   return CRYPT_OK;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/encauth/ccm/ccm_init.c b/libtomcrypt/src/encauth/ccm/ccm_init.c
new file mode 100644 (file)
index 0000000..b24e33e
--- /dev/null
@@ -0,0 +1,81 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+#ifdef LTC_CCM_MODE
+
+/**
+  Initialize a CCM state
+  @param ccm     The CCM state to initialize
+  @param cipher  The index of the cipher to use
+  @param key     The secret key
+  @param keylen  The length of the secret key
+  @param ptlen   The length of the plain/cipher text that will be processed
+  @param taglen  The max length of the MAC tag
+  @param aadlen  The length of the AAD
+
+  @return CRYPT_OK on success
+ */
+int ccm_init(ccm_state *ccm, int cipher,
+             const unsigned char *key, int keylen, int ptlen, int taglen, int aadlen)
+{
+   int            err;
+
+   LTC_ARGCHK(ccm    != NULL);
+   LTC_ARGCHK(key    != NULL);
+   LTC_ARGCHK(taglen != 0);
+
+   XMEMSET(ccm, 0, sizeof(ccm_state));
+
+   /* check cipher input */
+   if ((err = cipher_is_valid(cipher)) != CRYPT_OK) {
+      return err;
+   }
+   if (cipher_descriptor[cipher].block_length != 16) {
+      return CRYPT_INVALID_CIPHER;
+   }
+
+   /* make sure the taglen is even and <= 16 */
+   ccm->taglen = taglen;
+   ccm->taglen &= ~1;
+   if (ccm->taglen > 16) {
+      ccm->taglen = 16;
+   }
+
+   /* can't use < 4 */
+   if (ccm->taglen < 4) {
+      return CRYPT_INVALID_ARG;
+   }
+
+   /* schedule key */
+   if ((err = cipher_descriptor[cipher].setup(key, keylen, 0, &ccm->K)) != CRYPT_OK) {
+      return err;
+   }
+   ccm->cipher = cipher;
+
+   /* let's get the L value */
+   ccm->ptlen = ptlen;
+   ccm->L   = 0;
+   while (ptlen) {
+      ++ccm->L;
+      ptlen >>= 8;
+   }
+   if (ccm->L <= 1) {
+      ccm->L = 2;
+   }
+
+   ccm->aadlen = aadlen;
+   return CRYPT_OK;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/encauth/ccm/ccm_memory.c b/libtomcrypt/src/encauth/ccm/ccm_memory.c
new file mode 100644 (file)
index 0000000..631219e
--- /dev/null
@@ -0,0 +1,407 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file ccm_memory.c
+  CCM support, process a block of memory, Tom St Denis
+*/
+
+#ifdef LTC_CCM_MODE
+
+/**
+   CCM encrypt/decrypt and produce an authentication tag
+
+     *1 'pt', 'ct' and 'tag' can both be 'in' or 'out', depending on 'direction'
+
+   @param cipher     The index of the cipher desired
+   @param key        The secret key to use
+   @param keylen     The length of the secret key (octets)
+   @param uskey      A previously scheduled key [optional can be NULL]
+   @param nonce      The session nonce [use once]
+   @param noncelen   The length of the nonce
+   @param header     The header for the session
+   @param headerlen  The length of the header (octets)
+   @param pt         [*1] The plaintext
+   @param ptlen      The length of the plaintext (octets)
+   @param ct         [*1] The ciphertext
+   @param tag        [*1] The destination tag
+   @param taglen     The max size and resulting size of the authentication tag
+   @param direction  Encrypt or Decrypt direction (0 or 1)
+   @return CRYPT_OK if successful
+*/
+int ccm_memory(int cipher,
+    const unsigned char *key,    unsigned long keylen,
+    symmetric_key       *uskey,
+    const unsigned char *nonce,  unsigned long noncelen,
+    const unsigned char *header, unsigned long headerlen,
+          unsigned char *pt,     unsigned long ptlen,
+          unsigned char *ct,
+          unsigned char *tag,    unsigned long *taglen,
+                    int  direction)
+{
+   unsigned char  PAD[16], ctr[16], CTRPAD[16], ptTag[16], b, *pt_real;
+   unsigned char *pt_work = NULL;
+   symmetric_key *skey;
+   int            err;
+   unsigned long  len, L, x, y, z, CTRlen;
+#ifdef LTC_FAST
+   LTC_FAST_TYPE fastMask = ~(LTC_FAST_TYPE)0; /* initialize fastMask at all zeroes */
+#endif
+   unsigned char mask = 0xff; /* initialize mask at all zeroes */
+
+   if (uskey == NULL) {
+      LTC_ARGCHK(key    != NULL);
+   }
+   LTC_ARGCHK(nonce  != NULL);
+   if (headerlen > 0) {
+      LTC_ARGCHK(header != NULL);
+   }
+   LTC_ARGCHK(pt     != NULL);
+   LTC_ARGCHK(ct     != NULL);
+   LTC_ARGCHK(tag    != NULL);
+   LTC_ARGCHK(taglen != NULL);
+
+   pt_real = pt;
+
+#ifdef LTC_FAST
+   if (16 % sizeof(LTC_FAST_TYPE)) {
+      return CRYPT_INVALID_ARG;
+   }
+#endif
+
+   /* check cipher input */
+   if ((err = cipher_is_valid(cipher)) != CRYPT_OK) {
+      return err;
+   }
+   if (cipher_descriptor[cipher].block_length != 16) {
+      return CRYPT_INVALID_CIPHER;
+   }
+
+   /* make sure the taglen is even and <= 16 */
+   *taglen &= ~1;
+   if (*taglen > 16) {
+      *taglen = 16;
+   }
+
+   /* can't use < 4 */
+   if (*taglen < 4) {
+      return CRYPT_INVALID_ARG;
+   }
+
+   /* is there an accelerator? */
+   if (cipher_descriptor[cipher].accel_ccm_memory != NULL) {
+       return cipher_descriptor[cipher].accel_ccm_memory(
+           key,    keylen,
+           uskey,
+           nonce,  noncelen,
+           header, headerlen,
+           pt,     ptlen,
+           ct,
+           tag,    taglen,
+           direction);
+   }
+
+   /* let's get the L value */
+   len = ptlen;
+   L   = 0;
+   while (len) {
+      ++L;
+      len >>= 8;
+   }
+   if (L <= 1) {
+      L = 2;
+   }
+
+   /* increase L to match the nonce len */
+   noncelen = (noncelen > 13) ? 13 : noncelen;
+   if ((15 - noncelen) > L) {
+      L = 15 - noncelen;
+   }
+
+   /* allocate mem for the symmetric key */
+   if (uskey == NULL) {
+      skey = XMALLOC(sizeof(*skey));
+      if (skey == NULL) {
+         return CRYPT_MEM;
+      }
+
+      /* initialize the cipher */
+      if ((err = cipher_descriptor[cipher].setup(key, keylen, 0, skey)) != CRYPT_OK) {
+         XFREE(skey);
+         return err;
+      }
+   } else {
+      skey = uskey;
+   }
+
+   /* initialize buffer for pt */
+   if (direction == CCM_DECRYPT && ptlen > 0) {
+      pt_work = XMALLOC(ptlen);
+      if (pt_work == NULL) {
+         goto error;
+      }
+      pt = pt_work;
+   }
+
+   /* form B_0 == flags | Nonce N | l(m) */
+   x = 0;
+   PAD[x++] = (unsigned char)(((headerlen > 0) ? (1<<6) : 0) |
+            (((*taglen - 2)>>1)<<3)        |
+            (L-1));
+
+   /* nonce */
+   for (y = 0; y < (16 - (L + 1)); y++) {
+       PAD[x++] = nonce[y];
+   }
+
+   /* store len */
+   len = ptlen;
+
+   /* shift len so the upper bytes of len are the contents of the length */
+   for (y = L; y < 4; y++) {
+       len <<= 8;
+   }
+
+   /* store l(m) (only store 32-bits) */
+   for (y = 0; L > 4 && (L-y)>4; y++) {
+       PAD[x++] = 0;
+   }
+   for (; y < L; y++) {
+       PAD[x++] = (unsigned char)((len >> 24) & 255);
+       len <<= 8;
+   }
+
+   /* encrypt PAD */
+   if ((err = cipher_descriptor[cipher].ecb_encrypt(PAD, PAD, skey)) != CRYPT_OK) {
+       goto error;
+   }
+
+   /* handle header */
+   if (headerlen > 0) {
+      x = 0;
+
+      /* store length */
+      if (headerlen < ((1UL<<16) - (1UL<<8))) {
+         PAD[x++] ^= (headerlen>>8) & 255;
+         PAD[x++] ^= headerlen & 255;
+      } else {
+         PAD[x++] ^= 0xFF;
+         PAD[x++] ^= 0xFE;
+         PAD[x++] ^= (headerlen>>24) & 255;
+         PAD[x++] ^= (headerlen>>16) & 255;
+         PAD[x++] ^= (headerlen>>8) & 255;
+         PAD[x++] ^= headerlen & 255;
+      }
+
+      /* now add the data */
+      for (y = 0; y < headerlen; y++) {
+          if (x == 16) {
+             /* full block so let's encrypt it */
+             if ((err = cipher_descriptor[cipher].ecb_encrypt(PAD, PAD, skey)) != CRYPT_OK) {
+                goto error;
+             }
+             x = 0;
+          }
+          PAD[x++] ^= header[y];
+      }
+
+      /* remainder */
+      if ((err = cipher_descriptor[cipher].ecb_encrypt(PAD, PAD, skey)) != CRYPT_OK) {
+         goto error;
+      }
+   }
+
+   /* setup the ctr counter */
+   x = 0;
+
+   /* flags */
+   ctr[x++] = (unsigned char)L-1;
+
+   /* nonce */
+   for (y = 0; y < (16 - (L+1)); ++y) {
+      ctr[x++] = nonce[y];
+   }
+   /* offset */
+   while (x < 16) {
+      ctr[x++] = 0;
+   }
+
+   x      = 0;
+   CTRlen = 16;
+
+   /* now handle the PT */
+   if (ptlen > 0) {
+      y = 0;
+#ifdef LTC_FAST
+      if (ptlen & ~15)  {
+          if (direction == CCM_ENCRYPT) {
+             for (; y < (ptlen & ~15); y += 16) {
+                /* increment the ctr? */
+                for (z = 15; z > 15-L; z--) {
+                    ctr[z] = (ctr[z] + 1) & 255;
+                    if (ctr[z]) break;
+                }
+                if ((err = cipher_descriptor[cipher].ecb_encrypt(ctr, CTRPAD, skey)) != CRYPT_OK) {
+                   goto error;
+                }
+
+                /* xor the PT against the pad first */
+                for (z = 0; z < 16; z += sizeof(LTC_FAST_TYPE)) {
+                    *(LTC_FAST_TYPE_PTR_CAST(&PAD[z]))  ^= *(LTC_FAST_TYPE_PTR_CAST(&pt[y+z]));
+                    *(LTC_FAST_TYPE_PTR_CAST(&ct[y+z])) = *(LTC_FAST_TYPE_PTR_CAST(&pt[y+z])) ^ *(LTC_FAST_TYPE_PTR_CAST(&CTRPAD[z]));
+                }
+                if ((err = cipher_descriptor[cipher].ecb_encrypt(PAD, PAD, skey)) != CRYPT_OK) {
+                   goto error;
+                }
+             }
+          } else { /* direction == CCM_DECRYPT */
+             for (; y < (ptlen & ~15); y += 16) {
+                /* increment the ctr? */
+                for (z = 15; z > 15-L; z--) {
+                    ctr[z] = (ctr[z] + 1) & 255;
+                    if (ctr[z]) break;
+                }
+                if ((err = cipher_descriptor[cipher].ecb_encrypt(ctr, CTRPAD, skey)) != CRYPT_OK) {
+                   goto error;
+                }
+
+                /* xor the PT against the pad last */
+                for (z = 0; z < 16; z += sizeof(LTC_FAST_TYPE)) {
+                    *(LTC_FAST_TYPE_PTR_CAST(&pt[y+z])) = *(LTC_FAST_TYPE_PTR_CAST(&ct[y+z])) ^ *(LTC_FAST_TYPE_PTR_CAST(&CTRPAD[z]));
+                    *(LTC_FAST_TYPE_PTR_CAST(&PAD[z]))  ^= *(LTC_FAST_TYPE_PTR_CAST(&pt[y+z]));
+                }
+                if ((err = cipher_descriptor[cipher].ecb_encrypt(PAD, PAD, skey)) != CRYPT_OK) {
+                   goto error;
+                }
+             }
+          }
+      }
+#endif
+
+      for (; y < ptlen; y++) {
+          /* increment the ctr? */
+          if (CTRlen == 16) {
+             for (z = 15; z > 15-L; z--) {
+                 ctr[z] = (ctr[z] + 1) & 255;
+                 if (ctr[z]) break;
+             }
+             if ((err = cipher_descriptor[cipher].ecb_encrypt(ctr, CTRPAD, skey)) != CRYPT_OK) {
+                goto error;
+             }
+             CTRlen = 0;
+          }
+
+          /* if we encrypt we add the bytes to the MAC first */
+          if (direction == CCM_ENCRYPT) {
+             b     = pt[y];
+             ct[y] = b ^ CTRPAD[CTRlen++];
+          } else {
+             b     = ct[y] ^ CTRPAD[CTRlen++];
+             pt[y] = b;
+          }
+
+          if (x == 16) {
+             if ((err = cipher_descriptor[cipher].ecb_encrypt(PAD, PAD, skey)) != CRYPT_OK) {
+                goto error;
+             }
+             x = 0;
+          }
+          PAD[x++] ^= b;
+      }
+
+      if (x != 0) {
+         if ((err = cipher_descriptor[cipher].ecb_encrypt(PAD, PAD, skey)) != CRYPT_OK) {
+            goto error;
+         }
+      }
+   }
+
+   /* setup CTR for the TAG (zero the count) */
+   for (y = 15; y > 15 - L; y--) {
+      ctr[y] = 0x00;
+   }
+   if ((err = cipher_descriptor[cipher].ecb_encrypt(ctr, CTRPAD, skey)) != CRYPT_OK) {
+      goto error;
+   }
+
+   if (skey != uskey) {
+      cipher_descriptor[cipher].done(skey);
+#ifdef LTC_CLEAN_STACK
+      zeromem(skey,   sizeof(*skey));
+#endif
+   }
+
+   if (direction == CCM_ENCRYPT) {
+      /* store the TAG */
+      for (x = 0; x < 16 && x < *taglen; x++) {
+          tag[x] = PAD[x] ^ CTRPAD[x];
+      }
+      *taglen = x;
+   } else { /* direction == CCM_DECRYPT */
+      /* decrypt the tag */
+      for (x = 0; x < 16 && x < *taglen; x++) {
+         ptTag[x] = tag[x] ^ CTRPAD[x];
+      }
+      *taglen = x;
+
+      /* check validity of the decrypted tag against the computed PAD (in constant time) */
+      /* HACK: the boolean value of XMEM_NEQ becomes either 0 (CRYPT_OK) or 1 (CRYPT_ERR).
+       *       there should be a better way of setting the correct error code in constant
+       *       time.
+       */
+      err = XMEM_NEQ(ptTag, PAD, *taglen);
+
+      /* Zero the plaintext if the tag was invalid (in constant time) */
+      if (ptlen > 0) {
+         y = 0;
+         mask *= 1 - err; /* mask = ( err ? 0 : 0xff ) */
+#ifdef LTC_FAST
+         fastMask *= 1 - err;
+         if (ptlen & ~15) {
+            for (; y < (ptlen & ~15); y += 16) {
+              for (z = 0; z < 16; z += sizeof(LTC_FAST_TYPE)) {
+                *(LTC_FAST_TYPE_PTR_CAST(&pt_real[y+z])) = *(LTC_FAST_TYPE_PTR_CAST(&pt[y+z])) & fastMask;
+              }
+            }
+         }
+#endif
+         for (; y < ptlen; y++) {
+            pt_real[y] = pt[y] & mask;
+         }
+      }
+   }
+
+#ifdef LTC_CLEAN_STACK
+#ifdef LTC_FAST
+   fastMask = 0;
+#endif
+   mask = 0;
+   zeromem(PAD,    sizeof(PAD));
+   zeromem(CTRPAD, sizeof(CTRPAD));
+   if (pt_work != NULL) {
+     zeromem(pt_work, ptlen);
+   }
+#endif
+error:
+   if (pt_work) {
+      XFREE(pt_work);
+   }
+   if (skey != uskey) {
+      XFREE(skey);
+   }
+
+   return err;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/encauth/ccm/ccm_process.c b/libtomcrypt/src/encauth/ccm/ccm_process.c
new file mode 100644 (file)
index 0000000..8346d22
--- /dev/null
@@ -0,0 +1,88 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+#ifdef LTC_CCM_MODE
+
+/**
+  Process plaintext/ciphertext through CCM
+  @param ccm       The CCM state
+  @param pt        The plaintext
+  @param ptlen     The plaintext length (ciphertext length is the same)
+  @param ct        The ciphertext
+  @param direction Encrypt or Decrypt mode (CCM_ENCRYPT or CCM_DECRYPT)
+  @return CRYPT_OK on success
+ */
+int ccm_process(ccm_state *ccm,
+                unsigned char *pt,     unsigned long ptlen,
+                unsigned char *ct,
+                int direction)
+{
+   unsigned char z, b;
+   unsigned long y;
+   int err;
+
+   LTC_ARGCHK(ccm != NULL);
+
+   /* Check aad has been correctly added */
+   if (ccm->aadlen != ccm->current_aadlen) {
+      return CRYPT_ERROR;
+   }
+
+   /* Check we do not process too much data */
+   if (ccm->ptlen < ccm->current_ptlen + ptlen) {
+      return CRYPT_ERROR;
+   }
+   ccm->current_ptlen += ptlen;
+
+   /* now handle the PT */
+   if (ptlen > 0) {
+      LTC_ARGCHK(pt != NULL);
+      LTC_ARGCHK(ct != NULL);
+
+      for (y = 0; y < ptlen; y++) {
+         /* increment the ctr? */
+         if (ccm->CTRlen == 16) {
+            for (z = 15; z > 15-ccm->L; z--) {
+               ccm->ctr[z] = (ccm->ctr[z] + 1) & 255;
+               if (ccm->ctr[z]) break;
+            }
+            if ((err = cipher_descriptor[ccm->cipher].ecb_encrypt(ccm->ctr, ccm->CTRPAD, &ccm->K)) != CRYPT_OK) {
+               return err;
+            }
+            ccm->CTRlen = 0;
+         }
+
+         /* if we encrypt we add the bytes to the MAC first */
+         if (direction == CCM_ENCRYPT) {
+            b     = pt[y];
+            ct[y] = b ^ ccm->CTRPAD[ccm->CTRlen++];
+         } else {
+            b     = ct[y] ^ ccm->CTRPAD[ccm->CTRlen++];
+            pt[y] = b;
+         }
+
+         if (ccm->x == 16) {
+            if ((err = cipher_descriptor[ccm->cipher].ecb_encrypt(ccm->PAD, ccm->PAD, &ccm->K)) != CRYPT_OK) {
+               return err;
+            }
+            ccm->x = 0;
+         }
+         ccm->PAD[ccm->x++] ^= b;
+      }
+   }
+
+   return CRYPT_OK;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/encauth/ccm/ccm_reset.c b/libtomcrypt/src/encauth/ccm/ccm_reset.c
new file mode 100644 (file)
index 0000000..c2d0cae
--- /dev/null
@@ -0,0 +1,35 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+#ifdef LTC_CCM_MODE
+
+/**
+  Reset a CCM state to as if you just called ccm_init().  This saves the initialization time.
+  @param ccm   The CCM state to reset
+  @return CRYPT_OK on success
+*/
+int ccm_reset(ccm_state *ccm)
+{
+   LTC_ARGCHK(ccm != NULL);
+   zeromem(ccm->PAD, sizeof(ccm->PAD));
+   zeromem(ccm->ctr, sizeof(ccm->ctr));
+   zeromem(ccm->CTRPAD, sizeof(ccm->CTRPAD));
+   ccm->CTRlen = 0;
+   ccm->current_ptlen = 0;
+   ccm->current_aadlen = 0;
+
+   return CRYPT_OK;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/encauth/ccm/ccm_test.c b/libtomcrypt/src/encauth/ccm/ccm_test.c
new file mode 100644 (file)
index 0000000..6d1e1e6
--- /dev/null
@@ -0,0 +1,257 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file ccm_test.c
+  CCM support, process a block of memory, Tom St Denis
+*/
+
+#ifdef LTC_CCM_MODE
+
+int ccm_test(void)
+{
+#ifndef LTC_TEST
+   return CRYPT_NOP;
+#else
+   static const struct {
+       unsigned char key[16];
+       unsigned char nonce[16];
+       int           noncelen;
+       unsigned char header[64];
+       int           headerlen;
+       unsigned char pt[64];
+       int           ptlen;
+       unsigned char ct[64];
+       unsigned char tag[16];
+       unsigned long taglen;
+   } tests[] = {
+
+/* 13 byte nonce, 8 byte auth, 23 byte pt */
+{
+   { 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
+     0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF },
+   { 0x00, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00, 0xA0,
+     0xA1, 0xA2, 0xA3, 0xA4, 0xA5 },
+   13,
+   { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 },
+   8,
+   { 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+     0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+     0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E },
+   23,
+   { 0x58, 0x8C, 0x97, 0x9A, 0x61, 0xC6, 0x63, 0xD2,
+     0xF0, 0x66, 0xD0, 0xC2, 0xC0, 0xF9, 0x89, 0x80,
+     0x6D, 0x5F, 0x6B, 0x61, 0xDA, 0xC3, 0x84 },
+   { 0x17, 0xe8, 0xd1, 0x2c, 0xfd, 0xf9, 0x26, 0xe0 },
+   8
+},
+
+/* 13 byte nonce, 12 byte header, 19 byte pt */
+{
+   { 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
+     0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF },
+   { 0x00, 0x00, 0x00, 0x06, 0x05, 0x04, 0x03, 0xA0,
+     0xA1, 0xA2, 0xA3, 0xA4, 0xA5 },
+   13,
+   { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+     0x08, 0x09, 0x0A, 0x0B },
+   12,
+   { 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13,
+     0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B,
+     0x1C, 0x1D, 0x1E },
+   19,
+   { 0xA2, 0x8C, 0x68, 0x65, 0x93, 0x9A, 0x9A, 0x79,
+     0xFA, 0xAA, 0x5C, 0x4C, 0x2A, 0x9D, 0x4A, 0x91,
+     0xCD, 0xAC, 0x8C },
+   { 0x96, 0xC8, 0x61, 0xB9, 0xC9, 0xE6, 0x1E, 0xF1 },
+   8
+},
+
+/* supplied by Brian Gladman */
+{
+   { 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+     0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f },
+   { 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16  },
+   7,
+   { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 },
+   8,
+   { 0x20, 0x21, 0x22, 0x23 },
+   4,
+   { 0x71, 0x62, 0x01, 0x5b },
+   { 0x4d, 0xac, 0x25, 0x5d },
+   4
+},
+
+{
+   { 0xc9, 0x7c, 0x1f, 0x67, 0xce, 0x37, 0x11, 0x85,
+     0x51, 0x4a, 0x8a, 0x19, 0xf2, 0xbd, 0xd5, 0x2f },
+   { 0x00, 0x50, 0x30, 0xf1, 0x84, 0x44, 0x08, 0xb5,
+     0x03, 0x97, 0x76, 0xe7, 0x0c },
+   13,
+   { 0x08, 0x40, 0x0f, 0xd2, 0xe1, 0x28, 0xa5, 0x7c,
+     0x50, 0x30, 0xf1, 0x84, 0x44, 0x08, 0xab, 0xae,
+     0xa5, 0xb8, 0xfc, 0xba, 0x00, 0x00 },
+   22,
+   { 0xf8, 0xba, 0x1a, 0x55, 0xd0, 0x2f, 0x85, 0xae,
+     0x96, 0x7b, 0xb6, 0x2f, 0xb6, 0xcd, 0xa8, 0xeb,
+     0x7e, 0x78, 0xa0, 0x50 },
+   20,
+   { 0xf3, 0xd0, 0xa2, 0xfe, 0x9a, 0x3d, 0xbf, 0x23,
+     0x42, 0xa6, 0x43, 0xe4, 0x32, 0x46, 0xe8, 0x0c,
+     0x3c, 0x04, 0xd0, 0x19 },
+   { 0x78, 0x45, 0xce, 0x0b, 0x16, 0xf9, 0x76, 0x23 },
+   8
+},
+
+};
+  unsigned long taglen, x, y;
+  unsigned char buf[64], buf2[64], tag[16], tag2[16], tag3[16], zero[64];
+  int           err, idx;
+  symmetric_key skey;
+  ccm_state ccm;
+
+  zeromem(zero, 64);
+
+  idx = find_cipher("aes");
+  if (idx == -1) {
+     idx = find_cipher("rijndael");
+     if (idx == -1) {
+        return CRYPT_NOP;
+     }
+  }
+
+  for (x = 0; x < (sizeof(tests)/sizeof(tests[0])); x++) {
+    for (y = 0; y < 2; y++) {
+      taglen = tests[x].taglen;
+      if (y == 0) {
+         if ((err = cipher_descriptor[idx].setup(tests[x].key, 16, 0, &skey)) != CRYPT_OK) {
+            return err;
+         }
+
+         if ((err = ccm_memory(idx,
+                               tests[x].key, 16,
+                               &skey,
+                               tests[x].nonce, tests[x].noncelen,
+                               tests[x].header, tests[x].headerlen,
+                               (unsigned char*)tests[x].pt, tests[x].ptlen,
+                               buf,
+                               tag, &taglen, 0)) != CRYPT_OK) {
+            return err;
+         }
+         /* run a second time to make sure skey is not touched */
+         if ((err = ccm_memory(idx,
+                               tests[x].key, 16,
+                               &skey,
+                               tests[x].nonce, tests[x].noncelen,
+                               tests[x].header, tests[x].headerlen,
+                               (unsigned char*)tests[x].pt, tests[x].ptlen,
+                               buf,
+                               tag, &taglen, 0)) != CRYPT_OK) {
+            return err;
+         }
+      } else {
+         if ((err = ccm_init(&ccm, idx, tests[x].key, 16, tests[x].ptlen, tests[x].taglen, tests[x].headerlen)) != CRYPT_OK) {
+            return err;
+         }
+         if ((err = ccm_add_nonce(&ccm, tests[x].nonce, tests[x].noncelen)) != CRYPT_OK) {
+            return err;
+         }
+         if ((err = ccm_add_aad(&ccm, tests[x].header, tests[x].headerlen)) != CRYPT_OK) {
+            return err;
+         }
+         if ((err = ccm_process(&ccm, (unsigned char*)tests[x].pt, tests[x].ptlen, buf, CCM_ENCRYPT)) != CRYPT_OK) {
+            return err;
+         }
+         if ((err = ccm_done(&ccm, tag, &taglen)) != CRYPT_OK) {
+            return err;
+         }
+      }
+
+      if (compare_testvector(buf, tests[x].ptlen, tests[x].ct, tests[x].ptlen, "CCM encrypt data", x)) {
+         return CRYPT_FAIL_TESTVECTOR;
+      }
+      if (compare_testvector(tag, taglen, tests[x].tag, tests[x].taglen, "CCM encrypt tag", x)) {
+         return CRYPT_FAIL_TESTVECTOR;
+      }
+
+      if (y == 0) {
+         XMEMCPY(tag3, tests[x].tag, tests[x].taglen);
+         taglen = tests[x].taglen;
+         if ((err = ccm_memory(idx,
+                               tests[x].key, 16,
+                               NULL,
+                               tests[x].nonce, tests[x].noncelen,
+                               tests[x].header, tests[x].headerlen,
+                               buf2, tests[x].ptlen,
+                               buf,
+                               tag3, &taglen, 1   )) != CRYPT_OK) {
+            return err;
+         }
+      } else {
+         if ((err = ccm_init(&ccm, idx, tests[x].key, 16, tests[x].ptlen, tests[x].taglen, tests[x].headerlen)) != CRYPT_OK) {
+            return err;
+         }
+         if ((err = ccm_add_nonce(&ccm, tests[x].nonce, tests[x].noncelen)) != CRYPT_OK) {
+            return err;
+         }
+         if ((err = ccm_add_aad(&ccm, tests[x].header, tests[x].headerlen)) != CRYPT_OK) {
+            return err;
+         }
+         if ((err = ccm_process(&ccm, buf2, tests[x].ptlen, buf, CCM_DECRYPT)) != CRYPT_OK) {
+            return err;
+         }
+         if ((err = ccm_done(&ccm, tag2, &taglen)) != CRYPT_OK) {
+            return err;
+         }
+      }
+
+
+      if (compare_testvector(buf2, tests[x].ptlen, tests[x].pt, tests[x].ptlen, "CCM decrypt data", x)) {
+         return CRYPT_FAIL_TESTVECTOR;
+      }
+      if (y == 0) {
+        /* check if decryption with the wrong tag does not reveal the plaintext */
+        XMEMCPY(tag3, tests[x].tag, tests[x].taglen);
+        tag3[0] ^= 0xff; /* set the tag to the wrong value */
+        taglen = tests[x].taglen;
+        if ((err = ccm_memory(idx,
+                              tests[x].key, 16,
+                              NULL,
+                              tests[x].nonce, tests[x].noncelen,
+                              tests[x].header, tests[x].headerlen,
+                              buf2, tests[x].ptlen,
+                              buf,
+                              tag3, &taglen, 1   )) != CRYPT_ERROR) {
+          return CRYPT_FAIL_TESTVECTOR;
+        }
+        if (compare_testvector(buf2, tests[x].ptlen, zero, tests[x].ptlen, "CCM decrypt wrong tag", x)) {
+           return CRYPT_FAIL_TESTVECTOR;
+        }
+      } else {
+        if (compare_testvector(tag2, taglen, tests[x].tag, tests[x].taglen, "CCM decrypt tag", x)) {
+           return CRYPT_FAIL_TESTVECTOR;
+        }
+      }
+
+      if (y == 0) {
+         cipher_descriptor[idx].done(&skey);
+      }
+    }
+  }
+
+  return CRYPT_OK;
+#endif
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/encauth/chachapoly/chacha20poly1305_add_aad.c b/libtomcrypt/src/encauth/chachapoly/chacha20poly1305_add_aad.c
new file mode 100644 (file)
index 0000000..0c0cf9d
--- /dev/null
@@ -0,0 +1,38 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+#include "tomcrypt.h"
+
+#ifdef LTC_CHACHA20POLY1305_MODE
+
+/**
+  Add AAD to the ChaCha20Poly1305 state
+  @param st     The ChaCha20Poly1305 state
+  @param in     The additional authentication data to add to the ChaCha20Poly1305 state
+  @param inlen  The length of the ChaCha20Poly1305 data.
+  @return CRYPT_OK on success
+ */
+int chacha20poly1305_add_aad(chacha20poly1305_state *st, const unsigned char *in, unsigned long inlen)
+{
+   int err;
+
+   if (inlen == 0) return CRYPT_OK; /* nothing to do */
+   LTC_ARGCHK(st != NULL);
+
+   if (st->aadflg == 0) return CRYPT_ERROR;
+   if ((err = poly1305_process(&st->poly, in, inlen)) != CRYPT_OK) return err;
+   st->aadlen += (ulong64)inlen;
+   return CRYPT_OK;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/encauth/chachapoly/chacha20poly1305_decrypt.c b/libtomcrypt/src/encauth/chachapoly/chacha20poly1305_decrypt.c
new file mode 100644 (file)
index 0000000..1797932
--- /dev/null
@@ -0,0 +1,49 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+#include "tomcrypt.h"
+
+#ifdef LTC_CHACHA20POLY1305_MODE
+
+/**
+   Decrypt bytes of ciphertext with ChaCha20Poly1305
+   @param st      The ChaCha20Poly1305 state
+   @param in      The ciphertext
+   @param inlen   The length of the input (octets)
+   @param out     [out] The plaintext (length inlen)
+   @return CRYPT_OK if successful
+*/
+int chacha20poly1305_decrypt(chacha20poly1305_state *st, const unsigned char *in, unsigned long inlen, unsigned char *out)
+{
+   unsigned char padzero[16] = { 0 };
+   unsigned long padlen;
+   int err;
+
+   if (inlen == 0) return CRYPT_OK; /* nothing to do */
+   LTC_ARGCHK(st != NULL);
+
+   if (st->aadflg) {
+      padlen = 16 - (unsigned long)(st->aadlen % 16);
+      if (padlen < 16) {
+        if ((err = poly1305_process(&st->poly, padzero, padlen)) != CRYPT_OK) return err;
+      }
+      st->aadflg = 0; /* no more AAD */
+   }
+   if (st->aadflg) st->aadflg = 0; /* no more AAD */
+   if ((err = poly1305_process(&st->poly, in, inlen)) != CRYPT_OK)         return err;
+   if ((err = chacha_crypt(&st->chacha, in, inlen, out)) != CRYPT_OK)      return err;
+   st->ctlen += (ulong64)inlen;
+   return CRYPT_OK;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/encauth/chachapoly/chacha20poly1305_done.c b/libtomcrypt/src/encauth/chachapoly/chacha20poly1305_done.c
new file mode 100644 (file)
index 0000000..127a7f0
--- /dev/null
@@ -0,0 +1,46 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+#include "tomcrypt.h"
+
+#ifdef LTC_CHACHA20POLY1305_MODE
+
+/**
+  Terminate a ChaCha20Poly1305 stream
+  @param st      The ChaCha20Poly1305 state
+  @param tag     [out] The destination for the MAC tag
+  @param taglen  [in/out]  The length of the MAC tag
+  @return CRYPT_OK on success
+ */
+int chacha20poly1305_done(chacha20poly1305_state *st, unsigned char *tag, unsigned long *taglen)
+{
+   unsigned char padzero[16] = { 0 };
+   unsigned long padlen;
+   unsigned char buf[16];
+   int err;
+
+   LTC_ARGCHK(st != NULL);
+
+   padlen = 16 - (unsigned long)(st->ctlen % 16);
+   if (padlen < 16) {
+     if ((err = poly1305_process(&st->poly, padzero, padlen)) != CRYPT_OK) return err;
+   }
+   STORE64L(st->aadlen, buf);
+   STORE64L(st->ctlen, buf + 8);
+   if ((err = poly1305_process(&st->poly, buf, 16)) != CRYPT_OK)           return err;
+   if ((err = poly1305_done(&st->poly, tag, taglen)) != CRYPT_OK)          return err;
+   if ((err = chacha_done(&st->chacha)) != CRYPT_OK)                       return err;
+   return CRYPT_OK;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/encauth/chachapoly/chacha20poly1305_encrypt.c b/libtomcrypt/src/encauth/chachapoly/chacha20poly1305_encrypt.c
new file mode 100644 (file)
index 0000000..c53c4a6
--- /dev/null
@@ -0,0 +1,48 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+#include "tomcrypt.h"
+
+#ifdef LTC_CHACHA20POLY1305_MODE
+
+/**
+   Encrypt bytes of ciphertext with ChaCha20Poly1305
+   @param st      The ChaCha20Poly1305 state
+   @param in      The plaintext
+   @param inlen   The length of the input (octets)
+   @param out     [out] The ciphertext (length inlen)
+   @return CRYPT_OK if successful
+*/
+int chacha20poly1305_encrypt(chacha20poly1305_state *st, const unsigned char *in, unsigned long inlen, unsigned char *out)
+{
+   unsigned char padzero[16] = { 0 };
+   unsigned long padlen;
+   int err;
+
+   if (inlen == 0) return CRYPT_OK; /* nothing to do */
+   LTC_ARGCHK(st != NULL);
+
+   if ((err = chacha_crypt(&st->chacha, in, inlen, out)) != CRYPT_OK)         return err;
+   if (st->aadflg) {
+      padlen = 16 - (unsigned long)(st->aadlen % 16);
+      if (padlen < 16) {
+        if ((err = poly1305_process(&st->poly, padzero, padlen)) != CRYPT_OK) return err;
+      }
+      st->aadflg = 0; /* no more AAD */
+   }
+   if ((err = poly1305_process(&st->poly, out, inlen)) != CRYPT_OK)           return err;
+   st->ctlen += (ulong64)inlen;
+   return CRYPT_OK;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/encauth/chachapoly/chacha20poly1305_init.c b/libtomcrypt/src/encauth/chachapoly/chacha20poly1305_init.c
new file mode 100644 (file)
index 0000000..2799e98
--- /dev/null
@@ -0,0 +1,30 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+#include "tomcrypt.h"
+
+#ifdef LTC_CHACHA20POLY1305_MODE
+
+/**
+   Initialize an ChaCha20Poly1305 context (only the key)
+   @param st        [out] The destination of the ChaCha20Poly1305 state
+   @param key       The secret key
+   @param keylen    The length of the secret key (octets)
+   @return CRYPT_OK if successful
+*/
+int chacha20poly1305_init(chacha20poly1305_state *st, const unsigned char *key, unsigned long keylen)
+{
+   return chacha_setup(&st->chacha, key, keylen, 20);
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/encauth/chachapoly/chacha20poly1305_memory.c b/libtomcrypt/src/encauth/chachapoly/chacha20poly1305_memory.c
new file mode 100644 (file)
index 0000000..54e2011
--- /dev/null
@@ -0,0 +1,74 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+#include "tomcrypt.h"
+
+#ifdef LTC_CHACHA20POLY1305_MODE
+
+/**
+  Process an entire GCM packet in one call.
+  @param key               The secret key
+  @param keylen            The length of the secret key
+  @param iv                The initialization vector
+  @param ivlen             The length of the initialization vector
+  @param aad               The additional authentication data (header)
+  @param aadlen            The length of the aad
+  @param in                The plaintext
+  @param inlen             The length of the plaintext (ciphertext length is the same)
+  @param out               The ciphertext
+  @param tag               [out] The MAC tag
+  @param taglen            [in/out] The MAC tag length
+  @param direction         Encrypt or Decrypt mode (CHACHA20POLY1305_ENCRYPT or CHACHA20POLY1305_DECRYPT)
+  @return CRYPT_OK on success
+ */
+int chacha20poly1305_memory(const unsigned char *key, unsigned long keylen,
+                            const unsigned char *iv,  unsigned long ivlen,
+                            const unsigned char *aad, unsigned long aadlen,
+                            const unsigned char *in,  unsigned long inlen,
+                                  unsigned char *out,
+                                  unsigned char *tag, unsigned long *taglen,
+                            int direction)
+{
+   chacha20poly1305_state st;
+   int err;
+
+   LTC_ARGCHK(key != NULL);
+   LTC_ARGCHK(iv  != NULL);
+   LTC_ARGCHK(in  != NULL);
+   LTC_ARGCHK(out != NULL);
+   LTC_ARGCHK(tag != NULL);
+
+   if ((err = chacha20poly1305_init(&st, key, keylen)) != CRYPT_OK)          { goto LBL_ERR; }
+   if ((err = chacha20poly1305_setiv(&st, iv, ivlen)) != CRYPT_OK)           { goto LBL_ERR; }
+   if (aad && aadlen > 0) {
+      if ((err = chacha20poly1305_add_aad(&st, aad, aadlen)) != CRYPT_OK)    { goto LBL_ERR; }
+   }
+   if (direction == CHACHA20POLY1305_ENCRYPT) {
+      if ((err = chacha20poly1305_encrypt(&st, in, inlen, out)) != CRYPT_OK) { goto LBL_ERR; }
+   }
+   else if (direction == CHACHA20POLY1305_DECRYPT) {
+      if ((err = chacha20poly1305_decrypt(&st, in, inlen, out)) != CRYPT_OK) { goto LBL_ERR; }
+   }
+   else {
+      err = CRYPT_INVALID_ARG;
+      goto LBL_ERR;
+   }
+   err = chacha20poly1305_done(&st, tag, taglen);
+LBL_ERR:
+#ifdef LTC_CLEAN_STACK
+   zeromem(&st, sizeof(chacha20poly1305_state));
+#endif
+   return err;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/encauth/chachapoly/chacha20poly1305_setiv.c b/libtomcrypt/src/encauth/chachapoly/chacha20poly1305_setiv.c
new file mode 100644 (file)
index 0000000..b87666e
--- /dev/null
@@ -0,0 +1,68 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+#include "tomcrypt.h"
+
+#ifdef LTC_CHACHA20POLY1305_MODE
+
+/**
+  Set IV + counter data to the ChaCha20Poly1305 state and reset the context
+  @param st     The ChaCha20Poly1305 state
+  @param iv     The IV data to add
+  @param ivlen  The length of the IV (must be 12 or 8)
+  @return CRYPT_OK on success
+ */
+int chacha20poly1305_setiv(chacha20poly1305_state *st, const unsigned char *iv, unsigned long ivlen)
+{
+   chacha_state tmp_st;
+   int i, err;
+   unsigned char polykey[32];
+
+   LTC_ARGCHK(st != NULL);
+   LTC_ARGCHK(iv != NULL);
+   LTC_ARGCHK(ivlen == 12 || ivlen == 8);
+
+   /* set IV for chacha20 */
+   if (ivlen == 12) {
+      /* IV 96bit */
+      if ((err = chacha_ivctr32(&st->chacha, iv, ivlen, 1)) != CRYPT_OK) return err;
+   }
+   else {
+      /* IV 64bit */
+      if ((err = chacha_ivctr64(&st->chacha, iv, ivlen, 1)) != CRYPT_OK) return err;
+   }
+
+   /* copy chacha20 key to temporary state */
+   for(i = 0; i < 12; i++) tmp_st.input[i] = st->chacha.input[i];
+   tmp_st.rounds = 20;
+   /* set IV */
+   if (ivlen == 12) {
+      /* IV 32bit */
+      if ((err = chacha_ivctr32(&tmp_st, iv, ivlen, 0)) != CRYPT_OK) return err;
+   }
+   else {
+      /* IV 64bit */
+      if ((err = chacha_ivctr64(&tmp_st, iv, ivlen, 0)) != CRYPT_OK) return err;
+   }
+   /* (re)generate new poly1305 key */
+   if ((err = chacha_keystream(&tmp_st, polykey, 32)) != CRYPT_OK) return err;
+   /* (re)initialise poly1305 */
+   if ((err = poly1305_init(&st->poly, polykey, 32)) != CRYPT_OK) return err;
+   st->ctlen  = 0;
+   st->aadlen = 0;
+   st->aadflg = 1;
+
+   return CRYPT_OK;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/encauth/chachapoly/chacha20poly1305_setiv_rfc7905.c b/libtomcrypt/src/encauth/chachapoly/chacha20poly1305_setiv_rfc7905.c
new file mode 100644 (file)
index 0000000..7136a1e
--- /dev/null
@@ -0,0 +1,40 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+#include "tomcrypt.h"
+
+#ifdef LTC_CHACHA20POLY1305_MODE
+
+/**
+  Set IV + counter data (with RFC7905-magic) to the ChaCha20Poly1305 state and reset the context
+  @param st     The ChaCha20Poly1305 state
+  @param iv     The IV data to add
+  @param ivlen  The length of the IV (must be 12 or 8)
+  @param sequence_number   64bit sequence number which is incorporated into IV as described in RFC7905
+  @return CRYPT_OK on success
+ */
+int chacha20poly1305_setiv_rfc7905(chacha20poly1305_state *st, const unsigned char *iv, unsigned long ivlen, ulong64 sequence_number)
+{
+   int i;
+   unsigned char combined_iv[12] = { 0 };
+
+   LTC_ARGCHK(st != NULL);
+   LTC_ARGCHK(iv != NULL);
+   LTC_ARGCHK(ivlen == 12);
+
+   STORE64L(sequence_number, combined_iv + 4);
+   for (i = 0; i < 12; i++) combined_iv[i] = iv[i] ^ combined_iv[i];
+   return chacha20poly1305_setiv(st, combined_iv, 12);
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/encauth/chachapoly/chacha20poly1305_test.c b/libtomcrypt/src/encauth/chachapoly/chacha20poly1305_test.c
new file mode 100644 (file)
index 0000000..2ba88dd
--- /dev/null
@@ -0,0 +1,134 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+#include "tomcrypt.h"
+
+#ifdef LTC_CHACHA20POLY1305_MODE
+
+int chacha20poly1305_test(void)
+{
+#ifndef LTC_TEST
+   return CRYPT_NOP;
+#else
+   chacha20poly1305_state st1, st2;
+   unsigned char k[]   = { 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f };
+   unsigned char i12[] = { 0x07, 0x00, 0x00, 0x00, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47 };
+   unsigned char i8[]  = { 0x07, 0x00, 0x00, 0x00, 0x40, 0x41, 0x42, 0x43 };
+   unsigned char aad[] = { 0x50, 0x51, 0x52, 0x53, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7 };
+   unsigned char enc[] = { 0xD3, 0x1A, 0x8D, 0x34, 0x64, 0x8E, 0x60, 0xDB, 0x7B, 0x86, 0xAF, 0xBC, 0x53, 0xEF, 0x7E, 0xC2,
+                           0xA4, 0xAD, 0xED, 0x51, 0x29, 0x6E, 0x08, 0xFE, 0xA9, 0xE2, 0xB5, 0xA7, 0x36, 0xEE, 0x62, 0xD6,
+                           0x3D, 0xBE, 0xA4, 0x5E, 0x8C, 0xA9, 0x67, 0x12, 0x82, 0xFA, 0xFB, 0x69, 0xDA, 0x92, 0x72, 0x8B,
+                           0x1A, 0x71, 0xDE, 0x0A, 0x9E, 0x06, 0x0B, 0x29, 0x05, 0xD6, 0xA5, 0xB6, 0x7E, 0xCD, 0x3B, 0x36,
+                           0x92, 0xDD, 0xBD, 0x7F, 0x2D, 0x77, 0x8B, 0x8C, 0x98, 0x03, 0xAE, 0xE3, 0x28, 0x09, 0x1B, 0x58,
+                           0xFA, 0xB3, 0x24, 0xE4, 0xFA, 0xD6, 0x75, 0x94, 0x55, 0x85, 0x80, 0x8B, 0x48, 0x31, 0xD7, 0xBC,
+                           0x3F, 0xF4, 0xDE, 0xF0, 0x8E, 0x4B, 0x7A, 0x9D, 0xE5, 0x76, 0xD2, 0x65, 0x86, 0xCE, 0xC6, 0x4B,
+                           0x61, 0x16 };
+   unsigned char tag[] = { 0x1A, 0xE1, 0x0B, 0x59, 0x4F, 0x09, 0xE2, 0x6A, 0x7E, 0x90, 0x2E, 0xCB, 0xD0, 0x60, 0x06, 0x91 };
+   char m[] = "Ladies and Gentlemen of the class of '99: If I could offer you only one tip for the future, sunscreen would be it.";
+   unsigned long mlen = strlen(m);
+   unsigned long len;
+   unsigned char rfc7905_pt[]  = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F };
+   unsigned char rfc7905_enc[] = { 0xE4, 0x62, 0x85, 0xB4, 0x29, 0x95, 0x34, 0x96, 0xAB, 0xFB, 0x67, 0xCD, 0xAE, 0xAC, 0x94, 0x1E };
+   unsigned char rfc7905_tag[] = { 0x16, 0x2C, 0x92, 0x48, 0x2A, 0xDB, 0xD3, 0x5D, 0x48, 0xBE, 0xC6, 0xFF, 0x10, 0x9C, 0xBA, 0xE4 };
+   unsigned char ct[1000], pt[1000], emac[16], dmac[16];
+   int err;
+
+   /* encrypt IV 96bit */
+   if ((err = chacha20poly1305_init(&st1, k, sizeof(k))) != CRYPT_OK) return err;
+   if ((err = chacha20poly1305_setiv(&st1, i12, sizeof(i12))) != CRYPT_OK) return err;
+   if ((err = chacha20poly1305_add_aad(&st1, aad, sizeof(aad))) != CRYPT_OK) return err;
+   /* encrypt piece by piece */
+   if ((err = chacha20poly1305_encrypt(&st1, (unsigned char *)m,      25,        ct)) != CRYPT_OK) return err;
+   if ((err = chacha20poly1305_encrypt(&st1, (unsigned char *)m + 25, 10,        ct + 25)) != CRYPT_OK) return err;
+   if ((err = chacha20poly1305_encrypt(&st1, (unsigned char *)m + 35, 35,        ct + 35)) != CRYPT_OK) return err;
+   if ((err = chacha20poly1305_encrypt(&st1, (unsigned char *)m + 70, 5,         ct + 70)) != CRYPT_OK) return err;
+   if ((err = chacha20poly1305_encrypt(&st1, (unsigned char *)m + 75, 5,         ct + 75)) != CRYPT_OK) return err;
+   if ((err = chacha20poly1305_encrypt(&st1, (unsigned char *)m + 80, mlen - 80, ct + 80)) != CRYPT_OK) return err;
+   len = sizeof(emac);
+   if ((err = chacha20poly1305_done(&st1, emac, &len)) != CRYPT_OK) return err;
+
+   if (compare_testvector(ct, mlen, enc, sizeof(enc), "ENC-CT", 1) != 0) return CRYPT_FAIL_TESTVECTOR;
+   if (compare_testvector(emac, len, tag, sizeof(tag), "ENC-TAG", 2) != 0) return CRYPT_FAIL_TESTVECTOR;
+
+   /* decrypt IV 96bit */
+   if ((err = chacha20poly1305_init(&st2, k, sizeof(k))) != CRYPT_OK) return err;
+   if ((err = chacha20poly1305_setiv(&st2, i12, sizeof(i12))) != CRYPT_OK) return err;
+   if ((err = chacha20poly1305_add_aad(&st2, aad, sizeof(aad))) != CRYPT_OK) return err;
+   if ((err = chacha20poly1305_decrypt(&st2, ct,      21,        pt)) != CRYPT_OK) return err;
+   if ((err = chacha20poly1305_decrypt(&st2, ct + 21, mlen - 21, pt + 21)) != CRYPT_OK) return err;
+   len = sizeof(dmac);
+   if ((err = chacha20poly1305_done(&st2, dmac, &len)) != CRYPT_OK) return err;
+
+   if (compare_testvector(pt, mlen, m, mlen, "DEC-PT", 3) != 0) return CRYPT_FAIL_TESTVECTOR;
+   if (compare_testvector(dmac, len, tag, sizeof(tag), "DEC-TAG", 4) != 0) return CRYPT_FAIL_TESTVECTOR;
+
+   /* chacha20poly1305_memory - encrypt */
+   len = sizeof(emac);
+   if ((err = chacha20poly1305_memory(k, sizeof(k), i12, sizeof(i12), aad, sizeof(aad), (unsigned char *)m,
+                                      mlen, ct, emac, &len, CHACHA20POLY1305_ENCRYPT)) != CRYPT_OK) return err;
+   if (compare_testvector(ct, mlen, enc, sizeof(enc), "ENC-CT2", 1) != 0) return CRYPT_FAIL_TESTVECTOR;
+   if (compare_testvector(emac, len, tag, sizeof(tag), "ENC-TAG2", 2) != 0) return CRYPT_FAIL_TESTVECTOR;
+
+   /* chacha20poly1305_memory - decrypt */
+   len = sizeof(dmac);
+   if ((err = chacha20poly1305_memory(k, sizeof(k), i12, sizeof(i12), aad, sizeof(aad),
+                                      ct, mlen, pt, dmac, &len, CHACHA20POLY1305_DECRYPT)) != CRYPT_OK) return err;
+   if (compare_testvector(pt, mlen, m, mlen, "DEC-PT2", 3) != 0) return CRYPT_FAIL_TESTVECTOR;
+   if (compare_testvector(dmac, len, tag, sizeof(tag), "DEC-TAG2", 4) != 0) return CRYPT_FAIL_TESTVECTOR;
+
+   /* encrypt - rfc7905 */
+   if ((err = chacha20poly1305_init(&st1, k, sizeof(k))) != CRYPT_OK) return err;
+   if ((err = chacha20poly1305_setiv_rfc7905(&st1, i12, sizeof(i12), CONST64(0x1122334455667788))) != CRYPT_OK) return err;
+   if ((err = chacha20poly1305_add_aad(&st1, aad, sizeof(aad))) != CRYPT_OK) return err;
+   if ((err = chacha20poly1305_encrypt(&st1, rfc7905_pt, 16, ct)) != CRYPT_OK) return err;
+   len = sizeof(emac);
+   if ((err = chacha20poly1305_done(&st1, emac, &len)) != CRYPT_OK) return err;
+
+   if (compare_testvector(ct, 16, rfc7905_enc, 16, "ENC-CT3", 1) != 0) return CRYPT_FAIL_TESTVECTOR;
+   if (compare_testvector(emac, len, rfc7905_tag, 16, "ENC-TAG3", 2) != 0) return CRYPT_FAIL_TESTVECTOR;
+
+   /* decrypt - rfc7905 */
+   if ((err = chacha20poly1305_init(&st1, k, sizeof(k))) != CRYPT_OK) return err;
+   if ((err = chacha20poly1305_setiv_rfc7905(&st1, i12, sizeof(i12), CONST64(0x1122334455667788))) != CRYPT_OK) return err;
+   if ((err = chacha20poly1305_add_aad(&st1, aad, sizeof(aad))) != CRYPT_OK) return err;
+   if ((err = chacha20poly1305_decrypt(&st1, ct, 16, pt)) != CRYPT_OK) return err;
+   len = sizeof(dmac);
+   if ((err = chacha20poly1305_done(&st1, dmac, &len)) != CRYPT_OK) return err;
+
+   if (compare_testvector(pt, 16, rfc7905_pt, 16, "DEC-CT3", 1) != 0) return CRYPT_FAIL_TESTVECTOR;
+   if (compare_testvector(dmac, len, rfc7905_tag, 16, "DEC-TAG3", 2) != 0) return CRYPT_FAIL_TESTVECTOR;
+
+   /* encrypt IV 64bit */
+   if ((err = chacha20poly1305_init(&st1, k, sizeof(k))) != CRYPT_OK) return err;
+   if ((err = chacha20poly1305_setiv(&st1, i8, sizeof(i8))) != CRYPT_OK) return err;
+   if ((err = chacha20poly1305_add_aad(&st1, aad, sizeof(aad))) != CRYPT_OK) return err;
+   if ((err = chacha20poly1305_encrypt(&st1, (unsigned char *)m, mlen, ct)) != CRYPT_OK) return err;
+   len = sizeof(emac);
+   if ((err = chacha20poly1305_done(&st1, emac, &len)) != CRYPT_OK) return err;
+
+   /* decrypt IV 64bit */
+   if ((err = chacha20poly1305_init(&st2, k, sizeof(k))) != CRYPT_OK) return err;
+   if ((err = chacha20poly1305_setiv(&st2, i8, sizeof(i8))) != CRYPT_OK) return err;
+   if ((err = chacha20poly1305_add_aad(&st2, aad, sizeof(aad))) != CRYPT_OK) return err;
+   if ((err = chacha20poly1305_decrypt(&st2, ct, mlen, pt)) != CRYPT_OK) return err;
+   len = sizeof(dmac);
+   if ((err = chacha20poly1305_done(&st2, dmac, &len)) != CRYPT_OK) return err;
+
+   if (compare_testvector(pt, mlen, m, mlen, "DEC-PT4", 1) != 0) return CRYPT_FAIL_TESTVECTOR;
+   if (compare_testvector(dmac, len, emac, len, "DEC-TAG4", 2) != 0) return CRYPT_FAIL_TESTVECTOR;
+
+   return CRYPT_OK;
+#endif
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/encauth/eax/eax_addheader.c b/libtomcrypt/src/encauth/eax/eax_addheader.c
new file mode 100644 (file)
index 0000000..5545336
--- /dev/null
@@ -0,0 +1,36 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+/**
+    @file eax_addheader.c
+    EAX implementation, add meta-data, by Tom St Denis
+*/
+#include "tomcrypt.h"
+
+#ifdef LTC_EAX_MODE
+
+/**
+    add header (metadata) to the stream
+    @param eax    The current EAX state
+    @param header The header (meta-data) data you wish to add to the state
+    @param length The length of the header data
+    @return CRYPT_OK if successful
+*/
+int eax_addheader(eax_state *eax, const unsigned char *header,
+                  unsigned long length)
+{
+   LTC_ARGCHK(eax    != NULL);
+   LTC_ARGCHK(header != NULL);
+   return omac_process(&eax->headeromac, header, length);
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/encauth/eax/eax_decrypt.c b/libtomcrypt/src/encauth/eax/eax_decrypt.c
new file mode 100644 (file)
index 0000000..b140716
--- /dev/null
@@ -0,0 +1,48 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+/**
+    @file eax_decrypt.c
+    EAX implementation, decrypt block, by Tom St Denis
+*/
+#include "tomcrypt.h"
+
+#ifdef LTC_EAX_MODE
+
+/**
+   Decrypt data with the EAX protocol
+   @param eax     The EAX state
+   @param ct      The ciphertext
+   @param pt      [out] The plaintext
+   @param length  The length (octets) of the ciphertext
+   @return CRYPT_OK if successful
+*/
+int eax_decrypt(eax_state *eax, const unsigned char *ct, unsigned char *pt,
+                unsigned long length)
+{
+   int err;
+
+   LTC_ARGCHK(eax != NULL);
+   LTC_ARGCHK(pt  != NULL);
+   LTC_ARGCHK(ct  != NULL);
+
+   /* omac ciphertext */
+   if ((err = omac_process(&eax->ctomac, ct, length)) != CRYPT_OK) {
+      return err;
+   }
+
+   /* decrypt  */
+   return ctr_decrypt(ct, pt, length, &eax->ctr);
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/encauth/eax/eax_decrypt_verify_memory.c b/libtomcrypt/src/encauth/eax/eax_decrypt_verify_memory.c
new file mode 100644 (file)
index 0000000..8c6540f
--- /dev/null
@@ -0,0 +1,109 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+/**
+    @file eax_decrypt_verify_memory.c
+    EAX implementation, decrypt block of memory, by Tom St Denis
+*/
+#include "tomcrypt.h"
+
+#ifdef LTC_EAX_MODE
+
+/**
+   Decrypt a block of memory and verify the provided MAC tag with EAX
+   @param cipher     The index of the cipher desired
+   @param key        The secret key
+   @param keylen     The length of the key (octets)
+   @param nonce      The nonce data (use once) for the session
+   @param noncelen   The length of the nonce data.
+   @param header     The session header data
+   @param headerlen  The length of the header (octets)
+   @param ct         The ciphertext
+   @param ctlen      The length of the ciphertext (octets)
+   @param pt         [out] The plaintext
+   @param tag        The authentication tag provided by the encoder
+   @param taglen     [in/out] The length of the tag (octets)
+   @param stat       [out] The result of the decryption (1==valid tag, 0==invalid)
+   @return CRYPT_OK if successful regardless of the resulting tag comparison
+*/
+int eax_decrypt_verify_memory(int cipher,
+    const unsigned char *key,    unsigned long keylen,
+    const unsigned char *nonce,  unsigned long noncelen,
+    const unsigned char *header, unsigned long headerlen,
+    const unsigned char *ct,     unsigned long ctlen,
+          unsigned char *pt,
+          unsigned char *tag,    unsigned long taglen,
+          int           *stat)
+{
+   int            err;
+   eax_state     *eax;
+   unsigned char *buf;
+   unsigned long  buflen;
+
+   LTC_ARGCHK(stat != NULL);
+   LTC_ARGCHK(key  != NULL);
+   LTC_ARGCHK(pt   != NULL);
+   LTC_ARGCHK(ct   != NULL);
+   LTC_ARGCHK(tag  != NULL);
+
+   /* default to zero */
+   *stat = 0;
+
+   /* limit taglen */
+   taglen = MIN(taglen, MAXBLOCKSIZE);
+
+   /* allocate ram */
+   buf = XMALLOC(taglen);
+   eax = XMALLOC(sizeof(*eax));
+   if (eax == NULL || buf == NULL) {
+      if (eax != NULL) {
+         XFREE(eax);
+      }
+      if (buf != NULL) {
+         XFREE(buf);
+      }
+      return CRYPT_MEM;
+   }
+
+   if ((err = eax_init(eax, cipher, key, keylen, nonce, noncelen, header, headerlen)) != CRYPT_OK) {
+      goto LBL_ERR;
+   }
+
+   if ((err = eax_decrypt(eax, ct, pt, ctlen)) != CRYPT_OK) {
+      goto LBL_ERR;
+   }
+
+   buflen = taglen;
+   if ((err = eax_done(eax, buf, &buflen)) != CRYPT_OK) {
+      goto LBL_ERR;
+   }
+
+   /* compare tags */
+   if (buflen >= taglen && XMEM_NEQ(buf, tag, taglen) == 0) {
+      *stat = 1;
+   }
+
+   err = CRYPT_OK;
+LBL_ERR:
+#ifdef LTC_CLEAN_STACK
+   zeromem(buf, taglen);
+   zeromem(eax, sizeof(*eax));
+#endif
+
+   XFREE(eax);
+   XFREE(buf);
+
+   return err;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/encauth/eax/eax_done.c b/libtomcrypt/src/encauth/eax/eax_done.c
new file mode 100644 (file)
index 0000000..b00bfe0
--- /dev/null
@@ -0,0 +1,92 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+/**
+   @file eax_done.c
+   EAX implementation, terminate session, by Tom St Denis
+*/
+#include "tomcrypt.h"
+
+#ifdef LTC_EAX_MODE
+
+/**
+   Terminate an EAX session and get the tag.
+   @param eax       The EAX state
+   @param tag       [out] The destination of the authentication tag
+   @param taglen    [in/out] The max length and resulting length of the authentication tag
+   @return CRYPT_OK if successful
+*/
+int eax_done(eax_state *eax, unsigned char *tag, unsigned long *taglen)
+{
+   int           err;
+   unsigned char *headermac, *ctmac;
+   unsigned long x, len;
+
+   LTC_ARGCHK(eax    != NULL);
+   LTC_ARGCHK(tag    != NULL);
+   LTC_ARGCHK(taglen != NULL);
+
+   /* allocate ram */
+   headermac = XMALLOC(MAXBLOCKSIZE);
+   ctmac     = XMALLOC(MAXBLOCKSIZE);
+
+   if (headermac == NULL || ctmac == NULL) {
+      if (headermac != NULL) {
+         XFREE(headermac);
+      }
+      if (ctmac != NULL) {
+         XFREE(ctmac);
+      }
+      return CRYPT_MEM;
+   }
+
+   /* finish ctomac */
+   len = MAXBLOCKSIZE;
+   if ((err = omac_done(&eax->ctomac, ctmac, &len)) != CRYPT_OK) {
+      goto LBL_ERR;
+   }
+
+   /* finish headeromac */
+
+   /* note we specifically don't reset len so the two lens are minimal */
+
+   if ((err = omac_done(&eax->headeromac, headermac, &len)) != CRYPT_OK) {
+      goto LBL_ERR;
+   }
+
+   /* terminate the CTR chain */
+   if ((err = ctr_done(&eax->ctr)) != CRYPT_OK) {
+      goto LBL_ERR;
+   }
+
+   /* compute N xor H xor C */
+   for (x = 0; x < len && x < *taglen; x++) {
+       tag[x] = eax->N[x] ^ headermac[x] ^ ctmac[x];
+   }
+   *taglen = x;
+
+   err = CRYPT_OK;
+LBL_ERR:
+#ifdef LTC_CLEAN_STACK
+   zeromem(ctmac,     MAXBLOCKSIZE);
+   zeromem(headermac, MAXBLOCKSIZE);
+   zeromem(eax,       sizeof(*eax));
+#endif
+
+   XFREE(ctmac);
+   XFREE(headermac);
+
+   return err;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/encauth/eax/eax_encrypt.c b/libtomcrypt/src/encauth/eax/eax_encrypt.c
new file mode 100644 (file)
index 0000000..174f263
--- /dev/null
@@ -0,0 +1,49 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+/**
+   @file eax_encrypt.c
+   EAX implementation, encrypt block by Tom St Denis
+*/
+#include "tomcrypt.h"
+
+#ifdef LTC_EAX_MODE
+
+/**
+   Encrypt with EAX a block of data.
+   @param eax        The EAX state
+   @param pt         The plaintext to encrypt
+   @param ct         [out] The ciphertext as encrypted
+   @param length     The length of the plaintext (octets)
+   @return CRYPT_OK if successful
+*/
+int eax_encrypt(eax_state *eax, const unsigned char *pt, unsigned char *ct,
+                unsigned long length)
+{
+   int err;
+
+   LTC_ARGCHK(eax != NULL);
+   LTC_ARGCHK(pt  != NULL);
+   LTC_ARGCHK(ct  != NULL);
+
+   /* encrypt */
+   if ((err = ctr_encrypt(pt, ct, length, &eax->ctr)) != CRYPT_OK) {
+      return err;
+   }
+
+   /* omac ciphertext */
+   return omac_process(&eax->ctomac, ct, length);
+}
+
+#endif
+
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/encauth/eax/eax_encrypt_authenticate_memory.c b/libtomcrypt/src/encauth/eax/eax_encrypt_authenticate_memory.c
new file mode 100644 (file)
index 0000000..9980fc0
--- /dev/null
@@ -0,0 +1,80 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+/**
+  @file eax_encrypt_authenticate_memory.c
+  EAX implementation, encrypt a block of memory, by Tom St Denis
+*/
+#include "tomcrypt.h"
+
+#ifdef LTC_EAX_MODE
+
+/**
+   EAX encrypt and produce an authentication tag
+   @param cipher     The index of the cipher desired
+   @param key        The secret key to use
+   @param keylen     The length of the secret key (octets)
+   @param nonce      The session nonce [use once]
+   @param noncelen   The length of the nonce
+   @param header     The header for the session
+   @param headerlen  The length of the header (octets)
+   @param pt         The plaintext
+   @param ptlen      The length of the plaintext (octets)
+   @param ct         [out] The ciphertext
+   @param tag        [out] The destination tag
+   @param taglen     [in/out] The max size and resulting size of the authentication tag
+   @return CRYPT_OK if successful
+*/
+int eax_encrypt_authenticate_memory(int cipher,
+    const unsigned char *key,    unsigned long keylen,
+    const unsigned char *nonce,  unsigned long noncelen,
+    const unsigned char *header, unsigned long headerlen,
+    const unsigned char *pt,     unsigned long ptlen,
+          unsigned char *ct,
+          unsigned char *tag,    unsigned long *taglen)
+{
+   int err;
+   eax_state *eax;
+
+   LTC_ARGCHK(key    != NULL);
+   LTC_ARGCHK(pt     != NULL);
+   LTC_ARGCHK(ct     != NULL);
+   LTC_ARGCHK(tag    != NULL);
+   LTC_ARGCHK(taglen != NULL);
+
+   eax = XMALLOC(sizeof(*eax));
+
+   if ((err = eax_init(eax, cipher, key, keylen, nonce, noncelen, header, headerlen)) != CRYPT_OK) {
+      goto LBL_ERR;
+   }
+
+   if ((err = eax_encrypt(eax, pt, ct, ptlen)) != CRYPT_OK) {
+      goto LBL_ERR;
+   }
+
+   if ((err = eax_done(eax, tag, taglen)) != CRYPT_OK) {
+      goto LBL_ERR;
+   }
+
+   err = CRYPT_OK;
+LBL_ERR:
+#ifdef LTC_CLEAN_STACK
+   zeromem(eax, sizeof(*eax));
+#endif
+
+   XFREE(eax);
+
+   return err;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/encauth/eax/eax_init.c b/libtomcrypt/src/encauth/eax/eax_init.c
new file mode 100644 (file)
index 0000000..154d7a9
--- /dev/null
@@ -0,0 +1,142 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+/**
+   @file eax_init.c
+   EAX implementation, initialized EAX state, by Tom St Denis
+*/
+#include "tomcrypt.h"
+
+#ifdef LTC_EAX_MODE
+
+/**
+   Initialized an EAX state
+   @param eax       [out] The EAX state to initialize
+   @param cipher    The index of the desired cipher
+   @param key       The secret key
+   @param keylen    The length of the secret key (octets)
+   @param nonce     The use-once nonce for the session
+   @param noncelen  The length of the nonce (octets)
+   @param header    The header for the EAX state
+   @param headerlen The header length (octets)
+   @return CRYPT_OK if successful
+*/
+int eax_init(eax_state *eax, int cipher,
+             const unsigned char *key,    unsigned long keylen,
+             const unsigned char *nonce,  unsigned long noncelen,
+             const unsigned char *header, unsigned long headerlen)
+{
+   unsigned char *buf;
+   int           err, blklen;
+   omac_state    *omac;
+   unsigned long len;
+
+
+   LTC_ARGCHK(eax   != NULL);
+   LTC_ARGCHK(key   != NULL);
+   LTC_ARGCHK(nonce != NULL);
+   if (headerlen > 0) {
+      LTC_ARGCHK(header != NULL);
+   }
+
+   if ((err = cipher_is_valid(cipher)) != CRYPT_OK) {
+      return err;
+   }
+   blklen = cipher_descriptor[cipher].block_length;
+
+   /* allocate ram */
+   buf  = XMALLOC(MAXBLOCKSIZE);
+   omac = XMALLOC(sizeof(*omac));
+
+   if (buf == NULL || omac == NULL) {
+      if (buf != NULL) {
+         XFREE(buf);
+      }
+      if (omac != NULL) {
+         XFREE(omac);
+      }
+      return CRYPT_MEM;
+   }
+
+   /* N = LTC_OMAC_0K(nonce) */
+   zeromem(buf, MAXBLOCKSIZE);
+   if ((err = omac_init(omac, cipher, key, keylen)) != CRYPT_OK) {
+      goto LBL_ERR;
+   }
+
+   /* omac the [0]_n */
+   if ((err = omac_process(omac, buf, blklen)) != CRYPT_OK) {
+      goto LBL_ERR;
+   }
+   /* omac the nonce */
+   if ((err = omac_process(omac, nonce, noncelen)) != CRYPT_OK) {
+      goto LBL_ERR;
+   }
+   /* store result */
+   len = sizeof(eax->N);
+   if ((err = omac_done(omac, eax->N, &len)) != CRYPT_OK) {
+      goto LBL_ERR;
+   }
+
+   /* H = LTC_OMAC_1K(header) */
+   zeromem(buf, MAXBLOCKSIZE);
+   buf[blklen - 1] = 1;
+
+   if ((err = omac_init(&eax->headeromac, cipher, key, keylen)) != CRYPT_OK) {
+      goto LBL_ERR;
+   }
+
+   /* omac the [1]_n */
+   if ((err = omac_process(&eax->headeromac, buf, blklen)) != CRYPT_OK) {
+      goto LBL_ERR;
+   }
+   /* omac the header */
+   if (headerlen != 0) {
+      if ((err = omac_process(&eax->headeromac, header, headerlen)) != CRYPT_OK) {
+          goto LBL_ERR;
+      }
+   }
+
+   /* note we don't finish the headeromac, this allows us to add more header later */
+
+   /* setup the CTR mode */
+   if ((err = ctr_start(cipher, eax->N, key, keylen, 0, CTR_COUNTER_BIG_ENDIAN, &eax->ctr)) != CRYPT_OK) {
+      goto LBL_ERR;
+   }
+
+   /* setup the LTC_OMAC for the ciphertext */
+   if ((err = omac_init(&eax->ctomac, cipher, key, keylen)) != CRYPT_OK) {
+      goto LBL_ERR;
+   }
+
+   /* omac [2]_n */
+   zeromem(buf, MAXBLOCKSIZE);
+   buf[blklen-1] = 2;
+   if ((err = omac_process(&eax->ctomac, buf, blklen)) != CRYPT_OK) {
+      goto LBL_ERR;
+   }
+
+   err = CRYPT_OK;
+LBL_ERR:
+#ifdef LTC_CLEAN_STACK
+   zeromem(buf,  MAXBLOCKSIZE);
+   zeromem(omac, sizeof(*omac));
+#endif
+
+   XFREE(omac);
+   XFREE(buf);
+
+   return err;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/encauth/eax/eax_test.c b/libtomcrypt/src/encauth/eax/eax_test.c
new file mode 100644 (file)
index 0000000..7d29ee7
--- /dev/null
@@ -0,0 +1,259 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+/**
+    @file eax_test.c
+    EAX implementation, self-test, by Tom St Denis
+*/
+#include "tomcrypt.h"
+
+#ifdef LTC_EAX_MODE
+
+/**
+   Test the EAX implementation
+   @return CRYPT_OK if successful, CRYPT_NOP if self-testing has been disabled
+*/
+int eax_test(void)
+{
+#ifndef LTC_TEST
+   return CRYPT_NOP;
+#else
+   static const struct {
+       int               keylen,
+                       noncelen,
+                      headerlen,
+                         msglen;
+
+       unsigned char        key[MAXBLOCKSIZE],
+                          nonce[MAXBLOCKSIZE],
+                         header[MAXBLOCKSIZE],
+                      plaintext[MAXBLOCKSIZE],
+                     ciphertext[MAXBLOCKSIZE],
+                            tag[MAXBLOCKSIZE];
+   } tests[] = {
+
+/* NULL message */
+{
+   16, 0, 0, 0,
+   /* key */
+   { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+     0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f },
+   /* nonce */
+   { 0 },
+   /* header */
+   { 0 },
+   /* plaintext */
+   { 0 },
+   /* ciphertext */
+   { 0 },
+   /* tag */
+   { 0x9a, 0xd0, 0x7e, 0x7d, 0xbf, 0xf3, 0x01, 0xf5,
+     0x05, 0xde, 0x59, 0x6b, 0x96, 0x15, 0xdf, 0xff }
+},
+
+/* test with nonce */
+{
+   16, 16, 0, 0,
+   /* key */
+   { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+     0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f },
+   /* nonce */
+   { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+     0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f },
+   /* header */
+   { 0 },
+   /* plaintext */
+   { 0 },
+   /* ciphertext */
+   { 0 },
+   /* tag */
+   { 0x1c, 0xe1, 0x0d, 0x3e, 0xff, 0xd4, 0xca, 0xdb,
+     0xe2, 0xe4, 0x4b, 0x58, 0xd6, 0x0a, 0xb9, 0xec }
+},
+
+/* test with header [no nonce]  */
+{
+   16, 0, 16, 0,
+   /* key */
+   { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+     0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f },
+   /* nonce */
+   { 0 },
+   /* header */
+   { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+     0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f },
+   /* plaintext */
+   { 0 },
+   /* ciphertext */
+   { 0 },
+   /* tag */
+   { 0x3a, 0x69, 0x8f, 0x7a, 0x27, 0x0e, 0x51, 0xb0,
+     0xf6, 0x5b, 0x3d, 0x3e, 0x47, 0x19, 0x3c, 0xff }
+},
+
+/* test with header + nonce + plaintext */
+{
+   16, 16, 16, 32,
+   /* key */
+   { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+     0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f },
+   /* nonce */
+   { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+     0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f },
+   /* header */
+   { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+     0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f },
+   /* plaintext */
+   { 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 },
+   /* ciphertext */
+   { 0x29, 0xd8, 0x78, 0xd1, 0xa3, 0xbe, 0x85, 0x7b,
+     0x6f, 0xb8, 0xc8, 0xea, 0x59, 0x50, 0xa7, 0x78,
+     0x33, 0x1f, 0xbf, 0x2c, 0xcf, 0x33, 0x98, 0x6f,
+     0x35, 0xe8, 0xcf, 0x12, 0x1d, 0xcb, 0x30, 0xbc },
+   /* tag */
+   { 0x4f, 0xbe, 0x03, 0x38, 0xbe, 0x1c, 0x8c, 0x7e,
+     0x1d, 0x7a, 0xe7, 0xe4, 0x5b, 0x92, 0xc5, 0x87 }
+},
+
+/* test with header + nonce + plaintext [not even sizes!] */
+{
+   16, 15, 14, 29,
+   /* key */
+   { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+     0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f },
+   /* nonce */
+   { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+     0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e },
+   /* header */
+   { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+     0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d },
+   /* plaintext */
+   { 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 },
+   /* ciphertext */
+   { 0xdd, 0x25, 0xc7, 0x54, 0xc5, 0xb1, 0x7c, 0x59,
+     0x28, 0xb6, 0x9b, 0x73, 0x15, 0x5f, 0x7b, 0xb8,
+     0x88, 0x8f, 0xaf, 0x37, 0x09, 0x1a, 0xd9, 0x2c,
+     0x8a, 0x24, 0xdb, 0x86, 0x8b },
+   /* tag */
+   { 0x0d, 0x1a, 0x14, 0xe5, 0x22, 0x24, 0xff, 0xd2,
+     0x3a, 0x05, 0xfa, 0x02, 0xcd, 0xef, 0x52, 0xda }
+},
+
+/* Vectors from Brian Gladman */
+
+{
+   16, 16, 8, 0,
+   /* key */
+   { 0x23, 0x39, 0x52, 0xde, 0xe4, 0xd5, 0xed, 0x5f,
+     0x9b, 0x9c, 0x6d, 0x6f, 0xf8, 0x0f, 0xf4, 0x78 },
+   /* nonce */
+   { 0x62, 0xec, 0x67, 0xf9, 0xc3, 0xa4, 0xa4, 0x07,
+     0xfc, 0xb2, 0xa8, 0xc4, 0x90, 0x31, 0xa8, 0xb3 },
+   /* header */
+   { 0x6b, 0xfb, 0x91, 0x4f, 0xd0, 0x7e, 0xae, 0x6b },
+   /* PT */
+   { 0x00 },
+   /* CT */
+   { 0x00 },
+   /* tag */
+   { 0xe0, 0x37, 0x83, 0x0e, 0x83, 0x89, 0xf2, 0x7b,
+     0x02, 0x5a, 0x2d, 0x65, 0x27, 0xe7, 0x9d, 0x01 }
+},
+
+{
+   16, 16, 8, 2,
+   /* key */
+   { 0x91, 0x94, 0x5d, 0x3f, 0x4d, 0xcb, 0xee, 0x0b,
+     0xf4, 0x5e, 0xf5, 0x22, 0x55, 0xf0, 0x95, 0xa4 },
+   /* nonce */
+   { 0xbe, 0xca, 0xf0, 0x43, 0xb0, 0xa2, 0x3d, 0x84,
+     0x31, 0x94, 0xba, 0x97, 0x2c, 0x66, 0xde, 0xbd },
+   /* header */
+   { 0xfa, 0x3b, 0xfd, 0x48, 0x06, 0xeb, 0x53, 0xfa },
+   /* PT */
+   { 0xf7, 0xfb },
+   /* CT */
+   { 0x19, 0xdd },
+   /* tag */
+   { 0x5c, 0x4c, 0x93, 0x31, 0x04, 0x9d, 0x0b, 0xda,
+     0xb0, 0x27, 0x74, 0x08, 0xf6, 0x79, 0x67, 0xe5 }
+},
+
+{
+   16, 16, 8, 5,
+   /* key */
+   { 0x01, 0xf7, 0x4a, 0xd6, 0x40, 0x77, 0xf2, 0xe7,
+     0x04, 0xc0, 0xf6, 0x0a, 0xda, 0x3d, 0xd5, 0x23 },
+   /* nonce */
+   { 0x70, 0xc3, 0xdb, 0x4f, 0x0d, 0x26, 0x36, 0x84,
+     0x00, 0xa1, 0x0e, 0xd0, 0x5d, 0x2b, 0xff, 0x5e },
+   /* header */
+   { 0x23, 0x4a, 0x34, 0x63, 0xc1, 0x26, 0x4a, 0xc6 },
+   /* PT */
+   { 0x1a, 0x47, 0xcb, 0x49, 0x33 },
+   /* CT */
+   { 0xd8, 0x51, 0xd5, 0xba, 0xe0 },
+   /* Tag */
+   { 0x3a, 0x59, 0xf2, 0x38, 0xa2, 0x3e, 0x39, 0x19,
+     0x9d, 0xc9, 0x26, 0x66, 0x26, 0xc4, 0x0f, 0x80 }
+}
+
+};
+   int err, x, idx, res;
+   unsigned long len;
+   unsigned char outct[MAXBLOCKSIZE], outtag[MAXBLOCKSIZE];
+
+    /* AES can be under rijndael or aes... try to find it */
+    if ((idx = find_cipher("aes")) == -1) {
+       if ((idx = find_cipher("rijndael")) == -1) {
+          return CRYPT_NOP;
+       }
+    }
+
+    for (x = 0; x < (int)(sizeof(tests)/sizeof(tests[0])); x++) {
+        len = sizeof(outtag);
+        if ((err = eax_encrypt_authenticate_memory(idx, tests[x].key, tests[x].keylen,
+            tests[x].nonce, tests[x].noncelen, tests[x].header, tests[x].headerlen,
+            tests[x].plaintext, tests[x].msglen, outct, outtag, &len)) != CRYPT_OK) {
+           return err;
+        }
+        if (compare_testvector(outtag, len, tests[x].tag, len, "EAX Tag", x) ||
+              compare_testvector(outct, tests[x].msglen, tests[x].ciphertext, tests[x].msglen, "EAX CT", x)) {
+           return CRYPT_FAIL_TESTVECTOR;
+        }
+
+        /* test decrypt */
+        if ((err = eax_decrypt_verify_memory(idx, tests[x].key, tests[x].keylen,
+             tests[x].nonce, tests[x].noncelen, tests[x].header, tests[x].headerlen,
+             outct, tests[x].msglen, outct, outtag, len, &res)) != CRYPT_OK) {
+            return err;
+        }
+        if ((res != 1) || compare_testvector(outct, tests[x].msglen, tests[x].plaintext, tests[x].msglen, "EAX", x)) {
+#ifdef LTC_TEST_DBG
+           printf("\n\nEAX: Failure-decrypt - res = %d\n", res);
+#endif
+           return CRYPT_FAIL_TESTVECTOR;
+        }
+
+    }
+    return CRYPT_OK;
+#endif /* LTC_TEST */
+}
+
+#endif /* LTC_EAX_MODE */
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/encauth/gcm/gcm_add_aad.c b/libtomcrypt/src/encauth/gcm/gcm_add_aad.c
new file mode 100644 (file)
index 0000000..cacc15b
--- /dev/null
@@ -0,0 +1,124 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+/**
+   @file gcm_add_aad.c
+   GCM implementation, Add AAD data to the stream, by Tom St Denis
+*/
+#include "tomcrypt.h"
+
+#ifdef LTC_GCM_MODE
+
+/**
+  Add AAD to the GCM state
+  @param gcm       The GCM state
+  @param adata     The additional authentication data to add to the GCM state
+  @param adatalen  The length of the AAD data.
+  @return CRYPT_OK on success
+ */
+int gcm_add_aad(gcm_state *gcm,
+               const unsigned char *adata,  unsigned long adatalen)
+{
+   unsigned long x;
+   int           err;
+#ifdef LTC_FAST
+   unsigned long y;
+#endif
+
+   LTC_ARGCHK(gcm    != NULL);
+   if (adatalen > 0) {
+      LTC_ARGCHK(adata  != NULL);
+   }
+
+   if (gcm->buflen > 16 || gcm->buflen < 0) {
+      return CRYPT_INVALID_ARG;
+   }
+
+   if ((err = cipher_is_valid(gcm->cipher)) != CRYPT_OK) {
+      return err;
+   }
+
+   /* in IV mode? */
+   if (gcm->mode == LTC_GCM_MODE_IV) {
+      /* IV length must be > 0 */
+      if (gcm->buflen == 0 && gcm->totlen == 0) return CRYPT_ERROR;
+      /* let's process the IV */
+      if (gcm->ivmode || gcm->buflen != 12) {
+         for (x = 0; x < (unsigned long)gcm->buflen; x++) {
+             gcm->X[x] ^= gcm->buf[x];
+         }
+         if (gcm->buflen) {
+            gcm->totlen += gcm->buflen * CONST64(8);
+            gcm_mult_h(gcm, gcm->X);
+         }
+
+         /* mix in the length */
+         zeromem(gcm->buf, 8);
+         STORE64H(gcm->totlen, gcm->buf+8);
+         for (x = 0; x < 16; x++) {
+             gcm->X[x] ^= gcm->buf[x];
+         }
+         gcm_mult_h(gcm, gcm->X);
+
+         /* copy counter out */
+         XMEMCPY(gcm->Y, gcm->X, 16);
+         zeromem(gcm->X, 16);
+      } else {
+         XMEMCPY(gcm->Y, gcm->buf, 12);
+         gcm->Y[12] = 0;
+         gcm->Y[13] = 0;
+         gcm->Y[14] = 0;
+         gcm->Y[15] = 1;
+      }
+      XMEMCPY(gcm->Y_0, gcm->Y, 16);
+      zeromem(gcm->buf, 16);
+      gcm->buflen = 0;
+      gcm->totlen = 0;
+      gcm->mode   = LTC_GCM_MODE_AAD;
+   }
+
+   if (gcm->mode != LTC_GCM_MODE_AAD || gcm->buflen >= 16) {
+      return CRYPT_INVALID_ARG;
+   }
+
+   x = 0;
+#ifdef LTC_FAST
+   if (gcm->buflen == 0) {
+      for (x = 0; x < (adatalen & ~15); x += 16) {
+          for (y = 0; y < 16; y += sizeof(LTC_FAST_TYPE)) {
+              *(LTC_FAST_TYPE_PTR_CAST(&gcm->X[y])) ^= *(LTC_FAST_TYPE_PTR_CAST(&adata[x + y]));
+          }
+          gcm_mult_h(gcm, gcm->X);
+          gcm->totlen += 128;
+      }
+      adata += x;
+   }
+#endif
+
+
+   /* start adding AAD data to the state */
+   for (; x < adatalen; x++) {
+      gcm->X[gcm->buflen++] ^= *adata++;
+
+      if (gcm->buflen == 16) {
+         /* GF mult it */
+         gcm_mult_h(gcm, gcm->X);
+         gcm->buflen = 0;
+         gcm->totlen += 128;
+      }
+   }
+
+   return CRYPT_OK;
+}
+#endif
+
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/encauth/gcm/gcm_add_iv.c b/libtomcrypt/src/encauth/gcm/gcm_add_iv.c
new file mode 100644 (file)
index 0000000..3fd3861
--- /dev/null
@@ -0,0 +1,92 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+/**
+   @file gcm_add_iv.c
+   GCM implementation, add IV data to the state, by Tom St Denis
+*/
+#include "tomcrypt.h"
+
+#ifdef LTC_GCM_MODE
+
+/**
+  Add IV data to the GCM state
+  @param gcm    The GCM state
+  @param IV     The initial value data to add
+  @param IVlen  The length of the IV
+  @return CRYPT_OK on success
+ */
+int gcm_add_iv(gcm_state *gcm,
+               const unsigned char *IV,     unsigned long IVlen)
+{
+   unsigned long x, y;
+   int           err;
+
+   LTC_ARGCHK(gcm != NULL);
+   if (IVlen > 0) {
+      LTC_ARGCHK(IV  != NULL);
+   }
+
+   /* must be in IV mode */
+   if (gcm->mode != LTC_GCM_MODE_IV) {
+      return CRYPT_INVALID_ARG;
+   }
+
+   if (gcm->buflen >= 16 || gcm->buflen < 0) {
+      return CRYPT_INVALID_ARG;
+   }
+
+   if ((err = cipher_is_valid(gcm->cipher)) != CRYPT_OK) {
+      return err;
+   }
+
+
+   /* trip the ivmode flag */
+   if (IVlen + gcm->buflen > 12) {
+      gcm->ivmode |= 1;
+   }
+
+   x = 0;
+#ifdef LTC_FAST
+   if (gcm->buflen == 0) {
+      for (x = 0; x < (IVlen & ~15); x += 16) {
+          for (y = 0; y < 16; y += sizeof(LTC_FAST_TYPE)) {
+              *(LTC_FAST_TYPE_PTR_CAST(&gcm->X[y])) ^= *(LTC_FAST_TYPE_PTR_CAST(&IV[x + y]));
+          }
+          gcm_mult_h(gcm, gcm->X);
+          gcm->totlen += 128;
+      }
+      IV += x;
+   }
+#endif
+
+   /* start adding IV data to the state */
+   for (; x < IVlen; x++) {
+       gcm->buf[gcm->buflen++] = *IV++;
+
+      if (gcm->buflen == 16) {
+         /* GF mult it */
+         for (y = 0; y < 16; y++) {
+             gcm->X[y] ^= gcm->buf[y];
+         }
+         gcm_mult_h(gcm, gcm->X);
+         gcm->buflen = 0;
+         gcm->totlen += 128;
+      }
+   }
+
+   return CRYPT_OK;
+}
+
+#endif
+
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/encauth/gcm/gcm_done.c b/libtomcrypt/src/encauth/gcm/gcm_done.c
new file mode 100644 (file)
index 0000000..ffd551e
--- /dev/null
@@ -0,0 +1,90 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+/**
+   @file gcm_done.c
+   GCM implementation, Terminate the stream, by Tom St Denis
+*/
+#include "tomcrypt.h"
+
+#ifdef LTC_GCM_MODE
+
+/**
+  Terminate a GCM stream
+  @param gcm     The GCM state
+  @param tag     [out] The destination for the MAC tag
+  @param taglen  [in/out]  The length of the MAC tag
+  @return CRYPT_OK on success
+ */
+int gcm_done(gcm_state *gcm,
+                     unsigned char *tag,    unsigned long *taglen)
+{
+   unsigned long x;
+   int err;
+
+   LTC_ARGCHK(gcm     != NULL);
+   LTC_ARGCHK(tag     != NULL);
+   LTC_ARGCHK(taglen  != NULL);
+
+   if (gcm->buflen > 16 || gcm->buflen < 0) {
+      return CRYPT_INVALID_ARG;
+   }
+
+   if ((err = cipher_is_valid(gcm->cipher)) != CRYPT_OK) {
+      return err;
+   }
+
+   if (gcm->mode == LTC_GCM_MODE_IV) {
+      /* let's process the IV */
+      if ((err = gcm_add_aad(gcm, NULL, 0)) != CRYPT_OK) return err;
+   }
+
+   if (gcm->mode == LTC_GCM_MODE_AAD) {
+      /* let's process the AAD */
+      if ((err = gcm_process(gcm, NULL, 0, NULL, 0)) != CRYPT_OK) return err;
+   }
+
+   if (gcm->mode != LTC_GCM_MODE_TEXT) {
+      return CRYPT_INVALID_ARG;
+   }
+
+   /* handle remaining ciphertext */
+   if (gcm->buflen) {
+      gcm->pttotlen += gcm->buflen * CONST64(8);
+      gcm_mult_h(gcm, gcm->X);
+   }
+
+   /* length */
+   STORE64H(gcm->totlen, gcm->buf);
+   STORE64H(gcm->pttotlen, gcm->buf+8);
+   for (x = 0; x < 16; x++) {
+       gcm->X[x] ^= gcm->buf[x];
+   }
+   gcm_mult_h(gcm, gcm->X);
+
+   /* encrypt original counter */
+   if ((err = cipher_descriptor[gcm->cipher].ecb_encrypt(gcm->Y_0, gcm->buf, &gcm->K)) != CRYPT_OK) {
+      return err;
+   }
+   for (x = 0; x < 16 && x < *taglen; x++) {
+       tag[x] = gcm->buf[x] ^ gcm->X[x];
+   }
+   *taglen = x;
+
+   cipher_descriptor[gcm->cipher].done(&gcm->K);
+
+   return CRYPT_OK;
+}
+
+#endif
+
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/encauth/gcm/gcm_gf_mult.c b/libtomcrypt/src/encauth/gcm/gcm_gf_mult.c
new file mode 100644 (file)
index 0000000..2e7a906
--- /dev/null
@@ -0,0 +1,219 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+/**
+   @file gcm_gf_mult.c
+   GCM implementation, do the GF mult, by Tom St Denis
+*/
+#include "tomcrypt.h"
+
+#if defined(LTC_GCM_TABLES) || defined(LTC_LRW_TABLES) || ((defined(LTC_GCM_MODE) || defined(LTC_GCM_MODE)) && defined(LTC_FAST))
+
+/* this is x*2^128 mod p(x) ... the results are 16 bytes each stored in a packed format.  Since only the
+ * lower 16 bits are not zero'ed I removed the upper 14 bytes */
+const unsigned char gcm_shift_table[256*2] = {
+0x00, 0x00, 0x01, 0xc2, 0x03, 0x84, 0x02, 0x46, 0x07, 0x08, 0x06, 0xca, 0x04, 0x8c, 0x05, 0x4e,
+0x0e, 0x10, 0x0f, 0xd2, 0x0d, 0x94, 0x0c, 0x56, 0x09, 0x18, 0x08, 0xda, 0x0a, 0x9c, 0x0b, 0x5e,
+0x1c, 0x20, 0x1d, 0xe2, 0x1f, 0xa4, 0x1e, 0x66, 0x1b, 0x28, 0x1a, 0xea, 0x18, 0xac, 0x19, 0x6e,
+0x12, 0x30, 0x13, 0xf2, 0x11, 0xb4, 0x10, 0x76, 0x15, 0x38, 0x14, 0xfa, 0x16, 0xbc, 0x17, 0x7e,
+0x38, 0x40, 0x39, 0x82, 0x3b, 0xc4, 0x3a, 0x06, 0x3f, 0x48, 0x3e, 0x8a, 0x3c, 0xcc, 0x3d, 0x0e,
+0x36, 0x50, 0x37, 0x92, 0x35, 0xd4, 0x34, 0x16, 0x31, 0x58, 0x30, 0x9a, 0x32, 0xdc, 0x33, 0x1e,
+0x24, 0x60, 0x25, 0xa2, 0x27, 0xe4, 0x26, 0x26, 0x23, 0x68, 0x22, 0xaa, 0x20, 0xec, 0x21, 0x2e,
+0x2a, 0x70, 0x2b, 0xb2, 0x29, 0xf4, 0x28, 0x36, 0x2d, 0x78, 0x2c, 0xba, 0x2e, 0xfc, 0x2f, 0x3e,
+0x70, 0x80, 0x71, 0x42, 0x73, 0x04, 0x72, 0xc6, 0x77, 0x88, 0x76, 0x4a, 0x74, 0x0c, 0x75, 0xce,
+0x7e, 0x90, 0x7f, 0x52, 0x7d, 0x14, 0x7c, 0xd6, 0x79, 0x98, 0x78, 0x5a, 0x7a, 0x1c, 0x7b, 0xde,
+0x6c, 0xa0, 0x6d, 0x62, 0x6f, 0x24, 0x6e, 0xe6, 0x6b, 0xa8, 0x6a, 0x6a, 0x68, 0x2c, 0x69, 0xee,
+0x62, 0xb0, 0x63, 0x72, 0x61, 0x34, 0x60, 0xf6, 0x65, 0xb8, 0x64, 0x7a, 0x66, 0x3c, 0x67, 0xfe,
+0x48, 0xc0, 0x49, 0x02, 0x4b, 0x44, 0x4a, 0x86, 0x4f, 0xc8, 0x4e, 0x0a, 0x4c, 0x4c, 0x4d, 0x8e,
+0x46, 0xd0, 0x47, 0x12, 0x45, 0x54, 0x44, 0x96, 0x41, 0xd8, 0x40, 0x1a, 0x42, 0x5c, 0x43, 0x9e,
+0x54, 0xe0, 0x55, 0x22, 0x57, 0x64, 0x56, 0xa6, 0x53, 0xe8, 0x52, 0x2a, 0x50, 0x6c, 0x51, 0xae,
+0x5a, 0xf0, 0x5b, 0x32, 0x59, 0x74, 0x58, 0xb6, 0x5d, 0xf8, 0x5c, 0x3a, 0x5e, 0x7c, 0x5f, 0xbe,
+0xe1, 0x00, 0xe0, 0xc2, 0xe2, 0x84, 0xe3, 0x46, 0xe6, 0x08, 0xe7, 0xca, 0xe5, 0x8c, 0xe4, 0x4e,
+0xef, 0x10, 0xee, 0xd2, 0xec, 0x94, 0xed, 0x56, 0xe8, 0x18, 0xe9, 0xda, 0xeb, 0x9c, 0xea, 0x5e,
+0xfd, 0x20, 0xfc, 0xe2, 0xfe, 0xa4, 0xff, 0x66, 0xfa, 0x28, 0xfb, 0xea, 0xf9, 0xac, 0xf8, 0x6e,
+0xf3, 0x30, 0xf2, 0xf2, 0xf0, 0xb4, 0xf1, 0x76, 0xf4, 0x38, 0xf5, 0xfa, 0xf7, 0xbc, 0xf6, 0x7e,
+0xd9, 0x40, 0xd8, 0x82, 0xda, 0xc4, 0xdb, 0x06, 0xde, 0x48, 0xdf, 0x8a, 0xdd, 0xcc, 0xdc, 0x0e,
+0xd7, 0x50, 0xd6, 0x92, 0xd4, 0xd4, 0xd5, 0x16, 0xd0, 0x58, 0xd1, 0x9a, 0xd3, 0xdc, 0xd2, 0x1e,
+0xc5, 0x60, 0xc4, 0xa2, 0xc6, 0xe4, 0xc7, 0x26, 0xc2, 0x68, 0xc3, 0xaa, 0xc1, 0xec, 0xc0, 0x2e,
+0xcb, 0x70, 0xca, 0xb2, 0xc8, 0xf4, 0xc9, 0x36, 0xcc, 0x78, 0xcd, 0xba, 0xcf, 0xfc, 0xce, 0x3e,
+0x91, 0x80, 0x90, 0x42, 0x92, 0x04, 0x93, 0xc6, 0x96, 0x88, 0x97, 0x4a, 0x95, 0x0c, 0x94, 0xce,
+0x9f, 0x90, 0x9e, 0x52, 0x9c, 0x14, 0x9d, 0xd6, 0x98, 0x98, 0x99, 0x5a, 0x9b, 0x1c, 0x9a, 0xde,
+0x8d, 0xa0, 0x8c, 0x62, 0x8e, 0x24, 0x8f, 0xe6, 0x8a, 0xa8, 0x8b, 0x6a, 0x89, 0x2c, 0x88, 0xee,
+0x83, 0xb0, 0x82, 0x72, 0x80, 0x34, 0x81, 0xf6, 0x84, 0xb8, 0x85, 0x7a, 0x87, 0x3c, 0x86, 0xfe,
+0xa9, 0xc0, 0xa8, 0x02, 0xaa, 0x44, 0xab, 0x86, 0xae, 0xc8, 0xaf, 0x0a, 0xad, 0x4c, 0xac, 0x8e,
+0xa7, 0xd0, 0xa6, 0x12, 0xa4, 0x54, 0xa5, 0x96, 0xa0, 0xd8, 0xa1, 0x1a, 0xa3, 0x5c, 0xa2, 0x9e,
+0xb5, 0xe0, 0xb4, 0x22, 0xb6, 0x64, 0xb7, 0xa6, 0xb2, 0xe8, 0xb3, 0x2a, 0xb1, 0x6c, 0xb0, 0xae,
+0xbb, 0xf0, 0xba, 0x32, 0xb8, 0x74, 0xb9, 0xb6, 0xbc, 0xf8, 0xbd, 0x3a, 0xbf, 0x7c, 0xbe, 0xbe };
+
+#endif
+
+
+#if defined(LTC_GCM_MODE) || defined(LRW_MODE)
+
+#ifndef LTC_FAST
+/* right shift */
+static void _gcm_rightshift(unsigned char *a)
+{
+   int x;
+   for (x = 15; x > 0; x--) {
+       a[x] = (a[x]>>1) | ((a[x-1]<<7)&0x80);
+   }
+   a[0] >>= 1;
+}
+
+/* c = b*a */
+static const unsigned char mask[] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 };
+static const unsigned char poly[] = { 0x00, 0xE1 };
+
+
+/**
+  GCM GF multiplier (internal use only)  bitserial
+  @param a   First value
+  @param b   Second value
+  @param c   Destination for a * b
+ */
+void gcm_gf_mult(const unsigned char *a, const unsigned char *b, unsigned char *c)
+{
+   unsigned char Z[16], V[16];
+   unsigned char x, y, z;
+
+   zeromem(Z, 16);
+   XMEMCPY(V, a, 16);
+   for (x = 0; x < 128; x++) {
+       if (b[x>>3] & mask[x&7]) {
+          for (y = 0; y < 16; y++) {
+              Z[y] ^= V[y];
+          }
+       }
+       z     = V[15] & 0x01;
+       _gcm_rightshift(V);
+       V[0] ^= poly[z];
+   }
+   XMEMCPY(c, Z, 16);
+}
+
+#else
+
+/* map normal numbers to "ieee" way ... e.g. bit reversed */
+#define M(x) ( ((x&8)>>3) | ((x&4)>>1) | ((x&2)<<1) | ((x&1)<<3) )
+
+#define BPD (sizeof(LTC_FAST_TYPE) * 8)
+#define WPV (1 + (16 / sizeof(LTC_FAST_TYPE)))
+
+/**
+  GCM GF multiplier (internal use only)  word oriented
+  @param a   First value
+  @param b   Second value
+  @param c   Destination for a * b
+ */
+void gcm_gf_mult(const unsigned char *a, const unsigned char *b, unsigned char *c)
+{
+   int i, j, k, u;
+   LTC_FAST_TYPE B[16][WPV], tmp[32 / sizeof(LTC_FAST_TYPE)], pB[16 / sizeof(LTC_FAST_TYPE)], zz, z;
+   unsigned char pTmp[32];
+
+   /* create simple tables */
+   zeromem(B[0],       sizeof(B[0]));
+   zeromem(B[M(1)],    sizeof(B[M(1)]));
+
+#ifdef ENDIAN_32BITWORD
+   for (i = 0; i < 4; i++) {
+       LOAD32H(B[M(1)][i], a + (i<<2));
+       LOAD32L(pB[i],      b + (i<<2));
+   }
+#else
+   for (i = 0; i < 2; i++) {
+       LOAD64H(B[M(1)][i], a + (i<<3));
+       LOAD64L(pB[i],      b + (i<<3));
+   }
+#endif
+
+   /* now create 2, 4 and 8 */
+   B[M(2)][0] = B[M(1)][0] >> 1;
+   B[M(4)][0] = B[M(1)][0] >> 2;
+   B[M(8)][0] = B[M(1)][0] >> 3;
+   for (i = 1; i < (int)WPV; i++) {
+      B[M(2)][i] = (B[M(1)][i-1] << (BPD-1)) | (B[M(1)][i] >> 1);
+      B[M(4)][i] = (B[M(1)][i-1] << (BPD-2)) | (B[M(1)][i] >> 2);
+      B[M(8)][i] = (B[M(1)][i-1] << (BPD-3)) | (B[M(1)][i] >> 3);
+   }
+
+   /*  now all values with two bits which are 3, 5, 6, 9, 10, 12 */
+   for (i = 0; i < (int)WPV; i++) {
+      B[M(3)][i]  = B[M(1)][i] ^ B[M(2)][i];
+      B[M(5)][i]  = B[M(1)][i] ^ B[M(4)][i];
+      B[M(6)][i]  = B[M(2)][i] ^ B[M(4)][i];
+      B[M(9)][i]  = B[M(1)][i] ^ B[M(8)][i];
+      B[M(10)][i] = B[M(2)][i] ^ B[M(8)][i];
+      B[M(12)][i] = B[M(8)][i] ^ B[M(4)][i];
+
+   /*  now all 3 bit values and the only 4 bit value: 7, 11, 13, 14, 15 */
+      B[M(7)][i]  = B[M(3)][i] ^ B[M(4)][i];
+      B[M(11)][i] = B[M(3)][i] ^ B[M(8)][i];
+      B[M(13)][i] = B[M(1)][i] ^ B[M(12)][i];
+      B[M(14)][i] = B[M(6)][i] ^ B[M(8)][i];
+      B[M(15)][i] = B[M(7)][i] ^ B[M(8)][i];
+   }
+
+   zeromem(tmp, sizeof(tmp));
+
+   /* compute product four bits of each word at a time */
+   /* for each nibble */
+   for (i = (BPD/4)-1; i >= 0; i--) {
+       /* for each word */
+       for (j = 0; j < (int)(WPV-1); j++) {
+        /* grab the 4 bits recall the nibbles are backwards so it's a shift by (i^1)*4 */
+           u = (pB[j] >> ((i^1)<<2)) & 15;
+
+        /* add offset by the word count the table looked up value to the result */
+           for (k = 0; k < (int)WPV; k++) {
+               tmp[k+j] ^= B[u][k];
+           }
+       }
+     /* shift result up by 4 bits */
+       if (i != 0) {
+          for (z = j = 0; j < (int)(32 / sizeof(LTC_FAST_TYPE)); j++) {
+              zz = tmp[j] << (BPD-4);
+              tmp[j] = (tmp[j] >> 4) | z;
+              z = zz;
+          }
+       }
+   }
+
+   /* store product */
+#ifdef ENDIAN_32BITWORD
+   for (i = 0; i < 8; i++) {
+       STORE32H(tmp[i], pTmp + (i<<2));
+   }
+#else
+   for (i = 0; i < 4; i++) {
+       STORE64H(tmp[i], pTmp + (i<<3));
+   }
+#endif
+
+   /* reduce by taking most significant byte and adding the appropriate two byte sequence 16 bytes down */
+   for (i = 31; i >= 16; i--) {
+       pTmp[i-16] ^= gcm_shift_table[((unsigned)pTmp[i]<<1)];
+       pTmp[i-15] ^= gcm_shift_table[((unsigned)pTmp[i]<<1)+1];
+   }
+
+   for (i = 0; i < 16; i++) {
+       c[i] = pTmp[i];
+   }
+
+}
+
+#endif
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
+
diff --git a/libtomcrypt/src/encauth/gcm/gcm_init.c b/libtomcrypt/src/encauth/gcm/gcm_init.c
new file mode 100644 (file)
index 0000000..072870d
--- /dev/null
@@ -0,0 +1,105 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+/**
+   @file gcm_init.c
+   GCM implementation, initialize state, by Tom St Denis
+*/
+#include "tomcrypt.h"
+
+#ifdef LTC_GCM_MODE
+
+/**
+  Initialize a GCM state
+  @param gcm     The GCM state to initialize
+  @param cipher  The index of the cipher to use
+  @param key     The secret key
+  @param keylen  The length of the secret key
+  @return CRYPT_OK on success
+ */
+int gcm_init(gcm_state *gcm, int cipher,
+             const unsigned char *key,  int keylen)
+{
+   int           err;
+   unsigned char B[16];
+#ifdef LTC_GCM_TABLES
+   int           x, y, z, t;
+#endif
+
+   LTC_ARGCHK(gcm != NULL);
+   LTC_ARGCHK(key != NULL);
+
+#ifdef LTC_FAST
+   if (16 % sizeof(LTC_FAST_TYPE)) {
+      return CRYPT_INVALID_ARG;
+   }
+#endif
+
+   /* is cipher valid? */
+   if ((err = cipher_is_valid(cipher)) != CRYPT_OK) {
+      return err;
+   }
+   if (cipher_descriptor[cipher].block_length != 16) {
+      return CRYPT_INVALID_CIPHER;
+   }
+
+   /* schedule key */
+   if ((err = cipher_descriptor[cipher].setup(key, keylen, 0, &gcm->K)) != CRYPT_OK) {
+      return err;
+   }
+
+   /* H = E(0) */
+   zeromem(B, 16);
+   if ((err = cipher_descriptor[cipher].ecb_encrypt(B, gcm->H, &gcm->K)) != CRYPT_OK) {
+      return err;
+   }
+
+   /* setup state */
+   zeromem(gcm->buf, sizeof(gcm->buf));
+   zeromem(gcm->X,   sizeof(gcm->X));
+   gcm->cipher   = cipher;
+   gcm->mode     = LTC_GCM_MODE_IV;
+   gcm->ivmode   = 0;
+   gcm->buflen   = 0;
+   gcm->totlen   = 0;
+   gcm->pttotlen = 0;
+
+#ifdef LTC_GCM_TABLES
+   /* setup tables */
+
+   /* generate the first table as it has no shifting (from which we make the other tables) */
+   zeromem(B, 16);
+   for (y = 0; y < 256; y++) {
+        B[0] = y;
+        gcm_gf_mult(gcm->H, B, &gcm->PC[0][y][0]);
+   }
+
+   /* now generate the rest of the tables based the previous table */
+   for (x = 1; x < 16; x++) {
+      for (y = 0; y < 256; y++) {
+         /* now shift it right by 8 bits */
+         t = gcm->PC[x-1][y][15];
+         for (z = 15; z > 0; z--) {
+             gcm->PC[x][y][z] = gcm->PC[x-1][y][z-1];
+         }
+         gcm->PC[x][y][0] = gcm_shift_table[t<<1];
+         gcm->PC[x][y][1] ^= gcm_shift_table[(t<<1)+1];
+      }
+   }
+
+#endif
+
+   return CRYPT_OK;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/encauth/gcm/gcm_memory.c b/libtomcrypt/src/encauth/gcm/gcm_memory.c
new file mode 100644 (file)
index 0000000..7b59960
--- /dev/null
@@ -0,0 +1,106 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+/**
+   @file gcm_memory.c
+   GCM implementation, process a packet, by Tom St Denis
+*/
+#include "tomcrypt.h"
+
+#ifdef LTC_GCM_MODE
+
+/**
+  Process an entire GCM packet in one call.
+  @param cipher            Index of cipher to use
+  @param key               The secret key
+  @param keylen            The length of the secret key
+  @param IV                The initialization vector
+  @param IVlen             The length of the initialization vector
+  @param adata             The additional authentication data (header)
+  @param adatalen          The length of the adata
+  @param pt                The plaintext
+  @param ptlen             The length of the plaintext (ciphertext length is the same)
+  @param ct                The ciphertext
+  @param tag               [out] The MAC tag
+  @param taglen            [in/out] The MAC tag length
+  @param direction         Encrypt or Decrypt mode (GCM_ENCRYPT or GCM_DECRYPT)
+  @return CRYPT_OK on success
+ */
+int gcm_memory(      int           cipher,
+               const unsigned char *key,    unsigned long keylen,
+               const unsigned char *IV,     unsigned long IVlen,
+               const unsigned char *adata,  unsigned long adatalen,
+                     unsigned char *pt,     unsigned long ptlen,
+                     unsigned char *ct,
+                     unsigned char *tag,    unsigned long *taglen,
+                               int direction)
+{
+    void      *orig;
+    gcm_state *gcm;
+    int        err;
+
+    if ((err = cipher_is_valid(cipher)) != CRYPT_OK) {
+       return err;
+    }
+
+    if (cipher_descriptor[cipher].accel_gcm_memory != NULL) {
+       return cipher_descriptor[cipher].accel_gcm_memory
+                                          (key,   keylen,
+                                           IV,    IVlen,
+                                           adata, adatalen,
+                                           pt,    ptlen,
+                                           ct,
+                                           tag,   taglen,
+                                           direction);
+    }
+
+
+
+#ifndef LTC_GCM_TABLES_SSE2
+    orig = gcm = XMALLOC(sizeof(*gcm));
+#else
+    orig = gcm = XMALLOC(sizeof(*gcm) + 16);
+#endif
+    if (gcm == NULL) {
+        return CRYPT_MEM;
+    }
+
+   /* Force GCM to be on a multiple of 16 so we can use 128-bit aligned operations
+    * note that we only modify gcm and keep orig intact.  This code is not portable
+    * but again it's only for SSE2 anyways, so who cares?
+    */
+#ifdef LTC_GCM_TABLES_SSE2
+   if ((unsigned long)gcm & 15) {
+      gcm = (gcm_state *)((unsigned long)gcm + (16 - ((unsigned long)gcm & 15)));
+   }
+#endif
+
+    if ((err = gcm_init(gcm, cipher, key, keylen)) != CRYPT_OK) {
+       goto LTC_ERR;
+    }
+    if ((err = gcm_add_iv(gcm, IV, IVlen)) != CRYPT_OK) {
+       goto LTC_ERR;
+    }
+    if ((err = gcm_add_aad(gcm, adata, adatalen)) != CRYPT_OK) {
+       goto LTC_ERR;
+    }
+    if ((err = gcm_process(gcm, pt, ptlen, ct, direction)) != CRYPT_OK) {
+       goto LTC_ERR;
+    }
+    err = gcm_done(gcm, tag, taglen);
+LTC_ERR:
+    XFREE(orig);
+    return err;
+}
+#endif
+
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/encauth/gcm/gcm_mult_h.c b/libtomcrypt/src/encauth/gcm/gcm_mult_h.c
new file mode 100644 (file)
index 0000000..181d1d1
--- /dev/null
@@ -0,0 +1,57 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+/**
+   @file gcm_mult_h.c
+   GCM implementation, do the GF mult, by Tom St Denis
+*/
+#include "tomcrypt.h"
+
+#if defined(LTC_GCM_MODE)
+/**
+  GCM multiply by H
+  @param gcm   The GCM state which holds the H value
+  @param I     The value to multiply H by
+ */
+void gcm_mult_h(gcm_state *gcm, unsigned char *I)
+{
+   unsigned char T[16];
+#ifdef LTC_GCM_TABLES
+   int x;
+#ifdef LTC_GCM_TABLES_SSE2
+   asm("movdqa (%0),%%xmm0"::"r"(&gcm->PC[0][I[0]][0]));
+   for (x = 1; x < 16; x++) {
+      asm("pxor (%0),%%xmm0"::"r"(&gcm->PC[x][I[x]][0]));
+   }
+   asm("movdqa %%xmm0,(%0)"::"r"(&T));
+#else
+   int y;
+   XMEMCPY(T, &gcm->PC[0][I[0]][0], 16);
+   for (x = 1; x < 16; x++) {
+#ifdef LTC_FAST
+       for (y = 0; y < 16; y += sizeof(LTC_FAST_TYPE)) {
+           *(LTC_FAST_TYPE_PTR_CAST(T + y)) ^= *(LTC_FAST_TYPE_PTR_CAST(&gcm->PC[x][I[x]][y]));
+       }
+#else
+       for (y = 0; y < 16; y++) {
+           T[y] ^= gcm->PC[x][I[x]][y];
+       }
+#endif /* LTC_FAST */
+   }
+#endif /* LTC_GCM_TABLES_SSE2 */
+#else
+   gcm_gf_mult(gcm->H, I, T);
+#endif
+   XMEMCPY(I, T, 16);
+}
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/encauth/gcm/gcm_process.c b/libtomcrypt/src/encauth/gcm/gcm_process.c
new file mode 100644 (file)
index 0000000..b1ec20c
--- /dev/null
@@ -0,0 +1,160 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+/**
+   @file gcm_process.c
+   GCM implementation, process message data, by Tom St Denis
+*/
+#include "tomcrypt.h"
+
+#ifdef LTC_GCM_MODE
+
+/**
+  Process plaintext/ciphertext through GCM
+  @param gcm       The GCM state
+  @param pt        The plaintext
+  @param ptlen     The plaintext length (ciphertext length is the same)
+  @param ct        The ciphertext
+  @param direction Encrypt or Decrypt mode (GCM_ENCRYPT or GCM_DECRYPT)
+  @return CRYPT_OK on success
+ */
+int gcm_process(gcm_state *gcm,
+                     unsigned char *pt,     unsigned long ptlen,
+                     unsigned char *ct,
+                     int direction)
+{
+   unsigned long x;
+   int           y, err;
+   unsigned char b;
+
+   LTC_ARGCHK(gcm != NULL);
+   if (ptlen > 0) {
+      LTC_ARGCHK(pt  != NULL);
+      LTC_ARGCHK(ct  != NULL);
+   }
+
+   if (gcm->buflen > 16 || gcm->buflen < 0) {
+      return CRYPT_INVALID_ARG;
+   }
+
+   if ((err = cipher_is_valid(gcm->cipher)) != CRYPT_OK) {
+      return err;
+   }
+
+   /* 0xFFFFFFFE0 = ((2^39)-256)/8 */
+   if (gcm->pttotlen / 8 + (ulong64)gcm->buflen + (ulong64)ptlen >= CONST64(0xFFFFFFFE0)) {
+      return CRYPT_INVALID_ARG;
+   }
+
+   if (gcm->mode == LTC_GCM_MODE_IV) {
+      /* let's process the IV */
+      if ((err = gcm_add_aad(gcm, NULL, 0)) != CRYPT_OK) return err;
+   }
+
+   /* in AAD mode? */
+   if (gcm->mode == LTC_GCM_MODE_AAD) {
+      /* let's process the AAD */
+      if (gcm->buflen) {
+         gcm->totlen += gcm->buflen * CONST64(8);
+         gcm_mult_h(gcm, gcm->X);
+      }
+
+      /* increment counter */
+      for (y = 15; y >= 12; y--) {
+          if (++gcm->Y[y] & 255) { break; }
+      }
+      /* encrypt the counter */
+      if ((err = cipher_descriptor[gcm->cipher].ecb_encrypt(gcm->Y, gcm->buf, &gcm->K)) != CRYPT_OK) {
+         return err;
+      }
+
+      gcm->buflen = 0;
+      gcm->mode   = LTC_GCM_MODE_TEXT;
+   }
+
+   if (gcm->mode != LTC_GCM_MODE_TEXT) {
+      return CRYPT_INVALID_ARG;
+   }
+
+   x = 0;
+#ifdef LTC_FAST
+   if (gcm->buflen == 0) {
+      if (direction == GCM_ENCRYPT) {
+         for (x = 0; x < (ptlen & ~15); x += 16) {
+             /* ctr encrypt */
+             for (y = 0; y < 16; y += sizeof(LTC_FAST_TYPE)) {
+                 *(LTC_FAST_TYPE_PTR_CAST(&ct[x + y])) = *(LTC_FAST_TYPE_PTR_CAST(&pt[x+y])) ^ *(LTC_FAST_TYPE_PTR_CAST(&gcm->buf[y]));
+                 *(LTC_FAST_TYPE_PTR_CAST(&gcm->X[y])) ^= *(LTC_FAST_TYPE_PTR_CAST(&ct[x+y]));
+             }
+             /* GMAC it */
+             gcm->pttotlen += 128;
+             gcm_mult_h(gcm, gcm->X);
+             /* increment counter */
+             for (y = 15; y >= 12; y--) {
+                 if (++gcm->Y[y] & 255) { break; }
+             }
+             if ((err = cipher_descriptor[gcm->cipher].ecb_encrypt(gcm->Y, gcm->buf, &gcm->K)) != CRYPT_OK) {
+                return err;
+             }
+         }
+      } else {
+         for (x = 0; x < (ptlen & ~15); x += 16) {
+             /* ctr encrypt */
+             for (y = 0; y < 16; y += sizeof(LTC_FAST_TYPE)) {
+                 *(LTC_FAST_TYPE_PTR_CAST(&gcm->X[y])) ^= *(LTC_FAST_TYPE_PTR_CAST(&ct[x+y]));
+                 *(LTC_FAST_TYPE_PTR_CAST(&pt[x + y])) = *(LTC_FAST_TYPE_PTR_CAST(&ct[x+y])) ^ *(LTC_FAST_TYPE_PTR_CAST(&gcm->buf[y]));
+             }
+             /* GMAC it */
+             gcm->pttotlen += 128;
+             gcm_mult_h(gcm, gcm->X);
+             /* increment counter */
+             for (y = 15; y >= 12; y--) {
+                 if (++gcm->Y[y] & 255) { break; }
+             }
+             if ((err = cipher_descriptor[gcm->cipher].ecb_encrypt(gcm->Y, gcm->buf, &gcm->K)) != CRYPT_OK) {
+                return err;
+             }
+         }
+      }
+   }
+#endif
+
+   /* process text */
+   for (; x < ptlen; x++) {
+       if (gcm->buflen == 16) {
+          gcm->pttotlen += 128;
+          gcm_mult_h(gcm, gcm->X);
+
+          /* increment counter */
+          for (y = 15; y >= 12; y--) {
+              if (++gcm->Y[y] & 255) { break; }
+          }
+          if ((err = cipher_descriptor[gcm->cipher].ecb_encrypt(gcm->Y, gcm->buf, &gcm->K)) != CRYPT_OK) {
+             return err;
+          }
+          gcm->buflen = 0;
+       }
+
+       if (direction == GCM_ENCRYPT) {
+          b = ct[x] = pt[x] ^ gcm->buf[gcm->buflen];
+       } else {
+          b = ct[x];
+          pt[x] = ct[x] ^ gcm->buf[gcm->buflen];
+       }
+       gcm->X[gcm->buflen++] ^= b;
+   }
+
+   return CRYPT_OK;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/encauth/gcm/gcm_reset.c b/libtomcrypt/src/encauth/gcm/gcm_reset.c
new file mode 100644 (file)
index 0000000..3bd1088
--- /dev/null
@@ -0,0 +1,42 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+/**
+   @file gcm_reset.c
+   GCM implementation, reset a used state so it can accept IV data, by Tom St Denis
+*/
+#include "tomcrypt.h"
+
+#ifdef LTC_GCM_MODE
+
+/**
+  Reset a GCM state to as if you just called gcm_init().  This saves the initialization time.
+  @param gcm   The GCM state to reset
+  @return CRYPT_OK on success
+*/
+int gcm_reset(gcm_state *gcm)
+{
+   LTC_ARGCHK(gcm != NULL);
+
+   zeromem(gcm->buf, sizeof(gcm->buf));
+   zeromem(gcm->X,   sizeof(gcm->X));
+   gcm->mode     = LTC_GCM_MODE_IV;
+   gcm->ivmode   = 0;
+   gcm->buflen   = 0;
+   gcm->totlen   = 0;
+   gcm->pttotlen = 0;
+
+   return CRYPT_OK;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/encauth/gcm/gcm_test.c b/libtomcrypt/src/encauth/gcm/gcm_test.c
new file mode 100644 (file)
index 0000000..5f68b30
--- /dev/null
@@ -0,0 +1,392 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+/**
+   @file gcm_test.c
+   GCM implementation, testing, by Tom St Denis
+*/
+#include "tomcrypt.h"
+
+#ifdef LTC_GCM_MODE
+
+/**
+  Test the GCM code
+  @return CRYPT_OK on success
+ */
+int gcm_test(void)
+{
+#ifndef LTC_TEST
+   return CRYPT_NOP;
+#else
+   static const struct {
+       unsigned char K[32];
+       int           keylen;
+       unsigned char P[128];
+       unsigned long ptlen;
+       unsigned char A[128];
+       unsigned long alen;
+       unsigned char IV[128];
+       unsigned long IVlen;
+       unsigned char C[128];
+       unsigned char T[16];
+   } tests[] = {
+
+/* test case #1 */
+{
+  /* key */
+  { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+  16,
+
+  /* plaintext */
+  { 0 },
+  0,
+
+  /* AAD data */
+  { 0 },
+  0,
+
+  /* IV */
+  { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00 },
+  12,
+
+  /* ciphertext  */
+  { 0 },
+
+  /* tag */
+  { 0x58, 0xe2, 0xfc, 0xce, 0xfa, 0x7e, 0x30, 0x61,
+    0x36, 0x7f, 0x1d, 0x57, 0xa4, 0xe7, 0x45, 0x5a }
+},
+
+/* test case #2 */
+{
+  /* key */
+  { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+  16,
+
+  /* PT */
+  { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+  16,
+
+  /* ADATA */
+  { 0 },
+  0,
+
+  /* IV */
+  { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00 },
+  12,
+
+  /* CT */
+  { 0x03, 0x88, 0xda, 0xce, 0x60, 0xb6, 0xa3, 0x92,
+    0xf3, 0x28, 0xc2, 0xb9, 0x71, 0xb2, 0xfe, 0x78 },
+
+  /* TAG */
+  { 0xab, 0x6e, 0x47, 0xd4, 0x2c, 0xec, 0x13, 0xbd,
+    0xf5, 0x3a, 0x67, 0xb2, 0x12, 0x57, 0xbd, 0xdf }
+},
+
+/* test case #3 */
+{
+   /* key */
+   { 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c,
+     0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08, },
+   16,
+
+   /* PT */
+   { 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5,
+     0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a,
+     0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda,
+     0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72,
+     0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53,
+     0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25,
+     0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57,
+     0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x55, },
+  64,
+
+  /* ADATA */
+  { 0 },
+  0,
+
+  /* IV */
+  { 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad,
+    0xde, 0xca, 0xf8, 0x88,  },
+  12,
+
+  /* CT */
+  { 0x42, 0x83, 0x1e, 0xc2, 0x21, 0x77, 0x74, 0x24,
+    0x4b, 0x72, 0x21, 0xb7, 0x84, 0xd0, 0xd4, 0x9c,
+    0xe3, 0xaa, 0x21, 0x2f, 0x2c, 0x02, 0xa4, 0xe0,
+    0x35, 0xc1, 0x7e, 0x23, 0x29, 0xac, 0xa1, 0x2e,
+    0x21, 0xd5, 0x14, 0xb2, 0x54, 0x66, 0x93, 0x1c,
+    0x7d, 0x8f, 0x6a, 0x5a, 0xac, 0x84, 0xaa, 0x05,
+    0x1b, 0xa3, 0x0b, 0x39, 0x6a, 0x0a, 0xac, 0x97,
+    0x3d, 0x58, 0xe0, 0x91, 0x47, 0x3f, 0x59, 0x85, },
+
+  /* TAG */
+  { 0x4d, 0x5c, 0x2a, 0xf3, 0x27, 0xcd, 0x64, 0xa6,
+    0x2c, 0xf3, 0x5a, 0xbd, 0x2b, 0xa6, 0xfa, 0xb4, }
+},
+
+/* test case #4 */
+{
+   /* key */
+   { 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c,
+     0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08, },
+   16,
+
+   /* PT */
+   { 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5,
+     0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a,
+     0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda,
+     0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72,
+     0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53,
+     0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25,
+     0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57,
+     0xba, 0x63, 0x7b, 0x39,  },
+   60,
+
+   /* ADATA */
+   { 0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef,
+     0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef,
+     0xab, 0xad, 0xda, 0xd2,  },
+   20,
+
+   /* IV */
+   { 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad,
+     0xde, 0xca, 0xf8, 0x88,  },
+   12,
+
+   /* CT */
+   { 0x42, 0x83, 0x1e, 0xc2, 0x21, 0x77, 0x74, 0x24,
+     0x4b, 0x72, 0x21, 0xb7, 0x84, 0xd0, 0xd4, 0x9c,
+     0xe3, 0xaa, 0x21, 0x2f, 0x2c, 0x02, 0xa4, 0xe0,
+     0x35, 0xc1, 0x7e, 0x23, 0x29, 0xac, 0xa1, 0x2e,
+     0x21, 0xd5, 0x14, 0xb2, 0x54, 0x66, 0x93, 0x1c,
+     0x7d, 0x8f, 0x6a, 0x5a, 0xac, 0x84, 0xaa, 0x05,
+     0x1b, 0xa3, 0x0b, 0x39, 0x6a, 0x0a, 0xac, 0x97,
+     0x3d, 0x58, 0xe0, 0x91,  },
+
+   /* TAG */
+   { 0x5b, 0xc9, 0x4f, 0xbc, 0x32, 0x21, 0xa5, 0xdb,
+     0x94, 0xfa, 0xe9, 0x5a, 0xe7, 0x12, 0x1a, 0x47, }
+
+},
+
+/* test case #5 */
+{
+   /* key */
+   { 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c,
+     0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08, },
+   16,
+
+   /* PT */
+   { 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5,
+     0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a,
+     0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda,
+     0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72,
+     0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53,
+     0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25,
+     0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57,
+     0xba, 0x63, 0x7b, 0x39,  },
+   60,
+
+   /* ADATA */
+   { 0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef,
+     0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef,
+     0xab, 0xad, 0xda, 0xd2,  },
+   20,
+
+   /* IV */
+   { 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad, },
+   8,
+
+   /* CT */
+   { 0x61, 0x35, 0x3b, 0x4c, 0x28, 0x06, 0x93, 0x4a,
+     0x77, 0x7f, 0xf5, 0x1f, 0xa2, 0x2a, 0x47, 0x55,
+     0x69, 0x9b, 0x2a, 0x71, 0x4f, 0xcd, 0xc6, 0xf8,
+     0x37, 0x66, 0xe5, 0xf9, 0x7b, 0x6c, 0x74, 0x23,
+     0x73, 0x80, 0x69, 0x00, 0xe4, 0x9f, 0x24, 0xb2,
+     0x2b, 0x09, 0x75, 0x44, 0xd4, 0x89, 0x6b, 0x42,
+     0x49, 0x89, 0xb5, 0xe1, 0xeb, 0xac, 0x0f, 0x07,
+     0xc2, 0x3f, 0x45, 0x98,  },
+
+   /* TAG */
+   { 0x36, 0x12, 0xd2, 0xe7, 0x9e, 0x3b, 0x07, 0x85,
+     0x56, 0x1b, 0xe1, 0x4a, 0xac, 0xa2, 0xfc, 0xcb, }
+},
+
+/* test case #6 */
+{
+   /* key */
+   { 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c,
+     0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08, },
+   16,
+
+   /* PT */
+   { 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5,
+     0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a,
+     0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda,
+     0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72,
+     0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53,
+     0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25,
+     0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57,
+     0xba, 0x63, 0x7b, 0x39,  },
+   60,
+
+   /* ADATA */
+   { 0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef,
+     0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef,
+     0xab, 0xad, 0xda, 0xd2,  },
+   20,
+
+   /* IV */
+   { 0x93, 0x13, 0x22, 0x5d, 0xf8, 0x84, 0x06, 0xe5,
+     0x55, 0x90, 0x9c, 0x5a, 0xff, 0x52, 0x69, 0xaa,
+     0x6a, 0x7a, 0x95, 0x38, 0x53, 0x4f, 0x7d, 0xa1,
+     0xe4, 0xc3, 0x03, 0xd2, 0xa3, 0x18, 0xa7, 0x28,
+     0xc3, 0xc0, 0xc9, 0x51, 0x56, 0x80, 0x95, 0x39,
+     0xfc, 0xf0, 0xe2, 0x42, 0x9a, 0x6b, 0x52, 0x54,
+     0x16, 0xae, 0xdb, 0xf5, 0xa0, 0xde, 0x6a, 0x57,
+     0xa6, 0x37, 0xb3, 0x9b,  },
+   60,
+
+   /* CT */
+   { 0x8c, 0xe2, 0x49, 0x98, 0x62, 0x56, 0x15, 0xb6,
+     0x03, 0xa0, 0x33, 0xac, 0xa1, 0x3f, 0xb8, 0x94,
+     0xbe, 0x91, 0x12, 0xa5, 0xc3, 0xa2, 0x11, 0xa8,
+     0xba, 0x26, 0x2a, 0x3c, 0xca, 0x7e, 0x2c, 0xa7,
+     0x01, 0xe4, 0xa9, 0xa4, 0xfb, 0xa4, 0x3c, 0x90,
+     0xcc, 0xdc, 0xb2, 0x81, 0xd4, 0x8c, 0x7c, 0x6f,
+     0xd6, 0x28, 0x75, 0xd2, 0xac, 0xa4, 0x17, 0x03,
+     0x4c, 0x34, 0xae, 0xe5,  },
+
+   /* TAG */
+   { 0x61, 0x9c, 0xc5, 0xae, 0xff, 0xfe, 0x0b, 0xfa,
+     0x46, 0x2a, 0xf4, 0x3c, 0x16, 0x99, 0xd0, 0x50, }
+},
+
+/* test case #46 from BG (catches the LTC bug of v1.15) */
+{
+   /* key */
+   { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+   16,
+
+   /* PT */
+   { 0xa2, 0xaa, 0xb3, 0xad, 0x8b, 0x17, 0xac, 0xdd,
+     0xa2, 0x88, 0x42, 0x6c, 0xd7, 0xc4, 0x29, 0xb7,
+     0xca, 0x86, 0xb7, 0xac, 0xa0, 0x58, 0x09, 0xc7,
+     0x0c, 0xe8, 0x2d, 0xb2, 0x57, 0x11, 0xcb, 0x53,
+     0x02, 0xeb, 0x27, 0x43, 0xb0, 0x36, 0xf3, 0xd7,
+     0x50, 0xd6, 0xcf, 0x0d, 0xc0, 0xac, 0xb9, 0x29,
+     0x50, 0xd5, 0x46, 0xdb, 0x30, 0x8f, 0x93, 0xb4,
+     0xff, 0x24, 0x4a, 0xfa, 0x9d, 0xc7, 0x2b, 0xcd,
+     0x75, 0x8d, 0x2c },
+   67,
+
+   /* ADATA */
+   { 0x68, 0x8e, 0x1a, 0xa9, 0x84, 0xde, 0x92, 0x6d,
+     0xc7, 0xb4, 0xc4, 0x7f, 0x44 },
+   13,
+
+   /* IV */
+   { 0xb7, 0x21, 0x38, 0xb5, 0xa0, 0x5f, 0xf5, 0x07,
+     0x0e, 0x8c, 0xd9, 0x41, 0x83, 0xf7, 0x61, 0xd8 },
+   16,
+
+   /* CT */
+   { 0xcb, 0xc8, 0xd2, 0xf1, 0x54, 0x81, 0xa4, 0xcc,
+     0x7d, 0xd1, 0xe1, 0x9a, 0xaa, 0x83, 0xde, 0x56,
+     0x78, 0x48, 0x3e, 0xc3, 0x59, 0xae, 0x7d, 0xec,
+     0x2a, 0xb8, 0xd5, 0x34, 0xe0, 0x90, 0x6f, 0x4b,
+     0x46, 0x63, 0xfa, 0xff, 0x58, 0xa8, 0xb2, 0xd7,
+     0x33, 0xb8, 0x45, 0xee, 0xf7, 0xc9, 0xb3, 0x31,
+     0xe9, 0xe1, 0x0e, 0xb2, 0x61, 0x2c, 0x99, 0x5f,
+     0xeb, 0x1a, 0xc1, 0x5a, 0x62, 0x86, 0xcc, 0xe8,
+     0xb2, 0x97, 0xa8 },
+
+   /* TAG */
+   { 0x8d, 0x2d, 0x2a, 0x93, 0x72, 0x62, 0x6f, 0x6b,
+     0xee, 0x85, 0x80, 0x27, 0x6a, 0x63, 0x66, 0xbf }
+}
+
+/* rest of test cases are the same except AES key size changes... ignored... */
+};
+   int           idx, err;
+   unsigned long x, y;
+   unsigned char out[2][128], T[2][16];
+   gcm_state gcm;
+
+   /* find aes */
+   idx = find_cipher("aes");
+   if (idx == -1) {
+      idx = find_cipher("rijndael");
+      if (idx == -1) {
+         return CRYPT_NOP;
+      }
+   }
+
+   /* Special test case for empty AAD + empty PT */
+   y = sizeof(T[0]);
+   if ((err = gcm_init(&gcm, idx, tests[0].K, tests[0].keylen)) != CRYPT_OK) return err;
+   if ((err = gcm_add_iv(&gcm, tests[0].IV, tests[0].IVlen)) != CRYPT_OK)    return err;
+   /* intentionally skip gcm_add_aad + gcm_process */
+   if ((err = gcm_done(&gcm, T[0], &y)) != CRYPT_OK)                         return err;
+   if (compare_testvector(T[0], y, tests[0].T, 16, "GCM Encrypt Tag-special", 0))      return CRYPT_FAIL_TESTVECTOR;
+
+   for (x = 0; x < (int)(sizeof(tests)/sizeof(tests[0])); x++) {
+       y = sizeof(T[0]);
+       if ((err = gcm_memory(idx, tests[x].K, tests[x].keylen,
+                             tests[x].IV, tests[x].IVlen,
+                             tests[x].A, tests[x].alen,
+                             (unsigned char*)tests[x].P, tests[x].ptlen,
+                             out[0], T[0], &y, GCM_ENCRYPT)) != CRYPT_OK) {
+          return err;
+       }
+
+       if (compare_testvector(out[0], tests[x].ptlen, tests[x].C, tests[x].ptlen, "GCM CT", x)) {
+          return CRYPT_FAIL_TESTVECTOR;
+       }
+
+       if (compare_testvector(T[0], y, tests[x].T, 16, "GCM Encrypt Tag", x)) {
+          return CRYPT_FAIL_TESTVECTOR;
+       }
+
+       y = sizeof(T[1]);
+       if ((err = gcm_memory(idx, tests[x].K, tests[x].keylen,
+                             tests[x].IV, tests[x].IVlen,
+                             tests[x].A, tests[x].alen,
+                             out[1], tests[x].ptlen,
+                             out[0], T[1], &y, GCM_DECRYPT)) != CRYPT_OK) {
+          return err;
+       }
+
+       if (compare_testvector(out[1], tests[x].ptlen, tests[x].P, tests[x].ptlen, "GCM PT", x)) {
+          return CRYPT_FAIL_TESTVECTOR;
+       }
+
+       if (compare_testvector(T[1], y, tests[x].T, 16, "GCM Decrypt Tag", x)) {
+          return CRYPT_FAIL_TESTVECTOR;
+       }
+
+   }
+   return CRYPT_OK;
+#endif
+}
+
+#endif
+
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/encauth/ocb/ocb_decrypt.c b/libtomcrypt/src/encauth/ocb/ocb_decrypt.c
new file mode 100644 (file)
index 0000000..5dc8dad
--- /dev/null
@@ -0,0 +1,77 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+/**
+   @file ocb_decrypt.c
+   OCB implementation, decrypt data, by Tom St Denis
+*/
+#include "tomcrypt.h"
+
+#ifdef LTC_OCB_MODE
+
+/**
+  Decrypt a block with OCB.
+  @param ocb    The OCB state
+  @param ct     The ciphertext (length of the block size of the block cipher)
+  @param pt     [out] The plaintext (length of ct)
+  @return CRYPT_OK if successful
+*/
+int ocb_decrypt(ocb_state *ocb, const unsigned char *ct, unsigned char *pt)
+{
+   unsigned char Z[MAXBLOCKSIZE], tmp[MAXBLOCKSIZE];
+   int err, x;
+
+   LTC_ARGCHK(ocb != NULL);
+   LTC_ARGCHK(pt  != NULL);
+   LTC_ARGCHK(ct  != NULL);
+
+   /* check if valid cipher */
+   if ((err = cipher_is_valid(ocb->cipher)) != CRYPT_OK) {
+      return err;
+   }
+   LTC_ARGCHK(cipher_descriptor[ocb->cipher].ecb_decrypt != NULL);
+
+   /* check length */
+   if (ocb->block_len != cipher_descriptor[ocb->cipher].block_length) {
+      return CRYPT_INVALID_ARG;
+   }
+
+   /* Get Z[i] value */
+   ocb_shift_xor(ocb, Z);
+
+   /* xor ct in, encrypt, xor Z out */
+   for (x = 0; x < ocb->block_len; x++) {
+       tmp[x] = ct[x] ^ Z[x];
+   }
+   if ((err = cipher_descriptor[ocb->cipher].ecb_decrypt(tmp, pt, &ocb->key)) != CRYPT_OK) {
+      return err;
+   }
+   for (x = 0; x < ocb->block_len; x++) {
+       pt[x] ^= Z[x];
+   }
+
+   /* compute checksum */
+   for (x = 0; x < ocb->block_len; x++) {
+       ocb->checksum[x] ^= pt[x];
+   }
+
+
+#ifdef LTC_CLEAN_STACK
+   zeromem(Z, sizeof(Z));
+   zeromem(tmp, sizeof(tmp));
+#endif
+   return CRYPT_OK;
+}
+
+#endif
+
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/encauth/ocb/ocb_decrypt_verify_memory.c b/libtomcrypt/src/encauth/ocb/ocb_decrypt_verify_memory.c
new file mode 100644 (file)
index 0000000..a7a47f0
--- /dev/null
@@ -0,0 +1,84 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+/**
+  @file ocb_decrypt_verify_memory.c
+  OCB implementation, helper to decrypt block of memory, by Tom St Denis
+*/
+#include "tomcrypt.h"
+
+#ifdef LTC_OCB_MODE
+
+/**
+   Decrypt and compare the tag with OCB.
+   @param cipher     The index of the cipher desired
+   @param key        The secret key
+   @param keylen     The length of the secret key (octets)
+   @param nonce      The session nonce (length of the block size of the block cipher)
+   @param ct         The ciphertext
+   @param ctlen      The length of the ciphertext (octets)
+   @param pt         [out] The plaintext
+   @param tag        The tag to compare against
+   @param taglen     The length of the tag (octets)
+   @param stat       [out] The result of the tag comparison (1==valid, 0==invalid)
+   @return CRYPT_OK if successful regardless of the tag comparison
+*/
+int ocb_decrypt_verify_memory(int cipher,
+    const unsigned char *key,    unsigned long keylen,
+    const unsigned char *nonce,
+    const unsigned char *ct,     unsigned long ctlen,
+          unsigned char *pt,
+    const unsigned char *tag,    unsigned long taglen,
+          int           *stat)
+{
+   int err;
+   ocb_state *ocb;
+
+   LTC_ARGCHK(key    != NULL);
+   LTC_ARGCHK(nonce  != NULL);
+   LTC_ARGCHK(pt     != NULL);
+   LTC_ARGCHK(ct     != NULL);
+   LTC_ARGCHK(tag    != NULL);
+   LTC_ARGCHK(stat    != NULL);
+
+   /* allocate memory */
+   ocb = XMALLOC(sizeof(ocb_state));
+   if (ocb == NULL) {
+      return CRYPT_MEM;
+   }
+
+   if ((err = ocb_init(ocb, cipher, key, keylen, nonce)) != CRYPT_OK) {
+      goto LBL_ERR;
+   }
+
+   while (ctlen > (unsigned long)ocb->block_len) {
+        if ((err = ocb_decrypt(ocb, ct, pt)) != CRYPT_OK) {
+            goto LBL_ERR;
+        }
+        ctlen   -= ocb->block_len;
+        pt      += ocb->block_len;
+        ct      += ocb->block_len;
+   }
+
+   err = ocb_done_decrypt(ocb, ct, ctlen, pt, tag, taglen, stat);
+LBL_ERR:
+#ifdef LTC_CLEAN_STACK
+   zeromem(ocb, sizeof(ocb_state));
+#endif
+
+   XFREE(ocb);
+
+   return err;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/encauth/ocb/ocb_done_decrypt.c b/libtomcrypt/src/encauth/ocb/ocb_done_decrypt.c
new file mode 100644 (file)
index 0000000..357bd84
--- /dev/null
@@ -0,0 +1,78 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+/**
+   @file ocb_done_decrypt.c
+   OCB implementation, terminate decryption, by Tom St Denis
+*/
+#include "tomcrypt.h"
+
+#ifdef LTC_OCB_MODE
+
+/**
+   Terminate a decrypting OCB state
+   @param ocb    The OCB state
+   @param ct     The ciphertext (if any)
+   @param ctlen  The length of the ciphertext (octets)
+   @param pt     [out] The plaintext
+   @param tag    The authentication tag (to compare against)
+   @param taglen The length of the authentication tag provided
+   @param stat    [out] The result of the tag comparison
+   @return CRYPT_OK if the process was successful regardless if the tag is valid
+*/
+int ocb_done_decrypt(ocb_state *ocb,
+                     const unsigned char *ct,  unsigned long ctlen,
+                           unsigned char *pt,
+                     const unsigned char *tag, unsigned long taglen, int *stat)
+{
+   int err;
+   unsigned char *tagbuf;
+   unsigned long tagbuflen;
+
+   LTC_ARGCHK(ocb  != NULL);
+   LTC_ARGCHK(pt   != NULL);
+   LTC_ARGCHK(ct   != NULL);
+   LTC_ARGCHK(tag  != NULL);
+   LTC_ARGCHK(stat != NULL);
+
+   /* default to failed */
+   *stat = 0;
+
+   /* allocate memory */
+   tagbuf = XMALLOC(MAXBLOCKSIZE);
+   if (tagbuf == NULL) {
+      return CRYPT_MEM;
+   }
+
+   tagbuflen = MAXBLOCKSIZE;
+   if ((err = s_ocb_done(ocb, ct, ctlen, pt, tagbuf, &tagbuflen, 1)) != CRYPT_OK) {
+      goto LBL_ERR;
+   }
+
+   if (taglen <= tagbuflen && XMEM_NEQ(tagbuf, tag, taglen) == 0) {
+      *stat = 1;
+   }
+
+   err = CRYPT_OK;
+LBL_ERR:
+#ifdef LTC_CLEAN_STACK
+   zeromem(tagbuf, MAXBLOCKSIZE);
+#endif
+
+   XFREE(tagbuf);
+
+   return err;
+}
+
+#endif
+
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/encauth/ocb/ocb_done_encrypt.c b/libtomcrypt/src/encauth/ocb/ocb_done_encrypt.c
new file mode 100644 (file)
index 0000000..12ea68f
--- /dev/null
@@ -0,0 +1,44 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+/**
+   @file ocb_done_encrypt.c
+   OCB implementation, terminate encryption, by Tom St Denis
+*/
+#include "tomcrypt.h"
+
+#ifdef LTC_OCB_MODE
+
+/**
+   Terminate an encryption OCB state
+   @param ocb       The OCB state
+   @param pt        Remaining plaintext (if any)
+   @param ptlen     The length of the plaintext (octets)
+   @param ct        [out] The ciphertext (if any)
+   @param tag       [out] The tag for the OCB stream
+   @param taglen    [in/out] The max size and resulting size of the tag
+   @return CRYPT_OK if successful
+*/
+int ocb_done_encrypt(ocb_state *ocb, const unsigned char *pt, unsigned long ptlen,
+                     unsigned char *ct, unsigned char *tag, unsigned long *taglen)
+{
+   LTC_ARGCHK(ocb    != NULL);
+   LTC_ARGCHK(pt     != NULL);
+   LTC_ARGCHK(ct     != NULL);
+   LTC_ARGCHK(tag    != NULL);
+   LTC_ARGCHK(taglen != NULL);
+   return s_ocb_done(ocb, pt, ptlen, ct, tag, taglen, 0);
+}
+
+#endif
+
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/encauth/ocb/ocb_encrypt.c b/libtomcrypt/src/encauth/ocb/ocb_encrypt.c
new file mode 100644 (file)
index 0000000..aad76a0
--- /dev/null
@@ -0,0 +1,70 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+/**
+   @file ocb_encrypt.c
+   OCB implementation, encrypt data, by Tom St Denis
+*/
+#include "tomcrypt.h"
+
+#ifdef LTC_OCB_MODE
+
+/**
+   Encrypt a block of data with OCB.
+   @param ocb     The OCB state
+   @param pt      The plaintext (length of the block size of the block cipher)
+   @param ct      [out] The ciphertext (same size as the pt)
+   @return CRYPT_OK if successful
+*/
+int ocb_encrypt(ocb_state *ocb, const unsigned char *pt, unsigned char *ct)
+{
+   unsigned char Z[MAXBLOCKSIZE], tmp[MAXBLOCKSIZE];
+   int err, x;
+
+   LTC_ARGCHK(ocb != NULL);
+   LTC_ARGCHK(pt  != NULL);
+   LTC_ARGCHK(ct  != NULL);
+   if ((err = cipher_is_valid(ocb->cipher)) != CRYPT_OK) {
+      return err;
+   }
+   if (ocb->block_len != cipher_descriptor[ocb->cipher].block_length) {
+      return CRYPT_INVALID_ARG;
+   }
+
+   /* compute checksum */
+   for (x = 0; x < ocb->block_len; x++) {
+       ocb->checksum[x] ^= pt[x];
+   }
+
+   /* Get Z[i] value */
+   ocb_shift_xor(ocb, Z);
+
+   /* xor pt in, encrypt, xor Z out */
+   for (x = 0; x < ocb->block_len; x++) {
+       tmp[x] = pt[x] ^ Z[x];
+   }
+   if ((err = cipher_descriptor[ocb->cipher].ecb_encrypt(tmp, ct, &ocb->key)) != CRYPT_OK) {
+      return err;
+   }
+   for (x = 0; x < ocb->block_len; x++) {
+       ct[x] ^= Z[x];
+   }
+
+#ifdef LTC_CLEAN_STACK
+   zeromem(Z, sizeof(Z));
+   zeromem(tmp, sizeof(tmp));
+#endif
+   return CRYPT_OK;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/encauth/ocb/ocb_encrypt_authenticate_memory.c b/libtomcrypt/src/encauth/ocb/ocb_encrypt_authenticate_memory.c
new file mode 100644 (file)
index 0000000..1793a64
--- /dev/null
@@ -0,0 +1,82 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+/**
+  @file ocb_encrypt_authenticate_memory.c
+  OCB implementation, encrypt block of memory, by Tom St Denis
+*/
+#include "tomcrypt.h"
+
+#ifdef LTC_OCB_MODE
+
+/**
+   Encrypt and generate an authentication code for a buffer of memory
+   @param cipher     The index of the cipher desired
+   @param key        The secret key
+   @param keylen     The length of the secret key (octets)
+   @param nonce      The session nonce (length of the block ciphers block size)
+   @param pt         The plaintext
+   @param ptlen      The length of the plaintext (octets)
+   @param ct         [out] The ciphertext
+   @param tag        [out] The authentication tag
+   @param taglen     [in/out] The max size and resulting size of the authentication tag
+   @return CRYPT_OK if successful
+*/
+int ocb_encrypt_authenticate_memory(int cipher,
+    const unsigned char *key,    unsigned long keylen,
+    const unsigned char *nonce,
+    const unsigned char *pt,     unsigned long ptlen,
+          unsigned char *ct,
+          unsigned char *tag,    unsigned long *taglen)
+{
+   int err;
+   ocb_state *ocb;
+
+   LTC_ARGCHK(key    != NULL);
+   LTC_ARGCHK(nonce  != NULL);
+   LTC_ARGCHK(pt     != NULL);
+   LTC_ARGCHK(ct     != NULL);
+   LTC_ARGCHK(tag    != NULL);
+   LTC_ARGCHK(taglen != NULL);
+
+   /* allocate ram */
+   ocb = XMALLOC(sizeof(ocb_state));
+   if (ocb == NULL) {
+      return CRYPT_MEM;
+   }
+
+   if ((err = ocb_init(ocb, cipher, key, keylen, nonce)) != CRYPT_OK) {
+      goto LBL_ERR;
+   }
+
+   while (ptlen > (unsigned long)ocb->block_len) {
+        if ((err = ocb_encrypt(ocb, pt, ct)) != CRYPT_OK) {
+           goto LBL_ERR;
+        }
+        ptlen   -= ocb->block_len;
+        pt      += ocb->block_len;
+        ct      += ocb->block_len;
+   }
+
+   err = ocb_done_encrypt(ocb, pt, ptlen, ct, tag, taglen);
+LBL_ERR:
+#ifdef LTC_CLEAN_STACK
+   zeromem(ocb, sizeof(ocb_state));
+#endif
+
+   XFREE(ocb);
+
+   return err;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/encauth/ocb/ocb_init.c b/libtomcrypt/src/encauth/ocb/ocb_init.c
new file mode 100644 (file)
index 0000000..e008a44
--- /dev/null
@@ -0,0 +1,139 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+/**
+   @file ocb_init.c
+   OCB implementation, initialize state, by Tom St Denis
+*/
+#include "tomcrypt.h"
+
+#ifdef LTC_OCB_MODE
+
+static const struct {
+    int           len;
+    unsigned char poly_div[MAXBLOCKSIZE],
+                  poly_mul[MAXBLOCKSIZE];
+} polys[] = {
+{
+    8,
+    { 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D },
+    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1B }
+}, {
+    16,
+    { 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43 },
+    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x87 }
+}
+};
+
+/**
+  Initialize an OCB context.
+  @param ocb     [out] The destination of the OCB state
+  @param cipher  The index of the desired cipher
+  @param key     The secret key
+  @param keylen  The length of the secret key (octets)
+  @param nonce   The session nonce (length of the block size of the cipher)
+  @return CRYPT_OK if successful
+*/
+int ocb_init(ocb_state *ocb, int cipher,
+             const unsigned char *key, unsigned long keylen, const unsigned char *nonce)
+{
+   int poly, x, y, m, err;
+
+   LTC_ARGCHK(ocb   != NULL);
+   LTC_ARGCHK(key   != NULL);
+   LTC_ARGCHK(nonce != NULL);
+
+   /* valid cipher? */
+   if ((err = cipher_is_valid(cipher)) != CRYPT_OK) {
+      return err;
+   }
+
+   /* determine which polys to use */
+   ocb->block_len = cipher_descriptor[cipher].block_length;
+   x = (int)(sizeof(polys)/sizeof(polys[0]));
+   for (poly = 0; poly < x; poly++) {
+       if (polys[poly].len == ocb->block_len) {
+          break;
+       }
+   }
+   if (poly == x) {
+      return CRYPT_INVALID_ARG; /* block_len not found in polys */
+   }
+   if (polys[poly].len != ocb->block_len) {
+      return CRYPT_INVALID_ARG;
+   }
+
+   /* schedule the key */
+   if ((err = cipher_descriptor[cipher].setup(key, keylen, 0, &ocb->key)) != CRYPT_OK) {
+      return err;
+   }
+
+   /* find L = E[0] */
+   zeromem(ocb->L, ocb->block_len);
+   if ((err = cipher_descriptor[cipher].ecb_encrypt(ocb->L, ocb->L, &ocb->key)) != CRYPT_OK) {
+      return err;
+   }
+
+   /* find R = E[N xor L] */
+   for (x = 0; x < ocb->block_len; x++) {
+       ocb->R[x] = ocb->L[x] ^ nonce[x];
+   }
+   if ((err = cipher_descriptor[cipher].ecb_encrypt(ocb->R, ocb->R, &ocb->key)) != CRYPT_OK) {
+      return err;
+   }
+
+   /* find Ls[i] = L << i for i == 0..31 */
+   XMEMCPY(ocb->Ls[0], ocb->L, ocb->block_len);
+   for (x = 1; x < 32; x++) {
+       m = ocb->Ls[x-1][0] >> 7;
+       for (y = 0; y < ocb->block_len-1; y++) {
+           ocb->Ls[x][y] = ((ocb->Ls[x-1][y] << 1) | (ocb->Ls[x-1][y+1] >> 7)) & 255;
+       }
+       ocb->Ls[x][ocb->block_len-1] = (ocb->Ls[x-1][ocb->block_len-1] << 1) & 255;
+
+       if (m == 1) {
+          for (y = 0; y < ocb->block_len; y++) {
+              ocb->Ls[x][y] ^= polys[poly].poly_mul[y];
+          }
+       }
+   }
+
+   /* find Lr = L / x */
+   m = ocb->L[ocb->block_len-1] & 1;
+
+   /* shift right */
+   for (x = ocb->block_len - 1; x > 0; x--) {
+      ocb->Lr[x] = ((ocb->L[x] >> 1) | (ocb->L[x-1] << 7)) & 255;
+   }
+   ocb->Lr[0] = ocb->L[0] >> 1;
+
+   if (m == 1) {
+      for (x = 0; x < ocb->block_len; x++) {
+         ocb->Lr[x] ^= polys[poly].poly_div[x];
+      }
+   }
+
+   /* set Li, checksum */
+   zeromem(ocb->Li,       ocb->block_len);
+   zeromem(ocb->checksum, ocb->block_len);
+
+   /* set other params */
+   ocb->block_index = 1;
+   ocb->cipher      = cipher;
+
+   return CRYPT_OK;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/encauth/ocb/ocb_ntz.c b/libtomcrypt/src/encauth/ocb/ocb_ntz.c
new file mode 100644 (file)
index 0000000..cfdc667
--- /dev/null
@@ -0,0 +1,40 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+/**
+   @file ocb_ntz.c
+   OCB implementation, internal function, by Tom St Denis
+*/
+
+#include "tomcrypt.h"
+
+#ifdef LTC_OCB_MODE
+
+/**
+   Returns the number of leading zero bits [from lsb up]
+   @param x  The 32-bit value to observe
+   @return   The number of bits [from the lsb up] that are zero
+*/
+int ocb_ntz(unsigned long x)
+{
+   int c;
+   x &= 0xFFFFFFFFUL;
+   c = 0;
+   while ((x & 1) == 0) {
+      ++c;
+      x >>= 1;
+   }
+   return c;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/encauth/ocb/ocb_shift_xor.c b/libtomcrypt/src/encauth/ocb/ocb_shift_xor.c
new file mode 100644 (file)
index 0000000..8a8ad2d
--- /dev/null
@@ -0,0 +1,37 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+/**
+   @file ocb_shift_xor.c
+   OCB implementation, internal function, by Tom St Denis
+*/
+#include "tomcrypt.h"
+
+#ifdef LTC_OCB_MODE
+
+/**
+   Compute the shift/xor for OCB (internal function)
+   @param ocb  The OCB state
+   @param Z    The destination of the shift
+*/
+void ocb_shift_xor(ocb_state *ocb, unsigned char *Z)
+{
+   int x, y;
+   y = ocb_ntz(ocb->block_index++);
+   for (x = 0; x < ocb->block_len; x++) {
+       ocb->Li[x] ^= ocb->Ls[y][x];
+       Z[x]        = ocb->Li[x] ^ ocb->R[x];
+   }
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/encauth/ocb/ocb_test.c b/libtomcrypt/src/encauth/ocb/ocb_test.c
new file mode 100644 (file)
index 0000000..74431f7
--- /dev/null
@@ -0,0 +1,215 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+/**
+   @file ocb_test.c
+   OCB implementation, self-test by Tom St Denis
+*/
+#include "tomcrypt.h"
+
+#ifdef LTC_OCB_MODE
+
+/**
+  Test the OCB protocol
+  @return   CRYPT_OK if successful
+*/
+int ocb_test(void)
+{
+#ifndef LTC_TEST
+   return CRYPT_NOP;
+#else
+   static const struct {
+         int ptlen;
+         unsigned char key[16], nonce[16], pt[34], ct[34], tag[16];
+   } tests[] = {
+
+   /* OCB-AES-128-0B */
+{
+   0,
+   /* key */
+   { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+     0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f },
+   /* nonce */
+   { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 },
+   /* pt */
+   { 0 },
+   /* ct */
+   { 0 },
+   /* tag */
+   { 0x15, 0xd3, 0x7d, 0xd7, 0xc8, 0x90, 0xd5, 0xd6,
+     0xac, 0xab, 0x92, 0x7b, 0xc0, 0xdc, 0x60, 0xee },
+},
+
+
+   /* OCB-AES-128-3B */
+{
+   3,
+   /* key */
+   { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+     0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f },
+   /* nonce */
+   { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 },
+   /* pt */
+   { 0x00, 0x01, 0x02 },
+   /* ct */
+   { 0xfc, 0xd3, 0x7d },
+   /* tag */
+   { 0x02, 0x25, 0x47, 0x39, 0xa5, 0xe3, 0x56, 0x5a,
+     0xe2, 0xdc, 0xd6, 0x2c, 0x65, 0x97, 0x46, 0xba },
+},
+
+   /* OCB-AES-128-16B */
+{
+   16,
+   /* key */
+   { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+     0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f },
+   /* nonce */
+   { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 },
+   /* pt */
+   { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+     0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f },
+   /* ct */
+   { 0x37, 0xdf, 0x8c, 0xe1, 0x5b, 0x48, 0x9b, 0xf3,
+     0x1d, 0x0f, 0xc4, 0x4d, 0xa1, 0xfa, 0xf6, 0xd6 },
+   /* tag */
+   { 0xdf, 0xb7, 0x63, 0xeb, 0xdb, 0x5f, 0x0e, 0x71,
+     0x9c, 0x7b, 0x41, 0x61, 0x80, 0x80, 0x04, 0xdf },
+},
+
+   /* OCB-AES-128-20B  */
+{
+   20,
+   /* key */
+   { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+     0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f },
+   /* nonce */
+   { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 },
+   /* pt */
+   { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+     0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+     0x10, 0x11, 0x12, 0x13 },
+   /* ct */
+   { 0x01, 0xa0, 0x75, 0xf0, 0xd8, 0x15, 0xb1, 0xa4,
+     0xe9, 0xc8, 0x81, 0xa1, 0xbc, 0xff, 0xc3, 0xeb,
+     0x70, 0x03, 0xeb, 0x55},
+   /* tag */
+   { 0x75, 0x30, 0x84, 0x14, 0x4e, 0xb6, 0x3b, 0x77,
+     0x0b, 0x06, 0x3c, 0x2e, 0x23, 0xcd, 0xa0, 0xbb },
+},
+
+   /* OCB-AES-128-32B  */
+{
+   32,
+   /* key */
+   { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+     0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f },
+   /* nonce */
+   { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 },
+   /* pt */
+   { 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 },
+   /* ct */
+   { 0x01, 0xa0, 0x75, 0xf0, 0xd8, 0x15, 0xb1, 0xa4,
+     0xe9, 0xc8, 0x81, 0xa1, 0xbc, 0xff, 0xc3, 0xeb,
+     0x4a, 0xfc, 0xbb, 0x7f, 0xed, 0xc0, 0x8c, 0xa8,
+     0x65, 0x4c, 0x6d, 0x30, 0x4d, 0x16, 0x12, 0xfa },
+
+   /* tag */
+   { 0xc1, 0x4c, 0xbf, 0x2c, 0x1a, 0x1f, 0x1c, 0x3c,
+     0x13, 0x7e, 0xad, 0xea, 0x1f, 0x2f, 0x2f, 0xcf },
+},
+
+   /* OCB-AES-128-34B  */
+{
+   34,
+   /* key */
+   { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+     0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f },
+   /* nonce */
+   { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 },
+   /* pt */
+   { 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,
+     0x20, 0x21 },
+   /* ct */
+   { 0x01, 0xa0, 0x75, 0xf0, 0xd8, 0x15, 0xb1, 0xa4,
+     0xe9, 0xc8, 0x81, 0xa1, 0xbc, 0xff, 0xc3, 0xeb,
+     0xd4, 0x90, 0x3d, 0xd0, 0x02, 0x5b, 0xa4, 0xaa,
+     0x83, 0x7c, 0x74, 0xf1, 0x21, 0xb0, 0x26, 0x0f,
+     0xa9, 0x5d },
+
+   /* tag */
+   { 0xcf, 0x83, 0x41, 0xbb, 0x10, 0x82, 0x0c, 0xcf,
+     0x14, 0xbd, 0xec, 0x56, 0xb8, 0xd7, 0xd6, 0xab },
+},
+
+};
+
+   int err, x, idx, res;
+   unsigned long len;
+   unsigned char outct[MAXBLOCKSIZE], outtag[MAXBLOCKSIZE];
+
+    /* AES can be under rijndael or aes... try to find it */
+    if ((idx = find_cipher("aes")) == -1) {
+       if ((idx = find_cipher("rijndael")) == -1) {
+          return CRYPT_NOP;
+       }
+    }
+
+    for (x = 0; x < (int)(sizeof(tests)/sizeof(tests[0])); x++) {
+        len = sizeof(outtag);
+        if ((err = ocb_encrypt_authenticate_memory(idx, tests[x].key, 16,
+             tests[x].nonce, tests[x].pt, tests[x].ptlen, outct, outtag, &len)) != CRYPT_OK) {
+           return err;
+        }
+
+        if (compare_testvector(outtag, len, tests[x].tag, sizeof(tests[x].tag), "OCB Tag", x) ||
+              compare_testvector(outct, tests[x].ptlen, tests[x].ct, tests[x].ptlen, "OCB CT", x)) {
+           return CRYPT_FAIL_TESTVECTOR;
+        }
+
+        if ((err = ocb_decrypt_verify_memory(idx, tests[x].key, 16, tests[x].nonce, outct, tests[x].ptlen,
+             outct, tests[x].tag, len, &res)) != CRYPT_OK) {
+           return err;
+        }
+        if ((res != 1) || compare_testvector(outct, tests[x].ptlen, tests[x].pt, tests[x].ptlen, "OCB", x)) {
+#ifdef LTC_TEST_DBG
+           printf("\n\nOCB: Failure-decrypt - res = %d\n", res);
+#endif
+           return CRYPT_FAIL_TESTVECTOR;
+        }
+    }
+    return CRYPT_OK;
+#endif /* LTC_TEST */
+}
+
+#endif /* LTC_OCB_MODE */
+
+
+/* some comments
+
+   -- it's hard to seek
+   -- hard to stream [you can't emit ciphertext until full block]
+   -- The setup is somewhat complicated...
+*/
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/encauth/ocb/s_ocb_done.c b/libtomcrypt/src/encauth/ocb/s_ocb_done.c
new file mode 100644 (file)
index 0000000..e0501ed
--- /dev/null
@@ -0,0 +1,146 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+/**
+   @file s_ocb_done.c
+   OCB implementation, internal helper, by Tom St Denis
+*/
+#include "tomcrypt.h"
+
+#ifdef LTC_OCB_MODE
+
+/* Since the last block is encrypted in CTR mode the same code can
+ * be used to finish a decrypt or encrypt stream.  The only difference
+ * is we XOR the final ciphertext into the checksum so we have to xor it
+ * before we CTR [decrypt] or after [encrypt]
+ *
+ * the names pt/ptlen/ct really just mean in/inlen/out but this is the way I wrote it...
+ */
+
+/**
+   Shared code to finish an OCB stream
+   @param ocb    The OCB state
+   @param pt     The remaining plaintext [or input]
+   @param ptlen  The length of the input (octets)
+   @param ct     [out] The output buffer
+   @param tag    [out] The destination for the authentication tag
+   @param taglen [in/out] The max size and resulting size of the authentication tag
+   @param mode   The mode we are terminating, 0==encrypt, 1==decrypt
+   @return       CRYPT_OK if successful
+*/
+int s_ocb_done(ocb_state *ocb, const unsigned char *pt, unsigned long ptlen,
+               unsigned char *ct, unsigned char *tag, unsigned long *taglen, int mode)
+
+{
+   unsigned char *Z, *Y, *X;
+   int err, x;
+
+   LTC_ARGCHK(ocb    != NULL);
+   LTC_ARGCHK(pt     != NULL);
+   LTC_ARGCHK(ct     != NULL);
+   LTC_ARGCHK(tag    != NULL);
+   LTC_ARGCHK(taglen != NULL);
+   if ((err = cipher_is_valid(ocb->cipher)) != CRYPT_OK) {
+      return err;
+   }
+   if (ocb->block_len != cipher_descriptor[ocb->cipher].block_length ||
+       (int)ptlen > ocb->block_len || (int)ptlen < 0) {
+      return CRYPT_INVALID_ARG;
+   }
+
+   /* allocate ram */
+   Z = XMALLOC(MAXBLOCKSIZE);
+   Y = XMALLOC(MAXBLOCKSIZE);
+   X = XMALLOC(MAXBLOCKSIZE);
+   if (X == NULL || Y == NULL || Z == NULL) {
+      if (X != NULL) {
+         XFREE(X);
+      }
+      if (Y != NULL) {
+         XFREE(Y);
+      }
+      if (Z != NULL) {
+         XFREE(Z);
+      }
+      return CRYPT_MEM;
+   }
+
+   /* compute X[m] = len(pt[m]) XOR Lr XOR Z[m] */
+   ocb_shift_xor(ocb, X);
+   XMEMCPY(Z, X, ocb->block_len);
+
+   X[ocb->block_len-1] ^= (ptlen*8)&255;
+   X[ocb->block_len-2] ^= ((ptlen*8)>>8)&255;
+   for (x = 0; x < ocb->block_len; x++) {
+       X[x] ^= ocb->Lr[x];
+   }
+
+   /* Y[m] = E(X[m])) */
+   if ((err = cipher_descriptor[ocb->cipher].ecb_encrypt(X, Y, &ocb->key)) != CRYPT_OK) {
+      goto error;
+   }
+
+   if (mode == 1) {
+      /* decrypt mode, so let's xor it first */
+      /* xor C[m] into checksum */
+      for (x = 0; x < (int)ptlen; x++) {
+         ocb->checksum[x] ^= ct[x];
+      }
+   }
+
+   /* C[m] = P[m] xor Y[m] */
+   for (x = 0; x < (int)ptlen; x++) {
+       ct[x] = pt[x] ^ Y[x];
+   }
+
+   if (mode == 0) {
+      /* encrypt mode */
+      /* xor C[m] into checksum */
+      for (x = 0; x < (int)ptlen; x++) {
+          ocb->checksum[x] ^= ct[x];
+      }
+   }
+
+   /* xor Y[m] and Z[m] into checksum */
+   for (x = 0; x < ocb->block_len; x++) {
+       ocb->checksum[x] ^= Y[x] ^ Z[x];
+   }
+
+   /* encrypt checksum, er... tag!! */
+   if ((err = cipher_descriptor[ocb->cipher].ecb_encrypt(ocb->checksum, X, &ocb->key)) != CRYPT_OK) {
+      goto error;
+   }
+   cipher_descriptor[ocb->cipher].done(&ocb->key);
+
+   /* now store it */
+   for (x = 0; x < ocb->block_len && x < (int)*taglen; x++) {
+       tag[x] = X[x];
+   }
+   *taglen = x;
+
+#ifdef LTC_CLEAN_STACK
+   zeromem(X, MAXBLOCKSIZE);
+   zeromem(Y, MAXBLOCKSIZE);
+   zeromem(Z, MAXBLOCKSIZE);
+   zeromem(ocb, sizeof(*ocb));
+#endif
+error:
+   XFREE(X);
+   XFREE(Y);
+   XFREE(Z);
+
+   return err;
+}
+
+#endif
+
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/encauth/ocb3/ocb3_add_aad.c b/libtomcrypt/src/encauth/ocb3/ocb3_add_aad.c
new file mode 100644 (file)
index 0000000..70e3211
--- /dev/null
@@ -0,0 +1,106 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+/**
+   @file ocb3_add_aad.c
+   OCB implementation, add AAD data, by Karel Miko
+*/
+#include "tomcrypt.h"
+
+#ifdef LTC_OCB3_MODE
+
+/**
+   Add one block of AAD data (internal function)
+   @param ocb        The OCB state
+   @param aad_block  [in] AAD data (block_len size)
+   @return CRYPT_OK if successful
+*/
+static int _ocb3_int_aad_add_block(ocb3_state *ocb, const unsigned char *aad_block)
+{
+   unsigned char tmp[MAXBLOCKSIZE];
+   int err;
+
+   /* Offset_i = Offset_{i-1} xor L_{ntz(i)} */
+   ocb3_int_xor_blocks(ocb->aOffset_current, ocb->aOffset_current, ocb->L_[ocb3_int_ntz(ocb->ablock_index)], ocb->block_len);
+
+   /* Sum_i = Sum_{i-1} xor ENCIPHER(K, A_i xor Offset_i) */
+   ocb3_int_xor_blocks(tmp, aad_block, ocb->aOffset_current, ocb->block_len);
+   if ((err = cipher_descriptor[ocb->cipher].ecb_encrypt(tmp, tmp, &ocb->key)) != CRYPT_OK) {
+     return err;
+   }
+   ocb3_int_xor_blocks(ocb->aSum_current, ocb->aSum_current, tmp, ocb->block_len);
+
+   ocb->ablock_index++;
+
+   return CRYPT_OK;
+}
+
+/**
+   Add AAD - additional associated data
+   @param ocb       The OCB state
+   @param aad       The AAD data
+   @param aadlen    The size of AAD data (octets)
+   @return CRYPT_OK if successful
+*/
+int ocb3_add_aad(ocb3_state *ocb, const unsigned char *aad, unsigned long aadlen)
+{
+   int err, x, full_blocks, full_blocks_len, last_block_len;
+   unsigned char *data;
+   unsigned long datalen, l;
+
+   LTC_ARGCHK(ocb != NULL);
+   if (aadlen == 0) return CRYPT_OK;
+   LTC_ARGCHK(aad != NULL);
+
+   if (ocb->adata_buffer_bytes > 0) {
+     l = ocb->block_len - ocb->adata_buffer_bytes;
+     if (l > aadlen) l = aadlen;
+     XMEMCPY(ocb->adata_buffer+ocb->adata_buffer_bytes, aad, l);
+     ocb->adata_buffer_bytes += l;
+
+     if (ocb->adata_buffer_bytes == ocb->block_len) {
+       if ((err = _ocb3_int_aad_add_block(ocb, ocb->adata_buffer)) != CRYPT_OK) {
+         return err;
+       }
+       ocb->adata_buffer_bytes = 0;
+     }
+
+     data = (unsigned char *)aad + l;
+     datalen = aadlen - l;
+   }
+   else {
+     data = (unsigned char *)aad;
+     datalen = aadlen;
+   }
+
+   if (datalen == 0) return CRYPT_OK;
+
+   full_blocks = datalen/ocb->block_len;
+   full_blocks_len = full_blocks * ocb->block_len;
+   last_block_len = datalen - full_blocks_len;
+
+   for (x=0; x<full_blocks; x++) {
+     if ((err = _ocb3_int_aad_add_block(ocb, data+x*ocb->block_len)) != CRYPT_OK) {
+       return err;
+     }
+   }
+
+   if (last_block_len>0) {
+     XMEMCPY(ocb->adata_buffer, data+full_blocks_len, last_block_len);
+     ocb->adata_buffer_bytes = last_block_len;
+   }
+
+   return CRYPT_OK;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/encauth/ocb3/ocb3_decrypt.c b/libtomcrypt/src/encauth/ocb3/ocb3_decrypt.c
new file mode 100644 (file)
index 0000000..4973bd2
--- /dev/null
@@ -0,0 +1,86 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+/**
+   @file ocb3_decrypt.c
+   OCB implementation, decrypt data, by Tom St Denis
+*/
+#include "tomcrypt.h"
+
+#ifdef LTC_OCB3_MODE
+
+/**
+   Decrypt blocks of ciphertext with OCB
+   @param ocb     The OCB state
+   @param ct      The ciphertext (length multiple of the block size of the block cipher)
+   @param ctlen   The length of the input (octets)
+   @param pt      [out] The plaintext (length of ct)
+   @return CRYPT_OK if successful
+*/
+int ocb3_decrypt(ocb3_state *ocb, const unsigned char *ct, unsigned long ctlen, unsigned char *pt)
+{
+   unsigned char tmp[MAXBLOCKSIZE];
+   int err, i, full_blocks;
+   unsigned char *pt_b, *ct_b;
+
+   LTC_ARGCHK(ocb != NULL);
+   if (ctlen == 0) return CRYPT_OK; /* no data, nothing to do */
+   LTC_ARGCHK(ct != NULL);
+   LTC_ARGCHK(pt != NULL);
+
+   if ((err = cipher_is_valid(ocb->cipher)) != CRYPT_OK) {
+      return err;
+   }
+   if (ocb->block_len != cipher_descriptor[ocb->cipher].block_length) {
+      return CRYPT_INVALID_ARG;
+   }
+
+   if (ctlen % ocb->block_len) { /* ctlen has to bu multiple of block_len */
+      return CRYPT_INVALID_ARG;
+   }
+
+   full_blocks = ctlen/ocb->block_len;
+   for(i=0; i<full_blocks; i++) {
+     pt_b = (unsigned char *)pt+i*ocb->block_len;
+     ct_b = (unsigned char *)ct+i*ocb->block_len;
+
+     /* ocb->Offset_current[] = ocb->Offset_current[] ^ Offset_{ntz(block_index)} */
+     ocb3_int_xor_blocks(ocb->Offset_current, ocb->Offset_current, ocb->L_[ocb3_int_ntz(ocb->block_index)], ocb->block_len);
+
+     /* tmp[] = ct[] XOR ocb->Offset_current[] */
+     ocb3_int_xor_blocks(tmp, ct_b, ocb->Offset_current, ocb->block_len);
+
+     /* decrypt */
+     if ((err = cipher_descriptor[ocb->cipher].ecb_decrypt(tmp, tmp, &ocb->key)) != CRYPT_OK) {
+        goto LBL_ERR;
+     }
+
+     /* pt[] = tmp[] XOR ocb->Offset_current[] */
+     ocb3_int_xor_blocks(pt_b, tmp, ocb->Offset_current, ocb->block_len);
+
+     /* ocb->checksum[] = ocb->checksum[] XOR pt[] */
+     ocb3_int_xor_blocks(ocb->checksum, ocb->checksum, pt_b, ocb->block_len);
+
+     ocb->block_index++;
+   }
+
+   err = CRYPT_OK;
+
+LBL_ERR:
+#ifdef LTC_CLEAN_STACK
+   zeromem(tmp, sizeof(tmp));
+#endif
+   return err;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/encauth/ocb3/ocb3_decrypt_last.c b/libtomcrypt/src/encauth/ocb3/ocb3_decrypt_last.c
new file mode 100644 (file)
index 0000000..70608dc
--- /dev/null
@@ -0,0 +1,110 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+/**
+   @file ocb3_decrypt_last.c
+   OCB implementation, internal helper, by Karel Miko
+*/
+#include "tomcrypt.h"
+
+#ifdef LTC_OCB3_MODE
+
+/**
+   Finish an OCB (decryption) stream
+   @param ocb    The OCB state
+   @param ct     The remaining ciphertext
+   @param ctlen  The length of the ciphertext (octets)
+   @param pt     [out] The output buffer
+   @return CRYPT_OK if successful
+*/
+int ocb3_decrypt_last(ocb3_state *ocb, const unsigned char *ct, unsigned long ctlen, unsigned char *pt)
+{
+   unsigned char iOffset_star[MAXBLOCKSIZE];
+   unsigned char iPad[MAXBLOCKSIZE];
+   int err, x, full_blocks, full_blocks_len, last_block_len;
+
+   LTC_ARGCHK(ocb != NULL);
+   if (ct == NULL) LTC_ARGCHK(ctlen == 0);
+   if (ctlen != 0) {
+      LTC_ARGCHK(ct    != NULL);
+      LTC_ARGCHK(pt    != NULL);
+   }
+
+   if ((err = cipher_is_valid(ocb->cipher)) != CRYPT_OK) {
+      goto LBL_ERR;
+   }
+
+   full_blocks = ctlen/ocb->block_len;
+   full_blocks_len = full_blocks * ocb->block_len;
+   last_block_len = ctlen - full_blocks_len;
+
+   /* process full blocks first */
+   if (full_blocks>0) {
+     if ((err = ocb3_decrypt(ocb, ct, full_blocks_len, pt)) != CRYPT_OK) {
+       goto LBL_ERR;
+     }
+   }
+
+   if (last_block_len>0) {
+     /* Offset_* = Offset_m xor L_* */
+     ocb3_int_xor_blocks(iOffset_star, ocb->Offset_current, ocb->L_star, ocb->block_len);
+
+     /* Pad = ENCIPHER(K, Offset_*) */
+     if ((err = cipher_descriptor[ocb->cipher].ecb_encrypt(iOffset_star, iPad, &ocb->key)) != CRYPT_OK) {
+       goto LBL_ERR;
+     }
+
+     /* P_* = C_* xor Pad[1..bitlen(C_*)] */
+     ocb3_int_xor_blocks(pt+full_blocks_len, (unsigned char *)ct+full_blocks_len, iPad, last_block_len);
+
+     /* Checksum_* = Checksum_m xor (P_* || 1 || zeros(127-bitlen(P_*))) */
+     ocb3_int_xor_blocks(ocb->checksum, ocb->checksum, pt+full_blocks_len, last_block_len);
+     for(x=last_block_len; x<ocb->block_len; x++) {
+       if (x == last_block_len)
+         ocb->checksum[x] ^= 0x80;
+       else
+         ocb->checksum[x] ^= 0x00;
+     }
+
+     /* Tag = ENCIPHER(K, Checksum_* xor Offset_* xor L_$) xor HASH(K,A) */
+     /* at this point we calculate only: Tag_part = ENCIPHER(K, Checksum_* xor Offset_* xor L_$) */
+     for(x=0; x<ocb->block_len; x++) {
+       ocb->tag_part[x] = (ocb->checksum[x] ^ iOffset_star[x]) ^ ocb->L_dollar[x];
+     }
+     if ((err = cipher_descriptor[ocb->cipher].ecb_encrypt(ocb->tag_part, ocb->tag_part, &ocb->key)) != CRYPT_OK) {
+       goto LBL_ERR;
+     }
+   }
+   else {
+     /* Tag = ENCIPHER(K, Checksum_m xor Offset_m xor L_$) xor HASH(K,A) */
+     /* at this point we calculate only: Tag_part = ENCIPHER(K, Checksum_m xor Offset_m xor L_$) */
+     for(x=0; x<ocb->block_len; x++) {
+       ocb->tag_part[x] = (ocb->checksum[x] ^ ocb->Offset_current[x]) ^ ocb->L_dollar[x];
+     }
+     if ((err = cipher_descriptor[ocb->cipher].ecb_encrypt(ocb->tag_part, ocb->tag_part, &ocb->key)) != CRYPT_OK) {
+       goto LBL_ERR;
+     }
+   }
+
+   err = CRYPT_OK;
+
+LBL_ERR:
+#ifdef LTC_CLEAN_STACK
+   zeromem(iOffset_star, MAXBLOCKSIZE);
+   zeromem(iPad, MAXBLOCKSIZE);
+#endif
+
+   return err;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/encauth/ocb3/ocb3_decrypt_verify_memory.c b/libtomcrypt/src/encauth/ocb3/ocb3_decrypt_verify_memory.c
new file mode 100644 (file)
index 0000000..066b62c
--- /dev/null
@@ -0,0 +1,110 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+/**
+  @file ocb3_decrypt_verify_memory.c
+  OCB implementation, helper to decrypt block of memory, by Tom St Denis
+*/
+#include "tomcrypt.h"
+
+#ifdef LTC_OCB3_MODE
+
+/**
+   Decrypt and compare the tag with OCB
+   @param cipher     The index of the cipher desired
+   @param key        The secret key
+   @param keylen     The length of the secret key (octets)
+   @param nonce      The session nonce (length of the block size of the block cipher)
+   @param noncelen   The length of the nonce (octets)
+   @param adata      The AAD - additional associated data
+   @param adatalen   The length of AAD (octets)
+   @param ct         The ciphertext
+   @param ctlen      The length of the ciphertext (octets)
+   @param pt         [out] The plaintext
+   @param tag        The tag to compare against
+   @param taglen     The length of the tag (octets)
+   @param stat       [out] The result of the tag comparison (1==valid, 0==invalid)
+   @return CRYPT_OK if successful regardless of the tag comparison
+*/
+int ocb3_decrypt_verify_memory(int cipher,
+    const unsigned char *key,    unsigned long keylen,
+    const unsigned char *nonce,  unsigned long noncelen,
+    const unsigned char *adata,  unsigned long adatalen,
+    const unsigned char *ct,     unsigned long ctlen,
+          unsigned char *pt,
+    const unsigned char *tag,    unsigned long taglen,
+          int           *stat)
+{
+   int            err;
+   ocb3_state     *ocb;
+   unsigned char *buf;
+   unsigned long  buflen;
+
+   LTC_ARGCHK(stat    != NULL);
+
+   /* default to zero */
+   *stat = 0;
+
+   /* limit taglen */
+   taglen = MIN(taglen, MAXBLOCKSIZE);
+
+   /* allocate memory */
+   buf = XMALLOC(taglen);
+   ocb = XMALLOC(sizeof(ocb3_state));
+   if (ocb == NULL || buf == NULL) {
+      if (ocb != NULL) {
+         XFREE(ocb);
+      }
+      if (buf != NULL) {
+         XFREE(buf);
+      }
+      return CRYPT_MEM;
+   }
+
+   if ((err = ocb3_init(ocb, cipher, key, keylen, nonce, noncelen, taglen)) != CRYPT_OK) {
+      goto LBL_ERR;
+   }
+
+   if (adata != NULL || adatalen != 0) {
+      if ((err = ocb3_add_aad(ocb, adata, adatalen)) != CRYPT_OK) {
+         goto LBL_ERR;
+      }
+   }
+
+   if ((err = ocb3_decrypt_last(ocb, ct, ctlen, pt)) != CRYPT_OK) {
+      goto LBL_ERR;
+   }
+
+   buflen = taglen;
+   if ((err = ocb3_done(ocb, buf, &buflen)) != CRYPT_OK) {
+      goto LBL_ERR;
+   }
+
+   /* compare tags */
+   if (buflen >= taglen && XMEM_NEQ(buf, tag, taglen) == 0) {
+      *stat = 1;
+   }
+
+   err = CRYPT_OK;
+
+LBL_ERR:
+#ifdef LTC_CLEAN_STACK
+   zeromem(ocb, sizeof(ocb3_state));
+#endif
+
+   XFREE(ocb);
+   XFREE(buf);
+   return err;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/encauth/ocb3/ocb3_done.c b/libtomcrypt/src/encauth/ocb3/ocb3_done.c
new file mode 100644 (file)
index 0000000..b913d3a
--- /dev/null
@@ -0,0 +1,92 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+/**
+   @file ocb3_done.c
+   OCB implementation, INTERNAL ONLY helper, by Tom St Denis
+*/
+#include "tomcrypt.h"
+
+#ifdef LTC_OCB3_MODE
+
+/**
+   Finish OCB processing and compute the tag
+   @param ocb     The OCB state
+   @param tag     [out] The destination for the authentication tag
+   @param taglen  [in/out] The max size and resulting size of the authentication tag
+   @return CRYPT_OK if successful
+*/
+int ocb3_done(ocb3_state *ocb, unsigned char *tag, unsigned long *taglen)
+{
+   unsigned char tmp[MAXBLOCKSIZE];
+   int err, x;
+
+   LTC_ARGCHK(ocb    != NULL);
+   LTC_ARGCHK(tag    != NULL);
+   LTC_ARGCHK(taglen != NULL);
+   if ((err = cipher_is_valid(ocb->cipher)) != CRYPT_OK) {
+      goto LBL_ERR;
+   }
+
+   /* check taglen */
+   if ((int)*taglen < ocb->tag_len) {
+      *taglen = (unsigned long)ocb->tag_len;
+      return CRYPT_BUFFER_OVERFLOW;
+   }
+
+   /* finalize AAD processing */
+
+   if (ocb->adata_buffer_bytes>0) {
+     /* Offset_* = Offset_m xor L_* */
+     ocb3_int_xor_blocks(ocb->aOffset_current, ocb->aOffset_current, ocb->L_star, ocb->block_len);
+
+     /* CipherInput = (A_* || 1 || zeros(127-bitlen(A_*))) xor Offset_* */
+     ocb3_int_xor_blocks(tmp, ocb->adata_buffer, ocb->aOffset_current, ocb->adata_buffer_bytes);
+     for(x=ocb->adata_buffer_bytes; x<ocb->block_len; x++) {
+       if (x == ocb->adata_buffer_bytes) {
+         tmp[x] = 0x80 ^ ocb->aOffset_current[x];
+       }
+       else {
+         tmp[x] = 0x00 ^ ocb->aOffset_current[x];
+       }
+     }
+
+     /* Sum = Sum_m xor ENCIPHER(K, CipherInput) */
+     if ((err = cipher_descriptor[ocb->cipher].ecb_encrypt(tmp, tmp, &ocb->key)) != CRYPT_OK) {
+       goto LBL_ERR;
+     }
+     ocb3_int_xor_blocks(ocb->aSum_current, ocb->aSum_current, tmp, ocb->block_len);
+   }
+
+   /* finalize TAG computing */
+
+   /* at this point ocb->aSum_current = HASH(K, A) */
+   /* tag = tag ^ HASH(K, A) */
+   ocb3_int_xor_blocks(tmp, ocb->tag_part, ocb->aSum_current, ocb->block_len);
+
+   /* copy tag bytes */
+   for(x = 0; x < ocb->tag_len; x++) tag[x] = tmp[x];
+   *taglen = (unsigned long)ocb->tag_len;
+
+   err = CRYPT_OK;
+
+LBL_ERR:
+#ifdef LTC_CLEAN_STACK
+   zeromem(tmp, MAXBLOCKSIZE);
+   zeromem(ocb, sizeof(*ocb));
+#endif
+
+   return err;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/encauth/ocb3/ocb3_encrypt.c b/libtomcrypt/src/encauth/ocb3/ocb3_encrypt.c
new file mode 100644 (file)
index 0000000..337b025
--- /dev/null
@@ -0,0 +1,86 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+/**
+   @file ocb3_encrypt.c
+   OCB implementation, encrypt data, by Tom St Denis
+*/
+#include "tomcrypt.h"
+
+#ifdef LTC_OCB3_MODE
+
+/**
+   Encrypt blocks of data with OCB
+   @param ocb     The OCB state
+   @param pt      The plaintext (length multiple of the block size of the block cipher)
+   @param ptlen   The length of the input (octets)
+   @param ct      [out] The ciphertext (same size as the pt)
+   @return CRYPT_OK if successful
+*/
+int ocb3_encrypt(ocb3_state *ocb, const unsigned char *pt, unsigned long ptlen, unsigned char *ct)
+{
+   unsigned char tmp[MAXBLOCKSIZE];
+   int err, i, full_blocks;
+   unsigned char *pt_b, *ct_b;
+
+   LTC_ARGCHK(ocb != NULL);
+   if (ptlen == 0) return CRYPT_OK; /* no data, nothing to do */
+   LTC_ARGCHK(pt != NULL);
+   LTC_ARGCHK(ct != NULL);
+
+   if ((err = cipher_is_valid(ocb->cipher)) != CRYPT_OK) {
+      return err;
+   }
+   if (ocb->block_len != cipher_descriptor[ocb->cipher].block_length) {
+      return CRYPT_INVALID_ARG;
+   }
+
+   if (ptlen % ocb->block_len) { /* ptlen has to bu multiple of block_len */
+      return CRYPT_INVALID_ARG;
+   }
+
+   full_blocks = ptlen/ocb->block_len;
+   for(i=0; i<full_blocks; i++) {
+     pt_b = (unsigned char *)pt+i*ocb->block_len;
+     ct_b = (unsigned char *)ct+i*ocb->block_len;
+
+     /* ocb->Offset_current[] = ocb->Offset_current[] ^ Offset_{ntz(block_index)} */
+     ocb3_int_xor_blocks(ocb->Offset_current, ocb->Offset_current, ocb->L_[ocb3_int_ntz(ocb->block_index)], ocb->block_len);
+
+     /* tmp[] = pt[] XOR ocb->Offset_current[] */
+     ocb3_int_xor_blocks(tmp, pt_b, ocb->Offset_current, ocb->block_len);
+
+     /* encrypt */
+     if ((err = cipher_descriptor[ocb->cipher].ecb_encrypt(tmp, tmp, &ocb->key)) != CRYPT_OK) {
+        goto LBL_ERR;
+     }
+
+     /* ct[] = tmp[] XOR ocb->Offset_current[] */
+     ocb3_int_xor_blocks(ct_b, tmp, ocb->Offset_current, ocb->block_len);
+
+     /* ocb->checksum[] = ocb->checksum[] XOR pt[] */
+     ocb3_int_xor_blocks(ocb->checksum, ocb->checksum, pt_b, ocb->block_len);
+
+     ocb->block_index++;
+   }
+
+   err = CRYPT_OK;
+
+LBL_ERR:
+#ifdef LTC_CLEAN_STACK
+   zeromem(tmp, sizeof(tmp));
+#endif
+   return err;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/encauth/ocb3/ocb3_encrypt_authenticate_memory.c b/libtomcrypt/src/encauth/ocb3/ocb3_encrypt_authenticate_memory.c
new file mode 100644 (file)
index 0000000..efc1a8f
--- /dev/null
@@ -0,0 +1,82 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+/**
+  @file ocb3_encrypt_authenticate_memory.c
+  OCB implementation, encrypt block of memory, by Tom St Denis
+*/
+#include "tomcrypt.h"
+
+#ifdef LTC_OCB3_MODE
+
+/**
+   Encrypt and generate an authentication code for a buffer of memory
+   @param cipher     The index of the cipher desired
+   @param key        The secret key
+   @param keylen     The length of the secret key (octets)
+   @param nonce      The session nonce (length of the block ciphers block size)
+   @param noncelen   The length of the nonce (octets)
+   @param adata      The AAD - additional associated data
+   @param adatalen   The length of AAD (octets)
+   @param pt         The plaintext
+   @param ptlen      The length of the plaintext (octets)
+   @param ct         [out] The ciphertext
+   @param tag        [out] The authentication tag
+   @param taglen     [in/out] The max size and resulting size of the authentication tag
+   @return CRYPT_OK if successful
+*/
+int ocb3_encrypt_authenticate_memory(int cipher,
+    const unsigned char *key,    unsigned long keylen,
+    const unsigned char *nonce,  unsigned long noncelen,
+    const unsigned char *adata,  unsigned long adatalen,
+    const unsigned char *pt,     unsigned long ptlen,
+          unsigned char *ct,
+          unsigned char *tag,    unsigned long *taglen)
+{
+   int err;
+   ocb3_state *ocb;
+
+   LTC_ARGCHK(taglen != NULL);
+
+   /* allocate memory */
+   ocb = XMALLOC(sizeof(ocb3_state));
+   if (ocb == NULL) {
+      return CRYPT_MEM;
+   }
+
+   if ((err = ocb3_init(ocb, cipher, key, keylen, nonce, noncelen, *taglen)) != CRYPT_OK) {
+      goto LBL_ERR;
+   }
+
+   if (adata != NULL || adatalen != 0) {
+      if ((err = ocb3_add_aad(ocb, adata, adatalen)) != CRYPT_OK) {
+         goto LBL_ERR;
+      }
+   }
+
+   if ((err = ocb3_encrypt_last(ocb, pt, ptlen, ct)) != CRYPT_OK) {
+      goto LBL_ERR;
+   }
+
+   err = ocb3_done(ocb, tag, taglen);
+
+LBL_ERR:
+#ifdef LTC_CLEAN_STACK
+   zeromem(ocb, sizeof(ocb3_state));
+#endif
+
+   XFREE(ocb);
+   return err;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/encauth/ocb3/ocb3_encrypt_last.c b/libtomcrypt/src/encauth/ocb3/ocb3_encrypt_last.c
new file mode 100644 (file)
index 0000000..8110a3c
--- /dev/null
@@ -0,0 +1,112 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+/**
+   @file ocb3_encrypt_last.c
+   OCB implementation, internal helper, by Karel Miko
+*/
+#include "tomcrypt.h"
+
+#ifdef LTC_OCB3_MODE
+
+/**
+   Finish an OCB (encryption) stream
+   @param ocb    The OCB state
+   @param pt     The remaining plaintext
+   @param ptlen  The length of the plaintext (octets)
+   @param ct     [out] The output buffer
+   @return CRYPT_OK if successful
+*/
+int ocb3_encrypt_last(ocb3_state *ocb, const unsigned char *pt, unsigned long ptlen, unsigned char *ct)
+{
+   unsigned char iOffset_star[MAXBLOCKSIZE];
+   unsigned char iPad[MAXBLOCKSIZE];
+   int err, x, full_blocks, full_blocks_len, last_block_len;
+
+   LTC_ARGCHK(ocb != NULL);
+   if (pt == NULL) LTC_ARGCHK(ptlen == 0);
+   if (ptlen != 0) {
+      LTC_ARGCHK(pt    != NULL);
+      LTC_ARGCHK(ct    != NULL);
+   }
+
+   if ((err = cipher_is_valid(ocb->cipher)) != CRYPT_OK) {
+      goto LBL_ERR;
+   }
+
+   full_blocks = ptlen/ocb->block_len;
+   full_blocks_len = full_blocks * ocb->block_len;
+   last_block_len = ptlen - full_blocks_len;
+
+   /* process full blocks first */
+   if (full_blocks>0) {
+     if ((err = ocb3_encrypt(ocb, pt, full_blocks_len, ct)) != CRYPT_OK) {
+       goto LBL_ERR;
+     }
+   }
+
+   /* at this point: m = ocb->block_index (last block index), Offset_m = ocb->Offset_current */
+
+   if (last_block_len>0) {
+     /* Offset_* = Offset_m xor L_* */
+     ocb3_int_xor_blocks(iOffset_star, ocb->Offset_current, ocb->L_star, ocb->block_len);
+
+     /* Pad = ENCIPHER(K, Offset_*) */
+     if ((err = cipher_descriptor[ocb->cipher].ecb_encrypt(iOffset_star, iPad, &ocb->key)) != CRYPT_OK) {
+       goto LBL_ERR;
+     }
+
+     /* C_* = P_* xor Pad[1..bitlen(P_*)] */
+     ocb3_int_xor_blocks(ct+full_blocks_len, pt+full_blocks_len, iPad, last_block_len);
+
+     /* Checksum_* = Checksum_m xor (P_* || 1 || zeros(127-bitlen(P_*))) */
+     ocb3_int_xor_blocks(ocb->checksum, ocb->checksum, pt+full_blocks_len, last_block_len);
+     for(x=last_block_len; x<ocb->block_len; x++) {
+       if (x == last_block_len)
+         ocb->checksum[x] ^= 0x80;
+       else
+         ocb->checksum[x] ^= 0x00;
+     }
+
+     /* Tag = ENCIPHER(K, Checksum_* xor Offset_* xor L_$) xor HASH(K,A) */
+     /* at this point we calculate only: Tag_part = ENCIPHER(K, Checksum_* xor Offset_* xor L_$) */
+     for(x=0; x<ocb->block_len; x++) {
+       ocb->tag_part[x] = (ocb->checksum[x] ^ iOffset_star[x]) ^ ocb->L_dollar[x];
+     }
+     if ((err = cipher_descriptor[ocb->cipher].ecb_encrypt(ocb->tag_part, ocb->tag_part, &ocb->key)) != CRYPT_OK) {
+       goto LBL_ERR;
+     }
+   }
+   else {
+     /* Tag = ENCIPHER(K, Checksum_m xor Offset_m xor L_$) xor HASH(K,A) */
+     /* at this point we calculate only: Tag_part = ENCIPHER(K, Checksum_m xor Offset_m xor L_$) */
+     for(x=0; x<ocb->block_len; x++) {
+       ocb->tag_part[x] = (ocb->checksum[x] ^ ocb->Offset_current[x]) ^ ocb->L_dollar[x];
+     }
+     if ((err = cipher_descriptor[ocb->cipher].ecb_encrypt(ocb->tag_part, ocb->tag_part, &ocb->key)) != CRYPT_OK) {
+       goto LBL_ERR;
+     }
+   }
+
+   err = CRYPT_OK;
+
+LBL_ERR:
+#ifdef LTC_CLEAN_STACK
+   zeromem(iOffset_star, MAXBLOCKSIZE);
+   zeromem(iPad, MAXBLOCKSIZE);
+#endif
+
+   return err;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/encauth/ocb3/ocb3_init.c b/libtomcrypt/src/encauth/ocb3/ocb3_init.c
new file mode 100644 (file)
index 0000000..a3cabae
--- /dev/null
@@ -0,0 +1,196 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+/**
+   @file ocb3_init.c
+   OCB implementation, initialize state, by Tom St Denis
+*/
+#include "tomcrypt.h"
+
+#ifdef LTC_OCB3_MODE
+
+static void _ocb3_int_calc_offset_zero(ocb3_state *ocb, const unsigned char *nonce, unsigned long noncelen, unsigned long taglen)
+{
+   int x, y, bottom;
+   int idx, shift;
+   unsigned char iNonce[MAXBLOCKSIZE];
+   unsigned char iKtop[MAXBLOCKSIZE];
+   unsigned char iStretch[MAXBLOCKSIZE+8];
+
+   /* Nonce = zeros(127-bitlen(N)) || 1 || N          */
+   zeromem(iNonce, sizeof(iNonce));
+   for (x = ocb->block_len-1, y=0; y<(int)noncelen; x--, y++) {
+     iNonce[x] = nonce[noncelen-y-1];
+   }
+   iNonce[x] = 0x01;
+   iNonce[0] |= ((taglen*8) % 128) << 1;
+
+   /* bottom = str2num(Nonce[123..128])               */
+   bottom = iNonce[ocb->block_len-1] & 0x3F;
+
+   /* Ktop = ENCIPHER(K, Nonce[1..122] || zeros(6))   */
+   iNonce[ocb->block_len-1] = iNonce[ocb->block_len-1] & 0xC0;
+   if ((cipher_descriptor[ocb->cipher].ecb_encrypt(iNonce, iKtop, &ocb->key)) != CRYPT_OK) {
+      zeromem(ocb->Offset_current, ocb->block_len);
+      return;
+   }
+
+   /* Stretch = Ktop || (Ktop[1..64] xor Ktop[9..72]) */
+   for (x = 0; x < ocb->block_len; x++) {
+     iStretch[x] = iKtop[x];
+   }
+   for (y = 0; y < 8; y++) {
+     iStretch[x+y] = iKtop[y] ^ iKtop[y+1];
+   }
+
+   /* Offset_0 = Stretch[1+bottom..128+bottom]        */
+   idx = bottom / 8;
+   shift = (bottom % 8);
+   for (x = 0; x < ocb->block_len; x++) {
+      ocb->Offset_current[x] = iStretch[idx+x] << shift;
+      if (shift > 0) {
+        ocb->Offset_current[x] |= iStretch[idx+x+1] >> (8-shift);
+      }
+   }
+}
+
+static const struct {
+    int           len;
+    unsigned char poly_mul[MAXBLOCKSIZE];
+} polys[] = {
+{
+    8,
+    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1B }
+}, {
+    16,
+    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x87 }
+}
+};
+
+/**
+   Initialize an OCB context
+   @param ocb       [out] The destination of the OCB state
+   @param cipher    The index of the desired cipher
+   @param key       The secret key
+   @param keylen    The length of the secret key (octets)
+   @param nonce     The session nonce
+   @param noncelen  The length of the session nonce (octets, up to 15)
+   @param taglen    The length of the tag (octets, up to 16)
+   @return CRYPT_OK if successful
+*/
+int ocb3_init(ocb3_state *ocb, int cipher,
+             const unsigned char *key, unsigned long keylen,
+             const unsigned char *nonce, unsigned long noncelen,
+             unsigned long taglen)
+{
+   int poly, x, y, m, err;
+   unsigned char *previous, *current;
+
+   LTC_ARGCHK(ocb   != NULL);
+   LTC_ARGCHK(key   != NULL);
+   LTC_ARGCHK(nonce != NULL);
+
+   /* valid cipher? */
+   if ((err = cipher_is_valid(cipher)) != CRYPT_OK) {
+      return err;
+   }
+   ocb->cipher = cipher;
+
+   /* Valid Nonce?
+    * As of RFC7253: "string of no more than 120 bits" */
+   if (noncelen > (120/8)) {
+      return CRYPT_INVALID_ARG;
+   }
+
+   /* The blockcipher must have a 128-bit blocksize */
+   if (cipher_descriptor[cipher].block_length != 16) {
+      return CRYPT_INVALID_ARG;
+   }
+
+   /* The TAGLEN may be any value up to 128 (bits) */
+   if (taglen > 16) {
+      return CRYPT_INVALID_ARG;
+   }
+   ocb->tag_len = taglen;
+
+   /* determine which polys to use */
+   ocb->block_len = cipher_descriptor[cipher].block_length;
+   x = (int)(sizeof(polys)/sizeof(polys[0]));
+   for (poly = 0; poly < x; poly++) {
+       if (polys[poly].len == ocb->block_len) {
+          break;
+       }
+   }
+   if (poly == x) {
+      return CRYPT_INVALID_ARG; /* block_len not found in polys */
+   }
+   if (polys[poly].len != ocb->block_len) {
+      return CRYPT_INVALID_ARG;
+   }
+
+   /* schedule the key */
+   if ((err = cipher_descriptor[cipher].setup(key, keylen, 0, &ocb->key)) != CRYPT_OK) {
+      return err;
+   }
+
+   /* L_* = ENCIPHER(K, zeros(128)) */
+   zeromem(ocb->L_star, ocb->block_len);
+   if ((err = cipher_descriptor[cipher].ecb_encrypt(ocb->L_star, ocb->L_star, &ocb->key)) != CRYPT_OK) {
+      return err;
+   }
+
+   /* compute L_$, L_0, L_1, ... */
+   for (x = -1; x < 32; x++) {
+      if (x == -1) {                /* gonna compute: L_$ = double(L_*) */
+         current  = ocb->L_dollar;
+         previous = ocb->L_star;
+      }
+      else if (x == 0) {            /* gonna compute: L_0 = double(L_$) */
+         current  = ocb->L_[0];
+         previous = ocb->L_dollar;
+      }
+      else {                        /* gonna compute: L_i = double(L_{i-1}) for every integer i > 0 */
+         current  = ocb->L_[x];
+         previous = ocb->L_[x-1];
+      }
+      m = previous[0] >> 7;
+      for (y = 0; y < ocb->block_len-1; y++) {
+         current[y] = ((previous[y] << 1) | (previous[y+1] >> 7)) & 255;
+      }
+      current[ocb->block_len-1] = (previous[ocb->block_len-1] << 1) & 255;
+      if (m == 1) {
+         /* current[] = current[] XOR polys[poly].poly_mul[]*/
+         ocb3_int_xor_blocks(current, current, polys[poly].poly_mul, ocb->block_len);
+      }
+   }
+
+   /* initialize ocb->Offset_current = Offset_0 */
+   _ocb3_int_calc_offset_zero(ocb, nonce, noncelen, taglen);
+
+   /* initialize checksum to all zeros */
+   zeromem(ocb->checksum, ocb->block_len);
+
+   /* set block index */
+   ocb->block_index = 1;
+
+   /* initialize AAD related stuff */
+   ocb->ablock_index = 1;
+   ocb->adata_buffer_bytes = 0;
+   zeromem(ocb->aOffset_current, ocb->block_len);
+   zeromem(ocb->aSum_current, ocb->block_len);
+
+   return CRYPT_OK;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/encauth/ocb3/ocb3_int_ntz.c b/libtomcrypt/src/encauth/ocb3/ocb3_int_ntz.c
new file mode 100644 (file)
index 0000000..3c5b18d
--- /dev/null
@@ -0,0 +1,39 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+/**
+   @file ocb3_int_ntz.c
+   OCB implementation, INTERNAL ONLY helper, by Tom St Denis
+*/
+#include "tomcrypt.h"
+
+#ifdef LTC_OCB3_MODE
+
+/**
+   Returns the number of leading zero bits [from lsb up] (internal function)
+   @param x  The 32-bit value to observe
+   @return The number of bits [from the lsb up] that are zero
+*/
+int ocb3_int_ntz(unsigned long x)
+{
+   int c;
+   x &= 0xFFFFFFFFUL;
+   c = 0;
+   while ((x & 1) == 0) {
+      ++c;
+      x >>= 1;
+   }
+   return c;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/encauth/ocb3/ocb3_int_xor_blocks.c b/libtomcrypt/src/encauth/ocb3/ocb3_int_xor_blocks.c
new file mode 100644 (file)
index 0000000..798bddc
--- /dev/null
@@ -0,0 +1,40 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+/**
+   @file ocb3_int_xor_blocks.c
+   OCB implementation, INTERNAL ONLY helper, by Karel Miko
+*/
+#include "tomcrypt.h"
+
+#ifdef LTC_OCB3_MODE
+
+/**
+   Compute xor for two blocks of bytes 'out = block_a XOR block_b' (internal function)
+   @param out        The block of bytes (output)
+   @param block_a    The block of bytes (input)
+   @param block_b    The block of bytes (input)
+   @param block_len  The size of block_a, block_b, out
+*/
+void ocb3_int_xor_blocks(unsigned char *out, const unsigned char *block_a, const unsigned char *block_b, unsigned long block_len)
+{
+   int x;
+   if (out == block_a) {
+     for (x = 0; x < (int)block_len; x++) out[x] ^= block_b[x];
+   }
+   else {
+     for (x = 0; x < (int)block_len; x++) out[x] = block_a[x] ^ block_b[x];
+   }
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/encauth/ocb3/ocb3_test.c b/libtomcrypt/src/encauth/ocb3/ocb3_test.c
new file mode 100644 (file)
index 0000000..a3e5062
--- /dev/null
@@ -0,0 +1,309 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+/**
+   @file ocb3_test.c
+   OCB implementation, self-test by Tom St Denis
+*/
+#include "tomcrypt.h"
+
+#ifdef LTC_OCB3_MODE
+
+/**
+   Test the OCB protocol
+   @return CRYPT_OK if successful
+*/
+int ocb3_test(void)
+{
+#ifndef LTC_TEST
+   return CRYPT_NOP;
+#else
+   /* test vectors from: http://tools.ietf.org/html/draft-krovetz-ocb-03 */
+   unsigned char key[16]   = { 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F };
+   unsigned char nonce[12] = { 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B };
+   const struct {
+         int ptlen;
+         int aadlen;
+         unsigned char pt[64], aad[64], ct[64], tag[16];
+   } tests[] = {
+
+   { /* index:0 */
+     0, /* PLAINTEXT length */
+     0, /* AAD length */
+     { 0 }, /* PLAINTEXT */
+     { 0 }, /* AAD */
+     { 0 }, /* CIPHERTEXT */
+     { 0x19,0x7b,0x9c,0x3c,0x44,0x1d,0x3c,0x83,0xea,0xfb,0x2b,0xef,0x63,0x3b,0x91,0x82 }, /* TAG */
+   },
+   { /* index:1 */
+     8, /* PLAINTEXT length */
+     8, /* AAD length */
+     { 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07 }, /* PLAINTEXT */
+     { 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07 }, /* AAD */
+     { 0x92,0xb6,0x57,0x13,0x0a,0x74,0xb8,0x5a }, /* CIPHERTEXT */
+     { 0x16,0xdc,0x76,0xa4,0x6d,0x47,0xe1,0xea,0xd5,0x37,0x20,0x9e,0x8a,0x96,0xd1,0x4e }, /* TAG */
+   },
+   { /* index:2 */
+     0, /* PLAINTEXT length */
+     8, /* AAD length */
+     { 0 }, /* PLAINTEXT */
+     { 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07 }, /* AAD */
+     { 0 }, /* CIPHERTEXT */
+     { 0x98,0xb9,0x15,0x52,0xc8,0xc0,0x09,0x18,0x50,0x44,0xe3,0x0a,0x6e,0xb2,0xfe,0x21 }, /* TAG */
+   },
+   { /* index:3 */
+     8, /* PLAINTEXT length */
+     0, /* AAD length */
+     { 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07 }, /* PLAINTEXT */
+     { 0 }, /* AAD */
+     { 0x92,0xb6,0x57,0x13,0x0a,0x74,0xb8,0x5a }, /* CIPHERTEXT */
+     { 0x97,0x1e,0xff,0xca,0xe1,0x9a,0xd4,0x71,0x6f,0x88,0xe8,0x7b,0x87,0x1f,0xbe,0xed }, /* TAG */
+   },
+   { /* index:4 */
+     16, /* PLAINTEXT length */
+     16, /* AAD length */
+     { 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f }, /* PLAINTEXT */
+     { 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f }, /* AAD */
+     { 0xbe,0xa5,0xe8,0x79,0x8d,0xbe,0x71,0x10,0x03,0x1c,0x14,0x4d,0xa0,0xb2,0x61,0x22 }, /* CIPHERTEXT */
+     { 0x77,0x6c,0x99,0x24,0xd6,0x72,0x3a,0x1f,0xc4,0x52,0x45,0x32,0xac,0x3e,0x5b,0xeb }, /* TAG */
+   },
+   { /* index:5 */
+     0, /* PLAINTEXT length */
+     16, /* AAD length */
+     { 0 }, /* PLAINTEXT */
+     { 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f }, /* AAD */
+     { 0 }, /* CIPHERTEXT */
+     { 0x7d,0xdb,0x8e,0x6c,0xea,0x68,0x14,0x86,0x62,0x12,0x50,0x96,0x19,0xb1,0x9c,0xc6 }, /* TAG */
+   },
+   { /* index:6 */
+     16, /* PLAINTEXT length */
+     0, /* AAD length */
+     { 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f }, /* PLAINTEXT */
+     { 0 }, /* AAD */
+     { 0xbe,0xa5,0xe8,0x79,0x8d,0xbe,0x71,0x10,0x03,0x1c,0x14,0x4d,0xa0,0xb2,0x61,0x22 }, /* CIPHERTEXT */
+     { 0x13,0xcc,0x8b,0x74,0x78,0x07,0x12,0x1a,0x4c,0xbb,0x3e,0x4b,0xd6,0xb4,0x56,0xaf }, /* TAG */
+   },
+   { /* index:7 */
+     24, /* PLAINTEXT length */
+     24, /* AAD length */
+     { 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17 }, /* PLAINTEXT */
+     { 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17 }, /* AAD */
+     { 0xbe,0xa5,0xe8,0x79,0x8d,0xbe,0x71,0x10,0x03,0x1c,0x14,0x4d,0xa0,0xb2,0x61,0x22,0xfc,0xfc,0xee,0x7a,0x2a,0x8d,0x4d,0x48 }, /* CIPHERTEXT */
+     { 0x5f,0xa9,0x4f,0xc3,0xf3,0x88,0x20,0xf1,0xdc,0x3f,0x3d,0x1f,0xd4,0xe5,0x5e,0x1c }, /* TAG */
+   },
+   { /* index:8 */
+     0, /* PLAINTEXT length */
+     24, /* AAD length */
+     { 0 }, /* PLAINTEXT */
+     { 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17 }, /* AAD */
+     { 0 }, /* CIPHERTEXT */
+     { 0x28,0x20,0x26,0xda,0x30,0x68,0xbc,0x9f,0xa1,0x18,0x68,0x1d,0x55,0x9f,0x10,0xf6 }, /* TAG */
+   },
+   { /* index:9 */
+     24, /* PLAINTEXT length */
+     0, /* AAD length */
+     { 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17 }, /* PLAINTEXT */
+     { 0 }, /* AAD */
+     { 0xbe,0xa5,0xe8,0x79,0x8d,0xbe,0x71,0x10,0x03,0x1c,0x14,0x4d,0xa0,0xb2,0x61,0x22,0xfc,0xfc,0xee,0x7a,0x2a,0x8d,0x4d,0x48 }, /* CIPHERTEXT */
+     { 0x6e,0xf2,0xf5,0x25,0x87,0xfd,0xa0,0xed,0x97,0xdc,0x7e,0xed,0xe2,0x41,0xdf,0x68 }, /* TAG */
+   },
+   { /* index:10 */
+     32, /* PLAINTEXT length */
+     32, /* AAD length */
+     { 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 }, /* PLAINTEXT */
+     { 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 }, /* AAD */
+     { 0xbe,0xa5,0xe8,0x79,0x8d,0xbe,0x71,0x10,0x03,0x1c,0x14,0x4d,0xa0,0xb2,0x61,0x22,0xce,0xaa,0xb9,0xb0,0x5d,0xf7,0x71,0xa6,0x57,0x14,0x9d,0x53,0x77,0x34,0x63,0xcb }, /* CIPHERTEXT */
+     { 0xb2,0xa0,0x40,0xdd,0x3b,0xd5,0x16,0x43,0x72,0xd7,0x6d,0x7b,0xb6,0x82,0x42,0x40 }, /* TAG */
+   },
+   { /* index:11 */
+     0, /* PLAINTEXT length */
+     32, /* AAD length */
+     { 0 }, /* PLAINTEXT */
+     { 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 }, /* AAD */
+     { 0 }, /* CIPHERTEXT */
+     { 0xe1,0xe0,0x72,0x63,0x3b,0xad,0xe5,0x1a,0x60,0xe8,0x59,0x51,0xd9,0xc4,0x2a,0x1b }, /* TAG */
+   },
+   { /* index:12 */
+     32, /* PLAINTEXT length */
+     0, /* AAD length */
+     { 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 }, /* PLAINTEXT */
+     { 0 }, /* AAD */
+     { 0xbe,0xa5,0xe8,0x79,0x8d,0xbe,0x71,0x10,0x03,0x1c,0x14,0x4d,0xa0,0xb2,0x61,0x22,0xce,0xaa,0xb9,0xb0,0x5d,0xf7,0x71,0xa6,0x57,0x14,0x9d,0x53,0x77,0x34,0x63,0xcb }, /* CIPHERTEXT */
+     { 0x4a,0x3b,0xae,0x82,0x44,0x65,0xcf,0xda,0xf8,0xc4,0x1f,0xc5,0x0c,0x7d,0xf9,0xd9 }, /* TAG */
+   },
+   { /* index:13 */
+     40, /* PLAINTEXT length */
+     40, /* AAD length */
+     { 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,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27 }, /* PLAINTEXT */
+     { 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,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27 }, /* AAD */
+     { 0xbe,0xa5,0xe8,0x79,0x8d,0xbe,0x71,0x10,0x03,0x1c,0x14,0x4d,0xa0,0xb2,0x61,0x22,0xce,0xaa,0xb9,0xb0,0x5d,0xf7,0x71,0xa6,0x57,0x14,0x9d,0x53,0x77,0x34,0x63,0xcb,0x68,0xc6,0x57,0x78,0xb0,0x58,0xa6,0x35 }, /* CIPHERTEXT */
+     { 0x65,0x9c,0x62,0x32,0x11,0xde,0xea,0x0d,0xe3,0x0d,0x2c,0x38,0x18,0x79,0xf4,0xc8 }, /* TAG */
+   },
+   { /* index:14 */
+     0, /* PLAINTEXT length */
+     40, /* AAD length */
+     { 0 }, /* PLAINTEXT */
+     { 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,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27 }, /* AAD */
+     { 0 }, /* CIPHERTEXT */
+     { 0x7a,0xeb,0x7a,0x69,0xa1,0x68,0x7d,0xd0,0x82,0xca,0x27,0xb0,0xd9,0xa3,0x70,0x96 }, /* TAG */
+   },
+   { /* index:15 */
+     40, /* PLAINTEXT length */
+     0, /* AAD length */
+     { 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,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27 }, /* PLAINTEXT */
+     { 0 }, /* AAD */
+     { 0xbe,0xa5,0xe8,0x79,0x8d,0xbe,0x71,0x10,0x03,0x1c,0x14,0x4d,0xa0,0xb2,0x61,0x22,0xce,0xaa,0xb9,0xb0,0x5d,0xf7,0x71,0xa6,0x57,0x14,0x9d,0x53,0x77,0x34,0x63,0xcb,0x68,0xc6,0x57,0x78,0xb0,0x58,0xa6,0x35 }, /* CIPHERTEXT */
+     { 0x06,0x0c,0x84,0x67,0xf4,0xab,0xab,0x5e,0x8b,0x3c,0x20,0x67,0xa2,0xe1,0x15,0xdc }, /* TAG */
+   },
+
+};
+   /* As of RFC 7253 - 'Appendix A.  Sample Results'
+    *    The next tuple shows a result with a tag length of 96 bits and a
+   different key.
+
+     K: 0F0E0D0C0B0A09080706050403020100
+
+     N: BBAA9988776655443322110D
+     A: 000102030405060708090A0B0C0D0E0F1011121314151617
+        18191A1B1C1D1E1F2021222324252627
+     P: 000102030405060708090A0B0C0D0E0F1011121314151617
+        18191A1B1C1D1E1F2021222324252627
+     C: 1792A4E31E0755FB03E31B22116E6C2DDF9EFD6E33D536F1
+        A0124B0A55BAE884ED93481529C76B6AD0C515F4D1CDD4FD
+        AC4F02AA
+
+        The C has been split up in C and T (tag)
+    */
+   const unsigned char K[] = { 0x0F,0x0E,0x0D,0x0C,0x0B,0x0A,0x09,0x08,
+                               0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x00 };
+   const unsigned char N[] = { 0xBB,0xAA,0x99,0x88,0x77,0x66,0x55,0x44,
+                               0x33,0x22,0x11,0x0D };
+   const unsigned char A[] = { 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,
+                               0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27 };
+   const unsigned char P[] = { 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,
+                               0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27 };
+   const unsigned char C[] = { 0x17,0x92,0xA4,0xE3,0x1E,0x07,0x55,0xFB,
+                               0x03,0xE3,0x1B,0x22,0x11,0x6E,0x6C,0x2D,
+                               0xDF,0x9E,0xFD,0x6E,0x33,0xD5,0x36,0xF1,
+                               0xA0,0x12,0x4B,0x0A,0x55,0xBA,0xE8,0x84,
+                               0xED,0x93,0x48,0x15,0x29,0xC7,0x6B,0x6A };
+   const unsigned char T[] = { 0xD0,0xC5,0x15,0xF4,0xD1,0xCD,0xD4,0xFD,
+                               0xAC,0x4F,0x02,0xAA };
+
+   int err, x, idx, res;
+   unsigned long len;
+   unsigned char outct[MAXBLOCKSIZE]  = { 0 };
+   unsigned char outtag[MAXBLOCKSIZE] = { 0 };
+   ocb3_state ocb;
+
+    /* AES can be under rijndael or aes... try to find it */
+    if ((idx = find_cipher("aes")) == -1) {
+       if ((idx = find_cipher("rijndael")) == -1) {
+          return CRYPT_NOP;
+       }
+    }
+
+    for (x = 0; x < (int)(sizeof(tests)/sizeof(tests[0])); x++) {
+        len = 16; /* must be the same as the required taglen */
+        if ((err = ocb3_encrypt_authenticate_memory(idx,
+                                                   key, sizeof(key),
+                                                   nonce, sizeof(nonce),
+                                                   tests[x].aadlen != 0 ? tests[x].aad : NULL, tests[x].aadlen,
+                                                   tests[x].ptlen != 0 ? tests[x].pt : NULL, tests[x].ptlen,
+                                                   tests[x].ptlen != 0 ? outct : NULL, outtag, &len)) != CRYPT_OK) {
+           return err;
+        }
+
+        if (compare_testvector(outtag, len, tests[x].tag, sizeof(tests[x].tag), "OCB3 Tag", x) ||
+              compare_testvector(outct, tests[x].ptlen, tests[x].ct, tests[x].ptlen, "OCB3 CT", x)) {
+           return CRYPT_FAIL_TESTVECTOR;
+        }
+
+        if ((err = ocb3_decrypt_verify_memory(idx,
+                                             key, sizeof(key),
+                                             nonce, sizeof(nonce),
+                                             tests[x].aadlen != 0 ? tests[x].aad : NULL, tests[x].aadlen,
+                                             tests[x].ptlen != 0 ? outct : NULL, tests[x].ptlen,
+                                             tests[x].ptlen != 0 ? outct : NULL, tests[x].tag, len, &res)) != CRYPT_OK) {
+           return err;
+        }
+        if ((res != 1) || compare_testvector(outct, tests[x].ptlen, tests[x].pt, tests[x].ptlen, "OCB3", x)) {
+#ifdef LTC_TEST_DBG
+           printf("\n\nOCB3: Failure-decrypt - res = %d\n", res);
+#endif
+           return CRYPT_FAIL_TESTVECTOR;
+        }
+    }
+
+    /* RFC 7253 - test vector with a tag length of 96 bits - part 1 */
+    x = 99;
+    len = 12;
+    if ((err = ocb3_encrypt_authenticate_memory(idx,
+                                                K, sizeof(K),
+                                                N, sizeof(N),
+                                                A, sizeof(A),
+                                                P, sizeof(P),
+                                                outct, outtag, &len)) != CRYPT_OK) {
+       return err;
+    }
+
+    if (compare_testvector(outtag, len, T, sizeof(T), "OCB3 Tag", x) ||
+          compare_testvector(outct, sizeof(P), C, sizeof(C), "OCB3 CT", x)) {
+       return CRYPT_FAIL_TESTVECTOR;
+    }
+
+    if ((err = ocb3_decrypt_verify_memory(idx,
+                                          K, sizeof(K),
+                                          N, sizeof(N),
+                                          A, sizeof(A),
+                                          C, sizeof(C),
+                                          outct, T, sizeof(T), &res)) != CRYPT_OK) {
+       return err;
+    }
+    if ((res != 1) || compare_testvector(outct, sizeof(C), P, sizeof(P), "OCB3", x)) {
+#ifdef LTC_TEST_DBG
+       printf("\n\nOCB3: Failure-decrypt - res = %d\n", res);
+#endif
+       return CRYPT_FAIL_TESTVECTOR;
+    }
+
+    /* RFC 7253 - test vector with a tag length of 96 bits - part 2 */
+    x = 100;
+    if ((err = ocb3_init(&ocb, idx, K, sizeof(K), N, sizeof(N), 12)) != CRYPT_OK)  return err;
+    if ((err = ocb3_add_aad(&ocb, A, sizeof(A))) != CRYPT_OK)                      return err;
+    if ((err = ocb3_encrypt(&ocb, P, 32, outct)) != CRYPT_OK)                      return err;
+    if ((err = ocb3_encrypt_last(&ocb, P+32, sizeof(P)-32, outct+32)) != CRYPT_OK) return err;
+    len = sizeof(outtag); /* intentionally more than 12 */
+    if ((err = ocb3_done(&ocb, outtag, &len)) != CRYPT_OK)                         return err;
+    if (compare_testvector(outct, sizeof(P), C, sizeof(C), "OCB3 CT", x))          return CRYPT_FAIL_TESTVECTOR;
+    if (compare_testvector(outtag, len, T, sizeof(T), "OCB3 Tag.enc", x))          return CRYPT_FAIL_TESTVECTOR;
+    if ((err = ocb3_init(&ocb, idx, K, sizeof(K), N, sizeof(N), 12)) != CRYPT_OK)  return err;
+    if ((err = ocb3_add_aad(&ocb, A, sizeof(A))) != CRYPT_OK)                      return err;
+    if ((err = ocb3_decrypt(&ocb, C, 32, outct)) != CRYPT_OK)                      return err;
+    if ((err = ocb3_decrypt_last(&ocb, C+32, sizeof(C)-32, outct+32)) != CRYPT_OK) return err;
+    len = sizeof(outtag); /* intentionally more than 12 */
+    if ((err = ocb3_done(&ocb, outtag, &len)) != CRYPT_OK)                         return err;
+    if (compare_testvector(outct, sizeof(C), P, sizeof(P), "OCB3 PT", x))          return CRYPT_FAIL_TESTVECTOR;
+    if (compare_testvector(outtag, len, T, sizeof(T), "OCB3 Tag.dec", x))          return CRYPT_FAIL_TESTVECTOR;
+
+    return CRYPT_OK;
+#endif /* LTC_TEST */
+}
+
+#endif /* LTC_OCB3_MODE */
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/hashes/blake2b.c b/libtomcrypt/src/hashes/blake2b.c
new file mode 100644 (file)
index 0000000..cd5115c
--- /dev/null
@@ -0,0 +1,588 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+/*
+   BLAKE2 reference source code package - reference C implementations
+
+   Copyright 2012, Samuel Neves <sneves@dei.uc.pt>.  You may use this under the
+   terms of the CC0, the OpenSSL Licence, or the Apache Public License 2.0, at
+   your option.  The terms of these licenses can be found at:
+
+   - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
+   - OpenSSL license   : https://www.openssl.org/source/license.html
+   - Apache 2.0        : http://www.apache.org/licenses/LICENSE-2.0
+
+   More information about the BLAKE2 hash function can be found at
+   https://blake2.net.
+*/
+/* see also https://www.ietf.org/rfc/rfc7693.txt */
+
+#include "tomcrypt.h"
+
+#ifdef LTC_BLAKE2B
+
+enum blake2b_constant {
+   BLAKE2B_BLOCKBYTES = 128,
+   BLAKE2B_OUTBYTES = 64,
+   BLAKE2B_KEYBYTES = 64,
+   BLAKE2B_SALTBYTES = 16,
+   BLAKE2B_PERSONALBYTES = 16,
+   BLAKE2B_PARAM_SIZE = 64
+};
+
+/* param offsets */
+enum {
+   O_DIGEST_LENGTH = 0,
+   O_KEY_LENGTH = 1,
+   O_FANOUT = 2,
+   O_DEPTH = 3,
+   O_LEAF_LENGTH = 4,
+   O_NODE_OFFSET = 8,
+   O_XOF_LENGTH = 12,
+   O_NODE_DEPTH = 16,
+   O_INNER_LENGTH = 17,
+   O_RESERVED = 18,
+   O_SALT = 32,
+   O_PERSONAL = 48
+};
+
+/*
+struct blake2b_param {
+   unsigned char digest_length;
+   unsigned char key_length;
+   unsigned char fanout;
+   unsigned char depth;
+   ulong32 leaf_length;
+   ulong32 node_offset;
+   ulong32 xof_length;
+   unsigned char node_depth;
+   unsigned char inner_length;
+   unsigned char reserved[14];
+   unsigned char salt[BLAKE2B_SALTBYTES];
+   unsigned char personal[BLAKE2B_PERSONALBYTES];
+};
+*/
+
+const struct ltc_hash_descriptor blake2b_160_desc =
+{
+    "blake2b-160",
+    25,
+    20,
+    128,
+    { 1, 3, 6, 1, 4, 1, 1722, 12, 2, 1, 5 },
+    11,
+    &blake2b_160_init,
+    &blake2b_process,
+    &blake2b_done,
+    &blake2b_160_test,
+    NULL
+};
+
+const struct ltc_hash_descriptor blake2b_256_desc =
+{
+    "blake2b-256",
+    26,
+    32,
+    128,
+    { 1, 3, 6, 1, 4, 1, 1722, 12, 2, 1, 8 },
+    11,
+    &blake2b_256_init,
+    &blake2b_process,
+    &blake2b_done,
+    &blake2b_256_test,
+    NULL
+};
+
+const struct ltc_hash_descriptor blake2b_384_desc =
+{
+    "blake2b-384",
+    27,
+    48,
+    128,
+    { 1, 3, 6, 1, 4, 1, 1722, 12, 2, 1, 12 },
+    11,
+    &blake2b_384_init,
+    &blake2b_process,
+    &blake2b_done,
+    &blake2b_384_test,
+    NULL
+};
+
+const struct ltc_hash_descriptor blake2b_512_desc =
+{
+    "blake2b-512",
+    28,
+    64,
+    128,
+    { 1, 3, 6, 1, 4, 1, 1722, 12, 2, 1, 16 },
+    11,
+    &blake2b_512_init,
+    &blake2b_process,
+    &blake2b_done,
+    &blake2b_512_test,
+    NULL
+};
+
+static const ulong64 blake2b_IV[8] =
+{
+  CONST64(0x6a09e667f3bcc908), CONST64(0xbb67ae8584caa73b),
+  CONST64(0x3c6ef372fe94f82b), CONST64(0xa54ff53a5f1d36f1),
+  CONST64(0x510e527fade682d1), CONST64(0x9b05688c2b3e6c1f),
+  CONST64(0x1f83d9abfb41bd6b), CONST64(0x5be0cd19137e2179)
+};
+
+static const unsigned char blake2b_sigma[12][16] =
+{
+  {  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15 } ,
+  { 14, 10,  4,  8,  9, 15, 13,  6,  1, 12,  0,  2, 11,  7,  5,  3 } ,
+  { 11,  8, 12,  0,  5,  2, 15, 13, 10, 14,  3,  6,  7,  1,  9,  4 } ,
+  {  7,  9,  3,  1, 13, 12, 11, 14,  2,  6,  5, 10,  4,  0, 15,  8 } ,
+  {  9,  0,  5,  7,  2,  4, 10, 15, 14,  1, 11, 12,  6,  8,  3, 13 } ,
+  {  2, 12,  6, 10,  0, 11,  8,  3,  4, 13,  7,  5, 15, 14,  1,  9 } ,
+  { 12,  5,  1, 15, 14, 13,  4, 10,  0,  7,  6,  3,  9,  2,  8, 11 } ,
+  { 13, 11,  7, 14, 12,  1,  3,  9,  5,  0, 15,  4,  8,  6,  2, 10 } ,
+  {  6, 15, 14,  9, 11,  3,  0,  8, 12,  2, 13,  7,  1,  4, 10,  5 } ,
+  { 10,  2,  8,  4,  7,  6,  1,  5, 15, 11,  9, 14,  3, 12, 13 , 0 } ,
+  {  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15 } ,
+  { 14, 10,  4,  8,  9, 15, 13,  6,  1, 12,  0,  2, 11,  7,  5,  3 }
+};
+
+static void blake2b_set_lastnode(hash_state *md) { md->blake2b.f[1] = CONST64(0xffffffffffffffff); }
+
+/* Some helper functions, not necessarily useful */
+static int blake2b_is_lastblock(const hash_state *md) { return md->blake2b.f[0] != 0; }
+
+static void blake2b_set_lastblock(hash_state *md)
+{
+   if (md->blake2b.last_node)
+      blake2b_set_lastnode(md);
+
+   md->blake2b.f[0] = CONST64(0xffffffffffffffff);
+}
+
+static void blake2b_increment_counter(hash_state *md, ulong64 inc)
+{
+   md->blake2b.t[0] += inc;
+   if (md->blake2b.t[0] < inc) md->blake2b.t[1]++;
+}
+
+static void blake2b_init0(hash_state *md)
+{
+   unsigned long i;
+   XMEMSET(&md->blake2b, 0, sizeof(md->blake2b));
+
+   for (i = 0; i < 8; ++i)
+      md->blake2b.h[i] = blake2b_IV[i];
+}
+
+/* init xors IV with input parameter block */
+static int blake2b_init_param(hash_state *md, const unsigned char *P)
+{
+   unsigned long i;
+
+   blake2b_init0(md);
+
+   /* IV XOR ParamBlock */
+   for (i = 0; i < 8; ++i) {
+      ulong64 tmp;
+      LOAD64L(tmp, P + i * 8);
+      md->blake2b.h[i] ^= tmp;
+   }
+
+   md->blake2b.outlen = P[O_DIGEST_LENGTH];
+   return CRYPT_OK;
+}
+
+int blake2b_init(hash_state *md, unsigned long outlen, const unsigned char *key, unsigned long keylen)
+{
+   unsigned char P[BLAKE2B_PARAM_SIZE];
+   int err;
+
+   LTC_ARGCHK(md != NULL);
+
+   if ((!outlen) || (outlen > BLAKE2B_OUTBYTES))
+      return CRYPT_INVALID_ARG;
+
+   if ((key && !keylen) || (keylen && !key) || (keylen > BLAKE2B_KEYBYTES))
+      return CRYPT_INVALID_ARG;
+
+   XMEMSET(P, 0, sizeof(P));
+
+   P[O_DIGEST_LENGTH] = (unsigned char)outlen;
+   P[O_KEY_LENGTH] = (unsigned char)keylen;
+   P[O_FANOUT] = 1;
+   P[O_DEPTH] = 1;
+
+   err = blake2b_init_param(md, P);
+   if (err != CRYPT_OK) return err;
+
+   if (key) {
+      unsigned char block[BLAKE2B_BLOCKBYTES];
+
+      XMEMSET(block, 0, BLAKE2B_BLOCKBYTES);
+      XMEMCPY(block, key, keylen);
+      blake2b_process(md, block, BLAKE2B_BLOCKBYTES);
+
+#ifdef LTC_CLEAN_STACK
+      zeromem(block, sizeof(block));
+#endif
+   }
+
+   return CRYPT_OK;
+}
+
+int blake2b_160_init(hash_state *md) { return blake2b_init(md, 20, NULL, 0); }
+
+int blake2b_256_init(hash_state *md) { return blake2b_init(md, 32, NULL, 0); }
+
+int blake2b_384_init(hash_state *md) { return blake2b_init(md, 48, NULL, 0); }
+
+int blake2b_512_init(hash_state *md) { return blake2b_init(md, 64, NULL, 0); }
+
+#define G(r, i, a, b, c, d)                                                                                            \
+   do {                                                                                                                \
+      a = a + b + m[blake2b_sigma[r][2 * i + 0]];                                                                      \
+      d = ROR64(d ^ a, 32);                                                                                            \
+      c = c + d;                                                                                                       \
+      b = ROR64(b ^ c, 24);                                                                                            \
+      a = a + b + m[blake2b_sigma[r][2 * i + 1]];                                                                      \
+      d = ROR64(d ^ a, 16);                                                                                            \
+      c = c + d;                                                                                                       \
+      b = ROR64(b ^ c, 63);                                                                                            \
+   } while (0)
+
+#define ROUND(r)                                                                                                       \
+   do {                                                                                                                \
+      G(r, 0, v[0], v[4], v[8], v[12]);                                                                                \
+      G(r, 1, v[1], v[5], v[9], v[13]);                                                                                \
+      G(r, 2, v[2], v[6], v[10], v[14]);                                                                               \
+      G(r, 3, v[3], v[7], v[11], v[15]);                                                                               \
+      G(r, 4, v[0], v[5], v[10], v[15]);                                                                               \
+      G(r, 5, v[1], v[6], v[11], v[12]);                                                                               \
+      G(r, 6, v[2], v[7], v[8], v[13]);                                                                                \
+      G(r, 7, v[3], v[4], v[9], v[14]);                                                                                \
+   } while (0)
+
+#ifdef LTC_CLEAN_STACK
+static int _blake2b_compress(hash_state *md, const unsigned char *buf)
+#else
+static int blake2b_compress(hash_state *md, const unsigned char *buf)
+#endif
+{
+   ulong64 m[16];
+   ulong64 v[16];
+   unsigned long i;
+
+   for (i = 0; i < 16; ++i) {
+      LOAD64L(m[i], buf + i * sizeof(m[i]));
+   }
+
+   for (i = 0; i < 8; ++i) {
+      v[i] = md->blake2b.h[i];
+   }
+
+   v[8] = blake2b_IV[0];
+   v[9] = blake2b_IV[1];
+   v[10] = blake2b_IV[2];
+   v[11] = blake2b_IV[3];
+   v[12] = blake2b_IV[4] ^ md->blake2b.t[0];
+   v[13] = blake2b_IV[5] ^ md->blake2b.t[1];
+   v[14] = blake2b_IV[6] ^ md->blake2b.f[0];
+   v[15] = blake2b_IV[7] ^ md->blake2b.f[1];
+
+   ROUND(0);
+   ROUND(1);
+   ROUND(2);
+   ROUND(3);
+   ROUND(4);
+   ROUND(5);
+   ROUND(6);
+   ROUND(7);
+   ROUND(8);
+   ROUND(9);
+   ROUND(10);
+   ROUND(11);
+
+   for (i = 0; i < 8; ++i) {
+      md->blake2b.h[i] = md->blake2b.h[i] ^ v[i] ^ v[i + 8];
+   }
+   return CRYPT_OK;
+}
+
+#undef G
+#undef ROUND
+
+#ifdef LTC_CLEAN_STACK
+static int blake2b_compress(hash_state *md, const unsigned char *buf)
+{
+   int err;
+   err = _blake2b_compress(md, buf);
+   burn_stack(sizeof(ulong64) * 32 + sizeof(unsigned long));
+   return err;
+}
+#endif
+
+int blake2b_process(hash_state *md, const unsigned char *in, unsigned long inlen)
+{
+   LTC_ARGCHK(md != NULL);
+   LTC_ARGCHK(in != NULL);
+
+   if (md->blake2b.curlen > sizeof(md->blake2b.buf)) {
+      return CRYPT_INVALID_ARG;
+   }
+
+   if (inlen > 0) {
+      unsigned long left = md->blake2b.curlen;
+      unsigned long fill = BLAKE2B_BLOCKBYTES - left;
+      if (inlen > fill) {
+         md->blake2b.curlen = 0;
+         XMEMCPY(md->blake2b.buf + (left % sizeof(md->blake2b.buf)), in, fill); /* Fill buffer */
+         blake2b_increment_counter(md, BLAKE2B_BLOCKBYTES);
+         blake2b_compress(md, md->blake2b.buf); /* Compress */
+         in += fill;
+         inlen -= fill;
+         while (inlen > BLAKE2B_BLOCKBYTES) {
+            blake2b_increment_counter(md, BLAKE2B_BLOCKBYTES);
+            blake2b_compress(md, in);
+            in += BLAKE2B_BLOCKBYTES;
+            inlen -= BLAKE2B_BLOCKBYTES;
+         }
+      }
+      XMEMCPY(md->blake2b.buf + md->blake2b.curlen, in, inlen);
+      md->blake2b.curlen += inlen;
+   }
+   return CRYPT_OK;
+}
+
+int blake2b_done(hash_state *md, unsigned char *out)
+{
+   unsigned char buffer[BLAKE2B_OUTBYTES] = { 0 };
+   unsigned long i;
+
+   LTC_ARGCHK(md != NULL);
+   LTC_ARGCHK(out != NULL);
+
+   /* if(md->blakebs.outlen != outlen) return CRYPT_INVALID_ARG; */
+
+   if (blake2b_is_lastblock(md))
+      return CRYPT_ERROR;
+
+   blake2b_increment_counter(md, md->blake2b.curlen);
+   blake2b_set_lastblock(md);
+   XMEMSET(md->blake2b.buf + md->blake2b.curlen, 0, BLAKE2B_BLOCKBYTES - md->blake2b.curlen); /* Padding */
+   blake2b_compress(md, md->blake2b.buf);
+
+   for (i = 0; i < 8; ++i) /* Output full hash to temp buffer */
+      STORE64L(md->blake2b.h[i], buffer + i * 8);
+
+   XMEMCPY(out, buffer, md->blake2b.outlen);
+   zeromem(md, sizeof(hash_state));
+#ifdef LTC_CLEAN_STACK
+   zeromem(buffer, sizeof(buffer));
+#endif
+   return CRYPT_OK;
+}
+
+/**
+  Self-test the hash
+  @return CRYPT_OK if successful, CRYPT_NOP if self-tests have been disabled
+*/
+int blake2b_512_test(void)
+{
+#ifndef LTC_TEST
+   return CRYPT_NOP;
+#else
+   static const struct {
+      const char *msg;
+      unsigned char hash[64];
+  } tests[] = {
+    { "",
+      { 0x78, 0x6a, 0x02, 0xf7, 0x42, 0x01, 0x59, 0x03,
+        0xc6, 0xc6, 0xfd, 0x85, 0x25, 0x52, 0xd2, 0x72,
+        0x91, 0x2f, 0x47, 0x40, 0xe1, 0x58, 0x47, 0x61,
+        0x8a, 0x86, 0xe2, 0x17, 0xf7, 0x1f, 0x54, 0x19,
+        0xd2, 0x5e, 0x10, 0x31, 0xaf, 0xee, 0x58, 0x53,
+        0x13, 0x89, 0x64, 0x44, 0x93, 0x4e, 0xb0, 0x4b,
+        0x90, 0x3a, 0x68, 0x5b, 0x14, 0x48, 0xb7, 0x55,
+        0xd5, 0x6f, 0x70, 0x1a, 0xfe, 0x9b, 0xe2, 0xce } },
+    { "abc",
+      { 0xba, 0x80, 0xa5, 0x3f, 0x98, 0x1c, 0x4d, 0x0d,
+        0x6a, 0x27, 0x97, 0xb6, 0x9f, 0x12, 0xf6, 0xe9,
+        0x4c, 0x21, 0x2f, 0x14, 0x68, 0x5a, 0xc4, 0xb7,
+        0x4b, 0x12, 0xbb, 0x6f, 0xdb, 0xff, 0xa2, 0xd1,
+        0x7d, 0x87, 0xc5, 0x39, 0x2a, 0xab, 0x79, 0x2d,
+        0xc2, 0x52, 0xd5, 0xde, 0x45, 0x33, 0xcc, 0x95,
+        0x18, 0xd3, 0x8a, 0xa8, 0xdb, 0xf1, 0x92, 0x5a,
+        0xb9, 0x23, 0x86, 0xed, 0xd4, 0x00, 0x99, 0x23 } },
+
+    { NULL, { 0 } }
+  };
+
+   int i;
+   unsigned char tmp[64];
+   hash_state md;
+
+   for (i = 0; tests[i].msg != NULL; i++) {
+      blake2b_512_init(&md);
+      blake2b_process(&md, (unsigned char *)tests[i].msg, (unsigned long)strlen(tests[i].msg));
+      blake2b_done(&md, tmp);
+      if (compare_testvector(tmp, sizeof(tmp), tests[i].hash, sizeof(tests[i].hash), "BLAKE2B_512", i)) {
+         return CRYPT_FAIL_TESTVECTOR;
+      }
+   }
+   return CRYPT_OK;
+#endif
+}
+
+/**
+  Self-test the hash
+  @return CRYPT_OK if successful, CRYPT_NOP if self-tests have been disabled
+*/
+int blake2b_384_test(void)
+{
+#ifndef LTC_TEST
+   return CRYPT_NOP;
+#else
+   static const struct {
+      const char *msg;
+      unsigned char hash[48];
+  } tests[] = {
+    { "",
+      { 0xb3, 0x28, 0x11, 0x42, 0x33, 0x77, 0xf5, 0x2d,
+        0x78, 0x62, 0x28, 0x6e, 0xe1, 0xa7, 0x2e, 0xe5,
+        0x40, 0x52, 0x43, 0x80, 0xfd, 0xa1, 0x72, 0x4a,
+        0x6f, 0x25, 0xd7, 0x97, 0x8c, 0x6f, 0xd3, 0x24,
+        0x4a, 0x6c, 0xaf, 0x04, 0x98, 0x81, 0x26, 0x73,
+        0xc5, 0xe0, 0x5e, 0xf5, 0x83, 0x82, 0x51, 0x00 } },
+    { "abc",
+      { 0x6f, 0x56, 0xa8, 0x2c, 0x8e, 0x7e, 0xf5, 0x26,
+        0xdf, 0xe1, 0x82, 0xeb, 0x52, 0x12, 0xf7, 0xdb,
+        0x9d, 0xf1, 0x31, 0x7e, 0x57, 0x81, 0x5d, 0xbd,
+        0xa4, 0x60, 0x83, 0xfc, 0x30, 0xf5, 0x4e, 0xe6,
+        0xc6, 0x6b, 0xa8, 0x3b, 0xe6, 0x4b, 0x30, 0x2d,
+        0x7c, 0xba, 0x6c, 0xe1, 0x5b, 0xb5, 0x56, 0xf4 } },
+
+    { NULL, { 0 } }
+  };
+
+   int i;
+   unsigned char tmp[48];
+   hash_state md;
+
+   for (i = 0; tests[i].msg != NULL; i++) {
+      blake2b_384_init(&md);
+      blake2b_process(&md, (unsigned char *)tests[i].msg, (unsigned long)strlen(tests[i].msg));
+      blake2b_done(&md, tmp);
+      if (compare_testvector(tmp, sizeof(tmp), tests[i].hash, sizeof(tests[i].hash), "BLAKE2B_384", i)) {
+         return CRYPT_FAIL_TESTVECTOR;
+      }
+   }
+   return CRYPT_OK;
+#endif
+}
+
+/**
+  Self-test the hash
+  @return CRYPT_OK if successful, CRYPT_NOP if self-tests have been disabled
+*/
+int blake2b_256_test(void)
+{
+#ifndef LTC_TEST
+   return CRYPT_NOP;
+#else
+   static const struct {
+      const char *msg;
+      unsigned char hash[32];
+  } tests[] = {
+    { "",
+      { 0x0e, 0x57, 0x51, 0xc0, 0x26, 0xe5, 0x43, 0xb2,
+        0xe8, 0xab, 0x2e, 0xb0, 0x60, 0x99, 0xda, 0xa1,
+        0xd1, 0xe5, 0xdf, 0x47, 0x77, 0x8f, 0x77, 0x87,
+        0xfa, 0xab, 0x45, 0xcd, 0xf1, 0x2f, 0xe3, 0xa8 } },
+    { "abc",
+      { 0xbd, 0xdd, 0x81, 0x3c, 0x63, 0x42, 0x39, 0x72,
+        0x31, 0x71, 0xef, 0x3f, 0xee, 0x98, 0x57, 0x9b,
+        0x94, 0x96, 0x4e, 0x3b, 0xb1, 0xcb, 0x3e, 0x42,
+        0x72, 0x62, 0xc8, 0xc0, 0x68, 0xd5, 0x23, 0x19 } },
+    { "12345678901234567890123456789012345678901234567890"
+      "12345678901234567890123456789012345678901234567890"
+      "12345678901234567890123456789012345678901234567890"
+      "12345678901234567890123456789012345678901234567890"
+      "12345678901234567890123456789012345678901234567890"
+      "12345678901234567890123456789012345678901234567890",
+      { 0x0f, 0x6e, 0x01, 0x8d, 0x38, 0xd6, 0x3f, 0x08,
+        0x4d, 0x58, 0xe3, 0x0c, 0x90, 0xfb, 0xa2, 0x41,
+        0x5f, 0xca, 0x17, 0xfa, 0x66, 0x26, 0x49, 0xf3,
+        0x8a, 0x30, 0x41, 0x7c, 0x57, 0xcd, 0xa8, 0x14 } },
+
+    { NULL, { 0 } }
+  };
+
+   int i;
+   unsigned char tmp[32];
+   hash_state md;
+
+   for (i = 0; tests[i].msg != NULL; i++) {
+      blake2b_256_init(&md);
+      blake2b_process(&md, (unsigned char *)tests[i].msg, (unsigned long)strlen(tests[i].msg));
+      blake2b_done(&md, tmp);
+      if (compare_testvector(tmp, sizeof(tmp), tests[i].hash, sizeof(tests[i].hash), "BLAKE2B_256", i)) {
+         return CRYPT_FAIL_TESTVECTOR;
+      }
+   }
+   return CRYPT_OK;
+#endif
+}
+
+/**
+  Self-test the hash
+  @return CRYPT_OK if successful, CRYPT_NOP if self-tests have been disabled
+*/
+int blake2b_160_test(void)
+{
+#ifndef LTC_TEST
+   return CRYPT_NOP;
+#else
+   static const struct {
+      const char *msg;
+      unsigned char hash[20];
+  } tests[] = {
+    { "",
+      { 0x33, 0x45, 0x52, 0x4a, 0xbf, 0x6b, 0xbe, 0x18,
+        0x09, 0x44, 0x92, 0x24, 0xb5, 0x97, 0x2c, 0x41,
+        0x79, 0x0b, 0x6c, 0xf2 } },
+    { "abc",
+      { 0x38, 0x42, 0x64, 0xf6, 0x76, 0xf3, 0x95, 0x36,
+        0x84, 0x05, 0x23, 0xf2, 0x84, 0x92, 0x1c, 0xdc,
+        0x68, 0xb6, 0x84, 0x6b } },
+
+    { NULL, { 0 } }
+  };
+
+   int i;
+   unsigned char tmp[20];
+   hash_state md;
+
+   for (i = 0; tests[i].msg != NULL; i++) {
+      blake2b_160_init(&md);
+      blake2b_process(&md, (unsigned char *)tests[i].msg, (unsigned long)strlen(tests[i].msg));
+      blake2b_done(&md, tmp);
+      if (compare_testvector(tmp, sizeof(tmp), tests[i].hash, sizeof(tests[i].hash), "BLAKE2B_160", i)) {
+         return CRYPT_FAIL_TESTVECTOR;
+      }
+   }
+   return CRYPT_OK;
+#endif
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/hashes/blake2s.c b/libtomcrypt/src/hashes/blake2s.c
new file mode 100644 (file)
index 0000000..e3e90f8
--- /dev/null
@@ -0,0 +1,563 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+/*
+   BLAKE2 reference source code package - reference C implementations
+
+   Copyright 2012, Samuel Neves <sneves@dei.uc.pt>.  You may use this under the
+   terms of the CC0, the OpenSSL Licence, or the Apache Public License 2.0, at
+   your option.  The terms of these licenses can be found at:
+
+   - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
+   - OpenSSL license   : https://www.openssl.org/source/license.html
+   - Apache 2.0        : http://www.apache.org/licenses/LICENSE-2.0
+
+   More information about the BLAKE2 hash function can be found at
+   https://blake2.net.
+*/
+/* see also https://www.ietf.org/rfc/rfc7693.txt */
+
+#include "tomcrypt.h"
+
+#ifdef LTC_BLAKE2S
+
+enum blake2s_constant {
+   BLAKE2S_BLOCKBYTES = 64,
+   BLAKE2S_OUTBYTES = 32,
+   BLAKE2S_KEYBYTES = 32,
+   BLAKE2S_SALTBYTES = 8,
+   BLAKE2S_PERSONALBYTES = 8,
+   BLAKE2S_PARAM_SIZE = 32
+};
+
+/* param offsets */
+enum {
+   O_DIGEST_LENGTH = 0,
+   O_KEY_LENGTH = 1,
+   O_FANOUT = 2,
+   O_DEPTH = 3,
+   O_LEAF_LENGTH = 4,
+   O_NODE_OFFSET = 8,
+   O_XOF_LENGTH = 12,
+   O_NODE_DEPTH = 14,
+   O_INNER_LENGTH = 15,
+   O_SALT = 16,
+   O_PERSONAL = 24
+};
+
+/*
+struct blake2s_param {
+   unsigned char digest_length;
+   unsigned char key_length;
+   unsigned char fanout;
+   unsigned char depth;
+   ulong32 leaf_length;
+   ulong32 node_offset;
+   ushort16 xof_length;
+   unsigned char node_depth;
+   unsigned char inner_length;
+   unsigned char salt[BLAKE2S_SALTBYTES];
+   unsigned char personal[BLAKE2S_PERSONALBYTES];
+};
+*/
+
+const struct ltc_hash_descriptor blake2s_128_desc =
+{
+    "blake2s-128",
+    21,
+    16,
+    64,
+    { 1, 3, 6, 1, 4, 1, 1722, 12, 2, 2, 4 },
+    11,
+    &blake2s_128_init,
+    &blake2s_process,
+    &blake2s_done,
+    &blake2s_128_test,
+    NULL
+};
+
+const struct ltc_hash_descriptor blake2s_160_desc =
+{
+    "blake2s-160",
+    22,
+    20,
+    64,
+    { 1, 3, 6, 1, 4, 1, 1722, 12, 2, 2, 5 },
+    11,
+    &blake2s_160_init,
+    &blake2s_process,
+    &blake2s_done,
+    &blake2s_160_test,
+    NULL
+};
+
+const struct ltc_hash_descriptor blake2s_224_desc =
+{
+    "blake2s-224",
+    23,
+    28,
+    64,
+    { 1, 3, 6, 1, 4, 1, 1722, 12, 2, 2, 7 },
+    11,
+    &blake2s_224_init,
+    &blake2s_process,
+    &blake2s_done,
+    &blake2s_224_test,
+    NULL
+};
+
+const struct ltc_hash_descriptor blake2s_256_desc =
+{
+    "blake2s-256",
+    24,
+    32,
+    64,
+    { 1, 3, 6, 1, 4, 1, 1722, 12, 2, 2, 8 },
+    11,
+    &blake2s_256_init,
+    &blake2s_process,
+    &blake2s_done,
+    &blake2s_256_test,
+    NULL
+};
+
+static const ulong32 blake2s_IV[8] = {
+    0x6A09E667UL, 0xBB67AE85UL, 0x3C6EF372UL, 0xA54FF53AUL,
+    0x510E527FUL, 0x9B05688CUL, 0x1F83D9ABUL, 0x5BE0CD19UL
+};
+
+static const unsigned char blake2s_sigma[10][16] = {
+    { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 },
+    { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 },
+    { 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 },
+    { 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 },
+    { 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 },
+    { 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 },
+    { 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 },
+    { 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 },
+    { 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 },
+    { 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0 },
+};
+
+static void blake2s_set_lastnode(hash_state *md) { md->blake2s.f[1] = 0xffffffffUL; }
+
+/* Some helper functions, not necessarily useful */
+static int blake2s_is_lastblock(const hash_state *md) { return md->blake2s.f[0] != 0; }
+
+static void blake2s_set_lastblock(hash_state *md)
+{
+   if (md->blake2s.last_node)
+      blake2s_set_lastnode(md);
+
+   md->blake2s.f[0] = 0xffffffffUL;
+}
+
+static void blake2s_increment_counter(hash_state *md, const ulong32 inc)
+{
+   md->blake2s.t[0] += inc;
+   if (md->blake2s.t[0] < inc) md->blake2s.t[1]++;
+}
+
+static int blake2s_init0(hash_state *md)
+{
+   int i;
+   XMEMSET(&md->blake2s, 0, sizeof(struct blake2s_state));
+
+   for (i = 0; i < 8; ++i)
+      md->blake2s.h[i] = blake2s_IV[i];
+
+   return CRYPT_OK;
+}
+
+/* init2 xors IV with input parameter block */
+static int blake2s_init_param(hash_state *md, const unsigned char *P)
+{
+   unsigned long i;
+
+   blake2s_init0(md);
+
+   /* IV XOR ParamBlock */
+   for (i = 0; i < 8; ++i) {
+      ulong32 tmp;
+      LOAD32L(tmp, P + i * 4);
+      md->blake2s.h[i] ^= tmp;
+   }
+
+   md->blake2s.outlen = P[O_DIGEST_LENGTH];
+   return CRYPT_OK;
+}
+
+int blake2s_init(hash_state *md, unsigned long outlen, const unsigned char *key, unsigned long keylen)
+{
+   unsigned char P[BLAKE2S_PARAM_SIZE];
+   int err;
+
+   LTC_ARGCHK(md != NULL);
+
+   if ((!outlen) || (outlen > BLAKE2S_OUTBYTES))
+      return CRYPT_INVALID_ARG;
+
+   if ((key && !keylen) || (keylen && !key) || (keylen > BLAKE2S_KEYBYTES))
+      return CRYPT_INVALID_ARG;
+
+   XMEMSET(P, 0, sizeof(P));
+
+   P[O_DIGEST_LENGTH] = (unsigned char)outlen;
+   P[O_KEY_LENGTH] = (unsigned char)keylen;
+   P[O_FANOUT] = 1;
+   P[O_DEPTH] = 1;
+
+   err = blake2s_init_param(md, P);
+   if (err != CRYPT_OK) return err;
+
+   if (key) {
+      unsigned char block[BLAKE2S_BLOCKBYTES];
+
+      XMEMSET(block, 0, BLAKE2S_BLOCKBYTES);
+      XMEMCPY(block, key, keylen);
+      blake2s_process(md, block, BLAKE2S_BLOCKBYTES);
+
+#ifdef LTC_CLEAN_STACK
+      zeromem(block, sizeof(block));
+#endif
+   }
+   return CRYPT_OK;
+}
+
+int blake2s_128_init(hash_state *md) { return blake2s_init(md, 16, NULL, 0); }
+
+int blake2s_160_init(hash_state *md) { return blake2s_init(md, 20, NULL, 0); }
+
+int blake2s_224_init(hash_state *md) { return blake2s_init(md, 28, NULL, 0); }
+
+int blake2s_256_init(hash_state *md) { return blake2s_init(md, 32, NULL, 0); }
+
+#define G(r, i, a, b, c, d)                                                                                            \
+   do {                                                                                                                \
+      a = a + b + m[blake2s_sigma[r][2 * i + 0]];                                                                      \
+      d = ROR(d ^ a, 16);                                                                                              \
+      c = c + d;                                                                                                       \
+      b = ROR(b ^ c, 12);                                                                                              \
+      a = a + b + m[blake2s_sigma[r][2 * i + 1]];                                                                      \
+      d = ROR(d ^ a, 8);                                                                                               \
+      c = c + d;                                                                                                       \
+      b = ROR(b ^ c, 7);                                                                                               \
+   } while (0)
+#define ROUND(r)                                                                                                       \
+   do {                                                                                                                \
+      G(r, 0, v[0], v[4], v[8], v[12]);                                                                                \
+      G(r, 1, v[1], v[5], v[9], v[13]);                                                                                \
+      G(r, 2, v[2], v[6], v[10], v[14]);                                                                               \
+      G(r, 3, v[3], v[7], v[11], v[15]);                                                                               \
+      G(r, 4, v[0], v[5], v[10], v[15]);                                                                               \
+      G(r, 5, v[1], v[6], v[11], v[12]);                                                                               \
+      G(r, 6, v[2], v[7], v[8], v[13]);                                                                                \
+      G(r, 7, v[3], v[4], v[9], v[14]);                                                                                \
+   } while (0)
+
+#ifdef LTC_CLEAN_STACK
+static int _blake2s_compress(hash_state *md, const unsigned char *buf)
+#else
+static int blake2s_compress(hash_state *md, const unsigned char *buf)
+#endif
+{
+   unsigned long i;
+   ulong32 m[16];
+   ulong32 v[16];
+
+   for (i = 0; i < 16; ++i) {
+      LOAD32L(m[i], buf + i * sizeof(m[i]));
+   }
+
+   for (i = 0; i < 8; ++i)
+      v[i] = md->blake2s.h[i];
+
+   v[8] = blake2s_IV[0];
+   v[9] = blake2s_IV[1];
+   v[10] = blake2s_IV[2];
+   v[11] = blake2s_IV[3];
+   v[12] = md->blake2s.t[0] ^ blake2s_IV[4];
+   v[13] = md->blake2s.t[1] ^ blake2s_IV[5];
+   v[14] = md->blake2s.f[0] ^ blake2s_IV[6];
+   v[15] = md->blake2s.f[1] ^ blake2s_IV[7];
+
+   ROUND(0);
+   ROUND(1);
+   ROUND(2);
+   ROUND(3);
+   ROUND(4);
+   ROUND(5);
+   ROUND(6);
+   ROUND(7);
+   ROUND(8);
+   ROUND(9);
+
+   for (i = 0; i < 8; ++i)
+      md->blake2s.h[i] = md->blake2s.h[i] ^ v[i] ^ v[i + 8];
+
+   return CRYPT_OK;
+}
+#undef G
+#undef ROUND
+
+#ifdef LTC_CLEAN_STACK
+static int blake2s_compress(hash_state *md, const unsigned char *buf)
+{
+   int err;
+   err = _blake2s_compress(md, buf);
+   burn_stack(sizeof(ulong32) * (32) + sizeof(unsigned long));
+   return err;
+}
+#endif
+
+int blake2s_process(hash_state *md, const unsigned char *in, unsigned long inlen)
+{
+   LTC_ARGCHK(md != NULL);
+   LTC_ARGCHK(in != NULL);
+
+   if (md->blake2s.curlen > sizeof(md->blake2s.buf)) {
+      return CRYPT_INVALID_ARG;
+   }
+
+   if (inlen > 0) {
+      unsigned long left = md->blake2s.curlen;
+      unsigned long fill = BLAKE2S_BLOCKBYTES - left;
+      if (inlen > fill) {
+         md->blake2s.curlen = 0;
+         XMEMCPY(md->blake2s.buf + (left % sizeof(md->blake2s.buf)), in, fill); /* Fill buffer */
+         blake2s_increment_counter(md, BLAKE2S_BLOCKBYTES);
+         blake2s_compress(md, md->blake2s.buf); /* Compress */
+         in += fill;
+         inlen -= fill;
+         while (inlen > BLAKE2S_BLOCKBYTES) {
+            blake2s_increment_counter(md, BLAKE2S_BLOCKBYTES);
+            blake2s_compress(md, in);
+            in += BLAKE2S_BLOCKBYTES;
+            inlen -= BLAKE2S_BLOCKBYTES;
+         }
+      }
+      XMEMCPY(md->blake2s.buf + md->blake2s.curlen, in, inlen);
+      md->blake2s.curlen += inlen;
+   }
+   return CRYPT_OK;
+}
+
+int blake2s_done(hash_state *md, unsigned char *out)
+{
+   unsigned char buffer[BLAKE2S_OUTBYTES] = { 0 };
+   unsigned long i;
+
+   LTC_ARGCHK(md != NULL);
+   LTC_ARGCHK(out != NULL);
+
+   /* if(md->blake2s.outlen != outlen) return CRYPT_INVALID_ARG; */
+
+   if (blake2s_is_lastblock(md))
+      return CRYPT_ERROR;
+
+   blake2s_increment_counter(md, md->blake2s.curlen);
+   blake2s_set_lastblock(md);
+   XMEMSET(md->blake2s.buf + md->blake2s.curlen, 0, BLAKE2S_BLOCKBYTES - md->blake2s.curlen); /* Padding */
+   blake2s_compress(md, md->blake2s.buf);
+
+   for (i = 0; i < 8; ++i) /* Output full hash to temp buffer */
+      STORE32L(md->blake2s.h[i], buffer + i * 4);
+
+   XMEMCPY(out, buffer, md->blake2s.outlen);
+   zeromem(md, sizeof(hash_state));
+#ifdef LTC_CLEAN_STACK
+   zeromem(buffer, sizeof(buffer));
+#endif
+   return CRYPT_OK;
+}
+
+/**
+  Self-test the hash
+  @return CRYPT_OK if successful, CRYPT_NOP if self-tests have been disabled
+*/
+int blake2s_256_test(void)
+{
+#ifndef LTC_TEST
+   return CRYPT_NOP;
+#else
+   static const struct {
+      const char *msg;
+      unsigned char hash[32];
+  } tests[] = {
+    { "",
+      { 0x69, 0x21, 0x7a, 0x30, 0x79, 0x90, 0x80, 0x94,
+        0xe1, 0x11, 0x21, 0xd0, 0x42, 0x35, 0x4a, 0x7c,
+        0x1f, 0x55, 0xb6, 0x48, 0x2c, 0xa1, 0xa5, 0x1e,
+        0x1b, 0x25, 0x0d, 0xfd, 0x1e, 0xd0, 0xee, 0xf9 } },
+    { "abc",
+      { 0x50, 0x8c, 0x5e, 0x8c, 0x32, 0x7c, 0x14, 0xe2,
+        0xe1, 0xa7, 0x2b, 0xa3, 0x4e, 0xeb, 0x45, 0x2f,
+        0x37, 0x45, 0x8b, 0x20, 0x9e, 0xd6, 0x3a, 0x29,
+        0x4d, 0x99, 0x9b, 0x4c, 0x86, 0x67, 0x59, 0x82 } },
+    { "12345678901234567890123456789012345678901234567890"
+      "12345678901234567890123456789012345678901234567890"
+      "12345678901234567890123456789012345678901234567890"
+      "12345678901234567890123456789012345678901234567890"
+      "12345678901234567890123456789012345678901234567890"
+      "12345678901234567890123456789012345678901234567890",
+      { 0xa3, 0x78, 0x8b, 0x5b, 0x59, 0xee, 0xe4, 0x41,
+        0x95, 0x23, 0x58, 0x00, 0xa4, 0xf9, 0xfa, 0x41,
+        0x86, 0x0c, 0x7b, 0x1c, 0x35, 0xa2, 0x42, 0x70,
+        0x50, 0x80, 0x79, 0x56, 0xe3, 0xbe, 0x31, 0x74 } },
+
+    { NULL, { 0 } }
+  };
+
+   int i;
+   unsigned char tmp[32];
+   hash_state md;
+
+   for (i = 0; tests[i].msg != NULL; i++) {
+      blake2s_256_init(&md);
+      blake2s_process(&md, (unsigned char *)tests[i].msg, (unsigned long)strlen(tests[i].msg));
+      blake2s_done(&md, tmp);
+      if (compare_testvector(tmp, sizeof(tmp), tests[i].hash, sizeof(tests[i].hash), "BLAKE2S_256", i)) {
+         return CRYPT_FAIL_TESTVECTOR;
+      }
+
+   }
+   return CRYPT_OK;
+#endif
+}
+
+/**
+  Self-test the hash
+  @return CRYPT_OK if successful, CRYPT_NOP if self-tests have been disabled
+*/
+int blake2s_224_test(void)
+{
+#ifndef LTC_TEST
+   return CRYPT_NOP;
+#else
+   static const struct {
+      const char *msg;
+      unsigned char hash[28];
+  } tests[] = {
+    { "",
+      { 0x1f, 0xa1, 0x29, 0x1e, 0x65, 0x24, 0x8b, 0x37,
+        0xb3, 0x43, 0x34, 0x75, 0xb2, 0xa0, 0xdd, 0x63,
+        0xd5, 0x4a, 0x11, 0xec, 0xc4, 0xe3, 0xe0, 0x34,
+        0xe7, 0xbc, 0x1e, 0xf4 } },
+    { "abc",
+      { 0x0b, 0x03, 0x3f, 0xc2, 0x26, 0xdf, 0x7a, 0xbd,
+        0xe2, 0x9f, 0x67, 0xa0, 0x5d, 0x3d, 0xc6, 0x2c,
+        0xf2, 0x71, 0xef, 0x3d, 0xfe, 0xa4, 0xd3, 0x87,
+        0x40, 0x7f, 0xbd, 0x55 } },
+
+    { NULL, { 0 } }
+  };
+
+   int i;
+   unsigned char tmp[28];
+   hash_state md;
+
+   for (i = 0; tests[i].msg != NULL; i++) {
+      blake2s_224_init(&md);
+      blake2s_process(&md, (unsigned char *)tests[i].msg, (unsigned long)strlen(tests[i].msg));
+      blake2s_done(&md, tmp);
+      if (compare_testvector(tmp, sizeof(tmp), tests[i].hash, sizeof(tests[i].hash), "BLAKE2S_224", i)) {
+         return CRYPT_FAIL_TESTVECTOR;
+      }
+
+   }
+   return CRYPT_OK;
+#endif
+}
+
+/**
+  Self-test the hash
+  @return CRYPT_OK if successful, CRYPT_NOP if self-tests have been disabled
+*/
+int blake2s_160_test(void)
+{
+#ifndef LTC_TEST
+   return CRYPT_NOP;
+#else
+   static const struct {
+      const char *msg;
+      unsigned char hash[20];
+  } tests[] = {
+    { "",
+      { 0x35, 0x4c, 0x9c, 0x33, 0xf7, 0x35, 0x96, 0x24,
+        0x18, 0xbd, 0xac, 0xb9, 0x47, 0x98, 0x73, 0x42,
+        0x9c, 0x34, 0x91, 0x6f} },
+    { "abc",
+      { 0x5a, 0xe3, 0xb9, 0x9b, 0xe2, 0x9b, 0x01, 0x83,
+        0x4c, 0x3b, 0x50, 0x85, 0x21, 0xed, 0xe6, 0x04,
+        0x38, 0xf8, 0xde, 0x17 } },
+
+    { NULL, { 0 } }
+  };
+
+   int i;
+   unsigned char tmp[20];
+   hash_state md;
+
+   for (i = 0; tests[i].msg != NULL; i++) {
+      blake2s_160_init(&md);
+      blake2s_process(&md, (unsigned char *)tests[i].msg, (unsigned long)strlen(tests[i].msg));
+      blake2s_done(&md, tmp);
+      if (compare_testvector(tmp, sizeof(tmp), tests[i].hash, sizeof(tests[i].hash), "BLAKE2S_160", i)) {
+         return CRYPT_FAIL_TESTVECTOR;
+      }
+
+   }
+   return CRYPT_OK;
+#endif
+}
+
+/**
+  Self-test the hash
+  @return CRYPT_OK if successful, CRYPT_NOP if self-tests have been disabled
+*/
+int blake2s_128_test(void)
+{
+#ifndef LTC_TEST
+   return CRYPT_NOP;
+#else
+   static const struct {
+      const char *msg;
+      unsigned char hash[16];
+  } tests[] = {
+    { "",
+      { 0x64, 0x55, 0x0d, 0x6f, 0xfe, 0x2c, 0x0a, 0x01,
+        0xa1, 0x4a, 0xba, 0x1e, 0xad, 0xe0, 0x20, 0x0c } },
+    { "abc",
+      { 0xaa, 0x49, 0x38, 0x11, 0x9b, 0x1d, 0xc7, 0xb8,
+        0x7c, 0xba, 0xd0, 0xff, 0xd2, 0x00, 0xd0, 0xae } },
+
+    { NULL, { 0 } }
+  };
+
+   int i;
+   unsigned char tmp[16];
+   hash_state md;
+
+   for (i = 0; tests[i].msg != NULL; i++) {
+      blake2s_128_init(&md);
+      blake2s_process(&md, (unsigned char *)tests[i].msg, (unsigned long)strlen(tests[i].msg));
+      blake2s_done(&md, tmp);
+      if (compare_testvector(tmp, sizeof(tmp), tests[i].hash, sizeof(tests[i].hash), "BLAKE2S_128", i)) {
+         return CRYPT_FAIL_TESTVECTOR;
+      }
+   }
+   return CRYPT_OK;
+#endif
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/hashes/chc/chc.c b/libtomcrypt/src/hashes/chc/chc.c
new file mode 100644 (file)
index 0000000..0861a88
--- /dev/null
@@ -0,0 +1,306 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+#include "tomcrypt.h"
+
+/**
+  @file chc.c
+  CHC support. (Tom St Denis)
+*/
+
+#ifdef LTC_CHC_HASH
+
+#define UNDEFED_HASH  -17
+
+/* chc settings */
+static int            cipher_idx=UNDEFED_HASH,        /* which cipher */
+                      cipher_blocksize;               /* blocksize of cipher */
+
+
+const struct ltc_hash_descriptor chc_desc = {
+   "chc_hash", 12, 0, 0, { 0 }, 0,
+   &chc_init,
+   &chc_process,
+   &chc_done,
+   &chc_test,
+   NULL
+};
+
+/**
+  Initialize the CHC state with a given cipher
+  @param cipher  The index of the cipher you wish to bind
+  @return CRYPT_OK if successful
+*/
+int chc_register(int cipher)
+{
+   int err, kl, idx;
+
+   if ((err = cipher_is_valid(cipher)) != CRYPT_OK) {
+      return err;
+   }
+
+   /* will it be valid? */
+   kl = cipher_descriptor[cipher].block_length;
+
+   /* must be >64 bit block */
+   if (kl <= 8) {
+      return CRYPT_INVALID_CIPHER;
+   }
+
+   /* can we use the ideal keysize? */
+   if ((err = cipher_descriptor[cipher].keysize(&kl)) != CRYPT_OK) {
+      return err;
+   }
+   /* we require that key size == block size be a valid choice */
+   if (kl != cipher_descriptor[cipher].block_length) {
+      return CRYPT_INVALID_CIPHER;
+   }
+
+   /* determine if chc_hash has been register_hash'ed already */
+   if ((err = hash_is_valid(idx = find_hash("chc_hash"))) != CRYPT_OK) {
+      return err;
+   }
+
+   /* store into descriptor */
+   hash_descriptor[idx].hashsize  =
+   hash_descriptor[idx].blocksize = cipher_descriptor[cipher].block_length;
+
+   /* store the idx and block size */
+   cipher_idx       = cipher;
+   cipher_blocksize = cipher_descriptor[cipher].block_length;
+   return CRYPT_OK;
+}
+
+/**
+   Initialize the hash state
+   @param md   The hash state you wish to initialize
+   @return CRYPT_OK if successful
+*/
+int chc_init(hash_state *md)
+{
+   symmetric_key *key;
+   unsigned char  buf[MAXBLOCKSIZE];
+   int            err;
+
+   LTC_ARGCHK(md != NULL);
+
+   /* is the cipher valid? */
+   if ((err = cipher_is_valid(cipher_idx)) != CRYPT_OK) {
+      return err;
+   }
+
+   if (cipher_blocksize != cipher_descriptor[cipher_idx].block_length) {
+      return CRYPT_INVALID_CIPHER;
+   }
+
+   if ((key = XMALLOC(sizeof(*key))) == NULL) {
+      return CRYPT_MEM;
+   }
+
+   /* zero key and what not */
+   zeromem(buf, cipher_blocksize);
+   if ((err = cipher_descriptor[cipher_idx].setup(buf, cipher_blocksize, 0, key)) != CRYPT_OK) {
+      XFREE(key);
+      return err;
+   }
+
+   /* encrypt zero block */
+   cipher_descriptor[cipher_idx].ecb_encrypt(buf, md->chc.state, key);
+
+   /* zero other members */
+   md->chc.length = 0;
+   md->chc.curlen = 0;
+   zeromem(md->chc.buf, sizeof(md->chc.buf));
+   XFREE(key);
+   return CRYPT_OK;
+}
+
+/*
+   key    <= state
+   T0,T1  <= block
+   T0     <= encrypt T0
+   state  <= state xor T0 xor T1
+*/
+static int chc_compress(hash_state *md, unsigned char *buf)
+{
+   unsigned char  T[2][MAXBLOCKSIZE];
+   symmetric_key *key;
+   int            err, x;
+
+   if ((key = XMALLOC(sizeof(*key))) == NULL) {
+      return CRYPT_MEM;
+   }
+   if ((err = cipher_descriptor[cipher_idx].setup(md->chc.state, cipher_blocksize, 0, key)) != CRYPT_OK) {
+      XFREE(key);
+      return err;
+   }
+   XMEMCPY(T[1], buf, cipher_blocksize);
+   cipher_descriptor[cipher_idx].ecb_encrypt(buf, T[0], key);
+   for (x = 0; x < cipher_blocksize; x++) {
+       md->chc.state[x] ^= T[0][x] ^ T[1][x];
+   }
+#ifdef LTC_CLEAN_STACK
+   zeromem(T, sizeof(T));
+   zeromem(key, sizeof(*key));
+#endif
+   XFREE(key);
+   return CRYPT_OK;
+}
+
+/**
+   Function for processing blocks
+   @param md   The hash state
+   @param buf  The data to hash
+   @param len  The length of the data (octets)
+   @return CRYPT_OK if successful
+*/
+static int _chc_process(hash_state * md, const unsigned char *buf, unsigned long len);
+static HASH_PROCESS(_chc_process, chc_compress, chc, (unsigned long)cipher_blocksize)
+
+/**
+   Process a block of memory though the hash
+   @param md   The hash state
+   @param in   The data to hash
+   @param inlen  The length of the data (octets)
+   @return CRYPT_OK if successful
+*/
+int chc_process(hash_state * md, const unsigned char *in, unsigned long inlen)
+{
+   int err;
+
+   LTC_ARGCHK(md   != NULL);
+   LTC_ARGCHK(in  != NULL);
+
+   /* is the cipher valid? */
+   if ((err = cipher_is_valid(cipher_idx)) != CRYPT_OK) {
+      return err;
+   }
+   if (cipher_blocksize != cipher_descriptor[cipher_idx].block_length) {
+      return CRYPT_INVALID_CIPHER;
+   }
+
+   return _chc_process(md, in, inlen);
+}
+
+/**
+   Terminate the hash to get the digest
+   @param md   The hash state
+   @param out [out] The destination of the hash (length of the block size of the block cipher)
+   @return CRYPT_OK if successful
+*/
+int chc_done(hash_state *md, unsigned char *out)
+{
+    int err;
+
+    LTC_ARGCHK(md   != NULL);
+    LTC_ARGCHK(out  != NULL);
+
+    /* is the cipher valid? */
+    if ((err = cipher_is_valid(cipher_idx)) != CRYPT_OK) {
+       return err;
+    }
+    if (cipher_blocksize != cipher_descriptor[cipher_idx].block_length) {
+       return CRYPT_INVALID_CIPHER;
+    }
+
+    if (md->chc.curlen >= sizeof(md->chc.buf)) {
+       return CRYPT_INVALID_ARG;
+    }
+
+    /* increase the length of the message */
+    md->chc.length += md->chc.curlen * 8;
+
+    /* append the '1' bit */
+    md->chc.buf[md->chc.curlen++] = (unsigned char)0x80;
+
+    /* if the length is currently above l-8 bytes we append zeros
+     * then compress.  Then we can fall back to padding zeros and length
+     * encoding like normal.
+     */
+    if (md->chc.curlen > (unsigned long)(cipher_blocksize - 8)) {
+        while (md->chc.curlen < (unsigned long)cipher_blocksize) {
+            md->chc.buf[md->chc.curlen++] = (unsigned char)0;
+        }
+        chc_compress(md, md->chc.buf);
+        md->chc.curlen = 0;
+    }
+
+    /* pad upto l-8 bytes of zeroes */
+    while (md->chc.curlen < (unsigned long)(cipher_blocksize - 8)) {
+        md->chc.buf[md->chc.curlen++] = (unsigned char)0;
+    }
+
+    /* store length */
+    STORE64L(md->chc.length, md->chc.buf+(cipher_blocksize-8));
+    chc_compress(md, md->chc.buf);
+
+    /* copy output */
+    XMEMCPY(out, md->chc.state, cipher_blocksize);
+
+#ifdef LTC_CLEAN_STACK
+    zeromem(md, sizeof(hash_state));
+#endif
+    return CRYPT_OK;
+}
+
+/**
+  Self-test the hash
+  @return CRYPT_OK if successful, CRYPT_NOP if self-tests have been disabled
+*/
+int chc_test(void)
+{
+#ifndef LTC_TEST
+   return CRYPT_NOP;
+#else
+   static const struct {
+      unsigned char *msg,
+                     hash[MAXBLOCKSIZE];
+      int            len;
+   } tests[] = {
+{
+   (unsigned char *)"hello world",
+   { 0xcf, 0x57, 0x9d, 0xc3, 0x0a, 0x0e, 0xea, 0x61,
+     0x0d, 0x54, 0x47, 0xc4, 0x3c, 0x06, 0xf5, 0x4e },
+   16
+}
+};
+   int i, oldhashidx, idx;
+   unsigned char tmp[MAXBLOCKSIZE];
+   hash_state md;
+
+   /* AES can be under rijndael or aes... try to find it */
+   if ((idx = find_cipher("aes")) == -1) {
+      if ((idx = find_cipher("rijndael")) == -1) {
+         return CRYPT_NOP;
+      }
+   }
+   oldhashidx = cipher_idx;
+   chc_register(idx);
+
+   for (i = 0; i < (int)(sizeof(tests)/sizeof(tests[0])); i++) {
+       chc_init(&md);
+       chc_process(&md, tests[i].msg, strlen((char *)tests[i].msg));
+       chc_done(&md, tmp);
+       if (compare_testvector(tmp, tests[i].len, tests[i].hash, tests[i].len, "CHC", i)) {
+          return CRYPT_FAIL_TESTVECTOR;
+       }
+   }
+   if (oldhashidx != UNDEFED_HASH) {
+      chc_register(oldhashidx);
+   }
+
+   return CRYPT_OK;
+#endif
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/hashes/helper/hash_file.c b/libtomcrypt/src/hashes/helper/hash_file.c
new file mode 100644 (file)
index 0000000..0b96eae
--- /dev/null
@@ -0,0 +1,53 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+#ifndef LTC_NO_FILE
+/**
+  @file hash_file.c
+  Hash a file, Tom St Denis
+*/
+
+/**
+  @param hash   The index of the hash desired
+  @param fname  The name of the file you wish to hash
+  @param out    [out] The destination of the digest
+  @param outlen [in/out] The max size and resulting size of the message digest
+  @result CRYPT_OK if successful
+*/
+int hash_file(int hash, const char *fname, unsigned char *out, unsigned long *outlen)
+{
+    FILE *in;
+    int err;
+    LTC_ARGCHK(fname  != NULL);
+    LTC_ARGCHK(out    != NULL);
+    LTC_ARGCHK(outlen != NULL);
+
+    if ((err = hash_is_valid(hash)) != CRYPT_OK) {
+        return err;
+    }
+
+    in = fopen(fname, "rb");
+    if (in == NULL) {
+       return CRYPT_FILE_NOTFOUND;
+    }
+
+    err = hash_filehandle(hash, in, out, outlen);
+    if (fclose(in) != 0) {
+       return CRYPT_ERROR;
+    }
+
+    return err;
+}
+#endif /* #ifndef LTC_NO_FILE */
+
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/hashes/helper/hash_filehandle.c b/libtomcrypt/src/hashes/helper/hash_filehandle.c
new file mode 100644 (file)
index 0000000..0e4d7a6
--- /dev/null
@@ -0,0 +1,74 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+#ifndef LTC_NO_FILE
+/**
+   @file hash_filehandle.c
+   Hash open files, Tom St Denis
+*/
+
+/**
+  Hash data from an open file handle.
+  @param hash   The index of the hash you want to use
+  @param in     The FILE* handle of the file you want to hash
+  @param out    [out] The destination of the digest
+  @param outlen [in/out] The max size and resulting size of the digest
+  @result CRYPT_OK if successful
+*/
+int hash_filehandle(int hash, FILE *in, unsigned char *out, unsigned long *outlen)
+{
+    hash_state md;
+    unsigned char *buf;
+    size_t x;
+    int err;
+
+    LTC_ARGCHK(out    != NULL);
+    LTC_ARGCHK(outlen != NULL);
+    LTC_ARGCHK(in     != NULL);
+
+    if ((buf = XMALLOC(LTC_FILE_READ_BUFSIZE)) == NULL) {
+        return CRYPT_MEM;
+    }
+
+    if ((err = hash_is_valid(hash)) != CRYPT_OK) {
+        goto LBL_ERR;
+    }
+
+    if (*outlen < hash_descriptor[hash].hashsize) {
+       *outlen = hash_descriptor[hash].hashsize;
+       err = CRYPT_BUFFER_OVERFLOW;
+       goto LBL_ERR;
+    }
+    if ((err = hash_descriptor[hash].init(&md)) != CRYPT_OK) {
+       goto LBL_ERR;
+    }
+
+    do {
+        x = fread(buf, 1, LTC_FILE_READ_BUFSIZE, in);
+        if ((err = hash_descriptor[hash].process(&md, buf, (unsigned long)x)) != CRYPT_OK) {
+           goto LBL_CLEANBUF;
+        }
+    } while (x == LTC_FILE_READ_BUFSIZE);
+    if ((err = hash_descriptor[hash].done(&md, out)) == CRYPT_OK) {
+       *outlen = hash_descriptor[hash].hashsize;
+    }
+
+LBL_CLEANBUF:
+    zeromem(buf, LTC_FILE_READ_BUFSIZE);
+LBL_ERR:
+    XFREE(buf);
+    return err;
+}
+#endif /* #ifndef LTC_NO_FILE */
+
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/hashes/helper/hash_memory.c b/libtomcrypt/src/hashes/helper/hash_memory.c
new file mode 100644 (file)
index 0000000..e8471ac
--- /dev/null
@@ -0,0 +1,69 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+#ifdef LTC_HASH_HELPERS
+/**
+  @file hash_memory.c
+  Hash memory helper, Tom St Denis
+*/
+
+/**
+  Hash a block of memory and store the digest.
+  @param hash   The index of the hash you wish to use
+  @param in     The data you wish to hash
+  @param inlen  The length of the data to hash (octets)
+  @param out    [out] Where to store the digest
+  @param outlen [in/out] Max size and resulting size of the digest
+  @return CRYPT_OK if successful
+*/
+int hash_memory(int hash, const unsigned char *in, unsigned long inlen, unsigned char *out, unsigned long *outlen)
+{
+    hash_state *md;
+    int err;
+
+    LTC_ARGCHK(in     != NULL);
+    LTC_ARGCHK(out    != NULL);
+    LTC_ARGCHK(outlen != NULL);
+
+    if ((err = hash_is_valid(hash)) != CRYPT_OK) {
+        return err;
+    }
+
+    if (*outlen < hash_descriptor[hash].hashsize) {
+       *outlen = hash_descriptor[hash].hashsize;
+       return CRYPT_BUFFER_OVERFLOW;
+    }
+
+    md = XMALLOC(sizeof(hash_state));
+    if (md == NULL) {
+       return CRYPT_MEM;
+    }
+
+    if ((err = hash_descriptor[hash].init(md)) != CRYPT_OK) {
+       goto LBL_ERR;
+    }
+    if ((err = hash_descriptor[hash].process(md, in, inlen)) != CRYPT_OK) {
+       goto LBL_ERR;
+    }
+    err = hash_descriptor[hash].done(md, out);
+    *outlen = hash_descriptor[hash].hashsize;
+LBL_ERR:
+#ifdef LTC_CLEAN_STACK
+    zeromem(md, sizeof(hash_state));
+#endif
+    XFREE(md);
+
+    return err;
+}
+#endif /* #ifdef LTC_HASH_HELPERS */
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/hashes/helper/hash_memory_multi.c b/libtomcrypt/src/hashes/helper/hash_memory_multi.c
new file mode 100644 (file)
index 0000000..d10b458
--- /dev/null
@@ -0,0 +1,88 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+#include <stdarg.h>
+
+#ifdef LTC_HASH_HELPERS
+/**
+  @file hash_memory_multi.c
+  Hash (multiple buffers) memory helper, Tom St Denis
+*/
+
+/**
+  Hash multiple (non-adjacent) blocks of memory at once.
+  @param hash   The index of the hash you wish to use
+  @param out    [out] Where to store the digest
+  @param outlen [in/out] Max size and resulting size of the digest
+  @param in     The data you wish to hash
+  @param inlen  The length of the data to hash (octets)
+  @param ...    tuples of (data,len) pairs to hash, terminated with a (NULL,x) (x=don't care)
+  @return CRYPT_OK if successful
+*/
+int hash_memory_multi(int hash, unsigned char *out, unsigned long *outlen,
+                      const unsigned char *in, unsigned long inlen, ...)
+{
+    hash_state          *md;
+    int                  err;
+    va_list              args;
+    const unsigned char *curptr;
+    unsigned long        curlen;
+
+    LTC_ARGCHK(in     != NULL);
+    LTC_ARGCHK(out    != NULL);
+    LTC_ARGCHK(outlen != NULL);
+
+    if ((err = hash_is_valid(hash)) != CRYPT_OK) {
+        return err;
+    }
+
+    if (*outlen < hash_descriptor[hash].hashsize) {
+       *outlen = hash_descriptor[hash].hashsize;
+       return CRYPT_BUFFER_OVERFLOW;
+    }
+
+    md = XMALLOC(sizeof(hash_state));
+    if (md == NULL) {
+       return CRYPT_MEM;
+    }
+
+    if ((err = hash_descriptor[hash].init(md)) != CRYPT_OK) {
+       goto LBL_ERR;
+    }
+
+    va_start(args, inlen);
+    curptr = in;
+    curlen = inlen;
+    for (;;) {
+       /* process buf */
+       if ((err = hash_descriptor[hash].process(md, curptr, curlen)) != CRYPT_OK) {
+          goto LBL_ERR;
+       }
+       /* step to next */
+       curptr = va_arg(args, const unsigned char*);
+       if (curptr == NULL) {
+          break;
+       }
+       curlen = va_arg(args, unsigned long);
+    }
+    err = hash_descriptor[hash].done(md, out);
+    *outlen = hash_descriptor[hash].hashsize;
+LBL_ERR:
+#ifdef LTC_CLEAN_STACK
+    zeromem(md, sizeof(hash_state));
+#endif
+    XFREE(md);
+    va_end(args);
+    return err;
+}
+#endif /* #ifdef LTC_HASH_HELPERS */
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/hashes/md2.c b/libtomcrypt/src/hashes/md2.c
new file mode 100644 (file)
index 0000000..36cc8ae
--- /dev/null
@@ -0,0 +1,250 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+   @param md2.c
+   LTC_MD2 (RFC 1319) hash function implementation by Tom St Denis
+*/
+
+#ifdef LTC_MD2
+
+const struct ltc_hash_descriptor md2_desc =
+{
+    "md2",
+    7,
+    16,
+    16,
+
+    /* OID */
+   { 1, 2, 840, 113549, 2, 2,  },
+   6,
+
+    &md2_init,
+    &md2_process,
+    &md2_done,
+    &md2_test,
+    NULL
+};
+
+static const unsigned char PI_SUBST[256] = {
+  41, 46, 67, 201, 162, 216, 124, 1, 61, 54, 84, 161, 236, 240, 6,
+  19, 98, 167, 5, 243, 192, 199, 115, 140, 152, 147, 43, 217, 188,
+  76, 130, 202, 30, 155, 87, 60, 253, 212, 224, 22, 103, 66, 111, 24,
+  138, 23, 229, 18, 190, 78, 196, 214, 218, 158, 222, 73, 160, 251,
+  245, 142, 187, 47, 238, 122, 169, 104, 121, 145, 21, 178, 7, 63,
+  148, 194, 16, 137, 11, 34, 95, 33, 128, 127, 93, 154, 90, 144, 50,
+  39, 53, 62, 204, 231, 191, 247, 151, 3, 255, 25, 48, 179, 72, 165,
+  181, 209, 215, 94, 146, 42, 172, 86, 170, 198, 79, 184, 56, 210,
+  150, 164, 125, 182, 118, 252, 107, 226, 156, 116, 4, 241, 69, 157,
+  112, 89, 100, 113, 135, 32, 134, 91, 207, 101, 230, 45, 168, 2, 27,
+  96, 37, 173, 174, 176, 185, 246, 28, 70, 97, 105, 52, 64, 126, 15,
+  85, 71, 163, 35, 221, 81, 175, 58, 195, 92, 249, 206, 186, 197,
+  234, 38, 44, 83, 13, 110, 133, 40, 132, 9, 211, 223, 205, 244, 65,
+  129, 77, 82, 106, 220, 55, 200, 108, 193, 171, 250, 36, 225, 123,
+  8, 12, 189, 177, 74, 120, 136, 149, 139, 227, 99, 232, 109, 233,
+  203, 213, 254, 59, 0, 29, 57, 242, 239, 183, 14, 102, 88, 208, 228,
+  166, 119, 114, 248, 235, 117, 75, 10, 49, 68, 80, 180, 143, 237,
+  31, 26, 219, 153, 141, 51, 159, 17, 131, 20
+};
+
+/* adds 16 bytes to the checksum */
+static void md2_update_chksum(hash_state *md)
+{
+   int j;
+   unsigned char L;
+   L = md->md2.chksum[15];
+   for (j = 0; j < 16; j++) {
+
+/* caution, the RFC says its "C[j] = S[M[i*16+j] xor L]" but the reference source code [and test vectors] say
+   otherwise.
+*/
+       L = (md->md2.chksum[j] ^= PI_SUBST[(int)(md->md2.buf[j] ^ L)] & 255);
+   }
+}
+
+static void md2_compress(hash_state *md)
+{
+   int j, k;
+   unsigned char t;
+
+   /* copy block */
+   for (j = 0; j < 16; j++) {
+       md->md2.X[16+j] = md->md2.buf[j];
+       md->md2.X[32+j] = md->md2.X[j] ^ md->md2.X[16+j];
+   }
+
+   t = (unsigned char)0;
+
+   /* do 18 rounds */
+   for (j = 0; j < 18; j++) {
+       for (k = 0; k < 48; k++) {
+           t = (md->md2.X[k] ^= PI_SUBST[(int)(t & 255)]);
+       }
+       t = (t + (unsigned char)j) & 255;
+   }
+}
+
+/**
+   Initialize the hash state
+   @param md   The hash state you wish to initialize
+   @return CRYPT_OK if successful
+*/
+int md2_init(hash_state *md)
+{
+   LTC_ARGCHK(md != NULL);
+
+   /* LTC_MD2 uses a zero'ed state... */
+   zeromem(md->md2.X, sizeof(md->md2.X));
+   zeromem(md->md2.chksum, sizeof(md->md2.chksum));
+   zeromem(md->md2.buf, sizeof(md->md2.buf));
+   md->md2.curlen = 0;
+   return CRYPT_OK;
+}
+
+/**
+   Process a block of memory though the hash
+   @param md     The hash state
+   @param in     The data to hash
+   @param inlen  The length of the data (octets)
+   @return CRYPT_OK if successful
+*/
+int md2_process(hash_state *md, const unsigned char *in, unsigned long inlen)
+{
+    unsigned long n;
+    LTC_ARGCHK(md != NULL);
+    LTC_ARGCHK(in != NULL);
+    if (md-> md2 .curlen > sizeof(md-> md2 .buf)) {
+       return CRYPT_INVALID_ARG;
+    }
+    while (inlen > 0) {
+        n = MIN(inlen, (16 - md->md2.curlen));
+        XMEMCPY(md->md2.buf + md->md2.curlen, in, (size_t)n);
+        md->md2.curlen += n;
+        in             += n;
+        inlen          -= n;
+
+        /* is 16 bytes full? */
+        if (md->md2.curlen == 16) {
+            md2_compress(md);
+            md2_update_chksum(md);
+            md->md2.curlen = 0;
+        }
+    }
+    return CRYPT_OK;
+}
+
+/**
+   Terminate the hash to get the digest
+   @param md  The hash state
+   @param out [out] The destination of the hash (16 bytes)
+   @return CRYPT_OK if successful
+*/
+int md2_done(hash_state * md, unsigned char *out)
+{
+    unsigned long i, k;
+
+    LTC_ARGCHK(md  != NULL);
+    LTC_ARGCHK(out != NULL);
+
+    if (md->md2.curlen >= sizeof(md->md2.buf)) {
+       return CRYPT_INVALID_ARG;
+    }
+
+
+    /* pad the message */
+    k = 16 - md->md2.curlen;
+    for (i = md->md2.curlen; i < 16; i++) {
+        md->md2.buf[i] = (unsigned char)k;
+    }
+
+    /* hash and update */
+    md2_compress(md);
+    md2_update_chksum(md);
+
+    /* hash checksum */
+    XMEMCPY(md->md2.buf, md->md2.chksum, 16);
+    md2_compress(md);
+
+    /* output is lower 16 bytes of X */
+    XMEMCPY(out, md->md2.X, 16);
+
+#ifdef LTC_CLEAN_STACK
+    zeromem(md, sizeof(hash_state));
+#endif
+    return CRYPT_OK;
+}
+
+/**
+  Self-test the hash
+  @return CRYPT_OK if successful, CRYPT_NOP if self-tests have been disabled
+*/
+int md2_test(void)
+{
+ #ifndef LTC_TEST
+    return CRYPT_NOP;
+ #else
+   static const struct {
+        const char *msg;
+        unsigned char hash[16];
+   } tests[] = {
+      { "",
+        {0x83,0x50,0xe5,0xa3,0xe2,0x4c,0x15,0x3d,
+         0xf2,0x27,0x5c,0x9f,0x80,0x69,0x27,0x73
+        }
+      },
+      { "a",
+        {0x32,0xec,0x01,0xec,0x4a,0x6d,0xac,0x72,
+         0xc0,0xab,0x96,0xfb,0x34,0xc0,0xb5,0xd1
+        }
+      },
+      { "message digest",
+        {0xab,0x4f,0x49,0x6b,0xfb,0x2a,0x53,0x0b,
+         0x21,0x9f,0xf3,0x30,0x31,0xfe,0x06,0xb0
+        }
+      },
+      { "abcdefghijklmnopqrstuvwxyz",
+        {0x4e,0x8d,0xdf,0xf3,0x65,0x02,0x92,0xab,
+         0x5a,0x41,0x08,0xc3,0xaa,0x47,0x94,0x0b
+        }
+      },
+      { "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
+        {0xda,0x33,0xde,0xf2,0xa4,0x2d,0xf1,0x39,
+         0x75,0x35,0x28,0x46,0xc3,0x03,0x38,0xcd
+        }
+      },
+      { "12345678901234567890123456789012345678901234567890123456789012345678901234567890",
+        {0xd5,0x97,0x6f,0x79,0xd8,0x3d,0x3a,0x0d,
+         0xc9,0x80,0x6c,0x3c,0x66,0xf3,0xef,0xd8
+        }
+      }
+   };
+
+   int i;
+   unsigned char tmp[16];
+   hash_state md;
+
+   for (i = 0; i < (int)(sizeof(tests) / sizeof(tests[0])); i++) {
+       md2_init(&md);
+       md2_process(&md, (unsigned char*)tests[i].msg, (unsigned long)strlen(tests[i].msg));
+       md2_done(&md, tmp);
+       if (compare_testvector(tmp, sizeof(tmp), tests[i].hash, sizeof(tests[i].hash), "MD2", i)) {
+          return CRYPT_FAIL_TESTVECTOR;
+       }
+   }
+   return CRYPT_OK;
+  #endif
+}
+
+#endif
+
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/hashes/md4.c b/libtomcrypt/src/hashes/md4.c
new file mode 100644 (file)
index 0000000..09b6e31
--- /dev/null
@@ -0,0 +1,306 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+   @param md4.c
+   Submitted by Dobes Vandermeer  (dobes@smartt.com)
+*/
+
+#ifdef LTC_MD4
+
+const struct ltc_hash_descriptor md4_desc =
+{
+    "md4",
+    6,
+    16,
+    64,
+
+    /* OID */
+   { 1, 2, 840, 113549, 2, 4,  },
+   6,
+
+    &md4_init,
+    &md4_process,
+    &md4_done,
+    &md4_test,
+    NULL
+};
+
+#define S11 3
+#define S12 7
+#define S13 11
+#define S14 19
+#define S21 3
+#define S22 5
+#define S23 9
+#define S24 13
+#define S31 3
+#define S32 9
+#define S33 11
+#define S34 15
+
+/* F, G and H are basic LTC_MD4 functions. */
+#define F(x, y, z) (z ^ (x & (y ^ z)))
+#define G(x, y, z) ((x & y) | (z & (x | y)))
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+
+/* ROTATE_LEFT rotates x left n bits. */
+#define ROTATE_LEFT(x, n) ROLc(x, n)
+
+/* FF, GG and HH are transformations for rounds 1, 2 and 3 */
+/* Rotation is separate from addition to prevent recomputation */
+
+#define FF(a, b, c, d, x, s) { \
+    (a) += F ((b), (c), (d)) + (x); \
+    (a) = ROTATE_LEFT ((a), (s)); \
+  }
+#define GG(a, b, c, d, x, s) { \
+    (a) += G ((b), (c), (d)) + (x) + 0x5a827999UL; \
+    (a) = ROTATE_LEFT ((a), (s)); \
+  }
+#define HH(a, b, c, d, x, s) { \
+    (a) += H ((b), (c), (d)) + (x) + 0x6ed9eba1UL; \
+    (a) = ROTATE_LEFT ((a), (s)); \
+  }
+
+#ifdef LTC_CLEAN_STACK
+static int _md4_compress(hash_state *md, unsigned char *buf)
+#else
+static int  md4_compress(hash_state *md, unsigned char *buf)
+#endif
+{
+    ulong32 x[16], a, b, c, d;
+    int i;
+
+    /* copy state */
+    a = md->md4.state[0];
+    b = md->md4.state[1];
+    c = md->md4.state[2];
+    d = md->md4.state[3];
+
+    /* copy the state into 512-bits into W[0..15] */
+    for (i = 0; i < 16; i++) {
+        LOAD32L(x[i], buf + (4*i));
+    }
+
+    /* Round 1 */
+    FF (a, b, c, d, x[ 0], S11); /* 1 */
+    FF (d, a, b, c, x[ 1], S12); /* 2 */
+    FF (c, d, a, b, x[ 2], S13); /* 3 */
+    FF (b, c, d, a, x[ 3], S14); /* 4 */
+    FF (a, b, c, d, x[ 4], S11); /* 5 */
+    FF (d, a, b, c, x[ 5], S12); /* 6 */
+    FF (c, d, a, b, x[ 6], S13); /* 7 */
+    FF (b, c, d, a, x[ 7], S14); /* 8 */
+    FF (a, b, c, d, x[ 8], S11); /* 9 */
+    FF (d, a, b, c, x[ 9], S12); /* 10 */
+    FF (c, d, a, b, x[10], S13); /* 11 */
+    FF (b, c, d, a, x[11], S14); /* 12 */
+    FF (a, b, c, d, x[12], S11); /* 13 */
+    FF (d, a, b, c, x[13], S12); /* 14 */
+    FF (c, d, a, b, x[14], S13); /* 15 */
+    FF (b, c, d, a, x[15], S14); /* 16 */
+
+    /* Round 2 */
+    GG (a, b, c, d, x[ 0], S21); /* 17 */
+    GG (d, a, b, c, x[ 4], S22); /* 18 */
+    GG (c, d, a, b, x[ 8], S23); /* 19 */
+    GG (b, c, d, a, x[12], S24); /* 20 */
+    GG (a, b, c, d, x[ 1], S21); /* 21 */
+    GG (d, a, b, c, x[ 5], S22); /* 22 */
+    GG (c, d, a, b, x[ 9], S23); /* 23 */
+    GG (b, c, d, a, x[13], S24); /* 24 */
+    GG (a, b, c, d, x[ 2], S21); /* 25 */
+    GG (d, a, b, c, x[ 6], S22); /* 26 */
+    GG (c, d, a, b, x[10], S23); /* 27 */
+    GG (b, c, d, a, x[14], S24); /* 28 */
+    GG (a, b, c, d, x[ 3], S21); /* 29 */
+    GG (d, a, b, c, x[ 7], S22); /* 30 */
+    GG (c, d, a, b, x[11], S23); /* 31 */
+    GG (b, c, d, a, x[15], S24); /* 32 */
+
+    /* Round 3 */
+    HH (a, b, c, d, x[ 0], S31); /* 33 */
+    HH (d, a, b, c, x[ 8], S32); /* 34 */
+    HH (c, d, a, b, x[ 4], S33); /* 35 */
+    HH (b, c, d, a, x[12], S34); /* 36 */
+    HH (a, b, c, d, x[ 2], S31); /* 37 */
+    HH (d, a, b, c, x[10], S32); /* 38 */
+    HH (c, d, a, b, x[ 6], S33); /* 39 */
+    HH (b, c, d, a, x[14], S34); /* 40 */
+    HH (a, b, c, d, x[ 1], S31); /* 41 */
+    HH (d, a, b, c, x[ 9], S32); /* 42 */
+    HH (c, d, a, b, x[ 5], S33); /* 43 */
+    HH (b, c, d, a, x[13], S34); /* 44 */
+    HH (a, b, c, d, x[ 3], S31); /* 45 */
+    HH (d, a, b, c, x[11], S32); /* 46 */
+    HH (c, d, a, b, x[ 7], S33); /* 47 */
+    HH (b, c, d, a, x[15], S34); /* 48 */
+
+
+    /* Update our state */
+    md->md4.state[0] = md->md4.state[0] + a;
+    md->md4.state[1] = md->md4.state[1] + b;
+    md->md4.state[2] = md->md4.state[2] + c;
+    md->md4.state[3] = md->md4.state[3] + d;
+
+    return CRYPT_OK;
+}
+
+#ifdef LTC_CLEAN_STACK
+static int md4_compress(hash_state *md, unsigned char *buf)
+{
+   int err;
+   err = _md4_compress(md, buf);
+   burn_stack(sizeof(ulong32) * 20 + sizeof(int));
+   return err;
+}
+#endif
+
+/**
+   Initialize the hash state
+   @param md   The hash state you wish to initialize
+   @return CRYPT_OK if successful
+*/
+int md4_init(hash_state * md)
+{
+   LTC_ARGCHK(md != NULL);
+   md->md4.state[0] = 0x67452301UL;
+   md->md4.state[1] = 0xefcdab89UL;
+   md->md4.state[2] = 0x98badcfeUL;
+   md->md4.state[3] = 0x10325476UL;
+   md->md4.length  = 0;
+   md->md4.curlen  = 0;
+   return CRYPT_OK;
+}
+
+/**
+   Process a block of memory though the hash
+   @param md     The hash state
+   @param in     The data to hash
+   @param inlen  The length of the data (octets)
+   @return CRYPT_OK if successful
+*/
+HASH_PROCESS(md4_process, md4_compress, md4, 64)
+
+/**
+   Terminate the hash to get the digest
+   @param md  The hash state
+   @param out [out] The destination of the hash (16 bytes)
+   @return CRYPT_OK if successful
+*/
+int md4_done(hash_state * md, unsigned char *out)
+{
+    int i;
+
+    LTC_ARGCHK(md  != NULL);
+    LTC_ARGCHK(out != NULL);
+
+    if (md->md4.curlen >= sizeof(md->md4.buf)) {
+       return CRYPT_INVALID_ARG;
+    }
+
+    /* increase the length of the message */
+    md->md4.length += md->md4.curlen * 8;
+
+    /* append the '1' bit */
+    md->md4.buf[md->md4.curlen++] = (unsigned char)0x80;
+
+    /* if the length is currently above 56 bytes we append zeros
+     * then compress.  Then we can fall back to padding zeros and length
+     * encoding like normal.
+     */
+    if (md->md4.curlen > 56) {
+        while (md->md4.curlen < 64) {
+            md->md4.buf[md->md4.curlen++] = (unsigned char)0;
+        }
+        md4_compress(md, md->md4.buf);
+        md->md4.curlen = 0;
+    }
+
+    /* pad upto 56 bytes of zeroes */
+    while (md->md4.curlen < 56) {
+        md->md4.buf[md->md4.curlen++] = (unsigned char)0;
+    }
+
+    /* store length */
+    STORE64L(md->md4.length, md->md4.buf+56);
+    md4_compress(md, md->md4.buf);
+
+    /* copy output */
+    for (i = 0; i < 4; i++) {
+        STORE32L(md->md4.state[i], out+(4*i));
+    }
+#ifdef LTC_CLEAN_STACK
+    zeromem(md, sizeof(hash_state));
+#endif
+    return CRYPT_OK;
+}
+
+/**
+  Self-test the hash
+  @return CRYPT_OK if successful, CRYPT_NOP if self-tests have been disabled
+*/
+int md4_test(void)
+{
+ #ifndef LTC_TEST
+    return CRYPT_NOP;
+ #else
+    static const struct md4_test_case {
+        const char *input;
+        unsigned char hash[16];
+    } tests[] = {
+        { "",
+          {0x31, 0xd6, 0xcf, 0xe0, 0xd1, 0x6a, 0xe9, 0x31,
+           0xb7, 0x3c, 0x59, 0xd7, 0xe0, 0xc0, 0x89, 0xc0} },
+        { "a",
+          {0xbd, 0xe5, 0x2c, 0xb3, 0x1d, 0xe3, 0x3e, 0x46,
+           0x24, 0x5e, 0x05, 0xfb, 0xdb, 0xd6, 0xfb, 0x24} },
+        { "abc",
+          {0xa4, 0x48, 0x01, 0x7a, 0xaf, 0x21, 0xd8, 0x52,
+           0x5f, 0xc1, 0x0a, 0xe8, 0x7a, 0xa6, 0x72, 0x9d} },
+        { "message digest",
+          {0xd9, 0x13, 0x0a, 0x81, 0x64, 0x54, 0x9f, 0xe8,
+           0x18, 0x87, 0x48, 0x06, 0xe1, 0xc7, 0x01, 0x4b} },
+        { "abcdefghijklmnopqrstuvwxyz",
+          {0xd7, 0x9e, 0x1c, 0x30, 0x8a, 0xa5, 0xbb, 0xcd,
+           0xee, 0xa8, 0xed, 0x63, 0xdf, 0x41, 0x2d, 0xa9} },
+        { "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
+          {0x04, 0x3f, 0x85, 0x82, 0xf2, 0x41, 0xdb, 0x35,
+           0x1c, 0xe6, 0x27, 0xe1, 0x53, 0xe7, 0xf0, 0xe4} },
+        { "12345678901234567890123456789012345678901234567890123456789012345678901234567890",
+          {0xe3, 0x3b, 0x4d, 0xdc, 0x9c, 0x38, 0xf2, 0x19,
+           0x9c, 0x3e, 0x7b, 0x16, 0x4f, 0xcc, 0x05, 0x36} },
+    };
+
+    int i;
+    unsigned char tmp[16];
+    hash_state md;
+
+    for(i = 0; i < (int)(sizeof(tests) / sizeof(tests[0])); i++) {
+        md4_init(&md);
+        md4_process(&md, (unsigned char *)tests[i].input, (unsigned long)strlen(tests[i].input));
+        md4_done(&md, tmp);
+        if (compare_testvector(tmp, sizeof(tmp), tests[i].hash, sizeof(tests[i].hash), "MD4", i)) {
+           return CRYPT_FAIL_TESTVECTOR;
+        }
+
+    }
+    return CRYPT_OK;
+  #endif
+}
+
+#endif
+
+
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/hashes/md5.c b/libtomcrypt/src/hashes/md5.c
new file mode 100644 (file)
index 0000000..511329a
--- /dev/null
@@ -0,0 +1,366 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+
+/**
+  @file md5.c
+  LTC_MD5 hash function by Tom St Denis
+*/
+
+#ifdef LTC_MD5
+
+const struct ltc_hash_descriptor md5_desc =
+{
+    "md5",
+    3,
+    16,
+    64,
+
+    /* OID */
+   { 1, 2, 840, 113549, 2, 5,  },
+   6,
+
+    &md5_init,
+    &md5_process,
+    &md5_done,
+    &md5_test,
+    NULL
+};
+
+#define F(x,y,z)  (z ^ (x & (y ^ z)))
+#define G(x,y,z)  (y ^ (z & (y ^ x)))
+#define H(x,y,z)  (x^y^z)
+#define I(x,y,z)  (y^(x|(~z)))
+
+#ifdef LTC_SMALL_CODE
+
+#define FF(a,b,c,d,M,s,t) \
+    a = (a + F(b,c,d) + M + t); a = ROL(a, s) + b;
+
+#define GG(a,b,c,d,M,s,t) \
+    a = (a + G(b,c,d) + M + t); a = ROL(a, s) + b;
+
+#define HH(a,b,c,d,M,s,t) \
+    a = (a + H(b,c,d) + M + t); a = ROL(a, s) + b;
+
+#define II(a,b,c,d,M,s,t) \
+    a = (a + I(b,c,d) + M + t); a = ROL(a, s) + b;
+
+static const unsigned char Worder[64] = {
+   0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,
+   1,6,11,0,5,10,15,4,9,14,3,8,13,2,7,12,
+   5,8,11,14,1,4,7,10,13,0,3,6,9,12,15,2,
+   0,7,14,5,12,3,10,1,8,15,6,13,4,11,2,9
+};
+
+static const unsigned char Rorder[64] = {
+   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 const ulong32 Korder[64] = {
+0xd76aa478UL, 0xe8c7b756UL, 0x242070dbUL, 0xc1bdceeeUL, 0xf57c0fafUL, 0x4787c62aUL, 0xa8304613UL, 0xfd469501UL,
+0x698098d8UL, 0x8b44f7afUL, 0xffff5bb1UL, 0x895cd7beUL, 0x6b901122UL, 0xfd987193UL, 0xa679438eUL, 0x49b40821UL,
+0xf61e2562UL, 0xc040b340UL, 0x265e5a51UL, 0xe9b6c7aaUL, 0xd62f105dUL, 0x02441453UL, 0xd8a1e681UL, 0xe7d3fbc8UL,
+0x21e1cde6UL, 0xc33707d6UL, 0xf4d50d87UL, 0x455a14edUL, 0xa9e3e905UL, 0xfcefa3f8UL, 0x676f02d9UL, 0x8d2a4c8aUL,
+0xfffa3942UL, 0x8771f681UL, 0x6d9d6122UL, 0xfde5380cUL, 0xa4beea44UL, 0x4bdecfa9UL, 0xf6bb4b60UL, 0xbebfbc70UL,
+0x289b7ec6UL, 0xeaa127faUL, 0xd4ef3085UL, 0x04881d05UL, 0xd9d4d039UL, 0xe6db99e5UL, 0x1fa27cf8UL, 0xc4ac5665UL,
+0xf4292244UL, 0x432aff97UL, 0xab9423a7UL, 0xfc93a039UL, 0x655b59c3UL, 0x8f0ccc92UL, 0xffeff47dUL, 0x85845dd1UL,
+0x6fa87e4fUL, 0xfe2ce6e0UL, 0xa3014314UL, 0x4e0811a1UL, 0xf7537e82UL, 0xbd3af235UL, 0x2ad7d2bbUL, 0xeb86d391UL
+};
+
+#else
+
+#define FF(a,b,c,d,M,s,t) \
+    a = (a + F(b,c,d) + M + t); a = ROLc(a, s) + b;
+
+#define GG(a,b,c,d,M,s,t) \
+    a = (a + G(b,c,d) + M + t); a = ROLc(a, s) + b;
+
+#define HH(a,b,c,d,M,s,t) \
+    a = (a + H(b,c,d) + M + t); a = ROLc(a, s) + b;
+
+#define II(a,b,c,d,M,s,t) \
+    a = (a + I(b,c,d) + M + t); a = ROLc(a, s) + b;
+
+
+#endif
+
+#ifdef LTC_CLEAN_STACK
+static int _md5_compress(hash_state *md, unsigned char *buf)
+#else
+static int  md5_compress(hash_state *md, unsigned char *buf)
+#endif
+{
+    ulong32 i, W[16], a, b, c, d;
+#ifdef LTC_SMALL_CODE
+    ulong32 t;
+#endif
+
+    /* copy the state into 512-bits into W[0..15] */
+    for (i = 0; i < 16; i++) {
+        LOAD32L(W[i], buf + (4*i));
+    }
+
+    /* copy state */
+    a = md->md5.state[0];
+    b = md->md5.state[1];
+    c = md->md5.state[2];
+    d = md->md5.state[3];
+
+#ifdef LTC_SMALL_CODE
+    for (i = 0; i < 16; ++i) {
+        FF(a,b,c,d,W[Worder[i]],Rorder[i],Korder[i]);
+        t = d; d = c; c = b; b = a; a = t;
+    }
+
+    for (; i < 32; ++i) {
+        GG(a,b,c,d,W[Worder[i]],Rorder[i],Korder[i]);
+        t = d; d = c; c = b; b = a; a = t;
+    }
+
+    for (; i < 48; ++i) {
+        HH(a,b,c,d,W[Worder[i]],Rorder[i],Korder[i]);
+        t = d; d = c; c = b; b = a; a = t;
+    }
+
+    for (; i < 64; ++i) {
+        II(a,b,c,d,W[Worder[i]],Rorder[i],Korder[i]);
+        t = d; d = c; c = b; b = a; a = t;
+    }
+
+#else
+    FF(a,b,c,d,W[0],7,0xd76aa478UL)
+    FF(d,a,b,c,W[1],12,0xe8c7b756UL)
+    FF(c,d,a,b,W[2],17,0x242070dbUL)
+    FF(b,c,d,a,W[3],22,0xc1bdceeeUL)
+    FF(a,b,c,d,W[4],7,0xf57c0fafUL)
+    FF(d,a,b,c,W[5],12,0x4787c62aUL)
+    FF(c,d,a,b,W[6],17,0xa8304613UL)
+    FF(b,c,d,a,W[7],22,0xfd469501UL)
+    FF(a,b,c,d,W[8],7,0x698098d8UL)
+    FF(d,a,b,c,W[9],12,0x8b44f7afUL)
+    FF(c,d,a,b,W[10],17,0xffff5bb1UL)
+    FF(b,c,d,a,W[11],22,0x895cd7beUL)
+    FF(a,b,c,d,W[12],7,0x6b901122UL)
+    FF(d,a,b,c,W[13],12,0xfd987193UL)
+    FF(c,d,a,b,W[14],17,0xa679438eUL)
+    FF(b,c,d,a,W[15],22,0x49b40821UL)
+    GG(a,b,c,d,W[1],5,0xf61e2562UL)
+    GG(d,a,b,c,W[6],9,0xc040b340UL)
+    GG(c,d,a,b,W[11],14,0x265e5a51UL)
+    GG(b,c,d,a,W[0],20,0xe9b6c7aaUL)
+    GG(a,b,c,d,W[5],5,0xd62f105dUL)
+    GG(d,a,b,c,W[10],9,0x02441453UL)
+    GG(c,d,a,b,W[15],14,0xd8a1e681UL)
+    GG(b,c,d,a,W[4],20,0xe7d3fbc8UL)
+    GG(a,b,c,d,W[9],5,0x21e1cde6UL)
+    GG(d,a,b,c,W[14],9,0xc33707d6UL)
+    GG(c,d,a,b,W[3],14,0xf4d50d87UL)
+    GG(b,c,d,a,W[8],20,0x455a14edUL)
+    GG(a,b,c,d,W[13],5,0xa9e3e905UL)
+    GG(d,a,b,c,W[2],9,0xfcefa3f8UL)
+    GG(c,d,a,b,W[7],14,0x676f02d9UL)
+    GG(b,c,d,a,W[12],20,0x8d2a4c8aUL)
+    HH(a,b,c,d,W[5],4,0xfffa3942UL)
+    HH(d,a,b,c,W[8],11,0x8771f681UL)
+    HH(c,d,a,b,W[11],16,0x6d9d6122UL)
+    HH(b,c,d,a,W[14],23,0xfde5380cUL)
+    HH(a,b,c,d,W[1],4,0xa4beea44UL)
+    HH(d,a,b,c,W[4],11,0x4bdecfa9UL)
+    HH(c,d,a,b,W[7],16,0xf6bb4b60UL)
+    HH(b,c,d,a,W[10],23,0xbebfbc70UL)
+    HH(a,b,c,d,W[13],4,0x289b7ec6UL)
+    HH(d,a,b,c,W[0],11,0xeaa127faUL)
+    HH(c,d,a,b,W[3],16,0xd4ef3085UL)
+    HH(b,c,d,a,W[6],23,0x04881d05UL)
+    HH(a,b,c,d,W[9],4,0xd9d4d039UL)
+    HH(d,a,b,c,W[12],11,0xe6db99e5UL)
+    HH(c,d,a,b,W[15],16,0x1fa27cf8UL)
+    HH(b,c,d,a,W[2],23,0xc4ac5665UL)
+    II(a,b,c,d,W[0],6,0xf4292244UL)
+    II(d,a,b,c,W[7],10,0x432aff97UL)
+    II(c,d,a,b,W[14],15,0xab9423a7UL)
+    II(b,c,d,a,W[5],21,0xfc93a039UL)
+    II(a,b,c,d,W[12],6,0x655b59c3UL)
+    II(d,a,b,c,W[3],10,0x8f0ccc92UL)
+    II(c,d,a,b,W[10],15,0xffeff47dUL)
+    II(b,c,d,a,W[1],21,0x85845dd1UL)
+    II(a,b,c,d,W[8],6,0x6fa87e4fUL)
+    II(d,a,b,c,W[15],10,0xfe2ce6e0UL)
+    II(c,d,a,b,W[6],15,0xa3014314UL)
+    II(b,c,d,a,W[13],21,0x4e0811a1UL)
+    II(a,b,c,d,W[4],6,0xf7537e82UL)
+    II(d,a,b,c,W[11],10,0xbd3af235UL)
+    II(c,d,a,b,W[2],15,0x2ad7d2bbUL)
+    II(b,c,d,a,W[9],21,0xeb86d391UL)
+#endif
+
+    md->md5.state[0] = md->md5.state[0] + a;
+    md->md5.state[1] = md->md5.state[1] + b;
+    md->md5.state[2] = md->md5.state[2] + c;
+    md->md5.state[3] = md->md5.state[3] + d;
+
+    return CRYPT_OK;
+}
+
+#ifdef LTC_CLEAN_STACK
+static int md5_compress(hash_state *md, unsigned char *buf)
+{
+   int err;
+   err = _md5_compress(md, buf);
+   burn_stack(sizeof(ulong32) * 21);
+   return err;
+}
+#endif
+
+/**
+   Initialize the hash state
+   @param md   The hash state you wish to initialize
+   @return CRYPT_OK if successful
+*/
+int md5_init(hash_state * md)
+{
+   LTC_ARGCHK(md != NULL);
+   md->md5.state[0] = 0x67452301UL;
+   md->md5.state[1] = 0xefcdab89UL;
+   md->md5.state[2] = 0x98badcfeUL;
+   md->md5.state[3] = 0x10325476UL;
+   md->md5.curlen = 0;
+   md->md5.length = 0;
+   return CRYPT_OK;
+}
+
+/**
+   Process a block of memory though the hash
+   @param md     The hash state
+   @param in     The data to hash
+   @param inlen  The length of the data (octets)
+   @return CRYPT_OK if successful
+*/
+HASH_PROCESS(md5_process, md5_compress, md5, 64)
+
+/**
+   Terminate the hash to get the digest
+   @param md  The hash state
+   @param out [out] The destination of the hash (16 bytes)
+   @return CRYPT_OK if successful
+*/
+int md5_done(hash_state * md, unsigned char *out)
+{
+    int i;
+
+    LTC_ARGCHK(md  != NULL);
+    LTC_ARGCHK(out != NULL);
+
+    if (md->md5.curlen >= sizeof(md->md5.buf)) {
+       return CRYPT_INVALID_ARG;
+    }
+
+
+    /* increase the length of the message */
+    md->md5.length += md->md5.curlen * 8;
+
+    /* append the '1' bit */
+    md->md5.buf[md->md5.curlen++] = (unsigned char)0x80;
+
+    /* if the length is currently above 56 bytes we append zeros
+     * then compress.  Then we can fall back to padding zeros and length
+     * encoding like normal.
+     */
+    if (md->md5.curlen > 56) {
+        while (md->md5.curlen < 64) {
+            md->md5.buf[md->md5.curlen++] = (unsigned char)0;
+        }
+        md5_compress(md, md->md5.buf);
+        md->md5.curlen = 0;
+    }
+
+    /* pad upto 56 bytes of zeroes */
+    while (md->md5.curlen < 56) {
+        md->md5.buf[md->md5.curlen++] = (unsigned char)0;
+    }
+
+    /* store length */
+    STORE64L(md->md5.length, md->md5.buf+56);
+    md5_compress(md, md->md5.buf);
+
+    /* copy output */
+    for (i = 0; i < 4; i++) {
+        STORE32L(md->md5.state[i], out+(4*i));
+    }
+#ifdef LTC_CLEAN_STACK
+    zeromem(md, sizeof(hash_state));
+#endif
+    return CRYPT_OK;
+}
+
+/**
+  Self-test the hash
+  @return CRYPT_OK if successful, CRYPT_NOP if self-tests have been disabled
+*/
+int  md5_test(void)
+{
+ #ifndef LTC_TEST
+    return CRYPT_NOP;
+ #else
+  static const struct {
+      const char *msg;
+      unsigned char hash[16];
+  } tests[] = {
+    { "",
+      { 0xd4, 0x1d, 0x8c, 0xd9, 0x8f, 0x00, 0xb2, 0x04,
+        0xe9, 0x80, 0x09, 0x98, 0xec, 0xf8, 0x42, 0x7e } },
+    { "a",
+      {0x0c, 0xc1, 0x75, 0xb9, 0xc0, 0xf1, 0xb6, 0xa8,
+       0x31, 0xc3, 0x99, 0xe2, 0x69, 0x77, 0x26, 0x61 } },
+    { "abc",
+      { 0x90, 0x01, 0x50, 0x98, 0x3c, 0xd2, 0x4f, 0xb0,
+        0xd6, 0x96, 0x3f, 0x7d, 0x28, 0xe1, 0x7f, 0x72 } },
+    { "message digest",
+      { 0xf9, 0x6b, 0x69, 0x7d, 0x7c, 0xb7, 0x93, 0x8d,
+        0x52, 0x5a, 0x2f, 0x31, 0xaa, 0xf1, 0x61, 0xd0 } },
+    { "abcdefghijklmnopqrstuvwxyz",
+      { 0xc3, 0xfc, 0xd3, 0xd7, 0x61, 0x92, 0xe4, 0x00,
+        0x7d, 0xfb, 0x49, 0x6c, 0xca, 0x67, 0xe1, 0x3b } },
+    { "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
+      { 0xd1, 0x74, 0xab, 0x98, 0xd2, 0x77, 0xd9, 0xf5,
+        0xa5, 0x61, 0x1c, 0x2c, 0x9f, 0x41, 0x9d, 0x9f } },
+    { "12345678901234567890123456789012345678901234567890123456789012345678901234567890",
+      { 0x57, 0xed, 0xf4, 0xa2, 0x2b, 0xe3, 0xc9, 0x55,
+        0xac, 0x49, 0xda, 0x2e, 0x21, 0x07, 0xb6, 0x7a } },
+    { NULL, { 0 } }
+  };
+
+  int i;
+  unsigned char tmp[16];
+  hash_state md;
+
+  for (i = 0; tests[i].msg != NULL; i++) {
+      md5_init(&md);
+      md5_process(&md, (unsigned char *)tests[i].msg, (unsigned long)strlen(tests[i].msg));
+      md5_done(&md, tmp);
+      if (compare_testvector(tmp, sizeof(tmp), tests[i].hash, sizeof(tests[i].hash), "MD5", i)) {
+         return CRYPT_FAIL_TESTVECTOR;
+      }
+  }
+  return CRYPT_OK;
+ #endif
+}
+
+#endif
+
+
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/hashes/rmd128.c b/libtomcrypt/src/hashes/rmd128.c
new file mode 100644 (file)
index 0000000..df1af1a
--- /dev/null
@@ -0,0 +1,406 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+   @param rmd128.c
+   RMD128 Hash function
+*/
+
+/* Implementation of LTC_RIPEMD-128 based on the source by Antoon Bosselaers, ESAT-COSIC
+ *
+ * This source has been radically overhauled to be portable and work within
+ * the LibTomCrypt API by Tom St Denis
+ */
+
+#ifdef LTC_RIPEMD128
+
+const struct ltc_hash_descriptor rmd128_desc =
+{
+    "rmd128",
+    8,
+    16,
+    64,
+
+    /* OID */
+   { 1, 0, 10118, 3, 0, 50 },
+   6,
+
+    &rmd128_init,
+    &rmd128_process,
+    &rmd128_done,
+    &rmd128_test,
+    NULL
+};
+
+/* the four basic functions F(), G() and H() */
+#define F(x, y, z)        ((x) ^ (y) ^ (z))
+#define G(x, y, z)        (((x) & (y)) | (~(x) & (z)))
+#define H(x, y, z)        (((x) | ~(y)) ^ (z))
+#define I(x, y, z)        (((x) & (z)) | ((y) & ~(z)))
+
+/* the eight basic operations FF() through III() */
+#define FF(a, b, c, d, x, s)        \
+      (a) += F((b), (c), (d)) + (x);\
+      (a) = ROLc((a), (s));
+
+#define GG(a, b, c, d, x, s)        \
+      (a) += G((b), (c), (d)) + (x) + 0x5a827999UL;\
+      (a) = ROLc((a), (s));
+
+#define HH(a, b, c, d, x, s)        \
+      (a) += H((b), (c), (d)) + (x) + 0x6ed9eba1UL;\
+      (a) = ROLc((a), (s));
+
+#define II(a, b, c, d, x, s)        \
+      (a) += I((b), (c), (d)) + (x) + 0x8f1bbcdcUL;\
+      (a) = ROLc((a), (s));
+
+#define FFF(a, b, c, d, x, s)        \
+      (a) += F((b), (c), (d)) + (x);\
+      (a) = ROLc((a), (s));
+
+#define GGG(a, b, c, d, x, s)        \
+      (a) += G((b), (c), (d)) + (x) + 0x6d703ef3UL;\
+      (a) = ROLc((a), (s));
+
+#define HHH(a, b, c, d, x, s)        \
+      (a) += H((b), (c), (d)) + (x) + 0x5c4dd124UL;\
+      (a) = ROLc((a), (s));
+
+#define III(a, b, c, d, x, s)        \
+      (a) += I((b), (c), (d)) + (x) + 0x50a28be6UL;\
+      (a) = ROLc((a), (s));
+
+#ifdef LTC_CLEAN_STACK
+static int _rmd128_compress(hash_state *md, unsigned char *buf)
+#else
+static int  rmd128_compress(hash_state *md, unsigned char *buf)
+#endif
+{
+   ulong32 aa,bb,cc,dd,aaa,bbb,ccc,ddd,X[16];
+   int i;
+
+   /* load words X */
+   for (i = 0; i < 16; i++){
+      LOAD32L(X[i], buf + (4 * i));
+   }
+
+   /* load state */
+   aa = aaa = md->rmd128.state[0];
+   bb = bbb = md->rmd128.state[1];
+   cc = ccc = md->rmd128.state[2];
+   dd = ddd = md->rmd128.state[3];
+
+   /* round 1 */
+   FF(aa, bb, cc, dd, X[ 0], 11);
+   FF(dd, aa, bb, cc, X[ 1], 14);
+   FF(cc, dd, aa, bb, X[ 2], 15);
+   FF(bb, cc, dd, aa, X[ 3], 12);
+   FF(aa, bb, cc, dd, X[ 4],  5);
+   FF(dd, aa, bb, cc, X[ 5],  8);
+   FF(cc, dd, aa, bb, X[ 6],  7);
+   FF(bb, cc, dd, aa, X[ 7],  9);
+   FF(aa, bb, cc, dd, X[ 8], 11);
+   FF(dd, aa, bb, cc, X[ 9], 13);
+   FF(cc, dd, aa, bb, X[10], 14);
+   FF(bb, cc, dd, aa, X[11], 15);
+   FF(aa, bb, cc, dd, X[12],  6);
+   FF(dd, aa, bb, cc, X[13],  7);
+   FF(cc, dd, aa, bb, X[14],  9);
+   FF(bb, cc, dd, aa, X[15],  8);
+
+   /* round 2 */
+   GG(aa, bb, cc, dd, X[ 7],  7);
+   GG(dd, aa, bb, cc, X[ 4],  6);
+   GG(cc, dd, aa, bb, X[13],  8);
+   GG(bb, cc, dd, aa, X[ 1], 13);
+   GG(aa, bb, cc, dd, X[10], 11);
+   GG(dd, aa, bb, cc, X[ 6],  9);
+   GG(cc, dd, aa, bb, X[15],  7);
+   GG(bb, cc, dd, aa, X[ 3], 15);
+   GG(aa, bb, cc, dd, X[12],  7);
+   GG(dd, aa, bb, cc, X[ 0], 12);
+   GG(cc, dd, aa, bb, X[ 9], 15);
+   GG(bb, cc, dd, aa, X[ 5],  9);
+   GG(aa, bb, cc, dd, X[ 2], 11);
+   GG(dd, aa, bb, cc, X[14],  7);
+   GG(cc, dd, aa, bb, X[11], 13);
+   GG(bb, cc, dd, aa, X[ 8], 12);
+
+   /* round 3 */
+   HH(aa, bb, cc, dd, X[ 3], 11);
+   HH(dd, aa, bb, cc, X[10], 13);
+   HH(cc, dd, aa, bb, X[14],  6);
+   HH(bb, cc, dd, aa, X[ 4],  7);
+   HH(aa, bb, cc, dd, X[ 9], 14);
+   HH(dd, aa, bb, cc, X[15],  9);
+   HH(cc, dd, aa, bb, X[ 8], 13);
+   HH(bb, cc, dd, aa, X[ 1], 15);
+   HH(aa, bb, cc, dd, X[ 2], 14);
+   HH(dd, aa, bb, cc, X[ 7],  8);
+   HH(cc, dd, aa, bb, X[ 0], 13);
+   HH(bb, cc, dd, aa, X[ 6],  6);
+   HH(aa, bb, cc, dd, X[13],  5);
+   HH(dd, aa, bb, cc, X[11], 12);
+   HH(cc, dd, aa, bb, X[ 5],  7);
+   HH(bb, cc, dd, aa, X[12],  5);
+
+   /* round 4 */
+   II(aa, bb, cc, dd, X[ 1], 11);
+   II(dd, aa, bb, cc, X[ 9], 12);
+   II(cc, dd, aa, bb, X[11], 14);
+   II(bb, cc, dd, aa, X[10], 15);
+   II(aa, bb, cc, dd, X[ 0], 14);
+   II(dd, aa, bb, cc, X[ 8], 15);
+   II(cc, dd, aa, bb, X[12],  9);
+   II(bb, cc, dd, aa, X[ 4],  8);
+   II(aa, bb, cc, dd, X[13],  9);
+   II(dd, aa, bb, cc, X[ 3], 14);
+   II(cc, dd, aa, bb, X[ 7],  5);
+   II(bb, cc, dd, aa, X[15],  6);
+   II(aa, bb, cc, dd, X[14],  8);
+   II(dd, aa, bb, cc, X[ 5],  6);
+   II(cc, dd, aa, bb, X[ 6],  5);
+   II(bb, cc, dd, aa, X[ 2], 12);
+
+   /* parallel round 1 */
+   III(aaa, bbb, ccc, ddd, X[ 5],  8);
+   III(ddd, aaa, bbb, ccc, X[14],  9);
+   III(ccc, ddd, aaa, bbb, X[ 7],  9);
+   III(bbb, ccc, ddd, aaa, X[ 0], 11);
+   III(aaa, bbb, ccc, ddd, X[ 9], 13);
+   III(ddd, aaa, bbb, ccc, X[ 2], 15);
+   III(ccc, ddd, aaa, bbb, X[11], 15);
+   III(bbb, ccc, ddd, aaa, X[ 4],  5);
+   III(aaa, bbb, ccc, ddd, X[13],  7);
+   III(ddd, aaa, bbb, ccc, X[ 6],  7);
+   III(ccc, ddd, aaa, bbb, X[15],  8);
+   III(bbb, ccc, ddd, aaa, X[ 8], 11);
+   III(aaa, bbb, ccc, ddd, X[ 1], 14);
+   III(ddd, aaa, bbb, ccc, X[10], 14);
+   III(ccc, ddd, aaa, bbb, X[ 3], 12);
+   III(bbb, ccc, ddd, aaa, X[12],  6);
+
+   /* parallel round 2 */
+   HHH(aaa, bbb, ccc, ddd, X[ 6],  9);
+   HHH(ddd, aaa, bbb, ccc, X[11], 13);
+   HHH(ccc, ddd, aaa, bbb, X[ 3], 15);
+   HHH(bbb, ccc, ddd, aaa, X[ 7],  7);
+   HHH(aaa, bbb, ccc, ddd, X[ 0], 12);
+   HHH(ddd, aaa, bbb, ccc, X[13],  8);
+   HHH(ccc, ddd, aaa, bbb, X[ 5],  9);
+   HHH(bbb, ccc, ddd, aaa, X[10], 11);
+   HHH(aaa, bbb, ccc, ddd, X[14],  7);
+   HHH(ddd, aaa, bbb, ccc, X[15],  7);
+   HHH(ccc, ddd, aaa, bbb, X[ 8], 12);
+   HHH(bbb, ccc, ddd, aaa, X[12],  7);
+   HHH(aaa, bbb, ccc, ddd, X[ 4],  6);
+   HHH(ddd, aaa, bbb, ccc, X[ 9], 15);
+   HHH(ccc, ddd, aaa, bbb, X[ 1], 13);
+   HHH(bbb, ccc, ddd, aaa, X[ 2], 11);
+
+   /* parallel round 3 */
+   GGG(aaa, bbb, ccc, ddd, X[15],  9);
+   GGG(ddd, aaa, bbb, ccc, X[ 5],  7);
+   GGG(ccc, ddd, aaa, bbb, X[ 1], 15);
+   GGG(bbb, ccc, ddd, aaa, X[ 3], 11);
+   GGG(aaa, bbb, ccc, ddd, X[ 7],  8);
+   GGG(ddd, aaa, bbb, ccc, X[14],  6);
+   GGG(ccc, ddd, aaa, bbb, X[ 6],  6);
+   GGG(bbb, ccc, ddd, aaa, X[ 9], 14);
+   GGG(aaa, bbb, ccc, ddd, X[11], 12);
+   GGG(ddd, aaa, bbb, ccc, X[ 8], 13);
+   GGG(ccc, ddd, aaa, bbb, X[12],  5);
+   GGG(bbb, ccc, ddd, aaa, X[ 2], 14);
+   GGG(aaa, bbb, ccc, ddd, X[10], 13);
+   GGG(ddd, aaa, bbb, ccc, X[ 0], 13);
+   GGG(ccc, ddd, aaa, bbb, X[ 4],  7);
+   GGG(bbb, ccc, ddd, aaa, X[13],  5);
+
+   /* parallel round 4 */
+   FFF(aaa, bbb, ccc, ddd, X[ 8], 15);
+   FFF(ddd, aaa, bbb, ccc, X[ 6],  5);
+   FFF(ccc, ddd, aaa, bbb, X[ 4],  8);
+   FFF(bbb, ccc, ddd, aaa, X[ 1], 11);
+   FFF(aaa, bbb, ccc, ddd, X[ 3], 14);
+   FFF(ddd, aaa, bbb, ccc, X[11], 14);
+   FFF(ccc, ddd, aaa, bbb, X[15],  6);
+   FFF(bbb, ccc, ddd, aaa, X[ 0], 14);
+   FFF(aaa, bbb, ccc, ddd, X[ 5],  6);
+   FFF(ddd, aaa, bbb, ccc, X[12],  9);
+   FFF(ccc, ddd, aaa, bbb, X[ 2], 12);
+   FFF(bbb, ccc, ddd, aaa, X[13],  9);
+   FFF(aaa, bbb, ccc, ddd, X[ 9], 12);
+   FFF(ddd, aaa, bbb, ccc, X[ 7],  5);
+   FFF(ccc, ddd, aaa, bbb, X[10], 15);
+   FFF(bbb, ccc, ddd, aaa, X[14],  8);
+
+   /* combine results */
+   ddd += cc + md->rmd128.state[1];               /* final result for MDbuf[0] */
+   md->rmd128.state[1] = md->rmd128.state[2] + dd + aaa;
+   md->rmd128.state[2] = md->rmd128.state[3] + aa + bbb;
+   md->rmd128.state[3] = md->rmd128.state[0] + bb + ccc;
+   md->rmd128.state[0] = ddd;
+
+   return CRYPT_OK;
+}
+
+#ifdef LTC_CLEAN_STACK
+static int rmd128_compress(hash_state *md, unsigned char *buf)
+{
+   int err;
+   err = _rmd128_compress(md, buf);
+   burn_stack(sizeof(ulong32) * 24 + sizeof(int));
+   return err;
+}
+#endif
+
+/**
+   Initialize the hash state
+   @param md   The hash state you wish to initialize
+   @return CRYPT_OK if successful
+*/
+int rmd128_init(hash_state * md)
+{
+   LTC_ARGCHK(md != NULL);
+   md->rmd128.state[0] = 0x67452301UL;
+   md->rmd128.state[1] = 0xefcdab89UL;
+   md->rmd128.state[2] = 0x98badcfeUL;
+   md->rmd128.state[3] = 0x10325476UL;
+   md->rmd128.curlen   = 0;
+   md->rmd128.length   = 0;
+   return CRYPT_OK;
+}
+
+/**
+   Process a block of memory though the hash
+   @param md     The hash state
+   @param in     The data to hash
+   @param inlen  The length of the data (octets)
+   @return CRYPT_OK if successful
+*/
+HASH_PROCESS(rmd128_process, rmd128_compress, rmd128, 64)
+
+/**
+   Terminate the hash to get the digest
+   @param md  The hash state
+   @param out [out] The destination of the hash (16 bytes)
+   @return CRYPT_OK if successful
+*/
+int rmd128_done(hash_state * md, unsigned char *out)
+{
+    int i;
+
+    LTC_ARGCHK(md  != NULL);
+    LTC_ARGCHK(out != NULL);
+
+    if (md->rmd128.curlen >= sizeof(md->rmd128.buf)) {
+       return CRYPT_INVALID_ARG;
+    }
+
+
+    /* increase the length of the message */
+    md->rmd128.length += md->rmd128.curlen * 8;
+
+    /* append the '1' bit */
+    md->rmd128.buf[md->rmd128.curlen++] = (unsigned char)0x80;
+
+    /* if the length is currently above 56 bytes we append zeros
+     * then compress.  Then we can fall back to padding zeros and length
+     * encoding like normal.
+     */
+    if (md->rmd128.curlen > 56) {
+        while (md->rmd128.curlen < 64) {
+            md->rmd128.buf[md->rmd128.curlen++] = (unsigned char)0;
+        }
+        rmd128_compress(md, md->rmd128.buf);
+        md->rmd128.curlen = 0;
+    }
+
+    /* pad upto 56 bytes of zeroes */
+    while (md->rmd128.curlen < 56) {
+        md->rmd128.buf[md->rmd128.curlen++] = (unsigned char)0;
+    }
+
+    /* store length */
+    STORE64L(md->rmd128.length, md->rmd128.buf+56);
+    rmd128_compress(md, md->rmd128.buf);
+
+    /* copy output */
+    for (i = 0; i < 4; i++) {
+        STORE32L(md->rmd128.state[i], out+(4*i));
+    }
+#ifdef LTC_CLEAN_STACK
+    zeromem(md, sizeof(hash_state));
+#endif
+   return CRYPT_OK;
+}
+
+/**
+  Self-test the hash
+  @return CRYPT_OK if successful, CRYPT_NOP if self-tests have been disabled
+*/
+int rmd128_test(void)
+{
+#ifndef LTC_TEST
+   return CRYPT_NOP;
+#else
+   static const struct {
+        const char *msg;
+        unsigned char hash[16];
+   } tests[] = {
+   { "",
+     { 0xcd, 0xf2, 0x62, 0x13, 0xa1, 0x50, 0xdc, 0x3e,
+       0xcb, 0x61, 0x0f, 0x18, 0xf6, 0xb3, 0x8b, 0x46 }
+   },
+   { "a",
+     { 0x86, 0xbe, 0x7a, 0xfa, 0x33, 0x9d, 0x0f, 0xc7,
+       0xcf, 0xc7, 0x85, 0xe7, 0x2f, 0x57, 0x8d, 0x33 }
+   },
+   { "abc",
+     { 0xc1, 0x4a, 0x12, 0x19, 0x9c, 0x66, 0xe4, 0xba,
+       0x84, 0x63, 0x6b, 0x0f, 0x69, 0x14, 0x4c, 0x77 }
+   },
+   { "message digest",
+     { 0x9e, 0x32, 0x7b, 0x3d, 0x6e, 0x52, 0x30, 0x62,
+       0xaf, 0xc1, 0x13, 0x2d, 0x7d, 0xf9, 0xd1, 0xb8 }
+   },
+   { "abcdefghijklmnopqrstuvwxyz",
+     { 0xfd, 0x2a, 0xa6, 0x07, 0xf7, 0x1d, 0xc8, 0xf5,
+       0x10, 0x71, 0x49, 0x22, 0xb3, 0x71, 0x83, 0x4e }
+   },
+   { "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
+     { 0xd1, 0xe9, 0x59, 0xeb, 0x17, 0x9c, 0x91, 0x1f,
+       0xae, 0xa4, 0x62, 0x4c, 0x60, 0xc5, 0xc7, 0x02 }
+   }
+   };
+
+   int i;
+   unsigned char tmp[16];
+   hash_state md;
+
+   for (i = 0; i < (int)(sizeof(tests)/sizeof(tests[0])); i++) {
+       rmd128_init(&md);
+       rmd128_process(&md, (unsigned char *)tests[i].msg, strlen(tests[i].msg));
+       rmd128_done(&md, tmp);
+       if (compare_testvector(tmp, sizeof(tmp), tests[i].hash, sizeof(tests[i].hash), "RIPEMD128", i)) {
+          return CRYPT_FAIL_TESTVECTOR;
+       }
+   }
+   return CRYPT_OK;
+#endif
+}
+
+#endif
+
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/hashes/rmd160.c b/libtomcrypt/src/hashes/rmd160.c
new file mode 100644 (file)
index 0000000..8add41e
--- /dev/null
@@ -0,0 +1,465 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+   @file rmd160.c
+   RMD160 hash function
+*/
+
+/* Implementation of LTC_RIPEMD-160 based on the source by Antoon Bosselaers, ESAT-COSIC
+ *
+ * This source has been radically overhauled to be portable and work within
+ * the LibTomCrypt API by Tom St Denis
+ */
+
+#ifdef LTC_RIPEMD160
+
+const struct ltc_hash_descriptor rmd160_desc =
+{
+    "rmd160",
+    9,
+    20,
+    64,
+
+    /* OID */
+   { 1, 3, 36, 3, 2, 1,  },
+   6,
+
+    &rmd160_init,
+    &rmd160_process,
+    &rmd160_done,
+    &rmd160_test,
+    NULL
+};
+
+/* the five basic functions F(), G() and H() */
+#define F(x, y, z)        ((x) ^ (y) ^ (z))
+#define G(x, y, z)        (((x) & (y)) | (~(x) & (z)))
+#define H(x, y, z)        (((x) | ~(y)) ^ (z))
+#define I(x, y, z)        (((x) & (z)) | ((y) & ~(z)))
+#define J(x, y, z)        ((x) ^ ((y) | ~(z)))
+
+/* the ten basic operations FF() through III() */
+#define FF(a, b, c, d, e, x, s)        \
+      (a) += F((b), (c), (d)) + (x);\
+      (a) = ROLc((a), (s)) + (e);\
+      (c) = ROLc((c), 10);
+
+#define GG(a, b, c, d, e, x, s)        \
+      (a) += G((b), (c), (d)) + (x) + 0x5a827999UL;\
+      (a) = ROLc((a), (s)) + (e);\
+      (c) = ROLc((c), 10);
+
+#define HH(a, b, c, d, e, x, s)        \
+      (a) += H((b), (c), (d)) + (x) + 0x6ed9eba1UL;\
+      (a) = ROLc((a), (s)) + (e);\
+      (c) = ROLc((c), 10);
+
+#define II(a, b, c, d, e, x, s)        \
+      (a) += I((b), (c), (d)) + (x) + 0x8f1bbcdcUL;\
+      (a) = ROLc((a), (s)) + (e);\
+      (c) = ROLc((c), 10);
+
+#define JJ(a, b, c, d, e, x, s)        \
+      (a) += J((b), (c), (d)) + (x) + 0xa953fd4eUL;\
+      (a) = ROLc((a), (s)) + (e);\
+      (c) = ROLc((c), 10);
+
+#define FFF(a, b, c, d, e, x, s)        \
+      (a) += F((b), (c), (d)) + (x);\
+      (a) = ROLc((a), (s)) + (e);\
+      (c) = ROLc((c), 10);
+
+#define GGG(a, b, c, d, e, x, s)        \
+      (a) += G((b), (c), (d)) + (x) + 0x7a6d76e9UL;\
+      (a) = ROLc((a), (s)) + (e);\
+      (c) = ROLc((c), 10);
+
+#define HHH(a, b, c, d, e, x, s)        \
+      (a) += H((b), (c), (d)) + (x) + 0x6d703ef3UL;\
+      (a) = ROLc((a), (s)) + (e);\
+      (c) = ROLc((c), 10);
+
+#define III(a, b, c, d, e, x, s)        \
+      (a) += I((b), (c), (d)) + (x) + 0x5c4dd124UL;\
+      (a) = ROLc((a), (s)) + (e);\
+      (c) = ROLc((c), 10);
+
+#define JJJ(a, b, c, d, e, x, s)        \
+      (a) += J((b), (c), (d)) + (x) + 0x50a28be6UL;\
+      (a) = ROLc((a), (s)) + (e);\
+      (c) = ROLc((c), 10);
+
+
+#ifdef LTC_CLEAN_STACK
+static int _rmd160_compress(hash_state *md, unsigned char *buf)
+#else
+static int  rmd160_compress(hash_state *md, unsigned char *buf)
+#endif
+{
+   ulong32 aa,bb,cc,dd,ee,aaa,bbb,ccc,ddd,eee,X[16];
+   int i;
+
+   /* load words X */
+   for (i = 0; i < 16; i++){
+      LOAD32L(X[i], buf + (4 * i));
+   }
+
+   /* load state */
+   aa = aaa = md->rmd160.state[0];
+   bb = bbb = md->rmd160.state[1];
+   cc = ccc = md->rmd160.state[2];
+   dd = ddd = md->rmd160.state[3];
+   ee = eee = md->rmd160.state[4];
+
+   /* round 1 */
+   FF(aa, bb, cc, dd, ee, X[ 0], 11);
+   FF(ee, aa, bb, cc, dd, X[ 1], 14);
+   FF(dd, ee, aa, bb, cc, X[ 2], 15);
+   FF(cc, dd, ee, aa, bb, X[ 3], 12);
+   FF(bb, cc, dd, ee, aa, X[ 4],  5);
+   FF(aa, bb, cc, dd, ee, X[ 5],  8);
+   FF(ee, aa, bb, cc, dd, X[ 6],  7);
+   FF(dd, ee, aa, bb, cc, X[ 7],  9);
+   FF(cc, dd, ee, aa, bb, X[ 8], 11);
+   FF(bb, cc, dd, ee, aa, X[ 9], 13);
+   FF(aa, bb, cc, dd, ee, X[10], 14);
+   FF(ee, aa, bb, cc, dd, X[11], 15);
+   FF(dd, ee, aa, bb, cc, X[12],  6);
+   FF(cc, dd, ee, aa, bb, X[13],  7);
+   FF(bb, cc, dd, ee, aa, X[14],  9);
+   FF(aa, bb, cc, dd, ee, X[15],  8);
+
+   /* round 2 */
+   GG(ee, aa, bb, cc, dd, X[ 7],  7);
+   GG(dd, ee, aa, bb, cc, X[ 4],  6);
+   GG(cc, dd, ee, aa, bb, X[13],  8);
+   GG(bb, cc, dd, ee, aa, X[ 1], 13);
+   GG(aa, bb, cc, dd, ee, X[10], 11);
+   GG(ee, aa, bb, cc, dd, X[ 6],  9);
+   GG(dd, ee, aa, bb, cc, X[15],  7);
+   GG(cc, dd, ee, aa, bb, X[ 3], 15);
+   GG(bb, cc, dd, ee, aa, X[12],  7);
+   GG(aa, bb, cc, dd, ee, X[ 0], 12);
+   GG(ee, aa, bb, cc, dd, X[ 9], 15);
+   GG(dd, ee, aa, bb, cc, X[ 5],  9);
+   GG(cc, dd, ee, aa, bb, X[ 2], 11);
+   GG(bb, cc, dd, ee, aa, X[14],  7);
+   GG(aa, bb, cc, dd, ee, X[11], 13);
+   GG(ee, aa, bb, cc, dd, X[ 8], 12);
+
+   /* round 3 */
+   HH(dd, ee, aa, bb, cc, X[ 3], 11);
+   HH(cc, dd, ee, aa, bb, X[10], 13);
+   HH(bb, cc, dd, ee, aa, X[14],  6);
+   HH(aa, bb, cc, dd, ee, X[ 4],  7);
+   HH(ee, aa, bb, cc, dd, X[ 9], 14);
+   HH(dd, ee, aa, bb, cc, X[15],  9);
+   HH(cc, dd, ee, aa, bb, X[ 8], 13);
+   HH(bb, cc, dd, ee, aa, X[ 1], 15);
+   HH(aa, bb, cc, dd, ee, X[ 2], 14);
+   HH(ee, aa, bb, cc, dd, X[ 7],  8);
+   HH(dd, ee, aa, bb, cc, X[ 0], 13);
+   HH(cc, dd, ee, aa, bb, X[ 6],  6);
+   HH(bb, cc, dd, ee, aa, X[13],  5);
+   HH(aa, bb, cc, dd, ee, X[11], 12);
+   HH(ee, aa, bb, cc, dd, X[ 5],  7);
+   HH(dd, ee, aa, bb, cc, X[12],  5);
+
+   /* round 4 */
+   II(cc, dd, ee, aa, bb, X[ 1], 11);
+   II(bb, cc, dd, ee, aa, X[ 9], 12);
+   II(aa, bb, cc, dd, ee, X[11], 14);
+   II(ee, aa, bb, cc, dd, X[10], 15);
+   II(dd, ee, aa, bb, cc, X[ 0], 14);
+   II(cc, dd, ee, aa, bb, X[ 8], 15);
+   II(bb, cc, dd, ee, aa, X[12],  9);
+   II(aa, bb, cc, dd, ee, X[ 4],  8);
+   II(ee, aa, bb, cc, dd, X[13],  9);
+   II(dd, ee, aa, bb, cc, X[ 3], 14);
+   II(cc, dd, ee, aa, bb, X[ 7],  5);
+   II(bb, cc, dd, ee, aa, X[15],  6);
+   II(aa, bb, cc, dd, ee, X[14],  8);
+   II(ee, aa, bb, cc, dd, X[ 5],  6);
+   II(dd, ee, aa, bb, cc, X[ 6],  5);
+   II(cc, dd, ee, aa, bb, X[ 2], 12);
+
+   /* round 5 */
+   JJ(bb, cc, dd, ee, aa, X[ 4],  9);
+   JJ(aa, bb, cc, dd, ee, X[ 0], 15);
+   JJ(ee, aa, bb, cc, dd, X[ 5],  5);
+   JJ(dd, ee, aa, bb, cc, X[ 9], 11);
+   JJ(cc, dd, ee, aa, bb, X[ 7],  6);
+   JJ(bb, cc, dd, ee, aa, X[12],  8);
+   JJ(aa, bb, cc, dd, ee, X[ 2], 13);
+   JJ(ee, aa, bb, cc, dd, X[10], 12);
+   JJ(dd, ee, aa, bb, cc, X[14],  5);
+   JJ(cc, dd, ee, aa, bb, X[ 1], 12);
+   JJ(bb, cc, dd, ee, aa, X[ 3], 13);
+   JJ(aa, bb, cc, dd, ee, X[ 8], 14);
+   JJ(ee, aa, bb, cc, dd, X[11], 11);
+   JJ(dd, ee, aa, bb, cc, X[ 6],  8);
+   JJ(cc, dd, ee, aa, bb, X[15],  5);
+   JJ(bb, cc, dd, ee, aa, X[13],  6);
+
+   /* parallel round 1 */
+   JJJ(aaa, bbb, ccc, ddd, eee, X[ 5],  8);
+   JJJ(eee, aaa, bbb, ccc, ddd, X[14],  9);
+   JJJ(ddd, eee, aaa, bbb, ccc, X[ 7],  9);
+   JJJ(ccc, ddd, eee, aaa, bbb, X[ 0], 11);
+   JJJ(bbb, ccc, ddd, eee, aaa, X[ 9], 13);
+   JJJ(aaa, bbb, ccc, ddd, eee, X[ 2], 15);
+   JJJ(eee, aaa, bbb, ccc, ddd, X[11], 15);
+   JJJ(ddd, eee, aaa, bbb, ccc, X[ 4],  5);
+   JJJ(ccc, ddd, eee, aaa, bbb, X[13],  7);
+   JJJ(bbb, ccc, ddd, eee, aaa, X[ 6],  7);
+   JJJ(aaa, bbb, ccc, ddd, eee, X[15],  8);
+   JJJ(eee, aaa, bbb, ccc, ddd, X[ 8], 11);
+   JJJ(ddd, eee, aaa, bbb, ccc, X[ 1], 14);
+   JJJ(ccc, ddd, eee, aaa, bbb, X[10], 14);
+   JJJ(bbb, ccc, ddd, eee, aaa, X[ 3], 12);
+   JJJ(aaa, bbb, ccc, ddd, eee, X[12],  6);
+
+   /* parallel round 2 */
+   III(eee, aaa, bbb, ccc, ddd, X[ 6],  9);
+   III(ddd, eee, aaa, bbb, ccc, X[11], 13);
+   III(ccc, ddd, eee, aaa, bbb, X[ 3], 15);
+   III(bbb, ccc, ddd, eee, aaa, X[ 7],  7);
+   III(aaa, bbb, ccc, ddd, eee, X[ 0], 12);
+   III(eee, aaa, bbb, ccc, ddd, X[13],  8);
+   III(ddd, eee, aaa, bbb, ccc, X[ 5],  9);
+   III(ccc, ddd, eee, aaa, bbb, X[10], 11);
+   III(bbb, ccc, ddd, eee, aaa, X[14],  7);
+   III(aaa, bbb, ccc, ddd, eee, X[15],  7);
+   III(eee, aaa, bbb, ccc, ddd, X[ 8], 12);
+   III(ddd, eee, aaa, bbb, ccc, X[12],  7);
+   III(ccc, ddd, eee, aaa, bbb, X[ 4],  6);
+   III(bbb, ccc, ddd, eee, aaa, X[ 9], 15);
+   III(aaa, bbb, ccc, ddd, eee, X[ 1], 13);
+   III(eee, aaa, bbb, ccc, ddd, X[ 2], 11);
+
+   /* parallel round 3 */
+   HHH(ddd, eee, aaa, bbb, ccc, X[15],  9);
+   HHH(ccc, ddd, eee, aaa, bbb, X[ 5],  7);
+   HHH(bbb, ccc, ddd, eee, aaa, X[ 1], 15);
+   HHH(aaa, bbb, ccc, ddd, eee, X[ 3], 11);
+   HHH(eee, aaa, bbb, ccc, ddd, X[ 7],  8);
+   HHH(ddd, eee, aaa, bbb, ccc, X[14],  6);
+   HHH(ccc, ddd, eee, aaa, bbb, X[ 6],  6);
+   HHH(bbb, ccc, ddd, eee, aaa, X[ 9], 14);
+   HHH(aaa, bbb, ccc, ddd, eee, X[11], 12);
+   HHH(eee, aaa, bbb, ccc, ddd, X[ 8], 13);
+   HHH(ddd, eee, aaa, bbb, ccc, X[12],  5);
+   HHH(ccc, ddd, eee, aaa, bbb, X[ 2], 14);
+   HHH(bbb, ccc, ddd, eee, aaa, X[10], 13);
+   HHH(aaa, bbb, ccc, ddd, eee, X[ 0], 13);
+   HHH(eee, aaa, bbb, ccc, ddd, X[ 4],  7);
+   HHH(ddd, eee, aaa, bbb, ccc, X[13],  5);
+
+   /* parallel round 4 */
+   GGG(ccc, ddd, eee, aaa, bbb, X[ 8], 15);
+   GGG(bbb, ccc, ddd, eee, aaa, X[ 6],  5);
+   GGG(aaa, bbb, ccc, ddd, eee, X[ 4],  8);
+   GGG(eee, aaa, bbb, ccc, ddd, X[ 1], 11);
+   GGG(ddd, eee, aaa, bbb, ccc, X[ 3], 14);
+   GGG(ccc, ddd, eee, aaa, bbb, X[11], 14);
+   GGG(bbb, ccc, ddd, eee, aaa, X[15],  6);
+   GGG(aaa, bbb, ccc, ddd, eee, X[ 0], 14);
+   GGG(eee, aaa, bbb, ccc, ddd, X[ 5],  6);
+   GGG(ddd, eee, aaa, bbb, ccc, X[12],  9);
+   GGG(ccc, ddd, eee, aaa, bbb, X[ 2], 12);
+   GGG(bbb, ccc, ddd, eee, aaa, X[13],  9);
+   GGG(aaa, bbb, ccc, ddd, eee, X[ 9], 12);
+   GGG(eee, aaa, bbb, ccc, ddd, X[ 7],  5);
+   GGG(ddd, eee, aaa, bbb, ccc, X[10], 15);
+   GGG(ccc, ddd, eee, aaa, bbb, X[14],  8);
+
+   /* parallel round 5 */
+   FFF(bbb, ccc, ddd, eee, aaa, X[12] ,  8);
+   FFF(aaa, bbb, ccc, ddd, eee, X[15] ,  5);
+   FFF(eee, aaa, bbb, ccc, ddd, X[10] , 12);
+   FFF(ddd, eee, aaa, bbb, ccc, X[ 4] ,  9);
+   FFF(ccc, ddd, eee, aaa, bbb, X[ 1] , 12);
+   FFF(bbb, ccc, ddd, eee, aaa, X[ 5] ,  5);
+   FFF(aaa, bbb, ccc, ddd, eee, X[ 8] , 14);
+   FFF(eee, aaa, bbb, ccc, ddd, X[ 7] ,  6);
+   FFF(ddd, eee, aaa, bbb, ccc, X[ 6] ,  8);
+   FFF(ccc, ddd, eee, aaa, bbb, X[ 2] , 13);
+   FFF(bbb, ccc, ddd, eee, aaa, X[13] ,  6);
+   FFF(aaa, bbb, ccc, ddd, eee, X[14] ,  5);
+   FFF(eee, aaa, bbb, ccc, ddd, X[ 0] , 15);
+   FFF(ddd, eee, aaa, bbb, ccc, X[ 3] , 13);
+   FFF(ccc, ddd, eee, aaa, bbb, X[ 9] , 11);
+   FFF(bbb, ccc, ddd, eee, aaa, X[11] , 11);
+
+   /* combine results */
+   ddd += cc + md->rmd160.state[1];               /* final result for md->rmd160.state[0] */
+   md->rmd160.state[1] = md->rmd160.state[2] + dd + eee;
+   md->rmd160.state[2] = md->rmd160.state[3] + ee + aaa;
+   md->rmd160.state[3] = md->rmd160.state[4] + aa + bbb;
+   md->rmd160.state[4] = md->rmd160.state[0] + bb + ccc;
+   md->rmd160.state[0] = ddd;
+
+   return CRYPT_OK;
+}
+
+#ifdef LTC_CLEAN_STACK
+static int rmd160_compress(hash_state *md, unsigned char *buf)
+{
+   int err;
+   err = _rmd160_compress(md, buf);
+   burn_stack(sizeof(ulong32) * 26 + sizeof(int));
+   return err;
+}
+#endif
+
+/**
+   Initialize the hash state
+   @param md   The hash state you wish to initialize
+   @return CRYPT_OK if successful
+*/
+int rmd160_init(hash_state * md)
+{
+   LTC_ARGCHK(md != NULL);
+   md->rmd160.state[0] = 0x67452301UL;
+   md->rmd160.state[1] = 0xefcdab89UL;
+   md->rmd160.state[2] = 0x98badcfeUL;
+   md->rmd160.state[3] = 0x10325476UL;
+   md->rmd160.state[4] = 0xc3d2e1f0UL;
+   md->rmd160.curlen   = 0;
+   md->rmd160.length   = 0;
+   return CRYPT_OK;
+}
+
+/**
+   Process a block of memory though the hash
+   @param md     The hash state
+   @param in     The data to hash
+   @param inlen  The length of the data (octets)
+   @return CRYPT_OK if successful
+*/
+HASH_PROCESS(rmd160_process, rmd160_compress, rmd160, 64)
+
+/**
+   Terminate the hash to get the digest
+   @param md  The hash state
+   @param out [out] The destination of the hash (20 bytes)
+   @return CRYPT_OK if successful
+*/
+int rmd160_done(hash_state * md, unsigned char *out)
+{
+    int i;
+
+    LTC_ARGCHK(md  != NULL);
+    LTC_ARGCHK(out != NULL);
+
+    if (md->rmd160.curlen >= sizeof(md->rmd160.buf)) {
+       return CRYPT_INVALID_ARG;
+    }
+
+
+    /* increase the length of the message */
+    md->rmd160.length += md->rmd160.curlen * 8;
+
+    /* append the '1' bit */
+    md->rmd160.buf[md->rmd160.curlen++] = (unsigned char)0x80;
+
+    /* if the length is currently above 56 bytes we append zeros
+     * then compress.  Then we can fall back to padding zeros and length
+     * encoding like normal.
+     */
+    if (md->rmd160.curlen > 56) {
+        while (md->rmd160.curlen < 64) {
+            md->rmd160.buf[md->rmd160.curlen++] = (unsigned char)0;
+        }
+        rmd160_compress(md, md->rmd160.buf);
+        md->rmd160.curlen = 0;
+    }
+
+    /* pad upto 56 bytes of zeroes */
+    while (md->rmd160.curlen < 56) {
+        md->rmd160.buf[md->rmd160.curlen++] = (unsigned char)0;
+    }
+
+    /* store length */
+    STORE64L(md->rmd160.length, md->rmd160.buf+56);
+    rmd160_compress(md, md->rmd160.buf);
+
+    /* copy output */
+    for (i = 0; i < 5; i++) {
+        STORE32L(md->rmd160.state[i], out+(4*i));
+    }
+#ifdef LTC_CLEAN_STACK
+    zeromem(md, sizeof(hash_state));
+#endif
+    return CRYPT_OK;
+}
+
+/**
+  Self-test the hash
+  @return CRYPT_OK if successful, CRYPT_NOP if self-tests have been disabled
+*/
+int rmd160_test(void)
+{
+#ifndef LTC_TEST
+   return CRYPT_NOP;
+#else
+   static const struct {
+        const char *msg;
+        unsigned char hash[20];
+   } tests[] = {
+   { "",
+     { 0x9c, 0x11, 0x85, 0xa5, 0xc5, 0xe9, 0xfc, 0x54, 0x61, 0x28,
+       0x08, 0x97, 0x7e, 0xe8, 0xf5, 0x48, 0xb2, 0x25, 0x8d, 0x31 }
+   },
+   { "a",
+     { 0x0b, 0xdc, 0x9d, 0x2d, 0x25, 0x6b, 0x3e, 0xe9, 0xda, 0xae,
+       0x34, 0x7b, 0xe6, 0xf4, 0xdc, 0x83, 0x5a, 0x46, 0x7f, 0xfe }
+   },
+   { "abc",
+     { 0x8e, 0xb2, 0x08, 0xf7, 0xe0, 0x5d, 0x98, 0x7a, 0x9b, 0x04,
+       0x4a, 0x8e, 0x98, 0xc6, 0xb0, 0x87, 0xf1, 0x5a, 0x0b, 0xfc }
+   },
+   { "message digest",
+     { 0x5d, 0x06, 0x89, 0xef, 0x49, 0xd2, 0xfa, 0xe5, 0x72, 0xb8,
+       0x81, 0xb1, 0x23, 0xa8, 0x5f, 0xfa, 0x21, 0x59, 0x5f, 0x36 }
+   },
+   { "abcdefghijklmnopqrstuvwxyz",
+     { 0xf7, 0x1c, 0x27, 0x10, 0x9c, 0x69, 0x2c, 0x1b, 0x56, 0xbb,
+       0xdc, 0xeb, 0x5b, 0x9d, 0x28, 0x65, 0xb3, 0x70, 0x8d, 0xbc }
+   },
+   { "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
+     { 0x12, 0xa0, 0x53, 0x38, 0x4a, 0x9c, 0x0c, 0x88, 0xe4, 0x05,
+       0xa0, 0x6c, 0x27, 0xdc, 0xf4, 0x9a, 0xda, 0x62, 0xeb, 0x2b }
+   }
+   };
+
+   int i;
+   unsigned char tmp[20];
+   hash_state md;
+
+   for (i = 0; i < (int)(sizeof(tests)/sizeof(tests[0])); i++) {
+       rmd160_init(&md);
+       rmd160_process(&md, (unsigned char *)tests[i].msg, strlen(tests[i].msg));
+       rmd160_done(&md, tmp);
+       if (compare_testvector(tmp, sizeof(tmp), tests[i].hash, sizeof(tests[i].hash), "RIPEMD160", i)) {
+          return CRYPT_FAIL_TESTVECTOR;
+       }
+   }
+   return CRYPT_OK;
+#endif
+}
+
+#endif
+
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/hashes/rmd256.c b/libtomcrypt/src/hashes/rmd256.c
new file mode 100644 (file)
index 0000000..5fade82
--- /dev/null
@@ -0,0 +1,430 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+   @param rmd256.c
+   RLTC_MD256 Hash function
+*/
+
+#ifdef LTC_RIPEMD256
+
+const struct ltc_hash_descriptor rmd256_desc =
+{
+    "rmd256",
+    13,
+    32,
+    64,
+
+    /* OID */
+   { 1, 3, 36, 3, 2, 3 },
+   6,
+
+    &rmd256_init,
+    &rmd256_process,
+    &rmd256_done,
+    &rmd256_test,
+    NULL
+};
+
+/* the four basic functions F(), G() and H() */
+#define F(x, y, z)        ((x) ^ (y) ^ (z))
+#define G(x, y, z)        (((x) & (y)) | (~(x) & (z)))
+#define H(x, y, z)        (((x) | ~(y)) ^ (z))
+#define I(x, y, z)        (((x) & (z)) | ((y) & ~(z)))
+
+/* the eight basic operations FF() through III() */
+#define FF(a, b, c, d, x, s)        \
+      (a) += F((b), (c), (d)) + (x);\
+      (a) = ROLc((a), (s));
+
+#define GG(a, b, c, d, x, s)        \
+      (a) += G((b), (c), (d)) + (x) + 0x5a827999UL;\
+      (a) = ROLc((a), (s));
+
+#define HH(a, b, c, d, x, s)        \
+      (a) += H((b), (c), (d)) + (x) + 0x6ed9eba1UL;\
+      (a) = ROLc((a), (s));
+
+#define II(a, b, c, d, x, s)        \
+      (a) += I((b), (c), (d)) + (x) + 0x8f1bbcdcUL;\
+      (a) = ROLc((a), (s));
+
+#define FFF(a, b, c, d, x, s)        \
+      (a) += F((b), (c), (d)) + (x);\
+      (a) = ROLc((a), (s));
+
+#define GGG(a, b, c, d, x, s)        \
+      (a) += G((b), (c), (d)) + (x) + 0x6d703ef3UL;\
+      (a) = ROLc((a), (s));
+
+#define HHH(a, b, c, d, x, s)        \
+      (a) += H((b), (c), (d)) + (x) + 0x5c4dd124UL;\
+      (a) = ROLc((a), (s));
+
+#define III(a, b, c, d, x, s)        \
+      (a) += I((b), (c), (d)) + (x) + 0x50a28be6UL;\
+      (a) = ROLc((a), (s));
+
+#ifdef LTC_CLEAN_STACK
+static int _rmd256_compress(hash_state *md, unsigned char *buf)
+#else
+static int  rmd256_compress(hash_state *md, unsigned char *buf)
+#endif
+{
+   ulong32 aa,bb,cc,dd,aaa,bbb,ccc,ddd,tmp,X[16];
+   int i;
+
+   /* load words X */
+   for (i = 0; i < 16; i++){
+      LOAD32L(X[i], buf + (4 * i));
+   }
+
+   /* load state */
+   aa = md->rmd256.state[0];
+   bb = md->rmd256.state[1];
+   cc = md->rmd256.state[2];
+   dd = md->rmd256.state[3];
+   aaa = md->rmd256.state[4];
+   bbb = md->rmd256.state[5];
+   ccc = md->rmd256.state[6];
+   ddd = md->rmd256.state[7];
+
+   /* round 1 */
+   FF(aa, bb, cc, dd, X[ 0], 11);
+   FF(dd, aa, bb, cc, X[ 1], 14);
+   FF(cc, dd, aa, bb, X[ 2], 15);
+   FF(bb, cc, dd, aa, X[ 3], 12);
+   FF(aa, bb, cc, dd, X[ 4],  5);
+   FF(dd, aa, bb, cc, X[ 5],  8);
+   FF(cc, dd, aa, bb, X[ 6],  7);
+   FF(bb, cc, dd, aa, X[ 7],  9);
+   FF(aa, bb, cc, dd, X[ 8], 11);
+   FF(dd, aa, bb, cc, X[ 9], 13);
+   FF(cc, dd, aa, bb, X[10], 14);
+   FF(bb, cc, dd, aa, X[11], 15);
+   FF(aa, bb, cc, dd, X[12],  6);
+   FF(dd, aa, bb, cc, X[13],  7);
+   FF(cc, dd, aa, bb, X[14],  9);
+   FF(bb, cc, dd, aa, X[15],  8);
+
+   /* parallel round 1 */
+   III(aaa, bbb, ccc, ddd, X[ 5],  8);
+   III(ddd, aaa, bbb, ccc, X[14],  9);
+   III(ccc, ddd, aaa, bbb, X[ 7],  9);
+   III(bbb, ccc, ddd, aaa, X[ 0], 11);
+   III(aaa, bbb, ccc, ddd, X[ 9], 13);
+   III(ddd, aaa, bbb, ccc, X[ 2], 15);
+   III(ccc, ddd, aaa, bbb, X[11], 15);
+   III(bbb, ccc, ddd, aaa, X[ 4],  5);
+   III(aaa, bbb, ccc, ddd, X[13],  7);
+   III(ddd, aaa, bbb, ccc, X[ 6],  7);
+   III(ccc, ddd, aaa, bbb, X[15],  8);
+   III(bbb, ccc, ddd, aaa, X[ 8], 11);
+   III(aaa, bbb, ccc, ddd, X[ 1], 14);
+   III(ddd, aaa, bbb, ccc, X[10], 14);
+   III(ccc, ddd, aaa, bbb, X[ 3], 12);
+   III(bbb, ccc, ddd, aaa, X[12],  6);
+
+   tmp = aa; aa = aaa; aaa = tmp;
+
+   /* round 2 */
+   GG(aa, bb, cc, dd, X[ 7],  7);
+   GG(dd, aa, bb, cc, X[ 4],  6);
+   GG(cc, dd, aa, bb, X[13],  8);
+   GG(bb, cc, dd, aa, X[ 1], 13);
+   GG(aa, bb, cc, dd, X[10], 11);
+   GG(dd, aa, bb, cc, X[ 6],  9);
+   GG(cc, dd, aa, bb, X[15],  7);
+   GG(bb, cc, dd, aa, X[ 3], 15);
+   GG(aa, bb, cc, dd, X[12],  7);
+   GG(dd, aa, bb, cc, X[ 0], 12);
+   GG(cc, dd, aa, bb, X[ 9], 15);
+   GG(bb, cc, dd, aa, X[ 5],  9);
+   GG(aa, bb, cc, dd, X[ 2], 11);
+   GG(dd, aa, bb, cc, X[14],  7);
+   GG(cc, dd, aa, bb, X[11], 13);
+   GG(bb, cc, dd, aa, X[ 8], 12);
+
+   /* parallel round 2 */
+   HHH(aaa, bbb, ccc, ddd, X[ 6],  9);
+   HHH(ddd, aaa, bbb, ccc, X[11], 13);
+   HHH(ccc, ddd, aaa, bbb, X[ 3], 15);
+   HHH(bbb, ccc, ddd, aaa, X[ 7],  7);
+   HHH(aaa, bbb, ccc, ddd, X[ 0], 12);
+   HHH(ddd, aaa, bbb, ccc, X[13],  8);
+   HHH(ccc, ddd, aaa, bbb, X[ 5],  9);
+   HHH(bbb, ccc, ddd, aaa, X[10], 11);
+   HHH(aaa, bbb, ccc, ddd, X[14],  7);
+   HHH(ddd, aaa, bbb, ccc, X[15],  7);
+   HHH(ccc, ddd, aaa, bbb, X[ 8], 12);
+   HHH(bbb, ccc, ddd, aaa, X[12],  7);
+   HHH(aaa, bbb, ccc, ddd, X[ 4],  6);
+   HHH(ddd, aaa, bbb, ccc, X[ 9], 15);
+   HHH(ccc, ddd, aaa, bbb, X[ 1], 13);
+   HHH(bbb, ccc, ddd, aaa, X[ 2], 11);
+
+   tmp = bb; bb = bbb; bbb = tmp;
+
+   /* round 3 */
+   HH(aa, bb, cc, dd, X[ 3], 11);
+   HH(dd, aa, bb, cc, X[10], 13);
+   HH(cc, dd, aa, bb, X[14],  6);
+   HH(bb, cc, dd, aa, X[ 4],  7);
+   HH(aa, bb, cc, dd, X[ 9], 14);
+   HH(dd, aa, bb, cc, X[15],  9);
+   HH(cc, dd, aa, bb, X[ 8], 13);
+   HH(bb, cc, dd, aa, X[ 1], 15);
+   HH(aa, bb, cc, dd, X[ 2], 14);
+   HH(dd, aa, bb, cc, X[ 7],  8);
+   HH(cc, dd, aa, bb, X[ 0], 13);
+   HH(bb, cc, dd, aa, X[ 6],  6);
+   HH(aa, bb, cc, dd, X[13],  5);
+   HH(dd, aa, bb, cc, X[11], 12);
+   HH(cc, dd, aa, bb, X[ 5],  7);
+   HH(bb, cc, dd, aa, X[12],  5);
+
+   /* parallel round 3 */
+   GGG(aaa, bbb, ccc, ddd, X[15],  9);
+   GGG(ddd, aaa, bbb, ccc, X[ 5],  7);
+   GGG(ccc, ddd, aaa, bbb, X[ 1], 15);
+   GGG(bbb, ccc, ddd, aaa, X[ 3], 11);
+   GGG(aaa, bbb, ccc, ddd, X[ 7],  8);
+   GGG(ddd, aaa, bbb, ccc, X[14],  6);
+   GGG(ccc, ddd, aaa, bbb, X[ 6],  6);
+   GGG(bbb, ccc, ddd, aaa, X[ 9], 14);
+   GGG(aaa, bbb, ccc, ddd, X[11], 12);
+   GGG(ddd, aaa, bbb, ccc, X[ 8], 13);
+   GGG(ccc, ddd, aaa, bbb, X[12],  5);
+   GGG(bbb, ccc, ddd, aaa, X[ 2], 14);
+   GGG(aaa, bbb, ccc, ddd, X[10], 13);
+   GGG(ddd, aaa, bbb, ccc, X[ 0], 13);
+   GGG(ccc, ddd, aaa, bbb, X[ 4],  7);
+   GGG(bbb, ccc, ddd, aaa, X[13],  5);
+
+   tmp = cc; cc = ccc; ccc = tmp;
+
+   /* round 4 */
+   II(aa, bb, cc, dd, X[ 1], 11);
+   II(dd, aa, bb, cc, X[ 9], 12);
+   II(cc, dd, aa, bb, X[11], 14);
+   II(bb, cc, dd, aa, X[10], 15);
+   II(aa, bb, cc, dd, X[ 0], 14);
+   II(dd, aa, bb, cc, X[ 8], 15);
+   II(cc, dd, aa, bb, X[12],  9);
+   II(bb, cc, dd, aa, X[ 4],  8);
+   II(aa, bb, cc, dd, X[13],  9);
+   II(dd, aa, bb, cc, X[ 3], 14);
+   II(cc, dd, aa, bb, X[ 7],  5);
+   II(bb, cc, dd, aa, X[15],  6);
+   II(aa, bb, cc, dd, X[14],  8);
+   II(dd, aa, bb, cc, X[ 5],  6);
+   II(cc, dd, aa, bb, X[ 6],  5);
+   II(bb, cc, dd, aa, X[ 2], 12);
+
+   /* parallel round 4 */
+   FFF(aaa, bbb, ccc, ddd, X[ 8], 15);
+   FFF(ddd, aaa, bbb, ccc, X[ 6],  5);
+   FFF(ccc, ddd, aaa, bbb, X[ 4],  8);
+   FFF(bbb, ccc, ddd, aaa, X[ 1], 11);
+   FFF(aaa, bbb, ccc, ddd, X[ 3], 14);
+   FFF(ddd, aaa, bbb, ccc, X[11], 14);
+   FFF(ccc, ddd, aaa, bbb, X[15],  6);
+   FFF(bbb, ccc, ddd, aaa, X[ 0], 14);
+   FFF(aaa, bbb, ccc, ddd, X[ 5],  6);
+   FFF(ddd, aaa, bbb, ccc, X[12],  9);
+   FFF(ccc, ddd, aaa, bbb, X[ 2], 12);
+   FFF(bbb, ccc, ddd, aaa, X[13],  9);
+   FFF(aaa, bbb, ccc, ddd, X[ 9], 12);
+   FFF(ddd, aaa, bbb, ccc, X[ 7],  5);
+   FFF(ccc, ddd, aaa, bbb, X[10], 15);
+   FFF(bbb, ccc, ddd, aaa, X[14],  8);
+
+   tmp = dd; dd = ddd; ddd = tmp;
+
+   /* combine results */
+   md->rmd256.state[0] += aa;
+   md->rmd256.state[1] += bb;
+   md->rmd256.state[2] += cc;
+   md->rmd256.state[3] += dd;
+   md->rmd256.state[4] += aaa;
+   md->rmd256.state[5] += bbb;
+   md->rmd256.state[6] += ccc;
+   md->rmd256.state[7] += ddd;
+
+   return CRYPT_OK;
+}
+
+#ifdef LTC_CLEAN_STACK
+static int rmd256_compress(hash_state *md, unsigned char *buf)
+{
+   int err;
+   err = _rmd256_compress(md, buf);
+   burn_stack(sizeof(ulong32) * 25 + sizeof(int));
+   return err;
+}
+#endif
+
+/**
+   Initialize the hash state
+   @param md   The hash state you wish to initialize
+   @return CRYPT_OK if successful
+*/
+int rmd256_init(hash_state * md)
+{
+   LTC_ARGCHK(md != NULL);
+   md->rmd256.state[0] = 0x67452301UL;
+   md->rmd256.state[1] = 0xefcdab89UL;
+   md->rmd256.state[2] = 0x98badcfeUL;
+   md->rmd256.state[3] = 0x10325476UL;
+   md->rmd256.state[4] = 0x76543210UL;
+   md->rmd256.state[5] = 0xfedcba98UL;
+   md->rmd256.state[6] = 0x89abcdefUL;
+   md->rmd256.state[7] = 0x01234567UL;
+   md->rmd256.curlen   = 0;
+   md->rmd256.length   = 0;
+   return CRYPT_OK;
+}
+
+/**
+   Process a block of memory though the hash
+   @param md     The hash state
+   @param in     The data to hash
+   @param inlen  The length of the data (octets)
+   @return CRYPT_OK if successful
+*/
+HASH_PROCESS(rmd256_process, rmd256_compress, rmd256, 64)
+
+/**
+   Terminate the hash to get the digest
+   @param md  The hash state
+   @param out [out] The destination of the hash (16 bytes)
+   @return CRYPT_OK if successful
+*/
+int rmd256_done(hash_state * md, unsigned char *out)
+{
+    int i;
+
+    LTC_ARGCHK(md  != NULL);
+    LTC_ARGCHK(out != NULL);
+
+    if (md->rmd256.curlen >= sizeof(md->rmd256.buf)) {
+       return CRYPT_INVALID_ARG;
+    }
+
+
+    /* increase the length of the message */
+    md->rmd256.length += md->rmd256.curlen * 8;
+
+    /* append the '1' bit */
+    md->rmd256.buf[md->rmd256.curlen++] = (unsigned char)0x80;
+
+    /* if the length is currently above 56 bytes we append zeros
+     * then compress.  Then we can fall back to padding zeros and length
+     * encoding like normal.
+     */
+    if (md->rmd256.curlen > 56) {
+        while (md->rmd256.curlen < 64) {
+            md->rmd256.buf[md->rmd256.curlen++] = (unsigned char)0;
+        }
+        rmd256_compress(md, md->rmd256.buf);
+        md->rmd256.curlen = 0;
+    }
+
+    /* pad upto 56 bytes of zeroes */
+    while (md->rmd256.curlen < 56) {
+        md->rmd256.buf[md->rmd256.curlen++] = (unsigned char)0;
+    }
+
+    /* store length */
+    STORE64L(md->rmd256.length, md->rmd256.buf+56);
+    rmd256_compress(md, md->rmd256.buf);
+
+    /* copy output */
+    for (i = 0; i < 8; i++) {
+        STORE32L(md->rmd256.state[i], out+(4*i));
+    }
+#ifdef LTC_CLEAN_STACK
+    zeromem(md, sizeof(hash_state));
+#endif
+   return CRYPT_OK;
+}
+
+/**
+  Self-test the hash
+  @return CRYPT_OK if successful, CRYPT_NOP if self-tests have been disabled
+*/
+int rmd256_test(void)
+{
+#ifndef LTC_TEST
+   return CRYPT_NOP;
+#else
+   static const struct {
+        const char *msg;
+        unsigned char hash[32];
+   } tests[] = {
+   { "",
+     { 0x02, 0xba, 0x4c, 0x4e, 0x5f, 0x8e, 0xcd, 0x18,
+       0x77, 0xfc, 0x52, 0xd6, 0x4d, 0x30, 0xe3, 0x7a,
+       0x2d, 0x97, 0x74, 0xfb, 0x1e, 0x5d, 0x02, 0x63,
+       0x80, 0xae, 0x01, 0x68, 0xe3, 0xc5, 0x52, 0x2d }
+   },
+   { "a",
+     { 0xf9, 0x33, 0x3e, 0x45, 0xd8, 0x57, 0xf5, 0xd9,
+       0x0a, 0x91, 0xba, 0xb7, 0x0a, 0x1e, 0xba, 0x0c,
+       0xfb, 0x1b, 0xe4, 0xb0, 0x78, 0x3c, 0x9a, 0xcf,
+       0xcd, 0x88, 0x3a, 0x91, 0x34, 0x69, 0x29, 0x25 }
+   },
+   { "abc",
+     { 0xaf, 0xbd, 0x6e, 0x22, 0x8b, 0x9d, 0x8c, 0xbb,
+       0xce, 0xf5, 0xca, 0x2d, 0x03, 0xe6, 0xdb, 0xa1,
+       0x0a, 0xc0, 0xbc, 0x7d, 0xcb, 0xe4, 0x68, 0x0e,
+       0x1e, 0x42, 0xd2, 0xe9, 0x75, 0x45, 0x9b, 0x65 }
+   },
+   { "message digest",
+     { 0x87, 0xe9, 0x71, 0x75, 0x9a, 0x1c, 0xe4, 0x7a,
+       0x51, 0x4d, 0x5c, 0x91, 0x4c, 0x39, 0x2c, 0x90,
+       0x18, 0xc7, 0xc4, 0x6b, 0xc1, 0x44, 0x65, 0x55,
+       0x4a, 0xfc, 0xdf, 0x54, 0xa5, 0x07, 0x0c, 0x0e }
+   },
+   { "abcdefghijklmnopqrstuvwxyz",
+     { 0x64, 0x9d, 0x30, 0x34, 0x75, 0x1e, 0xa2, 0x16,
+       0x77, 0x6b, 0xf9, 0xa1, 0x8a, 0xcc, 0x81, 0xbc,
+       0x78, 0x96, 0x11, 0x8a, 0x51, 0x97, 0x96, 0x87,
+       0x82, 0xdd, 0x1f, 0xd9, 0x7d, 0x8d, 0x51, 0x33 }
+   },
+   { "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
+     { 0x57, 0x40, 0xa4, 0x08, 0xac, 0x16, 0xb7, 0x20,
+       0xb8, 0x44, 0x24, 0xae, 0x93, 0x1c, 0xbb, 0x1f,
+       0xe3, 0x63, 0xd1, 0xd0, 0xbf, 0x40, 0x17, 0xf1,
+       0xa8, 0x9f, 0x7e, 0xa6, 0xde, 0x77, 0xa0, 0xb8 }
+   }
+   };
+
+   int i;
+   unsigned char tmp[32];
+   hash_state md;
+
+   for (i = 0; i < (int)(sizeof(tests)/sizeof(tests[0])); i++) {
+       rmd256_init(&md);
+       rmd256_process(&md, (unsigned char *)tests[i].msg, strlen(tests[i].msg));
+       rmd256_done(&md, tmp);
+       if (compare_testvector(tmp, sizeof(tmp), tests[i].hash, sizeof(tests[i].hash), "RIPEMD256", i)) {
+          return CRYPT_FAIL_TESTVECTOR;
+       }
+   }
+   return CRYPT_OK;
+#endif
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/hashes/rmd320.c b/libtomcrypt/src/hashes/rmd320.c
new file mode 100644 (file)
index 0000000..a4356c4
--- /dev/null
@@ -0,0 +1,495 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+   @file rmd320.c
+   RMD320 hash function
+*/
+
+#ifdef LTC_RIPEMD320
+
+const struct ltc_hash_descriptor rmd320_desc =
+{
+    "rmd320",
+    14,
+    40,
+    64,
+
+    /* OID ... does not exist
+     * http://oid-info.com/get/1.3.36.3.2 */
+   { 0 },
+   0,
+
+    &rmd320_init,
+    &rmd320_process,
+    &rmd320_done,
+    &rmd320_test,
+    NULL
+};
+
+/* the five basic functions F(), G() and H() */
+#define F(x, y, z)        ((x) ^ (y) ^ (z))
+#define G(x, y, z)        (((x) & (y)) | (~(x) & (z)))
+#define H(x, y, z)        (((x) | ~(y)) ^ (z))
+#define I(x, y, z)        (((x) & (z)) | ((y) & ~(z)))
+#define J(x, y, z)        ((x) ^ ((y) | ~(z)))
+
+/* the ten basic operations FF() through III() */
+#define FF(a, b, c, d, e, x, s)        \
+      (a) += F((b), (c), (d)) + (x);\
+      (a) = ROLc((a), (s)) + (e);\
+      (c) = ROLc((c), 10);
+
+#define GG(a, b, c, d, e, x, s)        \
+      (a) += G((b), (c), (d)) + (x) + 0x5a827999UL;\
+      (a) = ROLc((a), (s)) + (e);\
+      (c) = ROLc((c), 10);
+
+#define HH(a, b, c, d, e, x, s)        \
+      (a) += H((b), (c), (d)) + (x) + 0x6ed9eba1UL;\
+      (a) = ROLc((a), (s)) + (e);\
+      (c) = ROLc((c), 10);
+
+#define II(a, b, c, d, e, x, s)        \
+      (a) += I((b), (c), (d)) + (x) + 0x8f1bbcdcUL;\
+      (a) = ROLc((a), (s)) + (e);\
+      (c) = ROLc((c), 10);
+
+#define JJ(a, b, c, d, e, x, s)        \
+      (a) += J((b), (c), (d)) + (x) + 0xa953fd4eUL;\
+      (a) = ROLc((a), (s)) + (e);\
+      (c) = ROLc((c), 10);
+
+#define FFF(a, b, c, d, e, x, s)        \
+      (a) += F((b), (c), (d)) + (x);\
+      (a) = ROLc((a), (s)) + (e);\
+      (c) = ROLc((c), 10);
+
+#define GGG(a, b, c, d, e, x, s)        \
+      (a) += G((b), (c), (d)) + (x) + 0x7a6d76e9UL;\
+      (a) = ROLc((a), (s)) + (e);\
+      (c) = ROLc((c), 10);
+
+#define HHH(a, b, c, d, e, x, s)        \
+      (a) += H((b), (c), (d)) + (x) + 0x6d703ef3UL;\
+      (a) = ROLc((a), (s)) + (e);\
+      (c) = ROLc((c), 10);
+
+#define III(a, b, c, d, e, x, s)        \
+      (a) += I((b), (c), (d)) + (x) + 0x5c4dd124UL;\
+      (a) = ROLc((a), (s)) + (e);\
+      (c) = ROLc((c), 10);
+
+#define JJJ(a, b, c, d, e, x, s)        \
+      (a) += J((b), (c), (d)) + (x) + 0x50a28be6UL;\
+      (a) = ROLc((a), (s)) + (e);\
+      (c) = ROLc((c), 10);
+
+
+#ifdef LTC_CLEAN_STACK
+static int _rmd320_compress(hash_state *md, unsigned char *buf)
+#else
+static int  rmd320_compress(hash_state *md, unsigned char *buf)
+#endif
+{
+   ulong32 aa,bb,cc,dd,ee,aaa,bbb,ccc,ddd,eee,tmp,X[16];
+   int i;
+
+   /* load words X */
+   for (i = 0; i < 16; i++){
+      LOAD32L(X[i], buf + (4 * i));
+   }
+
+   /* load state */
+   aa = md->rmd320.state[0];
+   bb = md->rmd320.state[1];
+   cc = md->rmd320.state[2];
+   dd = md->rmd320.state[3];
+   ee = md->rmd320.state[4];
+   aaa = md->rmd320.state[5];
+   bbb = md->rmd320.state[6];
+   ccc = md->rmd320.state[7];
+   ddd = md->rmd320.state[8];
+   eee = md->rmd320.state[9];
+
+   /* round 1 */
+   FF(aa, bb, cc, dd, ee, X[ 0], 11);
+   FF(ee, aa, bb, cc, dd, X[ 1], 14);
+   FF(dd, ee, aa, bb, cc, X[ 2], 15);
+   FF(cc, dd, ee, aa, bb, X[ 3], 12);
+   FF(bb, cc, dd, ee, aa, X[ 4],  5);
+   FF(aa, bb, cc, dd, ee, X[ 5],  8);
+   FF(ee, aa, bb, cc, dd, X[ 6],  7);
+   FF(dd, ee, aa, bb, cc, X[ 7],  9);
+   FF(cc, dd, ee, aa, bb, X[ 8], 11);
+   FF(bb, cc, dd, ee, aa, X[ 9], 13);
+   FF(aa, bb, cc, dd, ee, X[10], 14);
+   FF(ee, aa, bb, cc, dd, X[11], 15);
+   FF(dd, ee, aa, bb, cc, X[12],  6);
+   FF(cc, dd, ee, aa, bb, X[13],  7);
+   FF(bb, cc, dd, ee, aa, X[14],  9);
+   FF(aa, bb, cc, dd, ee, X[15],  8);
+
+   /* parallel round 1 */
+   JJJ(aaa, bbb, ccc, ddd, eee, X[ 5],  8);
+   JJJ(eee, aaa, bbb, ccc, ddd, X[14],  9);
+   JJJ(ddd, eee, aaa, bbb, ccc, X[ 7],  9);
+   JJJ(ccc, ddd, eee, aaa, bbb, X[ 0], 11);
+   JJJ(bbb, ccc, ddd, eee, aaa, X[ 9], 13);
+   JJJ(aaa, bbb, ccc, ddd, eee, X[ 2], 15);
+   JJJ(eee, aaa, bbb, ccc, ddd, X[11], 15);
+   JJJ(ddd, eee, aaa, bbb, ccc, X[ 4],  5);
+   JJJ(ccc, ddd, eee, aaa, bbb, X[13],  7);
+   JJJ(bbb, ccc, ddd, eee, aaa, X[ 6],  7);
+   JJJ(aaa, bbb, ccc, ddd, eee, X[15],  8);
+   JJJ(eee, aaa, bbb, ccc, ddd, X[ 8], 11);
+   JJJ(ddd, eee, aaa, bbb, ccc, X[ 1], 14);
+   JJJ(ccc, ddd, eee, aaa, bbb, X[10], 14);
+   JJJ(bbb, ccc, ddd, eee, aaa, X[ 3], 12);
+   JJJ(aaa, bbb, ccc, ddd, eee, X[12],  6);
+
+   tmp = aa; aa = aaa; aaa = tmp;
+
+   /* round 2 */
+   GG(ee, aa, bb, cc, dd, X[ 7],  7);
+   GG(dd, ee, aa, bb, cc, X[ 4],  6);
+   GG(cc, dd, ee, aa, bb, X[13],  8);
+   GG(bb, cc, dd, ee, aa, X[ 1], 13);
+   GG(aa, bb, cc, dd, ee, X[10], 11);
+   GG(ee, aa, bb, cc, dd, X[ 6],  9);
+   GG(dd, ee, aa, bb, cc, X[15],  7);
+   GG(cc, dd, ee, aa, bb, X[ 3], 15);
+   GG(bb, cc, dd, ee, aa, X[12],  7);
+   GG(aa, bb, cc, dd, ee, X[ 0], 12);
+   GG(ee, aa, bb, cc, dd, X[ 9], 15);
+   GG(dd, ee, aa, bb, cc, X[ 5],  9);
+   GG(cc, dd, ee, aa, bb, X[ 2], 11);
+   GG(bb, cc, dd, ee, aa, X[14],  7);
+   GG(aa, bb, cc, dd, ee, X[11], 13);
+   GG(ee, aa, bb, cc, dd, X[ 8], 12);
+
+   /* parallel round 2 */
+   III(eee, aaa, bbb, ccc, ddd, X[ 6],  9);
+   III(ddd, eee, aaa, bbb, ccc, X[11], 13);
+   III(ccc, ddd, eee, aaa, bbb, X[ 3], 15);
+   III(bbb, ccc, ddd, eee, aaa, X[ 7],  7);
+   III(aaa, bbb, ccc, ddd, eee, X[ 0], 12);
+   III(eee, aaa, bbb, ccc, ddd, X[13],  8);
+   III(ddd, eee, aaa, bbb, ccc, X[ 5],  9);
+   III(ccc, ddd, eee, aaa, bbb, X[10], 11);
+   III(bbb, ccc, ddd, eee, aaa, X[14],  7);
+   III(aaa, bbb, ccc, ddd, eee, X[15],  7);
+   III(eee, aaa, bbb, ccc, ddd, X[ 8], 12);
+   III(ddd, eee, aaa, bbb, ccc, X[12],  7);
+   III(ccc, ddd, eee, aaa, bbb, X[ 4],  6);
+   III(bbb, ccc, ddd, eee, aaa, X[ 9], 15);
+   III(aaa, bbb, ccc, ddd, eee, X[ 1], 13);
+   III(eee, aaa, bbb, ccc, ddd, X[ 2], 11);
+
+   tmp = bb; bb = bbb; bbb = tmp;
+
+   /* round 3 */
+   HH(dd, ee, aa, bb, cc, X[ 3], 11);
+   HH(cc, dd, ee, aa, bb, X[10], 13);
+   HH(bb, cc, dd, ee, aa, X[14],  6);
+   HH(aa, bb, cc, dd, ee, X[ 4],  7);
+   HH(ee, aa, bb, cc, dd, X[ 9], 14);
+   HH(dd, ee, aa, bb, cc, X[15],  9);
+   HH(cc, dd, ee, aa, bb, X[ 8], 13);
+   HH(bb, cc, dd, ee, aa, X[ 1], 15);
+   HH(aa, bb, cc, dd, ee, X[ 2], 14);
+   HH(ee, aa, bb, cc, dd, X[ 7],  8);
+   HH(dd, ee, aa, bb, cc, X[ 0], 13);
+   HH(cc, dd, ee, aa, bb, X[ 6],  6);
+   HH(bb, cc, dd, ee, aa, X[13],  5);
+   HH(aa, bb, cc, dd, ee, X[11], 12);
+   HH(ee, aa, bb, cc, dd, X[ 5],  7);
+   HH(dd, ee, aa, bb, cc, X[12],  5);
+
+   /* parallel round 3 */
+   HHH(ddd, eee, aaa, bbb, ccc, X[15],  9);
+   HHH(ccc, ddd, eee, aaa, bbb, X[ 5],  7);
+   HHH(bbb, ccc, ddd, eee, aaa, X[ 1], 15);
+   HHH(aaa, bbb, ccc, ddd, eee, X[ 3], 11);
+   HHH(eee, aaa, bbb, ccc, ddd, X[ 7],  8);
+   HHH(ddd, eee, aaa, bbb, ccc, X[14],  6);
+   HHH(ccc, ddd, eee, aaa, bbb, X[ 6],  6);
+   HHH(bbb, ccc, ddd, eee, aaa, X[ 9], 14);
+   HHH(aaa, bbb, ccc, ddd, eee, X[11], 12);
+   HHH(eee, aaa, bbb, ccc, ddd, X[ 8], 13);
+   HHH(ddd, eee, aaa, bbb, ccc, X[12],  5);
+   HHH(ccc, ddd, eee, aaa, bbb, X[ 2], 14);
+   HHH(bbb, ccc, ddd, eee, aaa, X[10], 13);
+   HHH(aaa, bbb, ccc, ddd, eee, X[ 0], 13);
+   HHH(eee, aaa, bbb, ccc, ddd, X[ 4],  7);
+   HHH(ddd, eee, aaa, bbb, ccc, X[13],  5);
+
+   tmp = cc; cc = ccc; ccc = tmp;
+
+   /* round 4 */
+   II(cc, dd, ee, aa, bb, X[ 1], 11);
+   II(bb, cc, dd, ee, aa, X[ 9], 12);
+   II(aa, bb, cc, dd, ee, X[11], 14);
+   II(ee, aa, bb, cc, dd, X[10], 15);
+   II(dd, ee, aa, bb, cc, X[ 0], 14);
+   II(cc, dd, ee, aa, bb, X[ 8], 15);
+   II(bb, cc, dd, ee, aa, X[12],  9);
+   II(aa, bb, cc, dd, ee, X[ 4],  8);
+   II(ee, aa, bb, cc, dd, X[13],  9);
+   II(dd, ee, aa, bb, cc, X[ 3], 14);
+   II(cc, dd, ee, aa, bb, X[ 7],  5);
+   II(bb, cc, dd, ee, aa, X[15],  6);
+   II(aa, bb, cc, dd, ee, X[14],  8);
+   II(ee, aa, bb, cc, dd, X[ 5],  6);
+   II(dd, ee, aa, bb, cc, X[ 6],  5);
+   II(cc, dd, ee, aa, bb, X[ 2], 12);
+
+   /* parallel round 4 */
+   GGG(ccc, ddd, eee, aaa, bbb, X[ 8], 15);
+   GGG(bbb, ccc, ddd, eee, aaa, X[ 6],  5);
+   GGG(aaa, bbb, ccc, ddd, eee, X[ 4],  8);
+   GGG(eee, aaa, bbb, ccc, ddd, X[ 1], 11);
+   GGG(ddd, eee, aaa, bbb, ccc, X[ 3], 14);
+   GGG(ccc, ddd, eee, aaa, bbb, X[11], 14);
+   GGG(bbb, ccc, ddd, eee, aaa, X[15],  6);
+   GGG(aaa, bbb, ccc, ddd, eee, X[ 0], 14);
+   GGG(eee, aaa, bbb, ccc, ddd, X[ 5],  6);
+   GGG(ddd, eee, aaa, bbb, ccc, X[12],  9);
+   GGG(ccc, ddd, eee, aaa, bbb, X[ 2], 12);
+   GGG(bbb, ccc, ddd, eee, aaa, X[13],  9);
+   GGG(aaa, bbb, ccc, ddd, eee, X[ 9], 12);
+   GGG(eee, aaa, bbb, ccc, ddd, X[ 7],  5);
+   GGG(ddd, eee, aaa, bbb, ccc, X[10], 15);
+   GGG(ccc, ddd, eee, aaa, bbb, X[14],  8);
+
+   tmp = dd; dd = ddd; ddd = tmp;
+
+   /* round 5 */
+   JJ(bb, cc, dd, ee, aa, X[ 4],  9);
+   JJ(aa, bb, cc, dd, ee, X[ 0], 15);
+   JJ(ee, aa, bb, cc, dd, X[ 5],  5);
+   JJ(dd, ee, aa, bb, cc, X[ 9], 11);
+   JJ(cc, dd, ee, aa, bb, X[ 7],  6);
+   JJ(bb, cc, dd, ee, aa, X[12],  8);
+   JJ(aa, bb, cc, dd, ee, X[ 2], 13);
+   JJ(ee, aa, bb, cc, dd, X[10], 12);
+   JJ(dd, ee, aa, bb, cc, X[14],  5);
+   JJ(cc, dd, ee, aa, bb, X[ 1], 12);
+   JJ(bb, cc, dd, ee, aa, X[ 3], 13);
+   JJ(aa, bb, cc, dd, ee, X[ 8], 14);
+   JJ(ee, aa, bb, cc, dd, X[11], 11);
+   JJ(dd, ee, aa, bb, cc, X[ 6],  8);
+   JJ(cc, dd, ee, aa, bb, X[15],  5);
+   JJ(bb, cc, dd, ee, aa, X[13],  6);
+
+   /* parallel round 5 */
+   FFF(bbb, ccc, ddd, eee, aaa, X[12] ,  8);
+   FFF(aaa, bbb, ccc, ddd, eee, X[15] ,  5);
+   FFF(eee, aaa, bbb, ccc, ddd, X[10] , 12);
+   FFF(ddd, eee, aaa, bbb, ccc, X[ 4] ,  9);
+   FFF(ccc, ddd, eee, aaa, bbb, X[ 1] , 12);
+   FFF(bbb, ccc, ddd, eee, aaa, X[ 5] ,  5);
+   FFF(aaa, bbb, ccc, ddd, eee, X[ 8] , 14);
+   FFF(eee, aaa, bbb, ccc, ddd, X[ 7] ,  6);
+   FFF(ddd, eee, aaa, bbb, ccc, X[ 6] ,  8);
+   FFF(ccc, ddd, eee, aaa, bbb, X[ 2] , 13);
+   FFF(bbb, ccc, ddd, eee, aaa, X[13] ,  6);
+   FFF(aaa, bbb, ccc, ddd, eee, X[14] ,  5);
+   FFF(eee, aaa, bbb, ccc, ddd, X[ 0] , 15);
+   FFF(ddd, eee, aaa, bbb, ccc, X[ 3] , 13);
+   FFF(ccc, ddd, eee, aaa, bbb, X[ 9] , 11);
+   FFF(bbb, ccc, ddd, eee, aaa, X[11] , 11);
+
+   tmp = ee; ee = eee; eee = tmp;
+
+   /* combine results */
+   md->rmd320.state[0] += aa;
+   md->rmd320.state[1] += bb;
+   md->rmd320.state[2] += cc;
+   md->rmd320.state[3] += dd;
+   md->rmd320.state[4] += ee;
+   md->rmd320.state[5] += aaa;
+   md->rmd320.state[6] += bbb;
+   md->rmd320.state[7] += ccc;
+   md->rmd320.state[8] += ddd;
+   md->rmd320.state[9] += eee;
+
+   return CRYPT_OK;
+}
+
+#ifdef LTC_CLEAN_STACK
+static int rmd320_compress(hash_state *md, unsigned char *buf)
+{
+   int err;
+   err = _rmd320_compress(md, buf);
+   burn_stack(sizeof(ulong32) * 27 + sizeof(int));
+   return err;
+}
+#endif
+
+/**
+   Initialize the hash state
+   @param md   The hash state you wish to initialize
+   @return CRYPT_OK if successful
+*/
+int rmd320_init(hash_state * md)
+{
+   LTC_ARGCHK(md != NULL);
+   md->rmd320.state[0] = 0x67452301UL;
+   md->rmd320.state[1] = 0xefcdab89UL;
+   md->rmd320.state[2] = 0x98badcfeUL;
+   md->rmd320.state[3] = 0x10325476UL;
+   md->rmd320.state[4] = 0xc3d2e1f0UL;
+   md->rmd320.state[5] = 0x76543210UL;
+   md->rmd320.state[6] = 0xfedcba98UL;
+   md->rmd320.state[7] = 0x89abcdefUL;
+   md->rmd320.state[8] = 0x01234567UL;
+   md->rmd320.state[9] = 0x3c2d1e0fUL;
+   md->rmd320.curlen   = 0;
+   md->rmd320.length   = 0;
+   return CRYPT_OK;
+}
+
+/**
+   Process a block of memory though the hash
+   @param md     The hash state
+   @param in     The data to hash
+   @param inlen  The length of the data (octets)
+   @return CRYPT_OK if successful
+*/
+HASH_PROCESS(rmd320_process, rmd320_compress, rmd320, 64)
+
+/**
+   Terminate the hash to get the digest
+   @param md  The hash state
+   @param out [out] The destination of the hash (20 bytes)
+   @return CRYPT_OK if successful
+*/
+int rmd320_done(hash_state * md, unsigned char *out)
+{
+    int i;
+
+    LTC_ARGCHK(md  != NULL);
+    LTC_ARGCHK(out != NULL);
+
+    if (md->rmd320.curlen >= sizeof(md->rmd320.buf)) {
+       return CRYPT_INVALID_ARG;
+    }
+
+
+    /* increase the length of the message */
+    md->rmd320.length += md->rmd320.curlen * 8;
+
+    /* append the '1' bit */
+    md->rmd320.buf[md->rmd320.curlen++] = (unsigned char)0x80;
+
+    /* if the length is currently above 56 bytes we append zeros
+     * then compress.  Then we can fall back to padding zeros and length
+     * encoding like normal.
+     */
+    if (md->rmd320.curlen > 56) {
+        while (md->rmd320.curlen < 64) {
+            md->rmd320.buf[md->rmd320.curlen++] = (unsigned char)0;
+        }
+        rmd320_compress(md, md->rmd320.buf);
+        md->rmd320.curlen = 0;
+    }
+
+    /* pad upto 56 bytes of zeroes */
+    while (md->rmd320.curlen < 56) {
+        md->rmd320.buf[md->rmd320.curlen++] = (unsigned char)0;
+    }
+
+    /* store length */
+    STORE64L(md->rmd320.length, md->rmd320.buf+56);
+    rmd320_compress(md, md->rmd320.buf);
+
+    /* copy output */
+    for (i = 0; i < 10; i++) {
+        STORE32L(md->rmd320.state[i], out+(4*i));
+    }
+#ifdef LTC_CLEAN_STACK
+    zeromem(md, sizeof(hash_state));
+#endif
+    return CRYPT_OK;
+}
+
+/**
+  Self-test the hash
+  @return CRYPT_OK if successful, CRYPT_NOP if self-tests have been disabled
+*/
+int rmd320_test(void)
+{
+#ifndef LTC_TEST
+   return CRYPT_NOP;
+#else
+   static const struct {
+        const char *msg;
+        unsigned char hash[40];
+   } tests[] = {
+   { "",
+     { 0x22, 0xd6, 0x5d, 0x56, 0x61, 0x53, 0x6c, 0xdc, 0x75, 0xc1,
+       0xfd, 0xf5, 0xc6, 0xde, 0x7b, 0x41, 0xb9, 0xf2, 0x73, 0x25,
+       0xeb, 0xc6, 0x1e, 0x85, 0x57, 0x17, 0x7d, 0x70, 0x5a, 0x0e,
+       0xc8, 0x80, 0x15, 0x1c, 0x3a, 0x32, 0xa0, 0x08, 0x99, 0xb8 }
+   },
+   { "a",
+     { 0xce, 0x78, 0x85, 0x06, 0x38, 0xf9, 0x26, 0x58, 0xa5, 0xa5,
+       0x85, 0x09, 0x75, 0x79, 0x92, 0x6d, 0xda, 0x66, 0x7a, 0x57,
+       0x16, 0x56, 0x2c, 0xfc, 0xf6, 0xfb, 0xe7, 0x7f, 0x63, 0x54,
+       0x2f, 0x99, 0xb0, 0x47, 0x05, 0xd6, 0x97, 0x0d, 0xff, 0x5d }
+   },
+   { "abc",
+     { 0xde, 0x4c, 0x01, 0xb3, 0x05, 0x4f, 0x89, 0x30, 0xa7, 0x9d,
+       0x09, 0xae, 0x73, 0x8e, 0x92, 0x30, 0x1e, 0x5a, 0x17, 0x08,
+       0x5b, 0xef, 0xfd, 0xc1, 0xb8, 0xd1, 0x16, 0x71, 0x3e, 0x74,
+       0xf8, 0x2f, 0xa9, 0x42, 0xd6, 0x4c, 0xdb, 0xc4, 0x68, 0x2d }
+   },
+   { "message digest",
+     { 0x3a, 0x8e, 0x28, 0x50, 0x2e, 0xd4, 0x5d, 0x42, 0x2f, 0x68,
+       0x84, 0x4f, 0x9d, 0xd3, 0x16, 0xe7, 0xb9, 0x85, 0x33, 0xfa,
+       0x3f, 0x2a, 0x91, 0xd2, 0x9f, 0x84, 0xd4, 0x25, 0xc8, 0x8d,
+       0x6b, 0x4e, 0xff, 0x72, 0x7d, 0xf6, 0x6a, 0x7c, 0x01, 0x97 }
+   },
+   { "abcdefghijklmnopqrstuvwxyz",
+     { 0xca, 0xbd, 0xb1, 0x81, 0x0b, 0x92, 0x47, 0x0a, 0x20, 0x93,
+       0xaa, 0x6b, 0xce, 0x05, 0x95, 0x2c, 0x28, 0x34, 0x8c, 0xf4,
+       0x3f, 0xf6, 0x08, 0x41, 0x97, 0x51, 0x66, 0xbb, 0x40, 0xed,
+       0x23, 0x40, 0x04, 0xb8, 0x82, 0x44, 0x63, 0xe6, 0xb0, 0x09 }
+   },
+   { "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
+     { 0xd0, 0x34, 0xa7, 0x95, 0x0c, 0xf7, 0x22, 0x02, 0x1b, 0xa4,
+       0xb8, 0x4d, 0xf7, 0x69, 0xa5, 0xde, 0x20, 0x60, 0xe2, 0x59,
+       0xdf, 0x4c, 0x9b, 0xb4, 0xa4, 0x26, 0x8c, 0x0e, 0x93, 0x5b,
+       0xbc, 0x74, 0x70, 0xa9, 0x69, 0xc9, 0xd0, 0x72, 0xa1, 0xac }
+   }
+   };
+
+   int i;
+   unsigned char tmp[40];
+   hash_state md;
+
+   for (i = 0; i < (int)(sizeof(tests)/sizeof(tests[0])); i++) {
+       rmd320_init(&md);
+       rmd320_process(&md, (unsigned char *)tests[i].msg, strlen(tests[i].msg));
+       rmd320_done(&md, tmp);
+       if (compare_testvector(tmp, sizeof(tmp), tests[i].hash, sizeof(tests[i].hash), "RIPEMD320", i)) {
+          return CRYPT_FAIL_TESTVECTOR;
+       }
+   }
+   return CRYPT_OK;
+#endif
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/hashes/sha1.c b/libtomcrypt/src/hashes/sha1.c
new file mode 100644 (file)
index 0000000..40f0175
--- /dev/null
@@ -0,0 +1,286 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file sha1.c
+  LTC_SHA1 code by Tom St Denis
+*/
+
+
+#ifdef LTC_SHA1
+
+const struct ltc_hash_descriptor sha1_desc =
+{
+    "sha1",
+    2,
+    20,
+    64,
+
+    /* OID */
+   { 1, 3, 14, 3, 2, 26,  },
+   6,
+
+    &sha1_init,
+    &sha1_process,
+    &sha1_done,
+    &sha1_test,
+    NULL
+};
+
+#define F0(x,y,z)  (z ^ (x & (y ^ z)))
+#define F1(x,y,z)  (x ^ y ^ z)
+#define F2(x,y,z)  ((x & y) | (z & (x | y)))
+#define F3(x,y,z)  (x ^ y ^ z)
+
+#ifdef LTC_CLEAN_STACK
+static int _sha1_compress(hash_state *md, unsigned char *buf)
+#else
+static int  sha1_compress(hash_state *md, unsigned char *buf)
+#endif
+{
+    ulong32 a,b,c,d,e,W[80],i;
+#ifdef LTC_SMALL_CODE
+    ulong32 t;
+#endif
+
+    /* copy the state into 512-bits into W[0..15] */
+    for (i = 0; i < 16; i++) {
+        LOAD32H(W[i], buf + (4*i));
+    }
+
+    /* copy state */
+    a = md->sha1.state[0];
+    b = md->sha1.state[1];
+    c = md->sha1.state[2];
+    d = md->sha1.state[3];
+    e = md->sha1.state[4];
+
+    /* expand it */
+    for (i = 16; i < 80; i++) {
+        W[i] = ROL(W[i-3] ^ W[i-8] ^ W[i-14] ^ W[i-16], 1);
+    }
+
+    /* compress */
+    /* round one */
+    #define FF0(a,b,c,d,e,i) e = (ROLc(a, 5) + F0(b,c,d) + e + W[i] + 0x5a827999UL); b = ROLc(b, 30);
+    #define FF1(a,b,c,d,e,i) e = (ROLc(a, 5) + F1(b,c,d) + e + W[i] + 0x6ed9eba1UL); b = ROLc(b, 30);
+    #define FF2(a,b,c,d,e,i) e = (ROLc(a, 5) + F2(b,c,d) + e + W[i] + 0x8f1bbcdcUL); b = ROLc(b, 30);
+    #define FF3(a,b,c,d,e,i) e = (ROLc(a, 5) + F3(b,c,d) + e + W[i] + 0xca62c1d6UL); b = ROLc(b, 30);
+
+#ifdef LTC_SMALL_CODE
+
+    for (i = 0; i < 20; ) {
+       FF0(a,b,c,d,e,i++); t = e; e = d; d = c; c = b; b = a; a = t;
+    }
+
+    for (; i < 40; ) {
+       FF1(a,b,c,d,e,i++); t = e; e = d; d = c; c = b; b = a; a = t;
+    }
+
+    for (; i < 60; ) {
+       FF2(a,b,c,d,e,i++); t = e; e = d; d = c; c = b; b = a; a = t;
+    }
+
+    for (; i < 80; ) {
+       FF3(a,b,c,d,e,i++); t = e; e = d; d = c; c = b; b = a; a = t;
+    }
+
+#else
+
+    for (i = 0; i < 20; ) {
+       FF0(a,b,c,d,e,i++);
+       FF0(e,a,b,c,d,i++);
+       FF0(d,e,a,b,c,i++);
+       FF0(c,d,e,a,b,i++);
+       FF0(b,c,d,e,a,i++);
+    }
+
+    /* round two */
+    for (; i < 40; )  {
+       FF1(a,b,c,d,e,i++);
+       FF1(e,a,b,c,d,i++);
+       FF1(d,e,a,b,c,i++);
+       FF1(c,d,e,a,b,i++);
+       FF1(b,c,d,e,a,i++);
+    }
+
+    /* round three */
+    for (; i < 60; )  {
+       FF2(a,b,c,d,e,i++);
+       FF2(e,a,b,c,d,i++);
+       FF2(d,e,a,b,c,i++);
+       FF2(c,d,e,a,b,i++);
+       FF2(b,c,d,e,a,i++);
+    }
+
+    /* round four */
+    for (; i < 80; )  {
+       FF3(a,b,c,d,e,i++);
+       FF3(e,a,b,c,d,i++);
+       FF3(d,e,a,b,c,i++);
+       FF3(c,d,e,a,b,i++);
+       FF3(b,c,d,e,a,i++);
+    }
+#endif
+
+    #undef FF0
+    #undef FF1
+    #undef FF2
+    #undef FF3
+
+    /* store */
+    md->sha1.state[0] = md->sha1.state[0] + a;
+    md->sha1.state[1] = md->sha1.state[1] + b;
+    md->sha1.state[2] = md->sha1.state[2] + c;
+    md->sha1.state[3] = md->sha1.state[3] + d;
+    md->sha1.state[4] = md->sha1.state[4] + e;
+
+    return CRYPT_OK;
+}
+
+#ifdef LTC_CLEAN_STACK
+static int sha1_compress(hash_state *md, unsigned char *buf)
+{
+   int err;
+   err = _sha1_compress(md, buf);
+   burn_stack(sizeof(ulong32) * 87);
+   return err;
+}
+#endif
+
+/**
+   Initialize the hash state
+   @param md   The hash state you wish to initialize
+   @return CRYPT_OK if successful
+*/
+int sha1_init(hash_state * md)
+{
+   LTC_ARGCHK(md != NULL);
+   md->sha1.state[0] = 0x67452301UL;
+   md->sha1.state[1] = 0xefcdab89UL;
+   md->sha1.state[2] = 0x98badcfeUL;
+   md->sha1.state[3] = 0x10325476UL;
+   md->sha1.state[4] = 0xc3d2e1f0UL;
+   md->sha1.curlen = 0;
+   md->sha1.length = 0;
+   return CRYPT_OK;
+}
+
+/**
+   Process a block of memory though the hash
+   @param md     The hash state
+   @param in     The data to hash
+   @param inlen  The length of the data (octets)
+   @return CRYPT_OK if successful
+*/
+HASH_PROCESS(sha1_process, sha1_compress, sha1, 64)
+
+/**
+   Terminate the hash to get the digest
+   @param md  The hash state
+   @param out [out] The destination of the hash (20 bytes)
+   @return CRYPT_OK if successful
+*/
+int sha1_done(hash_state * md, unsigned char *out)
+{
+    int i;
+
+    LTC_ARGCHK(md  != NULL);
+    LTC_ARGCHK(out != NULL);
+
+    if (md->sha1.curlen >= sizeof(md->sha1.buf)) {
+       return CRYPT_INVALID_ARG;
+    }
+
+    /* increase the length of the message */
+    md->sha1.length += md->sha1.curlen * 8;
+
+    /* append the '1' bit */
+    md->sha1.buf[md->sha1.curlen++] = (unsigned char)0x80;
+
+    /* if the length is currently above 56 bytes we append zeros
+     * then compress.  Then we can fall back to padding zeros and length
+     * encoding like normal.
+     */
+    if (md->sha1.curlen > 56) {
+        while (md->sha1.curlen < 64) {
+            md->sha1.buf[md->sha1.curlen++] = (unsigned char)0;
+        }
+        sha1_compress(md, md->sha1.buf);
+        md->sha1.curlen = 0;
+    }
+
+    /* pad upto 56 bytes of zeroes */
+    while (md->sha1.curlen < 56) {
+        md->sha1.buf[md->sha1.curlen++] = (unsigned char)0;
+    }
+
+    /* store length */
+    STORE64H(md->sha1.length, md->sha1.buf+56);
+    sha1_compress(md, md->sha1.buf);
+
+    /* copy output */
+    for (i = 0; i < 5; i++) {
+        STORE32H(md->sha1.state[i], out+(4*i));
+    }
+#ifdef LTC_CLEAN_STACK
+    zeromem(md, sizeof(hash_state));
+#endif
+    return CRYPT_OK;
+}
+
+/**
+  Self-test the hash
+  @return CRYPT_OK if successful, CRYPT_NOP if self-tests have been disabled
+*/
+int  sha1_test(void)
+{
+ #ifndef LTC_TEST
+    return CRYPT_NOP;
+ #else
+  static const struct {
+      const char *msg;
+      unsigned char hash[20];
+  } tests[] = {
+    { "abc",
+      { 0xa9, 0x99, 0x3e, 0x36, 0x47, 0x06, 0x81, 0x6a,
+        0xba, 0x3e, 0x25, 0x71, 0x78, 0x50, 0xc2, 0x6c,
+        0x9c, 0xd0, 0xd8, 0x9d }
+    },
+    { "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
+      { 0x84, 0x98, 0x3E, 0x44, 0x1C, 0x3B, 0xD2, 0x6E,
+        0xBA, 0xAE, 0x4A, 0xA1, 0xF9, 0x51, 0x29, 0xE5,
+        0xE5, 0x46, 0x70, 0xF1 }
+    }
+  };
+
+  int i;
+  unsigned char tmp[20];
+  hash_state md;
+
+  for (i = 0; i < (int)(sizeof(tests) / sizeof(tests[0]));  i++) {
+      sha1_init(&md);
+      sha1_process(&md, (unsigned char*)tests[i].msg, (unsigned long)strlen(tests[i].msg));
+      sha1_done(&md, tmp);
+      if (compare_testvector(tmp, sizeof(tmp), tests[i].hash, sizeof(tests[i].hash), "SHA1", i)) {
+         return CRYPT_FAIL_TESTVECTOR;
+      }
+  }
+  return CRYPT_OK;
+  #endif
+}
+
+#endif
+
+
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/hashes/sha2/sha224.c b/libtomcrypt/src/hashes/sha2/sha224.c
new file mode 100644 (file)
index 0000000..773a2c5
--- /dev/null
@@ -0,0 +1,129 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+/**
+   @param sha224.c
+   LTC_SHA-224 new NIST standard based off of LTC_SHA-256 truncated to 224 bits (Tom St Denis)
+*/
+
+#include "tomcrypt.h"
+
+#if defined(LTC_SHA224) && defined(LTC_SHA256)
+
+const struct ltc_hash_descriptor sha224_desc =
+{
+    "sha224",
+    10,
+    28,
+    64,
+
+    /* OID */
+   { 2, 16, 840, 1, 101, 3, 4, 2, 4,  },
+   9,
+
+    &sha224_init,
+    &sha256_process,
+    &sha224_done,
+    &sha224_test,
+    NULL
+};
+
+/* init the sha256 er... sha224 state ;-) */
+/**
+   Initialize the hash state
+   @param md   The hash state you wish to initialize
+   @return CRYPT_OK if successful
+*/
+int sha224_init(hash_state * md)
+{
+    LTC_ARGCHK(md != NULL);
+
+    md->sha256.curlen = 0;
+    md->sha256.length = 0;
+    md->sha256.state[0] = 0xc1059ed8UL;
+    md->sha256.state[1] = 0x367cd507UL;
+    md->sha256.state[2] = 0x3070dd17UL;
+    md->sha256.state[3] = 0xf70e5939UL;
+    md->sha256.state[4] = 0xffc00b31UL;
+    md->sha256.state[5] = 0x68581511UL;
+    md->sha256.state[6] = 0x64f98fa7UL;
+    md->sha256.state[7] = 0xbefa4fa4UL;
+    return CRYPT_OK;
+}
+
+/**
+   Terminate the hash to get the digest
+   @param md  The hash state
+   @param out [out] The destination of the hash (28 bytes)
+   @return CRYPT_OK if successful
+*/
+int sha224_done(hash_state * md, unsigned char *out)
+{
+    unsigned char buf[32];
+    int err;
+
+    LTC_ARGCHK(md  != NULL);
+    LTC_ARGCHK(out != NULL);
+
+    err = sha256_done(md, buf);
+    XMEMCPY(out, buf, 28);
+#ifdef LTC_CLEAN_STACK
+    zeromem(buf, sizeof(buf));
+#endif
+    return err;
+}
+
+/**
+  Self-test the hash
+  @return CRYPT_OK if successful, CRYPT_NOP if self-tests have been disabled
+*/
+int  sha224_test(void)
+{
+ #ifndef LTC_TEST
+    return CRYPT_NOP;
+ #else
+  static const struct {
+      const char *msg;
+      unsigned char hash[28];
+  } tests[] = {
+    { "abc",
+      { 0x23, 0x09, 0x7d, 0x22, 0x34, 0x05, 0xd8,
+        0x22, 0x86, 0x42, 0xa4, 0x77, 0xbd, 0xa2,
+        0x55, 0xb3, 0x2a, 0xad, 0xbc, 0xe4, 0xbd,
+        0xa0, 0xb3, 0xf7, 0xe3, 0x6c, 0x9d, 0xa7 }
+    },
+    { "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
+      { 0x75, 0x38, 0x8b, 0x16, 0x51, 0x27, 0x76,
+        0xcc, 0x5d, 0xba, 0x5d, 0xa1, 0xfd, 0x89,
+        0x01, 0x50, 0xb0, 0xc6, 0x45, 0x5c, 0xb4,
+        0xf5, 0x8b, 0x19, 0x52, 0x52, 0x25, 0x25 }
+    },
+  };
+
+  int i;
+  unsigned char tmp[28];
+  hash_state md;
+
+  for (i = 0; i < (int)(sizeof(tests) / sizeof(tests[0])); i++) {
+      sha224_init(&md);
+      sha224_process(&md, (unsigned char*)tests[i].msg, (unsigned long)strlen(tests[i].msg));
+      sha224_done(&md, tmp);
+      if (compare_testvector(tmp, sizeof(tmp), tests[i].hash, sizeof(tests[i].hash), "SHA224", i)) {
+         return CRYPT_FAIL_TESTVECTOR;
+      }
+  }
+  return CRYPT_OK;
+ #endif
+}
+
+#endif /* defined(LTC_SHA224) && defined(LTC_SHA256) */
+
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/hashes/sha2/sha256.c b/libtomcrypt/src/hashes/sha2/sha256.c
new file mode 100644 (file)
index 0000000..f1dc423
--- /dev/null
@@ -0,0 +1,334 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file sha256.c
+  LTC_SHA256 by Tom St Denis
+*/
+
+#ifdef LTC_SHA256
+
+const struct ltc_hash_descriptor sha256_desc =
+{
+    "sha256",
+    0,
+    32,
+    64,
+
+    /* OID */
+   { 2, 16, 840, 1, 101, 3, 4, 2, 1,  },
+   9,
+
+    &sha256_init,
+    &sha256_process,
+    &sha256_done,
+    &sha256_test,
+    NULL
+};
+
+#ifdef LTC_SMALL_CODE
+/* the K array */
+static const ulong32 K[64] = {
+    0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, 0x3956c25bUL,
+    0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, 0xd807aa98UL, 0x12835b01UL,
+    0x243185beUL, 0x550c7dc3UL, 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL,
+    0xc19bf174UL, 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL,
+    0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL, 0x983e5152UL,
+    0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, 0xc6e00bf3UL, 0xd5a79147UL,
+    0x06ca6351UL, 0x14292967UL, 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL,
+    0x53380d13UL, 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL,
+    0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL, 0xd192e819UL,
+    0xd6990624UL, 0xf40e3585UL, 0x106aa070UL, 0x19a4c116UL, 0x1e376c08UL,
+    0x2748774cUL, 0x34b0bcb5UL, 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL,
+    0x682e6ff3UL, 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL,
+    0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL
+};
+#endif
+
+/* Various logical functions */
+#define Ch(x,y,z)       (z ^ (x & (y ^ z)))
+#define Maj(x,y,z)      (((x | y) & z) | (x & y))
+#define S(x, n)         RORc((x),(n))
+#define R(x, n)         (((x)&0xFFFFFFFFUL)>>(n))
+#define Sigma0(x)       (S(x, 2) ^ S(x, 13) ^ S(x, 22))
+#define Sigma1(x)       (S(x, 6) ^ S(x, 11) ^ S(x, 25))
+#define Gamma0(x)       (S(x, 7) ^ S(x, 18) ^ R(x, 3))
+#define Gamma1(x)       (S(x, 17) ^ S(x, 19) ^ R(x, 10))
+
+/* compress 512-bits */
+#ifdef LTC_CLEAN_STACK
+static int _sha256_compress(hash_state * md, unsigned char *buf)
+#else
+static int  sha256_compress(hash_state * md, unsigned char *buf)
+#endif
+{
+    ulong32 S[8], W[64], t0, t1;
+#ifdef LTC_SMALL_CODE
+    ulong32 t;
+#endif
+    int i;
+
+    /* copy state into S */
+    for (i = 0; i < 8; i++) {
+        S[i] = md->sha256.state[i];
+    }
+
+    /* copy the state into 512-bits into W[0..15] */
+    for (i = 0; i < 16; i++) {
+        LOAD32H(W[i], buf + (4*i));
+    }
+
+    /* fill W[16..63] */
+    for (i = 16; i < 64; i++) {
+        W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) + W[i - 16];
+    }
+
+    /* Compress */
+#ifdef LTC_SMALL_CODE
+#define RND(a,b,c,d,e,f,g,h,i)                         \
+     t0 = h + Sigma1(e) + Ch(e, f, g) + K[i] + W[i];   \
+     t1 = Sigma0(a) + Maj(a, b, c);                    \
+     d += t0;                                          \
+     h  = t0 + t1;
+
+     for (i = 0; i < 64; ++i) {
+         RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],i);
+         t = S[7]; S[7] = S[6]; S[6] = S[5]; S[5] = S[4];
+         S[4] = S[3]; S[3] = S[2]; S[2] = S[1]; S[1] = S[0]; S[0] = t;
+     }
+#else
+#define RND(a,b,c,d,e,f,g,h,i,ki)                    \
+     t0 = h + Sigma1(e) + Ch(e, f, g) + ki + W[i];   \
+     t1 = Sigma0(a) + Maj(a, b, c);                  \
+     d += t0;                                        \
+     h  = t0 + t1;
+
+    RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],0,0x428a2f98);
+    RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],1,0x71374491);
+    RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],2,0xb5c0fbcf);
+    RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],3,0xe9b5dba5);
+    RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],4,0x3956c25b);
+    RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],5,0x59f111f1);
+    RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],6,0x923f82a4);
+    RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],7,0xab1c5ed5);
+    RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],8,0xd807aa98);
+    RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],9,0x12835b01);
+    RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],10,0x243185be);
+    RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],11,0x550c7dc3);
+    RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],12,0x72be5d74);
+    RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],13,0x80deb1fe);
+    RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],14,0x9bdc06a7);
+    RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],15,0xc19bf174);
+    RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],16,0xe49b69c1);
+    RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],17,0xefbe4786);
+    RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],18,0x0fc19dc6);
+    RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],19,0x240ca1cc);
+    RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],20,0x2de92c6f);
+    RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],21,0x4a7484aa);
+    RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],22,0x5cb0a9dc);
+    RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],23,0x76f988da);
+    RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],24,0x983e5152);
+    RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],25,0xa831c66d);
+    RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],26,0xb00327c8);
+    RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],27,0xbf597fc7);
+    RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],28,0xc6e00bf3);
+    RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],29,0xd5a79147);
+    RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],30,0x06ca6351);
+    RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],31,0x14292967);
+    RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],32,0x27b70a85);
+    RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],33,0x2e1b2138);
+    RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],34,0x4d2c6dfc);
+    RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],35,0x53380d13);
+    RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],36,0x650a7354);
+    RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],37,0x766a0abb);
+    RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],38,0x81c2c92e);
+    RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],39,0x92722c85);
+    RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],40,0xa2bfe8a1);
+    RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],41,0xa81a664b);
+    RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],42,0xc24b8b70);
+    RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],43,0xc76c51a3);
+    RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],44,0xd192e819);
+    RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],45,0xd6990624);
+    RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],46,0xf40e3585);
+    RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],47,0x106aa070);
+    RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],48,0x19a4c116);
+    RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],49,0x1e376c08);
+    RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],50,0x2748774c);
+    RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],51,0x34b0bcb5);
+    RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],52,0x391c0cb3);
+    RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],53,0x4ed8aa4a);
+    RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],54,0x5b9cca4f);
+    RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],55,0x682e6ff3);
+    RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],56,0x748f82ee);
+    RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],57,0x78a5636f);
+    RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],58,0x84c87814);
+    RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],59,0x8cc70208);
+    RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],60,0x90befffa);
+    RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],61,0xa4506ceb);
+    RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],62,0xbef9a3f7);
+    RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],63,0xc67178f2);
+
+#undef RND
+
+#endif
+
+    /* feedback */
+    for (i = 0; i < 8; i++) {
+        md->sha256.state[i] = md->sha256.state[i] + S[i];
+    }
+    return CRYPT_OK;
+}
+
+#ifdef LTC_CLEAN_STACK
+static int sha256_compress(hash_state * md, unsigned char *buf)
+{
+    int err;
+    err = _sha256_compress(md, buf);
+    burn_stack(sizeof(ulong32) * 74);
+    return err;
+}
+#endif
+
+/**
+   Initialize the hash state
+   @param md   The hash state you wish to initialize
+   @return CRYPT_OK if successful
+*/
+int sha256_init(hash_state * md)
+{
+    LTC_ARGCHK(md != NULL);
+
+    md->sha256.curlen = 0;
+    md->sha256.length = 0;
+    md->sha256.state[0] = 0x6A09E667UL;
+    md->sha256.state[1] = 0xBB67AE85UL;
+    md->sha256.state[2] = 0x3C6EF372UL;
+    md->sha256.state[3] = 0xA54FF53AUL;
+    md->sha256.state[4] = 0x510E527FUL;
+    md->sha256.state[5] = 0x9B05688CUL;
+    md->sha256.state[6] = 0x1F83D9ABUL;
+    md->sha256.state[7] = 0x5BE0CD19UL;
+    return CRYPT_OK;
+}
+
+/**
+   Process a block of memory though the hash
+   @param md     The hash state
+   @param in     The data to hash
+   @param inlen  The length of the data (octets)
+   @return CRYPT_OK if successful
+*/
+HASH_PROCESS(sha256_process, sha256_compress, sha256, 64)
+
+/**
+   Terminate the hash to get the digest
+   @param md  The hash state
+   @param out [out] The destination of the hash (32 bytes)
+   @return CRYPT_OK if successful
+*/
+int sha256_done(hash_state * md, unsigned char *out)
+{
+    int i;
+
+    LTC_ARGCHK(md  != NULL);
+    LTC_ARGCHK(out != NULL);
+
+    if (md->sha256.curlen >= sizeof(md->sha256.buf)) {
+       return CRYPT_INVALID_ARG;
+    }
+
+
+    /* increase the length of the message */
+    md->sha256.length += md->sha256.curlen * 8;
+
+    /* append the '1' bit */
+    md->sha256.buf[md->sha256.curlen++] = (unsigned char)0x80;
+
+    /* if the length is currently above 56 bytes we append zeros
+     * then compress.  Then we can fall back to padding zeros and length
+     * encoding like normal.
+     */
+    if (md->sha256.curlen > 56) {
+        while (md->sha256.curlen < 64) {
+            md->sha256.buf[md->sha256.curlen++] = (unsigned char)0;
+        }
+        sha256_compress(md, md->sha256.buf);
+        md->sha256.curlen = 0;
+    }
+
+    /* pad upto 56 bytes of zeroes */
+    while (md->sha256.curlen < 56) {
+        md->sha256.buf[md->sha256.curlen++] = (unsigned char)0;
+    }
+
+    /* store length */
+    STORE64H(md->sha256.length, md->sha256.buf+56);
+    sha256_compress(md, md->sha256.buf);
+
+    /* copy output */
+    for (i = 0; i < 8; i++) {
+        STORE32H(md->sha256.state[i], out+(4*i));
+    }
+#ifdef LTC_CLEAN_STACK
+    zeromem(md, sizeof(hash_state));
+#endif
+    return CRYPT_OK;
+}
+
+/**
+  Self-test the hash
+  @return CRYPT_OK if successful, CRYPT_NOP if self-tests have been disabled
+*/
+int  sha256_test(void)
+{
+ #ifndef LTC_TEST
+    return CRYPT_NOP;
+ #else
+  static const struct {
+      const char *msg;
+      unsigned char hash[32];
+  } tests[] = {
+    { "abc",
+      { 0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea,
+        0x41, 0x41, 0x40, 0xde, 0x5d, 0xae, 0x22, 0x23,
+        0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c,
+        0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad }
+    },
+    { "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
+      { 0x24, 0x8d, 0x6a, 0x61, 0xd2, 0x06, 0x38, 0xb8,
+        0xe5, 0xc0, 0x26, 0x93, 0x0c, 0x3e, 0x60, 0x39,
+        0xa3, 0x3c, 0xe4, 0x59, 0x64, 0xff, 0x21, 0x67,
+        0xf6, 0xec, 0xed, 0xd4, 0x19, 0xdb, 0x06, 0xc1 }
+    },
+  };
+
+  int i;
+  unsigned char tmp[32];
+  hash_state md;
+
+  for (i = 0; i < (int)(sizeof(tests) / sizeof(tests[0])); i++) {
+      sha256_init(&md);
+      sha256_process(&md, (unsigned char*)tests[i].msg, (unsigned long)strlen(tests[i].msg));
+      sha256_done(&md, tmp);
+      if (compare_testvector(tmp, sizeof(tmp), tests[i].hash, sizeof(tests[i].hash), "SHA256", i)) {
+         return CRYPT_FAIL_TESTVECTOR;
+      }
+  }
+  return CRYPT_OK;
+ #endif
+}
+
+#endif
+
+
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/hashes/sha2/sha384.c b/libtomcrypt/src/hashes/sha2/sha384.c
new file mode 100644 (file)
index 0000000..1623812
--- /dev/null
@@ -0,0 +1,134 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+/**
+   @param sha384.c
+   LTC_SHA384 hash included in sha512.c, Tom St Denis
+*/
+
+#include "tomcrypt.h"
+
+#if defined(LTC_SHA384) && defined(LTC_SHA512)
+
+const struct ltc_hash_descriptor sha384_desc =
+{
+    "sha384",
+    4,
+    48,
+    128,
+
+    /* OID */
+   { 2, 16, 840, 1, 101, 3, 4, 2, 2,  },
+   9,
+
+    &sha384_init,
+    &sha512_process,
+    &sha384_done,
+    &sha384_test,
+    NULL
+};
+
+/**
+   Initialize the hash state
+   @param md   The hash state you wish to initialize
+   @return CRYPT_OK if successful
+*/
+int sha384_init(hash_state * md)
+{
+    LTC_ARGCHK(md != NULL);
+
+    md->sha512.curlen = 0;
+    md->sha512.length = 0;
+    md->sha512.state[0] = CONST64(0xcbbb9d5dc1059ed8);
+    md->sha512.state[1] = CONST64(0x629a292a367cd507);
+    md->sha512.state[2] = CONST64(0x9159015a3070dd17);
+    md->sha512.state[3] = CONST64(0x152fecd8f70e5939);
+    md->sha512.state[4] = CONST64(0x67332667ffc00b31);
+    md->sha512.state[5] = CONST64(0x8eb44a8768581511);
+    md->sha512.state[6] = CONST64(0xdb0c2e0d64f98fa7);
+    md->sha512.state[7] = CONST64(0x47b5481dbefa4fa4);
+    return CRYPT_OK;
+}
+
+/**
+   Terminate the hash to get the digest
+   @param md  The hash state
+   @param out [out] The destination of the hash (48 bytes)
+   @return CRYPT_OK if successful
+*/
+int sha384_done(hash_state * md, unsigned char *out)
+{
+   unsigned char buf[64];
+
+   LTC_ARGCHK(md  != NULL);
+   LTC_ARGCHK(out != NULL);
+
+    if (md->sha512.curlen >= sizeof(md->sha512.buf)) {
+       return CRYPT_INVALID_ARG;
+    }
+
+   sha512_done(md, buf);
+   XMEMCPY(out, buf, 48);
+#ifdef LTC_CLEAN_STACK
+   zeromem(buf, sizeof(buf));
+#endif
+   return CRYPT_OK;
+}
+
+/**
+  Self-test the hash
+  @return CRYPT_OK if successful, CRYPT_NOP if self-tests have been disabled
+*/
+int  sha384_test(void)
+{
+ #ifndef LTC_TEST
+    return CRYPT_NOP;
+ #else
+  static const struct {
+      const char *msg;
+      unsigned char hash[48];
+  } tests[] = {
+    { "abc",
+      { 0xcb, 0x00, 0x75, 0x3f, 0x45, 0xa3, 0x5e, 0x8b,
+        0xb5, 0xa0, 0x3d, 0x69, 0x9a, 0xc6, 0x50, 0x07,
+        0x27, 0x2c, 0x32, 0xab, 0x0e, 0xde, 0xd1, 0x63,
+        0x1a, 0x8b, 0x60, 0x5a, 0x43, 0xff, 0x5b, 0xed,
+        0x80, 0x86, 0x07, 0x2b, 0xa1, 0xe7, 0xcc, 0x23,
+        0x58, 0xba, 0xec, 0xa1, 0x34, 0xc8, 0x25, 0xa7 }
+    },
+    { "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu",
+      { 0x09, 0x33, 0x0c, 0x33, 0xf7, 0x11, 0x47, 0xe8,
+        0x3d, 0x19, 0x2f, 0xc7, 0x82, 0xcd, 0x1b, 0x47,
+        0x53, 0x11, 0x1b, 0x17, 0x3b, 0x3b, 0x05, 0xd2,
+        0x2f, 0xa0, 0x80, 0x86, 0xe3, 0xb0, 0xf7, 0x12,
+        0xfc, 0xc7, 0xc7, 0x1a, 0x55, 0x7e, 0x2d, 0xb9,
+        0x66, 0xc3, 0xe9, 0xfa, 0x91, 0x74, 0x60, 0x39 }
+    },
+  };
+
+  int i;
+  unsigned char tmp[48];
+  hash_state md;
+
+  for (i = 0; i < (int)(sizeof(tests) / sizeof(tests[0])); i++) {
+      sha384_init(&md);
+      sha384_process(&md, (unsigned char*)tests[i].msg, (unsigned long)strlen(tests[i].msg));
+      sha384_done(&md, tmp);
+      if (compare_testvector(tmp, sizeof(tmp), tests[i].hash, sizeof(tests[i].hash), "SHA384", i)) {
+         return CRYPT_FAIL_TESTVECTOR;
+      }
+  }
+  return CRYPT_OK;
+ #endif
+}
+
+#endif /* defined(LTC_SHA384) && defined(LTC_SHA512) */
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/hashes/sha2/sha512.c b/libtomcrypt/src/hashes/sha2/sha512.c
new file mode 100644 (file)
index 0000000..110203a
--- /dev/null
@@ -0,0 +1,313 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+   @param sha512.c
+   LTC_SHA512 by Tom St Denis
+*/
+
+#ifdef LTC_SHA512
+
+const struct ltc_hash_descriptor sha512_desc =
+{
+    "sha512",
+    5,
+    64,
+    128,
+
+    /* OID */
+   { 2, 16, 840, 1, 101, 3, 4, 2, 3,  },
+   9,
+
+    &sha512_init,
+    &sha512_process,
+    &sha512_done,
+    &sha512_test,
+    NULL
+};
+
+/* the K array */
+static const ulong64 K[80] = {
+CONST64(0x428a2f98d728ae22), CONST64(0x7137449123ef65cd),
+CONST64(0xb5c0fbcfec4d3b2f), CONST64(0xe9b5dba58189dbbc),
+CONST64(0x3956c25bf348b538), CONST64(0x59f111f1b605d019),
+CONST64(0x923f82a4af194f9b), CONST64(0xab1c5ed5da6d8118),
+CONST64(0xd807aa98a3030242), CONST64(0x12835b0145706fbe),
+CONST64(0x243185be4ee4b28c), CONST64(0x550c7dc3d5ffb4e2),
+CONST64(0x72be5d74f27b896f), CONST64(0x80deb1fe3b1696b1),
+CONST64(0x9bdc06a725c71235), CONST64(0xc19bf174cf692694),
+CONST64(0xe49b69c19ef14ad2), CONST64(0xefbe4786384f25e3),
+CONST64(0x0fc19dc68b8cd5b5), CONST64(0x240ca1cc77ac9c65),
+CONST64(0x2de92c6f592b0275), CONST64(0x4a7484aa6ea6e483),
+CONST64(0x5cb0a9dcbd41fbd4), CONST64(0x76f988da831153b5),
+CONST64(0x983e5152ee66dfab), CONST64(0xa831c66d2db43210),
+CONST64(0xb00327c898fb213f), CONST64(0xbf597fc7beef0ee4),
+CONST64(0xc6e00bf33da88fc2), CONST64(0xd5a79147930aa725),
+CONST64(0x06ca6351e003826f), CONST64(0x142929670a0e6e70),
+CONST64(0x27b70a8546d22ffc), CONST64(0x2e1b21385c26c926),
+CONST64(0x4d2c6dfc5ac42aed), CONST64(0x53380d139d95b3df),
+CONST64(0x650a73548baf63de), CONST64(0x766a0abb3c77b2a8),
+CONST64(0x81c2c92e47edaee6), CONST64(0x92722c851482353b),
+CONST64(0xa2bfe8a14cf10364), CONST64(0xa81a664bbc423001),
+CONST64(0xc24b8b70d0f89791), CONST64(0xc76c51a30654be30),
+CONST64(0xd192e819d6ef5218), CONST64(0xd69906245565a910),
+CONST64(0xf40e35855771202a), CONST64(0x106aa07032bbd1b8),
+CONST64(0x19a4c116b8d2d0c8), CONST64(0x1e376c085141ab53),
+CONST64(0x2748774cdf8eeb99), CONST64(0x34b0bcb5e19b48a8),
+CONST64(0x391c0cb3c5c95a63), CONST64(0x4ed8aa4ae3418acb),
+CONST64(0x5b9cca4f7763e373), CONST64(0x682e6ff3d6b2b8a3),
+CONST64(0x748f82ee5defb2fc), CONST64(0x78a5636f43172f60),
+CONST64(0x84c87814a1f0ab72), CONST64(0x8cc702081a6439ec),
+CONST64(0x90befffa23631e28), CONST64(0xa4506cebde82bde9),
+CONST64(0xbef9a3f7b2c67915), CONST64(0xc67178f2e372532b),
+CONST64(0xca273eceea26619c), CONST64(0xd186b8c721c0c207),
+CONST64(0xeada7dd6cde0eb1e), CONST64(0xf57d4f7fee6ed178),
+CONST64(0x06f067aa72176fba), CONST64(0x0a637dc5a2c898a6),
+CONST64(0x113f9804bef90dae), CONST64(0x1b710b35131c471b),
+CONST64(0x28db77f523047d84), CONST64(0x32caab7b40c72493),
+CONST64(0x3c9ebe0a15c9bebc), CONST64(0x431d67c49c100d4c),
+CONST64(0x4cc5d4becb3e42b6), CONST64(0x597f299cfc657e2a),
+CONST64(0x5fcb6fab3ad6faec), CONST64(0x6c44198c4a475817)
+};
+
+/* Various logical functions */
+#define Ch(x,y,z)       (z ^ (x & (y ^ z)))
+#define Maj(x,y,z)      (((x | y) & z) | (x & y))
+#define S(x, n)         ROR64c(x, n)
+#define R(x, n)         (((x)&CONST64(0xFFFFFFFFFFFFFFFF))>>((ulong64)n))
+#define Sigma0(x)       (S(x, 28) ^ S(x, 34) ^ S(x, 39))
+#define Sigma1(x)       (S(x, 14) ^ S(x, 18) ^ S(x, 41))
+#define Gamma0(x)       (S(x, 1) ^ S(x, 8) ^ R(x, 7))
+#define Gamma1(x)       (S(x, 19) ^ S(x, 61) ^ R(x, 6))
+
+/* compress 1024-bits */
+#ifdef LTC_CLEAN_STACK
+static int _sha512_compress(hash_state * md, unsigned char *buf)
+#else
+static int  sha512_compress(hash_state * md, unsigned char *buf)
+#endif
+{
+    ulong64 S[8], W[80], t0, t1;
+    int i;
+
+    /* copy state into S */
+    for (i = 0; i < 8; i++) {
+        S[i] = md->sha512.state[i];
+    }
+
+    /* copy the state into 1024-bits into W[0..15] */
+    for (i = 0; i < 16; i++) {
+        LOAD64H(W[i], buf + (8*i));
+    }
+
+    /* fill W[16..79] */
+    for (i = 16; i < 80; i++) {
+        W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) + W[i - 16];
+    }
+
+    /* Compress */
+#ifdef LTC_SMALL_CODE
+    for (i = 0; i < 80; i++) {
+        t0 = S[7] + Sigma1(S[4]) + Ch(S[4], S[5], S[6]) + K[i] + W[i];
+        t1 = Sigma0(S[0]) + Maj(S[0], S[1], S[2]);
+        S[7] = S[6];
+        S[6] = S[5];
+        S[5] = S[4];
+        S[4] = S[3] + t0;
+        S[3] = S[2];
+        S[2] = S[1];
+        S[1] = S[0];
+        S[0] = t0 + t1;
+    }
+#else
+#define RND(a,b,c,d,e,f,g,h,i)                    \
+     t0 = h + Sigma1(e) + Ch(e, f, g) + K[i] + W[i];   \
+     t1 = Sigma0(a) + Maj(a, b, c);                  \
+     d += t0;                                        \
+     h  = t0 + t1;
+
+    for (i = 0; i < 80; i += 8) {
+        RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],i+0);
+        RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],i+1);
+        RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],i+2);
+        RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],i+3);
+        RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],i+4);
+        RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],i+5);
+        RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],i+6);
+        RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],i+7);
+    }
+#endif
+
+
+    /* feedback */
+    for (i = 0; i < 8; i++) {
+        md->sha512.state[i] = md->sha512.state[i] + S[i];
+    }
+
+    return CRYPT_OK;
+}
+
+/* compress 1024-bits */
+#ifdef LTC_CLEAN_STACK
+static int sha512_compress(hash_state * md, unsigned char *buf)
+{
+    int err;
+    err = _sha512_compress(md, buf);
+    burn_stack(sizeof(ulong64) * 90 + sizeof(int));
+    return err;
+}
+#endif
+
+/**
+   Initialize the hash state
+   @param md   The hash state you wish to initialize
+   @return CRYPT_OK if successful
+*/
+int sha512_init(hash_state * md)
+{
+    LTC_ARGCHK(md != NULL);
+    md->sha512.curlen = 0;
+    md->sha512.length = 0;
+    md->sha512.state[0] = CONST64(0x6a09e667f3bcc908);
+    md->sha512.state[1] = CONST64(0xbb67ae8584caa73b);
+    md->sha512.state[2] = CONST64(0x3c6ef372fe94f82b);
+    md->sha512.state[3] = CONST64(0xa54ff53a5f1d36f1);
+    md->sha512.state[4] = CONST64(0x510e527fade682d1);
+    md->sha512.state[5] = CONST64(0x9b05688c2b3e6c1f);
+    md->sha512.state[6] = CONST64(0x1f83d9abfb41bd6b);
+    md->sha512.state[7] = CONST64(0x5be0cd19137e2179);
+    return CRYPT_OK;
+}
+
+/**
+   Process a block of memory though the hash
+   @param md     The hash state
+   @param in     The data to hash
+   @param inlen  The length of the data (octets)
+   @return CRYPT_OK if successful
+*/
+HASH_PROCESS(sha512_process, sha512_compress, sha512, 128)
+
+/**
+   Terminate the hash to get the digest
+   @param md  The hash state
+   @param out [out] The destination of the hash (64 bytes)
+   @return CRYPT_OK if successful
+*/
+int sha512_done(hash_state * md, unsigned char *out)
+{
+    int i;
+
+    LTC_ARGCHK(md  != NULL);
+    LTC_ARGCHK(out != NULL);
+
+    if (md->sha512.curlen >= sizeof(md->sha512.buf)) {
+       return CRYPT_INVALID_ARG;
+    }
+
+    /* increase the length of the message */
+    md->sha512.length += md->sha512.curlen * CONST64(8);
+
+    /* append the '1' bit */
+    md->sha512.buf[md->sha512.curlen++] = (unsigned char)0x80;
+
+    /* if the length is currently above 112 bytes we append zeros
+     * then compress.  Then we can fall back to padding zeros and length
+     * encoding like normal.
+     */
+    if (md->sha512.curlen > 112) {
+        while (md->sha512.curlen < 128) {
+            md->sha512.buf[md->sha512.curlen++] = (unsigned char)0;
+        }
+        sha512_compress(md, md->sha512.buf);
+        md->sha512.curlen = 0;
+    }
+
+    /* pad upto 120 bytes of zeroes
+     * note: that from 112 to 120 is the 64 MSB of the length.  We assume that you won't hash
+     * > 2^64 bits of data... :-)
+     */
+    while (md->sha512.curlen < 120) {
+        md->sha512.buf[md->sha512.curlen++] = (unsigned char)0;
+    }
+
+    /* store length */
+    STORE64H(md->sha512.length, md->sha512.buf+120);
+    sha512_compress(md, md->sha512.buf);
+
+    /* copy output */
+    for (i = 0; i < 8; i++) {
+        STORE64H(md->sha512.state[i], out+(8*i));
+    }
+#ifdef LTC_CLEAN_STACK
+    zeromem(md, sizeof(hash_state));
+#endif
+    return CRYPT_OK;
+}
+
+/**
+  Self-test the hash
+  @return CRYPT_OK if successful, CRYPT_NOP if self-tests have been disabled
+*/
+int  sha512_test(void)
+{
+ #ifndef LTC_TEST
+    return CRYPT_NOP;
+ #else
+  static const struct {
+      const char *msg;
+      unsigned char hash[64];
+  } tests[] = {
+    { "abc",
+     { 0xdd, 0xaf, 0x35, 0xa1, 0x93, 0x61, 0x7a, 0xba,
+       0xcc, 0x41, 0x73, 0x49, 0xae, 0x20, 0x41, 0x31,
+       0x12, 0xe6, 0xfa, 0x4e, 0x89, 0xa9, 0x7e, 0xa2,
+       0x0a, 0x9e, 0xee, 0xe6, 0x4b, 0x55, 0xd3, 0x9a,
+       0x21, 0x92, 0x99, 0x2a, 0x27, 0x4f, 0xc1, 0xa8,
+       0x36, 0xba, 0x3c, 0x23, 0xa3, 0xfe, 0xeb, 0xbd,
+       0x45, 0x4d, 0x44, 0x23, 0x64, 0x3c, 0xe8, 0x0e,
+       0x2a, 0x9a, 0xc9, 0x4f, 0xa5, 0x4c, 0xa4, 0x9f }
+    },
+    { "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu",
+     { 0x8e, 0x95, 0x9b, 0x75, 0xda, 0xe3, 0x13, 0xda,
+       0x8c, 0xf4, 0xf7, 0x28, 0x14, 0xfc, 0x14, 0x3f,
+       0x8f, 0x77, 0x79, 0xc6, 0xeb, 0x9f, 0x7f, 0xa1,
+       0x72, 0x99, 0xae, 0xad, 0xb6, 0x88, 0x90, 0x18,
+       0x50, 0x1d, 0x28, 0x9e, 0x49, 0x00, 0xf7, 0xe4,
+       0x33, 0x1b, 0x99, 0xde, 0xc4, 0xb5, 0x43, 0x3a,
+       0xc7, 0xd3, 0x29, 0xee, 0xb6, 0xdd, 0x26, 0x54,
+       0x5e, 0x96, 0xe5, 0x5b, 0x87, 0x4b, 0xe9, 0x09 }
+    },
+  };
+
+  int i;
+  unsigned char tmp[64];
+  hash_state md;
+
+  for (i = 0; i < (int)(sizeof(tests) / sizeof(tests[0])); i++) {
+      sha512_init(&md);
+      sha512_process(&md, (unsigned char *)tests[i].msg, (unsigned long)strlen(tests[i].msg));
+      sha512_done(&md, tmp);
+      if (compare_testvector(tmp, sizeof(tmp), tests[i].hash, sizeof(tests[i].hash), "SHA512", i)) {
+         return CRYPT_FAIL_TESTVECTOR;
+      }
+  }
+  return CRYPT_OK;
+  #endif
+}
+
+#endif
+
+
+
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/hashes/sha2/sha512_224.c b/libtomcrypt/src/hashes/sha2/sha512_224.c
new file mode 100644 (file)
index 0000000..48bb938
--- /dev/null
@@ -0,0 +1,130 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+/**
+   @param sha512_224.c
+   SHA512/224 hash included in sha512.c
+*/
+
+#include "tomcrypt.h"
+
+#if defined(LTC_SHA512_224) && defined(LTC_SHA512)
+
+const struct ltc_hash_descriptor sha512_224_desc =
+{
+    "sha512-224",
+    15,
+    28,
+    128,
+
+    /* OID */
+   { 2, 16, 840, 1, 101, 3, 4, 2, 5,  },
+   9,
+
+    &sha512_224_init,
+    &sha512_process,
+    &sha512_224_done,
+    &sha512_224_test,
+    NULL
+};
+
+/**
+   Initialize the hash state
+   @param md   The hash state you wish to initialize
+   @return CRYPT_OK if successful
+*/
+int sha512_224_init(hash_state * md)
+{
+    LTC_ARGCHK(md != NULL);
+
+    md->sha512.curlen = 0;
+    md->sha512.length = 0;
+    md->sha512.state[0] = CONST64(0x8C3D37C819544DA2);
+    md->sha512.state[1] = CONST64(0x73E1996689DCD4D6);
+    md->sha512.state[2] = CONST64(0x1DFAB7AE32FF9C82);
+    md->sha512.state[3] = CONST64(0x679DD514582F9FCF);
+    md->sha512.state[4] = CONST64(0x0F6D2B697BD44DA8);
+    md->sha512.state[5] = CONST64(0x77E36F7304C48942);
+    md->sha512.state[6] = CONST64(0x3F9D85A86A1D36C8);
+    md->sha512.state[7] = CONST64(0x1112E6AD91D692A1);
+    return CRYPT_OK;
+}
+
+/**
+   Terminate the hash to get the digest
+   @param md  The hash state
+   @param out [out] The destination of the hash (48 bytes)
+   @return CRYPT_OK if successful
+*/
+int sha512_224_done(hash_state * md, unsigned char *out)
+{
+   unsigned char buf[64];
+
+   LTC_ARGCHK(md  != NULL);
+   LTC_ARGCHK(out != NULL);
+
+    if (md->sha512.curlen >= sizeof(md->sha512.buf)) {
+       return CRYPT_INVALID_ARG;
+    }
+
+   sha512_done(md, buf);
+   XMEMCPY(out, buf, 28);
+#ifdef LTC_CLEAN_STACK
+   zeromem(buf, sizeof(buf));
+#endif
+   return CRYPT_OK;
+}
+
+/**
+  Self-test the hash
+  @return CRYPT_OK if successful, CRYPT_NOP if self-tests have been disabled
+*/
+int  sha512_224_test(void)
+{
+ #ifndef LTC_TEST
+    return CRYPT_NOP;
+ #else
+  static const struct {
+      const char *msg;
+      unsigned char hash[28];
+  } tests[] = {
+    { "abc",
+      { 0x46, 0x34, 0x27, 0x0F, 0x70, 0x7B, 0x6A, 0x54,
+        0xDA, 0xAE, 0x75, 0x30, 0x46, 0x08, 0x42, 0xE2,
+        0x0E, 0x37, 0xED, 0x26, 0x5C, 0xEE, 0xE9, 0xA4,
+        0x3E, 0x89, 0x24, 0xAA }
+    },
+    { "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu",
+      { 0x23, 0xFE, 0xC5, 0xBB, 0x94, 0xD6, 0x0B, 0x23,
+        0x30, 0x81, 0x92, 0x64, 0x0B, 0x0C, 0x45, 0x33,
+        0x35, 0xD6, 0x64, 0x73, 0x4F, 0xE4, 0x0E, 0x72,
+        0x68, 0x67, 0x4A, 0xF9 }
+    },
+  };
+
+  int i;
+  unsigned char tmp[28];
+  hash_state md;
+
+  for (i = 0; i < (int)(sizeof(tests) / sizeof(tests[0])); i++) {
+      sha512_224_init(&md);
+      sha512_224_process(&md, (unsigned char*)tests[i].msg, (unsigned long)strlen(tests[i].msg));
+      sha512_224_done(&md, tmp);
+      if (compare_testvector(tmp, sizeof(tmp), tests[i].hash, sizeof(tests[i].hash), "SHA512-224", i)) {
+         return CRYPT_FAIL_TESTVECTOR;
+      }
+  }
+  return CRYPT_OK;
+ #endif
+}
+
+#endif /* defined(LTC_SHA384) && defined(LTC_SHA512) */
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/hashes/sha2/sha512_256.c b/libtomcrypt/src/hashes/sha2/sha512_256.c
new file mode 100644 (file)
index 0000000..943adaa
--- /dev/null
@@ -0,0 +1,130 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+/**
+   @param sha512_256.c
+   SHA512/256 hash included in sha512.c
+*/
+
+#include "tomcrypt.h"
+
+#if defined(LTC_SHA512_256) && defined(LTC_SHA512)
+
+const struct ltc_hash_descriptor sha512_256_desc =
+{
+    "sha512-256",
+    16,
+    32,
+    128,
+
+    /* OID */
+   { 2, 16, 840, 1, 101, 3, 4, 2, 6,  },
+   9,
+
+    &sha512_256_init,
+    &sha512_process,
+    &sha512_256_done,
+    &sha512_256_test,
+    NULL
+};
+
+/**
+   Initialize the hash state
+   @param md   The hash state you wish to initialize
+   @return CRYPT_OK if successful
+*/
+int sha512_256_init(hash_state * md)
+{
+    LTC_ARGCHK(md != NULL);
+
+    md->sha512.curlen = 0;
+    md->sha512.length = 0;
+    md->sha512.state[0] = CONST64(0x22312194FC2BF72C);
+    md->sha512.state[1] = CONST64(0x9F555FA3C84C64C2);
+    md->sha512.state[2] = CONST64(0x2393B86B6F53B151);
+    md->sha512.state[3] = CONST64(0x963877195940EABD);
+    md->sha512.state[4] = CONST64(0x96283EE2A88EFFE3);
+    md->sha512.state[5] = CONST64(0xBE5E1E2553863992);
+    md->sha512.state[6] = CONST64(0x2B0199FC2C85B8AA);
+    md->sha512.state[7] = CONST64(0x0EB72DDC81C52CA2);
+    return CRYPT_OK;
+}
+
+/**
+   Terminate the hash to get the digest
+   @param md  The hash state
+   @param out [out] The destination of the hash (48 bytes)
+   @return CRYPT_OK if successful
+*/
+int sha512_256_done(hash_state * md, unsigned char *out)
+{
+   unsigned char buf[64];
+
+   LTC_ARGCHK(md  != NULL);
+   LTC_ARGCHK(out != NULL);
+
+    if (md->sha512.curlen >= sizeof(md->sha512.buf)) {
+       return CRYPT_INVALID_ARG;
+    }
+
+   sha512_done(md, buf);
+   XMEMCPY(out, buf, 32);
+#ifdef LTC_CLEAN_STACK
+   zeromem(buf, sizeof(buf));
+#endif
+   return CRYPT_OK;
+}
+
+/**
+  Self-test the hash
+  @return CRYPT_OK if successful, CRYPT_NOP if self-tests have been disabled
+*/
+int  sha512_256_test(void)
+{
+ #ifndef LTC_TEST
+    return CRYPT_NOP;
+ #else
+  static const struct {
+      const char *msg;
+      unsigned char hash[32];
+  } tests[] = {
+    { "abc",
+      { 0x53, 0x04, 0x8E, 0x26, 0x81, 0x94, 0x1E, 0xF9,
+        0x9B, 0x2E, 0x29, 0xB7, 0x6B, 0x4C, 0x7D, 0xAB,
+        0xE4, 0xC2, 0xD0, 0xC6, 0x34, 0xFC, 0x6D, 0x46,
+        0xE0, 0xE2, 0xF1, 0x31, 0x07, 0xE7, 0xAF, 0x23 }
+    },
+    { "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu",
+      { 0x39, 0x28, 0xE1, 0x84, 0xFB, 0x86, 0x90, 0xF8,
+        0x40, 0xDA, 0x39, 0x88, 0x12, 0x1D, 0x31, 0xBE,
+        0x65, 0xCB, 0x9D, 0x3E, 0xF8, 0x3E, 0xE6, 0x14,
+        0x6F, 0xEA, 0xC8, 0x61, 0xE1, 0x9B, 0x56, 0x3A }
+    },
+  };
+
+  int i;
+  unsigned char tmp[32];
+  hash_state md;
+
+  for (i = 0; i < (int)(sizeof(tests) / sizeof(tests[0])); i++) {
+      sha512_256_init(&md);
+      sha512_256_process(&md, (unsigned char*)tests[i].msg, (unsigned long)strlen(tests[i].msg));
+      sha512_256_done(&md, tmp);
+      if (compare_testvector(tmp, sizeof(tmp), tests[i].hash, sizeof(tests[i].hash), "SHA512-265", i)) {
+         return CRYPT_FAIL_TESTVECTOR;
+      }
+  }
+  return CRYPT_OK;
+ #endif
+}
+
+#endif /* defined(LTC_SHA384) && defined(LTC_SHA512) */
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/hashes/sha3.c b/libtomcrypt/src/hashes/sha3.c
new file mode 100644 (file)
index 0000000..c6faa0b
--- /dev/null
@@ -0,0 +1,306 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+/* based on https://github.com/brainhub/SHA3IUF (public domain) */
+
+#include "tomcrypt.h"
+
+#ifdef LTC_SHA3
+
+const struct ltc_hash_descriptor sha3_224_desc =
+{
+   "sha3-224",                  /* name of hash */
+   17,                          /* internal ID */
+   28,                          /* Size of digest in octets */
+   144,                         /* Input block size in octets */
+   { 2,16,840,1,101,3,4,2,7 },  /* ASN.1 OID */
+   9,                           /* Length OID */
+   &sha3_224_init,
+   &sha3_process,
+   &sha3_done,
+   &sha3_224_test,
+   NULL
+};
+
+const struct ltc_hash_descriptor sha3_256_desc =
+{
+   "sha3-256",                  /* name of hash */
+   18,                          /* internal ID */
+   32,                          /* Size of digest in octets */
+   136,                         /* Input block size in octets */
+   { 2,16,840,1,101,3,4,2,8 },  /* ASN.1 OID */
+   9,                           /* Length OID */
+   &sha3_256_init,
+   &sha3_process,
+   &sha3_done,
+   &sha3_256_test,
+   NULL
+};
+
+const struct ltc_hash_descriptor sha3_384_desc =
+{
+   "sha3-384",                  /* name of hash */
+   19,                          /* internal ID */
+   48,                          /* Size of digest in octets */
+   104,                         /* Input block size in octets */
+   { 2,16,840,1,101,3,4,2,9 },  /* ASN.1 OID */
+   9,                           /* Length OID */
+   &sha3_384_init,
+   &sha3_process,
+   &sha3_done,
+   &sha3_384_test,
+   NULL
+};
+
+const struct ltc_hash_descriptor sha3_512_desc =
+{
+   "sha3-512",                  /* name of hash */
+   20,                          /* internal ID */
+   64,                          /* Size of digest in octets */
+   72,                          /* Input block size in octets */
+   { 2,16,840,1,101,3,4,2,10 }, /* ASN.1 OID */
+   9,                           /* Length OID */
+   &sha3_512_init,
+   &sha3_process,
+   &sha3_done,
+   &sha3_512_test,
+   NULL
+};
+
+#define SHA3_KECCAK_SPONGE_WORDS 25 /* 1600 bits > 200 bytes > 25 x ulong64 */
+#define SHA3_KECCAK_ROUNDS 24
+
+static const ulong64 keccakf_rndc[24] = {
+   CONST64(0x0000000000000001), CONST64(0x0000000000008082),
+   CONST64(0x800000000000808a), CONST64(0x8000000080008000),
+   CONST64(0x000000000000808b), CONST64(0x0000000080000001),
+   CONST64(0x8000000080008081), CONST64(0x8000000000008009),
+   CONST64(0x000000000000008a), CONST64(0x0000000000000088),
+   CONST64(0x0000000080008009), CONST64(0x000000008000000a),
+   CONST64(0x000000008000808b), CONST64(0x800000000000008b),
+   CONST64(0x8000000000008089), CONST64(0x8000000000008003),
+   CONST64(0x8000000000008002), CONST64(0x8000000000000080),
+   CONST64(0x000000000000800a), CONST64(0x800000008000000a),
+   CONST64(0x8000000080008081), CONST64(0x8000000000008080),
+   CONST64(0x0000000080000001), CONST64(0x8000000080008008)
+};
+
+static const unsigned keccakf_rotc[24] = {
+   1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 2, 14, 27, 41, 56, 8, 25, 43, 62, 18, 39, 61, 20, 44
+};
+
+static const unsigned keccakf_piln[24] = {
+   10, 7, 11, 17, 18, 3, 5, 16, 8, 21, 24, 4, 15, 23, 19, 13, 12, 2, 20, 14, 22, 9, 6, 1
+};
+
+static void keccakf(ulong64 s[25])
+{
+   int i, j, round;
+   ulong64 t, bc[5];
+
+   for(round = 0; round < SHA3_KECCAK_ROUNDS; round++) {
+      /* Theta */
+      for(i = 0; i < 5; i++)
+         bc[i] = s[i] ^ s[i + 5] ^ s[i + 10] ^ s[i + 15] ^ s[i + 20];
+
+      for(i = 0; i < 5; i++) {
+         t = bc[(i + 4) % 5] ^ ROL64(bc[(i + 1) % 5], 1);
+         for(j = 0; j < 25; j += 5)
+            s[j + i] ^= t;
+      }
+      /* Rho Pi */
+      t = s[1];
+      for(i = 0; i < 24; i++) {
+         j = keccakf_piln[i];
+         bc[0] = s[j];
+         s[j] = ROL64(t, keccakf_rotc[i]);
+         t = bc[0];
+      }
+      /* Chi */
+      for(j = 0; j < 25; j += 5) {
+         for(i = 0; i < 5; i++)
+            bc[i] = s[j + i];
+         for(i = 0; i < 5; i++)
+            s[j + i] ^= (~bc[(i + 1) % 5]) & bc[(i + 2) % 5];
+      }
+      /* Iota */
+      s[0] ^= keccakf_rndc[round];
+   }
+}
+
+/* Public Inteface */
+
+int sha3_224_init(hash_state *md)
+{
+   LTC_ARGCHK(md != NULL);
+   XMEMSET(&md->sha3, 0, sizeof(md->sha3));
+   md->sha3.capacity_words = 2 * 224 / (8 * sizeof(ulong64));
+   return CRYPT_OK;
+}
+
+int sha3_256_init(hash_state *md)
+{
+   LTC_ARGCHK(md != NULL);
+   XMEMSET(&md->sha3, 0, sizeof(md->sha3));
+   md->sha3.capacity_words = 2 * 256 / (8 * sizeof(ulong64));
+   return CRYPT_OK;
+}
+
+int sha3_384_init(hash_state *md)
+{
+   LTC_ARGCHK(md != NULL);
+   XMEMSET(&md->sha3, 0, sizeof(md->sha3));
+   md->sha3.capacity_words = 2 * 384 / (8 * sizeof(ulong64));
+   return CRYPT_OK;
+}
+
+int sha3_512_init(hash_state *md)
+{
+   LTC_ARGCHK(md != NULL);
+   XMEMSET(&md->sha3, 0, sizeof(md->sha3));
+   md->sha3.capacity_words = 2 * 512 / (8 * sizeof(ulong64));
+   return CRYPT_OK;
+}
+
+int sha3_shake_init(hash_state *md, int num)
+{
+   LTC_ARGCHK(md != NULL);
+   if (num != 128 && num != 256) return CRYPT_INVALID_ARG;
+   XMEMSET(&md->sha3, 0, sizeof(md->sha3));
+   md->sha3.capacity_words = (unsigned short)(2 * num / (8 * sizeof(ulong64)));
+   return CRYPT_OK;
+}
+
+int sha3_process(hash_state *md, const unsigned char *in, unsigned long inlen)
+{
+   /* 0...7 -- how much is needed to have a word */
+   unsigned old_tail = (8 - md->sha3.byte_index) & 7;
+
+   unsigned long words;
+   unsigned tail;
+   unsigned long i;
+
+   if (inlen == 0) return CRYPT_OK; /* nothing to do */
+   LTC_ARGCHK(md != NULL);
+   LTC_ARGCHK(in != NULL);
+
+   if(inlen < old_tail) {       /* have no complete word or haven't started the word yet */
+      while (inlen--) md->sha3.saved |= (ulong64) (*(in++)) << ((md->sha3.byte_index++) * 8);
+      return CRYPT_OK;
+   }
+
+   if(old_tail) {               /* will have one word to process */
+      inlen -= old_tail;
+      while (old_tail--) md->sha3.saved |= (ulong64) (*(in++)) << ((md->sha3.byte_index++) * 8);
+      /* now ready to add saved to the sponge */
+      md->sha3.s[md->sha3.word_index] ^= md->sha3.saved;
+      md->sha3.byte_index = 0;
+      md->sha3.saved = 0;
+      if(++md->sha3.word_index == (SHA3_KECCAK_SPONGE_WORDS - md->sha3.capacity_words)) {
+         keccakf(md->sha3.s);
+         md->sha3.word_index = 0;
+      }
+   }
+
+   /* now work in full words directly from input */
+   words = inlen / sizeof(ulong64);
+   tail = inlen - words * sizeof(ulong64);
+
+   for(i = 0; i < words; i++, in += sizeof(ulong64)) {
+      ulong64 t;
+      LOAD64L(t, in);
+      md->sha3.s[md->sha3.word_index] ^= t;
+      if(++md->sha3.word_index == (SHA3_KECCAK_SPONGE_WORDS - md->sha3.capacity_words)) {
+         keccakf(md->sha3.s);
+         md->sha3.word_index = 0;
+      }
+   }
+
+   /* finally, save the partial word */
+   while (tail--) {
+      md->sha3.saved |= (ulong64) (*(in++)) << ((md->sha3.byte_index++) * 8);
+   }
+   return CRYPT_OK;
+}
+
+int sha3_done(hash_state *md, unsigned char *hash)
+{
+   unsigned i;
+
+   LTC_ARGCHK(md   != NULL);
+   LTC_ARGCHK(hash != NULL);
+
+   md->sha3.s[md->sha3.word_index] ^= (md->sha3.saved ^ (CONST64(0x06) << (md->sha3.byte_index * 8)));
+   md->sha3.s[SHA3_KECCAK_SPONGE_WORDS - md->sha3.capacity_words - 1] ^= CONST64(0x8000000000000000);
+   keccakf(md->sha3.s);
+
+   /* store sha3.s[] as little-endian bytes into sha3.sb */
+   for(i = 0; i < SHA3_KECCAK_SPONGE_WORDS; i++) {
+      STORE64L(md->sha3.s[i], md->sha3.sb + i * 8);
+   }
+
+   XMEMCPY(hash, md->sha3.sb, md->sha3.capacity_words * 4);
+   return CRYPT_OK;
+}
+
+int sha3_shake_done(hash_state *md, unsigned char *out, unsigned long outlen)
+{
+   /* IMPORTANT NOTE: sha3_shake_done can be called many times */
+   unsigned long idx;
+   unsigned i;
+
+   if (outlen == 0) return CRYPT_OK; /* nothing to do */
+   LTC_ARGCHK(md  != NULL);
+   LTC_ARGCHK(out != NULL);
+
+   if (!md->sha3.xof_flag) {
+      /* shake_xof operation must be done only once */
+      md->sha3.s[md->sha3.word_index] ^= (md->sha3.saved ^ (CONST64(0x1F) << (md->sha3.byte_index * 8)));
+      md->sha3.s[SHA3_KECCAK_SPONGE_WORDS - md->sha3.capacity_words - 1] ^= CONST64(0x8000000000000000);
+      keccakf(md->sha3.s);
+      /* store sha3.s[] as little-endian bytes into sha3.sb */
+      for(i = 0; i < SHA3_KECCAK_SPONGE_WORDS; i++) {
+         STORE64L(md->sha3.s[i], md->sha3.sb + i * 8);
+      }
+      md->sha3.byte_index = 0;
+      md->sha3.xof_flag = 1;
+   }
+
+   for (idx = 0; idx < outlen; idx++) {
+      if(md->sha3.byte_index >= (SHA3_KECCAK_SPONGE_WORDS - md->sha3.capacity_words) * 8) {
+         keccakf(md->sha3.s);
+         /* store sha3.s[] as little-endian bytes into sha3.sb */
+         for(i = 0; i < SHA3_KECCAK_SPONGE_WORDS; i++) {
+            STORE64L(md->sha3.s[i], md->sha3.sb + i * 8);
+         }
+         md->sha3.byte_index = 0;
+      }
+      out[idx] = md->sha3.sb[md->sha3.byte_index++];
+   }
+   return CRYPT_OK;
+}
+
+int sha3_shake_memory(int num, const unsigned char *in, unsigned long inlen, unsigned char *out, unsigned long *outlen)
+{
+   hash_state md;
+   int err;
+   LTC_ARGCHK(in  != NULL);
+   LTC_ARGCHK(out != NULL);
+   LTC_ARGCHK(outlen != NULL);
+   if ((err = sha3_shake_init(&md, num))          != CRYPT_OK) return err;
+   if ((err = sha3_shake_process(&md, in, inlen)) != CRYPT_OK) return err;
+   if ((err = sha3_shake_done(&md, out, *outlen)) != CRYPT_OK) return err;
+   return CRYPT_OK;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/hashes/sha3_test.c b/libtomcrypt/src/hashes/sha3_test.c
new file mode 100644 (file)
index 0000000..5ae8650
--- /dev/null
@@ -0,0 +1,401 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+/* based on https://github.com/brainhub/SHA3IUF (public domain) */
+
+#include "tomcrypt.h"
+
+#ifdef LTC_SHA3
+
+int sha3_224_test(void)
+{
+#ifndef LTC_TEST
+   return CRYPT_NOP;
+#else
+   unsigned char buf[200], hash[224 / 8];
+   int i;
+   hash_state c;
+   const unsigned char c1 = 0xa3;
+
+   const unsigned char sha3_224_empty[224 / 8] = {
+      0x6b, 0x4e, 0x03, 0x42, 0x36, 0x67, 0xdb, 0xb7,
+      0x3b, 0x6e, 0x15, 0x45, 0x4f, 0x0e, 0xb1, 0xab,
+      0xd4, 0x59, 0x7f, 0x9a, 0x1b, 0x07, 0x8e, 0x3f,
+      0x5b, 0x5a, 0x6b, 0xc7
+   };
+
+   const unsigned char sha3_224_0xa3_200_times[224 / 8] = {
+      0x93, 0x76, 0x81, 0x6a, 0xba, 0x50, 0x3f, 0x72,
+      0xf9, 0x6c, 0xe7, 0xeb, 0x65, 0xac, 0x09, 0x5d,
+      0xee, 0xe3, 0xbe, 0x4b, 0xf9, 0xbb, 0xc2, 0xa1,
+      0xcb, 0x7e, 0x11, 0xe0
+   };
+
+   XMEMSET(buf, c1, sizeof(buf));
+
+   /* SHA3-224 on an empty buffer */
+   sha3_224_init(&c);
+   sha3_done(&c, hash);
+   if (compare_testvector(hash, sizeof(hash), sha3_224_empty, sizeof(sha3_224_empty), "SHA3-224", 0)) {
+      return CRYPT_FAIL_TESTVECTOR;
+   }
+
+   /* SHA3-224 in two steps. [FIPS 202] */
+   sha3_224_init(&c);
+   sha3_process(&c, buf, sizeof(buf) / 2);
+   sha3_process(&c, buf + sizeof(buf) / 2, sizeof(buf) / 2);
+   sha3_done(&c, hash);
+   if (compare_testvector(hash, sizeof(hash), sha3_224_0xa3_200_times, sizeof(sha3_224_0xa3_200_times), "SHA3-224", 1)) {
+      return CRYPT_FAIL_TESTVECTOR;
+   }
+
+   /* SHA3-224 byte-by-byte: 200 steps. [FIPS 202] */
+   i = 200;
+   sha3_224_init(&c);
+   while (i--) {
+       sha3_process(&c, &c1, 1);
+   }
+   sha3_done(&c, hash);
+   if (compare_testvector(hash, sizeof(hash), sha3_224_0xa3_200_times, sizeof(sha3_224_0xa3_200_times), "SHA3-224", 2)) {
+      return CRYPT_FAIL_TESTVECTOR;
+   }
+
+   return CRYPT_OK;
+#endif
+}
+
+int sha3_256_test(void)
+{
+#ifndef LTC_TEST
+   return CRYPT_NOP;
+#else
+   unsigned char buf[200], hash[256 / 8];
+   int i;
+   hash_state c;
+   const unsigned char c1 = 0xa3;
+
+   const unsigned char sha3_256_empty[256 / 8] = {
+      0xa7, 0xff, 0xc6, 0xf8, 0xbf, 0x1e, 0xd7, 0x66,
+      0x51, 0xc1, 0x47, 0x56, 0xa0, 0x61, 0xd6, 0x62,
+      0xf5, 0x80, 0xff, 0x4d, 0xe4, 0x3b, 0x49, 0xfa,
+      0x82, 0xd8, 0x0a, 0x4b, 0x80, 0xf8, 0x43, 0x4a
+   };
+   const unsigned char sha3_256_0xa3_200_times[256 / 8] = {
+      0x79, 0xf3, 0x8a, 0xde, 0xc5, 0xc2, 0x03, 0x07,
+      0xa9, 0x8e, 0xf7, 0x6e, 0x83, 0x24, 0xaf, 0xbf,
+      0xd4, 0x6c, 0xfd, 0x81, 0xb2, 0x2e, 0x39, 0x73,
+      0xc6, 0x5f, 0xa1, 0xbd, 0x9d, 0xe3, 0x17, 0x87
+   };
+
+   XMEMSET(buf, c1, sizeof(buf));
+
+   /* SHA3-256 on an empty buffer */
+   sha3_256_init(&c);
+   sha3_done(&c, hash);
+   if (compare_testvector(hash, sizeof(hash), sha3_256_empty, sizeof(sha3_256_empty), "SHA3-256", 0)) {
+      return CRYPT_FAIL_TESTVECTOR;
+   }
+
+   /* SHA3-256 as a single buffer. [FIPS 202] */
+   sha3_256_init(&c);
+   sha3_process(&c, buf, sizeof(buf));
+   sha3_done(&c, hash);
+   if (compare_testvector(hash, sizeof(hash), sha3_256_0xa3_200_times, sizeof(sha3_256_0xa3_200_times), "SHA3-256", 1)) {
+      return CRYPT_FAIL_TESTVECTOR;
+   }
+
+   /* SHA3-256 in two steps. [FIPS 202] */
+   sha3_256_init(&c);
+   sha3_process(&c, buf, sizeof(buf) / 2);
+   sha3_process(&c, buf + sizeof(buf) / 2, sizeof(buf) / 2);
+   sha3_done(&c, hash);
+   if (compare_testvector(hash, sizeof(hash), sha3_256_0xa3_200_times, sizeof(sha3_256_0xa3_200_times), "SHA3-256", 2)) {
+      return CRYPT_FAIL_TESTVECTOR;
+   }
+
+   /* SHA3-256 byte-by-byte: 200 steps. [FIPS 202] */
+   i = 200;
+   sha3_256_init(&c);
+   while (i--) {
+       sha3_process(&c, &c1, 1);
+   }
+   sha3_done(&c, hash);
+   if (compare_testvector(hash, sizeof(hash), sha3_256_0xa3_200_times, sizeof(sha3_256_0xa3_200_times), "SHA3-256", 3)) {
+      return CRYPT_FAIL_TESTVECTOR;
+   }
+
+   /* SHA3-256 byte-by-byte: 135 bytes. Input from [Keccak]. Output
+    * matched with sha3sum. */
+   sha3_256_init(&c);
+   sha3_process(&c, (unsigned char*)
+           "\xb7\x71\xd5\xce\xf5\xd1\xa4\x1a"
+           "\x93\xd1\x56\x43\xd7\x18\x1d\x2a"
+           "\x2e\xf0\xa8\xe8\x4d\x91\x81\x2f"
+           "\x20\xed\x21\xf1\x47\xbe\xf7\x32"
+           "\xbf\x3a\x60\xef\x40\x67\xc3\x73"
+           "\x4b\x85\xbc\x8c\xd4\x71\x78\x0f"
+           "\x10\xdc\x9e\x82\x91\xb5\x83\x39"
+           "\xa6\x77\xb9\x60\x21\x8f\x71\xe7"
+           "\x93\xf2\x79\x7a\xea\x34\x94\x06"
+           "\x51\x28\x29\x06\x5d\x37\xbb\x55"
+           "\xea\x79\x6f\xa4\xf5\x6f\xd8\x89"
+           "\x6b\x49\xb2\xcd\x19\xb4\x32\x15"
+           "\xad\x96\x7c\x71\x2b\x24\xe5\x03"
+           "\x2d\x06\x52\x32\xe0\x2c\x12\x74"
+           "\x09\xd2\xed\x41\x46\xb9\xd7\x5d"
+           "\x76\x3d\x52\xdb\x98\xd9\x49\xd3"
+           "\xb0\xfe\xd6\xa8\x05\x2f\xbb", 1080 / 8);
+   sha3_done(&c, hash);
+   if(compare_testvector(hash, sizeof(hash),
+           "\xa1\x9e\xee\x92\xbb\x20\x97\xb6"
+           "\x4e\x82\x3d\x59\x77\x98\xaa\x18"
+           "\xbe\x9b\x7c\x73\x6b\x80\x59\xab"
+           "\xfd\x67\x79\xac\x35\xac\x81\xb5", 256 / 8, "SHA3-256", 4)) {
+      return CRYPT_FAIL_TESTVECTOR;
+   }
+
+   return CRYPT_OK;
+#endif
+}
+
+int sha3_384_test(void)
+{
+#ifndef LTC_TEST
+   return CRYPT_NOP;
+#else
+   unsigned char buf[200], hash[384 / 8];
+   int i;
+   hash_state c;
+   const unsigned char c1 = 0xa3;
+
+   const unsigned char sha3_384_0xa3_200_times[384 / 8] = {
+      0x18, 0x81, 0xde, 0x2c, 0xa7, 0xe4, 0x1e, 0xf9,
+      0x5d, 0xc4, 0x73, 0x2b, 0x8f, 0x5f, 0x00, 0x2b,
+      0x18, 0x9c, 0xc1, 0xe4, 0x2b, 0x74, 0x16, 0x8e,
+      0xd1, 0x73, 0x26, 0x49, 0xce, 0x1d, 0xbc, 0xdd,
+      0x76, 0x19, 0x7a, 0x31, 0xfd, 0x55, 0xee, 0x98,
+      0x9f, 0x2d, 0x70, 0x50, 0xdd, 0x47, 0x3e, 0x8f
+   };
+
+   XMEMSET(buf, c1, sizeof(buf));
+
+   /* SHA3-384 as a single buffer. [FIPS 202] */
+   sha3_384_init(&c);
+   sha3_process(&c, buf, sizeof(buf));
+   sha3_done(&c, hash);
+   if (compare_testvector(hash, sizeof(hash), sha3_384_0xa3_200_times, sizeof(sha3_384_0xa3_200_times), "SHA3-384", 0)) {
+      return CRYPT_FAIL_TESTVECTOR;
+   }
+
+   /* SHA3-384 in two steps. [FIPS 202] */
+   sha3_384_init(&c);
+   sha3_process(&c, buf, sizeof(buf) / 2);
+   sha3_process(&c, buf + sizeof(buf) / 2, sizeof(buf) / 2);
+   sha3_done(&c, hash);
+   if (compare_testvector(hash, sizeof(hash), sha3_384_0xa3_200_times, sizeof(sha3_384_0xa3_200_times), "SHA3-384", 1)) {
+      return CRYPT_FAIL_TESTVECTOR;
+   }
+
+   /* SHA3-384 byte-by-byte: 200 steps. [FIPS 202] */
+   i = 200;
+   sha3_384_init(&c);
+   while (i--) {
+       sha3_process(&c, &c1, 1);
+   }
+   sha3_done(&c, hash);
+   if (compare_testvector(hash, sizeof(hash), sha3_384_0xa3_200_times, sizeof(sha3_384_0xa3_200_times), "SHA3-384", 2)) {
+      return CRYPT_FAIL_TESTVECTOR;
+   }
+
+   return CRYPT_OK;
+#endif
+}
+
+int sha3_512_test(void)
+{
+#ifndef LTC_TEST
+   return CRYPT_NOP;
+#else
+   unsigned char buf[200], hash[512 / 8];
+   int i;
+   hash_state c;
+   const unsigned char c1 = 0xa3;
+
+   const unsigned char sha3_512_0xa3_200_times[512 / 8] = {
+      0xe7, 0x6d, 0xfa, 0xd2, 0x20, 0x84, 0xa8, 0xb1,
+      0x46, 0x7f, 0xcf, 0x2f, 0xfa, 0x58, 0x36, 0x1b,
+      0xec, 0x76, 0x28, 0xed, 0xf5, 0xf3, 0xfd, 0xc0,
+      0xe4, 0x80, 0x5d, 0xc4, 0x8c, 0xae, 0xec, 0xa8,
+      0x1b, 0x7c, 0x13, 0xc3, 0x0a, 0xdf, 0x52, 0xa3,
+      0x65, 0x95, 0x84, 0x73, 0x9a, 0x2d, 0xf4, 0x6b,
+      0xe5, 0x89, 0xc5, 0x1c, 0xa1, 0xa4, 0xa8, 0x41,
+      0x6d, 0xf6, 0x54, 0x5a, 0x1c, 0xe8, 0xba, 0x00
+   };
+
+   XMEMSET(buf, c1, sizeof(buf));
+
+   /* SHA3-512 as a single buffer. [FIPS 202] */
+   sha3_512_init(&c);
+   sha3_process(&c, buf, sizeof(buf));
+   sha3_done(&c, hash);
+   if (compare_testvector(hash, sizeof(hash), sha3_512_0xa3_200_times, sizeof(sha3_512_0xa3_200_times), "SHA3-512", 0)) {
+      return CRYPT_FAIL_TESTVECTOR;
+   }
+
+   /* SHA3-512 in two steps. [FIPS 202] */
+   sha3_512_init(&c);
+   sha3_process(&c, buf, sizeof(buf) / 2);
+   sha3_process(&c, buf + sizeof(buf) / 2, sizeof(buf) / 2);
+   sha3_done(&c, hash);
+   if (compare_testvector(hash, sizeof(hash), sha3_512_0xa3_200_times, sizeof(sha3_512_0xa3_200_times), "SHA3-512", 1)) {
+      return CRYPT_FAIL_TESTVECTOR;
+   }
+
+   /* SHA3-512 byte-by-byte: 200 steps. [FIPS 202] */
+   i = 200;
+   sha3_512_init(&c);
+   while (i--) {
+       sha3_process(&c, &c1, 1);
+   }
+   sha3_done(&c, hash);
+   if (compare_testvector(hash, sizeof(hash), sha3_512_0xa3_200_times, sizeof(sha3_512_0xa3_200_times), "SHA3-512", 2)) {
+      return CRYPT_FAIL_TESTVECTOR;
+   }
+
+   return CRYPT_OK;
+#endif
+}
+
+int sha3_shake_test(void)
+{
+#ifndef LTC_TEST
+   return CRYPT_NOP;
+#else
+   unsigned char buf[200], hash[512];
+   int i;
+   hash_state c;
+   const unsigned char c1 = 0xa3;
+   unsigned long len;
+
+   const unsigned char shake256_empty[32] = {
+      0xab, 0x0b, 0xae, 0x31, 0x63, 0x39, 0x89, 0x43,
+      0x04, 0xe3, 0x58, 0x77, 0xb0, 0xc2, 0x8a, 0x9b,
+      0x1f, 0xd1, 0x66, 0xc7, 0x96, 0xb9, 0xcc, 0x25,
+      0x8a, 0x06, 0x4a, 0x8f, 0x57, 0xe2, 0x7f, 0x2a
+   };
+   const unsigned char shake256_0xa3_200_times[32] = {
+      0x6a, 0x1a, 0x9d, 0x78, 0x46, 0x43, 0x6e, 0x4d,
+      0xca, 0x57, 0x28, 0xb6, 0xf7, 0x60, 0xee, 0xf0,
+      0xca, 0x92, 0xbf, 0x0b, 0xe5, 0x61, 0x5e, 0x96,
+      0x95, 0x9d, 0x76, 0x71, 0x97, 0xa0, 0xbe, 0xeb
+   };
+   const unsigned char shake128_empty[32] = {
+      0x43, 0xe4, 0x1b, 0x45, 0xa6, 0x53, 0xf2, 0xa5,
+      0xc4, 0x49, 0x2c, 0x1a, 0xdd, 0x54, 0x45, 0x12,
+      0xdd, 0xa2, 0x52, 0x98, 0x33, 0x46, 0x2b, 0x71,
+      0xa4, 0x1a, 0x45, 0xbe, 0x97, 0x29, 0x0b, 0x6f
+   };
+   const unsigned char shake128_0xa3_200_times[32] = {
+      0x44, 0xc9, 0xfb, 0x35, 0x9f, 0xd5, 0x6a, 0xc0,
+      0xa9, 0xa7, 0x5a, 0x74, 0x3c, 0xff, 0x68, 0x62,
+      0xf1, 0x7d, 0x72, 0x59, 0xab, 0x07, 0x52, 0x16,
+      0xc0, 0x69, 0x95, 0x11, 0x64, 0x3b, 0x64, 0x39
+   };
+
+   XMEMSET(buf, c1, sizeof(buf));
+
+   /* SHAKE256 on an empty buffer */
+   sha3_shake_init(&c, 256);
+   for (i = 0; i < 16; i++) sha3_shake_done(&c, hash, 32); /* get 512 bytes, keep in hash the last 32 */
+   if (compare_testvector(hash, sizeof(shake256_empty), shake256_empty, sizeof(shake256_empty), "SHAKE256", 0)) {
+      return CRYPT_FAIL_TESTVECTOR;
+   }
+
+   /* SHAKE256 via sha3_shake_memory [FIPS 202] */
+   len = 512;
+   sha3_shake_memory(256, buf, sizeof(buf), hash, &len);
+   if (compare_testvector(hash + 480, sizeof(shake256_0xa3_200_times), shake256_0xa3_200_times, sizeof(shake256_0xa3_200_times), "SHAKE256", 1)) {
+      return CRYPT_FAIL_TESTVECTOR;
+   }
+
+   /* SHAKE256 as a single buffer. [FIPS 202] */
+   sha3_shake_init(&c, 256);
+   sha3_shake_process(&c, buf, sizeof(buf));
+   for (i = 0; i < 16; i++) sha3_shake_done(&c, hash, 32); /* get 512 bytes, keep in hash the last 32 */
+   if (compare_testvector(hash, sizeof(shake256_0xa3_200_times), shake256_0xa3_200_times, sizeof(shake256_0xa3_200_times), "SHAKE256", 2)) {
+      return CRYPT_FAIL_TESTVECTOR;
+   }
+
+   /* SHAKE256 in two steps. [FIPS 202] */
+   sha3_shake_init(&c, 256);
+   sha3_shake_process(&c, buf, sizeof(buf) / 2);
+   sha3_shake_process(&c, buf + sizeof(buf) / 2, sizeof(buf) / 2);
+   for (i = 0; i < 16; i++) sha3_shake_done(&c, hash, 32); /* get 512 bytes, keep in hash the last 32 */
+   if (compare_testvector(hash, sizeof(shake256_0xa3_200_times), shake256_0xa3_200_times, sizeof(shake256_0xa3_200_times), "SHAKE256", 3)) {
+      return CRYPT_FAIL_TESTVECTOR;
+   }
+
+   /* SHAKE256 byte-by-byte: 200 steps. [FIPS 202] */
+   i = 200;
+   sha3_shake_init(&c, 256);
+   while (i--) sha3_shake_process(&c, &c1, 1);
+   for (i = 0; i < 16; i++) sha3_shake_done(&c, hash, 32); /* get 512 bytes, keep in hash the last 32 */
+   if (compare_testvector(hash, sizeof(shake256_0xa3_200_times), shake256_0xa3_200_times, sizeof(shake256_0xa3_200_times), "SHAKE256", 4)) {
+      return CRYPT_FAIL_TESTVECTOR;
+   }
+
+   /* SHAKE128 on an empty buffer */
+   sha3_shake_init(&c, 128);
+   for (i = 0; i < 16; i++) sha3_shake_done(&c, hash, 32); /* get 512 bytes, keep in hash the last 32 */
+   if (compare_testvector(hash, sizeof(shake128_empty), shake128_empty, sizeof(shake128_empty), "SHAKE128", 0)) {
+      return CRYPT_FAIL_TESTVECTOR;
+   }
+
+   /* SHAKE128 via sha3_shake_memory [FIPS 202] */
+   len = 512;
+   sha3_shake_memory(128, buf, sizeof(buf), hash, &len);
+   if (compare_testvector(hash + 480, sizeof(shake128_0xa3_200_times), shake128_0xa3_200_times, sizeof(shake128_0xa3_200_times), "SHAKE128", 1)) {
+      return CRYPT_FAIL_TESTVECTOR;
+   }
+
+   /* SHAKE128 as a single buffer. [FIPS 202] */
+   sha3_shake_init(&c, 128);
+   sha3_shake_process(&c, buf, sizeof(buf));
+   for (i = 0; i < 16; i++) sha3_shake_done(&c, hash, 32); /* get 512 bytes, keep in hash the last 32 */
+   if (compare_testvector(hash, sizeof(shake128_0xa3_200_times), shake128_0xa3_200_times, sizeof(shake128_0xa3_200_times), "SHAKE128", 2)) {
+      return CRYPT_FAIL_TESTVECTOR;
+   }
+
+   /* SHAKE128 in two steps. [FIPS 202] */
+   sha3_shake_init(&c, 128);
+   sha3_shake_process(&c, buf, sizeof(buf) / 2);
+   sha3_shake_process(&c, buf + sizeof(buf) / 2, sizeof(buf) / 2);
+   for (i = 0; i < 16; i++) sha3_shake_done(&c, hash, 32); /* get 512 bytes, keep in hash the last 32 */
+   if (compare_testvector(hash, sizeof(shake128_0xa3_200_times), shake128_0xa3_200_times, sizeof(shake128_0xa3_200_times), "SHAKE128", 3)) {
+      return CRYPT_FAIL_TESTVECTOR;
+   }
+
+   /* SHAKE128 byte-by-byte: 200 steps. [FIPS 202] */
+   i = 200;
+   sha3_shake_init(&c, 128);
+   while (i--) sha3_shake_process(&c, &c1, 1);
+   for (i = 0; i < 16; i++) sha3_shake_done(&c, hash, 32); /* get 512 bytes, keep in hash the last 32 */
+   if (compare_testvector(hash, sizeof(shake128_0xa3_200_times), shake128_0xa3_200_times, sizeof(shake128_0xa3_200_times), "SHAKE128", 4)) {
+      return CRYPT_FAIL_TESTVECTOR;
+   }
+
+   return CRYPT_OK;
+#endif
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/hashes/tiger.c b/libtomcrypt/src/hashes/tiger.c
new file mode 100644 (file)
index 0000000..863f7fa
--- /dev/null
@@ -0,0 +1,812 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+#include "tomcrypt.h"
+
+/**
+   @file tiger.c
+   Tiger hash function, Tom St Denis
+*/
+
+#ifdef LTC_TIGER
+
+const struct ltc_hash_descriptor tiger_desc =
+{
+    "tiger",
+    1,
+    24,
+    64,
+
+    /* OID */
+   { 1, 3, 6, 1, 4, 1, 11591, 12, 2,  },
+   9,
+
+    &tiger_init,
+    &tiger_process,
+    &tiger_done,
+    &tiger_test,
+    NULL
+};
+
+#define t1 (table)
+#define t2 (table+256)
+#define t3 (table+256*2)
+#define t4 (table+256*3)
+
+static const ulong64 table[4*256] = {
+    CONST64(0x02AAB17CF7E90C5E) /*    0 */, CONST64(0xAC424B03E243A8EC) /*    1 */,
+    CONST64(0x72CD5BE30DD5FCD3) /*    2 */, CONST64(0x6D019B93F6F97F3A) /*    3 */,
+    CONST64(0xCD9978FFD21F9193) /*    4 */, CONST64(0x7573A1C9708029E2) /*    5 */,
+    CONST64(0xB164326B922A83C3) /*    6 */, CONST64(0x46883EEE04915870) /*    7 */,
+    CONST64(0xEAACE3057103ECE6) /*    8 */, CONST64(0xC54169B808A3535C) /*    9 */,
+    CONST64(0x4CE754918DDEC47C) /*   10 */, CONST64(0x0AA2F4DFDC0DF40C) /*   11 */,
+    CONST64(0x10B76F18A74DBEFA) /*   12 */, CONST64(0xC6CCB6235AD1AB6A) /*   13 */,
+    CONST64(0x13726121572FE2FF) /*   14 */, CONST64(0x1A488C6F199D921E) /*   15 */,
+    CONST64(0x4BC9F9F4DA0007CA) /*   16 */, CONST64(0x26F5E6F6E85241C7) /*   17 */,
+    CONST64(0x859079DBEA5947B6) /*   18 */, CONST64(0x4F1885C5C99E8C92) /*   19 */,
+    CONST64(0xD78E761EA96F864B) /*   20 */, CONST64(0x8E36428C52B5C17D) /*   21 */,
+    CONST64(0x69CF6827373063C1) /*   22 */, CONST64(0xB607C93D9BB4C56E) /*   23 */,
+    CONST64(0x7D820E760E76B5EA) /*   24 */, CONST64(0x645C9CC6F07FDC42) /*   25 */,
+    CONST64(0xBF38A078243342E0) /*   26 */, CONST64(0x5F6B343C9D2E7D04) /*   27 */,
+    CONST64(0xF2C28AEB600B0EC6) /*   28 */, CONST64(0x6C0ED85F7254BCAC) /*   29 */,
+    CONST64(0x71592281A4DB4FE5) /*   30 */, CONST64(0x1967FA69CE0FED9F) /*   31 */,
+    CONST64(0xFD5293F8B96545DB) /*   32 */, CONST64(0xC879E9D7F2A7600B) /*   33 */,
+    CONST64(0x860248920193194E) /*   34 */, CONST64(0xA4F9533B2D9CC0B3) /*   35 */,
+    CONST64(0x9053836C15957613) /*   36 */, CONST64(0xDB6DCF8AFC357BF1) /*   37 */,
+    CONST64(0x18BEEA7A7A370F57) /*   38 */, CONST64(0x037117CA50B99066) /*   39 */,
+    CONST64(0x6AB30A9774424A35) /*   40 */, CONST64(0xF4E92F02E325249B) /*   41 */,
+    CONST64(0x7739DB07061CCAE1) /*   42 */, CONST64(0xD8F3B49CECA42A05) /*   43 */,
+    CONST64(0xBD56BE3F51382F73) /*   44 */, CONST64(0x45FAED5843B0BB28) /*   45 */,
+    CONST64(0x1C813D5C11BF1F83) /*   46 */, CONST64(0x8AF0E4B6D75FA169) /*   47 */,
+    CONST64(0x33EE18A487AD9999) /*   48 */, CONST64(0x3C26E8EAB1C94410) /*   49 */,
+    CONST64(0xB510102BC0A822F9) /*   50 */, CONST64(0x141EEF310CE6123B) /*   51 */,
+    CONST64(0xFC65B90059DDB154) /*   52 */, CONST64(0xE0158640C5E0E607) /*   53 */,
+    CONST64(0x884E079826C3A3CF) /*   54 */, CONST64(0x930D0D9523C535FD) /*   55 */,
+    CONST64(0x35638D754E9A2B00) /*   56 */, CONST64(0x4085FCCF40469DD5) /*   57 */,
+    CONST64(0xC4B17AD28BE23A4C) /*   58 */, CONST64(0xCAB2F0FC6A3E6A2E) /*   59 */,
+    CONST64(0x2860971A6B943FCD) /*   60 */, CONST64(0x3DDE6EE212E30446) /*   61 */,
+    CONST64(0x6222F32AE01765AE) /*   62 */, CONST64(0x5D550BB5478308FE) /*   63 */,
+    CONST64(0xA9EFA98DA0EDA22A) /*   64 */, CONST64(0xC351A71686C40DA7) /*   65 */,
+    CONST64(0x1105586D9C867C84) /*   66 */, CONST64(0xDCFFEE85FDA22853) /*   67 */,
+    CONST64(0xCCFBD0262C5EEF76) /*   68 */, CONST64(0xBAF294CB8990D201) /*   69 */,
+    CONST64(0xE69464F52AFAD975) /*   70 */, CONST64(0x94B013AFDF133E14) /*   71 */,
+    CONST64(0x06A7D1A32823C958) /*   72 */, CONST64(0x6F95FE5130F61119) /*   73 */,
+    CONST64(0xD92AB34E462C06C0) /*   74 */, CONST64(0xED7BDE33887C71D2) /*   75 */,
+    CONST64(0x79746D6E6518393E) /*   76 */, CONST64(0x5BA419385D713329) /*   77 */,
+    CONST64(0x7C1BA6B948A97564) /*   78 */, CONST64(0x31987C197BFDAC67) /*   79 */,
+    CONST64(0xDE6C23C44B053D02) /*   80 */, CONST64(0x581C49FED002D64D) /*   81 */,
+    CONST64(0xDD474D6338261571) /*   82 */, CONST64(0xAA4546C3E473D062) /*   83 */,
+    CONST64(0x928FCE349455F860) /*   84 */, CONST64(0x48161BBACAAB94D9) /*   85 */,
+    CONST64(0x63912430770E6F68) /*   86 */, CONST64(0x6EC8A5E602C6641C) /*   87 */,
+    CONST64(0x87282515337DDD2B) /*   88 */, CONST64(0x2CDA6B42034B701B) /*   89 */,
+    CONST64(0xB03D37C181CB096D) /*   90 */, CONST64(0xE108438266C71C6F) /*   91 */,
+    CONST64(0x2B3180C7EB51B255) /*   92 */, CONST64(0xDF92B82F96C08BBC) /*   93 */,
+    CONST64(0x5C68C8C0A632F3BA) /*   94 */, CONST64(0x5504CC861C3D0556) /*   95 */,
+    CONST64(0xABBFA4E55FB26B8F) /*   96 */, CONST64(0x41848B0AB3BACEB4) /*   97 */,
+    CONST64(0xB334A273AA445D32) /*   98 */, CONST64(0xBCA696F0A85AD881) /*   99 */,
+    CONST64(0x24F6EC65B528D56C) /*  100 */, CONST64(0x0CE1512E90F4524A) /*  101 */,
+    CONST64(0x4E9DD79D5506D35A) /*  102 */, CONST64(0x258905FAC6CE9779) /*  103 */,
+    CONST64(0x2019295B3E109B33) /*  104 */, CONST64(0xF8A9478B73A054CC) /*  105 */,
+    CONST64(0x2924F2F934417EB0) /*  106 */, CONST64(0x3993357D536D1BC4) /*  107 */,
+    CONST64(0x38A81AC21DB6FF8B) /*  108 */, CONST64(0x47C4FBF17D6016BF) /*  109 */,
+    CONST64(0x1E0FAADD7667E3F5) /*  110 */, CONST64(0x7ABCFF62938BEB96) /*  111 */,
+    CONST64(0xA78DAD948FC179C9) /*  112 */, CONST64(0x8F1F98B72911E50D) /*  113 */,
+    CONST64(0x61E48EAE27121A91) /*  114 */, CONST64(0x4D62F7AD31859808) /*  115 */,
+    CONST64(0xECEBA345EF5CEAEB) /*  116 */, CONST64(0xF5CEB25EBC9684CE) /*  117 */,
+    CONST64(0xF633E20CB7F76221) /*  118 */, CONST64(0xA32CDF06AB8293E4) /*  119 */,
+    CONST64(0x985A202CA5EE2CA4) /*  120 */, CONST64(0xCF0B8447CC8A8FB1) /*  121 */,
+    CONST64(0x9F765244979859A3) /*  122 */, CONST64(0xA8D516B1A1240017) /*  123 */,
+    CONST64(0x0BD7BA3EBB5DC726) /*  124 */, CONST64(0xE54BCA55B86ADB39) /*  125 */,
+    CONST64(0x1D7A3AFD6C478063) /*  126 */, CONST64(0x519EC608E7669EDD) /*  127 */,
+    CONST64(0x0E5715A2D149AA23) /*  128 */, CONST64(0x177D4571848FF194) /*  129 */,
+    CONST64(0xEEB55F3241014C22) /*  130 */, CONST64(0x0F5E5CA13A6E2EC2) /*  131 */,
+    CONST64(0x8029927B75F5C361) /*  132 */, CONST64(0xAD139FABC3D6E436) /*  133 */,
+    CONST64(0x0D5DF1A94CCF402F) /*  134 */, CONST64(0x3E8BD948BEA5DFC8) /*  135 */,
+    CONST64(0xA5A0D357BD3FF77E) /*  136 */, CONST64(0xA2D12E251F74F645) /*  137 */,
+    CONST64(0x66FD9E525E81A082) /*  138 */, CONST64(0x2E0C90CE7F687A49) /*  139 */,
+    CONST64(0xC2E8BCBEBA973BC5) /*  140 */, CONST64(0x000001BCE509745F) /*  141 */,
+    CONST64(0x423777BBE6DAB3D6) /*  142 */, CONST64(0xD1661C7EAEF06EB5) /*  143 */,
+    CONST64(0xA1781F354DAACFD8) /*  144 */, CONST64(0x2D11284A2B16AFFC) /*  145 */,
+    CONST64(0xF1FC4F67FA891D1F) /*  146 */, CONST64(0x73ECC25DCB920ADA) /*  147 */,
+    CONST64(0xAE610C22C2A12651) /*  148 */, CONST64(0x96E0A810D356B78A) /*  149 */,
+    CONST64(0x5A9A381F2FE7870F) /*  150 */, CONST64(0xD5AD62EDE94E5530) /*  151 */,
+    CONST64(0xD225E5E8368D1427) /*  152 */, CONST64(0x65977B70C7AF4631) /*  153 */,
+    CONST64(0x99F889B2DE39D74F) /*  154 */, CONST64(0x233F30BF54E1D143) /*  155 */,
+    CONST64(0x9A9675D3D9A63C97) /*  156 */, CONST64(0x5470554FF334F9A8) /*  157 */,
+    CONST64(0x166ACB744A4F5688) /*  158 */, CONST64(0x70C74CAAB2E4AEAD) /*  159 */,
+    CONST64(0xF0D091646F294D12) /*  160 */, CONST64(0x57B82A89684031D1) /*  161 */,
+    CONST64(0xEFD95A5A61BE0B6B) /*  162 */, CONST64(0x2FBD12E969F2F29A) /*  163 */,
+    CONST64(0x9BD37013FEFF9FE8) /*  164 */, CONST64(0x3F9B0404D6085A06) /*  165 */,
+    CONST64(0x4940C1F3166CFE15) /*  166 */, CONST64(0x09542C4DCDF3DEFB) /*  167 */,
+    CONST64(0xB4C5218385CD5CE3) /*  168 */, CONST64(0xC935B7DC4462A641) /*  169 */,
+    CONST64(0x3417F8A68ED3B63F) /*  170 */, CONST64(0xB80959295B215B40) /*  171 */,
+    CONST64(0xF99CDAEF3B8C8572) /*  172 */, CONST64(0x018C0614F8FCB95D) /*  173 */,
+    CONST64(0x1B14ACCD1A3ACDF3) /*  174 */, CONST64(0x84D471F200BB732D) /*  175 */,
+    CONST64(0xC1A3110E95E8DA16) /*  176 */, CONST64(0x430A7220BF1A82B8) /*  177 */,
+    CONST64(0xB77E090D39DF210E) /*  178 */, CONST64(0x5EF4BD9F3CD05E9D) /*  179 */,
+    CONST64(0x9D4FF6DA7E57A444) /*  180 */, CONST64(0xDA1D60E183D4A5F8) /*  181 */,
+    CONST64(0xB287C38417998E47) /*  182 */, CONST64(0xFE3EDC121BB31886) /*  183 */,
+    CONST64(0xC7FE3CCC980CCBEF) /*  184 */, CONST64(0xE46FB590189BFD03) /*  185 */,
+    CONST64(0x3732FD469A4C57DC) /*  186 */, CONST64(0x7EF700A07CF1AD65) /*  187 */,
+    CONST64(0x59C64468A31D8859) /*  188 */, CONST64(0x762FB0B4D45B61F6) /*  189 */,
+    CONST64(0x155BAED099047718) /*  190 */, CONST64(0x68755E4C3D50BAA6) /*  191 */,
+    CONST64(0xE9214E7F22D8B4DF) /*  192 */, CONST64(0x2ADDBF532EAC95F4) /*  193 */,
+    CONST64(0x32AE3909B4BD0109) /*  194 */, CONST64(0x834DF537B08E3450) /*  195 */,
+    CONST64(0xFA209DA84220728D) /*  196 */, CONST64(0x9E691D9B9EFE23F7) /*  197 */,
+    CONST64(0x0446D288C4AE8D7F) /*  198 */, CONST64(0x7B4CC524E169785B) /*  199 */,
+    CONST64(0x21D87F0135CA1385) /*  200 */, CONST64(0xCEBB400F137B8AA5) /*  201 */,
+    CONST64(0x272E2B66580796BE) /*  202 */, CONST64(0x3612264125C2B0DE) /*  203 */,
+    CONST64(0x057702BDAD1EFBB2) /*  204 */, CONST64(0xD4BABB8EACF84BE9) /*  205 */,
+    CONST64(0x91583139641BC67B) /*  206 */, CONST64(0x8BDC2DE08036E024) /*  207 */,
+    CONST64(0x603C8156F49F68ED) /*  208 */, CONST64(0xF7D236F7DBEF5111) /*  209 */,
+    CONST64(0x9727C4598AD21E80) /*  210 */, CONST64(0xA08A0896670A5FD7) /*  211 */,
+    CONST64(0xCB4A8F4309EBA9CB) /*  212 */, CONST64(0x81AF564B0F7036A1) /*  213 */,
+    CONST64(0xC0B99AA778199ABD) /*  214 */, CONST64(0x959F1EC83FC8E952) /*  215 */,
+    CONST64(0x8C505077794A81B9) /*  216 */, CONST64(0x3ACAAF8F056338F0) /*  217 */,
+    CONST64(0x07B43F50627A6778) /*  218 */, CONST64(0x4A44AB49F5ECCC77) /*  219 */,
+    CONST64(0x3BC3D6E4B679EE98) /*  220 */, CONST64(0x9CC0D4D1CF14108C) /*  221 */,
+    CONST64(0x4406C00B206BC8A0) /*  222 */, CONST64(0x82A18854C8D72D89) /*  223 */,
+    CONST64(0x67E366B35C3C432C) /*  224 */, CONST64(0xB923DD61102B37F2) /*  225 */,
+    CONST64(0x56AB2779D884271D) /*  226 */, CONST64(0xBE83E1B0FF1525AF) /*  227 */,
+    CONST64(0xFB7C65D4217E49A9) /*  228 */, CONST64(0x6BDBE0E76D48E7D4) /*  229 */,
+    CONST64(0x08DF828745D9179E) /*  230 */, CONST64(0x22EA6A9ADD53BD34) /*  231 */,
+    CONST64(0xE36E141C5622200A) /*  232 */, CONST64(0x7F805D1B8CB750EE) /*  233 */,
+    CONST64(0xAFE5C7A59F58E837) /*  234 */, CONST64(0xE27F996A4FB1C23C) /*  235 */,
+    CONST64(0xD3867DFB0775F0D0) /*  236 */, CONST64(0xD0E673DE6E88891A) /*  237 */,
+    CONST64(0x123AEB9EAFB86C25) /*  238 */, CONST64(0x30F1D5D5C145B895) /*  239 */,
+    CONST64(0xBB434A2DEE7269E7) /*  240 */, CONST64(0x78CB67ECF931FA38) /*  241 */,
+    CONST64(0xF33B0372323BBF9C) /*  242 */, CONST64(0x52D66336FB279C74) /*  243 */,
+    CONST64(0x505F33AC0AFB4EAA) /*  244 */, CONST64(0xE8A5CD99A2CCE187) /*  245 */,
+    CONST64(0x534974801E2D30BB) /*  246 */, CONST64(0x8D2D5711D5876D90) /*  247 */,
+    CONST64(0x1F1A412891BC038E) /*  248 */, CONST64(0xD6E2E71D82E56648) /*  249 */,
+    CONST64(0x74036C3A497732B7) /*  250 */, CONST64(0x89B67ED96361F5AB) /*  251 */,
+    CONST64(0xFFED95D8F1EA02A2) /*  252 */, CONST64(0xE72B3BD61464D43D) /*  253 */,
+    CONST64(0xA6300F170BDC4820) /*  254 */, CONST64(0xEBC18760ED78A77A) /*  255 */,
+    CONST64(0xE6A6BE5A05A12138) /*  256 */, CONST64(0xB5A122A5B4F87C98) /*  257 */,
+    CONST64(0x563C6089140B6990) /*  258 */, CONST64(0x4C46CB2E391F5DD5) /*  259 */,
+    CONST64(0xD932ADDBC9B79434) /*  260 */, CONST64(0x08EA70E42015AFF5) /*  261 */,
+    CONST64(0xD765A6673E478CF1) /*  262 */, CONST64(0xC4FB757EAB278D99) /*  263 */,
+    CONST64(0xDF11C6862D6E0692) /*  264 */, CONST64(0xDDEB84F10D7F3B16) /*  265 */,
+    CONST64(0x6F2EF604A665EA04) /*  266 */, CONST64(0x4A8E0F0FF0E0DFB3) /*  267 */,
+    CONST64(0xA5EDEEF83DBCBA51) /*  268 */, CONST64(0xFC4F0A2A0EA4371E) /*  269 */,
+    CONST64(0xE83E1DA85CB38429) /*  270 */, CONST64(0xDC8FF882BA1B1CE2) /*  271 */,
+    CONST64(0xCD45505E8353E80D) /*  272 */, CONST64(0x18D19A00D4DB0717) /*  273 */,
+    CONST64(0x34A0CFEDA5F38101) /*  274 */, CONST64(0x0BE77E518887CAF2) /*  275 */,
+    CONST64(0x1E341438B3C45136) /*  276 */, CONST64(0xE05797F49089CCF9) /*  277 */,
+    CONST64(0xFFD23F9DF2591D14) /*  278 */, CONST64(0x543DDA228595C5CD) /*  279 */,
+    CONST64(0x661F81FD99052A33) /*  280 */, CONST64(0x8736E641DB0F7B76) /*  281 */,
+    CONST64(0x15227725418E5307) /*  282 */, CONST64(0xE25F7F46162EB2FA) /*  283 */,
+    CONST64(0x48A8B2126C13D9FE) /*  284 */, CONST64(0xAFDC541792E76EEA) /*  285 */,
+    CONST64(0x03D912BFC6D1898F) /*  286 */, CONST64(0x31B1AAFA1B83F51B) /*  287 */,
+    CONST64(0xF1AC2796E42AB7D9) /*  288 */, CONST64(0x40A3A7D7FCD2EBAC) /*  289 */,
+    CONST64(0x1056136D0AFBBCC5) /*  290 */, CONST64(0x7889E1DD9A6D0C85) /*  291 */,
+    CONST64(0xD33525782A7974AA) /*  292 */, CONST64(0xA7E25D09078AC09B) /*  293 */,
+    CONST64(0xBD4138B3EAC6EDD0) /*  294 */, CONST64(0x920ABFBE71EB9E70) /*  295 */,
+    CONST64(0xA2A5D0F54FC2625C) /*  296 */, CONST64(0xC054E36B0B1290A3) /*  297 */,
+    CONST64(0xF6DD59FF62FE932B) /*  298 */, CONST64(0x3537354511A8AC7D) /*  299 */,
+    CONST64(0xCA845E9172FADCD4) /*  300 */, CONST64(0x84F82B60329D20DC) /*  301 */,
+    CONST64(0x79C62CE1CD672F18) /*  302 */, CONST64(0x8B09A2ADD124642C) /*  303 */,
+    CONST64(0xD0C1E96A19D9E726) /*  304 */, CONST64(0x5A786A9B4BA9500C) /*  305 */,
+    CONST64(0x0E020336634C43F3) /*  306 */, CONST64(0xC17B474AEB66D822) /*  307 */,
+    CONST64(0x6A731AE3EC9BAAC2) /*  308 */, CONST64(0x8226667AE0840258) /*  309 */,
+    CONST64(0x67D4567691CAECA5) /*  310 */, CONST64(0x1D94155C4875ADB5) /*  311 */,
+    CONST64(0x6D00FD985B813FDF) /*  312 */, CONST64(0x51286EFCB774CD06) /*  313 */,
+    CONST64(0x5E8834471FA744AF) /*  314 */, CONST64(0xF72CA0AEE761AE2E) /*  315 */,
+    CONST64(0xBE40E4CDAEE8E09A) /*  316 */, CONST64(0xE9970BBB5118F665) /*  317 */,
+    CONST64(0x726E4BEB33DF1964) /*  318 */, CONST64(0x703B000729199762) /*  319 */,
+    CONST64(0x4631D816F5EF30A7) /*  320 */, CONST64(0xB880B5B51504A6BE) /*  321 */,
+    CONST64(0x641793C37ED84B6C) /*  322 */, CONST64(0x7B21ED77F6E97D96) /*  323 */,
+    CONST64(0x776306312EF96B73) /*  324 */, CONST64(0xAE528948E86FF3F4) /*  325 */,
+    CONST64(0x53DBD7F286A3F8F8) /*  326 */, CONST64(0x16CADCE74CFC1063) /*  327 */,
+    CONST64(0x005C19BDFA52C6DD) /*  328 */, CONST64(0x68868F5D64D46AD3) /*  329 */,
+    CONST64(0x3A9D512CCF1E186A) /*  330 */, CONST64(0x367E62C2385660AE) /*  331 */,
+    CONST64(0xE359E7EA77DCB1D7) /*  332 */, CONST64(0x526C0773749ABE6E) /*  333 */,
+    CONST64(0x735AE5F9D09F734B) /*  334 */, CONST64(0x493FC7CC8A558BA8) /*  335 */,
+    CONST64(0xB0B9C1533041AB45) /*  336 */, CONST64(0x321958BA470A59BD) /*  337 */,
+    CONST64(0x852DB00B5F46C393) /*  338 */, CONST64(0x91209B2BD336B0E5) /*  339 */,
+    CONST64(0x6E604F7D659EF19F) /*  340 */, CONST64(0xB99A8AE2782CCB24) /*  341 */,
+    CONST64(0xCCF52AB6C814C4C7) /*  342 */, CONST64(0x4727D9AFBE11727B) /*  343 */,
+    CONST64(0x7E950D0C0121B34D) /*  344 */, CONST64(0x756F435670AD471F) /*  345 */,
+    CONST64(0xF5ADD442615A6849) /*  346 */, CONST64(0x4E87E09980B9957A) /*  347 */,
+    CONST64(0x2ACFA1DF50AEE355) /*  348 */, CONST64(0xD898263AFD2FD556) /*  349 */,
+    CONST64(0xC8F4924DD80C8FD6) /*  350 */, CONST64(0xCF99CA3D754A173A) /*  351 */,
+    CONST64(0xFE477BACAF91BF3C) /*  352 */, CONST64(0xED5371F6D690C12D) /*  353 */,
+    CONST64(0x831A5C285E687094) /*  354 */, CONST64(0xC5D3C90A3708A0A4) /*  355 */,
+    CONST64(0x0F7F903717D06580) /*  356 */, CONST64(0x19F9BB13B8FDF27F) /*  357 */,
+    CONST64(0xB1BD6F1B4D502843) /*  358 */, CONST64(0x1C761BA38FFF4012) /*  359 */,
+    CONST64(0x0D1530C4E2E21F3B) /*  360 */, CONST64(0x8943CE69A7372C8A) /*  361 */,
+    CONST64(0xE5184E11FEB5CE66) /*  362 */, CONST64(0x618BDB80BD736621) /*  363 */,
+    CONST64(0x7D29BAD68B574D0B) /*  364 */, CONST64(0x81BB613E25E6FE5B) /*  365 */,
+    CONST64(0x071C9C10BC07913F) /*  366 */, CONST64(0xC7BEEB7909AC2D97) /*  367 */,
+    CONST64(0xC3E58D353BC5D757) /*  368 */, CONST64(0xEB017892F38F61E8) /*  369 */,
+    CONST64(0xD4EFFB9C9B1CC21A) /*  370 */, CONST64(0x99727D26F494F7AB) /*  371 */,
+    CONST64(0xA3E063A2956B3E03) /*  372 */, CONST64(0x9D4A8B9A4AA09C30) /*  373 */,
+    CONST64(0x3F6AB7D500090FB4) /*  374 */, CONST64(0x9CC0F2A057268AC0) /*  375 */,
+    CONST64(0x3DEE9D2DEDBF42D1) /*  376 */, CONST64(0x330F49C87960A972) /*  377 */,
+    CONST64(0xC6B2720287421B41) /*  378 */, CONST64(0x0AC59EC07C00369C) /*  379 */,
+    CONST64(0xEF4EAC49CB353425) /*  380 */, CONST64(0xF450244EEF0129D8) /*  381 */,
+    CONST64(0x8ACC46E5CAF4DEB6) /*  382 */, CONST64(0x2FFEAB63989263F7) /*  383 */,
+    CONST64(0x8F7CB9FE5D7A4578) /*  384 */, CONST64(0x5BD8F7644E634635) /*  385 */,
+    CONST64(0x427A7315BF2DC900) /*  386 */, CONST64(0x17D0C4AA2125261C) /*  387 */,
+    CONST64(0x3992486C93518E50) /*  388 */, CONST64(0xB4CBFEE0A2D7D4C3) /*  389 */,
+    CONST64(0x7C75D6202C5DDD8D) /*  390 */, CONST64(0xDBC295D8E35B6C61) /*  391 */,
+    CONST64(0x60B369D302032B19) /*  392 */, CONST64(0xCE42685FDCE44132) /*  393 */,
+    CONST64(0x06F3DDB9DDF65610) /*  394 */, CONST64(0x8EA4D21DB5E148F0) /*  395 */,
+    CONST64(0x20B0FCE62FCD496F) /*  396 */, CONST64(0x2C1B912358B0EE31) /*  397 */,
+    CONST64(0xB28317B818F5A308) /*  398 */, CONST64(0xA89C1E189CA6D2CF) /*  399 */,
+    CONST64(0x0C6B18576AAADBC8) /*  400 */, CONST64(0xB65DEAA91299FAE3) /*  401 */,
+    CONST64(0xFB2B794B7F1027E7) /*  402 */, CONST64(0x04E4317F443B5BEB) /*  403 */,
+    CONST64(0x4B852D325939D0A6) /*  404 */, CONST64(0xD5AE6BEEFB207FFC) /*  405 */,
+    CONST64(0x309682B281C7D374) /*  406 */, CONST64(0xBAE309A194C3B475) /*  407 */,
+    CONST64(0x8CC3F97B13B49F05) /*  408 */, CONST64(0x98A9422FF8293967) /*  409 */,
+    CONST64(0x244B16B01076FF7C) /*  410 */, CONST64(0xF8BF571C663D67EE) /*  411 */,
+    CONST64(0x1F0D6758EEE30DA1) /*  412 */, CONST64(0xC9B611D97ADEB9B7) /*  413 */,
+    CONST64(0xB7AFD5887B6C57A2) /*  414 */, CONST64(0x6290AE846B984FE1) /*  415 */,
+    CONST64(0x94DF4CDEACC1A5FD) /*  416 */, CONST64(0x058A5BD1C5483AFF) /*  417 */,
+    CONST64(0x63166CC142BA3C37) /*  418 */, CONST64(0x8DB8526EB2F76F40) /*  419 */,
+    CONST64(0xE10880036F0D6D4E) /*  420 */, CONST64(0x9E0523C9971D311D) /*  421 */,
+    CONST64(0x45EC2824CC7CD691) /*  422 */, CONST64(0x575B8359E62382C9) /*  423 */,
+    CONST64(0xFA9E400DC4889995) /*  424 */, CONST64(0xD1823ECB45721568) /*  425 */,
+    CONST64(0xDAFD983B8206082F) /*  426 */, CONST64(0xAA7D29082386A8CB) /*  427 */,
+    CONST64(0x269FCD4403B87588) /*  428 */, CONST64(0x1B91F5F728BDD1E0) /*  429 */,
+    CONST64(0xE4669F39040201F6) /*  430 */, CONST64(0x7A1D7C218CF04ADE) /*  431 */,
+    CONST64(0x65623C29D79CE5CE) /*  432 */, CONST64(0x2368449096C00BB1) /*  433 */,
+    CONST64(0xAB9BF1879DA503BA) /*  434 */, CONST64(0xBC23ECB1A458058E) /*  435 */,
+    CONST64(0x9A58DF01BB401ECC) /*  436 */, CONST64(0xA070E868A85F143D) /*  437 */,
+    CONST64(0x4FF188307DF2239E) /*  438 */, CONST64(0x14D565B41A641183) /*  439 */,
+    CONST64(0xEE13337452701602) /*  440 */, CONST64(0x950E3DCF3F285E09) /*  441 */,
+    CONST64(0x59930254B9C80953) /*  442 */, CONST64(0x3BF299408930DA6D) /*  443 */,
+    CONST64(0xA955943F53691387) /*  444 */, CONST64(0xA15EDECAA9CB8784) /*  445 */,
+    CONST64(0x29142127352BE9A0) /*  446 */, CONST64(0x76F0371FFF4E7AFB) /*  447 */,
+    CONST64(0x0239F450274F2228) /*  448 */, CONST64(0xBB073AF01D5E868B) /*  449 */,
+    CONST64(0xBFC80571C10E96C1) /*  450 */, CONST64(0xD267088568222E23) /*  451 */,
+    CONST64(0x9671A3D48E80B5B0) /*  452 */, CONST64(0x55B5D38AE193BB81) /*  453 */,
+    CONST64(0x693AE2D0A18B04B8) /*  454 */, CONST64(0x5C48B4ECADD5335F) /*  455 */,
+    CONST64(0xFD743B194916A1CA) /*  456 */, CONST64(0x2577018134BE98C4) /*  457 */,
+    CONST64(0xE77987E83C54A4AD) /*  458 */, CONST64(0x28E11014DA33E1B9) /*  459 */,
+    CONST64(0x270CC59E226AA213) /*  460 */, CONST64(0x71495F756D1A5F60) /*  461 */,
+    CONST64(0x9BE853FB60AFEF77) /*  462 */, CONST64(0xADC786A7F7443DBF) /*  463 */,
+    CONST64(0x0904456173B29A82) /*  464 */, CONST64(0x58BC7A66C232BD5E) /*  465 */,
+    CONST64(0xF306558C673AC8B2) /*  466 */, CONST64(0x41F639C6B6C9772A) /*  467 */,
+    CONST64(0x216DEFE99FDA35DA) /*  468 */, CONST64(0x11640CC71C7BE615) /*  469 */,
+    CONST64(0x93C43694565C5527) /*  470 */, CONST64(0xEA038E6246777839) /*  471 */,
+    CONST64(0xF9ABF3CE5A3E2469) /*  472 */, CONST64(0x741E768D0FD312D2) /*  473 */,
+    CONST64(0x0144B883CED652C6) /*  474 */, CONST64(0xC20B5A5BA33F8552) /*  475 */,
+    CONST64(0x1AE69633C3435A9D) /*  476 */, CONST64(0x97A28CA4088CFDEC) /*  477 */,
+    CONST64(0x8824A43C1E96F420) /*  478 */, CONST64(0x37612FA66EEEA746) /*  479 */,
+    CONST64(0x6B4CB165F9CF0E5A) /*  480 */, CONST64(0x43AA1C06A0ABFB4A) /*  481 */,
+    CONST64(0x7F4DC26FF162796B) /*  482 */, CONST64(0x6CBACC8E54ED9B0F) /*  483 */,
+    CONST64(0xA6B7FFEFD2BB253E) /*  484 */, CONST64(0x2E25BC95B0A29D4F) /*  485 */,
+    CONST64(0x86D6A58BDEF1388C) /*  486 */, CONST64(0xDED74AC576B6F054) /*  487 */,
+    CONST64(0x8030BDBC2B45805D) /*  488 */, CONST64(0x3C81AF70E94D9289) /*  489 */,
+    CONST64(0x3EFF6DDA9E3100DB) /*  490 */, CONST64(0xB38DC39FDFCC8847) /*  491 */,
+    CONST64(0x123885528D17B87E) /*  492 */, CONST64(0xF2DA0ED240B1B642) /*  493 */,
+    CONST64(0x44CEFADCD54BF9A9) /*  494 */, CONST64(0x1312200E433C7EE6) /*  495 */,
+    CONST64(0x9FFCC84F3A78C748) /*  496 */, CONST64(0xF0CD1F72248576BB) /*  497 */,
+    CONST64(0xEC6974053638CFE4) /*  498 */, CONST64(0x2BA7B67C0CEC4E4C) /*  499 */,
+    CONST64(0xAC2F4DF3E5CE32ED) /*  500 */, CONST64(0xCB33D14326EA4C11) /*  501 */,
+    CONST64(0xA4E9044CC77E58BC) /*  502 */, CONST64(0x5F513293D934FCEF) /*  503 */,
+    CONST64(0x5DC9645506E55444) /*  504 */, CONST64(0x50DE418F317DE40A) /*  505 */,
+    CONST64(0x388CB31A69DDE259) /*  506 */, CONST64(0x2DB4A83455820A86) /*  507 */,
+    CONST64(0x9010A91E84711AE9) /*  508 */, CONST64(0x4DF7F0B7B1498371) /*  509 */,
+    CONST64(0xD62A2EABC0977179) /*  510 */, CONST64(0x22FAC097AA8D5C0E) /*  511 */,
+    CONST64(0xF49FCC2FF1DAF39B) /*  512 */, CONST64(0x487FD5C66FF29281) /*  513 */,
+    CONST64(0xE8A30667FCDCA83F) /*  514 */, CONST64(0x2C9B4BE3D2FCCE63) /*  515 */,
+    CONST64(0xDA3FF74B93FBBBC2) /*  516 */, CONST64(0x2FA165D2FE70BA66) /*  517 */,
+    CONST64(0xA103E279970E93D4) /*  518 */, CONST64(0xBECDEC77B0E45E71) /*  519 */,
+    CONST64(0xCFB41E723985E497) /*  520 */, CONST64(0xB70AAA025EF75017) /*  521 */,
+    CONST64(0xD42309F03840B8E0) /*  522 */, CONST64(0x8EFC1AD035898579) /*  523 */,
+    CONST64(0x96C6920BE2B2ABC5) /*  524 */, CONST64(0x66AF4163375A9172) /*  525 */,
+    CONST64(0x2174ABDCCA7127FB) /*  526 */, CONST64(0xB33CCEA64A72FF41) /*  527 */,
+    CONST64(0xF04A4933083066A5) /*  528 */, CONST64(0x8D970ACDD7289AF5) /*  529 */,
+    CONST64(0x8F96E8E031C8C25E) /*  530 */, CONST64(0xF3FEC02276875D47) /*  531 */,
+    CONST64(0xEC7BF310056190DD) /*  532 */, CONST64(0xF5ADB0AEBB0F1491) /*  533 */,
+    CONST64(0x9B50F8850FD58892) /*  534 */, CONST64(0x4975488358B74DE8) /*  535 */,
+    CONST64(0xA3354FF691531C61) /*  536 */, CONST64(0x0702BBE481D2C6EE) /*  537 */,
+    CONST64(0x89FB24057DEDED98) /*  538 */, CONST64(0xAC3075138596E902) /*  539 */,
+    CONST64(0x1D2D3580172772ED) /*  540 */, CONST64(0xEB738FC28E6BC30D) /*  541 */,
+    CONST64(0x5854EF8F63044326) /*  542 */, CONST64(0x9E5C52325ADD3BBE) /*  543 */,
+    CONST64(0x90AA53CF325C4623) /*  544 */, CONST64(0xC1D24D51349DD067) /*  545 */,
+    CONST64(0x2051CFEEA69EA624) /*  546 */, CONST64(0x13220F0A862E7E4F) /*  547 */,
+    CONST64(0xCE39399404E04864) /*  548 */, CONST64(0xD9C42CA47086FCB7) /*  549 */,
+    CONST64(0x685AD2238A03E7CC) /*  550 */, CONST64(0x066484B2AB2FF1DB) /*  551 */,
+    CONST64(0xFE9D5D70EFBF79EC) /*  552 */, CONST64(0x5B13B9DD9C481854) /*  553 */,
+    CONST64(0x15F0D475ED1509AD) /*  554 */, CONST64(0x0BEBCD060EC79851) /*  555 */,
+    CONST64(0xD58C6791183AB7F8) /*  556 */, CONST64(0xD1187C5052F3EEE4) /*  557 */,
+    CONST64(0xC95D1192E54E82FF) /*  558 */, CONST64(0x86EEA14CB9AC6CA2) /*  559 */,
+    CONST64(0x3485BEB153677D5D) /*  560 */, CONST64(0xDD191D781F8C492A) /*  561 */,
+    CONST64(0xF60866BAA784EBF9) /*  562 */, CONST64(0x518F643BA2D08C74) /*  563 */,
+    CONST64(0x8852E956E1087C22) /*  564 */, CONST64(0xA768CB8DC410AE8D) /*  565 */,
+    CONST64(0x38047726BFEC8E1A) /*  566 */, CONST64(0xA67738B4CD3B45AA) /*  567 */,
+    CONST64(0xAD16691CEC0DDE19) /*  568 */, CONST64(0xC6D4319380462E07) /*  569 */,
+    CONST64(0xC5A5876D0BA61938) /*  570 */, CONST64(0x16B9FA1FA58FD840) /*  571 */,
+    CONST64(0x188AB1173CA74F18) /*  572 */, CONST64(0xABDA2F98C99C021F) /*  573 */,
+    CONST64(0x3E0580AB134AE816) /*  574 */, CONST64(0x5F3B05B773645ABB) /*  575 */,
+    CONST64(0x2501A2BE5575F2F6) /*  576 */, CONST64(0x1B2F74004E7E8BA9) /*  577 */,
+    CONST64(0x1CD7580371E8D953) /*  578 */, CONST64(0x7F6ED89562764E30) /*  579 */,
+    CONST64(0xB15926FF596F003D) /*  580 */, CONST64(0x9F65293DA8C5D6B9) /*  581 */,
+    CONST64(0x6ECEF04DD690F84C) /*  582 */, CONST64(0x4782275FFF33AF88) /*  583 */,
+    CONST64(0xE41433083F820801) /*  584 */, CONST64(0xFD0DFE409A1AF9B5) /*  585 */,
+    CONST64(0x4325A3342CDB396B) /*  586 */, CONST64(0x8AE77E62B301B252) /*  587 */,
+    CONST64(0xC36F9E9F6655615A) /*  588 */, CONST64(0x85455A2D92D32C09) /*  589 */,
+    CONST64(0xF2C7DEA949477485) /*  590 */, CONST64(0x63CFB4C133A39EBA) /*  591 */,
+    CONST64(0x83B040CC6EBC5462) /*  592 */, CONST64(0x3B9454C8FDB326B0) /*  593 */,
+    CONST64(0x56F56A9E87FFD78C) /*  594 */, CONST64(0x2DC2940D99F42BC6) /*  595 */,
+    CONST64(0x98F7DF096B096E2D) /*  596 */, CONST64(0x19A6E01E3AD852BF) /*  597 */,
+    CONST64(0x42A99CCBDBD4B40B) /*  598 */, CONST64(0xA59998AF45E9C559) /*  599 */,
+    CONST64(0x366295E807D93186) /*  600 */, CONST64(0x6B48181BFAA1F773) /*  601 */,
+    CONST64(0x1FEC57E2157A0A1D) /*  602 */, CONST64(0x4667446AF6201AD5) /*  603 */,
+    CONST64(0xE615EBCACFB0F075) /*  604 */, CONST64(0xB8F31F4F68290778) /*  605 */,
+    CONST64(0x22713ED6CE22D11E) /*  606 */, CONST64(0x3057C1A72EC3C93B) /*  607 */,
+    CONST64(0xCB46ACC37C3F1F2F) /*  608 */, CONST64(0xDBB893FD02AAF50E) /*  609 */,
+    CONST64(0x331FD92E600B9FCF) /*  610 */, CONST64(0xA498F96148EA3AD6) /*  611 */,
+    CONST64(0xA8D8426E8B6A83EA) /*  612 */, CONST64(0xA089B274B7735CDC) /*  613 */,
+    CONST64(0x87F6B3731E524A11) /*  614 */, CONST64(0x118808E5CBC96749) /*  615 */,
+    CONST64(0x9906E4C7B19BD394) /*  616 */, CONST64(0xAFED7F7E9B24A20C) /*  617 */,
+    CONST64(0x6509EADEEB3644A7) /*  618 */, CONST64(0x6C1EF1D3E8EF0EDE) /*  619 */,
+    CONST64(0xB9C97D43E9798FB4) /*  620 */, CONST64(0xA2F2D784740C28A3) /*  621 */,
+    CONST64(0x7B8496476197566F) /*  622 */, CONST64(0x7A5BE3E6B65F069D) /*  623 */,
+    CONST64(0xF96330ED78BE6F10) /*  624 */, CONST64(0xEEE60DE77A076A15) /*  625 */,
+    CONST64(0x2B4BEE4AA08B9BD0) /*  626 */, CONST64(0x6A56A63EC7B8894E) /*  627 */,
+    CONST64(0x02121359BA34FEF4) /*  628 */, CONST64(0x4CBF99F8283703FC) /*  629 */,
+    CONST64(0x398071350CAF30C8) /*  630 */, CONST64(0xD0A77A89F017687A) /*  631 */,
+    CONST64(0xF1C1A9EB9E423569) /*  632 */, CONST64(0x8C7976282DEE8199) /*  633 */,
+    CONST64(0x5D1737A5DD1F7ABD) /*  634 */, CONST64(0x4F53433C09A9FA80) /*  635 */,
+    CONST64(0xFA8B0C53DF7CA1D9) /*  636 */, CONST64(0x3FD9DCBC886CCB77) /*  637 */,
+    CONST64(0xC040917CA91B4720) /*  638 */, CONST64(0x7DD00142F9D1DCDF) /*  639 */,
+    CONST64(0x8476FC1D4F387B58) /*  640 */, CONST64(0x23F8E7C5F3316503) /*  641 */,
+    CONST64(0x032A2244E7E37339) /*  642 */, CONST64(0x5C87A5D750F5A74B) /*  643 */,
+    CONST64(0x082B4CC43698992E) /*  644 */, CONST64(0xDF917BECB858F63C) /*  645 */,
+    CONST64(0x3270B8FC5BF86DDA) /*  646 */, CONST64(0x10AE72BB29B5DD76) /*  647 */,
+    CONST64(0x576AC94E7700362B) /*  648 */, CONST64(0x1AD112DAC61EFB8F) /*  649 */,
+    CONST64(0x691BC30EC5FAA427) /*  650 */, CONST64(0xFF246311CC327143) /*  651 */,
+    CONST64(0x3142368E30E53206) /*  652 */, CONST64(0x71380E31E02CA396) /*  653 */,
+    CONST64(0x958D5C960AAD76F1) /*  654 */, CONST64(0xF8D6F430C16DA536) /*  655 */,
+    CONST64(0xC8FFD13F1BE7E1D2) /*  656 */, CONST64(0x7578AE66004DDBE1) /*  657 */,
+    CONST64(0x05833F01067BE646) /*  658 */, CONST64(0xBB34B5AD3BFE586D) /*  659 */,
+    CONST64(0x095F34C9A12B97F0) /*  660 */, CONST64(0x247AB64525D60CA8) /*  661 */,
+    CONST64(0xDCDBC6F3017477D1) /*  662 */, CONST64(0x4A2E14D4DECAD24D) /*  663 */,
+    CONST64(0xBDB5E6D9BE0A1EEB) /*  664 */, CONST64(0x2A7E70F7794301AB) /*  665 */,
+    CONST64(0xDEF42D8A270540FD) /*  666 */, CONST64(0x01078EC0A34C22C1) /*  667 */,
+    CONST64(0xE5DE511AF4C16387) /*  668 */, CONST64(0x7EBB3A52BD9A330A) /*  669 */,
+    CONST64(0x77697857AA7D6435) /*  670 */, CONST64(0x004E831603AE4C32) /*  671 */,
+    CONST64(0xE7A21020AD78E312) /*  672 */, CONST64(0x9D41A70C6AB420F2) /*  673 */,
+    CONST64(0x28E06C18EA1141E6) /*  674 */, CONST64(0xD2B28CBD984F6B28) /*  675 */,
+    CONST64(0x26B75F6C446E9D83) /*  676 */, CONST64(0xBA47568C4D418D7F) /*  677 */,
+    CONST64(0xD80BADBFE6183D8E) /*  678 */, CONST64(0x0E206D7F5F166044) /*  679 */,
+    CONST64(0xE258A43911CBCA3E) /*  680 */, CONST64(0x723A1746B21DC0BC) /*  681 */,
+    CONST64(0xC7CAA854F5D7CDD3) /*  682 */, CONST64(0x7CAC32883D261D9C) /*  683 */,
+    CONST64(0x7690C26423BA942C) /*  684 */, CONST64(0x17E55524478042B8) /*  685 */,
+    CONST64(0xE0BE477656A2389F) /*  686 */, CONST64(0x4D289B5E67AB2DA0) /*  687 */,
+    CONST64(0x44862B9C8FBBFD31) /*  688 */, CONST64(0xB47CC8049D141365) /*  689 */,
+    CONST64(0x822C1B362B91C793) /*  690 */, CONST64(0x4EB14655FB13DFD8) /*  691 */,
+    CONST64(0x1ECBBA0714E2A97B) /*  692 */, CONST64(0x6143459D5CDE5F14) /*  693 */,
+    CONST64(0x53A8FBF1D5F0AC89) /*  694 */, CONST64(0x97EA04D81C5E5B00) /*  695 */,
+    CONST64(0x622181A8D4FDB3F3) /*  696 */, CONST64(0xE9BCD341572A1208) /*  697 */,
+    CONST64(0x1411258643CCE58A) /*  698 */, CONST64(0x9144C5FEA4C6E0A4) /*  699 */,
+    CONST64(0x0D33D06565CF620F) /*  700 */, CONST64(0x54A48D489F219CA1) /*  701 */,
+    CONST64(0xC43E5EAC6D63C821) /*  702 */, CONST64(0xA9728B3A72770DAF) /*  703 */,
+    CONST64(0xD7934E7B20DF87EF) /*  704 */, CONST64(0xE35503B61A3E86E5) /*  705 */,
+    CONST64(0xCAE321FBC819D504) /*  706 */, CONST64(0x129A50B3AC60BFA6) /*  707 */,
+    CONST64(0xCD5E68EA7E9FB6C3) /*  708 */, CONST64(0xB01C90199483B1C7) /*  709 */,
+    CONST64(0x3DE93CD5C295376C) /*  710 */, CONST64(0xAED52EDF2AB9AD13) /*  711 */,
+    CONST64(0x2E60F512C0A07884) /*  712 */, CONST64(0xBC3D86A3E36210C9) /*  713 */,
+    CONST64(0x35269D9B163951CE) /*  714 */, CONST64(0x0C7D6E2AD0CDB5FA) /*  715 */,
+    CONST64(0x59E86297D87F5733) /*  716 */, CONST64(0x298EF221898DB0E7) /*  717 */,
+    CONST64(0x55000029D1A5AA7E) /*  718 */, CONST64(0x8BC08AE1B5061B45) /*  719 */,
+    CONST64(0xC2C31C2B6C92703A) /*  720 */, CONST64(0x94CC596BAF25EF42) /*  721 */,
+    CONST64(0x0A1D73DB22540456) /*  722 */, CONST64(0x04B6A0F9D9C4179A) /*  723 */,
+    CONST64(0xEFFDAFA2AE3D3C60) /*  724 */, CONST64(0xF7C8075BB49496C4) /*  725 */,
+    CONST64(0x9CC5C7141D1CD4E3) /*  726 */, CONST64(0x78BD1638218E5534) /*  727 */,
+    CONST64(0xB2F11568F850246A) /*  728 */, CONST64(0xEDFABCFA9502BC29) /*  729 */,
+    CONST64(0x796CE5F2DA23051B) /*  730 */, CONST64(0xAAE128B0DC93537C) /*  731 */,
+    CONST64(0x3A493DA0EE4B29AE) /*  732 */, CONST64(0xB5DF6B2C416895D7) /*  733 */,
+    CONST64(0xFCABBD25122D7F37) /*  734 */, CONST64(0x70810B58105DC4B1) /*  735 */,
+    CONST64(0xE10FDD37F7882A90) /*  736 */, CONST64(0x524DCAB5518A3F5C) /*  737 */,
+    CONST64(0x3C9E85878451255B) /*  738 */, CONST64(0x4029828119BD34E2) /*  739 */,
+    CONST64(0x74A05B6F5D3CECCB) /*  740 */, CONST64(0xB610021542E13ECA) /*  741 */,
+    CONST64(0x0FF979D12F59E2AC) /*  742 */, CONST64(0x6037DA27E4F9CC50) /*  743 */,
+    CONST64(0x5E92975A0DF1847D) /*  744 */, CONST64(0xD66DE190D3E623FE) /*  745 */,
+    CONST64(0x5032D6B87B568048) /*  746 */, CONST64(0x9A36B7CE8235216E) /*  747 */,
+    CONST64(0x80272A7A24F64B4A) /*  748 */, CONST64(0x93EFED8B8C6916F7) /*  749 */,
+    CONST64(0x37DDBFF44CCE1555) /*  750 */, CONST64(0x4B95DB5D4B99BD25) /*  751 */,
+    CONST64(0x92D3FDA169812FC0) /*  752 */, CONST64(0xFB1A4A9A90660BB6) /*  753 */,
+    CONST64(0x730C196946A4B9B2) /*  754 */, CONST64(0x81E289AA7F49DA68) /*  755 */,
+    CONST64(0x64669A0F83B1A05F) /*  756 */, CONST64(0x27B3FF7D9644F48B) /*  757 */,
+    CONST64(0xCC6B615C8DB675B3) /*  758 */, CONST64(0x674F20B9BCEBBE95) /*  759 */,
+    CONST64(0x6F31238275655982) /*  760 */, CONST64(0x5AE488713E45CF05) /*  761 */,
+    CONST64(0xBF619F9954C21157) /*  762 */, CONST64(0xEABAC46040A8EAE9) /*  763 */,
+    CONST64(0x454C6FE9F2C0C1CD) /*  764 */, CONST64(0x419CF6496412691C) /*  765 */,
+    CONST64(0xD3DC3BEF265B0F70) /*  766 */, CONST64(0x6D0E60F5C3578A9E) /*  767 */,
+    CONST64(0x5B0E608526323C55) /*  768 */, CONST64(0x1A46C1A9FA1B59F5) /*  769 */,
+    CONST64(0xA9E245A17C4C8FFA) /*  770 */, CONST64(0x65CA5159DB2955D7) /*  771 */,
+    CONST64(0x05DB0A76CE35AFC2) /*  772 */, CONST64(0x81EAC77EA9113D45) /*  773 */,
+    CONST64(0x528EF88AB6AC0A0D) /*  774 */, CONST64(0xA09EA253597BE3FF) /*  775 */,
+    CONST64(0x430DDFB3AC48CD56) /*  776 */, CONST64(0xC4B3A67AF45CE46F) /*  777 */,
+    CONST64(0x4ECECFD8FBE2D05E) /*  778 */, CONST64(0x3EF56F10B39935F0) /*  779 */,
+    CONST64(0x0B22D6829CD619C6) /*  780 */, CONST64(0x17FD460A74DF2069) /*  781 */,
+    CONST64(0x6CF8CC8E8510ED40) /*  782 */, CONST64(0xD6C824BF3A6ECAA7) /*  783 */,
+    CONST64(0x61243D581A817049) /*  784 */, CONST64(0x048BACB6BBC163A2) /*  785 */,
+    CONST64(0xD9A38AC27D44CC32) /*  786 */, CONST64(0x7FDDFF5BAAF410AB) /*  787 */,
+    CONST64(0xAD6D495AA804824B) /*  788 */, CONST64(0xE1A6A74F2D8C9F94) /*  789 */,
+    CONST64(0xD4F7851235DEE8E3) /*  790 */, CONST64(0xFD4B7F886540D893) /*  791 */,
+    CONST64(0x247C20042AA4BFDA) /*  792 */, CONST64(0x096EA1C517D1327C) /*  793 */,
+    CONST64(0xD56966B4361A6685) /*  794 */, CONST64(0x277DA5C31221057D) /*  795 */,
+    CONST64(0x94D59893A43ACFF7) /*  796 */, CONST64(0x64F0C51CCDC02281) /*  797 */,
+    CONST64(0x3D33BCC4FF6189DB) /*  798 */, CONST64(0xE005CB184CE66AF1) /*  799 */,
+    CONST64(0xFF5CCD1D1DB99BEA) /*  800 */, CONST64(0xB0B854A7FE42980F) /*  801 */,
+    CONST64(0x7BD46A6A718D4B9F) /*  802 */, CONST64(0xD10FA8CC22A5FD8C) /*  803 */,
+    CONST64(0xD31484952BE4BD31) /*  804 */, CONST64(0xC7FA975FCB243847) /*  805 */,
+    CONST64(0x4886ED1E5846C407) /*  806 */, CONST64(0x28CDDB791EB70B04) /*  807 */,
+    CONST64(0xC2B00BE2F573417F) /*  808 */, CONST64(0x5C9590452180F877) /*  809 */,
+    CONST64(0x7A6BDDFFF370EB00) /*  810 */, CONST64(0xCE509E38D6D9D6A4) /*  811 */,
+    CONST64(0xEBEB0F00647FA702) /*  812 */, CONST64(0x1DCC06CF76606F06) /*  813 */,
+    CONST64(0xE4D9F28BA286FF0A) /*  814 */, CONST64(0xD85A305DC918C262) /*  815 */,
+    CONST64(0x475B1D8732225F54) /*  816 */, CONST64(0x2D4FB51668CCB5FE) /*  817 */,
+    CONST64(0xA679B9D9D72BBA20) /*  818 */, CONST64(0x53841C0D912D43A5) /*  819 */,
+    CONST64(0x3B7EAA48BF12A4E8) /*  820 */, CONST64(0x781E0E47F22F1DDF) /*  821 */,
+    CONST64(0xEFF20CE60AB50973) /*  822 */, CONST64(0x20D261D19DFFB742) /*  823 */,
+    CONST64(0x16A12B03062A2E39) /*  824 */, CONST64(0x1960EB2239650495) /*  825 */,
+    CONST64(0x251C16FED50EB8B8) /*  826 */, CONST64(0x9AC0C330F826016E) /*  827 */,
+    CONST64(0xED152665953E7671) /*  828 */, CONST64(0x02D63194A6369570) /*  829 */,
+    CONST64(0x5074F08394B1C987) /*  830 */, CONST64(0x70BA598C90B25CE1) /*  831 */,
+    CONST64(0x794A15810B9742F6) /*  832 */, CONST64(0x0D5925E9FCAF8C6C) /*  833 */,
+    CONST64(0x3067716CD868744E) /*  834 */, CONST64(0x910AB077E8D7731B) /*  835 */,
+    CONST64(0x6A61BBDB5AC42F61) /*  836 */, CONST64(0x93513EFBF0851567) /*  837 */,
+    CONST64(0xF494724B9E83E9D5) /*  838 */, CONST64(0xE887E1985C09648D) /*  839 */,
+    CONST64(0x34B1D3C675370CFD) /*  840 */, CONST64(0xDC35E433BC0D255D) /*  841 */,
+    CONST64(0xD0AAB84234131BE0) /*  842 */, CONST64(0x08042A50B48B7EAF) /*  843 */,
+    CONST64(0x9997C4EE44A3AB35) /*  844 */, CONST64(0x829A7B49201799D0) /*  845 */,
+    CONST64(0x263B8307B7C54441) /*  846 */, CONST64(0x752F95F4FD6A6CA6) /*  847 */,
+    CONST64(0x927217402C08C6E5) /*  848 */, CONST64(0x2A8AB754A795D9EE) /*  849 */,
+    CONST64(0xA442F7552F72943D) /*  850 */, CONST64(0x2C31334E19781208) /*  851 */,
+    CONST64(0x4FA98D7CEAEE6291) /*  852 */, CONST64(0x55C3862F665DB309) /*  853 */,
+    CONST64(0xBD0610175D53B1F3) /*  854 */, CONST64(0x46FE6CB840413F27) /*  855 */,
+    CONST64(0x3FE03792DF0CFA59) /*  856 */, CONST64(0xCFE700372EB85E8F) /*  857 */,
+    CONST64(0xA7BE29E7ADBCE118) /*  858 */, CONST64(0xE544EE5CDE8431DD) /*  859 */,
+    CONST64(0x8A781B1B41F1873E) /*  860 */, CONST64(0xA5C94C78A0D2F0E7) /*  861 */,
+    CONST64(0x39412E2877B60728) /*  862 */, CONST64(0xA1265EF3AFC9A62C) /*  863 */,
+    CONST64(0xBCC2770C6A2506C5) /*  864 */, CONST64(0x3AB66DD5DCE1CE12) /*  865 */,
+    CONST64(0xE65499D04A675B37) /*  866 */, CONST64(0x7D8F523481BFD216) /*  867 */,
+    CONST64(0x0F6F64FCEC15F389) /*  868 */, CONST64(0x74EFBE618B5B13C8) /*  869 */,
+    CONST64(0xACDC82B714273E1D) /*  870 */, CONST64(0xDD40BFE003199D17) /*  871 */,
+    CONST64(0x37E99257E7E061F8) /*  872 */, CONST64(0xFA52626904775AAA) /*  873 */,
+    CONST64(0x8BBBF63A463D56F9) /*  874 */, CONST64(0xF0013F1543A26E64) /*  875 */,
+    CONST64(0xA8307E9F879EC898) /*  876 */, CONST64(0xCC4C27A4150177CC) /*  877 */,
+    CONST64(0x1B432F2CCA1D3348) /*  878 */, CONST64(0xDE1D1F8F9F6FA013) /*  879 */,
+    CONST64(0x606602A047A7DDD6) /*  880 */, CONST64(0xD237AB64CC1CB2C7) /*  881 */,
+    CONST64(0x9B938E7225FCD1D3) /*  882 */, CONST64(0xEC4E03708E0FF476) /*  883 */,
+    CONST64(0xFEB2FBDA3D03C12D) /*  884 */, CONST64(0xAE0BCED2EE43889A) /*  885 */,
+    CONST64(0x22CB8923EBFB4F43) /*  886 */, CONST64(0x69360D013CF7396D) /*  887 */,
+    CONST64(0x855E3602D2D4E022) /*  888 */, CONST64(0x073805BAD01F784C) /*  889 */,
+    CONST64(0x33E17A133852F546) /*  890 */, CONST64(0xDF4874058AC7B638) /*  891 */,
+    CONST64(0xBA92B29C678AA14A) /*  892 */, CONST64(0x0CE89FC76CFAADCD) /*  893 */,
+    CONST64(0x5F9D4E0908339E34) /*  894 */, CONST64(0xF1AFE9291F5923B9) /*  895 */,
+    CONST64(0x6E3480F60F4A265F) /*  896 */, CONST64(0xEEBF3A2AB29B841C) /*  897 */,
+    CONST64(0xE21938A88F91B4AD) /*  898 */, CONST64(0x57DFEFF845C6D3C3) /*  899 */,
+    CONST64(0x2F006B0BF62CAAF2) /*  900 */, CONST64(0x62F479EF6F75EE78) /*  901 */,
+    CONST64(0x11A55AD41C8916A9) /*  902 */, CONST64(0xF229D29084FED453) /*  903 */,
+    CONST64(0x42F1C27B16B000E6) /*  904 */, CONST64(0x2B1F76749823C074) /*  905 */,
+    CONST64(0x4B76ECA3C2745360) /*  906 */, CONST64(0x8C98F463B91691BD) /*  907 */,
+    CONST64(0x14BCC93CF1ADE66A) /*  908 */, CONST64(0x8885213E6D458397) /*  909 */,
+    CONST64(0x8E177DF0274D4711) /*  910 */, CONST64(0xB49B73B5503F2951) /*  911 */,
+    CONST64(0x10168168C3F96B6B) /*  912 */, CONST64(0x0E3D963B63CAB0AE) /*  913 */,
+    CONST64(0x8DFC4B5655A1DB14) /*  914 */, CONST64(0xF789F1356E14DE5C) /*  915 */,
+    CONST64(0x683E68AF4E51DAC1) /*  916 */, CONST64(0xC9A84F9D8D4B0FD9) /*  917 */,
+    CONST64(0x3691E03F52A0F9D1) /*  918 */, CONST64(0x5ED86E46E1878E80) /*  919 */,
+    CONST64(0x3C711A0E99D07150) /*  920 */, CONST64(0x5A0865B20C4E9310) /*  921 */,
+    CONST64(0x56FBFC1FE4F0682E) /*  922 */, CONST64(0xEA8D5DE3105EDF9B) /*  923 */,
+    CONST64(0x71ABFDB12379187A) /*  924 */, CONST64(0x2EB99DE1BEE77B9C) /*  925 */,
+    CONST64(0x21ECC0EA33CF4523) /*  926 */, CONST64(0x59A4D7521805C7A1) /*  927 */,
+    CONST64(0x3896F5EB56AE7C72) /*  928 */, CONST64(0xAA638F3DB18F75DC) /*  929 */,
+    CONST64(0x9F39358DABE9808E) /*  930 */, CONST64(0xB7DEFA91C00B72AC) /*  931 */,
+    CONST64(0x6B5541FD62492D92) /*  932 */, CONST64(0x6DC6DEE8F92E4D5B) /*  933 */,
+    CONST64(0x353F57ABC4BEEA7E) /*  934 */, CONST64(0x735769D6DA5690CE) /*  935 */,
+    CONST64(0x0A234AA642391484) /*  936 */, CONST64(0xF6F9508028F80D9D) /*  937 */,
+    CONST64(0xB8E319A27AB3F215) /*  938 */, CONST64(0x31AD9C1151341A4D) /*  939 */,
+    CONST64(0x773C22A57BEF5805) /*  940 */, CONST64(0x45C7561A07968633) /*  941 */,
+    CONST64(0xF913DA9E249DBE36) /*  942 */, CONST64(0xDA652D9B78A64C68) /*  943 */,
+    CONST64(0x4C27A97F3BC334EF) /*  944 */, CONST64(0x76621220E66B17F4) /*  945 */,
+    CONST64(0x967743899ACD7D0B) /*  946 */, CONST64(0xF3EE5BCAE0ED6782) /*  947 */,
+    CONST64(0x409F753600C879FC) /*  948 */, CONST64(0x06D09A39B5926DB6) /*  949 */,
+    CONST64(0x6F83AEB0317AC588) /*  950 */, CONST64(0x01E6CA4A86381F21) /*  951 */,
+    CONST64(0x66FF3462D19F3025) /*  952 */, CONST64(0x72207C24DDFD3BFB) /*  953 */,
+    CONST64(0x4AF6B6D3E2ECE2EB) /*  954 */, CONST64(0x9C994DBEC7EA08DE) /*  955 */,
+    CONST64(0x49ACE597B09A8BC4) /*  956 */, CONST64(0xB38C4766CF0797BA) /*  957 */,
+    CONST64(0x131B9373C57C2A75) /*  958 */, CONST64(0xB1822CCE61931E58) /*  959 */,
+    CONST64(0x9D7555B909BA1C0C) /*  960 */, CONST64(0x127FAFDD937D11D2) /*  961 */,
+    CONST64(0x29DA3BADC66D92E4) /*  962 */, CONST64(0xA2C1D57154C2ECBC) /*  963 */,
+    CONST64(0x58C5134D82F6FE24) /*  964 */, CONST64(0x1C3AE3515B62274F) /*  965 */,
+    CONST64(0xE907C82E01CB8126) /*  966 */, CONST64(0xF8ED091913E37FCB) /*  967 */,
+    CONST64(0x3249D8F9C80046C9) /*  968 */, CONST64(0x80CF9BEDE388FB63) /*  969 */,
+    CONST64(0x1881539A116CF19E) /*  970 */, CONST64(0x5103F3F76BD52457) /*  971 */,
+    CONST64(0x15B7E6F5AE47F7A8) /*  972 */, CONST64(0xDBD7C6DED47E9CCF) /*  973 */,
+    CONST64(0x44E55C410228BB1A) /*  974 */, CONST64(0xB647D4255EDB4E99) /*  975 */,
+    CONST64(0x5D11882BB8AAFC30) /*  976 */, CONST64(0xF5098BBB29D3212A) /*  977 */,
+    CONST64(0x8FB5EA14E90296B3) /*  978 */, CONST64(0x677B942157DD025A) /*  979 */,
+    CONST64(0xFB58E7C0A390ACB5) /*  980 */, CONST64(0x89D3674C83BD4A01) /*  981 */,
+    CONST64(0x9E2DA4DF4BF3B93B) /*  982 */, CONST64(0xFCC41E328CAB4829) /*  983 */,
+    CONST64(0x03F38C96BA582C52) /*  984 */, CONST64(0xCAD1BDBD7FD85DB2) /*  985 */,
+    CONST64(0xBBB442C16082AE83) /*  986 */, CONST64(0xB95FE86BA5DA9AB0) /*  987 */,
+    CONST64(0xB22E04673771A93F) /*  988 */, CONST64(0x845358C9493152D8) /*  989 */,
+    CONST64(0xBE2A488697B4541E) /*  990 */, CONST64(0x95A2DC2DD38E6966) /*  991 */,
+    CONST64(0xC02C11AC923C852B) /*  992 */, CONST64(0x2388B1990DF2A87B) /*  993 */,
+    CONST64(0x7C8008FA1B4F37BE) /*  994 */, CONST64(0x1F70D0C84D54E503) /*  995 */,
+    CONST64(0x5490ADEC7ECE57D4) /*  996 */, CONST64(0x002B3C27D9063A3A) /*  997 */,
+    CONST64(0x7EAEA3848030A2BF) /*  998 */, CONST64(0xC602326DED2003C0) /*  999 */,
+    CONST64(0x83A7287D69A94086) /* 1000 */, CONST64(0xC57A5FCB30F57A8A) /* 1001 */,
+    CONST64(0xB56844E479EBE779) /* 1002 */, CONST64(0xA373B40F05DCBCE9) /* 1003 */,
+    CONST64(0xD71A786E88570EE2) /* 1004 */, CONST64(0x879CBACDBDE8F6A0) /* 1005 */,
+    CONST64(0x976AD1BCC164A32F) /* 1006 */, CONST64(0xAB21E25E9666D78B) /* 1007 */,
+    CONST64(0x901063AAE5E5C33C) /* 1008 */, CONST64(0x9818B34448698D90) /* 1009 */,
+    CONST64(0xE36487AE3E1E8ABB) /* 1010 */, CONST64(0xAFBDF931893BDCB4) /* 1011 */,
+    CONST64(0x6345A0DC5FBBD519) /* 1012 */, CONST64(0x8628FE269B9465CA) /* 1013 */,
+    CONST64(0x1E5D01603F9C51EC) /* 1014 */, CONST64(0x4DE44006A15049B7) /* 1015 */,
+    CONST64(0xBF6C70E5F776CBB1) /* 1016 */, CONST64(0x411218F2EF552BED) /* 1017 */,
+    CONST64(0xCB0C0708705A36A3) /* 1018 */, CONST64(0xE74D14754F986044) /* 1019 */,
+    CONST64(0xCD56D9430EA8280E) /* 1020 */, CONST64(0xC12591D7535F5065) /* 1021 */,
+    CONST64(0xC83223F1720AEF96) /* 1022 */, CONST64(0xC3A0396F7363A51F) /* 1023 */};
+
+#ifdef _MSC_VER
+   #define INLINE __inline
+#else
+   #define INLINE
+#endif
+
+/* one round of the hash function */
+INLINE static void tiger_round(ulong64 *a, ulong64 *b, ulong64 *c, ulong64 x, int mul)
+{
+    ulong64 tmp;
+    tmp = (*c ^= x);
+           *a -= t1[byte(tmp, 0)] ^ t2[byte(tmp, 2)] ^ t3[byte(tmp, 4)] ^ t4[byte(tmp, 6)];
+    tmp = (*b += t4[byte(tmp, 1)] ^ t3[byte(tmp, 3)] ^ t2[byte(tmp,5)] ^ t1[byte(tmp,7)]);
+    switch (mul) {
+        case 5:  *b = (tmp << 2) + tmp; break;
+        case 7:  *b = (tmp << 3) - tmp; break;
+        case 9:  *b = (tmp << 3) + tmp; break;
+    }
+}
+
+/* one complete pass */
+static void pass(ulong64 *a, ulong64 *b, ulong64 *c, ulong64 *x, int mul)
+{
+   tiger_round(a,b,c,x[0],mul);
+   tiger_round(b,c,a,x[1],mul);
+   tiger_round(c,a,b,x[2],mul);
+   tiger_round(a,b,c,x[3],mul);
+   tiger_round(b,c,a,x[4],mul);
+   tiger_round(c,a,b,x[5],mul);
+   tiger_round(a,b,c,x[6],mul);
+   tiger_round(b,c,a,x[7],mul);
+}
+
+/* The key mixing schedule */
+static void key_schedule(ulong64 *x)
+{
+    x[0] -= x[7] ^ CONST64(0xA5A5A5A5A5A5A5A5);
+    x[1] ^= x[0];
+    x[2] += x[1];
+    x[3] -= x[2] ^ ((~x[1])<<19);
+    x[4] ^= x[3];
+    x[5] += x[4];
+    x[6] -= x[5] ^ ((~x[4])>>23);
+    x[7] ^= x[6];
+    x[0] += x[7];
+    x[1] -= x[0] ^ ((~x[7])<<19);
+    x[2] ^= x[1];
+    x[3] += x[2];
+    x[4] -= x[3] ^ ((~x[2])>>23);
+    x[5] ^= x[4];
+    x[6] += x[5];
+    x[7] -= x[6] ^ CONST64(0x0123456789ABCDEF);
+}
+
+#ifdef LTC_CLEAN_STACK
+static int _tiger_compress(hash_state *md, unsigned char *buf)
+#else
+static int  tiger_compress(hash_state *md, unsigned char *buf)
+#endif
+{
+    ulong64 a, b, c, x[8];
+    unsigned long i;
+
+    /* load words */
+    for (i = 0; i < 8; i++) {
+        LOAD64L(x[i],&buf[8*i]);
+    }
+    a = md->tiger.state[0];
+    b = md->tiger.state[1];
+    c = md->tiger.state[2];
+
+    pass(&a,&b,&c,x,5);
+    key_schedule(x);
+    pass(&c,&a,&b,x,7);
+    key_schedule(x);
+    pass(&b,&c,&a,x,9);
+
+    /* store state */
+    md->tiger.state[0] = a ^ md->tiger.state[0];
+    md->tiger.state[1] = b - md->tiger.state[1];
+    md->tiger.state[2] = c + md->tiger.state[2];
+
+    return CRYPT_OK;
+}
+
+#ifdef LTC_CLEAN_STACK
+static int tiger_compress(hash_state *md, unsigned char *buf)
+{
+   int err;
+   err = _tiger_compress(md, buf);
+   burn_stack(sizeof(ulong64) * 11 + sizeof(unsigned long));
+   return err;
+}
+#endif
+
+/**
+   Initialize the hash state
+   @param md   The hash state you wish to initialize
+   @return CRYPT_OK if successful
+*/
+int tiger_init(hash_state *md)
+{
+    LTC_ARGCHK(md != NULL);
+    md->tiger.state[0] = CONST64(0x0123456789ABCDEF);
+    md->tiger.state[1] = CONST64(0xFEDCBA9876543210);
+    md->tiger.state[2] = CONST64(0xF096A5B4C3B2E187);
+    md->tiger.curlen = 0;
+    md->tiger.length = 0;
+    return CRYPT_OK;
+}
+
+/**
+   Process a block of memory though the hash
+   @param md     The hash state
+   @param in     The data to hash
+   @param inlen  The length of the data (octets)
+   @return CRYPT_OK if successful
+*/
+HASH_PROCESS(tiger_process, tiger_compress, tiger, 64)
+
+/**
+   Terminate the hash to get the digest
+   @param md  The hash state
+   @param out [out] The destination of the hash (24 bytes)
+   @return CRYPT_OK if successful
+*/
+int tiger_done(hash_state * md, unsigned char *out)
+{
+    LTC_ARGCHK(md  != NULL);
+    LTC_ARGCHK(out != NULL);
+
+    if (md->tiger.curlen >= sizeof(md->tiger.buf)) {
+       return CRYPT_INVALID_ARG;
+    }
+
+    /* increase the length of the message */
+    md->tiger.length += md->tiger.curlen * 8;
+
+    /* append the '1' bit */
+    md->tiger.buf[md->tiger.curlen++] = (unsigned char)0x01;
+
+    /* if the length is currently above 56 bytes we append zeros
+     * then compress.  Then we can fall back to padding zeros and length
+     * encoding like normal. */
+    if (md->tiger.curlen > 56) {
+        while (md->tiger.curlen < 64) {
+            md->tiger.buf[md->tiger.curlen++] = (unsigned char)0;
+        }
+        tiger_compress(md, md->tiger.buf);
+        md->tiger.curlen = 0;
+    }
+
+    /* pad upto 56 bytes of zeroes */
+    while (md->tiger.curlen < 56) {
+        md->tiger.buf[md->tiger.curlen++] = (unsigned char)0;
+    }
+
+    /* store length */
+    STORE64L(md->tiger.length, md->tiger.buf+56);
+    tiger_compress(md, md->tiger.buf);
+
+    /* copy output */
+    STORE64L(md->tiger.state[0], &out[0]);
+    STORE64L(md->tiger.state[1], &out[8]);
+    STORE64L(md->tiger.state[2], &out[16]);
+#ifdef LTC_CLEAN_STACK
+    zeromem(md, sizeof(hash_state));
+#endif
+
+    return CRYPT_OK;
+}
+
+/**
+  Self-test the hash
+  @return CRYPT_OK if successful, CRYPT_NOP if self-tests have been disabled
+*/
+int  tiger_test(void)
+{
+ #ifndef LTC_TEST
+    return CRYPT_NOP;
+ #else
+  static const struct {
+      const char *msg;
+      unsigned char hash[24];
+  } tests[] = {
+    { "",
+     { 0x32, 0x93, 0xac, 0x63, 0x0c, 0x13, 0xf0, 0x24,
+       0x5f, 0x92, 0xbb, 0xb1, 0x76, 0x6e, 0x16, 0x16,
+       0x7a, 0x4e, 0x58, 0x49, 0x2d, 0xde, 0x73, 0xf3 }
+    },
+    { "abc",
+     { 0x2a, 0xab, 0x14, 0x84, 0xe8, 0xc1, 0x58, 0xf2,
+       0xbf, 0xb8, 0xc5, 0xff, 0x41, 0xb5, 0x7a, 0x52,
+       0x51, 0x29, 0x13, 0x1c, 0x95, 0x7b, 0x5f, 0x93 }
+    },
+    { "Tiger",
+     { 0xdd, 0x00, 0x23, 0x07, 0x99, 0xf5, 0x00, 0x9f,
+       0xec, 0x6d, 0xeb, 0xc8, 0x38, 0xbb, 0x6a, 0x27,
+       0xdf, 0x2b, 0x9d, 0x6f, 0x11, 0x0c, 0x79, 0x37 }
+    },
+    { "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-",
+     { 0xf7, 0x1c, 0x85, 0x83, 0x90, 0x2a, 0xfb, 0x87,
+       0x9e, 0xdf, 0xe6, 0x10, 0xf8, 0x2c, 0x0d, 0x47,
+       0x86, 0xa3, 0xa5, 0x34, 0x50, 0x44, 0x86, 0xb5 }
+    },
+    { "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-",
+     { 0xc5, 0x40, 0x34, 0xe5, 0xb4, 0x3e, 0xb8, 0x00,
+       0x58, 0x48, 0xa7, 0xe0, 0xae, 0x6a, 0xac, 0x76,
+       0xe4, 0xff, 0x59, 0x0a, 0xe7, 0x15, 0xfd, 0x25 }
+    },
+  };
+
+  int i;
+  unsigned char tmp[24];
+  hash_state md;
+
+  for (i = 0; i < (int)(sizeof(tests) / sizeof(tests[0])); i++) {
+      tiger_init(&md);
+      tiger_process(&md, (unsigned char *)tests[i].msg, (unsigned long)strlen(tests[i].msg));
+      tiger_done(&md, tmp);
+      if (compare_testvector(tmp, sizeof(tmp), tests[i].hash, sizeof(tests[i].hash), "TIGER", i)) {
+          return CRYPT_FAIL_TESTVECTOR;
+      }
+  }
+  return CRYPT_OK;
+  #endif
+}
+
+#endif
+
+/*
+Hash of "":
+        24F0130C63AC9332 16166E76B1BB925F F373DE2D49584E7A
+Hash of "abc":
+        F258C1E88414AB2A 527AB541FFC5B8BF 935F7B951C132951
+Hash of "Tiger":
+        9F00F599072300DD 276ABB38C8EB6DEC 37790C116F9D2BDF
+Hash of "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-":
+        87FB2A9083851CF7 470D2CF810E6DF9E B586445034A5A386
+Hash of "ABCDEFGHIJKLMNOPQRSTUVWXYZ=abcdefghijklmnopqrstuvwxyz+0123456789":
+        467DB80863EBCE48 8DF1CD1261655DE9 57896565975F9197
+Hash of "Tiger - A Fast New Hash Function, by Ross Anderson and Eli Biham":
+        0C410A042968868A 1671DA5A3FD29A72 5EC1E457D3CDB303
+Hash of "Tiger - A Fast New Hash Function, by Ross Anderson and Eli Biham, proceedings of Fast Software Encryption 3, Cambridge.":
+        EBF591D5AFA655CE 7F22894FF87F54AC 89C811B6B0DA3193
+Hash of "Tiger - A Fast New Hash Function, by Ross Anderson and Eli Biham, proceedings of Fast Software Encryption 3, Cambridge, 1996.":
+        3D9AEB03D1BD1A63 57B2774DFD6D5B24 DD68151D503974FC
+Hash of "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-":
+        00B83EB4E53440C5 76AC6AAEE0A74858 25FD15E70A59FFE4
+*/
+
+
+
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/hashes/whirl/whirl.c b/libtomcrypt/src/hashes/whirl/whirl.c
new file mode 100644 (file)
index 0000000..fe152cd
--- /dev/null
@@ -0,0 +1,306 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+/**
+   @file whirl.c
+   LTC_WHIRLPOOL (using their new sbox) hash function by Tom St Denis
+*/
+
+#include "tomcrypt.h"
+
+#ifdef LTC_WHIRLPOOL
+
+const struct ltc_hash_descriptor whirlpool_desc =
+{
+    "whirlpool",
+    11,
+    64,
+    64,
+
+   /* OID */
+   { 1, 0, 10118, 3, 0, 55 },
+   6,
+
+    &whirlpool_init,
+    &whirlpool_process,
+    &whirlpool_done,
+    &whirlpool_test,
+    NULL
+};
+
+/* the sboxes */
+#define __LTC_WHIRLTAB_C__
+#include "whirltab.c"
+
+/* get a_{i,j} */
+#define GB(a,i,j) ((a[(i) & 7] >> (8 * (j))) & 255)
+
+/* shortcut macro to perform three functions at once */
+#define theta_pi_gamma(a, i)             \
+   (SB0(GB(a, i-0, 7)) ^                 \
+    SB1(GB(a, i-1, 6)) ^                 \
+    SB2(GB(a, i-2, 5)) ^                 \
+    SB3(GB(a, i-3, 4)) ^                 \
+    SB4(GB(a, i-4, 3)) ^                 \
+    SB5(GB(a, i-5, 2)) ^                 \
+    SB6(GB(a, i-6, 1)) ^                 \
+    SB7(GB(a, i-7, 0)))
+
+#ifdef LTC_CLEAN_STACK
+static int _whirlpool_compress(hash_state *md, unsigned char *buf)
+#else
+static int whirlpool_compress(hash_state *md, unsigned char *buf)
+#endif
+{
+   ulong64 K[2][8], T[3][8];
+   int x, y;
+
+   /* load the block/state */
+   for (x = 0; x < 8; x++) {
+      K[0][x] = md->whirlpool.state[x];
+
+      LOAD64H(T[0][x], buf + (8 * x));
+      T[2][x]  = T[0][x];
+      T[0][x] ^= K[0][x];
+   }
+
+   /* do rounds 1..10 */
+   for (x = 0; x < 10; x += 2) {
+       /* odd round */
+       /* apply main transform to K[0] into K[1] */
+       for (y = 0; y < 8; y++) {
+           K[1][y] = theta_pi_gamma(K[0], y);
+       }
+       /* xor the constant */
+       K[1][0] ^= cont[x];
+
+       /* apply main transform to T[0] into T[1] */
+       for (y = 0; y < 8; y++) {
+           T[1][y] = theta_pi_gamma(T[0], y) ^ K[1][y];
+       }
+
+       /* even round */
+       /* apply main transform to K[1] into K[0] */
+       for (y = 0; y < 8; y++) {
+           K[0][y] = theta_pi_gamma(K[1], y);
+       }
+       /* xor the constant */
+       K[0][0] ^= cont[x+1];
+
+       /* apply main transform to T[1] into T[0] */
+       for (y = 0; y < 8; y++) {
+           T[0][y] = theta_pi_gamma(T[1], y) ^ K[0][y];
+       }
+   }
+
+   /* store state */
+   for (x = 0; x < 8; x++) {
+      md->whirlpool.state[x] ^= T[0][x] ^ T[2][x];
+   }
+
+   return CRYPT_OK;
+}
+
+
+#ifdef LTC_CLEAN_STACK
+static int whirlpool_compress(hash_state *md, unsigned char *buf)
+{
+   int err;
+   err = _whirlpool_compress(md, buf);
+   burn_stack((5 * 8 * sizeof(ulong64)) + (2 * sizeof(int)));
+   return err;
+}
+#endif
+
+
+/**
+   Initialize the hash state
+   @param md   The hash state you wish to initialize
+   @return CRYPT_OK if successful
+*/
+int whirlpool_init(hash_state * md)
+{
+   LTC_ARGCHK(md != NULL);
+   zeromem(&md->whirlpool, sizeof(md->whirlpool));
+   return CRYPT_OK;
+}
+
+/**
+   Process a block of memory though the hash
+   @param md     The hash state
+   @param in     The data to hash
+   @param inlen  The length of the data (octets)
+   @return CRYPT_OK if successful
+*/
+HASH_PROCESS(whirlpool_process, whirlpool_compress, whirlpool, 64)
+
+/**
+   Terminate the hash to get the digest
+   @param md  The hash state
+   @param out [out] The destination of the hash (64 bytes)
+   @return CRYPT_OK if successful
+*/
+int whirlpool_done(hash_state * md, unsigned char *out)
+{
+    int i;
+
+    LTC_ARGCHK(md  != NULL);
+    LTC_ARGCHK(out != NULL);
+
+    if (md->whirlpool.curlen >= sizeof(md->whirlpool.buf)) {
+       return CRYPT_INVALID_ARG;
+    }
+
+    /* increase the length of the message */
+    md->whirlpool.length += md->whirlpool.curlen * 8;
+
+    /* append the '1' bit */
+    md->whirlpool.buf[md->whirlpool.curlen++] = (unsigned char)0x80;
+
+    /* if the length is currently above 32 bytes we append zeros
+     * then compress.  Then we can fall back to padding zeros and length
+     * encoding like normal.
+     */
+    if (md->whirlpool.curlen > 32) {
+        while (md->whirlpool.curlen < 64) {
+            md->whirlpool.buf[md->whirlpool.curlen++] = (unsigned char)0;
+        }
+        whirlpool_compress(md, md->whirlpool.buf);
+        md->whirlpool.curlen = 0;
+    }
+
+    /* pad upto 56 bytes of zeroes (should be 32 but we only support 64-bit lengths)  */
+    while (md->whirlpool.curlen < 56) {
+        md->whirlpool.buf[md->whirlpool.curlen++] = (unsigned char)0;
+    }
+
+    /* store length */
+    STORE64H(md->whirlpool.length, md->whirlpool.buf+56);
+    whirlpool_compress(md, md->whirlpool.buf);
+
+    /* copy output */
+    for (i = 0; i < 8; i++) {
+        STORE64H(md->whirlpool.state[i], out+(8*i));
+    }
+#ifdef LTC_CLEAN_STACK
+    zeromem(md, sizeof(*md));
+#endif
+    return CRYPT_OK;
+}
+
+/**
+  Self-test the hash
+  @return CRYPT_OK if successful, CRYPT_NOP if self-tests have been disabled
+*/
+int  whirlpool_test(void)
+{
+ #ifndef LTC_TEST
+    return CRYPT_NOP;
+ #else
+  static const struct {
+      int len;
+      unsigned char msg[128], hash[64];
+  } tests[] = {
+
+  /* NULL Message */
+{
+  0,
+  { 0x00 },
+  { 0x19, 0xFA, 0x61, 0xD7, 0x55, 0x22, 0xA4, 0x66, 0x9B, 0x44, 0xE3, 0x9C, 0x1D, 0x2E, 0x17, 0x26,
+    0xC5, 0x30, 0x23, 0x21, 0x30, 0xD4, 0x07, 0xF8, 0x9A, 0xFE, 0xE0, 0x96, 0x49, 0x97, 0xF7, 0xA7,
+    0x3E, 0x83, 0xBE, 0x69, 0x8B, 0x28, 0x8F, 0xEB, 0xCF, 0x88, 0xE3, 0xE0, 0x3C, 0x4F, 0x07, 0x57,
+    0xEA, 0x89, 0x64, 0xE5, 0x9B, 0x63, 0xD9, 0x37, 0x08, 0xB1, 0x38, 0xCC, 0x42, 0xA6, 0x6E, 0xB3 }
+},
+
+
+   /* 448-bits of 0 bits */
+{
+
+  56,
+  { 0x00 },
+  { 0x0B, 0x3F, 0x53, 0x78, 0xEB, 0xED, 0x2B, 0xF4, 0xD7, 0xBE, 0x3C, 0xFD, 0x81, 0x8C, 0x1B, 0x03,
+    0xB6, 0xBB, 0x03, 0xD3, 0x46, 0x94, 0x8B, 0x04, 0xF4, 0xF4, 0x0C, 0x72, 0x6F, 0x07, 0x58, 0x70,
+    0x2A, 0x0F, 0x1E, 0x22, 0x58, 0x80, 0xE3, 0x8D, 0xD5, 0xF6, 0xED, 0x6D, 0xE9, 0xB1, 0xE9, 0x61,
+    0xE4, 0x9F, 0xC1, 0x31, 0x8D, 0x7C, 0xB7, 0x48, 0x22, 0xF3, 0xD0, 0xE2, 0xE9, 0xA7, 0xE7, 0xB0 }
+},
+
+   /* 520-bits of 0 bits */
+{
+  65,
+  { 0x00 },
+  { 0x85, 0xE1, 0x24, 0xC4, 0x41, 0x5B, 0xCF, 0x43, 0x19, 0x54, 0x3E, 0x3A, 0x63, 0xFF, 0x57, 0x1D,
+    0x09, 0x35, 0x4C, 0xEE, 0xBE, 0xE1, 0xE3, 0x25, 0x30, 0x8C, 0x90, 0x69, 0xF4, 0x3E, 0x2A, 0xE4,
+    0xD0, 0xE5, 0x1D, 0x4E, 0xB1, 0xE8, 0x64, 0x28, 0x70, 0x19, 0x4E, 0x95, 0x30, 0xD8, 0xD8, 0xAF,
+    0x65, 0x89, 0xD1, 0xBF, 0x69, 0x49, 0xDD, 0xF9, 0x0A, 0x7F, 0x12, 0x08, 0x62, 0x37, 0x95, 0xB9 }
+},
+
+   /* 512-bits, leading set */
+{
+  64,
+  { 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, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+  { 0x10, 0x3E, 0x00, 0x55, 0xA9, 0xB0, 0x90, 0xE1, 0x1C, 0x8F, 0xDD, 0xEB, 0xBA, 0x06, 0xC0, 0x5A,
+    0xCE, 0x8B, 0x64, 0xB8, 0x96, 0x12, 0x8F, 0x6E, 0xED, 0x30, 0x71, 0xFC, 0xF3, 0xDC, 0x16, 0x94,
+    0x67, 0x78, 0xE0, 0x72, 0x23, 0x23, 0x3F, 0xD1, 0x80, 0xFC, 0x40, 0xCC, 0xDB, 0x84, 0x30, 0xA6,
+    0x40, 0xE3, 0x76, 0x34, 0x27, 0x1E, 0x65, 0x5C, 0xA1, 0x67, 0x4E, 0xBF, 0xF5, 0x07, 0xF8, 0xCB }
+},
+
+   /* 512-bits, leading set of second byte */
+{
+  64,
+  { 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, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+  { 0x35, 0x7B, 0x42, 0xEA, 0x79, 0xBC, 0x97, 0x86, 0x97, 0x5A, 0x3C, 0x44, 0x70, 0xAA, 0xB2, 0x3E,
+    0x62, 0x29, 0x79, 0x7B, 0xAD, 0xBD, 0x54, 0x36, 0x5B, 0x54, 0x96, 0xE5, 0x5D, 0x9D, 0xD7, 0x9F,
+    0xE9, 0x62, 0x4F, 0xB4, 0x22, 0x66, 0x93, 0x0A, 0x62, 0x8E, 0xD4, 0xDB, 0x08, 0xF9, 0xDD, 0x35,
+    0xEF, 0x1B, 0xE1, 0x04, 0x53, 0xFC, 0x18, 0xF4, 0x2C, 0x7F, 0x5E, 0x1F, 0x9B, 0xAE, 0x55, 0xE0 }
+},
+
+   /* 512-bits, leading set of last byte */
+{
+  64,
+  { 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 },
+  { 0x8B, 0x39, 0x04, 0xDD, 0x19, 0x81, 0x41, 0x26, 0xFD, 0x02, 0x74, 0xAB, 0x49, 0xC5, 0x97, 0xF6,
+    0xD7, 0x75, 0x33, 0x52, 0xA2, 0xDD, 0x91, 0xFD, 0x8F, 0x9F, 0x54, 0x05, 0x4C, 0x54, 0xBF, 0x0F,
+    0x06, 0xDB, 0x4F, 0xF7, 0x08, 0xA3, 0xA2, 0x8B, 0xC3, 0x7A, 0x92, 0x1E, 0xEE, 0x11, 0xED, 0x7B,
+    0x6A, 0x53, 0x79, 0x32, 0xCC, 0x5E, 0x94, 0xEE, 0x1E, 0xA6, 0x57, 0x60, 0x7E, 0x36, 0xC9, 0xF7 }
+},
+
+};
+
+  int i;
+  unsigned char tmp[64];
+  hash_state md;
+
+  for (i = 0; i < (int)(sizeof(tests)/sizeof(tests[0])); i++) {
+      whirlpool_init(&md);
+      whirlpool_process(&md, (unsigned char *)tests[i].msg, tests[i].len);
+      whirlpool_done(&md, tmp);
+      if (compare_testvector(tmp, sizeof(tmp), tests[i].hash, sizeof(tests[i].hash), "WHIRLPOOL", i)) {
+         return CRYPT_FAIL_TESTVECTOR;
+      }
+  }
+  return CRYPT_OK;
+ #endif
+}
+
+
+#endif
+
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/hashes/whirl/whirltab.c b/libtomcrypt/src/hashes/whirl/whirltab.c
new file mode 100644 (file)
index 0000000..4fde89b
--- /dev/null
@@ -0,0 +1,596 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+/**
+   @file whirltab.c
+   LTC_WHIRLPOOL tables, Tom St Denis
+*/
+
+#ifdef __LTC_WHIRLTAB_C__
+
+static const ulong64 sbox0[] = {
+CONST64(0x18186018c07830d8), CONST64(0x23238c2305af4626), CONST64(0xc6c63fc67ef991b8), CONST64(0xe8e887e8136fcdfb),
+CONST64(0x878726874ca113cb), CONST64(0xb8b8dab8a9626d11), CONST64(0x0101040108050209), CONST64(0x4f4f214f426e9e0d),
+CONST64(0x3636d836adee6c9b), CONST64(0xa6a6a2a6590451ff), CONST64(0xd2d26fd2debdb90c), CONST64(0xf5f5f3f5fb06f70e),
+CONST64(0x7979f979ef80f296), CONST64(0x6f6fa16f5fcede30), CONST64(0x91917e91fcef3f6d), CONST64(0x52525552aa07a4f8),
+CONST64(0x60609d6027fdc047), CONST64(0xbcbccabc89766535), CONST64(0x9b9b569baccd2b37), CONST64(0x8e8e028e048c018a),
+CONST64(0xa3a3b6a371155bd2), CONST64(0x0c0c300c603c186c), CONST64(0x7b7bf17bff8af684), CONST64(0x3535d435b5e16a80),
+CONST64(0x1d1d741de8693af5), CONST64(0xe0e0a7e05347ddb3), CONST64(0xd7d77bd7f6acb321), CONST64(0xc2c22fc25eed999c),
+CONST64(0x2e2eb82e6d965c43), CONST64(0x4b4b314b627a9629), CONST64(0xfefedffea321e15d), CONST64(0x575741578216aed5),
+CONST64(0x15155415a8412abd), CONST64(0x7777c1779fb6eee8), CONST64(0x3737dc37a5eb6e92), CONST64(0xe5e5b3e57b56d79e),
+CONST64(0x9f9f469f8cd92313), CONST64(0xf0f0e7f0d317fd23), CONST64(0x4a4a354a6a7f9420), CONST64(0xdada4fda9e95a944),
+CONST64(0x58587d58fa25b0a2), CONST64(0xc9c903c906ca8fcf), CONST64(0x2929a429558d527c), CONST64(0x0a0a280a5022145a),
+CONST64(0xb1b1feb1e14f7f50), CONST64(0xa0a0baa0691a5dc9), CONST64(0x6b6bb16b7fdad614), CONST64(0x85852e855cab17d9),
+CONST64(0xbdbdcebd8173673c), CONST64(0x5d5d695dd234ba8f), CONST64(0x1010401080502090), CONST64(0xf4f4f7f4f303f507),
+CONST64(0xcbcb0bcb16c08bdd), CONST64(0x3e3ef83eedc67cd3), CONST64(0x0505140528110a2d), CONST64(0x676781671fe6ce78),
+CONST64(0xe4e4b7e47353d597), CONST64(0x27279c2725bb4e02), CONST64(0x4141194132588273), CONST64(0x8b8b168b2c9d0ba7),
+CONST64(0xa7a7a6a7510153f6), CONST64(0x7d7de97dcf94fab2), CONST64(0x95956e95dcfb3749), CONST64(0xd8d847d88e9fad56),
+CONST64(0xfbfbcbfb8b30eb70), CONST64(0xeeee9fee2371c1cd), CONST64(0x7c7ced7cc791f8bb), CONST64(0x6666856617e3cc71),
+CONST64(0xdddd53dda68ea77b), CONST64(0x17175c17b84b2eaf), CONST64(0x4747014702468e45), CONST64(0x9e9e429e84dc211a),
+CONST64(0xcaca0fca1ec589d4), CONST64(0x2d2db42d75995a58), CONST64(0xbfbfc6bf9179632e), CONST64(0x07071c07381b0e3f),
+CONST64(0xadad8ead012347ac), CONST64(0x5a5a755aea2fb4b0), CONST64(0x838336836cb51bef), CONST64(0x3333cc3385ff66b6),
+CONST64(0x636391633ff2c65c), CONST64(0x02020802100a0412), CONST64(0xaaaa92aa39384993), CONST64(0x7171d971afa8e2de),
+CONST64(0xc8c807c80ecf8dc6), CONST64(0x19196419c87d32d1), CONST64(0x494939497270923b), CONST64(0xd9d943d9869aaf5f),
+CONST64(0xf2f2eff2c31df931), CONST64(0xe3e3abe34b48dba8), CONST64(0x5b5b715be22ab6b9), CONST64(0x88881a8834920dbc),
+CONST64(0x9a9a529aa4c8293e), CONST64(0x262698262dbe4c0b), CONST64(0x3232c8328dfa64bf), CONST64(0xb0b0fab0e94a7d59),
+CONST64(0xe9e983e91b6acff2), CONST64(0x0f0f3c0f78331e77), CONST64(0xd5d573d5e6a6b733), CONST64(0x80803a8074ba1df4),
+CONST64(0xbebec2be997c6127), CONST64(0xcdcd13cd26de87eb), CONST64(0x3434d034bde46889), CONST64(0x48483d487a759032),
+CONST64(0xffffdbffab24e354), CONST64(0x7a7af57af78ff48d), CONST64(0x90907a90f4ea3d64), CONST64(0x5f5f615fc23ebe9d),
+CONST64(0x202080201da0403d), CONST64(0x6868bd6867d5d00f), CONST64(0x1a1a681ad07234ca), CONST64(0xaeae82ae192c41b7),
+CONST64(0xb4b4eab4c95e757d), CONST64(0x54544d549a19a8ce), CONST64(0x93937693ece53b7f), CONST64(0x222288220daa442f),
+CONST64(0x64648d6407e9c863), CONST64(0xf1f1e3f1db12ff2a), CONST64(0x7373d173bfa2e6cc), CONST64(0x12124812905a2482),
+CONST64(0x40401d403a5d807a), CONST64(0x0808200840281048), CONST64(0xc3c32bc356e89b95), CONST64(0xecec97ec337bc5df),
+CONST64(0xdbdb4bdb9690ab4d), CONST64(0xa1a1bea1611f5fc0), CONST64(0x8d8d0e8d1c830791), CONST64(0x3d3df43df5c97ac8),
+CONST64(0x97976697ccf1335b), CONST64(0x0000000000000000), CONST64(0xcfcf1bcf36d483f9), CONST64(0x2b2bac2b4587566e),
+CONST64(0x7676c57697b3ece1), CONST64(0x8282328264b019e6), CONST64(0xd6d67fd6fea9b128), CONST64(0x1b1b6c1bd87736c3),
+CONST64(0xb5b5eeb5c15b7774), CONST64(0xafaf86af112943be), CONST64(0x6a6ab56a77dfd41d), CONST64(0x50505d50ba0da0ea),
+CONST64(0x45450945124c8a57), CONST64(0xf3f3ebf3cb18fb38), CONST64(0x3030c0309df060ad), CONST64(0xefef9bef2b74c3c4),
+CONST64(0x3f3ffc3fe5c37eda), CONST64(0x55554955921caac7), CONST64(0xa2a2b2a2791059db), CONST64(0xeaea8fea0365c9e9),
+CONST64(0x656589650fecca6a), CONST64(0xbabad2bab9686903), CONST64(0x2f2fbc2f65935e4a), CONST64(0xc0c027c04ee79d8e),
+CONST64(0xdede5fdebe81a160), CONST64(0x1c1c701ce06c38fc), CONST64(0xfdfdd3fdbb2ee746), CONST64(0x4d4d294d52649a1f),
+CONST64(0x92927292e4e03976), CONST64(0x7575c9758fbceafa), CONST64(0x06061806301e0c36), CONST64(0x8a8a128a249809ae),
+CONST64(0xb2b2f2b2f940794b), CONST64(0xe6e6bfe66359d185), CONST64(0x0e0e380e70361c7e), CONST64(0x1f1f7c1ff8633ee7),
+CONST64(0x6262956237f7c455), CONST64(0xd4d477d4eea3b53a), CONST64(0xa8a89aa829324d81), CONST64(0x96966296c4f43152),
+CONST64(0xf9f9c3f99b3aef62), CONST64(0xc5c533c566f697a3), CONST64(0x2525942535b14a10), CONST64(0x59597959f220b2ab),
+CONST64(0x84842a8454ae15d0), CONST64(0x7272d572b7a7e4c5), CONST64(0x3939e439d5dd72ec), CONST64(0x4c4c2d4c5a619816),
+CONST64(0x5e5e655eca3bbc94), CONST64(0x7878fd78e785f09f), CONST64(0x3838e038ddd870e5), CONST64(0x8c8c0a8c14860598),
+CONST64(0xd1d163d1c6b2bf17), CONST64(0xa5a5aea5410b57e4), CONST64(0xe2e2afe2434dd9a1), CONST64(0x616199612ff8c24e),
+CONST64(0xb3b3f6b3f1457b42), CONST64(0x2121842115a54234), CONST64(0x9c9c4a9c94d62508), CONST64(0x1e1e781ef0663cee),
+CONST64(0x4343114322528661), CONST64(0xc7c73bc776fc93b1), CONST64(0xfcfcd7fcb32be54f), CONST64(0x0404100420140824),
+CONST64(0x51515951b208a2e3), CONST64(0x99995e99bcc72f25), CONST64(0x6d6da96d4fc4da22), CONST64(0x0d0d340d68391a65),
+CONST64(0xfafacffa8335e979), CONST64(0xdfdf5bdfb684a369), CONST64(0x7e7ee57ed79bfca9), CONST64(0x242490243db44819),
+CONST64(0x3b3bec3bc5d776fe), CONST64(0xabab96ab313d4b9a), CONST64(0xcece1fce3ed181f0), CONST64(0x1111441188552299),
+CONST64(0x8f8f068f0c890383), CONST64(0x4e4e254e4a6b9c04), CONST64(0xb7b7e6b7d1517366), CONST64(0xebeb8beb0b60cbe0),
+CONST64(0x3c3cf03cfdcc78c1), CONST64(0x81813e817cbf1ffd), CONST64(0x94946a94d4fe3540), CONST64(0xf7f7fbf7eb0cf31c),
+CONST64(0xb9b9deb9a1676f18), CONST64(0x13134c13985f268b), CONST64(0x2c2cb02c7d9c5851), CONST64(0xd3d36bd3d6b8bb05),
+CONST64(0xe7e7bbe76b5cd38c), CONST64(0x6e6ea56e57cbdc39), CONST64(0xc4c437c46ef395aa), CONST64(0x03030c03180f061b),
+CONST64(0x565645568a13acdc), CONST64(0x44440d441a49885e), CONST64(0x7f7fe17fdf9efea0), CONST64(0xa9a99ea921374f88),
+CONST64(0x2a2aa82a4d825467), CONST64(0xbbbbd6bbb16d6b0a), CONST64(0xc1c123c146e29f87), CONST64(0x53535153a202a6f1),
+CONST64(0xdcdc57dcae8ba572), CONST64(0x0b0b2c0b58271653), CONST64(0x9d9d4e9d9cd32701), CONST64(0x6c6cad6c47c1d82b),
+CONST64(0x3131c43195f562a4), CONST64(0x7474cd7487b9e8f3), CONST64(0xf6f6fff6e309f115), CONST64(0x464605460a438c4c),
+CONST64(0xacac8aac092645a5), CONST64(0x89891e893c970fb5), CONST64(0x14145014a04428b4), CONST64(0xe1e1a3e15b42dfba),
+CONST64(0x16165816b04e2ca6), CONST64(0x3a3ae83acdd274f7), CONST64(0x6969b9696fd0d206), CONST64(0x09092409482d1241),
+CONST64(0x7070dd70a7ade0d7), CONST64(0xb6b6e2b6d954716f), CONST64(0xd0d067d0ceb7bd1e), CONST64(0xeded93ed3b7ec7d6),
+CONST64(0xcccc17cc2edb85e2), CONST64(0x424215422a578468), CONST64(0x98985a98b4c22d2c), CONST64(0xa4a4aaa4490e55ed),
+CONST64(0x2828a0285d885075), CONST64(0x5c5c6d5cda31b886), CONST64(0xf8f8c7f8933fed6b), CONST64(0x8686228644a411c2)
+};
+
+#ifdef LTC_SMALL_CODE
+
+#define SB0(x) sbox0[x]
+#define SB1(x) ROR64c(sbox0[x], 8)
+#define SB2(x) ROR64c(sbox0[x], 16)
+#define SB3(x) ROR64c(sbox0[x], 24)
+#define SB4(x) ROR64c(sbox0[x], 32)
+#define SB5(x) ROR64c(sbox0[x], 40)
+#define SB6(x) ROR64c(sbox0[x], 48)
+#define SB7(x) ROR64c(sbox0[x], 56)
+
+#else
+
+#define SB0(x) sbox0[x]
+#define SB1(x) sbox1[x]
+#define SB2(x) sbox2[x]
+#define SB3(x) sbox3[x]
+#define SB4(x) sbox4[x]
+#define SB5(x) sbox5[x]
+#define SB6(x) sbox6[x]
+#define SB7(x) sbox7[x]
+
+
+static const ulong64 sbox1[] = {
+CONST64(0xd818186018c07830), CONST64(0x2623238c2305af46), CONST64(0xb8c6c63fc67ef991), CONST64(0xfbe8e887e8136fcd),
+CONST64(0xcb878726874ca113), CONST64(0x11b8b8dab8a9626d), CONST64(0x0901010401080502), CONST64(0x0d4f4f214f426e9e),
+CONST64(0x9b3636d836adee6c), CONST64(0xffa6a6a2a6590451), CONST64(0x0cd2d26fd2debdb9), CONST64(0x0ef5f5f3f5fb06f7),
+CONST64(0x967979f979ef80f2), CONST64(0x306f6fa16f5fcede), CONST64(0x6d91917e91fcef3f), CONST64(0xf852525552aa07a4),
+CONST64(0x4760609d6027fdc0), CONST64(0x35bcbccabc897665), CONST64(0x379b9b569baccd2b), CONST64(0x8a8e8e028e048c01),
+CONST64(0xd2a3a3b6a371155b), CONST64(0x6c0c0c300c603c18), CONST64(0x847b7bf17bff8af6), CONST64(0x803535d435b5e16a),
+CONST64(0xf51d1d741de8693a), CONST64(0xb3e0e0a7e05347dd), CONST64(0x21d7d77bd7f6acb3), CONST64(0x9cc2c22fc25eed99),
+CONST64(0x432e2eb82e6d965c), CONST64(0x294b4b314b627a96), CONST64(0x5dfefedffea321e1), CONST64(0xd5575741578216ae),
+CONST64(0xbd15155415a8412a), CONST64(0xe87777c1779fb6ee), CONST64(0x923737dc37a5eb6e), CONST64(0x9ee5e5b3e57b56d7),
+CONST64(0x139f9f469f8cd923), CONST64(0x23f0f0e7f0d317fd), CONST64(0x204a4a354a6a7f94), CONST64(0x44dada4fda9e95a9),
+CONST64(0xa258587d58fa25b0), CONST64(0xcfc9c903c906ca8f), CONST64(0x7c2929a429558d52), CONST64(0x5a0a0a280a502214),
+CONST64(0x50b1b1feb1e14f7f), CONST64(0xc9a0a0baa0691a5d), CONST64(0x146b6bb16b7fdad6), CONST64(0xd985852e855cab17),
+CONST64(0x3cbdbdcebd817367), CONST64(0x8f5d5d695dd234ba), CONST64(0x9010104010805020), CONST64(0x07f4f4f7f4f303f5),
+CONST64(0xddcbcb0bcb16c08b), CONST64(0xd33e3ef83eedc67c), CONST64(0x2d0505140528110a), CONST64(0x78676781671fe6ce),
+CONST64(0x97e4e4b7e47353d5), CONST64(0x0227279c2725bb4e), CONST64(0x7341411941325882), CONST64(0xa78b8b168b2c9d0b),
+CONST64(0xf6a7a7a6a7510153), CONST64(0xb27d7de97dcf94fa), CONST64(0x4995956e95dcfb37), CONST64(0x56d8d847d88e9fad),
+CONST64(0x70fbfbcbfb8b30eb), CONST64(0xcdeeee9fee2371c1), CONST64(0xbb7c7ced7cc791f8), CONST64(0x716666856617e3cc),
+CONST64(0x7bdddd53dda68ea7), CONST64(0xaf17175c17b84b2e), CONST64(0x454747014702468e), CONST64(0x1a9e9e429e84dc21),
+CONST64(0xd4caca0fca1ec589), CONST64(0x582d2db42d75995a), CONST64(0x2ebfbfc6bf917963), CONST64(0x3f07071c07381b0e),
+CONST64(0xacadad8ead012347), CONST64(0xb05a5a755aea2fb4), CONST64(0xef838336836cb51b), CONST64(0xb63333cc3385ff66),
+CONST64(0x5c636391633ff2c6), CONST64(0x1202020802100a04), CONST64(0x93aaaa92aa393849), CONST64(0xde7171d971afa8e2),
+CONST64(0xc6c8c807c80ecf8d), CONST64(0xd119196419c87d32), CONST64(0x3b49493949727092), CONST64(0x5fd9d943d9869aaf),
+CONST64(0x31f2f2eff2c31df9), CONST64(0xa8e3e3abe34b48db), CONST64(0xb95b5b715be22ab6), CONST64(0xbc88881a8834920d),
+CONST64(0x3e9a9a529aa4c829), CONST64(0x0b262698262dbe4c), CONST64(0xbf3232c8328dfa64), CONST64(0x59b0b0fab0e94a7d),
+CONST64(0xf2e9e983e91b6acf), CONST64(0x770f0f3c0f78331e), CONST64(0x33d5d573d5e6a6b7), CONST64(0xf480803a8074ba1d),
+CONST64(0x27bebec2be997c61), CONST64(0xebcdcd13cd26de87), CONST64(0x893434d034bde468), CONST64(0x3248483d487a7590),
+CONST64(0x54ffffdbffab24e3), CONST64(0x8d7a7af57af78ff4), CONST64(0x6490907a90f4ea3d), CONST64(0x9d5f5f615fc23ebe),
+CONST64(0x3d202080201da040), CONST64(0x0f6868bd6867d5d0), CONST64(0xca1a1a681ad07234), CONST64(0xb7aeae82ae192c41),
+CONST64(0x7db4b4eab4c95e75), CONST64(0xce54544d549a19a8), CONST64(0x7f93937693ece53b), CONST64(0x2f222288220daa44),
+CONST64(0x6364648d6407e9c8), CONST64(0x2af1f1e3f1db12ff), CONST64(0xcc7373d173bfa2e6), CONST64(0x8212124812905a24),
+CONST64(0x7a40401d403a5d80), CONST64(0x4808082008402810), CONST64(0x95c3c32bc356e89b), CONST64(0xdfecec97ec337bc5),
+CONST64(0x4ddbdb4bdb9690ab), CONST64(0xc0a1a1bea1611f5f), CONST64(0x918d8d0e8d1c8307), CONST64(0xc83d3df43df5c97a),
+CONST64(0x5b97976697ccf133), CONST64(0x0000000000000000), CONST64(0xf9cfcf1bcf36d483), CONST64(0x6e2b2bac2b458756),
+CONST64(0xe17676c57697b3ec), CONST64(0xe68282328264b019), CONST64(0x28d6d67fd6fea9b1), CONST64(0xc31b1b6c1bd87736),
+CONST64(0x74b5b5eeb5c15b77), CONST64(0xbeafaf86af112943), CONST64(0x1d6a6ab56a77dfd4), CONST64(0xea50505d50ba0da0),
+CONST64(0x5745450945124c8a), CONST64(0x38f3f3ebf3cb18fb), CONST64(0xad3030c0309df060), CONST64(0xc4efef9bef2b74c3),
+CONST64(0xda3f3ffc3fe5c37e), CONST64(0xc755554955921caa), CONST64(0xdba2a2b2a2791059), CONST64(0xe9eaea8fea0365c9),
+CONST64(0x6a656589650fecca), CONST64(0x03babad2bab96869), CONST64(0x4a2f2fbc2f65935e), CONST64(0x8ec0c027c04ee79d),
+CONST64(0x60dede5fdebe81a1), CONST64(0xfc1c1c701ce06c38), CONST64(0x46fdfdd3fdbb2ee7), CONST64(0x1f4d4d294d52649a),
+CONST64(0x7692927292e4e039), CONST64(0xfa7575c9758fbcea), CONST64(0x3606061806301e0c), CONST64(0xae8a8a128a249809),
+CONST64(0x4bb2b2f2b2f94079), CONST64(0x85e6e6bfe66359d1), CONST64(0x7e0e0e380e70361c), CONST64(0xe71f1f7c1ff8633e),
+CONST64(0x556262956237f7c4), CONST64(0x3ad4d477d4eea3b5), CONST64(0x81a8a89aa829324d), CONST64(0x5296966296c4f431),
+CONST64(0x62f9f9c3f99b3aef), CONST64(0xa3c5c533c566f697), CONST64(0x102525942535b14a), CONST64(0xab59597959f220b2),
+CONST64(0xd084842a8454ae15), CONST64(0xc57272d572b7a7e4), CONST64(0xec3939e439d5dd72), CONST64(0x164c4c2d4c5a6198),
+CONST64(0x945e5e655eca3bbc), CONST64(0x9f7878fd78e785f0), CONST64(0xe53838e038ddd870), CONST64(0x988c8c0a8c148605),
+CONST64(0x17d1d163d1c6b2bf), CONST64(0xe4a5a5aea5410b57), CONST64(0xa1e2e2afe2434dd9), CONST64(0x4e616199612ff8c2),
+CONST64(0x42b3b3f6b3f1457b), CONST64(0x342121842115a542), CONST64(0x089c9c4a9c94d625), CONST64(0xee1e1e781ef0663c),
+CONST64(0x6143431143225286), CONST64(0xb1c7c73bc776fc93), CONST64(0x4ffcfcd7fcb32be5), CONST64(0x2404041004201408),
+CONST64(0xe351515951b208a2), CONST64(0x2599995e99bcc72f), CONST64(0x226d6da96d4fc4da), CONST64(0x650d0d340d68391a),
+CONST64(0x79fafacffa8335e9), CONST64(0x69dfdf5bdfb684a3), CONST64(0xa97e7ee57ed79bfc), CONST64(0x19242490243db448),
+CONST64(0xfe3b3bec3bc5d776), CONST64(0x9aabab96ab313d4b), CONST64(0xf0cece1fce3ed181), CONST64(0x9911114411885522),
+CONST64(0x838f8f068f0c8903), CONST64(0x044e4e254e4a6b9c), CONST64(0x66b7b7e6b7d15173), CONST64(0xe0ebeb8beb0b60cb),
+CONST64(0xc13c3cf03cfdcc78), CONST64(0xfd81813e817cbf1f), CONST64(0x4094946a94d4fe35), CONST64(0x1cf7f7fbf7eb0cf3),
+CONST64(0x18b9b9deb9a1676f), CONST64(0x8b13134c13985f26), CONST64(0x512c2cb02c7d9c58), CONST64(0x05d3d36bd3d6b8bb),
+CONST64(0x8ce7e7bbe76b5cd3), CONST64(0x396e6ea56e57cbdc), CONST64(0xaac4c437c46ef395), CONST64(0x1b03030c03180f06),
+CONST64(0xdc565645568a13ac), CONST64(0x5e44440d441a4988), CONST64(0xa07f7fe17fdf9efe), CONST64(0x88a9a99ea921374f),
+CONST64(0x672a2aa82a4d8254), CONST64(0x0abbbbd6bbb16d6b), CONST64(0x87c1c123c146e29f), CONST64(0xf153535153a202a6),
+CONST64(0x72dcdc57dcae8ba5), CONST64(0x530b0b2c0b582716), CONST64(0x019d9d4e9d9cd327), CONST64(0x2b6c6cad6c47c1d8),
+CONST64(0xa43131c43195f562), CONST64(0xf37474cd7487b9e8), CONST64(0x15f6f6fff6e309f1), CONST64(0x4c464605460a438c),
+CONST64(0xa5acac8aac092645), CONST64(0xb589891e893c970f), CONST64(0xb414145014a04428), CONST64(0xbae1e1a3e15b42df),
+CONST64(0xa616165816b04e2c), CONST64(0xf73a3ae83acdd274), CONST64(0x066969b9696fd0d2), CONST64(0x4109092409482d12),
+CONST64(0xd77070dd70a7ade0), CONST64(0x6fb6b6e2b6d95471), CONST64(0x1ed0d067d0ceb7bd), CONST64(0xd6eded93ed3b7ec7),
+CONST64(0xe2cccc17cc2edb85), CONST64(0x68424215422a5784), CONST64(0x2c98985a98b4c22d), CONST64(0xeda4a4aaa4490e55),
+CONST64(0x752828a0285d8850), CONST64(0x865c5c6d5cda31b8), CONST64(0x6bf8f8c7f8933fed), CONST64(0xc28686228644a411)
+};
+
+static const ulong64 sbox2[] = {
+CONST64(0x30d818186018c078), CONST64(0x462623238c2305af), CONST64(0x91b8c6c63fc67ef9), CONST64(0xcdfbe8e887e8136f),
+CONST64(0x13cb878726874ca1), CONST64(0x6d11b8b8dab8a962), CONST64(0x0209010104010805), CONST64(0x9e0d4f4f214f426e),
+CONST64(0x6c9b3636d836adee), CONST64(0x51ffa6a6a2a65904), CONST64(0xb90cd2d26fd2debd), CONST64(0xf70ef5f5f3f5fb06),
+CONST64(0xf2967979f979ef80), CONST64(0xde306f6fa16f5fce), CONST64(0x3f6d91917e91fcef), CONST64(0xa4f852525552aa07),
+CONST64(0xc04760609d6027fd), CONST64(0x6535bcbccabc8976), CONST64(0x2b379b9b569baccd), CONST64(0x018a8e8e028e048c),
+CONST64(0x5bd2a3a3b6a37115), CONST64(0x186c0c0c300c603c), CONST64(0xf6847b7bf17bff8a), CONST64(0x6a803535d435b5e1),
+CONST64(0x3af51d1d741de869), CONST64(0xddb3e0e0a7e05347), CONST64(0xb321d7d77bd7f6ac), CONST64(0x999cc2c22fc25eed),
+CONST64(0x5c432e2eb82e6d96), CONST64(0x96294b4b314b627a), CONST64(0xe15dfefedffea321), CONST64(0xaed5575741578216),
+CONST64(0x2abd15155415a841), CONST64(0xeee87777c1779fb6), CONST64(0x6e923737dc37a5eb), CONST64(0xd79ee5e5b3e57b56),
+CONST64(0x23139f9f469f8cd9), CONST64(0xfd23f0f0e7f0d317), CONST64(0x94204a4a354a6a7f), CONST64(0xa944dada4fda9e95),
+CONST64(0xb0a258587d58fa25), CONST64(0x8fcfc9c903c906ca), CONST64(0x527c2929a429558d), CONST64(0x145a0a0a280a5022),
+CONST64(0x7f50b1b1feb1e14f), CONST64(0x5dc9a0a0baa0691a), CONST64(0xd6146b6bb16b7fda), CONST64(0x17d985852e855cab),
+CONST64(0x673cbdbdcebd8173), CONST64(0xba8f5d5d695dd234), CONST64(0x2090101040108050), CONST64(0xf507f4f4f7f4f303),
+CONST64(0x8bddcbcb0bcb16c0), CONST64(0x7cd33e3ef83eedc6), CONST64(0x0a2d050514052811), CONST64(0xce78676781671fe6),
+CONST64(0xd597e4e4b7e47353), CONST64(0x4e0227279c2725bb), CONST64(0x8273414119413258), CONST64(0x0ba78b8b168b2c9d),
+CONST64(0x53f6a7a7a6a75101), CONST64(0xfab27d7de97dcf94), CONST64(0x374995956e95dcfb), CONST64(0xad56d8d847d88e9f),
+CONST64(0xeb70fbfbcbfb8b30), CONST64(0xc1cdeeee9fee2371), CONST64(0xf8bb7c7ced7cc791), CONST64(0xcc716666856617e3),
+CONST64(0xa77bdddd53dda68e), CONST64(0x2eaf17175c17b84b), CONST64(0x8e45474701470246), CONST64(0x211a9e9e429e84dc),
+CONST64(0x89d4caca0fca1ec5), CONST64(0x5a582d2db42d7599), CONST64(0x632ebfbfc6bf9179), CONST64(0x0e3f07071c07381b),
+CONST64(0x47acadad8ead0123), CONST64(0xb4b05a5a755aea2f), CONST64(0x1bef838336836cb5), CONST64(0x66b63333cc3385ff),
+CONST64(0xc65c636391633ff2), CONST64(0x041202020802100a), CONST64(0x4993aaaa92aa3938), CONST64(0xe2de7171d971afa8),
+CONST64(0x8dc6c8c807c80ecf), CONST64(0x32d119196419c87d), CONST64(0x923b494939497270), CONST64(0xaf5fd9d943d9869a),
+CONST64(0xf931f2f2eff2c31d), CONST64(0xdba8e3e3abe34b48), CONST64(0xb6b95b5b715be22a), CONST64(0x0dbc88881a883492),
+CONST64(0x293e9a9a529aa4c8), CONST64(0x4c0b262698262dbe), CONST64(0x64bf3232c8328dfa), CONST64(0x7d59b0b0fab0e94a),
+CONST64(0xcff2e9e983e91b6a), CONST64(0x1e770f0f3c0f7833), CONST64(0xb733d5d573d5e6a6), CONST64(0x1df480803a8074ba),
+CONST64(0x6127bebec2be997c), CONST64(0x87ebcdcd13cd26de), CONST64(0x68893434d034bde4), CONST64(0x903248483d487a75),
+CONST64(0xe354ffffdbffab24), CONST64(0xf48d7a7af57af78f), CONST64(0x3d6490907a90f4ea), CONST64(0xbe9d5f5f615fc23e),
+CONST64(0x403d202080201da0), CONST64(0xd00f6868bd6867d5), CONST64(0x34ca1a1a681ad072), CONST64(0x41b7aeae82ae192c),
+CONST64(0x757db4b4eab4c95e), CONST64(0xa8ce54544d549a19), CONST64(0x3b7f93937693ece5), CONST64(0x442f222288220daa),
+CONST64(0xc86364648d6407e9), CONST64(0xff2af1f1e3f1db12), CONST64(0xe6cc7373d173bfa2), CONST64(0x248212124812905a),
+CONST64(0x807a40401d403a5d), CONST64(0x1048080820084028), CONST64(0x9b95c3c32bc356e8), CONST64(0xc5dfecec97ec337b),
+CONST64(0xab4ddbdb4bdb9690), CONST64(0x5fc0a1a1bea1611f), CONST64(0x07918d8d0e8d1c83), CONST64(0x7ac83d3df43df5c9),
+CONST64(0x335b97976697ccf1), CONST64(0x0000000000000000), CONST64(0x83f9cfcf1bcf36d4), CONST64(0x566e2b2bac2b4587),
+CONST64(0xece17676c57697b3), CONST64(0x19e68282328264b0), CONST64(0xb128d6d67fd6fea9), CONST64(0x36c31b1b6c1bd877),
+CONST64(0x7774b5b5eeb5c15b), CONST64(0x43beafaf86af1129), CONST64(0xd41d6a6ab56a77df), CONST64(0xa0ea50505d50ba0d),
+CONST64(0x8a5745450945124c), CONST64(0xfb38f3f3ebf3cb18), CONST64(0x60ad3030c0309df0), CONST64(0xc3c4efef9bef2b74),
+CONST64(0x7eda3f3ffc3fe5c3), CONST64(0xaac755554955921c), CONST64(0x59dba2a2b2a27910), CONST64(0xc9e9eaea8fea0365),
+CONST64(0xca6a656589650fec), CONST64(0x6903babad2bab968), CONST64(0x5e4a2f2fbc2f6593), CONST64(0x9d8ec0c027c04ee7),
+CONST64(0xa160dede5fdebe81), CONST64(0x38fc1c1c701ce06c), CONST64(0xe746fdfdd3fdbb2e), CONST64(0x9a1f4d4d294d5264),
+CONST64(0x397692927292e4e0), CONST64(0xeafa7575c9758fbc), CONST64(0x0c3606061806301e), CONST64(0x09ae8a8a128a2498),
+CONST64(0x794bb2b2f2b2f940), CONST64(0xd185e6e6bfe66359), CONST64(0x1c7e0e0e380e7036), CONST64(0x3ee71f1f7c1ff863),
+CONST64(0xc4556262956237f7), CONST64(0xb53ad4d477d4eea3), CONST64(0x4d81a8a89aa82932), CONST64(0x315296966296c4f4),
+CONST64(0xef62f9f9c3f99b3a), CONST64(0x97a3c5c533c566f6), CONST64(0x4a102525942535b1), CONST64(0xb2ab59597959f220),
+CONST64(0x15d084842a8454ae), CONST64(0xe4c57272d572b7a7), CONST64(0x72ec3939e439d5dd), CONST64(0x98164c4c2d4c5a61),
+CONST64(0xbc945e5e655eca3b), CONST64(0xf09f7878fd78e785), CONST64(0x70e53838e038ddd8), CONST64(0x05988c8c0a8c1486),
+CONST64(0xbf17d1d163d1c6b2), CONST64(0x57e4a5a5aea5410b), CONST64(0xd9a1e2e2afe2434d), CONST64(0xc24e616199612ff8),
+CONST64(0x7b42b3b3f6b3f145), CONST64(0x42342121842115a5), CONST64(0x25089c9c4a9c94d6), CONST64(0x3cee1e1e781ef066),
+CONST64(0x8661434311432252), CONST64(0x93b1c7c73bc776fc), CONST64(0xe54ffcfcd7fcb32b), CONST64(0x0824040410042014),
+CONST64(0xa2e351515951b208), CONST64(0x2f2599995e99bcc7), CONST64(0xda226d6da96d4fc4), CONST64(0x1a650d0d340d6839),
+CONST64(0xe979fafacffa8335), CONST64(0xa369dfdf5bdfb684), CONST64(0xfca97e7ee57ed79b), CONST64(0x4819242490243db4),
+CONST64(0x76fe3b3bec3bc5d7), CONST64(0x4b9aabab96ab313d), CONST64(0x81f0cece1fce3ed1), CONST64(0x2299111144118855),
+CONST64(0x03838f8f068f0c89), CONST64(0x9c044e4e254e4a6b), CONST64(0x7366b7b7e6b7d151), CONST64(0xcbe0ebeb8beb0b60),
+CONST64(0x78c13c3cf03cfdcc), CONST64(0x1ffd81813e817cbf), CONST64(0x354094946a94d4fe), CONST64(0xf31cf7f7fbf7eb0c),
+CONST64(0x6f18b9b9deb9a167), CONST64(0x268b13134c13985f), CONST64(0x58512c2cb02c7d9c), CONST64(0xbb05d3d36bd3d6b8),
+CONST64(0xd38ce7e7bbe76b5c), CONST64(0xdc396e6ea56e57cb), CONST64(0x95aac4c437c46ef3), CONST64(0x061b03030c03180f),
+CONST64(0xacdc565645568a13), CONST64(0x885e44440d441a49), CONST64(0xfea07f7fe17fdf9e), CONST64(0x4f88a9a99ea92137),
+CONST64(0x54672a2aa82a4d82), CONST64(0x6b0abbbbd6bbb16d), CONST64(0x9f87c1c123c146e2), CONST64(0xa6f153535153a202),
+CONST64(0xa572dcdc57dcae8b), CONST64(0x16530b0b2c0b5827), CONST64(0x27019d9d4e9d9cd3), CONST64(0xd82b6c6cad6c47c1),
+CONST64(0x62a43131c43195f5), CONST64(0xe8f37474cd7487b9), CONST64(0xf115f6f6fff6e309), CONST64(0x8c4c464605460a43),
+CONST64(0x45a5acac8aac0926), CONST64(0x0fb589891e893c97), CONST64(0x28b414145014a044), CONST64(0xdfbae1e1a3e15b42),
+CONST64(0x2ca616165816b04e), CONST64(0x74f73a3ae83acdd2), CONST64(0xd2066969b9696fd0), CONST64(0x124109092409482d),
+CONST64(0xe0d77070dd70a7ad), CONST64(0x716fb6b6e2b6d954), CONST64(0xbd1ed0d067d0ceb7), CONST64(0xc7d6eded93ed3b7e),
+CONST64(0x85e2cccc17cc2edb), CONST64(0x8468424215422a57), CONST64(0x2d2c98985a98b4c2), CONST64(0x55eda4a4aaa4490e),
+CONST64(0x50752828a0285d88), CONST64(0xb8865c5c6d5cda31), CONST64(0xed6bf8f8c7f8933f), CONST64(0x11c28686228644a4)
+};
+
+static const ulong64 sbox3[] = {
+CONST64(0x7830d818186018c0), CONST64(0xaf462623238c2305), CONST64(0xf991b8c6c63fc67e), CONST64(0x6fcdfbe8e887e813),
+CONST64(0xa113cb878726874c), CONST64(0x626d11b8b8dab8a9), CONST64(0x0502090101040108), CONST64(0x6e9e0d4f4f214f42),
+CONST64(0xee6c9b3636d836ad), CONST64(0x0451ffa6a6a2a659), CONST64(0xbdb90cd2d26fd2de), CONST64(0x06f70ef5f5f3f5fb),
+CONST64(0x80f2967979f979ef), CONST64(0xcede306f6fa16f5f), CONST64(0xef3f6d91917e91fc), CONST64(0x07a4f852525552aa),
+CONST64(0xfdc04760609d6027), CONST64(0x766535bcbccabc89), CONST64(0xcd2b379b9b569bac), CONST64(0x8c018a8e8e028e04),
+CONST64(0x155bd2a3a3b6a371), CONST64(0x3c186c0c0c300c60), CONST64(0x8af6847b7bf17bff), CONST64(0xe16a803535d435b5),
+CONST64(0x693af51d1d741de8), CONST64(0x47ddb3e0e0a7e053), CONST64(0xacb321d7d77bd7f6), CONST64(0xed999cc2c22fc25e),
+CONST64(0x965c432e2eb82e6d), CONST64(0x7a96294b4b314b62), CONST64(0x21e15dfefedffea3), CONST64(0x16aed55757415782),
+CONST64(0x412abd15155415a8), CONST64(0xb6eee87777c1779f), CONST64(0xeb6e923737dc37a5), CONST64(0x56d79ee5e5b3e57b),
+CONST64(0xd923139f9f469f8c), CONST64(0x17fd23f0f0e7f0d3), CONST64(0x7f94204a4a354a6a), CONST64(0x95a944dada4fda9e),
+CONST64(0x25b0a258587d58fa), CONST64(0xca8fcfc9c903c906), CONST64(0x8d527c2929a42955), CONST64(0x22145a0a0a280a50),
+CONST64(0x4f7f50b1b1feb1e1), CONST64(0x1a5dc9a0a0baa069), CONST64(0xdad6146b6bb16b7f), CONST64(0xab17d985852e855c),
+CONST64(0x73673cbdbdcebd81), CONST64(0x34ba8f5d5d695dd2), CONST64(0x5020901010401080), CONST64(0x03f507f4f4f7f4f3),
+CONST64(0xc08bddcbcb0bcb16), CONST64(0xc67cd33e3ef83eed), CONST64(0x110a2d0505140528), CONST64(0xe6ce78676781671f),
+CONST64(0x53d597e4e4b7e473), CONST64(0xbb4e0227279c2725), CONST64(0x5882734141194132), CONST64(0x9d0ba78b8b168b2c),
+CONST64(0x0153f6a7a7a6a751), CONST64(0x94fab27d7de97dcf), CONST64(0xfb374995956e95dc), CONST64(0x9fad56d8d847d88e),
+CONST64(0x30eb70fbfbcbfb8b), CONST64(0x71c1cdeeee9fee23), CONST64(0x91f8bb7c7ced7cc7), CONST64(0xe3cc716666856617),
+CONST64(0x8ea77bdddd53dda6), CONST64(0x4b2eaf17175c17b8), CONST64(0x468e454747014702), CONST64(0xdc211a9e9e429e84),
+CONST64(0xc589d4caca0fca1e), CONST64(0x995a582d2db42d75), CONST64(0x79632ebfbfc6bf91), CONST64(0x1b0e3f07071c0738),
+CONST64(0x2347acadad8ead01), CONST64(0x2fb4b05a5a755aea), CONST64(0xb51bef838336836c), CONST64(0xff66b63333cc3385),
+CONST64(0xf2c65c636391633f), CONST64(0x0a04120202080210), CONST64(0x384993aaaa92aa39), CONST64(0xa8e2de7171d971af),
+CONST64(0xcf8dc6c8c807c80e), CONST64(0x7d32d119196419c8), CONST64(0x70923b4949394972), CONST64(0x9aaf5fd9d943d986),
+CONST64(0x1df931f2f2eff2c3), CONST64(0x48dba8e3e3abe34b), CONST64(0x2ab6b95b5b715be2), CONST64(0x920dbc88881a8834),
+CONST64(0xc8293e9a9a529aa4), CONST64(0xbe4c0b262698262d), CONST64(0xfa64bf3232c8328d), CONST64(0x4a7d59b0b0fab0e9),
+CONST64(0x6acff2e9e983e91b), CONST64(0x331e770f0f3c0f78), CONST64(0xa6b733d5d573d5e6), CONST64(0xba1df480803a8074),
+CONST64(0x7c6127bebec2be99), CONST64(0xde87ebcdcd13cd26), CONST64(0xe468893434d034bd), CONST64(0x75903248483d487a),
+CONST64(0x24e354ffffdbffab), CONST64(0x8ff48d7a7af57af7), CONST64(0xea3d6490907a90f4), CONST64(0x3ebe9d5f5f615fc2),
+CONST64(0xa0403d202080201d), CONST64(0xd5d00f6868bd6867), CONST64(0x7234ca1a1a681ad0), CONST64(0x2c41b7aeae82ae19),
+CONST64(0x5e757db4b4eab4c9), CONST64(0x19a8ce54544d549a), CONST64(0xe53b7f93937693ec), CONST64(0xaa442f222288220d),
+CONST64(0xe9c86364648d6407), CONST64(0x12ff2af1f1e3f1db), CONST64(0xa2e6cc7373d173bf), CONST64(0x5a24821212481290),
+CONST64(0x5d807a40401d403a), CONST64(0x2810480808200840), CONST64(0xe89b95c3c32bc356), CONST64(0x7bc5dfecec97ec33),
+CONST64(0x90ab4ddbdb4bdb96), CONST64(0x1f5fc0a1a1bea161), CONST64(0x8307918d8d0e8d1c), CONST64(0xc97ac83d3df43df5),
+CONST64(0xf1335b97976697cc), CONST64(0x0000000000000000), CONST64(0xd483f9cfcf1bcf36), CONST64(0x87566e2b2bac2b45),
+CONST64(0xb3ece17676c57697), CONST64(0xb019e68282328264), CONST64(0xa9b128d6d67fd6fe), CONST64(0x7736c31b1b6c1bd8),
+CONST64(0x5b7774b5b5eeb5c1), CONST64(0x2943beafaf86af11), CONST64(0xdfd41d6a6ab56a77), CONST64(0x0da0ea50505d50ba),
+CONST64(0x4c8a574545094512), CONST64(0x18fb38f3f3ebf3cb), CONST64(0xf060ad3030c0309d), CONST64(0x74c3c4efef9bef2b),
+CONST64(0xc37eda3f3ffc3fe5), CONST64(0x1caac75555495592), CONST64(0x1059dba2a2b2a279), CONST64(0x65c9e9eaea8fea03),
+CONST64(0xecca6a656589650f), CONST64(0x686903babad2bab9), CONST64(0x935e4a2f2fbc2f65), CONST64(0xe79d8ec0c027c04e),
+CONST64(0x81a160dede5fdebe), CONST64(0x6c38fc1c1c701ce0), CONST64(0x2ee746fdfdd3fdbb), CONST64(0x649a1f4d4d294d52),
+CONST64(0xe0397692927292e4), CONST64(0xbceafa7575c9758f), CONST64(0x1e0c360606180630), CONST64(0x9809ae8a8a128a24),
+CONST64(0x40794bb2b2f2b2f9), CONST64(0x59d185e6e6bfe663), CONST64(0x361c7e0e0e380e70), CONST64(0x633ee71f1f7c1ff8),
+CONST64(0xf7c4556262956237), CONST64(0xa3b53ad4d477d4ee), CONST64(0x324d81a8a89aa829), CONST64(0xf4315296966296c4),
+CONST64(0x3aef62f9f9c3f99b), CONST64(0xf697a3c5c533c566), CONST64(0xb14a102525942535), CONST64(0x20b2ab59597959f2),
+CONST64(0xae15d084842a8454), CONST64(0xa7e4c57272d572b7), CONST64(0xdd72ec3939e439d5), CONST64(0x6198164c4c2d4c5a),
+CONST64(0x3bbc945e5e655eca), CONST64(0x85f09f7878fd78e7), CONST64(0xd870e53838e038dd), CONST64(0x8605988c8c0a8c14),
+CONST64(0xb2bf17d1d163d1c6), CONST64(0x0b57e4a5a5aea541), CONST64(0x4dd9a1e2e2afe243), CONST64(0xf8c24e616199612f),
+CONST64(0x457b42b3b3f6b3f1), CONST64(0xa542342121842115), CONST64(0xd625089c9c4a9c94), CONST64(0x663cee1e1e781ef0),
+CONST64(0x5286614343114322), CONST64(0xfc93b1c7c73bc776), CONST64(0x2be54ffcfcd7fcb3), CONST64(0x1408240404100420),
+CONST64(0x08a2e351515951b2), CONST64(0xc72f2599995e99bc), CONST64(0xc4da226d6da96d4f), CONST64(0x391a650d0d340d68),
+CONST64(0x35e979fafacffa83), CONST64(0x84a369dfdf5bdfb6), CONST64(0x9bfca97e7ee57ed7), CONST64(0xb44819242490243d),
+CONST64(0xd776fe3b3bec3bc5), CONST64(0x3d4b9aabab96ab31), CONST64(0xd181f0cece1fce3e), CONST64(0x5522991111441188),
+CONST64(0x8903838f8f068f0c), CONST64(0x6b9c044e4e254e4a), CONST64(0x517366b7b7e6b7d1), CONST64(0x60cbe0ebeb8beb0b),
+CONST64(0xcc78c13c3cf03cfd), CONST64(0xbf1ffd81813e817c), CONST64(0xfe354094946a94d4), CONST64(0x0cf31cf7f7fbf7eb),
+CONST64(0x676f18b9b9deb9a1), CONST64(0x5f268b13134c1398), CONST64(0x9c58512c2cb02c7d), CONST64(0xb8bb05d3d36bd3d6),
+CONST64(0x5cd38ce7e7bbe76b), CONST64(0xcbdc396e6ea56e57), CONST64(0xf395aac4c437c46e), CONST64(0x0f061b03030c0318),
+CONST64(0x13acdc565645568a), CONST64(0x49885e44440d441a), CONST64(0x9efea07f7fe17fdf), CONST64(0x374f88a9a99ea921),
+CONST64(0x8254672a2aa82a4d), CONST64(0x6d6b0abbbbd6bbb1), CONST64(0xe29f87c1c123c146), CONST64(0x02a6f153535153a2),
+CONST64(0x8ba572dcdc57dcae), CONST64(0x2716530b0b2c0b58), CONST64(0xd327019d9d4e9d9c), CONST64(0xc1d82b6c6cad6c47),
+CONST64(0xf562a43131c43195), CONST64(0xb9e8f37474cd7487), CONST64(0x09f115f6f6fff6e3), CONST64(0x438c4c464605460a),
+CONST64(0x2645a5acac8aac09), CONST64(0x970fb589891e893c), CONST64(0x4428b414145014a0), CONST64(0x42dfbae1e1a3e15b),
+CONST64(0x4e2ca616165816b0), CONST64(0xd274f73a3ae83acd), CONST64(0xd0d2066969b9696f), CONST64(0x2d12410909240948),
+CONST64(0xade0d77070dd70a7), CONST64(0x54716fb6b6e2b6d9), CONST64(0xb7bd1ed0d067d0ce), CONST64(0x7ec7d6eded93ed3b),
+CONST64(0xdb85e2cccc17cc2e), CONST64(0x578468424215422a), CONST64(0xc22d2c98985a98b4), CONST64(0x0e55eda4a4aaa449),
+CONST64(0x8850752828a0285d), CONST64(0x31b8865c5c6d5cda), CONST64(0x3fed6bf8f8c7f893), CONST64(0xa411c28686228644)
+};
+
+static const ulong64 sbox4[] = {
+CONST64(0xc07830d818186018), CONST64(0x05af462623238c23), CONST64(0x7ef991b8c6c63fc6), CONST64(0x136fcdfbe8e887e8),
+CONST64(0x4ca113cb87872687), CONST64(0xa9626d11b8b8dab8), CONST64(0x0805020901010401), CONST64(0x426e9e0d4f4f214f),
+CONST64(0xadee6c9b3636d836), CONST64(0x590451ffa6a6a2a6), CONST64(0xdebdb90cd2d26fd2), CONST64(0xfb06f70ef5f5f3f5),
+CONST64(0xef80f2967979f979), CONST64(0x5fcede306f6fa16f), CONST64(0xfcef3f6d91917e91), CONST64(0xaa07a4f852525552),
+CONST64(0x27fdc04760609d60), CONST64(0x89766535bcbccabc), CONST64(0xaccd2b379b9b569b), CONST64(0x048c018a8e8e028e),
+CONST64(0x71155bd2a3a3b6a3), CONST64(0x603c186c0c0c300c), CONST64(0xff8af6847b7bf17b), CONST64(0xb5e16a803535d435),
+CONST64(0xe8693af51d1d741d), CONST64(0x5347ddb3e0e0a7e0), CONST64(0xf6acb321d7d77bd7), CONST64(0x5eed999cc2c22fc2),
+CONST64(0x6d965c432e2eb82e), CONST64(0x627a96294b4b314b), CONST64(0xa321e15dfefedffe), CONST64(0x8216aed557574157),
+CONST64(0xa8412abd15155415), CONST64(0x9fb6eee87777c177), CONST64(0xa5eb6e923737dc37), CONST64(0x7b56d79ee5e5b3e5),
+CONST64(0x8cd923139f9f469f), CONST64(0xd317fd23f0f0e7f0), CONST64(0x6a7f94204a4a354a), CONST64(0x9e95a944dada4fda),
+CONST64(0xfa25b0a258587d58), CONST64(0x06ca8fcfc9c903c9), CONST64(0x558d527c2929a429), CONST64(0x5022145a0a0a280a),
+CONST64(0xe14f7f50b1b1feb1), CONST64(0x691a5dc9a0a0baa0), CONST64(0x7fdad6146b6bb16b), CONST64(0x5cab17d985852e85),
+CONST64(0x8173673cbdbdcebd), CONST64(0xd234ba8f5d5d695d), CONST64(0x8050209010104010), CONST64(0xf303f507f4f4f7f4),
+CONST64(0x16c08bddcbcb0bcb), CONST64(0xedc67cd33e3ef83e), CONST64(0x28110a2d05051405), CONST64(0x1fe6ce7867678167),
+CONST64(0x7353d597e4e4b7e4), CONST64(0x25bb4e0227279c27), CONST64(0x3258827341411941), CONST64(0x2c9d0ba78b8b168b),
+CONST64(0x510153f6a7a7a6a7), CONST64(0xcf94fab27d7de97d), CONST64(0xdcfb374995956e95), CONST64(0x8e9fad56d8d847d8),
+CONST64(0x8b30eb70fbfbcbfb), CONST64(0x2371c1cdeeee9fee), CONST64(0xc791f8bb7c7ced7c), CONST64(0x17e3cc7166668566),
+CONST64(0xa68ea77bdddd53dd), CONST64(0xb84b2eaf17175c17), CONST64(0x02468e4547470147), CONST64(0x84dc211a9e9e429e),
+CONST64(0x1ec589d4caca0fca), CONST64(0x75995a582d2db42d), CONST64(0x9179632ebfbfc6bf), CONST64(0x381b0e3f07071c07),
+CONST64(0x012347acadad8ead), CONST64(0xea2fb4b05a5a755a), CONST64(0x6cb51bef83833683), CONST64(0x85ff66b63333cc33),
+CONST64(0x3ff2c65c63639163), CONST64(0x100a041202020802), CONST64(0x39384993aaaa92aa), CONST64(0xafa8e2de7171d971),
+CONST64(0x0ecf8dc6c8c807c8), CONST64(0xc87d32d119196419), CONST64(0x7270923b49493949), CONST64(0x869aaf5fd9d943d9),
+CONST64(0xc31df931f2f2eff2), CONST64(0x4b48dba8e3e3abe3), CONST64(0xe22ab6b95b5b715b), CONST64(0x34920dbc88881a88),
+CONST64(0xa4c8293e9a9a529a), CONST64(0x2dbe4c0b26269826), CONST64(0x8dfa64bf3232c832), CONST64(0xe94a7d59b0b0fab0),
+CONST64(0x1b6acff2e9e983e9), CONST64(0x78331e770f0f3c0f), CONST64(0xe6a6b733d5d573d5), CONST64(0x74ba1df480803a80),
+CONST64(0x997c6127bebec2be), CONST64(0x26de87ebcdcd13cd), CONST64(0xbde468893434d034), CONST64(0x7a75903248483d48),
+CONST64(0xab24e354ffffdbff), CONST64(0xf78ff48d7a7af57a), CONST64(0xf4ea3d6490907a90), CONST64(0xc23ebe9d5f5f615f),
+CONST64(0x1da0403d20208020), CONST64(0x67d5d00f6868bd68), CONST64(0xd07234ca1a1a681a), CONST64(0x192c41b7aeae82ae),
+CONST64(0xc95e757db4b4eab4), CONST64(0x9a19a8ce54544d54), CONST64(0xece53b7f93937693), CONST64(0x0daa442f22228822),
+CONST64(0x07e9c86364648d64), CONST64(0xdb12ff2af1f1e3f1), CONST64(0xbfa2e6cc7373d173), CONST64(0x905a248212124812),
+CONST64(0x3a5d807a40401d40), CONST64(0x4028104808082008), CONST64(0x56e89b95c3c32bc3), CONST64(0x337bc5dfecec97ec),
+CONST64(0x9690ab4ddbdb4bdb), CONST64(0x611f5fc0a1a1bea1), CONST64(0x1c8307918d8d0e8d), CONST64(0xf5c97ac83d3df43d),
+CONST64(0xccf1335b97976697), CONST64(0x0000000000000000), CONST64(0x36d483f9cfcf1bcf), CONST64(0x4587566e2b2bac2b),
+CONST64(0x97b3ece17676c576), CONST64(0x64b019e682823282), CONST64(0xfea9b128d6d67fd6), CONST64(0xd87736c31b1b6c1b),
+CONST64(0xc15b7774b5b5eeb5), CONST64(0x112943beafaf86af), CONST64(0x77dfd41d6a6ab56a), CONST64(0xba0da0ea50505d50),
+CONST64(0x124c8a5745450945), CONST64(0xcb18fb38f3f3ebf3), CONST64(0x9df060ad3030c030), CONST64(0x2b74c3c4efef9bef),
+CONST64(0xe5c37eda3f3ffc3f), CONST64(0x921caac755554955), CONST64(0x791059dba2a2b2a2), CONST64(0x0365c9e9eaea8fea),
+CONST64(0x0fecca6a65658965), CONST64(0xb9686903babad2ba), CONST64(0x65935e4a2f2fbc2f), CONST64(0x4ee79d8ec0c027c0),
+CONST64(0xbe81a160dede5fde), CONST64(0xe06c38fc1c1c701c), CONST64(0xbb2ee746fdfdd3fd), CONST64(0x52649a1f4d4d294d),
+CONST64(0xe4e0397692927292), CONST64(0x8fbceafa7575c975), CONST64(0x301e0c3606061806), CONST64(0x249809ae8a8a128a),
+CONST64(0xf940794bb2b2f2b2), CONST64(0x6359d185e6e6bfe6), CONST64(0x70361c7e0e0e380e), CONST64(0xf8633ee71f1f7c1f),
+CONST64(0x37f7c45562629562), CONST64(0xeea3b53ad4d477d4), CONST64(0x29324d81a8a89aa8), CONST64(0xc4f4315296966296),
+CONST64(0x9b3aef62f9f9c3f9), CONST64(0x66f697a3c5c533c5), CONST64(0x35b14a1025259425), CONST64(0xf220b2ab59597959),
+CONST64(0x54ae15d084842a84), CONST64(0xb7a7e4c57272d572), CONST64(0xd5dd72ec3939e439), CONST64(0x5a6198164c4c2d4c),
+CONST64(0xca3bbc945e5e655e), CONST64(0xe785f09f7878fd78), CONST64(0xddd870e53838e038), CONST64(0x148605988c8c0a8c),
+CONST64(0xc6b2bf17d1d163d1), CONST64(0x410b57e4a5a5aea5), CONST64(0x434dd9a1e2e2afe2), CONST64(0x2ff8c24e61619961),
+CONST64(0xf1457b42b3b3f6b3), CONST64(0x15a5423421218421), CONST64(0x94d625089c9c4a9c), CONST64(0xf0663cee1e1e781e),
+CONST64(0x2252866143431143), CONST64(0x76fc93b1c7c73bc7), CONST64(0xb32be54ffcfcd7fc), CONST64(0x2014082404041004),
+CONST64(0xb208a2e351515951), CONST64(0xbcc72f2599995e99), CONST64(0x4fc4da226d6da96d), CONST64(0x68391a650d0d340d),
+CONST64(0x8335e979fafacffa), CONST64(0xb684a369dfdf5bdf), CONST64(0xd79bfca97e7ee57e), CONST64(0x3db4481924249024),
+CONST64(0xc5d776fe3b3bec3b), CONST64(0x313d4b9aabab96ab), CONST64(0x3ed181f0cece1fce), CONST64(0x8855229911114411),
+CONST64(0x0c8903838f8f068f), CONST64(0x4a6b9c044e4e254e), CONST64(0xd1517366b7b7e6b7), CONST64(0x0b60cbe0ebeb8beb),
+CONST64(0xfdcc78c13c3cf03c), CONST64(0x7cbf1ffd81813e81), CONST64(0xd4fe354094946a94), CONST64(0xeb0cf31cf7f7fbf7),
+CONST64(0xa1676f18b9b9deb9), CONST64(0x985f268b13134c13), CONST64(0x7d9c58512c2cb02c), CONST64(0xd6b8bb05d3d36bd3),
+CONST64(0x6b5cd38ce7e7bbe7), CONST64(0x57cbdc396e6ea56e), CONST64(0x6ef395aac4c437c4), CONST64(0x180f061b03030c03),
+CONST64(0x8a13acdc56564556), CONST64(0x1a49885e44440d44), CONST64(0xdf9efea07f7fe17f), CONST64(0x21374f88a9a99ea9),
+CONST64(0x4d8254672a2aa82a), CONST64(0xb16d6b0abbbbd6bb), CONST64(0x46e29f87c1c123c1), CONST64(0xa202a6f153535153),
+CONST64(0xae8ba572dcdc57dc), CONST64(0x582716530b0b2c0b), CONST64(0x9cd327019d9d4e9d), CONST64(0x47c1d82b6c6cad6c),
+CONST64(0x95f562a43131c431), CONST64(0x87b9e8f37474cd74), CONST64(0xe309f115f6f6fff6), CONST64(0x0a438c4c46460546),
+CONST64(0x092645a5acac8aac), CONST64(0x3c970fb589891e89), CONST64(0xa04428b414145014), CONST64(0x5b42dfbae1e1a3e1),
+CONST64(0xb04e2ca616165816), CONST64(0xcdd274f73a3ae83a), CONST64(0x6fd0d2066969b969), CONST64(0x482d124109092409),
+CONST64(0xa7ade0d77070dd70), CONST64(0xd954716fb6b6e2b6), CONST64(0xceb7bd1ed0d067d0), CONST64(0x3b7ec7d6eded93ed),
+CONST64(0x2edb85e2cccc17cc), CONST64(0x2a57846842421542), CONST64(0xb4c22d2c98985a98), CONST64(0x490e55eda4a4aaa4),
+CONST64(0x5d8850752828a028), CONST64(0xda31b8865c5c6d5c), CONST64(0x933fed6bf8f8c7f8), CONST64(0x44a411c286862286)
+};
+
+static const ulong64 sbox5[] = {
+CONST64(0x18c07830d8181860), CONST64(0x2305af462623238c), CONST64(0xc67ef991b8c6c63f), CONST64(0xe8136fcdfbe8e887),
+CONST64(0x874ca113cb878726), CONST64(0xb8a9626d11b8b8da), CONST64(0x0108050209010104), CONST64(0x4f426e9e0d4f4f21),
+CONST64(0x36adee6c9b3636d8), CONST64(0xa6590451ffa6a6a2), CONST64(0xd2debdb90cd2d26f), CONST64(0xf5fb06f70ef5f5f3),
+CONST64(0x79ef80f2967979f9), CONST64(0x6f5fcede306f6fa1), CONST64(0x91fcef3f6d91917e), CONST64(0x52aa07a4f8525255),
+CONST64(0x6027fdc04760609d), CONST64(0xbc89766535bcbcca), CONST64(0x9baccd2b379b9b56), CONST64(0x8e048c018a8e8e02),
+CONST64(0xa371155bd2a3a3b6), CONST64(0x0c603c186c0c0c30), CONST64(0x7bff8af6847b7bf1), CONST64(0x35b5e16a803535d4),
+CONST64(0x1de8693af51d1d74), CONST64(0xe05347ddb3e0e0a7), CONST64(0xd7f6acb321d7d77b), CONST64(0xc25eed999cc2c22f),
+CONST64(0x2e6d965c432e2eb8), CONST64(0x4b627a96294b4b31), CONST64(0xfea321e15dfefedf), CONST64(0x578216aed5575741),
+CONST64(0x15a8412abd151554), CONST64(0x779fb6eee87777c1), CONST64(0x37a5eb6e923737dc), CONST64(0xe57b56d79ee5e5b3),
+CONST64(0x9f8cd923139f9f46), CONST64(0xf0d317fd23f0f0e7), CONST64(0x4a6a7f94204a4a35), CONST64(0xda9e95a944dada4f),
+CONST64(0x58fa25b0a258587d), CONST64(0xc906ca8fcfc9c903), CONST64(0x29558d527c2929a4), CONST64(0x0a5022145a0a0a28),
+CONST64(0xb1e14f7f50b1b1fe), CONST64(0xa0691a5dc9a0a0ba), CONST64(0x6b7fdad6146b6bb1), CONST64(0x855cab17d985852e),
+CONST64(0xbd8173673cbdbdce), CONST64(0x5dd234ba8f5d5d69), CONST64(0x1080502090101040), CONST64(0xf4f303f507f4f4f7),
+CONST64(0xcb16c08bddcbcb0b), CONST64(0x3eedc67cd33e3ef8), CONST64(0x0528110a2d050514), CONST64(0x671fe6ce78676781),
+CONST64(0xe47353d597e4e4b7), CONST64(0x2725bb4e0227279c), CONST64(0x4132588273414119), CONST64(0x8b2c9d0ba78b8b16),
+CONST64(0xa7510153f6a7a7a6), CONST64(0x7dcf94fab27d7de9), CONST64(0x95dcfb374995956e), CONST64(0xd88e9fad56d8d847),
+CONST64(0xfb8b30eb70fbfbcb), CONST64(0xee2371c1cdeeee9f), CONST64(0x7cc791f8bb7c7ced), CONST64(0x6617e3cc71666685),
+CONST64(0xdda68ea77bdddd53), CONST64(0x17b84b2eaf17175c), CONST64(0x4702468e45474701), CONST64(0x9e84dc211a9e9e42),
+CONST64(0xca1ec589d4caca0f), CONST64(0x2d75995a582d2db4), CONST64(0xbf9179632ebfbfc6), CONST64(0x07381b0e3f07071c),
+CONST64(0xad012347acadad8e), CONST64(0x5aea2fb4b05a5a75), CONST64(0x836cb51bef838336), CONST64(0x3385ff66b63333cc),
+CONST64(0x633ff2c65c636391), CONST64(0x02100a0412020208), CONST64(0xaa39384993aaaa92), CONST64(0x71afa8e2de7171d9),
+CONST64(0xc80ecf8dc6c8c807), CONST64(0x19c87d32d1191964), CONST64(0x497270923b494939), CONST64(0xd9869aaf5fd9d943),
+CONST64(0xf2c31df931f2f2ef), CONST64(0xe34b48dba8e3e3ab), CONST64(0x5be22ab6b95b5b71), CONST64(0x8834920dbc88881a),
+CONST64(0x9aa4c8293e9a9a52), CONST64(0x262dbe4c0b262698), CONST64(0x328dfa64bf3232c8), CONST64(0xb0e94a7d59b0b0fa),
+CONST64(0xe91b6acff2e9e983), CONST64(0x0f78331e770f0f3c), CONST64(0xd5e6a6b733d5d573), CONST64(0x8074ba1df480803a),
+CONST64(0xbe997c6127bebec2), CONST64(0xcd26de87ebcdcd13), CONST64(0x34bde468893434d0), CONST64(0x487a75903248483d),
+CONST64(0xffab24e354ffffdb), CONST64(0x7af78ff48d7a7af5), CONST64(0x90f4ea3d6490907a), CONST64(0x5fc23ebe9d5f5f61),
+CONST64(0x201da0403d202080), CONST64(0x6867d5d00f6868bd), CONST64(0x1ad07234ca1a1a68), CONST64(0xae192c41b7aeae82),
+CONST64(0xb4c95e757db4b4ea), CONST64(0x549a19a8ce54544d), CONST64(0x93ece53b7f939376), CONST64(0x220daa442f222288),
+CONST64(0x6407e9c86364648d), CONST64(0xf1db12ff2af1f1e3), CONST64(0x73bfa2e6cc7373d1), CONST64(0x12905a2482121248),
+CONST64(0x403a5d807a40401d), CONST64(0x0840281048080820), CONST64(0xc356e89b95c3c32b), CONST64(0xec337bc5dfecec97),
+CONST64(0xdb9690ab4ddbdb4b), CONST64(0xa1611f5fc0a1a1be), CONST64(0x8d1c8307918d8d0e), CONST64(0x3df5c97ac83d3df4),
+CONST64(0x97ccf1335b979766), CONST64(0x0000000000000000), CONST64(0xcf36d483f9cfcf1b), CONST64(0x2b4587566e2b2bac),
+CONST64(0x7697b3ece17676c5), CONST64(0x8264b019e6828232), CONST64(0xd6fea9b128d6d67f), CONST64(0x1bd87736c31b1b6c),
+CONST64(0xb5c15b7774b5b5ee), CONST64(0xaf112943beafaf86), CONST64(0x6a77dfd41d6a6ab5), CONST64(0x50ba0da0ea50505d),
+CONST64(0x45124c8a57454509), CONST64(0xf3cb18fb38f3f3eb), CONST64(0x309df060ad3030c0), CONST64(0xef2b74c3c4efef9b),
+CONST64(0x3fe5c37eda3f3ffc), CONST64(0x55921caac7555549), CONST64(0xa2791059dba2a2b2), CONST64(0xea0365c9e9eaea8f),
+CONST64(0x650fecca6a656589), CONST64(0xbab9686903babad2), CONST64(0x2f65935e4a2f2fbc), CONST64(0xc04ee79d8ec0c027),
+CONST64(0xdebe81a160dede5f), CONST64(0x1ce06c38fc1c1c70), CONST64(0xfdbb2ee746fdfdd3), CONST64(0x4d52649a1f4d4d29),
+CONST64(0x92e4e03976929272), CONST64(0x758fbceafa7575c9), CONST64(0x06301e0c36060618), CONST64(0x8a249809ae8a8a12),
+CONST64(0xb2f940794bb2b2f2), CONST64(0xe66359d185e6e6bf), CONST64(0x0e70361c7e0e0e38), CONST64(0x1ff8633ee71f1f7c),
+CONST64(0x6237f7c455626295), CONST64(0xd4eea3b53ad4d477), CONST64(0xa829324d81a8a89a), CONST64(0x96c4f43152969662),
+CONST64(0xf99b3aef62f9f9c3), CONST64(0xc566f697a3c5c533), CONST64(0x2535b14a10252594), CONST64(0x59f220b2ab595979),
+CONST64(0x8454ae15d084842a), CONST64(0x72b7a7e4c57272d5), CONST64(0x39d5dd72ec3939e4), CONST64(0x4c5a6198164c4c2d),
+CONST64(0x5eca3bbc945e5e65), CONST64(0x78e785f09f7878fd), CONST64(0x38ddd870e53838e0), CONST64(0x8c148605988c8c0a),
+CONST64(0xd1c6b2bf17d1d163), CONST64(0xa5410b57e4a5a5ae), CONST64(0xe2434dd9a1e2e2af), CONST64(0x612ff8c24e616199),
+CONST64(0xb3f1457b42b3b3f6), CONST64(0x2115a54234212184), CONST64(0x9c94d625089c9c4a), CONST64(0x1ef0663cee1e1e78),
+CONST64(0x4322528661434311), CONST64(0xc776fc93b1c7c73b), CONST64(0xfcb32be54ffcfcd7), CONST64(0x0420140824040410),
+CONST64(0x51b208a2e3515159), CONST64(0x99bcc72f2599995e), CONST64(0x6d4fc4da226d6da9), CONST64(0x0d68391a650d0d34),
+CONST64(0xfa8335e979fafacf), CONST64(0xdfb684a369dfdf5b), CONST64(0x7ed79bfca97e7ee5), CONST64(0x243db44819242490),
+CONST64(0x3bc5d776fe3b3bec), CONST64(0xab313d4b9aabab96), CONST64(0xce3ed181f0cece1f), CONST64(0x1188552299111144),
+CONST64(0x8f0c8903838f8f06), CONST64(0x4e4a6b9c044e4e25), CONST64(0xb7d1517366b7b7e6), CONST64(0xeb0b60cbe0ebeb8b),
+CONST64(0x3cfdcc78c13c3cf0), CONST64(0x817cbf1ffd81813e), CONST64(0x94d4fe354094946a), CONST64(0xf7eb0cf31cf7f7fb),
+CONST64(0xb9a1676f18b9b9de), CONST64(0x13985f268b13134c), CONST64(0x2c7d9c58512c2cb0), CONST64(0xd3d6b8bb05d3d36b),
+CONST64(0xe76b5cd38ce7e7bb), CONST64(0x6e57cbdc396e6ea5), CONST64(0xc46ef395aac4c437), CONST64(0x03180f061b03030c),
+CONST64(0x568a13acdc565645), CONST64(0x441a49885e44440d), CONST64(0x7fdf9efea07f7fe1), CONST64(0xa921374f88a9a99e),
+CONST64(0x2a4d8254672a2aa8), CONST64(0xbbb16d6b0abbbbd6), CONST64(0xc146e29f87c1c123), CONST64(0x53a202a6f1535351),
+CONST64(0xdcae8ba572dcdc57), CONST64(0x0b582716530b0b2c), CONST64(0x9d9cd327019d9d4e), CONST64(0x6c47c1d82b6c6cad),
+CONST64(0x3195f562a43131c4), CONST64(0x7487b9e8f37474cd), CONST64(0xf6e309f115f6f6ff), CONST64(0x460a438c4c464605),
+CONST64(0xac092645a5acac8a), CONST64(0x893c970fb589891e), CONST64(0x14a04428b4141450), CONST64(0xe15b42dfbae1e1a3),
+CONST64(0x16b04e2ca6161658), CONST64(0x3acdd274f73a3ae8), CONST64(0x696fd0d2066969b9), CONST64(0x09482d1241090924),
+CONST64(0x70a7ade0d77070dd), CONST64(0xb6d954716fb6b6e2), CONST64(0xd0ceb7bd1ed0d067), CONST64(0xed3b7ec7d6eded93),
+CONST64(0xcc2edb85e2cccc17), CONST64(0x422a578468424215), CONST64(0x98b4c22d2c98985a), CONST64(0xa4490e55eda4a4aa),
+CONST64(0x285d8850752828a0), CONST64(0x5cda31b8865c5c6d), CONST64(0xf8933fed6bf8f8c7), CONST64(0x8644a411c2868622)
+};
+
+static const ulong64 sbox6[] = {
+CONST64(0x6018c07830d81818), CONST64(0x8c2305af46262323), CONST64(0x3fc67ef991b8c6c6), CONST64(0x87e8136fcdfbe8e8),
+CONST64(0x26874ca113cb8787), CONST64(0xdab8a9626d11b8b8), CONST64(0x0401080502090101), CONST64(0x214f426e9e0d4f4f),
+CONST64(0xd836adee6c9b3636), CONST64(0xa2a6590451ffa6a6), CONST64(0x6fd2debdb90cd2d2), CONST64(0xf3f5fb06f70ef5f5),
+CONST64(0xf979ef80f2967979), CONST64(0xa16f5fcede306f6f), CONST64(0x7e91fcef3f6d9191), CONST64(0x5552aa07a4f85252),
+CONST64(0x9d6027fdc0476060), CONST64(0xcabc89766535bcbc), CONST64(0x569baccd2b379b9b), CONST64(0x028e048c018a8e8e),
+CONST64(0xb6a371155bd2a3a3), CONST64(0x300c603c186c0c0c), CONST64(0xf17bff8af6847b7b), CONST64(0xd435b5e16a803535),
+CONST64(0x741de8693af51d1d), CONST64(0xa7e05347ddb3e0e0), CONST64(0x7bd7f6acb321d7d7), CONST64(0x2fc25eed999cc2c2),
+CONST64(0xb82e6d965c432e2e), CONST64(0x314b627a96294b4b), CONST64(0xdffea321e15dfefe), CONST64(0x41578216aed55757),
+CONST64(0x5415a8412abd1515), CONST64(0xc1779fb6eee87777), CONST64(0xdc37a5eb6e923737), CONST64(0xb3e57b56d79ee5e5),
+CONST64(0x469f8cd923139f9f), CONST64(0xe7f0d317fd23f0f0), CONST64(0x354a6a7f94204a4a), CONST64(0x4fda9e95a944dada),
+CONST64(0x7d58fa25b0a25858), CONST64(0x03c906ca8fcfc9c9), CONST64(0xa429558d527c2929), CONST64(0x280a5022145a0a0a),
+CONST64(0xfeb1e14f7f50b1b1), CONST64(0xbaa0691a5dc9a0a0), CONST64(0xb16b7fdad6146b6b), CONST64(0x2e855cab17d98585),
+CONST64(0xcebd8173673cbdbd), CONST64(0x695dd234ba8f5d5d), CONST64(0x4010805020901010), CONST64(0xf7f4f303f507f4f4),
+CONST64(0x0bcb16c08bddcbcb), CONST64(0xf83eedc67cd33e3e), CONST64(0x140528110a2d0505), CONST64(0x81671fe6ce786767),
+CONST64(0xb7e47353d597e4e4), CONST64(0x9c2725bb4e022727), CONST64(0x1941325882734141), CONST64(0x168b2c9d0ba78b8b),
+CONST64(0xa6a7510153f6a7a7), CONST64(0xe97dcf94fab27d7d), CONST64(0x6e95dcfb37499595), CONST64(0x47d88e9fad56d8d8),
+CONST64(0xcbfb8b30eb70fbfb), CONST64(0x9fee2371c1cdeeee), CONST64(0xed7cc791f8bb7c7c), CONST64(0x856617e3cc716666),
+CONST64(0x53dda68ea77bdddd), CONST64(0x5c17b84b2eaf1717), CONST64(0x014702468e454747), CONST64(0x429e84dc211a9e9e),
+CONST64(0x0fca1ec589d4caca), CONST64(0xb42d75995a582d2d), CONST64(0xc6bf9179632ebfbf), CONST64(0x1c07381b0e3f0707),
+CONST64(0x8ead012347acadad), CONST64(0x755aea2fb4b05a5a), CONST64(0x36836cb51bef8383), CONST64(0xcc3385ff66b63333),
+CONST64(0x91633ff2c65c6363), CONST64(0x0802100a04120202), CONST64(0x92aa39384993aaaa), CONST64(0xd971afa8e2de7171),
+CONST64(0x07c80ecf8dc6c8c8), CONST64(0x6419c87d32d11919), CONST64(0x39497270923b4949), CONST64(0x43d9869aaf5fd9d9),
+CONST64(0xeff2c31df931f2f2), CONST64(0xabe34b48dba8e3e3), CONST64(0x715be22ab6b95b5b), CONST64(0x1a8834920dbc8888),
+CONST64(0x529aa4c8293e9a9a), CONST64(0x98262dbe4c0b2626), CONST64(0xc8328dfa64bf3232), CONST64(0xfab0e94a7d59b0b0),
+CONST64(0x83e91b6acff2e9e9), CONST64(0x3c0f78331e770f0f), CONST64(0x73d5e6a6b733d5d5), CONST64(0x3a8074ba1df48080),
+CONST64(0xc2be997c6127bebe), CONST64(0x13cd26de87ebcdcd), CONST64(0xd034bde468893434), CONST64(0x3d487a7590324848),
+CONST64(0xdbffab24e354ffff), CONST64(0xf57af78ff48d7a7a), CONST64(0x7a90f4ea3d649090), CONST64(0x615fc23ebe9d5f5f),
+CONST64(0x80201da0403d2020), CONST64(0xbd6867d5d00f6868), CONST64(0x681ad07234ca1a1a), CONST64(0x82ae192c41b7aeae),
+CONST64(0xeab4c95e757db4b4), CONST64(0x4d549a19a8ce5454), CONST64(0x7693ece53b7f9393), CONST64(0x88220daa442f2222),
+CONST64(0x8d6407e9c8636464), CONST64(0xe3f1db12ff2af1f1), CONST64(0xd173bfa2e6cc7373), CONST64(0x4812905a24821212),
+CONST64(0x1d403a5d807a4040), CONST64(0x2008402810480808), CONST64(0x2bc356e89b95c3c3), CONST64(0x97ec337bc5dfecec),
+CONST64(0x4bdb9690ab4ddbdb), CONST64(0xbea1611f5fc0a1a1), CONST64(0x0e8d1c8307918d8d), CONST64(0xf43df5c97ac83d3d),
+CONST64(0x6697ccf1335b9797), CONST64(0x0000000000000000), CONST64(0x1bcf36d483f9cfcf), CONST64(0xac2b4587566e2b2b),
+CONST64(0xc57697b3ece17676), CONST64(0x328264b019e68282), CONST64(0x7fd6fea9b128d6d6), CONST64(0x6c1bd87736c31b1b),
+CONST64(0xeeb5c15b7774b5b5), CONST64(0x86af112943beafaf), CONST64(0xb56a77dfd41d6a6a), CONST64(0x5d50ba0da0ea5050),
+CONST64(0x0945124c8a574545), CONST64(0xebf3cb18fb38f3f3), CONST64(0xc0309df060ad3030), CONST64(0x9bef2b74c3c4efef),
+CONST64(0xfc3fe5c37eda3f3f), CONST64(0x4955921caac75555), CONST64(0xb2a2791059dba2a2), CONST64(0x8fea0365c9e9eaea),
+CONST64(0x89650fecca6a6565), CONST64(0xd2bab9686903baba), CONST64(0xbc2f65935e4a2f2f), CONST64(0x27c04ee79d8ec0c0),
+CONST64(0x5fdebe81a160dede), CONST64(0x701ce06c38fc1c1c), CONST64(0xd3fdbb2ee746fdfd), CONST64(0x294d52649a1f4d4d),
+CONST64(0x7292e4e039769292), CONST64(0xc9758fbceafa7575), CONST64(0x1806301e0c360606), CONST64(0x128a249809ae8a8a),
+CONST64(0xf2b2f940794bb2b2), CONST64(0xbfe66359d185e6e6), CONST64(0x380e70361c7e0e0e), CONST64(0x7c1ff8633ee71f1f),
+CONST64(0x956237f7c4556262), CONST64(0x77d4eea3b53ad4d4), CONST64(0x9aa829324d81a8a8), CONST64(0x6296c4f431529696),
+CONST64(0xc3f99b3aef62f9f9), CONST64(0x33c566f697a3c5c5), CONST64(0x942535b14a102525), CONST64(0x7959f220b2ab5959),
+CONST64(0x2a8454ae15d08484), CONST64(0xd572b7a7e4c57272), CONST64(0xe439d5dd72ec3939), CONST64(0x2d4c5a6198164c4c),
+CONST64(0x655eca3bbc945e5e), CONST64(0xfd78e785f09f7878), CONST64(0xe038ddd870e53838), CONST64(0x0a8c148605988c8c),
+CONST64(0x63d1c6b2bf17d1d1), CONST64(0xaea5410b57e4a5a5), CONST64(0xafe2434dd9a1e2e2), CONST64(0x99612ff8c24e6161),
+CONST64(0xf6b3f1457b42b3b3), CONST64(0x842115a542342121), CONST64(0x4a9c94d625089c9c), CONST64(0x781ef0663cee1e1e),
+CONST64(0x1143225286614343), CONST64(0x3bc776fc93b1c7c7), CONST64(0xd7fcb32be54ffcfc), CONST64(0x1004201408240404),
+CONST64(0x5951b208a2e35151), CONST64(0x5e99bcc72f259999), CONST64(0xa96d4fc4da226d6d), CONST64(0x340d68391a650d0d),
+CONST64(0xcffa8335e979fafa), CONST64(0x5bdfb684a369dfdf), CONST64(0xe57ed79bfca97e7e), CONST64(0x90243db448192424),
+CONST64(0xec3bc5d776fe3b3b), CONST64(0x96ab313d4b9aabab), CONST64(0x1fce3ed181f0cece), CONST64(0x4411885522991111),
+CONST64(0x068f0c8903838f8f), CONST64(0x254e4a6b9c044e4e), CONST64(0xe6b7d1517366b7b7), CONST64(0x8beb0b60cbe0ebeb),
+CONST64(0xf03cfdcc78c13c3c), CONST64(0x3e817cbf1ffd8181), CONST64(0x6a94d4fe35409494), CONST64(0xfbf7eb0cf31cf7f7),
+CONST64(0xdeb9a1676f18b9b9), CONST64(0x4c13985f268b1313), CONST64(0xb02c7d9c58512c2c), CONST64(0x6bd3d6b8bb05d3d3),
+CONST64(0xbbe76b5cd38ce7e7), CONST64(0xa56e57cbdc396e6e), CONST64(0x37c46ef395aac4c4), CONST64(0x0c03180f061b0303),
+CONST64(0x45568a13acdc5656), CONST64(0x0d441a49885e4444), CONST64(0xe17fdf9efea07f7f), CONST64(0x9ea921374f88a9a9),
+CONST64(0xa82a4d8254672a2a), CONST64(0xd6bbb16d6b0abbbb), CONST64(0x23c146e29f87c1c1), CONST64(0x5153a202a6f15353),
+CONST64(0x57dcae8ba572dcdc), CONST64(0x2c0b582716530b0b), CONST64(0x4e9d9cd327019d9d), CONST64(0xad6c47c1d82b6c6c),
+CONST64(0xc43195f562a43131), CONST64(0xcd7487b9e8f37474), CONST64(0xfff6e309f115f6f6), CONST64(0x05460a438c4c4646),
+CONST64(0x8aac092645a5acac), CONST64(0x1e893c970fb58989), CONST64(0x5014a04428b41414), CONST64(0xa3e15b42dfbae1e1),
+CONST64(0x5816b04e2ca61616), CONST64(0xe83acdd274f73a3a), CONST64(0xb9696fd0d2066969), CONST64(0x2409482d12410909),
+CONST64(0xdd70a7ade0d77070), CONST64(0xe2b6d954716fb6b6), CONST64(0x67d0ceb7bd1ed0d0), CONST64(0x93ed3b7ec7d6eded),
+CONST64(0x17cc2edb85e2cccc), CONST64(0x15422a5784684242), CONST64(0x5a98b4c22d2c9898), CONST64(0xaaa4490e55eda4a4),
+CONST64(0xa0285d8850752828), CONST64(0x6d5cda31b8865c5c), CONST64(0xc7f8933fed6bf8f8), CONST64(0x228644a411c28686)
+};
+
+static const ulong64 sbox7[] = {
+CONST64(0x186018c07830d818), CONST64(0x238c2305af462623), CONST64(0xc63fc67ef991b8c6), CONST64(0xe887e8136fcdfbe8),
+CONST64(0x8726874ca113cb87), CONST64(0xb8dab8a9626d11b8), CONST64(0x0104010805020901), CONST64(0x4f214f426e9e0d4f),
+CONST64(0x36d836adee6c9b36), CONST64(0xa6a2a6590451ffa6), CONST64(0xd26fd2debdb90cd2), CONST64(0xf5f3f5fb06f70ef5),
+CONST64(0x79f979ef80f29679), CONST64(0x6fa16f5fcede306f), CONST64(0x917e91fcef3f6d91), CONST64(0x525552aa07a4f852),
+CONST64(0x609d6027fdc04760), CONST64(0xbccabc89766535bc), CONST64(0x9b569baccd2b379b), CONST64(0x8e028e048c018a8e),
+CONST64(0xa3b6a371155bd2a3), CONST64(0x0c300c603c186c0c), CONST64(0x7bf17bff8af6847b), CONST64(0x35d435b5e16a8035),
+CONST64(0x1d741de8693af51d), CONST64(0xe0a7e05347ddb3e0), CONST64(0xd77bd7f6acb321d7), CONST64(0xc22fc25eed999cc2),
+CONST64(0x2eb82e6d965c432e), CONST64(0x4b314b627a96294b), CONST64(0xfedffea321e15dfe), CONST64(0x5741578216aed557),
+CONST64(0x155415a8412abd15), CONST64(0x77c1779fb6eee877), CONST64(0x37dc37a5eb6e9237), CONST64(0xe5b3e57b56d79ee5),
+CONST64(0x9f469f8cd923139f), CONST64(0xf0e7f0d317fd23f0), CONST64(0x4a354a6a7f94204a), CONST64(0xda4fda9e95a944da),
+CONST64(0x587d58fa25b0a258), CONST64(0xc903c906ca8fcfc9), CONST64(0x29a429558d527c29), CONST64(0x0a280a5022145a0a),
+CONST64(0xb1feb1e14f7f50b1), CONST64(0xa0baa0691a5dc9a0), CONST64(0x6bb16b7fdad6146b), CONST64(0x852e855cab17d985),
+CONST64(0xbdcebd8173673cbd), CONST64(0x5d695dd234ba8f5d), CONST64(0x1040108050209010), CONST64(0xf4f7f4f303f507f4),
+CONST64(0xcb0bcb16c08bddcb), CONST64(0x3ef83eedc67cd33e), CONST64(0x05140528110a2d05), CONST64(0x6781671fe6ce7867),
+CONST64(0xe4b7e47353d597e4), CONST64(0x279c2725bb4e0227), CONST64(0x4119413258827341), CONST64(0x8b168b2c9d0ba78b),
+CONST64(0xa7a6a7510153f6a7), CONST64(0x7de97dcf94fab27d), CONST64(0x956e95dcfb374995), CONST64(0xd847d88e9fad56d8),
+CONST64(0xfbcbfb8b30eb70fb), CONST64(0xee9fee2371c1cdee), CONST64(0x7ced7cc791f8bb7c), CONST64(0x66856617e3cc7166),
+CONST64(0xdd53dda68ea77bdd), CONST64(0x175c17b84b2eaf17), CONST64(0x47014702468e4547), CONST64(0x9e429e84dc211a9e),
+CONST64(0xca0fca1ec589d4ca), CONST64(0x2db42d75995a582d), CONST64(0xbfc6bf9179632ebf), CONST64(0x071c07381b0e3f07),
+CONST64(0xad8ead012347acad), CONST64(0x5a755aea2fb4b05a), CONST64(0x8336836cb51bef83), CONST64(0x33cc3385ff66b633),
+CONST64(0x6391633ff2c65c63), CONST64(0x020802100a041202), CONST64(0xaa92aa39384993aa), CONST64(0x71d971afa8e2de71),
+CONST64(0xc807c80ecf8dc6c8), CONST64(0x196419c87d32d119), CONST64(0x4939497270923b49), CONST64(0xd943d9869aaf5fd9),
+CONST64(0xf2eff2c31df931f2), CONST64(0xe3abe34b48dba8e3), CONST64(0x5b715be22ab6b95b), CONST64(0x881a8834920dbc88),
+CONST64(0x9a529aa4c8293e9a), CONST64(0x2698262dbe4c0b26), CONST64(0x32c8328dfa64bf32), CONST64(0xb0fab0e94a7d59b0),
+CONST64(0xe983e91b6acff2e9), CONST64(0x0f3c0f78331e770f), CONST64(0xd573d5e6a6b733d5), CONST64(0x803a8074ba1df480),
+CONST64(0xbec2be997c6127be), CONST64(0xcd13cd26de87ebcd), CONST64(0x34d034bde4688934), CONST64(0x483d487a75903248),
+CONST64(0xffdbffab24e354ff), CONST64(0x7af57af78ff48d7a), CONST64(0x907a90f4ea3d6490), CONST64(0x5f615fc23ebe9d5f),
+CONST64(0x2080201da0403d20), CONST64(0x68bd6867d5d00f68), CONST64(0x1a681ad07234ca1a), CONST64(0xae82ae192c41b7ae),
+CONST64(0xb4eab4c95e757db4), CONST64(0x544d549a19a8ce54), CONST64(0x937693ece53b7f93), CONST64(0x2288220daa442f22),
+CONST64(0x648d6407e9c86364), CONST64(0xf1e3f1db12ff2af1), CONST64(0x73d173bfa2e6cc73), CONST64(0x124812905a248212),
+CONST64(0x401d403a5d807a40), CONST64(0x0820084028104808), CONST64(0xc32bc356e89b95c3), CONST64(0xec97ec337bc5dfec),
+CONST64(0xdb4bdb9690ab4ddb), CONST64(0xa1bea1611f5fc0a1), CONST64(0x8d0e8d1c8307918d), CONST64(0x3df43df5c97ac83d),
+CONST64(0x976697ccf1335b97), CONST64(0x0000000000000000), CONST64(0xcf1bcf36d483f9cf), CONST64(0x2bac2b4587566e2b),
+CONST64(0x76c57697b3ece176), CONST64(0x82328264b019e682), CONST64(0xd67fd6fea9b128d6), CONST64(0x1b6c1bd87736c31b),
+CONST64(0xb5eeb5c15b7774b5), CONST64(0xaf86af112943beaf), CONST64(0x6ab56a77dfd41d6a), CONST64(0x505d50ba0da0ea50),
+CONST64(0x450945124c8a5745), CONST64(0xf3ebf3cb18fb38f3), CONST64(0x30c0309df060ad30), CONST64(0xef9bef2b74c3c4ef),
+CONST64(0x3ffc3fe5c37eda3f), CONST64(0x554955921caac755), CONST64(0xa2b2a2791059dba2), CONST64(0xea8fea0365c9e9ea),
+CONST64(0x6589650fecca6a65), CONST64(0xbad2bab9686903ba), CONST64(0x2fbc2f65935e4a2f), CONST64(0xc027c04ee79d8ec0),
+CONST64(0xde5fdebe81a160de), CONST64(0x1c701ce06c38fc1c), CONST64(0xfdd3fdbb2ee746fd), CONST64(0x4d294d52649a1f4d),
+CONST64(0x927292e4e0397692), CONST64(0x75c9758fbceafa75), CONST64(0x061806301e0c3606), CONST64(0x8a128a249809ae8a),
+CONST64(0xb2f2b2f940794bb2), CONST64(0xe6bfe66359d185e6), CONST64(0x0e380e70361c7e0e), CONST64(0x1f7c1ff8633ee71f),
+CONST64(0x62956237f7c45562), CONST64(0xd477d4eea3b53ad4), CONST64(0xa89aa829324d81a8), CONST64(0x966296c4f4315296),
+CONST64(0xf9c3f99b3aef62f9), CONST64(0xc533c566f697a3c5), CONST64(0x25942535b14a1025), CONST64(0x597959f220b2ab59),
+CONST64(0x842a8454ae15d084), CONST64(0x72d572b7a7e4c572), CONST64(0x39e439d5dd72ec39), CONST64(0x4c2d4c5a6198164c),
+CONST64(0x5e655eca3bbc945e), CONST64(0x78fd78e785f09f78), CONST64(0x38e038ddd870e538), CONST64(0x8c0a8c148605988c),
+CONST64(0xd163d1c6b2bf17d1), CONST64(0xa5aea5410b57e4a5), CONST64(0xe2afe2434dd9a1e2), CONST64(0x6199612ff8c24e61),
+CONST64(0xb3f6b3f1457b42b3), CONST64(0x21842115a5423421), CONST64(0x9c4a9c94d625089c), CONST64(0x1e781ef0663cee1e),
+CONST64(0x4311432252866143), CONST64(0xc73bc776fc93b1c7), CONST64(0xfcd7fcb32be54ffc), CONST64(0x0410042014082404),
+CONST64(0x515951b208a2e351), CONST64(0x995e99bcc72f2599), CONST64(0x6da96d4fc4da226d), CONST64(0x0d340d68391a650d),
+CONST64(0xfacffa8335e979fa), CONST64(0xdf5bdfb684a369df), CONST64(0x7ee57ed79bfca97e), CONST64(0x2490243db4481924),
+CONST64(0x3bec3bc5d776fe3b), CONST64(0xab96ab313d4b9aab), CONST64(0xce1fce3ed181f0ce), CONST64(0x1144118855229911),
+CONST64(0x8f068f0c8903838f), CONST64(0x4e254e4a6b9c044e), CONST64(0xb7e6b7d1517366b7), CONST64(0xeb8beb0b60cbe0eb),
+CONST64(0x3cf03cfdcc78c13c), CONST64(0x813e817cbf1ffd81), CONST64(0x946a94d4fe354094), CONST64(0xf7fbf7eb0cf31cf7),
+CONST64(0xb9deb9a1676f18b9), CONST64(0x134c13985f268b13), CONST64(0x2cb02c7d9c58512c), CONST64(0xd36bd3d6b8bb05d3),
+CONST64(0xe7bbe76b5cd38ce7), CONST64(0x6ea56e57cbdc396e), CONST64(0xc437c46ef395aac4), CONST64(0x030c03180f061b03),
+CONST64(0x5645568a13acdc56), CONST64(0x440d441a49885e44), CONST64(0x7fe17fdf9efea07f), CONST64(0xa99ea921374f88a9),
+CONST64(0x2aa82a4d8254672a), CONST64(0xbbd6bbb16d6b0abb), CONST64(0xc123c146e29f87c1), CONST64(0x535153a202a6f153),
+CONST64(0xdc57dcae8ba572dc), CONST64(0x0b2c0b582716530b), CONST64(0x9d4e9d9cd327019d), CONST64(0x6cad6c47c1d82b6c),
+CONST64(0x31c43195f562a431), CONST64(0x74cd7487b9e8f374), CONST64(0xf6fff6e309f115f6), CONST64(0x4605460a438c4c46),
+CONST64(0xac8aac092645a5ac), CONST64(0x891e893c970fb589), CONST64(0x145014a04428b414), CONST64(0xe1a3e15b42dfbae1),
+CONST64(0x165816b04e2ca616), CONST64(0x3ae83acdd274f73a), CONST64(0x69b9696fd0d20669), CONST64(0x092409482d124109),
+CONST64(0x70dd70a7ade0d770), CONST64(0xb6e2b6d954716fb6), CONST64(0xd067d0ceb7bd1ed0), CONST64(0xed93ed3b7ec7d6ed),
+CONST64(0xcc17cc2edb85e2cc), CONST64(0x4215422a57846842), CONST64(0x985a98b4c22d2c98), CONST64(0xa4aaa4490e55eda4),
+CONST64(0x28a0285d88507528), CONST64(0x5c6d5cda31b8865c), CONST64(0xf8c7f8933fed6bf8), CONST64(0x86228644a411c286)
+};
+
+#endif
+
+static const ulong64 cont[] = {
+CONST64(0x1823c6e887b8014f),
+CONST64(0x36a6d2f5796f9152),
+CONST64(0x60bc9b8ea30c7b35),
+CONST64(0x1de0d7c22e4bfe57),
+CONST64(0x157737e59ff04ada),
+CONST64(0x58c9290ab1a06b85),
+CONST64(0xbd5d10f4cb3e0567),
+CONST64(0xe427418ba77d95d8),
+CONST64(0xfbee7c66dd17479e),
+CONST64(0xca2dbf07ad5a8333),
+CONST64(0x6302aa71c81949d9),
+};
+
+#endif /* __LTC_WHIRLTAB_C__ */
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/headers/tomcrypt.h b/libtomcrypt/src/headers/tomcrypt.h
new file mode 100644 (file)
index 0000000..f4442d2
--- /dev/null
@@ -0,0 +1,105 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+#ifndef TOMCRYPT_H_
+#define TOMCRYPT_H_
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <time.h>
+#include <ctype.h>
+#include <limits.h>
+
+/* use configuration data */
+#include <tomcrypt_custom.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* version */
+#define CRYPT   0x0118
+#define SCRYPT  "1.18.2"
+
+/* max size of either a cipher/hash block or symmetric key [largest of the two] */
+#define MAXBLOCKSIZE  128
+
+#ifndef TAB_SIZE
+/* descriptor table size */
+#define TAB_SIZE      32
+#endif
+
+/* error codes [will be expanded in future releases] */
+enum {
+   CRYPT_OK=0,             /* Result OK */
+   CRYPT_ERROR,            /* Generic Error */
+   CRYPT_NOP,              /* Not a failure but no operation was performed */
+
+   CRYPT_INVALID_KEYSIZE,  /* Invalid key size given */
+   CRYPT_INVALID_ROUNDS,   /* Invalid number of rounds */
+   CRYPT_FAIL_TESTVECTOR,  /* Algorithm failed test vectors */
+
+   CRYPT_BUFFER_OVERFLOW,  /* Not enough space for output */
+   CRYPT_INVALID_PACKET,   /* Invalid input packet given */
+
+   CRYPT_INVALID_PRNGSIZE, /* Invalid number of bits for a PRNG */
+   CRYPT_ERROR_READPRNG,   /* Could not read enough from PRNG */
+
+   CRYPT_INVALID_CIPHER,   /* Invalid cipher specified */
+   CRYPT_INVALID_HASH,     /* Invalid hash specified */
+   CRYPT_INVALID_PRNG,     /* Invalid PRNG specified */
+
+   CRYPT_MEM,              /* Out of memory */
+
+   CRYPT_PK_TYPE_MISMATCH, /* Not equivalent types of PK keys */
+   CRYPT_PK_NOT_PRIVATE,   /* Requires a private PK key */
+
+   CRYPT_INVALID_ARG,      /* Generic invalid argument */
+   CRYPT_FILE_NOTFOUND,    /* File Not Found */
+
+   CRYPT_PK_INVALID_TYPE,  /* Invalid type of PK key */
+
+   CRYPT_OVERFLOW,         /* An overflow of a value was detected/prevented */
+
+   CRYPT_UNUSED1,          /* UNUSED1 */
+
+   CRYPT_INPUT_TOO_LONG,   /* The input was longer than expected. */
+
+   CRYPT_PK_INVALID_SIZE,  /* Invalid size input for PK parameters */
+
+   CRYPT_INVALID_PRIME_SIZE,/* Invalid size of prime requested */
+   CRYPT_PK_INVALID_PADDING, /* Invalid padding on input */
+
+   CRYPT_HASH_OVERFLOW      /* Hash applied to too many bits */
+};
+
+#include <tomcrypt_cfg.h>
+#include <tomcrypt_macros.h>
+#include <tomcrypt_cipher.h>
+#include <tomcrypt_hash.h>
+#include <tomcrypt_mac.h>
+#include <tomcrypt_prng.h>
+#include <tomcrypt_pk.h>
+#include <tomcrypt_math.h>
+#include <tomcrypt_misc.h>
+#include <tomcrypt_argchk.h>
+#include <tomcrypt_pkcs.h>
+
+#ifdef __cplusplus
+   }
+#endif
+
+#endif /* TOMCRYPT_H_ */
+
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/headers/tomcrypt_argchk.h b/libtomcrypt/src/headers/tomcrypt_argchk.h
new file mode 100644 (file)
index 0000000..be9ef0f
--- /dev/null
@@ -0,0 +1,53 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+/* Defines the LTC_ARGCHK macro used within the library */
+/* ARGTYPE is defined in tomcrypt_cfg.h */
+#if ARGTYPE == 0
+
+#include <signal.h>
+
+/* this is the default LibTomCrypt macro  */
+#if defined(__clang__) || defined(__GNUC_MINOR__)
+#define NORETURN __attribute__ ((noreturn))
+#else
+#define NORETURN
+#endif
+
+void crypt_argchk(const char *v, const char *s, int d) NORETURN;
+#define LTC_ARGCHK(x) do { if (!(x)) { crypt_argchk(#x, __FILE__, __LINE__); } }while(0)
+#define LTC_ARGCHKVD(x) do { if (!(x)) { crypt_argchk(#x, __FILE__, __LINE__); } }while(0)
+
+#elif ARGTYPE == 1
+
+/* fatal type of error */
+#define LTC_ARGCHK(x) assert((x))
+#define LTC_ARGCHKVD(x) LTC_ARGCHK(x)
+
+#elif ARGTYPE == 2
+
+#define LTC_ARGCHK(x) if (!(x)) { fprintf(stderr, "\nwarning: ARGCHK failed at %s:%d\n", __FILE__, __LINE__); }
+#define LTC_ARGCHKVD(x) LTC_ARGCHK(x)
+
+#elif ARGTYPE == 3
+
+#define LTC_ARGCHK(x)
+#define LTC_ARGCHKVD(x) LTC_ARGCHK(x)
+
+#elif ARGTYPE == 4
+
+#define LTC_ARGCHK(x)   if (!(x)) return CRYPT_INVALID_ARG;
+#define LTC_ARGCHKVD(x) if (!(x)) return;
+
+#endif
+
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/headers/tomcrypt_cfg.h b/libtomcrypt/src/headers/tomcrypt_cfg.h
new file mode 100644 (file)
index 0000000..b3fc68a
--- /dev/null
@@ -0,0 +1,285 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+/* This is the build config file.
+ *
+ * With this you can setup what to inlcude/exclude automatically during any
+ * build.  Just comment out the line that #define's the word for the thing you
+ * want to remove.  phew!
+ */
+
+#ifndef TOMCRYPT_CFG_H
+#define TOMCRYPT_CFG_H
+
+#if defined(_WIN32) || defined(_MSC_VER)
+   #define LTC_CALL __cdecl
+#elif !defined(LTC_CALL)
+   #define LTC_CALL
+#endif
+
+#ifndef LTC_EXPORT
+   #define LTC_EXPORT
+#endif
+
+/* certain platforms use macros for these, making the prototypes broken */
+#ifndef LTC_NO_PROTOTYPES
+
+/* you can change how memory allocation works ... */
+LTC_EXPORT void * LTC_CALL XMALLOC(size_t n);
+LTC_EXPORT void * LTC_CALL XREALLOC(void *p, size_t n);
+LTC_EXPORT void * LTC_CALL XCALLOC(size_t n, size_t s);
+LTC_EXPORT void LTC_CALL XFREE(void *p);
+
+LTC_EXPORT void LTC_CALL XQSORT(void *base, size_t nmemb, size_t size, int(*compar)(const void *, const void *));
+
+
+/* change the clock function too */
+LTC_EXPORT clock_t LTC_CALL XCLOCK(void);
+
+/* various other functions */
+LTC_EXPORT void * LTC_CALL XMEMCPY(void *dest, const void *src, size_t n);
+LTC_EXPORT int   LTC_CALL XMEMCMP(const void *s1, const void *s2, size_t n);
+LTC_EXPORT void * LTC_CALL XMEMSET(void *s, int c, size_t n);
+
+LTC_EXPORT int   LTC_CALL XSTRCMP(const char *s1, const char *s2);
+
+#endif
+
+/* some compilers do not like "inline" (or maybe "static inline"), namely: HP
+ * cc, IBM xlc */
+#if defined(__HP_cc) || defined(__xlc__)
+   #define LTC_INLINE
+#elif defined(_MSC_VER)
+   #define LTC_INLINE __inline
+#else
+   #define LTC_INLINE inline
+#endif
+
+/* type of argument checking, 0=default, 1=fatal and 2=error+continue, 3=nothing */
+#ifndef ARGTYPE
+   #define ARGTYPE  0
+#endif
+
+#undef LTC_ENCRYPT
+#define LTC_ENCRYPT 0
+#undef LTC_DECRYPT
+#define LTC_DECRYPT 1
+
+/* Controls endianess and size of registers.  Leave uncommented to get platform neutral [slower] code
+ *
+ * Note: in order to use the optimized macros your platform must support unaligned 32 and 64 bit read/writes.
+ * The x86 platforms allow this but some others [ARM for instance] do not.  On those platforms you **MUST**
+ * use the portable [slower] macros.
+ */
+/* detect x86/i386 32bit */
+#if defined(__i386__) || defined(__i386) || defined(_M_IX86)
+   #define ENDIAN_LITTLE
+   #define ENDIAN_32BITWORD
+   #define LTC_FAST
+#endif
+
+/* detect amd64/x64 */
+#if defined(__x86_64__) || defined(_M_X64) || defined(_M_AMD64)
+   #define ENDIAN_LITTLE
+   #define ENDIAN_64BITWORD
+   #define LTC_FAST
+#endif
+
+/* detect PPC32 */
+#if defined(LTC_PPC32)
+   #define ENDIAN_BIG
+   #define ENDIAN_32BITWORD
+   #define LTC_FAST
+#endif
+
+/* detects MIPS R5900 processors (PS2) */
+#if (defined(__R5900) || defined(R5900) || defined(__R5900__)) && (defined(_mips) || defined(__mips__) || defined(mips))
+   #define ENDIAN_64BITWORD
+   #if defined(_MIPSEB) || defined(__MIPSEB) || defined(__MIPSEB__)
+     #define ENDIAN_BIG
+   #endif
+     #define ENDIAN_LITTLE
+   #endif
+#endif
+
+/* detect AIX */
+#if defined(_AIX) && defined(_BIG_ENDIAN)
+  #define ENDIAN_BIG
+  #if defined(__LP64__) || defined(_ARCH_PPC64)
+    #define ENDIAN_64BITWORD
+  #else
+    #define ENDIAN_32BITWORD
+  #endif
+#endif
+
+/* detect HP-UX */
+#if defined(__hpux) || defined(__hpux__)
+  #define ENDIAN_BIG
+  #if defined(__ia64) || defined(__ia64__) || defined(__LP64__)
+    #define ENDIAN_64BITWORD
+  #else
+    #define ENDIAN_32BITWORD
+  #endif
+#endif
+
+/* detect Apple OS X */
+#if defined(__APPLE__) && defined(__MACH__)
+  #if defined(__LITTLE_ENDIAN__) || defined(__x86_64__)
+    #define ENDIAN_LITTLE
+  #else
+    #define ENDIAN_BIG
+  #endif
+  #if defined(__LP64__) || defined(__x86_64__)
+    #define ENDIAN_64BITWORD
+  #else
+    #define ENDIAN_32BITWORD
+  #endif
+#endif
+
+/* detect SPARC and SPARC64 */
+#if defined(__sparc__) || defined(__sparc)
+  #define ENDIAN_BIG
+  #if defined(__arch64__) || defined(__sparcv9) || defined(__sparc_v9__)
+    #define ENDIAN_64BITWORD
+  #else
+    #define ENDIAN_32BITWORD
+  #endif
+#endif
+
+/* detect IBM S390(x) */
+#if defined(__s390x__) || defined(__s390__)
+  #define ENDIAN_BIG
+  #if defined(__s390x__)
+    #define ENDIAN_64BITWORD
+  #else
+    #define ENDIAN_32BITWORD
+  #endif
+#endif
+
+/* detect PPC64 */
+#if defined(__powerpc64__) || defined(__ppc64__) || defined(__PPC64__)
+   #define ENDIAN_64BITWORD
+   #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+      #define ENDIAN_BIG
+   #elif  __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+      #define ENDIAN_LITTLE
+   #endif
+   #define LTC_FAST
+#endif
+
+/* endianness fallback */
+#if !defined(ENDIAN_BIG) && !defined(ENDIAN_LITTLE)
+  #if defined(_BYTE_ORDER) && _BYTE_ORDER == _BIG_ENDIAN || \
+      defined(__BYTE_ORDER) && __BYTE_ORDER == __BIG_ENDIAN || \
+      defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ || \
+      defined(__BIG_ENDIAN__) || \
+      defined(__ARMEB__) || defined(__THUMBEB__) || defined(__AARCH64EB__) || \
+      defined(_MIPSEB) || defined(__MIPSEB) || defined(__MIPSEB__)
+    #define ENDIAN_BIG
+  #elif defined(_BYTE_ORDER) && _BYTE_ORDER == _LITTLE_ENDIAN || \
+      defined(__BYTE_ORDER) && __BYTE_ORDER == __LITTLE_ENDIAN || \
+      defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ || \
+      defined(__LITTLE_ENDIAN__) || \
+      defined(__ARMEL__) || defined(__THUMBEL__) || defined(__AARCH64EL__) || \
+      defined(_MIPSEL) || defined(__MIPSEL) || defined(__MIPSEL__)
+    #define ENDIAN_LITTLE
+  #else
+    #error Cannot detect endianness
+  #endif
+#endif
+
+/* ulong64: 64-bit data type */
+#ifdef _MSC_VER
+   #define CONST64(n) n ## ui64
+   typedef unsigned __int64 ulong64;
+#else
+   #define CONST64(n) n ## ULL
+   typedef unsigned long long ulong64;
+#endif
+
+/* ulong32: "32-bit at least" data type */
+#if defined(__x86_64__) || defined(_M_X64) || defined(_M_AMD64) || \
+    defined(__powerpc64__) || defined(__ppc64__) || defined(__PPC64__) || \
+    defined(__s390x__) || defined(__arch64__) || defined(__aarch64__) || \
+    defined(__sparcv9) || defined(__sparc_v9__) || defined(__sparc64__) || \
+    defined(__ia64) || defined(__ia64__) || defined(__itanium__) || defined(_M_IA64) || \
+    defined(__LP64__) || defined(_LP64) || defined(__64BIT__)
+   typedef unsigned ulong32;
+   #if !defined(ENDIAN_64BITWORD) && !defined(ENDIAN_32BITWORD)
+     #define ENDIAN_64BITWORD
+   #endif
+#else
+   typedef unsigned long ulong32;
+   #if !defined(ENDIAN_64BITWORD) && !defined(ENDIAN_32BITWORD)
+     #define ENDIAN_32BITWORD
+   #endif
+#endif
+
+#if defined(ENDIAN_64BITWORD) && !defined(_MSC_VER)
+typedef unsigned long long ltc_mp_digit;
+#else
+typedef unsigned long ltc_mp_digit;
+#endif
+
+/* No asm is a quick way to disable anything "not portable" */
+#ifdef LTC_NO_ASM
+   #define ENDIAN_NEUTRAL
+   #undef ENDIAN_32BITWORD
+   #undef ENDIAN_64BITWORD
+   #undef LTC_FAST
+   #define LTC_NO_ROLC
+   #define LTC_NO_BSWAP
+#endif
+
+/* No LTC_FAST if: explicitly disabled OR non-gcc/non-clang compiler OR old gcc OR using -ansi -std=c99 */
+#if defined(LTC_NO_FAST) || (__GNUC__ < 4) || defined(__STRICT_ANSI__)
+   #undef LTC_FAST
+#endif
+
+#ifdef LTC_FAST
+   #define LTC_FAST_TYPE_PTR_CAST(x) ((LTC_FAST_TYPE*)(void*)(x))
+   #ifdef ENDIAN_64BITWORD
+   typedef ulong64 __attribute__((__may_alias__)) LTC_FAST_TYPE;
+   #else
+   typedef ulong32 __attribute__((__may_alias__)) LTC_FAST_TYPE;
+   #endif
+#endif
+
+#if !defined(ENDIAN_NEUTRAL) && (defined(ENDIAN_BIG) || defined(ENDIAN_LITTLE)) && !(defined(ENDIAN_32BITWORD) || defined(ENDIAN_64BITWORD))
+   #error You must specify a word size as well as endianess in tomcrypt_cfg.h
+#endif
+
+#if !(defined(ENDIAN_BIG) || defined(ENDIAN_LITTLE))
+   #define ENDIAN_NEUTRAL
+#endif
+
+#if (defined(ENDIAN_32BITWORD) && defined(ENDIAN_64BITWORD))
+   #error Cannot be 32 and 64 bit words...
+#endif
+
+/* gcc 4.3 and up has a bswap builtin; detect it by gcc version.
+ * clang also supports the bswap builtin, and although clang pretends
+ * to be gcc (macro-wise, anyway), clang pretends to be a version
+ * prior to gcc 4.3, so we can't detect bswap that way.  Instead,
+ * clang has a __has_builtin mechanism that can be used to check
+ * for builtins:
+ * http://clang.llvm.org/docs/LanguageExtensions.html#feature_check */
+#ifndef __has_builtin
+   #define __has_builtin(x) 0
+#endif
+#if !defined(LTC_NO_BSWAP) && defined(__GNUC__) &&                      \
+   ((__GNUC__ * 100 + __GNUC_MINOR__ >= 403) ||                         \
+    (__has_builtin(__builtin_bswap32) && __has_builtin(__builtin_bswap64)))
+   #define LTC_HAVE_BSWAP_BUILTIN
+#endif
+
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/headers/tomcrypt_cipher.h b/libtomcrypt/src/headers/tomcrypt_cipher.h
new file mode 100644 (file)
index 0000000..2ed201d
--- /dev/null
@@ -0,0 +1,1008 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+/* ---- SYMMETRIC KEY STUFF -----
+ *
+ * We put each of the ciphers scheduled keys in their own structs then we put all of
+ * the key formats in one union.  This makes the function prototypes easier to use.
+ */
+#ifdef LTC_BLOWFISH
+struct blowfish_key {
+   ulong32 S[4][256];
+   ulong32 K[18];
+};
+#endif
+
+#ifdef LTC_RC5
+struct rc5_key {
+   int rounds;
+   ulong32 K[50];
+};
+#endif
+
+#ifdef LTC_RC6
+struct rc6_key {
+   ulong32 K[44];
+};
+#endif
+
+#ifdef LTC_SAFERP
+struct saferp_key {
+   unsigned char K[33][16];
+   long rounds;
+};
+#endif
+
+#ifdef LTC_RIJNDAEL
+struct rijndael_key {
+   ulong32 eK[60], dK[60];
+   int Nr;
+};
+#endif
+
+#ifdef LTC_KSEED
+struct kseed_key {
+    ulong32 K[32], dK[32];
+};
+#endif
+
+#ifdef LTC_KASUMI
+struct kasumi_key {
+    ulong32 KLi1[8], KLi2[8],
+            KOi1[8], KOi2[8], KOi3[8],
+            KIi1[8], KIi2[8], KIi3[8];
+};
+#endif
+
+#ifdef LTC_XTEA
+struct xtea_key {
+   unsigned long A[32], B[32];
+};
+#endif
+
+#ifdef LTC_TWOFISH
+#ifndef LTC_TWOFISH_SMALL
+   struct twofish_key {
+      ulong32 S[4][256], K[40];
+   };
+#else
+   struct twofish_key {
+      ulong32 K[40];
+      unsigned char S[32], start;
+   };
+#endif
+#endif
+
+#ifdef LTC_SAFER
+#define LTC_SAFER_K64_DEFAULT_NOF_ROUNDS     6
+#define LTC_SAFER_K128_DEFAULT_NOF_ROUNDS   10
+#define LTC_SAFER_SK64_DEFAULT_NOF_ROUNDS    8
+#define LTC_SAFER_SK128_DEFAULT_NOF_ROUNDS  10
+#define LTC_SAFER_MAX_NOF_ROUNDS            13
+#define LTC_SAFER_BLOCK_LEN                  8
+#define LTC_SAFER_KEY_LEN     (1 + LTC_SAFER_BLOCK_LEN * (1 + 2 * LTC_SAFER_MAX_NOF_ROUNDS))
+typedef unsigned char safer_block_t[LTC_SAFER_BLOCK_LEN];
+typedef unsigned char safer_key_t[LTC_SAFER_KEY_LEN];
+struct safer_key { safer_key_t key; };
+#endif
+
+#ifdef LTC_RC2
+struct rc2_key { unsigned xkey[64]; };
+#endif
+
+#ifdef LTC_DES
+struct des_key {
+    ulong32 ek[32], dk[32];
+};
+
+struct des3_key {
+    ulong32 ek[3][32], dk[3][32];
+};
+#endif
+
+#ifdef LTC_CAST5
+struct cast5_key {
+    ulong32 K[32], keylen;
+};
+#endif
+
+#ifdef LTC_NOEKEON
+struct noekeon_key {
+    ulong32 K[4], dK[4];
+};
+#endif
+
+#ifdef LTC_SKIPJACK
+struct skipjack_key {
+    unsigned char key[10];
+};
+#endif
+
+#ifdef LTC_KHAZAD
+struct khazad_key {
+   ulong64 roundKeyEnc[8 + 1];
+   ulong64 roundKeyDec[8 + 1];
+};
+#endif
+
+#ifdef LTC_ANUBIS
+struct anubis_key {
+   int keyBits;
+   int R;
+   ulong32 roundKeyEnc[18 + 1][4];
+   ulong32 roundKeyDec[18 + 1][4];
+};
+#endif
+
+#ifdef LTC_MULTI2
+struct multi2_key {
+    int N;
+    ulong32 uk[8];
+};
+#endif
+
+#ifdef LTC_CAMELLIA
+struct camellia_key {
+    int R;
+    ulong64 kw[4], k[24], kl[6];
+};
+#endif
+
+typedef union Symmetric_key {
+#ifdef LTC_DES
+   struct des_key des;
+   struct des3_key des3;
+#endif
+#ifdef LTC_RC2
+   struct rc2_key rc2;
+#endif
+#ifdef LTC_SAFER
+   struct safer_key safer;
+#endif
+#ifdef LTC_TWOFISH
+   struct twofish_key  twofish;
+#endif
+#ifdef LTC_BLOWFISH
+   struct blowfish_key blowfish;
+#endif
+#ifdef LTC_RC5
+   struct rc5_key      rc5;
+#endif
+#ifdef LTC_RC6
+   struct rc6_key      rc6;
+#endif
+#ifdef LTC_SAFERP
+   struct saferp_key   saferp;
+#endif
+#ifdef LTC_RIJNDAEL
+   struct rijndael_key rijndael;
+#endif
+#ifdef LTC_XTEA
+   struct xtea_key     xtea;
+#endif
+#ifdef LTC_CAST5
+   struct cast5_key    cast5;
+#endif
+#ifdef LTC_NOEKEON
+   struct noekeon_key  noekeon;
+#endif
+#ifdef LTC_SKIPJACK
+   struct skipjack_key skipjack;
+#endif
+#ifdef LTC_KHAZAD
+   struct khazad_key   khazad;
+#endif
+#ifdef LTC_ANUBIS
+   struct anubis_key   anubis;
+#endif
+#ifdef LTC_KSEED
+   struct kseed_key    kseed;
+#endif
+#ifdef LTC_KASUMI
+   struct kasumi_key   kasumi;
+#endif
+#ifdef LTC_MULTI2
+   struct multi2_key   multi2;
+#endif
+#ifdef LTC_CAMELLIA
+   struct camellia_key camellia;
+#endif
+   void   *data;
+} symmetric_key;
+
+#ifdef LTC_ECB_MODE
+/** A block cipher ECB structure */
+typedef struct {
+   /** The index of the cipher chosen */
+   int                 cipher,
+   /** The block size of the given cipher */
+                       blocklen;
+   /** The scheduled key */
+   symmetric_key       key;
+} symmetric_ECB;
+#endif
+
+#ifdef LTC_CFB_MODE
+/** A block cipher CFB structure */
+typedef struct {
+   /** The index of the cipher chosen */
+   int                 cipher,
+   /** The block size of the given cipher */
+                       blocklen,
+   /** The padding offset */
+                       padlen;
+   /** The current IV */
+   unsigned char       IV[MAXBLOCKSIZE],
+   /** The pad used to encrypt/decrypt */
+                       pad[MAXBLOCKSIZE];
+   /** The scheduled key */
+   symmetric_key       key;
+} symmetric_CFB;
+#endif
+
+#ifdef LTC_OFB_MODE
+/** A block cipher OFB structure */
+typedef struct {
+   /** The index of the cipher chosen */
+   int                 cipher,
+   /** The block size of the given cipher */
+                       blocklen,
+   /** The padding offset */
+                       padlen;
+   /** The current IV */
+   unsigned char       IV[MAXBLOCKSIZE];
+   /** The scheduled key */
+   symmetric_key       key;
+} symmetric_OFB;
+#endif
+
+#ifdef LTC_CBC_MODE
+/** A block cipher CBC structure */
+typedef struct {
+   /** The index of the cipher chosen */
+   int                 cipher,
+   /** The block size of the given cipher */
+                       blocklen;
+   /** The current IV */
+   unsigned char       IV[MAXBLOCKSIZE];
+   /** The scheduled key */
+   symmetric_key       key;
+} symmetric_CBC;
+#endif
+
+
+#ifdef LTC_CTR_MODE
+/** A block cipher CTR structure */
+typedef struct {
+   /** The index of the cipher chosen */
+   int                 cipher,
+   /** The block size of the given cipher */
+                       blocklen,
+   /** The padding offset */
+                       padlen,
+   /** The mode (endianess) of the CTR, 0==little, 1==big */
+                       mode,
+   /** counter width */
+                       ctrlen;
+
+   /** The counter */
+   unsigned char       ctr[MAXBLOCKSIZE],
+   /** The pad used to encrypt/decrypt */
+                       pad[MAXBLOCKSIZE];
+   /** The scheduled key */
+   symmetric_key       key;
+} symmetric_CTR;
+#endif
+
+
+#ifdef LTC_LRW_MODE
+/** A LRW structure */
+typedef struct {
+    /** The index of the cipher chosen (must be a 128-bit block cipher) */
+    int               cipher;
+
+    /** The current IV */
+    unsigned char     IV[16],
+
+    /** the tweak key */
+                      tweak[16],
+
+    /** The current pad, it's the product of the first 15 bytes against the tweak key */
+                      pad[16];
+
+    /** The scheduled symmetric key */
+    symmetric_key     key;
+
+#ifdef LTC_LRW_TABLES
+    /** The pre-computed multiplication table */
+    unsigned char     PC[16][256][16];
+#endif
+} symmetric_LRW;
+#endif
+
+#ifdef LTC_F8_MODE
+/** A block cipher F8 structure */
+typedef struct {
+   /** The index of the cipher chosen */
+   int                 cipher,
+   /** The block size of the given cipher */
+                       blocklen,
+   /** The padding offset */
+                       padlen;
+   /** The current IV */
+   unsigned char       IV[MAXBLOCKSIZE],
+                       MIV[MAXBLOCKSIZE];
+   /** Current block count */
+   ulong32             blockcnt;
+   /** The scheduled key */
+   symmetric_key       key;
+} symmetric_F8;
+#endif
+
+
+/** cipher descriptor table, last entry has "name == NULL" to mark the end of table */
+extern struct ltc_cipher_descriptor {
+   /** name of cipher */
+   const char *name;
+   /** internal ID */
+   unsigned char ID;
+   /** min keysize (octets) */
+   int  min_key_length,
+   /** max keysize (octets) */
+        max_key_length,
+   /** block size (octets) */
+        block_length,
+   /** default number of rounds */
+        default_rounds;
+   /** Setup the cipher
+      @param key         The input symmetric key
+      @param keylen      The length of the input key (octets)
+      @param num_rounds  The requested number of rounds (0==default)
+      @param skey        [out] The destination of the scheduled key
+      @return CRYPT_OK if successful
+   */
+   int  (*setup)(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
+   /** Encrypt a block
+      @param pt      The plaintext
+      @param ct      [out] The ciphertext
+      @param skey    The scheduled key
+      @return CRYPT_OK if successful
+   */
+   int (*ecb_encrypt)(const unsigned char *pt, unsigned char *ct, symmetric_key *skey);
+   /** Decrypt a block
+      @param ct      The ciphertext
+      @param pt      [out] The plaintext
+      @param skey    The scheduled key
+      @return CRYPT_OK if successful
+   */
+   int (*ecb_decrypt)(const unsigned char *ct, unsigned char *pt, symmetric_key *skey);
+   /** Test the block cipher
+       @return CRYPT_OK if successful, CRYPT_NOP if self-testing has been disabled
+   */
+   int (*test)(void);
+
+   /** Terminate the context
+      @param skey    The scheduled key
+   */
+   void (*done)(symmetric_key *skey);
+
+   /** Determine a key size
+       @param keysize    [in/out] The size of the key desired and the suggested size
+       @return CRYPT_OK if successful
+   */
+   int  (*keysize)(int *keysize);
+
+/** Accelerators **/
+   /** Accelerated ECB encryption
+       @param pt      Plaintext
+       @param ct      Ciphertext
+       @param blocks  The number of complete blocks to process
+       @param skey    The scheduled key context
+       @return CRYPT_OK if successful
+   */
+   int (*accel_ecb_encrypt)(const unsigned char *pt, unsigned char *ct, unsigned long blocks, symmetric_key *skey);
+
+   /** Accelerated ECB decryption
+       @param pt      Plaintext
+       @param ct      Ciphertext
+       @param blocks  The number of complete blocks to process
+       @param skey    The scheduled key context
+       @return CRYPT_OK if successful
+   */
+   int (*accel_ecb_decrypt)(const unsigned char *ct, unsigned char *pt, unsigned long blocks, symmetric_key *skey);
+
+   /** Accelerated CBC encryption
+       @param pt      Plaintext
+       @param ct      Ciphertext
+       @param blocks  The number of complete blocks to process
+       @param IV      The initial value (input/output)
+       @param skey    The scheduled key context
+       @return CRYPT_OK if successful
+   */
+   int (*accel_cbc_encrypt)(const unsigned char *pt, unsigned char *ct, unsigned long blocks, unsigned char *IV, symmetric_key *skey);
+
+   /** Accelerated CBC decryption
+       @param pt      Plaintext
+       @param ct      Ciphertext
+       @param blocks  The number of complete blocks to process
+       @param IV      The initial value (input/output)
+       @param skey    The scheduled key context
+       @return CRYPT_OK if successful
+   */
+   int (*accel_cbc_decrypt)(const unsigned char *ct, unsigned char *pt, unsigned long blocks, unsigned char *IV, symmetric_key *skey);
+
+   /** Accelerated CTR encryption
+       @param pt      Plaintext
+       @param ct      Ciphertext
+       @param blocks  The number of complete blocks to process
+       @param IV      The initial value (input/output)
+       @param mode    little or big endian counter (mode=0 or mode=1)
+       @param skey    The scheduled key context
+       @return CRYPT_OK if successful
+   */
+   int (*accel_ctr_encrypt)(const unsigned char *pt, unsigned char *ct, unsigned long blocks, unsigned char *IV, int mode, symmetric_key *skey);
+
+   /** Accelerated LRW
+       @param pt      Plaintext
+       @param ct      Ciphertext
+       @param blocks  The number of complete blocks to process
+       @param IV      The initial value (input/output)
+       @param tweak   The LRW tweak
+       @param skey    The scheduled key context
+       @return CRYPT_OK if successful
+   */
+   int (*accel_lrw_encrypt)(const unsigned char *pt, unsigned char *ct, unsigned long blocks, unsigned char *IV, const unsigned char *tweak, symmetric_key *skey);
+
+   /** Accelerated LRW
+       @param ct      Ciphertext
+       @param pt      Plaintext
+       @param blocks  The number of complete blocks to process
+       @param IV      The initial value (input/output)
+       @param tweak   The LRW tweak
+       @param skey    The scheduled key context
+       @return CRYPT_OK if successful
+   */
+   int (*accel_lrw_decrypt)(const unsigned char *ct, unsigned char *pt, unsigned long blocks, unsigned char *IV, const unsigned char *tweak, symmetric_key *skey);
+
+   /** Accelerated CCM packet (one-shot)
+       @param key        The secret key to use
+       @param keylen     The length of the secret key (octets)
+       @param uskey      A previously scheduled key [optional can be NULL]
+       @param nonce      The session nonce [use once]
+       @param noncelen   The length of the nonce
+       @param header     The header for the session
+       @param headerlen  The length of the header (octets)
+       @param pt         [out] The plaintext
+       @param ptlen      The length of the plaintext (octets)
+       @param ct         [out] The ciphertext
+       @param tag        [out] The destination tag
+       @param taglen     [in/out] The max size and resulting size of the authentication tag
+       @param direction  Encrypt or Decrypt direction (0 or 1)
+       @return CRYPT_OK if successful
+   */
+   int (*accel_ccm_memory)(
+       const unsigned char *key,    unsigned long keylen,
+       symmetric_key       *uskey,
+       const unsigned char *nonce,  unsigned long noncelen,
+       const unsigned char *header, unsigned long headerlen,
+             unsigned char *pt,     unsigned long ptlen,
+             unsigned char *ct,
+             unsigned char *tag,    unsigned long *taglen,
+                       int  direction);
+
+   /** Accelerated GCM packet (one shot)
+       @param key        The secret key
+       @param keylen     The length of the secret key
+       @param IV         The initialization vector
+       @param IVlen      The length of the initialization vector
+       @param adata      The additional authentication data (header)
+       @param adatalen   The length of the adata
+       @param pt         The plaintext
+       @param ptlen      The length of the plaintext (ciphertext length is the same)
+       @param ct         The ciphertext
+       @param tag        [out] The MAC tag
+       @param taglen     [in/out] The MAC tag length
+       @param direction  Encrypt or Decrypt mode (GCM_ENCRYPT or GCM_DECRYPT)
+       @return CRYPT_OK on success
+   */
+   int (*accel_gcm_memory)(
+       const unsigned char *key,    unsigned long keylen,
+       const unsigned char *IV,     unsigned long IVlen,
+       const unsigned char *adata,  unsigned long adatalen,
+             unsigned char *pt,     unsigned long ptlen,
+             unsigned char *ct,
+             unsigned char *tag,    unsigned long *taglen,
+                       int direction);
+
+   /** Accelerated one shot LTC_OMAC
+       @param key            The secret key
+       @param keylen         The key length (octets)
+       @param in             The message
+       @param inlen          Length of message (octets)
+       @param out            [out] Destination for tag
+       @param outlen         [in/out] Initial and final size of out
+       @return CRYPT_OK on success
+   */
+   int (*omac_memory)(
+       const unsigned char *key, unsigned long keylen,
+       const unsigned char *in,  unsigned long inlen,
+             unsigned char *out, unsigned long *outlen);
+
+   /** Accelerated one shot XCBC
+       @param key            The secret key
+       @param keylen         The key length (octets)
+       @param in             The message
+       @param inlen          Length of message (octets)
+       @param out            [out] Destination for tag
+       @param outlen         [in/out] Initial and final size of out
+       @return CRYPT_OK on success
+   */
+   int (*xcbc_memory)(
+       const unsigned char *key, unsigned long keylen,
+       const unsigned char *in,  unsigned long inlen,
+             unsigned char *out, unsigned long *outlen);
+
+   /** Accelerated one shot F9
+       @param key            The secret key
+       @param keylen         The key length (octets)
+       @param in             The message
+       @param inlen          Length of message (octets)
+       @param out            [out] Destination for tag
+       @param outlen         [in/out] Initial and final size of out
+       @return CRYPT_OK on success
+       @remark Requires manual padding
+   */
+   int (*f9_memory)(
+       const unsigned char *key, unsigned long keylen,
+       const unsigned char *in,  unsigned long inlen,
+             unsigned char *out, unsigned long *outlen);
+
+   /** Accelerated XTS encryption
+       @param pt      Plaintext
+       @param ct      Ciphertext
+       @param blocks  The number of complete blocks to process
+       @param tweak   The 128-bit encryption tweak (input/output).
+                      The tweak should not be encrypted on input, but
+                      next tweak will be copied encrypted on output.
+       @param skey1   The first scheduled key context
+       @param skey2   The second scheduled key context
+       @return CRYPT_OK if successful
+    */
+    int (*accel_xts_encrypt)(const unsigned char *pt, unsigned char *ct,
+        unsigned long blocks, unsigned char *tweak, symmetric_key *skey1,
+        symmetric_key *skey2);
+
+    /** Accelerated XTS decryption
+        @param ct      Ciphertext
+        @param pt      Plaintext
+        @param blocks  The number of complete blocks to process
+        @param tweak   The 128-bit encryption tweak (input/output).
+                       The tweak should not be encrypted on input, but
+                       next tweak will be copied encrypted on output.
+        @param skey1   The first scheduled key context
+        @param skey2   The second scheduled key context
+        @return CRYPT_OK if successful
+     */
+     int (*accel_xts_decrypt)(const unsigned char *ct, unsigned char *pt,
+         unsigned long blocks, unsigned char *tweak, symmetric_key *skey1,
+         symmetric_key *skey2);
+} cipher_descriptor[];
+
+#ifdef LTC_BLOWFISH
+int blowfish_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
+int blowfish_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey);
+int blowfish_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey);
+int blowfish_test(void);
+void blowfish_done(symmetric_key *skey);
+int blowfish_keysize(int *keysize);
+extern const struct ltc_cipher_descriptor blowfish_desc;
+#endif
+
+#ifdef LTC_RC5
+int rc5_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
+int rc5_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey);
+int rc5_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey);
+int rc5_test(void);
+void rc5_done(symmetric_key *skey);
+int rc5_keysize(int *keysize);
+extern const struct ltc_cipher_descriptor rc5_desc;
+#endif
+
+#ifdef LTC_RC6
+int rc6_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
+int rc6_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey);
+int rc6_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey);
+int rc6_test(void);
+void rc6_done(symmetric_key *skey);
+int rc6_keysize(int *keysize);
+extern const struct ltc_cipher_descriptor rc6_desc;
+#endif
+
+#ifdef LTC_RC2
+int rc2_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
+int rc2_setup_ex(const unsigned char *key, int keylen, int bits, int num_rounds, symmetric_key *skey);
+int rc2_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey);
+int rc2_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey);
+int rc2_test(void);
+void rc2_done(symmetric_key *skey);
+int rc2_keysize(int *keysize);
+extern const struct ltc_cipher_descriptor rc2_desc;
+#endif
+
+#ifdef LTC_SAFERP
+int saferp_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
+int saferp_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey);
+int saferp_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey);
+int saferp_test(void);
+void saferp_done(symmetric_key *skey);
+int saferp_keysize(int *keysize);
+extern const struct ltc_cipher_descriptor saferp_desc;
+#endif
+
+#ifdef LTC_SAFER
+int safer_k64_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
+int safer_sk64_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
+int safer_k128_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
+int safer_sk128_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
+int safer_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *key);
+int safer_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *key);
+int safer_k64_test(void);
+int safer_sk64_test(void);
+int safer_sk128_test(void);
+void safer_done(symmetric_key *skey);
+int safer_64_keysize(int *keysize);
+int safer_128_keysize(int *keysize);
+extern const struct ltc_cipher_descriptor safer_k64_desc, safer_k128_desc, safer_sk64_desc, safer_sk128_desc;
+#endif
+
+#ifdef LTC_RIJNDAEL
+
+/* make aes an alias */
+#define aes_setup           rijndael_setup
+#define aes_ecb_encrypt     rijndael_ecb_encrypt
+#define aes_ecb_decrypt     rijndael_ecb_decrypt
+#define aes_test            rijndael_test
+#define aes_done            rijndael_done
+#define aes_keysize         rijndael_keysize
+
+#define aes_enc_setup           rijndael_enc_setup
+#define aes_enc_ecb_encrypt     rijndael_enc_ecb_encrypt
+#define aes_enc_keysize         rijndael_enc_keysize
+
+int rijndael_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
+int rijndael_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey);
+int rijndael_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey);
+int rijndael_test(void);
+void rijndael_done(symmetric_key *skey);
+int rijndael_keysize(int *keysize);
+int rijndael_enc_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
+int rijndael_enc_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey);
+void rijndael_enc_done(symmetric_key *skey);
+int rijndael_enc_keysize(int *keysize);
+extern const struct ltc_cipher_descriptor rijndael_desc, aes_desc;
+extern const struct ltc_cipher_descriptor rijndael_enc_desc, aes_enc_desc;
+#endif
+
+#ifdef LTC_XTEA
+int xtea_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
+int xtea_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey);
+int xtea_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey);
+int xtea_test(void);
+void xtea_done(symmetric_key *skey);
+int xtea_keysize(int *keysize);
+extern const struct ltc_cipher_descriptor xtea_desc;
+#endif
+
+#ifdef LTC_TWOFISH
+int twofish_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
+int twofish_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey);
+int twofish_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey);
+int twofish_test(void);
+void twofish_done(symmetric_key *skey);
+int twofish_keysize(int *keysize);
+extern const struct ltc_cipher_descriptor twofish_desc;
+#endif
+
+#ifdef LTC_DES
+int des_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
+int des_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey);
+int des_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey);
+int des_test(void);
+void des_done(symmetric_key *skey);
+int des_keysize(int *keysize);
+int des3_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
+int des3_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey);
+int des3_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey);
+int des3_test(void);
+void des3_done(symmetric_key *skey);
+int des3_keysize(int *keysize);
+extern const struct ltc_cipher_descriptor des_desc, des3_desc;
+#endif
+
+#ifdef LTC_CAST5
+int cast5_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
+int cast5_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey);
+int cast5_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey);
+int cast5_test(void);
+void cast5_done(symmetric_key *skey);
+int cast5_keysize(int *keysize);
+extern const struct ltc_cipher_descriptor cast5_desc;
+#endif
+
+#ifdef LTC_NOEKEON
+int noekeon_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
+int noekeon_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey);
+int noekeon_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey);
+int noekeon_test(void);
+void noekeon_done(symmetric_key *skey);
+int noekeon_keysize(int *keysize);
+extern const struct ltc_cipher_descriptor noekeon_desc;
+#endif
+
+#ifdef LTC_SKIPJACK
+int skipjack_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
+int skipjack_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey);
+int skipjack_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey);
+int skipjack_test(void);
+void skipjack_done(symmetric_key *skey);
+int skipjack_keysize(int *keysize);
+extern const struct ltc_cipher_descriptor skipjack_desc;
+#endif
+
+#ifdef LTC_KHAZAD
+int khazad_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
+int khazad_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey);
+int khazad_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey);
+int khazad_test(void);
+void khazad_done(symmetric_key *skey);
+int khazad_keysize(int *keysize);
+extern const struct ltc_cipher_descriptor khazad_desc;
+#endif
+
+#ifdef LTC_ANUBIS
+int anubis_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
+int anubis_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey);
+int anubis_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey);
+int anubis_test(void);
+void anubis_done(symmetric_key *skey);
+int anubis_keysize(int *keysize);
+extern const struct ltc_cipher_descriptor anubis_desc;
+#endif
+
+#ifdef LTC_KSEED
+int kseed_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
+int kseed_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey);
+int kseed_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey);
+int kseed_test(void);
+void kseed_done(symmetric_key *skey);
+int kseed_keysize(int *keysize);
+extern const struct ltc_cipher_descriptor kseed_desc;
+#endif
+
+#ifdef LTC_KASUMI
+int kasumi_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
+int kasumi_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey);
+int kasumi_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey);
+int kasumi_test(void);
+void kasumi_done(symmetric_key *skey);
+int kasumi_keysize(int *keysize);
+extern const struct ltc_cipher_descriptor kasumi_desc;
+#endif
+
+
+#ifdef LTC_MULTI2
+int multi2_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
+int multi2_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey);
+int multi2_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey);
+int multi2_test(void);
+void multi2_done(symmetric_key *skey);
+int multi2_keysize(int *keysize);
+extern const struct ltc_cipher_descriptor multi2_desc;
+#endif
+
+#ifdef LTC_CAMELLIA
+int camellia_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey);
+int camellia_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey);
+int camellia_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey);
+int camellia_test(void);
+void camellia_done(symmetric_key *skey);
+int camellia_keysize(int *keysize);
+extern const struct ltc_cipher_descriptor camellia_desc;
+#endif
+
+#ifdef LTC_ECB_MODE
+int ecb_start(int cipher, const unsigned char *key,
+              int keylen, int num_rounds, symmetric_ECB *ecb);
+int ecb_encrypt(const unsigned char *pt, unsigned char *ct, unsigned long len, symmetric_ECB *ecb);
+int ecb_decrypt(const unsigned char *ct, unsigned char *pt, unsigned long len, symmetric_ECB *ecb);
+int ecb_done(symmetric_ECB *ecb);
+#endif
+
+#ifdef LTC_CFB_MODE
+int cfb_start(int cipher, const unsigned char *IV, const unsigned char *key,
+              int keylen, int num_rounds, symmetric_CFB *cfb);
+int cfb_encrypt(const unsigned char *pt, unsigned char *ct, unsigned long len, symmetric_CFB *cfb);
+int cfb_decrypt(const unsigned char *ct, unsigned char *pt, unsigned long len, symmetric_CFB *cfb);
+int cfb_getiv(unsigned char *IV, unsigned long *len, symmetric_CFB *cfb);
+int cfb_setiv(const unsigned char *IV, unsigned long len, symmetric_CFB *cfb);
+int cfb_done(symmetric_CFB *cfb);
+#endif
+
+#ifdef LTC_OFB_MODE
+int ofb_start(int cipher, const unsigned char *IV, const unsigned char *key,
+              int keylen, int num_rounds, symmetric_OFB *ofb);
+int ofb_encrypt(const unsigned char *pt, unsigned char *ct, unsigned long len, symmetric_OFB *ofb);
+int ofb_decrypt(const unsigned char *ct, unsigned char *pt, unsigned long len, symmetric_OFB *ofb);
+int ofb_getiv(unsigned char *IV, unsigned long *len, symmetric_OFB *ofb);
+int ofb_setiv(const unsigned char *IV, unsigned long len, symmetric_OFB *ofb);
+int ofb_done(symmetric_OFB *ofb);
+#endif
+
+#ifdef LTC_CBC_MODE
+int cbc_start(int cipher, const unsigned char *IV, const unsigned char *key,
+               int keylen, int num_rounds, symmetric_CBC *cbc);
+int cbc_encrypt(const unsigned char *pt, unsigned char *ct, unsigned long len, symmetric_CBC *cbc);
+int cbc_decrypt(const unsigned char *ct, unsigned char *pt, unsigned long len, symmetric_CBC *cbc);
+int cbc_getiv(unsigned char *IV, unsigned long *len, symmetric_CBC *cbc);
+int cbc_setiv(const unsigned char *IV, unsigned long len, symmetric_CBC *cbc);
+int cbc_done(symmetric_CBC *cbc);
+#endif
+
+#ifdef LTC_CTR_MODE
+
+#define CTR_COUNTER_LITTLE_ENDIAN    0x0000
+#define CTR_COUNTER_BIG_ENDIAN       0x1000
+#define LTC_CTR_RFC3686              0x2000
+
+int ctr_start(               int   cipher,
+              const unsigned char *IV,
+              const unsigned char *key,       int keylen,
+                             int  num_rounds, int ctr_mode,
+                   symmetric_CTR *ctr);
+int ctr_encrypt(const unsigned char *pt, unsigned char *ct, unsigned long len, symmetric_CTR *ctr);
+int ctr_decrypt(const unsigned char *ct, unsigned char *pt, unsigned long len, symmetric_CTR *ctr);
+int ctr_getiv(unsigned char *IV, unsigned long *len, symmetric_CTR *ctr);
+int ctr_setiv(const unsigned char *IV, unsigned long len, symmetric_CTR *ctr);
+int ctr_done(symmetric_CTR *ctr);
+int ctr_test(void);
+#endif
+
+#ifdef LTC_LRW_MODE
+
+#define LRW_ENCRYPT LTC_ENCRYPT
+#define LRW_DECRYPT LTC_DECRYPT
+
+int lrw_start(               int   cipher,
+              const unsigned char *IV,
+              const unsigned char *key,       int keylen,
+              const unsigned char *tweak,
+                             int  num_rounds,
+                   symmetric_LRW *lrw);
+int lrw_encrypt(const unsigned char *pt, unsigned char *ct, unsigned long len, symmetric_LRW *lrw);
+int lrw_decrypt(const unsigned char *ct, unsigned char *pt, unsigned long len, symmetric_LRW *lrw);
+int lrw_getiv(unsigned char *IV, unsigned long *len, symmetric_LRW *lrw);
+int lrw_setiv(const unsigned char *IV, unsigned long len, symmetric_LRW *lrw);
+int lrw_done(symmetric_LRW *lrw);
+int lrw_test(void);
+
+/* don't call */
+int lrw_process(const unsigned char *pt, unsigned char *ct, unsigned long len, int mode, symmetric_LRW *lrw);
+#endif
+
+#ifdef LTC_F8_MODE
+int f8_start(                int  cipher, const unsigned char *IV,
+             const unsigned char *key,                    int  keylen,
+             const unsigned char *salt_key,               int  skeylen,
+                             int  num_rounds,   symmetric_F8  *f8);
+int f8_encrypt(const unsigned char *pt, unsigned char *ct, unsigned long len, symmetric_F8 *f8);
+int f8_decrypt(const unsigned char *ct, unsigned char *pt, unsigned long len, symmetric_F8 *f8);
+int f8_getiv(unsigned char *IV, unsigned long *len, symmetric_F8 *f8);
+int f8_setiv(const unsigned char *IV, unsigned long len, symmetric_F8 *f8);
+int f8_done(symmetric_F8 *f8);
+int f8_test_mode(void);
+#endif
+
+#ifdef LTC_XTS_MODE
+typedef struct {
+   symmetric_key  key1, key2;
+   int            cipher;
+} symmetric_xts;
+
+int xts_start(                int  cipher,
+              const unsigned char *key1,
+              const unsigned char *key2,
+                    unsigned long  keylen,
+                              int  num_rounds,
+                    symmetric_xts *xts);
+
+int xts_encrypt(
+   const unsigned char *pt, unsigned long ptlen,
+         unsigned char *ct,
+         unsigned char *tweak,
+         symmetric_xts *xts);
+int xts_decrypt(
+   const unsigned char *ct, unsigned long ptlen,
+         unsigned char *pt,
+         unsigned char *tweak,
+         symmetric_xts *xts);
+
+void xts_done(symmetric_xts *xts);
+int  xts_test(void);
+void xts_mult_x(unsigned char *I);
+#endif
+
+int find_cipher(const char *name);
+int find_cipher_any(const char *name, int blocklen, int keylen);
+int find_cipher_id(unsigned char ID);
+int register_cipher(const struct ltc_cipher_descriptor *cipher);
+int unregister_cipher(const struct ltc_cipher_descriptor *cipher);
+int register_all_ciphers(void);
+int cipher_is_valid(int idx);
+
+LTC_MUTEX_PROTO(ltc_cipher_mutex)
+
+/* ---- stream ciphers ---- */
+
+#ifdef LTC_CHACHA
+
+typedef struct {
+   ulong32 input[16];
+   unsigned char kstream[64];
+   unsigned long ksleft;
+   unsigned long ivlen;
+   int rounds;
+} chacha_state;
+
+int chacha_setup(chacha_state *st, const unsigned char *key, unsigned long keylen, int rounds);
+int chacha_ivctr32(chacha_state *st, const unsigned char *iv, unsigned long ivlen, ulong32 counter);
+int chacha_ivctr64(chacha_state *st, const unsigned char *iv, unsigned long ivlen, ulong64 counter);
+int chacha_crypt(chacha_state *st, const unsigned char *in, unsigned long inlen, unsigned char *out);
+int chacha_keystream(chacha_state *st, unsigned char *out, unsigned long outlen);
+int chacha_done(chacha_state *st);
+int chacha_test(void);
+
+#endif /* LTC_CHACHA */
+
+#ifdef LTC_RC4_STREAM
+
+typedef struct {
+   unsigned int x, y;
+   unsigned char buf[256];
+} rc4_state;
+
+int rc4_stream_setup(rc4_state *st, const unsigned char *key, unsigned long keylen);
+int rc4_stream_crypt(rc4_state *st, const unsigned char *in, unsigned long inlen, unsigned char *out);
+int rc4_stream_keystream(rc4_state *st, unsigned char *out, unsigned long outlen);
+int rc4_stream_done(rc4_state *st);
+int rc4_stream_test(void);
+
+#endif /* LTC_RC4_STREAM */
+
+#ifdef LTC_SOBER128_STREAM
+
+typedef struct {
+   ulong32 R[17],       /* Working storage for the shift register */
+           initR[17],   /* saved register contents */
+           konst,       /* key dependent constant */
+           sbuf;        /* partial word encryption buffer */
+   int     nbuf;        /* number of part-word stream bits buffered */
+} sober128_state;
+
+int sober128_stream_setup(sober128_state *st, const unsigned char *key, unsigned long keylen);
+int sober128_stream_setiv(sober128_state *st, const unsigned char *iv, unsigned long ivlen);
+int sober128_stream_crypt(sober128_state *st, const unsigned char *in, unsigned long inlen, unsigned char *out);
+int sober128_stream_keystream(sober128_state *st, unsigned char *out, unsigned long outlen);
+int sober128_stream_done(sober128_state *st);
+int sober128_stream_test(void);
+
+#endif /* LTC_SOBER128_STREAM */
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/headers/tomcrypt_custom.h b/libtomcrypt/src/headers/tomcrypt_custom.h
new file mode 100644 (file)
index 0000000..2d5cfec
--- /dev/null
@@ -0,0 +1,590 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+#ifndef TOMCRYPT_CUSTOM_H_
+#define TOMCRYPT_CUSTOM_H_
+
+/* macros for various libc functions you can change for embedded targets */
+#ifndef XMALLOC
+#define XMALLOC  malloc
+#endif
+#ifndef XREALLOC
+#define XREALLOC realloc
+#endif
+#ifndef XCALLOC
+#define XCALLOC  calloc
+#endif
+#ifndef XFREE
+#define XFREE    free
+#endif
+
+#ifndef XMEMSET
+#define XMEMSET  memset
+#endif
+#ifndef XMEMCPY
+#define XMEMCPY  memcpy
+#endif
+#ifndef XMEMMOVE
+#define XMEMMOVE memmove
+#endif
+#ifndef XMEMCMP
+#define XMEMCMP  memcmp
+#endif
+/* A memory compare function that has to run in constant time,
+ * c.f. mem_neq() API summary.
+ */
+#ifndef XMEM_NEQ
+#define XMEM_NEQ  mem_neq
+#endif
+#ifndef XSTRCMP
+#define XSTRCMP strcmp
+#endif
+
+#ifndef XCLOCK
+#define XCLOCK   clock
+#endif
+
+#ifndef XQSORT
+#define XQSORT qsort
+#endif
+
+#if ( defined(malloc) || defined(realloc) || defined(calloc) || defined(free) || \
+      defined(memset) || defined(memcpy) || defined(memcmp) || defined(strcmp) || \
+      defined(clock) || defined(qsort) ) && !defined(LTC_NO_PROTOTYPES)
+#define LTC_NO_PROTOTYPES
+#endif
+
+/* shortcut to disable automatic inclusion */
+#if defined LTC_NOTHING && !defined LTC_EASY
+  #define LTC_NO_CIPHERS
+  #define LTC_NO_MODES
+  #define LTC_NO_HASHES
+  #define LTC_NO_MACS
+  #define LTC_NO_PRNGS
+  #define LTC_NO_PK
+  #define LTC_NO_PKCS
+  #define LTC_NO_MISC
+#endif /* LTC_NOTHING */
+
+/* Easy button? */
+#ifdef LTC_EASY
+   #define LTC_NO_CIPHERS
+   #define LTC_RIJNDAEL
+   #define LTC_BLOWFISH
+   #define LTC_DES
+   #define LTC_CAST5
+
+   #define LTC_NO_MODES
+   #define LTC_ECB_MODE
+   #define LTC_CBC_MODE
+   #define LTC_CTR_MODE
+
+   #define LTC_NO_HASHES
+   #define LTC_SHA1
+   #define LTC_SHA3
+   #define LTC_SHA512
+   #define LTC_SHA384
+   #define LTC_SHA256
+   #define LTC_SHA224
+   #define LTC_HASH_HELPERS
+
+   #define LTC_NO_MACS
+   #define LTC_HMAC
+   #define LTC_OMAC
+   #define LTC_CCM_MODE
+
+   #define LTC_NO_PRNGS
+   #define LTC_SPRNG
+   #define LTC_YARROW
+   #define LTC_DEVRANDOM
+   #define LTC_TRY_URANDOM_FIRST
+   #define LTC_RNG_GET_BYTES
+   #define LTC_RNG_MAKE_PRNG
+
+   #define LTC_NO_PK
+   #define LTC_MRSA
+   #define LTC_MECC
+
+   #define LTC_NO_MISC
+   #define LTC_BASE64
+#endif
+
+/* The minimal set of functionality to run the tests */
+#ifdef LTC_MINIMAL
+   #define LTC_RIJNDAEL
+   #define LTC_SHA256
+   #define LTC_YARROW
+   #define LTC_CTR_MODE
+
+   #define LTC_RNG_MAKE_PRNG
+   #define LTC_RNG_GET_BYTES
+   #define LTC_DEVRANDOM
+   #define LTC_TRY_URANDOM_FIRST
+
+   #undef LTC_NO_FILE
+#endif
+
+/* Enable self-test test vector checking */
+#ifndef LTC_NO_TEST
+   #define LTC_TEST
+#endif
+/* Enable extended self-tests */
+/* #define LTC_TEST_EXT */
+
+/* Use small code where possible */
+/* #define LTC_SMALL_CODE */
+
+/* clean the stack of functions which put private information on stack */
+/* #define LTC_CLEAN_STACK */
+
+/* disable all file related functions */
+/* #define LTC_NO_FILE */
+
+/* disable all forms of ASM */
+/* #define LTC_NO_ASM */
+
+/* disable FAST mode */
+/* #define LTC_NO_FAST */
+
+/* disable BSWAP on x86 */
+/* #define LTC_NO_BSWAP */
+
+/* ---> math provider? <--- */
+#ifndef LTC_NO_MATH
+
+/* LibTomMath */
+/* #define LTM_DESC */
+
+/* TomsFastMath */
+/* #define TFM_DESC */
+
+/* GNU Multiple Precision Arithmetic Library */
+/* #define GMP_DESC */
+
+#endif /* LTC_NO_MATH */
+
+/* ---> Symmetric Block Ciphers <--- */
+#ifndef LTC_NO_CIPHERS
+
+#define LTC_BLOWFISH
+#define LTC_RC2
+#define LTC_RC5
+#define LTC_RC6
+#define LTC_SAFERP
+#define LTC_RIJNDAEL
+#define LTC_XTEA
+/* _TABLES tells it to use tables during setup, _SMALL means to use the smaller scheduled key format
+ * (saves 4KB of ram), _ALL_TABLES enables all tables during setup */
+#define LTC_TWOFISH
+#ifndef LTC_NO_TABLES
+   #define LTC_TWOFISH_TABLES
+   /* #define LTC_TWOFISH_ALL_TABLES */
+#else
+   #define LTC_TWOFISH_SMALL
+#endif
+/* #define LTC_TWOFISH_SMALL */
+/* LTC_DES includes EDE triple-DES */
+#define LTC_DES
+#define LTC_CAST5
+#define LTC_NOEKEON
+#define LTC_SKIPJACK
+#define LTC_SAFER
+#define LTC_KHAZAD
+#define LTC_ANUBIS
+#define LTC_ANUBIS_TWEAK
+#define LTC_KSEED
+#define LTC_KASUMI
+#define LTC_MULTI2
+#define LTC_CAMELLIA
+
+/* stream ciphers */
+#define LTC_CHACHA
+#define LTC_RC4_STREAM
+#define LTC_SOBER128_STREAM
+
+#endif /* LTC_NO_CIPHERS */
+
+
+/* ---> Block Cipher Modes of Operation <--- */
+#ifndef LTC_NO_MODES
+
+#define LTC_CFB_MODE
+#define LTC_OFB_MODE
+#define LTC_ECB_MODE
+#define LTC_CBC_MODE
+#define LTC_CTR_MODE
+
+/* F8 chaining mode */
+#define LTC_F8_MODE
+
+/* LRW mode */
+#define LTC_LRW_MODE
+#ifndef LTC_NO_TABLES
+   /* like GCM mode this will enable 16 8x128 tables [64KB] that make
+    * seeking very fast.
+    */
+   #define LTC_LRW_TABLES
+#endif
+
+/* XTS mode */
+#define LTC_XTS_MODE
+
+#endif /* LTC_NO_MODES */
+
+/* ---> One-Way Hash Functions <--- */
+#ifndef LTC_NO_HASHES
+
+#define LTC_CHC_HASH
+#define LTC_WHIRLPOOL
+#define LTC_SHA3
+#define LTC_SHA512
+#define LTC_SHA512_256
+#define LTC_SHA512_224
+#define LTC_SHA384
+#define LTC_SHA256
+#define LTC_SHA224
+#define LTC_TIGER
+#define LTC_SHA1
+#define LTC_MD5
+#define LTC_MD4
+#define LTC_MD2
+#define LTC_RIPEMD128
+#define LTC_RIPEMD160
+#define LTC_RIPEMD256
+#define LTC_RIPEMD320
+#define LTC_BLAKE2S
+#define LTC_BLAKE2B
+
+#define LTC_HASH_HELPERS
+
+#endif /* LTC_NO_HASHES */
+
+
+/* ---> MAC functions <--- */
+#ifndef LTC_NO_MACS
+
+#define LTC_HMAC
+#define LTC_OMAC
+#define LTC_PMAC
+#define LTC_XCBC
+#define LTC_F9_MODE
+#define LTC_PELICAN
+#define LTC_POLY1305
+#define LTC_BLAKE2SMAC
+#define LTC_BLAKE2BMAC
+
+/* ---> Encrypt + Authenticate Modes <--- */
+
+#define LTC_EAX_MODE
+
+#define LTC_OCB_MODE
+#define LTC_OCB3_MODE
+#define LTC_CCM_MODE
+#define LTC_GCM_MODE
+#define LTC_CHACHA20POLY1305_MODE
+
+/* Use 64KiB tables */
+#ifndef LTC_NO_TABLES
+   #define LTC_GCM_TABLES
+#endif
+
+/* USE SSE2? requires GCC works on x86_32 and x86_64*/
+#ifdef LTC_GCM_TABLES
+/* #define LTC_GCM_TABLES_SSE2 */
+#endif
+
+#endif /* LTC_NO_MACS */
+
+
+/* --> Pseudo Random Number Generators <--- */
+#ifndef LTC_NO_PRNGS
+
+/* Yarrow */
+#define LTC_YARROW
+
+/* a PRNG that simply reads from an available system source */
+#define LTC_SPRNG
+
+/* The RC4 stream cipher based PRNG */
+#define LTC_RC4
+
+/* The ChaCha20 stream cipher based PRNG */
+#define LTC_CHACHA20_PRNG
+
+/* Fortuna PRNG */
+#define LTC_FORTUNA
+
+/* Greg's SOBER128 stream cipher based PRNG */
+#define LTC_SOBER128
+
+/* the *nix style /dev/random device */
+#define LTC_DEVRANDOM
+/* try /dev/urandom before trying /dev/random
+ * are you sure you want to disable this? http://www.2uo.de/myths-about-urandom/ */
+#define LTC_TRY_URANDOM_FIRST
+/* rng_get_bytes() */
+#define LTC_RNG_GET_BYTES
+/* rng_make_prng() */
+#define LTC_RNG_MAKE_PRNG
+
+/* enable the ltc_rng hook to integrate e.g. embedded hardware RNG's easily */
+/* #define LTC_PRNG_ENABLE_LTC_RNG */
+
+#endif /* LTC_NO_PRNGS */
+
+#ifdef LTC_YARROW
+
+/* which descriptor of AES to use?  */
+/* 0 = rijndael_enc 1 = aes_enc, 2 = rijndael [full], 3 = aes [full] */
+#ifdef ENCRYPT_ONLY
+  #define LTC_YARROW_AES 0
+#else
+  #define LTC_YARROW_AES 2
+#endif
+
+#endif
+
+#ifdef LTC_FORTUNA
+
+#ifndef LTC_FORTUNA_WD
+/* reseed every N calls to the read function */
+#define LTC_FORTUNA_WD    10
+#endif
+
+#ifndef LTC_FORTUNA_POOLS
+/* number of pools (4..32) can save a bit of ram by lowering the count */
+#define LTC_FORTUNA_POOLS 32
+#endif
+
+#endif /* LTC_FORTUNA */
+
+
+/* ---> Public Key Crypto <--- */
+#ifndef LTC_NO_PK
+
+/* Include RSA support */
+#define LTC_MRSA
+
+/* Include Diffie-Hellman support */
+/* is_prime fails for GMP */
+#define LTC_MDH
+/* Supported Key Sizes */
+#define LTC_DH768
+#define LTC_DH1024
+#define LTC_DH1536
+#define LTC_DH2048
+
+#ifndef TFM_DESC
+/* tfm has a problem in fp_isprime for larger key sizes */
+#define LTC_DH3072
+#define LTC_DH4096
+#define LTC_DH6144
+#define LTC_DH8192
+#endif
+
+/* Include Katja (a Rabin variant like RSA) */
+/* #define LTC_MKAT */
+
+/* Digital Signature Algorithm */
+#define LTC_MDSA
+
+/* ECC */
+#define LTC_MECC
+
+/* use Shamir's trick for point mul (speeds up signature verification) */
+#define LTC_ECC_SHAMIR
+
+#if defined(TFM_DESC) && defined(LTC_MECC)
+   #define LTC_MECC_ACCEL
+#endif
+
+/* do we want fixed point ECC */
+/* #define LTC_MECC_FP */
+
+#endif /* LTC_NO_PK */
+
+#if defined(LTC_MRSA) && !defined(LTC_NO_RSA_BLINDING)
+/* Enable RSA blinding when doing private key operations by default */
+#define LTC_RSA_BLINDING
+#endif  /* LTC_NO_RSA_BLINDING */
+
+#if defined(LTC_MRSA) && !defined(LTC_NO_RSA_CRT_HARDENING)
+/* Enable RSA CRT hardening when doing private key operations by default */
+#define LTC_RSA_CRT_HARDENING
+#endif  /* LTC_NO_RSA_CRT_HARDENING */
+
+#if defined(LTC_MECC) && !defined(LTC_NO_ECC_TIMING_RESISTANT)
+/* Enable ECC timing resistant version by default */
+#define LTC_ECC_TIMING_RESISTANT
+#endif
+
+/* PKCS #1 (RSA) and #5 (Password Handling) stuff */
+#ifndef LTC_NO_PKCS
+
+#define LTC_PKCS_1
+#define LTC_PKCS_5
+
+/* Include ASN.1 DER (required by DSA/RSA) */
+#define LTC_DER
+
+#endif /* LTC_NO_PKCS */
+
+/* misc stuff */
+#ifndef LTC_NO_MISC
+
+/* Various tidbits of modern neatoness */
+#define LTC_BASE64
+/* ... and it's URL safe version */
+#define LTC_BASE64_URL
+
+/* Keep LTC_NO_HKDF for compatibility reasons
+ * superseeded by LTC_NO_MISC*/
+#ifndef LTC_NO_HKDF
+/* HKDF Key Derivation/Expansion stuff */
+#define LTC_HKDF
+#endif /* LTC_NO_HKDF */
+
+#define LTC_ADLER32
+
+#define LTC_CRC32
+
+#endif /* LTC_NO_MISC */
+
+/* cleanup */
+
+#ifdef LTC_MECC
+/* Supported ECC Key Sizes */
+#ifndef LTC_NO_CURVES
+   #define LTC_ECC112
+   #define LTC_ECC128
+   #define LTC_ECC160
+   #define LTC_ECC192
+   #define LTC_ECC224
+   #define LTC_ECC256
+   #define LTC_ECC384
+   #define LTC_ECC521
+#endif
+#endif
+
+#if defined(LTC_DER)
+   #ifndef LTC_DER_MAX_RECURSION
+      /* Maximum recursion limit when processing nested ASN.1 types. */
+      #define LTC_DER_MAX_RECURSION 30
+   #endif
+#endif
+
+#if defined(LTC_MECC) || defined(LTC_MRSA) || defined(LTC_MDSA) || defined(LTC_MKAT)
+   /* Include the MPI functionality?  (required by the PK algorithms) */
+   #define LTC_MPI
+
+   #ifndef LTC_PK_MAX_RETRIES
+      /* iterations limit for retry-loops */
+      #define LTC_PK_MAX_RETRIES  20
+   #endif
+#endif
+
+#ifdef LTC_MRSA
+   #define LTC_PKCS_1
+#endif
+
+#if defined(LTC_PELICAN) && !defined(LTC_RIJNDAEL)
+   #error Pelican-MAC requires LTC_RIJNDAEL
+#endif
+
+#if defined(LTC_EAX_MODE) && !(defined(LTC_CTR_MODE) && defined(LTC_OMAC))
+   #error LTC_EAX_MODE requires CTR and LTC_OMAC mode
+#endif
+
+#if defined(LTC_YARROW) && !defined(LTC_CTR_MODE)
+   #error LTC_YARROW requires LTC_CTR_MODE chaining mode to be defined!
+#endif
+
+#if defined(LTC_DER) && !defined(LTC_MPI)
+   #error ASN.1 DER requires MPI functionality
+#endif
+
+#if (defined(LTC_MDSA) || defined(LTC_MRSA) || defined(LTC_MECC) || defined(LTC_MKAT)) && !defined(LTC_DER)
+   #error PK requires ASN.1 DER functionality, make sure LTC_DER is enabled
+#endif
+
+#if defined(LTC_CHACHA20POLY1305_MODE) && (!defined(LTC_CHACHA) || !defined(LTC_POLY1305))
+   #error LTC_CHACHA20POLY1305_MODE requires LTC_CHACHA + LTC_POLY1305
+#endif
+
+#if defined(LTC_CHACHA20_PRNG) && !defined(LTC_CHACHA)
+   #error LTC_CHACHA20_PRNG requires LTC_CHACHA
+#endif
+
+#if defined(LTC_RC4) && !defined(LTC_RC4_STREAM)
+   #error LTC_RC4 requires LTC_RC4_STREAM
+#endif
+
+#if defined(LTC_SOBER128) && !defined(LTC_SOBER128_STREAM)
+   #error LTC_SOBER128 requires LTC_SOBER128_STREAM
+#endif
+
+#if defined(LTC_BLAKE2SMAC) && !defined(LTC_BLAKE2S)
+   #error LTC_BLAKE2SMAC requires LTC_BLAKE2S
+#endif
+
+#if defined(LTC_BLAKE2BMAC) && !defined(LTC_BLAKE2B)
+   #error LTC_BLAKE2BMAC requires LTC_BLAKE2B
+#endif
+
+#if defined(LTC_SPRNG) && !defined(LTC_RNG_GET_BYTES)
+   #error LTC_SPRNG requires LTC_RNG_GET_BYTES
+#endif
+
+#if defined(LTC_NO_MATH) && (defined(LTM_DESC) || defined(TFM_DESC) || defined(GMP_DESC))
+   #error LTC_NO_MATH defined, but also a math descriptor
+#endif
+
+/* THREAD management */
+#ifdef LTC_PTHREAD
+
+#include <pthread.h>
+
+#define LTC_MUTEX_GLOBAL(x)   pthread_mutex_t x = PTHREAD_MUTEX_INITIALIZER;
+#define LTC_MUTEX_PROTO(x)    extern pthread_mutex_t x;
+#define LTC_MUTEX_TYPE(x)     pthread_mutex_t x;
+#define LTC_MUTEX_INIT(x)     LTC_ARGCHK(pthread_mutex_init(x, NULL) == 0);
+#define LTC_MUTEX_LOCK(x)     LTC_ARGCHK(pthread_mutex_lock(x) == 0);
+#define LTC_MUTEX_UNLOCK(x)   LTC_ARGCHK(pthread_mutex_unlock(x) == 0);
+#define LTC_MUTEX_DESTROY(x)  LTC_ARGCHK(pthread_mutex_destroy(x) == 0);
+
+#else
+
+/* default no functions */
+#define LTC_MUTEX_GLOBAL(x)
+#define LTC_MUTEX_PROTO(x)
+#define LTC_MUTEX_TYPE(x)
+#define LTC_MUTEX_INIT(x)
+#define LTC_MUTEX_LOCK(x)
+#define LTC_MUTEX_UNLOCK(x)
+#define LTC_MUTEX_DESTROY(x)
+
+#endif
+
+/* Debuggers */
+
+/* define this if you use Valgrind, note: it CHANGES the way SOBER-128 and RC4 work (see the code) */
+/* #define LTC_VALGRIND */
+
+#endif
+
+#ifndef LTC_NO_FILE
+   /* buffer size for reading from a file via fread(..) */
+   #ifndef LTC_FILE_READ_BUFSIZE
+   #define LTC_FILE_READ_BUFSIZE 8192
+   #endif
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/headers/tomcrypt_hash.h b/libtomcrypt/src/headers/tomcrypt_hash.h
new file mode 100644 (file)
index 0000000..ef494f7
--- /dev/null
@@ -0,0 +1,531 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+/* ---- HASH FUNCTIONS ---- */
+#ifdef LTC_SHA3
+struct sha3_state {
+    ulong64 saved;                  /* the portion of the input message that we didn't consume yet */
+    ulong64 s[25];
+    unsigned char sb[25 * 8];       /* used for storing `ulong64 s[25]` as little-endian bytes */
+    unsigned short byte_index;      /* 0..7--the next byte after the set one (starts from 0; 0--none are buffered) */
+    unsigned short word_index;      /* 0..24--the next word to integrate input (starts from 0) */
+    unsigned short capacity_words;  /* the double size of the hash output in words (e.g. 16 for Keccak 512) */
+    unsigned short xof_flag;
+};
+#endif
+
+#ifdef LTC_SHA512
+struct sha512_state {
+    ulong64  length, state[8];
+    unsigned long curlen;
+    unsigned char buf[128];
+};
+#endif
+
+#ifdef LTC_SHA256
+struct sha256_state {
+    ulong64 length;
+    ulong32 state[8], curlen;
+    unsigned char buf[64];
+};
+#endif
+
+#ifdef LTC_SHA1
+struct sha1_state {
+    ulong64 length;
+    ulong32 state[5], curlen;
+    unsigned char buf[64];
+};
+#endif
+
+#ifdef LTC_MD5
+struct md5_state {
+    ulong64 length;
+    ulong32 state[4], curlen;
+    unsigned char buf[64];
+};
+#endif
+
+#ifdef LTC_MD4
+struct md4_state {
+    ulong64 length;
+    ulong32 state[4], curlen;
+    unsigned char buf[64];
+};
+#endif
+
+#ifdef LTC_TIGER
+struct tiger_state {
+    ulong64 state[3], length;
+    unsigned long curlen;
+    unsigned char buf[64];
+};
+#endif
+
+#ifdef LTC_MD2
+struct md2_state {
+    unsigned char chksum[16], X[48], buf[16];
+    unsigned long curlen;
+};
+#endif
+
+#ifdef LTC_RIPEMD128
+struct rmd128_state {
+    ulong64 length;
+    unsigned char buf[64];
+    ulong32 curlen, state[4];
+};
+#endif
+
+#ifdef LTC_RIPEMD160
+struct rmd160_state {
+    ulong64 length;
+    unsigned char buf[64];
+    ulong32 curlen, state[5];
+};
+#endif
+
+#ifdef LTC_RIPEMD256
+struct rmd256_state {
+    ulong64 length;
+    unsigned char buf[64];
+    ulong32 curlen, state[8];
+};
+#endif
+
+#ifdef LTC_RIPEMD320
+struct rmd320_state {
+    ulong64 length;
+    unsigned char buf[64];
+    ulong32 curlen, state[10];
+};
+#endif
+
+#ifdef LTC_WHIRLPOOL
+struct whirlpool_state {
+    ulong64 length, state[8];
+    unsigned char buf[64];
+    ulong32 curlen;
+};
+#endif
+
+#ifdef LTC_CHC_HASH
+struct chc_state {
+    ulong64 length;
+    unsigned char state[MAXBLOCKSIZE], buf[MAXBLOCKSIZE];
+    ulong32 curlen;
+};
+#endif
+
+#ifdef LTC_BLAKE2S
+struct blake2s_state {
+    ulong32 h[8];
+    ulong32 t[2];
+    ulong32 f[2];
+    unsigned char buf[64];
+    unsigned long curlen;
+    unsigned long outlen;
+    unsigned char last_node;
+};
+#endif
+
+#ifdef LTC_BLAKE2B
+struct blake2b_state {
+    ulong64 h[8];
+    ulong64 t[2];
+    ulong64 f[2];
+    unsigned char buf[128];
+    unsigned long curlen;
+    unsigned long outlen;
+    unsigned char last_node;
+};
+#endif
+
+typedef union Hash_state {
+    char dummy[1];
+#ifdef LTC_CHC_HASH
+    struct chc_state chc;
+#endif
+#ifdef LTC_WHIRLPOOL
+    struct whirlpool_state whirlpool;
+#endif
+#ifdef LTC_SHA3
+    struct sha3_state sha3;
+#endif
+#ifdef LTC_SHA512
+    struct sha512_state sha512;
+#endif
+#ifdef LTC_SHA256
+    struct sha256_state sha256;
+#endif
+#ifdef LTC_SHA1
+    struct sha1_state   sha1;
+#endif
+#ifdef LTC_MD5
+    struct md5_state    md5;
+#endif
+#ifdef LTC_MD4
+    struct md4_state    md4;
+#endif
+#ifdef LTC_MD2
+    struct md2_state    md2;
+#endif
+#ifdef LTC_TIGER
+    struct tiger_state  tiger;
+#endif
+#ifdef LTC_RIPEMD128
+    struct rmd128_state rmd128;
+#endif
+#ifdef LTC_RIPEMD160
+    struct rmd160_state rmd160;
+#endif
+#ifdef LTC_RIPEMD256
+    struct rmd256_state rmd256;
+#endif
+#ifdef LTC_RIPEMD320
+    struct rmd320_state rmd320;
+#endif
+#ifdef LTC_BLAKE2S
+    struct blake2s_state blake2s;
+#endif
+#ifdef LTC_BLAKE2B
+    struct blake2b_state blake2b;
+#endif
+
+    void *data;
+} hash_state;
+
+/** hash descriptor */
+extern  struct ltc_hash_descriptor {
+    /** name of hash */
+    const char *name;
+    /** internal ID */
+    unsigned char ID;
+    /** Size of digest in octets */
+    unsigned long hashsize;
+    /** Input block size in octets */
+    unsigned long blocksize;
+    /** ASN.1 OID */
+    unsigned long OID[16];
+    /** Length of DER encoding */
+    unsigned long OIDlen;
+
+    /** Init a hash state
+      @param hash   The hash to initialize
+      @return CRYPT_OK if successful
+    */
+    int (*init)(hash_state *hash);
+    /** Process a block of data
+      @param hash   The hash state
+      @param in     The data to hash
+      @param inlen  The length of the data (octets)
+      @return CRYPT_OK if successful
+    */
+    int (*process)(hash_state *hash, const unsigned char *in, unsigned long inlen);
+    /** Produce the digest and store it
+      @param hash   The hash state
+      @param out    [out] The destination of the digest
+      @return CRYPT_OK if successful
+    */
+    int (*done)(hash_state *hash, unsigned char *out);
+    /** Self-test
+      @return CRYPT_OK if successful, CRYPT_NOP if self-tests have been disabled
+    */
+    int (*test)(void);
+
+    /* accelerated hmac callback: if you need to-do multiple packets just use the generic hmac_memory and provide a hash callback */
+    int  (*hmac_block)(const unsigned char *key, unsigned long  keylen,
+                       const unsigned char *in,  unsigned long  inlen,
+                             unsigned char *out, unsigned long *outlen);
+
+} hash_descriptor[];
+
+#ifdef LTC_CHC_HASH
+int chc_register(int cipher);
+int chc_init(hash_state * md);
+int chc_process(hash_state * md, const unsigned char *in, unsigned long inlen);
+int chc_done(hash_state * md, unsigned char *hash);
+int chc_test(void);
+extern const struct ltc_hash_descriptor chc_desc;
+#endif
+
+#ifdef LTC_WHIRLPOOL
+int whirlpool_init(hash_state * md);
+int whirlpool_process(hash_state * md, const unsigned char *in, unsigned long inlen);
+int whirlpool_done(hash_state * md, unsigned char *hash);
+int whirlpool_test(void);
+extern const struct ltc_hash_descriptor whirlpool_desc;
+#endif
+
+#ifdef LTC_SHA3
+int sha3_512_init(hash_state * md);
+int sha3_512_test(void);
+extern const struct ltc_hash_descriptor sha3_512_desc;
+int sha3_384_init(hash_state * md);
+int sha3_384_test(void);
+extern const struct ltc_hash_descriptor sha3_384_desc;
+int sha3_256_init(hash_state * md);
+int sha3_256_test(void);
+extern const struct ltc_hash_descriptor sha3_256_desc;
+int sha3_224_init(hash_state * md);
+int sha3_224_test(void);
+extern const struct ltc_hash_descriptor sha3_224_desc;
+/* process + done are the same for all variants */
+int sha3_process(hash_state * md, const unsigned char *in, unsigned long inlen);
+int sha3_done(hash_state *md, unsigned char *hash);
+/* SHAKE128 + SHAKE256 */
+int sha3_shake_init(hash_state *md, int num);
+#define sha3_shake_process(a,b,c) sha3_process(a,b,c)
+int sha3_shake_done(hash_state *md, unsigned char *out, unsigned long outlen);
+int sha3_shake_test(void);
+int sha3_shake_memory(int num, const unsigned char *in, unsigned long inlen, unsigned char *out, unsigned long *outlen);
+#endif
+
+#ifdef LTC_SHA512
+int sha512_init(hash_state * md);
+int sha512_process(hash_state * md, const unsigned char *in, unsigned long inlen);
+int sha512_done(hash_state * md, unsigned char *hash);
+int sha512_test(void);
+extern const struct ltc_hash_descriptor sha512_desc;
+#endif
+
+#ifdef LTC_SHA384
+#ifndef LTC_SHA512
+   #error LTC_SHA512 is required for LTC_SHA384
+#endif
+int sha384_init(hash_state * md);
+#define sha384_process sha512_process
+int sha384_done(hash_state * md, unsigned char *hash);
+int sha384_test(void);
+extern const struct ltc_hash_descriptor sha384_desc;
+#endif
+
+#ifdef LTC_SHA512_256
+#ifndef LTC_SHA512
+   #error LTC_SHA512 is required for LTC_SHA512_256
+#endif
+int sha512_256_init(hash_state * md);
+#define sha512_256_process sha512_process
+int sha512_256_done(hash_state * md, unsigned char *hash);
+int sha512_256_test(void);
+extern const struct ltc_hash_descriptor sha512_256_desc;
+#endif
+
+#ifdef LTC_SHA512_224
+#ifndef LTC_SHA512
+   #error LTC_SHA512 is required for LTC_SHA512_224
+#endif
+int sha512_224_init(hash_state * md);
+#define sha512_224_process sha512_process
+int sha512_224_done(hash_state * md, unsigned char *hash);
+int sha512_224_test(void);
+extern const struct ltc_hash_descriptor sha512_224_desc;
+#endif
+
+#ifdef LTC_SHA256
+int sha256_init(hash_state * md);
+int sha256_process(hash_state * md, const unsigned char *in, unsigned long inlen);
+int sha256_done(hash_state * md, unsigned char *hash);
+int sha256_test(void);
+extern const struct ltc_hash_descriptor sha256_desc;
+
+#ifdef LTC_SHA224
+#ifndef LTC_SHA256
+   #error LTC_SHA256 is required for LTC_SHA224
+#endif
+int sha224_init(hash_state * md);
+#define sha224_process sha256_process
+int sha224_done(hash_state * md, unsigned char *hash);
+int sha224_test(void);
+extern const struct ltc_hash_descriptor sha224_desc;
+#endif
+#endif
+
+#ifdef LTC_SHA1
+int sha1_init(hash_state * md);
+int sha1_process(hash_state * md, const unsigned char *in, unsigned long inlen);
+int sha1_done(hash_state * md, unsigned char *hash);
+int sha1_test(void);
+extern const struct ltc_hash_descriptor sha1_desc;
+#endif
+
+#ifdef LTC_BLAKE2S
+extern const struct ltc_hash_descriptor blake2s_256_desc;
+int blake2s_256_init(hash_state * md);
+int blake2s_256_test(void);
+
+extern const struct ltc_hash_descriptor blake2s_224_desc;
+int blake2s_224_init(hash_state * md);
+int blake2s_224_test(void);
+
+extern const struct ltc_hash_descriptor blake2s_160_desc;
+int blake2s_160_init(hash_state * md);
+int blake2s_160_test(void);
+
+extern const struct ltc_hash_descriptor blake2s_128_desc;
+int blake2s_128_init(hash_state * md);
+int blake2s_128_test(void);
+
+int blake2s_init(hash_state * md, unsigned long outlen, const unsigned char *key, unsigned long keylen);
+int blake2s_process(hash_state * md, const unsigned char *in, unsigned long inlen);
+int blake2s_done(hash_state * md, unsigned char *hash);
+#endif
+
+#ifdef LTC_BLAKE2B
+extern const struct ltc_hash_descriptor blake2b_512_desc;
+int blake2b_512_init(hash_state * md);
+int blake2b_512_test(void);
+
+extern const struct ltc_hash_descriptor blake2b_384_desc;
+int blake2b_384_init(hash_state * md);
+int blake2b_384_test(void);
+
+extern const struct ltc_hash_descriptor blake2b_256_desc;
+int blake2b_256_init(hash_state * md);
+int blake2b_256_test(void);
+
+extern const struct ltc_hash_descriptor blake2b_160_desc;
+int blake2b_160_init(hash_state * md);
+int blake2b_160_test(void);
+
+int blake2b_init(hash_state * md, unsigned long outlen, const unsigned char *key, unsigned long keylen);
+int blake2b_process(hash_state * md, const unsigned char *in, unsigned long inlen);
+int blake2b_done(hash_state * md, unsigned char *hash);
+#endif
+
+#ifdef LTC_MD5
+int md5_init(hash_state * md);
+int md5_process(hash_state * md, const unsigned char *in, unsigned long inlen);
+int md5_done(hash_state * md, unsigned char *hash);
+int md5_test(void);
+extern const struct ltc_hash_descriptor md5_desc;
+#endif
+
+#ifdef LTC_MD4
+int md4_init(hash_state * md);
+int md4_process(hash_state * md, const unsigned char *in, unsigned long inlen);
+int md4_done(hash_state * md, unsigned char *hash);
+int md4_test(void);
+extern const struct ltc_hash_descriptor md4_desc;
+#endif
+
+#ifdef LTC_MD2
+int md2_init(hash_state * md);
+int md2_process(hash_state * md, const unsigned char *in, unsigned long inlen);
+int md2_done(hash_state * md, unsigned char *hash);
+int md2_test(void);
+extern const struct ltc_hash_descriptor md2_desc;
+#endif
+
+#ifdef LTC_TIGER
+int tiger_init(hash_state * md);
+int tiger_process(hash_state * md, const unsigned char *in, unsigned long inlen);
+int tiger_done(hash_state * md, unsigned char *hash);
+int tiger_test(void);
+extern const struct ltc_hash_descriptor tiger_desc;
+#endif
+
+#ifdef LTC_RIPEMD128
+int rmd128_init(hash_state * md);
+int rmd128_process(hash_state * md, const unsigned char *in, unsigned long inlen);
+int rmd128_done(hash_state * md, unsigned char *hash);
+int rmd128_test(void);
+extern const struct ltc_hash_descriptor rmd128_desc;
+#endif
+
+#ifdef LTC_RIPEMD160
+int rmd160_init(hash_state * md);
+int rmd160_process(hash_state * md, const unsigned char *in, unsigned long inlen);
+int rmd160_done(hash_state * md, unsigned char *hash);
+int rmd160_test(void);
+extern const struct ltc_hash_descriptor rmd160_desc;
+#endif
+
+#ifdef LTC_RIPEMD256
+int rmd256_init(hash_state * md);
+int rmd256_process(hash_state * md, const unsigned char *in, unsigned long inlen);
+int rmd256_done(hash_state * md, unsigned char *hash);
+int rmd256_test(void);
+extern const struct ltc_hash_descriptor rmd256_desc;
+#endif
+
+#ifdef LTC_RIPEMD320
+int rmd320_init(hash_state * md);
+int rmd320_process(hash_state * md, const unsigned char *in, unsigned long inlen);
+int rmd320_done(hash_state * md, unsigned char *hash);
+int rmd320_test(void);
+extern const struct ltc_hash_descriptor rmd320_desc;
+#endif
+
+
+int find_hash(const char *name);
+int find_hash_id(unsigned char ID);
+int find_hash_oid(const unsigned long *ID, unsigned long IDlen);
+int find_hash_any(const char *name, int digestlen);
+int register_hash(const struct ltc_hash_descriptor *hash);
+int unregister_hash(const struct ltc_hash_descriptor *hash);
+int register_all_hashes(void);
+int hash_is_valid(int idx);
+
+LTC_MUTEX_PROTO(ltc_hash_mutex)
+
+int hash_memory(int hash,
+                const unsigned char *in,  unsigned long inlen,
+                      unsigned char *out, unsigned long *outlen);
+int hash_memory_multi(int hash, unsigned char *out, unsigned long *outlen,
+                      const unsigned char *in, unsigned long inlen, ...);
+
+#ifndef LTC_NO_FILE
+int hash_filehandle(int hash, FILE *in, unsigned char *out, unsigned long *outlen);
+int hash_file(int hash, const char *fname, unsigned char *out, unsigned long *outlen);
+#endif
+
+/* a simple macro for making hash "process" functions */
+#define HASH_PROCESS(func_name, compress_name, state_var, block_size)                       \
+int func_name (hash_state * md, const unsigned char *in, unsigned long inlen)               \
+{                                                                                           \
+    unsigned long n;                                                                        \
+    int           err;                                                                      \
+    LTC_ARGCHK(md != NULL);                                                                 \
+    LTC_ARGCHK(in != NULL);                                                                 \
+    if (md-> state_var .curlen > sizeof(md-> state_var .buf)) {                             \
+       return CRYPT_INVALID_ARG;                                                            \
+    }                                                                                       \
+    if ((md-> state_var .length + inlen) < md-> state_var .length) {                        \
+      return CRYPT_HASH_OVERFLOW;                                                           \
+    }                                                                                       \
+    while (inlen > 0) {                                                                     \
+        if (md-> state_var .curlen == 0 && inlen >= block_size) {                           \
+           if ((err = compress_name (md, (unsigned char *)in)) != CRYPT_OK) {               \
+              return err;                                                                   \
+           }                                                                                \
+           md-> state_var .length += block_size * 8;                                        \
+           in             += block_size;                                                    \
+           inlen          -= block_size;                                                    \
+        } else {                                                                            \
+           n = MIN(inlen, (block_size - md-> state_var .curlen));                           \
+           XMEMCPY(md-> state_var .buf + md-> state_var.curlen, in, (size_t)n);             \
+           md-> state_var .curlen += n;                                                     \
+           in             += n;                                                             \
+           inlen          -= n;                                                             \
+           if (md-> state_var .curlen == block_size) {                                      \
+              if ((err = compress_name (md, md-> state_var .buf)) != CRYPT_OK) {            \
+                 return err;                                                                \
+              }                                                                             \
+              md-> state_var .length += 8*block_size;                                       \
+              md-> state_var .curlen = 0;                                                   \
+           }                                                                                \
+       }                                                                                    \
+    }                                                                                       \
+    return CRYPT_OK;                                                                        \
+}
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/headers/tomcrypt_mac.h b/libtomcrypt/src/headers/tomcrypt_mac.h
new file mode 100644 (file)
index 0000000..04f825d
--- /dev/null
@@ -0,0 +1,565 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+#ifdef LTC_HMAC
+typedef struct Hmac_state {
+     hash_state     md;
+     int            hash;
+     hash_state     hashstate;
+     unsigned char  *key;
+} hmac_state;
+
+int hmac_init(hmac_state *hmac, int hash, const unsigned char *key, unsigned long keylen);
+int hmac_process(hmac_state *hmac, const unsigned char *in, unsigned long inlen);
+int hmac_done(hmac_state *hmac, unsigned char *out, unsigned long *outlen);
+int hmac_test(void);
+int hmac_memory(int hash,
+                const unsigned char *key, unsigned long keylen,
+                const unsigned char *in,  unsigned long inlen,
+                      unsigned char *out, unsigned long *outlen);
+int hmac_memory_multi(int hash,
+                const unsigned char *key,  unsigned long keylen,
+                      unsigned char *out,  unsigned long *outlen,
+                const unsigned char *in,   unsigned long inlen, ...);
+int hmac_file(int hash, const char *fname, const unsigned char *key,
+              unsigned long keylen,
+              unsigned char *dst, unsigned long *dstlen);
+#endif
+
+#ifdef LTC_OMAC
+
+typedef struct {
+   int             cipher_idx,
+                   buflen,
+                   blklen;
+   unsigned char   block[MAXBLOCKSIZE],
+                   prev[MAXBLOCKSIZE],
+                   Lu[2][MAXBLOCKSIZE];
+   symmetric_key   key;
+} omac_state;
+
+int omac_init(omac_state *omac, int cipher, const unsigned char *key, unsigned long keylen);
+int omac_process(omac_state *omac, const unsigned char *in, unsigned long inlen);
+int omac_done(omac_state *omac, unsigned char *out, unsigned long *outlen);
+int omac_memory(int cipher,
+               const unsigned char *key, unsigned long keylen,
+               const unsigned char *in,  unsigned long inlen,
+                     unsigned char *out, unsigned long *outlen);
+int omac_memory_multi(int cipher,
+                const unsigned char *key, unsigned long keylen,
+                      unsigned char *out, unsigned long *outlen,
+                const unsigned char *in,  unsigned long inlen, ...);
+int omac_file(int cipher,
+              const unsigned char *key, unsigned long keylen,
+              const          char *filename,
+                    unsigned char *out, unsigned long *outlen);
+int omac_test(void);
+#endif /* LTC_OMAC */
+
+#ifdef LTC_PMAC
+
+typedef struct {
+   unsigned char     Ls[32][MAXBLOCKSIZE],    /* L shifted by i bits to the left */
+                     Li[MAXBLOCKSIZE],        /* value of Li [current value, we calc from previous recall] */
+                     Lr[MAXBLOCKSIZE],        /* L * x^-1 */
+                     block[MAXBLOCKSIZE],     /* currently accumulated block */
+                     checksum[MAXBLOCKSIZE];  /* current checksum */
+
+   symmetric_key     key;                     /* scheduled key for cipher */
+   unsigned long     block_index;             /* index # for current block */
+   int               cipher_idx,              /* cipher idx */
+                     block_len,               /* length of block */
+                     buflen;                  /* number of bytes in the buffer */
+} pmac_state;
+
+int pmac_init(pmac_state *pmac, int cipher, const unsigned char *key, unsigned long keylen);
+int pmac_process(pmac_state *pmac, const unsigned char *in, unsigned long inlen);
+int pmac_done(pmac_state *pmac, unsigned char *out, unsigned long *outlen);
+
+int pmac_memory(int cipher,
+               const unsigned char *key, unsigned long keylen,
+               const unsigned char *msg, unsigned long msglen,
+                     unsigned char *out, unsigned long *outlen);
+
+int pmac_memory_multi(int cipher,
+                const unsigned char *key, unsigned long keylen,
+                      unsigned char *out, unsigned long *outlen,
+                const unsigned char *in, unsigned long inlen, ...);
+
+int pmac_file(int cipher,
+             const unsigned char *key, unsigned long keylen,
+             const          char *filename,
+                   unsigned char *out, unsigned long *outlen);
+
+int pmac_test(void);
+
+/* internal functions */
+int pmac_ntz(unsigned long x);
+void pmac_shift_xor(pmac_state *pmac);
+
+#endif /* PMAC */
+
+#ifdef LTC_POLY1305
+typedef struct {
+   ulong32 r[5];
+   ulong32 h[5];
+   ulong32 pad[4];
+   unsigned long leftover;
+   unsigned char buffer[16];
+   int final;
+} poly1305_state;
+
+int poly1305_init(poly1305_state *st, const unsigned char *key, unsigned long keylen);
+int poly1305_process(poly1305_state *st, const unsigned char *in, unsigned long inlen);
+int poly1305_done(poly1305_state *st, unsigned char *mac, unsigned long *maclen);
+int poly1305_memory(const unsigned char *key, unsigned long keylen, const unsigned char *in, unsigned long inlen, unsigned char *mac, unsigned long *maclen);
+int poly1305_memory_multi(const unsigned char *key, unsigned long keylen, unsigned char *mac, unsigned long *maclen, const unsigned char *in,  unsigned long inlen, ...);
+int poly1305_file(const char *fname, const unsigned char *key, unsigned long keylen, unsigned char *mac, unsigned long *maclen);
+int poly1305_test(void);
+#endif /* LTC_POLY1305 */
+
+#ifdef LTC_BLAKE2SMAC
+typedef hash_state blake2smac_state;
+int blake2smac_init(blake2smac_state *st, unsigned long outlen, const unsigned char *key, unsigned long keylen);
+int blake2smac_process(blake2smac_state *st, const unsigned char *in, unsigned long inlen);
+int blake2smac_done(blake2smac_state *st, unsigned char *mac, unsigned long *maclen);
+int blake2smac_memory(const unsigned char *key, unsigned long keylen, const unsigned char *in, unsigned long inlen, unsigned char *mac, unsigned long *maclen);
+int blake2smac_memory_multi(const unsigned char *key, unsigned long keylen, unsigned char *mac, unsigned long *maclen, const unsigned char *in,  unsigned long inlen, ...);
+int blake2smac_file(const char *fname, const unsigned char *key, unsigned long keylen, unsigned char *mac, unsigned long *maclen);
+int blake2smac_test(void);
+#endif /* LTC_BLAKE2SMAC */
+
+#ifdef LTC_BLAKE2BMAC
+typedef hash_state blake2bmac_state;
+int blake2bmac_init(blake2bmac_state *st, unsigned long outlen, const unsigned char *key, unsigned long keylen);
+int blake2bmac_process(blake2bmac_state *st, const unsigned char *in, unsigned long inlen);
+int blake2bmac_done(blake2bmac_state *st, unsigned char *mac, unsigned long *maclen);
+int blake2bmac_memory(const unsigned char *key, unsigned long keylen, const unsigned char *in, unsigned long inlen, unsigned char *mac, unsigned long *maclen);
+int blake2bmac_memory_multi(const unsigned char *key, unsigned long keylen, unsigned char *mac, unsigned long *maclen, const unsigned char *in,  unsigned long inlen, ...);
+int blake2bmac_file(const char *fname, const unsigned char *key, unsigned long keylen, unsigned char *mac, unsigned long *maclen);
+int blake2bmac_test(void);
+#endif /* LTC_BLAKE2BMAC */
+
+#ifdef LTC_EAX_MODE
+
+#if !(defined(LTC_OMAC) && defined(LTC_CTR_MODE))
+   #error LTC_EAX_MODE requires LTC_OMAC and CTR
+#endif
+
+typedef struct {
+   unsigned char N[MAXBLOCKSIZE];
+   symmetric_CTR ctr;
+   omac_state    headeromac, ctomac;
+} eax_state;
+
+int eax_init(eax_state *eax, int cipher, const unsigned char *key, unsigned long keylen,
+             const unsigned char *nonce, unsigned long noncelen,
+             const unsigned char *header, unsigned long headerlen);
+
+int eax_encrypt(eax_state *eax, const unsigned char *pt, unsigned char *ct, unsigned long length);
+int eax_decrypt(eax_state *eax, const unsigned char *ct, unsigned char *pt, unsigned long length);
+int eax_addheader(eax_state *eax, const unsigned char *header, unsigned long length);
+int eax_done(eax_state *eax, unsigned char *tag, unsigned long *taglen);
+
+int eax_encrypt_authenticate_memory(int cipher,
+    const unsigned char *key,    unsigned long keylen,
+    const unsigned char *nonce,  unsigned long noncelen,
+    const unsigned char *header, unsigned long headerlen,
+    const unsigned char *pt,     unsigned long ptlen,
+          unsigned char *ct,
+          unsigned char *tag,    unsigned long *taglen);
+
+int eax_decrypt_verify_memory(int cipher,
+    const unsigned char *key,    unsigned long keylen,
+    const unsigned char *nonce,  unsigned long noncelen,
+    const unsigned char *header, unsigned long headerlen,
+    const unsigned char *ct,     unsigned long ctlen,
+          unsigned char *pt,
+          unsigned char *tag,    unsigned long taglen,
+          int           *stat);
+
+ int eax_test(void);
+#endif /* EAX MODE */
+
+#ifdef LTC_OCB_MODE
+typedef struct {
+   unsigned char     L[MAXBLOCKSIZE],         /* L value */
+                     Ls[32][MAXBLOCKSIZE],    /* L shifted by i bits to the left */
+                     Li[MAXBLOCKSIZE],        /* value of Li [current value, we calc from previous recall] */
+                     Lr[MAXBLOCKSIZE],        /* L * x^-1 */
+                     R[MAXBLOCKSIZE],         /* R value */
+                     checksum[MAXBLOCKSIZE];  /* current checksum */
+
+   symmetric_key     key;                     /* scheduled key for cipher */
+   unsigned long     block_index;             /* index # for current block */
+   int               cipher,                  /* cipher idx */
+                     block_len;               /* length of block */
+} ocb_state;
+
+int ocb_init(ocb_state *ocb, int cipher,
+             const unsigned char *key, unsigned long keylen, const unsigned char *nonce);
+
+int ocb_encrypt(ocb_state *ocb, const unsigned char *pt, unsigned char *ct);
+int ocb_decrypt(ocb_state *ocb, const unsigned char *ct, unsigned char *pt);
+
+int ocb_done_encrypt(ocb_state *ocb,
+                     const unsigned char *pt,  unsigned long ptlen,
+                           unsigned char *ct,
+                           unsigned char *tag, unsigned long *taglen);
+
+int ocb_done_decrypt(ocb_state *ocb,
+                     const unsigned char *ct,  unsigned long ctlen,
+                           unsigned char *pt,
+                     const unsigned char *tag, unsigned long taglen, int *stat);
+
+int ocb_encrypt_authenticate_memory(int cipher,
+    const unsigned char *key,    unsigned long keylen,
+    const unsigned char *nonce,
+    const unsigned char *pt,     unsigned long ptlen,
+          unsigned char *ct,
+          unsigned char *tag,    unsigned long *taglen);
+
+int ocb_decrypt_verify_memory(int cipher,
+    const unsigned char *key,    unsigned long keylen,
+    const unsigned char *nonce,
+    const unsigned char *ct,     unsigned long ctlen,
+          unsigned char *pt,
+    const unsigned char *tag,    unsigned long taglen,
+          int           *stat);
+
+int ocb_test(void);
+
+/* internal functions */
+void ocb_shift_xor(ocb_state *ocb, unsigned char *Z);
+int ocb_ntz(unsigned long x);
+int s_ocb_done(ocb_state *ocb, const unsigned char *pt, unsigned long ptlen,
+               unsigned char *ct, unsigned char *tag, unsigned long *taglen, int mode);
+
+#endif /* LTC_OCB_MODE */
+
+#ifdef LTC_OCB3_MODE
+typedef struct {
+   unsigned char     Offset_0[MAXBLOCKSIZE],       /* Offset_0 value */
+                     Offset_current[MAXBLOCKSIZE], /* Offset_{current_block_index} value */
+                     L_dollar[MAXBLOCKSIZE],       /* L_$ value */
+                     L_star[MAXBLOCKSIZE],         /* L_* value */
+                     L_[32][MAXBLOCKSIZE],         /* L_{i} values */
+                     tag_part[MAXBLOCKSIZE],       /* intermediate result of tag calculation */
+                     checksum[MAXBLOCKSIZE];       /* current checksum */
+
+   /* AAD related members */
+   unsigned char     aSum_current[MAXBLOCKSIZE],    /* AAD related helper variable */
+                     aOffset_current[MAXBLOCKSIZE], /* AAD related helper variable */
+                     adata_buffer[MAXBLOCKSIZE];    /* AAD buffer */
+   int               adata_buffer_bytes;            /* bytes in AAD buffer */
+   unsigned long     ablock_index;                  /* index # for current adata (AAD) block */
+
+   symmetric_key     key;                     /* scheduled key for cipher */
+   unsigned long     block_index;             /* index # for current data block */
+   int               cipher,                  /* cipher idx */
+                     tag_len,                 /* length of tag */
+                     block_len;               /* length of block */
+} ocb3_state;
+
+int ocb3_init(ocb3_state *ocb, int cipher,
+             const unsigned char *key, unsigned long keylen,
+             const unsigned char *nonce, unsigned long noncelen,
+             unsigned long taglen);
+
+int ocb3_encrypt(ocb3_state *ocb, const unsigned char *pt, unsigned long ptlen, unsigned char *ct);
+int ocb3_decrypt(ocb3_state *ocb, const unsigned char *ct, unsigned long ctlen, unsigned char *pt);
+int ocb3_encrypt_last(ocb3_state *ocb, const unsigned char *pt, unsigned long ptlen, unsigned char *ct);
+int ocb3_decrypt_last(ocb3_state *ocb, const unsigned char *ct, unsigned long ctlen, unsigned char *pt);
+int ocb3_add_aad(ocb3_state *ocb, const unsigned char *aad, unsigned long aadlen);
+int ocb3_done(ocb3_state *ocb, unsigned char *tag, unsigned long *taglen);
+
+int ocb3_encrypt_authenticate_memory(int cipher,
+    const unsigned char *key,    unsigned long keylen,
+    const unsigned char *nonce,  unsigned long noncelen,
+    const unsigned char *adata,  unsigned long adatalen,
+    const unsigned char *pt,     unsigned long ptlen,
+          unsigned char *ct,
+          unsigned char *tag,    unsigned long *taglen);
+
+int ocb3_decrypt_verify_memory(int cipher,
+    const unsigned char *key,    unsigned long keylen,
+    const unsigned char *nonce,  unsigned long noncelen,
+    const unsigned char *adata,  unsigned long adatalen,
+    const unsigned char *ct,     unsigned long ctlen,
+          unsigned char *pt,
+    const unsigned char *tag,    unsigned long taglen,
+          int           *stat);
+
+int ocb3_test(void);
+
+#ifdef LTC_SOURCE
+/* internal helper functions */
+int ocb3_int_ntz(unsigned long x);
+void ocb3_int_xor_blocks(unsigned char *out, const unsigned char *block_a, const unsigned char *block_b, unsigned long block_len);
+#endif /* LTC_SOURCE */
+
+#endif /* LTC_OCB3_MODE */
+
+#ifdef LTC_CCM_MODE
+
+#define CCM_ENCRYPT LTC_ENCRYPT
+#define CCM_DECRYPT LTC_DECRYPT
+
+typedef struct {
+   symmetric_key       K;
+   int                 cipher,               /* which cipher */
+                       taglen,               /* length of the tag */
+                       x;                    /* index in PAD */
+
+   unsigned long       L,                    /* L value */
+                       ptlen,                /* length that will be enc / dec */
+                       current_ptlen,        /* current processed length */
+                       aadlen,               /* length of the aad */
+                       current_aadlen,       /* length of the currently provided add */
+                       noncelen;             /* length of the nonce */
+
+   unsigned char       PAD[16],
+                       ctr[16],
+                       CTRPAD[16],
+                       CTRlen;
+} ccm_state;
+
+int ccm_init(ccm_state *ccm, int cipher,
+             const unsigned char *key, int keylen, int ptlen, int taglen, int aad_len);
+
+int ccm_reset(ccm_state *ccm);
+
+int ccm_add_nonce(ccm_state *ccm,
+                  const unsigned char *nonce,     unsigned long noncelen);
+
+int ccm_add_aad(ccm_state *ccm,
+                const unsigned char *adata,  unsigned long adatalen);
+
+int ccm_process(ccm_state *ccm,
+                unsigned char *pt,     unsigned long ptlen,
+                unsigned char *ct,
+                int direction);
+
+int ccm_done(ccm_state *ccm,
+             unsigned char *tag,    unsigned long *taglen);
+
+int ccm_memory(int cipher,
+    const unsigned char *key,    unsigned long keylen,
+    symmetric_key       *uskey,
+    const unsigned char *nonce,  unsigned long noncelen,
+    const unsigned char *header, unsigned long headerlen,
+          unsigned char *pt,     unsigned long ptlen,
+          unsigned char *ct,
+          unsigned char *tag,    unsigned long *taglen,
+                    int  direction);
+
+int ccm_test(void);
+
+#endif /* LTC_CCM_MODE */
+
+#if defined(LRW_MODE) || defined(LTC_GCM_MODE)
+void gcm_gf_mult(const unsigned char *a, const unsigned char *b, unsigned char *c);
+#endif
+
+
+/* table shared between GCM and LRW */
+#if defined(LTC_GCM_TABLES) || defined(LTC_LRW_TABLES) || ((defined(LTC_GCM_MODE) || defined(LTC_GCM_MODE)) && defined(LTC_FAST))
+extern const unsigned char gcm_shift_table[];
+#endif
+
+#ifdef LTC_GCM_MODE
+
+#define GCM_ENCRYPT LTC_ENCRYPT
+#define GCM_DECRYPT LTC_DECRYPT
+
+#define LTC_GCM_MODE_IV    0
+#define LTC_GCM_MODE_AAD   1
+#define LTC_GCM_MODE_TEXT  2
+
+typedef struct {
+   symmetric_key       K;
+   unsigned char       H[16],        /* multiplier */
+                       X[16],        /* accumulator */
+                       Y[16],        /* counter */
+                       Y_0[16],      /* initial counter */
+                       buf[16];      /* buffer for stuff */
+
+   int                 cipher,       /* which cipher */
+                       ivmode,       /* Which mode is the IV in? */
+                       mode,         /* mode the GCM code is in */
+                       buflen;       /* length of data in buf */
+
+   ulong64             totlen,       /* 64-bit counter used for IV and AAD */
+                       pttotlen;     /* 64-bit counter for the PT */
+
+#ifdef LTC_GCM_TABLES
+   unsigned char       PC[16][256][16]  /* 16 tables of 8x128 */
+#ifdef LTC_GCM_TABLES_SSE2
+__attribute__ ((aligned (16)))
+#endif
+;
+#endif
+} gcm_state;
+
+void gcm_mult_h(gcm_state *gcm, unsigned char *I);
+
+int gcm_init(gcm_state *gcm, int cipher,
+             const unsigned char *key, int keylen);
+
+int gcm_reset(gcm_state *gcm);
+
+int gcm_add_iv(gcm_state *gcm,
+               const unsigned char *IV,     unsigned long IVlen);
+
+int gcm_add_aad(gcm_state *gcm,
+               const unsigned char *adata,  unsigned long adatalen);
+
+int gcm_process(gcm_state *gcm,
+                     unsigned char *pt,     unsigned long ptlen,
+                     unsigned char *ct,
+                     int direction);
+
+int gcm_done(gcm_state *gcm,
+                     unsigned char *tag,    unsigned long *taglen);
+
+int gcm_memory(      int           cipher,
+               const unsigned char *key,    unsigned long keylen,
+               const unsigned char *IV,     unsigned long IVlen,
+               const unsigned char *adata,  unsigned long adatalen,
+                     unsigned char *pt,     unsigned long ptlen,
+                     unsigned char *ct,
+                     unsigned char *tag,    unsigned long *taglen,
+                               int direction);
+int gcm_test(void);
+
+#endif /* LTC_GCM_MODE */
+
+#ifdef LTC_PELICAN
+
+typedef struct pelican_state
+{
+    symmetric_key K;
+    unsigned char state[16];
+    int           buflen;
+} pelican_state;
+
+int pelican_init(pelican_state *pelmac, const unsigned char *key, unsigned long keylen);
+int pelican_process(pelican_state *pelmac, const unsigned char *in, unsigned long inlen);
+int pelican_done(pelican_state *pelmac, unsigned char *out);
+int pelican_test(void);
+
+int pelican_memory(const unsigned char *key, unsigned long keylen,
+                   const unsigned char *in, unsigned long inlen,
+                         unsigned char *out);
+
+#endif
+
+#ifdef LTC_XCBC
+
+/* add this to "keylen" to xcbc_init to use a pure three-key XCBC MAC */
+#define LTC_XCBC_PURE  0x8000UL
+
+typedef struct {
+   unsigned char K[3][MAXBLOCKSIZE],
+                 IV[MAXBLOCKSIZE];
+
+   symmetric_key key;
+
+             int cipher,
+                 buflen,
+                 blocksize;
+} xcbc_state;
+
+int xcbc_init(xcbc_state *xcbc, int cipher, const unsigned char *key, unsigned long keylen);
+int xcbc_process(xcbc_state *xcbc, const unsigned char *in, unsigned long inlen);
+int xcbc_done(xcbc_state *xcbc, unsigned char *out, unsigned long *outlen);
+int xcbc_memory(int cipher,
+               const unsigned char *key, unsigned long keylen,
+               const unsigned char *in,  unsigned long inlen,
+                     unsigned char *out, unsigned long *outlen);
+int xcbc_memory_multi(int cipher,
+                const unsigned char *key, unsigned long keylen,
+                      unsigned char *out, unsigned long *outlen,
+                const unsigned char *in,  unsigned long inlen, ...);
+int xcbc_file(int cipher,
+              const unsigned char *key, unsigned long keylen,
+              const          char *filename,
+                    unsigned char *out, unsigned long *outlen);
+int xcbc_test(void);
+
+#endif
+
+#ifdef LTC_F9_MODE
+
+typedef struct {
+   unsigned char akey[MAXBLOCKSIZE],
+                 ACC[MAXBLOCKSIZE],
+                 IV[MAXBLOCKSIZE];
+
+   symmetric_key key;
+
+             int cipher,
+                 buflen,
+                 keylen,
+                 blocksize;
+} f9_state;
+
+int f9_init(f9_state *f9, int cipher, const unsigned char *key, unsigned long keylen);
+int f9_process(f9_state *f9, const unsigned char *in, unsigned long inlen);
+int f9_done(f9_state *f9, unsigned char *out, unsigned long *outlen);
+int f9_memory(int cipher,
+               const unsigned char *key, unsigned long keylen,
+               const unsigned char *in,  unsigned long inlen,
+                     unsigned char *out, unsigned long *outlen);
+int f9_memory_multi(int cipher,
+                const unsigned char *key, unsigned long keylen,
+                      unsigned char *out, unsigned long *outlen,
+                const unsigned char *in,  unsigned long inlen, ...);
+int f9_file(int cipher,
+              const unsigned char *key, unsigned long keylen,
+              const          char *filename,
+                    unsigned char *out, unsigned long *outlen);
+int f9_test(void);
+
+#endif
+
+#ifdef LTC_CHACHA20POLY1305_MODE
+
+typedef struct {
+   poly1305_state poly;
+   chacha_state chacha;
+   ulong64 aadlen;
+   ulong64 ctlen;
+   int aadflg;
+} chacha20poly1305_state;
+
+#define CHACHA20POLY1305_ENCRYPT LTC_ENCRYPT
+#define CHACHA20POLY1305_DECRYPT LTC_DECRYPT
+
+int chacha20poly1305_init(chacha20poly1305_state *st, const unsigned char *key, unsigned long keylen);
+int chacha20poly1305_setiv(chacha20poly1305_state *st, const unsigned char *iv, unsigned long ivlen);
+int chacha20poly1305_setiv_rfc7905(chacha20poly1305_state *st, const unsigned char *iv, unsigned long ivlen, ulong64 sequence_number);
+int chacha20poly1305_add_aad(chacha20poly1305_state *st, const unsigned char *in, unsigned long inlen);
+int chacha20poly1305_encrypt(chacha20poly1305_state *st, const unsigned char *in, unsigned long inlen, unsigned char *out);
+int chacha20poly1305_decrypt(chacha20poly1305_state *st, const unsigned char *in, unsigned long inlen, unsigned char *out);
+int chacha20poly1305_done(chacha20poly1305_state *st, unsigned char *tag, unsigned long *taglen);
+int chacha20poly1305_memory(const unsigned char *key, unsigned long keylen,
+                            const unsigned char *iv,  unsigned long ivlen,
+                            const unsigned char *aad, unsigned long aadlen,
+                            const unsigned char *in,  unsigned long inlen,
+                                  unsigned char *out,
+                                  unsigned char *tag, unsigned long *taglen,
+                            int direction);
+int chacha20poly1305_test(void);
+
+#endif /* LTC_CHACHA20POLY1305_MODE */
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/headers/tomcrypt_macros.h b/libtomcrypt/src/headers/tomcrypt_macros.h
new file mode 100644 (file)
index 0000000..94e368f
--- /dev/null
@@ -0,0 +1,446 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+/* ---- HELPER MACROS ---- */
+#ifdef ENDIAN_NEUTRAL
+
+#define STORE32L(x, y)                                                                     \
+  do { (y)[3] = (unsigned char)(((x)>>24)&255); (y)[2] = (unsigned char)(((x)>>16)&255);   \
+       (y)[1] = (unsigned char)(((x)>>8)&255); (y)[0] = (unsigned char)((x)&255); } while(0)
+
+#define LOAD32L(x, y)                            \
+  do { x = ((ulong32)((y)[3] & 255)<<24) | \
+           ((ulong32)((y)[2] & 255)<<16) | \
+           ((ulong32)((y)[1] & 255)<<8)  | \
+           ((ulong32)((y)[0] & 255)); } while(0)
+
+#define STORE64L(x, y)                                                                     \
+  do { (y)[7] = (unsigned char)(((x)>>56)&255); (y)[6] = (unsigned char)(((x)>>48)&255);   \
+       (y)[5] = (unsigned char)(((x)>>40)&255); (y)[4] = (unsigned char)(((x)>>32)&255);   \
+       (y)[3] = (unsigned char)(((x)>>24)&255); (y)[2] = (unsigned char)(((x)>>16)&255);   \
+       (y)[1] = (unsigned char)(((x)>>8)&255); (y)[0] = (unsigned char)((x)&255); } while(0)
+
+#define LOAD64L(x, y)                                                       \
+  do { x = (((ulong64)((y)[7] & 255))<<56)|(((ulong64)((y)[6] & 255))<<48)| \
+           (((ulong64)((y)[5] & 255))<<40)|(((ulong64)((y)[4] & 255))<<32)| \
+           (((ulong64)((y)[3] & 255))<<24)|(((ulong64)((y)[2] & 255))<<16)| \
+           (((ulong64)((y)[1] & 255))<<8)|(((ulong64)((y)[0] & 255))); } while(0)
+
+#define STORE32H(x, y)                                                                     \
+  do { (y)[0] = (unsigned char)(((x)>>24)&255); (y)[1] = (unsigned char)(((x)>>16)&255);   \
+       (y)[2] = (unsigned char)(((x)>>8)&255); (y)[3] = (unsigned char)((x)&255); } while(0)
+
+#define LOAD32H(x, y)                            \
+  do { x = ((ulong32)((y)[0] & 255)<<24) | \
+           ((ulong32)((y)[1] & 255)<<16) | \
+           ((ulong32)((y)[2] & 255)<<8)  | \
+           ((ulong32)((y)[3] & 255)); } while(0)
+
+#define STORE64H(x, y)                                                                     \
+do { (y)[0] = (unsigned char)(((x)>>56)&255); (y)[1] = (unsigned char)(((x)>>48)&255);     \
+     (y)[2] = (unsigned char)(((x)>>40)&255); (y)[3] = (unsigned char)(((x)>>32)&255);     \
+     (y)[4] = (unsigned char)(((x)>>24)&255); (y)[5] = (unsigned char)(((x)>>16)&255);     \
+     (y)[6] = (unsigned char)(((x)>>8)&255); (y)[7] = (unsigned char)((x)&255); } while(0)
+
+#define LOAD64H(x, y)                                                      \
+do { x = (((ulong64)((y)[0] & 255))<<56)|(((ulong64)((y)[1] & 255))<<48) | \
+         (((ulong64)((y)[2] & 255))<<40)|(((ulong64)((y)[3] & 255))<<32) | \
+         (((ulong64)((y)[4] & 255))<<24)|(((ulong64)((y)[5] & 255))<<16) | \
+         (((ulong64)((y)[6] & 255))<<8)|(((ulong64)((y)[7] & 255))); } while(0)
+
+
+#elif defined(ENDIAN_LITTLE)
+
+#ifdef LTC_HAVE_BSWAP_BUILTIN
+
+#define STORE32H(x, y)                          \
+do { ulong32 __t = __builtin_bswap32 ((x));     \
+      XMEMCPY ((y), &__t, 4); } while(0)
+
+#define LOAD32H(x, y)                           \
+do { XMEMCPY (&(x), (y), 4);                    \
+      (x) = __builtin_bswap32 ((x)); } while(0)
+
+#elif !defined(LTC_NO_BSWAP) && (defined(INTEL_CC) || (defined(__GNUC__) && (defined(__DJGPP__) || defined(__CYGWIN__) || defined(__MINGW32__) || defined(__i386__) || defined(__x86_64__))))
+
+#define STORE32H(x, y)           \
+asm __volatile__ (               \
+   "bswapl %0     \n\t"          \
+   "movl   %0,(%1)\n\t"          \
+   "bswapl %0     \n\t"          \
+      ::"r"(x), "r"(y));
+
+#define LOAD32H(x, y)          \
+asm __volatile__ (             \
+   "movl (%1),%0\n\t"          \
+   "bswapl %0\n\t"             \
+   :"=r"(x): "r"(y));
+
+#else
+
+#define STORE32H(x, y)                                                                     \
+  do { (y)[0] = (unsigned char)(((x)>>24)&255); (y)[1] = (unsigned char)(((x)>>16)&255);   \
+       (y)[2] = (unsigned char)(((x)>>8)&255); (y)[3] = (unsigned char)((x)&255); } while(0)
+
+#define LOAD32H(x, y)                            \
+  do { x = ((ulong32)((y)[0] & 255)<<24) | \
+           ((ulong32)((y)[1] & 255)<<16) | \
+           ((ulong32)((y)[2] & 255)<<8)  | \
+           ((ulong32)((y)[3] & 255)); } while(0)
+
+#endif
+
+#ifdef LTC_HAVE_BSWAP_BUILTIN
+
+#define STORE64H(x, y)                          \
+do { ulong64 __t = __builtin_bswap64 ((x));     \
+      XMEMCPY ((y), &__t, 8); } while(0)
+
+#define LOAD64H(x, y)                           \
+do { XMEMCPY (&(x), (y), 8);                    \
+      (x) = __builtin_bswap64 ((x)); } while(0)
+
+/* x86_64 processor */
+#elif !defined(LTC_NO_BSWAP) && (defined(__GNUC__) && defined(__x86_64__))
+
+#define STORE64H(x, y)           \
+asm __volatile__ (               \
+   "bswapq %0     \n\t"          \
+   "movq   %0,(%1)\n\t"          \
+   "bswapq %0     \n\t"          \
+   ::"r"(x), "r"(y): "memory");
+
+#define LOAD64H(x, y)          \
+asm __volatile__ (             \
+   "movq (%1),%0\n\t"          \
+   "bswapq %0\n\t"             \
+   :"=r"(x): "r"(y): "memory");
+
+#else
+
+#define STORE64H(x, y)                                                                     \
+do { (y)[0] = (unsigned char)(((x)>>56)&255); (y)[1] = (unsigned char)(((x)>>48)&255);     \
+     (y)[2] = (unsigned char)(((x)>>40)&255); (y)[3] = (unsigned char)(((x)>>32)&255);     \
+     (y)[4] = (unsigned char)(((x)>>24)&255); (y)[5] = (unsigned char)(((x)>>16)&255);     \
+     (y)[6] = (unsigned char)(((x)>>8)&255); (y)[7] = (unsigned char)((x)&255); } while(0)
+
+#define LOAD64H(x, y)                                                      \
+do { x = (((ulong64)((y)[0] & 255))<<56)|(((ulong64)((y)[1] & 255))<<48) | \
+         (((ulong64)((y)[2] & 255))<<40)|(((ulong64)((y)[3] & 255))<<32) | \
+         (((ulong64)((y)[4] & 255))<<24)|(((ulong64)((y)[5] & 255))<<16) | \
+         (((ulong64)((y)[6] & 255))<<8)|(((ulong64)((y)[7] & 255))); } while(0)
+
+#endif
+
+#ifdef ENDIAN_32BITWORD
+
+#define STORE32L(x, y)        \
+  do { ulong32  __t = (x); XMEMCPY(y, &__t, 4); } while(0)
+
+#define LOAD32L(x, y)         \
+  do { XMEMCPY(&(x), y, 4); } while(0)
+
+#define STORE64L(x, y)                                                                     \
+  do { (y)[7] = (unsigned char)(((x)>>56)&255); (y)[6] = (unsigned char)(((x)>>48)&255);   \
+       (y)[5] = (unsigned char)(((x)>>40)&255); (y)[4] = (unsigned char)(((x)>>32)&255);   \
+       (y)[3] = (unsigned char)(((x)>>24)&255); (y)[2] = (unsigned char)(((x)>>16)&255);   \
+       (y)[1] = (unsigned char)(((x)>>8)&255); (y)[0] = (unsigned char)((x)&255); } while(0)
+
+#define LOAD64L(x, y)                                                       \
+  do { x = (((ulong64)((y)[7] & 255))<<56)|(((ulong64)((y)[6] & 255))<<48)| \
+           (((ulong64)((y)[5] & 255))<<40)|(((ulong64)((y)[4] & 255))<<32)| \
+           (((ulong64)((y)[3] & 255))<<24)|(((ulong64)((y)[2] & 255))<<16)| \
+           (((ulong64)((y)[1] & 255))<<8)|(((ulong64)((y)[0] & 255))); } while(0)
+
+#else /* 64-bit words then  */
+
+#define STORE32L(x, y)        \
+  do { ulong32 __t = (x); XMEMCPY(y, &__t, 4); } while(0)
+
+#define LOAD32L(x, y)         \
+  do { XMEMCPY(&(x), y, 4); x &= 0xFFFFFFFF; } while(0)
+
+#define STORE64L(x, y)        \
+  do { ulong64 __t = (x); XMEMCPY(y, &__t, 8); } while(0)
+
+#define LOAD64L(x, y)         \
+  do { XMEMCPY(&(x), y, 8); } while(0)
+
+#endif /* ENDIAN_64BITWORD */
+
+#elif defined(ENDIAN_BIG)
+
+#define STORE32L(x, y)                                                                     \
+  do { (y)[3] = (unsigned char)(((x)>>24)&255); (y)[2] = (unsigned char)(((x)>>16)&255);   \
+       (y)[1] = (unsigned char)(((x)>>8)&255); (y)[0] = (unsigned char)((x)&255); } while(0)
+
+#define LOAD32L(x, y)                            \
+  do { x = ((ulong32)((y)[3] & 255)<<24) | \
+           ((ulong32)((y)[2] & 255)<<16) | \
+           ((ulong32)((y)[1] & 255)<<8)  | \
+           ((ulong32)((y)[0] & 255)); } while(0)
+
+#define STORE64L(x, y)                                                                     \
+do { (y)[7] = (unsigned char)(((x)>>56)&255); (y)[6] = (unsigned char)(((x)>>48)&255);     \
+     (y)[5] = (unsigned char)(((x)>>40)&255); (y)[4] = (unsigned char)(((x)>>32)&255);     \
+     (y)[3] = (unsigned char)(((x)>>24)&255); (y)[2] = (unsigned char)(((x)>>16)&255);     \
+     (y)[1] = (unsigned char)(((x)>>8)&255); (y)[0] = (unsigned char)((x)&255); } while(0)
+
+#define LOAD64L(x, y)                                                      \
+do { x = (((ulong64)((y)[7] & 255))<<56)|(((ulong64)((y)[6] & 255))<<48) | \
+         (((ulong64)((y)[5] & 255))<<40)|(((ulong64)((y)[4] & 255))<<32) | \
+         (((ulong64)((y)[3] & 255))<<24)|(((ulong64)((y)[2] & 255))<<16) | \
+         (((ulong64)((y)[1] & 255))<<8)|(((ulong64)((y)[0] & 255))); } while(0)
+
+#ifdef ENDIAN_32BITWORD
+
+#define STORE32H(x, y)        \
+  do { ulong32 __t = (x); XMEMCPY(y, &__t, 4); } while(0)
+
+#define LOAD32H(x, y)         \
+  do { XMEMCPY(&(x), y, 4); } while(0)
+
+#define STORE64H(x, y)                                                                     \
+  do { (y)[0] = (unsigned char)(((x)>>56)&255); (y)[1] = (unsigned char)(((x)>>48)&255);   \
+       (y)[2] = (unsigned char)(((x)>>40)&255); (y)[3] = (unsigned char)(((x)>>32)&255);   \
+       (y)[4] = (unsigned char)(((x)>>24)&255); (y)[5] = (unsigned char)(((x)>>16)&255);   \
+       (y)[6] = (unsigned char)(((x)>>8)&255);  (y)[7] = (unsigned char)((x)&255); } while(0)
+
+#define LOAD64H(x, y)                                                       \
+  do { x = (((ulong64)((y)[0] & 255))<<56)|(((ulong64)((y)[1] & 255))<<48)| \
+           (((ulong64)((y)[2] & 255))<<40)|(((ulong64)((y)[3] & 255))<<32)| \
+           (((ulong64)((y)[4] & 255))<<24)|(((ulong64)((y)[5] & 255))<<16)| \
+           (((ulong64)((y)[6] & 255))<<8)| (((ulong64)((y)[7] & 255))); } while(0)
+
+#else /* 64-bit words then  */
+
+#define STORE32H(x, y)        \
+  do { ulong32 __t = (x); XMEMCPY(y, &__t, 4); } while(0)
+
+#define LOAD32H(x, y)         \
+  do { XMEMCPY(&(x), y, 4); x &= 0xFFFFFFFF; } while(0)
+
+#define STORE64H(x, y)        \
+  do { ulong64 __t = (x); XMEMCPY(y, &__t, 8); } while(0)
+
+#define LOAD64H(x, y)         \
+  do { XMEMCPY(&(x), y, 8); } while(0)
+
+#endif /* ENDIAN_64BITWORD */
+#endif /* ENDIAN_BIG */
+
+#define BSWAP(x)  ( ((x>>24)&0x000000FFUL) | ((x<<24)&0xFF000000UL)  | \
+                    ((x>>8)&0x0000FF00UL)  | ((x<<8)&0x00FF0000UL) )
+
+
+/* 32-bit Rotates */
+#if defined(_MSC_VER)
+#define LTC_ROx_ASM
+
+/* instrinsic rotate */
+#include <stdlib.h>
+#pragma intrinsic(_lrotr,_lrotl)
+#define ROR(x,n) _lrotr(x,n)
+#define ROL(x,n) _lrotl(x,n)
+#define RORc(x,n) _lrotr(x,n)
+#define ROLc(x,n) _lrotl(x,n)
+
+#elif !defined(__STRICT_ANSI__) && defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) && !defined(INTEL_CC) && !defined(LTC_NO_ASM)
+#define LTC_ROx_ASM
+
+static inline ulong32 ROL(ulong32 word, int i)
+{
+   asm ("roll %%cl,%0"
+      :"=r" (word)
+      :"0" (word),"c" (i));
+   return word;
+}
+
+static inline ulong32 ROR(ulong32 word, int i)
+{
+   asm ("rorl %%cl,%0"
+      :"=r" (word)
+      :"0" (word),"c" (i));
+   return word;
+}
+
+#ifndef LTC_NO_ROLC
+
+#define ROLc(word,i) ({ \
+   ulong32 __ROLc_tmp = (word); \
+   __asm__ ("roll %2, %0" : \
+            "=r" (__ROLc_tmp) : \
+            "0" (__ROLc_tmp), \
+            "I" (i)); \
+            __ROLc_tmp; \
+   })
+#define RORc(word,i) ({ \
+   ulong32 __RORc_tmp = (word); \
+   __asm__ ("rorl %2, %0" : \
+            "=r" (__RORc_tmp) : \
+            "0" (__RORc_tmp), \
+            "I" (i)); \
+            __RORc_tmp; \
+   })
+
+#else
+
+#define ROLc ROL
+#define RORc ROR
+
+#endif
+
+#elif !defined(__STRICT_ANSI__) && defined(LTC_PPC32)
+#define LTC_ROx_ASM
+
+static inline ulong32 ROL(ulong32 word, int i)
+{
+   asm ("rotlw %0,%0,%2"
+      :"=r" (word)
+      :"0" (word),"r" (i));
+   return word;
+}
+
+static inline ulong32 ROR(ulong32 word, int i)
+{
+   asm ("rotlw %0,%0,%2"
+      :"=r" (word)
+      :"0" (word),"r" (32-i));
+   return word;
+}
+
+#ifndef LTC_NO_ROLC
+
+static inline ulong32 ROLc(ulong32 word, const int i)
+{
+   asm ("rotlwi %0,%0,%2"
+      :"=r" (word)
+      :"0" (word),"I" (i));
+   return word;
+}
+
+static inline ulong32 RORc(ulong32 word, const int i)
+{
+   asm ("rotrwi %0,%0,%2"
+      :"=r" (word)
+      :"0" (word),"I" (i));
+   return word;
+}
+
+#else
+
+#define ROLc ROL
+#define RORc ROR
+
+#endif
+
+
+#else
+
+/* rotates the hard way */
+#define ROL(x, y) ( (((ulong32)(x)<<(ulong32)((y)&31)) | (((ulong32)(x)&0xFFFFFFFFUL)>>(ulong32)((32-((y)&31))&31))) & 0xFFFFFFFFUL)
+#define ROR(x, y) ( ((((ulong32)(x)&0xFFFFFFFFUL)>>(ulong32)((y)&31)) | ((ulong32)(x)<<(ulong32)((32-((y)&31))&31))) & 0xFFFFFFFFUL)
+#define ROLc(x, y) ( (((ulong32)(x)<<(ulong32)((y)&31)) | (((ulong32)(x)&0xFFFFFFFFUL)>>(ulong32)((32-((y)&31))&31))) & 0xFFFFFFFFUL)
+#define RORc(x, y) ( ((((ulong32)(x)&0xFFFFFFFFUL)>>(ulong32)((y)&31)) | ((ulong32)(x)<<(ulong32)((32-((y)&31))&31))) & 0xFFFFFFFFUL)
+
+#endif
+
+
+/* 64-bit Rotates */
+#if !defined(__STRICT_ANSI__) && defined(__GNUC__) && defined(__x86_64__) && !defined(_WIN64) && !defined(LTC_NO_ASM)
+
+static inline ulong64 ROL64(ulong64 word, int i)
+{
+   asm("rolq %%cl,%0"
+      :"=r" (word)
+      :"0" (word),"c" (i));
+   return word;
+}
+
+static inline ulong64 ROR64(ulong64 word, int i)
+{
+   asm("rorq %%cl,%0"
+      :"=r" (word)
+      :"0" (word),"c" (i));
+   return word;
+}
+
+#ifndef LTC_NO_ROLC
+
+#define ROL64c(word,i) ({ \
+   ulong64 __ROL64c_tmp = word; \
+   __asm__ ("rolq %2, %0" : \
+            "=r" (__ROL64c_tmp) : \
+            "0" (__ROL64c_tmp), \
+            "J" (i)); \
+            __ROL64c_tmp; \
+   })
+#define ROR64c(word,i) ({ \
+   ulong64 __ROR64c_tmp = word; \
+   __asm__ ("rorq %2, %0" : \
+            "=r" (__ROR64c_tmp) : \
+            "0" (__ROR64c_tmp), \
+            "J" (i)); \
+            __ROR64c_tmp; \
+   })
+
+#else /* LTC_NO_ROLC */
+
+#define ROL64c ROL64
+#define ROR64c ROR64
+
+#endif
+
+#else /* Not x86_64  */
+
+#define ROL64(x, y) \
+    ( (((x)<<((ulong64)(y)&63)) | \
+      (((x)&CONST64(0xFFFFFFFFFFFFFFFF))>>(((ulong64)64-((y)&63))&63))) & CONST64(0xFFFFFFFFFFFFFFFF))
+
+#define ROR64(x, y) \
+    ( ((((x)&CONST64(0xFFFFFFFFFFFFFFFF))>>((ulong64)(y)&CONST64(63))) | \
+      ((x)<<(((ulong64)64-((y)&63))&63))) & CONST64(0xFFFFFFFFFFFFFFFF))
+
+#define ROL64c(x, y) \
+    ( (((x)<<((ulong64)(y)&63)) | \
+      (((x)&CONST64(0xFFFFFFFFFFFFFFFF))>>(((ulong64)64-((y)&63))&63))) & CONST64(0xFFFFFFFFFFFFFFFF))
+
+#define ROR64c(x, y) \
+    ( ((((x)&CONST64(0xFFFFFFFFFFFFFFFF))>>((ulong64)(y)&CONST64(63))) | \
+      ((x)<<(((ulong64)64-((y)&63))&63))) & CONST64(0xFFFFFFFFFFFFFFFF))
+
+#endif
+
+#ifndef MAX
+   #define MAX(x, y) ( ((x)>(y))?(x):(y) )
+#endif
+
+#ifndef MIN
+   #define MIN(x, y) ( ((x)<(y))?(x):(y) )
+#endif
+
+#ifndef LTC_UNUSED_PARAM
+   #define LTC_UNUSED_PARAM(x) (void)(x)
+#endif
+
+/* extract a byte portably */
+#ifdef _MSC_VER
+   #define byte(x, n) ((unsigned char)((x) >> (8 * (n))))
+#else
+   #define byte(x, n) (((x) >> (8 * (n))) & 255)
+#endif
+
+/* there is no snprintf before Visual C++ 2015 */
+#if defined(_MSC_VER) && _MSC_VER < 1900
+#define snprintf _snprintf
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/headers/tomcrypt_math.h b/libtomcrypt/src/headers/tomcrypt_math.h
new file mode 100644 (file)
index 0000000..d8e7e36
--- /dev/null
@@ -0,0 +1,583 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+/** math functions **/
+
+#define LTC_MP_LT   -1
+#define LTC_MP_EQ    0
+#define LTC_MP_GT    1
+
+#define LTC_MP_NO    0
+#define LTC_MP_YES   1
+
+#ifndef LTC_MECC
+   typedef void ecc_point;
+#endif
+
+#ifndef LTC_MRSA
+   typedef void rsa_key;
+#endif
+
+#ifndef LTC_MILLER_RABIN_REPS
+   /* Number of rounds of the Miller-Rabin test
+    * "Reasonable values of reps are between 15 and 50." c.f. gmp doc of mpz_probab_prime_p()
+    * As of https://security.stackexchange.com/a/4546 we should use 40 rounds */
+   #define LTC_MILLER_RABIN_REPS    40
+#endif
+
+int radix_to_bin(const void *in, int radix, void *out, unsigned long *len);
+
+/** math descriptor */
+typedef struct {
+   /** Name of the math provider */
+   const char *name;
+
+   /** Bits per digit, amount of bits must fit in an unsigned long */
+   int  bits_per_digit;
+
+/* ---- init/deinit functions ---- */
+
+   /** initialize a bignum
+     @param   a     The number to initialize
+     @return  CRYPT_OK on success
+   */
+   int (*init)(void **a);
+
+   /** init copy
+     @param  dst    The number to initialize and write to
+     @param  src    The number to copy from
+     @return CRYPT_OK on success
+   */
+   int (*init_copy)(void **dst, void *src);
+
+   /** deinit
+      @param   a    The number to free
+      @return CRYPT_OK on success
+   */
+   void (*deinit)(void *a);
+
+/* ---- data movement ---- */
+
+   /** negate
+      @param   src   The number to negate
+      @param   dst   The destination
+      @return CRYPT_OK on success
+   */
+   int (*neg)(void *src, void *dst);
+
+   /** copy
+      @param   src   The number to copy from
+      @param   dst   The number to write to
+      @return CRYPT_OK on success
+   */
+   int (*copy)(void *src, void *dst);
+
+/* ---- trivial low level functions ---- */
+
+   /** set small constant
+      @param a    Number to write to
+      @param n    Source upto bits_per_digit (actually meant for very small constants)
+      @return CRYPT_OK on success
+   */
+   int (*set_int)(void *a, ltc_mp_digit n);
+
+   /** get small constant
+      @param a  Small number to read,
+                only fetches up to bits_per_digit from the number
+      @return   The lower bits_per_digit of the integer (unsigned)
+   */
+   unsigned long (*get_int)(void *a);
+
+   /** get digit n
+     @param a  The number to read from
+     @param n  The number of the digit to fetch
+     @return  The bits_per_digit  sized n'th digit of a
+   */
+   ltc_mp_digit (*get_digit)(void *a, int n);
+
+   /** Get the number of digits that represent the number
+     @param a   The number to count
+     @return The number of digits used to represent the number
+   */
+   int (*get_digit_count)(void *a);
+
+   /** compare two integers
+     @param a   The left side integer
+     @param b   The right side integer
+     @return LTC_MP_LT if a < b,
+             LTC_MP_GT if a > b and
+             LTC_MP_EQ otherwise.  (signed comparison)
+   */
+   int (*compare)(void *a, void *b);
+
+   /** compare against int
+     @param a   The left side integer
+     @param b   The right side integer (upto bits_per_digit)
+     @return LTC_MP_LT if a < b,
+             LTC_MP_GT if a > b and
+             LTC_MP_EQ otherwise.  (signed comparison)
+   */
+   int (*compare_d)(void *a, ltc_mp_digit n);
+
+   /** Count the number of bits used to represent the integer
+     @param a   The integer to count
+     @return The number of bits required to represent the integer
+   */
+   int (*count_bits)(void * a);
+
+   /** Count the number of LSB bits which are zero
+     @param a   The integer to count
+     @return The number of contiguous zero LSB bits
+   */
+   int (*count_lsb_bits)(void *a);
+
+   /** Compute a power of two
+     @param a  The integer to store the power in
+     @param n  The power of two you want to store (a = 2^n)
+     @return CRYPT_OK on success
+   */
+   int (*twoexpt)(void *a , int n);
+
+/* ---- radix conversions ---- */
+
+   /** read ascii string
+     @param a     The integer to store into
+     @param str   The string to read
+     @param radix The radix the integer has been represented in (2-64)
+     @return CRYPT_OK on success
+   */
+   int (*read_radix)(void *a, const char *str, int radix);
+
+   /** write number to string
+     @param a     The integer to store
+     @param str   The destination for the string
+     @param radix The radix the integer is to be represented in (2-64)
+     @return CRYPT_OK on success
+   */
+   int (*write_radix)(void *a, char *str, int radix);
+
+   /** get size as unsigned char string
+     @param a  The integer to get the size (when stored in array of octets)
+     @return   The length of the integer in octets
+   */
+   unsigned long (*unsigned_size)(void *a);
+
+   /** store an integer as an array of octets
+     @param src   The integer to store
+     @param dst   The buffer to store the integer in
+     @return CRYPT_OK on success
+   */
+   int (*unsigned_write)(void *src, unsigned char *dst);
+
+   /** read an array of octets and store as integer
+     @param dst   The integer to load
+     @param src   The array of octets
+     @param len   The number of octets
+     @return CRYPT_OK on success
+   */
+   int (*unsigned_read)(         void *dst,
+                        unsigned char *src,
+                        unsigned long  len);
+
+/* ---- basic math ---- */
+
+   /** add two integers
+     @param a   The first source integer
+     @param b   The second source integer
+     @param c   The destination of "a + b"
+     @return CRYPT_OK on success
+   */
+   int (*add)(void *a, void *b, void *c);
+
+   /** add two integers
+     @param a   The first source integer
+     @param b   The second source integer
+                (single digit of upto bits_per_digit in length)
+     @param c   The destination of "a + b"
+     @return CRYPT_OK on success
+   */
+   int (*addi)(void *a, ltc_mp_digit b, void *c);
+
+   /** subtract two integers
+     @param a   The first source integer
+     @param b   The second source integer
+     @param c   The destination of "a - b"
+     @return CRYPT_OK on success
+   */
+   int (*sub)(void *a, void *b, void *c);
+
+   /** subtract two integers
+     @param a   The first source integer
+     @param b   The second source integer
+                (single digit of upto bits_per_digit in length)
+     @param c   The destination of "a - b"
+     @return CRYPT_OK on success
+   */
+   int (*subi)(void *a, ltc_mp_digit b, void *c);
+
+   /** multiply two integers
+     @param a   The first source integer
+     @param b   The second source integer
+                (single digit of upto bits_per_digit in length)
+     @param c   The destination of "a * b"
+     @return CRYPT_OK on success
+   */
+   int (*mul)(void *a, void *b, void *c);
+
+   /** multiply two integers
+     @param a   The first source integer
+     @param b   The second source integer
+                (single digit of upto bits_per_digit in length)
+     @param c   The destination of "a * b"
+     @return CRYPT_OK on success
+   */
+   int (*muli)(void *a, ltc_mp_digit b, void *c);
+
+   /** Square an integer
+     @param a    The integer to square
+     @param b    The destination
+     @return CRYPT_OK on success
+   */
+   int (*sqr)(void *a, void *b);
+
+   /** Divide an integer
+     @param a    The dividend
+     @param b    The divisor
+     @param c    The quotient (can be NULL to signify don't care)
+     @param d    The remainder (can be NULL to signify don't care)
+     @return CRYPT_OK on success
+   */
+   int (*mpdiv)(void *a, void *b, void *c, void *d);
+
+   /** divide by two
+      @param  a   The integer to divide (shift right)
+      @param  b   The destination
+      @return CRYPT_OK on success
+   */
+   int (*div_2)(void *a, void *b);
+
+   /** Get remainder (small value)
+      @param  a    The integer to reduce
+      @param  b    The modulus (upto bits_per_digit in length)
+      @param  c    The destination for the residue
+      @return CRYPT_OK on success
+   */
+   int (*modi)(void *a, ltc_mp_digit b, ltc_mp_digit *c);
+
+   /** gcd
+      @param  a     The first integer
+      @param  b     The second integer
+      @param  c     The destination for (a, b)
+      @return CRYPT_OK on success
+   */
+   int (*gcd)(void *a, void *b, void *c);
+
+   /** lcm
+      @param  a     The first integer
+      @param  b     The second integer
+      @param  c     The destination for [a, b]
+      @return CRYPT_OK on success
+   */
+   int (*lcm)(void *a, void *b, void *c);
+
+   /** Modular multiplication
+      @param  a     The first source
+      @param  b     The second source
+      @param  c     The modulus
+      @param  d     The destination (a*b mod c)
+      @return CRYPT_OK on success
+   */
+   int (*mulmod)(void *a, void *b, void *c, void *d);
+
+   /** Modular squaring
+      @param  a     The first source
+      @param  b     The modulus
+      @param  c     The destination (a*a mod b)
+      @return CRYPT_OK on success
+   */
+   int (*sqrmod)(void *a, void *b, void *c);
+
+   /** Modular inversion
+      @param  a     The value to invert
+      @param  b     The modulus
+      @param  c     The destination (1/a mod b)
+      @return CRYPT_OK on success
+   */
+   int (*invmod)(void *, void *, void *);
+
+/* ---- reduction ---- */
+
+   /** setup Montgomery
+       @param a  The modulus
+       @param b  The destination for the reduction digit
+       @return CRYPT_OK on success
+   */
+   int (*montgomery_setup)(void *a, void **b);
+
+   /** get normalization value
+       @param a   The destination for the normalization value
+       @param b   The modulus
+       @return  CRYPT_OK on success
+   */
+   int (*montgomery_normalization)(void *a, void *b);
+
+   /** reduce a number
+       @param a   The number [and dest] to reduce
+       @param b   The modulus
+       @param c   The value "b" from montgomery_setup()
+       @return CRYPT_OK on success
+   */
+   int (*montgomery_reduce)(void *a, void *b, void *c);
+
+   /** clean up  (frees memory)
+       @param a   The value "b" from montgomery_setup()
+       @return CRYPT_OK on success
+   */
+   void (*montgomery_deinit)(void *a);
+
+/* ---- exponentiation ---- */
+
+   /** Modular exponentiation
+       @param a    The base integer
+       @param b    The power (can be negative) integer
+       @param c    The modulus integer
+       @param d    The destination
+       @return CRYPT_OK on success
+   */
+   int (*exptmod)(void *a, void *b, void *c, void *d);
+
+   /** Primality testing
+       @param a     The integer to test
+       @param b     The number of Miller-Rabin tests that shall be executed
+       @param c     The destination of the result (FP_YES if prime)
+       @return CRYPT_OK on success
+   */
+   int (*isprime)(void *a, int b, int *c);
+
+/* ----  (optional) ecc point math ---- */
+
+   /** ECC GF(p) point multiplication (from the NIST curves)
+       @param k   The integer to multiply the point by
+       @param G   The point to multiply
+       @param R   The destination for kG
+       @param modulus  The modulus for the field
+       @param map Boolean indicated whether to map back to affine or not
+                  (can be ignored if you work in affine only)
+       @return CRYPT_OK on success
+   */
+   int (*ecc_ptmul)(     void *k,
+                    ecc_point *G,
+                    ecc_point *R,
+                         void *modulus,
+                          int  map);
+
+   /** ECC GF(p) point addition
+       @param P    The first point
+       @param Q    The second point
+       @param R    The destination of P + Q
+       @param modulus  The modulus
+       @param mp   The "b" value from montgomery_setup()
+       @return CRYPT_OK on success
+   */
+   int (*ecc_ptadd)(ecc_point *P,
+                    ecc_point *Q,
+                    ecc_point *R,
+                         void *modulus,
+                         void *mp);
+
+   /** ECC GF(p) point double
+       @param P    The first point
+       @param R    The destination of 2P
+       @param modulus  The modulus
+       @param mp   The "b" value from montgomery_setup()
+       @return CRYPT_OK on success
+   */
+   int (*ecc_ptdbl)(ecc_point *P,
+                    ecc_point *R,
+                         void *modulus,
+                         void *mp);
+
+   /** ECC mapping from projective to affine,
+       currently uses (x,y,z) => (x/z^2, y/z^3, 1)
+       @param P     The point to map
+       @param modulus The modulus
+       @param mp    The "b" value from montgomery_setup()
+       @return CRYPT_OK on success
+       @remark The mapping can be different but keep in mind a
+               ecc_point only has three integers (x,y,z) so if
+               you use a different mapping you have to make it fit.
+   */
+   int (*ecc_map)(ecc_point *P, void *modulus, void *mp);
+
+   /** Computes kA*A + kB*B = C using Shamir's Trick
+       @param A        First point to multiply
+       @param kA       What to multiple A by
+       @param B        Second point to multiply
+       @param kB       What to multiple B by
+       @param C        [out] Destination point (can overlap with A or B)
+       @param modulus  Modulus for curve
+       @return CRYPT_OK on success
+   */
+   int (*ecc_mul2add)(ecc_point *A, void *kA,
+                      ecc_point *B, void *kB,
+                      ecc_point *C,
+                           void *modulus);
+
+/* ---- (optional) rsa optimized math (for internal CRT) ---- */
+
+   /** RSA Key Generation
+       @param prng     An active PRNG state
+       @param wprng    The index of the PRNG desired
+       @param size     The size of the key in octets
+       @param e        The "e" value (public key).
+                       e==65537 is a good choice
+       @param key      [out] Destination of a newly created private key pair
+       @return CRYPT_OK if successful, upon error all allocated ram is freed
+    */
+    int (*rsa_keygen)(prng_state *prng,
+                             int  wprng,
+                             int  size,
+                            long  e,
+                         rsa_key *key);
+
+   /** RSA exponentiation
+      @param in       The octet array representing the base
+      @param inlen    The length of the input
+      @param out      The destination (to be stored in an octet array format)
+      @param outlen   The length of the output buffer and the resulting size
+                      (zero padded to the size of the modulus)
+      @param which    PK_PUBLIC for public RSA and PK_PRIVATE for private RSA
+      @param key      The RSA key to use
+      @return CRYPT_OK on success
+   */
+   int (*rsa_me)(const unsigned char *in,   unsigned long inlen,
+                       unsigned char *out,  unsigned long *outlen, int which,
+                       rsa_key *key);
+
+/* ---- basic math continued ---- */
+
+   /** Modular addition
+      @param  a     The first source
+      @param  b     The second source
+      @param  c     The modulus
+      @param  d     The destination (a + b mod c)
+      @return CRYPT_OK on success
+   */
+   int (*addmod)(void *a, void *b, void *c, void *d);
+
+   /** Modular substraction
+      @param  a     The first source
+      @param  b     The second source
+      @param  c     The modulus
+      @param  d     The destination (a - b mod c)
+      @return CRYPT_OK on success
+   */
+   int (*submod)(void *a, void *b, void *c, void *d);
+
+/* ---- misc stuff ---- */
+
+   /** Make a pseudo-random mpi
+      @param  a     The mpi to make random
+      @param  size  The desired length
+      @return CRYPT_OK on success
+   */
+   int (*rand)(void *a, int size);
+} ltc_math_descriptor;
+
+extern ltc_math_descriptor ltc_mp;
+
+int ltc_init_multi(void **a, ...);
+void ltc_deinit_multi(void *a, ...);
+void ltc_cleanup_multi(void **a, ...);
+
+#ifdef LTM_DESC
+extern const ltc_math_descriptor ltm_desc;
+#endif
+
+#ifdef TFM_DESC
+extern const ltc_math_descriptor tfm_desc;
+#endif
+
+#ifdef GMP_DESC
+extern const ltc_math_descriptor gmp_desc;
+#endif
+
+#if !defined(DESC_DEF_ONLY) && defined(LTC_SOURCE)
+
+#define MP_DIGIT_BIT                 ltc_mp.bits_per_digit
+
+/* some handy macros */
+#define mp_init(a)                   ltc_mp.init(a)
+#define mp_init_multi                ltc_init_multi
+#define mp_clear(a)                  ltc_mp.deinit(a)
+#define mp_clear_multi               ltc_deinit_multi
+#define mp_cleanup_multi             ltc_cleanup_multi
+#define mp_init_copy(a, b)           ltc_mp.init_copy(a, b)
+
+#define mp_neg(a, b)                 ltc_mp.neg(a, b)
+#define mp_copy(a, b)                ltc_mp.copy(a, b)
+
+#define mp_set(a, b)                 ltc_mp.set_int(a, b)
+#define mp_set_int(a, b)             ltc_mp.set_int(a, b)
+#define mp_get_int(a)                ltc_mp.get_int(a)
+#define mp_get_digit(a, n)           ltc_mp.get_digit(a, n)
+#define mp_get_digit_count(a)        ltc_mp.get_digit_count(a)
+#define mp_cmp(a, b)                 ltc_mp.compare(a, b)
+#define mp_cmp_d(a, b)               ltc_mp.compare_d(a, b)
+#define mp_count_bits(a)             ltc_mp.count_bits(a)
+#define mp_cnt_lsb(a)                ltc_mp.count_lsb_bits(a)
+#define mp_2expt(a, b)               ltc_mp.twoexpt(a, b)
+
+#define mp_read_radix(a, b, c)       ltc_mp.read_radix(a, b, c)
+#define mp_toradix(a, b, c)          ltc_mp.write_radix(a, b, c)
+#define mp_unsigned_bin_size(a)      ltc_mp.unsigned_size(a)
+#define mp_to_unsigned_bin(a, b)     ltc_mp.unsigned_write(a, b)
+#define mp_read_unsigned_bin(a, b, c) ltc_mp.unsigned_read(a, b, c)
+
+#define mp_add(a, b, c)              ltc_mp.add(a, b, c)
+#define mp_add_d(a, b, c)            ltc_mp.addi(a, b, c)
+#define mp_sub(a, b, c)              ltc_mp.sub(a, b, c)
+#define mp_sub_d(a, b, c)            ltc_mp.subi(a, b, c)
+#define mp_mul(a, b, c)              ltc_mp.mul(a, b, c)
+#define mp_mul_d(a, b, c)            ltc_mp.muli(a, b, c)
+#define mp_sqr(a, b)                 ltc_mp.sqr(a, b)
+#define mp_div(a, b, c, d)           ltc_mp.mpdiv(a, b, c, d)
+#define mp_div_2(a, b)               ltc_mp.div_2(a, b)
+#define mp_mod(a, b, c)              ltc_mp.mpdiv(a, b, NULL, c)
+#define mp_mod_d(a, b, c)            ltc_mp.modi(a, b, c)
+#define mp_gcd(a, b, c)              ltc_mp.gcd(a, b, c)
+#define mp_lcm(a, b, c)              ltc_mp.lcm(a, b, c)
+
+#define mp_addmod(a, b, c, d)        ltc_mp.addmod(a, b, c, d)
+#define mp_submod(a, b, c, d)        ltc_mp.submod(a, b, c, d)
+#define mp_mulmod(a, b, c, d)        ltc_mp.mulmod(a, b, c, d)
+#define mp_sqrmod(a, b, c)           ltc_mp.sqrmod(a, b, c)
+#define mp_invmod(a, b, c)           ltc_mp.invmod(a, b, c)
+
+#define mp_montgomery_setup(a, b)    ltc_mp.montgomery_setup(a, b)
+#define mp_montgomery_normalization(a, b) ltc_mp.montgomery_normalization(a, b)
+#define mp_montgomery_reduce(a, b, c)   ltc_mp.montgomery_reduce(a, b, c)
+#define mp_montgomery_free(a)        ltc_mp.montgomery_deinit(a)
+
+#define mp_exptmod(a,b,c,d)          ltc_mp.exptmod(a,b,c,d)
+#define mp_prime_is_prime(a, b, c)   ltc_mp.isprime(a, b, c)
+
+#define mp_iszero(a)                 (mp_cmp_d(a, 0) == LTC_MP_EQ ? LTC_MP_YES : LTC_MP_NO)
+#define mp_isodd(a)                  (mp_get_digit_count(a) > 0 ? (mp_get_digit(a, 0) & 1 ? LTC_MP_YES : LTC_MP_NO) : LTC_MP_NO)
+#define mp_exch(a, b)                do { void *ABC__tmp = a; a = b; b = ABC__tmp; } while(0)
+
+#define mp_tohex(a, b)               mp_toradix(a, b, 16)
+
+#define mp_rand(a, b)                ltc_mp.rand(a, b)
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/headers/tomcrypt_misc.h b/libtomcrypt/src/headers/tomcrypt_misc.h
new file mode 100644 (file)
index 0000000..f21f30b
--- /dev/null
@@ -0,0 +1,113 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+/* ---- LTC_BASE64 Routines ---- */
+#ifdef LTC_BASE64
+int base64_encode(const unsigned char *in,  unsigned long len,
+                        unsigned char *out, unsigned long *outlen);
+
+int base64_decode(const unsigned char *in,  unsigned long len,
+                        unsigned char *out, unsigned long *outlen);
+int base64_strict_decode(const unsigned char *in,  unsigned long len,
+                        unsigned char *out, unsigned long *outlen);
+#endif
+
+#ifdef LTC_BASE64_URL
+int base64url_encode(const unsigned char *in,  unsigned long len,
+                        unsigned char *out, unsigned long *outlen);
+int base64url_strict_encode(const unsigned char *in,  unsigned long inlen,
+                        unsigned char *out, unsigned long *outlen);
+
+int base64url_decode(const unsigned char *in,  unsigned long len,
+                        unsigned char *out, unsigned long *outlen);
+int base64url_strict_decode(const unsigned char *in,  unsigned long len,
+                        unsigned char *out, unsigned long *outlen);
+#endif
+
+/* ===> LTC_HKDF -- RFC5869 HMAC-based Key Derivation Function <=== */
+#ifdef LTC_HKDF
+
+int hkdf_test(void);
+
+int hkdf_extract(int hash_idx,
+                 const unsigned char *salt, unsigned long saltlen,
+                 const unsigned char *in,   unsigned long inlen,
+                       unsigned char *out,  unsigned long *outlen);
+
+int hkdf_expand(int hash_idx,
+                const unsigned char *info, unsigned long infolen,
+                const unsigned char *in,   unsigned long inlen,
+                      unsigned char *out,  unsigned long outlen);
+
+int hkdf(int hash_idx,
+         const unsigned char *salt, unsigned long saltlen,
+         const unsigned char *info, unsigned long infolen,
+         const unsigned char *in,   unsigned long inlen,
+               unsigned char *out,  unsigned long outlen);
+
+#endif  /* LTC_HKDF */
+
+/* ---- MEM routines ---- */
+int mem_neq(const void *a, const void *b, size_t len);
+void zeromem(volatile void *dst, size_t len);
+void burn_stack(unsigned long len);
+
+const char *error_to_string(int err);
+
+extern const char *crypt_build_settings;
+
+/* ---- HMM ---- */
+int crypt_fsa(void *mp, ...);
+
+/* ---- Dynamic language support ---- */
+int crypt_get_constant(const char* namein, int *valueout);
+int crypt_list_all_constants(char *names_list, unsigned int *names_list_size);
+
+int crypt_get_size(const char* namein, unsigned int *sizeout);
+int crypt_list_all_sizes(char *names_list, unsigned int *names_list_size);
+
+#ifdef LTM_DESC
+void init_LTM(void);
+#endif
+#ifdef TFM_DESC
+void init_TFM(void);
+#endif
+#ifdef GMP_DESC
+void init_GMP(void);
+#endif
+
+#ifdef LTC_ADLER32
+typedef struct adler32_state_s
+{
+   unsigned short s[2];
+} adler32_state;
+
+void adler32_init(adler32_state *ctx);
+void adler32_update(adler32_state *ctx, const unsigned char *input, unsigned long length);
+void adler32_finish(adler32_state *ctx, void *hash, unsigned long size);
+int adler32_test(void);
+#endif
+
+#ifdef LTC_CRC32
+typedef struct crc32_state_s
+{
+   ulong32 crc;
+} crc32_state;
+
+void crc32_init(crc32_state *ctx);
+void crc32_update(crc32_state *ctx, const unsigned char *input, unsigned long length);
+void crc32_finish(crc32_state *ctx, void *hash, unsigned long size);
+int crc32_test(void);
+#endif
+
+int compare_testvector(const void* is, const unsigned long is_len, const void* should, const unsigned long should_len, const char* what, int which);
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/headers/tomcrypt_pk.h b/libtomcrypt/src/headers/tomcrypt_pk.h
new file mode 100644 (file)
index 0000000..fb9b07c
--- /dev/null
@@ -0,0 +1,747 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+/* ---- NUMBER THEORY ---- */
+
+enum {
+   PK_PUBLIC=0,
+   PK_PRIVATE=1
+};
+
+/* Indicates standard output formats that can be read e.g. by OpenSSL or GnuTLS */
+#define PK_STD          0x1000
+
+int rand_prime(void *N, long len, prng_state *prng, int wprng);
+
+#ifdef LTC_SOURCE
+/* internal helper functions */
+int rand_bn_bits(void *N, int bits, prng_state *prng, int wprng);
+int rand_bn_upto(void *N, void *limit, prng_state *prng, int wprng);
+
+enum public_key_algorithms {
+   PKA_RSA,
+   PKA_DSA
+};
+
+typedef struct Oid {
+    unsigned long OID[16];
+    /** Number of OID digits in use */
+    unsigned long OIDlen;
+} oid_st;
+
+int pk_get_oid(int pk, oid_st *st);
+#endif /* LTC_SOURCE */
+
+/* ---- RSA ---- */
+#ifdef LTC_MRSA
+
+/** RSA PKCS style key */
+typedef struct Rsa_key {
+    /** Type of key, PK_PRIVATE or PK_PUBLIC */
+    int type;
+    /** The public exponent */
+    void *e;
+    /** The private exponent */
+    void *d;
+    /** The modulus */
+    void *N;
+    /** The p factor of N */
+    void *p;
+    /** The q factor of N */
+    void *q;
+    /** The 1/q mod p CRT param */
+    void *qP;
+    /** The d mod (p - 1) CRT param */
+    void *dP;
+    /** The d mod (q - 1) CRT param */
+    void *dQ;
+} rsa_key;
+
+int rsa_make_key(prng_state *prng, int wprng, int size, long e, rsa_key *key);
+
+int rsa_get_size(rsa_key *key);
+
+int rsa_exptmod(const unsigned char *in,   unsigned long inlen,
+                      unsigned char *out,  unsigned long *outlen, int which,
+                      rsa_key *key);
+
+void rsa_free(rsa_key *key);
+
+/* These use PKCS #1 v2.0 padding */
+#define rsa_encrypt_key(_in, _inlen, _out, _outlen, _lparam, _lparamlen, _prng, _prng_idx, _hash_idx, _key) \
+  rsa_encrypt_key_ex(_in, _inlen, _out, _outlen, _lparam, _lparamlen, _prng, _prng_idx, _hash_idx, LTC_PKCS_1_OAEP, _key)
+
+#define rsa_decrypt_key(_in, _inlen, _out, _outlen, _lparam, _lparamlen, _hash_idx, _stat, _key) \
+  rsa_decrypt_key_ex(_in, _inlen, _out, _outlen, _lparam, _lparamlen, _hash_idx, LTC_PKCS_1_OAEP, _stat, _key)
+
+#define rsa_sign_hash(_in, _inlen, _out, _outlen, _prng, _prng_idx, _hash_idx, _saltlen, _key) \
+  rsa_sign_hash_ex(_in, _inlen, _out, _outlen, LTC_PKCS_1_PSS, _prng, _prng_idx, _hash_idx, _saltlen, _key)
+
+#define rsa_verify_hash(_sig, _siglen, _hash, _hashlen, _hash_idx, _saltlen, _stat, _key) \
+  rsa_verify_hash_ex(_sig, _siglen, _hash, _hashlen, LTC_PKCS_1_PSS, _hash_idx, _saltlen, _stat, _key)
+
+#define rsa_sign_saltlen_get_max(_hash_idx, _key) \
+  rsa_sign_saltlen_get_max_ex(LTC_PKCS_1_PSS, _hash_idx, _key)
+
+/* These can be switched between PKCS #1 v2.x and PKCS #1 v1.5 paddings */
+int rsa_encrypt_key_ex(const unsigned char *in,     unsigned long inlen,
+                             unsigned char *out,    unsigned long *outlen,
+                       const unsigned char *lparam, unsigned long lparamlen,
+                       prng_state *prng, int prng_idx, int hash_idx, int padding, rsa_key *key);
+
+int rsa_decrypt_key_ex(const unsigned char *in,       unsigned long  inlen,
+                             unsigned char *out,      unsigned long *outlen,
+                       const unsigned char *lparam,   unsigned long  lparamlen,
+                             int            hash_idx, int            padding,
+                             int           *stat,     rsa_key       *key);
+
+int rsa_sign_hash_ex(const unsigned char *in,       unsigned long  inlen,
+                           unsigned char *out,      unsigned long *outlen,
+                           int            padding,
+                           prng_state    *prng,     int            prng_idx,
+                           int            hash_idx, unsigned long  saltlen,
+                           rsa_key *key);
+
+int rsa_verify_hash_ex(const unsigned char *sig,      unsigned long siglen,
+                       const unsigned char *hash,     unsigned long hashlen,
+                             int            padding,
+                             int            hash_idx, unsigned long saltlen,
+                             int           *stat,     rsa_key      *key);
+
+int rsa_sign_saltlen_get_max_ex(int padding, int hash_idx, rsa_key *key);
+
+/* PKCS #1 import/export */
+int rsa_export(unsigned char *out, unsigned long *outlen, int type, rsa_key *key);
+int rsa_import(const unsigned char *in, unsigned long inlen, rsa_key *key);
+
+int rsa_import_x509(const unsigned char *in, unsigned long inlen, rsa_key *key);
+int rsa_import_pkcs8(const unsigned char *in, unsigned long inlen,
+                     const void *passwd, unsigned long passwdlen, rsa_key *key);
+
+int rsa_set_key(const unsigned char *N,  unsigned long Nlen,
+                const unsigned char *e,  unsigned long elen,
+                const unsigned char *d,  unsigned long dlen,
+                rsa_key *key);
+int rsa_set_factors(const unsigned char *p,  unsigned long plen,
+                    const unsigned char *q,  unsigned long qlen,
+                    rsa_key *key);
+int rsa_set_crt_params(const unsigned char *dP, unsigned long dPlen,
+                       const unsigned char *dQ, unsigned long dQlen,
+                       const unsigned char *qP, unsigned long qPlen,
+                       rsa_key *key);
+#endif
+
+/* ---- Katja ---- */
+#ifdef LTC_MKAT
+
+/* Min and Max KAT key sizes (in bits) */
+#define MIN_KAT_SIZE 1024
+#define MAX_KAT_SIZE 4096
+
+/** Katja PKCS style key */
+typedef struct KAT_key {
+    /** Type of key, PK_PRIVATE or PK_PUBLIC */
+    int type;
+    /** The private exponent */
+    void *d;
+    /** The modulus */
+    void *N;
+    /** The p factor of N */
+    void *p;
+    /** The q factor of N */
+    void *q;
+    /** The 1/q mod p CRT param */
+    void *qP;
+    /** The d mod (p - 1) CRT param */
+    void *dP;
+    /** The d mod (q - 1) CRT param */
+    void *dQ;
+    /** The pq param */
+    void *pq;
+} katja_key;
+
+int katja_make_key(prng_state *prng, int wprng, int size, katja_key *key);
+
+int katja_exptmod(const unsigned char *in,   unsigned long inlen,
+                        unsigned char *out,  unsigned long *outlen, int which,
+                        katja_key *key);
+
+void katja_free(katja_key *key);
+
+/* These use PKCS #1 v2.0 padding */
+int katja_encrypt_key(const unsigned char *in,     unsigned long inlen,
+                            unsigned char *out,    unsigned long *outlen,
+                      const unsigned char *lparam, unsigned long lparamlen,
+                      prng_state *prng, int prng_idx, int hash_idx, katja_key *key);
+
+int katja_decrypt_key(const unsigned char *in,       unsigned long inlen,
+                            unsigned char *out,      unsigned long *outlen,
+                      const unsigned char *lparam,   unsigned long lparamlen,
+                            int            hash_idx, int *stat,
+                            katja_key       *key);
+
+/* PKCS #1 import/export */
+int katja_export(unsigned char *out, unsigned long *outlen, int type, katja_key *key);
+int katja_import(const unsigned char *in, unsigned long inlen, katja_key *key);
+
+#endif
+
+/* ---- DH Routines ---- */
+#ifdef LTC_MDH
+
+typedef struct {
+    int type;
+    void *x;
+    void *y;
+    void *base;
+    void *prime;
+} dh_key;
+
+int dh_get_groupsize(dh_key *key);
+
+int dh_export(unsigned char *out, unsigned long *outlen, int type, dh_key *key);
+int dh_import(const unsigned char *in, unsigned long inlen, dh_key *key);
+
+int dh_set_pg(const unsigned char *p, unsigned long plen,
+              const unsigned char *g, unsigned long glen,
+              dh_key *key);
+int dh_set_pg_dhparam(const unsigned char *dhparam, unsigned long dhparamlen, dh_key *key);
+int dh_set_pg_groupsize(int groupsize, dh_key *key);
+
+int dh_set_key(const unsigned char *in, unsigned long inlen, int type, dh_key *key);
+int dh_generate_key(prng_state *prng, int wprng, dh_key *key);
+
+int dh_shared_secret(dh_key        *private_key, dh_key        *public_key,
+                     unsigned char *out,         unsigned long *outlen);
+
+void dh_free(dh_key *key);
+
+int dh_export_key(void *out, unsigned long *outlen, int type, dh_key *key);
+
+#ifdef LTC_SOURCE
+typedef struct {
+  int size;
+  const char *name, *base, *prime;
+} ltc_dh_set_type;
+
+extern const ltc_dh_set_type ltc_dh_sets[];
+
+/* internal helper functions */
+int dh_check_pubkey(dh_key *key);
+#endif
+
+#endif /* LTC_MDH */
+
+
+/* ---- ECC Routines ---- */
+#ifdef LTC_MECC
+
+/* size of our temp buffers for exported keys */
+#define ECC_BUF_SIZE 256
+
+/* max private key size */
+#define ECC_MAXSIZE  66
+
+/** Structure defines a NIST GF(p) curve */
+typedef struct {
+   /** The size of the curve in octets */
+   int size;
+
+   /** name of curve */
+   const char *name;
+
+   /** The prime that defines the field the curve is in (encoded in hex) */
+   const char *prime;
+
+   /** The fields B param (hex) */
+   const char *B;
+
+   /** The order of the curve (hex) */
+   const char *order;
+
+   /** The x co-ordinate of the base point on the curve (hex) */
+   const char *Gx;
+
+   /** The y co-ordinate of the base point on the curve (hex) */
+   const char *Gy;
+} ltc_ecc_set_type;
+
+/** A point on a ECC curve, stored in Jacbobian format such that (x,y,z) => (x/z^2, y/z^3, 1) when interpretted as affine */
+typedef struct {
+    /** The x co-ordinate */
+    void *x;
+
+    /** The y co-ordinate */
+    void *y;
+
+    /** The z co-ordinate */
+    void *z;
+} ecc_point;
+
+/** An ECC key */
+typedef struct {
+    /** Type of key, PK_PRIVATE or PK_PUBLIC */
+    int type;
+
+    /** Index into the ltc_ecc_sets[] for the parameters of this curve; if -1, then this key is using user supplied curve in dp */
+    int idx;
+
+    /** pointer to domain parameters; either points to NIST curves (identified by idx >= 0) or user supplied curve */
+    const ltc_ecc_set_type *dp;
+
+    /** The public key */
+    ecc_point pubkey;
+
+    /** The private key */
+    void *k;
+} ecc_key;
+
+/** the ECC params provided */
+extern const ltc_ecc_set_type ltc_ecc_sets[];
+
+int  ecc_test(void);
+void ecc_sizes(int *low, int *high);
+int  ecc_get_size(ecc_key *key);
+
+int  ecc_make_key(prng_state *prng, int wprng, int keysize, ecc_key *key);
+int  ecc_make_key_ex(prng_state *prng, int wprng, ecc_key *key, const ltc_ecc_set_type *dp);
+void ecc_free(ecc_key *key);
+
+int  ecc_export(unsigned char *out, unsigned long *outlen, int type, ecc_key *key);
+int  ecc_import(const unsigned char *in, unsigned long inlen, ecc_key *key);
+int  ecc_import_ex(const unsigned char *in, unsigned long inlen, ecc_key *key, const ltc_ecc_set_type *dp);
+
+int ecc_ansi_x963_export(ecc_key *key, unsigned char *out, unsigned long *outlen);
+int ecc_ansi_x963_import(const unsigned char *in, unsigned long inlen, ecc_key *key);
+int ecc_ansi_x963_import_ex(const unsigned char *in, unsigned long inlen, ecc_key *key, ltc_ecc_set_type *dp);
+
+int  ecc_shared_secret(ecc_key *private_key, ecc_key *public_key,
+                       unsigned char *out, unsigned long *outlen);
+
+int  ecc_encrypt_key(const unsigned char *in,   unsigned long inlen,
+                           unsigned char *out,  unsigned long *outlen,
+                           prng_state *prng, int wprng, int hash,
+                           ecc_key *key);
+
+int  ecc_decrypt_key(const unsigned char *in,  unsigned long  inlen,
+                           unsigned char *out, unsigned long *outlen,
+                           ecc_key *key);
+
+int ecc_sign_hash_rfc7518(const unsigned char *in,  unsigned long inlen,
+                                unsigned char *out, unsigned long *outlen,
+                                prng_state *prng, int wprng, ecc_key *key);
+
+int  ecc_sign_hash(const unsigned char *in,  unsigned long inlen,
+                         unsigned char *out, unsigned long *outlen,
+                         prng_state *prng, int wprng, ecc_key *key);
+
+int ecc_verify_hash_rfc7518(const unsigned char *sig,  unsigned long siglen,
+                            const unsigned char *hash, unsigned long hashlen,
+                            int *stat, ecc_key *key);
+
+int  ecc_verify_hash(const unsigned char *sig,  unsigned long siglen,
+                     const unsigned char *hash, unsigned long hashlen,
+                     int *stat, ecc_key *key);
+
+/* low level functions */
+ecc_point *ltc_ecc_new_point(void);
+void       ltc_ecc_del_point(ecc_point *p);
+int        ltc_ecc_is_valid_idx(int n);
+
+/* point ops (mp == montgomery digit) */
+#if !defined(LTC_MECC_ACCEL) || defined(LTM_DESC) || defined(GMP_DESC)
+/* R = 2P */
+int ltc_ecc_projective_dbl_point(ecc_point *P, ecc_point *R, void *modulus, void *mp);
+
+/* R = P + Q */
+int ltc_ecc_projective_add_point(ecc_point *P, ecc_point *Q, ecc_point *R, void *modulus, void *mp);
+#endif
+
+#if defined(LTC_MECC_FP)
+/* optimized point multiplication using fixed point cache (HAC algorithm 14.117) */
+int ltc_ecc_fp_mulmod(void *k, ecc_point *G, ecc_point *R, void *modulus, int map);
+
+/* functions for saving/loading/freeing/adding to fixed point cache */
+int ltc_ecc_fp_save_state(unsigned char **out, unsigned long *outlen);
+int ltc_ecc_fp_restore_state(unsigned char *in, unsigned long inlen);
+void ltc_ecc_fp_free(void);
+int ltc_ecc_fp_add_point(ecc_point *g, void *modulus, int lock);
+
+/* lock/unlock all points currently in fixed point cache */
+void ltc_ecc_fp_tablelock(int lock);
+#endif
+
+/* R = kG */
+int ltc_ecc_mulmod(void *k, ecc_point *G, ecc_point *R, void *modulus, int map);
+
+#ifdef LTC_ECC_SHAMIR
+/* kA*A + kB*B = C */
+int ltc_ecc_mul2add(ecc_point *A, void *kA,
+                    ecc_point *B, void *kB,
+                    ecc_point *C,
+                         void *modulus);
+
+#ifdef LTC_MECC_FP
+/* Shamir's trick with optimized point multiplication using fixed point cache */
+int ltc_ecc_fp_mul2add(ecc_point *A, void *kA,
+                       ecc_point *B, void *kB,
+                       ecc_point *C, void *modulus);
+#endif
+
+#endif
+
+
+/* map P to affine from projective */
+int ltc_ecc_map(ecc_point *P, void *modulus, void *mp);
+
+#endif
+
+#ifdef LTC_MDSA
+
+/* Max diff between group and modulus size in bytes */
+#define LTC_MDSA_DELTA     512
+
+/* Max DSA group size in bytes (default allows 4k-bit groups) */
+#define LTC_MDSA_MAX_GROUP 512
+
+/** DSA key structure */
+typedef struct {
+   /** The key type, PK_PRIVATE or PK_PUBLIC */
+   int type;
+
+   /** The order of the sub-group used in octets */
+   int qord;
+
+   /** The generator  */
+   void *g;
+
+   /** The prime used to generate the sub-group */
+   void *q;
+
+   /** The large prime that generats the field the contains the sub-group */
+   void *p;
+
+   /** The private key */
+   void *x;
+
+   /** The public key */
+   void *y;
+} dsa_key;
+
+int dsa_make_key(prng_state *prng, int wprng, int group_size, int modulus_size, dsa_key *key);
+
+int dsa_set_pqg(const unsigned char *p,  unsigned long plen,
+                const unsigned char *q,  unsigned long qlen,
+                const unsigned char *g,  unsigned long glen,
+                dsa_key *key);
+int dsa_set_pqg_dsaparam(const unsigned char *dsaparam, unsigned long dsaparamlen, dsa_key *key);
+int dsa_generate_pqg(prng_state *prng, int wprng, int group_size, int modulus_size, dsa_key *key);
+
+int dsa_set_key(const unsigned char *in, unsigned long inlen, int type, dsa_key *key);
+int dsa_generate_key(prng_state *prng, int wprng, dsa_key *key);
+
+void dsa_free(dsa_key *key);
+
+int dsa_sign_hash_raw(const unsigned char *in,  unsigned long inlen,
+                                   void *r,   void *s,
+                               prng_state *prng, int wprng, dsa_key *key);
+
+int dsa_sign_hash(const unsigned char *in,  unsigned long inlen,
+                        unsigned char *out, unsigned long *outlen,
+                        prng_state *prng, int wprng, dsa_key *key);
+
+int dsa_verify_hash_raw(         void *r,          void *s,
+                    const unsigned char *hash, unsigned long hashlen,
+                                    int *stat,      dsa_key *key);
+
+int dsa_verify_hash(const unsigned char *sig,  unsigned long siglen,
+                    const unsigned char *hash, unsigned long hashlen,
+                          int           *stat, dsa_key       *key);
+
+int dsa_encrypt_key(const unsigned char *in,   unsigned long inlen,
+                          unsigned char *out,  unsigned long *outlen,
+                          prng_state *prng, int wprng, int hash,
+                          dsa_key *key);
+
+int dsa_decrypt_key(const unsigned char *in,  unsigned long  inlen,
+                          unsigned char *out, unsigned long *outlen,
+                          dsa_key *key);
+
+int dsa_import(const unsigned char *in, unsigned long inlen, dsa_key *key);
+int dsa_export(unsigned char *out, unsigned long *outlen, int type, dsa_key *key);
+int dsa_verify_key(dsa_key *key, int *stat);
+#ifdef LTC_SOURCE
+/* internal helper functions */
+int dsa_int_validate_xy(dsa_key *key, int *stat);
+int dsa_int_validate_pqg(dsa_key *key, int *stat);
+int dsa_int_validate_primes(dsa_key *key, int *stat);
+#endif
+int dsa_shared_secret(void          *private_key, void *base,
+                      dsa_key       *public_key,
+                      unsigned char *out,         unsigned long *outlen);
+#endif
+
+#ifdef LTC_DER
+/* DER handling */
+
+typedef enum ltc_asn1_type_ {
+ /*  0 */
+ LTC_ASN1_EOL,
+ LTC_ASN1_BOOLEAN,
+ LTC_ASN1_INTEGER,
+ LTC_ASN1_SHORT_INTEGER,
+ LTC_ASN1_BIT_STRING,
+ /*  5 */
+ LTC_ASN1_OCTET_STRING,
+ LTC_ASN1_NULL,
+ LTC_ASN1_OBJECT_IDENTIFIER,
+ LTC_ASN1_IA5_STRING,
+ LTC_ASN1_PRINTABLE_STRING,
+ /* 10 */
+ LTC_ASN1_UTF8_STRING,
+ LTC_ASN1_UTCTIME,
+ LTC_ASN1_CHOICE,
+ LTC_ASN1_SEQUENCE,
+ LTC_ASN1_SET,
+ /* 15 */
+ LTC_ASN1_SETOF,
+ LTC_ASN1_RAW_BIT_STRING,
+ LTC_ASN1_TELETEX_STRING,
+ LTC_ASN1_CONSTRUCTED,
+ LTC_ASN1_CONTEXT_SPECIFIC,
+ /* 20 */
+ LTC_ASN1_GENERALIZEDTIME,
+} ltc_asn1_type;
+
+/** A LTC ASN.1 list type */
+typedef struct ltc_asn1_list_ {
+   /** The LTC ASN.1 enumerated type identifier */
+   ltc_asn1_type type;
+   /** The data to encode or place for decoding */
+   void         *data;
+   /** The size of the input or resulting output */
+   unsigned long size;
+   /** The used flag, this is used by the CHOICE ASN.1 type to indicate which choice was made */
+   int           used;
+   /** prev/next entry in the list */
+   struct ltc_asn1_list_ *prev, *next, *child, *parent;
+} ltc_asn1_list;
+
+#define LTC_SET_ASN1(list, index, Type, Data, Size)  \
+   do {                                              \
+      int LTC_MACRO_temp            = (index);       \
+      ltc_asn1_list *LTC_MACRO_list = (list);        \
+      LTC_MACRO_list[LTC_MACRO_temp].type = (Type);  \
+      LTC_MACRO_list[LTC_MACRO_temp].data = (void*)(Data);  \
+      LTC_MACRO_list[LTC_MACRO_temp].size = (Size);  \
+      LTC_MACRO_list[LTC_MACRO_temp].used = 0;       \
+   } while (0)
+
+/* SEQUENCE */
+int der_encode_sequence_ex(ltc_asn1_list *list, unsigned long inlen,
+                           unsigned char *out,  unsigned long *outlen, int type_of);
+
+#define der_encode_sequence(list, inlen, out, outlen) der_encode_sequence_ex(list, inlen, out, outlen, LTC_ASN1_SEQUENCE)
+
+int der_decode_sequence_ex(const unsigned char *in, unsigned long  inlen,
+                           ltc_asn1_list *list,     unsigned long  outlen, int ordered);
+
+#define der_decode_sequence(in, inlen, list, outlen) der_decode_sequence_ex(in, inlen, list, outlen, 1)
+
+int der_length_sequence(ltc_asn1_list *list, unsigned long inlen,
+                        unsigned long *outlen);
+
+
+#ifdef LTC_SOURCE
+/* internal helper functions */
+int der_length_sequence_ex(ltc_asn1_list *list, unsigned long inlen,
+                           unsigned long *outlen, unsigned long *payloadlen);
+/* SUBJECT PUBLIC KEY INFO */
+int der_encode_subject_public_key_info(unsigned char *out, unsigned long *outlen,
+        unsigned int algorithm, void* public_key, unsigned long public_key_len,
+        unsigned long parameters_type, void* parameters, unsigned long parameters_len);
+
+int der_decode_subject_public_key_info(const unsigned char *in, unsigned long inlen,
+        unsigned int algorithm, void* public_key, unsigned long* public_key_len,
+        unsigned long parameters_type, ltc_asn1_list* parameters, unsigned long parameters_len);
+#endif /* LTC_SOURCE */
+
+/* SET */
+#define der_decode_set(in, inlen, list, outlen) der_decode_sequence_ex(in, inlen, list, outlen, 0)
+#define der_length_set der_length_sequence
+int der_encode_set(ltc_asn1_list *list, unsigned long inlen,
+                   unsigned char *out,  unsigned long *outlen);
+
+int der_encode_setof(ltc_asn1_list *list, unsigned long inlen,
+                     unsigned char *out,  unsigned long *outlen);
+
+/* VA list handy helpers with triplets of <type, size, data> */
+int der_encode_sequence_multi(unsigned char *out, unsigned long *outlen, ...);
+int der_decode_sequence_multi(const unsigned char *in, unsigned long inlen, ...);
+
+/* FLEXI DECODER handle unknown list decoder */
+int  der_decode_sequence_flexi(const unsigned char *in, unsigned long *inlen, ltc_asn1_list **out);
+#define der_free_sequence_flexi         der_sequence_free
+void der_sequence_free(ltc_asn1_list *in);
+void der_sequence_shrink(ltc_asn1_list *in);
+
+/* BOOLEAN */
+int der_length_boolean(unsigned long *outlen);
+int der_encode_boolean(int in,
+                       unsigned char *out, unsigned long *outlen);
+int der_decode_boolean(const unsigned char *in, unsigned long inlen,
+                                       int *out);
+/* INTEGER */
+int der_encode_integer(void *num, unsigned char *out, unsigned long *outlen);
+int der_decode_integer(const unsigned char *in, unsigned long inlen, void *num);
+int der_length_integer(void *num, unsigned long *len);
+
+/* INTEGER -- handy for 0..2^32-1 values */
+int der_decode_short_integer(const unsigned char *in, unsigned long inlen, unsigned long *num);
+int der_encode_short_integer(unsigned long num, unsigned char *out, unsigned long *outlen);
+int der_length_short_integer(unsigned long num, unsigned long *outlen);
+
+/* BIT STRING */
+int der_encode_bit_string(const unsigned char *in, unsigned long inlen,
+                                unsigned char *out, unsigned long *outlen);
+int der_decode_bit_string(const unsigned char *in, unsigned long inlen,
+                                unsigned char *out, unsigned long *outlen);
+int der_encode_raw_bit_string(const unsigned char *in, unsigned long inlen,
+                                unsigned char *out, unsigned long *outlen);
+int der_decode_raw_bit_string(const unsigned char *in, unsigned long inlen,
+                                unsigned char *out, unsigned long *outlen);
+int der_length_bit_string(unsigned long nbits, unsigned long *outlen);
+
+/* OCTET STRING */
+int der_encode_octet_string(const unsigned char *in, unsigned long inlen,
+                                  unsigned char *out, unsigned long *outlen);
+int der_decode_octet_string(const unsigned char *in, unsigned long inlen,
+                                  unsigned char *out, unsigned long *outlen);
+int der_length_octet_string(unsigned long noctets, unsigned long *outlen);
+
+/* OBJECT IDENTIFIER */
+int der_encode_object_identifier(unsigned long *words, unsigned long  nwords,
+                                 unsigned char *out,   unsigned long *outlen);
+int der_decode_object_identifier(const unsigned char *in,    unsigned long  inlen,
+                                       unsigned long *words, unsigned long *outlen);
+int der_length_object_identifier(unsigned long *words, unsigned long nwords, unsigned long *outlen);
+unsigned long der_object_identifier_bits(unsigned long x);
+
+/* IA5 STRING */
+int der_encode_ia5_string(const unsigned char *in, unsigned long inlen,
+                                unsigned char *out, unsigned long *outlen);
+int der_decode_ia5_string(const unsigned char *in, unsigned long inlen,
+                                unsigned char *out, unsigned long *outlen);
+int der_length_ia5_string(const unsigned char *octets, unsigned long noctets, unsigned long *outlen);
+
+int der_ia5_char_encode(int c);
+int der_ia5_value_decode(int v);
+
+/* TELETEX STRING */
+int der_decode_teletex_string(const unsigned char *in, unsigned long inlen,
+                                unsigned char *out, unsigned long *outlen);
+int der_length_teletex_string(const unsigned char *octets, unsigned long noctets, unsigned long *outlen);
+
+#ifdef LTC_SOURCE
+/* internal helper functions */
+int der_teletex_char_encode(int c);
+int der_teletex_value_decode(int v);
+#endif /* LTC_SOURCE */
+
+
+/* PRINTABLE STRING */
+int der_encode_printable_string(const unsigned char *in, unsigned long inlen,
+                                unsigned char *out, unsigned long *outlen);
+int der_decode_printable_string(const unsigned char *in, unsigned long inlen,
+                                unsigned char *out, unsigned long *outlen);
+int der_length_printable_string(const unsigned char *octets, unsigned long noctets, unsigned long *outlen);
+
+int der_printable_char_encode(int c);
+int der_printable_value_decode(int v);
+
+/* UTF-8 */
+#if (defined(SIZE_MAX) || __STDC_VERSION__ >= 199901L || defined(WCHAR_MAX) || defined(__WCHAR_MAX__) || defined(_WCHAR_T) || defined(_WCHAR_T_DEFINED) || defined (__WCHAR_TYPE__)) && !defined(LTC_NO_WCHAR)
+   #if defined(__WCHAR_MAX__)
+      #define LTC_WCHAR_MAX __WCHAR_MAX__
+   #else
+      #include <wchar.h>
+      #define LTC_WCHAR_MAX WCHAR_MAX
+   #endif
+/* please note that it might happen that LTC_WCHAR_MAX is undefined */
+#else
+   typedef ulong32 wchar_t;
+   #define LTC_WCHAR_MAX 0xFFFFFFFF
+#endif
+
+int der_encode_utf8_string(const wchar_t *in,  unsigned long inlen,
+                           unsigned char *out, unsigned long *outlen);
+
+int der_decode_utf8_string(const unsigned char *in,  unsigned long inlen,
+                                       wchar_t *out, unsigned long *outlen);
+unsigned long der_utf8_charsize(const wchar_t c);
+#ifdef LTC_SOURCE
+/* internal helper functions */
+int der_utf8_valid_char(const wchar_t c);
+#endif /* LTC_SOURCE */
+int der_length_utf8_string(const wchar_t *in, unsigned long noctets, unsigned long *outlen);
+
+
+/* CHOICE */
+int der_decode_choice(const unsigned char *in,   unsigned long *inlen,
+                            ltc_asn1_list *list, unsigned long  outlen);
+
+/* UTCTime */
+typedef struct {
+   unsigned YY, /* year */
+            MM, /* month */
+            DD, /* day */
+            hh, /* hour */
+            mm, /* minute */
+            ss, /* second */
+            off_dir, /* timezone offset direction 0 == +, 1 == - */
+            off_hh, /* timezone offset hours */
+            off_mm; /* timezone offset minutes */
+} ltc_utctime;
+
+int der_encode_utctime(ltc_utctime *utctime,
+                       unsigned char *out,   unsigned long *outlen);
+
+int der_decode_utctime(const unsigned char *in, unsigned long *inlen,
+                             ltc_utctime   *out);
+
+int der_length_utctime(ltc_utctime *utctime, unsigned long *outlen);
+
+/* GeneralizedTime */
+typedef struct {
+   unsigned YYYY, /* year */
+            MM, /* month */
+            DD, /* day */
+            hh, /* hour */
+            mm, /* minute */
+            ss, /* second */
+            fs, /* fractional seconds */
+            off_dir, /* timezone offset direction 0 == +, 1 == - */
+            off_hh, /* timezone offset hours */
+            off_mm; /* timezone offset minutes */
+} ltc_generalizedtime;
+
+int der_encode_generalizedtime(ltc_generalizedtime *gtime,
+                               unsigned char       *out, unsigned long *outlen);
+
+int der_decode_generalizedtime(const unsigned char *in, unsigned long *inlen,
+                               ltc_generalizedtime *out);
+
+int der_length_generalizedtime(ltc_generalizedtime *gtime, unsigned long *outlen);
+
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/headers/tomcrypt_pkcs.h b/libtomcrypt/src/headers/tomcrypt_pkcs.h
new file mode 100644 (file)
index 0000000..247e538
--- /dev/null
@@ -0,0 +1,108 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+/* PKCS Header Info */
+
+/* ===> PKCS #1 -- RSA Cryptography <=== */
+#ifdef LTC_PKCS_1
+
+enum ltc_pkcs_1_v1_5_blocks
+{
+  LTC_PKCS_1_EMSA   = 1,        /* Block type 1 (PKCS #1 v1.5 signature padding) */
+  LTC_PKCS_1_EME    = 2         /* Block type 2 (PKCS #1 v1.5 encryption padding) */
+};
+
+enum ltc_pkcs_1_paddings
+{
+  LTC_PKCS_1_V1_5     = 1,        /* PKCS #1 v1.5 padding (\sa ltc_pkcs_1_v1_5_blocks) */
+  LTC_PKCS_1_OAEP     = 2,        /* PKCS #1 v2.0 encryption padding */
+  LTC_PKCS_1_PSS      = 3,        /* PKCS #1 v2.1 signature padding */
+  LTC_PKCS_1_V1_5_NA1 = 4         /* PKCS #1 v1.5 padding - No ASN.1 (\sa ltc_pkcs_1_v1_5_blocks) */
+};
+
+int pkcs_1_mgf1(      int            hash_idx,
+                const unsigned char *seed, unsigned long seedlen,
+                      unsigned char *mask, unsigned long masklen);
+
+int pkcs_1_i2osp(void *n, unsigned long modulus_len, unsigned char *out);
+int pkcs_1_os2ip(void *n, unsigned char *in, unsigned long inlen);
+
+/* *** v1.5 padding */
+int pkcs_1_v1_5_encode(const unsigned char *msg,
+                             unsigned long  msglen,
+                             int            block_type,
+                             unsigned long  modulus_bitlen,
+                                prng_state *prng,
+                                       int  prng_idx,
+                             unsigned char *out,
+                             unsigned long *outlen);
+
+int pkcs_1_v1_5_decode(const unsigned char *msg,
+                             unsigned long  msglen,
+                                       int  block_type,
+                             unsigned long  modulus_bitlen,
+                             unsigned char *out,
+                             unsigned long *outlen,
+                                       int *is_valid);
+
+/* *** v2.1 padding */
+int pkcs_1_oaep_encode(const unsigned char *msg,    unsigned long msglen,
+                       const unsigned char *lparam, unsigned long lparamlen,
+                             unsigned long modulus_bitlen, prng_state *prng,
+                             int           prng_idx,         int  hash_idx,
+                             unsigned char *out,    unsigned long *outlen);
+
+int pkcs_1_oaep_decode(const unsigned char *msg,    unsigned long msglen,
+                       const unsigned char *lparam, unsigned long lparamlen,
+                             unsigned long modulus_bitlen, int hash_idx,
+                             unsigned char *out,    unsigned long *outlen,
+                             int           *res);
+
+int pkcs_1_pss_encode(const unsigned char *msghash, unsigned long msghashlen,
+                            unsigned long saltlen,  prng_state   *prng,
+                            int           prng_idx, int           hash_idx,
+                            unsigned long modulus_bitlen,
+                            unsigned char *out,     unsigned long *outlen);
+
+int pkcs_1_pss_decode(const unsigned char *msghash, unsigned long msghashlen,
+                      const unsigned char *sig,     unsigned long siglen,
+                            unsigned long saltlen,  int           hash_idx,
+                            unsigned long modulus_bitlen, int    *res);
+
+#endif /* LTC_PKCS_1 */
+
+/* ===> PKCS #5 -- Password Based Cryptography <=== */
+#ifdef LTC_PKCS_5
+
+/* Algorithm #1 (PBKDF1) */
+int pkcs_5_alg1(const unsigned char *password, unsigned long password_len,
+                const unsigned char *salt,
+                int iteration_count,  int hash_idx,
+                unsigned char *out,   unsigned long *outlen);
+
+/* Algorithm #1 (PBKDF1) - OpenSSL-compatible variant for arbitrarily-long keys.
+   Compatible with EVP_BytesToKey() */
+int pkcs_5_alg1_openssl(const unsigned char *password,
+                        unsigned long password_len,
+                        const unsigned char *salt,
+                        int iteration_count,  int hash_idx,
+                        unsigned char *out,   unsigned long *outlen);
+
+/* Algorithm #2 (PBKDF2) */
+int pkcs_5_alg2(const unsigned char *password, unsigned long password_len,
+                const unsigned char *salt,     unsigned long salt_len,
+                int iteration_count,           int hash_idx,
+                unsigned char *out,            unsigned long *outlen);
+
+int pkcs_5_test (void);
+#endif  /* LTC_PKCS_5 */
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/headers/tomcrypt_prng.h b/libtomcrypt/src/headers/tomcrypt_prng.h
new file mode 100644 (file)
index 0000000..c516b8c
--- /dev/null
@@ -0,0 +1,232 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+/* ---- PRNG Stuff ---- */
+#ifdef LTC_YARROW
+struct yarrow_prng {
+    int                   cipher, hash;
+    unsigned char         pool[MAXBLOCKSIZE];
+    symmetric_CTR         ctr;
+};
+#endif
+
+#ifdef LTC_RC4
+struct rc4_prng {
+    rc4_state s;
+};
+#endif
+
+#ifdef LTC_CHACHA20_PRNG
+struct chacha20_prng {
+    chacha_state s;        /* chacha state */
+    unsigned char ent[40]; /* entropy buffer */
+    unsigned long idx;     /* entropy counter */
+};
+#endif
+
+#ifdef LTC_FORTUNA
+struct fortuna_prng {
+    hash_state pool[LTC_FORTUNA_POOLS];     /* the  pools */
+
+    symmetric_key skey;
+
+    unsigned char K[32],      /* the current key */
+                  IV[16];     /* IV for CTR mode */
+
+    unsigned long pool_idx,   /* current pool we will add to */
+                  pool0_len,  /* length of 0'th pool */
+                  wd;
+
+    ulong64       reset_cnt;  /* number of times we have reset */
+};
+#endif
+
+#ifdef LTC_SOBER128
+struct sober128_prng {
+    sober128_state s;      /* sober128 state */
+    unsigned char ent[40]; /* entropy buffer */
+    unsigned long idx;     /* entropy counter */
+};
+#endif
+
+typedef struct {
+   union {
+      char dummy[1];
+#ifdef LTC_YARROW
+      struct yarrow_prng    yarrow;
+#endif
+#ifdef LTC_RC4
+      struct rc4_prng       rc4;
+#endif
+#ifdef LTC_CHACHA20_PRNG
+      struct chacha20_prng  chacha;
+#endif
+#ifdef LTC_FORTUNA
+      struct fortuna_prng   fortuna;
+#endif
+#ifdef LTC_SOBER128
+      struct sober128_prng  sober128;
+#endif
+   };
+   short ready;            /* ready flag 0-1 */
+   LTC_MUTEX_TYPE(lock)    /* lock */
+} prng_state;
+
+/** PRNG descriptor */
+extern struct ltc_prng_descriptor {
+    /** Name of the PRNG */
+    const char *name;
+    /** size in bytes of exported state */
+    int  export_size;
+    /** Start a PRNG state
+        @param prng   [out] The state to initialize
+        @return CRYPT_OK if successful
+    */
+    int (*start)(prng_state *prng);
+    /** Add entropy to the PRNG
+        @param in         The entropy
+        @param inlen      Length of the entropy (octets)\
+        @param prng       The PRNG state
+        @return CRYPT_OK if successful
+    */
+    int (*add_entropy)(const unsigned char *in, unsigned long inlen, prng_state *prng);
+    /** Ready a PRNG state to read from
+        @param prng       The PRNG state to ready
+        @return CRYPT_OK if successful
+    */
+    int (*ready)(prng_state *prng);
+    /** Read from the PRNG
+        @param out     [out] Where to store the data
+        @param outlen  Length of data desired (octets)
+        @param prng    The PRNG state to read from
+        @return Number of octets read
+    */
+    unsigned long (*read)(unsigned char *out, unsigned long outlen, prng_state *prng);
+    /** Terminate a PRNG state
+        @param prng   The PRNG state to terminate
+        @return CRYPT_OK if successful
+    */
+    int (*done)(prng_state *prng);
+    /** Export a PRNG state
+        @param out     [out] The destination for the state
+        @param outlen  [in/out] The max size and resulting size of the PRNG state
+        @param prng    The PRNG to export
+        @return CRYPT_OK if successful
+    */
+    int (*pexport)(unsigned char *out, unsigned long *outlen, prng_state *prng);
+    /** Import a PRNG state
+        @param in      The data to import
+        @param inlen   The length of the data to import (octets)
+        @param prng    The PRNG to initialize/import
+        @return CRYPT_OK if successful
+    */
+    int (*pimport)(const unsigned char *in, unsigned long inlen, prng_state *prng);
+    /** Self-test the PRNG
+        @return CRYPT_OK if successful, CRYPT_NOP if self-testing has been disabled
+    */
+    int (*test)(void);
+} prng_descriptor[];
+
+#ifdef LTC_YARROW
+int yarrow_start(prng_state *prng);
+int yarrow_add_entropy(const unsigned char *in, unsigned long inlen, prng_state *prng);
+int yarrow_ready(prng_state *prng);
+unsigned long yarrow_read(unsigned char *out, unsigned long outlen, prng_state *prng);
+int yarrow_done(prng_state *prng);
+int  yarrow_export(unsigned char *out, unsigned long *outlen, prng_state *prng);
+int  yarrow_import(const unsigned char *in, unsigned long inlen, prng_state *prng);
+int  yarrow_test(void);
+extern const struct ltc_prng_descriptor yarrow_desc;
+#endif
+
+#ifdef LTC_FORTUNA
+int fortuna_start(prng_state *prng);
+int fortuna_add_entropy(const unsigned char *in, unsigned long inlen, prng_state *prng);
+int fortuna_ready(prng_state *prng);
+unsigned long fortuna_read(unsigned char *out, unsigned long outlen, prng_state *prng);
+int fortuna_done(prng_state *prng);
+int  fortuna_export(unsigned char *out, unsigned long *outlen, prng_state *prng);
+int  fortuna_import(const unsigned char *in, unsigned long inlen, prng_state *prng);
+int  fortuna_test(void);
+extern const struct ltc_prng_descriptor fortuna_desc;
+#endif
+
+#ifdef LTC_RC4
+int rc4_start(prng_state *prng);
+int rc4_add_entropy(const unsigned char *in, unsigned long inlen, prng_state *prng);
+int rc4_ready(prng_state *prng);
+unsigned long rc4_read(unsigned char *out, unsigned long outlen, prng_state *prng);
+int  rc4_done(prng_state *prng);
+int  rc4_export(unsigned char *out, unsigned long *outlen, prng_state *prng);
+int  rc4_import(const unsigned char *in, unsigned long inlen, prng_state *prng);
+int  rc4_test(void);
+extern const struct ltc_prng_descriptor rc4_desc;
+#endif
+
+#ifdef LTC_CHACHA20_PRNG
+int chacha20_prng_start(prng_state *prng);
+int chacha20_prng_add_entropy(const unsigned char *in, unsigned long inlen, prng_state *prng);
+int chacha20_prng_ready(prng_state *prng);
+unsigned long chacha20_prng_read(unsigned char *out, unsigned long outlen, prng_state *prng);
+int  chacha20_prng_done(prng_state *prng);
+int  chacha20_prng_export(unsigned char *out, unsigned long *outlen, prng_state *prng);
+int  chacha20_prng_import(const unsigned char *in, unsigned long inlen, prng_state *prng);
+int  chacha20_prng_test(void);
+extern const struct ltc_prng_descriptor chacha20_prng_desc;
+#endif
+
+#ifdef LTC_SPRNG
+int sprng_start(prng_state *prng);
+int sprng_add_entropy(const unsigned char *in, unsigned long inlen, prng_state *prng);
+int sprng_ready(prng_state *prng);
+unsigned long sprng_read(unsigned char *out, unsigned long outlen, prng_state *prng);
+int sprng_done(prng_state *prng);
+int  sprng_export(unsigned char *out, unsigned long *outlen, prng_state *prng);
+int  sprng_import(const unsigned char *in, unsigned long inlen, prng_state *prng);
+int  sprng_test(void);
+extern const struct ltc_prng_descriptor sprng_desc;
+#endif
+
+#ifdef LTC_SOBER128
+int sober128_start(prng_state *prng);
+int sober128_add_entropy(const unsigned char *in, unsigned long inlen, prng_state *prng);
+int sober128_ready(prng_state *prng);
+unsigned long sober128_read(unsigned char *out, unsigned long outlen, prng_state *prng);
+int sober128_done(prng_state *prng);
+int  sober128_export(unsigned char *out, unsigned long *outlen, prng_state *prng);
+int  sober128_import(const unsigned char *in, unsigned long inlen, prng_state *prng);
+int  sober128_test(void);
+extern const struct ltc_prng_descriptor sober128_desc;
+#endif
+
+int find_prng(const char *name);
+int register_prng(const struct ltc_prng_descriptor *prng);
+int unregister_prng(const struct ltc_prng_descriptor *prng);
+int register_all_prngs(void);
+int prng_is_valid(int idx);
+LTC_MUTEX_PROTO(ltc_prng_mutex)
+
+/* Slow RNG you **might** be able to use to seed a PRNG with.  Be careful as this
+ * might not work on all platforms as planned
+ */
+unsigned long rng_get_bytes(unsigned char *out,
+                            unsigned long outlen,
+                            void (*callback)(void));
+
+int rng_make_prng(int bits, int wprng, prng_state *prng, void (*callback)(void));
+
+#ifdef LTC_PRNG_ENABLE_LTC_RNG
+extern unsigned long (*ltc_rng)(unsigned char *out, unsigned long outlen,
+      void (*callback)(void));
+#endif
+
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/mac/blake2/blake2bmac.c b/libtomcrypt/src/mac/blake2/blake2bmac.c
new file mode 100644 (file)
index 0000000..1c80b1c
--- /dev/null
@@ -0,0 +1,66 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+#include "tomcrypt.h"
+
+#ifdef LTC_BLAKE2BMAC
+
+/**
+   Initialize an BLAKE2B MAC context.
+   @param st       The BLAKE2B MAC state
+   @param outlen   The size of the MAC output (octets)
+   @param key      The secret key
+   @param keylen   The length of the secret key (octets)
+   @return CRYPT_OK if successful
+*/
+int blake2bmac_init(blake2bmac_state *st, unsigned long outlen, const unsigned char *key, unsigned long keylen)
+{
+   LTC_ARGCHK(st  != NULL);
+   LTC_ARGCHK(key != NULL);
+   return blake2b_init(st, outlen, key, keylen);
+}
+
+/**
+  Process data through BLAKE2B MAC
+  @param st      The BLAKE2B MAC state
+  @param in      The data to send through HMAC
+  @param inlen   The length of the data to HMAC (octets)
+  @return CRYPT_OK if successful
+*/
+int blake2bmac_process(blake2bmac_state *st, const unsigned char *in, unsigned long inlen)
+{
+   if (inlen == 0) return CRYPT_OK; /* nothing to do */
+   LTC_ARGCHK(st != NULL);
+   LTC_ARGCHK(in != NULL);
+   return blake2b_process(st, in, inlen);
+}
+
+/**
+   Terminate a BLAKE2B MAC session
+   @param st      The BLAKE2B MAC state
+   @param mac     [out] The destination of the BLAKE2B MAC authentication tag
+   @param maclen  [in/out]  The max size and resulting size of the BLAKE2B MAC authentication tag
+   @return CRYPT_OK if successful
+*/
+int blake2bmac_done(blake2bmac_state *st, unsigned char *mac, unsigned long *maclen)
+{
+   LTC_ARGCHK(st     != NULL);
+   LTC_ARGCHK(mac    != NULL);
+   LTC_ARGCHK(maclen != NULL);
+   LTC_ARGCHK(*maclen >= st->blake2b.outlen);
+
+   *maclen = st->blake2b.outlen;
+   return blake2b_done(st, mac);
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/mac/blake2/blake2bmac_file.c b/libtomcrypt/src/mac/blake2/blake2bmac_file.c
new file mode 100644 (file)
index 0000000..c1e9c6b
--- /dev/null
@@ -0,0 +1,88 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+#include "tomcrypt.h"
+
+#ifdef LTC_BLAKE2BMAC
+
+/**
+  BLAKE2B MAC a file
+  @param fname    The name of the file you wish to BLAKE2B MAC
+  @param key      The secret key
+  @param keylen   The length of the secret key
+  @param mac      [out] The BLAKE2B MAC authentication tag
+  @param maclen   [in/out]  The max size and resulting size of the authentication tag
+  @return CRYPT_OK if successful, CRYPT_NOP if file support has been disabled
+*/
+int blake2bmac_file(const char *fname, const unsigned char *key, unsigned long keylen, unsigned char *mac, unsigned long *maclen)
+{
+#ifdef LTC_NO_FILE
+   LTC_UNUSED_PARAM(fname);
+   LTC_UNUSED_PARAM(key);
+   LTC_UNUSED_PARAM(keylen);
+   LTC_UNUSED_PARAM(mac);
+   LTC_UNUSED_PARAM(maclen);
+   return CRYPT_NOP;
+#else
+   blake2bmac_state st;
+   FILE *in;
+   unsigned char *buf;
+   size_t x;
+   int err;
+
+   LTC_ARGCHK(fname  != NULL);
+   LTC_ARGCHK(key    != NULL);
+   LTC_ARGCHK(mac    != NULL);
+   LTC_ARGCHK(maclen != NULL);
+
+   if ((buf = XMALLOC(LTC_FILE_READ_BUFSIZE)) == NULL) {
+      return CRYPT_MEM;
+   }
+
+   if ((err = blake2bmac_init(&st, *maclen, key, keylen)) != CRYPT_OK) {
+      goto LBL_ERR;
+   }
+
+   in = fopen(fname, "rb");
+   if (in == NULL) {
+      err = CRYPT_FILE_NOTFOUND;
+      goto LBL_ERR;
+   }
+
+   do {
+      x = fread(buf, 1, LTC_FILE_READ_BUFSIZE, in);
+      if ((err = blake2bmac_process(&st, buf, (unsigned long)x)) != CRYPT_OK) {
+         fclose(in);
+         goto LBL_CLEANBUF;
+      }
+   } while (x == LTC_FILE_READ_BUFSIZE);
+
+   if (fclose(in) != 0) {
+      err = CRYPT_ERROR;
+      goto LBL_CLEANBUF;
+   }
+
+   err = blake2bmac_done(&st, mac, maclen);
+
+LBL_CLEANBUF:
+   zeromem(buf, LTC_FILE_READ_BUFSIZE);
+LBL_ERR:
+#ifdef LTC_CLEAN_STACK
+   zeromem(&st, sizeof(blake2bmac_state));
+#endif
+   XFREE(buf);
+   return err;
+#endif
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/mac/blake2/blake2bmac_memory.c b/libtomcrypt/src/mac/blake2/blake2bmac_memory.c
new file mode 100644 (file)
index 0000000..45ddd6f
--- /dev/null
@@ -0,0 +1,48 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+#include "tomcrypt.h"
+
+#ifdef LTC_BLAKE2BMAC
+
+/**
+   BLAKE2B MAC a block of memory to produce the authentication tag
+   @param key       The secret key
+   @param keylen    The length of the secret key (octets)
+   @param in        The data to BLAKE2B MAC
+   @param inlen     The length of the data to BLAKE2B MAC (octets)
+   @param mac       [out] Destination of the authentication tag
+   @param maclen    [in/out] Max size and resulting size of authentication tag
+   @return CRYPT_OK if successful
+*/
+int blake2bmac_memory(const unsigned char *key, unsigned long keylen, const unsigned char *in, unsigned long inlen, unsigned char *mac, unsigned long *maclen)
+{
+   blake2bmac_state st;
+   int err;
+
+   LTC_ARGCHK(key    != NULL);
+   LTC_ARGCHK(in     != NULL);
+   LTC_ARGCHK(mac    != NULL);
+   LTC_ARGCHK(maclen != NULL);
+
+   if ((err = blake2bmac_init(&st, *maclen, key, keylen))  != CRYPT_OK) { goto LBL_ERR; }
+   if ((err = blake2bmac_process(&st, in, inlen)) != CRYPT_OK) { goto LBL_ERR; }
+   err = blake2bmac_done(&st, mac, maclen);
+LBL_ERR:
+#ifdef LTC_CLEAN_STACK
+   zeromem(&st, sizeof(blake2bmac_state));
+#endif
+   return err;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/mac/blake2/blake2bmac_memory_multi.c b/libtomcrypt/src/mac/blake2/blake2bmac_memory_multi.c
new file mode 100644 (file)
index 0000000..2b875d7
--- /dev/null
@@ -0,0 +1,62 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+#include "tomcrypt.h"
+#include <stdarg.h>
+
+#ifdef LTC_BLAKE2BMAC
+
+/**
+   BLAKE2B MAC multiple blocks of memory to produce the authentication tag
+   @param key       The secret key
+   @param keylen    The length of the secret key (octets)
+   @param mac       [out] Destination of the authentication tag
+   @param maclen    [in/out] Max size and resulting size of authentication tag
+   @param in        The data to BLAKE2B MAC
+   @param inlen     The length of the data to BLAKE2B MAC (octets)
+   @param ...       tuples of (data,len) pairs to BLAKE2B MAC, terminated with a (NULL,x) (x=don't care)
+   @return CRYPT_OK if successful
+*/
+int blake2bmac_memory_multi(const unsigned char *key, unsigned long keylen, unsigned char *mac, unsigned long *maclen, const unsigned char *in,  unsigned long inlen, ...)
+{
+   blake2bmac_state st;
+   int err;
+   va_list args;
+   const unsigned char *curptr;
+   unsigned long curlen;
+
+   LTC_ARGCHK(key    != NULL);
+   LTC_ARGCHK(in     != NULL);
+   LTC_ARGCHK(mac    != NULL);
+   LTC_ARGCHK(maclen != NULL);
+
+   va_start(args, inlen);
+   curptr = in;
+   curlen = inlen;
+   if ((err = blake2bmac_init(&st, *maclen, key, keylen)) != CRYPT_OK)          { goto LBL_ERR; }
+   for (;;) {
+      if ((err = blake2bmac_process(&st, curptr, curlen)) != CRYPT_OK) { goto LBL_ERR; }
+      curptr = va_arg(args, const unsigned char*);
+      if (curptr == NULL) break;
+      curlen = va_arg(args, unsigned long);
+   }
+   err = blake2bmac_done(&st, mac, maclen);
+LBL_ERR:
+#ifdef LTC_CLEAN_STACK
+   zeromem(&st, sizeof(blake2bmac_state));
+#endif
+   va_end(args);
+   return err;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/mac/blake2/blake2bmac_test.c b/libtomcrypt/src/mac/blake2/blake2bmac_test.c
new file mode 100644 (file)
index 0000000..ae70056
--- /dev/null
@@ -0,0 +1,314 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+#include "tomcrypt.h"
+
+#ifdef LTC_BLAKE2BMAC
+
+int blake2bmac_test(void)
+{
+#ifndef LTC_TEST
+   return CRYPT_NOP;
+#else
+   static const unsigned char tests[256][64] = {
+      /* source: https://github.com/BLAKE2/BLAKE2/blob/master/testvectors/blake2b-kat.txt */
+      { 0x10, 0xeb, 0xb6, 0x77, 0x00, 0xb1, 0x86, 0x8e, 0xfb, 0x44, 0x17, 0x98, 0x7a, 0xcf, 0x46, 0x90, 0xae, 0x9d, 0x97, 0x2f, 0xb7, 0xa5, 0x90, 0xc2, 0xf0, 0x28, 0x71, 0x79, 0x9a, 0xaa, 0x47, 0x86, 0xb5, 0xe9, 0x96, 0xe8, 0xf0, 0xf4, 0xeb, 0x98, 0x1f, 0xc2, 0x14, 0xb0, 0x05, 0xf4, 0x2d, 0x2f, 0xf4, 0x23, 0x34, 0x99, 0x39, 0x16, 0x53, 0xdf, 0x7a, 0xef, 0xcb, 0xc1, 0x3f, 0xc5, 0x15, 0x68 },
+      { 0x96, 0x1f, 0x6d, 0xd1, 0xe4, 0xdd, 0x30, 0xf6, 0x39, 0x01, 0x69, 0x0c, 0x51, 0x2e, 0x78, 0xe4, 0xb4, 0x5e, 0x47, 0x42, 0xed, 0x19, 0x7c, 0x3c, 0x5e, 0x45, 0xc5, 0x49, 0xfd, 0x25, 0xf2, 0xe4, 0x18, 0x7b, 0x0b, 0xc9, 0xfe, 0x30, 0x49, 0x2b, 0x16, 0xb0, 0xd0, 0xbc, 0x4e, 0xf9, 0xb0, 0xf3, 0x4c, 0x70, 0x03, 0xfa, 0xc0, 0x9a, 0x5e, 0xf1, 0x53, 0x2e, 0x69, 0x43, 0x02, 0x34, 0xce, 0xbd },
+      { 0xda, 0x2c, 0xfb, 0xe2, 0xd8, 0x40, 0x9a, 0x0f, 0x38, 0x02, 0x61, 0x13, 0x88, 0x4f, 0x84, 0xb5, 0x01, 0x56, 0x37, 0x1a, 0xe3, 0x04, 0xc4, 0x43, 0x01, 0x73, 0xd0, 0x8a, 0x99, 0xd9, 0xfb, 0x1b, 0x98, 0x31, 0x64, 0xa3, 0x77, 0x07, 0x06, 0xd5, 0x37, 0xf4, 0x9e, 0x0c, 0x91, 0x6d, 0x9f, 0x32, 0xb9, 0x5c, 0xc3, 0x7a, 0x95, 0xb9, 0x9d, 0x85, 0x74, 0x36, 0xf0, 0x23, 0x2c, 0x88, 0xa9, 0x65 },
+      { 0x33, 0xd0, 0x82, 0x5d, 0xdd, 0xf7, 0xad, 0xa9, 0x9b, 0x0e, 0x7e, 0x30, 0x71, 0x04, 0xad, 0x07, 0xca, 0x9c, 0xfd, 0x96, 0x92, 0x21, 0x4f, 0x15, 0x61, 0x35, 0x63, 0x15, 0xe7, 0x84, 0xf3, 0xe5, 0xa1, 0x7e, 0x36, 0x4a, 0xe9, 0xdb, 0xb1, 0x4c, 0xb2, 0x03, 0x6d, 0xf9, 0x32, 0xb7, 0x7f, 0x4b, 0x29, 0x27, 0x61, 0x36, 0x5f, 0xb3, 0x28, 0xde, 0x7a, 0xfd, 0xc6, 0xd8, 0x99, 0x8f, 0x5f, 0xc1 },
+      { 0xbe, 0xaa, 0x5a, 0x3d, 0x08, 0xf3, 0x80, 0x71, 0x43, 0xcf, 0x62, 0x1d, 0x95, 0xcd, 0x69, 0x05, 0x14, 0xd0, 0xb4, 0x9e, 0xff, 0xf9, 0xc9, 0x1d, 0x24, 0xb5, 0x92, 0x41, 0xec, 0x0e, 0xef, 0xa5, 0xf6, 0x01, 0x96, 0xd4, 0x07, 0x04, 0x8b, 0xba, 0x8d, 0x21, 0x46, 0x82, 0x8e, 0xbc, 0xb0, 0x48, 0x8d, 0x88, 0x42, 0xfd, 0x56, 0xbb, 0x4f, 0x6d, 0xf8, 0xe1, 0x9c, 0x4b, 0x4d, 0xaa, 0xb8, 0xac },
+      { 0x09, 0x80, 0x84, 0xb5, 0x1f, 0xd1, 0x3d, 0xea, 0xe5, 0xf4, 0x32, 0x0d, 0xe9, 0x4a, 0x68, 0x8e, 0xe0, 0x7b, 0xae, 0xa2, 0x80, 0x04, 0x86, 0x68, 0x9a, 0x86, 0x36, 0x11, 0x7b, 0x46, 0xc1, 0xf4, 0xc1, 0xf6, 0xaf, 0x7f, 0x74, 0xae, 0x7c, 0x85, 0x76, 0x00, 0x45, 0x6a, 0x58, 0xa3, 0xaf, 0x25, 0x1d, 0xc4, 0x72, 0x3a, 0x64, 0xcc, 0x7c, 0x0a, 0x5a, 0xb6, 0xd9, 0xca, 0xc9, 0x1c, 0x20, 0xbb },
+      { 0x60, 0x44, 0x54, 0x0d, 0x56, 0x08, 0x53, 0xeb, 0x1c, 0x57, 0xdf, 0x00, 0x77, 0xdd, 0x38, 0x10, 0x94, 0x78, 0x1c, 0xdb, 0x90, 0x73, 0xe5, 0xb1, 0xb3, 0xd3, 0xf6, 0xc7, 0x82, 0x9e, 0x12, 0x06, 0x6b, 0xba, 0xca, 0x96, 0xd9, 0x89, 0xa6, 0x90, 0xde, 0x72, 0xca, 0x31, 0x33, 0xa8, 0x36, 0x52, 0xba, 0x28, 0x4a, 0x6d, 0x62, 0x94, 0x2b, 0x27, 0x1f, 0xfa, 0x26, 0x20, 0xc9, 0xe7, 0x5b, 0x1f },
+      { 0x7a, 0x8c, 0xfe, 0x9b, 0x90, 0xf7, 0x5f, 0x7e, 0xcb, 0x3a, 0xcc, 0x05, 0x3a, 0xae, 0xd6, 0x19, 0x31, 0x12, 0xb6, 0xf6, 0xa4, 0xae, 0xeb, 0x3f, 0x65, 0xd3, 0xde, 0x54, 0x19, 0x42, 0xde, 0xb9, 0xe2, 0x22, 0x81, 0x52, 0xa3, 0xc4, 0xbb, 0xbe, 0x72, 0xfc, 0x3b, 0x12, 0x62, 0x95, 0x28, 0xcf, 0xbb, 0x09, 0xfe, 0x63, 0x0f, 0x04, 0x74, 0x33, 0x9f, 0x54, 0xab, 0xf4, 0x53, 0xe2, 0xed, 0x52 },
+      { 0x38, 0x0b, 0xea, 0xf6, 0xea, 0x7c, 0xc9, 0x36, 0x5e, 0x27, 0x0e, 0xf0, 0xe6, 0xf3, 0xa6, 0x4f, 0xb9, 0x02, 0xac, 0xae, 0x51, 0xdd, 0x55, 0x12, 0xf8, 0x42, 0x59, 0xad, 0x2c, 0x91, 0xf4, 0xbc, 0x41, 0x08, 0xdb, 0x73, 0x19, 0x2a, 0x5b, 0xbf, 0xb0, 0xcb, 0xcf, 0x71, 0xe4, 0x6c, 0x3e, 0x21, 0xae, 0xe1, 0xc5, 0xe8, 0x60, 0xdc, 0x96, 0xe8, 0xeb, 0x0b, 0x7b, 0x84, 0x26, 0xe6, 0xab, 0xe9 },
+      { 0x60, 0xfe, 0x3c, 0x45, 0x35, 0xe1, 0xb5, 0x9d, 0x9a, 0x61, 0xea, 0x85, 0x00, 0xbf, 0xac, 0x41, 0xa6, 0x9d, 0xff, 0xb1, 0xce, 0xad, 0xd9, 0xac, 0xa3, 0x23, 0xe9, 0xa6, 0x25, 0xb6, 0x4d, 0xa5, 0x76, 0x3b, 0xad, 0x72, 0x26, 0xda, 0x02, 0xb9, 0xc8, 0xc4, 0xf1, 0xa5, 0xde, 0x14, 0x0a, 0xc5, 0xa6, 0xc1, 0x12, 0x4e, 0x4f, 0x71, 0x8c, 0xe0, 0xb2, 0x8e, 0xa4, 0x73, 0x93, 0xaa, 0x66, 0x37 },
+      { 0x4f, 0xe1, 0x81, 0xf5, 0x4a, 0xd6, 0x3a, 0x29, 0x83, 0xfe, 0xaa, 0xf7, 0x7d, 0x1e, 0x72, 0x35, 0xc2, 0xbe, 0xb1, 0x7f, 0xa3, 0x28, 0xb6, 0xd9, 0x50, 0x5b, 0xda, 0x32, 0x7d, 0xf1, 0x9f, 0xc3, 0x7f, 0x02, 0xc4, 0xb6, 0xf0, 0x36, 0x8c, 0xe2, 0x31, 0x47, 0x31, 0x3a, 0x8e, 0x57, 0x38, 0xb5, 0xfa, 0x2a, 0x95, 0xb2, 0x9d, 0xe1, 0xc7, 0xf8, 0x26, 0x4e, 0xb7, 0x7b, 0x69, 0xf5, 0x85, 0xcd },
+      { 0xf2, 0x28, 0x77, 0x3c, 0xe3, 0xf3, 0xa4, 0x2b, 0x5f, 0x14, 0x4d, 0x63, 0x23, 0x7a, 0x72, 0xd9, 0x96, 0x93, 0xad, 0xb8, 0x83, 0x7d, 0x0e, 0x11, 0x2a, 0x8a, 0x0f, 0x8f, 0xff, 0xf2, 0xc3, 0x62, 0x85, 0x7a, 0xc4, 0x9c, 0x11, 0xec, 0x74, 0x0d, 0x15, 0x00, 0x74, 0x9d, 0xac, 0x9b, 0x1f, 0x45, 0x48, 0x10, 0x8b, 0xf3, 0x15, 0x57, 0x94, 0xdc, 0xc9, 0xe4, 0x08, 0x28, 0x49, 0xe2, 0xb8, 0x5b },
+      { 0x96, 0x24, 0x52, 0xa8, 0x45, 0x5c, 0xc5, 0x6c, 0x85, 0x11, 0x31, 0x7e, 0x3b, 0x1f, 0x3b, 0x2c, 0x37, 0xdf, 0x75, 0xf5, 0x88, 0xe9, 0x43, 0x25, 0xfd, 0xd7, 0x70, 0x70, 0x35, 0x9c, 0xf6, 0x3a, 0x9a, 0xe6, 0xe9, 0x30, 0x93, 0x6f, 0xdf, 0x8e, 0x1e, 0x08, 0xff, 0xca, 0x44, 0x0c, 0xfb, 0x72, 0xc2, 0x8f, 0x06, 0xd8, 0x9a, 0x21, 0x51, 0xd1, 0xc4, 0x6c, 0xd5, 0xb2, 0x68, 0xef, 0x85, 0x63 },
+      { 0x43, 0xd4, 0x4b, 0xfa, 0x18, 0x76, 0x8c, 0x59, 0x89, 0x6b, 0xf7, 0xed, 0x17, 0x65, 0xcb, 0x2d, 0x14, 0xaf, 0x8c, 0x26, 0x02, 0x66, 0x03, 0x90, 0x99, 0xb2, 0x5a, 0x60, 0x3e, 0x4d, 0xdc, 0x50, 0x39, 0xd6, 0xef, 0x3a, 0x91, 0x84, 0x7d, 0x10, 0x88, 0xd4, 0x01, 0xc0, 0xc7, 0xe8, 0x47, 0x78, 0x1a, 0x8a, 0x59, 0x0d, 0x33, 0xa3, 0xc6, 0xcb, 0x4d, 0xf0, 0xfa, 0xb1, 0xc2, 0xf2, 0x23, 0x55 },
+      { 0xdc, 0xff, 0xa9, 0xd5, 0x8c, 0x2a, 0x4c, 0xa2, 0xcd, 0xbb, 0x0c, 0x7a, 0xa4, 0xc4, 0xc1, 0xd4, 0x51, 0x65, 0x19, 0x00, 0x89, 0xf4, 0xe9, 0x83, 0xbb, 0x1c, 0x2c, 0xab, 0x4a, 0xae, 0xff, 0x1f, 0xa2, 0xb5, 0xee, 0x51, 0x6f, 0xec, 0xd7, 0x80, 0x54, 0x02, 0x40, 0xbf, 0x37, 0xe5, 0x6c, 0x8b, 0xcc, 0xa7, 0xfa, 0xb9, 0x80, 0xe1, 0xe6, 0x1c, 0x94, 0x00, 0xd8, 0xa9, 0xa5, 0xb1, 0x4a, 0xc6 },
+      { 0x6f, 0xbf, 0x31, 0xb4, 0x5a, 0xb0, 0xc0, 0xb8, 0xda, 0xd1, 0xc0, 0xf5, 0xf4, 0x06, 0x13, 0x79, 0x91, 0x2d, 0xde, 0x5a, 0xa9, 0x22, 0x09, 0x9a, 0x03, 0x0b, 0x72, 0x5c, 0x73, 0x34, 0x6c, 0x52, 0x42, 0x91, 0xad, 0xef, 0x89, 0xd2, 0xf6, 0xfd, 0x8d, 0xfc, 0xda, 0x6d, 0x07, 0xda, 0xd8, 0x11, 0xa9, 0x31, 0x45, 0x36, 0xc2, 0x91, 0x5e, 0xd4, 0x5d, 0xa3, 0x49, 0x47, 0xe8, 0x3d, 0xe3, 0x4e },
+      { 0xa0, 0xc6, 0x5b, 0xdd, 0xde, 0x8a, 0xde, 0xf5, 0x72, 0x82, 0xb0, 0x4b, 0x11, 0xe7, 0xbc, 0x8a, 0xab, 0x10, 0x5b, 0x99, 0x23, 0x1b, 0x75, 0x0c, 0x02, 0x1f, 0x4a, 0x73, 0x5c, 0xb1, 0xbc, 0xfa, 0xb8, 0x75, 0x53, 0xbb, 0xa3, 0xab, 0xb0, 0xc3, 0xe6, 0x4a, 0x0b, 0x69, 0x55, 0x28, 0x51, 0x85, 0xa0, 0xbd, 0x35, 0xfb, 0x8c, 0xfd, 0xe5, 0x57, 0x32, 0x9b, 0xeb, 0xb1, 0xf6, 0x29, 0xee, 0x93 },
+      { 0xf9, 0x9d, 0x81, 0x55, 0x50, 0x55, 0x8e, 0x81, 0xec, 0xa2, 0xf9, 0x67, 0x18, 0xae, 0xd1, 0x0d, 0x86, 0xf3, 0xf1, 0xcf, 0xb6, 0x75, 0xcc, 0xe0, 0x6b, 0x0e, 0xff, 0x02, 0xf6, 0x17, 0xc5, 0xa4, 0x2c, 0x5a, 0xa7, 0x60, 0x27, 0x0f, 0x26, 0x79, 0xda, 0x26, 0x77, 0xc5, 0xae, 0xb9, 0x4f, 0x11, 0x42, 0x27, 0x7f, 0x21, 0xc7, 0xf7, 0x9f, 0x3c, 0x4f, 0x0c, 0xce, 0x4e, 0xd8, 0xee, 0x62, 0xb1 },
+      { 0x95, 0x39, 0x1d, 0xa8, 0xfc, 0x7b, 0x91, 0x7a, 0x20, 0x44, 0xb3, 0xd6, 0xf5, 0x37, 0x4e, 0x1c, 0xa0, 0x72, 0xb4, 0x14, 0x54, 0xd5, 0x72, 0xc7, 0x35, 0x6c, 0x05, 0xfd, 0x4b, 0xc1, 0xe0, 0xf4, 0x0b, 0x8b, 0xb8, 0xb4, 0xa9, 0xf6, 0xbc, 0xe9, 0xbe, 0x2c, 0x46, 0x23, 0xc3, 0x99, 0xb0, 0xdc, 0xa0, 0xda, 0xb0, 0x5c, 0xb7, 0x28, 0x1b, 0x71, 0xa2, 0x1b, 0x0e, 0xbc, 0xd9, 0xe5, 0x56, 0x70 },
+      { 0x04, 0xb9, 0xcd, 0x3d, 0x20, 0xd2, 0x21, 0xc0, 0x9a, 0xc8, 0x69, 0x13, 0xd3, 0xdc, 0x63, 0x04, 0x19, 0x89, 0xa9, 0xa1, 0xe6, 0x94, 0xf1, 0xe6, 0x39, 0xa3, 0xba, 0x7e, 0x45, 0x18, 0x40, 0xf7, 0x50, 0xc2, 0xfc, 0x19, 0x1d, 0x56, 0xad, 0x61, 0xf2, 0xe7, 0x93, 0x6b, 0xc0, 0xac, 0x8e, 0x09, 0x4b, 0x60, 0xca, 0xee, 0xd8, 0x78, 0xc1, 0x87, 0x99, 0x04, 0x54, 0x02, 0xd6, 0x1c, 0xea, 0xf9 },
+      { 0xec, 0x0e, 0x0e, 0xf7, 0x07, 0xe4, 0xed, 0x6c, 0x0c, 0x66, 0xf9, 0xe0, 0x89, 0xe4, 0x95, 0x4b, 0x05, 0x80, 0x30, 0xd2, 0xdd, 0x86, 0x39, 0x8f, 0xe8, 0x40, 0x59, 0x63, 0x1f, 0x9e, 0xe5, 0x91, 0xd9, 0xd7, 0x73, 0x75, 0x35, 0x51, 0x49, 0x17, 0x8c, 0x0c, 0xf8, 0xf8, 0xe7, 0xc4, 0x9e, 0xd2, 0xa5, 0xe4, 0xf9, 0x54, 0x88, 0xa2, 0x24, 0x70, 0x67, 0xc2, 0x08, 0x51, 0x0f, 0xad, 0xc4, 0x4c },
+      { 0x9a, 0x37, 0xcc, 0xe2, 0x73, 0xb7, 0x9c, 0x09, 0x91, 0x36, 0x77, 0x51, 0x0e, 0xaf, 0x76, 0x88, 0xe8, 0x9b, 0x33, 0x14, 0xd3, 0x53, 0x2f, 0xd2, 0x76, 0x4c, 0x39, 0xde, 0x02, 0x2a, 0x29, 0x45, 0xb5, 0x71, 0x0d, 0x13, 0x51, 0x7a, 0xf8, 0xdd, 0xc0, 0x31, 0x66, 0x24, 0xe7, 0x3b, 0xec, 0x1c, 0xe6, 0x7d, 0xf1, 0x52, 0x28, 0x30, 0x20, 0x36, 0xf3, 0x30, 0xab, 0x0c, 0xb4, 0xd2, 0x18, 0xdd },
+      { 0x4c, 0xf9, 0xbb, 0x8f, 0xb3, 0xd4, 0xde, 0x8b, 0x38, 0xb2, 0xf2, 0x62, 0xd3, 0xc4, 0x0f, 0x46, 0xdf, 0xe7, 0x47, 0xe8, 0xfc, 0x0a, 0x41, 0x4c, 0x19, 0x3d, 0x9f, 0xcf, 0x75, 0x31, 0x06, 0xce, 0x47, 0xa1, 0x8f, 0x17, 0x2f, 0x12, 0xe8, 0xa2, 0xf1, 0xc2, 0x67, 0x26, 0x54, 0x53, 0x58, 0xe5, 0xee, 0x28, 0xc9, 0xe2, 0x21, 0x3a, 0x87, 0x87, 0xaa, 0xfb, 0xc5, 0x16, 0xd2, 0x34, 0x31, 0x52 },
+      { 0x64, 0xe0, 0xc6, 0x3a, 0xf9, 0xc8, 0x08, 0xfd, 0x89, 0x31, 0x37, 0x12, 0x98, 0x67, 0xfd, 0x91, 0x93, 0x9d, 0x53, 0xf2, 0xaf, 0x04, 0xbe, 0x4f, 0xa2, 0x68, 0x00, 0x61, 0x00, 0x06, 0x9b, 0x2d, 0x69, 0xda, 0xa5, 0xc5, 0xd8, 0xed, 0x7f, 0xdd, 0xcb, 0x2a, 0x70, 0xee, 0xec, 0xdf, 0x2b, 0x10, 0x5d, 0xd4, 0x6a, 0x1e, 0x3b, 0x73, 0x11, 0x72, 0x8f, 0x63, 0x9a, 0xb4, 0x89, 0x32, 0x6b, 0xc9 },
+      { 0x5e, 0x9c, 0x93, 0x15, 0x8d, 0x65, 0x9b, 0x2d, 0xef, 0x06, 0xb0, 0xc3, 0xc7, 0x56, 0x50, 0x45, 0x54, 0x26, 0x62, 0xd6, 0xee, 0xe8, 0xa9, 0x6a, 0x89, 0xb7, 0x8a, 0xde, 0x09, 0xfe, 0x8b, 0x3d, 0xcc, 0x09, 0x6d, 0x4f, 0xe4, 0x88, 0x15, 0xd8, 0x8d, 0x8f, 0x82, 0x62, 0x01, 0x56, 0x60, 0x2a, 0xf5, 0x41, 0x95, 0x5e, 0x1f, 0x6c, 0xa3, 0x0d, 0xce, 0x14, 0xe2, 0x54, 0xc3, 0x26, 0xb8, 0x8f },
+      { 0x77, 0x75, 0xdf, 0xf8, 0x89, 0x45, 0x8d, 0xd1, 0x1a, 0xef, 0x41, 0x72, 0x76, 0x85, 0x3e, 0x21, 0x33, 0x5e, 0xb8, 0x8e, 0x4d, 0xec, 0x9c, 0xfb, 0x4e, 0x9e, 0xdb, 0x49, 0x82, 0x00, 0x88, 0x55, 0x1a, 0x2c, 0xa6, 0x03, 0x39, 0xf1, 0x20, 0x66, 0x10, 0x11, 0x69, 0xf0, 0xdf, 0xe8, 0x4b, 0x09, 0x8f, 0xdd, 0xb1, 0x48, 0xd9, 0xda, 0x6b, 0x3d, 0x61, 0x3d, 0xf2, 0x63, 0x88, 0x9a, 0xd6, 0x4b },
+      { 0xf0, 0xd2, 0x80, 0x5a, 0xfb, 0xb9, 0x1f, 0x74, 0x39, 0x51, 0x35, 0x1a, 0x6d, 0x02, 0x4f, 0x93, 0x53, 0xa2, 0x3c, 0x7c, 0xe1, 0xfc, 0x2b, 0x05, 0x1b, 0x3a, 0x8b, 0x96, 0x8c, 0x23, 0x3f, 0x46, 0xf5, 0x0f, 0x80, 0x6e, 0xcb, 0x15, 0x68, 0xff, 0xaa, 0x0b, 0x60, 0x66, 0x1e, 0x33, 0x4b, 0x21, 0xdd, 0xe0, 0x4f, 0x8f, 0xa1, 0x55, 0xac, 0x74, 0x0e, 0xeb, 0x42, 0xe2, 0x0b, 0x60, 0xd7, 0x64 },
+      { 0x86, 0xa2, 0xaf, 0x31, 0x6e, 0x7d, 0x77, 0x54, 0x20, 0x1b, 0x94, 0x2e, 0x27, 0x53, 0x64, 0xac, 0x12, 0xea, 0x89, 0x62, 0xab, 0x5b, 0xd8, 0xd7, 0xfb, 0x27, 0x6d, 0xc5, 0xfb, 0xff, 0xc8, 0xf9, 0xa2, 0x8c, 0xae, 0x4e, 0x48, 0x67, 0xdf, 0x67, 0x80, 0xd9, 0xb7, 0x25, 0x24, 0x16, 0x09, 0x27, 0xc8, 0x55, 0xda, 0x5b, 0x60, 0x78, 0xe0, 0xb5, 0x54, 0xaa, 0x91, 0xe3, 0x1c, 0xb9, 0xca, 0x1d },
+      { 0x10, 0xbd, 0xf0, 0xca, 0xa0, 0x80, 0x27, 0x05, 0xe7, 0x06, 0x36, 0x9b, 0xaf, 0x8a, 0x3f, 0x79, 0xd7, 0x2c, 0x0a, 0x03, 0xa8, 0x06, 0x75, 0xa7, 0xbb, 0xb0, 0x0b, 0xe3, 0xa4, 0x5e, 0x51, 0x64, 0x24, 0xd1, 0xee, 0x88, 0xef, 0xb5, 0x6f, 0x6d, 0x57, 0x77, 0x54, 0x5a, 0xe6, 0xe2, 0x77, 0x65, 0xc3, 0xa8, 0xf5, 0xe4, 0x93, 0xfc, 0x30, 0x89, 0x15, 0x63, 0x89, 0x33, 0xa1, 0xdf, 0xee, 0x55 },
+      { 0xb0, 0x17, 0x81, 0x09, 0x2b, 0x17, 0x48, 0x45, 0x9e, 0x2e, 0x4e, 0xc1, 0x78, 0x69, 0x66, 0x27, 0xbf, 0x4e, 0xba, 0xfe, 0xbb, 0xa7, 0x74, 0xec, 0xf0, 0x18, 0xb7, 0x9a, 0x68, 0xae, 0xb8, 0x49, 0x17, 0xbf, 0x0b, 0x84, 0xbb, 0x79, 0xd1, 0x7b, 0x74, 0x31, 0x51, 0x14, 0x4c, 0xd6, 0x6b, 0x7b, 0x33, 0xa4, 0xb9, 0xe5, 0x2c, 0x76, 0xc4, 0xe1, 0x12, 0x05, 0x0f, 0xf5, 0x38, 0x5b, 0x7f, 0x0b },
+      { 0xc6, 0xdb, 0xc6, 0x1d, 0xec, 0x6e, 0xae, 0xac, 0x81, 0xe3, 0xd5, 0xf7, 0x55, 0x20, 0x3c, 0x8e, 0x22, 0x05, 0x51, 0x53, 0x4a, 0x0b, 0x2f, 0xd1, 0x05, 0xa9, 0x18, 0x89, 0x94, 0x5a, 0x63, 0x85, 0x50, 0x20, 0x4f, 0x44, 0x09, 0x3d, 0xd9, 0x98, 0xc0, 0x76, 0x20, 0x5d, 0xff, 0xad, 0x70, 0x3a, 0x0e, 0x5c, 0xd3, 0xc7, 0xf4, 0x38, 0xa7, 0xe6, 0x34, 0xcd, 0x59, 0xfe, 0xde, 0xdb, 0x53, 0x9e },
+      { 0xeb, 0xa5, 0x1a, 0xcf, 0xfb, 0x4c, 0xea, 0x31, 0xdb, 0x4b, 0x8d, 0x87, 0xe9, 0xbf, 0x7d, 0xd4, 0x8f, 0xe9, 0x7b, 0x02, 0x53, 0xae, 0x67, 0xaa, 0x58, 0x0f, 0x9a, 0xc4, 0xa9, 0xd9, 0x41, 0xf2, 0xbe, 0xa5, 0x18, 0xee, 0x28, 0x68, 0x18, 0xcc, 0x9f, 0x63, 0x3f, 0x2a, 0x3b, 0x9f, 0xb6, 0x8e, 0x59, 0x4b, 0x48, 0xcd, 0xd6, 0xd5, 0x15, 0xbf, 0x1d, 0x52, 0xba, 0x6c, 0x85, 0xa2, 0x03, 0xa7 },
+      { 0x86, 0x22, 0x1f, 0x3a, 0xda, 0x52, 0x03, 0x7b, 0x72, 0x22, 0x4f, 0x10, 0x5d, 0x79, 0x99, 0x23, 0x1c, 0x5e, 0x55, 0x34, 0xd0, 0x3d, 0xa9, 0xd9, 0xc0, 0xa1, 0x2a, 0xcb, 0x68, 0x46, 0x0c, 0xd3, 0x75, 0xda, 0xf8, 0xe2, 0x43, 0x86, 0x28, 0x6f, 0x96, 0x68, 0xf7, 0x23, 0x26, 0xdb, 0xf9, 0x9b, 0xa0, 0x94, 0x39, 0x24, 0x37, 0xd3, 0x98, 0xe9, 0x5b, 0xb8, 0x16, 0x1d, 0x71, 0x7f, 0x89, 0x91 },
+      { 0x55, 0x95, 0xe0, 0x5c, 0x13, 0xa7, 0xec, 0x4d, 0xc8, 0xf4, 0x1f, 0xb7, 0x0c, 0xb5, 0x0a, 0x71, 0xbc, 0xe1, 0x7c, 0x02, 0x4f, 0xf6, 0xde, 0x7a, 0xf6, 0x18, 0xd0, 0xcc, 0x4e, 0x9c, 0x32, 0xd9, 0x57, 0x0d, 0x6d, 0x3e, 0xa4, 0x5b, 0x86, 0x52, 0x54, 0x91, 0x03, 0x0c, 0x0d, 0x8f, 0x2b, 0x18, 0x36, 0xd5, 0x77, 0x8c, 0x1c, 0xe7, 0x35, 0xc1, 0x77, 0x07, 0xdf, 0x36, 0x4d, 0x05, 0x43, 0x47 },
+      { 0xce, 0x0f, 0x4f, 0x6a, 0xca, 0x89, 0x59, 0x0a, 0x37, 0xfe, 0x03, 0x4d, 0xd7, 0x4d, 0xd5, 0xfa, 0x65, 0xeb, 0x1c, 0xbd, 0x0a, 0x41, 0x50, 0x8a, 0xad, 0xdc, 0x09, 0x35, 0x1a, 0x3c, 0xea, 0x6d, 0x18, 0xcb, 0x21, 0x89, 0xc5, 0x4b, 0x70, 0x0c, 0x00, 0x9f, 0x4c, 0xbf, 0x05, 0x21, 0xc7, 0xea, 0x01, 0xbe, 0x61, 0xc5, 0xae, 0x09, 0xcb, 0x54, 0xf2, 0x7b, 0xc1, 0xb4, 0x4d, 0x65, 0x8c, 0x82 },
+      { 0x7e, 0xe8, 0x0b, 0x06, 0xa2, 0x15, 0xa3, 0xbc, 0xa9, 0x70, 0xc7, 0x7c, 0xda, 0x87, 0x61, 0x82, 0x2b, 0xc1, 0x03, 0xd4, 0x4f, 0xa4, 0xb3, 0x3f, 0x4d, 0x07, 0xdc, 0xb9, 0x97, 0xe3, 0x6d, 0x55, 0x29, 0x8b, 0xce, 0xae, 0x12, 0x24, 0x1b, 0x3f, 0xa0, 0x7f, 0xa6, 0x3b, 0xe5, 0x57, 0x60, 0x68, 0xda, 0x38, 0x7b, 0x8d, 0x58, 0x59, 0xae, 0xab, 0x70, 0x13, 0x69, 0x84, 0x8b, 0x17, 0x6d, 0x42 },
+      { 0x94, 0x0a, 0x84, 0xb6, 0xa8, 0x4d, 0x10, 0x9a, 0xab, 0x20, 0x8c, 0x02, 0x4c, 0x6c, 0xe9, 0x64, 0x76, 0x76, 0xba, 0x0a, 0xaa, 0x11, 0xf8, 0x6d, 0xbb, 0x70, 0x18, 0xf9, 0xfd, 0x22, 0x20, 0xa6, 0xd9, 0x01, 0xa9, 0x02, 0x7f, 0x9a, 0xbc, 0xf9, 0x35, 0x37, 0x27, 0x27, 0xcb, 0xf0, 0x9e, 0xbd, 0x61, 0xa2, 0xa2, 0xee, 0xb8, 0x76, 0x53, 0xe8, 0xec, 0xad, 0x1b, 0xab, 0x85, 0xdc, 0x83, 0x27 },
+      { 0x20, 0x20, 0xb7, 0x82, 0x64, 0xa8, 0x2d, 0x9f, 0x41, 0x51, 0x14, 0x1a, 0xdb, 0xa8, 0xd4, 0x4b, 0xf2, 0x0c, 0x5e, 0xc0, 0x62, 0xee, 0xe9, 0xb5, 0x95, 0xa1, 0x1f, 0x9e, 0x84, 0x90, 0x1b, 0xf1, 0x48, 0xf2, 0x98, 0xe0, 0xc9, 0xf8, 0x77, 0x7d, 0xcd, 0xbc, 0x7c, 0xc4, 0x67, 0x0a, 0xac, 0x35, 0x6c, 0xc2, 0xad, 0x8c, 0xcb, 0x16, 0x29, 0xf1, 0x6f, 0x6a, 0x76, 0xbc, 0xef, 0xbe, 0xe7, 0x60 },
+      { 0xd1, 0xb8, 0x97, 0xb0, 0xe0, 0x75, 0xba, 0x68, 0xab, 0x57, 0x2a, 0xdf, 0x9d, 0x9c, 0x43, 0x66, 0x63, 0xe4, 0x3e, 0xb3, 0xd8, 0xe6, 0x2d, 0x92, 0xfc, 0x49, 0xc9, 0xbe, 0x21, 0x4e, 0x6f, 0x27, 0x87, 0x3f, 0xe2, 0x15, 0xa6, 0x51, 0x70, 0xe6, 0xbe, 0xa9, 0x02, 0x40, 0x8a, 0x25, 0xb4, 0x95, 0x06, 0xf4, 0x7b, 0xab, 0xd0, 0x7c, 0xec, 0xf7, 0x11, 0x3e, 0xc1, 0x0c, 0x5d, 0xd3, 0x12, 0x52 },
+      { 0xb1, 0x4d, 0x0c, 0x62, 0xab, 0xfa, 0x46, 0x9a, 0x35, 0x71, 0x77, 0xe5, 0x94, 0xc1, 0x0c, 0x19, 0x42, 0x43, 0xed, 0x20, 0x25, 0xab, 0x8a, 0xa5, 0xad, 0x2f, 0xa4, 0x1a, 0xd3, 0x18, 0xe0, 0xff, 0x48, 0xcd, 0x5e, 0x60, 0xbe, 0xc0, 0x7b, 0x13, 0x63, 0x4a, 0x71, 0x1d, 0x23, 0x26, 0xe4, 0x88, 0xa9, 0x85, 0xf3, 0x1e, 0x31, 0x15, 0x33, 0x99, 0xe7, 0x30, 0x88, 0xef, 0xc8, 0x6a, 0x5c, 0x55 },
+      { 0x41, 0x69, 0xc5, 0xcc, 0x80, 0x8d, 0x26, 0x97, 0xdc, 0x2a, 0x82, 0x43, 0x0d, 0xc2, 0x3e, 0x3c, 0xd3, 0x56, 0xdc, 0x70, 0xa9, 0x45, 0x66, 0x81, 0x05, 0x02, 0xb8, 0xd6, 0x55, 0xb3, 0x9a, 0xbf, 0x9e, 0x7f, 0x90, 0x2f, 0xe7, 0x17, 0xe0, 0x38, 0x92, 0x19, 0x85, 0x9e, 0x19, 0x45, 0xdf, 0x1a, 0xf6, 0xad, 0xa4, 0x2e, 0x4c, 0xcd, 0xa5, 0x5a, 0x19, 0x7b, 0x71, 0x00, 0xa3, 0x0c, 0x30, 0xa1 },
+      { 0x25, 0x8a, 0x4e, 0xdb, 0x11, 0x3d, 0x66, 0xc8, 0x39, 0xc8, 0xb1, 0xc9, 0x1f, 0x15, 0xf3, 0x5a, 0xde, 0x60, 0x9f, 0x11, 0xcd, 0x7f, 0x86, 0x81, 0xa4, 0x04, 0x5b, 0x9f, 0xef, 0x7b, 0x0b, 0x24, 0xc8, 0x2c, 0xda, 0x06, 0xa5, 0xf2, 0x06, 0x7b, 0x36, 0x88, 0x25, 0xe3, 0x91, 0x4e, 0x53, 0xd6, 0x94, 0x8e, 0xde, 0x92, 0xef, 0xd6, 0xe8, 0x38, 0x7f, 0xa2, 0xe5, 0x37, 0x23, 0x9b, 0x5b, 0xee },
+      { 0x79, 0xd2, 0xd8, 0x69, 0x6d, 0x30, 0xf3, 0x0f, 0xb3, 0x46, 0x57, 0x76, 0x11, 0x71, 0xa1, 0x1e, 0x6c, 0x3f, 0x1e, 0x64, 0xcb, 0xe7, 0xbe, 0xbe, 0xe1, 0x59, 0xcb, 0x95, 0xbf, 0xaf, 0x81, 0x2b, 0x4f, 0x41, 0x1e, 0x2f, 0x26, 0xd9, 0xc4, 0x21, 0xdc, 0x2c, 0x28, 0x4a, 0x33, 0x42, 0xd8, 0x23, 0xec, 0x29, 0x38, 0x49, 0xe4, 0x2d, 0x1e, 0x46, 0xb0, 0xa4, 0xac, 0x1e, 0x3c, 0x86, 0xab, 0xaa },
+      { 0x8b, 0x94, 0x36, 0x01, 0x0d, 0xc5, 0xde, 0xe9, 0x92, 0xae, 0x38, 0xae, 0xa9, 0x7f, 0x2c, 0xd6, 0x3b, 0x94, 0x6d, 0x94, 0xfe, 0xdd, 0x2e, 0xc9, 0x67, 0x1d, 0xcd, 0xe3, 0xbd, 0x4c, 0xe9, 0x56, 0x4d, 0x55, 0x5c, 0x66, 0xc1, 0x5b, 0xb2, 0xb9, 0x00, 0xdf, 0x72, 0xed, 0xb6, 0xb8, 0x91, 0xeb, 0xca, 0xdf, 0xef, 0xf6, 0x3c, 0x9e, 0xa4, 0x03, 0x6a, 0x99, 0x8b, 0xe7, 0x97, 0x39, 0x81, 0xe7 },
+      { 0xc8, 0xf6, 0x8e, 0x69, 0x6e, 0xd2, 0x82, 0x42, 0xbf, 0x99, 0x7f, 0x5b, 0x3b, 0x34, 0x95, 0x95, 0x08, 0xe4, 0x2d, 0x61, 0x38, 0x10, 0xf1, 0xe2, 0xa4, 0x35, 0xc9, 0x6e, 0xd2, 0xff, 0x56, 0x0c, 0x70, 0x22, 0xf3, 0x61, 0xa9, 0x23, 0x4b, 0x98, 0x37, 0xfe, 0xee, 0x90, 0xbf, 0x47, 0x92, 0x2e, 0xe0, 0xfd, 0x5f, 0x8d, 0xdf, 0x82, 0x37, 0x18, 0xd8, 0x6d, 0x1e, 0x16, 0xc6, 0x09, 0x00, 0x71 },
+      { 0xb0, 0x2d, 0x3e, 0xee, 0x48, 0x60, 0xd5, 0x86, 0x8b, 0x2c, 0x39, 0xce, 0x39, 0xbf, 0xe8, 0x10, 0x11, 0x29, 0x05, 0x64, 0xdd, 0x67, 0x8c, 0x85, 0xe8, 0x78, 0x3f, 0x29, 0x30, 0x2d, 0xfc, 0x13, 0x99, 0xba, 0x95, 0xb6, 0xb5, 0x3c, 0xd9, 0xeb, 0xbf, 0x40, 0x0c, 0xca, 0x1d, 0xb0, 0xab, 0x67, 0xe1, 0x9a, 0x32, 0x5f, 0x2d, 0x11, 0x58, 0x12, 0xd2, 0x5d, 0x00, 0x97, 0x8a, 0xd1, 0xbc, 0xa4 },
+      { 0x76, 0x93, 0xea, 0x73, 0xaf, 0x3a, 0xc4, 0xda, 0xd2, 0x1c, 0xa0, 0xd8, 0xda, 0x85, 0xb3, 0x11, 0x8a, 0x7d, 0x1c, 0x60, 0x24, 0xcf, 0xaf, 0x55, 0x76, 0x99, 0x86, 0x82, 0x17, 0xbc, 0x0c, 0x2f, 0x44, 0xa1, 0x99, 0xbc, 0x6c, 0x0e, 0xdd, 0x51, 0x97, 0x98, 0xba, 0x05, 0xbd, 0x5b, 0x1b, 0x44, 0x84, 0x34, 0x6a, 0x47, 0xc2, 0xca, 0xdf, 0x6b, 0xf3, 0x0b, 0x78, 0x5c, 0xc8, 0x8b, 0x2b, 0xaf },
+      { 0xa0, 0xe5, 0xc1, 0xc0, 0x03, 0x1c, 0x02, 0xe4, 0x8b, 0x7f, 0x09, 0xa5, 0xe8, 0x96, 0xee, 0x9a, 0xef, 0x2f, 0x17, 0xfc, 0x9e, 0x18, 0xe9, 0x97, 0xd7, 0xf6, 0xca, 0xc7, 0xae, 0x31, 0x64, 0x22, 0xc2, 0xb1, 0xe7, 0x79, 0x84, 0xe5, 0xf3, 0xa7, 0x3c, 0xb4, 0x5d, 0xee, 0xd5, 0xd3, 0xf8, 0x46, 0x00, 0x10, 0x5e, 0x6e, 0xe3, 0x8f, 0x2d, 0x09, 0x0c, 0x7d, 0x04, 0x42, 0xea, 0x34, 0xc4, 0x6d },
+      { 0x41, 0xda, 0xa6, 0xad, 0xcf, 0xdb, 0x69, 0xf1, 0x44, 0x0c, 0x37, 0xb5, 0x96, 0x44, 0x01, 0x65, 0xc1, 0x5a, 0xda, 0x59, 0x68, 0x13, 0xe2, 0xe2, 0x2f, 0x06, 0x0f, 0xcd, 0x55, 0x1f, 0x24, 0xde, 0xe8, 0xe0, 0x4b, 0xa6, 0x89, 0x03, 0x87, 0x88, 0x6c, 0xee, 0xc4, 0xa7, 0xa0, 0xd7, 0xfc, 0x6b, 0x44, 0x50, 0x63, 0x92, 0xec, 0x38, 0x22, 0xc0, 0xd8, 0xc1, 0xac, 0xfc, 0x7d, 0x5a, 0xeb, 0xe8 },
+      { 0x14, 0xd4, 0xd4, 0x0d, 0x59, 0x84, 0xd8, 0x4c, 0x5c, 0xf7, 0x52, 0x3b, 0x77, 0x98, 0xb2, 0x54, 0xe2, 0x75, 0xa3, 0xa8, 0xcc, 0x0a, 0x1b, 0xd0, 0x6e, 0xbc, 0x0b, 0xee, 0x72, 0x68, 0x56, 0xac, 0xc3, 0xcb, 0xf5, 0x16, 0xff, 0x66, 0x7c, 0xda, 0x20, 0x58, 0xad, 0x5c, 0x34, 0x12, 0x25, 0x44, 0x60, 0xa8, 0x2c, 0x92, 0x18, 0x70, 0x41, 0x36, 0x3c, 0xc7, 0x7a, 0x4d, 0xc2, 0x15, 0xe4, 0x87 },
+      { 0xd0, 0xe7, 0xa1, 0xe2, 0xb9, 0xa4, 0x47, 0xfe, 0xe8, 0x3e, 0x22, 0x77, 0xe9, 0xff, 0x80, 0x10, 0xc2, 0xf3, 0x75, 0xae, 0x12, 0xfa, 0x7a, 0xaa, 0x8c, 0xa5, 0xa6, 0x31, 0x78, 0x68, 0xa2, 0x6a, 0x36, 0x7a, 0x0b, 0x69, 0xfb, 0xc1, 0xcf, 0x32, 0xa5, 0x5d, 0x34, 0xeb, 0x37, 0x06, 0x63, 0x01, 0x6f, 0x3d, 0x21, 0x10, 0x23, 0x0e, 0xba, 0x75, 0x40, 0x28, 0xa5, 0x6f, 0x54, 0xac, 0xf5, 0x7c },
+      { 0xe7, 0x71, 0xaa, 0x8d, 0xb5, 0xa3, 0xe0, 0x43, 0xe8, 0x17, 0x8f, 0x39, 0xa0, 0x85, 0x7b, 0xa0, 0x4a, 0x3f, 0x18, 0xe4, 0xaa, 0x05, 0x74, 0x3c, 0xf8, 0xd2, 0x22, 0xb0, 0xb0, 0x95, 0x82, 0x53, 0x50, 0xba, 0x42, 0x2f, 0x63, 0x38, 0x2a, 0x23, 0xd9, 0x2e, 0x41, 0x49, 0x07, 0x4e, 0x81, 0x6a, 0x36, 0xc1, 0xcd, 0x28, 0x28, 0x4d, 0x14, 0x62, 0x67, 0x94, 0x0b, 0x31, 0xf8, 0x81, 0x8e, 0xa2 },
+      { 0xfe, 0xb4, 0xfd, 0x6f, 0x9e, 0x87, 0xa5, 0x6b, 0xef, 0x39, 0x8b, 0x32, 0x84, 0xd2, 0xbd, 0xa5, 0xb5, 0xb0, 0xe1, 0x66, 0x58, 0x3a, 0x66, 0xb6, 0x1e, 0x53, 0x84, 0x57, 0xff, 0x05, 0x84, 0x87, 0x2c, 0x21, 0xa3, 0x29, 0x62, 0xb9, 0x92, 0x8f, 0xfa, 0xb5, 0x8d, 0xe4, 0xaf, 0x2e, 0xdd, 0x4e, 0x15, 0xd8, 0xb3, 0x55, 0x70, 0x52, 0x32, 0x07, 0xff, 0x4e, 0x2a, 0x5a, 0xa7, 0x75, 0x4c, 0xaa },
+      { 0x46, 0x2f, 0x17, 0xbf, 0x00, 0x5f, 0xb1, 0xc1, 0xb9, 0xe6, 0x71, 0x77, 0x9f, 0x66, 0x52, 0x09, 0xec, 0x28, 0x73, 0xe3, 0xe4, 0x11, 0xf9, 0x8d, 0xab, 0xf2, 0x40, 0xa1, 0xd5, 0xec, 0x3f, 0x95, 0xce, 0x67, 0x96, 0xb6, 0xfc, 0x23, 0xfe, 0x17, 0x19, 0x03, 0xb5, 0x02, 0x02, 0x34, 0x67, 0xde, 0xc7, 0x27, 0x3f, 0xf7, 0x48, 0x79, 0xb9, 0x29, 0x67, 0xa2, 0xa4, 0x3a, 0x5a, 0x18, 0x3d, 0x33 },
+      { 0xd3, 0x33, 0x81, 0x93, 0xb6, 0x45, 0x53, 0xdb, 0xd3, 0x8d, 0x14, 0x4b, 0xea, 0x71, 0xc5, 0x91, 0x5b, 0xb1, 0x10, 0xe2, 0xd8, 0x81, 0x80, 0xdb, 0xc5, 0xdb, 0x36, 0x4f, 0xd6, 0x17, 0x1d, 0xf3, 0x17, 0xfc, 0x72, 0x68, 0x83, 0x1b, 0x5a, 0xef, 0x75, 0xe4, 0x34, 0x2b, 0x2f, 0xad, 0x87, 0x97, 0xba, 0x39, 0xed, 0xdc, 0xef, 0x80, 0xe6, 0xec, 0x08, 0x15, 0x93, 0x50, 0xb1, 0xad, 0x69, 0x6d },
+      { 0xe1, 0x59, 0x0d, 0x58, 0x5a, 0x3d, 0x39, 0xf7, 0xcb, 0x59, 0x9a, 0xbd, 0x47, 0x90, 0x70, 0x96, 0x64, 0x09, 0xa6, 0x84, 0x6d, 0x43, 0x77, 0xac, 0xf4, 0x47, 0x1d, 0x06, 0x5d, 0x5d, 0xb9, 0x41, 0x29, 0xcc, 0x9b, 0xe9, 0x25, 0x73, 0xb0, 0x5e, 0xd2, 0x26, 0xbe, 0x1e, 0x9b, 0x7c, 0xb0, 0xca, 0xbe, 0x87, 0x91, 0x85, 0x89, 0xf8, 0x0d, 0xad, 0xd4, 0xef, 0x5e, 0xf2, 0x5a, 0x93, 0xd2, 0x8e },
+      { 0xf8, 0xf3, 0x72, 0x6a, 0xc5, 0xa2, 0x6c, 0xc8, 0x01, 0x32, 0x49, 0x3a, 0x6f, 0xed, 0xcb, 0x0e, 0x60, 0x76, 0x0c, 0x09, 0xcf, 0xc8, 0x4c, 0xad, 0x17, 0x81, 0x75, 0x98, 0x68, 0x19, 0x66, 0x5e, 0x76, 0x84, 0x2d, 0x7b, 0x9f, 0xed, 0xf7, 0x6d, 0xdd, 0xeb, 0xf5, 0xd3, 0xf5, 0x6f, 0xaa, 0xad, 0x44, 0x77, 0x58, 0x7a, 0xf2, 0x16, 0x06, 0xd3, 0x96, 0xae, 0x57, 0x0d, 0x8e, 0x71, 0x9a, 0xf2 },
+      { 0x30, 0x18, 0x60, 0x55, 0xc0, 0x79, 0x49, 0x94, 0x81, 0x83, 0xc8, 0x50, 0xe9, 0xa7, 0x56, 0xcc, 0x09, 0x93, 0x7e, 0x24, 0x7d, 0x9d, 0x92, 0x8e, 0x86, 0x9e, 0x20, 0xba, 0xfc, 0x3c, 0xd9, 0x72, 0x17, 0x19, 0xd3, 0x4e, 0x04, 0xa0, 0x89, 0x9b, 0x92, 0xc7, 0x36, 0x08, 0x45, 0x50, 0x18, 0x68, 0x86, 0xef, 0xba, 0x2e, 0x79, 0x0d, 0x8b, 0xe6, 0xeb, 0xf0, 0x40, 0xb2, 0x09, 0xc4, 0x39, 0xa4 },
+      { 0xf3, 0xc4, 0x27, 0x6c, 0xb8, 0x63, 0x63, 0x77, 0x12, 0xc2, 0x41, 0xc4, 0x44, 0xc5, 0xcc, 0x1e, 0x35, 0x54, 0xe0, 0xfd, 0xdb, 0x17, 0x4d, 0x03, 0x58, 0x19, 0xdd, 0x83, 0xeb, 0x70, 0x0b, 0x4c, 0xe8, 0x8d, 0xf3, 0xab, 0x38, 0x41, 0xba, 0x02, 0x08, 0x5e, 0x1a, 0x99, 0xb4, 0xe1, 0x73, 0x10, 0xc5, 0x34, 0x10, 0x75, 0xc0, 0x45, 0x8b, 0xa3, 0x76, 0xc9, 0x5a, 0x68, 0x18, 0xfb, 0xb3, 0xe2 },
+      { 0x0a, 0xa0, 0x07, 0xc4, 0xdd, 0x9d, 0x58, 0x32, 0x39, 0x30, 0x40, 0xa1, 0x58, 0x3c, 0x93, 0x0b, 0xca, 0x7d, 0xc5, 0xe7, 0x7e, 0xa5, 0x3a, 0xdd, 0x7e, 0x2b, 0x3f, 0x7c, 0x8e, 0x23, 0x13, 0x68, 0x04, 0x35, 0x20, 0xd4, 0xa3, 0xef, 0x53, 0xc9, 0x69, 0xb6, 0xbb, 0xfd, 0x02, 0x59, 0x46, 0xf6, 0x32, 0xbd, 0x7f, 0x76, 0x5d, 0x53, 0xc2, 0x10, 0x03, 0xb8, 0xf9, 0x83, 0xf7, 0x5e, 0x2a, 0x6a },
+      { 0x08, 0xe9, 0x46, 0x47, 0x20, 0x53, 0x3b, 0x23, 0xa0, 0x4e, 0xc2, 0x4f, 0x7a, 0xe8, 0xc1, 0x03, 0x14, 0x5f, 0x76, 0x53, 0x87, 0xd7, 0x38, 0x77, 0x7d, 0x3d, 0x34, 0x34, 0x77, 0xfd, 0x1c, 0x58, 0xdb, 0x05, 0x21, 0x42, 0xca, 0xb7, 0x54, 0xea, 0x67, 0x43, 0x78, 0xe1, 0x87, 0x66, 0xc5, 0x35, 0x42, 0xf7, 0x19, 0x70, 0x17, 0x1c, 0xc4, 0xf8, 0x16, 0x94, 0x24, 0x6b, 0x71, 0x7d, 0x75, 0x64 },
+      { 0xd3, 0x7f, 0xf7, 0xad, 0x29, 0x79, 0x93, 0xe7, 0xec, 0x21, 0xe0, 0xf1, 0xb4, 0xb5, 0xae, 0x71, 0x9c, 0xdc, 0x83, 0xc5, 0xdb, 0x68, 0x75, 0x27, 0xf2, 0x75, 0x16, 0xcb, 0xff, 0xa8, 0x22, 0x88, 0x8a, 0x68, 0x10, 0xee, 0x5c, 0x1c, 0xa7, 0xbf, 0xe3, 0x32, 0x11, 0x19, 0xbe, 0x1a, 0xb7, 0xbf, 0xa0, 0xa5, 0x02, 0x67, 0x1c, 0x83, 0x29, 0x49, 0x4d, 0xf7, 0xad, 0x6f, 0x52, 0x2d, 0x44, 0x0f },
+      { 0xdd, 0x90, 0x42, 0xf6, 0xe4, 0x64, 0xdc, 0xf8, 0x6b, 0x12, 0x62, 0xf6, 0xac, 0xcf, 0xaf, 0xbd, 0x8c, 0xfd, 0x90, 0x2e, 0xd3, 0xed, 0x89, 0xab, 0xf7, 0x8f, 0xfa, 0x48, 0x2d, 0xbd, 0xee, 0xb6, 0x96, 0x98, 0x42, 0x39, 0x4c, 0x9a, 0x11, 0x68, 0xae, 0x3d, 0x48, 0x1a, 0x01, 0x78, 0x42, 0xf6, 0x60, 0x00, 0x2d, 0x42, 0x44, 0x7c, 0x6b, 0x22, 0xf7, 0xb7, 0x2f, 0x21, 0xaa, 0xe0, 0x21, 0xc9 },
+      { 0xbd, 0x96, 0x5b, 0xf3, 0x1e, 0x87, 0xd7, 0x03, 0x27, 0x53, 0x6f, 0x2a, 0x34, 0x1c, 0xeb, 0xc4, 0x76, 0x8e, 0xca, 0x27, 0x5f, 0xa0, 0x5e, 0xf9, 0x8f, 0x7f, 0x1b, 0x71, 0xa0, 0x35, 0x12, 0x98, 0xde, 0x00, 0x6f, 0xba, 0x73, 0xfe, 0x67, 0x33, 0xed, 0x01, 0xd7, 0x58, 0x01, 0xb4, 0xa9, 0x28, 0xe5, 0x42, 0x31, 0xb3, 0x8e, 0x38, 0xc5, 0x62, 0xb2, 0xe3, 0x3e, 0xa1, 0x28, 0x49, 0x92, 0xfa },
+      { 0x65, 0x67, 0x6d, 0x80, 0x06, 0x17, 0x97, 0x2f, 0xbd, 0x87, 0xe4, 0xb9, 0x51, 0x4e, 0x1c, 0x67, 0x40, 0x2b, 0x7a, 0x33, 0x10, 0x96, 0xd3, 0xbf, 0xac, 0x22, 0xf1, 0xab, 0xb9, 0x53, 0x74, 0xab, 0xc9, 0x42, 0xf1, 0x6e, 0x9a, 0xb0, 0xea, 0xd3, 0x3b, 0x87, 0xc9, 0x19, 0x68, 0xa6, 0xe5, 0x09, 0xe1, 0x19, 0xff, 0x07, 0x78, 0x7b, 0x3e, 0xf4, 0x83, 0xe1, 0xdc, 0xdc, 0xcf, 0x6e, 0x30, 0x22 },
+      { 0x93, 0x9f, 0xa1, 0x89, 0x69, 0x9c, 0x5d, 0x2c, 0x81, 0xdd, 0xd1, 0xff, 0xc1, 0xfa, 0x20, 0x7c, 0x97, 0x0b, 0x6a, 0x36, 0x85, 0xbb, 0x29, 0xce, 0x1d, 0x3e, 0x99, 0xd4, 0x2f, 0x2f, 0x74, 0x42, 0xda, 0x53, 0xe9, 0x5a, 0x72, 0x90, 0x73, 0x14, 0xf4, 0x58, 0x83, 0x99, 0xa3, 0xff, 0x5b, 0x0a, 0x92, 0xbe, 0xb3, 0xf6, 0xbe, 0x26, 0x94, 0xf9, 0xf8, 0x6e, 0xcf, 0x29, 0x52, 0xd5, 0xb4, 0x1c },
+      { 0xc5, 0x16, 0x54, 0x17, 0x01, 0x86, 0x3f, 0x91, 0x00, 0x5f, 0x31, 0x41, 0x08, 0xce, 0xec, 0xe3, 0xc6, 0x43, 0xe0, 0x4f, 0xc8, 0xc4, 0x2f, 0xd2, 0xff, 0x55, 0x62, 0x20, 0xe6, 0x16, 0xaa, 0xa6, 0xa4, 0x8a, 0xeb, 0x97, 0xa8, 0x4b, 0xad, 0x74, 0x78, 0x2e, 0x8d, 0xff, 0x96, 0xa1, 0xa2, 0xfa, 0x94, 0x93, 0x39, 0xd7, 0x22, 0xed, 0xca, 0xa3, 0x2b, 0x57, 0x06, 0x70, 0x41, 0xdf, 0x88, 0xcc },
+      { 0x98, 0x7f, 0xd6, 0xe0, 0xd6, 0x85, 0x7c, 0x55, 0x3e, 0xae, 0xbb, 0x3d, 0x34, 0x97, 0x0a, 0x2c, 0x2f, 0x6e, 0x89, 0xa3, 0x54, 0x8f, 0x49, 0x25, 0x21, 0x72, 0x2b, 0x80, 0xa1, 0xc2, 0x1a, 0x15, 0x38, 0x92, 0x34, 0x6d, 0x2c, 0xba, 0x64, 0x44, 0x21, 0x2d, 0x56, 0xda, 0x9a, 0x26, 0xe3, 0x24, 0xdc, 0xcb, 0xc0, 0xdc, 0xde, 0x85, 0xd4, 0xd2, 0xee, 0x43, 0x99, 0xee, 0xc5, 0xa6, 0x4e, 0x8f },
+      { 0xae, 0x56, 0xde, 0xb1, 0xc2, 0x32, 0x8d, 0x9c, 0x40, 0x17, 0x70, 0x6b, 0xce, 0x6e, 0x99, 0xd4, 0x13, 0x49, 0x05, 0x3b, 0xa9, 0xd3, 0x36, 0xd6, 0x77, 0xc4, 0xc2, 0x7d, 0x9f, 0xd5, 0x0a, 0xe6, 0xae, 0xe1, 0x7e, 0x85, 0x31, 0x54, 0xe1, 0xf4, 0xfe, 0x76, 0x72, 0x34, 0x6d, 0xa2, 0xea, 0xa3, 0x1e, 0xea, 0x53, 0xfc, 0xf2, 0x4a, 0x22, 0x80, 0x4f, 0x11, 0xd0, 0x3d, 0xa6, 0xab, 0xfc, 0x2b },
+      { 0x49, 0xd6, 0xa6, 0x08, 0xc9, 0xbd, 0xe4, 0x49, 0x18, 0x70, 0x49, 0x85, 0x72, 0xac, 0x31, 0xaa, 0xc3, 0xfa, 0x40, 0x93, 0x8b, 0x38, 0xa7, 0x81, 0x8f, 0x72, 0x38, 0x3e, 0xb0, 0x40, 0xad, 0x39, 0x53, 0x2b, 0xc0, 0x65, 0x71, 0xe1, 0x3d, 0x76, 0x7e, 0x69, 0x45, 0xab, 0x77, 0xc0, 0xbd, 0xc3, 0xb0, 0x28, 0x42, 0x53, 0x34, 0x3f, 0x9f, 0x6c, 0x12, 0x44, 0xeb, 0xf2, 0xff, 0x0d, 0xf8, 0x66 },
+      { 0xda, 0x58, 0x2a, 0xd8, 0xc5, 0x37, 0x0b, 0x44, 0x69, 0xaf, 0x86, 0x2a, 0xa6, 0x46, 0x7a, 0x22, 0x93, 0xb2, 0xb2, 0x8b, 0xd8, 0x0a, 0xe0, 0xe9, 0x1f, 0x42, 0x5a, 0xd3, 0xd4, 0x72, 0x49, 0xfd, 0xf9, 0x88, 0x25, 0xcc, 0x86, 0xf1, 0x40, 0x28, 0xc3, 0x30, 0x8c, 0x98, 0x04, 0xc7, 0x8b, 0xfe, 0xee, 0xee, 0x46, 0x14, 0x44, 0xce, 0x24, 0x36, 0x87, 0xe1, 0xa5, 0x05, 0x22, 0x45, 0x6a, 0x1d },
+      { 0xd5, 0x26, 0x6a, 0xa3, 0x33, 0x11, 0x94, 0xae, 0xf8, 0x52, 0xee, 0xd8, 0x6d, 0x7b, 0x5b, 0x26, 0x33, 0xa0, 0xaf, 0x1c, 0x73, 0x59, 0x06, 0xf2, 0xe1, 0x32, 0x79, 0xf1, 0x49, 0x31, 0xa9, 0xfc, 0x3b, 0x0e, 0xac, 0x5c, 0xe9, 0x24, 0x52, 0x73, 0xbd, 0x1a, 0xa9, 0x29, 0x05, 0xab, 0xe1, 0x62, 0x78, 0xef, 0x7e, 0xfd, 0x47, 0x69, 0x47, 0x89, 0xa7, 0x28, 0x3b, 0x77, 0xda, 0x3c, 0x70, 0xf8 },
+      { 0x29, 0x62, 0x73, 0x4c, 0x28, 0x25, 0x21, 0x86, 0xa9, 0xa1, 0x11, 0x1c, 0x73, 0x2a, 0xd4, 0xde, 0x45, 0x06, 0xd4, 0xb4, 0x48, 0x09, 0x16, 0x30, 0x3e, 0xb7, 0x99, 0x1d, 0x65, 0x9c, 0xcd, 0xa0, 0x7a, 0x99, 0x11, 0x91, 0x4b, 0xc7, 0x5c, 0x41, 0x8a, 0xb7, 0xa4, 0x54, 0x17, 0x57, 0xad, 0x05, 0x47, 0x96, 0xe2, 0x67, 0x97, 0xfe, 0xaf, 0x36, 0xe9, 0xf6, 0xad, 0x43, 0xf1, 0x4b, 0x35, 0xa4 },
+      { 0xe8, 0xb7, 0x9e, 0xc5, 0xd0, 0x6e, 0x11, 0x1b, 0xdf, 0xaf, 0xd7, 0x1e, 0x9f, 0x57, 0x60, 0xf0, 0x0a, 0xc8, 0xac, 0x5d, 0x8b, 0xf7, 0x68, 0xf9, 0xff, 0x6f, 0x08, 0xb8, 0xf0, 0x26, 0x09, 0x6b, 0x1c, 0xc3, 0xa4, 0xc9, 0x73, 0x33, 0x30, 0x19, 0xf1, 0xe3, 0x55, 0x3e, 0x77, 0xda, 0x3f, 0x98, 0xcb, 0x9f, 0x54, 0x2e, 0x0a, 0x90, 0xe5, 0xf8, 0xa9, 0x40, 0xcc, 0x58, 0xe5, 0x98, 0x44, 0xb3 },
+      { 0xdf, 0xb3, 0x20, 0xc4, 0x4f, 0x9d, 0x41, 0xd1, 0xef, 0xdc, 0xc0, 0x15, 0xf0, 0x8d, 0xd5, 0x53, 0x9e, 0x52, 0x6e, 0x39, 0xc8, 0x7d, 0x50, 0x9a, 0xe6, 0x81, 0x2a, 0x96, 0x9e, 0x54, 0x31, 0xbf, 0x4f, 0xa7, 0xd9, 0x1f, 0xfd, 0x03, 0xb9, 0x81, 0xe0, 0xd5, 0x44, 0xcf, 0x72, 0xd7, 0xb1, 0xc0, 0x37, 0x4f, 0x88, 0x01, 0x48, 0x2e, 0x6d, 0xea, 0x2e, 0xf9, 0x03, 0x87, 0x7e, 0xba, 0x67, 0x5e },
+      { 0xd8, 0x86, 0x75, 0x11, 0x8f, 0xdb, 0x55, 0xa5, 0xfb, 0x36, 0x5a, 0xc2, 0xaf, 0x1d, 0x21, 0x7b, 0xf5, 0x26, 0xce, 0x1e, 0xe9, 0xc9, 0x4b, 0x2f, 0x00, 0x90, 0xb2, 0xc5, 0x8a, 0x06, 0xca, 0x58, 0x18, 0x7d, 0x7f, 0xe5, 0x7c, 0x7b, 0xed, 0x9d, 0x26, 0xfc, 0xa0, 0x67, 0xb4, 0x11, 0x0e, 0xef, 0xcd, 0x9a, 0x0a, 0x34, 0x5d, 0xe8, 0x72, 0xab, 0xe2, 0x0d, 0xe3, 0x68, 0x00, 0x1b, 0x07, 0x45 },
+      { 0xb8, 0x93, 0xf2, 0xfc, 0x41, 0xf7, 0xb0, 0xdd, 0x6e, 0x2f, 0x6a, 0xa2, 0xe0, 0x37, 0x0c, 0x0c, 0xff, 0x7d, 0xf0, 0x9e, 0x3a, 0xcf, 0xcc, 0x0e, 0x92, 0x0b, 0x6e, 0x6f, 0xad, 0x0e, 0xf7, 0x47, 0xc4, 0x06, 0x68, 0x41, 0x7d, 0x34, 0x2b, 0x80, 0xd2, 0x35, 0x1e, 0x8c, 0x17, 0x5f, 0x20, 0x89, 0x7a, 0x06, 0x2e, 0x97, 0x65, 0xe6, 0xc6, 0x7b, 0x53, 0x9b, 0x6b, 0xa8, 0xb9, 0x17, 0x05, 0x45 },
+      { 0x6c, 0x67, 0xec, 0x56, 0x97, 0xac, 0xcd, 0x23, 0x5c, 0x59, 0xb4, 0x86, 0xd7, 0xb7, 0x0b, 0xae, 0xed, 0xcb, 0xd4, 0xaa, 0x64, 0xeb, 0xd4, 0xee, 0xf3, 0xc7, 0xea, 0xc1, 0x89, 0x56, 0x1a, 0x72, 0x62, 0x50, 0xae, 0xc4, 0xd4, 0x8c, 0xad, 0xca, 0xfb, 0xbe, 0x2c, 0xe3, 0xc1, 0x6c, 0xe2, 0xd6, 0x91, 0xa8, 0xcc, 0xe0, 0x6e, 0x88, 0x79, 0x55, 0x6d, 0x44, 0x83, 0xed, 0x71, 0x65, 0xc0, 0x63 },
+      { 0xf1, 0xaa, 0x2b, 0x04, 0x4f, 0x8f, 0x0c, 0x63, 0x8a, 0x3f, 0x36, 0x2e, 0x67, 0x7b, 0x5d, 0x89, 0x1d, 0x6f, 0xd2, 0xab, 0x07, 0x65, 0xf6, 0xee, 0x1e, 0x49, 0x87, 0xde, 0x05, 0x7e, 0xad, 0x35, 0x78, 0x83, 0xd9, 0xb4, 0x05, 0xb9, 0xd6, 0x09, 0xee, 0xa1, 0xb8, 0x69, 0xd9, 0x7f, 0xb1, 0x6d, 0x9b, 0x51, 0x01, 0x7c, 0x55, 0x3f, 0x3b, 0x93, 0xc0, 0xa1, 0xe0, 0xf1, 0x29, 0x6f, 0xed, 0xcd },
+      { 0xcb, 0xaa, 0x25, 0x95, 0x72, 0xd4, 0xae, 0xbf, 0xc1, 0x91, 0x7a, 0xcd, 0xdc, 0x58, 0x2b, 0x9f, 0x8d, 0xfa, 0xa9, 0x28, 0xa1, 0x98, 0xca, 0x7a, 0xcd, 0x0f, 0x2a, 0xa7, 0x6a, 0x13, 0x4a, 0x90, 0x25, 0x2e, 0x62, 0x98, 0xa6, 0x5b, 0x08, 0x18, 0x6a, 0x35, 0x0d, 0x5b, 0x76, 0x26, 0x69, 0x9f, 0x8c, 0xb7, 0x21, 0xa3, 0xea, 0x59, 0x21, 0xb7, 0x53, 0xae, 0x3a, 0x2d, 0xce, 0x24, 0xba, 0x3a },
+      { 0xfa, 0x15, 0x49, 0xc9, 0x79, 0x6c, 0xd4, 0xd3, 0x03, 0xdc, 0xf4, 0x52, 0xc1, 0xfb, 0xd5, 0x74, 0x4f, 0xd9, 0xb9, 0xb4, 0x70, 0x03, 0xd9, 0x20, 0xb9, 0x2d, 0xe3, 0x48, 0x39, 0xd0, 0x7e, 0xf2, 0xa2, 0x9d, 0xed, 0x68, 0xf6, 0xfc, 0x9e, 0x6c, 0x45, 0xe0, 0x71, 0xa2, 0xe4, 0x8b, 0xd5, 0x0c, 0x50, 0x84, 0xe9, 0x6b, 0x65, 0x7d, 0xd0, 0x40, 0x40, 0x45, 0xa1, 0xdd, 0xef, 0xe2, 0x82, 0xed },
+      { 0x5c, 0xf2, 0xac, 0x89, 0x7a, 0xb4, 0x44, 0xdc, 0xb5, 0xc8, 0xd8, 0x7c, 0x49, 0x5d, 0xbd, 0xb3, 0x4e, 0x18, 0x38, 0xb6, 0xb6, 0x29, 0x42, 0x7c, 0xaa, 0x51, 0x70, 0x2a, 0xd0, 0xf9, 0x68, 0x85, 0x25, 0xf1, 0x3b, 0xec, 0x50, 0x3a, 0x3c, 0x3a, 0x2c, 0x80, 0xa6, 0x5e, 0x0b, 0x57, 0x15, 0xe8, 0xaf, 0xab, 0x00, 0xff, 0xa5, 0x6e, 0xc4, 0x55, 0xa4, 0x9a, 0x1a, 0xd3, 0x0a, 0xa2, 0x4f, 0xcd },
+      { 0x9a, 0xaf, 0x80, 0x20, 0x7b, 0xac, 0xe1, 0x7b, 0xb7, 0xab, 0x14, 0x57, 0x57, 0xd5, 0x69, 0x6b, 0xde, 0x32, 0x40, 0x6e, 0xf2, 0x2b, 0x44, 0x29, 0x2e, 0xf6, 0x5d, 0x45, 0x19, 0xc3, 0xbb, 0x2a, 0xd4, 0x1a, 0x59, 0xb6, 0x2c, 0xc3, 0xe9, 0x4b, 0x6f, 0xa9, 0x6d, 0x32, 0xa7, 0xfa, 0xad, 0xae, 0x28, 0xaf, 0x7d, 0x35, 0x09, 0x72, 0x19, 0xaa, 0x3f, 0xd8, 0xcd, 0xa3, 0x1e, 0x40, 0xc2, 0x75 },
+      { 0xaf, 0x88, 0xb1, 0x63, 0x40, 0x2c, 0x86, 0x74, 0x5c, 0xb6, 0x50, 0xc2, 0x98, 0x8f, 0xb9, 0x52, 0x11, 0xb9, 0x4b, 0x03, 0xef, 0x29, 0x0e, 0xed, 0x96, 0x62, 0x03, 0x42, 0x41, 0xfd, 0x51, 0xcf, 0x39, 0x8f, 0x80, 0x73, 0xe3, 0x69, 0x35, 0x4c, 0x43, 0xea, 0xe1, 0x05, 0x2f, 0x9b, 0x63, 0xb0, 0x81, 0x91, 0xca, 0xa1, 0x38, 0xaa, 0x54, 0xfe, 0xa8, 0x89, 0xcc, 0x70, 0x24, 0x23, 0x68, 0x97 },
+      { 0x48, 0xfa, 0x7d, 0x64, 0xe1, 0xce, 0xee, 0x27, 0xb9, 0x86, 0x4d, 0xb5, 0xad, 0xa4, 0xb5, 0x3d, 0x00, 0xc9, 0xbc, 0x76, 0x26, 0x55, 0x58, 0x13, 0xd3, 0xcd, 0x67, 0x30, 0xab, 0x3c, 0xc0, 0x6f, 0xf3, 0x42, 0xd7, 0x27, 0x90, 0x5e, 0x33, 0x17, 0x1b, 0xde, 0x6e, 0x84, 0x76, 0xe7, 0x7f, 0xb1, 0x72, 0x08, 0x61, 0xe9, 0x4b, 0x73, 0xa2, 0xc5, 0x38, 0xd2, 0x54, 0x74, 0x62, 0x85, 0xf4, 0x30 },
+      { 0x0e, 0x6f, 0xd9, 0x7a, 0x85, 0xe9, 0x04, 0xf8, 0x7b, 0xfe, 0x85, 0xbb, 0xeb, 0x34, 0xf6, 0x9e, 0x1f, 0x18, 0x10, 0x5c, 0xf4, 0xed, 0x4f, 0x87, 0xae, 0xc3, 0x6c, 0x6e, 0x8b, 0x5f, 0x68, 0xbd, 0x2a, 0x6f, 0x3d, 0xc8, 0xa9, 0xec, 0xb2, 0xb6, 0x1d, 0xb4, 0xee, 0xdb, 0x6b, 0x2e, 0xa1, 0x0b, 0xf9, 0xcb, 0x02, 0x51, 0xfb, 0x0f, 0x8b, 0x34, 0x4a, 0xbf, 0x7f, 0x36, 0x6b, 0x6d, 0xe5, 0xab },
+      { 0x06, 0x62, 0x2d, 0xa5, 0x78, 0x71, 0x76, 0x28, 0x7f, 0xdc, 0x8f, 0xed, 0x44, 0x0b, 0xad, 0x18, 0x7d, 0x83, 0x00, 0x99, 0xc9, 0x4e, 0x6d, 0x04, 0xc8, 0xe9, 0xc9, 0x54, 0xcd, 0xa7, 0x0c, 0x8b, 0xb9, 0xe1, 0xfc, 0x4a, 0x6d, 0x0b, 0xaa, 0x83, 0x1b, 0x9b, 0x78, 0xef, 0x66, 0x48, 0x68, 0x1a, 0x48, 0x67, 0xa1, 0x1d, 0xa9, 0x3e, 0xe3, 0x6e, 0x5e, 0x6a, 0x37, 0xd8, 0x7f, 0xc6, 0x3f, 0x6f },
+      { 0x1d, 0xa6, 0x77, 0x2b, 0x58, 0xfa, 0xbf, 0x9c, 0x61, 0xf6, 0x8d, 0x41, 0x2c, 0x82, 0xf1, 0x82, 0xc0, 0x23, 0x6d, 0x7d, 0x57, 0x5e, 0xf0, 0xb5, 0x8d, 0xd2, 0x24, 0x58, 0xd6, 0x43, 0xcd, 0x1d, 0xfc, 0x93, 0xb0, 0x38, 0x71, 0xc3, 0x16, 0xd8, 0x43, 0x0d, 0x31, 0x29, 0x95, 0xd4, 0x19, 0x7f, 0x08, 0x74, 0xc9, 0x91, 0x72, 0xba, 0x00, 0x4a, 0x01, 0xee, 0x29, 0x5a, 0xba, 0xc2, 0x4e, 0x46 },
+      { 0x3c, 0xd2, 0xd9, 0x32, 0x0b, 0x7b, 0x1d, 0x5f, 0xb9, 0xaa, 0xb9, 0x51, 0xa7, 0x60, 0x23, 0xfa, 0x66, 0x7b, 0xe1, 0x4a, 0x91, 0x24, 0xe3, 0x94, 0x51, 0x39, 0x18, 0xa3, 0xf4, 0x40, 0x96, 0xae, 0x49, 0x04, 0xba, 0x0f, 0xfc, 0x15, 0x0b, 0x63, 0xbc, 0x7a, 0xb1, 0xee, 0xb9, 0xa6, 0xe2, 0x57, 0xe5, 0xc8, 0xf0, 0x00, 0xa7, 0x03, 0x94, 0xa5, 0xaf, 0xd8, 0x42, 0x71, 0x5d, 0xe1, 0x5f, 0x29 },
+      { 0x04, 0xcd, 0xc1, 0x4f, 0x74, 0x34, 0xe0, 0xb4, 0xbe, 0x70, 0xcb, 0x41, 0xdb, 0x4c, 0x77, 0x9a, 0x88, 0xea, 0xef, 0x6a, 0xcc, 0xeb, 0xcb, 0x41, 0xf2, 0xd4, 0x2f, 0xff, 0xe7, 0xf3, 0x2a, 0x8e, 0x28, 0x1b, 0x5c, 0x10, 0x3a, 0x27, 0x02, 0x1d, 0x0d, 0x08, 0x36, 0x22, 0x50, 0x75, 0x3c, 0xdf, 0x70, 0x29, 0x21, 0x95, 0xa5, 0x3a, 0x48, 0x72, 0x8c, 0xeb, 0x58, 0x44, 0xc2, 0xd9, 0x8b, 0xab },
+      { 0x90, 0x71, 0xb7, 0xa8, 0xa0, 0x75, 0xd0, 0x09, 0x5b, 0x8f, 0xb3, 0xae, 0x51, 0x13, 0x78, 0x57, 0x35, 0xab, 0x98, 0xe2, 0xb5, 0x2f, 0xaf, 0x91, 0xd5, 0xb8, 0x9e, 0x44, 0xaa, 0xc5, 0xb5, 0xd4, 0xeb, 0xbf, 0x91, 0x22, 0x3b, 0x0f, 0xf4, 0xc7, 0x19, 0x05, 0xda, 0x55, 0x34, 0x2e, 0x64, 0x65, 0x5d, 0x6e, 0xf8, 0xc8, 0x9a, 0x47, 0x68, 0xc3, 0xf9, 0x3a, 0x6d, 0xc0, 0x36, 0x6b, 0x5b, 0xc8 },
+      { 0xeb, 0xb3, 0x02, 0x40, 0xdd, 0x96, 0xc7, 0xbc, 0x8d, 0x0a, 0xbe, 0x49, 0xaa, 0x4e, 0xdc, 0xbb, 0x4a, 0xfd, 0xc5, 0x1f, 0xf9, 0xaa, 0xf7, 0x20, 0xd3, 0xf9, 0xe7, 0xfb, 0xb0, 0xf9, 0xc6, 0xd6, 0x57, 0x13, 0x50, 0x50, 0x17, 0x69, 0xfc, 0x4e, 0xbd, 0x0b, 0x21, 0x41, 0x24, 0x7f, 0xf4, 0x00, 0xd4, 0xfd, 0x4b, 0xe4, 0x14, 0xed, 0xf3, 0x77, 0x57, 0xbb, 0x90, 0xa3, 0x2a, 0xc5, 0xc6, 0x5a },
+      { 0x85, 0x32, 0xc5, 0x8b, 0xf3, 0xc8, 0x01, 0x5d, 0x9d, 0x1c, 0xbe, 0x00, 0xee, 0xf1, 0xf5, 0x08, 0x2f, 0x8f, 0x36, 0x32, 0xfb, 0xe9, 0xf1, 0xed, 0x4f, 0x9d, 0xfb, 0x1f, 0xa7, 0x9e, 0x82, 0x83, 0x06, 0x6d, 0x77, 0xc4, 0x4c, 0x4a, 0xf9, 0x43, 0xd7, 0x6b, 0x30, 0x03, 0x64, 0xae, 0xcb, 0xd0, 0x64, 0x8c, 0x8a, 0x89, 0x39, 0xbd, 0x20, 0x41, 0x23, 0xf4, 0xb5, 0x62, 0x60, 0x42, 0x2d, 0xec },
+      { 0xfe, 0x98, 0x46, 0xd6, 0x4f, 0x7c, 0x77, 0x08, 0x69, 0x6f, 0x84, 0x0e, 0x2d, 0x76, 0xcb, 0x44, 0x08, 0xb6, 0x59, 0x5c, 0x2f, 0x81, 0xec, 0x6a, 0x28, 0xa7, 0xf2, 0xf2, 0x0c, 0xb8, 0x8c, 0xfe, 0x6a, 0xc0, 0xb9, 0xe9, 0xb8, 0x24, 0x4f, 0x08, 0xbd, 0x70, 0x95, 0xc3, 0x50, 0xc1, 0xd0, 0x84, 0x2f, 0x64, 0xfb, 0x01, 0xbb, 0x7f, 0x53, 0x2d, 0xfc, 0xd4, 0x73, 0x71, 0xb0, 0xae, 0xeb, 0x79 },
+      { 0x28, 0xf1, 0x7e, 0xa6, 0xfb, 0x6c, 0x42, 0x09, 0x2d, 0xc2, 0x64, 0x25, 0x7e, 0x29, 0x74, 0x63, 0x21, 0xfb, 0x5b, 0xda, 0xea, 0x98, 0x73, 0xc2, 0xa7, 0xfa, 0x9d, 0x8f, 0x53, 0x81, 0x8e, 0x89, 0x9e, 0x16, 0x1b, 0xc7, 0x7d, 0xfe, 0x80, 0x90, 0xaf, 0xd8, 0x2b, 0xf2, 0x26, 0x6c, 0x5c, 0x1b, 0xc9, 0x30, 0xa8, 0xd1, 0x54, 0x76, 0x24, 0x43, 0x9e, 0x66, 0x2e, 0xf6, 0x95, 0xf2, 0x6f, 0x24 },
+      { 0xec, 0x6b, 0x7d, 0x7f, 0x03, 0x0d, 0x48, 0x50, 0xac, 0xae, 0x3c, 0xb6, 0x15, 0xc2, 0x1d, 0xd2, 0x52, 0x06, 0xd6, 0x3e, 0x84, 0xd1, 0xdb, 0x8d, 0x95, 0x73, 0x70, 0x73, 0x7b, 0xa0, 0xe9, 0x84, 0x67, 0xea, 0x0c, 0xe2, 0x74, 0xc6, 0x61, 0x99, 0x90, 0x1e, 0xae, 0xc1, 0x8a, 0x08, 0x52, 0x57, 0x15, 0xf5, 0x3b, 0xfd, 0xb0, 0xaa, 0xcb, 0x61, 0x3d, 0x34, 0x2e, 0xbd, 0xce, 0xed, 0xdc, 0x3b },
+      { 0xb4, 0x03, 0xd3, 0x69, 0x1c, 0x03, 0xb0, 0xd3, 0x41, 0x8d, 0xf3, 0x27, 0xd5, 0x86, 0x0d, 0x34, 0xbb, 0xfc, 0xc4, 0x51, 0x9b, 0xfb, 0xce, 0x36, 0xbf, 0x33, 0xb2, 0x08, 0x38, 0x5f, 0xad, 0xb9, 0x18, 0x6b, 0xc7, 0x8a, 0x76, 0xc4, 0x89, 0xd8, 0x9f, 0xd5, 0x7e, 0x7d, 0xc7, 0x54, 0x12, 0xd2, 0x3b, 0xcd, 0x1d, 0xae, 0x84, 0x70, 0xce, 0x92, 0x74, 0x75, 0x4b, 0xb8, 0x58, 0x5b, 0x13, 0xc5 },
+      { 0x31, 0xfc, 0x79, 0x73, 0x8b, 0x87, 0x72, 0xb3, 0xf5, 0x5c, 0xd8, 0x17, 0x88, 0x13, 0xb3, 0xb5, 0x2d, 0x0d, 0xb5, 0xa4, 0x19, 0xd3, 0x0b, 0xa9, 0x49, 0x5c, 0x4b, 0x9d, 0xa0, 0x21, 0x9f, 0xac, 0x6d, 0xf8, 0xe7, 0xc2, 0x3a, 0x81, 0x15, 0x51, 0xa6, 0x2b, 0x82, 0x7f, 0x25, 0x6e, 0xcd, 0xb8, 0x12, 0x4a, 0xc8, 0xa6, 0x79, 0x2c, 0xcf, 0xec, 0xc3, 0xb3, 0x01, 0x27, 0x22, 0xe9, 0x44, 0x63 },
+      { 0xbb, 0x20, 0x39, 0xec, 0x28, 0x70, 0x91, 0xbc, 0xc9, 0x64, 0x2f, 0xc9, 0x00, 0x49, 0xe7, 0x37, 0x32, 0xe0, 0x2e, 0x57, 0x7e, 0x28, 0x62, 0xb3, 0x22, 0x16, 0xae, 0x9b, 0xed, 0xcd, 0x73, 0x0c, 0x4c, 0x28, 0x4e, 0xf3, 0x96, 0x8c, 0x36, 0x8b, 0x7d, 0x37, 0x58, 0x4f, 0x97, 0xbd, 0x4b, 0x4d, 0xc6, 0xef, 0x61, 0x27, 0xac, 0xfe, 0x2e, 0x6a, 0xe2, 0x50, 0x91, 0x24, 0xe6, 0x6c, 0x8a, 0xf4 },
+      { 0xf5, 0x3d, 0x68, 0xd1, 0x3f, 0x45, 0xed, 0xfc, 0xb9, 0xbd, 0x41, 0x5e, 0x28, 0x31, 0xe9, 0x38, 0x35, 0x0d, 0x53, 0x80, 0xd3, 0x43, 0x22, 0x78, 0xfc, 0x1c, 0x0c, 0x38, 0x1f, 0xcb, 0x7c, 0x65, 0xc8, 0x2d, 0xaf, 0xe0, 0x51, 0xd8, 0xc8, 0xb0, 0xd4, 0x4e, 0x09, 0x74, 0xa0, 0xe5, 0x9e, 0xc7, 0xbf, 0x7e, 0xd0, 0x45, 0x9f, 0x86, 0xe9, 0x6f, 0x32, 0x9f, 0xc7, 0x97, 0x52, 0x51, 0x0f, 0xd3 },
+      { 0x8d, 0x56, 0x8c, 0x79, 0x84, 0xf0, 0xec, 0xdf, 0x76, 0x40, 0xfb, 0xc4, 0x83, 0xb5, 0xd8, 0xc9, 0xf8, 0x66, 0x34, 0xf6, 0xf4, 0x32, 0x91, 0x84, 0x1b, 0x30, 0x9a, 0x35, 0x0a, 0xb9, 0xc1, 0x13, 0x7d, 0x24, 0x06, 0x6b, 0x09, 0xda, 0x99, 0x44, 0xba, 0xc5, 0x4d, 0x5b, 0xb6, 0x58, 0x0d, 0x83, 0x60, 0x47, 0xaa, 0xc7, 0x4a, 0xb7, 0x24, 0xb8, 0x87, 0xeb, 0xf9, 0x3d, 0x4b, 0x32, 0xec, 0xa9 },
+      { 0xc0, 0xb6, 0x5c, 0xe5, 0xa9, 0x6f, 0xf7, 0x74, 0xc4, 0x56, 0xca, 0xc3, 0xb5, 0xf2, 0xc4, 0xcd, 0x35, 0x9b, 0x4f, 0xf5, 0x3e, 0xf9, 0x3a, 0x3d, 0xa0, 0x77, 0x8b, 0xe4, 0x90, 0x0d, 0x1e, 0x8d, 0xa1, 0x60, 0x1e, 0x76, 0x9e, 0x8f, 0x1b, 0x02, 0xd2, 0xa2, 0xf8, 0xc5, 0xb9, 0xfa, 0x10, 0xb4, 0x4f, 0x1c, 0x18, 0x69, 0x85, 0x46, 0x8f, 0xee, 0xb0, 0x08, 0x73, 0x02, 0x83, 0xa6, 0x65, 0x7d },
+      { 0x49, 0x00, 0xbb, 0xa6, 0xf5, 0xfb, 0x10, 0x3e, 0xce, 0x8e, 0xc9, 0x6a, 0xda, 0x13, 0xa5, 0xc3, 0xc8, 0x54, 0x88, 0xe0, 0x55, 0x51, 0xda, 0x6b, 0x6b, 0x33, 0xd9, 0x88, 0xe6, 0x11, 0xec, 0x0f, 0xe2, 0xe3, 0xc2, 0xaa, 0x48, 0xea, 0x6a, 0xe8, 0x98, 0x6a, 0x3a, 0x23, 0x1b, 0x22, 0x3c, 0x5d, 0x27, 0xce, 0xc2, 0xea, 0xdd, 0xe9, 0x1c, 0xe0, 0x79, 0x81, 0xee, 0x65, 0x28, 0x62, 0xd1, 0xe4 },
+      { 0xc7, 0xf5, 0xc3, 0x7c, 0x72, 0x85, 0xf9, 0x27, 0xf7, 0x64, 0x43, 0x41, 0x4d, 0x43, 0x57, 0xff, 0x78, 0x96, 0x47, 0xd7, 0xa0, 0x05, 0xa5, 0xa7, 0x87, 0xe0, 0x3c, 0x34, 0x6b, 0x57, 0xf4, 0x9f, 0x21, 0xb6, 0x4f, 0xa9, 0xcf, 0x4b, 0x7e, 0x45, 0x57, 0x3e, 0x23, 0x04, 0x90, 0x17, 0x56, 0x71, 0x21, 0xa9, 0xc3, 0xd4, 0xb2, 0xb7, 0x3e, 0xc5, 0xe9, 0x41, 0x35, 0x77, 0x52, 0x5d, 0xb4, 0x5a },
+      { 0xec, 0x70, 0x96, 0x33, 0x07, 0x36, 0xfd, 0xb2, 0xd6, 0x4b, 0x56, 0x53, 0xe7, 0x47, 0x5d, 0xa7, 0x46, 0xc2, 0x3a, 0x46, 0x13, 0xa8, 0x26, 0x87, 0xa2, 0x80, 0x62, 0xd3, 0x23, 0x63, 0x64, 0x28, 0x4a, 0xc0, 0x17, 0x20, 0xff, 0xb4, 0x06, 0xcf, 0xe2, 0x65, 0xc0, 0xdf, 0x62, 0x6a, 0x18, 0x8c, 0x9e, 0x59, 0x63, 0xac, 0xe5, 0xd3, 0xd5, 0xbb, 0x36, 0x3e, 0x32, 0xc3, 0x8c, 0x21, 0x90, 0xa6 },
+      { 0x82, 0xe7, 0x44, 0xc7, 0x5f, 0x46, 0x49, 0xec, 0x52, 0xb8, 0x07, 0x71, 0xa7, 0x7d, 0x47, 0x5a, 0x3b, 0xc0, 0x91, 0x98, 0x95, 0x56, 0x96, 0x0e, 0x27, 0x6a, 0x5f, 0x9e, 0xad, 0x92, 0xa0, 0x3f, 0x71, 0x87, 0x42, 0xcd, 0xcf, 0xea, 0xee, 0x5c, 0xb8, 0x5c, 0x44, 0xaf, 0x19, 0x8a, 0xdc, 0x43, 0xa4, 0xa4, 0x28, 0xf5, 0xf0, 0xc2, 0xdd, 0xb0, 0xbe, 0x36, 0x05, 0x9f, 0x06, 0xd7, 0xdf, 0x73 },
+      { 0x28, 0x34, 0xb7, 0xa7, 0x17, 0x0f, 0x1f, 0x5b, 0x68, 0x55, 0x9a, 0xb7, 0x8c, 0x10, 0x50, 0xec, 0x21, 0xc9, 0x19, 0x74, 0x0b, 0x78, 0x4a, 0x90, 0x72, 0xf6, 0xe5, 0xd6, 0x9f, 0x82, 0x8d, 0x70, 0xc9, 0x19, 0xc5, 0x03, 0x9f, 0xb1, 0x48, 0xe3, 0x9e, 0x2c, 0x8a, 0x52, 0x11, 0x83, 0x78, 0xb0, 0x64, 0xca, 0x8d, 0x50, 0x01, 0xcd, 0x10, 0xa5, 0x47, 0x83, 0x87, 0xb9, 0x66, 0x71, 0x5e, 0xd6 },
+      { 0x16, 0xb4, 0xad, 0xa8, 0x83, 0xf7, 0x2f, 0x85, 0x3b, 0xb7, 0xef, 0x25, 0x3e, 0xfc, 0xab, 0x0c, 0x3e, 0x21, 0x61, 0x68, 0x7a, 0xd6, 0x15, 0x43, 0xa0, 0xd2, 0x82, 0x4f, 0x91, 0xc1, 0xf8, 0x13, 0x47, 0xd8, 0x6b, 0xe7, 0x09, 0xb1, 0x69, 0x96, 0xe1, 0x7f, 0x2d, 0xd4, 0x86, 0x92, 0x7b, 0x02, 0x88, 0xad, 0x38, 0xd1, 0x30, 0x63, 0xc4, 0xa9, 0x67, 0x2c, 0x39, 0x39, 0x7d, 0x37, 0x89, 0xb6 },
+      { 0x78, 0xd0, 0x48, 0xf3, 0xa6, 0x9d, 0x8b, 0x54, 0xae, 0x0e, 0xd6, 0x3a, 0x57, 0x3a, 0xe3, 0x50, 0xd8, 0x9f, 0x7c, 0x6c, 0xf1, 0xf3, 0x68, 0x89, 0x30, 0xde, 0x89, 0x9a, 0xfa, 0x03, 0x76, 0x97, 0x62, 0x9b, 0x31, 0x4e, 0x5c, 0xd3, 0x03, 0xaa, 0x62, 0xfe, 0xea, 0x72, 0xa2, 0x5b, 0xf4, 0x2b, 0x30, 0x4b, 0x6c, 0x6b, 0xcb, 0x27, 0xfa, 0xe2, 0x1c, 0x16, 0xd9, 0x25, 0xe1, 0xfb, 0xda, 0xc3 },
+      { 0x0f, 0x74, 0x6a, 0x48, 0x74, 0x92, 0x87, 0xad, 0xa7, 0x7a, 0x82, 0x96, 0x1f, 0x05, 0xa4, 0xda, 0x4a, 0xbd, 0xb7, 0xd7, 0x7b, 0x12, 0x20, 0xf8, 0x36, 0xd0, 0x9e, 0xc8, 0x14, 0x35, 0x9c, 0x0e, 0xc0, 0x23, 0x9b, 0x8c, 0x7b, 0x9f, 0xf9, 0xe0, 0x2f, 0x56, 0x9d, 0x1b, 0x30, 0x1e, 0xf6, 0x7c, 0x46, 0x12, 0xd1, 0xde, 0x4f, 0x73, 0x0f, 0x81, 0xc1, 0x2c, 0x40, 0xcc, 0x06, 0x3c, 0x5c, 0xaa },
+      { 0xf0, 0xfc, 0x85, 0x9d, 0x3b, 0xd1, 0x95, 0xfb, 0xdc, 0x2d, 0x59, 0x1e, 0x4c, 0xda, 0xc1, 0x51, 0x79, 0xec, 0x0f, 0x1d, 0xc8, 0x21, 0xc1, 0x1d, 0xf1, 0xf0, 0xc1, 0xd2, 0x6e, 0x62, 0x60, 0xaa, 0xa6, 0x5b, 0x79, 0xfa, 0xfa, 0xca, 0xfd, 0x7d, 0x3a, 0xd6, 0x1e, 0x60, 0x0f, 0x25, 0x09, 0x05, 0xf5, 0x87, 0x8c, 0x87, 0x45, 0x28, 0x97, 0x64, 0x7a, 0x35, 0xb9, 0x95, 0xbc, 0xad, 0xc3, 0xa3 },
+      { 0x26, 0x20, 0xf6, 0x87, 0xe8, 0x62, 0x5f, 0x6a, 0x41, 0x24, 0x60, 0xb4, 0x2e, 0x2c, 0xef, 0x67, 0x63, 0x42, 0x08, 0xce, 0x10, 0xa0, 0xcb, 0xd4, 0xdf, 0xf7, 0x04, 0x4a, 0x41, 0xb7, 0x88, 0x00, 0x77, 0xe9, 0xf8, 0xdc, 0x3b, 0x8d, 0x12, 0x16, 0xd3, 0x37, 0x6a, 0x21, 0xe0, 0x15, 0xb5, 0x8f, 0xb2, 0x79, 0xb5, 0x21, 0xd8, 0x3f, 0x93, 0x88, 0xc7, 0x38, 0x2c, 0x85, 0x05, 0x59, 0x0b, 0x9b },
+      { 0x22, 0x7e, 0x3a, 0xed, 0x8d, 0x2c, 0xb1, 0x0b, 0x91, 0x8f, 0xcb, 0x04, 0xf9, 0xde, 0x3e, 0x6d, 0x0a, 0x57, 0xe0, 0x84, 0x76, 0xd9, 0x37, 0x59, 0xcd, 0x7b, 0x2e, 0xd5, 0x4a, 0x1c, 0xbf, 0x02, 0x39, 0xc5, 0x28, 0xfb, 0x04, 0xbb, 0xf2, 0x88, 0x25, 0x3e, 0x60, 0x1d, 0x3b, 0xc3, 0x8b, 0x21, 0x79, 0x4a, 0xfe, 0xf9, 0x0b, 0x17, 0x09, 0x4a, 0x18, 0x2c, 0xac, 0x55, 0x77, 0x45, 0xe7, 0x5f },
+      { 0x1a, 0x92, 0x99, 0x01, 0xb0, 0x9c, 0x25, 0xf2, 0x7d, 0x6b, 0x35, 0xbe, 0x7b, 0x2f, 0x1c, 0x47, 0x45, 0x13, 0x1f, 0xde, 0xbc, 0xa7, 0xf3, 0xe2, 0x45, 0x19, 0x26, 0x72, 0x04, 0x34, 0xe0, 0xdb, 0x6e, 0x74, 0xfd, 0x69, 0x3a, 0xd2, 0x9b, 0x77, 0x7d, 0xc3, 0x35, 0x5c, 0x59, 0x2a, 0x36, 0x1c, 0x48, 0x73, 0xb0, 0x11, 0x33, 0xa5, 0x7c, 0x2e, 0x3b, 0x70, 0x75, 0xcb, 0xdb, 0x86, 0xf4, 0xfc },
+      { 0x5f, 0xd7, 0x96, 0x8b, 0xc2, 0xfe, 0x34, 0xf2, 0x20, 0xb5, 0xe3, 0xdc, 0x5a, 0xf9, 0x57, 0x17, 0x42, 0xd7, 0x3b, 0x7d, 0x60, 0x81, 0x9f, 0x28, 0x88, 0xb6, 0x29, 0x07, 0x2b, 0x96, 0xa9, 0xd8, 0xab, 0x2d, 0x91, 0xb8, 0x2d, 0x0a, 0x9a, 0xab, 0xa6, 0x1b, 0xbd, 0x39, 0x95, 0x81, 0x32, 0xfc, 0xc4, 0x25, 0x70, 0x23, 0xd1, 0xec, 0xa5, 0x91, 0xb3, 0x05, 0x4e, 0x2d, 0xc8, 0x1c, 0x82, 0x00 },
+      { 0xdf, 0xcc, 0xe8, 0xcf, 0x32, 0x87, 0x0c, 0xc6, 0xa5, 0x03, 0xea, 0xda, 0xfc, 0x87, 0xfd, 0x6f, 0x78, 0x91, 0x8b, 0x9b, 0x4d, 0x07, 0x37, 0xdb, 0x68, 0x10, 0xbe, 0x99, 0x6b, 0x54, 0x97, 0xe7, 0xe5, 0xcc, 0x80, 0xe3, 0x12, 0xf6, 0x1e, 0x71, 0xff, 0x3e, 0x96, 0x24, 0x43, 0x60, 0x73, 0x15, 0x64, 0x03, 0xf7, 0x35, 0xf5, 0x6b, 0x0b, 0x01, 0x84, 0x5c, 0x18, 0xf6, 0xca, 0xf7, 0x72, 0xe6 },
+      { 0x02, 0xf7, 0xef, 0x3a, 0x9c, 0xe0, 0xff, 0xf9, 0x60, 0xf6, 0x70, 0x32, 0xb2, 0x96, 0xef, 0xca, 0x30, 0x61, 0xf4, 0x93, 0x4d, 0x69, 0x07, 0x49, 0xf2, 0xd0, 0x1c, 0x35, 0xc8, 0x1c, 0x14, 0xf3, 0x9a, 0x67, 0xfa, 0x35, 0x0b, 0xc8, 0xa0, 0x35, 0x9b, 0xf1, 0x72, 0x4b, 0xff, 0xc3, 0xbc, 0xa6, 0xd7, 0xc7, 0xbb, 0xa4, 0x79, 0x1f, 0xd5, 0x22, 0xa3, 0xad, 0x35, 0x3c, 0x02, 0xec, 0x5a, 0xa8 },
+      { 0x64, 0xbe, 0x5c, 0x6a, 0xba, 0x65, 0xd5, 0x94, 0x84, 0x4a, 0xe7, 0x8b, 0xb0, 0x22, 0xe5, 0xbe, 0xbe, 0x12, 0x7f, 0xd6, 0xb6, 0xff, 0xa5, 0xa1, 0x37, 0x03, 0x85, 0x5a, 0xb6, 0x3b, 0x62, 0x4d, 0xcd, 0x1a, 0x36, 0x3f, 0x99, 0x20, 0x3f, 0x63, 0x2e, 0xc3, 0x86, 0xf3, 0xea, 0x76, 0x7f, 0xc9, 0x92, 0xe8, 0xed, 0x96, 0x86, 0x58, 0x6a, 0xa2, 0x75, 0x55, 0xa8, 0x59, 0x9d, 0x5b, 0x80, 0x8f },
+      { 0xf7, 0x85, 0x85, 0x50, 0x5c, 0x4e, 0xaa, 0x54, 0xa8, 0xb5, 0xbe, 0x70, 0xa6, 0x1e, 0x73, 0x5e, 0x0f, 0xf9, 0x7a, 0xf9, 0x44, 0xdd, 0xb3, 0x00, 0x1e, 0x35, 0xd8, 0x6c, 0x4e, 0x21, 0x99, 0xd9, 0x76, 0x10, 0x4b, 0x6a, 0xe3, 0x17, 0x50, 0xa3, 0x6a, 0x72, 0x6e, 0xd2, 0x85, 0x06, 0x4f, 0x59, 0x81, 0xb5, 0x03, 0x88, 0x9f, 0xef, 0x82, 0x2f, 0xcd, 0xc2, 0x89, 0x8d, 0xdd, 0xb7, 0x88, 0x9a },
+      { 0xe4, 0xb5, 0x56, 0x60, 0x33, 0x86, 0x95, 0x72, 0xed, 0xfd, 0x87, 0x47, 0x9a, 0x5b, 0xb7, 0x3c, 0x80, 0xe8, 0x75, 0x9b, 0x91, 0x23, 0x28, 0x79, 0xd9, 0x6b, 0x1d, 0xda, 0x36, 0xc0, 0x12, 0x07, 0x6e, 0xe5, 0xa2, 0xed, 0x7a, 0xe2, 0xde, 0x63, 0xef, 0x84, 0x06, 0xa0, 0x6a, 0xea, 0x82, 0xc1, 0x88, 0x03, 0x1b, 0x56, 0x0b, 0xea, 0xfb, 0x58, 0x3f, 0xb3, 0xde, 0x9e, 0x57, 0x95, 0x2a, 0x7e },
+      { 0xe1, 0xb3, 0xe7, 0xed, 0x86, 0x7f, 0x6c, 0x94, 0x84, 0xa2, 0xa9, 0x7f, 0x77, 0x15, 0xf2, 0x5e, 0x25, 0x29, 0x4e, 0x99, 0x2e, 0x41, 0xf6, 0xa7, 0xc1, 0x61, 0xff, 0xc2, 0xad, 0xc6, 0xda, 0xae, 0xb7, 0x11, 0x31, 0x02, 0xd5, 0xe6, 0x09, 0x02, 0x87, 0xfe, 0x6a, 0xd9, 0x4c, 0xe5, 0xd6, 0xb7, 0x39, 0xc6, 0xca, 0x24, 0x0b, 0x05, 0xc7, 0x6f, 0xb7, 0x3f, 0x25, 0xdd, 0x02, 0x4b, 0xf9, 0x35 },
+      { 0x85, 0xfd, 0x08, 0x5f, 0xdc, 0x12, 0xa0, 0x80, 0x98, 0x3d, 0xf0, 0x7b, 0xd7, 0x01, 0x2b, 0x0d, 0x40, 0x2a, 0x0f, 0x40, 0x43, 0xfc, 0xb2, 0x77, 0x5a, 0xdf, 0x0b, 0xad, 0x17, 0x4f, 0x9b, 0x08, 0xd1, 0x67, 0x6e, 0x47, 0x69, 0x85, 0x78, 0x5c, 0x0a, 0x5d, 0xcc, 0x41, 0xdb, 0xff, 0x6d, 0x95, 0xef, 0x4d, 0x66, 0xa3, 0xfb, 0xdc, 0x4a, 0x74, 0xb8, 0x2b, 0xa5, 0x2d, 0xa0, 0x51, 0x2b, 0x74 },
+      { 0xae, 0xd8, 0xfa, 0x76, 0x4b, 0x0f, 0xbf, 0xf8, 0x21, 0xe0, 0x52, 0x33, 0xd2, 0xf7, 0xb0, 0x90, 0x0e, 0xc4, 0x4d, 0x82, 0x6f, 0x95, 0xe9, 0x3c, 0x34, 0x3c, 0x1b, 0xc3, 0xba, 0x5a, 0x24, 0x37, 0x4b, 0x1d, 0x61, 0x6e, 0x7e, 0x7a, 0xba, 0x45, 0x3a, 0x0a, 0xda, 0x5e, 0x4f, 0xab, 0x53, 0x82, 0x40, 0x9e, 0x0d, 0x42, 0xce, 0x9c, 0x2b, 0xc7, 0xfb, 0x39, 0xa9, 0x9c, 0x34, 0x0c, 0x20, 0xf0 },
+      { 0x7b, 0xa3, 0xb2, 0xe2, 0x97, 0x23, 0x35, 0x22, 0xee, 0xb3, 0x43, 0xbd, 0x3e, 0xbc, 0xfd, 0x83, 0x5a, 0x04, 0x00, 0x77, 0x35, 0xe8, 0x7f, 0x0c, 0xa3, 0x00, 0xcb, 0xee, 0x6d, 0x41, 0x65, 0x65, 0x16, 0x21, 0x71, 0x58, 0x1e, 0x40, 0x20, 0xff, 0x4c, 0xf1, 0x76, 0x45, 0x0f, 0x12, 0x91, 0xea, 0x22, 0x85, 0xcb, 0x9e, 0xbf, 0xfe, 0x4c, 0x56, 0x66, 0x06, 0x27, 0x68, 0x51, 0x45, 0x05, 0x1c },
+      { 0xde, 0x74, 0x8b, 0xcf, 0x89, 0xec, 0x88, 0x08, 0x47, 0x21, 0xe1, 0x6b, 0x85, 0xf3, 0x0a, 0xdb, 0x1a, 0x61, 0x34, 0xd6, 0x64, 0xb5, 0x84, 0x35, 0x69, 0xba, 0xbc, 0x5b, 0xbd, 0x1a, 0x15, 0xca, 0x9b, 0x61, 0x80, 0x3c, 0x90, 0x1a, 0x4f, 0xef, 0x32, 0x96, 0x5a, 0x17, 0x49, 0xc9, 0xf3, 0xa4, 0xe2, 0x43, 0xe1, 0x73, 0x93, 0x9d, 0xc5, 0xa8, 0xdc, 0x49, 0x5c, 0x67, 0x1a, 0xb5, 0x21, 0x45 },
+      { 0xaa, 0xf4, 0xd2, 0xbd, 0xf2, 0x00, 0xa9, 0x19, 0x70, 0x6d, 0x98, 0x42, 0xdc, 0xe1, 0x6c, 0x98, 0x14, 0x0d, 0x34, 0xbc, 0x43, 0x3d, 0xf3, 0x20, 0xab, 0xa9, 0xbd, 0x42, 0x9e, 0x54, 0x9a, 0xa7, 0xa3, 0x39, 0x76, 0x52, 0xa4, 0xd7, 0x68, 0x27, 0x77, 0x86, 0xcf, 0x99, 0x3c, 0xde, 0x23, 0x38, 0x67, 0x3e, 0xd2, 0xe6, 0xb6, 0x6c, 0x96, 0x1f, 0xef, 0xb8, 0x2c, 0xd2, 0x0c, 0x93, 0x33, 0x8f },
+      { 0xc4, 0x08, 0x21, 0x89, 0x68, 0xb7, 0x88, 0xbf, 0x86, 0x4f, 0x09, 0x97, 0xe6, 0xbc, 0x4c, 0x3d, 0xba, 0x68, 0xb2, 0x76, 0xe2, 0x12, 0x5a, 0x48, 0x43, 0x29, 0x60, 0x52, 0xff, 0x93, 0xbf, 0x57, 0x67, 0xb8, 0xcd, 0xce, 0x71, 0x31, 0xf0, 0x87, 0x64, 0x30, 0xc1, 0x16, 0x5f, 0xec, 0x6c, 0x4f, 0x47, 0xad, 0xaa, 0x4f, 0xd8, 0xbc, 0xfa, 0xce, 0xf4, 0x63, 0xb5, 0xd3, 0xd0, 0xfa, 0x61, 0xa0 },
+      { 0x76, 0xd2, 0xd8, 0x19, 0xc9, 0x2b, 0xce, 0x55, 0xfa, 0x8e, 0x09, 0x2a, 0xb1, 0xbf, 0x9b, 0x9e, 0xab, 0x23, 0x7a, 0x25, 0x26, 0x79, 0x86, 0xca, 0xcf, 0x2b, 0x8e, 0xe1, 0x4d, 0x21, 0x4d, 0x73, 0x0d, 0xc9, 0xa5, 0xaa, 0x2d, 0x7b, 0x59, 0x6e, 0x86, 0xa1, 0xfd, 0x8f, 0xa0, 0x80, 0x4c, 0x77, 0x40, 0x2d, 0x2f, 0xcd, 0x45, 0x08, 0x36, 0x88, 0xb2, 0x18, 0xb1, 0xcd, 0xfa, 0x0d, 0xcb, 0xcb },
+      { 0x72, 0x06, 0x5e, 0xe4, 0xdd, 0x91, 0xc2, 0xd8, 0x50, 0x9f, 0xa1, 0xfc, 0x28, 0xa3, 0x7c, 0x7f, 0xc9, 0xfa, 0x7d, 0x5b, 0x3f, 0x8a, 0xd3, 0xd0, 0xd7, 0xa2, 0x56, 0x26, 0xb5, 0x7b, 0x1b, 0x44, 0x78, 0x8d, 0x4c, 0xaf, 0x80, 0x62, 0x90, 0x42, 0x5f, 0x98, 0x90, 0xa3, 0xa2, 0xa3, 0x5a, 0x90, 0x5a, 0xb4, 0xb3, 0x7a, 0xcf, 0xd0, 0xda, 0x6e, 0x45, 0x17, 0xb2, 0x52, 0x5c, 0x96, 0x51, 0xe4 },
+      { 0x64, 0x47, 0x5d, 0xfe, 0x76, 0x00, 0xd7, 0x17, 0x1b, 0xea, 0x0b, 0x39, 0x4e, 0x27, 0xc9, 0xb0, 0x0d, 0x8e, 0x74, 0xdd, 0x1e, 0x41, 0x6a, 0x79, 0x47, 0x36, 0x82, 0xad, 0x3d, 0xfd, 0xbb, 0x70, 0x66, 0x31, 0x55, 0x80, 0x55, 0xcf, 0xc8, 0xa4, 0x0e, 0x07, 0xbd, 0x01, 0x5a, 0x45, 0x40, 0xdc, 0xde, 0xa1, 0x58, 0x83, 0xcb, 0xbf, 0x31, 0x41, 0x2d, 0xf1, 0xde, 0x1c, 0xd4, 0x15, 0x2b, 0x91 },
+      { 0x12, 0xcd, 0x16, 0x74, 0xa4, 0x48, 0x8a, 0x5d, 0x7c, 0x2b, 0x31, 0x60, 0xd2, 0xe2, 0xc4, 0xb5, 0x83, 0x71, 0xbe, 0xda, 0xd7, 0x93, 0x41, 0x8d, 0x6f, 0x19, 0xc6, 0xee, 0x38, 0x5d, 0x70, 0xb3, 0xe0, 0x67, 0x39, 0x36, 0x9d, 0x4d, 0xf9, 0x10, 0xed, 0xb0, 0xb0, 0xa5, 0x4c, 0xbf, 0xf4, 0x3d, 0x54, 0x54, 0x4c, 0xd3, 0x7a, 0xb3, 0xa0, 0x6c, 0xfa, 0x0a, 0x3d, 0xda, 0xc8, 0xb6, 0x6c, 0x89 },
+      { 0x60, 0x75, 0x69, 0x66, 0x47, 0x9d, 0xed, 0xc6, 0xdd, 0x4b, 0xcf, 0xf8, 0xea, 0x7d, 0x1d, 0x4c, 0xe4, 0xd4, 0xaf, 0x2e, 0x7b, 0x09, 0x7e, 0x32, 0xe3, 0x76, 0x35, 0x18, 0x44, 0x11, 0x47, 0xcc, 0x12, 0xb3, 0xc0, 0xee, 0x6d, 0x2e, 0xca, 0xbf, 0x11, 0x98, 0xce, 0xc9, 0x2e, 0x86, 0xa3, 0x61, 0x6f, 0xba, 0x4f, 0x4e, 0x87, 0x2f, 0x58, 0x25, 0x33, 0x0a, 0xdb, 0xb4, 0xc1, 0xde, 0xe4, 0x44 },
+      { 0xa7, 0x80, 0x3b, 0xcb, 0x71, 0xbc, 0x1d, 0x0f, 0x43, 0x83, 0xdd, 0xe1, 0xe0, 0x61, 0x2e, 0x04, 0xf8, 0x72, 0xb7, 0x15, 0xad, 0x30, 0x81, 0x5c, 0x22, 0x49, 0xcf, 0x34, 0xab, 0xb8, 0xb0, 0x24, 0x91, 0x5c, 0xb2, 0xfc, 0x9f, 0x4e, 0x7c, 0xc4, 0xc8, 0xcf, 0xd4, 0x5b, 0xe2, 0xd5, 0xa9, 0x1e, 0xab, 0x09, 0x41, 0xc7, 0xd2, 0x70, 0xe2, 0xda, 0x4c, 0xa4, 0xa9, 0xf7, 0xac, 0x68, 0x66, 0x3a },
+      { 0xb8, 0x4e, 0xf6, 0xa7, 0x22, 0x9a, 0x34, 0xa7, 0x50, 0xd9, 0xa9, 0x8e, 0xe2, 0x52, 0x98, 0x71, 0x81, 0x6b, 0x87, 0xfb, 0xe3, 0xbc, 0x45, 0xb4, 0x5f, 0xa5, 0xae, 0x82, 0xd5, 0x14, 0x15, 0x40, 0x21, 0x11, 0x65, 0xc3, 0xc5, 0xd7, 0xa7, 0x47, 0x6b, 0xa5, 0xa4, 0xaa, 0x06, 0xd6, 0x64, 0x76, 0xf0, 0xd9, 0xdc, 0x49, 0xa3, 0xf1, 0xee, 0x72, 0xc3, 0xac, 0xab, 0xd4, 0x98, 0x96, 0x74, 0x14 },
+      { 0xfa, 0xe4, 0xb6, 0xd8, 0xef, 0xc3, 0xf8, 0xc8, 0xe6, 0x4d, 0x00, 0x1d, 0xab, 0xec, 0x3a, 0x21, 0xf5, 0x44, 0xe8, 0x27, 0x14, 0x74, 0x52, 0x51, 0xb2, 0xb4, 0xb3, 0x93, 0xf2, 0xf4, 0x3e, 0x0d, 0xa3, 0xd4, 0x03, 0xc6, 0x4d, 0xb9, 0x5a, 0x2c, 0xb6, 0xe2, 0x3e, 0xbb, 0x7b, 0x9e, 0x94, 0xcd, 0xd5, 0xdd, 0xac, 0x54, 0xf0, 0x7c, 0x4a, 0x61, 0xbd, 0x3c, 0xb1, 0x0a, 0xa6, 0xf9, 0x3b, 0x49 },
+      { 0x34, 0xf7, 0x28, 0x66, 0x05, 0xa1, 0x22, 0x36, 0x95, 0x40, 0x14, 0x1d, 0xed, 0x79, 0xb8, 0x95, 0x72, 0x55, 0xda, 0x2d, 0x41, 0x55, 0xab, 0xbf, 0x5a, 0x8d, 0xbb, 0x89, 0xc8, 0xeb, 0x7e, 0xde, 0x8e, 0xee, 0xf1, 0xda, 0xa4, 0x6d, 0xc2, 0x9d, 0x75, 0x1d, 0x04, 0x5d, 0xc3, 0xb1, 0xd6, 0x58, 0xbb, 0x64, 0xb8, 0x0f, 0xf8, 0x58, 0x9e, 0xdd, 0xb3, 0x82, 0x4b, 0x13, 0xda, 0x23, 0x5a, 0x6b },
+      { 0x3b, 0x3b, 0x48, 0x43, 0x4b, 0xe2, 0x7b, 0x9e, 0xab, 0xab, 0xba, 0x43, 0xbf, 0x6b, 0x35, 0xf1, 0x4b, 0x30, 0xf6, 0xa8, 0x8d, 0xc2, 0xe7, 0x50, 0xc3, 0x58, 0x47, 0x0d, 0x6b, 0x3a, 0xa3, 0xc1, 0x8e, 0x47, 0xdb, 0x40, 0x17, 0xfa, 0x55, 0x10, 0x6d, 0x82, 0x52, 0xf0, 0x16, 0x37, 0x1a, 0x00, 0xf5, 0xf8, 0xb0, 0x70, 0xb7, 0x4b, 0xa5, 0xf2, 0x3c, 0xff, 0xc5, 0x51, 0x1c, 0x9f, 0x09, 0xf0 },
+      { 0xba, 0x28, 0x9e, 0xbd, 0x65, 0x62, 0xc4, 0x8c, 0x3e, 0x10, 0xa8, 0xad, 0x6c, 0xe0, 0x2e, 0x73, 0x43, 0x3d, 0x1e, 0x93, 0xd7, 0xc9, 0x27, 0x9d, 0x4d, 0x60, 0xa7, 0xe8, 0x79, 0xee, 0x11, 0xf4, 0x41, 0xa0, 0x00, 0xf4, 0x8e, 0xd9, 0xf7, 0xc4, 0xed, 0x87, 0xa4, 0x51, 0x36, 0xd7, 0xdc, 0xcd, 0xca, 0x48, 0x21, 0x09, 0xc7, 0x8a, 0x51, 0x06, 0x2b, 0x3b, 0xa4, 0x04, 0x4a, 0xda, 0x24, 0x69 },
+      { 0x02, 0x29, 0x39, 0xe2, 0x38, 0x6c, 0x5a, 0x37, 0x04, 0x98, 0x56, 0xc8, 0x50, 0xa2, 0xbb, 0x10, 0xa1, 0x3d, 0xfe, 0xa4, 0x21, 0x2b, 0x4c, 0x73, 0x2a, 0x88, 0x40, 0xa9, 0xff, 0xa5, 0xfa, 0xf5, 0x48, 0x75, 0xc5, 0x44, 0x88, 0x16, 0xb2, 0x78, 0x5a, 0x00, 0x7d, 0xa8, 0xa8, 0xd2, 0xbc, 0x7d, 0x71, 0xa5, 0x4e, 0x4e, 0x65, 0x71, 0xf1, 0x0b, 0x60, 0x0c, 0xbd, 0xb2, 0x5d, 0x13, 0xed, 0xe3 },
+      { 0xe6, 0xfe, 0xc1, 0x9d, 0x89, 0xce, 0x87, 0x17, 0xb1, 0xa0, 0x87, 0x02, 0x46, 0x70, 0xfe, 0x02, 0x6f, 0x6c, 0x7c, 0xbd, 0xa1, 0x1c, 0xae, 0xf9, 0x59, 0xbb, 0x2d, 0x35, 0x1b, 0xf8, 0x56, 0xf8, 0x05, 0x5d, 0x1c, 0x0e, 0xbd, 0xaa, 0xa9, 0xd1, 0xb1, 0x78, 0x86, 0xfc, 0x2c, 0x56, 0x2b, 0x5e, 0x99, 0x64, 0x2f, 0xc0, 0x64, 0x71, 0x0c, 0x0d, 0x34, 0x88, 0xa0, 0x2b, 0x5e, 0xd7, 0xf6, 0xfd },
+      { 0x94, 0xc9, 0x6f, 0x02, 0xa8, 0xf5, 0x76, 0xac, 0xa3, 0x2b, 0xa6, 0x1c, 0x2b, 0x20, 0x6f, 0x90, 0x72, 0x85, 0xd9, 0x29, 0x9b, 0x83, 0xac, 0x17, 0x5c, 0x20, 0x9a, 0x8d, 0x43, 0xd5, 0x3b, 0xfe, 0x68, 0x3d, 0xd1, 0xd8, 0x3e, 0x75, 0x49, 0xcb, 0x90, 0x6c, 0x28, 0xf5, 0x9a, 0xb7, 0xc4, 0x6f, 0x87, 0x51, 0x36, 0x6a, 0x28, 0xc3, 0x9d, 0xd5, 0xfe, 0x26, 0x93, 0xc9, 0x01, 0x96, 0x66, 0xc8 },
+      { 0x31, 0xa0, 0xcd, 0x21, 0x5e, 0xbd, 0x2c, 0xb6, 0x1d, 0xe5, 0xb9, 0xed, 0xc9, 0x1e, 0x61, 0x95, 0xe3, 0x1c, 0x59, 0xa5, 0x64, 0x8d, 0x5c, 0x9f, 0x73, 0x7e, 0x12, 0x5b, 0x26, 0x05, 0x70, 0x8f, 0x2e, 0x32, 0x5a, 0xb3, 0x38, 0x1c, 0x8d, 0xce, 0x1a, 0x3e, 0x95, 0x88, 0x86, 0xf1, 0xec, 0xdc, 0x60, 0x31, 0x8f, 0x88, 0x2c, 0xfe, 0x20, 0xa2, 0x41, 0x91, 0x35, 0x2e, 0x61, 0x7b, 0x0f, 0x21 },
+      { 0x91, 0xab, 0x50, 0x4a, 0x52, 0x2d, 0xce, 0x78, 0x77, 0x9f, 0x4c, 0x6c, 0x6b, 0xa2, 0xe6, 0xb6, 0xdb, 0x55, 0x65, 0xc7, 0x6d, 0x3e, 0x7e, 0x7c, 0x92, 0x0c, 0xaf, 0x7f, 0x75, 0x7e, 0xf9, 0xdb, 0x7c, 0x8f, 0xcf, 0x10, 0xe5, 0x7f, 0x03, 0x37, 0x9e, 0xa9, 0xbf, 0x75, 0xeb, 0x59, 0x89, 0x5d, 0x96, 0xe1, 0x49, 0x80, 0x0b, 0x6a, 0xae, 0x01, 0xdb, 0x77, 0x8b, 0xb9, 0x0a, 0xfb, 0xc9, 0x89 },
+      { 0xd8, 0x5c, 0xab, 0xc6, 0xbd, 0x5b, 0x1a, 0x01, 0xa5, 0xaf, 0xd8, 0xc6, 0x73, 0x47, 0x40, 0xda, 0x9f, 0xd1, 0xc1, 0xac, 0xc6, 0xdb, 0x29, 0xbf, 0xc8, 0xa2, 0xe5, 0xb6, 0x68, 0xb0, 0x28, 0xb6, 0xb3, 0x15, 0x4b, 0xfb, 0x87, 0x03, 0xfa, 0x31, 0x80, 0x25, 0x1d, 0x58, 0x9a, 0xd3, 0x80, 0x40, 0xce, 0xb7, 0x07, 0xc4, 0xba, 0xd1, 0xb5, 0x34, 0x3c, 0xb4, 0x26, 0xb6, 0x1e, 0xaa, 0x49, 0xc1 },
+      { 0xd6, 0x2e, 0xfb, 0xec, 0x2c, 0xa9, 0xc1, 0xf8, 0xbd, 0x66, 0xce, 0x8b, 0x3f, 0x6a, 0x89, 0x8c, 0xb3, 0xf7, 0x56, 0x6b, 0xa6, 0x56, 0x8c, 0x61, 0x8a, 0xd1, 0xfe, 0xb2, 0xb6, 0x5b, 0x76, 0xc3, 0xce, 0x1d, 0xd2, 0x0f, 0x73, 0x95, 0x37, 0x2f, 0xaf, 0x28, 0x42, 0x7f, 0x61, 0xc9, 0x27, 0x80, 0x49, 0xcf, 0x01, 0x40, 0xdf, 0x43, 0x4f, 0x56, 0x33, 0x04, 0x8c, 0x86, 0xb8, 0x1e, 0x03, 0x99 },
+      { 0x7c, 0x8f, 0xdc, 0x61, 0x75, 0x43, 0x9e, 0x2c, 0x3d, 0xb1, 0x5b, 0xaf, 0xa7, 0xfb, 0x06, 0x14, 0x3a, 0x6a, 0x23, 0xbc, 0x90, 0xf4, 0x49, 0xe7, 0x9d, 0xee, 0xf7, 0x3c, 0x3d, 0x49, 0x2a, 0x67, 0x17, 0x15, 0xc1, 0x93, 0xb6, 0xfe, 0xa9, 0xf0, 0x36, 0x05, 0x0b, 0x94, 0x60, 0x69, 0x85, 0x6b, 0x89, 0x7e, 0x08, 0xc0, 0x07, 0x68, 0xf5, 0xee, 0x5d, 0xdc, 0xf7, 0x0b, 0x7c, 0xd6, 0xd0, 0xe0 },
+      { 0x58, 0x60, 0x2e, 0xe7, 0x46, 0x8e, 0x6b, 0xc9, 0xdf, 0x21, 0xbd, 0x51, 0xb2, 0x3c, 0x00, 0x5f, 0x72, 0xd6, 0xcb, 0x01, 0x3f, 0x0a, 0x1b, 0x48, 0xcb, 0xec, 0x5e, 0xca, 0x29, 0x92, 0x99, 0xf9, 0x7f, 0x09, 0xf5, 0x4a, 0x9a, 0x01, 0x48, 0x3e, 0xae, 0xb3, 0x15, 0xa6, 0x47, 0x8b, 0xad, 0x37, 0xba, 0x47, 0xca, 0x13, 0x47, 0xc7, 0xc8, 0xfc, 0x9e, 0x66, 0x95, 0x59, 0x2c, 0x91, 0xd7, 0x23 },
+      { 0x27, 0xf5, 0xb7, 0x9e, 0xd2, 0x56, 0xb0, 0x50, 0x99, 0x3d, 0x79, 0x34, 0x96, 0xed, 0xf4, 0x80, 0x7c, 0x1d, 0x85, 0xa7, 0xb0, 0xa6, 0x7c, 0x9c, 0x4f, 0xa9, 0x98, 0x60, 0x75, 0x0b, 0x0a, 0xe6, 0x69, 0x89, 0x67, 0x0a, 0x8f, 0xfd, 0x78, 0x56, 0xd7, 0xce, 0x41, 0x15, 0x99, 0xe5, 0x8c, 0x4d, 0x77, 0xb2, 0x32, 0xa6, 0x2b, 0xef, 0x64, 0xd1, 0x52, 0x75, 0xbe, 0x46, 0xa6, 0x82, 0x35, 0xff },
+      { 0x39, 0x57, 0xa9, 0x76, 0xb9, 0xf1, 0x88, 0x7b, 0xf0, 0x04, 0xa8, 0xdc, 0xa9, 0x42, 0xc9, 0x2d, 0x2b, 0x37, 0xea, 0x52, 0x60, 0x0f, 0x25, 0xe0, 0xc9, 0xbc, 0x57, 0x07, 0xd0, 0x27, 0x9c, 0x00, 0xc6, 0xe8, 0x5a, 0x83, 0x9b, 0x0d, 0x2d, 0x8e, 0xb5, 0x9c, 0x51, 0xd9, 0x47, 0x88, 0xeb, 0xe6, 0x24, 0x74, 0xa7, 0x91, 0xca, 0xdf, 0x52, 0xcc, 0xcf, 0x20, 0xf5, 0x07, 0x0b, 0x65, 0x73, 0xfc },
+      { 0xea, 0xa2, 0x37, 0x6d, 0x55, 0x38, 0x0b, 0xf7, 0x72, 0xec, 0xca, 0x9c, 0xb0, 0xaa, 0x46, 0x68, 0xc9, 0x5c, 0x70, 0x71, 0x62, 0xfa, 0x86, 0xd5, 0x18, 0xc8, 0xce, 0x0c, 0xa9, 0xbf, 0x73, 0x62, 0xb9, 0xf2, 0xa0, 0xad, 0xc3, 0xff, 0x59, 0x92, 0x2d, 0xf9, 0x21, 0xb9, 0x45, 0x67, 0xe8, 0x1e, 0x45, 0x2f, 0x6c, 0x1a, 0x07, 0xfc, 0x81, 0x7c, 0xeb, 0xe9, 0x96, 0x04, 0xb3, 0x50, 0x5d, 0x38 },
+      { 0xc1, 0xe2, 0xc7, 0x8b, 0x6b, 0x27, 0x34, 0xe2, 0x48, 0x0e, 0xc5, 0x50, 0x43, 0x4c, 0xb5, 0xd6, 0x13, 0x11, 0x1a, 0xdc, 0xc2, 0x1d, 0x47, 0x55, 0x45, 0xc3, 0xb1, 0xb7, 0xe6, 0xff, 0x12, 0x44, 0x44, 0x76, 0xe5, 0xc0, 0x55, 0x13, 0x2e, 0x22, 0x29, 0xdc, 0x0f, 0x80, 0x70, 0x44, 0xbb, 0x91, 0x9b, 0x1a, 0x56, 0x62, 0xdd, 0x38, 0xa9, 0xee, 0x65, 0xe2, 0x43, 0xa3, 0x91, 0x1a, 0xed, 0x1a },
+      { 0x8a, 0xb4, 0x87, 0x13, 0x38, 0x9d, 0xd0, 0xfc, 0xf9, 0xf9, 0x65, 0xd3, 0xce, 0x66, 0xb1, 0xe5, 0x59, 0xa1, 0xf8, 0xc5, 0x87, 0x41, 0xd6, 0x76, 0x83, 0xcd, 0x97, 0x13, 0x54, 0xf4, 0x52, 0xe6, 0x2d, 0x02, 0x07, 0xa6, 0x5e, 0x43, 0x6c, 0x5d, 0x5d, 0x8f, 0x8e, 0xe7, 0x1c, 0x6a, 0xbf, 0xe5, 0x0e, 0x66, 0x90, 0x04, 0xc3, 0x02, 0xb3, 0x1a, 0x7e, 0xa8, 0x31, 0x1d, 0x4a, 0x91, 0x60, 0x51 },
+      { 0x24, 0xce, 0x0a, 0xdd, 0xaa, 0x4c, 0x65, 0x03, 0x8b, 0xd1, 0xb1, 0xc0, 0xf1, 0x45, 0x2a, 0x0b, 0x12, 0x87, 0x77, 0xaa, 0xbc, 0x94, 0xa2, 0x9d, 0xf2, 0xfd, 0x6c, 0x7e, 0x2f, 0x85, 0xf8, 0xab, 0x9a, 0xc7, 0xef, 0xf5, 0x16, 0xb0, 0xe0, 0xa8, 0x25, 0xc8, 0x4a, 0x24, 0xcf, 0xe4, 0x92, 0xea, 0xad, 0x0a, 0x63, 0x08, 0xe4, 0x6d, 0xd4, 0x2f, 0xe8, 0x33, 0x3a, 0xb9, 0x71, 0xbb, 0x30, 0xca },
+      { 0x51, 0x54, 0xf9, 0x29, 0xee, 0x03, 0x04, 0x5b, 0x6b, 0x0c, 0x00, 0x04, 0xfa, 0x77, 0x8e, 0xde, 0xe1, 0xd1, 0x39, 0x89, 0x32, 0x67, 0xcc, 0x84, 0x82, 0x5a, 0xd7, 0xb3, 0x6c, 0x63, 0xde, 0x32, 0x79, 0x8e, 0x4a, 0x16, 0x6d, 0x24, 0x68, 0x65, 0x61, 0x35, 0x4f, 0x63, 0xb0, 0x07, 0x09, 0xa1, 0x36, 0x4b, 0x3c, 0x24, 0x1d, 0xe3, 0xfe, 0xbf, 0x07, 0x54, 0x04, 0x58, 0x97, 0x46, 0x7c, 0xd4 },
+      { 0xe7, 0x4e, 0x90, 0x79, 0x20, 0xfd, 0x87, 0xbd, 0x5a, 0xd6, 0x36, 0xdd, 0x11, 0x08, 0x5e, 0x50, 0xee, 0x70, 0x45, 0x9c, 0x44, 0x3e, 0x1c, 0xe5, 0x80, 0x9a, 0xf2, 0xbc, 0x2e, 0xba, 0x39, 0xf9, 0xe6, 0xd7, 0x12, 0x8e, 0x0e, 0x37, 0x12, 0xc3, 0x16, 0xda, 0x06, 0xf4, 0x70, 0x5d, 0x78, 0xa4, 0x83, 0x8e, 0x28, 0x12, 0x1d, 0x43, 0x44, 0xa2, 0xc7, 0x9c, 0x5e, 0x0d, 0xb3, 0x07, 0xa6, 0x77 },
+      { 0xbf, 0x91, 0xa2, 0x23, 0x34, 0xba, 0xc2, 0x0f, 0x3f, 0xd8, 0x06, 0x63, 0xb3, 0xcd, 0x06, 0xc4, 0xe8, 0x80, 0x2f, 0x30, 0xe6, 0xb5, 0x9f, 0x90, 0xd3, 0x03, 0x5c, 0xc9, 0x79, 0x8a, 0x21, 0x7e, 0xd5, 0xa3, 0x1a, 0xbb, 0xda, 0x7f, 0xa6, 0x84, 0x28, 0x27, 0xbd, 0xf2, 0xa7, 0xa1, 0xc2, 0x1f, 0x6f, 0xcf, 0xcc, 0xbb, 0x54, 0xc6, 0xc5, 0x29, 0x26, 0xf3, 0x2d, 0xa8, 0x16, 0x26, 0x9b, 0xe1 },
+      { 0xd9, 0xd5, 0xc7, 0x4b, 0xe5, 0x12, 0x1b, 0x0b, 0xd7, 0x42, 0xf2, 0x6b, 0xff, 0xb8, 0xc8, 0x9f, 0x89, 0x17, 0x1f, 0x3f, 0x93, 0x49, 0x13, 0x49, 0x2b, 0x09, 0x03, 0xc2, 0x71, 0xbb, 0xe2, 0xb3, 0x39, 0x5e, 0xf2, 0x59, 0x66, 0x9b, 0xef, 0x43, 0xb5, 0x7f, 0x7f, 0xcc, 0x30, 0x27, 0xdb, 0x01, 0x82, 0x3f, 0x6b, 0xae, 0xe6, 0x6e, 0x4f, 0x9f, 0xea, 0xd4, 0xd6, 0x72, 0x6c, 0x74, 0x1f, 0xce },
+      { 0x50, 0xc8, 0xb8, 0xcf, 0x34, 0xcd, 0x87, 0x9f, 0x80, 0xe2, 0xfa, 0xab, 0x32, 0x30, 0xb0, 0xc0, 0xe1, 0xcc, 0x3e, 0x9d, 0xca, 0xde, 0xb1, 0xb9, 0xd9, 0x7a, 0xb9, 0x23, 0x41, 0x5d, 0xd9, 0xa1, 0xfe, 0x38, 0xad, 0xdd, 0x5c, 0x11, 0x75, 0x6c, 0x67, 0x99, 0x0b, 0x25, 0x6e, 0x95, 0xad, 0x6d, 0x8f, 0x9f, 0xed, 0xce, 0x10, 0xbf, 0x1c, 0x90, 0x67, 0x9c, 0xde, 0x0e, 0xcf, 0x1b, 0xe3, 0x47 },
+      { 0x0a, 0x38, 0x6e, 0x7c, 0xd5, 0xdd, 0x9b, 0x77, 0xa0, 0x35, 0xe0, 0x9f, 0xe6, 0xfe, 0xe2, 0xc8, 0xce, 0x61, 0xb5, 0x38, 0x3c, 0x87, 0xea, 0x43, 0x20, 0x50, 0x59, 0xc5, 0xe4, 0xcd, 0x4f, 0x44, 0x08, 0x31, 0x9b, 0xb0, 0xa8, 0x23, 0x60, 0xf6, 0xa5, 0x8e, 0x6c, 0x9c, 0xe3, 0xf4, 0x87, 0xc4, 0x46, 0x06, 0x3b, 0xf8, 0x13, 0xbc, 0x6b, 0xa5, 0x35, 0xe1, 0x7f, 0xc1, 0x82, 0x6c, 0xfc, 0x91 },
+      { 0x1f, 0x14, 0x59, 0xcb, 0x6b, 0x61, 0xcb, 0xac, 0x5f, 0x0e, 0xfe, 0x8f, 0xc4, 0x87, 0x53, 0x8f, 0x42, 0x54, 0x89, 0x87, 0xfc, 0xd5, 0x62, 0x21, 0xcf, 0xa7, 0xbe, 0xb2, 0x25, 0x04, 0x76, 0x9e, 0x79, 0x2c, 0x45, 0xad, 0xfb, 0x1d, 0x6b, 0x3d, 0x60, 0xd7, 0xb7, 0x49, 0xc8, 0xa7, 0x5b, 0x0b, 0xdf, 0x14, 0xe8, 0xea, 0x72, 0x1b, 0x95, 0xdc, 0xa5, 0x38, 0xca, 0x6e, 0x25, 0x71, 0x12, 0x09 },
+      { 0xe5, 0x8b, 0x38, 0x36, 0xb7, 0xd8, 0xfe, 0xdb, 0xb5, 0x0c, 0xa5, 0x72, 0x5c, 0x65, 0x71, 0xe7, 0x4c, 0x07, 0x85, 0xe9, 0x78, 0x21, 0xda, 0xb8, 0xb6, 0x29, 0x8c, 0x10, 0xe4, 0xc0, 0x79, 0xd4, 0xa6, 0xcd, 0xf2, 0x2f, 0x0f, 0xed, 0xb5, 0x50, 0x32, 0x92, 0x5c, 0x16, 0x74, 0x81, 0x15, 0xf0, 0x1a, 0x10, 0x5e, 0x77, 0xe0, 0x0c, 0xee, 0x3d, 0x07, 0x92, 0x4d, 0xc0, 0xd8, 0xf9, 0x06, 0x59 },
+      { 0xb9, 0x29, 0xcc, 0x65, 0x05, 0xf0, 0x20, 0x15, 0x86, 0x72, 0xde, 0xda, 0x56, 0xd0, 0xdb, 0x08, 0x1a, 0x2e, 0xe3, 0x4c, 0x00, 0xc1, 0x10, 0x00, 0x29, 0xbd, 0xf8, 0xea, 0x98, 0x03, 0x4f, 0xa4, 0xbf, 0x3e, 0x86, 0x55, 0xec, 0x69, 0x7f, 0xe3, 0x6f, 0x40, 0x55, 0x3c, 0x5b, 0xb4, 0x68, 0x01, 0x64, 0x4a, 0x62, 0x7d, 0x33, 0x42, 0xf4, 0xfc, 0x92, 0xb6, 0x1f, 0x03, 0x29, 0x0f, 0xb3, 0x81 },
+      { 0x72, 0xd3, 0x53, 0x99, 0x4b, 0x49, 0xd3, 0xe0, 0x31, 0x53, 0x92, 0x9a, 0x1e, 0x4d, 0x4f, 0x18, 0x8e, 0xe5, 0x8a, 0xb9, 0xe7, 0x2e, 0xe8, 0xe5, 0x12, 0xf2, 0x9b, 0xc7, 0x73, 0x91, 0x38, 0x19, 0xce, 0x05, 0x7d, 0xdd, 0x70, 0x02, 0xc0, 0x43, 0x3e, 0xe0, 0xa1, 0x61, 0x14, 0xe3, 0xd1, 0x56, 0xdd, 0x2c, 0x4a, 0x7e, 0x80, 0xee, 0x53, 0x37, 0x8b, 0x86, 0x70, 0xf2, 0x3e, 0x33, 0xef, 0x56 },
+      { 0xc7, 0x0e, 0xf9, 0xbf, 0xd7, 0x75, 0xd4, 0x08, 0x17, 0x67, 0x37, 0xa0, 0x73, 0x6d, 0x68, 0x51, 0x7c, 0xe1, 0xaa, 0xad, 0x7e, 0x81, 0xa9, 0x3c, 0x8c, 0x1e, 0xd9, 0x67, 0xea, 0x21, 0x4f, 0x56, 0xc8, 0xa3, 0x77, 0xb1, 0x76, 0x3e, 0x67, 0x66, 0x15, 0xb6, 0x0f, 0x39, 0x88, 0x24, 0x1e, 0xae, 0x6e, 0xab, 0x96, 0x85, 0xa5, 0x12, 0x49, 0x29, 0xd2, 0x81, 0x88, 0xf2, 0x9e, 0xab, 0x06, 0xf7 },
+      { 0xc2, 0x30, 0xf0, 0x80, 0x26, 0x79, 0xcb, 0x33, 0x82, 0x2e, 0xf8, 0xb3, 0xb2, 0x1b, 0xf7, 0xa9, 0xa2, 0x89, 0x42, 0x09, 0x29, 0x01, 0xd7, 0xda, 0xc3, 0x76, 0x03, 0x00, 0x83, 0x10, 0x26, 0xcf, 0x35, 0x4c, 0x92, 0x32, 0xdf, 0x3e, 0x08, 0x4d, 0x99, 0x03, 0x13, 0x0c, 0x60, 0x1f, 0x63, 0xc1, 0xf4, 0xa4, 0xa4, 0xb8, 0x10, 0x6e, 0x46, 0x8c, 0xd4, 0x43, 0xbb, 0xe5, 0xa7, 0x34, 0xf4, 0x5f },
+      { 0x6f, 0x43, 0x09, 0x4c, 0xaf, 0xb5, 0xeb, 0xf1, 0xf7, 0xa4, 0x93, 0x7e, 0xc5, 0x0f, 0x56, 0xa4, 0xc9, 0xda, 0x30, 0x3c, 0xbb, 0x55, 0xac, 0x1f, 0x27, 0xf1, 0xf1, 0x97, 0x6c, 0xd9, 0x6b, 0xed, 0xa9, 0x46, 0x4f, 0x0e, 0x7b, 0x9c, 0x54, 0x62, 0x0b, 0x8a, 0x9f, 0xba, 0x98, 0x31, 0x64, 0xb8, 0xbe, 0x35, 0x78, 0x42, 0x5a, 0x02, 0x4f, 0x5f, 0xe1, 0x99, 0xc3, 0x63, 0x56, 0xb8, 0x89, 0x72 },
+      { 0x37, 0x45, 0x27, 0x3f, 0x4c, 0x38, 0x22, 0x5d, 0xb2, 0x33, 0x73, 0x81, 0x87, 0x1a, 0x0c, 0x6a, 0xaf, 0xd3, 0xaf, 0x9b, 0x01, 0x8c, 0x88, 0xaa, 0x02, 0x02, 0x58, 0x50, 0xa5, 0xdc, 0x3a, 0x42, 0xa1, 0xa3, 0xe0, 0x3e, 0x56, 0xcb, 0xf1, 0xb0, 0x87, 0x6d, 0x63, 0xa4, 0x41, 0xf1, 0xd2, 0x85, 0x6a, 0x39, 0xb8, 0x80, 0x1e, 0xb5, 0xaf, 0x32, 0x52, 0x01, 0xc4, 0x15, 0xd6, 0x5e, 0x97, 0xfe },
+      { 0xc5, 0x0c, 0x44, 0xcc, 0xa3, 0xec, 0x3e, 0xda, 0xae, 0x77, 0x9a, 0x7e, 0x17, 0x94, 0x50, 0xeb, 0xdd, 0xa2, 0xf9, 0x70, 0x67, 0xc6, 0x90, 0xaa, 0x6c, 0x5a, 0x4a, 0xc7, 0xc3, 0x01, 0x39, 0xbb, 0x27, 0xc0, 0xdf, 0x4d, 0xb3, 0x22, 0x0e, 0x63, 0xcb, 0x11, 0x0d, 0x64, 0xf3, 0x7f, 0xfe, 0x07, 0x8d, 0xb7, 0x26, 0x53, 0xe2, 0xda, 0xac, 0xf9, 0x3a, 0xe3, 0xf0, 0xa2, 0xd1, 0xa7, 0xeb, 0x2e },
+      { 0x8a, 0xef, 0x26, 0x3e, 0x38, 0x5c, 0xbc, 0x61, 0xe1, 0x9b, 0x28, 0x91, 0x42, 0x43, 0x26, 0x2a, 0xf5, 0xaf, 0xe8, 0x72, 0x6a, 0xf3, 0xce, 0x39, 0xa7, 0x9c, 0x27, 0x02, 0x8c, 0xf3, 0xec, 0xd3, 0xf8, 0xd2, 0xdf, 0xd9, 0xcf, 0xc9, 0xad, 0x91, 0xb5, 0x8f, 0x6f, 0x20, 0x77, 0x8f, 0xd5, 0xf0, 0x28, 0x94, 0xa3, 0xd9, 0x1c, 0x7d, 0x57, 0xd1, 0xe4, 0xb8, 0x66, 0xa7, 0xf3, 0x64, 0xb6, 0xbe },
+      { 0x28, 0x69, 0x61, 0x41, 0xde, 0x6e, 0x2d, 0x9b, 0xcb, 0x32, 0x35, 0x57, 0x8a, 0x66, 0x16, 0x6c, 0x14, 0x48, 0xd3, 0xe9, 0x05, 0xa1, 0xb4, 0x82, 0xd4, 0x23, 0xbe, 0x4b, 0xc5, 0x36, 0x9b, 0xc8, 0xc7, 0x4d, 0xae, 0x0a, 0xcc, 0x9c, 0xc1, 0x23, 0xe1, 0xd8, 0xdd, 0xce, 0x9f, 0x97, 0x91, 0x7e, 0x8c, 0x01, 0x9c, 0x55, 0x2d, 0xa3, 0x2d, 0x39, 0xd2, 0x21, 0x9b, 0x9a, 0xbf, 0x0f, 0xa8, 0xc8 },
+      { 0x2f, 0xb9, 0xeb, 0x20, 0x85, 0x83, 0x01, 0x81, 0x90, 0x3a, 0x9d, 0xaf, 0xe3, 0xdb, 0x42, 0x8e, 0xe1, 0x5b, 0xe7, 0x66, 0x22, 0x24, 0xef, 0xd6, 0x43, 0x37, 0x1f, 0xb2, 0x56, 0x46, 0xae, 0xe7, 0x16, 0xe5, 0x31, 0xec, 0xa6, 0x9b, 0x2b, 0xdc, 0x82, 0x33, 0xf1, 0xa8, 0x08, 0x1f, 0xa4, 0x3d, 0xa1, 0x50, 0x03, 0x02, 0x97, 0x5a, 0x77, 0xf4, 0x2f, 0xa5, 0x92, 0x13, 0x67, 0x10, 0xe9, 0xdc },
+      { 0x66, 0xf9, 0xa7, 0x14, 0x3f, 0x7a, 0x33, 0x14, 0xa6, 0x69, 0xbf, 0x2e, 0x24, 0xbb, 0xb3, 0x50, 0x14, 0x26, 0x1d, 0x63, 0x9f, 0x49, 0x5b, 0x6c, 0x9c, 0x1f, 0x10, 0x4f, 0xe8, 0xe3, 0x20, 0xac, 0xa6, 0x0d, 0x45, 0x50, 0xd6, 0x9d, 0x52, 0xed, 0xbd, 0x5a, 0x3c, 0xde, 0xb4, 0x01, 0x4a, 0xe6, 0x5b, 0x1d, 0x87, 0xaa, 0x77, 0x0b, 0x69, 0xae, 0x5c, 0x15, 0xf4, 0x33, 0x0b, 0x0b, 0x0a, 0xd8 },
+      { 0xf4, 0xc4, 0xdd, 0x1d, 0x59, 0x4c, 0x35, 0x65, 0xe3, 0xe2, 0x5c, 0xa4, 0x3d, 0xad, 0x82, 0xf6, 0x2a, 0xbe, 0xa4, 0x83, 0x5e, 0xd4, 0xcd, 0x81, 0x1b, 0xcd, 0x97, 0x5e, 0x46, 0x27, 0x98, 0x28, 0xd4, 0x4d, 0x4c, 0x62, 0xc3, 0x67, 0x9f, 0x1b, 0x7f, 0x7b, 0x9d, 0xd4, 0x57, 0x1d, 0x7b, 0x49, 0x55, 0x73, 0x47, 0xb8, 0xc5, 0x46, 0x0c, 0xbd, 0xc1, 0xbe, 0xf6, 0x90, 0xfb, 0x2a, 0x08, 0xc0 },
+      { 0x8f, 0x1d, 0xc9, 0x64, 0x9c, 0x3a, 0x84, 0x55, 0x1f, 0x8f, 0x6e, 0x91, 0xca, 0xc6, 0x82, 0x42, 0xa4, 0x3b, 0x1f, 0x8f, 0x32, 0x8e, 0xe9, 0x22, 0x80, 0x25, 0x73, 0x87, 0xfa, 0x75, 0x59, 0xaa, 0x6d, 0xb1, 0x2e, 0x4a, 0xea, 0xdc, 0x2d, 0x26, 0x09, 0x91, 0x78, 0x74, 0x9c, 0x68, 0x64, 0xb3, 0x57, 0xf3, 0xf8, 0x3b, 0x2f, 0xb3, 0xef, 0xa8, 0xd2, 0xa8, 0xdb, 0x05, 0x6b, 0xed, 0x6b, 0xcc },
+      { 0x31, 0x39, 0xc1, 0xa7, 0xf9, 0x7a, 0xfd, 0x16, 0x75, 0xd4, 0x60, 0xeb, 0xbc, 0x07, 0xf2, 0x72, 0x8a, 0xa1, 0x50, 0xdf, 0x84, 0x96, 0x24, 0x51, 0x1e, 0xe0, 0x4b, 0x74, 0x3b, 0xa0, 0xa8, 0x33, 0x09, 0x2f, 0x18, 0xc1, 0x2d, 0xc9, 0x1b, 0x4d, 0xd2, 0x43, 0xf3, 0x33, 0x40, 0x2f, 0x59, 0xfe, 0x28, 0xab, 0xdb, 0xbb, 0xae, 0x30, 0x1e, 0x7b, 0x65, 0x9c, 0x7a, 0x26, 0xd5, 0xc0, 0xf9, 0x79 },
+      { 0x06, 0xf9, 0x4a, 0x29, 0x96, 0x15, 0x8a, 0x81, 0x9f, 0xe3, 0x4c, 0x40, 0xde, 0x3c, 0xf0, 0x37, 0x9f, 0xd9, 0xfb, 0x85, 0xb3, 0xe3, 0x63, 0xba, 0x39, 0x26, 0xa0, 0xe7, 0xd9, 0x60, 0xe3, 0xf4, 0xc2, 0xe0, 0xc7, 0x0c, 0x7c, 0xe0, 0xcc, 0xb2, 0xa6, 0x4f, 0xc2, 0x98, 0x69, 0xf6, 0xe7, 0xab, 0x12, 0xbd, 0x4d, 0x3f, 0x14, 0xfc, 0xe9, 0x43, 0x27, 0x90, 0x27, 0xe7, 0x85, 0xfb, 0x5c, 0x29 },
+      { 0xc2, 0x9c, 0x39, 0x9e, 0xf3, 0xee, 0xe8, 0x96, 0x1e, 0x87, 0x56, 0x5c, 0x1c, 0xe2, 0x63, 0x92, 0x5f, 0xc3, 0xd0, 0xce, 0x26, 0x7d, 0x13, 0xe4, 0x8d, 0xd9, 0xe7, 0x32, 0xee, 0x67, 0xb0, 0xf6, 0x9f, 0xad, 0x56, 0x40, 0x1b, 0x0f, 0x10, 0xfc, 0xaa, 0xc1, 0x19, 0x20, 0x10, 0x46, 0xcc, 0xa2, 0x8c, 0x5b, 0x14, 0xab, 0xde, 0xa3, 0x21, 0x2a, 0xe6, 0x55, 0x62, 0xf7, 0xf1, 0x38, 0xdb, 0x3d },
+      { 0x4c, 0xec, 0x4c, 0x9d, 0xf5, 0x2e, 0xef, 0x05, 0xc3, 0xf6, 0xfa, 0xaa, 0x97, 0x91, 0xbc, 0x74, 0x45, 0x93, 0x71, 0x83, 0x22, 0x4e, 0xcc, 0x37, 0xa1, 0xe5, 0x8d, 0x01, 0x32, 0xd3, 0x56, 0x17, 0x53, 0x1d, 0x7e, 0x79, 0x5f, 0x52, 0xaf, 0x7b, 0x1e, 0xb9, 0xd1, 0x47, 0xde, 0x12, 0x92, 0xd3, 0x45, 0xfe, 0x34, 0x18, 0x23, 0xf8, 0xe6, 0xbc, 0x1e, 0x5b, 0xad, 0xca, 0x5c, 0x65, 0x61, 0x08 },
+      { 0x89, 0x8b, 0xfb, 0xae, 0x93, 0xb3, 0xe1, 0x8d, 0x00, 0x69, 0x7e, 0xab, 0x7d, 0x97, 0x04, 0xfa, 0x36, 0xec, 0x33, 0x9d, 0x07, 0x61, 0x31, 0xce, 0xfd, 0xf3, 0x0e, 0xdb, 0xe8, 0xd9, 0xcc, 0x81, 0xc3, 0xa8, 0x0b, 0x12, 0x96, 0x59, 0xb1, 0x63, 0xa3, 0x23, 0xba, 0xb9, 0x79, 0x3d, 0x4f, 0xee, 0xd9, 0x2d, 0x54, 0xda, 0xe9, 0x66, 0xc7, 0x75, 0x29, 0x76, 0x4a, 0x09, 0xbe, 0x88, 0xdb, 0x45 },
+      { 0xee, 0x9b, 0xd0, 0x46, 0x9d, 0x3a, 0xaf, 0x4f, 0x14, 0x03, 0x5b, 0xe4, 0x8a, 0x2c, 0x3b, 0x84, 0xd9, 0xb4, 0xb1, 0xff, 0xf1, 0xd9, 0x45, 0xe1, 0xf1, 0xc1, 0xd3, 0x89, 0x80, 0xa9, 0x51, 0xbe, 0x19, 0x7b, 0x25, 0xfe, 0x22, 0xc7, 0x31, 0xf2, 0x0a, 0xea, 0xcc, 0x93, 0x0b, 0xa9, 0xc4, 0xa1, 0xf4, 0x76, 0x22, 0x27, 0x61, 0x7a, 0xd3, 0x50, 0xfd, 0xab, 0xb4, 0xe8, 0x02, 0x73, 0xa0, 0xf4 },
+      { 0x3d, 0x4d, 0x31, 0x13, 0x30, 0x05, 0x81, 0xcd, 0x96, 0xac, 0xbf, 0x09, 0x1c, 0x3d, 0x0f, 0x3c, 0x31, 0x01, 0x38, 0xcd, 0x69, 0x79, 0xe6, 0x02, 0x6c, 0xde, 0x62, 0x3e, 0x2d, 0xd1, 0xb2, 0x4d, 0x4a, 0x86, 0x38, 0xbe, 0xd1, 0x07, 0x33, 0x44, 0x78, 0x3a, 0xd0, 0x64, 0x9c, 0xc6, 0x30, 0x5c, 0xce, 0xc0, 0x4b, 0xeb, 0x49, 0xf3, 0x1c, 0x63, 0x30, 0x88, 0xa9, 0x9b, 0x65, 0x13, 0x02, 0x67 },
+      { 0x95, 0xc0, 0x59, 0x1a, 0xd9, 0x1f, 0x92, 0x1a, 0xc7, 0xbe, 0x6d, 0x9c, 0xe3, 0x7e, 0x06, 0x63, 0xed, 0x80, 0x11, 0xc1, 0xcf, 0xd6, 0xd0, 0x16, 0x2a, 0x55, 0x72, 0xe9, 0x43, 0x68, 0xba, 0xc0, 0x20, 0x24, 0x48, 0x5e, 0x6a, 0x39, 0x85, 0x4a, 0xa4, 0x6f, 0xe3, 0x8e, 0x97, 0xd6, 0xc6, 0xb1, 0x94, 0x7c, 0xd2, 0x72, 0xd8, 0x6b, 0x06, 0xbb, 0x5b, 0x2f, 0x78, 0xb9, 0xb6, 0x8d, 0x55, 0x9d },
+      { 0x22, 0x7b, 0x79, 0xde, 0xd3, 0x68, 0x15, 0x3b, 0xf4, 0x6c, 0x0a, 0x3c, 0xa9, 0x78, 0xbf, 0xdb, 0xef, 0x31, 0xf3, 0x02, 0x4a, 0x56, 0x65, 0x84, 0x24, 0x68, 0x49, 0x0b, 0x0f, 0xf7, 0x48, 0xae, 0x04, 0xe7, 0x83, 0x2e, 0xd4, 0xc9, 0xf4, 0x9d, 0xe9, 0xb1, 0x70, 0x67, 0x09, 0xd6, 0x23, 0xe5, 0xc8, 0xc1, 0x5e, 0x3c, 0xae, 0xca, 0xe8, 0xd5, 0xe4, 0x33, 0x43, 0x0f, 0xf7, 0x2f, 0x20, 0xeb },
+      { 0x5d, 0x34, 0xf3, 0x95, 0x2f, 0x01, 0x05, 0xee, 0xf8, 0x8a, 0xe8, 0xb6, 0x4c, 0x6c, 0xe9, 0x5e, 0xbf, 0xad, 0xe0, 0xe0, 0x2c, 0x69, 0xb0, 0x87, 0x62, 0xa8, 0x71, 0x2d, 0x2e, 0x49, 0x11, 0xad, 0x3f, 0x94, 0x1f, 0xc4, 0x03, 0x4d, 0xc9, 0xb2, 0xe4, 0x79, 0xfd, 0xbc, 0xd2, 0x79, 0xb9, 0x02, 0xfa, 0xf5, 0xd8, 0x38, 0xbb, 0x2e, 0x0c, 0x64, 0x95, 0xd3, 0x72, 0xb5, 0xb7, 0x02, 0x98, 0x13 },
+      { 0x7f, 0x93, 0x9b, 0xf8, 0x35, 0x3a, 0xbc, 0xe4, 0x9e, 0x77, 0xf1, 0x4f, 0x37, 0x50, 0xaf, 0x20, 0xb7, 0xb0, 0x39, 0x02, 0xe1, 0xa1, 0xe7, 0xfb, 0x6a, 0xaf, 0x76, 0xd0, 0x25, 0x9c, 0xd4, 0x01, 0xa8, 0x31, 0x90, 0xf1, 0x56, 0x40, 0xe7, 0x4f, 0x3e, 0x6c, 0x5a, 0x90, 0xe8, 0x39, 0xc7, 0x82, 0x1f, 0x64, 0x74, 0x75, 0x7f, 0x75, 0xc7, 0xbf, 0x90, 0x02, 0x08, 0x4d, 0xdc, 0x7a, 0x62, 0xdc },
+      { 0x06, 0x2b, 0x61, 0xa2, 0xf9, 0xa3, 0x3a, 0x71, 0xd7, 0xd0, 0xa0, 0x61, 0x19, 0x64, 0x4c, 0x70, 0xb0, 0x71, 0x6a, 0x50, 0x4d, 0xe7, 0xe5, 0xe1, 0xbe, 0x49, 0xbd, 0x7b, 0x86, 0xe7, 0xed, 0x68, 0x17, 0x71, 0x4f, 0x9f, 0x0f, 0xc3, 0x13, 0xd0, 0x61, 0x29, 0x59, 0x7e, 0x9a, 0x22, 0x35, 0xec, 0x85, 0x21, 0xde, 0x36, 0xf7, 0x29, 0x0a, 0x90, 0xcc, 0xfc, 0x1f, 0xfa, 0x6d, 0x0a, 0xee, 0x29 },
+      { 0xf2, 0x9e, 0x01, 0xee, 0xae, 0x64, 0x31, 0x1e, 0xb7, 0xf1, 0xc6, 0x42, 0x2f, 0x94, 0x6b, 0xf7, 0xbe, 0xa3, 0x63, 0x79, 0x52, 0x3e, 0x7b, 0x2b, 0xba, 0xba, 0x7d, 0x1d, 0x34, 0xa2, 0x2d, 0x5e, 0xa5, 0xf1, 0xc5, 0xa0, 0x9d, 0x5c, 0xe1, 0xfe, 0x68, 0x2c, 0xce, 0xd9, 0xa4, 0x79, 0x8d, 0x1a, 0x05, 0xb4, 0x6c, 0xd7, 0x2d, 0xff, 0x5c, 0x1b, 0x35, 0x54, 0x40, 0xb2, 0xa2, 0xd4, 0x76, 0xbc },
+      { 0xec, 0x38, 0xcd, 0x3b, 0xba, 0xb3, 0xef, 0x35, 0xd7, 0xcb, 0x6d, 0x5c, 0x91, 0x42, 0x98, 0x35, 0x1d, 0x8a, 0x9d, 0xc9, 0x7f, 0xce, 0xe0, 0x51, 0xa8, 0xa0, 0x2f, 0x58, 0xe3, 0xed, 0x61, 0x84, 0xd0, 0xb7, 0x81, 0x0a, 0x56, 0x15, 0x41, 0x1a, 0xb1, 0xb9, 0x52, 0x09, 0xc3, 0xc8, 0x10, 0x11, 0x4f, 0xde, 0xb2, 0x24, 0x52, 0x08, 0x4e, 0x77, 0xf3, 0xf8, 0x47, 0xc6, 0xdb, 0xaa, 0xfe, 0x16 },
+      { 0xc2, 0xae, 0xf5, 0xe0, 0xca, 0x43, 0xe8, 0x26, 0x41, 0x56, 0x5b, 0x8c, 0xb9, 0x43, 0xaa, 0x8b, 0xa5, 0x35, 0x50, 0xca, 0xef, 0x79, 0x3b, 0x65, 0x32, 0xfa, 0xfa, 0xd9, 0x4b, 0x81, 0x60, 0x82, 0xf0, 0x11, 0x3a, 0x3e, 0xa2, 0xf6, 0x36, 0x08, 0xab, 0x40, 0x43, 0x7e, 0xcc, 0x0f, 0x02, 0x29, 0xcb, 0x8f, 0xa2, 0x24, 0xdc, 0xf1, 0xc4, 0x78, 0xa6, 0x7d, 0x9b, 0x64, 0x16, 0x2b, 0x92, 0xd1 },
+      { 0x15, 0xf5, 0x34, 0xef, 0xff, 0x71, 0x05, 0xcd, 0x1c, 0x25, 0x4d, 0x07, 0x4e, 0x27, 0xd5, 0x89, 0x8b, 0x89, 0x31, 0x3b, 0x7d, 0x36, 0x6d, 0xc2, 0xd7, 0xd8, 0x71, 0x13, 0xfa, 0x7d, 0x53, 0xaa, 0xe1, 0x3f, 0x6d, 0xba, 0x48, 0x7a, 0xd8, 0x10, 0x3d, 0x5e, 0x85, 0x4c, 0x91, 0xfd, 0xb6, 0xe1, 0xe7, 0x4b, 0x2e, 0xf6, 0xd1, 0x43, 0x17, 0x69, 0xc3, 0x07, 0x67, 0xdd, 0xe0, 0x67, 0xa3, 0x5c },
+      { 0x89, 0xac, 0xbc, 0xa0, 0xb1, 0x69, 0x89, 0x7a, 0x0a, 0x27, 0x14, 0xc2, 0xdf, 0x8c, 0x95, 0xb5, 0xb7, 0x9c, 0xb6, 0x93, 0x90, 0x14, 0x2b, 0x7d, 0x60, 0x18, 0xbb, 0x3e, 0x30, 0x76, 0xb0, 0x99, 0xb7, 0x9a, 0x96, 0x41, 0x52, 0xa9, 0xd9, 0x12, 0xb1, 0xb8, 0x64, 0x12, 0xb7, 0xe3, 0x72, 0xe9, 0xce, 0xca, 0xd7, 0xf2, 0x5d, 0x4c, 0xba, 0xb8, 0xa3, 0x17, 0xbe, 0x36, 0x49, 0x2a, 0x67, 0xd7 },
+      { 0xe3, 0xc0, 0x73, 0x91, 0x90, 0xed, 0x84, 0x9c, 0x9c, 0x96, 0x2f, 0xd9, 0xdb, 0xb5, 0x5e, 0x20, 0x7e, 0x62, 0x4f, 0xca, 0xc1, 0xeb, 0x41, 0x76, 0x91, 0x51, 0x54, 0x99, 0xee, 0xa8, 0xd8, 0x26, 0x7b, 0x7e, 0x8f, 0x12, 0x87, 0xa6, 0x36, 0x33, 0xaf, 0x50, 0x11, 0xfd, 0xe8, 0xc4, 0xdd, 0xf5, 0x5b, 0xfd, 0xf7, 0x22, 0xed, 0xf8, 0x88, 0x31, 0x41, 0x4f, 0x2c, 0xfa, 0xed, 0x59, 0xcb, 0x9a },
+      { 0x8d, 0x6c, 0xf8, 0x7c, 0x08, 0x38, 0x0d, 0x2d, 0x15, 0x06, 0xee, 0xe4, 0x6f, 0xd4, 0x22, 0x2d, 0x21, 0xd8, 0xc0, 0x4e, 0x58, 0x5f, 0xbf, 0xd0, 0x82, 0x69, 0xc9, 0x8f, 0x70, 0x28, 0x33, 0xa1, 0x56, 0x32, 0x6a, 0x07, 0x24, 0x65, 0x64, 0x00, 0xee, 0x09, 0x35, 0x1d, 0x57, 0xb4, 0x40, 0x17, 0x5e, 0x2a, 0x5d, 0xe9, 0x3c, 0xc5, 0xf8, 0x0d, 0xb6, 0xda, 0xf8, 0x35, 0x76, 0xcf, 0x75, 0xfa },
+      { 0xda, 0x24, 0xbe, 0xde, 0x38, 0x36, 0x66, 0xd5, 0x63, 0xee, 0xed, 0x37, 0xf6, 0x31, 0x9b, 0xaf, 0x20, 0xd5, 0xc7, 0x5d, 0x16, 0x35, 0xa6, 0xba, 0x5e, 0xf4, 0xcf, 0xa1, 0xac, 0x95, 0x48, 0x7e, 0x96, 0xf8, 0xc0, 0x8a, 0xf6, 0x00, 0xaa, 0xb8, 0x7c, 0x98, 0x6e, 0xba, 0xd4, 0x9f, 0xc7, 0x0a, 0x58, 0xb4, 0x89, 0x0b, 0x9c, 0x87, 0x6e, 0x09, 0x10, 0x16, 0xda, 0xf4, 0x9e, 0x1d, 0x32, 0x2e },
+      { 0xf9, 0xd1, 0xd1, 0xb1, 0xe8, 0x7e, 0xa7, 0xae, 0x75, 0x3a, 0x02, 0x97, 0x50, 0xcc, 0x1c, 0xf3, 0xd0, 0x15, 0x7d, 0x41, 0x80, 0x5e, 0x24, 0x5c, 0x56, 0x17, 0xbb, 0x93, 0x4e, 0x73, 0x2f, 0x0a, 0xe3, 0x18, 0x0b, 0x78, 0xe0, 0x5b, 0xfe, 0x76, 0xc7, 0xc3, 0x05, 0x1e, 0x3e, 0x3a, 0xc7, 0x8b, 0x9b, 0x50, 0xc0, 0x51, 0x42, 0x65, 0x7e, 0x1e, 0x03, 0x21, 0x5d, 0x6e, 0xc7, 0xbf, 0xd0, 0xfc },
+      { 0x11, 0xb7, 0xbc, 0x16, 0x68, 0x03, 0x20, 0x48, 0xaa, 0x43, 0x34, 0x3d, 0xe4, 0x76, 0x39, 0x5e, 0x81, 0x4b, 0xbb, 0xc2, 0x23, 0x67, 0x8d, 0xb9, 0x51, 0xa1, 0xb0, 0x3a, 0x02, 0x1e, 0xfa, 0xc9, 0x48, 0xcf, 0xbe, 0x21, 0x5f, 0x97, 0xfe, 0x9a, 0x72, 0xa2, 0xf6, 0xbc, 0x03, 0x9e, 0x39, 0x56, 0xbf, 0xa4, 0x17, 0xc1, 0xa9, 0xf1, 0x0d, 0x6d, 0x7b, 0xa5, 0xd3, 0xd3, 0x2f, 0xf3, 0x23, 0xe5 },
+      { 0xb8, 0xd9, 0x00, 0x0e, 0x4f, 0xc2, 0xb0, 0x66, 0xed, 0xb9, 0x1a, 0xfe, 0xe8, 0xe7, 0xeb, 0x0f, 0x24, 0xe3, 0xa2, 0x01, 0xdb, 0x8b, 0x67, 0x93, 0xc0, 0x60, 0x85, 0x81, 0xe6, 0x28, 0xed, 0x0b, 0xcc, 0x4e, 0x5a, 0xa6, 0x78, 0x79, 0x92, 0xa4, 0xbc, 0xc4, 0x4e, 0x28, 0x80, 0x93, 0xe6, 0x3e, 0xe8, 0x3a, 0xbd, 0x0b, 0xc3, 0xec, 0x6d, 0x09, 0x34, 0xa6, 0x74, 0xa4, 0xda, 0x13, 0x83, 0x8a },
+      { 0xce, 0x32, 0x5e, 0x29, 0x4f, 0x9b, 0x67, 0x19, 0xd6, 0xb6, 0x12, 0x78, 0x27, 0x6a, 0xe0, 0x6a, 0x25, 0x64, 0xc0, 0x3b, 0xb0, 0xb7, 0x83, 0xfa, 0xfe, 0x78, 0x5b, 0xdf, 0x89, 0xc7, 0xd5, 0xac, 0xd8, 0x3e, 0x78, 0x75, 0x6d, 0x30, 0x1b, 0x44, 0x56, 0x99, 0x02, 0x4e, 0xae, 0xb7, 0x7b, 0x54, 0xd4, 0x77, 0x33, 0x6e, 0xc2, 0xa4, 0xf3, 0x32, 0xf2, 0xb3, 0xf8, 0x87, 0x65, 0xdd, 0xb0, 0xc3 },
+      { 0x29, 0xac, 0xc3, 0x0e, 0x96, 0x03, 0xae, 0x2f, 0xcc, 0xf9, 0x0b, 0xf9, 0x7e, 0x6c, 0xc4, 0x63, 0xeb, 0xe2, 0x8c, 0x1b, 0x2f, 0x9b, 0x4b, 0x76, 0x5e, 0x70, 0x53, 0x7c, 0x25, 0xc7, 0x02, 0xa2, 0x9d, 0xcb, 0xfb, 0xf1, 0x4c, 0x99, 0xc5, 0x43, 0x45, 0xba, 0x2b, 0x51, 0xf1, 0x7b, 0x77, 0xb5, 0xf1, 0x5d, 0xb9, 0x2b, 0xba, 0xd8, 0xfa, 0x95, 0xc4, 0x71, 0xf5, 0xd0, 0x70, 0xa1, 0x37, 0xcc },
+      { 0x33, 0x79, 0xcb, 0xaa, 0xe5, 0x62, 0xa8, 0x7b, 0x4c, 0x04, 0x25, 0x55, 0x0f, 0xfd, 0xd6, 0xbf, 0xe1, 0x20, 0x3f, 0x0d, 0x66, 0x6c, 0xc7, 0xea, 0x09, 0x5b, 0xe4, 0x07, 0xa5, 0xdf, 0xe6, 0x1e, 0xe9, 0x14, 0x41, 0xcd, 0x51, 0x54, 0xb3, 0xe5, 0x3b, 0x4f, 0x5f, 0xb3, 0x1a, 0xd4, 0xc7, 0xa9, 0xad, 0x5c, 0x7a, 0xf4, 0xae, 0x67, 0x9a, 0xa5, 0x1a, 0x54, 0x00, 0x3a, 0x54, 0xca, 0x6b, 0x2d },
+      { 0x30, 0x95, 0xa3, 0x49, 0xd2, 0x45, 0x70, 0x8c, 0x7c, 0xf5, 0x50, 0x11, 0x87, 0x03, 0xd7, 0x30, 0x2c, 0x27, 0xb6, 0x0a, 0xf5, 0xd4, 0xe6, 0x7f, 0xc9, 0x78, 0xf8, 0xa4, 0xe6, 0x09, 0x53, 0xc7, 0xa0, 0x4f, 0x92, 0xfc, 0xf4, 0x1a, 0xee, 0x64, 0x32, 0x1c, 0xcb, 0x70, 0x7a, 0x89, 0x58, 0x51, 0x55, 0x2b, 0x1e, 0x37, 0xb0, 0x0b, 0xc5, 0xe6, 0xb7, 0x2f, 0xa5, 0xbc, 0xef, 0x9e, 0x3f, 0xff },
+      { 0x07, 0x26, 0x2d, 0x73, 0x8b, 0x09, 0x32, 0x1f, 0x4d, 0xbc, 0xce, 0xc4, 0xbb, 0x26, 0xf4, 0x8c, 0xb0, 0xf0, 0xed, 0x24, 0x6c, 0xe0, 0xb3, 0x1b, 0x9a, 0x6e, 0x7b, 0xc6, 0x83, 0x04, 0x9f, 0x1f, 0x3e, 0x55, 0x45, 0xf2, 0x8c, 0xe9, 0x32, 0xdd, 0x98, 0x5c, 0x5a, 0xb0, 0xf4, 0x3b, 0xd6, 0xde, 0x07, 0x70, 0x56, 0x0a, 0xf3, 0x29, 0x06, 0x5e, 0xd2, 0xe4, 0x9d, 0x34, 0x62, 0x4c, 0x2c, 0xbb },
+      { 0xb6, 0x40, 0x5e, 0xca, 0x8e, 0xe3, 0x31, 0x6c, 0x87, 0x06, 0x1c, 0xc6, 0xec, 0x18, 0xdb, 0xa5, 0x3e, 0x6c, 0x25, 0x0c, 0x63, 0xba, 0x1f, 0x3b, 0xae, 0x9e, 0x55, 0xdd, 0x34, 0x98, 0x03, 0x6a, 0xf0, 0x8c, 0xd2, 0x72, 0xaa, 0x24, 0xd7, 0x13, 0xc6, 0x02, 0x0d, 0x77, 0xab, 0x2f, 0x39, 0x19, 0xaf, 0x1a, 0x32, 0xf3, 0x07, 0x42, 0x06, 0x18, 0xab, 0x97, 0xe7, 0x39, 0x53, 0x99, 0x4f, 0xb4 },
+      { 0x7e, 0xe6, 0x82, 0xf6, 0x31, 0x48, 0xee, 0x45, 0xf6, 0xe5, 0x31, 0x5d, 0xa8, 0x1e, 0x5c, 0x6e, 0x55, 0x7c, 0x2c, 0x34, 0x64, 0x1f, 0xc5, 0x09, 0xc7, 0xa5, 0x70, 0x10, 0x88, 0xc3, 0x8a, 0x74, 0x75, 0x61, 0x68, 0xe2, 0xcd, 0x8d, 0x35, 0x1e, 0x88, 0xfd, 0x1a, 0x45, 0x1f, 0x36, 0x0a, 0x01, 0xf5, 0xb2, 0x58, 0x0f, 0x9b, 0x5a, 0x2e, 0x8c, 0xfc, 0x13, 0x8f, 0x3d, 0xd5, 0x9a, 0x3f, 0xfc },
+      { 0x1d, 0x26, 0x3c, 0x17, 0x9d, 0x6b, 0x26, 0x8f, 0x6f, 0xa0, 0x16, 0xf3, 0xa4, 0xf2, 0x9e, 0x94, 0x38, 0x91, 0x12, 0x5e, 0xd8, 0x59, 0x3c, 0x81, 0x25, 0x60, 0x59, 0xf5, 0xa7, 0xb4, 0x4a, 0xf2, 0xdc, 0xb2, 0x03, 0x0d, 0x17, 0x5c, 0x00, 0xe6, 0x2e, 0xca, 0xf7, 0xee, 0x96, 0x68, 0x2a, 0xa0, 0x7a, 0xb2, 0x0a, 0x61, 0x10, 0x24, 0xa2, 0x85, 0x32, 0xb1, 0xc2, 0x5b, 0x86, 0x65, 0x79, 0x02 },
+      { 0x10, 0x6d, 0x13, 0x2c, 0xbd, 0xb4, 0xcd, 0x25, 0x97, 0x81, 0x28, 0x46, 0xe2, 0xbc, 0x1b, 0xf7, 0x32, 0xfe, 0xc5, 0xf0, 0xa5, 0xf6, 0x5d, 0xbb, 0x39, 0xec, 0x4e, 0x6d, 0xc6, 0x4a, 0xb2, 0xce, 0x6d, 0x24, 0x63, 0x0d, 0x0f, 0x15, 0xa8, 0x05, 0xc3, 0x54, 0x00, 0x25, 0xd8, 0x4a, 0xfa, 0x98, 0xe3, 0x67, 0x03, 0xc3, 0xdb, 0xee, 0x71, 0x3e, 0x72, 0xdd, 0xe8, 0x46, 0x5b, 0xc1, 0xbe, 0x7e },
+      { 0x0e, 0x79, 0x96, 0x82, 0x26, 0x65, 0x06, 0x67, 0xa8, 0xd8, 0x62, 0xea, 0x8d, 0xa4, 0x89, 0x1a, 0xf5, 0x6a, 0x4e, 0x3a, 0x8b, 0x6d, 0x17, 0x50, 0xe3, 0x94, 0xf0, 0xde, 0xa7, 0x6d, 0x64, 0x0d, 0x85, 0x07, 0x7b, 0xce, 0xc2, 0xcc, 0x86, 0x88, 0x6e, 0x50, 0x67, 0x51, 0xb4, 0xf6, 0xa5, 0x83, 0x8f, 0x7f, 0x0b, 0x5f, 0xef, 0x76, 0x5d, 0x9d, 0xc9, 0x0d, 0xcd, 0xcb, 0xaf, 0x07, 0x9f, 0x08 },
+      { 0x52, 0x11, 0x56, 0xa8, 0x2a, 0xb0, 0xc4, 0xe5, 0x66, 0xe5, 0x84, 0x4d, 0x5e, 0x31, 0xad, 0x9a, 0xaf, 0x14, 0x4b, 0xbd, 0x5a, 0x46, 0x4f, 0xdc, 0xa3, 0x4d, 0xbd, 0x57, 0x17, 0xe8, 0xff, 0x71, 0x1d, 0x3f, 0xfe, 0xbb, 0xfa, 0x08, 0x5d, 0x67, 0xfe, 0x99, 0x6a, 0x34, 0xf6, 0xd3, 0xe4, 0xe6, 0x0b, 0x13, 0x96, 0xbf, 0x4b, 0x16, 0x10, 0xc2, 0x63, 0xbd, 0xbb, 0x83, 0x4d, 0x56, 0x08, 0x16 },
+      { 0x1a, 0xba, 0x88, 0xbe, 0xfc, 0x55, 0xbc, 0x25, 0xef, 0xbc, 0xe0, 0x2d, 0xb8, 0xb9, 0x93, 0x3e, 0x46, 0xf5, 0x76, 0x61, 0xba, 0xea, 0xbe, 0xb2, 0x1c, 0xc2, 0x57, 0x4d, 0x2a, 0x51, 0x8a, 0x3c, 0xba, 0x5d, 0xc5, 0xa3, 0x8e, 0x49, 0x71, 0x34, 0x40, 0xb2, 0x5f, 0x9c, 0x74, 0x4e, 0x75, 0xf6, 0xb8, 0x5c, 0x9d, 0x8f, 0x46, 0x81, 0xf6, 0x76, 0x16, 0x0f, 0x61, 0x05, 0x35, 0x7b, 0x84, 0x06 },
+      { 0x5a, 0x99, 0x49, 0xfc, 0xb2, 0xc4, 0x73, 0xcd, 0xa9, 0x68, 0xac, 0x1b, 0x5d, 0x08, 0x56, 0x6d, 0xc2, 0xd8, 0x16, 0xd9, 0x60, 0xf5, 0x7e, 0x63, 0xb8, 0x98, 0xfa, 0x70, 0x1c, 0xf8, 0xeb, 0xd3, 0xf5, 0x9b, 0x12, 0x4d, 0x95, 0xbf, 0xbb, 0xed, 0xc5, 0xf1, 0xcf, 0x0e, 0x17, 0xd5, 0xea, 0xed, 0x0c, 0x02, 0xc5, 0x0b, 0x69, 0xd8, 0xa4, 0x02, 0xca, 0xbc, 0xca, 0x44, 0x33, 0xb5, 0x1f, 0xd4 },
+      { 0xb0, 0xce, 0xad, 0x09, 0x80, 0x7c, 0x67, 0x2a, 0xf2, 0xeb, 0x2b, 0x0f, 0x06, 0xdd, 0xe4, 0x6c, 0xf5, 0x37, 0x0e, 0x15, 0xa4, 0x09, 0x6b, 0x1a, 0x7d, 0x7c, 0xbb, 0x36, 0xec, 0x31, 0xc2, 0x05, 0xfb, 0xef, 0xca, 0x00, 0xb7, 0xa4, 0x16, 0x2f, 0xa8, 0x9f, 0xb4, 0xfb, 0x3e, 0xb7, 0x8d, 0x79, 0x77, 0x0c, 0x23, 0xf4, 0x4e, 0x72, 0x06, 0x66, 0x4c, 0xe3, 0xcd, 0x93, 0x1c, 0x29, 0x1e, 0x5d },
+      { 0xbb, 0x66, 0x64, 0x93, 0x1e, 0xc9, 0x70, 0x44, 0xe4, 0x5b, 0x2a, 0xe4, 0x20, 0xae, 0x1c, 0x55, 0x1a, 0x88, 0x74, 0xbc, 0x93, 0x7d, 0x08, 0xe9, 0x69, 0x39, 0x9c, 0x39, 0x64, 0xeb, 0xdb, 0xa8, 0x34, 0x6c, 0xdd, 0x5d, 0x09, 0xca, 0xaf, 0xe4, 0xc2, 0x8b, 0xa7, 0xec, 0x78, 0x81, 0x91, 0xce, 0xca, 0x65, 0xdd, 0xd6, 0xf9, 0x5f, 0x18, 0x58, 0x3e, 0x04, 0x0d, 0x0f, 0x30, 0xd0, 0x36, 0x4d },
+      { 0x65, 0xbc, 0x77, 0x0a, 0x5f, 0xaa, 0x37, 0x92, 0x36, 0x98, 0x03, 0x68, 0x3e, 0x84, 0x4b, 0x0b, 0xe7, 0xee, 0x96, 0xf2, 0x9f, 0x6d, 0x6a, 0x35, 0x56, 0x80, 0x06, 0xbd, 0x55, 0x90, 0xf9, 0xa4, 0xef, 0x63, 0x9b, 0x7a, 0x80, 0x61, 0xc7, 0xb0, 0x42, 0x4b, 0x66, 0xb6, 0x0a, 0xc3, 0x4a, 0xf3, 0x11, 0x99, 0x05, 0xf3, 0x3a, 0x9d, 0x8c, 0x3a, 0xe1, 0x83, 0x82, 0xca, 0x9b, 0x68, 0x99, 0x00 },
+      { 0xea, 0x9b, 0x4d, 0xca, 0x33, 0x33, 0x36, 0xaa, 0xf8, 0x39, 0xa4, 0x5c, 0x6e, 0xaa, 0x48, 0xb8, 0xcb, 0x4c, 0x7d, 0xda, 0xbf, 0xfe, 0xa4, 0xf6, 0x43, 0xd6, 0x35, 0x7e, 0xa6, 0x62, 0x8a, 0x48, 0x0a, 0x5b, 0x45, 0xf2, 0xb0, 0x52, 0xc1, 0xb0, 0x7d, 0x1f, 0xed, 0xca, 0x91, 0x8b, 0x6f, 0x11, 0x39, 0xd8, 0x0f, 0x74, 0xc2, 0x45, 0x10, 0xdc, 0xba, 0xa4, 0xbe, 0x70, 0xea, 0xcc, 0x1b, 0x06 },
+      { 0xe6, 0x34, 0x2f, 0xb4, 0xa7, 0x80, 0xad, 0x97, 0x5d, 0x0e, 0x24, 0xbc, 0xe1, 0x49, 0x98, 0x9b, 0x91, 0xd3, 0x60, 0x55, 0x7e, 0x87, 0x99, 0x4f, 0x6b, 0x45, 0x7b, 0x89, 0x55, 0x75, 0xcc, 0x02, 0xd0, 0xc1, 0x5b, 0xad, 0x3c, 0xe7, 0x57, 0x7f, 0x4c, 0x63, 0x92, 0x7f, 0xf1, 0x3f, 0x3e, 0x38, 0x1f, 0xf7, 0xe7, 0x2b, 0xdb, 0xe7, 0x45, 0x32, 0x48, 0x44, 0xa9, 0xd2, 0x7e, 0x3f, 0x1c, 0x01 },
+      { 0x3e, 0x20, 0x9c, 0x9b, 0x33, 0xe8, 0xe4, 0x61, 0x17, 0x8a, 0xb4, 0x6b, 0x1c, 0x64, 0xb4, 0x9a, 0x07, 0xfb, 0x74, 0x5f, 0x1c, 0x8b, 0xc9, 0x5f, 0xbf, 0xb9, 0x4c, 0x6b, 0x87, 0xc6, 0x95, 0x16, 0x65, 0x1b, 0x26, 0x4e, 0xf9, 0x80, 0x93, 0x7f, 0xad, 0x41, 0x23, 0x8b, 0x91, 0xdd, 0xc0, 0x11, 0xa5, 0xdd, 0x77, 0x7c, 0x7e, 0xfd, 0x44, 0x94, 0xb4, 0xb6, 0xec, 0xd3, 0xa9, 0xc2, 0x2a, 0xc0 },
+      { 0xfd, 0x6a, 0x3d, 0x5b, 0x18, 0x75, 0xd8, 0x04, 0x86, 0xd6, 0xe6, 0x96, 0x94, 0xa5, 0x6d, 0xbb, 0x04, 0xa9, 0x9a, 0x4d, 0x05, 0x1f, 0x15, 0xdb, 0x26, 0x89, 0x77, 0x6b, 0xa1, 0xc4, 0x88, 0x2e, 0x6d, 0x46, 0x2a, 0x60, 0x3b, 0x70, 0x15, 0xdc, 0x9f, 0x4b, 0x74, 0x50, 0xf0, 0x53, 0x94, 0x30, 0x3b, 0x86, 0x52, 0xcf, 0xb4, 0x04, 0xa2, 0x66, 0x96, 0x2c, 0x41, 0xba, 0xe6, 0xe1, 0x8a, 0x94 },
+      { 0x95, 0x1e, 0x27, 0x51, 0x7e, 0x6b, 0xad, 0x9e, 0x41, 0x95, 0xfc, 0x86, 0x71, 0xde, 0xe3, 0xe7, 0xe9, 0xbe, 0x69, 0xce, 0xe1, 0x42, 0x2c, 0xb9, 0xfe, 0xcf, 0xce, 0x0d, 0xba, 0x87, 0x5f, 0x7b, 0x31, 0x0b, 0x93, 0xee, 0x3a, 0x3d, 0x55, 0x8f, 0x94, 0x1f, 0x63, 0x5f, 0x66, 0x8f, 0xf8, 0x32, 0xd2, 0xc1, 0xd0, 0x33, 0xc5, 0xe2, 0xf0, 0x99, 0x7e, 0x4c, 0x66, 0xf1, 0x47, 0x34, 0x4e, 0x02 },
+      { 0x8e, 0xba, 0x2f, 0x87, 0x4f, 0x1a, 0xe8, 0x40, 0x41, 0x90, 0x3c, 0x7c, 0x42, 0x53, 0xc8, 0x22, 0x92, 0x53, 0x0f, 0xc8, 0x50, 0x95, 0x50, 0xbf, 0xdc, 0x34, 0xc9, 0x5c, 0x7e, 0x28, 0x89, 0xd5, 0x65, 0x0b, 0x0a, 0xd8, 0xcb, 0x98, 0x8e, 0x5c, 0x48, 0x94, 0xcb, 0x87, 0xfb, 0xfb, 0xb1, 0x96, 0x12, 0xea, 0x93, 0xcc, 0xc4, 0xc5, 0xca, 0xd1, 0x71, 0x58, 0xb9, 0x76, 0x34, 0x64, 0xb4, 0x92 },
+      { 0x16, 0xf7, 0x12, 0xea, 0xa1, 0xb7, 0xc6, 0x35, 0x47, 0x19, 0xa8, 0xe7, 0xdb, 0xdf, 0xaf, 0x55, 0xe4, 0x06, 0x3a, 0x4d, 0x27, 0x7d, 0x94, 0x75, 0x50, 0x01, 0x9b, 0x38, 0xdf, 0xb5, 0x64, 0x83, 0x09, 0x11, 0x05, 0x7d, 0x50, 0x50, 0x61, 0x36, 0xe2, 0x39, 0x4c, 0x3b, 0x28, 0x94, 0x5c, 0xc9, 0x64, 0x96, 0x7d, 0x54, 0xe3, 0x00, 0x0c, 0x21, 0x81, 0x62, 0x6c, 0xfb, 0x9b, 0x73, 0xef, 0xd2 },
+      { 0xc3, 0x96, 0x39, 0xe7, 0xd5, 0xc7, 0xfb, 0x8c, 0xdd, 0x0f, 0xd3, 0xe6, 0xa5, 0x20, 0x96, 0x03, 0x94, 0x37, 0x12, 0x2f, 0x21, 0xc7, 0x8f, 0x16, 0x79, 0xce, 0xa9, 0xd7, 0x8a, 0x73, 0x4c, 0x56, 0xec, 0xbe, 0xb2, 0x86, 0x54, 0xb4, 0xf1, 0x8e, 0x34, 0x2c, 0x33, 0x1f, 0x6f, 0x72, 0x29, 0xec, 0x4b, 0x4b, 0xc2, 0x81, 0xb2, 0xd8, 0x0a, 0x6e, 0xb5, 0x00, 0x43, 0xf3, 0x17, 0x96, 0xc8, 0x8c },
+      { 0x72, 0xd0, 0x81, 0xaf, 0x99, 0xf8, 0xa1, 0x73, 0xdc, 0xc9, 0xa0, 0xac, 0x4e, 0xb3, 0x55, 0x74, 0x05, 0x63, 0x9a, 0x29, 0x08, 0x4b, 0x54, 0xa4, 0x01, 0x72, 0x91, 0x2a, 0x2f, 0x8a, 0x39, 0x51, 0x29, 0xd5, 0x53, 0x6f, 0x09, 0x18, 0xe9, 0x02, 0xf9, 0xe8, 0xfa, 0x60, 0x00, 0x99, 0x5f, 0x41, 0x68, 0xdd, 0xc5, 0xf8, 0x93, 0x01, 0x1b, 0xe6, 0xa0, 0xdb, 0xc9, 0xb8, 0xa1, 0xa3, 0xf5, 0xbb },
+      { 0xc1, 0x1a, 0xa8, 0x1e, 0x5e, 0xfd, 0x24, 0xd5, 0xfc, 0x27, 0xee, 0x58, 0x6c, 0xfd, 0x88, 0x47, 0xfb, 0xb0, 0xe2, 0x76, 0x01, 0xcc, 0xec, 0xe5, 0xec, 0xca, 0x01, 0x98, 0xe3, 0xc7, 0x76, 0x53, 0x93, 0xbb, 0x74, 0x45, 0x7c, 0x7e, 0x7a, 0x27, 0xeb, 0x91, 0x70, 0x35, 0x0e, 0x1f, 0xb5, 0x38, 0x57, 0x17, 0x75, 0x06, 0xbe, 0x3e, 0x76, 0x2c, 0xc0, 0xf1, 0x4d, 0x8c, 0x3a, 0xfe, 0x90, 0x77 },
+      { 0xc2, 0x8f, 0x21, 0x50, 0xb4, 0x52, 0xe6, 0xc0, 0xc4, 0x24, 0xbc, 0xde, 0x6f, 0x8d, 0x72, 0x00, 0x7f, 0x93, 0x10, 0xfe, 0xd7, 0xf2, 0xf8, 0x7d, 0xe0, 0xdb, 0xb6, 0x4f, 0x44, 0x79, 0xd6, 0xc1, 0x44, 0x1b, 0xa6, 0x6f, 0x44, 0xb2, 0xac, 0xce, 0xe6, 0x16, 0x09, 0x17, 0x7e, 0xd3, 0x40, 0x12, 0x8b, 0x40, 0x7e, 0xce, 0xc7, 0xc6, 0x4b, 0xbe, 0x50, 0xd6, 0x3d, 0x22, 0xd8, 0x62, 0x77, 0x27 },
+      { 0xf6, 0x3d, 0x88, 0x12, 0x28, 0x77, 0xec, 0x30, 0xb8, 0xc8, 0xb0, 0x0d, 0x22, 0xe8, 0x90, 0x00, 0xa9, 0x66, 0x42, 0x61, 0x12, 0xbd, 0x44, 0x16, 0x6e, 0x2f, 0x52, 0x5b, 0x76, 0x9c, 0xcb, 0xe9, 0xb2, 0x86, 0xd4, 0x37, 0xa0, 0x12, 0x91, 0x30, 0xdd, 0xe1, 0xa8, 0x6c, 0x43, 0xe0, 0x4b, 0xed, 0xb5, 0x94, 0xe6, 0x71, 0xd9, 0x82, 0x83, 0xaf, 0xe6, 0x4c, 0xe3, 0x31, 0xde, 0x98, 0x28, 0xfd },
+      { 0x34, 0x8b, 0x05, 0x32, 0x88, 0x0b, 0x88, 0xa6, 0x61, 0x4a, 0x8d, 0x74, 0x08, 0xc3, 0xf9, 0x13, 0x35, 0x7f, 0xbb, 0x60, 0xe9, 0x95, 0xc6, 0x02, 0x05, 0xbe, 0x91, 0x39, 0xe7, 0x49, 0x98, 0xae, 0xde, 0x7f, 0x45, 0x81, 0xe4, 0x2f, 0x6b, 0x52, 0x69, 0x8f, 0x7f, 0xa1, 0x21, 0x97, 0x08, 0xc1, 0x44, 0x98, 0x06, 0x7f, 0xd1, 0xe0, 0x95, 0x02, 0xde, 0x83, 0xa7, 0x7d, 0xd2, 0x81, 0x15, 0x0c },
+      { 0x51, 0x33, 0xdc, 0x8b, 0xef, 0x72, 0x53, 0x59, 0xdf, 0xf5, 0x97, 0x92, 0xd8, 0x5e, 0xaf, 0x75, 0xb7, 0xe1, 0xdc, 0xd1, 0x97, 0x8b, 0x01, 0xc3, 0x5b, 0x1b, 0x85, 0xfc, 0xeb, 0xc6, 0x33, 0x88, 0xad, 0x99, 0xa1, 0x7b, 0x63, 0x46, 0xa2, 0x17, 0xdc, 0x1a, 0x96, 0x22, 0xeb, 0xd1, 0x22, 0xec, 0xf6, 0x91, 0x3c, 0x4d, 0x31, 0xa6, 0xb5, 0x2a, 0x69, 0x5b, 0x86, 0xaf, 0x00, 0xd7, 0x41, 0xa0 },
+      { 0x27, 0x53, 0xc4, 0xc0, 0xe9, 0x8e, 0xca, 0xd8, 0x06, 0xe8, 0x87, 0x80, 0xec, 0x27, 0xfc, 0xcd, 0x0f, 0x5c, 0x1a, 0xb5, 0x47, 0xf9, 0xe4, 0xbf, 0x16, 0x59, 0xd1, 0x92, 0xc2, 0x3a, 0xa2, 0xcc, 0x97, 0x1b, 0x58, 0xb6, 0x80, 0x25, 0x80, 0xba, 0xef, 0x8a, 0xdc, 0x3b, 0x77, 0x6e, 0xf7, 0x08, 0x6b, 0x25, 0x45, 0xc2, 0x98, 0x7f, 0x34, 0x8e, 0xe3, 0x71, 0x9c, 0xde, 0xf2, 0x58, 0xc4, 0x03 },
+      { 0xb1, 0x66, 0x35, 0x73, 0xce, 0x4b, 0x9d, 0x8c, 0xae, 0xfc, 0x86, 0x50, 0x12, 0xf3, 0xe3, 0x97, 0x14, 0xb9, 0x89, 0x8a, 0x5d, 0xa6, 0xce, 0x17, 0xc2, 0x5a, 0x6a, 0x47, 0x93, 0x1a, 0x9d, 0xdb, 0x9b, 0xbe, 0x98, 0xad, 0xaa, 0x55, 0x3b, 0xee, 0xd4, 0x36, 0xe8, 0x95, 0x78, 0x45, 0x54, 0x16, 0xc2, 0xa5, 0x2a, 0x52, 0x5c, 0xf2, 0x86, 0x2b, 0x8d, 0x1d, 0x49, 0xa2, 0x53, 0x1b, 0x73, 0x91 },
+      { 0x64, 0xf5, 0x8b, 0xd6, 0xbf, 0xc8, 0x56, 0xf5, 0xe8, 0x73, 0xb2, 0xa2, 0x95, 0x6e, 0xa0, 0xed, 0xa0, 0xd6, 0xdb, 0x0d, 0xa3, 0x9c, 0x8c, 0x7f, 0xc6, 0x7c, 0x9f, 0x9f, 0xee, 0xfc, 0xff, 0x30, 0x72, 0xcd, 0xf9, 0xe6, 0xea, 0x37, 0xf6, 0x9a, 0x44, 0xf0, 0xc6, 0x1a, 0xa0, 0xda, 0x36, 0x93, 0xc2, 0xdb, 0x5b, 0x54, 0x96, 0x0c, 0x02, 0x81, 0xa0, 0x88, 0x15, 0x1d, 0xb4, 0x2b, 0x11, 0xe8 },
+      { 0x07, 0x64, 0xc7, 0xbe, 0x28, 0x12, 0x5d, 0x90, 0x65, 0xc4, 0xb9, 0x8a, 0x69, 0xd6, 0x0a, 0xed, 0xe7, 0x03, 0x54, 0x7c, 0x66, 0xa1, 0x2e, 0x17, 0xe1, 0xc6, 0x18, 0x99, 0x41, 0x32, 0xf5, 0xef, 0x82, 0x48, 0x2c, 0x1e, 0x3f, 0xe3, 0x14, 0x6c, 0xc6, 0x53, 0x76, 0xcc, 0x10, 0x9f, 0x01, 0x38, 0xed, 0x9a, 0x80, 0xe4, 0x9f, 0x1f, 0x3c, 0x7d, 0x61, 0x0d, 0x2f, 0x24, 0x32, 0xf2, 0x06, 0x05 },
+      { 0xf7, 0x48, 0x78, 0x43, 0x98, 0xa2, 0xff, 0x03, 0xeb, 0xeb, 0x07, 0xe1, 0x55, 0xe6, 0x61, 0x16, 0xa8, 0x39, 0x74, 0x1a, 0x33, 0x6e, 0x32, 0xda, 0x71, 0xec, 0x69, 0x60, 0x01, 0xf0, 0xad, 0x1b, 0x25, 0xcd, 0x48, 0xc6, 0x9c, 0xfc, 0xa7, 0x26, 0x5e, 0xca, 0x1d, 0xd7, 0x19, 0x04, 0xa0, 0xce, 0x74, 0x8a, 0xc4, 0x12, 0x4f, 0x35, 0x71, 0x07, 0x6d, 0xfa, 0x71, 0x16, 0xa9, 0xcf, 0x00, 0xe9 },
+      { 0x3f, 0x0d, 0xbc, 0x01, 0x86, 0xbc, 0xeb, 0x6b, 0x78, 0x5b, 0xa7, 0x8d, 0x2a, 0x2a, 0x01, 0x3c, 0x91, 0x0b, 0xe1, 0x57, 0xbd, 0xaf, 0xfa, 0xe8, 0x1b, 0xb6, 0x66, 0x3b, 0x1a, 0x73, 0x72, 0x2f, 0x7f, 0x12, 0x28, 0x79, 0x5f, 0x3e, 0xca, 0xda, 0x87, 0xcf, 0x6e, 0xf0, 0x07, 0x84, 0x74, 0xaf, 0x73, 0xf3, 0x1e, 0xca, 0x0c, 0xc2, 0x00, 0xed, 0x97, 0x5b, 0x68, 0x93, 0xf7, 0x61, 0xcb, 0x6d },
+      { 0xd4, 0x76, 0x2c, 0xd4, 0x59, 0x98, 0x76, 0xca, 0x75, 0xb2, 0xb8, 0xfe, 0x24, 0x99, 0x44, 0xdb, 0xd2, 0x7a, 0xce, 0x74, 0x1f, 0xda, 0xb9, 0x36, 0x16, 0xcb, 0xc6, 0xe4, 0x25, 0x46, 0x0f, 0xeb, 0x51, 0xd4, 0xe7, 0xad, 0xcc, 0x38, 0x18, 0x0e, 0x7f, 0xc4, 0x7c, 0x89, 0x02, 0x4a, 0x7f, 0x56, 0x19, 0x1a, 0xdb, 0x87, 0x8d, 0xfd, 0xe4, 0xea, 0xd6, 0x22, 0x23, 0xf5, 0xa2, 0x61, 0x0e, 0xfe },
+      { 0xcd, 0x36, 0xb3, 0xd5, 0xb4, 0xc9, 0x1b, 0x90, 0xfc, 0xbb, 0xa7, 0x95, 0x13, 0xcf, 0xee, 0x19, 0x07, 0xd8, 0x64, 0x5a, 0x16, 0x2a, 0xfd, 0x0c, 0xd4, 0xcf, 0x41, 0x92, 0xd4, 0xa5, 0xf4, 0xc8, 0x92, 0x18, 0x3a, 0x8e, 0xac, 0xdb, 0x2b, 0x6b, 0x6a, 0x9d, 0x9a, 0xa8, 0xc1, 0x1a, 0xc1, 0xb2, 0x61, 0xb3, 0x80, 0xdb, 0xee, 0x24, 0xca, 0x46, 0x8f, 0x1b, 0xfd, 0x04, 0x3c, 0x58, 0xee, 0xfe },
+      { 0x98, 0x59, 0x34, 0x52, 0x28, 0x16, 0x61, 0xa5, 0x3c, 0x48, 0xa9, 0xd8, 0xcd, 0x79, 0x08, 0x26, 0xc1, 0xa1, 0xce, 0x56, 0x77, 0x38, 0x05, 0x3d, 0x0b, 0xee, 0x4a, 0x91, 0xa3, 0xd5, 0xbd, 0x92, 0xee, 0xfd, 0xba, 0xbe, 0xbe, 0x32, 0x04, 0xf2, 0x03, 0x1c, 0xa5, 0xf7, 0x81, 0xbd, 0xa9, 0x9e, 0xf5, 0xd8, 0xae, 0x56, 0xe5, 0xb0, 0x4a, 0x9e, 0x1e, 0xcd, 0x21, 0xb0, 0xeb, 0x05, 0xd3, 0xe1 },
+      { 0x77, 0x1f, 0x57, 0xdd, 0x27, 0x75, 0xcc, 0xda, 0xb5, 0x59, 0x21, 0xd3, 0xe8, 0xe3, 0x0c, 0xcf, 0x48, 0x4d, 0x61, 0xfe, 0x1c, 0x1b, 0x9c, 0x2a, 0xe8, 0x19, 0xd0, 0xfb, 0x2a, 0x12, 0xfa, 0xb9, 0xbe, 0x70, 0xc4, 0xa7, 0xa1, 0x38, 0xda, 0x84, 0xe8, 0x28, 0x04, 0x35, 0xda, 0xad, 0xe5, 0xbb, 0xe6, 0x6a, 0xf0, 0x83, 0x6a, 0x15, 0x4f, 0x81, 0x7f, 0xb1, 0x7f, 0x33, 0x97, 0xe7, 0x25, 0xa3 },
+      { 0xc6, 0x08, 0x97, 0xc6, 0xf8, 0x28, 0xe2, 0x1f, 0x16, 0xfb, 0xb5, 0xf1, 0x5b, 0x32, 0x3f, 0x87, 0xb6, 0xc8, 0x95, 0x5e, 0xab, 0xf1, 0xd3, 0x80, 0x61, 0xf7, 0x07, 0xf6, 0x08, 0xab, 0xdd, 0x99, 0x3f, 0xac, 0x30, 0x70, 0x63, 0x3e, 0x28, 0x6c, 0xf8, 0x33, 0x9c, 0xe2, 0x95, 0xdd, 0x35, 0x2d, 0xf4, 0xb4, 0xb4, 0x0b, 0x2f, 0x29, 0xda, 0x1d, 0xd5, 0x0b, 0x3a, 0x05, 0xd0, 0x79, 0xe6, 0xbb },
+      { 0x82, 0x10, 0xcd, 0x2c, 0x2d, 0x3b, 0x13, 0x5c, 0x2c, 0xf0, 0x7f, 0xa0, 0xd1, 0x43, 0x3c, 0xd7, 0x71, 0xf3, 0x25, 0xd0, 0x75, 0xc6, 0x46, 0x9d, 0x9c, 0x7f, 0x1b, 0xa0, 0x94, 0x3c, 0xd4, 0xab, 0x09, 0x80, 0x8c, 0xab, 0xf4, 0xac, 0xb9, 0xce, 0x5b, 0xb8, 0x8b, 0x49, 0x89, 0x29, 0xb4, 0xb8, 0x47, 0xf6, 0x81, 0xad, 0x2c, 0x49, 0x0d, 0x04, 0x2d, 0xb2, 0xae, 0xc9, 0x42, 0x14, 0xb0, 0x6b },
+      { 0x1d, 0x4e, 0xdf, 0xff, 0xd8, 0xfd, 0x80, 0xf7, 0xe4, 0x10, 0x78, 0x40, 0xfa, 0x3a, 0xa3, 0x1e, 0x32, 0x59, 0x84, 0x91, 0xe4, 0xaf, 0x70, 0x13, 0xc1, 0x97, 0xa6, 0x5b, 0x7f, 0x36, 0xdd, 0x3a, 0xc4, 0xb4, 0x78, 0x45, 0x61, 0x11, 0xcd, 0x43, 0x09, 0xd9, 0x24, 0x35, 0x10, 0x78, 0x2f, 0xa3, 0x1b, 0x7c, 0x4c, 0x95, 0xfa, 0x95, 0x15, 0x20, 0xd0, 0x20, 0xeb, 0x7e, 0x5c, 0x36, 0xe4, 0xef },
+      { 0xaf, 0x8e, 0x6e, 0x91, 0xfa, 0xb4, 0x6c, 0xe4, 0x87, 0x3e, 0x1a, 0x50, 0xa8, 0xef, 0x44, 0x8c, 0xc2, 0x91, 0x21, 0xf7, 0xf7, 0x4d, 0xee, 0xf3, 0x4a, 0x71, 0xef, 0x89, 0xcc, 0x00, 0xd9, 0x27, 0x4b, 0xc6, 0xc2, 0x45, 0x4b, 0xbb, 0x32, 0x30, 0xd8, 0xb2, 0xec, 0x94, 0xc6, 0x2b, 0x1d, 0xec, 0x85, 0xf3, 0x59, 0x3b, 0xfa, 0x30, 0xea, 0x6f, 0x7a, 0x44, 0xd7, 0xc0, 0x94, 0x65, 0xa2, 0x53 },
+      { 0x29, 0xfd, 0x38, 0x4e, 0xd4, 0x90, 0x6f, 0x2d, 0x13, 0xaa, 0x9f, 0xe7, 0xaf, 0x90, 0x59, 0x90, 0x93, 0x8b, 0xed, 0x80, 0x7f, 0x18, 0x32, 0x45, 0x4a, 0x37, 0x2a, 0xb4, 0x12, 0xee, 0xa1, 0xf5, 0x62, 0x5a, 0x1f, 0xcc, 0x9a, 0xc8, 0x34, 0x3b, 0x7c, 0x67, 0xc5, 0xab, 0xa6, 0xe0, 0xb1, 0xcc, 0x46, 0x44, 0x65, 0x49, 0x13, 0x69, 0x2c, 0x6b, 0x39, 0xeb, 0x91, 0x87, 0xce, 0xac, 0xd3, 0xec },
+      { 0xa2, 0x68, 0xc7, 0x88, 0x5d, 0x98, 0x74, 0xa5, 0x1c, 0x44, 0xdf, 0xfe, 0xd8, 0xea, 0x53, 0xe9, 0x4f, 0x78, 0x45, 0x6e, 0x0b, 0x2e, 0xd9, 0x9f, 0xf5, 0xa3, 0x92, 0x47, 0x60, 0x81, 0x38, 0x26, 0xd9, 0x60, 0xa1, 0x5e, 0xdb, 0xed, 0xbb, 0x5d, 0xe5, 0x22, 0x6b, 0xa4, 0xb0, 0x74, 0xe7, 0x1b, 0x05, 0xc5, 0x5b, 0x97, 0x56, 0xbb, 0x79, 0xe5, 0x5c, 0x02, 0x75, 0x4c, 0x2c, 0x7b, 0x6c, 0x8a },
+      { 0x0c, 0xf8, 0x54, 0x54, 0x88, 0xd5, 0x6a, 0x86, 0x81, 0x7c, 0xd7, 0xec, 0xb1, 0x0f, 0x71, 0x16, 0xb7, 0xea, 0x53, 0x0a, 0x45, 0xb6, 0xea, 0x49, 0x7b, 0x6c, 0x72, 0xc9, 0x97, 0xe0, 0x9e, 0x3d, 0x0d, 0xa8, 0x69, 0x8f, 0x46, 0xbb, 0x00, 0x6f, 0xc9, 0x77, 0xc2, 0xcd, 0x3d, 0x11, 0x77, 0x46, 0x3a, 0xc9, 0x05, 0x7f, 0xdd, 0x16, 0x62, 0xc8, 0x5d, 0x0c, 0x12, 0x64, 0x43, 0xc1, 0x04, 0x73 },
+      { 0xb3, 0x96, 0x14, 0x26, 0x8f, 0xdd, 0x87, 0x81, 0x51, 0x5e, 0x2c, 0xfe, 0xbf, 0x89, 0xb4, 0xd5, 0x40, 0x2b, 0xab, 0x10, 0xc2, 0x26, 0xe6, 0x34, 0x4e, 0x6b, 0x9a, 0xe0, 0x00, 0xfb, 0x0d, 0x6c, 0x79, 0xcb, 0x2f, 0x3e, 0xc8, 0x0e, 0x80, 0xea, 0xeb, 0x19, 0x80, 0xd2, 0xf8, 0x69, 0x89, 0x16, 0xbd, 0x2e, 0x9f, 0x74, 0x72, 0x36, 0x65, 0x51, 0x16, 0x64, 0x9c, 0xd3, 0xca, 0x23, 0xa8, 0x37 },
+      { 0x74, 0xbe, 0xf0, 0x92, 0xfc, 0x6f, 0x1e, 0x5d, 0xba, 0x36, 0x63, 0xa3, 0xfb, 0x00, 0x3b, 0x2a, 0x5b, 0xa2, 0x57, 0x49, 0x65, 0x36, 0xd9, 0x9f, 0x62, 0xb9, 0xd7, 0x3f, 0x8f, 0x9e, 0xb3, 0xce, 0x9f, 0xf3, 0xee, 0xc7, 0x09, 0xeb, 0x88, 0x36, 0x55, 0xec, 0x9e, 0xb8, 0x96, 0xb9, 0x12, 0x8f, 0x2a, 0xfc, 0x89, 0xcf, 0x7d, 0x1a, 0xb5, 0x8a, 0x72, 0xf4, 0xa3, 0xbf, 0x03, 0x4d, 0x2b, 0x4a },
+      { 0x3a, 0x98, 0x8d, 0x38, 0xd7, 0x56, 0x11, 0xf3, 0xef, 0x38, 0xb8, 0x77, 0x49, 0x80, 0xb3, 0x3e, 0x57, 0x3b, 0x6c, 0x57, 0xbe, 0xe0, 0x46, 0x9b, 0xa5, 0xee, 0xd9, 0xb4, 0x4f, 0x29, 0x94, 0x5e, 0x73, 0x47, 0x96, 0x7f, 0xba, 0x2c, 0x16, 0x2e, 0x1c, 0x3b, 0xe7, 0xf3, 0x10, 0xf2, 0xf7, 0x5e, 0xe2, 0x38, 0x1e, 0x7b, 0xfd, 0x6b, 0x3f, 0x0b, 0xae, 0xa8, 0xd9, 0x5d, 0xfb, 0x1d, 0xaf, 0xb1 },
+      { 0x58, 0xae, 0xdf, 0xce, 0x6f, 0x67, 0xdd, 0xc8, 0x5a, 0x28, 0xc9, 0x92, 0xf1, 0xc0, 0xbd, 0x09, 0x69, 0xf0, 0x41, 0xe6, 0x6f, 0x1e, 0xe8, 0x80, 0x20, 0xa1, 0x25, 0xcb, 0xfc, 0xfe, 0xbc, 0xd6, 0x17, 0x09, 0xc9, 0xc4, 0xeb, 0xa1, 0x92, 0xc1, 0x5e, 0x69, 0xf0, 0x20, 0xd4, 0x62, 0x48, 0x60, 0x19, 0xfa, 0x8d, 0xea, 0x0c, 0xd7, 0xa4, 0x29, 0x21, 0xa1, 0x9d, 0x2f, 0xe5, 0x46, 0xd4, 0x3d },
+      { 0x93, 0x47, 0xbd, 0x29, 0x14, 0x73, 0xe6, 0xb4, 0xe3, 0x68, 0x43, 0x7b, 0x8e, 0x56, 0x1e, 0x06, 0x5f, 0x64, 0x9a, 0x6d, 0x8a, 0xda, 0x47, 0x9a, 0xd0, 0x9b, 0x19, 0x99, 0xa8, 0xf2, 0x6b, 0x91, 0xcf, 0x61, 0x20, 0xfd, 0x3b, 0xfe, 0x01, 0x4e, 0x83, 0xf2, 0x3a, 0xcf, 0xa4, 0xc0, 0xad, 0x7b, 0x37, 0x12, 0xb2, 0xc3, 0xc0, 0x73, 0x32, 0x70, 0x66, 0x31, 0x12, 0xcc, 0xd9, 0x28, 0x5c, 0xd9 },
+      { 0xb3, 0x21, 0x63, 0xe7, 0xc5, 0xdb, 0xb5, 0xf5, 0x1f, 0xdc, 0x11, 0xd2, 0xea, 0xc8, 0x75, 0xef, 0xbb, 0xcb, 0x7e, 0x76, 0x99, 0x09, 0x0a, 0x7e, 0x7f, 0xf8, 0xa8, 0xd5, 0x07, 0x95, 0xaf, 0x5d, 0x74, 0xd9, 0xff, 0x98, 0x54, 0x3e, 0xf8, 0xcd, 0xf8, 0x9a, 0xc1, 0x3d, 0x04, 0x85, 0x27, 0x87, 0x56, 0xe0, 0xef, 0x00, 0xc8, 0x17, 0x74, 0x56, 0x61, 0xe1, 0xd5, 0x9f, 0xe3, 0x8e, 0x75, 0x37 },
+      { 0x10, 0x85, 0xd7, 0x83, 0x07, 0xb1, 0xc4, 0xb0, 0x08, 0xc5, 0x7a, 0x2e, 0x7e, 0x5b, 0x23, 0x46, 0x58, 0xa0, 0xa8, 0x2e, 0x4f, 0xf1, 0xe4, 0xaa, 0xac, 0x72, 0xb3, 0x12, 0xfd, 0xa0, 0xfe, 0x27, 0xd2, 0x33, 0xbc, 0x5b, 0x10, 0xe9, 0xcc, 0x17, 0xfd, 0xc7, 0x69, 0x7b, 0x54, 0x0c, 0x7d, 0x95, 0xeb, 0x21, 0x5a, 0x19, 0xa1, 0xa0, 0xe2, 0x0e, 0x1a, 0xbf, 0xa1, 0x26, 0xef, 0xd5, 0x68, 0xc7 },
+      { 0x4e, 0x5c, 0x73, 0x4c, 0x7d, 0xde, 0x01, 0x1d, 0x83, 0xea, 0xc2, 0xb7, 0x34, 0x7b, 0x37, 0x35, 0x94, 0xf9, 0x2d, 0x70, 0x91, 0xb9, 0xca, 0x34, 0xcb, 0x9c, 0x6f, 0x39, 0xbd, 0xf5, 0xa8, 0xd2, 0xf1, 0x34, 0x37, 0x9e, 0x16, 0xd8, 0x22, 0xf6, 0x52, 0x21, 0x70, 0xcc, 0xf2, 0xdd, 0xd5, 0x5c, 0x84, 0xb9, 0xe6, 0xc6, 0x4f, 0xc9, 0x27, 0xac, 0x4c, 0xf8, 0xdf, 0xb2, 0xa1, 0x77, 0x01, 0xf2 },
+      { 0x69, 0x5d, 0x83, 0xbd, 0x99, 0x0a, 0x11, 0x17, 0xb3, 0xd0, 0xce, 0x06, 0xcc, 0x88, 0x80, 0x27, 0xd1, 0x2a, 0x05, 0x4c, 0x26, 0x77, 0xfd, 0x82, 0xf0, 0xd4, 0xfb, 0xfc, 0x93, 0x57, 0x55, 0x23, 0xe7, 0x99, 0x1a, 0x5e, 0x35, 0xa3, 0x75, 0x2e, 0x9b, 0x70, 0xce, 0x62, 0x99, 0x2e, 0x26, 0x8a, 0x87, 0x77, 0x44, 0xcd, 0xd4, 0x35, 0xf5, 0xf1, 0x30, 0x86, 0x9c, 0x9a, 0x20, 0x74, 0xb3, 0x38 },
+      { 0xa6, 0x21, 0x37, 0x43, 0x56, 0x8e, 0x3b, 0x31, 0x58, 0xb9, 0x18, 0x43, 0x01, 0xf3, 0x69, 0x08, 0x47, 0x55, 0x4c, 0x68, 0x45, 0x7c, 0xb4, 0x0f, 0xc9, 0xa4, 0xb8, 0xcf, 0xd8, 0xd4, 0xa1, 0x18, 0xc3, 0x01, 0xa0, 0x77, 0x37, 0xae, 0xda, 0x0f, 0x92, 0x9c, 0x68, 0x91, 0x3c, 0x5f, 0x51, 0xc8, 0x03, 0x94, 0xf5, 0x3b, 0xff, 0x1c, 0x3e, 0x83, 0xb2, 0xe4, 0x0c, 0xa9, 0x7e, 0xba, 0x9e, 0x15 },
+      { 0xd4, 0x44, 0xbf, 0xa2, 0x36, 0x2a, 0x96, 0xdf, 0x21, 0x3d, 0x07, 0x0e, 0x33, 0xfa, 0x84, 0x1f, 0x51, 0x33, 0x4e, 0x4e, 0x76, 0x86, 0x6b, 0x81, 0x39, 0xe8, 0xaf, 0x3b, 0xb3, 0x39, 0x8b, 0xe2, 0xdf, 0xad, 0xdc, 0xbc, 0x56, 0xb9, 0x14, 0x6d, 0xe9, 0xf6, 0x81, 0x18, 0xdc, 0x58, 0x29, 0xe7, 0x4b, 0x0c, 0x28, 0xd7, 0x71, 0x19, 0x07, 0xb1, 0x21, 0xf9, 0x16, 0x1c, 0xb9, 0x2b, 0x69, 0xa9 },
+      { 0x14, 0x27, 0x09, 0xd6, 0x2e, 0x28, 0xfc, 0xcc, 0xd0, 0xaf, 0x97, 0xfa, 0xd0, 0xf8, 0x46, 0x5b, 0x97, 0x1e, 0x82, 0x20, 0x1d, 0xc5, 0x10, 0x70, 0xfa, 0xa0, 0x37, 0x2a, 0xa4, 0x3e, 0x92, 0x48, 0x4b, 0xe1, 0xc1, 0xe7, 0x3b, 0xa1, 0x09, 0x06, 0xd5, 0xd1, 0x85, 0x3d, 0xb6, 0xa4, 0x10, 0x6e, 0x0a, 0x7b, 0xf9, 0x80, 0x0d, 0x37, 0x3d, 0x6d, 0xee, 0x2d, 0x46, 0xd6, 0x2e, 0xf2, 0xa4, 0x61 },
+   };
+   unsigned char inp[1000], out[1000];
+   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, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f };
+   unsigned long ilen, klen = sizeof(key), mlen = 64;
+   blake2bmac_state st;
+
+   for (ilen = 0; ilen < 256; ilen++) inp[ilen] = (unsigned char)ilen;
+
+   for (ilen = 0; ilen < 256; ilen++) {
+      const unsigned char *mac = tests[ilen];
+      unsigned long olen = mlen;
+      /* process piece by piece */
+      if (ilen > 15) {
+        blake2bmac_init(&st, olen, key, klen);
+        blake2bmac_process(&st, (unsigned char*)inp,      5);
+        blake2bmac_process(&st, (unsigned char*)inp + 5,  4);
+        blake2bmac_process(&st, (unsigned char*)inp + 9,  3);
+        blake2bmac_process(&st, (unsigned char*)inp + 12, 2);
+        blake2bmac_process(&st, (unsigned char*)inp + 14, 1);
+        blake2bmac_process(&st, (unsigned char*)inp + 15, ilen - 15);
+        blake2bmac_done(&st, out, &olen);
+        if (compare_testvector(out, olen, mac, mlen, "BLAKE2B MAC multi", ilen) != 0) return CRYPT_FAIL_TESTVECTOR;
+      }
+      /* process in one go */
+      blake2bmac_init(&st, olen, key, klen);
+      blake2bmac_process(&st, (unsigned char*)inp, ilen);
+      blake2bmac_done(&st, out, &olen);
+      if (compare_testvector(out, olen, mac, mlen, "BLAKE2B MAC single", ilen) != 0) return CRYPT_FAIL_TESTVECTOR;
+   }
+   return CRYPT_OK;
+#endif
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/mac/blake2/blake2smac.c b/libtomcrypt/src/mac/blake2/blake2smac.c
new file mode 100644 (file)
index 0000000..080241b
--- /dev/null
@@ -0,0 +1,66 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+#include "tomcrypt.h"
+
+#ifdef LTC_BLAKE2SMAC
+
+/**
+   Initialize an BLAKE2S MAC context.
+   @param st       The BLAKE2S MAC state
+   @param outlen   The size of the MAC output (octets)
+   @param key      The secret key
+   @param keylen   The length of the secret key (octets)
+   @return CRYPT_OK if successful
+*/
+int blake2smac_init(blake2smac_state *st, unsigned long outlen, const unsigned char *key, unsigned long keylen)
+{
+   LTC_ARGCHK(st  != NULL);
+   LTC_ARGCHK(key != NULL);
+   return blake2s_init(st, outlen, key, keylen);
+}
+
+/**
+  Process data through BLAKE2S MAC
+  @param st      The BLAKE2S MAC state
+  @param in      The data to send through HMAC
+  @param inlen   The length of the data to HMAC (octets)
+  @return CRYPT_OK if successful
+*/
+int blake2smac_process(blake2smac_state *st, const unsigned char *in, unsigned long inlen)
+{
+   if (inlen == 0) return CRYPT_OK; /* nothing to do */
+   LTC_ARGCHK(st != NULL);
+   LTC_ARGCHK(in != NULL);
+   return blake2s_process(st, in, inlen);
+}
+
+/**
+   Terminate a BLAKE2S MAC session
+   @param st      The BLAKE2S MAC state
+   @param mac     [out] The destination of the BLAKE2S MAC authentication tag
+   @param maclen  [in/out]  The max size and resulting size of the BLAKE2S MAC authentication tag
+   @return CRYPT_OK if successful
+*/
+int blake2smac_done(blake2smac_state *st, unsigned char *mac, unsigned long *maclen)
+{
+   LTC_ARGCHK(st     != NULL);
+   LTC_ARGCHK(mac    != NULL);
+   LTC_ARGCHK(maclen != NULL);
+   LTC_ARGCHK(*maclen >= st->blake2s.outlen);
+
+   *maclen = st->blake2s.outlen;
+   return blake2s_done(st, mac);
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/mac/blake2/blake2smac_file.c b/libtomcrypt/src/mac/blake2/blake2smac_file.c
new file mode 100644 (file)
index 0000000..1ac6679
--- /dev/null
@@ -0,0 +1,88 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+#include "tomcrypt.h"
+
+#ifdef LTC_BLAKE2SMAC
+
+/**
+  BLAKE2S MAC a file
+  @param fname    The name of the file you wish to BLAKE2S MAC
+  @param key      The secret key
+  @param keylen   The length of the secret key
+  @param mac      [out] The BLAKE2S MAC authentication tag
+  @param maclen   [in/out]  The max size and resulting size of the authentication tag
+  @return CRYPT_OK if successful, CRYPT_NOP if file support has been disabled
+*/
+int blake2smac_file(const char *fname, const unsigned char *key, unsigned long keylen, unsigned char *mac, unsigned long *maclen)
+{
+#ifdef LTC_NO_FILE
+   LTC_UNUSED_PARAM(fname);
+   LTC_UNUSED_PARAM(key);
+   LTC_UNUSED_PARAM(keylen);
+   LTC_UNUSED_PARAM(mac);
+   LTC_UNUSED_PARAM(maclen);
+   return CRYPT_NOP;
+#else
+   blake2smac_state st;
+   FILE *in;
+   unsigned char *buf;
+   size_t x;
+   int err;
+
+   LTC_ARGCHK(fname  != NULL);
+   LTC_ARGCHK(key    != NULL);
+   LTC_ARGCHK(mac    != NULL);
+   LTC_ARGCHK(maclen != NULL);
+
+   if ((buf = XMALLOC(LTC_FILE_READ_BUFSIZE)) == NULL) {
+      return CRYPT_MEM;
+   }
+
+   if ((err = blake2smac_init(&st, *maclen, key, keylen)) != CRYPT_OK) {
+      goto LBL_ERR;
+   }
+
+   in = fopen(fname, "rb");
+   if (in == NULL) {
+      err = CRYPT_FILE_NOTFOUND;
+      goto LBL_ERR;
+   }
+
+   do {
+      x = fread(buf, 1, LTC_FILE_READ_BUFSIZE, in);
+      if ((err = blake2smac_process(&st, buf, (unsigned long)x)) != CRYPT_OK) {
+         fclose(in);
+         goto LBL_CLEANBUF;
+      }
+   } while (x == LTC_FILE_READ_BUFSIZE);
+
+   if (fclose(in) != 0) {
+      err = CRYPT_ERROR;
+      goto LBL_CLEANBUF;
+   }
+
+   err = blake2smac_done(&st, mac, maclen);
+
+LBL_CLEANBUF:
+   zeromem(buf, LTC_FILE_READ_BUFSIZE);
+LBL_ERR:
+#ifdef LTC_CLEAN_STACK
+   zeromem(&st, sizeof(blake2smac_state));
+#endif
+   XFREE(buf);
+   return err;
+#endif
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/mac/blake2/blake2smac_memory.c b/libtomcrypt/src/mac/blake2/blake2smac_memory.c
new file mode 100644 (file)
index 0000000..1661fb0
--- /dev/null
@@ -0,0 +1,48 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+#include "tomcrypt.h"
+
+#ifdef LTC_BLAKE2SMAC
+
+/**
+   BLAKE2S MAC a block of memory to produce the authentication tag
+   @param key       The secret key
+   @param keylen    The length of the secret key (octets)
+   @param in        The data to BLAKE2S MAC
+   @param inlen     The length of the data to BLAKE2S MAC (octets)
+   @param mac       [out] Destination of the authentication tag
+   @param maclen    [in/out] Max size and resulting size of authentication tag
+   @return CRYPT_OK if successful
+*/
+int blake2smac_memory(const unsigned char *key, unsigned long keylen, const unsigned char *in, unsigned long inlen, unsigned char *mac, unsigned long *maclen)
+{
+   blake2smac_state st;
+   int err;
+
+   LTC_ARGCHK(key    != NULL);
+   LTC_ARGCHK(in     != NULL);
+   LTC_ARGCHK(mac    != NULL);
+   LTC_ARGCHK(maclen != NULL);
+
+   if ((err = blake2smac_init(&st, *maclen, key, keylen))  != CRYPT_OK) { goto LBL_ERR; }
+   if ((err = blake2smac_process(&st, in, inlen)) != CRYPT_OK) { goto LBL_ERR; }
+   err = blake2smac_done(&st, mac, maclen);
+LBL_ERR:
+#ifdef LTC_CLEAN_STACK
+   zeromem(&st, sizeof(blake2smac_state));
+#endif
+   return err;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/mac/blake2/blake2smac_memory_multi.c b/libtomcrypt/src/mac/blake2/blake2smac_memory_multi.c
new file mode 100644 (file)
index 0000000..0985c42
--- /dev/null
@@ -0,0 +1,62 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+#include "tomcrypt.h"
+#include <stdarg.h>
+
+#ifdef LTC_BLAKE2SMAC
+
+/**
+   BLAKE2S MAC multiple blocks of memory to produce the authentication tag
+   @param key       The secret key
+   @param keylen    The length of the secret key (octets)
+   @param mac       [out] Destination of the authentication tag
+   @param maclen    [in/out] Max size and resulting size of authentication tag
+   @param in        The data to BLAKE2S MAC
+   @param inlen     The length of the data to BLAKE2S MAC (octets)
+   @param ...       tuples of (data,len) pairs to BLAKE2S MAC, terminated with a (NULL,x) (x=don't care)
+   @return CRYPT_OK if successful
+*/
+int blake2smac_memory_multi(const unsigned char *key, unsigned long keylen, unsigned char *mac, unsigned long *maclen, const unsigned char *in,  unsigned long inlen, ...)
+{
+   blake2smac_state st;
+   int err;
+   va_list args;
+   const unsigned char *curptr;
+   unsigned long curlen;
+
+   LTC_ARGCHK(key    != NULL);
+   LTC_ARGCHK(in     != NULL);
+   LTC_ARGCHK(mac    != NULL);
+   LTC_ARGCHK(maclen != NULL);
+
+   va_start(args, inlen);
+   curptr = in;
+   curlen = inlen;
+   if ((err = blake2smac_init(&st, *maclen, key, keylen)) != CRYPT_OK)          { goto LBL_ERR; }
+   for (;;) {
+      if ((err = blake2smac_process(&st, curptr, curlen)) != CRYPT_OK) { goto LBL_ERR; }
+      curptr = va_arg(args, const unsigned char*);
+      if (curptr == NULL) break;
+      curlen = va_arg(args, unsigned long);
+   }
+   err = blake2smac_done(&st, mac, maclen);
+LBL_ERR:
+#ifdef LTC_CLEAN_STACK
+   zeromem(&st, sizeof(blake2smac_state));
+#endif
+   va_end(args);
+   return err;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/mac/blake2/blake2smac_test.c b/libtomcrypt/src/mac/blake2/blake2smac_test.c
new file mode 100644 (file)
index 0000000..a44ab8d
--- /dev/null
@@ -0,0 +1,314 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+#include "tomcrypt.h"
+
+#ifdef LTC_BLAKE2SMAC
+
+int blake2smac_test(void)
+{
+#ifndef LTC_TEST
+   return CRYPT_NOP;
+#else
+   static const unsigned char tests[256][32] = {
+      /* source: https://github.com/BLAKE2/BLAKE2/blob/master/testvectors/blake2s-kat.txt */
+      { 0x48, 0xa8, 0x99, 0x7d, 0xa4, 0x07, 0x87, 0x6b, 0x3d, 0x79, 0xc0, 0xd9, 0x23, 0x25, 0xad, 0x3b, 0x89, 0xcb, 0xb7, 0x54, 0xd8, 0x6a, 0xb7, 0x1a, 0xee, 0x04, 0x7a, 0xd3, 0x45, 0xfd, 0x2c, 0x49 },
+      { 0x40, 0xd1, 0x5f, 0xee, 0x7c, 0x32, 0x88, 0x30, 0x16, 0x6a, 0xc3, 0xf9, 0x18, 0x65, 0x0f, 0x80, 0x7e, 0x7e, 0x01, 0xe1, 0x77, 0x25, 0x8c, 0xdc, 0x0a, 0x39, 0xb1, 0x1f, 0x59, 0x80, 0x66, 0xf1 },
+      { 0x6b, 0xb7, 0x13, 0x00, 0x64, 0x4c, 0xd3, 0x99, 0x1b, 0x26, 0xcc, 0xd4, 0xd2, 0x74, 0xac, 0xd1, 0xad, 0xea, 0xb8, 0xb1, 0xd7, 0x91, 0x45, 0x46, 0xc1, 0x19, 0x8b, 0xbe, 0x9f, 0xc9, 0xd8, 0x03 },
+      { 0x1d, 0x22, 0x0d, 0xbe, 0x2e, 0xe1, 0x34, 0x66, 0x1f, 0xdf, 0x6d, 0x9e, 0x74, 0xb4, 0x17, 0x04, 0x71, 0x05, 0x56, 0xf2, 0xf6, 0xe5, 0xa0, 0x91, 0xb2, 0x27, 0x69, 0x74, 0x45, 0xdb, 0xea, 0x6b },
+      { 0xf6, 0xc3, 0xfb, 0xad, 0xb4, 0xcc, 0x68, 0x7a, 0x00, 0x64, 0xa5, 0xbe, 0x6e, 0x79, 0x1b, 0xec, 0x63, 0xb8, 0x68, 0xad, 0x62, 0xfb, 0xa6, 0x1b, 0x37, 0x57, 0xef, 0x9c, 0xa5, 0x2e, 0x05, 0xb2 },
+      { 0x49, 0xc1, 0xf2, 0x11, 0x88, 0xdf, 0xd7, 0x69, 0xae, 0xa0, 0xe9, 0x11, 0xdd, 0x6b, 0x41, 0xf1, 0x4d, 0xab, 0x10, 0x9d, 0x2b, 0x85, 0x97, 0x7a, 0xa3, 0x08, 0x8b, 0x5c, 0x70, 0x7e, 0x85, 0x98 },
+      { 0xfd, 0xd8, 0x99, 0x3d, 0xcd, 0x43, 0xf6, 0x96, 0xd4, 0x4f, 0x3c, 0xea, 0x0f, 0xf3, 0x53, 0x45, 0x23, 0x4e, 0xc8, 0xee, 0x08, 0x3e, 0xb3, 0xca, 0xda, 0x01, 0x7c, 0x7f, 0x78, 0xc1, 0x71, 0x43 },
+      { 0xe6, 0xc8, 0x12, 0x56, 0x37, 0x43, 0x8d, 0x09, 0x05, 0xb7, 0x49, 0xf4, 0x65, 0x60, 0xac, 0x89, 0xfd, 0x47, 0x1c, 0xf8, 0x69, 0x2e, 0x28, 0xfa, 0xb9, 0x82, 0xf7, 0x3f, 0x01, 0x9b, 0x83, 0xa9 },
+      { 0x19, 0xfc, 0x8c, 0xa6, 0x97, 0x9d, 0x60, 0xe6, 0xed, 0xd3, 0xb4, 0x54, 0x1e, 0x2f, 0x96, 0x7c, 0xed, 0x74, 0x0d, 0xf6, 0xec, 0x1e, 0xae, 0xbb, 0xfe, 0x81, 0x38, 0x32, 0xe9, 0x6b, 0x29, 0x74 },
+      { 0xa6, 0xad, 0x77, 0x7c, 0xe8, 0x81, 0xb5, 0x2b, 0xb5, 0xa4, 0x42, 0x1a, 0xb6, 0xcd, 0xd2, 0xdf, 0xba, 0x13, 0xe9, 0x63, 0x65, 0x2d, 0x4d, 0x6d, 0x12, 0x2a, 0xee, 0x46, 0x54, 0x8c, 0x14, 0xa7 },
+      { 0xf5, 0xc4, 0xb2, 0xba, 0x1a, 0x00, 0x78, 0x1b, 0x13, 0xab, 0xa0, 0x42, 0x52, 0x42, 0xc6, 0x9c, 0xb1, 0x55, 0x2f, 0x3f, 0x71, 0xa9, 0xa3, 0xbb, 0x22, 0xb4, 0xa6, 0xb4, 0x27, 0x7b, 0x46, 0xdd },
+      { 0xe3, 0x3c, 0x4c, 0x9b, 0xd0, 0xcc, 0x7e, 0x45, 0xc8, 0x0e, 0x65, 0xc7, 0x7f, 0xa5, 0x99, 0x7f, 0xec, 0x70, 0x02, 0x73, 0x85, 0x41, 0x50, 0x9e, 0x68, 0xa9, 0x42, 0x38, 0x91, 0xe8, 0x22, 0xa3 },
+      { 0xfb, 0xa1, 0x61, 0x69, 0xb2, 0xc3, 0xee, 0x10, 0x5b, 0xe6, 0xe1, 0xe6, 0x50, 0xe5, 0xcb, 0xf4, 0x07, 0x46, 0xb6, 0x75, 0x3d, 0x03, 0x6a, 0xb5, 0x51, 0x79, 0x01, 0x4a, 0xd7, 0xef, 0x66, 0x51 },
+      { 0xf5, 0xc4, 0xbe, 0xc6, 0xd6, 0x2f, 0xc6, 0x08, 0xbf, 0x41, 0xcc, 0x11, 0x5f, 0x16, 0xd6, 0x1c, 0x7e, 0xfd, 0x3f, 0xf6, 0xc6, 0x56, 0x92, 0xbb, 0xe0, 0xaf, 0xff, 0xb1, 0xfe, 0xde, 0x74, 0x75 },
+      { 0xa4, 0x86, 0x2e, 0x76, 0xdb, 0x84, 0x7f, 0x05, 0xba, 0x17, 0xed, 0xe5, 0xda, 0x4e, 0x7f, 0x91, 0xb5, 0x92, 0x5c, 0xf1, 0xad, 0x4b, 0xa1, 0x27, 0x32, 0xc3, 0x99, 0x57, 0x42, 0xa5, 0xcd, 0x6e },
+      { 0x65, 0xf4, 0xb8, 0x60, 0xcd, 0x15, 0xb3, 0x8e, 0xf8, 0x14, 0xa1, 0xa8, 0x04, 0x31, 0x4a, 0x55, 0xbe, 0x95, 0x3c, 0xaa, 0x65, 0xfd, 0x75, 0x8a, 0xd9, 0x89, 0xff, 0x34, 0xa4, 0x1c, 0x1e, 0xea },
+      { 0x19, 0xba, 0x23, 0x4f, 0x0a, 0x4f, 0x38, 0x63, 0x7d, 0x18, 0x39, 0xf9, 0xd9, 0xf7, 0x6a, 0xd9, 0x1c, 0x85, 0x22, 0x30, 0x71, 0x43, 0xc9, 0x7d, 0x5f, 0x93, 0xf6, 0x92, 0x74, 0xce, 0xc9, 0xa7 },
+      { 0x1a, 0x67, 0x18, 0x6c, 0xa4, 0xa5, 0xcb, 0x8e, 0x65, 0xfc, 0xa0, 0xe2, 0xec, 0xbc, 0x5d, 0xdc, 0x14, 0xae, 0x38, 0x1b, 0xb8, 0xbf, 0xfe, 0xb9, 0xe0, 0xa1, 0x03, 0x44, 0x9e, 0x3e, 0xf0, 0x3c },
+      { 0xaf, 0xbe, 0xa3, 0x17, 0xb5, 0xa2, 0xe8, 0x9c, 0x0b, 0xd9, 0x0c, 0xcf, 0x5d, 0x7f, 0xd0, 0xed, 0x57, 0xfe, 0x58, 0x5e, 0x4b, 0xe3, 0x27, 0x1b, 0x0a, 0x6b, 0xf0, 0xf5, 0x78, 0x6b, 0x0f, 0x26 },
+      { 0xf1, 0xb0, 0x15, 0x58, 0xce, 0x54, 0x12, 0x62, 0xf5, 0xec, 0x34, 0x29, 0x9d, 0x6f, 0xb4, 0x09, 0x00, 0x09, 0xe3, 0x43, 0x4b, 0xe2, 0xf4, 0x91, 0x05, 0xcf, 0x46, 0xaf, 0x4d, 0x2d, 0x41, 0x24 },
+      { 0x13, 0xa0, 0xa0, 0xc8, 0x63, 0x35, 0x63, 0x5e, 0xaa, 0x74, 0xca, 0x2d, 0x5d, 0x48, 0x8c, 0x79, 0x7b, 0xbb, 0x4f, 0x47, 0xdc, 0x07, 0x10, 0x50, 0x15, 0xed, 0x6a, 0x1f, 0x33, 0x09, 0xef, 0xce },
+      { 0x15, 0x80, 0xaf, 0xee, 0xbe, 0xbb, 0x34, 0x6f, 0x94, 0xd5, 0x9f, 0xe6, 0x2d, 0xa0, 0xb7, 0x92, 0x37, 0xea, 0xd7, 0xb1, 0x49, 0x1f, 0x56, 0x67, 0xa9, 0x0e, 0x45, 0xed, 0xf6, 0xca, 0x8b, 0x03 },
+      { 0x20, 0xbe, 0x1a, 0x87, 0x5b, 0x38, 0xc5, 0x73, 0xdd, 0x7f, 0xaa, 0xa0, 0xde, 0x48, 0x9d, 0x65, 0x5c, 0x11, 0xef, 0xb6, 0xa5, 0x52, 0x69, 0x8e, 0x07, 0xa2, 0xd3, 0x31, 0xb5, 0xf6, 0x55, 0xc3 },
+      { 0xbe, 0x1f, 0xe3, 0xc4, 0xc0, 0x40, 0x18, 0xc5, 0x4c, 0x4a, 0x0f, 0x6b, 0x9a, 0x2e, 0xd3, 0xc5, 0x3a, 0xbe, 0x3a, 0x9f, 0x76, 0xb4, 0xd2, 0x6d, 0xe5, 0x6f, 0xc9, 0xae, 0x95, 0x05, 0x9a, 0x99 },
+      { 0xe3, 0xe3, 0xac, 0xe5, 0x37, 0xeb, 0x3e, 0xdd, 0x84, 0x63, 0xd9, 0xad, 0x35, 0x82, 0xe1, 0x3c, 0xf8, 0x65, 0x33, 0xff, 0xde, 0x43, 0xd6, 0x68, 0xdd, 0x2e, 0x93, 0xbb, 0xdb, 0xd7, 0x19, 0x5a },
+      { 0x11, 0x0c, 0x50, 0xc0, 0xbf, 0x2c, 0x6e, 0x7a, 0xeb, 0x7e, 0x43, 0x5d, 0x92, 0xd1, 0x32, 0xab, 0x66, 0x55, 0x16, 0x8e, 0x78, 0xa2, 0xde, 0xcd, 0xec, 0x33, 0x30, 0x77, 0x76, 0x84, 0xd9, 0xc1 },
+      { 0xe9, 0xba, 0x8f, 0x50, 0x5c, 0x9c, 0x80, 0xc0, 0x86, 0x66, 0xa7, 0x01, 0xf3, 0x36, 0x7e, 0x6c, 0xc6, 0x65, 0xf3, 0x4b, 0x22, 0xe7, 0x3c, 0x3c, 0x04, 0x17, 0xeb, 0x1c, 0x22, 0x06, 0x08, 0x2f },
+      { 0x26, 0xcd, 0x66, 0xfc, 0xa0, 0x23, 0x79, 0xc7, 0x6d, 0xf1, 0x23, 0x17, 0x05, 0x2b, 0xca, 0xfd, 0x6c, 0xd8, 0xc3, 0xa7, 0xb8, 0x90, 0xd8, 0x05, 0xf3, 0x6c, 0x49, 0x98, 0x97, 0x82, 0x43, 0x3a },
+      { 0x21, 0x3f, 0x35, 0x96, 0xd6, 0xe3, 0xa5, 0xd0, 0xe9, 0x93, 0x2c, 0xd2, 0x15, 0x91, 0x46, 0x01, 0x5e, 0x2a, 0xbc, 0x94, 0x9f, 0x47, 0x29, 0xee, 0x26, 0x32, 0xfe, 0x1e, 0xdb, 0x78, 0xd3, 0x37 },
+      { 0x10, 0x15, 0xd7, 0x01, 0x08, 0xe0, 0x3b, 0xe1, 0xc7, 0x02, 0xfe, 0x97, 0x25, 0x36, 0x07, 0xd1, 0x4a, 0xee, 0x59, 0x1f, 0x24, 0x13, 0xea, 0x67, 0x87, 0x42, 0x7b, 0x64, 0x59, 0xff, 0x21, 0x9a },
+      { 0x3c, 0xa9, 0x89, 0xde, 0x10, 0xcf, 0xe6, 0x09, 0x90, 0x94, 0x72, 0xc8, 0xd3, 0x56, 0x10, 0x80, 0x5b, 0x2f, 0x97, 0x77, 0x34, 0xcf, 0x65, 0x2c, 0xc6, 0x4b, 0x3b, 0xfc, 0x88, 0x2d, 0x5d, 0x89 },
+      { 0xb6, 0x15, 0x6f, 0x72, 0xd3, 0x80, 0xee, 0x9e, 0xa6, 0xac, 0xd1, 0x90, 0x46, 0x4f, 0x23, 0x07, 0xa5, 0xc1, 0x79, 0xef, 0x01, 0xfd, 0x71, 0xf9, 0x9f, 0x2d, 0x0f, 0x7a, 0x57, 0x36, 0x0a, 0xea },
+      { 0xc0, 0x3b, 0xc6, 0x42, 0xb2, 0x09, 0x59, 0xcb, 0xe1, 0x33, 0xa0, 0x30, 0x3e, 0x0c, 0x1a, 0xbf, 0xf3, 0xe3, 0x1e, 0xc8, 0xe1, 0xa3, 0x28, 0xec, 0x85, 0x65, 0xc3, 0x6d, 0xec, 0xff, 0x52, 0x65 },
+      { 0x2c, 0x3e, 0x08, 0x17, 0x6f, 0x76, 0x0c, 0x62, 0x64, 0xc3, 0xa2, 0xcd, 0x66, 0xfe, 0xc6, 0xc3, 0xd7, 0x8d, 0xe4, 0x3f, 0xc1, 0x92, 0x45, 0x7b, 0x2a, 0x4a, 0x66, 0x0a, 0x1e, 0x0e, 0xb2, 0x2b },
+      { 0xf7, 0x38, 0xc0, 0x2f, 0x3c, 0x1b, 0x19, 0x0c, 0x51, 0x2b, 0x1a, 0x32, 0xde, 0xab, 0xf3, 0x53, 0x72, 0x8e, 0x0e, 0x9a, 0xb0, 0x34, 0x49, 0x0e, 0x3c, 0x34, 0x09, 0x94, 0x6a, 0x97, 0xae, 0xec },
+      { 0x8b, 0x18, 0x80, 0xdf, 0x30, 0x1c, 0xc9, 0x63, 0x41, 0x88, 0x11, 0x08, 0x89, 0x64, 0x83, 0x92, 0x87, 0xff, 0x7f, 0xe3, 0x1c, 0x49, 0xea, 0x6e, 0xbd, 0x9e, 0x48, 0xbd, 0xee, 0xe4, 0x97, 0xc5 },
+      { 0x1e, 0x75, 0xcb, 0x21, 0xc6, 0x09, 0x89, 0x02, 0x03, 0x75, 0xf1, 0xa7, 0xa2, 0x42, 0x83, 0x9f, 0x0b, 0x0b, 0x68, 0x97, 0x3a, 0x4c, 0x2a, 0x05, 0xcf, 0x75, 0x55, 0xed, 0x5a, 0xae, 0xc4, 0xc1 },
+      { 0x62, 0xbf, 0x8a, 0x9c, 0x32, 0xa5, 0xbc, 0xcf, 0x29, 0x0b, 0x6c, 0x47, 0x4d, 0x75, 0xb2, 0xa2, 0xa4, 0x09, 0x3f, 0x1a, 0x9e, 0x27, 0x13, 0x94, 0x33, 0xa8, 0xf2, 0xb3, 0xbc, 0xe7, 0xb8, 0xd7 },
+      { 0x16, 0x6c, 0x83, 0x50, 0xd3, 0x17, 0x3b, 0x5e, 0x70, 0x2b, 0x78, 0x3d, 0xfd, 0x33, 0xc6, 0x6e, 0xe0, 0x43, 0x27, 0x42, 0xe9, 0xb9, 0x2b, 0x99, 0x7f, 0xd2, 0x3c, 0x60, 0xdc, 0x67, 0x56, 0xca },
+      { 0x04, 0x4a, 0x14, 0xd8, 0x22, 0xa9, 0x0c, 0xac, 0xf2, 0xf5, 0xa1, 0x01, 0x42, 0x8a, 0xdc, 0x8f, 0x41, 0x09, 0x38, 0x6c, 0xcb, 0x15, 0x8b, 0xf9, 0x05, 0xc8, 0x61, 0x8b, 0x8e, 0xe2, 0x4e, 0xc3 },
+      { 0x38, 0x7d, 0x39, 0x7e, 0xa4, 0x3a, 0x99, 0x4b, 0xe8, 0x4d, 0x2d, 0x54, 0x4a, 0xfb, 0xe4, 0x81, 0xa2, 0x00, 0x0f, 0x55, 0x25, 0x26, 0x96, 0xbb, 0xa2, 0xc5, 0x0c, 0x8e, 0xbd, 0x10, 0x13, 0x47 },
+      { 0x56, 0xf8, 0xcc, 0xf1, 0xf8, 0x64, 0x09, 0xb4, 0x6c, 0xe3, 0x61, 0x66, 0xae, 0x91, 0x65, 0x13, 0x84, 0x41, 0x57, 0x75, 0x89, 0xdb, 0x08, 0xcb, 0xc5, 0xf6, 0x6c, 0xa2, 0x97, 0x43, 0xb9, 0xfd },
+      { 0x97, 0x06, 0xc0, 0x92, 0xb0, 0x4d, 0x91, 0xf5, 0x3d, 0xff, 0x91, 0xfa, 0x37, 0xb7, 0x49, 0x3d, 0x28, 0xb5, 0x76, 0xb5, 0xd7, 0x10, 0x46, 0x9d, 0xf7, 0x94, 0x01, 0x66, 0x22, 0x36, 0xfc, 0x03 },
+      { 0x87, 0x79, 0x68, 0x68, 0x6c, 0x06, 0x8c, 0xe2, 0xf7, 0xe2, 0xad, 0xcf, 0xf6, 0x8b, 0xf8, 0x74, 0x8e, 0xdf, 0x3c, 0xf8, 0x62, 0xcf, 0xb4, 0xd3, 0x94, 0x7a, 0x31, 0x06, 0x95, 0x80, 0x54, 0xe3 },
+      { 0x88, 0x17, 0xe5, 0x71, 0x98, 0x79, 0xac, 0xf7, 0x02, 0x47, 0x87, 0xec, 0xcd, 0xb2, 0x71, 0x03, 0x55, 0x66, 0xcf, 0xa3, 0x33, 0xe0, 0x49, 0x40, 0x7c, 0x01, 0x78, 0xcc, 0xc5, 0x7a, 0x5b, 0x9f },
+      { 0x89, 0x38, 0x24, 0x9e, 0x4b, 0x50, 0xca, 0xda, 0xcc, 0xdf, 0x5b, 0x18, 0x62, 0x13, 0x26, 0xcb, 0xb1, 0x52, 0x53, 0xe3, 0x3a, 0x20, 0xf5, 0x63, 0x6e, 0x99, 0x5d, 0x72, 0x47, 0x8d, 0xe4, 0x72 },
+      { 0xf1, 0x64, 0xab, 0xba, 0x49, 0x63, 0xa4, 0x4d, 0x10, 0x72, 0x57, 0xe3, 0x23, 0x2d, 0x90, 0xac, 0xa5, 0xe6, 0x6a, 0x14, 0x08, 0x24, 0x8c, 0x51, 0x74, 0x1e, 0x99, 0x1d, 0xb5, 0x22, 0x77, 0x56 },
+      { 0xd0, 0x55, 0x63, 0xe2, 0xb1, 0xcb, 0xa0, 0xc4, 0xa2, 0xa1, 0xe8, 0xbd, 0xe3, 0xa1, 0xa0, 0xd9, 0xf5, 0xb4, 0x0c, 0x85, 0xa0, 0x70, 0xd6, 0xf5, 0xfb, 0x21, 0x06, 0x6e, 0xad, 0x5d, 0x06, 0x01 },
+      { 0x03, 0xfb, 0xb1, 0x63, 0x84, 0xf0, 0xa3, 0x86, 0x6f, 0x4c, 0x31, 0x17, 0x87, 0x76, 0x66, 0xef, 0xbf, 0x12, 0x45, 0x97, 0x56, 0x4b, 0x29, 0x3d, 0x4a, 0xab, 0x0d, 0x26, 0x9f, 0xab, 0xdd, 0xfa },
+      { 0x5f, 0xa8, 0x48, 0x6a, 0xc0, 0xe5, 0x29, 0x64, 0xd1, 0x88, 0x1b, 0xbe, 0x33, 0x8e, 0xb5, 0x4b, 0xe2, 0xf7, 0x19, 0x54, 0x92, 0x24, 0x89, 0x20, 0x57, 0xb4, 0xda, 0x04, 0xba, 0x8b, 0x34, 0x75 },
+      { 0xcd, 0xfa, 0xbc, 0xee, 0x46, 0x91, 0x11, 0x11, 0x23, 0x6a, 0x31, 0x70, 0x8b, 0x25, 0x39, 0xd7, 0x1f, 0xc2, 0x11, 0xd9, 0xb0, 0x9c, 0x0d, 0x85, 0x30, 0xa1, 0x1e, 0x1d, 0xbf, 0x6e, 0xed, 0x01 },
+      { 0x4f, 0x82, 0xde, 0x03, 0xb9, 0x50, 0x47, 0x93, 0xb8, 0x2a, 0x07, 0xa0, 0xbd, 0xcd, 0xff, 0x31, 0x4d, 0x75, 0x9e, 0x7b, 0x62, 0xd2, 0x6b, 0x78, 0x49, 0x46, 0xb0, 0xd3, 0x6f, 0x91, 0x6f, 0x52 },
+      { 0x25, 0x9e, 0xc7, 0xf1, 0x73, 0xbc, 0xc7, 0x6a, 0x09, 0x94, 0xc9, 0x67, 0xb4, 0xf5, 0xf0, 0x24, 0xc5, 0x60, 0x57, 0xfb, 0x79, 0xc9, 0x65, 0xc4, 0xfa, 0xe4, 0x18, 0x75, 0xf0, 0x6a, 0x0e, 0x4c },
+      { 0x19, 0x3c, 0xc8, 0xe7, 0xc3, 0xe0, 0x8b, 0xb3, 0x0f, 0x54, 0x37, 0xaa, 0x27, 0xad, 0xe1, 0xf1, 0x42, 0x36, 0x9b, 0x24, 0x6a, 0x67, 0x5b, 0x23, 0x83, 0xe6, 0xda, 0x9b, 0x49, 0xa9, 0x80, 0x9e },
+      { 0x5c, 0x10, 0x89, 0x6f, 0x0e, 0x28, 0x56, 0xb2, 0xa2, 0xee, 0xe0, 0xfe, 0x4a, 0x2c, 0x16, 0x33, 0x56, 0x5d, 0x18, 0xf0, 0xe9, 0x3e, 0x1f, 0xab, 0x26, 0xc3, 0x73, 0xe8, 0xf8, 0x29, 0x65, 0x4d },
+      { 0xf1, 0x60, 0x12, 0xd9, 0x3f, 0x28, 0x85, 0x1a, 0x1e, 0xb9, 0x89, 0xf5, 0xd0, 0xb4, 0x3f, 0x3f, 0x39, 0xca, 0x73, 0xc9, 0xa6, 0x2d, 0x51, 0x81, 0xbf, 0xf2, 0x37, 0x53, 0x6b, 0xd3, 0x48, 0xc3 },
+      { 0x29, 0x66, 0xb3, 0xcf, 0xae, 0x1e, 0x44, 0xea, 0x99, 0x6d, 0xc5, 0xd6, 0x86, 0xcf, 0x25, 0xfa, 0x05, 0x3f, 0xb6, 0xf6, 0x72, 0x01, 0xb9, 0xe4, 0x6e, 0xad, 0xe8, 0x5d, 0x0a, 0xd6, 0xb8, 0x06 },
+      { 0xdd, 0xb8, 0x78, 0x24, 0x85, 0xe9, 0x00, 0xbc, 0x60, 0xbc, 0xf4, 0xc3, 0x3a, 0x6f, 0xd5, 0x85, 0x68, 0x0c, 0xc6, 0x83, 0xd5, 0x16, 0xef, 0xa0, 0x3e, 0xb9, 0x98, 0x5f, 0xad, 0x87, 0x15, 0xfb },
+      { 0x4c, 0x4d, 0x6e, 0x71, 0xae, 0xa0, 0x57, 0x86, 0x41, 0x31, 0x48, 0xfc, 0x7a, 0x78, 0x6b, 0x0e, 0xca, 0xf5, 0x82, 0xcf, 0xf1, 0x20, 0x9f, 0x5a, 0x80, 0x9f, 0xba, 0x85, 0x04, 0xce, 0x66, 0x2c },
+      { 0xfb, 0x4c, 0x5e, 0x86, 0xd7, 0xb2, 0x22, 0x9b, 0x99, 0xb8, 0xba, 0x6d, 0x94, 0xc2, 0x47, 0xef, 0x96, 0x4a, 0xa3, 0xa2, 0xba, 0xe8, 0xed, 0xc7, 0x75, 0x69, 0xf2, 0x8d, 0xbb, 0xff, 0x2d, 0x4e },
+      { 0xe9, 0x4f, 0x52, 0x6d, 0xe9, 0x01, 0x96, 0x33, 0xec, 0xd5, 0x4a, 0xc6, 0x12, 0x0f, 0x23, 0x95, 0x8d, 0x77, 0x18, 0xf1, 0xe7, 0x71, 0x7b, 0xf3, 0x29, 0x21, 0x1a, 0x4f, 0xae, 0xed, 0x4e, 0x6d },
+      { 0xcb, 0xd6, 0x66, 0x0a, 0x10, 0xdb, 0x3f, 0x23, 0xf7, 0xa0, 0x3d, 0x4b, 0x9d, 0x40, 0x44, 0xc7, 0x93, 0x2b, 0x28, 0x01, 0xac, 0x89, 0xd6, 0x0b, 0xc9, 0xeb, 0x92, 0xd6, 0x5a, 0x46, 0xc2, 0xa0 },
+      { 0x88, 0x18, 0xbb, 0xd3, 0xdb, 0x4d, 0xc1, 0x23, 0xb2, 0x5c, 0xbb, 0xa5, 0xf5, 0x4c, 0x2b, 0xc4, 0xb3, 0xfc, 0xf9, 0xbf, 0x7d, 0x7a, 0x77, 0x09, 0xf4, 0xae, 0x58, 0x8b, 0x26, 0x7c, 0x4e, 0xce },
+      { 0xc6, 0x53, 0x82, 0x51, 0x3f, 0x07, 0x46, 0x0d, 0xa3, 0x98, 0x33, 0xcb, 0x66, 0x6c, 0x5e, 0xd8, 0x2e, 0x61, 0xb9, 0xe9, 0x98, 0xf4, 0xb0, 0xc4, 0x28, 0x7c, 0xee, 0x56, 0xc3, 0xcc, 0x9b, 0xcd },
+      { 0x89, 0x75, 0xb0, 0x57, 0x7f, 0xd3, 0x55, 0x66, 0xd7, 0x50, 0xb3, 0x62, 0xb0, 0x89, 0x7a, 0x26, 0xc3, 0x99, 0x13, 0x6d, 0xf0, 0x7b, 0xab, 0xab, 0xbd, 0xe6, 0x20, 0x3f, 0xf2, 0x95, 0x4e, 0xd4 },
+      { 0x21, 0xfe, 0x0c, 0xeb, 0x00, 0x52, 0xbe, 0x7f, 0xb0, 0xf0, 0x04, 0x18, 0x7c, 0xac, 0xd7, 0xde, 0x67, 0xfa, 0x6e, 0xb0, 0x93, 0x8d, 0x92, 0x76, 0x77, 0xf2, 0x39, 0x8c, 0x13, 0x23, 0x17, 0xa8 },
+      { 0x2e, 0xf7, 0x3f, 0x3c, 0x26, 0xf1, 0x2d, 0x93, 0x88, 0x9f, 0x3c, 0x78, 0xb6, 0xa6, 0x6c, 0x1d, 0x52, 0xb6, 0x49, 0xdc, 0x9e, 0x85, 0x6e, 0x2c, 0x17, 0x2e, 0xa7, 0xc5, 0x8a, 0xc2, 0xb5, 0xe3 },
+      { 0x38, 0x8a, 0x3c, 0xd5, 0x6d, 0x73, 0x86, 0x7a, 0xbb, 0x5f, 0x84, 0x01, 0x49, 0x2b, 0x6e, 0x26, 0x81, 0xeb, 0x69, 0x85, 0x1e, 0x76, 0x7f, 0xd8, 0x42, 0x10, 0xa5, 0x60, 0x76, 0xfb, 0x3d, 0xd3 },
+      { 0xaf, 0x53, 0x3e, 0x02, 0x2f, 0xc9, 0x43, 0x9e, 0x4e, 0x3c, 0xb8, 0x38, 0xec, 0xd1, 0x86, 0x92, 0x23, 0x2a, 0xdf, 0x6f, 0xe9, 0x83, 0x95, 0x26, 0xd3, 0xc3, 0xdd, 0x1b, 0x71, 0x91, 0x0b, 0x1a },
+      { 0x75, 0x1c, 0x09, 0xd4, 0x1a, 0x93, 0x43, 0x88, 0x2a, 0x81, 0xcd, 0x13, 0xee, 0x40, 0x81, 0x8d, 0x12, 0xeb, 0x44, 0xc6, 0xc7, 0xf4, 0x0d, 0xf1, 0x6e, 0x4a, 0xea, 0x8f, 0xab, 0x91, 0x97, 0x2a },
+      { 0x5b, 0x73, 0xdd, 0xb6, 0x8d, 0x9d, 0x2b, 0x0a, 0xa2, 0x65, 0xa0, 0x79, 0x88, 0xd6, 0xb8, 0x8a, 0xe9, 0xaa, 0xc5, 0x82, 0xaf, 0x83, 0x03, 0x2f, 0x8a, 0x9b, 0x21, 0xa2, 0xe1, 0xb7, 0xbf, 0x18 },
+      { 0x3d, 0xa2, 0x91, 0x26, 0xc7, 0xc5, 0xd7, 0xf4, 0x3e, 0x64, 0x24, 0x2a, 0x79, 0xfe, 0xaa, 0x4e, 0xf3, 0x45, 0x9c, 0xde, 0xcc, 0xc8, 0x98, 0xed, 0x59, 0xa9, 0x7f, 0x6e, 0xc9, 0x3b, 0x9d, 0xab },
+      { 0x56, 0x6d, 0xc9, 0x20, 0x29, 0x3d, 0xa5, 0xcb, 0x4f, 0xe0, 0xaa, 0x8a, 0xbd, 0xa8, 0xbb, 0xf5, 0x6f, 0x55, 0x23, 0x13, 0xbf, 0xf1, 0x90, 0x46, 0x64, 0x1e, 0x36, 0x15, 0xc1, 0xe3, 0xed, 0x3f },
+      { 0x41, 0x15, 0xbe, 0xa0, 0x2f, 0x73, 0xf9, 0x7f, 0x62, 0x9e, 0x5c, 0x55, 0x90, 0x72, 0x0c, 0x01, 0xe7, 0xe4, 0x49, 0xae, 0x2a, 0x66, 0x97, 0xd4, 0xd2, 0x78, 0x33, 0x21, 0x30, 0x36, 0x92, 0xf9 },
+      { 0x4c, 0xe0, 0x8f, 0x47, 0x62, 0x46, 0x8a, 0x76, 0x70, 0x01, 0x21, 0x64, 0x87, 0x8d, 0x68, 0x34, 0x0c, 0x52, 0xa3, 0x5e, 0x66, 0xc1, 0x88, 0x4d, 0x5c, 0x86, 0x48, 0x89, 0xab, 0xc9, 0x66, 0x77 },
+      { 0x81, 0xea, 0x0b, 0x78, 0x04, 0x12, 0x4e, 0x0c, 0x22, 0xea, 0x5f, 0xc7, 0x11, 0x04, 0xa2, 0xaf, 0xcb, 0x52, 0xa1, 0xfa, 0x81, 0x6f, 0x3e, 0xcb, 0x7d, 0xcb, 0x5d, 0x9d, 0xea, 0x17, 0x86, 0xd0 },
+      { 0xfe, 0x36, 0x27, 0x33, 0xb0, 0x5f, 0x6b, 0xed, 0xaf, 0x93, 0x79, 0xd7, 0xf7, 0x93, 0x6e, 0xde, 0x20, 0x9b, 0x1f, 0x83, 0x23, 0xc3, 0x92, 0x25, 0x49, 0xd9, 0xe7, 0x36, 0x81, 0xb5, 0xdb, 0x7b },
+      { 0xef, 0xf3, 0x7d, 0x30, 0xdf, 0xd2, 0x03, 0x59, 0xbe, 0x4e, 0x73, 0xfd, 0xf4, 0x0d, 0x27, 0x73, 0x4b, 0x3d, 0xf9, 0x0a, 0x97, 0xa5, 0x5e, 0xd7, 0x45, 0x29, 0x72, 0x94, 0xca, 0x85, 0xd0, 0x9f },
+      { 0x17, 0x2f, 0xfc, 0x67, 0x15, 0x3d, 0x12, 0xe0, 0xca, 0x76, 0xa8, 0xb6, 0xcd, 0x5d, 0x47, 0x31, 0x88, 0x5b, 0x39, 0xce, 0x0c, 0xac, 0x93, 0xa8, 0x97, 0x2a, 0x18, 0x00, 0x6c, 0x8b, 0x8b, 0xaf },
+      { 0xc4, 0x79, 0x57, 0xf1, 0xcc, 0x88, 0xe8, 0x3e, 0xf9, 0x44, 0x58, 0x39, 0x70, 0x9a, 0x48, 0x0a, 0x03, 0x6b, 0xed, 0x5f, 0x88, 0xac, 0x0f, 0xcc, 0x8e, 0x1e, 0x70, 0x3f, 0xfa, 0xac, 0x13, 0x2c },
+      { 0x30, 0xf3, 0x54, 0x83, 0x70, 0xcf, 0xdc, 0xed, 0xa5, 0xc3, 0x7b, 0x56, 0x9b, 0x61, 0x75, 0xe7, 0x99, 0xee, 0xf1, 0xa6, 0x2a, 0xaa, 0x94, 0x32, 0x45, 0xae, 0x76, 0x69, 0xc2, 0x27, 0xa7, 0xb5 },
+      { 0xc9, 0x5d, 0xcb, 0x3c, 0xf1, 0xf2, 0x7d, 0x0e, 0xef, 0x2f, 0x25, 0xd2, 0x41, 0x38, 0x70, 0x90, 0x4a, 0x87, 0x7c, 0x4a, 0x56, 0xc2, 0xde, 0x1e, 0x83, 0xe2, 0xbc, 0x2a, 0xe2, 0xe4, 0x68, 0x21 },
+      { 0xd5, 0xd0, 0xb5, 0xd7, 0x05, 0x43, 0x4c, 0xd4, 0x6b, 0x18, 0x57, 0x49, 0xf6, 0x6b, 0xfb, 0x58, 0x36, 0xdc, 0xdf, 0x6e, 0xe5, 0x49, 0xa2, 0xb7, 0xa4, 0xae, 0xe7, 0xf5, 0x80, 0x07, 0xca, 0xaf },
+      { 0xbb, 0xc1, 0x24, 0xa7, 0x12, 0xf1, 0x5d, 0x07, 0xc3, 0x00, 0xe0, 0x5b, 0x66, 0x83, 0x89, 0xa4, 0x39, 0xc9, 0x17, 0x77, 0xf7, 0x21, 0xf8, 0x32, 0x0c, 0x1c, 0x90, 0x78, 0x06, 0x6d, 0x2c, 0x7e },
+      { 0xa4, 0x51, 0xb4, 0x8c, 0x35, 0xa6, 0xc7, 0x85, 0x4c, 0xfa, 0xae, 0x60, 0x26, 0x2e, 0x76, 0x99, 0x08, 0x16, 0x38, 0x2a, 0xc0, 0x66, 0x7e, 0x5a, 0x5c, 0x9e, 0x1b, 0x46, 0xc4, 0x34, 0x2d, 0xdf },
+      { 0xb0, 0xd1, 0x50, 0xfb, 0x55, 0xe7, 0x78, 0xd0, 0x11, 0x47, 0xf0, 0xb5, 0xd8, 0x9d, 0x99, 0xec, 0xb2, 0x0f, 0xf0, 0x7e, 0x5e, 0x67, 0x60, 0xd6, 0xb6, 0x45, 0xeb, 0x5b, 0x65, 0x4c, 0x62, 0x2b },
+      { 0x34, 0xf7, 0x37, 0xc0, 0xab, 0x21, 0x99, 0x51, 0xee, 0xe8, 0x9a, 0x9f, 0x8d, 0xac, 0x29, 0x9c, 0x9d, 0x4c, 0x38, 0xf3, 0x3f, 0xa4, 0x94, 0xc5, 0xc6, 0xee, 0xfc, 0x92, 0xb6, 0xdb, 0x08, 0xbc },
+      { 0x1a, 0x62, 0xcc, 0x3a, 0x00, 0x80, 0x0d, 0xcb, 0xd9, 0x98, 0x91, 0x08, 0x0c, 0x1e, 0x09, 0x84, 0x58, 0x19, 0x3a, 0x8c, 0xc9, 0xf9, 0x70, 0xea, 0x99, 0xfb, 0xef, 0xf0, 0x03, 0x18, 0xc2, 0x89 },
+      { 0xcf, 0xce, 0x55, 0xeb, 0xaf, 0xc8, 0x40, 0xd7, 0xae, 0x48, 0x28, 0x1c, 0x7f, 0xd5, 0x7e, 0xc8, 0xb4, 0x82, 0xd4, 0xb7, 0x04, 0x43, 0x74, 0x95, 0x49, 0x5a, 0xc4, 0x14, 0xcf, 0x4a, 0x37, 0x4b },
+      { 0x67, 0x46, 0xfa, 0xcf, 0x71, 0x14, 0x6d, 0x99, 0x9d, 0xab, 0xd0, 0x5d, 0x09, 0x3a, 0xe5, 0x86, 0x64, 0x8d, 0x1e, 0xe2, 0x8e, 0x72, 0x61, 0x7b, 0x99, 0xd0, 0xf0, 0x08, 0x6e, 0x1e, 0x45, 0xbf },
+      { 0x57, 0x1c, 0xed, 0x28, 0x3b, 0x3f, 0x23, 0xb4, 0xe7, 0x50, 0xbf, 0x12, 0xa2, 0xca, 0xf1, 0x78, 0x18, 0x47, 0xbd, 0x89, 0x0e, 0x43, 0x60, 0x3c, 0xdc, 0x59, 0x76, 0x10, 0x2b, 0x7b, 0xb1, 0x1b },
+      { 0xcf, 0xcb, 0x76, 0x5b, 0x04, 0x8e, 0x35, 0x02, 0x2c, 0x5d, 0x08, 0x9d, 0x26, 0xe8, 0x5a, 0x36, 0xb0, 0x05, 0xa2, 0xb8, 0x04, 0x93, 0xd0, 0x3a, 0x14, 0x4e, 0x09, 0xf4, 0x09, 0xb6, 0xaf, 0xd1 },
+      { 0x40, 0x50, 0xc7, 0xa2, 0x77, 0x05, 0xbb, 0x27, 0xf4, 0x20, 0x89, 0xb2, 0x99, 0xf3, 0xcb, 0xe5, 0x05, 0x4e, 0xad, 0x68, 0x72, 0x7e, 0x8e, 0xf9, 0x31, 0x8c, 0xe6, 0xf2, 0x5c, 0xd6, 0xf3, 0x1d },
+      { 0x18, 0x40, 0x70, 0xbd, 0x5d, 0x26, 0x5f, 0xbd, 0xc1, 0x42, 0xcd, 0x1c, 0x5c, 0xd0, 0xd7, 0xe4, 0x14, 0xe7, 0x03, 0x69, 0xa2, 0x66, 0xd6, 0x27, 0xc8, 0xfb, 0xa8, 0x4f, 0xa5, 0xe8, 0x4c, 0x34 },
+      { 0x9e, 0xdd, 0xa9, 0xa4, 0x44, 0x39, 0x02, 0xa9, 0x58, 0x8c, 0x0d, 0x0c, 0xcc, 0x62, 0xb9, 0x30, 0x21, 0x84, 0x79, 0xa6, 0x84, 0x1e, 0x6f, 0xe7, 0xd4, 0x30, 0x03, 0xf0, 0x4b, 0x1f, 0xd6, 0x43 },
+      { 0xe4, 0x12, 0xfe, 0xef, 0x79, 0x08, 0x32, 0x4a, 0x6d, 0xa1, 0x84, 0x16, 0x29, 0xf3, 0x5d, 0x3d, 0x35, 0x86, 0x42, 0x01, 0x93, 0x10, 0xec, 0x57, 0xc6, 0x14, 0x83, 0x6b, 0x63, 0xd3, 0x07, 0x63 },
+      { 0x1a, 0x2b, 0x8e, 0xdf, 0xf3, 0xf9, 0xac, 0xc1, 0x55, 0x4f, 0xcb, 0xae, 0x3c, 0xf1, 0xd6, 0x29, 0x8c, 0x64, 0x62, 0xe2, 0x2e, 0x5e, 0xb0, 0x25, 0x96, 0x84, 0xf8, 0x35, 0x01, 0x2b, 0xd1, 0x3f },
+      { 0x28, 0x8c, 0x4a, 0xd9, 0xb9, 0x40, 0x97, 0x62, 0xea, 0x07, 0xc2, 0x4a, 0x41, 0xf0, 0x4f, 0x69, 0xa7, 0xd7, 0x4b, 0xee, 0x2d, 0x95, 0x43, 0x53, 0x74, 0xbd, 0xe9, 0x46, 0xd7, 0x24, 0x1c, 0x7b },
+      { 0x80, 0x56, 0x91, 0xbb, 0x28, 0x67, 0x48, 0xcf, 0xb5, 0x91, 0xd3, 0xae, 0xbe, 0x7e, 0x6f, 0x4e, 0x4d, 0xc6, 0xe2, 0x80, 0x8c, 0x65, 0x14, 0x3c, 0xc0, 0x04, 0xe4, 0xeb, 0x6f, 0xd0, 0x9d, 0x43 },
+      { 0xd4, 0xac, 0x8d, 0x3a, 0x0a, 0xfc, 0x6c, 0xfa, 0x7b, 0x46, 0x0a, 0xe3, 0x00, 0x1b, 0xae, 0xb3, 0x6d, 0xad, 0xb3, 0x7d, 0xa0, 0x7d, 0x2e, 0x8a, 0xc9, 0x18, 0x22, 0xdf, 0x34, 0x8a, 0xed, 0x3d },
+      { 0xc3, 0x76, 0x61, 0x70, 0x14, 0xd2, 0x01, 0x58, 0xbc, 0xed, 0x3d, 0x3b, 0xa5, 0x52, 0xb6, 0xec, 0xcf, 0x84, 0xe6, 0x2a, 0xa3, 0xeb, 0x65, 0x0e, 0x90, 0x02, 0x9c, 0x84, 0xd1, 0x3e, 0xea, 0x69 },
+      { 0xc4, 0x1f, 0x09, 0xf4, 0x3c, 0xec, 0xae, 0x72, 0x93, 0xd6, 0x00, 0x7c, 0xa0, 0xa3, 0x57, 0x08, 0x7d, 0x5a, 0xe5, 0x9b, 0xe5, 0x00, 0xc1, 0xcd, 0x5b, 0x28, 0x9e, 0xe8, 0x10, 0xc7, 0xb0, 0x82 },
+      { 0x03, 0xd1, 0xce, 0xd1, 0xfb, 0xa5, 0xc3, 0x91, 0x55, 0xc4, 0x4b, 0x77, 0x65, 0xcb, 0x76, 0x0c, 0x78, 0x70, 0x8d, 0xcf, 0xc8, 0x0b, 0x0b, 0xd8, 0xad, 0xe3, 0xa5, 0x6d, 0xa8, 0x83, 0x0b, 0x29 },
+      { 0x09, 0xbd, 0xe6, 0xf1, 0x52, 0x21, 0x8d, 0xc9, 0x2c, 0x41, 0xd7, 0xf4, 0x53, 0x87, 0xe6, 0x3e, 0x58, 0x69, 0xd8, 0x07, 0xec, 0x70, 0xb8, 0x21, 0x40, 0x5d, 0xbd, 0x88, 0x4b, 0x7f, 0xcf, 0x4b },
+      { 0x71, 0xc9, 0x03, 0x6e, 0x18, 0x17, 0x9b, 0x90, 0xb3, 0x7d, 0x39, 0xe9, 0xf0, 0x5e, 0xb8, 0x9c, 0xc5, 0xfc, 0x34, 0x1f, 0xd7, 0xc4, 0x77, 0xd0, 0xd7, 0x49, 0x32, 0x85, 0xfa, 0xca, 0x08, 0xa4 },
+      { 0x59, 0x16, 0x83, 0x3e, 0xbb, 0x05, 0xcd, 0x91, 0x9c, 0xa7, 0xfe, 0x83, 0xb6, 0x92, 0xd3, 0x20, 0x5b, 0xef, 0x72, 0x39, 0x2b, 0x2c, 0xf6, 0xbb, 0x0a, 0x6d, 0x43, 0xf9, 0x94, 0xf9, 0x5f, 0x11 },
+      { 0xf6, 0x3a, 0xab, 0x3e, 0xc6, 0x41, 0xb3, 0xb0, 0x24, 0x96, 0x4c, 0x2b, 0x43, 0x7c, 0x04, 0xf6, 0x04, 0x3c, 0x4c, 0x7e, 0x02, 0x79, 0x23, 0x99, 0x95, 0x40, 0x19, 0x58, 0xf8, 0x6b, 0xbe, 0x54 },
+      { 0xf1, 0x72, 0xb1, 0x80, 0xbf, 0xb0, 0x97, 0x40, 0x49, 0x31, 0x20, 0xb6, 0x32, 0x6c, 0xbd, 0xc5, 0x61, 0xe4, 0x77, 0xde, 0xf9, 0xbb, 0xcf, 0xd2, 0x8c, 0xc8, 0xc1, 0xc5, 0xe3, 0x37, 0x9a, 0x31 },
+      { 0xcb, 0x9b, 0x89, 0xcc, 0x18, 0x38, 0x1d, 0xd9, 0x14, 0x1a, 0xde, 0x58, 0x86, 0x54, 0xd4, 0xe6, 0xa2, 0x31, 0xd5, 0xbf, 0x49, 0xd4, 0xd5, 0x9a, 0xc2, 0x7d, 0x86, 0x9c, 0xbe, 0x10, 0x0c, 0xf3 },
+      { 0x7b, 0xd8, 0x81, 0x50, 0x46, 0xfd, 0xd8, 0x10, 0xa9, 0x23, 0xe1, 0x98, 0x4a, 0xae, 0xbd, 0xcd, 0xf8, 0x4d, 0x87, 0xc8, 0x99, 0x2d, 0x68, 0xb5, 0xee, 0xb4, 0x60, 0xf9, 0x3e, 0xb3, 0xc8, 0xd7 },
+      { 0x60, 0x7b, 0xe6, 0x68, 0x62, 0xfd, 0x08, 0xee, 0x5b, 0x19, 0xfa, 0xca, 0xc0, 0x9d, 0xfd, 0xbc, 0xd4, 0x0c, 0x31, 0x21, 0x01, 0xd6, 0x6e, 0x6e, 0xbd, 0x2b, 0x84, 0x1f, 0x1b, 0x9a, 0x93, 0x25 },
+      { 0x9f, 0xe0, 0x3b, 0xbe, 0x69, 0xab, 0x18, 0x34, 0xf5, 0x21, 0x9b, 0x0d, 0xa8, 0x8a, 0x08, 0xb3, 0x0a, 0x66, 0xc5, 0x91, 0x3f, 0x01, 0x51, 0x96, 0x3c, 0x36, 0x05, 0x60, 0xdb, 0x03, 0x87, 0xb3 },
+      { 0x90, 0xa8, 0x35, 0x85, 0x71, 0x7b, 0x75, 0xf0, 0xe9, 0xb7, 0x25, 0xe0, 0x55, 0xee, 0xee, 0xb9, 0xe7, 0xa0, 0x28, 0xea, 0x7e, 0x6c, 0xbc, 0x07, 0xb2, 0x09, 0x17, 0xec, 0x03, 0x63, 0xe3, 0x8c },
+      { 0x33, 0x6e, 0xa0, 0x53, 0x0f, 0x4a, 0x74, 0x69, 0x12, 0x6e, 0x02, 0x18, 0x58, 0x7e, 0xbb, 0xde, 0x33, 0x58, 0xa0, 0xb3, 0x1c, 0x29, 0xd2, 0x00, 0xf7, 0xdc, 0x7e, 0xb1, 0x5c, 0x6a, 0xad, 0xd8 },
+      { 0xa7, 0x9e, 0x76, 0xdc, 0x0a, 0xbc, 0xa4, 0x39, 0x6f, 0x07, 0x47, 0xcd, 0x7b, 0x74, 0x8d, 0xf9, 0x13, 0x00, 0x76, 0x26, 0xb1, 0xd6, 0x59, 0xda, 0x0c, 0x1f, 0x78, 0xb9, 0x30, 0x3d, 0x01, 0xa3 },
+      { 0x44, 0xe7, 0x8a, 0x77, 0x37, 0x56, 0xe0, 0x95, 0x15, 0x19, 0x50, 0x4d, 0x70, 0x38, 0xd2, 0x8d, 0x02, 0x13, 0xa3, 0x7e, 0x0c, 0xe3, 0x75, 0x37, 0x17, 0x57, 0xbc, 0x99, 0x63, 0x11, 0xe3, 0xb8 },
+      { 0x77, 0xac, 0x01, 0x2a, 0x3f, 0x75, 0x4d, 0xcf, 0xea, 0xb5, 0xeb, 0x99, 0x6b, 0xe9, 0xcd, 0x2d, 0x1f, 0x96, 0x11, 0x1b, 0x6e, 0x49, 0xf3, 0x99, 0x4d, 0xf1, 0x81, 0xf2, 0x85, 0x69, 0xd8, 0x25 },
+      { 0xce, 0x5a, 0x10, 0xdb, 0x6f, 0xcc, 0xda, 0xf1, 0x40, 0xaa, 0xa4, 0xde, 0xd6, 0x25, 0x0a, 0x9c, 0x06, 0xe9, 0x22, 0x2b, 0xc9, 0xf9, 0xf3, 0x65, 0x8a, 0x4a, 0xff, 0x93, 0x5f, 0x2b, 0x9f, 0x3a },
+      { 0xec, 0xc2, 0x03, 0xa7, 0xfe, 0x2b, 0xe4, 0xab, 0xd5, 0x5b, 0xb5, 0x3e, 0x6e, 0x67, 0x35, 0x72, 0xe0, 0x07, 0x8d, 0xa8, 0xcd, 0x37, 0x5e, 0xf4, 0x30, 0xcc, 0x97, 0xf9, 0xf8, 0x00, 0x83, 0xaf },
+      { 0x14, 0xa5, 0x18, 0x6d, 0xe9, 0xd7, 0xa1, 0x8b, 0x04, 0x12, 0xb8, 0x56, 0x3e, 0x51, 0xcc, 0x54, 0x33, 0x84, 0x0b, 0x4a, 0x12, 0x9a, 0x8f, 0xf9, 0x63, 0xb3, 0x3a, 0x3c, 0x4a, 0xfe, 0x8e, 0xbb },
+      { 0x13, 0xf8, 0xef, 0x95, 0xcb, 0x86, 0xe6, 0xa6, 0x38, 0x93, 0x1c, 0x8e, 0x10, 0x76, 0x73, 0xeb, 0x76, 0xba, 0x10, 0xd7, 0xc2, 0xcd, 0x70, 0xb9, 0xd9, 0x92, 0x0b, 0xbe, 0xed, 0x92, 0x94, 0x09 },
+      { 0x0b, 0x33, 0x8f, 0x4e, 0xe1, 0x2f, 0x2d, 0xfc, 0xb7, 0x87, 0x13, 0x37, 0x79, 0x41, 0xe0, 0xb0, 0x63, 0x21, 0x52, 0x58, 0x1d, 0x13, 0x32, 0x51, 0x6e, 0x4a, 0x2c, 0xab, 0x19, 0x42, 0xcc, 0xa4 },
+      { 0xea, 0xab, 0x0e, 0xc3, 0x7b, 0x3b, 0x8a, 0xb7, 0x96, 0xe9, 0xf5, 0x72, 0x38, 0xde, 0x14, 0xa2, 0x64, 0xa0, 0x76, 0xf3, 0x88, 0x7d, 0x86, 0xe2, 0x9b, 0xb5, 0x90, 0x6d, 0xb5, 0xa0, 0x0e, 0x02 },
+      { 0x23, 0xcb, 0x68, 0xb8, 0xc0, 0xe6, 0xdc, 0x26, 0xdc, 0x27, 0x76, 0x6d, 0xdc, 0x0a, 0x13, 0xa9, 0x94, 0x38, 0xfd, 0x55, 0x61, 0x7a, 0xa4, 0x09, 0x5d, 0x8f, 0x96, 0x97, 0x20, 0xc8, 0x72, 0xdf },
+      { 0x09, 0x1d, 0x8e, 0xe3, 0x0d, 0x6f, 0x29, 0x68, 0xd4, 0x6b, 0x68, 0x7d, 0xd6, 0x52, 0x92, 0x66, 0x57, 0x42, 0xde, 0x0b, 0xb8, 0x3d, 0xcc, 0x00, 0x04, 0xc7, 0x2c, 0xe1, 0x00, 0x07, 0xa5, 0x49 },
+      { 0x7f, 0x50, 0x7a, 0xbc, 0x6d, 0x19, 0xba, 0x00, 0xc0, 0x65, 0xa8, 0x76, 0xec, 0x56, 0x57, 0x86, 0x88, 0x82, 0xd1, 0x8a, 0x22, 0x1b, 0xc4, 0x6c, 0x7a, 0x69, 0x12, 0x54, 0x1f, 0x5b, 0xc7, 0xba },
+      { 0xa0, 0x60, 0x7c, 0x24, 0xe1, 0x4e, 0x8c, 0x22, 0x3d, 0xb0, 0xd7, 0x0b, 0x4d, 0x30, 0xee, 0x88, 0x01, 0x4d, 0x60, 0x3f, 0x43, 0x7e, 0x9e, 0x02, 0xaa, 0x7d, 0xaf, 0xa3, 0xcd, 0xfb, 0xad, 0x94 },
+      { 0xdd, 0xbf, 0xea, 0x75, 0xcc, 0x46, 0x78, 0x82, 0xeb, 0x34, 0x83, 0xce, 0x5e, 0x2e, 0x75, 0x6a, 0x4f, 0x47, 0x01, 0xb7, 0x6b, 0x44, 0x55, 0x19, 0xe8, 0x9f, 0x22, 0xd6, 0x0f, 0xa8, 0x6e, 0x06 },
+      { 0x0c, 0x31, 0x1f, 0x38, 0xc3, 0x5a, 0x4f, 0xb9, 0x0d, 0x65, 0x1c, 0x28, 0x9d, 0x48, 0x68, 0x56, 0xcd, 0x14, 0x13, 0xdf, 0x9b, 0x06, 0x77, 0xf5, 0x3e, 0xce, 0x2c, 0xd9, 0xe4, 0x77, 0xc6, 0x0a },
+      { 0x46, 0xa7, 0x3a, 0x8d, 0xd3, 0xe7, 0x0f, 0x59, 0xd3, 0x94, 0x2c, 0x01, 0xdf, 0x59, 0x9d, 0xef, 0x78, 0x3c, 0x9d, 0xa8, 0x2f, 0xd8, 0x32, 0x22, 0xcd, 0x66, 0x2b, 0x53, 0xdc, 0xe7, 0xdb, 0xdf },
+      { 0xad, 0x03, 0x8f, 0xf9, 0xb1, 0x4d, 0xe8, 0x4a, 0x80, 0x1e, 0x4e, 0x62, 0x1c, 0xe5, 0xdf, 0x02, 0x9d, 0xd9, 0x35, 0x20, 0xd0, 0xc2, 0xfa, 0x38, 0xbf, 0xf1, 0x76, 0xa8, 0xb1, 0xd1, 0x69, 0x8c },
+      { 0xab, 0x70, 0xc5, 0xdf, 0xbd, 0x1e, 0xa8, 0x17, 0xfe, 0xd0, 0xcd, 0x06, 0x72, 0x93, 0xab, 0xf3, 0x19, 0xe5, 0xd7, 0x90, 0x1c, 0x21, 0x41, 0xd5, 0xd9, 0x9b, 0x23, 0xf0, 0x3a, 0x38, 0xe7, 0x48 },
+      { 0x1f, 0xff, 0xda, 0x67, 0x93, 0x2b, 0x73, 0xc8, 0xec, 0xaf, 0x00, 0x9a, 0x34, 0x91, 0xa0, 0x26, 0x95, 0x3b, 0xab, 0xfe, 0x1f, 0x66, 0x3b, 0x06, 0x97, 0xc3, 0xc4, 0xae, 0x8b, 0x2e, 0x7d, 0xcb },
+      { 0xb0, 0xd2, 0xcc, 0x19, 0x47, 0x2d, 0xd5, 0x7f, 0x2b, 0x17, 0xef, 0xc0, 0x3c, 0x8d, 0x58, 0xc2, 0x28, 0x3d, 0xbb, 0x19, 0xda, 0x57, 0x2f, 0x77, 0x55, 0x85, 0x5a, 0xa9, 0x79, 0x43, 0x17, 0xa0 },
+      { 0xa0, 0xd1, 0x9a, 0x6e, 0xe3, 0x39, 0x79, 0xc3, 0x25, 0x51, 0x0e, 0x27, 0x66, 0x22, 0xdf, 0x41, 0xf7, 0x15, 0x83, 0xd0, 0x75, 0x01, 0xb8, 0x70, 0x71, 0x12, 0x9a, 0x0a, 0xd9, 0x47, 0x32, 0xa5 },
+      { 0x72, 0x46, 0x42, 0xa7, 0x03, 0x2d, 0x10, 0x62, 0xb8, 0x9e, 0x52, 0xbe, 0xa3, 0x4b, 0x75, 0xdf, 0x7d, 0x8f, 0xe7, 0x72, 0xd9, 0xfe, 0x3c, 0x93, 0xdd, 0xf3, 0xc4, 0x54, 0x5a, 0xb5, 0xa9, 0x9b },
+      { 0xad, 0xe5, 0xea, 0xa7, 0xe6, 0x1f, 0x67, 0x2d, 0x58, 0x7e, 0xa0, 0x3d, 0xae, 0x7d, 0x7b, 0x55, 0x22, 0x9c, 0x01, 0xd0, 0x6b, 0xc0, 0xa5, 0x70, 0x14, 0x36, 0xcb, 0xd1, 0x83, 0x66, 0xa6, 0x26 },
+      { 0x01, 0x3b, 0x31, 0xeb, 0xd2, 0x28, 0xfc, 0xdd, 0xa5, 0x1f, 0xab, 0xb0, 0x3b, 0xb0, 0x2d, 0x60, 0xac, 0x20, 0xca, 0x21, 0x5a, 0xaf, 0xa8, 0x3b, 0xdd, 0x85, 0x5e, 0x37, 0x55, 0xa3, 0x5f, 0x0b },
+      { 0x33, 0x2e, 0xd4, 0x0b, 0xb1, 0x0d, 0xde, 0x3c, 0x95, 0x4a, 0x75, 0xd7, 0xb8, 0x99, 0x9d, 0x4b, 0x26, 0xa1, 0xc0, 0x63, 0xc1, 0xdc, 0x6e, 0x32, 0xc1, 0xd9, 0x1b, 0xab, 0x7b, 0xbb, 0x7d, 0x16 },
+      { 0xc7, 0xa1, 0x97, 0xb3, 0xa0, 0x5b, 0x56, 0x6b, 0xcc, 0x9f, 0xac, 0xd2, 0x0e, 0x44, 0x1d, 0x6f, 0x6c, 0x28, 0x60, 0xac, 0x96, 0x51, 0xcd, 0x51, 0xd6, 0xb9, 0xd2, 0xcd, 0xee, 0xea, 0x03, 0x90 },
+      { 0xbd, 0x9c, 0xf6, 0x4e, 0xa8, 0x95, 0x3c, 0x03, 0x71, 0x08, 0xe6, 0xf6, 0x54, 0x91, 0x4f, 0x39, 0x58, 0xb6, 0x8e, 0x29, 0xc1, 0x67, 0x00, 0xdc, 0x18, 0x4d, 0x94, 0xa2, 0x17, 0x08, 0xff, 0x60 },
+      { 0x88, 0x35, 0xb0, 0xac, 0x02, 0x11, 0x51, 0xdf, 0x71, 0x64, 0x74, 0xce, 0x27, 0xce, 0x4d, 0x3c, 0x15, 0xf0, 0xb2, 0xda, 0xb4, 0x80, 0x03, 0xcf, 0x3f, 0x3e, 0xfd, 0x09, 0x45, 0x10, 0x6b, 0x9a },
+      { 0x3b, 0xfe, 0xfa, 0x33, 0x01, 0xaa, 0x55, 0xc0, 0x80, 0x19, 0x0c, 0xff, 0xda, 0x8e, 0xae, 0x51, 0xd9, 0xaf, 0x48, 0x8b, 0x4c, 0x1f, 0x24, 0xc3, 0xd9, 0xa7, 0x52, 0x42, 0xfd, 0x8e, 0xa0, 0x1d },
+      { 0x08, 0x28, 0x4d, 0x14, 0x99, 0x3c, 0xd4, 0x7d, 0x53, 0xeb, 0xae, 0xcf, 0x0d, 0xf0, 0x47, 0x8c, 0xc1, 0x82, 0xc8, 0x9c, 0x00, 0xe1, 0x85, 0x9c, 0x84, 0x85, 0x16, 0x86, 0xdd, 0xf2, 0xc1, 0xb7 },
+      { 0x1e, 0xd7, 0xef, 0x9f, 0x04, 0xc2, 0xac, 0x8d, 0xb6, 0xa8, 0x64, 0xdb, 0x13, 0x10, 0x87, 0xf2, 0x70, 0x65, 0x09, 0x8e, 0x69, 0xc3, 0xfe, 0x78, 0x71, 0x8d, 0x9b, 0x94, 0x7f, 0x4a, 0x39, 0xd0 },
+      { 0xc1, 0x61, 0xf2, 0xdc, 0xd5, 0x7e, 0x9c, 0x14, 0x39, 0xb3, 0x1a, 0x9d, 0xd4, 0x3d, 0x8f, 0x3d, 0x7d, 0xd8, 0xf0, 0xeb, 0x7c, 0xfa, 0xc6, 0xfb, 0x25, 0xa0, 0xf2, 0x8e, 0x30, 0x6f, 0x06, 0x61 },
+      { 0xc0, 0x19, 0x69, 0xad, 0x34, 0xc5, 0x2c, 0xaf, 0x3d, 0xc4, 0xd8, 0x0d, 0x19, 0x73, 0x5c, 0x29, 0x73, 0x1a, 0xc6, 0xe7, 0xa9, 0x20, 0x85, 0xab, 0x92, 0x50, 0xc4, 0x8d, 0xea, 0x48, 0xa3, 0xfc },
+      { 0x17, 0x20, 0xb3, 0x65, 0x56, 0x19, 0xd2, 0xa5, 0x2b, 0x35, 0x21, 0xae, 0x0e, 0x49, 0xe3, 0x45, 0xcb, 0x33, 0x89, 0xeb, 0xd6, 0x20, 0x8a, 0xca, 0xf9, 0xf1, 0x3f, 0xda, 0xcc, 0xa8, 0xbe, 0x49 },
+      { 0x75, 0x62, 0x88, 0x36, 0x1c, 0x83, 0xe2, 0x4c, 0x61, 0x7c, 0xf9, 0x5c, 0x90, 0x5b, 0x22, 0xd0, 0x17, 0xcd, 0xc8, 0x6f, 0x0b, 0xf1, 0xd6, 0x58, 0xf4, 0x75, 0x6c, 0x73, 0x79, 0x87, 0x3b, 0x7f },
+      { 0xe7, 0xd0, 0xed, 0xa3, 0x45, 0x26, 0x93, 0xb7, 0x52, 0xab, 0xcd, 0xa1, 0xb5, 0x5e, 0x27, 0x6f, 0x82, 0x69, 0x8f, 0x5f, 0x16, 0x05, 0x40, 0x3e, 0xff, 0x83, 0x0b, 0xea, 0x00, 0x71, 0xa3, 0x94 },
+      { 0x2c, 0x82, 0xec, 0xaa, 0x6b, 0x84, 0x80, 0x3e, 0x04, 0x4a, 0xf6, 0x31, 0x18, 0xaf, 0xe5, 0x44, 0x68, 0x7c, 0xb6, 0xe6, 0xc7, 0xdf, 0x49, 0xed, 0x76, 0x2d, 0xfd, 0x7c, 0x86, 0x93, 0xa1, 0xbc },
+      { 0x61, 0x36, 0xcb, 0xf4, 0xb4, 0x41, 0x05, 0x6f, 0xa1, 0xe2, 0x72, 0x24, 0x98, 0x12, 0x5d, 0x6d, 0xed, 0x45, 0xe1, 0x7b, 0x52, 0x14, 0x39, 0x59, 0xc7, 0xf4, 0xd4, 0xe3, 0x95, 0x21, 0x8a, 0xc2 },
+      { 0x72, 0x1d, 0x32, 0x45, 0xaa, 0xfe, 0xf2, 0x7f, 0x6a, 0x62, 0x4f, 0x47, 0x95, 0x4b, 0x6c, 0x25, 0x50, 0x79, 0x52, 0x6f, 0xfa, 0x25, 0xe9, 0xff, 0x77, 0xe5, 0xdc, 0xff, 0x47, 0x3b, 0x15, 0x97 },
+      { 0x9d, 0xd2, 0xfb, 0xd8, 0xce, 0xf1, 0x6c, 0x35, 0x3c, 0x0a, 0xc2, 0x11, 0x91, 0xd5, 0x09, 0xeb, 0x28, 0xdd, 0x9e, 0x3e, 0x0d, 0x8c, 0xea, 0x5d, 0x26, 0xca, 0x83, 0x93, 0x93, 0x85, 0x1c, 0x3a },
+      { 0xb2, 0x39, 0x4c, 0xea, 0xcd, 0xeb, 0xf2, 0x1b, 0xf9, 0xdf, 0x2c, 0xed, 0x98, 0xe5, 0x8f, 0x1c, 0x3a, 0x4b, 0xbb, 0xff, 0x66, 0x0d, 0xd9, 0x00, 0xf6, 0x22, 0x02, 0xd6, 0x78, 0x5c, 0xc4, 0x6e },
+      { 0x57, 0x08, 0x9f, 0x22, 0x27, 0x49, 0xad, 0x78, 0x71, 0x76, 0x5f, 0x06, 0x2b, 0x11, 0x4f, 0x43, 0xba, 0x20, 0xec, 0x56, 0x42, 0x2a, 0x8b, 0x1e, 0x3f, 0x87, 0x19, 0x2c, 0x0e, 0xa7, 0x18, 0xc6 },
+      { 0xe4, 0x9a, 0x94, 0x59, 0x96, 0x1c, 0xd3, 0x3c, 0xdf, 0x4a, 0xae, 0x1b, 0x10, 0x78, 0xa5, 0xde, 0xa7, 0xc0, 0x40, 0xe0, 0xfe, 0xa3, 0x40, 0xc9, 0x3a, 0x72, 0x48, 0x72, 0xfc, 0x4a, 0xf8, 0x06 },
+      { 0xed, 0xe6, 0x7f, 0x72, 0x0e, 0xff, 0xd2, 0xca, 0x9c, 0x88, 0x99, 0x41, 0x52, 0xd0, 0x20, 0x1d, 0xee, 0x6b, 0x0a, 0x2d, 0x2c, 0x07, 0x7a, 0xca, 0x6d, 0xae, 0x29, 0xf7, 0x3f, 0x8b, 0x63, 0x09 },
+      { 0xe0, 0xf4, 0x34, 0xbf, 0x22, 0xe3, 0x08, 0x80, 0x39, 0xc2, 0x1f, 0x71, 0x9f, 0xfc, 0x67, 0xf0, 0xf2, 0xcb, 0x5e, 0x98, 0xa7, 0xa0, 0x19, 0x4c, 0x76, 0xe9, 0x6b, 0xf4, 0xe8, 0xe1, 0x7e, 0x61 },
+      { 0x27, 0x7c, 0x04, 0xe2, 0x85, 0x34, 0x84, 0xa4, 0xeb, 0xa9, 0x10, 0xad, 0x33, 0x6d, 0x01, 0xb4, 0x77, 0xb6, 0x7c, 0xc2, 0x00, 0xc5, 0x9f, 0x3c, 0x8d, 0x77, 0xee, 0xf8, 0x49, 0x4f, 0x29, 0xcd },
+      { 0x15, 0x6d, 0x57, 0x47, 0xd0, 0xc9, 0x9c, 0x7f, 0x27, 0x09, 0x7d, 0x7b, 0x7e, 0x00, 0x2b, 0x2e, 0x18, 0x5c, 0xb7, 0x2d, 0x8d, 0xd7, 0xeb, 0x42, 0x4a, 0x03, 0x21, 0x52, 0x81, 0x61, 0x21, 0x9f },
+      { 0x20, 0xdd, 0xd1, 0xed, 0x9b, 0x1c, 0xa8, 0x03, 0x94, 0x6d, 0x64, 0xa8, 0x3a, 0xe4, 0x65, 0x9d, 0xa6, 0x7f, 0xba, 0x7a, 0x1a, 0x3e, 0xdd, 0xb1, 0xe1, 0x03, 0xc0, 0xf5, 0xe0, 0x3e, 0x3a, 0x2c },
+      { 0xf0, 0xaf, 0x60, 0x4d, 0x3d, 0xab, 0xbf, 0x9a, 0x0f, 0x2a, 0x7d, 0x3d, 0xda, 0x6b, 0xd3, 0x8b, 0xba, 0x72, 0xc6, 0xd0, 0x9b, 0xe4, 0x94, 0xfc, 0xef, 0x71, 0x3f, 0xf1, 0x01, 0x89, 0xb6, 0xe6 },
+      { 0x98, 0x02, 0xbb, 0x87, 0xde, 0xf4, 0xcc, 0x10, 0xc4, 0xa5, 0xfd, 0x49, 0xaa, 0x58, 0xdf, 0xe2, 0xf3, 0xfd, 0xdb, 0x46, 0xb4, 0x70, 0x88, 0x14, 0xea, 0xd8, 0x1d, 0x23, 0xba, 0x95, 0x13, 0x9b },
+      { 0x4f, 0x8c, 0xe1, 0xe5, 0x1d, 0x2f, 0xe7, 0xf2, 0x40, 0x43, 0xa9, 0x04, 0xd8, 0x98, 0xeb, 0xfc, 0x91, 0x97, 0x54, 0x18, 0x75, 0x34, 0x13, 0xaa, 0x09, 0x9b, 0x79, 0x5e, 0xcb, 0x35, 0xce, 0xdb },
+      { 0xbd, 0xdc, 0x65, 0x14, 0xd7, 0xee, 0x6a, 0xce, 0x0a, 0x4a, 0xc1, 0xd0, 0xe0, 0x68, 0x11, 0x22, 0x88, 0xcb, 0xcf, 0x56, 0x04, 0x54, 0x64, 0x27, 0x05, 0x63, 0x01, 0x77, 0xcb, 0xa6, 0x08, 0xbd },
+      { 0xd6, 0x35, 0x99, 0x4f, 0x62, 0x91, 0x51, 0x7b, 0x02, 0x81, 0xff, 0xdd, 0x49, 0x6a, 0xfa, 0x86, 0x27, 0x12, 0xe5, 0xb3, 0xc4, 0xe5, 0x2e, 0x4c, 0xd5, 0xfd, 0xae, 0x8c, 0x0e, 0x72, 0xfb, 0x08 },
+      { 0x87, 0x8d, 0x9c, 0xa6, 0x00, 0xcf, 0x87, 0xe7, 0x69, 0xcc, 0x30, 0x5c, 0x1b, 0x35, 0x25, 0x51, 0x86, 0x61, 0x5a, 0x73, 0xa0, 0xda, 0x61, 0x3b, 0x5f, 0x1c, 0x98, 0xdb, 0xf8, 0x12, 0x83, 0xea },
+      { 0xa6, 0x4e, 0xbe, 0x5d, 0xc1, 0x85, 0xde, 0x9f, 0xdd, 0xe7, 0x60, 0x7b, 0x69, 0x98, 0x70, 0x2e, 0xb2, 0x34, 0x56, 0x18, 0x49, 0x57, 0x30, 0x7d, 0x2f, 0xa7, 0x2e, 0x87, 0xa4, 0x77, 0x02, 0xd6 },
+      { 0xce, 0x50, 0xea, 0xb7, 0xb5, 0xeb, 0x52, 0xbd, 0xc9, 0xad, 0x8e, 0x5a, 0x48, 0x0a, 0xb7, 0x80, 0xca, 0x93, 0x20, 0xe4, 0x43, 0x60, 0xb1, 0xfe, 0x37, 0xe0, 0x3f, 0x2f, 0x7a, 0xd7, 0xde, 0x01 },
+      { 0xee, 0xdd, 0xb7, 0xc0, 0xdb, 0x6e, 0x30, 0xab, 0xe6, 0x6d, 0x79, 0xe3, 0x27, 0x51, 0x1e, 0x61, 0xfc, 0xeb, 0xbc, 0x29, 0xf1, 0x59, 0xb4, 0x0a, 0x86, 0xb0, 0x46, 0xec, 0xf0, 0x51, 0x38, 0x23 },
+      { 0x78, 0x7f, 0xc9, 0x34, 0x40, 0xc1, 0xec, 0x96, 0xb5, 0xad, 0x01, 0xc1, 0x6c, 0xf7, 0x79, 0x16, 0xa1, 0x40, 0x5f, 0x94, 0x26, 0x35, 0x6e, 0xc9, 0x21, 0xd8, 0xdf, 0xf3, 0xea, 0x63, 0xb7, 0xe0 },
+      { 0x7f, 0x0d, 0x5e, 0xab, 0x47, 0xee, 0xfd, 0xa6, 0x96, 0xc0, 0xbf, 0x0f, 0xbf, 0x86, 0xab, 0x21, 0x6f, 0xce, 0x46, 0x1e, 0x93, 0x03, 0xab, 0xa6, 0xac, 0x37, 0x41, 0x20, 0xe8, 0x90, 0xe8, 0xdf },
+      { 0xb6, 0x80, 0x04, 0xb4, 0x2f, 0x14, 0xad, 0x02, 0x9f, 0x4c, 0x2e, 0x03, 0xb1, 0xd5, 0xeb, 0x76, 0xd5, 0x71, 0x60, 0xe2, 0x64, 0x76, 0xd2, 0x11, 0x31, 0xbe, 0xf2, 0x0a, 0xda, 0x7d, 0x27, 0xf4 },
+      { 0xb0, 0xc4, 0xeb, 0x18, 0xae, 0x25, 0x0b, 0x51, 0xa4, 0x13, 0x82, 0xea, 0xd9, 0x2d, 0x0d, 0xc7, 0x45, 0x5f, 0x93, 0x79, 0xfc, 0x98, 0x84, 0x42, 0x8e, 0x47, 0x70, 0x60, 0x8d, 0xb0, 0xfa, 0xec },
+      { 0xf9, 0x2b, 0x7a, 0x87, 0x0c, 0x05, 0x9f, 0x4d, 0x46, 0x46, 0x4c, 0x82, 0x4e, 0xc9, 0x63, 0x55, 0x14, 0x0b, 0xdc, 0xe6, 0x81, 0x32, 0x2c, 0xc3, 0xa9, 0x92, 0xff, 0x10, 0x3e, 0x3f, 0xea, 0x52 },
+      { 0x53, 0x64, 0x31, 0x26, 0x14, 0x81, 0x33, 0x98, 0xcc, 0x52, 0x5d, 0x4c, 0x4e, 0x14, 0x6e, 0xde, 0xb3, 0x71, 0x26, 0x5f, 0xba, 0x19, 0x13, 0x3a, 0x2c, 0x3d, 0x21, 0x59, 0x29, 0x8a, 0x17, 0x42 },
+      { 0xf6, 0x62, 0x0e, 0x68, 0xd3, 0x7f, 0xb2, 0xaf, 0x50, 0x00, 0xfc, 0x28, 0xe2, 0x3b, 0x83, 0x22, 0x97, 0xec, 0xd8, 0xbc, 0xe9, 0x9e, 0x8b, 0xe4, 0xd0, 0x4e, 0x85, 0x30, 0x9e, 0x3d, 0x33, 0x74 },
+      { 0x53, 0x16, 0xa2, 0x79, 0x69, 0xd7, 0xfe, 0x04, 0xff, 0x27, 0xb2, 0x83, 0x96, 0x1b, 0xff, 0xc3, 0xbf, 0x5d, 0xfb, 0x32, 0xfb, 0x6a, 0x89, 0xd1, 0x01, 0xc6, 0xc3, 0xb1, 0x93, 0x7c, 0x28, 0x71 },
+      { 0x81, 0xd1, 0x66, 0x4f, 0xdf, 0x3c, 0xb3, 0x3c, 0x24, 0xee, 0xba, 0xc0, 0xbd, 0x64, 0x24, 0x4b, 0x77, 0xc4, 0xab, 0xea, 0x90, 0xbb, 0xe8, 0xb5, 0xee, 0x0b, 0x2a, 0xaf, 0xcf, 0x2d, 0x6a, 0x53 },
+      { 0x34, 0x57, 0x82, 0xf2, 0x95, 0xb0, 0x88, 0x03, 0x52, 0xe9, 0x24, 0xa0, 0x46, 0x7b, 0x5f, 0xbc, 0x3e, 0x8f, 0x3b, 0xfb, 0xc3, 0xc7, 0xe4, 0x8b, 0x67, 0x09, 0x1f, 0xb5, 0xe8, 0x0a, 0x94, 0x42 },
+      { 0x79, 0x41, 0x11, 0xea, 0x6c, 0xd6, 0x5e, 0x31, 0x1f, 0x74, 0xee, 0x41, 0xd4, 0x76, 0xcb, 0x63, 0x2c, 0xe1, 0xe4, 0xb0, 0x51, 0xdc, 0x1d, 0x9e, 0x9d, 0x06, 0x1a, 0x19, 0xe1, 0xd0, 0xbb, 0x49 },
+      { 0x2a, 0x85, 0xda, 0xf6, 0x13, 0x88, 0x16, 0xb9, 0x9b, 0xf8, 0xd0, 0x8b, 0xa2, 0x11, 0x4b, 0x7a, 0xb0, 0x79, 0x75, 0xa7, 0x84, 0x20, 0xc1, 0xa3, 0xb0, 0x6a, 0x77, 0x7c, 0x22, 0xdd, 0x8b, 0xcb },
+      { 0x89, 0xb0, 0xd5, 0xf2, 0x89, 0xec, 0x16, 0x40, 0x1a, 0x06, 0x9a, 0x96, 0x0d, 0x0b, 0x09, 0x3e, 0x62, 0x5d, 0xa3, 0xcf, 0x41, 0xee, 0x29, 0xb5, 0x9b, 0x93, 0x0c, 0x58, 0x20, 0x14, 0x54, 0x55 },
+      { 0xd0, 0xfd, 0xcb, 0x54, 0x39, 0x43, 0xfc, 0x27, 0xd2, 0x08, 0x64, 0xf5, 0x21, 0x81, 0x47, 0x1b, 0x94, 0x2c, 0xc7, 0x7c, 0xa6, 0x75, 0xbc, 0xb3, 0x0d, 0xf3, 0x1d, 0x35, 0x8e, 0xf7, 0xb1, 0xeb },
+      { 0xb1, 0x7e, 0xa8, 0xd7, 0x70, 0x63, 0xc7, 0x09, 0xd4, 0xdc, 0x6b, 0x87, 0x94, 0x13, 0xc3, 0x43, 0xe3, 0x79, 0x0e, 0x9e, 0x62, 0xca, 0x85, 0xb7, 0x90, 0x0b, 0x08, 0x6f, 0x6b, 0x75, 0xc6, 0x72 },
+      { 0xe7, 0x1a, 0x3e, 0x2c, 0x27, 0x4d, 0xb8, 0x42, 0xd9, 0x21, 0x14, 0xf2, 0x17, 0xe2, 0xc0, 0xea, 0xc8, 0xb4, 0x50, 0x93, 0xfd, 0xfd, 0x9d, 0xf4, 0xca, 0x71, 0x62, 0x39, 0x48, 0x62, 0xd5, 0x01 },
+      { 0xc0, 0x47, 0x67, 0x59, 0xab, 0x7a, 0xa3, 0x33, 0x23, 0x4f, 0x6b, 0x44, 0xf5, 0xfd, 0x85, 0x83, 0x90, 0xec, 0x23, 0x69, 0x4c, 0x62, 0x2c, 0xb9, 0x86, 0xe7, 0x69, 0xc7, 0x8e, 0xdd, 0x73, 0x3e },
+      { 0x9a, 0xb8, 0xea, 0xbb, 0x14, 0x16, 0x43, 0x4d, 0x85, 0x39, 0x13, 0x41, 0xd5, 0x69, 0x93, 0xc5, 0x54, 0x58, 0x16, 0x7d, 0x44, 0x18, 0xb1, 0x9a, 0x0f, 0x2a, 0xd8, 0xb7, 0x9a, 0x83, 0xa7, 0x5b },
+      { 0x79, 0x92, 0xd0, 0xbb, 0xb1, 0x5e, 0x23, 0x82, 0x6f, 0x44, 0x3e, 0x00, 0x50, 0x5d, 0x68, 0xd3, 0xed, 0x73, 0x72, 0x99, 0x5a, 0x5c, 0x3e, 0x49, 0x86, 0x54, 0x10, 0x2f, 0xbc, 0xd0, 0x96, 0x4e },
+      { 0xc0, 0x21, 0xb3, 0x00, 0x85, 0x15, 0x14, 0x35, 0xdf, 0x33, 0xb0, 0x07, 0xcc, 0xec, 0xc6, 0x9d, 0xf1, 0x26, 0x9f, 0x39, 0xba, 0x25, 0x09, 0x2b, 0xed, 0x59, 0xd9, 0x32, 0xac, 0x0f, 0xdc, 0x28 },
+      { 0x91, 0xa2, 0x5e, 0xc0, 0xec, 0x0d, 0x9a, 0x56, 0x7f, 0x89, 0xc4, 0xbf, 0xe1, 0xa6, 0x5a, 0x0e, 0x43, 0x2d, 0x07, 0x06, 0x4b, 0x41, 0x90, 0xe2, 0x7d, 0xfb, 0x81, 0x90, 0x1f, 0xd3, 0x13, 0x9b },
+      { 0x59, 0x50, 0xd3, 0x9a, 0x23, 0xe1, 0x54, 0x5f, 0x30, 0x12, 0x70, 0xaa, 0x1a, 0x12, 0xf2, 0xe6, 0xc4, 0x53, 0x77, 0x6e, 0x4d, 0x63, 0x55, 0xde, 0x42, 0x5c, 0xc1, 0x53, 0xf9, 0x81, 0x88, 0x67 },
+      { 0xd7, 0x9f, 0x14, 0x72, 0x0c, 0x61, 0x0a, 0xf1, 0x79, 0xa3, 0x76, 0x5d, 0x4b, 0x7c, 0x09, 0x68, 0xf9, 0x77, 0x96, 0x2d, 0xbf, 0x65, 0x5b, 0x52, 0x12, 0x72, 0xb6, 0xf1, 0xe1, 0x94, 0x48, 0x8e },
+      { 0xe9, 0x53, 0x1b, 0xfc, 0x8b, 0x02, 0x99, 0x5a, 0xea, 0xa7, 0x5b, 0xa2, 0x70, 0x31, 0xfa, 0xdb, 0xcb, 0xf4, 0xa0, 0xda, 0xb8, 0x96, 0x1d, 0x92, 0x96, 0xcd, 0x7e, 0x84, 0xd2, 0x5d, 0x60, 0x06 },
+      { 0x34, 0xe9, 0xc2, 0x6a, 0x01, 0xd7, 0xf1, 0x61, 0x81, 0xb4, 0x54, 0xa9, 0xd1, 0x62, 0x3c, 0x23, 0x3c, 0xb9, 0x9d, 0x31, 0xc6, 0x94, 0x65, 0x6e, 0x94, 0x13, 0xac, 0xa3, 0xe9, 0x18, 0x69, 0x2f },
+      { 0xd9, 0xd7, 0x42, 0x2f, 0x43, 0x7b, 0xd4, 0x39, 0xdd, 0xd4, 0xd8, 0x83, 0xda, 0xe2, 0xa0, 0x83, 0x50, 0x17, 0x34, 0x14, 0xbe, 0x78, 0x15, 0x51, 0x33, 0xff, 0xf1, 0x96, 0x4c, 0x3d, 0x79, 0x72 },
+      { 0x4a, 0xee, 0x0c, 0x7a, 0xaf, 0x07, 0x54, 0x14, 0xff, 0x17, 0x93, 0xea, 0xd7, 0xea, 0xca, 0x60, 0x17, 0x75, 0xc6, 0x15, 0xdb, 0xd6, 0x0b, 0x64, 0x0b, 0x0a, 0x9f, 0x0c, 0xe5, 0x05, 0xd4, 0x35 },
+      { 0x6b, 0xfd, 0xd1, 0x54, 0x59, 0xc8, 0x3b, 0x99, 0xf0, 0x96, 0xbf, 0xb4, 0x9e, 0xe8, 0x7b, 0x06, 0x3d, 0x69, 0xc1, 0x97, 0x4c, 0x69, 0x28, 0xac, 0xfc, 0xfb, 0x40, 0x99, 0xf8, 0xc4, 0xef, 0x67 },
+      { 0x9f, 0xd1, 0xc4, 0x08, 0xfd, 0x75, 0xc3, 0x36, 0x19, 0x3a, 0x2a, 0x14, 0xd9, 0x4f, 0x6a, 0xf5, 0xad, 0xf0, 0x50, 0xb8, 0x03, 0x87, 0xb4, 0xb0, 0x10, 0xfb, 0x29, 0xf4, 0xcc, 0x72, 0x70, 0x7c },
+      { 0x13, 0xc8, 0x84, 0x80, 0xa5, 0xd0, 0x0d, 0x6c, 0x8c, 0x7a, 0xd2, 0x11, 0x0d, 0x76, 0xa8, 0x2d, 0x9b, 0x70, 0xf4, 0xfa, 0x66, 0x96, 0xd4, 0xe5, 0xdd, 0x42, 0xa0, 0x66, 0xdc, 0xaf, 0x99, 0x20 },
+      { 0x82, 0x0e, 0x72, 0x5e, 0xe2, 0x5f, 0xe8, 0xfd, 0x3a, 0x8d, 0x5a, 0xbe, 0x4c, 0x46, 0xc3, 0xba, 0x88, 0x9d, 0xe6, 0xfa, 0x91, 0x91, 0xaa, 0x22, 0xba, 0x67, 0xd5, 0x70, 0x54, 0x21, 0x54, 0x2b },
+      { 0x32, 0xd9, 0x3a, 0x0e, 0xb0, 0x2f, 0x42, 0xfb, 0xbc, 0xaf, 0x2b, 0xad, 0x00, 0x85, 0xb2, 0x82, 0xe4, 0x60, 0x46, 0xa4, 0xdf, 0x7a, 0xd1, 0x06, 0x57, 0xc9, 0xd6, 0x47, 0x63, 0x75, 0xb9, 0x3e },
+      { 0xad, 0xc5, 0x18, 0x79, 0x05, 0xb1, 0x66, 0x9c, 0xd8, 0xec, 0x9c, 0x72, 0x1e, 0x19, 0x53, 0x78, 0x6b, 0x9d, 0x89, 0xa9, 0xba, 0xe3, 0x07, 0x80, 0xf1, 0xe1, 0xea, 0xb2, 0x4a, 0x00, 0x52, 0x3c },
+      { 0xe9, 0x07, 0x56, 0xff, 0x7f, 0x9a, 0xd8, 0x10, 0xb2, 0x39, 0xa1, 0x0c, 0xed, 0x2c, 0xf9, 0xb2, 0x28, 0x43, 0x54, 0xc1, 0xf8, 0xc7, 0xe0, 0xac, 0xcc, 0x24, 0x61, 0xdc, 0x79, 0x6d, 0x6e, 0x89 },
+      { 0x12, 0x51, 0xf7, 0x6e, 0x56, 0x97, 0x84, 0x81, 0x87, 0x53, 0x59, 0x80, 0x1d, 0xb5, 0x89, 0xa0, 0xb2, 0x2f, 0x86, 0xd8, 0xd6, 0x34, 0xdc, 0x04, 0x50, 0x6f, 0x32, 0x2e, 0xd7, 0x8f, 0x17, 0xe8 },
+      { 0x3a, 0xfa, 0x89, 0x9f, 0xd9, 0x80, 0xe7, 0x3e, 0xcb, 0x7f, 0x4d, 0x8b, 0x8f, 0x29, 0x1d, 0xc9, 0xaf, 0x79, 0x6b, 0xc6, 0x5d, 0x27, 0xf9, 0x74, 0xc6, 0xf1, 0x93, 0xc9, 0x19, 0x1a, 0x09, 0xfd },
+      { 0xaa, 0x30, 0x5b, 0xe2, 0x6e, 0x5d, 0xed, 0xdc, 0x3c, 0x10, 0x10, 0xcb, 0xc2, 0x13, 0xf9, 0x5f, 0x05, 0x1c, 0x78, 0x5c, 0x5b, 0x43, 0x1e, 0x6a, 0x7c, 0xd0, 0x48, 0xf1, 0x61, 0x78, 0x75, 0x28 },
+      { 0x8e, 0xa1, 0x88, 0x4f, 0xf3, 0x2e, 0x9d, 0x10, 0xf0, 0x39, 0xb4, 0x07, 0xd0, 0xd4, 0x4e, 0x7e, 0x67, 0x0a, 0xbd, 0x88, 0x4a, 0xee, 0xe0, 0xfb, 0x75, 0x7a, 0xe9, 0x4e, 0xaa, 0x97, 0x37, 0x3d },
+      { 0xd4, 0x82, 0xb2, 0x15, 0x5d, 0x4d, 0xec, 0x6b, 0x47, 0x36, 0xa1, 0xf1, 0x61, 0x7b, 0x53, 0xaa, 0xa3, 0x73, 0x10, 0x27, 0x7d, 0x3f, 0xef, 0x0c, 0x37, 0xad, 0x41, 0x76, 0x8f, 0xc2, 0x35, 0xb4 },
+      { 0x4d, 0x41, 0x39, 0x71, 0x38, 0x7e, 0x7a, 0x88, 0x98, 0xa8, 0xdc, 0x2a, 0x27, 0x50, 0x07, 0x78, 0x53, 0x9e, 0xa2, 0x14, 0xa2, 0xdf, 0xe9, 0xb3, 0xd7, 0xe8, 0xeb, 0xdc, 0xe5, 0xcf, 0x3d, 0xb3 },
+      { 0x69, 0x6e, 0x5d, 0x46, 0xe6, 0xc5, 0x7e, 0x87, 0x96, 0xe4, 0x73, 0x5d, 0x08, 0x91, 0x6e, 0x0b, 0x79, 0x29, 0xb3, 0xcf, 0x29, 0x8c, 0x29, 0x6d, 0x22, 0xe9, 0xd3, 0x01, 0x96, 0x53, 0x37, 0x1c },
+      { 0x1f, 0x56, 0x47, 0xc1, 0xd3, 0xb0, 0x88, 0x22, 0x88, 0x85, 0x86, 0x5c, 0x89, 0x40, 0x90, 0x8b, 0xf4, 0x0d, 0x1a, 0x82, 0x72, 0x82, 0x19, 0x73, 0xb1, 0x60, 0x00, 0x8e, 0x7a, 0x3c, 0xe2, 0xeb },
+      { 0xb6, 0xe7, 0x6c, 0x33, 0x0f, 0x02, 0x1a, 0x5b, 0xda, 0x65, 0x87, 0x50, 0x10, 0xb0, 0xed, 0xf0, 0x91, 0x26, 0xc0, 0xf5, 0x10, 0xea, 0x84, 0x90, 0x48, 0x19, 0x20, 0x03, 0xae, 0xf4, 0xc6, 0x1c },
+      { 0x3c, 0xd9, 0x52, 0xa0, 0xbe, 0xad, 0xa4, 0x1a, 0xbb, 0x42, 0x4c, 0xe4, 0x7f, 0x94, 0xb4, 0x2b, 0xe6, 0x4e, 0x1f, 0xfb, 0x0f, 0xd0, 0x78, 0x22, 0x76, 0x80, 0x79, 0x46, 0xd0, 0xd0, 0xbc, 0x55 },
+      { 0x98, 0xd9, 0x26, 0x77, 0x43, 0x9b, 0x41, 0xb7, 0xbb, 0x51, 0x33, 0x12, 0xaf, 0xb9, 0x2b, 0xcc, 0x8e, 0xe9, 0x68, 0xb2, 0xe3, 0xb2, 0x38, 0xce, 0xcb, 0x9b, 0x0f, 0x34, 0xc9, 0xbb, 0x63, 0xd0 },
+      { 0xec, 0xbc, 0xa2, 0xcf, 0x08, 0xae, 0x57, 0xd5, 0x17, 0xad, 0x16, 0x15, 0x8a, 0x32, 0xbf, 0xa7, 0xdc, 0x03, 0x82, 0xea, 0xed, 0xa1, 0x28, 0xe9, 0x18, 0x86, 0x73, 0x4c, 0x24, 0xa0, 0xb2, 0x9d },
+      { 0x94, 0x2c, 0xc7, 0xc0, 0xb5, 0x2e, 0x2b, 0x16, 0xa4, 0xb8, 0x9f, 0xa4, 0xfc, 0x7e, 0x0b, 0xf6, 0x09, 0xe2, 0x9a, 0x08, 0xc1, 0xa8, 0x54, 0x34, 0x52, 0xb7, 0x7c, 0x7b, 0xfd, 0x11, 0xbb, 0x28 },
+      { 0x8a, 0x06, 0x5d, 0x8b, 0x61, 0xa0, 0xdf, 0xfb, 0x17, 0x0d, 0x56, 0x27, 0x73, 0x5a, 0x76, 0xb0, 0xe9, 0x50, 0x60, 0x37, 0x80, 0x8c, 0xba, 0x16, 0xc3, 0x45, 0x00, 0x7c, 0x9f, 0x79, 0xcf, 0x8f },
+      { 0x1b, 0x9f, 0xa1, 0x97, 0x14, 0x65, 0x9c, 0x78, 0xff, 0x41, 0x38, 0x71, 0x84, 0x92, 0x15, 0x36, 0x10, 0x29, 0xac, 0x80, 0x2b, 0x1c, 0xbc, 0xd5, 0x4e, 0x40, 0x8b, 0xd8, 0x72, 0x87, 0xf8, 0x1f },
+      { 0x8d, 0xab, 0x07, 0x1b, 0xcd, 0x6c, 0x72, 0x92, 0xa9, 0xef, 0x72, 0x7b, 0x4a, 0xe0, 0xd8, 0x67, 0x13, 0x30, 0x1d, 0xa8, 0x61, 0x8d, 0x9a, 0x48, 0xad, 0xce, 0x55, 0xf3, 0x03, 0xa8, 0x69, 0xa1 },
+      { 0x82, 0x53, 0xe3, 0xe7, 0xc7, 0xb6, 0x84, 0xb9, 0xcb, 0x2b, 0xeb, 0x01, 0x4c, 0xe3, 0x30, 0xff, 0x3d, 0x99, 0xd1, 0x7a, 0xbb, 0xdb, 0xab, 0xe4, 0xf4, 0xd6, 0x74, 0xde, 0xd5, 0x3f, 0xfc, 0x6b },
+      { 0xf1, 0x95, 0xf3, 0x21, 0xe9, 0xe3, 0xd6, 0xbd, 0x7d, 0x07, 0x45, 0x04, 0xdd, 0x2a, 0xb0, 0xe6, 0x24, 0x1f, 0x92, 0xe7, 0x84, 0xb1, 0xaa, 0x27, 0x1f, 0xf6, 0x48, 0xb1, 0xca, 0xb6, 0xd7, 0xf6 },
+      { 0x27, 0xe4, 0xcc, 0x72, 0x09, 0x0f, 0x24, 0x12, 0x66, 0x47, 0x6a, 0x7c, 0x09, 0x49, 0x5f, 0x2d, 0xb1, 0x53, 0xd5, 0xbc, 0xbd, 0x76, 0x19, 0x03, 0xef, 0x79, 0x27, 0x5e, 0xc5, 0x6b, 0x2e, 0xd8 },
+      { 0x89, 0x9c, 0x24, 0x05, 0x78, 0x8e, 0x25, 0xb9, 0x9a, 0x18, 0x46, 0x35, 0x5e, 0x64, 0x6d, 0x77, 0xcf, 0x40, 0x00, 0x83, 0x41, 0x5f, 0x7d, 0xc5, 0xaf, 0xe6, 0x9d, 0x6e, 0x17, 0xc0, 0x00, 0x23 },
+      { 0xa5, 0x9b, 0x78, 0xc4, 0x90, 0x57, 0x44, 0x07, 0x6b, 0xfe, 0xe8, 0x94, 0xde, 0x70, 0x7d, 0x4f, 0x12, 0x0b, 0x5c, 0x68, 0x93, 0xea, 0x04, 0x00, 0x29, 0x7d, 0x0b, 0xb8, 0x34, 0x72, 0x76, 0x32 },
+      { 0x59, 0xdc, 0x78, 0xb1, 0x05, 0x64, 0x97, 0x07, 0xa2, 0xbb, 0x44, 0x19, 0xc4, 0x8f, 0x00, 0x54, 0x00, 0xd3, 0x97, 0x3d, 0xe3, 0x73, 0x66, 0x10, 0x23, 0x04, 0x35, 0xb1, 0x04, 0x24, 0xb2, 0x4f },
+      { 0xc0, 0x14, 0x9d, 0x1d, 0x7e, 0x7a, 0x63, 0x53, 0xa6, 0xd9, 0x06, 0xef, 0xe7, 0x28, 0xf2, 0xf3, 0x29, 0xfe, 0x14, 0xa4, 0x14, 0x9a, 0x3e, 0xa7, 0x76, 0x09, 0xbc, 0x42, 0xb9, 0x75, 0xdd, 0xfa },
+      { 0xa3, 0x2f, 0x24, 0x14, 0x74, 0xa6, 0xc1, 0x69, 0x32, 0xe9, 0x24, 0x3b, 0xe0, 0xcf, 0x09, 0xbc, 0xdc, 0x7e, 0x0c, 0xa0, 0xe7, 0xa6, 0xa1, 0xb9, 0xb1, 0xa0, 0xf0, 0x1e, 0x41, 0x50, 0x23, 0x77 },
+      { 0xb2, 0x39, 0xb2, 0xe4, 0xf8, 0x18, 0x41, 0x36, 0x1c, 0x13, 0x39, 0xf6, 0x8e, 0x2c, 0x35, 0x9f, 0x92, 0x9a, 0xf9, 0xad, 0x9f, 0x34, 0xe0, 0x1a, 0xab, 0x46, 0x31, 0xad, 0x6d, 0x55, 0x00, 0xb0 },
+      { 0x85, 0xfb, 0x41, 0x9c, 0x70, 0x02, 0xa3, 0xe0, 0xb4, 0xb6, 0xea, 0x09, 0x3b, 0x4c, 0x1a, 0xc6, 0x93, 0x66, 0x45, 0xb6, 0x5d, 0xac, 0x5a, 0xc1, 0x5a, 0x85, 0x28, 0xb7, 0xb9, 0x4c, 0x17, 0x54 },
+      { 0x96, 0x19, 0x72, 0x06, 0x25, 0xf1, 0x90, 0xb9, 0x3a, 0x3f, 0xad, 0x18, 0x6a, 0xb3, 0x14, 0x18, 0x96, 0x33, 0xc0, 0xd3, 0xa0, 0x1e, 0x6f, 0x9b, 0xc8, 0xc4, 0xa8, 0xf8, 0x2f, 0x38, 0x3d, 0xbf },
+      { 0x7d, 0x62, 0x0d, 0x90, 0xfe, 0x69, 0xfa, 0x46, 0x9a, 0x65, 0x38, 0x38, 0x89, 0x70, 0xa1, 0xaa, 0x09, 0xbb, 0x48, 0xa2, 0xd5, 0x9b, 0x34, 0x7b, 0x97, 0xe8, 0xce, 0x71, 0xf4, 0x8c, 0x7f, 0x46 },
+      { 0x29, 0x43, 0x83, 0x56, 0x85, 0x96, 0xfb, 0x37, 0xc7, 0x5b, 0xba, 0xcd, 0x97, 0x9c, 0x5f, 0xf6, 0xf2, 0x0a, 0x55, 0x6b, 0xf8, 0x87, 0x9c, 0xc7, 0x29, 0x24, 0x85, 0x5d, 0xf9, 0xb8, 0x24, 0x0e },
+      { 0x16, 0xb1, 0x8a, 0xb3, 0x14, 0x35, 0x9c, 0x2b, 0x83, 0x3c, 0x1c, 0x69, 0x86, 0xd4, 0x8c, 0x55, 0xa9, 0xfc, 0x97, 0xcd, 0xe9, 0xa3, 0xc1, 0xf1, 0x0a, 0x31, 0x77, 0x14, 0x0f, 0x73, 0xf7, 0x38 },
+      { 0x8c, 0xbb, 0xdd, 0x14, 0xbc, 0x33, 0xf0, 0x4c, 0xf4, 0x58, 0x13, 0xe4, 0xa1, 0x53, 0xa2, 0x73, 0xd3, 0x6a, 0xda, 0xd5, 0xce, 0x71, 0xf4, 0x99, 0xee, 0xb8, 0x7f, 0xb8, 0xac, 0x63, 0xb7, 0x29 },
+      { 0x69, 0xc9, 0xa4, 0x98, 0xdb, 0x17, 0x4e, 0xca, 0xef, 0xcc, 0x5a, 0x3a, 0xc9, 0xfd, 0xed, 0xf0, 0xf8, 0x13, 0xa5, 0xbe, 0xc7, 0x27, 0xf1, 0xe7, 0x75, 0xba, 0xbd, 0xec, 0x77, 0x18, 0x81, 0x6e },
+      { 0xb4, 0x62, 0xc3, 0xbe, 0x40, 0x44, 0x8f, 0x1d, 0x4f, 0x80, 0x62, 0x62, 0x54, 0xe5, 0x35, 0xb0, 0x8b, 0xc9, 0xcd, 0xcf, 0xf5, 0x99, 0xa7, 0x68, 0x57, 0x8d, 0x4b, 0x28, 0x81, 0xa8, 0xe3, 0xf0 },
+      { 0x55, 0x3e, 0x9d, 0x9c, 0x5f, 0x36, 0x0a, 0xc0, 0xb7, 0x4a, 0x7d, 0x44, 0xe5, 0xa3, 0x91, 0xda, 0xd4, 0xce, 0xd0, 0x3e, 0x0c, 0x24, 0x18, 0x3b, 0x7e, 0x8e, 0xca, 0xbd, 0xf1, 0x71, 0x5a, 0x64 },
+      { 0x7a, 0x7c, 0x55, 0xa5, 0x6f, 0xa9, 0xae, 0x51, 0xe6, 0x55, 0xe0, 0x19, 0x75, 0xd8, 0xa6, 0xff, 0x4a, 0xe9, 0xe4, 0xb4, 0x86, 0xfc, 0xbe, 0x4e, 0xac, 0x04, 0x45, 0x88, 0xf2, 0x45, 0xeb, 0xea },
+      { 0x2a, 0xfd, 0xf3, 0xc8, 0x2a, 0xbc, 0x48, 0x67, 0xf5, 0xde, 0x11, 0x12, 0x86, 0xc2, 0xb3, 0xbe, 0x7d, 0x6e, 0x48, 0x65, 0x7b, 0xa9, 0x23, 0xcf, 0xbf, 0x10, 0x1a, 0x6d, 0xfc, 0xf9, 0xdb, 0x9a },
+      { 0x41, 0x03, 0x7d, 0x2e, 0xdc, 0xdc, 0xe0, 0xc4, 0x9b, 0x7f, 0xb4, 0xa6, 0xaa, 0x09, 0x99, 0xca, 0x66, 0x97, 0x6c, 0x74, 0x83, 0xaf, 0xe6, 0x31, 0xd4, 0xed, 0xa2, 0x83, 0x14, 0x4f, 0x6d, 0xfc },
+      { 0xc4, 0x46, 0x6f, 0x84, 0x97, 0xca, 0x2e, 0xeb, 0x45, 0x83, 0xa0, 0xb0, 0x8e, 0x9d, 0x9a, 0xc7, 0x43, 0x95, 0x70, 0x9f, 0xda, 0x10, 0x9d, 0x24, 0xf2, 0xe4, 0x46, 0x21, 0x96, 0x77, 0x9c, 0x5d },
+      { 0x75, 0xf6, 0x09, 0x33, 0x8a, 0xa6, 0x7d, 0x96, 0x9a, 0x2a, 0xe2, 0xa2, 0x36, 0x2b, 0x2d, 0xa9, 0xd7, 0x7c, 0x69, 0x5d, 0xfd, 0x1d, 0xf7, 0x22, 0x4a, 0x69, 0x01, 0xdb, 0x93, 0x2c, 0x33, 0x64 },
+      { 0x68, 0x60, 0x6c, 0xeb, 0x98, 0x9d, 0x54, 0x88, 0xfc, 0x7c, 0xf6, 0x49, 0xf3, 0xd7, 0xc2, 0x72, 0xef, 0x05, 0x5d, 0xa1, 0xa9, 0x3f, 0xae, 0xcd, 0x55, 0xfe, 0x06, 0xf6, 0x96, 0x70, 0x98, 0xca },
+      { 0x44, 0x34, 0x6b, 0xde, 0xb7, 0xe0, 0x52, 0xf6, 0x25, 0x50, 0x48, 0xf0, 0xd9, 0xb4, 0x2c, 0x42, 0x5b, 0xab, 0x9c, 0x3d, 0xd2, 0x41, 0x68, 0x21, 0x2c, 0x3e, 0xcf, 0x1e, 0xbf, 0x34, 0xe6, 0xae },
+      { 0x8e, 0x9c, 0xf6, 0xe1, 0xf3, 0x66, 0x47, 0x1f, 0x2a, 0xc7, 0xd2, 0xee, 0x9b, 0x5e, 0x62, 0x66, 0xfd, 0xa7, 0x1f, 0x8f, 0x2e, 0x41, 0x09, 0xf2, 0x23, 0x7e, 0xd5, 0xf8, 0x81, 0x3f, 0xc7, 0x18 },
+      { 0x84, 0xbb, 0xeb, 0x84, 0x06, 0xd2, 0x50, 0x95, 0x1f, 0x8c, 0x1b, 0x3e, 0x86, 0xa7, 0xc0, 0x10, 0x08, 0x29, 0x21, 0x83, 0x3d, 0xfd, 0x95, 0x55, 0xa2, 0xf9, 0x09, 0xb1, 0x08, 0x6e, 0xb4, 0xb8 },
+      { 0xee, 0x66, 0x6f, 0x3e, 0xef, 0x0f, 0x7e, 0x2a, 0x9c, 0x22, 0x29, 0x58, 0xc9, 0x7e, 0xaf, 0x35, 0xf5, 0x1c, 0xed, 0x39, 0x3d, 0x71, 0x44, 0x85, 0xab, 0x09, 0xa0, 0x69, 0x34, 0x0f, 0xdf, 0x88 },
+      { 0xc1, 0x53, 0xd3, 0x4a, 0x65, 0xc4, 0x7b, 0x4a, 0x62, 0xc5, 0xca, 0xcf, 0x24, 0x01, 0x09, 0x75, 0xd0, 0x35, 0x6b, 0x2f, 0x32, 0xc8, 0xf5, 0xda, 0x53, 0x0d, 0x33, 0x88, 0x16, 0xad, 0x5d, 0xe6 },
+      { 0x9f, 0xc5, 0x45, 0x01, 0x09, 0xe1, 0xb7, 0x79, 0xf6, 0xc7, 0xae, 0x79, 0xd5, 0x6c, 0x27, 0x63, 0x5c, 0x8d, 0xd4, 0x26, 0xc5, 0xa9, 0xd5, 0x4e, 0x25, 0x78, 0xdb, 0x98, 0x9b, 0x8c, 0x3b, 0x4e },
+      { 0xd1, 0x2b, 0xf3, 0x73, 0x2e, 0xf4, 0xaf, 0x5c, 0x22, 0xfa, 0x90, 0x35, 0x6a, 0xf8, 0xfc, 0x50, 0xfc, 0xb4, 0x0f, 0x8f, 0x2e, 0xa5, 0xc8, 0x59, 0x47, 0x37, 0xa3, 0xb3, 0xd5, 0xab, 0xdb, 0xd7 },
+      { 0x11, 0x03, 0x0b, 0x92, 0x89, 0xbb, 0xa5, 0xaf, 0x65, 0x26, 0x06, 0x72, 0xab, 0x6f, 0xee, 0x88, 0xb8, 0x74, 0x20, 0xac, 0xef, 0x4a, 0x17, 0x89, 0xa2, 0x07, 0x3b, 0x7e, 0xc2, 0xf2, 0xa0, 0x9e },
+      { 0x69, 0xcb, 0x19, 0x2b, 0x84, 0x44, 0x00, 0x5c, 0x8c, 0x0c, 0xeb, 0x12, 0xc8, 0x46, 0x86, 0x07, 0x68, 0x18, 0x8c, 0xda, 0x0a, 0xec, 0x27, 0xa9, 0xc8, 0xa5, 0x5c, 0xde, 0xe2, 0x12, 0x36, 0x32 },
+      { 0xdb, 0x44, 0x4c, 0x15, 0x59, 0x7b, 0x5f, 0x1a, 0x03, 0xd1, 0xf9, 0xed, 0xd1, 0x6e, 0x4a, 0x9f, 0x43, 0xa6, 0x67, 0xcc, 0x27, 0x51, 0x75, 0xdf, 0xa2, 0xb7, 0x04, 0xe3, 0xbb, 0x1a, 0x9b, 0x83 },
+      { 0x3f, 0xb7, 0x35, 0x06, 0x1a, 0xbc, 0x51, 0x9d, 0xfe, 0x97, 0x9e, 0x54, 0xc1, 0xee, 0x5b, 0xfa, 0xd0, 0xa9, 0xd8, 0x58, 0xb3, 0x31, 0x5b, 0xad, 0x34, 0xbd, 0xe9, 0x99, 0xef, 0xd7, 0x24, 0xdd },
+   };
+   unsigned char inp[1000], out[1000];
+   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 };
+   unsigned long ilen, klen = sizeof(key), mlen = 32;
+   blake2smac_state st;
+
+   for (ilen = 0; ilen < 256; ilen++) inp[ilen] = (unsigned char)ilen;
+
+   for (ilen = 0; ilen < 256; ilen++) {
+      const unsigned char *mac = tests[ilen];
+      unsigned long olen = mlen;
+      /* process piece by piece */
+      if (ilen > 15) {
+        blake2smac_init(&st, olen, key, klen);
+        blake2smac_process(&st, (unsigned char*)inp,      5);
+        blake2smac_process(&st, (unsigned char*)inp + 5,  4);
+        blake2smac_process(&st, (unsigned char*)inp + 9,  3);
+        blake2smac_process(&st, (unsigned char*)inp + 12, 2);
+        blake2smac_process(&st, (unsigned char*)inp + 14, 1);
+        blake2smac_process(&st, (unsigned char*)inp + 15, ilen - 15);
+        blake2smac_done(&st, out, &olen);
+        if (compare_testvector(out, olen, mac, mlen, "BLAKE2S MAC multi", ilen) != 0) return CRYPT_FAIL_TESTVECTOR;
+      }
+      /* process in one go */
+      blake2smac_init(&st, olen, key, klen);
+      blake2smac_process(&st, (unsigned char*)inp, ilen);
+      blake2smac_done(&st, out, &olen);
+      if (compare_testvector(out, olen, mac, mlen, "BLAKE2S MAC single", ilen) != 0) return CRYPT_FAIL_TESTVECTOR;
+   }
+   return CRYPT_OK;
+#endif
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/mac/f9/f9_done.c b/libtomcrypt/src/mac/f9/f9_done.c
new file mode 100644 (file)
index 0000000..8d2ccb0
--- /dev/null
@@ -0,0 +1,75 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file f9_done.c
+  f9 Support, terminate the state
+*/
+
+#ifdef LTC_F9_MODE
+
+/** Terminate the f9-MAC state
+  @param f9     f9 state to terminate
+  @param out      [out] Destination for the MAC tag
+  @param outlen   [in/out] Destination size and final tag size
+  Return CRYPT_OK on success
+*/
+int f9_done(f9_state *f9, unsigned char *out, unsigned long *outlen)
+{
+   int err, x;
+   LTC_ARGCHK(f9 != NULL);
+   LTC_ARGCHK(out  != NULL);
+
+   /* check structure */
+   if ((err = cipher_is_valid(f9->cipher)) != CRYPT_OK) {
+      return err;
+   }
+
+   if ((f9->blocksize > cipher_descriptor[f9->cipher].block_length) || (f9->blocksize < 0) ||
+       (f9->buflen > f9->blocksize) || (f9->buflen < 0)) {
+      return CRYPT_INVALID_ARG;
+   }
+
+   if (f9->buflen != 0) {
+      /* encrypt */
+      cipher_descriptor[f9->cipher].ecb_encrypt(f9->IV, f9->IV, &f9->key);
+      f9->buflen = 0;
+      for (x = 0; x < f9->blocksize; x++) {
+         f9->ACC[x] ^= f9->IV[x];
+      }
+   }
+
+   /* schedule modified key */
+   if ((err = cipher_descriptor[f9->cipher].setup(f9->akey, f9->keylen, 0, &f9->key)) != CRYPT_OK) {
+      return err;
+   }
+
+   /* encrypt the ACC */
+   cipher_descriptor[f9->cipher].ecb_encrypt(f9->ACC, f9->ACC, &f9->key);
+   cipher_descriptor[f9->cipher].done(&f9->key);
+
+   /* extract tag */
+   for (x = 0; x < f9->blocksize && (unsigned long)x < *outlen; x++) {
+      out[x] = f9->ACC[x];
+   }
+   *outlen = x;
+
+#ifdef LTC_CLEAN_STACK
+   zeromem(f9, sizeof(*f9));
+#endif
+   return CRYPT_OK;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
+
diff --git a/libtomcrypt/src/mac/f9/f9_file.c b/libtomcrypt/src/mac/f9/f9_file.c
new file mode 100644 (file)
index 0000000..04d509b
--- /dev/null
@@ -0,0 +1,97 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file f9_file.c
+  f9 support, process a file, Tom St Denis
+*/
+
+#ifdef LTC_F9_MODE
+
+/**
+   f9 a file
+   @param cipher   The index of the cipher desired
+   @param key      The secret key
+   @param keylen   The length of the secret key (octets)
+   @param fname    The name of the file you wish to f9
+   @param out      [out] Where the authentication tag is to be stored
+   @param outlen   [in/out] The max size and resulting size of the authentication tag
+   @return CRYPT_OK if successful, CRYPT_NOP if file support has been disabled
+*/
+int f9_file(int cipher,
+              const unsigned char *key, unsigned long keylen,
+              const char *fname,
+                    unsigned char *out, unsigned long *outlen)
+{
+#ifdef LTC_NO_FILE
+   LTC_UNUSED_PARAM(cipher);
+   LTC_UNUSED_PARAM(key);
+   LTC_UNUSED_PARAM(keylen);
+   LTC_UNUSED_PARAM(fname);
+   LTC_UNUSED_PARAM(out);
+   LTC_UNUSED_PARAM(outlen);
+   return CRYPT_NOP;
+#else
+   size_t x;
+   int err;
+   f9_state f9;
+   FILE *in;
+   unsigned char *buf;
+
+   LTC_ARGCHK(key    != NULL);
+   LTC_ARGCHK(fname  != NULL);
+   LTC_ARGCHK(out    != NULL);
+   LTC_ARGCHK(outlen != NULL);
+
+   if ((buf = XMALLOC(LTC_FILE_READ_BUFSIZE)) == NULL) {
+      return CRYPT_MEM;
+   }
+
+   if ((err = f9_init(&f9, cipher, key, keylen)) != CRYPT_OK) {
+      goto LBL_ERR;
+   }
+
+   in = fopen(fname, "rb");
+   if (in == NULL) {
+      err = CRYPT_FILE_NOTFOUND;
+      goto LBL_ERR;
+   }
+
+   do {
+      x = fread(buf, 1, LTC_FILE_READ_BUFSIZE, in);
+      if ((err = f9_process(&f9, buf, (unsigned long)x)) != CRYPT_OK) {
+         fclose(in);
+         goto LBL_CLEANBUF;
+      }
+   } while (x == LTC_FILE_READ_BUFSIZE);
+
+   if (fclose(in) != 0) {
+      err = CRYPT_ERROR;
+      goto LBL_CLEANBUF;
+   }
+
+   err = f9_done(&f9, out, outlen);
+
+LBL_CLEANBUF:
+   zeromem(buf, LTC_FILE_READ_BUFSIZE);
+LBL_ERR:
+#ifdef LTC_CLEAN_STACK
+   zeromem(&f9, sizeof(f9_state));
+#endif
+   XFREE(buf);
+   return err;
+#endif
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/mac/f9/f9_init.c b/libtomcrypt/src/mac/f9/f9_init.c
new file mode 100644 (file)
index 0000000..ba59b20
--- /dev/null
@@ -0,0 +1,68 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file f9_init.c
+  F9 Support, start an F9 state
+*/
+
+#ifdef LTC_F9_MODE
+
+/** Initialize F9-MAC state
+  @param f9    [out] f9 state to initialize
+  @param cipher  Index of cipher to use
+  @param key     [in]  Secret key
+  @param keylen  Length of secret key in octets
+  Return CRYPT_OK on success
+*/
+int f9_init(f9_state *f9, int cipher, const unsigned char *key, unsigned long keylen)
+{
+   int            x, err;
+
+   LTC_ARGCHK(f9   != NULL);
+   LTC_ARGCHK(key  != NULL);
+
+   /* schedule the key */
+   if ((err = cipher_is_valid(cipher)) != CRYPT_OK) {
+      return err;
+   }
+
+#ifdef LTC_FAST
+   if (cipher_descriptor[cipher].block_length % sizeof(LTC_FAST_TYPE)) {
+       return CRYPT_INVALID_ARG;
+   }
+#endif
+
+   if ((err = cipher_descriptor[cipher].setup(key, keylen, 0, &f9->key)) != CRYPT_OK) {
+      goto done;
+   }
+
+   /* make the second key */
+   for (x = 0; (unsigned)x < keylen; x++) {
+      f9->akey[x] = key[x] ^ 0xAA;
+   }
+
+   /* setup struct */
+   zeromem(f9->IV,  cipher_descriptor[cipher].block_length);
+   zeromem(f9->ACC, cipher_descriptor[cipher].block_length);
+   f9->blocksize = cipher_descriptor[cipher].block_length;
+   f9->cipher    = cipher;
+   f9->buflen    = 0;
+   f9->keylen    = keylen;
+done:
+   return err;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
+
diff --git a/libtomcrypt/src/mac/f9/f9_memory.c b/libtomcrypt/src/mac/f9/f9_memory.c
new file mode 100644 (file)
index 0000000..70c694b
--- /dev/null
@@ -0,0 +1,69 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file f9_process.c
+  f9 Support, Process a block through F9-MAC
+*/
+
+#ifdef LTC_F9_MODE
+
+/** f9-MAC a block of memory
+  @param cipher     Index of cipher to use
+  @param key        [in]  Secret key
+  @param keylen     Length of key in octets
+  @param in         [in]  Message to MAC
+  @param inlen      Length of input in octets
+  @param out        [out] Destination for the MAC tag
+  @param outlen     [in/out] Output size and final tag size
+  Return CRYPT_OK on success.
+*/
+int f9_memory(int cipher,
+               const unsigned char *key, unsigned long keylen,
+               const unsigned char *in,  unsigned long inlen,
+                     unsigned char *out, unsigned long *outlen)
+{
+   f9_state *f9;
+   int         err;
+
+   /* is the cipher valid? */
+   if ((err = cipher_is_valid(cipher)) != CRYPT_OK) {
+      return err;
+   }
+
+   /* Use accelerator if found */
+   if (cipher_descriptor[cipher].f9_memory != NULL) {
+      return cipher_descriptor[cipher].f9_memory(key, keylen, in, inlen, out, outlen);
+   }
+
+   f9 = XCALLOC(1, sizeof(*f9));
+   if (f9 == NULL) {
+      return CRYPT_MEM;
+   }
+
+   if ((err = f9_init(f9, cipher, key, keylen)) != CRYPT_OK) {
+     goto done;
+   }
+
+   if ((err = f9_process(f9, in, inlen)) != CRYPT_OK) {
+     goto done;
+   }
+
+   err = f9_done(f9, out, outlen);
+done:
+   XFREE(f9);
+   return err;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/mac/f9/f9_memory_multi.c b/libtomcrypt/src/mac/f9/f9_memory_multi.c
new file mode 100644 (file)
index 0000000..2c1d31a
--- /dev/null
@@ -0,0 +1,88 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+#include <stdarg.h>
+
+/**
+  @file f9_memory_multi.c
+  f9 support, process multiple blocks of memory, Tom St Denis
+*/
+
+#ifdef LTC_F9_MODE
+
+/**
+   f9 multiple blocks of memory
+   @param cipher    The index of the desired cipher
+   @param key       The secret key
+   @param keylen    The length of the secret key (octets)
+   @param out       [out] The destination of the authentication tag
+   @param outlen    [in/out]  The max size and resulting size of the authentication tag (octets)
+   @param in        The data to send through f9
+   @param inlen     The length of the data to send through f9 (octets)
+   @param ...       tuples of (data,len) pairs to f9, terminated with a (NULL,x) (x=don't care)
+   @return CRYPT_OK if successful
+*/
+int f9_memory_multi(int cipher,
+                const unsigned char *key, unsigned long keylen,
+                      unsigned char *out, unsigned long *outlen,
+                const unsigned char *in,  unsigned long inlen, ...)
+{
+   int                  err;
+   f9_state          *f9;
+   va_list              args;
+   const unsigned char *curptr;
+   unsigned long        curlen;
+
+   LTC_ARGCHK(key    != NULL);
+   LTC_ARGCHK(in     != NULL);
+   LTC_ARGCHK(out    != NULL);
+   LTC_ARGCHK(outlen != NULL);
+
+   /* allocate ram for f9 state */
+   f9 = XMALLOC(sizeof(f9_state));
+   if (f9 == NULL) {
+      return CRYPT_MEM;
+   }
+
+   /* f9 process the message */
+   if ((err = f9_init(f9, cipher, key, keylen)) != CRYPT_OK) {
+      goto LBL_ERR;
+   }
+   va_start(args, inlen);
+   curptr = in;
+   curlen = inlen;
+   for (;;) {
+      /* process buf */
+      if ((err = f9_process(f9, curptr, curlen)) != CRYPT_OK) {
+         goto LBL_ERR;
+      }
+      /* step to next */
+      curptr = va_arg(args, const unsigned char*);
+      if (curptr == NULL) {
+         break;
+      }
+      curlen = va_arg(args, unsigned long);
+   }
+   if ((err = f9_done(f9, out, outlen)) != CRYPT_OK) {
+      goto LBL_ERR;
+   }
+LBL_ERR:
+#ifdef LTC_CLEAN_STACK
+   zeromem(f9, sizeof(f9_state));
+#endif
+   XFREE(f9);
+   va_end(args);
+   return err;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/mac/f9/f9_process.c b/libtomcrypt/src/mac/f9/f9_process.c
new file mode 100644 (file)
index 0000000..ba4d39f
--- /dev/null
@@ -0,0 +1,76 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file f9_process.c
+  f9 Support, process blocks with f9
+*/
+
+#ifdef LTC_F9_MODE
+
+/** Process data through f9-MAC
+  @param f9       The f9-MAC state
+  @param in       Input data to process
+  @param inlen    Length of input in octets
+  Return CRYPT_OK on success
+*/
+int f9_process(f9_state *f9, const unsigned char *in, unsigned long inlen)
+{
+   int err, x;
+
+   LTC_ARGCHK(f9 != NULL);
+   LTC_ARGCHK(in   != NULL);
+
+   /* check structure */
+   if ((err = cipher_is_valid(f9->cipher)) != CRYPT_OK) {
+      return err;
+   }
+
+   if ((f9->blocksize > cipher_descriptor[f9->cipher].block_length) || (f9->blocksize < 0) ||
+       (f9->buflen > f9->blocksize) || (f9->buflen < 0)) {
+      return CRYPT_INVALID_ARG;
+   }
+
+#ifdef LTC_FAST
+   if (f9->buflen == 0) {
+       while (inlen >= (unsigned long)f9->blocksize) {
+           for (x = 0; x < f9->blocksize; x += sizeof(LTC_FAST_TYPE)) {
+              *(LTC_FAST_TYPE_PTR_CAST(&(f9->IV[x]))) ^= *(LTC_FAST_TYPE_PTR_CAST(&(in[x])));
+           }
+           cipher_descriptor[f9->cipher].ecb_encrypt(f9->IV, f9->IV, &f9->key);
+           for (x = 0; x < f9->blocksize; x += sizeof(LTC_FAST_TYPE)) {
+              *(LTC_FAST_TYPE_PTR_CAST(&(f9->ACC[x]))) ^= *(LTC_FAST_TYPE_PTR_CAST(&(f9->IV[x])));
+           }
+           in    += f9->blocksize;
+           inlen -= f9->blocksize;
+       }
+   }
+#endif
+
+   while (inlen) {
+      if (f9->buflen == f9->blocksize) {
+         cipher_descriptor[f9->cipher].ecb_encrypt(f9->IV, f9->IV, &f9->key);
+         for (x = 0; x < f9->blocksize; x++) {
+            f9->ACC[x] ^= f9->IV[x];
+         }
+         f9->buflen = 0;
+      }
+      f9->IV[f9->buflen++] ^= *in++;
+      --inlen;
+   }
+   return CRYPT_OK;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
+
diff --git a/libtomcrypt/src/mac/f9/f9_test.c b/libtomcrypt/src/mac/f9/f9_test.c
new file mode 100644 (file)
index 0000000..ca23acc
--- /dev/null
@@ -0,0 +1,76 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file f9_test.c
+  f9 Support, Test F9 mode
+*/
+
+#ifdef LTC_F9_MODE
+
+/** Test f9-MAC mode
+  Return CRYPT_OK on succes
+*/
+int f9_test(void)
+{
+#ifdef LTC_NO_TEST
+   return CRYPT_NOP;
+#else
+   static const struct {
+       int msglen;
+       unsigned char K[16], M[128], T[4];
+   } tests[] = {
+{
+   20,
+   { 0x2B, 0xD6, 0x45, 0x9F, 0x82, 0xC5, 0xB3, 0x00, 0x95, 0x2C, 0x49, 0x10, 0x48, 0x81, 0xFF, 0x48 },
+   { 0x38, 0xA6, 0xF0, 0x56, 0xB8, 0xAE, 0xFD, 0xA9, 0x33, 0x32, 0x34, 0x62, 0x63, 0x39, 0x38, 0x61, 0x37, 0x34, 0x79, 0x40 },
+   { 0x46, 0xE0, 0x0D, 0x4B }
+},
+
+{
+   105,
+   { 0x83, 0xFD, 0x23, 0xA2, 0x44, 0xA7, 0x4C, 0xF3, 0x58, 0xDA, 0x30, 0x19, 0xF1, 0x72, 0x26, 0x35 },
+   { 0x36, 0xAF, 0x61, 0x44, 0x4F, 0x30, 0x2A, 0xD2,
+     0x35, 0xC6, 0x87, 0x16, 0x63, 0x3C, 0x66, 0xFB, 0x75, 0x0C, 0x26, 0x68, 0x65, 0xD5, 0x3C, 0x11, 0xEA, 0x05, 0xB1, 0xE9, 0xFA, 0x49, 0xC8, 0x39, 0x8D, 0x48, 0xE1, 0xEF, 0xA5, 0x90, 0x9D, 0x39,
+     0x47, 0x90, 0x28, 0x37, 0xF5, 0xAE, 0x96, 0xD5, 0xA0, 0x5B, 0xC8, 0xD6, 0x1C, 0xA8, 0xDB, 0xEF, 0x1B, 0x13, 0xA4, 0xB4, 0xAB, 0xFE, 0x4F, 0xB1, 0x00, 0x60, 0x45, 0xB6, 0x74, 0xBB, 0x54, 0x72,
+     0x93, 0x04, 0xC3, 0x82, 0xBE, 0x53, 0xA5, 0xAF, 0x05, 0x55, 0x61, 0x76, 0xF6, 0xEA, 0xA2, 0xEF, 0x1D, 0x05, 0xE4, 0xB0, 0x83, 0x18, 0x1E, 0xE6, 0x74, 0xCD, 0xA5, 0xA4, 0x85, 0xF7, 0x4D, 0x7A,
+     0x40|0x80 },
+   { 0x95, 0xAE, 0x41, 0xBA },
+}
+};
+  unsigned char T[16];
+  unsigned long taglen;
+  int err, x, idx;
+
+  /* find kasumi */
+  if ((idx = find_cipher("kasumi")) == -1) {
+     return CRYPT_NOP;
+  }
+
+  for (x = 0; x < (int)(sizeof(tests)/sizeof(tests[0])); x++) {
+     taglen = 4;
+     if ((err = f9_memory(idx, tests[x].K, 16, tests[x].M, tests[x].msglen, T, &taglen)) != CRYPT_OK) {
+        return err;
+     }
+     if (compare_testvector(T, taglen, tests[x].T, 4, "F9", x)) {
+        return CRYPT_FAIL_TESTVECTOR;
+     }
+  }
+
+  return CRYPT_OK;
+#endif
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
+
diff --git a/libtomcrypt/src/mac/hmac/hmac_done.c b/libtomcrypt/src/mac/hmac/hmac_done.c
new file mode 100644 (file)
index 0000000..8a9b69b
--- /dev/null
@@ -0,0 +1,107 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file hmac_done.c
+  HMAC support, terminate stream, Tom St Denis/Dobes Vandermeer
+*/
+
+#ifdef LTC_HMAC
+
+#define LTC_HMAC_BLOCKSIZE hash_descriptor[hash].blocksize
+
+/**
+   Terminate an HMAC session
+   @param hmac    The HMAC state
+   @param out     [out] The destination of the HMAC authentication tag
+   @param outlen  [in/out]  The max size and resulting size of the HMAC authentication tag
+   @return CRYPT_OK if successful
+*/
+int hmac_done(hmac_state *hmac, unsigned char *out, unsigned long *outlen)
+{
+    unsigned char *buf, *isha;
+    unsigned long hashsize, i;
+    int hash, err;
+
+    LTC_ARGCHK(hmac  != NULL);
+    LTC_ARGCHK(out   != NULL);
+
+    /* test hash */
+    hash = hmac->hash;
+    if((err = hash_is_valid(hash)) != CRYPT_OK) {
+        return err;
+    }
+
+    /* get the hash message digest size */
+    hashsize = hash_descriptor[hash].hashsize;
+
+    /* allocate buffers */
+    buf  = XMALLOC(LTC_HMAC_BLOCKSIZE);
+    isha = XMALLOC(hashsize);
+    if (buf == NULL || isha == NULL) {
+       if (buf != NULL) {
+          XFREE(buf);
+       }
+       if (isha != NULL) {
+          XFREE(isha);
+       }
+       return CRYPT_MEM;
+    }
+
+    /* Get the hash of the first HMAC vector plus the data */
+    if ((err = hash_descriptor[hash].done(&hmac->md, isha)) != CRYPT_OK) {
+       goto LBL_ERR;
+    }
+
+    /* Create the second HMAC vector vector for step (3) */
+    for(i=0; i < LTC_HMAC_BLOCKSIZE; i++) {
+        buf[i] = hmac->key[i] ^ 0x5C;
+    }
+
+    /* Now calculate the "outer" hash for step (5), (6), and (7) */
+    if ((err = hash_descriptor[hash].init(&hmac->md)) != CRYPT_OK) {
+       goto LBL_ERR;
+    }
+    if ((err = hash_descriptor[hash].process(&hmac->md, buf, LTC_HMAC_BLOCKSIZE)) != CRYPT_OK) {
+       goto LBL_ERR;
+    }
+    if ((err = hash_descriptor[hash].process(&hmac->md, isha, hashsize)) != CRYPT_OK) {
+       goto LBL_ERR;
+    }
+    if ((err = hash_descriptor[hash].done(&hmac->md, buf)) != CRYPT_OK) {
+       goto LBL_ERR;
+    }
+
+    /* copy to output  */
+    for (i = 0; i < hashsize && i < *outlen; i++) {
+        out[i] = buf[i];
+    }
+    *outlen = i;
+
+    err = CRYPT_OK;
+LBL_ERR:
+    XFREE(hmac->key);
+#ifdef LTC_CLEAN_STACK
+    zeromem(isha, hashsize);
+    zeromem(buf,  hashsize);
+    zeromem(hmac, sizeof(*hmac));
+#endif
+
+    XFREE(isha);
+    XFREE(buf);
+
+    return err;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/mac/hmac/hmac_file.c b/libtomcrypt/src/mac/hmac/hmac_file.c
new file mode 100644 (file)
index 0000000..0e1a163
--- /dev/null
@@ -0,0 +1,100 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file hmac_file.c
+  HMAC support, process a file, Tom St Denis/Dobes Vandermeer
+*/
+
+#ifdef LTC_HMAC
+
+/**
+  HMAC a file
+  @param hash     The index of the hash you wish to use
+  @param fname    The name of the file you wish to HMAC
+  @param key      The secret key
+  @param keylen   The length of the secret key
+  @param out      [out] The HMAC authentication tag
+  @param outlen   [in/out]  The max size and resulting size of the authentication tag
+  @return CRYPT_OK if successful, CRYPT_NOP if file support has been disabled
+*/
+int hmac_file(int hash, const char *fname,
+              const unsigned char *key, unsigned long keylen,
+                    unsigned char *out, unsigned long *outlen)
+{
+#ifdef LTC_NO_FILE
+   LTC_UNUSED_PARAM(hash);
+   LTC_UNUSED_PARAM(fname);
+   LTC_UNUSED_PARAM(key);
+   LTC_UNUSED_PARAM(keylen);
+   LTC_UNUSED_PARAM(out);
+   LTC_UNUSED_PARAM(outlen);
+    return CRYPT_NOP;
+#else
+   hmac_state hmac;
+   FILE *in;
+   unsigned char *buf;
+   size_t x;
+   int err;
+
+   LTC_ARGCHK(fname  != NULL);
+   LTC_ARGCHK(key    != NULL);
+   LTC_ARGCHK(out    != NULL);
+   LTC_ARGCHK(outlen != NULL);
+
+   if ((buf = XMALLOC(LTC_FILE_READ_BUFSIZE)) == NULL) {
+      return CRYPT_MEM;
+   }
+
+   if ((err = hash_is_valid(hash)) != CRYPT_OK) {
+      goto LBL_ERR;
+   }
+
+   if ((err = hmac_init(&hmac, hash, key, keylen)) != CRYPT_OK) {
+      goto LBL_ERR;
+   }
+
+   in = fopen(fname, "rb");
+   if (in == NULL) {
+      err = CRYPT_FILE_NOTFOUND;
+      goto LBL_ERR;
+   }
+
+   do {
+      x = fread(buf, 1, LTC_FILE_READ_BUFSIZE, in);
+      if ((err = hmac_process(&hmac, buf, (unsigned long)x)) != CRYPT_OK) {
+         fclose(in); /* we don't trap this error since we're already returning an error! */
+         goto LBL_CLEANBUF;
+      }
+   } while (x == LTC_FILE_READ_BUFSIZE);
+
+   if (fclose(in) != 0) {
+      err = CRYPT_ERROR;
+      goto LBL_CLEANBUF;
+   }
+
+   err = hmac_done(&hmac, out, outlen);
+
+LBL_CLEANBUF:
+   zeromem(buf, LTC_FILE_READ_BUFSIZE);
+LBL_ERR:
+#ifdef LTC_CLEAN_STACK
+   zeromem(&hmac, sizeof(hmac_state));
+#endif
+   XFREE(buf);
+   return err;
+#endif
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/mac/hmac/hmac_init.c b/libtomcrypt/src/mac/hmac/hmac_init.c
new file mode 100644 (file)
index 0000000..6b6505e
--- /dev/null
@@ -0,0 +1,108 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file hmac_init.c
+  HMAC support, initialize state, Tom St Denis/Dobes Vandermeer
+*/
+
+#ifdef LTC_HMAC
+
+#define LTC_HMAC_BLOCKSIZE hash_descriptor[hash].blocksize
+
+/**
+   Initialize an HMAC context.
+   @param hmac     The HMAC state
+   @param hash     The index of the hash you want to use
+   @param key      The secret key
+   @param keylen   The length of the secret key (octets)
+   @return CRYPT_OK if successful
+*/
+int hmac_init(hmac_state *hmac, int hash, const unsigned char *key, unsigned long keylen)
+{
+    unsigned char *buf;
+    unsigned long hashsize;
+    unsigned long i, z;
+    int err;
+
+    LTC_ARGCHK(hmac != NULL);
+    LTC_ARGCHK(key  != NULL);
+
+    /* valid hash? */
+    if ((err = hash_is_valid(hash)) != CRYPT_OK) {
+        return err;
+    }
+    hmac->hash = hash;
+    hashsize   = hash_descriptor[hash].hashsize;
+
+    /* valid key length? */
+    if (keylen == 0) {
+        return CRYPT_INVALID_KEYSIZE;
+    }
+
+    /* allocate ram for buf */
+    buf = XMALLOC(LTC_HMAC_BLOCKSIZE);
+    if (buf == NULL) {
+       return CRYPT_MEM;
+    }
+
+    /* allocate memory for key */
+    hmac->key = XMALLOC(LTC_HMAC_BLOCKSIZE);
+    if (hmac->key == NULL) {
+       XFREE(buf);
+       return CRYPT_MEM;
+    }
+
+    /* (1) make sure we have a large enough key */
+    if(keylen > LTC_HMAC_BLOCKSIZE) {
+        z = LTC_HMAC_BLOCKSIZE;
+        if ((err = hash_memory(hash, key, keylen, hmac->key, &z)) != CRYPT_OK) {
+           goto LBL_ERR;
+        }
+        keylen = hashsize;
+    } else {
+        XMEMCPY(hmac->key, key, (size_t)keylen);
+    }
+
+    if(keylen < LTC_HMAC_BLOCKSIZE) {
+       zeromem((hmac->key) + keylen, (size_t)(LTC_HMAC_BLOCKSIZE - keylen));
+    }
+
+    /* Create the initialization vector for step (3) */
+    for(i=0; i < LTC_HMAC_BLOCKSIZE;   i++) {
+       buf[i] = hmac->key[i] ^ 0x36;
+    }
+
+    /* Pre-pend that to the hash data */
+    if ((err = hash_descriptor[hash].init(&hmac->md)) != CRYPT_OK) {
+       goto LBL_ERR;
+    }
+
+    if ((err = hash_descriptor[hash].process(&hmac->md, buf, LTC_HMAC_BLOCKSIZE)) != CRYPT_OK) {
+       goto LBL_ERR;
+    }
+    goto done;
+LBL_ERR:
+    /* free the key since we failed */
+    XFREE(hmac->key);
+done:
+#ifdef LTC_CLEAN_STACK
+   zeromem(buf, LTC_HMAC_BLOCKSIZE);
+#endif
+
+   XFREE(buf);
+   return err;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/mac/hmac/hmac_memory.c b/libtomcrypt/src/mac/hmac/hmac_memory.c
new file mode 100644 (file)
index 0000000..9a3a199
--- /dev/null
@@ -0,0 +1,86 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file hmac_memory.c
+  HMAC support, process a block of memory, Tom St Denis/Dobes Vandermeer
+*/
+
+#ifdef LTC_HMAC
+
+/**
+   HMAC a block of memory to produce the authentication tag
+   @param hash      The index of the hash to use
+   @param key       The secret key
+   @param keylen    The length of the secret key (octets)
+   @param in        The data to HMAC
+   @param inlen     The length of the data to HMAC (octets)
+   @param out       [out] Destination of the authentication tag
+   @param outlen    [in/out] Max size and resulting size of authentication tag
+   @return CRYPT_OK if successful
+*/
+int hmac_memory(int hash,
+                const unsigned char *key,  unsigned long keylen,
+                const unsigned char *in,   unsigned long inlen,
+                      unsigned char *out,  unsigned long *outlen)
+{
+    hmac_state *hmac;
+    int         err;
+
+    LTC_ARGCHK(key    != NULL);
+    LTC_ARGCHK(in     != NULL);
+    LTC_ARGCHK(out    != NULL);
+    LTC_ARGCHK(outlen != NULL);
+
+    /* make sure hash descriptor is valid */
+    if ((err = hash_is_valid(hash)) != CRYPT_OK) {
+       return err;
+    }
+
+    /* is there a descriptor? */
+    if (hash_descriptor[hash].hmac_block != NULL) {
+        return hash_descriptor[hash].hmac_block(key, keylen, in, inlen, out, outlen);
+    }
+
+    /* nope, so call the hmac functions */
+    /* allocate ram for hmac state */
+    hmac = XMALLOC(sizeof(hmac_state));
+    if (hmac == NULL) {
+       return CRYPT_MEM;
+    }
+
+    if ((err = hmac_init(hmac, hash, key, keylen)) != CRYPT_OK) {
+       goto LBL_ERR;
+    }
+
+    if ((err = hmac_process(hmac, in, inlen)) != CRYPT_OK) {
+       goto LBL_ERR;
+    }
+
+    if ((err = hmac_done(hmac, out, outlen)) != CRYPT_OK) {
+       goto LBL_ERR;
+    }
+
+   err = CRYPT_OK;
+LBL_ERR:
+#ifdef LTC_CLEAN_STACK
+   zeromem(hmac, sizeof(hmac_state));
+#endif
+
+   XFREE(hmac);
+   return err;
+}
+
+#endif
+
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/mac/hmac/hmac_memory_multi.c b/libtomcrypt/src/mac/hmac/hmac_memory_multi.c
new file mode 100644 (file)
index 0000000..6e3d0fe
--- /dev/null
@@ -0,0 +1,90 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+#include <stdarg.h>
+
+/**
+  @file hmac_memory_multi.c
+  HMAC support, process multiple blocks of memory, Tom St Denis/Dobes Vandermeer
+*/
+
+#ifdef LTC_HMAC
+
+/**
+   HMAC multiple blocks of memory to produce the authentication tag
+   @param hash      The index of the hash to use
+   @param key       The secret key
+   @param keylen    The length of the secret key (octets)
+   @param out       [out] Destination of the authentication tag
+   @param outlen    [in/out] Max size and resulting size of authentication tag
+   @param in        The data to HMAC
+   @param inlen     The length of the data to HMAC (octets)
+   @param ...       tuples of (data,len) pairs to HMAC, terminated with a (NULL,x) (x=don't care)
+   @return CRYPT_OK if successful
+*/
+int hmac_memory_multi(int hash,
+                const unsigned char *key,  unsigned long keylen,
+                      unsigned char *out,  unsigned long *outlen,
+                const unsigned char *in,   unsigned long inlen, ...)
+
+{
+    hmac_state          *hmac;
+    int                  err;
+    va_list              args;
+    const unsigned char *curptr;
+    unsigned long        curlen;
+
+    LTC_ARGCHK(key    != NULL);
+    LTC_ARGCHK(in     != NULL);
+    LTC_ARGCHK(out    != NULL);
+    LTC_ARGCHK(outlen != NULL);
+
+    /* allocate ram for hmac state */
+    hmac = XMALLOC(sizeof(hmac_state));
+    if (hmac == NULL) {
+       return CRYPT_MEM;
+    }
+
+    if ((err = hmac_init(hmac, hash, key, keylen)) != CRYPT_OK) {
+       goto LBL_ERR;
+    }
+
+    va_start(args, inlen);
+    curptr = in;
+    curlen = inlen;
+    for (;;) {
+       /* process buf */
+       if ((err = hmac_process(hmac, curptr, curlen)) != CRYPT_OK) {
+          goto LBL_ERR;
+       }
+       /* step to next */
+       curptr = va_arg(args, const unsigned char*);
+       if (curptr == NULL) {
+          break;
+       }
+       curlen = va_arg(args, unsigned long);
+    }
+    if ((err = hmac_done(hmac, out, outlen)) != CRYPT_OK) {
+       goto LBL_ERR;
+    }
+LBL_ERR:
+#ifdef LTC_CLEAN_STACK
+   zeromem(hmac, sizeof(hmac_state));
+#endif
+   XFREE(hmac);
+   va_end(args);
+   return err;
+}
+
+#endif
+
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/mac/hmac/hmac_process.c b/libtomcrypt/src/mac/hmac/hmac_process.c
new file mode 100644 (file)
index 0000000..8da62c1
--- /dev/null
@@ -0,0 +1,41 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file hmac_process.c
+  HMAC support, process data, Tom St Denis/Dobes Vandermeer
+*/
+
+#ifdef LTC_HMAC
+
+/**
+  Process data through HMAC
+  @param hmac    The hmac state
+  @param in      The data to send through HMAC
+  @param inlen   The length of the data to HMAC (octets)
+  @return CRYPT_OK if successful
+*/
+int hmac_process(hmac_state *hmac, const unsigned char *in, unsigned long inlen)
+{
+    int err;
+    LTC_ARGCHK(hmac != NULL);
+    LTC_ARGCHK(in != NULL);
+    if ((err = hash_is_valid(hmac->hash)) != CRYPT_OK) {
+        return err;
+    }
+    return hash_descriptor[hmac->hash].process(&hmac->md, in, inlen);
+}
+
+#endif
+
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/mac/hmac/hmac_test.c b/libtomcrypt/src/mac/hmac/hmac_test.c
new file mode 100644 (file)
index 0000000..1570a76
--- /dev/null
@@ -0,0 +1,630 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file hmac_test.c
+  HMAC support, self-test, Tom St Denis/Dobes Vandermeer/Steffen Jaeckel
+*/
+
+#ifdef LTC_HMAC
+
+#define LTC_HMAC_BLOCKSIZE hash_descriptor[hash].blocksize
+
+/*
+    TEST CASES SOURCE:
+
+Network Working Group                                          P. Cheng
+Request for Comments: 2202                                          IBM
+Category: Informational                                        R. Glenn
+                                                                   NIST
+                                                         September 1997
+
+                 Test Cases for HMAC-MD5 and HMAC-SHA-1
+
+*******************************************************************************
+
+Network Working Group                                            J. Kapp
+Request for Comments: 2286                           Reaper Technologies
+Category: Informational                                    February 1998
+
+            Test Cases for HMAC-RIPEMD160 and HMAC-RIPEMD128
+
+*******************************************************************************
+
+Network Working Group                                         M. Nystrom
+Request for Comments: 4231                                  RSA Security
+Category: Standards Track                                  December 2005
+
+     Identifiers and Test Vectors for HMAC-SHA-224, HMAC-SHA-256,
+                     HMAC-SHA-384, and HMAC-SHA-512
+*/
+
+/**
+  HMAC self-test
+  @return CRYPT_OK if successful, CRYPT_NOP if tests have been disabled.
+*/
+int hmac_test(void)
+{
+ #ifndef LTC_TEST
+    return CRYPT_NOP;
+ #else
+    unsigned char digest[MAXBLOCKSIZE];
+    int i;
+
+    static const unsigned char hmac_test_case_keys[][136] = {
+        { /* 1 */
+            0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+            0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+            0x0b, 0x0b, 0x0b, 0x0b
+        },
+#ifdef LTC_TEST_EXT
+        { /* 2 */
+            0x4a, 0x65, 0x66, 0x65
+        },
+        { /* 4 */
+            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
+        },
+        { /* 5 */
+            0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+            0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+            0x0c, 0x0c, 0x0c, 0x0c
+        },
+        { /* 3, 6, 7 */
+            0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+            0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+            0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+            0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+            0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+
+            0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+            0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+            0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+            0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+            0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+
+            0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+            0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+            0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+            0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+            0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+
+            0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+            0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa
+        }
+#endif /* LTC_TEST_EXT */
+    };
+
+
+    static const unsigned char hmac_test_case_data[][153] = {
+        {
+            "Hi There"
+        },
+#ifdef LTC_TEST_EXT
+        {
+            "what do ya want for nothing?"
+        },
+        {
+            0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+            0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+            0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+            0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+            0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd
+        },
+        {
+            0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+            0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+            0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+            0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+            0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd
+        },
+        {
+            "Test With Truncation"
+        },
+        {
+            "Test Using Larger Than Block-Size Key - Hash Key First"
+        },
+        {
+            "Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data"
+        },
+        {
+            "This is a test using a larger than block-size key and a larger than block-size data. The key needs to be hashed before being used by the HMAC algorithm."
+        }
+#endif /* LTC_TEST_EXT */
+    };
+
+    static const struct hmac_test_case {
+        const char *num;
+        const char *algo;
+        const unsigned char *key;
+        unsigned long keylen;
+        const unsigned char *data;
+        unsigned long datalen;
+        unsigned char digest[MAXBLOCKSIZE];
+    } cases[] = {
+        /*
+        RFC 2202 3. Test Cases for HMAC-SHA-1
+        */
+        { "rfc2202 3.1", "sha1",
+            hmac_test_case_keys[0], 20,
+            hmac_test_case_data[0], 8,
+            {0xb6, 0x17, 0x31, 0x86, 0x55, 0x05, 0x72, 0x64,
+             0xe2, 0x8b, 0xc0, 0xb6, 0xfb, 0x37, 0x8c, 0x8e,
+             0xf1, 0x46, 0xbe, 0x00} },
+
+#ifdef LTC_TEST_EXT
+        { "rfc2202 3.2", "sha1",
+            hmac_test_case_keys[1], 4,
+            hmac_test_case_data[1], 28,
+            {0xef, 0xfc, 0xdf, 0x6a, 0xe5, 0xeb, 0x2f, 0xa2,
+             0xd2, 0x74, 0x16, 0xd5, 0xf1, 0x84, 0xdf, 0x9c,
+             0x25, 0x9a, 0x7c, 0x79} },
+
+        { "rfc2202 3.3", "sha1",
+            hmac_test_case_keys[4], 20,
+            hmac_test_case_data[2], 50,
+            {0x12, 0x5d, 0x73, 0x42, 0xb9, 0xac, 0x11, 0xcd,
+             0x91, 0xa3, 0x9a, 0xf4, 0x8a, 0xa1, 0x7b, 0x4f,
+             0x63, 0xf1, 0x75, 0xd3} },
+
+        { "rfc2202 3.4", "sha1",
+            hmac_test_case_keys[2], 25,
+            hmac_test_case_data[3], 50,
+            {0x4c, 0x90, 0x07, 0xf4, 0x02, 0x62, 0x50, 0xc6,
+             0xbc, 0x84, 0x14, 0xf9, 0xbf, 0x50, 0xc8, 0x6c,
+             0x2d, 0x72, 0x35, 0xda} },
+
+        { "rfc2202 3.5", "sha1",
+            hmac_test_case_keys[3], 20,
+            hmac_test_case_data[4], 20,
+            {0x4c, 0x1a, 0x03, 0x42, 0x4b, 0x55, 0xe0, 0x7f, 0xe7, 0xf2,
+             0x7b, 0xe1, 0xd5, 0x8b, 0xb9, 0x32, 0x4a, 0x9a, 0x5a, 0x04} },
+
+        { "rfc2202 3.6", "sha1",
+            hmac_test_case_keys[4], 80,
+            hmac_test_case_data[5], 54,
+            {0xaa, 0x4a, 0xe5, 0xe1, 0x52, 0x72, 0xd0, 0x0e,
+             0x95, 0x70, 0x56, 0x37, 0xce, 0x8a, 0x3b, 0x55,
+             0xed, 0x40, 0x21, 0x12} },
+
+        { "rfc2202 3.7", "sha1",
+            hmac_test_case_keys[4], 80,
+           hmac_test_case_data[6], 73,
+            {0xe8, 0xe9, 0x9d, 0x0f, 0x45, 0x23, 0x7d, 0x78, 0x6d,
+             0x6b, 0xba, 0xa7, 0x96, 0x5c, 0x78, 0x08, 0xbb, 0xff, 0x1a, 0x91} },
+#endif /* LTC_TEST_EXT */
+
+        /*
+        RFC 2202 2. Test Cases for HMAC-MD5
+        */
+        { "rfc2202 2.1", "md5",
+            hmac_test_case_keys[0], 16,
+            hmac_test_case_data[0], 8,
+            {0x92, 0x94, 0x72, 0x7a, 0x36, 0x38, 0xbb, 0x1c,
+             0x13, 0xf4, 0x8e, 0xf8, 0x15, 0x8b, 0xfc, 0x9d}  },
+
+#ifdef LTC_TEST_EXT
+        { "rfc2202 2.2", "md5",
+            hmac_test_case_keys[1], 4,
+            hmac_test_case_data[1], 28,
+            {0x75, 0x0c, 0x78, 0x3e, 0x6a, 0xb0, 0xb5, 0x03,
+             0xea, 0xa8, 0x6e, 0x31, 0x0a, 0x5d, 0xb7, 0x38} },
+
+        { "rfc2202 2.3", "md5",
+            hmac_test_case_keys[4], 16,
+            hmac_test_case_data[2], 50,
+            {0x56, 0xbe, 0x34, 0x52, 0x1d, 0x14, 0x4c, 0x88,
+             0xdb, 0xb8, 0xc7, 0x33, 0xf0, 0xe8, 0xb3, 0xf6} },
+
+        { "rfc2202 2.4", "md5",
+            hmac_test_case_keys[2], 25,
+            hmac_test_case_data[3], 50,
+            {0x69, 0x7e, 0xaf, 0x0a, 0xca, 0x3a, 0x3a, 0xea,
+             0x3a, 0x75, 0x16, 0x47, 0x46, 0xff, 0xaa, 0x79} },
+
+        { "rfc2202 2.5", "md5",
+            hmac_test_case_keys[3], 16,
+            hmac_test_case_data[4], 20,
+            {0x56, 0x46, 0x1e, 0xf2, 0x34, 0x2e, 0xdc, 0x00,
+             0xf9, 0xba, 0xb9, 0x95, 0x69, 0x0e, 0xfd, 0x4c} },
+
+        { "rfc2202 2.6", "md5",
+            hmac_test_case_keys[4], 80,
+            hmac_test_case_data[5], 54,
+            {0x6b, 0x1a, 0xb7, 0xfe, 0x4b, 0xd7, 0xbf, 0x8f,
+             0x0b, 0x62, 0xe6, 0xce, 0x61, 0xb9, 0xd0, 0xcd} },
+
+        { "rfc2202 2.7", "md5",
+            hmac_test_case_keys[4], 80,
+           hmac_test_case_data[6], 73,
+            {0x6f, 0x63, 0x0f, 0xad, 0x67, 0xcd, 0xa0, 0xee,
+             0x1f, 0xb1, 0xf5, 0x62, 0xdb, 0x3a, 0xa5, 0x3e} },
+#endif /* LTC_TEST_EXT */
+
+        /*
+        RFC 2286 2. Test Cases for HMAC-RIPEMD160
+        */
+        { "rfc2286 2.1", "rmd160",
+            hmac_test_case_keys[0], 20,
+            hmac_test_case_data[0], 8,
+            {0x24, 0xcb, 0x4b, 0xd6, 0x7d, 0x20, 0xfc, 0x1a,
+             0x5d, 0x2e, 0xd7, 0x73, 0x2d, 0xcc, 0x39, 0x37,
+             0x7f, 0x0a, 0x56, 0x68} },
+
+#ifdef LTC_TEST_EXT
+        { "rfc2286 2.2", "rmd160",
+            hmac_test_case_keys[1], 4,
+            hmac_test_case_data[1], 28,
+            {0xdd, 0xa6, 0xc0, 0x21, 0x3a, 0x48, 0x5a, 0x9e,
+             0x24, 0xf4, 0x74, 0x20, 0x64, 0xa7, 0xf0, 0x33,
+             0xb4, 0x3c, 0x40, 0x69} },
+
+        { "rfc2286 2.3", "rmd160",
+            hmac_test_case_keys[4], 20,
+            hmac_test_case_data[2], 50,
+            {0xb0, 0xb1, 0x05, 0x36, 0x0d, 0xe7, 0x59, 0x96,
+             0x0a, 0xb4, 0xf3, 0x52, 0x98, 0xe1, 0x16, 0xe2,
+             0x95, 0xd8, 0xe7, 0xc1} },
+
+        { "rfc2286 2.4", "rmd160",
+            hmac_test_case_keys[2], 25,
+            hmac_test_case_data[3], 50,
+            {0xd5, 0xca, 0x86, 0x2f, 0x4d, 0x21, 0xd5, 0xe6,
+             0x10, 0xe1, 0x8b, 0x4c, 0xf1, 0xbe, 0xb9, 0x7a,
+             0x43, 0x65, 0xec, 0xf4} },
+
+        { "rfc2286 2.5", "rmd160",
+            hmac_test_case_keys[3], 20,
+            hmac_test_case_data[4], 20,
+            {0x76, 0x19, 0x69, 0x39, 0x78, 0xf9, 0x1d, 0x90,
+             0x53, 0x9a, 0xe7, 0x86, 0x50, 0x0f, 0xf3, 0xd8,
+             0xe0, 0x51, 0x8e, 0x39} },
+
+        { "rfc2286 2.6", "rmd160",
+            hmac_test_case_keys[4], 80,
+            hmac_test_case_data[5], 54,
+            {0x64, 0x66, 0xca, 0x07, 0xac, 0x5e, 0xac, 0x29,
+             0xe1, 0xbd, 0x52, 0x3e, 0x5a, 0xda, 0x76, 0x05,
+             0xb7, 0x91, 0xfd, 0x8b} },
+
+        { "rfc2286 2.7", "rmd160",
+            hmac_test_case_keys[4], 80,
+            hmac_test_case_data[6], 73,
+            {0x69, 0xea, 0x60, 0x79, 0x8d, 0x71, 0x61, 0x6c,
+             0xce, 0x5f, 0xd0, 0x87, 0x1e, 0x23, 0x75, 0x4c,
+             0xd7, 0x5d, 0x5a, 0x0a} },
+#endif /* LTC_TEST_EXT */
+
+        /*
+        RFC 2286 3. Test Cases for HMAC-RIPEMD128
+        */
+        { "rfc2286 3.1", "rmd128",
+            hmac_test_case_keys[0], 16,
+            hmac_test_case_data[0], 8,
+            {0xfb, 0xf6, 0x1f, 0x94, 0x92, 0xaa, 0x4b, 0xbf,
+             0x81, 0xc1, 0x72, 0xe8, 0x4e, 0x07, 0x34, 0xdb} },
+
+#ifdef LTC_TEST_EXT
+        { "rfc2286 3.2", "rmd128",
+            hmac_test_case_keys[1], 4,
+            hmac_test_case_data[1], 28,
+            {0x87, 0x5f, 0x82, 0x88, 0x62, 0xb6, 0xb3, 0x34,
+             0xb4, 0x27, 0xc5, 0x5f, 0x9f, 0x7f, 0xf0, 0x9b} },
+
+        { "rfc2286 3.3", "rmd128",
+            hmac_test_case_keys[4], 16,
+            hmac_test_case_data[2], 50,
+            {0x09, 0xf0, 0xb2, 0x84, 0x6d, 0x2f, 0x54, 0x3d,
+             0xa3, 0x63, 0xcb, 0xec, 0x8d, 0x62, 0xa3, 0x8d} },
+
+        { "rfc2286 3.4", "rmd128",
+            hmac_test_case_keys[2], 25,
+            hmac_test_case_data[3], 50,
+            {0xbd, 0xbb, 0xd7, 0xcf, 0x03, 0xe4, 0x4b, 0x5a,
+             0xa6, 0x0a, 0xf8, 0x15, 0xbe, 0x4d, 0x22, 0x94} },
+
+        { "rfc2286 3.5", "rmd128",
+            hmac_test_case_keys[3], 16,
+            hmac_test_case_data[4], 20,
+            {0xe7, 0x98, 0x08, 0xf2, 0x4b, 0x25, 0xfd, 0x03,
+             0x1c, 0x15, 0x5f, 0x0d, 0x55, 0x1d, 0x9a, 0x3a} },
+
+        { "rfc2286 3.6", "rmd128",
+            hmac_test_case_keys[4], 80,
+            hmac_test_case_data[5], 54,
+            {0xdc, 0x73, 0x29, 0x28, 0xde, 0x98, 0x10, 0x4a,
+             0x1f, 0x59, 0xd3, 0x73, 0xc1, 0x50, 0xac, 0xbb} },
+
+        { "rfc2286 3.7", "rmd128",
+            hmac_test_case_keys[4], 80,
+            hmac_test_case_data[6], 73,
+            {0x5c, 0x6b, 0xec, 0x96, 0x79, 0x3e, 0x16, 0xd4,
+             0x06, 0x90, 0xc2, 0x37, 0x63, 0x5f, 0x30, 0xc5} },
+#endif /* LTC_TEST_EXT */
+
+        /*
+        RFC 4231 4. Test Vectors
+        Ch. 4.6 with truncated output left out to simplify tests
+        */
+        { "rfc4231 4.2", "sha224",
+            hmac_test_case_keys[0], 20,
+            hmac_test_case_data[0], 8,
+            {0x89, 0x6f, 0xb1, 0x12, 0x8a, 0xbb, 0xdf, 0x19,
+             0x68, 0x32, 0x10, 0x7c, 0xd4, 0x9d, 0xf3, 0x3f,
+             0x47, 0xb4, 0xb1, 0x16, 0x99, 0x12, 0xba, 0x4f,
+             0x53, 0x68, 0x4b, 0x22} },
+
+#ifdef LTC_TEST_EXT
+        { "rfc4231 4.3", "sha224",
+            hmac_test_case_keys[1], 4,
+            hmac_test_case_data[1], 28,
+            {0xa3, 0x0e, 0x01, 0x09, 0x8b, 0xc6, 0xdb, 0xbf,
+             0x45, 0x69, 0x0f, 0x3a, 0x7e, 0x9e, 0x6d, 0x0f,
+             0x8b, 0xbe, 0xa2, 0xa3, 0x9e, 0x61, 0x48, 0x00,
+             0x8f, 0xd0, 0x5e, 0x44} },
+
+        { "rfc4231 4.4", "sha224",
+            hmac_test_case_keys[4], 20,
+            hmac_test_case_data[2], 50,
+            {0x7f, 0xb3, 0xcb, 0x35, 0x88, 0xc6, 0xc1, 0xf6,
+             0xff, 0xa9, 0x69, 0x4d, 0x7d, 0x6a, 0xd2, 0x64,
+             0x93, 0x65, 0xb0, 0xc1, 0xf6, 0x5d, 0x69, 0xd1,
+             0xec, 0x83, 0x33, 0xea} },
+
+        { "rfc4231 4.5", "sha224",
+            hmac_test_case_keys[2], 25,
+            hmac_test_case_data[3], 50,
+            {0x6c, 0x11, 0x50, 0x68, 0x74, 0x01, 0x3c, 0xac,
+             0x6a, 0x2a, 0xbc, 0x1b, 0xb3, 0x82, 0x62, 0x7c,
+             0xec, 0x6a, 0x90, 0xd8, 0x6e, 0xfc, 0x01, 0x2d,
+             0xe7, 0xaf, 0xec, 0x5a} },
+
+        { "rfc4231 4.7", "sha224",
+            hmac_test_case_keys[4], 131,
+            hmac_test_case_data[5], 54,
+            {0x95, 0xe9, 0xa0, 0xdb, 0x96, 0x20, 0x95, 0xad,
+             0xae, 0xbe, 0x9b, 0x2d, 0x6f, 0x0d, 0xbc, 0xe2,
+             0xd4, 0x99, 0xf1, 0x12, 0xf2, 0xd2, 0xb7, 0x27,
+             0x3f, 0xa6, 0x87, 0x0e} },
+
+        { "rfc4231 4.8", "sha224",
+            hmac_test_case_keys[4], 131,
+            hmac_test_case_data[7], 152,
+            {0x3a, 0x85, 0x41, 0x66, 0xac, 0x5d, 0x9f, 0x02,
+             0x3f, 0x54, 0xd5, 0x17, 0xd0, 0xb3, 0x9d, 0xbd,
+             0x94, 0x67, 0x70, 0xdb, 0x9c, 0x2b, 0x95, 0xc9,
+             0xf6, 0xf5, 0x65, 0xd1} },
+#endif /* LTC_TEST_EXT */
+
+        { "rfc4231 4.2", "sha256",
+            hmac_test_case_keys[0], 20,
+            hmac_test_case_data[0], 8,
+            {0xb0, 0x34, 0x4c, 0x61, 0xd8, 0xdb, 0x38, 0x53,
+             0x5c, 0xa8, 0xaf, 0xce, 0xaf, 0x0b, 0xf1, 0x2b,
+             0x88, 0x1d, 0xc2, 0x00, 0xc9, 0x83, 0x3d, 0xa7,
+             0x26, 0xe9, 0x37, 0x6c, 0x2e, 0x32, 0xcf, 0xf7} },
+
+#ifdef LTC_TEST_EXT
+        { "rfc4231 4.3", "sha256",
+            hmac_test_case_keys[1], 4,
+            hmac_test_case_data[1], 28,
+            {0x5b, 0xdc, 0xc1, 0x46, 0xbf, 0x60, 0x75, 0x4e,
+             0x6a, 0x04, 0x24, 0x26, 0x08, 0x95, 0x75, 0xc7,
+             0x5a, 0x00, 0x3f, 0x08, 0x9d, 0x27, 0x39, 0x83,
+             0x9d, 0xec, 0x58, 0xb9, 0x64, 0xec, 0x38, 0x43} },
+
+        { "rfc4231 4.4", "sha256",
+            hmac_test_case_keys[4], 20,
+            hmac_test_case_data[2], 50,
+            {0x77, 0x3e, 0xa9, 0x1e, 0x36, 0x80, 0x0e, 0x46,
+             0x85, 0x4d, 0xb8, 0xeb, 0xd0, 0x91, 0x81, 0xa7,
+             0x29, 0x59, 0x09, 0x8b, 0x3e, 0xf8, 0xc1, 0x22,
+             0xd9, 0x63, 0x55, 0x14, 0xce, 0xd5, 0x65, 0xfe} },
+
+        { "rfc4231 4.5", "sha256",
+            hmac_test_case_keys[2], 25,
+            hmac_test_case_data[3], 50,
+            {0x82, 0x55, 0x8a, 0x38, 0x9a, 0x44, 0x3c, 0x0e,
+             0xa4, 0xcc, 0x81, 0x98, 0x99, 0xf2, 0x08, 0x3a,
+             0x85, 0xf0, 0xfa, 0xa3, 0xe5, 0x78, 0xf8, 0x07,
+             0x7a, 0x2e, 0x3f, 0xf4, 0x67, 0x29, 0x66, 0x5b} },
+
+        { "rfc4231 4.7", "sha256",
+            hmac_test_case_keys[4], 131,
+            hmac_test_case_data[5], 54,
+            {0x60, 0xe4, 0x31, 0x59, 0x1e, 0xe0, 0xb6, 0x7f,
+             0x0d, 0x8a, 0x26, 0xaa, 0xcb, 0xf5, 0xb7, 0x7f,
+             0x8e, 0x0b, 0xc6, 0x21, 0x37, 0x28, 0xc5, 0x14,
+             0x05, 0x46, 0x04, 0x0f, 0x0e, 0xe3, 0x7f, 0x54} },
+
+        { "rfc4231 4.8", "sha256",
+            hmac_test_case_keys[4], 131,
+            hmac_test_case_data[7], 152,
+            {0x9b, 0x09, 0xff, 0xa7, 0x1b, 0x94, 0x2f, 0xcb,
+             0x27, 0x63, 0x5f, 0xbc, 0xd5, 0xb0, 0xe9, 0x44,
+             0xbf, 0xdc, 0x63, 0x64, 0x4f, 0x07, 0x13, 0x93,
+             0x8a, 0x7f, 0x51, 0x53, 0x5c, 0x3a, 0x35, 0xe2} },
+#endif /* LTC_TEST_EXT */
+
+        { "rfc4231 4.2", "sha384",
+            hmac_test_case_keys[0], 20,
+            hmac_test_case_data[0], 8,
+            {0xaf, 0xd0, 0x39, 0x44, 0xd8, 0x48, 0x95, 0x62,
+             0x6b, 0x08, 0x25, 0xf4, 0xab, 0x46, 0x90, 0x7f,
+             0x15, 0xf9, 0xda, 0xdb, 0xe4, 0x10, 0x1e, 0xc6,
+             0x82, 0xaa, 0x03, 0x4c, 0x7c, 0xeb, 0xc5, 0x9c,
+             0xfa, 0xea, 0x9e, 0xa9, 0x07, 0x6e, 0xde, 0x7f,
+             0x4a, 0xf1, 0x52, 0xe8, 0xb2, 0xfa, 0x9c, 0xb6} },
+
+#ifdef LTC_TEST_EXT
+        { "rfc4231 4.3", "sha384",
+            hmac_test_case_keys[1], 4,
+            hmac_test_case_data[1], 28,
+            {0xaf, 0x45, 0xd2, 0xe3, 0x76, 0x48, 0x40, 0x31,
+             0x61, 0x7f, 0x78, 0xd2, 0xb5, 0x8a, 0x6b, 0x1b,
+             0x9c, 0x7e, 0xf4, 0x64, 0xf5, 0xa0, 0x1b, 0x47,
+             0xe4, 0x2e, 0xc3, 0x73, 0x63, 0x22, 0x44, 0x5e,
+             0x8e, 0x22, 0x40, 0xca, 0x5e, 0x69, 0xe2, 0xc7,
+             0x8b, 0x32, 0x39, 0xec, 0xfa, 0xb2, 0x16, 0x49} },
+
+        { "rfc4231 4.4", "sha384",
+            hmac_test_case_keys[4], 20,
+            hmac_test_case_data[2], 50,
+            {0x88, 0x06, 0x26, 0x08, 0xd3, 0xe6, 0xad, 0x8a,
+             0x0a, 0xa2, 0xac, 0xe0, 0x14, 0xc8, 0xa8, 0x6f,
+             0x0a, 0xa6, 0x35, 0xd9, 0x47, 0xac, 0x9f, 0xeb,
+             0xe8, 0x3e, 0xf4, 0xe5, 0x59, 0x66, 0x14, 0x4b,
+             0x2a, 0x5a, 0xb3, 0x9d, 0xc1, 0x38, 0x14, 0xb9,
+             0x4e, 0x3a, 0xb6, 0xe1, 0x01, 0xa3, 0x4f, 0x27} },
+
+        { "rfc4231 4.5", "sha384",
+            hmac_test_case_keys[2], 25,
+            hmac_test_case_data[3], 50,
+            {0x3e, 0x8a, 0x69, 0xb7, 0x78, 0x3c, 0x25, 0x85,
+             0x19, 0x33, 0xab, 0x62, 0x90, 0xaf, 0x6c, 0xa7,
+             0x7a, 0x99, 0x81, 0x48, 0x08, 0x50, 0x00, 0x9c,
+             0xc5, 0x57, 0x7c, 0x6e, 0x1f, 0x57, 0x3b, 0x4e,
+             0x68, 0x01, 0xdd, 0x23, 0xc4, 0xa7, 0xd6, 0x79,
+             0xcc, 0xf8, 0xa3, 0x86, 0xc6, 0x74, 0xcf, 0xfb} },
+
+        { "rfc4231 4.7", "sha384",
+            hmac_test_case_keys[4], 131,
+            hmac_test_case_data[5], 54,
+            {0x4e, 0xce, 0x08, 0x44, 0x85, 0x81, 0x3e, 0x90,
+             0x88, 0xd2, 0xc6, 0x3a, 0x04, 0x1b, 0xc5, 0xb4,
+             0x4f, 0x9e, 0xf1, 0x01, 0x2a, 0x2b, 0x58, 0x8f,
+             0x3c, 0xd1, 0x1f, 0x05, 0x03, 0x3a, 0xc4, 0xc6,
+             0x0c, 0x2e, 0xf6, 0xab, 0x40, 0x30, 0xfe, 0x82,
+             0x96, 0x24, 0x8d, 0xf1, 0x63, 0xf4, 0x49, 0x52} },
+
+        { "rfc4231 4.8", "sha384",
+            hmac_test_case_keys[4], 131,
+            hmac_test_case_data[7], 152,
+            {0x66, 0x17, 0x17, 0x8e, 0x94, 0x1f, 0x02, 0x0d,
+             0x35, 0x1e, 0x2f, 0x25, 0x4e, 0x8f, 0xd3, 0x2c,
+             0x60, 0x24, 0x20, 0xfe, 0xb0, 0xb8, 0xfb, 0x9a,
+             0xdc, 0xce, 0xbb, 0x82, 0x46, 0x1e, 0x99, 0xc5,
+             0xa6, 0x78, 0xcc, 0x31, 0xe7, 0x99, 0x17, 0x6d,
+             0x38, 0x60, 0xe6, 0x11, 0x0c, 0x46, 0x52, 0x3e} },
+#endif /* LTC_TEST_EXT */
+
+        { "rfc4231 4.2", "sha512",
+            hmac_test_case_keys[0], 20,
+            hmac_test_case_data[0], 8,
+            {0x87, 0xaa, 0x7c, 0xde, 0xa5, 0xef, 0x61, 0x9d,
+             0x4f, 0xf0, 0xb4, 0x24, 0x1a, 0x1d, 0x6c, 0xb0,
+             0x23, 0x79, 0xf4, 0xe2, 0xce, 0x4e, 0xc2, 0x78,
+             0x7a, 0xd0, 0xb3, 0x05, 0x45, 0xe1, 0x7c, 0xde,
+             0xda, 0xa8, 0x33, 0xb7, 0xd6, 0xb8, 0xa7, 0x02,
+             0x03, 0x8b, 0x27, 0x4e, 0xae, 0xa3, 0xf4, 0xe4,
+             0xbe, 0x9d, 0x91, 0x4e, 0xeb, 0x61, 0xf1, 0x70,
+             0x2e, 0x69, 0x6c, 0x20, 0x3a, 0x12, 0x68, 0x54} },
+
+#ifdef LTC_TEST_EXT
+        { "rfc4231 4.3", "sha512",
+            hmac_test_case_keys[1], 4,
+            hmac_test_case_data[1], 28,
+            {0x16, 0x4b, 0x7a, 0x7b, 0xfc, 0xf8, 0x19, 0xe2,
+             0xe3, 0x95, 0xfb, 0xe7, 0x3b, 0x56, 0xe0, 0xa3,
+             0x87, 0xbd, 0x64, 0x22, 0x2e, 0x83, 0x1f, 0xd6,
+             0x10, 0x27, 0x0c, 0xd7, 0xea, 0x25, 0x05, 0x54,
+             0x97, 0x58, 0xbf, 0x75, 0xc0, 0x5a, 0x99, 0x4a,
+             0x6d, 0x03, 0x4f, 0x65, 0xf8, 0xf0, 0xe6, 0xfd,
+             0xca, 0xea, 0xb1, 0xa3, 0x4d, 0x4a, 0x6b, 0x4b,
+             0x63, 0x6e, 0x07, 0x0a, 0x38, 0xbc, 0xe7, 0x37} },
+
+        { "rfc4231 4.4", "sha512",
+            hmac_test_case_keys[4], 20,
+            hmac_test_case_data[2], 50,
+            {0xfa, 0x73, 0xb0, 0x08, 0x9d, 0x56, 0xa2, 0x84,
+             0xef, 0xb0, 0xf0, 0x75, 0x6c, 0x89, 0x0b, 0xe9,
+             0xb1, 0xb5, 0xdb, 0xdd, 0x8e, 0xe8, 0x1a, 0x36,
+             0x55, 0xf8, 0x3e, 0x33, 0xb2, 0x27, 0x9d, 0x39,
+             0xbf, 0x3e, 0x84, 0x82, 0x79, 0xa7, 0x22, 0xc8,
+             0x06, 0xb4, 0x85, 0xa4, 0x7e, 0x67, 0xc8, 0x07,
+             0xb9, 0x46, 0xa3, 0x37, 0xbe, 0xe8, 0x94, 0x26,
+             0x74, 0x27, 0x88, 0x59, 0xe1, 0x32, 0x92, 0xfb} },
+
+        { "rfc4231 4.5", "sha512",
+            hmac_test_case_keys[2], 25,
+            hmac_test_case_data[3], 50,
+            {0xb0, 0xba, 0x46, 0x56, 0x37, 0x45, 0x8c, 0x69,
+             0x90, 0xe5, 0xa8, 0xc5, 0xf6, 0x1d, 0x4a, 0xf7,
+             0xe5, 0x76, 0xd9, 0x7f, 0xf9, 0x4b, 0x87, 0x2d,
+             0xe7, 0x6f, 0x80, 0x50, 0x36, 0x1e, 0xe3, 0xdb,
+             0xa9, 0x1c, 0xa5, 0xc1, 0x1a, 0xa2, 0x5e, 0xb4,
+             0xd6, 0x79, 0x27, 0x5c, 0xc5, 0x78, 0x80, 0x63,
+             0xa5, 0xf1, 0x97, 0x41, 0x12, 0x0c, 0x4f, 0x2d,
+             0xe2, 0xad, 0xeb, 0xeb, 0x10, 0xa2, 0x98, 0xdd} },
+
+        { "rfc4231 4.7", "sha512",
+            hmac_test_case_keys[4], 131,
+            hmac_test_case_data[5], 54,
+            {0x80, 0xb2, 0x42, 0x63, 0xc7, 0xc1, 0xa3, 0xeb,
+             0xb7, 0x14, 0x93, 0xc1, 0xdd, 0x7b, 0xe8, 0xb4,
+             0x9b, 0x46, 0xd1, 0xf4, 0x1b, 0x4a, 0xee, 0xc1,
+             0x12, 0x1b, 0x01, 0x37, 0x83, 0xf8, 0xf3, 0x52,
+             0x6b, 0x56, 0xd0, 0x37, 0xe0, 0x5f, 0x25, 0x98,
+             0xbd, 0x0f, 0xd2, 0x21, 0x5d, 0x6a, 0x1e, 0x52,
+             0x95, 0xe6, 0x4f, 0x73, 0xf6, 0x3f, 0x0a, 0xec,
+             0x8b, 0x91, 0x5a, 0x98, 0x5d, 0x78, 0x65, 0x98} },
+
+        { "rfc4231 4.8", "sha512",
+            hmac_test_case_keys[4], 131,
+            hmac_test_case_data[7], 152,
+            {0xe3, 0x7b, 0x6a, 0x77, 0x5d, 0xc8, 0x7d, 0xba,
+             0xa4, 0xdf, 0xa9, 0xf9, 0x6e, 0x5e, 0x3f, 0xfd,
+             0xde, 0xbd, 0x71, 0xf8, 0x86, 0x72, 0x89, 0x86,
+             0x5d, 0xf5, 0xa3, 0x2d, 0x20, 0xcd, 0xc9, 0x44,
+             0xb6, 0x02, 0x2c, 0xac, 0x3c, 0x49, 0x82, 0xb1,
+             0x0d, 0x5e, 0xeb, 0x55, 0xc3, 0xe4, 0xde, 0x15,
+             0x13, 0x46, 0x76, 0xfb, 0x6d, 0xe0, 0x44, 0x60,
+             0x65, 0xc9, 0x74, 0x40, 0xfa, 0x8c, 0x6a, 0x58} },
+#endif /* LTC_TEST_EXT */
+
+    };
+
+    unsigned long outlen;
+    int err;
+    int tested=0,failed=0;
+    for(i=0; i < (int)(sizeof(cases) / sizeof(cases[0])); i++) {
+        int hash = find_hash(cases[i].algo);
+        if (hash == -1) continue;
+        ++tested;
+        outlen = sizeof(digest);
+        if((err = hmac_memory(hash, cases[i].key, cases[i].keylen, cases[i].data, cases[i].datalen, digest, &outlen)) != CRYPT_OK) {
+#ifdef LTC_TEST_DBG
+            printf("HMAC-%s test %s, %s\n", cases[i].algo, cases[i].num, error_to_string(err));
+#endif
+            return err;
+        }
+
+        if(compare_testvector(digest, outlen, cases[i].digest, (size_t)hash_descriptor[hash].hashsize, cases[i].num, i)) {
+            failed++;
+        }
+    }
+
+    if (failed != 0) {
+        return CRYPT_FAIL_TESTVECTOR;
+    } else if (tested == 0) {
+        return CRYPT_NOP;
+    } else {
+        return CRYPT_OK;
+    }
+ #endif
+}
+
+#endif
+
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/mac/omac/omac_done.c b/libtomcrypt/src/mac/omac/omac_done.c
new file mode 100644 (file)
index 0000000..bf22523
--- /dev/null
@@ -0,0 +1,84 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file omac_done.c
+  OMAC1 support, terminate a stream, Tom St Denis
+*/
+
+#ifdef LTC_OMAC
+
+/**
+  Terminate an OMAC stream
+  @param omac   The OMAC state
+  @param out    [out] Destination for the authentication tag
+  @param outlen [in/out]  The max size and resulting size of the authentication tag
+  @return CRYPT_OK if successful
+*/
+int omac_done(omac_state *omac, unsigned char *out, unsigned long *outlen)
+{
+   int       err, mode;
+   unsigned  x;
+
+   LTC_ARGCHK(omac   != NULL);
+   LTC_ARGCHK(out    != NULL);
+   LTC_ARGCHK(outlen != NULL);
+   if ((err = cipher_is_valid(omac->cipher_idx)) != CRYPT_OK) {
+      return err;
+   }
+
+   if ((omac->buflen > (int)sizeof(omac->block)) || (omac->buflen < 0) ||
+       (omac->blklen > (int)sizeof(omac->block)) || (omac->buflen > omac->blklen)) {
+      return CRYPT_INVALID_ARG;
+   }
+
+   /* figure out mode */
+   if (omac->buflen != omac->blklen) {
+      /* add the 0x80 byte */
+      omac->block[omac->buflen++] = 0x80;
+
+      /* pad with 0x00 */
+      while (omac->buflen < omac->blklen) {
+         omac->block[omac->buflen++] = 0x00;
+      }
+      mode = 1;
+   } else {
+      mode = 0;
+   }
+
+   /* now xor prev + Lu[mode] */
+   for (x = 0; x < (unsigned)omac->blklen; x++) {
+       omac->block[x] ^= omac->prev[x] ^ omac->Lu[mode][x];
+   }
+
+   /* encrypt it */
+   if ((err = cipher_descriptor[omac->cipher_idx].ecb_encrypt(omac->block, omac->block, &omac->key)) != CRYPT_OK) {
+      return err;
+   }
+   cipher_descriptor[omac->cipher_idx].done(&omac->key);
+
+   /* output it */
+   for (x = 0; x < (unsigned)omac->blklen && x < *outlen; x++) {
+       out[x] = omac->block[x];
+   }
+   *outlen = x;
+
+#ifdef LTC_CLEAN_STACK
+   zeromem(omac, sizeof(*omac));
+#endif
+   return CRYPT_OK;
+}
+
+#endif
+
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/mac/omac/omac_file.c b/libtomcrypt/src/mac/omac/omac_file.c
new file mode 100644 (file)
index 0000000..3f6a85d
--- /dev/null
@@ -0,0 +1,97 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file omac_file.c
+  OMAC1 support, process a file, Tom St Denis
+*/
+
+#ifdef LTC_OMAC
+
+/**
+   OMAC a file
+   @param cipher   The index of the cipher desired
+   @param key      The secret key
+   @param keylen   The length of the secret key (octets)
+   @param filename The name of the file you wish to OMAC
+   @param out      [out] Where the authentication tag is to be stored
+   @param outlen   [in/out] The max size and resulting size of the authentication tag
+   @return CRYPT_OK if successful, CRYPT_NOP if file support has been disabled
+*/
+int omac_file(int cipher,
+              const unsigned char *key, unsigned long keylen,
+              const char *filename,
+                    unsigned char *out, unsigned long *outlen)
+{
+#ifdef LTC_NO_FILE
+   LTC_UNUSED_PARAM(cipher);
+   LTC_UNUSED_PARAM(key);
+   LTC_UNUSED_PARAM(keylen);
+   LTC_UNUSED_PARAM(filename);
+   LTC_UNUSED_PARAM(out);
+   LTC_UNUSED_PARAM(outlen);
+   return CRYPT_NOP;
+#else
+   size_t x;
+   int err;
+   omac_state omac;
+   FILE *in;
+   unsigned char *buf;
+
+   LTC_ARGCHK(key      != NULL);
+   LTC_ARGCHK(filename != NULL);
+   LTC_ARGCHK(out      != NULL);
+   LTC_ARGCHK(outlen   != NULL);
+
+   if ((buf = XMALLOC(LTC_FILE_READ_BUFSIZE)) == NULL) {
+      return CRYPT_MEM;
+   }
+
+   if ((err = omac_init(&omac, cipher, key, keylen)) != CRYPT_OK) {
+      goto LBL_ERR;
+   }
+
+   in = fopen(filename, "rb");
+   if (in == NULL) {
+      err = CRYPT_FILE_NOTFOUND;
+      goto LBL_ERR;
+   }
+
+   do {
+      x = fread(buf, 1, LTC_FILE_READ_BUFSIZE, in);
+      if ((err = omac_process(&omac, buf, (unsigned long)x)) != CRYPT_OK) {
+         fclose(in);
+         goto LBL_CLEANBUF;
+      }
+   } while (x == LTC_FILE_READ_BUFSIZE);
+
+   if (fclose(in) != 0) {
+      err = CRYPT_ERROR;
+      goto LBL_CLEANBUF;
+   }
+
+   err = omac_done(&omac, out, outlen);
+
+LBL_CLEANBUF:
+   zeromem(buf, LTC_FILE_READ_BUFSIZE);
+LBL_ERR:
+#ifdef LTC_CLEAN_STACK
+   zeromem(&omac, sizeof(omac_state));
+#endif
+   XFREE(buf);
+   return err;
+#endif
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/mac/omac/omac_init.c b/libtomcrypt/src/mac/omac/omac_init.c
new file mode 100644 (file)
index 0000000..55de2a6
--- /dev/null
@@ -0,0 +1,99 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file omac_init.c
+  OMAC1 support, initialize state, by Tom St Denis
+*/
+
+
+#ifdef LTC_OMAC
+
+/**
+   Initialize an OMAC state
+   @param omac    The OMAC state to initialize
+   @param cipher  The index of the desired cipher
+   @param key     The secret key
+   @param keylen  The length of the secret key (octets)
+   @return CRYPT_OK if successful
+*/
+int omac_init(omac_state *omac, int cipher, const unsigned char *key, unsigned long keylen)
+{
+   int err, x, y, mask, msb, len;
+
+   LTC_ARGCHK(omac != NULL);
+   LTC_ARGCHK(key  != NULL);
+
+   /* schedule the key */
+   if ((err = cipher_is_valid(cipher)) != CRYPT_OK) {
+      return err;
+   }
+
+#ifdef LTC_FAST
+   if (cipher_descriptor[cipher].block_length % sizeof(LTC_FAST_TYPE)) {
+       return CRYPT_INVALID_ARG;
+   }
+#endif
+
+   /* now setup the system */
+   switch (cipher_descriptor[cipher].block_length) {
+       case 8:  mask = 0x1B;
+                len  = 8;
+                break;
+       case 16: mask = 0x87;
+                len  = 16;
+                break;
+       default: return CRYPT_INVALID_ARG;
+   }
+
+   if ((err = cipher_descriptor[cipher].setup(key, keylen, 0, &omac->key)) != CRYPT_OK) {
+      return err;
+   }
+
+   /* ok now we need Lu and Lu^2 [calc one from the other] */
+
+   /* first calc L which is Ek(0) */
+   zeromem(omac->Lu[0], cipher_descriptor[cipher].block_length);
+   if ((err = cipher_descriptor[cipher].ecb_encrypt(omac->Lu[0], omac->Lu[0], &omac->key)) != CRYPT_OK) {
+      return err;
+   }
+
+   /* now do the mults, whoopy! */
+   for (x = 0; x < 2; x++) {
+       /* if msb(L * u^(x+1)) = 0 then just shift, otherwise shift and xor constant mask */
+       msb = omac->Lu[x][0] >> 7;
+
+       /* shift left */
+       for (y = 0; y < (len - 1); y++) {
+           omac->Lu[x][y] = ((omac->Lu[x][y] << 1) | (omac->Lu[x][y+1] >> 7)) & 255;
+       }
+       omac->Lu[x][len - 1] = ((omac->Lu[x][len - 1] << 1) ^ (msb ? mask : 0)) & 255;
+
+       /* copy up as require */
+       if (x == 0) {
+          XMEMCPY(omac->Lu[1], omac->Lu[0], sizeof(omac->Lu[0]));
+       }
+   }
+
+   /* setup state */
+   omac->cipher_idx = cipher;
+   omac->buflen     = 0;
+   omac->blklen     = len;
+   zeromem(omac->prev,  sizeof(omac->prev));
+   zeromem(omac->block, sizeof(omac->block));
+
+   return CRYPT_OK;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/mac/omac/omac_memory.c b/libtomcrypt/src/mac/omac/omac_memory.c
new file mode 100644 (file)
index 0000000..1b57db8
--- /dev/null
@@ -0,0 +1,83 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file omac_memory.c
+  OMAC1 support, process a block of memory, Tom St Denis
+*/
+
+#ifdef LTC_OMAC
+
+/**
+   OMAC a block of memory
+   @param cipher    The index of the desired cipher
+   @param key       The secret key
+   @param keylen    The length of the secret key (octets)
+   @param in        The data to send through OMAC
+   @param inlen     The length of the data to send through OMAC (octets)
+   @param out       [out] The destination of the authentication tag
+   @param outlen    [in/out]  The max size and resulting size of the authentication tag (octets)
+   @return CRYPT_OK if successful
+*/
+int omac_memory(int cipher,
+                const unsigned char *key, unsigned long keylen,
+                const unsigned char *in,  unsigned long inlen,
+                      unsigned char *out, unsigned long *outlen)
+{
+   int err;
+   omac_state *omac;
+
+   LTC_ARGCHK(key    != NULL);
+   LTC_ARGCHK(in     != NULL);
+   LTC_ARGCHK(out    != NULL);
+   LTC_ARGCHK(outlen != NULL);
+
+   /* is the cipher valid? */
+   if ((err = cipher_is_valid(cipher)) != CRYPT_OK) {
+      return err;
+   }
+
+   /* Use accelerator if found */
+   if (cipher_descriptor[cipher].omac_memory != NULL) {
+      return cipher_descriptor[cipher].omac_memory(key, keylen, in, inlen, out, outlen);
+   }
+
+   /* allocate ram for omac state */
+   omac = XMALLOC(sizeof(omac_state));
+   if (omac == NULL) {
+      return CRYPT_MEM;
+   }
+
+   /* omac process the message */
+   if ((err = omac_init(omac, cipher, key, keylen)) != CRYPT_OK) {
+      goto LBL_ERR;
+   }
+   if ((err = omac_process(omac, in, inlen)) != CRYPT_OK) {
+      goto LBL_ERR;
+   }
+   if ((err = omac_done(omac, out, outlen)) != CRYPT_OK) {
+      goto LBL_ERR;
+   }
+
+   err = CRYPT_OK;
+LBL_ERR:
+#ifdef LTC_CLEAN_STACK
+   zeromem(omac, sizeof(omac_state));
+#endif
+
+   XFREE(omac);
+   return err;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/mac/omac/omac_memory_multi.c b/libtomcrypt/src/mac/omac/omac_memory_multi.c
new file mode 100644 (file)
index 0000000..50f26e6
--- /dev/null
@@ -0,0 +1,88 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+#include <stdarg.h>
+
+/**
+  @file omac_memory_multi.c
+  OMAC1 support, process multiple blocks of memory, Tom St Denis
+*/
+
+#ifdef LTC_OMAC
+
+/**
+   OMAC multiple blocks of memory
+   @param cipher    The index of the desired cipher
+   @param key       The secret key
+   @param keylen    The length of the secret key (octets)
+   @param out       [out] The destination of the authentication tag
+   @param outlen    [in/out]  The max size and resulting size of the authentication tag (octets)
+   @param in        The data to send through OMAC
+   @param inlen     The length of the data to send through OMAC (octets)
+   @param ...       tuples of (data,len) pairs to OMAC, terminated with a (NULL,x) (x=don't care)
+   @return CRYPT_OK if successful
+*/
+int omac_memory_multi(int cipher,
+                const unsigned char *key, unsigned long keylen,
+                      unsigned char *out, unsigned long *outlen,
+                const unsigned char *in,  unsigned long inlen, ...)
+{
+   int                  err;
+   omac_state          *omac;
+   va_list              args;
+   const unsigned char *curptr;
+   unsigned long        curlen;
+
+   LTC_ARGCHK(key    != NULL);
+   LTC_ARGCHK(in     != NULL);
+   LTC_ARGCHK(out    != NULL);
+   LTC_ARGCHK(outlen != NULL);
+
+   /* allocate ram for omac state */
+   omac = XMALLOC(sizeof(omac_state));
+   if (omac == NULL) {
+      return CRYPT_MEM;
+   }
+
+   /* omac process the message */
+   if ((err = omac_init(omac, cipher, key, keylen)) != CRYPT_OK) {
+      goto LBL_ERR;
+   }
+   va_start(args, inlen);
+   curptr = in;
+   curlen = inlen;
+   for (;;) {
+      /* process buf */
+      if ((err = omac_process(omac, curptr, curlen)) != CRYPT_OK) {
+         goto LBL_ERR;
+      }
+      /* step to next */
+      curptr = va_arg(args, const unsigned char*);
+      if (curptr == NULL) {
+         break;
+      }
+      curlen = va_arg(args, unsigned long);
+   }
+   if ((err = omac_done(omac, out, outlen)) != CRYPT_OK) {
+      goto LBL_ERR;
+   }
+LBL_ERR:
+#ifdef LTC_CLEAN_STACK
+   zeromem(omac, sizeof(omac_state));
+#endif
+   XFREE(omac);
+   va_end(args);
+   return err;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/mac/omac/omac_process.c b/libtomcrypt/src/mac/omac/omac_process.c
new file mode 100644 (file)
index 0000000..4ae2bd1
--- /dev/null
@@ -0,0 +1,90 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file omac_process.c
+  OMAC1 support, process data, Tom St Denis
+*/
+
+
+#ifdef LTC_OMAC
+
+/**
+   Process data through OMAC
+   @param omac     The OMAC state
+   @param in       The input data to send through OMAC
+   @param inlen    The length of the input (octets)
+   @return CRYPT_OK if successful
+*/
+int omac_process(omac_state *omac, const unsigned char *in, unsigned long inlen)
+{
+   unsigned long n, x;
+   int           err;
+
+   LTC_ARGCHK(omac  != NULL);
+   LTC_ARGCHK(in    != NULL);
+   if ((err = cipher_is_valid(omac->cipher_idx)) != CRYPT_OK) {
+      return err;
+   }
+
+   if ((omac->buflen > (int)sizeof(omac->block)) || (omac->buflen < 0) ||
+       (omac->blklen > (int)sizeof(omac->block)) || (omac->buflen > omac->blklen)) {
+      return CRYPT_INVALID_ARG;
+   }
+
+#ifdef LTC_FAST
+   {
+     unsigned long blklen = cipher_descriptor[omac->cipher_idx].block_length;
+
+     if (omac->buflen == 0 && inlen > blklen) {
+        unsigned long y;
+        for (x = 0; x < (inlen - blklen); x += blklen) {
+            for (y = 0; y < blklen; y += sizeof(LTC_FAST_TYPE)) {
+                *(LTC_FAST_TYPE_PTR_CAST(&omac->prev[y])) ^= *(LTC_FAST_TYPE_PTR_CAST(&in[y]));
+            }
+            in += blklen;
+            if ((err = cipher_descriptor[omac->cipher_idx].ecb_encrypt(omac->prev, omac->prev, &omac->key)) != CRYPT_OK) {
+               return err;
+            }
+        }
+        inlen -= x;
+     }
+   }
+#endif
+
+   while (inlen != 0) {
+       /* ok if the block is full we xor in prev, encrypt and replace prev */
+       if (omac->buflen == omac->blklen) {
+          for (x = 0; x < (unsigned long)omac->blklen; x++) {
+              omac->block[x] ^= omac->prev[x];
+          }
+          if ((err = cipher_descriptor[omac->cipher_idx].ecb_encrypt(omac->block, omac->prev, &omac->key)) != CRYPT_OK) {
+             return err;
+          }
+          omac->buflen = 0;
+       }
+
+       /* add bytes */
+       n = MIN(inlen, (unsigned long)(omac->blklen - omac->buflen));
+       XMEMCPY(omac->block + omac->buflen, in, n);
+       omac->buflen  += n;
+       inlen         -= n;
+       in            += n;
+   }
+
+   return CRYPT_OK;
+}
+
+#endif
+
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/mac/omac/omac_test.c b/libtomcrypt/src/mac/omac/omac_test.c
new file mode 100644 (file)
index 0000000..9bf392c
--- /dev/null
@@ -0,0 +1,103 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file omac_test.c
+  OMAC1 support, self-test, by Tom St Denis
+*/
+
+#ifdef LTC_OMAC
+
+/**
+  Test the OMAC setup
+  @return CRYPT_OK if successful, CRYPT_NOP if tests have been disabled
+*/
+int omac_test(void)
+{
+#if !defined(LTC_TEST)
+    return CRYPT_NOP;
+#else
+    static const struct {
+        int keylen, msglen;
+        unsigned char key[16], msg[64], tag[16];
+    } tests[] = {
+    { 16, 0,
+      { 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
+        0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c },
+      { 0x00 },
+      { 0xbb, 0x1d, 0x69, 0x29, 0xe9, 0x59, 0x37, 0x28,
+        0x7f, 0xa3, 0x7d, 0x12, 0x9b, 0x75, 0x67, 0x46 }
+    },
+    { 16, 16,
+      { 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
+        0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c },
+      { 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
+        0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a },
+      { 0x07, 0x0a, 0x16, 0xb4, 0x6b, 0x4d, 0x41, 0x44,
+        0xf7, 0x9b, 0xdd, 0x9d, 0xd0, 0x4a, 0x28, 0x7c }
+    },
+    { 16, 40,
+      { 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
+        0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c },
+      { 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
+        0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
+        0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c,
+        0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
+        0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11 },
+      { 0xdf, 0xa6, 0x67, 0x47, 0xde, 0x9a, 0xe6, 0x30,
+        0x30, 0xca, 0x32, 0x61, 0x14, 0x97, 0xc8, 0x27 }
+    },
+    { 16, 64,
+      { 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
+        0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c },
+      { 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
+        0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
+        0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c,
+        0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
+        0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11,
+        0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef,
+        0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17,
+        0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10 },
+      { 0x51, 0xf0, 0xbe, 0xbf, 0x7e, 0x3b, 0x9d, 0x92,
+        0xfc, 0x49, 0x74, 0x17, 0x79, 0x36, 0x3c, 0xfe }
+    }
+
+    };
+    unsigned char out[16];
+    int x, err, idx;
+    unsigned long len;
+
+
+    /* AES can be under rijndael or aes... try to find it */
+    if ((idx = find_cipher("aes")) == -1) {
+       if ((idx = find_cipher("rijndael")) == -1) {
+          return CRYPT_NOP;
+       }
+    }
+
+    for (x = 0; x < (int)(sizeof(tests)/sizeof(tests[0])); x++) {
+       len = sizeof(out);
+       if ((err = omac_memory(idx, tests[x].key, tests[x].keylen, tests[x].msg, tests[x].msglen, out, &len)) != CRYPT_OK) {
+          return err;
+       }
+
+       if (compare_testvector(out, len, tests[x].tag, sizeof(tests[x].tag), "OMAC", x) != 0) {
+          return CRYPT_FAIL_TESTVECTOR;
+       }
+    }
+    return CRYPT_OK;
+#endif
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/mac/pelican/pelican.c b/libtomcrypt/src/mac/pelican/pelican.c
new file mode 100644 (file)
index 0000000..6a4dde6
--- /dev/null
@@ -0,0 +1,164 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+   @file pelican.c
+   Pelican MAC, initialize state, by Tom St Denis
+*/
+
+#ifdef LTC_PELICAN
+
+#define __LTC_AES_TAB_C__
+#define ENCRYPT_ONLY
+#define PELI_TAB
+#include "../../ciphers/aes/aes_tab.c"
+
+/**
+   Initialize a Pelican state
+   @param pelmac    The Pelican state to initialize
+   @param key       The secret key
+   @param keylen    The length of the secret key (octets)
+   @return CRYPT_OK if successful
+*/
+int pelican_init(pelican_state *pelmac, const unsigned char *key, unsigned long keylen)
+{
+    int err;
+
+    LTC_ARGCHK(pelmac != NULL);
+    LTC_ARGCHK(key    != NULL);
+
+#ifdef LTC_FAST
+    if (16 % sizeof(LTC_FAST_TYPE)) {
+        return CRYPT_INVALID_ARG;
+    }
+#endif
+
+    if ((err = aes_setup(key, keylen, 0, &pelmac->K)) != CRYPT_OK) {
+       return err;
+    }
+
+    zeromem(pelmac->state, 16);
+    aes_ecb_encrypt(pelmac->state, pelmac->state, &pelmac->K);
+    pelmac->buflen = 0;
+
+    return CRYPT_OK;
+}
+
+static void _four_rounds(pelican_state *pelmac)
+{
+    ulong32 s0, s1, s2, s3, t0, t1, t2, t3;
+    int r;
+
+    LOAD32H(s0, pelmac->state      );
+    LOAD32H(s1, pelmac->state  +  4);
+    LOAD32H(s2, pelmac->state  +  8);
+    LOAD32H(s3, pelmac->state  + 12);
+    for (r = 0; r < 4; r++) {
+        t0 =
+            Te0(byte(s0, 3)) ^
+            Te1(byte(s1, 2)) ^
+            Te2(byte(s2, 1)) ^
+            Te3(byte(s3, 0));
+        t1 =
+            Te0(byte(s1, 3)) ^
+            Te1(byte(s2, 2)) ^
+            Te2(byte(s3, 1)) ^
+            Te3(byte(s0, 0));
+        t2 =
+            Te0(byte(s2, 3)) ^
+            Te1(byte(s3, 2)) ^
+            Te2(byte(s0, 1)) ^
+            Te3(byte(s1, 0));
+        t3 =
+            Te0(byte(s3, 3)) ^
+            Te1(byte(s0, 2)) ^
+            Te2(byte(s1, 1)) ^
+            Te3(byte(s2, 0));
+        s0 = t0; s1 = t1; s2 = t2; s3 = t3;
+    }
+    STORE32H(s0, pelmac->state      );
+    STORE32H(s1, pelmac->state  +  4);
+    STORE32H(s2, pelmac->state  +  8);
+    STORE32H(s3, pelmac->state  + 12);
+}
+
+/**
+  Process a block of text through Pelican
+  @param pelmac       The Pelican MAC state
+  @param in           The input
+  @param inlen        The length input (octets)
+  @return CRYPT_OK on success
+  */
+int pelican_process(pelican_state *pelmac, const unsigned char *in, unsigned long inlen)
+{
+
+   LTC_ARGCHK(pelmac != NULL);
+   LTC_ARGCHK(in     != NULL);
+
+   /* check range */
+   if (pelmac->buflen < 0 || pelmac->buflen > 15) {
+      return CRYPT_INVALID_ARG;
+   }
+
+#ifdef LTC_FAST
+   if (pelmac->buflen == 0) {
+      while (inlen & ~15) {
+         int x;
+         for (x = 0; x < 16; x += sizeof(LTC_FAST_TYPE)) {
+            *(LTC_FAST_TYPE_PTR_CAST((unsigned char *)pelmac->state + x)) ^= *(LTC_FAST_TYPE_PTR_CAST((unsigned char *)in + x));
+         }
+         _four_rounds(pelmac);
+         in    += 16;
+         inlen -= 16;
+      }
+   }
+#endif
+
+   while (inlen--) {
+       pelmac->state[pelmac->buflen++] ^= *in++;
+       if (pelmac->buflen == 16) {
+          _four_rounds(pelmac);
+          pelmac->buflen = 0;
+       }
+   }
+   return CRYPT_OK;
+}
+
+/**
+  Terminate Pelican MAC
+  @param pelmac      The Pelican MAC state
+  @param out         [out] The TAG
+  @return CRYPT_OK on sucess
+*/
+int pelican_done(pelican_state *pelmac, unsigned char *out)
+{
+   LTC_ARGCHK(pelmac  != NULL);
+   LTC_ARGCHK(out     != NULL);
+
+   /* check range */
+   if (pelmac->buflen < 0 || pelmac->buflen > 16) {
+      return CRYPT_INVALID_ARG;
+   }
+
+   if  (pelmac->buflen == 16) {
+       _four_rounds(pelmac);
+       pelmac->buflen = 0;
+   }
+   pelmac->state[pelmac->buflen++] ^= 0x80;
+   aes_ecb_encrypt(pelmac->state, out, &pelmac->K);
+   aes_done(&pelmac->K);
+   return CRYPT_OK;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/mac/pelican/pelican_memory.c b/libtomcrypt/src/mac/pelican/pelican_memory.c
new file mode 100644 (file)
index 0000000..08607a0
--- /dev/null
@@ -0,0 +1,57 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+   @file pelican_memory.c
+   Pelican MAC, MAC a block of memory, by Tom St Denis
+*/
+
+#ifdef LTC_PELICAN
+
+/**
+  Pelican block of memory
+  @param key      The key for the MAC
+  @param keylen   The length of the key (octets)
+  @param in       The input to MAC
+  @param inlen    The length of the input (octets)
+  @param out      [out] The output TAG
+  @return CRYPT_OK on success
+*/
+int pelican_memory(const unsigned char *key, unsigned long keylen,
+                   const unsigned char *in,  unsigned long inlen,
+                         unsigned char *out)
+{
+   pelican_state *pel;
+   int err;
+
+   pel = XMALLOC(sizeof(*pel));
+   if (pel == NULL) {
+      return CRYPT_MEM;
+   }
+
+   if ((err = pelican_init(pel, key, keylen)) != CRYPT_OK) {
+      XFREE(pel);
+      return err;
+   }
+   if ((err = pelican_process(pel, in ,inlen)) != CRYPT_OK) {
+      XFREE(pel);
+      return err;
+   }
+   err = pelican_done(pel, out);
+   XFREE(pel);
+   return err;
+}
+
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/mac/pelican/pelican_test.c b/libtomcrypt/src/mac/pelican/pelican_test.c
new file mode 100644 (file)
index 0000000..32a7df3
--- /dev/null
@@ -0,0 +1,113 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+   @file pelican_test.c
+   Pelican MAC, test, by Tom St Denis
+*/
+
+#ifdef LTC_PELICAN
+
+int pelican_test(void)
+{
+#ifndef LTC_TEST
+   return CRYPT_NOP;
+#else
+   static const struct {
+        unsigned char K[32], MSG[64], T[16];
+   int keylen, ptlen;
+   } tests[] = {
+/* K=16, M=0 */
+{
+   { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+     0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F },
+   { 0 },
+   { 0xeb, 0x58, 0x37, 0x15, 0xf8, 0x34, 0xde, 0xe5,
+     0xa4, 0xd1, 0x6e, 0xe4, 0xb9, 0xd7, 0x76, 0x0e, },
+   16, 0
+},
+
+/* K=16, M=3 */
+{
+   { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+     0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F },
+   { 0x00, 0x01, 0x02 },
+   { 0x1c, 0x97, 0x40, 0x60, 0x6c, 0x58, 0x17, 0x2d,
+     0x03, 0x94, 0x19, 0x70, 0x81, 0xc4, 0x38, 0x54, },
+   16, 3
+},
+
+/* K=16, M=16 */
+{
+   { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+     0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F },
+   { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+     0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F },
+   { 0x03, 0xcc, 0x46, 0xb8, 0xac, 0xa7, 0x9c, 0x36,
+     0x1e, 0x8c, 0x6e, 0xa6, 0x7b, 0x89, 0x32, 0x49, },
+   16, 16
+},
+
+/* K=16, M=32 */
+{
+   { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+     0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F },
+   { 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 },
+   { 0x89, 0xcc, 0x36, 0x58, 0x1b, 0xdd, 0x4d, 0xb5,
+     0x78, 0xbb, 0xac, 0xf0, 0xff, 0x8b, 0x08, 0x15, },
+   16, 32
+},
+
+/* K=16, M=35 */
+{
+   { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+     0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F },
+   { 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,
+     0x20, 0x21, 0x23 },
+   { 0x4a, 0x7d, 0x45, 0x4d, 0xcd, 0xb5, 0xda, 0x8d,
+     0x48, 0x78, 0x16, 0x48, 0x5d, 0x45, 0x95, 0x99, },
+   16, 35
+},
+};
+   int x, err;
+   unsigned char out[16];
+   pelican_state pel;
+
+   for (x = 0; x < (int)(sizeof(tests)/sizeof(tests[0])); x++) {
+       if ((err = pelican_init(&pel, tests[x].K, tests[x].keylen)) != CRYPT_OK) {
+          return err;
+       }
+       if ((err = pelican_process(&pel, tests[x].MSG, tests[x].ptlen)) != CRYPT_OK) {
+          return err;
+       }
+       if ((err = pelican_done(&pel, out)) != CRYPT_OK) {
+          return err;
+       }
+
+       if (compare_testvector(out, 16, tests[x].T, 16, "PELICAN", x)) {
+           return CRYPT_FAIL_TESTVECTOR;
+       }
+   }
+   return CRYPT_OK;
+#endif
+}
+
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/mac/pmac/pmac_done.c b/libtomcrypt/src/mac/pmac/pmac_done.c
new file mode 100644 (file)
index 0000000..de7a5aa
--- /dev/null
@@ -0,0 +1,72 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file pmac_done.c
+  PMAC implementation, terminate a session, by Tom St Denis
+*/
+
+#ifdef LTC_PMAC
+
+int pmac_done(pmac_state *state, unsigned char *out, unsigned long *outlen)
+{
+   int err, x;
+
+   LTC_ARGCHK(state != NULL);
+   LTC_ARGCHK(out   != NULL);
+   if ((err = cipher_is_valid(state->cipher_idx)) != CRYPT_OK) {
+      return err;
+   }
+
+   if ((state->buflen > (int)sizeof(state->block)) || (state->buflen < 0) ||
+       (state->block_len > (int)sizeof(state->block)) || (state->buflen > state->block_len)) {
+      return CRYPT_INVALID_ARG;
+   }
+
+
+   /* handle padding.  If multiple xor in L/x */
+
+   if (state->buflen == state->block_len) {
+      /* xor Lr against the checksum */
+      for (x = 0; x < state->block_len; x++) {
+          state->checksum[x] ^= state->block[x] ^ state->Lr[x];
+      }
+   } else {
+      /* otherwise xor message bytes then the 0x80 byte */
+      for (x = 0; x < state->buflen; x++) {
+          state->checksum[x] ^= state->block[x];
+      }
+      state->checksum[x] ^= 0x80;
+   }
+
+   /* encrypt it */
+   if ((err = cipher_descriptor[state->cipher_idx].ecb_encrypt(state->checksum, state->checksum, &state->key)) != CRYPT_OK) {
+      return err;
+   }
+   cipher_descriptor[state->cipher_idx].done(&state->key);
+
+   /* store it */
+   for (x = 0; x < state->block_len && x < (int)*outlen; x++) {
+       out[x] = state->checksum[x];
+   }
+   *outlen = x;
+
+#ifdef LTC_CLEAN_STACK
+   zeromem(state, sizeof(*state));
+#endif
+   return CRYPT_OK;
+}
+
+#endif
+
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/mac/pmac/pmac_file.c b/libtomcrypt/src/mac/pmac/pmac_file.c
new file mode 100644 (file)
index 0000000..fe202a2
--- /dev/null
@@ -0,0 +1,98 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+   @file pmac_file.c
+   PMAC implementation, process a file, by Tom St Denis
+*/
+
+#ifdef LTC_PMAC
+
+/**
+   PMAC a file
+   @param cipher       The index of the cipher desired
+   @param key          The secret key
+   @param keylen       The length of the secret key (octets)
+   @param filename     The name of the file to send through PMAC
+   @param out          [out] Destination for the authentication tag
+   @param outlen       [in/out] Max size and resulting size of the authentication tag
+   @return CRYPT_OK if successful, CRYPT_NOP if file support has been disabled
+*/
+int pmac_file(int cipher,
+              const unsigned char *key, unsigned long keylen,
+              const char *filename,
+                    unsigned char *out, unsigned long *outlen)
+{
+#ifdef LTC_NO_FILE
+   LTC_UNUSED_PARAM(cipher);
+   LTC_UNUSED_PARAM(key);
+   LTC_UNUSED_PARAM(keylen);
+   LTC_UNUSED_PARAM(filename);
+   LTC_UNUSED_PARAM(out);
+   LTC_UNUSED_PARAM(outlen);
+   return CRYPT_NOP;
+#else
+   size_t x;
+   int err;
+   pmac_state pmac;
+   FILE *in;
+   unsigned char *buf;
+
+
+   LTC_ARGCHK(key      != NULL);
+   LTC_ARGCHK(filename != NULL);
+   LTC_ARGCHK(out      != NULL);
+   LTC_ARGCHK(outlen   != NULL);
+
+   if ((buf = XMALLOC(LTC_FILE_READ_BUFSIZE)) == NULL) {
+      return CRYPT_MEM;
+   }
+
+   if ((err = pmac_init(&pmac, cipher, key, keylen)) != CRYPT_OK) {
+      goto LBL_ERR;
+   }
+
+   in = fopen(filename, "rb");
+   if (in == NULL) {
+      err = CRYPT_FILE_NOTFOUND;
+      goto LBL_ERR;
+   }
+
+   do {
+      x = fread(buf, 1, LTC_FILE_READ_BUFSIZE, in);
+      if ((err = pmac_process(&pmac, buf, (unsigned long)x)) != CRYPT_OK) {
+         fclose(in);
+         goto LBL_CLEANBUF;
+      }
+   } while (x == LTC_FILE_READ_BUFSIZE);
+
+   if (fclose(in) != 0) {
+      err = CRYPT_ERROR;
+      goto LBL_CLEANBUF;
+   }
+
+   err = pmac_done(&pmac, out, outlen);
+
+LBL_CLEANBUF:
+   zeromem(buf, LTC_FILE_READ_BUFSIZE);
+LBL_ERR:
+#ifdef LTC_CLEAN_STACK
+   zeromem(&pmac, sizeof(pmac_state));
+#endif
+   XFREE(buf);
+   return err;
+#endif
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/mac/pmac/pmac_init.c b/libtomcrypt/src/mac/pmac/pmac_init.c
new file mode 100644 (file)
index 0000000..b1bb400
--- /dev/null
@@ -0,0 +1,148 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+   @file pmac_init.c
+   PMAC implementation, initialize state, by Tom St Denis
+*/
+
+#ifdef LTC_PMAC
+
+static const struct {
+    int           len;
+    unsigned char poly_div[MAXBLOCKSIZE],
+                  poly_mul[MAXBLOCKSIZE];
+} polys[] = {
+{
+    8,
+    { 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D },
+    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1B }
+}, {
+    16,
+    { 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43 },
+    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x87 }
+}
+};
+
+/**
+   Initialize a PMAC state
+   @param pmac      The PMAC state to initialize
+   @param cipher    The index of the desired cipher
+   @param key       The secret key
+   @param keylen    The length of the secret key (octets)
+   @return CRYPT_OK if successful
+*/
+int pmac_init(pmac_state *pmac, int cipher, const unsigned char *key, unsigned long keylen)
+{
+   int poly, x, y, m, err;
+   unsigned char *L;
+
+   LTC_ARGCHK(pmac  != NULL);
+   LTC_ARGCHK(key   != NULL);
+
+   /* valid cipher? */
+   if ((err = cipher_is_valid(cipher)) != CRYPT_OK) {
+      return err;
+   }
+
+   /* determine which polys to use */
+   pmac->block_len = cipher_descriptor[cipher].block_length;
+   for (poly = 0; poly < (int)(sizeof(polys)/sizeof(polys[0])); poly++) {
+       if (polys[poly].len == pmac->block_len) {
+          break;
+       }
+   }
+   if (poly >= (int)(sizeof(polys)/sizeof(polys[0]))) {
+      return CRYPT_INVALID_ARG;
+    }
+   if (polys[poly].len != pmac->block_len) {
+      return CRYPT_INVALID_ARG;
+   }
+
+#ifdef LTC_FAST
+   if (pmac->block_len % sizeof(LTC_FAST_TYPE)) {
+      return CRYPT_INVALID_ARG;
+   }
+#endif
+
+
+   /* schedule the key */
+   if ((err = cipher_descriptor[cipher].setup(key, keylen, 0, &pmac->key)) != CRYPT_OK) {
+      return err;
+   }
+
+   /* allocate L */
+   L = XMALLOC(pmac->block_len);
+   if (L == NULL) {
+      return CRYPT_MEM;
+   }
+
+   /* find L = E[0] */
+   zeromem(L, pmac->block_len);
+   if ((err = cipher_descriptor[cipher].ecb_encrypt(L, L, &pmac->key)) != CRYPT_OK) {
+      goto error;
+   }
+
+   /* find Ls[i] = L << i for i == 0..31 */
+   XMEMCPY(pmac->Ls[0], L, pmac->block_len);
+   for (x = 1; x < 32; x++) {
+       m = pmac->Ls[x-1][0] >> 7;
+       for (y = 0; y < pmac->block_len-1; y++) {
+           pmac->Ls[x][y] = ((pmac->Ls[x-1][y] << 1) | (pmac->Ls[x-1][y+1] >> 7)) & 255;
+       }
+       pmac->Ls[x][pmac->block_len-1] = (pmac->Ls[x-1][pmac->block_len-1] << 1) & 255;
+
+       if (m == 1) {
+          for (y = 0; y < pmac->block_len; y++) {
+              pmac->Ls[x][y] ^= polys[poly].poly_mul[y];
+          }
+       }
+    }
+
+   /* find Lr = L / x */
+   m = L[pmac->block_len-1] & 1;
+
+   /* shift right */
+   for (x = pmac->block_len - 1; x > 0; x--) {
+      pmac->Lr[x] = ((L[x] >> 1) | (L[x-1] << 7)) & 255;
+   }
+   pmac->Lr[0] = L[0] >> 1;
+
+   if (m == 1) {
+      for (x = 0; x < pmac->block_len; x++) {
+         pmac->Lr[x] ^= polys[poly].poly_div[x];
+      }
+   }
+
+   /* zero buffer, counters, etc... */
+   pmac->block_index = 1;
+   pmac->cipher_idx  = cipher;
+   pmac->buflen      = 0;
+   zeromem(pmac->block,    sizeof(pmac->block));
+   zeromem(pmac->Li,       sizeof(pmac->Li));
+   zeromem(pmac->checksum, sizeof(pmac->checksum));
+   err = CRYPT_OK;
+error:
+#ifdef LTC_CLEAN_STACK
+   zeromem(L, pmac->block_len);
+#endif
+
+   XFREE(L);
+
+   return err;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/mac/pmac/pmac_memory.c b/libtomcrypt/src/mac/pmac/pmac_memory.c
new file mode 100644 (file)
index 0000000..7842781
--- /dev/null
@@ -0,0 +1,72 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+   @file pmac_memory.c
+   PMAC implementation, process a block of memory, by Tom St Denis
+*/
+
+#ifdef LTC_PMAC
+
+/**
+   PMAC a block of memory
+   @param cipher   The index of the cipher desired
+   @param key      The secret key
+   @param keylen   The length of the secret key (octets)
+   @param in       The data you wish to send through PMAC
+   @param inlen    The length of data you wish to send through PMAC (octets)
+   @param out      [out] Destination for the authentication tag
+   @param outlen   [in/out] The max size and resulting size of the authentication tag
+   @return CRYPT_OK if successful
+*/
+int pmac_memory(int cipher,
+                const unsigned char *key, unsigned long keylen,
+                const unsigned char *in, unsigned long inlen,
+                      unsigned char *out, unsigned long *outlen)
+{
+   int err;
+   pmac_state *pmac;
+
+   LTC_ARGCHK(key    != NULL);
+   LTC_ARGCHK(in    != NULL);
+   LTC_ARGCHK(out    != NULL);
+   LTC_ARGCHK(outlen != NULL);
+
+   /* allocate ram for pmac state */
+   pmac = XMALLOC(sizeof(pmac_state));
+   if (pmac == NULL) {
+      return CRYPT_MEM;
+   }
+
+   if ((err = pmac_init(pmac, cipher, key, keylen)) != CRYPT_OK) {
+      goto LBL_ERR;
+   }
+   if ((err = pmac_process(pmac, in, inlen)) != CRYPT_OK) {
+      goto LBL_ERR;
+   }
+   if ((err = pmac_done(pmac, out, outlen)) != CRYPT_OK) {
+      goto LBL_ERR;
+   }
+
+   err = CRYPT_OK;
+LBL_ERR:
+#ifdef LTC_CLEAN_STACK
+   zeromem(pmac, sizeof(pmac_state));
+#endif
+
+   XFREE(pmac);
+   return err;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/mac/pmac/pmac_memory_multi.c b/libtomcrypt/src/mac/pmac/pmac_memory_multi.c
new file mode 100644 (file)
index 0000000..f3de4b5
--- /dev/null
@@ -0,0 +1,87 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+#include <stdarg.h>
+
+/**
+   @file pmac_memory_multi.c
+   PMAC implementation, process multiple blocks of memory, by Tom St Denis
+*/
+
+#ifdef LTC_PMAC
+
+/**
+   PMAC multiple blocks of memory
+   @param cipher   The index of the cipher desired
+   @param key      The secret key
+   @param keylen   The length of the secret key (octets)
+   @param out      [out] Destination for the authentication tag
+   @param outlen   [in/out] The max size and resulting size of the authentication tag
+   @param in       The data you wish to send through PMAC
+   @param inlen    The length of data you wish to send through PMAC (octets)
+   @param ...      tuples of (data,len) pairs to PMAC, terminated with a (NULL,x) (x=don't care)
+   @return CRYPT_OK if successful
+*/
+int pmac_memory_multi(int cipher,
+                const unsigned char *key, unsigned long  keylen,
+                      unsigned char *out, unsigned long *outlen,
+                const unsigned char *in,  unsigned long  inlen, ...)
+{
+   int                  err;
+   pmac_state          *pmac;
+   va_list              args;
+   const unsigned char *curptr;
+   unsigned long        curlen;
+
+   LTC_ARGCHK(key    != NULL);
+   LTC_ARGCHK(in     != NULL);
+   LTC_ARGCHK(out    != NULL);
+   LTC_ARGCHK(outlen != NULL);
+
+   /* allocate ram for pmac state */
+   pmac = XMALLOC(sizeof(pmac_state));
+   if (pmac == NULL) {
+      return CRYPT_MEM;
+   }
+
+   if ((err = pmac_init(pmac, cipher, key, keylen)) != CRYPT_OK) {
+      goto LBL_ERR;
+   }
+   va_start(args, inlen);
+   curptr = in;
+   curlen = inlen;
+   for (;;) {
+      /* process buf */
+      if ((err = pmac_process(pmac, curptr, curlen)) != CRYPT_OK) {
+         goto LBL_ERR;
+      }
+      /* step to next */
+      curptr = va_arg(args, const unsigned char*);
+      if (curptr == NULL) {
+         break;
+      }
+      curlen = va_arg(args, unsigned long);
+   }
+   if ((err = pmac_done(pmac, out, outlen)) != CRYPT_OK) {
+      goto LBL_ERR;
+   }
+LBL_ERR:
+#ifdef LTC_CLEAN_STACK
+   zeromem(pmac, sizeof(pmac_state));
+#endif
+   XFREE(pmac);
+   va_end(args);
+   return err;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/mac/pmac/pmac_ntz.c b/libtomcrypt/src/mac/pmac/pmac_ntz.c
new file mode 100644 (file)
index 0000000..2c7dec5
--- /dev/null
@@ -0,0 +1,37 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+   @file pmac_ntz.c
+   PMAC implementation, internal function, by Tom St Denis
+*/
+
+#ifdef LTC_PMAC
+
+/**
+  Internal PMAC function
+*/
+int pmac_ntz(unsigned long x)
+{
+   int c;
+   x &= 0xFFFFFFFFUL;
+   c = 0;
+   while ((x & 1) == 0) {
+      ++c;
+      x >>= 1;
+   }
+   return c;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/mac/pmac/pmac_process.c b/libtomcrypt/src/mac/pmac/pmac_process.c
new file mode 100644 (file)
index 0000000..018fa27
--- /dev/null
@@ -0,0 +1,98 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+   @file pmac_process.c
+   PMAC implementation, process data, by Tom St Denis
+*/
+
+
+#ifdef LTC_PMAC
+
+/**
+  Process data in a PMAC stream
+  @param pmac     The PMAC state
+  @param in       The data to send through PMAC
+  @param inlen    The length of the data to send through PMAC
+  @return CRYPT_OK if successful
+*/
+int pmac_process(pmac_state *pmac, const unsigned char *in, unsigned long inlen)
+{
+   int err, n;
+   unsigned long x;
+   unsigned char Z[MAXBLOCKSIZE];
+
+   LTC_ARGCHK(pmac != NULL);
+   LTC_ARGCHK(in   != NULL);
+   if ((err = cipher_is_valid(pmac->cipher_idx)) != CRYPT_OK) {
+      return err;
+   }
+
+   if ((pmac->buflen > (int)sizeof(pmac->block)) || (pmac->buflen < 0) ||
+       (pmac->block_len > (int)sizeof(pmac->block)) || (pmac->buflen > pmac->block_len)) {
+      return CRYPT_INVALID_ARG;
+   }
+
+#ifdef LTC_FAST
+   if (pmac->buflen == 0 && inlen > 16) {
+      unsigned long y;
+      for (x = 0; x < (inlen - 16); x += 16) {
+          pmac_shift_xor(pmac);
+          for (y = 0; y < 16; y += sizeof(LTC_FAST_TYPE)) {
+              *(LTC_FAST_TYPE_PTR_CAST(&Z[y])) = *(LTC_FAST_TYPE_PTR_CAST(&in[y])) ^ *(LTC_FAST_TYPE_PTR_CAST(&pmac->Li[y]));
+          }
+          if ((err = cipher_descriptor[pmac->cipher_idx].ecb_encrypt(Z, Z, &pmac->key)) != CRYPT_OK) {
+             return err;
+          }
+          for (y = 0; y < 16; y += sizeof(LTC_FAST_TYPE)) {
+              *(LTC_FAST_TYPE_PTR_CAST(&pmac->checksum[y])) ^= *(LTC_FAST_TYPE_PTR_CAST(&Z[y]));
+          }
+          in += 16;
+      }
+      inlen -= x;
+   }
+#endif
+
+   while (inlen != 0) {
+       /* ok if the block is full we xor in prev, encrypt and replace prev */
+       if (pmac->buflen == pmac->block_len) {
+          pmac_shift_xor(pmac);
+          for (x = 0; x < (unsigned long)pmac->block_len; x++) {
+               Z[x] = pmac->Li[x] ^ pmac->block[x];
+          }
+          if ((err = cipher_descriptor[pmac->cipher_idx].ecb_encrypt(Z, Z, &pmac->key)) != CRYPT_OK) {
+             return err;
+           }
+          for (x = 0; x < (unsigned long)pmac->block_len; x++) {
+              pmac->checksum[x] ^= Z[x];
+          }
+          pmac->buflen = 0;
+       }
+
+       /* add bytes */
+       n = MIN(inlen, (unsigned long)(pmac->block_len - pmac->buflen));
+       XMEMCPY(pmac->block + pmac->buflen, in, n);
+       pmac->buflen  += n;
+       inlen         -= n;
+       in            += n;
+   }
+
+#ifdef LTC_CLEAN_STACK
+   zeromem(Z, sizeof(Z));
+#endif
+
+   return CRYPT_OK;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/mac/pmac/pmac_shift_xor.c b/libtomcrypt/src/mac/pmac/pmac_shift_xor.c
new file mode 100644 (file)
index 0000000..49d48f9
--- /dev/null
@@ -0,0 +1,42 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+   @file pmac_shift_xor.c
+   PMAC implementation, internal function, by Tom St Denis
+*/
+
+#ifdef LTC_PMAC
+
+/**
+  Internal function.  Performs the state update (adding correct multiple)
+  @param pmac   The PMAC state.
+*/
+void pmac_shift_xor(pmac_state *pmac)
+{
+   int x, y;
+   y = pmac_ntz(pmac->block_index++);
+#ifdef LTC_FAST
+   for (x = 0; x < pmac->block_len; x += sizeof(LTC_FAST_TYPE)) {
+       *(LTC_FAST_TYPE_PTR_CAST((unsigned char *)pmac->Li + x)) ^=
+       *(LTC_FAST_TYPE_PTR_CAST((unsigned char *)pmac->Ls[y] + x));
+   }
+#else
+   for (x = 0; x < pmac->block_len; x++) {
+       pmac->Li[x] ^= pmac->Ls[y][x];
+   }
+#endif
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/mac/pmac/pmac_test.c b/libtomcrypt/src/mac/pmac/pmac_test.c
new file mode 100644 (file)
index 0000000..19329c6
--- /dev/null
@@ -0,0 +1,154 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+   @file pmac_test.c
+   PMAC implementation, self-test, by Tom St Denis
+*/
+
+
+#ifdef LTC_PMAC
+
+/**
+   Test the LTC_OMAC implementation
+   @return CRYPT_OK if successful, CRYPT_NOP if testing has been disabled
+*/
+int pmac_test(void)
+{
+#if !defined(LTC_TEST)
+    return CRYPT_NOP;
+#else
+    static const struct {
+        int msglen;
+        unsigned char key[16], msg[34], tag[16];
+    } tests[] = {
+
+   /* PMAC-AES-128-0B */
+{
+   0,
+   /* key */
+   { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+     0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f },
+   /* msg */
+   { 0x00 },
+   /* tag */
+   { 0x43, 0x99, 0x57, 0x2c, 0xd6, 0xea, 0x53, 0x41,
+     0xb8, 0xd3, 0x58, 0x76, 0xa7, 0x09, 0x8a, 0xf7 }
+},
+
+   /* PMAC-AES-128-3B */
+{
+   3,
+   /* key */
+   { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+     0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f },
+   /* msg */
+   { 0x00, 0x01, 0x02 },
+   /* tag */
+   { 0x25, 0x6b, 0xa5, 0x19, 0x3c, 0x1b, 0x99, 0x1b,
+     0x4d, 0xf0, 0xc5, 0x1f, 0x38, 0x8a, 0x9e, 0x27 }
+},
+
+   /* PMAC-AES-128-16B */
+{
+   16,
+   /* key */
+   { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+     0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f },
+   /* msg */
+   { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+     0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f },
+   /* tag */
+   { 0xeb, 0xbd, 0x82, 0x2f, 0xa4, 0x58, 0xda, 0xf6,
+     0xdf, 0xda, 0xd7, 0xc2, 0x7d, 0xa7, 0x63, 0x38 }
+},
+
+   /* PMAC-AES-128-20B */
+{
+   20,
+   /* key */
+   { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+     0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f },
+   /* msg */
+   { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+     0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+     0x10, 0x11, 0x12, 0x13 },
+   /* tag */
+   { 0x04, 0x12, 0xca, 0x15, 0x0b, 0xbf, 0x79, 0x05,
+     0x8d, 0x8c, 0x75, 0xa5, 0x8c, 0x99, 0x3f, 0x55 }
+},
+
+   /* PMAC-AES-128-32B */
+{
+   32,
+   /* key */
+   { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+     0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f },
+   /* msg */
+   { 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 },
+   /* tag */
+   { 0xe9, 0x7a, 0xc0, 0x4e, 0x9e, 0x5e, 0x33, 0x99,
+     0xce, 0x53, 0x55, 0xcd, 0x74, 0x07, 0xbc, 0x75 }
+},
+
+   /* PMAC-AES-128-34B */
+{
+   34,
+   /* key */
+   { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+     0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f },
+   /* msg */
+   { 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,
+     0x20, 0x21 },
+   /* tag */
+   { 0x5c, 0xba, 0x7d, 0x5e, 0xb2, 0x4f, 0x7c, 0x86,
+     0xcc, 0xc5, 0x46, 0x04, 0xe5, 0x3d, 0x55, 0x12 }
+}
+
+};
+   int err, x, idx;
+   unsigned long len;
+   unsigned char outtag[MAXBLOCKSIZE];
+
+    /* AES can be under rijndael or aes... try to find it */
+    if ((idx = find_cipher("aes")) == -1) {
+       if ((idx = find_cipher("rijndael")) == -1) {
+          return CRYPT_NOP;
+       }
+    }
+
+    for (x = 0; x < (int)(sizeof(tests)/sizeof(tests[0])); x++) {
+        len = sizeof(outtag);
+        if ((err = pmac_memory(idx, tests[x].key, 16, tests[x].msg, tests[x].msglen, outtag, &len)) != CRYPT_OK) {
+           return err;
+        }
+
+        if (compare_testvector(outtag, len, tests[x].tag, sizeof(tests[x].tag), "PMAC", x)) {
+           return CRYPT_FAIL_TESTVECTOR;
+        }
+    }
+    return CRYPT_OK;
+#endif /* LTC_TEST */
+}
+
+#endif /* PMAC_MODE */
+
+
+
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/mac/poly1305/poly1305.c b/libtomcrypt/src/mac/poly1305/poly1305.c
new file mode 100644 (file)
index 0000000..f709f72
--- /dev/null
@@ -0,0 +1,268 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+/* The implementation is based on:
+ * Public Domain poly1305 from Andrew Moon
+ * https://github.com/floodyberry/poly1305-donna
+ */
+
+#include "tomcrypt.h"
+
+#ifdef LTC_POLY1305
+
+/* internal only */
+static void _poly1305_block(poly1305_state *st, const unsigned char *in, unsigned long inlen)
+{
+   const unsigned long hibit = (st->final) ? 0 : (1UL << 24); /* 1 << 128 */
+   ulong32 r0,r1,r2,r3,r4;
+   ulong32 s1,s2,s3,s4;
+   ulong32 h0,h1,h2,h3,h4;
+   ulong32 tmp;
+   ulong64 d0,d1,d2,d3,d4;
+   ulong32 c;
+
+   r0 = st->r[0];
+   r1 = st->r[1];
+   r2 = st->r[2];
+   r3 = st->r[3];
+   r4 = st->r[4];
+
+   s1 = r1 * 5;
+   s2 = r2 * 5;
+   s3 = r3 * 5;
+   s4 = r4 * 5;
+
+   h0 = st->h[0];
+   h1 = st->h[1];
+   h2 = st->h[2];
+   h3 = st->h[3];
+   h4 = st->h[4];
+
+   while (inlen >= 16) {
+      /* h += in[i] */
+      LOAD32L(tmp, in+ 0); h0 += (tmp     ) & 0x3ffffff;
+      LOAD32L(tmp, in+ 3); h1 += (tmp >> 2) & 0x3ffffff;
+      LOAD32L(tmp, in+ 6); h2 += (tmp >> 4) & 0x3ffffff;
+      LOAD32L(tmp, in+ 9); h3 += (tmp >> 6) & 0x3ffffff;
+      LOAD32L(tmp, in+12); h4 += (tmp >> 8) | hibit;
+
+      /* h *= r */
+      d0 = ((ulong64)h0 * r0) + ((ulong64)h1 * s4) + ((ulong64)h2 * s3) + ((ulong64)h3 * s2) + ((ulong64)h4 * s1);
+      d1 = ((ulong64)h0 * r1) + ((ulong64)h1 * r0) + ((ulong64)h2 * s4) + ((ulong64)h3 * s3) + ((ulong64)h4 * s2);
+      d2 = ((ulong64)h0 * r2) + ((ulong64)h1 * r1) + ((ulong64)h2 * r0) + ((ulong64)h3 * s4) + ((ulong64)h4 * s3);
+      d3 = ((ulong64)h0 * r3) + ((ulong64)h1 * r2) + ((ulong64)h2 * r1) + ((ulong64)h3 * r0) + ((ulong64)h4 * s4);
+      d4 = ((ulong64)h0 * r4) + ((ulong64)h1 * r3) + ((ulong64)h2 * r2) + ((ulong64)h3 * r1) + ((ulong64)h4 * r0);
+
+      /* (partial) h %= p */
+                    c = (ulong32)(d0 >> 26); h0 = (ulong32)d0 & 0x3ffffff;
+      d1 += c;      c = (ulong32)(d1 >> 26); h1 = (ulong32)d1 & 0x3ffffff;
+      d2 += c;      c = (ulong32)(d2 >> 26); h2 = (ulong32)d2 & 0x3ffffff;
+      d3 += c;      c = (ulong32)(d3 >> 26); h3 = (ulong32)d3 & 0x3ffffff;
+      d4 += c;      c = (ulong32)(d4 >> 26); h4 = (ulong32)d4 & 0x3ffffff;
+      h0 += c * 5;  c =          (h0 >> 26); h0 =          h0 & 0x3ffffff;
+      h1 += c;
+
+      in += 16;
+      inlen -= 16;
+   }
+
+   st->h[0] = h0;
+   st->h[1] = h1;
+   st->h[2] = h2;
+   st->h[3] = h3;
+   st->h[4] = h4;
+}
+
+/**
+   Initialize an POLY1305 context.
+   @param st       The POLY1305 state
+   @param key      The secret key
+   @param keylen   The length of the secret key (octets)
+   @return CRYPT_OK if successful
+*/
+int poly1305_init(poly1305_state *st, const unsigned char *key, unsigned long keylen)
+{
+   LTC_ARGCHK(st  != NULL);
+   LTC_ARGCHK(key != NULL);
+   LTC_ARGCHK(keylen == 32);
+
+   /* r &= 0xffffffc0ffffffc0ffffffc0fffffff */
+   LOAD32L(st->r[0], key +  0); st->r[0] = (st->r[0]     ) & 0x3ffffff;
+   LOAD32L(st->r[1], key +  3); st->r[1] = (st->r[1] >> 2) & 0x3ffff03;
+   LOAD32L(st->r[2], key +  6); st->r[2] = (st->r[2] >> 4) & 0x3ffc0ff;
+   LOAD32L(st->r[3], key +  9); st->r[3] = (st->r[3] >> 6) & 0x3f03fff;
+   LOAD32L(st->r[4], key + 12); st->r[4] = (st->r[4] >> 8) & 0x00fffff;
+
+   /* h = 0 */
+   st->h[0] = 0;
+   st->h[1] = 0;
+   st->h[2] = 0;
+   st->h[3] = 0;
+   st->h[4] = 0;
+
+   /* save pad for later */
+   LOAD32L(st->pad[0], key + 16);
+   LOAD32L(st->pad[1], key + 20);
+   LOAD32L(st->pad[2], key + 24);
+   LOAD32L(st->pad[3], key + 28);
+
+   st->leftover = 0;
+   st->final = 0;
+   return CRYPT_OK;
+}
+
+/**
+  Process data through POLY1305
+  @param st      The POLY1305 state
+  @param in      The data to send through HMAC
+  @param inlen   The length of the data to HMAC (octets)
+  @return CRYPT_OK if successful
+*/
+int poly1305_process(poly1305_state *st, const unsigned char *in, unsigned long inlen)
+{
+   unsigned long i;
+
+   if (inlen == 0) return CRYPT_OK; /* nothing to do */
+   LTC_ARGCHK(st != NULL);
+   LTC_ARGCHK(in != NULL);
+
+   /* handle leftover */
+   if (st->leftover) {
+      unsigned long want = (16 - st->leftover);
+      if (want > inlen) want = inlen;
+      for (i = 0; i < want; i++) st->buffer[st->leftover + i] = in[i];
+      inlen -= want;
+      in += want;
+      st->leftover += want;
+      if (st->leftover < 16) return CRYPT_OK;
+      _poly1305_block(st, st->buffer, 16);
+      st->leftover = 0;
+   }
+
+   /* process full blocks */
+   if (inlen >= 16) {
+      unsigned long want = (inlen & ~(16 - 1));
+      _poly1305_block(st, in, want);
+      in += want;
+      inlen -= want;
+   }
+
+   /* store leftover */
+   if (inlen) {
+      for (i = 0; i < inlen; i++) st->buffer[st->leftover + i] = in[i];
+      st->leftover += inlen;
+   }
+   return CRYPT_OK;
+}
+
+/**
+   Terminate a POLY1305 session
+   @param st      The POLY1305 state
+   @param mac     [out] The destination of the POLY1305 authentication tag
+   @param maclen  [in/out]  The max size and resulting size of the POLY1305 authentication tag
+   @return CRYPT_OK if successful
+*/
+int poly1305_done(poly1305_state *st, unsigned char *mac, unsigned long *maclen)
+{
+   ulong32 h0,h1,h2,h3,h4,c;
+   ulong32 g0,g1,g2,g3,g4;
+   ulong64 f;
+   ulong32 mask;
+
+   LTC_ARGCHK(st     != NULL);
+   LTC_ARGCHK(mac    != NULL);
+   LTC_ARGCHK(maclen != NULL);
+   LTC_ARGCHK(*maclen >= 16);
+
+   /* process the remaining block */
+   if (st->leftover) {
+      unsigned long i = st->leftover;
+      st->buffer[i++] = 1;
+      for (; i < 16; i++) st->buffer[i] = 0;
+      st->final = 1;
+      _poly1305_block(st, st->buffer, 16);
+   }
+
+   /* fully carry h */
+   h0 = st->h[0];
+   h1 = st->h[1];
+   h2 = st->h[2];
+   h3 = st->h[3];
+   h4 = st->h[4];
+
+                c = h1 >> 26; h1 = h1 & 0x3ffffff;
+   h2 +=     c; c = h2 >> 26; h2 = h2 & 0x3ffffff;
+   h3 +=     c; c = h3 >> 26; h3 = h3 & 0x3ffffff;
+   h4 +=     c; c = h4 >> 26; h4 = h4 & 0x3ffffff;
+   h0 += c * 5; c = h0 >> 26; h0 = h0 & 0x3ffffff;
+   h1 +=     c;
+
+   /* compute h + -p */
+   g0 = h0 + 5; c = g0 >> 26; g0 &= 0x3ffffff;
+   g1 = h1 + c; c = g1 >> 26; g1 &= 0x3ffffff;
+   g2 = h2 + c; c = g2 >> 26; g2 &= 0x3ffffff;
+   g3 = h3 + c; c = g3 >> 26; g3 &= 0x3ffffff;
+   g4 = h4 + c - (1UL << 26);
+
+   /* select h if h < p, or h + -p if h >= p */
+   mask = (g4 >> 31) - 1;
+   g0 &= mask;
+   g1 &= mask;
+   g2 &= mask;
+   g3 &= mask;
+   g4 &= mask;
+   mask = ~mask;
+   h0 = (h0 & mask) | g0;
+   h1 = (h1 & mask) | g1;
+   h2 = (h2 & mask) | g2;
+   h3 = (h3 & mask) | g3;
+   h4 = (h4 & mask) | g4;
+
+   /* h = h % (2^128) */
+   h0 = ((h0      ) | (h1 << 26)) & 0xffffffff;
+   h1 = ((h1 >>  6) | (h2 << 20)) & 0xffffffff;
+   h2 = ((h2 >> 12) | (h3 << 14)) & 0xffffffff;
+   h3 = ((h3 >> 18) | (h4 <<  8)) & 0xffffffff;
+
+   /* mac = (h + pad) % (2^128) */
+   f = (ulong64)h0 + st->pad[0]            ; h0 = (ulong32)f;
+   f = (ulong64)h1 + st->pad[1] + (f >> 32); h1 = (ulong32)f;
+   f = (ulong64)h2 + st->pad[2] + (f >> 32); h2 = (ulong32)f;
+   f = (ulong64)h3 + st->pad[3] + (f >> 32); h3 = (ulong32)f;
+
+   STORE32L(h0, mac +  0);
+   STORE32L(h1, mac +  4);
+   STORE32L(h2, mac +  8);
+   STORE32L(h3, mac + 12);
+
+   /* zero out the state */
+   st->h[0] = 0;
+   st->h[1] = 0;
+   st->h[2] = 0;
+   st->h[3] = 0;
+   st->h[4] = 0;
+   st->r[0] = 0;
+   st->r[1] = 0;
+   st->r[2] = 0;
+   st->r[3] = 0;
+   st->r[4] = 0;
+   st->pad[0] = 0;
+   st->pad[1] = 0;
+   st->pad[2] = 0;
+   st->pad[3] = 0;
+
+   *maclen = 16;
+   return CRYPT_OK;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/mac/poly1305/poly1305_file.c b/libtomcrypt/src/mac/poly1305/poly1305_file.c
new file mode 100644 (file)
index 0000000..e57437b
--- /dev/null
@@ -0,0 +1,93 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+/* The implementation is based on:
+ * Public Domain poly1305 from Andrew Moon
+ * https://github.com/floodyberry/poly1305-donna
+ */
+
+#include "tomcrypt.h"
+
+#ifdef LTC_POLY1305
+
+/**
+  POLY1305 a file
+  @param fname    The name of the file you wish to POLY1305
+  @param key      The secret key
+  @param keylen   The length of the secret key
+  @param mac      [out] The POLY1305 authentication tag
+  @param maclen   [in/out]  The max size and resulting size of the authentication tag
+  @return CRYPT_OK if successful, CRYPT_NOP if file support has been disabled
+*/
+int poly1305_file(const char *fname, const unsigned char *key, unsigned long keylen, unsigned char *mac, unsigned long *maclen)
+{
+#ifdef LTC_NO_FILE
+   LTC_UNUSED_PARAM(fname);
+   LTC_UNUSED_PARAM(key);
+   LTC_UNUSED_PARAM(keylen);
+   LTC_UNUSED_PARAM(mac);
+   LTC_UNUSED_PARAM(maclen);
+   return CRYPT_NOP;
+#else
+   poly1305_state st;
+   FILE *in;
+   unsigned char *buf;
+   size_t x;
+   int err;
+
+   LTC_ARGCHK(fname  != NULL);
+   LTC_ARGCHK(key    != NULL);
+   LTC_ARGCHK(mac    != NULL);
+   LTC_ARGCHK(maclen != NULL);
+
+   if ((buf = XMALLOC(LTC_FILE_READ_BUFSIZE)) == NULL) {
+      return CRYPT_MEM;
+   }
+
+   if ((err = poly1305_init(&st, key, keylen)) != CRYPT_OK) {
+      goto LBL_ERR;
+   }
+
+   in = fopen(fname, "rb");
+   if (in == NULL) {
+      err = CRYPT_FILE_NOTFOUND;
+      goto LBL_ERR;
+   }
+
+   do {
+      x = fread(buf, 1, LTC_FILE_READ_BUFSIZE, in);
+      if ((err = poly1305_process(&st, buf, (unsigned long)x)) != CRYPT_OK) {
+         fclose(in);
+         goto LBL_CLEANBUF;
+      }
+   } while (x == LTC_FILE_READ_BUFSIZE);
+
+   if (fclose(in) != 0) {
+      err = CRYPT_ERROR;
+      goto LBL_CLEANBUF;
+   }
+
+   err = poly1305_done(&st, mac, maclen);
+
+LBL_CLEANBUF:
+   zeromem(buf, LTC_FILE_READ_BUFSIZE);
+LBL_ERR:
+#ifdef LTC_CLEAN_STACK
+   zeromem(&st, sizeof(poly1305_state));
+#endif
+   XFREE(buf);
+   return err;
+#endif
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/mac/poly1305/poly1305_memory.c b/libtomcrypt/src/mac/poly1305/poly1305_memory.c
new file mode 100644 (file)
index 0000000..a827f8d
--- /dev/null
@@ -0,0 +1,53 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+/* The implementation is based on:
+ * Public Domain poly1305 from Andrew Moon
+ * https://github.com/floodyberry/poly1305-donna
+ */
+
+#include "tomcrypt.h"
+
+#ifdef LTC_POLY1305
+
+/**
+   POLY1305 a block of memory to produce the authentication tag
+   @param key       The secret key
+   @param keylen    The length of the secret key (octets)
+   @param in        The data to POLY1305
+   @param inlen     The length of the data to POLY1305 (octets)
+   @param mac       [out] Destination of the authentication tag
+   @param maclen    [in/out] Max size and resulting size of authentication tag
+   @return CRYPT_OK if successful
+*/
+int poly1305_memory(const unsigned char *key, unsigned long keylen, const unsigned char *in, unsigned long inlen, unsigned char *mac, unsigned long *maclen)
+{
+   poly1305_state st;
+   int err;
+
+   LTC_ARGCHK(key    != NULL);
+   LTC_ARGCHK(in     != NULL);
+   LTC_ARGCHK(mac    != NULL);
+   LTC_ARGCHK(maclen != NULL);
+
+   if ((err = poly1305_init(&st, key, keylen))  != CRYPT_OK) { goto LBL_ERR; }
+   if ((err = poly1305_process(&st, in, inlen)) != CRYPT_OK) { goto LBL_ERR; }
+   err = poly1305_done(&st, mac, maclen);
+LBL_ERR:
+#ifdef LTC_CLEAN_STACK
+   zeromem(&st, sizeof(poly1305_state));
+#endif
+   return err;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/mac/poly1305/poly1305_memory_multi.c b/libtomcrypt/src/mac/poly1305/poly1305_memory_multi.c
new file mode 100644 (file)
index 0000000..f22f255
--- /dev/null
@@ -0,0 +1,67 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+/* The implementation is based on:
+ * Public Domain poly1305 from Andrew Moon
+ * https://github.com/floodyberry/poly1305-donna
+ */
+
+#include "tomcrypt.h"
+#include <stdarg.h>
+
+#ifdef LTC_POLY1305
+
+/**
+   POLY1305 multiple blocks of memory to produce the authentication tag
+   @param key       The secret key
+   @param keylen    The length of the secret key (octets)
+   @param mac       [out] Destination of the authentication tag
+   @param maclen    [in/out] Max size and resulting size of authentication tag
+   @param in        The data to POLY1305
+   @param inlen     The length of the data to POLY1305 (octets)
+   @param ...       tuples of (data,len) pairs to POLY1305, terminated with a (NULL,x) (x=don't care)
+   @return CRYPT_OK if successful
+*/
+int poly1305_memory_multi(const unsigned char *key, unsigned long keylen, unsigned char *mac, unsigned long *maclen, const unsigned char *in,  unsigned long inlen, ...)
+{
+   poly1305_state st;
+   int err;
+   va_list args;
+   const unsigned char *curptr;
+   unsigned long curlen;
+
+   LTC_ARGCHK(key    != NULL);
+   LTC_ARGCHK(in     != NULL);
+   LTC_ARGCHK(mac    != NULL);
+   LTC_ARGCHK(maclen != NULL);
+
+   va_start(args, inlen);
+   curptr = in;
+   curlen = inlen;
+   if ((err = poly1305_init(&st, key, keylen)) != CRYPT_OK)          { goto LBL_ERR; }
+   for (;;) {
+      if ((err = poly1305_process(&st, curptr, curlen)) != CRYPT_OK) { goto LBL_ERR; }
+      curptr = va_arg(args, const unsigned char*);
+      if (curptr == NULL) break;
+      curlen = va_arg(args, unsigned long);
+   }
+   err = poly1305_done(&st, mac, maclen);
+LBL_ERR:
+#ifdef LTC_CLEAN_STACK
+   zeromem(&st, sizeof(poly1305_state));
+#endif
+   va_end(args);
+   return err;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/mac/poly1305/poly1305_test.c b/libtomcrypt/src/mac/poly1305/poly1305_test.c
new file mode 100644 (file)
index 0000000..5e4535b
--- /dev/null
@@ -0,0 +1,56 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+/* The implementation is based on:
+ * Public Domain poly1305 from Andrew Moon
+ * https://github.com/floodyberry/poly1305-donna
+ */
+
+#include "tomcrypt.h"
+
+#ifdef LTC_POLY1305
+
+int poly1305_test(void)
+{
+#ifndef LTC_TEST
+   return CRYPT_NOP;
+#else
+   /* https://tools.ietf.org/html/rfc7539#section-2.5.2 */
+   unsigned char k[]   = { 0x85, 0xd6, 0xbe, 0x78, 0x57, 0x55, 0x6d, 0x33, 0x7f, 0x44, 0x52, 0xfe, 0x42, 0xd5, 0x06, 0xa8, 0x01, 0x03, 0x80, 0x8a, 0xfb, 0x0d, 0xb2, 0xfd, 0x4a, 0xbf, 0xf6, 0xaf, 0x41, 0x49, 0xf5, 0x1b };
+   unsigned char tag[] = { 0xA8, 0x06, 0x1D, 0xC1, 0x30, 0x51, 0x36, 0xC6, 0xC2, 0x2B, 0x8B, 0xAF, 0x0C, 0x01, 0x27, 0xA9 };
+   char m[] = "Cryptographic Forum Research Group";
+   unsigned long len = 16, mlen = strlen(m);
+   unsigned char out[1000];
+   poly1305_state st;
+   int err;
+
+   /* process piece by piece */
+   if ((err = poly1305_init(&st, k, 32)) != CRYPT_OK)                                return err;
+   if ((err = poly1305_process(&st, (unsigned char*)m,      5)) != CRYPT_OK)         return err;
+   if ((err = poly1305_process(&st, (unsigned char*)m + 5,  4)) != CRYPT_OK)         return err;
+   if ((err = poly1305_process(&st, (unsigned char*)m + 9,  3)) != CRYPT_OK)         return err;
+   if ((err = poly1305_process(&st, (unsigned char*)m + 12, 2)) != CRYPT_OK)         return err;
+   if ((err = poly1305_process(&st, (unsigned char*)m + 14, 1)) != CRYPT_OK)         return err;
+   if ((err = poly1305_process(&st, (unsigned char*)m + 15, mlen - 15)) != CRYPT_OK) return err;
+   if ((err = poly1305_done(&st, out, &len)) != CRYPT_OK)                            return err;
+   if (compare_testvector(out, len, tag, sizeof(tag), "POLY1305-TV1", 1) != 0)       return CRYPT_FAIL_TESTVECTOR;
+   /* process in one go */
+   if ((err = poly1305_init(&st, k, 32)) != CRYPT_OK)                                return err;
+   if ((err = poly1305_process(&st, (unsigned char*)m, mlen)) != CRYPT_OK)           return err;
+   if ((err = poly1305_done(&st, out, &len)) != CRYPT_OK)                            return err;
+   if (compare_testvector(out, len, tag, sizeof(tag), "POLY1305-TV2", 1) != 0)       return CRYPT_FAIL_TESTVECTOR;
+   return CRYPT_OK;
+#endif
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/mac/xcbc/xcbc_done.c b/libtomcrypt/src/mac/xcbc/xcbc_done.c
new file mode 100644 (file)
index 0000000..133d16f
--- /dev/null
@@ -0,0 +1,75 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file xcbc_done.c
+  XCBC Support, terminate the state
+*/
+
+#ifdef LTC_XCBC
+
+/** Terminate the XCBC-MAC state
+  @param xcbc     XCBC state to terminate
+  @param out      [out] Destination for the MAC tag
+  @param outlen   [in/out] Destination size and final tag size
+  Return CRYPT_OK on success
+*/
+int xcbc_done(xcbc_state *xcbc, unsigned char *out, unsigned long *outlen)
+{
+   int err, x;
+   LTC_ARGCHK(xcbc != NULL);
+   LTC_ARGCHK(out  != NULL);
+
+   /* check structure */
+   if ((err = cipher_is_valid(xcbc->cipher)) != CRYPT_OK) {
+      return err;
+   }
+
+   if ((xcbc->blocksize > cipher_descriptor[xcbc->cipher].block_length) || (xcbc->blocksize < 0) ||
+       (xcbc->buflen > xcbc->blocksize) || (xcbc->buflen < 0)) {
+      return CRYPT_INVALID_ARG;
+   }
+
+   /* which key do we use? */
+   if (xcbc->buflen == xcbc->blocksize) {
+      /* k2 */
+      for (x = 0; x < xcbc->blocksize; x++) {
+         xcbc->IV[x] ^= xcbc->K[1][x];
+      }
+   } else {
+      xcbc->IV[xcbc->buflen] ^= 0x80;
+      /* k3 */
+      for (x = 0; x < xcbc->blocksize; x++) {
+         xcbc->IV[x] ^= xcbc->K[2][x];
+      }
+   }
+
+   /* encrypt */
+   cipher_descriptor[xcbc->cipher].ecb_encrypt(xcbc->IV, xcbc->IV, &xcbc->key);
+   cipher_descriptor[xcbc->cipher].done(&xcbc->key);
+
+   /* extract tag */
+   for (x = 0; x < xcbc->blocksize && (unsigned long)x < *outlen; x++) {
+      out[x] = xcbc->IV[x];
+   }
+   *outlen = x;
+
+#ifdef LTC_CLEAN_STACK
+   zeromem(xcbc, sizeof(*xcbc));
+#endif
+   return CRYPT_OK;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
+
diff --git a/libtomcrypt/src/mac/xcbc/xcbc_file.c b/libtomcrypt/src/mac/xcbc/xcbc_file.c
new file mode 100644 (file)
index 0000000..27eb0de
--- /dev/null
@@ -0,0 +1,97 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file xcbc_file.c
+  XCBC support, process a file, Tom St Denis
+*/
+
+#ifdef LTC_XCBC
+
+/**
+   XCBC a file
+   @param cipher   The index of the cipher desired
+   @param key      The secret key
+   @param keylen   The length of the secret key (octets)
+   @param filename The name of the file you wish to XCBC
+   @param out      [out] Where the authentication tag is to be stored
+   @param outlen   [in/out] The max size and resulting size of the authentication tag
+   @return CRYPT_OK if successful, CRYPT_NOP if file support has been disabled
+*/
+int xcbc_file(int cipher,
+              const unsigned char *key, unsigned long keylen,
+              const char *filename,
+                    unsigned char *out, unsigned long *outlen)
+{
+#ifdef LTC_NO_FILE
+   LTC_UNUSED_PARAM(cipher);
+   LTC_UNUSED_PARAM(key);
+   LTC_UNUSED_PARAM(keylen);
+   LTC_UNUSED_PARAM(filename);
+   LTC_UNUSED_PARAM(out);
+   LTC_UNUSED_PARAM(outlen);
+   return CRYPT_NOP;
+#else
+   size_t x;
+   int err;
+   xcbc_state xcbc;
+   FILE *in;
+   unsigned char *buf;
+
+   LTC_ARGCHK(key      != NULL);
+   LTC_ARGCHK(filename != NULL);
+   LTC_ARGCHK(out      != NULL);
+   LTC_ARGCHK(outlen   != NULL);
+
+   if ((buf = XMALLOC(LTC_FILE_READ_BUFSIZE)) == NULL) {
+      return CRYPT_MEM;
+   }
+
+   if ((err = xcbc_init(&xcbc, cipher, key, keylen)) != CRYPT_OK) {
+      goto LBL_ERR;
+   }
+
+   in = fopen(filename, "rb");
+   if (in == NULL) {
+      err = CRYPT_FILE_NOTFOUND;
+      goto LBL_ERR;
+   }
+
+   do {
+      x = fread(buf, 1, LTC_FILE_READ_BUFSIZE, in);
+      if ((err = xcbc_process(&xcbc, buf, (unsigned long)x)) != CRYPT_OK) {
+         fclose(in);
+         goto LBL_CLEANBUF;
+      }
+   } while (x == LTC_FILE_READ_BUFSIZE);
+
+   if (fclose(in) != 0) {
+      err = CRYPT_ERROR;
+      goto LBL_CLEANBUF;
+   }
+
+   err = xcbc_done(&xcbc, out, outlen);
+
+LBL_CLEANBUF:
+   zeromem(buf, LTC_FILE_READ_BUFSIZE);
+LBL_ERR:
+#ifdef LTC_CLEAN_STACK
+   zeromem(&xcbc, sizeof(xcbc_state));
+#endif
+   XFREE(buf);
+   return err;
+#endif
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/mac/xcbc/xcbc_init.c b/libtomcrypt/src/mac/xcbc/xcbc_init.c
new file mode 100644 (file)
index 0000000..4eccd5e
--- /dev/null
@@ -0,0 +1,106 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file xcbc_init.c
+  XCBC Support, start an XCBC state
+*/
+
+#ifdef LTC_XCBC
+
+/** Initialize XCBC-MAC state
+  @param xcbc    [out] XCBC state to initialize
+  @param cipher  Index of cipher to use
+  @param key     [in]  Secret key
+  @param keylen  Length of secret key in octets
+  Return CRYPT_OK on success
+*/
+int xcbc_init(xcbc_state *xcbc, int cipher, const unsigned char *key, unsigned long keylen)
+{
+   int            x, y, err;
+   symmetric_key *skey;
+   unsigned long  k1;
+
+   LTC_ARGCHK(xcbc != NULL);
+   LTC_ARGCHK(key  != NULL);
+
+   /* schedule the key */
+   if ((err = cipher_is_valid(cipher)) != CRYPT_OK) {
+      return err;
+   }
+
+#ifdef LTC_FAST
+   if (cipher_descriptor[cipher].block_length % sizeof(LTC_FAST_TYPE)) {
+       return CRYPT_INVALID_ARG;
+   }
+#endif
+
+   skey = NULL;
+
+   /* are we in pure XCBC mode with three keys? */
+   if (keylen & LTC_XCBC_PURE) {
+      keylen &= ~LTC_XCBC_PURE;
+
+      if (keylen < 2UL*cipher_descriptor[cipher].block_length) {
+         return CRYPT_INVALID_ARG;
+      }
+
+      k1      = keylen - 2*cipher_descriptor[cipher].block_length;
+      XMEMCPY(xcbc->K[0], key, k1);
+      XMEMCPY(xcbc->K[1], key+k1, cipher_descriptor[cipher].block_length);
+      XMEMCPY(xcbc->K[2], key+k1 + cipher_descriptor[cipher].block_length, cipher_descriptor[cipher].block_length);
+   } else {
+      /* use the key expansion */
+      k1      = cipher_descriptor[cipher].block_length;
+
+      /* schedule the user key */
+      skey = XCALLOC(1, sizeof(*skey));
+      if (skey == NULL) {
+         return CRYPT_MEM;
+      }
+
+      if ((err = cipher_descriptor[cipher].setup(key, keylen, 0, skey)) != CRYPT_OK) {
+         goto done;
+      }
+
+      /* make the three keys */
+      for (y = 0; y < 3; y++) {
+        for (x = 0; x < cipher_descriptor[cipher].block_length; x++) {
+           xcbc->K[y][x] = y + 1;
+        }
+        cipher_descriptor[cipher].ecb_encrypt(xcbc->K[y], xcbc->K[y], skey);
+      }
+   }
+
+   /* setup K1 */
+   err = cipher_descriptor[cipher].setup(xcbc->K[0], k1, 0, &xcbc->key);
+
+   /* setup struct */
+   zeromem(xcbc->IV, cipher_descriptor[cipher].block_length);
+   xcbc->blocksize = cipher_descriptor[cipher].block_length;
+   xcbc->cipher    = cipher;
+   xcbc->buflen    = 0;
+done:
+   cipher_descriptor[cipher].done(skey);
+   if (skey != NULL) {
+#ifdef LTC_CLEAN_STACK
+      zeromem(skey, sizeof(*skey));
+#endif
+      XFREE(skey);
+   }
+   return err;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
+
diff --git a/libtomcrypt/src/mac/xcbc/xcbc_memory.c b/libtomcrypt/src/mac/xcbc/xcbc_memory.c
new file mode 100644 (file)
index 0000000..a1bc045
--- /dev/null
@@ -0,0 +1,69 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file xcbc_process.c
+  XCBC Support, XCBC-MAC a block of memory
+*/
+
+#ifdef LTC_XCBC
+
+/** XCBC-MAC a block of memory
+  @param cipher     Index of cipher to use
+  @param key        [in]  Secret key
+  @param keylen     Length of key in octets
+  @param in         [in]  Message to MAC
+  @param inlen      Length of input in octets
+  @param out        [out] Destination for the MAC tag
+  @param outlen     [in/out] Output size and final tag size
+  Return CRYPT_OK on success.
+*/
+int xcbc_memory(int cipher,
+               const unsigned char *key, unsigned long keylen,
+               const unsigned char *in,  unsigned long inlen,
+                     unsigned char *out, unsigned long *outlen)
+{
+   xcbc_state *xcbc;
+   int         err;
+
+   /* is the cipher valid? */
+   if ((err = cipher_is_valid(cipher)) != CRYPT_OK) {
+      return err;
+   }
+
+   /* Use accelerator if found */
+   if (cipher_descriptor[cipher].xcbc_memory != NULL) {
+      return cipher_descriptor[cipher].xcbc_memory(key, keylen, in, inlen, out, outlen);
+   }
+
+   xcbc = XCALLOC(1, sizeof(*xcbc));
+   if (xcbc == NULL) {
+      return CRYPT_MEM;
+   }
+
+   if ((err = xcbc_init(xcbc, cipher, key, keylen)) != CRYPT_OK) {
+     goto done;
+   }
+
+   if ((err = xcbc_process(xcbc, in, inlen)) != CRYPT_OK) {
+     goto done;
+   }
+
+   err = xcbc_done(xcbc, out, outlen);
+done:
+   XFREE(xcbc);
+   return err;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/mac/xcbc/xcbc_memory_multi.c b/libtomcrypt/src/mac/xcbc/xcbc_memory_multi.c
new file mode 100644 (file)
index 0000000..a5b9d91
--- /dev/null
@@ -0,0 +1,88 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+#include <stdarg.h>
+
+/**
+  @file xcbc_memory_multi.c
+  XCBC support, process multiple blocks of memory, Tom St Denis
+*/
+
+#ifdef LTC_XCBC
+
+/**
+   XCBC multiple blocks of memory
+   @param cipher    The index of the desired cipher
+   @param key       The secret key
+   @param keylen    The length of the secret key (octets)
+   @param out       [out] The destination of the authentication tag
+   @param outlen    [in/out]  The max size and resulting size of the authentication tag (octets)
+   @param in        The data to send through XCBC
+   @param inlen     The length of the data to send through XCBC (octets)
+   @param ...       tuples of (data,len) pairs to XCBC, terminated with a (NULL,x) (x=don't care)
+   @return CRYPT_OK if successful
+*/
+int xcbc_memory_multi(int cipher,
+                const unsigned char *key, unsigned long keylen,
+                      unsigned char *out, unsigned long *outlen,
+                const unsigned char *in,  unsigned long inlen, ...)
+{
+   int                  err;
+   xcbc_state          *xcbc;
+   va_list              args;
+   const unsigned char *curptr;
+   unsigned long        curlen;
+
+   LTC_ARGCHK(key    != NULL);
+   LTC_ARGCHK(in     != NULL);
+   LTC_ARGCHK(out    != NULL);
+   LTC_ARGCHK(outlen != NULL);
+
+   /* allocate ram for xcbc state */
+   xcbc = XMALLOC(sizeof(xcbc_state));
+   if (xcbc == NULL) {
+      return CRYPT_MEM;
+   }
+
+   /* xcbc process the message */
+   if ((err = xcbc_init(xcbc, cipher, key, keylen)) != CRYPT_OK) {
+      goto LBL_ERR;
+   }
+   va_start(args, inlen);
+   curptr = in;
+   curlen = inlen;
+   for (;;) {
+      /* process buf */
+      if ((err = xcbc_process(xcbc, curptr, curlen)) != CRYPT_OK) {
+         goto LBL_ERR;
+      }
+      /* step to next */
+      curptr = va_arg(args, const unsigned char*);
+      if (curptr == NULL) {
+         break;
+      }
+      curlen = va_arg(args, unsigned long);
+   }
+   if ((err = xcbc_done(xcbc, out, outlen)) != CRYPT_OK) {
+      goto LBL_ERR;
+   }
+LBL_ERR:
+#ifdef LTC_CLEAN_STACK
+   zeromem(xcbc, sizeof(xcbc_state));
+#endif
+   XFREE(xcbc);
+   va_end(args);
+   return err;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/mac/xcbc/xcbc_process.c b/libtomcrypt/src/mac/xcbc/xcbc_process.c
new file mode 100644 (file)
index 0000000..12e25c5
--- /dev/null
@@ -0,0 +1,73 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file xcbc_process.c
+  XCBC Support, process blocks with XCBC
+*/
+
+#ifdef LTC_XCBC
+
+/** Process data through XCBC-MAC
+  @param xcbc     The XCBC-MAC state
+  @param in       Input data to process
+  @param inlen    Length of input in octets
+  Return CRYPT_OK on success
+*/
+int xcbc_process(xcbc_state *xcbc, const unsigned char *in, unsigned long inlen)
+{
+   int err;
+#ifdef LTC_FAST
+   int x;
+#endif
+
+   LTC_ARGCHK(xcbc != NULL);
+   LTC_ARGCHK(in   != NULL);
+
+   /* check structure */
+   if ((err = cipher_is_valid(xcbc->cipher)) != CRYPT_OK) {
+      return err;
+   }
+
+   if ((xcbc->blocksize > cipher_descriptor[xcbc->cipher].block_length) || (xcbc->blocksize < 0) ||
+       (xcbc->buflen > xcbc->blocksize) || (xcbc->buflen < 0)) {
+      return CRYPT_INVALID_ARG;
+   }
+
+#ifdef LTC_FAST
+   if (xcbc->buflen == 0) {
+       while (inlen > (unsigned long)xcbc->blocksize) {
+           for (x = 0; x < xcbc->blocksize; x += sizeof(LTC_FAST_TYPE)) {
+              *(LTC_FAST_TYPE_PTR_CAST(&(xcbc->IV[x]))) ^= *(LTC_FAST_TYPE_PTR_CAST(&(in[x])));
+           }
+           cipher_descriptor[xcbc->cipher].ecb_encrypt(xcbc->IV, xcbc->IV, &xcbc->key);
+           in    += xcbc->blocksize;
+           inlen -= xcbc->blocksize;
+       }
+   }
+#endif
+
+   while (inlen) {
+      if (xcbc->buflen == xcbc->blocksize) {
+         cipher_descriptor[xcbc->cipher].ecb_encrypt(xcbc->IV, xcbc->IV, &xcbc->key);
+         xcbc->buflen = 0;
+      }
+      xcbc->IV[xcbc->buflen++] ^= *in++;
+      --inlen;
+   }
+   return CRYPT_OK;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
+
diff --git a/libtomcrypt/src/mac/xcbc/xcbc_test.c b/libtomcrypt/src/mac/xcbc/xcbc_test.c
new file mode 100644 (file)
index 0000000..6a0ecdf
--- /dev/null
@@ -0,0 +1,126 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file xcbc_test.c
+  XCBC Support, Test XCBC-MAC mode
+*/
+
+#ifdef LTC_XCBC
+
+/** Test XCBC-MAC mode
+  Return CRYPT_OK on succes
+*/
+int xcbc_test(void)
+{
+#ifdef LTC_NO_TEST
+   return CRYPT_NOP;
+#else
+   static const struct {
+       int msglen;
+       unsigned char K[16], M[34], T[16];
+   } tests[] = {
+{
+   0,
+   { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+     0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f },
+
+   { 0 },
+
+   { 0x75, 0xf0, 0x25, 0x1d, 0x52, 0x8a, 0xc0, 0x1c,
+     0x45, 0x73, 0xdf, 0xd5, 0x84, 0xd7, 0x9f, 0x29 }
+},
+
+{
+   3,
+   { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+     0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f },
+
+   { 0x00, 0x01, 0x02 },
+
+   { 0x5b, 0x37, 0x65, 0x80, 0xae, 0x2f, 0x19, 0xaf,
+     0xe7, 0x21, 0x9c, 0xee, 0xf1, 0x72, 0x75, 0x6f }
+},
+
+{
+   16,
+   { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+     0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f },
+
+   { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+     0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f },
+
+   { 0xd2, 0xa2, 0x46, 0xfa, 0x34, 0x9b, 0x68, 0xa7,
+     0x99, 0x98, 0xa4, 0x39, 0x4f, 0xf7, 0xa2, 0x63 }
+},
+
+{
+   32,
+   { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+     0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f },
+
+   { 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 },
+
+   { 0xf5, 0x4f, 0x0e, 0xc8, 0xd2, 0xb9, 0xf3, 0xd3,
+     0x68, 0x07, 0x73, 0x4b, 0xd5, 0x28, 0x3f, 0xd4 }
+},
+
+{
+   34,
+   { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+     0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f },
+
+   { 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,
+     0x20, 0x21 },
+
+   { 0xbe, 0xcb, 0xb3, 0xbc, 0xcd, 0xb5, 0x18, 0xa3,
+     0x06, 0x77, 0xd5, 0x48, 0x1f, 0xb6, 0xb4, 0xd8 },
+},
+
+
+
+};
+  unsigned char T[16];
+  unsigned long taglen;
+  int err, x, idx;
+
+  /* AES can be under rijndael or aes... try to find it */
+  if ((idx = find_cipher("aes")) == -1) {
+     if ((idx = find_cipher("rijndael")) == -1) {
+        return CRYPT_NOP;
+     }
+  }
+
+  for (x = 0; x < (int)(sizeof(tests)/sizeof(tests[0])); x++) {
+     taglen = 16;
+     if ((err = xcbc_memory(idx, tests[x].K, 16, tests[x].M, tests[x].msglen, T, &taglen)) != CRYPT_OK) {
+        return err;
+     }
+     if (compare_testvector(T, taglen, tests[x].T, 16, "XCBC", x)) {
+        return CRYPT_FAIL_TESTVECTOR;
+     }
+  }
+
+  return CRYPT_OK;
+#endif
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
+
diff --git a/libtomcrypt/src/math/fp/ltc_ecc_fp_mulmod.c b/libtomcrypt/src/math/fp/ltc_ecc_fp_mulmod.c
new file mode 100644 (file)
index 0000000..24ed019
--- /dev/null
@@ -0,0 +1,1585 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file ltc_ecc_fp_mulmod.c
+  ECC Crypto, Tom St Denis
+*/
+
+#if defined(LTC_MECC) && defined(LTC_MECC_FP)
+#include <limits.h>
+
+/* number of entries in the cache */
+#ifndef FP_ENTRIES
+#define FP_ENTRIES 16
+#endif
+
+/* number of bits in LUT */
+#ifndef FP_LUT
+#define FP_LUT     8U
+#endif
+
+#if (FP_LUT > 12) || (FP_LUT < 2)
+   #error FP_LUT must be between 2 and 12 inclusively
+#endif
+
+/** Our FP cache */
+static struct {
+   ecc_point *g,              /* cached COPY of base point */
+             *LUT[1U<<FP_LUT]; /* fixed point lookup */
+   void      *mu;             /* copy of the montgomery constant */
+   int        lru_count;      /* amount of times this entry has been used */
+   int        lock;           /* flag to indicate cache eviction permitted (0) or not (1) */
+} fp_cache[FP_ENTRIES];
+
+LTC_MUTEX_GLOBAL(ltc_ecc_fp_lock)
+
+/* simple table to help direct the generation of the LUT */
+static const struct {
+   int ham, terma, termb;
+} lut_orders[] = {
+   { 0, 0, 0 }, { 1, 0, 0 }, { 1, 0, 0 }, { 2, 1, 2 }, { 1, 0, 0 }, { 2, 1, 4 }, { 2, 2, 4 }, { 3, 3, 4 },
+   { 1, 0, 0 }, { 2, 1, 8 }, { 2, 2, 8 }, { 3, 3, 8 }, { 2, 4, 8 }, { 3, 5, 8 }, { 3, 6, 8 }, { 4, 7, 8 },
+   { 1, 0, 0 }, { 2, 1, 16 }, { 2, 2, 16 }, { 3, 3, 16 }, { 2, 4, 16 }, { 3, 5, 16 }, { 3, 6, 16 }, { 4, 7, 16 },
+   { 2, 8, 16 }, { 3, 9, 16 }, { 3, 10, 16 }, { 4, 11, 16 }, { 3, 12, 16 }, { 4, 13, 16 }, { 4, 14, 16 }, { 5, 15, 16 },
+   { 1, 0, 0 }, { 2, 1, 32 }, { 2, 2, 32 }, { 3, 3, 32 }, { 2, 4, 32 }, { 3, 5, 32 }, { 3, 6, 32 }, { 4, 7, 32 },
+   { 2, 8, 32 }, { 3, 9, 32 }, { 3, 10, 32 }, { 4, 11, 32 }, { 3, 12, 32 }, { 4, 13, 32 }, { 4, 14, 32 }, { 5, 15, 32 },
+   { 2, 16, 32 }, { 3, 17, 32 }, { 3, 18, 32 }, { 4, 19, 32 }, { 3, 20, 32 }, { 4, 21, 32 }, { 4, 22, 32 }, { 5, 23, 32 },
+   { 3, 24, 32 }, { 4, 25, 32 }, { 4, 26, 32 }, { 5, 27, 32 }, { 4, 28, 32 }, { 5, 29, 32 }, { 5, 30, 32 }, { 6, 31, 32 },
+#if FP_LUT > 6
+   { 1, 0, 0 }, { 2, 1, 64 }, { 2, 2, 64 }, { 3, 3, 64 }, { 2, 4, 64 }, { 3, 5, 64 }, { 3, 6, 64 }, { 4, 7, 64 },
+   { 2, 8, 64 }, { 3, 9, 64 }, { 3, 10, 64 }, { 4, 11, 64 }, { 3, 12, 64 }, { 4, 13, 64 }, { 4, 14, 64 }, { 5, 15, 64 },
+   { 2, 16, 64 }, { 3, 17, 64 }, { 3, 18, 64 }, { 4, 19, 64 }, { 3, 20, 64 }, { 4, 21, 64 }, { 4, 22, 64 }, { 5, 23, 64 },
+   { 3, 24, 64 }, { 4, 25, 64 }, { 4, 26, 64 }, { 5, 27, 64 }, { 4, 28, 64 }, { 5, 29, 64 }, { 5, 30, 64 }, { 6, 31, 64 },
+   { 2, 32, 64 }, { 3, 33, 64 }, { 3, 34, 64 }, { 4, 35, 64 }, { 3, 36, 64 }, { 4, 37, 64 }, { 4, 38, 64 }, { 5, 39, 64 },
+   { 3, 40, 64 }, { 4, 41, 64 }, { 4, 42, 64 }, { 5, 43, 64 }, { 4, 44, 64 }, { 5, 45, 64 }, { 5, 46, 64 }, { 6, 47, 64 },
+   { 3, 48, 64 }, { 4, 49, 64 }, { 4, 50, 64 }, { 5, 51, 64 }, { 4, 52, 64 }, { 5, 53, 64 }, { 5, 54, 64 }, { 6, 55, 64 },
+   { 4, 56, 64 }, { 5, 57, 64 }, { 5, 58, 64 }, { 6, 59, 64 }, { 5, 60, 64 }, { 6, 61, 64 }, { 6, 62, 64 }, { 7, 63, 64 },
+#if FP_LUT > 7
+   { 1, 0, 0 }, { 2, 1, 128 }, { 2, 2, 128 }, { 3, 3, 128 }, { 2, 4, 128 }, { 3, 5, 128 }, { 3, 6, 128 }, { 4, 7, 128 },
+   { 2, 8, 128 }, { 3, 9, 128 }, { 3, 10, 128 }, { 4, 11, 128 }, { 3, 12, 128 }, { 4, 13, 128 }, { 4, 14, 128 }, { 5, 15, 128 },
+   { 2, 16, 128 }, { 3, 17, 128 }, { 3, 18, 128 }, { 4, 19, 128 }, { 3, 20, 128 }, { 4, 21, 128 }, { 4, 22, 128 }, { 5, 23, 128 },
+   { 3, 24, 128 }, { 4, 25, 128 }, { 4, 26, 128 }, { 5, 27, 128 }, { 4, 28, 128 }, { 5, 29, 128 }, { 5, 30, 128 }, { 6, 31, 128 },
+   { 2, 32, 128 }, { 3, 33, 128 }, { 3, 34, 128 }, { 4, 35, 128 }, { 3, 36, 128 }, { 4, 37, 128 }, { 4, 38, 128 }, { 5, 39, 128 },
+   { 3, 40, 128 }, { 4, 41, 128 }, { 4, 42, 128 }, { 5, 43, 128 }, { 4, 44, 128 }, { 5, 45, 128 }, { 5, 46, 128 }, { 6, 47, 128 },
+   { 3, 48, 128 }, { 4, 49, 128 }, { 4, 50, 128 }, { 5, 51, 128 }, { 4, 52, 128 }, { 5, 53, 128 }, { 5, 54, 128 }, { 6, 55, 128 },
+   { 4, 56, 128 }, { 5, 57, 128 }, { 5, 58, 128 }, { 6, 59, 128 }, { 5, 60, 128 }, { 6, 61, 128 }, { 6, 62, 128 }, { 7, 63, 128 },
+   { 2, 64, 128 }, { 3, 65, 128 }, { 3, 66, 128 }, { 4, 67, 128 }, { 3, 68, 128 }, { 4, 69, 128 }, { 4, 70, 128 }, { 5, 71, 128 },
+   { 3, 72, 128 }, { 4, 73, 128 }, { 4, 74, 128 }, { 5, 75, 128 }, { 4, 76, 128 }, { 5, 77, 128 }, { 5, 78, 128 }, { 6, 79, 128 },
+   { 3, 80, 128 }, { 4, 81, 128 }, { 4, 82, 128 }, { 5, 83, 128 }, { 4, 84, 128 }, { 5, 85, 128 }, { 5, 86, 128 }, { 6, 87, 128 },
+   { 4, 88, 128 }, { 5, 89, 128 }, { 5, 90, 128 }, { 6, 91, 128 }, { 5, 92, 128 }, { 6, 93, 128 }, { 6, 94, 128 }, { 7, 95, 128 },
+   { 3, 96, 128 }, { 4, 97, 128 }, { 4, 98, 128 }, { 5, 99, 128 }, { 4, 100, 128 }, { 5, 101, 128 }, { 5, 102, 128 }, { 6, 103, 128 },
+   { 4, 104, 128 }, { 5, 105, 128 }, { 5, 106, 128 }, { 6, 107, 128 }, { 5, 108, 128 }, { 6, 109, 128 }, { 6, 110, 128 }, { 7, 111, 128 },
+   { 4, 112, 128 }, { 5, 113, 128 }, { 5, 114, 128 }, { 6, 115, 128 }, { 5, 116, 128 }, { 6, 117, 128 }, { 6, 118, 128 }, { 7, 119, 128 },
+   { 5, 120, 128 }, { 6, 121, 128 }, { 6, 122, 128 }, { 7, 123, 128 }, { 6, 124, 128 }, { 7, 125, 128 }, { 7, 126, 128 }, { 8, 127, 128 },
+#if FP_LUT > 8
+   { 1, 0, 0 }, { 2, 1, 256 }, { 2, 2, 256 }, { 3, 3, 256 }, { 2, 4, 256 }, { 3, 5, 256 }, { 3, 6, 256 }, { 4, 7, 256 },
+   { 2, 8, 256 }, { 3, 9, 256 }, { 3, 10, 256 }, { 4, 11, 256 }, { 3, 12, 256 }, { 4, 13, 256 }, { 4, 14, 256 }, { 5, 15, 256 },
+   { 2, 16, 256 }, { 3, 17, 256 }, { 3, 18, 256 }, { 4, 19, 256 }, { 3, 20, 256 }, { 4, 21, 256 }, { 4, 22, 256 }, { 5, 23, 256 },
+   { 3, 24, 256 }, { 4, 25, 256 }, { 4, 26, 256 }, { 5, 27, 256 }, { 4, 28, 256 }, { 5, 29, 256 }, { 5, 30, 256 }, { 6, 31, 256 },
+   { 2, 32, 256 }, { 3, 33, 256 }, { 3, 34, 256 }, { 4, 35, 256 }, { 3, 36, 256 }, { 4, 37, 256 }, { 4, 38, 256 }, { 5, 39, 256 },
+   { 3, 40, 256 }, { 4, 41, 256 }, { 4, 42, 256 }, { 5, 43, 256 }, { 4, 44, 256 }, { 5, 45, 256 }, { 5, 46, 256 }, { 6, 47, 256 },
+   { 3, 48, 256 }, { 4, 49, 256 }, { 4, 50, 256 }, { 5, 51, 256 }, { 4, 52, 256 }, { 5, 53, 256 }, { 5, 54, 256 }, { 6, 55, 256 },
+   { 4, 56, 256 }, { 5, 57, 256 }, { 5, 58, 256 }, { 6, 59, 256 }, { 5, 60, 256 }, { 6, 61, 256 }, { 6, 62, 256 }, { 7, 63, 256 },
+   { 2, 64, 256 }, { 3, 65, 256 }, { 3, 66, 256 }, { 4, 67, 256 }, { 3, 68, 256 }, { 4, 69, 256 }, { 4, 70, 256 }, { 5, 71, 256 },
+   { 3, 72, 256 }, { 4, 73, 256 }, { 4, 74, 256 }, { 5, 75, 256 }, { 4, 76, 256 }, { 5, 77, 256 }, { 5, 78, 256 }, { 6, 79, 256 },
+   { 3, 80, 256 }, { 4, 81, 256 }, { 4, 82, 256 }, { 5, 83, 256 }, { 4, 84, 256 }, { 5, 85, 256 }, { 5, 86, 256 }, { 6, 87, 256 },
+   { 4, 88, 256 }, { 5, 89, 256 }, { 5, 90, 256 }, { 6, 91, 256 }, { 5, 92, 256 }, { 6, 93, 256 }, { 6, 94, 256 }, { 7, 95, 256 },
+   { 3, 96, 256 }, { 4, 97, 256 }, { 4, 98, 256 }, { 5, 99, 256 }, { 4, 100, 256 }, { 5, 101, 256 }, { 5, 102, 256 }, { 6, 103, 256 },
+   { 4, 104, 256 }, { 5, 105, 256 }, { 5, 106, 256 }, { 6, 107, 256 }, { 5, 108, 256 }, { 6, 109, 256 }, { 6, 110, 256 }, { 7, 111, 256 },
+   { 4, 112, 256 }, { 5, 113, 256 }, { 5, 114, 256 }, { 6, 115, 256 }, { 5, 116, 256 }, { 6, 117, 256 }, { 6, 118, 256 }, { 7, 119, 256 },
+   { 5, 120, 256 }, { 6, 121, 256 }, { 6, 122, 256 }, { 7, 123, 256 }, { 6, 124, 256 }, { 7, 125, 256 }, { 7, 126, 256 }, { 8, 127, 256 },
+   { 2, 128, 256 }, { 3, 129, 256 }, { 3, 130, 256 }, { 4, 131, 256 }, { 3, 132, 256 }, { 4, 133, 256 }, { 4, 134, 256 }, { 5, 135, 256 },
+   { 3, 136, 256 }, { 4, 137, 256 }, { 4, 138, 256 }, { 5, 139, 256 }, { 4, 140, 256 }, { 5, 141, 256 }, { 5, 142, 256 }, { 6, 143, 256 },
+   { 3, 144, 256 }, { 4, 145, 256 }, { 4, 146, 256 }, { 5, 147, 256 }, { 4, 148, 256 }, { 5, 149, 256 }, { 5, 150, 256 }, { 6, 151, 256 },
+   { 4, 152, 256 }, { 5, 153, 256 }, { 5, 154, 256 }, { 6, 155, 256 }, { 5, 156, 256 }, { 6, 157, 256 }, { 6, 158, 256 }, { 7, 159, 256 },
+   { 3, 160, 256 }, { 4, 161, 256 }, { 4, 162, 256 }, { 5, 163, 256 }, { 4, 164, 256 }, { 5, 165, 256 }, { 5, 166, 256 }, { 6, 167, 256 },
+   { 4, 168, 256 }, { 5, 169, 256 }, { 5, 170, 256 }, { 6, 171, 256 }, { 5, 172, 256 }, { 6, 173, 256 }, { 6, 174, 256 }, { 7, 175, 256 },
+   { 4, 176, 256 }, { 5, 177, 256 }, { 5, 178, 256 }, { 6, 179, 256 }, { 5, 180, 256 }, { 6, 181, 256 }, { 6, 182, 256 }, { 7, 183, 256 },
+   { 5, 184, 256 }, { 6, 185, 256 }, { 6, 186, 256 }, { 7, 187, 256 }, { 6, 188, 256 }, { 7, 189, 256 }, { 7, 190, 256 }, { 8, 191, 256 },
+   { 3, 192, 256 }, { 4, 193, 256 }, { 4, 194, 256 }, { 5, 195, 256 }, { 4, 196, 256 }, { 5, 197, 256 }, { 5, 198, 256 }, { 6, 199, 256 },
+   { 4, 200, 256 }, { 5, 201, 256 }, { 5, 202, 256 }, { 6, 203, 256 }, { 5, 204, 256 }, { 6, 205, 256 }, { 6, 206, 256 }, { 7, 207, 256 },
+   { 4, 208, 256 }, { 5, 209, 256 }, { 5, 210, 256 }, { 6, 211, 256 }, { 5, 212, 256 }, { 6, 213, 256 }, { 6, 214, 256 }, { 7, 215, 256 },
+   { 5, 216, 256 }, { 6, 217, 256 }, { 6, 218, 256 }, { 7, 219, 256 }, { 6, 220, 256 }, { 7, 221, 256 }, { 7, 222, 256 }, { 8, 223, 256 },
+   { 4, 224, 256 }, { 5, 225, 256 }, { 5, 226, 256 }, { 6, 227, 256 }, { 5, 228, 256 }, { 6, 229, 256 }, { 6, 230, 256 }, { 7, 231, 256 },
+   { 5, 232, 256 }, { 6, 233, 256 }, { 6, 234, 256 }, { 7, 235, 256 }, { 6, 236, 256 }, { 7, 237, 256 }, { 7, 238, 256 }, { 8, 239, 256 },
+   { 5, 240, 256 }, { 6, 241, 256 }, { 6, 242, 256 }, { 7, 243, 256 }, { 6, 244, 256 }, { 7, 245, 256 }, { 7, 246, 256 }, { 8, 247, 256 },
+   { 6, 248, 256 }, { 7, 249, 256 }, { 7, 250, 256 }, { 8, 251, 256 }, { 7, 252, 256 }, { 8, 253, 256 }, { 8, 254, 256 }, { 9, 255, 256 },
+#if FP_LUT > 9
+   { 1, 0, 0 }, { 2, 1, 512 }, { 2, 2, 512 }, { 3, 3, 512 }, { 2, 4, 512 }, { 3, 5, 512 }, { 3, 6, 512 }, { 4, 7, 512 },
+   { 2, 8, 512 }, { 3, 9, 512 }, { 3, 10, 512 }, { 4, 11, 512 }, { 3, 12, 512 }, { 4, 13, 512 }, { 4, 14, 512 }, { 5, 15, 512 },
+   { 2, 16, 512 }, { 3, 17, 512 }, { 3, 18, 512 }, { 4, 19, 512 }, { 3, 20, 512 }, { 4, 21, 512 }, { 4, 22, 512 }, { 5, 23, 512 },
+   { 3, 24, 512 }, { 4, 25, 512 }, { 4, 26, 512 }, { 5, 27, 512 }, { 4, 28, 512 }, { 5, 29, 512 }, { 5, 30, 512 }, { 6, 31, 512 },
+   { 2, 32, 512 }, { 3, 33, 512 }, { 3, 34, 512 }, { 4, 35, 512 }, { 3, 36, 512 }, { 4, 37, 512 }, { 4, 38, 512 }, { 5, 39, 512 },
+   { 3, 40, 512 }, { 4, 41, 512 }, { 4, 42, 512 }, { 5, 43, 512 }, { 4, 44, 512 }, { 5, 45, 512 }, { 5, 46, 512 }, { 6, 47, 512 },
+   { 3, 48, 512 }, { 4, 49, 512 }, { 4, 50, 512 }, { 5, 51, 512 }, { 4, 52, 512 }, { 5, 53, 512 }, { 5, 54, 512 }, { 6, 55, 512 },
+   { 4, 56, 512 }, { 5, 57, 512 }, { 5, 58, 512 }, { 6, 59, 512 }, { 5, 60, 512 }, { 6, 61, 512 }, { 6, 62, 512 }, { 7, 63, 512 },
+   { 2, 64, 512 }, { 3, 65, 512 }, { 3, 66, 512 }, { 4, 67, 512 }, { 3, 68, 512 }, { 4, 69, 512 }, { 4, 70, 512 }, { 5, 71, 512 },
+   { 3, 72, 512 }, { 4, 73, 512 }, { 4, 74, 512 }, { 5, 75, 512 }, { 4, 76, 512 }, { 5, 77, 512 }, { 5, 78, 512 }, { 6, 79, 512 },
+   { 3, 80, 512 }, { 4, 81, 512 }, { 4, 82, 512 }, { 5, 83, 512 }, { 4, 84, 512 }, { 5, 85, 512 }, { 5, 86, 512 }, { 6, 87, 512 },
+   { 4, 88, 512 }, { 5, 89, 512 }, { 5, 90, 512 }, { 6, 91, 512 }, { 5, 92, 512 }, { 6, 93, 512 }, { 6, 94, 512 }, { 7, 95, 512 },
+   { 3, 96, 512 }, { 4, 97, 512 }, { 4, 98, 512 }, { 5, 99, 512 }, { 4, 100, 512 }, { 5, 101, 512 }, { 5, 102, 512 }, { 6, 103, 512 },
+   { 4, 104, 512 }, { 5, 105, 512 }, { 5, 106, 512 }, { 6, 107, 512 }, { 5, 108, 512 }, { 6, 109, 512 }, { 6, 110, 512 }, { 7, 111, 512 },
+   { 4, 112, 512 }, { 5, 113, 512 }, { 5, 114, 512 }, { 6, 115, 512 }, { 5, 116, 512 }, { 6, 117, 512 }, { 6, 118, 512 }, { 7, 119, 512 },
+   { 5, 120, 512 }, { 6, 121, 512 }, { 6, 122, 512 }, { 7, 123, 512 }, { 6, 124, 512 }, { 7, 125, 512 }, { 7, 126, 512 }, { 8, 127, 512 },
+   { 2, 128, 512 }, { 3, 129, 512 }, { 3, 130, 512 }, { 4, 131, 512 }, { 3, 132, 512 }, { 4, 133, 512 }, { 4, 134, 512 }, { 5, 135, 512 },
+   { 3, 136, 512 }, { 4, 137, 512 }, { 4, 138, 512 }, { 5, 139, 512 }, { 4, 140, 512 }, { 5, 141, 512 }, { 5, 142, 512 }, { 6, 143, 512 },
+   { 3, 144, 512 }, { 4, 145, 512 }, { 4, 146, 512 }, { 5, 147, 512 }, { 4, 148, 512 }, { 5, 149, 512 }, { 5, 150, 512 }, { 6, 151, 512 },
+   { 4, 152, 512 }, { 5, 153, 512 }, { 5, 154, 512 }, { 6, 155, 512 }, { 5, 156, 512 }, { 6, 157, 512 }, { 6, 158, 512 }, { 7, 159, 512 },
+   { 3, 160, 512 }, { 4, 161, 512 }, { 4, 162, 512 }, { 5, 163, 512 }, { 4, 164, 512 }, { 5, 165, 512 }, { 5, 166, 512 }, { 6, 167, 512 },
+   { 4, 168, 512 }, { 5, 169, 512 }, { 5, 170, 512 }, { 6, 171, 512 }, { 5, 172, 512 }, { 6, 173, 512 }, { 6, 174, 512 }, { 7, 175, 512 },
+   { 4, 176, 512 }, { 5, 177, 512 }, { 5, 178, 512 }, { 6, 179, 512 }, { 5, 180, 512 }, { 6, 181, 512 }, { 6, 182, 512 }, { 7, 183, 512 },
+   { 5, 184, 512 }, { 6, 185, 512 }, { 6, 186, 512 }, { 7, 187, 512 }, { 6, 188, 512 }, { 7, 189, 512 }, { 7, 190, 512 }, { 8, 191, 512 },
+   { 3, 192, 512 }, { 4, 193, 512 }, { 4, 194, 512 }, { 5, 195, 512 }, { 4, 196, 512 }, { 5, 197, 512 }, { 5, 198, 512 }, { 6, 199, 512 },
+   { 4, 200, 512 }, { 5, 201, 512 }, { 5, 202, 512 }, { 6, 203, 512 }, { 5, 204, 512 }, { 6, 205, 512 }, { 6, 206, 512 }, { 7, 207, 512 },
+   { 4, 208, 512 }, { 5, 209, 512 }, { 5, 210, 512 }, { 6, 211, 512 }, { 5, 212, 512 }, { 6, 213, 512 }, { 6, 214, 512 }, { 7, 215, 512 },
+   { 5, 216, 512 }, { 6, 217, 512 }, { 6, 218, 512 }, { 7, 219, 512 }, { 6, 220, 512 }, { 7, 221, 512 }, { 7, 222, 512 }, { 8, 223, 512 },
+   { 4, 224, 512 }, { 5, 225, 512 }, { 5, 226, 512 }, { 6, 227, 512 }, { 5, 228, 512 }, { 6, 229, 512 }, { 6, 230, 512 }, { 7, 231, 512 },
+   { 5, 232, 512 }, { 6, 233, 512 }, { 6, 234, 512 }, { 7, 235, 512 }, { 6, 236, 512 }, { 7, 237, 512 }, { 7, 238, 512 }, { 8, 239, 512 },
+   { 5, 240, 512 }, { 6, 241, 512 }, { 6, 242, 512 }, { 7, 243, 512 }, { 6, 244, 512 }, { 7, 245, 512 }, { 7, 246, 512 }, { 8, 247, 512 },
+   { 6, 248, 512 }, { 7, 249, 512 }, { 7, 250, 512 }, { 8, 251, 512 }, { 7, 252, 512 }, { 8, 253, 512 }, { 8, 254, 512 }, { 9, 255, 512 },
+   { 2, 256, 512 }, { 3, 257, 512 }, { 3, 258, 512 }, { 4, 259, 512 }, { 3, 260, 512 }, { 4, 261, 512 }, { 4, 262, 512 }, { 5, 263, 512 },
+   { 3, 264, 512 }, { 4, 265, 512 }, { 4, 266, 512 }, { 5, 267, 512 }, { 4, 268, 512 }, { 5, 269, 512 }, { 5, 270, 512 }, { 6, 271, 512 },
+   { 3, 272, 512 }, { 4, 273, 512 }, { 4, 274, 512 }, { 5, 275, 512 }, { 4, 276, 512 }, { 5, 277, 512 }, { 5, 278, 512 }, { 6, 279, 512 },
+   { 4, 280, 512 }, { 5, 281, 512 }, { 5, 282, 512 }, { 6, 283, 512 }, { 5, 284, 512 }, { 6, 285, 512 }, { 6, 286, 512 }, { 7, 287, 512 },
+   { 3, 288, 512 }, { 4, 289, 512 }, { 4, 290, 512 }, { 5, 291, 512 }, { 4, 292, 512 }, { 5, 293, 512 }, { 5, 294, 512 }, { 6, 295, 512 },
+   { 4, 296, 512 }, { 5, 297, 512 }, { 5, 298, 512 }, { 6, 299, 512 }, { 5, 300, 512 }, { 6, 301, 512 }, { 6, 302, 512 }, { 7, 303, 512 },
+   { 4, 304, 512 }, { 5, 305, 512 }, { 5, 306, 512 }, { 6, 307, 512 }, { 5, 308, 512 }, { 6, 309, 512 }, { 6, 310, 512 }, { 7, 311, 512 },
+   { 5, 312, 512 }, { 6, 313, 512 }, { 6, 314, 512 }, { 7, 315, 512 }, { 6, 316, 512 }, { 7, 317, 512 }, { 7, 318, 512 }, { 8, 319, 512 },
+   { 3, 320, 512 }, { 4, 321, 512 }, { 4, 322, 512 }, { 5, 323, 512 }, { 4, 324, 512 }, { 5, 325, 512 }, { 5, 326, 512 }, { 6, 327, 512 },
+   { 4, 328, 512 }, { 5, 329, 512 }, { 5, 330, 512 }, { 6, 331, 512 }, { 5, 332, 512 }, { 6, 333, 512 }, { 6, 334, 512 }, { 7, 335, 512 },
+   { 4, 336, 512 }, { 5, 337, 512 }, { 5, 338, 512 }, { 6, 339, 512 }, { 5, 340, 512 }, { 6, 341, 512 }, { 6, 342, 512 }, { 7, 343, 512 },
+   { 5, 344, 512 }, { 6, 345, 512 }, { 6, 346, 512 }, { 7, 347, 512 }, { 6, 348, 512 }, { 7, 349, 512 }, { 7, 350, 512 }, { 8, 351, 512 },
+   { 4, 352, 512 }, { 5, 353, 512 }, { 5, 354, 512 }, { 6, 355, 512 }, { 5, 356, 512 }, { 6, 357, 512 }, { 6, 358, 512 }, { 7, 359, 512 },
+   { 5, 360, 512 }, { 6, 361, 512 }, { 6, 362, 512 }, { 7, 363, 512 }, { 6, 364, 512 }, { 7, 365, 512 }, { 7, 366, 512 }, { 8, 367, 512 },
+   { 5, 368, 512 }, { 6, 369, 512 }, { 6, 370, 512 }, { 7, 371, 512 }, { 6, 372, 512 }, { 7, 373, 512 }, { 7, 374, 512 }, { 8, 375, 512 },
+   { 6, 376, 512 }, { 7, 377, 512 }, { 7, 378, 512 }, { 8, 379, 512 }, { 7, 380, 512 }, { 8, 381, 512 }, { 8, 382, 512 }, { 9, 383, 512 },
+   { 3, 384, 512 }, { 4, 385, 512 }, { 4, 386, 512 }, { 5, 387, 512 }, { 4, 388, 512 }, { 5, 389, 512 }, { 5, 390, 512 }, { 6, 391, 512 },
+   { 4, 392, 512 }, { 5, 393, 512 }, { 5, 394, 512 }, { 6, 395, 512 }, { 5, 396, 512 }, { 6, 397, 512 }, { 6, 398, 512 }, { 7, 399, 512 },
+   { 4, 400, 512 }, { 5, 401, 512 }, { 5, 402, 512 }, { 6, 403, 512 }, { 5, 404, 512 }, { 6, 405, 512 }, { 6, 406, 512 }, { 7, 407, 512 },
+   { 5, 408, 512 }, { 6, 409, 512 }, { 6, 410, 512 }, { 7, 411, 512 }, { 6, 412, 512 }, { 7, 413, 512 }, { 7, 414, 512 }, { 8, 415, 512 },
+   { 4, 416, 512 }, { 5, 417, 512 }, { 5, 418, 512 }, { 6, 419, 512 }, { 5, 420, 512 }, { 6, 421, 512 }, { 6, 422, 512 }, { 7, 423, 512 },
+   { 5, 424, 512 }, { 6, 425, 512 }, { 6, 426, 512 }, { 7, 427, 512 }, { 6, 428, 512 }, { 7, 429, 512 }, { 7, 430, 512 }, { 8, 431, 512 },
+   { 5, 432, 512 }, { 6, 433, 512 }, { 6, 434, 512 }, { 7, 435, 512 }, { 6, 436, 512 }, { 7, 437, 512 }, { 7, 438, 512 }, { 8, 439, 512 },
+   { 6, 440, 512 }, { 7, 441, 512 }, { 7, 442, 512 }, { 8, 443, 512 }, { 7, 444, 512 }, { 8, 445, 512 }, { 8, 446, 512 }, { 9, 447, 512 },
+   { 4, 448, 512 }, { 5, 449, 512 }, { 5, 450, 512 }, { 6, 451, 512 }, { 5, 452, 512 }, { 6, 453, 512 }, { 6, 454, 512 }, { 7, 455, 512 },
+   { 5, 456, 512 }, { 6, 457, 512 }, { 6, 458, 512 }, { 7, 459, 512 }, { 6, 460, 512 }, { 7, 461, 512 }, { 7, 462, 512 }, { 8, 463, 512 },
+   { 5, 464, 512 }, { 6, 465, 512 }, { 6, 466, 512 }, { 7, 467, 512 }, { 6, 468, 512 }, { 7, 469, 512 }, { 7, 470, 512 }, { 8, 471, 512 },
+   { 6, 472, 512 }, { 7, 473, 512 }, { 7, 474, 512 }, { 8, 475, 512 }, { 7, 476, 512 }, { 8, 477, 512 }, { 8, 478, 512 }, { 9, 479, 512 },
+   { 5, 480, 512 }, { 6, 481, 512 }, { 6, 482, 512 }, { 7, 483, 512 }, { 6, 484, 512 }, { 7, 485, 512 }, { 7, 486, 512 }, { 8, 487, 512 },
+   { 6, 488, 512 }, { 7, 489, 512 }, { 7, 490, 512 }, { 8, 491, 512 }, { 7, 492, 512 }, { 8, 493, 512 }, { 8, 494, 512 }, { 9, 495, 512 },
+   { 6, 496, 512 }, { 7, 497, 512 }, { 7, 498, 512 }, { 8, 499, 512 }, { 7, 500, 512 }, { 8, 501, 512 }, { 8, 502, 512 }, { 9, 503, 512 },
+   { 7, 504, 512 }, { 8, 505, 512 }, { 8, 506, 512 }, { 9, 507, 512 }, { 8, 508, 512 }, { 9, 509, 512 }, { 9, 510, 512 }, { 10, 511, 512 },
+#if FP_LUT > 10
+   { 1, 0, 0 }, { 2, 1, 1024 }, { 2, 2, 1024 }, { 3, 3, 1024 }, { 2, 4, 1024 }, { 3, 5, 1024 }, { 3, 6, 1024 }, { 4, 7, 1024 },
+   { 2, 8, 1024 }, { 3, 9, 1024 }, { 3, 10, 1024 }, { 4, 11, 1024 }, { 3, 12, 1024 }, { 4, 13, 1024 }, { 4, 14, 1024 }, { 5, 15, 1024 },
+   { 2, 16, 1024 }, { 3, 17, 1024 }, { 3, 18, 1024 }, { 4, 19, 1024 }, { 3, 20, 1024 }, { 4, 21, 1024 }, { 4, 22, 1024 }, { 5, 23, 1024 },
+   { 3, 24, 1024 }, { 4, 25, 1024 }, { 4, 26, 1024 }, { 5, 27, 1024 }, { 4, 28, 1024 }, { 5, 29, 1024 }, { 5, 30, 1024 }, { 6, 31, 1024 },
+   { 2, 32, 1024 }, { 3, 33, 1024 }, { 3, 34, 1024 }, { 4, 35, 1024 }, { 3, 36, 1024 }, { 4, 37, 1024 }, { 4, 38, 1024 }, { 5, 39, 1024 },
+   { 3, 40, 1024 }, { 4, 41, 1024 }, { 4, 42, 1024 }, { 5, 43, 1024 }, { 4, 44, 1024 }, { 5, 45, 1024 }, { 5, 46, 1024 }, { 6, 47, 1024 },
+   { 3, 48, 1024 }, { 4, 49, 1024 }, { 4, 50, 1024 }, { 5, 51, 1024 }, { 4, 52, 1024 }, { 5, 53, 1024 }, { 5, 54, 1024 }, { 6, 55, 1024 },
+   { 4, 56, 1024 }, { 5, 57, 1024 }, { 5, 58, 1024 }, { 6, 59, 1024 }, { 5, 60, 1024 }, { 6, 61, 1024 }, { 6, 62, 1024 }, { 7, 63, 1024 },
+   { 2, 64, 1024 }, { 3, 65, 1024 }, { 3, 66, 1024 }, { 4, 67, 1024 }, { 3, 68, 1024 }, { 4, 69, 1024 }, { 4, 70, 1024 }, { 5, 71, 1024 },
+   { 3, 72, 1024 }, { 4, 73, 1024 }, { 4, 74, 1024 }, { 5, 75, 1024 }, { 4, 76, 1024 }, { 5, 77, 1024 }, { 5, 78, 1024 }, { 6, 79, 1024 },
+   { 3, 80, 1024 }, { 4, 81, 1024 }, { 4, 82, 1024 }, { 5, 83, 1024 }, { 4, 84, 1024 }, { 5, 85, 1024 }, { 5, 86, 1024 }, { 6, 87, 1024 },
+   { 4, 88, 1024 }, { 5, 89, 1024 }, { 5, 90, 1024 }, { 6, 91, 1024 }, { 5, 92, 1024 }, { 6, 93, 1024 }, { 6, 94, 1024 }, { 7, 95, 1024 },
+   { 3, 96, 1024 }, { 4, 97, 1024 }, { 4, 98, 1024 }, { 5, 99, 1024 }, { 4, 100, 1024 }, { 5, 101, 1024 }, { 5, 102, 1024 }, { 6, 103, 1024 },
+   { 4, 104, 1024 }, { 5, 105, 1024 }, { 5, 106, 1024 }, { 6, 107, 1024 }, { 5, 108, 1024 }, { 6, 109, 1024 }, { 6, 110, 1024 }, { 7, 111, 1024 },
+   { 4, 112, 1024 }, { 5, 113, 1024 }, { 5, 114, 1024 }, { 6, 115, 1024 }, { 5, 116, 1024 }, { 6, 117, 1024 }, { 6, 118, 1024 }, { 7, 119, 1024 },
+   { 5, 120, 1024 }, { 6, 121, 1024 }, { 6, 122, 1024 }, { 7, 123, 1024 }, { 6, 124, 1024 }, { 7, 125, 1024 }, { 7, 126, 1024 }, { 8, 127, 1024 },
+   { 2, 128, 1024 }, { 3, 129, 1024 }, { 3, 130, 1024 }, { 4, 131, 1024 }, { 3, 132, 1024 }, { 4, 133, 1024 }, { 4, 134, 1024 }, { 5, 135, 1024 },
+   { 3, 136, 1024 }, { 4, 137, 1024 }, { 4, 138, 1024 }, { 5, 139, 1024 }, { 4, 140, 1024 }, { 5, 141, 1024 }, { 5, 142, 1024 }, { 6, 143, 1024 },
+   { 3, 144, 1024 }, { 4, 145, 1024 }, { 4, 146, 1024 }, { 5, 147, 1024 }, { 4, 148, 1024 }, { 5, 149, 1024 }, { 5, 150, 1024 }, { 6, 151, 1024 },
+   { 4, 152, 1024 }, { 5, 153, 1024 }, { 5, 154, 1024 }, { 6, 155, 1024 }, { 5, 156, 1024 }, { 6, 157, 1024 }, { 6, 158, 1024 }, { 7, 159, 1024 },
+   { 3, 160, 1024 }, { 4, 161, 1024 }, { 4, 162, 1024 }, { 5, 163, 1024 }, { 4, 164, 1024 }, { 5, 165, 1024 }, { 5, 166, 1024 }, { 6, 167, 1024 },
+   { 4, 168, 1024 }, { 5, 169, 1024 }, { 5, 170, 1024 }, { 6, 171, 1024 }, { 5, 172, 1024 }, { 6, 173, 1024 }, { 6, 174, 1024 }, { 7, 175, 1024 },
+   { 4, 176, 1024 }, { 5, 177, 1024 }, { 5, 178, 1024 }, { 6, 179, 1024 }, { 5, 180, 1024 }, { 6, 181, 1024 }, { 6, 182, 1024 }, { 7, 183, 1024 },
+   { 5, 184, 1024 }, { 6, 185, 1024 }, { 6, 186, 1024 }, { 7, 187, 1024 }, { 6, 188, 1024 }, { 7, 189, 1024 }, { 7, 190, 1024 }, { 8, 191, 1024 },
+   { 3, 192, 1024 }, { 4, 193, 1024 }, { 4, 194, 1024 }, { 5, 195, 1024 }, { 4, 196, 1024 }, { 5, 197, 1024 }, { 5, 198, 1024 }, { 6, 199, 1024 },
+   { 4, 200, 1024 }, { 5, 201, 1024 }, { 5, 202, 1024 }, { 6, 203, 1024 }, { 5, 204, 1024 }, { 6, 205, 1024 }, { 6, 206, 1024 }, { 7, 207, 1024 },
+   { 4, 208, 1024 }, { 5, 209, 1024 }, { 5, 210, 1024 }, { 6, 211, 1024 }, { 5, 212, 1024 }, { 6, 213, 1024 }, { 6, 214, 1024 }, { 7, 215, 1024 },
+   { 5, 216, 1024 }, { 6, 217, 1024 }, { 6, 218, 1024 }, { 7, 219, 1024 }, { 6, 220, 1024 }, { 7, 221, 1024 }, { 7, 222, 1024 }, { 8, 223, 1024 },
+   { 4, 224, 1024 }, { 5, 225, 1024 }, { 5, 226, 1024 }, { 6, 227, 1024 }, { 5, 228, 1024 }, { 6, 229, 1024 }, { 6, 230, 1024 }, { 7, 231, 1024 },
+   { 5, 232, 1024 }, { 6, 233, 1024 }, { 6, 234, 1024 }, { 7, 235, 1024 }, { 6, 236, 1024 }, { 7, 237, 1024 }, { 7, 238, 1024 }, { 8, 239, 1024 },
+   { 5, 240, 1024 }, { 6, 241, 1024 }, { 6, 242, 1024 }, { 7, 243, 1024 }, { 6, 244, 1024 }, { 7, 245, 1024 }, { 7, 246, 1024 }, { 8, 247, 1024 },
+   { 6, 248, 1024 }, { 7, 249, 1024 }, { 7, 250, 1024 }, { 8, 251, 1024 }, { 7, 252, 1024 }, { 8, 253, 1024 }, { 8, 254, 1024 }, { 9, 255, 1024 },
+   { 2, 256, 1024 }, { 3, 257, 1024 }, { 3, 258, 1024 }, { 4, 259, 1024 }, { 3, 260, 1024 }, { 4, 261, 1024 }, { 4, 262, 1024 }, { 5, 263, 1024 },
+   { 3, 264, 1024 }, { 4, 265, 1024 }, { 4, 266, 1024 }, { 5, 267, 1024 }, { 4, 268, 1024 }, { 5, 269, 1024 }, { 5, 270, 1024 }, { 6, 271, 1024 },
+   { 3, 272, 1024 }, { 4, 273, 1024 }, { 4, 274, 1024 }, { 5, 275, 1024 }, { 4, 276, 1024 }, { 5, 277, 1024 }, { 5, 278, 1024 }, { 6, 279, 1024 },
+   { 4, 280, 1024 }, { 5, 281, 1024 }, { 5, 282, 1024 }, { 6, 283, 1024 }, { 5, 284, 1024 }, { 6, 285, 1024 }, { 6, 286, 1024 }, { 7, 287, 1024 },
+   { 3, 288, 1024 }, { 4, 289, 1024 }, { 4, 290, 1024 }, { 5, 291, 1024 }, { 4, 292, 1024 }, { 5, 293, 1024 }, { 5, 294, 1024 }, { 6, 295, 1024 },
+   { 4, 296, 1024 }, { 5, 297, 1024 }, { 5, 298, 1024 }, { 6, 299, 1024 }, { 5, 300, 1024 }, { 6, 301, 1024 }, { 6, 302, 1024 }, { 7, 303, 1024 },
+   { 4, 304, 1024 }, { 5, 305, 1024 }, { 5, 306, 1024 }, { 6, 307, 1024 }, { 5, 308, 1024 }, { 6, 309, 1024 }, { 6, 310, 1024 }, { 7, 311, 1024 },
+   { 5, 312, 1024 }, { 6, 313, 1024 }, { 6, 314, 1024 }, { 7, 315, 1024 }, { 6, 316, 1024 }, { 7, 317, 1024 }, { 7, 318, 1024 }, { 8, 319, 1024 },
+   { 3, 320, 1024 }, { 4, 321, 1024 }, { 4, 322, 1024 }, { 5, 323, 1024 }, { 4, 324, 1024 }, { 5, 325, 1024 }, { 5, 326, 1024 }, { 6, 327, 1024 },
+   { 4, 328, 1024 }, { 5, 329, 1024 }, { 5, 330, 1024 }, { 6, 331, 1024 }, { 5, 332, 1024 }, { 6, 333, 1024 }, { 6, 334, 1024 }, { 7, 335, 1024 },
+   { 4, 336, 1024 }, { 5, 337, 1024 }, { 5, 338, 1024 }, { 6, 339, 1024 }, { 5, 340, 1024 }, { 6, 341, 1024 }, { 6, 342, 1024 }, { 7, 343, 1024 },
+   { 5, 344, 1024 }, { 6, 345, 1024 }, { 6, 346, 1024 }, { 7, 347, 1024 }, { 6, 348, 1024 }, { 7, 349, 1024 }, { 7, 350, 1024 }, { 8, 351, 1024 },
+   { 4, 352, 1024 }, { 5, 353, 1024 }, { 5, 354, 1024 }, { 6, 355, 1024 }, { 5, 356, 1024 }, { 6, 357, 1024 }, { 6, 358, 1024 }, { 7, 359, 1024 },
+   { 5, 360, 1024 }, { 6, 361, 1024 }, { 6, 362, 1024 }, { 7, 363, 1024 }, { 6, 364, 1024 }, { 7, 365, 1024 }, { 7, 366, 1024 }, { 8, 367, 1024 },
+   { 5, 368, 1024 }, { 6, 369, 1024 }, { 6, 370, 1024 }, { 7, 371, 1024 }, { 6, 372, 1024 }, { 7, 373, 1024 }, { 7, 374, 1024 }, { 8, 375, 1024 },
+   { 6, 376, 1024 }, { 7, 377, 1024 }, { 7, 378, 1024 }, { 8, 379, 1024 }, { 7, 380, 1024 }, { 8, 381, 1024 }, { 8, 382, 1024 }, { 9, 383, 1024 },
+   { 3, 384, 1024 }, { 4, 385, 1024 }, { 4, 386, 1024 }, { 5, 387, 1024 }, { 4, 388, 1024 }, { 5, 389, 1024 }, { 5, 390, 1024 }, { 6, 391, 1024 },
+   { 4, 392, 1024 }, { 5, 393, 1024 }, { 5, 394, 1024 }, { 6, 395, 1024 }, { 5, 396, 1024 }, { 6, 397, 1024 }, { 6, 398, 1024 }, { 7, 399, 1024 },
+   { 4, 400, 1024 }, { 5, 401, 1024 }, { 5, 402, 1024 }, { 6, 403, 1024 }, { 5, 404, 1024 }, { 6, 405, 1024 }, { 6, 406, 1024 }, { 7, 407, 1024 },
+   { 5, 408, 1024 }, { 6, 409, 1024 }, { 6, 410, 1024 }, { 7, 411, 1024 }, { 6, 412, 1024 }, { 7, 413, 1024 }, { 7, 414, 1024 }, { 8, 415, 1024 },
+   { 4, 416, 1024 }, { 5, 417, 1024 }, { 5, 418, 1024 }, { 6, 419, 1024 }, { 5, 420, 1024 }, { 6, 421, 1024 }, { 6, 422, 1024 }, { 7, 423, 1024 },
+   { 5, 424, 1024 }, { 6, 425, 1024 }, { 6, 426, 1024 }, { 7, 427, 1024 }, { 6, 428, 1024 }, { 7, 429, 1024 }, { 7, 430, 1024 }, { 8, 431, 1024 },
+   { 5, 432, 1024 }, { 6, 433, 1024 }, { 6, 434, 1024 }, { 7, 435, 1024 }, { 6, 436, 1024 }, { 7, 437, 1024 }, { 7, 438, 1024 }, { 8, 439, 1024 },
+   { 6, 440, 1024 }, { 7, 441, 1024 }, { 7, 442, 1024 }, { 8, 443, 1024 }, { 7, 444, 1024 }, { 8, 445, 1024 }, { 8, 446, 1024 }, { 9, 447, 1024 },
+   { 4, 448, 1024 }, { 5, 449, 1024 }, { 5, 450, 1024 }, { 6, 451, 1024 }, { 5, 452, 1024 }, { 6, 453, 1024 }, { 6, 454, 1024 }, { 7, 455, 1024 },
+   { 5, 456, 1024 }, { 6, 457, 1024 }, { 6, 458, 1024 }, { 7, 459, 1024 }, { 6, 460, 1024 }, { 7, 461, 1024 }, { 7, 462, 1024 }, { 8, 463, 1024 },
+   { 5, 464, 1024 }, { 6, 465, 1024 }, { 6, 466, 1024 }, { 7, 467, 1024 }, { 6, 468, 1024 }, { 7, 469, 1024 }, { 7, 470, 1024 }, { 8, 471, 1024 },
+   { 6, 472, 1024 }, { 7, 473, 1024 }, { 7, 474, 1024 }, { 8, 475, 1024 }, { 7, 476, 1024 }, { 8, 477, 1024 }, { 8, 478, 1024 }, { 9, 479, 1024 },
+   { 5, 480, 1024 }, { 6, 481, 1024 }, { 6, 482, 1024 }, { 7, 483, 1024 }, { 6, 484, 1024 }, { 7, 485, 1024 }, { 7, 486, 1024 }, { 8, 487, 1024 },
+   { 6, 488, 1024 }, { 7, 489, 1024 }, { 7, 490, 1024 }, { 8, 491, 1024 }, { 7, 492, 1024 }, { 8, 493, 1024 }, { 8, 494, 1024 }, { 9, 495, 1024 },
+   { 6, 496, 1024 }, { 7, 497, 1024 }, { 7, 498, 1024 }, { 8, 499, 1024 }, { 7, 500, 1024 }, { 8, 501, 1024 }, { 8, 502, 1024 }, { 9, 503, 1024 },
+   { 7, 504, 1024 }, { 8, 505, 1024 }, { 8, 506, 1024 }, { 9, 507, 1024 }, { 8, 508, 1024 }, { 9, 509, 1024 }, { 9, 510, 1024 }, { 10, 511, 1024 },
+   { 2, 512, 1024 }, { 3, 513, 1024 }, { 3, 514, 1024 }, { 4, 515, 1024 }, { 3, 516, 1024 }, { 4, 517, 1024 }, { 4, 518, 1024 }, { 5, 519, 1024 },
+   { 3, 520, 1024 }, { 4, 521, 1024 }, { 4, 522, 1024 }, { 5, 523, 1024 }, { 4, 524, 1024 }, { 5, 525, 1024 }, { 5, 526, 1024 }, { 6, 527, 1024 },
+   { 3, 528, 1024 }, { 4, 529, 1024 }, { 4, 530, 1024 }, { 5, 531, 1024 }, { 4, 532, 1024 }, { 5, 533, 1024 }, { 5, 534, 1024 }, { 6, 535, 1024 },
+   { 4, 536, 1024 }, { 5, 537, 1024 }, { 5, 538, 1024 }, { 6, 539, 1024 }, { 5, 540, 1024 }, { 6, 541, 1024 }, { 6, 542, 1024 }, { 7, 543, 1024 },
+   { 3, 544, 1024 }, { 4, 545, 1024 }, { 4, 546, 1024 }, { 5, 547, 1024 }, { 4, 548, 1024 }, { 5, 549, 1024 }, { 5, 550, 1024 }, { 6, 551, 1024 },
+   { 4, 552, 1024 }, { 5, 553, 1024 }, { 5, 554, 1024 }, { 6, 555, 1024 }, { 5, 556, 1024 }, { 6, 557, 1024 }, { 6, 558, 1024 }, { 7, 559, 1024 },
+   { 4, 560, 1024 }, { 5, 561, 1024 }, { 5, 562, 1024 }, { 6, 563, 1024 }, { 5, 564, 1024 }, { 6, 565, 1024 }, { 6, 566, 1024 }, { 7, 567, 1024 },
+   { 5, 568, 1024 }, { 6, 569, 1024 }, { 6, 570, 1024 }, { 7, 571, 1024 }, { 6, 572, 1024 }, { 7, 573, 1024 }, { 7, 574, 1024 }, { 8, 575, 1024 },
+   { 3, 576, 1024 }, { 4, 577, 1024 }, { 4, 578, 1024 }, { 5, 579, 1024 }, { 4, 580, 1024 }, { 5, 581, 1024 }, { 5, 582, 1024 }, { 6, 583, 1024 },
+   { 4, 584, 1024 }, { 5, 585, 1024 }, { 5, 586, 1024 }, { 6, 587, 1024 }, { 5, 588, 1024 }, { 6, 589, 1024 }, { 6, 590, 1024 }, { 7, 591, 1024 },
+   { 4, 592, 1024 }, { 5, 593, 1024 }, { 5, 594, 1024 }, { 6, 595, 1024 }, { 5, 596, 1024 }, { 6, 597, 1024 }, { 6, 598, 1024 }, { 7, 599, 1024 },
+   { 5, 600, 1024 }, { 6, 601, 1024 }, { 6, 602, 1024 }, { 7, 603, 1024 }, { 6, 604, 1024 }, { 7, 605, 1024 }, { 7, 606, 1024 }, { 8, 607, 1024 },
+   { 4, 608, 1024 }, { 5, 609, 1024 }, { 5, 610, 1024 }, { 6, 611, 1024 }, { 5, 612, 1024 }, { 6, 613, 1024 }, { 6, 614, 1024 }, { 7, 615, 1024 },
+   { 5, 616, 1024 }, { 6, 617, 1024 }, { 6, 618, 1024 }, { 7, 619, 1024 }, { 6, 620, 1024 }, { 7, 621, 1024 }, { 7, 622, 1024 }, { 8, 623, 1024 },
+   { 5, 624, 1024 }, { 6, 625, 1024 }, { 6, 626, 1024 }, { 7, 627, 1024 }, { 6, 628, 1024 }, { 7, 629, 1024 }, { 7, 630, 1024 }, { 8, 631, 1024 },
+   { 6, 632, 1024 }, { 7, 633, 1024 }, { 7, 634, 1024 }, { 8, 635, 1024 }, { 7, 636, 1024 }, { 8, 637, 1024 }, { 8, 638, 1024 }, { 9, 639, 1024 },
+   { 3, 640, 1024 }, { 4, 641, 1024 }, { 4, 642, 1024 }, { 5, 643, 1024 }, { 4, 644, 1024 }, { 5, 645, 1024 }, { 5, 646, 1024 }, { 6, 647, 1024 },
+   { 4, 648, 1024 }, { 5, 649, 1024 }, { 5, 650, 1024 }, { 6, 651, 1024 }, { 5, 652, 1024 }, { 6, 653, 1024 }, { 6, 654, 1024 }, { 7, 655, 1024 },
+   { 4, 656, 1024 }, { 5, 657, 1024 }, { 5, 658, 1024 }, { 6, 659, 1024 }, { 5, 660, 1024 }, { 6, 661, 1024 }, { 6, 662, 1024 }, { 7, 663, 1024 },
+   { 5, 664, 1024 }, { 6, 665, 1024 }, { 6, 666, 1024 }, { 7, 667, 1024 }, { 6, 668, 1024 }, { 7, 669, 1024 }, { 7, 670, 1024 }, { 8, 671, 1024 },
+   { 4, 672, 1024 }, { 5, 673, 1024 }, { 5, 674, 1024 }, { 6, 675, 1024 }, { 5, 676, 1024 }, { 6, 677, 1024 }, { 6, 678, 1024 }, { 7, 679, 1024 },
+   { 5, 680, 1024 }, { 6, 681, 1024 }, { 6, 682, 1024 }, { 7, 683, 1024 }, { 6, 684, 1024 }, { 7, 685, 1024 }, { 7, 686, 1024 }, { 8, 687, 1024 },
+   { 5, 688, 1024 }, { 6, 689, 1024 }, { 6, 690, 1024 }, { 7, 691, 1024 }, { 6, 692, 1024 }, { 7, 693, 1024 }, { 7, 694, 1024 }, { 8, 695, 1024 },
+   { 6, 696, 1024 }, { 7, 697, 1024 }, { 7, 698, 1024 }, { 8, 699, 1024 }, { 7, 700, 1024 }, { 8, 701, 1024 }, { 8, 702, 1024 }, { 9, 703, 1024 },
+   { 4, 704, 1024 }, { 5, 705, 1024 }, { 5, 706, 1024 }, { 6, 707, 1024 }, { 5, 708, 1024 }, { 6, 709, 1024 }, { 6, 710, 1024 }, { 7, 711, 1024 },
+   { 5, 712, 1024 }, { 6, 713, 1024 }, { 6, 714, 1024 }, { 7, 715, 1024 }, { 6, 716, 1024 }, { 7, 717, 1024 }, { 7, 718, 1024 }, { 8, 719, 1024 },
+   { 5, 720, 1024 }, { 6, 721, 1024 }, { 6, 722, 1024 }, { 7, 723, 1024 }, { 6, 724, 1024 }, { 7, 725, 1024 }, { 7, 726, 1024 }, { 8, 727, 1024 },
+   { 6, 728, 1024 }, { 7, 729, 1024 }, { 7, 730, 1024 }, { 8, 731, 1024 }, { 7, 732, 1024 }, { 8, 733, 1024 }, { 8, 734, 1024 }, { 9, 735, 1024 },
+   { 5, 736, 1024 }, { 6, 737, 1024 }, { 6, 738, 1024 }, { 7, 739, 1024 }, { 6, 740, 1024 }, { 7, 741, 1024 }, { 7, 742, 1024 }, { 8, 743, 1024 },
+   { 6, 744, 1024 }, { 7, 745, 1024 }, { 7, 746, 1024 }, { 8, 747, 1024 }, { 7, 748, 1024 }, { 8, 749, 1024 }, { 8, 750, 1024 }, { 9, 751, 1024 },
+   { 6, 752, 1024 }, { 7, 753, 1024 }, { 7, 754, 1024 }, { 8, 755, 1024 }, { 7, 756, 1024 }, { 8, 757, 1024 }, { 8, 758, 1024 }, { 9, 759, 1024 },
+   { 7, 760, 1024 }, { 8, 761, 1024 }, { 8, 762, 1024 }, { 9, 763, 1024 }, { 8, 764, 1024 }, { 9, 765, 1024 }, { 9, 766, 1024 }, { 10, 767, 1024 },
+   { 3, 768, 1024 }, { 4, 769, 1024 }, { 4, 770, 1024 }, { 5, 771, 1024 }, { 4, 772, 1024 }, { 5, 773, 1024 }, { 5, 774, 1024 }, { 6, 775, 1024 },
+   { 4, 776, 1024 }, { 5, 777, 1024 }, { 5, 778, 1024 }, { 6, 779, 1024 }, { 5, 780, 1024 }, { 6, 781, 1024 }, { 6, 782, 1024 }, { 7, 783, 1024 },
+   { 4, 784, 1024 }, { 5, 785, 1024 }, { 5, 786, 1024 }, { 6, 787, 1024 }, { 5, 788, 1024 }, { 6, 789, 1024 }, { 6, 790, 1024 }, { 7, 791, 1024 },
+   { 5, 792, 1024 }, { 6, 793, 1024 }, { 6, 794, 1024 }, { 7, 795, 1024 }, { 6, 796, 1024 }, { 7, 797, 1024 }, { 7, 798, 1024 }, { 8, 799, 1024 },
+   { 4, 800, 1024 }, { 5, 801, 1024 }, { 5, 802, 1024 }, { 6, 803, 1024 }, { 5, 804, 1024 }, { 6, 805, 1024 }, { 6, 806, 1024 }, { 7, 807, 1024 },
+   { 5, 808, 1024 }, { 6, 809, 1024 }, { 6, 810, 1024 }, { 7, 811, 1024 }, { 6, 812, 1024 }, { 7, 813, 1024 }, { 7, 814, 1024 }, { 8, 815, 1024 },
+   { 5, 816, 1024 }, { 6, 817, 1024 }, { 6, 818, 1024 }, { 7, 819, 1024 }, { 6, 820, 1024 }, { 7, 821, 1024 }, { 7, 822, 1024 }, { 8, 823, 1024 },
+   { 6, 824, 1024 }, { 7, 825, 1024 }, { 7, 826, 1024 }, { 8, 827, 1024 }, { 7, 828, 1024 }, { 8, 829, 1024 }, { 8, 830, 1024 }, { 9, 831, 1024 },
+   { 4, 832, 1024 }, { 5, 833, 1024 }, { 5, 834, 1024 }, { 6, 835, 1024 }, { 5, 836, 1024 }, { 6, 837, 1024 }, { 6, 838, 1024 }, { 7, 839, 1024 },
+   { 5, 840, 1024 }, { 6, 841, 1024 }, { 6, 842, 1024 }, { 7, 843, 1024 }, { 6, 844, 1024 }, { 7, 845, 1024 }, { 7, 846, 1024 }, { 8, 847, 1024 },
+   { 5, 848, 1024 }, { 6, 849, 1024 }, { 6, 850, 1024 }, { 7, 851, 1024 }, { 6, 852, 1024 }, { 7, 853, 1024 }, { 7, 854, 1024 }, { 8, 855, 1024 },
+   { 6, 856, 1024 }, { 7, 857, 1024 }, { 7, 858, 1024 }, { 8, 859, 1024 }, { 7, 860, 1024 }, { 8, 861, 1024 }, { 8, 862, 1024 }, { 9, 863, 1024 },
+   { 5, 864, 1024 }, { 6, 865, 1024 }, { 6, 866, 1024 }, { 7, 867, 1024 }, { 6, 868, 1024 }, { 7, 869, 1024 }, { 7, 870, 1024 }, { 8, 871, 1024 },
+   { 6, 872, 1024 }, { 7, 873, 1024 }, { 7, 874, 1024 }, { 8, 875, 1024 }, { 7, 876, 1024 }, { 8, 877, 1024 }, { 8, 878, 1024 }, { 9, 879, 1024 },
+   { 6, 880, 1024 }, { 7, 881, 1024 }, { 7, 882, 1024 }, { 8, 883, 1024 }, { 7, 884, 1024 }, { 8, 885, 1024 }, { 8, 886, 1024 }, { 9, 887, 1024 },
+   { 7, 888, 1024 }, { 8, 889, 1024 }, { 8, 890, 1024 }, { 9, 891, 1024 }, { 8, 892, 1024 }, { 9, 893, 1024 }, { 9, 894, 1024 }, { 10, 895, 1024 },
+   { 4, 896, 1024 }, { 5, 897, 1024 }, { 5, 898, 1024 }, { 6, 899, 1024 }, { 5, 900, 1024 }, { 6, 901, 1024 }, { 6, 902, 1024 }, { 7, 903, 1024 },
+   { 5, 904, 1024 }, { 6, 905, 1024 }, { 6, 906, 1024 }, { 7, 907, 1024 }, { 6, 908, 1024 }, { 7, 909, 1024 }, { 7, 910, 1024 }, { 8, 911, 1024 },
+   { 5, 912, 1024 }, { 6, 913, 1024 }, { 6, 914, 1024 }, { 7, 915, 1024 }, { 6, 916, 1024 }, { 7, 917, 1024 }, { 7, 918, 1024 }, { 8, 919, 1024 },
+   { 6, 920, 1024 }, { 7, 921, 1024 }, { 7, 922, 1024 }, { 8, 923, 1024 }, { 7, 924, 1024 }, { 8, 925, 1024 }, { 8, 926, 1024 }, { 9, 927, 1024 },
+   { 5, 928, 1024 }, { 6, 929, 1024 }, { 6, 930, 1024 }, { 7, 931, 1024 }, { 6, 932, 1024 }, { 7, 933, 1024 }, { 7, 934, 1024 }, { 8, 935, 1024 },
+   { 6, 936, 1024 }, { 7, 937, 1024 }, { 7, 938, 1024 }, { 8, 939, 1024 }, { 7, 940, 1024 }, { 8, 941, 1024 }, { 8, 942, 1024 }, { 9, 943, 1024 },
+   { 6, 944, 1024 }, { 7, 945, 1024 }, { 7, 946, 1024 }, { 8, 947, 1024 }, { 7, 948, 1024 }, { 8, 949, 1024 }, { 8, 950, 1024 }, { 9, 951, 1024 },
+   { 7, 952, 1024 }, { 8, 953, 1024 }, { 8, 954, 1024 }, { 9, 955, 1024 }, { 8, 956, 1024 }, { 9, 957, 1024 }, { 9, 958, 1024 }, { 10, 959, 1024 },
+   { 5, 960, 1024 }, { 6, 961, 1024 }, { 6, 962, 1024 }, { 7, 963, 1024 }, { 6, 964, 1024 }, { 7, 965, 1024 }, { 7, 966, 1024 }, { 8, 967, 1024 },
+   { 6, 968, 1024 }, { 7, 969, 1024 }, { 7, 970, 1024 }, { 8, 971, 1024 }, { 7, 972, 1024 }, { 8, 973, 1024 }, { 8, 974, 1024 }, { 9, 975, 1024 },
+   { 6, 976, 1024 }, { 7, 977, 1024 }, { 7, 978, 1024 }, { 8, 979, 1024 }, { 7, 980, 1024 }, { 8, 981, 1024 }, { 8, 982, 1024 }, { 9, 983, 1024 },
+   { 7, 984, 1024 }, { 8, 985, 1024 }, { 8, 986, 1024 }, { 9, 987, 1024 }, { 8, 988, 1024 }, { 9, 989, 1024 }, { 9, 990, 1024 }, { 10, 991, 1024 },
+   { 6, 992, 1024 }, { 7, 993, 1024 }, { 7, 994, 1024 }, { 8, 995, 1024 }, { 7, 996, 1024 }, { 8, 997, 1024 }, { 8, 998, 1024 }, { 9, 999, 1024 },
+   { 7, 1000, 1024 }, { 8, 1001, 1024 }, { 8, 1002, 1024 }, { 9, 1003, 1024 }, { 8, 1004, 1024 }, { 9, 1005, 1024 }, { 9, 1006, 1024 }, { 10, 1007, 1024 },
+   { 7, 1008, 1024 }, { 8, 1009, 1024 }, { 8, 1010, 1024 }, { 9, 1011, 1024 }, { 8, 1012, 1024 }, { 9, 1013, 1024 }, { 9, 1014, 1024 }, { 10, 1015, 1024 },
+   { 8, 1016, 1024 }, { 9, 1017, 1024 }, { 9, 1018, 1024 }, { 10, 1019, 1024 }, { 9, 1020, 1024 }, { 10, 1021, 1024 }, { 10, 1022, 1024 }, { 11, 1023, 1024 },
+#if FP_LUT > 11
+   { 1, 0, 0 }, { 2, 1, 2048 }, { 2, 2, 2048 }, { 3, 3, 2048 }, { 2, 4, 2048 }, { 3, 5, 2048 }, { 3, 6, 2048 }, { 4, 7, 2048 },
+   { 2, 8, 2048 }, { 3, 9, 2048 }, { 3, 10, 2048 }, { 4, 11, 2048 }, { 3, 12, 2048 }, { 4, 13, 2048 }, { 4, 14, 2048 }, { 5, 15, 2048 },
+   { 2, 16, 2048 }, { 3, 17, 2048 }, { 3, 18, 2048 }, { 4, 19, 2048 }, { 3, 20, 2048 }, { 4, 21, 2048 }, { 4, 22, 2048 }, { 5, 23, 2048 },
+   { 3, 24, 2048 }, { 4, 25, 2048 }, { 4, 26, 2048 }, { 5, 27, 2048 }, { 4, 28, 2048 }, { 5, 29, 2048 }, { 5, 30, 2048 }, { 6, 31, 2048 },
+   { 2, 32, 2048 }, { 3, 33, 2048 }, { 3, 34, 2048 }, { 4, 35, 2048 }, { 3, 36, 2048 }, { 4, 37, 2048 }, { 4, 38, 2048 }, { 5, 39, 2048 },
+   { 3, 40, 2048 }, { 4, 41, 2048 }, { 4, 42, 2048 }, { 5, 43, 2048 }, { 4, 44, 2048 }, { 5, 45, 2048 }, { 5, 46, 2048 }, { 6, 47, 2048 },
+   { 3, 48, 2048 }, { 4, 49, 2048 }, { 4, 50, 2048 }, { 5, 51, 2048 }, { 4, 52, 2048 }, { 5, 53, 2048 }, { 5, 54, 2048 }, { 6, 55, 2048 },
+   { 4, 56, 2048 }, { 5, 57, 2048 }, { 5, 58, 2048 }, { 6, 59, 2048 }, { 5, 60, 2048 }, { 6, 61, 2048 }, { 6, 62, 2048 }, { 7, 63, 2048 },
+   { 2, 64, 2048 }, { 3, 65, 2048 }, { 3, 66, 2048 }, { 4, 67, 2048 }, { 3, 68, 2048 }, { 4, 69, 2048 }, { 4, 70, 2048 }, { 5, 71, 2048 },
+   { 3, 72, 2048 }, { 4, 73, 2048 }, { 4, 74, 2048 }, { 5, 75, 2048 }, { 4, 76, 2048 }, { 5, 77, 2048 }, { 5, 78, 2048 }, { 6, 79, 2048 },
+   { 3, 80, 2048 }, { 4, 81, 2048 }, { 4, 82, 2048 }, { 5, 83, 2048 }, { 4, 84, 2048 }, { 5, 85, 2048 }, { 5, 86, 2048 }, { 6, 87, 2048 },
+   { 4, 88, 2048 }, { 5, 89, 2048 }, { 5, 90, 2048 }, { 6, 91, 2048 }, { 5, 92, 2048 }, { 6, 93, 2048 }, { 6, 94, 2048 }, { 7, 95, 2048 },
+   { 3, 96, 2048 }, { 4, 97, 2048 }, { 4, 98, 2048 }, { 5, 99, 2048 }, { 4, 100, 2048 }, { 5, 101, 2048 }, { 5, 102, 2048 }, { 6, 103, 2048 },
+   { 4, 104, 2048 }, { 5, 105, 2048 }, { 5, 106, 2048 }, { 6, 107, 2048 }, { 5, 108, 2048 }, { 6, 109, 2048 }, { 6, 110, 2048 }, { 7, 111, 2048 },
+   { 4, 112, 2048 }, { 5, 113, 2048 }, { 5, 114, 2048 }, { 6, 115, 2048 }, { 5, 116, 2048 }, { 6, 117, 2048 }, { 6, 118, 2048 }, { 7, 119, 2048 },
+   { 5, 120, 2048 }, { 6, 121, 2048 }, { 6, 122, 2048 }, { 7, 123, 2048 }, { 6, 124, 2048 }, { 7, 125, 2048 }, { 7, 126, 2048 }, { 8, 127, 2048 },
+   { 2, 128, 2048 }, { 3, 129, 2048 }, { 3, 130, 2048 }, { 4, 131, 2048 }, { 3, 132, 2048 }, { 4, 133, 2048 }, { 4, 134, 2048 }, { 5, 135, 2048 },
+   { 3, 136, 2048 }, { 4, 137, 2048 }, { 4, 138, 2048 }, { 5, 139, 2048 }, { 4, 140, 2048 }, { 5, 141, 2048 }, { 5, 142, 2048 }, { 6, 143, 2048 },
+   { 3, 144, 2048 }, { 4, 145, 2048 }, { 4, 146, 2048 }, { 5, 147, 2048 }, { 4, 148, 2048 }, { 5, 149, 2048 }, { 5, 150, 2048 }, { 6, 151, 2048 },
+   { 4, 152, 2048 }, { 5, 153, 2048 }, { 5, 154, 2048 }, { 6, 155, 2048 }, { 5, 156, 2048 }, { 6, 157, 2048 }, { 6, 158, 2048 }, { 7, 159, 2048 },
+   { 3, 160, 2048 }, { 4, 161, 2048 }, { 4, 162, 2048 }, { 5, 163, 2048 }, { 4, 164, 2048 }, { 5, 165, 2048 }, { 5, 166, 2048 }, { 6, 167, 2048 },
+   { 4, 168, 2048 }, { 5, 169, 2048 }, { 5, 170, 2048 }, { 6, 171, 2048 }, { 5, 172, 2048 }, { 6, 173, 2048 }, { 6, 174, 2048 }, { 7, 175, 2048 },
+   { 4, 176, 2048 }, { 5, 177, 2048 }, { 5, 178, 2048 }, { 6, 179, 2048 }, { 5, 180, 2048 }, { 6, 181, 2048 }, { 6, 182, 2048 }, { 7, 183, 2048 },
+   { 5, 184, 2048 }, { 6, 185, 2048 }, { 6, 186, 2048 }, { 7, 187, 2048 }, { 6, 188, 2048 }, { 7, 189, 2048 }, { 7, 190, 2048 }, { 8, 191, 2048 },
+   { 3, 192, 2048 }, { 4, 193, 2048 }, { 4, 194, 2048 }, { 5, 195, 2048 }, { 4, 196, 2048 }, { 5, 197, 2048 }, { 5, 198, 2048 }, { 6, 199, 2048 },
+   { 4, 200, 2048 }, { 5, 201, 2048 }, { 5, 202, 2048 }, { 6, 203, 2048 }, { 5, 204, 2048 }, { 6, 205, 2048 }, { 6, 206, 2048 }, { 7, 207, 2048 },
+   { 4, 208, 2048 }, { 5, 209, 2048 }, { 5, 210, 2048 }, { 6, 211, 2048 }, { 5, 212, 2048 }, { 6, 213, 2048 }, { 6, 214, 2048 }, { 7, 215, 2048 },
+   { 5, 216, 2048 }, { 6, 217, 2048 }, { 6, 218, 2048 }, { 7, 219, 2048 }, { 6, 220, 2048 }, { 7, 221, 2048 }, { 7, 222, 2048 }, { 8, 223, 2048 },
+   { 4, 224, 2048 }, { 5, 225, 2048 }, { 5, 226, 2048 }, { 6, 227, 2048 }, { 5, 228, 2048 }, { 6, 229, 2048 }, { 6, 230, 2048 }, { 7, 231, 2048 },
+   { 5, 232, 2048 }, { 6, 233, 2048 }, { 6, 234, 2048 }, { 7, 235, 2048 }, { 6, 236, 2048 }, { 7, 237, 2048 }, { 7, 238, 2048 }, { 8, 239, 2048 },
+   { 5, 240, 2048 }, { 6, 241, 2048 }, { 6, 242, 2048 }, { 7, 243, 2048 }, { 6, 244, 2048 }, { 7, 245, 2048 }, { 7, 246, 2048 }, { 8, 247, 2048 },
+   { 6, 248, 2048 }, { 7, 249, 2048 }, { 7, 250, 2048 }, { 8, 251, 2048 }, { 7, 252, 2048 }, { 8, 253, 2048 }, { 8, 254, 2048 }, { 9, 255, 2048 },
+   { 2, 256, 2048 }, { 3, 257, 2048 }, { 3, 258, 2048 }, { 4, 259, 2048 }, { 3, 260, 2048 }, { 4, 261, 2048 }, { 4, 262, 2048 }, { 5, 263, 2048 },
+   { 3, 264, 2048 }, { 4, 265, 2048 }, { 4, 266, 2048 }, { 5, 267, 2048 }, { 4, 268, 2048 }, { 5, 269, 2048 }, { 5, 270, 2048 }, { 6, 271, 2048 },
+   { 3, 272, 2048 }, { 4, 273, 2048 }, { 4, 274, 2048 }, { 5, 275, 2048 }, { 4, 276, 2048 }, { 5, 277, 2048 }, { 5, 278, 2048 }, { 6, 279, 2048 },
+   { 4, 280, 2048 }, { 5, 281, 2048 }, { 5, 282, 2048 }, { 6, 283, 2048 }, { 5, 284, 2048 }, { 6, 285, 2048 }, { 6, 286, 2048 }, { 7, 287, 2048 },
+   { 3, 288, 2048 }, { 4, 289, 2048 }, { 4, 290, 2048 }, { 5, 291, 2048 }, { 4, 292, 2048 }, { 5, 293, 2048 }, { 5, 294, 2048 }, { 6, 295, 2048 },
+   { 4, 296, 2048 }, { 5, 297, 2048 }, { 5, 298, 2048 }, { 6, 299, 2048 }, { 5, 300, 2048 }, { 6, 301, 2048 }, { 6, 302, 2048 }, { 7, 303, 2048 },
+   { 4, 304, 2048 }, { 5, 305, 2048 }, { 5, 306, 2048 }, { 6, 307, 2048 }, { 5, 308, 2048 }, { 6, 309, 2048 }, { 6, 310, 2048 }, { 7, 311, 2048 },
+   { 5, 312, 2048 }, { 6, 313, 2048 }, { 6, 314, 2048 }, { 7, 315, 2048 }, { 6, 316, 2048 }, { 7, 317, 2048 }, { 7, 318, 2048 }, { 8, 319, 2048 },
+   { 3, 320, 2048 }, { 4, 321, 2048 }, { 4, 322, 2048 }, { 5, 323, 2048 }, { 4, 324, 2048 }, { 5, 325, 2048 }, { 5, 326, 2048 }, { 6, 327, 2048 },
+   { 4, 328, 2048 }, { 5, 329, 2048 }, { 5, 330, 2048 }, { 6, 331, 2048 }, { 5, 332, 2048 }, { 6, 333, 2048 }, { 6, 334, 2048 }, { 7, 335, 2048 },
+   { 4, 336, 2048 }, { 5, 337, 2048 }, { 5, 338, 2048 }, { 6, 339, 2048 }, { 5, 340, 2048 }, { 6, 341, 2048 }, { 6, 342, 2048 }, { 7, 343, 2048 },
+   { 5, 344, 2048 }, { 6, 345, 2048 }, { 6, 346, 2048 }, { 7, 347, 2048 }, { 6, 348, 2048 }, { 7, 349, 2048 }, { 7, 350, 2048 }, { 8, 351, 2048 },
+   { 4, 352, 2048 }, { 5, 353, 2048 }, { 5, 354, 2048 }, { 6, 355, 2048 }, { 5, 356, 2048 }, { 6, 357, 2048 }, { 6, 358, 2048 }, { 7, 359, 2048 },
+   { 5, 360, 2048 }, { 6, 361, 2048 }, { 6, 362, 2048 }, { 7, 363, 2048 }, { 6, 364, 2048 }, { 7, 365, 2048 }, { 7, 366, 2048 }, { 8, 367, 2048 },
+   { 5, 368, 2048 }, { 6, 369, 2048 }, { 6, 370, 2048 }, { 7, 371, 2048 }, { 6, 372, 2048 }, { 7, 373, 2048 }, { 7, 374, 2048 }, { 8, 375, 2048 },
+   { 6, 376, 2048 }, { 7, 377, 2048 }, { 7, 378, 2048 }, { 8, 379, 2048 }, { 7, 380, 2048 }, { 8, 381, 2048 }, { 8, 382, 2048 }, { 9, 383, 2048 },
+   { 3, 384, 2048 }, { 4, 385, 2048 }, { 4, 386, 2048 }, { 5, 387, 2048 }, { 4, 388, 2048 }, { 5, 389, 2048 }, { 5, 390, 2048 }, { 6, 391, 2048 },
+   { 4, 392, 2048 }, { 5, 393, 2048 }, { 5, 394, 2048 }, { 6, 395, 2048 }, { 5, 396, 2048 }, { 6, 397, 2048 }, { 6, 398, 2048 }, { 7, 399, 2048 },
+   { 4, 400, 2048 }, { 5, 401, 2048 }, { 5, 402, 2048 }, { 6, 403, 2048 }, { 5, 404, 2048 }, { 6, 405, 2048 }, { 6, 406, 2048 }, { 7, 407, 2048 },
+   { 5, 408, 2048 }, { 6, 409, 2048 }, { 6, 410, 2048 }, { 7, 411, 2048 }, { 6, 412, 2048 }, { 7, 413, 2048 }, { 7, 414, 2048 }, { 8, 415, 2048 },
+   { 4, 416, 2048 }, { 5, 417, 2048 }, { 5, 418, 2048 }, { 6, 419, 2048 }, { 5, 420, 2048 }, { 6, 421, 2048 }, { 6, 422, 2048 }, { 7, 423, 2048 },
+   { 5, 424, 2048 }, { 6, 425, 2048 }, { 6, 426, 2048 }, { 7, 427, 2048 }, { 6, 428, 2048 }, { 7, 429, 2048 }, { 7, 430, 2048 }, { 8, 431, 2048 },
+   { 5, 432, 2048 }, { 6, 433, 2048 }, { 6, 434, 2048 }, { 7, 435, 2048 }, { 6, 436, 2048 }, { 7, 437, 2048 }, { 7, 438, 2048 }, { 8, 439, 2048 },
+   { 6, 440, 2048 }, { 7, 441, 2048 }, { 7, 442, 2048 }, { 8, 443, 2048 }, { 7, 444, 2048 }, { 8, 445, 2048 }, { 8, 446, 2048 }, { 9, 447, 2048 },
+   { 4, 448, 2048 }, { 5, 449, 2048 }, { 5, 450, 2048 }, { 6, 451, 2048 }, { 5, 452, 2048 }, { 6, 453, 2048 }, { 6, 454, 2048 }, { 7, 455, 2048 },
+   { 5, 456, 2048 }, { 6, 457, 2048 }, { 6, 458, 2048 }, { 7, 459, 2048 }, { 6, 460, 2048 }, { 7, 461, 2048 }, { 7, 462, 2048 }, { 8, 463, 2048 },
+   { 5, 464, 2048 }, { 6, 465, 2048 }, { 6, 466, 2048 }, { 7, 467, 2048 }, { 6, 468, 2048 }, { 7, 469, 2048 }, { 7, 470, 2048 }, { 8, 471, 2048 },
+   { 6, 472, 2048 }, { 7, 473, 2048 }, { 7, 474, 2048 }, { 8, 475, 2048 }, { 7, 476, 2048 }, { 8, 477, 2048 }, { 8, 478, 2048 }, { 9, 479, 2048 },
+   { 5, 480, 2048 }, { 6, 481, 2048 }, { 6, 482, 2048 }, { 7, 483, 2048 }, { 6, 484, 2048 }, { 7, 485, 2048 }, { 7, 486, 2048 }, { 8, 487, 2048 },
+   { 6, 488, 2048 }, { 7, 489, 2048 }, { 7, 490, 2048 }, { 8, 491, 2048 }, { 7, 492, 2048 }, { 8, 493, 2048 }, { 8, 494, 2048 }, { 9, 495, 2048 },
+   { 6, 496, 2048 }, { 7, 497, 2048 }, { 7, 498, 2048 }, { 8, 499, 2048 }, { 7, 500, 2048 }, { 8, 501, 2048 }, { 8, 502, 2048 }, { 9, 503, 2048 },
+   { 7, 504, 2048 }, { 8, 505, 2048 }, { 8, 506, 2048 }, { 9, 507, 2048 }, { 8, 508, 2048 }, { 9, 509, 2048 }, { 9, 510, 2048 }, { 10, 511, 2048 },
+   { 2, 512, 2048 }, { 3, 513, 2048 }, { 3, 514, 2048 }, { 4, 515, 2048 }, { 3, 516, 2048 }, { 4, 517, 2048 }, { 4, 518, 2048 }, { 5, 519, 2048 },
+   { 3, 520, 2048 }, { 4, 521, 2048 }, { 4, 522, 2048 }, { 5, 523, 2048 }, { 4, 524, 2048 }, { 5, 525, 2048 }, { 5, 526, 2048 }, { 6, 527, 2048 },
+   { 3, 528, 2048 }, { 4, 529, 2048 }, { 4, 530, 2048 }, { 5, 531, 2048 }, { 4, 532, 2048 }, { 5, 533, 2048 }, { 5, 534, 2048 }, { 6, 535, 2048 },
+   { 4, 536, 2048 }, { 5, 537, 2048 }, { 5, 538, 2048 }, { 6, 539, 2048 }, { 5, 540, 2048 }, { 6, 541, 2048 }, { 6, 542, 2048 }, { 7, 543, 2048 },
+   { 3, 544, 2048 }, { 4, 545, 2048 }, { 4, 546, 2048 }, { 5, 547, 2048 }, { 4, 548, 2048 }, { 5, 549, 2048 }, { 5, 550, 2048 }, { 6, 551, 2048 },
+   { 4, 552, 2048 }, { 5, 553, 2048 }, { 5, 554, 2048 }, { 6, 555, 2048 }, { 5, 556, 2048 }, { 6, 557, 2048 }, { 6, 558, 2048 }, { 7, 559, 2048 },
+   { 4, 560, 2048 }, { 5, 561, 2048 }, { 5, 562, 2048 }, { 6, 563, 2048 }, { 5, 564, 2048 }, { 6, 565, 2048 }, { 6, 566, 2048 }, { 7, 567, 2048 },
+   { 5, 568, 2048 }, { 6, 569, 2048 }, { 6, 570, 2048 }, { 7, 571, 2048 }, { 6, 572, 2048 }, { 7, 573, 2048 }, { 7, 574, 2048 }, { 8, 575, 2048 },
+   { 3, 576, 2048 }, { 4, 577, 2048 }, { 4, 578, 2048 }, { 5, 579, 2048 }, { 4, 580, 2048 }, { 5, 581, 2048 }, { 5, 582, 2048 }, { 6, 583, 2048 },
+   { 4, 584, 2048 }, { 5, 585, 2048 }, { 5, 586, 2048 }, { 6, 587, 2048 }, { 5, 588, 2048 }, { 6, 589, 2048 }, { 6, 590, 2048 }, { 7, 591, 2048 },
+   { 4, 592, 2048 }, { 5, 593, 2048 }, { 5, 594, 2048 }, { 6, 595, 2048 }, { 5, 596, 2048 }, { 6, 597, 2048 }, { 6, 598, 2048 }, { 7, 599, 2048 },
+   { 5, 600, 2048 }, { 6, 601, 2048 }, { 6, 602, 2048 }, { 7, 603, 2048 }, { 6, 604, 2048 }, { 7, 605, 2048 }, { 7, 606, 2048 }, { 8, 607, 2048 },
+   { 4, 608, 2048 }, { 5, 609, 2048 }, { 5, 610, 2048 }, { 6, 611, 2048 }, { 5, 612, 2048 }, { 6, 613, 2048 }, { 6, 614, 2048 }, { 7, 615, 2048 },
+   { 5, 616, 2048 }, { 6, 617, 2048 }, { 6, 618, 2048 }, { 7, 619, 2048 }, { 6, 620, 2048 }, { 7, 621, 2048 }, { 7, 622, 2048 }, { 8, 623, 2048 },
+   { 5, 624, 2048 }, { 6, 625, 2048 }, { 6, 626, 2048 }, { 7, 627, 2048 }, { 6, 628, 2048 }, { 7, 629, 2048 }, { 7, 630, 2048 }, { 8, 631, 2048 },
+   { 6, 632, 2048 }, { 7, 633, 2048 }, { 7, 634, 2048 }, { 8, 635, 2048 }, { 7, 636, 2048 }, { 8, 637, 2048 }, { 8, 638, 2048 }, { 9, 639, 2048 },
+   { 3, 640, 2048 }, { 4, 641, 2048 }, { 4, 642, 2048 }, { 5, 643, 2048 }, { 4, 644, 2048 }, { 5, 645, 2048 }, { 5, 646, 2048 }, { 6, 647, 2048 },
+   { 4, 648, 2048 }, { 5, 649, 2048 }, { 5, 650, 2048 }, { 6, 651, 2048 }, { 5, 652, 2048 }, { 6, 653, 2048 }, { 6, 654, 2048 }, { 7, 655, 2048 },
+   { 4, 656, 2048 }, { 5, 657, 2048 }, { 5, 658, 2048 }, { 6, 659, 2048 }, { 5, 660, 2048 }, { 6, 661, 2048 }, { 6, 662, 2048 }, { 7, 663, 2048 },
+   { 5, 664, 2048 }, { 6, 665, 2048 }, { 6, 666, 2048 }, { 7, 667, 2048 }, { 6, 668, 2048 }, { 7, 669, 2048 }, { 7, 670, 2048 }, { 8, 671, 2048 },
+   { 4, 672, 2048 }, { 5, 673, 2048 }, { 5, 674, 2048 }, { 6, 675, 2048 }, { 5, 676, 2048 }, { 6, 677, 2048 }, { 6, 678, 2048 }, { 7, 679, 2048 },
+   { 5, 680, 2048 }, { 6, 681, 2048 }, { 6, 682, 2048 }, { 7, 683, 2048 }, { 6, 684, 2048 }, { 7, 685, 2048 }, { 7, 686, 2048 }, { 8, 687, 2048 },
+   { 5, 688, 2048 }, { 6, 689, 2048 }, { 6, 690, 2048 }, { 7, 691, 2048 }, { 6, 692, 2048 }, { 7, 693, 2048 }, { 7, 694, 2048 }, { 8, 695, 2048 },
+   { 6, 696, 2048 }, { 7, 697, 2048 }, { 7, 698, 2048 }, { 8, 699, 2048 }, { 7, 700, 2048 }, { 8, 701, 2048 }, { 8, 702, 2048 }, { 9, 703, 2048 },
+   { 4, 704, 2048 }, { 5, 705, 2048 }, { 5, 706, 2048 }, { 6, 707, 2048 }, { 5, 708, 2048 }, { 6, 709, 2048 }, { 6, 710, 2048 }, { 7, 711, 2048 },
+   { 5, 712, 2048 }, { 6, 713, 2048 }, { 6, 714, 2048 }, { 7, 715, 2048 }, { 6, 716, 2048 }, { 7, 717, 2048 }, { 7, 718, 2048 }, { 8, 719, 2048 },
+   { 5, 720, 2048 }, { 6, 721, 2048 }, { 6, 722, 2048 }, { 7, 723, 2048 }, { 6, 724, 2048 }, { 7, 725, 2048 }, { 7, 726, 2048 }, { 8, 727, 2048 },
+   { 6, 728, 2048 }, { 7, 729, 2048 }, { 7, 730, 2048 }, { 8, 731, 2048 }, { 7, 732, 2048 }, { 8, 733, 2048 }, { 8, 734, 2048 }, { 9, 735, 2048 },
+   { 5, 736, 2048 }, { 6, 737, 2048 }, { 6, 738, 2048 }, { 7, 739, 2048 }, { 6, 740, 2048 }, { 7, 741, 2048 }, { 7, 742, 2048 }, { 8, 743, 2048 },
+   { 6, 744, 2048 }, { 7, 745, 2048 }, { 7, 746, 2048 }, { 8, 747, 2048 }, { 7, 748, 2048 }, { 8, 749, 2048 }, { 8, 750, 2048 }, { 9, 751, 2048 },
+   { 6, 752, 2048 }, { 7, 753, 2048 }, { 7, 754, 2048 }, { 8, 755, 2048 }, { 7, 756, 2048 }, { 8, 757, 2048 }, { 8, 758, 2048 }, { 9, 759, 2048 },
+   { 7, 760, 2048 }, { 8, 761, 2048 }, { 8, 762, 2048 }, { 9, 763, 2048 }, { 8, 764, 2048 }, { 9, 765, 2048 }, { 9, 766, 2048 }, { 10, 767, 2048 },
+   { 3, 768, 2048 }, { 4, 769, 2048 }, { 4, 770, 2048 }, { 5, 771, 2048 }, { 4, 772, 2048 }, { 5, 773, 2048 }, { 5, 774, 2048 }, { 6, 775, 2048 },
+   { 4, 776, 2048 }, { 5, 777, 2048 }, { 5, 778, 2048 }, { 6, 779, 2048 }, { 5, 780, 2048 }, { 6, 781, 2048 }, { 6, 782, 2048 }, { 7, 783, 2048 },
+   { 4, 784, 2048 }, { 5, 785, 2048 }, { 5, 786, 2048 }, { 6, 787, 2048 }, { 5, 788, 2048 }, { 6, 789, 2048 }, { 6, 790, 2048 }, { 7, 791, 2048 },
+   { 5, 792, 2048 }, { 6, 793, 2048 }, { 6, 794, 2048 }, { 7, 795, 2048 }, { 6, 796, 2048 }, { 7, 797, 2048 }, { 7, 798, 2048 }, { 8, 799, 2048 },
+   { 4, 800, 2048 }, { 5, 801, 2048 }, { 5, 802, 2048 }, { 6, 803, 2048 }, { 5, 804, 2048 }, { 6, 805, 2048 }, { 6, 806, 2048 }, { 7, 807, 2048 },
+   { 5, 808, 2048 }, { 6, 809, 2048 }, { 6, 810, 2048 }, { 7, 811, 2048 }, { 6, 812, 2048 }, { 7, 813, 2048 }, { 7, 814, 2048 }, { 8, 815, 2048 },
+   { 5, 816, 2048 }, { 6, 817, 2048 }, { 6, 818, 2048 }, { 7, 819, 2048 }, { 6, 820, 2048 }, { 7, 821, 2048 }, { 7, 822, 2048 }, { 8, 823, 2048 },
+   { 6, 824, 2048 }, { 7, 825, 2048 }, { 7, 826, 2048 }, { 8, 827, 2048 }, { 7, 828, 2048 }, { 8, 829, 2048 }, { 8, 830, 2048 }, { 9, 831, 2048 },
+   { 4, 832, 2048 }, { 5, 833, 2048 }, { 5, 834, 2048 }, { 6, 835, 2048 }, { 5, 836, 2048 }, { 6, 837, 2048 }, { 6, 838, 2048 }, { 7, 839, 2048 },
+   { 5, 840, 2048 }, { 6, 841, 2048 }, { 6, 842, 2048 }, { 7, 843, 2048 }, { 6, 844, 2048 }, { 7, 845, 2048 }, { 7, 846, 2048 }, { 8, 847, 2048 },
+   { 5, 848, 2048 }, { 6, 849, 2048 }, { 6, 850, 2048 }, { 7, 851, 2048 }, { 6, 852, 2048 }, { 7, 853, 2048 }, { 7, 854, 2048 }, { 8, 855, 2048 },
+   { 6, 856, 2048 }, { 7, 857, 2048 }, { 7, 858, 2048 }, { 8, 859, 2048 }, { 7, 860, 2048 }, { 8, 861, 2048 }, { 8, 862, 2048 }, { 9, 863, 2048 },
+   { 5, 864, 2048 }, { 6, 865, 2048 }, { 6, 866, 2048 }, { 7, 867, 2048 }, { 6, 868, 2048 }, { 7, 869, 2048 }, { 7, 870, 2048 }, { 8, 871, 2048 },
+   { 6, 872, 2048 }, { 7, 873, 2048 }, { 7, 874, 2048 }, { 8, 875, 2048 }, { 7, 876, 2048 }, { 8, 877, 2048 }, { 8, 878, 2048 }, { 9, 879, 2048 },
+   { 6, 880, 2048 }, { 7, 881, 2048 }, { 7, 882, 2048 }, { 8, 883, 2048 }, { 7, 884, 2048 }, { 8, 885, 2048 }, { 8, 886, 2048 }, { 9, 887, 2048 },
+   { 7, 888, 2048 }, { 8, 889, 2048 }, { 8, 890, 2048 }, { 9, 891, 2048 }, { 8, 892, 2048 }, { 9, 893, 2048 }, { 9, 894, 2048 }, { 10, 895, 2048 },
+   { 4, 896, 2048 }, { 5, 897, 2048 }, { 5, 898, 2048 }, { 6, 899, 2048 }, { 5, 900, 2048 }, { 6, 901, 2048 }, { 6, 902, 2048 }, { 7, 903, 2048 },
+   { 5, 904, 2048 }, { 6, 905, 2048 }, { 6, 906, 2048 }, { 7, 907, 2048 }, { 6, 908, 2048 }, { 7, 909, 2048 }, { 7, 910, 2048 }, { 8, 911, 2048 },
+   { 5, 912, 2048 }, { 6, 913, 2048 }, { 6, 914, 2048 }, { 7, 915, 2048 }, { 6, 916, 2048 }, { 7, 917, 2048 }, { 7, 918, 2048 }, { 8, 919, 2048 },
+   { 6, 920, 2048 }, { 7, 921, 2048 }, { 7, 922, 2048 }, { 8, 923, 2048 }, { 7, 924, 2048 }, { 8, 925, 2048 }, { 8, 926, 2048 }, { 9, 927, 2048 },
+   { 5, 928, 2048 }, { 6, 929, 2048 }, { 6, 930, 2048 }, { 7, 931, 2048 }, { 6, 932, 2048 }, { 7, 933, 2048 }, { 7, 934, 2048 }, { 8, 935, 2048 },
+   { 6, 936, 2048 }, { 7, 937, 2048 }, { 7, 938, 2048 }, { 8, 939, 2048 }, { 7, 940, 2048 }, { 8, 941, 2048 }, { 8, 942, 2048 }, { 9, 943, 2048 },
+   { 6, 944, 2048 }, { 7, 945, 2048 }, { 7, 946, 2048 }, { 8, 947, 2048 }, { 7, 948, 2048 }, { 8, 949, 2048 }, { 8, 950, 2048 }, { 9, 951, 2048 },
+   { 7, 952, 2048 }, { 8, 953, 2048 }, { 8, 954, 2048 }, { 9, 955, 2048 }, { 8, 956, 2048 }, { 9, 957, 2048 }, { 9, 958, 2048 }, { 10, 959, 2048 },
+   { 5, 960, 2048 }, { 6, 961, 2048 }, { 6, 962, 2048 }, { 7, 963, 2048 }, { 6, 964, 2048 }, { 7, 965, 2048 }, { 7, 966, 2048 }, { 8, 967, 2048 },
+   { 6, 968, 2048 }, { 7, 969, 2048 }, { 7, 970, 2048 }, { 8, 971, 2048 }, { 7, 972, 2048 }, { 8, 973, 2048 }, { 8, 974, 2048 }, { 9, 975, 2048 },
+   { 6, 976, 2048 }, { 7, 977, 2048 }, { 7, 978, 2048 }, { 8, 979, 2048 }, { 7, 980, 2048 }, { 8, 981, 2048 }, { 8, 982, 2048 }, { 9, 983, 2048 },
+   { 7, 984, 2048 }, { 8, 985, 2048 }, { 8, 986, 2048 }, { 9, 987, 2048 }, { 8, 988, 2048 }, { 9, 989, 2048 }, { 9, 990, 2048 }, { 10, 991, 2048 },
+   { 6, 992, 2048 }, { 7, 993, 2048 }, { 7, 994, 2048 }, { 8, 995, 2048 }, { 7, 996, 2048 }, { 8, 997, 2048 }, { 8, 998, 2048 }, { 9, 999, 2048 },
+   { 7, 1000, 2048 }, { 8, 1001, 2048 }, { 8, 1002, 2048 }, { 9, 1003, 2048 }, { 8, 1004, 2048 }, { 9, 1005, 2048 }, { 9, 1006, 2048 }, { 10, 1007, 2048 },
+   { 7, 1008, 2048 }, { 8, 1009, 2048 }, { 8, 1010, 2048 }, { 9, 1011, 2048 }, { 8, 1012, 2048 }, { 9, 1013, 2048 }, { 9, 1014, 2048 }, { 10, 1015, 2048 },
+   { 8, 1016, 2048 }, { 9, 1017, 2048 }, { 9, 1018, 2048 }, { 10, 1019, 2048 }, { 9, 1020, 2048 }, { 10, 1021, 2048 }, { 10, 1022, 2048 }, { 11, 1023, 2048 },
+   { 2, 1024, 2048 }, { 3, 1025, 2048 }, { 3, 1026, 2048 }, { 4, 1027, 2048 }, { 3, 1028, 2048 }, { 4, 1029, 2048 }, { 4, 1030, 2048 }, { 5, 1031, 2048 },
+   { 3, 1032, 2048 }, { 4, 1033, 2048 }, { 4, 1034, 2048 }, { 5, 1035, 2048 }, { 4, 1036, 2048 }, { 5, 1037, 2048 }, { 5, 1038, 2048 }, { 6, 1039, 2048 },
+   { 3, 1040, 2048 }, { 4, 1041, 2048 }, { 4, 1042, 2048 }, { 5, 1043, 2048 }, { 4, 1044, 2048 }, { 5, 1045, 2048 }, { 5, 1046, 2048 }, { 6, 1047, 2048 },
+   { 4, 1048, 2048 }, { 5, 1049, 2048 }, { 5, 1050, 2048 }, { 6, 1051, 2048 }, { 5, 1052, 2048 }, { 6, 1053, 2048 }, { 6, 1054, 2048 }, { 7, 1055, 2048 },
+   { 3, 1056, 2048 }, { 4, 1057, 2048 }, { 4, 1058, 2048 }, { 5, 1059, 2048 }, { 4, 1060, 2048 }, { 5, 1061, 2048 }, { 5, 1062, 2048 }, { 6, 1063, 2048 },
+   { 4, 1064, 2048 }, { 5, 1065, 2048 }, { 5, 1066, 2048 }, { 6, 1067, 2048 }, { 5, 1068, 2048 }, { 6, 1069, 2048 }, { 6, 1070, 2048 }, { 7, 1071, 2048 },
+   { 4, 1072, 2048 }, { 5, 1073, 2048 }, { 5, 1074, 2048 }, { 6, 1075, 2048 }, { 5, 1076, 2048 }, { 6, 1077, 2048 }, { 6, 1078, 2048 }, { 7, 1079, 2048 },
+   { 5, 1080, 2048 }, { 6, 1081, 2048 }, { 6, 1082, 2048 }, { 7, 1083, 2048 }, { 6, 1084, 2048 }, { 7, 1085, 2048 }, { 7, 1086, 2048 }, { 8, 1087, 2048 },
+   { 3, 1088, 2048 }, { 4, 1089, 2048 }, { 4, 1090, 2048 }, { 5, 1091, 2048 }, { 4, 1092, 2048 }, { 5, 1093, 2048 }, { 5, 1094, 2048 }, { 6, 1095, 2048 },
+   { 4, 1096, 2048 }, { 5, 1097, 2048 }, { 5, 1098, 2048 }, { 6, 1099, 2048 }, { 5, 1100, 2048 }, { 6, 1101, 2048 }, { 6, 1102, 2048 }, { 7, 1103, 2048 },
+   { 4, 1104, 2048 }, { 5, 1105, 2048 }, { 5, 1106, 2048 }, { 6, 1107, 2048 }, { 5, 1108, 2048 }, { 6, 1109, 2048 }, { 6, 1110, 2048 }, { 7, 1111, 2048 },
+   { 5, 1112, 2048 }, { 6, 1113, 2048 }, { 6, 1114, 2048 }, { 7, 1115, 2048 }, { 6, 1116, 2048 }, { 7, 1117, 2048 }, { 7, 1118, 2048 }, { 8, 1119, 2048 },
+   { 4, 1120, 2048 }, { 5, 1121, 2048 }, { 5, 1122, 2048 }, { 6, 1123, 2048 }, { 5, 1124, 2048 }, { 6, 1125, 2048 }, { 6, 1126, 2048 }, { 7, 1127, 2048 },
+   { 5, 1128, 2048 }, { 6, 1129, 2048 }, { 6, 1130, 2048 }, { 7, 1131, 2048 }, { 6, 1132, 2048 }, { 7, 1133, 2048 }, { 7, 1134, 2048 }, { 8, 1135, 2048 },
+   { 5, 1136, 2048 }, { 6, 1137, 2048 }, { 6, 1138, 2048 }, { 7, 1139, 2048 }, { 6, 1140, 2048 }, { 7, 1141, 2048 }, { 7, 1142, 2048 }, { 8, 1143, 2048 },
+   { 6, 1144, 2048 }, { 7, 1145, 2048 }, { 7, 1146, 2048 }, { 8, 1147, 2048 }, { 7, 1148, 2048 }, { 8, 1149, 2048 }, { 8, 1150, 2048 }, { 9, 1151, 2048 },
+   { 3, 1152, 2048 }, { 4, 1153, 2048 }, { 4, 1154, 2048 }, { 5, 1155, 2048 }, { 4, 1156, 2048 }, { 5, 1157, 2048 }, { 5, 1158, 2048 }, { 6, 1159, 2048 },
+   { 4, 1160, 2048 }, { 5, 1161, 2048 }, { 5, 1162, 2048 }, { 6, 1163, 2048 }, { 5, 1164, 2048 }, { 6, 1165, 2048 }, { 6, 1166, 2048 }, { 7, 1167, 2048 },
+   { 4, 1168, 2048 }, { 5, 1169, 2048 }, { 5, 1170, 2048 }, { 6, 1171, 2048 }, { 5, 1172, 2048 }, { 6, 1173, 2048 }, { 6, 1174, 2048 }, { 7, 1175, 2048 },
+   { 5, 1176, 2048 }, { 6, 1177, 2048 }, { 6, 1178, 2048 }, { 7, 1179, 2048 }, { 6, 1180, 2048 }, { 7, 1181, 2048 }, { 7, 1182, 2048 }, { 8, 1183, 2048 },
+   { 4, 1184, 2048 }, { 5, 1185, 2048 }, { 5, 1186, 2048 }, { 6, 1187, 2048 }, { 5, 1188, 2048 }, { 6, 1189, 2048 }, { 6, 1190, 2048 }, { 7, 1191, 2048 },
+   { 5, 1192, 2048 }, { 6, 1193, 2048 }, { 6, 1194, 2048 }, { 7, 1195, 2048 }, { 6, 1196, 2048 }, { 7, 1197, 2048 }, { 7, 1198, 2048 }, { 8, 1199, 2048 },
+   { 5, 1200, 2048 }, { 6, 1201, 2048 }, { 6, 1202, 2048 }, { 7, 1203, 2048 }, { 6, 1204, 2048 }, { 7, 1205, 2048 }, { 7, 1206, 2048 }, { 8, 1207, 2048 },
+   { 6, 1208, 2048 }, { 7, 1209, 2048 }, { 7, 1210, 2048 }, { 8, 1211, 2048 }, { 7, 1212, 2048 }, { 8, 1213, 2048 }, { 8, 1214, 2048 }, { 9, 1215, 2048 },
+   { 4, 1216, 2048 }, { 5, 1217, 2048 }, { 5, 1218, 2048 }, { 6, 1219, 2048 }, { 5, 1220, 2048 }, { 6, 1221, 2048 }, { 6, 1222, 2048 }, { 7, 1223, 2048 },
+   { 5, 1224, 2048 }, { 6, 1225, 2048 }, { 6, 1226, 2048 }, { 7, 1227, 2048 }, { 6, 1228, 2048 }, { 7, 1229, 2048 }, { 7, 1230, 2048 }, { 8, 1231, 2048 },
+   { 5, 1232, 2048 }, { 6, 1233, 2048 }, { 6, 1234, 2048 }, { 7, 1235, 2048 }, { 6, 1236, 2048 }, { 7, 1237, 2048 }, { 7, 1238, 2048 }, { 8, 1239, 2048 },
+   { 6, 1240, 2048 }, { 7, 1241, 2048 }, { 7, 1242, 2048 }, { 8, 1243, 2048 }, { 7, 1244, 2048 }, { 8, 1245, 2048 }, { 8, 1246, 2048 }, { 9, 1247, 2048 },
+   { 5, 1248, 2048 }, { 6, 1249, 2048 }, { 6, 1250, 2048 }, { 7, 1251, 2048 }, { 6, 1252, 2048 }, { 7, 1253, 2048 }, { 7, 1254, 2048 }, { 8, 1255, 2048 },
+   { 6, 1256, 2048 }, { 7, 1257, 2048 }, { 7, 1258, 2048 }, { 8, 1259, 2048 }, { 7, 1260, 2048 }, { 8, 1261, 2048 }, { 8, 1262, 2048 }, { 9, 1263, 2048 },
+   { 6, 1264, 2048 }, { 7, 1265, 2048 }, { 7, 1266, 2048 }, { 8, 1267, 2048 }, { 7, 1268, 2048 }, { 8, 1269, 2048 }, { 8, 1270, 2048 }, { 9, 1271, 2048 },
+   { 7, 1272, 2048 }, { 8, 1273, 2048 }, { 8, 1274, 2048 }, { 9, 1275, 2048 }, { 8, 1276, 2048 }, { 9, 1277, 2048 }, { 9, 1278, 2048 }, { 10, 1279, 2048 },
+   { 3, 1280, 2048 }, { 4, 1281, 2048 }, { 4, 1282, 2048 }, { 5, 1283, 2048 }, { 4, 1284, 2048 }, { 5, 1285, 2048 }, { 5, 1286, 2048 }, { 6, 1287, 2048 },
+   { 4, 1288, 2048 }, { 5, 1289, 2048 }, { 5, 1290, 2048 }, { 6, 1291, 2048 }, { 5, 1292, 2048 }, { 6, 1293, 2048 }, { 6, 1294, 2048 }, { 7, 1295, 2048 },
+   { 4, 1296, 2048 }, { 5, 1297, 2048 }, { 5, 1298, 2048 }, { 6, 1299, 2048 }, { 5, 1300, 2048 }, { 6, 1301, 2048 }, { 6, 1302, 2048 }, { 7, 1303, 2048 },
+   { 5, 1304, 2048 }, { 6, 1305, 2048 }, { 6, 1306, 2048 }, { 7, 1307, 2048 }, { 6, 1308, 2048 }, { 7, 1309, 2048 }, { 7, 1310, 2048 }, { 8, 1311, 2048 },
+   { 4, 1312, 2048 }, { 5, 1313, 2048 }, { 5, 1314, 2048 }, { 6, 1315, 2048 }, { 5, 1316, 2048 }, { 6, 1317, 2048 }, { 6, 1318, 2048 }, { 7, 1319, 2048 },
+   { 5, 1320, 2048 }, { 6, 1321, 2048 }, { 6, 1322, 2048 }, { 7, 1323, 2048 }, { 6, 1324, 2048 }, { 7, 1325, 2048 }, { 7, 1326, 2048 }, { 8, 1327, 2048 },
+   { 5, 1328, 2048 }, { 6, 1329, 2048 }, { 6, 1330, 2048 }, { 7, 1331, 2048 }, { 6, 1332, 2048 }, { 7, 1333, 2048 }, { 7, 1334, 2048 }, { 8, 1335, 2048 },
+   { 6, 1336, 2048 }, { 7, 1337, 2048 }, { 7, 1338, 2048 }, { 8, 1339, 2048 }, { 7, 1340, 2048 }, { 8, 1341, 2048 }, { 8, 1342, 2048 }, { 9, 1343, 2048 },
+   { 4, 1344, 2048 }, { 5, 1345, 2048 }, { 5, 1346, 2048 }, { 6, 1347, 2048 }, { 5, 1348, 2048 }, { 6, 1349, 2048 }, { 6, 1350, 2048 }, { 7, 1351, 2048 },
+   { 5, 1352, 2048 }, { 6, 1353, 2048 }, { 6, 1354, 2048 }, { 7, 1355, 2048 }, { 6, 1356, 2048 }, { 7, 1357, 2048 }, { 7, 1358, 2048 }, { 8, 1359, 2048 },
+   { 5, 1360, 2048 }, { 6, 1361, 2048 }, { 6, 1362, 2048 }, { 7, 1363, 2048 }, { 6, 1364, 2048 }, { 7, 1365, 2048 }, { 7, 1366, 2048 }, { 8, 1367, 2048 },
+   { 6, 1368, 2048 }, { 7, 1369, 2048 }, { 7, 1370, 2048 }, { 8, 1371, 2048 }, { 7, 1372, 2048 }, { 8, 1373, 2048 }, { 8, 1374, 2048 }, { 9, 1375, 2048 },
+   { 5, 1376, 2048 }, { 6, 1377, 2048 }, { 6, 1378, 2048 }, { 7, 1379, 2048 }, { 6, 1380, 2048 }, { 7, 1381, 2048 }, { 7, 1382, 2048 }, { 8, 1383, 2048 },
+   { 6, 1384, 2048 }, { 7, 1385, 2048 }, { 7, 1386, 2048 }, { 8, 1387, 2048 }, { 7, 1388, 2048 }, { 8, 1389, 2048 }, { 8, 1390, 2048 }, { 9, 1391, 2048 },
+   { 6, 1392, 2048 }, { 7, 1393, 2048 }, { 7, 1394, 2048 }, { 8, 1395, 2048 }, { 7, 1396, 2048 }, { 8, 1397, 2048 }, { 8, 1398, 2048 }, { 9, 1399, 2048 },
+   { 7, 1400, 2048 }, { 8, 1401, 2048 }, { 8, 1402, 2048 }, { 9, 1403, 2048 }, { 8, 1404, 2048 }, { 9, 1405, 2048 }, { 9, 1406, 2048 }, { 10, 1407, 2048 },
+   { 4, 1408, 2048 }, { 5, 1409, 2048 }, { 5, 1410, 2048 }, { 6, 1411, 2048 }, { 5, 1412, 2048 }, { 6, 1413, 2048 }, { 6, 1414, 2048 }, { 7, 1415, 2048 },
+   { 5, 1416, 2048 }, { 6, 1417, 2048 }, { 6, 1418, 2048 }, { 7, 1419, 2048 }, { 6, 1420, 2048 }, { 7, 1421, 2048 }, { 7, 1422, 2048 }, { 8, 1423, 2048 },
+   { 5, 1424, 2048 }, { 6, 1425, 2048 }, { 6, 1426, 2048 }, { 7, 1427, 2048 }, { 6, 1428, 2048 }, { 7, 1429, 2048 }, { 7, 1430, 2048 }, { 8, 1431, 2048 },
+   { 6, 1432, 2048 }, { 7, 1433, 2048 }, { 7, 1434, 2048 }, { 8, 1435, 2048 }, { 7, 1436, 2048 }, { 8, 1437, 2048 }, { 8, 1438, 2048 }, { 9, 1439, 2048 },
+   { 5, 1440, 2048 }, { 6, 1441, 2048 }, { 6, 1442, 2048 }, { 7, 1443, 2048 }, { 6, 1444, 2048 }, { 7, 1445, 2048 }, { 7, 1446, 2048 }, { 8, 1447, 2048 },
+   { 6, 1448, 2048 }, { 7, 1449, 2048 }, { 7, 1450, 2048 }, { 8, 1451, 2048 }, { 7, 1452, 2048 }, { 8, 1453, 2048 }, { 8, 1454, 2048 }, { 9, 1455, 2048 },
+   { 6, 1456, 2048 }, { 7, 1457, 2048 }, { 7, 1458, 2048 }, { 8, 1459, 2048 }, { 7, 1460, 2048 }, { 8, 1461, 2048 }, { 8, 1462, 2048 }, { 9, 1463, 2048 },
+   { 7, 1464, 2048 }, { 8, 1465, 2048 }, { 8, 1466, 2048 }, { 9, 1467, 2048 }, { 8, 1468, 2048 }, { 9, 1469, 2048 }, { 9, 1470, 2048 }, { 10, 1471, 2048 },
+   { 5, 1472, 2048 }, { 6, 1473, 2048 }, { 6, 1474, 2048 }, { 7, 1475, 2048 }, { 6, 1476, 2048 }, { 7, 1477, 2048 }, { 7, 1478, 2048 }, { 8, 1479, 2048 },
+   { 6, 1480, 2048 }, { 7, 1481, 2048 }, { 7, 1482, 2048 }, { 8, 1483, 2048 }, { 7, 1484, 2048 }, { 8, 1485, 2048 }, { 8, 1486, 2048 }, { 9, 1487, 2048 },
+   { 6, 1488, 2048 }, { 7, 1489, 2048 }, { 7, 1490, 2048 }, { 8, 1491, 2048 }, { 7, 1492, 2048 }, { 8, 1493, 2048 }, { 8, 1494, 2048 }, { 9, 1495, 2048 },
+   { 7, 1496, 2048 }, { 8, 1497, 2048 }, { 8, 1498, 2048 }, { 9, 1499, 2048 }, { 8, 1500, 2048 }, { 9, 1501, 2048 }, { 9, 1502, 2048 }, { 10, 1503, 2048 },
+   { 6, 1504, 2048 }, { 7, 1505, 2048 }, { 7, 1506, 2048 }, { 8, 1507, 2048 }, { 7, 1508, 2048 }, { 8, 1509, 2048 }, { 8, 1510, 2048 }, { 9, 1511, 2048 },
+   { 7, 1512, 2048 }, { 8, 1513, 2048 }, { 8, 1514, 2048 }, { 9, 1515, 2048 }, { 8, 1516, 2048 }, { 9, 1517, 2048 }, { 9, 1518, 2048 }, { 10, 1519, 2048 },
+   { 7, 1520, 2048 }, { 8, 1521, 2048 }, { 8, 1522, 2048 }, { 9, 1523, 2048 }, { 8, 1524, 2048 }, { 9, 1525, 2048 }, { 9, 1526, 2048 }, { 10, 1527, 2048 },
+   { 8, 1528, 2048 }, { 9, 1529, 2048 }, { 9, 1530, 2048 }, { 10, 1531, 2048 }, { 9, 1532, 2048 }, { 10, 1533, 2048 }, { 10, 1534, 2048 }, { 11, 1535, 2048 },
+   { 3, 1536, 2048 }, { 4, 1537, 2048 }, { 4, 1538, 2048 }, { 5, 1539, 2048 }, { 4, 1540, 2048 }, { 5, 1541, 2048 }, { 5, 1542, 2048 }, { 6, 1543, 2048 },
+   { 4, 1544, 2048 }, { 5, 1545, 2048 }, { 5, 1546, 2048 }, { 6, 1547, 2048 }, { 5, 1548, 2048 }, { 6, 1549, 2048 }, { 6, 1550, 2048 }, { 7, 1551, 2048 },
+   { 4, 1552, 2048 }, { 5, 1553, 2048 }, { 5, 1554, 2048 }, { 6, 1555, 2048 }, { 5, 1556, 2048 }, { 6, 1557, 2048 }, { 6, 1558, 2048 }, { 7, 1559, 2048 },
+   { 5, 1560, 2048 }, { 6, 1561, 2048 }, { 6, 1562, 2048 }, { 7, 1563, 2048 }, { 6, 1564, 2048 }, { 7, 1565, 2048 }, { 7, 1566, 2048 }, { 8, 1567, 2048 },
+   { 4, 1568, 2048 }, { 5, 1569, 2048 }, { 5, 1570, 2048 }, { 6, 1571, 2048 }, { 5, 1572, 2048 }, { 6, 1573, 2048 }, { 6, 1574, 2048 }, { 7, 1575, 2048 },
+   { 5, 1576, 2048 }, { 6, 1577, 2048 }, { 6, 1578, 2048 }, { 7, 1579, 2048 }, { 6, 1580, 2048 }, { 7, 1581, 2048 }, { 7, 1582, 2048 }, { 8, 1583, 2048 },
+   { 5, 1584, 2048 }, { 6, 1585, 2048 }, { 6, 1586, 2048 }, { 7, 1587, 2048 }, { 6, 1588, 2048 }, { 7, 1589, 2048 }, { 7, 1590, 2048 }, { 8, 1591, 2048 },
+   { 6, 1592, 2048 }, { 7, 1593, 2048 }, { 7, 1594, 2048 }, { 8, 1595, 2048 }, { 7, 1596, 2048 }, { 8, 1597, 2048 }, { 8, 1598, 2048 }, { 9, 1599, 2048 },
+   { 4, 1600, 2048 }, { 5, 1601, 2048 }, { 5, 1602, 2048 }, { 6, 1603, 2048 }, { 5, 1604, 2048 }, { 6, 1605, 2048 }, { 6, 1606, 2048 }, { 7, 1607, 2048 },
+   { 5, 1608, 2048 }, { 6, 1609, 2048 }, { 6, 1610, 2048 }, { 7, 1611, 2048 }, { 6, 1612, 2048 }, { 7, 1613, 2048 }, { 7, 1614, 2048 }, { 8, 1615, 2048 },
+   { 5, 1616, 2048 }, { 6, 1617, 2048 }, { 6, 1618, 2048 }, { 7, 1619, 2048 }, { 6, 1620, 2048 }, { 7, 1621, 2048 }, { 7, 1622, 2048 }, { 8, 1623, 2048 },
+   { 6, 1624, 2048 }, { 7, 1625, 2048 }, { 7, 1626, 2048 }, { 8, 1627, 2048 }, { 7, 1628, 2048 }, { 8, 1629, 2048 }, { 8, 1630, 2048 }, { 9, 1631, 2048 },
+   { 5, 1632, 2048 }, { 6, 1633, 2048 }, { 6, 1634, 2048 }, { 7, 1635, 2048 }, { 6, 1636, 2048 }, { 7, 1637, 2048 }, { 7, 1638, 2048 }, { 8, 1639, 2048 },
+   { 6, 1640, 2048 }, { 7, 1641, 2048 }, { 7, 1642, 2048 }, { 8, 1643, 2048 }, { 7, 1644, 2048 }, { 8, 1645, 2048 }, { 8, 1646, 2048 }, { 9, 1647, 2048 },
+   { 6, 1648, 2048 }, { 7, 1649, 2048 }, { 7, 1650, 2048 }, { 8, 1651, 2048 }, { 7, 1652, 2048 }, { 8, 1653, 2048 }, { 8, 1654, 2048 }, { 9, 1655, 2048 },
+   { 7, 1656, 2048 }, { 8, 1657, 2048 }, { 8, 1658, 2048 }, { 9, 1659, 2048 }, { 8, 1660, 2048 }, { 9, 1661, 2048 }, { 9, 1662, 2048 }, { 10, 1663, 2048 },
+   { 4, 1664, 2048 }, { 5, 1665, 2048 }, { 5, 1666, 2048 }, { 6, 1667, 2048 }, { 5, 1668, 2048 }, { 6, 1669, 2048 }, { 6, 1670, 2048 }, { 7, 1671, 2048 },
+   { 5, 1672, 2048 }, { 6, 1673, 2048 }, { 6, 1674, 2048 }, { 7, 1675, 2048 }, { 6, 1676, 2048 }, { 7, 1677, 2048 }, { 7, 1678, 2048 }, { 8, 1679, 2048 },
+   { 5, 1680, 2048 }, { 6, 1681, 2048 }, { 6, 1682, 2048 }, { 7, 1683, 2048 }, { 6, 1684, 2048 }, { 7, 1685, 2048 }, { 7, 1686, 2048 }, { 8, 1687, 2048 },
+   { 6, 1688, 2048 }, { 7, 1689, 2048 }, { 7, 1690, 2048 }, { 8, 1691, 2048 }, { 7, 1692, 2048 }, { 8, 1693, 2048 }, { 8, 1694, 2048 }, { 9, 1695, 2048 },
+   { 5, 1696, 2048 }, { 6, 1697, 2048 }, { 6, 1698, 2048 }, { 7, 1699, 2048 }, { 6, 1700, 2048 }, { 7, 1701, 2048 }, { 7, 1702, 2048 }, { 8, 1703, 2048 },
+   { 6, 1704, 2048 }, { 7, 1705, 2048 }, { 7, 1706, 2048 }, { 8, 1707, 2048 }, { 7, 1708, 2048 }, { 8, 1709, 2048 }, { 8, 1710, 2048 }, { 9, 1711, 2048 },
+   { 6, 1712, 2048 }, { 7, 1713, 2048 }, { 7, 1714, 2048 }, { 8, 1715, 2048 }, { 7, 1716, 2048 }, { 8, 1717, 2048 }, { 8, 1718, 2048 }, { 9, 1719, 2048 },
+   { 7, 1720, 2048 }, { 8, 1721, 2048 }, { 8, 1722, 2048 }, { 9, 1723, 2048 }, { 8, 1724, 2048 }, { 9, 1725, 2048 }, { 9, 1726, 2048 }, { 10, 1727, 2048 },
+   { 5, 1728, 2048 }, { 6, 1729, 2048 }, { 6, 1730, 2048 }, { 7, 1731, 2048 }, { 6, 1732, 2048 }, { 7, 1733, 2048 }, { 7, 1734, 2048 }, { 8, 1735, 2048 },
+   { 6, 1736, 2048 }, { 7, 1737, 2048 }, { 7, 1738, 2048 }, { 8, 1739, 2048 }, { 7, 1740, 2048 }, { 8, 1741, 2048 }, { 8, 1742, 2048 }, { 9, 1743, 2048 },
+   { 6, 1744, 2048 }, { 7, 1745, 2048 }, { 7, 1746, 2048 }, { 8, 1747, 2048 }, { 7, 1748, 2048 }, { 8, 1749, 2048 }, { 8, 1750, 2048 }, { 9, 1751, 2048 },
+   { 7, 1752, 2048 }, { 8, 1753, 2048 }, { 8, 1754, 2048 }, { 9, 1755, 2048 }, { 8, 1756, 2048 }, { 9, 1757, 2048 }, { 9, 1758, 2048 }, { 10, 1759, 2048 },
+   { 6, 1760, 2048 }, { 7, 1761, 2048 }, { 7, 1762, 2048 }, { 8, 1763, 2048 }, { 7, 1764, 2048 }, { 8, 1765, 2048 }, { 8, 1766, 2048 }, { 9, 1767, 2048 },
+   { 7, 1768, 2048 }, { 8, 1769, 2048 }, { 8, 1770, 2048 }, { 9, 1771, 2048 }, { 8, 1772, 2048 }, { 9, 1773, 2048 }, { 9, 1774, 2048 }, { 10, 1775, 2048 },
+   { 7, 1776, 2048 }, { 8, 1777, 2048 }, { 8, 1778, 2048 }, { 9, 1779, 2048 }, { 8, 1780, 2048 }, { 9, 1781, 2048 }, { 9, 1782, 2048 }, { 10, 1783, 2048 },
+   { 8, 1784, 2048 }, { 9, 1785, 2048 }, { 9, 1786, 2048 }, { 10, 1787, 2048 }, { 9, 1788, 2048 }, { 10, 1789, 2048 }, { 10, 1790, 2048 }, { 11, 1791, 2048 },
+   { 4, 1792, 2048 }, { 5, 1793, 2048 }, { 5, 1794, 2048 }, { 6, 1795, 2048 }, { 5, 1796, 2048 }, { 6, 1797, 2048 }, { 6, 1798, 2048 }, { 7, 1799, 2048 },
+   { 5, 1800, 2048 }, { 6, 1801, 2048 }, { 6, 1802, 2048 }, { 7, 1803, 2048 }, { 6, 1804, 2048 }, { 7, 1805, 2048 }, { 7, 1806, 2048 }, { 8, 1807, 2048 },
+   { 5, 1808, 2048 }, { 6, 1809, 2048 }, { 6, 1810, 2048 }, { 7, 1811, 2048 }, { 6, 1812, 2048 }, { 7, 1813, 2048 }, { 7, 1814, 2048 }, { 8, 1815, 2048 },
+   { 6, 1816, 2048 }, { 7, 1817, 2048 }, { 7, 1818, 2048 }, { 8, 1819, 2048 }, { 7, 1820, 2048 }, { 8, 1821, 2048 }, { 8, 1822, 2048 }, { 9, 1823, 2048 },
+   { 5, 1824, 2048 }, { 6, 1825, 2048 }, { 6, 1826, 2048 }, { 7, 1827, 2048 }, { 6, 1828, 2048 }, { 7, 1829, 2048 }, { 7, 1830, 2048 }, { 8, 1831, 2048 },
+   { 6, 1832, 2048 }, { 7, 1833, 2048 }, { 7, 1834, 2048 }, { 8, 1835, 2048 }, { 7, 1836, 2048 }, { 8, 1837, 2048 }, { 8, 1838, 2048 }, { 9, 1839, 2048 },
+   { 6, 1840, 2048 }, { 7, 1841, 2048 }, { 7, 1842, 2048 }, { 8, 1843, 2048 }, { 7, 1844, 2048 }, { 8, 1845, 2048 }, { 8, 1846, 2048 }, { 9, 1847, 2048 },
+   { 7, 1848, 2048 }, { 8, 1849, 2048 }, { 8, 1850, 2048 }, { 9, 1851, 2048 }, { 8, 1852, 2048 }, { 9, 1853, 2048 }, { 9, 1854, 2048 }, { 10, 1855, 2048 },
+   { 5, 1856, 2048 }, { 6, 1857, 2048 }, { 6, 1858, 2048 }, { 7, 1859, 2048 }, { 6, 1860, 2048 }, { 7, 1861, 2048 }, { 7, 1862, 2048 }, { 8, 1863, 2048 },
+   { 6, 1864, 2048 }, { 7, 1865, 2048 }, { 7, 1866, 2048 }, { 8, 1867, 2048 }, { 7, 1868, 2048 }, { 8, 1869, 2048 }, { 8, 1870, 2048 }, { 9, 1871, 2048 },
+   { 6, 1872, 2048 }, { 7, 1873, 2048 }, { 7, 1874, 2048 }, { 8, 1875, 2048 }, { 7, 1876, 2048 }, { 8, 1877, 2048 }, { 8, 1878, 2048 }, { 9, 1879, 2048 },
+   { 7, 1880, 2048 }, { 8, 1881, 2048 }, { 8, 1882, 2048 }, { 9, 1883, 2048 }, { 8, 1884, 2048 }, { 9, 1885, 2048 }, { 9, 1886, 2048 }, { 10, 1887, 2048 },
+   { 6, 1888, 2048 }, { 7, 1889, 2048 }, { 7, 1890, 2048 }, { 8, 1891, 2048 }, { 7, 1892, 2048 }, { 8, 1893, 2048 }, { 8, 1894, 2048 }, { 9, 1895, 2048 },
+   { 7, 1896, 2048 }, { 8, 1897, 2048 }, { 8, 1898, 2048 }, { 9, 1899, 2048 }, { 8, 1900, 2048 }, { 9, 1901, 2048 }, { 9, 1902, 2048 }, { 10, 1903, 2048 },
+   { 7, 1904, 2048 }, { 8, 1905, 2048 }, { 8, 1906, 2048 }, { 9, 1907, 2048 }, { 8, 1908, 2048 }, { 9, 1909, 2048 }, { 9, 1910, 2048 }, { 10, 1911, 2048 },
+   { 8, 1912, 2048 }, { 9, 1913, 2048 }, { 9, 1914, 2048 }, { 10, 1915, 2048 }, { 9, 1916, 2048 }, { 10, 1917, 2048 }, { 10, 1918, 2048 }, { 11, 1919, 2048 },
+   { 5, 1920, 2048 }, { 6, 1921, 2048 }, { 6, 1922, 2048 }, { 7, 1923, 2048 }, { 6, 1924, 2048 }, { 7, 1925, 2048 }, { 7, 1926, 2048 }, { 8, 1927, 2048 },
+   { 6, 1928, 2048 }, { 7, 1929, 2048 }, { 7, 1930, 2048 }, { 8, 1931, 2048 }, { 7, 1932, 2048 }, { 8, 1933, 2048 }, { 8, 1934, 2048 }, { 9, 1935, 2048 },
+   { 6, 1936, 2048 }, { 7, 1937, 2048 }, { 7, 1938, 2048 }, { 8, 1939, 2048 }, { 7, 1940, 2048 }, { 8, 1941, 2048 }, { 8, 1942, 2048 }, { 9, 1943, 2048 },
+   { 7, 1944, 2048 }, { 8, 1945, 2048 }, { 8, 1946, 2048 }, { 9, 1947, 2048 }, { 8, 1948, 2048 }, { 9, 1949, 2048 }, { 9, 1950, 2048 }, { 10, 1951, 2048 },
+   { 6, 1952, 2048 }, { 7, 1953, 2048 }, { 7, 1954, 2048 }, { 8, 1955, 2048 }, { 7, 1956, 2048 }, { 8, 1957, 2048 }, { 8, 1958, 2048 }, { 9, 1959, 2048 },
+   { 7, 1960, 2048 }, { 8, 1961, 2048 }, { 8, 1962, 2048 }, { 9, 1963, 2048 }, { 8, 1964, 2048 }, { 9, 1965, 2048 }, { 9, 1966, 2048 }, { 10, 1967, 2048 },
+   { 7, 1968, 2048 }, { 8, 1969, 2048 }, { 8, 1970, 2048 }, { 9, 1971, 2048 }, { 8, 1972, 2048 }, { 9, 1973, 2048 }, { 9, 1974, 2048 }, { 10, 1975, 2048 },
+   { 8, 1976, 2048 }, { 9, 1977, 2048 }, { 9, 1978, 2048 }, { 10, 1979, 2048 }, { 9, 1980, 2048 }, { 10, 1981, 2048 }, { 10, 1982, 2048 }, { 11, 1983, 2048 },
+   { 6, 1984, 2048 }, { 7, 1985, 2048 }, { 7, 1986, 2048 }, { 8, 1987, 2048 }, { 7, 1988, 2048 }, { 8, 1989, 2048 }, { 8, 1990, 2048 }, { 9, 1991, 2048 },
+   { 7, 1992, 2048 }, { 8, 1993, 2048 }, { 8, 1994, 2048 }, { 9, 1995, 2048 }, { 8, 1996, 2048 }, { 9, 1997, 2048 }, { 9, 1998, 2048 }, { 10, 1999, 2048 },
+   { 7, 2000, 2048 }, { 8, 2001, 2048 }, { 8, 2002, 2048 }, { 9, 2003, 2048 }, { 8, 2004, 2048 }, { 9, 2005, 2048 }, { 9, 2006, 2048 }, { 10, 2007, 2048 },
+   { 8, 2008, 2048 }, { 9, 2009, 2048 }, { 9, 2010, 2048 }, { 10, 2011, 2048 }, { 9, 2012, 2048 }, { 10, 2013, 2048 }, { 10, 2014, 2048 }, { 11, 2015, 2048 },
+   { 7, 2016, 2048 }, { 8, 2017, 2048 }, { 8, 2018, 2048 }, { 9, 2019, 2048 }, { 8, 2020, 2048 }, { 9, 2021, 2048 }, { 9, 2022, 2048 }, { 10, 2023, 2048 },
+   { 8, 2024, 2048 }, { 9, 2025, 2048 }, { 9, 2026, 2048 }, { 10, 2027, 2048 }, { 9, 2028, 2048 }, { 10, 2029, 2048 }, { 10, 2030, 2048 }, { 11, 2031, 2048 },
+   { 8, 2032, 2048 }, { 9, 2033, 2048 }, { 9, 2034, 2048 }, { 10, 2035, 2048 }, { 9, 2036, 2048 }, { 10, 2037, 2048 }, { 10, 2038, 2048 }, { 11, 2039, 2048 },
+   { 9, 2040, 2048 }, { 10, 2041, 2048 }, { 10, 2042, 2048 }, { 11, 2043, 2048 }, { 10, 2044, 2048 }, { 11, 2045, 2048 }, { 11, 2046, 2048 }, { 12, 2047, 2048 },
+#endif
+#endif
+#endif
+#endif
+#endif
+#endif
+};
+
+/* find a hole and free as required, return -1 if no hole found */
+static int _find_hole(void)
+{
+   unsigned x;
+   int      y, z;
+   for (z = -1, y = INT_MAX, x = 0; x < FP_ENTRIES; x++) {
+       if (fp_cache[x].lru_count < y && fp_cache[x].lock == 0) {
+          z = x;
+          y = fp_cache[x].lru_count;
+       }
+   }
+
+   /* decrease all */
+   for (x = 0; x < FP_ENTRIES; x++) {
+      if (fp_cache[x].lru_count > 3) {
+         --(fp_cache[x].lru_count);
+      }
+   }
+
+   /* free entry z */
+   if (z >= 0 && fp_cache[z].g) {
+      if (fp_cache[z].mu != NULL) {
+         mp_clear(fp_cache[z].mu);
+         fp_cache[z].mu = NULL;
+      }
+      ltc_ecc_del_point(fp_cache[z].g);
+      fp_cache[z].g  = NULL;
+      for (x = 0; x < (1U<<FP_LUT); x++) {
+         ltc_ecc_del_point(fp_cache[z].LUT[x]);
+         fp_cache[z].LUT[x] = NULL;
+      }
+      fp_cache[z].lru_count = 0;
+   }
+   return z;
+}
+
+/* determine if a base is already in the cache and if so, where */
+static int _find_base(ecc_point *g)
+{
+   int x;
+   for (x = 0; x < FP_ENTRIES; x++) {
+      if (fp_cache[x].g != NULL &&
+          mp_cmp(fp_cache[x].g->x, g->x) == LTC_MP_EQ &&
+          mp_cmp(fp_cache[x].g->y, g->y) == LTC_MP_EQ &&
+          mp_cmp(fp_cache[x].g->z, g->z) == LTC_MP_EQ) {
+         break;
+      }
+   }
+   if (x == FP_ENTRIES) {
+      x = -1;
+   }
+   return x;
+}
+
+/* add a new base to the cache */
+static int _add_entry(int idx, ecc_point *g)
+{
+   unsigned x, y;
+
+   /* allocate base and LUT */
+   fp_cache[idx].g = ltc_ecc_new_point();
+   if (fp_cache[idx].g == NULL) {
+      return CRYPT_MEM;
+   }
+
+   /* copy x and y */
+   if ((mp_copy(g->x, fp_cache[idx].g->x) != CRYPT_OK) ||
+       (mp_copy(g->y, fp_cache[idx].g->y) != CRYPT_OK) ||
+       (mp_copy(g->z, fp_cache[idx].g->z) != CRYPT_OK)) {
+      ltc_ecc_del_point(fp_cache[idx].g);
+      fp_cache[idx].g = NULL;
+      return CRYPT_MEM;
+   }
+
+   for (x = 0; x < (1U<<FP_LUT); x++) {
+      fp_cache[idx].LUT[x] = ltc_ecc_new_point();
+      if (fp_cache[idx].LUT[x] == NULL) {
+         for (y = 0; y < x; y++) {
+            ltc_ecc_del_point(fp_cache[idx].LUT[y]);
+            fp_cache[idx].LUT[y] = NULL;
+         }
+         ltc_ecc_del_point(fp_cache[idx].g);
+         fp_cache[idx].g         = NULL;
+         fp_cache[idx].lru_count = 0;
+         return CRYPT_MEM;
+      }
+   }
+
+   fp_cache[idx].lru_count = 0;
+   return CRYPT_OK;
+}
+
+/* build the LUT by spacing the bits of the input by #modulus/FP_LUT bits apart
+ *
+ * The algorithm builds patterns in increasing bit order by first making all
+ * single bit input patterns, then all two bit input patterns and so on
+ */
+static int _build_lut(int idx, void *modulus, void *mp, void *mu)
+{
+   unsigned x, y, err, bitlen, lut_gap;
+   void    *tmp;
+
+   tmp = NULL;
+
+   /* sanity check to make sure lut_order table is of correct size, should compile out to a NOP if true */
+   if ((sizeof(lut_orders) / sizeof(lut_orders[0])) < (1U<<FP_LUT)) {
+       err = CRYPT_INVALID_ARG;
+       goto DONE;
+   }
+
+   /* get bitlen and round up to next multiple of FP_LUT */
+   bitlen  = mp_unsigned_bin_size(modulus) << 3;
+   x       = bitlen % FP_LUT;
+   if (x) {
+      bitlen += FP_LUT - x;
+   }
+   lut_gap = bitlen / FP_LUT;
+
+   /* init the mu */
+   if ((err = mp_init_copy(&fp_cache[idx].mu, mu)) != CRYPT_OK) {
+      goto ERR;
+   }
+
+   /* copy base */
+   if ((mp_mulmod(fp_cache[idx].g->x, mu, modulus, fp_cache[idx].LUT[1]->x) != CRYPT_OK) ||
+       (mp_mulmod(fp_cache[idx].g->y, mu, modulus, fp_cache[idx].LUT[1]->y) != CRYPT_OK) ||
+       (mp_mulmod(fp_cache[idx].g->z, mu, modulus, fp_cache[idx].LUT[1]->z) != CRYPT_OK))        { goto ERR; }
+
+   /* make all single bit entries */
+   for (x = 1; x < FP_LUT; x++) {
+      if ((mp_copy(fp_cache[idx].LUT[1<<(x-1)]->x, fp_cache[idx].LUT[1<<x]->x) != CRYPT_OK) ||
+          (mp_copy(fp_cache[idx].LUT[1<<(x-1)]->y, fp_cache[idx].LUT[1<<x]->y) != CRYPT_OK) ||
+          (mp_copy(fp_cache[idx].LUT[1<<(x-1)]->z, fp_cache[idx].LUT[1<<x]->z) != CRYPT_OK))     { goto ERR; }
+
+      /* now double it bitlen/FP_LUT times */
+      for (y = 0; y < lut_gap; y++) {
+          if ((err = ltc_mp.ecc_ptdbl(fp_cache[idx].LUT[1<<x], fp_cache[idx].LUT[1<<x], modulus, mp)) != CRYPT_OK) {
+             goto ERR;
+          }
+      }
+   }
+
+   /* now make all entries in increase order of hamming weight */
+   for (x = 2; x <= FP_LUT; x++) {
+       for (y = 0; y < (1UL<<FP_LUT); y++) {
+           if (lut_orders[y].ham != (int)x) continue;
+
+           /* perform the add */
+           if ((err = ltc_mp.ecc_ptadd(fp_cache[idx].LUT[lut_orders[y].terma], fp_cache[idx].LUT[lut_orders[y].termb],
+                                       fp_cache[idx].LUT[y], modulus, mp)) != CRYPT_OK) {
+              goto ERR;
+           }
+       }
+   }
+
+   /* now map all entries back to affine space to make point addition faster */
+   if ((err = mp_init(&tmp)) != CRYPT_OK)                                                                    { goto ERR; }
+   for (x = 1; x < (1UL<<FP_LUT); x++) {
+       /* convert z to normal from montgomery */
+       if ((err = mp_montgomery_reduce(fp_cache[idx].LUT[x]->z, modulus, mp)) != CRYPT_OK)                   { goto ERR; }
+
+       /* invert it */
+       if ((err = mp_invmod(fp_cache[idx].LUT[x]->z, modulus, fp_cache[idx].LUT[x]->z)) != CRYPT_OK)         { goto ERR; }
+
+       /* now square it */
+       if ((err = mp_sqrmod(fp_cache[idx].LUT[x]->z, modulus, tmp)) != CRYPT_OK)                             { goto ERR; }
+
+       /* fix x */
+       if ((err = mp_mulmod(fp_cache[idx].LUT[x]->x, tmp, modulus, fp_cache[idx].LUT[x]->x)) != CRYPT_OK)    { goto ERR; }
+
+       /* get 1/z^3 */
+       if ((err = mp_mulmod(tmp, fp_cache[idx].LUT[x]->z, modulus, tmp)) != CRYPT_OK)                        { goto ERR; }
+
+       /* fix y */
+       if ((err = mp_mulmod(fp_cache[idx].LUT[x]->y, tmp, modulus, fp_cache[idx].LUT[x]->y)) != CRYPT_OK)    { goto ERR; }
+
+       /* free z */
+       mp_clear(fp_cache[idx].LUT[x]->z);
+       fp_cache[idx].LUT[x]->z = NULL;
+   }
+   mp_clear(tmp);
+
+   return CRYPT_OK;
+ERR:
+   err = CRYPT_MEM;
+DONE:
+   for (y = 0; y < (1U<<FP_LUT); y++) {
+      ltc_ecc_del_point(fp_cache[idx].LUT[y]);
+      fp_cache[idx].LUT[y] = NULL;
+   }
+   ltc_ecc_del_point(fp_cache[idx].g);
+   fp_cache[idx].g         = NULL;
+   fp_cache[idx].lru_count = 0;
+   if (fp_cache[idx].mu != NULL) {
+      mp_clear(fp_cache[idx].mu);
+      fp_cache[idx].mu = NULL;
+   }
+   if (tmp != NULL) {
+      mp_clear(tmp);
+   }
+   return err;
+}
+
+/* perform a fixed point ECC mulmod */
+static int _accel_fp_mul(int idx, void *k, ecc_point *R, void *modulus, void *mp, int map)
+{
+   unsigned char kb[128];
+   int      x;
+   unsigned y, z, err, bitlen, bitpos, lut_gap, first;
+   void     *tk, *order;
+
+   /* if it's smaller than modulus we fine */
+   if (mp_unsigned_bin_size(k) > mp_unsigned_bin_size(modulus)) {
+      /* find order */
+      y = mp_unsigned_bin_size(modulus);
+      for (x = 0; ltc_ecc_sets[x].size; x++) {
+         if (y <= (unsigned)ltc_ecc_sets[x].size) break;
+      }
+
+      /* back off if we are on the 521 bit curve */
+      if (y == 66) --x;
+
+      if ((err = mp_init(&order)) != CRYPT_OK) {
+         return err;
+      }
+      if ((err = mp_read_radix(order, ltc_ecc_sets[x].order, 16)) != CRYPT_OK) {
+         mp_clear(&order);
+         return err;
+      }
+
+      /* k must be less than modulus */
+      if (mp_cmp(k, order) != LTC_MP_LT) {
+         if ((err = mp_init(&tk)) != CRYPT_OK) {
+            mp_clear(order);
+            return err;
+         }
+         if ((err = mp_mod(k, order, tk)) != CRYPT_OK) {
+            mp_clear(tk);
+            mp_clear(order);
+            return err;
+         }
+      } else {
+         tk = k;
+      }
+      mp_clear(order);
+   } else {
+       tk = k;
+   }
+
+   /* get bitlen and round up to next multiple of FP_LUT */
+   bitlen  = mp_unsigned_bin_size(modulus) << 3;
+   x       = bitlen % FP_LUT;
+   if (x) {
+      bitlen += FP_LUT - x;
+   }
+   lut_gap = bitlen / FP_LUT;
+
+   /* get the k value */
+   if (mp_unsigned_bin_size(tk) > (sizeof(kb) - 2)) {
+      if (tk != k) {
+         mp_clear(tk);
+      }
+      return CRYPT_BUFFER_OVERFLOW;
+   }
+
+   /* store k */
+   zeromem(kb, sizeof(kb));
+   if ((err = mp_to_unsigned_bin(tk, kb)) != CRYPT_OK) {
+      if (tk != k) {
+         mp_clear(tk);
+      }
+      return err;
+   }
+
+   /* let's reverse kb so it's little endian */
+   x = 0;
+   y = mp_unsigned_bin_size(tk) - 1;
+   if (tk != k) {
+      mp_clear(tk);
+   }
+   while ((unsigned)x < y) {
+      z = kb[x]; kb[x] = kb[y]; kb[y] = z;
+      ++x; --y;
+   }
+
+   /* at this point we can start, yipee */
+   first = 1;
+   for (x = lut_gap-1; x >= 0; x--) {
+       /* extract FP_LUT bits from kb spread out by lut_gap bits and offset by x bits from the start */
+       bitpos = x;
+       for (y = z = 0; y < FP_LUT; y++) {
+          z |= ((kb[bitpos>>3] >> (bitpos&7)) & 1) << y;
+          bitpos += lut_gap;                               /* it's y*lut_gap + x, but here we can avoid the mult in each loop */
+       }
+
+       /* double if not first */
+       if (!first) {
+          if ((err = ltc_mp.ecc_ptdbl(R, R, modulus, mp)) != CRYPT_OK) {
+             return err;
+          }
+       }
+
+       /* add if not first, otherwise copy */
+       if (!first && z) {
+          if ((err = ltc_mp.ecc_ptadd(R, fp_cache[idx].LUT[z], R, modulus, mp)) != CRYPT_OK) {
+             return err;
+          }
+       } else if (z) {
+          if ((mp_copy(fp_cache[idx].LUT[z]->x, R->x) != CRYPT_OK) ||
+              (mp_copy(fp_cache[idx].LUT[z]->y, R->y) != CRYPT_OK) ||
+              (mp_copy(fp_cache[idx].mu,        R->z) != CRYPT_OK)) { return CRYPT_MEM; }
+              first = 0;
+       }
+   }
+   z = 0;
+   zeromem(kb, sizeof(kb));
+   /* map R back from projective space */
+   if (map) {
+      err = ltc_ecc_map(R, modulus, mp);
+   } else {
+      err = CRYPT_OK;
+   }
+   return err;
+}
+
+#ifdef LTC_ECC_SHAMIR
+/* perform a fixed point ECC mulmod */
+static int _accel_fp_mul2add(int idx1, int idx2,
+                            void *kA, void *kB,
+                            ecc_point *R, void *modulus, void *mp)
+{
+   unsigned char kb[2][128];
+   int      x;
+   unsigned y, z, err, bitlen, bitpos, lut_gap, first, zA, zB;
+   void     *tka, *tkb, *order;
+
+   /* if it's smaller than modulus we fine */
+   if (mp_unsigned_bin_size(kA) > mp_unsigned_bin_size(modulus)) {
+      /* find order */
+      y = mp_unsigned_bin_size(modulus);
+      for (x = 0; ltc_ecc_sets[x].size; x++) {
+         if (y <= (unsigned)ltc_ecc_sets[x].size) break;
+      }
+
+      /* back off if we are on the 521 bit curve */
+      if (y == 66) --x;
+
+      if ((err = mp_init(&order)) != CRYPT_OK) {
+         return err;
+      }
+      if ((err = mp_read_radix(order, ltc_ecc_sets[x].order, 16)) != CRYPT_OK) {
+         mp_clear(&order);
+         return err;
+      }
+
+      /* kA must be less than modulus */
+      if (mp_cmp(kA, order) != LTC_MP_LT) {
+         if ((err = mp_init(&tka)) != CRYPT_OK) {
+            mp_clear(order);
+            return err;
+         }
+         if ((err = mp_mod(kA, order, tka)) != CRYPT_OK) {
+            mp_clear(tka);
+            mp_clear(order);
+            return err;
+         }
+      } else {
+         tka = kA;
+      }
+      mp_clear(order);
+   } else {
+      tka = kA;
+   }
+
+   /* if it's smaller than modulus we fine */
+   if (mp_unsigned_bin_size(kB) > mp_unsigned_bin_size(modulus)) {
+      /* find order */
+      y = mp_unsigned_bin_size(modulus);
+      for (x = 0; ltc_ecc_sets[x].size; x++) {
+         if (y <= (unsigned)ltc_ecc_sets[x].size) break;
+      }
+
+      /* back off if we are on the 521 bit curve */
+      if (y == 66) --x;
+
+      if ((err = mp_init(&order)) != CRYPT_OK) {
+         return err;
+      }
+      if ((err = mp_read_radix(order, ltc_ecc_sets[x].order, 16)) != CRYPT_OK) {
+         mp_clear(&order);
+         return err;
+      }
+
+      /* kB must be less than modulus */
+      if (mp_cmp(kB, order) != LTC_MP_LT) {
+         if ((err = mp_init(&tkb)) != CRYPT_OK) {
+            mp_clear(order);
+            return err;
+         }
+         if ((err = mp_mod(kB, order, tkb)) != CRYPT_OK) {
+            mp_clear(tkb);
+            mp_clear(order);
+            return err;
+         }
+      } else {
+         tkb = kB;
+      }
+      mp_clear(order);
+   } else {
+      tkb = kB;
+   }
+
+   /* get bitlen and round up to next multiple of FP_LUT */
+   bitlen  = mp_unsigned_bin_size(modulus) << 3;
+   x       = bitlen % FP_LUT;
+   if (x) {
+      bitlen += FP_LUT - x;
+   }
+   lut_gap = bitlen / FP_LUT;
+
+   /* get the k value */
+   if ((mp_unsigned_bin_size(tka) > (sizeof(kb[0]) - 2)) || (mp_unsigned_bin_size(tkb) > (sizeof(kb[0]) - 2))  ) {
+      if (tka != kA) {
+         mp_clear(tka);
+      }
+      if (tkb != kB) {
+         mp_clear(tkb);
+      }
+      return CRYPT_BUFFER_OVERFLOW;
+   }
+
+   /* store k */
+   zeromem(kb, sizeof(kb));
+   if ((err = mp_to_unsigned_bin(tka, kb[0])) != CRYPT_OK) {
+      if (tka != kA) {
+         mp_clear(tka);
+      }
+      if (tkb != kB) {
+         mp_clear(tkb);
+      }
+      return err;
+   }
+
+   /* let's reverse kb so it's little endian */
+   x = 0;
+   y = mp_unsigned_bin_size(tka) - 1;
+   if (tka != kA) {
+      mp_clear(tka);
+   }
+   while ((unsigned)x < y) {
+      z = kb[0][x]; kb[0][x] = kb[0][y]; kb[0][y] = z;
+      ++x; --y;
+   }
+
+   /* store b */
+   if ((err = mp_to_unsigned_bin(tkb, kb[1])) != CRYPT_OK) {
+      if (tkb != kB) {
+         mp_clear(tkb);
+      }
+      return err;
+   }
+
+   x = 0;
+   y = mp_unsigned_bin_size(tkb) - 1;
+   if (tkb != kB) {
+      mp_clear(tkb);
+   }
+   while ((unsigned)x < y) {
+      z = kb[1][x]; kb[1][x] = kb[1][y]; kb[1][y] = z;
+      ++x; --y;
+   }
+
+   /* at this point we can start, yipee */
+   first = 1;
+   for (x = lut_gap-1; x >= 0; x--) {
+       /* extract FP_LUT bits from kb spread out by lut_gap bits and offset by x bits from the start */
+       bitpos = x;
+       for (y = zA = zB = 0; y < FP_LUT; y++) {
+          zA |= ((kb[0][bitpos>>3] >> (bitpos&7)) & 1) << y;
+          zB |= ((kb[1][bitpos>>3] >> (bitpos&7)) & 1) << y;
+          bitpos += lut_gap;                               /* it's y*lut_gap + x, but here we can avoid the mult in each loop */
+       }
+
+       /* double if not first */
+       if (!first) {
+          if ((err = ltc_mp.ecc_ptdbl(R, R, modulus, mp)) != CRYPT_OK) {
+             return err;
+          }
+       }
+
+       /* add if not first, otherwise copy */
+       if (!first) {
+          if (zA) {
+             if ((err = ltc_mp.ecc_ptadd(R, fp_cache[idx1].LUT[zA], R, modulus, mp)) != CRYPT_OK) {
+                return err;
+             }
+          }
+          if (zB) {
+             if ((err = ltc_mp.ecc_ptadd(R, fp_cache[idx2].LUT[zB], R, modulus, mp)) != CRYPT_OK) {
+                return err;
+             }
+          }
+       } else {
+          if (zA) {
+              if ((mp_copy(fp_cache[idx1].LUT[zA]->x, R->x) != CRYPT_OK) ||
+                 (mp_copy(fp_cache[idx1].LUT[zA]->y, R->y) != CRYPT_OK) ||
+                 (mp_copy(fp_cache[idx1].mu,        R->z) != CRYPT_OK)) { return CRYPT_MEM; }
+                 first = 0;
+          }
+          if (zB && first == 0) {
+             if (zB) {
+                if ((err = ltc_mp.ecc_ptadd(R, fp_cache[idx2].LUT[zB], R, modulus, mp)) != CRYPT_OK) {
+                   return err;
+                }
+             }
+          } else if (zB && first == 1) {
+              if ((mp_copy(fp_cache[idx2].LUT[zB]->x, R->x) != CRYPT_OK) ||
+                 (mp_copy(fp_cache[idx2].LUT[zB]->y, R->y) != CRYPT_OK) ||
+                 (mp_copy(fp_cache[idx2].mu,        R->z) != CRYPT_OK)) { return CRYPT_MEM; }
+                 first = 0;
+          }
+       }
+   }
+   zeromem(kb, sizeof(kb));
+   return ltc_ecc_map(R, modulus, mp);
+}
+
+/** ECC Fixed Point mulmod global
+  Computes kA*A + kB*B = C using Shamir's Trick
+  @param A        First point to multiply
+  @param kA       What to multiple A by
+  @param B        Second point to multiply
+  @param kB       What to multiple B by
+  @param C        [out] Destination point (can overlap with A or B)
+  @param modulus  Modulus for curve
+  @return CRYPT_OK on success
+*/
+int ltc_ecc_fp_mul2add(ecc_point *A, void *kA,
+                       ecc_point *B, void *kB,
+                       ecc_point *C, void *modulus)
+{
+   int  idx1, idx2, err;
+   void *mp, *mu;
+
+   mp = NULL;
+   mu = NULL;
+   LTC_MUTEX_LOCK(&ltc_ecc_fp_lock);
+      /* find point */
+      idx1 = _find_base(A);
+
+      /* no entry? */
+      if (idx1 == -1) {
+         /* find hole and add it */
+         if ((idx1 = _find_hole()) >= 0) {
+            if ((err = _add_entry(idx1, A)) != CRYPT_OK) {
+               goto LBL_ERR;
+            }
+         }
+      }
+      if (idx1 != -1) {
+         /* increment LRU */
+         ++(fp_cache[idx1].lru_count);
+      }
+
+      /* find point */
+      idx2 = _find_base(B);
+
+      /* no entry? */
+      if (idx2 == -1) {
+         /* find hole and add it */
+         if ((idx2 = _find_hole()) >= 0) {
+            if ((err = _add_entry(idx2, B)) != CRYPT_OK) {
+               goto LBL_ERR;
+            }
+         }
+      }
+      if (idx2 != -1) {
+         /* increment LRU */
+         ++(fp_cache[idx2].lru_count);
+      }
+
+      /* if it's 2 build the LUT, if it's higher just use the LUT */
+      if (idx1 >= 0 && fp_cache[idx1].lru_count == 2) {
+         /* compute mp */
+         if ((err = mp_montgomery_setup(modulus, &mp)) != CRYPT_OK) { goto LBL_ERR; }
+
+         /* compute mu */
+         if ((err = mp_init(&mu)) != CRYPT_OK) {
+             goto LBL_ERR;
+         }
+         if ((err = mp_montgomery_normalization(mu, modulus)) != CRYPT_OK) {
+            goto LBL_ERR;
+         }
+
+         /* build the LUT */
+         if ((err = _build_lut(idx1, modulus, mp, mu)) != CRYPT_OK) {
+             goto LBL_ERR;;
+         }
+      }
+
+      /* if it's 2 build the LUT, if it's higher just use the LUT */
+      if (idx2 >= 0 && fp_cache[idx2].lru_count == 2) {
+         if (mp == NULL) {
+            /* compute mp */
+            if ((err = mp_montgomery_setup(modulus, &mp)) != CRYPT_OK) { goto LBL_ERR; }
+
+            /* compute mu */
+            if ((err = mp_init(&mu)) != CRYPT_OK) {
+                goto LBL_ERR;
+            }
+            if ((err = mp_montgomery_normalization(mu, modulus)) != CRYPT_OK) {
+               goto LBL_ERR;
+            }
+         }
+
+         /* build the LUT */
+         if ((err = _build_lut(idx2, modulus, mp, mu)) != CRYPT_OK) {
+             goto LBL_ERR;;
+         }
+      }
+
+
+      if (idx1 >=0 && idx2 >= 0 && fp_cache[idx1].lru_count >= 2 && fp_cache[idx2].lru_count >= 2) {
+         if (mp == NULL) {
+            /* compute mp */
+            if ((err = mp_montgomery_setup(modulus, &mp)) != CRYPT_OK) { goto LBL_ERR; }
+         }
+         err = _accel_fp_mul2add(idx1, idx2, kA, kB, C, modulus, mp);
+      } else {
+         err = ltc_ecc_mul2add(A, kA, B, kB, C, modulus);
+      }
+LBL_ERR:
+    LTC_MUTEX_UNLOCK(&ltc_ecc_fp_lock);
+    if (mp != NULL) {
+       mp_montgomery_free(mp);
+    }
+    if (mu != NULL) {
+       mp_clear(mu);
+    }
+    return err;
+}
+#endif
+
+/** ECC Fixed Point mulmod global
+    @param k        The multiplicand
+    @param G        Base point to multiply
+    @param R        [out] Destination of product
+    @param modulus  The modulus for the curve
+    @param map      [boolean] If non-zero maps the point back to affine co-ordinates, otherwise it's left in jacobian-montgomery form
+    @return CRYPT_OK if successful
+*/
+int ltc_ecc_fp_mulmod(void *k, ecc_point *G, ecc_point *R, void *modulus, int map)
+{
+   int   idx, err;
+   void *mp, *mu;
+
+   mp = NULL;
+   mu = NULL;
+   LTC_MUTEX_LOCK(&ltc_ecc_fp_lock);
+      /* find point */
+      idx = _find_base(G);
+
+      /* no entry? */
+      if (idx == -1) {
+         /* find hole and add it */
+         idx = _find_hole();
+
+         if (idx >= 0) {
+            if ((err = _add_entry(idx, G)) != CRYPT_OK) {
+               goto LBL_ERR;
+            }
+         }
+      }
+      if (idx != -1) {
+         /* increment LRU */
+         ++(fp_cache[idx].lru_count);
+      }
+
+
+      /* if it's 2 build the LUT, if it's higher just use the LUT */
+      if (idx >= 0 && fp_cache[idx].lru_count == 2) {
+         /* compute mp */
+         if ((err = mp_montgomery_setup(modulus, &mp)) != CRYPT_OK) { goto LBL_ERR; }
+
+         /* compute mu */
+         if ((err = mp_init(&mu)) != CRYPT_OK) {
+             goto LBL_ERR;
+         }
+         if ((err = mp_montgomery_normalization(mu, modulus)) != CRYPT_OK) {
+            goto LBL_ERR;
+         }
+
+         /* build the LUT */
+         if ((err = _build_lut(idx, modulus, mp, mu)) != CRYPT_OK) {
+             goto LBL_ERR;;
+         }
+      }
+
+      if (idx >= 0 && fp_cache[idx].lru_count >= 2) {
+         if (mp == NULL) {
+            /* compute mp */
+            if ((err = mp_montgomery_setup(modulus, &mp)) != CRYPT_OK) { goto LBL_ERR; }
+         }
+         err = _accel_fp_mul(idx, k, R, modulus, mp, map);
+      } else {
+         err = ltc_ecc_mulmod(k, G, R, modulus, map);
+      }
+LBL_ERR:
+    LTC_MUTEX_UNLOCK(&ltc_ecc_fp_lock);
+    if (mp != NULL) {
+       mp_montgomery_free(mp);
+    }
+    if (mu != NULL) {
+       mp_clear(mu);
+    }
+    return err;
+}
+
+/* helper function for freeing the cache ... must be called with the cache mutex locked */
+static void _ltc_ecc_fp_free_cache(void)
+{
+   unsigned x, y;
+   for (x = 0; x < FP_ENTRIES; x++) {
+      if (fp_cache[x].g != NULL) {
+         for (y = 0; y < (1U<<FP_LUT); y++) {
+            ltc_ecc_del_point(fp_cache[x].LUT[y]);
+            fp_cache[x].LUT[y] = NULL;
+         }
+         ltc_ecc_del_point(fp_cache[x].g);
+         fp_cache[x].g         = NULL;
+         if (fp_cache[x].mu != NULL) {
+            mp_clear(fp_cache[x].mu);
+            fp_cache[x].mu     = NULL;
+         }
+         fp_cache[x].lru_count = 0;
+         fp_cache[x].lock = 0;
+      }
+   }
+}
+
+/** Free the Fixed Point cache */
+void ltc_ecc_fp_free(void)
+{
+   LTC_MUTEX_LOCK(&ltc_ecc_fp_lock);
+   _ltc_ecc_fp_free_cache();
+   LTC_MUTEX_UNLOCK(&ltc_ecc_fp_lock);
+}
+
+/** Add a point to the cache and initialize the LUT
+  @param g        The point to add
+  @param modulus  Modulus for curve
+  @param lock     Flag to indicate if this entry should be locked into the cache or not
+  @return CRYPT_OK on success
+*/
+int
+ltc_ecc_fp_add_point(ecc_point *g, void *modulus, int lock)
+{
+   int idx;
+   int err;
+   void *mp = NULL;
+   void *mu = NULL;
+
+   LTC_MUTEX_LOCK(&ltc_ecc_fp_lock);
+   if ((idx = _find_base(g)) >= 0) {
+      /* it is already in the cache ... just check that the LUT is initialized */
+      if(fp_cache[idx].lru_count >= 2) {
+         LTC_MUTEX_UNLOCK(&ltc_ecc_fp_lock);
+         return CRYPT_OK;
+      }
+   }
+
+   if(idx == -1 && (idx = _find_hole()) == -1) {
+      err = CRYPT_BUFFER_OVERFLOW;
+      goto LBL_ERR;
+   }
+   if ((err = _add_entry(idx, g)) != CRYPT_OK) {
+      goto LBL_ERR;
+   }
+   /* compute mp */
+   if ((err = mp_montgomery_setup(modulus, &mp)) != CRYPT_OK) {
+      goto LBL_ERR;
+   }
+
+   /* compute mu */
+   if ((err = mp_init(&mu)) != CRYPT_OK) {
+       goto LBL_ERR;
+   }
+   if ((err = mp_montgomery_normalization(mu, modulus)) != CRYPT_OK) {
+      goto LBL_ERR;
+   }
+
+   /* build the LUT */
+   if ((err = _build_lut(idx, modulus, mp, mu)) != CRYPT_OK) {
+       goto LBL_ERR;
+   }
+   fp_cache[idx].lru_count = 2;
+   fp_cache[idx].lock = lock;
+LBL_ERR:
+   LTC_MUTEX_UNLOCK(&ltc_ecc_fp_lock);
+   if (mp != NULL) {
+      mp_montgomery_free(mp);
+   }
+   if (mu != NULL) {
+      mp_clear(mu);
+   }
+   return err;
+}
+
+/** Prevent/permit the FP cache from being updated
+    @param flag        If flag is 0, remove cache lock (unlock), otherwise lock it
+*/
+void ltc_ecc_fp_tablelock(int lock)
+{
+   int i;
+
+   LTC_MUTEX_LOCK(&ltc_ecc_fp_lock);
+   for (i = 0; i < FP_ENTRIES; i++) {
+      fp_cache[i].lock = lock;
+   }
+   LTC_MUTEX_UNLOCK(&ltc_ecc_fp_lock);
+}
+
+/** Export the current cache as a binary packet
+    @param out      [out] pointer to malloc'ed space containing the packet
+    @param outlen   [out] size of exported packet
+    @return CRYPT_OK if successful
+*/
+int ltc_ecc_fp_save_state(unsigned char **out, unsigned long *outlen)
+{
+   ltc_asn1_list *cache_entry;
+   unsigned int   i, j, k;
+   unsigned long  fp_entries, fp_lut, num_entries;
+   int            err;
+
+   LTC_ARGCHK(out    != NULL);
+   LTC_ARGCHK(outlen != NULL);
+
+   fp_entries  = FP_ENTRIES;
+   fp_lut      = FP_LUT;
+   num_entries = 0;
+
+   LTC_MUTEX_LOCK(&ltc_ecc_fp_lock);
+   /*
+    * build the list;
+      Cache DEFINITIONS ::=
+      BEGIN
+       CacheDump ::= SEQUENCE {
+         numEntries    SHORTINTEGER,
+         maxEntries    SHORTINTEGER,
+         numLUT        SHORTINTEGER,
+         cache         SEQUENCE OF INTEGER
+       }
+      END
+    *
+    */
+   /*
+    * The cache itself is a point (3 INTEGERS),
+    * the LUT as pairs of INTEGERS (2 * 1<<FP_LUT),
+    * and the mu INTEGER
+    */
+   cache_entry = XCALLOC(FP_ENTRIES*(2*(1U<<FP_LUT)+4)+3, sizeof(ltc_asn1_list));
+   if (cache_entry == NULL)
+      return CRYPT_MEM;
+   j = 1;   /* handle the zero'th element later */
+
+   LTC_SET_ASN1(cache_entry, j++, LTC_ASN1_SHORT_INTEGER, &fp_entries, 1);
+   LTC_SET_ASN1(cache_entry, j++, LTC_ASN1_SHORT_INTEGER, &fp_lut, 1);
+
+   for (i = 0; i < FP_ENTRIES; i++) {
+      /*
+       * do not save empty entries, or entries that have not yet had the lut built
+       */
+      if (fp_cache[i].g == NULL || fp_cache[i].lru_count < 2) {
+         continue;
+      }
+      num_entries++;
+      LTC_SET_ASN1(cache_entry, j++, LTC_ASN1_INTEGER, fp_cache[i].g->x, 1);
+      LTC_SET_ASN1(cache_entry, j++, LTC_ASN1_INTEGER, fp_cache[i].g->y, 1);
+      LTC_SET_ASN1(cache_entry, j++, LTC_ASN1_INTEGER, fp_cache[i].g->z, 1);
+      for (k = 0; k < (1U<<FP_LUT); k++) {
+         LTC_SET_ASN1(cache_entry, j++, LTC_ASN1_INTEGER, fp_cache[i].LUT[k]->x, 1);
+         LTC_SET_ASN1(cache_entry, j++, LTC_ASN1_INTEGER, fp_cache[i].LUT[k]->y, 1);
+      }
+      LTC_SET_ASN1(cache_entry, j++, LTC_ASN1_INTEGER, fp_cache[i].mu, 1);
+   }
+   LTC_SET_ASN1(cache_entry, j++, LTC_ASN1_EOL, 0, 0);
+
+   LTC_SET_ASN1(cache_entry, 0, LTC_ASN1_SHORT_INTEGER, &num_entries, 1);
+
+   if ((err = der_length_sequence(cache_entry, j, outlen)) != CRYPT_OK) {
+      goto save_err;
+   }
+   if ((*out = XMALLOC(*outlen)) == NULL) {
+      err = CRYPT_MEM;
+      goto save_err;
+   }
+   err = der_encode_sequence(cache_entry, j, *out, outlen);
+save_err:
+   XFREE(cache_entry);
+   LTC_MUTEX_UNLOCK(&ltc_ecc_fp_lock);
+   return err;
+}
+
+/** Import a binary packet into the current cache
+    @param in      [in] pointer to packet
+    @param inlen   [in] size of packet (bytes)
+    @return CRYPT_OK if successful
+*/
+int ltc_ecc_fp_restore_state(unsigned char *in, unsigned long inlen)
+{
+   int            err;
+   ltc_asn1_list *asn1_list;
+   unsigned long  num_entries, fp_entries, fp_lut;
+   unsigned long  i, j;
+   unsigned int   x;
+
+   LTC_ARGCHK(in != NULL);
+   if (inlen == 0) {
+      return CRYPT_INVALID_ARG;
+   }
+
+   /* zero indecies */
+   i         = 0;
+   j         = 0;
+   asn1_list = NULL;
+
+   LTC_MUTEX_LOCK(&ltc_ecc_fp_lock);
+   /*
+    * start with an empty cache
+    */
+   _ltc_ecc_fp_free_cache();
+
+   /*
+    * decode the input packet: It consists of a sequence with a few
+    * integers (including the FP_ENTRIES and FP_LUT sizes), followed by a
+    * SEQUENCE which is the cache itself.
+    *
+    * use standard decoding for the first part, then flexible for the second
+    */
+   if((err = der_decode_sequence_multi(in, inlen,
+                                       LTC_ASN1_SHORT_INTEGER, 1, &num_entries,
+                                       LTC_ASN1_SHORT_INTEGER, 1, &fp_entries,
+                                       LTC_ASN1_SHORT_INTEGER, 1, &fp_lut,
+                                       LTC_ASN1_EOL,           0, 0)) != CRYPT_OK) {
+      goto ERR_OUT;
+   }
+   if (fp_entries != FP_ENTRIES || fp_lut != FP_LUT || num_entries > fp_entries) {
+      err = CRYPT_INVALID_PACKET;
+      goto ERR_OUT;
+   }
+   if ((asn1_list = XCALLOC(3+num_entries*(4+2*(1<<FP_LUT))+1, sizeof(ltc_asn1_list))) == NULL) {
+      err = CRYPT_MEM;
+      goto ERR_OUT;
+   }
+   j = 0;
+   LTC_SET_ASN1(asn1_list, j++, LTC_ASN1_SHORT_INTEGER, &num_entries, 1);
+   LTC_SET_ASN1(asn1_list, j++, LTC_ASN1_SHORT_INTEGER, &fp_entries, 1);
+   LTC_SET_ASN1(asn1_list, j++, LTC_ASN1_SHORT_INTEGER, &fp_lut, 1);
+   for (i = 0; i < num_entries; i++) {
+      if((fp_cache[i].g = ltc_ecc_new_point()) == NULL) {
+         err = CRYPT_MEM;
+         goto ERR_OUT;
+      }
+      LTC_SET_ASN1(asn1_list, j++, LTC_ASN1_INTEGER, fp_cache[i].g->x, 1);
+      LTC_SET_ASN1(asn1_list, j++, LTC_ASN1_INTEGER, fp_cache[i].g->y, 1);
+      LTC_SET_ASN1(asn1_list, j++, LTC_ASN1_INTEGER, fp_cache[i].g->z, 1);
+      for (x = 0; x < (1U<<FP_LUT); x++) {
+         /* since we don't store z in the cache, don't use ltc_ecc_new_point()
+          * (which allocates space for z, only to have to free it later) */
+         ecc_point *p = XCALLOC(1, sizeof(*p));
+
+         if (p == NULL) {
+            err = CRYPT_MEM;
+            goto ERR_OUT;
+         }
+         fp_cache[i].LUT[x] = p;
+         if ((err = mp_init_multi(&p->x, &p->y, NULL)) != CRYPT_OK) {
+            goto ERR_OUT;
+         }
+         p->z = NULL;
+         LTC_SET_ASN1(asn1_list, j++, LTC_ASN1_INTEGER, p->x, 1);
+         LTC_SET_ASN1(asn1_list, j++, LTC_ASN1_INTEGER, p->y, 1);
+      }
+      if((err = mp_init(&fp_cache[i].mu)) != CRYPT_OK) {
+         goto ERR_OUT;
+      }
+      LTC_SET_ASN1(asn1_list, j++, LTC_ASN1_INTEGER, fp_cache[i].mu, 1);
+      fp_cache[i].lru_count = 3;
+      fp_cache[i].lock = 1;
+   }
+
+   if ((err = der_decode_sequence(in, inlen, asn1_list, j)) != CRYPT_OK) {
+      goto ERR_OUT;
+   }
+   XFREE(asn1_list);
+   LTC_MUTEX_UNLOCK(&ltc_ecc_fp_lock);
+   return CRYPT_OK;
+ERR_OUT:
+   if(asn1_list)
+      XFREE(asn1_list);
+   _ltc_ecc_fp_free_cache();
+   LTC_MUTEX_UNLOCK(&ltc_ecc_fp_lock);
+   return err;
+}
+
+#endif
+
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
+
diff --git a/libtomcrypt/src/math/gmp_desc.c b/libtomcrypt/src/math/gmp_desc.c
new file mode 100644 (file)
index 0000000..d80d87f
--- /dev/null
@@ -0,0 +1,554 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+#define DESC_DEF_ONLY
+#include "tomcrypt.h"
+
+#ifdef GMP_DESC
+
+#include <stdio.h>
+#include <gmp.h>
+
+static int init(void **a)
+{
+   LTC_ARGCHK(a != NULL);
+
+   *a = XCALLOC(1, sizeof(__mpz_struct));
+   if (*a == NULL) {
+      return CRYPT_MEM;
+   }
+   mpz_init(((__mpz_struct *)*a));
+   return CRYPT_OK;
+}
+
+static void deinit(void *a)
+{
+   LTC_ARGCHKVD(a != NULL);
+   mpz_clear(a);
+   XFREE(a);
+}
+
+static int neg(void *a, void *b)
+{
+   LTC_ARGCHK(a != NULL);
+   LTC_ARGCHK(b != NULL);
+   mpz_neg(b, a);
+   return CRYPT_OK;
+}
+
+static int copy(void *a, void *b)
+{
+   LTC_ARGCHK(a != NULL);
+   LTC_ARGCHK(b != NULL);
+   mpz_set(b, a);
+   return CRYPT_OK;
+}
+
+static int init_copy(void **a, void *b)
+{
+   if (init(a) != CRYPT_OK) {
+      return CRYPT_MEM;
+   }
+   return copy(b, *a);
+}
+
+/* ---- trivial ---- */
+static int set_int(void *a, ltc_mp_digit b)
+{
+   LTC_ARGCHK(a != NULL);
+   mpz_set_ui(((__mpz_struct *)a), b);
+   return CRYPT_OK;
+}
+
+static unsigned long get_int(void *a)
+{
+   LTC_ARGCHK(a != NULL);
+   return mpz_get_ui(a);
+}
+
+static ltc_mp_digit get_digit(void *a, int n)
+{
+   LTC_ARGCHK(a != NULL);
+   return mpz_getlimbn(a, n);
+}
+
+static int get_digit_count(void *a)
+{
+   LTC_ARGCHK(a != NULL);
+   return mpz_size(a);
+}
+
+static int compare(void *a, void *b)
+{
+   int ret;
+   LTC_ARGCHK(a != NULL);
+   LTC_ARGCHK(b != NULL);
+   ret = mpz_cmp(a, b);
+   if (ret < 0) {
+      return LTC_MP_LT;
+   } else if (ret > 0) {
+      return LTC_MP_GT;
+   } else {
+      return LTC_MP_EQ;
+   }
+}
+
+static int compare_d(void *a, ltc_mp_digit b)
+{
+   int ret;
+   LTC_ARGCHK(a != NULL);
+   ret = mpz_cmp_ui(((__mpz_struct *)a), b);
+   if (ret < 0) {
+      return LTC_MP_LT;
+   } else if (ret > 0) {
+      return LTC_MP_GT;
+   } else {
+      return LTC_MP_EQ;
+   }
+}
+
+static int count_bits(void *a)
+{
+   LTC_ARGCHK(a != NULL);
+   return mpz_sizeinbase(a, 2);
+}
+
+static int count_lsb_bits(void *a)
+{
+   LTC_ARGCHK(a != NULL);
+   return mpz_scan1(a, 0);
+}
+
+
+static int twoexpt(void *a, int n)
+{
+   LTC_ARGCHK(a != NULL);
+   mpz_set_ui(a, 0);
+   mpz_setbit(a, n);
+   return CRYPT_OK;
+}
+
+/* ---- conversions ---- */
+
+static const char rmap[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+/";
+
+/* read ascii string */
+static int read_radix(void *a, const char *b, int radix)
+{
+   int ret;
+   LTC_ARGCHK(a != NULL);
+   LTC_ARGCHK(b != NULL);
+   if (radix == 64) {
+      /* Sadly, GMP only supports radixes up to 62, but we need 64.
+       * So, although this is not the most elegant or efficient way,
+       * let's just convert the base 64 string (6 bits per digit) to
+       * an octal string (3 bits per digit) that's twice as long. */
+      char c, *tmp, *q;
+      const char *p;
+      int i;
+      tmp = XMALLOC (1 + 2 * strlen (b));
+      if (tmp == NULL) {
+         return CRYPT_MEM;
+      }
+      p = b;
+      q = tmp;
+      while ((c = *p++) != 0) {
+         for (i = 0; i < 64; i++) {
+            if (c == rmap[i])
+               break;
+         }
+         if (i == 64) {
+            XFREE (tmp);
+            /* printf ("c = '%c'\n", c); */
+            return CRYPT_ERROR;
+         }
+         *q++ = '0' + (i / 8);
+         *q++ = '0' + (i % 8);
+      }
+      *q = 0;
+      ret = mpz_set_str(a, tmp, 8);
+      /* printf ("ret = %d for '%s'\n", ret, tmp); */
+      XFREE (tmp);
+   } else {
+      ret = mpz_set_str(a, b, radix);
+   }
+   return (ret == 0 ? CRYPT_OK : CRYPT_ERROR);
+}
+
+/* write one */
+static int write_radix(void *a, char *b, int radix)
+{
+   LTC_ARGCHK(a != NULL);
+   LTC_ARGCHK(b != NULL);
+   if (radix >= 11 && radix <= 36)
+      /* If radix is positive, GMP uses lowercase, and if negative, uppercase.
+       * We want it to use uppercase, to match the test vectors (presumably
+       * generated with LibTomMath). */
+      radix = -radix;
+   mpz_get_str(b, radix, a);
+   return CRYPT_OK;
+}
+
+/* get size as unsigned char string */
+static unsigned long unsigned_size(void *a)
+{
+   unsigned long t;
+   LTC_ARGCHK(a != NULL);
+   t = mpz_sizeinbase(a, 2);
+   if (mpz_cmp_ui(((__mpz_struct *)a), 0) == 0) return 0;
+   return (t>>3) + ((t&7)?1:0);
+}
+
+/* store */
+static int unsigned_write(void *a, unsigned char *b)
+{
+   LTC_ARGCHK(a != NULL);
+   LTC_ARGCHK(b != NULL);
+   mpz_export(b, NULL, 1, 1, 1, 0, ((__mpz_struct*)a));
+   return CRYPT_OK;
+}
+
+/* read */
+static int unsigned_read(void *a, unsigned char *b, unsigned long len)
+{
+   LTC_ARGCHK(a != NULL);
+   LTC_ARGCHK(b != NULL);
+   mpz_import(a, len, 1, 1, 1, 0, b);
+   return CRYPT_OK;
+}
+
+/* add */
+static int add(void *a, void *b, void *c)
+{
+   LTC_ARGCHK(a != NULL);
+   LTC_ARGCHK(b != NULL);
+   LTC_ARGCHK(c != NULL);
+   mpz_add(c, a, b);
+   return CRYPT_OK;
+}
+
+static int addi(void *a, ltc_mp_digit b, void *c)
+{
+   LTC_ARGCHK(a != NULL);
+   LTC_ARGCHK(c != NULL);
+   mpz_add_ui(c, a, b);
+   return CRYPT_OK;
+}
+
+/* sub */
+static int sub(void *a, void *b, void *c)
+{
+   LTC_ARGCHK(a != NULL);
+   LTC_ARGCHK(b != NULL);
+   LTC_ARGCHK(c != NULL);
+   mpz_sub(c, a, b);
+   return CRYPT_OK;
+}
+
+static int subi(void *a, ltc_mp_digit b, void *c)
+{
+   LTC_ARGCHK(a != NULL);
+   LTC_ARGCHK(c != NULL);
+   mpz_sub_ui(c, a, b);
+   return CRYPT_OK;
+}
+
+/* mul */
+static int mul(void *a, void *b, void *c)
+{
+   LTC_ARGCHK(a != NULL);
+   LTC_ARGCHK(b != NULL);
+   LTC_ARGCHK(c != NULL);
+   mpz_mul(c, a, b);
+   return CRYPT_OK;
+}
+
+static int muli(void *a, ltc_mp_digit b, void *c)
+{
+   LTC_ARGCHK(a != NULL);
+   LTC_ARGCHK(c != NULL);
+   mpz_mul_ui(c, a, b);
+   return CRYPT_OK;
+}
+
+/* sqr */
+static int sqr(void *a, void *b)
+{
+   LTC_ARGCHK(a != NULL);
+   LTC_ARGCHK(b != NULL);
+   mpz_mul(b, a, a);
+   return CRYPT_OK;
+}
+
+/* div */
+static int divide(void *a, void *b, void *c, void *d)
+{
+   mpz_t tmp;
+   LTC_ARGCHK(a != NULL);
+   LTC_ARGCHK(b != NULL);
+   if (c != NULL) {
+      mpz_init(tmp);
+      mpz_divexact(tmp, a, b);
+   }
+   if (d != NULL) {
+      mpz_mod(d, a, b);
+   }
+   if (c != NULL) {
+      mpz_set(c, tmp);
+      mpz_clear(tmp);
+   }
+   return CRYPT_OK;
+}
+
+static int div_2(void *a, void *b)
+{
+   LTC_ARGCHK(a != NULL);
+   LTC_ARGCHK(b != NULL);
+   mpz_divexact_ui(b, a, 2);
+   return CRYPT_OK;
+}
+
+/* modi */
+static int modi(void *a, ltc_mp_digit b, ltc_mp_digit *c)
+{
+   LTC_ARGCHK(a != NULL);
+   LTC_ARGCHK(c != NULL);
+
+   *c = mpz_fdiv_ui(a, b);
+   return CRYPT_OK;
+}
+
+/* gcd */
+static int gcd(void *a, void *b, void *c)
+{
+   LTC_ARGCHK(a != NULL);
+   LTC_ARGCHK(b != NULL);
+   LTC_ARGCHK(c != NULL);
+   mpz_gcd(c, a, b);
+   return CRYPT_OK;
+}
+
+/* lcm */
+static int lcm(void *a, void *b, void *c)
+{
+   LTC_ARGCHK(a != NULL);
+   LTC_ARGCHK(b != NULL);
+   LTC_ARGCHK(c != NULL);
+   mpz_lcm(c, a, b);
+   return CRYPT_OK;
+}
+
+static int addmod(void *a, void *b, void *c, void *d)
+{
+   LTC_ARGCHK(a != NULL);
+   LTC_ARGCHK(b != NULL);
+   LTC_ARGCHK(c != NULL);
+   LTC_ARGCHK(d != NULL);
+   mpz_add(d, a, b);
+   mpz_mod(d, d, c);
+   return CRYPT_OK;
+}
+
+static int submod(void *a, void *b, void *c, void *d)
+{
+   LTC_ARGCHK(a != NULL);
+   LTC_ARGCHK(b != NULL);
+   LTC_ARGCHK(c != NULL);
+   LTC_ARGCHK(d != NULL);
+   mpz_sub(d, a, b);
+   mpz_mod(d, d, c);
+   return CRYPT_OK;
+}
+
+static int mulmod(void *a, void *b, void *c, void *d)
+{
+   LTC_ARGCHK(a != NULL);
+   LTC_ARGCHK(b != NULL);
+   LTC_ARGCHK(c != NULL);
+   LTC_ARGCHK(d != NULL);
+   mpz_mul(d, a, b);
+   mpz_mod(d, d, c);
+   return CRYPT_OK;
+}
+
+static int sqrmod(void *a, void *b, void *c)
+{
+   LTC_ARGCHK(a != NULL);
+   LTC_ARGCHK(b != NULL);
+   LTC_ARGCHK(c != NULL);
+   mpz_mul(c, a, a);
+   mpz_mod(c, c, b);
+   return CRYPT_OK;
+}
+
+/* invmod */
+static int invmod(void *a, void *b, void *c)
+{
+   LTC_ARGCHK(a != NULL);
+   LTC_ARGCHK(b != NULL);
+   LTC_ARGCHK(c != NULL);
+   mpz_invert(c, a, b);
+   return CRYPT_OK;
+}
+
+/* setup */
+static int montgomery_setup(void *a, void **b)
+{
+   LTC_ARGCHK(a != NULL);
+   LTC_ARGCHK(b != NULL);
+   *b = (void *)1;
+   return CRYPT_OK;
+}
+
+/* get normalization value */
+static int montgomery_normalization(void *a, void *b)
+{
+   LTC_ARGCHK(a != NULL);
+   LTC_ARGCHK(b != NULL);
+   mpz_set_ui(a, 1);
+   return CRYPT_OK;
+}
+
+/* reduce */
+static int montgomery_reduce(void *a, void *b, void *c)
+{
+   LTC_ARGCHK(a != NULL);
+   LTC_ARGCHK(b != NULL);
+   LTC_ARGCHK(c != NULL);
+   mpz_mod(a, a, b);
+   return CRYPT_OK;
+}
+
+/* clean up */
+static void montgomery_deinit(void *a)
+{
+  LTC_UNUSED_PARAM(a);
+}
+
+static int exptmod(void *a, void *b, void *c, void *d)
+{
+   LTC_ARGCHK(a != NULL);
+   LTC_ARGCHK(b != NULL);
+   LTC_ARGCHK(c != NULL);
+   LTC_ARGCHK(d != NULL);
+   mpz_powm(d, a, b, c);
+   return CRYPT_OK;
+}
+
+static int isprime(void *a, int b, int *c)
+{
+   LTC_ARGCHK(a != NULL);
+   LTC_ARGCHK(c != NULL);
+   if (b == 0) {
+       b = LTC_MILLER_RABIN_REPS;
+   } /* if */
+   *c = mpz_probab_prime_p(a, b) > 0 ? LTC_MP_YES : LTC_MP_NO;
+   return CRYPT_OK;
+}
+
+static int set_rand(void *a, int size)
+{
+   LTC_ARGCHK(a != NULL);
+   mpz_random(a, size);
+   return CRYPT_OK;
+}
+
+const ltc_math_descriptor gmp_desc = {
+   "GNU MP",
+   sizeof(mp_limb_t) * CHAR_BIT - GMP_NAIL_BITS,
+
+   &init,
+   &init_copy,
+   &deinit,
+
+   &neg,
+   &copy,
+
+   &set_int,
+   &get_int,
+   &get_digit,
+   &get_digit_count,
+   &compare,
+   &compare_d,
+   &count_bits,
+   &count_lsb_bits,
+   &twoexpt,
+
+   &read_radix,
+   &write_radix,
+   &unsigned_size,
+   &unsigned_write,
+   &unsigned_read,
+
+   &add,
+   &addi,
+   &sub,
+   &subi,
+   &mul,
+   &muli,
+   &sqr,
+   &divide,
+   &div_2,
+   &modi,
+   &gcd,
+   &lcm,
+
+   &mulmod,
+   &sqrmod,
+   &invmod,
+
+   &montgomery_setup,
+   &montgomery_normalization,
+   &montgomery_reduce,
+   &montgomery_deinit,
+
+   &exptmod,
+   &isprime,
+
+#ifdef LTC_MECC
+#ifdef LTC_MECC_FP
+   &ltc_ecc_fp_mulmod,
+#else
+   &ltc_ecc_mulmod,
+#endif /* LTC_MECC_FP */
+   &ltc_ecc_projective_add_point,
+   &ltc_ecc_projective_dbl_point,
+   &ltc_ecc_map,
+#ifdef LTC_ECC_SHAMIR
+#ifdef LTC_MECC_FP
+   &ltc_ecc_fp_mul2add,
+#else
+   &ltc_ecc_mul2add,
+#endif /* LTC_MECC_FP */
+#else
+   NULL,
+#endif /* LTC_ECC_SHAMIR */
+#else
+   NULL, NULL, NULL, NULL, NULL,
+#endif /* LTC_MECC */
+
+#ifdef LTC_MRSA
+   &rsa_make_key,
+   &rsa_exptmod,
+#else
+   NULL, NULL,
+#endif
+   &addmod,
+   &submod,
+
+   &set_rand,
+
+};
+
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/math/ltm_desc.c b/libtomcrypt/src/math/ltm_desc.c
new file mode 100644 (file)
index 0000000..3e2a0c9
--- /dev/null
@@ -0,0 +1,513 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+#define DESC_DEF_ONLY
+#include "tomcrypt.h"
+
+#ifdef LTM_DESC
+
+#include <tommath.h>
+
+static const struct {
+    int mpi_code, ltc_code;
+} mpi_to_ltc_codes[] = {
+   { MP_OKAY ,  CRYPT_OK},
+   { MP_MEM  ,  CRYPT_MEM},
+   { MP_VAL  ,  CRYPT_INVALID_ARG},
+};
+
+/**
+   Convert a MPI error to a LTC error (Possibly the most powerful function ever!  Oh wait... no)
+   @param err    The error to convert
+   @return The equivalent LTC error code or CRYPT_ERROR if none found
+*/
+static int mpi_to_ltc_error(int err)
+{
+   int x;
+
+   for (x = 0; x < (int)(sizeof(mpi_to_ltc_codes)/sizeof(mpi_to_ltc_codes[0])); x++) {
+       if (err == mpi_to_ltc_codes[x].mpi_code) {
+          return mpi_to_ltc_codes[x].ltc_code;
+       }
+   }
+   return CRYPT_ERROR;
+}
+
+static int init(void **a)
+{
+   int err;
+
+   LTC_ARGCHK(a != NULL);
+
+   *a = XCALLOC(1, sizeof(mp_int));
+   if (*a == NULL) {
+      return CRYPT_MEM;
+   }
+
+   if ((err = mpi_to_ltc_error(mp_init(*a))) != CRYPT_OK) {
+      XFREE(*a);
+   }
+   return err;
+}
+
+static void deinit(void *a)
+{
+   LTC_ARGCHKVD(a != NULL);
+   mp_clear(a);
+   XFREE(a);
+}
+
+static int neg(void *a, void *b)
+{
+   LTC_ARGCHK(a != NULL);
+   LTC_ARGCHK(b != NULL);
+   return mpi_to_ltc_error(mp_neg(a, b));
+}
+
+static int copy(void *a, void *b)
+{
+   LTC_ARGCHK(a != NULL);
+   LTC_ARGCHK(b != NULL);
+   return mpi_to_ltc_error(mp_copy(a, b));
+}
+
+static int init_copy(void **a, void *b)
+{
+   if (init(a) != CRYPT_OK) {
+      return CRYPT_MEM;
+   }
+   return copy(b, *a);
+}
+
+/* ---- trivial ---- */
+static int set_int(void *a, ltc_mp_digit b)
+{
+   LTC_ARGCHK(a != NULL);
+   return mpi_to_ltc_error(mp_set_int(a, b));
+}
+
+static unsigned long get_int(void *a)
+{
+   LTC_ARGCHK(a != NULL);
+   return mp_get_int(a);
+}
+
+static ltc_mp_digit get_digit(void *a, int n)
+{
+   mp_int *A;
+   LTC_ARGCHK(a != NULL);
+   A = a;
+   return (n >= A->used || n < 0) ? 0 : A->dp[n];
+}
+
+static int get_digit_count(void *a)
+{
+   mp_int *A;
+   LTC_ARGCHK(a != NULL);
+   A = a;
+   return A->used;
+}
+
+static int compare(void *a, void *b)
+{
+   int ret;
+   LTC_ARGCHK(a != NULL);
+   LTC_ARGCHK(b != NULL);
+   ret = mp_cmp(a, b);
+   switch (ret) {
+      case MP_LT: return LTC_MP_LT;
+      case MP_EQ: return LTC_MP_EQ;
+      case MP_GT: return LTC_MP_GT;
+      default:    return 0;
+   }
+}
+
+static int compare_d(void *a, ltc_mp_digit b)
+{
+   int ret;
+   LTC_ARGCHK(a != NULL);
+   ret = mp_cmp_d(a, b);
+   switch (ret) {
+      case MP_LT: return LTC_MP_LT;
+      case MP_EQ: return LTC_MP_EQ;
+      case MP_GT: return LTC_MP_GT;
+      default:    return 0;
+   }
+}
+
+static int count_bits(void *a)
+{
+   LTC_ARGCHK(a != NULL);
+   return mp_count_bits(a);
+}
+
+static int count_lsb_bits(void *a)
+{
+   LTC_ARGCHK(a != NULL);
+   return mp_cnt_lsb(a);
+}
+
+
+static int twoexpt(void *a, int n)
+{
+   LTC_ARGCHK(a != NULL);
+   return mpi_to_ltc_error(mp_2expt(a, n));
+}
+
+/* ---- conversions ---- */
+
+/* read ascii string */
+static int read_radix(void *a, const char *b, int radix)
+{
+   LTC_ARGCHK(a != NULL);
+   LTC_ARGCHK(b != NULL);
+   return mpi_to_ltc_error(mp_read_radix(a, b, radix));
+}
+
+/* write one */
+static int write_radix(void *a, char *b, int radix)
+{
+   LTC_ARGCHK(a != NULL);
+   LTC_ARGCHK(b != NULL);
+   return mpi_to_ltc_error(mp_toradix(a, b, radix));
+}
+
+/* get size as unsigned char string */
+static unsigned long unsigned_size(void *a)
+{
+   LTC_ARGCHK(a != NULL);
+   return mp_unsigned_bin_size(a);
+}
+
+/* store */
+static int unsigned_write(void *a, unsigned char *b)
+{
+   LTC_ARGCHK(a != NULL);
+   LTC_ARGCHK(b != NULL);
+   return mpi_to_ltc_error(mp_to_unsigned_bin(a, b));
+}
+
+/* read */
+static int unsigned_read(void *a, unsigned char *b, unsigned long len)
+{
+   LTC_ARGCHK(a != NULL);
+   LTC_ARGCHK(b != NULL);
+   return mpi_to_ltc_error(mp_read_unsigned_bin(a, b, len));
+}
+
+/* add */
+static int add(void *a, void *b, void *c)
+{
+   LTC_ARGCHK(a != NULL);
+   LTC_ARGCHK(b != NULL);
+   LTC_ARGCHK(c != NULL);
+   return mpi_to_ltc_error(mp_add(a, b, c));
+}
+
+static int addi(void *a, ltc_mp_digit b, void *c)
+{
+   LTC_ARGCHK(a != NULL);
+   LTC_ARGCHK(c != NULL);
+   return mpi_to_ltc_error(mp_add_d(a, b, c));
+}
+
+/* sub */
+static int sub(void *a, void *b, void *c)
+{
+   LTC_ARGCHK(a != NULL);
+   LTC_ARGCHK(b != NULL);
+   LTC_ARGCHK(c != NULL);
+   return mpi_to_ltc_error(mp_sub(a, b, c));
+}
+
+static int subi(void *a, ltc_mp_digit b, void *c)
+{
+   LTC_ARGCHK(a != NULL);
+   LTC_ARGCHK(c != NULL);
+   return mpi_to_ltc_error(mp_sub_d(a, b, c));
+}
+
+/* mul */
+static int mul(void *a, void *b, void *c)
+{
+   LTC_ARGCHK(a != NULL);
+   LTC_ARGCHK(b != NULL);
+   LTC_ARGCHK(c != NULL);
+   return mpi_to_ltc_error(mp_mul(a, b, c));
+}
+
+static int muli(void *a, ltc_mp_digit b, void *c)
+{
+   LTC_ARGCHK(a != NULL);
+   LTC_ARGCHK(c != NULL);
+   return mpi_to_ltc_error(mp_mul_d(a, b, c));
+}
+
+/* sqr */
+static int sqr(void *a, void *b)
+{
+   LTC_ARGCHK(a != NULL);
+   LTC_ARGCHK(b != NULL);
+   return mpi_to_ltc_error(mp_sqr(a, b));
+}
+
+/* div */
+static int divide(void *a, void *b, void *c, void *d)
+{
+   LTC_ARGCHK(a != NULL);
+   LTC_ARGCHK(b != NULL);
+   return mpi_to_ltc_error(mp_div(a, b, c, d));
+}
+
+static int div_2(void *a, void *b)
+{
+   LTC_ARGCHK(a != NULL);
+   LTC_ARGCHK(b != NULL);
+   return mpi_to_ltc_error(mp_div_2(a, b));
+}
+
+/* modi */
+static int modi(void *a, ltc_mp_digit b, ltc_mp_digit *c)
+{
+   mp_digit tmp;
+   int      err;
+
+   LTC_ARGCHK(a != NULL);
+   LTC_ARGCHK(c != NULL);
+
+   if ((err = mpi_to_ltc_error(mp_mod_d(a, b, &tmp))) != CRYPT_OK) {
+      return err;
+   }
+   *c = tmp;
+   return CRYPT_OK;
+}
+
+/* gcd */
+static int gcd(void *a, void *b, void *c)
+{
+   LTC_ARGCHK(a != NULL);
+   LTC_ARGCHK(b != NULL);
+   LTC_ARGCHK(c != NULL);
+   return mpi_to_ltc_error(mp_gcd(a, b, c));
+}
+
+/* lcm */
+static int lcm(void *a, void *b, void *c)
+{
+   LTC_ARGCHK(a != NULL);
+   LTC_ARGCHK(b != NULL);
+   LTC_ARGCHK(c != NULL);
+   return mpi_to_ltc_error(mp_lcm(a, b, c));
+}
+
+static int addmod(void *a, void *b, void *c, void *d)
+{
+   LTC_ARGCHK(a != NULL);
+   LTC_ARGCHK(b != NULL);
+   LTC_ARGCHK(c != NULL);
+   LTC_ARGCHK(d != NULL);
+   return mpi_to_ltc_error(mp_addmod(a,b,c,d));
+}
+
+static int submod(void *a, void *b, void *c, void *d)
+{
+   LTC_ARGCHK(a != NULL);
+   LTC_ARGCHK(b != NULL);
+   LTC_ARGCHK(c != NULL);
+   LTC_ARGCHK(d != NULL);
+   return mpi_to_ltc_error(mp_submod(a,b,c,d));
+}
+
+static int mulmod(void *a, void *b, void *c, void *d)
+{
+   LTC_ARGCHK(a != NULL);
+   LTC_ARGCHK(b != NULL);
+   LTC_ARGCHK(c != NULL);
+   LTC_ARGCHK(d != NULL);
+   return mpi_to_ltc_error(mp_mulmod(a,b,c,d));
+}
+
+static int sqrmod(void *a, void *b, void *c)
+{
+   LTC_ARGCHK(a != NULL);
+   LTC_ARGCHK(b != NULL);
+   LTC_ARGCHK(c != NULL);
+   return mpi_to_ltc_error(mp_sqrmod(a,b,c));
+}
+
+/* invmod */
+static int invmod(void *a, void *b, void *c)
+{
+   LTC_ARGCHK(a != NULL);
+   LTC_ARGCHK(b != NULL);
+   LTC_ARGCHK(c != NULL);
+   return mpi_to_ltc_error(mp_invmod(a, b, c));
+}
+
+/* setup */
+static int montgomery_setup(void *a, void **b)
+{
+   int err;
+   LTC_ARGCHK(a != NULL);
+   LTC_ARGCHK(b != NULL);
+   *b = XCALLOC(1, sizeof(mp_digit));
+   if (*b == NULL) {
+      return CRYPT_MEM;
+   }
+   if ((err = mpi_to_ltc_error(mp_montgomery_setup(a, (mp_digit *)*b))) != CRYPT_OK) {
+      XFREE(*b);
+   }
+   return err;
+}
+
+/* get normalization value */
+static int montgomery_normalization(void *a, void *b)
+{
+   LTC_ARGCHK(a != NULL);
+   LTC_ARGCHK(b != NULL);
+   return mpi_to_ltc_error(mp_montgomery_calc_normalization(a, b));
+}
+
+/* reduce */
+static int montgomery_reduce(void *a, void *b, void *c)
+{
+   LTC_ARGCHK(a != NULL);
+   LTC_ARGCHK(b != NULL);
+   LTC_ARGCHK(c != NULL);
+   return mpi_to_ltc_error(mp_montgomery_reduce(a, b, *((mp_digit *)c)));
+}
+
+/* clean up */
+static void montgomery_deinit(void *a)
+{
+   XFREE(a);
+}
+
+static int exptmod(void *a, void *b, void *c, void *d)
+{
+   LTC_ARGCHK(a != NULL);
+   LTC_ARGCHK(b != NULL);
+   LTC_ARGCHK(c != NULL);
+   LTC_ARGCHK(d != NULL);
+   return mpi_to_ltc_error(mp_exptmod(a,b,c,d));
+}
+
+static int isprime(void *a, int b, int *c)
+{
+   int err;
+   LTC_ARGCHK(a != NULL);
+   LTC_ARGCHK(c != NULL);
+   if (b == 0) {
+       b = LTC_MILLER_RABIN_REPS;
+   } /* if */
+   err = mpi_to_ltc_error(mp_prime_is_prime(a, b, c));
+   *c = (*c == MP_YES) ? LTC_MP_YES : LTC_MP_NO;
+   return err;
+}
+
+static int set_rand(void *a, int size)
+{
+   LTC_ARGCHK(a != NULL);
+   return mpi_to_ltc_error(mp_rand(a, size));
+}
+
+const ltc_math_descriptor ltm_desc = {
+
+   "LibTomMath",
+   (int)DIGIT_BIT,
+
+   &init,
+   &init_copy,
+   &deinit,
+
+   &neg,
+   &copy,
+
+   &set_int,
+   &get_int,
+   &get_digit,
+   &get_digit_count,
+   &compare,
+   &compare_d,
+   &count_bits,
+   &count_lsb_bits,
+   &twoexpt,
+
+   &read_radix,
+   &write_radix,
+   &unsigned_size,
+   &unsigned_write,
+   &unsigned_read,
+
+   &add,
+   &addi,
+   &sub,
+   &subi,
+   &mul,
+   &muli,
+   &sqr,
+   &divide,
+   &div_2,
+   &modi,
+   &gcd,
+   &lcm,
+
+   &mulmod,
+   &sqrmod,
+   &invmod,
+
+   &montgomery_setup,
+   &montgomery_normalization,
+   &montgomery_reduce,
+   &montgomery_deinit,
+
+   &exptmod,
+   &isprime,
+
+#ifdef LTC_MECC
+#ifdef LTC_MECC_FP
+   &ltc_ecc_fp_mulmod,
+#else
+   &ltc_ecc_mulmod,
+#endif
+   &ltc_ecc_projective_add_point,
+   &ltc_ecc_projective_dbl_point,
+   &ltc_ecc_map,
+#ifdef LTC_ECC_SHAMIR
+#ifdef LTC_MECC_FP
+   &ltc_ecc_fp_mul2add,
+#else
+   &ltc_ecc_mul2add,
+#endif /* LTC_MECC_FP */
+#else
+   NULL,
+#endif /* LTC_ECC_SHAMIR */
+#else
+   NULL, NULL, NULL, NULL, NULL,
+#endif /* LTC_MECC */
+
+#ifdef LTC_MRSA
+   &rsa_make_key,
+   &rsa_exptmod,
+#else
+   NULL, NULL,
+#endif
+   &addmod,
+   &submod,
+
+   &set_rand,
+
+};
+
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/math/multi.c b/libtomcrypt/src/math/multi.c
new file mode 100644 (file)
index 0000000..cfe1451
--- /dev/null
@@ -0,0 +1,76 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+#ifdef LTC_MPI
+#include <stdarg.h>
+
+int ltc_init_multi(void **a, ...)
+{
+   void    **cur = a;
+   int       np  = 0;
+   va_list   args;
+
+   va_start(args, a);
+   while (cur != NULL) {
+       if (mp_init(cur) != CRYPT_OK) {
+          /* failed */
+          va_list clean_list;
+
+          va_start(clean_list, a);
+          cur = a;
+          while (np--) {
+              mp_clear(*cur);
+              cur = va_arg(clean_list, void**);
+          }
+          va_end(clean_list);
+          va_end(args);
+          return CRYPT_MEM;
+       }
+       ++np;
+       cur = va_arg(args, void**);
+   }
+   va_end(args);
+   return CRYPT_OK;
+}
+
+void ltc_deinit_multi(void *a, ...)
+{
+   void     *cur = a;
+   va_list   args;
+
+   va_start(args, a);
+   while (cur != NULL) {
+       mp_clear(cur);
+       cur = va_arg(args, void *);
+   }
+   va_end(args);
+}
+
+void ltc_cleanup_multi(void **a, ...)
+{
+   void **cur = a;
+   va_list args;
+
+   va_start(args, a);
+   while (cur != NULL) {
+      if (*cur != NULL) {
+         mp_clear(*cur);
+         *cur = NULL;
+      }
+      cur = va_arg(args, void**);
+   }
+   va_end(args);
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/math/radix_to_bin.c b/libtomcrypt/src/math/radix_to_bin.c
new file mode 100644 (file)
index 0000000..409bd20
--- /dev/null
@@ -0,0 +1,62 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+   @file radix_to_bin.c
+   Convert data from a specific radix to binary.
+   Steffen Jaeckel
+*/
+
+/**
+   Convert data from a specific radix to binary
+
+      The default MPI descriptors #ltm_desc, #tfm_desc and #gmp_desc
+      have the following restrictions on parameters:
+
+        \p in    - NUL-terminated char buffer
+
+        \p radix - 2..64
+
+   @param in    The input
+   @param radix The radix of the input
+   @param out   The output buffer
+   @param len   [in/out] The length of the output buffer
+
+   @return CRYPT_OK on success.
+*/
+int radix_to_bin(const void *in, int radix, void *out, unsigned long *len)
+{
+   unsigned long l;
+   void* mpi;
+   int err;
+
+   LTC_ARGCHK(in  != NULL);
+   LTC_ARGCHK(len != NULL);
+
+   if ((err = mp_init(&mpi)) != CRYPT_OK) return err;
+   if ((err = mp_read_radix(mpi, in, radix)) != CRYPT_OK) goto LBL_ERR;
+
+   if ((l = mp_unsigned_bin_size(mpi)) > *len) {
+      *len = l;
+      err = CRYPT_BUFFER_OVERFLOW;
+      goto LBL_ERR;
+   }
+   *len = l;
+
+   if ((err = mp_to_unsigned_bin(mpi, out)) != CRYPT_OK) goto LBL_ERR;
+
+LBL_ERR:
+   mp_clear(mpi);
+   return err;
+}
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/math/rand_bn.c b/libtomcrypt/src/math/rand_bn.c
new file mode 100644 (file)
index 0000000..aa6539c
--- /dev/null
@@ -0,0 +1,75 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+#if defined(LTC_MDSA) || defined(LTC_MECC)
+/**
+  Generate a random number N with given bitlength (note: MSB can be 0)
+*/
+
+int rand_bn_bits(void *N, int bits, prng_state *prng, int wprng)
+{
+   int res, bytes;
+   unsigned char *buf, mask;
+
+   LTC_ARGCHK(N != NULL);
+   LTC_ARGCHK(bits > 1);
+
+   /* check PRNG */
+   if ((res = prng_is_valid(wprng)) != CRYPT_OK) return res;
+
+   bytes = (bits+7) >> 3;
+   mask = 0xff << (8 - bits % 8);
+
+   /* allocate buffer */
+   if ((buf = XCALLOC(1, bytes)) == NULL) return CRYPT_MEM;
+
+   /* generate random bytes */
+   if (prng_descriptor[wprng].read(buf, bytes, prng) != (unsigned long)bytes) {
+      res = CRYPT_ERROR_READPRNG;
+      goto cleanup;
+   }
+   /* mask bits */
+   buf[0] &= ~mask;
+   /* load value */
+   if ((res = mp_read_unsigned_bin(N, buf, bytes)) != CRYPT_OK) goto cleanup;
+
+   res = CRYPT_OK;
+
+cleanup:
+#ifdef LTC_CLEAN_STACK
+   zeromem(buf, bytes);
+#endif
+   XFREE(buf);
+   return res;
+}
+
+/**
+  Generate a random number N in a range: 1 <= N < limit
+*/
+int rand_bn_upto(void *N, void *limit, prng_state *prng, int wprng)
+{
+   int res, bits;
+
+   LTC_ARGCHK(N != NULL);
+   LTC_ARGCHK(limit != NULL);
+
+   bits = mp_count_bits(limit);
+   do {
+     res = rand_bn_bits(N, bits, prng, wprng);
+     if (res != CRYPT_OK) return res;
+   } while (mp_cmp_d(N, 0) != LTC_MP_GT || mp_cmp(N, limit) != LTC_MP_LT);
+
+   return CRYPT_OK;
+}
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/math/rand_prime.c b/libtomcrypt/src/math/rand_prime.c
new file mode 100644 (file)
index 0000000..4dd5764
--- /dev/null
@@ -0,0 +1,88 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+#if defined(LTC_MRSA) || (!defined(LTC_NO_MATH) && !defined(LTC_NO_PRNGS))
+
+/**
+  @file rand_prime.c
+  Generate a random prime, Tom St Denis
+*/
+
+#define USE_BBS 1
+
+int rand_prime(void *N, long len, prng_state *prng, int wprng)
+{
+   int            err, res, type;
+   unsigned char *buf;
+
+   LTC_ARGCHK(N != NULL);
+
+   /* get type */
+   if (len < 0) {
+      type = USE_BBS;
+      len = -len;
+   } else {
+      type = 0;
+   }
+
+   /* allow sizes between 2 and 512 bytes for a prime size */
+   if (len < 2 || len > 512) {
+      return CRYPT_INVALID_PRIME_SIZE;
+   }
+
+   /* valid PRNG? Better be! */
+   if ((err = prng_is_valid(wprng)) != CRYPT_OK) {
+      return err;
+   }
+
+   /* allocate buffer to work with */
+   buf = XCALLOC(1, len);
+   if (buf == NULL) {
+       return CRYPT_MEM;
+   }
+
+   do {
+      /* generate value */
+      if (prng_descriptor[wprng].read(buf, len, prng) != (unsigned long)len) {
+         XFREE(buf);
+         return CRYPT_ERROR_READPRNG;
+      }
+
+      /* munge bits */
+      buf[0]     |= 0x80 | 0x40;
+      buf[len-1] |= 0x01 | ((type & USE_BBS) ? 0x02 : 0x00);
+
+      /* load value */
+      if ((err = mp_read_unsigned_bin(N, buf, len)) != CRYPT_OK) {
+         XFREE(buf);
+         return err;
+      }
+
+      /* test */
+      if ((err = mp_prime_is_prime(N, LTC_MILLER_RABIN_REPS, &res)) != CRYPT_OK) {
+         XFREE(buf);
+         return err;
+      }
+   } while (res == LTC_MP_NO);
+
+#ifdef LTC_CLEAN_STACK
+   zeromem(buf, len);
+#endif
+
+   XFREE(buf);
+   return CRYPT_OK;
+}
+
+#endif /* LTC_NO_MATH */
+
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/math/tfm_desc.c b/libtomcrypt/src/math/tfm_desc.c
new file mode 100644 (file)
index 0000000..2a5a57d
--- /dev/null
@@ -0,0 +1,807 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+#define DESC_DEF_ONLY
+#include "tomcrypt.h"
+
+#ifdef TFM_DESC
+
+#include <tfm.h>
+
+static const struct {
+    int tfm_code, ltc_code;
+} tfm_to_ltc_codes[] = {
+   { FP_OKAY ,  CRYPT_OK},
+   { FP_MEM  ,  CRYPT_MEM},
+   { FP_VAL  ,  CRYPT_INVALID_ARG},
+};
+
+/**
+   Convert a tfm error to a LTC error (Possibly the most powerful function ever!  Oh wait... no)
+   @param err    The error to convert
+   @return The equivalent LTC error code or CRYPT_ERROR if none found
+*/
+static int tfm_to_ltc_error(int err)
+{
+   int x;
+
+   for (x = 0; x < (int)(sizeof(tfm_to_ltc_codes)/sizeof(tfm_to_ltc_codes[0])); x++) {
+       if (err == tfm_to_ltc_codes[x].tfm_code) {
+          return tfm_to_ltc_codes[x].ltc_code;
+       }
+   }
+   return CRYPT_ERROR;
+}
+
+static int init(void **a)
+{
+   LTC_ARGCHK(a != NULL);
+
+   *a = XCALLOC(1, sizeof(fp_int));
+   if (*a == NULL) {
+      return CRYPT_MEM;
+   }
+   fp_init(*a);
+   return CRYPT_OK;
+}
+
+static void deinit(void *a)
+{
+   LTC_ARGCHKVD(a != NULL);
+   XFREE(a);
+}
+
+static int neg(void *a, void *b)
+{
+   LTC_ARGCHK(a != NULL);
+   LTC_ARGCHK(b != NULL);
+   fp_neg(((fp_int*)a), ((fp_int*)b));
+   return CRYPT_OK;
+}
+
+static int copy(void *a, void *b)
+{
+   LTC_ARGCHK(a != NULL);
+   LTC_ARGCHK(b != NULL);
+   fp_copy(a, b);
+   return CRYPT_OK;
+}
+
+static int init_copy(void **a, void *b)
+{
+   if (init(a) != CRYPT_OK) {
+      return CRYPT_MEM;
+   }
+   return copy(b, *a);
+}
+
+/* ---- trivial ---- */
+static int set_int(void *a, ltc_mp_digit b)
+{
+   LTC_ARGCHK(a != NULL);
+   fp_set(a, b);
+   return CRYPT_OK;
+}
+
+static unsigned long get_int(void *a)
+{
+   fp_int *A;
+   LTC_ARGCHK(a != NULL);
+   A = a;
+   return A->used > 0 ? A->dp[0] : 0;
+}
+
+static ltc_mp_digit get_digit(void *a, int n)
+{
+   fp_int *A;
+   LTC_ARGCHK(a != NULL);
+   A = a;
+   return (n >= A->used || n < 0) ? 0 : A->dp[n];
+}
+
+static int get_digit_count(void *a)
+{
+   fp_int *A;
+   LTC_ARGCHK(a != NULL);
+   A = a;
+   return A->used;
+}
+
+static int compare(void *a, void *b)
+{
+   int ret;
+   LTC_ARGCHK(a != NULL);
+   LTC_ARGCHK(b != NULL);
+   ret = fp_cmp(a, b);
+   switch (ret) {
+      case FP_LT: return LTC_MP_LT;
+      case FP_EQ: return LTC_MP_EQ;
+      case FP_GT: return LTC_MP_GT;
+   }
+   return 0;
+}
+
+static int compare_d(void *a, ltc_mp_digit b)
+{
+   int ret;
+   LTC_ARGCHK(a != NULL);
+   ret = fp_cmp_d(a, b);
+   switch (ret) {
+      case FP_LT: return LTC_MP_LT;
+      case FP_EQ: return LTC_MP_EQ;
+      case FP_GT: return LTC_MP_GT;
+   }
+   return 0;
+}
+
+static int count_bits(void *a)
+{
+   LTC_ARGCHK(a != NULL);
+   return fp_count_bits(a);
+}
+
+static int count_lsb_bits(void *a)
+{
+   LTC_ARGCHK(a != NULL);
+   return fp_cnt_lsb(a);
+}
+
+static int twoexpt(void *a, int n)
+{
+   LTC_ARGCHK(a != NULL);
+   fp_2expt(a, n);
+   return CRYPT_OK;
+}
+
+/* ---- conversions ---- */
+
+/* read ascii string */
+static int read_radix(void *a, const char *b, int radix)
+{
+   LTC_ARGCHK(a != NULL);
+   LTC_ARGCHK(b != NULL);
+   return tfm_to_ltc_error(fp_read_radix(a, (char *)b, radix));
+}
+
+/* write one */
+static int write_radix(void *a, char *b, int radix)
+{
+   LTC_ARGCHK(a != NULL);
+   LTC_ARGCHK(b != NULL);
+   return tfm_to_ltc_error(fp_toradix(a, b, radix));
+}
+
+/* get size as unsigned char string */
+static unsigned long unsigned_size(void *a)
+{
+   LTC_ARGCHK(a != NULL);
+   return fp_unsigned_bin_size(a);
+}
+
+/* store */
+static int unsigned_write(void *a, unsigned char *b)
+{
+   LTC_ARGCHK(a != NULL);
+   LTC_ARGCHK(b != NULL);
+   fp_to_unsigned_bin(a, b);
+   return CRYPT_OK;
+}
+
+/* read */
+static int unsigned_read(void *a, unsigned char *b, unsigned long len)
+{
+   LTC_ARGCHK(a != NULL);
+   LTC_ARGCHK(b != NULL);
+   fp_read_unsigned_bin(a, b, len);
+   return CRYPT_OK;
+}
+
+/* add */
+static int add(void *a, void *b, void *c)
+{
+   LTC_ARGCHK(a != NULL);
+   LTC_ARGCHK(b != NULL);
+   LTC_ARGCHK(c != NULL);
+   fp_add(a, b, c);
+   return CRYPT_OK;
+}
+
+static int addi(void *a, ltc_mp_digit b, void *c)
+{
+   LTC_ARGCHK(a != NULL);
+   LTC_ARGCHK(c != NULL);
+   fp_add_d(a, b, c);
+   return CRYPT_OK;
+}
+
+/* sub */
+static int sub(void *a, void *b, void *c)
+{
+   LTC_ARGCHK(a != NULL);
+   LTC_ARGCHK(b != NULL);
+   LTC_ARGCHK(c != NULL);
+   fp_sub(a, b, c);
+   return CRYPT_OK;
+}
+
+static int subi(void *a, ltc_mp_digit b, void *c)
+{
+   LTC_ARGCHK(a != NULL);
+   LTC_ARGCHK(c != NULL);
+   fp_sub_d(a, b, c);
+   return CRYPT_OK;
+}
+
+/* mul */
+static int mul(void *a, void *b, void *c)
+{
+   LTC_ARGCHK(a != NULL);
+   LTC_ARGCHK(b != NULL);
+   LTC_ARGCHK(c != NULL);
+   fp_mul(a, b, c);
+   return CRYPT_OK;
+}
+
+static int muli(void *a, ltc_mp_digit b, void *c)
+{
+   LTC_ARGCHK(a != NULL);
+   LTC_ARGCHK(c != NULL);
+   fp_mul_d(a, b, c);
+   return CRYPT_OK;
+}
+
+/* sqr */
+static int sqr(void *a, void *b)
+{
+   LTC_ARGCHK(a != NULL);
+   LTC_ARGCHK(b != NULL);
+   fp_sqr(a, b);
+   return CRYPT_OK;
+}
+
+/* div */
+static int divide(void *a, void *b, void *c, void *d)
+{
+   LTC_ARGCHK(a != NULL);
+   LTC_ARGCHK(b != NULL);
+   return tfm_to_ltc_error(fp_div(a, b, c, d));
+}
+
+static int div_2(void *a, void *b)
+{
+   LTC_ARGCHK(a != NULL);
+   LTC_ARGCHK(b != NULL);
+   fp_div_2(a, b);
+   return CRYPT_OK;
+}
+
+/* modi */
+static int modi(void *a, ltc_mp_digit b, ltc_mp_digit *c)
+{
+   fp_digit tmp;
+   int      err;
+
+   LTC_ARGCHK(a != NULL);
+   LTC_ARGCHK(c != NULL);
+
+   if ((err = tfm_to_ltc_error(fp_mod_d(a, b, &tmp))) != CRYPT_OK) {
+      return err;
+   }
+   *c = tmp;
+   return CRYPT_OK;
+}
+
+/* gcd */
+static int gcd(void *a, void *b, void *c)
+{
+   LTC_ARGCHK(a != NULL);
+   LTC_ARGCHK(b != NULL);
+   LTC_ARGCHK(c != NULL);
+   fp_gcd(a, b, c);
+   return CRYPT_OK;
+}
+
+/* lcm */
+static int lcm(void *a, void *b, void *c)
+{
+   LTC_ARGCHK(a != NULL);
+   LTC_ARGCHK(b != NULL);
+   LTC_ARGCHK(c != NULL);
+   fp_lcm(a, b, c);
+   return CRYPT_OK;
+}
+
+static int addmod(void *a, void *b, void *c, void *d)
+{
+   LTC_ARGCHK(a != NULL);
+   LTC_ARGCHK(b != NULL);
+   LTC_ARGCHK(c != NULL);
+   LTC_ARGCHK(d != NULL);
+   return tfm_to_ltc_error(fp_addmod(a,b,c,d));
+}
+
+static int submod(void *a, void *b, void *c, void *d)
+{
+   LTC_ARGCHK(a != NULL);
+   LTC_ARGCHK(b != NULL);
+   LTC_ARGCHK(c != NULL);
+   LTC_ARGCHK(d != NULL);
+   return tfm_to_ltc_error(fp_submod(a,b,c,d));
+}
+
+static int mulmod(void *a, void *b, void *c, void *d)
+{
+   LTC_ARGCHK(a != NULL);
+   LTC_ARGCHK(b != NULL);
+   LTC_ARGCHK(c != NULL);
+   LTC_ARGCHK(d != NULL);
+   return tfm_to_ltc_error(fp_mulmod(a,b,c,d));
+}
+
+static int sqrmod(void *a, void *b, void *c)
+{
+   LTC_ARGCHK(a != NULL);
+   LTC_ARGCHK(b != NULL);
+   LTC_ARGCHK(c != NULL);
+   return tfm_to_ltc_error(fp_sqrmod(a,b,c));
+}
+
+/* invmod */
+static int invmod(void *a, void *b, void *c)
+{
+   LTC_ARGCHK(a != NULL);
+   LTC_ARGCHK(b != NULL);
+   LTC_ARGCHK(c != NULL);
+   return tfm_to_ltc_error(fp_invmod(a, b, c));
+}
+
+/* setup */
+static int montgomery_setup(void *a, void **b)
+{
+   int err;
+   LTC_ARGCHK(a != NULL);
+   LTC_ARGCHK(b != NULL);
+   *b = XCALLOC(1, sizeof(fp_digit));
+   if (*b == NULL) {
+      return CRYPT_MEM;
+   }
+   if ((err = tfm_to_ltc_error(fp_montgomery_setup(a, (fp_digit *)*b))) != CRYPT_OK) {
+      XFREE(*b);
+   }
+   return err;
+}
+
+/* get normalization value */
+static int montgomery_normalization(void *a, void *b)
+{
+   LTC_ARGCHK(a != NULL);
+   LTC_ARGCHK(b != NULL);
+   fp_montgomery_calc_normalization(a, b);
+   return CRYPT_OK;
+}
+
+/* reduce */
+static int montgomery_reduce(void *a, void *b, void *c)
+{
+   LTC_ARGCHK(a != NULL);
+   LTC_ARGCHK(b != NULL);
+   LTC_ARGCHK(c != NULL);
+   fp_montgomery_reduce(a, b, *((fp_digit *)c));
+   return CRYPT_OK;
+}
+
+/* clean up */
+static void montgomery_deinit(void *a)
+{
+   XFREE(a);
+}
+
+static int exptmod(void *a, void *b, void *c, void *d)
+{
+   LTC_ARGCHK(a != NULL);
+   LTC_ARGCHK(b != NULL);
+   LTC_ARGCHK(c != NULL);
+   LTC_ARGCHK(d != NULL);
+   return tfm_to_ltc_error(fp_exptmod(a,b,c,d));
+}
+
+static int isprime(void *a, int b, int *c)
+{
+   LTC_ARGCHK(a != NULL);
+   LTC_ARGCHK(c != NULL);
+   if (b == 0) {
+       b = LTC_MILLER_RABIN_REPS;
+   } /* if */
+   *c = (fp_isprime_ex(a, b) == FP_YES) ? LTC_MP_YES : LTC_MP_NO;
+   return CRYPT_OK;
+}
+
+#if defined(LTC_MECC) && defined(LTC_MECC_ACCEL)
+
+static int tfm_ecc_projective_dbl_point(ecc_point *P, ecc_point *R, void *modulus, void *Mp)
+{
+   fp_int t1, t2;
+   fp_digit mp;
+
+   LTC_ARGCHK(P       != NULL);
+   LTC_ARGCHK(R       != NULL);
+   LTC_ARGCHK(modulus != NULL);
+   LTC_ARGCHK(Mp      != NULL);
+
+   mp = *((fp_digit*)Mp);
+
+   fp_init(&t1);
+   fp_init(&t2);
+
+   if (P != R) {
+      fp_copy(P->x, R->x);
+      fp_copy(P->y, R->y);
+      fp_copy(P->z, R->z);
+   }
+
+   /* t1 = Z * Z */
+   fp_sqr(R->z, &t1);
+   fp_montgomery_reduce(&t1, modulus, mp);
+   /* Z = Y * Z */
+   fp_mul(R->z, R->y, R->z);
+   fp_montgomery_reduce(R->z, modulus, mp);
+   /* Z = 2Z */
+   fp_add(R->z, R->z, R->z);
+   if (fp_cmp(R->z, modulus) != FP_LT) {
+      fp_sub(R->z, modulus, R->z);
+   }
+
+   /* &t2 = X - T1 */
+   fp_sub(R->x, &t1, &t2);
+   if (fp_cmp_d(&t2, 0) == FP_LT) {
+      fp_add(&t2, modulus, &t2);
+   }
+   /* T1 = X + T1 */
+   fp_add(&t1, R->x, &t1);
+   if (fp_cmp(&t1, modulus) != FP_LT) {
+      fp_sub(&t1, modulus, &t1);
+   }
+   /* T2 = T1 * T2 */
+   fp_mul(&t1, &t2, &t2);
+   fp_montgomery_reduce(&t2, modulus, mp);
+   /* T1 = 2T2 */
+   fp_add(&t2, &t2, &t1);
+   if (fp_cmp(&t1, modulus) != FP_LT) {
+      fp_sub(&t1, modulus, &t1);
+   }
+   /* T1 = T1 + T2 */
+   fp_add(&t1, &t2, &t1);
+   if (fp_cmp(&t1, modulus) != FP_LT) {
+      fp_sub(&t1, modulus, &t1);
+   }
+
+   /* Y = 2Y */
+   fp_add(R->y, R->y, R->y);
+   if (fp_cmp(R->y, modulus) != FP_LT) {
+      fp_sub(R->y, modulus, R->y);
+   }
+   /* Y = Y * Y */
+   fp_sqr(R->y, R->y);
+   fp_montgomery_reduce(R->y, modulus, mp);
+   /* T2 = Y * Y */
+   fp_sqr(R->y, &t2);
+   fp_montgomery_reduce(&t2, modulus, mp);
+   /* T2 = T2/2 */
+   if (fp_isodd(&t2)) {
+      fp_add(&t2, modulus, &t2);
+   }
+   fp_div_2(&t2, &t2);
+   /* Y = Y * X */
+   fp_mul(R->y, R->x, R->y);
+   fp_montgomery_reduce(R->y, modulus, mp);
+
+   /* X  = T1 * T1 */
+   fp_sqr(&t1, R->x);
+   fp_montgomery_reduce(R->x, modulus, mp);
+   /* X = X - Y */
+   fp_sub(R->x, R->y, R->x);
+   if (fp_cmp_d(R->x, 0) == FP_LT) {
+      fp_add(R->x, modulus, R->x);
+   }
+   /* X = X - Y */
+   fp_sub(R->x, R->y, R->x);
+   if (fp_cmp_d(R->x, 0) == FP_LT) {
+      fp_add(R->x, modulus, R->x);
+   }
+
+   /* Y = Y - X */
+   fp_sub(R->y, R->x, R->y);
+   if (fp_cmp_d(R->y, 0) == FP_LT) {
+      fp_add(R->y, modulus, R->y);
+   }
+   /* Y = Y * T1 */
+   fp_mul(R->y, &t1, R->y);
+   fp_montgomery_reduce(R->y, modulus, mp);
+   /* Y = Y - T2 */
+   fp_sub(R->y, &t2, R->y);
+   if (fp_cmp_d(R->y, 0) == FP_LT) {
+      fp_add(R->y, modulus, R->y);
+   }
+
+   return CRYPT_OK;
+}
+
+/**
+   Add two ECC points
+   @param P        The point to add
+   @param Q        The point to add
+   @param R        [out] The destination of the double
+   @param modulus  The modulus of the field the ECC curve is in
+   @param Mp       The "b" value from montgomery_setup()
+   @return CRYPT_OK on success
+*/
+static int tfm_ecc_projective_add_point(ecc_point *P, ecc_point *Q, ecc_point *R, void *modulus, void *Mp)
+{
+   fp_int  t1, t2, x, y, z;
+   fp_digit mp;
+
+   LTC_ARGCHK(P       != NULL);
+   LTC_ARGCHK(Q       != NULL);
+   LTC_ARGCHK(R       != NULL);
+   LTC_ARGCHK(modulus != NULL);
+   LTC_ARGCHK(Mp      != NULL);
+
+   mp = *((fp_digit*)Mp);
+
+   fp_init(&t1);
+   fp_init(&t2);
+   fp_init(&x);
+   fp_init(&y);
+   fp_init(&z);
+
+   /* should we dbl instead? */
+   fp_sub(modulus, Q->y, &t1);
+   if ( (fp_cmp(P->x, Q->x) == FP_EQ) &&
+        (Q->z != NULL && fp_cmp(P->z, Q->z) == FP_EQ) &&
+        (fp_cmp(P->y, Q->y) == FP_EQ || fp_cmp(P->y, &t1) == FP_EQ)) {
+        return tfm_ecc_projective_dbl_point(P, R, modulus, Mp);
+   }
+
+   fp_copy(P->x, &x);
+   fp_copy(P->y, &y);
+   fp_copy(P->z, &z);
+
+   /* if Z is one then these are no-operations */
+   if (Q->z != NULL) {
+      /* T1 = Z' * Z' */
+      fp_sqr(Q->z, &t1);
+      fp_montgomery_reduce(&t1, modulus, mp);
+      /* X = X * T1 */
+      fp_mul(&t1, &x, &x);
+      fp_montgomery_reduce(&x, modulus, mp);
+      /* T1 = Z' * T1 */
+      fp_mul(Q->z, &t1, &t1);
+      fp_montgomery_reduce(&t1, modulus, mp);
+      /* Y = Y * T1 */
+      fp_mul(&t1, &y, &y);
+      fp_montgomery_reduce(&y, modulus, mp);
+   }
+
+   /* T1 = Z*Z */
+   fp_sqr(&z, &t1);
+   fp_montgomery_reduce(&t1, modulus, mp);
+   /* T2 = X' * T1 */
+   fp_mul(Q->x, &t1, &t2);
+   fp_montgomery_reduce(&t2, modulus, mp);
+   /* T1 = Z * T1 */
+   fp_mul(&z, &t1, &t1);
+   fp_montgomery_reduce(&t1, modulus, mp);
+   /* T1 = Y' * T1 */
+   fp_mul(Q->y, &t1, &t1);
+   fp_montgomery_reduce(&t1, modulus, mp);
+
+   /* Y = Y - T1 */
+   fp_sub(&y, &t1, &y);
+   if (fp_cmp_d(&y, 0) == FP_LT) {
+      fp_add(&y, modulus, &y);
+   }
+   /* T1 = 2T1 */
+   fp_add(&t1, &t1, &t1);
+   if (fp_cmp(&t1, modulus) != FP_LT) {
+      fp_sub(&t1, modulus, &t1);
+   }
+   /* T1 = Y + T1 */
+   fp_add(&t1, &y, &t1);
+   if (fp_cmp(&t1, modulus) != FP_LT) {
+      fp_sub(&t1, modulus, &t1);
+   }
+   /* X = X - T2 */
+   fp_sub(&x, &t2, &x);
+   if (fp_cmp_d(&x, 0) == FP_LT) {
+      fp_add(&x, modulus, &x);
+   }
+   /* T2 = 2T2 */
+   fp_add(&t2, &t2, &t2);
+   if (fp_cmp(&t2, modulus) != FP_LT) {
+      fp_sub(&t2, modulus, &t2);
+   }
+   /* T2 = X + T2 */
+   fp_add(&t2, &x, &t2);
+   if (fp_cmp(&t2, modulus) != FP_LT) {
+      fp_sub(&t2, modulus, &t2);
+   }
+
+   /* if Z' != 1 */
+   if (Q->z != NULL) {
+      /* Z = Z * Z' */
+      fp_mul(&z, Q->z, &z);
+      fp_montgomery_reduce(&z, modulus, mp);
+   }
+
+   /* Z = Z * X */
+   fp_mul(&z, &x, &z);
+   fp_montgomery_reduce(&z, modulus, mp);
+
+   /* T1 = T1 * X  */
+   fp_mul(&t1, &x, &t1);
+   fp_montgomery_reduce(&t1, modulus, mp);
+   /* X = X * X */
+   fp_sqr(&x, &x);
+   fp_montgomery_reduce(&x, modulus, mp);
+   /* T2 = T2 * x */
+   fp_mul(&t2, &x, &t2);
+   fp_montgomery_reduce(&t2, modulus, mp);
+   /* T1 = T1 * X  */
+   fp_mul(&t1, &x, &t1);
+   fp_montgomery_reduce(&t1, modulus, mp);
+
+   /* X = Y*Y */
+   fp_sqr(&y, &x);
+   fp_montgomery_reduce(&x, modulus, mp);
+   /* X = X - T2 */
+   fp_sub(&x, &t2, &x);
+   if (fp_cmp_d(&x, 0) == FP_LT) {
+      fp_add(&x, modulus, &x);
+   }
+
+   /* T2 = T2 - X */
+   fp_sub(&t2, &x, &t2);
+   if (fp_cmp_d(&t2, 0) == FP_LT) {
+      fp_add(&t2, modulus, &t2);
+   }
+   /* T2 = T2 - X */
+   fp_sub(&t2, &x, &t2);
+   if (fp_cmp_d(&t2, 0) == FP_LT) {
+      fp_add(&t2, modulus, &t2);
+   }
+   /* T2 = T2 * Y */
+   fp_mul(&t2, &y, &t2);
+   fp_montgomery_reduce(&t2, modulus, mp);
+   /* Y = T2 - T1 */
+   fp_sub(&t2, &t1, &y);
+   if (fp_cmp_d(&y, 0) == FP_LT) {
+      fp_add(&y, modulus, &y);
+   }
+   /* Y = Y/2 */
+   if (fp_isodd(&y)) {
+      fp_add(&y, modulus, &y);
+   }
+   fp_div_2(&y, &y);
+
+   fp_copy(&x, R->x);
+   fp_copy(&y, R->y);
+   fp_copy(&z, R->z);
+
+   return CRYPT_OK;
+}
+
+
+#endif
+
+static int set_rand(void *a, int size)
+{
+   LTC_ARGCHK(a != NULL);
+   fp_rand(a, size);
+   return CRYPT_OK;
+}
+
+const ltc_math_descriptor tfm_desc = {
+
+   "TomsFastMath",
+   (int)DIGIT_BIT,
+
+   &init,
+   &init_copy,
+   &deinit,
+
+   &neg,
+   &copy,
+
+   &set_int,
+   &get_int,
+   &get_digit,
+   &get_digit_count,
+   &compare,
+   &compare_d,
+   &count_bits,
+   &count_lsb_bits,
+   &twoexpt,
+
+   &read_radix,
+   &write_radix,
+   &unsigned_size,
+   &unsigned_write,
+   &unsigned_read,
+
+   &add,
+   &addi,
+   &sub,
+   &subi,
+   &mul,
+   &muli,
+   &sqr,
+   &divide,
+   &div_2,
+   &modi,
+   &gcd,
+   &lcm,
+
+   &mulmod,
+   &sqrmod,
+   &invmod,
+
+   &montgomery_setup,
+   &montgomery_normalization,
+   &montgomery_reduce,
+   &montgomery_deinit,
+
+   &exptmod,
+   &isprime,
+
+#ifdef LTC_MECC
+#ifdef LTC_MECC_FP
+   &ltc_ecc_fp_mulmod,
+#else
+   &ltc_ecc_mulmod,
+#endif /* LTC_MECC_FP */
+#ifdef LTC_MECC_ACCEL
+   &tfm_ecc_projective_add_point,
+   &tfm_ecc_projective_dbl_point,
+#else
+   &ltc_ecc_projective_add_point,
+   &ltc_ecc_projective_dbl_point,
+#endif /* LTC_MECC_ACCEL */
+   &ltc_ecc_map,
+#ifdef LTC_ECC_SHAMIR
+#ifdef LTC_MECC_FP
+   &ltc_ecc_fp_mul2add,
+#else
+   &ltc_ecc_mul2add,
+#endif /* LTC_MECC_FP */
+#else
+   NULL,
+#endif /* LTC_ECC_SHAMIR */
+#else
+   NULL, NULL, NULL, NULL, NULL,
+#endif /* LTC_MECC */
+
+#ifdef LTC_MRSA
+   &rsa_make_key,
+   &rsa_exptmod,
+#else
+   NULL, NULL,
+#endif
+   &addmod,
+   &submod,
+
+   set_rand,
+
+};
+
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/misc/adler32.c b/libtomcrypt/src/misc/adler32.c
new file mode 100644 (file)
index 0000000..8bbf2ac
--- /dev/null
@@ -0,0 +1,131 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+   @file adler32.c
+   Adler-32 checksum algorithm
+   Written and placed in the public domain by Wei Dai
+   Adapted for libtomcrypt by Steffen Jaeckel
+*/
+#ifdef LTC_ADLER32
+
+static const unsigned long _adler32_base = 65521;
+
+void adler32_init(adler32_state *ctx)
+{
+   LTC_ARGCHKVD(ctx != NULL);
+   ctx->s[0] = 1;
+   ctx->s[1] = 0;
+}
+
+void adler32_update(adler32_state *ctx, const unsigned char *input, unsigned long length)
+{
+   unsigned long s1, s2;
+
+   LTC_ARGCHKVD(ctx != NULL);
+   LTC_ARGCHKVD(input != NULL);
+   s1 = ctx->s[0];
+   s2 = ctx->s[1];
+
+   if (length % 8 != 0) {
+      do {
+         s1 += *input++;
+         s2 += s1;
+         length--;
+      } while (length % 8 != 0);
+
+      if (s1 >= _adler32_base)
+         s1 -= _adler32_base;
+      s2 %= _adler32_base;
+   }
+
+   while (length > 0) {
+      s1 += input[0];
+      s2 += s1;
+      s1 += input[1];
+      s2 += s1;
+      s1 += input[2];
+      s2 += s1;
+      s1 += input[3];
+      s2 += s1;
+      s1 += input[4];
+      s2 += s1;
+      s1 += input[5];
+      s2 += s1;
+      s1 += input[6];
+      s2 += s1;
+      s1 += input[7];
+      s2 += s1;
+
+      length -= 8;
+      input += 8;
+
+      if (s1 >= _adler32_base)
+         s1 -= _adler32_base;
+      s2 %= _adler32_base;
+   }
+
+   LTC_ARGCHKVD(s1 < _adler32_base);
+   LTC_ARGCHKVD(s2 < _adler32_base);
+
+   ctx->s[0] = (unsigned short)s1;
+   ctx->s[1] = (unsigned short)s2;
+}
+
+void adler32_finish(adler32_state *ctx, void *hash, unsigned long size)
+{
+   unsigned char* h;
+
+   LTC_ARGCHKVD(ctx != NULL);
+   LTC_ARGCHKVD(hash != NULL);
+
+   h = hash;
+
+   switch (size) {
+      default:
+         h[3] = ctx->s[0] & 0x0ff;
+         /* FALLTHROUGH */
+      case 3:
+         h[2] = (ctx->s[0] >> 8) & 0x0ff;
+         /* FALLTHROUGH */
+      case 2:
+         h[1] = ctx->s[1] & 0x0ff;
+         /* FALLTHROUGH */
+      case 1:
+         h[0] = (ctx->s[1] >> 8) & 0x0ff;
+         /* FALLTHROUGH */
+      case 0:
+         ;
+   }
+}
+
+int adler32_test(void)
+{
+#ifndef LTC_TEST
+   return CRYPT_NOP;
+#else
+   const void* in = "libtomcrypt";
+   const unsigned char adler32[] = { 0x1b, 0xe8, 0x04, 0xba };
+   unsigned char out[4];
+   adler32_state ctx;
+   adler32_init(&ctx);
+   adler32_update(&ctx, in, strlen(in));
+   adler32_finish(&ctx, out, 4);
+   if (compare_testvector(adler32, 4, out, 4, "adler32", 0)) {
+      return CRYPT_FAIL_TESTVECTOR;
+   }
+   return CRYPT_OK;
+#endif
+}
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/misc/base64/base64_decode.c b/libtomcrypt/src/misc/base64/base64_decode.c
new file mode 100644 (file)
index 0000000..4c58c68
--- /dev/null
@@ -0,0 +1,196 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file base64_decode.c
+  Compliant base64 code donated by Wayne Scott (wscott@bitmover.com)
+  base64 URL Safe variant (RFC 4648 section 5) by Karel Miko
+*/
+
+
+#if defined(LTC_BASE64) || defined (LTC_BASE64_URL)
+
+#if defined(LTC_BASE64)
+static const unsigned char map_base64[256] = {
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255,  62, 255, 255, 255,  63,
+ 52,  53,  54,  55,  56,  57,  58,  59,  60,  61, 255, 255,
+255, 254, 255, 255, 255,   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, 255, 255, 255, 255, 255,
+255,  26,  27,  28,  29,  30,  31,  32,  33,  34,  35,  36,
+ 37,  38,  39,  40,  41,  42,  43,  44,  45,  46,  47,  48,
+ 49,  50,  51, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255 };
+#endif /* LTC_BASE64 */
+
+static const unsigned char map_base64url[] = {
+#if defined(LTC_BASE64_URL)
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255, 255, 255,  62, 255, 255,
+ 52,  53,  54,  55,  56,  57,  58,  59,  60,  61, 255, 255,
+255, 254, 255, 255, 255,   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, 255, 255, 255, 255,  63,
+255,  26,  27,  28,  29,  30,  31,  32,  33,  34,  35,  36,
+ 37,  38,  39,  40,  41,  42,  43,  44,  45,  46,  47,  48,
+ 49,  50,  51, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255
+#endif /* LTC_BASE64_URL */
+};
+
+enum {
+   relaxed = 0,
+   strict = 1
+};
+
+static int _base64_decode_internal(const unsigned char *in,  unsigned long inlen,
+                                 unsigned char *out, unsigned long *outlen,
+                           const unsigned char *map, int is_strict)
+{
+   unsigned long t, x, y, z;
+   unsigned char c;
+   int           g;
+
+   LTC_ARGCHK(in     != NULL);
+   LTC_ARGCHK(out    != NULL);
+   LTC_ARGCHK(outlen != NULL);
+
+   g = 0; /* '=' counter */
+   for (x = y = z = t = 0; x < inlen; x++) {
+       c = map[in[x]&0xFF];
+       if (c == 254) {
+          g++;
+          continue;
+       }
+       else if (is_strict && g > 0) {
+          /* we only allow '=' to be at the end */
+          return CRYPT_INVALID_PACKET;
+       }
+       if (c == 255) {
+          if (is_strict)
+             return CRYPT_INVALID_PACKET;
+          else
+             continue;
+       }
+
+       t = (t<<6)|c;
+
+       if (++y == 4) {
+          if (z + 3 > *outlen) return CRYPT_BUFFER_OVERFLOW;
+          out[z++] = (unsigned char)((t>>16)&255);
+          out[z++] = (unsigned char)((t>>8)&255);
+          out[z++] = (unsigned char)(t&255);
+          y = t = 0;
+       }
+   }
+
+   if (y != 0) {
+      if (y == 1) return CRYPT_INVALID_PACKET;
+      if ((y + g) != 4 && is_strict && map != map_base64url) return CRYPT_INVALID_PACKET;
+      t = t << (6 * (4 - y));
+      if (z + y - 1 > *outlen) return CRYPT_BUFFER_OVERFLOW;
+      if (y >= 2) out[z++] = (unsigned char) ((t >> 16) & 255);
+      if (y == 3) out[z++] = (unsigned char) ((t >> 8) & 255);
+   }
+   *outlen = z;
+   return CRYPT_OK;
+}
+
+#if defined(LTC_BASE64)
+/**
+   Relaxed base64 decode a block of memory
+   @param in       The base64 data to decode
+   @param inlen    The length of the base64 data
+   @param out      [out] The destination of the binary decoded data
+   @param outlen   [in/out] The max size and resulting size of the decoded data
+   @return CRYPT_OK if successful
+*/
+int base64_decode(const unsigned char *in,  unsigned long inlen,
+                        unsigned char *out, unsigned long *outlen)
+{
+    return _base64_decode_internal(in, inlen, out, outlen, map_base64, relaxed);
+}
+
+/**
+   Strict base64 decode a block of memory
+   @param in       The base64 data to decode
+   @param inlen    The length of the base64 data
+   @param out      [out] The destination of the binary decoded data
+   @param outlen   [in/out] The max size and resulting size of the decoded data
+   @return CRYPT_OK if successful
+*/
+int base64_strict_decode(const unsigned char *in,  unsigned long inlen,
+                        unsigned char *out, unsigned long *outlen)
+{
+   return _base64_decode_internal(in, inlen, out, outlen, map_base64, strict);
+}
+#endif /* LTC_BASE64 */
+
+#if defined(LTC_BASE64_URL)
+/**
+   Relaxed base64 (URL Safe, RFC 4648 section 5) decode a block of memory
+   @param in       The base64 data to decode
+   @param inlen    The length of the base64 data
+   @param out      [out] The destination of the binary decoded data
+   @param outlen   [in/out] The max size and resulting size of the decoded data
+   @return CRYPT_OK if successful
+*/
+int base64url_decode(const unsigned char *in,  unsigned long inlen,
+                           unsigned char *out, unsigned long *outlen)
+{
+    return _base64_decode_internal(in, inlen, out, outlen, map_base64url, relaxed);
+}
+
+/**
+   Strict base64 (URL Safe, RFC 4648 section 5) decode a block of memory
+   @param in       The base64 data to decode
+   @param inlen    The length of the base64 data
+   @param out      [out] The destination of the binary decoded data
+   @param outlen   [in/out] The max size and resulting size of the decoded data
+   @return CRYPT_OK if successful
+*/
+int base64url_strict_decode(const unsigned char *in,  unsigned long inlen,
+                           unsigned char *out, unsigned long *outlen)
+{
+    return _base64_decode_internal(in, inlen, out, outlen, map_base64url, strict);
+}
+#endif /* LTC_BASE64_URL */
+
+#endif
+
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/misc/base64/base64_encode.c b/libtomcrypt/src/misc/base64/base64_encode.c
new file mode 100644 (file)
index 0000000..5c26e60
--- /dev/null
@@ -0,0 +1,124 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file base64_encode.c
+  Compliant base64 encoder donated by Wayne Scott (wscott@bitmover.com)
+  base64 URL Safe variant (RFC 4648 section 5) by Karel Miko
+*/
+
+
+#if defined(LTC_BASE64) || defined (LTC_BASE64_URL)
+
+#if defined(LTC_BASE64)
+static const char * const codes_base64 =
+"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+#endif /* LTC_BASE64 */
+
+#if defined(LTC_BASE64_URL)
+static const char * const codes_base64url =
+"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
+#endif /* LTC_BASE64_URL */
+
+static int _base64_encode_internal(const unsigned char *in,  unsigned long inlen,
+                                 unsigned char *out, unsigned long *outlen,
+                                 const char *codes, int pad)
+{
+   unsigned long i, len2, leven;
+   unsigned char *p;
+
+   LTC_ARGCHK(in     != NULL);
+   LTC_ARGCHK(out    != NULL);
+   LTC_ARGCHK(outlen != NULL);
+
+   /* valid output size ? */
+   len2 = 4 * ((inlen + 2) / 3);
+   if (*outlen < len2 + 1) {
+      *outlen = len2 + 1;
+      return CRYPT_BUFFER_OVERFLOW;
+   }
+   p = out;
+   leven = 3*(inlen / 3);
+   for (i = 0; i < leven; i += 3) {
+       *p++ = codes[(in[0] >> 2) & 0x3F];
+       *p++ = codes[(((in[0] & 3) << 4) + (in[1] >> 4)) & 0x3F];
+       *p++ = codes[(((in[1] & 0xf) << 2) + (in[2] >> 6)) & 0x3F];
+       *p++ = codes[in[2] & 0x3F];
+       in += 3;
+   }
+   /* Pad it if necessary...  */
+   if (i < inlen) {
+       unsigned a = in[0];
+       unsigned b = (i+1 < inlen) ? in[1] : 0;
+
+       *p++ = codes[(a >> 2) & 0x3F];
+       *p++ = codes[(((a & 3) << 4) + (b >> 4)) & 0x3F];
+       if (pad) {
+         *p++ = (i+1 < inlen) ? codes[(((b & 0xf) << 2)) & 0x3F] : '=';
+         *p++ = '=';
+       }
+       else {
+         if (i+1 < inlen) *p++ = codes[(((b & 0xf) << 2)) & 0x3F];
+       }
+   }
+
+   /* append a NULL byte */
+   *p = '\0';
+
+   /* return ok */
+   *outlen = (unsigned long)(p - out);
+   return CRYPT_OK;
+}
+
+#if defined(LTC_BASE64)
+/**
+   base64 Encode a buffer (NUL terminated)
+   @param in      The input buffer to encode
+   @param inlen   The length of the input buffer
+   @param out     [out] The destination of the base64 encoded data
+   @param outlen  [in/out] The max size and resulting size
+   @return CRYPT_OK if successful
+*/
+int base64_encode(const unsigned char *in,  unsigned long inlen,
+                        unsigned char *out, unsigned long *outlen)
+{
+    return _base64_encode_internal(in, inlen, out, outlen, codes_base64, 1);
+}
+#endif /* LTC_BASE64 */
+
+
+#if defined(LTC_BASE64_URL)
+/**
+   base64 (URL Safe, RFC 4648 section 5) Encode a buffer (NUL terminated)
+   @param in      The input buffer to encode
+   @param inlen   The length of the input buffer
+   @param out     [out] The destination of the base64 encoded data
+   @param outlen  [in/out] The max size and resulting size
+   @return CRYPT_OK if successful
+*/
+int base64url_encode(const unsigned char *in,  unsigned long inlen,
+                           unsigned char *out, unsigned long *outlen)
+{
+    return _base64_encode_internal(in, inlen, out, outlen, codes_base64url, 0);
+}
+
+int base64url_strict_encode(const unsigned char *in,  unsigned long inlen,
+                           unsigned char *out, unsigned long *outlen)
+{
+    return _base64_encode_internal(in, inlen, out, outlen, codes_base64url, 1);
+}
+#endif /* LTC_BASE64_URL */
+
+#endif
+
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/misc/burn_stack.c b/libtomcrypt/src/misc/burn_stack.c
new file mode 100644 (file)
index 0000000..afbafee
--- /dev/null
@@ -0,0 +1,32 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+   @file burn_stack.c
+   Burn stack, Tom St Denis
+*/
+
+/**
+   Burn some stack memory
+   @param len amount of stack to burn in bytes
+*/
+void burn_stack(unsigned long len)
+{
+   unsigned char buf[32];
+   zeromem(buf, sizeof(buf));
+   if (len > (unsigned long)sizeof(buf))
+      burn_stack(len - sizeof(buf));
+}
+
+
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/misc/compare_testvector.c b/libtomcrypt/src/misc/compare_testvector.c
new file mode 100644 (file)
index 0000000..82433c6
--- /dev/null
@@ -0,0 +1,87 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+#include "tomcrypt.h"
+
+/**
+  @file compare_testvector.c
+  Function to compare two testvectors and print a (detailed) error-message if required, Steffen Jaeckel
+*/
+
+#if defined(LTC_TEST) && defined(LTC_TEST_DBG)
+static void _print_hex(const char* what, const void* v, const unsigned long l)
+{
+  const unsigned char* p = v;
+  unsigned long x, y = 0, z;
+  fprintf(stderr, "%s contents: \n", what);
+  for (x = 0; x < l; ) {
+      fprintf(stderr, "%02X ", p[x]);
+      if (!(++x % 16) || x == l) {
+         if((x % 16) != 0) {
+            z = 16 - (x % 16);
+            if(z >= 8)
+               fprintf(stderr, " ");
+            for (; z != 0; --z) {
+               fprintf(stderr, "   ");
+            }
+         }
+         fprintf(stderr, " | ");
+         for(; y < x; y++) {
+            if((y % 8) == 0)
+               fprintf(stderr, " ");
+            if(isgraph(p[y]))
+               fprintf(stderr, "%c", p[y]);
+            else
+               fprintf(stderr, ".");
+         }
+         fprintf(stderr, "\n");
+      }
+      else if((x % 8) == 0) {
+         fprintf(stderr, " ");
+      }
+  }
+}
+#endif
+
+/**
+  Compare two test-vectors
+
+  @param is             The data as it is
+  @param is_len         The length of is
+  @param should         The data as it should
+  @param should_len     The length of should
+  @param what           The type of the data
+  @param which          The iteration count
+  @return 0 on equality, -1 or 1 on difference
+*/
+int compare_testvector(const void* is, const unsigned long is_len, const void* should, const unsigned long should_len, const char* what, int which)
+{
+   int res = 0;
+   if(is_len != should_len)
+      res = is_len > should_len ? -1 : 1;
+   else
+      res = XMEMCMP(is, should, is_len);
+
+#if defined(LTC_TEST) && defined(LTC_TEST_DBG)
+   if (res != 0) {
+      fprintf(stderr, "Testvector #%i of %s failed:\n", which, what);
+      _print_hex("SHOULD", should, should_len);
+      _print_hex("IS    ", is, is_len);
+   }
+#else
+   LTC_UNUSED_PARAM(which);
+   LTC_UNUSED_PARAM(what);
+#endif
+
+   return res;
+}
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/misc/crc32.c b/libtomcrypt/src/misc/crc32.c
new file mode 100644 (file)
index 0000000..beb54fc
--- /dev/null
@@ -0,0 +1,202 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+   @file crc32.c
+   CRC-32 checksum algorithm
+   Written and placed in the public domain by Wei Dai
+   Adapted for libtomcrypt by Steffen Jaeckel
+*/
+#ifdef LTC_CRC32
+
+static const ulong32 _CRC32_NEGL = 0xffffffffUL;
+
+#if defined(ENDIAN_LITTLE)
+#define CRC32_INDEX(c) (c & 0xff)
+#define CRC32_SHIFTED(c) (c >> 8)
+#elif defined(ENDIAN_BIG)
+#define CRC32_INDEX(c) (c >> 24)
+#define CRC32_SHIFTED(c) (c << 8)
+#else
+#error The existing CRC32 implementation only works properly when the endianness of the target platform is known.
+#endif
+
+/* Table of CRC-32's of all single byte values (made by makecrc.c) */
+static const ulong32 crc32_m_tab[] =
+{
+#if defined(ENDIAN_LITTLE)
+      0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
+      0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
+      0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
+      0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
+      0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
+      0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
+      0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
+      0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
+      0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
+      0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
+      0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
+      0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
+      0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
+      0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
+      0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
+      0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
+      0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
+      0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
+      0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
+      0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
+      0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
+      0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
+      0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
+      0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
+      0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
+      0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
+      0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
+      0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
+      0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
+      0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
+      0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
+      0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
+      0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
+      0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
+      0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
+      0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
+      0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
+      0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
+      0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
+      0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
+      0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
+      0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
+      0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
+      0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
+      0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
+      0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
+      0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
+      0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
+      0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
+      0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
+      0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
+      0x2d02ef8dL
+#else
+      0x00000000L, 0x96300777L, 0x2c610eeeL, 0xba510999L, 0x19c46d07L,
+      0x8ff46a70L, 0x35a563e9L, 0xa395649eL, 0x3288db0eL, 0xa4b8dc79L,
+      0x1ee9d5e0L, 0x88d9d297L, 0x2b4cb609L, 0xbd7cb17eL, 0x072db8e7L,
+      0x911dbf90L, 0x6410b71dL, 0xf220b06aL, 0x4871b9f3L, 0xde41be84L,
+      0x7dd4da1aL, 0xebe4dd6dL, 0x51b5d4f4L, 0xc785d383L, 0x56986c13L,
+      0xc0a86b64L, 0x7af962fdL, 0xecc9658aL, 0x4f5c0114L, 0xd96c0663L,
+      0x633d0ffaL, 0xf50d088dL, 0xc8206e3bL, 0x5e10694cL, 0xe44160d5L,
+      0x727167a2L, 0xd1e4033cL, 0x47d4044bL, 0xfd850dd2L, 0x6bb50aa5L,
+      0xfaa8b535L, 0x6c98b242L, 0xd6c9bbdbL, 0x40f9bcacL, 0xe36cd832L,
+      0x755cdf45L, 0xcf0dd6dcL, 0x593dd1abL, 0xac30d926L, 0x3a00de51L,
+      0x8051d7c8L, 0x1661d0bfL, 0xb5f4b421L, 0x23c4b356L, 0x9995bacfL,
+      0x0fa5bdb8L, 0x9eb80228L, 0x0888055fL, 0xb2d90cc6L, 0x24e90bb1L,
+      0x877c6f2fL, 0x114c6858L, 0xab1d61c1L, 0x3d2d66b6L, 0x9041dc76L,
+      0x0671db01L, 0xbc20d298L, 0x2a10d5efL, 0x8985b171L, 0x1fb5b606L,
+      0xa5e4bf9fL, 0x33d4b8e8L, 0xa2c90778L, 0x34f9000fL, 0x8ea80996L,
+      0x18980ee1L, 0xbb0d6a7fL, 0x2d3d6d08L, 0x976c6491L, 0x015c63e6L,
+      0xf4516b6bL, 0x62616c1cL, 0xd8306585L, 0x4e0062f2L, 0xed95066cL,
+      0x7ba5011bL, 0xc1f40882L, 0x57c40ff5L, 0xc6d9b065L, 0x50e9b712L,
+      0xeab8be8bL, 0x7c88b9fcL, 0xdf1ddd62L, 0x492dda15L, 0xf37cd38cL,
+      0x654cd4fbL, 0x5861b24dL, 0xce51b53aL, 0x7400bca3L, 0xe230bbd4L,
+      0x41a5df4aL, 0xd795d83dL, 0x6dc4d1a4L, 0xfbf4d6d3L, 0x6ae96943L,
+      0xfcd96e34L, 0x468867adL, 0xd0b860daL, 0x732d0444L, 0xe51d0333L,
+      0x5f4c0aaaL, 0xc97c0dddL, 0x3c710550L, 0xaa410227L, 0x10100bbeL,
+      0x86200cc9L, 0x25b56857L, 0xb3856f20L, 0x09d466b9L, 0x9fe461ceL,
+      0x0ef9de5eL, 0x98c9d929L, 0x2298d0b0L, 0xb4a8d7c7L, 0x173db359L,
+      0x810db42eL, 0x3b5cbdb7L, 0xad6cbac0L, 0x2083b8edL, 0xb6b3bf9aL,
+      0x0ce2b603L, 0x9ad2b174L, 0x3947d5eaL, 0xaf77d29dL, 0x1526db04L,
+      0x8316dc73L, 0x120b63e3L, 0x843b6494L, 0x3e6a6d0dL, 0xa85a6a7aL,
+      0x0bcf0ee4L, 0x9dff0993L, 0x27ae000aL, 0xb19e077dL, 0x44930ff0L,
+      0xd2a30887L, 0x68f2011eL, 0xfec20669L, 0x5d5762f7L, 0xcb676580L,
+      0x71366c19L, 0xe7066b6eL, 0x761bd4feL, 0xe02bd389L, 0x5a7ada10L,
+      0xcc4add67L, 0x6fdfb9f9L, 0xf9efbe8eL, 0x43beb717L, 0xd58eb060L,
+      0xe8a3d6d6L, 0x7e93d1a1L, 0xc4c2d838L, 0x52f2df4fL, 0xf167bbd1L,
+      0x6757bca6L, 0xdd06b53fL, 0x4b36b248L, 0xda2b0dd8L, 0x4c1b0aafL,
+      0xf64a0336L, 0x607a0441L, 0xc3ef60dfL, 0x55df67a8L, 0xef8e6e31L,
+      0x79be6946L, 0x8cb361cbL, 0x1a8366bcL, 0xa0d26f25L, 0x36e26852L,
+      0x95770cccL, 0x03470bbbL, 0xb9160222L, 0x2f260555L, 0xbe3bbac5L,
+      0x280bbdb2L, 0x925ab42bL, 0x046ab35cL, 0xa7ffd7c2L, 0x31cfd0b5L,
+      0x8b9ed92cL, 0x1daede5bL, 0xb0c2649bL, 0x26f263ecL, 0x9ca36a75L,
+      0x0a936d02L, 0xa906099cL, 0x3f360eebL, 0x85670772L, 0x13570005L,
+      0x824abf95L, 0x147ab8e2L, 0xae2bb17bL, 0x381bb60cL, 0x9b8ed292L,
+      0x0dbed5e5L, 0xb7efdc7cL, 0x21dfdb0bL, 0xd4d2d386L, 0x42e2d4f1L,
+      0xf8b3dd68L, 0x6e83da1fL, 0xcd16be81L, 0x5b26b9f6L, 0xe177b06fL,
+      0x7747b718L, 0xe65a0888L, 0x706a0fffL, 0xca3b0666L, 0x5c0b0111L,
+      0xff9e658fL, 0x69ae62f8L, 0xd3ff6b61L, 0x45cf6c16L, 0x78e20aa0L,
+      0xeed20dd7L, 0x5483044eL, 0xc2b30339L, 0x612667a7L, 0xf71660d0L,
+      0x4d476949L, 0xdb776e3eL, 0x4a6ad1aeL, 0xdc5ad6d9L, 0x660bdf40L,
+      0xf03bd837L, 0x53aebca9L, 0xc59ebbdeL, 0x7fcfb247L, 0xe9ffb530L,
+      0x1cf2bdbdL, 0x8ac2bacaL, 0x3093b353L, 0xa6a3b424L, 0x0536d0baL,
+      0x9306d7cdL, 0x2957de54L, 0xbf67d923L, 0x2e7a66b3L, 0xb84a61c4L,
+      0x021b685dL, 0x942b6f2aL, 0x37be0bb4L, 0xa18e0cc3L, 0x1bdf055aL,
+      0x8def022dL
+#endif
+};
+
+void crc32_init(crc32_state *ctx)
+{
+   LTC_ARGCHKVD(ctx != NULL);
+   ctx->crc = _CRC32_NEGL;
+}
+
+void crc32_update(crc32_state *ctx, const unsigned char *input, unsigned long length)
+{
+   ulong32 crc;
+   LTC_ARGCHKVD(ctx != NULL);
+   LTC_ARGCHKVD(input != NULL);
+   crc = ctx->crc;
+
+   while (length--)
+      crc = crc32_m_tab[CRC32_INDEX(crc) ^ *input++] ^ CRC32_SHIFTED(crc);
+
+   ctx->crc = crc;
+}
+
+void crc32_finish(crc32_state *ctx, void *hash, unsigned long size)
+{
+   unsigned long i;
+   unsigned char* h;
+   ulong32 crc;
+   LTC_ARGCHKVD(ctx != NULL);
+   LTC_ARGCHKVD(hash != NULL);
+
+   h = hash;
+   crc = ctx->crc;
+   crc ^= _CRC32_NEGL;
+
+   if (size > 4) size = 4;
+   for (i = 0; i < size; i++) {
+      h[i] = ((unsigned char*)&(crc))[size-i-1];
+   }
+}
+
+int crc32_test(void)
+{
+#ifndef LTC_TEST
+   return CRYPT_NOP;
+#else
+   const void* in = "libtomcrypt";
+   const unsigned char crc32[] = { 0xb3, 0x73, 0x76, 0xef };
+   unsigned char out[4];
+   crc32_state ctx;
+   crc32_init(&ctx);
+   crc32_update(&ctx, in, strlen(in));
+   crc32_finish(&ctx, out, 4);
+   if (compare_testvector(crc32, 4, out, 4, "CRC32", 0)) {
+      return CRYPT_FAIL_TESTVECTOR;
+   }
+   return CRYPT_OK;
+#endif
+}
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/misc/crypt/crypt.c b/libtomcrypt/src/misc/crypt/crypt.c
new file mode 100644 (file)
index 0000000..e5149b0
--- /dev/null
@@ -0,0 +1,496 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file crypt.c
+  Build strings, Tom St Denis
+*/
+#define NAME_VALUE(s) #s"="NAME(s)
+#define NAME(s) #s
+
+const char *crypt_build_settings =
+   "LibTomCrypt " SCRYPT " (www.libtom.net)\n"
+   "LibTomCrypt is public domain software.\n"
+#if defined(INCLUDE_BUILD_DATE)
+   "Built on " __DATE__ " at " __TIME__ "\n"
+#endif
+   "\n\nEndianness: "
+#if defined(ENDIAN_NEUTRAL)
+   "neutral/"
+#endif
+#if defined(ENDIAN_LITTLE)
+   "little"
+#elif defined(ENDIAN_BIG)
+   "big"
+#endif
+   #if defined(ENDIAN_32BITWORD)
+   " (32-bit words)\n"
+   #elif defined(ENDIAN_64BITWORD)
+   " (64-bit words)\n"
+   #else
+   " (no wordsize defined)\n"
+   #endif
+   "Clean stack: "
+#if defined(LTC_CLEAN_STACK)
+   "enabled\n"
+#else
+   "disabled\n"
+#endif
+   "\nCiphers built-in:\n"
+#if defined(LTC_BLOWFISH)
+   "   Blowfish\n"
+#endif
+#if defined(LTC_RC2)
+   "   RC2\n"
+#endif
+#if defined(LTC_RC5)
+   "   RC5\n"
+#endif
+#if defined(LTC_RC6)
+   "   RC6\n"
+#endif
+#if defined(LTC_SAFERP)
+   "   Safer+\n"
+#endif
+#if defined(LTC_SAFER)
+   "   Safer\n"
+#endif
+#if defined(LTC_RIJNDAEL)
+   "   Rijndael\n"
+#endif
+#if defined(LTC_XTEA)
+   "   XTEA\n"
+#endif
+#if defined(LTC_TWOFISH)
+   "   Twofish "
+   #if defined(LTC_TWOFISH_SMALL) && defined(LTC_TWOFISH_TABLES) && defined(LTC_TWOFISH_ALL_TABLES)
+       "(small, tables, all_tables)\n"
+   #elif defined(LTC_TWOFISH_SMALL) && defined(LTC_TWOFISH_TABLES)
+       "(small, tables)\n"
+   #elif defined(LTC_TWOFISH_SMALL) && defined(LTC_TWOFISH_ALL_TABLES)
+       "(small, all_tables)\n"
+   #elif defined(LTC_TWOFISH_TABLES) && defined(LTC_TWOFISH_ALL_TABLES)
+       "(tables, all_tables)\n"
+   #elif defined(LTC_TWOFISH_SMALL)
+       "(small)\n"
+   #elif defined(LTC_TWOFISH_TABLES)
+       "(tables)\n"
+   #elif defined(LTC_TWOFISH_ALL_TABLES)
+       "(all_tables)\n"
+   #else
+       "\n"
+   #endif
+#endif
+#if defined(LTC_DES)
+   "   DES\n"
+#endif
+#if defined(LTC_CAST5)
+   "   CAST5\n"
+#endif
+#if defined(LTC_NOEKEON)
+   "   Noekeon\n"
+#endif
+#if defined(LTC_SKIPJACK)
+   "   Skipjack\n"
+#endif
+#if defined(LTC_KHAZAD)
+   "   Khazad\n"
+#endif
+#if defined(LTC_ANUBIS)
+   "   Anubis "
+#endif
+#if defined(LTC_ANUBIS_TWEAK)
+   " (tweaked)"
+#endif
+   "\n"
+#if defined(LTC_KSEED)
+   "   KSEED\n"
+#endif
+#if defined(LTC_KASUMI)
+   "   KASUMI\n"
+#endif
+#if defined(LTC_MULTI2)
+   "   MULTI2\n"
+#endif
+#if defined(LTC_CAMELLIA)
+   "   Camellia\n"
+#endif
+   "Stream ciphers built-in:\n"
+#if defined(LTC_CHACHA)
+   "   ChaCha\n"
+#endif
+#if defined(LTC_RC4_STREAM)
+   "   RC4\n"
+#endif
+#if defined(LTC_SOBER128_STREAM)
+   "   SOBER128\n"
+#endif
+
+    "\nHashes built-in:\n"
+#if defined(LTC_SHA3)
+   "   SHA3\n"
+#endif
+#if defined(LTC_SHA512)
+   "   SHA-512\n"
+#endif
+#if defined(LTC_SHA384)
+   "   SHA-384\n"
+#endif
+#if defined(LTC_SHA512_256)
+   "   SHA-512/256\n"
+#endif
+#if defined(LTC_SHA256)
+   "   SHA-256\n"
+#endif
+#if defined(LTC_SHA512_224)
+   "   SHA-512/224\n"
+#endif
+#if defined(LTC_SHA224)
+   "   SHA-224\n"
+#endif
+#if defined(LTC_TIGER)
+   "   TIGER\n"
+#endif
+#if defined(LTC_SHA1)
+   "   SHA1\n"
+#endif
+#if defined(LTC_MD5)
+   "   MD5\n"
+#endif
+#if defined(LTC_MD4)
+   "   MD4\n"
+#endif
+#if defined(LTC_MD2)
+   "   MD2\n"
+#endif
+#if defined(LTC_RIPEMD128)
+   "   RIPEMD128\n"
+#endif
+#if defined(LTC_RIPEMD160)
+   "   RIPEMD160\n"
+#endif
+#if defined(LTC_RIPEMD256)
+   "   RIPEMD256\n"
+#endif
+#if defined(LTC_RIPEMD320)
+   "   RIPEMD320\n"
+#endif
+#if defined(LTC_WHIRLPOOL)
+   "   WHIRLPOOL\n"
+#endif
+#if defined(LTC_BLAKE2S)
+   "   BLAKE2S\n"
+#endif
+#if defined(LTC_BLAKE2B)
+   "   BLAKE2B\n"
+#endif
+#if defined(LTC_CHC_HASH)
+   "   CHC_HASH\n"
+#endif
+
+    "\nBlock Chaining Modes:\n"
+#if defined(LTC_CFB_MODE)
+    "   CFB\n"
+#endif
+#if defined(LTC_OFB_MODE)
+    "   OFB\n"
+#endif
+#if defined(LTC_ECB_MODE)
+    "   ECB\n"
+#endif
+#if defined(LTC_CBC_MODE)
+    "   CBC\n"
+#endif
+#if defined(LTC_CTR_MODE)
+    "   CTR\n"
+#endif
+#if defined(LTC_LRW_MODE)
+    "   LRW"
+#if defined(LTC_LRW_TABLES)
+    " (tables) "
+#endif
+    "\n"
+#endif
+#if defined(LTC_F8_MODE)
+    "   F8\n"
+#endif
+#if defined(LTC_XTS_MODE)
+    "   XTS\n"
+#endif
+
+    "\nMACs:\n"
+#if defined(LTC_HMAC)
+    "   HMAC\n"
+#endif
+#if defined(LTC_OMAC)
+    "   OMAC\n"
+#endif
+#if defined(LTC_PMAC)
+    "   PMAC\n"
+#endif
+#if defined(LTC_PELICAN)
+    "   PELICAN\n"
+#endif
+#if defined(LTC_XCBC)
+    "   XCBC\n"
+#endif
+#if defined(LTC_F9_MODE)
+    "   F9\n"
+#endif
+#if defined(LTC_POLY1305)
+    "   POLY1305\n"
+#endif
+#if defined(LTC_BLAKE2SMAC)
+    "   BLAKE2S MAC\n"
+#endif
+#if defined(LTC_BLAKE2BMAC)
+    "   BLAKE2B MAC\n"
+#endif
+
+    "\nENC + AUTH modes:\n"
+#if defined(LTC_EAX_MODE)
+    "   EAX\n"
+#endif
+#if defined(LTC_OCB_MODE)
+    "   OCB\n"
+#endif
+#if defined(LTC_OCB3_MODE)
+    "   OCB3\n"
+#endif
+#if defined(LTC_CCM_MODE)
+    "   CCM\n"
+#endif
+#if defined(LTC_GCM_MODE)
+    "   GCM"
+#if defined(LTC_GCM_TABLES)
+    " (tables) "
+#endif
+#if defined(LTC_GCM_TABLES_SSE2)
+    " (SSE2) "
+#endif
+   "\n"
+#endif
+#if defined(LTC_CHACHA20POLY1305_MODE)
+    "   CHACHA20POLY1305\n"
+#endif
+
+    "\nPRNG:\n"
+#if defined(LTC_YARROW)
+    "   Yarrow ("NAME_VALUE(LTC_YARROW_AES)")\n"
+#endif
+#if defined(LTC_SPRNG)
+    "   SPRNG\n"
+#endif
+#if defined(LTC_RC4)
+    "   RC4\n"
+#endif
+#if defined(LTC_CHACHA20_PRNG)
+    "   ChaCha20\n"
+#endif
+#if defined(LTC_FORTUNA)
+    "   Fortuna (" NAME_VALUE(LTC_FORTUNA_POOLS) ", " NAME_VALUE(LTC_FORTUNA_WD) ")\n"
+#endif
+#if defined(LTC_SOBER128)
+    "   SOBER128\n"
+#endif
+
+    "\nPK Crypto:\n"
+#if defined(LTC_MRSA)
+    "   RSA"
+#if defined(LTC_RSA_BLINDING) && defined(LTC_RSA_CRT_HARDENING)
+    " (with blinding and CRT hardening)"
+#elif defined(LTC_RSA_BLINDING)
+    " (with blinding)"
+#elif defined(LTC_RSA_CRT_HARDENING)
+    " (with CRT hardening)"
+#endif
+    "\n"
+#endif
+#if defined(LTC_MDH)
+    "   DH\n"
+#endif
+#if defined(LTC_MECC)
+    "   ECC"
+#if defined(LTC_ECC_TIMING_RESISTANT)
+    " (with blinding)"
+#endif
+    "\n"
+#endif
+#if defined(LTC_MDSA)
+    "   DSA\n"
+#endif
+#if defined(LTC_MKAT)
+    "   Katja\n"
+#endif
+#if defined(LTC_PK_MAX_RETRIES)
+    "   "NAME_VALUE(LTC_PK_MAX_RETRIES)"\n"
+#endif
+
+    "\nMPI (Math):\n"
+#if defined(LTC_MPI)
+    "   LTC_MPI\n"
+#endif
+#if defined(LTM_DESC)
+    "   LTM_DESC\n"
+#endif
+#if defined(TFM_DESC)
+    "   TFM_DESC\n"
+#endif
+#if defined(GMP_DESC)
+    "   GMP_DESC\n"
+#endif
+#if defined(LTC_MILLER_RABIN_REPS)
+    "   "NAME_VALUE(LTC_MILLER_RABIN_REPS)"\n"
+#endif
+
+    "\nCompiler:\n"
+#if defined(_WIN64)
+    "   WIN64 platform detected.\n"
+#elif defined(_WIN32)
+    "   WIN32 platform detected.\n"
+#endif
+#if defined(__CYGWIN__)
+    "   CYGWIN Detected.\n"
+#endif
+#if defined(__DJGPP__)
+    "   DJGPP Detected.\n"
+#endif
+#if defined(_MSC_VER)
+    "   MSVC compiler detected.\n"
+#endif
+#if defined(__clang_version__)
+    "   Clang compiler " __clang_version__ ".\n"
+#elif defined(INTEL_CC)
+    "   Intel C Compiler " __VERSION__ ".\n"
+#elif defined(__GNUC__)         /* clang and icc also define __GNUC__ */
+    "   GCC compiler " __VERSION__ ".\n"
+#endif
+
+#if defined(__x86_64__)
+    "   x86-64 detected.\n"
+#endif
+#if defined(LTC_PPC32)
+    "   PPC32 detected.\n"
+#endif
+
+    "\nVarious others: "
+#if defined(ARGTYPE)
+    " " NAME_VALUE(ARGTYPE) " "
+#endif
+#if defined(LTC_ADLER32)
+    " ADLER32 "
+#endif
+#if defined(LTC_BASE64)
+    " BASE64 "
+#endif
+#if defined(LTC_BASE64_URL)
+    " BASE64-URL-SAFE "
+#endif
+#if defined(LTC_CRC32)
+    " CRC32 "
+#endif
+#if defined(LTC_DER)
+    " DER "
+    " " NAME_VALUE(LTC_DER_MAX_RECURSION) " "
+#endif
+#if defined(LTC_PKCS_1)
+    " PKCS#1 "
+#endif
+#if defined(LTC_PKCS_5)
+    " PKCS#5 "
+#endif
+#if defined(LTC_HKDF)
+    " HKDF "
+#endif
+#if defined(LTC_DEVRANDOM)
+    " LTC_DEVRANDOM "
+#endif
+#if defined(LTC_TRY_URANDOM_FIRST)
+    " LTC_TRY_URANDOM_FIRST "
+#endif
+#if defined(LTC_RNG_GET_BYTES)
+    " LTC_RNG_GET_BYTES "
+#endif
+#if defined(LTC_RNG_MAKE_PRNG)
+    " LTC_RNG_MAKE_PRNG "
+#endif
+#if defined(LTC_PRNG_ENABLE_LTC_RNG)
+    " LTC_PRNG_ENABLE_LTC_RNG "
+#endif
+#if defined(LTC_HASH_HELPERS)
+    " LTC_HASH_HELPERS "
+#endif
+#if defined(LTC_VALGRIND)
+    " LTC_VALGRIND "
+#endif
+#if defined(LTC_TEST)
+    " LTC_TEST "
+#endif
+#if defined(LTC_TEST_DBG)
+    " " NAME_VALUE(LTC_TEST_DBG) " "
+#endif
+#if defined(LTC_TEST_EXT)
+    " LTC_TEST_EXT "
+#endif
+#if defined(LTC_SMALL_CODE)
+    " LTC_SMALL_CODE "
+#endif
+#if defined(LTC_NO_FILE)
+    " LTC_NO_FILE "
+#endif
+#if defined(LTC_FILE_READ_BUFSIZE)
+    " " NAME_VALUE(LTC_FILE_READ_BUFSIZE) " "
+#endif
+#if defined(LTC_FAST)
+    " LTC_FAST "
+#endif
+#if defined(LTC_NO_FAST)
+    " LTC_NO_FAST "
+#endif
+#if defined(LTC_NO_BSWAP)
+    " LTC_NO_BSWAP "
+#endif
+#if defined(LTC_NO_ASM)
+    " LTC_NO_ASM "
+#endif
+#if defined(LTC_ROx_ASM)
+    " LTC_ROx_ASM "
+#if defined(LTC_NO_ROLC)
+    " LTC_NO_ROLC "
+#endif
+#endif
+#if defined(LTC_NO_TEST)
+    " LTC_NO_TEST "
+#endif
+#if defined(LTC_NO_TABLES)
+    " LTC_NO_TABLES "
+#endif
+#if defined(LTC_PTHREAD)
+    " LTC_PTHREAD "
+#endif
+#if defined(LTC_EASY)
+    " LTC_EASY "
+#endif
+#if defined(LTC_MECC_ACCEL)
+    " LTC_MECC_ACCEL "
+#endif
+#if defined(LTC_MECC_FP)
+   " LTC_MECC_FP "
+#endif
+#if defined(LTC_ECC_SHAMIR)
+   " LTC_ECC_SHAMIR "
+#endif
+    "\n"
+    ;
+
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/misc/crypt/crypt_argchk.c b/libtomcrypt/src/misc/crypt/crypt_argchk.c
new file mode 100644 (file)
index 0000000..da7306b
--- /dev/null
@@ -0,0 +1,27 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file crypt_argchk.c
+  Perform argument checking, Tom St Denis
+*/
+
+#if (ARGTYPE == 0)
+void crypt_argchk(const char *v, const char *s, int d)
+{
+ fprintf(stderr, "LTC_ARGCHK '%s' failure on line %d of file %s\n",
+         v, d, s);
+ abort();
+}
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/misc/crypt/crypt_cipher_descriptor.c b/libtomcrypt/src/misc/crypt/crypt_cipher_descriptor.c
new file mode 100644 (file)
index 0000000..ccc9890
--- /dev/null
@@ -0,0 +1,25 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file crypt_cipher_descriptor.c
+  Stores the cipher descriptor table, Tom St Denis
+*/
+
+struct ltc_cipher_descriptor cipher_descriptor[TAB_SIZE] = {
+{ NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }
+ };
+
+LTC_MUTEX_GLOBAL(ltc_cipher_mutex)
+
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/misc/crypt/crypt_cipher_is_valid.c b/libtomcrypt/src/misc/crypt/crypt_cipher_is_valid.c
new file mode 100644 (file)
index 0000000..aebc94c
--- /dev/null
@@ -0,0 +1,34 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file crypt_cipher_is_valid.c
+  Determine if cipher is valid, Tom St Denis
+*/
+
+/*
+   Test if a cipher index is valid
+   @param idx   The index of the cipher to search for
+   @return CRYPT_OK if valid
+*/
+int cipher_is_valid(int idx)
+{
+   LTC_MUTEX_LOCK(&ltc_cipher_mutex);
+   if (idx < 0 || idx >= TAB_SIZE || cipher_descriptor[idx].name == NULL) {
+      LTC_MUTEX_UNLOCK(&ltc_cipher_mutex);
+      return CRYPT_INVALID_CIPHER;
+   }
+   LTC_MUTEX_UNLOCK(&ltc_cipher_mutex);
+   return CRYPT_OK;
+}
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/misc/crypt/crypt_constants.c b/libtomcrypt/src/misc/crypt/crypt_constants.c
new file mode 100644 (file)
index 0000000..9b3c938
--- /dev/null
@@ -0,0 +1,292 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file crypt_constants.c
+
+  Make various constants available to dynamic languages
+  like Python - Larry Bugbee, February 2013
+
+  LB - Dec 2013 - revised to include compiler define options
+  LB - Mar 2014 - added endianness and word size
+*/
+
+typedef struct {
+    const char *name;
+    const int value;
+} crypt_constant;
+
+#define _C_STRINGIFY(s) { #s, s }
+
+static const crypt_constant _crypt_constants[] = {
+
+    _C_STRINGIFY(CRYPT_OK),
+    _C_STRINGIFY(CRYPT_ERROR),
+    _C_STRINGIFY(CRYPT_NOP),
+    _C_STRINGIFY(CRYPT_INVALID_KEYSIZE),
+    _C_STRINGIFY(CRYPT_INVALID_ROUNDS),
+    _C_STRINGIFY(CRYPT_FAIL_TESTVECTOR),
+    _C_STRINGIFY(CRYPT_BUFFER_OVERFLOW),
+    _C_STRINGIFY(CRYPT_INVALID_PACKET),
+    _C_STRINGIFY(CRYPT_INVALID_PRNGSIZE),
+    _C_STRINGIFY(CRYPT_ERROR_READPRNG),
+    _C_STRINGIFY(CRYPT_INVALID_CIPHER),
+    _C_STRINGIFY(CRYPT_INVALID_HASH),
+    _C_STRINGIFY(CRYPT_INVALID_PRNG),
+    _C_STRINGIFY(CRYPT_MEM),
+    _C_STRINGIFY(CRYPT_PK_TYPE_MISMATCH),
+    _C_STRINGIFY(CRYPT_PK_NOT_PRIVATE),
+    _C_STRINGIFY(CRYPT_INVALID_ARG),
+    _C_STRINGIFY(CRYPT_FILE_NOTFOUND),
+    _C_STRINGIFY(CRYPT_PK_INVALID_TYPE),
+    _C_STRINGIFY(CRYPT_OVERFLOW),
+    _C_STRINGIFY(CRYPT_UNUSED1),
+    _C_STRINGIFY(CRYPT_INPUT_TOO_LONG),
+    _C_STRINGIFY(CRYPT_PK_INVALID_SIZE),
+    _C_STRINGIFY(CRYPT_INVALID_PRIME_SIZE),
+    _C_STRINGIFY(CRYPT_PK_INVALID_PADDING),
+    _C_STRINGIFY(CRYPT_HASH_OVERFLOW),
+
+    _C_STRINGIFY(PK_PUBLIC),
+    _C_STRINGIFY(PK_PRIVATE),
+
+    _C_STRINGIFY(LTC_ENCRYPT),
+    _C_STRINGIFY(LTC_DECRYPT),
+
+#ifdef LTC_PKCS_1
+    {"LTC_PKCS_1", 1},
+    /* Block types */
+    _C_STRINGIFY(LTC_PKCS_1_EMSA),
+    _C_STRINGIFY(LTC_PKCS_1_EME),
+
+    /* Padding types */
+    _C_STRINGIFY(LTC_PKCS_1_V1_5),
+    _C_STRINGIFY(LTC_PKCS_1_OAEP),
+    _C_STRINGIFY(LTC_PKCS_1_PSS),
+    _C_STRINGIFY(LTC_PKCS_1_V1_5_NA1),
+#else
+    {"LTC_PKCS_1", 0},
+#endif
+
+#ifdef LTC_MRSA
+    {"LTC_MRSA", 1},
+#else
+    {"LTC_MRSA", 0},
+#endif
+
+#ifdef LTC_MKAT
+    {"LTC_MKAT", 1},
+    _C_STRINGIFY(MIN_KAT_SIZE),
+    _C_STRINGIFY(MAX_KAT_SIZE),
+#else
+    {"LTC_MKAT", 0},
+#endif
+
+#ifdef LTC_MECC
+    {"LTC_MECC", 1},
+    _C_STRINGIFY(ECC_BUF_SIZE),
+    _C_STRINGIFY(ECC_MAXSIZE),
+#else
+    {"LTC_MECC", 0},
+#endif
+
+#ifdef LTC_MDSA
+    {"LTC_MDSA", 1},
+    _C_STRINGIFY(LTC_MDSA_DELTA),
+    _C_STRINGIFY(LTC_MDSA_MAX_GROUP),
+#else
+    {"LTC_MDSA", 0},
+#endif
+
+#ifdef LTC_MILLER_RABIN_REPS
+    _C_STRINGIFY(LTC_MILLER_RABIN_REPS),
+#endif
+
+#ifdef LTC_DER
+/* DER handling */
+    {"LTC_DER", 1},
+    _C_STRINGIFY(LTC_ASN1_EOL),
+    _C_STRINGIFY(LTC_ASN1_BOOLEAN),
+    _C_STRINGIFY(LTC_ASN1_INTEGER),
+    _C_STRINGIFY(LTC_ASN1_SHORT_INTEGER),
+    _C_STRINGIFY(LTC_ASN1_BIT_STRING),
+    _C_STRINGIFY(LTC_ASN1_OCTET_STRING),
+    _C_STRINGIFY(LTC_ASN1_NULL),
+    _C_STRINGIFY(LTC_ASN1_OBJECT_IDENTIFIER),
+    _C_STRINGIFY(LTC_ASN1_IA5_STRING),
+    _C_STRINGIFY(LTC_ASN1_PRINTABLE_STRING),
+    _C_STRINGIFY(LTC_ASN1_UTF8_STRING),
+    _C_STRINGIFY(LTC_ASN1_UTCTIME),
+    _C_STRINGIFY(LTC_ASN1_CHOICE),
+    _C_STRINGIFY(LTC_ASN1_SEQUENCE),
+    _C_STRINGIFY(LTC_ASN1_SET),
+    _C_STRINGIFY(LTC_ASN1_SETOF),
+    _C_STRINGIFY(LTC_ASN1_RAW_BIT_STRING),
+    _C_STRINGIFY(LTC_ASN1_TELETEX_STRING),
+    _C_STRINGIFY(LTC_ASN1_CONSTRUCTED),
+    _C_STRINGIFY(LTC_ASN1_CONTEXT_SPECIFIC),
+    _C_STRINGIFY(LTC_ASN1_GENERALIZEDTIME),
+    _C_STRINGIFY(LTC_DER_MAX_RECURSION),
+#else
+    {"LTC_DER", 0},
+#endif
+
+#ifdef LTC_CTR_MODE
+    {"LTC_CTR_MODE", 1},
+    _C_STRINGIFY(CTR_COUNTER_LITTLE_ENDIAN),
+    _C_STRINGIFY(CTR_COUNTER_BIG_ENDIAN),
+    _C_STRINGIFY(LTC_CTR_RFC3686),
+#else
+    {"LTC_CTR_MODE", 0},
+#endif
+#ifdef LTC_GCM_MODE
+    _C_STRINGIFY(LTC_GCM_MODE_IV),
+    _C_STRINGIFY(LTC_GCM_MODE_AAD),
+    _C_STRINGIFY(LTC_GCM_MODE_TEXT),
+#endif
+
+    _C_STRINGIFY(LTC_MP_LT),
+    _C_STRINGIFY(LTC_MP_EQ),
+    _C_STRINGIFY(LTC_MP_GT),
+
+    _C_STRINGIFY(LTC_MP_NO),
+    _C_STRINGIFY(LTC_MP_YES),
+
+    _C_STRINGIFY(MAXBLOCKSIZE),
+    _C_STRINGIFY(TAB_SIZE),
+    _C_STRINGIFY(ARGTYPE),
+
+#ifdef LTM_DESC
+    {"LTM_DESC", 1},
+#else
+    {"LTM_DESC", 0},
+#endif
+#ifdef TFM_DESC
+    {"TFM_DESC", 1},
+#else
+    {"TFM_DESC", 0},
+#endif
+#ifdef GMP_DESC
+    {"GMP_DESC", 1},
+#else
+    {"GMP_DESC", 0},
+#endif
+
+#ifdef LTC_FAST
+    {"LTC_FAST", 1},
+#else
+    {"LTC_FAST", 0},
+#endif
+
+#ifdef LTC_NO_FILE
+    {"LTC_NO_FILE", 1},
+#else
+    {"LTC_NO_FILE", 0},
+#endif
+
+#ifdef ENDIAN_LITTLE
+    {"ENDIAN_LITTLE",             1},
+#else
+    {"ENDIAN_LITTLE",             0},
+#endif
+
+#ifdef ENDIAN_BIG
+    {"ENDIAN_BIG",                1},
+#else
+    {"ENDIAN_BIG",                0},
+#endif
+
+#ifdef ENDIAN_32BITWORD
+    {"ENDIAN_32BITWORD",          1},
+#else
+    {"ENDIAN_32BITWORD",          0},
+#endif
+
+#ifdef ENDIAN_64BITWORD
+    {"ENDIAN_64BITWORD",          1},
+#else
+    {"ENDIAN_64BITWORD",          0},
+#endif
+
+#ifdef ENDIAN_NEUTRAL
+    {"ENDIAN_NEUTRAL",            1},
+#else
+    {"ENDIAN_NEUTRAL",            0},
+#endif
+};
+
+
+/* crypt_get_constant()
+ * valueout will be the value of the named constant
+ * return -1 if named item not found
+ */
+int crypt_get_constant(const char* namein, int *valueout) {
+    int i;
+    int _crypt_constants_len = sizeof(_crypt_constants) / sizeof(_crypt_constants[0]);
+    for (i=0; i<_crypt_constants_len; i++) {
+        if (XSTRCMP(_crypt_constants[i].name, namein) == 0) {
+            *valueout = _crypt_constants[i].value;
+            return 0;
+        }
+    }
+    return 1;
+}
+
+/* crypt_list_all_constants()
+ * if names_list is NULL, names_list_size will be the minimum
+ *     number of bytes needed to receive the complete names_list
+ * if names_list is NOT NULL, names_list must be the addr of
+ *     sufficient memory allocated into which the names_list
+ *     is to be written.  Also, the value in names_list_size
+ *     sets the upper bound of the number of characters to be
+ *     written.
+ * a -1 return value signifies insufficient space made available
+ */
+int crypt_list_all_constants(char *names_list, unsigned int *names_list_size) {
+    int i;
+    unsigned int total_len = 0;
+    char *ptr;
+    int number_len;
+    int count = sizeof(_crypt_constants) / sizeof(_crypt_constants[0]);
+
+    /* calculate amount of memory required for the list */
+    for (i=0; i<count; i++) {
+        number_len = snprintf(NULL, 0, "%s,%d\n", _crypt_constants[i].name, _crypt_constants[i].value);
+        if (number_len < 0)
+          return -1;
+        total_len += number_len;
+    }
+
+    if (names_list == NULL) {
+        *names_list_size = total_len;
+    } else {
+        if (total_len > *names_list_size) {
+            return -1;
+        }
+        /* build the names list */
+        ptr = names_list;
+        for (i=0; i<count; i++) {
+            number_len = snprintf(ptr, total_len, "%s,%d\n", _crypt_constants[i].name, _crypt_constants[i].value);
+            if (number_len < 0) return -1;
+            if ((unsigned int)number_len > total_len) return -1;
+            total_len -= number_len;
+            ptr += number_len;
+        }
+        /* to remove the trailing new-line */
+        ptr -= 1;
+        *ptr = 0;
+    }
+    return 0;
+}
+
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/misc/crypt/crypt_find_cipher.c b/libtomcrypt/src/misc/crypt/crypt_find_cipher.c
new file mode 100644 (file)
index 0000000..ba908f4
--- /dev/null
@@ -0,0 +1,39 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file crypt_find_cipher.c
+  Find a cipher in the descriptor tables, Tom St Denis
+*/
+
+/**
+   Find a registered cipher by name
+   @param name   The name of the cipher to look for
+   @return >= 0 if found, -1 if not present
+*/
+int find_cipher(const char *name)
+{
+   int x;
+   LTC_ARGCHK(name != NULL);
+   LTC_MUTEX_LOCK(&ltc_cipher_mutex);
+   for (x = 0; x < TAB_SIZE; x++) {
+       if (cipher_descriptor[x].name != NULL && !XSTRCMP(cipher_descriptor[x].name, name)) {
+          LTC_MUTEX_UNLOCK(&ltc_cipher_mutex);
+          return x;
+       }
+   }
+   LTC_MUTEX_UNLOCK(&ltc_cipher_mutex);
+   return -1;
+}
+
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/misc/crypt/crypt_find_cipher_any.c b/libtomcrypt/src/misc/crypt/crypt_find_cipher_any.c
new file mode 100644 (file)
index 0000000..5cdcdf8
--- /dev/null
@@ -0,0 +1,48 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file crypt_find_cipher_any.c
+  Find a cipher in the descriptor tables, Tom St Denis
+*/
+
+/**
+   Find a cipher flexibly.  First by name then if not present by block and key size
+   @param name        The name of the cipher desired
+   @param blocklen    The minimum length of the block cipher desired (octets)
+   @param keylen      The minimum length of the key size desired (octets)
+   @return >= 0 if found, -1 if not present
+*/
+int find_cipher_any(const char *name, int blocklen, int keylen)
+{
+   int x;
+
+   if(name != NULL) {
+      x = find_cipher(name);
+      if (x != -1) return x;
+   }
+
+   LTC_MUTEX_LOCK(&ltc_cipher_mutex);
+   for (x = 0; x < TAB_SIZE; x++) {
+       if (cipher_descriptor[x].name == NULL) {
+          continue;
+       }
+       if (blocklen <= (int)cipher_descriptor[x].block_length && keylen <= (int)cipher_descriptor[x].max_key_length) {
+          LTC_MUTEX_UNLOCK(&ltc_cipher_mutex);
+          return x;
+       }
+   }
+   LTC_MUTEX_UNLOCK(&ltc_cipher_mutex);
+   return -1;
+}
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/misc/crypt/crypt_find_cipher_id.c b/libtomcrypt/src/misc/crypt/crypt_find_cipher_id.c
new file mode 100644 (file)
index 0000000..34d0049
--- /dev/null
@@ -0,0 +1,38 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file crypt_find_cipher_id.c
+  Find cipher by ID, Tom St Denis
+*/
+
+/**
+   Find a cipher by ID number
+   @param ID    The ID (not same as index) of the cipher to find
+   @return >= 0 if found, -1 if not present
+*/
+int find_cipher_id(unsigned char ID)
+{
+   int x;
+   LTC_MUTEX_LOCK(&ltc_cipher_mutex);
+   for (x = 0; x < TAB_SIZE; x++) {
+       if (cipher_descriptor[x].ID == ID) {
+          x = (cipher_descriptor[x].name == NULL) ? -1 : x;
+          LTC_MUTEX_UNLOCK(&ltc_cipher_mutex);
+          return x;
+       }
+   }
+   LTC_MUTEX_UNLOCK(&ltc_cipher_mutex);
+   return -1;
+}
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/misc/crypt/crypt_find_hash.c b/libtomcrypt/src/misc/crypt/crypt_find_hash.c
new file mode 100644 (file)
index 0000000..19ee55c
--- /dev/null
@@ -0,0 +1,38 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file crypt_find_hash.c
+  Find a hash, Tom St Denis
+*/
+
+/**
+   Find a registered hash by name
+   @param name   The name of the hash to look for
+   @return >= 0 if found, -1 if not present
+*/
+int find_hash(const char *name)
+{
+   int x;
+   LTC_ARGCHK(name != NULL);
+   LTC_MUTEX_LOCK(&ltc_hash_mutex);
+   for (x = 0; x < TAB_SIZE; x++) {
+       if (hash_descriptor[x].name != NULL && XSTRCMP(hash_descriptor[x].name, name) == 0) {
+          LTC_MUTEX_UNLOCK(&ltc_hash_mutex);
+          return x;
+       }
+   }
+   LTC_MUTEX_UNLOCK(&ltc_hash_mutex);
+   return -1;
+}
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/misc/crypt/crypt_find_hash_any.c b/libtomcrypt/src/misc/crypt/crypt_find_hash_any.c
new file mode 100644 (file)
index 0000000..413809f
--- /dev/null
@@ -0,0 +1,47 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file crypt_find_hash_any.c
+  Find a hash, Tom St Denis
+*/
+
+/**
+   Find a hash flexibly.  First by name then if not present by digest size
+   @param name        The name of the hash desired
+   @param digestlen   The minimum length of the digest size (octets)
+   @return >= 0 if found, -1 if not present
+*/int find_hash_any(const char *name, int digestlen)
+{
+   int x, y, z;
+   LTC_ARGCHK(name != NULL);
+
+   x = find_hash(name);
+   if (x != -1) return x;
+
+   LTC_MUTEX_LOCK(&ltc_hash_mutex);
+   y = MAXBLOCKSIZE+1;
+   z = -1;
+   for (x = 0; x < TAB_SIZE; x++) {
+       if (hash_descriptor[x].name == NULL) {
+          continue;
+       }
+       if ((int)hash_descriptor[x].hashsize >= digestlen && (int)hash_descriptor[x].hashsize < y) {
+          z = x;
+          y = hash_descriptor[x].hashsize;
+       }
+   }
+   LTC_MUTEX_UNLOCK(&ltc_hash_mutex);
+   return z;
+}
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/misc/crypt/crypt_find_hash_id.c b/libtomcrypt/src/misc/crypt/crypt_find_hash_id.c
new file mode 100644 (file)
index 0000000..ea784e8
--- /dev/null
@@ -0,0 +1,38 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file crypt_find_hash_id.c
+  Find hash by ID, Tom St Denis
+*/
+
+/**
+   Find a hash by ID number
+   @param ID    The ID (not same as index) of the hash to find
+   @return >= 0 if found, -1 if not present
+*/
+int find_hash_id(unsigned char ID)
+{
+   int x;
+   LTC_MUTEX_LOCK(&ltc_hash_mutex);
+   for (x = 0; x < TAB_SIZE; x++) {
+      if (hash_descriptor[x].ID == ID) {
+          x = (hash_descriptor[x].name == NULL) ? -1 : x;
+          LTC_MUTEX_UNLOCK(&ltc_hash_mutex);
+          return x;
+      }
+   }
+   LTC_MUTEX_UNLOCK(&ltc_hash_mutex);
+   return -1;
+}
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/misc/crypt/crypt_find_hash_oid.c b/libtomcrypt/src/misc/crypt/crypt_find_hash_oid.c
new file mode 100644 (file)
index 0000000..026cc73
--- /dev/null
@@ -0,0 +1,33 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file crypt_find_hash_oid.c
+  Find a hash, Tom St Denis
+*/
+
+int find_hash_oid(const unsigned long *ID, unsigned long IDlen)
+{
+   int x;
+   LTC_ARGCHK(ID != NULL);
+   LTC_MUTEX_LOCK(&ltc_hash_mutex);
+   for (x = 0; x < TAB_SIZE; x++) {
+       if (hash_descriptor[x].name != NULL && hash_descriptor[x].OIDlen == IDlen && !XMEMCMP(hash_descriptor[x].OID, ID, sizeof(unsigned long) * IDlen)) {
+          LTC_MUTEX_UNLOCK(&ltc_hash_mutex);
+          return x;
+       }
+   }
+   LTC_MUTEX_UNLOCK(&ltc_hash_mutex);
+   return -1;
+}
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/misc/crypt/crypt_find_prng.c b/libtomcrypt/src/misc/crypt/crypt_find_prng.c
new file mode 100644 (file)
index 0000000..a0cad16
--- /dev/null
@@ -0,0 +1,39 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file crypt_find_prng.c
+  Find a PRNG, Tom St Denis
+*/
+
+/**
+   Find a registered PRNG by name
+   @param name   The name of the PRNG to look for
+   @return >= 0 if found, -1 if not present
+*/
+int find_prng(const char *name)
+{
+   int x;
+   LTC_ARGCHK(name != NULL);
+   LTC_MUTEX_LOCK(&ltc_prng_mutex);
+   for (x = 0; x < TAB_SIZE; x++) {
+       if ((prng_descriptor[x].name != NULL) && XSTRCMP(prng_descriptor[x].name, name) == 0) {
+          LTC_MUTEX_UNLOCK(&ltc_prng_mutex);
+          return x;
+       }
+   }
+   LTC_MUTEX_UNLOCK(&ltc_prng_mutex);
+   return -1;
+}
+
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/misc/crypt/crypt_fsa.c b/libtomcrypt/src/misc/crypt/crypt_fsa.c
new file mode 100644 (file)
index 0000000..dc2a570
--- /dev/null
@@ -0,0 +1,56 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+#include <stdarg.h>
+
+/**
+  @file crypt_fsa.c
+  LibTomCrypt FULL SPEED AHEAD!, Tom St Denis
+*/
+
+/* format is ltc_mp, cipher_desc, [cipher_desc], NULL, hash_desc, [hash_desc], NULL, prng_desc, [prng_desc], NULL */
+int crypt_fsa(void *mp, ...)
+{
+   va_list  args;
+   void     *p;
+
+   va_start(args, mp);
+   if (mp != NULL) {
+      XMEMCPY(&ltc_mp, mp, sizeof(ltc_mp));
+   }
+
+   while ((p = va_arg(args, void*)) != NULL) {
+      if (register_cipher(p) == -1) {
+         va_end(args);
+         return CRYPT_INVALID_CIPHER;
+      }
+   }
+
+   while ((p = va_arg(args, void*)) != NULL) {
+      if (register_hash(p) == -1) {
+         va_end(args);
+         return CRYPT_INVALID_HASH;
+      }
+   }
+
+   while ((p = va_arg(args, void*)) != NULL) {
+      if (register_prng(p) == -1) {
+         va_end(args);
+         return CRYPT_INVALID_PRNG;
+      }
+   }
+
+   va_end(args);
+   return CRYPT_OK;
+}
+
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/misc/crypt/crypt_hash_descriptor.c b/libtomcrypt/src/misc/crypt/crypt_hash_descriptor.c
new file mode 100644 (file)
index 0000000..6e1103f
--- /dev/null
@@ -0,0 +1,25 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file crypt_hash_descriptor.c
+  Stores the hash descriptor table, Tom St Denis
+*/
+
+struct ltc_hash_descriptor hash_descriptor[TAB_SIZE] = {
+{ NULL, 0, 0, 0, { 0 }, 0, NULL, NULL, NULL, NULL, NULL }
+};
+
+LTC_MUTEX_GLOBAL(ltc_hash_mutex)
+
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/misc/crypt/crypt_hash_is_valid.c b/libtomcrypt/src/misc/crypt/crypt_hash_is_valid.c
new file mode 100644 (file)
index 0000000..ca75f05
--- /dev/null
@@ -0,0 +1,34 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file crypt_hash_is_valid.c
+  Determine if hash is valid, Tom St Denis
+*/
+
+/*
+   Test if a hash index is valid
+   @param idx   The index of the hash to search for
+   @return CRYPT_OK if valid
+*/
+int hash_is_valid(int idx)
+{
+   LTC_MUTEX_LOCK(&ltc_hash_mutex);
+   if (idx < 0 || idx >= TAB_SIZE || hash_descriptor[idx].name == NULL) {
+      LTC_MUTEX_UNLOCK(&ltc_hash_mutex);
+      return CRYPT_INVALID_HASH;
+   }
+   LTC_MUTEX_UNLOCK(&ltc_hash_mutex);
+   return CRYPT_OK;
+}
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/misc/crypt/crypt_inits.c b/libtomcrypt/src/misc/crypt/crypt_inits.c
new file mode 100644 (file)
index 0000000..8042f38
--- /dev/null
@@ -0,0 +1,43 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file crypt_inits.c
+
+  Provide math library functions for dynamic languages
+  like Python - Larry Bugbee, February 2013
+*/
+
+
+#ifdef LTM_DESC
+void init_LTM(void)
+{
+    ltc_mp = ltm_desc;
+}
+#endif
+
+#ifdef TFM_DESC
+void init_TFM(void)
+{
+    ltc_mp = tfm_desc;
+}
+#endif
+
+#ifdef GMP_DESC
+void init_GMP(void)
+{
+    ltc_mp = gmp_desc;
+}
+#endif
+
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/misc/crypt/crypt_ltc_mp_descriptor.c b/libtomcrypt/src/misc/crypt/crypt_ltc_mp_descriptor.c
new file mode 100644 (file)
index 0000000..0f1407c
--- /dev/null
@@ -0,0 +1,16 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/* Initialize ltc_mp to nulls, to force allocation on all platforms, including macOS. */
+ltc_math_descriptor ltc_mp = { 0 };
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/misc/crypt/crypt_prng_descriptor.c b/libtomcrypt/src/misc/crypt/crypt_prng_descriptor.c
new file mode 100644 (file)
index 0000000..276047c
--- /dev/null
@@ -0,0 +1,24 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file crypt_prng_descriptor.c
+  Stores the PRNG descriptors, Tom St Denis
+*/
+struct ltc_prng_descriptor prng_descriptor[TAB_SIZE] = {
+{ NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }
+};
+
+LTC_MUTEX_GLOBAL(ltc_prng_mutex)
+
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/misc/crypt/crypt_prng_is_valid.c b/libtomcrypt/src/misc/crypt/crypt_prng_is_valid.c
new file mode 100644 (file)
index 0000000..9930a06
--- /dev/null
@@ -0,0 +1,34 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file crypt_prng_is_valid.c
+  Determine if PRNG is valid, Tom St Denis
+*/
+
+/*
+   Test if a PRNG index is valid
+   @param idx   The index of the PRNG to search for
+   @return CRYPT_OK if valid
+*/
+int prng_is_valid(int idx)
+{
+   LTC_MUTEX_LOCK(&ltc_prng_mutex);
+   if (idx < 0 || idx >= TAB_SIZE || prng_descriptor[idx].name == NULL) {
+      LTC_MUTEX_UNLOCK(&ltc_prng_mutex);
+      return CRYPT_INVALID_PRNG;
+   }
+   LTC_MUTEX_UNLOCK(&ltc_prng_mutex);
+   return CRYPT_OK;
+}
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/misc/crypt/crypt_prng_rng_descriptor.c b/libtomcrypt/src/misc/crypt/crypt_prng_rng_descriptor.c
new file mode 100644 (file)
index 0000000..1a79337
--- /dev/null
@@ -0,0 +1,17 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+#ifdef LTC_PRNG_ENABLE_LTC_RNG
+unsigned long (*ltc_rng)(unsigned char *out, unsigned long outlen, void (*callback)(void));
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/misc/crypt/crypt_register_all_ciphers.c b/libtomcrypt/src/misc/crypt/crypt_register_all_ciphers.c
new file mode 100644 (file)
index 0000000..3250a93
--- /dev/null
@@ -0,0 +1,100 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+#include "tomcrypt.h"
+
+/**
+  @file crypt_register_all_ciphers.c
+
+  Steffen Jaeckel
+*/
+
+#define REGISTER_CIPHER(h) do {\
+   LTC_ARGCHK(register_cipher(h) != -1); \
+} while(0)
+
+int register_all_ciphers(void)
+{
+#ifdef LTC_RIJNDAEL
+#ifdef ENCRYPT_ONLY
+   /* alternative would be
+    * register_cipher(&rijndael_enc_desc);
+    */
+   REGISTER_CIPHER(&aes_enc_desc);
+#else
+   /* alternative would be
+    * register_cipher(&rijndael_desc);
+    */
+   REGISTER_CIPHER(&aes_desc);
+#endif
+#endif
+#ifdef LTC_BLOWFISH
+   REGISTER_CIPHER(&blowfish_desc);
+#endif
+#ifdef LTC_XTEA
+   REGISTER_CIPHER(&xtea_desc);
+#endif
+#ifdef LTC_RC5
+   REGISTER_CIPHER(&rc5_desc);
+#endif
+#ifdef LTC_RC6
+   REGISTER_CIPHER(&rc6_desc);
+#endif
+#ifdef LTC_SAFERP
+   REGISTER_CIPHER(&saferp_desc);
+#endif
+#ifdef LTC_TWOFISH
+   REGISTER_CIPHER(&twofish_desc);
+#endif
+#ifdef LTC_SAFER
+   REGISTER_CIPHER(&safer_k64_desc);
+   REGISTER_CIPHER(&safer_sk64_desc);
+   REGISTER_CIPHER(&safer_k128_desc);
+   REGISTER_CIPHER(&safer_sk128_desc);
+#endif
+#ifdef LTC_RC2
+   REGISTER_CIPHER(&rc2_desc);
+#endif
+#ifdef LTC_DES
+   REGISTER_CIPHER(&des_desc);
+   REGISTER_CIPHER(&des3_desc);
+#endif
+#ifdef LTC_CAST5
+   REGISTER_CIPHER(&cast5_desc);
+#endif
+#ifdef LTC_NOEKEON
+   REGISTER_CIPHER(&noekeon_desc);
+#endif
+#ifdef LTC_SKIPJACK
+   REGISTER_CIPHER(&skipjack_desc);
+#endif
+#ifdef LTC_ANUBIS
+   REGISTER_CIPHER(&anubis_desc);
+#endif
+#ifdef LTC_KHAZAD
+   REGISTER_CIPHER(&khazad_desc);
+#endif
+#ifdef LTC_KSEED
+   REGISTER_CIPHER(&kseed_desc);
+#endif
+#ifdef LTC_KASUMI
+   REGISTER_CIPHER(&kasumi_desc);
+#endif
+#ifdef LTC_MULTI2
+   REGISTER_CIPHER(&multi2_desc);
+#endif
+#ifdef LTC_CAMELLIA
+   REGISTER_CIPHER(&camellia_desc);
+#endif
+   return CRYPT_OK;
+}
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/misc/crypt/crypt_register_all_hashes.c b/libtomcrypt/src/misc/crypt/crypt_register_all_hashes.c
new file mode 100644 (file)
index 0000000..b529389
--- /dev/null
@@ -0,0 +1,99 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+#include "tomcrypt.h"
+
+/**
+  @file crypt_register_all_hashes.c
+
+  Steffen Jaeckel
+*/
+
+#define REGISTER_HASH(h) do {\
+   LTC_ARGCHK(register_hash(h) != -1); \
+} while(0)
+
+int register_all_hashes(void)
+{
+#ifdef LTC_TIGER
+   REGISTER_HASH(&tiger_desc);
+#endif
+#ifdef LTC_MD2
+   REGISTER_HASH(&md2_desc);
+#endif
+#ifdef LTC_MD4
+   REGISTER_HASH(&md4_desc);
+#endif
+#ifdef LTC_MD5
+   REGISTER_HASH(&md5_desc);
+#endif
+#ifdef LTC_SHA1
+   REGISTER_HASH(&sha1_desc);
+#endif
+#ifdef LTC_SHA224
+   REGISTER_HASH(&sha224_desc);
+#endif
+#ifdef LTC_SHA256
+   REGISTER_HASH(&sha256_desc);
+#endif
+#ifdef LTC_SHA384
+   REGISTER_HASH(&sha384_desc);
+#endif
+#ifdef LTC_SHA512
+   REGISTER_HASH(&sha512_desc);
+#endif
+#ifdef LTC_SHA512_224
+   REGISTER_HASH(&sha512_224_desc);
+#endif
+#ifdef LTC_SHA512_256
+   REGISTER_HASH(&sha512_256_desc);
+#endif
+#ifdef LTC_SHA3
+   REGISTER_HASH(&sha3_224_desc);
+   REGISTER_HASH(&sha3_256_desc);
+   REGISTER_HASH(&sha3_384_desc);
+   REGISTER_HASH(&sha3_512_desc);
+#endif
+#ifdef LTC_RIPEMD128
+   REGISTER_HASH(&rmd128_desc);
+#endif
+#ifdef LTC_RIPEMD160
+   REGISTER_HASH(&rmd160_desc);
+#endif
+#ifdef LTC_RIPEMD256
+   REGISTER_HASH(&rmd256_desc);
+#endif
+#ifdef LTC_RIPEMD320
+   REGISTER_HASH(&rmd320_desc);
+#endif
+#ifdef LTC_WHIRLPOOL
+   REGISTER_HASH(&whirlpool_desc);
+#endif
+#ifdef LTC_BLAKE2S
+   REGISTER_HASH(&blake2s_128_desc);
+   REGISTER_HASH(&blake2s_160_desc);
+   REGISTER_HASH(&blake2s_224_desc);
+   REGISTER_HASH(&blake2s_256_desc);
+#endif
+#ifdef LTC_BLAKE2S
+   REGISTER_HASH(&blake2b_160_desc);
+   REGISTER_HASH(&blake2b_256_desc);
+   REGISTER_HASH(&blake2b_384_desc);
+   REGISTER_HASH(&blake2b_512_desc);
+#endif
+#ifdef LTC_CHC_HASH
+   REGISTER_HASH(&chc_desc);
+   LTC_ARGCHK(chc_register(find_cipher_any("aes", 8, 16)) == CRYPT_OK);
+#endif
+   return CRYPT_OK;
+}
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/misc/crypt/crypt_register_all_prngs.c b/libtomcrypt/src/misc/crypt/crypt_register_all_prngs.c
new file mode 100644 (file)
index 0000000..aca8a36
--- /dev/null
@@ -0,0 +1,48 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+#include "tomcrypt.h"
+
+/**
+  @file crypt_register_all_prngs.c
+
+  Steffen Jaeckel
+*/
+
+#define REGISTER_PRNG(h) do {\
+   LTC_ARGCHK(register_prng(h) != -1); \
+} while(0)
+
+int register_all_prngs(void)
+{
+#ifdef LTC_YARROW
+   REGISTER_PRNG(&yarrow_desc);
+#endif
+#ifdef LTC_FORTUNA
+   REGISTER_PRNG(&fortuna_desc);
+#endif
+#ifdef LTC_RC4
+   REGISTER_PRNG(&rc4_desc);
+#endif
+#ifdef LTC_CHACHA20_PRNG
+   REGISTER_PRNG(&chacha20_prng_desc);
+#endif
+#ifdef LTC_SOBER128
+   REGISTER_PRNG(&sober128_desc);
+#endif
+#ifdef LTC_SPRNG
+   REGISTER_PRNG(&sprng_desc);
+#endif
+
+   return CRYPT_OK;
+}
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/misc/crypt/crypt_register_cipher.c b/libtomcrypt/src/misc/crypt/crypt_register_cipher.c
new file mode 100644 (file)
index 0000000..85178d2
--- /dev/null
@@ -0,0 +1,52 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file crypt_register_cipher.c
+  Register a cipher, Tom St Denis
+*/
+
+/**
+   Register a cipher with the descriptor table
+   @param cipher   The cipher you wish to register
+   @return value >= 0 if successfully added (or already present), -1 if unsuccessful
+*/
+int register_cipher(const struct ltc_cipher_descriptor *cipher)
+{
+   int x;
+
+   LTC_ARGCHK(cipher != NULL);
+
+   /* is it already registered? */
+   LTC_MUTEX_LOCK(&ltc_cipher_mutex);
+   for (x = 0; x < TAB_SIZE; x++) {
+       if (cipher_descriptor[x].name != NULL && cipher_descriptor[x].ID == cipher->ID) {
+          LTC_MUTEX_UNLOCK(&ltc_cipher_mutex);
+          return x;
+       }
+   }
+
+   /* find a blank spot */
+   for (x = 0; x < TAB_SIZE; x++) {
+       if (cipher_descriptor[x].name == NULL) {
+          XMEMCPY(&cipher_descriptor[x], cipher, sizeof(struct ltc_cipher_descriptor));
+          LTC_MUTEX_UNLOCK(&ltc_cipher_mutex);
+          return x;
+       }
+   }
+
+   /* no spot */
+   LTC_MUTEX_UNLOCK(&ltc_cipher_mutex);
+   return -1;
+}
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/misc/crypt/crypt_register_hash.c b/libtomcrypt/src/misc/crypt/crypt_register_hash.c
new file mode 100644 (file)
index 0000000..fc7f4e0
--- /dev/null
@@ -0,0 +1,52 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file crypt_register_hash.c
+  Register a HASH, Tom St Denis
+*/
+
+/**
+   Register a hash with the descriptor table
+   @param hash   The hash you wish to register
+   @return value >= 0 if successfully added (or already present), -1 if unsuccessful
+*/
+int register_hash(const struct ltc_hash_descriptor *hash)
+{
+   int x;
+
+   LTC_ARGCHK(hash != NULL);
+
+   /* is it already registered? */
+   LTC_MUTEX_LOCK(&ltc_hash_mutex);
+   for (x = 0; x < TAB_SIZE; x++) {
+       if (XMEMCMP(&hash_descriptor[x], hash, sizeof(struct ltc_hash_descriptor)) == 0) {
+          LTC_MUTEX_UNLOCK(&ltc_hash_mutex);
+          return x;
+       }
+   }
+
+   /* find a blank spot */
+   for (x = 0; x < TAB_SIZE; x++) {
+       if (hash_descriptor[x].name == NULL) {
+          XMEMCPY(&hash_descriptor[x], hash, sizeof(struct ltc_hash_descriptor));
+          LTC_MUTEX_UNLOCK(&ltc_hash_mutex);
+          return x;
+       }
+   }
+
+   /* no spot */
+   LTC_MUTEX_UNLOCK(&ltc_hash_mutex);
+   return -1;
+}
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/misc/crypt/crypt_register_prng.c b/libtomcrypt/src/misc/crypt/crypt_register_prng.c
new file mode 100644 (file)
index 0000000..9cbd634
--- /dev/null
@@ -0,0 +1,52 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file crypt_register_prng.c
+  Register a PRNG, Tom St Denis
+*/
+
+/**
+   Register a PRNG with the descriptor table
+   @param prng   The PRNG you wish to register
+   @return value >= 0 if successfully added (or already present), -1 if unsuccessful
+*/
+int register_prng(const struct ltc_prng_descriptor *prng)
+{
+   int x;
+
+   LTC_ARGCHK(prng != NULL);
+
+   /* is it already registered? */
+   LTC_MUTEX_LOCK(&ltc_prng_mutex);
+   for (x = 0; x < TAB_SIZE; x++) {
+       if (XMEMCMP(&prng_descriptor[x], prng, sizeof(struct ltc_prng_descriptor)) == 0) {
+          LTC_MUTEX_UNLOCK(&ltc_prng_mutex);
+          return x;
+       }
+   }
+
+   /* find a blank spot */
+   for (x = 0; x < TAB_SIZE; x++) {
+       if (prng_descriptor[x].name == NULL) {
+          XMEMCPY(&prng_descriptor[x], prng, sizeof(struct ltc_prng_descriptor));
+          LTC_MUTEX_UNLOCK(&ltc_prng_mutex);
+          return x;
+       }
+   }
+
+   /* no spot */
+   LTC_MUTEX_UNLOCK(&ltc_prng_mutex);
+   return -1;
+}
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/misc/crypt/crypt_sizes.c b/libtomcrypt/src/misc/crypt/crypt_sizes.c
new file mode 100644 (file)
index 0000000..dd857ea
--- /dev/null
@@ -0,0 +1,348 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file crypt_sizes.c
+
+  Make various struct sizes available to dynamic languages
+  like Python - Larry Bugbee, February 2013
+
+  LB - Dec 2013 - revised to include compiler define options
+*/
+
+
+typedef struct {
+    const char *name;
+    const unsigned int size;
+} crypt_size;
+
+#define _SZ_STRINGIFY_S(s) { #s, sizeof(struct s) }
+#define _SZ_STRINGIFY_T(s) { #s, sizeof(s) }
+
+static const crypt_size _crypt_sizes[] = {
+    /* hash state sizes */
+    _SZ_STRINGIFY_S(ltc_hash_descriptor),
+    _SZ_STRINGIFY_T(hash_state),
+#ifdef LTC_CHC_HASH
+    _SZ_STRINGIFY_S(chc_state),
+#endif
+#ifdef LTC_WHIRLPOOL
+    _SZ_STRINGIFY_S(whirlpool_state),
+#endif
+#ifdef LTC_SHA3
+    _SZ_STRINGIFY_S(sha3_state),
+#endif
+#ifdef LTC_SHA512
+    _SZ_STRINGIFY_S(sha512_state),
+#endif
+#ifdef LTC_SHA256
+    _SZ_STRINGIFY_S(sha256_state),
+#endif
+#ifdef LTC_SHA1
+    _SZ_STRINGIFY_S(sha1_state),
+#endif
+#ifdef LTC_MD5
+    _SZ_STRINGIFY_S(md5_state),
+#endif
+#ifdef LTC_MD4
+    _SZ_STRINGIFY_S(md4_state),
+#endif
+#ifdef LTC_MD2
+    _SZ_STRINGIFY_S(md2_state),
+#endif
+#ifdef LTC_TIGER
+    _SZ_STRINGIFY_S(tiger_state),
+#endif
+#ifdef LTC_RIPEMD128
+    _SZ_STRINGIFY_S(rmd128_state),
+#endif
+#ifdef LTC_RIPEMD160
+    _SZ_STRINGIFY_S(rmd160_state),
+#endif
+#ifdef LTC_RIPEMD256
+    _SZ_STRINGIFY_S(rmd256_state),
+#endif
+#ifdef LTC_RIPEMD320
+    _SZ_STRINGIFY_S(rmd320_state),
+#endif
+#ifdef LTC_BLAKE2S
+    _SZ_STRINGIFY_S(blake2s_state),
+#endif
+#ifdef LTC_BLAKE2B
+    _SZ_STRINGIFY_S(blake2b_state),
+#endif
+
+    /* block cipher key sizes */
+    _SZ_STRINGIFY_S(ltc_cipher_descriptor),
+    _SZ_STRINGIFY_T(symmetric_key),
+#ifdef LTC_ANUBIS
+    _SZ_STRINGIFY_S(anubis_key),
+#endif
+#ifdef LTC_CAMELLIA
+    _SZ_STRINGIFY_S(camellia_key),
+#endif
+#ifdef LTC_BLOWFISH
+    _SZ_STRINGIFY_S(blowfish_key),
+#endif
+#ifdef LTC_CAST5
+    _SZ_STRINGIFY_S(cast5_key),
+#endif
+#ifdef LTC_DES
+    _SZ_STRINGIFY_S(des_key),
+    _SZ_STRINGIFY_S(des3_key),
+#endif
+#ifdef LTC_KASUMI
+    _SZ_STRINGIFY_S(kasumi_key),
+#endif
+#ifdef LTC_KHAZAD
+    _SZ_STRINGIFY_S(khazad_key),
+#endif
+#ifdef LTC_KSEED
+    _SZ_STRINGIFY_S(kseed_key),
+#endif
+#ifdef LTC_MULTI2
+    _SZ_STRINGIFY_S(multi2_key),
+#endif
+#ifdef LTC_NOEKEON
+    _SZ_STRINGIFY_S(noekeon_key),
+#endif
+#ifdef LTC_RC2
+    _SZ_STRINGIFY_S(rc2_key),
+#endif
+#ifdef LTC_RC5
+    _SZ_STRINGIFY_S(rc5_key),
+#endif
+#ifdef LTC_RC6
+    _SZ_STRINGIFY_S(rc6_key),
+#endif
+#ifdef LTC_SKIPJACK
+    _SZ_STRINGIFY_S(skipjack_key),
+#endif
+#ifdef LTC_XTEA
+    _SZ_STRINGIFY_S(xtea_key),
+#endif
+#ifdef LTC_RIJNDAEL
+    _SZ_STRINGIFY_S(rijndael_key),
+#endif
+#ifdef LTC_SAFER
+    _SZ_STRINGIFY_S(safer_key),
+#endif
+#ifdef LTC_SAFERP
+    _SZ_STRINGIFY_S(saferp_key),
+#endif
+#ifdef LTC_TWOFISH
+    _SZ_STRINGIFY_S(twofish_key),
+#endif
+
+    /* mode sizes */
+#ifdef LTC_ECB_MODE
+    _SZ_STRINGIFY_T(symmetric_ECB),
+#endif
+#ifdef LTC_CFB_MODE
+    _SZ_STRINGIFY_T(symmetric_CFB),
+#endif
+#ifdef LTC_OFB_MODE
+    _SZ_STRINGIFY_T(symmetric_OFB),
+#endif
+#ifdef LTC_CBC_MODE
+    _SZ_STRINGIFY_T(symmetric_CBC),
+#endif
+#ifdef LTC_CTR_MODE
+    _SZ_STRINGIFY_T(symmetric_CTR),
+#endif
+#ifdef LTC_LRW_MODE
+    _SZ_STRINGIFY_T(symmetric_LRW),
+#endif
+#ifdef LTC_F8_MODE
+    _SZ_STRINGIFY_T(symmetric_F8),
+#endif
+#ifdef LTC_XTS_MODE
+    _SZ_STRINGIFY_T(symmetric_xts),
+#endif
+
+    /* stream cipher sizes */
+#ifdef LTC_CHACHA
+    _SZ_STRINGIFY_T(chacha_state),
+#endif
+#ifdef LTC_RC4_STREAM
+    _SZ_STRINGIFY_T(rc4_state),
+#endif
+#ifdef LTC_SOBER128_STREAM
+    _SZ_STRINGIFY_T(sober128_state),
+#endif
+
+    /* MAC sizes            -- no states for ccm, lrw */
+#ifdef LTC_HMAC
+    _SZ_STRINGIFY_T(hmac_state),
+#endif
+#ifdef LTC_OMAC
+    _SZ_STRINGIFY_T(omac_state),
+#endif
+#ifdef LTC_PMAC
+    _SZ_STRINGIFY_T(pmac_state),
+#endif
+#ifdef LTC_POLY1305
+    _SZ_STRINGIFY_T(poly1305_state),
+#endif
+#ifdef LTC_EAX_MODE
+    _SZ_STRINGIFY_T(eax_state),
+#endif
+#ifdef LTC_OCB_MODE
+    _SZ_STRINGIFY_T(ocb_state),
+#endif
+#ifdef LTC_OCB3_MODE
+    _SZ_STRINGIFY_T(ocb3_state),
+#endif
+#ifdef LTC_CCM_MODE
+    _SZ_STRINGIFY_T(ccm_state),
+#endif
+#ifdef LTC_GCM_MODE
+    _SZ_STRINGIFY_T(gcm_state),
+#endif
+#ifdef LTC_PELICAN
+    _SZ_STRINGIFY_T(pelican_state),
+#endif
+#ifdef LTC_XCBC
+    _SZ_STRINGIFY_T(xcbc_state),
+#endif
+#ifdef LTC_F9_MODE
+    _SZ_STRINGIFY_T(f9_state),
+#endif
+#ifdef LTC_CHACHA20POLY1305_MODE
+    _SZ_STRINGIFY_T(chacha20poly1305_state),
+#endif
+
+    /* asymmetric keys */
+#ifdef LTC_MRSA
+    _SZ_STRINGIFY_T(rsa_key),
+#endif
+#ifdef LTC_MDSA
+    _SZ_STRINGIFY_T(dsa_key),
+#endif
+#ifdef LTC_MDH
+    _SZ_STRINGIFY_T(dh_key),
+#endif
+#ifdef LTC_MECC
+    _SZ_STRINGIFY_T(ltc_ecc_set_type),
+    _SZ_STRINGIFY_T(ecc_point),
+    _SZ_STRINGIFY_T(ecc_key),
+#endif
+#ifdef LTC_MKAT
+    _SZ_STRINGIFY_T(katja_key),
+#endif
+
+    /* DER handling */
+#ifdef LTC_DER
+    _SZ_STRINGIFY_T(ltc_asn1_list),  /* a list entry */
+    _SZ_STRINGIFY_T(ltc_utctime),
+    _SZ_STRINGIFY_T(ltc_generalizedtime),
+#endif
+
+    /* prng state sizes */
+    _SZ_STRINGIFY_S(ltc_prng_descriptor),
+    _SZ_STRINGIFY_T(prng_state),
+#ifdef LTC_FORTUNA
+    _SZ_STRINGIFY_S(fortuna_prng),
+#endif
+#ifdef LTC_CHACHA20_PRNG
+    _SZ_STRINGIFY_S(chacha20_prng),
+#endif
+#ifdef LTC_RC4
+    _SZ_STRINGIFY_S(rc4_prng),
+#endif
+#ifdef LTC_SOBER128
+    _SZ_STRINGIFY_S(sober128_prng),
+#endif
+#ifdef LTC_YARROW
+    _SZ_STRINGIFY_S(yarrow_prng),
+#endif
+    /* sprng has no state as it uses other potentially available sources */
+    /* like /dev/random.  See Developers Guide for more info. */
+
+#ifdef LTC_ADLER32
+    _SZ_STRINGIFY_T(adler32_state),
+#endif
+#ifdef LTC_CRC32
+    _SZ_STRINGIFY_T(crc32_state),
+#endif
+
+    _SZ_STRINGIFY_T(ltc_mp_digit),
+    _SZ_STRINGIFY_T(ltc_math_descriptor)
+
+};
+
+/* crypt_get_size()
+ * sizeout will be the size (bytes) of the named struct or union
+ * return -1 if named item not found
+ */
+int crypt_get_size(const char* namein, unsigned int *sizeout) {
+    int i;
+    int count = sizeof(_crypt_sizes) / sizeof(_crypt_sizes[0]);
+    for (i=0; i<count; i++) {
+        if (XSTRCMP(_crypt_sizes[i].name, namein) == 0) {
+            *sizeout = _crypt_sizes[i].size;
+            return 0;
+        }
+    }
+    return -1;
+}
+
+/* crypt_list_all_sizes()
+ * if names_list is NULL, names_list_size will be the minimum
+ *     size needed to receive the complete names_list
+ * if names_list is NOT NULL, names_list must be the addr with
+ *     sufficient memory allocated into which the names_list
+ *     is to be written.  Also, the value in names_list_size
+ *     sets the upper bound of the number of characters to be
+ *     written.
+ * a -1 return value signifies insufficient space made available
+ */
+int crypt_list_all_sizes(char *names_list, unsigned int *names_list_size) {
+    int i;
+    unsigned int total_len = 0;
+    char *ptr;
+    int number_len;
+    int count = sizeof(_crypt_sizes) / sizeof(_crypt_sizes[0]);
+
+    /* calculate amount of memory required for the list */
+    for (i=0; i<count; i++) {
+        number_len = snprintf(NULL, 0, "%s,%u\n", _crypt_sizes[i].name, _crypt_sizes[i].size);
+        if (number_len < 0)
+          return -1;
+        total_len += number_len;
+        /* this last +1 is for newlines (and ending NULL) */
+    }
+
+    if (names_list == NULL) {
+        *names_list_size = total_len;
+    } else {
+        if (total_len > *names_list_size) {
+            return -1;
+        }
+        /* build the names list */
+        ptr = names_list;
+        for (i=0; i<count; i++) {
+            number_len = snprintf(ptr, total_len, "%s,%u\n", _crypt_sizes[i].name, _crypt_sizes[i].size);
+            if (number_len < 0) return -1;
+            if ((unsigned int)number_len > total_len) return -1;
+            total_len -= number_len;
+            ptr += number_len;
+        }
+        /* to remove the trailing new-line */
+        ptr -= 1;
+        *ptr = 0;
+    }
+    return 0;
+}
+
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/misc/crypt/crypt_unregister_cipher.c b/libtomcrypt/src/misc/crypt/crypt_unregister_cipher.c
new file mode 100644 (file)
index 0000000..b57c736
--- /dev/null
@@ -0,0 +1,43 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file crypt_unregister_cipher.c
+  Unregister a cipher, Tom St Denis
+*/
+
+/**
+  Unregister a cipher from the descriptor table
+  @param cipher   The cipher descriptor to remove
+  @return CRYPT_OK on success
+*/
+int unregister_cipher(const struct ltc_cipher_descriptor *cipher)
+{
+   int x;
+
+   LTC_ARGCHK(cipher != NULL);
+
+   /* is it already registered? */
+   LTC_MUTEX_LOCK(&ltc_cipher_mutex);
+   for (x = 0; x < TAB_SIZE; x++) {
+       if (XMEMCMP(&cipher_descriptor[x], cipher, sizeof(struct ltc_cipher_descriptor)) == 0) {
+          cipher_descriptor[x].name = NULL;
+          cipher_descriptor[x].ID   = 255;
+          LTC_MUTEX_UNLOCK(&ltc_cipher_mutex);
+          return CRYPT_OK;
+       }
+   }
+   LTC_MUTEX_UNLOCK(&ltc_cipher_mutex);
+   return CRYPT_ERROR;
+}
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/misc/crypt/crypt_unregister_hash.c b/libtomcrypt/src/misc/crypt/crypt_unregister_hash.c
new file mode 100644 (file)
index 0000000..dbbff33
--- /dev/null
@@ -0,0 +1,42 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file crypt_unregister_hash.c
+  Unregister a hash, Tom St Denis
+*/
+
+/**
+  Unregister a hash from the descriptor table
+  @param hash   The hash descriptor to remove
+  @return CRYPT_OK on success
+*/
+int unregister_hash(const struct ltc_hash_descriptor *hash)
+{
+   int x;
+
+   LTC_ARGCHK(hash != NULL);
+
+   /* is it already registered? */
+   LTC_MUTEX_LOCK(&ltc_hash_mutex);
+   for (x = 0; x < TAB_SIZE; x++) {
+       if (XMEMCMP(&hash_descriptor[x], hash, sizeof(struct ltc_hash_descriptor)) == 0) {
+          hash_descriptor[x].name = NULL;
+          LTC_MUTEX_UNLOCK(&ltc_hash_mutex);
+          return CRYPT_OK;
+       }
+   }
+   LTC_MUTEX_UNLOCK(&ltc_hash_mutex);
+   return CRYPT_ERROR;
+}
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/misc/crypt/crypt_unregister_prng.c b/libtomcrypt/src/misc/crypt/crypt_unregister_prng.c
new file mode 100644 (file)
index 0000000..f7606ef
--- /dev/null
@@ -0,0 +1,42 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file crypt_unregister_prng.c
+  Unregister a PRNG, Tom St Denis
+*/
+
+/**
+  Unregister a PRNG from the descriptor table
+  @param prng   The PRNG descriptor to remove
+  @return CRYPT_OK on success
+*/
+int unregister_prng(const struct ltc_prng_descriptor *prng)
+{
+   int x;
+
+   LTC_ARGCHK(prng != NULL);
+
+   /* is it already registered? */
+   LTC_MUTEX_LOCK(&ltc_prng_mutex);
+   for (x = 0; x < TAB_SIZE; x++) {
+       if (XMEMCMP(&prng_descriptor[x], prng, sizeof(struct ltc_prng_descriptor)) == 0) {
+          prng_descriptor[x].name = NULL;
+          LTC_MUTEX_UNLOCK(&ltc_prng_mutex);
+          return CRYPT_OK;
+       }
+   }
+   LTC_MUTEX_UNLOCK(&ltc_prng_mutex);
+   return CRYPT_ERROR;
+}
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/misc/error_to_string.c b/libtomcrypt/src/misc/error_to_string.c
new file mode 100644 (file)
index 0000000..707f835
--- /dev/null
@@ -0,0 +1,79 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+#include "tomcrypt.h"
+
+/**
+  @file error_to_string.c
+  Convert error codes to ASCII strings, Tom St Denis
+*/
+
+static const char * const err_2_str[] =
+{
+   "CRYPT_OK",
+   "CRYPT_ERROR",
+   "Non-fatal 'no-operation' requested.",
+
+   "Invalid key size.",
+   "Invalid number of rounds for block cipher.",
+   "Algorithm failed test vectors.",
+
+   "Buffer overflow.",
+   "Invalid input packet.",
+
+   "Invalid number of bits for a PRNG.",
+   "Error reading the PRNG.",
+
+   "Invalid cipher specified.",
+   "Invalid hash specified.",
+   "Invalid PRNG specified.",
+
+   "Out of memory.",
+
+   "Invalid PK key or key type specified for function.",
+   "A private PK key is required.",
+
+   "Invalid argument provided.",
+   "File Not Found",
+
+   "Invalid PK type.",
+
+   "An overflow of a value was detected/prevented.",
+
+   "UNUSED1.",
+
+   "The input was longer than expected.",
+
+   "Invalid sized parameter.",
+
+   "Invalid size for prime.",
+
+   "Invalid padding.",
+
+   "Hash applied to too many bits.",
+};
+
+/**
+   Convert an LTC error code to ASCII
+   @param err    The error code
+   @return A pointer to the ASCII NUL terminated string for the error or "Invalid error code." if the err code was not valid.
+*/
+const char *error_to_string(int err)
+{
+   if (err < 0 || err >= (int)(sizeof(err_2_str)/sizeof(err_2_str[0]))) {
+      return "Invalid error code.";
+   } else {
+      return err_2_str[err];
+   }
+}
+
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/misc/hkdf/hkdf.c b/libtomcrypt/src/misc/hkdf/hkdf.c
new file mode 100644 (file)
index 0000000..0db4ed9
--- /dev/null
@@ -0,0 +1,143 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "tomcrypt.h"
+
+#ifdef LTC_HKDF
+
+/* This is mostly just a wrapper around hmac_memory */
+int hkdf_extract(int hash_idx, const unsigned char *salt, unsigned long  saltlen,
+                               const unsigned char *in,   unsigned long  inlen,
+                                     unsigned char *out,  unsigned long *outlen)
+{
+   /* libtomcrypt chokes on a zero length HMAC key, so we need to check for
+      that.  HMAC specifies that keys shorter than the hash's blocksize are
+      0 padded to the block size.  HKDF specifies that a NULL salt is to be
+      substituted with a salt comprised of hashLen 0 bytes.  HMAC's padding
+      means that in either case the HMAC is actually using a blocksize long
+      zero filled key.  Unless blocksize < hashLen (which wouldn't make any
+      sense), we can use a single 0 byte as the HMAC key and still generate
+      valid results for HKDF. */
+   if (salt == NULL || saltlen == 0) {
+      return hmac_memory(hash_idx, (const unsigned char *)"",   1,       in, inlen, out, outlen);
+   } else {
+      return hmac_memory(hash_idx, salt, saltlen, in, inlen, out, outlen);
+   }
+}
+
+int hkdf_expand(int hash_idx, const unsigned char *info, unsigned long infolen,
+                              const unsigned char *in,   unsigned long inlen,
+                                    unsigned char *out,  unsigned long outlen)
+{
+   unsigned long hashsize;
+   int err;
+   unsigned char N;
+   unsigned long Noutlen, outoff;
+
+   unsigned char *T,  *dat;
+   unsigned long Tlen, datlen;
+
+   /* make sure hash descriptor is valid */
+   if ((err = hash_is_valid(hash_idx)) != CRYPT_OK) {
+      return err;
+   }
+
+   hashsize = hash_descriptor[hash_idx].hashsize;
+
+   /* RFC5869 parameter restrictions */
+   if (inlen < hashsize || outlen > hashsize * 255)
+      return CRYPT_INVALID_ARG;
+   if (info == NULL && infolen != 0)
+      return CRYPT_INVALID_ARG;
+   LTC_ARGCHK(out != NULL);
+
+   Tlen = hashsize + infolen + 1;
+   T = XMALLOC(Tlen); /* Replace with static buffer? */
+   if (T == NULL) {
+      return CRYPT_MEM;
+   }
+   if (info != NULL) {
+      XMEMCPY(T + hashsize, info, infolen);
+   }
+
+   /* HMAC data T(1) doesn't include a previous hash value */
+   dat    = T    + hashsize;
+   datlen = Tlen - hashsize;
+
+   N = 0;
+   outoff = 0; /* offset in out to write to */
+   while (1) { /* an exit condition breaks mid-loop */
+      Noutlen = MIN(hashsize, outlen - outoff);
+      T[Tlen - 1] = ++N;
+      if ((err = hmac_memory(hash_idx, in, inlen, dat, datlen,
+                             out + outoff, &Noutlen)) != CRYPT_OK) {
+         zeromem(T, Tlen);
+         XFREE(T);
+         return err;
+      }
+      outoff += Noutlen;
+
+      if (outoff >= outlen) /* loop exit condition */
+         break;
+
+      /* All subsequent HMAC data T(N) DOES include the previous hash value */
+      XMEMCPY(T, out + hashsize * (N-1), hashsize);
+      if (N == 1) {
+         dat = T;
+         datlen = Tlen;
+      }
+   }
+   zeromem(T, Tlen);
+   XFREE(T);
+   return CRYPT_OK;
+}
+
+/* all in one step */
+int hkdf(int hash_idx, const unsigned char *salt, unsigned long saltlen,
+                       const unsigned char *info, unsigned long infolen,
+                       const unsigned char *in,   unsigned long inlen,
+                             unsigned char *out,  unsigned long outlen)
+{
+   unsigned long hashsize;
+   int err;
+   unsigned char *extracted;
+
+   /* make sure hash descriptor is valid */
+   if ((err = hash_is_valid(hash_idx)) != CRYPT_OK) {
+      return err;
+   }
+
+   hashsize = hash_descriptor[hash_idx].hashsize;
+
+   extracted = XMALLOC(hashsize); /* replace with static buffer? */
+   if (extracted == NULL) {
+      return CRYPT_MEM;
+   }
+   if ((err = hkdf_extract(hash_idx, salt, saltlen, in, inlen, extracted, &hashsize)) != 0) {
+      zeromem(extracted, hashsize);
+      XFREE(extracted);
+      return err;
+   }
+   err = hkdf_expand(hash_idx, info, infolen, extracted, hashsize, out, outlen);
+   zeromem(extracted, hashsize);
+   XFREE(extracted);
+   return err;
+}
+#endif /* LTC_HKDF */
+
+
+/* vim: set ts=2 sw=2 et ai si: */
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/misc/hkdf/hkdf_test.c b/libtomcrypt/src/misc/hkdf/hkdf_test.c
new file mode 100644 (file)
index 0000000..0c58255
--- /dev/null
@@ -0,0 +1,294 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file hkdf_test.c
+  LTC_HKDF support, self-test, Steffen Jaeckel
+*/
+
+#ifdef LTC_HKDF
+
+/*
+    TEST CASES SOURCE:
+
+Internet Engineering Task Force (IETF)                       H. Krawczyk
+Request for Comments: 5869                                  IBM Research
+Category: Informational                                        P. Eronen
+ISSN: 2070-1721                                                    Nokia
+                                                                May 2010
+Appendix A. Test Vectors
+*/
+
+/**
+  LTC_HKDF self-test
+  @return CRYPT_OK if successful, CRYPT_NOP if tests have been disabled.
+*/
+int hkdf_test(void)
+{
+ #ifndef LTC_TEST
+    return CRYPT_NOP;
+ #else
+    unsigned char OKM[82];
+    int i;
+
+    static const struct hkdf_test_case {
+        int num;
+        const char* Hash;
+        unsigned char IKM[80];
+        unsigned long IKM_l;
+        unsigned char salt[80];
+        unsigned long salt_l;
+        unsigned char info[80];
+        unsigned long info_l;
+        unsigned char PRK[32];
+        unsigned long PRK_l;
+        unsigned char OKM[82];
+        unsigned long OKM_l;
+    } cases[] = {
+#ifdef LTC_SHA256
+        /*
+           Basic test case with SHA-256
+
+           Hash = SHA-256
+           IKM  = 0x0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b (22 octets)
+           salt = 0x000102030405060708090a0b0c (13 octets)
+           info = 0xf0f1f2f3f4f5f6f7f8f9 (10 octets)
+           L    = 42
+
+           PRK  = 0x077709362c2e32df0ddc3f0dc47bba63
+                  90b6c73bb50f9c3122ec844ad7c2b3e5 (32 octets)
+           OKM  = 0x3cb25f25faacd57a90434f64d0362f2a
+                  2d2d0a90cf1a5a4c5db02d56ecc4c5bf
+                  34007208d5b887185865 (42 octets)
+        */
+           {1, "sha256",
+            {0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+             0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+             0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b}, 22,
+            {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+             0x08, 0x09, 0x0a, 0x0b, 0x0c}, 13,
+            {0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
+             0xf8, 0xf9}, 10,
+            {0x07, 0x77, 0x09, 0x36, 0x2c, 0x2e, 0x32, 0xdf,
+             0x0d, 0xdc, 0x3f, 0x0d, 0xc4, 0x7b, 0xba, 0x63,
+             0x90, 0xb6, 0xc7, 0x3b, 0xb5, 0x0f, 0x9c, 0x31,
+             0x22, 0xec, 0x84, 0x4a, 0xd7, 0xc2, 0xb3, 0xe5}, 32,
+            {0x3c, 0xb2, 0x5f, 0x25, 0xfa, 0xac, 0xd5, 0x7a,
+             0x90, 0x43, 0x4f, 0x64, 0xd0, 0x36, 0x2f, 0x2a,
+             0x2d, 0x2d, 0x0a, 0x90, 0xcf, 0x1a, 0x5a, 0x4c,
+             0x5d, 0xb0, 0x2d, 0x56, 0xec, 0xc4, 0xc5, 0xbf,
+             0x34, 0x00, 0x72, 0x08, 0xd5, 0xb8, 0x87, 0x18,
+             0x58, 0x65}, 42},
+#ifdef LTC_TEST_EXT
+       /* Test with SHA-256 and longer inputs/outputs */
+           {2, "sha256",
+            {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,
+             0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+             0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+             0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+             0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+             0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+             0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f}, 80,
+            {0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+             0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
+             0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
+             0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
+             0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+             0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
+             0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
+             0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
+             0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
+             0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf}, 80,
+            {0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
+             0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
+             0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
+             0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
+             0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
+             0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
+             0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
+             0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
+             0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
+             0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff}, 80,
+            {0x06, 0xa6, 0xb8, 0x8c, 0x58, 0x53, 0x36, 0x1a,
+             0x06, 0x10, 0x4c, 0x9c, 0xeb, 0x35, 0xb4, 0x5c,
+             0xef, 0x76, 0x00, 0x14, 0x90, 0x46, 0x71, 0x01,
+             0x4a, 0x19, 0x3f, 0x40, 0xc1, 0x5f, 0xc2, 0x44}, 32,
+            {0xb1, 0x1e, 0x39, 0x8d, 0xc8, 0x03, 0x27, 0xa1,
+             0xc8, 0xe7, 0xf7, 0x8c, 0x59, 0x6a, 0x49, 0x34,
+             0x4f, 0x01, 0x2e, 0xda, 0x2d, 0x4e, 0xfa, 0xd8,
+             0xa0, 0x50, 0xcc, 0x4c, 0x19, 0xaf, 0xa9, 0x7c,
+             0x59, 0x04, 0x5a, 0x99, 0xca, 0xc7, 0x82, 0x72,
+             0x71, 0xcb, 0x41, 0xc6, 0x5e, 0x59, 0x0e, 0x09,
+             0xda, 0x32, 0x75, 0x60, 0x0c, 0x2f, 0x09, 0xb8,
+             0x36, 0x77, 0x93, 0xa9, 0xac, 0xa3, 0xdb, 0x71,
+             0xcc, 0x30, 0xc5, 0x81, 0x79, 0xec, 0x3e, 0x87,
+             0xc1, 0x4c, 0x01, 0xd5, 0xc1, 0xf3, 0x43, 0x4f,
+             0x1d, 0x87}, 82},
+       /* Test with SHA-256 and zero length salt/info */
+           {3, "sha256",
+            {0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+             0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+             0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b}, 22,
+            {0}, 0,
+            {0}, 0,
+            {0x19, 0xef, 0x24, 0xa3, 0x2c, 0x71, 0x7b, 0x16,
+             0x7f, 0x33, 0xa9, 0x1d, 0x6f, 0x64, 0x8b, 0xdf,
+             0x96, 0x59, 0x67, 0x76, 0xaf, 0xdb, 0x63, 0x77,
+             0xac, 0x43, 0x4c, 0x1c, 0x29, 0x3c, 0xcb, 0x04}, 32,
+            {0x8d, 0xa4, 0xe7, 0x75, 0xa5, 0x63, 0xc1, 0x8f,
+             0x71, 0x5f, 0x80, 0x2a, 0x06, 0x3c, 0x5a, 0x31,
+             0xb8, 0xa1, 0x1f, 0x5c, 0x5e, 0xe1, 0x87, 0x9e,
+             0xc3, 0x45, 0x4e, 0x5f, 0x3c, 0x73, 0x8d, 0x2d,
+             0x9d, 0x20, 0x13, 0x95, 0xfa, 0xa4, 0xb6, 0x1a,
+             0x96, 0xc8}, 42},
+#endif /* LTC_TEST_EXT */
+#endif /* LTC_SHA256 */
+#ifdef LTC_SHA1
+       /* Basic test case with SHA-1 */
+           {4, "sha1",
+            {0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+             0x0b, 0x0b, 0x0b}, 11,
+            {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+             0x08, 0x09, 0x0a, 0x0b, 0x0c}, 13,
+            {0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
+             0xf8, 0xf9}, 10,
+            {0x9b, 0x6c, 0x18, 0xc4, 0x32, 0xa7, 0xbf, 0x8f,
+             0x0e, 0x71, 0xc8, 0xeb, 0x88, 0xf4, 0xb3, 0x0b,
+             0xaa, 0x2b, 0xa2, 0x43}, 20,
+            {0x08, 0x5a, 0x01, 0xea, 0x1b, 0x10, 0xf3, 0x69,
+             0x33, 0x06, 0x8b, 0x56, 0xef, 0xa5, 0xad, 0x81,
+             0xa4, 0xf1, 0x4b, 0x82, 0x2f, 0x5b, 0x09, 0x15,
+             0x68, 0xa9, 0xcd, 0xd4, 0xf1, 0x55, 0xfd, 0xa2,
+             0xc2, 0x2e, 0x42, 0x24, 0x78, 0xd3, 0x05, 0xf3,
+             0xf8, 0x96}, 42},
+#ifdef LTC_TEST_EXT
+       /* Test with SHA-1 and longer inputs/outputs */
+           {5, "sha1",
+            {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,
+             0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+             0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+             0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+             0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+             0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+             0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f}, 80,
+            {0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+             0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
+             0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
+             0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
+             0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+             0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
+             0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
+             0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
+             0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
+             0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf}, 80,
+            {0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
+             0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
+             0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
+             0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
+             0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
+             0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
+             0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
+             0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
+             0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
+             0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff}, 80,
+            {0x8a, 0xda, 0xe0, 0x9a, 0x2a, 0x30, 0x70, 0x59,
+             0x47, 0x8d, 0x30, 0x9b, 0x26, 0xc4, 0x11, 0x5a,
+             0x22, 0x4c, 0xfa, 0xf6}, 20,
+            {0x0b, 0xd7, 0x70, 0xa7, 0x4d, 0x11, 0x60, 0xf7,
+             0xc9, 0xf1, 0x2c, 0xd5, 0x91, 0x2a, 0x06, 0xeb,
+             0xff, 0x6a, 0xdc, 0xae, 0x89, 0x9d, 0x92, 0x19,
+             0x1f, 0xe4, 0x30, 0x56, 0x73, 0xba, 0x2f, 0xfe,
+             0x8f, 0xa3, 0xf1, 0xa4, 0xe5, 0xad, 0x79, 0xf3,
+             0xf3, 0x34, 0xb3, 0xb2, 0x02, 0xb2, 0x17, 0x3c,
+             0x48, 0x6e, 0xa3, 0x7c, 0xe3, 0xd3, 0x97, 0xed,
+             0x03, 0x4c, 0x7f, 0x9d, 0xfe, 0xb1, 0x5c, 0x5e,
+             0x92, 0x73, 0x36, 0xd0, 0x44, 0x1f, 0x4c, 0x43,
+             0x00, 0xe2, 0xcf, 0xf0, 0xd0, 0x90, 0x0b, 0x52,
+             0xd3, 0xb4}, 82},
+       /* Test with SHA-1 and zero-length salt/info */
+           {6, "sha1",
+            {0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+             0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+             0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b}, 22,
+            {0}, 0,
+            {0}, 0,
+            {0xda, 0x8c, 0x8a, 0x73, 0xc7, 0xfa, 0x77, 0x28,
+             0x8e, 0xc6, 0xf5, 0xe7, 0xc2, 0x97, 0x78, 0x6a,
+             0xa0, 0xd3, 0x2d, 0x01}, 20,
+            {0x0a, 0xc1, 0xaf, 0x70, 0x02, 0xb3, 0xd7, 0x61,
+             0xd1, 0xe5, 0x52, 0x98, 0xda, 0x9d, 0x05, 0x06,
+             0xb9, 0xae, 0x52, 0x05, 0x72, 0x20, 0xa3, 0x06,
+             0xe0, 0x7b, 0x6b, 0x87, 0xe8, 0xdf, 0x21, 0xd0,
+             0xea, 0x00, 0x03, 0x3d, 0xe0, 0x39, 0x84, 0xd3,
+             0x49, 0x18}, 42},
+       /* Test with SHA-1, salt not provided (defaults to HashLen zero octets),
+          zero-length info */
+           {7, "sha1",
+            {0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+             0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+             0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c}, 22,
+            {0}, 0, /* pass a null pointer */
+            {0}, 0,
+            {0x2a, 0xdc, 0xca, 0xda, 0x18, 0x77, 0x9e, 0x7c,
+             0x20, 0x77, 0xad, 0x2e, 0xb1, 0x9d, 0x3f, 0x3e,
+             0x73, 0x13, 0x85, 0xdd}, 20,
+            {0x2c, 0x91, 0x11, 0x72, 0x04, 0xd7, 0x45, 0xf3,
+             0x50, 0x0d, 0x63, 0x6a, 0x62, 0xf6, 0x4f, 0x0a,
+             0xb3, 0xba, 0xe5, 0x48, 0xaa, 0x53, 0xd4, 0x23,
+             0xb0, 0xd1, 0xf2, 0x7e, 0xbb, 0xa6, 0xf5, 0xe5,
+             0x67, 0x3a, 0x08, 0x1d, 0x70, 0xcc, 0xe7, 0xac,
+             0xfc, 0x48}, 42},
+#endif /* LTC_TEST_EXT */
+#endif /* LTC_SHA1 */
+    };
+
+    int err;
+    int tested=0,failed=0;
+    for(i=0; i < (int)(sizeof(cases) / sizeof(cases[0])); i++) {
+        int hash = find_hash(cases[i].Hash);
+        if (hash == -1) continue;
+        ++tested;
+        if((err = hkdf(hash, cases[i].salt, cases[i].salt_l,
+                        cases[i].info, cases[i].info_l,
+                        cases[i].IKM,   cases[i].IKM_l,
+                        OKM, cases[i].OKM_l)) != CRYPT_OK) {
+#if defined(LTC_TEST_DBG) && (LTC_TEST_DBG > 1)
+            printf("LTC_HKDF-%s test #%d, %s\n", cases[i].Hash, i, error_to_string(err));
+#endif
+            return err;
+        }
+
+        if(compare_testvector(OKM, cases[i].OKM_l, cases[i].OKM, (size_t)cases[i].OKM_l, "HKDF", cases[i].num)) {
+            failed++;
+        }
+    }
+
+    if (failed != 0) {
+        return CRYPT_FAIL_TESTVECTOR;
+    } else if (tested == 0) {
+        return CRYPT_NOP;
+    } else {
+        return CRYPT_OK;
+    }
+ #endif
+}
+
+#endif
+
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/misc/mem_neq.c b/libtomcrypt/src/misc/mem_neq.c
new file mode 100644 (file)
index 0000000..fbd0cce
--- /dev/null
@@ -0,0 +1,63 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+   @file mem_neq.c
+   Compare two blocks of memory for inequality in constant time.
+   Steffen Jaeckel
+*/
+
+/**
+   Compare two blocks of memory for inequality in constant time.
+
+   The usage is similar to that of standard memcmp, but you can only test
+   if the memory is equal or not - you can not determine by how much the
+   first different byte differs.
+
+   This function shall be used to compare results of cryptographic
+   operations where inequality means most likely usage of a wrong key.
+   The execution time has therefore to be constant as otherwise
+   timing attacks could be possible.
+
+   @param a     The first memory region
+   @param b     The second memory region
+   @param len   The length of the area to compare (octets)
+
+   @return 0 when a and b are equal for len bytes, 1 they are not equal.
+*/
+int mem_neq(const void *a, const void *b, size_t len)
+{
+   unsigned char ret = 0;
+   const unsigned char* pa;
+   const unsigned char* pb;
+
+   LTC_ARGCHK(a != NULL);
+   LTC_ARGCHK(b != NULL);
+
+   pa = a;
+   pb = b;
+
+   while (len-- > 0) {
+      ret |= *pa ^ *pb;
+      ++pa;
+      ++pb;
+   }
+
+   ret |= ret >> 4;
+   ret |= ret >> 2;
+   ret |= ret >> 1;
+   ret &= 1;
+
+   return ret;
+}
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/misc/pk_get_oid.c b/libtomcrypt/src/misc/pk_get_oid.c
new file mode 100644 (file)
index 0000000..4f75c5e
--- /dev/null
@@ -0,0 +1,44 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+#ifdef LTC_DER
+static const oid_st rsa_oid = {
+   { 1, 2, 840, 113549, 1, 1, 1  },
+   7,
+};
+
+static const oid_st dsa_oid = {
+   { 1, 2, 840, 10040, 4, 1  },
+   6,
+};
+
+/*
+   Returns the OID of the public key algorithm.
+   @return CRYPT_OK if valid
+*/
+int pk_get_oid(int pk, oid_st *st)
+{
+   switch (pk) {
+      case PKA_RSA:
+         XMEMCPY(st, &rsa_oid, sizeof(*st));
+         break;
+      case PKA_DSA:
+         XMEMCPY(st, &dsa_oid, sizeof(*st));
+         break;
+      default:
+         return CRYPT_INVALID_ARG;
+   }
+   return CRYPT_OK;
+}
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/misc/pkcs5/pkcs_5_1.c b/libtomcrypt/src/misc/pkcs5/pkcs_5_1.c
new file mode 100644 (file)
index 0000000..10325de
--- /dev/null
@@ -0,0 +1,187 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+   @file pkcs_5_1.c
+   PKCS #5, Algorithm #1, Tom St Denis
+*/
+#ifdef LTC_PKCS_5
+/**
+   Execute PKCS #5 v1 in strict or OpenSSL EVP_BytesToKey()-compat mode.
+
+   PKCS#5 v1 specifies that the output key length can be no larger than
+   the hash output length.  OpenSSL unilaterally extended that by repeating
+   the hash process on a block-by-block basis for as long as needed to make
+   bigger keys.  If you want to be compatible with KDF for e.g. "openssl enc",
+   you'll want that.
+
+   If you want strict PKCS behavior, turn openssl_compat off.  Or (more
+   likely), use one of the convenience functions below.
+
+   @param password         The password (or key)
+   @param password_len     The length of the password (octet)
+   @param salt             The salt (or nonce) which is 8 octets long
+   @param iteration_count  The PKCS #5 v1 iteration count
+   @param hash_idx         The index of the hash desired
+   @param out              [out] The destination for this algorithm
+   @param outlen           [in/out] The max size and resulting size of the algorithm output
+   @param openssl_compat   [in] Whether or not to grow the key to the buffer size ala OpenSSL
+   @return CRYPT_OK if successful
+*/
+static int _pkcs_5_alg1_common(const unsigned char *password,
+                       unsigned long password_len,
+                       const unsigned char *salt,
+                       int iteration_count,  int hash_idx,
+                       unsigned char *out,   unsigned long *outlen,
+                       int openssl_compat)
+{
+   int err;
+   unsigned long x;
+   hash_state    *md;
+   unsigned char *buf;
+   /* Storage vars in case we need to support > hashsize (OpenSSL compat) */
+   unsigned long block = 0, iter;
+   /* How many bytes to put in the outbut buffer (convenience calc) */
+   unsigned long outidx = 0, nb = 0;
+
+   LTC_ARGCHK(password != NULL);
+   LTC_ARGCHK(salt     != NULL);
+   LTC_ARGCHK(out      != NULL);
+   LTC_ARGCHK(outlen   != NULL);
+
+   /* test hash IDX */
+   if ((err = hash_is_valid(hash_idx)) != CRYPT_OK) {
+      return err;
+   }
+
+   /* allocate memory */
+   md  = XMALLOC(sizeof(hash_state));
+   buf = XMALLOC(MAXBLOCKSIZE);
+   if (md == NULL || buf == NULL) {
+      if (md != NULL) {
+         XFREE(md);
+      }
+      if (buf != NULL) {
+         XFREE(buf);
+      }
+      return CRYPT_MEM;
+   }
+
+   while(block * hash_descriptor[hash_idx].hashsize < *outlen) {
+
+      /* hash initial (maybe previous hash) + password + salt */
+      if ((err = hash_descriptor[hash_idx].init(md)) != CRYPT_OK) {
+          goto LBL_ERR;
+      }
+      /* in OpenSSL mode, we first hash the previous result for blocks 2-n */
+      if (openssl_compat && block) {
+          if ((err = hash_descriptor[hash_idx].process(md, buf, hash_descriptor[hash_idx].hashsize)) != CRYPT_OK) {
+              goto LBL_ERR;
+          }
+      }
+      if ((err = hash_descriptor[hash_idx].process(md, password, password_len)) != CRYPT_OK) {
+          goto LBL_ERR;
+      }
+      if ((err = hash_descriptor[hash_idx].process(md, salt, 8)) != CRYPT_OK) {
+          goto LBL_ERR;
+      }
+      if ((err = hash_descriptor[hash_idx].done(md, buf)) != CRYPT_OK) {
+          goto LBL_ERR;
+      }
+
+      iter = iteration_count;
+      while (--iter) {
+         /* code goes here. */
+         x = MAXBLOCKSIZE;
+         if ((err = hash_memory(hash_idx, buf, hash_descriptor[hash_idx].hashsize, buf, &x)) != CRYPT_OK) {
+            goto LBL_ERR;
+         }
+      }
+
+      /* limit the size of the copy to however many bytes we have left in
+         the output buffer (and how many bytes we have to copy) */
+      outidx = block*hash_descriptor[hash_idx].hashsize;
+      nb = hash_descriptor[hash_idx].hashsize;
+      if(outidx+nb > *outlen)
+          nb = *outlen - outidx;
+      if(nb > 0)
+          XMEMCPY(out+outidx, buf, nb);
+
+      block++;
+      if (!openssl_compat)
+          break;
+   }
+   /* In strict mode, we always return the hashsize, in compat we filled it
+      as much as was requested, so we leave it alone. */
+   if(!openssl_compat)
+      *outlen = hash_descriptor[hash_idx].hashsize;
+
+   err = CRYPT_OK;
+LBL_ERR:
+#ifdef LTC_CLEAN_STACK
+   zeromem(buf, MAXBLOCKSIZE);
+   zeromem(md, sizeof(hash_state));
+#endif
+
+   XFREE(buf);
+   XFREE(md);
+
+   return err;
+}
+
+/**
+   Execute PKCS #5 v1 - Strict mode (no OpenSSL-compatible extension)
+   @param password         The password (or key)
+   @param password_len     The length of the password (octet)
+   @param salt             The salt (or nonce) which is 8 octets long
+   @param iteration_count  The PKCS #5 v1 iteration count
+   @param hash_idx         The index of the hash desired
+   @param out              [out] The destination for this algorithm
+   @param outlen           [in/out] The max size and resulting size of the algorithm output
+   @return CRYPT_OK if successful
+*/
+int pkcs_5_alg1(const unsigned char *password, unsigned long password_len,
+                const unsigned char *salt,
+                int iteration_count,  int hash_idx,
+                unsigned char *out,   unsigned long *outlen)
+{
+   return _pkcs_5_alg1_common(password, password_len, salt, iteration_count,
+                             hash_idx, out, outlen, 0);
+}
+
+/**
+   Execute PKCS #5 v1 - OpenSSL-extension-compatible mode
+
+   Use this one if you need to derive keys as "openssl enc" does by default.
+   OpenSSL (for better or worse), uses MD5 as the hash and iteration_count=1.
+   @param password         The password (or key)
+   @param password_len     The length of the password (octet)
+   @param salt             The salt (or nonce) which is 8 octets long
+   @param iteration_count  The PKCS #5 v1 iteration count
+   @param hash_idx         The index of the hash desired
+   @param out              [out] The destination for this algorithm
+   @param outlen           [in/out] The max size and resulting size of the algorithm output
+   @return CRYPT_OK if successful
+*/
+int pkcs_5_alg1_openssl(const unsigned char *password,
+                        unsigned long password_len,
+                        const unsigned char *salt,
+                        int iteration_count,  int hash_idx,
+                        unsigned char *out,   unsigned long *outlen)
+{
+   return _pkcs_5_alg1_common(password, password_len, salt, iteration_count,
+                             hash_idx, out, outlen, 1);
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/misc/pkcs5/pkcs_5_2.c b/libtomcrypt/src/misc/pkcs5/pkcs_5_2.c
new file mode 100644 (file)
index 0000000..2265bcb
--- /dev/null
@@ -0,0 +1,127 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+   @file pkcs_5_2.c
+   PKCS #5, Algorithm #2, Tom St Denis
+*/
+#ifdef LTC_PKCS_5
+
+/**
+   Execute PKCS #5 v2
+   @param password          The input password (or key)
+   @param password_len      The length of the password (octets)
+   @param salt              The salt (or nonce)
+   @param salt_len          The length of the salt (octets)
+   @param iteration_count   # of iterations desired for PKCS #5 v2 [read specs for more]
+   @param hash_idx          The index of the hash desired
+   @param out               [out] The destination for this algorithm
+   @param outlen            [in/out] The max size and resulting size of the algorithm output
+   @return CRYPT_OK if successful
+*/
+int pkcs_5_alg2(const unsigned char *password, unsigned long password_len,
+                const unsigned char *salt,     unsigned long salt_len,
+                int iteration_count,           int hash_idx,
+                unsigned char *out,            unsigned long *outlen)
+{
+   int err, itts;
+   ulong32  blkno;
+   unsigned long stored, left, x, y;
+   unsigned char *buf[2];
+   hmac_state    *hmac;
+
+   LTC_ARGCHK(password != NULL);
+   LTC_ARGCHK(salt     != NULL);
+   LTC_ARGCHK(out      != NULL);
+   LTC_ARGCHK(outlen   != NULL);
+
+   /* test hash IDX */
+   if ((err = hash_is_valid(hash_idx)) != CRYPT_OK) {
+      return err;
+   }
+
+   buf[0] = XMALLOC(MAXBLOCKSIZE * 2);
+   hmac   = XMALLOC(sizeof(hmac_state));
+   if (hmac == NULL || buf[0] == NULL) {
+      if (hmac != NULL) {
+         XFREE(hmac);
+      }
+      if (buf[0] != NULL) {
+         XFREE(buf[0]);
+      }
+      return CRYPT_MEM;
+   }
+   /* buf[1] points to the second block of MAXBLOCKSIZE bytes */
+   buf[1] = buf[0] + MAXBLOCKSIZE;
+
+   left   = *outlen;
+   blkno  = 1;
+   stored = 0;
+   while (left != 0) {
+       /* process block number blkno */
+       zeromem(buf[0], MAXBLOCKSIZE*2);
+
+       /* store current block number and increment for next pass */
+       STORE32H(blkno, buf[1]);
+       ++blkno;
+
+       /* get PRF(P, S||int(blkno)) */
+       if ((err = hmac_init(hmac, hash_idx, password, password_len)) != CRYPT_OK) {
+          goto LBL_ERR;
+       }
+       if ((err = hmac_process(hmac, salt, salt_len)) != CRYPT_OK) {
+          goto LBL_ERR;
+       }
+       if ((err = hmac_process(hmac, buf[1], 4)) != CRYPT_OK) {
+          goto LBL_ERR;
+       }
+       x = MAXBLOCKSIZE;
+       if ((err = hmac_done(hmac, buf[0], &x)) != CRYPT_OK) {
+          goto LBL_ERR;
+       }
+
+       /* now compute repeated and XOR it in buf[1] */
+       XMEMCPY(buf[1], buf[0], x);
+       for (itts = 1; itts < iteration_count; ++itts) {
+           if ((err = hmac_memory(hash_idx, password, password_len, buf[0], x, buf[0], &x)) != CRYPT_OK) {
+              goto LBL_ERR;
+           }
+           for (y = 0; y < x; y++) {
+               buf[1][y] ^= buf[0][y];
+           }
+       }
+
+       /* now emit upto x bytes of buf[1] to output */
+       for (y = 0; y < x && left != 0; ++y) {
+           out[stored++] = buf[1][y];
+           --left;
+       }
+   }
+   *outlen = stored;
+
+   err = CRYPT_OK;
+LBL_ERR:
+#ifdef LTC_CLEAN_STACK
+   zeromem(buf[0], MAXBLOCKSIZE*2);
+   zeromem(hmac, sizeof(hmac_state));
+#endif
+
+   XFREE(hmac);
+   XFREE(buf[0]);
+
+   return err;
+}
+
+#endif
+
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/misc/pkcs5/pkcs_5_test.c b/libtomcrypt/src/misc/pkcs5/pkcs_5_test.c
new file mode 100644 (file)
index 0000000..f6e413b
--- /dev/null
@@ -0,0 +1,231 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file hkdf_test.c
+  PKCS #5 support, self-test, Steffen Jaeckel
+*/
+
+#ifdef LTC_PKCS_5
+
+/*
+    TEST CASES SOURCE:
+
+Internet Engineering Task Force (IETF)                      S. Josefsson
+Request for Comments: 6070                                        SJD AB
+Category: Informational                                     January 2011
+ISSN: 2070-1721
+*/
+
+/**
+  PKCS #5 self-test
+  @return CRYPT_OK if successful, CRYPT_NOP if tests have been disabled.
+*/
+int pkcs_5_test (void)
+{
+ #ifndef LTC_TEST
+    return CRYPT_NOP;
+ #else
+
+    typedef struct {
+        const char* P;
+        unsigned long P_len;
+        const char* S;
+        unsigned long S_len;
+        int c;
+        unsigned long dkLen;
+        unsigned char DK[40];
+    } case_item;
+
+    static const case_item cases_5_2[] = {
+        {
+            "password",
+            8,
+            "salt",
+            4,
+            1,
+            20,
+            { 0x0c, 0x60, 0xc8, 0x0f, 0x96, 0x1f, 0x0e, 0x71,
+              0xf3, 0xa9, 0xb5, 0x24, 0xaf, 0x60, 0x12, 0x06,
+              0x2f, 0xe0, 0x37, 0xa6 }
+        },
+        {
+            "password",
+            8,
+            "salt",
+            4,
+            2,
+            20,
+            { 0xea, 0x6c, 0x01, 0x4d, 0xc7, 0x2d, 0x6f, 0x8c,
+              0xcd, 0x1e, 0xd9, 0x2a, 0xce, 0x1d, 0x41, 0xf0,
+              0xd8, 0xde, 0x89, 0x57 }
+        },
+#ifdef LTC_TEST_EXT
+        {
+            "password",
+            8,
+            "salt",
+            4,
+            4096,
+            20,
+            { 0x4b, 0x00, 0x79, 0x01, 0xb7, 0x65, 0x48, 0x9a,
+              0xbe, 0xad, 0x49, 0xd9, 0x26, 0xf7, 0x21, 0xd0,
+              0x65, 0xa4, 0x29, 0xc1 }
+        },
+        {
+            "password",
+            8,
+            "salt",
+            4,
+            16777216,
+            20,
+            { 0xee, 0xfe, 0x3d, 0x61, 0xcd, 0x4d, 0xa4, 0xe4,
+              0xe9, 0x94, 0x5b, 0x3d, 0x6b, 0xa2, 0x15, 0x8c,
+              0x26, 0x34, 0xe9, 0x84 }
+        },
+        {
+            "passwordPASSWORDpassword",
+            25,
+            "saltSALTsaltSALTsaltSALTsaltSALTsalt",
+            36,
+            4096,
+            25,
+            { 0x3d, 0x2e, 0xec, 0x4f, 0xe4, 0x1c, 0x84, 0x9b,
+              0x80, 0xc8, 0xd8, 0x36, 0x62, 0xc0, 0xe4, 0x4a,
+              0x8b, 0x29, 0x1a, 0x96, 0x4c, 0xf2, 0xf0, 0x70,
+              0x38 }
+        },
+        {
+            "pass\0word",
+            9,
+            "sa\0lt",
+            5,
+            4096,
+            16,
+            { 0x56, 0xfa, 0x6a, 0xa7, 0x55, 0x48, 0x09, 0x9d,
+              0xcc, 0x37, 0xd7, 0xf0, 0x34, 0x25, 0xe0, 0xc3 }
+        },
+#endif /* LTC_TEST_EXT */
+    };
+
+    static const case_item cases_5_1[] = {
+        {
+            "password",
+            8,
+            "saltsalt", /* must be 8 octects */
+            8,          /* ignored by alg1 */
+            1,
+            20,
+            { 0xca, 0xb8, 0x6d, 0xd6, 0x26, 0x17, 0x10, 0x89, 0x1e, 0x8c,
+              0xb5, 0x6e, 0xe3, 0x62, 0x56, 0x91, 0xa7, 0x5d, 0xf3, 0x44 }
+        },
+    };
+
+    static const case_item cases_5_1o[] = {
+        {
+            "password",
+            8,
+            "saltsalt", /* must be 8 octects */
+            8,          /* ignored by alg1_openssl */
+            1,
+            20,
+            { 0xca, 0xb8, 0x6d, 0xd6, 0x26, 0x17, 0x10, 0x89, 0x1e, 0x8c,
+              0xb5, 0x6e, 0xe3, 0x62, 0x56, 0x91, 0xa7, 0x5d, 0xf3, 0x44 }
+
+        },
+        {
+            "password",
+            8,
+            "saltsalt", /* must be 8 octects */
+            8,          /* ignored by alg1_openssl */
+            1,
+            30,
+            { 0xca, 0xb8, 0x6d, 0xd6, 0x26, 0x17, 0x10, 0x89, 0x1e, 0x8c,
+              0xb5, 0x6e, 0xe3, 0x62, 0x56, 0x91, 0xa7, 0x5d, 0xf3, 0x44,
+              0xf0, 0xbf, 0xf4, 0xc1, 0x2c, 0xf3, 0x59, 0x6f, 0xc0, 0x0b }
+
+        }
+    };
+
+    unsigned char DK[40];
+    unsigned long dkLen;
+    int i, err;
+    int tested=0, failed=0;
+    int hash = find_hash("sha1");
+    if (hash == -1)
+    {
+#ifdef LTC_TEST_DBG
+      printf("PKCS#5 test failed: 'sha1' hash not found\n");
+#endif
+      return CRYPT_ERROR;
+    }
+
+    /* testing alg 2 */
+    for(i=0; i < (int)(sizeof(cases_5_2) / sizeof(cases_5_2[0])); i++) {
+        ++tested;
+        dkLen = cases_5_2[i].dkLen;
+        if((err = pkcs_5_alg2((unsigned char*)cases_5_2[i].P, cases_5_2[i].P_len,
+                              (unsigned char*)cases_5_2[i].S, cases_5_2[i].S_len,
+                              cases_5_2[i].c, hash,
+                              DK, &dkLen)) != CRYPT_OK) {
+#ifdef LTC_TEST_DBG
+            printf("\npkcs_5_alg2() #%d: Failed/1 (%s)\n", i, error_to_string(err));
+#endif
+            ++failed;
+        }
+        else if (compare_testvector(DK, dkLen, cases_5_2[i].DK, cases_5_2[i].dkLen, "PKCS#5_2", i)) {
+            ++failed;
+        }
+    }
+
+    /* testing alg 1 */
+    for(i=0; i < (int)(sizeof(cases_5_1) / sizeof(case_item)); i++, tested++) {
+        dkLen = cases_5_1[i].dkLen;
+        if((err = pkcs_5_alg1((unsigned char*)cases_5_1[i].P, cases_5_1[i].P_len,
+                              (unsigned char*)cases_5_1[i].S,
+                              cases_5_1[i].c, hash,
+                              DK, &dkLen)) != CRYPT_OK) {
+#ifdef LTC_TEST_DBG
+            printf("\npkcs_5_alg1() #%d: Failed/1 (%s)\n", i, error_to_string(err));
+#endif
+            ++failed;
+        }
+        else if (compare_testvector(DK, dkLen, cases_5_1[i].DK, cases_5_1[i].dkLen, "PKCS#5_1", i)) {
+            ++failed;
+        }
+    }
+
+    /* testing alg 1_openssl */
+    for(i = 0; i < (int)(sizeof(cases_5_1o) / sizeof(cases_5_1o[0])); i++, tested++) {
+        dkLen = cases_5_1o[i].dkLen;
+        if ((err = pkcs_5_alg1_openssl((unsigned char*)cases_5_1o[i].P, cases_5_1o[i].P_len,
+                                       (unsigned char*)cases_5_1o[i].S,
+                                       cases_5_1o[i].c, hash,
+                                       DK, &dkLen)) != CRYPT_OK) {
+#ifdef LTC_TEST_DBG
+            printf("\npkcs_5_alg1_openssl() #%d: Failed/1 (%s)\n", i, error_to_string(err));
+#endif
+            ++failed;
+        }
+        else if (compare_testvector(DK, dkLen, cases_5_1o[i].DK, cases_5_1o[i].dkLen, "PKCS#5_1o", i)) {
+            ++failed;
+        }
+    }
+
+    return (failed != 0) ? CRYPT_FAIL_TESTVECTOR : CRYPT_OK;
+ #endif
+}
+
+#endif
+
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/misc/zeromem.c b/libtomcrypt/src/misc/zeromem.c
new file mode 100644 (file)
index 0000000..1a3b8ed
--- /dev/null
@@ -0,0 +1,32 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+   @file zeromem.c
+   Zero a block of memory, Tom St Denis
+*/
+
+/**
+   Zero a block of memory
+   @param out    The destination of the area to zero
+   @param outlen The length of the area to zero (octets)
+*/
+void zeromem(volatile void *out, size_t outlen)
+{
+   volatile char *mem = out;
+   LTC_ARGCHKVD(out != NULL);
+   while (outlen-- > 0) {
+      *mem++ = '\0';
+   }
+}
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/modes/cbc/cbc_decrypt.c b/libtomcrypt/src/modes/cbc/cbc_decrypt.c
new file mode 100644 (file)
index 0000000..e9f2785
--- /dev/null
@@ -0,0 +1,95 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+   @file cbc_decrypt.c
+   CBC implementation, encrypt block, Tom St Denis
+*/
+
+
+#ifdef LTC_CBC_MODE
+
+/**
+  CBC decrypt
+  @param ct     Ciphertext
+  @param pt     [out] Plaintext
+  @param len    The number of bytes to process (must be multiple of block length)
+  @param cbc    CBC state
+  @return CRYPT_OK if successful
+*/
+int cbc_decrypt(const unsigned char *ct, unsigned char *pt, unsigned long len, symmetric_CBC *cbc)
+{
+   int x, err;
+   unsigned char tmp[16];
+#ifdef LTC_FAST
+   LTC_FAST_TYPE tmpy;
+#else
+   unsigned char tmpy;
+#endif
+
+   LTC_ARGCHK(pt  != NULL);
+   LTC_ARGCHK(ct  != NULL);
+   LTC_ARGCHK(cbc != NULL);
+
+   if ((err = cipher_is_valid(cbc->cipher)) != CRYPT_OK) {
+       return err;
+   }
+
+   /* is blocklen valid? */
+   if (cbc->blocklen < 1 || cbc->blocklen > (int)sizeof(cbc->IV) || cbc->blocklen > (int)sizeof(tmp)) {
+      return CRYPT_INVALID_ARG;
+   }
+
+   if (len % cbc->blocklen) {
+      return CRYPT_INVALID_ARG;
+   }
+#ifdef LTC_FAST
+   if (cbc->blocklen % sizeof(LTC_FAST_TYPE)) {
+      return CRYPT_INVALID_ARG;
+   }
+#endif
+
+   if (cipher_descriptor[cbc->cipher].accel_cbc_decrypt != NULL) {
+      return cipher_descriptor[cbc->cipher].accel_cbc_decrypt(ct, pt, len / cbc->blocklen, cbc->IV, &cbc->key);
+   } else {
+      while (len) {
+         /* decrypt */
+         if ((err = cipher_descriptor[cbc->cipher].ecb_decrypt(ct, tmp, &cbc->key)) != CRYPT_OK) {
+            return err;
+         }
+
+         /* xor IV against plaintext */
+         #if defined(LTC_FAST)
+         for (x = 0; x < cbc->blocklen; x += sizeof(LTC_FAST_TYPE)) {
+            tmpy = *(LTC_FAST_TYPE_PTR_CAST((unsigned char *)cbc->IV + x)) ^ *(LTC_FAST_TYPE_PTR_CAST((unsigned char *)tmp + x));
+            *(LTC_FAST_TYPE_PTR_CAST((unsigned char *)cbc->IV + x)) = *(LTC_FAST_TYPE_PTR_CAST((unsigned char *)ct + x));
+            *(LTC_FAST_TYPE_PTR_CAST((unsigned char *)pt + x)) = tmpy;
+         }
+    #else
+         for (x = 0; x < cbc->blocklen; x++) {
+            tmpy       = tmp[x] ^ cbc->IV[x];
+            cbc->IV[x] = ct[x];
+            pt[x]      = tmpy;
+         }
+    #endif
+
+         ct  += cbc->blocklen;
+         pt  += cbc->blocklen;
+         len -= cbc->blocklen;
+      }
+   }
+   return CRYPT_OK;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/modes/cbc/cbc_done.c b/libtomcrypt/src/modes/cbc/cbc_done.c
new file mode 100644 (file)
index 0000000..2f1293d
--- /dev/null
@@ -0,0 +1,40 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+   @file cbc_done.c
+   CBC implementation, finish chain, Tom St Denis
+*/
+
+#ifdef LTC_CBC_MODE
+
+/** Terminate the chain
+  @param cbc    The CBC chain to terminate
+  @return CRYPT_OK on success
+*/
+int cbc_done(symmetric_CBC *cbc)
+{
+   int err;
+   LTC_ARGCHK(cbc != NULL);
+
+   if ((err = cipher_is_valid(cbc->cipher)) != CRYPT_OK) {
+      return err;
+   }
+   cipher_descriptor[cbc->cipher].done(&cbc->key);
+   return CRYPT_OK;
+}
+
+
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/modes/cbc/cbc_encrypt.c b/libtomcrypt/src/modes/cbc/cbc_encrypt.c
new file mode 100644 (file)
index 0000000..00d85fc
--- /dev/null
@@ -0,0 +1,96 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+   @file cbc_encrypt.c
+   CBC implementation, encrypt block, Tom St Denis
+*/
+
+
+#ifdef LTC_CBC_MODE
+
+/**
+  CBC encrypt
+  @param pt     Plaintext
+  @param ct     [out] Ciphertext
+  @param len    The number of bytes to process (must be multiple of block length)
+  @param cbc    CBC state
+  @return CRYPT_OK if successful
+*/
+int cbc_encrypt(const unsigned char *pt, unsigned char *ct, unsigned long len, symmetric_CBC *cbc)
+{
+   int x, err;
+
+   LTC_ARGCHK(pt != NULL);
+   LTC_ARGCHK(ct != NULL);
+   LTC_ARGCHK(cbc != NULL);
+
+   if ((err = cipher_is_valid(cbc->cipher)) != CRYPT_OK) {
+       return err;
+   }
+
+   /* is blocklen valid? */
+   if (cbc->blocklen < 1 || cbc->blocklen > (int)sizeof(cbc->IV)) {
+      return CRYPT_INVALID_ARG;
+   }
+
+   if (len % cbc->blocklen) {
+      return CRYPT_INVALID_ARG;
+   }
+#ifdef LTC_FAST
+   if (cbc->blocklen % sizeof(LTC_FAST_TYPE)) {
+      return CRYPT_INVALID_ARG;
+   }
+#endif
+
+   if (cipher_descriptor[cbc->cipher].accel_cbc_encrypt != NULL) {
+      return cipher_descriptor[cbc->cipher].accel_cbc_encrypt(pt, ct, len / cbc->blocklen, cbc->IV, &cbc->key);
+   } else {
+      while (len) {
+         /* xor IV against plaintext */
+         #if defined(LTC_FAST)
+         for (x = 0; x < cbc->blocklen; x += sizeof(LTC_FAST_TYPE)) {
+            *(LTC_FAST_TYPE_PTR_CAST((unsigned char *)cbc->IV + x)) ^= *(LTC_FAST_TYPE_PTR_CAST((unsigned char *)pt + x));
+         }
+    #else
+         for (x = 0; x < cbc->blocklen; x++) {
+            cbc->IV[x] ^= pt[x];
+         }
+    #endif
+
+         /* encrypt */
+         if ((err = cipher_descriptor[cbc->cipher].ecb_encrypt(cbc->IV, ct, &cbc->key)) != CRYPT_OK) {
+            return err;
+         }
+
+         /* store IV [ciphertext] for a future block */
+         #if defined(LTC_FAST)
+         for (x = 0; x < cbc->blocklen; x += sizeof(LTC_FAST_TYPE)) {
+            *(LTC_FAST_TYPE_PTR_CAST((unsigned char *)cbc->IV + x)) = *(LTC_FAST_TYPE_PTR_CAST((unsigned char *)ct + x));
+         }
+    #else
+         for (x = 0; x < cbc->blocklen; x++) {
+            cbc->IV[x] = ct[x];
+         }
+    #endif
+
+         ct  += cbc->blocklen;
+         pt  += cbc->blocklen;
+         len -= cbc->blocklen;
+      }
+   }
+   return CRYPT_OK;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/modes/cbc/cbc_getiv.c b/libtomcrypt/src/modes/cbc/cbc_getiv.c
new file mode 100644 (file)
index 0000000..fbf6834
--- /dev/null
@@ -0,0 +1,44 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+   @file cbc_getiv.c
+   CBC implementation, get IV, Tom St Denis
+*/
+
+#ifdef LTC_CBC_MODE
+
+/**
+   Get the current initialization vector
+   @param IV   [out] The destination of the initialization vector
+   @param len  [in/out]  The max size and resulting size of the initialization vector
+   @param cbc  The CBC state
+   @return CRYPT_OK if successful
+*/
+int cbc_getiv(unsigned char *IV, unsigned long *len, symmetric_CBC *cbc)
+{
+   LTC_ARGCHK(IV  != NULL);
+   LTC_ARGCHK(len != NULL);
+   LTC_ARGCHK(cbc != NULL);
+   if ((unsigned long)cbc->blocklen > *len) {
+      *len = cbc->blocklen;
+      return CRYPT_BUFFER_OVERFLOW;
+   }
+   XMEMCPY(IV, cbc->IV, cbc->blocklen);
+   *len = cbc->blocklen;
+
+   return CRYPT_OK;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/modes/cbc/cbc_setiv.c b/libtomcrypt/src/modes/cbc/cbc_setiv.c
new file mode 100644 (file)
index 0000000..255d641
--- /dev/null
@@ -0,0 +1,42 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+   @file cbc_setiv.c
+   CBC implementation, set IV, Tom St Denis
+*/
+
+
+#ifdef LTC_CBC_MODE
+
+/**
+   Set an initialization vector
+   @param IV   The initialization vector
+   @param len  The length of the vector (in octets)
+   @param cbc  The CBC state
+   @return CRYPT_OK if successful
+*/
+int cbc_setiv(const unsigned char *IV, unsigned long len, symmetric_CBC *cbc)
+{
+   LTC_ARGCHK(IV  != NULL);
+   LTC_ARGCHK(cbc != NULL);
+   if (len != (unsigned long)cbc->blocklen) {
+      return CRYPT_INVALID_ARG;
+   }
+   XMEMCPY(cbc->IV, IV, len);
+   return CRYPT_OK;
+}
+
+#endif
+
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/modes/cbc/cbc_start.c b/libtomcrypt/src/modes/cbc/cbc_start.c
new file mode 100644 (file)
index 0000000..6c5c52c
--- /dev/null
@@ -0,0 +1,60 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+   @file cbc_start.c
+   CBC implementation, start chain, Tom St Denis
+*/
+
+#ifdef LTC_CBC_MODE
+
+/**
+   Initialize a CBC context
+   @param cipher      The index of the cipher desired
+   @param IV          The initialization vector
+   @param key         The secret key
+   @param keylen      The length of the secret key (octets)
+   @param num_rounds  Number of rounds in the cipher desired (0 for default)
+   @param cbc         The CBC state to initialize
+   @return CRYPT_OK if successful
+*/
+int cbc_start(int cipher, const unsigned char *IV, const unsigned char *key,
+              int keylen, int num_rounds, symmetric_CBC *cbc)
+{
+   int x, err;
+
+   LTC_ARGCHK(IV != NULL);
+   LTC_ARGCHK(key != NULL);
+   LTC_ARGCHK(cbc != NULL);
+
+   /* bad param? */
+   if ((err = cipher_is_valid(cipher)) != CRYPT_OK) {
+      return err;
+   }
+
+   /* setup cipher */
+   if ((err = cipher_descriptor[cipher].setup(key, keylen, num_rounds, &cbc->key)) != CRYPT_OK) {
+      return err;
+   }
+
+   /* copy IV */
+   cbc->blocklen = cipher_descriptor[cipher].block_length;
+   cbc->cipher   = cipher;
+   for (x = 0; x < cbc->blocklen; x++) {
+       cbc->IV[x] = IV[x];
+   }
+   return CRYPT_OK;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/modes/cfb/cfb_decrypt.c b/libtomcrypt/src/modes/cfb/cfb_decrypt.c
new file mode 100644 (file)
index 0000000..9749a0b
--- /dev/null
@@ -0,0 +1,65 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file cfb_decrypt.c
+  CFB implementation, decrypt data, Tom St Denis
+*/
+
+#ifdef LTC_CFB_MODE
+
+/**
+   CFB decrypt
+   @param ct      Ciphertext
+   @param pt      [out] Plaintext
+   @param len     Length of ciphertext (octets)
+   @param cfb     CFB state
+   @return CRYPT_OK if successful
+*/
+int cfb_decrypt(const unsigned char *ct, unsigned char *pt, unsigned long len, symmetric_CFB *cfb)
+{
+   int err;
+
+   LTC_ARGCHK(pt != NULL);
+   LTC_ARGCHK(ct != NULL);
+   LTC_ARGCHK(cfb != NULL);
+
+   if ((err = cipher_is_valid(cfb->cipher)) != CRYPT_OK) {
+       return err;
+   }
+
+   /* is blocklen/padlen valid? */
+   if (cfb->blocklen < 0 || cfb->blocklen > (int)sizeof(cfb->IV) ||
+       cfb->padlen   < 0 || cfb->padlen   > (int)sizeof(cfb->pad)) {
+      return CRYPT_INVALID_ARG;
+   }
+
+   while (len-- > 0) {
+       if (cfb->padlen == cfb->blocklen) {
+          if ((err = cipher_descriptor[cfb->cipher].ecb_encrypt(cfb->pad, cfb->IV, &cfb->key)) != CRYPT_OK) {
+             return err;
+          }
+          cfb->padlen = 0;
+       }
+       cfb->pad[cfb->padlen] = *ct;
+       *pt = *ct ^ cfb->IV[cfb->padlen];
+       ++pt;
+       ++ct;
+       ++(cfb->padlen);
+   }
+   return CRYPT_OK;
+}
+
+#endif
+
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/modes/cfb/cfb_done.c b/libtomcrypt/src/modes/cfb/cfb_done.c
new file mode 100644 (file)
index 0000000..24576c8
--- /dev/null
@@ -0,0 +1,40 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+   @file cfb_done.c
+   CFB implementation, finish chain, Tom St Denis
+*/
+
+#ifdef LTC_CFB_MODE
+
+/** Terminate the chain
+  @param cfb    The CFB chain to terminate
+  @return CRYPT_OK on success
+*/
+int cfb_done(symmetric_CFB *cfb)
+{
+   int err;
+   LTC_ARGCHK(cfb != NULL);
+
+   if ((err = cipher_is_valid(cfb->cipher)) != CRYPT_OK) {
+      return err;
+   }
+   cipher_descriptor[cfb->cipher].done(&cfb->key);
+   return CRYPT_OK;
+}
+
+
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/modes/cfb/cfb_encrypt.c b/libtomcrypt/src/modes/cfb/cfb_encrypt.c
new file mode 100644 (file)
index 0000000..4503e5b
--- /dev/null
@@ -0,0 +1,63 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file cfb_encrypt.c
+  CFB implementation, encrypt data, Tom St Denis
+*/
+
+#ifdef LTC_CFB_MODE
+
+/**
+  CFB encrypt
+  @param pt     Plaintext
+  @param ct     [out] Ciphertext
+  @param len    Length of plaintext (octets)
+  @param cfb    CFB state
+  @return CRYPT_OK if successful
+*/
+int cfb_encrypt(const unsigned char *pt, unsigned char *ct, unsigned long len, symmetric_CFB *cfb)
+{
+   int err;
+
+   LTC_ARGCHK(pt != NULL);
+   LTC_ARGCHK(ct != NULL);
+   LTC_ARGCHK(cfb != NULL);
+
+   if ((err = cipher_is_valid(cfb->cipher)) != CRYPT_OK) {
+       return err;
+   }
+
+   /* is blocklen/padlen valid? */
+   if (cfb->blocklen < 0 || cfb->blocklen > (int)sizeof(cfb->IV) ||
+       cfb->padlen   < 0 || cfb->padlen   > (int)sizeof(cfb->pad)) {
+      return CRYPT_INVALID_ARG;
+   }
+
+   while (len-- > 0) {
+       if (cfb->padlen == cfb->blocklen) {
+          if ((err = cipher_descriptor[cfb->cipher].ecb_encrypt(cfb->pad, cfb->IV, &cfb->key)) != CRYPT_OK) {
+             return err;
+          }
+          cfb->padlen = 0;
+       }
+       cfb->pad[cfb->padlen] = (*ct = *pt ^ cfb->IV[cfb->padlen]);
+       ++pt;
+       ++ct;
+       ++(cfb->padlen);
+   }
+   return CRYPT_OK;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/modes/cfb/cfb_getiv.c b/libtomcrypt/src/modes/cfb/cfb_getiv.c
new file mode 100644 (file)
index 0000000..b972c72
--- /dev/null
@@ -0,0 +1,44 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+   @file cfb_getiv.c
+   CFB implementation, get IV, Tom St Denis
+*/
+
+#ifdef LTC_CFB_MODE
+
+/**
+   Get the current initialization vector
+   @param IV   [out] The destination of the initialization vector
+   @param len  [in/out]  The max size and resulting size of the initialization vector
+   @param cfb  The CFB state
+   @return CRYPT_OK if successful
+*/
+int cfb_getiv(unsigned char *IV, unsigned long *len, symmetric_CFB *cfb)
+{
+   LTC_ARGCHK(IV  != NULL);
+   LTC_ARGCHK(len != NULL);
+   LTC_ARGCHK(cfb != NULL);
+   if ((unsigned long)cfb->blocklen > *len) {
+      *len = cfb->blocklen;
+      return CRYPT_BUFFER_OVERFLOW;
+   }
+   XMEMCPY(IV, cfb->IV, cfb->blocklen);
+   *len = cfb->blocklen;
+
+   return CRYPT_OK;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/modes/cfb/cfb_setiv.c b/libtomcrypt/src/modes/cfb/cfb_setiv.c
new file mode 100644 (file)
index 0000000..4495bf5
--- /dev/null
@@ -0,0 +1,50 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file cfb_setiv.c
+  CFB implementation, set IV, Tom St Denis
+*/
+
+#ifdef LTC_CFB_MODE
+
+/**
+   Set an initialization vector
+   @param IV   The initialization vector
+   @param len  The length of the vector (in octets)
+   @param cfb  The CFB state
+   @return CRYPT_OK if successful
+*/
+int cfb_setiv(const unsigned char *IV, unsigned long len, symmetric_CFB *cfb)
+{
+   int err;
+
+   LTC_ARGCHK(IV  != NULL);
+   LTC_ARGCHK(cfb != NULL);
+
+   if ((err = cipher_is_valid(cfb->cipher)) != CRYPT_OK) {
+       return err;
+   }
+
+   if (len != (unsigned long)cfb->blocklen) {
+      return CRYPT_INVALID_ARG;
+   }
+
+   /* force next block */
+   cfb->padlen = 0;
+   return cipher_descriptor[cfb->cipher].ecb_encrypt(IV, cfb->IV, &cfb->key);
+}
+
+#endif
+
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/modes/cfb/cfb_start.c b/libtomcrypt/src/modes/cfb/cfb_start.c
new file mode 100644 (file)
index 0000000..e49b119
--- /dev/null
@@ -0,0 +1,63 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+   @file cfb_start.c
+   CFB implementation, start chain, Tom St Denis
+*/
+
+
+#ifdef LTC_CFB_MODE
+
+/**
+   Initialize a CFB context
+   @param cipher      The index of the cipher desired
+   @param IV          The initialization vector
+   @param key         The secret key
+   @param keylen      The length of the secret key (octets)
+   @param num_rounds  Number of rounds in the cipher desired (0 for default)
+   @param cfb         The CFB state to initialize
+   @return CRYPT_OK if successful
+*/
+int cfb_start(int cipher, const unsigned char *IV, const unsigned char *key,
+              int keylen, int num_rounds, symmetric_CFB *cfb)
+{
+   int x, err;
+
+   LTC_ARGCHK(IV != NULL);
+   LTC_ARGCHK(key != NULL);
+   LTC_ARGCHK(cfb != NULL);
+
+   if ((err = cipher_is_valid(cipher)) != CRYPT_OK) {
+      return err;
+   }
+
+
+   /* copy data */
+   cfb->cipher = cipher;
+   cfb->blocklen = cipher_descriptor[cipher].block_length;
+   for (x = 0; x < cfb->blocklen; x++)
+       cfb->IV[x] = IV[x];
+
+   /* init the cipher */
+   if ((err = cipher_descriptor[cipher].setup(key, keylen, num_rounds, &cfb->key)) != CRYPT_OK) {
+      return err;
+   }
+
+   /* encrypt the IV */
+   cfb->padlen = 0;
+   return cipher_descriptor[cfb->cipher].ecb_encrypt(cfb->IV, cfb->IV, &cfb->key);
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/modes/ctr/ctr_decrypt.c b/libtomcrypt/src/modes/ctr/ctr_decrypt.c
new file mode 100644 (file)
index 0000000..5008089
--- /dev/null
@@ -0,0 +1,40 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file ctr_decrypt.c
+  CTR implementation, decrypt data, Tom St Denis
+*/
+
+#ifdef LTC_CTR_MODE
+
+/**
+   CTR decrypt
+   @param ct      Ciphertext
+   @param pt      [out] Plaintext
+   @param len     Length of ciphertext (octets)
+   @param ctr     CTR state
+   @return CRYPT_OK if successful
+*/
+int ctr_decrypt(const unsigned char *ct, unsigned char *pt, unsigned long len, symmetric_CTR *ctr)
+{
+   LTC_ARGCHK(pt != NULL);
+   LTC_ARGCHK(ct != NULL);
+   LTC_ARGCHK(ctr != NULL);
+
+   return ctr_encrypt(ct, pt, len, ctr);
+}
+
+#endif
+
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/modes/ctr/ctr_done.c b/libtomcrypt/src/modes/ctr/ctr_done.c
new file mode 100644 (file)
index 0000000..3de13c2
--- /dev/null
@@ -0,0 +1,40 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+   @file ctr_done.c
+   CTR implementation, finish chain, Tom St Denis
+*/
+
+#ifdef LTC_CTR_MODE
+
+/** Terminate the chain
+  @param ctr    The CTR chain to terminate
+  @return CRYPT_OK on success
+*/
+int ctr_done(symmetric_CTR *ctr)
+{
+   int err;
+   LTC_ARGCHK(ctr != NULL);
+
+   if ((err = cipher_is_valid(ctr->cipher)) != CRYPT_OK) {
+      return err;
+   }
+   cipher_descriptor[ctr->cipher].done(&ctr->key);
+   return CRYPT_OK;
+}
+
+
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/modes/ctr/ctr_encrypt.c b/libtomcrypt/src/modes/ctr/ctr_encrypt.c
new file mode 100644 (file)
index 0000000..eb7328c
--- /dev/null
@@ -0,0 +1,139 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file ctr_encrypt.c
+  CTR implementation, encrypt data, Tom St Denis
+*/
+
+
+#ifdef LTC_CTR_MODE
+
+/**
+  CTR encrypt software implementation
+  @param pt     Plaintext
+  @param ct     [out] Ciphertext
+  @param len    Length of plaintext (octets)
+  @param ctr    CTR state
+  @return CRYPT_OK if successful
+*/
+static int _ctr_encrypt(const unsigned char *pt, unsigned char *ct, unsigned long len, symmetric_CTR *ctr)
+{
+   int x, err;
+
+   while (len) {
+      /* is the pad empty? */
+      if (ctr->padlen == ctr->blocklen) {
+         /* increment counter */
+         if (ctr->mode == CTR_COUNTER_LITTLE_ENDIAN) {
+            /* little-endian */
+            for (x = 0; x < ctr->ctrlen; x++) {
+               ctr->ctr[x] = (ctr->ctr[x] + (unsigned char)1) & (unsigned char)255;
+               if (ctr->ctr[x] != (unsigned char)0) {
+                  break;
+               }
+            }
+         } else {
+            /* big-endian */
+            for (x = ctr->blocklen-1; x >= ctr->ctrlen; x--) {
+               ctr->ctr[x] = (ctr->ctr[x] + (unsigned char)1) & (unsigned char)255;
+               if (ctr->ctr[x] != (unsigned char)0) {
+                  break;
+               }
+            }
+         }
+
+         /* encrypt it */
+         if ((err = cipher_descriptor[ctr->cipher].ecb_encrypt(ctr->ctr, ctr->pad, &ctr->key)) != CRYPT_OK) {
+            return err;
+         }
+         ctr->padlen = 0;
+      }
+#ifdef LTC_FAST
+      if ((ctr->padlen == 0) && (len >= (unsigned long)ctr->blocklen)) {
+         for (x = 0; x < ctr->blocklen; x += sizeof(LTC_FAST_TYPE)) {
+            *(LTC_FAST_TYPE_PTR_CAST((unsigned char *)ct + x)) = *(LTC_FAST_TYPE_PTR_CAST((unsigned char *)pt + x)) ^
+                                                           *(LTC_FAST_TYPE_PTR_CAST((unsigned char *)ctr->pad + x));
+         }
+       pt         += ctr->blocklen;
+       ct         += ctr->blocklen;
+       len        -= ctr->blocklen;
+       ctr->padlen = ctr->blocklen;
+       continue;
+      }
+#endif
+      *ct++ = *pt++ ^ ctr->pad[ctr->padlen++];
+      --len;
+   }
+   return CRYPT_OK;
+}
+
+/**
+  CTR encrypt
+  @param pt     Plaintext
+  @param ct     [out] Ciphertext
+  @param len    Length of plaintext (octets)
+  @param ctr    CTR state
+  @return CRYPT_OK if successful
+*/
+int ctr_encrypt(const unsigned char *pt, unsigned char *ct, unsigned long len, symmetric_CTR *ctr)
+{
+   int err, fr;
+
+   LTC_ARGCHK(pt != NULL);
+   LTC_ARGCHK(ct != NULL);
+   LTC_ARGCHK(ctr != NULL);
+
+   if ((err = cipher_is_valid(ctr->cipher)) != CRYPT_OK) {
+       return err;
+   }
+
+   /* is blocklen/padlen valid? */
+   if ((ctr->blocklen < 1) || (ctr->blocklen > (int)sizeof(ctr->ctr)) ||
+       (ctr->padlen   < 0) || (ctr->padlen   > (int)sizeof(ctr->pad))) {
+      return CRYPT_INVALID_ARG;
+   }
+
+#ifdef LTC_FAST
+   if (ctr->blocklen % sizeof(LTC_FAST_TYPE)) {
+      return CRYPT_INVALID_ARG;
+   }
+#endif
+
+   /* handle acceleration only if pad is empty, accelerator is present and length is >= a block size */
+   if ((cipher_descriptor[ctr->cipher].accel_ctr_encrypt != NULL) && (len >= (unsigned long)ctr->blocklen)) {
+     if (ctr->padlen < ctr->blocklen) {
+       fr = ctr->blocklen - ctr->padlen;
+       if ((err = _ctr_encrypt(pt, ct, fr, ctr)) != CRYPT_OK) {
+          return err;
+       }
+       pt += fr;
+       ct += fr;
+       len -= fr;
+     }
+
+     if (len >= (unsigned long)ctr->blocklen) {
+       if ((err = cipher_descriptor[ctr->cipher].accel_ctr_encrypt(pt, ct, len/ctr->blocklen, ctr->ctr, ctr->mode, &ctr->key)) != CRYPT_OK) {
+          return err;
+       }
+       pt += (len / ctr->blocklen) * ctr->blocklen;
+       ct += (len / ctr->blocklen) * ctr->blocklen;
+       len %= ctr->blocklen;
+     }
+   }
+
+   return _ctr_encrypt(pt, ct, len, ctr);
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/modes/ctr/ctr_getiv.c b/libtomcrypt/src/modes/ctr/ctr_getiv.c
new file mode 100644 (file)
index 0000000..cbf92db
--- /dev/null
@@ -0,0 +1,44 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+   @file ctr_getiv.c
+   CTR implementation, get IV, Tom St Denis
+*/
+
+#ifdef LTC_CTR_MODE
+
+/**
+   Get the current initialization vector
+   @param IV   [out] The destination of the initialization vector
+   @param len  [in/out]  The max size and resulting size of the initialization vector
+   @param ctr  The CTR state
+   @return CRYPT_OK if successful
+*/
+int ctr_getiv(unsigned char *IV, unsigned long *len, symmetric_CTR *ctr)
+{
+   LTC_ARGCHK(IV  != NULL);
+   LTC_ARGCHK(len != NULL);
+   LTC_ARGCHK(ctr != NULL);
+   if ((unsigned long)ctr->blocklen > *len) {
+      *len = ctr->blocklen;
+      return CRYPT_BUFFER_OVERFLOW;
+   }
+   XMEMCPY(IV, ctr->ctr, ctr->blocklen);
+   *len = ctr->blocklen;
+
+   return CRYPT_OK;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/modes/ctr/ctr_setiv.c b/libtomcrypt/src/modes/ctr/ctr_setiv.c
new file mode 100644 (file)
index 0000000..64d73a1
--- /dev/null
@@ -0,0 +1,54 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file ctr_setiv.c
+  CTR implementation, set IV, Tom St Denis
+*/
+
+#ifdef LTC_CTR_MODE
+
+/**
+   Set an initialization vector
+   @param IV   The initialization vector
+   @param len  The length of the vector (in octets)
+   @param ctr  The CTR state
+   @return CRYPT_OK if successful
+*/
+int ctr_setiv(const unsigned char *IV, unsigned long len, symmetric_CTR *ctr)
+{
+   int err;
+
+   LTC_ARGCHK(IV  != NULL);
+   LTC_ARGCHK(ctr != NULL);
+
+   /* bad param? */
+   if ((err = cipher_is_valid(ctr->cipher)) != CRYPT_OK) {
+      return err;
+   }
+
+   if (len != (unsigned long)ctr->blocklen) {
+      return CRYPT_INVALID_ARG;
+   }
+
+   /* set IV */
+   XMEMCPY(ctr->ctr, IV, len);
+
+   /* force next block */
+   ctr->padlen = 0;
+   return cipher_descriptor[ctr->cipher].ecb_encrypt(IV, ctr->pad, &ctr->key);
+}
+
+#endif
+
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/modes/ctr/ctr_start.c b/libtomcrypt/src/modes/ctr/ctr_start.c
new file mode 100644 (file)
index 0000000..039fdd6
--- /dev/null
@@ -0,0 +1,99 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+   @file ctr_start.c
+   CTR implementation, start chain, Tom St Denis
+*/
+
+
+#ifdef LTC_CTR_MODE
+
+/**
+   Initialize a CTR context
+   @param cipher      The index of the cipher desired
+   @param IV          The initialization vector
+   @param key         The secret key
+   @param keylen      The length of the secret key (octets)
+   @param num_rounds  Number of rounds in the cipher desired (0 for default)
+   @param ctr_mode    The counter mode (CTR_COUNTER_LITTLE_ENDIAN or CTR_COUNTER_BIG_ENDIAN)
+   @param ctr         The CTR state to initialize
+   @return CRYPT_OK if successful
+*/
+int ctr_start(               int   cipher,
+              const unsigned char *IV,
+              const unsigned char *key,       int keylen,
+                             int  num_rounds, int ctr_mode,
+                   symmetric_CTR *ctr)
+{
+   int x, err;
+
+   LTC_ARGCHK(IV  != NULL);
+   LTC_ARGCHK(key != NULL);
+   LTC_ARGCHK(ctr != NULL);
+
+   /* bad param? */
+   if ((err = cipher_is_valid(cipher)) != CRYPT_OK) {
+      return err;
+   }
+
+   /* ctrlen == counter width */
+   ctr->ctrlen   = (ctr_mode & 255) ? (ctr_mode & 255) : cipher_descriptor[cipher].block_length;
+   if (ctr->ctrlen > cipher_descriptor[cipher].block_length) {
+      return CRYPT_INVALID_ARG;
+   }
+
+   if ((ctr_mode & 0x1000) == CTR_COUNTER_BIG_ENDIAN) {
+      ctr->ctrlen = cipher_descriptor[cipher].block_length - ctr->ctrlen;
+   }
+
+   /* setup cipher */
+   if ((err = cipher_descriptor[cipher].setup(key, keylen, num_rounds, &ctr->key)) != CRYPT_OK) {
+      return err;
+   }
+
+   /* copy ctr */
+   ctr->blocklen = cipher_descriptor[cipher].block_length;
+   ctr->cipher   = cipher;
+   ctr->padlen   = 0;
+   ctr->mode     = ctr_mode & 0x1000;
+   for (x = 0; x < ctr->blocklen; x++) {
+       ctr->ctr[x] = IV[x];
+   }
+
+   if (ctr_mode & LTC_CTR_RFC3686) {
+      /* increment the IV as per RFC 3686 */
+      if (ctr->mode == CTR_COUNTER_LITTLE_ENDIAN) {
+         /* little-endian */
+         for (x = 0; x < ctr->ctrlen; x++) {
+             ctr->ctr[x] = (ctr->ctr[x] + (unsigned char)1) & (unsigned char)255;
+             if (ctr->ctr[x] != (unsigned char)0) {
+                break;
+             }
+         }
+      } else {
+         /* big-endian */
+         for (x = ctr->blocklen-1; x >= ctr->ctrlen; x--) {
+             ctr->ctr[x] = (ctr->ctr[x] + (unsigned char)1) & (unsigned char)255;
+             if (ctr->ctr[x] != (unsigned char)0) {
+                break;
+             }
+         }
+      }
+   }
+
+   return cipher_descriptor[ctr->cipher].ecb_encrypt(ctr->ctr, ctr->pad, &ctr->key);
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/modes/ctr/ctr_test.c b/libtomcrypt/src/modes/ctr/ctr_test.c
new file mode 100644 (file)
index 0000000..878d425
--- /dev/null
@@ -0,0 +1,83 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file ctr_test.c
+  CTR implementation, Tests again RFC 3686, Tom St Denis
+*/
+
+#ifdef LTC_CTR_MODE
+
+int ctr_test(void)
+{
+#ifdef LTC_NO_TEST
+   return CRYPT_NOP;
+#else
+   static const struct {
+      int keylen, msglen;
+      unsigned char key[32], IV[16], pt[64], ct[64];
+   } tests[] = {
+/* 128-bit key, 16-byte pt */
+{
+   16, 16,
+   {0xAE,0x68,0x52,0xF8,0x12,0x10,0x67,0xCC,0x4B,0xF7,0xA5,0x76,0x55,0x77,0xF3,0x9E },
+   {0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 },
+   {0x53,0x69,0x6E,0x67,0x6C,0x65,0x20,0x62,0x6C,0x6F,0x63,0x6B,0x20,0x6D,0x73,0x67 },
+   {0xE4,0x09,0x5D,0x4F,0xB7,0xA7,0xB3,0x79,0x2D,0x61,0x75,0xA3,0x26,0x13,0x11,0xB8 },
+},
+
+/* 128-bit key, 36-byte pt */
+{
+   16, 36,
+   {0x76,0x91,0xBE,0x03,0x5E,0x50,0x20,0xA8,0xAC,0x6E,0x61,0x85,0x29,0xF9,0xA0,0xDC },
+   {0x00,0xE0,0x01,0x7B,0x27,0x77,0x7F,0x3F,0x4A,0x17,0x86,0xF0,0x00,0x00,0x00,0x00 },
+   {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,
+    0x20,0x21,0x22,0x23},
+   {0xC1,0xCF,0x48,0xA8,0x9F,0x2F,0xFD,0xD9,0xCF,0x46,0x52,0xE9,0xEF,0xDB,0x72,0xD7,
+    0x45,0x40,0xA4,0x2B,0xDE,0x6D,0x78,0x36,0xD5,0x9A,0x5C,0xEA,0xAE,0xF3,0x10,0x53,
+    0x25,0xB2,0x07,0x2F },
+},
+};
+  int idx, err, x;
+  unsigned char buf[64];
+  symmetric_CTR ctr;
+
+  /* AES can be under rijndael or aes... try to find it */
+  if ((idx = find_cipher("aes")) == -1) {
+     if ((idx = find_cipher("rijndael")) == -1) {
+        return CRYPT_NOP;
+     }
+  }
+
+  for (x = 0; x < (int)(sizeof(tests)/sizeof(tests[0])); x++) {
+     if ((err = ctr_start(idx, tests[x].IV, tests[x].key, tests[x].keylen, 0, CTR_COUNTER_BIG_ENDIAN|LTC_CTR_RFC3686, &ctr)) != CRYPT_OK) {
+        return err;
+     }
+     if ((err = ctr_encrypt(tests[x].pt, buf, tests[x].msglen, &ctr)) != CRYPT_OK) {
+        return err;
+     }
+     ctr_done(&ctr);
+     if (compare_testvector(buf, tests[x].msglen, tests[x].ct, tests[x].msglen, "CTR", x)) {
+        return CRYPT_FAIL_TESTVECTOR;
+     }
+  }
+  return CRYPT_OK;
+#endif
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
+
+
+
diff --git a/libtomcrypt/src/modes/ecb/ecb_decrypt.c b/libtomcrypt/src/modes/ecb/ecb_decrypt.c
new file mode 100644 (file)
index 0000000..213b253
--- /dev/null
@@ -0,0 +1,59 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file ecb_decrypt.c
+  ECB implementation, decrypt a block, Tom St Denis
+*/
+
+#ifdef LTC_ECB_MODE
+
+/**
+  ECB decrypt
+  @param ct     Ciphertext
+  @param pt     [out] Plaintext
+  @param len    The number of octets to process (must be multiple of the cipher block size)
+  @param ecb    ECB state
+  @return CRYPT_OK if successful
+*/
+int ecb_decrypt(const unsigned char *ct, unsigned char *pt, unsigned long len, symmetric_ECB *ecb)
+{
+   int err;
+   LTC_ARGCHK(pt != NULL);
+   LTC_ARGCHK(ct != NULL);
+   LTC_ARGCHK(ecb != NULL);
+   if ((err = cipher_is_valid(ecb->cipher)) != CRYPT_OK) {
+       return err;
+   }
+   if (len % cipher_descriptor[ecb->cipher].block_length) {
+      return CRYPT_INVALID_ARG;
+   }
+
+   /* check for accel */
+   if (cipher_descriptor[ecb->cipher].accel_ecb_decrypt != NULL) {
+      return cipher_descriptor[ecb->cipher].accel_ecb_decrypt(ct, pt, len / cipher_descriptor[ecb->cipher].block_length, &ecb->key);
+   } else {
+      while (len) {
+         if ((err = cipher_descriptor[ecb->cipher].ecb_decrypt(ct, pt, &ecb->key)) != CRYPT_OK) {
+            return err;
+         }
+         pt  += cipher_descriptor[ecb->cipher].block_length;
+         ct  += cipher_descriptor[ecb->cipher].block_length;
+         len -= cipher_descriptor[ecb->cipher].block_length;
+      }
+   }
+   return CRYPT_OK;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/modes/ecb/ecb_done.c b/libtomcrypt/src/modes/ecb/ecb_done.c
new file mode 100644 (file)
index 0000000..6df7eec
--- /dev/null
@@ -0,0 +1,40 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+   @file ecb_done.c
+   ECB implementation, finish chain, Tom St Denis
+*/
+
+#ifdef LTC_ECB_MODE
+
+/** Terminate the chain
+  @param ecb    The ECB chain to terminate
+  @return CRYPT_OK on success
+*/
+int ecb_done(symmetric_ECB *ecb)
+{
+   int err;
+   LTC_ARGCHK(ecb != NULL);
+
+   if ((err = cipher_is_valid(ecb->cipher)) != CRYPT_OK) {
+      return err;
+   }
+   cipher_descriptor[ecb->cipher].done(&ecb->key);
+   return CRYPT_OK;
+}
+
+
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/modes/ecb/ecb_encrypt.c b/libtomcrypt/src/modes/ecb/ecb_encrypt.c
new file mode 100644 (file)
index 0000000..5d4661f
--- /dev/null
@@ -0,0 +1,59 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file ecb_encrypt.c
+  ECB implementation, encrypt a block, Tom St Denis
+*/
+
+#ifdef LTC_ECB_MODE
+
+/**
+  ECB encrypt
+  @param pt     Plaintext
+  @param ct     [out] Ciphertext
+  @param len    The number of octets to process (must be multiple of the cipher block size)
+  @param ecb    ECB state
+  @return CRYPT_OK if successful
+*/
+int ecb_encrypt(const unsigned char *pt, unsigned char *ct, unsigned long len, symmetric_ECB *ecb)
+{
+   int err;
+   LTC_ARGCHK(pt != NULL);
+   LTC_ARGCHK(ct != NULL);
+   LTC_ARGCHK(ecb != NULL);
+   if ((err = cipher_is_valid(ecb->cipher)) != CRYPT_OK) {
+       return err;
+   }
+   if (len % cipher_descriptor[ecb->cipher].block_length) {
+      return CRYPT_INVALID_ARG;
+   }
+
+   /* check for accel */
+   if (cipher_descriptor[ecb->cipher].accel_ecb_encrypt != NULL) {
+      return cipher_descriptor[ecb->cipher].accel_ecb_encrypt(pt, ct, len / cipher_descriptor[ecb->cipher].block_length, &ecb->key);
+   } else {
+      while (len) {
+         if ((err = cipher_descriptor[ecb->cipher].ecb_encrypt(pt, ct, &ecb->key)) != CRYPT_OK) {
+            return err;
+         }
+         pt  += cipher_descriptor[ecb->cipher].block_length;
+         ct  += cipher_descriptor[ecb->cipher].block_length;
+         len -= cipher_descriptor[ecb->cipher].block_length;
+      }
+   }
+   return CRYPT_OK;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/modes/ecb/ecb_start.c b/libtomcrypt/src/modes/ecb/ecb_start.c
new file mode 100644 (file)
index 0000000..ecd301b
--- /dev/null
@@ -0,0 +1,46 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+   @file ecb_start.c
+   ECB implementation, start chain, Tom St Denis
+*/
+
+
+#ifdef LTC_ECB_MODE
+
+/**
+   Initialize a ECB context
+   @param cipher      The index of the cipher desired
+   @param key         The secret key
+   @param keylen      The length of the secret key (octets)
+   @param num_rounds  Number of rounds in the cipher desired (0 for default)
+   @param ecb         The ECB state to initialize
+   @return CRYPT_OK if successful
+*/
+int ecb_start(int cipher, const unsigned char *key, int keylen, int num_rounds, symmetric_ECB *ecb)
+{
+   int err;
+   LTC_ARGCHK(key != NULL);
+   LTC_ARGCHK(ecb != NULL);
+
+   if ((err = cipher_is_valid(cipher)) != CRYPT_OK) {
+      return err;
+   }
+   ecb->cipher = cipher;
+   ecb->blocklen = cipher_descriptor[cipher].block_length;
+   return cipher_descriptor[cipher].setup(key, keylen, num_rounds, &ecb->key);
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/modes/f8/f8_decrypt.c b/libtomcrypt/src/modes/f8/f8_decrypt.c
new file mode 100644 (file)
index 0000000..9c92952
--- /dev/null
@@ -0,0 +1,41 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file f8_decrypt.c
+  F8 implementation, decrypt data, Tom St Denis
+*/
+
+#ifdef LTC_F8_MODE
+
+/**
+   F8 decrypt
+   @param ct      Ciphertext
+   @param pt      [out] Plaintext
+   @param len     Length of ciphertext (octets)
+   @param f8      F8 state
+   @return CRYPT_OK if successful
+*/
+int f8_decrypt(const unsigned char *ct, unsigned char *pt, unsigned long len, symmetric_F8 *f8)
+{
+   LTC_ARGCHK(pt != NULL);
+   LTC_ARGCHK(ct != NULL);
+   LTC_ARGCHK(f8 != NULL);
+   return f8_encrypt(ct, pt, len, f8);
+}
+
+
+#endif
+
+
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/modes/f8/f8_done.c b/libtomcrypt/src/modes/f8/f8_done.c
new file mode 100644 (file)
index 0000000..3f0af66
--- /dev/null
@@ -0,0 +1,40 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+   @file f8_done.c
+   F8 implementation, finish chain, Tom St Denis
+*/
+
+#ifdef LTC_F8_MODE
+
+/** Terminate the chain
+  @param f8    The F8 chain to terminate
+  @return CRYPT_OK on success
+*/
+int f8_done(symmetric_F8 *f8)
+{
+   int err;
+   LTC_ARGCHK(f8 != NULL);
+
+   if ((err = cipher_is_valid(f8->cipher)) != CRYPT_OK) {
+      return err;
+   }
+   cipher_descriptor[f8->cipher].done(&f8->key);
+   return CRYPT_OK;
+}
+
+
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/modes/f8/f8_encrypt.c b/libtomcrypt/src/modes/f8/f8_encrypt.c
new file mode 100644 (file)
index 0000000..058f25a
--- /dev/null
@@ -0,0 +1,101 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file f8_encrypt.c
+  F8 implementation, encrypt data, Tom St Denis
+*/
+
+#ifdef LTC_F8_MODE
+
+/**
+  F8 encrypt
+  @param pt     Plaintext
+  @param ct     [out] Ciphertext
+  @param len    Length of plaintext (octets)
+  @param f8     F8 state
+  @return CRYPT_OK if successful
+*/
+int f8_encrypt(const unsigned char *pt, unsigned char *ct, unsigned long len, symmetric_F8 *f8)
+{
+   int           err, x;
+   unsigned char buf[MAXBLOCKSIZE];
+   LTC_ARGCHK(pt != NULL);
+   LTC_ARGCHK(ct != NULL);
+   LTC_ARGCHK(f8 != NULL);
+   if ((err = cipher_is_valid(f8->cipher)) != CRYPT_OK) {
+       return err;
+   }
+
+   /* is blocklen/padlen valid? */
+   if (f8->blocklen < 0 || f8->blocklen > (int)sizeof(f8->IV) ||
+       f8->padlen   < 0 || f8->padlen   > (int)sizeof(f8->IV)) {
+      return CRYPT_INVALID_ARG;
+   }
+
+   zeromem(buf, sizeof(buf));
+
+   /* make sure the pad is empty */
+   if (f8->padlen == f8->blocklen) {
+      /* xor of IV, MIV and blockcnt == what goes into cipher */
+      STORE32H(f8->blockcnt, (buf+(f8->blocklen-4)));
+      ++(f8->blockcnt);
+      for (x = 0; x < f8->blocklen; x++) {
+          f8->IV[x] ^= f8->MIV[x] ^ buf[x];
+      }
+      if ((err = cipher_descriptor[f8->cipher].ecb_encrypt(f8->IV, f8->IV, &f8->key)) != CRYPT_OK) {
+         return err;
+      }
+      f8->padlen = 0;
+   }
+
+#ifdef LTC_FAST
+   if (f8->padlen == 0) {
+      while (len >= (unsigned long)f8->blocklen) {
+         STORE32H(f8->blockcnt, (buf+(f8->blocklen-4)));
+         ++(f8->blockcnt);
+         for (x = 0; x < f8->blocklen; x += sizeof(LTC_FAST_TYPE)) {
+             *(LTC_FAST_TYPE_PTR_CAST(&ct[x])) = *(LTC_FAST_TYPE_PTR_CAST(&pt[x])) ^ *(LTC_FAST_TYPE_PTR_CAST(&f8->IV[x]));
+             *(LTC_FAST_TYPE_PTR_CAST(&f8->IV[x])) ^= *(LTC_FAST_TYPE_PTR_CAST(&f8->MIV[x])) ^ *(LTC_FAST_TYPE_PTR_CAST(&buf[x]));
+         }
+         if ((err = cipher_descriptor[f8->cipher].ecb_encrypt(f8->IV, f8->IV, &f8->key)) != CRYPT_OK) {
+            return err;
+         }
+         len -= x;
+         pt  += x;
+         ct  += x;
+      }
+   }
+#endif
+
+   while (len > 0) {
+       if (f8->padlen == f8->blocklen) {
+          /* xor of IV, MIV and blockcnt == what goes into cipher */
+          STORE32H(f8->blockcnt, (buf+(f8->blocklen-4)));
+          ++(f8->blockcnt);
+          for (x = 0; x < f8->blocklen; x++) {
+              f8->IV[x] ^= f8->MIV[x] ^ buf[x];
+          }
+          if ((err = cipher_descriptor[f8->cipher].ecb_encrypt(f8->IV, f8->IV, &f8->key)) != CRYPT_OK) {
+             return err;
+          }
+          f8->padlen = 0;
+       }
+       *ct++ = *pt++ ^ f8->IV[f8->padlen++];
+       --len;
+   }
+   return CRYPT_OK;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/modes/f8/f8_getiv.c b/libtomcrypt/src/modes/f8/f8_getiv.c
new file mode 100644 (file)
index 0000000..a5885c9
--- /dev/null
@@ -0,0 +1,44 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+   @file ofb_getiv.c
+   F8 implementation, get IV, Tom St Denis
+*/
+
+#ifdef LTC_F8_MODE
+
+/**
+   Get the current initialization vector
+   @param IV   [out] The destination of the initialization vector
+   @param len  [in/out]  The max size and resulting size of the initialization vector
+   @param f8   The F8 state
+   @return CRYPT_OK if successful
+*/
+int f8_getiv(unsigned char *IV, unsigned long *len, symmetric_F8 *f8)
+{
+   LTC_ARGCHK(IV  != NULL);
+   LTC_ARGCHK(len != NULL);
+   LTC_ARGCHK(f8  != NULL);
+   if ((unsigned long)f8->blocklen > *len) {
+      *len = f8->blocklen;
+      return CRYPT_BUFFER_OVERFLOW;
+   }
+   XMEMCPY(IV, f8->IV, f8->blocklen);
+   *len = f8->blocklen;
+
+   return CRYPT_OK;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/modes/f8/f8_setiv.c b/libtomcrypt/src/modes/f8/f8_setiv.c
new file mode 100644 (file)
index 0000000..8f45a3f
--- /dev/null
@@ -0,0 +1,50 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+   @file f8_setiv.c
+   F8 implementation, set IV, Tom St Denis
+*/
+
+#ifdef LTC_F8_MODE
+
+/**
+   Set an initialization vector
+   @param IV   The initialization vector
+   @param len  The length of the vector (in octets)
+   @param f8   The F8 state
+   @return CRYPT_OK if successful
+*/
+int f8_setiv(const unsigned char *IV, unsigned long len, symmetric_F8 *f8)
+{
+   int err;
+
+   LTC_ARGCHK(IV != NULL);
+   LTC_ARGCHK(f8 != NULL);
+
+   if ((err = cipher_is_valid(f8->cipher)) != CRYPT_OK) {
+       return err;
+   }
+
+   if (len != (unsigned long)f8->blocklen) {
+      return CRYPT_INVALID_ARG;
+   }
+
+   /* force next block */
+   f8->padlen = 0;
+   return cipher_descriptor[f8->cipher].ecb_encrypt(IV, f8->IV, &f8->key);
+}
+
+#endif
+
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/modes/f8/f8_start.c b/libtomcrypt/src/modes/f8/f8_start.c
new file mode 100644 (file)
index 0000000..6801702
--- /dev/null
@@ -0,0 +1,96 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+   @file f8_start.c
+   F8 implementation, start chain, Tom St Denis
+*/
+
+
+#ifdef LTC_F8_MODE
+
+/**
+   Initialize an F8 context
+   @param cipher      The index of the cipher desired
+   @param IV          The initialization vector
+   @param key         The secret key
+   @param keylen      The length of the secret key (octets)
+   @param salt_key    The salting key for the IV
+   @param skeylen     The length of the salting key (octets)
+   @param num_rounds  Number of rounds in the cipher desired (0 for default)
+   @param f8          The F8 state to initialize
+   @return CRYPT_OK if successful
+*/
+int f8_start(                int  cipher, const unsigned char *IV,
+             const unsigned char *key,                    int  keylen,
+             const unsigned char *salt_key,               int  skeylen,
+                             int  num_rounds,   symmetric_F8  *f8)
+{
+   int           x, err;
+   unsigned char tkey[MAXBLOCKSIZE];
+
+   LTC_ARGCHK(IV       != NULL);
+   LTC_ARGCHK(key      != NULL);
+   LTC_ARGCHK(salt_key != NULL);
+   LTC_ARGCHK(f8       != NULL);
+
+   if ((err = cipher_is_valid(cipher)) != CRYPT_OK) {
+      return err;
+   }
+
+#ifdef LTC_FAST
+   if (cipher_descriptor[cipher].block_length % sizeof(LTC_FAST_TYPE)) {
+      return CRYPT_INVALID_ARG;
+   }
+#endif
+
+   /* copy details */
+   f8->blockcnt = 0;
+   f8->cipher   = cipher;
+   f8->blocklen = cipher_descriptor[cipher].block_length;
+   f8->padlen   = f8->blocklen;
+
+   /* now get key ^ salt_key [extend salt_ket with 0x55 as required to match length] */
+   zeromem(tkey, sizeof(tkey));
+   for (x = 0; x < keylen && x < (int)sizeof(tkey); x++) {
+       tkey[x] = key[x];
+   }
+   for (x = 0; x < skeylen && x < (int)sizeof(tkey); x++) {
+       tkey[x] ^= salt_key[x];
+   }
+   for (; x < keylen && x < (int)sizeof(tkey); x++) {
+       tkey[x] ^= 0x55;
+   }
+
+   /* now encrypt with tkey[0..keylen-1] the IV and use that as the IV */
+   if ((err = cipher_descriptor[cipher].setup(tkey, keylen, num_rounds, &f8->key)) != CRYPT_OK) {
+      return err;
+   }
+
+   /* encrypt IV */
+   if ((err = cipher_descriptor[f8->cipher].ecb_encrypt(IV, f8->MIV, &f8->key)) != CRYPT_OK) {
+      cipher_descriptor[f8->cipher].done(&f8->key);
+      return err;
+   }
+   zeromem(tkey, sizeof(tkey));
+   zeromem(f8->IV, sizeof(f8->IV));
+
+   /* terminate this cipher */
+   cipher_descriptor[f8->cipher].done(&f8->key);
+
+   /* init the cipher */
+   return cipher_descriptor[cipher].setup(key, keylen, num_rounds, &f8->key);
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/modes/f8/f8_test_mode.c b/libtomcrypt/src/modes/f8/f8_test_mode.c
new file mode 100644 (file)
index 0000000..778cd35
--- /dev/null
@@ -0,0 +1,74 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+   @file f8_test_mode.c
+   F8 implementation, test, Tom St Denis
+*/
+
+
+#ifdef LTC_F8_MODE
+
+int f8_test_mode(void)
+{
+#ifndef LTC_TEST
+   return CRYPT_NOP;
+#else
+   static const unsigned char key[16] = { 0x23, 0x48, 0x29, 0x00, 0x84, 0x67, 0xbe, 0x18,
+                                          0x6c, 0x3d, 0xe1, 0x4a, 0xae, 0x72, 0xd6, 0x2c };
+   static const unsigned char salt[4] = { 0x32, 0xf2, 0x87, 0x0d };
+   static const unsigned char IV[16]  = { 0x00, 0x6e, 0x5c, 0xba, 0x50, 0x68, 0x1d, 0xe5,
+                                          0x5c, 0x62, 0x15, 0x99, 0xd4, 0x62, 0x56, 0x4a };
+   static const unsigned char pt[39]  = { 0x70, 0x73, 0x65, 0x75, 0x64, 0x6f, 0x72, 0x61,
+                                          0x6e, 0x64, 0x6f, 0x6d, 0x6e, 0x65, 0x73, 0x73,
+                                          0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20,
+                                          0x6e, 0x65, 0x78, 0x74, 0x20, 0x62, 0x65, 0x73,
+                                          0x74, 0x20, 0x74, 0x68, 0x69, 0x6e, 0x67       };
+   static const unsigned char ct[39]  = { 0x01, 0x9c, 0xe7, 0xa2, 0x6e, 0x78, 0x54, 0x01,
+                                          0x4a, 0x63, 0x66, 0xaa, 0x95, 0xd4, 0xee, 0xfd,
+                                          0x1a, 0xd4, 0x17, 0x2a, 0x14, 0xf9, 0xfa, 0xf4,
+                                          0x55, 0xb7, 0xf1, 0xd4, 0xb6, 0x2b, 0xd0, 0x8f,
+                                          0x56, 0x2c, 0x0e, 0xef, 0x7c, 0x48, 0x02       };
+   unsigned char buf[39];
+   symmetric_F8  f8;
+   int           err, idx;
+
+   idx = find_cipher("aes");
+   if (idx == -1) {
+      idx = find_cipher("rijndael");
+      if (idx == -1) return CRYPT_NOP;
+   }
+
+   /* initialize the context */
+   if ((err = f8_start(idx, IV, key, sizeof(key), salt, sizeof(salt), 0, &f8)) != CRYPT_OK) {
+      return err;
+   }
+
+   /* encrypt block */
+   if ((err = f8_encrypt(pt, buf, sizeof(pt), &f8)) != CRYPT_OK) {
+      f8_done(&f8);
+      return err;
+   }
+   f8_done(&f8);
+
+   /* compare */
+   if (compare_testvector(buf, sizeof(ct), ct, sizeof(ct), "f8", 0)) {
+      return CRYPT_FAIL_TESTVECTOR;
+   }
+
+   return CRYPT_OK;
+#endif
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/modes/lrw/lrw_decrypt.c b/libtomcrypt/src/modes/lrw/lrw_decrypt.c
new file mode 100644 (file)
index 0000000..bfedb64
--- /dev/null
@@ -0,0 +1,49 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+   @file lrw_decrypt.c
+   LRW_MODE implementation, Decrypt blocks, Tom St Denis
+*/
+
+#ifdef LTC_LRW_MODE
+
+/**
+  LRW decrypt blocks
+  @param ct     The ciphertext
+  @param pt     [out] The plaintext
+  @param len    The length in octets, must be a multiple of 16
+  @param lrw    The LRW state
+*/
+int lrw_decrypt(const unsigned char *ct, unsigned char *pt, unsigned long len, symmetric_LRW *lrw)
+{
+   int err;
+
+   LTC_ARGCHK(pt  != NULL);
+   LTC_ARGCHK(ct  != NULL);
+   LTC_ARGCHK(lrw != NULL);
+
+   if ((err = cipher_is_valid(lrw->cipher)) != CRYPT_OK) {
+      return err;
+   }
+
+   if (cipher_descriptor[lrw->cipher].accel_lrw_decrypt != NULL) {
+      return cipher_descriptor[lrw->cipher].accel_lrw_decrypt(ct, pt, len, lrw->IV, lrw->tweak, &lrw->key);
+   }
+
+   return lrw_process(ct, pt, len, LRW_DECRYPT, lrw);
+}
+
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/modes/lrw/lrw_done.c b/libtomcrypt/src/modes/lrw/lrw_done.c
new file mode 100644 (file)
index 0000000..0088f62
--- /dev/null
@@ -0,0 +1,40 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+   @file lrw_done.c
+   LRW_MODE implementation, Free resources, Tom St Denis
+*/
+
+#ifdef LTC_LRW_MODE
+
+/**
+  Terminate a LRW state
+  @param lrw   The state to terminate
+  @return CRYPT_OK if successful
+*/
+int lrw_done(symmetric_LRW *lrw)
+{
+   int err;
+
+   LTC_ARGCHK(lrw != NULL);
+
+   if ((err = cipher_is_valid(lrw->cipher)) != CRYPT_OK) {
+      return err;
+   }
+   cipher_descriptor[lrw->cipher].done(&lrw->key);
+
+   return CRYPT_OK;
+}
+
+#endif
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/modes/lrw/lrw_encrypt.c b/libtomcrypt/src/modes/lrw/lrw_encrypt.c
new file mode 100644 (file)
index 0000000..0738648
--- /dev/null
@@ -0,0 +1,48 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+   @file lrw_encrypt.c
+   LRW_MODE implementation, Encrypt blocks, Tom St Denis
+*/
+
+#ifdef LTC_LRW_MODE
+
+/**
+  LRW encrypt blocks
+  @param pt     The plaintext
+  @param ct     [out] The ciphertext
+  @param len    The length in octets, must be a multiple of 16
+  @param lrw    The LRW state
+*/
+int lrw_encrypt(const unsigned char *pt, unsigned char *ct, unsigned long len, symmetric_LRW *lrw)
+{
+   int err;
+
+   LTC_ARGCHK(pt  != NULL);
+   LTC_ARGCHK(ct  != NULL);
+   LTC_ARGCHK(lrw != NULL);
+
+   if ((err = cipher_is_valid(lrw->cipher)) != CRYPT_OK) {
+      return err;
+   }
+
+   if (cipher_descriptor[lrw->cipher].accel_lrw_encrypt != NULL) {
+      return cipher_descriptor[lrw->cipher].accel_lrw_encrypt(pt, ct, len, lrw->IV, lrw->tweak, &lrw->key);
+   }
+
+   return lrw_process(pt, ct, len, LRW_ENCRYPT, lrw);
+}
+
+
+#endif
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/modes/lrw/lrw_getiv.c b/libtomcrypt/src/modes/lrw/lrw_getiv.c
new file mode 100644 (file)
index 0000000..6dcd96d
--- /dev/null
@@ -0,0 +1,43 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+   @file lrw_getiv.c
+   LRW_MODE implementation, Retrieve the current IV, Tom St Denis
+*/
+
+#ifdef LTC_LRW_MODE
+
+/**
+  Get the IV for LRW
+  @param IV      [out] The IV, must be 16 octets
+  @param len     Length ... must be at least 16 :-)
+  @param lrw     The LRW state to read
+  @return CRYPT_OK if successful
+*/
+int lrw_getiv(unsigned char *IV, unsigned long *len, symmetric_LRW *lrw)
+{
+   LTC_ARGCHK(IV != NULL);
+   LTC_ARGCHK(len != NULL);
+   LTC_ARGCHK(lrw != NULL);
+   if (*len < 16) {
+       *len = 16;
+       return CRYPT_BUFFER_OVERFLOW;
+   }
+
+   XMEMCPY(IV, lrw->IV, 16);
+   *len = 16;
+   return CRYPT_OK;
+}
+
+#endif
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/modes/lrw/lrw_process.c b/libtomcrypt/src/modes/lrw/lrw_process.c
new file mode 100644 (file)
index 0000000..0896bc6
--- /dev/null
@@ -0,0 +1,118 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+   @file lrw_process.c
+   LRW_MODE implementation, Encrypt/decrypt blocks, Tom St Denis
+*/
+
+#ifdef LTC_LRW_MODE
+
+/**
+  Process blocks with LRW, since decrypt/encrypt are largely the same they share this code.
+  @param pt        The "input" data
+  @param ct        [out] The "output" data
+  @param len       The length of the input, must be a multiple of 128-bits (16 octets)
+  @param mode      LRW_ENCRYPT or LRW_DECRYPT
+  @param lrw       The LRW state
+  @return  CRYPT_OK if successful
+*/
+int lrw_process(const unsigned char *pt, unsigned char *ct, unsigned long len, int mode, symmetric_LRW *lrw)
+{
+   unsigned char prod[16];
+   int           x, err;
+#ifdef LTC_LRW_TABLES
+   int           y;
+#endif
+
+   LTC_ARGCHK(pt  != NULL);
+   LTC_ARGCHK(ct  != NULL);
+   LTC_ARGCHK(lrw != NULL);
+
+   if (len & 15) {
+      return CRYPT_INVALID_ARG;
+   }
+
+   while (len) {
+      /* copy pad */
+      XMEMCPY(prod, lrw->pad, 16);
+
+      /* increment IV */
+      for (x = 15; x >= 0; x--) {
+          lrw->IV[x] = (lrw->IV[x] + 1) & 255;
+          if (lrw->IV[x]) {
+              break;
+          }
+      }
+
+      /* update pad */
+#ifdef LTC_LRW_TABLES
+      /* for each byte changed we undo it's affect on the pad then add the new product */
+      for (; x < 16; x++) {
+#ifdef LTC_FAST
+          for (y = 0; y < 16; y += sizeof(LTC_FAST_TYPE)) {
+              *(LTC_FAST_TYPE_PTR_CAST(lrw->pad + y)) ^= *(LTC_FAST_TYPE_PTR_CAST(&lrw->PC[x][lrw->IV[x]][y])) ^ *(LTC_FAST_TYPE_PTR_CAST(&lrw->PC[x][(lrw->IV[x]-1)&255][y]));
+          }
+#else
+          for (y = 0; y < 16; y++) {
+              lrw->pad[y] ^= lrw->PC[x][lrw->IV[x]][y] ^ lrw->PC[x][(lrw->IV[x]-1)&255][y];
+          }
+#endif
+      }
+#else
+      gcm_gf_mult(lrw->tweak, lrw->IV, lrw->pad);
+#endif
+
+      /* xor prod */
+#ifdef LTC_FAST
+      for (x = 0; x < 16; x += sizeof(LTC_FAST_TYPE)) {
+           *(LTC_FAST_TYPE_PTR_CAST(ct + x)) = *(LTC_FAST_TYPE_PTR_CAST(pt + x)) ^ *(LTC_FAST_TYPE_PTR_CAST(prod + x));
+      }
+#else
+      for (x = 0; x < 16; x++) {
+         ct[x] = pt[x] ^ prod[x];
+      }
+#endif
+
+      /* send through cipher */
+      if (mode == LRW_ENCRYPT) {
+         if ((err = cipher_descriptor[lrw->cipher].ecb_encrypt(ct, ct, &lrw->key)) != CRYPT_OK) {
+            return err;
+         }
+      } else {
+         if ((err = cipher_descriptor[lrw->cipher].ecb_decrypt(ct, ct, &lrw->key)) != CRYPT_OK) {
+            return err;
+         }
+      }
+
+      /* xor prod */
+#ifdef LTC_FAST
+      for (x = 0; x < 16; x += sizeof(LTC_FAST_TYPE)) {
+           *(LTC_FAST_TYPE_PTR_CAST(ct + x)) = *(LTC_FAST_TYPE_PTR_CAST(ct + x)) ^ *(LTC_FAST_TYPE_PTR_CAST(prod + x));
+      }
+#else
+      for (x = 0; x < 16; x++) {
+         ct[x] = ct[x] ^ prod[x];
+      }
+#endif
+
+      /* move to next */
+      pt  += 16;
+      ct  += 16;
+      len -= 16;
+   }
+
+   return CRYPT_OK;
+}
+
+#endif
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/modes/lrw/lrw_setiv.c b/libtomcrypt/src/modes/lrw/lrw_setiv.c
new file mode 100644 (file)
index 0000000..5c04157
--- /dev/null
@@ -0,0 +1,77 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+   @file lrw_setiv.c
+   LRW_MODE implementation, Set the current IV, Tom St Denis
+*/
+
+#ifdef LTC_LRW_MODE
+
+/**
+  Set the IV for LRW
+  @param IV      The IV, must be 16 octets
+  @param len     Length ... must be 16 :-)
+  @param lrw     The LRW state to update
+  @return CRYPT_OK if successful
+*/
+int lrw_setiv(const unsigned char *IV, unsigned long len, symmetric_LRW *lrw)
+{
+   int           err;
+#ifdef LTC_LRW_TABLES
+   unsigned char T[16];
+   int           x, y;
+#endif
+   LTC_ARGCHK(IV != NULL);
+   LTC_ARGCHK(lrw != NULL);
+
+   if (len != 16) {
+      return CRYPT_INVALID_ARG;
+   }
+
+   if ((err = cipher_is_valid(lrw->cipher)) != CRYPT_OK) {
+      return err;
+   }
+
+   /* copy the IV */
+   XMEMCPY(lrw->IV, IV, 16);
+
+   /* check if we have to actually do work */
+   if (cipher_descriptor[lrw->cipher].accel_lrw_encrypt != NULL && cipher_descriptor[lrw->cipher].accel_lrw_decrypt != NULL) {
+       /* we have accelerators, let's bail since they don't use lrw->pad anyways */
+       return CRYPT_OK;
+   }
+
+#ifdef LTC_LRW_TABLES
+   XMEMCPY(T, &lrw->PC[0][IV[0]][0], 16);
+   for (x = 1; x < 16; x++) {
+#ifdef LTC_FAST
+       for (y = 0; y < 16; y += sizeof(LTC_FAST_TYPE)) {
+           *(LTC_FAST_TYPE_PTR_CAST(T + y)) ^= *(LTC_FAST_TYPE_PTR_CAST(&lrw->PC[x][IV[x]][y]));
+       }
+#else
+       for (y = 0; y < 16; y++) {
+           T[y] ^= lrw->PC[x][IV[x]][y];
+       }
+#endif
+   }
+   XMEMCPY(lrw->pad, T, 16);
+#else
+   gcm_gf_mult(lrw->tweak, IV, lrw->pad);
+#endif
+
+   return CRYPT_OK;
+}
+
+
+#endif
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/modes/lrw/lrw_start.c b/libtomcrypt/src/modes/lrw/lrw_start.c
new file mode 100644 (file)
index 0000000..e13d3bd
--- /dev/null
@@ -0,0 +1,101 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+   @file lrw_start.c
+   LRW_MODE implementation, start mode, Tom St Denis
+*/
+
+#ifdef LTC_LRW_MODE
+
+/**
+  Initialize the LRW context
+  @param cipher        The cipher desired, must be a 128-bit block cipher
+  @param IV            The index value, must be 128-bits
+  @param key           The cipher key
+  @param keylen        The length of the cipher key in octets
+  @param tweak         The tweak value (second key), must be 128-bits
+  @param num_rounds    The number of rounds for the cipher (0 == default)
+  @param lrw           [out] The LRW state
+  @return CRYPT_OK on success.
+*/
+int lrw_start(               int   cipher,
+              const unsigned char *IV,
+              const unsigned char *key,       int keylen,
+              const unsigned char *tweak,
+                             int  num_rounds,
+                   symmetric_LRW *lrw)
+{
+   int           err;
+#ifdef LTC_LRW_TABLES
+   unsigned char B[16];
+   int           x, y, z, t;
+#endif
+
+   LTC_ARGCHK(IV    != NULL);
+   LTC_ARGCHK(key   != NULL);
+   LTC_ARGCHK(tweak != NULL);
+   LTC_ARGCHK(lrw   != NULL);
+
+#ifdef LTC_FAST
+   if (16 % sizeof(LTC_FAST_TYPE)) {
+      return CRYPT_INVALID_ARG;
+   }
+#endif
+
+   /* is cipher valid? */
+   if ((err = cipher_is_valid(cipher)) != CRYPT_OK) {
+      return err;
+   }
+   if (cipher_descriptor[cipher].block_length != 16) {
+      return CRYPT_INVALID_CIPHER;
+   }
+
+   /* schedule key */
+   if ((err = cipher_descriptor[cipher].setup(key, keylen, num_rounds, &lrw->key)) != CRYPT_OK) {
+      return err;
+   }
+   lrw->cipher = cipher;
+
+   /* copy the IV and tweak */
+   XMEMCPY(lrw->tweak, tweak, 16);
+
+#ifdef LTC_LRW_TABLES
+   /* setup tables */
+   /* generate the first table as it has no shifting (from which we make the other tables) */
+   zeromem(B, 16);
+   for (y = 0; y < 256; y++) {
+        B[0] = y;
+        gcm_gf_mult(tweak, B, &lrw->PC[0][y][0]);
+   }
+
+   /* now generate the rest of the tables based the previous table */
+   for (x = 1; x < 16; x++) {
+      for (y = 0; y < 256; y++) {
+         /* now shift it right by 8 bits */
+         t = lrw->PC[x-1][y][15];
+         for (z = 15; z > 0; z--) {
+             lrw->PC[x][y][z] = lrw->PC[x-1][y][z-1];
+         }
+         lrw->PC[x][y][0]  = gcm_shift_table[t<<1];
+         lrw->PC[x][y][1] ^= gcm_shift_table[(t<<1)+1];
+      }
+   }
+#endif
+
+   /* generate first pad */
+   return lrw_setiv(IV, 16, lrw);
+}
+
+
+#endif
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/modes/lrw/lrw_test.c b/libtomcrypt/src/modes/lrw/lrw_test.c
new file mode 100644 (file)
index 0000000..7762d47
--- /dev/null
@@ -0,0 +1,134 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+   @file lrw_test.c
+   LRW_MODE implementation, test LRW, Tom St Denis
+*/
+
+#ifdef LTC_LRW_MODE
+
+/**
+  Test LRW against specs
+  @return CRYPT_OK if goodly
+*/
+int lrw_test(void)
+{
+#ifndef  LTC_TEST
+   return CRYPT_NOP;
+#else
+   static const struct {
+      unsigned char key[16], tweak[16], IV[16], P[16], expected_tweak[16], C[16];
+   } tests[] = {
+
+{
+{ 0x45, 0x62, 0xac, 0x25, 0xf8, 0x28, 0x17, 0x6d, 0x4c, 0x26, 0x84, 0x14, 0xb5, 0x68, 0x01, 0x85 },
+{ 0x25, 0x8e, 0x2a, 0x05, 0xe7, 0x3e, 0x9d, 0x03, 0xee, 0x5a, 0x83, 0x0c, 0xcc, 0x09, 0x4c, 0x87 },
+{ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+{ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46 },
+{ 0x25, 0x8e, 0x2a, 0x05, 0xe7, 0x3e, 0x9d, 0x03, 0xee, 0x5a, 0x83, 0x0c, 0xcc, 0x09, 0x4c, 0x87 },
+{ 0xf1, 0xb2, 0x73, 0xcd, 0x65, 0xa3, 0xdf, 0x5f, 0xe9, 0x5d, 0x48, 0x92, 0x54, 0x63, 0x4e, 0xb8 }
+},
+
+{
+{ 0x59, 0x70, 0x47, 0x14, 0xf5, 0x57, 0x47, 0x8c, 0xd7, 0x79, 0xe8, 0x0f, 0x54, 0x88, 0x79, 0x44 },
+{ 0x35, 0x23, 0xc2, 0xde, 0xc5, 0x69, 0x4f, 0xa8, 0x72, 0xa9, 0xac, 0xa7, 0x0b, 0x2b, 0xee, 0xbc },
+{ 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+{ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46 },
+{ 0x1a, 0x91, 0xe1, 0x6f, 0x62, 0xb4, 0xa7, 0xd4, 0x39, 0x54, 0xd6, 0x53, 0x85, 0x95, 0xf7, 0x5e },
+{ 0x00, 0xc8, 0x2b, 0xae, 0x95, 0xbb, 0xcd, 0xe5, 0x27, 0x4f, 0x07, 0x69, 0xb2, 0x60, 0xe1, 0x36 },
+},
+
+{
+{ 0x59, 0x70, 0x47, 0x14, 0xf5, 0x57, 0x47, 0x8c, 0xd7, 0x79, 0xe8, 0x0f, 0x54, 0x88, 0x79, 0x44 },
+{ 0x67, 0x53, 0xc9, 0x0c, 0xb7, 0xd8, 0xcd, 0xe5, 0x06, 0xa0, 0x47, 0x78, 0x1a, 0xad, 0x85, 0x11 },
+{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02 },
+{ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46 },
+{ 0x1a, 0x91, 0xe1, 0x6f, 0x62, 0xb4, 0xa7, 0xd4, 0x39, 0x54, 0xd6, 0x53, 0x85, 0x95, 0xf7, 0x5e },
+{ 0x00, 0xc8, 0x2b, 0xae, 0x95, 0xbb, 0xcd, 0xe5, 0x27, 0x4f, 0x07, 0x69, 0xb2, 0x60, 0xe1, 0x36 },
+},
+
+{
+
+{ 0xd8, 0x2a, 0x91, 0x34, 0xb2, 0x6a, 0x56, 0x50, 0x30, 0xfe, 0x69, 0xe2, 0x37, 0x7f, 0x98, 0x47 },
+{ 0x4e, 0xb5, 0x5d, 0x31, 0x05, 0x97, 0x3a, 0x3f, 0x5e, 0x23, 0xda, 0xfb, 0x5a, 0x45, 0xd6, 0xc0 },
+{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00 },
+{ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46 },
+{ 0x18, 0xc9, 0x1f, 0x6d, 0x60, 0x1a, 0x1a, 0x37, 0x5d, 0x0b, 0x0e, 0xf7, 0x3a, 0xd5, 0x74, 0xc4 },
+{ 0x76, 0x32, 0x21, 0x83, 0xed, 0x8f, 0xf1, 0x82, 0xf9, 0x59, 0x62, 0x03, 0x69, 0x0e, 0x5e, 0x01 },
+
+}
+};
+
+  int idx, err, x;
+  symmetric_LRW lrw;
+  unsigned char buf[2][16];
+
+  idx = find_cipher("aes");
+  if (idx == -1) {
+     idx = find_cipher("rijndael");
+     if (idx == -1) {
+        return CRYPT_NOP;
+     }
+  }
+
+  for (x = 0; x < (int)(sizeof(tests)/sizeof(tests[0])); x++) {
+     /* schedule it */
+     if ((err = lrw_start(idx, tests[x].IV, tests[x].key, 16, tests[x].tweak, 0, &lrw)) != CRYPT_OK) {
+        return err;
+     }
+
+     /* check pad against expected tweak */
+     if (compare_testvector(tests[x].expected_tweak, 16, lrw.pad, 16, "LRW Tweak", x)) {
+        lrw_done(&lrw);
+        return CRYPT_FAIL_TESTVECTOR;
+     }
+
+     /* process block */
+     if ((err = lrw_encrypt(tests[x].P, buf[0], 16, &lrw)) != CRYPT_OK) {
+        lrw_done(&lrw);
+        return err;
+     }
+
+     if (compare_testvector(buf[0], 16, tests[x].C, 16, "LRW Encrypt", x)) {
+        lrw_done(&lrw);
+        return CRYPT_FAIL_TESTVECTOR;
+     }
+
+     /* process block */
+     if ((err = lrw_setiv(tests[x].IV, 16, &lrw)) != CRYPT_OK) {
+        lrw_done(&lrw);
+        return err;
+     }
+
+     if ((err = lrw_decrypt(buf[0], buf[1], 16, &lrw)) != CRYPT_OK) {
+        lrw_done(&lrw);
+        return err;
+     }
+
+     if (compare_testvector(buf[1], 16, tests[x].P, 16, "LRW Decrypt", x)) {
+        lrw_done(&lrw);
+        return CRYPT_FAIL_TESTVECTOR;
+     }
+     if ((err = lrw_done(&lrw)) != CRYPT_OK) {
+        return err;
+     }
+  }
+  return CRYPT_OK;
+#endif
+}
+
+#endif
+
+
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/modes/ofb/ofb_decrypt.c b/libtomcrypt/src/modes/ofb/ofb_decrypt.c
new file mode 100644 (file)
index 0000000..f402802
--- /dev/null
@@ -0,0 +1,41 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file ofb_decrypt.c
+  OFB implementation, decrypt data, Tom St Denis
+*/
+
+#ifdef LTC_OFB_MODE
+
+/**
+   OFB decrypt
+   @param ct      Ciphertext
+   @param pt      [out] Plaintext
+   @param len     Length of ciphertext (octets)
+   @param ofb     OFB state
+   @return CRYPT_OK if successful
+*/
+int ofb_decrypt(const unsigned char *ct, unsigned char *pt, unsigned long len, symmetric_OFB *ofb)
+{
+   LTC_ARGCHK(pt != NULL);
+   LTC_ARGCHK(ct != NULL);
+   LTC_ARGCHK(ofb != NULL);
+   return ofb_encrypt(ct, pt, len, ofb);
+}
+
+
+#endif
+
+
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/modes/ofb/ofb_done.c b/libtomcrypt/src/modes/ofb/ofb_done.c
new file mode 100644 (file)
index 0000000..9caddbe
--- /dev/null
@@ -0,0 +1,40 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+   @file ofb_done.c
+   OFB implementation, finish chain, Tom St Denis
+*/
+
+#ifdef LTC_OFB_MODE
+
+/** Terminate the chain
+  @param ofb    The OFB chain to terminate
+  @return CRYPT_OK on success
+*/
+int ofb_done(symmetric_OFB *ofb)
+{
+   int err;
+   LTC_ARGCHK(ofb != NULL);
+
+   if ((err = cipher_is_valid(ofb->cipher)) != CRYPT_OK) {
+      return err;
+   }
+   cipher_descriptor[ofb->cipher].done(&ofb->key);
+   return CRYPT_OK;
+}
+
+
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/modes/ofb/ofb_encrypt.c b/libtomcrypt/src/modes/ofb/ofb_encrypt.c
new file mode 100644 (file)
index 0000000..415842d
--- /dev/null
@@ -0,0 +1,58 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file ofb_encrypt.c
+  OFB implementation, encrypt data, Tom St Denis
+*/
+
+#ifdef LTC_OFB_MODE
+
+/**
+  OFB encrypt
+  @param pt     Plaintext
+  @param ct     [out] Ciphertext
+  @param len    Length of plaintext (octets)
+  @param ofb    OFB state
+  @return CRYPT_OK if successful
+*/
+int ofb_encrypt(const unsigned char *pt, unsigned char *ct, unsigned long len, symmetric_OFB *ofb)
+{
+   int err;
+   LTC_ARGCHK(pt != NULL);
+   LTC_ARGCHK(ct != NULL);
+   LTC_ARGCHK(ofb != NULL);
+   if ((err = cipher_is_valid(ofb->cipher)) != CRYPT_OK) {
+       return err;
+   }
+
+   /* is blocklen/padlen valid? */
+   if (ofb->blocklen < 0 || ofb->blocklen > (int)sizeof(ofb->IV) ||
+       ofb->padlen   < 0 || ofb->padlen   > (int)sizeof(ofb->IV)) {
+      return CRYPT_INVALID_ARG;
+   }
+
+   while (len-- > 0) {
+       if (ofb->padlen == ofb->blocklen) {
+          if ((err = cipher_descriptor[ofb->cipher].ecb_encrypt(ofb->IV, ofb->IV, &ofb->key)) != CRYPT_OK) {
+             return err;
+          }
+          ofb->padlen = 0;
+       }
+       *ct++ = *pt++ ^ ofb->IV[(ofb->padlen)++];
+   }
+   return CRYPT_OK;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/modes/ofb/ofb_getiv.c b/libtomcrypt/src/modes/ofb/ofb_getiv.c
new file mode 100644 (file)
index 0000000..e6bc0ed
--- /dev/null
@@ -0,0 +1,44 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+   @file ofb_getiv.c
+   OFB implementation, get IV, Tom St Denis
+*/
+
+#ifdef LTC_OFB_MODE
+
+/**
+   Get the current initialization vector
+   @param IV   [out] The destination of the initialization vector
+   @param len  [in/out]  The max size and resulting size of the initialization vector
+   @param ofb  The OFB state
+   @return CRYPT_OK if successful
+*/
+int ofb_getiv(unsigned char *IV, unsigned long *len, symmetric_OFB *ofb)
+{
+   LTC_ARGCHK(IV  != NULL);
+   LTC_ARGCHK(len != NULL);
+   LTC_ARGCHK(ofb != NULL);
+   if ((unsigned long)ofb->blocklen > *len) {
+      *len = ofb->blocklen;
+      return CRYPT_BUFFER_OVERFLOW;
+   }
+   XMEMCPY(IV, ofb->IV, ofb->blocklen);
+   *len = ofb->blocklen;
+
+   return CRYPT_OK;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/modes/ofb/ofb_setiv.c b/libtomcrypt/src/modes/ofb/ofb_setiv.c
new file mode 100644 (file)
index 0000000..005dbc7
--- /dev/null
@@ -0,0 +1,50 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+   @file ofb_setiv.c
+   OFB implementation, set IV, Tom St Denis
+*/
+
+#ifdef LTC_OFB_MODE
+
+/**
+   Set an initialization vector
+   @param IV   The initialization vector
+   @param len  The length of the vector (in octets)
+   @param ofb  The OFB state
+   @return CRYPT_OK if successful
+*/
+int ofb_setiv(const unsigned char *IV, unsigned long len, symmetric_OFB *ofb)
+{
+   int err;
+
+   LTC_ARGCHK(IV  != NULL);
+   LTC_ARGCHK(ofb != NULL);
+
+   if ((err = cipher_is_valid(ofb->cipher)) != CRYPT_OK) {
+       return err;
+   }
+
+   if (len != (unsigned long)ofb->blocklen) {
+      return CRYPT_INVALID_ARG;
+   }
+
+   /* force next block */
+   ofb->padlen = 0;
+   return cipher_descriptor[ofb->cipher].ecb_encrypt(IV, ofb->IV, &ofb->key);
+}
+
+#endif
+
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/modes/ofb/ofb_start.c b/libtomcrypt/src/modes/ofb/ofb_start.c
new file mode 100644 (file)
index 0000000..fe7a764
--- /dev/null
@@ -0,0 +1,58 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+   @file ofb_start.c
+   OFB implementation, start chain, Tom St Denis
+*/
+
+
+#ifdef LTC_OFB_MODE
+
+/**
+   Initialize a OFB context
+   @param cipher      The index of the cipher desired
+   @param IV          The initialization vector
+   @param key         The secret key
+   @param keylen      The length of the secret key (octets)
+   @param num_rounds  Number of rounds in the cipher desired (0 for default)
+   @param ofb         The OFB state to initialize
+   @return CRYPT_OK if successful
+*/
+int ofb_start(int cipher, const unsigned char *IV, const unsigned char *key,
+              int keylen, int num_rounds, symmetric_OFB *ofb)
+{
+   int x, err;
+
+   LTC_ARGCHK(IV != NULL);
+   LTC_ARGCHK(key != NULL);
+   LTC_ARGCHK(ofb != NULL);
+
+   if ((err = cipher_is_valid(cipher)) != CRYPT_OK) {
+      return err;
+   }
+
+   /* copy details */
+   ofb->cipher = cipher;
+   ofb->blocklen = cipher_descriptor[cipher].block_length;
+   for (x = 0; x < ofb->blocklen; x++) {
+       ofb->IV[x] = IV[x];
+   }
+
+   /* init the cipher */
+   ofb->padlen = ofb->blocklen;
+   return cipher_descriptor[cipher].setup(key, keylen, num_rounds, &ofb->key);
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/modes/xts/xts_decrypt.c b/libtomcrypt/src/modes/xts/xts_decrypt.c
new file mode 100644 (file)
index 0000000..4580991
--- /dev/null
@@ -0,0 +1,156 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+ Source donated by Elliptic Semiconductor Inc (www.ellipticsemi.com) to the LibTom Projects
+ */
+
+#ifdef LTC_XTS_MODE
+
+static int _tweak_uncrypt(const unsigned char *C, unsigned char *P, unsigned char *T, symmetric_xts *xts)
+{
+   unsigned long x;
+   int err;
+
+   /* tweak encrypt block i */
+#ifdef LTC_FAST
+   for (x = 0; x < 16; x += sizeof(LTC_FAST_TYPE)) {
+      *(LTC_FAST_TYPE_PTR_CAST(&P[x])) = *(LTC_FAST_TYPE_PTR_CAST(&C[x])) ^ *(LTC_FAST_TYPE_PTR_CAST(&T[x]));
+   }
+#else
+   for (x = 0; x < 16; x++) {
+      P[x] = C[x] ^ T[x];
+   }
+#endif
+
+   err = cipher_descriptor[xts->cipher].ecb_decrypt(P, P, &xts->key1);
+
+#ifdef LTC_FAST
+   for (x = 0; x < 16; x += sizeof(LTC_FAST_TYPE)) {
+      *(LTC_FAST_TYPE_PTR_CAST(&P[x])) ^= *(LTC_FAST_TYPE_PTR_CAST(&T[x]));
+   }
+#else
+   for (x = 0; x < 16; x++) {
+      P[x] = P[x] ^ T[x];
+   }
+#endif
+
+   /* LFSR the tweak */
+   xts_mult_x(T);
+
+   return err;
+}
+
+/** XTS Decryption
+ @param ct     [in] Ciphertext
+ @param ptlen  Length of plaintext (and ciphertext)
+ @param pt     [out]  Plaintext
+ @param tweak  [in] The 128--bit encryption tweak (e.g. sector number)
+ @param xts    The XTS structure
+ Returns CRYPT_OK upon success
+ */
+int xts_decrypt(const unsigned char *ct, unsigned long ptlen, unsigned char *pt, unsigned char *tweak,
+                symmetric_xts *xts)
+{
+   unsigned char PP[16], CC[16], T[16];
+   unsigned long i, m, mo, lim;
+   int err;
+
+   /* check inputs */
+   LTC_ARGCHK(pt != NULL);
+   LTC_ARGCHK(ct != NULL);
+   LTC_ARGCHK(tweak != NULL);
+   LTC_ARGCHK(xts != NULL);
+
+   /* check if valid */
+   if ((err = cipher_is_valid(xts->cipher)) != CRYPT_OK) {
+      return err;
+   }
+
+   /* get number of blocks */
+   m = ptlen >> 4;
+   mo = ptlen & 15;
+
+   /* must have at least one full block */
+   if (m == 0) {
+      return CRYPT_INVALID_ARG;
+   }
+
+   if (mo == 0) {
+      lim = m;
+   } else {
+      lim = m - 1;
+   }
+
+   if (cipher_descriptor[xts->cipher].accel_xts_decrypt && lim > 0) {
+
+      /* use accelerated decryption for whole blocks */
+      if ((err = cipher_descriptor[xts->cipher].accel_xts_decrypt(ct, pt, lim, tweak, &xts->key1, &xts->key2)) !=
+                 CRYPT_OK) {
+         return err;
+      }
+      ct += lim * 16;
+      pt += lim * 16;
+
+      /* tweak is encrypted on output */
+      XMEMCPY(T, tweak, sizeof(T));
+   } else {
+      /* encrypt the tweak */
+      if ((err = cipher_descriptor[xts->cipher].ecb_encrypt(tweak, T, &xts->key2)) != CRYPT_OK) {
+         return err;
+      }
+
+      for (i = 0; i < lim; i++) {
+         if ((err = _tweak_uncrypt(ct, pt, T, xts)) != CRYPT_OK) {
+            return err;
+         }
+         ct += 16;
+         pt += 16;
+      }
+   }
+
+   /* if ptlen not divide 16 then */
+   if (mo > 0) {
+      XMEMCPY(CC, T, 16);
+      xts_mult_x(CC);
+
+      /* PP = tweak decrypt block m-1 */
+      if ((err = _tweak_uncrypt(ct, PP, CC, xts)) != CRYPT_OK) {
+         return err;
+      }
+
+      /* Pm = first ptlen % 16 bytes of PP */
+      for (i = 0; i < mo; i++) {
+         CC[i] = ct[16 + i];
+         pt[16 + i] = PP[i];
+      }
+      for (; i < 16; i++) {
+         CC[i] = PP[i];
+      }
+
+      /* Pm-1 = Tweak uncrypt CC */
+      if ((err = _tweak_uncrypt(CC, pt, T, xts)) != CRYPT_OK) {
+         return err;
+      }
+   }
+
+   /* Decrypt the tweak back */
+   if ((err = cipher_descriptor[xts->cipher].ecb_decrypt(T, tweak, &xts->key2)) != CRYPT_OK) {
+      return err;
+   }
+
+   return CRYPT_OK;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/modes/xts/xts_done.c b/libtomcrypt/src/modes/xts/xts_done.c
new file mode 100644 (file)
index 0000000..558c043
--- /dev/null
@@ -0,0 +1,31 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  Source donated by Elliptic Semiconductor Inc (www.ellipticsemi.com) to the LibTom Projects
+*/
+
+#ifdef LTC_XTS_MODE
+
+/** Terminate XTS state
+   @param xts    The state to terminate
+*/
+void xts_done(symmetric_xts *xts)
+{
+   LTC_ARGCHKVD(xts != NULL);
+   cipher_descriptor[xts->cipher].done(&xts->key1);
+   cipher_descriptor[xts->cipher].done(&xts->key2);
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/modes/xts/xts_encrypt.c b/libtomcrypt/src/modes/xts/xts_encrypt.c
new file mode 100644 (file)
index 0000000..787c302
--- /dev/null
@@ -0,0 +1,157 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+ Source donated by Elliptic Semiconductor Inc (www.ellipticsemi.com) to the LibTom Projects
+ */
+
+#ifdef LTC_XTS_MODE
+
+static int _tweak_crypt(const unsigned char *P, unsigned char *C, unsigned char *T, symmetric_xts *xts)
+{
+   unsigned long x;
+   int err;
+
+   /* tweak encrypt block i */
+#ifdef LTC_FAST
+   for (x = 0; x < 16; x += sizeof(LTC_FAST_TYPE)) {
+      *(LTC_FAST_TYPE_PTR_CAST(&C[x])) = *(LTC_FAST_TYPE_PTR_CAST(&P[x])) ^ *(LTC_FAST_TYPE_PTR_CAST(&T[x]));
+   }
+#else
+   for (x = 0; x < 16; x++) {
+      C[x] = P[x] ^ T[x];
+   }
+#endif
+
+   if ((err = cipher_descriptor[xts->cipher].ecb_encrypt(C, C, &xts->key1)) != CRYPT_OK) {
+      return err;
+   }
+
+#ifdef LTC_FAST
+   for (x = 0; x < 16; x += sizeof(LTC_FAST_TYPE)) {
+      *(LTC_FAST_TYPE_PTR_CAST(&C[x])) ^= *(LTC_FAST_TYPE_PTR_CAST(&T[x]));
+   }
+#else
+   for (x = 0; x < 16; x++) {
+      C[x] = C[x] ^ T[x];
+   }
+#endif
+
+   /* LFSR the tweak */
+   xts_mult_x(T);
+
+   return CRYPT_OK;
+}
+
+/** XTS Encryption
+ @param pt     [in]  Plaintext
+ @param ptlen  Length of plaintext (and ciphertext)
+ @param ct     [out] Ciphertext
+ @param tweak  [in] The 128--bit encryption tweak (e.g. sector number)
+ @param xts    The XTS structure
+ Returns CRYPT_OK upon success
+ */
+int xts_encrypt(const unsigned char *pt, unsigned long ptlen, unsigned char *ct, unsigned char *tweak,
+                symmetric_xts *xts)
+{
+   unsigned char PP[16], CC[16], T[16];
+   unsigned long i, m, mo, lim;
+   int err;
+
+   /* check inputs */
+   LTC_ARGCHK(pt != NULL);
+   LTC_ARGCHK(ct != NULL);
+   LTC_ARGCHK(tweak != NULL);
+   LTC_ARGCHK(xts != NULL);
+
+   /* check if valid */
+   if ((err = cipher_is_valid(xts->cipher)) != CRYPT_OK) {
+      return err;
+   }
+
+   /* get number of blocks */
+   m = ptlen >> 4;
+   mo = ptlen & 15;
+
+   /* must have at least one full block */
+   if (m == 0) {
+      return CRYPT_INVALID_ARG;
+   }
+
+   if (mo == 0) {
+      lim = m;
+   } else {
+      lim = m - 1;
+   }
+
+   if (cipher_descriptor[xts->cipher].accel_xts_encrypt && lim > 0) {
+
+      /* use accelerated encryption for whole blocks */
+      if ((err = cipher_descriptor[xts->cipher].accel_xts_encrypt(pt, ct, lim, tweak, &xts->key1, &xts->key2)) !=
+                 CRYPT_OK) {
+         return err;
+      }
+      ct += lim * 16;
+      pt += lim * 16;
+
+      /* tweak is encrypted on output */
+      XMEMCPY(T, tweak, sizeof(T));
+   } else {
+
+      /* encrypt the tweak */
+      if ((err = cipher_descriptor[xts->cipher].ecb_encrypt(tweak, T, &xts->key2)) != CRYPT_OK) {
+         return err;
+      }
+
+      for (i = 0; i < lim; i++) {
+         if ((err = _tweak_crypt(pt, ct, T, xts)) != CRYPT_OK) {
+            return err;
+         }
+         ct += 16;
+         pt += 16;
+      }
+   }
+
+   /* if ptlen not divide 16 then */
+   if (mo > 0) {
+      /* CC = tweak encrypt block m-1 */
+      if ((err = _tweak_crypt(pt, CC, T, xts)) != CRYPT_OK) {
+         return err;
+      }
+
+      /* Cm = first ptlen % 16 bytes of CC */
+      for (i = 0; i < mo; i++) {
+         PP[i] = pt[16 + i];
+         ct[16 + i] = CC[i];
+      }
+
+      for (; i < 16; i++) {
+         PP[i] = CC[i];
+      }
+
+      /* Cm-1 = Tweak encrypt PP */
+      if ((err = _tweak_crypt(PP, ct, T, xts)) != CRYPT_OK) {
+         return err;
+      }
+   }
+
+   /* Decrypt the tweak back */
+   if ((err = cipher_descriptor[xts->cipher].ecb_decrypt(T, tweak, &xts->key2)) != CRYPT_OK) {
+      return err;
+   }
+
+   return err;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/modes/xts/xts_init.c b/libtomcrypt/src/modes/xts/xts_init.c
new file mode 100644 (file)
index 0000000..be0ac6a
--- /dev/null
@@ -0,0 +1,61 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  Source donated by Elliptic Semiconductor Inc (www.ellipticsemi.com) to the LibTom Projects
+*/
+
+#ifdef LTC_XTS_MODE
+
+/** Start XTS mode
+   @param cipher      The index of the cipher to use
+   @param key1        The encrypt key
+   @param key2        The tweak encrypt key
+   @param keylen      The length of the keys (each) in octets
+   @param num_rounds  The number of rounds for the cipher (0 == default)
+   @param xts         [out] XTS structure
+   Returns CRYPT_OK upon success.
+*/
+int xts_start(int cipher, const unsigned char *key1, const unsigned char *key2, unsigned long keylen, int num_rounds,
+              symmetric_xts *xts)
+{
+   int err;
+
+   /* check inputs */
+   LTC_ARGCHK(key1 != NULL);
+   LTC_ARGCHK(key2 != NULL);
+   LTC_ARGCHK(xts != NULL);
+
+   /* check if valid */
+   if ((err = cipher_is_valid(cipher)) != CRYPT_OK) {
+      return err;
+   }
+
+   if (cipher_descriptor[cipher].block_length != 16) {
+      return CRYPT_INVALID_ARG;
+   }
+
+   /* schedule the two ciphers */
+   if ((err = cipher_descriptor[cipher].setup(key1, keylen, num_rounds, &xts->key1)) != CRYPT_OK) {
+      return err;
+   }
+   if ((err = cipher_descriptor[cipher].setup(key2, keylen, num_rounds, &xts->key2)) != CRYPT_OK) {
+      return err;
+   }
+   xts->cipher = cipher;
+
+   return err;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/modes/xts/xts_mult_x.c b/libtomcrypt/src/modes/xts/xts_mult_x.c
new file mode 100644 (file)
index 0000000..3fad22b
--- /dev/null
@@ -0,0 +1,39 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  Source donated by Elliptic Semiconductor Inc (www.ellipticsemi.com) to the LibTom Projects
+*/
+
+#ifdef LTC_XTS_MODE
+
+/** multiply by x
+  @param I      The value to multiply by x (LFSR shift)
+*/
+void xts_mult_x(unsigned char *I)
+{
+   int x;
+   unsigned char t, tt;
+
+   for (x = t = 0; x < 16; x++) {
+      tt = I[x] >> 7;
+      I[x] = ((I[x] << 1) | t) & 0xFF;
+      t = tt;
+   }
+   if (tt) {
+      I[0] ^= 0x87;
+   }
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/modes/xts/xts_test.c b/libtomcrypt/src/modes/xts/xts_test.c
new file mode 100644 (file)
index 0000000..347fb4b
--- /dev/null
@@ -0,0 +1,306 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+#ifdef LTC_XTS_MODE
+
+#ifndef LTC_NO_TEST
+static int _xts_test_accel_xts_encrypt(const unsigned char *pt, unsigned char *ct, unsigned long blocks,
+                                       unsigned char *tweak, symmetric_key *skey1, symmetric_key *skey2)
+{
+   int ret;
+   symmetric_xts xts;
+   int (*orig)(const unsigned char *, unsigned char *,
+               unsigned long , unsigned char *, symmetric_key *,
+               symmetric_key *);
+
+   /* AES can be under rijndael or aes... try to find it */
+   if ((xts.cipher = find_cipher("aes")) == -1) {
+      if ((xts.cipher = find_cipher("rijndael")) == -1) {
+         return CRYPT_NOP;
+      }
+   }
+   orig = cipher_descriptor[xts.cipher].accel_xts_encrypt;
+   cipher_descriptor[xts.cipher].accel_xts_encrypt = NULL;
+
+   XMEMCPY(&xts.key1, skey1, sizeof(symmetric_key));
+   XMEMCPY(&xts.key2, skey2, sizeof(symmetric_key));
+
+   ret = xts_encrypt(pt, blocks << 4, ct, tweak, &xts);
+   cipher_descriptor[xts.cipher].accel_xts_encrypt = orig;
+
+   return ret;
+}
+
+static int _xts_test_accel_xts_decrypt(const unsigned char *ct, unsigned char *pt, unsigned long blocks,
+                                       unsigned char *tweak, symmetric_key *skey1, symmetric_key *skey2)
+{
+   int ret;
+   symmetric_xts xts;
+   int (*orig)(const unsigned char *, unsigned char *,
+               unsigned long , unsigned char *, symmetric_key *,
+               symmetric_key *);
+
+   /* AES can be under rijndael or aes... try to find it */
+   if ((xts.cipher = find_cipher("aes")) == -1) {
+      if ((xts.cipher = find_cipher("rijndael")) == -1) {
+         return CRYPT_NOP;
+      }
+   }
+   orig = cipher_descriptor[xts.cipher].accel_xts_decrypt;
+   cipher_descriptor[xts.cipher].accel_xts_decrypt = NULL;
+
+   XMEMCPY(&xts.key1, skey1, sizeof(symmetric_key));
+   XMEMCPY(&xts.key2, skey2, sizeof(symmetric_key));
+
+   ret = xts_decrypt(ct, blocks << 4, pt, tweak, &xts);
+   cipher_descriptor[xts.cipher].accel_xts_decrypt = orig;
+
+   return ret;
+}
+#endif
+
+/**
+  Source donated by Elliptic Semiconductor Inc (www.ellipticsemi.com) to the LibTom Projects
+
+  Returns CRYPT_OK upon success.
+*/
+int xts_test(void)
+{
+#ifdef LTC_NO_TEST
+   return CRYPT_NOP;
+#else
+   static const struct
+   {
+      int keylen;
+      unsigned char key1[32];
+      unsigned char key2[32];
+      ulong64 seqnum;
+      unsigned long PTLEN;
+      unsigned char PTX[512], CTX[512];
+   } tests[] = {
+
+/* #1 32 byte key, 32 byte PTX */
+{
+   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 },
+   0,
+   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 },
+   { 0x91,0x7c,0xf6,0x9e,0xbd,0x68,0xb2,0xec,0x9b,0x9f,0xe9,0xa3,0xea,0xdd,0xa6,0x92,0xcd,0x43,0xd2,0xf5,0x95,0x98,0xed,0x85,0x8c,0x02,0xc2,0x65,0x2f,0xbf,0x92,0x2e },
+},
+
+/* #2, 32 byte key, 32 byte PTX */
+{
+   32,
+   { 0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11 },
+   { 0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22 },
+   CONST64(0x3333333333),
+   32,
+   { 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44 },
+   { 0xc4,0x54,0x18,0x5e,0x6a,0x16,0x93,0x6e,0x39,0x33,0x40,0x38,0xac,0xef,0x83,0x8b,0xfb,0x18,0x6f,0xff,0x74,0x80,0xad,0xc4,0x28,0x93,0x82,0xec,0xd6,0xd3,0x94,0xf0 },
+},
+
+/* #5 from xts.7, 32 byte key, 32 byte PTX */
+{
+   32,
+   { 0xff,0xfe,0xfd,0xfc,0xfb,0xfa,0xf9,0xf8,0xf7,0xf6,0xf5,0xf4,0xf3,0xf2,0xf1,0xf0 },
+   { 0xbf,0xbe,0xbd,0xbc,0xbb,0xba,0xb9,0xb8,0xb7,0xb6,0xb5,0xb4,0xb3,0xb2,0xb1,0xb0 },
+   CONST64(0x123456789a),
+   32,
+   { 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44 },
+   { 0xb0,0x1f,0x86,0xf8,0xed,0xc1,0x86,0x37,0x06,0xfa,0x8a,0x42,0x53,0xe3,0x4f,0x28,0xaf,0x31,0x9d,0xe3,0x83,0x34,0x87,0x0f,0x4d,0xd1,0xf9,0x4c,0xbe,0x98,0x32,0xf1 },
+},
+
+/* #4, 32 byte key, 512 byte PTX  */
+{
+   32,
+   { 0x27,0x18,0x28,0x18,0x28,0x45,0x90,0x45,0x23,0x53,0x60,0x28,0x74,0x71,0x35,0x26 },
+   { 0x31,0x41,0x59,0x26,0x53,0x58,0x97,0x93,0x23,0x84,0x62,0x64,0x33,0x83,0x27,0x95 },
+   0,
+   512,
+   {
+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,
+0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
+0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f,
+0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,
+0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f,
+0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf,
+0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf,
+0xe0,0xe1,0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,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,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,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
+0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f,
+0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,
+0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f,
+0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf,
+0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf,
+0xe0,0xe1,0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0xff,
+   },
+   {
+0x27,0xa7,0x47,0x9b,0xef,0xa1,0xd4,0x76,0x48,0x9f,0x30,0x8c,0xd4,0xcf,0xa6,0xe2,0xa9,0x6e,0x4b,0xbe,0x32,0x08,0xff,0x25,0x28,0x7d,0xd3,0x81,0x96,0x16,0xe8,0x9c,
+0xc7,0x8c,0xf7,0xf5,0xe5,0x43,0x44,0x5f,0x83,0x33,0xd8,0xfa,0x7f,0x56,0x00,0x00,0x05,0x27,0x9f,0xa5,0xd8,0xb5,0xe4,0xad,0x40,0xe7,0x36,0xdd,0xb4,0xd3,0x54,0x12,
+0x32,0x80,0x63,0xfd,0x2a,0xab,0x53,0xe5,0xea,0x1e,0x0a,0x9f,0x33,0x25,0x00,0xa5,0xdf,0x94,0x87,0xd0,0x7a,0x5c,0x92,0xcc,0x51,0x2c,0x88,0x66,0xc7,0xe8,0x60,0xce,
+0x93,0xfd,0xf1,0x66,0xa2,0x49,0x12,0xb4,0x22,0x97,0x61,0x46,0xae,0x20,0xce,0x84,0x6b,0xb7,0xdc,0x9b,0xa9,0x4a,0x76,0x7a,0xae,0xf2,0x0c,0x0d,0x61,0xad,0x02,0x65,
+0x5e,0xa9,0x2d,0xc4,0xc4,0xe4,0x1a,0x89,0x52,0xc6,0x51,0xd3,0x31,0x74,0xbe,0x51,0xa1,0x0c,0x42,0x11,0x10,0xe6,0xd8,0x15,0x88,0xed,0xe8,0x21,0x03,0xa2,0x52,0xd8,
+0xa7,0x50,0xe8,0x76,0x8d,0xef,0xff,0xed,0x91,0x22,0x81,0x0a,0xae,0xb9,0x9f,0x91,0x72,0xaf,0x82,0xb6,0x04,0xdc,0x4b,0x8e,0x51,0xbc,0xb0,0x82,0x35,0xa6,0xf4,0x34,
+0x13,0x32,0xe4,0xca,0x60,0x48,0x2a,0x4b,0xa1,0xa0,0x3b,0x3e,0x65,0x00,0x8f,0xc5,0xda,0x76,0xb7,0x0b,0xf1,0x69,0x0d,0xb4,0xea,0xe2,0x9c,0x5f,0x1b,0xad,0xd0,0x3c,
+0x5c,0xcf,0x2a,0x55,0xd7,0x05,0xdd,0xcd,0x86,0xd4,0x49,0x51,0x1c,0xeb,0x7e,0xc3,0x0b,0xf1,0x2b,0x1f,0xa3,0x5b,0x91,0x3f,0x9f,0x74,0x7a,0x8a,0xfd,0x1b,0x13,0x0e,
+0x94,0xbf,0xf9,0x4e,0xff,0xd0,0x1a,0x91,0x73,0x5c,0xa1,0x72,0x6a,0xcd,0x0b,0x19,0x7c,0x4e,0x5b,0x03,0x39,0x36,0x97,0xe1,0x26,0x82,0x6f,0xb6,0xbb,0xde,0x8e,0xcc,
+0x1e,0x08,0x29,0x85,0x16,0xe2,0xc9,0xed,0x03,0xff,0x3c,0x1b,0x78,0x60,0xf6,0xde,0x76,0xd4,0xce,0xcd,0x94,0xc8,0x11,0x98,0x55,0xef,0x52,0x97,0xca,0x67,0xe9,0xf3,
+0xe7,0xff,0x72,0xb1,0xe9,0x97,0x85,0xca,0x0a,0x7e,0x77,0x20,0xc5,0xb3,0x6d,0xc6,0xd7,0x2c,0xac,0x95,0x74,0xc8,0xcb,0xbc,0x2f,0x80,0x1e,0x23,0xe5,0x6f,0xd3,0x44,
+0xb0,0x7f,0x22,0x15,0x4b,0xeb,0xa0,0xf0,0x8c,0xe8,0x89,0x1e,0x64,0x3e,0xd9,0x95,0xc9,0x4d,0x9a,0x69,0xc9,0xf1,0xb5,0xf4,0x99,0x02,0x7a,0x78,0x57,0x2a,0xee,0xbd,
+0x74,0xd2,0x0c,0xc3,0x98,0x81,0xc2,0x13,0xee,0x77,0x0b,0x10,0x10,0xe4,0xbe,0xa7,0x18,0x84,0x69,0x77,0xae,0x11,0x9f,0x7a,0x02,0x3a,0xb5,0x8c,0xca,0x0a,0xd7,0x52,
+0xaf,0xe6,0x56,0xbb,0x3c,0x17,0x25,0x6a,0x9f,0x6e,0x9b,0xf1,0x9f,0xdd,0x5a,0x38,0xfc,0x82,0xbb,0xe8,0x72,0xc5,0x53,0x9e,0xdb,0x60,0x9e,0xf4,0xf7,0x9c,0x20,0x3e,
+0xbb,0x14,0x0f,0x2e,0x58,0x3c,0xb2,0xad,0x15,0xb4,0xaa,0x5b,0x65,0x50,0x16,0xa8,0x44,0x92,0x77,0xdb,0xd4,0x77,0xef,0x2c,0x8d,0x6c,0x01,0x7d,0xb7,0x38,0xb1,0x8d,
+0xeb,0x4a,0x42,0x7d,0x19,0x23,0xce,0x3f,0xf2,0x62,0x73,0x57,0x79,0xa4,0x18,0xf2,0x0a,0x28,0x2d,0xf9,0x20,0x14,0x7b,0xea,0xbe,0x42,0x1e,0xe5,0x31,0x9d,0x05,0x68,
+   }
+},
+
+/* #7, 32 byte key, 17 byte PTX */
+{
+   32,
+   { 0xff,0xfe,0xfd,0xfc,0xfb,0xfa,0xf9,0xf8,0xf7,0xf6,0xf5,0xf4,0xf3,0xf2,0xf1,0xf0 },
+   { 0xbf,0xbe,0xbd,0xbc,0xbb,0xba,0xb9,0xb8,0xb7,0xb6,0xb5,0xb4,0xb3,0xb2,0xb1,0xb0 },
+   CONST64(0x123456789a),
+   17,
+   { 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x10 },
+   { 0x6c,0x16,0x25,0xdb,0x46,0x71,0x52,0x2d,0x3d,0x75,0x99,0x60,0x1d,0xe7,0xca,0x09,0xed },
+},
+
+/* #15, 32 byte key, 25 byte PTX */
+{
+   32,
+   { 0xff,0xfe,0xfd,0xfc,0xfb,0xfa,0xf9,0xf8,0xf7,0xf6,0xf5,0xf4,0xf3,0xf2,0xf1,0xf0 },
+   { 0xbf,0xbe,0xbd,0xbc,0xbb,0xba,0xb9,0xb8,0xb7,0xb6,0xb5,0xb4,0xb3,0xb2,0xb1,0xb0 },
+   CONST64(0x123456789a),
+   25,
+   { 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 },
+   { 0x8f,0x4d,0xcb,0xad,0x55,0x55,0x8d,0x7b,0x4e,0x01,0xd9,0x37,0x9c,0xd4,0xea,0x22,0xed,0xbf,0x9d,0xac,0xe4,0x5d,0x6f,0x6a,0x73 },
+},
+
+/* #21, 32 byte key, 31 byte PTX */
+{
+   32,
+   { 0xff,0xfe,0xfd,0xfc,0xfb,0xfa,0xf9,0xf8,0xf7,0xf6,0xf5,0xf4,0xf3,0xf2,0xf1,0xf0 },
+   { 0xbf,0xbe,0xbd,0xbc,0xbb,0xba,0xb9,0xb8,0xb7,0xb6,0xb5,0xb4,0xb3,0xb2,0xb1,0xb0 },
+   CONST64(0x123456789a),
+   31,
+   { 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 },
+   { 0xd0,0x5b,0xc0,0x90,0xa8,0xe0,0x4f,0x1b,0x3d,0x3e,0xcd,0xd5,0xba,0xec,0x0f,0xd4,0xed,0xbf,0x9d,0xac,0xe4,0x5d,0x6f,0x6a,0x73,0x06,0xe6,0x4b,0xe5,0xdd,0x82 },
+},
+
+};
+   unsigned char OUT[512], Torg[16], T[16];
+   ulong64 seq;
+   symmetric_xts xts;
+   int i, j, k, err, idx;
+   unsigned long len;
+
+   /* AES can be under rijndael or aes... try to find it */
+   if ((idx = find_cipher("aes")) == -1) {
+      if ((idx = find_cipher("rijndael")) == -1) {
+         return CRYPT_NOP;
+      }
+   }
+   for (k = 0; k < 4; ++k) {
+      cipher_descriptor[idx].accel_xts_encrypt = NULL;
+      cipher_descriptor[idx].accel_xts_decrypt = NULL;
+      if (k & 0x1) {
+         cipher_descriptor[idx].accel_xts_encrypt = _xts_test_accel_xts_encrypt;
+      }
+      if (k & 0x2) {
+         cipher_descriptor[idx].accel_xts_decrypt = _xts_test_accel_xts_decrypt;
+      }
+      for (j = 0; j < 2; j++) {
+         for (i = 0; i < (int)(sizeof(tests) / sizeof(tests[0])); i++) {
+            /* skip the cases where
+             * the length is smaller than 2*blocklen
+             * or the length is not a multiple of 32
+             */
+            if ((j == 1) && ((tests[i].PTLEN < 32) || (tests[i].PTLEN % 32))) {
+               continue;
+            }
+            if ((k > 0) && (j == 1)) {
+               continue;
+            }
+            len = tests[i].PTLEN / 2;
+
+            err = xts_start(idx, tests[i].key1, tests[i].key2, tests[i].keylen / 2, 0, &xts);
+            if (err != CRYPT_OK) {
+               return err;
+            }
+
+            seq = tests[i].seqnum;
+            STORE64L(seq, Torg);
+            XMEMSET(Torg + 8, 0, 8);
+
+            XMEMCPY(T, Torg, sizeof(T));
+            if (j == 0) {
+               err = xts_encrypt(tests[i].PTX, tests[i].PTLEN, OUT, T, &xts);
+               if (err != CRYPT_OK) {
+                  xts_done(&xts);
+                  return err;
+               }
+            } else {
+               err = xts_encrypt(tests[i].PTX, len, OUT, T, &xts);
+               if (err != CRYPT_OK) {
+                  xts_done(&xts);
+                  return err;
+               }
+               err = xts_encrypt(&tests[i].PTX[len], len, &OUT[len], T, &xts);
+               if (err != CRYPT_OK) {
+                  xts_done(&xts);
+                  return err;
+               }
+            }
+
+            if (compare_testvector(OUT, tests[i].PTLEN, tests[i].CTX, tests[i].PTLEN, "XTS encrypt", i)) {
+               xts_done(&xts);
+               return CRYPT_FAIL_TESTVECTOR;
+            }
+
+            XMEMCPY(T, Torg, sizeof(T));
+            if (j == 0) {
+               err = xts_decrypt(tests[i].CTX, tests[i].PTLEN, OUT, T, &xts);
+               if (err != CRYPT_OK) {
+                  xts_done(&xts);
+                  return err;
+               }
+            } else {
+               err = xts_decrypt(tests[i].CTX, len, OUT, T, &xts);
+               if (err != CRYPT_OK) {
+                  xts_done(&xts);
+                  return err;
+               }
+               err = xts_decrypt(&tests[i].CTX[len], len, &OUT[len], T, &xts);
+               if (err != CRYPT_OK) {
+                  xts_done(&xts);
+                  return err;
+               }
+            }
+
+            if (compare_testvector(OUT, tests[i].PTLEN, tests[i].PTX, tests[i].PTLEN, "XTS decrypt", i)) {
+               xts_done(&xts);
+               return CRYPT_FAIL_TESTVECTOR;
+            }
+            xts_done(&xts);
+         }
+      }
+   }
+   return CRYPT_OK;
+#endif
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/pk/asn1/der/bit/der_decode_bit_string.c b/libtomcrypt/src/pk/asn1/der/bit/der_decode_bit_string.c
new file mode 100644 (file)
index 0000000..5203fcf
--- /dev/null
@@ -0,0 +1,100 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file der_decode_bit_string.c
+  ASN.1 DER, encode a BIT STRING, Tom St Denis
+*/
+
+
+#ifdef LTC_DER
+
+/**
+  Store a BIT STRING
+  @param in      The DER encoded BIT STRING
+  @param inlen   The size of the DER BIT STRING
+  @param out     [out] The array of bits stored (one per char)
+  @param outlen  [in/out] The number of bits stored
+  @return CRYPT_OK if successful
+*/
+int der_decode_bit_string(const unsigned char *in,  unsigned long inlen,
+                                unsigned char *out, unsigned long *outlen)
+{
+   unsigned long dlen, blen, x, y;
+
+   LTC_ARGCHK(in     != NULL);
+   LTC_ARGCHK(out    != NULL);
+   LTC_ARGCHK(outlen != NULL);
+
+   /* packet must be at least 4 bytes */
+   if (inlen < 4) {
+       return CRYPT_INVALID_ARG;
+   }
+
+   /* check for 0x03 */
+   if ((in[0]&0x1F) != 0x03) {
+      return CRYPT_INVALID_PACKET;
+   }
+
+   /* offset in the data */
+   x = 1;
+
+   /* get the length of the data */
+   if (in[x] & 0x80) {
+      /* long format get number of length bytes */
+      y = in[x++] & 0x7F;
+
+      /* invalid if 0 or > 2 */
+      if (y == 0 || y > 2) {
+         return CRYPT_INVALID_PACKET;
+      }
+
+      /* read the data len */
+      dlen = 0;
+      while (y--) {
+         dlen = (dlen << 8) | (unsigned long)in[x++];
+      }
+   } else {
+      /* short format */
+      dlen = in[x++] & 0x7F;
+   }
+
+   /* is the data len too long or too short? */
+   if ((dlen == 0) || (dlen + x > inlen)) {
+       return CRYPT_INVALID_PACKET;
+   }
+
+   /* get padding count */
+   blen = ((dlen - 1) << 3) - (in[x++] & 7);
+
+   /* too many bits? */
+   if (blen > *outlen) {
+      *outlen = blen;
+      return CRYPT_BUFFER_OVERFLOW;
+   }
+
+   /* decode/store the bits */
+   for (y = 0; y < blen; y++) {
+       out[y] = (in[x] & (1 << (7 - (y & 7)))) ? 1 : 0;
+       if ((y & 7) == 7) {
+          ++x;
+       }
+   }
+
+   /* we done */
+   *outlen = blen;
+   return CRYPT_OK;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/pk/asn1/der/bit/der_decode_raw_bit_string.c b/libtomcrypt/src/pk/asn1/der/bit/der_decode_raw_bit_string.c
new file mode 100644 (file)
index 0000000..223899b
--- /dev/null
@@ -0,0 +1,107 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file der_decode_bit_string.c
+  ASN.1 DER, encode a BIT STRING, Tom St Denis
+*/
+
+
+#ifdef LTC_DER
+
+#define SETBIT(v, n)    (v=((unsigned char)(v) | (1U << (unsigned char)(n))))
+#define CLRBIT(v, n)    (v=((unsigned char)(v) & ~(1U << (unsigned char)(n))))
+
+/**
+  Store a BIT STRING
+  @param in      The DER encoded BIT STRING
+  @param inlen   The size of the DER BIT STRING
+  @param out     [out] The array of bits stored (8 per char)
+  @param outlen  [in/out] The number of bits stored
+  @return CRYPT_OK if successful
+*/
+int der_decode_raw_bit_string(const unsigned char *in,  unsigned long inlen,
+                                unsigned char *out, unsigned long *outlen)
+{
+   unsigned long dlen, blen, x, y;
+
+   LTC_ARGCHK(in     != NULL);
+   LTC_ARGCHK(out    != NULL);
+   LTC_ARGCHK(outlen != NULL);
+
+   /* packet must be at least 4 bytes */
+   if (inlen < 4) {
+       return CRYPT_INVALID_ARG;
+   }
+
+   /* check for 0x03 */
+   if ((in[0]&0x1F) != 0x03) {
+      return CRYPT_INVALID_PACKET;
+   }
+
+   /* offset in the data */
+   x = 1;
+
+   /* get the length of the data */
+   if (in[x] & 0x80) {
+      /* long format get number of length bytes */
+      y = in[x++] & 0x7F;
+
+      /* invalid if 0 or > 2 */
+      if (y == 0 || y > 2) {
+         return CRYPT_INVALID_PACKET;
+      }
+
+      /* read the data len */
+      dlen = 0;
+      while (y--) {
+         dlen = (dlen << 8) | (unsigned long)in[x++];
+      }
+   } else {
+      /* short format */
+      dlen = in[x++] & 0x7F;
+   }
+
+   /* is the data len too long or too short? */
+   if ((dlen == 0) || (dlen + x > inlen)) {
+       return CRYPT_INVALID_PACKET;
+   }
+
+   /* get padding count */
+   blen = ((dlen - 1) << 3) - (in[x++] & 7);
+
+   /* too many bits? */
+   if (blen > *outlen) {
+      *outlen = blen;
+      return CRYPT_BUFFER_OVERFLOW;
+   }
+
+   /* decode/store the bits */
+   for (y = 0; y < blen; y++) {
+      if (in[x] & (1 << (7 - (y & 7)))) {
+         SETBIT(out[y/8], 7-(y%8));
+      } else {
+         CLRBIT(out[y/8], 7-(y%8));
+      }
+      if ((y & 7) == 7) {
+         ++x;
+      }
+   }
+
+   /* we done */
+   *outlen = blen;
+   return CRYPT_OK;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/pk/asn1/der/bit/der_encode_bit_string.c b/libtomcrypt/src/pk/asn1/der/bit/der_encode_bit_string.c
new file mode 100644 (file)
index 0000000..c552184
--- /dev/null
@@ -0,0 +1,87 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file der_encode_bit_string.c
+  ASN.1 DER, encode a BIT STRING, Tom St Denis
+*/
+
+
+#ifdef LTC_DER
+
+/**
+  Store a BIT STRING
+  @param in       The array of bits to store (one per char)
+  @param inlen    The number of bits tostore
+  @param out      [out] The destination for the DER encoded BIT STRING
+  @param outlen   [in/out] The max size and resulting size of the DER BIT STRING
+  @return CRYPT_OK if successful
+*/
+int der_encode_bit_string(const unsigned char *in, unsigned long inlen,
+                                unsigned char *out, unsigned long *outlen)
+{
+   unsigned long len, x, y;
+   unsigned char buf;
+   int           err;
+
+   LTC_ARGCHK(in     != NULL);
+   LTC_ARGCHK(out    != NULL);
+   LTC_ARGCHK(outlen != NULL);
+
+   /* avoid overflows */
+   if ((err = der_length_bit_string(inlen, &len)) != CRYPT_OK) {
+      return err;
+   }
+
+   if (len > *outlen) {
+      *outlen = len;
+      return CRYPT_BUFFER_OVERFLOW;
+   }
+
+   /* store header (include bit padding count in length) */
+   x = 0;
+   y = (inlen >> 3) + ((inlen&7) ? 1 : 0) + 1;
+
+   out[x++] = 0x03;
+   if (y < 128) {
+      out[x++] = (unsigned char)y;
+   } else if (y < 256) {
+      out[x++] = 0x81;
+      out[x++] = (unsigned char)y;
+   } else if (y < 65536) {
+      out[x++] = 0x82;
+      out[x++] = (unsigned char)((y>>8)&255);
+      out[x++] = (unsigned char)(y&255);
+   }
+
+   /* store number of zero padding bits */
+   out[x++] = (unsigned char)((8 - inlen) & 7);
+
+   /* store the bits in big endian format */
+   for (y = buf = 0; y < inlen; y++) {
+       buf |= (in[y] ? 1 : 0) << (7 - (y & 7));
+       if ((y & 7) == 7) {
+          out[x++] = buf;
+          buf      = 0;
+       }
+   }
+   /* store last byte */
+   if (inlen & 7) {
+      out[x++] = buf;
+   }
+   *outlen = x;
+   return CRYPT_OK;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/pk/asn1/der/bit/der_encode_raw_bit_string.c b/libtomcrypt/src/pk/asn1/der/bit/der_encode_raw_bit_string.c
new file mode 100644 (file)
index 0000000..298c4e3
--- /dev/null
@@ -0,0 +1,90 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file der_encode_bit_string.c
+  ASN.1 DER, encode a BIT STRING, Tom St Denis
+*/
+
+
+#ifdef LTC_DER
+
+#define getbit(n, k) (((n) & ( 1 << (k) )) >> (k))
+
+/**
+  Store a BIT STRING
+  @param in       The array of bits to store (8 per char)
+  @param inlen    The number of bits to store
+  @param out      [out] The destination for the DER encoded BIT STRING
+  @param outlen   [in/out] The max size and resulting size of the DER BIT STRING
+  @return CRYPT_OK if successful
+*/
+int der_encode_raw_bit_string(const unsigned char *in, unsigned long inlen,
+                                unsigned char *out, unsigned long *outlen)
+{
+   unsigned long len, x, y;
+   unsigned char buf;
+   int           err;
+
+   LTC_ARGCHK(in     != NULL);
+   LTC_ARGCHK(out    != NULL);
+   LTC_ARGCHK(outlen != NULL);
+
+   /* avoid overflows */
+   if ((err = der_length_bit_string(inlen, &len)) != CRYPT_OK) {
+      return err;
+   }
+
+   if (len > *outlen) {
+      *outlen = len;
+      return CRYPT_BUFFER_OVERFLOW;
+   }
+
+   /* store header (include bit padding count in length) */
+   x = 0;
+   y = (inlen >> 3) + ((inlen&7) ? 1 : 0) + 1;
+
+   out[x++] = 0x03;
+   if (y < 128) {
+      out[x++] = (unsigned char)y;
+   } else if (y < 256) {
+      out[x++] = 0x81;
+      out[x++] = (unsigned char)y;
+   } else if (y < 65536) {
+      out[x++] = 0x82;
+      out[x++] = (unsigned char)((y>>8)&255);
+      out[x++] = (unsigned char)(y&255);
+   }
+
+   /* store number of zero padding bits */
+   out[x++] = (unsigned char)((8 - inlen) & 7);
+
+   /* store the bits in big endian format */
+   for (y = buf = 0; y < inlen; y++) {
+      buf |= (getbit(in[y/8],7-y%8)?1:0) << (7 - (y & 7));
+      if ((y & 7) == 7) {
+         out[x++] = buf;
+         buf      = 0;
+      }
+   }
+   /* store last byte */
+   if (inlen & 7) {
+      out[x++] = buf;
+   }
+
+   *outlen = x;
+   return CRYPT_OK;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/pk/asn1/der/bit/der_length_bit_string.c b/libtomcrypt/src/pk/asn1/der/bit/der_length_bit_string.c
new file mode 100644 (file)
index 0000000..b9c99fb
--- /dev/null
@@ -0,0 +1,52 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file der_length_bit_string.c
+  ASN.1 DER, get length of BIT STRING, Tom St Denis
+*/
+
+#ifdef LTC_DER
+/**
+  Gets length of DER encoding of BIT STRING
+  @param nbits  The number of bits in the string to encode
+  @param outlen [out] The length of the DER encoding for the given string
+  @return CRYPT_OK if successful
+*/
+int der_length_bit_string(unsigned long nbits, unsigned long *outlen)
+{
+   unsigned long nbytes;
+   LTC_ARGCHK(outlen != NULL);
+
+   /* get the number of the bytes */
+   nbytes = (nbits >> 3) + ((nbits & 7) ? 1 : 0) + 1;
+
+   if (nbytes < 128) {
+      /* 03 LL PP DD DD DD ... */
+      *outlen = 2 + nbytes;
+   } else if (nbytes < 256) {
+      /* 03 81 LL PP DD DD DD ... */
+      *outlen = 3 + nbytes;
+   } else if (nbytes < 65536) {
+      /* 03 82 LL LL PP DD DD DD ... */
+      *outlen = 4 + nbytes;
+   } else {
+      return CRYPT_INVALID_ARG;
+   }
+
+   return CRYPT_OK;
+}
+
+#endif
+
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/pk/asn1/der/boolean/der_decode_boolean.c b/libtomcrypt/src/pk/asn1/der/boolean/der_decode_boolean.c
new file mode 100644 (file)
index 0000000..da60ca9
--- /dev/null
@@ -0,0 +1,45 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file der_decode_boolean.c
+  ASN.1 DER, decode a BOOLEAN, Tom St Denis
+*/
+
+
+#ifdef LTC_DER
+
+/**
+  Read a BOOLEAN
+  @param in      The destination for the DER encoded BOOLEAN
+  @param inlen   The size of the DER BOOLEAN
+  @param out     [out]  The boolean to decode
+  @return CRYPT_OK if successful
+*/
+int der_decode_boolean(const unsigned char *in, unsigned long inlen,
+                                       int *out)
+{
+   LTC_ARGCHK(in  != NULL);
+   LTC_ARGCHK(out != NULL);
+
+   if (inlen < 3 || in[0] != 0x01 || in[1] != 0x01 || (in[2] != 0x00 && in[2] != 0xFF)) {
+      return CRYPT_INVALID_ARG;
+   }
+
+   *out = (in[2]==0xFF) ? 1 : 0;
+
+   return CRYPT_OK;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/pk/asn1/der/boolean/der_encode_boolean.c b/libtomcrypt/src/pk/asn1/der/boolean/der_encode_boolean.c
new file mode 100644 (file)
index 0000000..c5cacdd
--- /dev/null
@@ -0,0 +1,49 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file der_encode_boolean.c
+  ASN.1 DER, encode a BOOLEAN, Tom St Denis
+*/
+
+
+#ifdef LTC_DER
+
+/**
+  Store a BOOLEAN
+  @param in       The boolean to encode
+  @param out      [out] The destination for the DER encoded BOOLEAN
+  @param outlen   [in/out] The max size and resulting size of the DER BOOLEAN
+  @return CRYPT_OK if successful
+*/
+int der_encode_boolean(int in,
+                       unsigned char *out, unsigned long *outlen)
+{
+   LTC_ARGCHK(outlen != NULL);
+   LTC_ARGCHK(out    != NULL);
+
+   if (*outlen < 3) {
+       *outlen = 3;
+       return CRYPT_BUFFER_OVERFLOW;
+   }
+
+   *outlen = 3;
+   out[0] = 0x01;
+   out[1] = 0x01;
+   out[2] = in ? 0xFF : 0x00;
+
+   return CRYPT_OK;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/pk/asn1/der/boolean/der_length_boolean.c b/libtomcrypt/src/pk/asn1/der/boolean/der_length_boolean.c
new file mode 100644 (file)
index 0000000..a1a3a7b
--- /dev/null
@@ -0,0 +1,33 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file der_length_boolean.c
+  ASN.1 DER, get length of a BOOLEAN, Tom St Denis
+*/
+
+#ifdef LTC_DER
+/**
+  Gets length of DER encoding of a BOOLEAN
+  @param outlen [out] The length of the DER encoding
+  @return CRYPT_OK if successful
+*/
+int der_length_boolean(unsigned long *outlen)
+{
+   LTC_ARGCHK(outlen != NULL);
+   *outlen = 3;
+   return CRYPT_OK;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/pk/asn1/der/choice/der_decode_choice.c b/libtomcrypt/src/pk/asn1/der/choice/der_decode_choice.c
new file mode 100644 (file)
index 0000000..0bfd3bb
--- /dev/null
@@ -0,0 +1,223 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file der_decode_choice.c
+  ASN.1 DER, decode a CHOICE, Tom St Denis
+*/
+
+#ifdef LTC_DER
+
+/**
+   Decode a CHOICE
+   @param in       The DER encoded input
+   @param inlen    [in/out] The size of the input and resulting size of read type
+   @param list     The list of items to decode
+   @param outlen   The number of items in the list
+   @return CRYPT_OK on success
+*/
+int der_decode_choice(const unsigned char *in,   unsigned long *inlen,
+                            ltc_asn1_list *list, unsigned long  outlen)
+{
+   unsigned long size, x, z;
+   void          *data;
+
+   LTC_ARGCHK(in    != NULL);
+   LTC_ARGCHK(inlen != NULL);
+   LTC_ARGCHK(list  != NULL);
+
+   /* get blk size */
+   if (*inlen < 2) {
+      return CRYPT_INVALID_PACKET;
+   }
+
+   /* set all of the "used" flags to zero */
+   for (x = 0; x < outlen; x++) {
+       list[x].used = 0;
+   }
+
+   /* now scan until we have a winner */
+   for (x = 0; x < outlen; x++) {
+       size = list[x].size;
+       data = list[x].data;
+
+       switch (list[x].type) {
+           case LTC_ASN1_BOOLEAN:
+               if (der_decode_boolean(in, *inlen, data) == CRYPT_OK) {
+                  if (der_length_boolean(&z) == CRYPT_OK) {
+                      list[x].used = 1;
+                      *inlen       = z;
+                      return CRYPT_OK;
+                  }
+               }
+               break;
+
+           case LTC_ASN1_INTEGER:
+               if (der_decode_integer(in, *inlen, data) == CRYPT_OK) {
+                  if (der_length_integer(data, &z) == CRYPT_OK) {
+                      list[x].used = 1;
+                      *inlen       = z;
+                      return CRYPT_OK;
+                  }
+               }
+               break;
+
+           case LTC_ASN1_SHORT_INTEGER:
+               if (der_decode_short_integer(in, *inlen, data) == CRYPT_OK) {
+                  if (der_length_short_integer(size, &z) == CRYPT_OK) {
+                      list[x].used = 1;
+                      *inlen       = z;
+                      return CRYPT_OK;
+                  }
+               }
+               break;
+
+           case LTC_ASN1_BIT_STRING:
+               if (der_decode_bit_string(in, *inlen, data, &size) == CRYPT_OK) {
+                  if (der_length_bit_string(size, &z) == CRYPT_OK) {
+                     list[x].used = 1;
+                     list[x].size = size;
+                     *inlen       = z;
+                     return CRYPT_OK;
+                  }
+               }
+               break;
+
+           case LTC_ASN1_RAW_BIT_STRING:
+               if (der_decode_raw_bit_string(in, *inlen, data, &size) == CRYPT_OK) {
+                  if (der_length_bit_string(size, &z) == CRYPT_OK) {
+                     list[x].used = 1;
+                     list[x].size = size;
+                     *inlen       = z;
+                     return CRYPT_OK;
+                  }
+               }
+               break;
+
+           case LTC_ASN1_OCTET_STRING:
+               if (der_decode_octet_string(in, *inlen, data, &size) == CRYPT_OK) {
+                  if (der_length_octet_string(size, &z) == CRYPT_OK) {
+                     list[x].used = 1;
+                     list[x].size = size;
+                     *inlen       = z;
+                     return CRYPT_OK;
+                  }
+               }
+               break;
+
+           case LTC_ASN1_NULL:
+               if (*inlen == 2 && in[x] == 0x05 && in[x+1] == 0x00) {
+                  *inlen = 2;
+                  list[x].used   = 1;
+                  return CRYPT_OK;
+               }
+               break;
+
+           case LTC_ASN1_OBJECT_IDENTIFIER:
+               if (der_decode_object_identifier(in, *inlen, data, &size) == CRYPT_OK) {
+                  if (der_length_object_identifier(data, size, &z) == CRYPT_OK) {
+                     list[x].used = 1;
+                     list[x].size = size;
+                     *inlen       = z;
+                     return CRYPT_OK;
+                  }
+               }
+               break;
+
+           case LTC_ASN1_TELETEX_STRING:
+               if (der_decode_teletex_string(in, *inlen, data, &size) == CRYPT_OK) {
+                  if (der_length_teletex_string(data, size, &z) == CRYPT_OK) {
+                     list[x].used = 1;
+                     list[x].size = size;
+                     *inlen       = z;
+                     return CRYPT_OK;
+                  }
+               }
+               break;
+
+           case LTC_ASN1_IA5_STRING:
+               if (der_decode_ia5_string(in, *inlen, data, &size) == CRYPT_OK) {
+                  if (der_length_ia5_string(data, size, &z) == CRYPT_OK) {
+                     list[x].used = 1;
+                     list[x].size = size;
+                     *inlen       = z;
+                     return CRYPT_OK;
+                  }
+               }
+               break;
+
+           case LTC_ASN1_PRINTABLE_STRING:
+               if (der_decode_printable_string(in, *inlen, data, &size) == CRYPT_OK) {
+                  if (der_length_printable_string(data, size, &z) == CRYPT_OK) {
+                     list[x].used = 1;
+                     list[x].size = size;
+                     *inlen       = z;
+                     return CRYPT_OK;
+                  }
+               }
+               break;
+
+           case LTC_ASN1_UTF8_STRING:
+               if (der_decode_utf8_string(in, *inlen, data, &size) == CRYPT_OK) {
+                  if (der_length_utf8_string(data, size, &z) == CRYPT_OK) {
+                     list[x].used = 1;
+                     list[x].size = size;
+                     *inlen       = z;
+                     return CRYPT_OK;
+                  }
+               }
+               break;
+
+           case LTC_ASN1_UTCTIME:
+               z = *inlen;
+               if (der_decode_utctime(in, &z, data) == CRYPT_OK) {
+                  list[x].used = 1;
+                  *inlen       = z;
+                  return CRYPT_OK;
+               }
+               break;
+
+           case LTC_ASN1_GENERALIZEDTIME:
+               z = *inlen;
+               if (der_decode_generalizedtime(in, &z, data) == CRYPT_OK) {
+                  list[x].used = 1;
+                  *inlen       = z;
+                  return CRYPT_OK;
+               }
+               break;
+
+           case LTC_ASN1_SET:
+           case LTC_ASN1_SETOF:
+           case LTC_ASN1_SEQUENCE:
+               if (der_decode_sequence(in, *inlen, data, size) == CRYPT_OK) {
+                  if (der_length_sequence(data, size, &z) == CRYPT_OK) {
+                     list[x].used = 1;
+                     *inlen       = z;
+                     return CRYPT_OK;
+                  }
+               }
+               break;
+
+           case LTC_ASN1_CHOICE:
+           case LTC_ASN1_CONSTRUCTED:
+           case LTC_ASN1_CONTEXT_SPECIFIC:
+           case LTC_ASN1_EOL:
+               return CRYPT_INVALID_ARG;
+       }
+   }
+
+   return CRYPT_INVALID_PACKET;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/pk/asn1/der/generalizedtime/der_decode_generalizedtime.c b/libtomcrypt/src/pk/asn1/der/generalizedtime/der_decode_generalizedtime.c
new file mode 100644 (file)
index 0000000..016a4c2
--- /dev/null
@@ -0,0 +1,144 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file der_decode_generalizedtime.c
+  ASN.1 DER, decode a GeneralizedTime, Steffen Jaeckel
+  Based on der_decode_utctime.c
+*/
+
+#ifdef LTC_DER
+
+static int _char_to_int(unsigned char x)
+{
+   switch (x)  {
+      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;
+      default:  return 100;
+   }
+}
+
+#define DECODE_V(y, max) do {\
+   y  = _char_to_int(buf[x])*10 + _char_to_int(buf[x+1]); \
+   if (y >= max) return CRYPT_INVALID_PACKET;           \
+   x += 2; \
+} while(0)
+
+#define DECODE_V4(y, max) do {\
+   y  = _char_to_int(buf[x])*1000 + _char_to_int(buf[x+1])*100 + _char_to_int(buf[x+2])*10 + _char_to_int(buf[x+3]); \
+   if (y >= max) return CRYPT_INVALID_PACKET; \
+   x += 4; \
+} while(0)
+
+/**
+  Decodes a Generalized time structure in DER format (reads all 6 valid encoding formats)
+  @param in     Input buffer
+  @param inlen  Length of input buffer in octets
+  @param out    [out] Destination of Generalized time structure
+  @return CRYPT_OK   if successful
+*/
+int der_decode_generalizedtime(const unsigned char *in, unsigned long *inlen,
+                               ltc_generalizedtime *out)
+{
+   unsigned char buf[32];
+   unsigned long x;
+   int           y;
+
+   LTC_ARGCHK(in    != NULL);
+   LTC_ARGCHK(inlen != NULL);
+   LTC_ARGCHK(out   != NULL);
+
+   /* check header */
+   if (*inlen < 2UL || (in[1] >= sizeof(buf)) || ((in[1] + 2UL) > *inlen)) {
+      return CRYPT_INVALID_PACKET;
+   }
+
+   /* decode the string */
+   for (x = 0; x < in[1]; x++) {
+       y = der_ia5_value_decode(in[x+2]);
+       if (y == -1) {
+          return CRYPT_INVALID_PACKET;
+       }
+       if (!((y >= '0' && y <= '9')
+            || y == 'Z' || y == '.'
+            || y == '+' || y == '-')) {
+          return CRYPT_INVALID_PACKET;
+       }
+       buf[x] = y;
+   }
+   *inlen = 2 + x;
+
+   if (x < 15) {
+      return CRYPT_INVALID_PACKET;
+   }
+
+   /* possible encodings are
+YYYYMMDDhhmmssZ
+YYYYMMDDhhmmss+hh'mm'
+YYYYMMDDhhmmss-hh'mm'
+YYYYMMDDhhmmss.fsZ
+YYYYMMDDhhmmss.fs+hh'mm'
+YYYYMMDDhhmmss.fs-hh'mm'
+
+    So let's do a trivial decode upto [including] ss
+   */
+
+    x = 0;
+    DECODE_V4(out->YYYY, 10000);
+    DECODE_V(out->MM, 13);
+    DECODE_V(out->DD, 32);
+    DECODE_V(out->hh, 24);
+    DECODE_V(out->mm, 60);
+    DECODE_V(out->ss, 60);
+
+    /* clear fractional seconds info */
+    out->fs = 0;
+
+    /* now is it Z or . */
+    if (buf[x] == 'Z') {
+       return CRYPT_OK;
+    } else if (buf[x] == '.') {
+       x++;
+       while (buf[x] >= '0' && buf[x] <= '9') {
+          unsigned fs = out->fs;
+          if (x >= sizeof(buf)) return CRYPT_INVALID_PACKET;
+          out->fs *= 10;
+          out->fs += _char_to_int(buf[x]);
+          if (fs > out->fs) return CRYPT_OVERFLOW;
+          x++;
+       }
+    }
+
+    /* now is it Z, +, - */
+    if (buf[x] == 'Z') {
+       return CRYPT_OK;
+    } else if (buf[x] == '+' || buf[x] == '-') {
+       out->off_dir = (buf[x++] == '+') ? 0 : 1;
+       DECODE_V(out->off_hh, 24);
+       DECODE_V(out->off_mm, 60);
+       return CRYPT_OK;
+    } else {
+       return CRYPT_INVALID_PACKET;
+    }
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/pk/asn1/der/generalizedtime/der_encode_generalizedtime.c b/libtomcrypt/src/pk/asn1/der/generalizedtime/der_encode_generalizedtime.c
new file mode 100644 (file)
index 0000000..ddc472a
--- /dev/null
@@ -0,0 +1,108 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file der_encode_utctime.c
+  ASN.1 DER, encode a GeneralizedTime, Steffen Jaeckel
+  Based on der_encode_utctime.c
+*/
+
+#ifdef LTC_DER
+
+static const char * const baseten = "0123456789";
+
+#define STORE_V(y) do {\
+    out[x++] = der_ia5_char_encode(baseten[(y/10) % 10]); \
+    out[x++] = der_ia5_char_encode(baseten[y % 10]); \
+} while(0)
+
+#define STORE_V4(y) do {\
+    out[x++] = der_ia5_char_encode(baseten[(y/1000) % 10]); \
+    out[x++] = der_ia5_char_encode(baseten[(y/100) % 10]); \
+    out[x++] = der_ia5_char_encode(baseten[(y/10) % 10]); \
+    out[x++] = der_ia5_char_encode(baseten[y % 10]); \
+} while(0)
+
+/**
+  Encodes a Generalized time structure in DER format
+  @param gtime        The GeneralizedTime structure to encode
+  @param out          The destination of the DER encoding of the GeneralizedTime structure
+  @param outlen       [in/out] The length of the DER encoding
+  @return CRYPT_OK if successful
+*/
+int der_encode_generalizedtime(ltc_generalizedtime *gtime,
+                               unsigned char       *out,   unsigned long *outlen)
+{
+    unsigned long x, tmplen;
+    int           err;
+
+    LTC_ARGCHK(gtime != NULL);
+    LTC_ARGCHK(out     != NULL);
+    LTC_ARGCHK(outlen  != NULL);
+
+    if ((err = der_length_generalizedtime(gtime, &tmplen)) != CRYPT_OK) {
+       return err;
+    }
+    if (tmplen > *outlen) {
+        *outlen = tmplen;
+        return CRYPT_BUFFER_OVERFLOW;
+    }
+
+    /* store header */
+    out[0] = 0x18;
+
+    /* store values */
+    x = 2;
+    STORE_V4(gtime->YYYY);
+    STORE_V(gtime->MM);
+    STORE_V(gtime->DD);
+    STORE_V(gtime->hh);
+    STORE_V(gtime->mm);
+    STORE_V(gtime->ss);
+
+    if (gtime->fs) {
+       unsigned long divisor;
+       unsigned fs = gtime->fs;
+       unsigned len = 0;
+       out[x++] = der_ia5_char_encode('.');
+       divisor = 1;
+       do {
+          fs /= 10;
+          divisor *= 10;
+          len++;
+       } while(fs != 0);
+       while (len-- > 1) {
+          divisor /= 10;
+          out[x++] = der_ia5_char_encode(baseten[(gtime->fs/divisor) % 10]);
+       }
+       out[x++] = der_ia5_char_encode(baseten[gtime->fs % 10]);
+    }
+
+    if (gtime->off_mm || gtime->off_hh) {
+       out[x++] = der_ia5_char_encode(gtime->off_dir ? '-' : '+');
+       STORE_V(gtime->off_hh);
+       STORE_V(gtime->off_mm);
+    } else {
+       out[x++] = der_ia5_char_encode('Z');
+    }
+
+    /* store length */
+    out[1] = (unsigned char)(x - 2);
+
+    /* all good let's return */
+    *outlen = x;
+    return CRYPT_OK;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/pk/asn1/der/generalizedtime/der_length_generalizedtime.c b/libtomcrypt/src/pk/asn1/der/generalizedtime/der_length_generalizedtime.c
new file mode 100644 (file)
index 0000000..def6270
--- /dev/null
@@ -0,0 +1,58 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file der_length_utctime.c
+  ASN.1 DER, get length of GeneralizedTime, Steffen Jaeckel
+  Based on der_length_utctime.c
+*/
+
+#ifdef LTC_DER
+
+/**
+  Gets length of DER encoding of GeneralizedTime
+  @param gtime        The GeneralizedTime structure to get the size of
+  @param outlen [out] The length of the DER encoding
+  @return CRYPT_OK if successful
+*/
+int der_length_generalizedtime(ltc_generalizedtime *gtime, unsigned long *outlen)
+{
+   LTC_ARGCHK(outlen  != NULL);
+   LTC_ARGCHK(gtime != NULL);
+
+   if (gtime->fs == 0) {
+      /* we encode as YYYYMMDDhhmmssZ */
+      *outlen = 2 + 14 + 1;
+   } else {
+      unsigned long len = 2 + 14 + 1;
+      unsigned fs = gtime->fs;
+      do {
+         fs /= 10;
+         len++;
+      } while(fs != 0);
+      if (gtime->off_hh == 0 && gtime->off_mm == 0) {
+         /* we encode as YYYYMMDDhhmmss.fsZ */
+         len += 1;
+      }
+      else {
+         /* we encode as YYYYMMDDhhmmss.fs{+|-}hh'mm' */
+         len += 5;
+      }
+      *outlen = len;
+   }
+
+   return CRYPT_OK;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/pk/asn1/der/ia5/der_decode_ia5_string.c b/libtomcrypt/src/pk/asn1/der/ia5/der_decode_ia5_string.c
new file mode 100644 (file)
index 0000000..c347251
--- /dev/null
@@ -0,0 +1,94 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file der_decode_ia5_string.c
+  ASN.1 DER, encode a IA5 STRING, Tom St Denis
+*/
+
+
+#ifdef LTC_DER
+
+/**
+  Store a IA5 STRING
+  @param in      The DER encoded IA5 STRING
+  @param inlen   The size of the DER IA5 STRING
+  @param out     [out] The array of octets stored (one per char)
+  @param outlen  [in/out] The number of octets stored
+  @return CRYPT_OK if successful
+*/
+int der_decode_ia5_string(const unsigned char *in, unsigned long inlen,
+                                unsigned char *out, unsigned long *outlen)
+{
+   unsigned long x, y, len;
+   int           t;
+
+   LTC_ARGCHK(in     != NULL);
+   LTC_ARGCHK(out    != NULL);
+   LTC_ARGCHK(outlen != NULL);
+
+   /* must have header at least */
+   if (inlen < 2) {
+      return CRYPT_INVALID_PACKET;
+   }
+
+   /* check for 0x16 */
+   if ((in[0] & 0x1F) != 0x16) {
+      return CRYPT_INVALID_PACKET;
+   }
+   x = 1;
+
+   /* decode the length */
+   if (in[x] & 0x80) {
+      /* valid # of bytes in length are 1,2,3 */
+      y = in[x] & 0x7F;
+      if ((y == 0) || (y > 3) || ((x + y) > inlen)) {
+         return CRYPT_INVALID_PACKET;
+      }
+
+      /* read the length in */
+      len = 0;
+      ++x;
+      while (y--) {
+         len = (len << 8) | in[x++];
+      }
+   } else {
+      len = in[x++] & 0x7F;
+   }
+
+   /* is it too long? */
+   if (len > *outlen) {
+      *outlen = len;
+      return CRYPT_BUFFER_OVERFLOW;
+   }
+
+   if (len + x > inlen) {
+      return CRYPT_INVALID_PACKET;
+   }
+
+   /* read the data */
+   for (y = 0; y < len; y++) {
+       t = der_ia5_value_decode(in[x++]);
+       if (t == -1) {
+           return CRYPT_INVALID_ARG;
+       }
+       out[y] = t;
+   }
+
+   *outlen = y;
+
+   return CRYPT_OK;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/pk/asn1/der/ia5/der_encode_ia5_string.c b/libtomcrypt/src/pk/asn1/der/ia5/der_encode_ia5_string.c
new file mode 100644 (file)
index 0000000..18b926e
--- /dev/null
@@ -0,0 +1,83 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file der_encode_ia5_string.c
+  ASN.1 DER, encode a IA5 STRING, Tom St Denis
+*/
+
+#ifdef LTC_DER
+
+/**
+  Store an IA5 STRING
+  @param in       The array of IA5 to store (one per char)
+  @param inlen    The number of IA5 to store
+  @param out      [out] The destination for the DER encoded IA5 STRING
+  @param outlen   [in/out] The max size and resulting size of the DER IA5 STRING
+  @return CRYPT_OK if successful
+*/
+int der_encode_ia5_string(const unsigned char *in, unsigned long inlen,
+                                unsigned char *out, unsigned long *outlen)
+{
+   unsigned long x, y, len;
+   int           err;
+
+   LTC_ARGCHK(in     != NULL);
+   LTC_ARGCHK(out    != NULL);
+   LTC_ARGCHK(outlen != NULL);
+
+   /* get the size */
+   if ((err = der_length_ia5_string(in, inlen, &len)) != CRYPT_OK) {
+      return err;
+   }
+
+   /* too big? */
+   if (len > *outlen) {
+      *outlen = len;
+      return CRYPT_BUFFER_OVERFLOW;
+   }
+
+   /* encode the header+len */
+   x = 0;
+   out[x++] = 0x16;
+   if (inlen < 128) {
+      out[x++] = (unsigned char)inlen;
+   } else if (inlen < 256) {
+      out[x++] = 0x81;
+      out[x++] = (unsigned char)inlen;
+   } else if (inlen < 65536UL) {
+      out[x++] = 0x82;
+      out[x++] = (unsigned char)((inlen>>8)&255);
+      out[x++] = (unsigned char)(inlen&255);
+   } else if (inlen < 16777216UL) {
+      out[x++] = 0x83;
+      out[x++] = (unsigned char)((inlen>>16)&255);
+      out[x++] = (unsigned char)((inlen>>8)&255);
+      out[x++] = (unsigned char)(inlen&255);
+   } else {
+      return CRYPT_INVALID_ARG;
+   }
+
+   /* store octets */
+   for (y = 0; y < inlen; y++) {
+       out[x++] = der_ia5_char_encode(in[y]);
+   }
+
+   /* retun length */
+   *outlen = x;
+
+   return CRYPT_OK;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/pk/asn1/der/ia5/der_length_ia5_string.c b/libtomcrypt/src/pk/asn1/der/ia5/der_length_ia5_string.c
new file mode 100644 (file)
index 0000000..5f1a78d
--- /dev/null
@@ -0,0 +1,192 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file der_length_ia5_string.c
+  ASN.1 DER, get length of IA5 STRING, Tom St Denis
+*/
+
+#ifdef LTC_DER
+
+static const struct {
+   int code, value;
+} ia5_table[] = {
+{ '\0', 0 },
+{ '\a', 7 },
+{ '\b', 8 },
+{ '\t', 9 },
+{ '\n', 10 },
+{ '\f', 12 },
+{ '\r', 13 },
+{ ' ', 32 },
+{ '!', 33 },
+{ '"', 34 },
+{ '#', 35 },
+{ '$', 36 },
+{ '%', 37 },
+{ '&', 38 },
+{ '\'', 39 },
+{ '(', 40 },
+{ ')', 41 },
+{ '*', 42 },
+{ '+', 43 },
+{ ',', 44 },
+{ '-', 45 },
+{ '.', 46 },
+{ '/', 47 },
+{ '0', 48 },
+{ '1', 49 },
+{ '2', 50 },
+{ '3', 51 },
+{ '4', 52 },
+{ '5', 53 },
+{ '6', 54 },
+{ '7', 55 },
+{ '8', 56 },
+{ '9', 57 },
+{ ':', 58 },
+{ ';', 59 },
+{ '<', 60 },
+{ '=', 61 },
+{ '>', 62 },
+{ '?', 63 },
+{ '@', 64 },
+{ 'A', 65 },
+{ 'B', 66 },
+{ 'C', 67 },
+{ 'D', 68 },
+{ 'E', 69 },
+{ 'F', 70 },
+{ 'G', 71 },
+{ 'H', 72 },
+{ 'I', 73 },
+{ 'J', 74 },
+{ 'K', 75 },
+{ 'L', 76 },
+{ 'M', 77 },
+{ 'N', 78 },
+{ 'O', 79 },
+{ 'P', 80 },
+{ 'Q', 81 },
+{ 'R', 82 },
+{ 'S', 83 },
+{ 'T', 84 },
+{ 'U', 85 },
+{ 'V', 86 },
+{ 'W', 87 },
+{ 'X', 88 },
+{ 'Y', 89 },
+{ 'Z', 90 },
+{ '[', 91 },
+{ '\\', 92 },
+{ ']', 93 },
+{ '^', 94 },
+{ '_', 95 },
+{ '`', 96 },
+{ 'a', 97 },
+{ 'b', 98 },
+{ 'c', 99 },
+{ 'd', 100 },
+{ 'e', 101 },
+{ 'f', 102 },
+{ 'g', 103 },
+{ 'h', 104 },
+{ 'i', 105 },
+{ 'j', 106 },
+{ 'k', 107 },
+{ 'l', 108 },
+{ 'm', 109 },
+{ 'n', 110 },
+{ 'o', 111 },
+{ 'p', 112 },
+{ 'q', 113 },
+{ 'r', 114 },
+{ 's', 115 },
+{ 't', 116 },
+{ 'u', 117 },
+{ 'v', 118 },
+{ 'w', 119 },
+{ 'x', 120 },
+{ 'y', 121 },
+{ 'z', 122 },
+{ '{', 123 },
+{ '|', 124 },
+{ '}', 125 },
+{ '~', 126 }
+};
+
+int der_ia5_char_encode(int c)
+{
+   int x;
+   for (x = 0; x < (int)(sizeof(ia5_table)/sizeof(ia5_table[0])); x++) {
+       if (ia5_table[x].code == c) {
+          return ia5_table[x].value;
+       }
+   }
+   return -1;
+}
+
+int der_ia5_value_decode(int v)
+{
+   int x;
+   for (x = 0; x < (int)(sizeof(ia5_table)/sizeof(ia5_table[0])); x++) {
+       if (ia5_table[x].value == v) {
+          return ia5_table[x].code;
+       }
+   }
+   return -1;
+}
+
+/**
+  Gets length of DER encoding of IA5 STRING
+  @param octets   The values you want to encode
+  @param noctets  The number of octets in the string to encode
+  @param outlen   [out] The length of the DER encoding for the given string
+  @return CRYPT_OK if successful
+*/
+int der_length_ia5_string(const unsigned char *octets, unsigned long noctets, unsigned long *outlen)
+{
+   unsigned long x;
+
+   LTC_ARGCHK(outlen != NULL);
+   LTC_ARGCHK(octets != NULL);
+
+   /* scan string for validity */
+   for (x = 0; x < noctets; x++) {
+       if (der_ia5_char_encode(octets[x]) == -1) {
+          return CRYPT_INVALID_ARG;
+       }
+   }
+
+   if (noctets < 128) {
+      /* 16 LL DD DD DD ... */
+      *outlen = 2 + noctets;
+   } else if (noctets < 256) {
+      /* 16 81 LL DD DD DD ... */
+      *outlen = 3 + noctets;
+   } else if (noctets < 65536UL) {
+      /* 16 82 LL LL DD DD DD ... */
+      *outlen = 4 + noctets;
+   } else if (noctets < 16777216UL) {
+      /* 16 83 LL LL LL DD DD DD ... */
+      *outlen = 5 + noctets;
+   } else {
+      return CRYPT_INVALID_ARG;
+   }
+
+   return CRYPT_OK;
+}
+
+#endif
+
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/pk/asn1/der/integer/der_decode_integer.c b/libtomcrypt/src/pk/asn1/der/integer/der_decode_integer.c
new file mode 100644 (file)
index 0000000..88cf93f
--- /dev/null
@@ -0,0 +1,108 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file der_decode_integer.c
+  ASN.1 DER, decode an integer, Tom St Denis
+*/
+
+
+#ifdef LTC_DER
+
+/**
+  Read a mp_int integer
+  @param in       The DER encoded data
+  @param inlen    Size of DER encoded data
+  @param num      The first mp_int to decode
+  @return CRYPT_OK if successful
+*/
+int der_decode_integer(const unsigned char *in, unsigned long inlen, void *num)
+{
+   unsigned long x, y, z;
+   int           err;
+
+   LTC_ARGCHK(num    != NULL);
+   LTC_ARGCHK(in     != NULL);
+
+   /* min DER INTEGER is 0x02 01 00 == 0 */
+   if (inlen < (1 + 1 + 1)) {
+      return CRYPT_INVALID_PACKET;
+   }
+
+   /* ok expect 0x02 when we AND with 0001 1111 [1F] */
+   x = 0;
+   if ((in[x++] & 0x1F) != 0x02) {
+      return CRYPT_INVALID_PACKET;
+   }
+
+   /* now decode the len stuff */
+   z = in[x++];
+
+   if ((z & 0x80) == 0x00) {
+      /* short form */
+
+      /* will it overflow? */
+      if (x + z > inlen) {
+         return CRYPT_INVALID_PACKET;
+      }
+
+      /* no so read it */
+      if ((err = mp_read_unsigned_bin(num, (unsigned char *)in + x, z)) != CRYPT_OK) {
+         return err;
+      }
+   } else {
+      /* long form */
+      z &= 0x7F;
+
+      /* will number of length bytes overflow? (or > 4) */
+      if (((x + z) > inlen) || (z > 4) || (z == 0)) {
+         return CRYPT_INVALID_PACKET;
+      }
+
+      /* now read it in */
+      y = 0;
+      while (z--) {
+         y = ((unsigned long)(in[x++])) | (y << 8);
+      }
+
+      /* now will reading y bytes overrun? */
+      if ((x + y) > inlen) {
+         return CRYPT_INVALID_PACKET;
+      }
+
+      /* no so read it */
+      if ((err = mp_read_unsigned_bin(num, (unsigned char *)in + x, y)) != CRYPT_OK) {
+         return err;
+      }
+   }
+
+   /* see if it's negative */
+   if (in[x] & 0x80) {
+      void *tmp;
+      if (mp_init(&tmp) != CRYPT_OK) {
+         return CRYPT_MEM;
+      }
+
+      if (mp_2expt(tmp, mp_count_bits(num)) != CRYPT_OK || mp_sub(num, tmp, num) != CRYPT_OK) {
+         mp_clear(tmp);
+         return CRYPT_MEM;
+      }
+      mp_clear(tmp);
+   }
+
+   return CRYPT_OK;
+
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/pk/asn1/der/integer/der_encode_integer.c b/libtomcrypt/src/pk/asn1/der/integer/der_encode_integer.c
new file mode 100644 (file)
index 0000000..a8bada5
--- /dev/null
@@ -0,0 +1,128 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file der_encode_integer.c
+  ASN.1 DER, encode an integer, Tom St Denis
+*/
+
+
+#ifdef LTC_DER
+
+/* Exports a positive bignum as DER format (upto 2^32 bytes in size) */
+/**
+  Store a mp_int integer
+  @param num      The first mp_int to encode
+  @param out      [out] The destination for the DER encoded integers
+  @param outlen   [in/out] The max size and resulting size of the DER encoded integers
+  @return CRYPT_OK if successful
+*/
+int der_encode_integer(void *num, unsigned char *out, unsigned long *outlen)
+{
+   unsigned long tmplen, y;
+   int           err, leading_zero;
+
+   LTC_ARGCHK(num    != NULL);
+   LTC_ARGCHK(out    != NULL);
+   LTC_ARGCHK(outlen != NULL);
+
+   /* find out how big this will be */
+   if ((err = der_length_integer(num, &tmplen)) != CRYPT_OK) {
+      return err;
+   }
+
+   if (*outlen < tmplen) {
+      *outlen = tmplen;
+      return CRYPT_BUFFER_OVERFLOW;
+   }
+
+   if (mp_cmp_d(num, 0) != LTC_MP_LT) {
+      /* we only need a leading zero if the msb of the first byte is one */
+      if ((mp_count_bits(num) & 7) == 0 || mp_iszero(num) == LTC_MP_YES) {
+         leading_zero = 1;
+      } else {
+         leading_zero = 0;
+      }
+
+      /* get length of num in bytes (plus 1 since we force the msbyte to zero) */
+      y = mp_unsigned_bin_size(num) + leading_zero;
+   } else {
+      leading_zero = 0;
+      y            = mp_count_bits(num);
+      y            = y + (8 - (y & 7));
+      y            = y >> 3;
+      if (((mp_cnt_lsb(num)+1)==mp_count_bits(num)) && ((mp_count_bits(num)&7)==0)) --y;
+   }
+
+   /* now store initial data */
+   *out++ = 0x02;
+   if (y < 128) {
+      /* short form */
+      *out++ = (unsigned char)y;
+   } else if (y < 256) {
+      *out++ = 0x81;
+      *out++ = (unsigned char)y;
+   } else if (y < 65536UL) {
+      *out++ = 0x82;
+      *out++ = (unsigned char)((y>>8)&255);
+      *out++ = (unsigned char)y;
+   } else if (y < 16777216UL) {
+      *out++ = 0x83;
+      *out++ = (unsigned char)((y>>16)&255);
+      *out++ = (unsigned char)((y>>8)&255);
+      *out++ = (unsigned char)y;
+   } else {
+      return CRYPT_INVALID_ARG;
+   }
+
+   /* now store msbyte of zero if num is non-zero */
+   if (leading_zero) {
+      *out++ = 0x00;
+   }
+
+   /* if it's not zero store it as big endian */
+   if (mp_cmp_d(num, 0) == LTC_MP_GT) {
+      /* now store the mpint */
+      if ((err = mp_to_unsigned_bin(num, out)) != CRYPT_OK) {
+          return err;
+      }
+   } else if (mp_iszero(num) != LTC_MP_YES) {
+      void *tmp;
+
+      /* negative */
+      if (mp_init(&tmp) != CRYPT_OK) {
+         return CRYPT_MEM;
+      }
+
+      /* 2^roundup and subtract */
+      y = mp_count_bits(num);
+      y = y + (8 - (y & 7));
+      if (((mp_cnt_lsb(num)+1)==mp_count_bits(num)) && ((mp_count_bits(num)&7)==0)) y -= 8;
+      if (mp_2expt(tmp, y) != CRYPT_OK || mp_add(tmp, num, tmp) != CRYPT_OK) {
+         mp_clear(tmp);
+         return CRYPT_MEM;
+      }
+      if ((err = mp_to_unsigned_bin(tmp, out)) != CRYPT_OK) {
+         mp_clear(tmp);
+         return err;
+      }
+      mp_clear(tmp);
+   }
+
+   /* we good */
+   *outlen = tmplen;
+   return CRYPT_OK;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/pk/asn1/der/integer/der_length_integer.c b/libtomcrypt/src/pk/asn1/der/integer/der_length_integer.c
new file mode 100644 (file)
index 0000000..753ef0e
--- /dev/null
@@ -0,0 +1,79 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file der_length_integer.c
+  ASN.1 DER, get length of encoding, Tom St Denis
+*/
+
+
+#ifdef LTC_DER
+/**
+  Gets length of DER encoding of num
+  @param num    The int to get the size of
+  @param outlen [out] The length of the DER encoding for the given integer
+  @return CRYPT_OK if successful
+*/
+int der_length_integer(void *num, unsigned long *outlen)
+{
+   unsigned long z, len;
+   int           leading_zero;
+
+   LTC_ARGCHK(num     != NULL);
+   LTC_ARGCHK(outlen  != NULL);
+
+   if (mp_cmp_d(num, 0) != LTC_MP_LT) {
+      /* positive */
+
+      /* we only need a leading zero if the msb of the first byte is one */
+      if ((mp_count_bits(num) & 7) == 0 || mp_iszero(num) == LTC_MP_YES) {
+         leading_zero = 1;
+      } else {
+         leading_zero = 0;
+      }
+
+      /* size for bignum */
+      z = len = leading_zero + mp_unsigned_bin_size(num);
+   } else {
+      /* it's negative */
+      /* find power of 2 that is a multiple of eight and greater than count bits */
+      z = mp_count_bits(num);
+      z = z + (8 - (z & 7));
+      if (((mp_cnt_lsb(num)+1)==mp_count_bits(num)) && ((mp_count_bits(num)&7)==0)) --z;
+      len = z = z >> 3;
+   }
+
+   /* now we need a length */
+   if (z < 128) {
+      /* short form */
+      ++len;
+   } else {
+      /* long form (relies on z != 0), assumes length bytes < 128 */
+      ++len;
+
+      while (z) {
+         ++len;
+         z >>= 8;
+      }
+   }
+
+   /* we need a 0x02 to indicate it's INTEGER */
+   ++len;
+
+   /* return length */
+   *outlen = len;
+   return CRYPT_OK;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/pk/asn1/der/object_identifier/der_decode_object_identifier.c b/libtomcrypt/src/pk/asn1/der/object_identifier/der_decode_object_identifier.c
new file mode 100644 (file)
index 0000000..75bc127
--- /dev/null
@@ -0,0 +1,106 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file der_decode_object_identifier.c
+  ASN.1 DER, Decode Object Identifier, Tom St Denis
+*/
+
+#ifdef LTC_DER
+/**
+  Decode OID data and store the array of integers in words
+  @param in      The OID DER encoded data
+  @param inlen   The length of the OID data
+  @param words   [out] The destination of the OID words
+  @param outlen  [in/out] The number of OID words
+  @return CRYPT_OK if successful
+*/
+int der_decode_object_identifier(const unsigned char *in,    unsigned long  inlen,
+                                       unsigned long *words, unsigned long *outlen)
+{
+   unsigned long x, y, t, len;
+   int err;
+
+   LTC_ARGCHK(in     != NULL);
+   LTC_ARGCHK(words  != NULL);
+   LTC_ARGCHK(outlen != NULL);
+
+   /* header is at least 3 bytes */
+   if (inlen < 3) {
+      return CRYPT_INVALID_PACKET;
+   }
+
+   /* must be room for at least two words */
+   if (*outlen < 2) {
+      *outlen = 2;
+      return CRYPT_BUFFER_OVERFLOW;
+   }
+
+   /* decode the packet header */
+   x = 0;
+   if ((in[x++] & 0x1F) != 0x06) {
+      return CRYPT_INVALID_PACKET;
+   }
+
+   /* get the length */
+   if (in[x] < 128) {
+      len = in[x++];
+   } else {
+      if (in[x] < 0x81 || in[x] > 0x82) {
+         return CRYPT_INVALID_PACKET;
+      }
+      y   = in[x++] & 0x7F;
+      len = 0;
+      while (y--) {
+         len = (len << 8) | (unsigned long)in[x++];
+      }
+   }
+
+   if (len < 1 || (len + x) > inlen) {
+      return CRYPT_INVALID_PACKET;
+   }
+
+   /* decode words */
+   y = 0;
+   t = 0;
+   while (len--) {
+      t = (t << 7) | (in[x] & 0x7F);
+      if (!(in[x++] & 0x80)) {
+         /* store t */
+         if (y >= *outlen) {
+            y++;
+         } else {
+            if (y == 0) {
+               words[0] = t / 40;
+               words[1] = t % 40;
+               y = 2;
+            } else {
+               words[y++] = t;
+            }
+         }
+         t = 0;
+      }
+   }
+
+   if (y > *outlen) {
+      err =  CRYPT_BUFFER_OVERFLOW;
+   } else {
+      err =  CRYPT_OK;
+   }
+
+   *outlen = y;
+   return err;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/pk/asn1/der/object_identifier/der_encode_object_identifier.c b/libtomcrypt/src/pk/asn1/der/object_identifier/der_encode_object_identifier.c
new file mode 100644 (file)
index 0000000..b1ce62c
--- /dev/null
@@ -0,0 +1,109 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file der_encode_object_identifier.c
+  ASN.1 DER, Encode Object Identifier, Tom St Denis
+*/
+
+#ifdef LTC_DER
+/**
+  Encode an OID
+  @param words   The words to encode  (upto 32-bits each)
+  @param nwords  The number of words in the OID
+  @param out     [out] Destination of OID data
+  @param outlen  [in/out] The max and resulting size of the OID
+  @return CRYPT_OK if successful
+*/
+int der_encode_object_identifier(unsigned long *words, unsigned long  nwords,
+                                 unsigned char *out,   unsigned long *outlen)
+{
+   unsigned long i, x, y, z, t, mask, wordbuf;
+   int           err;
+
+   LTC_ARGCHK(words  != NULL);
+   LTC_ARGCHK(out    != NULL);
+   LTC_ARGCHK(outlen != NULL);
+
+   /* check length */
+   if ((err = der_length_object_identifier(words, nwords, &x)) != CRYPT_OK) {
+      return err;
+   }
+   if (x > *outlen) {
+      *outlen = x;
+      return CRYPT_BUFFER_OVERFLOW;
+   }
+
+   /* compute length to store OID data */
+   z = 0;
+   wordbuf = words[0] * 40 + words[1];
+   for (y = 1; y < nwords; y++) {
+       t = der_object_identifier_bits(wordbuf);
+       z += t/7 + ((t%7) ? 1 : 0) + (wordbuf == 0 ? 1 : 0);
+       if (y < nwords - 1) {
+          wordbuf = words[y + 1];
+       }
+   }
+
+   /* store header + length */
+   x = 0;
+   out[x++] = 0x06;
+   if (z < 128) {
+      out[x++] = (unsigned char)z;
+   } else if (z < 256) {
+      out[x++] = 0x81;
+      out[x++] = (unsigned char)z;
+   } else if (z < 65536UL) {
+      out[x++] = 0x82;
+      out[x++] = (unsigned char)((z>>8)&255);
+      out[x++] = (unsigned char)(z&255);
+   } else {
+      return CRYPT_INVALID_ARG;
+   }
+
+   /* store first byte */
+   wordbuf = words[0] * 40 + words[1];
+   for (i = 1; i < nwords; i++) {
+      /* store 7 bit words in little endian */
+      t    = wordbuf & 0xFFFFFFFF;
+      if (t) {
+         y    = x;
+         mask = 0;
+         while (t) {
+            out[x++] = (unsigned char)((t & 0x7F) | mask);
+            t    >>= 7;
+            mask  |= 0x80;  /* upper bit is set on all but the last byte */
+         }
+         /* now swap bytes y...x-1 */
+         z = x - 1;
+         while (y < z) {
+            t = out[y]; out[y] = out[z]; out[z] = (unsigned char)t;
+            ++y;
+            --z;
+         }
+      } else {
+         /* zero word */
+         out[x++] = 0x00;
+      }
+
+      if (i < nwords - 1) {
+         wordbuf = words[i + 1];
+      }
+   }
+
+   *outlen = x;
+   return CRYPT_OK;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/pk/asn1/der/object_identifier/der_length_object_identifier.c b/libtomcrypt/src/pk/asn1/der/object_identifier/der_length_object_identifier.c
new file mode 100644 (file)
index 0000000..ac08915
--- /dev/null
@@ -0,0 +1,87 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file der_length_object_identifier.c
+  ASN.1 DER, get length of Object Identifier, Tom St Denis
+*/
+
+#ifdef LTC_DER
+
+unsigned long der_object_identifier_bits(unsigned long x)
+{
+   unsigned long c;
+   x &= 0xFFFFFFFF;
+   c  = 0;
+   while (x) {
+     ++c;
+     x >>= 1;
+   }
+   return c;
+}
+
+
+/**
+  Gets length of DER encoding of Object Identifier
+  @param nwords   The number of OID words
+  @param words    The actual OID words to get the size of
+  @param outlen   [out] The length of the DER encoding for the given string
+  @return CRYPT_OK if successful
+*/
+int der_length_object_identifier(unsigned long *words, unsigned long nwords, unsigned long *outlen)
+{
+   unsigned long y, z, t, wordbuf;
+
+   LTC_ARGCHK(words  != NULL);
+   LTC_ARGCHK(outlen != NULL);
+
+
+   /* must be >= 2 words */
+   if (nwords < 2) {
+      return CRYPT_INVALID_ARG;
+   }
+
+   /* word1 = 0,1,2,3 and word2 0..39 */
+   if (words[0] > 3 || (words[0] < 2 && words[1] > 39)) {
+      return CRYPT_INVALID_ARG;
+   }
+
+   /* leading word is the first two */
+   z = 0;
+   wordbuf = words[0] * 40 + words[1];
+   for (y = 1; y < nwords; y++) {
+       t = der_object_identifier_bits(wordbuf);
+       z += t/7 + ((t%7) ? 1 : 0) + (wordbuf == 0 ? 1 : 0);
+       if (y < nwords - 1) {
+          /* grab next word */
+          wordbuf = words[y+1];
+       }
+   }
+
+   /* now depending on the length our length encoding changes */
+   if (z < 128) {
+      z += 2;
+   } else if (z < 256) {
+      z += 3;
+   } else if (z < 65536UL) {
+      z += 4;
+   } else {
+      return CRYPT_INVALID_ARG;
+   }
+
+   *outlen = z;
+   return CRYPT_OK;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/pk/asn1/der/octet/der_decode_octet_string.c b/libtomcrypt/src/pk/asn1/der/octet/der_decode_octet_string.c
new file mode 100644 (file)
index 0000000..02859dc
--- /dev/null
@@ -0,0 +1,89 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file der_decode_octet_string.c
+  ASN.1 DER, encode a OCTET STRING, Tom St Denis
+*/
+
+
+#ifdef LTC_DER
+
+/**
+  Store a OCTET STRING
+  @param in      The DER encoded OCTET STRING
+  @param inlen   The size of the DER OCTET STRING
+  @param out     [out] The array of octets stored (one per char)
+  @param outlen  [in/out] The number of octets stored
+  @return CRYPT_OK if successful
+*/
+int der_decode_octet_string(const unsigned char *in, unsigned long inlen,
+                                  unsigned char *out, unsigned long *outlen)
+{
+   unsigned long x, y, len;
+
+   LTC_ARGCHK(in     != NULL);
+   LTC_ARGCHK(out    != NULL);
+   LTC_ARGCHK(outlen != NULL);
+
+   /* must have header at least */
+   if (inlen < 2) {
+      return CRYPT_INVALID_PACKET;
+   }
+
+   /* check for 0x04 */
+   if ((in[0] & 0x1F) != 0x04) {
+      return CRYPT_INVALID_PACKET;
+   }
+   x = 1;
+
+   /* decode the length */
+   if (in[x] & 0x80) {
+      /* valid # of bytes in length are 1,2,3 */
+      y = in[x] & 0x7F;
+      if ((y == 0) || (y > 3) || ((x + y) > inlen)) {
+         return CRYPT_INVALID_PACKET;
+      }
+
+      /* read the length in */
+      len = 0;
+      ++x;
+      while (y--) {
+         len = (len << 8) | in[x++];
+      }
+   } else {
+      len = in[x++] & 0x7F;
+   }
+
+   /* is it too long? */
+   if (len > *outlen) {
+      *outlen = len;
+      return CRYPT_BUFFER_OVERFLOW;
+   }
+
+   if (len + x > inlen) {
+      return CRYPT_INVALID_PACKET;
+   }
+
+   /* read the data */
+   for (y = 0; y < len; y++) {
+       out[y] = in[x++];
+   }
+
+   *outlen = y;
+
+   return CRYPT_OK;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/pk/asn1/der/octet/der_encode_octet_string.c b/libtomcrypt/src/pk/asn1/der/octet/der_encode_octet_string.c
new file mode 100644 (file)
index 0000000..9c9d1a6
--- /dev/null
@@ -0,0 +1,84 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file der_encode_octet_string.c
+  ASN.1 DER, encode a OCTET STRING, Tom St Denis
+*/
+
+
+#ifdef LTC_DER
+
+/**
+  Store an OCTET STRING
+  @param in       The array of OCTETS to store (one per char)
+  @param inlen    The number of OCTETS to store
+  @param out      [out] The destination for the DER encoded OCTET STRING
+  @param outlen   [in/out] The max size and resulting size of the DER OCTET STRING
+  @return CRYPT_OK if successful
+*/
+int der_encode_octet_string(const unsigned char *in, unsigned long inlen,
+                                  unsigned char *out, unsigned long *outlen)
+{
+   unsigned long x, y, len;
+   int           err;
+
+   LTC_ARGCHK(in     != NULL);
+   LTC_ARGCHK(out    != NULL);
+   LTC_ARGCHK(outlen != NULL);
+
+   /* get the size */
+   if ((err = der_length_octet_string(inlen, &len)) != CRYPT_OK) {
+      return err;
+   }
+
+   /* too big? */
+   if (len > *outlen) {
+      *outlen = len;
+      return CRYPT_BUFFER_OVERFLOW;
+   }
+
+   /* encode the header+len */
+   x = 0;
+   out[x++] = 0x04;
+   if (inlen < 128) {
+      out[x++] = (unsigned char)inlen;
+   } else if (inlen < 256) {
+      out[x++] = 0x81;
+      out[x++] = (unsigned char)inlen;
+   } else if (inlen < 65536UL) {
+      out[x++] = 0x82;
+      out[x++] = (unsigned char)((inlen>>8)&255);
+      out[x++] = (unsigned char)(inlen&255);
+   } else if (inlen < 16777216UL) {
+      out[x++] = 0x83;
+      out[x++] = (unsigned char)((inlen>>16)&255);
+      out[x++] = (unsigned char)((inlen>>8)&255);
+      out[x++] = (unsigned char)(inlen&255);
+   } else {
+      return CRYPT_INVALID_ARG;
+   }
+
+   /* store octets */
+   for (y = 0; y < inlen; y++) {
+       out[x++] = in[y];
+   }
+
+   /* retun length */
+   *outlen = x;
+
+   return CRYPT_OK;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/pk/asn1/der/octet/der_length_octet_string.c b/libtomcrypt/src/pk/asn1/der/octet/der_length_octet_string.c
new file mode 100644 (file)
index 0000000..10c9e89
--- /dev/null
@@ -0,0 +1,51 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file der_length_octet_string.c
+  ASN.1 DER, get length of OCTET STRING, Tom St Denis
+*/
+
+#ifdef LTC_DER
+/**
+  Gets length of DER encoding of OCTET STRING
+  @param noctets  The number of octets in the string to encode
+  @param outlen   [out] The length of the DER encoding for the given string
+  @return CRYPT_OK if successful
+*/
+int der_length_octet_string(unsigned long noctets, unsigned long *outlen)
+{
+   LTC_ARGCHK(outlen != NULL);
+
+   if (noctets < 128) {
+      /* 04 LL DD DD DD ... */
+      *outlen = 2 + noctets;
+   } else if (noctets < 256) {
+      /* 04 81 LL DD DD DD ... */
+      *outlen = 3 + noctets;
+   } else if (noctets < 65536UL) {
+      /* 04 82 LL LL DD DD DD ... */
+      *outlen = 4 + noctets;
+   } else if (noctets < 16777216UL) {
+      /* 04 83 LL LL LL DD DD DD ... */
+      *outlen = 5 + noctets;
+   } else {
+      return CRYPT_INVALID_ARG;
+   }
+
+   return CRYPT_OK;
+}
+
+#endif
+
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/pk/asn1/der/printable_string/der_decode_printable_string.c b/libtomcrypt/src/pk/asn1/der/printable_string/der_decode_printable_string.c
new file mode 100644 (file)
index 0000000..6947429
--- /dev/null
@@ -0,0 +1,94 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file der_decode_printable_string.c
+  ASN.1 DER, encode a printable STRING, Tom St Denis
+*/
+
+
+#ifdef LTC_DER
+
+/**
+  Store a printable STRING
+  @param in      The DER encoded printable STRING
+  @param inlen   The size of the DER printable STRING
+  @param out     [out] The array of octets stored (one per char)
+  @param outlen  [in/out] The number of octets stored
+  @return CRYPT_OK if successful
+*/
+int der_decode_printable_string(const unsigned char *in, unsigned long inlen,
+                                unsigned char *out, unsigned long *outlen)
+{
+   unsigned long x, y, len;
+   int           t;
+
+   LTC_ARGCHK(in     != NULL);
+   LTC_ARGCHK(out    != NULL);
+   LTC_ARGCHK(outlen != NULL);
+
+   /* must have header at least */
+   if (inlen < 2) {
+      return CRYPT_INVALID_PACKET;
+   }
+
+   /* check for 0x13 */
+   if ((in[0] & 0x1F) != 0x13) {
+      return CRYPT_INVALID_PACKET;
+   }
+   x = 1;
+
+   /* decode the length */
+   if (in[x] & 0x80) {
+      /* valid # of bytes in length are 1,2,3 */
+      y = in[x] & 0x7F;
+      if ((y == 0) || (y > 3) || ((x + y) > inlen)) {
+         return CRYPT_INVALID_PACKET;
+      }
+
+      /* read the length in */
+      len = 0;
+      ++x;
+      while (y--) {
+         len = (len << 8) | in[x++];
+      }
+   } else {
+      len = in[x++] & 0x7F;
+   }
+
+   /* is it too long? */
+   if (len > *outlen) {
+      *outlen = len;
+      return CRYPT_BUFFER_OVERFLOW;
+   }
+
+   if (len + x > inlen) {
+      return CRYPT_INVALID_PACKET;
+   }
+
+   /* read the data */
+   for (y = 0; y < len; y++) {
+       t = der_printable_value_decode(in[x++]);
+       if (t == -1) {
+           return CRYPT_INVALID_ARG;
+       }
+       out[y] = t;
+   }
+
+   *outlen = y;
+
+   return CRYPT_OK;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/pk/asn1/der/printable_string/der_encode_printable_string.c b/libtomcrypt/src/pk/asn1/der/printable_string/der_encode_printable_string.c
new file mode 100644 (file)
index 0000000..ee54e48
--- /dev/null
@@ -0,0 +1,83 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file der_encode_printable_string.c
+  ASN.1 DER, encode a printable STRING, Tom St Denis
+*/
+
+#ifdef LTC_DER
+
+/**
+  Store an printable STRING
+  @param in       The array of printable to store (one per char)
+  @param inlen    The number of printable to store
+  @param out      [out] The destination for the DER encoded printable STRING
+  @param outlen   [in/out] The max size and resulting size of the DER printable STRING
+  @return CRYPT_OK if successful
+*/
+int der_encode_printable_string(const unsigned char *in, unsigned long inlen,
+                                unsigned char *out, unsigned long *outlen)
+{
+   unsigned long x, y, len;
+   int           err;
+
+   LTC_ARGCHK(in     != NULL);
+   LTC_ARGCHK(out    != NULL);
+   LTC_ARGCHK(outlen != NULL);
+
+   /* get the size */
+   if ((err = der_length_printable_string(in, inlen, &len)) != CRYPT_OK) {
+      return err;
+   }
+
+   /* too big? */
+   if (len > *outlen) {
+      *outlen = len;
+      return CRYPT_BUFFER_OVERFLOW;
+   }
+
+   /* encode the header+len */
+   x = 0;
+   out[x++] = 0x13;
+   if (inlen < 128) {
+      out[x++] = (unsigned char)inlen;
+   } else if (inlen < 256) {
+      out[x++] = 0x81;
+      out[x++] = (unsigned char)inlen;
+   } else if (inlen < 65536UL) {
+      out[x++] = 0x82;
+      out[x++] = (unsigned char)((inlen>>8)&255);
+      out[x++] = (unsigned char)(inlen&255);
+   } else if (inlen < 16777216UL) {
+      out[x++] = 0x83;
+      out[x++] = (unsigned char)((inlen>>16)&255);
+      out[x++] = (unsigned char)((inlen>>8)&255);
+      out[x++] = (unsigned char)(inlen&255);
+   } else {
+      return CRYPT_INVALID_ARG;
+   }
+
+   /* store octets */
+   for (y = 0; y < inlen; y++) {
+       out[x++] = der_printable_char_encode(in[y]);
+   }
+
+   /* retun length */
+   *outlen = x;
+
+   return CRYPT_OK;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/pk/asn1/der/printable_string/der_length_printable_string.c b/libtomcrypt/src/pk/asn1/der/printable_string/der_length_printable_string.c
new file mode 100644 (file)
index 0000000..40f0beb
--- /dev/null
@@ -0,0 +1,164 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file der_length_printable_string.c
+  ASN.1 DER, get length of Printable STRING, Tom St Denis
+*/
+
+#ifdef LTC_DER
+
+static const struct {
+   int code, value;
+} printable_table[] = {
+{ ' ', 32 },
+{ '\'', 39 },
+{ '(', 40 },
+{ ')', 41 },
+{ '+', 43 },
+{ ',', 44 },
+{ '-', 45 },
+{ '.', 46 },
+{ '/', 47 },
+{ '0', 48 },
+{ '1', 49 },
+{ '2', 50 },
+{ '3', 51 },
+{ '4', 52 },
+{ '5', 53 },
+{ '6', 54 },
+{ '7', 55 },
+{ '8', 56 },
+{ '9', 57 },
+{ ':', 58 },
+{ '=', 61 },
+{ '?', 63 },
+{ 'A', 65 },
+{ 'B', 66 },
+{ 'C', 67 },
+{ 'D', 68 },
+{ 'E', 69 },
+{ 'F', 70 },
+{ 'G', 71 },
+{ 'H', 72 },
+{ 'I', 73 },
+{ 'J', 74 },
+{ 'K', 75 },
+{ 'L', 76 },
+{ 'M', 77 },
+{ 'N', 78 },
+{ 'O', 79 },
+{ 'P', 80 },
+{ 'Q', 81 },
+{ 'R', 82 },
+{ 'S', 83 },
+{ 'T', 84 },
+{ 'U', 85 },
+{ 'V', 86 },
+{ 'W', 87 },
+{ 'X', 88 },
+{ 'Y', 89 },
+{ 'Z', 90 },
+{ 'a', 97 },
+{ 'b', 98 },
+{ 'c', 99 },
+{ 'd', 100 },
+{ 'e', 101 },
+{ 'f', 102 },
+{ 'g', 103 },
+{ 'h', 104 },
+{ 'i', 105 },
+{ 'j', 106 },
+{ 'k', 107 },
+{ 'l', 108 },
+{ 'm', 109 },
+{ 'n', 110 },
+{ 'o', 111 },
+{ 'p', 112 },
+{ 'q', 113 },
+{ 'r', 114 },
+{ 's', 115 },
+{ 't', 116 },
+{ 'u', 117 },
+{ 'v', 118 },
+{ 'w', 119 },
+{ 'x', 120 },
+{ 'y', 121 },
+{ 'z', 122 },
+};
+
+int der_printable_char_encode(int c)
+{
+   int x;
+   for (x = 0; x < (int)(sizeof(printable_table)/sizeof(printable_table[0])); x++) {
+       if (printable_table[x].code == c) {
+          return printable_table[x].value;
+       }
+   }
+   return -1;
+}
+
+int der_printable_value_decode(int v)
+{
+   int x;
+   for (x = 0; x < (int)(sizeof(printable_table)/sizeof(printable_table[0])); x++) {
+       if (printable_table[x].value == v) {
+          return printable_table[x].code;
+       }
+   }
+   return -1;
+}
+
+/**
+  Gets length of DER encoding of Printable STRING
+  @param octets   The values you want to encode
+  @param noctets  The number of octets in the string to encode
+  @param outlen   [out] The length of the DER encoding for the given string
+  @return CRYPT_OK if successful
+*/
+int der_length_printable_string(const unsigned char *octets, unsigned long noctets, unsigned long *outlen)
+{
+   unsigned long x;
+
+   LTC_ARGCHK(outlen != NULL);
+   LTC_ARGCHK(octets != NULL);
+
+   /* scan string for validity */
+   for (x = 0; x < noctets; x++) {
+       if (der_printable_char_encode(octets[x]) == -1) {
+          return CRYPT_INVALID_ARG;
+       }
+   }
+
+   if (noctets < 128) {
+      /* 16 LL DD DD DD ... */
+      *outlen = 2 + noctets;
+   } else if (noctets < 256) {
+      /* 16 81 LL DD DD DD ... */
+      *outlen = 3 + noctets;
+   } else if (noctets < 65536UL) {
+      /* 16 82 LL LL DD DD DD ... */
+      *outlen = 4 + noctets;
+   } else if (noctets < 16777216UL) {
+      /* 16 83 LL LL LL DD DD DD ... */
+      *outlen = 5 + noctets;
+   } else {
+      return CRYPT_INVALID_ARG;
+   }
+
+   return CRYPT_OK;
+}
+
+#endif
+
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/pk/asn1/der/sequence/der_decode_sequence_ex.c b/libtomcrypt/src/pk/asn1/der/sequence/der_decode_sequence_ex.c
new file mode 100644 (file)
index 0000000..b820c68
--- /dev/null
@@ -0,0 +1,328 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+
+/**
+  @file der_decode_sequence_ex.c
+  ASN.1 DER, decode a SEQUENCE, Tom St Denis
+*/
+
+#ifdef LTC_DER
+
+/**
+   Decode a SEQUENCE
+   @param in       The DER encoded input
+   @param inlen    The size of the input
+   @param list     The list of items to decode
+   @param outlen   The number of items in the list
+   @param ordered  Search an unordeded or ordered list
+   @return CRYPT_OK on success
+*/
+int der_decode_sequence_ex(const unsigned char *in, unsigned long  inlen,
+                           ltc_asn1_list *list,     unsigned long  outlen, int ordered)
+{
+   int           err, i;
+   ltc_asn1_type type;
+   unsigned long size, x, y, z, blksize;
+   void          *data;
+
+   LTC_ARGCHK(in   != NULL);
+   LTC_ARGCHK(list != NULL);
+
+   /* get blk size */
+   if (inlen < 2) {
+      return CRYPT_INVALID_PACKET;
+   }
+
+   /* sequence type? We allow 0x30 SEQUENCE and 0x31 SET since fundamentally they're the same structure */
+   x = 0;
+   if (in[x] != 0x30 && in[x] != 0x31) {
+      return CRYPT_INVALID_PACKET;
+   }
+   ++x;
+
+   /* check if the msb is set, which signals that the
+    * 7 lsb bits represent the number of bytes of the length
+    */
+   if (in[x] < 128) {
+      blksize = in[x++];
+   } else {
+      if (in[x] < 0x81 || in[x] > 0x83) {
+         return CRYPT_INVALID_PACKET;
+      }
+      y = in[x++] & 0x7F;
+
+      /* would reading the len bytes overrun? */
+      if (x + y > inlen) {
+         return CRYPT_INVALID_PACKET;
+      }
+
+      /* read len */
+      blksize = 0;
+      while (y--) {
+          blksize = (blksize << 8) | (unsigned long)in[x++];
+      }
+   }
+
+   /* would this blksize overflow? */
+   if (x + blksize > inlen) {
+      return CRYPT_INVALID_PACKET;
+   }
+
+   /* mark all as unused */
+   for (i = 0; i < (int)outlen; i++) {
+       list[i].used = 0;
+   }
+
+   /* ok read data */
+   inlen = blksize;
+   for (i = 0; i < (int)outlen; i++) {
+       z    = 0;
+       type = list[i].type;
+       size = list[i].size;
+       data = list[i].data;
+       if (!ordered && list[i].used == 1) { continue; }
+
+       if (type == LTC_ASN1_EOL) {
+          break;
+       }
+
+       switch (type) {
+           case LTC_ASN1_BOOLEAN:
+               z = inlen;
+               if ((err = der_decode_boolean(in + x, z, ((int *)data))) != CRYPT_OK) {
+                   if (!ordered) { continue; }
+                   goto LBL_ERR;
+               }
+               if ((err = der_length_boolean(&z)) != CRYPT_OK) {
+                   goto LBL_ERR;
+               }
+               break;
+
+           case LTC_ASN1_INTEGER:
+               z = inlen;
+               if ((err = der_decode_integer(in + x, z, data)) != CRYPT_OK) {
+                  if (!ordered) {  continue; }
+                  goto LBL_ERR;
+               }
+               if ((err = der_length_integer(data, &z)) != CRYPT_OK) {
+                  goto LBL_ERR;
+               }
+               break;
+
+           case LTC_ASN1_SHORT_INTEGER:
+               z = inlen;
+               if ((err = der_decode_short_integer(in + x, z, data)) != CRYPT_OK) {
+                  if (!ordered) { continue; }
+                  goto LBL_ERR;
+               }
+               if ((err = der_length_short_integer(((unsigned long*)data)[0], &z)) != CRYPT_OK) {
+                  goto LBL_ERR;
+               }
+
+               break;
+
+           case LTC_ASN1_BIT_STRING:
+               z = inlen;
+               if ((err = der_decode_bit_string(in + x, z, data, &size)) != CRYPT_OK) {
+                  if (!ordered) { continue; }
+                  goto LBL_ERR;
+               }
+               list[i].size = size;
+               if ((err = der_length_bit_string(size, &z)) != CRYPT_OK) {
+                  goto LBL_ERR;
+               }
+               break;
+
+           case LTC_ASN1_RAW_BIT_STRING:
+               z = inlen;
+               if ((err = der_decode_raw_bit_string(in + x, z, data, &size)) != CRYPT_OK) {
+                  if (!ordered) { continue; }
+                  goto LBL_ERR;
+               }
+               list[i].size = size;
+               if ((err = der_length_bit_string(size, &z)) != CRYPT_OK) {
+                  goto LBL_ERR;
+               }
+               break;
+
+           case LTC_ASN1_OCTET_STRING:
+               z = inlen;
+               if ((err = der_decode_octet_string(in + x, z, data, &size)) != CRYPT_OK) {
+                  if (!ordered) { continue; }
+                  goto LBL_ERR;
+               }
+               list[i].size = size;
+               if ((err = der_length_octet_string(size, &z)) != CRYPT_OK) {
+                  goto LBL_ERR;
+               }
+               break;
+
+           case LTC_ASN1_NULL:
+               if (inlen < 2 || in[x] != 0x05 || in[x+1] != 0x00) {
+                  if (!ordered) { continue; }
+                  err = CRYPT_INVALID_PACKET;
+                  goto LBL_ERR;
+               }
+               z = 2;
+               break;
+
+           case LTC_ASN1_OBJECT_IDENTIFIER:
+               z = inlen;
+               if ((err = der_decode_object_identifier(in + x, z, data, &size)) != CRYPT_OK) {
+                  if (!ordered) { continue; }
+                  goto LBL_ERR;
+               }
+               list[i].size = size;
+               if ((err = der_length_object_identifier(data, size, &z)) != CRYPT_OK) {
+                  goto LBL_ERR;
+               }
+               break;
+
+           case LTC_ASN1_TELETEX_STRING:
+               z = inlen;
+               if ((err = der_decode_teletex_string(in + x, z, data, &size)) != CRYPT_OK) {
+                  if (!ordered) { continue; }
+                  goto LBL_ERR;
+               }
+               list[i].size = size;
+               if ((err = der_length_teletex_string(data, size, &z)) != CRYPT_OK) {
+                  goto LBL_ERR;
+               }
+               break;
+
+           case LTC_ASN1_IA5_STRING:
+               z = inlen;
+               if ((err = der_decode_ia5_string(in + x, z, data, &size)) != CRYPT_OK) {
+                  if (!ordered) { continue; }
+                  goto LBL_ERR;
+               }
+               list[i].size = size;
+               if ((err = der_length_ia5_string(data, size, &z)) != CRYPT_OK) {
+                  goto LBL_ERR;
+               }
+               break;
+
+
+           case LTC_ASN1_PRINTABLE_STRING:
+               z = inlen;
+               if ((err = der_decode_printable_string(in + x, z, data, &size)) != CRYPT_OK) {
+                  if (!ordered) { continue; }
+                  goto LBL_ERR;
+               }
+               list[i].size = size;
+               if ((err = der_length_printable_string(data, size, &z)) != CRYPT_OK) {
+                  goto LBL_ERR;
+               }
+               break;
+
+           case LTC_ASN1_UTF8_STRING:
+               z = inlen;
+               if ((err = der_decode_utf8_string(in + x, z, data, &size)) != CRYPT_OK) {
+                  if (!ordered) { continue; }
+                  goto LBL_ERR;
+               }
+               list[i].size = size;
+               if ((err = der_length_utf8_string(data, size, &z)) != CRYPT_OK) {
+                  goto LBL_ERR;
+               }
+               break;
+
+           case LTC_ASN1_UTCTIME:
+               z = inlen;
+               if ((err = der_decode_utctime(in + x, &z, data)) != CRYPT_OK) {
+                  if (!ordered) { continue; }
+                  goto LBL_ERR;
+               }
+               break;
+
+           case LTC_ASN1_GENERALIZEDTIME:
+               z = inlen;
+               if ((err = der_decode_generalizedtime(in + x, &z, data)) != CRYPT_OK) {
+                  if (!ordered) { continue; }
+                  goto LBL_ERR;
+               }
+               break;
+
+           case LTC_ASN1_SET:
+               z = inlen;
+               if ((err = der_decode_set(in + x, z, data, size)) != CRYPT_OK) {
+                  if (!ordered) { continue; }
+                  goto LBL_ERR;
+               }
+               if ((err = der_length_sequence(data, size, &z)) != CRYPT_OK) {
+                  goto LBL_ERR;
+               }
+               break;
+
+           case LTC_ASN1_SETOF:
+           case LTC_ASN1_SEQUENCE:
+               /* detect if we have the right type */
+               if ((type == LTC_ASN1_SETOF && (in[x] & 0x3F) != 0x31) || (type == LTC_ASN1_SEQUENCE && (in[x] & 0x3F) != 0x30)) {
+                  err = CRYPT_INVALID_PACKET;
+                  goto LBL_ERR;
+               }
+
+               z = inlen;
+               if ((err = der_decode_sequence(in + x, z, data, size)) != CRYPT_OK) {
+                  if (!ordered) { continue; }
+                  goto LBL_ERR;
+               }
+               if ((err = der_length_sequence(data, size, &z)) != CRYPT_OK) {
+                  goto LBL_ERR;
+               }
+               break;
+
+
+           case LTC_ASN1_CHOICE:
+               z = inlen;
+               if ((err = der_decode_choice(in + x, &z, data, size)) != CRYPT_OK) {
+                  if (!ordered) { continue; }
+                  goto LBL_ERR;
+               }
+               break;
+
+           case LTC_ASN1_CONSTRUCTED:
+           case LTC_ASN1_CONTEXT_SPECIFIC:
+           case LTC_ASN1_EOL:
+               err = CRYPT_INVALID_ARG;
+               goto LBL_ERR;
+       }
+       x           += z;
+       inlen       -= z;
+       list[i].used = 1;
+       if (!ordered) {
+          /* restart the decoder */
+          i = -1;
+       }
+   }
+
+   for (i = 0; i < (int)outlen; i++) {
+      if (list[i].used == 0) {
+          err = CRYPT_INVALID_PACKET;
+          goto LBL_ERR;
+      }
+   }
+
+   if (inlen == 0) {
+      err = CRYPT_OK;
+   } else {
+      err = CRYPT_INPUT_TOO_LONG;
+   }
+
+LBL_ERR:
+   return err;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/pk/asn1/der/sequence/der_decode_sequence_flexi.c b/libtomcrypt/src/pk/asn1/der/sequence/der_decode_sequence_flexi.c
new file mode 100644 (file)
index 0000000..cb93e8f
--- /dev/null
@@ -0,0 +1,484 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file der_decode_sequence_flexi.c
+  ASN.1 DER, decode an array of ASN.1 types with a flexi parser, Tom St Denis
+*/
+
+#ifdef LTC_DER
+
+static unsigned long _fetch_length(const unsigned char *in, unsigned long inlen, unsigned long *data_offset)
+{
+   unsigned long x, z;
+
+   *data_offset = 0;
+
+   /* skip type and read len */
+   if (inlen < 2) {
+      return 0xFFFFFFFF;
+   }
+   ++in; ++(*data_offset);
+
+   /* read len */
+   x = *in++; ++(*data_offset);
+
+   /* <128 means literal */
+   if (x < 128) {
+      return x+*data_offset;
+   }
+   x     &= 0x7F; /* the lower 7 bits are the length of the length */
+   inlen -= 2;
+
+   /* len means len of len! */
+   if (x == 0 || x > 4 || x > inlen) {
+      return 0xFFFFFFFF;
+   }
+
+   *data_offset += x;
+   z = 0;
+   while (x--) {
+      z = (z<<8) | ((unsigned long)*in);
+      ++in;
+   }
+   return z+*data_offset;
+}
+
+static int _new_element(ltc_asn1_list **l)
+{
+   /* alloc new link */
+   if (*l == NULL) {
+      *l = XCALLOC(1, sizeof(ltc_asn1_list));
+      if (*l == NULL) {
+         return CRYPT_MEM;
+      }
+   } else {
+      (*l)->next = XCALLOC(1, sizeof(ltc_asn1_list));
+      if ((*l)->next == NULL) {
+         return CRYPT_MEM;
+      }
+      (*l)->next->prev = *l;
+      *l = (*l)->next;
+   }
+   return CRYPT_OK;
+}
+
+/**
+   ASN.1 DER Flexi(ble) decoder will decode arbitrary DER packets and create a linked list of the decoded elements.
+   @param in      The input buffer
+   @param inlen   [in/out] The length of the input buffer and on output the amount of decoded data
+   @param out     [out] A pointer to the linked list
+   @return CRYPT_OK on success.
+*/
+int der_decode_sequence_flexi(const unsigned char *in, unsigned long *inlen, ltc_asn1_list **out)
+{
+   ltc_asn1_list *l, *t;
+   unsigned long err, type, len, totlen, data_offset, len_len;
+   void          *realloc_tmp;
+
+   LTC_ARGCHK(in    != NULL);
+   LTC_ARGCHK(inlen != NULL);
+   LTC_ARGCHK(out   != NULL);
+
+   l = NULL;
+   totlen = 0;
+
+   if (*inlen == 0) {
+      /* alloc new link */
+      if ((err = _new_element(&l)) != CRYPT_OK) {
+         goto error;
+      }
+   }
+
+   /* scan the input and and get lengths and what not */
+   while (*inlen) {
+      /* read the type byte */
+      type = *in;
+
+      /* fetch length */
+      len = _fetch_length(in, *inlen, &data_offset);
+      if (len > *inlen) {
+         err = CRYPT_INVALID_PACKET;
+         goto error;
+      }
+
+      /* alloc new link */
+      if ((err = _new_element(&l)) != CRYPT_OK) {
+         goto error;
+      }
+
+      if ((type & 0x20) && (type != 0x30) && (type != 0x31)) {
+         /* constructed, use the 'used' field to store the original identifier */
+         l->used = type;
+         /* treat constructed elements like SETs */
+         type = 0x20;
+      }
+      else if ((type & 0xC0) == 0x80) {
+         /* context-specific, use the 'used' field to store the original identifier */
+         l->used = type;
+         /* context-specific elements are treated as opaque data */
+         type = 0x80;
+      }
+
+     /* now switch on type */
+      switch (type) {
+         case 0x01: /* BOOLEAN */
+            l->type = LTC_ASN1_BOOLEAN;
+            l->size = 1;
+            l->data = XCALLOC(1, sizeof(int));
+
+            if ((err = der_decode_boolean(in, *inlen, l->data)) != CRYPT_OK) {
+               goto error;
+            }
+
+            if ((err = der_length_boolean(&len)) != CRYPT_OK) {
+               goto error;
+            }
+            break;
+
+         case 0x02: /* INTEGER */
+             /* init field */
+             l->type = LTC_ASN1_INTEGER;
+             l->size = 1;
+             if ((err = mp_init(&l->data)) != CRYPT_OK) {
+                 goto error;
+             }
+
+             /* decode field */
+             if ((err = der_decode_integer(in, *inlen, l->data)) != CRYPT_OK) {
+                 goto error;
+             }
+
+             /* calc length of object */
+             if ((err = der_length_integer(l->data, &len)) != CRYPT_OK) {
+                 goto error;
+             }
+             break;
+
+         case 0x03: /* BIT */
+            /* init field */
+            l->type = LTC_ASN1_BIT_STRING;
+            l->size = len * 8; /* *8 because we store decoded bits one per char and they are encoded 8 per char.  */
+
+            if ((l->data = XCALLOC(1, l->size)) == NULL) {
+               err = CRYPT_MEM;
+               goto error;
+            }
+
+            if ((err = der_decode_bit_string(in, *inlen, l->data, &l->size)) != CRYPT_OK) {
+               goto error;
+            }
+
+            if ((err = der_length_bit_string(l->size, &len)) != CRYPT_OK) {
+               goto error;
+            }
+            break;
+
+         case 0x04: /* OCTET */
+
+            /* init field */
+            l->type = LTC_ASN1_OCTET_STRING;
+            l->size = len;
+
+            if ((l->data = XCALLOC(1, l->size)) == NULL) {
+               err = CRYPT_MEM;
+               goto error;
+            }
+
+            if ((err = der_decode_octet_string(in, *inlen, l->data, &l->size)) != CRYPT_OK) {
+               goto error;
+            }
+
+            if ((err = der_length_octet_string(l->size, &len)) != CRYPT_OK) {
+               goto error;
+            }
+            break;
+
+         case 0x05: /* NULL */
+
+            /* valid NULL is 0x05 0x00 */
+            if (in[0] != 0x05 || in[1] != 0x00) {
+               err = CRYPT_INVALID_PACKET;
+               goto error;
+            }
+
+            /* simple to store ;-) */
+            l->type = LTC_ASN1_NULL;
+            l->data = NULL;
+            l->size = 0;
+            len     = 2;
+
+            break;
+
+         case 0x06: /* OID */
+
+            /* init field */
+            l->type = LTC_ASN1_OBJECT_IDENTIFIER;
+            l->size = len;
+
+            if ((l->data = XCALLOC(len, sizeof(unsigned long))) == NULL) {
+               err = CRYPT_MEM;
+               goto error;
+            }
+
+            if ((err = der_decode_object_identifier(in, *inlen, l->data, &l->size)) != CRYPT_OK) {
+               goto error;
+            }
+
+            if ((err = der_length_object_identifier(l->data, l->size, &len)) != CRYPT_OK) {
+               goto error;
+            }
+
+            /* resize it to save a bunch of mem */
+            if ((realloc_tmp = XREALLOC(l->data, l->size * sizeof(unsigned long))) == NULL) {
+               /* out of heap but this is not an error */
+               break;
+            }
+            l->data = realloc_tmp;
+            break;
+
+         case 0x0C: /* UTF8 */
+
+            /* init field */
+            l->type = LTC_ASN1_UTF8_STRING;
+            l->size = len;
+
+            if ((l->data = XCALLOC(sizeof(wchar_t), l->size)) == NULL) {
+               err = CRYPT_MEM;
+               goto error;
+            }
+
+            if ((err = der_decode_utf8_string(in, *inlen, l->data, &l->size)) != CRYPT_OK) {
+               goto error;
+            }
+
+            if ((err = der_length_utf8_string(l->data, l->size, &len)) != CRYPT_OK) {
+               goto error;
+            }
+            break;
+
+         case 0x13: /* PRINTABLE */
+
+            /* init field */
+            l->type = LTC_ASN1_PRINTABLE_STRING;
+            l->size = len;
+
+            if ((l->data = XCALLOC(1, l->size)) == NULL) {
+               err = CRYPT_MEM;
+               goto error;
+            }
+
+            if ((err = der_decode_printable_string(in, *inlen, l->data, &l->size)) != CRYPT_OK) {
+               goto error;
+            }
+
+            if ((err = der_length_printable_string(l->data, l->size, &len)) != CRYPT_OK) {
+               goto error;
+            }
+            break;
+
+         case 0x14: /* TELETEXT */
+
+            /* init field */
+            l->type = LTC_ASN1_TELETEX_STRING;
+            l->size = len;
+
+            if ((l->data = XCALLOC(1, l->size)) == NULL) {
+               err = CRYPT_MEM;
+               goto error;
+            }
+
+            if ((err = der_decode_teletex_string(in, *inlen, l->data, &l->size)) != CRYPT_OK) {
+               goto error;
+            }
+
+            if ((err = der_length_teletex_string(l->data, l->size, &len)) != CRYPT_OK) {
+               goto error;
+            }
+            break;
+
+         case 0x16: /* IA5 */
+
+            /* init field */
+            l->type = LTC_ASN1_IA5_STRING;
+            l->size = len;
+
+            if ((l->data = XCALLOC(1, l->size)) == NULL) {
+               err = CRYPT_MEM;
+               goto error;
+            }
+
+            if ((err = der_decode_ia5_string(in, *inlen, l->data, &l->size)) != CRYPT_OK) {
+               goto error;
+            }
+
+            if ((err = der_length_ia5_string(l->data, l->size, &len)) != CRYPT_OK) {
+               goto error;
+            }
+            break;
+
+         case 0x17: /* UTC TIME */
+
+            /* init field */
+            l->type = LTC_ASN1_UTCTIME;
+            l->size = 1;
+
+            if ((l->data = XCALLOC(1, sizeof(ltc_utctime))) == NULL) {
+               err = CRYPT_MEM;
+               goto error;
+            }
+
+            len = *inlen;
+            if ((err = der_decode_utctime(in, &len, l->data)) != CRYPT_OK) {
+               goto error;
+            }
+
+            if ((err = der_length_utctime(l->data, &len)) != CRYPT_OK) {
+               goto error;
+            }
+            break;
+
+         case 0x18:
+            l->type = LTC_ASN1_GENERALIZEDTIME;
+            l->size = len;
+
+            if ((l->data = XCALLOC(1, sizeof(ltc_generalizedtime))) == NULL) {
+               err = CRYPT_MEM;
+               goto error;
+            }
+
+            if ((err = der_decode_generalizedtime(in, &len, l->data)) != CRYPT_OK) {
+               goto error;
+            }
+
+            if ((err = der_length_generalizedtime(l->data, &len)) != CRYPT_OK) {
+               goto error;
+            }
+
+            break;
+
+         case 0x20: /* Any CONSTRUCTED element that is neither SEQUENCE nor SET */
+         case 0x30: /* SEQUENCE */
+         case 0x31: /* SET */
+
+             /* init field */
+             if (type == 0x20) {
+                l->type = LTC_ASN1_CONSTRUCTED;
+             }
+             else if (type == 0x30) {
+                l->type = LTC_ASN1_SEQUENCE;
+             }
+             else {
+                l->type = LTC_ASN1_SET;
+             }
+
+             if ((l->data = XMALLOC(len)) == NULL) {
+                err = CRYPT_MEM;
+                goto error;
+             }
+
+             XMEMCPY(l->data, in, len);
+             l->size = len;
+
+
+             /* jump to the start of the data */
+             in     += data_offset;
+             *inlen -= data_offset;
+             len = len - data_offset;
+
+             /* Sequence elements go as child */
+             if ((err = der_decode_sequence_flexi(in, &len, &(l->child))) != CRYPT_OK) {
+                goto error;
+             }
+
+             /* len update */
+             totlen += data_offset;
+
+             /* the flexi decoder can also do nothing, so make sure a child has been allocated */
+             if (l->child) {
+                /* link them up y0 */
+                l->child->parent = l;
+             }
+
+             t = l;
+             len_len = 0;
+             while((t != NULL) && (t->child != NULL)) {
+                len_len++;
+                t = t->child;
+             }
+             if (len_len > LTC_DER_MAX_RECURSION) {
+                err = CRYPT_ERROR;
+                goto error;
+             }
+
+             break;
+
+         case 0x80: /* Context-specific */
+             l->type = LTC_ASN1_CONTEXT_SPECIFIC;
+
+             if ((l->data = XCALLOC(1, len - data_offset)) == NULL) {
+                err = CRYPT_MEM;
+                goto error;
+             }
+
+             XMEMCPY(l->data, in + data_offset, len - data_offset);
+             l->size = len - data_offset;
+
+             break;
+
+         default:
+           /* invalid byte ... this is a soft error */
+           /* remove link */
+           if (l->prev) {
+              l       = l->prev;
+              XFREE(l->next);
+              l->next = NULL;
+           }
+           goto outside;
+      }
+
+      /* advance pointers */
+      totlen  += len;
+      in      += len;
+      *inlen  -= len;
+   }
+
+outside:
+
+   /* in case we processed anything */
+   if (totlen) {
+      /* rewind l please */
+      while (l->prev != NULL || l->parent != NULL) {
+         if (l->parent != NULL) {
+            l = l->parent;
+         } else {
+            l = l->prev;
+         }
+      }
+   }
+
+   /* return */
+   *out   = l;
+   *inlen = totlen;
+   return CRYPT_OK;
+
+error:
+   /* free list */
+   der_sequence_free(l);
+
+   return err;
+}
+
+#endif
+
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/pk/asn1/der/sequence/der_decode_sequence_multi.c b/libtomcrypt/src/pk/asn1/der/sequence/der_decode_sequence_multi.c
new file mode 100644 (file)
index 0000000..1361b76
--- /dev/null
@@ -0,0 +1,145 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+#include <stdarg.h>
+
+
+/**
+  @file der_decode_sequence_multi.c
+  ASN.1 DER, decode a SEQUENCE, Tom St Denis
+*/
+
+#ifdef LTC_DER
+
+/**
+  Decode a SEQUENCE type using a VA list
+  @param in    Input buffer
+  @param inlen Length of input in octets
+  @remark <...> is of the form <type, size, data> (int, unsigned long, void*)
+  @return CRYPT_OK on success
+*/
+int der_decode_sequence_multi(const unsigned char *in, unsigned long inlen, ...)
+{
+   int           err;
+   ltc_asn1_type type;
+   unsigned long size, x;
+   void          *data;
+   va_list       args;
+   ltc_asn1_list *list;
+
+   LTC_ARGCHK(in    != NULL);
+
+   /* get size of output that will be required */
+   va_start(args, inlen);
+   x = 0;
+   for (;;) {
+       type = (ltc_asn1_type)va_arg(args, int);
+       size = va_arg(args, unsigned long);
+       data = va_arg(args, void*);
+       LTC_UNUSED_PARAM(size);
+       LTC_UNUSED_PARAM(data);
+
+       if (type == LTC_ASN1_EOL) {
+          break;
+       }
+
+       switch (type) {
+           case LTC_ASN1_BOOLEAN:
+           case LTC_ASN1_INTEGER:
+           case LTC_ASN1_SHORT_INTEGER:
+           case LTC_ASN1_BIT_STRING:
+           case LTC_ASN1_OCTET_STRING:
+           case LTC_ASN1_NULL:
+           case LTC_ASN1_OBJECT_IDENTIFIER:
+           case LTC_ASN1_IA5_STRING:
+           case LTC_ASN1_PRINTABLE_STRING:
+           case LTC_ASN1_UTF8_STRING:
+           case LTC_ASN1_UTCTIME:
+           case LTC_ASN1_SET:
+           case LTC_ASN1_SETOF:
+           case LTC_ASN1_SEQUENCE:
+           case LTC_ASN1_CHOICE:
+           case LTC_ASN1_RAW_BIT_STRING:
+           case LTC_ASN1_TELETEX_STRING:
+           case LTC_ASN1_GENERALIZEDTIME:
+                ++x;
+                break;
+
+           case LTC_ASN1_EOL:
+           case LTC_ASN1_CONSTRUCTED:
+           case LTC_ASN1_CONTEXT_SPECIFIC:
+               va_end(args);
+               return CRYPT_INVALID_ARG;
+       }
+   }
+   va_end(args);
+
+   /* allocate structure for x elements */
+   if (x == 0) {
+      return CRYPT_NOP;
+   }
+
+   list = XCALLOC(sizeof(*list), x);
+   if (list == NULL) {
+      return CRYPT_MEM;
+   }
+
+   /* fill in the structure */
+   va_start(args, inlen);
+   x = 0;
+   for (;;) {
+       type = (ltc_asn1_type)va_arg(args, int);
+       size = va_arg(args, unsigned long);
+       data = va_arg(args, void*);
+
+       if (type == LTC_ASN1_EOL) {
+          break;
+       }
+
+       switch (type) {
+           case LTC_ASN1_BOOLEAN:
+           case LTC_ASN1_INTEGER:
+           case LTC_ASN1_SHORT_INTEGER:
+           case LTC_ASN1_BIT_STRING:
+           case LTC_ASN1_OCTET_STRING:
+           case LTC_ASN1_NULL:
+           case LTC_ASN1_OBJECT_IDENTIFIER:
+           case LTC_ASN1_IA5_STRING:
+           case LTC_ASN1_PRINTABLE_STRING:
+           case LTC_ASN1_UTF8_STRING:
+           case LTC_ASN1_UTCTIME:
+           case LTC_ASN1_SEQUENCE:
+           case LTC_ASN1_SET:
+           case LTC_ASN1_SETOF:
+           case LTC_ASN1_CHOICE:
+           case LTC_ASN1_RAW_BIT_STRING:
+           case LTC_ASN1_TELETEX_STRING:
+           case LTC_ASN1_GENERALIZEDTIME:
+                LTC_SET_ASN1(list, x++, type, data, size);
+                break;
+           /* coverity[dead_error_line] */
+           case LTC_ASN1_EOL:
+           case LTC_ASN1_CONSTRUCTED:
+           case LTC_ASN1_CONTEXT_SPECIFIC:
+                break;
+       }
+   }
+   va_end(args);
+
+   err = der_decode_sequence(in, inlen, list, x);
+   XFREE(list);
+   return err;
+}
+
+#endif
+
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/pk/asn1/der/sequence/der_decode_subject_public_key_info.c b/libtomcrypt/src/pk/asn1/der/sequence/der_decode_subject_public_key_info.c
new file mode 100644 (file)
index 0000000..d2d0811
--- /dev/null
@@ -0,0 +1,112 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+/**
+  @file der_decode_subject_public_key_info.c
+  ASN.1 DER, encode a Subject Public Key structure --nmav
+*/
+
+#ifdef LTC_DER
+
+/* AlgorithmIdentifier := SEQUENCE {
+ *    algorithm OBJECT IDENTIFIER,
+ *    parameters ANY DEFINED BY algorithm
+ * }
+ *
+ * SubjectPublicKeyInfo := SEQUENCE {
+ *    algorithm AlgorithmIdentifier,
+ *    subjectPublicKey BIT STRING
+ * }
+ */
+/**
+  Decode a subject public key info
+   @param in      The input buffer
+   @param inlen   The length of the input buffer
+   @param algorithm             One out of the enum #public_key_algorithms
+   @param public_key            The buffer for the public key
+   @param public_key_len        [in/out] The length of the public key buffer and the written length
+   @param parameters_type       The parameters' type out of the enum ltc_asn1_type
+   @param parameters            The parameters to include
+   @param parameters_len        The number of parameters to include
+   @return CRYPT_OK on success
+*/
+int der_decode_subject_public_key_info(const unsigned char *in, unsigned long inlen,
+        unsigned int algorithm, void* public_key, unsigned long* public_key_len,
+        unsigned long parameters_type, ltc_asn1_list* parameters, unsigned long parameters_len)
+{
+   int err;
+   unsigned long len;
+   oid_st oid;
+   unsigned char *tmpbuf;
+   unsigned long  tmpoid[16];
+   ltc_asn1_list alg_id[2];
+   ltc_asn1_list subject_pubkey[2];
+
+   LTC_ARGCHK(in    != NULL);
+   LTC_ARGCHK(inlen != 0);
+   LTC_ARGCHK(public_key_len != NULL);
+
+   err = pk_get_oid(algorithm, &oid);
+   if (err != CRYPT_OK) {
+        return err;
+   }
+
+   /* see if the OpenSSL DER format RSA public key will work */
+   tmpbuf = XCALLOC(1, inlen);
+   if (tmpbuf == NULL) {
+       err = CRYPT_MEM;
+       goto LBL_ERR;
+   }
+
+   /* this includes the internal hash ID and optional params (NULL in this case) */
+   LTC_SET_ASN1(alg_id, 0, LTC_ASN1_OBJECT_IDENTIFIER, tmpoid, sizeof(tmpoid)/sizeof(tmpoid[0]));
+   LTC_SET_ASN1(alg_id, 1, (ltc_asn1_type)parameters_type, parameters, parameters_len);
+
+   /* the actual format of the SSL DER key is odd, it stores a RSAPublicKey
+    * in a **BIT** string ... so we have to extract it then proceed to convert bit to octet
+    */
+   LTC_SET_ASN1(subject_pubkey, 0, LTC_ASN1_SEQUENCE, alg_id, 2);
+   LTC_SET_ASN1(subject_pubkey, 1, LTC_ASN1_RAW_BIT_STRING, tmpbuf, inlen*8U);
+
+   err=der_decode_sequence(in, inlen, subject_pubkey, 2UL);
+   if (err != CRYPT_OK) {
+           goto LBL_ERR;
+   }
+
+   if ((alg_id[0].size != oid.OIDlen) ||
+        XMEMCMP(oid.OID, alg_id[0].data, oid.OIDlen * sizeof(oid.OID[0])) != 0) {
+        /* OID mismatch */
+        err = CRYPT_PK_INVALID_TYPE;
+        goto LBL_ERR;
+   }
+
+   len = subject_pubkey[1].size/8;
+   if (*public_key_len > len) {
+       XMEMCPY(public_key, subject_pubkey[1].data, len);
+       *public_key_len = len;
+    } else {
+        *public_key_len = len;
+        err = CRYPT_BUFFER_OVERFLOW;
+        goto LBL_ERR;
+    }
+
+    err = CRYPT_OK;
+
+LBL_ERR:
+
+    XFREE(tmpbuf);
+
+    return err;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/pk/asn1/der/sequence/der_encode_sequence_ex.c b/libtomcrypt/src/pk/asn1/der/sequence/der_encode_sequence_ex.c
new file mode 100644 (file)
index 0000000..2b42ff4
--- /dev/null
@@ -0,0 +1,217 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+
+/**
+  @file der_encode_sequence_ex.c
+  ASN.1 DER, encode a SEQUENCE, Tom St Denis
+*/
+
+#ifdef LTC_DER
+
+/**
+   Encode a SEQUENCE
+   @param list      The list of items to encode
+   @param inlen     The number of items in the list
+   @param out       [out] The destination
+   @param outlen    [in/out] The size of the output
+   @param type_of   LTC_ASN1_SEQUENCE or LTC_ASN1_SET/LTC_ASN1_SETOF
+   @return CRYPT_OK on success
+*/
+int der_encode_sequence_ex(ltc_asn1_list *list, unsigned long inlen,
+                           unsigned char *out,  unsigned long *outlen, int type_of)
+{
+   int           err;
+   ltc_asn1_type type;
+   unsigned long size, x, y, z, i;
+   void          *data;
+
+   LTC_ARGCHK(list    != NULL);
+   LTC_ARGCHK(out     != NULL);
+   LTC_ARGCHK(outlen  != NULL);
+
+   /* get size of output that will be required */
+   y = 0; z = 0;
+   if ((err = der_length_sequence_ex(list, inlen, &y, &z)) != CRYPT_OK) return CRYPT_INVALID_ARG;
+
+   /* too big ? */
+   if (*outlen < y) {
+      *outlen = y;
+      err = CRYPT_BUFFER_OVERFLOW;
+      goto LBL_ERR;
+   }
+
+   /* store header */
+   x = 0;
+   out[x++] = (type_of == LTC_ASN1_SEQUENCE) ? 0x30 : 0x31;
+
+   if (z < 128) {
+      out[x++] = (unsigned char)z;
+   } else if (z < 256) {
+      out[x++] = 0x81;
+      out[x++] = (unsigned char)z;
+   } else if (z < 65536UL) {
+      out[x++] = 0x82;
+      out[x++] = (unsigned char)((z>>8UL)&255);
+      out[x++] = (unsigned char)(z&255);
+   } else if (z < 16777216UL) {
+      out[x++] = 0x83;
+      out[x++] = (unsigned char)((z>>16UL)&255);
+      out[x++] = (unsigned char)((z>>8UL)&255);
+      out[x++] = (unsigned char)(z&255);
+   }
+
+   /* store data */
+   *outlen -= x;
+   for (i = 0; i < inlen; i++) {
+       type = list[i].type;
+       size = list[i].size;
+       data = list[i].data;
+
+       if (type == LTC_ASN1_EOL) {
+          break;
+       }
+
+       switch (type) {
+            case LTC_ASN1_BOOLEAN:
+               z = *outlen;
+               if ((err = der_encode_boolean(*((int *)data), out + x, &z)) != CRYPT_OK) {
+                  goto LBL_ERR;
+               }
+               break;
+
+           case LTC_ASN1_INTEGER:
+               z = *outlen;
+               if ((err = der_encode_integer(data, out + x, &z)) != CRYPT_OK) {
+                  goto LBL_ERR;
+               }
+               break;
+
+           case LTC_ASN1_SHORT_INTEGER:
+               z = *outlen;
+               if ((err = der_encode_short_integer(*((unsigned long*)data), out + x, &z)) != CRYPT_OK) {
+                  goto LBL_ERR;
+               }
+               break;
+
+           case LTC_ASN1_BIT_STRING:
+               z = *outlen;
+               if ((err = der_encode_bit_string(data, size, out + x, &z)) != CRYPT_OK) {
+                  goto LBL_ERR;
+               }
+               break;
+
+           case LTC_ASN1_RAW_BIT_STRING:
+               z = *outlen;
+               if ((err = der_encode_raw_bit_string(data, size, out + x, &z)) != CRYPT_OK) {
+                  goto LBL_ERR;
+               }
+               break;
+
+           case LTC_ASN1_OCTET_STRING:
+               z = *outlen;
+               if ((err = der_encode_octet_string(data, size, out + x, &z)) != CRYPT_OK) {
+                  goto LBL_ERR;
+               }
+               break;
+
+           case LTC_ASN1_NULL:
+               out[x] = 0x05;
+               out[x+1] = 0x00;
+               z = 2;
+               break;
+
+           case LTC_ASN1_OBJECT_IDENTIFIER:
+               z = *outlen;
+               if ((err = der_encode_object_identifier(data, size, out + x, &z)) != CRYPT_OK) {
+                  goto LBL_ERR;
+               }
+               break;
+
+           case LTC_ASN1_IA5_STRING:
+               z = *outlen;
+               if ((err = der_encode_ia5_string(data, size, out + x, &z)) != CRYPT_OK) {
+                  goto LBL_ERR;
+               }
+               break;
+
+           case LTC_ASN1_PRINTABLE_STRING:
+               z = *outlen;
+               if ((err = der_encode_printable_string(data, size, out + x, &z)) != CRYPT_OK) {
+                  goto LBL_ERR;
+               }
+               break;
+
+           case LTC_ASN1_UTF8_STRING:
+               z = *outlen;
+               if ((err = der_encode_utf8_string(data, size, out + x, &z)) != CRYPT_OK) {
+                  goto LBL_ERR;
+               }
+               break;
+
+           case LTC_ASN1_UTCTIME:
+               z = *outlen;
+               if ((err = der_encode_utctime(data, out + x, &z)) != CRYPT_OK) {
+                  goto LBL_ERR;
+               }
+               break;
+
+           case LTC_ASN1_GENERALIZEDTIME:
+               z = *outlen;
+               if ((err = der_encode_generalizedtime(data, out + x, &z)) != CRYPT_OK) {
+                  goto LBL_ERR;
+               }
+               break;
+
+           case LTC_ASN1_SET:
+               z = *outlen;
+               if ((err = der_encode_set(data, size, out + x, &z)) != CRYPT_OK) {
+                  goto LBL_ERR;
+               }
+               break;
+
+           case LTC_ASN1_SETOF:
+               z = *outlen;
+               if ((err = der_encode_setof(data, size, out + x, &z)) != CRYPT_OK) {
+                  goto LBL_ERR;
+               }
+               break;
+
+           case LTC_ASN1_SEQUENCE:
+               z = *outlen;
+               if ((err = der_encode_sequence_ex(data, size, out + x, &z, type)) != CRYPT_OK) {
+                  goto LBL_ERR;
+               }
+               break;
+
+           case LTC_ASN1_CHOICE:
+           case LTC_ASN1_CONSTRUCTED:
+           case LTC_ASN1_CONTEXT_SPECIFIC:
+           case LTC_ASN1_EOL:
+           case LTC_ASN1_TELETEX_STRING:
+               err = CRYPT_INVALID_ARG;
+               goto LBL_ERR;
+       }
+
+       x       += z;
+       *outlen -= z;
+   }
+   *outlen = x;
+   err = CRYPT_OK;
+
+LBL_ERR:
+   return err;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/pk/asn1/der/sequence/der_encode_sequence_multi.c b/libtomcrypt/src/pk/asn1/der/sequence/der_encode_sequence_multi.c
new file mode 100644 (file)
index 0000000..c1b40c7
--- /dev/null
@@ -0,0 +1,149 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+#include <stdarg.h>
+
+
+/**
+  @file der_encode_sequence_multi.c
+  ASN.1 DER, encode a SEQUENCE, Tom St Denis
+*/
+
+#ifdef LTC_DER
+
+/**
+  Encode a SEQUENCE type using a VA list
+  @param out    [out] Destination for data
+  @param outlen [in/out] Length of buffer and resulting length of output
+  @remark <...> is of the form <type, size, data> (int, unsigned long, void*)
+  @return CRYPT_OK on success
+*/
+int der_encode_sequence_multi(unsigned char *out, unsigned long *outlen, ...)
+{
+   int           err;
+   ltc_asn1_type type;
+   unsigned long size, x;
+   void          *data;
+   va_list       args;
+   ltc_asn1_list *list;
+
+   LTC_ARGCHK(out    != NULL);
+   LTC_ARGCHK(outlen != NULL);
+
+   /* get size of output that will be required */
+   va_start(args, outlen);
+   x = 0;
+   for (;;) {
+       type = (ltc_asn1_type)va_arg(args, int);
+       size = va_arg(args, unsigned long);
+       data = va_arg(args, void*);
+       LTC_UNUSED_PARAM(size);
+       LTC_UNUSED_PARAM(data);
+
+       if (type == LTC_ASN1_EOL) {
+          break;
+       }
+
+       switch (type) {
+           case LTC_ASN1_BOOLEAN:
+           case LTC_ASN1_INTEGER:
+           case LTC_ASN1_SHORT_INTEGER:
+           case LTC_ASN1_BIT_STRING:
+           case LTC_ASN1_OCTET_STRING:
+           case LTC_ASN1_NULL:
+           case LTC_ASN1_OBJECT_IDENTIFIER:
+           case LTC_ASN1_IA5_STRING:
+           case LTC_ASN1_PRINTABLE_STRING:
+           case LTC_ASN1_UTF8_STRING:
+           case LTC_ASN1_UTCTIME:
+           case LTC_ASN1_SEQUENCE:
+           case LTC_ASN1_SET:
+           case LTC_ASN1_SETOF:
+           case LTC_ASN1_RAW_BIT_STRING:
+           case LTC_ASN1_GENERALIZEDTIME:
+                ++x;
+                break;
+
+           case LTC_ASN1_CHOICE:
+           case LTC_ASN1_CONSTRUCTED:
+           case LTC_ASN1_CONTEXT_SPECIFIC:
+           case LTC_ASN1_EOL:
+           case LTC_ASN1_TELETEX_STRING:
+               va_end(args);
+               return CRYPT_INVALID_ARG;
+       }
+   }
+   va_end(args);
+
+   /* allocate structure for x elements */
+   if (x == 0) {
+      return CRYPT_NOP;
+   }
+
+   list = XCALLOC(sizeof(*list), x);
+   if (list == NULL) {
+      return CRYPT_MEM;
+   }
+
+   /* fill in the structure */
+   va_start(args, outlen);
+   x = 0;
+   for (;;) {
+       type = (ltc_asn1_type)va_arg(args, int);
+       size = va_arg(args, unsigned long);
+       data = va_arg(args, void*);
+
+       if (type == LTC_ASN1_EOL) {
+          break;
+       }
+
+       switch (type) {
+           case LTC_ASN1_BOOLEAN:
+           case LTC_ASN1_INTEGER:
+           case LTC_ASN1_SHORT_INTEGER:
+           case LTC_ASN1_BIT_STRING:
+           case LTC_ASN1_OCTET_STRING:
+           case LTC_ASN1_NULL:
+           case LTC_ASN1_OBJECT_IDENTIFIER:
+           case LTC_ASN1_IA5_STRING:
+           case LTC_ASN1_PRINTABLE_STRING:
+           case LTC_ASN1_UTF8_STRING:
+           case LTC_ASN1_UTCTIME:
+           case LTC_ASN1_SEQUENCE:
+           case LTC_ASN1_SET:
+           case LTC_ASN1_SETOF:
+           case LTC_ASN1_RAW_BIT_STRING:
+           case LTC_ASN1_GENERALIZEDTIME:
+                LTC_SET_ASN1(list, x++, type, data, size);
+                break;
+
+           case LTC_ASN1_CHOICE:
+           case LTC_ASN1_CONSTRUCTED:
+           case LTC_ASN1_CONTEXT_SPECIFIC:
+           case LTC_ASN1_EOL:
+           case LTC_ASN1_TELETEX_STRING:
+               va_end(args);
+               err = CRYPT_INVALID_ARG;
+               goto LBL_ERR;
+       }
+   }
+   va_end(args);
+
+   err = der_encode_sequence(list, x, out, outlen);
+LBL_ERR:
+   XFREE(list);
+   return err;
+}
+
+#endif
+
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/pk/asn1/der/sequence/der_encode_subject_public_key_info.c b/libtomcrypt/src/pk/asn1/der/sequence/der_encode_subject_public_key_info.c
new file mode 100644 (file)
index 0000000..dcb869a
--- /dev/null
@@ -0,0 +1,71 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file der_encode_subject_public_key_info.c
+  ASN.1 DER, encode a Subject Public Key structure --nmav
+*/
+
+#ifdef LTC_DER
+
+/* AlgorithmIdentifier := SEQUENCE {
+ *    algorithm OBJECT IDENTIFIER,
+ *    parameters ANY DEFINED BY algorithm
+ * }
+ *
+ * SubjectPublicKeyInfo := SEQUENCE {
+ *    algorithm AlgorithmIdentifier,
+ *    subjectPublicKey BIT STRING
+ * }
+ */
+/**
+  Encode a subject public key info
+   @param out           The output buffer
+   @param outlen        [in/out] Length of buffer and resulting length of output
+   @param algorithm             One out of the enum #public_key_algorithms
+   @param public_key            The buffer for the public key
+   @param public_key_len        The length of the public key buffer
+   @param parameters_type       The parameters' type out of the enum ltc_asn1_type
+   @param parameters            The parameters to include
+   @param parameters_len        The number of parameters to include
+   @return CRYPT_OK on success
+*/
+int der_encode_subject_public_key_info(unsigned char *out, unsigned long *outlen,
+        unsigned int algorithm, void* public_key, unsigned long public_key_len,
+        unsigned long parameters_type, void* parameters, unsigned long parameters_len)
+{
+   int           err;
+   ltc_asn1_list alg_id[2];
+   oid_st oid;
+
+   LTC_ARGCHK(out    != NULL);
+   LTC_ARGCHK(outlen != NULL);
+
+   err = pk_get_oid(algorithm, &oid);
+   if (err != CRYPT_OK) {
+        return err;
+   }
+
+   LTC_SET_ASN1(alg_id, 0, LTC_ASN1_OBJECT_IDENTIFIER, oid.OID,    oid.OIDlen);
+   LTC_SET_ASN1(alg_id, 1, (ltc_asn1_type)parameters_type,            parameters, parameters_len);
+
+   return der_encode_sequence_multi(out, outlen,
+        LTC_ASN1_SEQUENCE, (unsigned long)sizeof(alg_id)/sizeof(alg_id[0]), alg_id,
+        LTC_ASN1_RAW_BIT_STRING, public_key_len*8U, public_key,
+        LTC_ASN1_EOL,     0UL, NULL);
+
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
+
diff --git a/libtomcrypt/src/pk/asn1/der/sequence/der_length_sequence.c b/libtomcrypt/src/pk/asn1/der/sequence/der_length_sequence.c
new file mode 100644 (file)
index 0000000..aed7cc2
--- /dev/null
@@ -0,0 +1,193 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file der_length_sequence.c
+  ASN.1 DER, length a SEQUENCE, Tom St Denis
+*/
+
+#ifdef LTC_DER
+
+/**
+   Get the length of a DER sequence
+   @param list   The sequences of items in the SEQUENCE
+   @param inlen  The number of items
+   @param outlen [out] The length required in octets to store it
+   @return CRYPT_OK on success
+*/
+int der_length_sequence(ltc_asn1_list *list, unsigned long inlen,
+                        unsigned long *outlen)
+{
+   return der_length_sequence_ex(list, inlen, outlen, NULL);
+}
+
+int der_length_sequence_ex(ltc_asn1_list *list, unsigned long inlen,
+                           unsigned long *outlen, unsigned long *payloadlen)
+{
+   int           err;
+   ltc_asn1_type type;
+   unsigned long size, x, y, i, z;
+   void          *data;
+
+   LTC_ARGCHK(list    != NULL);
+   LTC_ARGCHK(outlen  != NULL);
+
+   /* get size of output that will be required */
+   y = 0;
+   for (i = 0; i < inlen; i++) {
+       type = list[i].type;
+       size = list[i].size;
+       data = list[i].data;
+
+       if (type == LTC_ASN1_EOL) {
+          break;
+       }
+
+       switch (type) {
+           case LTC_ASN1_BOOLEAN:
+              if ((err = der_length_boolean(&x)) != CRYPT_OK) {
+                 goto LBL_ERR;
+              }
+              y += x;
+              break;
+
+           case LTC_ASN1_INTEGER:
+               if ((err = der_length_integer(data, &x)) != CRYPT_OK) {
+                  goto LBL_ERR;
+               }
+               y += x;
+               break;
+
+           case LTC_ASN1_SHORT_INTEGER:
+               if ((err = der_length_short_integer(*((unsigned long *)data), &x)) != CRYPT_OK) {
+                  goto LBL_ERR;
+               }
+               y += x;
+               break;
+
+           case LTC_ASN1_BIT_STRING:
+           case LTC_ASN1_RAW_BIT_STRING:
+               if ((err = der_length_bit_string(size, &x)) != CRYPT_OK) {
+                  goto LBL_ERR;
+               }
+               y += x;
+               break;
+
+           case LTC_ASN1_OCTET_STRING:
+               if ((err = der_length_octet_string(size, &x)) != CRYPT_OK) {
+                  goto LBL_ERR;
+               }
+               y += x;
+               break;
+
+           case LTC_ASN1_NULL:
+               y += 2;
+               break;
+
+           case LTC_ASN1_OBJECT_IDENTIFIER:
+               if ((err = der_length_object_identifier(data, size, &x)) != CRYPT_OK) {
+                  goto LBL_ERR;
+               }
+               y += x;
+               break;
+
+           case LTC_ASN1_IA5_STRING:
+               if ((err = der_length_ia5_string(data, size, &x)) != CRYPT_OK) {
+                  goto LBL_ERR;
+               }
+               y += x;
+               break;
+
+           case LTC_ASN1_TELETEX_STRING:
+               if ((err = der_length_teletex_string(data, size, &x)) != CRYPT_OK) {
+                  goto LBL_ERR;
+               }
+               y += x;
+               break;
+
+           case LTC_ASN1_PRINTABLE_STRING:
+               if ((err = der_length_printable_string(data, size, &x)) != CRYPT_OK) {
+                  goto LBL_ERR;
+               }
+               y += x;
+               break;
+
+           case LTC_ASN1_UTCTIME:
+               if ((err = der_length_utctime(data, &x)) != CRYPT_OK) {
+                  goto LBL_ERR;
+               }
+               y += x;
+               break;
+
+           case LTC_ASN1_GENERALIZEDTIME:
+               if ((err = der_length_generalizedtime(data, &x)) != CRYPT_OK) {
+                  goto LBL_ERR;
+               }
+               y += x;
+               break;
+
+           case LTC_ASN1_UTF8_STRING:
+               if ((err = der_length_utf8_string(data, size, &x)) != CRYPT_OK) {
+                  goto LBL_ERR;
+               }
+               y += x;
+               break;
+
+           case LTC_ASN1_SET:
+           case LTC_ASN1_SETOF:
+           case LTC_ASN1_SEQUENCE:
+               if ((err = der_length_sequence(data, size, &x)) != CRYPT_OK) {
+                  goto LBL_ERR;
+               }
+               y += x;
+               break;
+
+
+           case LTC_ASN1_CHOICE:
+           case LTC_ASN1_CONSTRUCTED:
+           case LTC_ASN1_CONTEXT_SPECIFIC:
+           case LTC_ASN1_EOL:
+               err = CRYPT_INVALID_ARG;
+               goto LBL_ERR;
+       }
+   }
+
+   /* calc header size */
+   z = y;
+   if (y < 128) {
+      y += 2;
+   } else if (y < 256) {
+      /* 0x30 0x81 LL */
+      y += 3;
+   } else if (y < 65536UL) {
+      /* 0x30 0x82 LL LL */
+      y += 4;
+   } else if (y < 16777216UL) {
+      /* 0x30 0x83 LL LL LL */
+      y += 5;
+   } else {
+      err = CRYPT_INVALID_ARG;
+      goto LBL_ERR;
+   }
+
+   /* store size */
+   if (payloadlen) *payloadlen = z;
+   *outlen = y;
+   err     = CRYPT_OK;
+
+LBL_ERR:
+   return err;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/pk/asn1/der/sequence/der_sequence_free.c b/libtomcrypt/src/pk/asn1/der/sequence/der_sequence_free.c
new file mode 100644 (file)
index 0000000..3c2a663
--- /dev/null
@@ -0,0 +1,63 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file der_sequence_free.c
+  ASN.1 DER, free's a structure allocated by der_decode_sequence_flexi(), Tom St Denis
+*/
+
+#ifdef LTC_DER
+
+/**
+  Free memory allocated by der_decode_sequence_flexi()
+  @param in     The list to free
+*/
+void der_sequence_free(ltc_asn1_list *in)
+{
+   ltc_asn1_list *l;
+
+   if (!in) return;
+
+   /* walk to the start of the chain */
+   while (in->prev != NULL || in->parent != NULL) {
+      if (in->parent != NULL) {
+          in = in->parent;
+      } else {
+          in = in->prev;
+      }
+   }
+
+   /* now walk the list and free stuff */
+   while (in != NULL) {
+      /* is there a child? */
+      if (in->child) {
+         /* disconnect */
+         in->child->parent = NULL;
+         der_sequence_free(in->child);
+      }
+
+      switch (in->type) {
+         case LTC_ASN1_SETOF: break;
+         case LTC_ASN1_INTEGER : if (in->data != NULL) { mp_clear(in->data); } break;
+         default               : if (in->data != NULL) { XFREE(in->data);    }
+      }
+
+      /* move to next and free current */
+      l = in->next;
+      XFREE(in);
+      in = l;
+   }
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/pk/asn1/der/sequence/der_sequence_shrink.c b/libtomcrypt/src/pk/asn1/der/sequence/der_sequence_shrink.c
new file mode 100644 (file)
index 0000000..9b9e036
--- /dev/null
@@ -0,0 +1,50 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file der_sequence_shrink.c
+  Free memory allocated for CONSTRUCTED, SET or SEQUENCE elements by der_decode_sequence_flexi(), Steffen Jaeckel
+*/
+
+#ifdef LTC_DER
+
+/**
+  Free memory allocated for CONSTRUCTED,
+  SET or SEQUENCE elements by der_decode_sequence_flexi()
+  @param in     The list to shrink
+*/
+void der_sequence_shrink(ltc_asn1_list *in)
+{
+   if (!in) return;
+
+   /* now walk the list and free stuff */
+   while (in != NULL) {
+      /* is there a child? */
+      if (in->child) {
+         der_sequence_shrink(in->child);
+      }
+
+      switch (in->type) {
+         case LTC_ASN1_CONSTRUCTED:
+         case LTC_ASN1_SET:
+         case LTC_ASN1_SEQUENCE : if (in->data != NULL) { XFREE(in->data); in->data = NULL; } break;
+         default: break;
+      }
+
+      /* move to next and free current */
+      in = in->next;
+   }
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/pk/asn1/der/set/der_encode_set.c b/libtomcrypt/src/pk/asn1/der/set/der_encode_set.c
new file mode 100644 (file)
index 0000000..fef3092
--- /dev/null
@@ -0,0 +1,108 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file der_encode_set.c
+  ASN.1 DER, Encode a SET, Tom St Denis
+*/
+
+#ifdef LTC_DER
+
+/* LTC define to ASN.1 TAG */
+static int _ltc_to_asn1(ltc_asn1_type v)
+{
+   switch (v) {
+      case LTC_ASN1_BOOLEAN:                 return 0x01;
+      case LTC_ASN1_INTEGER:
+      case LTC_ASN1_SHORT_INTEGER:           return 0x02;
+      case LTC_ASN1_RAW_BIT_STRING:
+      case LTC_ASN1_BIT_STRING:              return 0x03;
+      case LTC_ASN1_OCTET_STRING:            return 0x04;
+      case LTC_ASN1_NULL:                    return 0x05;
+      case LTC_ASN1_OBJECT_IDENTIFIER:       return 0x06;
+      case LTC_ASN1_UTF8_STRING:             return 0x0C;
+      case LTC_ASN1_PRINTABLE_STRING:        return 0x13;
+      case LTC_ASN1_TELETEX_STRING:          return 0x14;
+      case LTC_ASN1_IA5_STRING:              return 0x16;
+      case LTC_ASN1_UTCTIME:                 return 0x17;
+      case LTC_ASN1_GENERALIZEDTIME:         return 0x18;
+      case LTC_ASN1_SEQUENCE:                return 0x30;
+      case LTC_ASN1_SET:
+      case LTC_ASN1_SETOF:                   return 0x31;
+      case LTC_ASN1_CHOICE:
+      case LTC_ASN1_CONSTRUCTED:
+      case LTC_ASN1_CONTEXT_SPECIFIC:
+      case LTC_ASN1_EOL:                     return -1;
+   }
+   return -1;
+}
+
+
+static int _qsort_helper(const void *a, const void *b)
+{
+   ltc_asn1_list *A = (ltc_asn1_list *)a, *B = (ltc_asn1_list *)b;
+   int            r;
+
+   r = _ltc_to_asn1(A->type) - _ltc_to_asn1(B->type);
+
+   /* for QSORT the order is UNDEFINED if they are "equal" which means it is NOT DETERMINISTIC.  So we force it to be :-) */
+   if (r == 0) {
+      /* their order in the original list now determines the position */
+      return A->used - B->used;
+   } else {
+      return r;
+   }
+}
+
+/*
+   Encode a SET type
+   @param list      The list of items to encode
+   @param inlen     The number of items in the list
+   @param out       [out] The destination
+   @param outlen    [in/out] The size of the output
+   @return CRYPT_OK on success
+*/
+int der_encode_set(ltc_asn1_list *list, unsigned long inlen,
+                   unsigned char *out,  unsigned long *outlen)
+{
+   ltc_asn1_list  *copy;
+   unsigned long   x;
+   int             err;
+
+   /* make copy of list */
+   copy = XCALLOC(inlen, sizeof(*copy));
+   if (copy == NULL) {
+      return CRYPT_MEM;
+   }
+
+   /* fill in used member with index so we can fully sort it */
+   for (x = 0; x < inlen; x++) {
+       copy[x]      = list[x];
+       copy[x].used = x;
+   }
+
+   /* sort it by the "type" field */
+   XQSORT(copy, inlen, sizeof(*copy), &_qsort_helper);
+
+   /* call der_encode_sequence_ex() */
+   err = der_encode_sequence_ex(copy, inlen, out, outlen, LTC_ASN1_SET);
+
+   /* free list */
+   XFREE(copy);
+
+   return err;
+}
+
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/pk/asn1/der/set/der_encode_setof.c b/libtomcrypt/src/pk/asn1/der/set/der_encode_setof.c
new file mode 100644 (file)
index 0000000..b837cdd
--- /dev/null
@@ -0,0 +1,161 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file der_encode_setof.c
+  ASN.1 DER, Encode SET OF, Tom St Denis
+*/
+
+#ifdef LTC_DER
+
+struct edge {
+   unsigned char *start;
+   unsigned long  size;
+};
+
+static int _qsort_helper(const void *a, const void *b)
+{
+   struct edge   *A = (struct edge *)a, *B = (struct edge *)b;
+   int            r;
+   unsigned long  x;
+
+   /* compare min length */
+   r = XMEMCMP(A->start, B->start, MIN(A->size, B->size));
+
+   if (r == 0 && A->size != B->size) {
+      if (A->size > B->size) {
+         for (x = B->size; x < A->size; x++) {
+            if (A->start[x]) {
+               return 1;
+            }
+         }
+      } else {
+         for (x = A->size; x < B->size; x++) {
+            if (B->start[x]) {
+               return -1;
+            }
+         }
+      }
+   }
+
+   return r;
+}
+
+/**
+   Encode a SETOF stucture
+   @param list      The list of items to encode
+   @param inlen     The number of items in the list
+   @param out       [out] The destination
+   @param outlen    [in/out] The size of the output
+   @return CRYPT_OK on success
+*/
+int der_encode_setof(ltc_asn1_list *list, unsigned long inlen,
+                     unsigned char *out,  unsigned long *outlen)
+{
+   unsigned long  x, y, z;
+   ptrdiff_t hdrlen;
+   int            err;
+   struct edge   *edges;
+   unsigned char *ptr, *buf;
+
+   /* check that they're all the same type */
+   for (x = 1; x < inlen; x++) {
+      if (list[x].type != list[x-1].type) {
+         return CRYPT_INVALID_ARG;
+      }
+   }
+
+   /* alloc buffer to store copy of output */
+   buf = XCALLOC(1, *outlen);
+   if (buf == NULL) {
+      return CRYPT_MEM;
+   }
+
+   /* encode list */
+   if ((err = der_encode_sequence_ex(list, inlen, buf, outlen, LTC_ASN1_SETOF)) != CRYPT_OK) {
+       XFREE(buf);
+       return err;
+   }
+
+   /* allocate edges */
+   edges = XCALLOC(inlen, sizeof(*edges));
+   if (edges == NULL) {
+      XFREE(buf);
+      return CRYPT_MEM;
+   }
+
+   /* skip header */
+   ptr = buf + 1;
+
+   /* now skip length data */
+   x = *ptr++;
+   if (x >= 0x80) {
+      ptr += (x & 0x7F);
+   }
+
+   /* get the size of the static header */
+   hdrlen = ptr - buf;
+
+
+   /* scan for edges */
+   x = 0;
+   while (ptr < (buf + *outlen)) {
+      /* store start */
+      edges[x].start = ptr;
+
+      /* skip type */
+      z = 1;
+
+      /* parse length */
+      y = ptr[z++];
+      if (y < 128) {
+         edges[x].size = y;
+      } else {
+         y &= 0x7F;
+         edges[x].size = 0;
+         while (y--) {
+            edges[x].size = (edges[x].size << 8) | ((unsigned long)ptr[z++]);
+         }
+      }
+
+      /* skip content */
+      edges[x].size += z;
+      ptr           += edges[x].size;
+      ++x;
+   }
+
+   /* sort based on contents (using edges) */
+   XQSORT(edges, inlen, sizeof(*edges), &_qsort_helper);
+
+   /* copy static header */
+   XMEMCPY(out, buf, hdrlen);
+
+   /* copy+sort using edges+indecies to output from buffer */
+   for (y = (unsigned long)hdrlen, x = 0; x < inlen; x++) {
+      XMEMCPY(out+y, edges[x].start, edges[x].size);
+      y += edges[x].size;
+   }
+
+#ifdef LTC_CLEAN_STACK
+   zeromem(buf, *outlen);
+#endif
+
+   /* free buffers */
+   XFREE(edges);
+   XFREE(buf);
+
+   return CRYPT_OK;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/pk/asn1/der/short_integer/der_decode_short_integer.c b/libtomcrypt/src/pk/asn1/der/short_integer/der_decode_short_integer.c
new file mode 100644 (file)
index 0000000..71debf3
--- /dev/null
@@ -0,0 +1,66 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file der_decode_short_integer.c
+  ASN.1 DER, decode an integer, Tom St Denis
+*/
+
+
+#ifdef LTC_DER
+
+/**
+  Read a short integer
+  @param in       The DER encoded data
+  @param inlen    Size of data
+  @param num      [out] The integer to decode
+  @return CRYPT_OK if successful
+*/
+int der_decode_short_integer(const unsigned char *in, unsigned long inlen, unsigned long *num)
+{
+   unsigned long len, x, y;
+
+   LTC_ARGCHK(num    != NULL);
+   LTC_ARGCHK(in     != NULL);
+
+   /* check length */
+   if (inlen < 2) {
+      return CRYPT_INVALID_PACKET;
+   }
+
+   /* check header */
+   x = 0;
+   if ((in[x++] & 0x1F) != 0x02) {
+      return CRYPT_INVALID_PACKET;
+   }
+
+   /* get the packet len */
+   len = in[x++];
+
+   if (x + len > inlen) {
+      return CRYPT_INVALID_PACKET;
+   }
+
+   /* read number */
+   y = 0;
+   while (len--) {
+      y = (y<<8) | (unsigned long)in[x++];
+   }
+   *num = y;
+
+   return CRYPT_OK;
+
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/pk/asn1/der/short_integer/der_encode_short_integer.c b/libtomcrypt/src/pk/asn1/der/short_integer/der_encode_short_integer.c
new file mode 100644 (file)
index 0000000..ea413eb
--- /dev/null
@@ -0,0 +1,95 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file der_encode_short_integer.c
+  ASN.1 DER, encode an integer, Tom St Denis
+*/
+
+
+#ifdef LTC_DER
+
+/**
+  Store a short integer in the range (0,2^32-1)
+  @param num      The integer to encode
+  @param out      [out] The destination for the DER encoded integers
+  @param outlen   [in/out] The max size and resulting size of the DER encoded integers
+  @return CRYPT_OK if successful
+*/
+int der_encode_short_integer(unsigned long num, unsigned char *out, unsigned long *outlen)
+{
+   unsigned long len, x, y, z;
+   int           err;
+
+   LTC_ARGCHK(out    != NULL);
+   LTC_ARGCHK(outlen != NULL);
+
+   /* force to 32 bits */
+   num &= 0xFFFFFFFFUL;
+
+   /* find out how big this will be */
+   if ((err = der_length_short_integer(num, &len)) != CRYPT_OK) {
+      return err;
+   }
+
+   if (*outlen < len) {
+      *outlen = len;
+      return CRYPT_BUFFER_OVERFLOW;
+   }
+
+   /* get len of output */
+   z = 0;
+   y = num;
+   while (y) {
+     ++z;
+     y >>= 8;
+   }
+
+   /* handle zero */
+   if (z == 0) {
+      z = 1;
+   }
+
+   /* see if msb is set */
+   z += (num&(1UL<<((z<<3) - 1))) ? 1 : 0;
+
+   /* adjust the number so the msB is non-zero */
+   for (x = 0; (z <= 4) && (x < (4 - z)); x++) {
+      num <<= 8;
+   }
+
+   /* store header */
+   x = 0;
+   out[x++] = 0x02;
+   out[x++] = (unsigned char)z;
+
+   /* if 31st bit is set output a leading zero and decrement count */
+   if (z == 5) {
+      out[x++] = 0;
+      --z;
+   }
+
+   /* store values */
+   for (y = 0; y < z; y++) {
+      out[x++] = (unsigned char)((num >> 24) & 0xFF);
+      num    <<= 8;
+   }
+
+   /* we good */
+   *outlen = x;
+
+   return CRYPT_OK;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/pk/asn1/der/short_integer/der_length_short_integer.c b/libtomcrypt/src/pk/asn1/der/short_integer/der_length_short_integer.c
new file mode 100644 (file)
index 0000000..52d0e1a
--- /dev/null
@@ -0,0 +1,68 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file der_length_short_integer.c
+  ASN.1 DER, get length of encoding, Tom St Denis
+*/
+
+
+#ifdef LTC_DER
+/**
+  Gets length of DER encoding of num
+  @param num    The integer to get the size of
+  @param outlen [out] The length of the DER encoding for the given integer
+  @return CRYPT_OK if successful
+*/
+int der_length_short_integer(unsigned long num, unsigned long *outlen)
+{
+   unsigned long z, y, len;
+
+   LTC_ARGCHK(outlen  != NULL);
+
+   /* force to 32 bits */
+   num &= 0xFFFFFFFFUL;
+
+   /* get the number of bytes */
+   z = 0;
+   y = num;
+   while (y) {
+     ++z;
+     y >>= 8;
+   }
+
+   /* handle zero */
+   if (z == 0) {
+      z = 1;
+   }
+
+   /* we need a 0x02 to indicate it's INTEGER */
+   len = 1;
+
+   /* length byte */
+   ++len;
+
+   /* bytes in value */
+   len += z;
+
+   /* see if msb is set */
+   len += (num&(1UL<<((z<<3) - 1))) ? 1 : 0;
+
+   /* return length */
+   *outlen = len;
+
+   return CRYPT_OK;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/pk/asn1/der/teletex_string/der_decode_teletex_string.c b/libtomcrypt/src/pk/asn1/der/teletex_string/der_decode_teletex_string.c
new file mode 100644 (file)
index 0000000..0c7c3c8
--- /dev/null
@@ -0,0 +1,93 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file der_decode_teletex_string.c
+  ASN.1 DER, encode a teletex STRING
+*/
+
+#ifdef LTC_DER
+
+/**
+  Store a teletex STRING
+  @param in      The DER encoded teletex STRING
+  @param inlen   The size of the DER teletex STRING
+  @param out     [out] The array of octets stored (one per char)
+  @param outlen  [in/out] The number of octets stored
+  @return CRYPT_OK if successful
+*/
+int der_decode_teletex_string(const unsigned char *in, unsigned long inlen,
+                                unsigned char *out, unsigned long *outlen)
+{
+   unsigned long x, y, len;
+   int           t;
+
+   LTC_ARGCHK(in     != NULL);
+   LTC_ARGCHK(out    != NULL);
+   LTC_ARGCHK(outlen != NULL);
+
+   /* must have header at least */
+   if (inlen < 2) {
+      return CRYPT_INVALID_PACKET;
+   }
+
+   /* check for 0x14 */
+   if ((in[0] & 0x1F) != 0x14) {
+      return CRYPT_INVALID_PACKET;
+   }
+   x = 1;
+
+   /* decode the length */
+   if (in[x] & 0x80) {
+      /* valid # of bytes in length are 1,2,3 */
+      y = in[x] & 0x7F;
+      if ((y == 0) || (y > 3) || ((x + y) > inlen)) {
+         return CRYPT_INVALID_PACKET;
+      }
+
+      /* read the length in */
+      len = 0;
+      ++x;
+      while (y--) {
+         len = (len << 8) | in[x++];
+      }
+   } else {
+      len = in[x++] & 0x7F;
+   }
+
+   /* is it too long? */
+   if (len > *outlen) {
+      *outlen = len;
+      return CRYPT_BUFFER_OVERFLOW;
+   }
+
+   if (len + x > inlen) {
+      return CRYPT_INVALID_PACKET;
+   }
+
+   /* read the data */
+   for (y = 0; y < len; y++) {
+       t = der_teletex_value_decode(in[x++]);
+       if (t == -1) {
+           return CRYPT_INVALID_ARG;
+       }
+       out[y] = t;
+   }
+
+   *outlen = y;
+
+   return CRYPT_OK;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/pk/asn1/der/teletex_string/der_length_teletex_string.c b/libtomcrypt/src/pk/asn1/der/teletex_string/der_length_teletex_string.c
new file mode 100644 (file)
index 0000000..29fe5b0
--- /dev/null
@@ -0,0 +1,208 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file der_length_teletex_string.c
+  ASN.1 DER, get length of teletex STRING
+*/
+
+#ifdef LTC_DER
+
+static const struct {
+   int code, value;
+} teletex_table[] = {
+{ '\0',  0 },
+{ '\a',  7 },
+{ '\b',  8 },
+{ '\t',  9 },
+{ '\n', 10 },
+{ '\v', 11 },
+{ '\f', 12 },
+{ '\r', 13 },
+{ ' ',  32 },
+{ '!',  33 },
+{ '"',  34 },
+{ '%',  37 },
+{ '&',  38 },
+{ '\'', 39 },
+{ '(',  40 },
+{ ')',  41 },
+{ '+',  43 },
+{ ',',  44 },
+{ '-',  45 },
+{ '.',  46 },
+{ '/',  47 },
+{ '0',  48 },
+{ '1',  49 },
+{ '2',  50 },
+{ '3',  51 },
+{ '4',  52 },
+{ '5',  53 },
+{ '6',  54 },
+{ '7',  55 },
+{ '8',  56 },
+{ '9',  57 },
+{ ':',  58 },
+{ ';',  59 },
+{ '<',  60 },
+{ '=',  61 },
+{ '>',  62 },
+{ '?',  63 },
+{ '@',  64 },
+{ 'A',  65 },
+{ 'B',  66 },
+{ 'C',  67 },
+{ 'D',  68 },
+{ 'E',  69 },
+{ 'F',  70 },
+{ 'G',  71 },
+{ 'H',  72 },
+{ 'I',  73 },
+{ 'J',  74 },
+{ 'K',  75 },
+{ 'L',  76 },
+{ 'M',  77 },
+{ 'N',  78 },
+{ 'O',  79 },
+{ 'P',  80 },
+{ 'Q',  81 },
+{ 'R',  82 },
+{ 'S',  83 },
+{ 'T',  84 },
+{ 'U',  85 },
+{ 'V',  86 },
+{ 'W',  87 },
+{ 'X',  88 },
+{ 'Y',  89 },
+{ 'Z',  90 },
+{ '[',  91 },
+{ ']',  93 },
+{ '_',  95 },
+{ 'a',  97 },
+{ 'b',  98 },
+{ 'c',  99 },
+{ 'd',  100 },
+{ 'e',  101 },
+{ 'f',  102 },
+{ 'g',  103 },
+{ 'h',  104 },
+{ 'i',  105 },
+{ 'j',  106 },
+{ 'k',  107 },
+{ 'l',  108 },
+{ 'm',  109 },
+{ 'n',  110 },
+{ 'o',  111 },
+{ 'p',  112 },
+{ 'q',  113 },
+{ 'r',  114 },
+{ 's',  115 },
+{ 't',  116 },
+{ 'u',  117 },
+{ 'v',  118 },
+{ 'w',  119 },
+{ 'x',  120 },
+{ 'y',  121 },
+{ 'z',  122 },
+{ '|',  124 },
+{ ' ',  160 },
+{ 0xa1, 161 },
+{ 0xa2, 162 },
+{ 0xa3, 163 },
+{ '$',  164 },
+{ 0xa5, 165 },
+{ '#',  166 },
+{ 0xa7, 167 },
+{ 0xa4, 168 },
+{ 0xab, 171 },
+{ 0xb0, 176 },
+{ 0xb1, 177 },
+{ 0xb2, 178 },
+{ 0xb3, 179 },
+{ 0xd7, 180 },
+{ 0xb5, 181 },
+{ 0xb6, 182 },
+{ 0xb7, 183 },
+{ 0xf7, 184 },
+{ 0xbb, 187 },
+{ 0xbc, 188 },
+{ 0xbd, 189 },
+{ 0xbe, 190 },
+{ 0xbf, 191 },
+};
+
+int der_teletex_char_encode(int c)
+{
+   int x;
+   for (x = 0; x < (int)(sizeof(teletex_table)/sizeof(teletex_table[0])); x++) {
+       if (teletex_table[x].code == c) {
+          return teletex_table[x].value;
+       }
+   }
+   return -1;
+}
+
+int der_teletex_value_decode(int v)
+{
+   int x;
+   for (x = 0; x < (int)(sizeof(teletex_table)/sizeof(teletex_table[0])); x++) {
+       if (teletex_table[x].value == v) {
+          return teletex_table[x].code;
+       }
+   }
+   return -1;
+}
+
+/**
+  Gets length of DER encoding of teletex STRING
+  @param octets   The values you want to encode
+  @param noctets  The number of octets in the string to encode
+  @param outlen   [out] The length of the DER encoding for the given string
+  @return CRYPT_OK if successful
+*/
+int der_length_teletex_string(const unsigned char *octets, unsigned long noctets, unsigned long *outlen)
+{
+   unsigned long x;
+
+   LTC_ARGCHK(outlen != NULL);
+   LTC_ARGCHK(octets != NULL);
+
+   /* scan string for validity */
+   for (x = 0; x < noctets; x++) {
+       if (der_teletex_char_encode(octets[x]) == -1) {
+          return CRYPT_INVALID_ARG;
+       }
+   }
+
+   if (noctets < 128) {
+      /* 16 LL DD DD DD ... */
+      *outlen = 2 + noctets;
+   } else if (noctets < 256) {
+      /* 16 81 LL DD DD DD ... */
+      *outlen = 3 + noctets;
+   } else if (noctets < 65536UL) {
+      /* 16 82 LL LL DD DD DD ... */
+      *outlen = 4 + noctets;
+   } else if (noctets < 16777216UL) {
+      /* 16 83 LL LL LL DD DD DD ... */
+      *outlen = 5 + noctets;
+   } else {
+      return CRYPT_INVALID_ARG;
+   }
+
+   return CRYPT_OK;
+}
+
+#endif
+
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/pk/asn1/der/utctime/der_decode_utctime.c b/libtomcrypt/src/pk/asn1/der/utctime/der_decode_utctime.c
new file mode 100644 (file)
index 0000000..07fcb80
--- /dev/null
@@ -0,0 +1,125 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file der_decode_utctime.c
+  ASN.1 DER, decode a  UTCTIME, Tom St Denis
+*/
+
+#ifdef LTC_DER
+
+static int _char_to_int(unsigned char x)
+{
+   switch (x)  {
+      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;
+      default:  return 100;
+   }
+}
+
+#define DECODE_V(y, max) \
+   y  = _char_to_int(buf[x])*10 + _char_to_int(buf[x+1]); \
+   if (y >= max) return CRYPT_INVALID_PACKET;           \
+   x += 2;
+
+/**
+  Decodes a UTC time structure in DER format (reads all 6 valid encoding formats)
+  @param in     Input buffer
+  @param inlen  Length of input buffer in octets
+  @param out    [out] Destination of UTC time structure
+  @return CRYPT_OK   if successful
+*/
+int der_decode_utctime(const unsigned char *in, unsigned long *inlen,
+                             ltc_utctime   *out)
+{
+   unsigned char buf[32] = { 0 }; /* initialize as all zeroes */
+   unsigned long x;
+   int           y;
+
+   LTC_ARGCHK(in    != NULL);
+   LTC_ARGCHK(inlen != NULL);
+   LTC_ARGCHK(out   != NULL);
+
+   /* check header */
+   if (*inlen < 2UL || (in[1] >= sizeof(buf)) || ((in[1] + 2UL) > *inlen)) {
+      return CRYPT_INVALID_PACKET;
+   }
+
+   /* decode the string */
+   for (x = 0; x < in[1]; x++) {
+       y = der_ia5_value_decode(in[x+2]);
+       if (y == -1) {
+          return CRYPT_INVALID_PACKET;
+       }
+       buf[x] = y;
+   }
+   *inlen = 2 + x;
+
+
+   /* possible encodings are
+YYMMDDhhmmZ
+YYMMDDhhmm+hh'mm'
+YYMMDDhhmm-hh'mm'
+YYMMDDhhmmssZ
+YYMMDDhhmmss+hh'mm'
+YYMMDDhhmmss-hh'mm'
+
+    So let's do a trivial decode upto [including] mm
+   */
+
+    x = 0;
+    DECODE_V(out->YY, 100);
+    DECODE_V(out->MM, 13);
+    DECODE_V(out->DD, 32);
+    DECODE_V(out->hh, 24);
+    DECODE_V(out->mm, 60);
+
+    /* clear timezone and seconds info */
+    out->off_dir = out->off_hh = out->off_mm = out->ss = 0;
+
+    /* now is it Z, +, - or 0-9 */
+    if (buf[x] == 'Z') {
+       return CRYPT_OK;
+    } else if (buf[x] == '+' || buf[x] == '-') {
+       out->off_dir = (buf[x++] == '+') ? 0 : 1;
+       DECODE_V(out->off_hh, 24);
+       DECODE_V(out->off_mm, 60);
+       return CRYPT_OK;
+    }
+
+    /* decode seconds */
+    DECODE_V(out->ss, 60);
+
+    /* now is it Z, +, - */
+    if (buf[x] == 'Z') {
+       return CRYPT_OK;
+    } else if (buf[x] == '+' || buf[x] == '-') {
+       out->off_dir = (buf[x++] == '+') ? 0 : 1;
+       DECODE_V(out->off_hh, 24);
+       DECODE_V(out->off_mm, 60);
+       return CRYPT_OK;
+    } else {
+       return CRYPT_INVALID_PACKET;
+    }
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/pk/asn1/der/utctime/der_encode_utctime.c b/libtomcrypt/src/pk/asn1/der/utctime/der_encode_utctime.c
new file mode 100644 (file)
index 0000000..c6c8464
--- /dev/null
@@ -0,0 +1,81 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file der_encode_utctime.c
+  ASN.1 DER, encode a  UTCTIME, Tom St Denis
+*/
+
+#ifdef LTC_DER
+
+static const char * const baseten = "0123456789";
+
+#define STORE_V(y) \
+    out[x++] = der_ia5_char_encode(baseten[(y/10) % 10]); \
+    out[x++] = der_ia5_char_encode(baseten[y % 10]);
+
+/**
+  Encodes a UTC time structure in DER format
+  @param utctime      The UTC time structure to encode
+  @param out          The destination of the DER encoding of the UTC time structure
+  @param outlen       [in/out] The length of the DER encoding
+  @return CRYPT_OK if successful
+*/
+int der_encode_utctime(ltc_utctime *utctime,
+                       unsigned char *out,   unsigned long *outlen)
+{
+    unsigned long x, tmplen;
+    int           err;
+
+    LTC_ARGCHK(utctime != NULL);
+    LTC_ARGCHK(out     != NULL);
+    LTC_ARGCHK(outlen  != NULL);
+
+    if ((err = der_length_utctime(utctime, &tmplen)) != CRYPT_OK) {
+       return err;
+    }
+    if (tmplen > *outlen) {
+        *outlen = tmplen;
+        return CRYPT_BUFFER_OVERFLOW;
+    }
+
+    /* store header */
+    out[0] = 0x17;
+
+    /* store values */
+    x = 2;
+    STORE_V(utctime->YY);
+    STORE_V(utctime->MM);
+    STORE_V(utctime->DD);
+    STORE_V(utctime->hh);
+    STORE_V(utctime->mm);
+    STORE_V(utctime->ss);
+
+    if (utctime->off_mm || utctime->off_hh) {
+       out[x++] = der_ia5_char_encode(utctime->off_dir ? '-' : '+');
+       STORE_V(utctime->off_hh);
+       STORE_V(utctime->off_mm);
+    } else {
+       out[x++] = der_ia5_char_encode('Z');
+    }
+
+    /* store length */
+    out[1] = (unsigned char)(x - 2);
+
+    /* all good let's return */
+    *outlen = x;
+    return CRYPT_OK;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/pk/asn1/der/utctime/der_length_utctime.c b/libtomcrypt/src/pk/asn1/der/utctime/der_length_utctime.c
new file mode 100644 (file)
index 0000000..4202083
--- /dev/null
@@ -0,0 +1,44 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file der_length_utctime.c
+  ASN.1 DER, get length of UTCTIME, Tom St Denis
+*/
+
+#ifdef LTC_DER
+
+/**
+  Gets length of DER encoding of UTCTIME
+  @param utctime      The UTC time structure to get the size of
+  @param outlen [out] The length of the DER encoding
+  @return CRYPT_OK if successful
+*/
+int der_length_utctime(ltc_utctime *utctime, unsigned long *outlen)
+{
+   LTC_ARGCHK(outlen  != NULL);
+   LTC_ARGCHK(utctime != NULL);
+
+   if (utctime->off_hh == 0 && utctime->off_mm == 0) {
+      /* we encode as YYMMDDhhmmssZ */
+      *outlen = 2 + 13;
+   } else {
+      /* we encode as YYMMDDhhmmss{+|-}hh'mm' */
+      *outlen = 2 + 17;
+   }
+
+   return CRYPT_OK;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/pk/asn1/der/utf8/der_decode_utf8_string.c b/libtomcrypt/src/pk/asn1/der/utf8/der_decode_utf8_string.c
new file mode 100644 (file)
index 0000000..195a3f5
--- /dev/null
@@ -0,0 +1,114 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file der_decode_utf8_string.c
+  ASN.1 DER, encode a UTF8 STRING, Tom St Denis
+*/
+
+
+#ifdef LTC_DER
+
+/**
+  Store a UTF8 STRING
+  @param in      The DER encoded UTF8 STRING
+  @param inlen   The size of the DER UTF8 STRING
+  @param out     [out] The array of utf8s stored (one per char)
+  @param outlen  [in/out] The number of utf8s stored
+  @return CRYPT_OK if successful
+*/
+int der_decode_utf8_string(const unsigned char *in,  unsigned long inlen,
+                                       wchar_t *out, unsigned long *outlen)
+{
+   wchar_t       tmp;
+   unsigned long x, y, z, len;
+   int err;
+
+   LTC_ARGCHK(in     != NULL);
+   LTC_ARGCHK(out    != NULL);
+   LTC_ARGCHK(outlen != NULL);
+
+   /* must have header at least */
+   if (inlen < 2) {
+      return CRYPT_INVALID_PACKET;
+   }
+
+   /* check for 0x0C */
+   if ((in[0] & 0x1F) != 0x0C) {
+      return CRYPT_INVALID_PACKET;
+   }
+   x = 1;
+
+   /* decode the length */
+   if (in[x] & 0x80) {
+      /* valid # of bytes in length are 1,2,3 */
+      y = in[x] & 0x7F;
+      if ((y == 0) || (y > 3) || ((x + y) > inlen)) {
+         return CRYPT_INVALID_PACKET;
+      }
+
+      /* read the length in */
+      len = 0;
+      ++x;
+      while (y--) {
+         len = (len << 8) | in[x++];
+      }
+   } else {
+      len = in[x++] & 0x7F;
+   }
+
+   if (len + x > inlen) {
+      return CRYPT_INVALID_PACKET;
+   }
+
+   /* proceed to decode */
+   for (y = 0; x < inlen; ) {
+      /* get first byte */
+      tmp = in[x++];
+
+      /* count number of bytes */
+      for (z = 0; (tmp & 0x80) && (z <= 4); z++, tmp = (tmp << 1) & 0xFF);
+
+      if (z > 4 || (x + (z - 1) > inlen)) {
+         return CRYPT_INVALID_PACKET;
+      }
+
+      /* decode, grab upper bits */
+      tmp >>= z;
+
+      /* grab remaining bytes */
+      if (z > 1) { --z; }
+      while (z-- != 0) {
+         if ((in[x] & 0xC0) != 0x80) {
+            return CRYPT_INVALID_PACKET;
+         }
+         tmp = (tmp << 6) | ((wchar_t)in[x++] & 0x3F);
+      }
+
+      if (y < *outlen) {
+         out[y] = tmp;
+      }
+      y++;
+   }
+   if (y > *outlen) {
+      err = CRYPT_BUFFER_OVERFLOW;
+   } else {
+      err = CRYPT_OK;
+   }
+   *outlen = y;
+
+   return err;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/pk/asn1/der/utf8/der_encode_utf8_string.c b/libtomcrypt/src/pk/asn1/der/utf8/der_encode_utf8_string.c
new file mode 100644 (file)
index 0000000..4c2030f
--- /dev/null
@@ -0,0 +1,104 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file der_encode_utf8_string.c
+  ASN.1 DER, encode a UTF8 STRING, Tom St Denis
+*/
+
+
+#ifdef LTC_DER
+
+/**
+  Store an UTF8 STRING
+  @param in       The array of UTF8 to store (one per wchar_t)
+  @param inlen    The number of UTF8 to store
+  @param out      [out] The destination for the DER encoded UTF8 STRING
+  @param outlen   [in/out] The max size and resulting size of the DER UTF8 STRING
+  @return CRYPT_OK if successful
+*/
+int der_encode_utf8_string(const wchar_t *in,  unsigned long inlen,
+                           unsigned char *out, unsigned long *outlen)
+{
+   unsigned long x, y, len;
+
+   LTC_ARGCHK(in     != NULL);
+   LTC_ARGCHK(out    != NULL);
+   LTC_ARGCHK(outlen != NULL);
+
+   /* get the size */
+   for (x = len = 0; x < inlen; x++) {
+       if (!der_utf8_valid_char(in[x])) return CRYPT_INVALID_ARG;
+       len += der_utf8_charsize(in[x]);
+   }
+
+   if (len < 128) {
+      y = 2 + len;
+   } else if (len < 256) {
+      y = 3 + len;
+   } else if (len < 65536UL) {
+      y = 4 + len;
+   } else if (len < 16777216UL) {
+      y = 5 + len;
+   } else {
+      return CRYPT_INVALID_ARG;
+   }
+
+   /* too big? */
+   if (y > *outlen) {
+      *outlen = y;
+      return CRYPT_BUFFER_OVERFLOW;
+   }
+
+   /* encode the header+len */
+   x = 0;
+   out[x++] = 0x0C;
+   if (len < 128) {
+      out[x++] = (unsigned char)len;
+   } else if (len < 256) {
+      out[x++] = 0x81;
+      out[x++] = (unsigned char)len;
+   } else if (len < 65536UL) {
+      out[x++] = 0x82;
+      out[x++] = (unsigned char)((len>>8)&255);
+      out[x++] = (unsigned char)(len&255);
+   } else if (len < 16777216UL) {
+      out[x++] = 0x83;
+      out[x++] = (unsigned char)((len>>16)&255);
+      out[x++] = (unsigned char)((len>>8)&255);
+      out[x++] = (unsigned char)(len&255);
+   } else {
+       /* coverity[dead_error_line] */
+      return CRYPT_INVALID_ARG;
+   }
+
+   /* store UTF8 */
+   for (y = 0; y < inlen; y++) {
+       switch (der_utf8_charsize(in[y])) {
+          case 1: out[x++] = (unsigned char)in[y]; break;
+          case 2: out[x++] = 0xC0 | ((in[y] >> 6) & 0x1F);  out[x++] = 0x80 | (in[y] & 0x3F); break;
+          case 3: out[x++] = 0xE0 | ((in[y] >> 12) & 0x0F); out[x++] = 0x80 | ((in[y] >> 6) & 0x3F); out[x++] = 0x80 | (in[y] & 0x3F); break;
+#if !defined(LTC_WCHAR_MAX) || LTC_WCHAR_MAX > 0xFFFF
+          case 4: out[x++] = 0xF0 | ((in[y] >> 18) & 0x07); out[x++] = 0x80 | ((in[y] >> 12) & 0x3F); out[x++] = 0x80 | ((in[y] >> 6) & 0x3F); out[x++] = 0x80 | (in[y] & 0x3F); break;
+#endif
+       }
+   }
+
+   /* retun length */
+   *outlen = x;
+
+   return CRYPT_OK;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/pk/asn1/der/utf8/der_length_utf8_string.c b/libtomcrypt/src/pk/asn1/der/utf8/der_length_utf8_string.c
new file mode 100644 (file)
index 0000000..88f4355
--- /dev/null
@@ -0,0 +1,102 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file der_length_utf8_string.c
+  ASN.1 DER, get length of UTF8 STRING, Tom St Denis
+*/
+
+#ifdef LTC_DER
+
+/** Return the size in bytes of a UTF-8 character
+  @param c   The UTF-8 character to measure
+  @return    The size in bytes
+*/
+unsigned long der_utf8_charsize(const wchar_t c)
+{
+   if (c <= 0x7F) {
+      return 1;
+   } else if (c <= 0x7FF) {
+      return 2;
+#if LTC_WCHAR_MAX == 0xFFFF
+   } else {
+      return 3;
+   }
+#else
+   } else if (c <= 0xFFFF) {
+      return 3;
+   } else {
+      return 4;
+   }
+#endif
+}
+
+/**
+  Test whether the given code point is valid character
+  @param c   The UTF-8 character to test
+  @return    1 - valid, 0 - invalid
+*/
+int der_utf8_valid_char(const wchar_t c)
+{
+   LTC_UNUSED_PARAM(c);
+#if !defined(LTC_WCHAR_MAX) || LTC_WCHAR_MAX > 0xFFFF
+   if (c > 0x10FFFF) return 0;
+#endif
+#if LTC_WCHAR_MAX != 0xFFFF && LTC_WCHAR_MAX != 0xFFFFFFFF
+   if (c < 0) return 0;
+#endif
+   return 1;
+}
+
+/**
+  Gets length of DER encoding of UTF8 STRING
+  @param in       The characters to measure the length of
+  @param noctets  The number of octets in the string to encode
+  @param outlen   [out] The length of the DER encoding for the given string
+  @return CRYPT_OK if successful
+*/
+int der_length_utf8_string(const wchar_t *in, unsigned long noctets, unsigned long *outlen)
+{
+   unsigned long x, len;
+
+   LTC_ARGCHK(in     != NULL);
+   LTC_ARGCHK(outlen != NULL);
+
+   len = 0;
+   for (x = 0; x < noctets; x++) {
+      if (!der_utf8_valid_char(in[x])) return CRYPT_INVALID_ARG;
+      len += der_utf8_charsize(in[x]);
+   }
+
+   if (len < 128) {
+      /* 0C LL DD DD DD ... */
+      *outlen = 2 + len;
+   } else if (len < 256) {
+      /* 0C 81 LL DD DD DD ... */
+      *outlen = 3 + len;
+   } else if (len < 65536UL) {
+      /* 0C 82 LL LL DD DD DD ... */
+      *outlen = 4 + len;
+   } else if (len < 16777216UL) {
+      /* 0C 83 LL LL LL DD DD DD ... */
+      *outlen = 5 + len;
+   } else {
+      return CRYPT_INVALID_ARG;
+   }
+
+   return CRYPT_OK;
+}
+
+#endif
+
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/pk/dh/dh.c b/libtomcrypt/src/pk/dh/dh.c
new file mode 100644 (file)
index 0000000..763b007
--- /dev/null
@@ -0,0 +1,237 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+#include "tomcrypt.h"
+
+#ifdef LTC_MDH
+
+/* This holds the key settings.  ***MUST*** be organized by size from smallest to largest. */
+const ltc_dh_set_type ltc_dh_sets[] = {
+#ifdef LTC_DH768
+{  /* 768-bit MODP Group 1 - https://tools.ietf.org/html/rfc7296#appendix-B.1 */
+   96,
+   "DH-768",
+   "2",
+   "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
+   "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
+   "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
+   "E485B576625E7EC6F44C42E9A63A3620FFFFFFFFFFFFFFFF"
+},
+#endif
+#ifdef LTC_DH1024
+{  /* 1024-bit MODP Group 2 - https://tools.ietf.org/html/rfc7296#appendix-B.2 */
+   128,
+   "DH-1024",
+   "2",
+   "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
+   "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
+   "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
+   "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
+   "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381"
+   "FFFFFFFFFFFFFFFF"
+},
+#endif
+#ifdef LTC_DH1536
+{  /* 1536-bit MODP Group 5 - https://tools.ietf.org/html/rfc3526#section-2 */
+   192,
+   "DH-1536",
+   "2",
+   "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
+   "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
+   "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
+   "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
+   "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D"
+   "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F"
+   "83655D23DCA3AD961C62F356208552BB9ED529077096966D"
+   "670C354E4ABC9804F1746C08CA237327FFFFFFFFFFFFFFFF"
+},
+#endif
+#ifdef LTC_DH2048
+{  /* 2048-bit MODP Group 14 - https://tools.ietf.org/html/rfc3526#section-3 */
+   256,
+   "DH-2048",
+   "2",
+   "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
+   "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
+   "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
+   "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
+   "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D"
+   "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F"
+   "83655D23DCA3AD961C62F356208552BB9ED529077096966D"
+   "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B"
+   "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9"
+   "DE2BCBF6955817183995497CEA956AE515D2261898FA0510"
+   "15728E5A8AACAA68FFFFFFFFFFFFFFFF"
+},
+#endif
+#ifdef LTC_DH3072
+{  /* 3072-bit MODP Group 15 - https://tools.ietf.org/html/rfc3526#section-4 */
+   384,
+   "DH-3072",
+   "2",
+   "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
+   "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
+   "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
+   "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
+   "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D"
+   "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F"
+   "83655D23DCA3AD961C62F356208552BB9ED529077096966D"
+   "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B"
+   "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9"
+   "DE2BCBF6955817183995497CEA956AE515D2261898FA0510"
+   "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64"
+   "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7"
+   "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B"
+   "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C"
+   "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31"
+   "43DB5BFCE0FD108E4B82D120A93AD2CAFFFFFFFFFFFFFFFF"
+},
+#endif
+#ifdef LTC_DH4096
+{  /* 4096-bit MODP Group 16 - https://tools.ietf.org/html/rfc3526#section-5 */
+   512,
+   "DH-4096",
+   "2",
+   "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
+   "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
+   "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
+   "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
+   "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D"
+   "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F"
+   "83655D23DCA3AD961C62F356208552BB9ED529077096966D"
+   "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B"
+   "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9"
+   "DE2BCBF6955817183995497CEA956AE515D2261898FA0510"
+   "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64"
+   "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7"
+   "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B"
+   "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C"
+   "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31"
+   "43DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7"
+   "88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA"
+   "2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6"
+   "287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED"
+   "1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9"
+   "93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934063199"
+   "FFFFFFFFFFFFFFFF"
+},
+#endif
+#ifdef LTC_DH6144
+{  /* 6144-bit MODP Group 17 - https://tools.ietf.org/html/rfc3526#section-6 */
+   768,
+   "DH-6144",
+   "2",
+   "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
+   "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
+   "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
+   "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
+   "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D"
+   "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F"
+   "83655D23DCA3AD961C62F356208552BB9ED529077096966D"
+   "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B"
+   "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9"
+   "DE2BCBF6955817183995497CEA956AE515D2261898FA0510"
+   "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64"
+   "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7"
+   "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B"
+   "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C"
+   "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31"
+   "43DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7"
+   "88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA"
+   "2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6"
+   "287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED"
+   "1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9"
+   "93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934028492"
+   "36C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BD"
+   "F8FF9406AD9E530EE5DB382F413001AEB06A53ED9027D831"
+   "179727B0865A8918DA3EDBEBCF9B14ED44CE6CBACED4BB1B"
+   "DB7F1447E6CC254B332051512BD7AF426FB8F401378CD2BF"
+   "5983CA01C64B92ECF032EA15D1721D03F482D7CE6E74FEF6"
+   "D55E702F46980C82B5A84031900B1C9E59E7C97FBEC7E8F3"
+   "23A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AA"
+   "CC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE328"
+   "06A1D58BB7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55C"
+   "DA56C9EC2EF29632387FE8D76E3C0468043E8F663F4860EE"
+   "12BF2D5B0B7474D6E694F91E6DCC4024FFFFFFFFFFFFFFFF"
+},
+#endif
+#ifdef LTC_DH8192
+{  /* 8192-bit MODP Group 18 - https://tools.ietf.org/html/rfc3526#section-7 */
+   1024,
+   "DH-8192",
+   "2",
+   "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
+   "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
+   "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
+   "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
+   "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D"
+   "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F"
+   "83655D23DCA3AD961C62F356208552BB9ED529077096966D"
+   "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B"
+   "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9"
+   "DE2BCBF6955817183995497CEA956AE515D2261898FA0510"
+   "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64"
+   "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7"
+   "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B"
+   "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C"
+   "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31"
+   "43DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7"
+   "88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA"
+   "2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6"
+   "287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED"
+   "1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9"
+   "93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934028492"
+   "36C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BD"
+   "F8FF9406AD9E530EE5DB382F413001AEB06A53ED9027D831"
+   "179727B0865A8918DA3EDBEBCF9B14ED44CE6CBACED4BB1B"
+   "DB7F1447E6CC254B332051512BD7AF426FB8F401378CD2BF"
+   "5983CA01C64B92ECF032EA15D1721D03F482D7CE6E74FEF6"
+   "D55E702F46980C82B5A84031900B1C9E59E7C97FBEC7E8F3"
+   "23A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AA"
+   "CC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE328"
+   "06A1D58BB7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55C"
+   "DA56C9EC2EF29632387FE8D76E3C0468043E8F663F4860EE"
+   "12BF2D5B0B7474D6E694F91E6DBE115974A3926F12FEE5E4"
+   "38777CB6A932DF8CD8BEC4D073B931BA3BC832B68D9DD300"
+   "741FA7BF8AFC47ED2576F6936BA424663AAB639C5AE4F568"
+   "3423B4742BF1C978238F16CBE39D652DE3FDB8BEFC848AD9"
+   "22222E04A4037C0713EB57A81A23F0C73473FC646CEA306B"
+   "4BCBC8862F8385DDFA9D4B7FA2C087E879683303ED5BDD3A"
+   "062B3CF5B3A278A66D2A13F83F44F82DDF310EE074AB6A36"
+   "4597E899A0255DC164F31CC50846851DF9AB48195DED7EA1"
+   "B1D510BD7EE74D73FAF36BC31ECFA268359046F4EB879F92"
+   "4009438B481C6CD7889A002ED5EE382BC9190DA6FC026E47"
+   "9558E4475677E9AA9E3050E2765694DFC81F56E880B96E71"
+   "60C980DD98EDD3DFFFFFFFFFFFFFFFFF"
+},
+#endif
+{
+   0,
+   NULL,
+   NULL,
+   NULL
+}
+};
+
+/**
+  Returns the DH group size (octets) for given key
+  @param key   The DH key to get the size of
+  @return The group size in octets (0 on error)
+ */
+int dh_get_groupsize(dh_key *key)
+{
+   if (key == NULL) return 0;
+   return mp_unsigned_bin_size(key->prime);
+}
+
+#endif /* LTC_MDH */
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/pk/dh/dh_check_pubkey.c b/libtomcrypt/src/pk/dh/dh_check_pubkey.c
new file mode 100644 (file)
index 0000000..fb4f37b
--- /dev/null
@@ -0,0 +1,65 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+#include "tomcrypt.h"
+
+#ifdef LTC_MDH
+
+/**
+  Check DH public key (INTERNAL ONLY, not part of public API)
+  @param key    The key you wish to test
+  @return CRYPT_OK if successful
+*/
+int dh_check_pubkey(dh_key *key)
+{
+   void *p_minus1;
+   ltc_mp_digit digit;
+   int i, digit_count, bits_set = 0, err;
+
+   LTC_ARGCHK(key != NULL);
+
+   if ((err = mp_init(&p_minus1)) != CRYPT_OK) {
+      return err;
+   }
+
+   /* avoid: y <= 1 OR y >= p-1 */
+   if ((err = mp_sub_d(key->prime, 1, p_minus1)) != CRYPT_OK) {
+      goto error;
+   }
+   if (mp_cmp(key->y, p_minus1) != LTC_MP_LT || mp_cmp_d(key->y, 1) != LTC_MP_GT) {
+      err = CRYPT_INVALID_ARG;
+      goto error;
+   }
+
+   /* public key must have more than one bit set */
+   digit_count = mp_get_digit_count(key->y);
+   for (i = 0; i < digit_count && bits_set < 2; i++) {
+      digit = mp_get_digit(key->y, i);
+      while (digit > 0) {
+         if (digit & 1) bits_set++;
+         digit >>= 1;
+      }
+   }
+   if (bits_set > 1) {
+      err = CRYPT_OK;
+   }
+   else {
+      err = CRYPT_INVALID_ARG;
+   }
+
+error:
+   mp_clear(p_minus1);
+   return err;
+}
+
+#endif /* LTC_MDH */
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/pk/dh/dh_export.c b/libtomcrypt/src/pk/dh/dh_export.c
new file mode 100644 (file)
index 0000000..6a02a89
--- /dev/null
@@ -0,0 +1,62 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+#include "tomcrypt.h"
+
+#ifdef LTC_MDH
+
+/**
+  Export a DH key to a binary packet
+  @param out    [out] The destination for the key
+  @param outlen [in/out] The max size and resulting size of the DH key
+  @param type   Which type of key (PK_PRIVATE or PK_PUBLIC)
+  @param key    The key you wish to export
+  @return CRYPT_OK if successful
+*/
+int dh_export(unsigned char *out, unsigned long *outlen, int type, dh_key *key)
+{
+   unsigned char flags[1];
+   int err;
+   unsigned long version = 0;
+
+   LTC_ARGCHK(out    != NULL);
+   LTC_ARGCHK(outlen != NULL);
+   LTC_ARGCHK(key    != NULL);
+
+   if (type == PK_PRIVATE) {
+      /* export x - private key */
+      flags[0] = 1;
+      err = der_encode_sequence_multi(out, outlen,
+                                LTC_ASN1_SHORT_INTEGER, 1UL, &version,
+                                LTC_ASN1_BIT_STRING,    1UL, flags,
+                                LTC_ASN1_INTEGER,       1UL, key->prime,
+                                LTC_ASN1_INTEGER,       1UL, key->base,
+                                LTC_ASN1_INTEGER,       1UL, key->x,
+                                LTC_ASN1_EOL,           0UL, NULL);
+   }
+   else {
+      /* export y - public key */
+      flags[0] = 0;
+      err = der_encode_sequence_multi(out, outlen,
+                                LTC_ASN1_SHORT_INTEGER, 1UL, &version,
+                                LTC_ASN1_BIT_STRING,    1UL, flags,
+                                LTC_ASN1_INTEGER,       1UL, key->prime,
+                                LTC_ASN1_INTEGER,       1UL, key->base,
+                                LTC_ASN1_INTEGER,       1UL, key->y,
+                                LTC_ASN1_EOL,           0UL, NULL);
+   }
+
+   return err;
+}
+
+#endif /* LTC_MDH */
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/pk/dh/dh_export_key.c b/libtomcrypt/src/pk/dh/dh_export_key.c
new file mode 100644 (file)
index 0000000..d48c011
--- /dev/null
@@ -0,0 +1,47 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+#include "tomcrypt.h"
+
+#ifdef LTC_MDH
+
+/**
+  Binary export a DH key to a buffer
+  @param out    [out] The destination for the key
+  @param outlen [in/out] The max size and resulting size of the DH key
+  @param type   Which type of key (PK_PRIVATE or PK_PUBLIC)
+  @param key    The key you wish to export
+  @return CRYPT_OK if successful
+*/
+int dh_export_key(void *out, unsigned long *outlen, int type, dh_key *key)
+{
+   unsigned long len;
+   void *k;
+
+   LTC_ARGCHK(out    != NULL);
+   LTC_ARGCHK(outlen != NULL);
+   LTC_ARGCHK(key    != NULL);
+
+   k = (type == PK_PRIVATE) ? key->x : key->y;
+   len = mp_unsigned_bin_size(k);
+
+   if (*outlen < len) {
+      *outlen = len;
+      return CRYPT_BUFFER_OVERFLOW;
+   }
+   *outlen = len;
+
+   return mp_to_unsigned_bin(k, out);
+}
+
+#endif /* LTC_MDH */
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/pk/dh/dh_free.c b/libtomcrypt/src/pk/dh/dh_free.c
new file mode 100644 (file)
index 0000000..b4f58ca
--- /dev/null
@@ -0,0 +1,28 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+#include "tomcrypt.h"
+
+#ifdef LTC_MDH
+
+/**
+  Free the allocated ram for a DH key
+  @param key   The key which you wish to free
+*/
+void dh_free(dh_key *key)
+{
+   LTC_ARGCHKVD(key != NULL);
+   mp_cleanup_multi(&key->prime, &key->base, &key->y, &key->x, NULL);
+}
+
+#endif /* LTC_MDH */
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/pk/dh/dh_generate_key.c b/libtomcrypt/src/pk/dh/dh_generate_key.c
new file mode 100644 (file)
index 0000000..69fb6f9
--- /dev/null
@@ -0,0 +1,102 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+#include "tomcrypt.h"
+
+#ifdef LTC_MDH
+
+static int _dh_groupsize_to_keysize(int groupsize)
+{
+   /* The strength estimates from https://tools.ietf.org/html/rfc3526#section-8
+    * We use "Estimate 2" to get an appropriate private key (exponent) size.
+    */
+   if (groupsize <= 0) {
+      return 0;
+   }
+   else if (groupsize <= 192) {
+      return 30;     /* 1536-bit => key size 240-bit */
+   }
+   else if (groupsize <= 256) {
+      return 40;     /* 2048-bit => key size 320-bit */
+   }
+   else if (groupsize <= 384) {
+      return 52;     /* 3072-bit => key size 416-bit */
+   }
+   else if (groupsize <= 512) {
+      return 60;     /* 4096-bit => key size 480-bit */
+   }
+   else if (groupsize <= 768) {
+      return 67;     /* 6144-bit => key size 536-bit */
+   }
+   else if (groupsize <= 1024) {
+      return 77;     /* 8192-bit => key size 616-bit */
+   }
+   else {
+      return 0;
+   }
+}
+
+int dh_generate_key(prng_state *prng, int wprng, dh_key *key)
+{
+   unsigned char *buf;
+   unsigned long keysize;
+   int err, max_iterations = LTC_PK_MAX_RETRIES;
+
+   LTC_ARGCHK(key         != NULL);
+   LTC_ARGCHK(ltc_mp.name != NULL);
+
+   /* good prng? */
+   if ((err = prng_is_valid(wprng)) != CRYPT_OK) {
+      return err;
+   }
+
+   keysize = _dh_groupsize_to_keysize(mp_unsigned_bin_size(key->prime));
+   if (keysize == 0) {
+      err = CRYPT_INVALID_KEYSIZE;
+      goto freemp;
+   }
+
+   /* allocate buffer */
+   buf = XMALLOC(keysize);
+   if (buf == NULL) {
+      err = CRYPT_MEM;
+      goto freemp;
+   }
+
+   key->type = PK_PRIVATE;
+   do {
+      /* make up random buf */
+      if (prng_descriptor[wprng].read(buf, keysize, prng) != keysize) {
+         err = CRYPT_ERROR_READPRNG;
+         goto freebuf;
+      }
+      /* load the x value - private key */
+      if ((err = mp_read_unsigned_bin(key->x, buf, keysize)) != CRYPT_OK) {
+         goto freebuf;
+      }
+      /* compute the y value - public key */
+      if ((err = mp_exptmod(key->base, key->x, key->prime, key->y)) != CRYPT_OK) {
+         goto freebuf;
+      }
+      err = dh_check_pubkey(key);
+   } while (err != CRYPT_OK && max_iterations-- > 0);
+
+freebuf:
+   zeromem(buf, keysize);
+   XFREE(buf);
+freemp:
+   if (err != CRYPT_OK) dh_free(key);
+   return err;
+}
+
+#endif /* LTC_MDH */
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/pk/dh/dh_import.c b/libtomcrypt/src/pk/dh/dh_import.c
new file mode 100644 (file)
index 0000000..601e5e7
--- /dev/null
@@ -0,0 +1,99 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+#include "tomcrypt.h"
+
+#ifdef LTC_MDH
+
+/**
+  Import a DH key from a binary packet
+  @param in     The packet to read
+  @param inlen  The length of the input packet
+  @param key    [out] Where to import the key to
+  @return CRYPT_OK if successful, on error all allocated memory is freed automatically
+*/
+int dh_import(const unsigned char *in, unsigned long inlen, dh_key *key)
+{
+   unsigned char flags[1];
+   int err;
+   unsigned long version;
+
+   LTC_ARGCHK(in  != NULL);
+   LTC_ARGCHK(key != NULL);
+
+   /* init */
+   if ((err = mp_init_multi(&key->x, &key->y, &key->base, &key->prime, NULL)) != CRYPT_OK) {
+      return err;
+   }
+
+   /* find out what type of key it is */
+   err = der_decode_sequence_multi(in, inlen,
+                                   LTC_ASN1_SHORT_INTEGER, 1UL, &version,
+                                   LTC_ASN1_BIT_STRING, 1UL, &flags,
+                                   LTC_ASN1_EOL, 0UL, NULL);
+   if (err != CRYPT_OK && err != CRYPT_INPUT_TOO_LONG) {
+      goto error;
+   }
+
+   if (version == 0) {
+      if (flags[0] == 1) {
+         key->type = PK_PRIVATE;
+         if ((err = der_decode_sequence_multi(in, inlen,
+                                              LTC_ASN1_SHORT_INTEGER, 1UL, &version,
+                                              LTC_ASN1_BIT_STRING,    1UL, flags,
+                                              LTC_ASN1_INTEGER,       1UL, key->prime,
+                                              LTC_ASN1_INTEGER,       1UL, key->base,
+                                              LTC_ASN1_INTEGER,       1UL, key->x,
+                                              LTC_ASN1_EOL,           0UL, NULL)) != CRYPT_OK) {
+            goto error;
+         }
+         /* compute public key: y = (base ^ x) mod prime */
+         if ((err = mp_exptmod(key->base, key->x, key->prime, key->y)) != CRYPT_OK) {
+            goto error;
+         }
+      }
+      else if (flags[0] == 0) {
+         key->type = PK_PUBLIC;
+         if ((err = der_decode_sequence_multi(in, inlen,
+                                              LTC_ASN1_SHORT_INTEGER, 1UL, &version,
+                                              LTC_ASN1_BIT_STRING,    1UL, flags,
+                                              LTC_ASN1_INTEGER,       1UL, key->prime,
+                                              LTC_ASN1_INTEGER,       1UL, key->base,
+                                              LTC_ASN1_INTEGER,       1UL, key->y,
+                                              LTC_ASN1_EOL,           0UL, NULL)) != CRYPT_OK) {
+            goto error;
+         }
+      }
+      else {
+         err = CRYPT_INVALID_PACKET;
+         goto error;
+      }
+   }
+   else {
+      err = CRYPT_INVALID_PACKET;
+      goto error;
+   }
+
+   /* check public key */
+   if ((err = dh_check_pubkey(key)) != CRYPT_OK) {
+      goto error;
+   }
+
+   return CRYPT_OK;
+
+error:
+   dh_free(key);
+   return err;
+}
+
+#endif /* LTC_MDH */
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/pk/dh/dh_set.c b/libtomcrypt/src/pk/dh/dh_set.c
new file mode 100644 (file)
index 0000000..8d0af7d
--- /dev/null
@@ -0,0 +1,124 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+#include "tomcrypt.h"
+
+#ifdef LTC_MDH
+
+/**
+  Import DH key parts p and g from raw numbers
+
+  @param p       DH's p (prime)
+  @param plen    DH's p's length
+  @param g       DH's g (group)
+  @param glen    DH's g's length
+  @param key     [out] the destination for the imported key
+  @return CRYPT_OK if successful
+*/
+int dh_set_pg(const unsigned char *p, unsigned long plen,
+              const unsigned char *g, unsigned long glen,
+              dh_key *key)
+{
+   int err;
+
+   LTC_ARGCHK(key         != NULL);
+   LTC_ARGCHK(p           != NULL);
+   LTC_ARGCHK(g           != NULL);
+   LTC_ARGCHK(ltc_mp.name != NULL);
+
+   if ((err = mp_init_multi(&key->x, &key->y, &key->base, &key->prime, NULL)) != CRYPT_OK) {
+      return err;
+   }
+
+   if ((err = mp_read_unsigned_bin(key->base, (unsigned char*)g, glen)) != CRYPT_OK)     { goto LBL_ERR; }
+   if ((err = mp_read_unsigned_bin(key->prime, (unsigned char*)p, plen)) != CRYPT_OK)  { goto LBL_ERR; }
+
+   return CRYPT_OK;
+
+LBL_ERR:
+   dh_free(key);
+   return err;
+}
+
+/**
+  Import DH key parts p and g from built-in DH groups
+
+  @param groupsize  The size of the DH group to use
+  @param key        [out] Where the newly created DH key will be stored
+  @return CRYPT_OK if successful, note: on error all allocated memory will be freed automatically.
+*/
+int dh_set_pg_groupsize(int groupsize, dh_key *key)
+{
+   int err, i;
+
+   LTC_ARGCHK(key         != NULL);
+   LTC_ARGCHK(ltc_mp.name != NULL);
+   LTC_ARGCHK(groupsize   > 0);
+
+   for (i = 0; (groupsize > ltc_dh_sets[i].size) && (ltc_dh_sets[i].size != 0); i++);
+   if (ltc_dh_sets[i].size == 0) return CRYPT_INVALID_KEYSIZE;
+
+   if ((err = mp_init_multi(&key->x, &key->y, &key->base, &key->prime, NULL)) != CRYPT_OK) {
+      return err;
+   }
+   if ((err = mp_read_radix(key->base, ltc_dh_sets[i].base, 16)) != CRYPT_OK)  { goto LBL_ERR; }
+   if ((err = mp_read_radix(key->prime, ltc_dh_sets[i].prime, 16)) != CRYPT_OK) { goto LBL_ERR; }
+
+   return CRYPT_OK;
+
+LBL_ERR:
+   dh_free(key);
+   return err;
+}
+
+/**
+  Import DH public or private key part from raw numbers
+
+     NB: The p & g parts must be set beforehand
+
+  @param in      The key-part to import, either public or private.
+  @param inlen   The key-part's length
+  @param type    Which type of key (PK_PRIVATE or PK_PUBLIC)
+  @param key     [out] the destination for the imported key
+  @return CRYPT_OK if successful
+*/
+int dh_set_key(const unsigned char *in, unsigned long inlen, int type, dh_key *key)
+{
+   int err;
+
+   LTC_ARGCHK(key         != NULL);
+   LTC_ARGCHK(ltc_mp.name != NULL);
+
+   if (type == PK_PRIVATE) {
+      key->type = PK_PRIVATE;
+      if ((err = mp_read_unsigned_bin(key->x, (unsigned char*)in, inlen)) != CRYPT_OK) { goto LBL_ERR; }
+      if ((err = mp_exptmod(key->base, key->x, key->prime, key->y)) != CRYPT_OK)       { goto LBL_ERR; }
+   }
+   else {
+      key->type = PK_PUBLIC;
+      if ((err = mp_read_unsigned_bin(key->y, (unsigned char*)in, inlen)) != CRYPT_OK) { goto LBL_ERR; }
+   }
+
+   /* check public key */
+   if ((err = dh_check_pubkey(key)) != CRYPT_OK) {
+      goto LBL_ERR;
+   }
+
+   return CRYPT_OK;
+
+LBL_ERR:
+   dh_free(key);
+   return err;
+}
+
+#endif /* LTC_MDH */
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/pk/dh/dh_set_pg_dhparam.c b/libtomcrypt/src/pk/dh/dh_set_pg_dhparam.c
new file mode 100644 (file)
index 0000000..7003011
--- /dev/null
@@ -0,0 +1,54 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+#include "tomcrypt.h"
+
+#ifdef LTC_MDH
+
+/**
+  Import DH key parts p and g from dhparam
+
+      dhparam data: openssl dhparam -outform DER -out dhparam.der 2048
+
+  @param dhparam    The DH param DER encoded data
+  @param dhparamlen The length of dhparam data
+  @param key        [out] Where the newly created DH key will be stored
+  @return CRYPT_OK if successful, note: on error all allocated memory will be freed automatically.
+*/
+int dh_set_pg_dhparam(const unsigned char *dhparam, unsigned long dhparamlen, dh_key *key)
+{
+   int err;
+
+   LTC_ARGCHK(key         != NULL);
+   LTC_ARGCHK(ltc_mp.name != NULL);
+   LTC_ARGCHK(dhparam     != NULL);
+   LTC_ARGCHK(dhparamlen  > 0);
+
+   if ((err = mp_init_multi(&key->x, &key->y, &key->base, &key->prime, NULL)) != CRYPT_OK) {
+      return err;
+   }
+   if ((err = der_decode_sequence_multi(dhparam, dhparamlen,
+                                        LTC_ASN1_INTEGER, 1UL, key->prime,
+                                        LTC_ASN1_INTEGER, 1UL, key->base,
+                                        LTC_ASN1_EOL,     0UL, NULL)) != CRYPT_OK) {
+      goto LBL_ERR;
+   }
+
+   return CRYPT_OK;
+
+LBL_ERR:
+   dh_free(key);
+   return err;
+}
+
+#endif /* LTC_MDH */
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/pk/dh/dh_shared_secret.c b/libtomcrypt/src/pk/dh/dh_shared_secret.c
new file mode 100644 (file)
index 0000000..1eb69fb
--- /dev/null
@@ -0,0 +1,80 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+#include "tomcrypt.h"
+
+#ifdef LTC_MDH
+
+/**
+   Create a DH shared secret.
+   @param private_key     The private DH key in the pair
+   @param public_key      The public DH key in the pair
+   @param out             [out] The destination of the shared data
+   @param outlen          [in/out] The max size and resulting size of the shared data.
+   @return CRYPT_OK if successful
+*/
+int dh_shared_secret(dh_key *private_key, dh_key *public_key,
+                     unsigned char *out, unsigned long *outlen)
+{
+   void *tmp;
+   unsigned long x;
+   int err;
+
+   LTC_ARGCHK(private_key != NULL);
+   LTC_ARGCHK(public_key  != NULL);
+   LTC_ARGCHK(out         != NULL);
+   LTC_ARGCHK(outlen      != NULL);
+
+   /* types valid? */
+   if (private_key->type != PK_PRIVATE) {
+      return CRYPT_PK_NOT_PRIVATE;
+   }
+
+   /* same DH group? */
+   if (mp_cmp(private_key->prime, public_key->prime) != LTC_MP_EQ) { return CRYPT_PK_TYPE_MISMATCH; }
+   if (mp_cmp(private_key->base, public_key->base) != LTC_MP_EQ)   { return CRYPT_PK_TYPE_MISMATCH; }
+
+   /* init big numbers */
+   if ((err = mp_init(&tmp)) != CRYPT_OK) {
+      return err;
+   }
+
+   /* check public key */
+   if ((err = dh_check_pubkey(public_key)) != CRYPT_OK) {
+      goto error;
+   }
+
+   /* compute tmp = y^x mod p */
+   if ((err = mp_exptmod(public_key->y, private_key->x, private_key->prime, tmp)) != CRYPT_OK)  {
+      goto error;
+   }
+
+   /* enough space for output? */
+   x = (unsigned long)mp_unsigned_bin_size(tmp);
+   if (*outlen < x) {
+      *outlen = x;
+      err = CRYPT_BUFFER_OVERFLOW;
+      goto error;
+   }
+   if ((err = mp_to_unsigned_bin(tmp, out)) != CRYPT_OK) {
+      goto error;
+   }
+   *outlen = x;
+   err = CRYPT_OK;
+
+error:
+   mp_clear(tmp);
+   return err;
+}
+
+#endif /* LTC_MDH */
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/pk/dsa/dsa_decrypt_key.c b/libtomcrypt/src/pk/dsa/dsa_decrypt_key.c
new file mode 100644 (file)
index 0000000..ef4e1dd
--- /dev/null
@@ -0,0 +1,139 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file dsa_decrypt_key.c
+  DSA Crypto, Tom St Denis
+*/
+
+#ifdef LTC_MDSA
+
+/**
+  Decrypt an DSA encrypted key
+  @param in       The ciphertext
+  @param inlen    The length of the ciphertext (octets)
+  @param out      [out] The plaintext
+  @param outlen   [in/out] The max size and resulting size of the plaintext
+  @param key      The corresponding private DSA key
+  @return CRYPT_OK if successful
+*/
+int dsa_decrypt_key(const unsigned char *in,  unsigned long  inlen,
+                          unsigned char *out, unsigned long *outlen,
+                          dsa_key *key)
+{
+   unsigned char  *skey, *expt;
+   void           *g_pub;
+   unsigned long  x, y;
+   unsigned long  hashOID[32] = { 0 };
+   int            hash, err;
+   ltc_asn1_list  decode[3];
+
+   LTC_ARGCHK(in     != NULL);
+   LTC_ARGCHK(out    != NULL);
+   LTC_ARGCHK(outlen != NULL);
+   LTC_ARGCHK(key    != NULL);
+
+   /* right key type? */
+   if (key->type != PK_PRIVATE) {
+      return CRYPT_PK_NOT_PRIVATE;
+   }
+
+   /* decode to find out hash */
+   LTC_SET_ASN1(decode, 0, LTC_ASN1_OBJECT_IDENTIFIER, hashOID, sizeof(hashOID)/sizeof(hashOID[0]));
+   err = der_decode_sequence(in, inlen, decode, 1);
+   if (err != CRYPT_OK && err != CRYPT_INPUT_TOO_LONG) {
+      return err;
+   }
+
+   hash = find_hash_oid(hashOID, decode[0].size);
+   if (hash_is_valid(hash) != CRYPT_OK) {
+      return CRYPT_INVALID_PACKET;
+   }
+
+   /* we now have the hash! */
+
+   if ((err = mp_init(&g_pub)) != CRYPT_OK) {
+      return err;
+   }
+
+   /* allocate memory */
+   expt   = XMALLOC(mp_unsigned_bin_size(key->p) + 1);
+   skey   = XMALLOC(MAXBLOCKSIZE);
+   if (expt == NULL || skey == NULL) {
+      if (expt != NULL) {
+         XFREE(expt);
+      }
+      if (skey != NULL) {
+         XFREE(skey);
+      }
+      mp_clear(g_pub);
+      return CRYPT_MEM;
+   }
+
+   LTC_SET_ASN1(decode, 1, LTC_ASN1_INTEGER,          g_pub,      1UL);
+   LTC_SET_ASN1(decode, 2, LTC_ASN1_OCTET_STRING,      skey,      MAXBLOCKSIZE);
+
+   /* read the structure in now */
+   if ((err = der_decode_sequence(in, inlen, decode, 3)) != CRYPT_OK) {
+      goto LBL_ERR;
+   }
+
+   /* make shared key */
+   x = mp_unsigned_bin_size(key->p) + 1;
+   if ((err = dsa_shared_secret(key->x, g_pub, key, expt, &x)) != CRYPT_OK) {
+      goto LBL_ERR;
+   }
+
+   y = mp_unsigned_bin_size(key->p) + 1;
+   y = MIN(y, MAXBLOCKSIZE);
+   if ((err = hash_memory(hash, expt, x, expt, &y)) != CRYPT_OK) {
+      goto LBL_ERR;
+   }
+
+   /* ensure the hash of the shared secret is at least as big as the encrypt itself */
+   if (decode[2].size > y) {
+      err = CRYPT_INVALID_PACKET;
+      goto LBL_ERR;
+   }
+
+   /* avoid buffer overflow */
+   if (*outlen < decode[2].size) {
+      *outlen = decode[2].size;
+      err = CRYPT_BUFFER_OVERFLOW;
+      goto LBL_ERR;
+   }
+
+   /* Decrypt the key */
+   for (x = 0; x < decode[2].size; x++) {
+     out[x] = expt[x] ^ skey[x];
+   }
+   *outlen = x;
+
+   err = CRYPT_OK;
+LBL_ERR:
+#ifdef LTC_CLEAN_STACK
+   zeromem(expt,   mp_unsigned_bin_size(key->p) + 1);
+   zeromem(skey,   MAXBLOCKSIZE);
+#endif
+
+   XFREE(expt);
+   XFREE(skey);
+
+   mp_clear(g_pub);
+
+   return err;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
+
diff --git a/libtomcrypt/src/pk/dsa/dsa_encrypt_key.c b/libtomcrypt/src/pk/dsa/dsa_encrypt_key.c
new file mode 100644 (file)
index 0000000..c854367
--- /dev/null
@@ -0,0 +1,128 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file dsa_encrypt_key.c
+  DSA Crypto, Tom St Denis
+*/
+
+#ifdef LTC_MDSA
+
+/**
+  Encrypt a symmetric key with DSA
+  @param in         The symmetric key you want to encrypt
+  @param inlen      The length of the key to encrypt (octets)
+  @param out        [out] The destination for the ciphertext
+  @param outlen     [in/out] The max size and resulting size of the ciphertext
+  @param prng       An active PRNG state
+  @param wprng      The index of the PRNG you wish to use
+  @param hash       The index of the hash you want to use
+  @param key        The DSA key you want to encrypt to
+  @return CRYPT_OK if successful
+*/
+int dsa_encrypt_key(const unsigned char *in,   unsigned long inlen,
+                          unsigned char *out,  unsigned long *outlen,
+                          prng_state *prng, int wprng, int hash,
+                          dsa_key *key)
+{
+    unsigned char *expt, *skey;
+    void          *g_pub, *g_priv;
+    unsigned long  x, y;
+    int            err;
+
+    LTC_ARGCHK(in      != NULL);
+    LTC_ARGCHK(out     != NULL);
+    LTC_ARGCHK(outlen  != NULL);
+    LTC_ARGCHK(key     != NULL);
+
+    /* check that wprng/cipher/hash are not invalid */
+    if ((err = prng_is_valid(wprng)) != CRYPT_OK) {
+       return err;
+    }
+
+    if ((err = hash_is_valid(hash)) != CRYPT_OK) {
+       return err;
+    }
+
+    if (inlen > hash_descriptor[hash].hashsize) {
+       return CRYPT_INVALID_HASH;
+    }
+
+    /* make a random key and export the public copy */
+    if ((err = mp_init_multi(&g_pub, &g_priv, NULL)) != CRYPT_OK) {
+       return err;
+    }
+
+    expt       = XMALLOC(mp_unsigned_bin_size(key->p) + 1);
+    skey       = XMALLOC(MAXBLOCKSIZE);
+    if (expt == NULL  || skey == NULL) {
+       if (expt != NULL) {
+          XFREE(expt);
+       }
+       if (skey != NULL) {
+          XFREE(skey);
+       }
+       mp_clear_multi(g_pub, g_priv, NULL);
+       return CRYPT_MEM;
+    }
+
+    /* make a random g_priv, g_pub = g^x pair
+       private key x should be in range: 1 <= x <= q-1 (see FIPS 186-4 B.1.2)
+     */
+    if ((err = rand_bn_upto(g_priv, key->q, prng, wprng)) != CRYPT_OK) {
+      goto LBL_ERR;
+    }
+
+    /* compute y */
+    if ((err = mp_exptmod(key->g, g_priv, key->p, g_pub)) != CRYPT_OK) {
+       goto LBL_ERR;
+    }
+
+    /* make random key */
+    x        = mp_unsigned_bin_size(key->p) + 1;
+    if ((err = dsa_shared_secret(g_priv, key->y, key, expt, &x)) != CRYPT_OK) {
+       goto LBL_ERR;
+    }
+
+    y = MAXBLOCKSIZE;
+    if ((err = hash_memory(hash, expt, x, skey, &y)) != CRYPT_OK) {
+       goto LBL_ERR;
+    }
+
+    /* Encrypt key */
+    for (x = 0; x < inlen; x++) {
+      skey[x] ^= in[x];
+    }
+
+    err = der_encode_sequence_multi(out, outlen,
+                                    LTC_ASN1_OBJECT_IDENTIFIER,  hash_descriptor[hash].OIDlen,   hash_descriptor[hash].OID,
+                                    LTC_ASN1_INTEGER,            1UL,                            g_pub,
+                                    LTC_ASN1_OCTET_STRING,       inlen,                          skey,
+                                    LTC_ASN1_EOL,                0UL,                            NULL);
+
+LBL_ERR:
+#ifdef LTC_CLEAN_STACK
+    /* clean up */
+    zeromem(expt,   mp_unsigned_bin_size(key->p) + 1);
+    zeromem(skey,   MAXBLOCKSIZE);
+#endif
+
+    XFREE(skey);
+    XFREE(expt);
+
+    mp_clear_multi(g_pub, g_priv, NULL);
+    return err;
+}
+
+#endif
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
+
diff --git a/libtomcrypt/src/pk/dsa/dsa_export.c b/libtomcrypt/src/pk/dsa/dsa_export.c
new file mode 100644 (file)
index 0000000..f3a9f59
--- /dev/null
@@ -0,0 +1,116 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+   @file dsa_export.c
+   DSA implementation, export key, Tom St Denis
+*/
+
+#ifdef LTC_MDSA
+
+/**
+  Export a DSA key to a binary packet
+  @param out    [out] Where to store the packet
+  @param outlen [in/out] The max size and resulting size of the packet
+  @param type   The type of key to export (PK_PRIVATE or PK_PUBLIC)
+  @param key    The key to export
+  @return CRYPT_OK if successful
+*/
+int dsa_export(unsigned char *out, unsigned long *outlen, int type, dsa_key *key)
+{
+   unsigned long zero=0;
+   int err, std;
+
+   LTC_ARGCHK(out    != NULL);
+   LTC_ARGCHK(outlen != NULL);
+   LTC_ARGCHK(key    != NULL);
+
+   std = type & PK_STD;
+   type &= ~PK_STD;
+
+   /* can we store the static header?  */
+   if (type == PK_PRIVATE && key->type != PK_PRIVATE) {
+      return CRYPT_PK_TYPE_MISMATCH;
+   }
+
+   if (type != PK_PUBLIC && type != PK_PRIVATE) {
+      return CRYPT_INVALID_ARG;
+   }
+
+   if (type == PK_PRIVATE) {
+      if (std) {
+          return der_encode_sequence_multi(out, outlen,
+                                         LTC_ASN1_SHORT_INTEGER, 1UL, &zero,
+                                         LTC_ASN1_INTEGER,      1UL, key->p,
+                                         LTC_ASN1_INTEGER,      1UL, key->q,
+                                         LTC_ASN1_INTEGER,      1UL, key->g,
+                                         LTC_ASN1_INTEGER,      1UL, key->y,
+                                         LTC_ASN1_INTEGER,      1UL, key->x,
+                                         LTC_ASN1_EOL,          0UL, NULL);
+      }
+      else {
+          unsigned char flags[1];
+          flags[0] = 1;
+          return der_encode_sequence_multi(out, outlen,
+                                         LTC_ASN1_BIT_STRING,   1UL, flags,
+                                         LTC_ASN1_INTEGER,      1UL, key->g,
+                                         LTC_ASN1_INTEGER,      1UL, key->p,
+                                         LTC_ASN1_INTEGER,      1UL, key->q,
+                                         LTC_ASN1_INTEGER,      1UL, key->y,
+                                         LTC_ASN1_INTEGER,      1UL, key->x,
+                                         LTC_ASN1_EOL,          0UL, NULL);
+      }
+   } else {
+      if (std) {
+          unsigned long tmplen = (unsigned long)(mp_count_bits(key->y) / 8) + 8;
+          unsigned char* tmp = XMALLOC(tmplen);
+          ltc_asn1_list int_list[3];
+
+          if (tmp == NULL) {
+              return CRYPT_MEM;
+          }
+
+          err = der_encode_integer(key->y, tmp, &tmplen);
+          if (err != CRYPT_OK) {
+              goto error;
+          }
+
+          LTC_SET_ASN1(int_list, 0, LTC_ASN1_INTEGER, key->p, 1UL);
+          LTC_SET_ASN1(int_list, 1, LTC_ASN1_INTEGER, key->q, 1UL);
+          LTC_SET_ASN1(int_list, 2, LTC_ASN1_INTEGER, key->g, 1UL);
+
+          err = der_encode_subject_public_key_info(out, outlen, PKA_DSA, tmp,
+              tmplen, LTC_ASN1_SEQUENCE, int_list,
+              sizeof(int_list) / sizeof(int_list[0]));
+
+error:
+          XFREE(tmp);
+          return err;
+      }
+      else {
+          unsigned char flags[1];
+          flags[0] = 0;
+          return der_encode_sequence_multi(out, outlen,
+                                     LTC_ASN1_BIT_STRING,   1UL, flags,
+                                     LTC_ASN1_INTEGER,      1UL, key->g,
+                                     LTC_ASN1_INTEGER,      1UL, key->p,
+                                     LTC_ASN1_INTEGER,      1UL, key->q,
+                                     LTC_ASN1_INTEGER,      1UL, key->y,
+                                     LTC_ASN1_EOL,          0UL, NULL);
+      }
+   }
+}
+
+#endif
+
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/pk/dsa/dsa_free.c b/libtomcrypt/src/pk/dsa/dsa_free.c
new file mode 100644 (file)
index 0000000..5cac656
--- /dev/null
@@ -0,0 +1,33 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+   @file dsa_free.c
+   DSA implementation, free a DSA key, Tom St Denis
+*/
+
+#ifdef LTC_MDSA
+
+/**
+   Free a DSA key
+   @param key   The key to free from memory
+*/
+void dsa_free(dsa_key *key)
+{
+   LTC_ARGCHKVD(key != NULL);
+   mp_cleanup_multi(&key->y, &key->x, &key->q, &key->g, &key->p, NULL);
+   key->type = key->qord = 0;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/pk/dsa/dsa_generate_key.c b/libtomcrypt/src/pk/dsa/dsa_generate_key.c
new file mode 100644 (file)
index 0000000..18b2df6
--- /dev/null
@@ -0,0 +1,47 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+   @file dsa_make_key.c
+   DSA implementation, generate a DSA key
+*/
+
+#ifdef LTC_MDSA
+
+/**
+  Create a DSA key
+  @param prng          An active PRNG state
+  @param wprng         The index of the PRNG desired
+  @param key           [in/out] Where to store the created key
+  @return CRYPT_OK if successful.
+*/
+int dsa_generate_key(prng_state *prng, int wprng, dsa_key *key)
+{
+  int err;
+
+  LTC_ARGCHK(key         != NULL);
+  LTC_ARGCHK(ltc_mp.name != NULL);
+
+  /* so now we have our DH structure, generator g, order q, modulus p
+     Now we need a random exponent [mod q] and it's power g^x mod p
+   */
+  /* private key x should be from range: 1 <= x <= q-1 (see FIPS 186-4 B.1.2) */
+  if ((err = rand_bn_upto(key->x, key->q, prng, wprng)) != CRYPT_OK)          { return err; }
+  if ((err = mp_exptmod(key->g, key->x, key->p, key->y)) != CRYPT_OK)            { return err; }
+  key->type = PK_PRIVATE;
+
+  return CRYPT_OK;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/pk/dsa/dsa_generate_pqg.c b/libtomcrypt/src/pk/dsa/dsa_generate_pqg.c
new file mode 100644 (file)
index 0000000..8c5f558
--- /dev/null
@@ -0,0 +1,244 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+   @file dsa_generate_pqg.c
+   DSA implementation - generate DSA parameters p, q & g
+*/
+
+#ifdef LTC_MDSA
+
+/**
+  Create DSA parameters (INTERNAL ONLY, not part of public API)
+  @param prng          An active PRNG state
+  @param wprng         The index of the PRNG desired
+  @param group_size    Size of the multiplicative group (octets)
+  @param modulus_size  Size of the modulus (octets)
+  @param p             [out] bignum where generated 'p' is stored (must be initialized by caller)
+  @param q             [out] bignum where generated 'q' is stored (must be initialized by caller)
+  @param g             [out] bignum where generated 'g' is stored (must be initialized by caller)
+  @return CRYPT_OK if successful, upon error this function will free all allocated memory
+*/
+static int _dsa_make_params(prng_state *prng, int wprng, int group_size, int modulus_size, void *p, void *q, void *g)
+{
+  unsigned long L, N, n, outbytes, seedbytes, counter, j, i;
+  int err, res, mr_tests_q, mr_tests_p, found_p, found_q, hash;
+  unsigned char *wbuf, *sbuf, digest[MAXBLOCKSIZE];
+  void *t2L1, *t2N1, *t2q, *t2seedlen, *U, *W, *X, *c, *h, *e, *seedinc;
+
+  /* check size */
+  if (group_size >= LTC_MDSA_MAX_GROUP || group_size < 1 || group_size >= modulus_size) {
+    return CRYPT_INVALID_ARG;
+  }
+
+ /* FIPS-186-4 A.1.1.2 Generation of the Probable Primes p and q Using an Approved Hash Function
+  *
+  * L = The desired length of the prime p (in bits e.g. L = 1024)
+  * N = The desired length of the prime q (in bits e.g. N = 160)
+  * seedlen = The desired bit length of the domain parameter seed; seedlen shallbe equal to or greater than N
+  * outlen  = The bit length of Hash function
+  *
+  * 1.  Check that the (L, N)
+  * 2.  If (seedlen <N), then return INVALID.
+  * 3.  n = ceil(L / outlen) - 1
+  * 4.  b = L- 1 - (n * outlen)
+  * 5.  domain_parameter_seed = an arbitrary sequence of seedlen bits
+  * 6.  U = Hash (domain_parameter_seed) mod 2^(N-1)
+  * 7.  q = 2^(N-1) + U + 1 - (U mod 2)
+  * 8.  Test whether or not q is prime as specified in Appendix C.3
+  * 9.  If qis not a prime, then go to step 5.
+  * 10. offset = 1
+  * 11. For counter = 0 to (4L- 1) do {
+  *       For j=0 to n do {
+  *         Vj = Hash ((domain_parameter_seed+ offset + j) mod 2^seedlen
+  *       }
+  *       W = V0 + (V1 *2^outlen) + ... + (Vn-1 * 2^((n-1) * outlen)) + ((Vn mod 2^b) * 2^(n * outlen))
+  *       X = W + 2^(L-1)           Comment: 0 <= W < 2^(L-1); hence 2^(L-1) <= X < 2^L
+  *       c = X mod 2*q
+  *       p = X - (c - 1)           Comment: p ~ 1 (mod 2*q)
+  *       If (p >= 2^(L-1)) {
+  *         Test whether or not p is prime as specified in Appendix C.3.
+  *         If p is determined to be prime, then return VALID and the values of p, qand (optionally) the values of domain_parameter_seed and counter
+  *       }
+  *       offset = offset + n + 1   Comment: Increment offset
+  *     }
+  */
+
+  seedbytes = group_size;
+  L = (unsigned long)modulus_size * 8;
+  N = (unsigned long)group_size * 8;
+
+  /* XXX-TODO no Lucas test */
+#ifdef LTC_MPI_HAS_LUCAS_TEST
+  /* M-R tests (when followed by one Lucas test) according FIPS-186-4 - Appendix C.3 - table C.1 */
+  mr_tests_p = (L <= 2048) ? 3 : 2;
+  if      (N <= 160)  { mr_tests_q = 19; }
+  else if (N <= 224)  { mr_tests_q = 24; }
+  else                { mr_tests_q = 27; }
+#else
+  /* M-R tests (without Lucas test) according FIPS-186-4 - Appendix C.3 - table C.1 */
+  if      (L <= 1024) { mr_tests_p = 40; }
+  else if (L <= 2048) { mr_tests_p = 56; }
+  else                { mr_tests_p = 64; }
+
+  if      (N <= 160)  { mr_tests_q = 40; }
+  else if (N <= 224)  { mr_tests_q = 56; }
+  else                { mr_tests_q = 64; }
+#endif
+
+  if (N <= 256) {
+    hash = register_hash(&sha256_desc);
+  }
+  else if (N <= 384) {
+    hash = register_hash(&sha384_desc);
+  }
+  else if (N <= 512) {
+    hash = register_hash(&sha512_desc);
+  }
+  else {
+    return CRYPT_INVALID_ARG; /* group_size too big */
+  }
+
+  if ((err = hash_is_valid(hash)) != CRYPT_OK)                                   { return err; }
+  outbytes = hash_descriptor[hash].hashsize;
+
+  n = ((L + outbytes*8 - 1) / (outbytes*8)) - 1;
+
+  if ((wbuf = XMALLOC((n+1)*outbytes)) == NULL)                                  { err = CRYPT_MEM; goto cleanup3; }
+  if ((sbuf = XMALLOC(seedbytes)) == NULL)                                       { err = CRYPT_MEM; goto cleanup2; }
+
+  err = mp_init_multi(&t2L1, &t2N1, &t2q, &t2seedlen, &U, &W, &X, &c, &h, &e, &seedinc, NULL);
+  if (err != CRYPT_OK)                                                           { goto cleanup1; }
+
+  if ((err = mp_2expt(t2L1, L-1)) != CRYPT_OK)                                   { goto cleanup; }
+  /* t2L1 = 2^(L-1) */
+  if ((err = mp_2expt(t2N1, N-1)) != CRYPT_OK)                                   { goto cleanup; }
+  /* t2N1 = 2^(N-1) */
+  if ((err = mp_2expt(t2seedlen, seedbytes*8)) != CRYPT_OK)                      { goto cleanup; }
+  /* t2seedlen = 2^seedlen */
+
+  for(found_p=0; !found_p;) {
+    /* q */
+    for(found_q=0; !found_q;) {
+      if (prng_descriptor[wprng].read(sbuf, seedbytes, prng) != seedbytes)       { err = CRYPT_ERROR_READPRNG; goto cleanup; }
+      i = outbytes;
+      if ((err = hash_memory(hash, sbuf, seedbytes, digest, &i)) != CRYPT_OK)    { goto cleanup; }
+      if ((err = mp_read_unsigned_bin(U, digest, outbytes)) != CRYPT_OK)         { goto cleanup; }
+      if ((err = mp_mod(U, t2N1, U)) != CRYPT_OK)                                { goto cleanup; }
+      if ((err = mp_add(t2N1, U, q)) != CRYPT_OK)                                { goto cleanup; }
+      if (!mp_isodd(q)) mp_add_d(q, 1, q);
+      if ((err = mp_prime_is_prime(q, mr_tests_q, &res)) != CRYPT_OK)            { goto cleanup; }
+      if (res == LTC_MP_YES) found_q = 1;
+    }
+
+    /* p */
+    if ((err = mp_read_unsigned_bin(seedinc, sbuf, seedbytes)) != CRYPT_OK)      { goto cleanup; }
+    if ((err = mp_add(q, q, t2q)) != CRYPT_OK)                                   { goto cleanup; }
+    for(counter=0; counter < 4*L && !found_p; counter++) {
+      for(j=0; j<=n; j++) {
+        if ((err = mp_add_d(seedinc, 1, seedinc)) != CRYPT_OK)                   { goto cleanup; }
+        if ((err = mp_mod(seedinc, t2seedlen, seedinc)) != CRYPT_OK)             { goto cleanup; }
+        /* seedinc = (seedinc+1) % 2^seed_bitlen */
+        if ((i = mp_unsigned_bin_size(seedinc)) > seedbytes)                     { err = CRYPT_INVALID_ARG; goto cleanup; }
+        zeromem(sbuf, seedbytes);
+        if ((err = mp_to_unsigned_bin(seedinc, sbuf + seedbytes-i)) != CRYPT_OK) { goto cleanup; }
+        i = outbytes;
+        err = hash_memory(hash, sbuf, seedbytes, wbuf+(n-j)*outbytes, &i);
+        if (err != CRYPT_OK)                                                     { goto cleanup; }
+      }
+      if ((err = mp_read_unsigned_bin(W, wbuf, (n+1)*outbytes)) != CRYPT_OK)     { goto cleanup; }
+      if ((err = mp_mod(W, t2L1, W)) != CRYPT_OK)                                { goto cleanup; }
+      if ((err = mp_add(W, t2L1, X)) != CRYPT_OK)                                { goto cleanup; }
+      if ((err = mp_mod(X, t2q, c))  != CRYPT_OK)                                { goto cleanup; }
+      if ((err = mp_sub_d(c, 1, p))  != CRYPT_OK)                                { goto cleanup; }
+      if ((err = mp_sub(X, p, p))    != CRYPT_OK)                                { goto cleanup; }
+      if (mp_cmp(p, t2L1) != LTC_MP_LT) {
+        /* p >= 2^(L-1) */
+        if ((err = mp_prime_is_prime(p, mr_tests_p, &res)) != CRYPT_OK)          { goto cleanup; }
+        if (res == LTC_MP_YES) {
+          found_p = 1;
+        }
+      }
+    }
+  }
+
+ /* FIPS-186-4 A.2.1 Unverifiable Generation of the Generator g
+  * 1. e = (p - 1)/q
+  * 2. h = any integer satisfying: 1 < h < (p - 1)
+  *    h could be obtained from a random number generator or from a counter that changes after each use
+  * 3. g = h^e mod p
+  * 4. if (g == 1), then go to step 2.
+  *
+  */
+
+  if ((err = mp_sub_d(p, 1, e)) != CRYPT_OK)                                     { goto cleanup; }
+  if ((err = mp_div(e, q, e, c)) != CRYPT_OK)                                    { goto cleanup; }
+  /* e = (p - 1)/q */
+  i = mp_count_bits(p);
+  do {
+    do {
+      if ((err = rand_bn_bits(h, i, prng, wprng)) != CRYPT_OK)                   { goto cleanup; }
+    } while (mp_cmp(h, p) != LTC_MP_LT || mp_cmp_d(h, 2) != LTC_MP_GT);
+    if ((err = mp_sub_d(h, 1, h)) != CRYPT_OK)                                   { goto cleanup; }
+    /* h is randon and 1 < h < (p-1) */
+    if ((err = mp_exptmod(h, e, p, g)) != CRYPT_OK)                              { goto cleanup; }
+  } while (mp_cmp_d(g, 1) == LTC_MP_EQ);
+
+  err = CRYPT_OK;
+cleanup:
+  mp_clear_multi(t2L1, t2N1, t2q, t2seedlen, U, W, X, c, h, e, seedinc, NULL);
+cleanup1:
+  XFREE(sbuf);
+cleanup2:
+  XFREE(wbuf);
+cleanup3:
+  return err;
+}
+
+/**
+  Generate DSA parameters p, q & g
+  @param prng          An active PRNG state
+  @param wprng         The index of the PRNG desired
+  @param group_size    Size of the multiplicative group (octets)
+  @param modulus_size  Size of the modulus (octets)
+  @param key           [out] Where to store the created key
+  @return CRYPT_OK if successful.
+*/
+int dsa_generate_pqg(prng_state *prng, int wprng, int group_size, int modulus_size, dsa_key *key)
+{
+   int err;
+
+   LTC_ARGCHK(key         != NULL);
+   LTC_ARGCHK(ltc_mp.name != NULL);
+
+   /* init mp_ints */
+   if ((err = mp_init_multi(&key->p, &key->g, &key->q, &key->x, &key->y, NULL)) != CRYPT_OK) {
+      return err;
+   }
+   /* generate params */
+   err = _dsa_make_params(prng, wprng, group_size, modulus_size, key->p, key->q, key->g);
+   if (err != CRYPT_OK) {
+      goto cleanup;
+   }
+
+   key->qord = group_size;
+
+   return CRYPT_OK;
+
+cleanup:
+   dsa_free(key);
+   return err;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/pk/dsa/dsa_import.c b/libtomcrypt/src/pk/dsa/dsa_import.c
new file mode 100644 (file)
index 0000000..e6a7560
--- /dev/null
@@ -0,0 +1,152 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+   @file dsa_import.c
+   DSA implementation, import a DSA key, Tom St Denis
+*/
+
+#ifdef LTC_MDSA
+
+/**
+   Import a DSA key
+   @param in       The binary packet to import from
+   @param inlen    The length of the binary packet
+   @param key      [out] Where to store the imported key
+   @return CRYPT_OK if successful, upon error this function will free all allocated memory
+*/
+int dsa_import(const unsigned char *in, unsigned long inlen, dsa_key *key)
+{
+   int           err, stat;
+   unsigned long zero = 0;
+   unsigned char* tmpbuf = NULL;
+   unsigned char flags[1];
+
+   LTC_ARGCHK(in  != NULL);
+   LTC_ARGCHK(key != NULL);
+   LTC_ARGCHK(ltc_mp.name != NULL);
+
+   /* init key */
+   if (mp_init_multi(&key->p, &key->g, &key->q, &key->x, &key->y, NULL) != CRYPT_OK) {
+      return CRYPT_MEM;
+   }
+
+   /* try to match the old libtomcrypt format */
+   err = der_decode_sequence_multi(in, inlen, LTC_ASN1_BIT_STRING, 1UL, flags,
+                                              LTC_ASN1_EOL,        0UL, NULL);
+
+   if (err == CRYPT_OK || err == CRYPT_INPUT_TOO_LONG) {
+       /* private key */
+       if (flags[0] == 1) {
+           if ((err = der_decode_sequence_multi(in, inlen,
+                                  LTC_ASN1_BIT_STRING,   1UL, flags,
+                                  LTC_ASN1_INTEGER,      1UL, key->g,
+                                  LTC_ASN1_INTEGER,      1UL, key->p,
+                                  LTC_ASN1_INTEGER,      1UL, key->q,
+                                  LTC_ASN1_INTEGER,      1UL, key->y,
+                                  LTC_ASN1_INTEGER,      1UL, key->x,
+                                  LTC_ASN1_EOL,          0UL, NULL)) != CRYPT_OK) {
+               goto LBL_ERR;
+           }
+           key->type = PK_PRIVATE;
+           goto LBL_OK;
+       }
+       /* public key */
+       else if (flags[0] == 0) {
+           if ((err = der_decode_sequence_multi(in, inlen,
+                                      LTC_ASN1_BIT_STRING,   1UL, flags,
+                                      LTC_ASN1_INTEGER,      1UL, key->g,
+                                      LTC_ASN1_INTEGER,      1UL, key->p,
+                                      LTC_ASN1_INTEGER,      1UL, key->q,
+                                      LTC_ASN1_INTEGER,      1UL, key->y,
+                                      LTC_ASN1_EOL,          0UL, NULL)) != CRYPT_OK) {
+               goto LBL_ERR;
+           }
+           key->type = PK_PUBLIC;
+           goto LBL_OK;
+       }
+       else {
+          err = CRYPT_INVALID_PACKET;
+          goto LBL_ERR;
+       }
+   }
+   /* get key type */
+   if ((err = der_decode_sequence_multi(in, inlen,
+                          LTC_ASN1_SHORT_INTEGER, 1UL, &zero,
+                          LTC_ASN1_INTEGER,      1UL, key->p,
+                          LTC_ASN1_INTEGER,      1UL, key->q,
+                          LTC_ASN1_INTEGER,      1UL, key->g,
+                          LTC_ASN1_INTEGER,      1UL, key->y,
+                          LTC_ASN1_INTEGER,      1UL, key->x,
+                          LTC_ASN1_EOL,          0UL, NULL)) == CRYPT_OK) {
+
+       key->type = PK_PRIVATE;
+   } else { /* public */
+      ltc_asn1_list params[3];
+      unsigned long tmpbuf_len = inlen;
+
+      LTC_SET_ASN1(params, 0, LTC_ASN1_INTEGER, key->p, 1UL);
+      LTC_SET_ASN1(params, 1, LTC_ASN1_INTEGER, key->q, 1UL);
+      LTC_SET_ASN1(params, 2, LTC_ASN1_INTEGER, key->g, 1UL);
+
+      tmpbuf = XCALLOC(1, tmpbuf_len);
+      if (tmpbuf == NULL) {
+         err = CRYPT_MEM;
+         goto LBL_ERR;
+      }
+
+      err = der_decode_subject_public_key_info(in, inlen, PKA_DSA,
+                                               tmpbuf, &tmpbuf_len,
+                                               LTC_ASN1_SEQUENCE, params, 3);
+      if (err != CRYPT_OK) {
+         XFREE(tmpbuf);
+         goto LBL_ERR;
+      }
+
+      if ((err=der_decode_integer(tmpbuf, tmpbuf_len, key->y)) != CRYPT_OK) {
+         XFREE(tmpbuf);
+         goto LBL_ERR;
+      }
+
+      XFREE(tmpbuf);
+      key->type = PK_PUBLIC;
+   }
+
+LBL_OK:
+   key->qord = mp_unsigned_bin_size(key->q);
+
+   /* quick p, q, g validation, without primality testing */
+   if ((err = dsa_int_validate_pqg(key, &stat)) != CRYPT_OK) {
+      goto LBL_ERR;
+   }
+   if (stat == 0) {
+      err = CRYPT_INVALID_PACKET;
+      goto LBL_ERR;
+   }
+   /* validate x, y */
+   if ((err = dsa_int_validate_xy(key, &stat)) != CRYPT_OK) {
+      goto LBL_ERR;
+   }
+   if (stat == 0) {
+      err = CRYPT_INVALID_PACKET;
+      goto LBL_ERR;
+   }
+
+  return CRYPT_OK;
+LBL_ERR:
+   dsa_free(key);
+   return err;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/pk/dsa/dsa_make_key.c b/libtomcrypt/src/pk/dsa/dsa_make_key.c
new file mode 100644 (file)
index 0000000..8ac08f8
--- /dev/null
@@ -0,0 +1,41 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+   @file dsa_make_key.c
+   DSA implementation, generate a DSA key
+*/
+
+#ifdef LTC_MDSA
+
+/**
+  Old-style creation of a DSA key
+  @param prng          An active PRNG state
+  @param wprng         The index of the PRNG desired
+  @param group_size    Size of the multiplicative group (octets)
+  @param modulus_size  Size of the modulus (octets)
+  @param key           [out] Where to store the created key
+  @return CRYPT_OK if successful.
+*/
+int dsa_make_key(prng_state *prng, int wprng, int group_size, int modulus_size, dsa_key *key)
+{
+  int err;
+
+  if ((err = dsa_generate_pqg(prng, wprng, group_size, modulus_size, key)) != CRYPT_OK) { return err; }
+  if ((err = dsa_generate_key(prng, wprng, key)) != CRYPT_OK) { return err; }
+
+  return CRYPT_OK;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/pk/dsa/dsa_set.c b/libtomcrypt/src/pk/dsa/dsa_set.c
new file mode 100644 (file)
index 0000000..a4d4042
--- /dev/null
@@ -0,0 +1,112 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+
+#ifdef LTC_MDSA
+
+/**
+  Import DSA's p, q & g from raw numbers
+  @param p       DSA's p  in binary representation
+  @param plen    The length of p
+  @param q       DSA's q  in binary representation
+  @param qlen    The length of q
+  @param g       DSA's g  in binary representation
+  @param glen    The length of g
+  @param key     [out] the destination for the imported key
+  @return CRYPT_OK if successful.
+*/
+int dsa_set_pqg(const unsigned char *p,  unsigned long plen,
+                const unsigned char *q,  unsigned long qlen,
+                const unsigned char *g,  unsigned long glen,
+                dsa_key *key)
+{
+   int err, stat;
+
+   LTC_ARGCHK(p           != NULL);
+   LTC_ARGCHK(q           != NULL);
+   LTC_ARGCHK(g           != NULL);
+   LTC_ARGCHK(key         != NULL);
+   LTC_ARGCHK(ltc_mp.name != NULL);
+
+   /* init key */
+   err = mp_init_multi(&key->p, &key->g, &key->q, &key->x, &key->y, NULL);
+   if (err != CRYPT_OK) return err;
+
+   if ((err = mp_read_unsigned_bin(key->p, (unsigned char *)p , plen)) != CRYPT_OK) { goto LBL_ERR; }
+   if ((err = mp_read_unsigned_bin(key->g, (unsigned char *)g , glen)) != CRYPT_OK) { goto LBL_ERR; }
+   if ((err = mp_read_unsigned_bin(key->q, (unsigned char *)q , qlen)) != CRYPT_OK) { goto LBL_ERR; }
+
+   key->qord = mp_unsigned_bin_size(key->q);
+
+   /* do only a quick validation, without primality testing */
+   if ((err = dsa_int_validate_pqg(key, &stat)) != CRYPT_OK)                        { goto LBL_ERR; }
+   if (stat == 0) {
+      err = CRYPT_INVALID_PACKET;
+      goto LBL_ERR;
+   }
+
+   return CRYPT_OK;
+
+LBL_ERR:
+   dsa_free(key);
+   return err;
+}
+
+/**
+  Import DSA public or private key-part from raw numbers
+
+     NB: The p, q & g parts must be set beforehand
+
+  @param in      The key-part to import, either public or private.
+  @param inlen   The key-part's length
+  @param type    Which type of key (PK_PRIVATE or PK_PUBLIC)
+  @param key     [out] the destination for the imported key
+  @return CRYPT_OK if successful.
+*/
+int dsa_set_key(const unsigned char *in, unsigned long inlen, int type, dsa_key *key)
+{
+   int err, stat = 0;
+
+   LTC_ARGCHK(key         != NULL);
+   LTC_ARGCHK(key->x      != NULL);
+   LTC_ARGCHK(key->y      != NULL);
+   LTC_ARGCHK(key->p      != NULL);
+   LTC_ARGCHK(key->g      != NULL);
+   LTC_ARGCHK(key->q      != NULL);
+   LTC_ARGCHK(ltc_mp.name != NULL);
+
+   if (type == PK_PRIVATE) {
+      key->type = PK_PRIVATE;
+      if ((err = mp_read_unsigned_bin(key->x, (unsigned char *)in, inlen)) != CRYPT_OK) { goto LBL_ERR; }
+      if ((err = mp_exptmod(key->g, key->x, key->p, key->y)) != CRYPT_OK)               { goto LBL_ERR; }
+   }
+   else {
+      key->type = PK_PUBLIC;
+      if ((err = mp_read_unsigned_bin(key->y, (unsigned char *)in, inlen)) != CRYPT_OK) { goto LBL_ERR; }
+   }
+
+   if ((err = dsa_int_validate_xy(key, &stat)) != CRYPT_OK)                             { goto LBL_ERR; }
+   if (stat == 0) {
+      err = CRYPT_INVALID_PACKET;
+      goto LBL_ERR;
+   }
+
+   return CRYPT_OK;
+
+LBL_ERR:
+   dsa_free(key);
+   return err;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/pk/dsa/dsa_set_pqg_dsaparam.c b/libtomcrypt/src/pk/dsa/dsa_set_pqg_dsaparam.c
new file mode 100644 (file)
index 0000000..edbed1c
--- /dev/null
@@ -0,0 +1,67 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+
+#ifdef LTC_MDSA
+
+/**
+  Import DSA's p, q & g from dsaparam
+
+      dsaparam data: openssl dsaparam -outform DER -out dsaparam.der 2048
+
+  @param dsaparam    The DSA param DER encoded data
+  @param dsaparamlen The length of dhparam data
+  @param key         [out] the destination for the imported key
+  @return CRYPT_OK if successful.
+*/
+int dsa_set_pqg_dsaparam(const unsigned char *dsaparam, unsigned long dsaparamlen,
+                         dsa_key *key)
+{
+   int err, stat;
+
+   LTC_ARGCHK(dsaparam    != NULL);
+   LTC_ARGCHK(key         != NULL);
+   LTC_ARGCHK(ltc_mp.name != NULL);
+
+   /* init key */
+   err = mp_init_multi(&key->p, &key->g, &key->q, &key->x, &key->y, NULL);
+   if (err != CRYPT_OK) return err;
+
+   if ((err = der_decode_sequence_multi(dsaparam, dsaparamlen,
+                                        LTC_ASN1_INTEGER, 1UL, key->p,
+                                        LTC_ASN1_INTEGER, 1UL, key->q,
+                                        LTC_ASN1_INTEGER, 1UL, key->g,
+                                        LTC_ASN1_EOL,     0UL, NULL)) != CRYPT_OK) {
+      goto LBL_ERR;
+   }
+
+   key->qord = mp_unsigned_bin_size(key->q);
+
+   /* quick p, q, g validation, without primality testing */
+   if ((err = dsa_int_validate_pqg(key, &stat)) != CRYPT_OK) {
+      goto LBL_ERR;
+   }
+   if (stat == 0) {
+      err = CRYPT_INVALID_PACKET;
+      goto LBL_ERR;
+   }
+
+   return CRYPT_OK;
+
+LBL_ERR:
+   dsa_free(key);
+   return err;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/pk/dsa/dsa_shared_secret.c b/libtomcrypt/src/pk/dsa/dsa_shared_secret.c
new file mode 100644 (file)
index 0000000..4c18261
--- /dev/null
@@ -0,0 +1,70 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file dsa_shared_secret.c
+  DSA Crypto, Tom St Denis
+*/
+
+#ifdef LTC_MDSA
+
+/**
+  Create a DSA shared secret between two keys
+  @param private_key      The private DSA key (the exponent)
+  @param base             The base of the exponentiation (allows this to be used for both encrypt and decrypt)
+  @param public_key       The public key
+  @param out              [out] Destination of the shared secret
+  @param outlen           [in/out] The max size and resulting size of the shared secret
+  @return CRYPT_OK if successful
+*/
+int dsa_shared_secret(void          *private_key, void *base,
+                      dsa_key       *public_key,
+                      unsigned char *out,         unsigned long *outlen)
+{
+   unsigned long  x;
+   void          *res;
+   int            err;
+
+   LTC_ARGCHK(private_key != NULL);
+   LTC_ARGCHK(public_key  != NULL);
+   LTC_ARGCHK(out         != NULL);
+   LTC_ARGCHK(outlen      != NULL);
+
+   /* make new point */
+   if ((err = mp_init(&res)) != CRYPT_OK) {
+      return err;
+   }
+
+   if ((err = mp_exptmod(base, private_key, public_key->p, res)) != CRYPT_OK) {
+      mp_clear(res);
+      return err;
+   }
+
+   x = (unsigned long)mp_unsigned_bin_size(res);
+   if (*outlen < x) {
+      *outlen = x;
+      err = CRYPT_BUFFER_OVERFLOW;
+      goto done;
+   }
+   zeromem(out, x);
+   if ((err = mp_to_unsigned_bin(res, out + (x - mp_unsigned_bin_size(res))))   != CRYPT_OK)          { goto done; }
+
+   err     = CRYPT_OK;
+   *outlen = x;
+done:
+   mp_clear(res);
+   return err;
+}
+
+#endif
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
+
diff --git a/libtomcrypt/src/pk/dsa/dsa_sign_hash.c b/libtomcrypt/src/pk/dsa/dsa_sign_hash.c
new file mode 100644 (file)
index 0000000..fda2ca1
--- /dev/null
@@ -0,0 +1,152 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+   @file dsa_sign_hash.c
+   DSA implementation, sign a hash, Tom St Denis
+*/
+
+#ifdef LTC_MDSA
+
+/**
+  Sign a hash with DSA
+  @param in       The hash to sign
+  @param inlen    The length of the hash to sign
+  @param r        The "r" integer of the signature (caller must initialize with mp_init() first)
+  @param s        The "s" integer of the signature (caller must initialize with mp_init() first)
+  @param prng     An active PRNG state
+  @param wprng    The index of the PRNG desired
+  @param key      A private DSA key
+  @return CRYPT_OK if successful
+*/
+int dsa_sign_hash_raw(const unsigned char *in,  unsigned long inlen,
+                                   void   *r,   void *s,
+                               prng_state *prng, int wprng, dsa_key *key)
+{
+   void         *k, *kinv, *tmp;
+   unsigned char *buf;
+   int            err, qbits;
+
+   LTC_ARGCHK(in  != NULL);
+   LTC_ARGCHK(r   != NULL);
+   LTC_ARGCHK(s   != NULL);
+   LTC_ARGCHK(key != NULL);
+
+   if ((err = prng_is_valid(wprng)) != CRYPT_OK) {
+      return err;
+   }
+   if (key->type != PK_PRIVATE) {
+      return CRYPT_PK_NOT_PRIVATE;
+   }
+
+   /* check group order size  */
+   if (key->qord >= LTC_MDSA_MAX_GROUP) {
+      return CRYPT_INVALID_ARG;
+   }
+
+   buf = XMALLOC(LTC_MDSA_MAX_GROUP);
+   if (buf == NULL) {
+      return CRYPT_MEM;
+   }
+
+   /* Init our temps */
+   if ((err = mp_init_multi(&k, &kinv, &tmp, NULL)) != CRYPT_OK)                       { goto ERRBUF; }
+
+   qbits = mp_count_bits(key->q);
+retry:
+
+   do {
+      /* gen random k */
+      if ((err = rand_bn_bits(k, qbits, prng, wprng)) != CRYPT_OK)                     { goto error; }
+
+      /* k should be from range: 1 <= k <= q-1 (see FIPS 186-4 B.2.2) */
+      if (mp_cmp_d(k, 0) != LTC_MP_GT || mp_cmp(k, key->q) != LTC_MP_LT)               { goto retry; }
+
+      /* test gcd */
+      if ((err = mp_gcd(k, key->q, tmp)) != CRYPT_OK)                                  { goto error; }
+   } while (mp_cmp_d(tmp, 1) != LTC_MP_EQ);
+
+   /* now find 1/k mod q */
+   if ((err = mp_invmod(k, key->q, kinv)) != CRYPT_OK)                                 { goto error; }
+
+   /* now find r = g^k mod p mod q */
+   if ((err = mp_exptmod(key->g, k, key->p, r)) != CRYPT_OK)                           { goto error; }
+   if ((err = mp_mod(r, key->q, r)) != CRYPT_OK)                                       { goto error; }
+
+   if (mp_iszero(r) == LTC_MP_YES)                                                     { goto retry; }
+
+   /* FIPS 186-4 4.6: use leftmost min(bitlen(q), bitlen(hash)) bits of 'hash'*/
+   inlen = MIN(inlen, (unsigned long)(key->qord));
+
+   /* now find s = (in + xr)/k mod q */
+   if ((err = mp_read_unsigned_bin(tmp, (unsigned char *)in, inlen)) != CRYPT_OK)      { goto error; }
+   if ((err = mp_mul(key->x, r, s)) != CRYPT_OK)                                       { goto error; }
+   if ((err = mp_add(s, tmp, s)) != CRYPT_OK)                                          { goto error; }
+   if ((err = mp_mulmod(s, kinv, key->q, s)) != CRYPT_OK)                              { goto error; }
+
+   if (mp_iszero(s) == LTC_MP_YES)                                                     { goto retry; }
+
+   err = CRYPT_OK;
+error:
+   mp_clear_multi(k, kinv, tmp, NULL);
+ERRBUF:
+#ifdef LTC_CLEAN_STACK
+   zeromem(buf, LTC_MDSA_MAX_GROUP);
+#endif
+   XFREE(buf);
+   return err;
+}
+
+/**
+  Sign a hash with DSA
+  @param in       The hash to sign
+  @param inlen    The length of the hash to sign
+  @param out      [out] Where to store the signature
+  @param outlen   [in/out] The max size and resulting size of the signature
+  @param prng     An active PRNG state
+  @param wprng    The index of the PRNG desired
+  @param key      A private DSA key
+  @return CRYPT_OK if successful
+*/
+int dsa_sign_hash(const unsigned char *in,  unsigned long inlen,
+                        unsigned char *out, unsigned long *outlen,
+                        prng_state *prng, int wprng, dsa_key *key)
+{
+   void         *r, *s;
+   int           err;
+
+   LTC_ARGCHK(in      != NULL);
+   LTC_ARGCHK(out     != NULL);
+   LTC_ARGCHK(outlen  != NULL);
+   LTC_ARGCHK(key     != NULL);
+
+   if (mp_init_multi(&r, &s, NULL) != CRYPT_OK) {
+      return CRYPT_MEM;
+   }
+
+   if ((err = dsa_sign_hash_raw(in, inlen, r, s, prng, wprng, key)) != CRYPT_OK) {
+      goto error;
+   }
+
+   err = der_encode_sequence_multi(out, outlen,
+                             LTC_ASN1_INTEGER, 1UL, r,
+                             LTC_ASN1_INTEGER, 1UL, s,
+                             LTC_ASN1_EOL,     0UL, NULL);
+
+error:
+   mp_clear_multi(r, s, NULL);
+   return err;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/pk/dsa/dsa_verify_hash.c b/libtomcrypt/src/pk/dsa/dsa_verify_hash.c
new file mode 100644 (file)
index 0000000..3d3fab5
--- /dev/null
@@ -0,0 +1,137 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+   @file dsa_verify_hash.c
+   DSA implementation, verify a signature, Tom St Denis
+*/
+
+
+#ifdef LTC_MDSA
+
+/**
+  Verify a DSA signature
+  @param r        DSA "r" parameter
+  @param s        DSA "s" parameter
+  @param hash     The hash that was signed
+  @param hashlen  The length of the hash that was signed
+  @param stat     [out] The result of the signature verification, 1==valid, 0==invalid
+  @param key      The corresponding public DSA key
+  @return CRYPT_OK if successful (even if the signature is invalid)
+*/
+int dsa_verify_hash_raw(         void   *r,          void   *s,
+                    const unsigned char *hash, unsigned long hashlen,
+                                    int *stat,      dsa_key *key)
+{
+   void          *w, *v, *u1, *u2;
+   int           err;
+
+   LTC_ARGCHK(r    != NULL);
+   LTC_ARGCHK(s    != NULL);
+   LTC_ARGCHK(stat != NULL);
+   LTC_ARGCHK(key  != NULL);
+
+   /* default to invalid signature */
+   *stat = 0;
+
+   /* init our variables */
+   if ((err = mp_init_multi(&w, &v, &u1, &u2, NULL)) != CRYPT_OK) {
+      return err;
+   }
+
+   /* neither r or s can be null or >q*/
+   if (mp_cmp_d(r, 0) != LTC_MP_GT || mp_cmp_d(s, 0) != LTC_MP_GT || mp_cmp(r, key->q) != LTC_MP_LT || mp_cmp(s, key->q) != LTC_MP_LT) {
+      err = CRYPT_INVALID_PACKET;
+      goto error;
+   }
+
+   /* FIPS 186-4 4.7: use leftmost min(bitlen(q), bitlen(hash)) bits of 'hash' */
+   hashlen = MIN(hashlen, (unsigned long)(key->qord));
+
+   /* w = 1/s mod q */
+   if ((err = mp_invmod(s, key->q, w)) != CRYPT_OK)                                       { goto error; }
+
+   /* u1 = m * w mod q */
+   if ((err = mp_read_unsigned_bin(u1, (unsigned char *)hash, hashlen)) != CRYPT_OK)      { goto error; }
+   if ((err = mp_mulmod(u1, w, key->q, u1)) != CRYPT_OK)                                  { goto error; }
+
+   /* u2 = r*w mod q */
+   if ((err = mp_mulmod(r, w, key->q, u2)) != CRYPT_OK)                                   { goto error; }
+
+   /* v = g^u1 * y^u2 mod p mod q */
+   if ((err = mp_exptmod(key->g, u1, key->p, u1)) != CRYPT_OK)                            { goto error; }
+   if ((err = mp_exptmod(key->y, u2, key->p, u2)) != CRYPT_OK)                            { goto error; }
+   if ((err = mp_mulmod(u1, u2, key->p, v)) != CRYPT_OK)                                  { goto error; }
+   if ((err = mp_mod(v, key->q, v)) != CRYPT_OK)                                          { goto error; }
+
+   /* if r = v then we're set */
+   if (mp_cmp(r, v) == LTC_MP_EQ) {
+      *stat = 1;
+   }
+
+   err = CRYPT_OK;
+error:
+   mp_clear_multi(w, v, u1, u2, NULL);
+   return err;
+}
+
+/**
+  Verify a DSA signature
+  @param sig      The signature
+  @param siglen   The length of the signature (octets)
+  @param hash     The hash that was signed
+  @param hashlen  The length of the hash that was signed
+  @param stat     [out] The result of the signature verification, 1==valid, 0==invalid
+  @param key      The corresponding public DSA key
+  @return CRYPT_OK if successful (even if the signature is invalid)
+*/
+int dsa_verify_hash(const unsigned char *sig, unsigned long siglen,
+                    const unsigned char *hash, unsigned long hashlen,
+                    int *stat, dsa_key *key)
+{
+   int    err;
+   void   *r, *s;
+   ltc_asn1_list sig_seq[2];
+   unsigned long reallen = 0;
+
+   LTC_ARGCHK(stat != NULL);
+   *stat = 0; /* must be set before the first return */
+
+   if ((err = mp_init_multi(&r, &s, NULL)) != CRYPT_OK) {
+      return err;
+   }
+
+   LTC_SET_ASN1(sig_seq, 0, LTC_ASN1_INTEGER, r, 1UL);
+   LTC_SET_ASN1(sig_seq, 1, LTC_ASN1_INTEGER, s, 1UL);
+
+   err = der_decode_sequence(sig, siglen, sig_seq, 2);
+   if (err != CRYPT_OK) {
+      goto LBL_ERR;
+   }
+
+   err = der_length_sequence(sig_seq, 2, &reallen);
+   if (err != CRYPT_OK || reallen != siglen) {
+      goto LBL_ERR;
+   }
+
+   /* do the op */
+   err = dsa_verify_hash_raw(r, s, hash, hashlen, stat, key);
+
+LBL_ERR:
+   mp_clear_multi(r, s, NULL);
+   return err;
+}
+
+#endif
+
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/pk/dsa/dsa_verify_key.c b/libtomcrypt/src/pk/dsa/dsa_verify_key.c
new file mode 100644 (file)
index 0000000..258e6cb
--- /dev/null
@@ -0,0 +1,199 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+   @file dsa_verify_key.c
+   DSA implementation, verify a key, Tom St Denis
+*/
+
+#ifdef LTC_MDSA
+
+/**
+   Validate a DSA key
+
+     Yeah, this function should've been called dsa_validate_key()
+     in the first place and for compat-reasons we keep it
+     as it was (for now).
+
+   @param key   The key to validate
+   @param stat  [out]  Result of test, 1==valid, 0==invalid
+   @return CRYPT_OK if successful
+*/
+int dsa_verify_key(dsa_key *key, int *stat)
+{
+   int err;
+
+   err = dsa_int_validate_primes(key, stat);
+   if (err != CRYPT_OK || *stat == 0) return err;
+
+   err = dsa_int_validate_pqg(key, stat);
+   if (err != CRYPT_OK || *stat == 0) return err;
+
+   return dsa_int_validate_xy(key, stat);
+}
+
+/**
+   Non-complex part (no primality testing) of the validation
+   of DSA params (p, q, g)
+
+   @param key   The key to validate
+   @param stat  [out]  Result of test, 1==valid, 0==invalid
+   @return CRYPT_OK if successful
+*/
+int dsa_int_validate_pqg(dsa_key *key, int *stat)
+{
+   void *tmp1, *tmp2;
+   int  err;
+
+   LTC_ARGCHK(key  != NULL);
+   LTC_ARGCHK(stat != NULL);
+   *stat = 0;
+
+   /* check q-order */
+   if ( key->qord >= LTC_MDSA_MAX_GROUP || key->qord <= 15 ||
+        (unsigned long)key->qord >= mp_unsigned_bin_size(key->p) ||
+        (mp_unsigned_bin_size(key->p) - key->qord) >= LTC_MDSA_DELTA ) {
+      return CRYPT_OK;
+   }
+
+   /* FIPS 186-4 chapter 4.1: 1 < g < p */
+   if (mp_cmp_d(key->g, 1) != LTC_MP_GT || mp_cmp(key->g, key->p) != LTC_MP_LT) {
+      return CRYPT_OK;
+   }
+
+   if ((err = mp_init_multi(&tmp1, &tmp2, NULL)) != CRYPT_OK)        { return err; }
+
+   /* FIPS 186-4 chapter 4.1: q is a divisor of (p - 1) */
+   if ((err = mp_sub_d(key->p, 1, tmp1)) != CRYPT_OK)                { goto error; }
+   if ((err = mp_div(tmp1, key->q, tmp1, tmp2)) != CRYPT_OK)         { goto error; }
+   if (mp_iszero(tmp2) != LTC_MP_YES) {
+      err = CRYPT_OK;
+      goto error;
+   }
+
+   /* FIPS 186-4 chapter 4.1: g is a generator of a subgroup of order q in
+    * the multiplicative group of GF(p) - so we make sure that g^q mod p = 1
+    */
+   if ((err = mp_exptmod(key->g, key->q, key->p, tmp1)) != CRYPT_OK) { goto error; }
+   if (mp_cmp_d(tmp1, 1) != LTC_MP_EQ) {
+      err = CRYPT_OK;
+      goto error;
+   }
+
+   err   = CRYPT_OK;
+   *stat = 1;
+error:
+   mp_clear_multi(tmp2, tmp1, NULL);
+   return err;
+}
+
+/**
+   Primality testing of DSA params p and q
+
+   @param key   The key to validate
+   @param stat  [out]  Result of test, 1==valid, 0==invalid
+   @return CRYPT_OK if successful
+*/
+int dsa_int_validate_primes(dsa_key *key, int *stat)
+{
+   int err, res;
+
+   *stat = 0;
+   LTC_ARGCHK(key  != NULL);
+   LTC_ARGCHK(stat != NULL);
+
+   /* key->q prime? */
+   if ((err = mp_prime_is_prime(key->q, LTC_MILLER_RABIN_REPS, &res)) != CRYPT_OK) {
+      return err;
+   }
+   if (res == LTC_MP_NO) {
+      return CRYPT_OK;
+   }
+
+   /* key->p prime? */
+   if ((err = mp_prime_is_prime(key->p, LTC_MILLER_RABIN_REPS, &res)) != CRYPT_OK) {
+      return err;
+   }
+   if (res == LTC_MP_NO) {
+      return CRYPT_OK;
+   }
+
+   *stat = 1;
+   return CRYPT_OK;
+}
+
+/**
+   Validation of a DSA key (x and y values)
+
+   @param key   The key to validate
+   @param stat  [out]  Result of test, 1==valid, 0==invalid
+   @return CRYPT_OK if successful
+*/
+int dsa_int_validate_xy(dsa_key *key, int *stat)
+{
+   void *tmp;
+   int  err;
+
+   *stat = 0;
+   LTC_ARGCHK(key  != NULL);
+   LTC_ARGCHK(stat != NULL);
+
+   /* 1 < y < p-1 */
+   if ((err = mp_init(&tmp)) != CRYPT_OK) {
+      return err;
+   }
+   if ((err = mp_sub_d(key->p, 1, tmp)) != CRYPT_OK) {
+      goto error;
+   }
+   if (mp_cmp_d(key->y, 1) != LTC_MP_GT || mp_cmp(key->y, tmp) != LTC_MP_LT) {
+      err = CRYPT_OK;
+      goto error;
+   }
+
+   if (key->type == PK_PRIVATE) {
+      /* FIPS 186-4 chapter 4.1: 0 < x < q */
+      if (mp_cmp_d(key->x, 0) != LTC_MP_GT || mp_cmp(key->x, key->q) != LTC_MP_LT) {
+         err = CRYPT_OK;
+         goto error;
+      }
+      /* FIPS 186-4 chapter 4.1: y = g^x mod p */
+      if ((err = mp_exptmod(key->g, key->x, key->p, tmp)) != CRYPT_OK) {
+         goto error;
+      }
+      if (mp_cmp(tmp, key->y) != LTC_MP_EQ) {
+         err = CRYPT_OK;
+         goto error;
+      }
+   }
+   else {
+      /* with just a public key we cannot test y = g^x mod p therefore we
+       * only test that y^q mod p = 1, which makes sure y is in g^x mod p
+       */
+      if ((err = mp_exptmod(key->y, key->q, key->p, tmp)) != CRYPT_OK) {
+         goto error;
+      }
+      if (mp_cmp_d(tmp, 1) != LTC_MP_EQ) {
+         err = CRYPT_OK;
+         goto error;
+      }
+   }
+
+   err   = CRYPT_OK;
+   *stat = 1;
+error:
+   mp_clear(tmp);
+   return err;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/pk/ecc/ecc.c b/libtomcrypt/src/pk/ecc/ecc.c
new file mode 100644 (file)
index 0000000..18da0b3
--- /dev/null
@@ -0,0 +1,125 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+/* Implements ECC over Z/pZ for curve y^2 = x^3 - 3x + b
+ *
+ * All curves taken from NIST recommendation paper of July 1999
+ * Available at http://csrc.nist.gov/cryptval/dss.htm
+ */
+#include "tomcrypt.h"
+
+/**
+  @file ecc.c
+  ECC Crypto, Tom St Denis
+*/
+
+#ifdef LTC_MECC
+
+/* This holds the key settings.  ***MUST*** be organized by size from smallest to largest. */
+const ltc_ecc_set_type ltc_ecc_sets[] = {
+#ifdef LTC_ECC112
+{
+        14,
+        "SECP112R1",
+        "DB7C2ABF62E35E668076BEAD208B",
+        "659EF8BA043916EEDE8911702B22",
+        "DB7C2ABF62E35E7628DFAC6561C5",
+        "09487239995A5EE76B55F9C2F098",
+        "A89CE5AF8724C0A23E0E0FF77500"
+},
+#endif
+#ifdef LTC_ECC128
+{
+        16,
+        "SECP128R1",
+        "FFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFF",
+        "E87579C11079F43DD824993C2CEE5ED3",
+        "FFFFFFFE0000000075A30D1B9038A115",
+        "161FF7528B899B2D0C28607CA52C5B86",
+        "CF5AC8395BAFEB13C02DA292DDED7A83",
+},
+#endif
+#ifdef LTC_ECC160
+{
+        20,
+        "SECP160R1",
+        "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFF",
+        "1C97BEFC54BD7A8B65ACF89F81D4D4ADC565FA45",
+        "0100000000000000000001F4C8F927AED3CA752257",
+        "4A96B5688EF573284664698968C38BB913CBFC82",
+        "23A628553168947D59DCC912042351377AC5FB32",
+},
+#endif
+#ifdef LTC_ECC192
+{
+        24,
+        "ECC-192",
+        "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF",
+        "64210519E59C80E70FA7E9AB72243049FEB8DEECC146B9B1",
+        "FFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D22831",
+        "188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF1012",
+        "7192B95FFC8DA78631011ED6B24CDD573F977A11E794811",
+},
+#endif
+#ifdef LTC_ECC224
+{
+        28,
+        "ECC-224",
+        "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000001",
+        "B4050A850C04B3ABF54132565044B0B7D7BFD8BA270B39432355FFB4",
+        "FFFFFFFFFFFFFFFFFFFFFFFFFFFF16A2E0B8F03E13DD29455C5C2A3D",
+        "B70E0CBD6BB4BF7F321390B94A03C1D356C21122343280D6115C1D21",
+        "BD376388B5F723FB4C22DFE6CD4375A05A07476444D5819985007E34",
+},
+#endif
+#ifdef LTC_ECC256
+{
+        32,
+        "ECC-256",
+        "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF",
+        "5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B",
+        "FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551",
+        "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296",
+        "4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5",
+},
+#endif
+#ifdef LTC_ECC384
+{
+        48,
+        "ECC-384",
+        "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFF",
+        "B3312FA7E23EE7E4988E056BE3F82D19181D9C6EFE8141120314088F5013875AC656398D8A2ED19D2A85C8EDD3EC2AEF",
+        "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973",
+        "AA87CA22BE8B05378EB1C71EF320AD746E1D3B628BA79B9859F741E082542A385502F25DBF55296C3A545E3872760AB7",
+        "3617DE4A96262C6F5D9E98BF9292DC29F8F41DBD289A147CE9DA3113B5F0B8C00A60B1CE1D7E819D7A431D7C90EA0E5F",
+},
+#endif
+#ifdef LTC_ECC521
+{
+        66,
+        "ECC-521",
+        "1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF",
+        "51953EB9618E1C9A1F929A21A0B68540EEA2DA725B99B315F3B8B489918EF109E156193951EC7E937B1652C0BD3BB1BF073573DF883D2C34F1EF451FD46B503F00",
+        "1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA51868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E91386409",
+        "C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66",
+        "11839296A789A3BC0045C8A5FB42C7D1BD998F54449579B446817AFBD17273E662C97EE72995EF42640C550B9013FAD0761353C7086A272C24088BE94769FD16650",
+},
+#endif
+{
+   0,
+   NULL, NULL, NULL, NULL, NULL, NULL
+}
+};
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
+
diff --git a/libtomcrypt/src/pk/ecc/ecc_ansi_x963_export.c b/libtomcrypt/src/pk/ecc/ecc_ansi_x963_export.c
new file mode 100644 (file)
index 0000000..773b683
--- /dev/null
@@ -0,0 +1,77 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+/* Implements ECC over Z/pZ for curve y^2 = x^3 - 3x + b
+ *
+ * All curves taken from NIST recommendation paper of July 1999
+ * Available at http://csrc.nist.gov/cryptval/dss.htm
+ */
+#include "tomcrypt.h"
+
+/**
+  @file ecc_ansi_x963_export.c
+  ECC Crypto, Tom St Denis
+*/
+
+#ifdef LTC_MECC
+
+/** ECC X9.63 (Sec. 4.3.6) uncompressed export
+  @param key     Key to export
+  @param out     [out] destination of export
+  @param outlen  [in/out]  Length of destination and final output size
+  Return CRYPT_OK on success
+*/
+int ecc_ansi_x963_export(ecc_key *key, unsigned char *out, unsigned long *outlen)
+{
+   unsigned char buf[ECC_BUF_SIZE];
+   unsigned long numlen, xlen, ylen;
+
+   LTC_ARGCHK(key    != NULL);
+   LTC_ARGCHK(outlen != NULL);
+
+   if (ltc_ecc_is_valid_idx(key->idx) == 0) {
+      return CRYPT_INVALID_ARG;
+   }
+   numlen = key->dp->size;
+   xlen = mp_unsigned_bin_size(key->pubkey.x);
+   ylen = mp_unsigned_bin_size(key->pubkey.y);
+
+   if (xlen > numlen || ylen > numlen || sizeof(buf) < numlen) {
+      return CRYPT_BUFFER_OVERFLOW;
+   }
+
+   if (*outlen < (1 + 2*numlen)) {
+      *outlen = 1 + 2*numlen;
+      return CRYPT_BUFFER_OVERFLOW;
+   }
+
+   LTC_ARGCHK(out    != NULL);
+
+   /* store byte 0x04 */
+   out[0] = 0x04;
+
+   /* pad and store x */
+   zeromem(buf, sizeof(buf));
+   mp_to_unsigned_bin(key->pubkey.x, buf + (numlen - xlen));
+   XMEMCPY(out+1, buf, numlen);
+
+   /* pad and store y */
+   zeromem(buf, sizeof(buf));
+   mp_to_unsigned_bin(key->pubkey.y, buf + (numlen - ylen));
+   XMEMCPY(out+1+numlen, buf, numlen);
+
+   *outlen = 1 + 2*numlen;
+   return CRYPT_OK;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/pk/ecc/ecc_ansi_x963_import.c b/libtomcrypt/src/pk/ecc/ecc_ansi_x963_import.c
new file mode 100644 (file)
index 0000000..ee5a4c9
--- /dev/null
@@ -0,0 +1,102 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+/* Implements ECC over Z/pZ for curve y^2 = x^3 - 3x + b
+ *
+ * All curves taken from NIST recommendation paper of July 1999
+ * Available at http://csrc.nist.gov/cryptval/dss.htm
+ */
+#include "tomcrypt.h"
+
+/**
+  @file ecc_ansi_x963_import.c
+  ECC Crypto, Tom St Denis
+*/
+
+#ifdef LTC_MECC
+
+/** Import an ANSI X9.63 format public key
+  @param in      The input data to read
+  @param inlen   The length of the input data
+  @param key     [out] destination to store imported key \
+*/
+int ecc_ansi_x963_import(const unsigned char *in, unsigned long inlen, ecc_key *key)
+{
+   return ecc_ansi_x963_import_ex(in, inlen, key, NULL);
+}
+
+int ecc_ansi_x963_import_ex(const unsigned char *in, unsigned long inlen, ecc_key *key, ltc_ecc_set_type *dp)
+{
+   int x, err;
+
+   LTC_ARGCHK(in  != NULL);
+   LTC_ARGCHK(key != NULL);
+
+   /* must be odd */
+   if ((inlen & 1) == 0) {
+      return CRYPT_INVALID_ARG;
+   }
+
+   /* init key */
+   if (mp_init_multi(&key->pubkey.x, &key->pubkey.y, &key->pubkey.z, &key->k, NULL) != CRYPT_OK) {
+      return CRYPT_MEM;
+   }
+
+   /* check for 4, 6 or 7 */
+   if (in[0] != 4 && in[0] != 6 && in[0] != 7) {
+      err = CRYPT_INVALID_PACKET;
+      goto error;
+   }
+
+   /* read data */
+   if ((err = mp_read_unsigned_bin(key->pubkey.x, (unsigned char *)in+1, (inlen-1)>>1)) != CRYPT_OK) {
+      goto error;
+   }
+
+   if ((err = mp_read_unsigned_bin(key->pubkey.y, (unsigned char *)in+1+((inlen-1)>>1), (inlen-1)>>1)) != CRYPT_OK) {
+      goto error;
+   }
+   if ((err = mp_set(key->pubkey.z, 1)) != CRYPT_OK) { goto error; }
+
+   if (dp == NULL) {
+     /* determine the idx */
+      for (x = 0; ltc_ecc_sets[x].size != 0; x++) {
+         if ((unsigned)ltc_ecc_sets[x].size >= ((inlen-1)>>1)) {
+            break;
+         }
+      }
+      if (ltc_ecc_sets[x].size == 0) {
+         err = CRYPT_INVALID_PACKET;
+         goto error;
+      }
+      /* set the idx */
+      key->idx  = x;
+      key->dp = &ltc_ecc_sets[x];
+   } else {
+      if (((inlen-1)>>1) != (unsigned long) dp->size) {
+         err = CRYPT_INVALID_PACKET;
+         goto error;
+      }
+      key->idx = -1;
+      key->dp  = dp;
+   }
+   key->type = PK_PUBLIC;
+
+   /* we're done */
+   return CRYPT_OK;
+error:
+   mp_clear_multi(key->pubkey.x, key->pubkey.y, key->pubkey.z, key->k, NULL);
+   return err;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/pk/ecc/ecc_decrypt_key.c b/libtomcrypt/src/pk/ecc/ecc_decrypt_key.c
new file mode 100644 (file)
index 0000000..51b894b
--- /dev/null
@@ -0,0 +1,149 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+/* Implements ECC over Z/pZ for curve y^2 = x^3 - 3x + b
+ *
+ * All curves taken from NIST recommendation paper of July 1999
+ * Available at http://csrc.nist.gov/cryptval/dss.htm
+ */
+#include "tomcrypt.h"
+
+/**
+  @file ecc_decrypt_key.c
+  ECC Crypto, Tom St Denis
+*/
+
+#ifdef LTC_MECC
+
+/**
+  Decrypt an ECC encrypted key
+  @param in       The ciphertext
+  @param inlen    The length of the ciphertext (octets)
+  @param out      [out] The plaintext
+  @param outlen   [in/out] The max size and resulting size of the plaintext
+  @param key      The corresponding private ECC key
+  @return CRYPT_OK if successful
+*/
+int ecc_decrypt_key(const unsigned char *in,  unsigned long  inlen,
+                          unsigned char *out, unsigned long *outlen,
+                          ecc_key *key)
+{
+   unsigned char *ecc_shared, *skey, *pub_expt;
+   unsigned long  x, y;
+   unsigned long  hashOID[32] = { 0 };
+   int            hash, err;
+   ecc_key        pubkey;
+   ltc_asn1_list  decode[3];
+
+   LTC_ARGCHK(in     != NULL);
+   LTC_ARGCHK(out    != NULL);
+   LTC_ARGCHK(outlen != NULL);
+   LTC_ARGCHK(key    != NULL);
+
+   /* right key type? */
+   if (key->type != PK_PRIVATE) {
+      return CRYPT_PK_NOT_PRIVATE;
+   }
+
+   /* decode to find out hash */
+   LTC_SET_ASN1(decode, 0, LTC_ASN1_OBJECT_IDENTIFIER, hashOID, sizeof(hashOID)/sizeof(hashOID[0]));
+   err = der_decode_sequence(in, inlen, decode, 1);
+   if (err != CRYPT_OK && err != CRYPT_INPUT_TOO_LONG) {
+      return err;
+   }
+
+   hash = find_hash_oid(hashOID, decode[0].size);
+   if (hash_is_valid(hash) != CRYPT_OK) {
+      return CRYPT_INVALID_PACKET;
+   }
+
+   /* we now have the hash! */
+
+   /* allocate memory */
+   pub_expt   = XMALLOC(ECC_BUF_SIZE);
+   ecc_shared = XMALLOC(ECC_BUF_SIZE);
+   skey       = XMALLOC(MAXBLOCKSIZE);
+   if (pub_expt == NULL || ecc_shared == NULL || skey == NULL) {
+      if (pub_expt != NULL) {
+         XFREE(pub_expt);
+      }
+      if (ecc_shared != NULL) {
+         XFREE(ecc_shared);
+      }
+      if (skey != NULL) {
+         XFREE(skey);
+      }
+      return CRYPT_MEM;
+   }
+   LTC_SET_ASN1(decode, 1, LTC_ASN1_OCTET_STRING,      pub_expt,  ECC_BUF_SIZE);
+   LTC_SET_ASN1(decode, 2, LTC_ASN1_OCTET_STRING,      skey,      MAXBLOCKSIZE);
+
+   /* read the structure in now */
+   if ((err = der_decode_sequence(in, inlen, decode, 3)) != CRYPT_OK) {
+      goto LBL_ERR;
+   }
+
+   /* import ECC key from packet */
+   if ((err = ecc_import(decode[1].data, decode[1].size, &pubkey)) != CRYPT_OK) {
+      goto LBL_ERR;
+   }
+
+   /* make shared key */
+   x = ECC_BUF_SIZE;
+   if ((err = ecc_shared_secret(key, &pubkey, ecc_shared, &x)) != CRYPT_OK) {
+      ecc_free(&pubkey);
+      goto LBL_ERR;
+   }
+   ecc_free(&pubkey);
+
+   y = MIN(ECC_BUF_SIZE, MAXBLOCKSIZE);
+   if ((err = hash_memory(hash, ecc_shared, x, ecc_shared, &y)) != CRYPT_OK) {
+      goto LBL_ERR;
+   }
+
+   /* ensure the hash of the shared secret is at least as big as the encrypt itself */
+   if (decode[2].size > y) {
+      err = CRYPT_INVALID_PACKET;
+      goto LBL_ERR;
+   }
+
+   /* avoid buffer overflow */
+   if (*outlen < decode[2].size) {
+      *outlen = decode[2].size;
+      err = CRYPT_BUFFER_OVERFLOW;
+      goto LBL_ERR;
+   }
+
+   /* Decrypt the key */
+   for (x = 0; x < decode[2].size; x++) {
+     out[x] = skey[x] ^ ecc_shared[x];
+   }
+   *outlen = x;
+
+   err = CRYPT_OK;
+LBL_ERR:
+#ifdef LTC_CLEAN_STACK
+   zeromem(pub_expt,   ECC_BUF_SIZE);
+   zeromem(ecc_shared, ECC_BUF_SIZE);
+   zeromem(skey,       MAXBLOCKSIZE);
+#endif
+
+   XFREE(pub_expt);
+   XFREE(ecc_shared);
+   XFREE(skey);
+
+   return err;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
+
diff --git a/libtomcrypt/src/pk/ecc/ecc_encrypt_key.c b/libtomcrypt/src/pk/ecc/ecc_encrypt_key.c
new file mode 100644 (file)
index 0000000..e92738b
--- /dev/null
@@ -0,0 +1,134 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+/* Implements ECC over Z/pZ for curve y^2 = x^3 - 3x + b
+ *
+ * All curves taken from NIST recommendation paper of July 1999
+ * Available at http://csrc.nist.gov/cryptval/dss.htm
+ */
+#include "tomcrypt.h"
+
+/**
+  @file ecc_encrypt_key.c
+  ECC Crypto, Tom St Denis
+*/
+
+#ifdef LTC_MECC
+
+/**
+  Encrypt a symmetric key with ECC
+  @param in         The symmetric key you want to encrypt
+  @param inlen      The length of the key to encrypt (octets)
+  @param out        [out] The destination for the ciphertext
+  @param outlen     [in/out] The max size and resulting size of the ciphertext
+  @param prng       An active PRNG state
+  @param wprng      The index of the PRNG you wish to use
+  @param hash       The index of the hash you want to use
+  @param key        The ECC key you want to encrypt to
+  @return CRYPT_OK if successful
+*/
+int ecc_encrypt_key(const unsigned char *in,   unsigned long inlen,
+                          unsigned char *out,  unsigned long *outlen,
+                          prng_state *prng, int wprng, int hash,
+                          ecc_key *key)
+{
+    unsigned char *pub_expt, *ecc_shared, *skey;
+    ecc_key        pubkey;
+    unsigned long  x, y, pubkeysize;
+    int            err;
+
+    LTC_ARGCHK(in      != NULL);
+    LTC_ARGCHK(out     != NULL);
+    LTC_ARGCHK(outlen  != NULL);
+    LTC_ARGCHK(key     != NULL);
+
+    /* check that wprng/cipher/hash are not invalid */
+    if ((err = prng_is_valid(wprng)) != CRYPT_OK) {
+       return err;
+    }
+
+    if ((err = hash_is_valid(hash)) != CRYPT_OK) {
+       return err;
+    }
+
+    if (inlen > hash_descriptor[hash].hashsize) {
+       return CRYPT_INVALID_HASH;
+    }
+
+    /* make a random key and export the public copy */
+    if ((err = ecc_make_key_ex(prng, wprng, &pubkey, key->dp)) != CRYPT_OK) {
+       return err;
+    }
+
+    pub_expt   = XMALLOC(ECC_BUF_SIZE);
+    ecc_shared = XMALLOC(ECC_BUF_SIZE);
+    skey       = XMALLOC(MAXBLOCKSIZE);
+    if (pub_expt == NULL || ecc_shared == NULL || skey == NULL) {
+       if (pub_expt != NULL) {
+          XFREE(pub_expt);
+       }
+       if (ecc_shared != NULL) {
+          XFREE(ecc_shared);
+       }
+       if (skey != NULL) {
+          XFREE(skey);
+       }
+       ecc_free(&pubkey);
+       return CRYPT_MEM;
+    }
+
+    pubkeysize = ECC_BUF_SIZE;
+    if ((err = ecc_export(pub_expt, &pubkeysize, PK_PUBLIC, &pubkey)) != CRYPT_OK) {
+       ecc_free(&pubkey);
+       goto LBL_ERR;
+    }
+
+    /* make random key */
+    x        = ECC_BUF_SIZE;
+    if ((err = ecc_shared_secret(&pubkey, key, ecc_shared, &x)) != CRYPT_OK) {
+       ecc_free(&pubkey);
+       goto LBL_ERR;
+    }
+    ecc_free(&pubkey);
+    y = MAXBLOCKSIZE;
+    if ((err = hash_memory(hash, ecc_shared, x, skey, &y)) != CRYPT_OK) {
+       goto LBL_ERR;
+    }
+
+    /* Encrypt key */
+    for (x = 0; x < inlen; x++) {
+      skey[x] ^= in[x];
+    }
+
+    err = der_encode_sequence_multi(out, outlen,
+                                    LTC_ASN1_OBJECT_IDENTIFIER,  hash_descriptor[hash].OIDlen,   hash_descriptor[hash].OID,
+                                    LTC_ASN1_OCTET_STRING,       pubkeysize,                     pub_expt,
+                                    LTC_ASN1_OCTET_STRING,       inlen,                          skey,
+                                    LTC_ASN1_EOL,                0UL,                            NULL);
+
+LBL_ERR:
+#ifdef LTC_CLEAN_STACK
+    /* clean up */
+    zeromem(pub_expt,   ECC_BUF_SIZE);
+    zeromem(ecc_shared, ECC_BUF_SIZE);
+    zeromem(skey,       MAXBLOCKSIZE);
+#endif
+
+    XFREE(skey);
+    XFREE(ecc_shared);
+    XFREE(pub_expt);
+
+    return err;
+}
+
+#endif
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
+
diff --git a/libtomcrypt/src/pk/ecc/ecc_export.c b/libtomcrypt/src/pk/ecc/ecc_export.c
new file mode 100644 (file)
index 0000000..6c2659e
--- /dev/null
@@ -0,0 +1,80 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+/* Implements ECC over Z/pZ for curve y^2 = x^3 - 3x + b
+ *
+ * All curves taken from NIST recommendation paper of July 1999
+ * Available at http://csrc.nist.gov/cryptval/dss.htm
+ */
+#include "tomcrypt.h"
+
+/**
+  @file ecc_export.c
+  ECC Crypto, Tom St Denis
+*/
+
+#ifdef LTC_MECC
+
+/**
+  Export an ECC key as a binary packet
+  @param out     [out] Destination for the key
+  @param outlen  [in/out] Max size and resulting size of the exported key
+  @param type    The type of key you want to export (PK_PRIVATE or PK_PUBLIC)
+  @param key     The key to export
+  @return CRYPT_OK if successful
+*/
+int ecc_export(unsigned char *out, unsigned long *outlen, int type, ecc_key *key)
+{
+   int           err;
+   unsigned char flags[1];
+   unsigned long key_size;
+
+   LTC_ARGCHK(out    != NULL);
+   LTC_ARGCHK(outlen != NULL);
+   LTC_ARGCHK(key    != NULL);
+
+   /* type valid? */
+   if (key->type != PK_PRIVATE && type == PK_PRIVATE) {
+      return CRYPT_PK_TYPE_MISMATCH;
+   }
+
+   if (ltc_ecc_is_valid_idx(key->idx) == 0) {
+      return CRYPT_INVALID_ARG;
+   }
+
+   /* we store the NIST byte size */
+   key_size = key->dp->size;
+
+   if (type == PK_PRIVATE) {
+       flags[0] = 1;
+       err = der_encode_sequence_multi(out, outlen,
+                                 LTC_ASN1_BIT_STRING,      1UL, flags,
+                                 LTC_ASN1_SHORT_INTEGER,   1UL, &key_size,
+                                 LTC_ASN1_INTEGER,         1UL, key->pubkey.x,
+                                 LTC_ASN1_INTEGER,         1UL, key->pubkey.y,
+                                 LTC_ASN1_INTEGER,         1UL, key->k,
+                                 LTC_ASN1_EOL,             0UL, NULL);
+   } else {
+       flags[0] = 0;
+       err = der_encode_sequence_multi(out, outlen,
+                                 LTC_ASN1_BIT_STRING,      1UL, flags,
+                                 LTC_ASN1_SHORT_INTEGER,   1UL, &key_size,
+                                 LTC_ASN1_INTEGER,         1UL, key->pubkey.x,
+                                 LTC_ASN1_INTEGER,         1UL, key->pubkey.y,
+                                 LTC_ASN1_EOL,             0UL, NULL);
+   }
+
+   return err;
+}
+
+#endif
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
+
diff --git a/libtomcrypt/src/pk/ecc/ecc_free.c b/libtomcrypt/src/pk/ecc/ecc_free.c
new file mode 100644 (file)
index 0000000..4a8ca45
--- /dev/null
@@ -0,0 +1,38 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+/* Implements ECC over Z/pZ for curve y^2 = x^3 - 3x + b
+ *
+ * All curves taken from NIST recommendation paper of July 1999
+ * Available at http://csrc.nist.gov/cryptval/dss.htm
+ */
+#include "tomcrypt.h"
+
+/**
+  @file ecc_free.c
+  ECC Crypto, Tom St Denis
+*/
+
+#ifdef LTC_MECC
+
+/**
+  Free an ECC key from memory
+  @param key   The key you wish to free
+*/
+void ecc_free(ecc_key *key)
+{
+   LTC_ARGCHKVD(key != NULL);
+   mp_clear_multi(key->pubkey.x, key->pubkey.y, key->pubkey.z, key->k, NULL);
+}
+
+#endif
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
+
diff --git a/libtomcrypt/src/pk/ecc/ecc_get_size.c b/libtomcrypt/src/pk/ecc/ecc_get_size.c
new file mode 100644 (file)
index 0000000..4dc5d22
--- /dev/null
@@ -0,0 +1,42 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+/* Implements ECC over Z/pZ for curve y^2 = x^3 - 3x + b
+ *
+ * All curves taken from NIST recommendation paper of July 1999
+ * Available at http://csrc.nist.gov/cryptval/dss.htm
+ */
+#include "tomcrypt.h"
+
+/**
+  @file ecc_get_size.c
+  ECC Crypto, Tom St Denis
+*/
+
+#ifdef LTC_MECC
+
+/**
+  Get the size of an ECC key
+  @param key    The key to get the size of
+  @return The size (octets) of the key or INT_MAX on error
+*/
+int ecc_get_size(ecc_key *key)
+{
+   LTC_ARGCHK(key != NULL);
+   if (ltc_ecc_is_valid_idx(key->idx))
+      return key->dp->size;
+   else
+      return INT_MAX; /* large value known to cause it to fail when passed to ecc_make_key() */
+}
+
+#endif
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
+
diff --git a/libtomcrypt/src/pk/ecc/ecc_import.c b/libtomcrypt/src/pk/ecc/ecc_import.c
new file mode 100644 (file)
index 0000000..c6d474f
--- /dev/null
@@ -0,0 +1,174 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+/* Implements ECC over Z/pZ for curve y^2 = x^3 - 3x + b
+ *
+ * All curves taken from NIST recommendation paper of July 1999
+ * Available at http://csrc.nist.gov/cryptval/dss.htm
+ */
+#include "tomcrypt.h"
+
+/**
+  @file ecc_import.c
+  ECC Crypto, Tom St Denis
+*/
+
+#ifdef LTC_MECC
+
+static int _is_point(ecc_key *key)
+{
+   void *prime, *b, *t1, *t2;
+   int err;
+
+   if ((err = mp_init_multi(&prime, &b, &t1, &t2, NULL)) != CRYPT_OK) {
+      return err;
+   }
+
+   /* load prime and b */
+   if ((err = mp_read_radix(prime, key->dp->prime, 16)) != CRYPT_OK)                          { goto error; }
+   if ((err = mp_read_radix(b, key->dp->B, 16)) != CRYPT_OK)                                  { goto error; }
+
+   /* compute y^2 */
+   if ((err = mp_sqr(key->pubkey.y, t1)) != CRYPT_OK)                                         { goto error; }
+
+   /* compute x^3 */
+   if ((err = mp_sqr(key->pubkey.x, t2)) != CRYPT_OK)                                         { goto error; }
+   if ((err = mp_mod(t2, prime, t2)) != CRYPT_OK)                                             { goto error; }
+   if ((err = mp_mul(key->pubkey.x, t2, t2)) != CRYPT_OK)                                     { goto error; }
+
+   /* compute y^2 - x^3 */
+   if ((err = mp_sub(t1, t2, t1)) != CRYPT_OK)                                                { goto error; }
+
+   /* compute y^2 - x^3 + 3x */
+   if ((err = mp_add(t1, key->pubkey.x, t1)) != CRYPT_OK)                                     { goto error; }
+   if ((err = mp_add(t1, key->pubkey.x, t1)) != CRYPT_OK)                                     { goto error; }
+   if ((err = mp_add(t1, key->pubkey.x, t1)) != CRYPT_OK)                                     { goto error; }
+   if ((err = mp_mod(t1, prime, t1)) != CRYPT_OK)                                             { goto error; }
+   while (mp_cmp_d(t1, 0) == LTC_MP_LT) {
+      if ((err = mp_add(t1, prime, t1)) != CRYPT_OK)                                          { goto error; }
+   }
+   while (mp_cmp(t1, prime) != LTC_MP_LT) {
+      if ((err = mp_sub(t1, prime, t1)) != CRYPT_OK)                                          { goto error; }
+   }
+
+   /* compare to b */
+   if (mp_cmp(t1, b) != LTC_MP_EQ) {
+      err = CRYPT_INVALID_PACKET;
+   } else {
+      err = CRYPT_OK;
+   }
+
+error:
+   mp_clear_multi(prime, b, t1, t2, NULL);
+   return err;
+}
+
+/**
+  Import an ECC key from a binary packet
+  @param in      The packet to import
+  @param inlen   The length of the packet
+  @param key     [out] The destination of the import
+  @return CRYPT_OK if successful, upon error all allocated memory will be freed
+*/
+int ecc_import(const unsigned char *in, unsigned long inlen, ecc_key *key)
+{
+   return ecc_import_ex(in, inlen, key, NULL);
+}
+
+/**
+  Import an ECC key from a binary packet, using user supplied domain params rather than one of the NIST ones
+  @param in      The packet to import
+  @param inlen   The length of the packet
+  @param key     [out] The destination of the import
+  @param dp      pointer to user supplied params; must be the same as the params used when exporting
+  @return CRYPT_OK if successful, upon error all allocated memory will be freed
+*/
+int ecc_import_ex(const unsigned char *in, unsigned long inlen, ecc_key *key, const ltc_ecc_set_type *dp)
+{
+   unsigned long key_size;
+   unsigned char flags[1];
+   int           err;
+
+   LTC_ARGCHK(in  != NULL);
+   LTC_ARGCHK(key != NULL);
+   LTC_ARGCHK(ltc_mp.name != NULL);
+
+   /* init key */
+   if (mp_init_multi(&key->pubkey.x, &key->pubkey.y, &key->pubkey.z, &key->k, NULL) != CRYPT_OK) {
+      return CRYPT_MEM;
+   }
+
+   /* find out what type of key it is */
+   err = der_decode_sequence_multi(in, inlen, LTC_ASN1_BIT_STRING, 1UL, flags,
+                                              LTC_ASN1_EOL,        0UL, NULL);
+   if (err != CRYPT_OK && err != CRYPT_INPUT_TOO_LONG) {
+      goto done;
+   }
+
+
+   if (flags[0] == 1) {
+      /* private key */
+      key->type = PK_PRIVATE;
+      if ((err = der_decode_sequence_multi(in, inlen,
+                                     LTC_ASN1_BIT_STRING,      1UL, flags,
+                                     LTC_ASN1_SHORT_INTEGER,   1UL, &key_size,
+                                     LTC_ASN1_INTEGER,         1UL, key->pubkey.x,
+                                     LTC_ASN1_INTEGER,         1UL, key->pubkey.y,
+                                     LTC_ASN1_INTEGER,         1UL, key->k,
+                                     LTC_ASN1_EOL,             0UL, NULL)) != CRYPT_OK) {
+         goto done;
+      }
+   } else if (flags[0] == 0) {
+      /* public key */
+      key->type = PK_PUBLIC;
+      if ((err = der_decode_sequence_multi(in, inlen,
+                                     LTC_ASN1_BIT_STRING,      1UL, flags,
+                                     LTC_ASN1_SHORT_INTEGER,   1UL, &key_size,
+                                     LTC_ASN1_INTEGER,         1UL, key->pubkey.x,
+                                     LTC_ASN1_INTEGER,         1UL, key->pubkey.y,
+                                     LTC_ASN1_EOL,             0UL, NULL)) != CRYPT_OK) {
+         goto done;
+      }
+   }
+   else {
+      err = CRYPT_INVALID_PACKET;
+      goto done;
+   }
+
+   if (dp == NULL) {
+     /* find the idx */
+     for (key->idx = 0; ltc_ecc_sets[key->idx].size && (unsigned long)ltc_ecc_sets[key->idx].size != key_size; ++key->idx);
+     if (ltc_ecc_sets[key->idx].size == 0) {
+       err = CRYPT_INVALID_PACKET;
+       goto done;
+     }
+     key->dp = &ltc_ecc_sets[key->idx];
+   } else {
+     key->idx = -1;
+     key->dp = dp;
+   }
+   /* set z */
+   if ((err = mp_set(key->pubkey.z, 1)) != CRYPT_OK) { goto done; }
+
+   /* is it a point on the curve?  */
+   if ((err = _is_point(key)) != CRYPT_OK) {
+      goto done;
+   }
+
+   /* we're good */
+   return CRYPT_OK;
+done:
+   mp_clear_multi(key->pubkey.x, key->pubkey.y, key->pubkey.z, key->k, NULL);
+   return err;
+}
+#endif
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
+
diff --git a/libtomcrypt/src/pk/ecc/ecc_make_key.c b/libtomcrypt/src/pk/ecc/ecc_make_key.c
new file mode 100644 (file)
index 0000000..113a994
--- /dev/null
@@ -0,0 +1,128 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+/* Implements ECC over Z/pZ for curve y^2 = x^3 - 3x + b
+ *
+ * All curves taken from NIST recommendation paper of July 1999
+ * Available at http://csrc.nist.gov/cryptval/dss.htm
+ */
+#include "tomcrypt.h"
+
+/**
+  @file ecc_make_key.c
+  ECC Crypto, Tom St Denis
+*/
+
+#ifdef LTC_MECC
+
+/**
+  Make a new ECC key
+  @param prng         An active PRNG state
+  @param wprng        The index of the PRNG you wish to use
+  @param keysize      The keysize for the new key (in octets from 20 to 65 bytes)
+  @param key          [out] Destination of the newly created key
+  @return CRYPT_OK if successful, upon error all allocated memory will be freed
+*/
+int ecc_make_key(prng_state *prng, int wprng, int keysize, ecc_key *key)
+{
+   int x, err;
+
+   /* find key size */
+   for (x = 0; (keysize > ltc_ecc_sets[x].size) && (ltc_ecc_sets[x].size != 0); x++);
+   keysize = ltc_ecc_sets[x].size;
+
+   if (keysize > ECC_MAXSIZE || ltc_ecc_sets[x].size == 0) {
+      return CRYPT_INVALID_KEYSIZE;
+   }
+   err = ecc_make_key_ex(prng, wprng, key, &ltc_ecc_sets[x]);
+   key->idx = x;
+   return err;
+}
+
+int ecc_make_key_ex(prng_state *prng, int wprng, ecc_key *key, const ltc_ecc_set_type *dp)
+{
+   int            err;
+   ecc_point     *base;
+   void          *prime, *order;
+   unsigned char *buf;
+   int            keysize;
+
+   LTC_ARGCHK(key         != NULL);
+   LTC_ARGCHK(ltc_mp.name != NULL);
+   LTC_ARGCHK(dp          != NULL);
+
+   /* good prng? */
+   if ((err = prng_is_valid(wprng)) != CRYPT_OK) {
+      return err;
+   }
+
+   key->idx = -1;
+   key->dp  = dp;
+   keysize  = dp->size;
+
+   /* allocate ram */
+   base = NULL;
+   buf  = XMALLOC(ECC_MAXSIZE);
+   if (buf == NULL) {
+      return CRYPT_MEM;
+   }
+
+   /* make up random string */
+   if (prng_descriptor[wprng].read(buf, (unsigned long)keysize, prng) != (unsigned long)keysize) {
+      err = CRYPT_ERROR_READPRNG;
+      goto ERR_BUF;
+   }
+
+   /* setup the key variables */
+   if ((err = mp_init_multi(&key->pubkey.x, &key->pubkey.y, &key->pubkey.z, &key->k, &prime, &order, NULL)) != CRYPT_OK) {
+      goto ERR_BUF;
+   }
+   base = ltc_ecc_new_point();
+   if (base == NULL) {
+      err = CRYPT_MEM;
+      goto errkey;
+   }
+
+   /* read in the specs for this key */
+   if ((err = mp_read_radix(prime,   (char *)key->dp->prime, 16)) != CRYPT_OK)                  { goto errkey; }
+   if ((err = mp_read_radix(order,   (char *)key->dp->order, 16)) != CRYPT_OK)                  { goto errkey; }
+   if ((err = mp_read_radix(base->x, (char *)key->dp->Gx, 16)) != CRYPT_OK)                     { goto errkey; }
+   if ((err = mp_read_radix(base->y, (char *)key->dp->Gy, 16)) != CRYPT_OK)                     { goto errkey; }
+   if ((err = mp_set(base->z, 1)) != CRYPT_OK)                                                  { goto errkey; }
+   if ((err = mp_read_unsigned_bin(key->k, (unsigned char *)buf, keysize)) != CRYPT_OK)         { goto errkey; }
+
+   /* the key should be smaller than the order of base point */
+   if (mp_cmp(key->k, order) != LTC_MP_LT) {
+       if((err = mp_mod(key->k, order, key->k)) != CRYPT_OK)                                    { goto errkey; }
+   }
+   /* make the public key */
+   if ((err = ltc_mp.ecc_ptmul(key->k, base, &key->pubkey, prime, 1)) != CRYPT_OK)              { goto errkey; }
+   key->type = PK_PRIVATE;
+
+   /* free up ram */
+   err = CRYPT_OK;
+   goto cleanup;
+errkey:
+   mp_clear_multi(key->pubkey.x, key->pubkey.y, key->pubkey.z, key->k, NULL);
+cleanup:
+   ltc_ecc_del_point(base);
+   mp_clear_multi(prime, order, NULL);
+ERR_BUF:
+#ifdef LTC_CLEAN_STACK
+   zeromem(buf, ECC_MAXSIZE);
+#endif
+   XFREE(buf);
+   return err;
+}
+
+#endif
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
+
diff --git a/libtomcrypt/src/pk/ecc/ecc_shared_secret.c b/libtomcrypt/src/pk/ecc/ecc_shared_secret.c
new file mode 100644 (file)
index 0000000..d18a205
--- /dev/null
@@ -0,0 +1,93 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+/* Implements ECC over Z/pZ for curve y^2 = x^3 - 3x + b
+ *
+ * All curves taken from NIST recommendation paper of July 1999
+ * Available at http://csrc.nist.gov/cryptval/dss.htm
+ */
+#include "tomcrypt.h"
+
+/**
+  @file ecc_shared_secret.c
+  ECC Crypto, Tom St Denis
+*/
+
+#ifdef LTC_MECC
+
+/**
+  Create an ECC shared secret between two keys
+  @param private_key      The private ECC key
+  @param public_key       The public key
+  @param out              [out] Destination of the shared secret (Conforms to EC-DH from ANSI X9.63)
+  @param outlen           [in/out] The max size and resulting size of the shared secret
+  @return CRYPT_OK if successful
+*/
+int ecc_shared_secret(ecc_key *private_key, ecc_key *public_key,
+                      unsigned char *out, unsigned long *outlen)
+{
+   unsigned long  x;
+   ecc_point     *result;
+   void          *prime;
+   int            err;
+
+   LTC_ARGCHK(private_key != NULL);
+   LTC_ARGCHK(public_key  != NULL);
+   LTC_ARGCHK(out         != NULL);
+   LTC_ARGCHK(outlen      != NULL);
+
+   /* type valid? */
+   if (private_key->type != PK_PRIVATE) {
+      return CRYPT_PK_NOT_PRIVATE;
+   }
+
+   if (ltc_ecc_is_valid_idx(private_key->idx) == 0 || ltc_ecc_is_valid_idx(public_key->idx) == 0) {
+      return CRYPT_INVALID_ARG;
+   }
+
+   if (XSTRCMP(private_key->dp->name, public_key->dp->name) != 0) {
+      return CRYPT_PK_TYPE_MISMATCH;
+   }
+
+   /* make new point */
+   result = ltc_ecc_new_point();
+   if (result == NULL) {
+      return CRYPT_MEM;
+   }
+
+   if ((err = mp_init(&prime)) != CRYPT_OK) {
+      ltc_ecc_del_point(result);
+      return err;
+   }
+
+   if ((err = mp_read_radix(prime, (char *)private_key->dp->prime, 16)) != CRYPT_OK)                               { goto done; }
+   if ((err = ltc_mp.ecc_ptmul(private_key->k, &public_key->pubkey, result, prime, 1)) != CRYPT_OK)                { goto done; }
+
+   x = (unsigned long)mp_unsigned_bin_size(prime);
+   if (*outlen < x) {
+      *outlen = x;
+      err = CRYPT_BUFFER_OVERFLOW;
+      goto done;
+   }
+   zeromem(out, x);
+   if ((err = mp_to_unsigned_bin(result->x, out + (x - mp_unsigned_bin_size(result->x))))   != CRYPT_OK)           { goto done; }
+
+   err     = CRYPT_OK;
+   *outlen = x;
+done:
+   mp_clear(prime);
+   ltc_ecc_del_point(result);
+   return err;
+}
+
+#endif
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
+
diff --git a/libtomcrypt/src/pk/ecc/ecc_sign_hash.c b/libtomcrypt/src/pk/ecc/ecc_sign_hash.c
new file mode 100644 (file)
index 0000000..5d43569
--- /dev/null
@@ -0,0 +1,171 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+#include "tomcrypt.h"
+
+#ifdef LTC_MECC
+
+/**
+  @file ecc_sign_hash.c
+  ECC Crypto, Tom St Denis
+*/
+
+static int _ecc_sign_hash(const unsigned char *in,  unsigned long inlen,
+                                unsigned char *out, unsigned long *outlen,
+                                prng_state *prng, int wprng, ecc_key *key, int sigformat)
+{
+   ecc_key       pubkey;
+   void          *r, *s, *e, *p, *b;
+   int           err, max_iterations = LTC_PK_MAX_RETRIES;
+   unsigned long pbits, pbytes, i, shift_right;
+   unsigned char ch, buf[MAXBLOCKSIZE];
+
+   LTC_ARGCHK(in     != NULL);
+   LTC_ARGCHK(out    != NULL);
+   LTC_ARGCHK(outlen != NULL);
+   LTC_ARGCHK(key    != NULL);
+
+   /* is this a private key? */
+   if (key->type != PK_PRIVATE) {
+      return CRYPT_PK_NOT_PRIVATE;
+   }
+
+   /* is the IDX valid ?  */
+   if (ltc_ecc_is_valid_idx(key->idx) != 1) {
+      return CRYPT_PK_INVALID_TYPE;
+   }
+
+   if ((err = prng_is_valid(wprng)) != CRYPT_OK) {
+      return err;
+   }
+
+   /* init the bignums */
+   if ((err = mp_init_multi(&r, &s, &p, &e, &b, NULL)) != CRYPT_OK) {
+      return err;
+   }
+   if ((err = mp_read_radix(p, (char *)key->dp->order, 16)) != CRYPT_OK)              { goto errnokey; }
+
+   /* get the hash and load it as a bignum into 'e' */
+   pbits = mp_count_bits(p);
+   pbytes = (pbits+7) >> 3;
+   if (pbits > inlen*8) {
+      if ((err = mp_read_unsigned_bin(e, (unsigned char *)in, inlen)) != CRYPT_OK)    { goto errnokey; }
+   }
+   else if (pbits % 8 == 0) {
+      if ((err = mp_read_unsigned_bin(e, (unsigned char *)in, pbytes)) != CRYPT_OK)   { goto errnokey; }
+   }
+   else {
+      shift_right = 8 - pbits % 8;
+      for (i=0, ch=0; i<pbytes; i++) {
+        buf[i] = ch;
+        ch = (in[i] << (8-shift_right));
+        buf[i] = buf[i] ^ (in[i] >> shift_right);
+      }
+      if ((err = mp_read_unsigned_bin(e, (unsigned char *)buf, pbytes)) != CRYPT_OK)  { goto errnokey; }
+   }
+
+   /* make up a key and export the public copy */
+   do {
+      if ((err = ecc_make_key_ex(prng, wprng, &pubkey, key->dp)) != CRYPT_OK) {
+         goto errnokey;
+      }
+
+      /* find r = x1 mod n */
+      if ((err = mp_mod(pubkey.pubkey.x, p, r)) != CRYPT_OK)                          { goto error; }
+
+      if (mp_iszero(r) == LTC_MP_YES) {
+         ecc_free(&pubkey);
+      } else {
+         if ((err = rand_bn_upto(b, p, prng, wprng)) != CRYPT_OK)          { goto error; } /* b = blinding value */
+         /* find s = (e + xr)/k */
+         if ((err = mp_mulmod(pubkey.k, b, p, pubkey.k)) != CRYPT_OK)      { goto error; } /* k = kb */
+         if ((err = mp_invmod(pubkey.k, p, pubkey.k)) != CRYPT_OK)         { goto error; } /* k = 1/kb */
+         if ((err = mp_mulmod(key->k, r, p, s)) != CRYPT_OK)               { goto error; } /* s = xr */
+         if ((err = mp_mulmod(pubkey.k, s, p, s)) != CRYPT_OK)             { goto error; } /* s = xr/kb */
+         if ((err = mp_mulmod(pubkey.k, e, p, e)) != CRYPT_OK)             { goto error; } /* e = e/kb */
+         if ((err = mp_add(e, s, s)) != CRYPT_OK)                          { goto error; } /* s = e/kb + xr/kb */
+         if ((err = mp_mulmod(s, b, p, s)) != CRYPT_OK)                    { goto error; } /* s = b(e/kb + xr/kb) = (e + xr)/k */
+         ecc_free(&pubkey);
+         if (mp_iszero(s) == LTC_MP_NO) {
+            break;
+         }
+      }
+   } while (--max_iterations > 0);
+
+   if (max_iterations == 0) {
+      goto errnokey;
+   }
+
+   if (sigformat == 1) {
+      /* RFC7518 format */
+      if (*outlen < 2*pbytes) { err = CRYPT_MEM; goto errnokey; }
+      zeromem(out, 2*pbytes);
+      i = mp_unsigned_bin_size(r);
+      if ((err = mp_to_unsigned_bin(r, out + (pbytes - i)))   != CRYPT_OK) { goto errnokey; }
+      i = mp_unsigned_bin_size(s);
+      if ((err = mp_to_unsigned_bin(s, out + (2*pbytes - i))) != CRYPT_OK) { goto errnokey; }
+      *outlen = 2*pbytes;
+      err = CRYPT_OK;
+   }
+   else {
+      /* store as ASN.1 SEQUENCE { r, s -- integer } */
+      err = der_encode_sequence_multi(out, outlen,
+                               LTC_ASN1_INTEGER, 1UL, r,
+                               LTC_ASN1_INTEGER, 1UL, s,
+                               LTC_ASN1_EOL, 0UL, NULL);
+   }
+   goto errnokey;
+error:
+   ecc_free(&pubkey);
+errnokey:
+   mp_clear_multi(r, s, p, e, b, NULL);
+   return err;
+}
+
+/**
+  Sign a message digest
+  @param in        The message digest to sign
+  @param inlen     The length of the digest
+  @param out       [out] The destination for the signature
+  @param outlen    [in/out] The max size and resulting size of the signature
+  @param prng      An active PRNG state
+  @param wprng     The index of the PRNG you wish to use
+  @param key       A private ECC key
+  @return CRYPT_OK if successful
+*/
+int ecc_sign_hash(const unsigned char *in,  unsigned long inlen,
+                        unsigned char *out, unsigned long *outlen,
+                        prng_state *prng, int wprng, ecc_key *key)
+{
+   return _ecc_sign_hash(in, inlen, out, outlen, prng, wprng, key, 0);
+}
+
+/**
+  Sign a message digest in RFC7518 format
+  @param in        The message digest to sign
+  @param inlen     The length of the digest
+  @param out       [out] The destination for the signature
+  @param outlen    [in/out] The max size and resulting size of the signature
+  @param prng      An active PRNG state
+  @param wprng     The index of the PRNG you wish to use
+  @param key       A private ECC key
+  @return CRYPT_OK if successful
+*/
+int ecc_sign_hash_rfc7518(const unsigned char *in,  unsigned long inlen,
+                                unsigned char *out, unsigned long *outlen,
+                                prng_state *prng, int wprng, ecc_key *key)
+{
+   return _ecc_sign_hash(in, inlen, out, outlen, prng, wprng, key, 1);
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/pk/ecc/ecc_sizes.c b/libtomcrypt/src/pk/ecc/ecc_sizes.c
new file mode 100644 (file)
index 0000000..7c311fe
--- /dev/null
@@ -0,0 +1,46 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+/* Implements ECC over Z/pZ for curve y^2 = x^3 - 3x + b
+ *
+ * All curves taken from NIST recommendation paper of July 1999
+ * Available at http://csrc.nist.gov/cryptval/dss.htm
+ */
+#include "tomcrypt.h"
+
+/**
+  @file ecc_sizes.c
+  ECC Crypto, Tom St Denis
+*/
+
+#ifdef LTC_MECC
+
+void ecc_sizes(int *low, int *high)
+{
+ int i;
+ LTC_ARGCHKVD(low  != NULL);
+ LTC_ARGCHKVD(high != NULL);
+
+ *low = INT_MAX;
+ *high = 0;
+ for (i = 0; ltc_ecc_sets[i].size != 0; i++) {
+     if (ltc_ecc_sets[i].size < *low)  {
+        *low  = ltc_ecc_sets[i].size;
+     }
+     if (ltc_ecc_sets[i].size > *high) {
+        *high = ltc_ecc_sets[i].size;
+     }
+ }
+}
+
+#endif
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
+
diff --git a/libtomcrypt/src/pk/ecc/ecc_test.c b/libtomcrypt/src/pk/ecc/ecc_test.c
new file mode 100644 (file)
index 0000000..b6d54d1
--- /dev/null
@@ -0,0 +1,93 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+/* Implements ECC over Z/pZ for curve y^2 = x^3 - 3x + b
+ *
+ * All curves taken from NIST recommendation paper of July 1999
+ * Available at http://csrc.nist.gov/cryptval/dss.htm
+ */
+#include "tomcrypt.h"
+
+/**
+  @file ecc_test.c
+  ECC Crypto, Tom St Denis
+*/
+
+#ifdef LTC_MECC
+
+/**
+  Perform on the ECC system
+  @return CRYPT_OK if successful
+*/
+int ecc_test(void)
+{
+   void     *modulus, *order;
+   ecc_point  *G, *GG;
+   int i, err, primality;
+
+   if ((err = mp_init_multi(&modulus, &order, NULL)) != CRYPT_OK) {
+      return err;
+   }
+
+   G   = ltc_ecc_new_point();
+   GG  = ltc_ecc_new_point();
+   if (G == NULL || GG == NULL) {
+      mp_clear_multi(modulus, order, NULL);
+      ltc_ecc_del_point(G);
+      ltc_ecc_del_point(GG);
+      return CRYPT_MEM;
+   }
+
+   for (i = 0; ltc_ecc_sets[i].size; i++) {
+       #if 0
+          printf("Testing %d\n", ltc_ecc_sets[i].size);
+       #endif
+       if ((err = mp_read_radix(modulus, (char *)ltc_ecc_sets[i].prime, 16)) != CRYPT_OK)   { goto done; }
+       if ((err = mp_read_radix(order, (char *)ltc_ecc_sets[i].order, 16)) != CRYPT_OK)     { goto done; }
+
+       /* is prime actually prime? */
+       if ((err = mp_prime_is_prime(modulus, 8, &primality)) != CRYPT_OK)                   { goto done; }
+       if (primality == 0) {
+          err = CRYPT_FAIL_TESTVECTOR;
+          goto done;
+       }
+
+       /* is order prime ? */
+       if ((err = mp_prime_is_prime(order, 8, &primality)) != CRYPT_OK)                     { goto done; }
+       if (primality == 0) {
+          err = CRYPT_FAIL_TESTVECTOR;
+          goto done;
+       }
+
+       if ((err = mp_read_radix(G->x, (char *)ltc_ecc_sets[i].Gx, 16)) != CRYPT_OK)         { goto done; }
+       if ((err = mp_read_radix(G->y, (char *)ltc_ecc_sets[i].Gy, 16)) != CRYPT_OK)         { goto done; }
+       mp_set(G->z, 1);
+
+       /* then we should have G == (order + 1)G */
+       if ((err = mp_add_d(order, 1, order)) != CRYPT_OK)                                   { goto done; }
+       if ((err = ltc_mp.ecc_ptmul(order, G, GG, modulus, 1)) != CRYPT_OK)                  { goto done; }
+       if (mp_cmp(G->x, GG->x) != LTC_MP_EQ || mp_cmp(G->y, GG->y) != LTC_MP_EQ) {
+          err = CRYPT_FAIL_TESTVECTOR;
+          goto done;
+       }
+   }
+   err = CRYPT_OK;
+done:
+   ltc_ecc_del_point(GG);
+   ltc_ecc_del_point(G);
+   mp_clear_multi(order, modulus, NULL);
+   return err;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
+
diff --git a/libtomcrypt/src/pk/ecc/ecc_verify_hash.c b/libtomcrypt/src/pk/ecc/ecc_verify_hash.c
new file mode 100644 (file)
index 0000000..af17758
--- /dev/null
@@ -0,0 +1,200 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+#include "tomcrypt.h"
+
+#ifdef LTC_MECC
+
+/**
+  @file ecc_verify_hash.c
+  ECC Crypto, Tom St Denis
+*/
+
+static int _ecc_verify_hash(const unsigned char *sig,  unsigned long siglen,
+                            const unsigned char *hash, unsigned long hashlen,
+                            int *stat, ecc_key *key, int sigformat)
+{
+   ecc_point    *mG, *mQ;
+   void          *r, *s, *v, *w, *u1, *u2, *e, *p, *m;
+   void          *mp;
+   int           err;
+   unsigned long pbits, pbytes, i, shift_right;
+   unsigned char ch, buf[MAXBLOCKSIZE];
+
+   LTC_ARGCHK(sig  != NULL);
+   LTC_ARGCHK(hash != NULL);
+   LTC_ARGCHK(stat != NULL);
+   LTC_ARGCHK(key  != NULL);
+
+   /* default to invalid signature */
+   *stat = 0;
+   mp    = NULL;
+
+   /* is the IDX valid ?  */
+   if (ltc_ecc_is_valid_idx(key->idx) != 1) {
+      return CRYPT_PK_INVALID_TYPE;
+   }
+
+   /* allocate ints */
+   if ((err = mp_init_multi(&r, &s, &v, &w, &u1, &u2, &p, &e, &m, NULL)) != CRYPT_OK) {
+      return CRYPT_MEM;
+   }
+
+   /* allocate points */
+   mG = ltc_ecc_new_point();
+   mQ = ltc_ecc_new_point();
+   if (mQ  == NULL || mG == NULL) {
+      err = CRYPT_MEM;
+      goto error;
+   }
+
+   if (sigformat == 1) {
+      /* RFC7518 format */
+      if ((siglen % 2) == 1) {
+         err = CRYPT_INVALID_PACKET;
+         goto error;
+      }
+      i = siglen / 2;
+      if ((err = mp_read_unsigned_bin(r, (unsigned char *)sig,   i)) != CRYPT_OK)                       { goto error; }
+      if ((err = mp_read_unsigned_bin(s, (unsigned char *)sig+i, i)) != CRYPT_OK)                       { goto error; }
+   }
+   else {
+      /* ASN.1 format */
+      if ((err = der_decode_sequence_multi(sig, siglen,
+                                     LTC_ASN1_INTEGER, 1UL, r,
+                                     LTC_ASN1_INTEGER, 1UL, s,
+                                     LTC_ASN1_EOL, 0UL, NULL)) != CRYPT_OK)                             { goto error; }
+   }
+
+   /* get the order */
+   if ((err = mp_read_radix(p, (char *)key->dp->order, 16)) != CRYPT_OK)                                { goto error; }
+
+   /* get the modulus */
+   if ((err = mp_read_radix(m, (char *)key->dp->prime, 16)) != CRYPT_OK)                                { goto error; }
+
+   /* check for zero */
+   if (mp_iszero(r) || mp_iszero(s) || mp_cmp(r, p) != LTC_MP_LT || mp_cmp(s, p) != LTC_MP_LT) {
+      err = CRYPT_INVALID_PACKET;
+      goto error;
+   }
+
+   /* read hash - truncate if needed */
+   pbits = mp_count_bits(p);
+   pbytes = (pbits+7) >> 3;
+   if (pbits > hashlen*8) {
+      if ((err = mp_read_unsigned_bin(e, (unsigned char *)hash, hashlen)) != CRYPT_OK)                  { goto error; }
+   }
+   else if (pbits % 8 == 0) {
+      if ((err = mp_read_unsigned_bin(e, (unsigned char *)hash, pbytes)) != CRYPT_OK)                   { goto error; }
+   }
+   else {
+      shift_right = 8 - pbits % 8;
+      for (i=0, ch=0; i<pbytes; i++) {
+        buf[i] = ch;
+        ch = (hash[i] << (8-shift_right));
+        buf[i] = buf[i] ^ (hash[i] >> shift_right);
+      }
+      if ((err = mp_read_unsigned_bin(e, (unsigned char *)buf, pbytes)) != CRYPT_OK)                    { goto error; }
+   }
+
+   /*  w  = s^-1 mod n */
+   if ((err = mp_invmod(s, p, w)) != CRYPT_OK)                                                          { goto error; }
+
+   /* u1 = ew */
+   if ((err = mp_mulmod(e, w, p, u1)) != CRYPT_OK)                                                      { goto error; }
+
+   /* u2 = rw */
+   if ((err = mp_mulmod(r, w, p, u2)) != CRYPT_OK)                                                      { goto error; }
+
+   /* find mG and mQ */
+   if ((err = mp_read_radix(mG->x, (char *)key->dp->Gx, 16)) != CRYPT_OK)                               { goto error; }
+   if ((err = mp_read_radix(mG->y, (char *)key->dp->Gy, 16)) != CRYPT_OK)                               { goto error; }
+   if ((err = mp_set(mG->z, 1)) != CRYPT_OK)                                                            { goto error; }
+
+   if ((err = mp_copy(key->pubkey.x, mQ->x)) != CRYPT_OK)                                               { goto error; }
+   if ((err = mp_copy(key->pubkey.y, mQ->y)) != CRYPT_OK)                                               { goto error; }
+   if ((err = mp_copy(key->pubkey.z, mQ->z)) != CRYPT_OK)                                               { goto error; }
+
+   /* compute u1*mG + u2*mQ = mG */
+   if (ltc_mp.ecc_mul2add == NULL) {
+      if ((err = ltc_mp.ecc_ptmul(u1, mG, mG, m, 0)) != CRYPT_OK)                                       { goto error; }
+      if ((err = ltc_mp.ecc_ptmul(u2, mQ, mQ, m, 0)) != CRYPT_OK)                                       { goto error; }
+
+      /* find the montgomery mp */
+      if ((err = mp_montgomery_setup(m, &mp)) != CRYPT_OK)                                              { goto error; }
+
+      /* add them */
+      if ((err = ltc_mp.ecc_ptadd(mQ, mG, mG, m, mp)) != CRYPT_OK)                                      { goto error; }
+
+      /* reduce */
+      if ((err = ltc_mp.ecc_map(mG, m, mp)) != CRYPT_OK)                                                { goto error; }
+   } else {
+      /* use Shamir's trick to compute u1*mG + u2*mQ using half of the doubles */
+      if ((err = ltc_mp.ecc_mul2add(mG, u1, mQ, u2, mG, m)) != CRYPT_OK)                                { goto error; }
+   }
+
+   /* v = X_x1 mod n */
+   if ((err = mp_mod(mG->x, p, v)) != CRYPT_OK)                                                         { goto error; }
+
+   /* does v == r */
+   if (mp_cmp(v, r) == LTC_MP_EQ) {
+      *stat = 1;
+   }
+
+   /* clear up and return */
+   err = CRYPT_OK;
+error:
+   ltc_ecc_del_point(mG);
+   ltc_ecc_del_point(mQ);
+   mp_clear_multi(r, s, v, w, u1, u2, p, e, m, NULL);
+   if (mp != NULL) {
+      mp_montgomery_free(mp);
+   }
+   return err;
+}
+
+/**
+   Verify an ECC signature
+   @param sig         The signature to verify
+   @param siglen      The length of the signature (octets)
+   @param hash        The hash (message digest) that was signed
+   @param hashlen     The length of the hash (octets)
+   @param stat        Result of signature, 1==valid, 0==invalid
+   @param key         The corresponding public ECC key
+   @return CRYPT_OK if successful (even if the signature is not valid)
+*/
+int ecc_verify_hash(const unsigned char *sig,  unsigned long siglen,
+                    const unsigned char *hash, unsigned long hashlen,
+                    int *stat, ecc_key *key)
+{
+   return _ecc_verify_hash(sig, siglen, hash, hashlen, stat, key, 0);
+}
+
+/**
+   Verify an ECC signature in RFC7518 format
+   @param sig         The signature to verify
+   @param siglen      The length of the signature (octets)
+   @param hash        The hash (message digest) that was signed
+   @param hashlen     The length of the hash (octets)
+   @param stat        Result of signature, 1==valid, 0==invalid
+   @param key         The corresponding public ECC key
+   @return CRYPT_OK if successful (even if the signature is not valid)
+*/
+int ecc_verify_hash_rfc7518(const unsigned char *sig,  unsigned long siglen,
+                            const unsigned char *hash, unsigned long hashlen,
+                            int *stat, ecc_key *key)
+{
+   return _ecc_verify_hash(sig, siglen, hash, hashlen, stat, key, 1);
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/pk/ecc/ltc_ecc_is_valid_idx.c b/libtomcrypt/src/pk/ecc/ltc_ecc_is_valid_idx.c
new file mode 100644 (file)
index 0000000..057a899
--- /dev/null
@@ -0,0 +1,44 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+/* Implements ECC over Z/pZ for curve y^2 = x^3 - 3x + b
+ *
+ * All curves taken from NIST recommendation paper of July 1999
+ * Available at http://csrc.nist.gov/cryptval/dss.htm
+ */
+#include "tomcrypt.h"
+
+/**
+  @file ltc_ecc_is_valid_idx.c
+  ECC Crypto, Tom St Denis
+*/
+
+#ifdef LTC_MECC
+
+/** Returns whether an ECC idx is valid or not
+  @param n   The idx number to check
+  @return 1 if valid, 0 if not
+*/
+int ltc_ecc_is_valid_idx(int n)
+{
+   int x;
+
+   for (x = 0; ltc_ecc_sets[x].size != 0; x++);
+   /* -1 is a valid index --- indicating that the domain params were supplied by the user */
+   if ((n >= -1) && (n < x)) {
+      return 1;
+   }
+   return 0;
+}
+
+#endif
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
+
diff --git a/libtomcrypt/src/pk/ecc/ltc_ecc_map.c b/libtomcrypt/src/pk/ecc/ltc_ecc_map.c
new file mode 100644 (file)
index 0000000..c745f29
--- /dev/null
@@ -0,0 +1,74 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+/* Implements ECC over Z/pZ for curve y^2 = x^3 - 3x + b
+ *
+ * All curves taken from NIST recommendation paper of July 1999
+ * Available at http://csrc.nist.gov/cryptval/dss.htm
+ */
+#include "tomcrypt.h"
+
+/**
+  @file ltc_ecc_map.c
+  ECC Crypto, Tom St Denis
+*/
+
+#ifdef LTC_MECC
+
+/**
+  Map a projective jacbobian point back to affine space
+  @param P        [in/out] The point to map
+  @param modulus  The modulus of the field the ECC curve is in
+  @param mp       The "b" value from montgomery_setup()
+  @return CRYPT_OK on success
+*/
+int ltc_ecc_map(ecc_point *P, void *modulus, void *mp)
+{
+   void *t1, *t2;
+   int   err;
+
+   LTC_ARGCHK(P       != NULL);
+   LTC_ARGCHK(modulus != NULL);
+   LTC_ARGCHK(mp      != NULL);
+
+   if ((err = mp_init_multi(&t1, &t2, NULL)) != CRYPT_OK) {
+      return err;
+   }
+
+   /* first map z back to normal */
+   if ((err = mp_montgomery_reduce(P->z, modulus, mp)) != CRYPT_OK)           { goto done; }
+
+   /* get 1/z */
+   if ((err = mp_invmod(P->z, modulus, t1)) != CRYPT_OK)                      { goto done; }
+
+   /* get 1/z^2 and 1/z^3 */
+   if ((err = mp_sqr(t1, t2)) != CRYPT_OK)                                    { goto done; }
+   if ((err = mp_mod(t2, modulus, t2)) != CRYPT_OK)                           { goto done; }
+   if ((err = mp_mul(t1, t2, t1)) != CRYPT_OK)                                { goto done; }
+   if ((err = mp_mod(t1, modulus, t1)) != CRYPT_OK)                           { goto done; }
+
+   /* multiply against x/y */
+   if ((err = mp_mul(P->x, t2, P->x)) != CRYPT_OK)                            { goto done; }
+   if ((err = mp_montgomery_reduce(P->x, modulus, mp)) != CRYPT_OK)           { goto done; }
+   if ((err = mp_mul(P->y, t1, P->y)) != CRYPT_OK)                            { goto done; }
+   if ((err = mp_montgomery_reduce(P->y, modulus, mp)) != CRYPT_OK)           { goto done; }
+   if ((err = mp_set(P->z, 1)) != CRYPT_OK)                                   { goto done; }
+
+   err = CRYPT_OK;
+done:
+   mp_clear_multi(t1, t2, NULL);
+   return err;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
+
diff --git a/libtomcrypt/src/pk/ecc/ltc_ecc_mul2add.c b/libtomcrypt/src/pk/ecc/ltc_ecc_mul2add.c
new file mode 100644 (file)
index 0000000..cef1844
--- /dev/null
@@ -0,0 +1,206 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+/* Implements ECC over Z/pZ for curve y^2 = x^3 - 3x + b
+ *
+ * All curves taken from NIST recommendation paper of July 1999
+ * Available at http://csrc.nist.gov/cryptval/dss.htm
+ */
+#include "tomcrypt.h"
+
+/**
+  @file ltc_ecc_mul2add.c
+  ECC Crypto, Shamir's Trick, Tom St Denis
+*/
+
+#ifdef LTC_MECC
+
+#ifdef LTC_ECC_SHAMIR
+
+/** Computes kA*A + kB*B = C using Shamir's Trick
+  @param A        First point to multiply
+  @param kA       What to multiple A by
+  @param B        Second point to multiply
+  @param kB       What to multiple B by
+  @param C        [out] Destination point (can overlap with A or B
+  @param modulus  Modulus for curve
+  @return CRYPT_OK on success
+*/
+int ltc_ecc_mul2add(ecc_point *A, void *kA,
+                    ecc_point *B, void *kB,
+                    ecc_point *C,
+                         void *modulus)
+{
+  ecc_point     *precomp[16];
+  unsigned       bitbufA, bitbufB, lenA, lenB, len, x, y, nA, nB, nibble;
+  unsigned char *tA, *tB;
+  int            err, first;
+  void          *mp, *mu;
+
+  /* argchks */
+  LTC_ARGCHK(A       != NULL);
+  LTC_ARGCHK(B       != NULL);
+  LTC_ARGCHK(C       != NULL);
+  LTC_ARGCHK(kA      != NULL);
+  LTC_ARGCHK(kB      != NULL);
+  LTC_ARGCHK(modulus != NULL);
+
+  /* allocate memory */
+  tA = XCALLOC(1, ECC_BUF_SIZE);
+  if (tA == NULL) {
+     return CRYPT_MEM;
+  }
+  tB = XCALLOC(1, ECC_BUF_SIZE);
+  if (tB == NULL) {
+     XFREE(tA);
+     return CRYPT_MEM;
+  }
+
+  /* get sizes */
+  lenA = mp_unsigned_bin_size(kA);
+  lenB = mp_unsigned_bin_size(kB);
+  len  = MAX(lenA, lenB);
+
+  /* sanity check */
+  if ((lenA > ECC_BUF_SIZE) || (lenB > ECC_BUF_SIZE)) {
+     err = CRYPT_INVALID_ARG;
+     goto ERR_T;
+  }
+
+  /* extract and justify kA */
+  mp_to_unsigned_bin(kA, (len - lenA) + tA);
+
+  /* extract and justify kB */
+  mp_to_unsigned_bin(kB, (len - lenB) + tB);
+
+  /* allocate the table */
+  for (x = 0; x < 16; x++) {
+     precomp[x] = ltc_ecc_new_point();
+     if (precomp[x] == NULL) {
+         for (y = 0; y < x; ++y) {
+            ltc_ecc_del_point(precomp[y]);
+         }
+         err = CRYPT_MEM;
+         goto ERR_T;
+     }
+  }
+
+  /* init montgomery reduction */
+  if ((err = mp_montgomery_setup(modulus, &mp)) != CRYPT_OK) {
+      goto ERR_P;
+  }
+  if ((err = mp_init(&mu)) != CRYPT_OK) {
+      goto ERR_MP;
+  }
+  if ((err = mp_montgomery_normalization(mu, modulus)) != CRYPT_OK) {
+      goto ERR_MU;
+  }
+
+  /* copy ones ... */
+  if ((err = mp_mulmod(A->x, mu, modulus, precomp[1]->x)) != CRYPT_OK)                                         { goto ERR_MU; }
+  if ((err = mp_mulmod(A->y, mu, modulus, precomp[1]->y)) != CRYPT_OK)                                         { goto ERR_MU; }
+  if ((err = mp_mulmod(A->z, mu, modulus, precomp[1]->z)) != CRYPT_OK)                                         { goto ERR_MU; }
+
+  if ((err = mp_mulmod(B->x, mu, modulus, precomp[1<<2]->x)) != CRYPT_OK)                                      { goto ERR_MU; }
+  if ((err = mp_mulmod(B->y, mu, modulus, precomp[1<<2]->y)) != CRYPT_OK)                                      { goto ERR_MU; }
+  if ((err = mp_mulmod(B->z, mu, modulus, precomp[1<<2]->z)) != CRYPT_OK)                                      { goto ERR_MU; }
+
+  /* precomp [i,0](A + B) table */
+  if ((err = ltc_mp.ecc_ptdbl(precomp[1], precomp[2], modulus, mp)) != CRYPT_OK)                               { goto ERR_MU; }
+  if ((err = ltc_mp.ecc_ptadd(precomp[1], precomp[2], precomp[3], modulus, mp)) != CRYPT_OK)                   { goto ERR_MU; }
+
+  /* precomp [0,i](A + B) table */
+  if ((err = ltc_mp.ecc_ptdbl(precomp[1<<2], precomp[2<<2], modulus, mp)) != CRYPT_OK)                         { goto ERR_MU; }
+  if ((err = ltc_mp.ecc_ptadd(precomp[1<<2], precomp[2<<2], precomp[3<<2], modulus, mp)) != CRYPT_OK)          { goto ERR_MU; }
+
+  /* precomp [i,j](A + B) table (i != 0, j != 0) */
+  for (x = 1; x < 4; x++) {
+     for (y = 1; y < 4; y++) {
+        if ((err = ltc_mp.ecc_ptadd(precomp[x], precomp[(y<<2)], precomp[x+(y<<2)], modulus, mp)) != CRYPT_OK) { goto ERR_MU; }
+     }
+  }
+
+  nibble  = 3;
+  first   = 1;
+  bitbufA = tA[0];
+  bitbufB = tB[0];
+
+  /* for every byte of the multiplicands */
+  for (x = 0;; ) {
+     /* grab a nibble */
+     if (++nibble == 4) {
+        if (x == len) break;
+        bitbufA = tA[x];
+        bitbufB = tB[x];
+        nibble  = 0;
+        ++x;
+     }
+
+     /* extract two bits from both, shift/update */
+     nA = (bitbufA >> 6) & 0x03;
+     nB = (bitbufB >> 6) & 0x03;
+     bitbufA = (bitbufA << 2) & 0xFF;
+     bitbufB = (bitbufB << 2) & 0xFF;
+
+     /* if both zero, if first, continue */
+     if ((nA == 0) && (nB == 0) && (first == 1)) {
+        continue;
+     }
+
+     /* double twice, only if this isn't the first */
+     if (first == 0) {
+        /* double twice */
+        if ((err = ltc_mp.ecc_ptdbl(C, C, modulus, mp)) != CRYPT_OK)                  { goto ERR_MU; }
+        if ((err = ltc_mp.ecc_ptdbl(C, C, modulus, mp)) != CRYPT_OK)                  { goto ERR_MU; }
+     }
+
+     /* if not both zero */
+     if ((nA != 0) || (nB != 0)) {
+        if (first == 1) {
+           /* if first, copy from table */
+           first = 0;
+           if ((err = mp_copy(precomp[nA + (nB<<2)]->x, C->x)) != CRYPT_OK)           { goto ERR_MU; }
+           if ((err = mp_copy(precomp[nA + (nB<<2)]->y, C->y)) != CRYPT_OK)           { goto ERR_MU; }
+           if ((err = mp_copy(precomp[nA + (nB<<2)]->z, C->z)) != CRYPT_OK)           { goto ERR_MU; }
+        } else {
+           /* if not first, add from table */
+           if ((err = ltc_mp.ecc_ptadd(C, precomp[nA + (nB<<2)], C, modulus, mp)) != CRYPT_OK) { goto ERR_MU; }
+        }
+     }
+  }
+
+  /* reduce to affine */
+  err = ltc_ecc_map(C, modulus, mp);
+
+  /* clean up */
+ERR_MU:
+   mp_clear(mu);
+ERR_MP:
+   mp_montgomery_free(mp);
+ERR_P:
+   for (x = 0; x < 16; x++) {
+       ltc_ecc_del_point(precomp[x]);
+   }
+ERR_T:
+#ifdef LTC_CLEAN_STACK
+   zeromem(tA, ECC_BUF_SIZE);
+   zeromem(tB, ECC_BUF_SIZE);
+#endif
+   XFREE(tA);
+   XFREE(tB);
+
+   return err;
+}
+
+#endif
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/pk/ecc/ltc_ecc_mulmod.c b/libtomcrypt/src/pk/ecc/ltc_ecc_mulmod.c
new file mode 100644 (file)
index 0000000..5834865
--- /dev/null
@@ -0,0 +1,220 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+/* Implements ECC over Z/pZ for curve y^2 = x^3 - 3x + b
+ *
+ * All curves taken from NIST recommendation paper of July 1999
+ * Available at http://csrc.nist.gov/cryptval/dss.htm
+ */
+#include "tomcrypt.h"
+
+/**
+  @file ltc_ecc_mulmod.c
+  ECC Crypto, Tom St Denis
+*/
+
+#ifdef LTC_MECC
+#ifndef LTC_ECC_TIMING_RESISTANT
+
+/* size of sliding window, don't change this! */
+#define WINSIZE 4
+
+/**
+   Perform a point multiplication
+   @param k    The scalar to multiply by
+   @param G    The base point
+   @param R    [out] Destination for kG
+   @param modulus  The modulus of the field the ECC curve is in
+   @param map      Boolean whether to map back to affine or not (1==map, 0 == leave in projective)
+   @return CRYPT_OK on success
+*/
+int ltc_ecc_mulmod(void *k, ecc_point *G, ecc_point *R, void *modulus, int map)
+{
+   ecc_point *tG, *M[8];
+   int        i, j, err;
+   void       *mu, *mp;
+   ltc_mp_digit buf;
+   int        first, bitbuf, bitcpy, bitcnt, mode, digidx;
+
+   LTC_ARGCHK(k       != NULL);
+   LTC_ARGCHK(G       != NULL);
+   LTC_ARGCHK(R       != NULL);
+   LTC_ARGCHK(modulus != NULL);
+
+   /* init montgomery reduction */
+   if ((err = mp_montgomery_setup(modulus, &mp)) != CRYPT_OK) {
+      return err;
+   }
+   if ((err = mp_init(&mu)) != CRYPT_OK) {
+      mp_montgomery_free(mp);
+      return err;
+   }
+   if ((err = mp_montgomery_normalization(mu, modulus)) != CRYPT_OK) {
+      mp_montgomery_free(mp);
+      mp_clear(mu);
+      return err;
+   }
+
+  /* alloc ram for window temps */
+  for (i = 0; i < 8; i++) {
+      M[i] = ltc_ecc_new_point();
+      if (M[i] == NULL) {
+         for (j = 0; j < i; j++) {
+             ltc_ecc_del_point(M[j]);
+         }
+         mp_montgomery_free(mp);
+         mp_clear(mu);
+         return CRYPT_MEM;
+      }
+  }
+
+   /* make a copy of G incase R==G */
+   tG = ltc_ecc_new_point();
+   if (tG == NULL)                                                                   { err = CRYPT_MEM; goto done; }
+
+   /* tG = G  and convert to montgomery */
+   if (mp_cmp_d(mu, 1) == LTC_MP_EQ) {
+      if ((err = mp_copy(G->x, tG->x)) != CRYPT_OK)                                  { goto done; }
+      if ((err = mp_copy(G->y, tG->y)) != CRYPT_OK)                                  { goto done; }
+      if ((err = mp_copy(G->z, tG->z)) != CRYPT_OK)                                  { goto done; }
+   } else {
+      if ((err = mp_mulmod(G->x, mu, modulus, tG->x)) != CRYPT_OK)                   { goto done; }
+      if ((err = mp_mulmod(G->y, mu, modulus, tG->y)) != CRYPT_OK)                   { goto done; }
+      if ((err = mp_mulmod(G->z, mu, modulus, tG->z)) != CRYPT_OK)                   { goto done; }
+   }
+   mp_clear(mu);
+   mu = NULL;
+
+   /* calc the M tab, which holds kG for k==8..15 */
+   /* M[0] == 8G */
+   if ((err = ltc_mp.ecc_ptdbl(tG, M[0], modulus, mp)) != CRYPT_OK)                 { goto done; }
+   if ((err = ltc_mp.ecc_ptdbl(M[0], M[0], modulus, mp)) != CRYPT_OK)               { goto done; }
+   if ((err = ltc_mp.ecc_ptdbl(M[0], M[0], modulus, mp)) != CRYPT_OK)               { goto done; }
+
+   /* now find (8+k)G for k=1..7 */
+   for (j = 9; j < 16; j++) {
+       if ((err = ltc_mp.ecc_ptadd(M[j-9], tG, M[j-8], modulus, mp)) != CRYPT_OK)   { goto done; }
+   }
+
+   /* setup sliding window */
+   mode   = 0;
+   bitcnt = 1;
+   buf    = 0;
+   digidx = mp_get_digit_count(k) - 1;
+   bitcpy = bitbuf = 0;
+   first  = 1;
+
+   /* perform ops */
+   for (;;) {
+     /* grab next digit as required */
+     if (--bitcnt == 0) {
+       if (digidx == -1) {
+          break;
+       }
+       buf    = mp_get_digit(k, digidx);
+       bitcnt = (int) ltc_mp.bits_per_digit;
+       --digidx;
+     }
+
+     /* grab the next msb from the ltiplicand */
+     i = (buf >> (ltc_mp.bits_per_digit - 1)) & 1;
+     buf <<= 1;
+
+     /* skip leading zero bits */
+     if (mode == 0 && i == 0) {
+        continue;
+     }
+
+     /* if the bit is zero and mode == 1 then we double */
+     if (mode == 1 && i == 0) {
+        if ((err = ltc_mp.ecc_ptdbl(R, R, modulus, mp)) != CRYPT_OK)                 { goto done; }
+        continue;
+     }
+
+     /* else we add it to the window */
+     bitbuf |= (i << (WINSIZE - ++bitcpy));
+     mode = 2;
+
+     if (bitcpy == WINSIZE) {
+       /* if this is the first window we do a simple copy */
+       if (first == 1) {
+          /* R = kG [k = first window] */
+          if ((err = mp_copy(M[bitbuf-8]->x, R->x)) != CRYPT_OK)                     { goto done; }
+          if ((err = mp_copy(M[bitbuf-8]->y, R->y)) != CRYPT_OK)                     { goto done; }
+          if ((err = mp_copy(M[bitbuf-8]->z, R->z)) != CRYPT_OK)                     { goto done; }
+          first = 0;
+       } else {
+         /* normal window */
+         /* ok window is filled so double as required and add  */
+         /* double first */
+         for (j = 0; j < WINSIZE; j++) {
+           if ((err = ltc_mp.ecc_ptdbl(R, R, modulus, mp)) != CRYPT_OK)              { goto done; }
+         }
+
+         /* then add, bitbuf will be 8..15 [8..2^WINSIZE] guaranteed */
+         if ((err = ltc_mp.ecc_ptadd(R, M[bitbuf-8], R, modulus, mp)) != CRYPT_OK)   { goto done; }
+       }
+       /* empty window and reset */
+       bitcpy = bitbuf = 0;
+       mode = 1;
+    }
+  }
+
+   /* if bits remain then double/add */
+   if (mode == 2 && bitcpy > 0) {
+     /* double then add */
+     for (j = 0; j < bitcpy; j++) {
+       /* only double if we have had at least one add first */
+       if (first == 0) {
+          if ((err = ltc_mp.ecc_ptdbl(R, R, modulus, mp)) != CRYPT_OK)              { goto done; }
+       }
+
+       bitbuf <<= 1;
+       if ((bitbuf & (1 << WINSIZE)) != 0) {
+         if (first == 1){
+            /* first add, so copy */
+            if ((err = mp_copy(tG->x, R->x)) != CRYPT_OK)                           { goto done; }
+            if ((err = mp_copy(tG->y, R->y)) != CRYPT_OK)                           { goto done; }
+            if ((err = mp_copy(tG->z, R->z)) != CRYPT_OK)                           { goto done; }
+            first = 0;
+         } else {
+            /* then add */
+            if ((err = ltc_mp.ecc_ptadd(R, tG, R, modulus, mp)) != CRYPT_OK)        { goto done; }
+         }
+       }
+     }
+   }
+
+   /* map R back from projective space */
+   if (map) {
+      err = ltc_ecc_map(R, modulus, mp);
+   } else {
+      err = CRYPT_OK;
+   }
+done:
+   if (mu != NULL) {
+      mp_clear(mu);
+   }
+   mp_montgomery_free(mp);
+   ltc_ecc_del_point(tG);
+   for (i = 0; i < 8; i++) {
+       ltc_ecc_del_point(M[i]);
+   }
+   return err;
+}
+
+#endif
+
+#undef WINSIZE
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/pk/ecc/ltc_ecc_mulmod_timing.c b/libtomcrypt/src/pk/ecc/ltc_ecc_mulmod_timing.c
new file mode 100644 (file)
index 0000000..ab26ede
--- /dev/null
@@ -0,0 +1,163 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+/* Implements ECC over Z/pZ for curve y^2 = x^3 - 3x + b
+ *
+ * All curves taken from NIST recommendation paper of July 1999
+ * Available at http://csrc.nist.gov/cryptval/dss.htm
+ */
+#include "tomcrypt.h"
+
+/**
+  @file ltc_ecc_mulmod_timing.c
+  ECC Crypto, Tom St Denis
+*/
+
+#ifdef LTC_MECC
+
+#ifdef LTC_ECC_TIMING_RESISTANT
+
+/**
+   Perform a point multiplication  (timing resistant)
+   @param k    The scalar to multiply by
+   @param G    The base point
+   @param R    [out] Destination for kG
+   @param modulus  The modulus of the field the ECC curve is in
+   @param map      Boolean whether to map back to affine or not (1==map, 0 == leave in projective)
+   @return CRYPT_OK on success
+*/
+int ltc_ecc_mulmod(void *k, ecc_point *G, ecc_point *R, void *modulus, int map)
+{
+   ecc_point *tG, *M[3];
+   int        i, j, err;
+   void       *mu, *mp;
+   ltc_mp_digit buf;
+   int        bitcnt, mode, digidx;
+
+   LTC_ARGCHK(k       != NULL);
+   LTC_ARGCHK(G       != NULL);
+   LTC_ARGCHK(R       != NULL);
+   LTC_ARGCHK(modulus != NULL);
+
+   /* init montgomery reduction */
+   if ((err = mp_montgomery_setup(modulus, &mp)) != CRYPT_OK) {
+      return err;
+   }
+   if ((err = mp_init(&mu)) != CRYPT_OK) {
+      mp_montgomery_free(mp);
+      return err;
+   }
+   if ((err = mp_montgomery_normalization(mu, modulus)) != CRYPT_OK) {
+      mp_clear(mu);
+      mp_montgomery_free(mp);
+      return err;
+   }
+
+   /* alloc ram for window temps */
+   for (i = 0; i < 3; i++) {
+      M[i] = ltc_ecc_new_point();
+      if (M[i] == NULL) {
+         for (j = 0; j < i; j++) {
+             ltc_ecc_del_point(M[j]);
+         }
+         mp_clear(mu);
+         mp_montgomery_free(mp);
+         return CRYPT_MEM;
+      }
+   }
+
+   /* make a copy of G incase R==G */
+   tG = ltc_ecc_new_point();
+   if (tG == NULL)                                                                   { err = CRYPT_MEM; goto done; }
+
+   /* tG = G  and convert to montgomery */
+   if ((err = mp_mulmod(G->x, mu, modulus, tG->x)) != CRYPT_OK)                      { goto done; }
+   if ((err = mp_mulmod(G->y, mu, modulus, tG->y)) != CRYPT_OK)                      { goto done; }
+   if ((err = mp_mulmod(G->z, mu, modulus, tG->z)) != CRYPT_OK)                      { goto done; }
+   mp_clear(mu);
+   mu = NULL;
+
+   /* calc the M tab */
+   /* M[0] == G */
+   if ((err = mp_copy(tG->x, M[0]->x)) != CRYPT_OK)                                  { goto done; }
+   if ((err = mp_copy(tG->y, M[0]->y)) != CRYPT_OK)                                  { goto done; }
+   if ((err = mp_copy(tG->z, M[0]->z)) != CRYPT_OK)                                  { goto done; }
+   /* M[1] == 2G */
+   if ((err = ltc_mp.ecc_ptdbl(tG, M[1], modulus, mp)) != CRYPT_OK)                  { goto done; }
+
+   /* setup sliding window */
+   mode   = 0;
+   bitcnt = 1;
+   buf    = 0;
+   digidx = mp_get_digit_count(k) - 1;
+
+   /* perform ops */
+   for (;;) {
+     /* grab next digit as required */
+      if (--bitcnt == 0) {
+         if (digidx == -1) {
+            break;
+         }
+         buf    = mp_get_digit(k, digidx);
+         bitcnt = (int) MP_DIGIT_BIT;
+         --digidx;
+      }
+
+      /* grab the next msb from the ltiplicand */
+      i = (buf >> (MP_DIGIT_BIT - 1)) & 1;
+      buf <<= 1;
+
+      if (mode == 0 && i == 0) {
+         /* dummy operations */
+         if ((err = ltc_mp.ecc_ptadd(M[0], M[1], M[2], modulus, mp)) != CRYPT_OK)    { goto done; }
+         if ((err = ltc_mp.ecc_ptdbl(M[1], M[2], modulus, mp)) != CRYPT_OK)          { goto done; }
+         continue;
+      }
+
+      if (mode == 0 && i == 1) {
+         mode = 1;
+         /* dummy operations */
+         if ((err = ltc_mp.ecc_ptadd(M[0], M[1], M[2], modulus, mp)) != CRYPT_OK)    { goto done; }
+         if ((err = ltc_mp.ecc_ptdbl(M[1], M[2], modulus, mp)) != CRYPT_OK)          { goto done; }
+         continue;
+      }
+
+      if ((err = ltc_mp.ecc_ptadd(M[0], M[1], M[i^1], modulus, mp)) != CRYPT_OK)     { goto done; }
+      if ((err = ltc_mp.ecc_ptdbl(M[i], M[i], modulus, mp)) != CRYPT_OK)             { goto done; }
+   }
+
+   /* copy result out */
+   if ((err = mp_copy(M[0]->x, R->x)) != CRYPT_OK)                                   { goto done; }
+   if ((err = mp_copy(M[0]->y, R->y)) != CRYPT_OK)                                   { goto done; }
+   if ((err = mp_copy(M[0]->z, R->z)) != CRYPT_OK)                                   { goto done; }
+
+   /* map R back from projective space */
+   if (map) {
+      err = ltc_ecc_map(R, modulus, mp);
+   } else {
+      err = CRYPT_OK;
+   }
+done:
+   if (mu != NULL) {
+      mp_clear(mu);
+   }
+   mp_montgomery_free(mp);
+   ltc_ecc_del_point(tG);
+   for (i = 0; i < 3; i++) {
+       ltc_ecc_del_point(M[i]);
+   }
+   return err;
+}
+
+#endif
+#endif
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
+
diff --git a/libtomcrypt/src/pk/ecc/ltc_ecc_points.c b/libtomcrypt/src/pk/ecc/ltc_ecc_points.c
new file mode 100644 (file)
index 0000000..a63bdb5
--- /dev/null
@@ -0,0 +1,58 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+/* Implements ECC over Z/pZ for curve y^2 = x^3 - 3x + b
+ *
+ * All curves taken from NIST recommendation paper of July 1999
+ * Available at http://csrc.nist.gov/cryptval/dss.htm
+ */
+#include "tomcrypt.h"
+
+/**
+  @file ltc_ecc_points.c
+  ECC Crypto, Tom St Denis
+*/
+
+#ifdef LTC_MECC
+
+/**
+   Allocate a new ECC point
+   @return A newly allocated point or NULL on error
+*/
+ecc_point *ltc_ecc_new_point(void)
+{
+   ecc_point *p;
+   p = XCALLOC(1, sizeof(*p));
+   if (p == NULL) {
+      return NULL;
+   }
+   if (mp_init_multi(&p->x, &p->y, &p->z, NULL) != CRYPT_OK) {
+      XFREE(p);
+      return NULL;
+   }
+   return p;
+}
+
+/** Free an ECC point from memory
+  @param p   The point to free
+*/
+void ltc_ecc_del_point(ecc_point *p)
+{
+   /* prevents free'ing null arguments */
+   if (p != NULL) {
+      mp_clear_multi(p->x, p->y, p->z, NULL); /* note: p->z may be NULL but that's ok with this function anyways */
+      XFREE(p);
+   }
+}
+
+#endif
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
+
diff --git a/libtomcrypt/src/pk/ecc/ltc_ecc_projective_add_point.c b/libtomcrypt/src/pk/ecc/ltc_ecc_projective_add_point.c
new file mode 100644 (file)
index 0000000..9e22e10
--- /dev/null
@@ -0,0 +1,194 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+/* Implements ECC over Z/pZ for curve y^2 = x^3 - 3x + b
+ *
+ * All curves taken from NIST recommendation paper of July 1999
+ * Available at http://csrc.nist.gov/cryptval/dss.htm
+ */
+#include "tomcrypt.h"
+
+/**
+  @file ltc_ecc_projective_add_point.c
+  ECC Crypto, Tom St Denis
+*/
+
+#if defined(LTC_MECC) && (!defined(LTC_MECC_ACCEL) || defined(LTM_DESC))
+
+/**
+   Add two ECC points
+   @param P        The point to add
+   @param Q        The point to add
+   @param R        [out] The destination of the double
+   @param modulus  The modulus of the field the ECC curve is in
+   @param mp       The "b" value from montgomery_setup()
+   @return CRYPT_OK on success
+*/
+int ltc_ecc_projective_add_point(ecc_point *P, ecc_point *Q, ecc_point *R, void *modulus, void *mp)
+{
+   void  *t1, *t2, *x, *y, *z;
+   int    err;
+
+   LTC_ARGCHK(P       != NULL);
+   LTC_ARGCHK(Q       != NULL);
+   LTC_ARGCHK(R       != NULL);
+   LTC_ARGCHK(modulus != NULL);
+   LTC_ARGCHK(mp      != NULL);
+
+   if ((err = mp_init_multi(&t1, &t2, &x, &y, &z, NULL)) != CRYPT_OK) {
+      return err;
+   }
+
+   /* should we dbl instead? */
+   if ((err = mp_sub(modulus, Q->y, t1)) != CRYPT_OK)                          { goto done; }
+
+   if ( (mp_cmp(P->x, Q->x) == LTC_MP_EQ) &&
+        (Q->z != NULL && mp_cmp(P->z, Q->z) == LTC_MP_EQ) &&
+        (mp_cmp(P->y, Q->y) == LTC_MP_EQ || mp_cmp(P->y, t1) == LTC_MP_EQ)) {
+        mp_clear_multi(t1, t2, x, y, z, NULL);
+        return ltc_ecc_projective_dbl_point(P, R, modulus, mp);
+   }
+
+   if ((err = mp_copy(P->x, x)) != CRYPT_OK)                                   { goto done; }
+   if ((err = mp_copy(P->y, y)) != CRYPT_OK)                                   { goto done; }
+   if ((err = mp_copy(P->z, z)) != CRYPT_OK)                                   { goto done; }
+
+   /* if Z is one then these are no-operations */
+   if (Q->z != NULL) {
+      /* T1 = Z' * Z' */
+      if ((err = mp_sqr(Q->z, t1)) != CRYPT_OK)                                { goto done; }
+      if ((err = mp_montgomery_reduce(t1, modulus, mp)) != CRYPT_OK)           { goto done; }
+      /* X = X * T1 */
+      if ((err = mp_mul(t1, x, x)) != CRYPT_OK)                                { goto done; }
+      if ((err = mp_montgomery_reduce(x, modulus, mp)) != CRYPT_OK)            { goto done; }
+      /* T1 = Z' * T1 */
+      if ((err = mp_mul(Q->z, t1, t1)) != CRYPT_OK)                            { goto done; }
+      if ((err = mp_montgomery_reduce(t1, modulus, mp)) != CRYPT_OK)           { goto done; }
+      /* Y = Y * T1 */
+      if ((err = mp_mul(t1, y, y)) != CRYPT_OK)                                { goto done; }
+      if ((err = mp_montgomery_reduce(y, modulus, mp)) != CRYPT_OK)            { goto done; }
+   }
+
+   /* T1 = Z*Z */
+   if ((err = mp_sqr(z, t1)) != CRYPT_OK)                                      { goto done; }
+   if ((err = mp_montgomery_reduce(t1, modulus, mp)) != CRYPT_OK)              { goto done; }
+   /* T2 = X' * T1 */
+   if ((err = mp_mul(Q->x, t1, t2)) != CRYPT_OK)                               { goto done; }
+   if ((err = mp_montgomery_reduce(t2, modulus, mp)) != CRYPT_OK)              { goto done; }
+   /* T1 = Z * T1 */
+   if ((err = mp_mul(z, t1, t1)) != CRYPT_OK)                                  { goto done; }
+   if ((err = mp_montgomery_reduce(t1, modulus, mp)) != CRYPT_OK)              { goto done; }
+   /* T1 = Y' * T1 */
+   if ((err = mp_mul(Q->y, t1, t1)) != CRYPT_OK)                               { goto done; }
+   if ((err = mp_montgomery_reduce(t1, modulus, mp)) != CRYPT_OK)              { goto done; }
+
+   /* Y = Y - T1 */
+   if ((err = mp_sub(y, t1, y)) != CRYPT_OK)                                   { goto done; }
+   if (mp_cmp_d(y, 0) == LTC_MP_LT) {
+      if ((err = mp_add(y, modulus, y)) != CRYPT_OK)                           { goto done; }
+   }
+   /* T1 = 2T1 */
+   if ((err = mp_add(t1, t1, t1)) != CRYPT_OK)                                 { goto done; }
+   if (mp_cmp(t1, modulus) != LTC_MP_LT) {
+      if ((err = mp_sub(t1, modulus, t1)) != CRYPT_OK)                         { goto done; }
+   }
+   /* T1 = Y + T1 */
+   if ((err = mp_add(t1, y, t1)) != CRYPT_OK)                                  { goto done; }
+   if (mp_cmp(t1, modulus) != LTC_MP_LT) {
+      if ((err = mp_sub(t1, modulus, t1)) != CRYPT_OK)                         { goto done; }
+   }
+   /* X = X - T2 */
+   if ((err = mp_sub(x, t2, x)) != CRYPT_OK)                                   { goto done; }
+   if (mp_cmp_d(x, 0) == LTC_MP_LT) {
+      if ((err = mp_add(x, modulus, x)) != CRYPT_OK)                           { goto done; }
+   }
+   /* T2 = 2T2 */
+   if ((err = mp_add(t2, t2, t2)) != CRYPT_OK)                                 { goto done; }
+   if (mp_cmp(t2, modulus) != LTC_MP_LT) {
+      if ((err = mp_sub(t2, modulus, t2)) != CRYPT_OK)                         { goto done; }
+   }
+   /* T2 = X + T2 */
+   if ((err = mp_add(t2, x, t2)) != CRYPT_OK)                                  { goto done; }
+   if (mp_cmp(t2, modulus) != LTC_MP_LT) {
+      if ((err = mp_sub(t2, modulus, t2)) != CRYPT_OK)                         { goto done; }
+   }
+
+   /* if Z' != 1 */
+   if (Q->z != NULL) {
+      /* Z = Z * Z' */
+      if ((err = mp_mul(z, Q->z, z)) != CRYPT_OK)                              { goto done; }
+      if ((err = mp_montgomery_reduce(z, modulus, mp)) != CRYPT_OK)            { goto done; }
+   }
+
+   /* Z = Z * X */
+   if ((err = mp_mul(z, x, z)) != CRYPT_OK)                                    { goto done; }
+   if ((err = mp_montgomery_reduce(z, modulus, mp)) != CRYPT_OK)               { goto done; }
+
+   /* T1 = T1 * X  */
+   if ((err = mp_mul(t1, x, t1)) != CRYPT_OK)                                  { goto done; }
+   if ((err = mp_montgomery_reduce(t1, modulus, mp)) != CRYPT_OK)              { goto done; }
+   /* X = X * X */
+   if ((err = mp_sqr(x, x)) != CRYPT_OK)                                       { goto done; }
+   if ((err = mp_montgomery_reduce(x, modulus, mp)) != CRYPT_OK)               { goto done; }
+   /* T2 = T2 * x */
+   if ((err = mp_mul(t2, x, t2)) != CRYPT_OK)                                  { goto done; }
+   if ((err = mp_montgomery_reduce(t2, modulus, mp)) != CRYPT_OK)              { goto done; }
+   /* T1 = T1 * X  */
+   if ((err = mp_mul(t1, x, t1)) != CRYPT_OK)                                  { goto done; }
+   if ((err = mp_montgomery_reduce(t1, modulus, mp)) != CRYPT_OK)              { goto done; }
+
+   /* X = Y*Y */
+   if ((err = mp_sqr(y, x)) != CRYPT_OK)                                       { goto done; }
+   if ((err = mp_montgomery_reduce(x, modulus, mp)) != CRYPT_OK)               { goto done; }
+   /* X = X - T2 */
+   if ((err = mp_sub(x, t2, x)) != CRYPT_OK)                                   { goto done; }
+   if (mp_cmp_d(x, 0) == LTC_MP_LT) {
+      if ((err = mp_add(x, modulus, x)) != CRYPT_OK)                           { goto done; }
+   }
+
+   /* T2 = T2 - X */
+   if ((err = mp_sub(t2, x, t2)) != CRYPT_OK)                                  { goto done; }
+   if (mp_cmp_d(t2, 0) == LTC_MP_LT) {
+      if ((err = mp_add(t2, modulus, t2)) != CRYPT_OK)                         { goto done; }
+   }
+   /* T2 = T2 - X */
+   if ((err = mp_sub(t2, x, t2)) != CRYPT_OK)                                  { goto done; }
+   if (mp_cmp_d(t2, 0) == LTC_MP_LT) {
+      if ((err = mp_add(t2, modulus, t2)) != CRYPT_OK)                         { goto done; }
+   }
+   /* T2 = T2 * Y */
+   if ((err = mp_mul(t2, y, t2)) != CRYPT_OK)                                  { goto done; }
+   if ((err = mp_montgomery_reduce(t2, modulus, mp)) != CRYPT_OK)              { goto done; }
+   /* Y = T2 - T1 */
+   if ((err = mp_sub(t2, t1, y)) != CRYPT_OK)                                  { goto done; }
+   if (mp_cmp_d(y, 0) == LTC_MP_LT) {
+      if ((err = mp_add(y, modulus, y)) != CRYPT_OK)                           { goto done; }
+   }
+   /* Y = Y/2 */
+   if (mp_isodd(y)) {
+      if ((err = mp_add(y, modulus, y)) != CRYPT_OK)                           { goto done; }
+   }
+   if ((err = mp_div_2(y, y)) != CRYPT_OK)                                     { goto done; }
+
+   if ((err = mp_copy(x, R->x)) != CRYPT_OK)                                   { goto done; }
+   if ((err = mp_copy(y, R->y)) != CRYPT_OK)                                   { goto done; }
+   if ((err = mp_copy(z, R->z)) != CRYPT_OK)                                   { goto done; }
+
+   err = CRYPT_OK;
+done:
+   mp_clear_multi(t1, t2, x, y, z, NULL);
+   return err;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
+
diff --git a/libtomcrypt/src/pk/ecc/ltc_ecc_projective_dbl_point.c b/libtomcrypt/src/pk/ecc/ltc_ecc_projective_dbl_point.c
new file mode 100644 (file)
index 0000000..0c6b996
--- /dev/null
@@ -0,0 +1,145 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+/* Implements ECC over Z/pZ for curve y^2 = x^3 - 3x + b
+ *
+ * All curves taken from NIST recommendation paper of July 1999
+ * Available at http://csrc.nist.gov/cryptval/dss.htm
+ */
+#include "tomcrypt.h"
+
+/**
+  @file ltc_ecc_projective_dbl_point.c
+  ECC Crypto, Tom St Denis
+*/
+
+#if defined(LTC_MECC) && (!defined(LTC_MECC_ACCEL) || defined(LTM_DESC))
+
+/**
+   Double an ECC point
+   @param P   The point to double
+   @param R   [out] The destination of the double
+   @param modulus  The modulus of the field the ECC curve is in
+   @param mp       The "b" value from montgomery_setup()
+   @return CRYPT_OK on success
+*/
+int ltc_ecc_projective_dbl_point(ecc_point *P, ecc_point *R, void *modulus, void *mp)
+{
+   void *t1, *t2;
+   int   err;
+
+   LTC_ARGCHK(P       != NULL);
+   LTC_ARGCHK(R       != NULL);
+   LTC_ARGCHK(modulus != NULL);
+   LTC_ARGCHK(mp      != NULL);
+
+   if ((err = mp_init_multi(&t1, &t2, NULL)) != CRYPT_OK) {
+      return err;
+   }
+
+   if (P != R) {
+      if ((err = mp_copy(P->x, R->x)) != CRYPT_OK)                                { goto done; }
+      if ((err = mp_copy(P->y, R->y)) != CRYPT_OK)                                { goto done; }
+      if ((err = mp_copy(P->z, R->z)) != CRYPT_OK)                                { goto done; }
+   }
+
+   /* t1 = Z * Z */
+   if ((err = mp_sqr(R->z, t1)) != CRYPT_OK)                                      { goto done; }
+   if ((err = mp_montgomery_reduce(t1, modulus, mp)) != CRYPT_OK)                 { goto done; }
+   /* Z = Y * Z */
+   if ((err = mp_mul(R->z, R->y, R->z)) != CRYPT_OK)                              { goto done; }
+   if ((err = mp_montgomery_reduce(R->z, modulus, mp)) != CRYPT_OK)               { goto done; }
+   /* Z = 2Z */
+   if ((err = mp_add(R->z, R->z, R->z)) != CRYPT_OK)                              { goto done; }
+   if (mp_cmp(R->z, modulus) != LTC_MP_LT) {
+      if ((err = mp_sub(R->z, modulus, R->z)) != CRYPT_OK)                        { goto done; }
+   }
+
+   /* T2 = X - T1 */
+   if ((err = mp_sub(R->x, t1, t2)) != CRYPT_OK)                                  { goto done; }
+   if (mp_cmp_d(t2, 0) == LTC_MP_LT) {
+      if ((err = mp_add(t2, modulus, t2)) != CRYPT_OK)                            { goto done; }
+   }
+   /* T1 = X + T1 */
+   if ((err = mp_add(t1, R->x, t1)) != CRYPT_OK)                                  { goto done; }
+   if (mp_cmp(t1, modulus) != LTC_MP_LT) {
+      if ((err = mp_sub(t1, modulus, t1)) != CRYPT_OK)                            { goto done; }
+   }
+   /* T2 = T1 * T2 */
+   if ((err = mp_mul(t1, t2, t2)) != CRYPT_OK)                                    { goto done; }
+   if ((err = mp_montgomery_reduce(t2, modulus, mp)) != CRYPT_OK)                 { goto done; }
+   /* T1 = 2T2 */
+   if ((err = mp_add(t2, t2, t1)) != CRYPT_OK)                                    { goto done; }
+   if (mp_cmp(t1, modulus) != LTC_MP_LT) {
+      if ((err = mp_sub(t1, modulus, t1)) != CRYPT_OK)                            { goto done; }
+   }
+   /* T1 = T1 + T2 */
+   if ((err = mp_add(t1, t2, t1)) != CRYPT_OK)                                    { goto done; }
+   if (mp_cmp(t1, modulus) != LTC_MP_LT) {
+      if ((err = mp_sub(t1, modulus, t1)) != CRYPT_OK)                            { goto done; }
+   }
+
+   /* Y = 2Y */
+   if ((err = mp_add(R->y, R->y, R->y)) != CRYPT_OK)                              { goto done; }
+   if (mp_cmp(R->y, modulus) != LTC_MP_LT) {
+      if ((err = mp_sub(R->y, modulus, R->y)) != CRYPT_OK)                        { goto done; }
+   }
+   /* Y = Y * Y */
+   if ((err = mp_sqr(R->y, R->y)) != CRYPT_OK)                                    { goto done; }
+   if ((err = mp_montgomery_reduce(R->y, modulus, mp)) != CRYPT_OK)               { goto done; }
+   /* T2 = Y * Y */
+   if ((err = mp_sqr(R->y, t2)) != CRYPT_OK)                                      { goto done; }
+   if ((err = mp_montgomery_reduce(t2, modulus, mp)) != CRYPT_OK)                 { goto done; }
+   /* T2 = T2/2 */
+   if (mp_isodd(t2)) {
+      if ((err = mp_add(t2, modulus, t2)) != CRYPT_OK)                            { goto done; }
+   }
+   if ((err = mp_div_2(t2, t2)) != CRYPT_OK)                                      { goto done; }
+   /* Y = Y * X */
+   if ((err = mp_mul(R->y, R->x, R->y)) != CRYPT_OK)                              { goto done; }
+   if ((err = mp_montgomery_reduce(R->y, modulus, mp)) != CRYPT_OK)               { goto done; }
+
+   /* X  = T1 * T1 */
+   if ((err = mp_sqr(t1, R->x)) != CRYPT_OK)                                      { goto done; }
+   if ((err = mp_montgomery_reduce(R->x, modulus, mp)) != CRYPT_OK)               { goto done; }
+   /* X = X - Y */
+   if ((err = mp_sub(R->x, R->y, R->x)) != CRYPT_OK)                              { goto done; }
+   if (mp_cmp_d(R->x, 0) == LTC_MP_LT) {
+      if ((err = mp_add(R->x, modulus, R->x)) != CRYPT_OK)                        { goto done; }
+   }
+   /* X = X - Y */
+   if ((err = mp_sub(R->x, R->y, R->x)) != CRYPT_OK)                              { goto done; }
+   if (mp_cmp_d(R->x, 0) == LTC_MP_LT) {
+      if ((err = mp_add(R->x, modulus, R->x)) != CRYPT_OK)                        { goto done; }
+   }
+
+   /* Y = Y - X */
+   if ((err = mp_sub(R->y, R->x, R->y)) != CRYPT_OK)                              { goto done; }
+   if (mp_cmp_d(R->y, 0) == LTC_MP_LT) {
+      if ((err = mp_add(R->y, modulus, R->y)) != CRYPT_OK)                        { goto done; }
+   }
+   /* Y = Y * T1 */
+   if ((err = mp_mul(R->y, t1, R->y)) != CRYPT_OK)                                { goto done; }
+   if ((err = mp_montgomery_reduce(R->y, modulus, mp)) != CRYPT_OK)               { goto done; }
+   /* Y = Y - T2 */
+   if ((err = mp_sub(R->y, t2, R->y)) != CRYPT_OK)                                { goto done; }
+   if (mp_cmp_d(R->y, 0) == LTC_MP_LT) {
+      if ((err = mp_add(R->y, modulus, R->y)) != CRYPT_OK)                        { goto done; }
+   }
+
+   err = CRYPT_OK;
+done:
+   mp_clear_multi(t1, t2, NULL);
+   return err;
+}
+#endif
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
+
diff --git a/libtomcrypt/src/pk/katja/katja_decrypt_key.c b/libtomcrypt/src/pk/katja/katja_decrypt_key.c
new file mode 100644 (file)
index 0000000..72009b0
--- /dev/null
@@ -0,0 +1,103 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file katja_decrypt_key.c
+  Katja PKCS #1 OAEP Decryption, Tom St Denis
+*/
+
+#ifdef LTC_MKAT
+
+/**
+   (PKCS #1 v2.0) decrypt then OAEP depad
+   @param in          The ciphertext
+   @param inlen       The length of the ciphertext (octets)
+   @param out         [out] The plaintext
+   @param outlen      [in/out] The max size and resulting size of the plaintext (octets)
+   @param lparam      The system "lparam" value
+   @param lparamlen   The length of the lparam value (octets)
+   @param hash_idx    The index of the hash desired
+   @param stat        [out] Result of the decryption, 1==valid, 0==invalid
+   @param key         The corresponding private Katja key
+   @return CRYPT_OK if succcessul (even if invalid)
+*/
+int katja_decrypt_key(const unsigned char *in,       unsigned long  inlen,
+                          unsigned char *out,      unsigned long *outlen,
+                    const unsigned char *lparam,   unsigned long  lparamlen,
+                          int            hash_idx, int           *stat,
+                          katja_key       *key)
+{
+  unsigned long modulus_bitlen, modulus_bytelen, x;
+  int           err;
+  unsigned char *tmp;
+
+  LTC_ARGCHK(out    != NULL);
+  LTC_ARGCHK(outlen != NULL);
+  LTC_ARGCHK(key    != NULL);
+  LTC_ARGCHK(stat   != NULL);
+
+  /* default to invalid */
+  *stat = 0;
+
+  /* valid hash ? */
+  if ((err = hash_is_valid(hash_idx)) != CRYPT_OK) {
+     return err;
+  }
+
+  /* get modulus len in bits */
+  modulus_bitlen = mp_count_bits( (key->N));
+
+  /* payload is upto pq, so we know q is 1/3rd the size of N and therefore pq is 2/3th the size */
+ modulus_bitlen = ((modulus_bitlen << 1) / 3);
+
+  /* round down to next byte */
+  modulus_bitlen -= (modulus_bitlen & 7) + 8;
+
+  /* outlen must be at least the size of the modulus */
+  modulus_bytelen = mp_unsigned_bin_size( (key->N));
+  if (modulus_bytelen != inlen) {
+     return CRYPT_INVALID_PACKET;
+  }
+
+  /* allocate ram */
+  tmp = XMALLOC(inlen);
+  if (tmp == NULL) {
+     return CRYPT_MEM;
+  }
+
+  /* rsa decode the packet */
+  x = inlen;
+  if ((err = katja_exptmod(in, inlen, tmp, &x, PK_PRIVATE, key)) != CRYPT_OK) {
+     XFREE(tmp);
+     return err;
+  }
+
+  /* shift right by modulus_bytelen - modulus_bitlen/8  bytes */
+  for (x = 0; x < (modulus_bitlen >> 3); x++) {
+     tmp[x] = tmp[x+(modulus_bytelen-(modulus_bitlen>>3))];
+  }
+
+  /* now OAEP decode the packet */
+  err = pkcs_1_oaep_decode(tmp, x, lparam, lparamlen, modulus_bitlen, hash_idx,
+                           out, outlen, stat);
+
+  XFREE(tmp);
+  return err;
+}
+
+#endif /* LTC_MRSA */
+
+
+
+
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/pk/katja/katja_encrypt_key.c b/libtomcrypt/src/pk/katja/katja_encrypt_key.c
new file mode 100644 (file)
index 0000000..9ed72fb
--- /dev/null
@@ -0,0 +1,85 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file katja_encrypt_key.c
+  Katja PKCS-style OAEP encryption, Tom St Denis
+*/
+
+#ifdef LTC_MKAT
+
+/**
+    (PKCS #1 v2.0) OAEP pad then encrypt
+    @param in          The plaintext
+    @param inlen       The length of the plaintext (octets)
+    @param out         [out] The ciphertext
+    @param outlen      [in/out] The max size and resulting size of the ciphertext
+    @param lparam      The system "lparam" for the encryption
+    @param lparamlen   The length of lparam (octets)
+    @param prng        An active PRNG
+    @param prng_idx    The index of the desired prng
+    @param hash_idx    The index of the desired hash
+    @param key         The Katja key to encrypt to
+    @return CRYPT_OK if successful
+*/
+int katja_encrypt_key(const unsigned char *in,     unsigned long inlen,
+                          unsigned char *out,    unsigned long *outlen,
+                    const unsigned char *lparam, unsigned long lparamlen,
+                    prng_state *prng, int prng_idx, int hash_idx, katja_key *key)
+{
+  unsigned long modulus_bitlen, modulus_bytelen, x;
+  int           err;
+
+  LTC_ARGCHK(in     != NULL);
+  LTC_ARGCHK(out    != NULL);
+  LTC_ARGCHK(outlen != NULL);
+  LTC_ARGCHK(key    != NULL);
+
+  /* valid prng and hash ? */
+  if ((err = prng_is_valid(prng_idx)) != CRYPT_OK) {
+     return err;
+  }
+  if ((err = hash_is_valid(hash_idx)) != CRYPT_OK) {
+     return err;
+  }
+
+  /* get modulus len in bits */
+  modulus_bitlen = mp_count_bits((key->N));
+
+  /* payload is upto pq, so we know q is 1/3rd the size of N and therefore pq is 2/3th the size */
+  modulus_bitlen = ((modulus_bitlen << 1) / 3);
+
+  /* round down to next byte */
+  modulus_bitlen -= (modulus_bitlen & 7) + 8;
+
+  /* outlen must be at least the size of the modulus */
+  modulus_bytelen = mp_unsigned_bin_size((key->N));
+  if (modulus_bytelen > *outlen) {
+     *outlen = modulus_bytelen;
+     return CRYPT_BUFFER_OVERFLOW;
+  }
+
+  /* OAEP pad the key */
+  x = *outlen;
+  if ((err = pkcs_1_oaep_encode(in, inlen, lparam,
+                                lparamlen, modulus_bitlen, prng, prng_idx, hash_idx,
+                                out, &x)) != CRYPT_OK) {
+     return err;
+  }
+
+  /* Katja exptmod the OAEP pad */
+  return katja_exptmod(out, x, out, outlen, PK_PUBLIC, key);
+}
+
+#endif /* LTC_MRSA */
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/pk/katja/katja_export.c b/libtomcrypt/src/pk/katja/katja_export.c
new file mode 100644 (file)
index 0000000..0412e65
--- /dev/null
@@ -0,0 +1,73 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file katja_export.c
+  Export Katja PKCS-style keys, Tom St Denis
+*/
+
+#ifdef LTC_MKAT
+
+/**
+    This will export either an KatjaPublicKey or KatjaPrivateKey
+    @param out       [out] Destination of the packet
+    @param outlen    [in/out] The max size and resulting size of the packet
+    @param type      The type of exported key (PK_PRIVATE or PK_PUBLIC)
+    @param key       The Katja key to export
+    @return CRYPT_OK if successful
+*/
+int katja_export(unsigned char *out, unsigned long *outlen, int type, katja_key *key)
+{
+   int           err;
+   unsigned long zero=0;
+
+   LTC_ARGCHK(out    != NULL);
+   LTC_ARGCHK(outlen != NULL);
+   LTC_ARGCHK(key    != NULL);
+
+   /* type valid? */
+   if (!(key->type == PK_PRIVATE) && (type == PK_PRIVATE)) {
+      return CRYPT_PK_INVALID_TYPE;
+   }
+
+   if (type == PK_PRIVATE) {
+      /* private key */
+      /* output is
+            Version, n, d, p, q, d mod (p-1), d mod (q - 1), 1/q mod p, pq
+       */
+      if ((err = der_encode_sequence_multi(out, outlen,
+                          LTC_ASN1_SHORT_INTEGER, 1UL, &zero,
+                          LTC_ASN1_INTEGER, 1UL,  key->N,
+                          LTC_ASN1_INTEGER, 1UL,  key->d,
+                          LTC_ASN1_INTEGER, 1UL,  key->p,
+                          LTC_ASN1_INTEGER, 1UL,  key->q,
+                          LTC_ASN1_INTEGER, 1UL,  key->dP,
+                          LTC_ASN1_INTEGER, 1UL,  key->dQ,
+                          LTC_ASN1_INTEGER, 1UL,  key->qP,
+                          LTC_ASN1_INTEGER, 1UL,  key->pq,
+                          LTC_ASN1_EOL,     0UL, NULL)) != CRYPT_OK) {
+         return err;
+      }
+
+      /* clear zero and return */
+      return CRYPT_OK;
+   } else {
+      /* public key */
+      return der_encode_sequence_multi(out, outlen,
+                                 LTC_ASN1_INTEGER, 1UL, key->N,
+                                 LTC_ASN1_EOL,     0UL, NULL);
+   }
+}
+
+#endif /* LTC_MRSA */
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/pk/katja/katja_exptmod.c b/libtomcrypt/src/pk/katja/katja_exptmod.c
new file mode 100644 (file)
index 0000000..afc847f
--- /dev/null
@@ -0,0 +1,113 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file katja_exptmod.c
+  Katja PKCS-style exptmod, Tom St Denis
+*/
+
+#ifdef LTC_MKAT
+
+/**
+   Compute an RSA modular exponentiation
+   @param in         The input data to send into RSA
+   @param inlen      The length of the input (octets)
+   @param out        [out] The destination
+   @param outlen     [in/out] The max size and resulting size of the output
+   @param which      Which exponent to use, e.g. PK_PRIVATE or PK_PUBLIC
+   @param key        The RSA key to use
+   @return CRYPT_OK if successful
+*/
+int katja_exptmod(const unsigned char *in,   unsigned long inlen,
+                        unsigned char *out,  unsigned long *outlen, int which,
+                        katja_key *key)
+{
+   void         *tmp, *tmpa, *tmpb;
+   unsigned long x;
+   int           err;
+
+   LTC_ARGCHK(in     != NULL);
+   LTC_ARGCHK(out    != NULL);
+   LTC_ARGCHK(outlen != NULL);
+   LTC_ARGCHK(key    != NULL);
+
+   /* is the key of the right type for the operation? */
+   if (which == PK_PRIVATE && (key->type != PK_PRIVATE)) {
+      return CRYPT_PK_NOT_PRIVATE;
+   }
+
+   /* must be a private or public operation */
+   if (which != PK_PRIVATE && which != PK_PUBLIC) {
+      return CRYPT_PK_INVALID_TYPE;
+   }
+
+   /* init and copy into tmp */
+   if ((err = mp_init_multi(&tmp, &tmpa, &tmpb, NULL)) != CRYPT_OK)                                    { return err; }
+   if ((err = mp_read_unsigned_bin(tmp, (unsigned char *)in, (int)inlen)) != CRYPT_OK)                 { goto error; }
+
+   /* sanity check on the input */
+   if (mp_cmp(key->N, tmp) == LTC_MP_LT) {
+      err = CRYPT_PK_INVALID_SIZE;
+      goto done;
+   }
+
+   /* are we using the private exponent and is the key optimized? */
+   if (which == PK_PRIVATE) {
+      /* tmpa = tmp^dP mod p */
+      if ((err = mp_exptmod(tmp, key->dP, key->p, tmpa)) != CRYPT_OK)                               { goto error; }
+
+      /* tmpb = tmp^dQ mod q */
+      if ((err = mp_exptmod(tmp, key->dQ, key->q, tmpb)) != CRYPT_OK)                               { goto error; }
+
+      /* tmp = (tmpa - tmpb) * qInv (mod p) */
+      if ((err = mp_sub(tmpa, tmpb, tmp)) != CRYPT_OK)                                              { goto error; }
+      if ((err = mp_mulmod(tmp, key->qP, key->p, tmp)) != CRYPT_OK)                                 { goto error; }
+
+      /* tmp = tmpb + q * tmp */
+      if ((err = mp_mul(tmp, key->q, tmp)) != CRYPT_OK)                                             { goto error; }
+      if ((err = mp_add(tmp, tmpb, tmp)) != CRYPT_OK)                                               { goto error; }
+   } else {
+      /* exptmod it */
+      if ((err = mp_exptmod(tmp, key->N, key->N, tmp)) != CRYPT_OK)                                 { goto error; }
+   }
+
+   /* read it back */
+   x = (unsigned long)mp_unsigned_bin_size(key->N);
+   if (x > *outlen) {
+      *outlen = x;
+      err = CRYPT_BUFFER_OVERFLOW;
+      goto done;
+   }
+
+   /* this should never happen ... */
+   if (mp_unsigned_bin_size(tmp) > mp_unsigned_bin_size(key->N)) {
+      err = CRYPT_ERROR;
+      goto done;
+   }
+   *outlen = x;
+
+   /* convert it */
+   zeromem(out, x);
+   if ((err = mp_to_unsigned_bin(tmp, out+(x-mp_unsigned_bin_size(tmp)))) != CRYPT_OK)               { goto error; }
+
+   /* clean up and return */
+   err = CRYPT_OK;
+   goto done;
+error:
+done:
+   mp_clear_multi(tmp, tmpa, tmpb, NULL);
+   return err;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/pk/katja/katja_free.c b/libtomcrypt/src/pk/katja/katja_free.c
new file mode 100644 (file)
index 0000000..117bbf4
--- /dev/null
@@ -0,0 +1,33 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file katja_free.c
+  Free an Katja key, Tom St Denis
+*/
+
+#ifdef LTC_MKAT
+
+/**
+  Free an Katja key from memory
+  @param key   The RSA key to free
+*/
+void katja_free(katja_key *key)
+{
+   LTC_ARGCHK(key != NULL);
+   mp_clear_multi( key->d,  key->N,  key->dQ,  key->dP,
+                   key->qP,  key->p,  key->q, key->pq, NULL);
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/pk/katja/katja_import.c b/libtomcrypt/src/pk/katja/katja_import.c
new file mode 100644 (file)
index 0000000..98357c0
--- /dev/null
@@ -0,0 +1,79 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file katja_import.c
+  Import a PKCS-style Katja key, Tom St Denis
+*/
+
+#ifdef LTC_MKAT
+
+/**
+  Import an KatjaPublicKey or KatjaPrivateKey [two-prime only, only support >= 1024-bit keys, defined in PKCS #1 v2.1]
+  @param in      The packet to import from
+  @param inlen   It's length (octets)
+  @param key     [out] Destination for newly imported key
+  @return CRYPT_OK if successful, upon error allocated memory is freed
+*/
+int katja_import(const unsigned char *in, unsigned long inlen, katja_key *key)
+{
+   int           err;
+   void         *zero;
+
+   LTC_ARGCHK(in  != NULL);
+   LTC_ARGCHK(key != NULL);
+   LTC_ARGCHK(ltc_mp.name != NULL);
+
+   /* init key */
+   if ((err = mp_init_multi(&zero, &key->d, &key->N, &key->dQ,
+                            &key->dP, &key->qP, &key->p, &key->q, &key->pq, NULL)) != CRYPT_OK) {
+      return err;
+   }
+
+   if ((err = der_decode_sequence_multi(in, inlen,
+                                  LTC_ASN1_INTEGER, 1UL, key->N,
+                                  LTC_ASN1_EOL,     0UL, NULL)) != CRYPT_OK) {
+      goto LBL_ERR;
+   }
+
+   if (mp_cmp_d(key->N, 0) == LTC_MP_EQ) {
+      /* it's a private key */
+      if ((err = der_decode_sequence_multi(in, inlen,
+                          LTC_ASN1_INTEGER, 1UL, zero,
+                          LTC_ASN1_INTEGER, 1UL, key->N,
+                          LTC_ASN1_INTEGER, 1UL, key->d,
+                          LTC_ASN1_INTEGER, 1UL, key->p,
+                          LTC_ASN1_INTEGER, 1UL, key->q,
+                          LTC_ASN1_INTEGER, 1UL, key->dP,
+                          LTC_ASN1_INTEGER, 1UL, key->dQ,
+                          LTC_ASN1_INTEGER, 1UL, key->qP,
+                          LTC_ASN1_INTEGER, 1UL, key->pq,
+                          LTC_ASN1_EOL,     0UL, NULL)) != CRYPT_OK) {
+         goto LBL_ERR;
+      }
+      key->type = PK_PRIVATE;
+   } else {
+      /* public we have N */
+      key->type = PK_PUBLIC;
+   }
+   mp_clear(zero);
+   return CRYPT_OK;
+LBL_ERR:
+   mp_clear_multi(zero,    key->d, key->N, key->dQ, key->dP,
+                  key->qP, key->p, key->q, key->pq, NULL);
+   return err;
+}
+
+#endif /* LTC_MRSA */
+
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/pk/katja/katja_make_key.c b/libtomcrypt/src/pk/katja/katja_make_key.c
new file mode 100644 (file)
index 0000000..6f83bcc
--- /dev/null
@@ -0,0 +1,99 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file katja_make_key.c
+  Katja key generation, Tom St Denis
+*/
+
+#ifdef LTC_MKAT
+
+/**
+   Create a Katja key
+   @param prng     An active PRNG state
+   @param wprng    The index of the PRNG desired
+   @param size     The size of the modulus (key size) desired (octets)
+   @param key      [out] Destination of a newly created private key pair
+   @return CRYPT_OK if successful, upon error all allocated ram is freed
+*/
+int katja_make_key(prng_state *prng, int wprng, int size, katja_key *key)
+{
+   void *p, *q, *tmp1, *tmp2;
+   int    err;
+
+   LTC_ARGCHK(key != NULL);
+   LTC_ARGCHK(ltc_mp.name != NULL);
+
+   if ((size < (MIN_KAT_SIZE/8)) || (size > (MAX_KAT_SIZE/8))) {
+      return CRYPT_INVALID_KEYSIZE;
+   }
+
+   if ((err = prng_is_valid(wprng)) != CRYPT_OK) {
+      return err;
+   }
+
+   if ((err = mp_init_multi(&p, &q, &tmp1, &tmp2, NULL)) != CRYPT_OK) {
+      return err;
+   }
+
+   /* divide size by three  */
+   size   = (((size << 3) / 3) + 7) >> 3;
+
+   /* make prime "q" (we negate size to make q == 3 mod 4) */
+   if ((err = rand_prime(q, -size, prng, wprng)) != CRYPT_OK)      { goto done; }
+   if ((err = mp_sub_d(q, 1, tmp1)) != CRYPT_OK)                   { goto done; }
+
+   /* make prime "p" */
+   do {
+      if ((err = rand_prime(p, size+1, prng, wprng)) != CRYPT_OK)  { goto done; }
+      if ((err = mp_gcd(p, tmp1, tmp2)) != CRYPT_OK)               { goto done; }
+   } while (mp_cmp_d(tmp2, 1) != LTC_MP_EQ);
+
+   /* make key */
+   if ((err = mp_init_multi(&key->d, &key->N, &key->dQ, &key->dP,
+                     &key->qP, &key->p, &key->q, &key->pq, NULL)) != CRYPT_OK) {
+      goto error;
+   }
+
+   /* n=p^2q and 1/n mod pq */
+   if ((err = mp_copy( p,  key->p)) != CRYPT_OK)                       { goto error2; }
+   if ((err = mp_copy( q,  key->q)) != CRYPT_OK)                       { goto error2; }
+   if ((err = mp_mul(key->p, key->q, key->pq)) != CRYPT_OK)            { goto error2; } /* tmp1 = pq  */
+   if ((err = mp_mul(key->pq, key->p, key->N)) != CRYPT_OK)            { goto error2; } /* N = p^2q   */
+   if ((err = mp_sub_d( p, 1,  tmp1)) != CRYPT_OK)                     { goto error2; } /* tmp1 = q-1 */
+   if ((err = mp_sub_d( q, 1,  tmp2)) != CRYPT_OK)                     { goto error2; } /* tmp2 = p-1 */
+   if ((err = mp_lcm(tmp1, tmp2, key->d)) != CRYPT_OK)                 { goto error2; } /* tmp1 = lcd(p-1,q-1) */
+   if ((err = mp_invmod( key->N,  key->d,  key->d)) != CRYPT_OK)       { goto error2; } /* key->d = 1/N mod pq */
+
+   /* optimize for CRT now */
+   /* find d mod q-1 and d mod p-1 */
+   if ((err = mp_mod( key->d,  tmp1,  key->dP)) != CRYPT_OK)           { goto error2; } /* dP = d mod p-1 */
+   if ((err = mp_mod( key->d,  tmp2,  key->dQ)) != CRYPT_OK)           { goto error2; } /* dQ = d mod q-1 */
+   if ((err = mp_invmod( q,  p,  key->qP)) != CRYPT_OK)                { goto error2; } /* qP = 1/q mod p */
+
+   /* set key type (in this case it's CRT optimized) */
+   key->type = PK_PRIVATE;
+
+   /* return ok and free temps */
+   err       = CRYPT_OK;
+   goto done;
+error2:
+   mp_clear_multi( key->d,  key->N,  key->dQ,  key->dP,  key->qP,  key->p,  key->q, key->pq, NULL);
+error:
+done:
+   mp_clear_multi( tmp2,  tmp1,  p,  q, NULL);
+   return err;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/pk/pkcs1/pkcs_1_i2osp.c b/libtomcrypt/src/pk/pkcs1/pkcs_1_i2osp.c
new file mode 100644 (file)
index 0000000..5324c1e
--- /dev/null
@@ -0,0 +1,49 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file pkcs_1_i2osp.c
+  Integer to Octet I2OSP, Tom St Denis
+*/
+
+#ifdef LTC_PKCS_1
+
+/* always stores the same # of bytes, pads with leading zero bytes
+   as required
+ */
+
+/**
+   PKCS #1 Integer to binary
+   @param n             The integer to store
+   @param modulus_len   The length of the RSA modulus
+   @param out           [out] The destination for the integer
+   @return CRYPT_OK if successful
+*/
+int pkcs_1_i2osp(void *n, unsigned long modulus_len, unsigned char *out)
+{
+   unsigned long size;
+
+   size = mp_unsigned_bin_size(n);
+
+   if (size > modulus_len) {
+      return CRYPT_BUFFER_OVERFLOW;
+   }
+
+   /* store it */
+   zeromem(out, modulus_len);
+   return mp_to_unsigned_bin(n, out+(modulus_len-size));
+}
+
+#endif /* LTC_PKCS_1 */
+
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/pk/pkcs1/pkcs_1_mgf1.c b/libtomcrypt/src/pk/pkcs1/pkcs_1_mgf1.c
new file mode 100644 (file)
index 0000000..c6283ca
--- /dev/null
@@ -0,0 +1,106 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file pkcs_1_mgf1.c
+  The Mask Generation Function (MGF1) for PKCS #1, Tom St Denis
+*/
+
+#ifdef LTC_PKCS_1
+
+/**
+   Perform PKCS #1 MGF1 (internal)
+   @param hash_idx    The index of the hash desired
+   @param seed        The seed for MGF1
+   @param seedlen     The length of the seed
+   @param mask        [out] The destination
+   @param masklen     The length of the mask desired
+   @return CRYPT_OK if successful
+*/
+int pkcs_1_mgf1(int                  hash_idx,
+                const unsigned char *seed, unsigned long seedlen,
+                      unsigned char *mask, unsigned long masklen)
+{
+   unsigned long hLen, x;
+   ulong32       counter;
+   int           err;
+   hash_state    *md;
+   unsigned char *buf;
+
+   LTC_ARGCHK(seed != NULL);
+   LTC_ARGCHK(mask != NULL);
+
+   /* ensure valid hash */
+   if ((err = hash_is_valid(hash_idx)) != CRYPT_OK) {
+      return err;
+   }
+
+   /* get hash output size */
+   hLen = hash_descriptor[hash_idx].hashsize;
+
+   /* allocate memory */
+   md  = XMALLOC(sizeof(hash_state));
+   buf = XMALLOC(hLen);
+   if (md == NULL || buf == NULL) {
+      if (md != NULL) {
+         XFREE(md);
+      }
+      if (buf != NULL) {
+         XFREE(buf);
+      }
+      return CRYPT_MEM;
+   }
+
+   /* start counter */
+   counter = 0;
+
+   while (masklen > 0) {
+       /* handle counter */
+       STORE32H(counter, buf);
+       ++counter;
+
+       /* get hash of seed || counter */
+       if ((err = hash_descriptor[hash_idx].init(md)) != CRYPT_OK) {
+          goto LBL_ERR;
+       }
+       if ((err = hash_descriptor[hash_idx].process(md, seed, seedlen)) != CRYPT_OK) {
+          goto LBL_ERR;
+       }
+       if ((err = hash_descriptor[hash_idx].process(md, buf, 4)) != CRYPT_OK) {
+          goto LBL_ERR;
+       }
+       if ((err = hash_descriptor[hash_idx].done(md, buf)) != CRYPT_OK) {
+          goto LBL_ERR;
+       }
+
+       /* store it */
+       for (x = 0; x < hLen && masklen > 0; x++, masklen--) {
+          *mask++ = buf[x];
+       }
+   }
+
+   err = CRYPT_OK;
+LBL_ERR:
+#ifdef LTC_CLEAN_STACK
+   zeromem(buf, hLen);
+   zeromem(md,  sizeof(hash_state));
+#endif
+
+   XFREE(buf);
+   XFREE(md);
+
+   return err;
+}
+
+#endif /* LTC_PKCS_1 */
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/pk/pkcs1/pkcs_1_oaep_decode.c b/libtomcrypt/src/pk/pkcs1/pkcs_1_oaep_decode.c
new file mode 100644 (file)
index 0000000..27c9245
--- /dev/null
@@ -0,0 +1,185 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file pkcs_1_oaep_decode.c
+  OAEP Padding for PKCS #1, Tom St Denis
+*/
+
+#ifdef LTC_PKCS_1
+
+/**
+   PKCS #1 v2.00 OAEP decode
+   @param msg              The encoded data to decode
+   @param msglen           The length of the encoded data (octets)
+   @param lparam           The session or system data (can be NULL)
+   @param lparamlen        The length of the lparam
+   @param modulus_bitlen   The bit length of the RSA modulus
+   @param hash_idx         The index of the hash desired
+   @param out              [out] Destination of decoding
+   @param outlen           [in/out] The max size and resulting size of the decoding
+   @param res              [out] Result of decoding, 1==valid, 0==invalid
+   @return CRYPT_OK if successful
+*/
+int pkcs_1_oaep_decode(const unsigned char *msg,    unsigned long msglen,
+                       const unsigned char *lparam, unsigned long lparamlen,
+                             unsigned long modulus_bitlen, int hash_idx,
+                             unsigned char *out,    unsigned long *outlen,
+                             int           *res)
+{
+   unsigned char *DB, *seed, *mask;
+   unsigned long hLen, x, y, modulus_len;
+   int           err, ret;
+
+   LTC_ARGCHK(msg    != NULL);
+   LTC_ARGCHK(out    != NULL);
+   LTC_ARGCHK(outlen != NULL);
+   LTC_ARGCHK(res    != NULL);
+
+   /* default to invalid packet */
+   *res = 0;
+
+   /* test valid hash */
+   if ((err = hash_is_valid(hash_idx)) != CRYPT_OK) {
+      return err;
+   }
+   hLen        = hash_descriptor[hash_idx].hashsize;
+   modulus_len = (modulus_bitlen >> 3) + (modulus_bitlen & 7 ? 1 : 0);
+
+   /* test hash/message size */
+   if ((2*hLen >= (modulus_len - 2)) || (msglen != modulus_len)) {
+      return CRYPT_PK_INVALID_SIZE;
+   }
+
+   /* allocate ram for DB/mask/salt of size modulus_len */
+   DB   = XMALLOC(modulus_len);
+   mask = XMALLOC(modulus_len);
+   seed = XMALLOC(hLen);
+   if (DB == NULL || mask == NULL || seed == NULL) {
+      if (DB != NULL) {
+         XFREE(DB);
+      }
+      if (mask != NULL) {
+         XFREE(mask);
+      }
+      if (seed != NULL) {
+         XFREE(seed);
+      }
+      return CRYPT_MEM;
+   }
+
+   /* ok so it's now in the form
+
+      0x00  || maskedseed || maskedDB
+
+       1    ||   hLen     ||  modulus_len - hLen - 1
+
+    */
+
+   ret = CRYPT_OK;
+
+   /* must have leading 0x00 byte */
+   if (msg[0] != 0x00) {
+      ret = CRYPT_INVALID_PACKET;
+   }
+
+   /* now read the masked seed */
+   x = 1;
+   XMEMCPY(seed, msg + x, hLen);
+   x += hLen;
+
+   /* now read the masked DB */
+   XMEMCPY(DB, msg + x, modulus_len - hLen - 1);
+   x += modulus_len - hLen - 1;
+
+   /* compute MGF1 of maskedDB (hLen) */
+   if ((err = pkcs_1_mgf1(hash_idx, DB, modulus_len - hLen - 1, mask, hLen)) != CRYPT_OK) {
+      goto LBL_ERR;
+   }
+
+   /* XOR against seed */
+   for (y = 0; y < hLen; y++) {
+      seed[y] ^= mask[y];
+   }
+
+   /* compute MGF1 of seed (k - hlen - 1) */
+   if ((err = pkcs_1_mgf1(hash_idx, seed, hLen, mask, modulus_len - hLen - 1)) != CRYPT_OK) {
+      goto LBL_ERR;
+   }
+
+   /* xor against DB */
+   for (y = 0; y < (modulus_len - hLen - 1); y++) {
+       DB[y] ^= mask[y];
+   }
+
+   /* now DB == lhash || PS || 0x01 || M, PS == k - mlen - 2hlen - 2 zeroes */
+
+   /* compute lhash and store it in seed [reuse temps!] */
+   x = modulus_len;
+   if (lparam != NULL) {
+      if ((err = hash_memory(hash_idx, lparam, lparamlen, seed, &x)) != CRYPT_OK) {
+         goto LBL_ERR;
+      }
+   } else {
+      /* can't pass hash_memory a NULL so use DB with zero length */
+      if ((err = hash_memory(hash_idx, DB, 0, seed, &x)) != CRYPT_OK) {
+         goto LBL_ERR;
+      }
+   }
+
+   /* compare the lhash'es */
+   if (XMEM_NEQ(seed, DB, hLen) != 0) {
+      ret = CRYPT_INVALID_PACKET;
+   }
+
+   /* now zeroes before a 0x01 */
+   for (x = hLen; x < (modulus_len - hLen - 1) && DB[x] == 0x00; x++) {
+      /* step... */
+   }
+
+   /* error if wasn't 0x01 */
+   if (x == (modulus_len - hLen - 1) || DB[x] != 0x01) {
+      ret = CRYPT_INVALID_PACKET;
+   }
+
+   /* rest is the message (and skip 0x01) */
+   if ((modulus_len - hLen - 1 - ++x) > *outlen) {
+      ret = CRYPT_INVALID_PACKET;
+   }
+
+   if (ret == CRYPT_OK) {
+      /* copy message */
+      *outlen = modulus_len - hLen - 1 - x;
+      XMEMCPY(out, DB + x, modulus_len - hLen - 1 - x);
+
+      /* valid packet */
+      *res = 1;
+   }
+   err = ret;
+
+LBL_ERR:
+#ifdef LTC_CLEAN_STACK
+   zeromem(DB,   modulus_len);
+   zeromem(seed, hLen);
+   zeromem(mask, modulus_len);
+#endif
+
+   XFREE(seed);
+   XFREE(mask);
+   XFREE(DB);
+
+   return err;
+}
+
+#endif /* LTC_PKCS_1 */
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/pk/pkcs1/pkcs_1_oaep_encode.c b/libtomcrypt/src/pk/pkcs1/pkcs_1_oaep_encode.c
new file mode 100644 (file)
index 0000000..5042946
--- /dev/null
@@ -0,0 +1,171 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file pkcs_1_oaep_encode.c
+  OAEP Padding for PKCS #1, Tom St Denis
+*/
+
+#ifdef LTC_PKCS_1
+
+/**
+  PKCS #1 v2.00 OAEP encode
+  @param msg             The data to encode
+  @param msglen          The length of the data to encode (octets)
+  @param lparam          A session or system parameter (can be NULL)
+  @param lparamlen       The length of the lparam data
+  @param modulus_bitlen  The bit length of the RSA modulus
+  @param prng            An active PRNG state
+  @param prng_idx        The index of the PRNG desired
+  @param hash_idx        The index of the hash desired
+  @param out             [out] The destination for the encoded data
+  @param outlen          [in/out] The max size and resulting size of the encoded data
+  @return CRYPT_OK if successful
+*/
+int pkcs_1_oaep_encode(const unsigned char *msg,    unsigned long msglen,
+                       const unsigned char *lparam, unsigned long lparamlen,
+                             unsigned long modulus_bitlen, prng_state *prng,
+                             int           prng_idx,         int  hash_idx,
+                             unsigned char *out,    unsigned long *outlen)
+{
+   unsigned char *DB, *seed, *mask;
+   unsigned long hLen, x, y, modulus_len;
+   int           err;
+
+   LTC_ARGCHK(msg    != NULL);
+   LTC_ARGCHK(out    != NULL);
+   LTC_ARGCHK(outlen != NULL);
+
+   /* test valid hash */
+   if ((err = hash_is_valid(hash_idx)) != CRYPT_OK) {
+      return err;
+   }
+
+   /* valid prng */
+   if ((err = prng_is_valid(prng_idx)) != CRYPT_OK) {
+      return err;
+   }
+
+   hLen        = hash_descriptor[hash_idx].hashsize;
+   modulus_len = (modulus_bitlen >> 3) + (modulus_bitlen & 7 ? 1 : 0);
+
+   /* test message size */
+   if ((2*hLen >= (modulus_len - 2)) || (msglen > (modulus_len - 2*hLen - 2))) {
+      return CRYPT_PK_INVALID_SIZE;
+   }
+
+   /* allocate ram for DB/mask/salt of size modulus_len */
+   DB   = XMALLOC(modulus_len);
+   mask = XMALLOC(modulus_len);
+   seed = XMALLOC(hLen);
+   if (DB == NULL || mask == NULL || seed == NULL) {
+      if (DB != NULL) {
+         XFREE(DB);
+      }
+      if (mask != NULL) {
+         XFREE(mask);
+      }
+      if (seed != NULL) {
+         XFREE(seed);
+      }
+      return CRYPT_MEM;
+   }
+
+   /* get lhash */
+   /* DB == lhash || PS || 0x01 || M, PS == k - mlen - 2hlen - 2 zeroes */
+   x = modulus_len;
+   if (lparam != NULL) {
+      if ((err = hash_memory(hash_idx, lparam, lparamlen, DB, &x)) != CRYPT_OK) {
+         goto LBL_ERR;
+      }
+   } else {
+      /* can't pass hash_memory a NULL so use DB with zero length */
+      if ((err = hash_memory(hash_idx, DB, 0, DB, &x)) != CRYPT_OK) {
+         goto LBL_ERR;
+      }
+   }
+
+   /* append PS then 0x01 (to lhash)  */
+   x = hLen;
+   y = modulus_len - msglen - 2*hLen - 2;
+   XMEMSET(DB+x, 0, y);
+   x += y;
+
+   /* 0x01 byte */
+   DB[x++] = 0x01;
+
+   /* message (length = msglen) */
+   XMEMCPY(DB+x, msg, msglen);
+   x += msglen;
+
+   /* now choose a random seed */
+   if (prng_descriptor[prng_idx].read(seed, hLen, prng) != hLen) {
+      err = CRYPT_ERROR_READPRNG;
+      goto LBL_ERR;
+   }
+
+   /* compute MGF1 of seed (k - hlen - 1) */
+   if ((err = pkcs_1_mgf1(hash_idx, seed, hLen, mask, modulus_len - hLen - 1)) != CRYPT_OK) {
+      goto LBL_ERR;
+   }
+
+   /* xor against DB */
+   for (y = 0; y < (modulus_len - hLen - 1); y++) {
+       DB[y] ^= mask[y];
+   }
+
+   /* compute MGF1 of maskedDB (hLen) */
+   if ((err = pkcs_1_mgf1(hash_idx, DB, modulus_len - hLen - 1, mask, hLen)) != CRYPT_OK) {
+      goto LBL_ERR;
+   }
+
+   /* XOR against seed */
+   for (y = 0; y < hLen; y++) {
+      seed[y] ^= mask[y];
+   }
+
+   /* create string of length modulus_len */
+   if (*outlen < modulus_len) {
+      *outlen = modulus_len;
+      err = CRYPT_BUFFER_OVERFLOW;
+      goto LBL_ERR;
+   }
+
+   /* start output which is 0x00 || maskedSeed || maskedDB */
+   x = 0;
+   out[x++] = 0x00;
+   XMEMCPY(out+x, seed, hLen);
+   x += hLen;
+   XMEMCPY(out+x, DB, modulus_len - hLen - 1);
+   x += modulus_len - hLen - 1;
+
+   *outlen = x;
+
+   err = CRYPT_OK;
+LBL_ERR:
+#ifdef LTC_CLEAN_STACK
+   zeromem(DB,   modulus_len);
+   zeromem(seed, hLen);
+   zeromem(mask, modulus_len);
+#endif
+
+   XFREE(seed);
+   XFREE(mask);
+   XFREE(DB);
+
+   return err;
+}
+
+#endif /* LTC_PKCS_1 */
+
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/pk/pkcs1/pkcs_1_os2ip.c b/libtomcrypt/src/pk/pkcs1/pkcs_1_os2ip.c
new file mode 100644 (file)
index 0000000..743c70b
--- /dev/null
@@ -0,0 +1,34 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file pkcs_1_os2ip.c
+  Octet to Integer OS2IP, Tom St Denis
+*/
+#ifdef LTC_PKCS_1
+
+/**
+  Read a binary string into an mp_int
+  @param n          [out] The mp_int destination
+  @param in         The binary string to read
+  @param inlen      The length of the binary string
+  @return CRYPT_OK if successful
+*/
+int pkcs_1_os2ip(void *n, unsigned char *in, unsigned long inlen)
+{
+   return mp_read_unsigned_bin(n, in, inlen);
+}
+
+#endif /* LTC_PKCS_1 */
+
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/pk/pkcs1/pkcs_1_pss_decode.c b/libtomcrypt/src/pk/pkcs1/pkcs_1_pss_decode.c
new file mode 100644 (file)
index 0000000..8e112a1
--- /dev/null
@@ -0,0 +1,176 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file pkcs_1_pss_decode.c
+  PKCS #1 PSS Signature Padding, Tom St Denis
+*/
+
+#ifdef LTC_PKCS_1
+
+/**
+   PKCS #1 v2.00 PSS decode
+   @param  msghash         The hash to verify
+   @param  msghashlen      The length of the hash (octets)
+   @param  sig             The signature data (encoded data)
+   @param  siglen          The length of the signature data (octets)
+   @param  saltlen         The length of the salt used (octets)
+   @param  hash_idx        The index of the hash desired
+   @param  modulus_bitlen  The bit length of the RSA modulus
+   @param  res             [out] The result of the comparison, 1==valid, 0==invalid
+   @return CRYPT_OK if successful (even if the comparison failed)
+*/
+int pkcs_1_pss_decode(const unsigned char *msghash, unsigned long msghashlen,
+                      const unsigned char *sig,     unsigned long siglen,
+                            unsigned long saltlen,  int           hash_idx,
+                            unsigned long modulus_bitlen, int    *res)
+{
+   unsigned char *DB, *mask, *salt, *hash;
+   unsigned long x, y, hLen, modulus_len;
+   int           err;
+   hash_state    md;
+
+   LTC_ARGCHK(msghash != NULL);
+   LTC_ARGCHK(res     != NULL);
+
+   /* default to invalid */
+   *res = 0;
+
+   /* ensure hash is valid */
+   if ((err = hash_is_valid(hash_idx)) != CRYPT_OK) {
+      return err;
+   }
+
+   hLen        = hash_descriptor[hash_idx].hashsize;
+   modulus_bitlen--;
+   modulus_len = (modulus_bitlen>>3) + (modulus_bitlen & 7 ? 1 : 0);
+
+   /* check sizes */
+   if ((saltlen > modulus_len) ||
+       (modulus_len < hLen + saltlen + 2)) {
+      return CRYPT_PK_INVALID_SIZE;
+   }
+
+   /* allocate ram for DB/mask/salt/hash of size modulus_len */
+   DB   = XMALLOC(modulus_len);
+   mask = XMALLOC(modulus_len);
+   salt = XMALLOC(modulus_len);
+   hash = XMALLOC(modulus_len);
+   if (DB == NULL || mask == NULL || salt == NULL || hash == NULL) {
+      if (DB != NULL) {
+         XFREE(DB);
+      }
+      if (mask != NULL) {
+         XFREE(mask);
+      }
+      if (salt != NULL) {
+         XFREE(salt);
+      }
+      if (hash != NULL) {
+         XFREE(hash);
+      }
+      return CRYPT_MEM;
+   }
+
+   /* ensure the 0xBC byte */
+   if (sig[siglen-1] != 0xBC) {
+      err = CRYPT_INVALID_PACKET;
+      goto LBL_ERR;
+   }
+
+   /* copy out the DB */
+   x = 0;
+   XMEMCPY(DB, sig + x, modulus_len - hLen - 1);
+   x += modulus_len - hLen - 1;
+
+   /* copy out the hash */
+   XMEMCPY(hash, sig + x, hLen);
+   /* x += hLen; */
+
+   /* check the MSB */
+   if ((sig[0] & ~(0xFF >> ((modulus_len<<3) - (modulus_bitlen)))) != 0) {
+      err = CRYPT_INVALID_PACKET;
+      goto LBL_ERR;
+   }
+
+   /* generate mask of length modulus_len - hLen - 1 from hash */
+   if ((err = pkcs_1_mgf1(hash_idx, hash, hLen, mask, modulus_len - hLen - 1)) != CRYPT_OK) {
+      goto LBL_ERR;
+   }
+
+   /* xor against DB */
+   for (y = 0; y < (modulus_len - hLen - 1); y++) {
+      DB[y] ^= mask[y];
+   }
+
+   /* now clear the first byte [make sure smaller than modulus] */
+   DB[0] &= 0xFF >> ((modulus_len<<3) - (modulus_bitlen));
+
+   /* DB = PS || 0x01 || salt, PS == modulus_len - saltlen - hLen - 2 zero bytes */
+
+   /* check for zeroes and 0x01 */
+   for (x = 0; x < modulus_len - saltlen - hLen - 2; x++) {
+       if (DB[x] != 0x00) {
+          err = CRYPT_INVALID_PACKET;
+          goto LBL_ERR;
+       }
+   }
+
+   /* check for the 0x01 */
+   if (DB[x++] != 0x01) {
+      err = CRYPT_INVALID_PACKET;
+      goto LBL_ERR;
+   }
+
+   /* M = (eight) 0x00 || msghash || salt, mask = H(M) */
+   if ((err = hash_descriptor[hash_idx].init(&md)) != CRYPT_OK) {
+      goto LBL_ERR;
+   }
+   zeromem(mask, 8);
+   if ((err = hash_descriptor[hash_idx].process(&md, mask, 8)) != CRYPT_OK) {
+      goto LBL_ERR;
+   }
+   if ((err = hash_descriptor[hash_idx].process(&md, msghash, msghashlen)) != CRYPT_OK) {
+      goto LBL_ERR;
+   }
+   if ((err = hash_descriptor[hash_idx].process(&md, DB+x, saltlen)) != CRYPT_OK) {
+      goto LBL_ERR;
+   }
+   if ((err = hash_descriptor[hash_idx].done(&md, mask)) != CRYPT_OK) {
+      goto LBL_ERR;
+   }
+
+   /* mask == hash means valid signature */
+   if (XMEM_NEQ(mask, hash, hLen) == 0) {
+      *res = 1;
+   }
+
+   err = CRYPT_OK;
+LBL_ERR:
+#ifdef LTC_CLEAN_STACK
+   zeromem(DB,   modulus_len);
+   zeromem(mask, modulus_len);
+   zeromem(salt, modulus_len);
+   zeromem(hash, modulus_len);
+#endif
+
+   XFREE(hash);
+   XFREE(salt);
+   XFREE(mask);
+   XFREE(DB);
+
+   return err;
+}
+
+#endif /* LTC_PKCS_1 */
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/pk/pkcs1/pkcs_1_pss_encode.c b/libtomcrypt/src/pk/pkcs1/pkcs_1_pss_encode.c
new file mode 100644 (file)
index 0000000..c795114
--- /dev/null
@@ -0,0 +1,174 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file pkcs_1_pss_encode.c
+  PKCS #1 PSS Signature Padding, Tom St Denis
+*/
+
+#ifdef LTC_PKCS_1
+
+/**
+   PKCS #1 v2.00 Signature Encoding
+   @param msghash          The hash to encode
+   @param msghashlen       The length of the hash (octets)
+   @param saltlen          The length of the salt desired (octets)
+   @param prng             An active PRNG context
+   @param prng_idx         The index of the PRNG desired
+   @param hash_idx         The index of the hash desired
+   @param modulus_bitlen   The bit length of the RSA modulus
+   @param out              [out] The destination of the encoding
+   @param outlen           [in/out] The max size and resulting size of the encoded data
+   @return CRYPT_OK if successful
+*/
+int pkcs_1_pss_encode(const unsigned char *msghash, unsigned long msghashlen,
+                            unsigned long saltlen,  prng_state   *prng,
+                            int           prng_idx, int           hash_idx,
+                            unsigned long modulus_bitlen,
+                            unsigned char *out,     unsigned long *outlen)
+{
+   unsigned char *DB, *mask, *salt, *hash;
+   unsigned long x, y, hLen, modulus_len;
+   int           err;
+   hash_state    md;
+
+   LTC_ARGCHK(msghash != NULL);
+   LTC_ARGCHK(out     != NULL);
+   LTC_ARGCHK(outlen  != NULL);
+
+   /* ensure hash and PRNG are valid */
+   if ((err = hash_is_valid(hash_idx)) != CRYPT_OK) {
+      return err;
+   }
+   if ((err = prng_is_valid(prng_idx)) != CRYPT_OK) {
+      return err;
+   }
+
+   hLen        = hash_descriptor[hash_idx].hashsize;
+   modulus_bitlen--;
+   modulus_len = (modulus_bitlen>>3) + (modulus_bitlen & 7 ? 1 : 0);
+
+   /* check sizes */
+   if ((saltlen > modulus_len) || (modulus_len < hLen + saltlen + 2)) {
+      return CRYPT_PK_INVALID_SIZE;
+   }
+
+   /* allocate ram for DB/mask/salt/hash of size modulus_len */
+   DB   = XMALLOC(modulus_len);
+   mask = XMALLOC(modulus_len);
+   salt = XMALLOC(modulus_len);
+   hash = XMALLOC(modulus_len);
+   if (DB == NULL || mask == NULL || salt == NULL || hash == NULL) {
+      if (DB != NULL) {
+         XFREE(DB);
+      }
+      if (mask != NULL) {
+         XFREE(mask);
+      }
+      if (salt != NULL) {
+         XFREE(salt);
+      }
+      if (hash != NULL) {
+         XFREE(hash);
+      }
+      return CRYPT_MEM;
+   }
+
+
+   /* generate random salt */
+   if (saltlen > 0) {
+      if (prng_descriptor[prng_idx].read(salt, saltlen, prng) != saltlen) {
+         err = CRYPT_ERROR_READPRNG;
+         goto LBL_ERR;
+      }
+   }
+
+   /* M = (eight) 0x00 || msghash || salt, hash = H(M) */
+   if ((err = hash_descriptor[hash_idx].init(&md)) != CRYPT_OK) {
+      goto LBL_ERR;
+   }
+   zeromem(DB, 8);
+   if ((err = hash_descriptor[hash_idx].process(&md, DB, 8)) != CRYPT_OK) {
+      goto LBL_ERR;
+   }
+   if ((err = hash_descriptor[hash_idx].process(&md, msghash, msghashlen)) != CRYPT_OK) {
+      goto LBL_ERR;
+   }
+   if ((err = hash_descriptor[hash_idx].process(&md, salt, saltlen)) != CRYPT_OK) {
+      goto LBL_ERR;
+   }
+   if ((err = hash_descriptor[hash_idx].done(&md, hash)) != CRYPT_OK) {
+      goto LBL_ERR;
+   }
+
+   /* generate DB = PS || 0x01 || salt, PS == modulus_len - saltlen - hLen - 2 zero bytes */
+   x = 0;
+   XMEMSET(DB + x, 0, modulus_len - saltlen - hLen - 2);
+   x += modulus_len - saltlen - hLen - 2;
+   DB[x++] = 0x01;
+   XMEMCPY(DB + x, salt, saltlen);
+   /* x += saltlen; */
+
+   /* generate mask of length modulus_len - hLen - 1 from hash */
+   if ((err = pkcs_1_mgf1(hash_idx, hash, hLen, mask, modulus_len - hLen - 1)) != CRYPT_OK) {
+      goto LBL_ERR;
+   }
+
+   /* xor against DB */
+   for (y = 0; y < (modulus_len - hLen - 1); y++) {
+      DB[y] ^= mask[y];
+   }
+
+   /* output is DB || hash || 0xBC */
+   if (*outlen < modulus_len) {
+      *outlen = modulus_len;
+      err = CRYPT_BUFFER_OVERFLOW;
+      goto LBL_ERR;
+   }
+
+   /* DB len = modulus_len - hLen - 1 */
+   y = 0;
+   XMEMCPY(out + y, DB, modulus_len - hLen - 1);
+   y += modulus_len - hLen - 1;
+
+   /* hash */
+   XMEMCPY(out + y, hash, hLen);
+   y += hLen;
+
+   /* 0xBC */
+   out[y] = 0xBC;
+
+   /* now clear the 8*modulus_len - modulus_bitlen most significant bits */
+   out[0] &= 0xFF >> ((modulus_len<<3) - modulus_bitlen);
+
+   /* store output size */
+   *outlen = modulus_len;
+   err = CRYPT_OK;
+LBL_ERR:
+#ifdef LTC_CLEAN_STACK
+   zeromem(DB,   modulus_len);
+   zeromem(mask, modulus_len);
+   zeromem(salt, modulus_len);
+   zeromem(hash, modulus_len);
+#endif
+
+   XFREE(hash);
+   XFREE(salt);
+   XFREE(mask);
+   XFREE(DB);
+
+   return err;
+}
+
+#endif /* LTC_PKCS_1 */
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/pk/pkcs1/pkcs_1_v1_5_decode.c b/libtomcrypt/src/pk/pkcs1/pkcs_1_v1_5_decode.c
new file mode 100644 (file)
index 0000000..94e1b2a
--- /dev/null
@@ -0,0 +1,112 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/** @file pkcs_1_v1_5_decode.c
+ *
+ *  PKCS #1 v1.5 Padding. (Andreas Lange)
+ */
+
+#ifdef LTC_PKCS_1
+
+/** @brief PKCS #1 v1.5 decode.
+ *
+ *  @param msg              The encoded data to decode
+ *  @param msglen           The length of the encoded data (octets)
+ *  @param block_type       Block type to use in padding (\sa ltc_pkcs_1_v1_5_blocks)
+ *  @param modulus_bitlen   The bit length of the RSA modulus
+ *  @param out              [out] Destination of decoding
+ *  @param outlen           [in/out] The max size and resulting size of the decoding
+ *  @param is_valid         [out] Boolean whether the padding was valid
+ *
+ *  @return CRYPT_OK if successful
+ */
+int pkcs_1_v1_5_decode(const unsigned char *msg,
+                             unsigned long  msglen,
+                                       int  block_type,
+                             unsigned long  modulus_bitlen,
+                             unsigned char *out,
+                             unsigned long *outlen,
+                                       int *is_valid)
+{
+  unsigned long modulus_len, ps_len, i;
+  int result;
+
+  /* default to invalid packet */
+  *is_valid = 0;
+
+  modulus_len = (modulus_bitlen >> 3) + (modulus_bitlen & 7 ? 1 : 0);
+
+  /* test message size */
+
+  if ((msglen > modulus_len) || (modulus_len < 11)) {
+    return CRYPT_PK_INVALID_SIZE;
+  }
+
+  result = CRYPT_OK;
+
+  /* separate encoded message */
+
+  if ((msg[0] != 0x00) || (msg[1] != (unsigned char)block_type)) {
+    result = CRYPT_INVALID_PACKET;
+  }
+
+  if (block_type == LTC_PKCS_1_EME) {
+    for (i = 2; i < modulus_len; i++) {
+      /* separator */
+      if (msg[i] == 0x00) { break; }
+    }
+    ps_len = i++ - 2;
+
+    if (i >= modulus_len) {
+      /* There was no octet with hexadecimal value 0x00 to separate ps from m.
+       */
+      result = CRYPT_INVALID_PACKET;
+    }
+  } else {
+    for (i = 2; i < modulus_len - 1; i++) {
+       if (msg[i] != 0xFF) { break; }
+    }
+
+    /* separator check */
+    if (msg[i] != 0) {
+      /* There was no octet with hexadecimal value 0x00 to separate ps from m. */
+      result = CRYPT_INVALID_PACKET;
+    }
+
+    ps_len = i - 2;
+  }
+
+  if (ps_len < 8)
+  {
+    /* The length of ps is less than 8 octets.
+     */
+    result = CRYPT_INVALID_PACKET;
+  }
+
+  if (*outlen < (msglen - (2 + ps_len + 1))) {
+    result = CRYPT_INVALID_PACKET;
+  }
+
+  if (result == CRYPT_OK) {
+     *outlen = (msglen - (2 + ps_len + 1));
+     XMEMCPY(out, &msg[2 + ps_len + 1], *outlen);
+
+     /* valid packet */
+     *is_valid = 1;
+  }
+
+  return result;
+} /* pkcs_1_v1_5_decode */
+
+#endif /* #ifdef LTC_PKCS_1 */
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/pk/pkcs1/pkcs_1_v1_5_encode.c b/libtomcrypt/src/pk/pkcs1/pkcs_1_v1_5_encode.c
new file mode 100644 (file)
index 0000000..dd92c64
--- /dev/null
@@ -0,0 +1,109 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/*! \file pkcs_1_v1_5_encode.c
+ *
+ *  PKCS #1 v1.5 Padding (Andreas Lange)
+ */
+
+#ifdef LTC_PKCS_1
+
+/*! \brief PKCS #1 v1.5 encode.
+ *
+ *  \param msg              The data to encode
+ *  \param msglen           The length of the data to encode (octets)
+ *  \param block_type       Block type to use in padding (\sa ltc_pkcs_1_v1_5_blocks)
+ *  \param modulus_bitlen   The bit length of the RSA modulus
+ *  \param prng             An active PRNG state (only for LTC_PKCS_1_EME)
+ *  \param prng_idx         The index of the PRNG desired (only for LTC_PKCS_1_EME)
+ *  \param out              [out] The destination for the encoded data
+ *  \param outlen           [in/out] The max size and resulting size of the encoded data
+ *
+ *  \return CRYPT_OK if successful
+ */
+int pkcs_1_v1_5_encode(const unsigned char *msg,
+                             unsigned long  msglen,
+                                       int  block_type,
+                             unsigned long  modulus_bitlen,
+                                prng_state *prng,
+                                       int  prng_idx,
+                             unsigned char *out,
+                             unsigned long *outlen)
+{
+  unsigned long modulus_len, ps_len, i;
+  unsigned char *ps;
+  int result;
+
+  /* valid block_type? */
+  if ((block_type != LTC_PKCS_1_EMSA) &&
+      (block_type != LTC_PKCS_1_EME)) {
+     return CRYPT_PK_INVALID_PADDING;
+  }
+
+  if (block_type == LTC_PKCS_1_EME) {    /* encryption padding, we need a valid PRNG */
+    if ((result = prng_is_valid(prng_idx)) != CRYPT_OK) {
+       return result;
+    }
+  }
+
+  modulus_len = (modulus_bitlen >> 3) + (modulus_bitlen & 7 ? 1 : 0);
+
+  /* test message size */
+  if ((msglen + 11) > modulus_len) {
+    return CRYPT_PK_INVALID_SIZE;
+  }
+
+  if (*outlen < modulus_len) {
+    *outlen = modulus_len;
+    result = CRYPT_BUFFER_OVERFLOW;
+    goto bail;
+  }
+
+  /* generate an octets string PS */
+  ps = &out[2];
+  ps_len = modulus_len - msglen - 3;
+
+  if (block_type == LTC_PKCS_1_EME) {
+    /* now choose a random ps */
+    if (prng_descriptor[prng_idx].read(ps, ps_len, prng) != ps_len) {
+      result = CRYPT_ERROR_READPRNG;
+      goto bail;
+    }
+
+    /* transform zero bytes (if any) to non-zero random bytes */
+    for (i = 0; i < ps_len; i++) {
+      while (ps[i] == 0) {
+        if (prng_descriptor[prng_idx].read(&ps[i], 1, prng) != 1) {
+          result = CRYPT_ERROR_READPRNG;
+          goto bail;
+        }
+      }
+    }
+  } else {
+    XMEMSET(ps, 0xFF, ps_len);
+  }
+
+  /* create string of length modulus_len */
+  out[0]          = 0x00;
+  out[1]          = (unsigned char)block_type;  /* block_type 1 or 2 */
+  out[2 + ps_len] = 0x00;
+  XMEMCPY(&out[2 + ps_len + 1], msg, msglen);
+  *outlen = modulus_len;
+
+  result  = CRYPT_OK;
+bail:
+  return result;
+} /* pkcs_1_v1_5_encode */
+
+#endif /* #ifdef LTC_PKCS_1 */
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/pk/rsa/rsa_decrypt_key.c b/libtomcrypt/src/pk/rsa/rsa_decrypt_key.c
new file mode 100644 (file)
index 0000000..9e1bced
--- /dev/null
@@ -0,0 +1,103 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file rsa_decrypt_key.c
+  RSA PKCS #1 Decryption, Tom St Denis and Andreas Lange
+*/
+
+#ifdef LTC_MRSA
+
+/**
+   PKCS #1 decrypt then v1.5 or OAEP depad
+   @param in          The ciphertext
+   @param inlen       The length of the ciphertext (octets)
+   @param out         [out] The plaintext
+   @param outlen      [in/out] The max size and resulting size of the plaintext (octets)
+   @param lparam      The system "lparam" value
+   @param lparamlen   The length of the lparam value (octets)
+   @param hash_idx    The index of the hash desired
+   @param padding     Type of padding (LTC_PKCS_1_OAEP or LTC_PKCS_1_V1_5)
+   @param stat        [out] Result of the decryption, 1==valid, 0==invalid
+   @param key         The corresponding private RSA key
+   @return CRYPT_OK if succcessul (even if invalid)
+*/
+int rsa_decrypt_key_ex(const unsigned char *in,       unsigned long  inlen,
+                             unsigned char *out,      unsigned long *outlen,
+                       const unsigned char *lparam,   unsigned long  lparamlen,
+                             int            hash_idx, int            padding,
+                             int           *stat,     rsa_key       *key)
+{
+  unsigned long modulus_bitlen, modulus_bytelen, x;
+  int           err;
+  unsigned char *tmp;
+
+  LTC_ARGCHK(out    != NULL);
+  LTC_ARGCHK(outlen != NULL);
+  LTC_ARGCHK(key    != NULL);
+  LTC_ARGCHK(stat   != NULL);
+
+  /* default to invalid */
+  *stat = 0;
+
+  /* valid padding? */
+
+  if ((padding != LTC_PKCS_1_V1_5) &&
+      (padding != LTC_PKCS_1_OAEP)) {
+    return CRYPT_PK_INVALID_PADDING;
+  }
+
+  if (padding == LTC_PKCS_1_OAEP) {
+    /* valid hash ? */
+    if ((err = hash_is_valid(hash_idx)) != CRYPT_OK) {
+       return err;
+    }
+  }
+
+  /* get modulus len in bits */
+  modulus_bitlen = mp_count_bits( (key->N));
+
+  /* outlen must be at least the size of the modulus */
+  modulus_bytelen = mp_unsigned_bin_size( (key->N));
+  if (modulus_bytelen != inlen) {
+     return CRYPT_INVALID_PACKET;
+  }
+
+  /* allocate ram */
+  tmp = XMALLOC(inlen);
+  if (tmp == NULL) {
+     return CRYPT_MEM;
+  }
+
+  /* rsa decode the packet */
+  x = inlen;
+  if ((err = ltc_mp.rsa_me(in, inlen, tmp, &x, PK_PRIVATE, key)) != CRYPT_OK) {
+     XFREE(tmp);
+     return err;
+  }
+
+  if (padding == LTC_PKCS_1_OAEP) {
+    /* now OAEP decode the packet */
+    err = pkcs_1_oaep_decode(tmp, x, lparam, lparamlen, modulus_bitlen, hash_idx,
+                             out, outlen, stat);
+  } else {
+    /* now PKCS #1 v1.5 depad the packet */
+    err = pkcs_1_v1_5_decode(tmp, x, LTC_PKCS_1_EME, modulus_bitlen, out, outlen, stat);
+  }
+
+  XFREE(tmp);
+  return err;
+}
+
+#endif /* LTC_MRSA */
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/pk/rsa/rsa_encrypt_key.c b/libtomcrypt/src/pk/rsa/rsa_encrypt_key.c
new file mode 100644 (file)
index 0000000..ef066d2
--- /dev/null
@@ -0,0 +1,100 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file rsa_encrypt_key.c
+  RSA PKCS #1 encryption, Tom St Denis and Andreas Lange
+*/
+
+#ifdef LTC_MRSA
+
+/**
+    (PKCS #1 v2.0) OAEP pad then encrypt
+    @param in          The plaintext
+    @param inlen       The length of the plaintext (octets)
+    @param out         [out] The ciphertext
+    @param outlen      [in/out] The max size and resulting size of the ciphertext
+    @param lparam      The system "lparam" for the encryption
+    @param lparamlen   The length of lparam (octets)
+    @param prng        An active PRNG
+    @param prng_idx    The index of the desired prng
+    @param hash_idx    The index of the desired hash
+    @param padding     Type of padding (LTC_PKCS_1_OAEP or LTC_PKCS_1_V1_5)
+    @param key         The RSA key to encrypt to
+    @return CRYPT_OK if successful
+*/
+int rsa_encrypt_key_ex(const unsigned char *in,     unsigned long inlen,
+                             unsigned char *out,    unsigned long *outlen,
+                       const unsigned char *lparam, unsigned long lparamlen,
+                       prng_state *prng, int prng_idx, int hash_idx, int padding, rsa_key *key)
+{
+  unsigned long modulus_bitlen, modulus_bytelen, x;
+  int           err;
+
+  LTC_ARGCHK(in     != NULL);
+  LTC_ARGCHK(out    != NULL);
+  LTC_ARGCHK(outlen != NULL);
+  LTC_ARGCHK(key    != NULL);
+
+  /* valid padding? */
+  if ((padding != LTC_PKCS_1_V1_5) &&
+      (padding != LTC_PKCS_1_OAEP)) {
+    return CRYPT_PK_INVALID_PADDING;
+  }
+
+  /* valid prng? */
+  if ((err = prng_is_valid(prng_idx)) != CRYPT_OK) {
+     return err;
+  }
+
+  if (padding == LTC_PKCS_1_OAEP) {
+    /* valid hash? */
+    if ((err = hash_is_valid(hash_idx)) != CRYPT_OK) {
+       return err;
+    }
+  }
+
+  /* get modulus len in bits */
+  modulus_bitlen = mp_count_bits( (key->N));
+
+  /* outlen must be at least the size of the modulus */
+  modulus_bytelen = mp_unsigned_bin_size( (key->N));
+  if (modulus_bytelen > *outlen) {
+     *outlen = modulus_bytelen;
+     return CRYPT_BUFFER_OVERFLOW;
+  }
+
+  if (padding == LTC_PKCS_1_OAEP) {
+    /* OAEP pad the key */
+    x = *outlen;
+    if ((err = pkcs_1_oaep_encode(in, inlen, lparam,
+                                  lparamlen, modulus_bitlen, prng, prng_idx, hash_idx,
+                                  out, &x)) != CRYPT_OK) {
+       return err;
+    }
+  } else {
+    /* PKCS #1 v1.5 pad the key */
+    x = *outlen;
+    if ((err = pkcs_1_v1_5_encode(in, inlen, LTC_PKCS_1_EME,
+                                  modulus_bitlen, prng, prng_idx,
+                                  out, &x)) != CRYPT_OK) {
+      return err;
+    }
+  }
+
+  /* rsa exptmod the OAEP or PKCS #1 v1.5 pad */
+  return ltc_mp.rsa_me(out, x, out, outlen, PK_PUBLIC, key);
+}
+
+#endif /* LTC_MRSA */
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/pk/rsa/rsa_export.c b/libtomcrypt/src/pk/rsa/rsa_export.c
new file mode 100644 (file)
index 0000000..efd61d6
--- /dev/null
@@ -0,0 +1,97 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file rsa_export.c
+  Export RSA PKCS keys, Tom St Denis
+*/
+
+#ifdef LTC_MRSA
+
+/**
+    This will export either an RSAPublicKey or RSAPrivateKey [defined in PKCS #1 v2.1]
+    @param out       [out] Destination of the packet
+    @param outlen    [in/out] The max size and resulting size of the packet
+    @param type      The type of exported key (PK_PRIVATE or PK_PUBLIC)
+    @param key       The RSA key to export
+    @return CRYPT_OK if successful
+*/
+int rsa_export(unsigned char *out, unsigned long *outlen, int type, rsa_key *key)
+{
+   unsigned long zero=0;
+   int err;
+   LTC_ARGCHK(out    != NULL);
+   LTC_ARGCHK(outlen != NULL);
+   LTC_ARGCHK(key    != NULL);
+
+   /* type valid? */
+   if (!(key->type == PK_PRIVATE) && (type == PK_PRIVATE)) {
+      return CRYPT_PK_INVALID_TYPE;
+   }
+
+   if (type == PK_PRIVATE) {
+      /* private key */
+      /* output is
+            Version, n, e, d, p, q, d mod (p-1), d mod (q - 1), 1/q mod p
+       */
+      return der_encode_sequence_multi(out, outlen,
+                          LTC_ASN1_SHORT_INTEGER, 1UL, &zero,
+                          LTC_ASN1_INTEGER, 1UL,  key->N,
+                          LTC_ASN1_INTEGER, 1UL,  key->e,
+                          LTC_ASN1_INTEGER, 1UL,  key->d,
+                          LTC_ASN1_INTEGER, 1UL,  key->p,
+                          LTC_ASN1_INTEGER, 1UL,  key->q,
+                          LTC_ASN1_INTEGER, 1UL,  key->dP,
+                          LTC_ASN1_INTEGER, 1UL,  key->dQ,
+                          LTC_ASN1_INTEGER, 1UL,  key->qP,
+                          LTC_ASN1_EOL,     0UL, NULL);
+   } else {
+      /* public key */
+      unsigned long tmplen, *ptmplen;
+      unsigned char* tmp = NULL;
+
+      if (type & PK_STD) {
+          tmplen = (unsigned long)(mp_count_bits(key->N) / 8) * 2 + 8;
+          tmp = XMALLOC(tmplen);
+          ptmplen = &tmplen;
+          if (tmp == NULL) {
+              return CRYPT_MEM;
+          }
+      }
+      else {
+          tmp = out;
+          ptmplen = outlen;
+      }
+
+      err = der_encode_sequence_multi(tmp, ptmplen,
+                                 LTC_ASN1_INTEGER, 1UL,  key->N,
+                                 LTC_ASN1_INTEGER, 1UL,  key->e,
+                                 LTC_ASN1_EOL,     0UL, NULL);
+
+      if ((err != CRYPT_OK) || !(type & PK_STD)) {
+          goto finish;
+      }
+
+      err = der_encode_subject_public_key_info(out, outlen,
+        PKA_RSA, tmp, tmplen, LTC_ASN1_NULL, NULL, 0);
+
+finish:
+      if (tmp != out)
+        XFREE(tmp);
+      return err;
+
+   }
+}
+
+#endif /* LTC_MRSA */
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/pk/rsa/rsa_exptmod.c b/libtomcrypt/src/pk/rsa/rsa_exptmod.c
new file mode 100644 (file)
index 0000000..37f62d1
--- /dev/null
@@ -0,0 +1,182 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file rsa_exptmod.c
+  RSA PKCS exptmod, Tom St Denis
+  Added RSA blinding --nmav
+*/
+
+#ifdef LTC_MRSA
+
+/**
+   Compute an RSA modular exponentiation
+   @param in         The input data to send into RSA
+   @param inlen      The length of the input (octets)
+   @param out        [out] The destination
+   @param outlen     [in/out] The max size and resulting size of the output
+   @param which      Which exponent to use, e.g. PK_PRIVATE or PK_PUBLIC
+   @param key        The RSA key to use
+   @return CRYPT_OK if successful
+*/
+int rsa_exptmod(const unsigned char *in,   unsigned long inlen,
+                      unsigned char *out,  unsigned long *outlen, int which,
+                      rsa_key *key)
+{
+   void        *tmp, *tmpa, *tmpb;
+   #ifdef LTC_RSA_BLINDING
+   void        *rnd, *rndi /* inverse of rnd */;
+   #endif
+   unsigned long x;
+   int           err, has_crt_parameters;
+
+   LTC_ARGCHK(in     != NULL);
+   LTC_ARGCHK(out    != NULL);
+   LTC_ARGCHK(outlen != NULL);
+   LTC_ARGCHK(key    != NULL);
+
+   /* is the key of the right type for the operation? */
+   if (which == PK_PRIVATE && (key->type != PK_PRIVATE)) {
+      return CRYPT_PK_NOT_PRIVATE;
+   }
+
+   /* must be a private or public operation */
+   if (which != PK_PRIVATE && which != PK_PUBLIC) {
+      return CRYPT_PK_INVALID_TYPE;
+   }
+
+   /* init and copy into tmp */
+   if ((err = mp_init_multi(&tmp, &tmpa, &tmpb,
+#ifdef LTC_RSA_BLINDING
+                                               &rnd, &rndi,
+#endif /* LTC_RSA_BLINDING */
+                                                           NULL)) != CRYPT_OK)
+        { return err; }
+   if ((err = mp_read_unsigned_bin(tmp, (unsigned char *)in, (int)inlen)) != CRYPT_OK)
+        { goto error; }
+
+
+   /* sanity check on the input */
+   if (mp_cmp(key->N, tmp) == LTC_MP_LT) {
+      err = CRYPT_PK_INVALID_SIZE;
+      goto error;
+   }
+
+   /* are we using the private exponent and is the key optimized? */
+   if (which == PK_PRIVATE) {
+      #ifdef LTC_RSA_BLINDING
+      /* do blinding */
+      err = mp_rand(rnd, mp_get_digit_count(key->N));
+      if (err != CRYPT_OK) {
+             goto error;
+      }
+
+      /* rndi = 1/rnd mod N */
+      err = mp_invmod(rnd, key->N, rndi);
+      if (err != CRYPT_OK) {
+             goto error;
+      }
+
+      /* rnd = rnd^e */
+      err = mp_exptmod( rnd, key->e, key->N, rnd);
+      if (err != CRYPT_OK) {
+             goto error;
+      }
+
+      /* tmp = tmp*rnd mod N */
+      err = mp_mulmod( tmp, rnd, key->N, tmp);
+      if (err != CRYPT_OK) {
+             goto error;
+      }
+      #endif /* LTC_RSA_BLINDING */
+
+      has_crt_parameters = (key->p != NULL) && (mp_get_digit_count(key->p) != 0) &&
+                              (key->q != NULL) && (mp_get_digit_count(key->q) != 0) &&
+                                 (key->dP != NULL) && (mp_get_digit_count(key->dP) != 0) &&
+                                    (key->dQ != NULL) && (mp_get_digit_count(key->dQ) != 0) &&
+                                       (key->qP != NULL) && (mp_get_digit_count(key->qP) != 0);
+
+      if (!has_crt_parameters) {
+         /*
+          * In case CRT optimization parameters are not provided,
+          * the private key is directly used to exptmod it
+          */
+         if ((err = mp_exptmod(tmp, key->d, key->N, tmp)) != CRYPT_OK)                              { goto error; }
+      } else {
+         /* tmpa = tmp^dP mod p */
+         if ((err = mp_exptmod(tmp, key->dP, key->p, tmpa)) != CRYPT_OK)                            { goto error; }
+
+         /* tmpb = tmp^dQ mod q */
+         if ((err = mp_exptmod(tmp, key->dQ, key->q, tmpb)) != CRYPT_OK)                            { goto error; }
+
+         /* tmp = (tmpa - tmpb) * qInv (mod p) */
+         if ((err = mp_sub(tmpa, tmpb, tmp)) != CRYPT_OK)                                           { goto error; }
+         if ((err = mp_mulmod(tmp, key->qP, key->p, tmp)) != CRYPT_OK)                              { goto error; }
+
+         /* tmp = tmpb + q * tmp */
+         if ((err = mp_mul(tmp, key->q, tmp)) != CRYPT_OK)                                          { goto error; }
+         if ((err = mp_add(tmp, tmpb, tmp)) != CRYPT_OK)                                            { goto error; }
+      }
+
+      #ifdef LTC_RSA_BLINDING
+      /* unblind */
+      err = mp_mulmod( tmp, rndi, key->N, tmp);
+      if (err != CRYPT_OK) {
+             goto error;
+      }
+      #endif
+
+      #ifdef LTC_RSA_CRT_HARDENING
+      if (has_crt_parameters) {
+         if ((err = mp_exptmod(tmp, key->e, key->N, tmpa)) != CRYPT_OK)                              { goto error; }
+         if ((err = mp_read_unsigned_bin(tmpb, (unsigned char *)in, (int)inlen)) != CRYPT_OK)        { goto error; }
+         if (mp_cmp(tmpa, tmpb) != LTC_MP_EQ)                                     { err = CRYPT_ERROR; goto error; }
+      }
+      #endif
+   } else {
+      /* exptmod it */
+      if ((err = mp_exptmod(tmp, key->e, key->N, tmp)) != CRYPT_OK)                                { goto error; }
+   }
+
+   /* read it back */
+   x = (unsigned long)mp_unsigned_bin_size(key->N);
+   if (x > *outlen) {
+      *outlen = x;
+      err = CRYPT_BUFFER_OVERFLOW;
+      goto error;
+   }
+
+   /* this should never happen ... */
+   if (mp_unsigned_bin_size(tmp) > mp_unsigned_bin_size(key->N)) {
+      err = CRYPT_ERROR;
+      goto error;
+   }
+   *outlen = x;
+
+   /* convert it */
+   zeromem(out, x);
+   if ((err = mp_to_unsigned_bin(tmp, out+(x-mp_unsigned_bin_size(tmp)))) != CRYPT_OK)               { goto error; }
+
+   /* clean up and return */
+   err = CRYPT_OK;
+error:
+   mp_clear_multi(
+#ifdef LTC_RSA_BLINDING
+                  rndi, rnd,
+#endif /* LTC_RSA_BLINDING */
+                             tmpb, tmpa, tmp, NULL);
+   return err;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/pk/rsa/rsa_free.c b/libtomcrypt/src/pk/rsa/rsa_free.c
new file mode 100644 (file)
index 0000000..1e62f09
--- /dev/null
@@ -0,0 +1,32 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file rsa_free.c
+  Free an RSA key, Tom St Denis
+*/
+
+#ifdef LTC_MRSA
+
+/**
+  Free an RSA key from memory
+  @param key   The RSA key to free
+*/
+void rsa_free(rsa_key *key)
+{
+   LTC_ARGCHKVD(key != NULL);
+   mp_cleanup_multi(&key->q, &key->p, &key->qP, &key->dP, &key->dQ, &key->N, &key->d, &key->e, NULL);
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/pk/rsa/rsa_get_size.c b/libtomcrypt/src/pk/rsa/rsa_get_size.c
new file mode 100644 (file)
index 0000000..8c90194
--- /dev/null
@@ -0,0 +1,40 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file rsa_get_size.c
+  Retrieve the size of an RSA key, Steffen Jaeckel.
+*/
+
+#ifdef LTC_MRSA
+
+/**
+  Retrieve the size in bytes of an RSA key.
+  @param key      The RSA key
+  @return The size in bytes of the RSA key or INT_MAX on error.
+*/
+int rsa_get_size(rsa_key *key)
+{
+  int ret = INT_MAX;
+  LTC_ARGCHK(key != NULL);
+
+  if (key)
+  {
+    ret = mp_unsigned_bin_size(key->N);
+  } /* if */
+
+  return ret;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/pk/rsa/rsa_import.c b/libtomcrypt/src/pk/rsa/rsa_import.c
new file mode 100644 (file)
index 0000000..84cd6f6
--- /dev/null
@@ -0,0 +1,129 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file rsa_import.c
+  Import a PKCS RSA key, Tom St Denis
+*/
+
+#ifdef LTC_MRSA
+
+/**
+  Import an RSAPublicKey or RSAPrivateKey [two-prime only, only support >= 1024-bit keys, defined in PKCS #1 v2.1]
+  @param in      The packet to import from
+  @param inlen   It's length (octets)
+  @param key     [out] Destination for newly imported key
+  @return CRYPT_OK if successful, upon error allocated memory is freed
+*/
+int rsa_import(const unsigned char *in, unsigned long inlen, rsa_key *key)
+{
+   int           err;
+   void         *zero;
+   unsigned char *tmpbuf=NULL;
+   unsigned long tmpbuf_len;
+
+   LTC_ARGCHK(in          != NULL);
+   LTC_ARGCHK(key         != NULL);
+   LTC_ARGCHK(ltc_mp.name != NULL);
+
+   /* init key */
+   if ((err = mp_init_multi(&key->e, &key->d, &key->N, &key->dQ,
+                            &key->dP, &key->qP, &key->p, &key->q, NULL)) != CRYPT_OK) {
+      return err;
+   }
+
+   /* see if the OpenSSL DER format RSA public key will work */
+   tmpbuf_len = inlen;
+   tmpbuf = XCALLOC(1, tmpbuf_len);
+   if (tmpbuf == NULL) {
+       err = CRYPT_MEM;
+       goto LBL_ERR;
+   }
+
+   err = der_decode_subject_public_key_info(in, inlen,
+        PKA_RSA, tmpbuf, &tmpbuf_len,
+        LTC_ASN1_NULL, NULL, 0);
+
+   if (err == CRYPT_OK) { /* SubjectPublicKeyInfo format */
+
+      /* now it should be SEQUENCE { INTEGER, INTEGER } */
+      if ((err = der_decode_sequence_multi(tmpbuf, tmpbuf_len,
+                                           LTC_ASN1_INTEGER, 1UL, key->N,
+                                           LTC_ASN1_INTEGER, 1UL, key->e,
+                                           LTC_ASN1_EOL,     0UL, NULL)) != CRYPT_OK) {
+         goto LBL_ERR;
+      }
+      key->type = PK_PUBLIC;
+      err = CRYPT_OK;
+      goto LBL_FREE;
+   }
+
+   /* not SSL public key, try to match against PKCS #1 standards */
+   err = der_decode_sequence_multi(in, inlen, LTC_ASN1_INTEGER, 1UL, key->N,
+                                              LTC_ASN1_EOL,     0UL, NULL);
+
+   if (err != CRYPT_OK && err != CRYPT_INPUT_TOO_LONG) {
+      goto LBL_ERR;
+   }
+
+   if (mp_cmp_d(key->N, 0) == LTC_MP_EQ) {
+      if ((err = mp_init(&zero)) != CRYPT_OK) {
+         goto LBL_ERR;
+      }
+      /* it's a private key */
+      if ((err = der_decode_sequence_multi(in, inlen,
+                          LTC_ASN1_INTEGER, 1UL, zero,
+                          LTC_ASN1_INTEGER, 1UL, key->N,
+                          LTC_ASN1_INTEGER, 1UL, key->e,
+                          LTC_ASN1_INTEGER, 1UL, key->d,
+                          LTC_ASN1_INTEGER, 1UL, key->p,
+                          LTC_ASN1_INTEGER, 1UL, key->q,
+                          LTC_ASN1_INTEGER, 1UL, key->dP,
+                          LTC_ASN1_INTEGER, 1UL, key->dQ,
+                          LTC_ASN1_INTEGER, 1UL, key->qP,
+                          LTC_ASN1_EOL,     0UL, NULL)) != CRYPT_OK) {
+         mp_clear(zero);
+         goto LBL_ERR;
+      }
+      mp_clear(zero);
+      key->type = PK_PRIVATE;
+   } else if (mp_cmp_d(key->N, 1) == LTC_MP_EQ) {
+      /* we don't support multi-prime RSA */
+      err = CRYPT_PK_INVALID_TYPE;
+      goto LBL_ERR;
+   } else {
+      /* it's a public key and we lack e */
+      if ((err = der_decode_sequence_multi(in, inlen,
+                                     LTC_ASN1_INTEGER, 1UL, key->N,
+                                     LTC_ASN1_INTEGER, 1UL, key->e,
+                                     LTC_ASN1_EOL,     0UL, NULL)) != CRYPT_OK) {
+         goto LBL_ERR;
+      }
+      key->type = PK_PUBLIC;
+   }
+   err = CRYPT_OK;
+   goto LBL_FREE;
+
+LBL_ERR:
+   mp_clear_multi(key->d,  key->e, key->N, key->dQ, key->dP, key->qP, key->p, key->q, NULL);
+
+LBL_FREE:
+   if (tmpbuf != NULL)
+     XFREE(tmpbuf);
+
+   return err;
+}
+
+#endif /* LTC_MRSA */
+
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/pk/rsa/rsa_import_pkcs8.c b/libtomcrypt/src/pk/rsa/rsa_import_pkcs8.c
new file mode 100644 (file)
index 0000000..0546eb0
--- /dev/null
@@ -0,0 +1,153 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file rsa_import_pkcs8.c
+  Import a PKCS RSA key
+*/
+
+#ifdef LTC_MRSA
+
+/* Public-Key Cryptography Standards (PKCS) #8:
+ * Private-Key Information Syntax Specification Version 1.2
+ * https://tools.ietf.org/html/rfc5208
+ *
+ * PrivateKeyInfo ::= SEQUENCE {
+ *      version                   Version,
+ *      privateKeyAlgorithm       PrivateKeyAlgorithmIdentifier,
+ *      privateKey                PrivateKey,
+ *      attributes           [0]  IMPLICIT Attributes OPTIONAL }
+ * where:
+ * - Version ::= INTEGER
+ * - PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier
+ * - PrivateKey ::= OCTET STRING
+ * - Attributes ::= SET OF Attribute
+ *
+ * EncryptedPrivateKeyInfo ::= SEQUENCE {
+ *        encryptionAlgorithm  EncryptionAlgorithmIdentifier,
+ *        encryptedData        EncryptedData }
+ * where:
+ * - EncryptionAlgorithmIdentifier ::= AlgorithmIdentifier
+ * - EncryptedData ::= OCTET STRING
+ */
+
+/**
+  Import an RSAPublicKey or RSAPrivateKey in PKCS#8 format
+  @param in        The packet to import from
+  @param inlen     It's length (octets)
+  @param passwd    The password for decrypting privkey (NOT SUPPORTED YET)
+  @param passwdlen Password's length (octets)
+  @param key       [out] Destination for newly imported key
+  @return CRYPT_OK if successful, upon error allocated memory is freed
+*/
+int rsa_import_pkcs8(const unsigned char *in, unsigned long inlen,
+                     const void *passwd, unsigned long passwdlen,
+                     rsa_key *key)
+{
+   int           err;
+   void          *zero, *iter;
+   unsigned char *buf1 = NULL, *buf2 = NULL;
+   unsigned long buf1len, buf2len;
+   unsigned long oid[16];
+   oid_st        rsaoid;
+   ltc_asn1_list alg_seq[2], top_seq[3];
+   ltc_asn1_list alg_seq_e[2], key_seq_e[2], top_seq_e[2];
+   unsigned char *decrypted = NULL;
+   unsigned long decryptedlen;
+
+   LTC_ARGCHK(in          != NULL);
+   LTC_ARGCHK(key         != NULL);
+   LTC_ARGCHK(ltc_mp.name != NULL);
+
+   /* get RSA alg oid */
+   err = pk_get_oid(PKA_RSA, &rsaoid);
+   if (err != CRYPT_OK) { goto LBL_NOFREE; }
+
+   /* alloc buffers */
+   buf1len = inlen; /* approx. */
+   buf1 = XMALLOC(buf1len);
+   if (buf1 == NULL) { err = CRYPT_MEM; goto LBL_NOFREE; }
+   buf2len = inlen; /* approx. */
+   buf2 = XMALLOC(buf2len);
+   if (buf2 == NULL) { err = CRYPT_MEM; goto LBL_FREE1; }
+
+   /* init key */
+   err = mp_init_multi(&key->e, &key->d, &key->N, &key->dQ, &key->dP, &key->qP, &key->p, &key->q, &zero, &iter, NULL);
+   if (err != CRYPT_OK) { goto LBL_FREE2; }
+
+   /* try to decode encrypted priv key */
+   LTC_SET_ASN1(key_seq_e, 0, LTC_ASN1_OCTET_STRING, buf1, buf1len);
+   LTC_SET_ASN1(key_seq_e, 1, LTC_ASN1_INTEGER, iter, 1UL);
+   LTC_SET_ASN1(alg_seq_e, 0, LTC_ASN1_OBJECT_IDENTIFIER, oid, 16UL);
+   LTC_SET_ASN1(alg_seq_e, 1, LTC_ASN1_SEQUENCE, key_seq_e, 2UL);
+   LTC_SET_ASN1(top_seq_e, 0, LTC_ASN1_SEQUENCE, alg_seq_e, 2UL);
+   LTC_SET_ASN1(top_seq_e, 1, LTC_ASN1_OCTET_STRING, buf2, buf2len);
+   err=der_decode_sequence(in, inlen, top_seq_e, 2UL);
+   if (err == CRYPT_OK) {
+      LTC_UNUSED_PARAM(passwd);
+      LTC_UNUSED_PARAM(passwdlen);
+      /* XXX: TODO encrypted pkcs8 not implemented yet */
+      /* fprintf(stderr, "decrypt: iter=%ld salt.len=%ld encdata.len=%ld\n", mp_get_int(iter), key_seq_e[0].size, top_seq_e[1].size); */
+      err = CRYPT_PK_INVALID_TYPE;
+      goto LBL_ERR;
+   }
+   else {
+      decrypted    = (unsigned char *)in;
+      decryptedlen = inlen;
+   }
+
+   /* try to decode unencrypted priv key */
+   LTC_SET_ASN1(alg_seq, 0, LTC_ASN1_OBJECT_IDENTIFIER, oid, 16UL);
+   LTC_SET_ASN1(alg_seq, 1, LTC_ASN1_NULL, NULL, 0UL);
+   LTC_SET_ASN1(top_seq, 0, LTC_ASN1_INTEGER, zero, 1UL);
+   LTC_SET_ASN1(top_seq, 1, LTC_ASN1_SEQUENCE, alg_seq, 2UL);
+   LTC_SET_ASN1(top_seq, 2, LTC_ASN1_OCTET_STRING, buf1, buf1len);
+   err=der_decode_sequence(decrypted, decryptedlen, top_seq, 3UL);
+   if (err != CRYPT_OK) { goto LBL_ERR; }
+
+   /* check alg oid */
+   if ((alg_seq[0].size != rsaoid.OIDlen) ||
+      XMEMCMP(rsaoid.OID, alg_seq[0].data, rsaoid.OIDlen * sizeof(rsaoid.OID[0])) != 0) {
+      err = CRYPT_PK_INVALID_TYPE;
+      goto LBL_ERR;
+   }
+
+   err = der_decode_sequence_multi(buf1, top_seq[2].size,
+                                   LTC_ASN1_INTEGER, 1UL, zero,
+                                   LTC_ASN1_INTEGER, 1UL, key->N,
+                                   LTC_ASN1_INTEGER, 1UL, key->e,
+                                   LTC_ASN1_INTEGER, 1UL, key->d,
+                                   LTC_ASN1_INTEGER, 1UL, key->p,
+                                   LTC_ASN1_INTEGER, 1UL, key->q,
+                                   LTC_ASN1_INTEGER, 1UL, key->dP,
+                                   LTC_ASN1_INTEGER, 1UL, key->dQ,
+                                   LTC_ASN1_INTEGER, 1UL, key->qP,
+                                   LTC_ASN1_EOL,     0UL, NULL);
+   if (err != CRYPT_OK) { goto LBL_ERR; }
+   key->type = PK_PRIVATE;
+   err = CRYPT_OK;
+   goto LBL_FREE2;
+
+LBL_ERR:
+   rsa_free(key);
+LBL_FREE2:
+   mp_clear_multi(iter, zero, NULL);
+   XFREE(buf2);
+LBL_FREE1:
+   XFREE(buf1);
+LBL_NOFREE:
+   return err;
+}
+
+#endif /* LTC_MRSA */
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/pk/rsa/rsa_import_x509.c b/libtomcrypt/src/pk/rsa/rsa_import_x509.c
new file mode 100644 (file)
index 0000000..0f2d5f1
--- /dev/null
@@ -0,0 +1,118 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file rsa_import.c
+  Import an RSA key from a X.509 certificate, Steffen Jaeckel
+*/
+
+#ifdef LTC_MRSA
+
+/**
+  Import an RSA key from a X.509 certificate
+  @param in      The packet to import from
+  @param inlen   It's length (octets)
+  @param key     [out] Destination for newly imported key
+  @return CRYPT_OK if successful, upon error allocated memory is freed
+*/
+int rsa_import_x509(const unsigned char *in, unsigned long inlen, rsa_key *key)
+{
+   int           err;
+   unsigned char *tmpbuf;
+   unsigned long tmpbuf_len, tmp_inlen;
+   ltc_asn1_list *decoded_list = NULL, *l;
+
+   LTC_ARGCHK(in          != NULL);
+   LTC_ARGCHK(key         != NULL);
+   LTC_ARGCHK(ltc_mp.name != NULL);
+
+   /* init key */
+   if ((err = mp_init_multi(&key->e, &key->d, &key->N, &key->dQ,
+                            &key->dP, &key->qP, &key->p, &key->q, NULL)) != CRYPT_OK) {
+      return err;
+   }
+
+   tmpbuf_len = inlen;
+   tmpbuf = XCALLOC(1, tmpbuf_len);
+   if (tmpbuf == NULL) {
+       err = CRYPT_MEM;
+       goto LBL_ERR;
+   }
+
+   tmp_inlen = inlen;
+   if ((err = der_decode_sequence_flexi(in, &tmp_inlen, &decoded_list)) == CRYPT_OK) {
+      l = decoded_list;
+      /* Move 2 levels up in the tree
+         SEQUENCE
+             SEQUENCE
+                 ...
+       */
+      if (l->type == LTC_ASN1_SEQUENCE && l->child) {
+         l = l->child;
+         if (l->type == LTC_ASN1_SEQUENCE && l->child) {
+            l = l->child;
+
+            err = CRYPT_ERROR;
+
+            /* Move forward in the tree until we find this combination
+                 ...
+                 SEQUENCE
+                     SEQUENCE
+                         OBJECT IDENTIFIER 1.2.840.113549.1.1.1
+                         NULL
+                     BIT STRING
+             */
+            do {
+               /* The additional check for l->data is there to make sure
+                * we won't try to decode a list that has been 'shrunk'
+                */
+               if (l->type == LTC_ASN1_SEQUENCE && l->data && l->child &&
+                     l->child->type == LTC_ASN1_SEQUENCE && l->child->child &&
+                     l->child->child->type == LTC_ASN1_OBJECT_IDENTIFIER && l->child->next &&
+                     l->child->next->type == LTC_ASN1_BIT_STRING) {
+                  err = der_decode_subject_public_key_info(l->data, l->size,
+                       PKA_RSA, tmpbuf, &tmpbuf_len,
+                       LTC_ASN1_NULL, NULL, 0);
+                  if (err == CRYPT_OK) {
+                     /* now it should be SEQUENCE { INTEGER, INTEGER } */
+                     if ((err = der_decode_sequence_multi(tmpbuf, tmpbuf_len,
+                                                          LTC_ASN1_INTEGER, 1UL, key->N,
+                                                          LTC_ASN1_INTEGER, 1UL, key->e,
+                                                          LTC_ASN1_EOL,     0UL, NULL)) != CRYPT_OK) {
+                        goto LBL_ERR;
+                     }
+                     key->type = PK_PUBLIC;
+                     err = CRYPT_OK;
+                     goto LBL_FREE;
+                  }
+               }
+               l = l->next;
+            } while(l);
+         }
+      }
+   }
+
+
+LBL_ERR:
+   rsa_free(key);
+
+LBL_FREE:
+   if (decoded_list) der_free_sequence_flexi(decoded_list);
+   if (tmpbuf != NULL) XFREE(tmpbuf);
+
+   return err;
+}
+
+#endif /* LTC_MRSA */
+
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/pk/rsa/rsa_make_key.c b/libtomcrypt/src/pk/rsa/rsa_make_key.c
new file mode 100644 (file)
index 0000000..c5c4c28
--- /dev/null
@@ -0,0 +1,107 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file rsa_make_key.c
+  RSA key generation, Tom St Denis
+*/
+
+#ifdef LTC_MRSA
+
+/**
+   Create an RSA key
+   @param prng     An active PRNG state
+   @param wprng    The index of the PRNG desired
+   @param size     The size of the modulus (key size) desired (octets)
+   @param e        The "e" value (public key).  e==65537 is a good choice
+   @param key      [out] Destination of a newly created private key pair
+   @return CRYPT_OK if successful, upon error all allocated ram is freed
+*/
+int rsa_make_key(prng_state *prng, int wprng, int size, long e, rsa_key *key)
+{
+   void *p, *q, *tmp1, *tmp2, *tmp3;
+   int    err;
+
+   LTC_ARGCHK(ltc_mp.name != NULL);
+   LTC_ARGCHK(key         != NULL);
+   LTC_ARGCHK(size        > 0);
+
+   if ((e < 3) || ((e & 1) == 0)) {
+      return CRYPT_INVALID_ARG;
+   }
+
+   if ((err = prng_is_valid(wprng)) != CRYPT_OK) {
+      return err;
+   }
+
+   if ((err = mp_init_multi(&p, &q, &tmp1, &tmp2, &tmp3, NULL)) != CRYPT_OK) {
+      return err;
+   }
+
+   /* make primes p and q (optimization provided by Wayne Scott) */
+   if ((err = mp_set_int(tmp3, e)) != CRYPT_OK)                      { goto cleanup; }  /* tmp3 = e */
+
+   /* make prime "p" */
+   do {
+       if ((err = rand_prime( p, size/2, prng, wprng)) != CRYPT_OK)  { goto cleanup; }
+       if ((err = mp_sub_d( p, 1,  tmp1)) != CRYPT_OK)               { goto cleanup; }  /* tmp1 = p-1 */
+       if ((err = mp_gcd( tmp1,  tmp3,  tmp2)) != CRYPT_OK)          { goto cleanup; }  /* tmp2 = gcd(p-1, e) */
+   } while (mp_cmp_d( tmp2, 1) != 0);                                                  /* while e divides p-1 */
+
+   /* make prime "q" */
+   do {
+       if ((err = rand_prime( q, size/2, prng, wprng)) != CRYPT_OK)  { goto cleanup; }
+       if ((err = mp_sub_d( q, 1,  tmp1)) != CRYPT_OK)               { goto cleanup; } /* tmp1 = q-1 */
+       if ((err = mp_gcd( tmp1,  tmp3,  tmp2)) != CRYPT_OK)          { goto cleanup; } /* tmp2 = gcd(q-1, e) */
+   } while (mp_cmp_d( tmp2, 1) != 0);                                                 /* while e divides q-1 */
+
+   /* tmp1 = lcm(p-1, q-1) */
+   if ((err = mp_sub_d( p, 1,  tmp2)) != CRYPT_OK)                   { goto cleanup; } /* tmp2 = p-1 */
+                                                                                      /* tmp1 = q-1 (previous do/while loop) */
+   if ((err = mp_lcm( tmp1,  tmp2,  tmp1)) != CRYPT_OK)              { goto cleanup; } /* tmp1 = lcm(p-1, q-1) */
+
+   /* make key */
+   if ((err = mp_init_multi(&key->e, &key->d, &key->N, &key->dQ, &key->dP, &key->qP, &key->p, &key->q, NULL)) != CRYPT_OK) {
+      goto errkey;
+   }
+
+   if ((err = mp_set_int( key->e, e)) != CRYPT_OK)                     { goto errkey; } /* key->e =  e */
+   if ((err = mp_invmod( key->e,  tmp1,  key->d)) != CRYPT_OK)         { goto errkey; } /* key->d = 1/e mod lcm(p-1,q-1) */
+   if ((err = mp_mul( p,  q,  key->N)) != CRYPT_OK)                    { goto errkey; } /* key->N = pq */
+
+   /* optimize for CRT now */
+   /* find d mod q-1 and d mod p-1 */
+   if ((err = mp_sub_d( p, 1,  tmp1)) != CRYPT_OK)                     { goto errkey; } /* tmp1 = q-1 */
+   if ((err = mp_sub_d( q, 1,  tmp2)) != CRYPT_OK)                     { goto errkey; } /* tmp2 = p-1 */
+   if ((err = mp_mod( key->d,  tmp1,  key->dP)) != CRYPT_OK)           { goto errkey; } /* dP = d mod p-1 */
+   if ((err = mp_mod( key->d,  tmp2,  key->dQ)) != CRYPT_OK)           { goto errkey; } /* dQ = d mod q-1 */
+   if ((err = mp_invmod( q,  p,  key->qP)) != CRYPT_OK)                { goto errkey; } /* qP = 1/q mod p */
+
+   if ((err = mp_copy( p,  key->p)) != CRYPT_OK)                       { goto errkey; }
+   if ((err = mp_copy( q,  key->q)) != CRYPT_OK)                       { goto errkey; }
+
+   /* set key type (in this case it's CRT optimized) */
+   key->type = PK_PRIVATE;
+
+   /* return ok and free temps */
+   err       = CRYPT_OK;
+   goto cleanup;
+errkey:
+   rsa_free(key);
+cleanup:
+   mp_clear_multi(tmp3, tmp2, tmp1, q, p, NULL);
+   return err;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/pk/rsa/rsa_set.c b/libtomcrypt/src/pk/rsa/rsa_set.c
new file mode 100644 (file)
index 0000000..0d540c4
--- /dev/null
@@ -0,0 +1,134 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+
+#ifdef LTC_MRSA
+
+/**
+  Import RSA key from raw numbers
+
+  @param N       RSA's N
+  @param Nlen    RSA's N's length
+  @param e       RSA's e
+  @param elen    RSA's e's length
+  @param d       RSA's d  (only private key, NULL for public key)
+  @param dlen    RSA's d's length
+  @param key     [out] the destination for the imported key
+  @return CRYPT_OK if successful
+*/
+int rsa_set_key(const unsigned char *N,  unsigned long Nlen,
+                const unsigned char *e,  unsigned long elen,
+                const unsigned char *d,  unsigned long dlen,
+                rsa_key *key)
+{
+   int err;
+
+   LTC_ARGCHK(key         != NULL);
+   LTC_ARGCHK(N           != NULL);
+   LTC_ARGCHK(e           != NULL);
+   LTC_ARGCHK(ltc_mp.name != NULL);
+
+   err = mp_init_multi(&key->e, &key->d, &key->N, &key->dQ, &key->dP, &key->qP, &key->p, &key->q, NULL);
+   if (err != CRYPT_OK) return err;
+
+   if ((err = mp_read_unsigned_bin(key->N , (unsigned char *)N , Nlen)) != CRYPT_OK)    { goto LBL_ERR; }
+   if ((err = mp_read_unsigned_bin(key->e , (unsigned char *)e , elen)) != CRYPT_OK)    { goto LBL_ERR; }
+   if (d && dlen) {
+      if ((err = mp_read_unsigned_bin(key->d , (unsigned char *)d , dlen)) != CRYPT_OK) { goto LBL_ERR; }
+      key->type = PK_PRIVATE;
+   }
+   else {
+      key->type = PK_PUBLIC;
+   }
+   return CRYPT_OK;
+
+LBL_ERR:
+   rsa_free(key);
+   return err;
+}
+
+/**
+  Import factors of an RSA key from raw numbers
+
+  Only for private keys.
+
+  @param p       RSA's p
+  @param plen    RSA's p's length
+  @param q       RSA's q
+  @param qlen    RSA's q's length
+  @param key     [out] the destination for the imported key
+  @return CRYPT_OK if successful
+*/
+int rsa_set_factors(const unsigned char *p,  unsigned long plen,
+                    const unsigned char *q,  unsigned long qlen,
+                    rsa_key *key)
+{
+   int err;
+
+   LTC_ARGCHK(key         != NULL);
+   LTC_ARGCHK(p           != NULL);
+   LTC_ARGCHK(q           != NULL);
+   LTC_ARGCHK(ltc_mp.name != NULL);
+
+   if (key->type != PK_PRIVATE) return CRYPT_PK_TYPE_MISMATCH;
+
+   if ((err = mp_read_unsigned_bin(key->p , (unsigned char *)p , plen)) != CRYPT_OK) { goto LBL_ERR; }
+   if ((err = mp_read_unsigned_bin(key->q , (unsigned char *)q , qlen)) != CRYPT_OK) { goto LBL_ERR; }
+   return CRYPT_OK;
+
+LBL_ERR:
+   rsa_free(key);
+   return err;
+}
+
+/**
+  Import CRT parameters of an RSA key from raw numbers
+
+  Only for private keys.
+
+  @param dP      RSA's dP
+  @param dPlen   RSA's dP's length
+  @param dQ      RSA's dQ
+  @param dQlen   RSA's dQ's length
+  @param qP      RSA's qP
+  @param qPlen   RSA's qP's length
+  @param key     [out] the destination for the imported key
+  @return CRYPT_OK if successful
+*/
+int rsa_set_crt_params(const unsigned char *dP, unsigned long dPlen,
+                       const unsigned char *dQ, unsigned long dQlen,
+                       const unsigned char *qP, unsigned long qPlen,
+                       rsa_key *key)
+{
+   int err;
+
+   LTC_ARGCHK(key         != NULL);
+   LTC_ARGCHK(dP          != NULL);
+   LTC_ARGCHK(dQ          != NULL);
+   LTC_ARGCHK(qP          != NULL);
+   LTC_ARGCHK(ltc_mp.name != NULL);
+
+   if (key->type != PK_PRIVATE) return CRYPT_PK_TYPE_MISMATCH;
+
+   if ((err = mp_read_unsigned_bin(key->dP, (unsigned char *)dP, dPlen)) != CRYPT_OK) { goto LBL_ERR; }
+   if ((err = mp_read_unsigned_bin(key->dQ, (unsigned char *)dQ, dQlen)) != CRYPT_OK) { goto LBL_ERR; }
+   if ((err = mp_read_unsigned_bin(key->qP, (unsigned char *)qP, qPlen)) != CRYPT_OK) { goto LBL_ERR; }
+   return CRYPT_OK;
+
+LBL_ERR:
+   rsa_free(key);
+   return err;
+}
+
+#endif /* LTC_MRSA */
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/pk/rsa/rsa_sign_hash.c b/libtomcrypt/src/pk/rsa/rsa_sign_hash.c
new file mode 100644 (file)
index 0000000..05c7155
--- /dev/null
@@ -0,0 +1,146 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file rsa_sign_hash.c
+  RSA PKCS #1 v1.5 and v2 PSS sign hash, Tom St Denis and Andreas Lange
+*/
+
+#ifdef LTC_MRSA
+
+/**
+  PKCS #1 pad then sign
+  @param in        The hash to sign
+  @param inlen     The length of the hash to sign (octets)
+  @param out       [out] The signature
+  @param outlen    [in/out] The max size and resulting size of the signature
+  @param padding   Type of padding (LTC_PKCS_1_PSS, LTC_PKCS_1_V1_5 or LTC_PKCS_1_V1_5_NA1)
+  @param prng      An active PRNG state
+  @param prng_idx  The index of the PRNG desired
+  @param hash_idx  The index of the hash desired
+  @param saltlen   The length of the salt desired (octets)
+  @param key       The private RSA key to use
+  @return CRYPT_OK if successful
+*/
+int rsa_sign_hash_ex(const unsigned char *in,       unsigned long  inlen,
+                           unsigned char *out,      unsigned long *outlen,
+                           int            padding,
+                           prng_state    *prng,     int            prng_idx,
+                           int            hash_idx, unsigned long  saltlen,
+                           rsa_key *key)
+{
+   unsigned long modulus_bitlen, modulus_bytelen, x, y;
+   int           err;
+
+   LTC_ARGCHK(in       != NULL);
+   LTC_ARGCHK(out      != NULL);
+   LTC_ARGCHK(outlen   != NULL);
+   LTC_ARGCHK(key      != NULL);
+
+   /* valid padding? */
+   if ((padding != LTC_PKCS_1_V1_5) &&
+       (padding != LTC_PKCS_1_PSS) &&
+       (padding != LTC_PKCS_1_V1_5_NA1)) {
+     return CRYPT_PK_INVALID_PADDING;
+   }
+
+   if (padding == LTC_PKCS_1_PSS) {
+     /* valid prng ? */
+     if ((err = prng_is_valid(prng_idx)) != CRYPT_OK) {
+        return err;
+     }
+   }
+
+   if (padding != LTC_PKCS_1_V1_5_NA1) {
+     /* valid hash ? */
+     if ((err = hash_is_valid(hash_idx)) != CRYPT_OK) {
+        return err;
+     }
+   }
+
+   /* get modulus len in bits */
+   modulus_bitlen = mp_count_bits((key->N));
+
+  /* outlen must be at least the size of the modulus */
+  modulus_bytelen = mp_unsigned_bin_size((key->N));
+  if (modulus_bytelen > *outlen) {
+     *outlen = modulus_bytelen;
+     return CRYPT_BUFFER_OVERFLOW;
+  }
+
+  if (padding == LTC_PKCS_1_PSS) {
+    /* PSS pad the key */
+    x = *outlen;
+    if ((err = pkcs_1_pss_encode(in, inlen, saltlen, prng, prng_idx,
+                                 hash_idx, modulus_bitlen, out, &x)) != CRYPT_OK) {
+       return err;
+    }
+  } else {
+    /* PKCS #1 v1.5 pad the hash */
+    unsigned char *tmpin;
+
+    if (padding == LTC_PKCS_1_V1_5) {
+      ltc_asn1_list digestinfo[2], siginfo[2];
+      /* not all hashes have OIDs... so sad */
+      if (hash_descriptor[hash_idx].OIDlen == 0) {
+         return CRYPT_INVALID_ARG;
+      }
+
+    /* construct the SEQUENCE
+        SEQUENCE {
+           SEQUENCE {hashoid OID
+                     blah    NULL
+           }
+         hash    OCTET STRING
+        }
+     */
+      LTC_SET_ASN1(digestinfo, 0, LTC_ASN1_OBJECT_IDENTIFIER, hash_descriptor[hash_idx].OID, hash_descriptor[hash_idx].OIDlen);
+      LTC_SET_ASN1(digestinfo, 1, LTC_ASN1_NULL,              NULL,                          0);
+      LTC_SET_ASN1(siginfo,    0, LTC_ASN1_SEQUENCE,          digestinfo,                    2);
+      LTC_SET_ASN1(siginfo,    1, LTC_ASN1_OCTET_STRING,      in,                            inlen);
+
+      /* allocate memory for the encoding */
+      y = mp_unsigned_bin_size(key->N);
+      tmpin = XMALLOC(y);
+      if (tmpin == NULL) {
+         return CRYPT_MEM;
+      }
+
+      if ((err = der_encode_sequence(siginfo, 2, tmpin, &y)) != CRYPT_OK) {
+         XFREE(tmpin);
+         return err;
+      }
+    } else {
+      /* set the pointer and data-length to the input values */
+      tmpin = (unsigned char *)in;
+      y = inlen;
+    }
+
+    x = *outlen;
+    err = pkcs_1_v1_5_encode(tmpin, y, LTC_PKCS_1_EMSA, modulus_bitlen, NULL, 0, out, &x);
+
+    if (padding == LTC_PKCS_1_V1_5) {
+      XFREE(tmpin);
+    }
+
+    if (err != CRYPT_OK) {
+      return err;
+    }
+  }
+
+  /* RSA encode it */
+  return ltc_mp.rsa_me(out, x, out, outlen, PK_PRIVATE, key);
+}
+
+#endif /* LTC_MRSA */
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/pk/rsa/rsa_sign_saltlen_get.c b/libtomcrypt/src/pk/rsa/rsa_sign_saltlen_get.c
new file mode 100644 (file)
index 0000000..b217f94
--- /dev/null
@@ -0,0 +1,47 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file rsa_sign_saltlen_get.c
+  Retrieve the maximum size of the salt, Steffen Jaeckel.
+*/
+
+#ifdef LTC_MRSA
+
+/**
+  Retrieve the maximum possible size of the salt when creating a PKCS#1 PSS signature.
+  @param padding    Type of padding (LTC_PKCS_1_PSS only)
+  @param hash_idx   The index of the desired hash
+  @param key        The RSA key
+  @return The maximum salt length in bytes or INT_MAX on error.
+*/
+int rsa_sign_saltlen_get_max_ex(int padding, int hash_idx, rsa_key *key)
+{
+  int ret = INT_MAX;
+  LTC_ARGCHK(key != NULL);
+
+  if ((hash_is_valid(hash_idx) == CRYPT_OK) &&
+      (padding == LTC_PKCS_1_PSS))
+  {
+    ret = rsa_get_size(key);
+    if (ret < INT_MAX)
+    {
+      ret -= (hash_descriptor[hash_idx].hashsize + 2);
+    } /* if */
+  } /* if */
+
+  return ret;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/pk/rsa/rsa_verify_hash.c b/libtomcrypt/src/pk/rsa/rsa_verify_hash.c
new file mode 100644 (file)
index 0000000..b584696
--- /dev/null
@@ -0,0 +1,193 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file rsa_verify_hash.c
+  RSA PKCS #1 v1.5 or v2 PSS signature verification, Tom St Denis and Andreas Lange
+*/
+
+#ifdef LTC_MRSA
+
+/**
+  PKCS #1 de-sign then v1.5 or PSS depad
+  @param sig              The signature data
+  @param siglen           The length of the signature data (octets)
+  @param hash             The hash of the message that was signed
+  @param hashlen          The length of the hash of the message that was signed (octets)
+  @param padding          Type of padding (LTC_PKCS_1_PSS, LTC_PKCS_1_V1_5 or LTC_PKCS_1_V1_5_NA1)
+  @param hash_idx         The index of the desired hash
+  @param saltlen          The length of the salt used during signature
+  @param stat             [out] The result of the signature comparison, 1==valid, 0==invalid
+  @param key              The public RSA key corresponding to the key that performed the signature
+  @return CRYPT_OK on success (even if the signature is invalid)
+*/
+int rsa_verify_hash_ex(const unsigned char *sig,      unsigned long siglen,
+                       const unsigned char *hash,     unsigned long hashlen,
+                             int            padding,
+                             int            hash_idx, unsigned long saltlen,
+                             int           *stat,     rsa_key      *key)
+{
+  unsigned long modulus_bitlen, modulus_bytelen, x;
+  int           err;
+  unsigned char *tmpbuf;
+
+  LTC_ARGCHK(hash  != NULL);
+  LTC_ARGCHK(sig   != NULL);
+  LTC_ARGCHK(stat  != NULL);
+  LTC_ARGCHK(key   != NULL);
+
+  /* default to invalid */
+  *stat = 0;
+
+  /* valid padding? */
+
+  if ((padding != LTC_PKCS_1_V1_5) &&
+      (padding != LTC_PKCS_1_PSS) &&
+      (padding != LTC_PKCS_1_V1_5_NA1)) {
+    return CRYPT_PK_INVALID_PADDING;
+  }
+
+  if (padding != LTC_PKCS_1_V1_5_NA1) {
+    /* valid hash ? */
+    if ((err = hash_is_valid(hash_idx)) != CRYPT_OK) {
+       return err;
+    }
+  }
+
+  /* get modulus len in bits */
+  modulus_bitlen = mp_count_bits( (key->N));
+
+  /* outlen must be at least the size of the modulus */
+  modulus_bytelen = mp_unsigned_bin_size( (key->N));
+  if (modulus_bytelen != siglen) {
+     return CRYPT_INVALID_PACKET;
+  }
+
+  /* allocate temp buffer for decoded sig */
+  tmpbuf = XMALLOC(siglen);
+  if (tmpbuf == NULL) {
+     return CRYPT_MEM;
+  }
+
+  /* RSA decode it  */
+  x = siglen;
+  if ((err = ltc_mp.rsa_me(sig, siglen, tmpbuf, &x, PK_PUBLIC, key)) != CRYPT_OK) {
+     XFREE(tmpbuf);
+     return err;
+  }
+
+  /* make sure the output is the right size */
+  if (x != siglen) {
+     XFREE(tmpbuf);
+     return CRYPT_INVALID_PACKET;
+  }
+
+  if (padding == LTC_PKCS_1_PSS) {
+    /* PSS decode and verify it */
+
+    if(modulus_bitlen%8 == 1){
+      err = pkcs_1_pss_decode(hash, hashlen, tmpbuf+1, x-1, saltlen, hash_idx, modulus_bitlen, stat);
+    }
+    else{
+      err = pkcs_1_pss_decode(hash, hashlen, tmpbuf, x, saltlen, hash_idx, modulus_bitlen, stat);
+    }
+
+  } else {
+    /* PKCS #1 v1.5 decode it */
+    unsigned char *out;
+    unsigned long outlen;
+    int           decoded;
+
+    /* allocate temp buffer for decoded hash */
+    outlen = ((modulus_bitlen >> 3) + (modulus_bitlen & 7 ? 1 : 0)) - 3;
+    out    = XMALLOC(outlen);
+    if (out == NULL) {
+      err = CRYPT_MEM;
+      goto bail_2;
+    }
+
+    if ((err = pkcs_1_v1_5_decode(tmpbuf, x, LTC_PKCS_1_EMSA, modulus_bitlen, out, &outlen, &decoded)) != CRYPT_OK) {
+      XFREE(out);
+      goto bail_2;
+    }
+
+    if (padding == LTC_PKCS_1_V1_5) {
+      unsigned long loid[16], reallen;
+      ltc_asn1_list digestinfo[2], siginfo[2];
+
+      /* not all hashes have OIDs... so sad */
+      if (hash_descriptor[hash_idx].OIDlen == 0) {
+         err = CRYPT_INVALID_ARG;
+         goto bail_2;
+      }
+
+      /* now we must decode out[0...outlen-1] using ASN.1, test the OID and then test the hash */
+      /* construct the SEQUENCE
+        SEQUENCE {
+           SEQUENCE {hashoid OID
+                     blah    NULL
+           }
+           hash    OCTET STRING
+        }
+     */
+      LTC_SET_ASN1(digestinfo, 0, LTC_ASN1_OBJECT_IDENTIFIER, loid, sizeof(loid)/sizeof(loid[0]));
+      LTC_SET_ASN1(digestinfo, 1, LTC_ASN1_NULL,              NULL,                          0);
+      LTC_SET_ASN1(siginfo,    0, LTC_ASN1_SEQUENCE,          digestinfo,                    2);
+      LTC_SET_ASN1(siginfo,    1, LTC_ASN1_OCTET_STRING,      tmpbuf,                        siglen);
+
+      if ((err = der_decode_sequence(out, outlen, siginfo, 2)) != CRYPT_OK) {
+         /* fallback to Legacy:missing NULL */
+         LTC_SET_ASN1(siginfo, 0, LTC_ASN1_SEQUENCE,          digestinfo,                    1);
+         if ((err = der_decode_sequence(out, outlen, siginfo, 2)) != CRYPT_OK) {
+           XFREE(out);
+           goto bail_2;
+         }
+      }
+
+      if ((err = der_length_sequence(siginfo, 2, &reallen)) != CRYPT_OK) {
+         XFREE(out);
+         goto bail_2;
+      }
+
+      /* test OID */
+      if ((reallen == outlen) &&
+          (digestinfo[0].size == hash_descriptor[hash_idx].OIDlen) &&
+        (XMEMCMP(digestinfo[0].data, hash_descriptor[hash_idx].OID, sizeof(unsigned long) * hash_descriptor[hash_idx].OIDlen) == 0) &&
+          (siginfo[1].size == hashlen) &&
+        (XMEMCMP(siginfo[1].data, hash, hashlen) == 0)) {
+         *stat = 1;
+      }
+    } else {
+      /* only check if the hash is equal */
+      if ((hashlen == outlen) &&
+          (XMEMCMP(out, hash, hashlen) == 0)) {
+        *stat = 1;
+      }
+    }
+
+#ifdef LTC_CLEAN_STACK
+    zeromem(out, outlen);
+#endif
+    XFREE(out);
+  }
+
+bail_2:
+#ifdef LTC_CLEAN_STACK
+  zeromem(tmpbuf, siglen);
+#endif
+  XFREE(tmpbuf);
+  return err;
+}
+
+#endif /* LTC_MRSA */
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/prngs/chacha20.c b/libtomcrypt/src/prngs/chacha20.c
new file mode 100644 (file)
index 0000000..72a6d63
--- /dev/null
@@ -0,0 +1,247 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+ /* the idea of re-keying loosely follows the approach used in:
+  * http://bxr.su/OpenBSD/lib/libc/crypt/arc4random.c
+  */
+
+#include "tomcrypt.h"
+
+#ifdef LTC_CHACHA20_PRNG
+
+const struct ltc_prng_descriptor chacha20_prng_desc =
+{
+   "chacha20",
+   40,
+   &chacha20_prng_start,
+   &chacha20_prng_add_entropy,
+   &chacha20_prng_ready,
+   &chacha20_prng_read,
+   &chacha20_prng_done,
+   &chacha20_prng_export,
+   &chacha20_prng_import,
+   &chacha20_prng_test
+};
+
+/**
+  Start the PRNG
+  @param prng The PRNG state to initialize
+  @return CRYPT_OK if successful
+*/
+int chacha20_prng_start(prng_state *prng)
+{
+   LTC_ARGCHK(prng != NULL);
+   prng->ready = 0;
+   XMEMSET(&prng->chacha.ent, 0, sizeof(prng->chacha.ent));
+   prng->chacha.idx = 0;
+   LTC_MUTEX_INIT(&prng->lock)
+   return CRYPT_OK;
+}
+
+/**
+  Add entropy to the PRNG state
+  @param in       The data to add
+  @param inlen    Length of the data to add
+  @param prng     PRNG state to update
+  @return CRYPT_OK if successful
+*/
+int chacha20_prng_add_entropy(const unsigned char *in, unsigned long inlen, prng_state *prng)
+{
+   unsigned char buf[40];
+   unsigned long i;
+   int err;
+
+   LTC_ARGCHK(prng != NULL);
+   LTC_ARGCHK(in != NULL);
+   LTC_ARGCHK(inlen > 0);
+
+   LTC_MUTEX_LOCK(&prng->lock);
+   if (prng->ready) {
+      /* chacha20_prng_ready() was already called, do "rekey" operation */
+      if ((err = chacha_keystream(&prng->chacha.s, buf, sizeof(buf))) != CRYPT_OK) goto LBL_UNLOCK;
+      for(i = 0; i < inlen; i++) buf[i % sizeof(buf)] ^= in[i];
+      /* key 32 bytes, 20 rounds */
+      if ((err = chacha_setup(&prng->chacha.s, buf, 32, 20)) != CRYPT_OK)      goto LBL_UNLOCK;
+      /* iv 8 bytes */
+      if ((err = chacha_ivctr64(&prng->chacha.s, buf + 32, 8, 0)) != CRYPT_OK) goto LBL_UNLOCK;
+      /* clear KEY + IV */
+      zeromem(buf, sizeof(buf));
+   }
+   else {
+      /* chacha20_prng_ready() was not called yet, add entropy to ent buffer */
+      while (inlen--) prng->chacha.ent[prng->chacha.idx++ % sizeof(prng->chacha.ent)] ^= *in++;
+   }
+   err = CRYPT_OK;
+LBL_UNLOCK:
+   LTC_MUTEX_UNLOCK(&prng->lock);
+   return err;
+}
+
+/**
+  Make the PRNG ready to read from
+  @param prng   The PRNG to make active
+  @return CRYPT_OK if successful
+*/
+int chacha20_prng_ready(prng_state *prng)
+{
+   int err;
+
+   LTC_ARGCHK(prng != NULL);
+
+   LTC_MUTEX_LOCK(&prng->lock);
+   if (prng->ready)                                                    { err = CRYPT_OK; goto LBL_UNLOCK; }
+   /* key 32 bytes, 20 rounds */
+   if ((err = chacha_setup(&prng->chacha.s, prng->chacha.ent, 32, 20)) != CRYPT_OK)      goto LBL_UNLOCK;
+   /* iv 8 bytes */
+   if ((err = chacha_ivctr64(&prng->chacha.s, prng->chacha.ent + 32, 8, 0)) != CRYPT_OK) goto LBL_UNLOCK;
+   XMEMSET(&prng->chacha.ent, 0, sizeof(prng->chacha.ent));
+   prng->chacha.idx = 0;
+   prng->ready = 1;
+LBL_UNLOCK:
+   LTC_MUTEX_UNLOCK(&prng->lock);
+   return err;
+}
+
+/**
+  Read from the PRNG
+  @param out      Destination
+  @param outlen   Length of output
+  @param prng     The active PRNG to read from
+  @return Number of octets read
+*/
+unsigned long chacha20_prng_read(unsigned char *out, unsigned long outlen, prng_state *prng)
+{
+   if (outlen == 0 || prng == NULL || out == NULL) return 0;
+   LTC_MUTEX_LOCK(&prng->lock);
+   if (!prng->ready) { outlen = 0; goto LBL_UNLOCK; }
+   if (chacha_keystream(&prng->chacha.s, out, outlen) != CRYPT_OK) outlen = 0;
+LBL_UNLOCK:
+   LTC_MUTEX_UNLOCK(&prng->lock);
+   return outlen;
+}
+
+/**
+  Terminate the PRNG
+  @param prng   The PRNG to terminate
+  @return CRYPT_OK if successful
+*/
+int chacha20_prng_done(prng_state *prng)
+{
+   int err;
+   LTC_ARGCHK(prng != NULL);
+   LTC_MUTEX_LOCK(&prng->lock);
+   prng->ready = 0;
+   err = chacha_done(&prng->chacha.s);
+   LTC_MUTEX_UNLOCK(&prng->lock);
+   LTC_MUTEX_DESTROY(&prng->lock);
+   return err;
+}
+
+/**
+  Export the PRNG state
+  @param out       [out] Destination
+  @param outlen    [in/out] Max size and resulting size of the state
+  @param prng      The PRNG to export
+  @return CRYPT_OK if successful
+*/
+int chacha20_prng_export(unsigned char *out, unsigned long *outlen, prng_state *prng)
+{
+   unsigned long len = chacha20_prng_desc.export_size;
+
+   LTC_ARGCHK(prng   != NULL);
+   LTC_ARGCHK(out    != NULL);
+   LTC_ARGCHK(outlen != NULL);
+
+   if (*outlen < len) {
+      *outlen = len;
+      return CRYPT_BUFFER_OVERFLOW;
+   }
+
+   if (chacha20_prng_read(out, len, prng) != len) {
+      return CRYPT_ERROR_READPRNG;
+   }
+
+   *outlen = len;
+   return CRYPT_OK;
+}
+
+/**
+  Import a PRNG state
+  @param in       The PRNG state
+  @param inlen    Size of the state
+  @param prng     The PRNG to import
+  @return CRYPT_OK if successful
+*/
+int chacha20_prng_import(const unsigned char *in, unsigned long inlen, prng_state *prng)
+{
+   int err;
+
+   LTC_ARGCHK(prng != NULL);
+   LTC_ARGCHK(in   != NULL);
+   if (inlen < (unsigned long)chacha20_prng_desc.export_size) return CRYPT_INVALID_ARG;
+
+   if ((err = chacha20_prng_start(prng)) != CRYPT_OK)                  return err;
+   if ((err = chacha20_prng_add_entropy(in, inlen, prng)) != CRYPT_OK) return err;
+   return CRYPT_OK;
+}
+
+/**
+  PRNG self-test
+  @return CRYPT_OK if successful, CRYPT_NOP if self-testing has been disabled
+*/
+int chacha20_prng_test(void)
+{
+#ifndef LTC_TEST
+   return CRYPT_NOP;
+#else
+   prng_state st;
+   unsigned char en[] = { 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, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
+                          0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32 };
+   unsigned char dmp[300];
+   unsigned long dmplen = sizeof(dmp);
+   unsigned char out[500];
+   unsigned char t1[] = { 0x59, 0xB2, 0x26, 0x95, 0x2B, 0x01, 0x8F, 0x05, 0xBE, 0xD8 };
+   unsigned char t2[] = { 0x47, 0xC9, 0x0D, 0x03, 0xE4, 0x75, 0x34, 0x27, 0xBD, 0xDE };
+   unsigned char t3[] = { 0xBC, 0xFA, 0xEF, 0x59, 0x37, 0x7F, 0x1A, 0x91, 0x1A, 0xA6 };
+   int err;
+
+   if ((err = chacha20_prng_start(&st)) != CRYPT_OK)                       return err;
+   /* add entropy to uninitialized prng */
+   if ((err = chacha20_prng_add_entropy(en, sizeof(en), &st)) != CRYPT_OK) return err;
+   if ((err = chacha20_prng_ready(&st)) != CRYPT_OK)                       return err;
+   if (chacha20_prng_read(out, 10, &st) != 10)                             return CRYPT_ERROR_READPRNG; /* 10 bytes for testing */
+   if (compare_testvector(out, 10, t1, sizeof(t1), "CHACHA-PRNG", 1))      return CRYPT_FAIL_TESTVECTOR;
+   if (chacha20_prng_read(out, 500, &st) != 500)                           return CRYPT_ERROR_READPRNG; /* skip 500 bytes */
+   /* add entropy to already initialized prng */
+   if ((err = chacha20_prng_add_entropy(en, sizeof(en), &st)) != CRYPT_OK) return err;
+   if (chacha20_prng_read(out, 500, &st) != 500)                           return CRYPT_ERROR_READPRNG; /* skip 500 bytes */
+   if ((err = chacha20_prng_export(dmp, &dmplen, &st)) != CRYPT_OK)        return err;
+   if (chacha20_prng_read(out, 500, &st) != 500)                           return CRYPT_ERROR_READPRNG; /* skip 500 bytes */
+   if (chacha20_prng_read(out, 10, &st) != 10)                             return CRYPT_ERROR_READPRNG; /* 10 bytes for testing */
+   if (compare_testvector(out, 10, t2, sizeof(t2), "CHACHA-PRNG", 2))      return CRYPT_FAIL_TESTVECTOR;
+   if ((err = chacha20_prng_done(&st)) != CRYPT_OK)                        return err;
+   if ((err = chacha20_prng_import(dmp, dmplen, &st)) != CRYPT_OK)         return err;
+   if ((err = chacha20_prng_ready(&st)) != CRYPT_OK)                       return err;
+   if (chacha20_prng_read(out, 500, &st) != 500)                           return CRYPT_ERROR_READPRNG; /* skip 500 bytes */
+   if (chacha20_prng_read(out, 10, &st) != 10)                             return CRYPT_ERROR_READPRNG; /* 10 bytes for testing */
+   if (compare_testvector(out, 10, t3, sizeof(t3), "CHACHA-PRNG", 3))      return CRYPT_FAIL_TESTVECTOR;
+   if ((err = chacha20_prng_done(&st)) != CRYPT_OK)                        return err;
+
+   return CRYPT_OK;
+#endif
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/prngs/fortuna.c b/libtomcrypt/src/prngs/fortuna.c
new file mode 100644 (file)
index 0000000..1f07233
--- /dev/null
@@ -0,0 +1,498 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file fortuna.c
+  Fortuna PRNG, Tom St Denis
+*/
+
+/* Implementation of Fortuna by Tom St Denis
+
+We deviate slightly here for reasons of simplicity [and to fit in the API].  First all "sources"
+in the AddEntropy function are fixed to 0.  Second since no reliable timer is provided
+we reseed automatically when len(pool0) >= 64 or every LTC_FORTUNA_WD calls to the read function */
+
+#ifdef LTC_FORTUNA
+
+/* requries LTC_SHA256 and AES  */
+#if !(defined(LTC_RIJNDAEL) && defined(LTC_SHA256))
+   #error LTC_FORTUNA requires LTC_SHA256 and LTC_RIJNDAEL (AES)
+#endif
+
+#ifndef LTC_FORTUNA_POOLS
+   #warning LTC_FORTUNA_POOLS was not previously defined (old headers?)
+   #define LTC_FORTUNA_POOLS 32
+#endif
+
+#if LTC_FORTUNA_POOLS < 4 || LTC_FORTUNA_POOLS > 32
+   #error LTC_FORTUNA_POOLS must be in [4..32]
+#endif
+
+const struct ltc_prng_descriptor fortuna_desc = {
+    "fortuna",
+    (32 * LTC_FORTUNA_POOLS), /* default: 1024 */
+    &fortuna_start,
+    &fortuna_add_entropy,
+    &fortuna_ready,
+    &fortuna_read,
+    &fortuna_done,
+    &fortuna_export,
+    &fortuna_import,
+    &fortuna_test
+};
+
+/* update the IV */
+static void _fortuna_update_iv(prng_state *prng)
+{
+   int            x;
+   unsigned char *IV;
+   /* update IV */
+   IV = prng->fortuna.IV;
+   for (x = 0; x < 16; x++) {
+      IV[x] = (IV[x] + 1) & 255;
+      if (IV[x] != 0) break;
+   }
+}
+
+/* reseed the PRNG */
+static int _fortuna_reseed(prng_state *prng)
+{
+   unsigned char tmp[MAXBLOCKSIZE];
+   hash_state    md;
+   ulong64       reset_cnt;
+   int           err, x;
+
+
+   /* new K == LTC_SHA256(K || s) where s == LTC_SHA256(P0) || LTC_SHA256(P1) ... */
+   sha256_init(&md);
+   if ((err = sha256_process(&md, prng->fortuna.K, 32)) != CRYPT_OK) {
+      sha256_done(&md, tmp);
+      return err;
+   }
+
+   reset_cnt = prng->fortuna.reset_cnt + 1;
+
+   for (x = 0; x < LTC_FORTUNA_POOLS; x++) {
+       if (x == 0 || ((reset_cnt >> (x-1)) & 1) == 0) {
+          /* terminate this hash */
+          if ((err = sha256_done(&prng->fortuna.pool[x], tmp)) != CRYPT_OK) {
+             sha256_done(&md, tmp);
+             return err;
+          }
+          /* add it to the string */
+          if ((err = sha256_process(&md, tmp, 32)) != CRYPT_OK) {
+             sha256_done(&md, tmp);
+             return err;
+          }
+          /* reset this pool */
+          if ((err = sha256_init(&prng->fortuna.pool[x])) != CRYPT_OK) {
+             sha256_done(&md, tmp);
+             return err;
+          }
+       } else {
+          break;
+       }
+   }
+
+   /* finish key */
+   if ((err = sha256_done(&md, prng->fortuna.K)) != CRYPT_OK) {
+      return err;
+   }
+   if ((err = rijndael_setup(prng->fortuna.K, 32, 0, &prng->fortuna.skey)) != CRYPT_OK) {
+      return err;
+   }
+   _fortuna_update_iv(prng);
+
+   /* reset/update internals */
+   prng->fortuna.pool0_len = 0;
+   prng->fortuna.wd        = 0;
+   prng->fortuna.reset_cnt = reset_cnt;
+
+
+#ifdef LTC_CLEAN_STACK
+   zeromem(&md, sizeof(md));
+   zeromem(tmp, sizeof(tmp));
+#endif
+
+   return CRYPT_OK;
+}
+
+/**
+  "Update Seed File"-compliant update of K
+
+  @param in       The PRNG state
+  @param inlen    Size of the state
+  @param prng     The PRNG to import
+  @return CRYPT_OK if successful
+*/
+static int _fortuna_update_seed(const unsigned char *in, unsigned long inlen, prng_state *prng)
+{
+   int           err;
+   unsigned char tmp[MAXBLOCKSIZE];
+   hash_state    md;
+
+   LTC_MUTEX_LOCK(&prng->lock);
+   /* new K = LTC_SHA256(K || in) */
+   sha256_init(&md);
+   if ((err = sha256_process(&md, prng->fortuna.K, 32)) != CRYPT_OK) {
+      sha256_done(&md, tmp);
+      goto LBL_UNLOCK;
+   }
+   if ((err = sha256_process(&md, in, inlen)) != CRYPT_OK) {
+      sha256_done(&md, tmp);
+      goto LBL_UNLOCK;
+   }
+   /* finish key */
+   if ((err = sha256_done(&md, prng->fortuna.K)) != CRYPT_OK) {
+      goto LBL_UNLOCK;
+   }
+   _fortuna_update_iv(prng);
+
+LBL_UNLOCK:
+   LTC_MUTEX_UNLOCK(&prng->lock);
+#ifdef LTC_CLEAN_STACK
+   zeromem(&md, sizeof(md));
+#endif
+
+   return err;
+}
+
+/**
+  Start the PRNG
+  @param prng     [out] The PRNG state to initialize
+  @return CRYPT_OK if successful
+*/
+int fortuna_start(prng_state *prng)
+{
+   int err, x, y;
+   unsigned char tmp[MAXBLOCKSIZE];
+
+   LTC_ARGCHK(prng != NULL);
+   prng->ready = 0;
+
+   /* initialize the pools */
+   for (x = 0; x < LTC_FORTUNA_POOLS; x++) {
+       if ((err = sha256_init(&prng->fortuna.pool[x])) != CRYPT_OK) {
+          for (y = 0; y < x; y++) {
+              sha256_done(&prng->fortuna.pool[y], tmp);
+          }
+          return err;
+       }
+   }
+   prng->fortuna.pool_idx = prng->fortuna.pool0_len = prng->fortuna.wd = 0;
+   prng->fortuna.reset_cnt = 0;
+
+   /* reset bufs */
+   zeromem(prng->fortuna.K, 32);
+   if ((err = rijndael_setup(prng->fortuna.K, 32, 0, &prng->fortuna.skey)) != CRYPT_OK) {
+      for (x = 0; x < LTC_FORTUNA_POOLS; x++) {
+          sha256_done(&prng->fortuna.pool[x], tmp);
+      }
+      return err;
+   }
+   zeromem(prng->fortuna.IV, 16);
+
+   LTC_MUTEX_INIT(&prng->lock)
+
+   return CRYPT_OK;
+}
+
+/**
+  Add entropy to the PRNG state
+  @param in       The data to add
+  @param inlen    Length of the data to add
+  @param prng     PRNG state to update
+  @return CRYPT_OK if successful
+*/
+int fortuna_add_entropy(const unsigned char *in, unsigned long inlen, prng_state *prng)
+{
+   unsigned char tmp[2];
+   int           err;
+
+   LTC_ARGCHK(prng != NULL);
+   LTC_ARGCHK(in != NULL);
+   LTC_ARGCHK(inlen > 0);
+
+   /* ensure inlen <= 32 */
+   if (inlen > 32) {
+      inlen = 32;
+   }
+
+   /* add s || length(in) || in to pool[pool_idx] */
+   tmp[0] = 0;
+   tmp[1] = (unsigned char)inlen;
+
+   LTC_MUTEX_LOCK(&prng->lock);
+   if ((err = sha256_process(&prng->fortuna.pool[prng->fortuna.pool_idx], tmp, 2)) != CRYPT_OK) {
+      goto LBL_UNLOCK;
+   }
+   if ((err = sha256_process(&prng->fortuna.pool[prng->fortuna.pool_idx], in, inlen)) != CRYPT_OK) {
+      goto LBL_UNLOCK;
+   }
+   if (prng->fortuna.pool_idx == 0) {
+      prng->fortuna.pool0_len += inlen;
+   }
+   if (++(prng->fortuna.pool_idx) == LTC_FORTUNA_POOLS) {
+      prng->fortuna.pool_idx = 0;
+   }
+   err = CRYPT_OK; /* success */
+
+LBL_UNLOCK:
+   LTC_MUTEX_UNLOCK(&prng->lock);
+   return err;
+}
+
+/**
+  Make the PRNG ready to read from
+  @param prng   The PRNG to make active
+  @return CRYPT_OK if successful
+*/
+int fortuna_ready(prng_state *prng)
+{
+   int err;
+   LTC_ARGCHK(prng != NULL);
+
+   LTC_MUTEX_LOCK(&prng->lock);
+   err = _fortuna_reseed(prng);
+   prng->ready = (err == CRYPT_OK) ? 1 : 0;
+
+   LTC_MUTEX_UNLOCK(&prng->lock);
+   return err;
+}
+
+/**
+  Read from the PRNG
+  @param out      Destination
+  @param outlen   Length of output
+  @param prng     The active PRNG to read from
+  @return Number of octets read
+*/
+unsigned long fortuna_read(unsigned char *out, unsigned long outlen, prng_state *prng)
+{
+   unsigned char tmp[16];
+   unsigned long tlen = 0;
+
+   if (outlen == 0 || prng == NULL || out == NULL) return 0;
+
+   LTC_MUTEX_LOCK(&prng->lock);
+
+   if (!prng->ready) {
+      goto LBL_UNLOCK;
+   }
+
+   /* do we have to reseed? */
+   if ((++prng->fortuna.wd == LTC_FORTUNA_WD) && (prng->fortuna.pool0_len >= 64)) {
+      if (_fortuna_reseed(prng) != CRYPT_OK) {
+         goto LBL_UNLOCK;
+      }
+   }
+
+   /* ensure that one reseed happened before allowing to read */
+   if (prng->fortuna.reset_cnt == 0) {
+      goto LBL_UNLOCK;
+   }
+
+   /* now generate the blocks required */
+   tlen = outlen;
+
+   /* handle whole blocks without the extra XMEMCPY */
+   while (outlen >= 16) {
+      /* encrypt the IV and store it */
+      rijndael_ecb_encrypt(prng->fortuna.IV, out, &prng->fortuna.skey);
+      out += 16;
+      outlen -= 16;
+      _fortuna_update_iv(prng);
+   }
+
+   /* left over bytes? */
+   if (outlen > 0) {
+      rijndael_ecb_encrypt(prng->fortuna.IV, tmp, &prng->fortuna.skey);
+      XMEMCPY(out, tmp, outlen);
+      _fortuna_update_iv(prng);
+   }
+
+   /* generate new key */
+   rijndael_ecb_encrypt(prng->fortuna.IV, prng->fortuna.K   , &prng->fortuna.skey);
+   _fortuna_update_iv(prng);
+
+   rijndael_ecb_encrypt(prng->fortuna.IV, prng->fortuna.K+16, &prng->fortuna.skey);
+   _fortuna_update_iv(prng);
+
+   if (rijndael_setup(prng->fortuna.K, 32, 0, &prng->fortuna.skey) != CRYPT_OK) {
+      tlen = 0;
+   }
+
+LBL_UNLOCK:
+#ifdef LTC_CLEAN_STACK
+   zeromem(tmp, sizeof(tmp));
+#endif
+   LTC_MUTEX_UNLOCK(&prng->lock);
+   return tlen;
+}
+
+/**
+  Terminate the PRNG
+  @param prng   The PRNG to terminate
+  @return CRYPT_OK if successful
+*/
+int fortuna_done(prng_state *prng)
+{
+   int           err, x;
+   unsigned char tmp[32];
+
+   LTC_ARGCHK(prng != NULL);
+
+   LTC_MUTEX_LOCK(&prng->lock);
+   prng->ready = 0;
+
+   /* terminate all the hashes */
+   for (x = 0; x < LTC_FORTUNA_POOLS; x++) {
+       if ((err = sha256_done(&(prng->fortuna.pool[x]), tmp)) != CRYPT_OK) {
+          goto LBL_UNLOCK;
+       }
+   }
+   /* call cipher done when we invent one ;-) */
+   err = CRYPT_OK; /* success */
+
+LBL_UNLOCK:
+#ifdef LTC_CLEAN_STACK
+   zeromem(tmp, sizeof(tmp));
+#endif
+   LTC_MUTEX_UNLOCK(&prng->lock);
+   LTC_MUTEX_DESTROY(&prng->lock);
+   return err;
+}
+
+/**
+  Export the PRNG state
+  @param out       [out] Destination
+  @param outlen    [in/out] Max size and resulting size of the state
+  @param prng      The PRNG to export
+  @return CRYPT_OK if successful
+*/
+int fortuna_export(unsigned char *out, unsigned long *outlen, prng_state *prng)
+{
+   int         x, err;
+   hash_state *md;
+   unsigned long len = fortuna_desc.export_size;
+
+   LTC_ARGCHK(out    != NULL);
+   LTC_ARGCHK(outlen != NULL);
+   LTC_ARGCHK(prng   != NULL);
+
+   LTC_MUTEX_LOCK(&prng->lock);
+
+   if (!prng->ready) {
+      err = CRYPT_ERROR;
+      goto LBL_UNLOCK;
+   }
+
+   /* we'll write bytes for s&g's */
+   if (*outlen < len) {
+      *outlen = len;
+      err = CRYPT_BUFFER_OVERFLOW;
+      goto LBL_UNLOCK;
+   }
+
+   md = XMALLOC(sizeof(hash_state));
+   if (md == NULL) {
+      err = CRYPT_MEM;
+      goto LBL_UNLOCK;
+   }
+
+   /* to emit the state we copy each pool, terminate it then hash it again so
+    * an attacker who sees the state can't determine the current state of the PRNG
+    */
+   for (x = 0; x < LTC_FORTUNA_POOLS; x++) {
+      /* copy the PRNG */
+      XMEMCPY(md, &(prng->fortuna.pool[x]), sizeof(*md));
+
+      /* terminate it */
+      if ((err = sha256_done(md, out+x*32)) != CRYPT_OK) {
+         goto LBL_ERR;
+      }
+
+      /* now hash it */
+      if ((err = sha256_init(md)) != CRYPT_OK) {
+         goto LBL_ERR;
+      }
+      if ((err = sha256_process(md, out+x*32, 32)) != CRYPT_OK) {
+         goto LBL_ERR;
+      }
+      if ((err = sha256_done(md, out+x*32)) != CRYPT_OK) {
+         goto LBL_ERR;
+      }
+   }
+   *outlen = len;
+   err = CRYPT_OK;
+
+LBL_ERR:
+#ifdef LTC_CLEAN_STACK
+   zeromem(md, sizeof(*md));
+#endif
+   XFREE(md);
+LBL_UNLOCK:
+   LTC_MUTEX_UNLOCK(&prng->lock);
+   return err;
+}
+
+/**
+  Import a PRNG state
+  @param in       The PRNG state
+  @param inlen    Size of the state
+  @param prng     The PRNG to import
+  @return CRYPT_OK if successful
+*/
+int fortuna_import(const unsigned char *in, unsigned long inlen, prng_state *prng)
+{
+   int           err;
+
+   LTC_ARGCHK(in    != NULL);
+   LTC_ARGCHK(prng  != NULL);
+
+   if (inlen < (unsigned long)fortuna_desc.export_size) {
+      return CRYPT_INVALID_ARG;
+   }
+
+   if ((err = fortuna_start(prng)) != CRYPT_OK) {
+      return err;
+   }
+
+   if ((err = _fortuna_update_seed(in, inlen, prng)) != CRYPT_OK) {
+      return err;
+   }
+
+   return err;
+}
+
+/**
+  PRNG self-test
+  @return CRYPT_OK if successful, CRYPT_NOP if self-testing has been disabled
+*/
+int fortuna_test(void)
+{
+#ifndef LTC_TEST
+   return CRYPT_NOP;
+#else
+   int err;
+
+   if ((err = sha256_test()) != CRYPT_OK) {
+      return err;
+   }
+   return rijndael_test();
+#endif
+}
+
+#endif
+
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/prngs/rc4.c b/libtomcrypt/src/prngs/rc4.c
new file mode 100644 (file)
index 0000000..e2aa921
--- /dev/null
@@ -0,0 +1,250 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file prngs/rc4.c
+  RC4 PRNG, Tom St Denis
+*/
+
+#ifdef LTC_RC4
+
+const struct ltc_prng_descriptor rc4_desc =
+{
+   "rc4",
+   32,
+   &rc4_start,
+   &rc4_add_entropy,
+   &rc4_ready,
+   &rc4_read,
+   &rc4_done,
+   &rc4_export,
+   &rc4_import,
+   &rc4_test
+};
+
+/**
+  Start the PRNG
+  @param prng     [out] The PRNG state to initialize
+  @return CRYPT_OK if successful
+*/
+int rc4_start(prng_state *prng)
+{
+   LTC_ARGCHK(prng != NULL);
+   prng->ready = 0;
+   /* set entropy (key) size to zero */
+   prng->rc4.s.x = 0;
+   /* clear entropy (key) buffer */
+   XMEMSET(&prng->rc4.s.buf, 0, sizeof(prng->rc4.s.buf));
+   LTC_MUTEX_INIT(&prng->lock)
+   return CRYPT_OK;
+}
+
+/**
+  Add entropy to the PRNG state
+  @param in       The data to add
+  @param inlen    Length of the data to add
+  @param prng     PRNG state to update
+  @return CRYPT_OK if successful
+*/
+int rc4_add_entropy(const unsigned char *in, unsigned long inlen, prng_state *prng)
+{
+   unsigned char buf[256];
+   unsigned long i;
+   int err;
+
+   LTC_ARGCHK(prng != NULL);
+   LTC_ARGCHK(in != NULL);
+   LTC_ARGCHK(inlen > 0);
+
+   LTC_MUTEX_LOCK(&prng->lock);
+   if (prng->ready) {
+      /* rc4_ready() was already called, do "rekey" operation */
+      if ((err = rc4_stream_keystream(&prng->rc4.s, buf, sizeof(buf))) != CRYPT_OK) goto LBL_UNLOCK;
+      for(i = 0; i < inlen; i++) buf[i % sizeof(buf)] ^= in[i];
+      /* initialize RC4 */
+      if ((err = rc4_stream_setup(&prng->rc4.s, buf, sizeof(buf))) != CRYPT_OK) goto LBL_UNLOCK;
+      /* drop first 3072 bytes - https://en.wikipedia.org/wiki/RC4#Fluhrer.2C_Mantin_and_Shamir_attack */
+      for (i = 0; i < 12; i++) rc4_stream_keystream(&prng->rc4.s, buf, sizeof(buf));
+      zeromem(buf, sizeof(buf));
+   }
+   else {
+      /* rc4_ready() was not called yet, add entropy to the buffer */
+      while (inlen--) prng->rc4.s.buf[prng->rc4.s.x++ % sizeof(prng->rc4.s.buf)] ^= *in++;
+   }
+   err = CRYPT_OK;
+LBL_UNLOCK:
+   LTC_MUTEX_UNLOCK(&prng->lock);
+   return err;
+}
+
+/**
+  Make the PRNG ready to read from
+  @param prng   The PRNG to make active
+  @return CRYPT_OK if successful
+*/
+int rc4_ready(prng_state *prng)
+{
+   unsigned char buf[256] = { 0 };
+   unsigned long len;
+   int err, i;
+
+   LTC_ARGCHK(prng != NULL);
+
+   LTC_MUTEX_LOCK(&prng->lock);
+   if (prng->ready) { err = CRYPT_OK; goto LBL_UNLOCK; }
+   XMEMCPY(buf, prng->rc4.s.buf, sizeof(buf));
+   /* initialize RC4 */
+   len = MIN(prng->rc4.s.x, 256); /* TODO: we can perhaps always use all 256 bytes */
+   if ((err = rc4_stream_setup(&prng->rc4.s, buf, len)) != CRYPT_OK) goto LBL_UNLOCK;
+   /* drop first 3072 bytes - https://en.wikipedia.org/wiki/RC4#Fluhrer.2C_Mantin_and_Shamir_attack */
+   for (i = 0; i < 12; i++) rc4_stream_keystream(&prng->rc4.s, buf, sizeof(buf));
+   prng->ready = 1;
+LBL_UNLOCK:
+   LTC_MUTEX_UNLOCK(&prng->lock);
+   return err;
+}
+
+/**
+  Read from the PRNG
+  @param out      Destination
+  @param outlen   Length of output
+  @param prng     The active PRNG to read from
+  @return Number of octets read
+*/
+unsigned long rc4_read(unsigned char *out, unsigned long outlen, prng_state *prng)
+{
+   if (outlen == 0 || prng == NULL || out == NULL) return 0;
+   LTC_MUTEX_LOCK(&prng->lock);
+   if (!prng->ready) { outlen = 0; goto LBL_UNLOCK; }
+   if (rc4_stream_keystream(&prng->rc4.s, out, outlen) != CRYPT_OK) outlen = 0;
+LBL_UNLOCK:
+   LTC_MUTEX_UNLOCK(&prng->lock);
+   return outlen;
+}
+
+/**
+  Terminate the PRNG
+  @param prng   The PRNG to terminate
+  @return CRYPT_OK if successful
+*/
+int rc4_done(prng_state *prng)
+{
+   int err;
+   LTC_ARGCHK(prng != NULL);
+   LTC_MUTEX_LOCK(&prng->lock);
+   prng->ready = 0;
+   err = rc4_stream_done(&prng->rc4.s);
+   LTC_MUTEX_UNLOCK(&prng->lock);
+   LTC_MUTEX_DESTROY(&prng->lock);
+   return err;
+}
+
+/**
+  Export the PRNG state
+  @param out       [out] Destination
+  @param outlen    [in/out] Max size and resulting size of the state
+  @param prng      The PRNG to export
+  @return CRYPT_OK if successful
+*/
+int rc4_export(unsigned char *out, unsigned long *outlen, prng_state *prng)
+{
+   unsigned long len = rc4_desc.export_size;
+
+   LTC_ARGCHK(prng   != NULL);
+   LTC_ARGCHK(out    != NULL);
+   LTC_ARGCHK(outlen != NULL);
+
+   if (*outlen < len) {
+      *outlen = len;
+      return CRYPT_BUFFER_OVERFLOW;
+   }
+
+   if (rc4_read(out, len, prng) != len) {
+      return CRYPT_ERROR_READPRNG;
+   }
+
+   *outlen = len;
+   return CRYPT_OK;
+}
+
+/**
+  Import a PRNG state
+  @param in       The PRNG state
+  @param inlen    Size of the state
+  @param prng     The PRNG to import
+  @return CRYPT_OK if successful
+*/
+int rc4_import(const unsigned char *in, unsigned long inlen, prng_state *prng)
+{
+   int err;
+
+   LTC_ARGCHK(prng != NULL);
+   LTC_ARGCHK(in   != NULL);
+   if (inlen < (unsigned long)rc4_desc.export_size) return CRYPT_INVALID_ARG;
+
+   if ((err = rc4_start(prng)) != CRYPT_OK)                  return err;
+   if ((err = rc4_add_entropy(in, inlen, prng)) != CRYPT_OK) return err;
+   return CRYPT_OK;
+}
+
+/**
+  PRNG self-test
+  @return CRYPT_OK if successful, CRYPT_NOP if self-testing has been disabled
+*/
+int rc4_test(void)
+{
+#ifndef LTC_TEST
+   return CRYPT_NOP;
+#else
+   prng_state st;
+   unsigned char en[] = { 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, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
+                          0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32 };
+   unsigned char dmp[500];
+   unsigned long dmplen = sizeof(dmp);
+   unsigned char out[1000];
+   unsigned char t1[] = { 0xE0, 0x4D, 0x9A, 0xF6, 0xA8, 0x9D, 0x77, 0x53, 0xAE, 0x09 };
+   unsigned char t2[] = { 0xEF, 0x80, 0xA2, 0xE6, 0x50, 0x91, 0xF3, 0x17, 0x4A, 0x8A };
+   unsigned char t3[] = { 0x4B, 0xD6, 0x5C, 0x67, 0x99, 0x03, 0x56, 0x12, 0x80, 0x48 };
+   int err;
+
+   if ((err = rc4_start(&st)) != CRYPT_OK)                         return err;
+   /* add entropy to uninitialized prng */
+   if ((err = rc4_add_entropy(en, sizeof(en), &st)) != CRYPT_OK)   return err;
+   if ((err = rc4_ready(&st)) != CRYPT_OK)                         return err;
+   if (rc4_read(out, 10, &st) != 10)                               return CRYPT_ERROR_READPRNG; /* 10 bytes for testing */
+   if (compare_testvector(out, 10, t1, sizeof(t1), "RC4-PRNG", 1)) return CRYPT_FAIL_TESTVECTOR;
+   if (rc4_read(out, 500, &st) != 500)                             return CRYPT_ERROR_READPRNG; /* skip 500 bytes */
+   /* add entropy to already initialized prng */
+   if ((err = rc4_add_entropy(en, sizeof(en), &st)) != CRYPT_OK)   return err;
+   if (rc4_read(out, 500, &st) != 500)                             return CRYPT_ERROR_READPRNG; /* skip 500 bytes */
+   if ((err = rc4_export(dmp, &dmplen, &st)) != CRYPT_OK)          return err;
+   if (rc4_read(out, 500, &st) != 500)                             return CRYPT_ERROR_READPRNG; /* skip 500 bytes */
+   if (rc4_read(out, 10, &st) != 10)                               return CRYPT_ERROR_READPRNG; /* 10 bytes for testing */
+   if (compare_testvector(out, 10, t2, sizeof(t2), "RC4-PRNG", 2)) return CRYPT_FAIL_TESTVECTOR;
+   if ((err = rc4_done(&st)) != CRYPT_OK)                          return err;
+   if ((err = rc4_import(dmp, dmplen, &st)) != CRYPT_OK)           return err;
+   if ((err = rc4_ready(&st)) != CRYPT_OK)                         return err;
+   if (rc4_read(out, 500, &st) != 500)                             return CRYPT_ERROR_READPRNG; /* skip 500 bytes */
+   if (rc4_read(out, 10, &st) != 10)                               return CRYPT_ERROR_READPRNG; /* 10 bytes for testing */
+   if (compare_testvector(out, 10, t3, sizeof(t3), "RC4-PRNG", 3)) return CRYPT_FAIL_TESTVECTOR;
+   if ((err = rc4_done(&st)) != CRYPT_OK)                          return err;
+
+   return CRYPT_OK;
+#endif
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/prngs/rng_get_bytes.c b/libtomcrypt/src/prngs/rng_get_bytes.c
new file mode 100644 (file)
index 0000000..4e9a063
--- /dev/null
@@ -0,0 +1,159 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+#ifdef LTC_RNG_GET_BYTES
+/**
+   @file rng_get_bytes.c
+   portable way to get secure random bits to feed a PRNG (Tom St Denis)
+*/
+
+#if defined(LTC_DEVRANDOM) && !defined(_WIN32)
+/* on *NIX read /dev/random */
+static unsigned long _rng_nix(unsigned char *buf, unsigned long len,
+                             void (*callback)(void))
+{
+#ifdef LTC_NO_FILE
+    LTC_UNUSED_PARAM(callback);
+    LTC_UNUSED_PARAM(buf);
+    LTC_UNUSED_PARAM(len);
+    return 0;
+#else
+    FILE *f;
+    unsigned long x;
+    LTC_UNUSED_PARAM(callback);
+#ifdef LTC_TRY_URANDOM_FIRST
+    f = fopen("/dev/urandom", "rb");
+    if (f == NULL)
+#endif /* LTC_TRY_URANDOM_FIRST */
+       f = fopen("/dev/random", "rb");
+
+    if (f == NULL) {
+       return 0;
+    }
+
+    /* disable buffering */
+    if (setvbuf(f, NULL, _IONBF, 0) != 0) {
+       fclose(f);
+       return 0;
+    }
+
+    x = (unsigned long)fread(buf, 1, (size_t)len, f);
+    fclose(f);
+    return x;
+#endif /* LTC_NO_FILE */
+}
+
+#endif /* LTC_DEVRANDOM */
+
+#if !defined(_WIN32_WCE)
+
+#define ANSI_RNG
+
+static unsigned long _rng_ansic(unsigned char *buf, unsigned long len,
+                               void (*callback)(void))
+{
+   clock_t t1;
+   int l, acc, bits, a, b;
+
+   l = len;
+   bits = 8;
+   acc  = a = b = 0;
+   while (len--) {
+       if (callback != NULL) callback();
+       while (bits--) {
+          do {
+             t1 = XCLOCK(); while (t1 == XCLOCK()) a ^= 1;
+             t1 = XCLOCK(); while (t1 == XCLOCK()) b ^= 1;
+          } while (a == b);
+          acc = (acc << 1) | a;
+       }
+       *buf++ = acc;
+       acc  = 0;
+       bits = 8;
+   }
+   return l;
+}
+
+#endif
+
+/* Try the Microsoft CSP */
+#if defined(_WIN32) || defined(_WIN32_WCE)
+#ifndef _WIN32_WINNT
+  #define _WIN32_WINNT 0x0400
+#endif
+#ifdef _WIN32_WCE
+   #define UNDER_CE
+   #define ARM
+#endif
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <wincrypt.h>
+
+static unsigned long _rng_win32(unsigned char *buf, unsigned long len,
+                               void (*callback)(void))
+{
+   HCRYPTPROV hProv = 0;
+   LTC_UNUSED_PARAM(callback);
+   if (!CryptAcquireContext(&hProv, NULL, MS_DEF_PROV, PROV_RSA_FULL,
+                            (CRYPT_VERIFYCONTEXT | CRYPT_MACHINE_KEYSET)) &&
+       !CryptAcquireContext (&hProv, NULL, MS_DEF_PROV, PROV_RSA_FULL,
+                            CRYPT_VERIFYCONTEXT | CRYPT_MACHINE_KEYSET | CRYPT_NEWKEYSET))
+      return 0;
+
+   if (CryptGenRandom(hProv, len, buf) == TRUE) {
+      CryptReleaseContext(hProv, 0);
+      return len;
+   } else {
+      CryptReleaseContext(hProv, 0);
+      return 0;
+   }
+}
+
+#endif /* WIN32 */
+
+/**
+  Read the system RNG
+  @param out       Destination
+  @param outlen    Length desired (octets)
+  @param callback  Pointer to void function to act as "callback" when RNG is slow.  This can be NULL
+  @return Number of octets read
+*/
+unsigned long rng_get_bytes(unsigned char *out, unsigned long outlen,
+                            void (*callback)(void))
+{
+   unsigned long x;
+
+   LTC_ARGCHK(out != NULL);
+
+#ifdef LTC_PRNG_ENABLE_LTC_RNG
+   if (ltc_rng) {
+      x = ltc_rng(out, outlen, callback);
+      if (x != 0) {
+         return x;
+      }
+   }
+#endif
+
+#if defined(_WIN32) || defined(_WIN32_WCE)
+   x = _rng_win32(out, outlen, callback); if (x != 0) { return x; }
+#elif defined(LTC_DEVRANDOM)
+   x = _rng_nix(out, outlen, callback);   if (x != 0) { return x; }
+#endif
+#ifdef ANSI_RNG
+   x = _rng_ansic(out, outlen, callback); if (x != 0) { return x; }
+#endif
+   return 0;
+}
+#endif /* #ifdef LTC_RNG_GET_BYTES */
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/prngs/rng_make_prng.c b/libtomcrypt/src/prngs/rng_make_prng.c
new file mode 100644 (file)
index 0000000..b01c325
--- /dev/null
@@ -0,0 +1,69 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+#ifdef LTC_RNG_MAKE_PRNG
+/**
+  @file rng_make_prng.c
+  portable way to get secure random bits to feed a PRNG  (Tom St Denis)
+*/
+
+/**
+  Create a PRNG from a RNG
+  @param bits     Number of bits of entropy desired (64 ... 1024)
+  @param wprng    Index of which PRNG to setup
+  @param prng     [out] PRNG state to initialize
+  @param callback A pointer to a void function for when the RNG is slow, this can be NULL
+  @return CRYPT_OK if successful
+*/
+int rng_make_prng(int bits, int wprng, prng_state *prng,
+                  void (*callback)(void))
+{
+   unsigned char buf[256];
+   int err;
+
+   LTC_ARGCHK(prng != NULL);
+
+   /* check parameter */
+   if ((err = prng_is_valid(wprng)) != CRYPT_OK) {
+      return err;
+   }
+
+   if (bits < 64 || bits > 1024) {
+      return CRYPT_INVALID_PRNGSIZE;
+   }
+
+   if ((err = prng_descriptor[wprng].start(prng)) != CRYPT_OK) {
+      return err;
+   }
+
+   bits = ((bits/8)+((bits&7)!=0?1:0)) * 2;
+   if (rng_get_bytes(buf, (unsigned long)bits, callback) != (unsigned long)bits) {
+      return CRYPT_ERROR_READPRNG;
+   }
+
+   if ((err = prng_descriptor[wprng].add_entropy(buf, (unsigned long)bits, prng)) != CRYPT_OK) {
+      return err;
+   }
+
+   if ((err = prng_descriptor[wprng].ready(prng)) != CRYPT_OK) {
+      return err;
+   }
+
+   #ifdef LTC_CLEAN_STACK
+      zeromem(buf, sizeof(buf));
+   #endif
+   return CRYPT_OK;
+}
+#endif /* #ifdef LTC_RNG_MAKE_PRNG */
+
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/prngs/sober128.c b/libtomcrypt/src/prngs/sober128.c
new file mode 100644 (file)
index 0000000..275920c
--- /dev/null
@@ -0,0 +1,249 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+#include "tomcrypt.h"
+
+/**
+ @file prngs/sober128.c
+ Implementation of SOBER-128 by Tom St Denis.
+ Based on s128fast.c reference code supplied by Greg Rose of QUALCOMM.
+*/
+
+#ifdef LTC_SOBER128
+
+const struct ltc_prng_descriptor sober128_desc =
+{
+   "sober128",
+   40,
+   &sober128_start,
+   &sober128_add_entropy,
+   &sober128_ready,
+   &sober128_read,
+   &sober128_done,
+   &sober128_export,
+   &sober128_import,
+   &sober128_test
+};
+
+/**
+  Start the PRNG
+  @param prng     [out] The PRNG state to initialize
+  @return CRYPT_OK if successful
+*/
+int sober128_start(prng_state *prng)
+{
+   LTC_ARGCHK(prng != NULL);
+   prng->ready = 0;
+   XMEMSET(&prng->sober128.ent, 0, sizeof(prng->sober128.ent));
+   prng->sober128.idx = 0;
+   LTC_MUTEX_INIT(&prng->lock)
+   return CRYPT_OK;
+}
+
+/**
+  Add entropy to the PRNG state
+  @param in       The data to add
+  @param inlen    Length of the data to add
+  @param prng     PRNG state to update
+  @return CRYPT_OK if successful
+*/
+int sober128_add_entropy(const unsigned char *in, unsigned long inlen, prng_state *prng)
+{
+   unsigned char buf[40];
+   unsigned long i;
+   int err;
+
+   LTC_ARGCHK(prng != NULL);
+   LTC_ARGCHK(in != NULL);
+   LTC_ARGCHK(inlen > 0);
+
+   LTC_MUTEX_LOCK(&prng->lock);
+   if (prng->ready) {
+      /* sober128_ready() was already called, do "rekey" operation */
+      if ((err = sober128_stream_keystream(&prng->sober128.s, buf, sizeof(buf))) != CRYPT_OK) goto LBL_UNLOCK;
+      for(i = 0; i < inlen; i++) buf[i % sizeof(buf)] ^= in[i];
+      /* key 32 bytes, 20 rounds */
+      if ((err = sober128_stream_setup(&prng->sober128.s, buf, 32)) != CRYPT_OK)     goto LBL_UNLOCK;
+      /* iv 8 bytes */
+      if ((err = sober128_stream_setiv(&prng->sober128.s, buf + 32, 8)) != CRYPT_OK) goto LBL_UNLOCK;
+      /* clear KEY + IV */
+      zeromem(buf, sizeof(buf));
+   }
+   else {
+      /* sober128_ready() was not called yet, add entropy to ent buffer */
+      while (inlen--) prng->sober128.ent[prng->sober128.idx++ % sizeof(prng->sober128.ent)] ^= *in++;
+   }
+   err = CRYPT_OK;
+LBL_UNLOCK:
+   LTC_MUTEX_UNLOCK(&prng->lock);
+   return err;
+}
+
+/**
+  Make the PRNG ready to read from
+  @param prng   The PRNG to make active
+  @return CRYPT_OK if successful
+*/
+int sober128_ready(prng_state *prng)
+{
+   int err;
+
+   LTC_ARGCHK(prng != NULL);
+
+   LTC_MUTEX_LOCK(&prng->lock);
+   if (prng->ready)                                                            { err = CRYPT_OK; goto LBL_UNLOCK; }
+   /* key 32 bytes, 20 rounds */
+   if ((err = sober128_stream_setup(&prng->sober128.s, prng->sober128.ent, 32)) != CRYPT_OK)     goto LBL_UNLOCK;
+   /* iv 8 bytes */
+   if ((err = sober128_stream_setiv(&prng->sober128.s, prng->sober128.ent + 32, 8)) != CRYPT_OK) goto LBL_UNLOCK;
+   XMEMSET(&prng->sober128.ent, 0, sizeof(prng->sober128.ent));
+   prng->sober128.idx = 0;
+   prng->ready = 1;
+LBL_UNLOCK:
+   LTC_MUTEX_UNLOCK(&prng->lock);
+   return err;
+}
+
+/**
+  Read from the PRNG
+  @param out      Destination
+  @param outlen   Length of output
+  @param prng     The active PRNG to read from
+  @return Number of octets read
+*/
+unsigned long sober128_read(unsigned char *out, unsigned long outlen, prng_state *prng)
+{
+   if (outlen == 0 || prng == NULL || out == NULL) return 0;
+   LTC_MUTEX_LOCK(&prng->lock);
+   if (!prng->ready) { outlen = 0; goto LBL_UNLOCK; }
+   if (sober128_stream_keystream(&prng->sober128.s, out, outlen) != CRYPT_OK) outlen = 0;
+LBL_UNLOCK:
+   LTC_MUTEX_UNLOCK(&prng->lock);
+   return outlen;
+}
+
+/**
+  Terminate the PRNG
+  @param prng   The PRNG to terminate
+  @return CRYPT_OK if successful
+*/
+int sober128_done(prng_state *prng)
+{
+   int err;
+   LTC_ARGCHK(prng != NULL);
+   LTC_MUTEX_LOCK(&prng->lock);
+   prng->ready = 0;
+   err = sober128_stream_done(&prng->sober128.s);
+   LTC_MUTEX_UNLOCK(&prng->lock);
+   LTC_MUTEX_DESTROY(&prng->lock);
+   return err;
+}
+
+/**
+  Export the PRNG state
+  @param out       [out] Destination
+  @param outlen    [in/out] Max size and resulting size of the state
+  @param prng      The PRNG to export
+  @return CRYPT_OK if successful
+*/
+int sober128_export(unsigned char *out, unsigned long *outlen, prng_state *prng)
+{
+   unsigned long len = sober128_desc.export_size;
+
+   LTC_ARGCHK(prng   != NULL);
+   LTC_ARGCHK(out    != NULL);
+   LTC_ARGCHK(outlen != NULL);
+
+   if (*outlen < len) {
+      *outlen = len;
+      return CRYPT_BUFFER_OVERFLOW;
+   }
+
+   if (sober128_read(out, len, prng) != len) {
+      return CRYPT_ERROR_READPRNG;
+   }
+
+   *outlen = len;
+   return CRYPT_OK;
+}
+
+/**
+  Import a PRNG state
+  @param in       The PRNG state
+  @param inlen    Size of the state
+  @param prng     The PRNG to import
+  @return CRYPT_OK if successful
+*/
+int sober128_import(const unsigned char *in, unsigned long inlen, prng_state *prng)
+{
+   int err;
+
+   LTC_ARGCHK(prng != NULL);
+   LTC_ARGCHK(in   != NULL);
+   if (inlen < (unsigned long)sober128_desc.export_size) return CRYPT_INVALID_ARG;
+
+   if ((err = sober128_start(prng)) != CRYPT_OK) return err;
+   if ((err = sober128_add_entropy(in, inlen, prng)) != CRYPT_OK) return err;
+   return CRYPT_OK;
+}
+
+/**
+  PRNG self-test
+  @return CRYPT_OK if successful, CRYPT_NOP if self-testing has been disabled
+*/
+int sober128_test(void)
+{
+#ifndef LTC_TEST
+   return CRYPT_NOP;
+#else
+   prng_state st;
+   unsigned char en[] = { 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, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
+                          0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32 };
+   unsigned char dmp[300];
+   unsigned long dmplen = sizeof(dmp);
+   unsigned char out[500];
+   unsigned char t1[] = { 0x31, 0x82, 0xA7, 0xA5, 0x8B, 0xD7, 0xCB, 0x39, 0x86, 0x1A };
+   unsigned char t2[] = { 0x6B, 0x43, 0x9E, 0xBC, 0xE7, 0x62, 0x9B, 0xE6, 0x9B, 0x83 };
+   unsigned char t3[] = { 0x4A, 0x0E, 0x6C, 0xC1, 0xCF, 0xB4, 0x73, 0x49, 0x99, 0x05 };
+   int err;
+
+   if ((err = sober128_start(&st)) != CRYPT_OK)                         return err;
+   /* add entropy to uninitialized prng */
+   if ((err = sober128_add_entropy(en, sizeof(en), &st)) != CRYPT_OK)   return err;
+   if ((err = sober128_ready(&st)) != CRYPT_OK)                         return err;
+   if (sober128_read(out, 10, &st) != 10)                               return CRYPT_ERROR_READPRNG; /* 10 bytes for testing */
+   if (compare_testvector(out, 10, t1, sizeof(t1), "SOBER128-PRNG", 1)) return CRYPT_FAIL_TESTVECTOR;
+   if (sober128_read(out, 500, &st) != 500)                             return CRYPT_ERROR_READPRNG; /* skip 500 bytes */
+   /* add entropy to already initialized prng */
+   if ((err = sober128_add_entropy(en, sizeof(en), &st)) != CRYPT_OK)   return err;
+   if (sober128_read(out, 500, &st) != 500)                             return CRYPT_ERROR_READPRNG; /* skip 500 bytes */
+   if ((err = sober128_export(dmp, &dmplen, &st)) != CRYPT_OK)          return err;
+   if (sober128_read(out, 500, &st) != 500)                             return CRYPT_ERROR_READPRNG; /* skip 500 bytes */
+   if (sober128_read(out, 10, &st) != 10)                               return CRYPT_ERROR_READPRNG; /* 10 bytes for testing */
+   if (compare_testvector(out, 10, t2, sizeof(t2), "SOBER128-PRNG", 2)) return CRYPT_FAIL_TESTVECTOR;
+   if ((err = sober128_done(&st)) != CRYPT_OK)                          return err;
+   if ((err = sober128_import(dmp, dmplen, &st)) != CRYPT_OK)           return err;
+   if ((err = sober128_ready(&st)) != CRYPT_OK)                         return err;
+   if (sober128_read(out, 500, &st) != 500)                             return CRYPT_ERROR_READPRNG; /* skip 500 bytes */
+   if (sober128_read(out, 10, &st) != 10)                               return CRYPT_ERROR_READPRNG; /* 10 bytes for testing */
+   if (compare_testvector(out, 10, t3, sizeof(t3), "SOBER128-PRNG", 3)) return CRYPT_FAIL_TESTVECTOR;
+   if ((err = sober128_done(&st)) != CRYPT_OK)                          return err;
+
+   return CRYPT_OK;
+#endif
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/prngs/sprng.c b/libtomcrypt/src/prngs/sprng.c
new file mode 100644 (file)
index 0000000..b74d8da
--- /dev/null
@@ -0,0 +1,161 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+   @file sprng.c
+   Secure PRNG, Tom St Denis
+*/
+
+/* A secure PRNG using the RNG functions.  Basically this is a
+ * wrapper that allows you to use a secure RNG as a PRNG
+ * in the various other functions.
+ */
+
+#ifdef LTC_SPRNG
+
+const struct ltc_prng_descriptor sprng_desc =
+{
+    "sprng", 0,
+    &sprng_start,
+    &sprng_add_entropy,
+    &sprng_ready,
+    &sprng_read,
+    &sprng_done,
+    &sprng_export,
+    &sprng_import,
+    &sprng_test
+};
+
+/**
+  Start the PRNG
+  @param prng     [out] The PRNG state to initialize
+  @return CRYPT_OK if successful
+*/
+int sprng_start(prng_state *prng)
+{
+   LTC_UNUSED_PARAM(prng);
+   return CRYPT_OK;
+}
+
+/**
+  Add entropy to the PRNG state
+  @param in       The data to add
+  @param inlen    Length of the data to add
+  @param prng     PRNG state to update
+  @return CRYPT_OK if successful
+*/
+int sprng_add_entropy(const unsigned char *in, unsigned long inlen, prng_state *prng)
+{
+   LTC_UNUSED_PARAM(in);
+   LTC_UNUSED_PARAM(inlen);
+   LTC_UNUSED_PARAM(prng);
+   return CRYPT_OK;
+}
+
+/**
+  Make the PRNG ready to read from
+  @param prng   The PRNG to make active
+  @return CRYPT_OK if successful
+*/
+int sprng_ready(prng_state *prng)
+{
+   LTC_UNUSED_PARAM(prng);
+   return CRYPT_OK;
+}
+
+/**
+  Read from the PRNG
+  @param out      Destination
+  @param outlen   Length of output
+  @param prng     The active PRNG to read from
+  @return Number of octets read
+*/
+unsigned long sprng_read(unsigned char *out, unsigned long outlen, prng_state *prng)
+{
+   LTC_ARGCHK(out != NULL);
+   LTC_UNUSED_PARAM(prng);
+   return rng_get_bytes(out, outlen, NULL);
+}
+
+/**
+  Terminate the PRNG
+  @param prng   The PRNG to terminate
+  @return CRYPT_OK if successful
+*/
+int sprng_done(prng_state *prng)
+{
+   LTC_UNUSED_PARAM(prng);
+   return CRYPT_OK;
+}
+
+/**
+  Export the PRNG state
+  @param out       [out] Destination
+  @param outlen    [in/out] Max size and resulting size of the state
+  @param prng      The PRNG to export
+  @return CRYPT_OK if successful
+*/
+int sprng_export(unsigned char *out, unsigned long *outlen, prng_state *prng)
+{
+   LTC_ARGCHK(outlen != NULL);
+   LTC_UNUSED_PARAM(out);
+   LTC_UNUSED_PARAM(prng);
+
+   *outlen = 0;
+   return CRYPT_OK;
+}
+
+/**
+  Import a PRNG state
+  @param in       The PRNG state
+  @param inlen    Size of the state
+  @param prng     The PRNG to import
+  @return CRYPT_OK if successful
+*/
+int sprng_import(const unsigned char *in, unsigned long inlen, prng_state *prng)
+{
+  LTC_UNUSED_PARAM(in);
+  LTC_UNUSED_PARAM(inlen);
+  LTC_UNUSED_PARAM(prng);
+   return CRYPT_OK;
+}
+
+/**
+  PRNG self-test
+  @return CRYPT_OK if successful, CRYPT_NOP if self-testing has been disabled
+*/
+int sprng_test(void)
+{
+#ifndef LTC_TEST
+   return CRYPT_NOP;
+#else
+   prng_state st;
+   unsigned char en[] = { 0x01, 0x02, 0x03, 0x04 };
+   unsigned char out[1000];
+   int err;
+
+   if ((err = sprng_start(&st)) != CRYPT_OK)                         return err;
+   if ((err = sprng_add_entropy(en, sizeof(en), &st)) != CRYPT_OK)   return err;
+   if ((err = sprng_ready(&st)) != CRYPT_OK)                         return err;
+   if (sprng_read(out, 500, &st) != 500)                             return CRYPT_ERROR_READPRNG; /* skip 500 bytes */
+   if ((err = sprng_done(&st)) != CRYPT_OK)                          return err;
+
+   return CRYPT_OK;
+#endif
+}
+
+#endif
+
+
+
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/prngs/yarrow.c b/libtomcrypt/src/prngs/yarrow.c
new file mode 100644 (file)
index 0000000..e598834
--- /dev/null
@@ -0,0 +1,352 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+  @file yarrow.c
+  Yarrow PRNG, Tom St Denis
+*/
+
+#ifdef LTC_YARROW
+
+const struct ltc_prng_descriptor yarrow_desc =
+{
+    "yarrow", 64,
+    &yarrow_start,
+    &yarrow_add_entropy,
+    &yarrow_ready,
+    &yarrow_read,
+    &yarrow_done,
+    &yarrow_export,
+    &yarrow_import,
+    &yarrow_test
+};
+
+/**
+  Start the PRNG
+  @param prng     [out] The PRNG state to initialize
+  @return CRYPT_OK if successful
+*/
+int yarrow_start(prng_state *prng)
+{
+   int err;
+
+   LTC_ARGCHK(prng != NULL);
+   prng->ready = 0;
+
+   /* these are the default hash/cipher combo used */
+#ifdef LTC_RIJNDAEL
+#if    LTC_YARROW_AES==0
+   prng->yarrow.cipher = register_cipher(&rijndael_enc_desc);
+#elif  LTC_YARROW_AES==1
+   prng->yarrow.cipher = register_cipher(&aes_enc_desc);
+#elif  LTC_YARROW_AES==2
+   prng->yarrow.cipher = register_cipher(&rijndael_desc);
+#elif  LTC_YARROW_AES==3
+   prng->yarrow.cipher = register_cipher(&aes_desc);
+#endif
+#elif defined(LTC_BLOWFISH)
+   prng->yarrow.cipher = register_cipher(&blowfish_desc);
+#elif defined(LTC_TWOFISH)
+   prng->yarrow.cipher = register_cipher(&twofish_desc);
+#elif defined(LTC_RC6)
+   prng->yarrow.cipher = register_cipher(&rc6_desc);
+#elif defined(LTC_RC5)
+   prng->yarrow.cipher = register_cipher(&rc5_desc);
+#elif defined(LTC_SAFERP)
+   prng->yarrow.cipher = register_cipher(&saferp_desc);
+#elif defined(LTC_RC2)
+   prng->yarrow.cipher = register_cipher(&rc2_desc);
+#elif defined(LTC_NOEKEON)
+   prng->yarrow.cipher = register_cipher(&noekeon_desc);
+#elif defined(LTC_ANUBIS)
+   prng->yarrow.cipher = register_cipher(&anubis_desc);
+#elif defined(LTC_KSEED)
+   prng->yarrow.cipher = register_cipher(&kseed_desc);
+#elif defined(LTC_KHAZAD)
+   prng->yarrow.cipher = register_cipher(&khazad_desc);
+#elif defined(LTC_CAST5)
+   prng->yarrow.cipher = register_cipher(&cast5_desc);
+#elif defined(LTC_XTEA)
+   prng->yarrow.cipher = register_cipher(&xtea_desc);
+#elif defined(LTC_SAFER)
+   prng->yarrow.cipher = register_cipher(&safer_sk128_desc);
+#elif defined(LTC_DES)
+   prng->yarrow.cipher = register_cipher(&des3_desc);
+#else
+   #error LTC_YARROW needs at least one CIPHER
+#endif
+   if ((err = cipher_is_valid(prng->yarrow.cipher)) != CRYPT_OK) {
+      return err;
+   }
+
+#ifdef LTC_SHA256
+   prng->yarrow.hash   = register_hash(&sha256_desc);
+#elif defined(LTC_SHA512)
+   prng->yarrow.hash   = register_hash(&sha512_desc);
+#elif defined(LTC_TIGER)
+   prng->yarrow.hash   = register_hash(&tiger_desc);
+#elif defined(LTC_SHA1)
+   prng->yarrow.hash   = register_hash(&sha1_desc);
+#elif defined(LTC_RIPEMD320)
+   prng->yarrow.hash   = register_hash(&rmd320_desc);
+#elif defined(LTC_RIPEMD256)
+   prng->yarrow.hash   = register_hash(&rmd256_desc);
+#elif defined(LTC_RIPEMD160)
+   prng->yarrow.hash   = register_hash(&rmd160_desc);
+#elif defined(LTC_RIPEMD128)
+   prng->yarrow.hash   = register_hash(&rmd128_desc);
+#elif defined(LTC_MD5)
+   prng->yarrow.hash   = register_hash(&md5_desc);
+#elif defined(LTC_MD4)
+   prng->yarrow.hash   = register_hash(&md4_desc);
+#elif defined(LTC_MD2)
+   prng->yarrow.hash   = register_hash(&md2_desc);
+#elif defined(LTC_WHIRLPOOL)
+   prng->yarrow.hash   = register_hash(&whirlpool_desc);
+#else
+   #error LTC_YARROW needs at least one HASH
+#endif
+   if ((err = hash_is_valid(prng->yarrow.hash)) != CRYPT_OK) {
+      return err;
+   }
+
+   /* zero the memory used */
+   zeromem(prng->yarrow.pool, sizeof(prng->yarrow.pool));
+   LTC_MUTEX_INIT(&prng->lock)
+
+   return CRYPT_OK;
+}
+
+/**
+  Add entropy to the PRNG state
+  @param in       The data to add
+  @param inlen    Length of the data to add
+  @param prng     PRNG state to update
+  @return CRYPT_OK if successful
+*/
+int yarrow_add_entropy(const unsigned char *in, unsigned long inlen, prng_state *prng)
+{
+   hash_state md;
+   int err;
+
+   LTC_ARGCHK(prng != NULL);
+   LTC_ARGCHK(in != NULL);
+   LTC_ARGCHK(inlen > 0);
+
+   LTC_MUTEX_LOCK(&prng->lock);
+
+   if ((err = hash_is_valid(prng->yarrow.hash)) != CRYPT_OK) {
+      goto LBL_UNLOCK;
+   }
+
+   /* start the hash */
+   if ((err = hash_descriptor[prng->yarrow.hash].init(&md)) != CRYPT_OK) {
+      goto LBL_UNLOCK;
+   }
+
+   /* hash the current pool */
+   if ((err = hash_descriptor[prng->yarrow.hash].process(&md, prng->yarrow.pool,
+                                                        hash_descriptor[prng->yarrow.hash].hashsize)) != CRYPT_OK) {
+      goto LBL_UNLOCK;
+   }
+
+   /* add the new entropy */
+   if ((err = hash_descriptor[prng->yarrow.hash].process(&md, in, inlen)) != CRYPT_OK) {
+      goto LBL_UNLOCK;
+   }
+
+   /* store result */
+   err = hash_descriptor[prng->yarrow.hash].done(&md, prng->yarrow.pool);
+
+LBL_UNLOCK:
+   LTC_MUTEX_UNLOCK(&prng->lock);
+   return err;
+}
+
+/**
+  Make the PRNG ready to read from
+  @param prng   The PRNG to make active
+  @return CRYPT_OK if successful
+*/
+int yarrow_ready(prng_state *prng)
+{
+   int ks, err;
+
+   LTC_ARGCHK(prng != NULL);
+
+   LTC_MUTEX_LOCK(&prng->lock);
+
+   if ((err = hash_is_valid(prng->yarrow.hash)) != CRYPT_OK) {
+      goto LBL_UNLOCK;
+   }
+
+   if ((err = cipher_is_valid(prng->yarrow.cipher)) != CRYPT_OK) {
+      goto LBL_UNLOCK;
+   }
+
+   /* setup CTR mode using the "pool" as the key */
+   ks = (int)hash_descriptor[prng->yarrow.hash].hashsize;
+   if ((err = cipher_descriptor[prng->yarrow.cipher].keysize(&ks)) != CRYPT_OK) {
+      goto LBL_UNLOCK;
+   }
+
+   if ((err = ctr_start(prng->yarrow.cipher,     /* what cipher to use */
+                        prng->yarrow.pool,       /* IV */
+                        prng->yarrow.pool, ks,   /* KEY and key size */
+                        0,                       /* number of rounds */
+                        CTR_COUNTER_LITTLE_ENDIAN, /* little endian counter */
+                        &prng->yarrow.ctr)) != CRYPT_OK) {
+      goto LBL_UNLOCK;
+   }
+   prng->ready = 1;
+
+LBL_UNLOCK:
+   LTC_MUTEX_UNLOCK(&prng->lock);
+   return err;
+}
+
+/**
+  Read from the PRNG
+  @param out      Destination
+  @param outlen   Length of output
+  @param prng     The active PRNG to read from
+  @return Number of octets read
+*/
+unsigned long yarrow_read(unsigned char *out, unsigned long outlen, prng_state *prng)
+{
+   if (outlen == 0 || prng == NULL || out == NULL) return 0;
+
+   LTC_MUTEX_LOCK(&prng->lock);
+
+   if (!prng->ready) {
+      outlen = 0;
+      goto LBL_UNLOCK;
+   }
+
+   /* put out in predictable state first */
+   zeromem(out, outlen);
+
+   /* now randomize it */
+   if (ctr_encrypt(out, out, outlen, &prng->yarrow.ctr) != CRYPT_OK) {
+      outlen = 0;
+   }
+
+LBL_UNLOCK:
+   LTC_MUTEX_UNLOCK(&prng->lock);
+   return outlen;
+}
+
+/**
+  Terminate the PRNG
+  @param prng   The PRNG to terminate
+  @return CRYPT_OK if successful
+*/
+int yarrow_done(prng_state *prng)
+{
+   int err;
+   LTC_ARGCHK(prng != NULL);
+
+   LTC_MUTEX_LOCK(&prng->lock);
+   prng->ready = 0;
+
+   /* call cipher done when we invent one ;-) */
+
+   /* we invented one */
+   err = ctr_done(&prng->yarrow.ctr);
+
+   LTC_MUTEX_UNLOCK(&prng->lock);
+   LTC_MUTEX_DESTROY(&prng->lock);
+   return err;
+}
+
+/**
+  Export the PRNG state
+  @param out       [out] Destination
+  @param outlen    [in/out] Max size and resulting size of the state
+  @param prng      The PRNG to export
+  @return CRYPT_OK if successful
+*/
+int yarrow_export(unsigned char *out, unsigned long *outlen, prng_state *prng)
+{
+   unsigned long len = yarrow_desc.export_size;
+
+   LTC_ARGCHK(out    != NULL);
+   LTC_ARGCHK(outlen != NULL);
+   LTC_ARGCHK(prng   != NULL);
+
+   if (*outlen < len) {
+      *outlen = len;
+      return CRYPT_BUFFER_OVERFLOW;
+   }
+
+   if (yarrow_read(out, len, prng) != len) {
+      return CRYPT_ERROR_READPRNG;
+   }
+
+   *outlen = len;
+   return CRYPT_OK;
+}
+
+/**
+  Import a PRNG state
+  @param in       The PRNG state
+  @param inlen    Size of the state
+  @param prng     The PRNG to import
+  @return CRYPT_OK if successful
+*/
+int yarrow_import(const unsigned char *in, unsigned long inlen, prng_state *prng)
+{
+   int err;
+
+   LTC_ARGCHK(in   != NULL);
+   LTC_ARGCHK(prng != NULL);
+   if (inlen < (unsigned long)yarrow_desc.export_size) return CRYPT_INVALID_ARG;
+
+   if ((err = yarrow_start(prng)) != CRYPT_OK)                  return err;
+   if ((err = yarrow_add_entropy(in, inlen, prng)) != CRYPT_OK) return err;
+   return CRYPT_OK;
+}
+
+/**
+  PRNG self-test
+  @return CRYPT_OK if successful, CRYPT_NOP if self-testing has been disabled
+*/
+int yarrow_test(void)
+{
+#ifndef LTC_TEST
+   return CRYPT_NOP;
+#else
+   int err;
+   prng_state prng;
+
+   if ((err = yarrow_start(&prng)) != CRYPT_OK) {
+      return err;
+   }
+
+   /* now let's test the hash/cipher that was chosen */
+   if (cipher_descriptor[prng.yarrow.cipher].test &&
+       ((err = cipher_descriptor[prng.yarrow.cipher].test()) != CRYPT_OK)) {
+      return err;
+   }
+   if (hash_descriptor[prng.yarrow.hash].test &&
+       ((err = hash_descriptor[prng.yarrow.hash].test()) != CRYPT_OK)) {
+      return err;
+   }
+
+   return CRYPT_OK;
+#endif
+}
+
+#endif
+
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/stream/chacha/chacha_crypt.c b/libtomcrypt/src/stream/chacha/chacha_crypt.c
new file mode 100644 (file)
index 0000000..6814058
--- /dev/null
@@ -0,0 +1,101 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+/* The implementation is based on:
+ * chacha-ref.c version 20080118
+ * Public domain from D. J. Bernstein
+ */
+
+#include "tomcrypt.h"
+
+#ifdef LTC_CHACHA
+
+#define QUARTERROUND(a,b,c,d) \
+  x[a] += x[b]; x[d] = ROL(x[d] ^ x[a], 16); \
+  x[c] += x[d]; x[b] = ROL(x[b] ^ x[c], 12); \
+  x[a] += x[b]; x[d] = ROL(x[d] ^ x[a],  8); \
+  x[c] += x[d]; x[b] = ROL(x[b] ^ x[c],  7);
+
+static void _chacha_block(unsigned char *output, const ulong32 *input, int rounds)
+{
+   ulong32 x[16];
+   int i;
+   XMEMCPY(x, input, sizeof(x));
+   for (i = rounds; i > 0; i -= 2) {
+      QUARTERROUND(0, 4, 8,12)
+      QUARTERROUND(1, 5, 9,13)
+      QUARTERROUND(2, 6,10,14)
+      QUARTERROUND(3, 7,11,15)
+      QUARTERROUND(0, 5,10,15)
+      QUARTERROUND(1, 6,11,12)
+      QUARTERROUND(2, 7, 8,13)
+      QUARTERROUND(3, 4, 9,14)
+   }
+   for (i = 0; i < 16; ++i) {
+     x[i] += input[i];
+     STORE32L(x[i], output + 4 * i);
+   }
+}
+
+/**
+   Encrypt (or decrypt) bytes of ciphertext (or plaintext) with ChaCha
+   @param st      The ChaCha state
+   @param in      The plaintext (or ciphertext)
+   @param inlen   The length of the input (octets)
+   @param out     [out] The ciphertext (or plaintext), length inlen
+   @return CRYPT_OK if successful
+*/
+int chacha_crypt(chacha_state *st, const unsigned char *in, unsigned long inlen, unsigned char *out)
+{
+   unsigned char buf[64];
+   unsigned long i, j;
+
+   if (inlen == 0) return CRYPT_OK; /* nothing to do */
+
+   LTC_ARGCHK(st        != NULL);
+   LTC_ARGCHK(in        != NULL);
+   LTC_ARGCHK(out       != NULL);
+   LTC_ARGCHK(st->ivlen != 0);
+
+   if (st->ksleft > 0) {
+      j = MIN(st->ksleft, inlen);
+      for (i = 0; i < j; ++i, st->ksleft--) out[i] = in[i] ^ st->kstream[64 - st->ksleft];
+      inlen -= j;
+      if (inlen == 0) return CRYPT_OK;
+      out += j;
+      in  += j;
+   }
+   for (;;) {
+     _chacha_block(buf, st->input, st->rounds);
+     if (st->ivlen == 8) {
+       /* IV-64bit, increment 64bit counter */
+       if (0 == ++st->input[12] && 0 == ++st->input[13]) return CRYPT_OVERFLOW;
+     }
+     else {
+       /* IV-96bit, increment 32bit counter */
+       if (0 == ++st->input[12]) return CRYPT_OVERFLOW;
+     }
+     if (inlen <= 64) {
+       for (i = 0; i < inlen; ++i) out[i] = in[i] ^ buf[i];
+       st->ksleft = 64 - inlen;
+       for (i = inlen; i < 64; ++i) st->kstream[i] = buf[i];
+       return CRYPT_OK;
+     }
+     for (i = 0; i < 64; ++i) out[i] = in[i] ^ buf[i];
+     inlen -= 64;
+     out += 64;
+     in  += 64;
+   }
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/stream/chacha/chacha_done.c b/libtomcrypt/src/stream/chacha/chacha_done.c
new file mode 100644 (file)
index 0000000..9f0196e
--- /dev/null
@@ -0,0 +1,30 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+#include "tomcrypt.h"
+
+#ifdef LTC_CHACHA
+
+/**
+  Terminate and clear ChaCha state
+  @param st      The ChaCha state
+  @return CRYPT_OK on success
+*/
+int chacha_done(chacha_state *st)
+{
+   LTC_ARGCHK(st != NULL);
+   XMEMSET(st, 0, sizeof(chacha_state));
+   return CRYPT_OK;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/stream/chacha/chacha_ivctr32.c b/libtomcrypt/src/stream/chacha/chacha_ivctr32.c
new file mode 100644 (file)
index 0000000..c9a6dbb
--- /dev/null
@@ -0,0 +1,47 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+/* The implementation is based on:
+ * chacha-ref.c version 20080118
+ * Public domain from D. J. Bernstein
+ */
+
+#include "tomcrypt.h"
+
+#ifdef LTC_CHACHA
+
+/**
+  Set IV + counter data to the ChaCha state
+  @param st      The ChaCha20 state
+  @param iv      The IV data to add
+  @param ivlen   The length of the IV (must be 12)
+  @param counter 32bit (unsigned) initial counter value
+  @return CRYPT_OK on success
+ */
+int chacha_ivctr32(chacha_state *st, const unsigned char *iv, unsigned long ivlen, ulong32 counter)
+{
+   LTC_ARGCHK(st != NULL);
+   LTC_ARGCHK(iv != NULL);
+   /* 96bit IV + 32bit counter */
+   LTC_ARGCHK(ivlen == 12);
+
+   st->input[12] = counter;
+   LOAD32L(st->input[13], iv + 0);
+   LOAD32L(st->input[14], iv + 4);
+   LOAD32L(st->input[15], iv + 8);
+   st->ksleft = 0;
+   st->ivlen = ivlen;
+   return CRYPT_OK;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/stream/chacha/chacha_ivctr64.c b/libtomcrypt/src/stream/chacha/chacha_ivctr64.c
new file mode 100644 (file)
index 0000000..643d11f
--- /dev/null
@@ -0,0 +1,47 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+/* The implementation is based on:
+ * chacha-ref.c version 20080118
+ * Public domain from D. J. Bernstein
+ */
+
+#include "tomcrypt.h"
+
+#ifdef LTC_CHACHA
+
+/**
+  Set IV + counter data to the ChaCha state
+  @param st      The ChaCha20 state
+  @param iv      The IV data to add
+  @param ivlen   The length of the IV (must be 8)
+  @param counter 64bit (unsigned) initial counter value
+  @return CRYPT_OK on success
+ */
+int chacha_ivctr64(chacha_state *st, const unsigned char *iv, unsigned long ivlen, ulong64 counter)
+{
+   LTC_ARGCHK(st != NULL);
+   LTC_ARGCHK(iv != NULL);
+   /* 64bit IV + 64bit counter */
+   LTC_ARGCHK(ivlen == 8);
+
+   st->input[12] = (ulong32)(counter & 0xFFFFFFFF);
+   st->input[13] = (ulong32)(counter >> 32);
+   LOAD32L(st->input[14], iv + 0);
+   LOAD32L(st->input[15], iv + 4);
+   st->ksleft = 0;
+   st->ivlen = ivlen;
+   return CRYPT_OK;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/stream/chacha/chacha_keystream.c b/libtomcrypt/src/stream/chacha/chacha_keystream.c
new file mode 100644 (file)
index 0000000..25eb63a
--- /dev/null
@@ -0,0 +1,38 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+/* The implementation is based on:
+ * chacha-ref.c version 20080118
+ * Public domain from D. J. Bernstein
+ */
+
+#include "tomcrypt.h"
+
+#ifdef LTC_CHACHA
+
+/**
+  Generate a stream of random bytes via ChaCha
+  @param st      The ChaCha20 state
+  @param out     [out] The output buffer
+  @param outlen  The output length
+  @return CRYPT_OK on success
+ */
+int chacha_keystream(chacha_state *st, unsigned char *out, unsigned long outlen)
+{
+   if (outlen == 0) return CRYPT_OK; /* nothing to do */
+   LTC_ARGCHK(out != NULL);
+   XMEMSET(out, 0, outlen);
+   return chacha_crypt(st, out, outlen, out);
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/stream/chacha/chacha_setup.c b/libtomcrypt/src/stream/chacha/chacha_setup.c
new file mode 100644 (file)
index 0000000..e34370b
--- /dev/null
@@ -0,0 +1,67 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+/* The implementation is based on:
+ * chacha-ref.c version 20080118
+ * Public domain from D. J. Bernstein
+ */
+
+#include "tomcrypt.h"
+
+#ifdef LTC_CHACHA
+
+static const char * const sigma = "expand 32-byte k";
+static const char * const tau   = "expand 16-byte k";
+
+/**
+   Initialize an ChaCha context (only the key)
+   @param st        [out] The destination of the ChaCha state
+   @param key       The secret key
+   @param keylen    The length of the secret key (octets)
+   @param rounds    Number of rounds (e.g. 20 for ChaCha20)
+   @return CRYPT_OK if successful
+*/
+int chacha_setup(chacha_state *st, const unsigned char *key, unsigned long keylen, int rounds)
+{
+   const char *constants;
+
+   LTC_ARGCHK(st  != NULL);
+   LTC_ARGCHK(key != NULL);
+   LTC_ARGCHK(keylen == 32 || keylen == 16);
+
+   if (rounds == 0) rounds = 20;
+
+   LOAD32L(st->input[4], key + 0);
+   LOAD32L(st->input[5], key + 4);
+   LOAD32L(st->input[6], key + 8);
+   LOAD32L(st->input[7], key + 12);
+   if (keylen == 32) { /* 256bit */
+      key += 16;
+      constants = sigma;
+   } else { /* 128bit */
+      constants = tau;
+   }
+   LOAD32L(st->input[8],  key + 0);
+   LOAD32L(st->input[9],  key + 4);
+   LOAD32L(st->input[10], key + 8);
+   LOAD32L(st->input[11], key + 12);
+   LOAD32L(st->input[0],  constants + 0);
+   LOAD32L(st->input[1],  constants + 4);
+   LOAD32L(st->input[2],  constants + 8);
+   LOAD32L(st->input[3],  constants + 12);
+   st->rounds = rounds; /* e.g. 20 for chacha20 */
+   st->ivlen = 0; /* will be set later by chacha_ivctr(32|64) */
+   return CRYPT_OK;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/stream/chacha/chacha_test.c b/libtomcrypt/src/stream/chacha/chacha_test.c
new file mode 100644 (file)
index 0000000..649ebf9
--- /dev/null
@@ -0,0 +1,71 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+/* The implementation is based on:
+ * chacha-ref.c version 20080118
+ * Public domain from D. J. Bernstein
+ */
+
+#include "tomcrypt.h"
+
+#ifdef LTC_CHACHA
+
+int chacha_test(void)
+{
+#ifndef LTC_TEST
+   return CRYPT_NOP;
+#else
+   unsigned long len;
+   unsigned char out[1000];
+   /* https://tools.ietf.org/html/rfc7539#section-2.4.2 */
+   unsigned char k[]  = { 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 };
+   unsigned char n[]  = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4a, 0x00, 0x00, 0x00, 0x00 };
+   unsigned char ct[] = { 0x6E, 0x2E, 0x35, 0x9A, 0x25, 0x68, 0xF9, 0x80, 0x41, 0xBA, 0x07, 0x28, 0xDD, 0x0D, 0x69, 0x81,
+                          0xE9, 0x7E, 0x7A, 0xEC, 0x1D, 0x43, 0x60, 0xC2, 0x0A, 0x27, 0xAF, 0xCC, 0xFD, 0x9F, 0xAE, 0x0B,
+                          0xF9, 0x1B, 0x65, 0xC5, 0x52, 0x47, 0x33, 0xAB, 0x8F, 0x59, 0x3D, 0xAB, 0xCD, 0x62, 0xB3, 0x57,
+                          0x16, 0x39, 0xD6, 0x24, 0xE6, 0x51, 0x52, 0xAB, 0x8F, 0x53, 0x0C, 0x35, 0x9F, 0x08, 0x61, 0xD8,
+                          0x07, 0xCA, 0x0D, 0xBF, 0x50, 0x0D, 0x6A, 0x61, 0x56, 0xA3, 0x8E, 0x08, 0x8A, 0x22, 0xB6, 0x5E,
+                          0x52, 0xBC, 0x51, 0x4D, 0x16, 0xCC, 0xF8, 0x06, 0x81, 0x8C, 0xE9, 0x1A, 0xB7, 0x79, 0x37, 0x36,
+                          0x5A, 0xF9, 0x0B, 0xBF, 0x74, 0xA3, 0x5B, 0xE6, 0xB4, 0x0B, 0x8E, 0xED, 0xF2, 0x78, 0x5E, 0x42,
+                          0x87, 0x4D };
+   char pt[] = "Ladies and Gentlemen of the class of '99: If I could offer you only one tip for the future, sunscreen would be it.";
+   chacha_state st;
+   int err;
+
+   len = strlen(pt);
+   /* crypt piece by piece */
+   if ((err = chacha_setup(&st, k, sizeof(k), 20)) != CRYPT_OK)                            return err;
+   if ((err = chacha_ivctr32(&st, n, sizeof(n), 1)) != CRYPT_OK)                           return err;
+   if ((err = chacha_crypt(&st, (unsigned char*)pt,      35,       out)) != CRYPT_OK)      return err;
+   if ((err = chacha_crypt(&st, (unsigned char*)pt + 35, 35,       out + 35)) != CRYPT_OK) return err;
+   if ((err = chacha_crypt(&st, (unsigned char*)pt + 70,  5,       out + 70)) != CRYPT_OK) return err;
+   if ((err = chacha_crypt(&st, (unsigned char*)pt + 75,  5,       out + 75)) != CRYPT_OK) return err;
+   if ((err = chacha_crypt(&st, (unsigned char*)pt + 80, len - 80, out + 80)) != CRYPT_OK) return err;
+   if (compare_testvector(out, len, ct, sizeof(ct), "CHACHA-TV1", 1))                      return CRYPT_FAIL_TESTVECTOR;
+   /* crypt in one go */
+   if ((err = chacha_setup(&st, k, sizeof(k), 20)) != CRYPT_OK)                            return err;
+   if ((err = chacha_ivctr32(&st, n, sizeof(n), 1)) != CRYPT_OK)                           return err;
+   if ((err = chacha_crypt(&st, (unsigned char*)pt, len, out)) != CRYPT_OK)                return err;
+   if (compare_testvector(out, len, ct, sizeof(ct), "CHACHA-TV2", 1))                      return CRYPT_FAIL_TESTVECTOR;
+   /* crypt in one go - using chacha_ivctr64() */
+   if ((err = chacha_setup(&st, k, sizeof(k), 20)) != CRYPT_OK)                            return err;
+   if ((err = chacha_ivctr64(&st, n + 4, sizeof(n) - 4, 1)) != CRYPT_OK)                   return err;
+   if ((err = chacha_crypt(&st, (unsigned char*)pt, len, out)) != CRYPT_OK)                return err;
+   if (compare_testvector(out, len, ct, sizeof(ct), "CHACHA-TV3", 1))                      return CRYPT_FAIL_TESTVECTOR;
+
+   return CRYPT_OK;
+#endif
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/stream/rc4/rc4_stream.c b/libtomcrypt/src/stream/rc4/rc4_stream.c
new file mode 100644 (file)
index 0000000..178489d
--- /dev/null
@@ -0,0 +1,111 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+#include "tomcrypt.h"
+
+#ifdef LTC_RC4_STREAM
+
+/**
+   Initialize an RC4 context (only the key)
+   @param st        [out] The destination of the RC4 state
+   @param key       The secret key
+   @param keylen    The length of the secret key (8 - 256 bytes)
+   @return CRYPT_OK if successful
+*/
+int rc4_stream_setup(rc4_state *st, const unsigned char *key, unsigned long keylen)
+{
+   unsigned char tmp, *s;
+   int x, y;
+   unsigned long j;
+
+   LTC_ARGCHK(st  != NULL);
+   LTC_ARGCHK(key != NULL);
+   LTC_ARGCHK(keylen >= 5); /* 40-2048 bits */
+
+   s = st->buf;
+   for (x = 0; x < 256; x++) {
+      s[x] = x;
+   }
+
+   for (j = x = y = 0; x < 256; x++) {
+      y = (y + s[x] + key[j++]) & 255;
+      if (j == keylen) {
+         j = 0;
+      }
+      tmp = s[x]; s[x] = s[y]; s[y] = tmp;
+   }
+   st->x = 0;
+   st->y = 0;
+
+   return CRYPT_OK;
+}
+
+/**
+   Encrypt (or decrypt) bytes of ciphertext (or plaintext) with RC4
+   @param st      The RC4 state
+   @param in      The plaintext (or ciphertext)
+   @param inlen   The length of the input (octets)
+   @param out     [out] The ciphertext (or plaintext), length inlen
+   @return CRYPT_OK if successful
+*/
+int rc4_stream_crypt(rc4_state *st, const unsigned char *in, unsigned long inlen, unsigned char *out)
+{
+   unsigned char x, y, *s, tmp;
+
+   LTC_ARGCHK(st  != NULL);
+   LTC_ARGCHK(in  != NULL);
+   LTC_ARGCHK(out != NULL);
+
+   x = st->x;
+   y = st->y;
+   s = st->buf;
+   while (inlen--) {
+      x = (x + 1) & 255;
+      y = (y + s[x]) & 255;
+      tmp = s[x]; s[x] = s[y]; s[y] = tmp;
+      tmp = (s[x] + s[y]) & 255;
+      *out++ = *in++ ^ s[tmp];
+   }
+   st->x = x;
+   st->y = y;
+   return CRYPT_OK;
+}
+
+/**
+  Generate a stream of random bytes via RC4
+  @param st      The RC420 state
+  @param out     [out] The output buffer
+  @param outlen  The output length
+  @return CRYPT_OK on success
+ */
+int rc4_stream_keystream(rc4_state *st, unsigned char *out, unsigned long outlen)
+{
+   if (outlen == 0) return CRYPT_OK; /* nothing to do */
+   LTC_ARGCHK(out != NULL);
+   XMEMSET(out, 0, outlen);
+   return rc4_stream_crypt(st, out, outlen, out);
+}
+
+/**
+  Terminate and clear RC4 state
+  @param st      The RC4 state
+  @return CRYPT_OK on success
+*/
+int rc4_stream_done(rc4_state *st)
+{
+   LTC_ARGCHK(st != NULL);
+   XMEMSET(st, 0, sizeof(rc4_state));
+   return CRYPT_OK;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/stream/rc4/rc4_test.c b/libtomcrypt/src/stream/rc4/rc4_test.c
new file mode 100644 (file)
index 0000000..a7e4887
--- /dev/null
@@ -0,0 +1,39 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+#include "tomcrypt.h"
+
+#ifdef LTC_RC4_STREAM
+
+int rc4_stream_test(void)
+{
+#ifndef LTC_TEST
+   return CRYPT_NOP;
+#else
+   rc4_state st;
+   int err;
+   const unsigned char key[] = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef };
+   const unsigned char pt[]  = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef };
+   const unsigned char ct[]  = { 0x75, 0xb7, 0x87, 0x80, 0x99, 0xe0, 0xc5, 0x96 };
+   unsigned char buf[10];
+
+   if ((err = rc4_stream_setup(&st, key, sizeof(key))) != CRYPT_OK)    return err;
+   if ((err = rc4_stream_crypt(&st, pt, sizeof(pt), buf)) != CRYPT_OK) return err;
+   if (compare_testvector(buf, sizeof(ct), ct, sizeof(ct), "RC4", 0))  return CRYPT_FAIL_TESTVECTOR;
+   if ((err = rc4_stream_done(&st)) != CRYPT_OK)                       return err;
+
+   return CRYPT_OK;
+#endif
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/stream/sober128/sober128_stream.c b/libtomcrypt/src/stream/sober128/sober128_stream.c
new file mode 100644 (file)
index 0000000..5c35eda
--- /dev/null
@@ -0,0 +1,346 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+/**
+ @file sober128_stream.c
+ Implementation of SOBER-128 by Tom St Denis.
+ Based on s128fast.c reference code supplied by Greg Rose of QUALCOMM.
+*/
+
+#ifdef LTC_SOBER128
+
+#define __LTC_SOBER128TAB_C__
+#include "sober128tab.c"
+
+/* don't change these... */
+#define N                        17
+#define FOLD                      N /* how many iterations of folding to do */
+#define INITKONST        0x6996c53a /* value of KONST to use during key loading */
+#define KEYP                     15 /* where to insert key words */
+#define FOLDP                     4 /* where to insert non-linear feedback */
+
+#define B(x,i) ((unsigned char)(((x) >> (8*i)) & 0xFF))
+
+static ulong32 BYTE2WORD(unsigned char *b)
+{
+   ulong32 t;
+   LOAD32L(t, b);
+   return t;
+}
+
+static void XORWORD(ulong32 w, const unsigned char *in, unsigned char *out)
+{
+   ulong32 t;
+   LOAD32L(t, in);
+   t ^= w;
+   STORE32L(t, out);
+}
+
+/* give correct offset for the current position of the register,
+ * where logically R[0] is at position "zero".
+ */
+#define OFF(zero, i) (((zero)+(i)) % N)
+
+/* step the LFSR */
+/* After stepping, "zero" moves right one place */
+#define STEP(R,z) \
+    R[OFF(z,0)] = R[OFF(z,15)] ^ R[OFF(z,4)] ^ (R[OFF(z,0)] << 8) ^ Multab[(R[OFF(z,0)] >> 24) & 0xFF];
+
+static void cycle(ulong32 *R)
+{
+    ulong32 t;
+    int     i;
+
+    STEP(R,0);
+    t = R[0];
+    for (i = 1; i < N; ++i) {
+        R[i-1] = R[i];
+    }
+    R[N-1] = t;
+}
+
+/* Return a non-linear function of some parts of the register.
+ */
+#define NLFUNC(c,z) \
+{ \
+    t = c->R[OFF(z,0)] + c->R[OFF(z,16)]; \
+    t ^= Sbox[(t >> 24) & 0xFF]; \
+    t = RORc(t, 8); \
+    t = ((t + c->R[OFF(z,1)]) ^ c->konst) + c->R[OFF(z,6)]; \
+    t ^= Sbox[(t >> 24) & 0xFF]; \
+    t = t + c->R[OFF(z,13)]; \
+}
+
+static ulong32 nltap(sober128_state *c)
+{
+    ulong32 t;
+    NLFUNC(c, 0);
+    return t;
+}
+
+/* Save the current register state
+ */
+static void s128_savestate(sober128_state *c)
+{
+    int i;
+    for (i = 0; i < N; ++i) {
+        c->initR[i] = c->R[i];
+    }
+}
+
+/* initialise to previously saved register state
+ */
+static void s128_reloadstate(sober128_state *c)
+{
+    int i;
+
+    for (i = 0; i < N; ++i) {
+        c->R[i] = c->initR[i];
+    }
+}
+
+/* Initialise "konst"
+ */
+static void s128_genkonst(sober128_state *c)
+{
+    ulong32 newkonst;
+
+    do {
+       cycle(c->R);
+       newkonst = nltap(c);
+    } while ((newkonst & 0xFF000000) == 0);
+    c->konst = newkonst;
+}
+
+/* Load key material into the register
+ */
+#define ADDKEY(k) \
+   c->R[KEYP] += (k);
+
+#define XORNL(nl) \
+   c->R[FOLDP] ^= (nl);
+
+/* nonlinear diffusion of register for key */
+#define DROUND(z) STEP(c->R,z); NLFUNC(c,(z+1)); c->R[OFF((z+1),FOLDP)] ^= t;
+static void s128_diffuse(sober128_state *c)
+{
+    ulong32 t;
+    /* relies on FOLD == N == 17! */
+    DROUND(0);
+    DROUND(1);
+    DROUND(2);
+    DROUND(3);
+    DROUND(4);
+    DROUND(5);
+    DROUND(6);
+    DROUND(7);
+    DROUND(8);
+    DROUND(9);
+    DROUND(10);
+    DROUND(11);
+    DROUND(12);
+    DROUND(13);
+    DROUND(14);
+    DROUND(15);
+    DROUND(16);
+}
+
+/**
+   Initialize an Sober128 context (only the key)
+   @param c         [out] The destination of the Sober128 state
+   @param key       The secret key
+   @param keylen    The length of the secret key (octets)
+   @return CRYPT_OK if successful
+*/
+int sober128_stream_setup(sober128_state *c, const unsigned char *key, unsigned long keylen)
+{
+   ulong32 i, k;
+
+   LTC_ARGCHK(c   != NULL);
+   LTC_ARGCHK(key != NULL);
+   LTC_ARGCHK(keylen > 0);
+
+   /* keylen must be multiple of 4 bytes */
+   if ((keylen & 3) != 0) {
+      return CRYPT_INVALID_KEYSIZE;
+   }
+
+   /* Register initialised to Fibonacci numbers */
+   c->R[0] = 1;
+   c->R[1] = 1;
+   for (i = 2; i < N; ++i) {
+      c->R[i] = c->R[i-1] + c->R[i-2];
+   }
+   c->konst = INITKONST;
+
+   for (i = 0; i < keylen; i += 4) {
+      k = BYTE2WORD((unsigned char *)&key[i]);
+      ADDKEY(k);
+      cycle(c->R);
+      XORNL(nltap(c));
+   }
+
+   /* also fold in the length of the key */
+   ADDKEY(keylen);
+
+   /* now diffuse */
+   s128_diffuse(c);
+   s128_genkonst(c);
+   s128_savestate(c);
+   c->nbuf = 0;
+
+   return CRYPT_OK;
+}
+
+/**
+  Set IV to the Sober128 state
+  @param c       The Sober12820 state
+  @param iv      The IV data to add
+  @param ivlen   The length of the IV (must be 12)
+  @return CRYPT_OK on success
+ */
+int sober128_stream_setiv(sober128_state *c, const unsigned char *iv, unsigned long ivlen)
+{
+   ulong32 i, k;
+
+   LTC_ARGCHK(c  != NULL);
+   LTC_ARGCHK(iv != NULL);
+   LTC_ARGCHK(ivlen > 0);
+
+   /* ok we are adding an IV then... */
+   s128_reloadstate(c);
+
+   /* ivlen must be multiple of 4 bytes */
+   if ((ivlen & 3) != 0) {
+      return CRYPT_INVALID_KEYSIZE;
+   }
+
+   for (i = 0; i < ivlen; i += 4) {
+      k = BYTE2WORD((unsigned char *)&iv[i]);
+      ADDKEY(k);
+      cycle(c->R);
+      XORNL(nltap(c));
+   }
+
+   /* also fold in the length of the key */
+   ADDKEY(ivlen);
+
+   /* now diffuse */
+   s128_diffuse(c);
+   c->nbuf = 0;
+
+   return CRYPT_OK;
+}
+
+/* XOR pseudo-random bytes into buffer
+ */
+#define SROUND(z) STEP(c->R,z); NLFUNC(c,(z+1)); XORWORD(t, in+(z*4), out+(z*4));
+
+/**
+   Encrypt (or decrypt) bytes of ciphertext (or plaintext) with Sober128
+   @param c       The Sober128 state
+   @param in      The plaintext (or ciphertext)
+   @param inlen   The length of the input (octets)
+   @param out     [out] The ciphertext (or plaintext), length inlen
+   @return CRYPT_OK if successful
+*/
+int sober128_stream_crypt(sober128_state *c, const unsigned char *in, unsigned long inlen, unsigned char *out)
+{
+   ulong32 t;
+
+   if (inlen == 0) return CRYPT_OK; /* nothing to do */
+   LTC_ARGCHK(out != NULL);
+   LTC_ARGCHK(c   != NULL);
+
+   /* handle any previously buffered bytes */
+   while (c->nbuf != 0 && inlen != 0) {
+      *out++ = *in++ ^ (unsigned char)(c->sbuf & 0xFF);
+      c->sbuf >>= 8;
+      c->nbuf -= 8;
+      --inlen;
+   }
+
+#ifndef LTC_SMALL_CODE
+   /* do lots at a time, if there's enough to do */
+   while (inlen >= N*4) {
+      SROUND(0);
+      SROUND(1);
+      SROUND(2);
+      SROUND(3);
+      SROUND(4);
+      SROUND(5);
+      SROUND(6);
+      SROUND(7);
+      SROUND(8);
+      SROUND(9);
+      SROUND(10);
+      SROUND(11);
+      SROUND(12);
+      SROUND(13);
+      SROUND(14);
+      SROUND(15);
+      SROUND(16);
+      out    += 4*N;
+      in     += 4*N;
+      inlen  -= 4*N;
+   }
+#endif
+
+   /* do small or odd size buffers the slow way */
+   while (4 <= inlen) {
+      cycle(c->R);
+      t = nltap(c);
+      XORWORD(t, in, out);
+      out    += 4;
+      in     += 4;
+      inlen  -= 4;
+   }
+
+   /* handle any trailing bytes */
+   if (inlen != 0) {
+      cycle(c->R);
+      c->sbuf = nltap(c);
+      c->nbuf = 32;
+      while (c->nbuf != 0 && inlen != 0) {
+          *out++ = *in++ ^ (unsigned char)(c->sbuf & 0xFF);
+          c->sbuf >>= 8;
+          c->nbuf -= 8;
+          --inlen;
+      }
+   }
+
+   return CRYPT_OK;
+}
+
+int sober128_stream_keystream(sober128_state *c, unsigned char *out, unsigned long outlen)
+{
+   if (outlen == 0) return CRYPT_OK; /* nothing to do */
+   LTC_ARGCHK(out != NULL);
+   XMEMSET(out, 0, outlen);
+   return sober128_stream_crypt(c, out, outlen, out);
+}
+
+/**
+  Terminate and clear Sober128 state
+  @param c       The Sober128 state
+  @return CRYPT_OK on success
+*/
+int sober128_stream_done(sober128_state *c)
+{
+   LTC_ARGCHK(c != NULL);
+   XMEMSET(c, 0, sizeof(sober128_state));
+   return CRYPT_OK;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/stream/sober128/sober128_test.c b/libtomcrypt/src/stream/sober128/sober128_test.c
new file mode 100644 (file)
index 0000000..32ea461
--- /dev/null
@@ -0,0 +1,45 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+#include "tomcrypt.h"
+
+#ifdef LTC_SOBER128
+
+int sober128_stream_test(void)
+{
+#ifndef LTC_TEST
+   return CRYPT_NOP;
+#else
+   unsigned char key[16] = { 0x74, 0x65, 0x73, 0x74, 0x20, 0x6b, 0x65, 0x79,
+                             0x20, 0x31, 0x32, 0x38, 0x62, 0x69, 0x74, 0x73 };
+   unsigned char iv[4]   = { 0x00, 0x00, 0x00, 0x00 };
+   unsigned char out[20] = { 0x43, 0x50, 0x0c, 0xcf, 0x89, 0x91, 0x9f, 0x1d,
+                             0xaa, 0x37, 0x74, 0x95, 0xf4, 0xb4, 0x58, 0xc2,
+                             0x40, 0x37, 0x8b, 0xbb };
+   int err, len = 20;
+   unsigned char  src[20], dst[20];
+   sober128_state st;
+
+   XMEMSET(src, 0, len); /* input */
+   if ((err = sober128_stream_setup(&st, key, sizeof(key))) != CRYPT_OK) return err;
+   if ((err = sober128_stream_setiv(&st, iv, sizeof(iv))) != CRYPT_OK)   return err;
+   if ((err = sober128_stream_crypt(&st, src, len, dst)) != CRYPT_OK)    return err;
+   if ((err = sober128_stream_done(&st)) != CRYPT_OK)                    return err;
+   if (compare_testvector(dst, len, out, len, "SOBER-128", 0)) {
+      return CRYPT_FAIL_TESTVECTOR;
+   }
+   return CRYPT_OK;
+#endif
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/libtomcrypt/src/stream/sober128/sober128tab.c b/libtomcrypt/src/stream/sober128/sober128tab.c
new file mode 100644 (file)
index 0000000..e02ff23
--- /dev/null
@@ -0,0 +1,176 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+/**
+   @file sober128tab.c
+   SOBER-128 Tables
+*/
+
+#ifdef __LTC_SOBER128TAB_C__
+
+/* $ID$ */
+/* @(#)TuringMultab.h   1.3 (QUALCOMM) 02/09/03 */
+/* Multiplication table for Turing using 0xD02B4367 */
+static const ulong32 Multab[256] = {
+    0x00000000, 0xD02B4367, 0xED5686CE, 0x3D7DC5A9,
+    0x97AC41D1, 0x478702B6, 0x7AFAC71F, 0xAAD18478,
+    0x631582EF, 0xB33EC188, 0x8E430421, 0x5E684746,
+    0xF4B9C33E, 0x24928059, 0x19EF45F0, 0xC9C40697,
+    0xC62A4993, 0x16010AF4, 0x2B7CCF5D, 0xFB578C3A,
+    0x51860842, 0x81AD4B25, 0xBCD08E8C, 0x6CFBCDEB,
+    0xA53FCB7C, 0x7514881B, 0x48694DB2, 0x98420ED5,
+    0x32938AAD, 0xE2B8C9CA, 0xDFC50C63, 0x0FEE4F04,
+    0xC154926B, 0x117FD10C, 0x2C0214A5, 0xFC2957C2,
+    0x56F8D3BA, 0x86D390DD, 0xBBAE5574, 0x6B851613,
+    0xA2411084, 0x726A53E3, 0x4F17964A, 0x9F3CD52D,
+    0x35ED5155, 0xE5C61232, 0xD8BBD79B, 0x089094FC,
+    0x077EDBF8, 0xD755989F, 0xEA285D36, 0x3A031E51,
+    0x90D29A29, 0x40F9D94E, 0x7D841CE7, 0xADAF5F80,
+    0x646B5917, 0xB4401A70, 0x893DDFD9, 0x59169CBE,
+    0xF3C718C6, 0x23EC5BA1, 0x1E919E08, 0xCEBADD6F,
+    0xCFA869D6, 0x1F832AB1, 0x22FEEF18, 0xF2D5AC7F,
+    0x58042807, 0x882F6B60, 0xB552AEC9, 0x6579EDAE,
+    0xACBDEB39, 0x7C96A85E, 0x41EB6DF7, 0x91C02E90,
+    0x3B11AAE8, 0xEB3AE98F, 0xD6472C26, 0x066C6F41,
+    0x09822045, 0xD9A96322, 0xE4D4A68B, 0x34FFE5EC,
+    0x9E2E6194, 0x4E0522F3, 0x7378E75A, 0xA353A43D,
+    0x6A97A2AA, 0xBABCE1CD, 0x87C12464, 0x57EA6703,
+    0xFD3BE37B, 0x2D10A01C, 0x106D65B5, 0xC04626D2,
+    0x0EFCFBBD, 0xDED7B8DA, 0xE3AA7D73, 0x33813E14,
+    0x9950BA6C, 0x497BF90B, 0x74063CA2, 0xA42D7FC5,
+    0x6DE97952, 0xBDC23A35, 0x80BFFF9C, 0x5094BCFB,
+    0xFA453883, 0x2A6E7BE4, 0x1713BE4D, 0xC738FD2A,
+    0xC8D6B22E, 0x18FDF149, 0x258034E0, 0xF5AB7787,
+    0x5F7AF3FF, 0x8F51B098, 0xB22C7531, 0x62073656,
+    0xABC330C1, 0x7BE873A6, 0x4695B60F, 0x96BEF568,
+    0x3C6F7110, 0xEC443277, 0xD139F7DE, 0x0112B4B9,
+    0xD31DD2E1, 0x03369186, 0x3E4B542F, 0xEE601748,
+    0x44B19330, 0x949AD057, 0xA9E715FE, 0x79CC5699,
+    0xB008500E, 0x60231369, 0x5D5ED6C0, 0x8D7595A7,
+    0x27A411DF, 0xF78F52B8, 0xCAF29711, 0x1AD9D476,
+    0x15379B72, 0xC51CD815, 0xF8611DBC, 0x284A5EDB,
+    0x829BDAA3, 0x52B099C4, 0x6FCD5C6D, 0xBFE61F0A,
+    0x7622199D, 0xA6095AFA, 0x9B749F53, 0x4B5FDC34,
+    0xE18E584C, 0x31A51B2B, 0x0CD8DE82, 0xDCF39DE5,
+    0x1249408A, 0xC26203ED, 0xFF1FC644, 0x2F348523,
+    0x85E5015B, 0x55CE423C, 0x68B38795, 0xB898C4F2,
+    0x715CC265, 0xA1778102, 0x9C0A44AB, 0x4C2107CC,
+    0xE6F083B4, 0x36DBC0D3, 0x0BA6057A, 0xDB8D461D,
+    0xD4630919, 0x04484A7E, 0x39358FD7, 0xE91ECCB0,
+    0x43CF48C8, 0x93E40BAF, 0xAE99CE06, 0x7EB28D61,
+    0xB7768BF6, 0x675DC891, 0x5A200D38, 0x8A0B4E5F,
+    0x20DACA27, 0xF0F18940, 0xCD8C4CE9, 0x1DA70F8E,
+    0x1CB5BB37, 0xCC9EF850, 0xF1E33DF9, 0x21C87E9E,
+    0x8B19FAE6, 0x5B32B981, 0x664F7C28, 0xB6643F4F,
+    0x7FA039D8, 0xAF8B7ABF, 0x92F6BF16, 0x42DDFC71,
+    0xE80C7809, 0x38273B6E, 0x055AFEC7, 0xD571BDA0,
+    0xDA9FF2A4, 0x0AB4B1C3, 0x37C9746A, 0xE7E2370D,
+    0x4D33B375, 0x9D18F012, 0xA06535BB, 0x704E76DC,
+    0xB98A704B, 0x69A1332C, 0x54DCF685, 0x84F7B5E2,
+    0x2E26319A, 0xFE0D72FD, 0xC370B754, 0x135BF433,
+    0xDDE1295C, 0x0DCA6A3B, 0x30B7AF92, 0xE09CECF5,
+    0x4A4D688D, 0x9A662BEA, 0xA71BEE43, 0x7730AD24,
+    0xBEF4ABB3, 0x6EDFE8D4, 0x53A22D7D, 0x83896E1A,
+    0x2958EA62, 0xF973A905, 0xC40E6CAC, 0x14252FCB,
+    0x1BCB60CF, 0xCBE023A8, 0xF69DE601, 0x26B6A566,
+    0x8C67211E, 0x5C4C6279, 0x6131A7D0, 0xB11AE4B7,
+    0x78DEE220, 0xA8F5A147, 0x958864EE, 0x45A32789,
+    0xEF72A3F1, 0x3F59E096, 0x0224253F, 0xD20F6658,
+};
+
+/* $ID$ */
+/* Sbox for SOBER-128 */
+/*
+ * This is really the combination of two SBoxes; the least significant
+ * 24 bits comes from:
+ * 8->32 Sbox generated by Millan et. al. at Queensland University of
+ * Technology. See: E. Dawson, W. Millan, L. Burnett, G. Carter,
+ * "On the Design of 8*32 S-boxes". Unpublished report, by the
+ * Information Systems Research Centre,
+ * Queensland University of Technology, 1999.
+ *
+ * The most significant 8 bits are the Skipjack "F table", which can be
+ * found at http://csrc.nist.gov/CryptoToolkit/skipjack/skipjack.pdf .
+ * In this optimised table, though, the intent is to XOR the word from
+ * the table selected by the high byte with the input word. Thus, the
+ * high byte is actually the Skipjack F-table entry XORED with its
+ * table index.
+ */
+static const ulong32 Sbox[256] = {
+    0xa3aa1887, 0xd65e435c, 0x0b65c042, 0x800e6ef4,
+    0xfc57ee20, 0x4d84fed3, 0xf066c502, 0xf354e8ae,
+    0xbb2ee9d9, 0x281f38d4, 0x1f829b5d, 0x735cdf3c,
+    0x95864249, 0xbc2e3963, 0xa1f4429f, 0xf6432c35,
+    0xf7f40325, 0x3cc0dd70, 0x5f973ded, 0x9902dc5e,
+    0xda175b42, 0x590012bf, 0xdc94d78c, 0x39aab26b,
+    0x4ac11b9a, 0x8c168146, 0xc3ea8ec5, 0x058ac28f,
+    0x52ed5c0f, 0x25b4101c, 0x5a2db082, 0x370929e1,
+    0x2a1843de, 0xfe8299fc, 0x202fbc4b, 0x833915dd,
+    0x33a803fa, 0xd446b2de, 0x46233342, 0x4fcee7c3,
+    0x3ad607ef, 0x9e97ebab, 0x507f859b, 0xe81f2e2f,
+    0xc55b71da, 0xd7e2269a, 0x1339c3d1, 0x7ca56b36,
+    0xa6c9def2, 0xb5c9fc5f, 0x5927b3a3, 0x89a56ddf,
+    0xc625b510, 0x560f85a7, 0xace82e71, 0x2ecb8816,
+    0x44951e2a, 0x97f5f6af, 0xdfcbc2b3, 0xce4ff55d,
+    0xcb6b6214, 0x2b0b83e3, 0x549ea6f5, 0x9de041af,
+    0x792f1f17, 0xf73b99ee, 0x39a65ec0, 0x4c7016c6,
+    0x857709a4, 0xd6326e01, 0xc7b280d9, 0x5cfb1418,
+    0xa6aff227, 0xfd548203, 0x506b9d96, 0xa117a8c0,
+    0x9cd5bf6e, 0xdcee7888, 0x61fcfe64, 0xf7a193cd,
+    0x050d0184, 0xe8ae4930, 0x88014f36, 0xd6a87088,
+    0x6bad6c2a, 0x1422c678, 0xe9204de7, 0xb7c2e759,
+    0x0200248e, 0x013b446b, 0xda0d9fc2, 0x0414a895,
+    0x3a6cc3a1, 0x56fef170, 0x86c19155, 0xcf7b8a66,
+    0x551b5e69, 0xb4a8623e, 0xa2bdfa35, 0xc4f068cc,
+    0x573a6acd, 0x6355e936, 0x03602db9, 0x0edf13c1,
+    0x2d0bb16d, 0x6980b83c, 0xfeb23763, 0x3dd8a911,
+    0x01b6bc13, 0xf55579d7, 0xf55c2fa8, 0x19f4196e,
+    0xe7db5476, 0x8d64a866, 0xc06e16ad, 0xb17fc515,
+    0xc46feb3c, 0x8bc8a306, 0xad6799d9, 0x571a9133,
+    0x992466dd, 0x92eb5dcd, 0xac118f50, 0x9fafb226,
+    0xa1b9cef3, 0x3ab36189, 0x347a19b1, 0x62c73084,
+    0xc27ded5c, 0x6c8bc58f, 0x1cdde421, 0xed1e47fb,
+    0xcdcc715e, 0xb9c0ff99, 0x4b122f0f, 0xc4d25184,
+    0xaf7a5e6c, 0x5bbf18bc, 0x8dd7c6e0, 0x5fb7e420,
+    0x521f523f, 0x4ad9b8a2, 0xe9da1a6b, 0x97888c02,
+    0x19d1e354, 0x5aba7d79, 0xa2cc7753, 0x8c2d9655,
+    0x19829da1, 0x531590a7, 0x19c1c149, 0x3d537f1c,
+    0x50779b69, 0xed71f2b7, 0x463c58fa, 0x52dc4418,
+    0xc18c8c76, 0xc120d9f0, 0xafa80d4d, 0x3b74c473,
+    0xd09410e9, 0x290e4211, 0xc3c8082b, 0x8f6b334a,
+    0x3bf68ed2, 0xa843cc1b, 0x8d3c0ff3, 0x20e564a0,
+    0xf8f55a4f, 0x2b40f8e7, 0xfea7f15f, 0xcf00fe21,
+    0x8a6d37d6, 0xd0d506f1, 0xade00973, 0xefbbde36,
+    0x84670fa8, 0xfa31ab9e, 0xaedab618, 0xc01f52f5,
+    0x6558eb4f, 0x71b9e343, 0x4b8d77dd, 0x8cb93da6,
+    0x740fd52d, 0x425412f8, 0xc5a63360, 0x10e53ad0,
+    0x5a700f1c, 0x8324ed0b, 0xe53dc1ec, 0x1a366795,
+    0x6d549d15, 0xc5ce46d7, 0xe17abe76, 0x5f48e0a0,
+    0xd0f07c02, 0x941249b7, 0xe49ed6ba, 0x37a47f78,
+    0xe1cfffbd, 0xb007ca84, 0xbb65f4da, 0xb59f35da,
+    0x33d2aa44, 0x417452ac, 0xc0d674a7, 0x2d61a46a,
+    0xdc63152a, 0x3e12b7aa, 0x6e615927, 0xa14fb118,
+    0xa151758d, 0xba81687b, 0xe152f0b3, 0x764254ed,
+    0x34c77271, 0x0a31acab, 0x54f94aec, 0xb9e994cd,
+    0x574d9e81, 0x5b623730, 0xce8a21e8, 0x37917f0b,
+    0xe8a9b5d6, 0x9697adf8, 0xf3d30431, 0x5dcac921,
+    0x76b35d46, 0xaa430a36, 0xc2194022, 0x22bca65e,
+    0xdaec70ba, 0xdfaea8cc, 0x777bae8b, 0x242924d5,
+    0x1f098a5a, 0x4b396b81, 0x55de2522, 0x435c1cb8,
+    0xaeb8fe1d, 0x9db3c697, 0x5b164f83, 0xe0c16376,
+    0xa319224c, 0xd0203b35, 0x433ac0fe, 0x1466a19a,
+    0x45f0b24f, 0x51fda998, 0xc0d52d71, 0xfa0896a8,
+    0xf9e6053f, 0xa4b0d300, 0xd499cbcc, 0xb95e3d40,
+};
+
+#endif /* __LTC_SOBER128TAB_C__ */
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/tomsfastmath/src/addsub/fp_add.c b/tomsfastmath/src/addsub/fp_add.c
new file mode 100644 (file)
index 0000000..9d1cf45
--- /dev/null
@@ -0,0 +1,43 @@
+/* TomsFastMath, a fast ISO C bignum library.
+ * 
+ * This project is meant to fill in where LibTomMath
+ * falls short.  That is speed ;-)
+ *
+ * This project is public domain and free for all purposes.
+ * 
+ * Tom St Denis, tomstdenis@gmail.com
+ */
+#include <tfm_private.h>
+
+void fp_add(fp_int *a, fp_int *b, fp_int *c)
+{
+  int     sa, sb;
+
+  /* get sign of both inputs */
+  sa = a->sign;
+  sb = b->sign;
+
+  /* handle two cases, not four */
+  if (sa == sb) {
+    /* both positive or both negative */
+    /* add their magnitudes, copy the sign */
+    c->sign = sa;
+    s_fp_add (a, b, c);
+  } else {
+    /* one positive, the other negative */
+    /* subtract the one with the greater magnitude from */
+    /* the one of the lesser magnitude.  The result gets */
+    /* the sign of the one with the greater magnitude. */
+    if (fp_cmp_mag (a, b) == FP_LT) {
+      c->sign = sb;
+      s_fp_sub (b, a, c);
+    } else {
+      c->sign = sa;
+      s_fp_sub (a, b, c);
+    }
+  }
+}
+
+/* $Source$ */
+/* $Revision$ */
+/* $Date$ */
diff --git a/tomsfastmath/src/addsub/fp_add_d.c b/tomsfastmath/src/addsub/fp_add_d.c
new file mode 100644 (file)
index 0000000..4b990fb
--- /dev/null
@@ -0,0 +1,22 @@
+/* TomsFastMath, a fast ISO C bignum library.
+ * 
+ * This project is meant to fill in where LibTomMath
+ * falls short.  That is speed ;-)
+ *
+ * This project is public domain and free for all purposes.
+ * 
+ * Tom St Denis, tomstdenis@gmail.com
+ */
+#include <tfm_private.h>
+
+/* c = a + b */
+void fp_add_d(fp_int *a, fp_digit b, fp_int *c)
+{
+   fp_int tmp;
+   fp_set(&tmp, b);
+   fp_add(a,&tmp,c);
+}
+
+/* $Source$ */
+/* $Revision$ */
+/* $Date$ */
diff --git a/tomsfastmath/src/addsub/fp_addmod.c b/tomsfastmath/src/addsub/fp_addmod.c
new file mode 100644 (file)
index 0000000..40191e7
--- /dev/null
@@ -0,0 +1,23 @@
+/* TomsFastMath, a fast ISO C bignum library.
+ * 
+ * This project is meant to fill in where LibTomMath
+ * falls short.  That is speed ;-)
+ *
+ * This project is public domain and free for all purposes.
+ * 
+ * Tom St Denis, tomstdenis@gmail.com
+ */
+#include <tfm_private.h>
+
+/* d = a + b (mod c) */
+int fp_addmod(fp_int *a, fp_int *b, fp_int *c, fp_int *d)
+{
+  fp_int tmp;
+  fp_zero(&tmp);
+  fp_add(a, b, &tmp);
+  return fp_mod(&tmp, c, d);
+}
+
+/* $Source$ */
+/* $Revision$ */
+/* $Date$ */
diff --git a/tomsfastmath/src/addsub/fp_cmp.c b/tomsfastmath/src/addsub/fp_cmp.c
new file mode 100644 (file)
index 0000000..23f27e8
--- /dev/null
@@ -0,0 +1,31 @@
+/* TomsFastMath, a fast ISO C bignum library.
+ * 
+ * This project is meant to fill in where LibTomMath
+ * falls short.  That is speed ;-)
+ *
+ * This project is public domain and free for all purposes.
+ * 
+ * Tom St Denis, tomstdenis@gmail.com
+ */
+#include <tfm_private.h>
+
+int fp_cmp(fp_int *a, fp_int *b)
+{
+   if (a->sign == FP_NEG && b->sign == FP_ZPOS) {
+      return FP_LT;
+   } else if (a->sign == FP_ZPOS && b->sign == FP_NEG) {
+      return FP_GT;
+   } else {
+      /* compare digits */
+      if (a->sign == FP_NEG) {
+         /* if negative compare opposite direction */
+         return fp_cmp_mag(b, a);
+      } else {
+         return fp_cmp_mag(a, b);
+      }
+   }
+}
+
+/* $Source$ */
+/* $Revision$ */
+/* $Date$ */
diff --git a/tomsfastmath/src/addsub/fp_cmp_d.c b/tomsfastmath/src/addsub/fp_cmp_d.c
new file mode 100644 (file)
index 0000000..c2fb2ec
--- /dev/null
@@ -0,0 +1,38 @@
+/* TomsFastMath, a fast ISO C bignum library.
+ * 
+ * This project is meant to fill in where LibTomMath
+ * falls short.  That is speed ;-)
+ *
+ * This project is public domain and free for all purposes.
+ * 
+ * Tom St Denis, tomstdenis@gmail.com
+ */
+#include <tfm_private.h>
+
+/* compare against a single digit */
+int fp_cmp_d(fp_int *a, fp_digit b)
+{
+  /* compare based on sign */
+  if ((b && a->used == 0) || a->sign == FP_NEG) {
+    return FP_LT;
+  }
+
+  /* compare based on magnitude */
+  if (a->used > 1) {
+    return FP_GT;
+  }
+
+  /* compare the only digit of a to b */
+  if (a->dp[0] > b) {
+    return FP_GT;
+  } else if (a->dp[0] < b) {
+    return FP_LT;
+  } else {
+    return FP_EQ;
+  }
+
+}
+
+/* $Source$ */
+/* $Revision$ */
+/* $Date$ */
diff --git a/tomsfastmath/src/addsub/fp_cmp_mag.c b/tomsfastmath/src/addsub/fp_cmp_mag.c
new file mode 100644 (file)
index 0000000..bdce60b
--- /dev/null
@@ -0,0 +1,35 @@
+/* TomsFastMath, a fast ISO C bignum library.
+ * 
+ * This project is meant to fill in where LibTomMath
+ * falls short.  That is speed ;-)
+ *
+ * This project is public domain and free for all purposes.
+ * 
+ * Tom St Denis, tomstdenis@gmail.com
+ */
+#include <tfm_private.h>
+
+int fp_cmp_mag(fp_int *a, fp_int *b)
+{
+   int x;
+
+   if (a->used > b->used) {
+      return FP_GT;
+   } else if (a->used < b->used) {
+      return FP_LT;
+   } else {
+      for (x = a->used - 1; x >= 0; x--) {
+          if (a->dp[x] > b->dp[x]) {
+             return FP_GT;
+          } else if (a->dp[x] < b->dp[x]) {
+             return FP_LT;
+          }
+      }
+   }
+   return FP_EQ;
+}
+
+
+/* $Source$ */
+/* $Revision$ */
+/* $Date$ */
diff --git a/tomsfastmath/src/addsub/fp_sub.c b/tomsfastmath/src/addsub/fp_sub.c
new file mode 100644 (file)
index 0000000..c482a6a
--- /dev/null
@@ -0,0 +1,50 @@
+/* TomsFastMath, a fast ISO C bignum library.
+ * 
+ * This project is meant to fill in where LibTomMath
+ * falls short.  That is speed ;-)
+ *
+ * This project is public domain and free for all purposes.
+ * 
+ * Tom St Denis, tomstdenis@gmail.com
+ */
+#include <tfm_private.h>
+
+/* c = a - b */
+void fp_sub(fp_int *a, fp_int *b, fp_int *c)
+{
+  int     sa, sb;
+
+  sa = a->sign;
+  sb = b->sign;
+
+  if (sa != sb) {
+    /* subtract a negative from a positive, OR */
+    /* subtract a positive from a negative. */
+    /* In either case, ADD their magnitudes, */
+    /* and use the sign of the first number. */
+    c->sign = sa;
+    s_fp_add (a, b, c);
+  } else {
+    /* subtract a positive from a positive, OR */
+    /* subtract a negative from a negative. */
+    /* First, take the difference between their */
+    /* magnitudes, then... */
+    if (fp_cmp_mag (a, b) != FP_LT) {
+      /* Copy the sign from the first */
+      c->sign = sa;
+      /* The first has a larger or equal magnitude */
+      s_fp_sub (a, b, c);
+    } else {
+      /* The result has the *opposite* sign from */
+      /* the first number. */
+      c->sign = (sa == FP_ZPOS) ? FP_NEG : FP_ZPOS;
+      /* The second has a larger magnitude */
+      s_fp_sub (b, a, c);
+    }
+  }
+}
+
+
+/* $Source$ */
+/* $Revision$ */
+/* $Date$ */
diff --git a/tomsfastmath/src/addsub/fp_sub_d.c b/tomsfastmath/src/addsub/fp_sub_d.c
new file mode 100644 (file)
index 0000000..ba63a17
--- /dev/null
@@ -0,0 +1,22 @@
+/* TomsFastMath, a fast ISO C bignum library.
+ * 
+ * This project is meant to fill in where LibTomMath
+ * falls short.  That is speed ;-)
+ *
+ * This project is public domain and free for all purposes.
+ * 
+ * Tom St Denis, tomstdenis@gmail.com
+ */
+#include <tfm_private.h>
+
+/* c = a - b */
+void fp_sub_d(fp_int *a, fp_digit b, fp_int *c)
+{
+   fp_int tmp;
+   fp_set(&tmp, b);
+   fp_sub(a, &tmp, c);
+}
+
+/* $Source$ */
+/* $Revision$ */
+/* $Date$ */
diff --git a/tomsfastmath/src/addsub/fp_submod.c b/tomsfastmath/src/addsub/fp_submod.c
new file mode 100644 (file)
index 0000000..7e1ad48
--- /dev/null
@@ -0,0 +1,24 @@
+/* TomsFastMath, a fast ISO C bignum library.
+ * 
+ * This project is meant to fill in where LibTomMath
+ * falls short.  That is speed ;-)
+ *
+ * This project is public domain and free for all purposes.
+ * 
+ * Tom St Denis, tomstdenis@gmail.com
+ */
+#include <tfm_private.h>
+
+/* d = a - b (mod c) */
+int fp_submod(fp_int *a, fp_int *b, fp_int *c, fp_int *d)
+{
+  fp_int tmp;
+  fp_zero(&tmp);
+  fp_sub(a, b, &tmp);
+  return fp_mod(&tmp, c, d);
+}
+
+
+/* $Source$ */
+/* $Revision$ */
+/* $Date$ */
diff --git a/tomsfastmath/src/addsub/s_fp_add.c b/tomsfastmath/src/addsub/s_fp_add.c
new file mode 100644 (file)
index 0000000..0633242
--- /dev/null
@@ -0,0 +1,42 @@
+/* TomsFastMath, a fast ISO C bignum library.
+ * 
+ * This project is meant to fill in where LibTomMath
+ * falls short.  That is speed ;-)
+ *
+ * This project is public domain and free for all purposes.
+ * 
+ * Tom St Denis, tomstdenis@gmail.com
+ */
+#include <tfm_private.h>
+
+/* unsigned addition */
+void s_fp_add(fp_int *a, fp_int *b, fp_int *c)
+{
+  int      x, y, oldused;
+  register fp_word  t;
+
+  y       = MAX(a->used, b->used);
+  oldused = MIN(c->used, FP_SIZE);
+  c->used = y;
+  t = 0;
+  for (x = 0; x < y; x++) {
+      t         += ((fp_word)a->dp[x]) + ((fp_word)b->dp[x]);
+      c->dp[x]   = (fp_digit)t;
+      t        >>= DIGIT_BIT;
+  }
+  if (t != 0 && x < FP_SIZE) {
+     c->dp[c->used++] = (fp_digit)t;
+     ++x;
+  }
+
+  c->used = x;
+  for (; x < oldused; x++) {
+     c->dp[x] = 0;
+  }
+  fp_clamp(c);
+}
+
+/* $Source$ */
+/* $Revision$ */
+/* $Date$ */
diff --git a/tomsfastmath/src/addsub/s_fp_sub.c b/tomsfastmath/src/addsub/s_fp_sub.c
new file mode 100644 (file)
index 0000000..dc03f0a
--- /dev/null
@@ -0,0 +1,40 @@
+/* TomsFastMath, a fast ISO C bignum library.
+ * 
+ * This project is meant to fill in where LibTomMath
+ * falls short.  That is speed ;-)
+ *
+ * This project is public domain and free for all purposes.
+ * 
+ * Tom St Denis, tomstdenis@gmail.com
+ */
+#include <tfm_private.h>
+
+/* unsigned subtraction ||a|| >= ||b|| ALWAYS! */
+void s_fp_sub(fp_int *a, fp_int *b, fp_int *c)
+{
+  int      x, oldbused, oldused;
+  fp_word  t;
+
+  oldused  = c->used;
+  oldbused = b->used;
+  c->used  = a->used;
+  t       = 0;
+  for (x = 0; x < oldbused; x++) {
+     t         = ((fp_word)a->dp[x]) - (((fp_word)b->dp[x]) + t);
+     c->dp[x]  = (fp_digit)t;
+     t         = (t >> DIGIT_BIT)&1;
+  }
+  for (; x < a->used; x++) {
+     t         = ((fp_word)a->dp[x]) - t;
+     c->dp[x]  = (fp_digit)t;
+     t         = (t >> DIGIT_BIT)&1;
+   }
+  for (; x < oldused; x++) {
+     c->dp[x] = 0;
+  }
+  fp_clamp(c);
+}
+
+/* $Source$ */
+/* $Revision$ */
+/* $Date$ */
diff --git a/tomsfastmath/src/bin/fp_radix_size.c b/tomsfastmath/src/bin/fp_radix_size.c
new file mode 100644 (file)
index 0000000..8fc1da1
--- /dev/null
@@ -0,0 +1,51 @@
+/* TomsFastMath, a fast ISO C bignum library.
+ *
+ * This project is meant to fill in where LibTomMath
+ * falls short.  That is speed ;-)
+ *
+ * This project is public domain and free for all purposes.
+ *
+ * Tom St Denis, tomstdenis@gmail.com
+ */
+#include <tfm_private.h>
+
+int fp_radix_size(fp_int *a, int radix, int *size)
+{
+  fp_int  t;
+  fp_digit d;
+
+  *size = 0;
+
+  /* check range of the radix */
+  if (radix < 2 || radix > 64) {
+    return FP_VAL;
+  }
+
+  /* quick out if its zero */
+  if (fp_iszero(a) == 1) {
+     *size = 2;
+     return FP_OKAY;
+  }
+
+  fp_init_copy(&t, a);
+
+  /* if it is negative output a - */
+  if (t.sign == FP_NEG) {
+    (*size)++;
+    t.sign = FP_ZPOS;
+  }
+
+  while (fp_iszero (&t) == FP_NO) {
+    fp_div_d (&t, (fp_digit) radix, &t, &d);
+    (*size)++;
+  }
+
+  /* append a NULL so the string is properly terminated */
+  (*size)++;
+  return FP_OKAY;
+
+}
+
+/* $Source$ */
+/* $Revision$ */
+/* $Date$ */
diff --git a/tomsfastmath/src/bin/fp_read_radix.c b/tomsfastmath/src/bin/fp_read_radix.c
new file mode 100644 (file)
index 0000000..431afa0
--- /dev/null
@@ -0,0 +1,70 @@
+/* TomsFastMath, a fast ISO C bignum library.
+ *
+ * This project is meant to fill in where LibTomMath
+ * falls short.  That is speed ;-)
+ *
+ * This project is public domain and free for all purposes.
+ *
+ * Tom St Denis, tomstdenis@gmail.com
+ */
+#include <tfm_private.h>
+
+int fp_read_radix(fp_int *a, const char *str, int radix)
+{
+  int     y, neg;
+  char    ch;
+
+  /* set the integer to the default of zero */
+  fp_zero (a);
+
+  /* make sure the radix is ok */
+  if (radix < 2 || radix > 64) {
+    return FP_VAL;
+  }
+
+  /* if the leading digit is a
+   * minus set the sign to negative.
+   */
+  if (*str == '-') {
+    ++str;
+    neg = FP_NEG;
+  } else {
+    neg = FP_ZPOS;
+  }
+
+  /* process each digit of the string */
+  while (*str) {
+    /* if the radix < 36 the conversion is case insensitive
+     * this allows numbers like 1AB and 1ab to represent the same  value
+     * [e.g. in hex]
+     */
+    ch = (char) ((radix <= 36) ? toupper ((int)*str) : *str);
+    for (y = 0; y < 64; y++) {
+      if (ch == fp_s_rmap[y]) {
+         break;
+      }
+    }
+
+    /* if the char was found in the map
+     * and is less than the given radix add it
+     * to the number, otherwise exit the loop.
+     */
+    if (y < radix) {
+      fp_mul_d (a, (fp_digit) radix, a);
+      fp_add_d (a, (fp_digit) y, a);
+    } else {
+      break;
+    }
+    ++str;
+  }
+
+  /* set the sign only if a != 0 */
+  if (fp_iszero(a) != FP_YES) {
+     a->sign = neg;
+  }
+  return FP_OKAY;
+}
+
+/* $Source$ */
+/* $Revision$ */
+/* $Date$ */
diff --git a/tomsfastmath/src/bin/fp_read_signed_bin.c b/tomsfastmath/src/bin/fp_read_signed_bin.c
new file mode 100644 (file)
index 0000000..6467d19
--- /dev/null
@@ -0,0 +1,27 @@
+/* TomsFastMath, a fast ISO C bignum library.
+ * 
+ * This project is meant to fill in where LibTomMath
+ * falls short.  That is speed ;-)
+ *
+ * This project is public domain and free for all purposes.
+ * 
+ * Tom St Denis, tomstdenis@gmail.com
+ */
+#include <tfm_private.h>
+
+void fp_read_signed_bin(fp_int *a, const unsigned char *b, int c)
+{
+  /* read magnitude */
+  fp_read_unsigned_bin (a, b + 1, c - 1);
+
+  /* first byte is 0 for positive, non-zero for negative */
+  if (b[0] == 0) {
+     a->sign = FP_ZPOS;
+  } else {
+     a->sign = FP_NEG;
+  }
+}
+
+/* $Source$ */
+/* $Revision$ */
+/* $Date$ */
diff --git a/tomsfastmath/src/bin/fp_read_unsigned_bin.c b/tomsfastmath/src/bin/fp_read_unsigned_bin.c
new file mode 100644 (file)
index 0000000..2ee89cb
--- /dev/null
@@ -0,0 +1,66 @@
+/* TomsFastMath, a fast ISO C bignum library.
+ * 
+ * This project is meant to fill in where LibTomMath
+ * falls short.  That is speed ;-)
+ *
+ * This project is public domain and free for all purposes.
+ * 
+ * Tom St Denis, tomstdenis@gmail.com
+ */
+#include <tfm_private.h>
+
+void fp_read_unsigned_bin(fp_int *a, const unsigned char *b, int c)
+{
+  /* zero the int */
+  fp_zero (a);
+
+  /* If we know the endianness of this architecture, and we're using
+     32-bit fp_digits, we can optimize this */
+#if (defined(ENDIAN_LITTLE) || defined(ENDIAN_BIG)) && !defined(FP_64BIT)
+  /* But not for both simultaneously */
+#if defined(ENDIAN_LITTLE) && defined(ENDIAN_BIG)
+#error Both ENDIAN_LITTLE and ENDIAN_BIG defined.
+#endif
+  {
+     unsigned char *pd = (unsigned char *)a->dp;
+
+     if ((unsigned)c > (FP_SIZE * sizeof(fp_digit))) {
+        int excess = c - (FP_SIZE * sizeof(fp_digit));
+        c -= excess;
+        b += excess;
+     }
+     a->used = (c + sizeof(fp_digit) - 1)/sizeof(fp_digit);
+     /* read the bytes in */
+#ifdef ENDIAN_BIG
+     {
+       /* Use Duff's device to unroll the loop. */
+       int idx = (c - 1) & ~3;
+       switch (c % 4) {
+       case 0: do { pd[idx+0] = *b++;
+       case 3:      pd[idx+1] = *b++;
+       case 2:      pd[idx+2] = *b++;
+       case 1:      pd[idx+3] = *b++;
+                     idx -= 4;
+                       } while ((c -= 4) > 0);
+       }
+     }
+#else
+     for (c -= 1; c >= 0; c -= 1) {
+       pd[c] = *b++;
+     }
+#endif
+  }
+#else
+  /* read the bytes in */
+  for (; c > 0; c--) {
+     fp_mul_2d (a, 8, a);
+     a->dp[0] |= *b++;
+     a->used += 1;
+  }
+#endif
+  fp_clamp (a);
+}
+
+/* $Source$ */
+/* $Revision$ */
+/* $Date$ */
diff --git a/tomsfastmath/src/bin/fp_reverse.c b/tomsfastmath/src/bin/fp_reverse.c
new file mode 100644 (file)
index 0000000..ece1d4a
--- /dev/null
@@ -0,0 +1,31 @@
+/* TomsFastMath, a fast ISO C bignum library.
+ * 
+ * This project is meant to fill in where LibTomMath
+ * falls short.  That is speed ;-)
+ *
+ * This project is public domain and free for all purposes.
+ * 
+ * Tom St Denis, tomstdenis@gmail.com
+ */
+#include <tfm_private.h>
+
+/* reverse an array, used for radix code */
+void fp_reverse (unsigned char *s, int len)
+{
+  int     ix, iy;
+  unsigned char t;
+
+  ix = 0;
+  iy = len - 1;
+  while (ix < iy) {
+    t     = s[ix];
+    s[ix] = s[iy];
+    s[iy] = t;
+    ++ix;
+    --iy;
+  }
+}
+
+/* $Source$ */
+/* $Revision$ */
+/* $Date$ */
diff --git a/tomsfastmath/src/bin/fp_s_rmap.c b/tomsfastmath/src/bin/fp_s_rmap.c
new file mode 100644 (file)
index 0000000..832fc7b
--- /dev/null
@@ -0,0 +1,17 @@
+/* TomsFastMath, a fast ISO C bignum library.
+ * 
+ * This project is meant to fill in where LibTomMath
+ * falls short.  That is speed ;-)
+ *
+ * This project is public domain and free for all purposes.
+ * 
+ * Tom St Denis, tomstdenis@gmail.com
+ */
+#include <tfm_private.h>
+
+/* chars used in radix conversions */
+const char *fp_s_rmap = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+/";
+
+/* $Source$ */
+/* $Revision$ */
+/* $Date$ */
diff --git a/tomsfastmath/src/bin/fp_signed_bin_size.c b/tomsfastmath/src/bin/fp_signed_bin_size.c
new file mode 100644 (file)
index 0000000..9db4baf
--- /dev/null
@@ -0,0 +1,19 @@
+/* TomsFastMath, a fast ISO C bignum library.
+ * 
+ * This project is meant to fill in where LibTomMath
+ * falls short.  That is speed ;-)
+ *
+ * This project is public domain and free for all purposes.
+ * 
+ * Tom St Denis, tomstdenis@gmail.com
+ */
+#include <tfm_private.h>
+
+int fp_signed_bin_size(fp_int *a)
+{
+  return 1 + fp_unsigned_bin_size (a);
+}
+
+/* $Source$ */
+/* $Revision$ */
+/* $Date$ */
diff --git a/tomsfastmath/src/bin/fp_to_signed_bin.c b/tomsfastmath/src/bin/fp_to_signed_bin.c
new file mode 100644 (file)
index 0000000..ab2a83f
--- /dev/null
@@ -0,0 +1,20 @@
+/* TomsFastMath, a fast ISO C bignum library.
+ * 
+ * This project is meant to fill in where LibTomMath
+ * falls short.  That is speed ;-)
+ *
+ * This project is public domain and free for all purposes.
+ * 
+ * Tom St Denis, tomstdenis@gmail.com
+ */
+#include <tfm_private.h>
+
+void fp_to_signed_bin(fp_int *a, unsigned char *b)
+{
+  fp_to_unsigned_bin (a, b + 1);
+  b[0] = (unsigned char) ((a->sign == FP_ZPOS) ? 0 : 1);
+}
+
+/* $Source$ */
+/* $Revision$ */
+/* $Date$ */
diff --git a/tomsfastmath/src/bin/fp_to_unsigned_bin.c b/tomsfastmath/src/bin/fp_to_unsigned_bin.c
new file mode 100644 (file)
index 0000000..f0eeb56
--- /dev/null
@@ -0,0 +1,29 @@
+/* TomsFastMath, a fast ISO C bignum library.
+ * 
+ * This project is meant to fill in where LibTomMath
+ * falls short.  That is speed ;-)
+ *
+ * This project is public domain and free for all purposes.
+ * 
+ * Tom St Denis, tomstdenis@gmail.com
+ */
+#include <tfm_private.h>
+
+void fp_to_unsigned_bin(fp_int *a, unsigned char *b)
+{
+  int     x;
+  fp_int  t;
+
+  fp_init_copy(&t, a);
+
+  x = 0;
+  while (fp_iszero (&t) == FP_NO) {
+      b[x++] = (unsigned char) (t.dp[0] & 255);
+      fp_div_2d (&t, 8, &t, NULL);
+  }
+  fp_reverse (b, x);
+}
+
+/* $Source$ */
+/* $Revision$ */
+/* $Date$ */
diff --git a/tomsfastmath/src/bin/fp_toradix.c b/tomsfastmath/src/bin/fp_toradix.c
new file mode 100644 (file)
index 0000000..d16b065
--- /dev/null
@@ -0,0 +1,31 @@
+/* TomsFastMath, a fast ISO C bignum library.
+ *
+ * This project is meant to fill in where LibTomMath
+ * falls short.  That is speed ;-)
+ *
+ * This project is public domain and free for all purposes.
+ *
+ * Tom St Denis, tomstdenis@gmail.com
+ */
+#include <tfm_private.h>
+
+/**
+ * a:          pointer to fp_int representing the input number
+ * str:                output buffer
+ * radix:      number of character to use for encoding of the number
+ *
+ * The radix value can be in the range 2 to 64. This function converts number
+ * a into a string str. Please don't use this function because a too small
+ * chosen str buffer would lead to an overflow which can not be detected.
+ * Please use fp_toradix_n() instead.
+ *
+ * Return: FP_VAL on error, FP_OKAY on success.
+ */
+int fp_toradix(fp_int *a, char *str, int radix)
+{
+   return fp_toradix_n(a, str, radix, INT_MAX);
+}
+
+/* $Source$ */
+/* $Revision$ */
+/* $Date$ */
diff --git a/tomsfastmath/src/bin/fp_toradix_n.c b/tomsfastmath/src/bin/fp_toradix_n.c
new file mode 100644 (file)
index 0000000..5c9bf62
--- /dev/null
@@ -0,0 +1,71 @@
+/* TomsFastMath, a fast ISO C bignum library.
+ *
+ * This project is meant to fill in where LibTomMath
+ * falls short.  That is speed ;-)
+ *
+ * This project is public domain and free for all purposes.
+ *
+ * Tom St Denis, tomstdenis@gmail.com
+ */
+#include <tfm_private.h>
+
+int fp_toradix_n(fp_int *a, char *str, int radix, int maxlen)
+{
+   int digs;
+   fp_int t;
+   fp_digit d;
+   char *_s = str;
+
+   /* check range of the radix */
+   if (maxlen < 2 || radix < 2 || radix > 64)
+      return FP_VAL;
+
+   /* quick check for zero */
+   if (fp_iszero(a) == FP_YES) {
+      *str++ = '0';
+      *str = '\0';
+      return FP_OKAY;
+   }
+
+   fp_init_copy(&t, a);
+
+   /* if it is negative output a - */
+   if (t.sign == FP_NEG) {
+      /* we have to reverse our digits later... but not the - sign!! */
+      ++_s;
+
+      /* store the flag and mark the number as positive */
+      *str++ = '-';
+      t.sign = FP_ZPOS;
+
+      /* subtract a char */
+      --maxlen;
+   }
+
+   digs = 0;
+   while (fp_iszero (&t) == FP_NO) {
+      if (--maxlen < 1) {
+         /* no more room */
+         break;
+      }
+      fp_div_d(&t, (fp_digit) radix, &t, &d);
+      *str++ = fp_s_rmap[d];
+      ++digs;
+   }
+
+   /* reverse the digits of the string.  In this case _s points
+    * to the first digit [exluding the sign] of the number]
+    */
+   fp_reverse((unsigned char *) _s, digs);
+
+   /* append a NULL so the string is properly terminated */
+   *str = '\0';
+
+   if (maxlen < 1)
+      return FP_VAL;
+   return FP_OKAY;
+}
+
+/* $Source$ */
+/* $Revision$ */
+/* $Date$ */
diff --git a/tomsfastmath/src/bin/fp_unsigned_bin_size.c b/tomsfastmath/src/bin/fp_unsigned_bin_size.c
new file mode 100644 (file)
index 0000000..120a1a7
--- /dev/null
@@ -0,0 +1,20 @@
+/* TomsFastMath, a fast ISO C bignum library.
+ * 
+ * This project is meant to fill in where LibTomMath
+ * falls short.  That is speed ;-)
+ *
+ * This project is public domain and free for all purposes.
+ * 
+ * Tom St Denis, tomstdenis@gmail.com
+ */
+#include <tfm_private.h>
+
+int fp_unsigned_bin_size(fp_int *a)
+{
+  int     size = fp_count_bits (a);
+  return (size / 8 + ((size & 7) != 0 ? 1 : 0));
+}
+
+/* $Source$ */
+/* $Revision$ */
+/* $Date$ */
diff --git a/tomsfastmath/src/bit/fp_cnt_lsb.c b/tomsfastmath/src/bit/fp_cnt_lsb.c
new file mode 100644 (file)
index 0000000..5dfd0f7
--- /dev/null
@@ -0,0 +1,46 @@
+/* TomsFastMath, a fast ISO C bignum library.
+ * 
+ * This project is meant to fill in where LibTomMath
+ * falls short.  That is speed ;-)
+ *
+ * This project is public domain and free for all purposes.
+ * 
+ * Tom St Denis, tomstdenis@gmail.com
+ */
+#include <tfm_private.h>
+
+static const int lnz[16] = {
+   4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0
+};
+
+/* Counts the number of lsbs which are zero before the first zero bit */
+int fp_cnt_lsb(fp_int *a)
+{
+   int x;
+   fp_digit q, qq;
+
+   /* easy out */
+   if (fp_iszero(a) == 1) {
+      return 0;
+   }
+
+   /* scan lower digits until non-zero */
+   for (x = 0; x < a->used && a->dp[x] == 0; x++);
+   q = a->dp[x];
+   x *= DIGIT_BIT;
+
+   /* now scan this digit until a 1 is found */
+   if ((q & 1) == 0) {
+      do {
+         qq  = q & 15;
+         x  += lnz[qq];
+         q >>= 4;
+      } while (qq == 0);
+   }
+   return x;
+}
+
+
+/* $Source$ */
+/* $Revision$ */
+/* $Date$ */
diff --git a/tomsfastmath/src/bit/fp_count_bits.c b/tomsfastmath/src/bit/fp_count_bits.c
new file mode 100644 (file)
index 0000000..4968a0f
--- /dev/null
@@ -0,0 +1,36 @@
+/* TomsFastMath, a fast ISO C bignum library.
+ * 
+ * This project is meant to fill in where LibTomMath
+ * falls short.  That is speed ;-)
+ *
+ * This project is public domain and free for all purposes.
+ * 
+ * Tom St Denis, tomstdenis@gmail.com
+ */
+#include <tfm_private.h>
+
+int fp_count_bits (fp_int * a)
+{
+  int     r;
+  fp_digit q;
+
+  /* shortcut */
+  if (a->used == 0) {
+    return 0;
+  }
+
+  /* get number of digits and add that */
+  r = (a->used - 1) * DIGIT_BIT;
+
+  /* take the last digit and count the bits in it */
+  q = a->dp[a->used - 1];
+  while (q > ((fp_digit) 0)) {
+    ++r;
+    q >>= ((fp_digit) 1);
+  }
+  return r;
+}
+
+/* $Source$ */
+/* $Revision$ */
+/* $Date$ */
diff --git a/tomsfastmath/src/bit/fp_div_2.c b/tomsfastmath/src/bit/fp_div_2.c
new file mode 100644 (file)
index 0000000..4ddc4b5
--- /dev/null
@@ -0,0 +1,53 @@
+/* TomsFastMath, a fast ISO C bignum library.
+ * 
+ * This project is meant to fill in where LibTomMath
+ * falls short.  That is speed ;-)
+ *
+ * This project is public domain and free for all purposes.
+ * 
+ * Tom St Denis, tomstdenis@gmail.com
+ */
+#include <tfm_private.h>
+
+/* b = a/2 */
+void fp_div_2(fp_int * a, fp_int * b)
+{
+  int     x, oldused;
+
+  oldused = b->used;
+  b->used = a->used;
+  {
+    register fp_digit r, rr, *tmpa, *tmpb;
+
+    /* source alias */
+    tmpa = a->dp + b->used - 1;
+
+    /* dest alias */
+    tmpb = b->dp + b->used - 1;
+
+    /* carry */
+    r = 0;
+    for (x = b->used - 1; x >= 0; x--) {
+      /* get the carry for the next iteration */
+      rr = *tmpa & 1;
+
+      /* shift the current digit, add in carry and store */
+      *tmpb-- = (*tmpa-- >> 1) | (r << (DIGIT_BIT - 1));
+
+      /* forward carry to next iteration */
+      r = rr;
+    }
+
+    /* zero excess digits */
+    tmpb = b->dp + b->used;
+    for (x = b->used; x < oldused; x++) {
+      *tmpb++ = 0;
+    }
+  }
+  b->sign = a->sign;
+  fp_clamp (b);
+}
+
+/* $Source$ */
+/* $Revision$ */
+/* $Date$ */
diff --git a/tomsfastmath/src/bit/fp_div_2d.c b/tomsfastmath/src/bit/fp_div_2d.c
new file mode 100644 (file)
index 0000000..e4a3edd
--- /dev/null
@@ -0,0 +1,79 @@
+/* TomsFastMath, a fast ISO C bignum library.
+ * 
+ * This project is meant to fill in where LibTomMath
+ * falls short.  That is speed ;-)
+ *
+ * This project is public domain and free for all purposes.
+ * 
+ * Tom St Denis, tomstdenis@gmail.com
+ */
+#include <tfm_private.h>
+
+/* c = a / 2**b */
+void fp_div_2d(fp_int *a, int b, fp_int *c, fp_int *d)
+{
+  fp_digit D, r, rr;
+  int      x;
+  fp_int   t;
+
+  /* if the shift count is <= 0 then we do no work */
+  if (b <= 0) {
+    fp_copy (a, c);
+    if (d != NULL) {
+      fp_zero (d);
+    }
+    return;
+  }
+
+  fp_init(&t);
+
+  /* get the remainder */
+  if (d != NULL) {
+    fp_mod_2d (a, b, &t);
+  }
+
+  /* copy */
+  fp_copy(a, c);
+
+  /* shift by as many digits in the bit count */
+  if (b >= (int)DIGIT_BIT) {
+    fp_rshd (c, b / DIGIT_BIT);
+  }
+
+  /* shift any bit count < DIGIT_BIT */
+  D = (fp_digit) (b % DIGIT_BIT);
+  if (D != 0) {
+    register fp_digit *tmpc, mask, shift;
+
+    /* mask */
+    mask = (((fp_digit)1) << D) - 1;
+
+    /* shift for lsb */
+    shift = DIGIT_BIT - D;
+
+    /* alias */
+    tmpc = c->dp + (c->used - 1);
+
+    /* carry */
+    r = 0;
+    for (x = c->used - 1; x >= 0; x--) {
+      /* get the lower  bits of this word in a temp */
+      rr = *tmpc & mask;
+
+      /* shift the current word and mix in the carry bits from the previous word */
+      *tmpc = (*tmpc >> D) | (r << shift);
+      --tmpc;
+
+      /* set the carry to the carry bits of the current word found above */
+      r = rr;
+    }
+  }
+  fp_clamp (c);
+  if (d != NULL) {
+    fp_copy (&t, d);
+  }
+}
+
+/* $Source$ */
+/* $Revision$ */
+/* $Date$ */
diff --git a/tomsfastmath/src/bit/fp_lshd.c b/tomsfastmath/src/bit/fp_lshd.c
new file mode 100644 (file)
index 0000000..0933655
--- /dev/null
@@ -0,0 +1,38 @@
+/* TomsFastMath, a fast ISO C bignum library.
+ * 
+ * This project is meant to fill in where LibTomMath
+ * falls short.  That is speed ;-)
+ *
+ * This project is public domain and free for all purposes.
+ * 
+ * Tom St Denis, tomstdenis@gmail.com
+ */
+#include <tfm_private.h>
+
+void fp_lshd(fp_int *a, int x)
+{
+   int y;
+
+   /* move up and truncate as required */
+   y = MIN(a->used + x - 1, (int)(FP_SIZE-1));
+
+   /* store new size */
+   a->used = y + 1;
+
+   /* move digits */
+   for (; y >= x; y--) {
+       a->dp[y] = a->dp[y-x];
+   }
+   /* zero lower digits */
+   for (; y >= 0; y--) {
+       a->dp[y] = 0;
+   }
+
+   /* clamp digits */
+   fp_clamp(a);
+}
+
+/* $Source$ */
+/* $Revision$ */
+/* $Date$ */
diff --git a/tomsfastmath/src/bit/fp_mod_2d.c b/tomsfastmath/src/bit/fp_mod_2d.c
new file mode 100644 (file)
index 0000000..d2818f0
--- /dev/null
@@ -0,0 +1,42 @@
+/* TomsFastMath, a fast ISO C bignum library.
+ * 
+ * This project is meant to fill in where LibTomMath
+ * falls short.  That is speed ;-)
+ *
+ * This project is public domain and free for all purposes.
+ * 
+ * Tom St Denis, tomstdenis@gmail.com
+ */
+#include <tfm_private.h>
+
+/* c = a mod 2**d */
+void fp_mod_2d(fp_int *a, int b, fp_int *c)
+{
+   int x;
+
+   /* zero if count less than or equal to zero */
+   if (b <= 0) {
+      fp_zero(c);
+      return;
+   }
+
+   /* get copy of input */
+   fp_copy(a, c);
+   /* if 2**d is larger than we just return */
+   if (b >= (DIGIT_BIT * a->used)) {
+      return;
+   }
+
+  /* zero digits above the last digit of the modulus */
+  for (x = (b / DIGIT_BIT) + ((b % DIGIT_BIT) == 0 ? 0 : 1); x < c->used; x++) {
+    c->dp[x] = 0;
+  }
+  /* clear the digit that is not completely outside/inside the modulus */
+  c->dp[b / DIGIT_BIT] &= ~((fp_digit)0) >> (DIGIT_BIT - b);
+  fp_clamp (c);
+}
+
+/* $Source$ */
+/* $Revision$ */
+/* $Date$ */
diff --git a/tomsfastmath/src/bit/fp_rshd.c b/tomsfastmath/src/bit/fp_rshd.c
new file mode 100644 (file)
index 0000000..6dc3589
--- /dev/null
@@ -0,0 +1,40 @@
+/* TomsFastMath, a fast ISO C bignum library.
+ * 
+ * This project is meant to fill in where LibTomMath
+ * falls short.  That is speed ;-)
+ *
+ * This project is public domain and free for all purposes.
+ * 
+ * Tom St Denis, tomstdenis@gmail.com
+ */
+#include <tfm_private.h>
+
+void fp_rshd(fp_int *a, int x)
+{
+  int y;
+
+  /* too many digits just zero and return */
+  if (x >= a->used) {
+     fp_zero(a);
+     return;
+  }
+
+   /* shift */
+   for (y = 0; y < a->used - x; y++) {
+      a->dp[y] = a->dp[y+x];
+   }
+
+   /* zero rest */
+   for (; y < a->used; y++) {
+      a->dp[y] = 0;
+   }
+   
+   /* decrement count */
+   a->used -= x;
+   fp_clamp(a);
+}
+
+
+/* $Source$ */
+/* $Revision$ */
+/* $Date$ */
diff --git a/tomsfastmath/src/divide/fp_div.c b/tomsfastmath/src/divide/fp_div.c
new file mode 100644 (file)
index 0000000..4f6dd47
--- /dev/null
@@ -0,0 +1,157 @@
+/* TomsFastMath, a fast ISO C bignum library.
+ * 
+ * This project is meant to fill in where LibTomMath
+ * falls short.  That is speed ;-)
+ *
+ * This project is public domain and free for all purposes.
+ * 
+ * Tom St Denis, tomstdenis@gmail.com
+ */
+#include <tfm_private.h>
+
+/* a/b => cb + d == a */
+int fp_div(fp_int *a, fp_int *b, fp_int *c, fp_int *d)
+{
+  fp_int  q, x, y, t1, t2;
+  int     n, t, i, norm, neg;
+
+  /* is divisor zero ? */
+  if (fp_iszero (b) == 1) {
+    return FP_VAL;
+  }
+
+  /* if a < b then q=0, r = a */
+  if (fp_cmp_mag (a, b) == FP_LT) {
+    if (d != NULL) {
+      fp_copy (a, d);
+    } 
+    if (c != NULL) {
+      fp_zero (c);
+    }
+    return FP_OKAY;
+  }
+
+  fp_init(&q);
+  q.used = a->used + 2;
+
+  fp_init(&t1);
+  fp_init(&t2);
+  fp_init_copy(&x, a);
+  fp_init_copy(&y, b);
+
+  /* fix the sign */
+  neg = (a->sign == b->sign) ? FP_ZPOS : FP_NEG;
+  x.sign = y.sign = FP_ZPOS;
+
+  /* normalize both x and y, ensure that y >= b/2, [b == 2**DIGIT_BIT] */
+  norm = fp_count_bits(&y) % DIGIT_BIT;
+  if (norm < (int)(DIGIT_BIT-1)) {
+     norm = (DIGIT_BIT-1) - norm;
+     fp_mul_2d (&x, norm, &x);
+     fp_mul_2d (&y, norm, &y);
+  } else {
+     norm = 0;
+  }
+
+  /* note hac does 0 based, so if used==5 then its 0,1,2,3,4, e.g. use 4 */
+  n = x.used - 1;
+  t = y.used - 1;
+
+  /* while (x >= y*b**n-t) do { q[n-t] += 1; x -= y*b**{n-t} } */
+  fp_lshd (&y, n - t);                                             /* y = y*b**{n-t} */
+
+  while (fp_cmp (&x, &y) != FP_LT) {
+    ++(q.dp[n - t]);
+    fp_sub (&x, &y, &x);
+  }
+
+  /* reset y by shifting it back down */
+  fp_rshd (&y, n - t);
+
+  /* step 3. for i from n down to (t + 1) */
+  for (i = n; i >= (t + 1); i--) {
+    if (i > x.used) {
+      continue;
+    }
+
+    /* step 3.1 if xi == yt then set q{i-t-1} to b-1, 
+     * otherwise set q{i-t-1} to (xi*b + x{i-1})/yt */
+    if (x.dp[i] == y.dp[t]) {
+      q.dp[i - t - 1] = ((((fp_word)1) << DIGIT_BIT) - 1);
+    } else {
+      fp_word tmp;
+      tmp = ((fp_word) x.dp[i]) << ((fp_word) DIGIT_BIT);
+      tmp |= ((fp_word) x.dp[i - 1]);
+      tmp /= ((fp_word) y.dp[t]);
+      q.dp[i - t - 1] = (fp_digit) (tmp);
+    }
+
+    /* while (q{i-t-1} * (yt * b + y{t-1})) > 
+             xi * b**2 + xi-1 * b + xi-2 
+     
+       do q{i-t-1} -= 1; 
+    */
+    q.dp[i - t - 1] = (q.dp[i - t - 1] + 1);
+    do {
+      q.dp[i - t - 1] = (q.dp[i - t - 1] - 1);
+
+      /* find left hand */
+      fp_zero (&t1);
+      t1.dp[0] = (t - 1 < 0) ? 0 : y.dp[t - 1];
+      t1.dp[1] = y.dp[t];
+      t1.used = 2;
+      fp_mul_d (&t1, q.dp[i - t - 1], &t1);
+
+      /* find right hand */
+      t2.dp[0] = (i - 2 < 0) ? 0 : x.dp[i - 2];
+      t2.dp[1] = (i - 1 < 0) ? 0 : x.dp[i - 1];
+      t2.dp[2] = x.dp[i];
+      t2.used = 3;
+    } while (fp_cmp_mag(&t1, &t2) == FP_GT);
+
+    /* step 3.3 x = x - q{i-t-1} * y * b**{i-t-1} */
+    fp_mul_d (&y, q.dp[i - t - 1], &t1);
+    fp_lshd  (&t1, i - t - 1);
+    fp_sub   (&x, &t1, &x);
+
+    /* if x < 0 then { x = x + y*b**{i-t-1}; q{i-t-1} -= 1; } */
+    if (x.sign == FP_NEG) {
+      fp_copy (&y, &t1);
+      fp_lshd (&t1, i - t - 1);
+      fp_add (&x, &t1, &x);
+      q.dp[i - t - 1] = q.dp[i - t - 1] - 1;
+    }
+  }
+
+  /* now q is the quotient and x is the remainder 
+   * [which we have to normalize] 
+   */
+  
+  /* get sign before writing to c */
+  x.sign = x.used == 0 ? FP_ZPOS : a->sign;
+
+  if (c != NULL) {
+    fp_clamp (&q);
+    fp_copy (&q, c);
+    c->sign = neg;
+  }
+
+  if (d != NULL) {
+    fp_div_2d (&x, norm, &x, NULL);
+
+/* the following is a kludge, essentially we were seeing the right remainder but 
+   with excess digits that should have been zero
+ */
+    for (i = b->used; i < x.used; i++) {
+        x.dp[i] = 0;
+    }
+    fp_clamp(&x);
+    fp_copy (&x, d);
+  }
+
+  return FP_OKAY;
+}
+
+/* $Source$ */
+/* $Revision$ */
+/* $Date$ */
diff --git a/tomsfastmath/src/divide/fp_div_d.c b/tomsfastmath/src/divide/fp_div_d.c
new file mode 100644 (file)
index 0000000..982008d
--- /dev/null
@@ -0,0 +1,98 @@
+/* TomsFastMath, a fast ISO C bignum library.
+ * 
+ * This project is meant to fill in where LibTomMath
+ * falls short.  That is speed ;-)
+ *
+ * This project is public domain and free for all purposes.
+ * 
+ * Tom St Denis, tomstdenis@gmail.com
+ */
+#include <tfm_private.h>
+
+static int s_is_power_of_two(fp_digit b, int *p)
+{
+   int x;
+
+   /* fast return if no power of two */
+   if ((b==0) || (b & (b-1))) {
+      return 0;
+   }
+
+   for (x = 0; x < DIGIT_BIT; x++) {
+      if (b == (((fp_digit)1)<<x)) {
+         *p = x;
+         return 1;
+      }
+   }
+   return 0;
+}
+
+/* a/b => cb + d == a */
+int fp_div_d(fp_int *a, fp_digit b, fp_int *c, fp_digit *d)
+{
+  fp_int   q;
+  fp_word  w;
+  fp_digit t;
+  int      ix;
+
+  /* cannot divide by zero */
+  if (b == 0) {
+     return FP_VAL;
+  }
+
+  /* quick outs */
+  if (b == 1 || fp_iszero(a) == 1) {
+     if (d != NULL) {
+        *d = 0;
+     }
+     if (c != NULL) {
+        fp_copy(a, c);
+     }
+     return FP_OKAY;
+  }
+
+  /* power of two ? */
+  if (s_is_power_of_two(b, &ix) == 1) {
+     if (d != NULL) {
+        *d = a->dp[0] & ((((fp_digit)1)<<ix) - 1);
+     }
+     if (c != NULL) {
+        fp_div_2d(a, ix, c, NULL);
+     }
+     return FP_OKAY;
+  }
+
+  /* no easy answer [c'est la vie].  Just division */
+  fp_init(&q);
+  
+  q.used = a->used;
+  q.sign = a->sign;
+  w = 0;
+  for (ix = a->used - 1; ix >= 0; ix--) {
+     w = (w << ((fp_word)DIGIT_BIT)) | ((fp_word)a->dp[ix]);
+     
+     if (w >= b) {
+        t = (fp_digit)(w / b);
+        w -= ((fp_word)t) * ((fp_word)b);
+      } else {
+        t = 0;
+      }
+      q.dp[ix] = (fp_digit)t;
+  }
+  
+  if (d != NULL) {
+     *d = (fp_digit)w;
+  }
+  
+  if (c != NULL) {
+     fp_clamp(&q);
+     fp_copy(&q, c);
+  }
+  return FP_OKAY;
+}
+
+
+/* $Source$ */
+/* $Revision$ */
+/* $Date$ */
diff --git a/tomsfastmath/src/divide/fp_mod.c b/tomsfastmath/src/divide/fp_mod.c
new file mode 100644 (file)
index 0000000..147c0d7
--- /dev/null
@@ -0,0 +1,34 @@
+/* TomsFastMath, a fast ISO C bignum library.
+ * 
+ * This project is meant to fill in where LibTomMath
+ * falls short.  That is speed ;-)
+ *
+ * This project is public domain and free for all purposes.
+ * 
+ * Tom St Denis, tomstdenis@gmail.com
+ */
+#include <tfm_private.h>
+
+/* c = a mod b, 0 <= c < b  */
+int fp_mod(fp_int *a, fp_int *b, fp_int *c)
+{
+   fp_int t;
+   int    err;
+
+   fp_zero(&t);
+   if ((err = fp_div(a, b, NULL, &t)) != FP_OKAY) {
+      return err;
+   }
+   if (t.sign != b->sign) {
+      fp_add(&t, b, c);
+   } else {
+      fp_copy(&t, c);
+  }
+  return FP_OKAY;
+}
+
+
+
+/* $Source$ */
+/* $Revision$ */
+/* $Date$ */
diff --git a/tomsfastmath/src/divide/fp_mod_d.c b/tomsfastmath/src/divide/fp_mod_d.c
new file mode 100644 (file)
index 0000000..be31fbe
--- /dev/null
@@ -0,0 +1,20 @@
+/* TomsFastMath, a fast ISO C bignum library.
+ * 
+ * This project is meant to fill in where LibTomMath
+ * falls short.  That is speed ;-)
+ *
+ * This project is public domain and free for all purposes.
+ * 
+ * Tom St Denis, tomstdenis@gmail.com
+ */
+#include <tfm_private.h>
+
+/* c = a mod b, 0 <= c < b  */
+int fp_mod_d(fp_int *a, fp_digit b, fp_digit *c)
+{
+   return fp_div_d(a, b, NULL, c);
+}
+
+/* $Source$ */
+/* $Revision$ */
+/* $Date$ */
diff --git a/tomsfastmath/src/exptmod/fp_2expt.c b/tomsfastmath/src/exptmod/fp_2expt.c
new file mode 100644 (file)
index 0000000..a6ed603
--- /dev/null
@@ -0,0 +1,39 @@
+/* TomsFastMath, a fast ISO C bignum library.
+ * 
+ * This project is meant to fill in where LibTomMath
+ * falls short.  That is speed ;-)
+ *
+ * This project is public domain and free for all purposes.
+ * 
+ * Tom St Denis, tomstdenis@gmail.com
+ */
+#include <tfm_private.h>
+
+/* computes a = 2**b */
+void fp_2expt(fp_int *a, int b)
+{
+   int     z;
+
+   /* zero a as per default */
+   fp_zero (a);
+
+   if (b < 0) { 
+      return;
+   }
+
+   z = b / DIGIT_BIT;
+   if (z >= FP_SIZE) {
+      return; 
+   }
+
+  /* set the used count of where the bit will go */
+  a->used = z + 1;
+
+  /* put the single bit in its place */
+  a->dp[z] = ((fp_digit)1) << (b % DIGIT_BIT);
+}
+
+
+/* $Source$ */
+/* $Revision$ */
+/* $Date$ */
diff --git a/tomsfastmath/src/exptmod/fp_exptmod.c b/tomsfastmath/src/exptmod/fp_exptmod.c
new file mode 100644 (file)
index 0000000..418a931
--- /dev/null
@@ -0,0 +1,276 @@
+/* TomsFastMath, a fast ISO C bignum library.
+ * 
+ * This project is meant to fill in where LibTomMath
+ * falls short.  That is speed ;-)
+ *
+ * This project is public domain and free for all purposes.
+ * 
+ * Tom St Denis, tomstdenis@gmail.com
+ */
+#include <tfm_private.h>
+
+#ifdef TFM_TIMING_RESISTANT
+
+/* timing resistant montgomery ladder based exptmod 
+
+   Based on work by Marc Joye, Sung-Ming Yen, "The Montgomery Powering Ladder", Cryptographic Hardware and Embedded Systems, CHES 2002
+*/
+static int _fp_exptmod(fp_int * G, fp_int * X, fp_int * P, fp_int * Y)
+{
+  fp_int   R[2];
+  fp_digit buf, mp;
+  int      err, bitcnt, digidx, y;
+
+  /* now setup montgomery  */
+  if ((err = fp_montgomery_setup (P, &mp)) != FP_OKAY) {
+     return err;
+  }
+
+  fp_init(&R[0]);   
+  fp_init(&R[1]);   
+   
+  /* now we need R mod m */
+  fp_montgomery_calc_normalization (&R[0], P);
+
+  /* now set R[0][1] to G * R mod m */
+  if (fp_cmp_mag(P, G) != FP_GT) {
+     /* G > P so we reduce it first */
+     fp_mod(G, P, &R[1]);
+  } else {
+     fp_copy(G, &R[1]);
+  }
+  fp_mulmod (&R[1], &R[0], P, &R[1]);
+
+  /* for j = t-1 downto 0 do
+        r_!k = R0*R1; r_k = r_k^2
+  */
+  
+  /* set initial mode and bit cnt */
+  bitcnt = 1;
+  buf    = 0;
+  digidx = X->used - 1;
+
+  for (;;) {
+    /* grab next digit as required */
+    if (--bitcnt == 0) {
+      /* if digidx == -1 we are out of digits so break */
+      if (digidx == -1) {
+        break;
+      }
+      /* read next digit and reset bitcnt */
+      buf    = X->dp[digidx--];
+      bitcnt = (int)DIGIT_BIT;
+    }
+
+    /* grab the next msb from the exponent */
+    y     = (fp_digit)(buf >> (DIGIT_BIT - 1)) & 1;
+    buf <<= (fp_digit)1;
+
+    /* do ops */
+    fp_mul(&R[0], &R[1], &R[y^1]); fp_montgomery_reduce(&R[y^1], P, mp);
+    fp_sqr(&R[y], &R[y]);          fp_montgomery_reduce(&R[y], P, mp);
+  }
+
+   fp_montgomery_reduce(&R[0], P, mp);
+   fp_copy(&R[0], Y);
+   return FP_OKAY;
+}   
+
+#else
+
+/* y = g**x (mod b) 
+ * Some restrictions... x must be positive and < b
+ */
+static int _fp_exptmod(fp_int * G, fp_int * X, fp_int * P, fp_int * Y)
+{
+  fp_int   M[64], res;
+  fp_digit buf, mp;
+  int      err, bitbuf, bitcpy, bitcnt, mode, digidx, x, y, winsize;
+
+  /* find window size */
+  x = fp_count_bits (X);
+  if (x <= 21) {
+    winsize = 1;
+  } else if (x <= 36) {
+    winsize = 3;
+  } else if (x <= 140) {
+    winsize = 4;
+  } else if (x <= 450) {
+    winsize = 5;
+  } else {
+    winsize = 6;
+  } 
+
+  /* init M array */
+  memset(M, 0, sizeof(M)); 
+
+  /* now setup montgomery  */
+  if ((err = fp_montgomery_setup (P, &mp)) != FP_OKAY) {
+     return err;
+  }
+
+  /* setup result */
+  fp_init(&res);
+
+  /* create M table
+   *
+   * The M table contains powers of the input base, e.g. M[x] = G^x mod P
+   *
+   * The first half of the table is not computed though accept for M[0] and M[1]
+   */
+
+   /* now we need R mod m */
+   fp_montgomery_calc_normalization (&res, P);
+
+   /* now set M[1] to G * R mod m */
+   if (fp_cmp_mag(P, G) != FP_GT) {
+      /* G > P so we reduce it first */
+      fp_mod(G, P, &M[1]);
+   } else {
+      fp_copy(G, &M[1]);
+   }
+   fp_mulmod (&M[1], &res, P, &M[1]);
+
+  /* compute the value at M[1<<(winsize-1)] by squaring M[1] (winsize-1) times */
+  fp_copy (&M[1], &M[1 << (winsize - 1)]);
+  for (x = 0; x < (winsize - 1); x++) {
+    fp_sqr (&M[1 << (winsize - 1)], &M[1 << (winsize - 1)]);
+    fp_montgomery_reduce (&M[1 << (winsize - 1)], P, mp);
+  }
+
+  /* create upper table */
+  for (x = (1 << (winsize - 1)) + 1; x < (1 << winsize); x++) {
+    fp_mul(&M[x - 1], &M[1], &M[x]);
+    fp_montgomery_reduce(&M[x], P, mp);
+  }
+
+  /* set initial mode and bit cnt */
+  mode   = 0;
+  bitcnt = 1;
+  buf    = 0;
+  digidx = X->used - 1;
+  bitcpy = 0;
+  bitbuf = 0;
+
+  for (;;) {
+    /* grab next digit as required */
+    if (--bitcnt == 0) {
+      /* if digidx == -1 we are out of digits so break */
+      if (digidx == -1) {
+        break;
+      }
+      /* read next digit and reset bitcnt */
+      buf    = X->dp[digidx--];
+      bitcnt = (int)DIGIT_BIT;
+    }
+
+    /* grab the next msb from the exponent */
+    y     = (fp_digit)(buf >> (DIGIT_BIT - 1)) & 1;
+    buf <<= (fp_digit)1;
+
+    /* if the bit is zero and mode == 0 then we ignore it
+     * These represent the leading zero bits before the first 1 bit
+     * in the exponent.  Technically this opt is not required but it
+     * does lower the # of trivial squaring/reductions used
+     */
+    if (mode == 0 && y == 0) {
+      continue;
+    }
+
+    /* if the bit is zero and mode == 1 then we square */
+    if (mode == 1 && y == 0) {
+      fp_sqr(&res, &res);
+      fp_montgomery_reduce(&res, P, mp);
+      continue;
+    }
+
+    /* else we add it to the window */
+    bitbuf |= (y << (winsize - ++bitcpy));
+    mode    = 2;
+
+    if (bitcpy == winsize) {
+      /* ok window is filled so square as required and multiply  */
+      /* square first */
+      for (x = 0; x < winsize; x++) {
+        fp_sqr(&res, &res);
+        fp_montgomery_reduce(&res, P, mp);
+      }
+
+      /* then multiply */
+      fp_mul(&res, &M[bitbuf], &res);
+      fp_montgomery_reduce(&res, P, mp);
+
+      /* empty window and reset */
+      bitcpy = 0;
+      bitbuf = 0;
+      mode   = 1;
+    }
+  }
+
+  /* if bits remain then square/multiply */
+  if (mode == 2 && bitcpy > 0) {
+    /* square then multiply if the bit is set */
+    for (x = 0; x < bitcpy; x++) {
+      fp_sqr(&res, &res);
+      fp_montgomery_reduce(&res, P, mp);
+
+      /* get next bit of the window */
+      bitbuf <<= 1;
+      if ((bitbuf & (1 << winsize)) != 0) {
+        /* then multiply */
+        fp_mul(&res, &M[1], &res);
+        fp_montgomery_reduce(&res, P, mp);
+      }
+    }
+  }
+
+  /* fixup result if Montgomery reduction is used
+   * recall that any value in a Montgomery system is
+   * actually multiplied by R mod n.  So we have
+   * to reduce one more time to cancel out the factor
+   * of R.
+   */
+  fp_montgomery_reduce(&res, P, mp);
+
+  /* swap res with Y */
+  fp_copy (&res, Y);
+  return FP_OKAY;
+}
+
+#endif
+
+
+int fp_exptmod(fp_int * G, fp_int * X, fp_int * P, fp_int * Y)
+{
+   fp_int tmp;
+   int    err;
+   
+#ifdef TFM_CHECK
+   /* prevent overflows */
+   if (P->used > (FP_SIZE/2)) {
+      return FP_VAL;
+   }
+#endif
+
+   /* is X negative?  */
+   if (X->sign == FP_NEG) {
+      /* yes, copy G and invmod it */
+      fp_copy(G, &tmp);
+      if ((err = fp_invmod(&tmp, P, &tmp)) != FP_OKAY) {
+         return err;
+      }
+      X->sign = FP_ZPOS;
+      err =  _fp_exptmod(&tmp, X, P, Y);
+      if (X != Y) {
+         X->sign = FP_NEG;
+      }
+      return err;
+   } else {
+      /* Positive exponent so just exptmod */
+      return _fp_exptmod(G, X, P, Y);
+   }
+}
+
+/* $Source$ */
+/* $Revision$ */
+/* $Date$ */
diff --git a/tomsfastmath/src/generators/comba_mont_gen.c b/tomsfastmath/src/generators/comba_mont_gen.c
new file mode 100644 (file)
index 0000000..04870e3
--- /dev/null
@@ -0,0 +1,132 @@
+#include <stdio.h>
+
+int main(void)
+{
+   int x, y, z;
+
+printf(
+#if 1
+"#ifdef TFM_SMALL_SET\n"
+"/* computes x/R == x (mod N) via Montgomery Reduction */\n"
+"void fp_montgomery_reduce_small(fp_int *a, fp_int *m, fp_digit mp)\n"
+"{\n"
+"   fp_digit c[FP_SIZE], *_c, *tmpm, mu, cy;\n"
+"   int      oldused, x, y, pa;\n"
+"\n"
+"#if defined(USE_MEMSET)\n"
+"   /* now zero the buff */\n"
+"   memset(c, 0, sizeof c);\n"
+"#endif\n"
+"   pa = m->used;\n"
+"\n"
+"   /* copy the input */\n"
+"   oldused = a->used;\n"
+"   for (x = 0; x < oldused; x++) {\n"
+"       c[x] = a->dp[x];\n"
+"   }\n"
+"#if !defined(USE_MEMSET)\n"
+"   for (; x < 2*pa+3; x++) {\n"
+"       c[x] = 0;\n"
+"   }\n"
+"#endif\n"
+"   MONT_START;\n"
+#endif
+"\n"
+"   switch (pa) {\n");
+
+for (x = 1; x <= 16; x++) {
+if (x > 16 && (x != 32 && x != 48 && x != 64)) continue;
+if (x > 16) printf("#ifdef TFM_HUGE\n");
+
+
+
+printf("      case %d:\n", x);
+
+for (y = 0; y < x; y++) {
+
+printf("            x = %d; cy   = 0;\n"
+       "            LOOP_START;\n"
+       "            _c   = c + %d;\n"
+       "            tmpm = m->dp;\n", y, y);
+
+printf("#ifdef INNERMUL8\n");
+for (z = 0; z+8 <= x; z += 8) {
+printf("            INNERMUL8; _c += 8; tmpm += 8;\n");
+}
+for (; z < x; z++) {
+printf("            INNERMUL; ++_c;\n");
+}
+printf("#else\n");
+for (z = 0; z < x; z++) {
+printf("            INNERMUL; ++_c;\n");
+}
+printf("#endif\n");
+printf("            LOOP_END;\n"
+       "            while (cy) {\n"
+       "               PROPCARRY;\n"
+       "               ++_c;\n"
+       "            }\n");
+}
+//printf("         }\n");
+printf("         break;\n");
+
+
+
+#define LOOP_MACRO(stride)                                 \
+   for (x = 0; x < stride; x++) {                          \
+       fp_digit cy = 0;                                    \
+       /* get Mu for this round */                         \
+       LOOP_START;                                         \
+       _c   = c + x;                                       \
+       tmpm = m->dp;                                       \
+       for (y = 0; y < stride; y++) {                      \
+          INNERMUL;                                        \
+          ++_c;                                            \
+       }                                                   \
+       LOOP_END;                                           \
+       while (cy) {                                        \
+           PROPCARRY;                                      \
+           ++_c;                                           \
+       }                                                   \
+  }         
+
+
+
+
+
+if (x > 16) printf("#endif /* TFM_HUGE */\n");
+
+
+}
+
+#if 1
+
+printf(
+"  }\n"
+"  /* now copy out */\n"
+"  _c   = c + pa;\n"
+"  tmpm = a->dp;\n"
+"  for (x = 0; x < pa+1; x++) {\n"
+"     *tmpm++ = *_c++;\n"
+"  }\n"
+"\n"
+"  for (; x < oldused; x++)   {\n"
+"     *tmpm++ = 0;\n"
+"  }\n"
+"\n"
+"  MONT_FINI;\n"
+"\n"
+"  a->used = pa+1;\n"
+"  fp_clamp(a);\n"
+"\n"  
+"  /* if A >= m then A = A - m */\n"
+"  if (fp_cmp_mag (a, m) != FP_LT) {\n"
+"    s_fp_sub (a, m, a);\n"
+"  }\n"
+"}\n\n#endif\n");
+
+#endif
+
+
+return 0;
+}
diff --git a/tomsfastmath/src/generators/comba_mult_gen.c b/tomsfastmath/src/generators/comba_mult_gen.c
new file mode 100644 (file)
index 0000000..cde8f2f
--- /dev/null
@@ -0,0 +1,71 @@
+/* TomsFastMath, a fast ISO C bignum library.
+ *
+ * This project is meant to fill in where LibTomMath
+ * falls short.  That is speed ;-)
+ *
+ * This project is public domain and free for all purposes.
+ *
+ * Tom St Denis, tomstdenis@gmail.com
+ */
+
+/* program emits a NxN comba multiplier */
+#include <stdio.h>
+
+int main(int argc, char **argv)
+{
+   int N, x, y, z;
+   N = atoi(argv[1]);
+
+   /* print out preamble */
+printf(
+"#define TFM_DEFINES\n"
+"#include \"fp_mul_comba.c\"\n"
+"\n"
+"#if defined(TFM_MUL%d) && FP_SIZE >= %d\n"
+"void fp_mul_comba%d(fp_int *A, fp_int *B, fp_int *C)\n"
+"{\n"
+"   fp_digit c0, c1, c2, at[%d];\n"
+"\n"
+"   memcpy(at, A->dp, %d * sizeof(fp_digit));\n"
+"   memcpy(at+%d, B->dp, %d * sizeof(fp_digit));\n"
+"   COMBA_START;\n"
+"\n"
+"   COMBA_CLEAR;\n", N, N+N, N, N+N, N, N, N);
+
+   /* now do the rows */
+   for (x = 0; x < (N+N-1); x++) {
+printf(
+"   /* %d */\n", x);
+if (x > 0) {
+printf(
+"   COMBA_FORWARD;\n");
+}
+      for (y = 0; y < N; y++) {
+      for (z = 0; z < N; z++) {
+          if ((y+z)==x) {
+             printf("   MULADD(at[%d], at[%d]); ", y, z+N);
+          }
+      }
+      }
+printf(
+"\n"
+"   COMBA_STORE(C->dp[%d]);\n", x);
+   }
+printf(
+"   COMBA_STORE2(C->dp[%d]);\n"
+"   C->used = %d;\n"
+"   C->sign = A->sign ^ B->sign;\n"
+"   fp_clamp(C);\n"
+"   COMBA_FINI;\n"
+"}\n#endif\n\n\n"
+"/* $Source$ */\n"
+"/* $Revision$ */\n"
+"/* $Date$ */\n"
+, N+N-1, N+N);
+
+  return 0;
+}
+
+/* $Source$ */
+/* $Revision$ */
+/* $Date$ */
diff --git a/tomsfastmath/src/generators/comba_mult_smallgen.c b/tomsfastmath/src/generators/comba_mult_smallgen.c
new file mode 100644 (file)
index 0000000..db9fddb
--- /dev/null
@@ -0,0 +1,68 @@
+/* program emits a NxN comba multiplier for 1x1 to 16x16 */
+#include <stdio.h>
+
+int main(int argc, char **argv)
+{
+   int N, x, y, z;
+
+   /* print out preamble */
+printf(
+"#define TFM_DEFINES\n"
+"#include \"fp_mul_comba.c\"\n"
+"\n"
+"#if defined(TFM_SMALL_SET)\n"
+"void fp_mul_comba_small(fp_int *A, fp_int *B, fp_int *C)\n"
+"{\n"
+"   fp_digit c0, c1, c2, at[32];\n"
+"   switch (MAX(A->used, B->used)) { \n"
+);
+
+for (N = 1; N <= 16; N++) {
+
+printf(
+"\n"
+"   case %d:\n"
+"      memcpy(at, A->dp, %d * sizeof(fp_digit));\n"
+"      memcpy(at+%d, B->dp, %d * sizeof(fp_digit));\n"
+"      COMBA_START;\n"
+"\n"
+"      COMBA_CLEAR;\n", N, N, N, N);
+
+   /* now do the rows */
+   for (x = 0; x < (N+N-1); x++) {
+printf(
+"      /* %d */\n", x);
+if (x > 0) {
+printf(
+"      COMBA_FORWARD;\n");
+}
+      for (y = 0; y < N; y++) {
+      for (z = 0; z < N; z++) {
+          if ((y+z)==x) {
+             printf("      MULADD(at[%d], at[%d]); ", y, z+N);
+          }
+      }
+      }
+printf(
+"\n"
+"      COMBA_STORE(C->dp[%d]);\n", x);
+   }
+printf(
+"      COMBA_STORE2(C->dp[%d]);\n"
+"      C->used = %d;\n"
+"      C->sign = A->sign ^ B->sign;\n"
+"      fp_clamp(C);\n"
+"      COMBA_FINI;\n"
+"      break;\n", N+N-1, N+N);
+}
+printf("   }\n}\n\n#endif\n\n\n"
+"/* $Source$ */\n"
+"/* $Revision$ */\n"
+"/* $Date$ */\n");
+
+  return 0;
+}
+
+/* $Source$ */
+/* $Revision$ */
+/* $Date$ */
diff --git a/tomsfastmath/src/generators/comba_sqr_gen.c b/tomsfastmath/src/generators/comba_sqr_gen.c
new file mode 100644 (file)
index 0000000..8ebe650
--- /dev/null
@@ -0,0 +1,112 @@
+/* TomsFastMath, a fast ISO C bignum library.
+ *
+ * This project is meant to fill in where LibTomMath
+ * falls short.  That is speed ;-)
+ *
+ * This project is public domain and free for all purposes.
+ *
+ * Tom St Denis, tomstdenis@gmail.com
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+int main(int argc, char **argv)
+{
+   int x, y, z, N, f;
+   N = atoi(argv[1]);
+
+printf(
+"#define TFM_DEFINES\n"
+"#include \"fp_sqr_comba.c\"\n"
+"\n"
+"#if defined(TFM_SQR%d) && FP_SIZE >= %d\n"
+"void fp_sqr_comba%d(fp_int *A, fp_int *B)\n"
+"{\n"
+"   fp_digit *a, b[%d], c0, c1, c2, sc0, sc1, sc2;\n"
+"#ifdef TFM_ISO\n"
+"   fp_word tt;\n"
+"#endif\n"
+"\n"
+"   a = A->dp;\n"
+"   COMBA_START;\n"
+"\n"
+"   /* clear carries */\n"
+"   CLEAR_CARRY;\n"
+"\n"
+"   /* output 0 */\n"
+"   SQRADD(a[0],a[0]);\n"
+"   COMBA_STORE(b[0]);\n", N, N+N, N, N+N);
+
+   for (x = 1; x < N+N-1; x++) {
+printf(
+"\n   /* output %d */\n"
+"   CARRY_FORWARD;\n   ", x);
+
+       for (f = y = 0; y < N; y++) {
+           for (z = 0; z < N; z++) {
+               if (z != y && z + y == x && y <= z) {
+                  ++f;
+               }
+           }
+       }
+
+   if (f <= 2) {
+       for (y = 0; y < N; y++) {
+           for (z = 0; z < N; z++) {
+               if (y<=z && (y+z)==x) {
+                  if (y == z) {
+                     printf("SQRADD(a[%d], a[%d]); ", y, y);
+                  } else {
+                     printf("SQRADD2(a[%d], a[%d]); ", y, z);
+                  }
+               }
+           }
+       }
+   } else {
+      // new method
+      /* do evens first */
+       f = 0;
+       for (y = 0; y < N; y++) {
+           for (z = 0; z < N; z++) {
+               if (z != y && z + y == x && y <= z) {
+                  if (f == 0) {
+                     // first double
+                     printf("SQRADDSC(a[%d], a[%d]); ", y, z);
+                     f = 1;
+                  } else {
+                     printf("SQRADDAC(a[%d], a[%d]); ", y, z);
+                  }
+               }
+           }
+       }
+       // forward the carry
+       printf("SQRADDDB; ");
+       if ((x&1) == 0) {
+          // add the square
+          printf("SQRADD(a[%d], a[%d]); ", x/2, x/2);
+       }
+    }
+printf("\n   COMBA_STORE(b[%d]);\n", x);
+   }
+printf("   COMBA_STORE2(b[%d]);\n", N+N-1);
+
+printf(
+"   COMBA_FINI;\n"
+"\n"
+"   B->used = %d;\n"
+"   B->sign = FP_ZPOS;\n"
+"   memcpy(B->dp, b, %d * sizeof(fp_digit));\n"
+"   fp_clamp(B);\n"
+"}\n#endif\n\n\n"
+"/* $Source$ */\n"
+"/* $Revision$ */\n"
+"/* $Date$ */\n"
+, N+N, N+N);
+
+  return 0;
+}
+
+/* $Source$ */
+/* $Revision$ */
+/* $Date$ */
diff --git a/tomsfastmath/src/generators/comba_sqr_smallgen.c b/tomsfastmath/src/generators/comba_sqr_smallgen.c
new file mode 100644 (file)
index 0000000..f5dc3e5
--- /dev/null
@@ -0,0 +1,120 @@
+/* TomsFastMath, a fast ISO C bignum library.
+ *
+ * This project is meant to fill in where LibTomMath
+ * falls short.  That is speed ;-)
+ *
+ * This project is public domain and free for all purposes.
+ *
+ * Tom St Denis, tomstdenis@gmail.com
+ */
+
+/* Generates squaring comba code... it learns it knows our secrets! */
+#include <stdio.h>
+
+int main(int argc, char **argv)
+{
+   int x, y, z, N, f;
+
+printf(
+"#define TFM_DEFINES\n"
+"#include \"fp_sqr_comba.c\"\n"
+"\n"
+"#if defined(TFM_SMALL_SET)\n"
+"void fp_sqr_comba_small(fp_int *A, fp_int *B)\n"
+"{\n"
+"   fp_digit *a, b[32], c0, c1, c2, sc0, sc1, sc2;\n"
+"#ifdef TFM_ISO\n"
+"   fp_word tt;\n"
+"#endif\n"
+);
+
+printf("   switch (A->used) { \n");
+
+for (N = 1; N <= 16; N++) {
+printf(
+"   case %d:\n"
+"      a = A->dp;\n"
+"      COMBA_START; \n"
+"\n"
+"      /* clear carries */\n"
+"      CLEAR_CARRY;\n"
+"\n"
+"      /* output 0 */\n"
+"      SQRADD(a[0],a[0]);\n"
+"      COMBA_STORE(b[0]);\n", N);
+
+   for (x = 1; x < N+N-1; x++) {
+printf(
+"\n      /* output %d */\n"
+"      CARRY_FORWARD;\n   ", x);
+
+       for (f = y = 0; y < N; y++) {
+           for (z = 0; z < N; z++) {
+               if (z != y && z + y == x && y <= z) {
+                  ++f;
+               }
+           }
+       }
+
+   if (f <= 2) {
+       for (y = 0; y < N; y++) {
+           for (z = 0; z < N; z++) {
+               if (y<=z && (y+z)==x) {
+                  if (y == z) {
+                     printf("   SQRADD(a[%d], a[%d]); ", y, y);
+                  } else {
+                     printf("   SQRADD2(a[%d], a[%d]); ", y, z);
+                  }
+               }
+           }
+       }
+   } else {
+      // new method
+      /* do evens first */
+       f = 0;
+       for (y = 0; y < N; y++) {
+           for (z = 0; z < N; z++) {
+               if (z != y && z + y == x && y <= z) {
+                  if (f == 0) {
+                     // first double
+                     printf("SQRADDSC(a[%d], a[%d]); ", y, z);
+                     f = 1;
+                  } else {
+                     printf("SQRADDAC(a[%d], a[%d]); ", y, z);
+                  }
+               }
+           }
+       }
+       // forward the carry
+       printf("SQRADDDB; ");
+       if ((x&1) == 0) {
+          // add the square
+          printf("SQRADD(a[%d], a[%d]); ", x/2, x/2);
+       }
+    }
+printf("\n      COMBA_STORE(b[%d]);\n", x);
+   }
+printf("      COMBA_STORE2(b[%d]);\n", N+N-1);
+
+printf(
+"      COMBA_FINI;\n"
+"\n"
+"      B->used = %d;\n"
+"      B->sign = FP_ZPOS;\n"
+"      memcpy(B->dp, b, %d * sizeof(fp_digit));\n"
+"      fp_clamp(B);\n"
+"      break;\n\n", N+N, N+N);
+}
+
+printf("}\n}\n\n#endif /* TFM_SMALL_SET */\n\n"
+"/* $Source$ */\n"
+"/* $Revision$ */\n"
+"/* $Date$ */\n"
+);
+
+  return 0;
+}
+
+/* $Source$ */
+/* $Revision$ */
+/* $Date$ */
diff --git a/tomsfastmath/src/headers/tfm.h b/tomsfastmath/src/headers/tfm.h
new file mode 100644 (file)
index 0000000..8230c33
--- /dev/null
@@ -0,0 +1,501 @@
+/* TomsFastMath, a fast ISO C bignum library.
+ *
+ * This project is meant to fill in where LibTomMath
+ * falls short.  That is speed ;-)
+ *
+ * This project is public domain and free for all purposes.
+ *
+ * Tom St Denis, tomstdenis@gmail.com
+ */
+#ifndef TFM_H_
+#define TFM_H_
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <limits.h>
+
+/* 0xMaMiPaXX
+ * Major
+ * Minor
+ * Patch
+ * XX - undefined
+ */
+#define TFM_VERSION     0x000D0100
+#define TFM_VERSION_S   "v0.13.1"
+
+#ifndef MIN
+   #define MIN(x,y) ((x)<(y)?(x):(y))
+#endif
+
+#ifndef MAX
+   #define MAX(x,y) ((x)>(y)?(x):(y))
+#endif
+
+/* externally define this symbol to ignore the default settings, useful for changing the build from the make process */
+#ifndef TFM_ALREADY_SET
+
+/* do we want the large set of small multiplications ?
+   Enable these if you are going to be doing a lot of small (<= 16 digit) multiplications say in ECC
+   Or if you're on a 64-bit machine doing RSA as a 1024-bit integer == 16 digits ;-)
+ */
+#define TFM_SMALL_SET
+
+/* do we want huge code
+   Enable these if you are doing 20, 24, 28, 32, 48, 64 digit multiplications (useful for RSA)
+   Less important on 64-bit machines as 32 digits == 2048 bits
+ */
+#if 0
+#define TFM_MUL3
+#define TFM_MUL4
+#define TFM_MUL6
+#define TFM_MUL7
+#define TFM_MUL8
+#define TFM_MUL9
+#define TFM_MUL12
+#define TFM_MUL17
+#endif
+#define TFM_MUL20
+#define TFM_MUL24
+#define TFM_MUL28
+#define TFM_MUL32
+#define TFM_MUL48
+#define TFM_MUL64
+
+#if 0
+#define TFM_SQR3
+#define TFM_SQR4
+#define TFM_SQR6
+#define TFM_SQR7
+#define TFM_SQR8
+#define TFM_SQR9
+#define TFM_SQR12
+#define TFM_SQR17
+#endif
+#define TFM_SQR20
+#define TFM_SQR24
+#define TFM_SQR28
+#define TFM_SQR32
+#define TFM_SQR48
+#define TFM_SQR64
+
+/* do we want some overflow checks
+   Not required if you make sure your numbers are within range (e.g. by default a modulus for fp_exptmod() can only be upto 2048 bits long)
+ */
+/* #define TFM_CHECK */
+
+/* Is the target a P4 Prescott
+ */
+/* #define TFM_PRESCOTT */
+
+/* Do we want timing resistant fp_exptmod() ?
+ * This makes it slower but also timing invariant with respect to the exponent
+ */
+/* #define TFM_TIMING_RESISTANT */
+
+#endif
+
+/* Max size of any number in bits.  Basically the largest size you will be multiplying
+ * should be half [or smaller] of FP_MAX_SIZE-four_digit
+ *
+ * You can externally define this or it defaults to 4096-bits [allowing multiplications upto 2048x2048 bits ]
+ */
+#ifndef FP_MAX_SIZE
+   #define FP_MAX_SIZE           (4*4096+(8*DIGIT_BIT))
+#endif
+
+/* will this lib work? */
+#if (CHAR_BIT & 7)
+   #error CHAR_BIT must be a multiple of eight.
+#endif
+#if FP_MAX_SIZE % CHAR_BIT
+   #error FP_MAX_SIZE must be a multiple of CHAR_BIT
+#endif
+
+#if 0
+#if __SIZEOF_LONG__ == 8
+       #define FP_64BIT
+#endif
+#endif
+
+/* autodetect x86-64 and make sure we are using 64-bit digits with x86-64 asm */
+#if defined(__x86_64__)
+   #if defined(TFM_X86) || defined(TFM_SSE2) || defined(TFM_ARM)
+       #error x86-64 detected, x86-32/SSE2/ARM optimizations are not valid!
+   #endif
+   #if !defined(TFM_X86_64) && !defined(TFM_NO_ASM)
+      #define TFM_X86_64
+   #endif
+#endif
+#if defined(TFM_X86_64)
+    #if !defined(FP_64BIT)
+       #define FP_64BIT
+    #endif
+#endif
+
+/* try to detect x86-32 */
+#if defined(__i386__) && !defined(TFM_SSE2)
+   #if defined(TFM_X86_64) || defined(TFM_ARM)
+       #error x86-32 detected, x86-64/ARM optimizations are not valid!
+   #endif
+   #if !defined(TFM_X86) && !defined(TFM_NO_ASM)
+      #define TFM_X86
+   #endif
+#endif
+
+/* make sure we're 32-bit for x86-32/sse/arm/ppc32 */
+#if (defined(TFM_X86) || defined(TFM_SSE2) || defined(TFM_ARM) || defined(TFM_PPC32)) && defined(FP_64BIT)
+   #warning x86-32, SSE2 and ARM, PPC32 optimizations require 32-bit digits (undefining)
+   #undef FP_64BIT
+#endif
+
+/* multi asms? */
+#ifdef TFM_X86
+   #define TFM_ASM
+#endif
+#ifdef TFM_X86_64
+   #ifdef TFM_ASM
+      #error TFM_ASM already defined!
+   #endif
+   #define TFM_ASM
+#endif
+#ifdef TFM_SSE2
+   #ifdef TFM_ASM
+      #error TFM_ASM already defined!
+   #endif
+   #define TFM_ASM
+#endif
+#ifdef TFM_ARM
+   #ifdef TFM_ASM
+      #error TFM_ASM already defined!
+   #endif
+   #define TFM_ASM
+#endif
+#ifdef TFM_PPC32
+   #ifdef TFM_ASM
+      #error TFM_ASM already defined!
+   #endif
+   #define TFM_ASM
+#endif
+#ifdef TFM_PPC64
+   #ifdef TFM_ASM
+      #error TFM_ASM already defined!
+   #endif
+   #define TFM_ASM
+#endif
+#ifdef TFM_AVR32
+   #ifdef TFM_ASM
+      #error TFM_ASM already defined!
+   #endif
+   #define TFM_ASM
+#endif
+
+/* we want no asm? */
+#ifdef TFM_NO_ASM
+   #undef TFM_X86
+   #undef TFM_X86_64
+   #undef TFM_SSE2
+   #undef TFM_ARM
+   #undef TFM_PPC32
+   #undef TFM_PPC64
+   #undef TFM_AVR32
+   #undef TFM_ASM
+#endif
+
+/* ECC helpers */
+#ifdef TFM_ECC192
+   #ifdef FP_64BIT
+       #define TFM_MUL3
+       #define TFM_SQR3
+   #else
+       #define TFM_MUL6
+       #define TFM_SQR6
+   #endif
+#endif
+
+#ifdef TFM_ECC224
+   #ifdef FP_64BIT
+       #define TFM_MUL4
+       #define TFM_SQR4
+   #else
+       #define TFM_MUL7
+       #define TFM_SQR7
+   #endif
+#endif
+
+#ifdef TFM_ECC256
+   #ifdef FP_64BIT
+       #define TFM_MUL4
+       #define TFM_SQR4
+   #else
+       #define TFM_MUL8
+       #define TFM_SQR8
+   #endif
+#endif
+
+#ifdef TFM_ECC384
+   #ifdef FP_64BIT
+       #define TFM_MUL6
+       #define TFM_SQR6
+   #else
+       #define TFM_MUL12
+       #define TFM_SQR12
+   #endif
+#endif
+
+#ifdef TFM_ECC521
+   #ifdef FP_64BIT
+       #define TFM_MUL9
+       #define TFM_SQR9
+   #else
+       #define TFM_MUL17
+       #define TFM_SQR17
+   #endif
+#endif
+
+/* use arc4random on platforms that support it */
+#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__)
+    #define FP_GEN_RANDOM()    arc4random()
+    #define FP_GEN_RANDOM_MAX  0xffffffff
+#endif
+
+/* use rand() as fall-back if there's no better rand function */
+#ifndef FP_GEN_RANDOM
+   #define FP_GEN_RANDOM()    rand()
+   #define FP_GEN_RANDOM_MAX  RAND_MAX
+#endif
+
+/* some default configurations.
+ */
+#if defined(FP_64BIT)
+#error cannot use 128 bit words
+   /* for GCC only on supported platforms */
+#ifndef CRYPT
+   typedef unsigned long long ulong64;
+#endif /* CRYPT */
+
+   typedef ulong64            fp_digit;
+#define SIZEOF_FP_DIGIT 8
+   typedef unsigned long      fp_word __attribute__ ((mode(TI)));
+
+#else
+
+   /* this is to make porting into LibTomCrypt easier :-) */
+#ifndef CRYPT
+   #if defined(_MSC_VER) || defined(__BORLANDC__)
+      typedef unsigned __int64   ulong64;
+      typedef signed __int64     long64;
+   #else
+      typedef unsigned long long ulong64;
+      typedef signed long long   long64;
+   #endif /* defined(_MSC_VER) ... */
+#endif /* CRYPT */
+
+   typedef unsigned int       fp_digit;
+#define SIZEOF_FP_DIGIT 4
+   typedef ulong64            fp_word;
+#endif /* FP_64BIT */
+
+/* # of digits this is */
+#define DIGIT_BIT  ((CHAR_BIT) * SIZEOF_FP_DIGIT)
+#define FP_MASK    (fp_digit)(-1)
+#define FP_SIZE    (FP_MAX_SIZE/DIGIT_BIT)
+
+/* signs */
+#define FP_ZPOS     0
+#define FP_NEG      1
+
+/* return codes */
+#define FP_OKAY     0
+#define FP_VAL      1
+#define FP_MEM      2
+
+/* equalities */
+#define FP_LT        -1   /* less than */
+#define FP_EQ         0   /* equal to */
+#define FP_GT         1   /* greater than */
+
+/* replies */
+#define FP_YES        1   /* yes response */
+#define FP_NO         0   /* no response */
+
+/* a FP type */
+typedef struct {
+    fp_digit dp[FP_SIZE];
+    int      used,
+             sign;
+} fp_int;
+
+/* functions */
+
+/* returns a TFM ident string useful for debugging... */
+const char *fp_ident(void);
+
+/* initialize [or zero] an fp int */
+#define fp_init(a)  (void)memset((a), 0, sizeof(fp_int))
+#define fp_zero(a)  fp_init(a)
+
+/* zero/even/odd ? */
+#define fp_iszero(a) (((a)->used == 0) ? FP_YES : FP_NO)
+#define fp_iseven(a) (((a)->used >= 0 && (((a)->dp[0] & 1) == 0)) ? FP_YES : FP_NO)
+#define fp_isodd(a)  (((a)->used > 0  && (((a)->dp[0] & 1) == 1)) ? FP_YES : FP_NO)
+
+/* set to a small digit */
+void fp_set(fp_int *a, fp_digit b);
+
+/* makes a pseudo-random int of a given size */
+void fp_rand(fp_int *a, int digits);
+
+/* copy from a to b */
+#define fp_copy(a, b)      (void)(((a) != (b)) && memcpy((b), (a), sizeof(fp_int)))
+#define fp_init_copy(a, b) fp_copy(b, a)
+
+/* clamp digits */
+#define fp_clamp(a)   { while ((a)->used && (a)->dp[(a)->used-1] == 0) --((a)->used); (a)->sign = (a)->used ? (a)->sign : FP_ZPOS; }
+
+/* negate and absolute */
+#define fp_neg(a, b)  { fp_copy(a, b); (b)->sign ^= 1; fp_clamp(b); }
+#define fp_abs(a, b)  { fp_copy(a, b); (b)->sign  = 0; }
+
+/* right shift x digits */
+void fp_rshd(fp_int *a, int x);
+
+/* left shift x digits */
+void fp_lshd(fp_int *a, int x);
+
+/* signed comparison */
+int fp_cmp(fp_int *a, fp_int *b);
+
+/* unsigned comparison */
+int fp_cmp_mag(fp_int *a, fp_int *b);
+
+/* power of 2 operations */
+void fp_div_2d(fp_int *a, int b, fp_int *c, fp_int *d);
+void fp_mod_2d(fp_int *a, int b, fp_int *c);
+void fp_mul_2d(fp_int *a, int b, fp_int *c);
+void fp_2expt (fp_int *a, int b);
+void fp_mul_2(fp_int *a, fp_int *c);
+void fp_div_2(fp_int *a, fp_int *c);
+
+/* Counts the number of lsbs which are zero before the first zero bit */
+int fp_cnt_lsb(fp_int *a);
+
+/* c = a + b */
+void fp_add(fp_int *a, fp_int *b, fp_int *c);
+
+/* c = a - b */
+void fp_sub(fp_int *a, fp_int *b, fp_int *c);
+
+/* c = a * b */
+void fp_mul(fp_int *a, fp_int *b, fp_int *c);
+
+/* b = a*a  */
+void fp_sqr(fp_int *a, fp_int *b);
+
+/* a/b => cb + d == a */
+int fp_div(fp_int *a, fp_int *b, fp_int *c, fp_int *d);
+
+/* c = a mod b, 0 <= c < b  */
+int fp_mod(fp_int *a, fp_int *b, fp_int *c);
+
+/* compare against a single digit */
+int fp_cmp_d(fp_int *a, fp_digit b);
+
+/* c = a + b */
+void fp_add_d(fp_int *a, fp_digit b, fp_int *c);
+
+/* c = a - b */
+void fp_sub_d(fp_int *a, fp_digit b, fp_int *c);
+
+/* c = a * b */
+void fp_mul_d(fp_int *a, fp_digit b, fp_int *c);
+
+/* a/b => cb + d == a */
+int fp_div_d(fp_int *a, fp_digit b, fp_int *c, fp_digit *d);
+
+/* c = a mod b, 0 <= c < b  */
+int fp_mod_d(fp_int *a, fp_digit b, fp_digit *c);
+
+/* ---> number theory <--- */
+/* d = a + b (mod c) */
+int fp_addmod(fp_int *a, fp_int *b, fp_int *c, fp_int *d);
+
+/* d = a - b (mod c) */
+int fp_submod(fp_int *a, fp_int *b, fp_int *c, fp_int *d);
+
+/* d = a * b (mod c) */
+int fp_mulmod(fp_int *a, fp_int *b, fp_int *c, fp_int *d);
+
+/* c = a * a (mod b) */
+int fp_sqrmod(fp_int *a, fp_int *b, fp_int *c);
+
+/* c = 1/a (mod b) */
+int fp_invmod(fp_int *a, fp_int *b, fp_int *c);
+
+/* c = (a, b) */
+void fp_gcd(fp_int *a, fp_int *b, fp_int *c);
+
+/* c = [a, b] */
+void fp_lcm(fp_int *a, fp_int *b, fp_int *c);
+
+/* setups the montgomery reduction */
+int fp_montgomery_setup(fp_int *a, fp_digit *mp);
+
+/* computes a = B**n mod b without division or multiplication useful for
+ * normalizing numbers in a Montgomery system.
+ */
+void fp_montgomery_calc_normalization(fp_int *a, fp_int *b);
+
+/* computes x/R == x (mod N) via Montgomery Reduction */
+void fp_montgomery_reduce(fp_int *a, fp_int *m, fp_digit mp);
+
+/* d = a**b (mod c) */
+int fp_exptmod(fp_int *a, fp_int *b, fp_int *c, fp_int *d);
+
+/* primality stuff */
+
+/* perform a Miller-Rabin test of a to the base b and store result in "result" */
+void fp_prime_miller_rabin (fp_int * a, fp_int * b, int *result);
+
+#define FP_PRIME_SIZE      256
+/* 256 trial divisions + 8 Miller-Rabins, returns FP_YES if probable prime  */
+int fp_isprime(fp_int *a);
+/* extended version of fp_isprime, do 't' Miller-Rabins instead of only 8 */
+int fp_isprime_ex(fp_int *a, int t);
+
+/* Primality generation flags */
+#define TFM_PRIME_BBS      0x0001 /* BBS style prime */
+#define TFM_PRIME_SAFE     0x0002 /* Safe prime (p-1)/2 == prime */
+#define TFM_PRIME_2MSB_OFF 0x0004 /* force 2nd MSB to 0 */
+#define TFM_PRIME_2MSB_ON  0x0008 /* force 2nd MSB to 1 */
+
+/* callback for fp_prime_random, should fill dst with random bytes and return how many read [upto len] */
+typedef int tfm_prime_callback(unsigned char *dst, int len, void *dat);
+
+#define fp_prime_random(a, t, size, bbs, cb, dat) fp_prime_random_ex(a, t, ((size) * 8) + 1, (bbs==1)?TFM_PRIME_BBS:0, cb, dat)
+
+int fp_prime_random_ex(fp_int *a, int t, int size, int flags, tfm_prime_callback cb, void *dat);
+
+/* radix conersions */
+int fp_count_bits(fp_int *a);
+
+int fp_unsigned_bin_size(fp_int *a);
+void fp_read_unsigned_bin(fp_int *a, const unsigned char *b, int c);
+void fp_to_unsigned_bin(fp_int *a, unsigned char *b);
+
+int fp_signed_bin_size(fp_int *a);
+void fp_read_signed_bin(fp_int *a, const unsigned char *b, int c);
+void fp_to_signed_bin(fp_int *a, unsigned char *b);
+
+int fp_read_radix(fp_int *a, const char *str, int radix);
+
+int fp_radix_size(fp_int *a, int radix, int *size);
+int fp_toradix(fp_int *a, char *str, int radix);
+int fp_toradix_n(fp_int * a, char *str, int radix, int maxlen);
+
+#endif
+
+/* $Source$ */
+/* $Revision$ */
+/* $Date$ */
diff --git a/tomsfastmath/src/headers/tfm_private.h b/tomsfastmath/src/headers/tfm_private.h
new file mode 100644 (file)
index 0000000..0afbac4
--- /dev/null
@@ -0,0 +1,125 @@
+/* TomsFastMath, a fast ISO C bignum library.
+ *
+ * This project is meant to fill in where LibTomMath
+ * falls short.  That is speed ;-)
+ *
+ * This project is public domain and free for all purposes.
+ *
+ * Tom St Denis, tomstdenis@gmail.com
+ */
+#ifndef TFM_PRIVATE_H_
+#define TFM_PRIVATE_H_
+
+#include <tfm.h>
+
+/* VARIOUS LOW LEVEL STUFFS */
+void s_fp_add(fp_int *a, fp_int *b, fp_int *c);
+void s_fp_sub(fp_int *a, fp_int *b, fp_int *c);
+void fp_reverse(unsigned char *s, int len);
+
+void fp_mul_comba(fp_int *A, fp_int *B, fp_int *C);
+
+#ifdef TFM_SMALL_SET
+void fp_mul_comba_small(fp_int *A, fp_int *B, fp_int *C);
+#endif
+
+#ifdef TFM_MUL3
+void fp_mul_comba3(fp_int *A, fp_int *B, fp_int *C);
+#endif
+#ifdef TFM_MUL4
+void fp_mul_comba4(fp_int *A, fp_int *B, fp_int *C);
+#endif
+#ifdef TFM_MUL6
+void fp_mul_comba6(fp_int *A, fp_int *B, fp_int *C);
+#endif
+#ifdef TFM_MUL7
+void fp_mul_comba7(fp_int *A, fp_int *B, fp_int *C);
+#endif
+#ifdef TFM_MUL8
+void fp_mul_comba8(fp_int *A, fp_int *B, fp_int *C);
+#endif
+#ifdef TFM_MUL9
+void fp_mul_comba9(fp_int *A, fp_int *B, fp_int *C);
+#endif
+#ifdef TFM_MUL12
+void fp_mul_comba12(fp_int *A, fp_int *B, fp_int *C);
+#endif
+#ifdef TFM_MUL17
+void fp_mul_comba17(fp_int *A, fp_int *B, fp_int *C);
+#endif
+
+#ifdef TFM_MUL20
+void fp_mul_comba20(fp_int *A, fp_int *B, fp_int *C);
+#endif
+#ifdef TFM_MUL24
+void fp_mul_comba24(fp_int *A, fp_int *B, fp_int *C);
+#endif
+#ifdef TFM_MUL28
+void fp_mul_comba28(fp_int *A, fp_int *B, fp_int *C);
+#endif
+#ifdef TFM_MUL32
+void fp_mul_comba32(fp_int *A, fp_int *B, fp_int *C);
+#endif
+#ifdef TFM_MUL48
+void fp_mul_comba48(fp_int *A, fp_int *B, fp_int *C);
+#endif
+#ifdef TFM_MUL64
+void fp_mul_comba64(fp_int *A, fp_int *B, fp_int *C);
+#endif
+
+void fp_sqr_comba(fp_int *A, fp_int *B);
+
+#ifdef TFM_SMALL_SET
+void fp_sqr_comba_small(fp_int *A, fp_int *B);
+#endif
+
+#ifdef TFM_SQR3
+void fp_sqr_comba3(fp_int *A, fp_int *B);
+#endif
+#ifdef TFM_SQR4
+void fp_sqr_comba4(fp_int *A, fp_int *B);
+#endif
+#ifdef TFM_SQR6
+void fp_sqr_comba6(fp_int *A, fp_int *B);
+#endif
+#ifdef TFM_SQR7
+void fp_sqr_comba7(fp_int *A, fp_int *B);
+#endif
+#ifdef TFM_SQR8
+void fp_sqr_comba8(fp_int *A, fp_int *B);
+#endif
+#ifdef TFM_SQR9
+void fp_sqr_comba9(fp_int *A, fp_int *B);
+#endif
+#ifdef TFM_SQR12
+void fp_sqr_comba12(fp_int *A, fp_int *B);
+#endif
+#ifdef TFM_SQR17
+void fp_sqr_comba17(fp_int *A, fp_int *B);
+#endif
+
+#ifdef TFM_SQR20
+void fp_sqr_comba20(fp_int *A, fp_int *B);
+#endif
+#ifdef TFM_SQR24
+void fp_sqr_comba24(fp_int *A, fp_int *B);
+#endif
+#ifdef TFM_SQR28
+void fp_sqr_comba28(fp_int *A, fp_int *B);
+#endif
+#ifdef TFM_SQR32
+void fp_sqr_comba32(fp_int *A, fp_int *B);
+#endif
+#ifdef TFM_SQR48
+void fp_sqr_comba48(fp_int *A, fp_int *B);
+#endif
+#ifdef TFM_SQR64
+void fp_sqr_comba64(fp_int *A, fp_int *B);
+#endif
+extern const char *fp_s_rmap;
+
+#endif
+
+/* $Source$ */
+/* $Revision$ */
+/* $Date$ */
diff --git a/tomsfastmath/src/misc/fp_ident.c b/tomsfastmath/src/misc/fp_ident.c
new file mode 100644 (file)
index 0000000..5177a54
--- /dev/null
@@ -0,0 +1,98 @@
+/* TomsFastMath, a fast ISO C bignum library.
+ *
+ * This project is meant to fill in where LibTomMath
+ * falls short.  That is speed ;-)
+ *
+ * This project is public domain and free for all purposes.
+ *
+ * Tom St Denis, tomstdenis@gmail.com
+ */
+#include <tfm_private.h>
+
+const char *fp_ident(void)
+{
+   static char buf[1024];
+
+   memset(buf, 0, sizeof(buf));
+   snprintf(buf, sizeof(buf)-1,
+"TomsFastMath " TFM_VERSION_S "\n"
+#if defined(TFM_IDENT_BUILD_DATE)
+"Built on " __DATE__ " at " __TIME__ "\n"
+#endif
+"\n"
+"Sizeofs\n"
+"\tfp_digit = %lu\n"
+"\tfp_word  = %lu\n"
+"\n"
+"FP_MAX_SIZE = %u\n"
+"\n"
+"Defines: \n"
+#ifdef __i386__
+" __i386__ "
+#endif
+#ifdef __x86_64__
+" __x86_64__ "
+#endif
+#ifdef TFM_X86
+" TFM_X86 "
+#endif
+#ifdef TFM_X86_64
+" TFM_X86_64 "
+#endif
+#ifdef TFM_SSE2
+" TFM_SSE2 "
+#endif
+#ifdef TFM_ARM
+" TFM_ARM "
+#endif
+#ifdef TFM_PPC32
+" TFM_PPC32 "
+#endif
+#ifdef TFM_AVR32
+" TFM_AVR32 "
+#endif
+#ifdef TFM_ECC192
+" TFM_ECC192 "
+#endif
+#ifdef TFM_ECC224
+" TFM_ECC224 "
+#endif
+#ifdef TFM_ECC384
+" TFM_ECC384 "
+#endif
+#ifdef TFM_ECC521
+" TFM_ECC521 "
+#endif
+
+#ifdef TFM_NO_ASM
+" TFM_NO_ASM "
+#endif
+#ifdef FP_64BIT
+" FP_64BIT "
+#endif
+#ifdef TFM_HUGE
+" TFM_HUGE "
+#endif
+"\n", (unsigned long)sizeof(fp_digit), (unsigned long)sizeof(fp_word), FP_MAX_SIZE);
+
+   if (sizeof(fp_digit) == sizeof(fp_word)) {
+      strncat(buf, "WARNING: sizeof(fp_digit) == sizeof(fp_word), this build is likely to not work properly.\n",
+              sizeof(buf) - strlen(buf) - 1);
+   }
+   return buf;
+}
+
+#ifdef STANDALONE
+
+int main(void)
+{
+   printf("%s\n", fp_ident());
+   return 0;
+}
+
+#endif
+
+
+/* $Source$ */
+/* $Revision$ */
+/* $Date$ */
diff --git a/tomsfastmath/src/misc/fp_rand.c b/tomsfastmath/src/misc/fp_rand.c
new file mode 100644 (file)
index 0000000..01198c5
--- /dev/null
@@ -0,0 +1,65 @@
+/* TomsFastMath, a fast ISO C bignum library.
+ *
+ * This project is meant to fill in where LibTomMath
+ * falls short.  That is speed ;-)
+ *
+ * This project is public domain and free for all purposes.
+ *
+ * Tom St Denis, tomstdenis@gmail.com
+ */
+#include <tfm_private.h>
+
+#if FP_GEN_RANDOM_MAX == 0xffffffff
+  #define FP_GEN_RANDOM_SHIFT  32
+#elif FP_GEN_RANDOM_MAX == 32767
+  /* SHRT_MAX */
+  #define FP_GEN_RANDOM_SHIFT  15
+#elif FP_GEN_RANDOM_MAX == 2147483647
+  /* INT_MAX */
+  #define FP_GEN_RANDOM_SHIFT  31
+#elif !defined(FP_GEN_RANDOM_SHIFT)
+#error Thou shalt define their own valid FP_GEN_RANDOM_SHIFT
+#endif
+
+/* makes a pseudo-random int of a given size */
+static fp_digit fp_gen_random(void)
+{
+  fp_digit d = 0, msk = 0;
+  do {
+    d <<= FP_GEN_RANDOM_SHIFT;
+    d |= ((fp_digit) FP_GEN_RANDOM());
+    msk <<= FP_GEN_RANDOM_SHIFT;
+    msk |= FP_GEN_RANDOM_MAX;
+  } while ((FP_MASK & msk) != FP_MASK);
+  d &= FP_MASK;
+  return d;
+}
+
+void fp_rand(fp_int *a, int digits)
+{
+   fp_digit d;
+
+   fp_zero(a);
+   if (digits <= 0) {
+     return;
+   }
+
+   /* first place a random non-zero digit */
+   do {
+     d = fp_gen_random();
+   } while (d == 0);
+
+   fp_add_d (a, d, a);
+
+   while (--digits > 0) {
+     fp_lshd (a, 1);
+     fp_add_d (a, fp_gen_random(), a);
+   }
+
+   return;
+
+}
+
+/* $Source$ */
+/* $Revision$ */
+/* $Date$ */
diff --git a/tomsfastmath/src/misc/fp_set.c b/tomsfastmath/src/misc/fp_set.c
new file mode 100644 (file)
index 0000000..5693759
--- /dev/null
@@ -0,0 +1,21 @@
+/* TomsFastMath, a fast ISO C bignum library.
+ * 
+ * This project is meant to fill in where LibTomMath
+ * falls short.  That is speed ;-)
+ *
+ * This project is public domain and free for all purposes.
+ * 
+ * Tom St Denis, tomstdenis@gmail.com
+ */
+#include <tfm_private.h>
+
+void fp_set(fp_int *a, fp_digit b)
+{
+   fp_zero(a);
+   a->dp[0] = b;
+   a->used  = a->dp[0] ? 1 : 0;
+}
+
+/* $Source$ */
+/* $Revision$ */
+/* $Date$ */
diff --git a/tomsfastmath/src/mont/fp_montgomery_calc_normalization.c b/tomsfastmath/src/mont/fp_montgomery_calc_normalization.c
new file mode 100644 (file)
index 0000000..c21c8d0
--- /dev/null
@@ -0,0 +1,43 @@
+/* TomsFastMath, a fast ISO C bignum library.
+ * 
+ * This project is meant to fill in where LibTomMath
+ * falls short.  That is speed ;-)
+ *
+ * This project is public domain and free for all purposes.
+ * 
+ * Tom St Denis, tomstdenis@gmail.com
+ */
+#include <tfm_private.h>
+
+/* computes a = B**n mod b without division or multiplication useful for
+ * normalizing numbers in a Montgomery system.
+ */
+void fp_montgomery_calc_normalization(fp_int *a, fp_int *b)
+{
+  int     x, bits;
+
+  /* how many bits of last digit does b use */
+  bits = fp_count_bits (b) % DIGIT_BIT;
+  if (!bits) bits = DIGIT_BIT;
+
+  /* compute A = B^(n-1) * 2^(bits-1) */
+  if (b->used > 1) {
+     fp_2expt (a, (b->used - 1) * DIGIT_BIT + bits - 1);
+  } else {
+     fp_set(a, 1);
+     bits = 1;
+  }
+
+  /* now compute C = A * B mod b */
+  for (x = bits - 1; x < (int)DIGIT_BIT; x++) {
+    fp_mul_2 (a, a);
+    if (fp_cmp_mag (a, b) != FP_LT) {
+      s_fp_sub (a, b, a);
+    }
+  }
+}
+
+
+/* $Source$ */
+/* $Revision$ */
+/* $Date$ */
diff --git a/tomsfastmath/src/mont/fp_montgomery_reduce.c b/tomsfastmath/src/mont/fp_montgomery_reduce.c
new file mode 100644 (file)
index 0000000..7222e44
--- /dev/null
@@ -0,0 +1,552 @@
+/* TomsFastMath, a fast ISO C bignum library.
+ *
+ * This project is meant to fill in where LibTomMath
+ * falls short.  That is speed ;-)
+ *
+ * This project is public domain and free for all purposes.
+ *
+ * Tom St Denis, tomstdenis@gmail.com
+ */
+#include <tfm_private.h>
+
+/******************************************************************/
+#if defined(TFM_X86) && !defined(TFM_SSE2)
+/* x86-32 code */
+
+#define MONT_START
+#define MONT_FINI
+#define LOOP_END
+#define LOOP_START \
+   mu = c[x] * mp
+
+#define INNERMUL                                          \
+asm(                                                      \
+   "movl %5,%%eax \n\t"                                   \
+   "mull %4       \n\t"                                   \
+   "addl %1,%%eax \n\t"                                   \
+   "adcl $0,%%edx \n\t"                                   \
+   "addl %%eax,%0 \n\t"                                   \
+   "adcl $0,%%edx \n\t"                                   \
+   "movl %%edx,%1 \n\t"                                   \
+:"=g"(_c[LO]), "=r"(cy)                                   \
+:"0"(_c[LO]), "1"(cy), "r"(mu), "r"(*tmpm++)              \
+: "%eax", "%edx", "cc")
+
+#define PROPCARRY                           \
+asm(                                        \
+   "addl   %1,%0    \n\t"                   \
+   "setb   %%al     \n\t"                   \
+   "movzbl %%al,%1 \n\t"                    \
+:"=g"(_c[LO]), "=r"(cy)                     \
+:"0"(_c[LO]), "1"(cy)                       \
+: "%eax", "cc")
+
+/******************************************************************/
+#elif defined(TFM_X86_64)
+/* x86-64 code */
+
+#define MONT_START
+#define MONT_FINI
+#define LOOP_END
+#define LOOP_START \
+   mu = c[x] * mp
+
+#define INNERMUL                                          \
+asm(                                                      \
+   "movq %5,%%rax \n\t"                                   \
+   "mulq %4       \n\t"                                   \
+   "addq %1,%%rax \n\t"                                   \
+   "adcq $0,%%rdx \n\t"                                   \
+   "addq %%rax,%0 \n\t"                                   \
+   "adcq $0,%%rdx \n\t"                                   \
+   "movq %%rdx,%1 \n\t"                                   \
+:"=g"(_c[LO]), "=r"(cy)                                   \
+:"0"(_c[LO]), "1"(cy), "r"(mu), "r"(*tmpm++)              \
+: "%rax", "%rdx", "cc")
+
+#define INNERMUL8 \
+ asm(                  \
+ "movq 0(%5),%%rax    \n\t"  \
+ "movq 0(%2),%%r10    \n\t"  \
+ "movq 0x8(%5),%%r11  \n\t"  \
+ "mulq %4             \n\t"  \
+ "addq %%r10,%%rax    \n\t"  \
+ "adcq $0,%%rdx       \n\t"  \
+ "movq 0x8(%2),%%r10  \n\t"  \
+ "addq %3,%%rax       \n\t"  \
+ "adcq $0,%%rdx       \n\t"  \
+ "movq %%rax,0(%0)    \n\t"  \
+ "movq %%rdx,%1       \n\t"  \
+ \
+ "movq %%r11,%%rax    \n\t"  \
+ "movq 0x10(%5),%%r11 \n\t"  \
+ "mulq %4             \n\t"  \
+ "addq %%r10,%%rax    \n\t"  \
+ "adcq $0,%%rdx       \n\t"  \
+ "movq 0x10(%2),%%r10 \n\t"  \
+ "addq %3,%%rax       \n\t"  \
+ "adcq $0,%%rdx       \n\t"  \
+ "movq %%rax,0x8(%0)  \n\t"  \
+ "movq %%rdx,%1       \n\t"  \
+ \
+ "movq %%r11,%%rax    \n\t"  \
+ "movq 0x18(%5),%%r11 \n\t"  \
+ "mulq %4             \n\t"  \
+ "addq %%r10,%%rax    \n\t"  \
+ "adcq $0,%%rdx       \n\t"  \
+ "movq 0x18(%2),%%r10 \n\t"  \
+ "addq %3,%%rax       \n\t"  \
+ "adcq $0,%%rdx       \n\t"  \
+ "movq %%rax,0x10(%0) \n\t"  \
+ "movq %%rdx,%1       \n\t"  \
+ \
+ "movq %%r11,%%rax    \n\t"  \
+ "movq 0x20(%5),%%r11 \n\t"  \
+ "mulq %4             \n\t"  \
+ "addq %%r10,%%rax    \n\t"  \
+ "adcq $0,%%rdx       \n\t"  \
+ "movq 0x20(%2),%%r10 \n\t"  \
+ "addq %3,%%rax       \n\t"  \
+ "adcq $0,%%rdx       \n\t"  \
+ "movq %%rax,0x18(%0) \n\t"  \
+ "movq %%rdx,%1       \n\t"  \
+ \
+ "movq %%r11,%%rax    \n\t"  \
+ "movq 0x28(%5),%%r11 \n\t"  \
+ "mulq %4             \n\t"  \
+ "addq %%r10,%%rax    \n\t"  \
+ "adcq $0,%%rdx       \n\t"  \
+ "movq 0x28(%2),%%r10 \n\t"  \
+ "addq %3,%%rax       \n\t"  \
+ "adcq $0,%%rdx       \n\t"  \
+ "movq %%rax,0x20(%0) \n\t"  \
+ "movq %%rdx,%1       \n\t"  \
+ \
+ "movq %%r11,%%rax    \n\t"  \
+ "movq 0x30(%5),%%r11 \n\t"  \
+ "mulq %4             \n\t"  \
+ "addq %%r10,%%rax    \n\t"  \
+ "adcq $0,%%rdx       \n\t"  \
+ "movq 0x30(%2),%%r10 \n\t"  \
+ "addq %3,%%rax       \n\t"  \
+ "adcq $0,%%rdx       \n\t"  \
+ "movq %%rax,0x28(%0) \n\t"  \
+ "movq %%rdx,%1       \n\t"  \
+ \
+ "movq %%r11,%%rax    \n\t"  \
+ "movq 0x38(%5),%%r11 \n\t"  \
+ "mulq %4             \n\t"  \
+ "addq %%r10,%%rax    \n\t"  \
+ "adcq $0,%%rdx       \n\t"  \
+ "movq 0x38(%2),%%r10 \n\t"  \
+ "addq %3,%%rax       \n\t"  \
+ "adcq $0,%%rdx       \n\t"  \
+ "movq %%rax,0x30(%0) \n\t"  \
+ "movq %%rdx,%1       \n\t"  \
+ \
+ "movq %%r11,%%rax    \n\t"  \
+ "mulq %4             \n\t"  \
+ "addq %%r10,%%rax    \n\t"  \
+ "adcq $0,%%rdx       \n\t"  \
+ "addq %3,%%rax       \n\t"  \
+ "adcq $0,%%rdx       \n\t"  \
+ "movq %%rax,0x38(%0) \n\t"  \
+ "movq %%rdx,%1       \n\t"  \
+ \
+:"=r"(_c), "=r"(cy)                    \
+: "0"(_c),  "1"(cy), "g"(mu), "r"(tmpm)\
+: "%rax", "%rdx", "%r10", "%r11", "cc")
+
+
+#define PROPCARRY                           \
+asm(                                        \
+   "addq   %1,%0    \n\t"                   \
+   "setb   %%al     \n\t"                   \
+   "movzbq %%al,%1 \n\t"                    \
+:"=g"(_c[LO]), "=r"(cy)                     \
+:"0"(_c[LO]), "1"(cy)                       \
+: "%rax", "cc")
+
+/******************************************************************/
+#elif defined(TFM_SSE2)
+/* SSE2 code (assumes 32-bit fp_digits) */
+/* XMM register assignments:
+ * xmm0  *tmpm++, then Mu * (*tmpm++)
+ * xmm1  c[x], then Mu
+ * xmm2  mp
+ * xmm3  cy
+ * xmm4  _c[LO]
+ */
+
+#define MONT_START \
+   asm("movd %0,%%mm2"::"g"(mp))
+
+#define MONT_FINI \
+   asm("emms")
+
+#define LOOP_START          \
+asm(                        \
+"movd %0,%%mm1        \n\t" \
+"pxor %%mm3,%%mm3     \n\t" \
+"pmuludq %%mm2,%%mm1  \n\t" \
+:: "g"(c[x]))
+
+/* pmuludq on mmx registers does a 32x32->64 multiply. */
+#define INNERMUL               \
+asm(                           \
+   "movd %1,%%mm4        \n\t" \
+   "movd %2,%%mm0        \n\t" \
+   "paddq %%mm4,%%mm3    \n\t" \
+   "pmuludq %%mm1,%%mm0  \n\t" \
+   "paddq %%mm0,%%mm3    \n\t" \
+   "movd %%mm3,%0        \n\t" \
+   "psrlq $32, %%mm3     \n\t" \
+:"=g"(_c[LO]) : "0"(_c[LO]), "g"(*tmpm++) );
+
+#define INNERMUL8 \
+asm(                           \
+   "movd 0(%1),%%mm4     \n\t" \
+   "movd 0(%2),%%mm0     \n\t" \
+   "paddq %%mm4,%%mm3    \n\t" \
+   "pmuludq %%mm1,%%mm0  \n\t" \
+   "movd 4(%2),%%mm5     \n\t" \
+   "paddq %%mm0,%%mm3    \n\t" \
+   "movd 4(%1),%%mm6     \n\t" \
+   "movd %%mm3,0(%0)     \n\t" \
+   "psrlq $32, %%mm3     \n\t" \
+\
+   "paddq %%mm6,%%mm3    \n\t" \
+   "pmuludq %%mm1,%%mm5  \n\t" \
+   "movd 8(%2),%%mm6     \n\t" \
+   "paddq %%mm5,%%mm3    \n\t" \
+   "movd 8(%1),%%mm7     \n\t" \
+   "movd %%mm3,4(%0)     \n\t" \
+   "psrlq $32, %%mm3     \n\t" \
+\
+   "paddq %%mm7,%%mm3    \n\t" \
+   "pmuludq %%mm1,%%mm6  \n\t" \
+   "movd 12(%2),%%mm7    \n\t" \
+   "paddq %%mm6,%%mm3    \n\t" \
+   "movd 12(%1),%%mm5     \n\t" \
+   "movd %%mm3,8(%0)     \n\t" \
+   "psrlq $32, %%mm3     \n\t" \
+\
+   "paddq %%mm5,%%mm3    \n\t" \
+   "pmuludq %%mm1,%%mm7  \n\t" \
+   "movd 16(%2),%%mm5    \n\t" \
+   "paddq %%mm7,%%mm3    \n\t" \
+   "movd 16(%1),%%mm6    \n\t" \
+   "movd %%mm3,12(%0)    \n\t" \
+   "psrlq $32, %%mm3     \n\t" \
+\
+   "paddq %%mm6,%%mm3    \n\t" \
+   "pmuludq %%mm1,%%mm5  \n\t" \
+   "movd 20(%2),%%mm6    \n\t" \
+   "paddq %%mm5,%%mm3    \n\t" \
+   "movd 20(%1),%%mm7    \n\t" \
+   "movd %%mm3,16(%0)    \n\t" \
+   "psrlq $32, %%mm3     \n\t" \
+\
+   "paddq %%mm7,%%mm3    \n\t" \
+   "pmuludq %%mm1,%%mm6  \n\t" \
+   "movd 24(%2),%%mm7    \n\t" \
+   "paddq %%mm6,%%mm3    \n\t" \
+   "movd 24(%1),%%mm5     \n\t" \
+   "movd %%mm3,20(%0)    \n\t" \
+   "psrlq $32, %%mm3     \n\t" \
+\
+   "paddq %%mm5,%%mm3    \n\t" \
+   "pmuludq %%mm1,%%mm7  \n\t" \
+   "movd 28(%2),%%mm5    \n\t" \
+   "paddq %%mm7,%%mm3    \n\t" \
+   "movd 28(%1),%%mm6    \n\t" \
+   "movd %%mm3,24(%0)    \n\t" \
+   "psrlq $32, %%mm3     \n\t" \
+\
+   "paddq %%mm6,%%mm3    \n\t" \
+   "pmuludq %%mm1,%%mm5  \n\t" \
+   "paddq %%mm5,%%mm3    \n\t" \
+   "movd %%mm3,28(%0)    \n\t" \
+   "psrlq $32, %%mm3     \n\t" \
+:"=r"(_c) : "0"(_c), "g"(tmpm) );
+
+#define LOOP_END \
+asm( "movd %%mm3,%0  \n" :"=r"(cy))
+
+#define PROPCARRY                           \
+asm(                                        \
+   "addl   %1,%0    \n\t"                   \
+   "setb   %%al     \n\t"                   \
+   "movzbl %%al,%1 \n\t"                    \
+:"=g"(_c[LO]), "=r"(cy)                     \
+:"0"(_c[LO]), "1"(cy)                       \
+: "%eax", "cc")
+
+/******************************************************************/
+#elif defined(TFM_ARM)
+   /* ARMv4 code */
+
+#define MONT_START
+#define MONT_FINI
+#define LOOP_END
+#define LOOP_START \
+   mu = c[x] * mp
+
+#define INNERMUL                    \
+asm(                                \
+    " LDR    r0,%1            \n\t" \
+    " ADDS   r0,r0,%0         \n\t" \
+    " MOVCS  %0,#1            \n\t" \
+    " MOVCC  %0,#0            \n\t" \
+    " UMLAL  r0,%0,%3,%4      \n\t" \
+    " STR    r0,%1            \n\t" \
+:"=r"(cy),"=m"(_c[0]):"0"(cy),"r"(mu),"r"(*tmpm++),"1"(_c[0]):"r0","cc");
+
+#define PROPCARRY                  \
+asm(                               \
+    " LDR   r0,%1            \n\t" \
+    " ADDS  r0,r0,%0         \n\t" \
+    " STR   r0,%1            \n\t" \
+    " MOVCS %0,#1            \n\t" \
+    " MOVCC %0,#0            \n\t" \
+:"=r"(cy),"=m"(_c[0]):"0"(cy),"1"(_c[0]):"r0","cc");
+
+/******************************************************************/
+#elif defined(TFM_PPC32)
+
+/* PPC32 */
+#define MONT_START
+#define MONT_FINI
+#define LOOP_END
+#define LOOP_START \
+   mu = c[x] * mp
+
+#define INNERMUL                     \
+asm(                                 \
+   " mullw    16,%3,%4       \n\t"   \
+   " mulhwu   17,%3,%4       \n\t"   \
+   " addc     16,16,%2       \n\t"   \
+   " addze    17,17          \n\t"   \
+   " addc     %1,16,%5       \n\t"   \
+   " addze    %0,17          \n\t"   \
+:"=r"(cy),"=r"(_c[0]):"0"(cy),"r"(mu),"r"(tmpm[0]),"1"(_c[0]):"16", "17", "cc"); ++tmpm;
+
+#define PROPCARRY                    \
+asm(                                 \
+   " addc     %1,%3,%2      \n\t"    \
+   " xor      %0,%2,%2      \n\t"    \
+   " addze    %0,%2         \n\t"    \
+:"=r"(cy),"=r"(_c[0]):"0"(cy),"1"(_c[0]):"cc");
+
+/******************************************************************/
+#elif defined(TFM_PPC64)
+
+/* PPC64 */
+#define MONT_START
+#define MONT_FINI
+#define LOOP_END
+#define LOOP_START \
+   mu = c[x] * mp
+
+#define INNERMUL                     \
+asm(                                 \
+   " mulld    r16,%3,%4       \n\t"   \
+   " mulhdu   r17,%3,%4       \n\t"   \
+   " addc     r16,16,%0       \n\t"   \
+   " addze    r17,r17          \n\t"   \
+   " ldx      r18,0,%1        \n\t"   \
+   " addc     r16,r16,r18       \n\t"   \
+   " addze    %0,r17          \n\t"   \
+   " sdx      r16,0,%1        \n\t"   \
+:"=r"(cy),"=m"(_c[0]):"0"(cy),"r"(mu),"r"(tmpm[0]),"1"(_c[0]):"r16", "r17", "r18","cc"); ++tmpm;
+
+#define PROPCARRY                    \
+asm(                                 \
+   " ldx      r16,0,%1       \n\t"    \
+   " addc     r16,r16,%0      \n\t"    \
+   " sdx      r16,0,%1       \n\t"    \
+   " xor      %0,%0,%0      \n\t"    \
+   " addze    %0,%0         \n\t"    \
+:"=r"(cy),"=m"(_c[0]):"0"(cy),"1"(_c[0]):"r16","cc");
+
+/******************************************************************/
+#elif defined(TFM_AVR32)
+
+/* AVR32 */
+#define MONT_START
+#define MONT_FINI
+#define LOOP_END
+#define LOOP_START \
+   mu = c[x] * mp
+
+#define INNERMUL                    \
+asm(                                \
+    " ld.w   r2,%1            \n\t" \
+    " add    r2,%0            \n\t" \
+    " eor    r3,r3            \n\t" \
+    " acr    r3               \n\t" \
+    " macu.d r2,%3,%4         \n\t" \
+    " st.w   %1,r2            \n\t" \
+    " mov    %0,r3            \n\t" \
+:"=r"(cy),"=r"(_c):"0"(cy),"r"(mu),"r"(*tmpm++),"1"(_c):"r2","r3");
+
+#define PROPCARRY                    \
+asm(                                 \
+   " ld.w     r2,%1         \n\t"    \
+   " add      r2,%0         \n\t"    \
+   " st.w     %1,r2         \n\t"    \
+   " eor      %0,%0         \n\t"    \
+   " acr      %0            \n\t"    \
+:"=r"(cy),"=r"(&_c[0]):"0"(cy),"1"(&_c[0]):"r2","cc");
+
+/******************************************************************/
+#elif defined(TFM_MIPS)
+
+/* MIPS */
+#define MONT_START
+#define MONT_FINI
+#define LOOP_END
+#define LOOP_START \
+   mu = c[x] * mp
+
+#define INNERMUL                     \
+asm(                                 \
+   " multu    %3,%4          \n\t"   \
+   " mflo     $12            \n\t"   \
+   " mfhi     $13            \n\t"   \
+   " addu     $12,$12,%0     \n\t"   \
+   " sltu     $10,$12,%0     \n\t"   \
+   " addu     $13,$13,$10    \n\t"   \
+   " lw       $10,%1         \n\t"   \
+   " addu     $12,$12,$10    \n\t"   \
+   " sltu     $10,$12,$10    \n\t"   \
+   " addu     %0,$13,$10     \n\t"   \
+   " sw       $12,%1         \n\t"   \
+:"=r"(cy),"=m"(_c[0]):"0"(cy),"r"(mu),"r"(tmpm[0]),"1"(_c[0]):"$10","$12","$13"); ++tmpm;
+
+#define PROPCARRY                    \
+asm(                                 \
+   " lw       $10,%1        \n\t"    \
+   " addu     $10,$10,%0    \n\t"    \
+   " sw       $10,%1        \n\t"    \
+   " sltu     %0,$10,%0     \n\t"    \
+:"=r"(cy),"=m"(_c[0]):"0"(cy),"1"(_c[0]):"$10");
+
+/******************************************************************/
+#else
+
+/* ISO C code */
+#define MONT_START
+#define MONT_FINI
+#define LOOP_END
+#define LOOP_START \
+   mu = c[x] * mp
+
+#define INNERMUL                                      \
+   do { fp_word t;                                    \
+   _c[0] = t  = ((fp_word)_c[0] + (fp_word)cy) +      \
+                (((fp_word)mu) * ((fp_word)*tmpm++)); \
+   cy = (t >> DIGIT_BIT);                             \
+   } while (0)
+
+#define PROPCARRY \
+   do { fp_digit t = _c[0] += cy; cy = (t < cy); } while (0)
+
+#endif
+/******************************************************************/
+
+
+#define LO  0
+
+#ifdef TFM_SMALL_MONT_SET
+#include "fp_mont_small.i"
+#endif
+
+/* computes x/R == x (mod N) via Montgomery Reduction */
+void fp_montgomery_reduce(fp_int *a, fp_int *m, fp_digit mp)
+{
+   fp_digit c[FP_SIZE], *_c, *tmpm, mu;
+   int      oldused, x, y, pa;
+
+   /* bail if too large */
+   if (m->used > (FP_SIZE/2)) {
+      return;
+   }
+
+#ifdef TFM_SMALL_MONT_SET
+   if (m->used <= 16) {
+      fp_montgomery_reduce_small(a, m, mp);
+      return;
+   }
+#endif
+
+#if defined(USE_MEMSET)
+   /* now zero the buff */
+   memset(c, 0, sizeof c);
+#endif
+   pa = m->used;
+
+   /* copy the input */
+   oldused = a->used;
+   for (x = 0; x < oldused; x++) {
+       c[x] = a->dp[x];
+   }
+#if !defined(USE_MEMSET)
+   for (; x < 2*pa+1; x++) {
+       c[x] = 0;
+   }
+#endif
+   MONT_START;
+
+   for (x = 0; x < pa; x++) {
+       fp_digit cy = 0;
+       /* get Mu for this round */
+       LOOP_START;
+       _c   = c + x;
+       tmpm = m->dp;
+       y = 0;
+       #if defined(INNERMUL8)
+        for (; y < (pa & ~7); y += 8) {
+              INNERMUL8;
+              _c   += 8;
+              tmpm += 8;
+           }
+       #endif
+
+       for (; y < pa; y++) {
+          INNERMUL;
+          ++_c;
+       }
+       LOOP_END;
+       while (cy) {
+           PROPCARRY;
+           ++_c;
+       }
+  }
+
+  /* now copy out */
+  _c   = c + pa;
+  tmpm = a->dp;
+  for (x = 0; x < pa+1; x++) {
+     *tmpm++ = *_c++;
+  }
+
+  for (; x < oldused; x++)   {
+     *tmpm++ = 0;
+  }
+
+  MONT_FINI;
+
+  a->used = pa+1;
+  fp_clamp(a);
+
+  /* if A >= m then A = A - m */
+  if (fp_cmp_mag (a, m) != FP_LT) {
+    s_fp_sub (a, m, a);
+  }
+}
+
+
+/* $Source$ */
+/* $Revision$ */
+/* $Date$ */
diff --git a/tomsfastmath/src/mont/fp_montgomery_setup.c b/tomsfastmath/src/mont/fp_montgomery_setup.c
new file mode 100644 (file)
index 0000000..55f16dc
--- /dev/null
@@ -0,0 +1,48 @@
+/* TomsFastMath, a fast ISO C bignum library.
+ * 
+ * This project is meant to fill in where LibTomMath
+ * falls short.  That is speed ;-)
+ *
+ * This project is public domain and free for all purposes.
+ * 
+ * Tom St Denis, tomstdenis@gmail.com
+ */
+#include <tfm_private.h>
+
+/* setups the montgomery reduction */
+int fp_montgomery_setup(fp_int *a, fp_digit *rho)
+{
+  fp_digit x, b;
+
+/* fast inversion mod 2**k
+ *
+ * Based on the fact that
+ *
+ * XA = 1 (mod 2**n)  =>  (X(2-XA)) A = 1 (mod 2**2n)
+ *                    =>  2*X*A - X*X*A*A = 1
+ *                    =>  2*(1) - (1)     = 1
+ */
+  b = a->dp[0];
+
+  if ((b & 1) == 0) {
+    return FP_VAL;
+  }
+
+  x = (((b + 2) & 4) << 1) + b; /* here x*a==1 mod 2**4 */
+  x *= 2 - b * x;               /* here x*a==1 mod 2**8 */
+  x *= 2 - b * x;               /* here x*a==1 mod 2**16 */
+  x *= 2 - b * x;               /* here x*a==1 mod 2**32 */
+#ifdef FP_64BIT
+  x *= 2 - b * x;               /* here x*a==1 mod 2**64 */
+#endif
+
+  /* rho = -1/m mod b */
+  *rho = (((fp_word) 1 << ((fp_word) DIGIT_BIT)) - ((fp_word)x));
+
+  return FP_OKAY;
+}
+
+
+/* $Source$ */
+/* $Revision$ */
+/* $Date$ */
diff --git a/tomsfastmath/src/mul/fp_mul.c b/tomsfastmath/src/mul/fp_mul.c
new file mode 100644 (file)
index 0000000..e97c6cf
--- /dev/null
@@ -0,0 +1,139 @@
+/* TomsFastMath, a fast ISO C bignum library.
+ *
+ * This project is meant to fill in where LibTomMath
+ * falls short.  That is speed ;-)
+ *
+ * This project is public domain and free for all purposes.
+ *
+ * Tom St Denis, tomstdenis@gmail.com
+ */
+#include <tfm_private.h>
+
+/* c = a * b */
+void fp_mul(fp_int *A, fp_int *B, fp_int *C)
+{
+    int   y, old_used;
+#if FP_SIZE >= 48
+    int   yy;
+#endif
+
+    old_used = C->used;
+
+    /* call generic if we're out of range */
+    if (A->used + B->used > FP_SIZE) {
+       fp_mul_comba(A, B, C);
+       goto clean;
+    }
+
+     y  = MAX(A->used, B->used);
+#if FP_SIZE >= 48
+     yy = MIN(A->used, B->used);
+#endif
+    /* pick a comba (unrolled 4/8/16/32 x or rolled) based on the size
+       of the largest input.  We also want to avoid doing excess mults if the
+       inputs are not close to the next power of two.  That is, for example,
+       if say y=17 then we would do (32-17)^2 = 225 unneeded multiplications
+    */
+
+#if defined(TFM_MUL3) && FP_SIZE >= 6
+        if (y <= 3) {
+           fp_mul_comba3(A,B,C);
+           goto clean;
+        }
+#endif
+#if defined(TFM_MUL4) && FP_SIZE >= 8
+        if (y == 4) {
+           fp_mul_comba4(A,B,C);
+           goto clean;
+        }
+#endif
+#if defined(TFM_MUL6) && FP_SIZE >= 12
+        if (y <= 6) {
+           fp_mul_comba6(A,B,C);
+           goto clean;
+        }
+#endif
+#if defined(TFM_MUL7) && FP_SIZE >= 14
+        if (y == 7) {
+           fp_mul_comba7(A,B,C);
+           goto clean;
+        }
+#endif
+#if defined(TFM_MUL8) && FP_SIZE >= 16
+        if (y == 8) {
+           fp_mul_comba8(A,B,C);
+           goto clean;
+        }
+#endif
+#if defined(TFM_MUL9) && FP_SIZE >= 18
+        if (y == 9) {
+           fp_mul_comba9(A,B,C);
+           goto clean;
+        }
+#endif
+#if defined(TFM_MUL12) && FP_SIZE >= 24
+        if (y <= 12) {
+           fp_mul_comba12(A,B,C);
+           goto clean;
+        }
+#endif
+#if defined(TFM_MUL17) && FP_SIZE >= 34
+        if (y <= 17) {
+           fp_mul_comba17(A,B,C);
+           goto clean;
+        }
+#endif
+
+#if defined(TFM_SMALL_SET) && FP_SIZE >= 32
+        if (y <= 16) {
+           fp_mul_comba_small(A,B,C);
+           goto clean;
+        }
+#endif
+#if defined(TFM_MUL20) && FP_SIZE >= 40
+        if (y <= 20) {
+           fp_mul_comba20(A,B,C);
+           goto clean;
+        }
+#endif
+#if defined(TFM_MUL24) && FP_SIZE >= 48
+        if (yy >= 16 && y <= 24) {
+           fp_mul_comba24(A,B,C);
+           goto clean;
+        }
+#endif
+#if defined(TFM_MUL28) && FP_SIZE >= 56
+        if (yy >= 20 && y <= 28) {
+           fp_mul_comba28(A,B,C);
+           goto clean;
+        }
+#endif
+#if defined(TFM_MUL32) && FP_SIZE >= 64
+        if (yy >= 24 && y <= 32) {
+           fp_mul_comba32(A,B,C);
+           goto clean;
+        }
+#endif
+#if defined(TFM_MUL48) && FP_SIZE >= 96
+        if (yy >= 40 && y <= 48) {
+           fp_mul_comba48(A,B,C);
+           goto clean;
+        }
+#endif
+#if defined(TFM_MUL64) && FP_SIZE >= 128
+        if (yy >= 56 && y <= 64) {
+           fp_mul_comba64(A,B,C);
+           goto clean;
+        }
+#endif
+        fp_mul_comba(A,B,C);
+clean:
+    for (y = C->used; y < old_used; y++) {
+       C->dp[y] = 0;
+    }
+}
+
+
+/* $Source: /cvs/libtom/tomsfastmath/src/mul/fp_mul.c,v $ */
+/* $Revision: 1.1 $ */
+/* $Date: 2006/12/31 21:25:53 $ */
diff --git a/tomsfastmath/src/mul/fp_mul_2.c b/tomsfastmath/src/mul/fp_mul_2.c
new file mode 100644 (file)
index 0000000..bd40163
--- /dev/null
@@ -0,0 +1,67 @@
+/* TomsFastMath, a fast ISO C bignum library.
+ * 
+ * This project is meant to fill in where LibTomMath
+ * falls short.  That is speed ;-)
+ *
+ * This project is public domain and free for all purposes.
+ * 
+ * Tom St Denis, tomstdenis@gmail.com
+ */
+#include <tfm_private.h>
+
+void fp_mul_2(fp_int * a, fp_int * b)
+{
+  int     x, oldused;
+   
+  oldused = b->used;
+  b->used = a->used;
+
+  {
+    register fp_digit r, rr, *tmpa, *tmpb;
+
+    /* alias for source */
+    tmpa = a->dp;
+    
+    /* alias for dest */
+    tmpb = b->dp;
+
+    /* carry */
+    r = 0;
+    for (x = 0; x < a->used; x++) {
+    
+      /* get what will be the *next* carry bit from the 
+       * MSB of the current digit 
+       */
+      rr = *tmpa >> ((fp_digit)(DIGIT_BIT - 1));
+      
+      /* now shift up this digit, add in the carry [from the previous] */
+      *tmpb++ = ((*tmpa++ << ((fp_digit)1)) | r);
+      
+      /* copy the carry that would be from the source 
+       * digit into the next iteration 
+       */
+      r = rr;
+    }
+
+    /* new leading digit? */
+    if (r != 0 && b->used != (FP_SIZE-1)) {
+      /* add a MSB which is always 1 at this point */
+      *tmpb = 1;
+      ++(b->used);
+    }
+
+    /* now zero any excess digits on the destination 
+     * that we didn't write to 
+     */
+    tmpb = b->dp + b->used;
+    for (x = b->used; x < oldused; x++) {
+      *tmpb++ = 0;
+    }
+  }
+  b->sign = a->sign;
+}
+
+
+/* $Source$ */
+/* $Revision$ */
+/* $Date$ */
diff --git a/tomsfastmath/src/mul/fp_mul_2d.c b/tomsfastmath/src/mul/fp_mul_2d.c
new file mode 100644 (file)
index 0000000..dd81d41
--- /dev/null
@@ -0,0 +1,47 @@
+/* TomsFastMath, a fast ISO C bignum library.
+ * 
+ * This project is meant to fill in where LibTomMath
+ * falls short.  That is speed ;-)
+ *
+ * This project is public domain and free for all purposes.
+ * 
+ * Tom St Denis, tomstdenis@gmail.com
+ */
+#include <tfm_private.h>
+
+/* c = a * 2**d */
+void fp_mul_2d(fp_int *a, int b, fp_int *c)
+{
+   fp_digit carry, carrytmp, shift;
+   int x;
+
+   /* copy it */
+   fp_copy(a, c);
+
+   /* handle whole digits */
+   if (b >= DIGIT_BIT) {
+      fp_lshd(c, b/DIGIT_BIT);
+   }
+   b %= DIGIT_BIT;
+
+   /* shift the digits */
+   if (b != 0) {
+      carry = 0;   
+      shift = DIGIT_BIT - b;
+      for (x = 0; x < c->used; x++) {
+          carrytmp = c->dp[x] >> shift;
+          c->dp[x] = (c->dp[x] << b) + carry;
+          carry = carrytmp;
+      }
+      /* store last carry if room */
+      if (carry && x < FP_SIZE) {
+         c->dp[c->used++] = carry;
+      }
+   }
+   fp_clamp(c);
+}
+
+
+/* $Source$ */
+/* $Revision$ */
+/* $Date$ */
diff --git a/tomsfastmath/src/mul/fp_mul_comba.c b/tomsfastmath/src/mul/fp_mul_comba.c
new file mode 100644 (file)
index 0000000..a4253fb
--- /dev/null
@@ -0,0 +1,373 @@
+/* TomsFastMath, a fast ISO C bignum library.
+ *
+ * This project is meant to fill in where LibTomMath
+ * falls short.  That is speed ;-)
+ *
+ * This project is public domain and free for all purposes.
+ *
+ * Tom St Denis, tomstdenis@gmail.com
+ */
+
+/* About this file...
+
+*/
+
+#include <tfm_private.h>
+
+#if defined(TFM_PRESCOTT) && defined(TFM_SSE2)
+   #undef TFM_SSE2
+   #define TFM_X86
+#endif
+
+/* these are the combas.  Worship them. */
+#if defined(TFM_X86)
+/* Generic x86 optimized code */
+
+/* anything you need at the start */
+#define COMBA_START
+
+/* clear the chaining variables */
+#define COMBA_CLEAR \
+   c0 = c1 = c2 = 0;
+
+/* forward the carry to the next digit */
+#define COMBA_FORWARD \
+   do { c0 = c1; c1 = c2; c2 = 0; } while (0);
+
+/* store the first sum */
+#define COMBA_STORE(x) \
+   x = c0;
+
+/* store the second sum [carry] */
+#define COMBA_STORE2(x) \
+   x = c1;
+
+/* anything you need at the end */
+#define COMBA_FINI
+
+/* this should multiply i and j  */
+#define MULADD(i, j)                                      \
+asm(                                                      \
+     "movl  %6,%%eax     \n\t"                            \
+     "mull  %7           \n\t"                            \
+     "addl  %%eax,%0     \n\t"                            \
+     "adcl  %%edx,%1     \n\t"                            \
+     "adcl  $0,%2        \n\t"                            \
+     :"=r"(c0), "=r"(c1), "=r"(c2): "0"(c0), "1"(c1), "2"(c2), "m"(i), "m"(j)  :"%eax","%edx","cc");
+
+#elif defined(TFM_X86_64)
+/* x86-64 optimized */
+
+/* anything you need at the start */
+#define COMBA_START
+
+/* clear the chaining variables */
+#define COMBA_CLEAR \
+   c0 = c1 = c2 = 0;
+
+/* forward the carry to the next digit */
+#define COMBA_FORWARD \
+   do { c0 = c1; c1 = c2; c2 = 0; } while (0);
+
+/* store the first sum */
+#define COMBA_STORE(x) \
+   x = c0;
+
+/* store the second sum [carry] */
+#define COMBA_STORE2(x) \
+   x = c1;
+
+/* anything you need at the end */
+#define COMBA_FINI
+
+/* this should multiply i and j  */
+#define MULADD(i, j)                                      \
+asm  (                                                    \
+     "movq  %6,%%rax     \n\t"                            \
+     "mulq  %7           \n\t"                            \
+     "addq  %%rax,%0     \n\t"                            \
+     "adcq  %%rdx,%1     \n\t"                            \
+     "adcq  $0,%2        \n\t"                            \
+     :"=r"(c0), "=r"(c1), "=r"(c2): "0"(c0), "1"(c1), "2"(c2), "g"(i), "g"(j)  :"%rax","%rdx","cc");
+
+#elif defined(TFM_SSE2)
+/* use SSE2 optimizations */
+
+/* anything you need at the start */
+#define COMBA_START
+
+/* clear the chaining variables */
+#define COMBA_CLEAR \
+   c0 = c1 = c2 = 0;
+
+/* forward the carry to the next digit */
+#define COMBA_FORWARD \
+   do { c0 = c1; c1 = c2; c2 = 0; } while (0);
+
+/* store the first sum */
+#define COMBA_STORE(x) \
+   x = c0;
+
+/* store the second sum [carry] */
+#define COMBA_STORE2(x) \
+   x = c1;
+
+/* anything you need at the end */
+#define COMBA_FINI \
+   asm("emms");
+
+/* this should multiply i and j  */
+#define MULADD(i, j)                                     \
+asm(                                                     \
+    "movd  %6,%%mm0     \n\t"                            \
+    "movd  %7,%%mm1     \n\t"                            \
+    "pmuludq %%mm1,%%mm0\n\t"                            \
+    "movd  %%mm0,%%eax  \n\t"                            \
+    "psrlq $32,%%mm0    \n\t"                            \
+    "addl  %%eax,%0     \n\t"                            \
+    "movd  %%mm0,%%eax  \n\t"                            \
+    "adcl  %%eax,%1     \n\t"                            \
+    "adcl  $0,%2        \n\t"                            \
+    :"=r"(c0), "=r"(c1), "=r"(c2): "0"(c0), "1"(c1), "2"(c2), "m"(i), "m"(j)  :"%eax","cc");
+
+#elif defined(TFM_ARM)
+/* ARM code */
+
+#define COMBA_START
+
+#define COMBA_CLEAR \
+   c0 = c1 = c2 = 0;
+
+#define COMBA_FORWARD \
+   do { c0 = c1; c1 = c2; c2 = 0; } while (0);
+
+#define COMBA_STORE(x) \
+   x = c0;
+
+#define COMBA_STORE2(x) \
+   x = c1;
+
+#define COMBA_FINI
+
+#define MULADD(i, j)                                          \
+asm(                                                          \
+"  UMULL  r0,r1,%6,%7           \n\t"                         \
+"  ADDS   %0,%0,r0              \n\t"                         \
+"  ADCS   %1,%1,r1              \n\t"                         \
+"  ADC    %2,%2,#0              \n\t"                         \
+:"=r"(c0), "=r"(c1), "=r"(c2) : "0"(c0), "1"(c1), "2"(c2), "r"(i), "r"(j) : "r0", "r1", "cc");
+
+#elif defined(TFM_PPC32)
+/* For 32-bit PPC */
+
+#define COMBA_START
+
+#define COMBA_CLEAR \
+   c0 = c1 = c2 = 0;
+
+#define COMBA_FORWARD \
+   do { c0 = c1; c1 = c2; c2 = 0; } while (0);
+
+#define COMBA_STORE(x) \
+   x = c0;
+
+#define COMBA_STORE2(x) \
+   x = c1;
+
+#define COMBA_FINI
+
+/* untested: will mulhwu change the flags?  Docs say no */
+#define MULADD(i, j)              \
+asm(                              \
+   " mullw  16,%6,%7       \n\t" \
+   " addc   %0,%0,16       \n\t" \
+   " mulhwu 16,%6,%7       \n\t" \
+   " adde   %1,%1,16       \n\t" \
+   " addze  %2,%2          \n\t" \
+:"=r"(c0), "=r"(c1), "=r"(c2):"0"(c0), "1"(c1), "2"(c2), "r"(i), "r"(j):"16");
+
+#elif defined(TFM_PPC64)
+/* For 64-bit PPC */
+
+#define COMBA_START
+
+#define COMBA_CLEAR \
+   c0 = c1 = c2 = 0;
+
+#define COMBA_FORWARD \
+   do { c0 = c1; c1 = c2; c2 = 0; } while (0);
+
+#define COMBA_STORE(x) \
+   x = c0;
+
+#define COMBA_STORE2(x) \
+   x = c1;
+
+#define COMBA_FINI
+
+/* untested: will mulhdu change the flags?  Docs say no */
+#define MULADD(i, j)              \
+asm(                              \
+   " mulld  r16,%6,%7       \n\t" \
+   " addc   %0,%0,16       \n\t" \
+   " mulhdu r16,%6,%7       \n\t" \
+   " adde   %1,%1,16       \n\t" \
+   " addze  %2,%2          \n\t" \
+:"=r"(c0), "=r"(c1), "=r"(c2):"0"(c0), "1"(c1), "2"(c2), "r"(i), "r"(j):"r16");
+
+#elif defined(TFM_AVR32)
+
+/* ISO C code */
+
+#define COMBA_START
+
+#define COMBA_CLEAR \
+   c0 = c1 = c2 = 0;
+
+#define COMBA_FORWARD \
+   do { c0 = c1; c1 = c2; c2 = 0; } while (0);
+
+#define COMBA_STORE(x) \
+   x = c0;
+
+#define COMBA_STORE2(x) \
+   x = c1;
+
+#define COMBA_FINI
+
+#define MULADD(i, j)             \
+asm(                             \
+   " mulu.d r2,%6,%7        \n\t"\
+   " add    %0,r2           \n\t"\
+   " adc    %1,%1,r3        \n\t"\
+   " acr    %2              \n\t"\
+:"=r"(c0), "=r"(c1), "=r"(c2):"0"(c0), "1"(c1), "2"(c2), "r"(i), "r"(j):"r2","r3");
+
+#elif defined(TFM_MIPS)
+
+#define COMBA_START
+
+#define COMBA_CLEAR \
+   c0 = c1 = c2 = 0;
+
+#define COMBA_FORWARD \
+   do { c0 = c1; c1 = c2; c2 = 0; } while (0);
+
+#define COMBA_STORE(x) \
+   x = c0;
+
+#define COMBA_STORE2(x) \
+   x = c1;
+
+#define COMBA_FINI
+
+#define MULADD(i, j)              \
+asm(                              \
+   " multu  %6,%7          \n\t"  \
+   " mflo   $12            \n\t"  \
+   " mfhi   $13            \n\t"  \
+   " addu    %0,%0,$12     \n\t"  \
+   " sltu   $12,%0,$12     \n\t"  \
+   " addu    %1,%1,$13     \n\t"  \
+   " sltu   $13,%1,$13     \n\t"  \
+   " addu    %1,%1,$12     \n\t"  \
+   " sltu   $12,%1,$12     \n\t"  \
+   " addu    %2,%2,$13     \n\t"  \
+   " addu    %2,%2,$12     \n\t"  \
+:"=r"(c0), "=r"(c1), "=r"(c2):"0"(c0), "1"(c1), "2"(c2), "r"(i), "r"(j):"$12","$13");
+
+#else
+/* ISO C code */
+
+#define COMBA_START
+
+#define COMBA_CLEAR \
+   c0 = c1 = c2 = 0;
+
+#define COMBA_FORWARD \
+   do { c0 = c1; c1 = c2; c2 = 0; } while (0);
+
+#define COMBA_STORE(x) \
+   x = c0;
+
+#define COMBA_STORE2(x) \
+   x = c1;
+
+#define COMBA_FINI
+
+#define MULADD(i, j)                                    \
+   do { fp_word t;                                      \
+   t = (fp_word)c0 + ((fp_word)i) * ((fp_word)j);       \
+   c0 = t;                                              \
+   t = (fp_word)c1 + (t >> DIGIT_BIT);                  \
+   c1 = t;                                              \
+   c2 += t >> DIGIT_BIT;                                \
+   } while (0);
+
+#endif
+
+#ifndef TFM_DEFINES
+
+/* generic PxQ multiplier */
+void fp_mul_comba(fp_int *A, fp_int *B, fp_int *C)
+{
+   int       ix, iy, iz, tx, ty, pa;
+   fp_digit  c0, c1, c2, *tmpx, *tmpy;
+   fp_int    tmp, *dst;
+
+   COMBA_START;
+   COMBA_CLEAR;
+
+   /* get size of output and trim */
+   pa = A->used + B->used;
+   if (pa >= FP_SIZE) {
+      pa = FP_SIZE-1;
+   }
+
+   if (A == C || B == C) {
+      fp_zero(&tmp);
+      dst = &tmp;
+   } else {
+      fp_zero(C);
+      dst = C;
+   }
+
+   for (ix = 0; ix < pa; ix++) {
+      /* get offsets into the two bignums */
+      ty = MIN(ix, B->used-1);
+      tx = ix - ty;
+
+      /* setup temp aliases */
+      tmpx = A->dp + tx;
+      tmpy = B->dp + ty;
+
+      /* this is the number of times the loop will iterrate, essentially its
+         while (tx++ < a->used && ty-- >= 0) { ... }
+       */
+      iy = MIN(A->used-tx, ty+1);
+
+      /* execute loop */
+      COMBA_FORWARD;
+      for (iz = 0; iz < iy; ++iz) {
+          fp_digit _tmpx = *tmpx++;
+          fp_digit _tmpy = *tmpy--;
+          MULADD(_tmpx, _tmpy);
+      }
+
+      /* store term */
+      COMBA_STORE(dst->dp[ix]);
+  }
+  COMBA_FINI;
+
+  dst->used = pa;
+  dst->sign = A->sign ^ B->sign;
+  fp_clamp(dst);
+  fp_copy(dst, C);
+}
+
+#endif
+
+/* $Source$ */
+/* $Revision$ */
+/* $Date$ */
+
diff --git a/tomsfastmath/src/mul/fp_mul_comba_12.c b/tomsfastmath/src/mul/fp_mul_comba_12.c
new file mode 100644 (file)
index 0000000..95346c7
--- /dev/null
@@ -0,0 +1,116 @@
+#define TFM_DEFINES
+#include "fp_mul_comba.c"
+
+#if defined(TFM_MUL12) && FP_SIZE >= 24
+void fp_mul_comba12(fp_int *A, fp_int *B, fp_int *C)
+{
+   fp_digit c0, c1, c2, at[24];
+
+   memcpy(at, A->dp, 12 * sizeof(fp_digit));
+   memcpy(at+12, B->dp, 12 * sizeof(fp_digit));
+   COMBA_START;
+
+   COMBA_CLEAR;
+   /* 0 */
+   MULADD(at[0], at[12]);
+   COMBA_STORE(C->dp[0]);
+   /* 1 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[13]);    MULADD(at[1], at[12]);
+   COMBA_STORE(C->dp[1]);
+   /* 2 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[14]);    MULADD(at[1], at[13]);    MULADD(at[2], at[12]);
+   COMBA_STORE(C->dp[2]);
+   /* 3 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[15]);    MULADD(at[1], at[14]);    MULADD(at[2], at[13]);    MULADD(at[3], at[12]);
+   COMBA_STORE(C->dp[3]);
+   /* 4 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[16]);    MULADD(at[1], at[15]);    MULADD(at[2], at[14]);    MULADD(at[3], at[13]);    MULADD(at[4], at[12]);
+   COMBA_STORE(C->dp[4]);
+   /* 5 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[17]);    MULADD(at[1], at[16]);    MULADD(at[2], at[15]);    MULADD(at[3], at[14]);    MULADD(at[4], at[13]);    MULADD(at[5], at[12]);
+   COMBA_STORE(C->dp[5]);
+   /* 6 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[18]);    MULADD(at[1], at[17]);    MULADD(at[2], at[16]);    MULADD(at[3], at[15]);    MULADD(at[4], at[14]);    MULADD(at[5], at[13]);    MULADD(at[6], at[12]);
+   COMBA_STORE(C->dp[6]);
+   /* 7 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[19]);    MULADD(at[1], at[18]);    MULADD(at[2], at[17]);    MULADD(at[3], at[16]);    MULADD(at[4], at[15]);    MULADD(at[5], at[14]);    MULADD(at[6], at[13]);    MULADD(at[7], at[12]);
+   COMBA_STORE(C->dp[7]);
+   /* 8 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[20]);    MULADD(at[1], at[19]);    MULADD(at[2], at[18]);    MULADD(at[3], at[17]);    MULADD(at[4], at[16]);    MULADD(at[5], at[15]);    MULADD(at[6], at[14]);    MULADD(at[7], at[13]);    MULADD(at[8], at[12]);
+   COMBA_STORE(C->dp[8]);
+   /* 9 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[21]);    MULADD(at[1], at[20]);    MULADD(at[2], at[19]);    MULADD(at[3], at[18]);    MULADD(at[4], at[17]);    MULADD(at[5], at[16]);    MULADD(at[6], at[15]);    MULADD(at[7], at[14]);    MULADD(at[8], at[13]);    MULADD(at[9], at[12]);
+   COMBA_STORE(C->dp[9]);
+   /* 10 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[22]);    MULADD(at[1], at[21]);    MULADD(at[2], at[20]);    MULADD(at[3], at[19]);    MULADD(at[4], at[18]);    MULADD(at[5], at[17]);    MULADD(at[6], at[16]);    MULADD(at[7], at[15]);    MULADD(at[8], at[14]);    MULADD(at[9], at[13]);    MULADD(at[10], at[12]);
+   COMBA_STORE(C->dp[10]);
+   /* 11 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[23]);    MULADD(at[1], at[22]);    MULADD(at[2], at[21]);    MULADD(at[3], at[20]);    MULADD(at[4], at[19]);    MULADD(at[5], at[18]);    MULADD(at[6], at[17]);    MULADD(at[7], at[16]);    MULADD(at[8], at[15]);    MULADD(at[9], at[14]);    MULADD(at[10], at[13]);    MULADD(at[11], at[12]);
+   COMBA_STORE(C->dp[11]);
+   /* 12 */
+   COMBA_FORWARD;
+   MULADD(at[1], at[23]);    MULADD(at[2], at[22]);    MULADD(at[3], at[21]);    MULADD(at[4], at[20]);    MULADD(at[5], at[19]);    MULADD(at[6], at[18]);    MULADD(at[7], at[17]);    MULADD(at[8], at[16]);    MULADD(at[9], at[15]);    MULADD(at[10], at[14]);    MULADD(at[11], at[13]);
+   COMBA_STORE(C->dp[12]);
+   /* 13 */
+   COMBA_FORWARD;
+   MULADD(at[2], at[23]);    MULADD(at[3], at[22]);    MULADD(at[4], at[21]);    MULADD(at[5], at[20]);    MULADD(at[6], at[19]);    MULADD(at[7], at[18]);    MULADD(at[8], at[17]);    MULADD(at[9], at[16]);    MULADD(at[10], at[15]);    MULADD(at[11], at[14]);
+   COMBA_STORE(C->dp[13]);
+   /* 14 */
+   COMBA_FORWARD;
+   MULADD(at[3], at[23]);    MULADD(at[4], at[22]);    MULADD(at[5], at[21]);    MULADD(at[6], at[20]);    MULADD(at[7], at[19]);    MULADD(at[8], at[18]);    MULADD(at[9], at[17]);    MULADD(at[10], at[16]);    MULADD(at[11], at[15]);
+   COMBA_STORE(C->dp[14]);
+   /* 15 */
+   COMBA_FORWARD;
+   MULADD(at[4], at[23]);    MULADD(at[5], at[22]);    MULADD(at[6], at[21]);    MULADD(at[7], at[20]);    MULADD(at[8], at[19]);    MULADD(at[9], at[18]);    MULADD(at[10], at[17]);    MULADD(at[11], at[16]);
+   COMBA_STORE(C->dp[15]);
+   /* 16 */
+   COMBA_FORWARD;
+   MULADD(at[5], at[23]);    MULADD(at[6], at[22]);    MULADD(at[7], at[21]);    MULADD(at[8], at[20]);    MULADD(at[9], at[19]);    MULADD(at[10], at[18]);    MULADD(at[11], at[17]);
+   COMBA_STORE(C->dp[16]);
+   /* 17 */
+   COMBA_FORWARD;
+   MULADD(at[6], at[23]);    MULADD(at[7], at[22]);    MULADD(at[8], at[21]);    MULADD(at[9], at[20]);    MULADD(at[10], at[19]);    MULADD(at[11], at[18]);
+   COMBA_STORE(C->dp[17]);
+   /* 18 */
+   COMBA_FORWARD;
+   MULADD(at[7], at[23]);    MULADD(at[8], at[22]);    MULADD(at[9], at[21]);    MULADD(at[10], at[20]);    MULADD(at[11], at[19]);
+   COMBA_STORE(C->dp[18]);
+   /* 19 */
+   COMBA_FORWARD;
+   MULADD(at[8], at[23]);    MULADD(at[9], at[22]);    MULADD(at[10], at[21]);    MULADD(at[11], at[20]);
+   COMBA_STORE(C->dp[19]);
+   /* 20 */
+   COMBA_FORWARD;
+   MULADD(at[9], at[23]);    MULADD(at[10], at[22]);    MULADD(at[11], at[21]);
+   COMBA_STORE(C->dp[20]);
+   /* 21 */
+   COMBA_FORWARD;
+   MULADD(at[10], at[23]);    MULADD(at[11], at[22]);
+   COMBA_STORE(C->dp[21]);
+   /* 22 */
+   COMBA_FORWARD;
+   MULADD(at[11], at[23]);
+   COMBA_STORE(C->dp[22]);
+   COMBA_STORE2(C->dp[23]);
+   C->used = 24;
+   C->sign = A->sign ^ B->sign;
+   fp_clamp(C);
+   COMBA_FINI;
+}
+#endif
+
+
+/* $Source$ */
+/* $Revision$ */
+/* $Date$ */
diff --git a/tomsfastmath/src/mul/fp_mul_comba_17.c b/tomsfastmath/src/mul/fp_mul_comba_17.c
new file mode 100644 (file)
index 0000000..8bc360c
--- /dev/null
@@ -0,0 +1,156 @@
+#define TFM_DEFINES
+#include "fp_mul_comba.c"
+
+#if defined(TFM_MUL17) && FP_SIZE >= 34
+void fp_mul_comba17(fp_int *A, fp_int *B, fp_int *C)
+{
+   fp_digit c0, c1, c2, at[34];
+
+   memcpy(at, A->dp, 17 * sizeof(fp_digit));
+   memcpy(at+17, B->dp, 17 * sizeof(fp_digit));
+   COMBA_START;
+
+   COMBA_CLEAR;
+   /* 0 */
+   MULADD(at[0], at[17]);
+   COMBA_STORE(C->dp[0]);
+   /* 1 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[18]);    MULADD(at[1], at[17]);
+   COMBA_STORE(C->dp[1]);
+   /* 2 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[19]);    MULADD(at[1], at[18]);    MULADD(at[2], at[17]);
+   COMBA_STORE(C->dp[2]);
+   /* 3 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[20]);    MULADD(at[1], at[19]);    MULADD(at[2], at[18]);    MULADD(at[3], at[17]);
+   COMBA_STORE(C->dp[3]);
+   /* 4 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[21]);    MULADD(at[1], at[20]);    MULADD(at[2], at[19]);    MULADD(at[3], at[18]);    MULADD(at[4], at[17]);
+   COMBA_STORE(C->dp[4]);
+   /* 5 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[22]);    MULADD(at[1], at[21]);    MULADD(at[2], at[20]);    MULADD(at[3], at[19]);    MULADD(at[4], at[18]);    MULADD(at[5], at[17]);
+   COMBA_STORE(C->dp[5]);
+   /* 6 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[23]);    MULADD(at[1], at[22]);    MULADD(at[2], at[21]);    MULADD(at[3], at[20]);    MULADD(at[4], at[19]);    MULADD(at[5], at[18]);    MULADD(at[6], at[17]);
+   COMBA_STORE(C->dp[6]);
+   /* 7 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[24]);    MULADD(at[1], at[23]);    MULADD(at[2], at[22]);    MULADD(at[3], at[21]);    MULADD(at[4], at[20]);    MULADD(at[5], at[19]);    MULADD(at[6], at[18]);    MULADD(at[7], at[17]);
+   COMBA_STORE(C->dp[7]);
+   /* 8 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[25]);    MULADD(at[1], at[24]);    MULADD(at[2], at[23]);    MULADD(at[3], at[22]);    MULADD(at[4], at[21]);    MULADD(at[5], at[20]);    MULADD(at[6], at[19]);    MULADD(at[7], at[18]);    MULADD(at[8], at[17]);
+   COMBA_STORE(C->dp[8]);
+   /* 9 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[26]);    MULADD(at[1], at[25]);    MULADD(at[2], at[24]);    MULADD(at[3], at[23]);    MULADD(at[4], at[22]);    MULADD(at[5], at[21]);    MULADD(at[6], at[20]);    MULADD(at[7], at[19]);    MULADD(at[8], at[18]);    MULADD(at[9], at[17]);
+   COMBA_STORE(C->dp[9]);
+   /* 10 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[27]);    MULADD(at[1], at[26]);    MULADD(at[2], at[25]);    MULADD(at[3], at[24]);    MULADD(at[4], at[23]);    MULADD(at[5], at[22]);    MULADD(at[6], at[21]);    MULADD(at[7], at[20]);    MULADD(at[8], at[19]);    MULADD(at[9], at[18]);    MULADD(at[10], at[17]);
+   COMBA_STORE(C->dp[10]);
+   /* 11 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[28]);    MULADD(at[1], at[27]);    MULADD(at[2], at[26]);    MULADD(at[3], at[25]);    MULADD(at[4], at[24]);    MULADD(at[5], at[23]);    MULADD(at[6], at[22]);    MULADD(at[7], at[21]);    MULADD(at[8], at[20]);    MULADD(at[9], at[19]);    MULADD(at[10], at[18]);    MULADD(at[11], at[17]);
+   COMBA_STORE(C->dp[11]);
+   /* 12 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[29]);    MULADD(at[1], at[28]);    MULADD(at[2], at[27]);    MULADD(at[3], at[26]);    MULADD(at[4], at[25]);    MULADD(at[5], at[24]);    MULADD(at[6], at[23]);    MULADD(at[7], at[22]);    MULADD(at[8], at[21]);    MULADD(at[9], at[20]);    MULADD(at[10], at[19]);    MULADD(at[11], at[18]);    MULADD(at[12], at[17]);
+   COMBA_STORE(C->dp[12]);
+   /* 13 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[30]);    MULADD(at[1], at[29]);    MULADD(at[2], at[28]);    MULADD(at[3], at[27]);    MULADD(at[4], at[26]);    MULADD(at[5], at[25]);    MULADD(at[6], at[24]);    MULADD(at[7], at[23]);    MULADD(at[8], at[22]);    MULADD(at[9], at[21]);    MULADD(at[10], at[20]);    MULADD(at[11], at[19]);    MULADD(at[12], at[18]);    MULADD(at[13], at[17]);
+   COMBA_STORE(C->dp[13]);
+   /* 14 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[31]);    MULADD(at[1], at[30]);    MULADD(at[2], at[29]);    MULADD(at[3], at[28]);    MULADD(at[4], at[27]);    MULADD(at[5], at[26]);    MULADD(at[6], at[25]);    MULADD(at[7], at[24]);    MULADD(at[8], at[23]);    MULADD(at[9], at[22]);    MULADD(at[10], at[21]);    MULADD(at[11], at[20]);    MULADD(at[12], at[19]);    MULADD(at[13], at[18]);    MULADD(at[14], at[17]);
+   COMBA_STORE(C->dp[14]);
+   /* 15 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[32]);    MULADD(at[1], at[31]);    MULADD(at[2], at[30]);    MULADD(at[3], at[29]);    MULADD(at[4], at[28]);    MULADD(at[5], at[27]);    MULADD(at[6], at[26]);    MULADD(at[7], at[25]);    MULADD(at[8], at[24]);    MULADD(at[9], at[23]);    MULADD(at[10], at[22]);    MULADD(at[11], at[21]);    MULADD(at[12], at[20]);    MULADD(at[13], at[19]);    MULADD(at[14], at[18]);    MULADD(at[15], at[17]);
+   COMBA_STORE(C->dp[15]);
+   /* 16 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[33]);    MULADD(at[1], at[32]);    MULADD(at[2], at[31]);    MULADD(at[3], at[30]);    MULADD(at[4], at[29]);    MULADD(at[5], at[28]);    MULADD(at[6], at[27]);    MULADD(at[7], at[26]);    MULADD(at[8], at[25]);    MULADD(at[9], at[24]);    MULADD(at[10], at[23]);    MULADD(at[11], at[22]);    MULADD(at[12], at[21]);    MULADD(at[13], at[20]);    MULADD(at[14], at[19]);    MULADD(at[15], at[18]);    MULADD(at[16], at[17]);
+   COMBA_STORE(C->dp[16]);
+   /* 17 */
+   COMBA_FORWARD;
+   MULADD(at[1], at[33]);    MULADD(at[2], at[32]);    MULADD(at[3], at[31]);    MULADD(at[4], at[30]);    MULADD(at[5], at[29]);    MULADD(at[6], at[28]);    MULADD(at[7], at[27]);    MULADD(at[8], at[26]);    MULADD(at[9], at[25]);    MULADD(at[10], at[24]);    MULADD(at[11], at[23]);    MULADD(at[12], at[22]);    MULADD(at[13], at[21]);    MULADD(at[14], at[20]);    MULADD(at[15], at[19]);    MULADD(at[16], at[18]);
+   COMBA_STORE(C->dp[17]);
+   /* 18 */
+   COMBA_FORWARD;
+   MULADD(at[2], at[33]);    MULADD(at[3], at[32]);    MULADD(at[4], at[31]);    MULADD(at[5], at[30]);    MULADD(at[6], at[29]);    MULADD(at[7], at[28]);    MULADD(at[8], at[27]);    MULADD(at[9], at[26]);    MULADD(at[10], at[25]);    MULADD(at[11], at[24]);    MULADD(at[12], at[23]);    MULADD(at[13], at[22]);    MULADD(at[14], at[21]);    MULADD(at[15], at[20]);    MULADD(at[16], at[19]);
+   COMBA_STORE(C->dp[18]);
+   /* 19 */
+   COMBA_FORWARD;
+   MULADD(at[3], at[33]);    MULADD(at[4], at[32]);    MULADD(at[5], at[31]);    MULADD(at[6], at[30]);    MULADD(at[7], at[29]);    MULADD(at[8], at[28]);    MULADD(at[9], at[27]);    MULADD(at[10], at[26]);    MULADD(at[11], at[25]);    MULADD(at[12], at[24]);    MULADD(at[13], at[23]);    MULADD(at[14], at[22]);    MULADD(at[15], at[21]);    MULADD(at[16], at[20]);
+   COMBA_STORE(C->dp[19]);
+   /* 20 */
+   COMBA_FORWARD;
+   MULADD(at[4], at[33]);    MULADD(at[5], at[32]);    MULADD(at[6], at[31]);    MULADD(at[7], at[30]);    MULADD(at[8], at[29]);    MULADD(at[9], at[28]);    MULADD(at[10], at[27]);    MULADD(at[11], at[26]);    MULADD(at[12], at[25]);    MULADD(at[13], at[24]);    MULADD(at[14], at[23]);    MULADD(at[15], at[22]);    MULADD(at[16], at[21]);
+   COMBA_STORE(C->dp[20]);
+   /* 21 */
+   COMBA_FORWARD;
+   MULADD(at[5], at[33]);    MULADD(at[6], at[32]);    MULADD(at[7], at[31]);    MULADD(at[8], at[30]);    MULADD(at[9], at[29]);    MULADD(at[10], at[28]);    MULADD(at[11], at[27]);    MULADD(at[12], at[26]);    MULADD(at[13], at[25]);    MULADD(at[14], at[24]);    MULADD(at[15], at[23]);    MULADD(at[16], at[22]);
+   COMBA_STORE(C->dp[21]);
+   /* 22 */
+   COMBA_FORWARD;
+   MULADD(at[6], at[33]);    MULADD(at[7], at[32]);    MULADD(at[8], at[31]);    MULADD(at[9], at[30]);    MULADD(at[10], at[29]);    MULADD(at[11], at[28]);    MULADD(at[12], at[27]);    MULADD(at[13], at[26]);    MULADD(at[14], at[25]);    MULADD(at[15], at[24]);    MULADD(at[16], at[23]);
+   COMBA_STORE(C->dp[22]);
+   /* 23 */
+   COMBA_FORWARD;
+   MULADD(at[7], at[33]);    MULADD(at[8], at[32]);    MULADD(at[9], at[31]);    MULADD(at[10], at[30]);    MULADD(at[11], at[29]);    MULADD(at[12], at[28]);    MULADD(at[13], at[27]);    MULADD(at[14], at[26]);    MULADD(at[15], at[25]);    MULADD(at[16], at[24]);
+   COMBA_STORE(C->dp[23]);
+   /* 24 */
+   COMBA_FORWARD;
+   MULADD(at[8], at[33]);    MULADD(at[9], at[32]);    MULADD(at[10], at[31]);    MULADD(at[11], at[30]);    MULADD(at[12], at[29]);    MULADD(at[13], at[28]);    MULADD(at[14], at[27]);    MULADD(at[15], at[26]);    MULADD(at[16], at[25]);
+   COMBA_STORE(C->dp[24]);
+   /* 25 */
+   COMBA_FORWARD;
+   MULADD(at[9], at[33]);    MULADD(at[10], at[32]);    MULADD(at[11], at[31]);    MULADD(at[12], at[30]);    MULADD(at[13], at[29]);    MULADD(at[14], at[28]);    MULADD(at[15], at[27]);    MULADD(at[16], at[26]);
+   COMBA_STORE(C->dp[25]);
+   /* 26 */
+   COMBA_FORWARD;
+   MULADD(at[10], at[33]);    MULADD(at[11], at[32]);    MULADD(at[12], at[31]);    MULADD(at[13], at[30]);    MULADD(at[14], at[29]);    MULADD(at[15], at[28]);    MULADD(at[16], at[27]);
+   COMBA_STORE(C->dp[26]);
+   /* 27 */
+   COMBA_FORWARD;
+   MULADD(at[11], at[33]);    MULADD(at[12], at[32]);    MULADD(at[13], at[31]);    MULADD(at[14], at[30]);    MULADD(at[15], at[29]);    MULADD(at[16], at[28]);
+   COMBA_STORE(C->dp[27]);
+   /* 28 */
+   COMBA_FORWARD;
+   MULADD(at[12], at[33]);    MULADD(at[13], at[32]);    MULADD(at[14], at[31]);    MULADD(at[15], at[30]);    MULADD(at[16], at[29]);
+   COMBA_STORE(C->dp[28]);
+   /* 29 */
+   COMBA_FORWARD;
+   MULADD(at[13], at[33]);    MULADD(at[14], at[32]);    MULADD(at[15], at[31]);    MULADD(at[16], at[30]);
+   COMBA_STORE(C->dp[29]);
+   /* 30 */
+   COMBA_FORWARD;
+   MULADD(at[14], at[33]);    MULADD(at[15], at[32]);    MULADD(at[16], at[31]);
+   COMBA_STORE(C->dp[30]);
+   /* 31 */
+   COMBA_FORWARD;
+   MULADD(at[15], at[33]);    MULADD(at[16], at[32]);
+   COMBA_STORE(C->dp[31]);
+   /* 32 */
+   COMBA_FORWARD;
+   MULADD(at[16], at[33]);
+   COMBA_STORE(C->dp[32]);
+   COMBA_STORE2(C->dp[33]);
+   C->used = 34;
+   C->sign = A->sign ^ B->sign;
+   fp_clamp(C);
+   COMBA_FINI;
+}
+#endif
+
+
+/* $Source$ */
+/* $Revision$ */
+/* $Date$ */
diff --git a/tomsfastmath/src/mul/fp_mul_comba_20.c b/tomsfastmath/src/mul/fp_mul_comba_20.c
new file mode 100644 (file)
index 0000000..905741d
--- /dev/null
@@ -0,0 +1,180 @@
+#define TFM_DEFINES
+#include "fp_mul_comba.c"
+
+#if defined(TFM_MUL20) && FP_SIZE >= 40
+void fp_mul_comba20(fp_int *A, fp_int *B, fp_int *C)
+{
+   fp_digit c0, c1, c2, at[40];
+
+   memcpy(at, A->dp, 20 * sizeof(fp_digit));
+   memcpy(at+20, B->dp, 20 * sizeof(fp_digit));
+   COMBA_START;
+
+   COMBA_CLEAR;
+   /* 0 */
+   MULADD(at[0], at[20]);
+   COMBA_STORE(C->dp[0]);
+   /* 1 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[21]);    MULADD(at[1], at[20]);
+   COMBA_STORE(C->dp[1]);
+   /* 2 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[22]);    MULADD(at[1], at[21]);    MULADD(at[2], at[20]);
+   COMBA_STORE(C->dp[2]);
+   /* 3 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[23]);    MULADD(at[1], at[22]);    MULADD(at[2], at[21]);    MULADD(at[3], at[20]);
+   COMBA_STORE(C->dp[3]);
+   /* 4 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[24]);    MULADD(at[1], at[23]);    MULADD(at[2], at[22]);    MULADD(at[3], at[21]);    MULADD(at[4], at[20]);
+   COMBA_STORE(C->dp[4]);
+   /* 5 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[25]);    MULADD(at[1], at[24]);    MULADD(at[2], at[23]);    MULADD(at[3], at[22]);    MULADD(at[4], at[21]);    MULADD(at[5], at[20]);
+   COMBA_STORE(C->dp[5]);
+   /* 6 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[26]);    MULADD(at[1], at[25]);    MULADD(at[2], at[24]);    MULADD(at[3], at[23]);    MULADD(at[4], at[22]);    MULADD(at[5], at[21]);    MULADD(at[6], at[20]);
+   COMBA_STORE(C->dp[6]);
+   /* 7 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[27]);    MULADD(at[1], at[26]);    MULADD(at[2], at[25]);    MULADD(at[3], at[24]);    MULADD(at[4], at[23]);    MULADD(at[5], at[22]);    MULADD(at[6], at[21]);    MULADD(at[7], at[20]);
+   COMBA_STORE(C->dp[7]);
+   /* 8 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[28]);    MULADD(at[1], at[27]);    MULADD(at[2], at[26]);    MULADD(at[3], at[25]);    MULADD(at[4], at[24]);    MULADD(at[5], at[23]);    MULADD(at[6], at[22]);    MULADD(at[7], at[21]);    MULADD(at[8], at[20]);
+   COMBA_STORE(C->dp[8]);
+   /* 9 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[29]);    MULADD(at[1], at[28]);    MULADD(at[2], at[27]);    MULADD(at[3], at[26]);    MULADD(at[4], at[25]);    MULADD(at[5], at[24]);    MULADD(at[6], at[23]);    MULADD(at[7], at[22]);    MULADD(at[8], at[21]);    MULADD(at[9], at[20]);
+   COMBA_STORE(C->dp[9]);
+   /* 10 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[30]);    MULADD(at[1], at[29]);    MULADD(at[2], at[28]);    MULADD(at[3], at[27]);    MULADD(at[4], at[26]);    MULADD(at[5], at[25]);    MULADD(at[6], at[24]);    MULADD(at[7], at[23]);    MULADD(at[8], at[22]);    MULADD(at[9], at[21]);    MULADD(at[10], at[20]);
+   COMBA_STORE(C->dp[10]);
+   /* 11 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[31]);    MULADD(at[1], at[30]);    MULADD(at[2], at[29]);    MULADD(at[3], at[28]);    MULADD(at[4], at[27]);    MULADD(at[5], at[26]);    MULADD(at[6], at[25]);    MULADD(at[7], at[24]);    MULADD(at[8], at[23]);    MULADD(at[9], at[22]);    MULADD(at[10], at[21]);    MULADD(at[11], at[20]);
+   COMBA_STORE(C->dp[11]);
+   /* 12 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[32]);    MULADD(at[1], at[31]);    MULADD(at[2], at[30]);    MULADD(at[3], at[29]);    MULADD(at[4], at[28]);    MULADD(at[5], at[27]);    MULADD(at[6], at[26]);    MULADD(at[7], at[25]);    MULADD(at[8], at[24]);    MULADD(at[9], at[23]);    MULADD(at[10], at[22]);    MULADD(at[11], at[21]);    MULADD(at[12], at[20]);
+   COMBA_STORE(C->dp[12]);
+   /* 13 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[33]);    MULADD(at[1], at[32]);    MULADD(at[2], at[31]);    MULADD(at[3], at[30]);    MULADD(at[4], at[29]);    MULADD(at[5], at[28]);    MULADD(at[6], at[27]);    MULADD(at[7], at[26]);    MULADD(at[8], at[25]);    MULADD(at[9], at[24]);    MULADD(at[10], at[23]);    MULADD(at[11], at[22]);    MULADD(at[12], at[21]);    MULADD(at[13], at[20]);
+   COMBA_STORE(C->dp[13]);
+   /* 14 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[34]);    MULADD(at[1], at[33]);    MULADD(at[2], at[32]);    MULADD(at[3], at[31]);    MULADD(at[4], at[30]);    MULADD(at[5], at[29]);    MULADD(at[6], at[28]);    MULADD(at[7], at[27]);    MULADD(at[8], at[26]);    MULADD(at[9], at[25]);    MULADD(at[10], at[24]);    MULADD(at[11], at[23]);    MULADD(at[12], at[22]);    MULADD(at[13], at[21]);    MULADD(at[14], at[20]);
+   COMBA_STORE(C->dp[14]);
+   /* 15 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[35]);    MULADD(at[1], at[34]);    MULADD(at[2], at[33]);    MULADD(at[3], at[32]);    MULADD(at[4], at[31]);    MULADD(at[5], at[30]);    MULADD(at[6], at[29]);    MULADD(at[7], at[28]);    MULADD(at[8], at[27]);    MULADD(at[9], at[26]);    MULADD(at[10], at[25]);    MULADD(at[11], at[24]);    MULADD(at[12], at[23]);    MULADD(at[13], at[22]);    MULADD(at[14], at[21]);    MULADD(at[15], at[20]);
+   COMBA_STORE(C->dp[15]);
+   /* 16 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[36]);    MULADD(at[1], at[35]);    MULADD(at[2], at[34]);    MULADD(at[3], at[33]);    MULADD(at[4], at[32]);    MULADD(at[5], at[31]);    MULADD(at[6], at[30]);    MULADD(at[7], at[29]);    MULADD(at[8], at[28]);    MULADD(at[9], at[27]);    MULADD(at[10], at[26]);    MULADD(at[11], at[25]);    MULADD(at[12], at[24]);    MULADD(at[13], at[23]);    MULADD(at[14], at[22]);    MULADD(at[15], at[21]);    MULADD(at[16], at[20]);
+   COMBA_STORE(C->dp[16]);
+   /* 17 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[37]);    MULADD(at[1], at[36]);    MULADD(at[2], at[35]);    MULADD(at[3], at[34]);    MULADD(at[4], at[33]);    MULADD(at[5], at[32]);    MULADD(at[6], at[31]);    MULADD(at[7], at[30]);    MULADD(at[8], at[29]);    MULADD(at[9], at[28]);    MULADD(at[10], at[27]);    MULADD(at[11], at[26]);    MULADD(at[12], at[25]);    MULADD(at[13], at[24]);    MULADD(at[14], at[23]);    MULADD(at[15], at[22]);    MULADD(at[16], at[21]);    MULADD(at[17], at[20]);
+   COMBA_STORE(C->dp[17]);
+   /* 18 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[38]);    MULADD(at[1], at[37]);    MULADD(at[2], at[36]);    MULADD(at[3], at[35]);    MULADD(at[4], at[34]);    MULADD(at[5], at[33]);    MULADD(at[6], at[32]);    MULADD(at[7], at[31]);    MULADD(at[8], at[30]);    MULADD(at[9], at[29]);    MULADD(at[10], at[28]);    MULADD(at[11], at[27]);    MULADD(at[12], at[26]);    MULADD(at[13], at[25]);    MULADD(at[14], at[24]);    MULADD(at[15], at[23]);    MULADD(at[16], at[22]);    MULADD(at[17], at[21]);    MULADD(at[18], at[20]);
+   COMBA_STORE(C->dp[18]);
+   /* 19 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[39]);    MULADD(at[1], at[38]);    MULADD(at[2], at[37]);    MULADD(at[3], at[36]);    MULADD(at[4], at[35]);    MULADD(at[5], at[34]);    MULADD(at[6], at[33]);    MULADD(at[7], at[32]);    MULADD(at[8], at[31]);    MULADD(at[9], at[30]);    MULADD(at[10], at[29]);    MULADD(at[11], at[28]);    MULADD(at[12], at[27]);    MULADD(at[13], at[26]);    MULADD(at[14], at[25]);    MULADD(at[15], at[24]);    MULADD(at[16], at[23]);    MULADD(at[17], at[22]);    MULADD(at[18], at[21]);    MULADD(at[19], at[20]);
+   COMBA_STORE(C->dp[19]);
+   /* 20 */
+   COMBA_FORWARD;
+   MULADD(at[1], at[39]);    MULADD(at[2], at[38]);    MULADD(at[3], at[37]);    MULADD(at[4], at[36]);    MULADD(at[5], at[35]);    MULADD(at[6], at[34]);    MULADD(at[7], at[33]);    MULADD(at[8], at[32]);    MULADD(at[9], at[31]);    MULADD(at[10], at[30]);    MULADD(at[11], at[29]);    MULADD(at[12], at[28]);    MULADD(at[13], at[27]);    MULADD(at[14], at[26]);    MULADD(at[15], at[25]);    MULADD(at[16], at[24]);    MULADD(at[17], at[23]);    MULADD(at[18], at[22]);    MULADD(at[19], at[21]);
+   COMBA_STORE(C->dp[20]);
+   /* 21 */
+   COMBA_FORWARD;
+   MULADD(at[2], at[39]);    MULADD(at[3], at[38]);    MULADD(at[4], at[37]);    MULADD(at[5], at[36]);    MULADD(at[6], at[35]);    MULADD(at[7], at[34]);    MULADD(at[8], at[33]);    MULADD(at[9], at[32]);    MULADD(at[10], at[31]);    MULADD(at[11], at[30]);    MULADD(at[12], at[29]);    MULADD(at[13], at[28]);    MULADD(at[14], at[27]);    MULADD(at[15], at[26]);    MULADD(at[16], at[25]);    MULADD(at[17], at[24]);    MULADD(at[18], at[23]);    MULADD(at[19], at[22]);
+   COMBA_STORE(C->dp[21]);
+   /* 22 */
+   COMBA_FORWARD;
+   MULADD(at[3], at[39]);    MULADD(at[4], at[38]);    MULADD(at[5], at[37]);    MULADD(at[6], at[36]);    MULADD(at[7], at[35]);    MULADD(at[8], at[34]);    MULADD(at[9], at[33]);    MULADD(at[10], at[32]);    MULADD(at[11], at[31]);    MULADD(at[12], at[30]);    MULADD(at[13], at[29]);    MULADD(at[14], at[28]);    MULADD(at[15], at[27]);    MULADD(at[16], at[26]);    MULADD(at[17], at[25]);    MULADD(at[18], at[24]);    MULADD(at[19], at[23]);
+   COMBA_STORE(C->dp[22]);
+   /* 23 */
+   COMBA_FORWARD;
+   MULADD(at[4], at[39]);    MULADD(at[5], at[38]);    MULADD(at[6], at[37]);    MULADD(at[7], at[36]);    MULADD(at[8], at[35]);    MULADD(at[9], at[34]);    MULADD(at[10], at[33]);    MULADD(at[11], at[32]);    MULADD(at[12], at[31]);    MULADD(at[13], at[30]);    MULADD(at[14], at[29]);    MULADD(at[15], at[28]);    MULADD(at[16], at[27]);    MULADD(at[17], at[26]);    MULADD(at[18], at[25]);    MULADD(at[19], at[24]);
+   COMBA_STORE(C->dp[23]);
+   /* 24 */
+   COMBA_FORWARD;
+   MULADD(at[5], at[39]);    MULADD(at[6], at[38]);    MULADD(at[7], at[37]);    MULADD(at[8], at[36]);    MULADD(at[9], at[35]);    MULADD(at[10], at[34]);    MULADD(at[11], at[33]);    MULADD(at[12], at[32]);    MULADD(at[13], at[31]);    MULADD(at[14], at[30]);    MULADD(at[15], at[29]);    MULADD(at[16], at[28]);    MULADD(at[17], at[27]);    MULADD(at[18], at[26]);    MULADD(at[19], at[25]);
+   COMBA_STORE(C->dp[24]);
+   /* 25 */
+   COMBA_FORWARD;
+   MULADD(at[6], at[39]);    MULADD(at[7], at[38]);    MULADD(at[8], at[37]);    MULADD(at[9], at[36]);    MULADD(at[10], at[35]);    MULADD(at[11], at[34]);    MULADD(at[12], at[33]);    MULADD(at[13], at[32]);    MULADD(at[14], at[31]);    MULADD(at[15], at[30]);    MULADD(at[16], at[29]);    MULADD(at[17], at[28]);    MULADD(at[18], at[27]);    MULADD(at[19], at[26]);
+   COMBA_STORE(C->dp[25]);
+   /* 26 */
+   COMBA_FORWARD;
+   MULADD(at[7], at[39]);    MULADD(at[8], at[38]);    MULADD(at[9], at[37]);    MULADD(at[10], at[36]);    MULADD(at[11], at[35]);    MULADD(at[12], at[34]);    MULADD(at[13], at[33]);    MULADD(at[14], at[32]);    MULADD(at[15], at[31]);    MULADD(at[16], at[30]);    MULADD(at[17], at[29]);    MULADD(at[18], at[28]);    MULADD(at[19], at[27]);
+   COMBA_STORE(C->dp[26]);
+   /* 27 */
+   COMBA_FORWARD;
+   MULADD(at[8], at[39]);    MULADD(at[9], at[38]);    MULADD(at[10], at[37]);    MULADD(at[11], at[36]);    MULADD(at[12], at[35]);    MULADD(at[13], at[34]);    MULADD(at[14], at[33]);    MULADD(at[15], at[32]);    MULADD(at[16], at[31]);    MULADD(at[17], at[30]);    MULADD(at[18], at[29]);    MULADD(at[19], at[28]);
+   COMBA_STORE(C->dp[27]);
+   /* 28 */
+   COMBA_FORWARD;
+   MULADD(at[9], at[39]);    MULADD(at[10], at[38]);    MULADD(at[11], at[37]);    MULADD(at[12], at[36]);    MULADD(at[13], at[35]);    MULADD(at[14], at[34]);    MULADD(at[15], at[33]);    MULADD(at[16], at[32]);    MULADD(at[17], at[31]);    MULADD(at[18], at[30]);    MULADD(at[19], at[29]);
+   COMBA_STORE(C->dp[28]);
+   /* 29 */
+   COMBA_FORWARD;
+   MULADD(at[10], at[39]);    MULADD(at[11], at[38]);    MULADD(at[12], at[37]);    MULADD(at[13], at[36]);    MULADD(at[14], at[35]);    MULADD(at[15], at[34]);    MULADD(at[16], at[33]);    MULADD(at[17], at[32]);    MULADD(at[18], at[31]);    MULADD(at[19], at[30]);
+   COMBA_STORE(C->dp[29]);
+   /* 30 */
+   COMBA_FORWARD;
+   MULADD(at[11], at[39]);    MULADD(at[12], at[38]);    MULADD(at[13], at[37]);    MULADD(at[14], at[36]);    MULADD(at[15], at[35]);    MULADD(at[16], at[34]);    MULADD(at[17], at[33]);    MULADD(at[18], at[32]);    MULADD(at[19], at[31]);
+   COMBA_STORE(C->dp[30]);
+   /* 31 */
+   COMBA_FORWARD;
+   MULADD(at[12], at[39]);    MULADD(at[13], at[38]);    MULADD(at[14], at[37]);    MULADD(at[15], at[36]);    MULADD(at[16], at[35]);    MULADD(at[17], at[34]);    MULADD(at[18], at[33]);    MULADD(at[19], at[32]);
+   COMBA_STORE(C->dp[31]);
+   /* 32 */
+   COMBA_FORWARD;
+   MULADD(at[13], at[39]);    MULADD(at[14], at[38]);    MULADD(at[15], at[37]);    MULADD(at[16], at[36]);    MULADD(at[17], at[35]);    MULADD(at[18], at[34]);    MULADD(at[19], at[33]);
+   COMBA_STORE(C->dp[32]);
+   /* 33 */
+   COMBA_FORWARD;
+   MULADD(at[14], at[39]);    MULADD(at[15], at[38]);    MULADD(at[16], at[37]);    MULADD(at[17], at[36]);    MULADD(at[18], at[35]);    MULADD(at[19], at[34]);
+   COMBA_STORE(C->dp[33]);
+   /* 34 */
+   COMBA_FORWARD;
+   MULADD(at[15], at[39]);    MULADD(at[16], at[38]);    MULADD(at[17], at[37]);    MULADD(at[18], at[36]);    MULADD(at[19], at[35]);
+   COMBA_STORE(C->dp[34]);
+   /* 35 */
+   COMBA_FORWARD;
+   MULADD(at[16], at[39]);    MULADD(at[17], at[38]);    MULADD(at[18], at[37]);    MULADD(at[19], at[36]);
+   COMBA_STORE(C->dp[35]);
+   /* 36 */
+   COMBA_FORWARD;
+   MULADD(at[17], at[39]);    MULADD(at[18], at[38]);    MULADD(at[19], at[37]);
+   COMBA_STORE(C->dp[36]);
+   /* 37 */
+   COMBA_FORWARD;
+   MULADD(at[18], at[39]);    MULADD(at[19], at[38]);
+   COMBA_STORE(C->dp[37]);
+   /* 38 */
+   COMBA_FORWARD;
+   MULADD(at[19], at[39]);
+   COMBA_STORE(C->dp[38]);
+   COMBA_STORE2(C->dp[39]);
+   C->used = 40;
+   C->sign = A->sign ^ B->sign;
+   fp_clamp(C);
+   COMBA_FINI;
+}
+#endif
+
+
+/* $Source$ */
+/* $Revision$ */
+/* $Date$ */
diff --git a/tomsfastmath/src/mul/fp_mul_comba_24.c b/tomsfastmath/src/mul/fp_mul_comba_24.c
new file mode 100644 (file)
index 0000000..0aaccad
--- /dev/null
@@ -0,0 +1,212 @@
+#define TFM_DEFINES
+#include "fp_mul_comba.c"
+
+#if defined(TFM_MUL24) && FP_SIZE >= 48
+void fp_mul_comba24(fp_int *A, fp_int *B, fp_int *C)
+{
+   fp_digit c0, c1, c2, at[48];
+
+   memcpy(at, A->dp, 24 * sizeof(fp_digit));
+   memcpy(at+24, B->dp, 24 * sizeof(fp_digit));
+   COMBA_START;
+
+   COMBA_CLEAR;
+   /* 0 */
+   MULADD(at[0], at[24]);
+   COMBA_STORE(C->dp[0]);
+   /* 1 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[25]);    MULADD(at[1], at[24]);
+   COMBA_STORE(C->dp[1]);
+   /* 2 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[26]);    MULADD(at[1], at[25]);    MULADD(at[2], at[24]);
+   COMBA_STORE(C->dp[2]);
+   /* 3 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[27]);    MULADD(at[1], at[26]);    MULADD(at[2], at[25]);    MULADD(at[3], at[24]);
+   COMBA_STORE(C->dp[3]);
+   /* 4 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[28]);    MULADD(at[1], at[27]);    MULADD(at[2], at[26]);    MULADD(at[3], at[25]);    MULADD(at[4], at[24]);
+   COMBA_STORE(C->dp[4]);
+   /* 5 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[29]);    MULADD(at[1], at[28]);    MULADD(at[2], at[27]);    MULADD(at[3], at[26]);    MULADD(at[4], at[25]);    MULADD(at[5], at[24]);
+   COMBA_STORE(C->dp[5]);
+   /* 6 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[30]);    MULADD(at[1], at[29]);    MULADD(at[2], at[28]);    MULADD(at[3], at[27]);    MULADD(at[4], at[26]);    MULADD(at[5], at[25]);    MULADD(at[6], at[24]);
+   COMBA_STORE(C->dp[6]);
+   /* 7 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[31]);    MULADD(at[1], at[30]);    MULADD(at[2], at[29]);    MULADD(at[3], at[28]);    MULADD(at[4], at[27]);    MULADD(at[5], at[26]);    MULADD(at[6], at[25]);    MULADD(at[7], at[24]);
+   COMBA_STORE(C->dp[7]);
+   /* 8 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[32]);    MULADD(at[1], at[31]);    MULADD(at[2], at[30]);    MULADD(at[3], at[29]);    MULADD(at[4], at[28]);    MULADD(at[5], at[27]);    MULADD(at[6], at[26]);    MULADD(at[7], at[25]);    MULADD(at[8], at[24]);
+   COMBA_STORE(C->dp[8]);
+   /* 9 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[33]);    MULADD(at[1], at[32]);    MULADD(at[2], at[31]);    MULADD(at[3], at[30]);    MULADD(at[4], at[29]);    MULADD(at[5], at[28]);    MULADD(at[6], at[27]);    MULADD(at[7], at[26]);    MULADD(at[8], at[25]);    MULADD(at[9], at[24]);
+   COMBA_STORE(C->dp[9]);
+   /* 10 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[34]);    MULADD(at[1], at[33]);    MULADD(at[2], at[32]);    MULADD(at[3], at[31]);    MULADD(at[4], at[30]);    MULADD(at[5], at[29]);    MULADD(at[6], at[28]);    MULADD(at[7], at[27]);    MULADD(at[8], at[26]);    MULADD(at[9], at[25]);    MULADD(at[10], at[24]);
+   COMBA_STORE(C->dp[10]);
+   /* 11 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[35]);    MULADD(at[1], at[34]);    MULADD(at[2], at[33]);    MULADD(at[3], at[32]);    MULADD(at[4], at[31]);    MULADD(at[5], at[30]);    MULADD(at[6], at[29]);    MULADD(at[7], at[28]);    MULADD(at[8], at[27]);    MULADD(at[9], at[26]);    MULADD(at[10], at[25]);    MULADD(at[11], at[24]);
+   COMBA_STORE(C->dp[11]);
+   /* 12 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[36]);    MULADD(at[1], at[35]);    MULADD(at[2], at[34]);    MULADD(at[3], at[33]);    MULADD(at[4], at[32]);    MULADD(at[5], at[31]);    MULADD(at[6], at[30]);    MULADD(at[7], at[29]);    MULADD(at[8], at[28]);    MULADD(at[9], at[27]);    MULADD(at[10], at[26]);    MULADD(at[11], at[25]);    MULADD(at[12], at[24]);
+   COMBA_STORE(C->dp[12]);
+   /* 13 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[37]);    MULADD(at[1], at[36]);    MULADD(at[2], at[35]);    MULADD(at[3], at[34]);    MULADD(at[4], at[33]);    MULADD(at[5], at[32]);    MULADD(at[6], at[31]);    MULADD(at[7], at[30]);    MULADD(at[8], at[29]);    MULADD(at[9], at[28]);    MULADD(at[10], at[27]);    MULADD(at[11], at[26]);    MULADD(at[12], at[25]);    MULADD(at[13], at[24]);
+   COMBA_STORE(C->dp[13]);
+   /* 14 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[38]);    MULADD(at[1], at[37]);    MULADD(at[2], at[36]);    MULADD(at[3], at[35]);    MULADD(at[4], at[34]);    MULADD(at[5], at[33]);    MULADD(at[6], at[32]);    MULADD(at[7], at[31]);    MULADD(at[8], at[30]);    MULADD(at[9], at[29]);    MULADD(at[10], at[28]);    MULADD(at[11], at[27]);    MULADD(at[12], at[26]);    MULADD(at[13], at[25]);    MULADD(at[14], at[24]);
+   COMBA_STORE(C->dp[14]);
+   /* 15 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[39]);    MULADD(at[1], at[38]);    MULADD(at[2], at[37]);    MULADD(at[3], at[36]);    MULADD(at[4], at[35]);    MULADD(at[5], at[34]);    MULADD(at[6], at[33]);    MULADD(at[7], at[32]);    MULADD(at[8], at[31]);    MULADD(at[9], at[30]);    MULADD(at[10], at[29]);    MULADD(at[11], at[28]);    MULADD(at[12], at[27]);    MULADD(at[13], at[26]);    MULADD(at[14], at[25]);    MULADD(at[15], at[24]);
+   COMBA_STORE(C->dp[15]);
+   /* 16 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[40]);    MULADD(at[1], at[39]);    MULADD(at[2], at[38]);    MULADD(at[3], at[37]);    MULADD(at[4], at[36]);    MULADD(at[5], at[35]);    MULADD(at[6], at[34]);    MULADD(at[7], at[33]);    MULADD(at[8], at[32]);    MULADD(at[9], at[31]);    MULADD(at[10], at[30]);    MULADD(at[11], at[29]);    MULADD(at[12], at[28]);    MULADD(at[13], at[27]);    MULADD(at[14], at[26]);    MULADD(at[15], at[25]);    MULADD(at[16], at[24]);
+   COMBA_STORE(C->dp[16]);
+   /* 17 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[41]);    MULADD(at[1], at[40]);    MULADD(at[2], at[39]);    MULADD(at[3], at[38]);    MULADD(at[4], at[37]);    MULADD(at[5], at[36]);    MULADD(at[6], at[35]);    MULADD(at[7], at[34]);    MULADD(at[8], at[33]);    MULADD(at[9], at[32]);    MULADD(at[10], at[31]);    MULADD(at[11], at[30]);    MULADD(at[12], at[29]);    MULADD(at[13], at[28]);    MULADD(at[14], at[27]);    MULADD(at[15], at[26]);    MULADD(at[16], at[25]);    MULADD(at[17], at[24]);
+   COMBA_STORE(C->dp[17]);
+   /* 18 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[42]);    MULADD(at[1], at[41]);    MULADD(at[2], at[40]);    MULADD(at[3], at[39]);    MULADD(at[4], at[38]);    MULADD(at[5], at[37]);    MULADD(at[6], at[36]);    MULADD(at[7], at[35]);    MULADD(at[8], at[34]);    MULADD(at[9], at[33]);    MULADD(at[10], at[32]);    MULADD(at[11], at[31]);    MULADD(at[12], at[30]);    MULADD(at[13], at[29]);    MULADD(at[14], at[28]);    MULADD(at[15], at[27]);    MULADD(at[16], at[26]);    MULADD(at[17], at[25]);    MULADD(at[18], at[24]);
+   COMBA_STORE(C->dp[18]);
+   /* 19 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[43]);    MULADD(at[1], at[42]);    MULADD(at[2], at[41]);    MULADD(at[3], at[40]);    MULADD(at[4], at[39]);    MULADD(at[5], at[38]);    MULADD(at[6], at[37]);    MULADD(at[7], at[36]);    MULADD(at[8], at[35]);    MULADD(at[9], at[34]);    MULADD(at[10], at[33]);    MULADD(at[11], at[32]);    MULADD(at[12], at[31]);    MULADD(at[13], at[30]);    MULADD(at[14], at[29]);    MULADD(at[15], at[28]);    MULADD(at[16], at[27]);    MULADD(at[17], at[26]);    MULADD(at[18], at[25]);    MULADD(at[19], at[24]);
+   COMBA_STORE(C->dp[19]);
+   /* 20 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[44]);    MULADD(at[1], at[43]);    MULADD(at[2], at[42]);    MULADD(at[3], at[41]);    MULADD(at[4], at[40]);    MULADD(at[5], at[39]);    MULADD(at[6], at[38]);    MULADD(at[7], at[37]);    MULADD(at[8], at[36]);    MULADD(at[9], at[35]);    MULADD(at[10], at[34]);    MULADD(at[11], at[33]);    MULADD(at[12], at[32]);    MULADD(at[13], at[31]);    MULADD(at[14], at[30]);    MULADD(at[15], at[29]);    MULADD(at[16], at[28]);    MULADD(at[17], at[27]);    MULADD(at[18], at[26]);    MULADD(at[19], at[25]);    MULADD(at[20], at[24]);
+   COMBA_STORE(C->dp[20]);
+   /* 21 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[45]);    MULADD(at[1], at[44]);    MULADD(at[2], at[43]);    MULADD(at[3], at[42]);    MULADD(at[4], at[41]);    MULADD(at[5], at[40]);    MULADD(at[6], at[39]);    MULADD(at[7], at[38]);    MULADD(at[8], at[37]);    MULADD(at[9], at[36]);    MULADD(at[10], at[35]);    MULADD(at[11], at[34]);    MULADD(at[12], at[33]);    MULADD(at[13], at[32]);    MULADD(at[14], at[31]);    MULADD(at[15], at[30]);    MULADD(at[16], at[29]);    MULADD(at[17], at[28]);    MULADD(at[18], at[27]);    MULADD(at[19], at[26]);    MULADD(at[20], at[25]);    MULADD(at[21], at[24]);
+   COMBA_STORE(C->dp[21]);
+   /* 22 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[46]);    MULADD(at[1], at[45]);    MULADD(at[2], at[44]);    MULADD(at[3], at[43]);    MULADD(at[4], at[42]);    MULADD(at[5], at[41]);    MULADD(at[6], at[40]);    MULADD(at[7], at[39]);    MULADD(at[8], at[38]);    MULADD(at[9], at[37]);    MULADD(at[10], at[36]);    MULADD(at[11], at[35]);    MULADD(at[12], at[34]);    MULADD(at[13], at[33]);    MULADD(at[14], at[32]);    MULADD(at[15], at[31]);    MULADD(at[16], at[30]);    MULADD(at[17], at[29]);    MULADD(at[18], at[28]);    MULADD(at[19], at[27]);    MULADD(at[20], at[26]);    MULADD(at[21], at[25]);    MULADD(at[22], at[24]);
+   COMBA_STORE(C->dp[22]);
+   /* 23 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[47]);    MULADD(at[1], at[46]);    MULADD(at[2], at[45]);    MULADD(at[3], at[44]);    MULADD(at[4], at[43]);    MULADD(at[5], at[42]);    MULADD(at[6], at[41]);    MULADD(at[7], at[40]);    MULADD(at[8], at[39]);    MULADD(at[9], at[38]);    MULADD(at[10], at[37]);    MULADD(at[11], at[36]);    MULADD(at[12], at[35]);    MULADD(at[13], at[34]);    MULADD(at[14], at[33]);    MULADD(at[15], at[32]);    MULADD(at[16], at[31]);    MULADD(at[17], at[30]);    MULADD(at[18], at[29]);    MULADD(at[19], at[28]);    MULADD(at[20], at[27]);    MULADD(at[21], at[26]);    MULADD(at[22], at[25]);    MULADD(at[23], at[24]);
+   COMBA_STORE(C->dp[23]);
+   /* 24 */
+   COMBA_FORWARD;
+   MULADD(at[1], at[47]);    MULADD(at[2], at[46]);    MULADD(at[3], at[45]);    MULADD(at[4], at[44]);    MULADD(at[5], at[43]);    MULADD(at[6], at[42]);    MULADD(at[7], at[41]);    MULADD(at[8], at[40]);    MULADD(at[9], at[39]);    MULADD(at[10], at[38]);    MULADD(at[11], at[37]);    MULADD(at[12], at[36]);    MULADD(at[13], at[35]);    MULADD(at[14], at[34]);    MULADD(at[15], at[33]);    MULADD(at[16], at[32]);    MULADD(at[17], at[31]);    MULADD(at[18], at[30]);    MULADD(at[19], at[29]);    MULADD(at[20], at[28]);    MULADD(at[21], at[27]);    MULADD(at[22], at[26]);    MULADD(at[23], at[25]);
+   COMBA_STORE(C->dp[24]);
+   /* 25 */
+   COMBA_FORWARD;
+   MULADD(at[2], at[47]);    MULADD(at[3], at[46]);    MULADD(at[4], at[45]);    MULADD(at[5], at[44]);    MULADD(at[6], at[43]);    MULADD(at[7], at[42]);    MULADD(at[8], at[41]);    MULADD(at[9], at[40]);    MULADD(at[10], at[39]);    MULADD(at[11], at[38]);    MULADD(at[12], at[37]);    MULADD(at[13], at[36]);    MULADD(at[14], at[35]);    MULADD(at[15], at[34]);    MULADD(at[16], at[33]);    MULADD(at[17], at[32]);    MULADD(at[18], at[31]);    MULADD(at[19], at[30]);    MULADD(at[20], at[29]);    MULADD(at[21], at[28]);    MULADD(at[22], at[27]);    MULADD(at[23], at[26]);
+   COMBA_STORE(C->dp[25]);
+   /* 26 */
+   COMBA_FORWARD;
+   MULADD(at[3], at[47]);    MULADD(at[4], at[46]);    MULADD(at[5], at[45]);    MULADD(at[6], at[44]);    MULADD(at[7], at[43]);    MULADD(at[8], at[42]);    MULADD(at[9], at[41]);    MULADD(at[10], at[40]);    MULADD(at[11], at[39]);    MULADD(at[12], at[38]);    MULADD(at[13], at[37]);    MULADD(at[14], at[36]);    MULADD(at[15], at[35]);    MULADD(at[16], at[34]);    MULADD(at[17], at[33]);    MULADD(at[18], at[32]);    MULADD(at[19], at[31]);    MULADD(at[20], at[30]);    MULADD(at[21], at[29]);    MULADD(at[22], at[28]);    MULADD(at[23], at[27]);
+   COMBA_STORE(C->dp[26]);
+   /* 27 */
+   COMBA_FORWARD;
+   MULADD(at[4], at[47]);    MULADD(at[5], at[46]);    MULADD(at[6], at[45]);    MULADD(at[7], at[44]);    MULADD(at[8], at[43]);    MULADD(at[9], at[42]);    MULADD(at[10], at[41]);    MULADD(at[11], at[40]);    MULADD(at[12], at[39]);    MULADD(at[13], at[38]);    MULADD(at[14], at[37]);    MULADD(at[15], at[36]);    MULADD(at[16], at[35]);    MULADD(at[17], at[34]);    MULADD(at[18], at[33]);    MULADD(at[19], at[32]);    MULADD(at[20], at[31]);    MULADD(at[21], at[30]);    MULADD(at[22], at[29]);    MULADD(at[23], at[28]);
+   COMBA_STORE(C->dp[27]);
+   /* 28 */
+   COMBA_FORWARD;
+   MULADD(at[5], at[47]);    MULADD(at[6], at[46]);    MULADD(at[7], at[45]);    MULADD(at[8], at[44]);    MULADD(at[9], at[43]);    MULADD(at[10], at[42]);    MULADD(at[11], at[41]);    MULADD(at[12], at[40]);    MULADD(at[13], at[39]);    MULADD(at[14], at[38]);    MULADD(at[15], at[37]);    MULADD(at[16], at[36]);    MULADD(at[17], at[35]);    MULADD(at[18], at[34]);    MULADD(at[19], at[33]);    MULADD(at[20], at[32]);    MULADD(at[21], at[31]);    MULADD(at[22], at[30]);    MULADD(at[23], at[29]);
+   COMBA_STORE(C->dp[28]);
+   /* 29 */
+   COMBA_FORWARD;
+   MULADD(at[6], at[47]);    MULADD(at[7], at[46]);    MULADD(at[8], at[45]);    MULADD(at[9], at[44]);    MULADD(at[10], at[43]);    MULADD(at[11], at[42]);    MULADD(at[12], at[41]);    MULADD(at[13], at[40]);    MULADD(at[14], at[39]);    MULADD(at[15], at[38]);    MULADD(at[16], at[37]);    MULADD(at[17], at[36]);    MULADD(at[18], at[35]);    MULADD(at[19], at[34]);    MULADD(at[20], at[33]);    MULADD(at[21], at[32]);    MULADD(at[22], at[31]);    MULADD(at[23], at[30]);
+   COMBA_STORE(C->dp[29]);
+   /* 30 */
+   COMBA_FORWARD;
+   MULADD(at[7], at[47]);    MULADD(at[8], at[46]);    MULADD(at[9], at[45]);    MULADD(at[10], at[44]);    MULADD(at[11], at[43]);    MULADD(at[12], at[42]);    MULADD(at[13], at[41]);    MULADD(at[14], at[40]);    MULADD(at[15], at[39]);    MULADD(at[16], at[38]);    MULADD(at[17], at[37]);    MULADD(at[18], at[36]);    MULADD(at[19], at[35]);    MULADD(at[20], at[34]);    MULADD(at[21], at[33]);    MULADD(at[22], at[32]);    MULADD(at[23], at[31]);
+   COMBA_STORE(C->dp[30]);
+   /* 31 */
+   COMBA_FORWARD;
+   MULADD(at[8], at[47]);    MULADD(at[9], at[46]);    MULADD(at[10], at[45]);    MULADD(at[11], at[44]);    MULADD(at[12], at[43]);    MULADD(at[13], at[42]);    MULADD(at[14], at[41]);    MULADD(at[15], at[40]);    MULADD(at[16], at[39]);    MULADD(at[17], at[38]);    MULADD(at[18], at[37]);    MULADD(at[19], at[36]);    MULADD(at[20], at[35]);    MULADD(at[21], at[34]);    MULADD(at[22], at[33]);    MULADD(at[23], at[32]);
+   COMBA_STORE(C->dp[31]);
+   /* 32 */
+   COMBA_FORWARD;
+   MULADD(at[9], at[47]);    MULADD(at[10], at[46]);    MULADD(at[11], at[45]);    MULADD(at[12], at[44]);    MULADD(at[13], at[43]);    MULADD(at[14], at[42]);    MULADD(at[15], at[41]);    MULADD(at[16], at[40]);    MULADD(at[17], at[39]);    MULADD(at[18], at[38]);    MULADD(at[19], at[37]);    MULADD(at[20], at[36]);    MULADD(at[21], at[35]);    MULADD(at[22], at[34]);    MULADD(at[23], at[33]);
+   COMBA_STORE(C->dp[32]);
+   /* 33 */
+   COMBA_FORWARD;
+   MULADD(at[10], at[47]);    MULADD(at[11], at[46]);    MULADD(at[12], at[45]);    MULADD(at[13], at[44]);    MULADD(at[14], at[43]);    MULADD(at[15], at[42]);    MULADD(at[16], at[41]);    MULADD(at[17], at[40]);    MULADD(at[18], at[39]);    MULADD(at[19], at[38]);    MULADD(at[20], at[37]);    MULADD(at[21], at[36]);    MULADD(at[22], at[35]);    MULADD(at[23], at[34]);
+   COMBA_STORE(C->dp[33]);
+   /* 34 */
+   COMBA_FORWARD;
+   MULADD(at[11], at[47]);    MULADD(at[12], at[46]);    MULADD(at[13], at[45]);    MULADD(at[14], at[44]);    MULADD(at[15], at[43]);    MULADD(at[16], at[42]);    MULADD(at[17], at[41]);    MULADD(at[18], at[40]);    MULADD(at[19], at[39]);    MULADD(at[20], at[38]);    MULADD(at[21], at[37]);    MULADD(at[22], at[36]);    MULADD(at[23], at[35]);
+   COMBA_STORE(C->dp[34]);
+   /* 35 */
+   COMBA_FORWARD;
+   MULADD(at[12], at[47]);    MULADD(at[13], at[46]);    MULADD(at[14], at[45]);    MULADD(at[15], at[44]);    MULADD(at[16], at[43]);    MULADD(at[17], at[42]);    MULADD(at[18], at[41]);    MULADD(at[19], at[40]);    MULADD(at[20], at[39]);    MULADD(at[21], at[38]);    MULADD(at[22], at[37]);    MULADD(at[23], at[36]);
+   COMBA_STORE(C->dp[35]);
+   /* 36 */
+   COMBA_FORWARD;
+   MULADD(at[13], at[47]);    MULADD(at[14], at[46]);    MULADD(at[15], at[45]);    MULADD(at[16], at[44]);    MULADD(at[17], at[43]);    MULADD(at[18], at[42]);    MULADD(at[19], at[41]);    MULADD(at[20], at[40]);    MULADD(at[21], at[39]);    MULADD(at[22], at[38]);    MULADD(at[23], at[37]);
+   COMBA_STORE(C->dp[36]);
+   /* 37 */
+   COMBA_FORWARD;
+   MULADD(at[14], at[47]);    MULADD(at[15], at[46]);    MULADD(at[16], at[45]);    MULADD(at[17], at[44]);    MULADD(at[18], at[43]);    MULADD(at[19], at[42]);    MULADD(at[20], at[41]);    MULADD(at[21], at[40]);    MULADD(at[22], at[39]);    MULADD(at[23], at[38]);
+   COMBA_STORE(C->dp[37]);
+   /* 38 */
+   COMBA_FORWARD;
+   MULADD(at[15], at[47]);    MULADD(at[16], at[46]);    MULADD(at[17], at[45]);    MULADD(at[18], at[44]);    MULADD(at[19], at[43]);    MULADD(at[20], at[42]);    MULADD(at[21], at[41]);    MULADD(at[22], at[40]);    MULADD(at[23], at[39]);
+   COMBA_STORE(C->dp[38]);
+   /* 39 */
+   COMBA_FORWARD;
+   MULADD(at[16], at[47]);    MULADD(at[17], at[46]);    MULADD(at[18], at[45]);    MULADD(at[19], at[44]);    MULADD(at[20], at[43]);    MULADD(at[21], at[42]);    MULADD(at[22], at[41]);    MULADD(at[23], at[40]);
+   COMBA_STORE(C->dp[39]);
+   /* 40 */
+   COMBA_FORWARD;
+   MULADD(at[17], at[47]);    MULADD(at[18], at[46]);    MULADD(at[19], at[45]);    MULADD(at[20], at[44]);    MULADD(at[21], at[43]);    MULADD(at[22], at[42]);    MULADD(at[23], at[41]);
+   COMBA_STORE(C->dp[40]);
+   /* 41 */
+   COMBA_FORWARD;
+   MULADD(at[18], at[47]);    MULADD(at[19], at[46]);    MULADD(at[20], at[45]);    MULADD(at[21], at[44]);    MULADD(at[22], at[43]);    MULADD(at[23], at[42]);
+   COMBA_STORE(C->dp[41]);
+   /* 42 */
+   COMBA_FORWARD;
+   MULADD(at[19], at[47]);    MULADD(at[20], at[46]);    MULADD(at[21], at[45]);    MULADD(at[22], at[44]);    MULADD(at[23], at[43]);
+   COMBA_STORE(C->dp[42]);
+   /* 43 */
+   COMBA_FORWARD;
+   MULADD(at[20], at[47]);    MULADD(at[21], at[46]);    MULADD(at[22], at[45]);    MULADD(at[23], at[44]);
+   COMBA_STORE(C->dp[43]);
+   /* 44 */
+   COMBA_FORWARD;
+   MULADD(at[21], at[47]);    MULADD(at[22], at[46]);    MULADD(at[23], at[45]);
+   COMBA_STORE(C->dp[44]);
+   /* 45 */
+   COMBA_FORWARD;
+   MULADD(at[22], at[47]);    MULADD(at[23], at[46]);
+   COMBA_STORE(C->dp[45]);
+   /* 46 */
+   COMBA_FORWARD;
+   MULADD(at[23], at[47]);
+   COMBA_STORE(C->dp[46]);
+   COMBA_STORE2(C->dp[47]);
+   C->used = 48;
+   C->sign = A->sign ^ B->sign;
+   fp_clamp(C);
+   COMBA_FINI;
+}
+#endif
+
+
+/* $Source$ */
+/* $Revision$ */
+/* $Date$ */
diff --git a/tomsfastmath/src/mul/fp_mul_comba_28.c b/tomsfastmath/src/mul/fp_mul_comba_28.c
new file mode 100644 (file)
index 0000000..d72c08e
--- /dev/null
@@ -0,0 +1,244 @@
+#define TFM_DEFINES
+#include "fp_mul_comba.c"
+
+#if defined(TFM_MUL28) && FP_SIZE >= 56
+void fp_mul_comba28(fp_int *A, fp_int *B, fp_int *C)
+{
+   fp_digit c0, c1, c2, at[56];
+
+   memcpy(at, A->dp, 28 * sizeof(fp_digit));
+   memcpy(at+28, B->dp, 28 * sizeof(fp_digit));
+   COMBA_START;
+
+   COMBA_CLEAR;
+   /* 0 */
+   MULADD(at[0], at[28]);
+   COMBA_STORE(C->dp[0]);
+   /* 1 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[29]);    MULADD(at[1], at[28]);
+   COMBA_STORE(C->dp[1]);
+   /* 2 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[30]);    MULADD(at[1], at[29]);    MULADD(at[2], at[28]);
+   COMBA_STORE(C->dp[2]);
+   /* 3 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[31]);    MULADD(at[1], at[30]);    MULADD(at[2], at[29]);    MULADD(at[3], at[28]);
+   COMBA_STORE(C->dp[3]);
+   /* 4 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[32]);    MULADD(at[1], at[31]);    MULADD(at[2], at[30]);    MULADD(at[3], at[29]);    MULADD(at[4], at[28]);
+   COMBA_STORE(C->dp[4]);
+   /* 5 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[33]);    MULADD(at[1], at[32]);    MULADD(at[2], at[31]);    MULADD(at[3], at[30]);    MULADD(at[4], at[29]);    MULADD(at[5], at[28]);
+   COMBA_STORE(C->dp[5]);
+   /* 6 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[34]);    MULADD(at[1], at[33]);    MULADD(at[2], at[32]);    MULADD(at[3], at[31]);    MULADD(at[4], at[30]);    MULADD(at[5], at[29]);    MULADD(at[6], at[28]);
+   COMBA_STORE(C->dp[6]);
+   /* 7 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[35]);    MULADD(at[1], at[34]);    MULADD(at[2], at[33]);    MULADD(at[3], at[32]);    MULADD(at[4], at[31]);    MULADD(at[5], at[30]);    MULADD(at[6], at[29]);    MULADD(at[7], at[28]);
+   COMBA_STORE(C->dp[7]);
+   /* 8 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[36]);    MULADD(at[1], at[35]);    MULADD(at[2], at[34]);    MULADD(at[3], at[33]);    MULADD(at[4], at[32]);    MULADD(at[5], at[31]);    MULADD(at[6], at[30]);    MULADD(at[7], at[29]);    MULADD(at[8], at[28]);
+   COMBA_STORE(C->dp[8]);
+   /* 9 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[37]);    MULADD(at[1], at[36]);    MULADD(at[2], at[35]);    MULADD(at[3], at[34]);    MULADD(at[4], at[33]);    MULADD(at[5], at[32]);    MULADD(at[6], at[31]);    MULADD(at[7], at[30]);    MULADD(at[8], at[29]);    MULADD(at[9], at[28]);
+   COMBA_STORE(C->dp[9]);
+   /* 10 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[38]);    MULADD(at[1], at[37]);    MULADD(at[2], at[36]);    MULADD(at[3], at[35]);    MULADD(at[4], at[34]);    MULADD(at[5], at[33]);    MULADD(at[6], at[32]);    MULADD(at[7], at[31]);    MULADD(at[8], at[30]);    MULADD(at[9], at[29]);    MULADD(at[10], at[28]);
+   COMBA_STORE(C->dp[10]);
+   /* 11 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[39]);    MULADD(at[1], at[38]);    MULADD(at[2], at[37]);    MULADD(at[3], at[36]);    MULADD(at[4], at[35]);    MULADD(at[5], at[34]);    MULADD(at[6], at[33]);    MULADD(at[7], at[32]);    MULADD(at[8], at[31]);    MULADD(at[9], at[30]);    MULADD(at[10], at[29]);    MULADD(at[11], at[28]);
+   COMBA_STORE(C->dp[11]);
+   /* 12 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[40]);    MULADD(at[1], at[39]);    MULADD(at[2], at[38]);    MULADD(at[3], at[37]);    MULADD(at[4], at[36]);    MULADD(at[5], at[35]);    MULADD(at[6], at[34]);    MULADD(at[7], at[33]);    MULADD(at[8], at[32]);    MULADD(at[9], at[31]);    MULADD(at[10], at[30]);    MULADD(at[11], at[29]);    MULADD(at[12], at[28]);
+   COMBA_STORE(C->dp[12]);
+   /* 13 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[41]);    MULADD(at[1], at[40]);    MULADD(at[2], at[39]);    MULADD(at[3], at[38]);    MULADD(at[4], at[37]);    MULADD(at[5], at[36]);    MULADD(at[6], at[35]);    MULADD(at[7], at[34]);    MULADD(at[8], at[33]);    MULADD(at[9], at[32]);    MULADD(at[10], at[31]);    MULADD(at[11], at[30]);    MULADD(at[12], at[29]);    MULADD(at[13], at[28]);
+   COMBA_STORE(C->dp[13]);
+   /* 14 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[42]);    MULADD(at[1], at[41]);    MULADD(at[2], at[40]);    MULADD(at[3], at[39]);    MULADD(at[4], at[38]);    MULADD(at[5], at[37]);    MULADD(at[6], at[36]);    MULADD(at[7], at[35]);    MULADD(at[8], at[34]);    MULADD(at[9], at[33]);    MULADD(at[10], at[32]);    MULADD(at[11], at[31]);    MULADD(at[12], at[30]);    MULADD(at[13], at[29]);    MULADD(at[14], at[28]);
+   COMBA_STORE(C->dp[14]);
+   /* 15 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[43]);    MULADD(at[1], at[42]);    MULADD(at[2], at[41]);    MULADD(at[3], at[40]);    MULADD(at[4], at[39]);    MULADD(at[5], at[38]);    MULADD(at[6], at[37]);    MULADD(at[7], at[36]);    MULADD(at[8], at[35]);    MULADD(at[9], at[34]);    MULADD(at[10], at[33]);    MULADD(at[11], at[32]);    MULADD(at[12], at[31]);    MULADD(at[13], at[30]);    MULADD(at[14], at[29]);    MULADD(at[15], at[28]);
+   COMBA_STORE(C->dp[15]);
+   /* 16 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[44]);    MULADD(at[1], at[43]);    MULADD(at[2], at[42]);    MULADD(at[3], at[41]);    MULADD(at[4], at[40]);    MULADD(at[5], at[39]);    MULADD(at[6], at[38]);    MULADD(at[7], at[37]);    MULADD(at[8], at[36]);    MULADD(at[9], at[35]);    MULADD(at[10], at[34]);    MULADD(at[11], at[33]);    MULADD(at[12], at[32]);    MULADD(at[13], at[31]);    MULADD(at[14], at[30]);    MULADD(at[15], at[29]);    MULADD(at[16], at[28]);
+   COMBA_STORE(C->dp[16]);
+   /* 17 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[45]);    MULADD(at[1], at[44]);    MULADD(at[2], at[43]);    MULADD(at[3], at[42]);    MULADD(at[4], at[41]);    MULADD(at[5], at[40]);    MULADD(at[6], at[39]);    MULADD(at[7], at[38]);    MULADD(at[8], at[37]);    MULADD(at[9], at[36]);    MULADD(at[10], at[35]);    MULADD(at[11], at[34]);    MULADD(at[12], at[33]);    MULADD(at[13], at[32]);    MULADD(at[14], at[31]);    MULADD(at[15], at[30]);    MULADD(at[16], at[29]);    MULADD(at[17], at[28]);
+   COMBA_STORE(C->dp[17]);
+   /* 18 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[46]);    MULADD(at[1], at[45]);    MULADD(at[2], at[44]);    MULADD(at[3], at[43]);    MULADD(at[4], at[42]);    MULADD(at[5], at[41]);    MULADD(at[6], at[40]);    MULADD(at[7], at[39]);    MULADD(at[8], at[38]);    MULADD(at[9], at[37]);    MULADD(at[10], at[36]);    MULADD(at[11], at[35]);    MULADD(at[12], at[34]);    MULADD(at[13], at[33]);    MULADD(at[14], at[32]);    MULADD(at[15], at[31]);    MULADD(at[16], at[30]);    MULADD(at[17], at[29]);    MULADD(at[18], at[28]);
+   COMBA_STORE(C->dp[18]);
+   /* 19 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[47]);    MULADD(at[1], at[46]);    MULADD(at[2], at[45]);    MULADD(at[3], at[44]);    MULADD(at[4], at[43]);    MULADD(at[5], at[42]);    MULADD(at[6], at[41]);    MULADD(at[7], at[40]);    MULADD(at[8], at[39]);    MULADD(at[9], at[38]);    MULADD(at[10], at[37]);    MULADD(at[11], at[36]);    MULADD(at[12], at[35]);    MULADD(at[13], at[34]);    MULADD(at[14], at[33]);    MULADD(at[15], at[32]);    MULADD(at[16], at[31]);    MULADD(at[17], at[30]);    MULADD(at[18], at[29]);    MULADD(at[19], at[28]);
+   COMBA_STORE(C->dp[19]);
+   /* 20 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[48]);    MULADD(at[1], at[47]);    MULADD(at[2], at[46]);    MULADD(at[3], at[45]);    MULADD(at[4], at[44]);    MULADD(at[5], at[43]);    MULADD(at[6], at[42]);    MULADD(at[7], at[41]);    MULADD(at[8], at[40]);    MULADD(at[9], at[39]);    MULADD(at[10], at[38]);    MULADD(at[11], at[37]);    MULADD(at[12], at[36]);    MULADD(at[13], at[35]);    MULADD(at[14], at[34]);    MULADD(at[15], at[33]);    MULADD(at[16], at[32]);    MULADD(at[17], at[31]);    MULADD(at[18], at[30]);    MULADD(at[19], at[29]);    MULADD(at[20], at[28]);
+   COMBA_STORE(C->dp[20]);
+   /* 21 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[49]);    MULADD(at[1], at[48]);    MULADD(at[2], at[47]);    MULADD(at[3], at[46]);    MULADD(at[4], at[45]);    MULADD(at[5], at[44]);    MULADD(at[6], at[43]);    MULADD(at[7], at[42]);    MULADD(at[8], at[41]);    MULADD(at[9], at[40]);    MULADD(at[10], at[39]);    MULADD(at[11], at[38]);    MULADD(at[12], at[37]);    MULADD(at[13], at[36]);    MULADD(at[14], at[35]);    MULADD(at[15], at[34]);    MULADD(at[16], at[33]);    MULADD(at[17], at[32]);    MULADD(at[18], at[31]);    MULADD(at[19], at[30]);    MULADD(at[20], at[29]);    MULADD(at[21], at[28]);
+   COMBA_STORE(C->dp[21]);
+   /* 22 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[50]);    MULADD(at[1], at[49]);    MULADD(at[2], at[48]);    MULADD(at[3], at[47]);    MULADD(at[4], at[46]);    MULADD(at[5], at[45]);    MULADD(at[6], at[44]);    MULADD(at[7], at[43]);    MULADD(at[8], at[42]);    MULADD(at[9], at[41]);    MULADD(at[10], at[40]);    MULADD(at[11], at[39]);    MULADD(at[12], at[38]);    MULADD(at[13], at[37]);    MULADD(at[14], at[36]);    MULADD(at[15], at[35]);    MULADD(at[16], at[34]);    MULADD(at[17], at[33]);    MULADD(at[18], at[32]);    MULADD(at[19], at[31]);    MULADD(at[20], at[30]);    MULADD(at[21], at[29]);    MULADD(at[22], at[28]);
+   COMBA_STORE(C->dp[22]);
+   /* 23 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[51]);    MULADD(at[1], at[50]);    MULADD(at[2], at[49]);    MULADD(at[3], at[48]);    MULADD(at[4], at[47]);    MULADD(at[5], at[46]);    MULADD(at[6], at[45]);    MULADD(at[7], at[44]);    MULADD(at[8], at[43]);    MULADD(at[9], at[42]);    MULADD(at[10], at[41]);    MULADD(at[11], at[40]);    MULADD(at[12], at[39]);    MULADD(at[13], at[38]);    MULADD(at[14], at[37]);    MULADD(at[15], at[36]);    MULADD(at[16], at[35]);    MULADD(at[17], at[34]);    MULADD(at[18], at[33]);    MULADD(at[19], at[32]);    MULADD(at[20], at[31]);    MULADD(at[21], at[30]);    MULADD(at[22], at[29]);    MULADD(at[23], at[28]);
+   COMBA_STORE(C->dp[23]);
+   /* 24 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[52]);    MULADD(at[1], at[51]);    MULADD(at[2], at[50]);    MULADD(at[3], at[49]);    MULADD(at[4], at[48]);    MULADD(at[5], at[47]);    MULADD(at[6], at[46]);    MULADD(at[7], at[45]);    MULADD(at[8], at[44]);    MULADD(at[9], at[43]);    MULADD(at[10], at[42]);    MULADD(at[11], at[41]);    MULADD(at[12], at[40]);    MULADD(at[13], at[39]);    MULADD(at[14], at[38]);    MULADD(at[15], at[37]);    MULADD(at[16], at[36]);    MULADD(at[17], at[35]);    MULADD(at[18], at[34]);    MULADD(at[19], at[33]);    MULADD(at[20], at[32]);    MULADD(at[21], at[31]);    MULADD(at[22], at[30]);    MULADD(at[23], at[29]);    MULADD(at[24], at[28]);
+   COMBA_STORE(C->dp[24]);
+   /* 25 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[53]);    MULADD(at[1], at[52]);    MULADD(at[2], at[51]);    MULADD(at[3], at[50]);    MULADD(at[4], at[49]);    MULADD(at[5], at[48]);    MULADD(at[6], at[47]);    MULADD(at[7], at[46]);    MULADD(at[8], at[45]);    MULADD(at[9], at[44]);    MULADD(at[10], at[43]);    MULADD(at[11], at[42]);    MULADD(at[12], at[41]);    MULADD(at[13], at[40]);    MULADD(at[14], at[39]);    MULADD(at[15], at[38]);    MULADD(at[16], at[37]);    MULADD(at[17], at[36]);    MULADD(at[18], at[35]);    MULADD(at[19], at[34]);    MULADD(at[20], at[33]);    MULADD(at[21], at[32]);    MULADD(at[22], at[31]);    MULADD(at[23], at[30]);    MULADD(at[24], at[29]);    MULADD(at[25], at[28]);
+   COMBA_STORE(C->dp[25]);
+   /* 26 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[54]);    MULADD(at[1], at[53]);    MULADD(at[2], at[52]);    MULADD(at[3], at[51]);    MULADD(at[4], at[50]);    MULADD(at[5], at[49]);    MULADD(at[6], at[48]);    MULADD(at[7], at[47]);    MULADD(at[8], at[46]);    MULADD(at[9], at[45]);    MULADD(at[10], at[44]);    MULADD(at[11], at[43]);    MULADD(at[12], at[42]);    MULADD(at[13], at[41]);    MULADD(at[14], at[40]);    MULADD(at[15], at[39]);    MULADD(at[16], at[38]);    MULADD(at[17], at[37]);    MULADD(at[18], at[36]);    MULADD(at[19], at[35]);    MULADD(at[20], at[34]);    MULADD(at[21], at[33]);    MULADD(at[22], at[32]);    MULADD(at[23], at[31]);    MULADD(at[24], at[30]);    MULADD(at[25], at[29]);    MULADD(at[26], at[28]);
+   COMBA_STORE(C->dp[26]);
+   /* 27 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[55]);    MULADD(at[1], at[54]);    MULADD(at[2], at[53]);    MULADD(at[3], at[52]);    MULADD(at[4], at[51]);    MULADD(at[5], at[50]);    MULADD(at[6], at[49]);    MULADD(at[7], at[48]);    MULADD(at[8], at[47]);    MULADD(at[9], at[46]);    MULADD(at[10], at[45]);    MULADD(at[11], at[44]);    MULADD(at[12], at[43]);    MULADD(at[13], at[42]);    MULADD(at[14], at[41]);    MULADD(at[15], at[40]);    MULADD(at[16], at[39]);    MULADD(at[17], at[38]);    MULADD(at[18], at[37]);    MULADD(at[19], at[36]);    MULADD(at[20], at[35]);    MULADD(at[21], at[34]);    MULADD(at[22], at[33]);    MULADD(at[23], at[32]);    MULADD(at[24], at[31]);    MULADD(at[25], at[30]);    MULADD(at[26], at[29]);    MULADD(at[27], at[28]);
+   COMBA_STORE(C->dp[27]);
+   /* 28 */
+   COMBA_FORWARD;
+   MULADD(at[1], at[55]);    MULADD(at[2], at[54]);    MULADD(at[3], at[53]);    MULADD(at[4], at[52]);    MULADD(at[5], at[51]);    MULADD(at[6], at[50]);    MULADD(at[7], at[49]);    MULADD(at[8], at[48]);    MULADD(at[9], at[47]);    MULADD(at[10], at[46]);    MULADD(at[11], at[45]);    MULADD(at[12], at[44]);    MULADD(at[13], at[43]);    MULADD(at[14], at[42]);    MULADD(at[15], at[41]);    MULADD(at[16], at[40]);    MULADD(at[17], at[39]);    MULADD(at[18], at[38]);    MULADD(at[19], at[37]);    MULADD(at[20], at[36]);    MULADD(at[21], at[35]);    MULADD(at[22], at[34]);    MULADD(at[23], at[33]);    MULADD(at[24], at[32]);    MULADD(at[25], at[31]);    MULADD(at[26], at[30]);    MULADD(at[27], at[29]);
+   COMBA_STORE(C->dp[28]);
+   /* 29 */
+   COMBA_FORWARD;
+   MULADD(at[2], at[55]);    MULADD(at[3], at[54]);    MULADD(at[4], at[53]);    MULADD(at[5], at[52]);    MULADD(at[6], at[51]);    MULADD(at[7], at[50]);    MULADD(at[8], at[49]);    MULADD(at[9], at[48]);    MULADD(at[10], at[47]);    MULADD(at[11], at[46]);    MULADD(at[12], at[45]);    MULADD(at[13], at[44]);    MULADD(at[14], at[43]);    MULADD(at[15], at[42]);    MULADD(at[16], at[41]);    MULADD(at[17], at[40]);    MULADD(at[18], at[39]);    MULADD(at[19], at[38]);    MULADD(at[20], at[37]);    MULADD(at[21], at[36]);    MULADD(at[22], at[35]);    MULADD(at[23], at[34]);    MULADD(at[24], at[33]);    MULADD(at[25], at[32]);    MULADD(at[26], at[31]);    MULADD(at[27], at[30]);
+   COMBA_STORE(C->dp[29]);
+   /* 30 */
+   COMBA_FORWARD;
+   MULADD(at[3], at[55]);    MULADD(at[4], at[54]);    MULADD(at[5], at[53]);    MULADD(at[6], at[52]);    MULADD(at[7], at[51]);    MULADD(at[8], at[50]);    MULADD(at[9], at[49]);    MULADD(at[10], at[48]);    MULADD(at[11], at[47]);    MULADD(at[12], at[46]);    MULADD(at[13], at[45]);    MULADD(at[14], at[44]);    MULADD(at[15], at[43]);    MULADD(at[16], at[42]);    MULADD(at[17], at[41]);    MULADD(at[18], at[40]);    MULADD(at[19], at[39]);    MULADD(at[20], at[38]);    MULADD(at[21], at[37]);    MULADD(at[22], at[36]);    MULADD(at[23], at[35]);    MULADD(at[24], at[34]);    MULADD(at[25], at[33]);    MULADD(at[26], at[32]);    MULADD(at[27], at[31]);
+   COMBA_STORE(C->dp[30]);
+   /* 31 */
+   COMBA_FORWARD;
+   MULADD(at[4], at[55]);    MULADD(at[5], at[54]);    MULADD(at[6], at[53]);    MULADD(at[7], at[52]);    MULADD(at[8], at[51]);    MULADD(at[9], at[50]);    MULADD(at[10], at[49]);    MULADD(at[11], at[48]);    MULADD(at[12], at[47]);    MULADD(at[13], at[46]);    MULADD(at[14], at[45]);    MULADD(at[15], at[44]);    MULADD(at[16], at[43]);    MULADD(at[17], at[42]);    MULADD(at[18], at[41]);    MULADD(at[19], at[40]);    MULADD(at[20], at[39]);    MULADD(at[21], at[38]);    MULADD(at[22], at[37]);    MULADD(at[23], at[36]);    MULADD(at[24], at[35]);    MULADD(at[25], at[34]);    MULADD(at[26], at[33]);    MULADD(at[27], at[32]);
+   COMBA_STORE(C->dp[31]);
+   /* 32 */
+   COMBA_FORWARD;
+   MULADD(at[5], at[55]);    MULADD(at[6], at[54]);    MULADD(at[7], at[53]);    MULADD(at[8], at[52]);    MULADD(at[9], at[51]);    MULADD(at[10], at[50]);    MULADD(at[11], at[49]);    MULADD(at[12], at[48]);    MULADD(at[13], at[47]);    MULADD(at[14], at[46]);    MULADD(at[15], at[45]);    MULADD(at[16], at[44]);    MULADD(at[17], at[43]);    MULADD(at[18], at[42]);    MULADD(at[19], at[41]);    MULADD(at[20], at[40]);    MULADD(at[21], at[39]);    MULADD(at[22], at[38]);    MULADD(at[23], at[37]);    MULADD(at[24], at[36]);    MULADD(at[25], at[35]);    MULADD(at[26], at[34]);    MULADD(at[27], at[33]);
+   COMBA_STORE(C->dp[32]);
+   /* 33 */
+   COMBA_FORWARD;
+   MULADD(at[6], at[55]);    MULADD(at[7], at[54]);    MULADD(at[8], at[53]);    MULADD(at[9], at[52]);    MULADD(at[10], at[51]);    MULADD(at[11], at[50]);    MULADD(at[12], at[49]);    MULADD(at[13], at[48]);    MULADD(at[14], at[47]);    MULADD(at[15], at[46]);    MULADD(at[16], at[45]);    MULADD(at[17], at[44]);    MULADD(at[18], at[43]);    MULADD(at[19], at[42]);    MULADD(at[20], at[41]);    MULADD(at[21], at[40]);    MULADD(at[22], at[39]);    MULADD(at[23], at[38]);    MULADD(at[24], at[37]);    MULADD(at[25], at[36]);    MULADD(at[26], at[35]);    MULADD(at[27], at[34]);
+   COMBA_STORE(C->dp[33]);
+   /* 34 */
+   COMBA_FORWARD;
+   MULADD(at[7], at[55]);    MULADD(at[8], at[54]);    MULADD(at[9], at[53]);    MULADD(at[10], at[52]);    MULADD(at[11], at[51]);    MULADD(at[12], at[50]);    MULADD(at[13], at[49]);    MULADD(at[14], at[48]);    MULADD(at[15], at[47]);    MULADD(at[16], at[46]);    MULADD(at[17], at[45]);    MULADD(at[18], at[44]);    MULADD(at[19], at[43]);    MULADD(at[20], at[42]);    MULADD(at[21], at[41]);    MULADD(at[22], at[40]);    MULADD(at[23], at[39]);    MULADD(at[24], at[38]);    MULADD(at[25], at[37]);    MULADD(at[26], at[36]);    MULADD(at[27], at[35]);
+   COMBA_STORE(C->dp[34]);
+   /* 35 */
+   COMBA_FORWARD;
+   MULADD(at[8], at[55]);    MULADD(at[9], at[54]);    MULADD(at[10], at[53]);    MULADD(at[11], at[52]);    MULADD(at[12], at[51]);    MULADD(at[13], at[50]);    MULADD(at[14], at[49]);    MULADD(at[15], at[48]);    MULADD(at[16], at[47]);    MULADD(at[17], at[46]);    MULADD(at[18], at[45]);    MULADD(at[19], at[44]);    MULADD(at[20], at[43]);    MULADD(at[21], at[42]);    MULADD(at[22], at[41]);    MULADD(at[23], at[40]);    MULADD(at[24], at[39]);    MULADD(at[25], at[38]);    MULADD(at[26], at[37]);    MULADD(at[27], at[36]);
+   COMBA_STORE(C->dp[35]);
+   /* 36 */
+   COMBA_FORWARD;
+   MULADD(at[9], at[55]);    MULADD(at[10], at[54]);    MULADD(at[11], at[53]);    MULADD(at[12], at[52]);    MULADD(at[13], at[51]);    MULADD(at[14], at[50]);    MULADD(at[15], at[49]);    MULADD(at[16], at[48]);    MULADD(at[17], at[47]);    MULADD(at[18], at[46]);    MULADD(at[19], at[45]);    MULADD(at[20], at[44]);    MULADD(at[21], at[43]);    MULADD(at[22], at[42]);    MULADD(at[23], at[41]);    MULADD(at[24], at[40]);    MULADD(at[25], at[39]);    MULADD(at[26], at[38]);    MULADD(at[27], at[37]);
+   COMBA_STORE(C->dp[36]);
+   /* 37 */
+   COMBA_FORWARD;
+   MULADD(at[10], at[55]);    MULADD(at[11], at[54]);    MULADD(at[12], at[53]);    MULADD(at[13], at[52]);    MULADD(at[14], at[51]);    MULADD(at[15], at[50]);    MULADD(at[16], at[49]);    MULADD(at[17], at[48]);    MULADD(at[18], at[47]);    MULADD(at[19], at[46]);    MULADD(at[20], at[45]);    MULADD(at[21], at[44]);    MULADD(at[22], at[43]);    MULADD(at[23], at[42]);    MULADD(at[24], at[41]);    MULADD(at[25], at[40]);    MULADD(at[26], at[39]);    MULADD(at[27], at[38]);
+   COMBA_STORE(C->dp[37]);
+   /* 38 */
+   COMBA_FORWARD;
+   MULADD(at[11], at[55]);    MULADD(at[12], at[54]);    MULADD(at[13], at[53]);    MULADD(at[14], at[52]);    MULADD(at[15], at[51]);    MULADD(at[16], at[50]);    MULADD(at[17], at[49]);    MULADD(at[18], at[48]);    MULADD(at[19], at[47]);    MULADD(at[20], at[46]);    MULADD(at[21], at[45]);    MULADD(at[22], at[44]);    MULADD(at[23], at[43]);    MULADD(at[24], at[42]);    MULADD(at[25], at[41]);    MULADD(at[26], at[40]);    MULADD(at[27], at[39]);
+   COMBA_STORE(C->dp[38]);
+   /* 39 */
+   COMBA_FORWARD;
+   MULADD(at[12], at[55]);    MULADD(at[13], at[54]);    MULADD(at[14], at[53]);    MULADD(at[15], at[52]);    MULADD(at[16], at[51]);    MULADD(at[17], at[50]);    MULADD(at[18], at[49]);    MULADD(at[19], at[48]);    MULADD(at[20], at[47]);    MULADD(at[21], at[46]);    MULADD(at[22], at[45]);    MULADD(at[23], at[44]);    MULADD(at[24], at[43]);    MULADD(at[25], at[42]);    MULADD(at[26], at[41]);    MULADD(at[27], at[40]);
+   COMBA_STORE(C->dp[39]);
+   /* 40 */
+   COMBA_FORWARD;
+   MULADD(at[13], at[55]);    MULADD(at[14], at[54]);    MULADD(at[15], at[53]);    MULADD(at[16], at[52]);    MULADD(at[17], at[51]);    MULADD(at[18], at[50]);    MULADD(at[19], at[49]);    MULADD(at[20], at[48]);    MULADD(at[21], at[47]);    MULADD(at[22], at[46]);    MULADD(at[23], at[45]);    MULADD(at[24], at[44]);    MULADD(at[25], at[43]);    MULADD(at[26], at[42]);    MULADD(at[27], at[41]);
+   COMBA_STORE(C->dp[40]);
+   /* 41 */
+   COMBA_FORWARD;
+   MULADD(at[14], at[55]);    MULADD(at[15], at[54]);    MULADD(at[16], at[53]);    MULADD(at[17], at[52]);    MULADD(at[18], at[51]);    MULADD(at[19], at[50]);    MULADD(at[20], at[49]);    MULADD(at[21], at[48]);    MULADD(at[22], at[47]);    MULADD(at[23], at[46]);    MULADD(at[24], at[45]);    MULADD(at[25], at[44]);    MULADD(at[26], at[43]);    MULADD(at[27], at[42]);
+   COMBA_STORE(C->dp[41]);
+   /* 42 */
+   COMBA_FORWARD;
+   MULADD(at[15], at[55]);    MULADD(at[16], at[54]);    MULADD(at[17], at[53]);    MULADD(at[18], at[52]);    MULADD(at[19], at[51]);    MULADD(at[20], at[50]);    MULADD(at[21], at[49]);    MULADD(at[22], at[48]);    MULADD(at[23], at[47]);    MULADD(at[24], at[46]);    MULADD(at[25], at[45]);    MULADD(at[26], at[44]);    MULADD(at[27], at[43]);
+   COMBA_STORE(C->dp[42]);
+   /* 43 */
+   COMBA_FORWARD;
+   MULADD(at[16], at[55]);    MULADD(at[17], at[54]);    MULADD(at[18], at[53]);    MULADD(at[19], at[52]);    MULADD(at[20], at[51]);    MULADD(at[21], at[50]);    MULADD(at[22], at[49]);    MULADD(at[23], at[48]);    MULADD(at[24], at[47]);    MULADD(at[25], at[46]);    MULADD(at[26], at[45]);    MULADD(at[27], at[44]);
+   COMBA_STORE(C->dp[43]);
+   /* 44 */
+   COMBA_FORWARD;
+   MULADD(at[17], at[55]);    MULADD(at[18], at[54]);    MULADD(at[19], at[53]);    MULADD(at[20], at[52]);    MULADD(at[21], at[51]);    MULADD(at[22], at[50]);    MULADD(at[23], at[49]);    MULADD(at[24], at[48]);    MULADD(at[25], at[47]);    MULADD(at[26], at[46]);    MULADD(at[27], at[45]);
+   COMBA_STORE(C->dp[44]);
+   /* 45 */
+   COMBA_FORWARD;
+   MULADD(at[18], at[55]);    MULADD(at[19], at[54]);    MULADD(at[20], at[53]);    MULADD(at[21], at[52]);    MULADD(at[22], at[51]);    MULADD(at[23], at[50]);    MULADD(at[24], at[49]);    MULADD(at[25], at[48]);    MULADD(at[26], at[47]);    MULADD(at[27], at[46]);
+   COMBA_STORE(C->dp[45]);
+   /* 46 */
+   COMBA_FORWARD;
+   MULADD(at[19], at[55]);    MULADD(at[20], at[54]);    MULADD(at[21], at[53]);    MULADD(at[22], at[52]);    MULADD(at[23], at[51]);    MULADD(at[24], at[50]);    MULADD(at[25], at[49]);    MULADD(at[26], at[48]);    MULADD(at[27], at[47]);
+   COMBA_STORE(C->dp[46]);
+   /* 47 */
+   COMBA_FORWARD;
+   MULADD(at[20], at[55]);    MULADD(at[21], at[54]);    MULADD(at[22], at[53]);    MULADD(at[23], at[52]);    MULADD(at[24], at[51]);    MULADD(at[25], at[50]);    MULADD(at[26], at[49]);    MULADD(at[27], at[48]);
+   COMBA_STORE(C->dp[47]);
+   /* 48 */
+   COMBA_FORWARD;
+   MULADD(at[21], at[55]);    MULADD(at[22], at[54]);    MULADD(at[23], at[53]);    MULADD(at[24], at[52]);    MULADD(at[25], at[51]);    MULADD(at[26], at[50]);    MULADD(at[27], at[49]);
+   COMBA_STORE(C->dp[48]);
+   /* 49 */
+   COMBA_FORWARD;
+   MULADD(at[22], at[55]);    MULADD(at[23], at[54]);    MULADD(at[24], at[53]);    MULADD(at[25], at[52]);    MULADD(at[26], at[51]);    MULADD(at[27], at[50]);
+   COMBA_STORE(C->dp[49]);
+   /* 50 */
+   COMBA_FORWARD;
+   MULADD(at[23], at[55]);    MULADD(at[24], at[54]);    MULADD(at[25], at[53]);    MULADD(at[26], at[52]);    MULADD(at[27], at[51]);
+   COMBA_STORE(C->dp[50]);
+   /* 51 */
+   COMBA_FORWARD;
+   MULADD(at[24], at[55]);    MULADD(at[25], at[54]);    MULADD(at[26], at[53]);    MULADD(at[27], at[52]);
+   COMBA_STORE(C->dp[51]);
+   /* 52 */
+   COMBA_FORWARD;
+   MULADD(at[25], at[55]);    MULADD(at[26], at[54]);    MULADD(at[27], at[53]);
+   COMBA_STORE(C->dp[52]);
+   /* 53 */
+   COMBA_FORWARD;
+   MULADD(at[26], at[55]);    MULADD(at[27], at[54]);
+   COMBA_STORE(C->dp[53]);
+   /* 54 */
+   COMBA_FORWARD;
+   MULADD(at[27], at[55]);
+   COMBA_STORE(C->dp[54]);
+   COMBA_STORE2(C->dp[55]);
+   C->used = 56;
+   C->sign = A->sign ^ B->sign;
+   fp_clamp(C);
+   COMBA_FINI;
+}
+#endif
+
+
+/* $Source$ */
+/* $Revision$ */
+/* $Date$ */
diff --git a/tomsfastmath/src/mul/fp_mul_comba_3.c b/tomsfastmath/src/mul/fp_mul_comba_3.c
new file mode 100644 (file)
index 0000000..0e0cea1
--- /dev/null
@@ -0,0 +1,44 @@
+#define TFM_DEFINES
+#include "fp_mul_comba.c"
+
+#if defined(TFM_MUL3) && FP_SIZE >= 6
+void fp_mul_comba3(fp_int *A, fp_int *B, fp_int *C)
+{
+   fp_digit c0, c1, c2, at[6];
+
+   memcpy(at, A->dp, 3 * sizeof(fp_digit));
+   memcpy(at+3, B->dp, 3 * sizeof(fp_digit));
+   COMBA_START;
+
+   COMBA_CLEAR;
+   /* 0 */
+   MULADD(at[0], at[3]);
+   COMBA_STORE(C->dp[0]);
+   /* 1 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[4]);    MULADD(at[1], at[3]);
+   COMBA_STORE(C->dp[1]);
+   /* 2 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[5]);    MULADD(at[1], at[4]);    MULADD(at[2], at[3]);
+   COMBA_STORE(C->dp[2]);
+   /* 3 */
+   COMBA_FORWARD;
+   MULADD(at[1], at[5]);    MULADD(at[2], at[4]);
+   COMBA_STORE(C->dp[3]);
+   /* 4 */
+   COMBA_FORWARD;
+   MULADD(at[2], at[5]);
+   COMBA_STORE(C->dp[4]);
+   COMBA_STORE2(C->dp[5]);
+   C->used = 6;
+   C->sign = A->sign ^ B->sign;
+   fp_clamp(C);
+   COMBA_FINI;
+}
+#endif
+
+
+/* $Source$ */
+/* $Revision$ */
+/* $Date$ */
diff --git a/tomsfastmath/src/mul/fp_mul_comba_32.c b/tomsfastmath/src/mul/fp_mul_comba_32.c
new file mode 100644 (file)
index 0000000..f8c304e
--- /dev/null
@@ -0,0 +1,290 @@
+#define TFM_DEFINES
+#include "fp_mul_comba.c"
+
+#if defined(TFM_MUL32) && FP_SIZE >= 64
+void fp_mul_comba32(fp_int *A, fp_int *B, fp_int *C)
+{
+   fp_digit c0, c1, c2, at[64];
+   int out_size;
+
+   out_size = A->used + B->used;
+   memcpy(at, A->dp, 32 * sizeof(fp_digit));
+   memcpy(at+32, B->dp, 32 * sizeof(fp_digit));
+   COMBA_START;
+
+   COMBA_CLEAR;
+   /* 0 */
+   MULADD(at[0], at[32]);
+   COMBA_STORE(C->dp[0]);
+   /* 1 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[33]);    MULADD(at[1], at[32]);
+   COMBA_STORE(C->dp[1]);
+   /* 2 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[34]);    MULADD(at[1], at[33]);    MULADD(at[2], at[32]);
+   COMBA_STORE(C->dp[2]);
+   /* 3 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[35]);    MULADD(at[1], at[34]);    MULADD(at[2], at[33]);    MULADD(at[3], at[32]);
+   COMBA_STORE(C->dp[3]);
+   /* 4 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[36]);    MULADD(at[1], at[35]);    MULADD(at[2], at[34]);    MULADD(at[3], at[33]);    MULADD(at[4], at[32]);
+   COMBA_STORE(C->dp[4]);
+   /* 5 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[37]);    MULADD(at[1], at[36]);    MULADD(at[2], at[35]);    MULADD(at[3], at[34]);    MULADD(at[4], at[33]);    MULADD(at[5], at[32]);
+   COMBA_STORE(C->dp[5]);
+   /* 6 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[38]);    MULADD(at[1], at[37]);    MULADD(at[2], at[36]);    MULADD(at[3], at[35]);    MULADD(at[4], at[34]);    MULADD(at[5], at[33]);    MULADD(at[6], at[32]);
+   COMBA_STORE(C->dp[6]);
+   /* 7 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[39]);    MULADD(at[1], at[38]);    MULADD(at[2], at[37]);    MULADD(at[3], at[36]);    MULADD(at[4], at[35]);    MULADD(at[5], at[34]);    MULADD(at[6], at[33]);    MULADD(at[7], at[32]);
+   COMBA_STORE(C->dp[7]);
+   /* 8 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[40]);    MULADD(at[1], at[39]);    MULADD(at[2], at[38]);    MULADD(at[3], at[37]);    MULADD(at[4], at[36]);    MULADD(at[5], at[35]);    MULADD(at[6], at[34]);    MULADD(at[7], at[33]);    MULADD(at[8], at[32]);
+   COMBA_STORE(C->dp[8]);
+   /* 9 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[41]);    MULADD(at[1], at[40]);    MULADD(at[2], at[39]);    MULADD(at[3], at[38]);    MULADD(at[4], at[37]);    MULADD(at[5], at[36]);    MULADD(at[6], at[35]);    MULADD(at[7], at[34]);    MULADD(at[8], at[33]);    MULADD(at[9], at[32]);
+   COMBA_STORE(C->dp[9]);
+   /* 10 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[42]);    MULADD(at[1], at[41]);    MULADD(at[2], at[40]);    MULADD(at[3], at[39]);    MULADD(at[4], at[38]);    MULADD(at[5], at[37]);    MULADD(at[6], at[36]);    MULADD(at[7], at[35]);    MULADD(at[8], at[34]);    MULADD(at[9], at[33]);    MULADD(at[10], at[32]);
+   COMBA_STORE(C->dp[10]);
+   /* 11 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[43]);    MULADD(at[1], at[42]);    MULADD(at[2], at[41]);    MULADD(at[3], at[40]);    MULADD(at[4], at[39]);    MULADD(at[5], at[38]);    MULADD(at[6], at[37]);    MULADD(at[7], at[36]);    MULADD(at[8], at[35]);    MULADD(at[9], at[34]);    MULADD(at[10], at[33]);    MULADD(at[11], at[32]);
+   COMBA_STORE(C->dp[11]);
+   /* 12 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[44]);    MULADD(at[1], at[43]);    MULADD(at[2], at[42]);    MULADD(at[3], at[41]);    MULADD(at[4], at[40]);    MULADD(at[5], at[39]);    MULADD(at[6], at[38]);    MULADD(at[7], at[37]);    MULADD(at[8], at[36]);    MULADD(at[9], at[35]);    MULADD(at[10], at[34]);    MULADD(at[11], at[33]);    MULADD(at[12], at[32]);
+   COMBA_STORE(C->dp[12]);
+   /* 13 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[45]);    MULADD(at[1], at[44]);    MULADD(at[2], at[43]);    MULADD(at[3], at[42]);    MULADD(at[4], at[41]);    MULADD(at[5], at[40]);    MULADD(at[6], at[39]);    MULADD(at[7], at[38]);    MULADD(at[8], at[37]);    MULADD(at[9], at[36]);    MULADD(at[10], at[35]);    MULADD(at[11], at[34]);    MULADD(at[12], at[33]);    MULADD(at[13], at[32]);
+   COMBA_STORE(C->dp[13]);
+   /* 14 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[46]);    MULADD(at[1], at[45]);    MULADD(at[2], at[44]);    MULADD(at[3], at[43]);    MULADD(at[4], at[42]);    MULADD(at[5], at[41]);    MULADD(at[6], at[40]);    MULADD(at[7], at[39]);    MULADD(at[8], at[38]);    MULADD(at[9], at[37]);    MULADD(at[10], at[36]);    MULADD(at[11], at[35]);    MULADD(at[12], at[34]);    MULADD(at[13], at[33]);    MULADD(at[14], at[32]);
+   COMBA_STORE(C->dp[14]);
+   /* 15 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[47]);    MULADD(at[1], at[46]);    MULADD(at[2], at[45]);    MULADD(at[3], at[44]);    MULADD(at[4], at[43]);    MULADD(at[5], at[42]);    MULADD(at[6], at[41]);    MULADD(at[7], at[40]);    MULADD(at[8], at[39]);    MULADD(at[9], at[38]);    MULADD(at[10], at[37]);    MULADD(at[11], at[36]);    MULADD(at[12], at[35]);    MULADD(at[13], at[34]);    MULADD(at[14], at[33]);    MULADD(at[15], at[32]);
+   COMBA_STORE(C->dp[15]);
+   /* 16 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[48]);    MULADD(at[1], at[47]);    MULADD(at[2], at[46]);    MULADD(at[3], at[45]);    MULADD(at[4], at[44]);    MULADD(at[5], at[43]);    MULADD(at[6], at[42]);    MULADD(at[7], at[41]);    MULADD(at[8], at[40]);    MULADD(at[9], at[39]);    MULADD(at[10], at[38]);    MULADD(at[11], at[37]);    MULADD(at[12], at[36]);    MULADD(at[13], at[35]);    MULADD(at[14], at[34]);    MULADD(at[15], at[33]);    MULADD(at[16], at[32]);
+   COMBA_STORE(C->dp[16]);
+   /* 17 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[49]);    MULADD(at[1], at[48]);    MULADD(at[2], at[47]);    MULADD(at[3], at[46]);    MULADD(at[4], at[45]);    MULADD(at[5], at[44]);    MULADD(at[6], at[43]);    MULADD(at[7], at[42]);    MULADD(at[8], at[41]);    MULADD(at[9], at[40]);    MULADD(at[10], at[39]);    MULADD(at[11], at[38]);    MULADD(at[12], at[37]);    MULADD(at[13], at[36]);    MULADD(at[14], at[35]);    MULADD(at[15], at[34]);    MULADD(at[16], at[33]);    MULADD(at[17], at[32]);
+   COMBA_STORE(C->dp[17]);
+   /* 18 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[50]);    MULADD(at[1], at[49]);    MULADD(at[2], at[48]);    MULADD(at[3], at[47]);    MULADD(at[4], at[46]);    MULADD(at[5], at[45]);    MULADD(at[6], at[44]);    MULADD(at[7], at[43]);    MULADD(at[8], at[42]);    MULADD(at[9], at[41]);    MULADD(at[10], at[40]);    MULADD(at[11], at[39]);    MULADD(at[12], at[38]);    MULADD(at[13], at[37]);    MULADD(at[14], at[36]);    MULADD(at[15], at[35]);    MULADD(at[16], at[34]);    MULADD(at[17], at[33]);    MULADD(at[18], at[32]);
+   COMBA_STORE(C->dp[18]);
+   /* 19 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[51]);    MULADD(at[1], at[50]);    MULADD(at[2], at[49]);    MULADD(at[3], at[48]);    MULADD(at[4], at[47]);    MULADD(at[5], at[46]);    MULADD(at[6], at[45]);    MULADD(at[7], at[44]);    MULADD(at[8], at[43]);    MULADD(at[9], at[42]);    MULADD(at[10], at[41]);    MULADD(at[11], at[40]);    MULADD(at[12], at[39]);    MULADD(at[13], at[38]);    MULADD(at[14], at[37]);    MULADD(at[15], at[36]);    MULADD(at[16], at[35]);    MULADD(at[17], at[34]);    MULADD(at[18], at[33]);    MULADD(at[19], at[32]);
+   COMBA_STORE(C->dp[19]);
+   /* 20 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[52]);    MULADD(at[1], at[51]);    MULADD(at[2], at[50]);    MULADD(at[3], at[49]);    MULADD(at[4], at[48]);    MULADD(at[5], at[47]);    MULADD(at[6], at[46]);    MULADD(at[7], at[45]);    MULADD(at[8], at[44]);    MULADD(at[9], at[43]);    MULADD(at[10], at[42]);    MULADD(at[11], at[41]);    MULADD(at[12], at[40]);    MULADD(at[13], at[39]);    MULADD(at[14], at[38]);    MULADD(at[15], at[37]);    MULADD(at[16], at[36]);    MULADD(at[17], at[35]);    MULADD(at[18], at[34]);    MULADD(at[19], at[33]);    MULADD(at[20], at[32]);
+   COMBA_STORE(C->dp[20]);
+   /* 21 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[53]);    MULADD(at[1], at[52]);    MULADD(at[2], at[51]);    MULADD(at[3], at[50]);    MULADD(at[4], at[49]);    MULADD(at[5], at[48]);    MULADD(at[6], at[47]);    MULADD(at[7], at[46]);    MULADD(at[8], at[45]);    MULADD(at[9], at[44]);    MULADD(at[10], at[43]);    MULADD(at[11], at[42]);    MULADD(at[12], at[41]);    MULADD(at[13], at[40]);    MULADD(at[14], at[39]);    MULADD(at[15], at[38]);    MULADD(at[16], at[37]);    MULADD(at[17], at[36]);    MULADD(at[18], at[35]);    MULADD(at[19], at[34]);    MULADD(at[20], at[33]);    MULADD(at[21], at[32]);
+   COMBA_STORE(C->dp[21]);
+   /* 22 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[54]);    MULADD(at[1], at[53]);    MULADD(at[2], at[52]);    MULADD(at[3], at[51]);    MULADD(at[4], at[50]);    MULADD(at[5], at[49]);    MULADD(at[6], at[48]);    MULADD(at[7], at[47]);    MULADD(at[8], at[46]);    MULADD(at[9], at[45]);    MULADD(at[10], at[44]);    MULADD(at[11], at[43]);    MULADD(at[12], at[42]);    MULADD(at[13], at[41]);    MULADD(at[14], at[40]);    MULADD(at[15], at[39]);    MULADD(at[16], at[38]);    MULADD(at[17], at[37]);    MULADD(at[18], at[36]);    MULADD(at[19], at[35]);    MULADD(at[20], at[34]);    MULADD(at[21], at[33]);    MULADD(at[22], at[32]);
+   COMBA_STORE(C->dp[22]);
+   /* 23 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[55]);    MULADD(at[1], at[54]);    MULADD(at[2], at[53]);    MULADD(at[3], at[52]);    MULADD(at[4], at[51]);    MULADD(at[5], at[50]);    MULADD(at[6], at[49]);    MULADD(at[7], at[48]);    MULADD(at[8], at[47]);    MULADD(at[9], at[46]);    MULADD(at[10], at[45]);    MULADD(at[11], at[44]);    MULADD(at[12], at[43]);    MULADD(at[13], at[42]);    MULADD(at[14], at[41]);    MULADD(at[15], at[40]);    MULADD(at[16], at[39]);    MULADD(at[17], at[38]);    MULADD(at[18], at[37]);    MULADD(at[19], at[36]);    MULADD(at[20], at[35]);    MULADD(at[21], at[34]);    MULADD(at[22], at[33]);    MULADD(at[23], at[32]);
+   COMBA_STORE(C->dp[23]);
+   /* 24 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[56]);    MULADD(at[1], at[55]);    MULADD(at[2], at[54]);    MULADD(at[3], at[53]);    MULADD(at[4], at[52]);    MULADD(at[5], at[51]);    MULADD(at[6], at[50]);    MULADD(at[7], at[49]);    MULADD(at[8], at[48]);    MULADD(at[9], at[47]);    MULADD(at[10], at[46]);    MULADD(at[11], at[45]);    MULADD(at[12], at[44]);    MULADD(at[13], at[43]);    MULADD(at[14], at[42]);    MULADD(at[15], at[41]);    MULADD(at[16], at[40]);    MULADD(at[17], at[39]);    MULADD(at[18], at[38]);    MULADD(at[19], at[37]);    MULADD(at[20], at[36]);    MULADD(at[21], at[35]);    MULADD(at[22], at[34]);    MULADD(at[23], at[33]);    MULADD(at[24], at[32]);
+   COMBA_STORE(C->dp[24]);
+   /* 25 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[57]);    MULADD(at[1], at[56]);    MULADD(at[2], at[55]);    MULADD(at[3], at[54]);    MULADD(at[4], at[53]);    MULADD(at[5], at[52]);    MULADD(at[6], at[51]);    MULADD(at[7], at[50]);    MULADD(at[8], at[49]);    MULADD(at[9], at[48]);    MULADD(at[10], at[47]);    MULADD(at[11], at[46]);    MULADD(at[12], at[45]);    MULADD(at[13], at[44]);    MULADD(at[14], at[43]);    MULADD(at[15], at[42]);    MULADD(at[16], at[41]);    MULADD(at[17], at[40]);    MULADD(at[18], at[39]);    MULADD(at[19], at[38]);    MULADD(at[20], at[37]);    MULADD(at[21], at[36]);    MULADD(at[22], at[35]);    MULADD(at[23], at[34]);    MULADD(at[24], at[33]);    MULADD(at[25], at[32]);
+   COMBA_STORE(C->dp[25]);
+   /* 26 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[58]);    MULADD(at[1], at[57]);    MULADD(at[2], at[56]);    MULADD(at[3], at[55]);    MULADD(at[4], at[54]);    MULADD(at[5], at[53]);    MULADD(at[6], at[52]);    MULADD(at[7], at[51]);    MULADD(at[8], at[50]);    MULADD(at[9], at[49]);    MULADD(at[10], at[48]);    MULADD(at[11], at[47]);    MULADD(at[12], at[46]);    MULADD(at[13], at[45]);    MULADD(at[14], at[44]);    MULADD(at[15], at[43]);    MULADD(at[16], at[42]);    MULADD(at[17], at[41]);    MULADD(at[18], at[40]);    MULADD(at[19], at[39]);    MULADD(at[20], at[38]);    MULADD(at[21], at[37]);    MULADD(at[22], at[36]);    MULADD(at[23], at[35]);    MULADD(at[24], at[34]);    MULADD(at[25], at[33]);    MULADD(at[26], at[32]);
+   COMBA_STORE(C->dp[26]);
+   /* 27 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[59]);    MULADD(at[1], at[58]);    MULADD(at[2], at[57]);    MULADD(at[3], at[56]);    MULADD(at[4], at[55]);    MULADD(at[5], at[54]);    MULADD(at[6], at[53]);    MULADD(at[7], at[52]);    MULADD(at[8], at[51]);    MULADD(at[9], at[50]);    MULADD(at[10], at[49]);    MULADD(at[11], at[48]);    MULADD(at[12], at[47]);    MULADD(at[13], at[46]);    MULADD(at[14], at[45]);    MULADD(at[15], at[44]);    MULADD(at[16], at[43]);    MULADD(at[17], at[42]);    MULADD(at[18], at[41]);    MULADD(at[19], at[40]);    MULADD(at[20], at[39]);    MULADD(at[21], at[38]);    MULADD(at[22], at[37]);    MULADD(at[23], at[36]);    MULADD(at[24], at[35]);    MULADD(at[25], at[34]);    MULADD(at[26], at[33]);    MULADD(at[27], at[32]);
+   COMBA_STORE(C->dp[27]);
+   /* 28 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[60]);    MULADD(at[1], at[59]);    MULADD(at[2], at[58]);    MULADD(at[3], at[57]);    MULADD(at[4], at[56]);    MULADD(at[5], at[55]);    MULADD(at[6], at[54]);    MULADD(at[7], at[53]);    MULADD(at[8], at[52]);    MULADD(at[9], at[51]);    MULADD(at[10], at[50]);    MULADD(at[11], at[49]);    MULADD(at[12], at[48]);    MULADD(at[13], at[47]);    MULADD(at[14], at[46]);    MULADD(at[15], at[45]);    MULADD(at[16], at[44]);    MULADD(at[17], at[43]);    MULADD(at[18], at[42]);    MULADD(at[19], at[41]);    MULADD(at[20], at[40]);    MULADD(at[21], at[39]);    MULADD(at[22], at[38]);    MULADD(at[23], at[37]);    MULADD(at[24], at[36]);    MULADD(at[25], at[35]);    MULADD(at[26], at[34]);    MULADD(at[27], at[33]);    MULADD(at[28], at[32]);
+   COMBA_STORE(C->dp[28]);
+   /* 29 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[61]);    MULADD(at[1], at[60]);    MULADD(at[2], at[59]);    MULADD(at[3], at[58]);    MULADD(at[4], at[57]);    MULADD(at[5], at[56]);    MULADD(at[6], at[55]);    MULADD(at[7], at[54]);    MULADD(at[8], at[53]);    MULADD(at[9], at[52]);    MULADD(at[10], at[51]);    MULADD(at[11], at[50]);    MULADD(at[12], at[49]);    MULADD(at[13], at[48]);    MULADD(at[14], at[47]);    MULADD(at[15], at[46]);    MULADD(at[16], at[45]);    MULADD(at[17], at[44]);    MULADD(at[18], at[43]);    MULADD(at[19], at[42]);    MULADD(at[20], at[41]);    MULADD(at[21], at[40]);    MULADD(at[22], at[39]);    MULADD(at[23], at[38]);    MULADD(at[24], at[37]);    MULADD(at[25], at[36]);    MULADD(at[26], at[35]);    MULADD(at[27], at[34]);    MULADD(at[28], at[33]);    MULADD(at[29], at[32]);
+   COMBA_STORE(C->dp[29]);
+   /* 30 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[62]);    MULADD(at[1], at[61]);    MULADD(at[2], at[60]);    MULADD(at[3], at[59]);    MULADD(at[4], at[58]);    MULADD(at[5], at[57]);    MULADD(at[6], at[56]);    MULADD(at[7], at[55]);    MULADD(at[8], at[54]);    MULADD(at[9], at[53]);    MULADD(at[10], at[52]);    MULADD(at[11], at[51]);    MULADD(at[12], at[50]);    MULADD(at[13], at[49]);    MULADD(at[14], at[48]);    MULADD(at[15], at[47]);    MULADD(at[16], at[46]);    MULADD(at[17], at[45]);    MULADD(at[18], at[44]);    MULADD(at[19], at[43]);    MULADD(at[20], at[42]);    MULADD(at[21], at[41]);    MULADD(at[22], at[40]);    MULADD(at[23], at[39]);    MULADD(at[24], at[38]);    MULADD(at[25], at[37]);    MULADD(at[26], at[36]);    MULADD(at[27], at[35]);    MULADD(at[28], at[34]);    MULADD(at[29], at[33]);    MULADD(at[30], at[32]);
+   COMBA_STORE(C->dp[30]);
+   /* 31 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[63]);    MULADD(at[1], at[62]);    MULADD(at[2], at[61]);    MULADD(at[3], at[60]);    MULADD(at[4], at[59]);    MULADD(at[5], at[58]);    MULADD(at[6], at[57]);    MULADD(at[7], at[56]);    MULADD(at[8], at[55]);    MULADD(at[9], at[54]);    MULADD(at[10], at[53]);    MULADD(at[11], at[52]);    MULADD(at[12], at[51]);    MULADD(at[13], at[50]);    MULADD(at[14], at[49]);    MULADD(at[15], at[48]);    MULADD(at[16], at[47]);    MULADD(at[17], at[46]);    MULADD(at[18], at[45]);    MULADD(at[19], at[44]);    MULADD(at[20], at[43]);    MULADD(at[21], at[42]);    MULADD(at[22], at[41]);    MULADD(at[23], at[40]);    MULADD(at[24], at[39]);    MULADD(at[25], at[38]);    MULADD(at[26], at[37]);    MULADD(at[27], at[36]);    MULADD(at[28], at[35]);    MULADD(at[29], at[34]);    MULADD(at[30], at[33]);    MULADD(at[31], at[32]);
+   COMBA_STORE(C->dp[31]);
+   /* 32 */
+   COMBA_FORWARD;
+   MULADD(at[1], at[63]);    MULADD(at[2], at[62]);    MULADD(at[3], at[61]);    MULADD(at[4], at[60]);    MULADD(at[5], at[59]);    MULADD(at[6], at[58]);    MULADD(at[7], at[57]);    MULADD(at[8], at[56]);    MULADD(at[9], at[55]);    MULADD(at[10], at[54]);    MULADD(at[11], at[53]);    MULADD(at[12], at[52]);    MULADD(at[13], at[51]);    MULADD(at[14], at[50]);    MULADD(at[15], at[49]);    MULADD(at[16], at[48]);    MULADD(at[17], at[47]);    MULADD(at[18], at[46]);    MULADD(at[19], at[45]);    MULADD(at[20], at[44]);    MULADD(at[21], at[43]);    MULADD(at[22], at[42]);    MULADD(at[23], at[41]);    MULADD(at[24], at[40]);    MULADD(at[25], at[39]);    MULADD(at[26], at[38]);    MULADD(at[27], at[37]);    MULADD(at[28], at[36]);    MULADD(at[29], at[35]);    MULADD(at[30], at[34]);    MULADD(at[31], at[33]);
+   COMBA_STORE(C->dp[32]);
+   /* 33 */
+   COMBA_FORWARD;
+   MULADD(at[2], at[63]);    MULADD(at[3], at[62]);    MULADD(at[4], at[61]);    MULADD(at[5], at[60]);    MULADD(at[6], at[59]);    MULADD(at[7], at[58]);    MULADD(at[8], at[57]);    MULADD(at[9], at[56]);    MULADD(at[10], at[55]);    MULADD(at[11], at[54]);    MULADD(at[12], at[53]);    MULADD(at[13], at[52]);    MULADD(at[14], at[51]);    MULADD(at[15], at[50]);    MULADD(at[16], at[49]);    MULADD(at[17], at[48]);    MULADD(at[18], at[47]);    MULADD(at[19], at[46]);    MULADD(at[20], at[45]);    MULADD(at[21], at[44]);    MULADD(at[22], at[43]);    MULADD(at[23], at[42]);    MULADD(at[24], at[41]);    MULADD(at[25], at[40]);    MULADD(at[26], at[39]);    MULADD(at[27], at[38]);    MULADD(at[28], at[37]);    MULADD(at[29], at[36]);    MULADD(at[30], at[35]);    MULADD(at[31], at[34]);
+   COMBA_STORE(C->dp[33]);
+   /* 34 */
+   COMBA_FORWARD;
+   MULADD(at[3], at[63]);    MULADD(at[4], at[62]);    MULADD(at[5], at[61]);    MULADD(at[6], at[60]);    MULADD(at[7], at[59]);    MULADD(at[8], at[58]);    MULADD(at[9], at[57]);    MULADD(at[10], at[56]);    MULADD(at[11], at[55]);    MULADD(at[12], at[54]);    MULADD(at[13], at[53]);    MULADD(at[14], at[52]);    MULADD(at[15], at[51]);    MULADD(at[16], at[50]);    MULADD(at[17], at[49]);    MULADD(at[18], at[48]);    MULADD(at[19], at[47]);    MULADD(at[20], at[46]);    MULADD(at[21], at[45]);    MULADD(at[22], at[44]);    MULADD(at[23], at[43]);    MULADD(at[24], at[42]);    MULADD(at[25], at[41]);    MULADD(at[26], at[40]);    MULADD(at[27], at[39]);    MULADD(at[28], at[38]);    MULADD(at[29], at[37]);    MULADD(at[30], at[36]);    MULADD(at[31], at[35]);
+   COMBA_STORE(C->dp[34]);
+   /* 35 */
+   COMBA_FORWARD;
+   MULADD(at[4], at[63]);    MULADD(at[5], at[62]);    MULADD(at[6], at[61]);    MULADD(at[7], at[60]);    MULADD(at[8], at[59]);    MULADD(at[9], at[58]);    MULADD(at[10], at[57]);    MULADD(at[11], at[56]);    MULADD(at[12], at[55]);    MULADD(at[13], at[54]);    MULADD(at[14], at[53]);    MULADD(at[15], at[52]);    MULADD(at[16], at[51]);    MULADD(at[17], at[50]);    MULADD(at[18], at[49]);    MULADD(at[19], at[48]);    MULADD(at[20], at[47]);    MULADD(at[21], at[46]);    MULADD(at[22], at[45]);    MULADD(at[23], at[44]);    MULADD(at[24], at[43]);    MULADD(at[25], at[42]);    MULADD(at[26], at[41]);    MULADD(at[27], at[40]);    MULADD(at[28], at[39]);    MULADD(at[29], at[38]);    MULADD(at[30], at[37]);    MULADD(at[31], at[36]);
+   COMBA_STORE(C->dp[35]);
+   /* 36 */
+   COMBA_FORWARD;
+   MULADD(at[5], at[63]);    MULADD(at[6], at[62]);    MULADD(at[7], at[61]);    MULADD(at[8], at[60]);    MULADD(at[9], at[59]);    MULADD(at[10], at[58]);    MULADD(at[11], at[57]);    MULADD(at[12], at[56]);    MULADD(at[13], at[55]);    MULADD(at[14], at[54]);    MULADD(at[15], at[53]);    MULADD(at[16], at[52]);    MULADD(at[17], at[51]);    MULADD(at[18], at[50]);    MULADD(at[19], at[49]);    MULADD(at[20], at[48]);    MULADD(at[21], at[47]);    MULADD(at[22], at[46]);    MULADD(at[23], at[45]);    MULADD(at[24], at[44]);    MULADD(at[25], at[43]);    MULADD(at[26], at[42]);    MULADD(at[27], at[41]);    MULADD(at[28], at[40]);    MULADD(at[29], at[39]);    MULADD(at[30], at[38]);    MULADD(at[31], at[37]);
+   COMBA_STORE(C->dp[36]);
+   /* 37 */
+   COMBA_FORWARD;
+   MULADD(at[6], at[63]);    MULADD(at[7], at[62]);    MULADD(at[8], at[61]);    MULADD(at[9], at[60]);    MULADD(at[10], at[59]);    MULADD(at[11], at[58]);    MULADD(at[12], at[57]);    MULADD(at[13], at[56]);    MULADD(at[14], at[55]);    MULADD(at[15], at[54]);    MULADD(at[16], at[53]);    MULADD(at[17], at[52]);    MULADD(at[18], at[51]);    MULADD(at[19], at[50]);    MULADD(at[20], at[49]);    MULADD(at[21], at[48]);    MULADD(at[22], at[47]);    MULADD(at[23], at[46]);    MULADD(at[24], at[45]);    MULADD(at[25], at[44]);    MULADD(at[26], at[43]);    MULADD(at[27], at[42]);    MULADD(at[28], at[41]);    MULADD(at[29], at[40]);    MULADD(at[30], at[39]);    MULADD(at[31], at[38]);
+   COMBA_STORE(C->dp[37]);
+   /* 38 */
+   COMBA_FORWARD;
+   MULADD(at[7], at[63]);    MULADD(at[8], at[62]);    MULADD(at[9], at[61]);    MULADD(at[10], at[60]);    MULADD(at[11], at[59]);    MULADD(at[12], at[58]);    MULADD(at[13], at[57]);    MULADD(at[14], at[56]);    MULADD(at[15], at[55]);    MULADD(at[16], at[54]);    MULADD(at[17], at[53]);    MULADD(at[18], at[52]);    MULADD(at[19], at[51]);    MULADD(at[20], at[50]);    MULADD(at[21], at[49]);    MULADD(at[22], at[48]);    MULADD(at[23], at[47]);    MULADD(at[24], at[46]);    MULADD(at[25], at[45]);    MULADD(at[26], at[44]);    MULADD(at[27], at[43]);    MULADD(at[28], at[42]);    MULADD(at[29], at[41]);    MULADD(at[30], at[40]);    MULADD(at[31], at[39]);
+   COMBA_STORE(C->dp[38]);
+
+   /* early out at 40 digits, 40*32==1280, or two 640 bit operands */
+   if (out_size <= 40) { COMBA_STORE2(C->dp[39]); C->used = 40; C->sign = A->sign ^ B->sign; fp_clamp(C); COMBA_FINI; return; }
+
+   /* 39 */
+   COMBA_FORWARD;
+   MULADD(at[8], at[63]);    MULADD(at[9], at[62]);    MULADD(at[10], at[61]);    MULADD(at[11], at[60]);    MULADD(at[12], at[59]);    MULADD(at[13], at[58]);    MULADD(at[14], at[57]);    MULADD(at[15], at[56]);    MULADD(at[16], at[55]);    MULADD(at[17], at[54]);    MULADD(at[18], at[53]);    MULADD(at[19], at[52]);    MULADD(at[20], at[51]);    MULADD(at[21], at[50]);    MULADD(at[22], at[49]);    MULADD(at[23], at[48]);    MULADD(at[24], at[47]);    MULADD(at[25], at[46]);    MULADD(at[26], at[45]);    MULADD(at[27], at[44]);    MULADD(at[28], at[43]);    MULADD(at[29], at[42]);    MULADD(at[30], at[41]);    MULADD(at[31], at[40]);
+   COMBA_STORE(C->dp[39]);
+   /* 40 */
+   COMBA_FORWARD;
+   MULADD(at[9], at[63]);    MULADD(at[10], at[62]);    MULADD(at[11], at[61]);    MULADD(at[12], at[60]);    MULADD(at[13], at[59]);    MULADD(at[14], at[58]);    MULADD(at[15], at[57]);    MULADD(at[16], at[56]);    MULADD(at[17], at[55]);    MULADD(at[18], at[54]);    MULADD(at[19], at[53]);    MULADD(at[20], at[52]);    MULADD(at[21], at[51]);    MULADD(at[22], at[50]);    MULADD(at[23], at[49]);    MULADD(at[24], at[48]);    MULADD(at[25], at[47]);    MULADD(at[26], at[46]);    MULADD(at[27], at[45]);    MULADD(at[28], at[44]);    MULADD(at[29], at[43]);    MULADD(at[30], at[42]);    MULADD(at[31], at[41]);
+   COMBA_STORE(C->dp[40]);
+   /* 41 */
+   COMBA_FORWARD;
+   MULADD(at[10], at[63]);    MULADD(at[11], at[62]);    MULADD(at[12], at[61]);    MULADD(at[13], at[60]);    MULADD(at[14], at[59]);    MULADD(at[15], at[58]);    MULADD(at[16], at[57]);    MULADD(at[17], at[56]);    MULADD(at[18], at[55]);    MULADD(at[19], at[54]);    MULADD(at[20], at[53]);    MULADD(at[21], at[52]);    MULADD(at[22], at[51]);    MULADD(at[23], at[50]);    MULADD(at[24], at[49]);    MULADD(at[25], at[48]);    MULADD(at[26], at[47]);    MULADD(at[27], at[46]);    MULADD(at[28], at[45]);    MULADD(at[29], at[44]);    MULADD(at[30], at[43]);    MULADD(at[31], at[42]);
+   COMBA_STORE(C->dp[41]);
+   /* 42 */
+   COMBA_FORWARD;
+   MULADD(at[11], at[63]);    MULADD(at[12], at[62]);    MULADD(at[13], at[61]);    MULADD(at[14], at[60]);    MULADD(at[15], at[59]);    MULADD(at[16], at[58]);    MULADD(at[17], at[57]);    MULADD(at[18], at[56]);    MULADD(at[19], at[55]);    MULADD(at[20], at[54]);    MULADD(at[21], at[53]);    MULADD(at[22], at[52]);    MULADD(at[23], at[51]);    MULADD(at[24], at[50]);    MULADD(at[25], at[49]);    MULADD(at[26], at[48]);    MULADD(at[27], at[47]);    MULADD(at[28], at[46]);    MULADD(at[29], at[45]);    MULADD(at[30], at[44]);    MULADD(at[31], at[43]);
+   COMBA_STORE(C->dp[42]);
+   /* 43 */
+   COMBA_FORWARD;
+   MULADD(at[12], at[63]);    MULADD(at[13], at[62]);    MULADD(at[14], at[61]);    MULADD(at[15], at[60]);    MULADD(at[16], at[59]);    MULADD(at[17], at[58]);    MULADD(at[18], at[57]);    MULADD(at[19], at[56]);    MULADD(at[20], at[55]);    MULADD(at[21], at[54]);    MULADD(at[22], at[53]);    MULADD(at[23], at[52]);    MULADD(at[24], at[51]);    MULADD(at[25], at[50]);    MULADD(at[26], at[49]);    MULADD(at[27], at[48]);    MULADD(at[28], at[47]);    MULADD(at[29], at[46]);    MULADD(at[30], at[45]);    MULADD(at[31], at[44]);
+   COMBA_STORE(C->dp[43]);
+   /* 44 */
+   COMBA_FORWARD;
+   MULADD(at[13], at[63]);    MULADD(at[14], at[62]);    MULADD(at[15], at[61]);    MULADD(at[16], at[60]);    MULADD(at[17], at[59]);    MULADD(at[18], at[58]);    MULADD(at[19], at[57]);    MULADD(at[20], at[56]);    MULADD(at[21], at[55]);    MULADD(at[22], at[54]);    MULADD(at[23], at[53]);    MULADD(at[24], at[52]);    MULADD(at[25], at[51]);    MULADD(at[26], at[50]);    MULADD(at[27], at[49]);    MULADD(at[28], at[48]);    MULADD(at[29], at[47]);    MULADD(at[30], at[46]);    MULADD(at[31], at[45]);
+   COMBA_STORE(C->dp[44]);
+   /* 45 */
+   COMBA_FORWARD;
+   MULADD(at[14], at[63]);    MULADD(at[15], at[62]);    MULADD(at[16], at[61]);    MULADD(at[17], at[60]);    MULADD(at[18], at[59]);    MULADD(at[19], at[58]);    MULADD(at[20], at[57]);    MULADD(at[21], at[56]);    MULADD(at[22], at[55]);    MULADD(at[23], at[54]);    MULADD(at[24], at[53]);    MULADD(at[25], at[52]);    MULADD(at[26], at[51]);    MULADD(at[27], at[50]);    MULADD(at[28], at[49]);    MULADD(at[29], at[48]);    MULADD(at[30], at[47]);    MULADD(at[31], at[46]);
+   COMBA_STORE(C->dp[45]);
+   /* 46 */
+   COMBA_FORWARD;
+   MULADD(at[15], at[63]);    MULADD(at[16], at[62]);    MULADD(at[17], at[61]);    MULADD(at[18], at[60]);    MULADD(at[19], at[59]);    MULADD(at[20], at[58]);    MULADD(at[21], at[57]);    MULADD(at[22], at[56]);    MULADD(at[23], at[55]);    MULADD(at[24], at[54]);    MULADD(at[25], at[53]);    MULADD(at[26], at[52]);    MULADD(at[27], at[51]);    MULADD(at[28], at[50]);    MULADD(at[29], at[49]);    MULADD(at[30], at[48]);    MULADD(at[31], at[47]);
+   COMBA_STORE(C->dp[46]);
+
+   /* early out at 48 digits, 48*32==1536, or two 768 bit operands */
+   if (out_size <= 48) { COMBA_STORE2(C->dp[47]); C->used = 48; C->sign = A->sign ^ B->sign; fp_clamp(C); COMBA_FINI; return; }
+
+   /* 47 */
+   COMBA_FORWARD;
+   MULADD(at[16], at[63]);    MULADD(at[17], at[62]);    MULADD(at[18], at[61]);    MULADD(at[19], at[60]);    MULADD(at[20], at[59]);    MULADD(at[21], at[58]);    MULADD(at[22], at[57]);    MULADD(at[23], at[56]);    MULADD(at[24], at[55]);    MULADD(at[25], at[54]);    MULADD(at[26], at[53]);    MULADD(at[27], at[52]);    MULADD(at[28], at[51]);    MULADD(at[29], at[50]);    MULADD(at[30], at[49]);    MULADD(at[31], at[48]);
+   COMBA_STORE(C->dp[47]);
+   /* 48 */
+   COMBA_FORWARD;
+   MULADD(at[17], at[63]);    MULADD(at[18], at[62]);    MULADD(at[19], at[61]);    MULADD(at[20], at[60]);    MULADD(at[21], at[59]);    MULADD(at[22], at[58]);    MULADD(at[23], at[57]);    MULADD(at[24], at[56]);    MULADD(at[25], at[55]);    MULADD(at[26], at[54]);    MULADD(at[27], at[53]);    MULADD(at[28], at[52]);    MULADD(at[29], at[51]);    MULADD(at[30], at[50]);    MULADD(at[31], at[49]);
+   COMBA_STORE(C->dp[48]);
+   /* 49 */
+   COMBA_FORWARD;
+   MULADD(at[18], at[63]);    MULADD(at[19], at[62]);    MULADD(at[20], at[61]);    MULADD(at[21], at[60]);    MULADD(at[22], at[59]);    MULADD(at[23], at[58]);    MULADD(at[24], at[57]);    MULADD(at[25], at[56]);    MULADD(at[26], at[55]);    MULADD(at[27], at[54]);    MULADD(at[28], at[53]);    MULADD(at[29], at[52]);    MULADD(at[30], at[51]);    MULADD(at[31], at[50]);
+   COMBA_STORE(C->dp[49]);
+   /* 50 */
+   COMBA_FORWARD;
+   MULADD(at[19], at[63]);    MULADD(at[20], at[62]);    MULADD(at[21], at[61]);    MULADD(at[22], at[60]);    MULADD(at[23], at[59]);    MULADD(at[24], at[58]);    MULADD(at[25], at[57]);    MULADD(at[26], at[56]);    MULADD(at[27], at[55]);    MULADD(at[28], at[54]);    MULADD(at[29], at[53]);    MULADD(at[30], at[52]);    MULADD(at[31], at[51]);
+   COMBA_STORE(C->dp[50]);
+   /* 51 */
+   COMBA_FORWARD;
+   MULADD(at[20], at[63]);    MULADD(at[21], at[62]);    MULADD(at[22], at[61]);    MULADD(at[23], at[60]);    MULADD(at[24], at[59]);    MULADD(at[25], at[58]);    MULADD(at[26], at[57]);    MULADD(at[27], at[56]);    MULADD(at[28], at[55]);    MULADD(at[29], at[54]);    MULADD(at[30], at[53]);    MULADD(at[31], at[52]);
+   COMBA_STORE(C->dp[51]);
+   /* 52 */
+   COMBA_FORWARD;
+   MULADD(at[21], at[63]);    MULADD(at[22], at[62]);    MULADD(at[23], at[61]);    MULADD(at[24], at[60]);    MULADD(at[25], at[59]);    MULADD(at[26], at[58]);    MULADD(at[27], at[57]);    MULADD(at[28], at[56]);    MULADD(at[29], at[55]);    MULADD(at[30], at[54]);    MULADD(at[31], at[53]);
+   COMBA_STORE(C->dp[52]);
+   /* 53 */
+   COMBA_FORWARD;
+   MULADD(at[22], at[63]);    MULADD(at[23], at[62]);    MULADD(at[24], at[61]);    MULADD(at[25], at[60]);    MULADD(at[26], at[59]);    MULADD(at[27], at[58]);    MULADD(at[28], at[57]);    MULADD(at[29], at[56]);    MULADD(at[30], at[55]);    MULADD(at[31], at[54]);
+   COMBA_STORE(C->dp[53]);
+   /* 54 */
+   COMBA_FORWARD;
+   MULADD(at[23], at[63]);    MULADD(at[24], at[62]);    MULADD(at[25], at[61]);    MULADD(at[26], at[60]);    MULADD(at[27], at[59]);    MULADD(at[28], at[58]);    MULADD(at[29], at[57]);    MULADD(at[30], at[56]);    MULADD(at[31], at[55]);
+   COMBA_STORE(C->dp[54]);
+
+   /* early out at 56 digits, 56*32==1792, or two 896 bit operands */
+   if (out_size <= 56) { COMBA_STORE2(C->dp[55]); C->used = 56; C->sign = A->sign ^ B->sign; fp_clamp(C); COMBA_FINI; return; }
+
+   /* 55 */
+   COMBA_FORWARD;
+   MULADD(at[24], at[63]);    MULADD(at[25], at[62]);    MULADD(at[26], at[61]);    MULADD(at[27], at[60]);    MULADD(at[28], at[59]);    MULADD(at[29], at[58]);    MULADD(at[30], at[57]);    MULADD(at[31], at[56]);
+   COMBA_STORE(C->dp[55]);
+   /* 56 */
+   COMBA_FORWARD;
+   MULADD(at[25], at[63]);    MULADD(at[26], at[62]);    MULADD(at[27], at[61]);    MULADD(at[28], at[60]);    MULADD(at[29], at[59]);    MULADD(at[30], at[58]);    MULADD(at[31], at[57]);
+   COMBA_STORE(C->dp[56]);
+   /* 57 */
+   COMBA_FORWARD;
+   MULADD(at[26], at[63]);    MULADD(at[27], at[62]);    MULADD(at[28], at[61]);    MULADD(at[29], at[60]);    MULADD(at[30], at[59]);    MULADD(at[31], at[58]);
+   COMBA_STORE(C->dp[57]);
+   /* 58 */
+   COMBA_FORWARD;
+   MULADD(at[27], at[63]);    MULADD(at[28], at[62]);    MULADD(at[29], at[61]);    MULADD(at[30], at[60]);    MULADD(at[31], at[59]);
+   COMBA_STORE(C->dp[58]);
+   /* 59 */
+   COMBA_FORWARD;
+   MULADD(at[28], at[63]);    MULADD(at[29], at[62]);    MULADD(at[30], at[61]);    MULADD(at[31], at[60]);
+   COMBA_STORE(C->dp[59]);
+   /* 60 */
+   COMBA_FORWARD;
+   MULADD(at[29], at[63]);    MULADD(at[30], at[62]);    MULADD(at[31], at[61]);
+   COMBA_STORE(C->dp[60]);
+   /* 61 */
+   COMBA_FORWARD;
+   MULADD(at[30], at[63]);    MULADD(at[31], at[62]);
+   COMBA_STORE(C->dp[61]);
+   /* 62 */
+   COMBA_FORWARD;
+   MULADD(at[31], at[63]);
+   COMBA_STORE(C->dp[62]);
+   COMBA_STORE2(C->dp[63]);
+   C->used = 64;
+   C->sign = A->sign ^ B->sign;
+   fp_clamp(C);
+   COMBA_FINI;
+}
+#endif
+
+
+/* $Source$ */
+/* $Revision$ */
+/* $Date$ */
diff --git a/tomsfastmath/src/mul/fp_mul_comba_4.c b/tomsfastmath/src/mul/fp_mul_comba_4.c
new file mode 100644 (file)
index 0000000..7a3769e
--- /dev/null
@@ -0,0 +1,52 @@
+#define TFM_DEFINES
+#include "fp_mul_comba.c"
+
+#if defined(TFM_MUL4) && FP_SIZE >= 8
+void fp_mul_comba4(fp_int *A, fp_int *B, fp_int *C)
+{
+   fp_digit c0, c1, c2, at[8];
+
+   memcpy(at, A->dp, 4 * sizeof(fp_digit));
+   memcpy(at+4, B->dp, 4 * sizeof(fp_digit));
+   COMBA_START;
+
+   COMBA_CLEAR;
+   /* 0 */
+   MULADD(at[0], at[4]);
+   COMBA_STORE(C->dp[0]);
+   /* 1 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[5]);    MULADD(at[1], at[4]);
+   COMBA_STORE(C->dp[1]);
+   /* 2 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[6]);    MULADD(at[1], at[5]);    MULADD(at[2], at[4]);
+   COMBA_STORE(C->dp[2]);
+   /* 3 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[7]);    MULADD(at[1], at[6]);    MULADD(at[2], at[5]);    MULADD(at[3], at[4]);
+   COMBA_STORE(C->dp[3]);
+   /* 4 */
+   COMBA_FORWARD;
+   MULADD(at[1], at[7]);    MULADD(at[2], at[6]);    MULADD(at[3], at[5]);
+   COMBA_STORE(C->dp[4]);
+   /* 5 */
+   COMBA_FORWARD;
+   MULADD(at[2], at[7]);    MULADD(at[3], at[6]);
+   COMBA_STORE(C->dp[5]);
+   /* 6 */
+   COMBA_FORWARD;
+   MULADD(at[3], at[7]);
+   COMBA_STORE(C->dp[6]);
+   COMBA_STORE2(C->dp[7]);
+   C->used = 8;
+   C->sign = A->sign ^ B->sign;
+   fp_clamp(C);
+   COMBA_FINI;
+}
+#endif
+
+
+/* $Source$ */
+/* $Revision$ */
+/* $Date$ */
diff --git a/tomsfastmath/src/mul/fp_mul_comba_48.c b/tomsfastmath/src/mul/fp_mul_comba_48.c
new file mode 100644 (file)
index 0000000..7eafe75
--- /dev/null
@@ -0,0 +1,404 @@
+#define TFM_DEFINES
+#include "fp_mul_comba.c"
+
+#if defined(TFM_MUL48) && FP_SIZE >= 96
+void fp_mul_comba48(fp_int *A, fp_int *B, fp_int *C)
+{
+   fp_digit c0, c1, c2, at[96];
+
+   memcpy(at, A->dp, 48 * sizeof(fp_digit));
+   memcpy(at+48, B->dp, 48 * sizeof(fp_digit));
+   COMBA_START;
+
+   COMBA_CLEAR;
+   /* 0 */
+   MULADD(at[0], at[48]);
+   COMBA_STORE(C->dp[0]);
+   /* 1 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[49]);    MULADD(at[1], at[48]);
+   COMBA_STORE(C->dp[1]);
+   /* 2 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[50]);    MULADD(at[1], at[49]);    MULADD(at[2], at[48]);
+   COMBA_STORE(C->dp[2]);
+   /* 3 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[51]);    MULADD(at[1], at[50]);    MULADD(at[2], at[49]);    MULADD(at[3], at[48]);
+   COMBA_STORE(C->dp[3]);
+   /* 4 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[52]);    MULADD(at[1], at[51]);    MULADD(at[2], at[50]);    MULADD(at[3], at[49]);    MULADD(at[4], at[48]);
+   COMBA_STORE(C->dp[4]);
+   /* 5 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[53]);    MULADD(at[1], at[52]);    MULADD(at[2], at[51]);    MULADD(at[3], at[50]);    MULADD(at[4], at[49]);    MULADD(at[5], at[48]);
+   COMBA_STORE(C->dp[5]);
+   /* 6 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[54]);    MULADD(at[1], at[53]);    MULADD(at[2], at[52]);    MULADD(at[3], at[51]);    MULADD(at[4], at[50]);    MULADD(at[5], at[49]);    MULADD(at[6], at[48]);
+   COMBA_STORE(C->dp[6]);
+   /* 7 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[55]);    MULADD(at[1], at[54]);    MULADD(at[2], at[53]);    MULADD(at[3], at[52]);    MULADD(at[4], at[51]);    MULADD(at[5], at[50]);    MULADD(at[6], at[49]);    MULADD(at[7], at[48]);
+   COMBA_STORE(C->dp[7]);
+   /* 8 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[56]);    MULADD(at[1], at[55]);    MULADD(at[2], at[54]);    MULADD(at[3], at[53]);    MULADD(at[4], at[52]);    MULADD(at[5], at[51]);    MULADD(at[6], at[50]);    MULADD(at[7], at[49]);    MULADD(at[8], at[48]);
+   COMBA_STORE(C->dp[8]);
+   /* 9 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[57]);    MULADD(at[1], at[56]);    MULADD(at[2], at[55]);    MULADD(at[3], at[54]);    MULADD(at[4], at[53]);    MULADD(at[5], at[52]);    MULADD(at[6], at[51]);    MULADD(at[7], at[50]);    MULADD(at[8], at[49]);    MULADD(at[9], at[48]);
+   COMBA_STORE(C->dp[9]);
+   /* 10 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[58]);    MULADD(at[1], at[57]);    MULADD(at[2], at[56]);    MULADD(at[3], at[55]);    MULADD(at[4], at[54]);    MULADD(at[5], at[53]);    MULADD(at[6], at[52]);    MULADD(at[7], at[51]);    MULADD(at[8], at[50]);    MULADD(at[9], at[49]);    MULADD(at[10], at[48]);
+   COMBA_STORE(C->dp[10]);
+   /* 11 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[59]);    MULADD(at[1], at[58]);    MULADD(at[2], at[57]);    MULADD(at[3], at[56]);    MULADD(at[4], at[55]);    MULADD(at[5], at[54]);    MULADD(at[6], at[53]);    MULADD(at[7], at[52]);    MULADD(at[8], at[51]);    MULADD(at[9], at[50]);    MULADD(at[10], at[49]);    MULADD(at[11], at[48]);
+   COMBA_STORE(C->dp[11]);
+   /* 12 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[60]);    MULADD(at[1], at[59]);    MULADD(at[2], at[58]);    MULADD(at[3], at[57]);    MULADD(at[4], at[56]);    MULADD(at[5], at[55]);    MULADD(at[6], at[54]);    MULADD(at[7], at[53]);    MULADD(at[8], at[52]);    MULADD(at[9], at[51]);    MULADD(at[10], at[50]);    MULADD(at[11], at[49]);    MULADD(at[12], at[48]);
+   COMBA_STORE(C->dp[12]);
+   /* 13 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[61]);    MULADD(at[1], at[60]);    MULADD(at[2], at[59]);    MULADD(at[3], at[58]);    MULADD(at[4], at[57]);    MULADD(at[5], at[56]);    MULADD(at[6], at[55]);    MULADD(at[7], at[54]);    MULADD(at[8], at[53]);    MULADD(at[9], at[52]);    MULADD(at[10], at[51]);    MULADD(at[11], at[50]);    MULADD(at[12], at[49]);    MULADD(at[13], at[48]);
+   COMBA_STORE(C->dp[13]);
+   /* 14 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[62]);    MULADD(at[1], at[61]);    MULADD(at[2], at[60]);    MULADD(at[3], at[59]);    MULADD(at[4], at[58]);    MULADD(at[5], at[57]);    MULADD(at[6], at[56]);    MULADD(at[7], at[55]);    MULADD(at[8], at[54]);    MULADD(at[9], at[53]);    MULADD(at[10], at[52]);    MULADD(at[11], at[51]);    MULADD(at[12], at[50]);    MULADD(at[13], at[49]);    MULADD(at[14], at[48]);
+   COMBA_STORE(C->dp[14]);
+   /* 15 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[63]);    MULADD(at[1], at[62]);    MULADD(at[2], at[61]);    MULADD(at[3], at[60]);    MULADD(at[4], at[59]);    MULADD(at[5], at[58]);    MULADD(at[6], at[57]);    MULADD(at[7], at[56]);    MULADD(at[8], at[55]);    MULADD(at[9], at[54]);    MULADD(at[10], at[53]);    MULADD(at[11], at[52]);    MULADD(at[12], at[51]);    MULADD(at[13], at[50]);    MULADD(at[14], at[49]);    MULADD(at[15], at[48]);
+   COMBA_STORE(C->dp[15]);
+   /* 16 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[64]);    MULADD(at[1], at[63]);    MULADD(at[2], at[62]);    MULADD(at[3], at[61]);    MULADD(at[4], at[60]);    MULADD(at[5], at[59]);    MULADD(at[6], at[58]);    MULADD(at[7], at[57]);    MULADD(at[8], at[56]);    MULADD(at[9], at[55]);    MULADD(at[10], at[54]);    MULADD(at[11], at[53]);    MULADD(at[12], at[52]);    MULADD(at[13], at[51]);    MULADD(at[14], at[50]);    MULADD(at[15], at[49]);    MULADD(at[16], at[48]);
+   COMBA_STORE(C->dp[16]);
+   /* 17 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[65]);    MULADD(at[1], at[64]);    MULADD(at[2], at[63]);    MULADD(at[3], at[62]);    MULADD(at[4], at[61]);    MULADD(at[5], at[60]);    MULADD(at[6], at[59]);    MULADD(at[7], at[58]);    MULADD(at[8], at[57]);    MULADD(at[9], at[56]);    MULADD(at[10], at[55]);    MULADD(at[11], at[54]);    MULADD(at[12], at[53]);    MULADD(at[13], at[52]);    MULADD(at[14], at[51]);    MULADD(at[15], at[50]);    MULADD(at[16], at[49]);    MULADD(at[17], at[48]);
+   COMBA_STORE(C->dp[17]);
+   /* 18 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[66]);    MULADD(at[1], at[65]);    MULADD(at[2], at[64]);    MULADD(at[3], at[63]);    MULADD(at[4], at[62]);    MULADD(at[5], at[61]);    MULADD(at[6], at[60]);    MULADD(at[7], at[59]);    MULADD(at[8], at[58]);    MULADD(at[9], at[57]);    MULADD(at[10], at[56]);    MULADD(at[11], at[55]);    MULADD(at[12], at[54]);    MULADD(at[13], at[53]);    MULADD(at[14], at[52]);    MULADD(at[15], at[51]);    MULADD(at[16], at[50]);    MULADD(at[17], at[49]);    MULADD(at[18], at[48]);
+   COMBA_STORE(C->dp[18]);
+   /* 19 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[67]);    MULADD(at[1], at[66]);    MULADD(at[2], at[65]);    MULADD(at[3], at[64]);    MULADD(at[4], at[63]);    MULADD(at[5], at[62]);    MULADD(at[6], at[61]);    MULADD(at[7], at[60]);    MULADD(at[8], at[59]);    MULADD(at[9], at[58]);    MULADD(at[10], at[57]);    MULADD(at[11], at[56]);    MULADD(at[12], at[55]);    MULADD(at[13], at[54]);    MULADD(at[14], at[53]);    MULADD(at[15], at[52]);    MULADD(at[16], at[51]);    MULADD(at[17], at[50]);    MULADD(at[18], at[49]);    MULADD(at[19], at[48]);
+   COMBA_STORE(C->dp[19]);
+   /* 20 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[68]);    MULADD(at[1], at[67]);    MULADD(at[2], at[66]);    MULADD(at[3], at[65]);    MULADD(at[4], at[64]);    MULADD(at[5], at[63]);    MULADD(at[6], at[62]);    MULADD(at[7], at[61]);    MULADD(at[8], at[60]);    MULADD(at[9], at[59]);    MULADD(at[10], at[58]);    MULADD(at[11], at[57]);    MULADD(at[12], at[56]);    MULADD(at[13], at[55]);    MULADD(at[14], at[54]);    MULADD(at[15], at[53]);    MULADD(at[16], at[52]);    MULADD(at[17], at[51]);    MULADD(at[18], at[50]);    MULADD(at[19], at[49]);    MULADD(at[20], at[48]);
+   COMBA_STORE(C->dp[20]);
+   /* 21 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[69]);    MULADD(at[1], at[68]);    MULADD(at[2], at[67]);    MULADD(at[3], at[66]);    MULADD(at[4], at[65]);    MULADD(at[5], at[64]);    MULADD(at[6], at[63]);    MULADD(at[7], at[62]);    MULADD(at[8], at[61]);    MULADD(at[9], at[60]);    MULADD(at[10], at[59]);    MULADD(at[11], at[58]);    MULADD(at[12], at[57]);    MULADD(at[13], at[56]);    MULADD(at[14], at[55]);    MULADD(at[15], at[54]);    MULADD(at[16], at[53]);    MULADD(at[17], at[52]);    MULADD(at[18], at[51]);    MULADD(at[19], at[50]);    MULADD(at[20], at[49]);    MULADD(at[21], at[48]);
+   COMBA_STORE(C->dp[21]);
+   /* 22 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[70]);    MULADD(at[1], at[69]);    MULADD(at[2], at[68]);    MULADD(at[3], at[67]);    MULADD(at[4], at[66]);    MULADD(at[5], at[65]);    MULADD(at[6], at[64]);    MULADD(at[7], at[63]);    MULADD(at[8], at[62]);    MULADD(at[9], at[61]);    MULADD(at[10], at[60]);    MULADD(at[11], at[59]);    MULADD(at[12], at[58]);    MULADD(at[13], at[57]);    MULADD(at[14], at[56]);    MULADD(at[15], at[55]);    MULADD(at[16], at[54]);    MULADD(at[17], at[53]);    MULADD(at[18], at[52]);    MULADD(at[19], at[51]);    MULADD(at[20], at[50]);    MULADD(at[21], at[49]);    MULADD(at[22], at[48]);
+   COMBA_STORE(C->dp[22]);
+   /* 23 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[71]);    MULADD(at[1], at[70]);    MULADD(at[2], at[69]);    MULADD(at[3], at[68]);    MULADD(at[4], at[67]);    MULADD(at[5], at[66]);    MULADD(at[6], at[65]);    MULADD(at[7], at[64]);    MULADD(at[8], at[63]);    MULADD(at[9], at[62]);    MULADD(at[10], at[61]);    MULADD(at[11], at[60]);    MULADD(at[12], at[59]);    MULADD(at[13], at[58]);    MULADD(at[14], at[57]);    MULADD(at[15], at[56]);    MULADD(at[16], at[55]);    MULADD(at[17], at[54]);    MULADD(at[18], at[53]);    MULADD(at[19], at[52]);    MULADD(at[20], at[51]);    MULADD(at[21], at[50]);    MULADD(at[22], at[49]);    MULADD(at[23], at[48]);
+   COMBA_STORE(C->dp[23]);
+   /* 24 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[72]);    MULADD(at[1], at[71]);    MULADD(at[2], at[70]);    MULADD(at[3], at[69]);    MULADD(at[4], at[68]);    MULADD(at[5], at[67]);    MULADD(at[6], at[66]);    MULADD(at[7], at[65]);    MULADD(at[8], at[64]);    MULADD(at[9], at[63]);    MULADD(at[10], at[62]);    MULADD(at[11], at[61]);    MULADD(at[12], at[60]);    MULADD(at[13], at[59]);    MULADD(at[14], at[58]);    MULADD(at[15], at[57]);    MULADD(at[16], at[56]);    MULADD(at[17], at[55]);    MULADD(at[18], at[54]);    MULADD(at[19], at[53]);    MULADD(at[20], at[52]);    MULADD(at[21], at[51]);    MULADD(at[22], at[50]);    MULADD(at[23], at[49]);    MULADD(at[24], at[48]);
+   COMBA_STORE(C->dp[24]);
+   /* 25 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[73]);    MULADD(at[1], at[72]);    MULADD(at[2], at[71]);    MULADD(at[3], at[70]);    MULADD(at[4], at[69]);    MULADD(at[5], at[68]);    MULADD(at[6], at[67]);    MULADD(at[7], at[66]);    MULADD(at[8], at[65]);    MULADD(at[9], at[64]);    MULADD(at[10], at[63]);    MULADD(at[11], at[62]);    MULADD(at[12], at[61]);    MULADD(at[13], at[60]);    MULADD(at[14], at[59]);    MULADD(at[15], at[58]);    MULADD(at[16], at[57]);    MULADD(at[17], at[56]);    MULADD(at[18], at[55]);    MULADD(at[19], at[54]);    MULADD(at[20], at[53]);    MULADD(at[21], at[52]);    MULADD(at[22], at[51]);    MULADD(at[23], at[50]);    MULADD(at[24], at[49]);    MULADD(at[25], at[48]);
+   COMBA_STORE(C->dp[25]);
+   /* 26 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[74]);    MULADD(at[1], at[73]);    MULADD(at[2], at[72]);    MULADD(at[3], at[71]);    MULADD(at[4], at[70]);    MULADD(at[5], at[69]);    MULADD(at[6], at[68]);    MULADD(at[7], at[67]);    MULADD(at[8], at[66]);    MULADD(at[9], at[65]);    MULADD(at[10], at[64]);    MULADD(at[11], at[63]);    MULADD(at[12], at[62]);    MULADD(at[13], at[61]);    MULADD(at[14], at[60]);    MULADD(at[15], at[59]);    MULADD(at[16], at[58]);    MULADD(at[17], at[57]);    MULADD(at[18], at[56]);    MULADD(at[19], at[55]);    MULADD(at[20], at[54]);    MULADD(at[21], at[53]);    MULADD(at[22], at[52]);    MULADD(at[23], at[51]);    MULADD(at[24], at[50]);    MULADD(at[25], at[49]);    MULADD(at[26], at[48]);
+   COMBA_STORE(C->dp[26]);
+   /* 27 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[75]);    MULADD(at[1], at[74]);    MULADD(at[2], at[73]);    MULADD(at[3], at[72]);    MULADD(at[4], at[71]);    MULADD(at[5], at[70]);    MULADD(at[6], at[69]);    MULADD(at[7], at[68]);    MULADD(at[8], at[67]);    MULADD(at[9], at[66]);    MULADD(at[10], at[65]);    MULADD(at[11], at[64]);    MULADD(at[12], at[63]);    MULADD(at[13], at[62]);    MULADD(at[14], at[61]);    MULADD(at[15], at[60]);    MULADD(at[16], at[59]);    MULADD(at[17], at[58]);    MULADD(at[18], at[57]);    MULADD(at[19], at[56]);    MULADD(at[20], at[55]);    MULADD(at[21], at[54]);    MULADD(at[22], at[53]);    MULADD(at[23], at[52]);    MULADD(at[24], at[51]);    MULADD(at[25], at[50]);    MULADD(at[26], at[49]);    MULADD(at[27], at[48]);
+   COMBA_STORE(C->dp[27]);
+   /* 28 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[76]);    MULADD(at[1], at[75]);    MULADD(at[2], at[74]);    MULADD(at[3], at[73]);    MULADD(at[4], at[72]);    MULADD(at[5], at[71]);    MULADD(at[6], at[70]);    MULADD(at[7], at[69]);    MULADD(at[8], at[68]);    MULADD(at[9], at[67]);    MULADD(at[10], at[66]);    MULADD(at[11], at[65]);    MULADD(at[12], at[64]);    MULADD(at[13], at[63]);    MULADD(at[14], at[62]);    MULADD(at[15], at[61]);    MULADD(at[16], at[60]);    MULADD(at[17], at[59]);    MULADD(at[18], at[58]);    MULADD(at[19], at[57]);    MULADD(at[20], at[56]);    MULADD(at[21], at[55]);    MULADD(at[22], at[54]);    MULADD(at[23], at[53]);    MULADD(at[24], at[52]);    MULADD(at[25], at[51]);    MULADD(at[26], at[50]);    MULADD(at[27], at[49]);    MULADD(at[28], at[48]);
+   COMBA_STORE(C->dp[28]);
+   /* 29 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[77]);    MULADD(at[1], at[76]);    MULADD(at[2], at[75]);    MULADD(at[3], at[74]);    MULADD(at[4], at[73]);    MULADD(at[5], at[72]);    MULADD(at[6], at[71]);    MULADD(at[7], at[70]);    MULADD(at[8], at[69]);    MULADD(at[9], at[68]);    MULADD(at[10], at[67]);    MULADD(at[11], at[66]);    MULADD(at[12], at[65]);    MULADD(at[13], at[64]);    MULADD(at[14], at[63]);    MULADD(at[15], at[62]);    MULADD(at[16], at[61]);    MULADD(at[17], at[60]);    MULADD(at[18], at[59]);    MULADD(at[19], at[58]);    MULADD(at[20], at[57]);    MULADD(at[21], at[56]);    MULADD(at[22], at[55]);    MULADD(at[23], at[54]);    MULADD(at[24], at[53]);    MULADD(at[25], at[52]);    MULADD(at[26], at[51]);    MULADD(at[27], at[50]);    MULADD(at[28], at[49]);    MULADD(at[29], at[48]);
+   COMBA_STORE(C->dp[29]);
+   /* 30 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[78]);    MULADD(at[1], at[77]);    MULADD(at[2], at[76]);    MULADD(at[3], at[75]);    MULADD(at[4], at[74]);    MULADD(at[5], at[73]);    MULADD(at[6], at[72]);    MULADD(at[7], at[71]);    MULADD(at[8], at[70]);    MULADD(at[9], at[69]);    MULADD(at[10], at[68]);    MULADD(at[11], at[67]);    MULADD(at[12], at[66]);    MULADD(at[13], at[65]);    MULADD(at[14], at[64]);    MULADD(at[15], at[63]);    MULADD(at[16], at[62]);    MULADD(at[17], at[61]);    MULADD(at[18], at[60]);    MULADD(at[19], at[59]);    MULADD(at[20], at[58]);    MULADD(at[21], at[57]);    MULADD(at[22], at[56]);    MULADD(at[23], at[55]);    MULADD(at[24], at[54]);    MULADD(at[25], at[53]);    MULADD(at[26], at[52]);    MULADD(at[27], at[51]);    MULADD(at[28], at[50]);    MULADD(at[29], at[49]);    MULADD(at[30], at[48]);
+   COMBA_STORE(C->dp[30]);
+   /* 31 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[79]);    MULADD(at[1], at[78]);    MULADD(at[2], at[77]);    MULADD(at[3], at[76]);    MULADD(at[4], at[75]);    MULADD(at[5], at[74]);    MULADD(at[6], at[73]);    MULADD(at[7], at[72]);    MULADD(at[8], at[71]);    MULADD(at[9], at[70]);    MULADD(at[10], at[69]);    MULADD(at[11], at[68]);    MULADD(at[12], at[67]);    MULADD(at[13], at[66]);    MULADD(at[14], at[65]);    MULADD(at[15], at[64]);    MULADD(at[16], at[63]);    MULADD(at[17], at[62]);    MULADD(at[18], at[61]);    MULADD(at[19], at[60]);    MULADD(at[20], at[59]);    MULADD(at[21], at[58]);    MULADD(at[22], at[57]);    MULADD(at[23], at[56]);    MULADD(at[24], at[55]);    MULADD(at[25], at[54]);    MULADD(at[26], at[53]);    MULADD(at[27], at[52]);    MULADD(at[28], at[51]);    MULADD(at[29], at[50]);    MULADD(at[30], at[49]);    MULADD(at[31], at[48]);
+   COMBA_STORE(C->dp[31]);
+   /* 32 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[80]);    MULADD(at[1], at[79]);    MULADD(at[2], at[78]);    MULADD(at[3], at[77]);    MULADD(at[4], at[76]);    MULADD(at[5], at[75]);    MULADD(at[6], at[74]);    MULADD(at[7], at[73]);    MULADD(at[8], at[72]);    MULADD(at[9], at[71]);    MULADD(at[10], at[70]);    MULADD(at[11], at[69]);    MULADD(at[12], at[68]);    MULADD(at[13], at[67]);    MULADD(at[14], at[66]);    MULADD(at[15], at[65]);    MULADD(at[16], at[64]);    MULADD(at[17], at[63]);    MULADD(at[18], at[62]);    MULADD(at[19], at[61]);    MULADD(at[20], at[60]);    MULADD(at[21], at[59]);    MULADD(at[22], at[58]);    MULADD(at[23], at[57]);    MULADD(at[24], at[56]);    MULADD(at[25], at[55]);    MULADD(at[26], at[54]);    MULADD(at[27], at[53]);    MULADD(at[28], at[52]);    MULADD(at[29], at[51]);    MULADD(at[30], at[50]);    MULADD(at[31], at[49]);    MULADD(at[32], at[48]);
+   COMBA_STORE(C->dp[32]);
+   /* 33 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[81]);    MULADD(at[1], at[80]);    MULADD(at[2], at[79]);    MULADD(at[3], at[78]);    MULADD(at[4], at[77]);    MULADD(at[5], at[76]);    MULADD(at[6], at[75]);    MULADD(at[7], at[74]);    MULADD(at[8], at[73]);    MULADD(at[9], at[72]);    MULADD(at[10], at[71]);    MULADD(at[11], at[70]);    MULADD(at[12], at[69]);    MULADD(at[13], at[68]);    MULADD(at[14], at[67]);    MULADD(at[15], at[66]);    MULADD(at[16], at[65]);    MULADD(at[17], at[64]);    MULADD(at[18], at[63]);    MULADD(at[19], at[62]);    MULADD(at[20], at[61]);    MULADD(at[21], at[60]);    MULADD(at[22], at[59]);    MULADD(at[23], at[58]);    MULADD(at[24], at[57]);    MULADD(at[25], at[56]);    MULADD(at[26], at[55]);    MULADD(at[27], at[54]);    MULADD(at[28], at[53]);    MULADD(at[29], at[52]);    MULADD(at[30], at[51]);    MULADD(at[31], at[50]);    MULADD(at[32], at[49]);    MULADD(at[33], at[48]);
+   COMBA_STORE(C->dp[33]);
+   /* 34 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[82]);    MULADD(at[1], at[81]);    MULADD(at[2], at[80]);    MULADD(at[3], at[79]);    MULADD(at[4], at[78]);    MULADD(at[5], at[77]);    MULADD(at[6], at[76]);    MULADD(at[7], at[75]);    MULADD(at[8], at[74]);    MULADD(at[9], at[73]);    MULADD(at[10], at[72]);    MULADD(at[11], at[71]);    MULADD(at[12], at[70]);    MULADD(at[13], at[69]);    MULADD(at[14], at[68]);    MULADD(at[15], at[67]);    MULADD(at[16], at[66]);    MULADD(at[17], at[65]);    MULADD(at[18], at[64]);    MULADD(at[19], at[63]);    MULADD(at[20], at[62]);    MULADD(at[21], at[61]);    MULADD(at[22], at[60]);    MULADD(at[23], at[59]);    MULADD(at[24], at[58]);    MULADD(at[25], at[57]);    MULADD(at[26], at[56]);    MULADD(at[27], at[55]);    MULADD(at[28], at[54]);    MULADD(at[29], at[53]);    MULADD(at[30], at[52]);    MULADD(at[31], at[51]);    MULADD(at[32], at[50]);    MULADD(at[33], at[49]);    MULADD(at[34], at[48]);
+   COMBA_STORE(C->dp[34]);
+   /* 35 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[83]);    MULADD(at[1], at[82]);    MULADD(at[2], at[81]);    MULADD(at[3], at[80]);    MULADD(at[4], at[79]);    MULADD(at[5], at[78]);    MULADD(at[6], at[77]);    MULADD(at[7], at[76]);    MULADD(at[8], at[75]);    MULADD(at[9], at[74]);    MULADD(at[10], at[73]);    MULADD(at[11], at[72]);    MULADD(at[12], at[71]);    MULADD(at[13], at[70]);    MULADD(at[14], at[69]);    MULADD(at[15], at[68]);    MULADD(at[16], at[67]);    MULADD(at[17], at[66]);    MULADD(at[18], at[65]);    MULADD(at[19], at[64]);    MULADD(at[20], at[63]);    MULADD(at[21], at[62]);    MULADD(at[22], at[61]);    MULADD(at[23], at[60]);    MULADD(at[24], at[59]);    MULADD(at[25], at[58]);    MULADD(at[26], at[57]);    MULADD(at[27], at[56]);    MULADD(at[28], at[55]);    MULADD(at[29], at[54]);    MULADD(at[30], at[53]);    MULADD(at[31], at[52]);    MULADD(at[32], at[51]);    MULADD(at[33], at[50]);    MULADD(at[34], at[49]);    MULADD(at[35], at[48]);
+   COMBA_STORE(C->dp[35]);
+   /* 36 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[84]);    MULADD(at[1], at[83]);    MULADD(at[2], at[82]);    MULADD(at[3], at[81]);    MULADD(at[4], at[80]);    MULADD(at[5], at[79]);    MULADD(at[6], at[78]);    MULADD(at[7], at[77]);    MULADD(at[8], at[76]);    MULADD(at[9], at[75]);    MULADD(at[10], at[74]);    MULADD(at[11], at[73]);    MULADD(at[12], at[72]);    MULADD(at[13], at[71]);    MULADD(at[14], at[70]);    MULADD(at[15], at[69]);    MULADD(at[16], at[68]);    MULADD(at[17], at[67]);    MULADD(at[18], at[66]);    MULADD(at[19], at[65]);    MULADD(at[20], at[64]);    MULADD(at[21], at[63]);    MULADD(at[22], at[62]);    MULADD(at[23], at[61]);    MULADD(at[24], at[60]);    MULADD(at[25], at[59]);    MULADD(at[26], at[58]);    MULADD(at[27], at[57]);    MULADD(at[28], at[56]);    MULADD(at[29], at[55]);    MULADD(at[30], at[54]);    MULADD(at[31], at[53]);    MULADD(at[32], at[52]);    MULADD(at[33], at[51]);    MULADD(at[34], at[50]);    MULADD(at[35], at[49]);    MULADD(at[36], at[48]);
+   COMBA_STORE(C->dp[36]);
+   /* 37 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[85]);    MULADD(at[1], at[84]);    MULADD(at[2], at[83]);    MULADD(at[3], at[82]);    MULADD(at[4], at[81]);    MULADD(at[5], at[80]);    MULADD(at[6], at[79]);    MULADD(at[7], at[78]);    MULADD(at[8], at[77]);    MULADD(at[9], at[76]);    MULADD(at[10], at[75]);    MULADD(at[11], at[74]);    MULADD(at[12], at[73]);    MULADD(at[13], at[72]);    MULADD(at[14], at[71]);    MULADD(at[15], at[70]);    MULADD(at[16], at[69]);    MULADD(at[17], at[68]);    MULADD(at[18], at[67]);    MULADD(at[19], at[66]);    MULADD(at[20], at[65]);    MULADD(at[21], at[64]);    MULADD(at[22], at[63]);    MULADD(at[23], at[62]);    MULADD(at[24], at[61]);    MULADD(at[25], at[60]);    MULADD(at[26], at[59]);    MULADD(at[27], at[58]);    MULADD(at[28], at[57]);    MULADD(at[29], at[56]);    MULADD(at[30], at[55]);    MULADD(at[31], at[54]);    MULADD(at[32], at[53]);    MULADD(at[33], at[52]);    MULADD(at[34], at[51]);    MULADD(at[35], at[50]);    MULADD(at[36], at[49]);    MULADD(at[37], at[48]);
+   COMBA_STORE(C->dp[37]);
+   /* 38 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[86]);    MULADD(at[1], at[85]);    MULADD(at[2], at[84]);    MULADD(at[3], at[83]);    MULADD(at[4], at[82]);    MULADD(at[5], at[81]);    MULADD(at[6], at[80]);    MULADD(at[7], at[79]);    MULADD(at[8], at[78]);    MULADD(at[9], at[77]);    MULADD(at[10], at[76]);    MULADD(at[11], at[75]);    MULADD(at[12], at[74]);    MULADD(at[13], at[73]);    MULADD(at[14], at[72]);    MULADD(at[15], at[71]);    MULADD(at[16], at[70]);    MULADD(at[17], at[69]);    MULADD(at[18], at[68]);    MULADD(at[19], at[67]);    MULADD(at[20], at[66]);    MULADD(at[21], at[65]);    MULADD(at[22], at[64]);    MULADD(at[23], at[63]);    MULADD(at[24], at[62]);    MULADD(at[25], at[61]);    MULADD(at[26], at[60]);    MULADD(at[27], at[59]);    MULADD(at[28], at[58]);    MULADD(at[29], at[57]);    MULADD(at[30], at[56]);    MULADD(at[31], at[55]);    MULADD(at[32], at[54]);    MULADD(at[33], at[53]);    MULADD(at[34], at[52]);    MULADD(at[35], at[51]);    MULADD(at[36], at[50]);    MULADD(at[37], at[49]);    MULADD(at[38], at[48]);
+   COMBA_STORE(C->dp[38]);
+   /* 39 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[87]);    MULADD(at[1], at[86]);    MULADD(at[2], at[85]);    MULADD(at[3], at[84]);    MULADD(at[4], at[83]);    MULADD(at[5], at[82]);    MULADD(at[6], at[81]);    MULADD(at[7], at[80]);    MULADD(at[8], at[79]);    MULADD(at[9], at[78]);    MULADD(at[10], at[77]);    MULADD(at[11], at[76]);    MULADD(at[12], at[75]);    MULADD(at[13], at[74]);    MULADD(at[14], at[73]);    MULADD(at[15], at[72]);    MULADD(at[16], at[71]);    MULADD(at[17], at[70]);    MULADD(at[18], at[69]);    MULADD(at[19], at[68]);    MULADD(at[20], at[67]);    MULADD(at[21], at[66]);    MULADD(at[22], at[65]);    MULADD(at[23], at[64]);    MULADD(at[24], at[63]);    MULADD(at[25], at[62]);    MULADD(at[26], at[61]);    MULADD(at[27], at[60]);    MULADD(at[28], at[59]);    MULADD(at[29], at[58]);    MULADD(at[30], at[57]);    MULADD(at[31], at[56]);    MULADD(at[32], at[55]);    MULADD(at[33], at[54]);    MULADD(at[34], at[53]);    MULADD(at[35], at[52]);    MULADD(at[36], at[51]);    MULADD(at[37], at[50]);    MULADD(at[38], at[49]);    MULADD(at[39], at[48]);
+   COMBA_STORE(C->dp[39]);
+   /* 40 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[88]);    MULADD(at[1], at[87]);    MULADD(at[2], at[86]);    MULADD(at[3], at[85]);    MULADD(at[4], at[84]);    MULADD(at[5], at[83]);    MULADD(at[6], at[82]);    MULADD(at[7], at[81]);    MULADD(at[8], at[80]);    MULADD(at[9], at[79]);    MULADD(at[10], at[78]);    MULADD(at[11], at[77]);    MULADD(at[12], at[76]);    MULADD(at[13], at[75]);    MULADD(at[14], at[74]);    MULADD(at[15], at[73]);    MULADD(at[16], at[72]);    MULADD(at[17], at[71]);    MULADD(at[18], at[70]);    MULADD(at[19], at[69]);    MULADD(at[20], at[68]);    MULADD(at[21], at[67]);    MULADD(at[22], at[66]);    MULADD(at[23], at[65]);    MULADD(at[24], at[64]);    MULADD(at[25], at[63]);    MULADD(at[26], at[62]);    MULADD(at[27], at[61]);    MULADD(at[28], at[60]);    MULADD(at[29], at[59]);    MULADD(at[30], at[58]);    MULADD(at[31], at[57]);    MULADD(at[32], at[56]);    MULADD(at[33], at[55]);    MULADD(at[34], at[54]);    MULADD(at[35], at[53]);    MULADD(at[36], at[52]);    MULADD(at[37], at[51]);    MULADD(at[38], at[50]);    MULADD(at[39], at[49]);    MULADD(at[40], at[48]);
+   COMBA_STORE(C->dp[40]);
+   /* 41 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[89]);    MULADD(at[1], at[88]);    MULADD(at[2], at[87]);    MULADD(at[3], at[86]);    MULADD(at[4], at[85]);    MULADD(at[5], at[84]);    MULADD(at[6], at[83]);    MULADD(at[7], at[82]);    MULADD(at[8], at[81]);    MULADD(at[9], at[80]);    MULADD(at[10], at[79]);    MULADD(at[11], at[78]);    MULADD(at[12], at[77]);    MULADD(at[13], at[76]);    MULADD(at[14], at[75]);    MULADD(at[15], at[74]);    MULADD(at[16], at[73]);    MULADD(at[17], at[72]);    MULADD(at[18], at[71]);    MULADD(at[19], at[70]);    MULADD(at[20], at[69]);    MULADD(at[21], at[68]);    MULADD(at[22], at[67]);    MULADD(at[23], at[66]);    MULADD(at[24], at[65]);    MULADD(at[25], at[64]);    MULADD(at[26], at[63]);    MULADD(at[27], at[62]);    MULADD(at[28], at[61]);    MULADD(at[29], at[60]);    MULADD(at[30], at[59]);    MULADD(at[31], at[58]);    MULADD(at[32], at[57]);    MULADD(at[33], at[56]);    MULADD(at[34], at[55]);    MULADD(at[35], at[54]);    MULADD(at[36], at[53]);    MULADD(at[37], at[52]);    MULADD(at[38], at[51]);    MULADD(at[39], at[50]);    MULADD(at[40], at[49]);    MULADD(at[41], at[48]);
+   COMBA_STORE(C->dp[41]);
+   /* 42 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[90]);    MULADD(at[1], at[89]);    MULADD(at[2], at[88]);    MULADD(at[3], at[87]);    MULADD(at[4], at[86]);    MULADD(at[5], at[85]);    MULADD(at[6], at[84]);    MULADD(at[7], at[83]);    MULADD(at[8], at[82]);    MULADD(at[9], at[81]);    MULADD(at[10], at[80]);    MULADD(at[11], at[79]);    MULADD(at[12], at[78]);    MULADD(at[13], at[77]);    MULADD(at[14], at[76]);    MULADD(at[15], at[75]);    MULADD(at[16], at[74]);    MULADD(at[17], at[73]);    MULADD(at[18], at[72]);    MULADD(at[19], at[71]);    MULADD(at[20], at[70]);    MULADD(at[21], at[69]);    MULADD(at[22], at[68]);    MULADD(at[23], at[67]);    MULADD(at[24], at[66]);    MULADD(at[25], at[65]);    MULADD(at[26], at[64]);    MULADD(at[27], at[63]);    MULADD(at[28], at[62]);    MULADD(at[29], at[61]);    MULADD(at[30], at[60]);    MULADD(at[31], at[59]);    MULADD(at[32], at[58]);    MULADD(at[33], at[57]);    MULADD(at[34], at[56]);    MULADD(at[35], at[55]);    MULADD(at[36], at[54]);    MULADD(at[37], at[53]);    MULADD(at[38], at[52]);    MULADD(at[39], at[51]);    MULADD(at[40], at[50]);    MULADD(at[41], at[49]);    MULADD(at[42], at[48]);
+   COMBA_STORE(C->dp[42]);
+   /* 43 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[91]);    MULADD(at[1], at[90]);    MULADD(at[2], at[89]);    MULADD(at[3], at[88]);    MULADD(at[4], at[87]);    MULADD(at[5], at[86]);    MULADD(at[6], at[85]);    MULADD(at[7], at[84]);    MULADD(at[8], at[83]);    MULADD(at[9], at[82]);    MULADD(at[10], at[81]);    MULADD(at[11], at[80]);    MULADD(at[12], at[79]);    MULADD(at[13], at[78]);    MULADD(at[14], at[77]);    MULADD(at[15], at[76]);    MULADD(at[16], at[75]);    MULADD(at[17], at[74]);    MULADD(at[18], at[73]);    MULADD(at[19], at[72]);    MULADD(at[20], at[71]);    MULADD(at[21], at[70]);    MULADD(at[22], at[69]);    MULADD(at[23], at[68]);    MULADD(at[24], at[67]);    MULADD(at[25], at[66]);    MULADD(at[26], at[65]);    MULADD(at[27], at[64]);    MULADD(at[28], at[63]);    MULADD(at[29], at[62]);    MULADD(at[30], at[61]);    MULADD(at[31], at[60]);    MULADD(at[32], at[59]);    MULADD(at[33], at[58]);    MULADD(at[34], at[57]);    MULADD(at[35], at[56]);    MULADD(at[36], at[55]);    MULADD(at[37], at[54]);    MULADD(at[38], at[53]);    MULADD(at[39], at[52]);    MULADD(at[40], at[51]);    MULADD(at[41], at[50]);    MULADD(at[42], at[49]);    MULADD(at[43], at[48]);
+   COMBA_STORE(C->dp[43]);
+   /* 44 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[92]);    MULADD(at[1], at[91]);    MULADD(at[2], at[90]);    MULADD(at[3], at[89]);    MULADD(at[4], at[88]);    MULADD(at[5], at[87]);    MULADD(at[6], at[86]);    MULADD(at[7], at[85]);    MULADD(at[8], at[84]);    MULADD(at[9], at[83]);    MULADD(at[10], at[82]);    MULADD(at[11], at[81]);    MULADD(at[12], at[80]);    MULADD(at[13], at[79]);    MULADD(at[14], at[78]);    MULADD(at[15], at[77]);    MULADD(at[16], at[76]);    MULADD(at[17], at[75]);    MULADD(at[18], at[74]);    MULADD(at[19], at[73]);    MULADD(at[20], at[72]);    MULADD(at[21], at[71]);    MULADD(at[22], at[70]);    MULADD(at[23], at[69]);    MULADD(at[24], at[68]);    MULADD(at[25], at[67]);    MULADD(at[26], at[66]);    MULADD(at[27], at[65]);    MULADD(at[28], at[64]);    MULADD(at[29], at[63]);    MULADD(at[30], at[62]);    MULADD(at[31], at[61]);    MULADD(at[32], at[60]);    MULADD(at[33], at[59]);    MULADD(at[34], at[58]);    MULADD(at[35], at[57]);    MULADD(at[36], at[56]);    MULADD(at[37], at[55]);    MULADD(at[38], at[54]);    MULADD(at[39], at[53]);    MULADD(at[40], at[52]);    MULADD(at[41], at[51]);    MULADD(at[42], at[50]);    MULADD(at[43], at[49]);    MULADD(at[44], at[48]);
+   COMBA_STORE(C->dp[44]);
+   /* 45 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[93]);    MULADD(at[1], at[92]);    MULADD(at[2], at[91]);    MULADD(at[3], at[90]);    MULADD(at[4], at[89]);    MULADD(at[5], at[88]);    MULADD(at[6], at[87]);    MULADD(at[7], at[86]);    MULADD(at[8], at[85]);    MULADD(at[9], at[84]);    MULADD(at[10], at[83]);    MULADD(at[11], at[82]);    MULADD(at[12], at[81]);    MULADD(at[13], at[80]);    MULADD(at[14], at[79]);    MULADD(at[15], at[78]);    MULADD(at[16], at[77]);    MULADD(at[17], at[76]);    MULADD(at[18], at[75]);    MULADD(at[19], at[74]);    MULADD(at[20], at[73]);    MULADD(at[21], at[72]);    MULADD(at[22], at[71]);    MULADD(at[23], at[70]);    MULADD(at[24], at[69]);    MULADD(at[25], at[68]);    MULADD(at[26], at[67]);    MULADD(at[27], at[66]);    MULADD(at[28], at[65]);    MULADD(at[29], at[64]);    MULADD(at[30], at[63]);    MULADD(at[31], at[62]);    MULADD(at[32], at[61]);    MULADD(at[33], at[60]);    MULADD(at[34], at[59]);    MULADD(at[35], at[58]);    MULADD(at[36], at[57]);    MULADD(at[37], at[56]);    MULADD(at[38], at[55]);    MULADD(at[39], at[54]);    MULADD(at[40], at[53]);    MULADD(at[41], at[52]);    MULADD(at[42], at[51]);    MULADD(at[43], at[50]);    MULADD(at[44], at[49]);    MULADD(at[45], at[48]);
+   COMBA_STORE(C->dp[45]);
+   /* 46 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[94]);    MULADD(at[1], at[93]);    MULADD(at[2], at[92]);    MULADD(at[3], at[91]);    MULADD(at[4], at[90]);    MULADD(at[5], at[89]);    MULADD(at[6], at[88]);    MULADD(at[7], at[87]);    MULADD(at[8], at[86]);    MULADD(at[9], at[85]);    MULADD(at[10], at[84]);    MULADD(at[11], at[83]);    MULADD(at[12], at[82]);    MULADD(at[13], at[81]);    MULADD(at[14], at[80]);    MULADD(at[15], at[79]);    MULADD(at[16], at[78]);    MULADD(at[17], at[77]);    MULADD(at[18], at[76]);    MULADD(at[19], at[75]);    MULADD(at[20], at[74]);    MULADD(at[21], at[73]);    MULADD(at[22], at[72]);    MULADD(at[23], at[71]);    MULADD(at[24], at[70]);    MULADD(at[25], at[69]);    MULADD(at[26], at[68]);    MULADD(at[27], at[67]);    MULADD(at[28], at[66]);    MULADD(at[29], at[65]);    MULADD(at[30], at[64]);    MULADD(at[31], at[63]);    MULADD(at[32], at[62]);    MULADD(at[33], at[61]);    MULADD(at[34], at[60]);    MULADD(at[35], at[59]);    MULADD(at[36], at[58]);    MULADD(at[37], at[57]);    MULADD(at[38], at[56]);    MULADD(at[39], at[55]);    MULADD(at[40], at[54]);    MULADD(at[41], at[53]);    MULADD(at[42], at[52]);    MULADD(at[43], at[51]);    MULADD(at[44], at[50]);    MULADD(at[45], at[49]);    MULADD(at[46], at[48]);
+   COMBA_STORE(C->dp[46]);
+   /* 47 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[95]);    MULADD(at[1], at[94]);    MULADD(at[2], at[93]);    MULADD(at[3], at[92]);    MULADD(at[4], at[91]);    MULADD(at[5], at[90]);    MULADD(at[6], at[89]);    MULADD(at[7], at[88]);    MULADD(at[8], at[87]);    MULADD(at[9], at[86]);    MULADD(at[10], at[85]);    MULADD(at[11], at[84]);    MULADD(at[12], at[83]);    MULADD(at[13], at[82]);    MULADD(at[14], at[81]);    MULADD(at[15], at[80]);    MULADD(at[16], at[79]);    MULADD(at[17], at[78]);    MULADD(at[18], at[77]);    MULADD(at[19], at[76]);    MULADD(at[20], at[75]);    MULADD(at[21], at[74]);    MULADD(at[22], at[73]);    MULADD(at[23], at[72]);    MULADD(at[24], at[71]);    MULADD(at[25], at[70]);    MULADD(at[26], at[69]);    MULADD(at[27], at[68]);    MULADD(at[28], at[67]);    MULADD(at[29], at[66]);    MULADD(at[30], at[65]);    MULADD(at[31], at[64]);    MULADD(at[32], at[63]);    MULADD(at[33], at[62]);    MULADD(at[34], at[61]);    MULADD(at[35], at[60]);    MULADD(at[36], at[59]);    MULADD(at[37], at[58]);    MULADD(at[38], at[57]);    MULADD(at[39], at[56]);    MULADD(at[40], at[55]);    MULADD(at[41], at[54]);    MULADD(at[42], at[53]);    MULADD(at[43], at[52]);    MULADD(at[44], at[51]);    MULADD(at[45], at[50]);    MULADD(at[46], at[49]);    MULADD(at[47], at[48]);
+   COMBA_STORE(C->dp[47]);
+   /* 48 */
+   COMBA_FORWARD;
+   MULADD(at[1], at[95]);    MULADD(at[2], at[94]);    MULADD(at[3], at[93]);    MULADD(at[4], at[92]);    MULADD(at[5], at[91]);    MULADD(at[6], at[90]);    MULADD(at[7], at[89]);    MULADD(at[8], at[88]);    MULADD(at[9], at[87]);    MULADD(at[10], at[86]);    MULADD(at[11], at[85]);    MULADD(at[12], at[84]);    MULADD(at[13], at[83]);    MULADD(at[14], at[82]);    MULADD(at[15], at[81]);    MULADD(at[16], at[80]);    MULADD(at[17], at[79]);    MULADD(at[18], at[78]);    MULADD(at[19], at[77]);    MULADD(at[20], at[76]);    MULADD(at[21], at[75]);    MULADD(at[22], at[74]);    MULADD(at[23], at[73]);    MULADD(at[24], at[72]);    MULADD(at[25], at[71]);    MULADD(at[26], at[70]);    MULADD(at[27], at[69]);    MULADD(at[28], at[68]);    MULADD(at[29], at[67]);    MULADD(at[30], at[66]);    MULADD(at[31], at[65]);    MULADD(at[32], at[64]);    MULADD(at[33], at[63]);    MULADD(at[34], at[62]);    MULADD(at[35], at[61]);    MULADD(at[36], at[60]);    MULADD(at[37], at[59]);    MULADD(at[38], at[58]);    MULADD(at[39], at[57]);    MULADD(at[40], at[56]);    MULADD(at[41], at[55]);    MULADD(at[42], at[54]);    MULADD(at[43], at[53]);    MULADD(at[44], at[52]);    MULADD(at[45], at[51]);    MULADD(at[46], at[50]);    MULADD(at[47], at[49]);
+   COMBA_STORE(C->dp[48]);
+   /* 49 */
+   COMBA_FORWARD;
+   MULADD(at[2], at[95]);    MULADD(at[3], at[94]);    MULADD(at[4], at[93]);    MULADD(at[5], at[92]);    MULADD(at[6], at[91]);    MULADD(at[7], at[90]);    MULADD(at[8], at[89]);    MULADD(at[9], at[88]);    MULADD(at[10], at[87]);    MULADD(at[11], at[86]);    MULADD(at[12], at[85]);    MULADD(at[13], at[84]);    MULADD(at[14], at[83]);    MULADD(at[15], at[82]);    MULADD(at[16], at[81]);    MULADD(at[17], at[80]);    MULADD(at[18], at[79]);    MULADD(at[19], at[78]);    MULADD(at[20], at[77]);    MULADD(at[21], at[76]);    MULADD(at[22], at[75]);    MULADD(at[23], at[74]);    MULADD(at[24], at[73]);    MULADD(at[25], at[72]);    MULADD(at[26], at[71]);    MULADD(at[27], at[70]);    MULADD(at[28], at[69]);    MULADD(at[29], at[68]);    MULADD(at[30], at[67]);    MULADD(at[31], at[66]);    MULADD(at[32], at[65]);    MULADD(at[33], at[64]);    MULADD(at[34], at[63]);    MULADD(at[35], at[62]);    MULADD(at[36], at[61]);    MULADD(at[37], at[60]);    MULADD(at[38], at[59]);    MULADD(at[39], at[58]);    MULADD(at[40], at[57]);    MULADD(at[41], at[56]);    MULADD(at[42], at[55]);    MULADD(at[43], at[54]);    MULADD(at[44], at[53]);    MULADD(at[45], at[52]);    MULADD(at[46], at[51]);    MULADD(at[47], at[50]);
+   COMBA_STORE(C->dp[49]);
+   /* 50 */
+   COMBA_FORWARD;
+   MULADD(at[3], at[95]);    MULADD(at[4], at[94]);    MULADD(at[5], at[93]);    MULADD(at[6], at[92]);    MULADD(at[7], at[91]);    MULADD(at[8], at[90]);    MULADD(at[9], at[89]);    MULADD(at[10], at[88]);    MULADD(at[11], at[87]);    MULADD(at[12], at[86]);    MULADD(at[13], at[85]);    MULADD(at[14], at[84]);    MULADD(at[15], at[83]);    MULADD(at[16], at[82]);    MULADD(at[17], at[81]);    MULADD(at[18], at[80]);    MULADD(at[19], at[79]);    MULADD(at[20], at[78]);    MULADD(at[21], at[77]);    MULADD(at[22], at[76]);    MULADD(at[23], at[75]);    MULADD(at[24], at[74]);    MULADD(at[25], at[73]);    MULADD(at[26], at[72]);    MULADD(at[27], at[71]);    MULADD(at[28], at[70]);    MULADD(at[29], at[69]);    MULADD(at[30], at[68]);    MULADD(at[31], at[67]);    MULADD(at[32], at[66]);    MULADD(at[33], at[65]);    MULADD(at[34], at[64]);    MULADD(at[35], at[63]);    MULADD(at[36], at[62]);    MULADD(at[37], at[61]);    MULADD(at[38], at[60]);    MULADD(at[39], at[59]);    MULADD(at[40], at[58]);    MULADD(at[41], at[57]);    MULADD(at[42], at[56]);    MULADD(at[43], at[55]);    MULADD(at[44], at[54]);    MULADD(at[45], at[53]);    MULADD(at[46], at[52]);    MULADD(at[47], at[51]);
+   COMBA_STORE(C->dp[50]);
+   /* 51 */
+   COMBA_FORWARD;
+   MULADD(at[4], at[95]);    MULADD(at[5], at[94]);    MULADD(at[6], at[93]);    MULADD(at[7], at[92]);    MULADD(at[8], at[91]);    MULADD(at[9], at[90]);    MULADD(at[10], at[89]);    MULADD(at[11], at[88]);    MULADD(at[12], at[87]);    MULADD(at[13], at[86]);    MULADD(at[14], at[85]);    MULADD(at[15], at[84]);    MULADD(at[16], at[83]);    MULADD(at[17], at[82]);    MULADD(at[18], at[81]);    MULADD(at[19], at[80]);    MULADD(at[20], at[79]);    MULADD(at[21], at[78]);    MULADD(at[22], at[77]);    MULADD(at[23], at[76]);    MULADD(at[24], at[75]);    MULADD(at[25], at[74]);    MULADD(at[26], at[73]);    MULADD(at[27], at[72]);    MULADD(at[28], at[71]);    MULADD(at[29], at[70]);    MULADD(at[30], at[69]);    MULADD(at[31], at[68]);    MULADD(at[32], at[67]);    MULADD(at[33], at[66]);    MULADD(at[34], at[65]);    MULADD(at[35], at[64]);    MULADD(at[36], at[63]);    MULADD(at[37], at[62]);    MULADD(at[38], at[61]);    MULADD(at[39], at[60]);    MULADD(at[40], at[59]);    MULADD(at[41], at[58]);    MULADD(at[42], at[57]);    MULADD(at[43], at[56]);    MULADD(at[44], at[55]);    MULADD(at[45], at[54]);    MULADD(at[46], at[53]);    MULADD(at[47], at[52]);
+   COMBA_STORE(C->dp[51]);
+   /* 52 */
+   COMBA_FORWARD;
+   MULADD(at[5], at[95]);    MULADD(at[6], at[94]);    MULADD(at[7], at[93]);    MULADD(at[8], at[92]);    MULADD(at[9], at[91]);    MULADD(at[10], at[90]);    MULADD(at[11], at[89]);    MULADD(at[12], at[88]);    MULADD(at[13], at[87]);    MULADD(at[14], at[86]);    MULADD(at[15], at[85]);    MULADD(at[16], at[84]);    MULADD(at[17], at[83]);    MULADD(at[18], at[82]);    MULADD(at[19], at[81]);    MULADD(at[20], at[80]);    MULADD(at[21], at[79]);    MULADD(at[22], at[78]);    MULADD(at[23], at[77]);    MULADD(at[24], at[76]);    MULADD(at[25], at[75]);    MULADD(at[26], at[74]);    MULADD(at[27], at[73]);    MULADD(at[28], at[72]);    MULADD(at[29], at[71]);    MULADD(at[30], at[70]);    MULADD(at[31], at[69]);    MULADD(at[32], at[68]);    MULADD(at[33], at[67]);    MULADD(at[34], at[66]);    MULADD(at[35], at[65]);    MULADD(at[36], at[64]);    MULADD(at[37], at[63]);    MULADD(at[38], at[62]);    MULADD(at[39], at[61]);    MULADD(at[40], at[60]);    MULADD(at[41], at[59]);    MULADD(at[42], at[58]);    MULADD(at[43], at[57]);    MULADD(at[44], at[56]);    MULADD(at[45], at[55]);    MULADD(at[46], at[54]);    MULADD(at[47], at[53]);
+   COMBA_STORE(C->dp[52]);
+   /* 53 */
+   COMBA_FORWARD;
+   MULADD(at[6], at[95]);    MULADD(at[7], at[94]);    MULADD(at[8], at[93]);    MULADD(at[9], at[92]);    MULADD(at[10], at[91]);    MULADD(at[11], at[90]);    MULADD(at[12], at[89]);    MULADD(at[13], at[88]);    MULADD(at[14], at[87]);    MULADD(at[15], at[86]);    MULADD(at[16], at[85]);    MULADD(at[17], at[84]);    MULADD(at[18], at[83]);    MULADD(at[19], at[82]);    MULADD(at[20], at[81]);    MULADD(at[21], at[80]);    MULADD(at[22], at[79]);    MULADD(at[23], at[78]);    MULADD(at[24], at[77]);    MULADD(at[25], at[76]);    MULADD(at[26], at[75]);    MULADD(at[27], at[74]);    MULADD(at[28], at[73]);    MULADD(at[29], at[72]);    MULADD(at[30], at[71]);    MULADD(at[31], at[70]);    MULADD(at[32], at[69]);    MULADD(at[33], at[68]);    MULADD(at[34], at[67]);    MULADD(at[35], at[66]);    MULADD(at[36], at[65]);    MULADD(at[37], at[64]);    MULADD(at[38], at[63]);    MULADD(at[39], at[62]);    MULADD(at[40], at[61]);    MULADD(at[41], at[60]);    MULADD(at[42], at[59]);    MULADD(at[43], at[58]);    MULADD(at[44], at[57]);    MULADD(at[45], at[56]);    MULADD(at[46], at[55]);    MULADD(at[47], at[54]);
+   COMBA_STORE(C->dp[53]);
+   /* 54 */
+   COMBA_FORWARD;
+   MULADD(at[7], at[95]);    MULADD(at[8], at[94]);    MULADD(at[9], at[93]);    MULADD(at[10], at[92]);    MULADD(at[11], at[91]);    MULADD(at[12], at[90]);    MULADD(at[13], at[89]);    MULADD(at[14], at[88]);    MULADD(at[15], at[87]);    MULADD(at[16], at[86]);    MULADD(at[17], at[85]);    MULADD(at[18], at[84]);    MULADD(at[19], at[83]);    MULADD(at[20], at[82]);    MULADD(at[21], at[81]);    MULADD(at[22], at[80]);    MULADD(at[23], at[79]);    MULADD(at[24], at[78]);    MULADD(at[25], at[77]);    MULADD(at[26], at[76]);    MULADD(at[27], at[75]);    MULADD(at[28], at[74]);    MULADD(at[29], at[73]);    MULADD(at[30], at[72]);    MULADD(at[31], at[71]);    MULADD(at[32], at[70]);    MULADD(at[33], at[69]);    MULADD(at[34], at[68]);    MULADD(at[35], at[67]);    MULADD(at[36], at[66]);    MULADD(at[37], at[65]);    MULADD(at[38], at[64]);    MULADD(at[39], at[63]);    MULADD(at[40], at[62]);    MULADD(at[41], at[61]);    MULADD(at[42], at[60]);    MULADD(at[43], at[59]);    MULADD(at[44], at[58]);    MULADD(at[45], at[57]);    MULADD(at[46], at[56]);    MULADD(at[47], at[55]);
+   COMBA_STORE(C->dp[54]);
+   /* 55 */
+   COMBA_FORWARD;
+   MULADD(at[8], at[95]);    MULADD(at[9], at[94]);    MULADD(at[10], at[93]);    MULADD(at[11], at[92]);    MULADD(at[12], at[91]);    MULADD(at[13], at[90]);    MULADD(at[14], at[89]);    MULADD(at[15], at[88]);    MULADD(at[16], at[87]);    MULADD(at[17], at[86]);    MULADD(at[18], at[85]);    MULADD(at[19], at[84]);    MULADD(at[20], at[83]);    MULADD(at[21], at[82]);    MULADD(at[22], at[81]);    MULADD(at[23], at[80]);    MULADD(at[24], at[79]);    MULADD(at[25], at[78]);    MULADD(at[26], at[77]);    MULADD(at[27], at[76]);    MULADD(at[28], at[75]);    MULADD(at[29], at[74]);    MULADD(at[30], at[73]);    MULADD(at[31], at[72]);    MULADD(at[32], at[71]);    MULADD(at[33], at[70]);    MULADD(at[34], at[69]);    MULADD(at[35], at[68]);    MULADD(at[36], at[67]);    MULADD(at[37], at[66]);    MULADD(at[38], at[65]);    MULADD(at[39], at[64]);    MULADD(at[40], at[63]);    MULADD(at[41], at[62]);    MULADD(at[42], at[61]);    MULADD(at[43], at[60]);    MULADD(at[44], at[59]);    MULADD(at[45], at[58]);    MULADD(at[46], at[57]);    MULADD(at[47], at[56]);
+   COMBA_STORE(C->dp[55]);
+   /* 56 */
+   COMBA_FORWARD;
+   MULADD(at[9], at[95]);    MULADD(at[10], at[94]);    MULADD(at[11], at[93]);    MULADD(at[12], at[92]);    MULADD(at[13], at[91]);    MULADD(at[14], at[90]);    MULADD(at[15], at[89]);    MULADD(at[16], at[88]);    MULADD(at[17], at[87]);    MULADD(at[18], at[86]);    MULADD(at[19], at[85]);    MULADD(at[20], at[84]);    MULADD(at[21], at[83]);    MULADD(at[22], at[82]);    MULADD(at[23], at[81]);    MULADD(at[24], at[80]);    MULADD(at[25], at[79]);    MULADD(at[26], at[78]);    MULADD(at[27], at[77]);    MULADD(at[28], at[76]);    MULADD(at[29], at[75]);    MULADD(at[30], at[74]);    MULADD(at[31], at[73]);    MULADD(at[32], at[72]);    MULADD(at[33], at[71]);    MULADD(at[34], at[70]);    MULADD(at[35], at[69]);    MULADD(at[36], at[68]);    MULADD(at[37], at[67]);    MULADD(at[38], at[66]);    MULADD(at[39], at[65]);    MULADD(at[40], at[64]);    MULADD(at[41], at[63]);    MULADD(at[42], at[62]);    MULADD(at[43], at[61]);    MULADD(at[44], at[60]);    MULADD(at[45], at[59]);    MULADD(at[46], at[58]);    MULADD(at[47], at[57]);
+   COMBA_STORE(C->dp[56]);
+   /* 57 */
+   COMBA_FORWARD;
+   MULADD(at[10], at[95]);    MULADD(at[11], at[94]);    MULADD(at[12], at[93]);    MULADD(at[13], at[92]);    MULADD(at[14], at[91]);    MULADD(at[15], at[90]);    MULADD(at[16], at[89]);    MULADD(at[17], at[88]);    MULADD(at[18], at[87]);    MULADD(at[19], at[86]);    MULADD(at[20], at[85]);    MULADD(at[21], at[84]);    MULADD(at[22], at[83]);    MULADD(at[23], at[82]);    MULADD(at[24], at[81]);    MULADD(at[25], at[80]);    MULADD(at[26], at[79]);    MULADD(at[27], at[78]);    MULADD(at[28], at[77]);    MULADD(at[29], at[76]);    MULADD(at[30], at[75]);    MULADD(at[31], at[74]);    MULADD(at[32], at[73]);    MULADD(at[33], at[72]);    MULADD(at[34], at[71]);    MULADD(at[35], at[70]);    MULADD(at[36], at[69]);    MULADD(at[37], at[68]);    MULADD(at[38], at[67]);    MULADD(at[39], at[66]);    MULADD(at[40], at[65]);    MULADD(at[41], at[64]);    MULADD(at[42], at[63]);    MULADD(at[43], at[62]);    MULADD(at[44], at[61]);    MULADD(at[45], at[60]);    MULADD(at[46], at[59]);    MULADD(at[47], at[58]);
+   COMBA_STORE(C->dp[57]);
+   /* 58 */
+   COMBA_FORWARD;
+   MULADD(at[11], at[95]);    MULADD(at[12], at[94]);    MULADD(at[13], at[93]);    MULADD(at[14], at[92]);    MULADD(at[15], at[91]);    MULADD(at[16], at[90]);    MULADD(at[17], at[89]);    MULADD(at[18], at[88]);    MULADD(at[19], at[87]);    MULADD(at[20], at[86]);    MULADD(at[21], at[85]);    MULADD(at[22], at[84]);    MULADD(at[23], at[83]);    MULADD(at[24], at[82]);    MULADD(at[25], at[81]);    MULADD(at[26], at[80]);    MULADD(at[27], at[79]);    MULADD(at[28], at[78]);    MULADD(at[29], at[77]);    MULADD(at[30], at[76]);    MULADD(at[31], at[75]);    MULADD(at[32], at[74]);    MULADD(at[33], at[73]);    MULADD(at[34], at[72]);    MULADD(at[35], at[71]);    MULADD(at[36], at[70]);    MULADD(at[37], at[69]);    MULADD(at[38], at[68]);    MULADD(at[39], at[67]);    MULADD(at[40], at[66]);    MULADD(at[41], at[65]);    MULADD(at[42], at[64]);    MULADD(at[43], at[63]);    MULADD(at[44], at[62]);    MULADD(at[45], at[61]);    MULADD(at[46], at[60]);    MULADD(at[47], at[59]);
+   COMBA_STORE(C->dp[58]);
+   /* 59 */
+   COMBA_FORWARD;
+   MULADD(at[12], at[95]);    MULADD(at[13], at[94]);    MULADD(at[14], at[93]);    MULADD(at[15], at[92]);    MULADD(at[16], at[91]);    MULADD(at[17], at[90]);    MULADD(at[18], at[89]);    MULADD(at[19], at[88]);    MULADD(at[20], at[87]);    MULADD(at[21], at[86]);    MULADD(at[22], at[85]);    MULADD(at[23], at[84]);    MULADD(at[24], at[83]);    MULADD(at[25], at[82]);    MULADD(at[26], at[81]);    MULADD(at[27], at[80]);    MULADD(at[28], at[79]);    MULADD(at[29], at[78]);    MULADD(at[30], at[77]);    MULADD(at[31], at[76]);    MULADD(at[32], at[75]);    MULADD(at[33], at[74]);    MULADD(at[34], at[73]);    MULADD(at[35], at[72]);    MULADD(at[36], at[71]);    MULADD(at[37], at[70]);    MULADD(at[38], at[69]);    MULADD(at[39], at[68]);    MULADD(at[40], at[67]);    MULADD(at[41], at[66]);    MULADD(at[42], at[65]);    MULADD(at[43], at[64]);    MULADD(at[44], at[63]);    MULADD(at[45], at[62]);    MULADD(at[46], at[61]);    MULADD(at[47], at[60]);
+   COMBA_STORE(C->dp[59]);
+   /* 60 */
+   COMBA_FORWARD;
+   MULADD(at[13], at[95]);    MULADD(at[14], at[94]);    MULADD(at[15], at[93]);    MULADD(at[16], at[92]);    MULADD(at[17], at[91]);    MULADD(at[18], at[90]);    MULADD(at[19], at[89]);    MULADD(at[20], at[88]);    MULADD(at[21], at[87]);    MULADD(at[22], at[86]);    MULADD(at[23], at[85]);    MULADD(at[24], at[84]);    MULADD(at[25], at[83]);    MULADD(at[26], at[82]);    MULADD(at[27], at[81]);    MULADD(at[28], at[80]);    MULADD(at[29], at[79]);    MULADD(at[30], at[78]);    MULADD(at[31], at[77]);    MULADD(at[32], at[76]);    MULADD(at[33], at[75]);    MULADD(at[34], at[74]);    MULADD(at[35], at[73]);    MULADD(at[36], at[72]);    MULADD(at[37], at[71]);    MULADD(at[38], at[70]);    MULADD(at[39], at[69]);    MULADD(at[40], at[68]);    MULADD(at[41], at[67]);    MULADD(at[42], at[66]);    MULADD(at[43], at[65]);    MULADD(at[44], at[64]);    MULADD(at[45], at[63]);    MULADD(at[46], at[62]);    MULADD(at[47], at[61]);
+   COMBA_STORE(C->dp[60]);
+   /* 61 */
+   COMBA_FORWARD;
+   MULADD(at[14], at[95]);    MULADD(at[15], at[94]);    MULADD(at[16], at[93]);    MULADD(at[17], at[92]);    MULADD(at[18], at[91]);    MULADD(at[19], at[90]);    MULADD(at[20], at[89]);    MULADD(at[21], at[88]);    MULADD(at[22], at[87]);    MULADD(at[23], at[86]);    MULADD(at[24], at[85]);    MULADD(at[25], at[84]);    MULADD(at[26], at[83]);    MULADD(at[27], at[82]);    MULADD(at[28], at[81]);    MULADD(at[29], at[80]);    MULADD(at[30], at[79]);    MULADD(at[31], at[78]);    MULADD(at[32], at[77]);    MULADD(at[33], at[76]);    MULADD(at[34], at[75]);    MULADD(at[35], at[74]);    MULADD(at[36], at[73]);    MULADD(at[37], at[72]);    MULADD(at[38], at[71]);    MULADD(at[39], at[70]);    MULADD(at[40], at[69]);    MULADD(at[41], at[68]);    MULADD(at[42], at[67]);    MULADD(at[43], at[66]);    MULADD(at[44], at[65]);    MULADD(at[45], at[64]);    MULADD(at[46], at[63]);    MULADD(at[47], at[62]);
+   COMBA_STORE(C->dp[61]);
+   /* 62 */
+   COMBA_FORWARD;
+   MULADD(at[15], at[95]);    MULADD(at[16], at[94]);    MULADD(at[17], at[93]);    MULADD(at[18], at[92]);    MULADD(at[19], at[91]);    MULADD(at[20], at[90]);    MULADD(at[21], at[89]);    MULADD(at[22], at[88]);    MULADD(at[23], at[87]);    MULADD(at[24], at[86]);    MULADD(at[25], at[85]);    MULADD(at[26], at[84]);    MULADD(at[27], at[83]);    MULADD(at[28], at[82]);    MULADD(at[29], at[81]);    MULADD(at[30], at[80]);    MULADD(at[31], at[79]);    MULADD(at[32], at[78]);    MULADD(at[33], at[77]);    MULADD(at[34], at[76]);    MULADD(at[35], at[75]);    MULADD(at[36], at[74]);    MULADD(at[37], at[73]);    MULADD(at[38], at[72]);    MULADD(at[39], at[71]);    MULADD(at[40], at[70]);    MULADD(at[41], at[69]);    MULADD(at[42], at[68]);    MULADD(at[43], at[67]);    MULADD(at[44], at[66]);    MULADD(at[45], at[65]);    MULADD(at[46], at[64]);    MULADD(at[47], at[63]);
+   COMBA_STORE(C->dp[62]);
+   /* 63 */
+   COMBA_FORWARD;
+   MULADD(at[16], at[95]);    MULADD(at[17], at[94]);    MULADD(at[18], at[93]);    MULADD(at[19], at[92]);    MULADD(at[20], at[91]);    MULADD(at[21], at[90]);    MULADD(at[22], at[89]);    MULADD(at[23], at[88]);    MULADD(at[24], at[87]);    MULADD(at[25], at[86]);    MULADD(at[26], at[85]);    MULADD(at[27], at[84]);    MULADD(at[28], at[83]);    MULADD(at[29], at[82]);    MULADD(at[30], at[81]);    MULADD(at[31], at[80]);    MULADD(at[32], at[79]);    MULADD(at[33], at[78]);    MULADD(at[34], at[77]);    MULADD(at[35], at[76]);    MULADD(at[36], at[75]);    MULADD(at[37], at[74]);    MULADD(at[38], at[73]);    MULADD(at[39], at[72]);    MULADD(at[40], at[71]);    MULADD(at[41], at[70]);    MULADD(at[42], at[69]);    MULADD(at[43], at[68]);    MULADD(at[44], at[67]);    MULADD(at[45], at[66]);    MULADD(at[46], at[65]);    MULADD(at[47], at[64]);
+   COMBA_STORE(C->dp[63]);
+   /* 64 */
+   COMBA_FORWARD;
+   MULADD(at[17], at[95]);    MULADD(at[18], at[94]);    MULADD(at[19], at[93]);    MULADD(at[20], at[92]);    MULADD(at[21], at[91]);    MULADD(at[22], at[90]);    MULADD(at[23], at[89]);    MULADD(at[24], at[88]);    MULADD(at[25], at[87]);    MULADD(at[26], at[86]);    MULADD(at[27], at[85]);    MULADD(at[28], at[84]);    MULADD(at[29], at[83]);    MULADD(at[30], at[82]);    MULADD(at[31], at[81]);    MULADD(at[32], at[80]);    MULADD(at[33], at[79]);    MULADD(at[34], at[78]);    MULADD(at[35], at[77]);    MULADD(at[36], at[76]);    MULADD(at[37], at[75]);    MULADD(at[38], at[74]);    MULADD(at[39], at[73]);    MULADD(at[40], at[72]);    MULADD(at[41], at[71]);    MULADD(at[42], at[70]);    MULADD(at[43], at[69]);    MULADD(at[44], at[68]);    MULADD(at[45], at[67]);    MULADD(at[46], at[66]);    MULADD(at[47], at[65]);
+   COMBA_STORE(C->dp[64]);
+   /* 65 */
+   COMBA_FORWARD;
+   MULADD(at[18], at[95]);    MULADD(at[19], at[94]);    MULADD(at[20], at[93]);    MULADD(at[21], at[92]);    MULADD(at[22], at[91]);    MULADD(at[23], at[90]);    MULADD(at[24], at[89]);    MULADD(at[25], at[88]);    MULADD(at[26], at[87]);    MULADD(at[27], at[86]);    MULADD(at[28], at[85]);    MULADD(at[29], at[84]);    MULADD(at[30], at[83]);    MULADD(at[31], at[82]);    MULADD(at[32], at[81]);    MULADD(at[33], at[80]);    MULADD(at[34], at[79]);    MULADD(at[35], at[78]);    MULADD(at[36], at[77]);    MULADD(at[37], at[76]);    MULADD(at[38], at[75]);    MULADD(at[39], at[74]);    MULADD(at[40], at[73]);    MULADD(at[41], at[72]);    MULADD(at[42], at[71]);    MULADD(at[43], at[70]);    MULADD(at[44], at[69]);    MULADD(at[45], at[68]);    MULADD(at[46], at[67]);    MULADD(at[47], at[66]);
+   COMBA_STORE(C->dp[65]);
+   /* 66 */
+   COMBA_FORWARD;
+   MULADD(at[19], at[95]);    MULADD(at[20], at[94]);    MULADD(at[21], at[93]);    MULADD(at[22], at[92]);    MULADD(at[23], at[91]);    MULADD(at[24], at[90]);    MULADD(at[25], at[89]);    MULADD(at[26], at[88]);    MULADD(at[27], at[87]);    MULADD(at[28], at[86]);    MULADD(at[29], at[85]);    MULADD(at[30], at[84]);    MULADD(at[31], at[83]);    MULADD(at[32], at[82]);    MULADD(at[33], at[81]);    MULADD(at[34], at[80]);    MULADD(at[35], at[79]);    MULADD(at[36], at[78]);    MULADD(at[37], at[77]);    MULADD(at[38], at[76]);    MULADD(at[39], at[75]);    MULADD(at[40], at[74]);    MULADD(at[41], at[73]);    MULADD(at[42], at[72]);    MULADD(at[43], at[71]);    MULADD(at[44], at[70]);    MULADD(at[45], at[69]);    MULADD(at[46], at[68]);    MULADD(at[47], at[67]);
+   COMBA_STORE(C->dp[66]);
+   /* 67 */
+   COMBA_FORWARD;
+   MULADD(at[20], at[95]);    MULADD(at[21], at[94]);    MULADD(at[22], at[93]);    MULADD(at[23], at[92]);    MULADD(at[24], at[91]);    MULADD(at[25], at[90]);    MULADD(at[26], at[89]);    MULADD(at[27], at[88]);    MULADD(at[28], at[87]);    MULADD(at[29], at[86]);    MULADD(at[30], at[85]);    MULADD(at[31], at[84]);    MULADD(at[32], at[83]);    MULADD(at[33], at[82]);    MULADD(at[34], at[81]);    MULADD(at[35], at[80]);    MULADD(at[36], at[79]);    MULADD(at[37], at[78]);    MULADD(at[38], at[77]);    MULADD(at[39], at[76]);    MULADD(at[40], at[75]);    MULADD(at[41], at[74]);    MULADD(at[42], at[73]);    MULADD(at[43], at[72]);    MULADD(at[44], at[71]);    MULADD(at[45], at[70]);    MULADD(at[46], at[69]);    MULADD(at[47], at[68]);
+   COMBA_STORE(C->dp[67]);
+   /* 68 */
+   COMBA_FORWARD;
+   MULADD(at[21], at[95]);    MULADD(at[22], at[94]);    MULADD(at[23], at[93]);    MULADD(at[24], at[92]);    MULADD(at[25], at[91]);    MULADD(at[26], at[90]);    MULADD(at[27], at[89]);    MULADD(at[28], at[88]);    MULADD(at[29], at[87]);    MULADD(at[30], at[86]);    MULADD(at[31], at[85]);    MULADD(at[32], at[84]);    MULADD(at[33], at[83]);    MULADD(at[34], at[82]);    MULADD(at[35], at[81]);    MULADD(at[36], at[80]);    MULADD(at[37], at[79]);    MULADD(at[38], at[78]);    MULADD(at[39], at[77]);    MULADD(at[40], at[76]);    MULADD(at[41], at[75]);    MULADD(at[42], at[74]);    MULADD(at[43], at[73]);    MULADD(at[44], at[72]);    MULADD(at[45], at[71]);    MULADD(at[46], at[70]);    MULADD(at[47], at[69]);
+   COMBA_STORE(C->dp[68]);
+   /* 69 */
+   COMBA_FORWARD;
+   MULADD(at[22], at[95]);    MULADD(at[23], at[94]);    MULADD(at[24], at[93]);    MULADD(at[25], at[92]);    MULADD(at[26], at[91]);    MULADD(at[27], at[90]);    MULADD(at[28], at[89]);    MULADD(at[29], at[88]);    MULADD(at[30], at[87]);    MULADD(at[31], at[86]);    MULADD(at[32], at[85]);    MULADD(at[33], at[84]);    MULADD(at[34], at[83]);    MULADD(at[35], at[82]);    MULADD(at[36], at[81]);    MULADD(at[37], at[80]);    MULADD(at[38], at[79]);    MULADD(at[39], at[78]);    MULADD(at[40], at[77]);    MULADD(at[41], at[76]);    MULADD(at[42], at[75]);    MULADD(at[43], at[74]);    MULADD(at[44], at[73]);    MULADD(at[45], at[72]);    MULADD(at[46], at[71]);    MULADD(at[47], at[70]);
+   COMBA_STORE(C->dp[69]);
+   /* 70 */
+   COMBA_FORWARD;
+   MULADD(at[23], at[95]);    MULADD(at[24], at[94]);    MULADD(at[25], at[93]);    MULADD(at[26], at[92]);    MULADD(at[27], at[91]);    MULADD(at[28], at[90]);    MULADD(at[29], at[89]);    MULADD(at[30], at[88]);    MULADD(at[31], at[87]);    MULADD(at[32], at[86]);    MULADD(at[33], at[85]);    MULADD(at[34], at[84]);    MULADD(at[35], at[83]);    MULADD(at[36], at[82]);    MULADD(at[37], at[81]);    MULADD(at[38], at[80]);    MULADD(at[39], at[79]);    MULADD(at[40], at[78]);    MULADD(at[41], at[77]);    MULADD(at[42], at[76]);    MULADD(at[43], at[75]);    MULADD(at[44], at[74]);    MULADD(at[45], at[73]);    MULADD(at[46], at[72]);    MULADD(at[47], at[71]);
+   COMBA_STORE(C->dp[70]);
+   /* 71 */
+   COMBA_FORWARD;
+   MULADD(at[24], at[95]);    MULADD(at[25], at[94]);    MULADD(at[26], at[93]);    MULADD(at[27], at[92]);    MULADD(at[28], at[91]);    MULADD(at[29], at[90]);    MULADD(at[30], at[89]);    MULADD(at[31], at[88]);    MULADD(at[32], at[87]);    MULADD(at[33], at[86]);    MULADD(at[34], at[85]);    MULADD(at[35], at[84]);    MULADD(at[36], at[83]);    MULADD(at[37], at[82]);    MULADD(at[38], at[81]);    MULADD(at[39], at[80]);    MULADD(at[40], at[79]);    MULADD(at[41], at[78]);    MULADD(at[42], at[77]);    MULADD(at[43], at[76]);    MULADD(at[44], at[75]);    MULADD(at[45], at[74]);    MULADD(at[46], at[73]);    MULADD(at[47], at[72]);
+   COMBA_STORE(C->dp[71]);
+   /* 72 */
+   COMBA_FORWARD;
+   MULADD(at[25], at[95]);    MULADD(at[26], at[94]);    MULADD(at[27], at[93]);    MULADD(at[28], at[92]);    MULADD(at[29], at[91]);    MULADD(at[30], at[90]);    MULADD(at[31], at[89]);    MULADD(at[32], at[88]);    MULADD(at[33], at[87]);    MULADD(at[34], at[86]);    MULADD(at[35], at[85]);    MULADD(at[36], at[84]);    MULADD(at[37], at[83]);    MULADD(at[38], at[82]);    MULADD(at[39], at[81]);    MULADD(at[40], at[80]);    MULADD(at[41], at[79]);    MULADD(at[42], at[78]);    MULADD(at[43], at[77]);    MULADD(at[44], at[76]);    MULADD(at[45], at[75]);    MULADD(at[46], at[74]);    MULADD(at[47], at[73]);
+   COMBA_STORE(C->dp[72]);
+   /* 73 */
+   COMBA_FORWARD;
+   MULADD(at[26], at[95]);    MULADD(at[27], at[94]);    MULADD(at[28], at[93]);    MULADD(at[29], at[92]);    MULADD(at[30], at[91]);    MULADD(at[31], at[90]);    MULADD(at[32], at[89]);    MULADD(at[33], at[88]);    MULADD(at[34], at[87]);    MULADD(at[35], at[86]);    MULADD(at[36], at[85]);    MULADD(at[37], at[84]);    MULADD(at[38], at[83]);    MULADD(at[39], at[82]);    MULADD(at[40], at[81]);    MULADD(at[41], at[80]);    MULADD(at[42], at[79]);    MULADD(at[43], at[78]);    MULADD(at[44], at[77]);    MULADD(at[45], at[76]);    MULADD(at[46], at[75]);    MULADD(at[47], at[74]);
+   COMBA_STORE(C->dp[73]);
+   /* 74 */
+   COMBA_FORWARD;
+   MULADD(at[27], at[95]);    MULADD(at[28], at[94]);    MULADD(at[29], at[93]);    MULADD(at[30], at[92]);    MULADD(at[31], at[91]);    MULADD(at[32], at[90]);    MULADD(at[33], at[89]);    MULADD(at[34], at[88]);    MULADD(at[35], at[87]);    MULADD(at[36], at[86]);    MULADD(at[37], at[85]);    MULADD(at[38], at[84]);    MULADD(at[39], at[83]);    MULADD(at[40], at[82]);    MULADD(at[41], at[81]);    MULADD(at[42], at[80]);    MULADD(at[43], at[79]);    MULADD(at[44], at[78]);    MULADD(at[45], at[77]);    MULADD(at[46], at[76]);    MULADD(at[47], at[75]);
+   COMBA_STORE(C->dp[74]);
+   /* 75 */
+   COMBA_FORWARD;
+   MULADD(at[28], at[95]);    MULADD(at[29], at[94]);    MULADD(at[30], at[93]);    MULADD(at[31], at[92]);    MULADD(at[32], at[91]);    MULADD(at[33], at[90]);    MULADD(at[34], at[89]);    MULADD(at[35], at[88]);    MULADD(at[36], at[87]);    MULADD(at[37], at[86]);    MULADD(at[38], at[85]);    MULADD(at[39], at[84]);    MULADD(at[40], at[83]);    MULADD(at[41], at[82]);    MULADD(at[42], at[81]);    MULADD(at[43], at[80]);    MULADD(at[44], at[79]);    MULADD(at[45], at[78]);    MULADD(at[46], at[77]);    MULADD(at[47], at[76]);
+   COMBA_STORE(C->dp[75]);
+   /* 76 */
+   COMBA_FORWARD;
+   MULADD(at[29], at[95]);    MULADD(at[30], at[94]);    MULADD(at[31], at[93]);    MULADD(at[32], at[92]);    MULADD(at[33], at[91]);    MULADD(at[34], at[90]);    MULADD(at[35], at[89]);    MULADD(at[36], at[88]);    MULADD(at[37], at[87]);    MULADD(at[38], at[86]);    MULADD(at[39], at[85]);    MULADD(at[40], at[84]);    MULADD(at[41], at[83]);    MULADD(at[42], at[82]);    MULADD(at[43], at[81]);    MULADD(at[44], at[80]);    MULADD(at[45], at[79]);    MULADD(at[46], at[78]);    MULADD(at[47], at[77]);
+   COMBA_STORE(C->dp[76]);
+   /* 77 */
+   COMBA_FORWARD;
+   MULADD(at[30], at[95]);    MULADD(at[31], at[94]);    MULADD(at[32], at[93]);    MULADD(at[33], at[92]);    MULADD(at[34], at[91]);    MULADD(at[35], at[90]);    MULADD(at[36], at[89]);    MULADD(at[37], at[88]);    MULADD(at[38], at[87]);    MULADD(at[39], at[86]);    MULADD(at[40], at[85]);    MULADD(at[41], at[84]);    MULADD(at[42], at[83]);    MULADD(at[43], at[82]);    MULADD(at[44], at[81]);    MULADD(at[45], at[80]);    MULADD(at[46], at[79]);    MULADD(at[47], at[78]);
+   COMBA_STORE(C->dp[77]);
+   /* 78 */
+   COMBA_FORWARD;
+   MULADD(at[31], at[95]);    MULADD(at[32], at[94]);    MULADD(at[33], at[93]);    MULADD(at[34], at[92]);    MULADD(at[35], at[91]);    MULADD(at[36], at[90]);    MULADD(at[37], at[89]);    MULADD(at[38], at[88]);    MULADD(at[39], at[87]);    MULADD(at[40], at[86]);    MULADD(at[41], at[85]);    MULADD(at[42], at[84]);    MULADD(at[43], at[83]);    MULADD(at[44], at[82]);    MULADD(at[45], at[81]);    MULADD(at[46], at[80]);    MULADD(at[47], at[79]);
+   COMBA_STORE(C->dp[78]);
+   /* 79 */
+   COMBA_FORWARD;
+   MULADD(at[32], at[95]);    MULADD(at[33], at[94]);    MULADD(at[34], at[93]);    MULADD(at[35], at[92]);    MULADD(at[36], at[91]);    MULADD(at[37], at[90]);    MULADD(at[38], at[89]);    MULADD(at[39], at[88]);    MULADD(at[40], at[87]);    MULADD(at[41], at[86]);    MULADD(at[42], at[85]);    MULADD(at[43], at[84]);    MULADD(at[44], at[83]);    MULADD(at[45], at[82]);    MULADD(at[46], at[81]);    MULADD(at[47], at[80]);
+   COMBA_STORE(C->dp[79]);
+   /* 80 */
+   COMBA_FORWARD;
+   MULADD(at[33], at[95]);    MULADD(at[34], at[94]);    MULADD(at[35], at[93]);    MULADD(at[36], at[92]);    MULADD(at[37], at[91]);    MULADD(at[38], at[90]);    MULADD(at[39], at[89]);    MULADD(at[40], at[88]);    MULADD(at[41], at[87]);    MULADD(at[42], at[86]);    MULADD(at[43], at[85]);    MULADD(at[44], at[84]);    MULADD(at[45], at[83]);    MULADD(at[46], at[82]);    MULADD(at[47], at[81]);
+   COMBA_STORE(C->dp[80]);
+   /* 81 */
+   COMBA_FORWARD;
+   MULADD(at[34], at[95]);    MULADD(at[35], at[94]);    MULADD(at[36], at[93]);    MULADD(at[37], at[92]);    MULADD(at[38], at[91]);    MULADD(at[39], at[90]);    MULADD(at[40], at[89]);    MULADD(at[41], at[88]);    MULADD(at[42], at[87]);    MULADD(at[43], at[86]);    MULADD(at[44], at[85]);    MULADD(at[45], at[84]);    MULADD(at[46], at[83]);    MULADD(at[47], at[82]);
+   COMBA_STORE(C->dp[81]);
+   /* 82 */
+   COMBA_FORWARD;
+   MULADD(at[35], at[95]);    MULADD(at[36], at[94]);    MULADD(at[37], at[93]);    MULADD(at[38], at[92]);    MULADD(at[39], at[91]);    MULADD(at[40], at[90]);    MULADD(at[41], at[89]);    MULADD(at[42], at[88]);    MULADD(at[43], at[87]);    MULADD(at[44], at[86]);    MULADD(at[45], at[85]);    MULADD(at[46], at[84]);    MULADD(at[47], at[83]);
+   COMBA_STORE(C->dp[82]);
+   /* 83 */
+   COMBA_FORWARD;
+   MULADD(at[36], at[95]);    MULADD(at[37], at[94]);    MULADD(at[38], at[93]);    MULADD(at[39], at[92]);    MULADD(at[40], at[91]);    MULADD(at[41], at[90]);    MULADD(at[42], at[89]);    MULADD(at[43], at[88]);    MULADD(at[44], at[87]);    MULADD(at[45], at[86]);    MULADD(at[46], at[85]);    MULADD(at[47], at[84]);
+   COMBA_STORE(C->dp[83]);
+   /* 84 */
+   COMBA_FORWARD;
+   MULADD(at[37], at[95]);    MULADD(at[38], at[94]);    MULADD(at[39], at[93]);    MULADD(at[40], at[92]);    MULADD(at[41], at[91]);    MULADD(at[42], at[90]);    MULADD(at[43], at[89]);    MULADD(at[44], at[88]);    MULADD(at[45], at[87]);    MULADD(at[46], at[86]);    MULADD(at[47], at[85]);
+   COMBA_STORE(C->dp[84]);
+   /* 85 */
+   COMBA_FORWARD;
+   MULADD(at[38], at[95]);    MULADD(at[39], at[94]);    MULADD(at[40], at[93]);    MULADD(at[41], at[92]);    MULADD(at[42], at[91]);    MULADD(at[43], at[90]);    MULADD(at[44], at[89]);    MULADD(at[45], at[88]);    MULADD(at[46], at[87]);    MULADD(at[47], at[86]);
+   COMBA_STORE(C->dp[85]);
+   /* 86 */
+   COMBA_FORWARD;
+   MULADD(at[39], at[95]);    MULADD(at[40], at[94]);    MULADD(at[41], at[93]);    MULADD(at[42], at[92]);    MULADD(at[43], at[91]);    MULADD(at[44], at[90]);    MULADD(at[45], at[89]);    MULADD(at[46], at[88]);    MULADD(at[47], at[87]);
+   COMBA_STORE(C->dp[86]);
+   /* 87 */
+   COMBA_FORWARD;
+   MULADD(at[40], at[95]);    MULADD(at[41], at[94]);    MULADD(at[42], at[93]);    MULADD(at[43], at[92]);    MULADD(at[44], at[91]);    MULADD(at[45], at[90]);    MULADD(at[46], at[89]);    MULADD(at[47], at[88]);
+   COMBA_STORE(C->dp[87]);
+   /* 88 */
+   COMBA_FORWARD;
+   MULADD(at[41], at[95]);    MULADD(at[42], at[94]);    MULADD(at[43], at[93]);    MULADD(at[44], at[92]);    MULADD(at[45], at[91]);    MULADD(at[46], at[90]);    MULADD(at[47], at[89]);
+   COMBA_STORE(C->dp[88]);
+   /* 89 */
+   COMBA_FORWARD;
+   MULADD(at[42], at[95]);    MULADD(at[43], at[94]);    MULADD(at[44], at[93]);    MULADD(at[45], at[92]);    MULADD(at[46], at[91]);    MULADD(at[47], at[90]);
+   COMBA_STORE(C->dp[89]);
+   /* 90 */
+   COMBA_FORWARD;
+   MULADD(at[43], at[95]);    MULADD(at[44], at[94]);    MULADD(at[45], at[93]);    MULADD(at[46], at[92]);    MULADD(at[47], at[91]);
+   COMBA_STORE(C->dp[90]);
+   /* 91 */
+   COMBA_FORWARD;
+   MULADD(at[44], at[95]);    MULADD(at[45], at[94]);    MULADD(at[46], at[93]);    MULADD(at[47], at[92]);
+   COMBA_STORE(C->dp[91]);
+   /* 92 */
+   COMBA_FORWARD;
+   MULADD(at[45], at[95]);    MULADD(at[46], at[94]);    MULADD(at[47], at[93]);
+   COMBA_STORE(C->dp[92]);
+   /* 93 */
+   COMBA_FORWARD;
+   MULADD(at[46], at[95]);    MULADD(at[47], at[94]);
+   COMBA_STORE(C->dp[93]);
+   /* 94 */
+   COMBA_FORWARD;
+   MULADD(at[47], at[95]);
+   COMBA_STORE(C->dp[94]);
+   COMBA_STORE2(C->dp[95]);
+   C->used = 96;
+   C->sign = A->sign ^ B->sign;
+   fp_clamp(C);
+   COMBA_FINI;
+}
+#endif
+
+
+/* $Source$ */
+/* $Revision$ */
+/* $Date$ */
diff --git a/tomsfastmath/src/mul/fp_mul_comba_6.c b/tomsfastmath/src/mul/fp_mul_comba_6.c
new file mode 100644 (file)
index 0000000..d337be2
--- /dev/null
@@ -0,0 +1,68 @@
+#define TFM_DEFINES
+#include "fp_mul_comba.c"
+
+#if defined(TFM_MUL6) && FP_SIZE >= 12
+void fp_mul_comba6(fp_int *A, fp_int *B, fp_int *C)
+{
+   fp_digit c0, c1, c2, at[12];
+
+   memcpy(at, A->dp, 6 * sizeof(fp_digit));
+   memcpy(at+6, B->dp, 6 * sizeof(fp_digit));
+   COMBA_START;
+
+   COMBA_CLEAR;
+   /* 0 */
+   MULADD(at[0], at[6]);
+   COMBA_STORE(C->dp[0]);
+   /* 1 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[7]);    MULADD(at[1], at[6]);
+   COMBA_STORE(C->dp[1]);
+   /* 2 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[8]);    MULADD(at[1], at[7]);    MULADD(at[2], at[6]);
+   COMBA_STORE(C->dp[2]);
+   /* 3 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[9]);    MULADD(at[1], at[8]);    MULADD(at[2], at[7]);    MULADD(at[3], at[6]);
+   COMBA_STORE(C->dp[3]);
+   /* 4 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[10]);    MULADD(at[1], at[9]);    MULADD(at[2], at[8]);    MULADD(at[3], at[7]);    MULADD(at[4], at[6]);
+   COMBA_STORE(C->dp[4]);
+   /* 5 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[11]);    MULADD(at[1], at[10]);    MULADD(at[2], at[9]);    MULADD(at[3], at[8]);    MULADD(at[4], at[7]);    MULADD(at[5], at[6]);
+   COMBA_STORE(C->dp[5]);
+   /* 6 */
+   COMBA_FORWARD;
+   MULADD(at[1], at[11]);    MULADD(at[2], at[10]);    MULADD(at[3], at[9]);    MULADD(at[4], at[8]);    MULADD(at[5], at[7]);
+   COMBA_STORE(C->dp[6]);
+   /* 7 */
+   COMBA_FORWARD;
+   MULADD(at[2], at[11]);    MULADD(at[3], at[10]);    MULADD(at[4], at[9]);    MULADD(at[5], at[8]);
+   COMBA_STORE(C->dp[7]);
+   /* 8 */
+   COMBA_FORWARD;
+   MULADD(at[3], at[11]);    MULADD(at[4], at[10]);    MULADD(at[5], at[9]);
+   COMBA_STORE(C->dp[8]);
+   /* 9 */
+   COMBA_FORWARD;
+   MULADD(at[4], at[11]);    MULADD(at[5], at[10]);
+   COMBA_STORE(C->dp[9]);
+   /* 10 */
+   COMBA_FORWARD;
+   MULADD(at[5], at[11]);
+   COMBA_STORE(C->dp[10]);
+   COMBA_STORE2(C->dp[11]);
+   C->used = 12;
+   C->sign = A->sign ^ B->sign;
+   fp_clamp(C);
+   COMBA_FINI;
+}
+#endif
+
+
+/* $Source$ */
+/* $Revision$ */
+/* $Date$ */
diff --git a/tomsfastmath/src/mul/fp_mul_comba_64.c b/tomsfastmath/src/mul/fp_mul_comba_64.c
new file mode 100644 (file)
index 0000000..e06dbaa
--- /dev/null
@@ -0,0 +1,532 @@
+#define TFM_DEFINES
+#include "fp_mul_comba.c"
+
+#if defined(TFM_MUL64) && FP_SIZE >= 128
+void fp_mul_comba64(fp_int *A, fp_int *B, fp_int *C)
+{
+   fp_digit c0, c1, c2, at[128];
+
+   memcpy(at, A->dp, 64 * sizeof(fp_digit));
+   memcpy(at+64, B->dp, 64 * sizeof(fp_digit));
+   COMBA_START;
+
+   COMBA_CLEAR;
+   /* 0 */
+   MULADD(at[0], at[64]);
+   COMBA_STORE(C->dp[0]);
+   /* 1 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[65]);    MULADD(at[1], at[64]);
+   COMBA_STORE(C->dp[1]);
+   /* 2 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[66]);    MULADD(at[1], at[65]);    MULADD(at[2], at[64]);
+   COMBA_STORE(C->dp[2]);
+   /* 3 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[67]);    MULADD(at[1], at[66]);    MULADD(at[2], at[65]);    MULADD(at[3], at[64]);
+   COMBA_STORE(C->dp[3]);
+   /* 4 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[68]);    MULADD(at[1], at[67]);    MULADD(at[2], at[66]);    MULADD(at[3], at[65]);    MULADD(at[4], at[64]);
+   COMBA_STORE(C->dp[4]);
+   /* 5 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[69]);    MULADD(at[1], at[68]);    MULADD(at[2], at[67]);    MULADD(at[3], at[66]);    MULADD(at[4], at[65]);    MULADD(at[5], at[64]);
+   COMBA_STORE(C->dp[5]);
+   /* 6 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[70]);    MULADD(at[1], at[69]);    MULADD(at[2], at[68]);    MULADD(at[3], at[67]);    MULADD(at[4], at[66]);    MULADD(at[5], at[65]);    MULADD(at[6], at[64]);
+   COMBA_STORE(C->dp[6]);
+   /* 7 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[71]);    MULADD(at[1], at[70]);    MULADD(at[2], at[69]);    MULADD(at[3], at[68]);    MULADD(at[4], at[67]);    MULADD(at[5], at[66]);    MULADD(at[6], at[65]);    MULADD(at[7], at[64]);
+   COMBA_STORE(C->dp[7]);
+   /* 8 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[72]);    MULADD(at[1], at[71]);    MULADD(at[2], at[70]);    MULADD(at[3], at[69]);    MULADD(at[4], at[68]);    MULADD(at[5], at[67]);    MULADD(at[6], at[66]);    MULADD(at[7], at[65]);    MULADD(at[8], at[64]);
+   COMBA_STORE(C->dp[8]);
+   /* 9 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[73]);    MULADD(at[1], at[72]);    MULADD(at[2], at[71]);    MULADD(at[3], at[70]);    MULADD(at[4], at[69]);    MULADD(at[5], at[68]);    MULADD(at[6], at[67]);    MULADD(at[7], at[66]);    MULADD(at[8], at[65]);    MULADD(at[9], at[64]);
+   COMBA_STORE(C->dp[9]);
+   /* 10 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[74]);    MULADD(at[1], at[73]);    MULADD(at[2], at[72]);    MULADD(at[3], at[71]);    MULADD(at[4], at[70]);    MULADD(at[5], at[69]);    MULADD(at[6], at[68]);    MULADD(at[7], at[67]);    MULADD(at[8], at[66]);    MULADD(at[9], at[65]);    MULADD(at[10], at[64]);
+   COMBA_STORE(C->dp[10]);
+   /* 11 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[75]);    MULADD(at[1], at[74]);    MULADD(at[2], at[73]);    MULADD(at[3], at[72]);    MULADD(at[4], at[71]);    MULADD(at[5], at[70]);    MULADD(at[6], at[69]);    MULADD(at[7], at[68]);    MULADD(at[8], at[67]);    MULADD(at[9], at[66]);    MULADD(at[10], at[65]);    MULADD(at[11], at[64]);
+   COMBA_STORE(C->dp[11]);
+   /* 12 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[76]);    MULADD(at[1], at[75]);    MULADD(at[2], at[74]);    MULADD(at[3], at[73]);    MULADD(at[4], at[72]);    MULADD(at[5], at[71]);    MULADD(at[6], at[70]);    MULADD(at[7], at[69]);    MULADD(at[8], at[68]);    MULADD(at[9], at[67]);    MULADD(at[10], at[66]);    MULADD(at[11], at[65]);    MULADD(at[12], at[64]);
+   COMBA_STORE(C->dp[12]);
+   /* 13 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[77]);    MULADD(at[1], at[76]);    MULADD(at[2], at[75]);    MULADD(at[3], at[74]);    MULADD(at[4], at[73]);    MULADD(at[5], at[72]);    MULADD(at[6], at[71]);    MULADD(at[7], at[70]);    MULADD(at[8], at[69]);    MULADD(at[9], at[68]);    MULADD(at[10], at[67]);    MULADD(at[11], at[66]);    MULADD(at[12], at[65]);    MULADD(at[13], at[64]);
+   COMBA_STORE(C->dp[13]);
+   /* 14 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[78]);    MULADD(at[1], at[77]);    MULADD(at[2], at[76]);    MULADD(at[3], at[75]);    MULADD(at[4], at[74]);    MULADD(at[5], at[73]);    MULADD(at[6], at[72]);    MULADD(at[7], at[71]);    MULADD(at[8], at[70]);    MULADD(at[9], at[69]);    MULADD(at[10], at[68]);    MULADD(at[11], at[67]);    MULADD(at[12], at[66]);    MULADD(at[13], at[65]);    MULADD(at[14], at[64]);
+   COMBA_STORE(C->dp[14]);
+   /* 15 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[79]);    MULADD(at[1], at[78]);    MULADD(at[2], at[77]);    MULADD(at[3], at[76]);    MULADD(at[4], at[75]);    MULADD(at[5], at[74]);    MULADD(at[6], at[73]);    MULADD(at[7], at[72]);    MULADD(at[8], at[71]);    MULADD(at[9], at[70]);    MULADD(at[10], at[69]);    MULADD(at[11], at[68]);    MULADD(at[12], at[67]);    MULADD(at[13], at[66]);    MULADD(at[14], at[65]);    MULADD(at[15], at[64]);
+   COMBA_STORE(C->dp[15]);
+   /* 16 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[80]);    MULADD(at[1], at[79]);    MULADD(at[2], at[78]);    MULADD(at[3], at[77]);    MULADD(at[4], at[76]);    MULADD(at[5], at[75]);    MULADD(at[6], at[74]);    MULADD(at[7], at[73]);    MULADD(at[8], at[72]);    MULADD(at[9], at[71]);    MULADD(at[10], at[70]);    MULADD(at[11], at[69]);    MULADD(at[12], at[68]);    MULADD(at[13], at[67]);    MULADD(at[14], at[66]);    MULADD(at[15], at[65]);    MULADD(at[16], at[64]);
+   COMBA_STORE(C->dp[16]);
+   /* 17 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[81]);    MULADD(at[1], at[80]);    MULADD(at[2], at[79]);    MULADD(at[3], at[78]);    MULADD(at[4], at[77]);    MULADD(at[5], at[76]);    MULADD(at[6], at[75]);    MULADD(at[7], at[74]);    MULADD(at[8], at[73]);    MULADD(at[9], at[72]);    MULADD(at[10], at[71]);    MULADD(at[11], at[70]);    MULADD(at[12], at[69]);    MULADD(at[13], at[68]);    MULADD(at[14], at[67]);    MULADD(at[15], at[66]);    MULADD(at[16], at[65]);    MULADD(at[17], at[64]);
+   COMBA_STORE(C->dp[17]);
+   /* 18 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[82]);    MULADD(at[1], at[81]);    MULADD(at[2], at[80]);    MULADD(at[3], at[79]);    MULADD(at[4], at[78]);    MULADD(at[5], at[77]);    MULADD(at[6], at[76]);    MULADD(at[7], at[75]);    MULADD(at[8], at[74]);    MULADD(at[9], at[73]);    MULADD(at[10], at[72]);    MULADD(at[11], at[71]);    MULADD(at[12], at[70]);    MULADD(at[13], at[69]);    MULADD(at[14], at[68]);    MULADD(at[15], at[67]);    MULADD(at[16], at[66]);    MULADD(at[17], at[65]);    MULADD(at[18], at[64]);
+   COMBA_STORE(C->dp[18]);
+   /* 19 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[83]);    MULADD(at[1], at[82]);    MULADD(at[2], at[81]);    MULADD(at[3], at[80]);    MULADD(at[4], at[79]);    MULADD(at[5], at[78]);    MULADD(at[6], at[77]);    MULADD(at[7], at[76]);    MULADD(at[8], at[75]);    MULADD(at[9], at[74]);    MULADD(at[10], at[73]);    MULADD(at[11], at[72]);    MULADD(at[12], at[71]);    MULADD(at[13], at[70]);    MULADD(at[14], at[69]);    MULADD(at[15], at[68]);    MULADD(at[16], at[67]);    MULADD(at[17], at[66]);    MULADD(at[18], at[65]);    MULADD(at[19], at[64]);
+   COMBA_STORE(C->dp[19]);
+   /* 20 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[84]);    MULADD(at[1], at[83]);    MULADD(at[2], at[82]);    MULADD(at[3], at[81]);    MULADD(at[4], at[80]);    MULADD(at[5], at[79]);    MULADD(at[6], at[78]);    MULADD(at[7], at[77]);    MULADD(at[8], at[76]);    MULADD(at[9], at[75]);    MULADD(at[10], at[74]);    MULADD(at[11], at[73]);    MULADD(at[12], at[72]);    MULADD(at[13], at[71]);    MULADD(at[14], at[70]);    MULADD(at[15], at[69]);    MULADD(at[16], at[68]);    MULADD(at[17], at[67]);    MULADD(at[18], at[66]);    MULADD(at[19], at[65]);    MULADD(at[20], at[64]);
+   COMBA_STORE(C->dp[20]);
+   /* 21 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[85]);    MULADD(at[1], at[84]);    MULADD(at[2], at[83]);    MULADD(at[3], at[82]);    MULADD(at[4], at[81]);    MULADD(at[5], at[80]);    MULADD(at[6], at[79]);    MULADD(at[7], at[78]);    MULADD(at[8], at[77]);    MULADD(at[9], at[76]);    MULADD(at[10], at[75]);    MULADD(at[11], at[74]);    MULADD(at[12], at[73]);    MULADD(at[13], at[72]);    MULADD(at[14], at[71]);    MULADD(at[15], at[70]);    MULADD(at[16], at[69]);    MULADD(at[17], at[68]);    MULADD(at[18], at[67]);    MULADD(at[19], at[66]);    MULADD(at[20], at[65]);    MULADD(at[21], at[64]);
+   COMBA_STORE(C->dp[21]);
+   /* 22 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[86]);    MULADD(at[1], at[85]);    MULADD(at[2], at[84]);    MULADD(at[3], at[83]);    MULADD(at[4], at[82]);    MULADD(at[5], at[81]);    MULADD(at[6], at[80]);    MULADD(at[7], at[79]);    MULADD(at[8], at[78]);    MULADD(at[9], at[77]);    MULADD(at[10], at[76]);    MULADD(at[11], at[75]);    MULADD(at[12], at[74]);    MULADD(at[13], at[73]);    MULADD(at[14], at[72]);    MULADD(at[15], at[71]);    MULADD(at[16], at[70]);    MULADD(at[17], at[69]);    MULADD(at[18], at[68]);    MULADD(at[19], at[67]);    MULADD(at[20], at[66]);    MULADD(at[21], at[65]);    MULADD(at[22], at[64]);
+   COMBA_STORE(C->dp[22]);
+   /* 23 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[87]);    MULADD(at[1], at[86]);    MULADD(at[2], at[85]);    MULADD(at[3], at[84]);    MULADD(at[4], at[83]);    MULADD(at[5], at[82]);    MULADD(at[6], at[81]);    MULADD(at[7], at[80]);    MULADD(at[8], at[79]);    MULADD(at[9], at[78]);    MULADD(at[10], at[77]);    MULADD(at[11], at[76]);    MULADD(at[12], at[75]);    MULADD(at[13], at[74]);    MULADD(at[14], at[73]);    MULADD(at[15], at[72]);    MULADD(at[16], at[71]);    MULADD(at[17], at[70]);    MULADD(at[18], at[69]);    MULADD(at[19], at[68]);    MULADD(at[20], at[67]);    MULADD(at[21], at[66]);    MULADD(at[22], at[65]);    MULADD(at[23], at[64]);
+   COMBA_STORE(C->dp[23]);
+   /* 24 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[88]);    MULADD(at[1], at[87]);    MULADD(at[2], at[86]);    MULADD(at[3], at[85]);    MULADD(at[4], at[84]);    MULADD(at[5], at[83]);    MULADD(at[6], at[82]);    MULADD(at[7], at[81]);    MULADD(at[8], at[80]);    MULADD(at[9], at[79]);    MULADD(at[10], at[78]);    MULADD(at[11], at[77]);    MULADD(at[12], at[76]);    MULADD(at[13], at[75]);    MULADD(at[14], at[74]);    MULADD(at[15], at[73]);    MULADD(at[16], at[72]);    MULADD(at[17], at[71]);    MULADD(at[18], at[70]);    MULADD(at[19], at[69]);    MULADD(at[20], at[68]);    MULADD(at[21], at[67]);    MULADD(at[22], at[66]);    MULADD(at[23], at[65]);    MULADD(at[24], at[64]);
+   COMBA_STORE(C->dp[24]);
+   /* 25 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[89]);    MULADD(at[1], at[88]);    MULADD(at[2], at[87]);    MULADD(at[3], at[86]);    MULADD(at[4], at[85]);    MULADD(at[5], at[84]);    MULADD(at[6], at[83]);    MULADD(at[7], at[82]);    MULADD(at[8], at[81]);    MULADD(at[9], at[80]);    MULADD(at[10], at[79]);    MULADD(at[11], at[78]);    MULADD(at[12], at[77]);    MULADD(at[13], at[76]);    MULADD(at[14], at[75]);    MULADD(at[15], at[74]);    MULADD(at[16], at[73]);    MULADD(at[17], at[72]);    MULADD(at[18], at[71]);    MULADD(at[19], at[70]);    MULADD(at[20], at[69]);    MULADD(at[21], at[68]);    MULADD(at[22], at[67]);    MULADD(at[23], at[66]);    MULADD(at[24], at[65]);    MULADD(at[25], at[64]);
+   COMBA_STORE(C->dp[25]);
+   /* 26 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[90]);    MULADD(at[1], at[89]);    MULADD(at[2], at[88]);    MULADD(at[3], at[87]);    MULADD(at[4], at[86]);    MULADD(at[5], at[85]);    MULADD(at[6], at[84]);    MULADD(at[7], at[83]);    MULADD(at[8], at[82]);    MULADD(at[9], at[81]);    MULADD(at[10], at[80]);    MULADD(at[11], at[79]);    MULADD(at[12], at[78]);    MULADD(at[13], at[77]);    MULADD(at[14], at[76]);    MULADD(at[15], at[75]);    MULADD(at[16], at[74]);    MULADD(at[17], at[73]);    MULADD(at[18], at[72]);    MULADD(at[19], at[71]);    MULADD(at[20], at[70]);    MULADD(at[21], at[69]);    MULADD(at[22], at[68]);    MULADD(at[23], at[67]);    MULADD(at[24], at[66]);    MULADD(at[25], at[65]);    MULADD(at[26], at[64]);
+   COMBA_STORE(C->dp[26]);
+   /* 27 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[91]);    MULADD(at[1], at[90]);    MULADD(at[2], at[89]);    MULADD(at[3], at[88]);    MULADD(at[4], at[87]);    MULADD(at[5], at[86]);    MULADD(at[6], at[85]);    MULADD(at[7], at[84]);    MULADD(at[8], at[83]);    MULADD(at[9], at[82]);    MULADD(at[10], at[81]);    MULADD(at[11], at[80]);    MULADD(at[12], at[79]);    MULADD(at[13], at[78]);    MULADD(at[14], at[77]);    MULADD(at[15], at[76]);    MULADD(at[16], at[75]);    MULADD(at[17], at[74]);    MULADD(at[18], at[73]);    MULADD(at[19], at[72]);    MULADD(at[20], at[71]);    MULADD(at[21], at[70]);    MULADD(at[22], at[69]);    MULADD(at[23], at[68]);    MULADD(at[24], at[67]);    MULADD(at[25], at[66]);    MULADD(at[26], at[65]);    MULADD(at[27], at[64]);
+   COMBA_STORE(C->dp[27]);
+   /* 28 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[92]);    MULADD(at[1], at[91]);    MULADD(at[2], at[90]);    MULADD(at[3], at[89]);    MULADD(at[4], at[88]);    MULADD(at[5], at[87]);    MULADD(at[6], at[86]);    MULADD(at[7], at[85]);    MULADD(at[8], at[84]);    MULADD(at[9], at[83]);    MULADD(at[10], at[82]);    MULADD(at[11], at[81]);    MULADD(at[12], at[80]);    MULADD(at[13], at[79]);    MULADD(at[14], at[78]);    MULADD(at[15], at[77]);    MULADD(at[16], at[76]);    MULADD(at[17], at[75]);    MULADD(at[18], at[74]);    MULADD(at[19], at[73]);    MULADD(at[20], at[72]);    MULADD(at[21], at[71]);    MULADD(at[22], at[70]);    MULADD(at[23], at[69]);    MULADD(at[24], at[68]);    MULADD(at[25], at[67]);    MULADD(at[26], at[66]);    MULADD(at[27], at[65]);    MULADD(at[28], at[64]);
+   COMBA_STORE(C->dp[28]);
+   /* 29 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[93]);    MULADD(at[1], at[92]);    MULADD(at[2], at[91]);    MULADD(at[3], at[90]);    MULADD(at[4], at[89]);    MULADD(at[5], at[88]);    MULADD(at[6], at[87]);    MULADD(at[7], at[86]);    MULADD(at[8], at[85]);    MULADD(at[9], at[84]);    MULADD(at[10], at[83]);    MULADD(at[11], at[82]);    MULADD(at[12], at[81]);    MULADD(at[13], at[80]);    MULADD(at[14], at[79]);    MULADD(at[15], at[78]);    MULADD(at[16], at[77]);    MULADD(at[17], at[76]);    MULADD(at[18], at[75]);    MULADD(at[19], at[74]);    MULADD(at[20], at[73]);    MULADD(at[21], at[72]);    MULADD(at[22], at[71]);    MULADD(at[23], at[70]);    MULADD(at[24], at[69]);    MULADD(at[25], at[68]);    MULADD(at[26], at[67]);    MULADD(at[27], at[66]);    MULADD(at[28], at[65]);    MULADD(at[29], at[64]);
+   COMBA_STORE(C->dp[29]);
+   /* 30 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[94]);    MULADD(at[1], at[93]);    MULADD(at[2], at[92]);    MULADD(at[3], at[91]);    MULADD(at[4], at[90]);    MULADD(at[5], at[89]);    MULADD(at[6], at[88]);    MULADD(at[7], at[87]);    MULADD(at[8], at[86]);    MULADD(at[9], at[85]);    MULADD(at[10], at[84]);    MULADD(at[11], at[83]);    MULADD(at[12], at[82]);    MULADD(at[13], at[81]);    MULADD(at[14], at[80]);    MULADD(at[15], at[79]);    MULADD(at[16], at[78]);    MULADD(at[17], at[77]);    MULADD(at[18], at[76]);    MULADD(at[19], at[75]);    MULADD(at[20], at[74]);    MULADD(at[21], at[73]);    MULADD(at[22], at[72]);    MULADD(at[23], at[71]);    MULADD(at[24], at[70]);    MULADD(at[25], at[69]);    MULADD(at[26], at[68]);    MULADD(at[27], at[67]);    MULADD(at[28], at[66]);    MULADD(at[29], at[65]);    MULADD(at[30], at[64]);
+   COMBA_STORE(C->dp[30]);
+   /* 31 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[95]);    MULADD(at[1], at[94]);    MULADD(at[2], at[93]);    MULADD(at[3], at[92]);    MULADD(at[4], at[91]);    MULADD(at[5], at[90]);    MULADD(at[6], at[89]);    MULADD(at[7], at[88]);    MULADD(at[8], at[87]);    MULADD(at[9], at[86]);    MULADD(at[10], at[85]);    MULADD(at[11], at[84]);    MULADD(at[12], at[83]);    MULADD(at[13], at[82]);    MULADD(at[14], at[81]);    MULADD(at[15], at[80]);    MULADD(at[16], at[79]);    MULADD(at[17], at[78]);    MULADD(at[18], at[77]);    MULADD(at[19], at[76]);    MULADD(at[20], at[75]);    MULADD(at[21], at[74]);    MULADD(at[22], at[73]);    MULADD(at[23], at[72]);    MULADD(at[24], at[71]);    MULADD(at[25], at[70]);    MULADD(at[26], at[69]);    MULADD(at[27], at[68]);    MULADD(at[28], at[67]);    MULADD(at[29], at[66]);    MULADD(at[30], at[65]);    MULADD(at[31], at[64]);
+   COMBA_STORE(C->dp[31]);
+   /* 32 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[96]);    MULADD(at[1], at[95]);    MULADD(at[2], at[94]);    MULADD(at[3], at[93]);    MULADD(at[4], at[92]);    MULADD(at[5], at[91]);    MULADD(at[6], at[90]);    MULADD(at[7], at[89]);    MULADD(at[8], at[88]);    MULADD(at[9], at[87]);    MULADD(at[10], at[86]);    MULADD(at[11], at[85]);    MULADD(at[12], at[84]);    MULADD(at[13], at[83]);    MULADD(at[14], at[82]);    MULADD(at[15], at[81]);    MULADD(at[16], at[80]);    MULADD(at[17], at[79]);    MULADD(at[18], at[78]);    MULADD(at[19], at[77]);    MULADD(at[20], at[76]);    MULADD(at[21], at[75]);    MULADD(at[22], at[74]);    MULADD(at[23], at[73]);    MULADD(at[24], at[72]);    MULADD(at[25], at[71]);    MULADD(at[26], at[70]);    MULADD(at[27], at[69]);    MULADD(at[28], at[68]);    MULADD(at[29], at[67]);    MULADD(at[30], at[66]);    MULADD(at[31], at[65]);    MULADD(at[32], at[64]);
+   COMBA_STORE(C->dp[32]);
+   /* 33 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[97]);    MULADD(at[1], at[96]);    MULADD(at[2], at[95]);    MULADD(at[3], at[94]);    MULADD(at[4], at[93]);    MULADD(at[5], at[92]);    MULADD(at[6], at[91]);    MULADD(at[7], at[90]);    MULADD(at[8], at[89]);    MULADD(at[9], at[88]);    MULADD(at[10], at[87]);    MULADD(at[11], at[86]);    MULADD(at[12], at[85]);    MULADD(at[13], at[84]);    MULADD(at[14], at[83]);    MULADD(at[15], at[82]);    MULADD(at[16], at[81]);    MULADD(at[17], at[80]);    MULADD(at[18], at[79]);    MULADD(at[19], at[78]);    MULADD(at[20], at[77]);    MULADD(at[21], at[76]);    MULADD(at[22], at[75]);    MULADD(at[23], at[74]);    MULADD(at[24], at[73]);    MULADD(at[25], at[72]);    MULADD(at[26], at[71]);    MULADD(at[27], at[70]);    MULADD(at[28], at[69]);    MULADD(at[29], at[68]);    MULADD(at[30], at[67]);    MULADD(at[31], at[66]);    MULADD(at[32], at[65]);    MULADD(at[33], at[64]);
+   COMBA_STORE(C->dp[33]);
+   /* 34 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[98]);    MULADD(at[1], at[97]);    MULADD(at[2], at[96]);    MULADD(at[3], at[95]);    MULADD(at[4], at[94]);    MULADD(at[5], at[93]);    MULADD(at[6], at[92]);    MULADD(at[7], at[91]);    MULADD(at[8], at[90]);    MULADD(at[9], at[89]);    MULADD(at[10], at[88]);    MULADD(at[11], at[87]);    MULADD(at[12], at[86]);    MULADD(at[13], at[85]);    MULADD(at[14], at[84]);    MULADD(at[15], at[83]);    MULADD(at[16], at[82]);    MULADD(at[17], at[81]);    MULADD(at[18], at[80]);    MULADD(at[19], at[79]);    MULADD(at[20], at[78]);    MULADD(at[21], at[77]);    MULADD(at[22], at[76]);    MULADD(at[23], at[75]);    MULADD(at[24], at[74]);    MULADD(at[25], at[73]);    MULADD(at[26], at[72]);    MULADD(at[27], at[71]);    MULADD(at[28], at[70]);    MULADD(at[29], at[69]);    MULADD(at[30], at[68]);    MULADD(at[31], at[67]);    MULADD(at[32], at[66]);    MULADD(at[33], at[65]);    MULADD(at[34], at[64]);
+   COMBA_STORE(C->dp[34]);
+   /* 35 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[99]);    MULADD(at[1], at[98]);    MULADD(at[2], at[97]);    MULADD(at[3], at[96]);    MULADD(at[4], at[95]);    MULADD(at[5], at[94]);    MULADD(at[6], at[93]);    MULADD(at[7], at[92]);    MULADD(at[8], at[91]);    MULADD(at[9], at[90]);    MULADD(at[10], at[89]);    MULADD(at[11], at[88]);    MULADD(at[12], at[87]);    MULADD(at[13], at[86]);    MULADD(at[14], at[85]);    MULADD(at[15], at[84]);    MULADD(at[16], at[83]);    MULADD(at[17], at[82]);    MULADD(at[18], at[81]);    MULADD(at[19], at[80]);    MULADD(at[20], at[79]);    MULADD(at[21], at[78]);    MULADD(at[22], at[77]);    MULADD(at[23], at[76]);    MULADD(at[24], at[75]);    MULADD(at[25], at[74]);    MULADD(at[26], at[73]);    MULADD(at[27], at[72]);    MULADD(at[28], at[71]);    MULADD(at[29], at[70]);    MULADD(at[30], at[69]);    MULADD(at[31], at[68]);    MULADD(at[32], at[67]);    MULADD(at[33], at[66]);    MULADD(at[34], at[65]);    MULADD(at[35], at[64]);
+   COMBA_STORE(C->dp[35]);
+   /* 36 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[100]);    MULADD(at[1], at[99]);    MULADD(at[2], at[98]);    MULADD(at[3], at[97]);    MULADD(at[4], at[96]);    MULADD(at[5], at[95]);    MULADD(at[6], at[94]);    MULADD(at[7], at[93]);    MULADD(at[8], at[92]);    MULADD(at[9], at[91]);    MULADD(at[10], at[90]);    MULADD(at[11], at[89]);    MULADD(at[12], at[88]);    MULADD(at[13], at[87]);    MULADD(at[14], at[86]);    MULADD(at[15], at[85]);    MULADD(at[16], at[84]);    MULADD(at[17], at[83]);    MULADD(at[18], at[82]);    MULADD(at[19], at[81]);    MULADD(at[20], at[80]);    MULADD(at[21], at[79]);    MULADD(at[22], at[78]);    MULADD(at[23], at[77]);    MULADD(at[24], at[76]);    MULADD(at[25], at[75]);    MULADD(at[26], at[74]);    MULADD(at[27], at[73]);    MULADD(at[28], at[72]);    MULADD(at[29], at[71]);    MULADD(at[30], at[70]);    MULADD(at[31], at[69]);    MULADD(at[32], at[68]);    MULADD(at[33], at[67]);    MULADD(at[34], at[66]);    MULADD(at[35], at[65]);    MULADD(at[36], at[64]);
+   COMBA_STORE(C->dp[36]);
+   /* 37 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[101]);    MULADD(at[1], at[100]);    MULADD(at[2], at[99]);    MULADD(at[3], at[98]);    MULADD(at[4], at[97]);    MULADD(at[5], at[96]);    MULADD(at[6], at[95]);    MULADD(at[7], at[94]);    MULADD(at[8], at[93]);    MULADD(at[9], at[92]);    MULADD(at[10], at[91]);    MULADD(at[11], at[90]);    MULADD(at[12], at[89]);    MULADD(at[13], at[88]);    MULADD(at[14], at[87]);    MULADD(at[15], at[86]);    MULADD(at[16], at[85]);    MULADD(at[17], at[84]);    MULADD(at[18], at[83]);    MULADD(at[19], at[82]);    MULADD(at[20], at[81]);    MULADD(at[21], at[80]);    MULADD(at[22], at[79]);    MULADD(at[23], at[78]);    MULADD(at[24], at[77]);    MULADD(at[25], at[76]);    MULADD(at[26], at[75]);    MULADD(at[27], at[74]);    MULADD(at[28], at[73]);    MULADD(at[29], at[72]);    MULADD(at[30], at[71]);    MULADD(at[31], at[70]);    MULADD(at[32], at[69]);    MULADD(at[33], at[68]);    MULADD(at[34], at[67]);    MULADD(at[35], at[66]);    MULADD(at[36], at[65]);    MULADD(at[37], at[64]);
+   COMBA_STORE(C->dp[37]);
+   /* 38 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[102]);    MULADD(at[1], at[101]);    MULADD(at[2], at[100]);    MULADD(at[3], at[99]);    MULADD(at[4], at[98]);    MULADD(at[5], at[97]);    MULADD(at[6], at[96]);    MULADD(at[7], at[95]);    MULADD(at[8], at[94]);    MULADD(at[9], at[93]);    MULADD(at[10], at[92]);    MULADD(at[11], at[91]);    MULADD(at[12], at[90]);    MULADD(at[13], at[89]);    MULADD(at[14], at[88]);    MULADD(at[15], at[87]);    MULADD(at[16], at[86]);    MULADD(at[17], at[85]);    MULADD(at[18], at[84]);    MULADD(at[19], at[83]);    MULADD(at[20], at[82]);    MULADD(at[21], at[81]);    MULADD(at[22], at[80]);    MULADD(at[23], at[79]);    MULADD(at[24], at[78]);    MULADD(at[25], at[77]);    MULADD(at[26], at[76]);    MULADD(at[27], at[75]);    MULADD(at[28], at[74]);    MULADD(at[29], at[73]);    MULADD(at[30], at[72]);    MULADD(at[31], at[71]);    MULADD(at[32], at[70]);    MULADD(at[33], at[69]);    MULADD(at[34], at[68]);    MULADD(at[35], at[67]);    MULADD(at[36], at[66]);    MULADD(at[37], at[65]);    MULADD(at[38], at[64]);
+   COMBA_STORE(C->dp[38]);
+   /* 39 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[103]);    MULADD(at[1], at[102]);    MULADD(at[2], at[101]);    MULADD(at[3], at[100]);    MULADD(at[4], at[99]);    MULADD(at[5], at[98]);    MULADD(at[6], at[97]);    MULADD(at[7], at[96]);    MULADD(at[8], at[95]);    MULADD(at[9], at[94]);    MULADD(at[10], at[93]);    MULADD(at[11], at[92]);    MULADD(at[12], at[91]);    MULADD(at[13], at[90]);    MULADD(at[14], at[89]);    MULADD(at[15], at[88]);    MULADD(at[16], at[87]);    MULADD(at[17], at[86]);    MULADD(at[18], at[85]);    MULADD(at[19], at[84]);    MULADD(at[20], at[83]);    MULADD(at[21], at[82]);    MULADD(at[22], at[81]);    MULADD(at[23], at[80]);    MULADD(at[24], at[79]);    MULADD(at[25], at[78]);    MULADD(at[26], at[77]);    MULADD(at[27], at[76]);    MULADD(at[28], at[75]);    MULADD(at[29], at[74]);    MULADD(at[30], at[73]);    MULADD(at[31], at[72]);    MULADD(at[32], at[71]);    MULADD(at[33], at[70]);    MULADD(at[34], at[69]);    MULADD(at[35], at[68]);    MULADD(at[36], at[67]);    MULADD(at[37], at[66]);    MULADD(at[38], at[65]);    MULADD(at[39], at[64]);
+   COMBA_STORE(C->dp[39]);
+   /* 40 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[104]);    MULADD(at[1], at[103]);    MULADD(at[2], at[102]);    MULADD(at[3], at[101]);    MULADD(at[4], at[100]);    MULADD(at[5], at[99]);    MULADD(at[6], at[98]);    MULADD(at[7], at[97]);    MULADD(at[8], at[96]);    MULADD(at[9], at[95]);    MULADD(at[10], at[94]);    MULADD(at[11], at[93]);    MULADD(at[12], at[92]);    MULADD(at[13], at[91]);    MULADD(at[14], at[90]);    MULADD(at[15], at[89]);    MULADD(at[16], at[88]);    MULADD(at[17], at[87]);    MULADD(at[18], at[86]);    MULADD(at[19], at[85]);    MULADD(at[20], at[84]);    MULADD(at[21], at[83]);    MULADD(at[22], at[82]);    MULADD(at[23], at[81]);    MULADD(at[24], at[80]);    MULADD(at[25], at[79]);    MULADD(at[26], at[78]);    MULADD(at[27], at[77]);    MULADD(at[28], at[76]);    MULADD(at[29], at[75]);    MULADD(at[30], at[74]);    MULADD(at[31], at[73]);    MULADD(at[32], at[72]);    MULADD(at[33], at[71]);    MULADD(at[34], at[70]);    MULADD(at[35], at[69]);    MULADD(at[36], at[68]);    MULADD(at[37], at[67]);    MULADD(at[38], at[66]);    MULADD(at[39], at[65]);    MULADD(at[40], at[64]);
+   COMBA_STORE(C->dp[40]);
+   /* 41 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[105]);    MULADD(at[1], at[104]);    MULADD(at[2], at[103]);    MULADD(at[3], at[102]);    MULADD(at[4], at[101]);    MULADD(at[5], at[100]);    MULADD(at[6], at[99]);    MULADD(at[7], at[98]);    MULADD(at[8], at[97]);    MULADD(at[9], at[96]);    MULADD(at[10], at[95]);    MULADD(at[11], at[94]);    MULADD(at[12], at[93]);    MULADD(at[13], at[92]);    MULADD(at[14], at[91]);    MULADD(at[15], at[90]);    MULADD(at[16], at[89]);    MULADD(at[17], at[88]);    MULADD(at[18], at[87]);    MULADD(at[19], at[86]);    MULADD(at[20], at[85]);    MULADD(at[21], at[84]);    MULADD(at[22], at[83]);    MULADD(at[23], at[82]);    MULADD(at[24], at[81]);    MULADD(at[25], at[80]);    MULADD(at[26], at[79]);    MULADD(at[27], at[78]);    MULADD(at[28], at[77]);    MULADD(at[29], at[76]);    MULADD(at[30], at[75]);    MULADD(at[31], at[74]);    MULADD(at[32], at[73]);    MULADD(at[33], at[72]);    MULADD(at[34], at[71]);    MULADD(at[35], at[70]);    MULADD(at[36], at[69]);    MULADD(at[37], at[68]);    MULADD(at[38], at[67]);    MULADD(at[39], at[66]);    MULADD(at[40], at[65]);    MULADD(at[41], at[64]);
+   COMBA_STORE(C->dp[41]);
+   /* 42 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[106]);    MULADD(at[1], at[105]);    MULADD(at[2], at[104]);    MULADD(at[3], at[103]);    MULADD(at[4], at[102]);    MULADD(at[5], at[101]);    MULADD(at[6], at[100]);    MULADD(at[7], at[99]);    MULADD(at[8], at[98]);    MULADD(at[9], at[97]);    MULADD(at[10], at[96]);    MULADD(at[11], at[95]);    MULADD(at[12], at[94]);    MULADD(at[13], at[93]);    MULADD(at[14], at[92]);    MULADD(at[15], at[91]);    MULADD(at[16], at[90]);    MULADD(at[17], at[89]);    MULADD(at[18], at[88]);    MULADD(at[19], at[87]);    MULADD(at[20], at[86]);    MULADD(at[21], at[85]);    MULADD(at[22], at[84]);    MULADD(at[23], at[83]);    MULADD(at[24], at[82]);    MULADD(at[25], at[81]);    MULADD(at[26], at[80]);    MULADD(at[27], at[79]);    MULADD(at[28], at[78]);    MULADD(at[29], at[77]);    MULADD(at[30], at[76]);    MULADD(at[31], at[75]);    MULADD(at[32], at[74]);    MULADD(at[33], at[73]);    MULADD(at[34], at[72]);    MULADD(at[35], at[71]);    MULADD(at[36], at[70]);    MULADD(at[37], at[69]);    MULADD(at[38], at[68]);    MULADD(at[39], at[67]);    MULADD(at[40], at[66]);    MULADD(at[41], at[65]);    MULADD(at[42], at[64]);
+   COMBA_STORE(C->dp[42]);
+   /* 43 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[107]);    MULADD(at[1], at[106]);    MULADD(at[2], at[105]);    MULADD(at[3], at[104]);    MULADD(at[4], at[103]);    MULADD(at[5], at[102]);    MULADD(at[6], at[101]);    MULADD(at[7], at[100]);    MULADD(at[8], at[99]);    MULADD(at[9], at[98]);    MULADD(at[10], at[97]);    MULADD(at[11], at[96]);    MULADD(at[12], at[95]);    MULADD(at[13], at[94]);    MULADD(at[14], at[93]);    MULADD(at[15], at[92]);    MULADD(at[16], at[91]);    MULADD(at[17], at[90]);    MULADD(at[18], at[89]);    MULADD(at[19], at[88]);    MULADD(at[20], at[87]);    MULADD(at[21], at[86]);    MULADD(at[22], at[85]);    MULADD(at[23], at[84]);    MULADD(at[24], at[83]);    MULADD(at[25], at[82]);    MULADD(at[26], at[81]);    MULADD(at[27], at[80]);    MULADD(at[28], at[79]);    MULADD(at[29], at[78]);    MULADD(at[30], at[77]);    MULADD(at[31], at[76]);    MULADD(at[32], at[75]);    MULADD(at[33], at[74]);    MULADD(at[34], at[73]);    MULADD(at[35], at[72]);    MULADD(at[36], at[71]);    MULADD(at[37], at[70]);    MULADD(at[38], at[69]);    MULADD(at[39], at[68]);    MULADD(at[40], at[67]);    MULADD(at[41], at[66]);    MULADD(at[42], at[65]);    MULADD(at[43], at[64]);
+   COMBA_STORE(C->dp[43]);
+   /* 44 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[108]);    MULADD(at[1], at[107]);    MULADD(at[2], at[106]);    MULADD(at[3], at[105]);    MULADD(at[4], at[104]);    MULADD(at[5], at[103]);    MULADD(at[6], at[102]);    MULADD(at[7], at[101]);    MULADD(at[8], at[100]);    MULADD(at[9], at[99]);    MULADD(at[10], at[98]);    MULADD(at[11], at[97]);    MULADD(at[12], at[96]);    MULADD(at[13], at[95]);    MULADD(at[14], at[94]);    MULADD(at[15], at[93]);    MULADD(at[16], at[92]);    MULADD(at[17], at[91]);    MULADD(at[18], at[90]);    MULADD(at[19], at[89]);    MULADD(at[20], at[88]);    MULADD(at[21], at[87]);    MULADD(at[22], at[86]);    MULADD(at[23], at[85]);    MULADD(at[24], at[84]);    MULADD(at[25], at[83]);    MULADD(at[26], at[82]);    MULADD(at[27], at[81]);    MULADD(at[28], at[80]);    MULADD(at[29], at[79]);    MULADD(at[30], at[78]);    MULADD(at[31], at[77]);    MULADD(at[32], at[76]);    MULADD(at[33], at[75]);    MULADD(at[34], at[74]);    MULADD(at[35], at[73]);    MULADD(at[36], at[72]);    MULADD(at[37], at[71]);    MULADD(at[38], at[70]);    MULADD(at[39], at[69]);    MULADD(at[40], at[68]);    MULADD(at[41], at[67]);    MULADD(at[42], at[66]);    MULADD(at[43], at[65]);    MULADD(at[44], at[64]);
+   COMBA_STORE(C->dp[44]);
+   /* 45 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[109]);    MULADD(at[1], at[108]);    MULADD(at[2], at[107]);    MULADD(at[3], at[106]);    MULADD(at[4], at[105]);    MULADD(at[5], at[104]);    MULADD(at[6], at[103]);    MULADD(at[7], at[102]);    MULADD(at[8], at[101]);    MULADD(at[9], at[100]);    MULADD(at[10], at[99]);    MULADD(at[11], at[98]);    MULADD(at[12], at[97]);    MULADD(at[13], at[96]);    MULADD(at[14], at[95]);    MULADD(at[15], at[94]);    MULADD(at[16], at[93]);    MULADD(at[17], at[92]);    MULADD(at[18], at[91]);    MULADD(at[19], at[90]);    MULADD(at[20], at[89]);    MULADD(at[21], at[88]);    MULADD(at[22], at[87]);    MULADD(at[23], at[86]);    MULADD(at[24], at[85]);    MULADD(at[25], at[84]);    MULADD(at[26], at[83]);    MULADD(at[27], at[82]);    MULADD(at[28], at[81]);    MULADD(at[29], at[80]);    MULADD(at[30], at[79]);    MULADD(at[31], at[78]);    MULADD(at[32], at[77]);    MULADD(at[33], at[76]);    MULADD(at[34], at[75]);    MULADD(at[35], at[74]);    MULADD(at[36], at[73]);    MULADD(at[37], at[72]);    MULADD(at[38], at[71]);    MULADD(at[39], at[70]);    MULADD(at[40], at[69]);    MULADD(at[41], at[68]);    MULADD(at[42], at[67]);    MULADD(at[43], at[66]);    MULADD(at[44], at[65]);    MULADD(at[45], at[64]);
+   COMBA_STORE(C->dp[45]);
+   /* 46 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[110]);    MULADD(at[1], at[109]);    MULADD(at[2], at[108]);    MULADD(at[3], at[107]);    MULADD(at[4], at[106]);    MULADD(at[5], at[105]);    MULADD(at[6], at[104]);    MULADD(at[7], at[103]);    MULADD(at[8], at[102]);    MULADD(at[9], at[101]);    MULADD(at[10], at[100]);    MULADD(at[11], at[99]);    MULADD(at[12], at[98]);    MULADD(at[13], at[97]);    MULADD(at[14], at[96]);    MULADD(at[15], at[95]);    MULADD(at[16], at[94]);    MULADD(at[17], at[93]);    MULADD(at[18], at[92]);    MULADD(at[19], at[91]);    MULADD(at[20], at[90]);    MULADD(at[21], at[89]);    MULADD(at[22], at[88]);    MULADD(at[23], at[87]);    MULADD(at[24], at[86]);    MULADD(at[25], at[85]);    MULADD(at[26], at[84]);    MULADD(at[27], at[83]);    MULADD(at[28], at[82]);    MULADD(at[29], at[81]);    MULADD(at[30], at[80]);    MULADD(at[31], at[79]);    MULADD(at[32], at[78]);    MULADD(at[33], at[77]);    MULADD(at[34], at[76]);    MULADD(at[35], at[75]);    MULADD(at[36], at[74]);    MULADD(at[37], at[73]);    MULADD(at[38], at[72]);    MULADD(at[39], at[71]);    MULADD(at[40], at[70]);    MULADD(at[41], at[69]);    MULADD(at[42], at[68]);    MULADD(at[43], at[67]);    MULADD(at[44], at[66]);    MULADD(at[45], at[65]);    MULADD(at[46], at[64]);
+   COMBA_STORE(C->dp[46]);
+   /* 47 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[111]);    MULADD(at[1], at[110]);    MULADD(at[2], at[109]);    MULADD(at[3], at[108]);    MULADD(at[4], at[107]);    MULADD(at[5], at[106]);    MULADD(at[6], at[105]);    MULADD(at[7], at[104]);    MULADD(at[8], at[103]);    MULADD(at[9], at[102]);    MULADD(at[10], at[101]);    MULADD(at[11], at[100]);    MULADD(at[12], at[99]);    MULADD(at[13], at[98]);    MULADD(at[14], at[97]);    MULADD(at[15], at[96]);    MULADD(at[16], at[95]);    MULADD(at[17], at[94]);    MULADD(at[18], at[93]);    MULADD(at[19], at[92]);    MULADD(at[20], at[91]);    MULADD(at[21], at[90]);    MULADD(at[22], at[89]);    MULADD(at[23], at[88]);    MULADD(at[24], at[87]);    MULADD(at[25], at[86]);    MULADD(at[26], at[85]);    MULADD(at[27], at[84]);    MULADD(at[28], at[83]);    MULADD(at[29], at[82]);    MULADD(at[30], at[81]);    MULADD(at[31], at[80]);    MULADD(at[32], at[79]);    MULADD(at[33], at[78]);    MULADD(at[34], at[77]);    MULADD(at[35], at[76]);    MULADD(at[36], at[75]);    MULADD(at[37], at[74]);    MULADD(at[38], at[73]);    MULADD(at[39], at[72]);    MULADD(at[40], at[71]);    MULADD(at[41], at[70]);    MULADD(at[42], at[69]);    MULADD(at[43], at[68]);    MULADD(at[44], at[67]);    MULADD(at[45], at[66]);    MULADD(at[46], at[65]);    MULADD(at[47], at[64]);
+   COMBA_STORE(C->dp[47]);
+   /* 48 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[112]);    MULADD(at[1], at[111]);    MULADD(at[2], at[110]);    MULADD(at[3], at[109]);    MULADD(at[4], at[108]);    MULADD(at[5], at[107]);    MULADD(at[6], at[106]);    MULADD(at[7], at[105]);    MULADD(at[8], at[104]);    MULADD(at[9], at[103]);    MULADD(at[10], at[102]);    MULADD(at[11], at[101]);    MULADD(at[12], at[100]);    MULADD(at[13], at[99]);    MULADD(at[14], at[98]);    MULADD(at[15], at[97]);    MULADD(at[16], at[96]);    MULADD(at[17], at[95]);    MULADD(at[18], at[94]);    MULADD(at[19], at[93]);    MULADD(at[20], at[92]);    MULADD(at[21], at[91]);    MULADD(at[22], at[90]);    MULADD(at[23], at[89]);    MULADD(at[24], at[88]);    MULADD(at[25], at[87]);    MULADD(at[26], at[86]);    MULADD(at[27], at[85]);    MULADD(at[28], at[84]);    MULADD(at[29], at[83]);    MULADD(at[30], at[82]);    MULADD(at[31], at[81]);    MULADD(at[32], at[80]);    MULADD(at[33], at[79]);    MULADD(at[34], at[78]);    MULADD(at[35], at[77]);    MULADD(at[36], at[76]);    MULADD(at[37], at[75]);    MULADD(at[38], at[74]);    MULADD(at[39], at[73]);    MULADD(at[40], at[72]);    MULADD(at[41], at[71]);    MULADD(at[42], at[70]);    MULADD(at[43], at[69]);    MULADD(at[44], at[68]);    MULADD(at[45], at[67]);    MULADD(at[46], at[66]);    MULADD(at[47], at[65]);    MULADD(at[48], at[64]);
+   COMBA_STORE(C->dp[48]);
+   /* 49 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[113]);    MULADD(at[1], at[112]);    MULADD(at[2], at[111]);    MULADD(at[3], at[110]);    MULADD(at[4], at[109]);    MULADD(at[5], at[108]);    MULADD(at[6], at[107]);    MULADD(at[7], at[106]);    MULADD(at[8], at[105]);    MULADD(at[9], at[104]);    MULADD(at[10], at[103]);    MULADD(at[11], at[102]);    MULADD(at[12], at[101]);    MULADD(at[13], at[100]);    MULADD(at[14], at[99]);    MULADD(at[15], at[98]);    MULADD(at[16], at[97]);    MULADD(at[17], at[96]);    MULADD(at[18], at[95]);    MULADD(at[19], at[94]);    MULADD(at[20], at[93]);    MULADD(at[21], at[92]);    MULADD(at[22], at[91]);    MULADD(at[23], at[90]);    MULADD(at[24], at[89]);    MULADD(at[25], at[88]);    MULADD(at[26], at[87]);    MULADD(at[27], at[86]);    MULADD(at[28], at[85]);    MULADD(at[29], at[84]);    MULADD(at[30], at[83]);    MULADD(at[31], at[82]);    MULADD(at[32], at[81]);    MULADD(at[33], at[80]);    MULADD(at[34], at[79]);    MULADD(at[35], at[78]);    MULADD(at[36], at[77]);    MULADD(at[37], at[76]);    MULADD(at[38], at[75]);    MULADD(at[39], at[74]);    MULADD(at[40], at[73]);    MULADD(at[41], at[72]);    MULADD(at[42], at[71]);    MULADD(at[43], at[70]);    MULADD(at[44], at[69]);    MULADD(at[45], at[68]);    MULADD(at[46], at[67]);    MULADD(at[47], at[66]);    MULADD(at[48], at[65]);    MULADD(at[49], at[64]);
+   COMBA_STORE(C->dp[49]);
+   /* 50 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[114]);    MULADD(at[1], at[113]);    MULADD(at[2], at[112]);    MULADD(at[3], at[111]);    MULADD(at[4], at[110]);    MULADD(at[5], at[109]);    MULADD(at[6], at[108]);    MULADD(at[7], at[107]);    MULADD(at[8], at[106]);    MULADD(at[9], at[105]);    MULADD(at[10], at[104]);    MULADD(at[11], at[103]);    MULADD(at[12], at[102]);    MULADD(at[13], at[101]);    MULADD(at[14], at[100]);    MULADD(at[15], at[99]);    MULADD(at[16], at[98]);    MULADD(at[17], at[97]);    MULADD(at[18], at[96]);    MULADD(at[19], at[95]);    MULADD(at[20], at[94]);    MULADD(at[21], at[93]);    MULADD(at[22], at[92]);    MULADD(at[23], at[91]);    MULADD(at[24], at[90]);    MULADD(at[25], at[89]);    MULADD(at[26], at[88]);    MULADD(at[27], at[87]);    MULADD(at[28], at[86]);    MULADD(at[29], at[85]);    MULADD(at[30], at[84]);    MULADD(at[31], at[83]);    MULADD(at[32], at[82]);    MULADD(at[33], at[81]);    MULADD(at[34], at[80]);    MULADD(at[35], at[79]);    MULADD(at[36], at[78]);    MULADD(at[37], at[77]);    MULADD(at[38], at[76]);    MULADD(at[39], at[75]);    MULADD(at[40], at[74]);    MULADD(at[41], at[73]);    MULADD(at[42], at[72]);    MULADD(at[43], at[71]);    MULADD(at[44], at[70]);    MULADD(at[45], at[69]);    MULADD(at[46], at[68]);    MULADD(at[47], at[67]);    MULADD(at[48], at[66]);    MULADD(at[49], at[65]);    MULADD(at[50], at[64]);
+   COMBA_STORE(C->dp[50]);
+   /* 51 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[115]);    MULADD(at[1], at[114]);    MULADD(at[2], at[113]);    MULADD(at[3], at[112]);    MULADD(at[4], at[111]);    MULADD(at[5], at[110]);    MULADD(at[6], at[109]);    MULADD(at[7], at[108]);    MULADD(at[8], at[107]);    MULADD(at[9], at[106]);    MULADD(at[10], at[105]);    MULADD(at[11], at[104]);    MULADD(at[12], at[103]);    MULADD(at[13], at[102]);    MULADD(at[14], at[101]);    MULADD(at[15], at[100]);    MULADD(at[16], at[99]);    MULADD(at[17], at[98]);    MULADD(at[18], at[97]);    MULADD(at[19], at[96]);    MULADD(at[20], at[95]);    MULADD(at[21], at[94]);    MULADD(at[22], at[93]);    MULADD(at[23], at[92]);    MULADD(at[24], at[91]);    MULADD(at[25], at[90]);    MULADD(at[26], at[89]);    MULADD(at[27], at[88]);    MULADD(at[28], at[87]);    MULADD(at[29], at[86]);    MULADD(at[30], at[85]);    MULADD(at[31], at[84]);    MULADD(at[32], at[83]);    MULADD(at[33], at[82]);    MULADD(at[34], at[81]);    MULADD(at[35], at[80]);    MULADD(at[36], at[79]);    MULADD(at[37], at[78]);    MULADD(at[38], at[77]);    MULADD(at[39], at[76]);    MULADD(at[40], at[75]);    MULADD(at[41], at[74]);    MULADD(at[42], at[73]);    MULADD(at[43], at[72]);    MULADD(at[44], at[71]);    MULADD(at[45], at[70]);    MULADD(at[46], at[69]);    MULADD(at[47], at[68]);    MULADD(at[48], at[67]);    MULADD(at[49], at[66]);    MULADD(at[50], at[65]);    MULADD(at[51], at[64]);
+   COMBA_STORE(C->dp[51]);
+   /* 52 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[116]);    MULADD(at[1], at[115]);    MULADD(at[2], at[114]);    MULADD(at[3], at[113]);    MULADD(at[4], at[112]);    MULADD(at[5], at[111]);    MULADD(at[6], at[110]);    MULADD(at[7], at[109]);    MULADD(at[8], at[108]);    MULADD(at[9], at[107]);    MULADD(at[10], at[106]);    MULADD(at[11], at[105]);    MULADD(at[12], at[104]);    MULADD(at[13], at[103]);    MULADD(at[14], at[102]);    MULADD(at[15], at[101]);    MULADD(at[16], at[100]);    MULADD(at[17], at[99]);    MULADD(at[18], at[98]);    MULADD(at[19], at[97]);    MULADD(at[20], at[96]);    MULADD(at[21], at[95]);    MULADD(at[22], at[94]);    MULADD(at[23], at[93]);    MULADD(at[24], at[92]);    MULADD(at[25], at[91]);    MULADD(at[26], at[90]);    MULADD(at[27], at[89]);    MULADD(at[28], at[88]);    MULADD(at[29], at[87]);    MULADD(at[30], at[86]);    MULADD(at[31], at[85]);    MULADD(at[32], at[84]);    MULADD(at[33], at[83]);    MULADD(at[34], at[82]);    MULADD(at[35], at[81]);    MULADD(at[36], at[80]);    MULADD(at[37], at[79]);    MULADD(at[38], at[78]);    MULADD(at[39], at[77]);    MULADD(at[40], at[76]);    MULADD(at[41], at[75]);    MULADD(at[42], at[74]);    MULADD(at[43], at[73]);    MULADD(at[44], at[72]);    MULADD(at[45], at[71]);    MULADD(at[46], at[70]);    MULADD(at[47], at[69]);    MULADD(at[48], at[68]);    MULADD(at[49], at[67]);    MULADD(at[50], at[66]);    MULADD(at[51], at[65]);    MULADD(at[52], at[64]);
+   COMBA_STORE(C->dp[52]);
+   /* 53 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[117]);    MULADD(at[1], at[116]);    MULADD(at[2], at[115]);    MULADD(at[3], at[114]);    MULADD(at[4], at[113]);    MULADD(at[5], at[112]);    MULADD(at[6], at[111]);    MULADD(at[7], at[110]);    MULADD(at[8], at[109]);    MULADD(at[9], at[108]);    MULADD(at[10], at[107]);    MULADD(at[11], at[106]);    MULADD(at[12], at[105]);    MULADD(at[13], at[104]);    MULADD(at[14], at[103]);    MULADD(at[15], at[102]);    MULADD(at[16], at[101]);    MULADD(at[17], at[100]);    MULADD(at[18], at[99]);    MULADD(at[19], at[98]);    MULADD(at[20], at[97]);    MULADD(at[21], at[96]);    MULADD(at[22], at[95]);    MULADD(at[23], at[94]);    MULADD(at[24], at[93]);    MULADD(at[25], at[92]);    MULADD(at[26], at[91]);    MULADD(at[27], at[90]);    MULADD(at[28], at[89]);    MULADD(at[29], at[88]);    MULADD(at[30], at[87]);    MULADD(at[31], at[86]);    MULADD(at[32], at[85]);    MULADD(at[33], at[84]);    MULADD(at[34], at[83]);    MULADD(at[35], at[82]);    MULADD(at[36], at[81]);    MULADD(at[37], at[80]);    MULADD(at[38], at[79]);    MULADD(at[39], at[78]);    MULADD(at[40], at[77]);    MULADD(at[41], at[76]);    MULADD(at[42], at[75]);    MULADD(at[43], at[74]);    MULADD(at[44], at[73]);    MULADD(at[45], at[72]);    MULADD(at[46], at[71]);    MULADD(at[47], at[70]);    MULADD(at[48], at[69]);    MULADD(at[49], at[68]);    MULADD(at[50], at[67]);    MULADD(at[51], at[66]);    MULADD(at[52], at[65]);    MULADD(at[53], at[64]);
+   COMBA_STORE(C->dp[53]);
+   /* 54 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[118]);    MULADD(at[1], at[117]);    MULADD(at[2], at[116]);    MULADD(at[3], at[115]);    MULADD(at[4], at[114]);    MULADD(at[5], at[113]);    MULADD(at[6], at[112]);    MULADD(at[7], at[111]);    MULADD(at[8], at[110]);    MULADD(at[9], at[109]);    MULADD(at[10], at[108]);    MULADD(at[11], at[107]);    MULADD(at[12], at[106]);    MULADD(at[13], at[105]);    MULADD(at[14], at[104]);    MULADD(at[15], at[103]);    MULADD(at[16], at[102]);    MULADD(at[17], at[101]);    MULADD(at[18], at[100]);    MULADD(at[19], at[99]);    MULADD(at[20], at[98]);    MULADD(at[21], at[97]);    MULADD(at[22], at[96]);    MULADD(at[23], at[95]);    MULADD(at[24], at[94]);    MULADD(at[25], at[93]);    MULADD(at[26], at[92]);    MULADD(at[27], at[91]);    MULADD(at[28], at[90]);    MULADD(at[29], at[89]);    MULADD(at[30], at[88]);    MULADD(at[31], at[87]);    MULADD(at[32], at[86]);    MULADD(at[33], at[85]);    MULADD(at[34], at[84]);    MULADD(at[35], at[83]);    MULADD(at[36], at[82]);    MULADD(at[37], at[81]);    MULADD(at[38], at[80]);    MULADD(at[39], at[79]);    MULADD(at[40], at[78]);    MULADD(at[41], at[77]);    MULADD(at[42], at[76]);    MULADD(at[43], at[75]);    MULADD(at[44], at[74]);    MULADD(at[45], at[73]);    MULADD(at[46], at[72]);    MULADD(at[47], at[71]);    MULADD(at[48], at[70]);    MULADD(at[49], at[69]);    MULADD(at[50], at[68]);    MULADD(at[51], at[67]);    MULADD(at[52], at[66]);    MULADD(at[53], at[65]);    MULADD(at[54], at[64]);
+   COMBA_STORE(C->dp[54]);
+   /* 55 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[119]);    MULADD(at[1], at[118]);    MULADD(at[2], at[117]);    MULADD(at[3], at[116]);    MULADD(at[4], at[115]);    MULADD(at[5], at[114]);    MULADD(at[6], at[113]);    MULADD(at[7], at[112]);    MULADD(at[8], at[111]);    MULADD(at[9], at[110]);    MULADD(at[10], at[109]);    MULADD(at[11], at[108]);    MULADD(at[12], at[107]);    MULADD(at[13], at[106]);    MULADD(at[14], at[105]);    MULADD(at[15], at[104]);    MULADD(at[16], at[103]);    MULADD(at[17], at[102]);    MULADD(at[18], at[101]);    MULADD(at[19], at[100]);    MULADD(at[20], at[99]);    MULADD(at[21], at[98]);    MULADD(at[22], at[97]);    MULADD(at[23], at[96]);    MULADD(at[24], at[95]);    MULADD(at[25], at[94]);    MULADD(at[26], at[93]);    MULADD(at[27], at[92]);    MULADD(at[28], at[91]);    MULADD(at[29], at[90]);    MULADD(at[30], at[89]);    MULADD(at[31], at[88]);    MULADD(at[32], at[87]);    MULADD(at[33], at[86]);    MULADD(at[34], at[85]);    MULADD(at[35], at[84]);    MULADD(at[36], at[83]);    MULADD(at[37], at[82]);    MULADD(at[38], at[81]);    MULADD(at[39], at[80]);    MULADD(at[40], at[79]);    MULADD(at[41], at[78]);    MULADD(at[42], at[77]);    MULADD(at[43], at[76]);    MULADD(at[44], at[75]);    MULADD(at[45], at[74]);    MULADD(at[46], at[73]);    MULADD(at[47], at[72]);    MULADD(at[48], at[71]);    MULADD(at[49], at[70]);    MULADD(at[50], at[69]);    MULADD(at[51], at[68]);    MULADD(at[52], at[67]);    MULADD(at[53], at[66]);    MULADD(at[54], at[65]);    MULADD(at[55], at[64]);
+   COMBA_STORE(C->dp[55]);
+   /* 56 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[120]);    MULADD(at[1], at[119]);    MULADD(at[2], at[118]);    MULADD(at[3], at[117]);    MULADD(at[4], at[116]);    MULADD(at[5], at[115]);    MULADD(at[6], at[114]);    MULADD(at[7], at[113]);    MULADD(at[8], at[112]);    MULADD(at[9], at[111]);    MULADD(at[10], at[110]);    MULADD(at[11], at[109]);    MULADD(at[12], at[108]);    MULADD(at[13], at[107]);    MULADD(at[14], at[106]);    MULADD(at[15], at[105]);    MULADD(at[16], at[104]);    MULADD(at[17], at[103]);    MULADD(at[18], at[102]);    MULADD(at[19], at[101]);    MULADD(at[20], at[100]);    MULADD(at[21], at[99]);    MULADD(at[22], at[98]);    MULADD(at[23], at[97]);    MULADD(at[24], at[96]);    MULADD(at[25], at[95]);    MULADD(at[26], at[94]);    MULADD(at[27], at[93]);    MULADD(at[28], at[92]);    MULADD(at[29], at[91]);    MULADD(at[30], at[90]);    MULADD(at[31], at[89]);    MULADD(at[32], at[88]);    MULADD(at[33], at[87]);    MULADD(at[34], at[86]);    MULADD(at[35], at[85]);    MULADD(at[36], at[84]);    MULADD(at[37], at[83]);    MULADD(at[38], at[82]);    MULADD(at[39], at[81]);    MULADD(at[40], at[80]);    MULADD(at[41], at[79]);    MULADD(at[42], at[78]);    MULADD(at[43], at[77]);    MULADD(at[44], at[76]);    MULADD(at[45], at[75]);    MULADD(at[46], at[74]);    MULADD(at[47], at[73]);    MULADD(at[48], at[72]);    MULADD(at[49], at[71]);    MULADD(at[50], at[70]);    MULADD(at[51], at[69]);    MULADD(at[52], at[68]);    MULADD(at[53], at[67]);    MULADD(at[54], at[66]);    MULADD(at[55], at[65]);    MULADD(at[56], at[64]);
+   COMBA_STORE(C->dp[56]);
+   /* 57 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[121]);    MULADD(at[1], at[120]);    MULADD(at[2], at[119]);    MULADD(at[3], at[118]);    MULADD(at[4], at[117]);    MULADD(at[5], at[116]);    MULADD(at[6], at[115]);    MULADD(at[7], at[114]);    MULADD(at[8], at[113]);    MULADD(at[9], at[112]);    MULADD(at[10], at[111]);    MULADD(at[11], at[110]);    MULADD(at[12], at[109]);    MULADD(at[13], at[108]);    MULADD(at[14], at[107]);    MULADD(at[15], at[106]);    MULADD(at[16], at[105]);    MULADD(at[17], at[104]);    MULADD(at[18], at[103]);    MULADD(at[19], at[102]);    MULADD(at[20], at[101]);    MULADD(at[21], at[100]);    MULADD(at[22], at[99]);    MULADD(at[23], at[98]);    MULADD(at[24], at[97]);    MULADD(at[25], at[96]);    MULADD(at[26], at[95]);    MULADD(at[27], at[94]);    MULADD(at[28], at[93]);    MULADD(at[29], at[92]);    MULADD(at[30], at[91]);    MULADD(at[31], at[90]);    MULADD(at[32], at[89]);    MULADD(at[33], at[88]);    MULADD(at[34], at[87]);    MULADD(at[35], at[86]);    MULADD(at[36], at[85]);    MULADD(at[37], at[84]);    MULADD(at[38], at[83]);    MULADD(at[39], at[82]);    MULADD(at[40], at[81]);    MULADD(at[41], at[80]);    MULADD(at[42], at[79]);    MULADD(at[43], at[78]);    MULADD(at[44], at[77]);    MULADD(at[45], at[76]);    MULADD(at[46], at[75]);    MULADD(at[47], at[74]);    MULADD(at[48], at[73]);    MULADD(at[49], at[72]);    MULADD(at[50], at[71]);    MULADD(at[51], at[70]);    MULADD(at[52], at[69]);    MULADD(at[53], at[68]);    MULADD(at[54], at[67]);    MULADD(at[55], at[66]);    MULADD(at[56], at[65]);    MULADD(at[57], at[64]);
+   COMBA_STORE(C->dp[57]);
+   /* 58 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[122]);    MULADD(at[1], at[121]);    MULADD(at[2], at[120]);    MULADD(at[3], at[119]);    MULADD(at[4], at[118]);    MULADD(at[5], at[117]);    MULADD(at[6], at[116]);    MULADD(at[7], at[115]);    MULADD(at[8], at[114]);    MULADD(at[9], at[113]);    MULADD(at[10], at[112]);    MULADD(at[11], at[111]);    MULADD(at[12], at[110]);    MULADD(at[13], at[109]);    MULADD(at[14], at[108]);    MULADD(at[15], at[107]);    MULADD(at[16], at[106]);    MULADD(at[17], at[105]);    MULADD(at[18], at[104]);    MULADD(at[19], at[103]);    MULADD(at[20], at[102]);    MULADD(at[21], at[101]);    MULADD(at[22], at[100]);    MULADD(at[23], at[99]);    MULADD(at[24], at[98]);    MULADD(at[25], at[97]);    MULADD(at[26], at[96]);    MULADD(at[27], at[95]);    MULADD(at[28], at[94]);    MULADD(at[29], at[93]);    MULADD(at[30], at[92]);    MULADD(at[31], at[91]);    MULADD(at[32], at[90]);    MULADD(at[33], at[89]);    MULADD(at[34], at[88]);    MULADD(at[35], at[87]);    MULADD(at[36], at[86]);    MULADD(at[37], at[85]);    MULADD(at[38], at[84]);    MULADD(at[39], at[83]);    MULADD(at[40], at[82]);    MULADD(at[41], at[81]);    MULADD(at[42], at[80]);    MULADD(at[43], at[79]);    MULADD(at[44], at[78]);    MULADD(at[45], at[77]);    MULADD(at[46], at[76]);    MULADD(at[47], at[75]);    MULADD(at[48], at[74]);    MULADD(at[49], at[73]);    MULADD(at[50], at[72]);    MULADD(at[51], at[71]);    MULADD(at[52], at[70]);    MULADD(at[53], at[69]);    MULADD(at[54], at[68]);    MULADD(at[55], at[67]);    MULADD(at[56], at[66]);    MULADD(at[57], at[65]);    MULADD(at[58], at[64]);
+   COMBA_STORE(C->dp[58]);
+   /* 59 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[123]);    MULADD(at[1], at[122]);    MULADD(at[2], at[121]);    MULADD(at[3], at[120]);    MULADD(at[4], at[119]);    MULADD(at[5], at[118]);    MULADD(at[6], at[117]);    MULADD(at[7], at[116]);    MULADD(at[8], at[115]);    MULADD(at[9], at[114]);    MULADD(at[10], at[113]);    MULADD(at[11], at[112]);    MULADD(at[12], at[111]);    MULADD(at[13], at[110]);    MULADD(at[14], at[109]);    MULADD(at[15], at[108]);    MULADD(at[16], at[107]);    MULADD(at[17], at[106]);    MULADD(at[18], at[105]);    MULADD(at[19], at[104]);    MULADD(at[20], at[103]);    MULADD(at[21], at[102]);    MULADD(at[22], at[101]);    MULADD(at[23], at[100]);    MULADD(at[24], at[99]);    MULADD(at[25], at[98]);    MULADD(at[26], at[97]);    MULADD(at[27], at[96]);    MULADD(at[28], at[95]);    MULADD(at[29], at[94]);    MULADD(at[30], at[93]);    MULADD(at[31], at[92]);    MULADD(at[32], at[91]);    MULADD(at[33], at[90]);    MULADD(at[34], at[89]);    MULADD(at[35], at[88]);    MULADD(at[36], at[87]);    MULADD(at[37], at[86]);    MULADD(at[38], at[85]);    MULADD(at[39], at[84]);    MULADD(at[40], at[83]);    MULADD(at[41], at[82]);    MULADD(at[42], at[81]);    MULADD(at[43], at[80]);    MULADD(at[44], at[79]);    MULADD(at[45], at[78]);    MULADD(at[46], at[77]);    MULADD(at[47], at[76]);    MULADD(at[48], at[75]);    MULADD(at[49], at[74]);    MULADD(at[50], at[73]);    MULADD(at[51], at[72]);    MULADD(at[52], at[71]);    MULADD(at[53], at[70]);    MULADD(at[54], at[69]);    MULADD(at[55], at[68]);    MULADD(at[56], at[67]);    MULADD(at[57], at[66]);    MULADD(at[58], at[65]);    MULADD(at[59], at[64]);
+   COMBA_STORE(C->dp[59]);
+   /* 60 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[124]);    MULADD(at[1], at[123]);    MULADD(at[2], at[122]);    MULADD(at[3], at[121]);    MULADD(at[4], at[120]);    MULADD(at[5], at[119]);    MULADD(at[6], at[118]);    MULADD(at[7], at[117]);    MULADD(at[8], at[116]);    MULADD(at[9], at[115]);    MULADD(at[10], at[114]);    MULADD(at[11], at[113]);    MULADD(at[12], at[112]);    MULADD(at[13], at[111]);    MULADD(at[14], at[110]);    MULADD(at[15], at[109]);    MULADD(at[16], at[108]);    MULADD(at[17], at[107]);    MULADD(at[18], at[106]);    MULADD(at[19], at[105]);    MULADD(at[20], at[104]);    MULADD(at[21], at[103]);    MULADD(at[22], at[102]);    MULADD(at[23], at[101]);    MULADD(at[24], at[100]);    MULADD(at[25], at[99]);    MULADD(at[26], at[98]);    MULADD(at[27], at[97]);    MULADD(at[28], at[96]);    MULADD(at[29], at[95]);    MULADD(at[30], at[94]);    MULADD(at[31], at[93]);    MULADD(at[32], at[92]);    MULADD(at[33], at[91]);    MULADD(at[34], at[90]);    MULADD(at[35], at[89]);    MULADD(at[36], at[88]);    MULADD(at[37], at[87]);    MULADD(at[38], at[86]);    MULADD(at[39], at[85]);    MULADD(at[40], at[84]);    MULADD(at[41], at[83]);    MULADD(at[42], at[82]);    MULADD(at[43], at[81]);    MULADD(at[44], at[80]);    MULADD(at[45], at[79]);    MULADD(at[46], at[78]);    MULADD(at[47], at[77]);    MULADD(at[48], at[76]);    MULADD(at[49], at[75]);    MULADD(at[50], at[74]);    MULADD(at[51], at[73]);    MULADD(at[52], at[72]);    MULADD(at[53], at[71]);    MULADD(at[54], at[70]);    MULADD(at[55], at[69]);    MULADD(at[56], at[68]);    MULADD(at[57], at[67]);    MULADD(at[58], at[66]);    MULADD(at[59], at[65]);    MULADD(at[60], at[64]);
+   COMBA_STORE(C->dp[60]);
+   /* 61 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[125]);    MULADD(at[1], at[124]);    MULADD(at[2], at[123]);    MULADD(at[3], at[122]);    MULADD(at[4], at[121]);    MULADD(at[5], at[120]);    MULADD(at[6], at[119]);    MULADD(at[7], at[118]);    MULADD(at[8], at[117]);    MULADD(at[9], at[116]);    MULADD(at[10], at[115]);    MULADD(at[11], at[114]);    MULADD(at[12], at[113]);    MULADD(at[13], at[112]);    MULADD(at[14], at[111]);    MULADD(at[15], at[110]);    MULADD(at[16], at[109]);    MULADD(at[17], at[108]);    MULADD(at[18], at[107]);    MULADD(at[19], at[106]);    MULADD(at[20], at[105]);    MULADD(at[21], at[104]);    MULADD(at[22], at[103]);    MULADD(at[23], at[102]);    MULADD(at[24], at[101]);    MULADD(at[25], at[100]);    MULADD(at[26], at[99]);    MULADD(at[27], at[98]);    MULADD(at[28], at[97]);    MULADD(at[29], at[96]);    MULADD(at[30], at[95]);    MULADD(at[31], at[94]);    MULADD(at[32], at[93]);    MULADD(at[33], at[92]);    MULADD(at[34], at[91]);    MULADD(at[35], at[90]);    MULADD(at[36], at[89]);    MULADD(at[37], at[88]);    MULADD(at[38], at[87]);    MULADD(at[39], at[86]);    MULADD(at[40], at[85]);    MULADD(at[41], at[84]);    MULADD(at[42], at[83]);    MULADD(at[43], at[82]);    MULADD(at[44], at[81]);    MULADD(at[45], at[80]);    MULADD(at[46], at[79]);    MULADD(at[47], at[78]);    MULADD(at[48], at[77]);    MULADD(at[49], at[76]);    MULADD(at[50], at[75]);    MULADD(at[51], at[74]);    MULADD(at[52], at[73]);    MULADD(at[53], at[72]);    MULADD(at[54], at[71]);    MULADD(at[55], at[70]);    MULADD(at[56], at[69]);    MULADD(at[57], at[68]);    MULADD(at[58], at[67]);    MULADD(at[59], at[66]);    MULADD(at[60], at[65]);    MULADD(at[61], at[64]);
+   COMBA_STORE(C->dp[61]);
+   /* 62 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[126]);    MULADD(at[1], at[125]);    MULADD(at[2], at[124]);    MULADD(at[3], at[123]);    MULADD(at[4], at[122]);    MULADD(at[5], at[121]);    MULADD(at[6], at[120]);    MULADD(at[7], at[119]);    MULADD(at[8], at[118]);    MULADD(at[9], at[117]);    MULADD(at[10], at[116]);    MULADD(at[11], at[115]);    MULADD(at[12], at[114]);    MULADD(at[13], at[113]);    MULADD(at[14], at[112]);    MULADD(at[15], at[111]);    MULADD(at[16], at[110]);    MULADD(at[17], at[109]);    MULADD(at[18], at[108]);    MULADD(at[19], at[107]);    MULADD(at[20], at[106]);    MULADD(at[21], at[105]);    MULADD(at[22], at[104]);    MULADD(at[23], at[103]);    MULADD(at[24], at[102]);    MULADD(at[25], at[101]);    MULADD(at[26], at[100]);    MULADD(at[27], at[99]);    MULADD(at[28], at[98]);    MULADD(at[29], at[97]);    MULADD(at[30], at[96]);    MULADD(at[31], at[95]);    MULADD(at[32], at[94]);    MULADD(at[33], at[93]);    MULADD(at[34], at[92]);    MULADD(at[35], at[91]);    MULADD(at[36], at[90]);    MULADD(at[37], at[89]);    MULADD(at[38], at[88]);    MULADD(at[39], at[87]);    MULADD(at[40], at[86]);    MULADD(at[41], at[85]);    MULADD(at[42], at[84]);    MULADD(at[43], at[83]);    MULADD(at[44], at[82]);    MULADD(at[45], at[81]);    MULADD(at[46], at[80]);    MULADD(at[47], at[79]);    MULADD(at[48], at[78]);    MULADD(at[49], at[77]);    MULADD(at[50], at[76]);    MULADD(at[51], at[75]);    MULADD(at[52], at[74]);    MULADD(at[53], at[73]);    MULADD(at[54], at[72]);    MULADD(at[55], at[71]);    MULADD(at[56], at[70]);    MULADD(at[57], at[69]);    MULADD(at[58], at[68]);    MULADD(at[59], at[67]);    MULADD(at[60], at[66]);    MULADD(at[61], at[65]);    MULADD(at[62], at[64]);
+   COMBA_STORE(C->dp[62]);
+   /* 63 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[127]);    MULADD(at[1], at[126]);    MULADD(at[2], at[125]);    MULADD(at[3], at[124]);    MULADD(at[4], at[123]);    MULADD(at[5], at[122]);    MULADD(at[6], at[121]);    MULADD(at[7], at[120]);    MULADD(at[8], at[119]);    MULADD(at[9], at[118]);    MULADD(at[10], at[117]);    MULADD(at[11], at[116]);    MULADD(at[12], at[115]);    MULADD(at[13], at[114]);    MULADD(at[14], at[113]);    MULADD(at[15], at[112]);    MULADD(at[16], at[111]);    MULADD(at[17], at[110]);    MULADD(at[18], at[109]);    MULADD(at[19], at[108]);    MULADD(at[20], at[107]);    MULADD(at[21], at[106]);    MULADD(at[22], at[105]);    MULADD(at[23], at[104]);    MULADD(at[24], at[103]);    MULADD(at[25], at[102]);    MULADD(at[26], at[101]);    MULADD(at[27], at[100]);    MULADD(at[28], at[99]);    MULADD(at[29], at[98]);    MULADD(at[30], at[97]);    MULADD(at[31], at[96]);    MULADD(at[32], at[95]);    MULADD(at[33], at[94]);    MULADD(at[34], at[93]);    MULADD(at[35], at[92]);    MULADD(at[36], at[91]);    MULADD(at[37], at[90]);    MULADD(at[38], at[89]);    MULADD(at[39], at[88]);    MULADD(at[40], at[87]);    MULADD(at[41], at[86]);    MULADD(at[42], at[85]);    MULADD(at[43], at[84]);    MULADD(at[44], at[83]);    MULADD(at[45], at[82]);    MULADD(at[46], at[81]);    MULADD(at[47], at[80]);    MULADD(at[48], at[79]);    MULADD(at[49], at[78]);    MULADD(at[50], at[77]);    MULADD(at[51], at[76]);    MULADD(at[52], at[75]);    MULADD(at[53], at[74]);    MULADD(at[54], at[73]);    MULADD(at[55], at[72]);    MULADD(at[56], at[71]);    MULADD(at[57], at[70]);    MULADD(at[58], at[69]);    MULADD(at[59], at[68]);    MULADD(at[60], at[67]);    MULADD(at[61], at[66]);    MULADD(at[62], at[65]);    MULADD(at[63], at[64]);
+   COMBA_STORE(C->dp[63]);
+   /* 64 */
+   COMBA_FORWARD;
+   MULADD(at[1], at[127]);    MULADD(at[2], at[126]);    MULADD(at[3], at[125]);    MULADD(at[4], at[124]);    MULADD(at[5], at[123]);    MULADD(at[6], at[122]);    MULADD(at[7], at[121]);    MULADD(at[8], at[120]);    MULADD(at[9], at[119]);    MULADD(at[10], at[118]);    MULADD(at[11], at[117]);    MULADD(at[12], at[116]);    MULADD(at[13], at[115]);    MULADD(at[14], at[114]);    MULADD(at[15], at[113]);    MULADD(at[16], at[112]);    MULADD(at[17], at[111]);    MULADD(at[18], at[110]);    MULADD(at[19], at[109]);    MULADD(at[20], at[108]);    MULADD(at[21], at[107]);    MULADD(at[22], at[106]);    MULADD(at[23], at[105]);    MULADD(at[24], at[104]);    MULADD(at[25], at[103]);    MULADD(at[26], at[102]);    MULADD(at[27], at[101]);    MULADD(at[28], at[100]);    MULADD(at[29], at[99]);    MULADD(at[30], at[98]);    MULADD(at[31], at[97]);    MULADD(at[32], at[96]);    MULADD(at[33], at[95]);    MULADD(at[34], at[94]);    MULADD(at[35], at[93]);    MULADD(at[36], at[92]);    MULADD(at[37], at[91]);    MULADD(at[38], at[90]);    MULADD(at[39], at[89]);    MULADD(at[40], at[88]);    MULADD(at[41], at[87]);    MULADD(at[42], at[86]);    MULADD(at[43], at[85]);    MULADD(at[44], at[84]);    MULADD(at[45], at[83]);    MULADD(at[46], at[82]);    MULADD(at[47], at[81]);    MULADD(at[48], at[80]);    MULADD(at[49], at[79]);    MULADD(at[50], at[78]);    MULADD(at[51], at[77]);    MULADD(at[52], at[76]);    MULADD(at[53], at[75]);    MULADD(at[54], at[74]);    MULADD(at[55], at[73]);    MULADD(at[56], at[72]);    MULADD(at[57], at[71]);    MULADD(at[58], at[70]);    MULADD(at[59], at[69]);    MULADD(at[60], at[68]);    MULADD(at[61], at[67]);    MULADD(at[62], at[66]);    MULADD(at[63], at[65]);
+   COMBA_STORE(C->dp[64]);
+   /* 65 */
+   COMBA_FORWARD;
+   MULADD(at[2], at[127]);    MULADD(at[3], at[126]);    MULADD(at[4], at[125]);    MULADD(at[5], at[124]);    MULADD(at[6], at[123]);    MULADD(at[7], at[122]);    MULADD(at[8], at[121]);    MULADD(at[9], at[120]);    MULADD(at[10], at[119]);    MULADD(at[11], at[118]);    MULADD(at[12], at[117]);    MULADD(at[13], at[116]);    MULADD(at[14], at[115]);    MULADD(at[15], at[114]);    MULADD(at[16], at[113]);    MULADD(at[17], at[112]);    MULADD(at[18], at[111]);    MULADD(at[19], at[110]);    MULADD(at[20], at[109]);    MULADD(at[21], at[108]);    MULADD(at[22], at[107]);    MULADD(at[23], at[106]);    MULADD(at[24], at[105]);    MULADD(at[25], at[104]);    MULADD(at[26], at[103]);    MULADD(at[27], at[102]);    MULADD(at[28], at[101]);    MULADD(at[29], at[100]);    MULADD(at[30], at[99]);    MULADD(at[31], at[98]);    MULADD(at[32], at[97]);    MULADD(at[33], at[96]);    MULADD(at[34], at[95]);    MULADD(at[35], at[94]);    MULADD(at[36], at[93]);    MULADD(at[37], at[92]);    MULADD(at[38], at[91]);    MULADD(at[39], at[90]);    MULADD(at[40], at[89]);    MULADD(at[41], at[88]);    MULADD(at[42], at[87]);    MULADD(at[43], at[86]);    MULADD(at[44], at[85]);    MULADD(at[45], at[84]);    MULADD(at[46], at[83]);    MULADD(at[47], at[82]);    MULADD(at[48], at[81]);    MULADD(at[49], at[80]);    MULADD(at[50], at[79]);    MULADD(at[51], at[78]);    MULADD(at[52], at[77]);    MULADD(at[53], at[76]);    MULADD(at[54], at[75]);    MULADD(at[55], at[74]);    MULADD(at[56], at[73]);    MULADD(at[57], at[72]);    MULADD(at[58], at[71]);    MULADD(at[59], at[70]);    MULADD(at[60], at[69]);    MULADD(at[61], at[68]);    MULADD(at[62], at[67]);    MULADD(at[63], at[66]);
+   COMBA_STORE(C->dp[65]);
+   /* 66 */
+   COMBA_FORWARD;
+   MULADD(at[3], at[127]);    MULADD(at[4], at[126]);    MULADD(at[5], at[125]);    MULADD(at[6], at[124]);    MULADD(at[7], at[123]);    MULADD(at[8], at[122]);    MULADD(at[9], at[121]);    MULADD(at[10], at[120]);    MULADD(at[11], at[119]);    MULADD(at[12], at[118]);    MULADD(at[13], at[117]);    MULADD(at[14], at[116]);    MULADD(at[15], at[115]);    MULADD(at[16], at[114]);    MULADD(at[17], at[113]);    MULADD(at[18], at[112]);    MULADD(at[19], at[111]);    MULADD(at[20], at[110]);    MULADD(at[21], at[109]);    MULADD(at[22], at[108]);    MULADD(at[23], at[107]);    MULADD(at[24], at[106]);    MULADD(at[25], at[105]);    MULADD(at[26], at[104]);    MULADD(at[27], at[103]);    MULADD(at[28], at[102]);    MULADD(at[29], at[101]);    MULADD(at[30], at[100]);    MULADD(at[31], at[99]);    MULADD(at[32], at[98]);    MULADD(at[33], at[97]);    MULADD(at[34], at[96]);    MULADD(at[35], at[95]);    MULADD(at[36], at[94]);    MULADD(at[37], at[93]);    MULADD(at[38], at[92]);    MULADD(at[39], at[91]);    MULADD(at[40], at[90]);    MULADD(at[41], at[89]);    MULADD(at[42], at[88]);    MULADD(at[43], at[87]);    MULADD(at[44], at[86]);    MULADD(at[45], at[85]);    MULADD(at[46], at[84]);    MULADD(at[47], at[83]);    MULADD(at[48], at[82]);    MULADD(at[49], at[81]);    MULADD(at[50], at[80]);    MULADD(at[51], at[79]);    MULADD(at[52], at[78]);    MULADD(at[53], at[77]);    MULADD(at[54], at[76]);    MULADD(at[55], at[75]);    MULADD(at[56], at[74]);    MULADD(at[57], at[73]);    MULADD(at[58], at[72]);    MULADD(at[59], at[71]);    MULADD(at[60], at[70]);    MULADD(at[61], at[69]);    MULADD(at[62], at[68]);    MULADD(at[63], at[67]);
+   COMBA_STORE(C->dp[66]);
+   /* 67 */
+   COMBA_FORWARD;
+   MULADD(at[4], at[127]);    MULADD(at[5], at[126]);    MULADD(at[6], at[125]);    MULADD(at[7], at[124]);    MULADD(at[8], at[123]);    MULADD(at[9], at[122]);    MULADD(at[10], at[121]);    MULADD(at[11], at[120]);    MULADD(at[12], at[119]);    MULADD(at[13], at[118]);    MULADD(at[14], at[117]);    MULADD(at[15], at[116]);    MULADD(at[16], at[115]);    MULADD(at[17], at[114]);    MULADD(at[18], at[113]);    MULADD(at[19], at[112]);    MULADD(at[20], at[111]);    MULADD(at[21], at[110]);    MULADD(at[22], at[109]);    MULADD(at[23], at[108]);    MULADD(at[24], at[107]);    MULADD(at[25], at[106]);    MULADD(at[26], at[105]);    MULADD(at[27], at[104]);    MULADD(at[28], at[103]);    MULADD(at[29], at[102]);    MULADD(at[30], at[101]);    MULADD(at[31], at[100]);    MULADD(at[32], at[99]);    MULADD(at[33], at[98]);    MULADD(at[34], at[97]);    MULADD(at[35], at[96]);    MULADD(at[36], at[95]);    MULADD(at[37], at[94]);    MULADD(at[38], at[93]);    MULADD(at[39], at[92]);    MULADD(at[40], at[91]);    MULADD(at[41], at[90]);    MULADD(at[42], at[89]);    MULADD(at[43], at[88]);    MULADD(at[44], at[87]);    MULADD(at[45], at[86]);    MULADD(at[46], at[85]);    MULADD(at[47], at[84]);    MULADD(at[48], at[83]);    MULADD(at[49], at[82]);    MULADD(at[50], at[81]);    MULADD(at[51], at[80]);    MULADD(at[52], at[79]);    MULADD(at[53], at[78]);    MULADD(at[54], at[77]);    MULADD(at[55], at[76]);    MULADD(at[56], at[75]);    MULADD(at[57], at[74]);    MULADD(at[58], at[73]);    MULADD(at[59], at[72]);    MULADD(at[60], at[71]);    MULADD(at[61], at[70]);    MULADD(at[62], at[69]);    MULADD(at[63], at[68]);
+   COMBA_STORE(C->dp[67]);
+   /* 68 */
+   COMBA_FORWARD;
+   MULADD(at[5], at[127]);    MULADD(at[6], at[126]);    MULADD(at[7], at[125]);    MULADD(at[8], at[124]);    MULADD(at[9], at[123]);    MULADD(at[10], at[122]);    MULADD(at[11], at[121]);    MULADD(at[12], at[120]);    MULADD(at[13], at[119]);    MULADD(at[14], at[118]);    MULADD(at[15], at[117]);    MULADD(at[16], at[116]);    MULADD(at[17], at[115]);    MULADD(at[18], at[114]);    MULADD(at[19], at[113]);    MULADD(at[20], at[112]);    MULADD(at[21], at[111]);    MULADD(at[22], at[110]);    MULADD(at[23], at[109]);    MULADD(at[24], at[108]);    MULADD(at[25], at[107]);    MULADD(at[26], at[106]);    MULADD(at[27], at[105]);    MULADD(at[28], at[104]);    MULADD(at[29], at[103]);    MULADD(at[30], at[102]);    MULADD(at[31], at[101]);    MULADD(at[32], at[100]);    MULADD(at[33], at[99]);    MULADD(at[34], at[98]);    MULADD(at[35], at[97]);    MULADD(at[36], at[96]);    MULADD(at[37], at[95]);    MULADD(at[38], at[94]);    MULADD(at[39], at[93]);    MULADD(at[40], at[92]);    MULADD(at[41], at[91]);    MULADD(at[42], at[90]);    MULADD(at[43], at[89]);    MULADD(at[44], at[88]);    MULADD(at[45], at[87]);    MULADD(at[46], at[86]);    MULADD(at[47], at[85]);    MULADD(at[48], at[84]);    MULADD(at[49], at[83]);    MULADD(at[50], at[82]);    MULADD(at[51], at[81]);    MULADD(at[52], at[80]);    MULADD(at[53], at[79]);    MULADD(at[54], at[78]);    MULADD(at[55], at[77]);    MULADD(at[56], at[76]);    MULADD(at[57], at[75]);    MULADD(at[58], at[74]);    MULADD(at[59], at[73]);    MULADD(at[60], at[72]);    MULADD(at[61], at[71]);    MULADD(at[62], at[70]);    MULADD(at[63], at[69]);
+   COMBA_STORE(C->dp[68]);
+   /* 69 */
+   COMBA_FORWARD;
+   MULADD(at[6], at[127]);    MULADD(at[7], at[126]);    MULADD(at[8], at[125]);    MULADD(at[9], at[124]);    MULADD(at[10], at[123]);    MULADD(at[11], at[122]);    MULADD(at[12], at[121]);    MULADD(at[13], at[120]);    MULADD(at[14], at[119]);    MULADD(at[15], at[118]);    MULADD(at[16], at[117]);    MULADD(at[17], at[116]);    MULADD(at[18], at[115]);    MULADD(at[19], at[114]);    MULADD(at[20], at[113]);    MULADD(at[21], at[112]);    MULADD(at[22], at[111]);    MULADD(at[23], at[110]);    MULADD(at[24], at[109]);    MULADD(at[25], at[108]);    MULADD(at[26], at[107]);    MULADD(at[27], at[106]);    MULADD(at[28], at[105]);    MULADD(at[29], at[104]);    MULADD(at[30], at[103]);    MULADD(at[31], at[102]);    MULADD(at[32], at[101]);    MULADD(at[33], at[100]);    MULADD(at[34], at[99]);    MULADD(at[35], at[98]);    MULADD(at[36], at[97]);    MULADD(at[37], at[96]);    MULADD(at[38], at[95]);    MULADD(at[39], at[94]);    MULADD(at[40], at[93]);    MULADD(at[41], at[92]);    MULADD(at[42], at[91]);    MULADD(at[43], at[90]);    MULADD(at[44], at[89]);    MULADD(at[45], at[88]);    MULADD(at[46], at[87]);    MULADD(at[47], at[86]);    MULADD(at[48], at[85]);    MULADD(at[49], at[84]);    MULADD(at[50], at[83]);    MULADD(at[51], at[82]);    MULADD(at[52], at[81]);    MULADD(at[53], at[80]);    MULADD(at[54], at[79]);    MULADD(at[55], at[78]);    MULADD(at[56], at[77]);    MULADD(at[57], at[76]);    MULADD(at[58], at[75]);    MULADD(at[59], at[74]);    MULADD(at[60], at[73]);    MULADD(at[61], at[72]);    MULADD(at[62], at[71]);    MULADD(at[63], at[70]);
+   COMBA_STORE(C->dp[69]);
+   /* 70 */
+   COMBA_FORWARD;
+   MULADD(at[7], at[127]);    MULADD(at[8], at[126]);    MULADD(at[9], at[125]);    MULADD(at[10], at[124]);    MULADD(at[11], at[123]);    MULADD(at[12], at[122]);    MULADD(at[13], at[121]);    MULADD(at[14], at[120]);    MULADD(at[15], at[119]);    MULADD(at[16], at[118]);    MULADD(at[17], at[117]);    MULADD(at[18], at[116]);    MULADD(at[19], at[115]);    MULADD(at[20], at[114]);    MULADD(at[21], at[113]);    MULADD(at[22], at[112]);    MULADD(at[23], at[111]);    MULADD(at[24], at[110]);    MULADD(at[25], at[109]);    MULADD(at[26], at[108]);    MULADD(at[27], at[107]);    MULADD(at[28], at[106]);    MULADD(at[29], at[105]);    MULADD(at[30], at[104]);    MULADD(at[31], at[103]);    MULADD(at[32], at[102]);    MULADD(at[33], at[101]);    MULADD(at[34], at[100]);    MULADD(at[35], at[99]);    MULADD(at[36], at[98]);    MULADD(at[37], at[97]);    MULADD(at[38], at[96]);    MULADD(at[39], at[95]);    MULADD(at[40], at[94]);    MULADD(at[41], at[93]);    MULADD(at[42], at[92]);    MULADD(at[43], at[91]);    MULADD(at[44], at[90]);    MULADD(at[45], at[89]);    MULADD(at[46], at[88]);    MULADD(at[47], at[87]);    MULADD(at[48], at[86]);    MULADD(at[49], at[85]);    MULADD(at[50], at[84]);    MULADD(at[51], at[83]);    MULADD(at[52], at[82]);    MULADD(at[53], at[81]);    MULADD(at[54], at[80]);    MULADD(at[55], at[79]);    MULADD(at[56], at[78]);    MULADD(at[57], at[77]);    MULADD(at[58], at[76]);    MULADD(at[59], at[75]);    MULADD(at[60], at[74]);    MULADD(at[61], at[73]);    MULADD(at[62], at[72]);    MULADD(at[63], at[71]);
+   COMBA_STORE(C->dp[70]);
+   /* 71 */
+   COMBA_FORWARD;
+   MULADD(at[8], at[127]);    MULADD(at[9], at[126]);    MULADD(at[10], at[125]);    MULADD(at[11], at[124]);    MULADD(at[12], at[123]);    MULADD(at[13], at[122]);    MULADD(at[14], at[121]);    MULADD(at[15], at[120]);    MULADD(at[16], at[119]);    MULADD(at[17], at[118]);    MULADD(at[18], at[117]);    MULADD(at[19], at[116]);    MULADD(at[20], at[115]);    MULADD(at[21], at[114]);    MULADD(at[22], at[113]);    MULADD(at[23], at[112]);    MULADD(at[24], at[111]);    MULADD(at[25], at[110]);    MULADD(at[26], at[109]);    MULADD(at[27], at[108]);    MULADD(at[28], at[107]);    MULADD(at[29], at[106]);    MULADD(at[30], at[105]);    MULADD(at[31], at[104]);    MULADD(at[32], at[103]);    MULADD(at[33], at[102]);    MULADD(at[34], at[101]);    MULADD(at[35], at[100]);    MULADD(at[36], at[99]);    MULADD(at[37], at[98]);    MULADD(at[38], at[97]);    MULADD(at[39], at[96]);    MULADD(at[40], at[95]);    MULADD(at[41], at[94]);    MULADD(at[42], at[93]);    MULADD(at[43], at[92]);    MULADD(at[44], at[91]);    MULADD(at[45], at[90]);    MULADD(at[46], at[89]);    MULADD(at[47], at[88]);    MULADD(at[48], at[87]);    MULADD(at[49], at[86]);    MULADD(at[50], at[85]);    MULADD(at[51], at[84]);    MULADD(at[52], at[83]);    MULADD(at[53], at[82]);    MULADD(at[54], at[81]);    MULADD(at[55], at[80]);    MULADD(at[56], at[79]);    MULADD(at[57], at[78]);    MULADD(at[58], at[77]);    MULADD(at[59], at[76]);    MULADD(at[60], at[75]);    MULADD(at[61], at[74]);    MULADD(at[62], at[73]);    MULADD(at[63], at[72]);
+   COMBA_STORE(C->dp[71]);
+   /* 72 */
+   COMBA_FORWARD;
+   MULADD(at[9], at[127]);    MULADD(at[10], at[126]);    MULADD(at[11], at[125]);    MULADD(at[12], at[124]);    MULADD(at[13], at[123]);    MULADD(at[14], at[122]);    MULADD(at[15], at[121]);    MULADD(at[16], at[120]);    MULADD(at[17], at[119]);    MULADD(at[18], at[118]);    MULADD(at[19], at[117]);    MULADD(at[20], at[116]);    MULADD(at[21], at[115]);    MULADD(at[22], at[114]);    MULADD(at[23], at[113]);    MULADD(at[24], at[112]);    MULADD(at[25], at[111]);    MULADD(at[26], at[110]);    MULADD(at[27], at[109]);    MULADD(at[28], at[108]);    MULADD(at[29], at[107]);    MULADD(at[30], at[106]);    MULADD(at[31], at[105]);    MULADD(at[32], at[104]);    MULADD(at[33], at[103]);    MULADD(at[34], at[102]);    MULADD(at[35], at[101]);    MULADD(at[36], at[100]);    MULADD(at[37], at[99]);    MULADD(at[38], at[98]);    MULADD(at[39], at[97]);    MULADD(at[40], at[96]);    MULADD(at[41], at[95]);    MULADD(at[42], at[94]);    MULADD(at[43], at[93]);    MULADD(at[44], at[92]);    MULADD(at[45], at[91]);    MULADD(at[46], at[90]);    MULADD(at[47], at[89]);    MULADD(at[48], at[88]);    MULADD(at[49], at[87]);    MULADD(at[50], at[86]);    MULADD(at[51], at[85]);    MULADD(at[52], at[84]);    MULADD(at[53], at[83]);    MULADD(at[54], at[82]);    MULADD(at[55], at[81]);    MULADD(at[56], at[80]);    MULADD(at[57], at[79]);    MULADD(at[58], at[78]);    MULADD(at[59], at[77]);    MULADD(at[60], at[76]);    MULADD(at[61], at[75]);    MULADD(at[62], at[74]);    MULADD(at[63], at[73]);
+   COMBA_STORE(C->dp[72]);
+   /* 73 */
+   COMBA_FORWARD;
+   MULADD(at[10], at[127]);    MULADD(at[11], at[126]);    MULADD(at[12], at[125]);    MULADD(at[13], at[124]);    MULADD(at[14], at[123]);    MULADD(at[15], at[122]);    MULADD(at[16], at[121]);    MULADD(at[17], at[120]);    MULADD(at[18], at[119]);    MULADD(at[19], at[118]);    MULADD(at[20], at[117]);    MULADD(at[21], at[116]);    MULADD(at[22], at[115]);    MULADD(at[23], at[114]);    MULADD(at[24], at[113]);    MULADD(at[25], at[112]);    MULADD(at[26], at[111]);    MULADD(at[27], at[110]);    MULADD(at[28], at[109]);    MULADD(at[29], at[108]);    MULADD(at[30], at[107]);    MULADD(at[31], at[106]);    MULADD(at[32], at[105]);    MULADD(at[33], at[104]);    MULADD(at[34], at[103]);    MULADD(at[35], at[102]);    MULADD(at[36], at[101]);    MULADD(at[37], at[100]);    MULADD(at[38], at[99]);    MULADD(at[39], at[98]);    MULADD(at[40], at[97]);    MULADD(at[41], at[96]);    MULADD(at[42], at[95]);    MULADD(at[43], at[94]);    MULADD(at[44], at[93]);    MULADD(at[45], at[92]);    MULADD(at[46], at[91]);    MULADD(at[47], at[90]);    MULADD(at[48], at[89]);    MULADD(at[49], at[88]);    MULADD(at[50], at[87]);    MULADD(at[51], at[86]);    MULADD(at[52], at[85]);    MULADD(at[53], at[84]);    MULADD(at[54], at[83]);    MULADD(at[55], at[82]);    MULADD(at[56], at[81]);    MULADD(at[57], at[80]);    MULADD(at[58], at[79]);    MULADD(at[59], at[78]);    MULADD(at[60], at[77]);    MULADD(at[61], at[76]);    MULADD(at[62], at[75]);    MULADD(at[63], at[74]);
+   COMBA_STORE(C->dp[73]);
+   /* 74 */
+   COMBA_FORWARD;
+   MULADD(at[11], at[127]);    MULADD(at[12], at[126]);    MULADD(at[13], at[125]);    MULADD(at[14], at[124]);    MULADD(at[15], at[123]);    MULADD(at[16], at[122]);    MULADD(at[17], at[121]);    MULADD(at[18], at[120]);    MULADD(at[19], at[119]);    MULADD(at[20], at[118]);    MULADD(at[21], at[117]);    MULADD(at[22], at[116]);    MULADD(at[23], at[115]);    MULADD(at[24], at[114]);    MULADD(at[25], at[113]);    MULADD(at[26], at[112]);    MULADD(at[27], at[111]);    MULADD(at[28], at[110]);    MULADD(at[29], at[109]);    MULADD(at[30], at[108]);    MULADD(at[31], at[107]);    MULADD(at[32], at[106]);    MULADD(at[33], at[105]);    MULADD(at[34], at[104]);    MULADD(at[35], at[103]);    MULADD(at[36], at[102]);    MULADD(at[37], at[101]);    MULADD(at[38], at[100]);    MULADD(at[39], at[99]);    MULADD(at[40], at[98]);    MULADD(at[41], at[97]);    MULADD(at[42], at[96]);    MULADD(at[43], at[95]);    MULADD(at[44], at[94]);    MULADD(at[45], at[93]);    MULADD(at[46], at[92]);    MULADD(at[47], at[91]);    MULADD(at[48], at[90]);    MULADD(at[49], at[89]);    MULADD(at[50], at[88]);    MULADD(at[51], at[87]);    MULADD(at[52], at[86]);    MULADD(at[53], at[85]);    MULADD(at[54], at[84]);    MULADD(at[55], at[83]);    MULADD(at[56], at[82]);    MULADD(at[57], at[81]);    MULADD(at[58], at[80]);    MULADD(at[59], at[79]);    MULADD(at[60], at[78]);    MULADD(at[61], at[77]);    MULADD(at[62], at[76]);    MULADD(at[63], at[75]);
+   COMBA_STORE(C->dp[74]);
+   /* 75 */
+   COMBA_FORWARD;
+   MULADD(at[12], at[127]);    MULADD(at[13], at[126]);    MULADD(at[14], at[125]);    MULADD(at[15], at[124]);    MULADD(at[16], at[123]);    MULADD(at[17], at[122]);    MULADD(at[18], at[121]);    MULADD(at[19], at[120]);    MULADD(at[20], at[119]);    MULADD(at[21], at[118]);    MULADD(at[22], at[117]);    MULADD(at[23], at[116]);    MULADD(at[24], at[115]);    MULADD(at[25], at[114]);    MULADD(at[26], at[113]);    MULADD(at[27], at[112]);    MULADD(at[28], at[111]);    MULADD(at[29], at[110]);    MULADD(at[30], at[109]);    MULADD(at[31], at[108]);    MULADD(at[32], at[107]);    MULADD(at[33], at[106]);    MULADD(at[34], at[105]);    MULADD(at[35], at[104]);    MULADD(at[36], at[103]);    MULADD(at[37], at[102]);    MULADD(at[38], at[101]);    MULADD(at[39], at[100]);    MULADD(at[40], at[99]);    MULADD(at[41], at[98]);    MULADD(at[42], at[97]);    MULADD(at[43], at[96]);    MULADD(at[44], at[95]);    MULADD(at[45], at[94]);    MULADD(at[46], at[93]);    MULADD(at[47], at[92]);    MULADD(at[48], at[91]);    MULADD(at[49], at[90]);    MULADD(at[50], at[89]);    MULADD(at[51], at[88]);    MULADD(at[52], at[87]);    MULADD(at[53], at[86]);    MULADD(at[54], at[85]);    MULADD(at[55], at[84]);    MULADD(at[56], at[83]);    MULADD(at[57], at[82]);    MULADD(at[58], at[81]);    MULADD(at[59], at[80]);    MULADD(at[60], at[79]);    MULADD(at[61], at[78]);    MULADD(at[62], at[77]);    MULADD(at[63], at[76]);
+   COMBA_STORE(C->dp[75]);
+   /* 76 */
+   COMBA_FORWARD;
+   MULADD(at[13], at[127]);    MULADD(at[14], at[126]);    MULADD(at[15], at[125]);    MULADD(at[16], at[124]);    MULADD(at[17], at[123]);    MULADD(at[18], at[122]);    MULADD(at[19], at[121]);    MULADD(at[20], at[120]);    MULADD(at[21], at[119]);    MULADD(at[22], at[118]);    MULADD(at[23], at[117]);    MULADD(at[24], at[116]);    MULADD(at[25], at[115]);    MULADD(at[26], at[114]);    MULADD(at[27], at[113]);    MULADD(at[28], at[112]);    MULADD(at[29], at[111]);    MULADD(at[30], at[110]);    MULADD(at[31], at[109]);    MULADD(at[32], at[108]);    MULADD(at[33], at[107]);    MULADD(at[34], at[106]);    MULADD(at[35], at[105]);    MULADD(at[36], at[104]);    MULADD(at[37], at[103]);    MULADD(at[38], at[102]);    MULADD(at[39], at[101]);    MULADD(at[40], at[100]);    MULADD(at[41], at[99]);    MULADD(at[42], at[98]);    MULADD(at[43], at[97]);    MULADD(at[44], at[96]);    MULADD(at[45], at[95]);    MULADD(at[46], at[94]);    MULADD(at[47], at[93]);    MULADD(at[48], at[92]);    MULADD(at[49], at[91]);    MULADD(at[50], at[90]);    MULADD(at[51], at[89]);    MULADD(at[52], at[88]);    MULADD(at[53], at[87]);    MULADD(at[54], at[86]);    MULADD(at[55], at[85]);    MULADD(at[56], at[84]);    MULADD(at[57], at[83]);    MULADD(at[58], at[82]);    MULADD(at[59], at[81]);    MULADD(at[60], at[80]);    MULADD(at[61], at[79]);    MULADD(at[62], at[78]);    MULADD(at[63], at[77]);
+   COMBA_STORE(C->dp[76]);
+   /* 77 */
+   COMBA_FORWARD;
+   MULADD(at[14], at[127]);    MULADD(at[15], at[126]);    MULADD(at[16], at[125]);    MULADD(at[17], at[124]);    MULADD(at[18], at[123]);    MULADD(at[19], at[122]);    MULADD(at[20], at[121]);    MULADD(at[21], at[120]);    MULADD(at[22], at[119]);    MULADD(at[23], at[118]);    MULADD(at[24], at[117]);    MULADD(at[25], at[116]);    MULADD(at[26], at[115]);    MULADD(at[27], at[114]);    MULADD(at[28], at[113]);    MULADD(at[29], at[112]);    MULADD(at[30], at[111]);    MULADD(at[31], at[110]);    MULADD(at[32], at[109]);    MULADD(at[33], at[108]);    MULADD(at[34], at[107]);    MULADD(at[35], at[106]);    MULADD(at[36], at[105]);    MULADD(at[37], at[104]);    MULADD(at[38], at[103]);    MULADD(at[39], at[102]);    MULADD(at[40], at[101]);    MULADD(at[41], at[100]);    MULADD(at[42], at[99]);    MULADD(at[43], at[98]);    MULADD(at[44], at[97]);    MULADD(at[45], at[96]);    MULADD(at[46], at[95]);    MULADD(at[47], at[94]);    MULADD(at[48], at[93]);    MULADD(at[49], at[92]);    MULADD(at[50], at[91]);    MULADD(at[51], at[90]);    MULADD(at[52], at[89]);    MULADD(at[53], at[88]);    MULADD(at[54], at[87]);    MULADD(at[55], at[86]);    MULADD(at[56], at[85]);    MULADD(at[57], at[84]);    MULADD(at[58], at[83]);    MULADD(at[59], at[82]);    MULADD(at[60], at[81]);    MULADD(at[61], at[80]);    MULADD(at[62], at[79]);    MULADD(at[63], at[78]);
+   COMBA_STORE(C->dp[77]);
+   /* 78 */
+   COMBA_FORWARD;
+   MULADD(at[15], at[127]);    MULADD(at[16], at[126]);    MULADD(at[17], at[125]);    MULADD(at[18], at[124]);    MULADD(at[19], at[123]);    MULADD(at[20], at[122]);    MULADD(at[21], at[121]);    MULADD(at[22], at[120]);    MULADD(at[23], at[119]);    MULADD(at[24], at[118]);    MULADD(at[25], at[117]);    MULADD(at[26], at[116]);    MULADD(at[27], at[115]);    MULADD(at[28], at[114]);    MULADD(at[29], at[113]);    MULADD(at[30], at[112]);    MULADD(at[31], at[111]);    MULADD(at[32], at[110]);    MULADD(at[33], at[109]);    MULADD(at[34], at[108]);    MULADD(at[35], at[107]);    MULADD(at[36], at[106]);    MULADD(at[37], at[105]);    MULADD(at[38], at[104]);    MULADD(at[39], at[103]);    MULADD(at[40], at[102]);    MULADD(at[41], at[101]);    MULADD(at[42], at[100]);    MULADD(at[43], at[99]);    MULADD(at[44], at[98]);    MULADD(at[45], at[97]);    MULADD(at[46], at[96]);    MULADD(at[47], at[95]);    MULADD(at[48], at[94]);    MULADD(at[49], at[93]);    MULADD(at[50], at[92]);    MULADD(at[51], at[91]);    MULADD(at[52], at[90]);    MULADD(at[53], at[89]);    MULADD(at[54], at[88]);    MULADD(at[55], at[87]);    MULADD(at[56], at[86]);    MULADD(at[57], at[85]);    MULADD(at[58], at[84]);    MULADD(at[59], at[83]);    MULADD(at[60], at[82]);    MULADD(at[61], at[81]);    MULADD(at[62], at[80]);    MULADD(at[63], at[79]);
+   COMBA_STORE(C->dp[78]);
+   /* 79 */
+   COMBA_FORWARD;
+   MULADD(at[16], at[127]);    MULADD(at[17], at[126]);    MULADD(at[18], at[125]);    MULADD(at[19], at[124]);    MULADD(at[20], at[123]);    MULADD(at[21], at[122]);    MULADD(at[22], at[121]);    MULADD(at[23], at[120]);    MULADD(at[24], at[119]);    MULADD(at[25], at[118]);    MULADD(at[26], at[117]);    MULADD(at[27], at[116]);    MULADD(at[28], at[115]);    MULADD(at[29], at[114]);    MULADD(at[30], at[113]);    MULADD(at[31], at[112]);    MULADD(at[32], at[111]);    MULADD(at[33], at[110]);    MULADD(at[34], at[109]);    MULADD(at[35], at[108]);    MULADD(at[36], at[107]);    MULADD(at[37], at[106]);    MULADD(at[38], at[105]);    MULADD(at[39], at[104]);    MULADD(at[40], at[103]);    MULADD(at[41], at[102]);    MULADD(at[42], at[101]);    MULADD(at[43], at[100]);    MULADD(at[44], at[99]);    MULADD(at[45], at[98]);    MULADD(at[46], at[97]);    MULADD(at[47], at[96]);    MULADD(at[48], at[95]);    MULADD(at[49], at[94]);    MULADD(at[50], at[93]);    MULADD(at[51], at[92]);    MULADD(at[52], at[91]);    MULADD(at[53], at[90]);    MULADD(at[54], at[89]);    MULADD(at[55], at[88]);    MULADD(at[56], at[87]);    MULADD(at[57], at[86]);    MULADD(at[58], at[85]);    MULADD(at[59], at[84]);    MULADD(at[60], at[83]);    MULADD(at[61], at[82]);    MULADD(at[62], at[81]);    MULADD(at[63], at[80]);
+   COMBA_STORE(C->dp[79]);
+   /* 80 */
+   COMBA_FORWARD;
+   MULADD(at[17], at[127]);    MULADD(at[18], at[126]);    MULADD(at[19], at[125]);    MULADD(at[20], at[124]);    MULADD(at[21], at[123]);    MULADD(at[22], at[122]);    MULADD(at[23], at[121]);    MULADD(at[24], at[120]);    MULADD(at[25], at[119]);    MULADD(at[26], at[118]);    MULADD(at[27], at[117]);    MULADD(at[28], at[116]);    MULADD(at[29], at[115]);    MULADD(at[30], at[114]);    MULADD(at[31], at[113]);    MULADD(at[32], at[112]);    MULADD(at[33], at[111]);    MULADD(at[34], at[110]);    MULADD(at[35], at[109]);    MULADD(at[36], at[108]);    MULADD(at[37], at[107]);    MULADD(at[38], at[106]);    MULADD(at[39], at[105]);    MULADD(at[40], at[104]);    MULADD(at[41], at[103]);    MULADD(at[42], at[102]);    MULADD(at[43], at[101]);    MULADD(at[44], at[100]);    MULADD(at[45], at[99]);    MULADD(at[46], at[98]);    MULADD(at[47], at[97]);    MULADD(at[48], at[96]);    MULADD(at[49], at[95]);    MULADD(at[50], at[94]);    MULADD(at[51], at[93]);    MULADD(at[52], at[92]);    MULADD(at[53], at[91]);    MULADD(at[54], at[90]);    MULADD(at[55], at[89]);    MULADD(at[56], at[88]);    MULADD(at[57], at[87]);    MULADD(at[58], at[86]);    MULADD(at[59], at[85]);    MULADD(at[60], at[84]);    MULADD(at[61], at[83]);    MULADD(at[62], at[82]);    MULADD(at[63], at[81]);
+   COMBA_STORE(C->dp[80]);
+   /* 81 */
+   COMBA_FORWARD;
+   MULADD(at[18], at[127]);    MULADD(at[19], at[126]);    MULADD(at[20], at[125]);    MULADD(at[21], at[124]);    MULADD(at[22], at[123]);    MULADD(at[23], at[122]);    MULADD(at[24], at[121]);    MULADD(at[25], at[120]);    MULADD(at[26], at[119]);    MULADD(at[27], at[118]);    MULADD(at[28], at[117]);    MULADD(at[29], at[116]);    MULADD(at[30], at[115]);    MULADD(at[31], at[114]);    MULADD(at[32], at[113]);    MULADD(at[33], at[112]);    MULADD(at[34], at[111]);    MULADD(at[35], at[110]);    MULADD(at[36], at[109]);    MULADD(at[37], at[108]);    MULADD(at[38], at[107]);    MULADD(at[39], at[106]);    MULADD(at[40], at[105]);    MULADD(at[41], at[104]);    MULADD(at[42], at[103]);    MULADD(at[43], at[102]);    MULADD(at[44], at[101]);    MULADD(at[45], at[100]);    MULADD(at[46], at[99]);    MULADD(at[47], at[98]);    MULADD(at[48], at[97]);    MULADD(at[49], at[96]);    MULADD(at[50], at[95]);    MULADD(at[51], at[94]);    MULADD(at[52], at[93]);    MULADD(at[53], at[92]);    MULADD(at[54], at[91]);    MULADD(at[55], at[90]);    MULADD(at[56], at[89]);    MULADD(at[57], at[88]);    MULADD(at[58], at[87]);    MULADD(at[59], at[86]);    MULADD(at[60], at[85]);    MULADD(at[61], at[84]);    MULADD(at[62], at[83]);    MULADD(at[63], at[82]);
+   COMBA_STORE(C->dp[81]);
+   /* 82 */
+   COMBA_FORWARD;
+   MULADD(at[19], at[127]);    MULADD(at[20], at[126]);    MULADD(at[21], at[125]);    MULADD(at[22], at[124]);    MULADD(at[23], at[123]);    MULADD(at[24], at[122]);    MULADD(at[25], at[121]);    MULADD(at[26], at[120]);    MULADD(at[27], at[119]);    MULADD(at[28], at[118]);    MULADD(at[29], at[117]);    MULADD(at[30], at[116]);    MULADD(at[31], at[115]);    MULADD(at[32], at[114]);    MULADD(at[33], at[113]);    MULADD(at[34], at[112]);    MULADD(at[35], at[111]);    MULADD(at[36], at[110]);    MULADD(at[37], at[109]);    MULADD(at[38], at[108]);    MULADD(at[39], at[107]);    MULADD(at[40], at[106]);    MULADD(at[41], at[105]);    MULADD(at[42], at[104]);    MULADD(at[43], at[103]);    MULADD(at[44], at[102]);    MULADD(at[45], at[101]);    MULADD(at[46], at[100]);    MULADD(at[47], at[99]);    MULADD(at[48], at[98]);    MULADD(at[49], at[97]);    MULADD(at[50], at[96]);    MULADD(at[51], at[95]);    MULADD(at[52], at[94]);    MULADD(at[53], at[93]);    MULADD(at[54], at[92]);    MULADD(at[55], at[91]);    MULADD(at[56], at[90]);    MULADD(at[57], at[89]);    MULADD(at[58], at[88]);    MULADD(at[59], at[87]);    MULADD(at[60], at[86]);    MULADD(at[61], at[85]);    MULADD(at[62], at[84]);    MULADD(at[63], at[83]);
+   COMBA_STORE(C->dp[82]);
+   /* 83 */
+   COMBA_FORWARD;
+   MULADD(at[20], at[127]);    MULADD(at[21], at[126]);    MULADD(at[22], at[125]);    MULADD(at[23], at[124]);    MULADD(at[24], at[123]);    MULADD(at[25], at[122]);    MULADD(at[26], at[121]);    MULADD(at[27], at[120]);    MULADD(at[28], at[119]);    MULADD(at[29], at[118]);    MULADD(at[30], at[117]);    MULADD(at[31], at[116]);    MULADD(at[32], at[115]);    MULADD(at[33], at[114]);    MULADD(at[34], at[113]);    MULADD(at[35], at[112]);    MULADD(at[36], at[111]);    MULADD(at[37], at[110]);    MULADD(at[38], at[109]);    MULADD(at[39], at[108]);    MULADD(at[40], at[107]);    MULADD(at[41], at[106]);    MULADD(at[42], at[105]);    MULADD(at[43], at[104]);    MULADD(at[44], at[103]);    MULADD(at[45], at[102]);    MULADD(at[46], at[101]);    MULADD(at[47], at[100]);    MULADD(at[48], at[99]);    MULADD(at[49], at[98]);    MULADD(at[50], at[97]);    MULADD(at[51], at[96]);    MULADD(at[52], at[95]);    MULADD(at[53], at[94]);    MULADD(at[54], at[93]);    MULADD(at[55], at[92]);    MULADD(at[56], at[91]);    MULADD(at[57], at[90]);    MULADD(at[58], at[89]);    MULADD(at[59], at[88]);    MULADD(at[60], at[87]);    MULADD(at[61], at[86]);    MULADD(at[62], at[85]);    MULADD(at[63], at[84]);
+   COMBA_STORE(C->dp[83]);
+   /* 84 */
+   COMBA_FORWARD;
+   MULADD(at[21], at[127]);    MULADD(at[22], at[126]);    MULADD(at[23], at[125]);    MULADD(at[24], at[124]);    MULADD(at[25], at[123]);    MULADD(at[26], at[122]);    MULADD(at[27], at[121]);    MULADD(at[28], at[120]);    MULADD(at[29], at[119]);    MULADD(at[30], at[118]);    MULADD(at[31], at[117]);    MULADD(at[32], at[116]);    MULADD(at[33], at[115]);    MULADD(at[34], at[114]);    MULADD(at[35], at[113]);    MULADD(at[36], at[112]);    MULADD(at[37], at[111]);    MULADD(at[38], at[110]);    MULADD(at[39], at[109]);    MULADD(at[40], at[108]);    MULADD(at[41], at[107]);    MULADD(at[42], at[106]);    MULADD(at[43], at[105]);    MULADD(at[44], at[104]);    MULADD(at[45], at[103]);    MULADD(at[46], at[102]);    MULADD(at[47], at[101]);    MULADD(at[48], at[100]);    MULADD(at[49], at[99]);    MULADD(at[50], at[98]);    MULADD(at[51], at[97]);    MULADD(at[52], at[96]);    MULADD(at[53], at[95]);    MULADD(at[54], at[94]);    MULADD(at[55], at[93]);    MULADD(at[56], at[92]);    MULADD(at[57], at[91]);    MULADD(at[58], at[90]);    MULADD(at[59], at[89]);    MULADD(at[60], at[88]);    MULADD(at[61], at[87]);    MULADD(at[62], at[86]);    MULADD(at[63], at[85]);
+   COMBA_STORE(C->dp[84]);
+   /* 85 */
+   COMBA_FORWARD;
+   MULADD(at[22], at[127]);    MULADD(at[23], at[126]);    MULADD(at[24], at[125]);    MULADD(at[25], at[124]);    MULADD(at[26], at[123]);    MULADD(at[27], at[122]);    MULADD(at[28], at[121]);    MULADD(at[29], at[120]);    MULADD(at[30], at[119]);    MULADD(at[31], at[118]);    MULADD(at[32], at[117]);    MULADD(at[33], at[116]);    MULADD(at[34], at[115]);    MULADD(at[35], at[114]);    MULADD(at[36], at[113]);    MULADD(at[37], at[112]);    MULADD(at[38], at[111]);    MULADD(at[39], at[110]);    MULADD(at[40], at[109]);    MULADD(at[41], at[108]);    MULADD(at[42], at[107]);    MULADD(at[43], at[106]);    MULADD(at[44], at[105]);    MULADD(at[45], at[104]);    MULADD(at[46], at[103]);    MULADD(at[47], at[102]);    MULADD(at[48], at[101]);    MULADD(at[49], at[100]);    MULADD(at[50], at[99]);    MULADD(at[51], at[98]);    MULADD(at[52], at[97]);    MULADD(at[53], at[96]);    MULADD(at[54], at[95]);    MULADD(at[55], at[94]);    MULADD(at[56], at[93]);    MULADD(at[57], at[92]);    MULADD(at[58], at[91]);    MULADD(at[59], at[90]);    MULADD(at[60], at[89]);    MULADD(at[61], at[88]);    MULADD(at[62], at[87]);    MULADD(at[63], at[86]);
+   COMBA_STORE(C->dp[85]);
+   /* 86 */
+   COMBA_FORWARD;
+   MULADD(at[23], at[127]);    MULADD(at[24], at[126]);    MULADD(at[25], at[125]);    MULADD(at[26], at[124]);    MULADD(at[27], at[123]);    MULADD(at[28], at[122]);    MULADD(at[29], at[121]);    MULADD(at[30], at[120]);    MULADD(at[31], at[119]);    MULADD(at[32], at[118]);    MULADD(at[33], at[117]);    MULADD(at[34], at[116]);    MULADD(at[35], at[115]);    MULADD(at[36], at[114]);    MULADD(at[37], at[113]);    MULADD(at[38], at[112]);    MULADD(at[39], at[111]);    MULADD(at[40], at[110]);    MULADD(at[41], at[109]);    MULADD(at[42], at[108]);    MULADD(at[43], at[107]);    MULADD(at[44], at[106]);    MULADD(at[45], at[105]);    MULADD(at[46], at[104]);    MULADD(at[47], at[103]);    MULADD(at[48], at[102]);    MULADD(at[49], at[101]);    MULADD(at[50], at[100]);    MULADD(at[51], at[99]);    MULADD(at[52], at[98]);    MULADD(at[53], at[97]);    MULADD(at[54], at[96]);    MULADD(at[55], at[95]);    MULADD(at[56], at[94]);    MULADD(at[57], at[93]);    MULADD(at[58], at[92]);    MULADD(at[59], at[91]);    MULADD(at[60], at[90]);    MULADD(at[61], at[89]);    MULADD(at[62], at[88]);    MULADD(at[63], at[87]);
+   COMBA_STORE(C->dp[86]);
+   /* 87 */
+   COMBA_FORWARD;
+   MULADD(at[24], at[127]);    MULADD(at[25], at[126]);    MULADD(at[26], at[125]);    MULADD(at[27], at[124]);    MULADD(at[28], at[123]);    MULADD(at[29], at[122]);    MULADD(at[30], at[121]);    MULADD(at[31], at[120]);    MULADD(at[32], at[119]);    MULADD(at[33], at[118]);    MULADD(at[34], at[117]);    MULADD(at[35], at[116]);    MULADD(at[36], at[115]);    MULADD(at[37], at[114]);    MULADD(at[38], at[113]);    MULADD(at[39], at[112]);    MULADD(at[40], at[111]);    MULADD(at[41], at[110]);    MULADD(at[42], at[109]);    MULADD(at[43], at[108]);    MULADD(at[44], at[107]);    MULADD(at[45], at[106]);    MULADD(at[46], at[105]);    MULADD(at[47], at[104]);    MULADD(at[48], at[103]);    MULADD(at[49], at[102]);    MULADD(at[50], at[101]);    MULADD(at[51], at[100]);    MULADD(at[52], at[99]);    MULADD(at[53], at[98]);    MULADD(at[54], at[97]);    MULADD(at[55], at[96]);    MULADD(at[56], at[95]);    MULADD(at[57], at[94]);    MULADD(at[58], at[93]);    MULADD(at[59], at[92]);    MULADD(at[60], at[91]);    MULADD(at[61], at[90]);    MULADD(at[62], at[89]);    MULADD(at[63], at[88]);
+   COMBA_STORE(C->dp[87]);
+   /* 88 */
+   COMBA_FORWARD;
+   MULADD(at[25], at[127]);    MULADD(at[26], at[126]);    MULADD(at[27], at[125]);    MULADD(at[28], at[124]);    MULADD(at[29], at[123]);    MULADD(at[30], at[122]);    MULADD(at[31], at[121]);    MULADD(at[32], at[120]);    MULADD(at[33], at[119]);    MULADD(at[34], at[118]);    MULADD(at[35], at[117]);    MULADD(at[36], at[116]);    MULADD(at[37], at[115]);    MULADD(at[38], at[114]);    MULADD(at[39], at[113]);    MULADD(at[40], at[112]);    MULADD(at[41], at[111]);    MULADD(at[42], at[110]);    MULADD(at[43], at[109]);    MULADD(at[44], at[108]);    MULADD(at[45], at[107]);    MULADD(at[46], at[106]);    MULADD(at[47], at[105]);    MULADD(at[48], at[104]);    MULADD(at[49], at[103]);    MULADD(at[50], at[102]);    MULADD(at[51], at[101]);    MULADD(at[52], at[100]);    MULADD(at[53], at[99]);    MULADD(at[54], at[98]);    MULADD(at[55], at[97]);    MULADD(at[56], at[96]);    MULADD(at[57], at[95]);    MULADD(at[58], at[94]);    MULADD(at[59], at[93]);    MULADD(at[60], at[92]);    MULADD(at[61], at[91]);    MULADD(at[62], at[90]);    MULADD(at[63], at[89]);
+   COMBA_STORE(C->dp[88]);
+   /* 89 */
+   COMBA_FORWARD;
+   MULADD(at[26], at[127]);    MULADD(at[27], at[126]);    MULADD(at[28], at[125]);    MULADD(at[29], at[124]);    MULADD(at[30], at[123]);    MULADD(at[31], at[122]);    MULADD(at[32], at[121]);    MULADD(at[33], at[120]);    MULADD(at[34], at[119]);    MULADD(at[35], at[118]);    MULADD(at[36], at[117]);    MULADD(at[37], at[116]);    MULADD(at[38], at[115]);    MULADD(at[39], at[114]);    MULADD(at[40], at[113]);    MULADD(at[41], at[112]);    MULADD(at[42], at[111]);    MULADD(at[43], at[110]);    MULADD(at[44], at[109]);    MULADD(at[45], at[108]);    MULADD(at[46], at[107]);    MULADD(at[47], at[106]);    MULADD(at[48], at[105]);    MULADD(at[49], at[104]);    MULADD(at[50], at[103]);    MULADD(at[51], at[102]);    MULADD(at[52], at[101]);    MULADD(at[53], at[100]);    MULADD(at[54], at[99]);    MULADD(at[55], at[98]);    MULADD(at[56], at[97]);    MULADD(at[57], at[96]);    MULADD(at[58], at[95]);    MULADD(at[59], at[94]);    MULADD(at[60], at[93]);    MULADD(at[61], at[92]);    MULADD(at[62], at[91]);    MULADD(at[63], at[90]);
+   COMBA_STORE(C->dp[89]);
+   /* 90 */
+   COMBA_FORWARD;
+   MULADD(at[27], at[127]);    MULADD(at[28], at[126]);    MULADD(at[29], at[125]);    MULADD(at[30], at[124]);    MULADD(at[31], at[123]);    MULADD(at[32], at[122]);    MULADD(at[33], at[121]);    MULADD(at[34], at[120]);    MULADD(at[35], at[119]);    MULADD(at[36], at[118]);    MULADD(at[37], at[117]);    MULADD(at[38], at[116]);    MULADD(at[39], at[115]);    MULADD(at[40], at[114]);    MULADD(at[41], at[113]);    MULADD(at[42], at[112]);    MULADD(at[43], at[111]);    MULADD(at[44], at[110]);    MULADD(at[45], at[109]);    MULADD(at[46], at[108]);    MULADD(at[47], at[107]);    MULADD(at[48], at[106]);    MULADD(at[49], at[105]);    MULADD(at[50], at[104]);    MULADD(at[51], at[103]);    MULADD(at[52], at[102]);    MULADD(at[53], at[101]);    MULADD(at[54], at[100]);    MULADD(at[55], at[99]);    MULADD(at[56], at[98]);    MULADD(at[57], at[97]);    MULADD(at[58], at[96]);    MULADD(at[59], at[95]);    MULADD(at[60], at[94]);    MULADD(at[61], at[93]);    MULADD(at[62], at[92]);    MULADD(at[63], at[91]);
+   COMBA_STORE(C->dp[90]);
+   /* 91 */
+   COMBA_FORWARD;
+   MULADD(at[28], at[127]);    MULADD(at[29], at[126]);    MULADD(at[30], at[125]);    MULADD(at[31], at[124]);    MULADD(at[32], at[123]);    MULADD(at[33], at[122]);    MULADD(at[34], at[121]);    MULADD(at[35], at[120]);    MULADD(at[36], at[119]);    MULADD(at[37], at[118]);    MULADD(at[38], at[117]);    MULADD(at[39], at[116]);    MULADD(at[40], at[115]);    MULADD(at[41], at[114]);    MULADD(at[42], at[113]);    MULADD(at[43], at[112]);    MULADD(at[44], at[111]);    MULADD(at[45], at[110]);    MULADD(at[46], at[109]);    MULADD(at[47], at[108]);    MULADD(at[48], at[107]);    MULADD(at[49], at[106]);    MULADD(at[50], at[105]);    MULADD(at[51], at[104]);    MULADD(at[52], at[103]);    MULADD(at[53], at[102]);    MULADD(at[54], at[101]);    MULADD(at[55], at[100]);    MULADD(at[56], at[99]);    MULADD(at[57], at[98]);    MULADD(at[58], at[97]);    MULADD(at[59], at[96]);    MULADD(at[60], at[95]);    MULADD(at[61], at[94]);    MULADD(at[62], at[93]);    MULADD(at[63], at[92]);
+   COMBA_STORE(C->dp[91]);
+   /* 92 */
+   COMBA_FORWARD;
+   MULADD(at[29], at[127]);    MULADD(at[30], at[126]);    MULADD(at[31], at[125]);    MULADD(at[32], at[124]);    MULADD(at[33], at[123]);    MULADD(at[34], at[122]);    MULADD(at[35], at[121]);    MULADD(at[36], at[120]);    MULADD(at[37], at[119]);    MULADD(at[38], at[118]);    MULADD(at[39], at[117]);    MULADD(at[40], at[116]);    MULADD(at[41], at[115]);    MULADD(at[42], at[114]);    MULADD(at[43], at[113]);    MULADD(at[44], at[112]);    MULADD(at[45], at[111]);    MULADD(at[46], at[110]);    MULADD(at[47], at[109]);    MULADD(at[48], at[108]);    MULADD(at[49], at[107]);    MULADD(at[50], at[106]);    MULADD(at[51], at[105]);    MULADD(at[52], at[104]);    MULADD(at[53], at[103]);    MULADD(at[54], at[102]);    MULADD(at[55], at[101]);    MULADD(at[56], at[100]);    MULADD(at[57], at[99]);    MULADD(at[58], at[98]);    MULADD(at[59], at[97]);    MULADD(at[60], at[96]);    MULADD(at[61], at[95]);    MULADD(at[62], at[94]);    MULADD(at[63], at[93]);
+   COMBA_STORE(C->dp[92]);
+   /* 93 */
+   COMBA_FORWARD;
+   MULADD(at[30], at[127]);    MULADD(at[31], at[126]);    MULADD(at[32], at[125]);    MULADD(at[33], at[124]);    MULADD(at[34], at[123]);    MULADD(at[35], at[122]);    MULADD(at[36], at[121]);    MULADD(at[37], at[120]);    MULADD(at[38], at[119]);    MULADD(at[39], at[118]);    MULADD(at[40], at[117]);    MULADD(at[41], at[116]);    MULADD(at[42], at[115]);    MULADD(at[43], at[114]);    MULADD(at[44], at[113]);    MULADD(at[45], at[112]);    MULADD(at[46], at[111]);    MULADD(at[47], at[110]);    MULADD(at[48], at[109]);    MULADD(at[49], at[108]);    MULADD(at[50], at[107]);    MULADD(at[51], at[106]);    MULADD(at[52], at[105]);    MULADD(at[53], at[104]);    MULADD(at[54], at[103]);    MULADD(at[55], at[102]);    MULADD(at[56], at[101]);    MULADD(at[57], at[100]);    MULADD(at[58], at[99]);    MULADD(at[59], at[98]);    MULADD(at[60], at[97]);    MULADD(at[61], at[96]);    MULADD(at[62], at[95]);    MULADD(at[63], at[94]);
+   COMBA_STORE(C->dp[93]);
+   /* 94 */
+   COMBA_FORWARD;
+   MULADD(at[31], at[127]);    MULADD(at[32], at[126]);    MULADD(at[33], at[125]);    MULADD(at[34], at[124]);    MULADD(at[35], at[123]);    MULADD(at[36], at[122]);    MULADD(at[37], at[121]);    MULADD(at[38], at[120]);    MULADD(at[39], at[119]);    MULADD(at[40], at[118]);    MULADD(at[41], at[117]);    MULADD(at[42], at[116]);    MULADD(at[43], at[115]);    MULADD(at[44], at[114]);    MULADD(at[45], at[113]);    MULADD(at[46], at[112]);    MULADD(at[47], at[111]);    MULADD(at[48], at[110]);    MULADD(at[49], at[109]);    MULADD(at[50], at[108]);    MULADD(at[51], at[107]);    MULADD(at[52], at[106]);    MULADD(at[53], at[105]);    MULADD(at[54], at[104]);    MULADD(at[55], at[103]);    MULADD(at[56], at[102]);    MULADD(at[57], at[101]);    MULADD(at[58], at[100]);    MULADD(at[59], at[99]);    MULADD(at[60], at[98]);    MULADD(at[61], at[97]);    MULADD(at[62], at[96]);    MULADD(at[63], at[95]);
+   COMBA_STORE(C->dp[94]);
+   /* 95 */
+   COMBA_FORWARD;
+   MULADD(at[32], at[127]);    MULADD(at[33], at[126]);    MULADD(at[34], at[125]);    MULADD(at[35], at[124]);    MULADD(at[36], at[123]);    MULADD(at[37], at[122]);    MULADD(at[38], at[121]);    MULADD(at[39], at[120]);    MULADD(at[40], at[119]);    MULADD(at[41], at[118]);    MULADD(at[42], at[117]);    MULADD(at[43], at[116]);    MULADD(at[44], at[115]);    MULADD(at[45], at[114]);    MULADD(at[46], at[113]);    MULADD(at[47], at[112]);    MULADD(at[48], at[111]);    MULADD(at[49], at[110]);    MULADD(at[50], at[109]);    MULADD(at[51], at[108]);    MULADD(at[52], at[107]);    MULADD(at[53], at[106]);    MULADD(at[54], at[105]);    MULADD(at[55], at[104]);    MULADD(at[56], at[103]);    MULADD(at[57], at[102]);    MULADD(at[58], at[101]);    MULADD(at[59], at[100]);    MULADD(at[60], at[99]);    MULADD(at[61], at[98]);    MULADD(at[62], at[97]);    MULADD(at[63], at[96]);
+   COMBA_STORE(C->dp[95]);
+   /* 96 */
+   COMBA_FORWARD;
+   MULADD(at[33], at[127]);    MULADD(at[34], at[126]);    MULADD(at[35], at[125]);    MULADD(at[36], at[124]);    MULADD(at[37], at[123]);    MULADD(at[38], at[122]);    MULADD(at[39], at[121]);    MULADD(at[40], at[120]);    MULADD(at[41], at[119]);    MULADD(at[42], at[118]);    MULADD(at[43], at[117]);    MULADD(at[44], at[116]);    MULADD(at[45], at[115]);    MULADD(at[46], at[114]);    MULADD(at[47], at[113]);    MULADD(at[48], at[112]);    MULADD(at[49], at[111]);    MULADD(at[50], at[110]);    MULADD(at[51], at[109]);    MULADD(at[52], at[108]);    MULADD(at[53], at[107]);    MULADD(at[54], at[106]);    MULADD(at[55], at[105]);    MULADD(at[56], at[104]);    MULADD(at[57], at[103]);    MULADD(at[58], at[102]);    MULADD(at[59], at[101]);    MULADD(at[60], at[100]);    MULADD(at[61], at[99]);    MULADD(at[62], at[98]);    MULADD(at[63], at[97]);
+   COMBA_STORE(C->dp[96]);
+   /* 97 */
+   COMBA_FORWARD;
+   MULADD(at[34], at[127]);    MULADD(at[35], at[126]);    MULADD(at[36], at[125]);    MULADD(at[37], at[124]);    MULADD(at[38], at[123]);    MULADD(at[39], at[122]);    MULADD(at[40], at[121]);    MULADD(at[41], at[120]);    MULADD(at[42], at[119]);    MULADD(at[43], at[118]);    MULADD(at[44], at[117]);    MULADD(at[45], at[116]);    MULADD(at[46], at[115]);    MULADD(at[47], at[114]);    MULADD(at[48], at[113]);    MULADD(at[49], at[112]);    MULADD(at[50], at[111]);    MULADD(at[51], at[110]);    MULADD(at[52], at[109]);    MULADD(at[53], at[108]);    MULADD(at[54], at[107]);    MULADD(at[55], at[106]);    MULADD(at[56], at[105]);    MULADD(at[57], at[104]);    MULADD(at[58], at[103]);    MULADD(at[59], at[102]);    MULADD(at[60], at[101]);    MULADD(at[61], at[100]);    MULADD(at[62], at[99]);    MULADD(at[63], at[98]);
+   COMBA_STORE(C->dp[97]);
+   /* 98 */
+   COMBA_FORWARD;
+   MULADD(at[35], at[127]);    MULADD(at[36], at[126]);    MULADD(at[37], at[125]);    MULADD(at[38], at[124]);    MULADD(at[39], at[123]);    MULADD(at[40], at[122]);    MULADD(at[41], at[121]);    MULADD(at[42], at[120]);    MULADD(at[43], at[119]);    MULADD(at[44], at[118]);    MULADD(at[45], at[117]);    MULADD(at[46], at[116]);    MULADD(at[47], at[115]);    MULADD(at[48], at[114]);    MULADD(at[49], at[113]);    MULADD(at[50], at[112]);    MULADD(at[51], at[111]);    MULADD(at[52], at[110]);    MULADD(at[53], at[109]);    MULADD(at[54], at[108]);    MULADD(at[55], at[107]);    MULADD(at[56], at[106]);    MULADD(at[57], at[105]);    MULADD(at[58], at[104]);    MULADD(at[59], at[103]);    MULADD(at[60], at[102]);    MULADD(at[61], at[101]);    MULADD(at[62], at[100]);    MULADD(at[63], at[99]);
+   COMBA_STORE(C->dp[98]);
+   /* 99 */
+   COMBA_FORWARD;
+   MULADD(at[36], at[127]);    MULADD(at[37], at[126]);    MULADD(at[38], at[125]);    MULADD(at[39], at[124]);    MULADD(at[40], at[123]);    MULADD(at[41], at[122]);    MULADD(at[42], at[121]);    MULADD(at[43], at[120]);    MULADD(at[44], at[119]);    MULADD(at[45], at[118]);    MULADD(at[46], at[117]);    MULADD(at[47], at[116]);    MULADD(at[48], at[115]);    MULADD(at[49], at[114]);    MULADD(at[50], at[113]);    MULADD(at[51], at[112]);    MULADD(at[52], at[111]);    MULADD(at[53], at[110]);    MULADD(at[54], at[109]);    MULADD(at[55], at[108]);    MULADD(at[56], at[107]);    MULADD(at[57], at[106]);    MULADD(at[58], at[105]);    MULADD(at[59], at[104]);    MULADD(at[60], at[103]);    MULADD(at[61], at[102]);    MULADD(at[62], at[101]);    MULADD(at[63], at[100]);
+   COMBA_STORE(C->dp[99]);
+   /* 100 */
+   COMBA_FORWARD;
+   MULADD(at[37], at[127]);    MULADD(at[38], at[126]);    MULADD(at[39], at[125]);    MULADD(at[40], at[124]);    MULADD(at[41], at[123]);    MULADD(at[42], at[122]);    MULADD(at[43], at[121]);    MULADD(at[44], at[120]);    MULADD(at[45], at[119]);    MULADD(at[46], at[118]);    MULADD(at[47], at[117]);    MULADD(at[48], at[116]);    MULADD(at[49], at[115]);    MULADD(at[50], at[114]);    MULADD(at[51], at[113]);    MULADD(at[52], at[112]);    MULADD(at[53], at[111]);    MULADD(at[54], at[110]);    MULADD(at[55], at[109]);    MULADD(at[56], at[108]);    MULADD(at[57], at[107]);    MULADD(at[58], at[106]);    MULADD(at[59], at[105]);    MULADD(at[60], at[104]);    MULADD(at[61], at[103]);    MULADD(at[62], at[102]);    MULADD(at[63], at[101]);
+   COMBA_STORE(C->dp[100]);
+   /* 101 */
+   COMBA_FORWARD;
+   MULADD(at[38], at[127]);    MULADD(at[39], at[126]);    MULADD(at[40], at[125]);    MULADD(at[41], at[124]);    MULADD(at[42], at[123]);    MULADD(at[43], at[122]);    MULADD(at[44], at[121]);    MULADD(at[45], at[120]);    MULADD(at[46], at[119]);    MULADD(at[47], at[118]);    MULADD(at[48], at[117]);    MULADD(at[49], at[116]);    MULADD(at[50], at[115]);    MULADD(at[51], at[114]);    MULADD(at[52], at[113]);    MULADD(at[53], at[112]);    MULADD(at[54], at[111]);    MULADD(at[55], at[110]);    MULADD(at[56], at[109]);    MULADD(at[57], at[108]);    MULADD(at[58], at[107]);    MULADD(at[59], at[106]);    MULADD(at[60], at[105]);    MULADD(at[61], at[104]);    MULADD(at[62], at[103]);    MULADD(at[63], at[102]);
+   COMBA_STORE(C->dp[101]);
+   /* 102 */
+   COMBA_FORWARD;
+   MULADD(at[39], at[127]);    MULADD(at[40], at[126]);    MULADD(at[41], at[125]);    MULADD(at[42], at[124]);    MULADD(at[43], at[123]);    MULADD(at[44], at[122]);    MULADD(at[45], at[121]);    MULADD(at[46], at[120]);    MULADD(at[47], at[119]);    MULADD(at[48], at[118]);    MULADD(at[49], at[117]);    MULADD(at[50], at[116]);    MULADD(at[51], at[115]);    MULADD(at[52], at[114]);    MULADD(at[53], at[113]);    MULADD(at[54], at[112]);    MULADD(at[55], at[111]);    MULADD(at[56], at[110]);    MULADD(at[57], at[109]);    MULADD(at[58], at[108]);    MULADD(at[59], at[107]);    MULADD(at[60], at[106]);    MULADD(at[61], at[105]);    MULADD(at[62], at[104]);    MULADD(at[63], at[103]);
+   COMBA_STORE(C->dp[102]);
+   /* 103 */
+   COMBA_FORWARD;
+   MULADD(at[40], at[127]);    MULADD(at[41], at[126]);    MULADD(at[42], at[125]);    MULADD(at[43], at[124]);    MULADD(at[44], at[123]);    MULADD(at[45], at[122]);    MULADD(at[46], at[121]);    MULADD(at[47], at[120]);    MULADD(at[48], at[119]);    MULADD(at[49], at[118]);    MULADD(at[50], at[117]);    MULADD(at[51], at[116]);    MULADD(at[52], at[115]);    MULADD(at[53], at[114]);    MULADD(at[54], at[113]);    MULADD(at[55], at[112]);    MULADD(at[56], at[111]);    MULADD(at[57], at[110]);    MULADD(at[58], at[109]);    MULADD(at[59], at[108]);    MULADD(at[60], at[107]);    MULADD(at[61], at[106]);    MULADD(at[62], at[105]);    MULADD(at[63], at[104]);
+   COMBA_STORE(C->dp[103]);
+   /* 104 */
+   COMBA_FORWARD;
+   MULADD(at[41], at[127]);    MULADD(at[42], at[126]);    MULADD(at[43], at[125]);    MULADD(at[44], at[124]);    MULADD(at[45], at[123]);    MULADD(at[46], at[122]);    MULADD(at[47], at[121]);    MULADD(at[48], at[120]);    MULADD(at[49], at[119]);    MULADD(at[50], at[118]);    MULADD(at[51], at[117]);    MULADD(at[52], at[116]);    MULADD(at[53], at[115]);    MULADD(at[54], at[114]);    MULADD(at[55], at[113]);    MULADD(at[56], at[112]);    MULADD(at[57], at[111]);    MULADD(at[58], at[110]);    MULADD(at[59], at[109]);    MULADD(at[60], at[108]);    MULADD(at[61], at[107]);    MULADD(at[62], at[106]);    MULADD(at[63], at[105]);
+   COMBA_STORE(C->dp[104]);
+   /* 105 */
+   COMBA_FORWARD;
+   MULADD(at[42], at[127]);    MULADD(at[43], at[126]);    MULADD(at[44], at[125]);    MULADD(at[45], at[124]);    MULADD(at[46], at[123]);    MULADD(at[47], at[122]);    MULADD(at[48], at[121]);    MULADD(at[49], at[120]);    MULADD(at[50], at[119]);    MULADD(at[51], at[118]);    MULADD(at[52], at[117]);    MULADD(at[53], at[116]);    MULADD(at[54], at[115]);    MULADD(at[55], at[114]);    MULADD(at[56], at[113]);    MULADD(at[57], at[112]);    MULADD(at[58], at[111]);    MULADD(at[59], at[110]);    MULADD(at[60], at[109]);    MULADD(at[61], at[108]);    MULADD(at[62], at[107]);    MULADD(at[63], at[106]);
+   COMBA_STORE(C->dp[105]);
+   /* 106 */
+   COMBA_FORWARD;
+   MULADD(at[43], at[127]);    MULADD(at[44], at[126]);    MULADD(at[45], at[125]);    MULADD(at[46], at[124]);    MULADD(at[47], at[123]);    MULADD(at[48], at[122]);    MULADD(at[49], at[121]);    MULADD(at[50], at[120]);    MULADD(at[51], at[119]);    MULADD(at[52], at[118]);    MULADD(at[53], at[117]);    MULADD(at[54], at[116]);    MULADD(at[55], at[115]);    MULADD(at[56], at[114]);    MULADD(at[57], at[113]);    MULADD(at[58], at[112]);    MULADD(at[59], at[111]);    MULADD(at[60], at[110]);    MULADD(at[61], at[109]);    MULADD(at[62], at[108]);    MULADD(at[63], at[107]);
+   COMBA_STORE(C->dp[106]);
+   /* 107 */
+   COMBA_FORWARD;
+   MULADD(at[44], at[127]);    MULADD(at[45], at[126]);    MULADD(at[46], at[125]);    MULADD(at[47], at[124]);    MULADD(at[48], at[123]);    MULADD(at[49], at[122]);    MULADD(at[50], at[121]);    MULADD(at[51], at[120]);    MULADD(at[52], at[119]);    MULADD(at[53], at[118]);    MULADD(at[54], at[117]);    MULADD(at[55], at[116]);    MULADD(at[56], at[115]);    MULADD(at[57], at[114]);    MULADD(at[58], at[113]);    MULADD(at[59], at[112]);    MULADD(at[60], at[111]);    MULADD(at[61], at[110]);    MULADD(at[62], at[109]);    MULADD(at[63], at[108]);
+   COMBA_STORE(C->dp[107]);
+   /* 108 */
+   COMBA_FORWARD;
+   MULADD(at[45], at[127]);    MULADD(at[46], at[126]);    MULADD(at[47], at[125]);    MULADD(at[48], at[124]);    MULADD(at[49], at[123]);    MULADD(at[50], at[122]);    MULADD(at[51], at[121]);    MULADD(at[52], at[120]);    MULADD(at[53], at[119]);    MULADD(at[54], at[118]);    MULADD(at[55], at[117]);    MULADD(at[56], at[116]);    MULADD(at[57], at[115]);    MULADD(at[58], at[114]);    MULADD(at[59], at[113]);    MULADD(at[60], at[112]);    MULADD(at[61], at[111]);    MULADD(at[62], at[110]);    MULADD(at[63], at[109]);
+   COMBA_STORE(C->dp[108]);
+   /* 109 */
+   COMBA_FORWARD;
+   MULADD(at[46], at[127]);    MULADD(at[47], at[126]);    MULADD(at[48], at[125]);    MULADD(at[49], at[124]);    MULADD(at[50], at[123]);    MULADD(at[51], at[122]);    MULADD(at[52], at[121]);    MULADD(at[53], at[120]);    MULADD(at[54], at[119]);    MULADD(at[55], at[118]);    MULADD(at[56], at[117]);    MULADD(at[57], at[116]);    MULADD(at[58], at[115]);    MULADD(at[59], at[114]);    MULADD(at[60], at[113]);    MULADD(at[61], at[112]);    MULADD(at[62], at[111]);    MULADD(at[63], at[110]);
+   COMBA_STORE(C->dp[109]);
+   /* 110 */
+   COMBA_FORWARD;
+   MULADD(at[47], at[127]);    MULADD(at[48], at[126]);    MULADD(at[49], at[125]);    MULADD(at[50], at[124]);    MULADD(at[51], at[123]);    MULADD(at[52], at[122]);    MULADD(at[53], at[121]);    MULADD(at[54], at[120]);    MULADD(at[55], at[119]);    MULADD(at[56], at[118]);    MULADD(at[57], at[117]);    MULADD(at[58], at[116]);    MULADD(at[59], at[115]);    MULADD(at[60], at[114]);    MULADD(at[61], at[113]);    MULADD(at[62], at[112]);    MULADD(at[63], at[111]);
+   COMBA_STORE(C->dp[110]);
+   /* 111 */
+   COMBA_FORWARD;
+   MULADD(at[48], at[127]);    MULADD(at[49], at[126]);    MULADD(at[50], at[125]);    MULADD(at[51], at[124]);    MULADD(at[52], at[123]);    MULADD(at[53], at[122]);    MULADD(at[54], at[121]);    MULADD(at[55], at[120]);    MULADD(at[56], at[119]);    MULADD(at[57], at[118]);    MULADD(at[58], at[117]);    MULADD(at[59], at[116]);    MULADD(at[60], at[115]);    MULADD(at[61], at[114]);    MULADD(at[62], at[113]);    MULADD(at[63], at[112]);
+   COMBA_STORE(C->dp[111]);
+   /* 112 */
+   COMBA_FORWARD;
+   MULADD(at[49], at[127]);    MULADD(at[50], at[126]);    MULADD(at[51], at[125]);    MULADD(at[52], at[124]);    MULADD(at[53], at[123]);    MULADD(at[54], at[122]);    MULADD(at[55], at[121]);    MULADD(at[56], at[120]);    MULADD(at[57], at[119]);    MULADD(at[58], at[118]);    MULADD(at[59], at[117]);    MULADD(at[60], at[116]);    MULADD(at[61], at[115]);    MULADD(at[62], at[114]);    MULADD(at[63], at[113]);
+   COMBA_STORE(C->dp[112]);
+   /* 113 */
+   COMBA_FORWARD;
+   MULADD(at[50], at[127]);    MULADD(at[51], at[126]);    MULADD(at[52], at[125]);    MULADD(at[53], at[124]);    MULADD(at[54], at[123]);    MULADD(at[55], at[122]);    MULADD(at[56], at[121]);    MULADD(at[57], at[120]);    MULADD(at[58], at[119]);    MULADD(at[59], at[118]);    MULADD(at[60], at[117]);    MULADD(at[61], at[116]);    MULADD(at[62], at[115]);    MULADD(at[63], at[114]);
+   COMBA_STORE(C->dp[113]);
+   /* 114 */
+   COMBA_FORWARD;
+   MULADD(at[51], at[127]);    MULADD(at[52], at[126]);    MULADD(at[53], at[125]);    MULADD(at[54], at[124]);    MULADD(at[55], at[123]);    MULADD(at[56], at[122]);    MULADD(at[57], at[121]);    MULADD(at[58], at[120]);    MULADD(at[59], at[119]);    MULADD(at[60], at[118]);    MULADD(at[61], at[117]);    MULADD(at[62], at[116]);    MULADD(at[63], at[115]);
+   COMBA_STORE(C->dp[114]);
+   /* 115 */
+   COMBA_FORWARD;
+   MULADD(at[52], at[127]);    MULADD(at[53], at[126]);    MULADD(at[54], at[125]);    MULADD(at[55], at[124]);    MULADD(at[56], at[123]);    MULADD(at[57], at[122]);    MULADD(at[58], at[121]);    MULADD(at[59], at[120]);    MULADD(at[60], at[119]);    MULADD(at[61], at[118]);    MULADD(at[62], at[117]);    MULADD(at[63], at[116]);
+   COMBA_STORE(C->dp[115]);
+   /* 116 */
+   COMBA_FORWARD;
+   MULADD(at[53], at[127]);    MULADD(at[54], at[126]);    MULADD(at[55], at[125]);    MULADD(at[56], at[124]);    MULADD(at[57], at[123]);    MULADD(at[58], at[122]);    MULADD(at[59], at[121]);    MULADD(at[60], at[120]);    MULADD(at[61], at[119]);    MULADD(at[62], at[118]);    MULADD(at[63], at[117]);
+   COMBA_STORE(C->dp[116]);
+   /* 117 */
+   COMBA_FORWARD;
+   MULADD(at[54], at[127]);    MULADD(at[55], at[126]);    MULADD(at[56], at[125]);    MULADD(at[57], at[124]);    MULADD(at[58], at[123]);    MULADD(at[59], at[122]);    MULADD(at[60], at[121]);    MULADD(at[61], at[120]);    MULADD(at[62], at[119]);    MULADD(at[63], at[118]);
+   COMBA_STORE(C->dp[117]);
+   /* 118 */
+   COMBA_FORWARD;
+   MULADD(at[55], at[127]);    MULADD(at[56], at[126]);    MULADD(at[57], at[125]);    MULADD(at[58], at[124]);    MULADD(at[59], at[123]);    MULADD(at[60], at[122]);    MULADD(at[61], at[121]);    MULADD(at[62], at[120]);    MULADD(at[63], at[119]);
+   COMBA_STORE(C->dp[118]);
+   /* 119 */
+   COMBA_FORWARD;
+   MULADD(at[56], at[127]);    MULADD(at[57], at[126]);    MULADD(at[58], at[125]);    MULADD(at[59], at[124]);    MULADD(at[60], at[123]);    MULADD(at[61], at[122]);    MULADD(at[62], at[121]);    MULADD(at[63], at[120]);
+   COMBA_STORE(C->dp[119]);
+   /* 120 */
+   COMBA_FORWARD;
+   MULADD(at[57], at[127]);    MULADD(at[58], at[126]);    MULADD(at[59], at[125]);    MULADD(at[60], at[124]);    MULADD(at[61], at[123]);    MULADD(at[62], at[122]);    MULADD(at[63], at[121]);
+   COMBA_STORE(C->dp[120]);
+   /* 121 */
+   COMBA_FORWARD;
+   MULADD(at[58], at[127]);    MULADD(at[59], at[126]);    MULADD(at[60], at[125]);    MULADD(at[61], at[124]);    MULADD(at[62], at[123]);    MULADD(at[63], at[122]);
+   COMBA_STORE(C->dp[121]);
+   /* 122 */
+   COMBA_FORWARD;
+   MULADD(at[59], at[127]);    MULADD(at[60], at[126]);    MULADD(at[61], at[125]);    MULADD(at[62], at[124]);    MULADD(at[63], at[123]);
+   COMBA_STORE(C->dp[122]);
+   /* 123 */
+   COMBA_FORWARD;
+   MULADD(at[60], at[127]);    MULADD(at[61], at[126]);    MULADD(at[62], at[125]);    MULADD(at[63], at[124]);
+   COMBA_STORE(C->dp[123]);
+   /* 124 */
+   COMBA_FORWARD;
+   MULADD(at[61], at[127]);    MULADD(at[62], at[126]);    MULADD(at[63], at[125]);
+   COMBA_STORE(C->dp[124]);
+   /* 125 */
+   COMBA_FORWARD;
+   MULADD(at[62], at[127]);    MULADD(at[63], at[126]);
+   COMBA_STORE(C->dp[125]);
+   /* 126 */
+   COMBA_FORWARD;
+   MULADD(at[63], at[127]);
+   COMBA_STORE(C->dp[126]);
+   COMBA_STORE2(C->dp[127]);
+   C->used = 128;
+   C->sign = A->sign ^ B->sign;
+   fp_clamp(C);
+   COMBA_FINI;
+}
+#endif
+
+
+/* $Source$ */
+/* $Revision$ */
+/* $Date$ */
diff --git a/tomsfastmath/src/mul/fp_mul_comba_7.c b/tomsfastmath/src/mul/fp_mul_comba_7.c
new file mode 100644 (file)
index 0000000..c526c1c
--- /dev/null
@@ -0,0 +1,76 @@
+#define TFM_DEFINES
+#include "fp_mul_comba.c"
+
+#if defined(TFM_MUL7) && FP_SIZE >= 14
+void fp_mul_comba7(fp_int *A, fp_int *B, fp_int *C)
+{
+   fp_digit c0, c1, c2, at[14];
+
+   memcpy(at, A->dp, 7 * sizeof(fp_digit));
+   memcpy(at+7, B->dp, 7 * sizeof(fp_digit));
+   COMBA_START;
+
+   COMBA_CLEAR;
+   /* 0 */
+   MULADD(at[0], at[7]);
+   COMBA_STORE(C->dp[0]);
+   /* 1 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[8]);    MULADD(at[1], at[7]);
+   COMBA_STORE(C->dp[1]);
+   /* 2 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[9]);    MULADD(at[1], at[8]);    MULADD(at[2], at[7]);
+   COMBA_STORE(C->dp[2]);
+   /* 3 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[10]);    MULADD(at[1], at[9]);    MULADD(at[2], at[8]);    MULADD(at[3], at[7]);
+   COMBA_STORE(C->dp[3]);
+   /* 4 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[11]);    MULADD(at[1], at[10]);    MULADD(at[2], at[9]);    MULADD(at[3], at[8]);    MULADD(at[4], at[7]);
+   COMBA_STORE(C->dp[4]);
+   /* 5 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[12]);    MULADD(at[1], at[11]);    MULADD(at[2], at[10]);    MULADD(at[3], at[9]);    MULADD(at[4], at[8]);    MULADD(at[5], at[7]);
+   COMBA_STORE(C->dp[5]);
+   /* 6 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[13]);    MULADD(at[1], at[12]);    MULADD(at[2], at[11]);    MULADD(at[3], at[10]);    MULADD(at[4], at[9]);    MULADD(at[5], at[8]);    MULADD(at[6], at[7]);
+   COMBA_STORE(C->dp[6]);
+   /* 7 */
+   COMBA_FORWARD;
+   MULADD(at[1], at[13]);    MULADD(at[2], at[12]);    MULADD(at[3], at[11]);    MULADD(at[4], at[10]);    MULADD(at[5], at[9]);    MULADD(at[6], at[8]);
+   COMBA_STORE(C->dp[7]);
+   /* 8 */
+   COMBA_FORWARD;
+   MULADD(at[2], at[13]);    MULADD(at[3], at[12]);    MULADD(at[4], at[11]);    MULADD(at[5], at[10]);    MULADD(at[6], at[9]);
+   COMBA_STORE(C->dp[8]);
+   /* 9 */
+   COMBA_FORWARD;
+   MULADD(at[3], at[13]);    MULADD(at[4], at[12]);    MULADD(at[5], at[11]);    MULADD(at[6], at[10]);
+   COMBA_STORE(C->dp[9]);
+   /* 10 */
+   COMBA_FORWARD;
+   MULADD(at[4], at[13]);    MULADD(at[5], at[12]);    MULADD(at[6], at[11]);
+   COMBA_STORE(C->dp[10]);
+   /* 11 */
+   COMBA_FORWARD;
+   MULADD(at[5], at[13]);    MULADD(at[6], at[12]);
+   COMBA_STORE(C->dp[11]);
+   /* 12 */
+   COMBA_FORWARD;
+   MULADD(at[6], at[13]);
+   COMBA_STORE(C->dp[12]);
+   COMBA_STORE2(C->dp[13]);
+   C->used = 14;
+   C->sign = A->sign ^ B->sign;
+   fp_clamp(C);
+   COMBA_FINI;
+}
+#endif
+
+
+/* $Source$ */
+/* $Revision$ */
+/* $Date$ */
diff --git a/tomsfastmath/src/mul/fp_mul_comba_8.c b/tomsfastmath/src/mul/fp_mul_comba_8.c
new file mode 100644 (file)
index 0000000..b60ea25
--- /dev/null
@@ -0,0 +1,84 @@
+#define TFM_DEFINES
+#include "fp_mul_comba.c"
+
+#if defined(TFM_MUL8) && FP_SIZE >= 16
+void fp_mul_comba8(fp_int *A, fp_int *B, fp_int *C)
+{
+   fp_digit c0, c1, c2, at[16];
+
+   memcpy(at, A->dp, 8 * sizeof(fp_digit));
+   memcpy(at+8, B->dp, 8 * sizeof(fp_digit));
+   COMBA_START;
+
+   COMBA_CLEAR;
+   /* 0 */
+   MULADD(at[0], at[8]);
+   COMBA_STORE(C->dp[0]);
+   /* 1 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[9]);    MULADD(at[1], at[8]);
+   COMBA_STORE(C->dp[1]);
+   /* 2 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[10]);    MULADD(at[1], at[9]);    MULADD(at[2], at[8]);
+   COMBA_STORE(C->dp[2]);
+   /* 3 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[11]);    MULADD(at[1], at[10]);    MULADD(at[2], at[9]);    MULADD(at[3], at[8]);
+   COMBA_STORE(C->dp[3]);
+   /* 4 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[12]);    MULADD(at[1], at[11]);    MULADD(at[2], at[10]);    MULADD(at[3], at[9]);    MULADD(at[4], at[8]);
+   COMBA_STORE(C->dp[4]);
+   /* 5 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[13]);    MULADD(at[1], at[12]);    MULADD(at[2], at[11]);    MULADD(at[3], at[10]);    MULADD(at[4], at[9]);    MULADD(at[5], at[8]);
+   COMBA_STORE(C->dp[5]);
+   /* 6 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[14]);    MULADD(at[1], at[13]);    MULADD(at[2], at[12]);    MULADD(at[3], at[11]);    MULADD(at[4], at[10]);    MULADD(at[5], at[9]);    MULADD(at[6], at[8]);
+   COMBA_STORE(C->dp[6]);
+   /* 7 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[15]);    MULADD(at[1], at[14]);    MULADD(at[2], at[13]);    MULADD(at[3], at[12]);    MULADD(at[4], at[11]);    MULADD(at[5], at[10]);    MULADD(at[6], at[9]);    MULADD(at[7], at[8]);
+   COMBA_STORE(C->dp[7]);
+   /* 8 */
+   COMBA_FORWARD;
+   MULADD(at[1], at[15]);    MULADD(at[2], at[14]);    MULADD(at[3], at[13]);    MULADD(at[4], at[12]);    MULADD(at[5], at[11]);    MULADD(at[6], at[10]);    MULADD(at[7], at[9]);
+   COMBA_STORE(C->dp[8]);
+   /* 9 */
+   COMBA_FORWARD;
+   MULADD(at[2], at[15]);    MULADD(at[3], at[14]);    MULADD(at[4], at[13]);    MULADD(at[5], at[12]);    MULADD(at[6], at[11]);    MULADD(at[7], at[10]);
+   COMBA_STORE(C->dp[9]);
+   /* 10 */
+   COMBA_FORWARD;
+   MULADD(at[3], at[15]);    MULADD(at[4], at[14]);    MULADD(at[5], at[13]);    MULADD(at[6], at[12]);    MULADD(at[7], at[11]);
+   COMBA_STORE(C->dp[10]);
+   /* 11 */
+   COMBA_FORWARD;
+   MULADD(at[4], at[15]);    MULADD(at[5], at[14]);    MULADD(at[6], at[13]);    MULADD(at[7], at[12]);
+   COMBA_STORE(C->dp[11]);
+   /* 12 */
+   COMBA_FORWARD;
+   MULADD(at[5], at[15]);    MULADD(at[6], at[14]);    MULADD(at[7], at[13]);
+   COMBA_STORE(C->dp[12]);
+   /* 13 */
+   COMBA_FORWARD;
+   MULADD(at[6], at[15]);    MULADD(at[7], at[14]);
+   COMBA_STORE(C->dp[13]);
+   /* 14 */
+   COMBA_FORWARD;
+   MULADD(at[7], at[15]);
+   COMBA_STORE(C->dp[14]);
+   COMBA_STORE2(C->dp[15]);
+   C->used = 16;
+   C->sign = A->sign ^ B->sign;
+   fp_clamp(C);
+   COMBA_FINI;
+}
+#endif
+
+
+/* $Source$ */
+/* $Revision$ */
+/* $Date$ */
diff --git a/tomsfastmath/src/mul/fp_mul_comba_9.c b/tomsfastmath/src/mul/fp_mul_comba_9.c
new file mode 100644 (file)
index 0000000..edc53d9
--- /dev/null
@@ -0,0 +1,92 @@
+#define TFM_DEFINES
+#include "fp_mul_comba.c"
+
+#if defined(TFM_MUL9) && FP_SIZE >= 18
+void fp_mul_comba9(fp_int *A, fp_int *B, fp_int *C)
+{
+   fp_digit c0, c1, c2, at[18];
+
+   memcpy(at, A->dp, 9 * sizeof(fp_digit));
+   memcpy(at+9, B->dp, 9 * sizeof(fp_digit));
+   COMBA_START;
+
+   COMBA_CLEAR;
+   /* 0 */
+   MULADD(at[0], at[9]);
+   COMBA_STORE(C->dp[0]);
+   /* 1 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[10]);    MULADD(at[1], at[9]);
+   COMBA_STORE(C->dp[1]);
+   /* 2 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[11]);    MULADD(at[1], at[10]);    MULADD(at[2], at[9]);
+   COMBA_STORE(C->dp[2]);
+   /* 3 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[12]);    MULADD(at[1], at[11]);    MULADD(at[2], at[10]);    MULADD(at[3], at[9]);
+   COMBA_STORE(C->dp[3]);
+   /* 4 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[13]);    MULADD(at[1], at[12]);    MULADD(at[2], at[11]);    MULADD(at[3], at[10]);    MULADD(at[4], at[9]);
+   COMBA_STORE(C->dp[4]);
+   /* 5 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[14]);    MULADD(at[1], at[13]);    MULADD(at[2], at[12]);    MULADD(at[3], at[11]);    MULADD(at[4], at[10]);    MULADD(at[5], at[9]);
+   COMBA_STORE(C->dp[5]);
+   /* 6 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[15]);    MULADD(at[1], at[14]);    MULADD(at[2], at[13]);    MULADD(at[3], at[12]);    MULADD(at[4], at[11]);    MULADD(at[5], at[10]);    MULADD(at[6], at[9]);
+   COMBA_STORE(C->dp[6]);
+   /* 7 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[16]);    MULADD(at[1], at[15]);    MULADD(at[2], at[14]);    MULADD(at[3], at[13]);    MULADD(at[4], at[12]);    MULADD(at[5], at[11]);    MULADD(at[6], at[10]);    MULADD(at[7], at[9]);
+   COMBA_STORE(C->dp[7]);
+   /* 8 */
+   COMBA_FORWARD;
+   MULADD(at[0], at[17]);    MULADD(at[1], at[16]);    MULADD(at[2], at[15]);    MULADD(at[3], at[14]);    MULADD(at[4], at[13]);    MULADD(at[5], at[12]);    MULADD(at[6], at[11]);    MULADD(at[7], at[10]);    MULADD(at[8], at[9]);
+   COMBA_STORE(C->dp[8]);
+   /* 9 */
+   COMBA_FORWARD;
+   MULADD(at[1], at[17]);    MULADD(at[2], at[16]);    MULADD(at[3], at[15]);    MULADD(at[4], at[14]);    MULADD(at[5], at[13]);    MULADD(at[6], at[12]);    MULADD(at[7], at[11]);    MULADD(at[8], at[10]);
+   COMBA_STORE(C->dp[9]);
+   /* 10 */
+   COMBA_FORWARD;
+   MULADD(at[2], at[17]);    MULADD(at[3], at[16]);    MULADD(at[4], at[15]);    MULADD(at[5], at[14]);    MULADD(at[6], at[13]);    MULADD(at[7], at[12]);    MULADD(at[8], at[11]);
+   COMBA_STORE(C->dp[10]);
+   /* 11 */
+   COMBA_FORWARD;
+   MULADD(at[3], at[17]);    MULADD(at[4], at[16]);    MULADD(at[5], at[15]);    MULADD(at[6], at[14]);    MULADD(at[7], at[13]);    MULADD(at[8], at[12]);
+   COMBA_STORE(C->dp[11]);
+   /* 12 */
+   COMBA_FORWARD;
+   MULADD(at[4], at[17]);    MULADD(at[5], at[16]);    MULADD(at[6], at[15]);    MULADD(at[7], at[14]);    MULADD(at[8], at[13]);
+   COMBA_STORE(C->dp[12]);
+   /* 13 */
+   COMBA_FORWARD;
+   MULADD(at[5], at[17]);    MULADD(at[6], at[16]);    MULADD(at[7], at[15]);    MULADD(at[8], at[14]);
+   COMBA_STORE(C->dp[13]);
+   /* 14 */
+   COMBA_FORWARD;
+   MULADD(at[6], at[17]);    MULADD(at[7], at[16]);    MULADD(at[8], at[15]);
+   COMBA_STORE(C->dp[14]);
+   /* 15 */
+   COMBA_FORWARD;
+   MULADD(at[7], at[17]);    MULADD(at[8], at[16]);
+   COMBA_STORE(C->dp[15]);
+   /* 16 */
+   COMBA_FORWARD;
+   MULADD(at[8], at[17]);
+   COMBA_STORE(C->dp[16]);
+   COMBA_STORE2(C->dp[17]);
+   C->used = 18;
+   C->sign = A->sign ^ B->sign;
+   fp_clamp(C);
+   COMBA_FINI;
+}
+#endif
+
+
+/* $Source$ */
+/* $Revision$ */
+/* $Date$ */
diff --git a/tomsfastmath/src/mul/fp_mul_comba_small_set.c b/tomsfastmath/src/mul/fp_mul_comba_small_set.c
new file mode 100644 (file)
index 0000000..c4b9413
--- /dev/null
@@ -0,0 +1,1233 @@
+#define TFM_DEFINES
+#include "fp_mul_comba.c"
+
+#if defined(TFM_SMALL_SET)
+void fp_mul_comba_small(fp_int *A, fp_int *B, fp_int *C)
+{
+   fp_digit c0, c1, c2, at[32];
+   switch (MAX(A->used, B->used)) { 
+
+   case 1:
+      memcpy(at, A->dp, 1 * sizeof(fp_digit));
+      memcpy(at+1, B->dp, 1 * sizeof(fp_digit));
+      COMBA_START;
+
+      COMBA_CLEAR;
+      /* 0 */
+      MULADD(at[0], at[1]); 
+      COMBA_STORE(C->dp[0]);
+      COMBA_STORE2(C->dp[1]);
+      C->used = 2;
+      C->sign = A->sign ^ B->sign;
+      fp_clamp(C);
+      COMBA_FINI;
+      break;
+
+   case 2:
+      memcpy(at, A->dp, 2 * sizeof(fp_digit));
+      memcpy(at+2, B->dp, 2 * sizeof(fp_digit));
+      COMBA_START;
+
+      COMBA_CLEAR;
+      /* 0 */
+      MULADD(at[0], at[2]); 
+      COMBA_STORE(C->dp[0]);
+      /* 1 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[3]);       MULADD(at[1], at[2]); 
+      COMBA_STORE(C->dp[1]);
+      /* 2 */
+      COMBA_FORWARD;
+      MULADD(at[1], at[3]); 
+      COMBA_STORE(C->dp[2]);
+      COMBA_STORE2(C->dp[3]);
+      C->used = 4;
+      C->sign = A->sign ^ B->sign;
+      fp_clamp(C);
+      COMBA_FINI;
+      break;
+
+   case 3:
+      memcpy(at, A->dp, 3 * sizeof(fp_digit));
+      memcpy(at+3, B->dp, 3 * sizeof(fp_digit));
+      COMBA_START;
+
+      COMBA_CLEAR;
+      /* 0 */
+      MULADD(at[0], at[3]); 
+      COMBA_STORE(C->dp[0]);
+      /* 1 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[4]);       MULADD(at[1], at[3]); 
+      COMBA_STORE(C->dp[1]);
+      /* 2 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[5]);       MULADD(at[1], at[4]);       MULADD(at[2], at[3]); 
+      COMBA_STORE(C->dp[2]);
+      /* 3 */
+      COMBA_FORWARD;
+      MULADD(at[1], at[5]);       MULADD(at[2], at[4]); 
+      COMBA_STORE(C->dp[3]);
+      /* 4 */
+      COMBA_FORWARD;
+      MULADD(at[2], at[5]); 
+      COMBA_STORE(C->dp[4]);
+      COMBA_STORE2(C->dp[5]);
+      C->used = 6;
+      C->sign = A->sign ^ B->sign;
+      fp_clamp(C);
+      COMBA_FINI;
+      break;
+
+   case 4:
+      memcpy(at, A->dp, 4 * sizeof(fp_digit));
+      memcpy(at+4, B->dp, 4 * sizeof(fp_digit));
+      COMBA_START;
+
+      COMBA_CLEAR;
+      /* 0 */
+      MULADD(at[0], at[4]); 
+      COMBA_STORE(C->dp[0]);
+      /* 1 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[5]);       MULADD(at[1], at[4]); 
+      COMBA_STORE(C->dp[1]);
+      /* 2 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[6]);       MULADD(at[1], at[5]);       MULADD(at[2], at[4]); 
+      COMBA_STORE(C->dp[2]);
+      /* 3 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[7]);       MULADD(at[1], at[6]);       MULADD(at[2], at[5]);       MULADD(at[3], at[4]); 
+      COMBA_STORE(C->dp[3]);
+      /* 4 */
+      COMBA_FORWARD;
+      MULADD(at[1], at[7]);       MULADD(at[2], at[6]);       MULADD(at[3], at[5]); 
+      COMBA_STORE(C->dp[4]);
+      /* 5 */
+      COMBA_FORWARD;
+      MULADD(at[2], at[7]);       MULADD(at[3], at[6]); 
+      COMBA_STORE(C->dp[5]);
+      /* 6 */
+      COMBA_FORWARD;
+      MULADD(at[3], at[7]); 
+      COMBA_STORE(C->dp[6]);
+      COMBA_STORE2(C->dp[7]);
+      C->used = 8;
+      C->sign = A->sign ^ B->sign;
+      fp_clamp(C);
+      COMBA_FINI;
+      break;
+
+   case 5:
+      memcpy(at, A->dp, 5 * sizeof(fp_digit));
+      memcpy(at+5, B->dp, 5 * sizeof(fp_digit));
+      COMBA_START;
+
+      COMBA_CLEAR;
+      /* 0 */
+      MULADD(at[0], at[5]); 
+      COMBA_STORE(C->dp[0]);
+      /* 1 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[6]);       MULADD(at[1], at[5]); 
+      COMBA_STORE(C->dp[1]);
+      /* 2 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[7]);       MULADD(at[1], at[6]);       MULADD(at[2], at[5]); 
+      COMBA_STORE(C->dp[2]);
+      /* 3 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[8]);       MULADD(at[1], at[7]);       MULADD(at[2], at[6]);       MULADD(at[3], at[5]); 
+      COMBA_STORE(C->dp[3]);
+      /* 4 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[9]);       MULADD(at[1], at[8]);       MULADD(at[2], at[7]);       MULADD(at[3], at[6]);       MULADD(at[4], at[5]); 
+      COMBA_STORE(C->dp[4]);
+      /* 5 */
+      COMBA_FORWARD;
+      MULADD(at[1], at[9]);       MULADD(at[2], at[8]);       MULADD(at[3], at[7]);       MULADD(at[4], at[6]); 
+      COMBA_STORE(C->dp[5]);
+      /* 6 */
+      COMBA_FORWARD;
+      MULADD(at[2], at[9]);       MULADD(at[3], at[8]);       MULADD(at[4], at[7]); 
+      COMBA_STORE(C->dp[6]);
+      /* 7 */
+      COMBA_FORWARD;
+      MULADD(at[3], at[9]);       MULADD(at[4], at[8]); 
+      COMBA_STORE(C->dp[7]);
+      /* 8 */
+      COMBA_FORWARD;
+      MULADD(at[4], at[9]); 
+      COMBA_STORE(C->dp[8]);
+      COMBA_STORE2(C->dp[9]);
+      C->used = 10;
+      C->sign = A->sign ^ B->sign;
+      fp_clamp(C);
+      COMBA_FINI;
+      break;
+
+   case 6:
+      memcpy(at, A->dp, 6 * sizeof(fp_digit));
+      memcpy(at+6, B->dp, 6 * sizeof(fp_digit));
+      COMBA_START;
+
+      COMBA_CLEAR;
+      /* 0 */
+      MULADD(at[0], at[6]); 
+      COMBA_STORE(C->dp[0]);
+      /* 1 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[7]);       MULADD(at[1], at[6]); 
+      COMBA_STORE(C->dp[1]);
+      /* 2 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[8]);       MULADD(at[1], at[7]);       MULADD(at[2], at[6]); 
+      COMBA_STORE(C->dp[2]);
+      /* 3 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[9]);       MULADD(at[1], at[8]);       MULADD(at[2], at[7]);       MULADD(at[3], at[6]); 
+      COMBA_STORE(C->dp[3]);
+      /* 4 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[10]);       MULADD(at[1], at[9]);       MULADD(at[2], at[8]);       MULADD(at[3], at[7]);       MULADD(at[4], at[6]); 
+      COMBA_STORE(C->dp[4]);
+      /* 5 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[11]);       MULADD(at[1], at[10]);       MULADD(at[2], at[9]);       MULADD(at[3], at[8]);       MULADD(at[4], at[7]);       MULADD(at[5], at[6]); 
+      COMBA_STORE(C->dp[5]);
+      /* 6 */
+      COMBA_FORWARD;
+      MULADD(at[1], at[11]);       MULADD(at[2], at[10]);       MULADD(at[3], at[9]);       MULADD(at[4], at[8]);       MULADD(at[5], at[7]); 
+      COMBA_STORE(C->dp[6]);
+      /* 7 */
+      COMBA_FORWARD;
+      MULADD(at[2], at[11]);       MULADD(at[3], at[10]);       MULADD(at[4], at[9]);       MULADD(at[5], at[8]); 
+      COMBA_STORE(C->dp[7]);
+      /* 8 */
+      COMBA_FORWARD;
+      MULADD(at[3], at[11]);       MULADD(at[4], at[10]);       MULADD(at[5], at[9]); 
+      COMBA_STORE(C->dp[8]);
+      /* 9 */
+      COMBA_FORWARD;
+      MULADD(at[4], at[11]);       MULADD(at[5], at[10]); 
+      COMBA_STORE(C->dp[9]);
+      /* 10 */
+      COMBA_FORWARD;
+      MULADD(at[5], at[11]); 
+      COMBA_STORE(C->dp[10]);
+      COMBA_STORE2(C->dp[11]);
+      C->used = 12;
+      C->sign = A->sign ^ B->sign;
+      fp_clamp(C);
+      COMBA_FINI;
+      break;
+
+   case 7:
+      memcpy(at, A->dp, 7 * sizeof(fp_digit));
+      memcpy(at+7, B->dp, 7 * sizeof(fp_digit));
+      COMBA_START;
+
+      COMBA_CLEAR;
+      /* 0 */
+      MULADD(at[0], at[7]); 
+      COMBA_STORE(C->dp[0]);
+      /* 1 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[8]);       MULADD(at[1], at[7]); 
+      COMBA_STORE(C->dp[1]);
+      /* 2 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[9]);       MULADD(at[1], at[8]);       MULADD(at[2], at[7]); 
+      COMBA_STORE(C->dp[2]);
+      /* 3 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[10]);       MULADD(at[1], at[9]);       MULADD(at[2], at[8]);       MULADD(at[3], at[7]); 
+      COMBA_STORE(C->dp[3]);
+      /* 4 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[11]);       MULADD(at[1], at[10]);       MULADD(at[2], at[9]);       MULADD(at[3], at[8]);       MULADD(at[4], at[7]); 
+      COMBA_STORE(C->dp[4]);
+      /* 5 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[12]);       MULADD(at[1], at[11]);       MULADD(at[2], at[10]);       MULADD(at[3], at[9]);       MULADD(at[4], at[8]);       MULADD(at[5], at[7]); 
+      COMBA_STORE(C->dp[5]);
+      /* 6 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[13]);       MULADD(at[1], at[12]);       MULADD(at[2], at[11]);       MULADD(at[3], at[10]);       MULADD(at[4], at[9]);       MULADD(at[5], at[8]);       MULADD(at[6], at[7]); 
+      COMBA_STORE(C->dp[6]);
+      /* 7 */
+      COMBA_FORWARD;
+      MULADD(at[1], at[13]);       MULADD(at[2], at[12]);       MULADD(at[3], at[11]);       MULADD(at[4], at[10]);       MULADD(at[5], at[9]);       MULADD(at[6], at[8]); 
+      COMBA_STORE(C->dp[7]);
+      /* 8 */
+      COMBA_FORWARD;
+      MULADD(at[2], at[13]);       MULADD(at[3], at[12]);       MULADD(at[4], at[11]);       MULADD(at[5], at[10]);       MULADD(at[6], at[9]); 
+      COMBA_STORE(C->dp[8]);
+      /* 9 */
+      COMBA_FORWARD;
+      MULADD(at[3], at[13]);       MULADD(at[4], at[12]);       MULADD(at[5], at[11]);       MULADD(at[6], at[10]); 
+      COMBA_STORE(C->dp[9]);
+      /* 10 */
+      COMBA_FORWARD;
+      MULADD(at[4], at[13]);       MULADD(at[5], at[12]);       MULADD(at[6], at[11]); 
+      COMBA_STORE(C->dp[10]);
+      /* 11 */
+      COMBA_FORWARD;
+      MULADD(at[5], at[13]);       MULADD(at[6], at[12]); 
+      COMBA_STORE(C->dp[11]);
+      /* 12 */
+      COMBA_FORWARD;
+      MULADD(at[6], at[13]); 
+      COMBA_STORE(C->dp[12]);
+      COMBA_STORE2(C->dp[13]);
+      C->used = 14;
+      C->sign = A->sign ^ B->sign;
+      fp_clamp(C);
+      COMBA_FINI;
+      break;
+
+   case 8:
+      memcpy(at, A->dp, 8 * sizeof(fp_digit));
+      memcpy(at+8, B->dp, 8 * sizeof(fp_digit));
+      COMBA_START;
+
+      COMBA_CLEAR;
+      /* 0 */
+      MULADD(at[0], at[8]); 
+      COMBA_STORE(C->dp[0]);
+      /* 1 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[9]);       MULADD(at[1], at[8]); 
+      COMBA_STORE(C->dp[1]);
+      /* 2 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[10]);       MULADD(at[1], at[9]);       MULADD(at[2], at[8]); 
+      COMBA_STORE(C->dp[2]);
+      /* 3 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[11]);       MULADD(at[1], at[10]);       MULADD(at[2], at[9]);       MULADD(at[3], at[8]); 
+      COMBA_STORE(C->dp[3]);
+      /* 4 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[12]);       MULADD(at[1], at[11]);       MULADD(at[2], at[10]);       MULADD(at[3], at[9]);       MULADD(at[4], at[8]); 
+      COMBA_STORE(C->dp[4]);
+      /* 5 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[13]);       MULADD(at[1], at[12]);       MULADD(at[2], at[11]);       MULADD(at[3], at[10]);       MULADD(at[4], at[9]);       MULADD(at[5], at[8]); 
+      COMBA_STORE(C->dp[5]);
+      /* 6 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[14]);       MULADD(at[1], at[13]);       MULADD(at[2], at[12]);       MULADD(at[3], at[11]);       MULADD(at[4], at[10]);       MULADD(at[5], at[9]);       MULADD(at[6], at[8]); 
+      COMBA_STORE(C->dp[6]);
+      /* 7 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[15]);       MULADD(at[1], at[14]);       MULADD(at[2], at[13]);       MULADD(at[3], at[12]);       MULADD(at[4], at[11]);       MULADD(at[5], at[10]);       MULADD(at[6], at[9]);       MULADD(at[7], at[8]); 
+      COMBA_STORE(C->dp[7]);
+      /* 8 */
+      COMBA_FORWARD;
+      MULADD(at[1], at[15]);       MULADD(at[2], at[14]);       MULADD(at[3], at[13]);       MULADD(at[4], at[12]);       MULADD(at[5], at[11]);       MULADD(at[6], at[10]);       MULADD(at[7], at[9]); 
+      COMBA_STORE(C->dp[8]);
+      /* 9 */
+      COMBA_FORWARD;
+      MULADD(at[2], at[15]);       MULADD(at[3], at[14]);       MULADD(at[4], at[13]);       MULADD(at[5], at[12]);       MULADD(at[6], at[11]);       MULADD(at[7], at[10]); 
+      COMBA_STORE(C->dp[9]);
+      /* 10 */
+      COMBA_FORWARD;
+      MULADD(at[3], at[15]);       MULADD(at[4], at[14]);       MULADD(at[5], at[13]);       MULADD(at[6], at[12]);       MULADD(at[7], at[11]); 
+      COMBA_STORE(C->dp[10]);
+      /* 11 */
+      COMBA_FORWARD;
+      MULADD(at[4], at[15]);       MULADD(at[5], at[14]);       MULADD(at[6], at[13]);       MULADD(at[7], at[12]); 
+      COMBA_STORE(C->dp[11]);
+      /* 12 */
+      COMBA_FORWARD;
+      MULADD(at[5], at[15]);       MULADD(at[6], at[14]);       MULADD(at[7], at[13]); 
+      COMBA_STORE(C->dp[12]);
+      /* 13 */
+      COMBA_FORWARD;
+      MULADD(at[6], at[15]);       MULADD(at[7], at[14]); 
+      COMBA_STORE(C->dp[13]);
+      /* 14 */
+      COMBA_FORWARD;
+      MULADD(at[7], at[15]); 
+      COMBA_STORE(C->dp[14]);
+      COMBA_STORE2(C->dp[15]);
+      C->used = 16;
+      C->sign = A->sign ^ B->sign;
+      fp_clamp(C);
+      COMBA_FINI;
+      break;
+
+   case 9:
+      memcpy(at, A->dp, 9 * sizeof(fp_digit));
+      memcpy(at+9, B->dp, 9 * sizeof(fp_digit));
+      COMBA_START;
+
+      COMBA_CLEAR;
+      /* 0 */
+      MULADD(at[0], at[9]); 
+      COMBA_STORE(C->dp[0]);
+      /* 1 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[10]);       MULADD(at[1], at[9]); 
+      COMBA_STORE(C->dp[1]);
+      /* 2 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[11]);       MULADD(at[1], at[10]);       MULADD(at[2], at[9]); 
+      COMBA_STORE(C->dp[2]);
+      /* 3 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[12]);       MULADD(at[1], at[11]);       MULADD(at[2], at[10]);       MULADD(at[3], at[9]); 
+      COMBA_STORE(C->dp[3]);
+      /* 4 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[13]);       MULADD(at[1], at[12]);       MULADD(at[2], at[11]);       MULADD(at[3], at[10]);       MULADD(at[4], at[9]); 
+      COMBA_STORE(C->dp[4]);
+      /* 5 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[14]);       MULADD(at[1], at[13]);       MULADD(at[2], at[12]);       MULADD(at[3], at[11]);       MULADD(at[4], at[10]);       MULADD(at[5], at[9]); 
+      COMBA_STORE(C->dp[5]);
+      /* 6 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[15]);       MULADD(at[1], at[14]);       MULADD(at[2], at[13]);       MULADD(at[3], at[12]);       MULADD(at[4], at[11]);       MULADD(at[5], at[10]);       MULADD(at[6], at[9]); 
+      COMBA_STORE(C->dp[6]);
+      /* 7 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[16]);       MULADD(at[1], at[15]);       MULADD(at[2], at[14]);       MULADD(at[3], at[13]);       MULADD(at[4], at[12]);       MULADD(at[5], at[11]);       MULADD(at[6], at[10]);       MULADD(at[7], at[9]); 
+      COMBA_STORE(C->dp[7]);
+      /* 8 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[17]);       MULADD(at[1], at[16]);       MULADD(at[2], at[15]);       MULADD(at[3], at[14]);       MULADD(at[4], at[13]);       MULADD(at[5], at[12]);       MULADD(at[6], at[11]);       MULADD(at[7], at[10]);       MULADD(at[8], at[9]); 
+      COMBA_STORE(C->dp[8]);
+      /* 9 */
+      COMBA_FORWARD;
+      MULADD(at[1], at[17]);       MULADD(at[2], at[16]);       MULADD(at[3], at[15]);       MULADD(at[4], at[14]);       MULADD(at[5], at[13]);       MULADD(at[6], at[12]);       MULADD(at[7], at[11]);       MULADD(at[8], at[10]); 
+      COMBA_STORE(C->dp[9]);
+      /* 10 */
+      COMBA_FORWARD;
+      MULADD(at[2], at[17]);       MULADD(at[3], at[16]);       MULADD(at[4], at[15]);       MULADD(at[5], at[14]);       MULADD(at[6], at[13]);       MULADD(at[7], at[12]);       MULADD(at[8], at[11]); 
+      COMBA_STORE(C->dp[10]);
+      /* 11 */
+      COMBA_FORWARD;
+      MULADD(at[3], at[17]);       MULADD(at[4], at[16]);       MULADD(at[5], at[15]);       MULADD(at[6], at[14]);       MULADD(at[7], at[13]);       MULADD(at[8], at[12]); 
+      COMBA_STORE(C->dp[11]);
+      /* 12 */
+      COMBA_FORWARD;
+      MULADD(at[4], at[17]);       MULADD(at[5], at[16]);       MULADD(at[6], at[15]);       MULADD(at[7], at[14]);       MULADD(at[8], at[13]); 
+      COMBA_STORE(C->dp[12]);
+      /* 13 */
+      COMBA_FORWARD;
+      MULADD(at[5], at[17]);       MULADD(at[6], at[16]);       MULADD(at[7], at[15]);       MULADD(at[8], at[14]); 
+      COMBA_STORE(C->dp[13]);
+      /* 14 */
+      COMBA_FORWARD;
+      MULADD(at[6], at[17]);       MULADD(at[7], at[16]);       MULADD(at[8], at[15]); 
+      COMBA_STORE(C->dp[14]);
+      /* 15 */
+      COMBA_FORWARD;
+      MULADD(at[7], at[17]);       MULADD(at[8], at[16]); 
+      COMBA_STORE(C->dp[15]);
+      /* 16 */
+      COMBA_FORWARD;
+      MULADD(at[8], at[17]); 
+      COMBA_STORE(C->dp[16]);
+      COMBA_STORE2(C->dp[17]);
+      C->used = 18;
+      C->sign = A->sign ^ B->sign;
+      fp_clamp(C);
+      COMBA_FINI;
+      break;
+
+   case 10:
+      memcpy(at, A->dp, 10 * sizeof(fp_digit));
+      memcpy(at+10, B->dp, 10 * sizeof(fp_digit));
+      COMBA_START;
+
+      COMBA_CLEAR;
+      /* 0 */
+      MULADD(at[0], at[10]); 
+      COMBA_STORE(C->dp[0]);
+      /* 1 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[11]);       MULADD(at[1], at[10]); 
+      COMBA_STORE(C->dp[1]);
+      /* 2 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[12]);       MULADD(at[1], at[11]);       MULADD(at[2], at[10]); 
+      COMBA_STORE(C->dp[2]);
+      /* 3 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[13]);       MULADD(at[1], at[12]);       MULADD(at[2], at[11]);       MULADD(at[3], at[10]); 
+      COMBA_STORE(C->dp[3]);
+      /* 4 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[14]);       MULADD(at[1], at[13]);       MULADD(at[2], at[12]);       MULADD(at[3], at[11]);       MULADD(at[4], at[10]); 
+      COMBA_STORE(C->dp[4]);
+      /* 5 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[15]);       MULADD(at[1], at[14]);       MULADD(at[2], at[13]);       MULADD(at[3], at[12]);       MULADD(at[4], at[11]);       MULADD(at[5], at[10]); 
+      COMBA_STORE(C->dp[5]);
+      /* 6 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[16]);       MULADD(at[1], at[15]);       MULADD(at[2], at[14]);       MULADD(at[3], at[13]);       MULADD(at[4], at[12]);       MULADD(at[5], at[11]);       MULADD(at[6], at[10]); 
+      COMBA_STORE(C->dp[6]);
+      /* 7 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[17]);       MULADD(at[1], at[16]);       MULADD(at[2], at[15]);       MULADD(at[3], at[14]);       MULADD(at[4], at[13]);       MULADD(at[5], at[12]);       MULADD(at[6], at[11]);       MULADD(at[7], at[10]); 
+      COMBA_STORE(C->dp[7]);
+      /* 8 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[18]);       MULADD(at[1], at[17]);       MULADD(at[2], at[16]);       MULADD(at[3], at[15]);       MULADD(at[4], at[14]);       MULADD(at[5], at[13]);       MULADD(at[6], at[12]);       MULADD(at[7], at[11]);       MULADD(at[8], at[10]); 
+      COMBA_STORE(C->dp[8]);
+      /* 9 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[19]);       MULADD(at[1], at[18]);       MULADD(at[2], at[17]);       MULADD(at[3], at[16]);       MULADD(at[4], at[15]);       MULADD(at[5], at[14]);       MULADD(at[6], at[13]);       MULADD(at[7], at[12]);       MULADD(at[8], at[11]);       MULADD(at[9], at[10]); 
+      COMBA_STORE(C->dp[9]);
+      /* 10 */
+      COMBA_FORWARD;
+      MULADD(at[1], at[19]);       MULADD(at[2], at[18]);       MULADD(at[3], at[17]);       MULADD(at[4], at[16]);       MULADD(at[5], at[15]);       MULADD(at[6], at[14]);       MULADD(at[7], at[13]);       MULADD(at[8], at[12]);       MULADD(at[9], at[11]); 
+      COMBA_STORE(C->dp[10]);
+      /* 11 */
+      COMBA_FORWARD;
+      MULADD(at[2], at[19]);       MULADD(at[3], at[18]);       MULADD(at[4], at[17]);       MULADD(at[5], at[16]);       MULADD(at[6], at[15]);       MULADD(at[7], at[14]);       MULADD(at[8], at[13]);       MULADD(at[9], at[12]); 
+      COMBA_STORE(C->dp[11]);
+      /* 12 */
+      COMBA_FORWARD;
+      MULADD(at[3], at[19]);       MULADD(at[4], at[18]);       MULADD(at[5], at[17]);       MULADD(at[6], at[16]);       MULADD(at[7], at[15]);       MULADD(at[8], at[14]);       MULADD(at[9], at[13]); 
+      COMBA_STORE(C->dp[12]);
+      /* 13 */
+      COMBA_FORWARD;
+      MULADD(at[4], at[19]);       MULADD(at[5], at[18]);       MULADD(at[6], at[17]);       MULADD(at[7], at[16]);       MULADD(at[8], at[15]);       MULADD(at[9], at[14]); 
+      COMBA_STORE(C->dp[13]);
+      /* 14 */
+      COMBA_FORWARD;
+      MULADD(at[5], at[19]);       MULADD(at[6], at[18]);       MULADD(at[7], at[17]);       MULADD(at[8], at[16]);       MULADD(at[9], at[15]); 
+      COMBA_STORE(C->dp[14]);
+      /* 15 */
+      COMBA_FORWARD;
+      MULADD(at[6], at[19]);       MULADD(at[7], at[18]);       MULADD(at[8], at[17]);       MULADD(at[9], at[16]); 
+      COMBA_STORE(C->dp[15]);
+      /* 16 */
+      COMBA_FORWARD;
+      MULADD(at[7], at[19]);       MULADD(at[8], at[18]);       MULADD(at[9], at[17]); 
+      COMBA_STORE(C->dp[16]);
+      /* 17 */
+      COMBA_FORWARD;
+      MULADD(at[8], at[19]);       MULADD(at[9], at[18]); 
+      COMBA_STORE(C->dp[17]);
+      /* 18 */
+      COMBA_FORWARD;
+      MULADD(at[9], at[19]); 
+      COMBA_STORE(C->dp[18]);
+      COMBA_STORE2(C->dp[19]);
+      C->used = 20;
+      C->sign = A->sign ^ B->sign;
+      fp_clamp(C);
+      COMBA_FINI;
+      break;
+
+   case 11:
+      memcpy(at, A->dp, 11 * sizeof(fp_digit));
+      memcpy(at+11, B->dp, 11 * sizeof(fp_digit));
+      COMBA_START;
+
+      COMBA_CLEAR;
+      /* 0 */
+      MULADD(at[0], at[11]); 
+      COMBA_STORE(C->dp[0]);
+      /* 1 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[12]);       MULADD(at[1], at[11]); 
+      COMBA_STORE(C->dp[1]);
+      /* 2 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[13]);       MULADD(at[1], at[12]);       MULADD(at[2], at[11]); 
+      COMBA_STORE(C->dp[2]);
+      /* 3 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[14]);       MULADD(at[1], at[13]);       MULADD(at[2], at[12]);       MULADD(at[3], at[11]); 
+      COMBA_STORE(C->dp[3]);
+      /* 4 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[15]);       MULADD(at[1], at[14]);       MULADD(at[2], at[13]);       MULADD(at[3], at[12]);       MULADD(at[4], at[11]); 
+      COMBA_STORE(C->dp[4]);
+      /* 5 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[16]);       MULADD(at[1], at[15]);       MULADD(at[2], at[14]);       MULADD(at[3], at[13]);       MULADD(at[4], at[12]);       MULADD(at[5], at[11]); 
+      COMBA_STORE(C->dp[5]);
+      /* 6 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[17]);       MULADD(at[1], at[16]);       MULADD(at[2], at[15]);       MULADD(at[3], at[14]);       MULADD(at[4], at[13]);       MULADD(at[5], at[12]);       MULADD(at[6], at[11]); 
+      COMBA_STORE(C->dp[6]);
+      /* 7 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[18]);       MULADD(at[1], at[17]);       MULADD(at[2], at[16]);       MULADD(at[3], at[15]);       MULADD(at[4], at[14]);       MULADD(at[5], at[13]);       MULADD(at[6], at[12]);       MULADD(at[7], at[11]); 
+      COMBA_STORE(C->dp[7]);
+      /* 8 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[19]);       MULADD(at[1], at[18]);       MULADD(at[2], at[17]);       MULADD(at[3], at[16]);       MULADD(at[4], at[15]);       MULADD(at[5], at[14]);       MULADD(at[6], at[13]);       MULADD(at[7], at[12]);       MULADD(at[8], at[11]); 
+      COMBA_STORE(C->dp[8]);
+      /* 9 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[20]);       MULADD(at[1], at[19]);       MULADD(at[2], at[18]);       MULADD(at[3], at[17]);       MULADD(at[4], at[16]);       MULADD(at[5], at[15]);       MULADD(at[6], at[14]);       MULADD(at[7], at[13]);       MULADD(at[8], at[12]);       MULADD(at[9], at[11]); 
+      COMBA_STORE(C->dp[9]);
+      /* 10 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[21]);       MULADD(at[1], at[20]);       MULADD(at[2], at[19]);       MULADD(at[3], at[18]);       MULADD(at[4], at[17]);       MULADD(at[5], at[16]);       MULADD(at[6], at[15]);       MULADD(at[7], at[14]);       MULADD(at[8], at[13]);       MULADD(at[9], at[12]);       MULADD(at[10], at[11]); 
+      COMBA_STORE(C->dp[10]);
+      /* 11 */
+      COMBA_FORWARD;
+      MULADD(at[1], at[21]);       MULADD(at[2], at[20]);       MULADD(at[3], at[19]);       MULADD(at[4], at[18]);       MULADD(at[5], at[17]);       MULADD(at[6], at[16]);       MULADD(at[7], at[15]);       MULADD(at[8], at[14]);       MULADD(at[9], at[13]);       MULADD(at[10], at[12]); 
+      COMBA_STORE(C->dp[11]);
+      /* 12 */
+      COMBA_FORWARD;
+      MULADD(at[2], at[21]);       MULADD(at[3], at[20]);       MULADD(at[4], at[19]);       MULADD(at[5], at[18]);       MULADD(at[6], at[17]);       MULADD(at[7], at[16]);       MULADD(at[8], at[15]);       MULADD(at[9], at[14]);       MULADD(at[10], at[13]); 
+      COMBA_STORE(C->dp[12]);
+      /* 13 */
+      COMBA_FORWARD;
+      MULADD(at[3], at[21]);       MULADD(at[4], at[20]);       MULADD(at[5], at[19]);       MULADD(at[6], at[18]);       MULADD(at[7], at[17]);       MULADD(at[8], at[16]);       MULADD(at[9], at[15]);       MULADD(at[10], at[14]); 
+      COMBA_STORE(C->dp[13]);
+      /* 14 */
+      COMBA_FORWARD;
+      MULADD(at[4], at[21]);       MULADD(at[5], at[20]);       MULADD(at[6], at[19]);       MULADD(at[7], at[18]);       MULADD(at[8], at[17]);       MULADD(at[9], at[16]);       MULADD(at[10], at[15]); 
+      COMBA_STORE(C->dp[14]);
+      /* 15 */
+      COMBA_FORWARD;
+      MULADD(at[5], at[21]);       MULADD(at[6], at[20]);       MULADD(at[7], at[19]);       MULADD(at[8], at[18]);       MULADD(at[9], at[17]);       MULADD(at[10], at[16]); 
+      COMBA_STORE(C->dp[15]);
+      /* 16 */
+      COMBA_FORWARD;
+      MULADD(at[6], at[21]);       MULADD(at[7], at[20]);       MULADD(at[8], at[19]);       MULADD(at[9], at[18]);       MULADD(at[10], at[17]); 
+      COMBA_STORE(C->dp[16]);
+      /* 17 */
+      COMBA_FORWARD;
+      MULADD(at[7], at[21]);       MULADD(at[8], at[20]);       MULADD(at[9], at[19]);       MULADD(at[10], at[18]); 
+      COMBA_STORE(C->dp[17]);
+      /* 18 */
+      COMBA_FORWARD;
+      MULADD(at[8], at[21]);       MULADD(at[9], at[20]);       MULADD(at[10], at[19]); 
+      COMBA_STORE(C->dp[18]);
+      /* 19 */
+      COMBA_FORWARD;
+      MULADD(at[9], at[21]);       MULADD(at[10], at[20]); 
+      COMBA_STORE(C->dp[19]);
+      /* 20 */
+      COMBA_FORWARD;
+      MULADD(at[10], at[21]); 
+      COMBA_STORE(C->dp[20]);
+      COMBA_STORE2(C->dp[21]);
+      C->used = 22;
+      C->sign = A->sign ^ B->sign;
+      fp_clamp(C);
+      COMBA_FINI;
+      break;
+
+   case 12:
+      memcpy(at, A->dp, 12 * sizeof(fp_digit));
+      memcpy(at+12, B->dp, 12 * sizeof(fp_digit));
+      COMBA_START;
+
+      COMBA_CLEAR;
+      /* 0 */
+      MULADD(at[0], at[12]); 
+      COMBA_STORE(C->dp[0]);
+      /* 1 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[13]);       MULADD(at[1], at[12]); 
+      COMBA_STORE(C->dp[1]);
+      /* 2 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[14]);       MULADD(at[1], at[13]);       MULADD(at[2], at[12]); 
+      COMBA_STORE(C->dp[2]);
+      /* 3 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[15]);       MULADD(at[1], at[14]);       MULADD(at[2], at[13]);       MULADD(at[3], at[12]); 
+      COMBA_STORE(C->dp[3]);
+      /* 4 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[16]);       MULADD(at[1], at[15]);       MULADD(at[2], at[14]);       MULADD(at[3], at[13]);       MULADD(at[4], at[12]); 
+      COMBA_STORE(C->dp[4]);
+      /* 5 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[17]);       MULADD(at[1], at[16]);       MULADD(at[2], at[15]);       MULADD(at[3], at[14]);       MULADD(at[4], at[13]);       MULADD(at[5], at[12]); 
+      COMBA_STORE(C->dp[5]);
+      /* 6 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[18]);       MULADD(at[1], at[17]);       MULADD(at[2], at[16]);       MULADD(at[3], at[15]);       MULADD(at[4], at[14]);       MULADD(at[5], at[13]);       MULADD(at[6], at[12]); 
+      COMBA_STORE(C->dp[6]);
+      /* 7 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[19]);       MULADD(at[1], at[18]);       MULADD(at[2], at[17]);       MULADD(at[3], at[16]);       MULADD(at[4], at[15]);       MULADD(at[5], at[14]);       MULADD(at[6], at[13]);       MULADD(at[7], at[12]); 
+      COMBA_STORE(C->dp[7]);
+      /* 8 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[20]);       MULADD(at[1], at[19]);       MULADD(at[2], at[18]);       MULADD(at[3], at[17]);       MULADD(at[4], at[16]);       MULADD(at[5], at[15]);       MULADD(at[6], at[14]);       MULADD(at[7], at[13]);       MULADD(at[8], at[12]); 
+      COMBA_STORE(C->dp[8]);
+      /* 9 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[21]);       MULADD(at[1], at[20]);       MULADD(at[2], at[19]);       MULADD(at[3], at[18]);       MULADD(at[4], at[17]);       MULADD(at[5], at[16]);       MULADD(at[6], at[15]);       MULADD(at[7], at[14]);       MULADD(at[8], at[13]);       MULADD(at[9], at[12]); 
+      COMBA_STORE(C->dp[9]);
+      /* 10 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[22]);       MULADD(at[1], at[21]);       MULADD(at[2], at[20]);       MULADD(at[3], at[19]);       MULADD(at[4], at[18]);       MULADD(at[5], at[17]);       MULADD(at[6], at[16]);       MULADD(at[7], at[15]);       MULADD(at[8], at[14]);       MULADD(at[9], at[13]);       MULADD(at[10], at[12]); 
+      COMBA_STORE(C->dp[10]);
+      /* 11 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[23]);       MULADD(at[1], at[22]);       MULADD(at[2], at[21]);       MULADD(at[3], at[20]);       MULADD(at[4], at[19]);       MULADD(at[5], at[18]);       MULADD(at[6], at[17]);       MULADD(at[7], at[16]);       MULADD(at[8], at[15]);       MULADD(at[9], at[14]);       MULADD(at[10], at[13]);       MULADD(at[11], at[12]); 
+      COMBA_STORE(C->dp[11]);
+      /* 12 */
+      COMBA_FORWARD;
+      MULADD(at[1], at[23]);       MULADD(at[2], at[22]);       MULADD(at[3], at[21]);       MULADD(at[4], at[20]);       MULADD(at[5], at[19]);       MULADD(at[6], at[18]);       MULADD(at[7], at[17]);       MULADD(at[8], at[16]);       MULADD(at[9], at[15]);       MULADD(at[10], at[14]);       MULADD(at[11], at[13]); 
+      COMBA_STORE(C->dp[12]);
+      /* 13 */
+      COMBA_FORWARD;
+      MULADD(at[2], at[23]);       MULADD(at[3], at[22]);       MULADD(at[4], at[21]);       MULADD(at[5], at[20]);       MULADD(at[6], at[19]);       MULADD(at[7], at[18]);       MULADD(at[8], at[17]);       MULADD(at[9], at[16]);       MULADD(at[10], at[15]);       MULADD(at[11], at[14]); 
+      COMBA_STORE(C->dp[13]);
+      /* 14 */
+      COMBA_FORWARD;
+      MULADD(at[3], at[23]);       MULADD(at[4], at[22]);       MULADD(at[5], at[21]);       MULADD(at[6], at[20]);       MULADD(at[7], at[19]);       MULADD(at[8], at[18]);       MULADD(at[9], at[17]);       MULADD(at[10], at[16]);       MULADD(at[11], at[15]); 
+      COMBA_STORE(C->dp[14]);
+      /* 15 */
+      COMBA_FORWARD;
+      MULADD(at[4], at[23]);       MULADD(at[5], at[22]);       MULADD(at[6], at[21]);       MULADD(at[7], at[20]);       MULADD(at[8], at[19]);       MULADD(at[9], at[18]);       MULADD(at[10], at[17]);       MULADD(at[11], at[16]); 
+      COMBA_STORE(C->dp[15]);
+      /* 16 */
+      COMBA_FORWARD;
+      MULADD(at[5], at[23]);       MULADD(at[6], at[22]);       MULADD(at[7], at[21]);       MULADD(at[8], at[20]);       MULADD(at[9], at[19]);       MULADD(at[10], at[18]);       MULADD(at[11], at[17]); 
+      COMBA_STORE(C->dp[16]);
+      /* 17 */
+      COMBA_FORWARD;
+      MULADD(at[6], at[23]);       MULADD(at[7], at[22]);       MULADD(at[8], at[21]);       MULADD(at[9], at[20]);       MULADD(at[10], at[19]);       MULADD(at[11], at[18]); 
+      COMBA_STORE(C->dp[17]);
+      /* 18 */
+      COMBA_FORWARD;
+      MULADD(at[7], at[23]);       MULADD(at[8], at[22]);       MULADD(at[9], at[21]);       MULADD(at[10], at[20]);       MULADD(at[11], at[19]); 
+      COMBA_STORE(C->dp[18]);
+      /* 19 */
+      COMBA_FORWARD;
+      MULADD(at[8], at[23]);       MULADD(at[9], at[22]);       MULADD(at[10], at[21]);       MULADD(at[11], at[20]); 
+      COMBA_STORE(C->dp[19]);
+      /* 20 */
+      COMBA_FORWARD;
+      MULADD(at[9], at[23]);       MULADD(at[10], at[22]);       MULADD(at[11], at[21]); 
+      COMBA_STORE(C->dp[20]);
+      /* 21 */
+      COMBA_FORWARD;
+      MULADD(at[10], at[23]);       MULADD(at[11], at[22]); 
+      COMBA_STORE(C->dp[21]);
+      /* 22 */
+      COMBA_FORWARD;
+      MULADD(at[11], at[23]); 
+      COMBA_STORE(C->dp[22]);
+      COMBA_STORE2(C->dp[23]);
+      C->used = 24;
+      C->sign = A->sign ^ B->sign;
+      fp_clamp(C);
+      COMBA_FINI;
+      break;
+
+   case 13:
+      memcpy(at, A->dp, 13 * sizeof(fp_digit));
+      memcpy(at+13, B->dp, 13 * sizeof(fp_digit));
+      COMBA_START;
+
+      COMBA_CLEAR;
+      /* 0 */
+      MULADD(at[0], at[13]); 
+      COMBA_STORE(C->dp[0]);
+      /* 1 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[14]);       MULADD(at[1], at[13]); 
+      COMBA_STORE(C->dp[1]);
+      /* 2 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[15]);       MULADD(at[1], at[14]);       MULADD(at[2], at[13]); 
+      COMBA_STORE(C->dp[2]);
+      /* 3 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[16]);       MULADD(at[1], at[15]);       MULADD(at[2], at[14]);       MULADD(at[3], at[13]); 
+      COMBA_STORE(C->dp[3]);
+      /* 4 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[17]);       MULADD(at[1], at[16]);       MULADD(at[2], at[15]);       MULADD(at[3], at[14]);       MULADD(at[4], at[13]); 
+      COMBA_STORE(C->dp[4]);
+      /* 5 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[18]);       MULADD(at[1], at[17]);       MULADD(at[2], at[16]);       MULADD(at[3], at[15]);       MULADD(at[4], at[14]);       MULADD(at[5], at[13]); 
+      COMBA_STORE(C->dp[5]);
+      /* 6 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[19]);       MULADD(at[1], at[18]);       MULADD(at[2], at[17]);       MULADD(at[3], at[16]);       MULADD(at[4], at[15]);       MULADD(at[5], at[14]);       MULADD(at[6], at[13]); 
+      COMBA_STORE(C->dp[6]);
+      /* 7 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[20]);       MULADD(at[1], at[19]);       MULADD(at[2], at[18]);       MULADD(at[3], at[17]);       MULADD(at[4], at[16]);       MULADD(at[5], at[15]);       MULADD(at[6], at[14]);       MULADD(at[7], at[13]); 
+      COMBA_STORE(C->dp[7]);
+      /* 8 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[21]);       MULADD(at[1], at[20]);       MULADD(at[2], at[19]);       MULADD(at[3], at[18]);       MULADD(at[4], at[17]);       MULADD(at[5], at[16]);       MULADD(at[6], at[15]);       MULADD(at[7], at[14]);       MULADD(at[8], at[13]); 
+      COMBA_STORE(C->dp[8]);
+      /* 9 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[22]);       MULADD(at[1], at[21]);       MULADD(at[2], at[20]);       MULADD(at[3], at[19]);       MULADD(at[4], at[18]);       MULADD(at[5], at[17]);       MULADD(at[6], at[16]);       MULADD(at[7], at[15]);       MULADD(at[8], at[14]);       MULADD(at[9], at[13]); 
+      COMBA_STORE(C->dp[9]);
+      /* 10 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[23]);       MULADD(at[1], at[22]);       MULADD(at[2], at[21]);       MULADD(at[3], at[20]);       MULADD(at[4], at[19]);       MULADD(at[5], at[18]);       MULADD(at[6], at[17]);       MULADD(at[7], at[16]);       MULADD(at[8], at[15]);       MULADD(at[9], at[14]);       MULADD(at[10], at[13]); 
+      COMBA_STORE(C->dp[10]);
+      /* 11 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[24]);       MULADD(at[1], at[23]);       MULADD(at[2], at[22]);       MULADD(at[3], at[21]);       MULADD(at[4], at[20]);       MULADD(at[5], at[19]);       MULADD(at[6], at[18]);       MULADD(at[7], at[17]);       MULADD(at[8], at[16]);       MULADD(at[9], at[15]);       MULADD(at[10], at[14]);       MULADD(at[11], at[13]); 
+      COMBA_STORE(C->dp[11]);
+      /* 12 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[25]);       MULADD(at[1], at[24]);       MULADD(at[2], at[23]);       MULADD(at[3], at[22]);       MULADD(at[4], at[21]);       MULADD(at[5], at[20]);       MULADD(at[6], at[19]);       MULADD(at[7], at[18]);       MULADD(at[8], at[17]);       MULADD(at[9], at[16]);       MULADD(at[10], at[15]);       MULADD(at[11], at[14]);       MULADD(at[12], at[13]); 
+      COMBA_STORE(C->dp[12]);
+      /* 13 */
+      COMBA_FORWARD;
+      MULADD(at[1], at[25]);       MULADD(at[2], at[24]);       MULADD(at[3], at[23]);       MULADD(at[4], at[22]);       MULADD(at[5], at[21]);       MULADD(at[6], at[20]);       MULADD(at[7], at[19]);       MULADD(at[8], at[18]);       MULADD(at[9], at[17]);       MULADD(at[10], at[16]);       MULADD(at[11], at[15]);       MULADD(at[12], at[14]); 
+      COMBA_STORE(C->dp[13]);
+      /* 14 */
+      COMBA_FORWARD;
+      MULADD(at[2], at[25]);       MULADD(at[3], at[24]);       MULADD(at[4], at[23]);       MULADD(at[5], at[22]);       MULADD(at[6], at[21]);       MULADD(at[7], at[20]);       MULADD(at[8], at[19]);       MULADD(at[9], at[18]);       MULADD(at[10], at[17]);       MULADD(at[11], at[16]);       MULADD(at[12], at[15]); 
+      COMBA_STORE(C->dp[14]);
+      /* 15 */
+      COMBA_FORWARD;
+      MULADD(at[3], at[25]);       MULADD(at[4], at[24]);       MULADD(at[5], at[23]);       MULADD(at[6], at[22]);       MULADD(at[7], at[21]);       MULADD(at[8], at[20]);       MULADD(at[9], at[19]);       MULADD(at[10], at[18]);       MULADD(at[11], at[17]);       MULADD(at[12], at[16]); 
+      COMBA_STORE(C->dp[15]);
+      /* 16 */
+      COMBA_FORWARD;
+      MULADD(at[4], at[25]);       MULADD(at[5], at[24]);       MULADD(at[6], at[23]);       MULADD(at[7], at[22]);       MULADD(at[8], at[21]);       MULADD(at[9], at[20]);       MULADD(at[10], at[19]);       MULADD(at[11], at[18]);       MULADD(at[12], at[17]); 
+      COMBA_STORE(C->dp[16]);
+      /* 17 */
+      COMBA_FORWARD;
+      MULADD(at[5], at[25]);       MULADD(at[6], at[24]);       MULADD(at[7], at[23]);       MULADD(at[8], at[22]);       MULADD(at[9], at[21]);       MULADD(at[10], at[20]);       MULADD(at[11], at[19]);       MULADD(at[12], at[18]); 
+      COMBA_STORE(C->dp[17]);
+      /* 18 */
+      COMBA_FORWARD;
+      MULADD(at[6], at[25]);       MULADD(at[7], at[24]);       MULADD(at[8], at[23]);       MULADD(at[9], at[22]);       MULADD(at[10], at[21]);       MULADD(at[11], at[20]);       MULADD(at[12], at[19]); 
+      COMBA_STORE(C->dp[18]);
+      /* 19 */
+      COMBA_FORWARD;
+      MULADD(at[7], at[25]);       MULADD(at[8], at[24]);       MULADD(at[9], at[23]);       MULADD(at[10], at[22]);       MULADD(at[11], at[21]);       MULADD(at[12], at[20]); 
+      COMBA_STORE(C->dp[19]);
+      /* 20 */
+      COMBA_FORWARD;
+      MULADD(at[8], at[25]);       MULADD(at[9], at[24]);       MULADD(at[10], at[23]);       MULADD(at[11], at[22]);       MULADD(at[12], at[21]); 
+      COMBA_STORE(C->dp[20]);
+      /* 21 */
+      COMBA_FORWARD;
+      MULADD(at[9], at[25]);       MULADD(at[10], at[24]);       MULADD(at[11], at[23]);       MULADD(at[12], at[22]); 
+      COMBA_STORE(C->dp[21]);
+      /* 22 */
+      COMBA_FORWARD;
+      MULADD(at[10], at[25]);       MULADD(at[11], at[24]);       MULADD(at[12], at[23]); 
+      COMBA_STORE(C->dp[22]);
+      /* 23 */
+      COMBA_FORWARD;
+      MULADD(at[11], at[25]);       MULADD(at[12], at[24]); 
+      COMBA_STORE(C->dp[23]);
+      /* 24 */
+      COMBA_FORWARD;
+      MULADD(at[12], at[25]); 
+      COMBA_STORE(C->dp[24]);
+      COMBA_STORE2(C->dp[25]);
+      C->used = 26;
+      C->sign = A->sign ^ B->sign;
+      fp_clamp(C);
+      COMBA_FINI;
+      break;
+
+   case 14:
+      memcpy(at, A->dp, 14 * sizeof(fp_digit));
+      memcpy(at+14, B->dp, 14 * sizeof(fp_digit));
+      COMBA_START;
+
+      COMBA_CLEAR;
+      /* 0 */
+      MULADD(at[0], at[14]); 
+      COMBA_STORE(C->dp[0]);
+      /* 1 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[15]);       MULADD(at[1], at[14]); 
+      COMBA_STORE(C->dp[1]);
+      /* 2 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[16]);       MULADD(at[1], at[15]);       MULADD(at[2], at[14]); 
+      COMBA_STORE(C->dp[2]);
+      /* 3 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[17]);       MULADD(at[1], at[16]);       MULADD(at[2], at[15]);       MULADD(at[3], at[14]); 
+      COMBA_STORE(C->dp[3]);
+      /* 4 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[18]);       MULADD(at[1], at[17]);       MULADD(at[2], at[16]);       MULADD(at[3], at[15]);       MULADD(at[4], at[14]); 
+      COMBA_STORE(C->dp[4]);
+      /* 5 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[19]);       MULADD(at[1], at[18]);       MULADD(at[2], at[17]);       MULADD(at[3], at[16]);       MULADD(at[4], at[15]);       MULADD(at[5], at[14]); 
+      COMBA_STORE(C->dp[5]);
+      /* 6 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[20]);       MULADD(at[1], at[19]);       MULADD(at[2], at[18]);       MULADD(at[3], at[17]);       MULADD(at[4], at[16]);       MULADD(at[5], at[15]);       MULADD(at[6], at[14]); 
+      COMBA_STORE(C->dp[6]);
+      /* 7 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[21]);       MULADD(at[1], at[20]);       MULADD(at[2], at[19]);       MULADD(at[3], at[18]);       MULADD(at[4], at[17]);       MULADD(at[5], at[16]);       MULADD(at[6], at[15]);       MULADD(at[7], at[14]); 
+      COMBA_STORE(C->dp[7]);
+      /* 8 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[22]);       MULADD(at[1], at[21]);       MULADD(at[2], at[20]);       MULADD(at[3], at[19]);       MULADD(at[4], at[18]);       MULADD(at[5], at[17]);       MULADD(at[6], at[16]);       MULADD(at[7], at[15]);       MULADD(at[8], at[14]); 
+      COMBA_STORE(C->dp[8]);
+      /* 9 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[23]);       MULADD(at[1], at[22]);       MULADD(at[2], at[21]);       MULADD(at[3], at[20]);       MULADD(at[4], at[19]);       MULADD(at[5], at[18]);       MULADD(at[6], at[17]);       MULADD(at[7], at[16]);       MULADD(at[8], at[15]);       MULADD(at[9], at[14]); 
+      COMBA_STORE(C->dp[9]);
+      /* 10 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[24]);       MULADD(at[1], at[23]);       MULADD(at[2], at[22]);       MULADD(at[3], at[21]);       MULADD(at[4], at[20]);       MULADD(at[5], at[19]);       MULADD(at[6], at[18]);       MULADD(at[7], at[17]);       MULADD(at[8], at[16]);       MULADD(at[9], at[15]);       MULADD(at[10], at[14]); 
+      COMBA_STORE(C->dp[10]);
+      /* 11 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[25]);       MULADD(at[1], at[24]);       MULADD(at[2], at[23]);       MULADD(at[3], at[22]);       MULADD(at[4], at[21]);       MULADD(at[5], at[20]);       MULADD(at[6], at[19]);       MULADD(at[7], at[18]);       MULADD(at[8], at[17]);       MULADD(at[9], at[16]);       MULADD(at[10], at[15]);       MULADD(at[11], at[14]); 
+      COMBA_STORE(C->dp[11]);
+      /* 12 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[26]);       MULADD(at[1], at[25]);       MULADD(at[2], at[24]);       MULADD(at[3], at[23]);       MULADD(at[4], at[22]);       MULADD(at[5], at[21]);       MULADD(at[6], at[20]);       MULADD(at[7], at[19]);       MULADD(at[8], at[18]);       MULADD(at[9], at[17]);       MULADD(at[10], at[16]);       MULADD(at[11], at[15]);       MULADD(at[12], at[14]); 
+      COMBA_STORE(C->dp[12]);
+      /* 13 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[27]);       MULADD(at[1], at[26]);       MULADD(at[2], at[25]);       MULADD(at[3], at[24]);       MULADD(at[4], at[23]);       MULADD(at[5], at[22]);       MULADD(at[6], at[21]);       MULADD(at[7], at[20]);       MULADD(at[8], at[19]);       MULADD(at[9], at[18]);       MULADD(at[10], at[17]);       MULADD(at[11], at[16]);       MULADD(at[12], at[15]);       MULADD(at[13], at[14]); 
+      COMBA_STORE(C->dp[13]);
+      /* 14 */
+      COMBA_FORWARD;
+      MULADD(at[1], at[27]);       MULADD(at[2], at[26]);       MULADD(at[3], at[25]);       MULADD(at[4], at[24]);       MULADD(at[5], at[23]);       MULADD(at[6], at[22]);       MULADD(at[7], at[21]);       MULADD(at[8], at[20]);       MULADD(at[9], at[19]);       MULADD(at[10], at[18]);       MULADD(at[11], at[17]);       MULADD(at[12], at[16]);       MULADD(at[13], at[15]); 
+      COMBA_STORE(C->dp[14]);
+      /* 15 */
+      COMBA_FORWARD;
+      MULADD(at[2], at[27]);       MULADD(at[3], at[26]);       MULADD(at[4], at[25]);       MULADD(at[5], at[24]);       MULADD(at[6], at[23]);       MULADD(at[7], at[22]);       MULADD(at[8], at[21]);       MULADD(at[9], at[20]);       MULADD(at[10], at[19]);       MULADD(at[11], at[18]);       MULADD(at[12], at[17]);       MULADD(at[13], at[16]); 
+      COMBA_STORE(C->dp[15]);
+      /* 16 */
+      COMBA_FORWARD;
+      MULADD(at[3], at[27]);       MULADD(at[4], at[26]);       MULADD(at[5], at[25]);       MULADD(at[6], at[24]);       MULADD(at[7], at[23]);       MULADD(at[8], at[22]);       MULADD(at[9], at[21]);       MULADD(at[10], at[20]);       MULADD(at[11], at[19]);       MULADD(at[12], at[18]);       MULADD(at[13], at[17]); 
+      COMBA_STORE(C->dp[16]);
+      /* 17 */
+      COMBA_FORWARD;
+      MULADD(at[4], at[27]);       MULADD(at[5], at[26]);       MULADD(at[6], at[25]);       MULADD(at[7], at[24]);       MULADD(at[8], at[23]);       MULADD(at[9], at[22]);       MULADD(at[10], at[21]);       MULADD(at[11], at[20]);       MULADD(at[12], at[19]);       MULADD(at[13], at[18]); 
+      COMBA_STORE(C->dp[17]);
+      /* 18 */
+      COMBA_FORWARD;
+      MULADD(at[5], at[27]);       MULADD(at[6], at[26]);       MULADD(at[7], at[25]);       MULADD(at[8], at[24]);       MULADD(at[9], at[23]);       MULADD(at[10], at[22]);       MULADD(at[11], at[21]);       MULADD(at[12], at[20]);       MULADD(at[13], at[19]); 
+      COMBA_STORE(C->dp[18]);
+      /* 19 */
+      COMBA_FORWARD;
+      MULADD(at[6], at[27]);       MULADD(at[7], at[26]);       MULADD(at[8], at[25]);       MULADD(at[9], at[24]);       MULADD(at[10], at[23]);       MULADD(at[11], at[22]);       MULADD(at[12], at[21]);       MULADD(at[13], at[20]); 
+      COMBA_STORE(C->dp[19]);
+      /* 20 */
+      COMBA_FORWARD;
+      MULADD(at[7], at[27]);       MULADD(at[8], at[26]);       MULADD(at[9], at[25]);       MULADD(at[10], at[24]);       MULADD(at[11], at[23]);       MULADD(at[12], at[22]);       MULADD(at[13], at[21]); 
+      COMBA_STORE(C->dp[20]);
+      /* 21 */
+      COMBA_FORWARD;
+      MULADD(at[8], at[27]);       MULADD(at[9], at[26]);       MULADD(at[10], at[25]);       MULADD(at[11], at[24]);       MULADD(at[12], at[23]);       MULADD(at[13], at[22]); 
+      COMBA_STORE(C->dp[21]);
+      /* 22 */
+      COMBA_FORWARD;
+      MULADD(at[9], at[27]);       MULADD(at[10], at[26]);       MULADD(at[11], at[25]);       MULADD(at[12], at[24]);       MULADD(at[13], at[23]); 
+      COMBA_STORE(C->dp[22]);
+      /* 23 */
+      COMBA_FORWARD;
+      MULADD(at[10], at[27]);       MULADD(at[11], at[26]);       MULADD(at[12], at[25]);       MULADD(at[13], at[24]); 
+      COMBA_STORE(C->dp[23]);
+      /* 24 */
+      COMBA_FORWARD;
+      MULADD(at[11], at[27]);       MULADD(at[12], at[26]);       MULADD(at[13], at[25]); 
+      COMBA_STORE(C->dp[24]);
+      /* 25 */
+      COMBA_FORWARD;
+      MULADD(at[12], at[27]);       MULADD(at[13], at[26]); 
+      COMBA_STORE(C->dp[25]);
+      /* 26 */
+      COMBA_FORWARD;
+      MULADD(at[13], at[27]); 
+      COMBA_STORE(C->dp[26]);
+      COMBA_STORE2(C->dp[27]);
+      C->used = 28;
+      C->sign = A->sign ^ B->sign;
+      fp_clamp(C);
+      COMBA_FINI;
+      break;
+
+   case 15:
+      memcpy(at, A->dp, 15 * sizeof(fp_digit));
+      memcpy(at+15, B->dp, 15 * sizeof(fp_digit));
+      COMBA_START;
+
+      COMBA_CLEAR;
+      /* 0 */
+      MULADD(at[0], at[15]); 
+      COMBA_STORE(C->dp[0]);
+      /* 1 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[16]);       MULADD(at[1], at[15]); 
+      COMBA_STORE(C->dp[1]);
+      /* 2 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[17]);       MULADD(at[1], at[16]);       MULADD(at[2], at[15]); 
+      COMBA_STORE(C->dp[2]);
+      /* 3 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[18]);       MULADD(at[1], at[17]);       MULADD(at[2], at[16]);       MULADD(at[3], at[15]); 
+      COMBA_STORE(C->dp[3]);
+      /* 4 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[19]);       MULADD(at[1], at[18]);       MULADD(at[2], at[17]);       MULADD(at[3], at[16]);       MULADD(at[4], at[15]); 
+      COMBA_STORE(C->dp[4]);
+      /* 5 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[20]);       MULADD(at[1], at[19]);       MULADD(at[2], at[18]);       MULADD(at[3], at[17]);       MULADD(at[4], at[16]);       MULADD(at[5], at[15]); 
+      COMBA_STORE(C->dp[5]);
+      /* 6 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[21]);       MULADD(at[1], at[20]);       MULADD(at[2], at[19]);       MULADD(at[3], at[18]);       MULADD(at[4], at[17]);       MULADD(at[5], at[16]);       MULADD(at[6], at[15]); 
+      COMBA_STORE(C->dp[6]);
+      /* 7 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[22]);       MULADD(at[1], at[21]);       MULADD(at[2], at[20]);       MULADD(at[3], at[19]);       MULADD(at[4], at[18]);       MULADD(at[5], at[17]);       MULADD(at[6], at[16]);       MULADD(at[7], at[15]); 
+      COMBA_STORE(C->dp[7]);
+      /* 8 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[23]);       MULADD(at[1], at[22]);       MULADD(at[2], at[21]);       MULADD(at[3], at[20]);       MULADD(at[4], at[19]);       MULADD(at[5], at[18]);       MULADD(at[6], at[17]);       MULADD(at[7], at[16]);       MULADD(at[8], at[15]); 
+      COMBA_STORE(C->dp[8]);
+      /* 9 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[24]);       MULADD(at[1], at[23]);       MULADD(at[2], at[22]);       MULADD(at[3], at[21]);       MULADD(at[4], at[20]);       MULADD(at[5], at[19]);       MULADD(at[6], at[18]);       MULADD(at[7], at[17]);       MULADD(at[8], at[16]);       MULADD(at[9], at[15]); 
+      COMBA_STORE(C->dp[9]);
+      /* 10 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[25]);       MULADD(at[1], at[24]);       MULADD(at[2], at[23]);       MULADD(at[3], at[22]);       MULADD(at[4], at[21]);       MULADD(at[5], at[20]);       MULADD(at[6], at[19]);       MULADD(at[7], at[18]);       MULADD(at[8], at[17]);       MULADD(at[9], at[16]);       MULADD(at[10], at[15]); 
+      COMBA_STORE(C->dp[10]);
+      /* 11 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[26]);       MULADD(at[1], at[25]);       MULADD(at[2], at[24]);       MULADD(at[3], at[23]);       MULADD(at[4], at[22]);       MULADD(at[5], at[21]);       MULADD(at[6], at[20]);       MULADD(at[7], at[19]);       MULADD(at[8], at[18]);       MULADD(at[9], at[17]);       MULADD(at[10], at[16]);       MULADD(at[11], at[15]); 
+      COMBA_STORE(C->dp[11]);
+      /* 12 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[27]);       MULADD(at[1], at[26]);       MULADD(at[2], at[25]);       MULADD(at[3], at[24]);       MULADD(at[4], at[23]);       MULADD(at[5], at[22]);       MULADD(at[6], at[21]);       MULADD(at[7], at[20]);       MULADD(at[8], at[19]);       MULADD(at[9], at[18]);       MULADD(at[10], at[17]);       MULADD(at[11], at[16]);       MULADD(at[12], at[15]); 
+      COMBA_STORE(C->dp[12]);
+      /* 13 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[28]);       MULADD(at[1], at[27]);       MULADD(at[2], at[26]);       MULADD(at[3], at[25]);       MULADD(at[4], at[24]);       MULADD(at[5], at[23]);       MULADD(at[6], at[22]);       MULADD(at[7], at[21]);       MULADD(at[8], at[20]);       MULADD(at[9], at[19]);       MULADD(at[10], at[18]);       MULADD(at[11], at[17]);       MULADD(at[12], at[16]);       MULADD(at[13], at[15]); 
+      COMBA_STORE(C->dp[13]);
+      /* 14 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[29]);       MULADD(at[1], at[28]);       MULADD(at[2], at[27]);       MULADD(at[3], at[26]);       MULADD(at[4], at[25]);       MULADD(at[5], at[24]);       MULADD(at[6], at[23]);       MULADD(at[7], at[22]);       MULADD(at[8], at[21]);       MULADD(at[9], at[20]);       MULADD(at[10], at[19]);       MULADD(at[11], at[18]);       MULADD(at[12], at[17]);       MULADD(at[13], at[16]);       MULADD(at[14], at[15]); 
+      COMBA_STORE(C->dp[14]);
+      /* 15 */
+      COMBA_FORWARD;
+      MULADD(at[1], at[29]);       MULADD(at[2], at[28]);       MULADD(at[3], at[27]);       MULADD(at[4], at[26]);       MULADD(at[5], at[25]);       MULADD(at[6], at[24]);       MULADD(at[7], at[23]);       MULADD(at[8], at[22]);       MULADD(at[9], at[21]);       MULADD(at[10], at[20]);       MULADD(at[11], at[19]);       MULADD(at[12], at[18]);       MULADD(at[13], at[17]);       MULADD(at[14], at[16]); 
+      COMBA_STORE(C->dp[15]);
+      /* 16 */
+      COMBA_FORWARD;
+      MULADD(at[2], at[29]);       MULADD(at[3], at[28]);       MULADD(at[4], at[27]);       MULADD(at[5], at[26]);       MULADD(at[6], at[25]);       MULADD(at[7], at[24]);       MULADD(at[8], at[23]);       MULADD(at[9], at[22]);       MULADD(at[10], at[21]);       MULADD(at[11], at[20]);       MULADD(at[12], at[19]);       MULADD(at[13], at[18]);       MULADD(at[14], at[17]); 
+      COMBA_STORE(C->dp[16]);
+      /* 17 */
+      COMBA_FORWARD;
+      MULADD(at[3], at[29]);       MULADD(at[4], at[28]);       MULADD(at[5], at[27]);       MULADD(at[6], at[26]);       MULADD(at[7], at[25]);       MULADD(at[8], at[24]);       MULADD(at[9], at[23]);       MULADD(at[10], at[22]);       MULADD(at[11], at[21]);       MULADD(at[12], at[20]);       MULADD(at[13], at[19]);       MULADD(at[14], at[18]); 
+      COMBA_STORE(C->dp[17]);
+      /* 18 */
+      COMBA_FORWARD;
+      MULADD(at[4], at[29]);       MULADD(at[5], at[28]);       MULADD(at[6], at[27]);       MULADD(at[7], at[26]);       MULADD(at[8], at[25]);       MULADD(at[9], at[24]);       MULADD(at[10], at[23]);       MULADD(at[11], at[22]);       MULADD(at[12], at[21]);       MULADD(at[13], at[20]);       MULADD(at[14], at[19]); 
+      COMBA_STORE(C->dp[18]);
+      /* 19 */
+      COMBA_FORWARD;
+      MULADD(at[5], at[29]);       MULADD(at[6], at[28]);       MULADD(at[7], at[27]);       MULADD(at[8], at[26]);       MULADD(at[9], at[25]);       MULADD(at[10], at[24]);       MULADD(at[11], at[23]);       MULADD(at[12], at[22]);       MULADD(at[13], at[21]);       MULADD(at[14], at[20]); 
+      COMBA_STORE(C->dp[19]);
+      /* 20 */
+      COMBA_FORWARD;
+      MULADD(at[6], at[29]);       MULADD(at[7], at[28]);       MULADD(at[8], at[27]);       MULADD(at[9], at[26]);       MULADD(at[10], at[25]);       MULADD(at[11], at[24]);       MULADD(at[12], at[23]);       MULADD(at[13], at[22]);       MULADD(at[14], at[21]); 
+      COMBA_STORE(C->dp[20]);
+      /* 21 */
+      COMBA_FORWARD;
+      MULADD(at[7], at[29]);       MULADD(at[8], at[28]);       MULADD(at[9], at[27]);       MULADD(at[10], at[26]);       MULADD(at[11], at[25]);       MULADD(at[12], at[24]);       MULADD(at[13], at[23]);       MULADD(at[14], at[22]); 
+      COMBA_STORE(C->dp[21]);
+      /* 22 */
+      COMBA_FORWARD;
+      MULADD(at[8], at[29]);       MULADD(at[9], at[28]);       MULADD(at[10], at[27]);       MULADD(at[11], at[26]);       MULADD(at[12], at[25]);       MULADD(at[13], at[24]);       MULADD(at[14], at[23]); 
+      COMBA_STORE(C->dp[22]);
+      /* 23 */
+      COMBA_FORWARD;
+      MULADD(at[9], at[29]);       MULADD(at[10], at[28]);       MULADD(at[11], at[27]);       MULADD(at[12], at[26]);       MULADD(at[13], at[25]);       MULADD(at[14], at[24]); 
+      COMBA_STORE(C->dp[23]);
+      /* 24 */
+      COMBA_FORWARD;
+      MULADD(at[10], at[29]);       MULADD(at[11], at[28]);       MULADD(at[12], at[27]);       MULADD(at[13], at[26]);       MULADD(at[14], at[25]); 
+      COMBA_STORE(C->dp[24]);
+      /* 25 */
+      COMBA_FORWARD;
+      MULADD(at[11], at[29]);       MULADD(at[12], at[28]);       MULADD(at[13], at[27]);       MULADD(at[14], at[26]); 
+      COMBA_STORE(C->dp[25]);
+      /* 26 */
+      COMBA_FORWARD;
+      MULADD(at[12], at[29]);       MULADD(at[13], at[28]);       MULADD(at[14], at[27]); 
+      COMBA_STORE(C->dp[26]);
+      /* 27 */
+      COMBA_FORWARD;
+      MULADD(at[13], at[29]);       MULADD(at[14], at[28]); 
+      COMBA_STORE(C->dp[27]);
+      /* 28 */
+      COMBA_FORWARD;
+      MULADD(at[14], at[29]); 
+      COMBA_STORE(C->dp[28]);
+      COMBA_STORE2(C->dp[29]);
+      C->used = 30;
+      C->sign = A->sign ^ B->sign;
+      fp_clamp(C);
+      COMBA_FINI;
+      break;
+
+   case 16:
+      memcpy(at, A->dp, 16 * sizeof(fp_digit));
+      memcpy(at+16, B->dp, 16 * sizeof(fp_digit));
+      COMBA_START;
+
+      COMBA_CLEAR;
+      /* 0 */
+      MULADD(at[0], at[16]); 
+      COMBA_STORE(C->dp[0]);
+      /* 1 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[17]);       MULADD(at[1], at[16]); 
+      COMBA_STORE(C->dp[1]);
+      /* 2 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[18]);       MULADD(at[1], at[17]);       MULADD(at[2], at[16]); 
+      COMBA_STORE(C->dp[2]);
+      /* 3 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[19]);       MULADD(at[1], at[18]);       MULADD(at[2], at[17]);       MULADD(at[3], at[16]); 
+      COMBA_STORE(C->dp[3]);
+      /* 4 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[20]);       MULADD(at[1], at[19]);       MULADD(at[2], at[18]);       MULADD(at[3], at[17]);       MULADD(at[4], at[16]); 
+      COMBA_STORE(C->dp[4]);
+      /* 5 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[21]);       MULADD(at[1], at[20]);       MULADD(at[2], at[19]);       MULADD(at[3], at[18]);       MULADD(at[4], at[17]);       MULADD(at[5], at[16]); 
+      COMBA_STORE(C->dp[5]);
+      /* 6 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[22]);       MULADD(at[1], at[21]);       MULADD(at[2], at[20]);       MULADD(at[3], at[19]);       MULADD(at[4], at[18]);       MULADD(at[5], at[17]);       MULADD(at[6], at[16]); 
+      COMBA_STORE(C->dp[6]);
+      /* 7 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[23]);       MULADD(at[1], at[22]);       MULADD(at[2], at[21]);       MULADD(at[3], at[20]);       MULADD(at[4], at[19]);       MULADD(at[5], at[18]);       MULADD(at[6], at[17]);       MULADD(at[7], at[16]); 
+      COMBA_STORE(C->dp[7]);
+      /* 8 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[24]);       MULADD(at[1], at[23]);       MULADD(at[2], at[22]);       MULADD(at[3], at[21]);       MULADD(at[4], at[20]);       MULADD(at[5], at[19]);       MULADD(at[6], at[18]);       MULADD(at[7], at[17]);       MULADD(at[8], at[16]); 
+      COMBA_STORE(C->dp[8]);
+      /* 9 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[25]);       MULADD(at[1], at[24]);       MULADD(at[2], at[23]);       MULADD(at[3], at[22]);       MULADD(at[4], at[21]);       MULADD(at[5], at[20]);       MULADD(at[6], at[19]);       MULADD(at[7], at[18]);       MULADD(at[8], at[17]);       MULADD(at[9], at[16]); 
+      COMBA_STORE(C->dp[9]);
+      /* 10 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[26]);       MULADD(at[1], at[25]);       MULADD(at[2], at[24]);       MULADD(at[3], at[23]);       MULADD(at[4], at[22]);       MULADD(at[5], at[21]);       MULADD(at[6], at[20]);       MULADD(at[7], at[19]);       MULADD(at[8], at[18]);       MULADD(at[9], at[17]);       MULADD(at[10], at[16]); 
+      COMBA_STORE(C->dp[10]);
+      /* 11 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[27]);       MULADD(at[1], at[26]);       MULADD(at[2], at[25]);       MULADD(at[3], at[24]);       MULADD(at[4], at[23]);       MULADD(at[5], at[22]);       MULADD(at[6], at[21]);       MULADD(at[7], at[20]);       MULADD(at[8], at[19]);       MULADD(at[9], at[18]);       MULADD(at[10], at[17]);       MULADD(at[11], at[16]); 
+      COMBA_STORE(C->dp[11]);
+      /* 12 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[28]);       MULADD(at[1], at[27]);       MULADD(at[2], at[26]);       MULADD(at[3], at[25]);       MULADD(at[4], at[24]);       MULADD(at[5], at[23]);       MULADD(at[6], at[22]);       MULADD(at[7], at[21]);       MULADD(at[8], at[20]);       MULADD(at[9], at[19]);       MULADD(at[10], at[18]);       MULADD(at[11], at[17]);       MULADD(at[12], at[16]); 
+      COMBA_STORE(C->dp[12]);
+      /* 13 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[29]);       MULADD(at[1], at[28]);       MULADD(at[2], at[27]);       MULADD(at[3], at[26]);       MULADD(at[4], at[25]);       MULADD(at[5], at[24]);       MULADD(at[6], at[23]);       MULADD(at[7], at[22]);       MULADD(at[8], at[21]);       MULADD(at[9], at[20]);       MULADD(at[10], at[19]);       MULADD(at[11], at[18]);       MULADD(at[12], at[17]);       MULADD(at[13], at[16]); 
+      COMBA_STORE(C->dp[13]);
+      /* 14 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[30]);       MULADD(at[1], at[29]);       MULADD(at[2], at[28]);       MULADD(at[3], at[27]);       MULADD(at[4], at[26]);       MULADD(at[5], at[25]);       MULADD(at[6], at[24]);       MULADD(at[7], at[23]);       MULADD(at[8], at[22]);       MULADD(at[9], at[21]);       MULADD(at[10], at[20]);       MULADD(at[11], at[19]);       MULADD(at[12], at[18]);       MULADD(at[13], at[17]);       MULADD(at[14], at[16]); 
+      COMBA_STORE(C->dp[14]);
+      /* 15 */
+      COMBA_FORWARD;
+      MULADD(at[0], at[31]);       MULADD(at[1], at[30]);       MULADD(at[2], at[29]);       MULADD(at[3], at[28]);       MULADD(at[4], at[27]);       MULADD(at[5], at[26]);       MULADD(at[6], at[25]);       MULADD(at[7], at[24]);       MULADD(at[8], at[23]);       MULADD(at[9], at[22]);       MULADD(at[10], at[21]);       MULADD(at[11], at[20]);       MULADD(at[12], at[19]);       MULADD(at[13], at[18]);       MULADD(at[14], at[17]);       MULADD(at[15], at[16]); 
+      COMBA_STORE(C->dp[15]);
+      /* 16 */
+      COMBA_FORWARD;
+      MULADD(at[1], at[31]);       MULADD(at[2], at[30]);       MULADD(at[3], at[29]);       MULADD(at[4], at[28]);       MULADD(at[5], at[27]);       MULADD(at[6], at[26]);       MULADD(at[7], at[25]);       MULADD(at[8], at[24]);       MULADD(at[9], at[23]);       MULADD(at[10], at[22]);       MULADD(at[11], at[21]);       MULADD(at[12], at[20]);       MULADD(at[13], at[19]);       MULADD(at[14], at[18]);       MULADD(at[15], at[17]); 
+      COMBA_STORE(C->dp[16]);
+      /* 17 */
+      COMBA_FORWARD;
+      MULADD(at[2], at[31]);       MULADD(at[3], at[30]);       MULADD(at[4], at[29]);       MULADD(at[5], at[28]);       MULADD(at[6], at[27]);       MULADD(at[7], at[26]);       MULADD(at[8], at[25]);       MULADD(at[9], at[24]);       MULADD(at[10], at[23]);       MULADD(at[11], at[22]);       MULADD(at[12], at[21]);       MULADD(at[13], at[20]);       MULADD(at[14], at[19]);       MULADD(at[15], at[18]); 
+      COMBA_STORE(C->dp[17]);
+      /* 18 */
+      COMBA_FORWARD;
+      MULADD(at[3], at[31]);       MULADD(at[4], at[30]);       MULADD(at[5], at[29]);       MULADD(at[6], at[28]);       MULADD(at[7], at[27]);       MULADD(at[8], at[26]);       MULADD(at[9], at[25]);       MULADD(at[10], at[24]);       MULADD(at[11], at[23]);       MULADD(at[12], at[22]);       MULADD(at[13], at[21]);       MULADD(at[14], at[20]);       MULADD(at[15], at[19]); 
+      COMBA_STORE(C->dp[18]);
+      /* 19 */
+      COMBA_FORWARD;
+      MULADD(at[4], at[31]);       MULADD(at[5], at[30]);       MULADD(at[6], at[29]);       MULADD(at[7], at[28]);       MULADD(at[8], at[27]);       MULADD(at[9], at[26]);       MULADD(at[10], at[25]);       MULADD(at[11], at[24]);       MULADD(at[12], at[23]);       MULADD(at[13], at[22]);       MULADD(at[14], at[21]);       MULADD(at[15], at[20]); 
+      COMBA_STORE(C->dp[19]);
+      /* 20 */
+      COMBA_FORWARD;
+      MULADD(at[5], at[31]);       MULADD(at[6], at[30]);       MULADD(at[7], at[29]);       MULADD(at[8], at[28]);       MULADD(at[9], at[27]);       MULADD(at[10], at[26]);       MULADD(at[11], at[25]);       MULADD(at[12], at[24]);       MULADD(at[13], at[23]);       MULADD(at[14], at[22]);       MULADD(at[15], at[21]); 
+      COMBA_STORE(C->dp[20]);
+      /* 21 */
+      COMBA_FORWARD;
+      MULADD(at[6], at[31]);       MULADD(at[7], at[30]);       MULADD(at[8], at[29]);       MULADD(at[9], at[28]);       MULADD(at[10], at[27]);       MULADD(at[11], at[26]);       MULADD(at[12], at[25]);       MULADD(at[13], at[24]);       MULADD(at[14], at[23]);       MULADD(at[15], at[22]); 
+      COMBA_STORE(C->dp[21]);
+      /* 22 */
+      COMBA_FORWARD;
+      MULADD(at[7], at[31]);       MULADD(at[8], at[30]);       MULADD(at[9], at[29]);       MULADD(at[10], at[28]);       MULADD(at[11], at[27]);       MULADD(at[12], at[26]);       MULADD(at[13], at[25]);       MULADD(at[14], at[24]);       MULADD(at[15], at[23]); 
+      COMBA_STORE(C->dp[22]);
+      /* 23 */
+      COMBA_FORWARD;
+      MULADD(at[8], at[31]);       MULADD(at[9], at[30]);       MULADD(at[10], at[29]);       MULADD(at[11], at[28]);       MULADD(at[12], at[27]);       MULADD(at[13], at[26]);       MULADD(at[14], at[25]);       MULADD(at[15], at[24]); 
+      COMBA_STORE(C->dp[23]);
+      /* 24 */
+      COMBA_FORWARD;
+      MULADD(at[9], at[31]);       MULADD(at[10], at[30]);       MULADD(at[11], at[29]);       MULADD(at[12], at[28]);       MULADD(at[13], at[27]);       MULADD(at[14], at[26]);       MULADD(at[15], at[25]); 
+      COMBA_STORE(C->dp[24]);
+      /* 25 */
+      COMBA_FORWARD;
+      MULADD(at[10], at[31]);       MULADD(at[11], at[30]);       MULADD(at[12], at[29]);       MULADD(at[13], at[28]);       MULADD(at[14], at[27]);       MULADD(at[15], at[26]); 
+      COMBA_STORE(C->dp[25]);
+      /* 26 */
+      COMBA_FORWARD;
+      MULADD(at[11], at[31]);       MULADD(at[12], at[30]);       MULADD(at[13], at[29]);       MULADD(at[14], at[28]);       MULADD(at[15], at[27]); 
+      COMBA_STORE(C->dp[26]);
+      /* 27 */
+      COMBA_FORWARD;
+      MULADD(at[12], at[31]);       MULADD(at[13], at[30]);       MULADD(at[14], at[29]);       MULADD(at[15], at[28]); 
+      COMBA_STORE(C->dp[27]);
+      /* 28 */
+      COMBA_FORWARD;
+      MULADD(at[13], at[31]);       MULADD(at[14], at[30]);       MULADD(at[15], at[29]); 
+      COMBA_STORE(C->dp[28]);
+      /* 29 */
+      COMBA_FORWARD;
+      MULADD(at[14], at[31]);       MULADD(at[15], at[30]); 
+      COMBA_STORE(C->dp[29]);
+      /* 30 */
+      COMBA_FORWARD;
+      MULADD(at[15], at[31]); 
+      COMBA_STORE(C->dp[30]);
+      COMBA_STORE2(C->dp[31]);
+      C->used = 32;
+      C->sign = A->sign ^ B->sign;
+      fp_clamp(C);
+      COMBA_FINI;
+      break;
+   }
+}
+
+#endif
+
+
+/* $Source$ */
+/* $Revision$ */
+/* $Date$ */
diff --git a/tomsfastmath/src/mul/fp_mul_d.c b/tomsfastmath/src/mul/fp_mul_d.c
new file mode 100644 (file)
index 0000000..27dbc0d
--- /dev/null
@@ -0,0 +1,40 @@
+/* TomsFastMath, a fast ISO C bignum library.
+ * 
+ * This project is meant to fill in where LibTomMath
+ * falls short.  That is speed ;-)
+ *
+ * This project is public domain and free for all purposes.
+ * 
+ * Tom St Denis, tomstdenis@gmail.com
+ */
+#include <tfm_private.h>
+
+/* c = a * b */
+void fp_mul_d(fp_int *a, fp_digit b, fp_int *c)
+{
+   fp_word  w;
+   int      x, oldused;
+
+   oldused = c->used;
+   c->used = a->used;
+   c->sign = a->sign;
+   w       = 0;
+   for (x = 0; x < a->used; x++) {
+       w         = ((fp_word)a->dp[x]) * ((fp_word)b) + w;
+       c->dp[x]  = (fp_digit)w;
+       w         = w >> DIGIT_BIT;
+   }
+   if (w != 0 && (a->used != FP_SIZE)) {
+      c->dp[c->used++] = w;
+      ++x;
+   }
+   for (; x < oldused; x++) {
+      c->dp[x] = 0;
+   }
+   fp_clamp(c);
+}
+
+
+/* $Source$ */
+/* $Revision$ */
+/* $Date$ */
diff --git a/tomsfastmath/src/mul/fp_mulmod.c b/tomsfastmath/src/mul/fp_mulmod.c
new file mode 100644 (file)
index 0000000..3c0069c
--- /dev/null
@@ -0,0 +1,22 @@
+/* TomsFastMath, a fast ISO C bignum library.
+ * 
+ * This project is meant to fill in where LibTomMath
+ * falls short.  That is speed ;-)
+ *
+ * This project is public domain and free for all purposes.
+ * 
+ * Tom St Denis, tomstdenis@gmail.com
+ */
+#include <tfm_private.h>
+/* d = a * b (mod c) */
+int fp_mulmod(fp_int *a, fp_int *b, fp_int *c, fp_int *d)
+{
+  fp_int tmp;
+  fp_zero(&tmp);
+  fp_mul(a, b, &tmp);
+  return fp_mod(&tmp, c, d);
+}
+
+/* $Source$ */
+/* $Revision$ */
+/* $Date$ */
diff --git a/tomsfastmath/src/numtheory/fp_gcd.c b/tomsfastmath/src/numtheory/fp_gcd.c
new file mode 100644 (file)
index 0000000..3aa6387
--- /dev/null
@@ -0,0 +1,55 @@
+/* TomsFastMath, a fast ISO C bignum library.
+ * 
+ * This project is meant to fill in where LibTomMath
+ * falls short.  That is speed ;-)
+ *
+ * This project is public domain and free for all purposes.
+ * 
+ * Tom St Denis, tomstdenis@gmail.com
+ */
+#include <tfm_private.h>
+
+/* c = (a, b) */
+void fp_gcd(fp_int *a, fp_int *b, fp_int *c)
+{
+   fp_int u, v, r;
+
+   /* either zero than gcd is the largest */
+   if (fp_iszero (a) == 1 && fp_iszero (b) == 0) {
+     fp_abs (b, c);
+     return;
+   }
+   if (fp_iszero (a) == 0 && fp_iszero (b) == 1) {
+     fp_abs (a, c);
+     return;
+   }
+
+   /* optimized.  At this point if a == 0 then
+    * b must equal zero too
+    */
+   if (fp_iszero (a) == 1) {
+     fp_zero(c);
+     return;
+   }
+
+   /* sort inputs */
+   if (fp_cmp_mag(a, b) != FP_LT) {
+      fp_init_copy(&u, a);
+      fp_init_copy(&v, b);
+   } else {
+      fp_init_copy(&u, b);
+      fp_init_copy(&v, a);
+   }
+   fp_zero(&r);
+   while (fp_iszero(&v) == FP_NO) {
+      fp_mod(&u, &v, &r);
+      fp_copy(&v, &u);
+      fp_copy(&r, &v);
+   }
+   fp_copy(&u, c);
+}
+
+/* $Source$ */
+/* $Revision$ */
+/* $Date$ */
diff --git a/tomsfastmath/src/numtheory/fp_invmod.c b/tomsfastmath/src/numtheory/fp_invmod.c
new file mode 100644 (file)
index 0000000..9a2329e
--- /dev/null
@@ -0,0 +1,207 @@
+/* TomsFastMath, a fast ISO C bignum library.
+ * 
+ * This project is meant to fill in where LibTomMath
+ * falls short.  That is speed ;-)
+ *
+ * This project is public domain and free for all purposes.
+ * 
+ * Tom St Denis, tomstdenis@gmail.com
+ */
+#include <tfm_private.h>
+
+static int fp_invmod_slow (fp_int * a, fp_int * b, fp_int * c)
+{
+  fp_int  x, y, u, v, A, B, C, D;
+  int     res;
+
+  /* b cannot be negative */
+  if (b->sign == FP_NEG || fp_iszero(b) == 1) {
+    return FP_VAL;
+  }
+
+  /* init temps */
+  fp_init(&x);    fp_init(&y);
+  fp_init(&u);    fp_init(&v);
+  fp_init(&A);    fp_init(&B);
+  fp_init(&C);    fp_init(&D);
+
+  /* x = a, y = b */
+  if ((res = fp_mod(a, b, &x)) != FP_OKAY) {
+      return res;
+  }
+  fp_copy(b, &y);
+
+  /* 2. [modified] if x,y are both even then return an error! */
+  if (fp_iseven (&x) == 1 && fp_iseven (&y) == 1) {
+    return FP_VAL;
+  }
+
+  /* 3. u=x, v=y, A=1, B=0, C=0,D=1 */
+  fp_copy (&x, &u);
+  fp_copy (&y, &v);
+  fp_set (&A, 1);
+  fp_set (&D, 1);
+
+top:
+  /* 4.  while u is even do */
+  while (fp_iseven (&u) == 1) {
+    /* 4.1 u = u/2 */
+    fp_div_2 (&u, &u);
+
+    /* 4.2 if A or B is odd then */
+    if (fp_isodd (&A) == 1 || fp_isodd (&B) == 1) {
+      /* A = (A+y)/2, B = (B-x)/2 */
+      fp_add (&A, &y, &A);
+      fp_sub (&B, &x, &B);
+    }
+    /* A = A/2, B = B/2 */
+    fp_div_2 (&A, &A);
+    fp_div_2 (&B, &B);
+  }
+
+  /* 5.  while v is even do */
+  while (fp_iseven (&v) == 1) {
+    /* 5.1 v = v/2 */
+    fp_div_2 (&v, &v);
+
+    /* 5.2 if C or D is odd then */
+    if (fp_isodd (&C) == 1 || fp_isodd (&D) == 1) {
+      /* C = (C+y)/2, D = (D-x)/2 */
+      fp_add (&C, &y, &C);
+      fp_sub (&D, &x, &D);
+    }
+    /* C = C/2, D = D/2 */
+    fp_div_2 (&C, &C);
+    fp_div_2 (&D, &D);
+  }
+
+  /* 6.  if u >= v then */
+  if (fp_cmp (&u, &v) != FP_LT) {
+    /* u = u - v, A = A - C, B = B - D */
+    fp_sub (&u, &v, &u);
+    fp_sub (&A, &C, &A);
+    fp_sub (&B, &D, &B);
+  } else {
+    /* v - v - u, C = C - A, D = D - B */
+    fp_sub (&v, &u, &v);
+    fp_sub (&C, &A, &C);
+    fp_sub (&D, &B, &D);
+  }
+
+  /* if not zero goto step 4 */
+  if (fp_iszero (&u) == 0)
+    goto top;
+
+  /* now a = C, b = D, gcd == g*v */
+
+  /* if v != 1 then there is no inverse */
+  if (fp_cmp_d (&v, 1) != FP_EQ) {
+    return FP_VAL;
+  }
+
+  /* if its too low */
+  while (fp_cmp_d(&C, 0) == FP_LT) {
+      fp_add(&C, b, &C);
+  }
+  
+  /* too big */
+  while (fp_cmp_mag(&C, b) != FP_LT) {
+      fp_sub(&C, b, &C);
+  }
+  
+  /* C is now the inverse */
+  fp_copy(&C, c);
+  return FP_OKAY;
+}
+
+/* c = 1/a (mod b) for odd b only */
+int fp_invmod(fp_int *a, fp_int *b, fp_int *c)
+{
+  fp_int  x, y, u, v, B, D;
+  int     neg;
+
+  /* 2. [modified] b must be odd   */
+  if (fp_iseven (b) == FP_YES) {
+    return fp_invmod_slow(a,b,c);
+  }
+
+  /* init all our temps */
+  fp_init(&x);  fp_init(&y);
+  fp_init(&u);  fp_init(&v);
+  fp_init(&B);  fp_init(&D);
+
+  /* x == modulus, y == value to invert */
+  fp_copy(b, &x);
+
+  /* we need y = |a| */
+  fp_abs(a, &y);
+
+  /* 3. u=x, v=y, A=1, B=0, C=0,D=1 */
+  fp_copy(&x, &u);
+  fp_copy(&y, &v);
+  fp_set (&D, 1);
+
+top:
+  /* 4.  while u is even do */
+  while (fp_iseven (&u) == FP_YES) {
+    /* 4.1 u = u/2 */
+    fp_div_2 (&u, &u);
+
+    /* 4.2 if B is odd then */
+    if (fp_isodd (&B) == FP_YES) {
+      fp_sub (&B, &x, &B);
+    }
+    /* B = B/2 */
+    fp_div_2 (&B, &B);
+  }
+
+  /* 5.  while v is even do */
+  while (fp_iseven (&v) == FP_YES) {
+    /* 5.1 v = v/2 */
+    fp_div_2 (&v, &v);
+
+    /* 5.2 if D is odd then */
+    if (fp_isodd (&D) == FP_YES) {
+      /* D = (D-x)/2 */
+      fp_sub (&D, &x, &D);
+    }
+    /* D = D/2 */
+    fp_div_2 (&D, &D);
+  }
+
+  /* 6.  if u >= v then */
+  if (fp_cmp (&u, &v) != FP_LT) {
+    /* u = u - v, B = B - D */
+    fp_sub (&u, &v, &u);
+    fp_sub (&B, &D, &B);
+  } else {
+    /* v - v - u, D = D - B */
+    fp_sub (&v, &u, &v);
+    fp_sub (&D, &B, &D);
+  }
+
+  /* if not zero goto step 4 */
+  if (fp_iszero (&u) == FP_NO) {
+    goto top;
+  }
+
+  /* now a = C, b = D, gcd == g*v */
+
+  /* if v != 1 then there is no inverse */
+  if (fp_cmp_d (&v, 1) != FP_EQ) {
+    return FP_VAL;
+  }
+
+  /* b is now the inverse */
+  neg = a->sign;
+  while (D.sign == FP_NEG) {
+    fp_add (&D, b, &D);
+  }
+  fp_copy (&D, c);
+  c->sign = neg;
+  return FP_OKAY;
+}
+
+/* $Source$ */
+/* $Revision$ */
+/* $Date$ */
diff --git a/tomsfastmath/src/numtheory/fp_isprime.c b/tomsfastmath/src/numtheory/fp_isprime.c
new file mode 100644 (file)
index 0000000..8d73fb7
--- /dev/null
@@ -0,0 +1,19 @@
+/* TomsFastMath, a fast ISO C bignum library.
+ *
+ * This project is meant to fill in where LibTomMath
+ * falls short.  That is speed ;-)
+ *
+ * This project is public domain and free for all purposes.
+ *
+ * Tom St Denis, tomstdenis@gmail.com
+ */
+#include <tfm_private.h>
+
+int fp_isprime(fp_int *a)
+{
+  return fp_isprime_ex(a, 8);
+}
+
+/* $Source$ */
+/* $Revision$ */
+/* $Date$ */
diff --git a/tomsfastmath/src/numtheory/fp_isprime_ex.c b/tomsfastmath/src/numtheory/fp_isprime_ex.c
new file mode 100644 (file)
index 0000000..1c08a6d
--- /dev/null
@@ -0,0 +1,83 @@
+/* TomsFastMath, a fast ISO C bignum library.
+ *
+ * This project is meant to fill in where LibTomMath
+ * falls short.  That is speed ;-)
+ *
+ * This project is public domain and free for all purposes.
+ *
+ * Tom St Denis, tomstdenis@gmail.com
+ */
+#include <tfm_private.h>
+
+/* a few primes */
+static const fp_digit primes[FP_PRIME_SIZE] = {
+  0x0002, 0x0003, 0x0005, 0x0007, 0x000B, 0x000D, 0x0011, 0x0013,
+  0x0017, 0x001D, 0x001F, 0x0025, 0x0029, 0x002B, 0x002F, 0x0035,
+  0x003B, 0x003D, 0x0043, 0x0047, 0x0049, 0x004F, 0x0053, 0x0059,
+  0x0061, 0x0065, 0x0067, 0x006B, 0x006D, 0x0071, 0x007F, 0x0083,
+  0x0089, 0x008B, 0x0095, 0x0097, 0x009D, 0x00A3, 0x00A7, 0x00AD,
+  0x00B3, 0x00B5, 0x00BF, 0x00C1, 0x00C5, 0x00C7, 0x00D3, 0x00DF,
+  0x00E3, 0x00E5, 0x00E9, 0x00EF, 0x00F1, 0x00FB, 0x0101, 0x0107,
+  0x010D, 0x010F, 0x0115, 0x0119, 0x011B, 0x0125, 0x0133, 0x0137,
+
+  0x0139, 0x013D, 0x014B, 0x0151, 0x015B, 0x015D, 0x0161, 0x0167,
+  0x016F, 0x0175, 0x017B, 0x017F, 0x0185, 0x018D, 0x0191, 0x0199,
+  0x01A3, 0x01A5, 0x01AF, 0x01B1, 0x01B7, 0x01BB, 0x01C1, 0x01C9,
+  0x01CD, 0x01CF, 0x01D3, 0x01DF, 0x01E7, 0x01EB, 0x01F3, 0x01F7,
+  0x01FD, 0x0209, 0x020B, 0x021D, 0x0223, 0x022D, 0x0233, 0x0239,
+  0x023B, 0x0241, 0x024B, 0x0251, 0x0257, 0x0259, 0x025F, 0x0265,
+  0x0269, 0x026B, 0x0277, 0x0281, 0x0283, 0x0287, 0x028D, 0x0293,
+  0x0295, 0x02A1, 0x02A5, 0x02AB, 0x02B3, 0x02BD, 0x02C5, 0x02CF,
+
+  0x02D7, 0x02DD, 0x02E3, 0x02E7, 0x02EF, 0x02F5, 0x02F9, 0x0301,
+  0x0305, 0x0313, 0x031D, 0x0329, 0x032B, 0x0335, 0x0337, 0x033B,
+  0x033D, 0x0347, 0x0355, 0x0359, 0x035B, 0x035F, 0x036D, 0x0371,
+  0x0373, 0x0377, 0x038B, 0x038F, 0x0397, 0x03A1, 0x03A9, 0x03AD,
+  0x03B3, 0x03B9, 0x03C7, 0x03CB, 0x03D1, 0x03D7, 0x03DF, 0x03E5,
+  0x03F1, 0x03F5, 0x03FB, 0x03FD, 0x0407, 0x0409, 0x040F, 0x0419,
+  0x041B, 0x0425, 0x0427, 0x042D, 0x043F, 0x0443, 0x0445, 0x0449,
+  0x044F, 0x0455, 0x045D, 0x0463, 0x0469, 0x047F, 0x0481, 0x048B,
+
+  0x0493, 0x049D, 0x04A3, 0x04A9, 0x04B1, 0x04BD, 0x04C1, 0x04C7,
+  0x04CD, 0x04CF, 0x04D5, 0x04E1, 0x04EB, 0x04FD, 0x04FF, 0x0503,
+  0x0509, 0x050B, 0x0511, 0x0515, 0x0517, 0x051B, 0x0527, 0x0529,
+  0x052F, 0x0551, 0x0557, 0x055D, 0x0565, 0x0577, 0x0581, 0x058F,
+  0x0593, 0x0595, 0x0599, 0x059F, 0x05A7, 0x05AB, 0x05AD, 0x05B3,
+  0x05BF, 0x05C9, 0x05CB, 0x05CF, 0x05D1, 0x05D5, 0x05DB, 0x05E7,
+  0x05F3, 0x05FB, 0x0607, 0x060D, 0x0611, 0x0617, 0x061F, 0x0623,
+  0x062B, 0x062F, 0x063D, 0x0641, 0x0647, 0x0649, 0x064D, 0x0653
+};
+
+int fp_isprime_ex(fp_int *a, int t)
+{
+   fp_int   b;
+   fp_digit d;
+   int      r, res;
+
+   if (t <= 0 || t > FP_PRIME_SIZE) {
+     return FP_NO;
+   }
+
+   /* do trial division */
+   for (r = 0; r < 256; r++) {
+       fp_mod_d(a, primes[r], &d);
+       if (d == 0) {
+          return FP_NO;
+       }
+   }
+
+   /* now do 't' miller rabins */
+   fp_init(&b);
+   for (r = 0; r < t; r++) {
+       fp_set(&b, primes[r]);
+       fp_prime_miller_rabin(a, &b, &res);
+       if (res == FP_NO) {
+          return FP_NO;
+       }
+   }
+   return FP_YES;
+}
+
+/* $Source$ */
+/* $Revision$ */
+/* $Date$ */
diff --git a/tomsfastmath/src/numtheory/fp_lcm.c b/tomsfastmath/src/numtheory/fp_lcm.c
new file mode 100644 (file)
index 0000000..19d9ea1
--- /dev/null
@@ -0,0 +1,31 @@
+/* TomsFastMath, a fast ISO C bignum library.
+ * 
+ * This project is meant to fill in where LibTomMath
+ * falls short.  That is speed ;-)
+ *
+ * This project is public domain and free for all purposes.
+ * 
+ * Tom St Denis, tomstdenis@gmail.com
+ */
+#include <tfm_private.h>
+
+/* c = [a, b] */
+void fp_lcm(fp_int *a, fp_int *b, fp_int *c)
+{
+   fp_int  t1, t2;
+
+   fp_init(&t1);
+   fp_init(&t2);
+   fp_gcd(a, b, &t1);
+   if (fp_cmp_mag(a, b) == FP_GT) {
+      fp_div(a, &t1, &t2, NULL);
+      fp_mul(b, &t2, c);
+   } else {
+      fp_div(b, &t1, &t2, NULL);
+      fp_mul(a, &t2, c);
+   }   
+}
+
+/* $Source$ */
+/* $Revision$ */
+/* $Date$ */
diff --git a/tomsfastmath/src/numtheory/fp_prime_miller_rabin.c b/tomsfastmath/src/numtheory/fp_prime_miller_rabin.c
new file mode 100644 (file)
index 0000000..5d3302c
--- /dev/null
@@ -0,0 +1,77 @@
+/* TomsFastMath, a fast ISO C bignum library.
+ * 
+ * This project is meant to fill in where LibTomMath
+ * falls short.  That is speed ;-)
+ *
+ * This project is public domain and free for all purposes.
+ * 
+ * Tom St Denis, tomstdenis@gmail.com
+ */
+#include <tfm_private.h>
+
+/* Miller-Rabin test of "a" to the base of "b" as described in 
+ * HAC pp. 139 Algorithm 4.24
+ *
+ * Sets result to 0 if definitely composite or 1 if probably prime.
+ * Randomly the chance of error is no more than 1/4 and often 
+ * very much lower.
+ */
+void fp_prime_miller_rabin (fp_int * a, fp_int * b, int *result)
+{
+  fp_int  n1, y, r;
+  int     s, j;
+
+  /* default */
+  *result = FP_NO;
+
+  /* ensure b > 1 */
+  if (fp_cmp_d(b, 1) != FP_GT) {
+     return;
+  }     
+
+  /* get n1 = a - 1 */
+  fp_init_copy(&n1, a);
+  fp_sub_d(&n1, 1, &n1);
+
+  /* set 2**s * r = n1 */
+  fp_init_copy(&r, &n1);
+
+  /* count the number of least significant bits
+   * which are zero
+   */
+  s = fp_cnt_lsb(&r);
+
+  /* now divide n - 1 by 2**s */
+  fp_div_2d (&r, s, &r, NULL);
+
+  /* compute y = b**r mod a */
+  fp_init(&y);
+  fp_exptmod(b, &r, a, &y);
+
+  /* if y != 1 and y != n1 do */
+  if (fp_cmp_d (&y, 1) != FP_EQ && fp_cmp (&y, &n1) != FP_EQ) {
+    j = 1;
+    /* while j <= s-1 and y != n1 */
+    while ((j <= (s - 1)) && fp_cmp (&y, &n1) != FP_EQ) {
+      fp_sqrmod (&y, a, &y);
+
+      /* if y == 1 then composite */
+      if (fp_cmp_d (&y, 1) == FP_EQ) {
+         return;
+      }
+      ++j;
+    }
+
+    /* if y != n1 then composite */
+    if (fp_cmp (&y, &n1) != FP_EQ) {
+       return;
+    }
+  }
+
+  /* probably prime now */
+  *result = FP_YES;
+}
+
+/* $Source$ */
+/* $Revision$ */
+/* $Date$ */
diff --git a/tomsfastmath/src/numtheory/fp_prime_random_ex.c b/tomsfastmath/src/numtheory/fp_prime_random_ex.c
new file mode 100644 (file)
index 0000000..52b90e2
--- /dev/null
@@ -0,0 +1,101 @@
+/* TomsFastMath, a fast ISO C bignum library.
+ *
+ * This project is meant to fill in where LibTomMath
+ * falls short.  That is speed ;-)
+ *
+ * This project is public domain and free for all purposes.
+ *
+ * Tom St Denis, tomstdenis@gmail.com
+ */
+#include <tfm_private.h>
+
+/* This is possibly the mother of all prime generation functions, muahahahahaha! */
+int fp_prime_random_ex(fp_int *a, int t, int size, int flags, tfm_prime_callback cb, void *dat)
+{
+   unsigned char *tmp, maskAND, maskOR_msb, maskOR_lsb;
+   int res, err, bsize, maskOR_msb_offset;
+
+   /* sanity check the input */
+   if (size <= 1 || cb == NULL || t <= 0 || t > FP_PRIME_SIZE) {
+      return FP_VAL;
+   }
+
+   /* TFM_PRIME_SAFE implies TFM_PRIME_BBS */
+   if (flags & TFM_PRIME_SAFE) {
+      flags |= TFM_PRIME_BBS;
+   }
+
+   /* calc the byte size */
+   bsize = (size>>3)+(size&7?1:0);
+
+   /* we need a buffer of bsize bytes */
+   tmp = malloc(bsize);
+   if (tmp == NULL) {
+      return FP_MEM;
+   }
+
+   /* calc the maskAND value for the MSbyte*/
+   maskAND = 0xFF >> ((8 - (size & 7)) & 7);
+
+   /* calc the maskOR_msb */
+   maskOR_msb        = 0;
+   maskOR_msb_offset = (size - 2) >> 3;
+   if (flags & TFM_PRIME_2MSB_ON) {
+      maskOR_msb     |= 1 << ((size - 2) & 7);
+   } else if (flags & TFM_PRIME_2MSB_OFF) {
+      maskAND        &= ~(1 << ((size - 2) & 7));
+   }
+
+   /* get the maskOR_lsb */
+   maskOR_lsb         = 1;
+   if (flags & TFM_PRIME_BBS) {
+      maskOR_lsb     |= 3;
+   }
+
+   do {
+      /* read the bytes */
+      if (cb(tmp, bsize, dat) != bsize) {
+         err = FP_VAL;
+         goto error;
+      }
+
+      /* work over the MSbyte */
+      tmp[0]    &= maskAND;
+      tmp[0]    |= 1 << ((size - 1) & 7);
+
+      /* mix in the maskORs */
+      tmp[maskOR_msb_offset]   |= maskOR_msb;
+      tmp[bsize-1]             |= maskOR_lsb;
+
+      /* read it in */
+      fp_read_unsigned_bin(a, tmp, bsize);
+
+      /* is it prime? */
+      res = fp_isprime_ex(a, t);
+      if (res == FP_NO) continue;
+
+      if (flags & TFM_PRIME_SAFE) {
+         /* see if (a-1)/2 is prime */
+         fp_sub_d(a, 1, a);
+         fp_div_2(a, a);
+
+         /* is it prime? */
+         res = fp_isprime_ex(a, t);
+      }
+   } while (res == FP_NO);
+
+   if (flags & TFM_PRIME_SAFE) {
+      /* restore a to the original value */
+      fp_mul_2(a, a);
+      fp_add_d(a, 1, a);
+   }
+
+   err = FP_OKAY;
+error:
+   free(tmp);
+   return err;
+}
+
+/* $Source$ */
+/* $Revision$ */
+/* $Date$ */
diff --git a/tomsfastmath/src/sqr/fp_sqr.c b/tomsfastmath/src/sqr/fp_sqr.c
new file mode 100644 (file)
index 0000000..3678c7a
--- /dev/null
@@ -0,0 +1,126 @@
+/* TomsFastMath, a fast ISO C bignum library.
+ *
+ * This project is meant to fill in where LibTomMath
+ * falls short.  That is speed ;-)
+ *
+ * This project is public domain and free for all purposes.
+ *
+ * Tom St Denis, tomstdenis@gmail.com
+ */
+#include <tfm_private.h>
+
+/* b = a*a  */
+void fp_sqr(fp_int *A, fp_int *B)
+{
+    int     y, old_used;
+
+    old_used = B->used;
+
+    /* call generic if we're out of range */
+    if (A->used + A->used > FP_SIZE) {
+       fp_sqr_comba(A, B);
+       goto clean;
+    }
+
+    y = A->used;
+#if defined(TFM_SQR3) && FP_SIZE >= 6
+        if (y <= 3) {
+           fp_sqr_comba3(A,B);
+           goto clean;
+        }
+#endif
+#if defined(TFM_SQR4) && FP_SIZE >= 8
+        if (y == 4) {
+           fp_sqr_comba4(A,B);
+           goto clean;
+        }
+#endif
+#if defined(TFM_SQR6) && FP_SIZE >= 12
+        if (y <= 6) {
+           fp_sqr_comba6(A,B);
+           goto clean;
+        }
+#endif
+#if defined(TFM_SQR7) && FP_SIZE >= 14
+        if (y == 7) {
+           fp_sqr_comba7(A,B);
+           goto clean;
+        }
+#endif
+#if defined(TFM_SQR8) && FP_SIZE >= 16
+        if (y == 8) {
+           fp_sqr_comba8(A,B);
+           goto clean;
+        }
+#endif
+#if defined(TFM_SQR9) && FP_SIZE >= 18
+        if (y == 9) {
+           fp_sqr_comba9(A,B);
+           goto clean;
+        }
+#endif
+#if defined(TFM_SQR12) && FP_SIZE >= 24
+        if (y <= 12) {
+           fp_sqr_comba12(A,B);
+           goto clean;
+        }
+#endif
+#if defined(TFM_SQR17) && FP_SIZE >= 34
+        if (y <= 17) {
+           fp_sqr_comba17(A,B);
+           goto clean;
+        }
+#endif
+#if defined(TFM_SMALL_SET)
+        if (y <= 16) {
+           fp_sqr_comba_small(A,B);
+           goto clean;
+        }
+#endif
+#if defined(TFM_SQR20) && FP_SIZE >= 40
+        if (y <= 20) {
+           fp_sqr_comba20(A,B);
+           goto clean;
+        }
+#endif
+#if defined(TFM_SQR24) && FP_SIZE >= 48
+        if (y <= 24) {
+           fp_sqr_comba24(A,B);
+           goto clean;
+        }
+#endif
+#if defined(TFM_SQR28) && FP_SIZE >= 56
+        if (y <= 28) {
+           fp_sqr_comba28(A,B);
+           goto clean;
+        }
+#endif
+#if defined(TFM_SQR32) && FP_SIZE >= 64
+        if (y <= 32) {
+           fp_sqr_comba32(A,B);
+           goto clean;
+        }
+#endif
+#if defined(TFM_SQR48) && FP_SIZE >= 96
+        if (y <= 48) {
+           fp_sqr_comba48(A,B);
+           goto clean;
+        }
+#endif
+#if defined(TFM_SQR64) && FP_SIZE >= 128
+        if (y <= 64) {
+           fp_sqr_comba64(A,B);
+           goto clean;
+        }
+#endif
+       fp_sqr_comba(A, B);
+clean:
+    for (y = B->used; y < old_used; y++) {
+       B->dp[y] = 0;
+    }
+}
+
+
+/* $Source: /cvs/libtom/tomsfastmath/src/sqr/fp_sqr.c,v $ */
+/* $Revision: 1.1 $ */
+/* $Date: 2006/12/31 21:25:53 $ */
diff --git a/tomsfastmath/src/sqr/fp_sqr_comba.c b/tomsfastmath/src/sqr/fp_sqr_comba.c
new file mode 100644 (file)
index 0000000..1150333
--- /dev/null
@@ -0,0 +1,677 @@
+/*
+ *
+ * This project is meant to fill in where LibTomMath
+ * falls short.  That is speed ;-)
+ *
+ * This project is public domain and free for all purposes.
+ *
+ * Tom St Denis, tomstdenis@gmail.com
+ */
+#include <tfm_private.h>
+
+#if defined(TFM_PRESCOTT) && defined(TFM_SSE2)
+   #undef TFM_SSE2
+   #define TFM_X86
+#endif
+
+#if defined(TFM_X86)
+
+/* x86-32 optimized */
+
+#define COMBA_START
+
+#define CLEAR_CARRY \
+   c0 = c1 = c2 = 0;
+
+#define COMBA_STORE(x) \
+   x = c0;
+
+#define COMBA_STORE2(x) \
+   x = c1;
+
+#define CARRY_FORWARD \
+   do { c0 = c1; c1 = c2; c2 = 0; } while (0);
+
+#define COMBA_FINI
+
+#define SQRADD(i, j)                                      \
+asm(                                            \
+     "movl  %6,%%eax     \n\t"                            \
+     "mull  %%eax        \n\t"                            \
+     "addl  %%eax,%0     \n\t"                            \
+     "adcl  %%edx,%1     \n\t"                            \
+     "adcl  $0,%2        \n\t"                            \
+     :"=r"(c0), "=r"(c1), "=r"(c2): "0"(c0), "1"(c1), "2"(c2), "m"(i) :"%eax","%edx","cc");
+
+#define SQRADD2(i, j)                                     \
+asm(                                            \
+     "movl  %6,%%eax     \n\t"                            \
+     "mull  %7           \n\t"                            \
+     "addl  %%eax,%0     \n\t"                            \
+     "adcl  %%edx,%1     \n\t"                            \
+     "adcl  $0,%2        \n\t"                            \
+     "addl  %%eax,%0     \n\t"                            \
+     "adcl  %%edx,%1     \n\t"                            \
+     "adcl  $0,%2        \n\t"                            \
+     :"=r"(c0), "=r"(c1), "=r"(c2): "0"(c0), "1"(c1), "2"(c2), "m"(i), "m"(j)  :"%eax","%edx","cc");
+
+#define SQRADDSC(i, j)                                    \
+asm(                                                     \
+     "movl  %3,%%eax     \n\t"                            \
+     "mull  %4           \n\t"                            \
+     "movl  %%eax,%0     \n\t"                            \
+     "movl  %%edx,%1     \n\t"                            \
+     "xorl  %2,%2        \n\t"                            \
+     :"=r"(sc0), "=r"(sc1), "=r"(sc2): "g"(i), "g"(j) :"%eax","%edx","cc");
+
+#define SQRADDAC(i, j)                                    \
+asm(                                                     \
+     "movl  %6,%%eax     \n\t"                            \
+     "mull  %7           \n\t"                            \
+     "addl  %%eax,%0     \n\t"                            \
+     "adcl  %%edx,%1     \n\t"                            \
+     "adcl  $0,%2        \n\t"                            \
+     :"=r"(sc0), "=r"(sc1), "=r"(sc2): "0"(sc0), "1"(sc1), "2"(sc2), "g"(i), "g"(j) :"%eax","%edx","cc");
+
+#define SQRADDDB                                          \
+asm(                                                     \
+     "addl %6,%0         \n\t"                            \
+     "adcl %7,%1         \n\t"                            \
+     "adcl %8,%2         \n\t"                            \
+     "addl %6,%0         \n\t"                            \
+     "adcl %7,%1         \n\t"                            \
+     "adcl %8,%2         \n\t"                            \
+     :"=r"(c0), "=r"(c1), "=r"(c2) : "0"(c0), "1"(c1), "2"(c2), "r"(sc0), "r"(sc1), "r"(sc2) : "cc");
+
+#elif defined(TFM_X86_64)
+/* x86-64 optimized */
+
+#define COMBA_START
+
+#define CLEAR_CARRY \
+   c0 = c1 = c2 = 0;
+
+#define COMBA_STORE(x) \
+   x = c0;
+
+#define COMBA_STORE2(x) \
+   x = c1;
+
+#define CARRY_FORWARD \
+   do { c0 = c1; c1 = c2; c2 = 0; } while (0);
+
+#define COMBA_FINI
+
+#define SQRADD(i, j)                                      \
+asm(                                                     \
+     "movq  %6,%%rax     \n\t"                            \
+     "mulq  %%rax        \n\t"                            \
+     "addq  %%rax,%0     \n\t"                            \
+     "adcq  %%rdx,%1     \n\t"                            \
+     "adcq  $0,%2        \n\t"                            \
+     :"=r"(c0), "=r"(c1), "=r"(c2): "0"(c0), "1"(c1), "2"(c2), "x"(i) :"%rax","%rdx","cc");
+
+#define SQRADD2(i, j)                                     \
+asm(                                                     \
+     "movq  %6,%%rax     \n\t"                            \
+     "mulq  %7           \n\t"                            \
+     "addq  %%rax,%0     \n\t"                            \
+     "adcq  %%rdx,%1     \n\t"                            \
+     "adcq  $0,%2        \n\t"                            \
+     "addq  %%rax,%0     \n\t"                            \
+     "adcq  %%rdx,%1     \n\t"                            \
+     "adcq  $0,%2        \n\t"                            \
+     :"=r"(c0), "=r"(c1), "=r"(c2): "0"(c0), "1"(c1), "2"(c2), "g"(i), "g"(j)  :"%rax","%rdx","cc");
+
+#define SQRADDSC(i, j)                                    \
+asm(                                                     \
+     "movq  %3,%%rax     \n\t"                            \
+     "mulq  %4           \n\t"                            \
+     "movq  %%rax,%0     \n\t"                            \
+     "movq  %%rdx,%1     \n\t"                            \
+     "xorq  %2,%2        \n\t"                            \
+     :"=r"(sc0), "=r"(sc1), "=r"(sc2): "g"(i), "g"(j) :"%rax","%rdx","cc");
+
+#define SQRADDAC(i, j)                                                         \
+asm(                                                     \
+     "movq  %6,%%rax     \n\t"                            \
+     "mulq  %7           \n\t"                            \
+     "addq  %%rax,%0     \n\t"                            \
+     "adcq  %%rdx,%1     \n\t"                            \
+     "adcq  $0,%2        \n\t"                            \
+     :"=r"(sc0), "=r"(sc1), "=r"(sc2): "0"(sc0), "1"(sc1), "2"(sc2), "g"(i), "g"(j) :"%rax","%rdx","cc");
+
+#define SQRADDDB                                          \
+asm(                                                     \
+     "addq %6,%0         \n\t"                            \
+     "adcq %7,%1         \n\t"                            \
+     "adcq %8,%2         \n\t"                            \
+     "addq %6,%0         \n\t"                            \
+     "adcq %7,%1         \n\t"                            \
+     "adcq %8,%2         \n\t"                            \
+     :"=r"(c0), "=r"(c1), "=r"(c2) : "0"(c0), "1"(c1), "2"(c2), "r"(sc0), "r"(sc1), "r"(sc2) : "cc");
+
+#elif defined(TFM_SSE2)
+
+/* SSE2 Optimized */
+#define COMBA_START
+
+#define CLEAR_CARRY \
+   c0 = c1 = c2 = 0;
+
+#define COMBA_STORE(x) \
+   x = c0;
+
+#define COMBA_STORE2(x) \
+   x = c1;
+
+#define CARRY_FORWARD \
+   do { c0 = c1; c1 = c2; c2 = 0; } while (0);
+
+#define COMBA_FINI \
+   asm("emms");
+
+#define SQRADD(i, j)                                      \
+asm(                                            \
+     "movd  %6,%%mm0     \n\t"                            \
+     "pmuludq %%mm0,%%mm0\n\t"                            \
+     "movd  %%mm0,%%eax  \n\t"                            \
+     "psrlq $32,%%mm0    \n\t"                            \
+     "addl  %%eax,%0     \n\t"                            \
+     "movd  %%mm0,%%eax  \n\t"                            \
+     "adcl  %%eax,%1     \n\t"                            \
+     "adcl  $0,%2        \n\t"                            \
+     :"=r"(c0), "=r"(c1), "=r"(c2): "0"(c0), "1"(c1), "2"(c2), "m"(i) :"%eax","cc");
+
+#define SQRADD2(i, j)                                     \
+asm(                                            \
+     "movd  %6,%%mm0     \n\t"                            \
+     "movd  %7,%%mm1     \n\t"                            \
+     "pmuludq %%mm1,%%mm0\n\t"                            \
+     "movd  %%mm0,%%eax  \n\t"                            \
+     "psrlq $32,%%mm0    \n\t"                            \
+     "movd  %%mm0,%%edx  \n\t"                            \
+     "addl  %%eax,%0     \n\t"                            \
+     "adcl  %%edx,%1     \n\t"                            \
+     "adcl  $0,%2        \n\t"                            \
+     "addl  %%eax,%0     \n\t"                            \
+     "adcl  %%edx,%1     \n\t"                            \
+     "adcl  $0,%2        \n\t"                            \
+     :"=r"(c0), "=r"(c1), "=r"(c2): "0"(c0), "1"(c1), "2"(c2), "m"(i), "m"(j)  :"%eax","%edx","cc");
+
+#define SQRADDSC(i, j)                                                         \
+asm(                                            \
+     "movd  %6,%%mm0     \n\t"                            \
+     "movd  %7,%%mm1     \n\t"                            \
+     "pmuludq %%mm1,%%mm0\n\t"                            \
+     "movd  %%mm0,%0     \n\t"                            \
+     "psrlq $32,%%mm0    \n\t"                            \
+     "movd  %%mm0,%1     \n\t"                            \
+     "xorl  %2,%2        \n\t"                            \
+     :"=r"(sc0), "=r"(sc1), "=r"(sc2): "0"(sc0), "1"(sc1), "2"(sc2), "m"(i), "m"(j));
+
+#define SQRADDAC(i, j)                                                         \
+asm(                                            \
+     "movd  %6,%%mm0     \n\t"                            \
+     "movd  %7,%%mm1     \n\t"                            \
+     "pmuludq %%mm1,%%mm0\n\t"                            \
+     "movd  %%mm0,%%eax  \n\t"                            \
+     "psrlq $32,%%mm0    \n\t"                            \
+     "movd  %%mm0,%%edx  \n\t"                            \
+     "addl  %%eax,%0     \n\t"                            \
+     "adcl  %%edx,%1     \n\t"                            \
+     "adcl  $0,%2        \n\t"                            \
+     :"=r"(sc0), "=r"(sc1), "=r"(sc2): "0"(sc0), "1"(sc1), "2"(sc2), "m"(i), "m"(j)  :"%eax","%edx","cc");
+
+#define SQRADDDB                                          \
+asm(                                                     \
+     "addl %6,%0         \n\t"                            \
+     "adcl %7,%1         \n\t"                            \
+     "adcl %8,%2         \n\t"                            \
+     "addl %6,%0         \n\t"                            \
+     "adcl %7,%1         \n\t"                            \
+     "adcl %8,%2         \n\t"                            \
+     :"=r"(c0), "=r"(c1), "=r"(c2) : "0"(c0), "1"(c1), "2"(c2), "r"(sc0), "r"(sc1), "r"(sc2) : "cc");
+
+#elif defined(TFM_ARM)
+
+/* ARM code */
+
+#define COMBA_START
+
+#define CLEAR_CARRY \
+   c0 = c1 = c2 = 0;
+
+#define COMBA_STORE(x) \
+   x = c0;
+
+#define COMBA_STORE2(x) \
+   x = c1;
+
+#define CARRY_FORWARD \
+   do { c0 = c1; c1 = c2; c2 = 0; } while (0);
+
+#define COMBA_FINI
+
+/* multiplies point i and j, updates carry "c1" and digit c2 */
+#define SQRADD(i, j)                                             \
+asm(                                                             \
+"  UMULL  r0,r1,%6,%6              \n\t"                         \
+"  ADDS   %0,%0,r0                 \n\t"                         \
+"  ADCS   %1,%1,r1                 \n\t"                         \
+"  ADC    %2,%2,#0                 \n\t"                         \
+:"=r"(c0), "=r"(c1), "=r"(c2) : "0"(c0), "1"(c1), "2"(c2), "r"(i) : "r0", "r1", "cc");
+
+/* for squaring some of the terms are doubled... */
+#define SQRADD2(i, j)                                            \
+asm(                                                             \
+"  UMULL  r0,r1,%6,%7              \n\t"                         \
+"  ADDS   %0,%0,r0                 \n\t"                         \
+"  ADCS   %1,%1,r1                 \n\t"                         \
+"  ADC    %2,%2,#0                 \n\t"                         \
+"  ADDS   %0,%0,r0                 \n\t"                         \
+"  ADCS   %1,%1,r1                 \n\t"                         \
+"  ADC    %2,%2,#0                 \n\t"                         \
+:"=r"(c0), "=r"(c1), "=r"(c2) : "0"(c0), "1"(c1), "2"(c2), "r"(i), "r"(j) : "r0", "r1", "cc");
+
+#define SQRADDSC(i, j)                                           \
+asm(                                                             \
+"  UMULL  %0,%1,%6,%7              \n\t"                         \
+"  SUB    %2,%2,%2                 \n\t"                         \
+:"=r"(sc0), "=r"(sc1), "=r"(sc2) : "0"(sc0), "1"(sc1), "2"(sc2), "r"(i), "r"(j) : "cc");
+
+#define SQRADDAC(i, j)                                           \
+asm(                                                             \
+"  UMULL  r0,r1,%6,%7              \n\t"                         \
+"  ADDS   %0,%0,r0                 \n\t"                         \
+"  ADCS   %1,%1,r1                 \n\t"                         \
+"  ADC    %2,%2,#0                 \n\t"                         \
+:"=r"(sc0), "=r"(sc1), "=r"(sc2) : "0"(sc0), "1"(sc1), "2"(sc2), "r"(i), "r"(j) : "r0", "r1", "cc");
+
+#define SQRADDDB                                                 \
+asm(                                                             \
+"  ADDS  %0,%0,%3                     \n\t"                      \
+"  ADCS  %1,%1,%4                     \n\t"                      \
+"  ADC   %2,%2,%5                     \n\t"                      \
+"  ADDS  %0,%0,%3                     \n\t"                      \
+"  ADCS  %1,%1,%4                     \n\t"                      \
+"  ADC   %2,%2,%5                     \n\t"                      \
+:"=r"(c0), "=r"(c1), "=r"(c2) : "r"(sc0), "r"(sc1), "r"(sc2), "0"(c0), "1"(c1), "2"(c2) : "cc");
+
+#elif defined(TFM_PPC32)
+
+/* PPC32 */
+
+#define COMBA_START
+
+#define CLEAR_CARRY \
+   c0 = c1 = c2 = 0;
+
+#define COMBA_STORE(x) \
+   x = c0;
+
+#define COMBA_STORE2(x) \
+   x = c1;
+
+#define CARRY_FORWARD \
+   do { c0 = c1; c1 = c2; c2 = 0; } while (0);
+
+#define COMBA_FINI
+
+/* multiplies point i and j, updates carry "c1" and digit c2 */
+#define SQRADD(i, j)             \
+asm(                             \
+   " mullw  16,%6,%6       \n\t" \
+   " addc   %0,%0,16       \n\t" \
+   " mulhwu 16,%6,%6       \n\t" \
+   " adde   %1,%1,16       \n\t" \
+   " addze  %2,%2          \n\t" \
+:"=r"(c0), "=r"(c1), "=r"(c2):"0"(c0), "1"(c1), "2"(c2), "r"(i):"16","cc");
+
+/* for squaring some of the terms are doubled... */
+#define SQRADD2(i, j)            \
+asm(                             \
+   " mullw  16,%6,%7       \n\t" \
+   " mulhwu 17,%6,%7       \n\t" \
+   " addc   %0,%0,16       \n\t" \
+   " adde   %1,%1,17       \n\t" \
+   " addze  %2,%2          \n\t" \
+   " addc   %0,%0,16       \n\t" \
+   " adde   %1,%1,17       \n\t" \
+   " addze  %2,%2          \n\t" \
+:"=r"(c0), "=r"(c1), "=r"(c2):"0"(c0), "1"(c1), "2"(c2), "r"(i), "r"(j):"16", "17","cc");
+
+#define SQRADDSC(i, j)            \
+asm(                              \
+   " mullw  %0,%6,%7        \n\t" \
+   " mulhwu %1,%6,%7        \n\t" \
+   " xor    %2,%2,%2        \n\t" \
+:"=r"(sc0), "=r"(sc1), "=r"(sc2):"0"(sc0), "1"(sc1), "2"(sc2), "r"(i),"r"(j) : "cc");
+
+#define SQRADDAC(i, j)           \
+asm(                             \
+   " mullw  16,%6,%7       \n\t" \
+   " addc   %0,%0,16       \n\t" \
+   " mulhwu 16,%6,%7       \n\t" \
+   " adde   %1,%1,16       \n\t" \
+   " addze  %2,%2          \n\t" \
+:"=r"(sc0), "=r"(sc1), "=r"(sc2):"0"(sc0), "1"(sc1), "2"(sc2), "r"(i), "r"(j):"16", "cc");
+
+#define SQRADDDB                  \
+asm(                              \
+   " addc   %0,%0,%3        \n\t" \
+   " adde   %1,%1,%4        \n\t" \
+   " adde   %2,%2,%5        \n\t" \
+   " addc   %0,%0,%3        \n\t" \
+   " adde   %1,%1,%4        \n\t" \
+   " adde   %2,%2,%5        \n\t" \
+:"=r"(c0), "=r"(c1), "=r"(c2) : "r"(sc0), "r"(sc1), "r"(sc2), "0"(c0), "1"(c1), "2"(c2) : "cc");
+
+#elif defined(TFM_PPC64)
+/* PPC64 */
+
+#define COMBA_START
+
+#define CLEAR_CARRY \
+   c0 = c1 = c2 = 0;
+
+#define COMBA_STORE(x) \
+   x = c0;
+
+#define COMBA_STORE2(x) \
+   x = c1;
+
+#define CARRY_FORWARD \
+   do { c0 = c1; c1 = c2; c2 = 0; } while (0);
+
+#define COMBA_FINI
+
+/* multiplies point i and j, updates carry "c1" and digit c2 */
+#define SQRADD(i, j)             \
+asm(                             \
+   " mulld  r16,%6,%6       \n\t" \
+   " addc   %0,%0,r16       \n\t" \
+   " mulhdu r16,%6,%6       \n\t" \
+   " adde   %1,%1,r16       \n\t" \
+   " addze  %2,%2          \n\t" \
+:"=r"(c0), "=r"(c1), "=r"(c2):"0"(c0), "1"(c1), "2"(c2), "r"(i):"r16","cc");
+
+/* for squaring some of the terms are doubled... */
+#define SQRADD2(i, j)            \
+asm(                             \
+   " mulld  r16,%6,%7       \n\t" \
+   " mulhdu r17,%6,%7       \n\t" \
+   " addc   %0,%0,r16       \n\t" \
+   " adde   %1,%1,r17       \n\t" \
+   " addze  %2,%2          \n\t" \
+   " addc   %0,%0,r16       \n\t" \
+   " adde   %1,%1,r17       \n\t" \
+   " addze  %2,%2          \n\t" \
+:"=r"(c0), "=r"(c1), "=r"(c2):"0"(c0), "1"(c1), "2"(c2), "r"(i), "r"(j):"r16", "r17","cc");
+
+#define SQRADDSC(i, j)            \
+asm(                              \
+   " mulld  %0,%6,%7        \n\t" \
+   " mulhdu %1,%6,%7        \n\t" \
+   " xor    %2,%2,%2        \n\t" \
+:"=r"(sc0), "=r"(sc1), "=r"(sc2):"0"(sc0), "1"(sc1), "2"(sc2), "r"(i),"r"(j) : "cc");
+
+#define SQRADDAC(i, j)           \
+asm(                             \
+   " mulld  r16,%6,%7       \n\t" \
+   " addc   %0,%0,r16       \n\t" \
+   " mulhdu r16,%6,%7       \n\t" \
+   " adde   %1,%1,r16       \n\t" \
+   " addze  %2,%2          \n\t" \
+:"=r"(sc0), "=r"(sc1), "=r"(sc2):"0"(sc0), "1"(sc1), "2"(sc2), "r"(i), "r"(j):"r16", "cc");
+
+#define SQRADDDB                  \
+asm(                              \
+   " addc   %0,%0,%3        \n\t" \
+   " adde   %1,%1,%4        \n\t" \
+   " adde   %2,%2,%5        \n\t" \
+   " addc   %0,%0,%3        \n\t" \
+   " adde   %1,%1,%4        \n\t" \
+   " adde   %2,%2,%5        \n\t" \
+:"=r"(c0), "=r"(c1), "=r"(c2) : "r"(sc0), "r"(sc1), "r"(sc2), "0"(c0), "1"(c1), "2"(c2) : "cc");
+
+
+#elif defined(TFM_AVR32)
+
+/* AVR32 */
+
+#define COMBA_START
+
+#define CLEAR_CARRY \
+   c0 = c1 = c2 = 0;
+
+#define COMBA_STORE(x) \
+   x = c0;
+
+#define COMBA_STORE2(x) \
+   x = c1;
+
+#define CARRY_FORWARD \
+   do { c0 = c1; c1 = c2; c2 = 0; } while (0);
+
+#define COMBA_FINI
+
+/* multiplies point i and j, updates carry "c1" and digit c2 */
+#define SQRADD(i, j)             \
+asm(                             \
+   " mulu.d r2,%6,%6       \n\t" \
+   " add    %0,%0,r2       \n\t" \
+   " adc    %1,%1,r3       \n\t" \
+   " acr    %2             \n\t" \
+:"=r"(c0), "=r"(c1), "=r"(c2):"0"(c0), "1"(c1), "2"(c2), "r"(i):"r2","r3");
+
+/* for squaring some of the terms are doubled... */
+#define SQRADD2(i, j)            \
+asm(                             \
+   " mulu.d r2,%6,%7       \n\t" \
+   " add    %0,%0,r2       \n\t" \
+   " adc    %1,%1,r3       \n\t" \
+   " acr    %2,            \n\t" \
+   " add    %0,%0,r2       \n\t" \
+   " adc    %1,%1,r3       \n\t" \
+   " acr    %2,            \n\t" \
+:"=r"(c0), "=r"(c1), "=r"(c2):"0"(c0), "1"(c1), "2"(c2), "r"(i), "r"(j):"r2", "r3");
+
+#define SQRADDSC(i, j)            \
+asm(                              \
+   " mulu.d r2,%6,%7        \n\t" \
+   " mov    %0,r2           \n\t" \
+   " mov    %1,r3           \n\t" \
+   " eor    %2,%2           \n\t" \
+:"=r"(sc0), "=r"(sc1), "=r"(sc2):"0"(sc0), "1"(sc1), "2"(sc2), "r"(i),"r"(j) : "r2", "r3");
+
+#define SQRADDAC(i, j)           \
+asm(                             \
+   " mulu.d r2,%6,%7       \n\t" \
+   " add    %0,%0,r2       \n\t" \
+   " adc    %1,%1,r3       \n\t" \
+   " acr    %2             \n\t" \
+:"=r"(sc0), "=r"(sc1), "=r"(sc2):"0"(sc0), "1"(sc1), "2"(sc2), "r"(i), "r"(j):"r2", "r3");
+
+#define SQRADDDB                  \
+asm(                              \
+   " add    %0,%0,%3        \n\t" \
+   " adc    %1,%1,%4        \n\t" \
+   " adc    %2,%2,%5        \n\t" \
+   " add    %0,%0,%3        \n\t" \
+   " adc    %1,%1,%4        \n\t" \
+   " adc    %2,%2,%5        \n\t" \
+:"=r"(c0), "=r"(c1), "=r"(c2) : "r"(sc0), "r"(sc1), "r"(sc2), "0"(c0), "1"(c1), "2"(c2) : "cc");
+
+#elif defined(TFM_MIPS)
+
+/* MIPS */
+
+#define COMBA_START
+
+#define CLEAR_CARRY \
+   c0 = c1 = c2 = 0;
+
+#define COMBA_STORE(x) \
+   x = c0;
+
+#define COMBA_STORE2(x) \
+   x = c1;
+
+#define CARRY_FORWARD \
+   do { c0 = c1; c1 = c2; c2 = 0; } while (0);
+
+#define COMBA_FINI
+
+/* multiplies point i and j, updates carry "c1" and digit c2 */
+#define SQRADD(i, j)              \
+asm(                              \
+   " multu  %6,%6          \n\t"  \
+   " mflo   $12            \n\t"  \
+   " mfhi   $13            \n\t"  \
+   " addu    %0,%0,$12     \n\t"  \
+   " sltu   $12,%0,$12     \n\t"  \
+   " addu    %1,%1,$13     \n\t"  \
+   " sltu   $13,%1,$13     \n\t"  \
+   " addu    %1,%1,$12     \n\t"  \
+   " sltu   $12,%1,$12     \n\t"  \
+   " addu    %2,%2,$13     \n\t"  \
+   " addu    %2,%2,$12     \n\t"  \
+:"=r"(c0), "=r"(c1), "=r"(c2):"0"(c0), "1"(c1), "2"(c2), "r"(i):"$12","$13");
+
+/* for squaring some of the terms are doubled... */
+#define SQRADD2(i, j)            \
+asm(                             \
+   " multu  %6,%7          \n\t" \
+   " mflo   $12            \n\t" \
+   " mfhi   $13            \n\t" \
+                                 \
+   " addu    %0,%0,$12     \n\t" \
+   " sltu   $14,%0,$12     \n\t" \
+   " addu    %1,%1,$13     \n\t" \
+   " sltu   $15,%1,$13     \n\t" \
+   " addu    %1,%1,$14     \n\t" \
+   " sltu   $14,%1,$14     \n\t" \
+   " addu    %2,%2,$15     \n\t" \
+   " addu    %2,%2,$14     \n\t" \
+                                 \
+   " addu    %0,%0,$12     \n\t" \
+   " sltu   $14,%0,$12     \n\t" \
+   " addu    %1,%1,$13     \n\t" \
+   " sltu   $15,%1,$13     \n\t" \
+   " addu    %1,%1,$14     \n\t" \
+   " sltu   $14,%1,$14     \n\t" \
+   " addu    %2,%2,$15     \n\t" \
+   " addu    %2,%2,$14     \n\t" \
+:"=r"(c0), "=r"(c1), "=r"(c2):"0"(c0), "1"(c1), "2"(c2), "r"(i), "r"(j):"$12", "$13", "$14", "$15");
+
+#define SQRADDSC(i, j)            \
+asm(                              \
+   " multu  %6,%7          \n\t"  \
+   " mflo   %0             \n\t"  \
+   " mfhi   %1             \n\t"  \
+   " xor    %2,%2,%2       \n\t"  \
+:"=r"(sc0), "=r"(sc1), "=r"(sc2):"0"(sc0), "1"(sc1), "2"(sc2), "r"(i),"r"(j) : "cc");
+
+#define SQRADDAC(i, j)           \
+asm(                             \
+   " multu  %6,%7          \n\t" \
+   " mflo   $12            \n\t" \
+   " mfhi   $13            \n\t" \
+   " addu    %0,%0,$12     \n\t" \
+   " sltu   $12,%0,$12     \n\t" \
+   " addu    %1,%1,$13     \n\t" \
+   " sltu   $13,%1,$13     \n\t" \
+   " addu    %1,%1,$12     \n\t" \
+   " sltu   $12,%1,$12     \n\t" \
+   " addu    %2,%2,$13     \n\t" \
+   " addu    %2,%2,$12     \n\t" \
+:"=r"(sc0), "=r"(sc1), "=r"(sc2):"0"(sc0), "1"(sc1), "2"(sc2), "r"(i), "r"(j):"$12", "$13", "$14");
+
+#define SQRADDDB                  \
+asm(                              \
+   " addu    %0,%0,%3       \n\t" \
+   " sltu   $10,%0,%3       \n\t" \
+   " addu    %1,%1,$10      \n\t" \
+   " sltu   $10,%1,$10      \n\t" \
+   " addu    %1,%1,%4       \n\t" \
+   " sltu   $11,%1,%4       \n\t" \
+   " addu    %2,%2,$10      \n\t" \
+   " addu    %2,%2,$11      \n\t" \
+   " addu    %2,%2,%5       \n\t" \
+                                  \
+   " addu    %0,%0,%3       \n\t" \
+   " sltu   $10,%0,%3       \n\t" \
+   " addu    %1,%1,$10      \n\t" \
+   " sltu   $10,%1,$10      \n\t" \
+   " addu    %1,%1,%4       \n\t" \
+   " sltu   $11,%1,%4       \n\t" \
+   " addu    %2,%2,$10      \n\t" \
+   " addu    %2,%2,$11      \n\t" \
+   " addu    %2,%2,%5       \n\t" \
+:"=r"(c0), "=r"(c1), "=r"(c2) : "r"(sc0), "r"(sc1), "r"(sc2), "0"(c0), "1"(c1), "2"(c2) : "$10", "$11");
+
+#else
+
+#define TFM_ISO
+
+/* ISO C portable code */
+
+#define COMBA_START
+
+#define CLEAR_CARRY \
+   c0 = c1 = c2 = 0;
+
+#define COMBA_STORE(x) \
+   x = c0;
+
+#define COMBA_STORE2(x) \
+   x = c1;
+
+#define CARRY_FORWARD \
+   do { c0 = c1; c1 = c2; c2 = 0; } while (0);
+
+#define COMBA_FINI
+
+/* multiplies point i and j, updates carry "c1" and digit c2 */
+#define SQRADD(i, j)                                 \
+   do { fp_word t;                                   \
+   t = c0 + ((fp_word)i) * ((fp_word)j);  c0 = t;    \
+   t = c1 + (t >> DIGIT_BIT);             c1 = t; c2 += t >> DIGIT_BIT; \
+   } while (0);
+
+
+/* for squaring some of the terms are doubled... */
+#define SQRADD2(i, j)                                                 \
+   do { fp_word t;                                                    \
+   t  = ((fp_word)i) * ((fp_word)j);                                  \
+   tt = (fp_word)c0 + t;                 c0 = tt;                              \
+   tt = (fp_word)c1 + (tt >> DIGIT_BIT); c1 = tt; c2 += tt >> DIGIT_BIT;       \
+   tt = (fp_word)c0 + t;                 c0 = tt;                              \
+   tt = (fp_word)c1 + (tt >> DIGIT_BIT); c1 = tt; c2 += tt >> DIGIT_BIT;       \
+   } while (0);
+
+#define SQRADDSC(i, j)                                                         \
+   do { fp_word t;                                                             \
+      t =  ((fp_word)i) * ((fp_word)j);                                        \
+      sc0 = (fp_digit)t; sc1 = (t >> DIGIT_BIT); sc2 = 0;                      \
+   } while (0);
+
+#define SQRADDAC(i, j)                                                         \
+   do { fp_word t;                                                             \
+   t = sc0 + ((fp_word)i) * ((fp_word)j);  sc0 = t;                            \
+   t = sc1 + (t >> DIGIT_BIT);             sc1 = t; sc2 += t >> DIGIT_BIT;     \
+   } while (0);
+
+#define SQRADDDB                                                               \
+   do { fp_word t;                                                             \
+   t = ((fp_word)sc0) + ((fp_word)sc0) + c0; c0 = t;                                                 \
+   t = ((fp_word)sc1) + ((fp_word)sc1) + c1 + (t >> DIGIT_BIT); c1 = t;                              \
+   c2 = c2 + ((fp_word)sc2) + ((fp_word)sc2) + (t >> DIGIT_BIT);                                     \
+   } while (0);
+
+#endif
+
+/* $Source$ */
+/* $Revision$ */
+/* $Date$ */
diff --git a/tomsfastmath/src/sqr/fp_sqr_comba_12.c b/tomsfastmath/src/sqr/fp_sqr_comba_12.c
new file mode 100644 (file)
index 0000000..53f2bdd
--- /dev/null
@@ -0,0 +1,144 @@
+#define TFM_DEFINES
+#include "fp_sqr_comba.c"
+
+#if defined(TFM_SQR12) && FP_SIZE >= 24
+void fp_sqr_comba12(fp_int *A, fp_int *B)
+{
+   fp_digit *a, b[24], c0, c1, c2, sc0, sc1, sc2;
+#ifdef TFM_ISO
+   fp_word tt;
+#endif
+
+   a = A->dp;
+   COMBA_START;
+
+   /* clear carries */
+   CLEAR_CARRY;
+
+   /* output 0 */
+   SQRADD(a[0],a[0]);
+   COMBA_STORE(b[0]);
+
+   /* output 1 */
+   CARRY_FORWARD;
+   SQRADD2(a[0], a[1]);
+   COMBA_STORE(b[1]);
+
+   /* output 2 */
+   CARRY_FORWARD;
+   SQRADD2(a[0], a[2]); SQRADD(a[1], a[1]);
+   COMBA_STORE(b[2]);
+
+   /* output 3 */
+   CARRY_FORWARD;
+   SQRADD2(a[0], a[3]); SQRADD2(a[1], a[2]);
+   COMBA_STORE(b[3]);
+
+   /* output 4 */
+   CARRY_FORWARD;
+   SQRADD2(a[0], a[4]); SQRADD2(a[1], a[3]); SQRADD(a[2], a[2]);
+   COMBA_STORE(b[4]);
+
+   /* output 5 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[5]); SQRADDAC(a[1], a[4]); SQRADDAC(a[2], a[3]); SQRADDDB;
+   COMBA_STORE(b[5]);
+
+   /* output 6 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[6]); SQRADDAC(a[1], a[5]); SQRADDAC(a[2], a[4]); SQRADDDB; SQRADD(a[3], a[3]);
+   COMBA_STORE(b[6]);
+
+   /* output 7 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[7]); SQRADDAC(a[1], a[6]); SQRADDAC(a[2], a[5]); SQRADDAC(a[3], a[4]); SQRADDDB;
+   COMBA_STORE(b[7]);
+
+   /* output 8 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[8]); SQRADDAC(a[1], a[7]); SQRADDAC(a[2], a[6]); SQRADDAC(a[3], a[5]); SQRADDDB; SQRADD(a[4], a[4]);
+   COMBA_STORE(b[8]);
+
+   /* output 9 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[9]); SQRADDAC(a[1], a[8]); SQRADDAC(a[2], a[7]); SQRADDAC(a[3], a[6]); SQRADDAC(a[4], a[5]); SQRADDDB;
+   COMBA_STORE(b[9]);
+
+   /* output 10 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[10]); SQRADDAC(a[1], a[9]); SQRADDAC(a[2], a[8]); SQRADDAC(a[3], a[7]); SQRADDAC(a[4], a[6]); SQRADDDB; SQRADD(a[5], a[5]);
+   COMBA_STORE(b[10]);
+
+   /* output 11 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[11]); SQRADDAC(a[1], a[10]); SQRADDAC(a[2], a[9]); SQRADDAC(a[3], a[8]); SQRADDAC(a[4], a[7]); SQRADDAC(a[5], a[6]); SQRADDDB;
+   COMBA_STORE(b[11]);
+
+   /* output 12 */
+   CARRY_FORWARD;
+   SQRADDSC(a[1], a[11]); SQRADDAC(a[2], a[10]); SQRADDAC(a[3], a[9]); SQRADDAC(a[4], a[8]); SQRADDAC(a[5], a[7]); SQRADDDB; SQRADD(a[6], a[6]);
+   COMBA_STORE(b[12]);
+
+   /* output 13 */
+   CARRY_FORWARD;
+   SQRADDSC(a[2], a[11]); SQRADDAC(a[3], a[10]); SQRADDAC(a[4], a[9]); SQRADDAC(a[5], a[8]); SQRADDAC(a[6], a[7]); SQRADDDB;
+   COMBA_STORE(b[13]);
+
+   /* output 14 */
+   CARRY_FORWARD;
+   SQRADDSC(a[3], a[11]); SQRADDAC(a[4], a[10]); SQRADDAC(a[5], a[9]); SQRADDAC(a[6], a[8]); SQRADDDB; SQRADD(a[7], a[7]);
+   COMBA_STORE(b[14]);
+
+   /* output 15 */
+   CARRY_FORWARD;
+   SQRADDSC(a[4], a[11]); SQRADDAC(a[5], a[10]); SQRADDAC(a[6], a[9]); SQRADDAC(a[7], a[8]); SQRADDDB;
+   COMBA_STORE(b[15]);
+
+   /* output 16 */
+   CARRY_FORWARD;
+   SQRADDSC(a[5], a[11]); SQRADDAC(a[6], a[10]); SQRADDAC(a[7], a[9]); SQRADDDB; SQRADD(a[8], a[8]);
+   COMBA_STORE(b[16]);
+
+   /* output 17 */
+   CARRY_FORWARD;
+   SQRADDSC(a[6], a[11]); SQRADDAC(a[7], a[10]); SQRADDAC(a[8], a[9]); SQRADDDB;
+   COMBA_STORE(b[17]);
+
+   /* output 18 */
+   CARRY_FORWARD;
+   SQRADD2(a[7], a[11]); SQRADD2(a[8], a[10]); SQRADD(a[9], a[9]);
+   COMBA_STORE(b[18]);
+
+   /* output 19 */
+   CARRY_FORWARD;
+   SQRADD2(a[8], a[11]); SQRADD2(a[9], a[10]);
+   COMBA_STORE(b[19]);
+
+   /* output 20 */
+   CARRY_FORWARD;
+   SQRADD2(a[9], a[11]); SQRADD(a[10], a[10]);
+   COMBA_STORE(b[20]);
+
+   /* output 21 */
+   CARRY_FORWARD;
+   SQRADD2(a[10], a[11]);
+   COMBA_STORE(b[21]);
+
+   /* output 22 */
+   CARRY_FORWARD;
+   SQRADD(a[11], a[11]);
+   COMBA_STORE(b[22]);
+   COMBA_STORE2(b[23]);
+   COMBA_FINI;
+
+   B->used = 24;
+   B->sign = FP_ZPOS;
+   memcpy(B->dp, b, 24 * sizeof(fp_digit));
+   fp_clamp(B);
+}
+#endif
+
+
+/* $Source$ */
+/* $Revision$ */
+/* $Date$ */
diff --git a/tomsfastmath/src/sqr/fp_sqr_comba_17.c b/tomsfastmath/src/sqr/fp_sqr_comba_17.c
new file mode 100644 (file)
index 0000000..5c25fb5
--- /dev/null
@@ -0,0 +1,194 @@
+#define TFM_DEFINES
+#include "fp_sqr_comba.c"
+
+#if defined(TFM_SQR17) && FP_SIZE >= 34
+void fp_sqr_comba17(fp_int *A, fp_int *B)
+{
+   fp_digit *a, b[34], c0, c1, c2, sc0, sc1, sc2;
+#ifdef TFM_ISO
+   fp_word tt;
+#endif
+
+   a = A->dp;
+   COMBA_START;
+
+   /* clear carries */
+   CLEAR_CARRY;
+
+   /* output 0 */
+   SQRADD(a[0],a[0]);
+   COMBA_STORE(b[0]);
+
+   /* output 1 */
+   CARRY_FORWARD;
+   SQRADD2(a[0], a[1]);
+   COMBA_STORE(b[1]);
+
+   /* output 2 */
+   CARRY_FORWARD;
+   SQRADD2(a[0], a[2]); SQRADD(a[1], a[1]);
+   COMBA_STORE(b[2]);
+
+   /* output 3 */
+   CARRY_FORWARD;
+   SQRADD2(a[0], a[3]); SQRADD2(a[1], a[2]);
+   COMBA_STORE(b[3]);
+
+   /* output 4 */
+   CARRY_FORWARD;
+   SQRADD2(a[0], a[4]); SQRADD2(a[1], a[3]); SQRADD(a[2], a[2]);
+   COMBA_STORE(b[4]);
+
+   /* output 5 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[5]); SQRADDAC(a[1], a[4]); SQRADDAC(a[2], a[3]); SQRADDDB;
+   COMBA_STORE(b[5]);
+
+   /* output 6 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[6]); SQRADDAC(a[1], a[5]); SQRADDAC(a[2], a[4]); SQRADDDB; SQRADD(a[3], a[3]);
+   COMBA_STORE(b[6]);
+
+   /* output 7 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[7]); SQRADDAC(a[1], a[6]); SQRADDAC(a[2], a[5]); SQRADDAC(a[3], a[4]); SQRADDDB;
+   COMBA_STORE(b[7]);
+
+   /* output 8 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[8]); SQRADDAC(a[1], a[7]); SQRADDAC(a[2], a[6]); SQRADDAC(a[3], a[5]); SQRADDDB; SQRADD(a[4], a[4]);
+   COMBA_STORE(b[8]);
+
+   /* output 9 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[9]); SQRADDAC(a[1], a[8]); SQRADDAC(a[2], a[7]); SQRADDAC(a[3], a[6]); SQRADDAC(a[4], a[5]); SQRADDDB;
+   COMBA_STORE(b[9]);
+
+   /* output 10 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[10]); SQRADDAC(a[1], a[9]); SQRADDAC(a[2], a[8]); SQRADDAC(a[3], a[7]); SQRADDAC(a[4], a[6]); SQRADDDB; SQRADD(a[5], a[5]);
+   COMBA_STORE(b[10]);
+
+   /* output 11 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[11]); SQRADDAC(a[1], a[10]); SQRADDAC(a[2], a[9]); SQRADDAC(a[3], a[8]); SQRADDAC(a[4], a[7]); SQRADDAC(a[5], a[6]); SQRADDDB;
+   COMBA_STORE(b[11]);
+
+   /* output 12 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[12]); SQRADDAC(a[1], a[11]); SQRADDAC(a[2], a[10]); SQRADDAC(a[3], a[9]); SQRADDAC(a[4], a[8]); SQRADDAC(a[5], a[7]); SQRADDDB; SQRADD(a[6], a[6]);
+   COMBA_STORE(b[12]);
+
+   /* output 13 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[13]); SQRADDAC(a[1], a[12]); SQRADDAC(a[2], a[11]); SQRADDAC(a[3], a[10]); SQRADDAC(a[4], a[9]); SQRADDAC(a[5], a[8]); SQRADDAC(a[6], a[7]); SQRADDDB;
+   COMBA_STORE(b[13]);
+
+   /* output 14 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[14]); SQRADDAC(a[1], a[13]); SQRADDAC(a[2], a[12]); SQRADDAC(a[3], a[11]); SQRADDAC(a[4], a[10]); SQRADDAC(a[5], a[9]); SQRADDAC(a[6], a[8]); SQRADDDB; SQRADD(a[7], a[7]);
+   COMBA_STORE(b[14]);
+
+   /* output 15 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[15]); SQRADDAC(a[1], a[14]); SQRADDAC(a[2], a[13]); SQRADDAC(a[3], a[12]); SQRADDAC(a[4], a[11]); SQRADDAC(a[5], a[10]); SQRADDAC(a[6], a[9]); SQRADDAC(a[7], a[8]); SQRADDDB;
+   COMBA_STORE(b[15]);
+
+   /* output 16 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[16]); SQRADDAC(a[1], a[15]); SQRADDAC(a[2], a[14]); SQRADDAC(a[3], a[13]); SQRADDAC(a[4], a[12]); SQRADDAC(a[5], a[11]); SQRADDAC(a[6], a[10]); SQRADDAC(a[7], a[9]); SQRADDDB; SQRADD(a[8], a[8]);
+   COMBA_STORE(b[16]);
+
+   /* output 17 */
+   CARRY_FORWARD;
+   SQRADDSC(a[1], a[16]); SQRADDAC(a[2], a[15]); SQRADDAC(a[3], a[14]); SQRADDAC(a[4], a[13]); SQRADDAC(a[5], a[12]); SQRADDAC(a[6], a[11]); SQRADDAC(a[7], a[10]); SQRADDAC(a[8], a[9]); SQRADDDB;
+   COMBA_STORE(b[17]);
+
+   /* output 18 */
+   CARRY_FORWARD;
+   SQRADDSC(a[2], a[16]); SQRADDAC(a[3], a[15]); SQRADDAC(a[4], a[14]); SQRADDAC(a[5], a[13]); SQRADDAC(a[6], a[12]); SQRADDAC(a[7], a[11]); SQRADDAC(a[8], a[10]); SQRADDDB; SQRADD(a[9], a[9]);
+   COMBA_STORE(b[18]);
+
+   /* output 19 */
+   CARRY_FORWARD;
+   SQRADDSC(a[3], a[16]); SQRADDAC(a[4], a[15]); SQRADDAC(a[5], a[14]); SQRADDAC(a[6], a[13]); SQRADDAC(a[7], a[12]); SQRADDAC(a[8], a[11]); SQRADDAC(a[9], a[10]); SQRADDDB;
+   COMBA_STORE(b[19]);
+
+   /* output 20 */
+   CARRY_FORWARD;
+   SQRADDSC(a[4], a[16]); SQRADDAC(a[5], a[15]); SQRADDAC(a[6], a[14]); SQRADDAC(a[7], a[13]); SQRADDAC(a[8], a[12]); SQRADDAC(a[9], a[11]); SQRADDDB; SQRADD(a[10], a[10]);
+   COMBA_STORE(b[20]);
+
+   /* output 21 */
+   CARRY_FORWARD;
+   SQRADDSC(a[5], a[16]); SQRADDAC(a[6], a[15]); SQRADDAC(a[7], a[14]); SQRADDAC(a[8], a[13]); SQRADDAC(a[9], a[12]); SQRADDAC(a[10], a[11]); SQRADDDB;
+   COMBA_STORE(b[21]);
+
+   /* output 22 */
+   CARRY_FORWARD;
+   SQRADDSC(a[6], a[16]); SQRADDAC(a[7], a[15]); SQRADDAC(a[8], a[14]); SQRADDAC(a[9], a[13]); SQRADDAC(a[10], a[12]); SQRADDDB; SQRADD(a[11], a[11]);
+   COMBA_STORE(b[22]);
+
+   /* output 23 */
+   CARRY_FORWARD;
+   SQRADDSC(a[7], a[16]); SQRADDAC(a[8], a[15]); SQRADDAC(a[9], a[14]); SQRADDAC(a[10], a[13]); SQRADDAC(a[11], a[12]); SQRADDDB;
+   COMBA_STORE(b[23]);
+
+   /* output 24 */
+   CARRY_FORWARD;
+   SQRADDSC(a[8], a[16]); SQRADDAC(a[9], a[15]); SQRADDAC(a[10], a[14]); SQRADDAC(a[11], a[13]); SQRADDDB; SQRADD(a[12], a[12]);
+   COMBA_STORE(b[24]);
+
+   /* output 25 */
+   CARRY_FORWARD;
+   SQRADDSC(a[9], a[16]); SQRADDAC(a[10], a[15]); SQRADDAC(a[11], a[14]); SQRADDAC(a[12], a[13]); SQRADDDB;
+   COMBA_STORE(b[25]);
+
+   /* output 26 */
+   CARRY_FORWARD;
+   SQRADDSC(a[10], a[16]); SQRADDAC(a[11], a[15]); SQRADDAC(a[12], a[14]); SQRADDDB; SQRADD(a[13], a[13]);
+   COMBA_STORE(b[26]);
+
+   /* output 27 */
+   CARRY_FORWARD;
+   SQRADDSC(a[11], a[16]); SQRADDAC(a[12], a[15]); SQRADDAC(a[13], a[14]); SQRADDDB;
+   COMBA_STORE(b[27]);
+
+   /* output 28 */
+   CARRY_FORWARD;
+   SQRADD2(a[12], a[16]); SQRADD2(a[13], a[15]); SQRADD(a[14], a[14]);
+   COMBA_STORE(b[28]);
+
+   /* output 29 */
+   CARRY_FORWARD;
+   SQRADD2(a[13], a[16]); SQRADD2(a[14], a[15]);
+   COMBA_STORE(b[29]);
+
+   /* output 30 */
+   CARRY_FORWARD;
+   SQRADD2(a[14], a[16]); SQRADD(a[15], a[15]);
+   COMBA_STORE(b[30]);
+
+   /* output 31 */
+   CARRY_FORWARD;
+   SQRADD2(a[15], a[16]);
+   COMBA_STORE(b[31]);
+
+   /* output 32 */
+   CARRY_FORWARD;
+   SQRADD(a[16], a[16]);
+   COMBA_STORE(b[32]);
+   COMBA_STORE2(b[33]);
+   COMBA_FINI;
+
+   B->used = 34;
+   B->sign = FP_ZPOS;
+   memcpy(B->dp, b, 34 * sizeof(fp_digit));
+   fp_clamp(B);
+}
+#endif
+
+
+/* $Source$ */
+/* $Revision$ */
+/* $Date$ */
diff --git a/tomsfastmath/src/sqr/fp_sqr_comba_20.c b/tomsfastmath/src/sqr/fp_sqr_comba_20.c
new file mode 100644 (file)
index 0000000..506f754
--- /dev/null
@@ -0,0 +1,224 @@
+#define TFM_DEFINES
+#include "fp_sqr_comba.c"
+
+#if defined(TFM_SQR20) && FP_SIZE >= 40
+void fp_sqr_comba20(fp_int *A, fp_int *B)
+{
+   fp_digit *a, b[40], c0, c1, c2, sc0, sc1, sc2;
+#ifdef TFM_ISO
+   fp_word tt;
+#endif
+
+   a = A->dp;
+   COMBA_START;
+
+   /* clear carries */
+   CLEAR_CARRY;
+
+   /* output 0 */
+   SQRADD(a[0],a[0]);
+   COMBA_STORE(b[0]);
+
+   /* output 1 */
+   CARRY_FORWARD;
+   SQRADD2(a[0], a[1]);
+   COMBA_STORE(b[1]);
+
+   /* output 2 */
+   CARRY_FORWARD;
+   SQRADD2(a[0], a[2]); SQRADD(a[1], a[1]);
+   COMBA_STORE(b[2]);
+
+   /* output 3 */
+   CARRY_FORWARD;
+   SQRADD2(a[0], a[3]); SQRADD2(a[1], a[2]);
+   COMBA_STORE(b[3]);
+
+   /* output 4 */
+   CARRY_FORWARD;
+   SQRADD2(a[0], a[4]); SQRADD2(a[1], a[3]); SQRADD(a[2], a[2]);
+   COMBA_STORE(b[4]);
+
+   /* output 5 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[5]); SQRADDAC(a[1], a[4]); SQRADDAC(a[2], a[3]); SQRADDDB;
+   COMBA_STORE(b[5]);
+
+   /* output 6 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[6]); SQRADDAC(a[1], a[5]); SQRADDAC(a[2], a[4]); SQRADDDB; SQRADD(a[3], a[3]);
+   COMBA_STORE(b[6]);
+
+   /* output 7 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[7]); SQRADDAC(a[1], a[6]); SQRADDAC(a[2], a[5]); SQRADDAC(a[3], a[4]); SQRADDDB;
+   COMBA_STORE(b[7]);
+
+   /* output 8 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[8]); SQRADDAC(a[1], a[7]); SQRADDAC(a[2], a[6]); SQRADDAC(a[3], a[5]); SQRADDDB; SQRADD(a[4], a[4]);
+   COMBA_STORE(b[8]);
+
+   /* output 9 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[9]); SQRADDAC(a[1], a[8]); SQRADDAC(a[2], a[7]); SQRADDAC(a[3], a[6]); SQRADDAC(a[4], a[5]); SQRADDDB;
+   COMBA_STORE(b[9]);
+
+   /* output 10 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[10]); SQRADDAC(a[1], a[9]); SQRADDAC(a[2], a[8]); SQRADDAC(a[3], a[7]); SQRADDAC(a[4], a[6]); SQRADDDB; SQRADD(a[5], a[5]);
+   COMBA_STORE(b[10]);
+
+   /* output 11 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[11]); SQRADDAC(a[1], a[10]); SQRADDAC(a[2], a[9]); SQRADDAC(a[3], a[8]); SQRADDAC(a[4], a[7]); SQRADDAC(a[5], a[6]); SQRADDDB;
+   COMBA_STORE(b[11]);
+
+   /* output 12 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[12]); SQRADDAC(a[1], a[11]); SQRADDAC(a[2], a[10]); SQRADDAC(a[3], a[9]); SQRADDAC(a[4], a[8]); SQRADDAC(a[5], a[7]); SQRADDDB; SQRADD(a[6], a[6]);
+   COMBA_STORE(b[12]);
+
+   /* output 13 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[13]); SQRADDAC(a[1], a[12]); SQRADDAC(a[2], a[11]); SQRADDAC(a[3], a[10]); SQRADDAC(a[4], a[9]); SQRADDAC(a[5], a[8]); SQRADDAC(a[6], a[7]); SQRADDDB;
+   COMBA_STORE(b[13]);
+
+   /* output 14 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[14]); SQRADDAC(a[1], a[13]); SQRADDAC(a[2], a[12]); SQRADDAC(a[3], a[11]); SQRADDAC(a[4], a[10]); SQRADDAC(a[5], a[9]); SQRADDAC(a[6], a[8]); SQRADDDB; SQRADD(a[7], a[7]);
+   COMBA_STORE(b[14]);
+
+   /* output 15 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[15]); SQRADDAC(a[1], a[14]); SQRADDAC(a[2], a[13]); SQRADDAC(a[3], a[12]); SQRADDAC(a[4], a[11]); SQRADDAC(a[5], a[10]); SQRADDAC(a[6], a[9]); SQRADDAC(a[7], a[8]); SQRADDDB;
+   COMBA_STORE(b[15]);
+
+   /* output 16 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[16]); SQRADDAC(a[1], a[15]); SQRADDAC(a[2], a[14]); SQRADDAC(a[3], a[13]); SQRADDAC(a[4], a[12]); SQRADDAC(a[5], a[11]); SQRADDAC(a[6], a[10]); SQRADDAC(a[7], a[9]); SQRADDDB; SQRADD(a[8], a[8]);
+   COMBA_STORE(b[16]);
+
+   /* output 17 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[17]); SQRADDAC(a[1], a[16]); SQRADDAC(a[2], a[15]); SQRADDAC(a[3], a[14]); SQRADDAC(a[4], a[13]); SQRADDAC(a[5], a[12]); SQRADDAC(a[6], a[11]); SQRADDAC(a[7], a[10]); SQRADDAC(a[8], a[9]); SQRADDDB;
+   COMBA_STORE(b[17]);
+
+   /* output 18 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[18]); SQRADDAC(a[1], a[17]); SQRADDAC(a[2], a[16]); SQRADDAC(a[3], a[15]); SQRADDAC(a[4], a[14]); SQRADDAC(a[5], a[13]); SQRADDAC(a[6], a[12]); SQRADDAC(a[7], a[11]); SQRADDAC(a[8], a[10]); SQRADDDB; SQRADD(a[9], a[9]);
+   COMBA_STORE(b[18]);
+
+   /* output 19 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[19]); SQRADDAC(a[1], a[18]); SQRADDAC(a[2], a[17]); SQRADDAC(a[3], a[16]); SQRADDAC(a[4], a[15]); SQRADDAC(a[5], a[14]); SQRADDAC(a[6], a[13]); SQRADDAC(a[7], a[12]); SQRADDAC(a[8], a[11]); SQRADDAC(a[9], a[10]); SQRADDDB;
+   COMBA_STORE(b[19]);
+
+   /* output 20 */
+   CARRY_FORWARD;
+   SQRADDSC(a[1], a[19]); SQRADDAC(a[2], a[18]); SQRADDAC(a[3], a[17]); SQRADDAC(a[4], a[16]); SQRADDAC(a[5], a[15]); SQRADDAC(a[6], a[14]); SQRADDAC(a[7], a[13]); SQRADDAC(a[8], a[12]); SQRADDAC(a[9], a[11]); SQRADDDB; SQRADD(a[10], a[10]);
+   COMBA_STORE(b[20]);
+
+   /* output 21 */
+   CARRY_FORWARD;
+   SQRADDSC(a[2], a[19]); SQRADDAC(a[3], a[18]); SQRADDAC(a[4], a[17]); SQRADDAC(a[5], a[16]); SQRADDAC(a[6], a[15]); SQRADDAC(a[7], a[14]); SQRADDAC(a[8], a[13]); SQRADDAC(a[9], a[12]); SQRADDAC(a[10], a[11]); SQRADDDB;
+   COMBA_STORE(b[21]);
+
+   /* output 22 */
+   CARRY_FORWARD;
+   SQRADDSC(a[3], a[19]); SQRADDAC(a[4], a[18]); SQRADDAC(a[5], a[17]); SQRADDAC(a[6], a[16]); SQRADDAC(a[7], a[15]); SQRADDAC(a[8], a[14]); SQRADDAC(a[9], a[13]); SQRADDAC(a[10], a[12]); SQRADDDB; SQRADD(a[11], a[11]);
+   COMBA_STORE(b[22]);
+
+   /* output 23 */
+   CARRY_FORWARD;
+   SQRADDSC(a[4], a[19]); SQRADDAC(a[5], a[18]); SQRADDAC(a[6], a[17]); SQRADDAC(a[7], a[16]); SQRADDAC(a[8], a[15]); SQRADDAC(a[9], a[14]); SQRADDAC(a[10], a[13]); SQRADDAC(a[11], a[12]); SQRADDDB;
+   COMBA_STORE(b[23]);
+
+   /* output 24 */
+   CARRY_FORWARD;
+   SQRADDSC(a[5], a[19]); SQRADDAC(a[6], a[18]); SQRADDAC(a[7], a[17]); SQRADDAC(a[8], a[16]); SQRADDAC(a[9], a[15]); SQRADDAC(a[10], a[14]); SQRADDAC(a[11], a[13]); SQRADDDB; SQRADD(a[12], a[12]);
+   COMBA_STORE(b[24]);
+
+   /* output 25 */
+   CARRY_FORWARD;
+   SQRADDSC(a[6], a[19]); SQRADDAC(a[7], a[18]); SQRADDAC(a[8], a[17]); SQRADDAC(a[9], a[16]); SQRADDAC(a[10], a[15]); SQRADDAC(a[11], a[14]); SQRADDAC(a[12], a[13]); SQRADDDB;
+   COMBA_STORE(b[25]);
+
+   /* output 26 */
+   CARRY_FORWARD;
+   SQRADDSC(a[7], a[19]); SQRADDAC(a[8], a[18]); SQRADDAC(a[9], a[17]); SQRADDAC(a[10], a[16]); SQRADDAC(a[11], a[15]); SQRADDAC(a[12], a[14]); SQRADDDB; SQRADD(a[13], a[13]);
+   COMBA_STORE(b[26]);
+
+   /* output 27 */
+   CARRY_FORWARD;
+   SQRADDSC(a[8], a[19]); SQRADDAC(a[9], a[18]); SQRADDAC(a[10], a[17]); SQRADDAC(a[11], a[16]); SQRADDAC(a[12], a[15]); SQRADDAC(a[13], a[14]); SQRADDDB;
+   COMBA_STORE(b[27]);
+
+   /* output 28 */
+   CARRY_FORWARD;
+   SQRADDSC(a[9], a[19]); SQRADDAC(a[10], a[18]); SQRADDAC(a[11], a[17]); SQRADDAC(a[12], a[16]); SQRADDAC(a[13], a[15]); SQRADDDB; SQRADD(a[14], a[14]);
+   COMBA_STORE(b[28]);
+
+   /* output 29 */
+   CARRY_FORWARD;
+   SQRADDSC(a[10], a[19]); SQRADDAC(a[11], a[18]); SQRADDAC(a[12], a[17]); SQRADDAC(a[13], a[16]); SQRADDAC(a[14], a[15]); SQRADDDB;
+   COMBA_STORE(b[29]);
+
+   /* output 30 */
+   CARRY_FORWARD;
+   SQRADDSC(a[11], a[19]); SQRADDAC(a[12], a[18]); SQRADDAC(a[13], a[17]); SQRADDAC(a[14], a[16]); SQRADDDB; SQRADD(a[15], a[15]);
+   COMBA_STORE(b[30]);
+
+   /* output 31 */
+   CARRY_FORWARD;
+   SQRADDSC(a[12], a[19]); SQRADDAC(a[13], a[18]); SQRADDAC(a[14], a[17]); SQRADDAC(a[15], a[16]); SQRADDDB;
+   COMBA_STORE(b[31]);
+
+   /* output 32 */
+   CARRY_FORWARD;
+   SQRADDSC(a[13], a[19]); SQRADDAC(a[14], a[18]); SQRADDAC(a[15], a[17]); SQRADDDB; SQRADD(a[16], a[16]);
+   COMBA_STORE(b[32]);
+
+   /* output 33 */
+   CARRY_FORWARD;
+   SQRADDSC(a[14], a[19]); SQRADDAC(a[15], a[18]); SQRADDAC(a[16], a[17]); SQRADDDB;
+   COMBA_STORE(b[33]);
+
+   /* output 34 */
+   CARRY_FORWARD;
+   SQRADD2(a[15], a[19]); SQRADD2(a[16], a[18]); SQRADD(a[17], a[17]);
+   COMBA_STORE(b[34]);
+
+   /* output 35 */
+   CARRY_FORWARD;
+   SQRADD2(a[16], a[19]); SQRADD2(a[17], a[18]);
+   COMBA_STORE(b[35]);
+
+   /* output 36 */
+   CARRY_FORWARD;
+   SQRADD2(a[17], a[19]); SQRADD(a[18], a[18]);
+   COMBA_STORE(b[36]);
+
+   /* output 37 */
+   CARRY_FORWARD;
+   SQRADD2(a[18], a[19]);
+   COMBA_STORE(b[37]);
+
+   /* output 38 */
+   CARRY_FORWARD;
+   SQRADD(a[19], a[19]);
+   COMBA_STORE(b[38]);
+   COMBA_STORE2(b[39]);
+   COMBA_FINI;
+
+   B->used = 40;
+   B->sign = FP_ZPOS;
+   memcpy(B->dp, b, 40 * sizeof(fp_digit));
+   fp_clamp(B);
+}
+#endif
+
+
+/* $Source$ */
+/* $Revision$ */
+/* $Date$ */
diff --git a/tomsfastmath/src/sqr/fp_sqr_comba_24.c b/tomsfastmath/src/sqr/fp_sqr_comba_24.c
new file mode 100644 (file)
index 0000000..4c9f0f8
--- /dev/null
@@ -0,0 +1,264 @@
+#define TFM_DEFINES
+#include "fp_sqr_comba.c"
+
+#if defined(TFM_SQR24) && FP_SIZE >= 48
+void fp_sqr_comba24(fp_int *A, fp_int *B)
+{
+   fp_digit *a, b[48], c0, c1, c2, sc0, sc1, sc2;
+#ifdef TFM_ISO
+   fp_word tt;
+#endif
+
+   a = A->dp;
+   COMBA_START;
+
+   /* clear carries */
+   CLEAR_CARRY;
+
+   /* output 0 */
+   SQRADD(a[0],a[0]);
+   COMBA_STORE(b[0]);
+
+   /* output 1 */
+   CARRY_FORWARD;
+   SQRADD2(a[0], a[1]);
+   COMBA_STORE(b[1]);
+
+   /* output 2 */
+   CARRY_FORWARD;
+   SQRADD2(a[0], a[2]); SQRADD(a[1], a[1]);
+   COMBA_STORE(b[2]);
+
+   /* output 3 */
+   CARRY_FORWARD;
+   SQRADD2(a[0], a[3]); SQRADD2(a[1], a[2]);
+   COMBA_STORE(b[3]);
+
+   /* output 4 */
+   CARRY_FORWARD;
+   SQRADD2(a[0], a[4]); SQRADD2(a[1], a[3]); SQRADD(a[2], a[2]);
+   COMBA_STORE(b[4]);
+
+   /* output 5 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[5]); SQRADDAC(a[1], a[4]); SQRADDAC(a[2], a[3]); SQRADDDB;
+   COMBA_STORE(b[5]);
+
+   /* output 6 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[6]); SQRADDAC(a[1], a[5]); SQRADDAC(a[2], a[4]); SQRADDDB; SQRADD(a[3], a[3]);
+   COMBA_STORE(b[6]);
+
+   /* output 7 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[7]); SQRADDAC(a[1], a[6]); SQRADDAC(a[2], a[5]); SQRADDAC(a[3], a[4]); SQRADDDB;
+   COMBA_STORE(b[7]);
+
+   /* output 8 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[8]); SQRADDAC(a[1], a[7]); SQRADDAC(a[2], a[6]); SQRADDAC(a[3], a[5]); SQRADDDB; SQRADD(a[4], a[4]);
+   COMBA_STORE(b[8]);
+
+   /* output 9 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[9]); SQRADDAC(a[1], a[8]); SQRADDAC(a[2], a[7]); SQRADDAC(a[3], a[6]); SQRADDAC(a[4], a[5]); SQRADDDB;
+   COMBA_STORE(b[9]);
+
+   /* output 10 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[10]); SQRADDAC(a[1], a[9]); SQRADDAC(a[2], a[8]); SQRADDAC(a[3], a[7]); SQRADDAC(a[4], a[6]); SQRADDDB; SQRADD(a[5], a[5]);
+   COMBA_STORE(b[10]);
+
+   /* output 11 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[11]); SQRADDAC(a[1], a[10]); SQRADDAC(a[2], a[9]); SQRADDAC(a[3], a[8]); SQRADDAC(a[4], a[7]); SQRADDAC(a[5], a[6]); SQRADDDB;
+   COMBA_STORE(b[11]);
+
+   /* output 12 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[12]); SQRADDAC(a[1], a[11]); SQRADDAC(a[2], a[10]); SQRADDAC(a[3], a[9]); SQRADDAC(a[4], a[8]); SQRADDAC(a[5], a[7]); SQRADDDB; SQRADD(a[6], a[6]);
+   COMBA_STORE(b[12]);
+
+   /* output 13 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[13]); SQRADDAC(a[1], a[12]); SQRADDAC(a[2], a[11]); SQRADDAC(a[3], a[10]); SQRADDAC(a[4], a[9]); SQRADDAC(a[5], a[8]); SQRADDAC(a[6], a[7]); SQRADDDB;
+   COMBA_STORE(b[13]);
+
+   /* output 14 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[14]); SQRADDAC(a[1], a[13]); SQRADDAC(a[2], a[12]); SQRADDAC(a[3], a[11]); SQRADDAC(a[4], a[10]); SQRADDAC(a[5], a[9]); SQRADDAC(a[6], a[8]); SQRADDDB; SQRADD(a[7], a[7]);
+   COMBA_STORE(b[14]);
+
+   /* output 15 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[15]); SQRADDAC(a[1], a[14]); SQRADDAC(a[2], a[13]); SQRADDAC(a[3], a[12]); SQRADDAC(a[4], a[11]); SQRADDAC(a[5], a[10]); SQRADDAC(a[6], a[9]); SQRADDAC(a[7], a[8]); SQRADDDB;
+   COMBA_STORE(b[15]);
+
+   /* output 16 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[16]); SQRADDAC(a[1], a[15]); SQRADDAC(a[2], a[14]); SQRADDAC(a[3], a[13]); SQRADDAC(a[4], a[12]); SQRADDAC(a[5], a[11]); SQRADDAC(a[6], a[10]); SQRADDAC(a[7], a[9]); SQRADDDB; SQRADD(a[8], a[8]);
+   COMBA_STORE(b[16]);
+
+   /* output 17 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[17]); SQRADDAC(a[1], a[16]); SQRADDAC(a[2], a[15]); SQRADDAC(a[3], a[14]); SQRADDAC(a[4], a[13]); SQRADDAC(a[5], a[12]); SQRADDAC(a[6], a[11]); SQRADDAC(a[7], a[10]); SQRADDAC(a[8], a[9]); SQRADDDB;
+   COMBA_STORE(b[17]);
+
+   /* output 18 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[18]); SQRADDAC(a[1], a[17]); SQRADDAC(a[2], a[16]); SQRADDAC(a[3], a[15]); SQRADDAC(a[4], a[14]); SQRADDAC(a[5], a[13]); SQRADDAC(a[6], a[12]); SQRADDAC(a[7], a[11]); SQRADDAC(a[8], a[10]); SQRADDDB; SQRADD(a[9], a[9]);
+   COMBA_STORE(b[18]);
+
+   /* output 19 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[19]); SQRADDAC(a[1], a[18]); SQRADDAC(a[2], a[17]); SQRADDAC(a[3], a[16]); SQRADDAC(a[4], a[15]); SQRADDAC(a[5], a[14]); SQRADDAC(a[6], a[13]); SQRADDAC(a[7], a[12]); SQRADDAC(a[8], a[11]); SQRADDAC(a[9], a[10]); SQRADDDB;
+   COMBA_STORE(b[19]);
+
+   /* output 20 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[20]); SQRADDAC(a[1], a[19]); SQRADDAC(a[2], a[18]); SQRADDAC(a[3], a[17]); SQRADDAC(a[4], a[16]); SQRADDAC(a[5], a[15]); SQRADDAC(a[6], a[14]); SQRADDAC(a[7], a[13]); SQRADDAC(a[8], a[12]); SQRADDAC(a[9], a[11]); SQRADDDB; SQRADD(a[10], a[10]);
+   COMBA_STORE(b[20]);
+
+   /* output 21 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[21]); SQRADDAC(a[1], a[20]); SQRADDAC(a[2], a[19]); SQRADDAC(a[3], a[18]); SQRADDAC(a[4], a[17]); SQRADDAC(a[5], a[16]); SQRADDAC(a[6], a[15]); SQRADDAC(a[7], a[14]); SQRADDAC(a[8], a[13]); SQRADDAC(a[9], a[12]); SQRADDAC(a[10], a[11]); SQRADDDB;
+   COMBA_STORE(b[21]);
+
+   /* output 22 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[22]); SQRADDAC(a[1], a[21]); SQRADDAC(a[2], a[20]); SQRADDAC(a[3], a[19]); SQRADDAC(a[4], a[18]); SQRADDAC(a[5], a[17]); SQRADDAC(a[6], a[16]); SQRADDAC(a[7], a[15]); SQRADDAC(a[8], a[14]); SQRADDAC(a[9], a[13]); SQRADDAC(a[10], a[12]); SQRADDDB; SQRADD(a[11], a[11]);
+   COMBA_STORE(b[22]);
+
+   /* output 23 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[23]); SQRADDAC(a[1], a[22]); SQRADDAC(a[2], a[21]); SQRADDAC(a[3], a[20]); SQRADDAC(a[4], a[19]); SQRADDAC(a[5], a[18]); SQRADDAC(a[6], a[17]); SQRADDAC(a[7], a[16]); SQRADDAC(a[8], a[15]); SQRADDAC(a[9], a[14]); SQRADDAC(a[10], a[13]); SQRADDAC(a[11], a[12]); SQRADDDB;
+   COMBA_STORE(b[23]);
+
+   /* output 24 */
+   CARRY_FORWARD;
+   SQRADDSC(a[1], a[23]); SQRADDAC(a[2], a[22]); SQRADDAC(a[3], a[21]); SQRADDAC(a[4], a[20]); SQRADDAC(a[5], a[19]); SQRADDAC(a[6], a[18]); SQRADDAC(a[7], a[17]); SQRADDAC(a[8], a[16]); SQRADDAC(a[9], a[15]); SQRADDAC(a[10], a[14]); SQRADDAC(a[11], a[13]); SQRADDDB; SQRADD(a[12], a[12]);
+   COMBA_STORE(b[24]);
+
+   /* output 25 */
+   CARRY_FORWARD;
+   SQRADDSC(a[2], a[23]); SQRADDAC(a[3], a[22]); SQRADDAC(a[4], a[21]); SQRADDAC(a[5], a[20]); SQRADDAC(a[6], a[19]); SQRADDAC(a[7], a[18]); SQRADDAC(a[8], a[17]); SQRADDAC(a[9], a[16]); SQRADDAC(a[10], a[15]); SQRADDAC(a[11], a[14]); SQRADDAC(a[12], a[13]); SQRADDDB;
+   COMBA_STORE(b[25]);
+
+   /* output 26 */
+   CARRY_FORWARD;
+   SQRADDSC(a[3], a[23]); SQRADDAC(a[4], a[22]); SQRADDAC(a[5], a[21]); SQRADDAC(a[6], a[20]); SQRADDAC(a[7], a[19]); SQRADDAC(a[8], a[18]); SQRADDAC(a[9], a[17]); SQRADDAC(a[10], a[16]); SQRADDAC(a[11], a[15]); SQRADDAC(a[12], a[14]); SQRADDDB; SQRADD(a[13], a[13]);
+   COMBA_STORE(b[26]);
+
+   /* output 27 */
+   CARRY_FORWARD;
+   SQRADDSC(a[4], a[23]); SQRADDAC(a[5], a[22]); SQRADDAC(a[6], a[21]); SQRADDAC(a[7], a[20]); SQRADDAC(a[8], a[19]); SQRADDAC(a[9], a[18]); SQRADDAC(a[10], a[17]); SQRADDAC(a[11], a[16]); SQRADDAC(a[12], a[15]); SQRADDAC(a[13], a[14]); SQRADDDB;
+   COMBA_STORE(b[27]);
+
+   /* output 28 */
+   CARRY_FORWARD;
+   SQRADDSC(a[5], a[23]); SQRADDAC(a[6], a[22]); SQRADDAC(a[7], a[21]); SQRADDAC(a[8], a[20]); SQRADDAC(a[9], a[19]); SQRADDAC(a[10], a[18]); SQRADDAC(a[11], a[17]); SQRADDAC(a[12], a[16]); SQRADDAC(a[13], a[15]); SQRADDDB; SQRADD(a[14], a[14]);
+   COMBA_STORE(b[28]);
+
+   /* output 29 */
+   CARRY_FORWARD;
+   SQRADDSC(a[6], a[23]); SQRADDAC(a[7], a[22]); SQRADDAC(a[8], a[21]); SQRADDAC(a[9], a[20]); SQRADDAC(a[10], a[19]); SQRADDAC(a[11], a[18]); SQRADDAC(a[12], a[17]); SQRADDAC(a[13], a[16]); SQRADDAC(a[14], a[15]); SQRADDDB;
+   COMBA_STORE(b[29]);
+
+   /* output 30 */
+   CARRY_FORWARD;
+   SQRADDSC(a[7], a[23]); SQRADDAC(a[8], a[22]); SQRADDAC(a[9], a[21]); SQRADDAC(a[10], a[20]); SQRADDAC(a[11], a[19]); SQRADDAC(a[12], a[18]); SQRADDAC(a[13], a[17]); SQRADDAC(a[14], a[16]); SQRADDDB; SQRADD(a[15], a[15]);
+   COMBA_STORE(b[30]);
+
+   /* output 31 */
+   CARRY_FORWARD;
+   SQRADDSC(a[8], a[23]); SQRADDAC(a[9], a[22]); SQRADDAC(a[10], a[21]); SQRADDAC(a[11], a[20]); SQRADDAC(a[12], a[19]); SQRADDAC(a[13], a[18]); SQRADDAC(a[14], a[17]); SQRADDAC(a[15], a[16]); SQRADDDB;
+   COMBA_STORE(b[31]);
+
+   /* output 32 */
+   CARRY_FORWARD;
+   SQRADDSC(a[9], a[23]); SQRADDAC(a[10], a[22]); SQRADDAC(a[11], a[21]); SQRADDAC(a[12], a[20]); SQRADDAC(a[13], a[19]); SQRADDAC(a[14], a[18]); SQRADDAC(a[15], a[17]); SQRADDDB; SQRADD(a[16], a[16]);
+   COMBA_STORE(b[32]);
+
+   /* output 33 */
+   CARRY_FORWARD;
+   SQRADDSC(a[10], a[23]); SQRADDAC(a[11], a[22]); SQRADDAC(a[12], a[21]); SQRADDAC(a[13], a[20]); SQRADDAC(a[14], a[19]); SQRADDAC(a[15], a[18]); SQRADDAC(a[16], a[17]); SQRADDDB;
+   COMBA_STORE(b[33]);
+
+   /* output 34 */
+   CARRY_FORWARD;
+   SQRADDSC(a[11], a[23]); SQRADDAC(a[12], a[22]); SQRADDAC(a[13], a[21]); SQRADDAC(a[14], a[20]); SQRADDAC(a[15], a[19]); SQRADDAC(a[16], a[18]); SQRADDDB; SQRADD(a[17], a[17]);
+   COMBA_STORE(b[34]);
+
+   /* output 35 */
+   CARRY_FORWARD;
+   SQRADDSC(a[12], a[23]); SQRADDAC(a[13], a[22]); SQRADDAC(a[14], a[21]); SQRADDAC(a[15], a[20]); SQRADDAC(a[16], a[19]); SQRADDAC(a[17], a[18]); SQRADDDB;
+   COMBA_STORE(b[35]);
+
+   /* output 36 */
+   CARRY_FORWARD;
+   SQRADDSC(a[13], a[23]); SQRADDAC(a[14], a[22]); SQRADDAC(a[15], a[21]); SQRADDAC(a[16], a[20]); SQRADDAC(a[17], a[19]); SQRADDDB; SQRADD(a[18], a[18]);
+   COMBA_STORE(b[36]);
+
+   /* output 37 */
+   CARRY_FORWARD;
+   SQRADDSC(a[14], a[23]); SQRADDAC(a[15], a[22]); SQRADDAC(a[16], a[21]); SQRADDAC(a[17], a[20]); SQRADDAC(a[18], a[19]); SQRADDDB;
+   COMBA_STORE(b[37]);
+
+   /* output 38 */
+   CARRY_FORWARD;
+   SQRADDSC(a[15], a[23]); SQRADDAC(a[16], a[22]); SQRADDAC(a[17], a[21]); SQRADDAC(a[18], a[20]); SQRADDDB; SQRADD(a[19], a[19]);
+   COMBA_STORE(b[38]);
+
+   /* output 39 */
+   CARRY_FORWARD;
+   SQRADDSC(a[16], a[23]); SQRADDAC(a[17], a[22]); SQRADDAC(a[18], a[21]); SQRADDAC(a[19], a[20]); SQRADDDB;
+   COMBA_STORE(b[39]);
+
+   /* output 40 */
+   CARRY_FORWARD;
+   SQRADDSC(a[17], a[23]); SQRADDAC(a[18], a[22]); SQRADDAC(a[19], a[21]); SQRADDDB; SQRADD(a[20], a[20]);
+   COMBA_STORE(b[40]);
+
+   /* output 41 */
+   CARRY_FORWARD;
+   SQRADDSC(a[18], a[23]); SQRADDAC(a[19], a[22]); SQRADDAC(a[20], a[21]); SQRADDDB;
+   COMBA_STORE(b[41]);
+
+   /* output 42 */
+   CARRY_FORWARD;
+   SQRADD2(a[19], a[23]); SQRADD2(a[20], a[22]); SQRADD(a[21], a[21]);
+   COMBA_STORE(b[42]);
+
+   /* output 43 */
+   CARRY_FORWARD;
+   SQRADD2(a[20], a[23]); SQRADD2(a[21], a[22]);
+   COMBA_STORE(b[43]);
+
+   /* output 44 */
+   CARRY_FORWARD;
+   SQRADD2(a[21], a[23]); SQRADD(a[22], a[22]);
+   COMBA_STORE(b[44]);
+
+   /* output 45 */
+   CARRY_FORWARD;
+   SQRADD2(a[22], a[23]);
+   COMBA_STORE(b[45]);
+
+   /* output 46 */
+   CARRY_FORWARD;
+   SQRADD(a[23], a[23]);
+   COMBA_STORE(b[46]);
+   COMBA_STORE2(b[47]);
+   COMBA_FINI;
+
+   B->used = 48;
+   B->sign = FP_ZPOS;
+   memcpy(B->dp, b, 48 * sizeof(fp_digit));
+   fp_clamp(B);
+}
+#endif
+
+
+/* $Source$ */
+/* $Revision$ */
+/* $Date$ */
diff --git a/tomsfastmath/src/sqr/fp_sqr_comba_28.c b/tomsfastmath/src/sqr/fp_sqr_comba_28.c
new file mode 100644 (file)
index 0000000..bd13a0a
--- /dev/null
@@ -0,0 +1,304 @@
+#define TFM_DEFINES
+#include "fp_sqr_comba.c"
+
+#if defined(TFM_SQR28) && FP_SIZE >= 56
+void fp_sqr_comba28(fp_int *A, fp_int *B)
+{
+   fp_digit *a, b[56], c0, c1, c2, sc0, sc1, sc2;
+#ifdef TFM_ISO
+   fp_word tt;
+#endif
+
+   a = A->dp;
+   COMBA_START;
+
+   /* clear carries */
+   CLEAR_CARRY;
+
+   /* output 0 */
+   SQRADD(a[0],a[0]);
+   COMBA_STORE(b[0]);
+
+   /* output 1 */
+   CARRY_FORWARD;
+   SQRADD2(a[0], a[1]);
+   COMBA_STORE(b[1]);
+
+   /* output 2 */
+   CARRY_FORWARD;
+   SQRADD2(a[0], a[2]); SQRADD(a[1], a[1]);
+   COMBA_STORE(b[2]);
+
+   /* output 3 */
+   CARRY_FORWARD;
+   SQRADD2(a[0], a[3]); SQRADD2(a[1], a[2]);
+   COMBA_STORE(b[3]);
+
+   /* output 4 */
+   CARRY_FORWARD;
+   SQRADD2(a[0], a[4]); SQRADD2(a[1], a[3]); SQRADD(a[2], a[2]);
+   COMBA_STORE(b[4]);
+
+   /* output 5 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[5]); SQRADDAC(a[1], a[4]); SQRADDAC(a[2], a[3]); SQRADDDB;
+   COMBA_STORE(b[5]);
+
+   /* output 6 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[6]); SQRADDAC(a[1], a[5]); SQRADDAC(a[2], a[4]); SQRADDDB; SQRADD(a[3], a[3]);
+   COMBA_STORE(b[6]);
+
+   /* output 7 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[7]); SQRADDAC(a[1], a[6]); SQRADDAC(a[2], a[5]); SQRADDAC(a[3], a[4]); SQRADDDB;
+   COMBA_STORE(b[7]);
+
+   /* output 8 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[8]); SQRADDAC(a[1], a[7]); SQRADDAC(a[2], a[6]); SQRADDAC(a[3], a[5]); SQRADDDB; SQRADD(a[4], a[4]);
+   COMBA_STORE(b[8]);
+
+   /* output 9 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[9]); SQRADDAC(a[1], a[8]); SQRADDAC(a[2], a[7]); SQRADDAC(a[3], a[6]); SQRADDAC(a[4], a[5]); SQRADDDB;
+   COMBA_STORE(b[9]);
+
+   /* output 10 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[10]); SQRADDAC(a[1], a[9]); SQRADDAC(a[2], a[8]); SQRADDAC(a[3], a[7]); SQRADDAC(a[4], a[6]); SQRADDDB; SQRADD(a[5], a[5]);
+   COMBA_STORE(b[10]);
+
+   /* output 11 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[11]); SQRADDAC(a[1], a[10]); SQRADDAC(a[2], a[9]); SQRADDAC(a[3], a[8]); SQRADDAC(a[4], a[7]); SQRADDAC(a[5], a[6]); SQRADDDB;
+   COMBA_STORE(b[11]);
+
+   /* output 12 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[12]); SQRADDAC(a[1], a[11]); SQRADDAC(a[2], a[10]); SQRADDAC(a[3], a[9]); SQRADDAC(a[4], a[8]); SQRADDAC(a[5], a[7]); SQRADDDB; SQRADD(a[6], a[6]);
+   COMBA_STORE(b[12]);
+
+   /* output 13 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[13]); SQRADDAC(a[1], a[12]); SQRADDAC(a[2], a[11]); SQRADDAC(a[3], a[10]); SQRADDAC(a[4], a[9]); SQRADDAC(a[5], a[8]); SQRADDAC(a[6], a[7]); SQRADDDB;
+   COMBA_STORE(b[13]);
+
+   /* output 14 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[14]); SQRADDAC(a[1], a[13]); SQRADDAC(a[2], a[12]); SQRADDAC(a[3], a[11]); SQRADDAC(a[4], a[10]); SQRADDAC(a[5], a[9]); SQRADDAC(a[6], a[8]); SQRADDDB; SQRADD(a[7], a[7]);
+   COMBA_STORE(b[14]);
+
+   /* output 15 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[15]); SQRADDAC(a[1], a[14]); SQRADDAC(a[2], a[13]); SQRADDAC(a[3], a[12]); SQRADDAC(a[4], a[11]); SQRADDAC(a[5], a[10]); SQRADDAC(a[6], a[9]); SQRADDAC(a[7], a[8]); SQRADDDB;
+   COMBA_STORE(b[15]);
+
+   /* output 16 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[16]); SQRADDAC(a[1], a[15]); SQRADDAC(a[2], a[14]); SQRADDAC(a[3], a[13]); SQRADDAC(a[4], a[12]); SQRADDAC(a[5], a[11]); SQRADDAC(a[6], a[10]); SQRADDAC(a[7], a[9]); SQRADDDB; SQRADD(a[8], a[8]);
+   COMBA_STORE(b[16]);
+
+   /* output 17 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[17]); SQRADDAC(a[1], a[16]); SQRADDAC(a[2], a[15]); SQRADDAC(a[3], a[14]); SQRADDAC(a[4], a[13]); SQRADDAC(a[5], a[12]); SQRADDAC(a[6], a[11]); SQRADDAC(a[7], a[10]); SQRADDAC(a[8], a[9]); SQRADDDB;
+   COMBA_STORE(b[17]);
+
+   /* output 18 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[18]); SQRADDAC(a[1], a[17]); SQRADDAC(a[2], a[16]); SQRADDAC(a[3], a[15]); SQRADDAC(a[4], a[14]); SQRADDAC(a[5], a[13]); SQRADDAC(a[6], a[12]); SQRADDAC(a[7], a[11]); SQRADDAC(a[8], a[10]); SQRADDDB; SQRADD(a[9], a[9]);
+   COMBA_STORE(b[18]);
+
+   /* output 19 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[19]); SQRADDAC(a[1], a[18]); SQRADDAC(a[2], a[17]); SQRADDAC(a[3], a[16]); SQRADDAC(a[4], a[15]); SQRADDAC(a[5], a[14]); SQRADDAC(a[6], a[13]); SQRADDAC(a[7], a[12]); SQRADDAC(a[8], a[11]); SQRADDAC(a[9], a[10]); SQRADDDB;
+   COMBA_STORE(b[19]);
+
+   /* output 20 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[20]); SQRADDAC(a[1], a[19]); SQRADDAC(a[2], a[18]); SQRADDAC(a[3], a[17]); SQRADDAC(a[4], a[16]); SQRADDAC(a[5], a[15]); SQRADDAC(a[6], a[14]); SQRADDAC(a[7], a[13]); SQRADDAC(a[8], a[12]); SQRADDAC(a[9], a[11]); SQRADDDB; SQRADD(a[10], a[10]);
+   COMBA_STORE(b[20]);
+
+   /* output 21 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[21]); SQRADDAC(a[1], a[20]); SQRADDAC(a[2], a[19]); SQRADDAC(a[3], a[18]); SQRADDAC(a[4], a[17]); SQRADDAC(a[5], a[16]); SQRADDAC(a[6], a[15]); SQRADDAC(a[7], a[14]); SQRADDAC(a[8], a[13]); SQRADDAC(a[9], a[12]); SQRADDAC(a[10], a[11]); SQRADDDB;
+   COMBA_STORE(b[21]);
+
+   /* output 22 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[22]); SQRADDAC(a[1], a[21]); SQRADDAC(a[2], a[20]); SQRADDAC(a[3], a[19]); SQRADDAC(a[4], a[18]); SQRADDAC(a[5], a[17]); SQRADDAC(a[6], a[16]); SQRADDAC(a[7], a[15]); SQRADDAC(a[8], a[14]); SQRADDAC(a[9], a[13]); SQRADDAC(a[10], a[12]); SQRADDDB; SQRADD(a[11], a[11]);
+   COMBA_STORE(b[22]);
+
+   /* output 23 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[23]); SQRADDAC(a[1], a[22]); SQRADDAC(a[2], a[21]); SQRADDAC(a[3], a[20]); SQRADDAC(a[4], a[19]); SQRADDAC(a[5], a[18]); SQRADDAC(a[6], a[17]); SQRADDAC(a[7], a[16]); SQRADDAC(a[8], a[15]); SQRADDAC(a[9], a[14]); SQRADDAC(a[10], a[13]); SQRADDAC(a[11], a[12]); SQRADDDB;
+   COMBA_STORE(b[23]);
+
+   /* output 24 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[24]); SQRADDAC(a[1], a[23]); SQRADDAC(a[2], a[22]); SQRADDAC(a[3], a[21]); SQRADDAC(a[4], a[20]); SQRADDAC(a[5], a[19]); SQRADDAC(a[6], a[18]); SQRADDAC(a[7], a[17]); SQRADDAC(a[8], a[16]); SQRADDAC(a[9], a[15]); SQRADDAC(a[10], a[14]); SQRADDAC(a[11], a[13]); SQRADDDB; SQRADD(a[12], a[12]);
+   COMBA_STORE(b[24]);
+
+   /* output 25 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[25]); SQRADDAC(a[1], a[24]); SQRADDAC(a[2], a[23]); SQRADDAC(a[3], a[22]); SQRADDAC(a[4], a[21]); SQRADDAC(a[5], a[20]); SQRADDAC(a[6], a[19]); SQRADDAC(a[7], a[18]); SQRADDAC(a[8], a[17]); SQRADDAC(a[9], a[16]); SQRADDAC(a[10], a[15]); SQRADDAC(a[11], a[14]); SQRADDAC(a[12], a[13]); SQRADDDB;
+   COMBA_STORE(b[25]);
+
+   /* output 26 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[26]); SQRADDAC(a[1], a[25]); SQRADDAC(a[2], a[24]); SQRADDAC(a[3], a[23]); SQRADDAC(a[4], a[22]); SQRADDAC(a[5], a[21]); SQRADDAC(a[6], a[20]); SQRADDAC(a[7], a[19]); SQRADDAC(a[8], a[18]); SQRADDAC(a[9], a[17]); SQRADDAC(a[10], a[16]); SQRADDAC(a[11], a[15]); SQRADDAC(a[12], a[14]); SQRADDDB; SQRADD(a[13], a[13]);
+   COMBA_STORE(b[26]);
+
+   /* output 27 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[27]); SQRADDAC(a[1], a[26]); SQRADDAC(a[2], a[25]); SQRADDAC(a[3], a[24]); SQRADDAC(a[4], a[23]); SQRADDAC(a[5], a[22]); SQRADDAC(a[6], a[21]); SQRADDAC(a[7], a[20]); SQRADDAC(a[8], a[19]); SQRADDAC(a[9], a[18]); SQRADDAC(a[10], a[17]); SQRADDAC(a[11], a[16]); SQRADDAC(a[12], a[15]); SQRADDAC(a[13], a[14]); SQRADDDB;
+   COMBA_STORE(b[27]);
+
+   /* output 28 */
+   CARRY_FORWARD;
+   SQRADDSC(a[1], a[27]); SQRADDAC(a[2], a[26]); SQRADDAC(a[3], a[25]); SQRADDAC(a[4], a[24]); SQRADDAC(a[5], a[23]); SQRADDAC(a[6], a[22]); SQRADDAC(a[7], a[21]); SQRADDAC(a[8], a[20]); SQRADDAC(a[9], a[19]); SQRADDAC(a[10], a[18]); SQRADDAC(a[11], a[17]); SQRADDAC(a[12], a[16]); SQRADDAC(a[13], a[15]); SQRADDDB; SQRADD(a[14], a[14]);
+   COMBA_STORE(b[28]);
+
+   /* output 29 */
+   CARRY_FORWARD;
+   SQRADDSC(a[2], a[27]); SQRADDAC(a[3], a[26]); SQRADDAC(a[4], a[25]); SQRADDAC(a[5], a[24]); SQRADDAC(a[6], a[23]); SQRADDAC(a[7], a[22]); SQRADDAC(a[8], a[21]); SQRADDAC(a[9], a[20]); SQRADDAC(a[10], a[19]); SQRADDAC(a[11], a[18]); SQRADDAC(a[12], a[17]); SQRADDAC(a[13], a[16]); SQRADDAC(a[14], a[15]); SQRADDDB;
+   COMBA_STORE(b[29]);
+
+   /* output 30 */
+   CARRY_FORWARD;
+   SQRADDSC(a[3], a[27]); SQRADDAC(a[4], a[26]); SQRADDAC(a[5], a[25]); SQRADDAC(a[6], a[24]); SQRADDAC(a[7], a[23]); SQRADDAC(a[8], a[22]); SQRADDAC(a[9], a[21]); SQRADDAC(a[10], a[20]); SQRADDAC(a[11], a[19]); SQRADDAC(a[12], a[18]); SQRADDAC(a[13], a[17]); SQRADDAC(a[14], a[16]); SQRADDDB; SQRADD(a[15], a[15]);
+   COMBA_STORE(b[30]);
+
+   /* output 31 */
+   CARRY_FORWARD;
+   SQRADDSC(a[4], a[27]); SQRADDAC(a[5], a[26]); SQRADDAC(a[6], a[25]); SQRADDAC(a[7], a[24]); SQRADDAC(a[8], a[23]); SQRADDAC(a[9], a[22]); SQRADDAC(a[10], a[21]); SQRADDAC(a[11], a[20]); SQRADDAC(a[12], a[19]); SQRADDAC(a[13], a[18]); SQRADDAC(a[14], a[17]); SQRADDAC(a[15], a[16]); SQRADDDB;
+   COMBA_STORE(b[31]);
+
+   /* output 32 */
+   CARRY_FORWARD;
+   SQRADDSC(a[5], a[27]); SQRADDAC(a[6], a[26]); SQRADDAC(a[7], a[25]); SQRADDAC(a[8], a[24]); SQRADDAC(a[9], a[23]); SQRADDAC(a[10], a[22]); SQRADDAC(a[11], a[21]); SQRADDAC(a[12], a[20]); SQRADDAC(a[13], a[19]); SQRADDAC(a[14], a[18]); SQRADDAC(a[15], a[17]); SQRADDDB; SQRADD(a[16], a[16]);
+   COMBA_STORE(b[32]);
+
+   /* output 33 */
+   CARRY_FORWARD;
+   SQRADDSC(a[6], a[27]); SQRADDAC(a[7], a[26]); SQRADDAC(a[8], a[25]); SQRADDAC(a[9], a[24]); SQRADDAC(a[10], a[23]); SQRADDAC(a[11], a[22]); SQRADDAC(a[12], a[21]); SQRADDAC(a[13], a[20]); SQRADDAC(a[14], a[19]); SQRADDAC(a[15], a[18]); SQRADDAC(a[16], a[17]); SQRADDDB;
+   COMBA_STORE(b[33]);
+
+   /* output 34 */
+   CARRY_FORWARD;
+   SQRADDSC(a[7], a[27]); SQRADDAC(a[8], a[26]); SQRADDAC(a[9], a[25]); SQRADDAC(a[10], a[24]); SQRADDAC(a[11], a[23]); SQRADDAC(a[12], a[22]); SQRADDAC(a[13], a[21]); SQRADDAC(a[14], a[20]); SQRADDAC(a[15], a[19]); SQRADDAC(a[16], a[18]); SQRADDDB; SQRADD(a[17], a[17]);
+   COMBA_STORE(b[34]);
+
+   /* output 35 */
+   CARRY_FORWARD;
+   SQRADDSC(a[8], a[27]); SQRADDAC(a[9], a[26]); SQRADDAC(a[10], a[25]); SQRADDAC(a[11], a[24]); SQRADDAC(a[12], a[23]); SQRADDAC(a[13], a[22]); SQRADDAC(a[14], a[21]); SQRADDAC(a[15], a[20]); SQRADDAC(a[16], a[19]); SQRADDAC(a[17], a[18]); SQRADDDB;
+   COMBA_STORE(b[35]);
+
+   /* output 36 */
+   CARRY_FORWARD;
+   SQRADDSC(a[9], a[27]); SQRADDAC(a[10], a[26]); SQRADDAC(a[11], a[25]); SQRADDAC(a[12], a[24]); SQRADDAC(a[13], a[23]); SQRADDAC(a[14], a[22]); SQRADDAC(a[15], a[21]); SQRADDAC(a[16], a[20]); SQRADDAC(a[17], a[19]); SQRADDDB; SQRADD(a[18], a[18]);
+   COMBA_STORE(b[36]);
+
+   /* output 37 */
+   CARRY_FORWARD;
+   SQRADDSC(a[10], a[27]); SQRADDAC(a[11], a[26]); SQRADDAC(a[12], a[25]); SQRADDAC(a[13], a[24]); SQRADDAC(a[14], a[23]); SQRADDAC(a[15], a[22]); SQRADDAC(a[16], a[21]); SQRADDAC(a[17], a[20]); SQRADDAC(a[18], a[19]); SQRADDDB;
+   COMBA_STORE(b[37]);
+
+   /* output 38 */
+   CARRY_FORWARD;
+   SQRADDSC(a[11], a[27]); SQRADDAC(a[12], a[26]); SQRADDAC(a[13], a[25]); SQRADDAC(a[14], a[24]); SQRADDAC(a[15], a[23]); SQRADDAC(a[16], a[22]); SQRADDAC(a[17], a[21]); SQRADDAC(a[18], a[20]); SQRADDDB; SQRADD(a[19], a[19]);
+   COMBA_STORE(b[38]);
+
+   /* output 39 */
+   CARRY_FORWARD;
+   SQRADDSC(a[12], a[27]); SQRADDAC(a[13], a[26]); SQRADDAC(a[14], a[25]); SQRADDAC(a[15], a[24]); SQRADDAC(a[16], a[23]); SQRADDAC(a[17], a[22]); SQRADDAC(a[18], a[21]); SQRADDAC(a[19], a[20]); SQRADDDB;
+   COMBA_STORE(b[39]);
+
+   /* output 40 */
+   CARRY_FORWARD;
+   SQRADDSC(a[13], a[27]); SQRADDAC(a[14], a[26]); SQRADDAC(a[15], a[25]); SQRADDAC(a[16], a[24]); SQRADDAC(a[17], a[23]); SQRADDAC(a[18], a[22]); SQRADDAC(a[19], a[21]); SQRADDDB; SQRADD(a[20], a[20]);
+   COMBA_STORE(b[40]);
+
+   /* output 41 */
+   CARRY_FORWARD;
+   SQRADDSC(a[14], a[27]); SQRADDAC(a[15], a[26]); SQRADDAC(a[16], a[25]); SQRADDAC(a[17], a[24]); SQRADDAC(a[18], a[23]); SQRADDAC(a[19], a[22]); SQRADDAC(a[20], a[21]); SQRADDDB;
+   COMBA_STORE(b[41]);
+
+   /* output 42 */
+   CARRY_FORWARD;
+   SQRADDSC(a[15], a[27]); SQRADDAC(a[16], a[26]); SQRADDAC(a[17], a[25]); SQRADDAC(a[18], a[24]); SQRADDAC(a[19], a[23]); SQRADDAC(a[20], a[22]); SQRADDDB; SQRADD(a[21], a[21]);
+   COMBA_STORE(b[42]);
+
+   /* output 43 */
+   CARRY_FORWARD;
+   SQRADDSC(a[16], a[27]); SQRADDAC(a[17], a[26]); SQRADDAC(a[18], a[25]); SQRADDAC(a[19], a[24]); SQRADDAC(a[20], a[23]); SQRADDAC(a[21], a[22]); SQRADDDB;
+   COMBA_STORE(b[43]);
+
+   /* output 44 */
+   CARRY_FORWARD;
+   SQRADDSC(a[17], a[27]); SQRADDAC(a[18], a[26]); SQRADDAC(a[19], a[25]); SQRADDAC(a[20], a[24]); SQRADDAC(a[21], a[23]); SQRADDDB; SQRADD(a[22], a[22]);
+   COMBA_STORE(b[44]);
+
+   /* output 45 */
+   CARRY_FORWARD;
+   SQRADDSC(a[18], a[27]); SQRADDAC(a[19], a[26]); SQRADDAC(a[20], a[25]); SQRADDAC(a[21], a[24]); SQRADDAC(a[22], a[23]); SQRADDDB;
+   COMBA_STORE(b[45]);
+
+   /* output 46 */
+   CARRY_FORWARD;
+   SQRADDSC(a[19], a[27]); SQRADDAC(a[20], a[26]); SQRADDAC(a[21], a[25]); SQRADDAC(a[22], a[24]); SQRADDDB; SQRADD(a[23], a[23]);
+   COMBA_STORE(b[46]);
+
+   /* output 47 */
+   CARRY_FORWARD;
+   SQRADDSC(a[20], a[27]); SQRADDAC(a[21], a[26]); SQRADDAC(a[22], a[25]); SQRADDAC(a[23], a[24]); SQRADDDB;
+   COMBA_STORE(b[47]);
+
+   /* output 48 */
+   CARRY_FORWARD;
+   SQRADDSC(a[21], a[27]); SQRADDAC(a[22], a[26]); SQRADDAC(a[23], a[25]); SQRADDDB; SQRADD(a[24], a[24]);
+   COMBA_STORE(b[48]);
+
+   /* output 49 */
+   CARRY_FORWARD;
+   SQRADDSC(a[22], a[27]); SQRADDAC(a[23], a[26]); SQRADDAC(a[24], a[25]); SQRADDDB;
+   COMBA_STORE(b[49]);
+
+   /* output 50 */
+   CARRY_FORWARD;
+   SQRADD2(a[23], a[27]); SQRADD2(a[24], a[26]); SQRADD(a[25], a[25]);
+   COMBA_STORE(b[50]);
+
+   /* output 51 */
+   CARRY_FORWARD;
+   SQRADD2(a[24], a[27]); SQRADD2(a[25], a[26]);
+   COMBA_STORE(b[51]);
+
+   /* output 52 */
+   CARRY_FORWARD;
+   SQRADD2(a[25], a[27]); SQRADD(a[26], a[26]);
+   COMBA_STORE(b[52]);
+
+   /* output 53 */
+   CARRY_FORWARD;
+   SQRADD2(a[26], a[27]);
+   COMBA_STORE(b[53]);
+
+   /* output 54 */
+   CARRY_FORWARD;
+   SQRADD(a[27], a[27]);
+   COMBA_STORE(b[54]);
+   COMBA_STORE2(b[55]);
+   COMBA_FINI;
+
+   B->used = 56;
+   B->sign = FP_ZPOS;
+   memcpy(B->dp, b, 56 * sizeof(fp_digit));
+   fp_clamp(B);
+}
+#endif
+
+
+/* $Source$ */
+/* $Revision$ */
+/* $Date$ */
diff --git a/tomsfastmath/src/sqr/fp_sqr_comba_3.c b/tomsfastmath/src/sqr/fp_sqr_comba_3.c
new file mode 100644 (file)
index 0000000..ea0c272
--- /dev/null
@@ -0,0 +1,54 @@
+#define TFM_DEFINES
+#include "fp_sqr_comba.c"
+
+#if defined(TFM_SQR3) && FP_SIZE >= 6
+void fp_sqr_comba3(fp_int *A, fp_int *B)
+{
+   fp_digit *a, b[6], c0, c1, c2, sc0, sc1, sc2;
+#ifdef TFM_ISO
+   fp_word tt;
+#endif
+
+   a = A->dp;
+   COMBA_START;
+
+   /* clear carries */
+   CLEAR_CARRY;
+
+   /* output 0 */
+   SQRADD(a[0],a[0]);
+   COMBA_STORE(b[0]);
+
+   /* output 1 */
+   CARRY_FORWARD;
+   SQRADD2(a[0], a[1]);
+   COMBA_STORE(b[1]);
+
+   /* output 2 */
+   CARRY_FORWARD;
+   SQRADD2(a[0], a[2]); SQRADD(a[1], a[1]);
+   COMBA_STORE(b[2]);
+
+   /* output 3 */
+   CARRY_FORWARD;
+   SQRADD2(a[1], a[2]);
+   COMBA_STORE(b[3]);
+
+   /* output 4 */
+   CARRY_FORWARD;
+   SQRADD(a[2], a[2]);
+   COMBA_STORE(b[4]);
+   COMBA_STORE2(b[5]);
+   COMBA_FINI;
+
+   B->used = 6;
+   B->sign = FP_ZPOS;
+   memcpy(B->dp, b, 6 * sizeof(fp_digit));
+   fp_clamp(B);
+}
+#endif
+
+
+/* $Source$ */
+/* $Revision$ */
+/* $Date$ */
diff --git a/tomsfastmath/src/sqr/fp_sqr_comba_32.c b/tomsfastmath/src/sqr/fp_sqr_comba_32.c
new file mode 100644 (file)
index 0000000..5ce343d
--- /dev/null
@@ -0,0 +1,344 @@
+#define TFM_DEFINES
+#include "fp_sqr_comba.c"
+
+#if defined(TFM_SQR32) && FP_SIZE >= 64
+void fp_sqr_comba32(fp_int *A, fp_int *B)
+{
+   fp_digit *a, b[64], c0, c1, c2, sc0, sc1, sc2;
+#ifdef TFM_ISO
+   fp_word tt;
+#endif
+
+   a = A->dp;
+   COMBA_START;
+
+   /* clear carries */
+   CLEAR_CARRY;
+
+   /* output 0 */
+   SQRADD(a[0],a[0]);
+   COMBA_STORE(b[0]);
+
+   /* output 1 */
+   CARRY_FORWARD;
+   SQRADD2(a[0], a[1]);
+   COMBA_STORE(b[1]);
+
+   /* output 2 */
+   CARRY_FORWARD;
+   SQRADD2(a[0], a[2]); SQRADD(a[1], a[1]);
+   COMBA_STORE(b[2]);
+
+   /* output 3 */
+   CARRY_FORWARD;
+   SQRADD2(a[0], a[3]); SQRADD2(a[1], a[2]);
+   COMBA_STORE(b[3]);
+
+   /* output 4 */
+   CARRY_FORWARD;
+   SQRADD2(a[0], a[4]); SQRADD2(a[1], a[3]); SQRADD(a[2], a[2]);
+   COMBA_STORE(b[4]);
+
+   /* output 5 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[5]); SQRADDAC(a[1], a[4]); SQRADDAC(a[2], a[3]); SQRADDDB;
+   COMBA_STORE(b[5]);
+
+   /* output 6 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[6]); SQRADDAC(a[1], a[5]); SQRADDAC(a[2], a[4]); SQRADDDB; SQRADD(a[3], a[3]);
+   COMBA_STORE(b[6]);
+
+   /* output 7 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[7]); SQRADDAC(a[1], a[6]); SQRADDAC(a[2], a[5]); SQRADDAC(a[3], a[4]); SQRADDDB;
+   COMBA_STORE(b[7]);
+
+   /* output 8 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[8]); SQRADDAC(a[1], a[7]); SQRADDAC(a[2], a[6]); SQRADDAC(a[3], a[5]); SQRADDDB; SQRADD(a[4], a[4]);
+   COMBA_STORE(b[8]);
+
+   /* output 9 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[9]); SQRADDAC(a[1], a[8]); SQRADDAC(a[2], a[7]); SQRADDAC(a[3], a[6]); SQRADDAC(a[4], a[5]); SQRADDDB;
+   COMBA_STORE(b[9]);
+
+   /* output 10 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[10]); SQRADDAC(a[1], a[9]); SQRADDAC(a[2], a[8]); SQRADDAC(a[3], a[7]); SQRADDAC(a[4], a[6]); SQRADDDB; SQRADD(a[5], a[5]);
+   COMBA_STORE(b[10]);
+
+   /* output 11 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[11]); SQRADDAC(a[1], a[10]); SQRADDAC(a[2], a[9]); SQRADDAC(a[3], a[8]); SQRADDAC(a[4], a[7]); SQRADDAC(a[5], a[6]); SQRADDDB;
+   COMBA_STORE(b[11]);
+
+   /* output 12 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[12]); SQRADDAC(a[1], a[11]); SQRADDAC(a[2], a[10]); SQRADDAC(a[3], a[9]); SQRADDAC(a[4], a[8]); SQRADDAC(a[5], a[7]); SQRADDDB; SQRADD(a[6], a[6]);
+   COMBA_STORE(b[12]);
+
+   /* output 13 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[13]); SQRADDAC(a[1], a[12]); SQRADDAC(a[2], a[11]); SQRADDAC(a[3], a[10]); SQRADDAC(a[4], a[9]); SQRADDAC(a[5], a[8]); SQRADDAC(a[6], a[7]); SQRADDDB;
+   COMBA_STORE(b[13]);
+
+   /* output 14 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[14]); SQRADDAC(a[1], a[13]); SQRADDAC(a[2], a[12]); SQRADDAC(a[3], a[11]); SQRADDAC(a[4], a[10]); SQRADDAC(a[5], a[9]); SQRADDAC(a[6], a[8]); SQRADDDB; SQRADD(a[7], a[7]);
+   COMBA_STORE(b[14]);
+
+   /* output 15 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[15]); SQRADDAC(a[1], a[14]); SQRADDAC(a[2], a[13]); SQRADDAC(a[3], a[12]); SQRADDAC(a[4], a[11]); SQRADDAC(a[5], a[10]); SQRADDAC(a[6], a[9]); SQRADDAC(a[7], a[8]); SQRADDDB;
+   COMBA_STORE(b[15]);
+
+   /* output 16 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[16]); SQRADDAC(a[1], a[15]); SQRADDAC(a[2], a[14]); SQRADDAC(a[3], a[13]); SQRADDAC(a[4], a[12]); SQRADDAC(a[5], a[11]); SQRADDAC(a[6], a[10]); SQRADDAC(a[7], a[9]); SQRADDDB; SQRADD(a[8], a[8]);
+   COMBA_STORE(b[16]);
+
+   /* output 17 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[17]); SQRADDAC(a[1], a[16]); SQRADDAC(a[2], a[15]); SQRADDAC(a[3], a[14]); SQRADDAC(a[4], a[13]); SQRADDAC(a[5], a[12]); SQRADDAC(a[6], a[11]); SQRADDAC(a[7], a[10]); SQRADDAC(a[8], a[9]); SQRADDDB;
+   COMBA_STORE(b[17]);
+
+   /* output 18 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[18]); SQRADDAC(a[1], a[17]); SQRADDAC(a[2], a[16]); SQRADDAC(a[3], a[15]); SQRADDAC(a[4], a[14]); SQRADDAC(a[5], a[13]); SQRADDAC(a[6], a[12]); SQRADDAC(a[7], a[11]); SQRADDAC(a[8], a[10]); SQRADDDB; SQRADD(a[9], a[9]);
+   COMBA_STORE(b[18]);
+
+   /* output 19 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[19]); SQRADDAC(a[1], a[18]); SQRADDAC(a[2], a[17]); SQRADDAC(a[3], a[16]); SQRADDAC(a[4], a[15]); SQRADDAC(a[5], a[14]); SQRADDAC(a[6], a[13]); SQRADDAC(a[7], a[12]); SQRADDAC(a[8], a[11]); SQRADDAC(a[9], a[10]); SQRADDDB;
+   COMBA_STORE(b[19]);
+
+   /* output 20 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[20]); SQRADDAC(a[1], a[19]); SQRADDAC(a[2], a[18]); SQRADDAC(a[3], a[17]); SQRADDAC(a[4], a[16]); SQRADDAC(a[5], a[15]); SQRADDAC(a[6], a[14]); SQRADDAC(a[7], a[13]); SQRADDAC(a[8], a[12]); SQRADDAC(a[9], a[11]); SQRADDDB; SQRADD(a[10], a[10]);
+   COMBA_STORE(b[20]);
+
+   /* output 21 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[21]); SQRADDAC(a[1], a[20]); SQRADDAC(a[2], a[19]); SQRADDAC(a[3], a[18]); SQRADDAC(a[4], a[17]); SQRADDAC(a[5], a[16]); SQRADDAC(a[6], a[15]); SQRADDAC(a[7], a[14]); SQRADDAC(a[8], a[13]); SQRADDAC(a[9], a[12]); SQRADDAC(a[10], a[11]); SQRADDDB;
+   COMBA_STORE(b[21]);
+
+   /* output 22 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[22]); SQRADDAC(a[1], a[21]); SQRADDAC(a[2], a[20]); SQRADDAC(a[3], a[19]); SQRADDAC(a[4], a[18]); SQRADDAC(a[5], a[17]); SQRADDAC(a[6], a[16]); SQRADDAC(a[7], a[15]); SQRADDAC(a[8], a[14]); SQRADDAC(a[9], a[13]); SQRADDAC(a[10], a[12]); SQRADDDB; SQRADD(a[11], a[11]);
+   COMBA_STORE(b[22]);
+
+   /* output 23 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[23]); SQRADDAC(a[1], a[22]); SQRADDAC(a[2], a[21]); SQRADDAC(a[3], a[20]); SQRADDAC(a[4], a[19]); SQRADDAC(a[5], a[18]); SQRADDAC(a[6], a[17]); SQRADDAC(a[7], a[16]); SQRADDAC(a[8], a[15]); SQRADDAC(a[9], a[14]); SQRADDAC(a[10], a[13]); SQRADDAC(a[11], a[12]); SQRADDDB;
+   COMBA_STORE(b[23]);
+
+   /* output 24 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[24]); SQRADDAC(a[1], a[23]); SQRADDAC(a[2], a[22]); SQRADDAC(a[3], a[21]); SQRADDAC(a[4], a[20]); SQRADDAC(a[5], a[19]); SQRADDAC(a[6], a[18]); SQRADDAC(a[7], a[17]); SQRADDAC(a[8], a[16]); SQRADDAC(a[9], a[15]); SQRADDAC(a[10], a[14]); SQRADDAC(a[11], a[13]); SQRADDDB; SQRADD(a[12], a[12]);
+   COMBA_STORE(b[24]);
+
+   /* output 25 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[25]); SQRADDAC(a[1], a[24]); SQRADDAC(a[2], a[23]); SQRADDAC(a[3], a[22]); SQRADDAC(a[4], a[21]); SQRADDAC(a[5], a[20]); SQRADDAC(a[6], a[19]); SQRADDAC(a[7], a[18]); SQRADDAC(a[8], a[17]); SQRADDAC(a[9], a[16]); SQRADDAC(a[10], a[15]); SQRADDAC(a[11], a[14]); SQRADDAC(a[12], a[13]); SQRADDDB;
+   COMBA_STORE(b[25]);
+
+   /* output 26 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[26]); SQRADDAC(a[1], a[25]); SQRADDAC(a[2], a[24]); SQRADDAC(a[3], a[23]); SQRADDAC(a[4], a[22]); SQRADDAC(a[5], a[21]); SQRADDAC(a[6], a[20]); SQRADDAC(a[7], a[19]); SQRADDAC(a[8], a[18]); SQRADDAC(a[9], a[17]); SQRADDAC(a[10], a[16]); SQRADDAC(a[11], a[15]); SQRADDAC(a[12], a[14]); SQRADDDB; SQRADD(a[13], a[13]);
+   COMBA_STORE(b[26]);
+
+   /* output 27 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[27]); SQRADDAC(a[1], a[26]); SQRADDAC(a[2], a[25]); SQRADDAC(a[3], a[24]); SQRADDAC(a[4], a[23]); SQRADDAC(a[5], a[22]); SQRADDAC(a[6], a[21]); SQRADDAC(a[7], a[20]); SQRADDAC(a[8], a[19]); SQRADDAC(a[9], a[18]); SQRADDAC(a[10], a[17]); SQRADDAC(a[11], a[16]); SQRADDAC(a[12], a[15]); SQRADDAC(a[13], a[14]); SQRADDDB;
+   COMBA_STORE(b[27]);
+
+   /* output 28 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[28]); SQRADDAC(a[1], a[27]); SQRADDAC(a[2], a[26]); SQRADDAC(a[3], a[25]); SQRADDAC(a[4], a[24]); SQRADDAC(a[5], a[23]); SQRADDAC(a[6], a[22]); SQRADDAC(a[7], a[21]); SQRADDAC(a[8], a[20]); SQRADDAC(a[9], a[19]); SQRADDAC(a[10], a[18]); SQRADDAC(a[11], a[17]); SQRADDAC(a[12], a[16]); SQRADDAC(a[13], a[15]); SQRADDDB; SQRADD(a[14], a[14]);
+   COMBA_STORE(b[28]);
+
+   /* output 29 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[29]); SQRADDAC(a[1], a[28]); SQRADDAC(a[2], a[27]); SQRADDAC(a[3], a[26]); SQRADDAC(a[4], a[25]); SQRADDAC(a[5], a[24]); SQRADDAC(a[6], a[23]); SQRADDAC(a[7], a[22]); SQRADDAC(a[8], a[21]); SQRADDAC(a[9], a[20]); SQRADDAC(a[10], a[19]); SQRADDAC(a[11], a[18]); SQRADDAC(a[12], a[17]); SQRADDAC(a[13], a[16]); SQRADDAC(a[14], a[15]); SQRADDDB;
+   COMBA_STORE(b[29]);
+
+   /* output 30 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[30]); SQRADDAC(a[1], a[29]); SQRADDAC(a[2], a[28]); SQRADDAC(a[3], a[27]); SQRADDAC(a[4], a[26]); SQRADDAC(a[5], a[25]); SQRADDAC(a[6], a[24]); SQRADDAC(a[7], a[23]); SQRADDAC(a[8], a[22]); SQRADDAC(a[9], a[21]); SQRADDAC(a[10], a[20]); SQRADDAC(a[11], a[19]); SQRADDAC(a[12], a[18]); SQRADDAC(a[13], a[17]); SQRADDAC(a[14], a[16]); SQRADDDB; SQRADD(a[15], a[15]);
+   COMBA_STORE(b[30]);
+
+   /* output 31 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[31]); SQRADDAC(a[1], a[30]); SQRADDAC(a[2], a[29]); SQRADDAC(a[3], a[28]); SQRADDAC(a[4], a[27]); SQRADDAC(a[5], a[26]); SQRADDAC(a[6], a[25]); SQRADDAC(a[7], a[24]); SQRADDAC(a[8], a[23]); SQRADDAC(a[9], a[22]); SQRADDAC(a[10], a[21]); SQRADDAC(a[11], a[20]); SQRADDAC(a[12], a[19]); SQRADDAC(a[13], a[18]); SQRADDAC(a[14], a[17]); SQRADDAC(a[15], a[16]); SQRADDDB;
+   COMBA_STORE(b[31]);
+
+   /* output 32 */
+   CARRY_FORWARD;
+   SQRADDSC(a[1], a[31]); SQRADDAC(a[2], a[30]); SQRADDAC(a[3], a[29]); SQRADDAC(a[4], a[28]); SQRADDAC(a[5], a[27]); SQRADDAC(a[6], a[26]); SQRADDAC(a[7], a[25]); SQRADDAC(a[8], a[24]); SQRADDAC(a[9], a[23]); SQRADDAC(a[10], a[22]); SQRADDAC(a[11], a[21]); SQRADDAC(a[12], a[20]); SQRADDAC(a[13], a[19]); SQRADDAC(a[14], a[18]); SQRADDAC(a[15], a[17]); SQRADDDB; SQRADD(a[16], a[16]);
+   COMBA_STORE(b[32]);
+
+   /* output 33 */
+   CARRY_FORWARD;
+   SQRADDSC(a[2], a[31]); SQRADDAC(a[3], a[30]); SQRADDAC(a[4], a[29]); SQRADDAC(a[5], a[28]); SQRADDAC(a[6], a[27]); SQRADDAC(a[7], a[26]); SQRADDAC(a[8], a[25]); SQRADDAC(a[9], a[24]); SQRADDAC(a[10], a[23]); SQRADDAC(a[11], a[22]); SQRADDAC(a[12], a[21]); SQRADDAC(a[13], a[20]); SQRADDAC(a[14], a[19]); SQRADDAC(a[15], a[18]); SQRADDAC(a[16], a[17]); SQRADDDB;
+   COMBA_STORE(b[33]);
+
+   /* output 34 */
+   CARRY_FORWARD;
+   SQRADDSC(a[3], a[31]); SQRADDAC(a[4], a[30]); SQRADDAC(a[5], a[29]); SQRADDAC(a[6], a[28]); SQRADDAC(a[7], a[27]); SQRADDAC(a[8], a[26]); SQRADDAC(a[9], a[25]); SQRADDAC(a[10], a[24]); SQRADDAC(a[11], a[23]); SQRADDAC(a[12], a[22]); SQRADDAC(a[13], a[21]); SQRADDAC(a[14], a[20]); SQRADDAC(a[15], a[19]); SQRADDAC(a[16], a[18]); SQRADDDB; SQRADD(a[17], a[17]);
+   COMBA_STORE(b[34]);
+
+   /* output 35 */
+   CARRY_FORWARD;
+   SQRADDSC(a[4], a[31]); SQRADDAC(a[5], a[30]); SQRADDAC(a[6], a[29]); SQRADDAC(a[7], a[28]); SQRADDAC(a[8], a[27]); SQRADDAC(a[9], a[26]); SQRADDAC(a[10], a[25]); SQRADDAC(a[11], a[24]); SQRADDAC(a[12], a[23]); SQRADDAC(a[13], a[22]); SQRADDAC(a[14], a[21]); SQRADDAC(a[15], a[20]); SQRADDAC(a[16], a[19]); SQRADDAC(a[17], a[18]); SQRADDDB;
+   COMBA_STORE(b[35]);
+
+   /* output 36 */
+   CARRY_FORWARD;
+   SQRADDSC(a[5], a[31]); SQRADDAC(a[6], a[30]); SQRADDAC(a[7], a[29]); SQRADDAC(a[8], a[28]); SQRADDAC(a[9], a[27]); SQRADDAC(a[10], a[26]); SQRADDAC(a[11], a[25]); SQRADDAC(a[12], a[24]); SQRADDAC(a[13], a[23]); SQRADDAC(a[14], a[22]); SQRADDAC(a[15], a[21]); SQRADDAC(a[16], a[20]); SQRADDAC(a[17], a[19]); SQRADDDB; SQRADD(a[18], a[18]);
+   COMBA_STORE(b[36]);
+
+   /* output 37 */
+   CARRY_FORWARD;
+   SQRADDSC(a[6], a[31]); SQRADDAC(a[7], a[30]); SQRADDAC(a[8], a[29]); SQRADDAC(a[9], a[28]); SQRADDAC(a[10], a[27]); SQRADDAC(a[11], a[26]); SQRADDAC(a[12], a[25]); SQRADDAC(a[13], a[24]); SQRADDAC(a[14], a[23]); SQRADDAC(a[15], a[22]); SQRADDAC(a[16], a[21]); SQRADDAC(a[17], a[20]); SQRADDAC(a[18], a[19]); SQRADDDB;
+   COMBA_STORE(b[37]);
+
+   /* output 38 */
+   CARRY_FORWARD;
+   SQRADDSC(a[7], a[31]); SQRADDAC(a[8], a[30]); SQRADDAC(a[9], a[29]); SQRADDAC(a[10], a[28]); SQRADDAC(a[11], a[27]); SQRADDAC(a[12], a[26]); SQRADDAC(a[13], a[25]); SQRADDAC(a[14], a[24]); SQRADDAC(a[15], a[23]); SQRADDAC(a[16], a[22]); SQRADDAC(a[17], a[21]); SQRADDAC(a[18], a[20]); SQRADDDB; SQRADD(a[19], a[19]);
+   COMBA_STORE(b[38]);
+
+   /* output 39 */
+   CARRY_FORWARD;
+   SQRADDSC(a[8], a[31]); SQRADDAC(a[9], a[30]); SQRADDAC(a[10], a[29]); SQRADDAC(a[11], a[28]); SQRADDAC(a[12], a[27]); SQRADDAC(a[13], a[26]); SQRADDAC(a[14], a[25]); SQRADDAC(a[15], a[24]); SQRADDAC(a[16], a[23]); SQRADDAC(a[17], a[22]); SQRADDAC(a[18], a[21]); SQRADDAC(a[19], a[20]); SQRADDDB;
+   COMBA_STORE(b[39]);
+
+   /* output 40 */
+   CARRY_FORWARD;
+   SQRADDSC(a[9], a[31]); SQRADDAC(a[10], a[30]); SQRADDAC(a[11], a[29]); SQRADDAC(a[12], a[28]); SQRADDAC(a[13], a[27]); SQRADDAC(a[14], a[26]); SQRADDAC(a[15], a[25]); SQRADDAC(a[16], a[24]); SQRADDAC(a[17], a[23]); SQRADDAC(a[18], a[22]); SQRADDAC(a[19], a[21]); SQRADDDB; SQRADD(a[20], a[20]);
+   COMBA_STORE(b[40]);
+
+   /* output 41 */
+   CARRY_FORWARD;
+   SQRADDSC(a[10], a[31]); SQRADDAC(a[11], a[30]); SQRADDAC(a[12], a[29]); SQRADDAC(a[13], a[28]); SQRADDAC(a[14], a[27]); SQRADDAC(a[15], a[26]); SQRADDAC(a[16], a[25]); SQRADDAC(a[17], a[24]); SQRADDAC(a[18], a[23]); SQRADDAC(a[19], a[22]); SQRADDAC(a[20], a[21]); SQRADDDB;
+   COMBA_STORE(b[41]);
+
+   /* output 42 */
+   CARRY_FORWARD;
+   SQRADDSC(a[11], a[31]); SQRADDAC(a[12], a[30]); SQRADDAC(a[13], a[29]); SQRADDAC(a[14], a[28]); SQRADDAC(a[15], a[27]); SQRADDAC(a[16], a[26]); SQRADDAC(a[17], a[25]); SQRADDAC(a[18], a[24]); SQRADDAC(a[19], a[23]); SQRADDAC(a[20], a[22]); SQRADDDB; SQRADD(a[21], a[21]);
+   COMBA_STORE(b[42]);
+
+   /* output 43 */
+   CARRY_FORWARD;
+   SQRADDSC(a[12], a[31]); SQRADDAC(a[13], a[30]); SQRADDAC(a[14], a[29]); SQRADDAC(a[15], a[28]); SQRADDAC(a[16], a[27]); SQRADDAC(a[17], a[26]); SQRADDAC(a[18], a[25]); SQRADDAC(a[19], a[24]); SQRADDAC(a[20], a[23]); SQRADDAC(a[21], a[22]); SQRADDDB;
+   COMBA_STORE(b[43]);
+
+   /* output 44 */
+   CARRY_FORWARD;
+   SQRADDSC(a[13], a[31]); SQRADDAC(a[14], a[30]); SQRADDAC(a[15], a[29]); SQRADDAC(a[16], a[28]); SQRADDAC(a[17], a[27]); SQRADDAC(a[18], a[26]); SQRADDAC(a[19], a[25]); SQRADDAC(a[20], a[24]); SQRADDAC(a[21], a[23]); SQRADDDB; SQRADD(a[22], a[22]);
+   COMBA_STORE(b[44]);
+
+   /* output 45 */
+   CARRY_FORWARD;
+   SQRADDSC(a[14], a[31]); SQRADDAC(a[15], a[30]); SQRADDAC(a[16], a[29]); SQRADDAC(a[17], a[28]); SQRADDAC(a[18], a[27]); SQRADDAC(a[19], a[26]); SQRADDAC(a[20], a[25]); SQRADDAC(a[21], a[24]); SQRADDAC(a[22], a[23]); SQRADDDB;
+   COMBA_STORE(b[45]);
+
+   /* output 46 */
+   CARRY_FORWARD;
+   SQRADDSC(a[15], a[31]); SQRADDAC(a[16], a[30]); SQRADDAC(a[17], a[29]); SQRADDAC(a[18], a[28]); SQRADDAC(a[19], a[27]); SQRADDAC(a[20], a[26]); SQRADDAC(a[21], a[25]); SQRADDAC(a[22], a[24]); SQRADDDB; SQRADD(a[23], a[23]);
+   COMBA_STORE(b[46]);
+
+   /* output 47 */
+   CARRY_FORWARD;
+   SQRADDSC(a[16], a[31]); SQRADDAC(a[17], a[30]); SQRADDAC(a[18], a[29]); SQRADDAC(a[19], a[28]); SQRADDAC(a[20], a[27]); SQRADDAC(a[21], a[26]); SQRADDAC(a[22], a[25]); SQRADDAC(a[23], a[24]); SQRADDDB;
+   COMBA_STORE(b[47]);
+
+   /* output 48 */
+   CARRY_FORWARD;
+   SQRADDSC(a[17], a[31]); SQRADDAC(a[18], a[30]); SQRADDAC(a[19], a[29]); SQRADDAC(a[20], a[28]); SQRADDAC(a[21], a[27]); SQRADDAC(a[22], a[26]); SQRADDAC(a[23], a[25]); SQRADDDB; SQRADD(a[24], a[24]);
+   COMBA_STORE(b[48]);
+
+   /* output 49 */
+   CARRY_FORWARD;
+   SQRADDSC(a[18], a[31]); SQRADDAC(a[19], a[30]); SQRADDAC(a[20], a[29]); SQRADDAC(a[21], a[28]); SQRADDAC(a[22], a[27]); SQRADDAC(a[23], a[26]); SQRADDAC(a[24], a[25]); SQRADDDB;
+   COMBA_STORE(b[49]);
+
+   /* output 50 */
+   CARRY_FORWARD;
+   SQRADDSC(a[19], a[31]); SQRADDAC(a[20], a[30]); SQRADDAC(a[21], a[29]); SQRADDAC(a[22], a[28]); SQRADDAC(a[23], a[27]); SQRADDAC(a[24], a[26]); SQRADDDB; SQRADD(a[25], a[25]);
+   COMBA_STORE(b[50]);
+
+   /* output 51 */
+   CARRY_FORWARD;
+   SQRADDSC(a[20], a[31]); SQRADDAC(a[21], a[30]); SQRADDAC(a[22], a[29]); SQRADDAC(a[23], a[28]); SQRADDAC(a[24], a[27]); SQRADDAC(a[25], a[26]); SQRADDDB;
+   COMBA_STORE(b[51]);
+
+   /* output 52 */
+   CARRY_FORWARD;
+   SQRADDSC(a[21], a[31]); SQRADDAC(a[22], a[30]); SQRADDAC(a[23], a[29]); SQRADDAC(a[24], a[28]); SQRADDAC(a[25], a[27]); SQRADDDB; SQRADD(a[26], a[26]);
+   COMBA_STORE(b[52]);
+
+   /* output 53 */
+   CARRY_FORWARD;
+   SQRADDSC(a[22], a[31]); SQRADDAC(a[23], a[30]); SQRADDAC(a[24], a[29]); SQRADDAC(a[25], a[28]); SQRADDAC(a[26], a[27]); SQRADDDB;
+   COMBA_STORE(b[53]);
+
+   /* output 54 */
+   CARRY_FORWARD;
+   SQRADDSC(a[23], a[31]); SQRADDAC(a[24], a[30]); SQRADDAC(a[25], a[29]); SQRADDAC(a[26], a[28]); SQRADDDB; SQRADD(a[27], a[27]);
+   COMBA_STORE(b[54]);
+
+   /* output 55 */
+   CARRY_FORWARD;
+   SQRADDSC(a[24], a[31]); SQRADDAC(a[25], a[30]); SQRADDAC(a[26], a[29]); SQRADDAC(a[27], a[28]); SQRADDDB;
+   COMBA_STORE(b[55]);
+
+   /* output 56 */
+   CARRY_FORWARD;
+   SQRADDSC(a[25], a[31]); SQRADDAC(a[26], a[30]); SQRADDAC(a[27], a[29]); SQRADDDB; SQRADD(a[28], a[28]);
+   COMBA_STORE(b[56]);
+
+   /* output 57 */
+   CARRY_FORWARD;
+   SQRADDSC(a[26], a[31]); SQRADDAC(a[27], a[30]); SQRADDAC(a[28], a[29]); SQRADDDB;
+   COMBA_STORE(b[57]);
+
+   /* output 58 */
+   CARRY_FORWARD;
+   SQRADD2(a[27], a[31]); SQRADD2(a[28], a[30]); SQRADD(a[29], a[29]);
+   COMBA_STORE(b[58]);
+
+   /* output 59 */
+   CARRY_FORWARD;
+   SQRADD2(a[28], a[31]); SQRADD2(a[29], a[30]);
+   COMBA_STORE(b[59]);
+
+   /* output 60 */
+   CARRY_FORWARD;
+   SQRADD2(a[29], a[31]); SQRADD(a[30], a[30]);
+   COMBA_STORE(b[60]);
+
+   /* output 61 */
+   CARRY_FORWARD;
+   SQRADD2(a[30], a[31]);
+   COMBA_STORE(b[61]);
+
+   /* output 62 */
+   CARRY_FORWARD;
+   SQRADD(a[31], a[31]);
+   COMBA_STORE(b[62]);
+   COMBA_STORE2(b[63]);
+   COMBA_FINI;
+
+   B->used = 64;
+   B->sign = FP_ZPOS;
+   memcpy(B->dp, b, 64 * sizeof(fp_digit));
+   fp_clamp(B);
+}
+#endif
+
+
+/* $Source$ */
+/* $Revision$ */
+/* $Date$ */
diff --git a/tomsfastmath/src/sqr/fp_sqr_comba_4.c b/tomsfastmath/src/sqr/fp_sqr_comba_4.c
new file mode 100644 (file)
index 0000000..05be36e
--- /dev/null
@@ -0,0 +1,64 @@
+#define TFM_DEFINES
+#include "fp_sqr_comba.c"
+
+#if defined(TFM_SQR4) && FP_SIZE >= 8
+void fp_sqr_comba4(fp_int *A, fp_int *B)
+{
+   fp_digit *a, b[8], c0, c1, c2, sc0, sc1, sc2;
+#ifdef TFM_ISO
+   fp_word tt;
+#endif
+
+   a = A->dp;
+   COMBA_START;
+
+   /* clear carries */
+   CLEAR_CARRY;
+
+   /* output 0 */
+   SQRADD(a[0],a[0]);
+   COMBA_STORE(b[0]);
+
+   /* output 1 */
+   CARRY_FORWARD;
+   SQRADD2(a[0], a[1]);
+   COMBA_STORE(b[1]);
+
+   /* output 2 */
+   CARRY_FORWARD;
+   SQRADD2(a[0], a[2]); SQRADD(a[1], a[1]);
+   COMBA_STORE(b[2]);
+
+   /* output 3 */
+   CARRY_FORWARD;
+   SQRADD2(a[0], a[3]); SQRADD2(a[1], a[2]);
+   COMBA_STORE(b[3]);
+
+   /* output 4 */
+   CARRY_FORWARD;
+   SQRADD2(a[1], a[3]); SQRADD(a[2], a[2]);
+   COMBA_STORE(b[4]);
+
+   /* output 5 */
+   CARRY_FORWARD;
+   SQRADD2(a[2], a[3]);
+   COMBA_STORE(b[5]);
+
+   /* output 6 */
+   CARRY_FORWARD;
+   SQRADD(a[3], a[3]);
+   COMBA_STORE(b[6]);
+   COMBA_STORE2(b[7]);
+   COMBA_FINI;
+
+   B->used = 8;
+   B->sign = FP_ZPOS;
+   memcpy(B->dp, b, 8 * sizeof(fp_digit));
+   fp_clamp(B);
+}
+#endif
+
+
+/* $Source$ */
+/* $Revision$ */
+/* $Date$ */
diff --git a/tomsfastmath/src/sqr/fp_sqr_comba_48.c b/tomsfastmath/src/sqr/fp_sqr_comba_48.c
new file mode 100644 (file)
index 0000000..406af9b
--- /dev/null
@@ -0,0 +1,504 @@
+#define TFM_DEFINES
+#include "fp_sqr_comba.c"
+
+#if defined(TFM_SQR48) && FP_SIZE >= 96
+void fp_sqr_comba48(fp_int *A, fp_int *B)
+{
+   fp_digit *a, b[96], c0, c1, c2, sc0, sc1, sc2;
+#ifdef TFM_ISO
+   fp_word tt;
+#endif
+
+   a = A->dp;
+   COMBA_START;
+
+   /* clear carries */
+   CLEAR_CARRY;
+
+   /* output 0 */
+   SQRADD(a[0],a[0]);
+   COMBA_STORE(b[0]);
+
+   /* output 1 */
+   CARRY_FORWARD;
+   SQRADD2(a[0], a[1]);
+   COMBA_STORE(b[1]);
+
+   /* output 2 */
+   CARRY_FORWARD;
+   SQRADD2(a[0], a[2]); SQRADD(a[1], a[1]);
+   COMBA_STORE(b[2]);
+
+   /* output 3 */
+   CARRY_FORWARD;
+   SQRADD2(a[0], a[3]); SQRADD2(a[1], a[2]);
+   COMBA_STORE(b[3]);
+
+   /* output 4 */
+   CARRY_FORWARD;
+   SQRADD2(a[0], a[4]); SQRADD2(a[1], a[3]); SQRADD(a[2], a[2]);
+   COMBA_STORE(b[4]);
+
+   /* output 5 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[5]); SQRADDAC(a[1], a[4]); SQRADDAC(a[2], a[3]); SQRADDDB;
+   COMBA_STORE(b[5]);
+
+   /* output 6 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[6]); SQRADDAC(a[1], a[5]); SQRADDAC(a[2], a[4]); SQRADDDB; SQRADD(a[3], a[3]);
+   COMBA_STORE(b[6]);
+
+   /* output 7 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[7]); SQRADDAC(a[1], a[6]); SQRADDAC(a[2], a[5]); SQRADDAC(a[3], a[4]); SQRADDDB;
+   COMBA_STORE(b[7]);
+
+   /* output 8 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[8]); SQRADDAC(a[1], a[7]); SQRADDAC(a[2], a[6]); SQRADDAC(a[3], a[5]); SQRADDDB; SQRADD(a[4], a[4]);
+   COMBA_STORE(b[8]);
+
+   /* output 9 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[9]); SQRADDAC(a[1], a[8]); SQRADDAC(a[2], a[7]); SQRADDAC(a[3], a[6]); SQRADDAC(a[4], a[5]); SQRADDDB;
+   COMBA_STORE(b[9]);
+
+   /* output 10 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[10]); SQRADDAC(a[1], a[9]); SQRADDAC(a[2], a[8]); SQRADDAC(a[3], a[7]); SQRADDAC(a[4], a[6]); SQRADDDB; SQRADD(a[5], a[5]);
+   COMBA_STORE(b[10]);
+
+   /* output 11 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[11]); SQRADDAC(a[1], a[10]); SQRADDAC(a[2], a[9]); SQRADDAC(a[3], a[8]); SQRADDAC(a[4], a[7]); SQRADDAC(a[5], a[6]); SQRADDDB;
+   COMBA_STORE(b[11]);
+
+   /* output 12 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[12]); SQRADDAC(a[1], a[11]); SQRADDAC(a[2], a[10]); SQRADDAC(a[3], a[9]); SQRADDAC(a[4], a[8]); SQRADDAC(a[5], a[7]); SQRADDDB; SQRADD(a[6], a[6]);
+   COMBA_STORE(b[12]);
+
+   /* output 13 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[13]); SQRADDAC(a[1], a[12]); SQRADDAC(a[2], a[11]); SQRADDAC(a[3], a[10]); SQRADDAC(a[4], a[9]); SQRADDAC(a[5], a[8]); SQRADDAC(a[6], a[7]); SQRADDDB;
+   COMBA_STORE(b[13]);
+
+   /* output 14 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[14]); SQRADDAC(a[1], a[13]); SQRADDAC(a[2], a[12]); SQRADDAC(a[3], a[11]); SQRADDAC(a[4], a[10]); SQRADDAC(a[5], a[9]); SQRADDAC(a[6], a[8]); SQRADDDB; SQRADD(a[7], a[7]);
+   COMBA_STORE(b[14]);
+
+   /* output 15 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[15]); SQRADDAC(a[1], a[14]); SQRADDAC(a[2], a[13]); SQRADDAC(a[3], a[12]); SQRADDAC(a[4], a[11]); SQRADDAC(a[5], a[10]); SQRADDAC(a[6], a[9]); SQRADDAC(a[7], a[8]); SQRADDDB;
+   COMBA_STORE(b[15]);
+
+   /* output 16 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[16]); SQRADDAC(a[1], a[15]); SQRADDAC(a[2], a[14]); SQRADDAC(a[3], a[13]); SQRADDAC(a[4], a[12]); SQRADDAC(a[5], a[11]); SQRADDAC(a[6], a[10]); SQRADDAC(a[7], a[9]); SQRADDDB; SQRADD(a[8], a[8]);
+   COMBA_STORE(b[16]);
+
+   /* output 17 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[17]); SQRADDAC(a[1], a[16]); SQRADDAC(a[2], a[15]); SQRADDAC(a[3], a[14]); SQRADDAC(a[4], a[13]); SQRADDAC(a[5], a[12]); SQRADDAC(a[6], a[11]); SQRADDAC(a[7], a[10]); SQRADDAC(a[8], a[9]); SQRADDDB;
+   COMBA_STORE(b[17]);
+
+   /* output 18 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[18]); SQRADDAC(a[1], a[17]); SQRADDAC(a[2], a[16]); SQRADDAC(a[3], a[15]); SQRADDAC(a[4], a[14]); SQRADDAC(a[5], a[13]); SQRADDAC(a[6], a[12]); SQRADDAC(a[7], a[11]); SQRADDAC(a[8], a[10]); SQRADDDB; SQRADD(a[9], a[9]);
+   COMBA_STORE(b[18]);
+
+   /* output 19 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[19]); SQRADDAC(a[1], a[18]); SQRADDAC(a[2], a[17]); SQRADDAC(a[3], a[16]); SQRADDAC(a[4], a[15]); SQRADDAC(a[5], a[14]); SQRADDAC(a[6], a[13]); SQRADDAC(a[7], a[12]); SQRADDAC(a[8], a[11]); SQRADDAC(a[9], a[10]); SQRADDDB;
+   COMBA_STORE(b[19]);
+
+   /* output 20 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[20]); SQRADDAC(a[1], a[19]); SQRADDAC(a[2], a[18]); SQRADDAC(a[3], a[17]); SQRADDAC(a[4], a[16]); SQRADDAC(a[5], a[15]); SQRADDAC(a[6], a[14]); SQRADDAC(a[7], a[13]); SQRADDAC(a[8], a[12]); SQRADDAC(a[9], a[11]); SQRADDDB; SQRADD(a[10], a[10]);
+   COMBA_STORE(b[20]);
+
+   /* output 21 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[21]); SQRADDAC(a[1], a[20]); SQRADDAC(a[2], a[19]); SQRADDAC(a[3], a[18]); SQRADDAC(a[4], a[17]); SQRADDAC(a[5], a[16]); SQRADDAC(a[6], a[15]); SQRADDAC(a[7], a[14]); SQRADDAC(a[8], a[13]); SQRADDAC(a[9], a[12]); SQRADDAC(a[10], a[11]); SQRADDDB;
+   COMBA_STORE(b[21]);
+
+   /* output 22 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[22]); SQRADDAC(a[1], a[21]); SQRADDAC(a[2], a[20]); SQRADDAC(a[3], a[19]); SQRADDAC(a[4], a[18]); SQRADDAC(a[5], a[17]); SQRADDAC(a[6], a[16]); SQRADDAC(a[7], a[15]); SQRADDAC(a[8], a[14]); SQRADDAC(a[9], a[13]); SQRADDAC(a[10], a[12]); SQRADDDB; SQRADD(a[11], a[11]);
+   COMBA_STORE(b[22]);
+
+   /* output 23 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[23]); SQRADDAC(a[1], a[22]); SQRADDAC(a[2], a[21]); SQRADDAC(a[3], a[20]); SQRADDAC(a[4], a[19]); SQRADDAC(a[5], a[18]); SQRADDAC(a[6], a[17]); SQRADDAC(a[7], a[16]); SQRADDAC(a[8], a[15]); SQRADDAC(a[9], a[14]); SQRADDAC(a[10], a[13]); SQRADDAC(a[11], a[12]); SQRADDDB;
+   COMBA_STORE(b[23]);
+
+   /* output 24 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[24]); SQRADDAC(a[1], a[23]); SQRADDAC(a[2], a[22]); SQRADDAC(a[3], a[21]); SQRADDAC(a[4], a[20]); SQRADDAC(a[5], a[19]); SQRADDAC(a[6], a[18]); SQRADDAC(a[7], a[17]); SQRADDAC(a[8], a[16]); SQRADDAC(a[9], a[15]); SQRADDAC(a[10], a[14]); SQRADDAC(a[11], a[13]); SQRADDDB; SQRADD(a[12], a[12]);
+   COMBA_STORE(b[24]);
+
+   /* output 25 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[25]); SQRADDAC(a[1], a[24]); SQRADDAC(a[2], a[23]); SQRADDAC(a[3], a[22]); SQRADDAC(a[4], a[21]); SQRADDAC(a[5], a[20]); SQRADDAC(a[6], a[19]); SQRADDAC(a[7], a[18]); SQRADDAC(a[8], a[17]); SQRADDAC(a[9], a[16]); SQRADDAC(a[10], a[15]); SQRADDAC(a[11], a[14]); SQRADDAC(a[12], a[13]); SQRADDDB;
+   COMBA_STORE(b[25]);
+
+   /* output 26 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[26]); SQRADDAC(a[1], a[25]); SQRADDAC(a[2], a[24]); SQRADDAC(a[3], a[23]); SQRADDAC(a[4], a[22]); SQRADDAC(a[5], a[21]); SQRADDAC(a[6], a[20]); SQRADDAC(a[7], a[19]); SQRADDAC(a[8], a[18]); SQRADDAC(a[9], a[17]); SQRADDAC(a[10], a[16]); SQRADDAC(a[11], a[15]); SQRADDAC(a[12], a[14]); SQRADDDB; SQRADD(a[13], a[13]);
+   COMBA_STORE(b[26]);
+
+   /* output 27 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[27]); SQRADDAC(a[1], a[26]); SQRADDAC(a[2], a[25]); SQRADDAC(a[3], a[24]); SQRADDAC(a[4], a[23]); SQRADDAC(a[5], a[22]); SQRADDAC(a[6], a[21]); SQRADDAC(a[7], a[20]); SQRADDAC(a[8], a[19]); SQRADDAC(a[9], a[18]); SQRADDAC(a[10], a[17]); SQRADDAC(a[11], a[16]); SQRADDAC(a[12], a[15]); SQRADDAC(a[13], a[14]); SQRADDDB;
+   COMBA_STORE(b[27]);
+
+   /* output 28 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[28]); SQRADDAC(a[1], a[27]); SQRADDAC(a[2], a[26]); SQRADDAC(a[3], a[25]); SQRADDAC(a[4], a[24]); SQRADDAC(a[5], a[23]); SQRADDAC(a[6], a[22]); SQRADDAC(a[7], a[21]); SQRADDAC(a[8], a[20]); SQRADDAC(a[9], a[19]); SQRADDAC(a[10], a[18]); SQRADDAC(a[11], a[17]); SQRADDAC(a[12], a[16]); SQRADDAC(a[13], a[15]); SQRADDDB; SQRADD(a[14], a[14]);
+   COMBA_STORE(b[28]);
+
+   /* output 29 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[29]); SQRADDAC(a[1], a[28]); SQRADDAC(a[2], a[27]); SQRADDAC(a[3], a[26]); SQRADDAC(a[4], a[25]); SQRADDAC(a[5], a[24]); SQRADDAC(a[6], a[23]); SQRADDAC(a[7], a[22]); SQRADDAC(a[8], a[21]); SQRADDAC(a[9], a[20]); SQRADDAC(a[10], a[19]); SQRADDAC(a[11], a[18]); SQRADDAC(a[12], a[17]); SQRADDAC(a[13], a[16]); SQRADDAC(a[14], a[15]); SQRADDDB;
+   COMBA_STORE(b[29]);
+
+   /* output 30 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[30]); SQRADDAC(a[1], a[29]); SQRADDAC(a[2], a[28]); SQRADDAC(a[3], a[27]); SQRADDAC(a[4], a[26]); SQRADDAC(a[5], a[25]); SQRADDAC(a[6], a[24]); SQRADDAC(a[7], a[23]); SQRADDAC(a[8], a[22]); SQRADDAC(a[9], a[21]); SQRADDAC(a[10], a[20]); SQRADDAC(a[11], a[19]); SQRADDAC(a[12], a[18]); SQRADDAC(a[13], a[17]); SQRADDAC(a[14], a[16]); SQRADDDB; SQRADD(a[15], a[15]);
+   COMBA_STORE(b[30]);
+
+   /* output 31 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[31]); SQRADDAC(a[1], a[30]); SQRADDAC(a[2], a[29]); SQRADDAC(a[3], a[28]); SQRADDAC(a[4], a[27]); SQRADDAC(a[5], a[26]); SQRADDAC(a[6], a[25]); SQRADDAC(a[7], a[24]); SQRADDAC(a[8], a[23]); SQRADDAC(a[9], a[22]); SQRADDAC(a[10], a[21]); SQRADDAC(a[11], a[20]); SQRADDAC(a[12], a[19]); SQRADDAC(a[13], a[18]); SQRADDAC(a[14], a[17]); SQRADDAC(a[15], a[16]); SQRADDDB;
+   COMBA_STORE(b[31]);
+
+   /* output 32 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[32]); SQRADDAC(a[1], a[31]); SQRADDAC(a[2], a[30]); SQRADDAC(a[3], a[29]); SQRADDAC(a[4], a[28]); SQRADDAC(a[5], a[27]); SQRADDAC(a[6], a[26]); SQRADDAC(a[7], a[25]); SQRADDAC(a[8], a[24]); SQRADDAC(a[9], a[23]); SQRADDAC(a[10], a[22]); SQRADDAC(a[11], a[21]); SQRADDAC(a[12], a[20]); SQRADDAC(a[13], a[19]); SQRADDAC(a[14], a[18]); SQRADDAC(a[15], a[17]); SQRADDDB; SQRADD(a[16], a[16]);
+   COMBA_STORE(b[32]);
+
+   /* output 33 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[33]); SQRADDAC(a[1], a[32]); SQRADDAC(a[2], a[31]); SQRADDAC(a[3], a[30]); SQRADDAC(a[4], a[29]); SQRADDAC(a[5], a[28]); SQRADDAC(a[6], a[27]); SQRADDAC(a[7], a[26]); SQRADDAC(a[8], a[25]); SQRADDAC(a[9], a[24]); SQRADDAC(a[10], a[23]); SQRADDAC(a[11], a[22]); SQRADDAC(a[12], a[21]); SQRADDAC(a[13], a[20]); SQRADDAC(a[14], a[19]); SQRADDAC(a[15], a[18]); SQRADDAC(a[16], a[17]); SQRADDDB;
+   COMBA_STORE(b[33]);
+
+   /* output 34 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[34]); SQRADDAC(a[1], a[33]); SQRADDAC(a[2], a[32]); SQRADDAC(a[3], a[31]); SQRADDAC(a[4], a[30]); SQRADDAC(a[5], a[29]); SQRADDAC(a[6], a[28]); SQRADDAC(a[7], a[27]); SQRADDAC(a[8], a[26]); SQRADDAC(a[9], a[25]); SQRADDAC(a[10], a[24]); SQRADDAC(a[11], a[23]); SQRADDAC(a[12], a[22]); SQRADDAC(a[13], a[21]); SQRADDAC(a[14], a[20]); SQRADDAC(a[15], a[19]); SQRADDAC(a[16], a[18]); SQRADDDB; SQRADD(a[17], a[17]);
+   COMBA_STORE(b[34]);
+
+   /* output 35 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[35]); SQRADDAC(a[1], a[34]); SQRADDAC(a[2], a[33]); SQRADDAC(a[3], a[32]); SQRADDAC(a[4], a[31]); SQRADDAC(a[5], a[30]); SQRADDAC(a[6], a[29]); SQRADDAC(a[7], a[28]); SQRADDAC(a[8], a[27]); SQRADDAC(a[9], a[26]); SQRADDAC(a[10], a[25]); SQRADDAC(a[11], a[24]); SQRADDAC(a[12], a[23]); SQRADDAC(a[13], a[22]); SQRADDAC(a[14], a[21]); SQRADDAC(a[15], a[20]); SQRADDAC(a[16], a[19]); SQRADDAC(a[17], a[18]); SQRADDDB;
+   COMBA_STORE(b[35]);
+
+   /* output 36 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[36]); SQRADDAC(a[1], a[35]); SQRADDAC(a[2], a[34]); SQRADDAC(a[3], a[33]); SQRADDAC(a[4], a[32]); SQRADDAC(a[5], a[31]); SQRADDAC(a[6], a[30]); SQRADDAC(a[7], a[29]); SQRADDAC(a[8], a[28]); SQRADDAC(a[9], a[27]); SQRADDAC(a[10], a[26]); SQRADDAC(a[11], a[25]); SQRADDAC(a[12], a[24]); SQRADDAC(a[13], a[23]); SQRADDAC(a[14], a[22]); SQRADDAC(a[15], a[21]); SQRADDAC(a[16], a[20]); SQRADDAC(a[17], a[19]); SQRADDDB; SQRADD(a[18], a[18]);
+   COMBA_STORE(b[36]);
+
+   /* output 37 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[37]); SQRADDAC(a[1], a[36]); SQRADDAC(a[2], a[35]); SQRADDAC(a[3], a[34]); SQRADDAC(a[4], a[33]); SQRADDAC(a[5], a[32]); SQRADDAC(a[6], a[31]); SQRADDAC(a[7], a[30]); SQRADDAC(a[8], a[29]); SQRADDAC(a[9], a[28]); SQRADDAC(a[10], a[27]); SQRADDAC(a[11], a[26]); SQRADDAC(a[12], a[25]); SQRADDAC(a[13], a[24]); SQRADDAC(a[14], a[23]); SQRADDAC(a[15], a[22]); SQRADDAC(a[16], a[21]); SQRADDAC(a[17], a[20]); SQRADDAC(a[18], a[19]); SQRADDDB;
+   COMBA_STORE(b[37]);
+
+   /* output 38 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[38]); SQRADDAC(a[1], a[37]); SQRADDAC(a[2], a[36]); SQRADDAC(a[3], a[35]); SQRADDAC(a[4], a[34]); SQRADDAC(a[5], a[33]); SQRADDAC(a[6], a[32]); SQRADDAC(a[7], a[31]); SQRADDAC(a[8], a[30]); SQRADDAC(a[9], a[29]); SQRADDAC(a[10], a[28]); SQRADDAC(a[11], a[27]); SQRADDAC(a[12], a[26]); SQRADDAC(a[13], a[25]); SQRADDAC(a[14], a[24]); SQRADDAC(a[15], a[23]); SQRADDAC(a[16], a[22]); SQRADDAC(a[17], a[21]); SQRADDAC(a[18], a[20]); SQRADDDB; SQRADD(a[19], a[19]);
+   COMBA_STORE(b[38]);
+
+   /* output 39 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[39]); SQRADDAC(a[1], a[38]); SQRADDAC(a[2], a[37]); SQRADDAC(a[3], a[36]); SQRADDAC(a[4], a[35]); SQRADDAC(a[5], a[34]); SQRADDAC(a[6], a[33]); SQRADDAC(a[7], a[32]); SQRADDAC(a[8], a[31]); SQRADDAC(a[9], a[30]); SQRADDAC(a[10], a[29]); SQRADDAC(a[11], a[28]); SQRADDAC(a[12], a[27]); SQRADDAC(a[13], a[26]); SQRADDAC(a[14], a[25]); SQRADDAC(a[15], a[24]); SQRADDAC(a[16], a[23]); SQRADDAC(a[17], a[22]); SQRADDAC(a[18], a[21]); SQRADDAC(a[19], a[20]); SQRADDDB;
+   COMBA_STORE(b[39]);
+
+   /* output 40 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[40]); SQRADDAC(a[1], a[39]); SQRADDAC(a[2], a[38]); SQRADDAC(a[3], a[37]); SQRADDAC(a[4], a[36]); SQRADDAC(a[5], a[35]); SQRADDAC(a[6], a[34]); SQRADDAC(a[7], a[33]); SQRADDAC(a[8], a[32]); SQRADDAC(a[9], a[31]); SQRADDAC(a[10], a[30]); SQRADDAC(a[11], a[29]); SQRADDAC(a[12], a[28]); SQRADDAC(a[13], a[27]); SQRADDAC(a[14], a[26]); SQRADDAC(a[15], a[25]); SQRADDAC(a[16], a[24]); SQRADDAC(a[17], a[23]); SQRADDAC(a[18], a[22]); SQRADDAC(a[19], a[21]); SQRADDDB; SQRADD(a[20], a[20]);
+   COMBA_STORE(b[40]);
+
+   /* output 41 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[41]); SQRADDAC(a[1], a[40]); SQRADDAC(a[2], a[39]); SQRADDAC(a[3], a[38]); SQRADDAC(a[4], a[37]); SQRADDAC(a[5], a[36]); SQRADDAC(a[6], a[35]); SQRADDAC(a[7], a[34]); SQRADDAC(a[8], a[33]); SQRADDAC(a[9], a[32]); SQRADDAC(a[10], a[31]); SQRADDAC(a[11], a[30]); SQRADDAC(a[12], a[29]); SQRADDAC(a[13], a[28]); SQRADDAC(a[14], a[27]); SQRADDAC(a[15], a[26]); SQRADDAC(a[16], a[25]); SQRADDAC(a[17], a[24]); SQRADDAC(a[18], a[23]); SQRADDAC(a[19], a[22]); SQRADDAC(a[20], a[21]); SQRADDDB;
+   COMBA_STORE(b[41]);
+
+   /* output 42 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[42]); SQRADDAC(a[1], a[41]); SQRADDAC(a[2], a[40]); SQRADDAC(a[3], a[39]); SQRADDAC(a[4], a[38]); SQRADDAC(a[5], a[37]); SQRADDAC(a[6], a[36]); SQRADDAC(a[7], a[35]); SQRADDAC(a[8], a[34]); SQRADDAC(a[9], a[33]); SQRADDAC(a[10], a[32]); SQRADDAC(a[11], a[31]); SQRADDAC(a[12], a[30]); SQRADDAC(a[13], a[29]); SQRADDAC(a[14], a[28]); SQRADDAC(a[15], a[27]); SQRADDAC(a[16], a[26]); SQRADDAC(a[17], a[25]); SQRADDAC(a[18], a[24]); SQRADDAC(a[19], a[23]); SQRADDAC(a[20], a[22]); SQRADDDB; SQRADD(a[21], a[21]);
+   COMBA_STORE(b[42]);
+
+   /* output 43 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[43]); SQRADDAC(a[1], a[42]); SQRADDAC(a[2], a[41]); SQRADDAC(a[3], a[40]); SQRADDAC(a[4], a[39]); SQRADDAC(a[5], a[38]); SQRADDAC(a[6], a[37]); SQRADDAC(a[7], a[36]); SQRADDAC(a[8], a[35]); SQRADDAC(a[9], a[34]); SQRADDAC(a[10], a[33]); SQRADDAC(a[11], a[32]); SQRADDAC(a[12], a[31]); SQRADDAC(a[13], a[30]); SQRADDAC(a[14], a[29]); SQRADDAC(a[15], a[28]); SQRADDAC(a[16], a[27]); SQRADDAC(a[17], a[26]); SQRADDAC(a[18], a[25]); SQRADDAC(a[19], a[24]); SQRADDAC(a[20], a[23]); SQRADDAC(a[21], a[22]); SQRADDDB;
+   COMBA_STORE(b[43]);
+
+   /* output 44 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[44]); SQRADDAC(a[1], a[43]); SQRADDAC(a[2], a[42]); SQRADDAC(a[3], a[41]); SQRADDAC(a[4], a[40]); SQRADDAC(a[5], a[39]); SQRADDAC(a[6], a[38]); SQRADDAC(a[7], a[37]); SQRADDAC(a[8], a[36]); SQRADDAC(a[9], a[35]); SQRADDAC(a[10], a[34]); SQRADDAC(a[11], a[33]); SQRADDAC(a[12], a[32]); SQRADDAC(a[13], a[31]); SQRADDAC(a[14], a[30]); SQRADDAC(a[15], a[29]); SQRADDAC(a[16], a[28]); SQRADDAC(a[17], a[27]); SQRADDAC(a[18], a[26]); SQRADDAC(a[19], a[25]); SQRADDAC(a[20], a[24]); SQRADDAC(a[21], a[23]); SQRADDDB; SQRADD(a[22], a[22]);
+   COMBA_STORE(b[44]);
+
+   /* output 45 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[45]); SQRADDAC(a[1], a[44]); SQRADDAC(a[2], a[43]); SQRADDAC(a[3], a[42]); SQRADDAC(a[4], a[41]); SQRADDAC(a[5], a[40]); SQRADDAC(a[6], a[39]); SQRADDAC(a[7], a[38]); SQRADDAC(a[8], a[37]); SQRADDAC(a[9], a[36]); SQRADDAC(a[10], a[35]); SQRADDAC(a[11], a[34]); SQRADDAC(a[12], a[33]); SQRADDAC(a[13], a[32]); SQRADDAC(a[14], a[31]); SQRADDAC(a[15], a[30]); SQRADDAC(a[16], a[29]); SQRADDAC(a[17], a[28]); SQRADDAC(a[18], a[27]); SQRADDAC(a[19], a[26]); SQRADDAC(a[20], a[25]); SQRADDAC(a[21], a[24]); SQRADDAC(a[22], a[23]); SQRADDDB;
+   COMBA_STORE(b[45]);
+
+   /* output 46 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[46]); SQRADDAC(a[1], a[45]); SQRADDAC(a[2], a[44]); SQRADDAC(a[3], a[43]); SQRADDAC(a[4], a[42]); SQRADDAC(a[5], a[41]); SQRADDAC(a[6], a[40]); SQRADDAC(a[7], a[39]); SQRADDAC(a[8], a[38]); SQRADDAC(a[9], a[37]); SQRADDAC(a[10], a[36]); SQRADDAC(a[11], a[35]); SQRADDAC(a[12], a[34]); SQRADDAC(a[13], a[33]); SQRADDAC(a[14], a[32]); SQRADDAC(a[15], a[31]); SQRADDAC(a[16], a[30]); SQRADDAC(a[17], a[29]); SQRADDAC(a[18], a[28]); SQRADDAC(a[19], a[27]); SQRADDAC(a[20], a[26]); SQRADDAC(a[21], a[25]); SQRADDAC(a[22], a[24]); SQRADDDB; SQRADD(a[23], a[23]);
+   COMBA_STORE(b[46]);
+
+   /* output 47 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[47]); SQRADDAC(a[1], a[46]); SQRADDAC(a[2], a[45]); SQRADDAC(a[3], a[44]); SQRADDAC(a[4], a[43]); SQRADDAC(a[5], a[42]); SQRADDAC(a[6], a[41]); SQRADDAC(a[7], a[40]); SQRADDAC(a[8], a[39]); SQRADDAC(a[9], a[38]); SQRADDAC(a[10], a[37]); SQRADDAC(a[11], a[36]); SQRADDAC(a[12], a[35]); SQRADDAC(a[13], a[34]); SQRADDAC(a[14], a[33]); SQRADDAC(a[15], a[32]); SQRADDAC(a[16], a[31]); SQRADDAC(a[17], a[30]); SQRADDAC(a[18], a[29]); SQRADDAC(a[19], a[28]); SQRADDAC(a[20], a[27]); SQRADDAC(a[21], a[26]); SQRADDAC(a[22], a[25]); SQRADDAC(a[23], a[24]); SQRADDDB;
+   COMBA_STORE(b[47]);
+
+   /* output 48 */
+   CARRY_FORWARD;
+   SQRADDSC(a[1], a[47]); SQRADDAC(a[2], a[46]); SQRADDAC(a[3], a[45]); SQRADDAC(a[4], a[44]); SQRADDAC(a[5], a[43]); SQRADDAC(a[6], a[42]); SQRADDAC(a[7], a[41]); SQRADDAC(a[8], a[40]); SQRADDAC(a[9], a[39]); SQRADDAC(a[10], a[38]); SQRADDAC(a[11], a[37]); SQRADDAC(a[12], a[36]); SQRADDAC(a[13], a[35]); SQRADDAC(a[14], a[34]); SQRADDAC(a[15], a[33]); SQRADDAC(a[16], a[32]); SQRADDAC(a[17], a[31]); SQRADDAC(a[18], a[30]); SQRADDAC(a[19], a[29]); SQRADDAC(a[20], a[28]); SQRADDAC(a[21], a[27]); SQRADDAC(a[22], a[26]); SQRADDAC(a[23], a[25]); SQRADDDB; SQRADD(a[24], a[24]);
+   COMBA_STORE(b[48]);
+
+   /* output 49 */
+   CARRY_FORWARD;
+   SQRADDSC(a[2], a[47]); SQRADDAC(a[3], a[46]); SQRADDAC(a[4], a[45]); SQRADDAC(a[5], a[44]); SQRADDAC(a[6], a[43]); SQRADDAC(a[7], a[42]); SQRADDAC(a[8], a[41]); SQRADDAC(a[9], a[40]); SQRADDAC(a[10], a[39]); SQRADDAC(a[11], a[38]); SQRADDAC(a[12], a[37]); SQRADDAC(a[13], a[36]); SQRADDAC(a[14], a[35]); SQRADDAC(a[15], a[34]); SQRADDAC(a[16], a[33]); SQRADDAC(a[17], a[32]); SQRADDAC(a[18], a[31]); SQRADDAC(a[19], a[30]); SQRADDAC(a[20], a[29]); SQRADDAC(a[21], a[28]); SQRADDAC(a[22], a[27]); SQRADDAC(a[23], a[26]); SQRADDAC(a[24], a[25]); SQRADDDB;
+   COMBA_STORE(b[49]);
+
+   /* output 50 */
+   CARRY_FORWARD;
+   SQRADDSC(a[3], a[47]); SQRADDAC(a[4], a[46]); SQRADDAC(a[5], a[45]); SQRADDAC(a[6], a[44]); SQRADDAC(a[7], a[43]); SQRADDAC(a[8], a[42]); SQRADDAC(a[9], a[41]); SQRADDAC(a[10], a[40]); SQRADDAC(a[11], a[39]); SQRADDAC(a[12], a[38]); SQRADDAC(a[13], a[37]); SQRADDAC(a[14], a[36]); SQRADDAC(a[15], a[35]); SQRADDAC(a[16], a[34]); SQRADDAC(a[17], a[33]); SQRADDAC(a[18], a[32]); SQRADDAC(a[19], a[31]); SQRADDAC(a[20], a[30]); SQRADDAC(a[21], a[29]); SQRADDAC(a[22], a[28]); SQRADDAC(a[23], a[27]); SQRADDAC(a[24], a[26]); SQRADDDB; SQRADD(a[25], a[25]);
+   COMBA_STORE(b[50]);
+
+   /* output 51 */
+   CARRY_FORWARD;
+   SQRADDSC(a[4], a[47]); SQRADDAC(a[5], a[46]); SQRADDAC(a[6], a[45]); SQRADDAC(a[7], a[44]); SQRADDAC(a[8], a[43]); SQRADDAC(a[9], a[42]); SQRADDAC(a[10], a[41]); SQRADDAC(a[11], a[40]); SQRADDAC(a[12], a[39]); SQRADDAC(a[13], a[38]); SQRADDAC(a[14], a[37]); SQRADDAC(a[15], a[36]); SQRADDAC(a[16], a[35]); SQRADDAC(a[17], a[34]); SQRADDAC(a[18], a[33]); SQRADDAC(a[19], a[32]); SQRADDAC(a[20], a[31]); SQRADDAC(a[21], a[30]); SQRADDAC(a[22], a[29]); SQRADDAC(a[23], a[28]); SQRADDAC(a[24], a[27]); SQRADDAC(a[25], a[26]); SQRADDDB;
+   COMBA_STORE(b[51]);
+
+   /* output 52 */
+   CARRY_FORWARD;
+   SQRADDSC(a[5], a[47]); SQRADDAC(a[6], a[46]); SQRADDAC(a[7], a[45]); SQRADDAC(a[8], a[44]); SQRADDAC(a[9], a[43]); SQRADDAC(a[10], a[42]); SQRADDAC(a[11], a[41]); SQRADDAC(a[12], a[40]); SQRADDAC(a[13], a[39]); SQRADDAC(a[14], a[38]); SQRADDAC(a[15], a[37]); SQRADDAC(a[16], a[36]); SQRADDAC(a[17], a[35]); SQRADDAC(a[18], a[34]); SQRADDAC(a[19], a[33]); SQRADDAC(a[20], a[32]); SQRADDAC(a[21], a[31]); SQRADDAC(a[22], a[30]); SQRADDAC(a[23], a[29]); SQRADDAC(a[24], a[28]); SQRADDAC(a[25], a[27]); SQRADDDB; SQRADD(a[26], a[26]);
+   COMBA_STORE(b[52]);
+
+   /* output 53 */
+   CARRY_FORWARD;
+   SQRADDSC(a[6], a[47]); SQRADDAC(a[7], a[46]); SQRADDAC(a[8], a[45]); SQRADDAC(a[9], a[44]); SQRADDAC(a[10], a[43]); SQRADDAC(a[11], a[42]); SQRADDAC(a[12], a[41]); SQRADDAC(a[13], a[40]); SQRADDAC(a[14], a[39]); SQRADDAC(a[15], a[38]); SQRADDAC(a[16], a[37]); SQRADDAC(a[17], a[36]); SQRADDAC(a[18], a[35]); SQRADDAC(a[19], a[34]); SQRADDAC(a[20], a[33]); SQRADDAC(a[21], a[32]); SQRADDAC(a[22], a[31]); SQRADDAC(a[23], a[30]); SQRADDAC(a[24], a[29]); SQRADDAC(a[25], a[28]); SQRADDAC(a[26], a[27]); SQRADDDB;
+   COMBA_STORE(b[53]);
+
+   /* output 54 */
+   CARRY_FORWARD;
+   SQRADDSC(a[7], a[47]); SQRADDAC(a[8], a[46]); SQRADDAC(a[9], a[45]); SQRADDAC(a[10], a[44]); SQRADDAC(a[11], a[43]); SQRADDAC(a[12], a[42]); SQRADDAC(a[13], a[41]); SQRADDAC(a[14], a[40]); SQRADDAC(a[15], a[39]); SQRADDAC(a[16], a[38]); SQRADDAC(a[17], a[37]); SQRADDAC(a[18], a[36]); SQRADDAC(a[19], a[35]); SQRADDAC(a[20], a[34]); SQRADDAC(a[21], a[33]); SQRADDAC(a[22], a[32]); SQRADDAC(a[23], a[31]); SQRADDAC(a[24], a[30]); SQRADDAC(a[25], a[29]); SQRADDAC(a[26], a[28]); SQRADDDB; SQRADD(a[27], a[27]);
+   COMBA_STORE(b[54]);
+
+   /* output 55 */
+   CARRY_FORWARD;
+   SQRADDSC(a[8], a[47]); SQRADDAC(a[9], a[46]); SQRADDAC(a[10], a[45]); SQRADDAC(a[11], a[44]); SQRADDAC(a[12], a[43]); SQRADDAC(a[13], a[42]); SQRADDAC(a[14], a[41]); SQRADDAC(a[15], a[40]); SQRADDAC(a[16], a[39]); SQRADDAC(a[17], a[38]); SQRADDAC(a[18], a[37]); SQRADDAC(a[19], a[36]); SQRADDAC(a[20], a[35]); SQRADDAC(a[21], a[34]); SQRADDAC(a[22], a[33]); SQRADDAC(a[23], a[32]); SQRADDAC(a[24], a[31]); SQRADDAC(a[25], a[30]); SQRADDAC(a[26], a[29]); SQRADDAC(a[27], a[28]); SQRADDDB;
+   COMBA_STORE(b[55]);
+
+   /* output 56 */
+   CARRY_FORWARD;
+   SQRADDSC(a[9], a[47]); SQRADDAC(a[10], a[46]); SQRADDAC(a[11], a[45]); SQRADDAC(a[12], a[44]); SQRADDAC(a[13], a[43]); SQRADDAC(a[14], a[42]); SQRADDAC(a[15], a[41]); SQRADDAC(a[16], a[40]); SQRADDAC(a[17], a[39]); SQRADDAC(a[18], a[38]); SQRADDAC(a[19], a[37]); SQRADDAC(a[20], a[36]); SQRADDAC(a[21], a[35]); SQRADDAC(a[22], a[34]); SQRADDAC(a[23], a[33]); SQRADDAC(a[24], a[32]); SQRADDAC(a[25], a[31]); SQRADDAC(a[26], a[30]); SQRADDAC(a[27], a[29]); SQRADDDB; SQRADD(a[28], a[28]);
+   COMBA_STORE(b[56]);
+
+   /* output 57 */
+   CARRY_FORWARD;
+   SQRADDSC(a[10], a[47]); SQRADDAC(a[11], a[46]); SQRADDAC(a[12], a[45]); SQRADDAC(a[13], a[44]); SQRADDAC(a[14], a[43]); SQRADDAC(a[15], a[42]); SQRADDAC(a[16], a[41]); SQRADDAC(a[17], a[40]); SQRADDAC(a[18], a[39]); SQRADDAC(a[19], a[38]); SQRADDAC(a[20], a[37]); SQRADDAC(a[21], a[36]); SQRADDAC(a[22], a[35]); SQRADDAC(a[23], a[34]); SQRADDAC(a[24], a[33]); SQRADDAC(a[25], a[32]); SQRADDAC(a[26], a[31]); SQRADDAC(a[27], a[30]); SQRADDAC(a[28], a[29]); SQRADDDB;
+   COMBA_STORE(b[57]);
+
+   /* output 58 */
+   CARRY_FORWARD;
+   SQRADDSC(a[11], a[47]); SQRADDAC(a[12], a[46]); SQRADDAC(a[13], a[45]); SQRADDAC(a[14], a[44]); SQRADDAC(a[15], a[43]); SQRADDAC(a[16], a[42]); SQRADDAC(a[17], a[41]); SQRADDAC(a[18], a[40]); SQRADDAC(a[19], a[39]); SQRADDAC(a[20], a[38]); SQRADDAC(a[21], a[37]); SQRADDAC(a[22], a[36]); SQRADDAC(a[23], a[35]); SQRADDAC(a[24], a[34]); SQRADDAC(a[25], a[33]); SQRADDAC(a[26], a[32]); SQRADDAC(a[27], a[31]); SQRADDAC(a[28], a[30]); SQRADDDB; SQRADD(a[29], a[29]);
+   COMBA_STORE(b[58]);
+
+   /* output 59 */
+   CARRY_FORWARD;
+   SQRADDSC(a[12], a[47]); SQRADDAC(a[13], a[46]); SQRADDAC(a[14], a[45]); SQRADDAC(a[15], a[44]); SQRADDAC(a[16], a[43]); SQRADDAC(a[17], a[42]); SQRADDAC(a[18], a[41]); SQRADDAC(a[19], a[40]); SQRADDAC(a[20], a[39]); SQRADDAC(a[21], a[38]); SQRADDAC(a[22], a[37]); SQRADDAC(a[23], a[36]); SQRADDAC(a[24], a[35]); SQRADDAC(a[25], a[34]); SQRADDAC(a[26], a[33]); SQRADDAC(a[27], a[32]); SQRADDAC(a[28], a[31]); SQRADDAC(a[29], a[30]); SQRADDDB;
+   COMBA_STORE(b[59]);
+
+   /* output 60 */
+   CARRY_FORWARD;
+   SQRADDSC(a[13], a[47]); SQRADDAC(a[14], a[46]); SQRADDAC(a[15], a[45]); SQRADDAC(a[16], a[44]); SQRADDAC(a[17], a[43]); SQRADDAC(a[18], a[42]); SQRADDAC(a[19], a[41]); SQRADDAC(a[20], a[40]); SQRADDAC(a[21], a[39]); SQRADDAC(a[22], a[38]); SQRADDAC(a[23], a[37]); SQRADDAC(a[24], a[36]); SQRADDAC(a[25], a[35]); SQRADDAC(a[26], a[34]); SQRADDAC(a[27], a[33]); SQRADDAC(a[28], a[32]); SQRADDAC(a[29], a[31]); SQRADDDB; SQRADD(a[30], a[30]);
+   COMBA_STORE(b[60]);
+
+   /* output 61 */
+   CARRY_FORWARD;
+   SQRADDSC(a[14], a[47]); SQRADDAC(a[15], a[46]); SQRADDAC(a[16], a[45]); SQRADDAC(a[17], a[44]); SQRADDAC(a[18], a[43]); SQRADDAC(a[19], a[42]); SQRADDAC(a[20], a[41]); SQRADDAC(a[21], a[40]); SQRADDAC(a[22], a[39]); SQRADDAC(a[23], a[38]); SQRADDAC(a[24], a[37]); SQRADDAC(a[25], a[36]); SQRADDAC(a[26], a[35]); SQRADDAC(a[27], a[34]); SQRADDAC(a[28], a[33]); SQRADDAC(a[29], a[32]); SQRADDAC(a[30], a[31]); SQRADDDB;
+   COMBA_STORE(b[61]);
+
+   /* output 62 */
+   CARRY_FORWARD;
+   SQRADDSC(a[15], a[47]); SQRADDAC(a[16], a[46]); SQRADDAC(a[17], a[45]); SQRADDAC(a[18], a[44]); SQRADDAC(a[19], a[43]); SQRADDAC(a[20], a[42]); SQRADDAC(a[21], a[41]); SQRADDAC(a[22], a[40]); SQRADDAC(a[23], a[39]); SQRADDAC(a[24], a[38]); SQRADDAC(a[25], a[37]); SQRADDAC(a[26], a[36]); SQRADDAC(a[27], a[35]); SQRADDAC(a[28], a[34]); SQRADDAC(a[29], a[33]); SQRADDAC(a[30], a[32]); SQRADDDB; SQRADD(a[31], a[31]);
+   COMBA_STORE(b[62]);
+
+   /* output 63 */
+   CARRY_FORWARD;
+   SQRADDSC(a[16], a[47]); SQRADDAC(a[17], a[46]); SQRADDAC(a[18], a[45]); SQRADDAC(a[19], a[44]); SQRADDAC(a[20], a[43]); SQRADDAC(a[21], a[42]); SQRADDAC(a[22], a[41]); SQRADDAC(a[23], a[40]); SQRADDAC(a[24], a[39]); SQRADDAC(a[25], a[38]); SQRADDAC(a[26], a[37]); SQRADDAC(a[27], a[36]); SQRADDAC(a[28], a[35]); SQRADDAC(a[29], a[34]); SQRADDAC(a[30], a[33]); SQRADDAC(a[31], a[32]); SQRADDDB;
+   COMBA_STORE(b[63]);
+
+   /* output 64 */
+   CARRY_FORWARD;
+   SQRADDSC(a[17], a[47]); SQRADDAC(a[18], a[46]); SQRADDAC(a[19], a[45]); SQRADDAC(a[20], a[44]); SQRADDAC(a[21], a[43]); SQRADDAC(a[22], a[42]); SQRADDAC(a[23], a[41]); SQRADDAC(a[24], a[40]); SQRADDAC(a[25], a[39]); SQRADDAC(a[26], a[38]); SQRADDAC(a[27], a[37]); SQRADDAC(a[28], a[36]); SQRADDAC(a[29], a[35]); SQRADDAC(a[30], a[34]); SQRADDAC(a[31], a[33]); SQRADDDB; SQRADD(a[32], a[32]);
+   COMBA_STORE(b[64]);
+
+   /* output 65 */
+   CARRY_FORWARD;
+   SQRADDSC(a[18], a[47]); SQRADDAC(a[19], a[46]); SQRADDAC(a[20], a[45]); SQRADDAC(a[21], a[44]); SQRADDAC(a[22], a[43]); SQRADDAC(a[23], a[42]); SQRADDAC(a[24], a[41]); SQRADDAC(a[25], a[40]); SQRADDAC(a[26], a[39]); SQRADDAC(a[27], a[38]); SQRADDAC(a[28], a[37]); SQRADDAC(a[29], a[36]); SQRADDAC(a[30], a[35]); SQRADDAC(a[31], a[34]); SQRADDAC(a[32], a[33]); SQRADDDB;
+   COMBA_STORE(b[65]);
+
+   /* output 66 */
+   CARRY_FORWARD;
+   SQRADDSC(a[19], a[47]); SQRADDAC(a[20], a[46]); SQRADDAC(a[21], a[45]); SQRADDAC(a[22], a[44]); SQRADDAC(a[23], a[43]); SQRADDAC(a[24], a[42]); SQRADDAC(a[25], a[41]); SQRADDAC(a[26], a[40]); SQRADDAC(a[27], a[39]); SQRADDAC(a[28], a[38]); SQRADDAC(a[29], a[37]); SQRADDAC(a[30], a[36]); SQRADDAC(a[31], a[35]); SQRADDAC(a[32], a[34]); SQRADDDB; SQRADD(a[33], a[33]);
+   COMBA_STORE(b[66]);
+
+   /* output 67 */
+   CARRY_FORWARD;
+   SQRADDSC(a[20], a[47]); SQRADDAC(a[21], a[46]); SQRADDAC(a[22], a[45]); SQRADDAC(a[23], a[44]); SQRADDAC(a[24], a[43]); SQRADDAC(a[25], a[42]); SQRADDAC(a[26], a[41]); SQRADDAC(a[27], a[40]); SQRADDAC(a[28], a[39]); SQRADDAC(a[29], a[38]); SQRADDAC(a[30], a[37]); SQRADDAC(a[31], a[36]); SQRADDAC(a[32], a[35]); SQRADDAC(a[33], a[34]); SQRADDDB;
+   COMBA_STORE(b[67]);
+
+   /* output 68 */
+   CARRY_FORWARD;
+   SQRADDSC(a[21], a[47]); SQRADDAC(a[22], a[46]); SQRADDAC(a[23], a[45]); SQRADDAC(a[24], a[44]); SQRADDAC(a[25], a[43]); SQRADDAC(a[26], a[42]); SQRADDAC(a[27], a[41]); SQRADDAC(a[28], a[40]); SQRADDAC(a[29], a[39]); SQRADDAC(a[30], a[38]); SQRADDAC(a[31], a[37]); SQRADDAC(a[32], a[36]); SQRADDAC(a[33], a[35]); SQRADDDB; SQRADD(a[34], a[34]);
+   COMBA_STORE(b[68]);
+
+   /* output 69 */
+   CARRY_FORWARD;
+   SQRADDSC(a[22], a[47]); SQRADDAC(a[23], a[46]); SQRADDAC(a[24], a[45]); SQRADDAC(a[25], a[44]); SQRADDAC(a[26], a[43]); SQRADDAC(a[27], a[42]); SQRADDAC(a[28], a[41]); SQRADDAC(a[29], a[40]); SQRADDAC(a[30], a[39]); SQRADDAC(a[31], a[38]); SQRADDAC(a[32], a[37]); SQRADDAC(a[33], a[36]); SQRADDAC(a[34], a[35]); SQRADDDB;
+   COMBA_STORE(b[69]);
+
+   /* output 70 */
+   CARRY_FORWARD;
+   SQRADDSC(a[23], a[47]); SQRADDAC(a[24], a[46]); SQRADDAC(a[25], a[45]); SQRADDAC(a[26], a[44]); SQRADDAC(a[27], a[43]); SQRADDAC(a[28], a[42]); SQRADDAC(a[29], a[41]); SQRADDAC(a[30], a[40]); SQRADDAC(a[31], a[39]); SQRADDAC(a[32], a[38]); SQRADDAC(a[33], a[37]); SQRADDAC(a[34], a[36]); SQRADDDB; SQRADD(a[35], a[35]);
+   COMBA_STORE(b[70]);
+
+   /* output 71 */
+   CARRY_FORWARD;
+   SQRADDSC(a[24], a[47]); SQRADDAC(a[25], a[46]); SQRADDAC(a[26], a[45]); SQRADDAC(a[27], a[44]); SQRADDAC(a[28], a[43]); SQRADDAC(a[29], a[42]); SQRADDAC(a[30], a[41]); SQRADDAC(a[31], a[40]); SQRADDAC(a[32], a[39]); SQRADDAC(a[33], a[38]); SQRADDAC(a[34], a[37]); SQRADDAC(a[35], a[36]); SQRADDDB;
+   COMBA_STORE(b[71]);
+
+   /* output 72 */
+   CARRY_FORWARD;
+   SQRADDSC(a[25], a[47]); SQRADDAC(a[26], a[46]); SQRADDAC(a[27], a[45]); SQRADDAC(a[28], a[44]); SQRADDAC(a[29], a[43]); SQRADDAC(a[30], a[42]); SQRADDAC(a[31], a[41]); SQRADDAC(a[32], a[40]); SQRADDAC(a[33], a[39]); SQRADDAC(a[34], a[38]); SQRADDAC(a[35], a[37]); SQRADDDB; SQRADD(a[36], a[36]);
+   COMBA_STORE(b[72]);
+
+   /* output 73 */
+   CARRY_FORWARD;
+   SQRADDSC(a[26], a[47]); SQRADDAC(a[27], a[46]); SQRADDAC(a[28], a[45]); SQRADDAC(a[29], a[44]); SQRADDAC(a[30], a[43]); SQRADDAC(a[31], a[42]); SQRADDAC(a[32], a[41]); SQRADDAC(a[33], a[40]); SQRADDAC(a[34], a[39]); SQRADDAC(a[35], a[38]); SQRADDAC(a[36], a[37]); SQRADDDB;
+   COMBA_STORE(b[73]);
+
+   /* output 74 */
+   CARRY_FORWARD;
+   SQRADDSC(a[27], a[47]); SQRADDAC(a[28], a[46]); SQRADDAC(a[29], a[45]); SQRADDAC(a[30], a[44]); SQRADDAC(a[31], a[43]); SQRADDAC(a[32], a[42]); SQRADDAC(a[33], a[41]); SQRADDAC(a[34], a[40]); SQRADDAC(a[35], a[39]); SQRADDAC(a[36], a[38]); SQRADDDB; SQRADD(a[37], a[37]);
+   COMBA_STORE(b[74]);
+
+   /* output 75 */
+   CARRY_FORWARD;
+   SQRADDSC(a[28], a[47]); SQRADDAC(a[29], a[46]); SQRADDAC(a[30], a[45]); SQRADDAC(a[31], a[44]); SQRADDAC(a[32], a[43]); SQRADDAC(a[33], a[42]); SQRADDAC(a[34], a[41]); SQRADDAC(a[35], a[40]); SQRADDAC(a[36], a[39]); SQRADDAC(a[37], a[38]); SQRADDDB;
+   COMBA_STORE(b[75]);
+
+   /* output 76 */
+   CARRY_FORWARD;
+   SQRADDSC(a[29], a[47]); SQRADDAC(a[30], a[46]); SQRADDAC(a[31], a[45]); SQRADDAC(a[32], a[44]); SQRADDAC(a[33], a[43]); SQRADDAC(a[34], a[42]); SQRADDAC(a[35], a[41]); SQRADDAC(a[36], a[40]); SQRADDAC(a[37], a[39]); SQRADDDB; SQRADD(a[38], a[38]);
+   COMBA_STORE(b[76]);
+
+   /* output 77 */
+   CARRY_FORWARD;
+   SQRADDSC(a[30], a[47]); SQRADDAC(a[31], a[46]); SQRADDAC(a[32], a[45]); SQRADDAC(a[33], a[44]); SQRADDAC(a[34], a[43]); SQRADDAC(a[35], a[42]); SQRADDAC(a[36], a[41]); SQRADDAC(a[37], a[40]); SQRADDAC(a[38], a[39]); SQRADDDB;
+   COMBA_STORE(b[77]);
+
+   /* output 78 */
+   CARRY_FORWARD;
+   SQRADDSC(a[31], a[47]); SQRADDAC(a[32], a[46]); SQRADDAC(a[33], a[45]); SQRADDAC(a[34], a[44]); SQRADDAC(a[35], a[43]); SQRADDAC(a[36], a[42]); SQRADDAC(a[37], a[41]); SQRADDAC(a[38], a[40]); SQRADDDB; SQRADD(a[39], a[39]);
+   COMBA_STORE(b[78]);
+
+   /* output 79 */
+   CARRY_FORWARD;
+   SQRADDSC(a[32], a[47]); SQRADDAC(a[33], a[46]); SQRADDAC(a[34], a[45]); SQRADDAC(a[35], a[44]); SQRADDAC(a[36], a[43]); SQRADDAC(a[37], a[42]); SQRADDAC(a[38], a[41]); SQRADDAC(a[39], a[40]); SQRADDDB;
+   COMBA_STORE(b[79]);
+
+   /* output 80 */
+   CARRY_FORWARD;
+   SQRADDSC(a[33], a[47]); SQRADDAC(a[34], a[46]); SQRADDAC(a[35], a[45]); SQRADDAC(a[36], a[44]); SQRADDAC(a[37], a[43]); SQRADDAC(a[38], a[42]); SQRADDAC(a[39], a[41]); SQRADDDB; SQRADD(a[40], a[40]);
+   COMBA_STORE(b[80]);
+
+   /* output 81 */
+   CARRY_FORWARD;
+   SQRADDSC(a[34], a[47]); SQRADDAC(a[35], a[46]); SQRADDAC(a[36], a[45]); SQRADDAC(a[37], a[44]); SQRADDAC(a[38], a[43]); SQRADDAC(a[39], a[42]); SQRADDAC(a[40], a[41]); SQRADDDB;
+   COMBA_STORE(b[81]);
+
+   /* output 82 */
+   CARRY_FORWARD;
+   SQRADDSC(a[35], a[47]); SQRADDAC(a[36], a[46]); SQRADDAC(a[37], a[45]); SQRADDAC(a[38], a[44]); SQRADDAC(a[39], a[43]); SQRADDAC(a[40], a[42]); SQRADDDB; SQRADD(a[41], a[41]);
+   COMBA_STORE(b[82]);
+
+   /* output 83 */
+   CARRY_FORWARD;
+   SQRADDSC(a[36], a[47]); SQRADDAC(a[37], a[46]); SQRADDAC(a[38], a[45]); SQRADDAC(a[39], a[44]); SQRADDAC(a[40], a[43]); SQRADDAC(a[41], a[42]); SQRADDDB;
+   COMBA_STORE(b[83]);
+
+   /* output 84 */
+   CARRY_FORWARD;
+   SQRADDSC(a[37], a[47]); SQRADDAC(a[38], a[46]); SQRADDAC(a[39], a[45]); SQRADDAC(a[40], a[44]); SQRADDAC(a[41], a[43]); SQRADDDB; SQRADD(a[42], a[42]);
+   COMBA_STORE(b[84]);
+
+   /* output 85 */
+   CARRY_FORWARD;
+   SQRADDSC(a[38], a[47]); SQRADDAC(a[39], a[46]); SQRADDAC(a[40], a[45]); SQRADDAC(a[41], a[44]); SQRADDAC(a[42], a[43]); SQRADDDB;
+   COMBA_STORE(b[85]);
+
+   /* output 86 */
+   CARRY_FORWARD;
+   SQRADDSC(a[39], a[47]); SQRADDAC(a[40], a[46]); SQRADDAC(a[41], a[45]); SQRADDAC(a[42], a[44]); SQRADDDB; SQRADD(a[43], a[43]);
+   COMBA_STORE(b[86]);
+
+   /* output 87 */
+   CARRY_FORWARD;
+   SQRADDSC(a[40], a[47]); SQRADDAC(a[41], a[46]); SQRADDAC(a[42], a[45]); SQRADDAC(a[43], a[44]); SQRADDDB;
+   COMBA_STORE(b[87]);
+
+   /* output 88 */
+   CARRY_FORWARD;
+   SQRADDSC(a[41], a[47]); SQRADDAC(a[42], a[46]); SQRADDAC(a[43], a[45]); SQRADDDB; SQRADD(a[44], a[44]);
+   COMBA_STORE(b[88]);
+
+   /* output 89 */
+   CARRY_FORWARD;
+   SQRADDSC(a[42], a[47]); SQRADDAC(a[43], a[46]); SQRADDAC(a[44], a[45]); SQRADDDB;
+   COMBA_STORE(b[89]);
+
+   /* output 90 */
+   CARRY_FORWARD;
+   SQRADD2(a[43], a[47]); SQRADD2(a[44], a[46]); SQRADD(a[45], a[45]);
+   COMBA_STORE(b[90]);
+
+   /* output 91 */
+   CARRY_FORWARD;
+   SQRADD2(a[44], a[47]); SQRADD2(a[45], a[46]);
+   COMBA_STORE(b[91]);
+
+   /* output 92 */
+   CARRY_FORWARD;
+   SQRADD2(a[45], a[47]); SQRADD(a[46], a[46]);
+   COMBA_STORE(b[92]);
+
+   /* output 93 */
+   CARRY_FORWARD;
+   SQRADD2(a[46], a[47]);
+   COMBA_STORE(b[93]);
+
+   /* output 94 */
+   CARRY_FORWARD;
+   SQRADD(a[47], a[47]);
+   COMBA_STORE(b[94]);
+   COMBA_STORE2(b[95]);
+   COMBA_FINI;
+
+   B->used = 96;
+   B->sign = FP_ZPOS;
+   memcpy(B->dp, b, 96 * sizeof(fp_digit));
+   fp_clamp(B);
+}
+#endif
+
+
+/* $Source$ */
+/* $Revision$ */
+/* $Date$ */
diff --git a/tomsfastmath/src/sqr/fp_sqr_comba_6.c b/tomsfastmath/src/sqr/fp_sqr_comba_6.c
new file mode 100644 (file)
index 0000000..e86c144
--- /dev/null
@@ -0,0 +1,84 @@
+#define TFM_DEFINES
+#include "fp_sqr_comba.c"
+
+#if defined(TFM_SQR6) && FP_SIZE >= 12
+void fp_sqr_comba6(fp_int *A, fp_int *B)
+{
+   fp_digit *a, b[12], c0, c1, c2, sc0, sc1, sc2;
+#ifdef TFM_ISO
+   fp_word tt;
+#endif
+
+   a = A->dp;
+   COMBA_START;
+
+   /* clear carries */
+   CLEAR_CARRY;
+
+   /* output 0 */
+   SQRADD(a[0],a[0]);
+   COMBA_STORE(b[0]);
+
+   /* output 1 */
+   CARRY_FORWARD;
+   SQRADD2(a[0], a[1]);
+   COMBA_STORE(b[1]);
+
+   /* output 2 */
+   CARRY_FORWARD;
+   SQRADD2(a[0], a[2]); SQRADD(a[1], a[1]);
+   COMBA_STORE(b[2]);
+
+   /* output 3 */
+   CARRY_FORWARD;
+   SQRADD2(a[0], a[3]); SQRADD2(a[1], a[2]);
+   COMBA_STORE(b[3]);
+
+   /* output 4 */
+   CARRY_FORWARD;
+   SQRADD2(a[0], a[4]); SQRADD2(a[1], a[3]); SQRADD(a[2], a[2]);
+   COMBA_STORE(b[4]);
+
+   /* output 5 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[5]); SQRADDAC(a[1], a[4]); SQRADDAC(a[2], a[3]); SQRADDDB;
+   COMBA_STORE(b[5]);
+
+   /* output 6 */
+   CARRY_FORWARD;
+   SQRADD2(a[1], a[5]); SQRADD2(a[2], a[4]); SQRADD(a[3], a[3]);
+   COMBA_STORE(b[6]);
+
+   /* output 7 */
+   CARRY_FORWARD;
+   SQRADD2(a[2], a[5]); SQRADD2(a[3], a[4]);
+   COMBA_STORE(b[7]);
+
+   /* output 8 */
+   CARRY_FORWARD;
+   SQRADD2(a[3], a[5]); SQRADD(a[4], a[4]);
+   COMBA_STORE(b[8]);
+
+   /* output 9 */
+   CARRY_FORWARD;
+   SQRADD2(a[4], a[5]);
+   COMBA_STORE(b[9]);
+
+   /* output 10 */
+   CARRY_FORWARD;
+   SQRADD(a[5], a[5]);
+   COMBA_STORE(b[10]);
+   COMBA_STORE2(b[11]);
+   COMBA_FINI;
+
+   B->used = 12;
+   B->sign = FP_ZPOS;
+   memcpy(B->dp, b, 12 * sizeof(fp_digit));
+   fp_clamp(B);
+}
+#endif
+
+
+/* $Source$ */
+/* $Revision$ */
+/* $Date$ */
diff --git a/tomsfastmath/src/sqr/fp_sqr_comba_64.c b/tomsfastmath/src/sqr/fp_sqr_comba_64.c
new file mode 100644 (file)
index 0000000..f2a66e6
--- /dev/null
@@ -0,0 +1,664 @@
+#define TFM_DEFINES
+#include "fp_sqr_comba.c"
+
+#if defined(TFM_SQR64) && FP_SIZE >= 128
+void fp_sqr_comba64(fp_int *A, fp_int *B)
+{
+   fp_digit *a, b[128], c0, c1, c2, sc0, sc1, sc2;
+#ifdef TFM_ISO
+   fp_word tt;
+#endif
+
+   a = A->dp;
+   COMBA_START;
+
+   /* clear carries */
+   CLEAR_CARRY;
+
+   /* output 0 */
+   SQRADD(a[0],a[0]);
+   COMBA_STORE(b[0]);
+
+   /* output 1 */
+   CARRY_FORWARD;
+   SQRADD2(a[0], a[1]);
+   COMBA_STORE(b[1]);
+
+   /* output 2 */
+   CARRY_FORWARD;
+   SQRADD2(a[0], a[2]); SQRADD(a[1], a[1]);
+   COMBA_STORE(b[2]);
+
+   /* output 3 */
+   CARRY_FORWARD;
+   SQRADD2(a[0], a[3]); SQRADD2(a[1], a[2]);
+   COMBA_STORE(b[3]);
+
+   /* output 4 */
+   CARRY_FORWARD;
+   SQRADD2(a[0], a[4]); SQRADD2(a[1], a[3]); SQRADD(a[2], a[2]);
+   COMBA_STORE(b[4]);
+
+   /* output 5 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[5]); SQRADDAC(a[1], a[4]); SQRADDAC(a[2], a[3]); SQRADDDB;
+   COMBA_STORE(b[5]);
+
+   /* output 6 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[6]); SQRADDAC(a[1], a[5]); SQRADDAC(a[2], a[4]); SQRADDDB; SQRADD(a[3], a[3]);
+   COMBA_STORE(b[6]);
+
+   /* output 7 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[7]); SQRADDAC(a[1], a[6]); SQRADDAC(a[2], a[5]); SQRADDAC(a[3], a[4]); SQRADDDB;
+   COMBA_STORE(b[7]);
+
+   /* output 8 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[8]); SQRADDAC(a[1], a[7]); SQRADDAC(a[2], a[6]); SQRADDAC(a[3], a[5]); SQRADDDB; SQRADD(a[4], a[4]);
+   COMBA_STORE(b[8]);
+
+   /* output 9 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[9]); SQRADDAC(a[1], a[8]); SQRADDAC(a[2], a[7]); SQRADDAC(a[3], a[6]); SQRADDAC(a[4], a[5]); SQRADDDB;
+   COMBA_STORE(b[9]);
+
+   /* output 10 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[10]); SQRADDAC(a[1], a[9]); SQRADDAC(a[2], a[8]); SQRADDAC(a[3], a[7]); SQRADDAC(a[4], a[6]); SQRADDDB; SQRADD(a[5], a[5]);
+   COMBA_STORE(b[10]);
+
+   /* output 11 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[11]); SQRADDAC(a[1], a[10]); SQRADDAC(a[2], a[9]); SQRADDAC(a[3], a[8]); SQRADDAC(a[4], a[7]); SQRADDAC(a[5], a[6]); SQRADDDB;
+   COMBA_STORE(b[11]);
+
+   /* output 12 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[12]); SQRADDAC(a[1], a[11]); SQRADDAC(a[2], a[10]); SQRADDAC(a[3], a[9]); SQRADDAC(a[4], a[8]); SQRADDAC(a[5], a[7]); SQRADDDB; SQRADD(a[6], a[6]);
+   COMBA_STORE(b[12]);
+
+   /* output 13 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[13]); SQRADDAC(a[1], a[12]); SQRADDAC(a[2], a[11]); SQRADDAC(a[3], a[10]); SQRADDAC(a[4], a[9]); SQRADDAC(a[5], a[8]); SQRADDAC(a[6], a[7]); SQRADDDB;
+   COMBA_STORE(b[13]);
+
+   /* output 14 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[14]); SQRADDAC(a[1], a[13]); SQRADDAC(a[2], a[12]); SQRADDAC(a[3], a[11]); SQRADDAC(a[4], a[10]); SQRADDAC(a[5], a[9]); SQRADDAC(a[6], a[8]); SQRADDDB; SQRADD(a[7], a[7]);
+   COMBA_STORE(b[14]);
+
+   /* output 15 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[15]); SQRADDAC(a[1], a[14]); SQRADDAC(a[2], a[13]); SQRADDAC(a[3], a[12]); SQRADDAC(a[4], a[11]); SQRADDAC(a[5], a[10]); SQRADDAC(a[6], a[9]); SQRADDAC(a[7], a[8]); SQRADDDB;
+   COMBA_STORE(b[15]);
+
+   /* output 16 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[16]); SQRADDAC(a[1], a[15]); SQRADDAC(a[2], a[14]); SQRADDAC(a[3], a[13]); SQRADDAC(a[4], a[12]); SQRADDAC(a[5], a[11]); SQRADDAC(a[6], a[10]); SQRADDAC(a[7], a[9]); SQRADDDB; SQRADD(a[8], a[8]);
+   COMBA_STORE(b[16]);
+
+   /* output 17 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[17]); SQRADDAC(a[1], a[16]); SQRADDAC(a[2], a[15]); SQRADDAC(a[3], a[14]); SQRADDAC(a[4], a[13]); SQRADDAC(a[5], a[12]); SQRADDAC(a[6], a[11]); SQRADDAC(a[7], a[10]); SQRADDAC(a[8], a[9]); SQRADDDB;
+   COMBA_STORE(b[17]);
+
+   /* output 18 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[18]); SQRADDAC(a[1], a[17]); SQRADDAC(a[2], a[16]); SQRADDAC(a[3], a[15]); SQRADDAC(a[4], a[14]); SQRADDAC(a[5], a[13]); SQRADDAC(a[6], a[12]); SQRADDAC(a[7], a[11]); SQRADDAC(a[8], a[10]); SQRADDDB; SQRADD(a[9], a[9]);
+   COMBA_STORE(b[18]);
+
+   /* output 19 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[19]); SQRADDAC(a[1], a[18]); SQRADDAC(a[2], a[17]); SQRADDAC(a[3], a[16]); SQRADDAC(a[4], a[15]); SQRADDAC(a[5], a[14]); SQRADDAC(a[6], a[13]); SQRADDAC(a[7], a[12]); SQRADDAC(a[8], a[11]); SQRADDAC(a[9], a[10]); SQRADDDB;
+   COMBA_STORE(b[19]);
+
+   /* output 20 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[20]); SQRADDAC(a[1], a[19]); SQRADDAC(a[2], a[18]); SQRADDAC(a[3], a[17]); SQRADDAC(a[4], a[16]); SQRADDAC(a[5], a[15]); SQRADDAC(a[6], a[14]); SQRADDAC(a[7], a[13]); SQRADDAC(a[8], a[12]); SQRADDAC(a[9], a[11]); SQRADDDB; SQRADD(a[10], a[10]);
+   COMBA_STORE(b[20]);
+
+   /* output 21 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[21]); SQRADDAC(a[1], a[20]); SQRADDAC(a[2], a[19]); SQRADDAC(a[3], a[18]); SQRADDAC(a[4], a[17]); SQRADDAC(a[5], a[16]); SQRADDAC(a[6], a[15]); SQRADDAC(a[7], a[14]); SQRADDAC(a[8], a[13]); SQRADDAC(a[9], a[12]); SQRADDAC(a[10], a[11]); SQRADDDB;
+   COMBA_STORE(b[21]);
+
+   /* output 22 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[22]); SQRADDAC(a[1], a[21]); SQRADDAC(a[2], a[20]); SQRADDAC(a[3], a[19]); SQRADDAC(a[4], a[18]); SQRADDAC(a[5], a[17]); SQRADDAC(a[6], a[16]); SQRADDAC(a[7], a[15]); SQRADDAC(a[8], a[14]); SQRADDAC(a[9], a[13]); SQRADDAC(a[10], a[12]); SQRADDDB; SQRADD(a[11], a[11]);
+   COMBA_STORE(b[22]);
+
+   /* output 23 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[23]); SQRADDAC(a[1], a[22]); SQRADDAC(a[2], a[21]); SQRADDAC(a[3], a[20]); SQRADDAC(a[4], a[19]); SQRADDAC(a[5], a[18]); SQRADDAC(a[6], a[17]); SQRADDAC(a[7], a[16]); SQRADDAC(a[8], a[15]); SQRADDAC(a[9], a[14]); SQRADDAC(a[10], a[13]); SQRADDAC(a[11], a[12]); SQRADDDB;
+   COMBA_STORE(b[23]);
+
+   /* output 24 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[24]); SQRADDAC(a[1], a[23]); SQRADDAC(a[2], a[22]); SQRADDAC(a[3], a[21]); SQRADDAC(a[4], a[20]); SQRADDAC(a[5], a[19]); SQRADDAC(a[6], a[18]); SQRADDAC(a[7], a[17]); SQRADDAC(a[8], a[16]); SQRADDAC(a[9], a[15]); SQRADDAC(a[10], a[14]); SQRADDAC(a[11], a[13]); SQRADDDB; SQRADD(a[12], a[12]);
+   COMBA_STORE(b[24]);
+
+   /* output 25 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[25]); SQRADDAC(a[1], a[24]); SQRADDAC(a[2], a[23]); SQRADDAC(a[3], a[22]); SQRADDAC(a[4], a[21]); SQRADDAC(a[5], a[20]); SQRADDAC(a[6], a[19]); SQRADDAC(a[7], a[18]); SQRADDAC(a[8], a[17]); SQRADDAC(a[9], a[16]); SQRADDAC(a[10], a[15]); SQRADDAC(a[11], a[14]); SQRADDAC(a[12], a[13]); SQRADDDB;
+   COMBA_STORE(b[25]);
+
+   /* output 26 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[26]); SQRADDAC(a[1], a[25]); SQRADDAC(a[2], a[24]); SQRADDAC(a[3], a[23]); SQRADDAC(a[4], a[22]); SQRADDAC(a[5], a[21]); SQRADDAC(a[6], a[20]); SQRADDAC(a[7], a[19]); SQRADDAC(a[8], a[18]); SQRADDAC(a[9], a[17]); SQRADDAC(a[10], a[16]); SQRADDAC(a[11], a[15]); SQRADDAC(a[12], a[14]); SQRADDDB; SQRADD(a[13], a[13]);
+   COMBA_STORE(b[26]);
+
+   /* output 27 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[27]); SQRADDAC(a[1], a[26]); SQRADDAC(a[2], a[25]); SQRADDAC(a[3], a[24]); SQRADDAC(a[4], a[23]); SQRADDAC(a[5], a[22]); SQRADDAC(a[6], a[21]); SQRADDAC(a[7], a[20]); SQRADDAC(a[8], a[19]); SQRADDAC(a[9], a[18]); SQRADDAC(a[10], a[17]); SQRADDAC(a[11], a[16]); SQRADDAC(a[12], a[15]); SQRADDAC(a[13], a[14]); SQRADDDB;
+   COMBA_STORE(b[27]);
+
+   /* output 28 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[28]); SQRADDAC(a[1], a[27]); SQRADDAC(a[2], a[26]); SQRADDAC(a[3], a[25]); SQRADDAC(a[4], a[24]); SQRADDAC(a[5], a[23]); SQRADDAC(a[6], a[22]); SQRADDAC(a[7], a[21]); SQRADDAC(a[8], a[20]); SQRADDAC(a[9], a[19]); SQRADDAC(a[10], a[18]); SQRADDAC(a[11], a[17]); SQRADDAC(a[12], a[16]); SQRADDAC(a[13], a[15]); SQRADDDB; SQRADD(a[14], a[14]);
+   COMBA_STORE(b[28]);
+
+   /* output 29 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[29]); SQRADDAC(a[1], a[28]); SQRADDAC(a[2], a[27]); SQRADDAC(a[3], a[26]); SQRADDAC(a[4], a[25]); SQRADDAC(a[5], a[24]); SQRADDAC(a[6], a[23]); SQRADDAC(a[7], a[22]); SQRADDAC(a[8], a[21]); SQRADDAC(a[9], a[20]); SQRADDAC(a[10], a[19]); SQRADDAC(a[11], a[18]); SQRADDAC(a[12], a[17]); SQRADDAC(a[13], a[16]); SQRADDAC(a[14], a[15]); SQRADDDB;
+   COMBA_STORE(b[29]);
+
+   /* output 30 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[30]); SQRADDAC(a[1], a[29]); SQRADDAC(a[2], a[28]); SQRADDAC(a[3], a[27]); SQRADDAC(a[4], a[26]); SQRADDAC(a[5], a[25]); SQRADDAC(a[6], a[24]); SQRADDAC(a[7], a[23]); SQRADDAC(a[8], a[22]); SQRADDAC(a[9], a[21]); SQRADDAC(a[10], a[20]); SQRADDAC(a[11], a[19]); SQRADDAC(a[12], a[18]); SQRADDAC(a[13], a[17]); SQRADDAC(a[14], a[16]); SQRADDDB; SQRADD(a[15], a[15]);
+   COMBA_STORE(b[30]);
+
+   /* output 31 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[31]); SQRADDAC(a[1], a[30]); SQRADDAC(a[2], a[29]); SQRADDAC(a[3], a[28]); SQRADDAC(a[4], a[27]); SQRADDAC(a[5], a[26]); SQRADDAC(a[6], a[25]); SQRADDAC(a[7], a[24]); SQRADDAC(a[8], a[23]); SQRADDAC(a[9], a[22]); SQRADDAC(a[10], a[21]); SQRADDAC(a[11], a[20]); SQRADDAC(a[12], a[19]); SQRADDAC(a[13], a[18]); SQRADDAC(a[14], a[17]); SQRADDAC(a[15], a[16]); SQRADDDB;
+   COMBA_STORE(b[31]);
+
+   /* output 32 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[32]); SQRADDAC(a[1], a[31]); SQRADDAC(a[2], a[30]); SQRADDAC(a[3], a[29]); SQRADDAC(a[4], a[28]); SQRADDAC(a[5], a[27]); SQRADDAC(a[6], a[26]); SQRADDAC(a[7], a[25]); SQRADDAC(a[8], a[24]); SQRADDAC(a[9], a[23]); SQRADDAC(a[10], a[22]); SQRADDAC(a[11], a[21]); SQRADDAC(a[12], a[20]); SQRADDAC(a[13], a[19]); SQRADDAC(a[14], a[18]); SQRADDAC(a[15], a[17]); SQRADDDB; SQRADD(a[16], a[16]);
+   COMBA_STORE(b[32]);
+
+   /* output 33 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[33]); SQRADDAC(a[1], a[32]); SQRADDAC(a[2], a[31]); SQRADDAC(a[3], a[30]); SQRADDAC(a[4], a[29]); SQRADDAC(a[5], a[28]); SQRADDAC(a[6], a[27]); SQRADDAC(a[7], a[26]); SQRADDAC(a[8], a[25]); SQRADDAC(a[9], a[24]); SQRADDAC(a[10], a[23]); SQRADDAC(a[11], a[22]); SQRADDAC(a[12], a[21]); SQRADDAC(a[13], a[20]); SQRADDAC(a[14], a[19]); SQRADDAC(a[15], a[18]); SQRADDAC(a[16], a[17]); SQRADDDB;
+   COMBA_STORE(b[33]);
+
+   /* output 34 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[34]); SQRADDAC(a[1], a[33]); SQRADDAC(a[2], a[32]); SQRADDAC(a[3], a[31]); SQRADDAC(a[4], a[30]); SQRADDAC(a[5], a[29]); SQRADDAC(a[6], a[28]); SQRADDAC(a[7], a[27]); SQRADDAC(a[8], a[26]); SQRADDAC(a[9], a[25]); SQRADDAC(a[10], a[24]); SQRADDAC(a[11], a[23]); SQRADDAC(a[12], a[22]); SQRADDAC(a[13], a[21]); SQRADDAC(a[14], a[20]); SQRADDAC(a[15], a[19]); SQRADDAC(a[16], a[18]); SQRADDDB; SQRADD(a[17], a[17]);
+   COMBA_STORE(b[34]);
+
+   /* output 35 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[35]); SQRADDAC(a[1], a[34]); SQRADDAC(a[2], a[33]); SQRADDAC(a[3], a[32]); SQRADDAC(a[4], a[31]); SQRADDAC(a[5], a[30]); SQRADDAC(a[6], a[29]); SQRADDAC(a[7], a[28]); SQRADDAC(a[8], a[27]); SQRADDAC(a[9], a[26]); SQRADDAC(a[10], a[25]); SQRADDAC(a[11], a[24]); SQRADDAC(a[12], a[23]); SQRADDAC(a[13], a[22]); SQRADDAC(a[14], a[21]); SQRADDAC(a[15], a[20]); SQRADDAC(a[16], a[19]); SQRADDAC(a[17], a[18]); SQRADDDB;
+   COMBA_STORE(b[35]);
+
+   /* output 36 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[36]); SQRADDAC(a[1], a[35]); SQRADDAC(a[2], a[34]); SQRADDAC(a[3], a[33]); SQRADDAC(a[4], a[32]); SQRADDAC(a[5], a[31]); SQRADDAC(a[6], a[30]); SQRADDAC(a[7], a[29]); SQRADDAC(a[8], a[28]); SQRADDAC(a[9], a[27]); SQRADDAC(a[10], a[26]); SQRADDAC(a[11], a[25]); SQRADDAC(a[12], a[24]); SQRADDAC(a[13], a[23]); SQRADDAC(a[14], a[22]); SQRADDAC(a[15], a[21]); SQRADDAC(a[16], a[20]); SQRADDAC(a[17], a[19]); SQRADDDB; SQRADD(a[18], a[18]);
+   COMBA_STORE(b[36]);
+
+   /* output 37 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[37]); SQRADDAC(a[1], a[36]); SQRADDAC(a[2], a[35]); SQRADDAC(a[3], a[34]); SQRADDAC(a[4], a[33]); SQRADDAC(a[5], a[32]); SQRADDAC(a[6], a[31]); SQRADDAC(a[7], a[30]); SQRADDAC(a[8], a[29]); SQRADDAC(a[9], a[28]); SQRADDAC(a[10], a[27]); SQRADDAC(a[11], a[26]); SQRADDAC(a[12], a[25]); SQRADDAC(a[13], a[24]); SQRADDAC(a[14], a[23]); SQRADDAC(a[15], a[22]); SQRADDAC(a[16], a[21]); SQRADDAC(a[17], a[20]); SQRADDAC(a[18], a[19]); SQRADDDB;
+   COMBA_STORE(b[37]);
+
+   /* output 38 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[38]); SQRADDAC(a[1], a[37]); SQRADDAC(a[2], a[36]); SQRADDAC(a[3], a[35]); SQRADDAC(a[4], a[34]); SQRADDAC(a[5], a[33]); SQRADDAC(a[6], a[32]); SQRADDAC(a[7], a[31]); SQRADDAC(a[8], a[30]); SQRADDAC(a[9], a[29]); SQRADDAC(a[10], a[28]); SQRADDAC(a[11], a[27]); SQRADDAC(a[12], a[26]); SQRADDAC(a[13], a[25]); SQRADDAC(a[14], a[24]); SQRADDAC(a[15], a[23]); SQRADDAC(a[16], a[22]); SQRADDAC(a[17], a[21]); SQRADDAC(a[18], a[20]); SQRADDDB; SQRADD(a[19], a[19]);
+   COMBA_STORE(b[38]);
+
+   /* output 39 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[39]); SQRADDAC(a[1], a[38]); SQRADDAC(a[2], a[37]); SQRADDAC(a[3], a[36]); SQRADDAC(a[4], a[35]); SQRADDAC(a[5], a[34]); SQRADDAC(a[6], a[33]); SQRADDAC(a[7], a[32]); SQRADDAC(a[8], a[31]); SQRADDAC(a[9], a[30]); SQRADDAC(a[10], a[29]); SQRADDAC(a[11], a[28]); SQRADDAC(a[12], a[27]); SQRADDAC(a[13], a[26]); SQRADDAC(a[14], a[25]); SQRADDAC(a[15], a[24]); SQRADDAC(a[16], a[23]); SQRADDAC(a[17], a[22]); SQRADDAC(a[18], a[21]); SQRADDAC(a[19], a[20]); SQRADDDB;
+   COMBA_STORE(b[39]);
+
+   /* output 40 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[40]); SQRADDAC(a[1], a[39]); SQRADDAC(a[2], a[38]); SQRADDAC(a[3], a[37]); SQRADDAC(a[4], a[36]); SQRADDAC(a[5], a[35]); SQRADDAC(a[6], a[34]); SQRADDAC(a[7], a[33]); SQRADDAC(a[8], a[32]); SQRADDAC(a[9], a[31]); SQRADDAC(a[10], a[30]); SQRADDAC(a[11], a[29]); SQRADDAC(a[12], a[28]); SQRADDAC(a[13], a[27]); SQRADDAC(a[14], a[26]); SQRADDAC(a[15], a[25]); SQRADDAC(a[16], a[24]); SQRADDAC(a[17], a[23]); SQRADDAC(a[18], a[22]); SQRADDAC(a[19], a[21]); SQRADDDB; SQRADD(a[20], a[20]);
+   COMBA_STORE(b[40]);
+
+   /* output 41 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[41]); SQRADDAC(a[1], a[40]); SQRADDAC(a[2], a[39]); SQRADDAC(a[3], a[38]); SQRADDAC(a[4], a[37]); SQRADDAC(a[5], a[36]); SQRADDAC(a[6], a[35]); SQRADDAC(a[7], a[34]); SQRADDAC(a[8], a[33]); SQRADDAC(a[9], a[32]); SQRADDAC(a[10], a[31]); SQRADDAC(a[11], a[30]); SQRADDAC(a[12], a[29]); SQRADDAC(a[13], a[28]); SQRADDAC(a[14], a[27]); SQRADDAC(a[15], a[26]); SQRADDAC(a[16], a[25]); SQRADDAC(a[17], a[24]); SQRADDAC(a[18], a[23]); SQRADDAC(a[19], a[22]); SQRADDAC(a[20], a[21]); SQRADDDB;
+   COMBA_STORE(b[41]);
+
+   /* output 42 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[42]); SQRADDAC(a[1], a[41]); SQRADDAC(a[2], a[40]); SQRADDAC(a[3], a[39]); SQRADDAC(a[4], a[38]); SQRADDAC(a[5], a[37]); SQRADDAC(a[6], a[36]); SQRADDAC(a[7], a[35]); SQRADDAC(a[8], a[34]); SQRADDAC(a[9], a[33]); SQRADDAC(a[10], a[32]); SQRADDAC(a[11], a[31]); SQRADDAC(a[12], a[30]); SQRADDAC(a[13], a[29]); SQRADDAC(a[14], a[28]); SQRADDAC(a[15], a[27]); SQRADDAC(a[16], a[26]); SQRADDAC(a[17], a[25]); SQRADDAC(a[18], a[24]); SQRADDAC(a[19], a[23]); SQRADDAC(a[20], a[22]); SQRADDDB; SQRADD(a[21], a[21]);
+   COMBA_STORE(b[42]);
+
+   /* output 43 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[43]); SQRADDAC(a[1], a[42]); SQRADDAC(a[2], a[41]); SQRADDAC(a[3], a[40]); SQRADDAC(a[4], a[39]); SQRADDAC(a[5], a[38]); SQRADDAC(a[6], a[37]); SQRADDAC(a[7], a[36]); SQRADDAC(a[8], a[35]); SQRADDAC(a[9], a[34]); SQRADDAC(a[10], a[33]); SQRADDAC(a[11], a[32]); SQRADDAC(a[12], a[31]); SQRADDAC(a[13], a[30]); SQRADDAC(a[14], a[29]); SQRADDAC(a[15], a[28]); SQRADDAC(a[16], a[27]); SQRADDAC(a[17], a[26]); SQRADDAC(a[18], a[25]); SQRADDAC(a[19], a[24]); SQRADDAC(a[20], a[23]); SQRADDAC(a[21], a[22]); SQRADDDB;
+   COMBA_STORE(b[43]);
+
+   /* output 44 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[44]); SQRADDAC(a[1], a[43]); SQRADDAC(a[2], a[42]); SQRADDAC(a[3], a[41]); SQRADDAC(a[4], a[40]); SQRADDAC(a[5], a[39]); SQRADDAC(a[6], a[38]); SQRADDAC(a[7], a[37]); SQRADDAC(a[8], a[36]); SQRADDAC(a[9], a[35]); SQRADDAC(a[10], a[34]); SQRADDAC(a[11], a[33]); SQRADDAC(a[12], a[32]); SQRADDAC(a[13], a[31]); SQRADDAC(a[14], a[30]); SQRADDAC(a[15], a[29]); SQRADDAC(a[16], a[28]); SQRADDAC(a[17], a[27]); SQRADDAC(a[18], a[26]); SQRADDAC(a[19], a[25]); SQRADDAC(a[20], a[24]); SQRADDAC(a[21], a[23]); SQRADDDB; SQRADD(a[22], a[22]);
+   COMBA_STORE(b[44]);
+
+   /* output 45 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[45]); SQRADDAC(a[1], a[44]); SQRADDAC(a[2], a[43]); SQRADDAC(a[3], a[42]); SQRADDAC(a[4], a[41]); SQRADDAC(a[5], a[40]); SQRADDAC(a[6], a[39]); SQRADDAC(a[7], a[38]); SQRADDAC(a[8], a[37]); SQRADDAC(a[9], a[36]); SQRADDAC(a[10], a[35]); SQRADDAC(a[11], a[34]); SQRADDAC(a[12], a[33]); SQRADDAC(a[13], a[32]); SQRADDAC(a[14], a[31]); SQRADDAC(a[15], a[30]); SQRADDAC(a[16], a[29]); SQRADDAC(a[17], a[28]); SQRADDAC(a[18], a[27]); SQRADDAC(a[19], a[26]); SQRADDAC(a[20], a[25]); SQRADDAC(a[21], a[24]); SQRADDAC(a[22], a[23]); SQRADDDB;
+   COMBA_STORE(b[45]);
+
+   /* output 46 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[46]); SQRADDAC(a[1], a[45]); SQRADDAC(a[2], a[44]); SQRADDAC(a[3], a[43]); SQRADDAC(a[4], a[42]); SQRADDAC(a[5], a[41]); SQRADDAC(a[6], a[40]); SQRADDAC(a[7], a[39]); SQRADDAC(a[8], a[38]); SQRADDAC(a[9], a[37]); SQRADDAC(a[10], a[36]); SQRADDAC(a[11], a[35]); SQRADDAC(a[12], a[34]); SQRADDAC(a[13], a[33]); SQRADDAC(a[14], a[32]); SQRADDAC(a[15], a[31]); SQRADDAC(a[16], a[30]); SQRADDAC(a[17], a[29]); SQRADDAC(a[18], a[28]); SQRADDAC(a[19], a[27]); SQRADDAC(a[20], a[26]); SQRADDAC(a[21], a[25]); SQRADDAC(a[22], a[24]); SQRADDDB; SQRADD(a[23], a[23]);
+   COMBA_STORE(b[46]);
+
+   /* output 47 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[47]); SQRADDAC(a[1], a[46]); SQRADDAC(a[2], a[45]); SQRADDAC(a[3], a[44]); SQRADDAC(a[4], a[43]); SQRADDAC(a[5], a[42]); SQRADDAC(a[6], a[41]); SQRADDAC(a[7], a[40]); SQRADDAC(a[8], a[39]); SQRADDAC(a[9], a[38]); SQRADDAC(a[10], a[37]); SQRADDAC(a[11], a[36]); SQRADDAC(a[12], a[35]); SQRADDAC(a[13], a[34]); SQRADDAC(a[14], a[33]); SQRADDAC(a[15], a[32]); SQRADDAC(a[16], a[31]); SQRADDAC(a[17], a[30]); SQRADDAC(a[18], a[29]); SQRADDAC(a[19], a[28]); SQRADDAC(a[20], a[27]); SQRADDAC(a[21], a[26]); SQRADDAC(a[22], a[25]); SQRADDAC(a[23], a[24]); SQRADDDB;
+   COMBA_STORE(b[47]);
+
+   /* output 48 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[48]); SQRADDAC(a[1], a[47]); SQRADDAC(a[2], a[46]); SQRADDAC(a[3], a[45]); SQRADDAC(a[4], a[44]); SQRADDAC(a[5], a[43]); SQRADDAC(a[6], a[42]); SQRADDAC(a[7], a[41]); SQRADDAC(a[8], a[40]); SQRADDAC(a[9], a[39]); SQRADDAC(a[10], a[38]); SQRADDAC(a[11], a[37]); SQRADDAC(a[12], a[36]); SQRADDAC(a[13], a[35]); SQRADDAC(a[14], a[34]); SQRADDAC(a[15], a[33]); SQRADDAC(a[16], a[32]); SQRADDAC(a[17], a[31]); SQRADDAC(a[18], a[30]); SQRADDAC(a[19], a[29]); SQRADDAC(a[20], a[28]); SQRADDAC(a[21], a[27]); SQRADDAC(a[22], a[26]); SQRADDAC(a[23], a[25]); SQRADDDB; SQRADD(a[24], a[24]);
+   COMBA_STORE(b[48]);
+
+   /* output 49 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[49]); SQRADDAC(a[1], a[48]); SQRADDAC(a[2], a[47]); SQRADDAC(a[3], a[46]); SQRADDAC(a[4], a[45]); SQRADDAC(a[5], a[44]); SQRADDAC(a[6], a[43]); SQRADDAC(a[7], a[42]); SQRADDAC(a[8], a[41]); SQRADDAC(a[9], a[40]); SQRADDAC(a[10], a[39]); SQRADDAC(a[11], a[38]); SQRADDAC(a[12], a[37]); SQRADDAC(a[13], a[36]); SQRADDAC(a[14], a[35]); SQRADDAC(a[15], a[34]); SQRADDAC(a[16], a[33]); SQRADDAC(a[17], a[32]); SQRADDAC(a[18], a[31]); SQRADDAC(a[19], a[30]); SQRADDAC(a[20], a[29]); SQRADDAC(a[21], a[28]); SQRADDAC(a[22], a[27]); SQRADDAC(a[23], a[26]); SQRADDAC(a[24], a[25]); SQRADDDB;
+   COMBA_STORE(b[49]);
+
+   /* output 50 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[50]); SQRADDAC(a[1], a[49]); SQRADDAC(a[2], a[48]); SQRADDAC(a[3], a[47]); SQRADDAC(a[4], a[46]); SQRADDAC(a[5], a[45]); SQRADDAC(a[6], a[44]); SQRADDAC(a[7], a[43]); SQRADDAC(a[8], a[42]); SQRADDAC(a[9], a[41]); SQRADDAC(a[10], a[40]); SQRADDAC(a[11], a[39]); SQRADDAC(a[12], a[38]); SQRADDAC(a[13], a[37]); SQRADDAC(a[14], a[36]); SQRADDAC(a[15], a[35]); SQRADDAC(a[16], a[34]); SQRADDAC(a[17], a[33]); SQRADDAC(a[18], a[32]); SQRADDAC(a[19], a[31]); SQRADDAC(a[20], a[30]); SQRADDAC(a[21], a[29]); SQRADDAC(a[22], a[28]); SQRADDAC(a[23], a[27]); SQRADDAC(a[24], a[26]); SQRADDDB; SQRADD(a[25], a[25]);
+   COMBA_STORE(b[50]);
+
+   /* output 51 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[51]); SQRADDAC(a[1], a[50]); SQRADDAC(a[2], a[49]); SQRADDAC(a[3], a[48]); SQRADDAC(a[4], a[47]); SQRADDAC(a[5], a[46]); SQRADDAC(a[6], a[45]); SQRADDAC(a[7], a[44]); SQRADDAC(a[8], a[43]); SQRADDAC(a[9], a[42]); SQRADDAC(a[10], a[41]); SQRADDAC(a[11], a[40]); SQRADDAC(a[12], a[39]); SQRADDAC(a[13], a[38]); SQRADDAC(a[14], a[37]); SQRADDAC(a[15], a[36]); SQRADDAC(a[16], a[35]); SQRADDAC(a[17], a[34]); SQRADDAC(a[18], a[33]); SQRADDAC(a[19], a[32]); SQRADDAC(a[20], a[31]); SQRADDAC(a[21], a[30]); SQRADDAC(a[22], a[29]); SQRADDAC(a[23], a[28]); SQRADDAC(a[24], a[27]); SQRADDAC(a[25], a[26]); SQRADDDB;
+   COMBA_STORE(b[51]);
+
+   /* output 52 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[52]); SQRADDAC(a[1], a[51]); SQRADDAC(a[2], a[50]); SQRADDAC(a[3], a[49]); SQRADDAC(a[4], a[48]); SQRADDAC(a[5], a[47]); SQRADDAC(a[6], a[46]); SQRADDAC(a[7], a[45]); SQRADDAC(a[8], a[44]); SQRADDAC(a[9], a[43]); SQRADDAC(a[10], a[42]); SQRADDAC(a[11], a[41]); SQRADDAC(a[12], a[40]); SQRADDAC(a[13], a[39]); SQRADDAC(a[14], a[38]); SQRADDAC(a[15], a[37]); SQRADDAC(a[16], a[36]); SQRADDAC(a[17], a[35]); SQRADDAC(a[18], a[34]); SQRADDAC(a[19], a[33]); SQRADDAC(a[20], a[32]); SQRADDAC(a[21], a[31]); SQRADDAC(a[22], a[30]); SQRADDAC(a[23], a[29]); SQRADDAC(a[24], a[28]); SQRADDAC(a[25], a[27]); SQRADDDB; SQRADD(a[26], a[26]);
+   COMBA_STORE(b[52]);
+
+   /* output 53 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[53]); SQRADDAC(a[1], a[52]); SQRADDAC(a[2], a[51]); SQRADDAC(a[3], a[50]); SQRADDAC(a[4], a[49]); SQRADDAC(a[5], a[48]); SQRADDAC(a[6], a[47]); SQRADDAC(a[7], a[46]); SQRADDAC(a[8], a[45]); SQRADDAC(a[9], a[44]); SQRADDAC(a[10], a[43]); SQRADDAC(a[11], a[42]); SQRADDAC(a[12], a[41]); SQRADDAC(a[13], a[40]); SQRADDAC(a[14], a[39]); SQRADDAC(a[15], a[38]); SQRADDAC(a[16], a[37]); SQRADDAC(a[17], a[36]); SQRADDAC(a[18], a[35]); SQRADDAC(a[19], a[34]); SQRADDAC(a[20], a[33]); SQRADDAC(a[21], a[32]); SQRADDAC(a[22], a[31]); SQRADDAC(a[23], a[30]); SQRADDAC(a[24], a[29]); SQRADDAC(a[25], a[28]); SQRADDAC(a[26], a[27]); SQRADDDB;
+   COMBA_STORE(b[53]);
+
+   /* output 54 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[54]); SQRADDAC(a[1], a[53]); SQRADDAC(a[2], a[52]); SQRADDAC(a[3], a[51]); SQRADDAC(a[4], a[50]); SQRADDAC(a[5], a[49]); SQRADDAC(a[6], a[48]); SQRADDAC(a[7], a[47]); SQRADDAC(a[8], a[46]); SQRADDAC(a[9], a[45]); SQRADDAC(a[10], a[44]); SQRADDAC(a[11], a[43]); SQRADDAC(a[12], a[42]); SQRADDAC(a[13], a[41]); SQRADDAC(a[14], a[40]); SQRADDAC(a[15], a[39]); SQRADDAC(a[16], a[38]); SQRADDAC(a[17], a[37]); SQRADDAC(a[18], a[36]); SQRADDAC(a[19], a[35]); SQRADDAC(a[20], a[34]); SQRADDAC(a[21], a[33]); SQRADDAC(a[22], a[32]); SQRADDAC(a[23], a[31]); SQRADDAC(a[24], a[30]); SQRADDAC(a[25], a[29]); SQRADDAC(a[26], a[28]); SQRADDDB; SQRADD(a[27], a[27]);
+   COMBA_STORE(b[54]);
+
+   /* output 55 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[55]); SQRADDAC(a[1], a[54]); SQRADDAC(a[2], a[53]); SQRADDAC(a[3], a[52]); SQRADDAC(a[4], a[51]); SQRADDAC(a[5], a[50]); SQRADDAC(a[6], a[49]); SQRADDAC(a[7], a[48]); SQRADDAC(a[8], a[47]); SQRADDAC(a[9], a[46]); SQRADDAC(a[10], a[45]); SQRADDAC(a[11], a[44]); SQRADDAC(a[12], a[43]); SQRADDAC(a[13], a[42]); SQRADDAC(a[14], a[41]); SQRADDAC(a[15], a[40]); SQRADDAC(a[16], a[39]); SQRADDAC(a[17], a[38]); SQRADDAC(a[18], a[37]); SQRADDAC(a[19], a[36]); SQRADDAC(a[20], a[35]); SQRADDAC(a[21], a[34]); SQRADDAC(a[22], a[33]); SQRADDAC(a[23], a[32]); SQRADDAC(a[24], a[31]); SQRADDAC(a[25], a[30]); SQRADDAC(a[26], a[29]); SQRADDAC(a[27], a[28]); SQRADDDB;
+   COMBA_STORE(b[55]);
+
+   /* output 56 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[56]); SQRADDAC(a[1], a[55]); SQRADDAC(a[2], a[54]); SQRADDAC(a[3], a[53]); SQRADDAC(a[4], a[52]); SQRADDAC(a[5], a[51]); SQRADDAC(a[6], a[50]); SQRADDAC(a[7], a[49]); SQRADDAC(a[8], a[48]); SQRADDAC(a[9], a[47]); SQRADDAC(a[10], a[46]); SQRADDAC(a[11], a[45]); SQRADDAC(a[12], a[44]); SQRADDAC(a[13], a[43]); SQRADDAC(a[14], a[42]); SQRADDAC(a[15], a[41]); SQRADDAC(a[16], a[40]); SQRADDAC(a[17], a[39]); SQRADDAC(a[18], a[38]); SQRADDAC(a[19], a[37]); SQRADDAC(a[20], a[36]); SQRADDAC(a[21], a[35]); SQRADDAC(a[22], a[34]); SQRADDAC(a[23], a[33]); SQRADDAC(a[24], a[32]); SQRADDAC(a[25], a[31]); SQRADDAC(a[26], a[30]); SQRADDAC(a[27], a[29]); SQRADDDB; SQRADD(a[28], a[28]);
+   COMBA_STORE(b[56]);
+
+   /* output 57 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[57]); SQRADDAC(a[1], a[56]); SQRADDAC(a[2], a[55]); SQRADDAC(a[3], a[54]); SQRADDAC(a[4], a[53]); SQRADDAC(a[5], a[52]); SQRADDAC(a[6], a[51]); SQRADDAC(a[7], a[50]); SQRADDAC(a[8], a[49]); SQRADDAC(a[9], a[48]); SQRADDAC(a[10], a[47]); SQRADDAC(a[11], a[46]); SQRADDAC(a[12], a[45]); SQRADDAC(a[13], a[44]); SQRADDAC(a[14], a[43]); SQRADDAC(a[15], a[42]); SQRADDAC(a[16], a[41]); SQRADDAC(a[17], a[40]); SQRADDAC(a[18], a[39]); SQRADDAC(a[19], a[38]); SQRADDAC(a[20], a[37]); SQRADDAC(a[21], a[36]); SQRADDAC(a[22], a[35]); SQRADDAC(a[23], a[34]); SQRADDAC(a[24], a[33]); SQRADDAC(a[25], a[32]); SQRADDAC(a[26], a[31]); SQRADDAC(a[27], a[30]); SQRADDAC(a[28], a[29]); SQRADDDB;
+   COMBA_STORE(b[57]);
+
+   /* output 58 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[58]); SQRADDAC(a[1], a[57]); SQRADDAC(a[2], a[56]); SQRADDAC(a[3], a[55]); SQRADDAC(a[4], a[54]); SQRADDAC(a[5], a[53]); SQRADDAC(a[6], a[52]); SQRADDAC(a[7], a[51]); SQRADDAC(a[8], a[50]); SQRADDAC(a[9], a[49]); SQRADDAC(a[10], a[48]); SQRADDAC(a[11], a[47]); SQRADDAC(a[12], a[46]); SQRADDAC(a[13], a[45]); SQRADDAC(a[14], a[44]); SQRADDAC(a[15], a[43]); SQRADDAC(a[16], a[42]); SQRADDAC(a[17], a[41]); SQRADDAC(a[18], a[40]); SQRADDAC(a[19], a[39]); SQRADDAC(a[20], a[38]); SQRADDAC(a[21], a[37]); SQRADDAC(a[22], a[36]); SQRADDAC(a[23], a[35]); SQRADDAC(a[24], a[34]); SQRADDAC(a[25], a[33]); SQRADDAC(a[26], a[32]); SQRADDAC(a[27], a[31]); SQRADDAC(a[28], a[30]); SQRADDDB; SQRADD(a[29], a[29]);
+   COMBA_STORE(b[58]);
+
+   /* output 59 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[59]); SQRADDAC(a[1], a[58]); SQRADDAC(a[2], a[57]); SQRADDAC(a[3], a[56]); SQRADDAC(a[4], a[55]); SQRADDAC(a[5], a[54]); SQRADDAC(a[6], a[53]); SQRADDAC(a[7], a[52]); SQRADDAC(a[8], a[51]); SQRADDAC(a[9], a[50]); SQRADDAC(a[10], a[49]); SQRADDAC(a[11], a[48]); SQRADDAC(a[12], a[47]); SQRADDAC(a[13], a[46]); SQRADDAC(a[14], a[45]); SQRADDAC(a[15], a[44]); SQRADDAC(a[16], a[43]); SQRADDAC(a[17], a[42]); SQRADDAC(a[18], a[41]); SQRADDAC(a[19], a[40]); SQRADDAC(a[20], a[39]); SQRADDAC(a[21], a[38]); SQRADDAC(a[22], a[37]); SQRADDAC(a[23], a[36]); SQRADDAC(a[24], a[35]); SQRADDAC(a[25], a[34]); SQRADDAC(a[26], a[33]); SQRADDAC(a[27], a[32]); SQRADDAC(a[28], a[31]); SQRADDAC(a[29], a[30]); SQRADDDB;
+   COMBA_STORE(b[59]);
+
+   /* output 60 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[60]); SQRADDAC(a[1], a[59]); SQRADDAC(a[2], a[58]); SQRADDAC(a[3], a[57]); SQRADDAC(a[4], a[56]); SQRADDAC(a[5], a[55]); SQRADDAC(a[6], a[54]); SQRADDAC(a[7], a[53]); SQRADDAC(a[8], a[52]); SQRADDAC(a[9], a[51]); SQRADDAC(a[10], a[50]); SQRADDAC(a[11], a[49]); SQRADDAC(a[12], a[48]); SQRADDAC(a[13], a[47]); SQRADDAC(a[14], a[46]); SQRADDAC(a[15], a[45]); SQRADDAC(a[16], a[44]); SQRADDAC(a[17], a[43]); SQRADDAC(a[18], a[42]); SQRADDAC(a[19], a[41]); SQRADDAC(a[20], a[40]); SQRADDAC(a[21], a[39]); SQRADDAC(a[22], a[38]); SQRADDAC(a[23], a[37]); SQRADDAC(a[24], a[36]); SQRADDAC(a[25], a[35]); SQRADDAC(a[26], a[34]); SQRADDAC(a[27], a[33]); SQRADDAC(a[28], a[32]); SQRADDAC(a[29], a[31]); SQRADDDB; SQRADD(a[30], a[30]);
+   COMBA_STORE(b[60]);
+
+   /* output 61 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[61]); SQRADDAC(a[1], a[60]); SQRADDAC(a[2], a[59]); SQRADDAC(a[3], a[58]); SQRADDAC(a[4], a[57]); SQRADDAC(a[5], a[56]); SQRADDAC(a[6], a[55]); SQRADDAC(a[7], a[54]); SQRADDAC(a[8], a[53]); SQRADDAC(a[9], a[52]); SQRADDAC(a[10], a[51]); SQRADDAC(a[11], a[50]); SQRADDAC(a[12], a[49]); SQRADDAC(a[13], a[48]); SQRADDAC(a[14], a[47]); SQRADDAC(a[15], a[46]); SQRADDAC(a[16], a[45]); SQRADDAC(a[17], a[44]); SQRADDAC(a[18], a[43]); SQRADDAC(a[19], a[42]); SQRADDAC(a[20], a[41]); SQRADDAC(a[21], a[40]); SQRADDAC(a[22], a[39]); SQRADDAC(a[23], a[38]); SQRADDAC(a[24], a[37]); SQRADDAC(a[25], a[36]); SQRADDAC(a[26], a[35]); SQRADDAC(a[27], a[34]); SQRADDAC(a[28], a[33]); SQRADDAC(a[29], a[32]); SQRADDAC(a[30], a[31]); SQRADDDB;
+   COMBA_STORE(b[61]);
+
+   /* output 62 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[62]); SQRADDAC(a[1], a[61]); SQRADDAC(a[2], a[60]); SQRADDAC(a[3], a[59]); SQRADDAC(a[4], a[58]); SQRADDAC(a[5], a[57]); SQRADDAC(a[6], a[56]); SQRADDAC(a[7], a[55]); SQRADDAC(a[8], a[54]); SQRADDAC(a[9], a[53]); SQRADDAC(a[10], a[52]); SQRADDAC(a[11], a[51]); SQRADDAC(a[12], a[50]); SQRADDAC(a[13], a[49]); SQRADDAC(a[14], a[48]); SQRADDAC(a[15], a[47]); SQRADDAC(a[16], a[46]); SQRADDAC(a[17], a[45]); SQRADDAC(a[18], a[44]); SQRADDAC(a[19], a[43]); SQRADDAC(a[20], a[42]); SQRADDAC(a[21], a[41]); SQRADDAC(a[22], a[40]); SQRADDAC(a[23], a[39]); SQRADDAC(a[24], a[38]); SQRADDAC(a[25], a[37]); SQRADDAC(a[26], a[36]); SQRADDAC(a[27], a[35]); SQRADDAC(a[28], a[34]); SQRADDAC(a[29], a[33]); SQRADDAC(a[30], a[32]); SQRADDDB; SQRADD(a[31], a[31]);
+   COMBA_STORE(b[62]);
+
+   /* output 63 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[63]); SQRADDAC(a[1], a[62]); SQRADDAC(a[2], a[61]); SQRADDAC(a[3], a[60]); SQRADDAC(a[4], a[59]); SQRADDAC(a[5], a[58]); SQRADDAC(a[6], a[57]); SQRADDAC(a[7], a[56]); SQRADDAC(a[8], a[55]); SQRADDAC(a[9], a[54]); SQRADDAC(a[10], a[53]); SQRADDAC(a[11], a[52]); SQRADDAC(a[12], a[51]); SQRADDAC(a[13], a[50]); SQRADDAC(a[14], a[49]); SQRADDAC(a[15], a[48]); SQRADDAC(a[16], a[47]); SQRADDAC(a[17], a[46]); SQRADDAC(a[18], a[45]); SQRADDAC(a[19], a[44]); SQRADDAC(a[20], a[43]); SQRADDAC(a[21], a[42]); SQRADDAC(a[22], a[41]); SQRADDAC(a[23], a[40]); SQRADDAC(a[24], a[39]); SQRADDAC(a[25], a[38]); SQRADDAC(a[26], a[37]); SQRADDAC(a[27], a[36]); SQRADDAC(a[28], a[35]); SQRADDAC(a[29], a[34]); SQRADDAC(a[30], a[33]); SQRADDAC(a[31], a[32]); SQRADDDB;
+   COMBA_STORE(b[63]);
+
+   /* output 64 */
+   CARRY_FORWARD;
+   SQRADDSC(a[1], a[63]); SQRADDAC(a[2], a[62]); SQRADDAC(a[3], a[61]); SQRADDAC(a[4], a[60]); SQRADDAC(a[5], a[59]); SQRADDAC(a[6], a[58]); SQRADDAC(a[7], a[57]); SQRADDAC(a[8], a[56]); SQRADDAC(a[9], a[55]); SQRADDAC(a[10], a[54]); SQRADDAC(a[11], a[53]); SQRADDAC(a[12], a[52]); SQRADDAC(a[13], a[51]); SQRADDAC(a[14], a[50]); SQRADDAC(a[15], a[49]); SQRADDAC(a[16], a[48]); SQRADDAC(a[17], a[47]); SQRADDAC(a[18], a[46]); SQRADDAC(a[19], a[45]); SQRADDAC(a[20], a[44]); SQRADDAC(a[21], a[43]); SQRADDAC(a[22], a[42]); SQRADDAC(a[23], a[41]); SQRADDAC(a[24], a[40]); SQRADDAC(a[25], a[39]); SQRADDAC(a[26], a[38]); SQRADDAC(a[27], a[37]); SQRADDAC(a[28], a[36]); SQRADDAC(a[29], a[35]); SQRADDAC(a[30], a[34]); SQRADDAC(a[31], a[33]); SQRADDDB; SQRADD(a[32], a[32]);
+   COMBA_STORE(b[64]);
+
+   /* output 65 */
+   CARRY_FORWARD;
+   SQRADDSC(a[2], a[63]); SQRADDAC(a[3], a[62]); SQRADDAC(a[4], a[61]); SQRADDAC(a[5], a[60]); SQRADDAC(a[6], a[59]); SQRADDAC(a[7], a[58]); SQRADDAC(a[8], a[57]); SQRADDAC(a[9], a[56]); SQRADDAC(a[10], a[55]); SQRADDAC(a[11], a[54]); SQRADDAC(a[12], a[53]); SQRADDAC(a[13], a[52]); SQRADDAC(a[14], a[51]); SQRADDAC(a[15], a[50]); SQRADDAC(a[16], a[49]); SQRADDAC(a[17], a[48]); SQRADDAC(a[18], a[47]); SQRADDAC(a[19], a[46]); SQRADDAC(a[20], a[45]); SQRADDAC(a[21], a[44]); SQRADDAC(a[22], a[43]); SQRADDAC(a[23], a[42]); SQRADDAC(a[24], a[41]); SQRADDAC(a[25], a[40]); SQRADDAC(a[26], a[39]); SQRADDAC(a[27], a[38]); SQRADDAC(a[28], a[37]); SQRADDAC(a[29], a[36]); SQRADDAC(a[30], a[35]); SQRADDAC(a[31], a[34]); SQRADDAC(a[32], a[33]); SQRADDDB;
+   COMBA_STORE(b[65]);
+
+   /* output 66 */
+   CARRY_FORWARD;
+   SQRADDSC(a[3], a[63]); SQRADDAC(a[4], a[62]); SQRADDAC(a[5], a[61]); SQRADDAC(a[6], a[60]); SQRADDAC(a[7], a[59]); SQRADDAC(a[8], a[58]); SQRADDAC(a[9], a[57]); SQRADDAC(a[10], a[56]); SQRADDAC(a[11], a[55]); SQRADDAC(a[12], a[54]); SQRADDAC(a[13], a[53]); SQRADDAC(a[14], a[52]); SQRADDAC(a[15], a[51]); SQRADDAC(a[16], a[50]); SQRADDAC(a[17], a[49]); SQRADDAC(a[18], a[48]); SQRADDAC(a[19], a[47]); SQRADDAC(a[20], a[46]); SQRADDAC(a[21], a[45]); SQRADDAC(a[22], a[44]); SQRADDAC(a[23], a[43]); SQRADDAC(a[24], a[42]); SQRADDAC(a[25], a[41]); SQRADDAC(a[26], a[40]); SQRADDAC(a[27], a[39]); SQRADDAC(a[28], a[38]); SQRADDAC(a[29], a[37]); SQRADDAC(a[30], a[36]); SQRADDAC(a[31], a[35]); SQRADDAC(a[32], a[34]); SQRADDDB; SQRADD(a[33], a[33]);
+   COMBA_STORE(b[66]);
+
+   /* output 67 */
+   CARRY_FORWARD;
+   SQRADDSC(a[4], a[63]); SQRADDAC(a[5], a[62]); SQRADDAC(a[6], a[61]); SQRADDAC(a[7], a[60]); SQRADDAC(a[8], a[59]); SQRADDAC(a[9], a[58]); SQRADDAC(a[10], a[57]); SQRADDAC(a[11], a[56]); SQRADDAC(a[12], a[55]); SQRADDAC(a[13], a[54]); SQRADDAC(a[14], a[53]); SQRADDAC(a[15], a[52]); SQRADDAC(a[16], a[51]); SQRADDAC(a[17], a[50]); SQRADDAC(a[18], a[49]); SQRADDAC(a[19], a[48]); SQRADDAC(a[20], a[47]); SQRADDAC(a[21], a[46]); SQRADDAC(a[22], a[45]); SQRADDAC(a[23], a[44]); SQRADDAC(a[24], a[43]); SQRADDAC(a[25], a[42]); SQRADDAC(a[26], a[41]); SQRADDAC(a[27], a[40]); SQRADDAC(a[28], a[39]); SQRADDAC(a[29], a[38]); SQRADDAC(a[30], a[37]); SQRADDAC(a[31], a[36]); SQRADDAC(a[32], a[35]); SQRADDAC(a[33], a[34]); SQRADDDB;
+   COMBA_STORE(b[67]);
+
+   /* output 68 */
+   CARRY_FORWARD;
+   SQRADDSC(a[5], a[63]); SQRADDAC(a[6], a[62]); SQRADDAC(a[7], a[61]); SQRADDAC(a[8], a[60]); SQRADDAC(a[9], a[59]); SQRADDAC(a[10], a[58]); SQRADDAC(a[11], a[57]); SQRADDAC(a[12], a[56]); SQRADDAC(a[13], a[55]); SQRADDAC(a[14], a[54]); SQRADDAC(a[15], a[53]); SQRADDAC(a[16], a[52]); SQRADDAC(a[17], a[51]); SQRADDAC(a[18], a[50]); SQRADDAC(a[19], a[49]); SQRADDAC(a[20], a[48]); SQRADDAC(a[21], a[47]); SQRADDAC(a[22], a[46]); SQRADDAC(a[23], a[45]); SQRADDAC(a[24], a[44]); SQRADDAC(a[25], a[43]); SQRADDAC(a[26], a[42]); SQRADDAC(a[27], a[41]); SQRADDAC(a[28], a[40]); SQRADDAC(a[29], a[39]); SQRADDAC(a[30], a[38]); SQRADDAC(a[31], a[37]); SQRADDAC(a[32], a[36]); SQRADDAC(a[33], a[35]); SQRADDDB; SQRADD(a[34], a[34]);
+   COMBA_STORE(b[68]);
+
+   /* output 69 */
+   CARRY_FORWARD;
+   SQRADDSC(a[6], a[63]); SQRADDAC(a[7], a[62]); SQRADDAC(a[8], a[61]); SQRADDAC(a[9], a[60]); SQRADDAC(a[10], a[59]); SQRADDAC(a[11], a[58]); SQRADDAC(a[12], a[57]); SQRADDAC(a[13], a[56]); SQRADDAC(a[14], a[55]); SQRADDAC(a[15], a[54]); SQRADDAC(a[16], a[53]); SQRADDAC(a[17], a[52]); SQRADDAC(a[18], a[51]); SQRADDAC(a[19], a[50]); SQRADDAC(a[20], a[49]); SQRADDAC(a[21], a[48]); SQRADDAC(a[22], a[47]); SQRADDAC(a[23], a[46]); SQRADDAC(a[24], a[45]); SQRADDAC(a[25], a[44]); SQRADDAC(a[26], a[43]); SQRADDAC(a[27], a[42]); SQRADDAC(a[28], a[41]); SQRADDAC(a[29], a[40]); SQRADDAC(a[30], a[39]); SQRADDAC(a[31], a[38]); SQRADDAC(a[32], a[37]); SQRADDAC(a[33], a[36]); SQRADDAC(a[34], a[35]); SQRADDDB;
+   COMBA_STORE(b[69]);
+
+   /* output 70 */
+   CARRY_FORWARD;
+   SQRADDSC(a[7], a[63]); SQRADDAC(a[8], a[62]); SQRADDAC(a[9], a[61]); SQRADDAC(a[10], a[60]); SQRADDAC(a[11], a[59]); SQRADDAC(a[12], a[58]); SQRADDAC(a[13], a[57]); SQRADDAC(a[14], a[56]); SQRADDAC(a[15], a[55]); SQRADDAC(a[16], a[54]); SQRADDAC(a[17], a[53]); SQRADDAC(a[18], a[52]); SQRADDAC(a[19], a[51]); SQRADDAC(a[20], a[50]); SQRADDAC(a[21], a[49]); SQRADDAC(a[22], a[48]); SQRADDAC(a[23], a[47]); SQRADDAC(a[24], a[46]); SQRADDAC(a[25], a[45]); SQRADDAC(a[26], a[44]); SQRADDAC(a[27], a[43]); SQRADDAC(a[28], a[42]); SQRADDAC(a[29], a[41]); SQRADDAC(a[30], a[40]); SQRADDAC(a[31], a[39]); SQRADDAC(a[32], a[38]); SQRADDAC(a[33], a[37]); SQRADDAC(a[34], a[36]); SQRADDDB; SQRADD(a[35], a[35]);
+   COMBA_STORE(b[70]);
+
+   /* output 71 */
+   CARRY_FORWARD;
+   SQRADDSC(a[8], a[63]); SQRADDAC(a[9], a[62]); SQRADDAC(a[10], a[61]); SQRADDAC(a[11], a[60]); SQRADDAC(a[12], a[59]); SQRADDAC(a[13], a[58]); SQRADDAC(a[14], a[57]); SQRADDAC(a[15], a[56]); SQRADDAC(a[16], a[55]); SQRADDAC(a[17], a[54]); SQRADDAC(a[18], a[53]); SQRADDAC(a[19], a[52]); SQRADDAC(a[20], a[51]); SQRADDAC(a[21], a[50]); SQRADDAC(a[22], a[49]); SQRADDAC(a[23], a[48]); SQRADDAC(a[24], a[47]); SQRADDAC(a[25], a[46]); SQRADDAC(a[26], a[45]); SQRADDAC(a[27], a[44]); SQRADDAC(a[28], a[43]); SQRADDAC(a[29], a[42]); SQRADDAC(a[30], a[41]); SQRADDAC(a[31], a[40]); SQRADDAC(a[32], a[39]); SQRADDAC(a[33], a[38]); SQRADDAC(a[34], a[37]); SQRADDAC(a[35], a[36]); SQRADDDB;
+   COMBA_STORE(b[71]);
+
+   /* output 72 */
+   CARRY_FORWARD;
+   SQRADDSC(a[9], a[63]); SQRADDAC(a[10], a[62]); SQRADDAC(a[11], a[61]); SQRADDAC(a[12], a[60]); SQRADDAC(a[13], a[59]); SQRADDAC(a[14], a[58]); SQRADDAC(a[15], a[57]); SQRADDAC(a[16], a[56]); SQRADDAC(a[17], a[55]); SQRADDAC(a[18], a[54]); SQRADDAC(a[19], a[53]); SQRADDAC(a[20], a[52]); SQRADDAC(a[21], a[51]); SQRADDAC(a[22], a[50]); SQRADDAC(a[23], a[49]); SQRADDAC(a[24], a[48]); SQRADDAC(a[25], a[47]); SQRADDAC(a[26], a[46]); SQRADDAC(a[27], a[45]); SQRADDAC(a[28], a[44]); SQRADDAC(a[29], a[43]); SQRADDAC(a[30], a[42]); SQRADDAC(a[31], a[41]); SQRADDAC(a[32], a[40]); SQRADDAC(a[33], a[39]); SQRADDAC(a[34], a[38]); SQRADDAC(a[35], a[37]); SQRADDDB; SQRADD(a[36], a[36]);
+   COMBA_STORE(b[72]);
+
+   /* output 73 */
+   CARRY_FORWARD;
+   SQRADDSC(a[10], a[63]); SQRADDAC(a[11], a[62]); SQRADDAC(a[12], a[61]); SQRADDAC(a[13], a[60]); SQRADDAC(a[14], a[59]); SQRADDAC(a[15], a[58]); SQRADDAC(a[16], a[57]); SQRADDAC(a[17], a[56]); SQRADDAC(a[18], a[55]); SQRADDAC(a[19], a[54]); SQRADDAC(a[20], a[53]); SQRADDAC(a[21], a[52]); SQRADDAC(a[22], a[51]); SQRADDAC(a[23], a[50]); SQRADDAC(a[24], a[49]); SQRADDAC(a[25], a[48]); SQRADDAC(a[26], a[47]); SQRADDAC(a[27], a[46]); SQRADDAC(a[28], a[45]); SQRADDAC(a[29], a[44]); SQRADDAC(a[30], a[43]); SQRADDAC(a[31], a[42]); SQRADDAC(a[32], a[41]); SQRADDAC(a[33], a[40]); SQRADDAC(a[34], a[39]); SQRADDAC(a[35], a[38]); SQRADDAC(a[36], a[37]); SQRADDDB;
+   COMBA_STORE(b[73]);
+
+   /* output 74 */
+   CARRY_FORWARD;
+   SQRADDSC(a[11], a[63]); SQRADDAC(a[12], a[62]); SQRADDAC(a[13], a[61]); SQRADDAC(a[14], a[60]); SQRADDAC(a[15], a[59]); SQRADDAC(a[16], a[58]); SQRADDAC(a[17], a[57]); SQRADDAC(a[18], a[56]); SQRADDAC(a[19], a[55]); SQRADDAC(a[20], a[54]); SQRADDAC(a[21], a[53]); SQRADDAC(a[22], a[52]); SQRADDAC(a[23], a[51]); SQRADDAC(a[24], a[50]); SQRADDAC(a[25], a[49]); SQRADDAC(a[26], a[48]); SQRADDAC(a[27], a[47]); SQRADDAC(a[28], a[46]); SQRADDAC(a[29], a[45]); SQRADDAC(a[30], a[44]); SQRADDAC(a[31], a[43]); SQRADDAC(a[32], a[42]); SQRADDAC(a[33], a[41]); SQRADDAC(a[34], a[40]); SQRADDAC(a[35], a[39]); SQRADDAC(a[36], a[38]); SQRADDDB; SQRADD(a[37], a[37]);
+   COMBA_STORE(b[74]);
+
+   /* output 75 */
+   CARRY_FORWARD;
+   SQRADDSC(a[12], a[63]); SQRADDAC(a[13], a[62]); SQRADDAC(a[14], a[61]); SQRADDAC(a[15], a[60]); SQRADDAC(a[16], a[59]); SQRADDAC(a[17], a[58]); SQRADDAC(a[18], a[57]); SQRADDAC(a[19], a[56]); SQRADDAC(a[20], a[55]); SQRADDAC(a[21], a[54]); SQRADDAC(a[22], a[53]); SQRADDAC(a[23], a[52]); SQRADDAC(a[24], a[51]); SQRADDAC(a[25], a[50]); SQRADDAC(a[26], a[49]); SQRADDAC(a[27], a[48]); SQRADDAC(a[28], a[47]); SQRADDAC(a[29], a[46]); SQRADDAC(a[30], a[45]); SQRADDAC(a[31], a[44]); SQRADDAC(a[32], a[43]); SQRADDAC(a[33], a[42]); SQRADDAC(a[34], a[41]); SQRADDAC(a[35], a[40]); SQRADDAC(a[36], a[39]); SQRADDAC(a[37], a[38]); SQRADDDB;
+   COMBA_STORE(b[75]);
+
+   /* output 76 */
+   CARRY_FORWARD;
+   SQRADDSC(a[13], a[63]); SQRADDAC(a[14], a[62]); SQRADDAC(a[15], a[61]); SQRADDAC(a[16], a[60]); SQRADDAC(a[17], a[59]); SQRADDAC(a[18], a[58]); SQRADDAC(a[19], a[57]); SQRADDAC(a[20], a[56]); SQRADDAC(a[21], a[55]); SQRADDAC(a[22], a[54]); SQRADDAC(a[23], a[53]); SQRADDAC(a[24], a[52]); SQRADDAC(a[25], a[51]); SQRADDAC(a[26], a[50]); SQRADDAC(a[27], a[49]); SQRADDAC(a[28], a[48]); SQRADDAC(a[29], a[47]); SQRADDAC(a[30], a[46]); SQRADDAC(a[31], a[45]); SQRADDAC(a[32], a[44]); SQRADDAC(a[33], a[43]); SQRADDAC(a[34], a[42]); SQRADDAC(a[35], a[41]); SQRADDAC(a[36], a[40]); SQRADDAC(a[37], a[39]); SQRADDDB; SQRADD(a[38], a[38]);
+   COMBA_STORE(b[76]);
+
+   /* output 77 */
+   CARRY_FORWARD;
+   SQRADDSC(a[14], a[63]); SQRADDAC(a[15], a[62]); SQRADDAC(a[16], a[61]); SQRADDAC(a[17], a[60]); SQRADDAC(a[18], a[59]); SQRADDAC(a[19], a[58]); SQRADDAC(a[20], a[57]); SQRADDAC(a[21], a[56]); SQRADDAC(a[22], a[55]); SQRADDAC(a[23], a[54]); SQRADDAC(a[24], a[53]); SQRADDAC(a[25], a[52]); SQRADDAC(a[26], a[51]); SQRADDAC(a[27], a[50]); SQRADDAC(a[28], a[49]); SQRADDAC(a[29], a[48]); SQRADDAC(a[30], a[47]); SQRADDAC(a[31], a[46]); SQRADDAC(a[32], a[45]); SQRADDAC(a[33], a[44]); SQRADDAC(a[34], a[43]); SQRADDAC(a[35], a[42]); SQRADDAC(a[36], a[41]); SQRADDAC(a[37], a[40]); SQRADDAC(a[38], a[39]); SQRADDDB;
+   COMBA_STORE(b[77]);
+
+   /* output 78 */
+   CARRY_FORWARD;
+   SQRADDSC(a[15], a[63]); SQRADDAC(a[16], a[62]); SQRADDAC(a[17], a[61]); SQRADDAC(a[18], a[60]); SQRADDAC(a[19], a[59]); SQRADDAC(a[20], a[58]); SQRADDAC(a[21], a[57]); SQRADDAC(a[22], a[56]); SQRADDAC(a[23], a[55]); SQRADDAC(a[24], a[54]); SQRADDAC(a[25], a[53]); SQRADDAC(a[26], a[52]); SQRADDAC(a[27], a[51]); SQRADDAC(a[28], a[50]); SQRADDAC(a[29], a[49]); SQRADDAC(a[30], a[48]); SQRADDAC(a[31], a[47]); SQRADDAC(a[32], a[46]); SQRADDAC(a[33], a[45]); SQRADDAC(a[34], a[44]); SQRADDAC(a[35], a[43]); SQRADDAC(a[36], a[42]); SQRADDAC(a[37], a[41]); SQRADDAC(a[38], a[40]); SQRADDDB; SQRADD(a[39], a[39]);
+   COMBA_STORE(b[78]);
+
+   /* output 79 */
+   CARRY_FORWARD;
+   SQRADDSC(a[16], a[63]); SQRADDAC(a[17], a[62]); SQRADDAC(a[18], a[61]); SQRADDAC(a[19], a[60]); SQRADDAC(a[20], a[59]); SQRADDAC(a[21], a[58]); SQRADDAC(a[22], a[57]); SQRADDAC(a[23], a[56]); SQRADDAC(a[24], a[55]); SQRADDAC(a[25], a[54]); SQRADDAC(a[26], a[53]); SQRADDAC(a[27], a[52]); SQRADDAC(a[28], a[51]); SQRADDAC(a[29], a[50]); SQRADDAC(a[30], a[49]); SQRADDAC(a[31], a[48]); SQRADDAC(a[32], a[47]); SQRADDAC(a[33], a[46]); SQRADDAC(a[34], a[45]); SQRADDAC(a[35], a[44]); SQRADDAC(a[36], a[43]); SQRADDAC(a[37], a[42]); SQRADDAC(a[38], a[41]); SQRADDAC(a[39], a[40]); SQRADDDB;
+   COMBA_STORE(b[79]);
+
+   /* output 80 */
+   CARRY_FORWARD;
+   SQRADDSC(a[17], a[63]); SQRADDAC(a[18], a[62]); SQRADDAC(a[19], a[61]); SQRADDAC(a[20], a[60]); SQRADDAC(a[21], a[59]); SQRADDAC(a[22], a[58]); SQRADDAC(a[23], a[57]); SQRADDAC(a[24], a[56]); SQRADDAC(a[25], a[55]); SQRADDAC(a[26], a[54]); SQRADDAC(a[27], a[53]); SQRADDAC(a[28], a[52]); SQRADDAC(a[29], a[51]); SQRADDAC(a[30], a[50]); SQRADDAC(a[31], a[49]); SQRADDAC(a[32], a[48]); SQRADDAC(a[33], a[47]); SQRADDAC(a[34], a[46]); SQRADDAC(a[35], a[45]); SQRADDAC(a[36], a[44]); SQRADDAC(a[37], a[43]); SQRADDAC(a[38], a[42]); SQRADDAC(a[39], a[41]); SQRADDDB; SQRADD(a[40], a[40]);
+   COMBA_STORE(b[80]);
+
+   /* output 81 */
+   CARRY_FORWARD;
+   SQRADDSC(a[18], a[63]); SQRADDAC(a[19], a[62]); SQRADDAC(a[20], a[61]); SQRADDAC(a[21], a[60]); SQRADDAC(a[22], a[59]); SQRADDAC(a[23], a[58]); SQRADDAC(a[24], a[57]); SQRADDAC(a[25], a[56]); SQRADDAC(a[26], a[55]); SQRADDAC(a[27], a[54]); SQRADDAC(a[28], a[53]); SQRADDAC(a[29], a[52]); SQRADDAC(a[30], a[51]); SQRADDAC(a[31], a[50]); SQRADDAC(a[32], a[49]); SQRADDAC(a[33], a[48]); SQRADDAC(a[34], a[47]); SQRADDAC(a[35], a[46]); SQRADDAC(a[36], a[45]); SQRADDAC(a[37], a[44]); SQRADDAC(a[38], a[43]); SQRADDAC(a[39], a[42]); SQRADDAC(a[40], a[41]); SQRADDDB;
+   COMBA_STORE(b[81]);
+
+   /* output 82 */
+   CARRY_FORWARD;
+   SQRADDSC(a[19], a[63]); SQRADDAC(a[20], a[62]); SQRADDAC(a[21], a[61]); SQRADDAC(a[22], a[60]); SQRADDAC(a[23], a[59]); SQRADDAC(a[24], a[58]); SQRADDAC(a[25], a[57]); SQRADDAC(a[26], a[56]); SQRADDAC(a[27], a[55]); SQRADDAC(a[28], a[54]); SQRADDAC(a[29], a[53]); SQRADDAC(a[30], a[52]); SQRADDAC(a[31], a[51]); SQRADDAC(a[32], a[50]); SQRADDAC(a[33], a[49]); SQRADDAC(a[34], a[48]); SQRADDAC(a[35], a[47]); SQRADDAC(a[36], a[46]); SQRADDAC(a[37], a[45]); SQRADDAC(a[38], a[44]); SQRADDAC(a[39], a[43]); SQRADDAC(a[40], a[42]); SQRADDDB; SQRADD(a[41], a[41]);
+   COMBA_STORE(b[82]);
+
+   /* output 83 */
+   CARRY_FORWARD;
+   SQRADDSC(a[20], a[63]); SQRADDAC(a[21], a[62]); SQRADDAC(a[22], a[61]); SQRADDAC(a[23], a[60]); SQRADDAC(a[24], a[59]); SQRADDAC(a[25], a[58]); SQRADDAC(a[26], a[57]); SQRADDAC(a[27], a[56]); SQRADDAC(a[28], a[55]); SQRADDAC(a[29], a[54]); SQRADDAC(a[30], a[53]); SQRADDAC(a[31], a[52]); SQRADDAC(a[32], a[51]); SQRADDAC(a[33], a[50]); SQRADDAC(a[34], a[49]); SQRADDAC(a[35], a[48]); SQRADDAC(a[36], a[47]); SQRADDAC(a[37], a[46]); SQRADDAC(a[38], a[45]); SQRADDAC(a[39], a[44]); SQRADDAC(a[40], a[43]); SQRADDAC(a[41], a[42]); SQRADDDB;
+   COMBA_STORE(b[83]);
+
+   /* output 84 */
+   CARRY_FORWARD;
+   SQRADDSC(a[21], a[63]); SQRADDAC(a[22], a[62]); SQRADDAC(a[23], a[61]); SQRADDAC(a[24], a[60]); SQRADDAC(a[25], a[59]); SQRADDAC(a[26], a[58]); SQRADDAC(a[27], a[57]); SQRADDAC(a[28], a[56]); SQRADDAC(a[29], a[55]); SQRADDAC(a[30], a[54]); SQRADDAC(a[31], a[53]); SQRADDAC(a[32], a[52]); SQRADDAC(a[33], a[51]); SQRADDAC(a[34], a[50]); SQRADDAC(a[35], a[49]); SQRADDAC(a[36], a[48]); SQRADDAC(a[37], a[47]); SQRADDAC(a[38], a[46]); SQRADDAC(a[39], a[45]); SQRADDAC(a[40], a[44]); SQRADDAC(a[41], a[43]); SQRADDDB; SQRADD(a[42], a[42]);
+   COMBA_STORE(b[84]);
+
+   /* output 85 */
+   CARRY_FORWARD;
+   SQRADDSC(a[22], a[63]); SQRADDAC(a[23], a[62]); SQRADDAC(a[24], a[61]); SQRADDAC(a[25], a[60]); SQRADDAC(a[26], a[59]); SQRADDAC(a[27], a[58]); SQRADDAC(a[28], a[57]); SQRADDAC(a[29], a[56]); SQRADDAC(a[30], a[55]); SQRADDAC(a[31], a[54]); SQRADDAC(a[32], a[53]); SQRADDAC(a[33], a[52]); SQRADDAC(a[34], a[51]); SQRADDAC(a[35], a[50]); SQRADDAC(a[36], a[49]); SQRADDAC(a[37], a[48]); SQRADDAC(a[38], a[47]); SQRADDAC(a[39], a[46]); SQRADDAC(a[40], a[45]); SQRADDAC(a[41], a[44]); SQRADDAC(a[42], a[43]); SQRADDDB;
+   COMBA_STORE(b[85]);
+
+   /* output 86 */
+   CARRY_FORWARD;
+   SQRADDSC(a[23], a[63]); SQRADDAC(a[24], a[62]); SQRADDAC(a[25], a[61]); SQRADDAC(a[26], a[60]); SQRADDAC(a[27], a[59]); SQRADDAC(a[28], a[58]); SQRADDAC(a[29], a[57]); SQRADDAC(a[30], a[56]); SQRADDAC(a[31], a[55]); SQRADDAC(a[32], a[54]); SQRADDAC(a[33], a[53]); SQRADDAC(a[34], a[52]); SQRADDAC(a[35], a[51]); SQRADDAC(a[36], a[50]); SQRADDAC(a[37], a[49]); SQRADDAC(a[38], a[48]); SQRADDAC(a[39], a[47]); SQRADDAC(a[40], a[46]); SQRADDAC(a[41], a[45]); SQRADDAC(a[42], a[44]); SQRADDDB; SQRADD(a[43], a[43]);
+   COMBA_STORE(b[86]);
+
+   /* output 87 */
+   CARRY_FORWARD;
+   SQRADDSC(a[24], a[63]); SQRADDAC(a[25], a[62]); SQRADDAC(a[26], a[61]); SQRADDAC(a[27], a[60]); SQRADDAC(a[28], a[59]); SQRADDAC(a[29], a[58]); SQRADDAC(a[30], a[57]); SQRADDAC(a[31], a[56]); SQRADDAC(a[32], a[55]); SQRADDAC(a[33], a[54]); SQRADDAC(a[34], a[53]); SQRADDAC(a[35], a[52]); SQRADDAC(a[36], a[51]); SQRADDAC(a[37], a[50]); SQRADDAC(a[38], a[49]); SQRADDAC(a[39], a[48]); SQRADDAC(a[40], a[47]); SQRADDAC(a[41], a[46]); SQRADDAC(a[42], a[45]); SQRADDAC(a[43], a[44]); SQRADDDB;
+   COMBA_STORE(b[87]);
+
+   /* output 88 */
+   CARRY_FORWARD;
+   SQRADDSC(a[25], a[63]); SQRADDAC(a[26], a[62]); SQRADDAC(a[27], a[61]); SQRADDAC(a[28], a[60]); SQRADDAC(a[29], a[59]); SQRADDAC(a[30], a[58]); SQRADDAC(a[31], a[57]); SQRADDAC(a[32], a[56]); SQRADDAC(a[33], a[55]); SQRADDAC(a[34], a[54]); SQRADDAC(a[35], a[53]); SQRADDAC(a[36], a[52]); SQRADDAC(a[37], a[51]); SQRADDAC(a[38], a[50]); SQRADDAC(a[39], a[49]); SQRADDAC(a[40], a[48]); SQRADDAC(a[41], a[47]); SQRADDAC(a[42], a[46]); SQRADDAC(a[43], a[45]); SQRADDDB; SQRADD(a[44], a[44]);
+   COMBA_STORE(b[88]);
+
+   /* output 89 */
+   CARRY_FORWARD;
+   SQRADDSC(a[26], a[63]); SQRADDAC(a[27], a[62]); SQRADDAC(a[28], a[61]); SQRADDAC(a[29], a[60]); SQRADDAC(a[30], a[59]); SQRADDAC(a[31], a[58]); SQRADDAC(a[32], a[57]); SQRADDAC(a[33], a[56]); SQRADDAC(a[34], a[55]); SQRADDAC(a[35], a[54]); SQRADDAC(a[36], a[53]); SQRADDAC(a[37], a[52]); SQRADDAC(a[38], a[51]); SQRADDAC(a[39], a[50]); SQRADDAC(a[40], a[49]); SQRADDAC(a[41], a[48]); SQRADDAC(a[42], a[47]); SQRADDAC(a[43], a[46]); SQRADDAC(a[44], a[45]); SQRADDDB;
+   COMBA_STORE(b[89]);
+
+   /* output 90 */
+   CARRY_FORWARD;
+   SQRADDSC(a[27], a[63]); SQRADDAC(a[28], a[62]); SQRADDAC(a[29], a[61]); SQRADDAC(a[30], a[60]); SQRADDAC(a[31], a[59]); SQRADDAC(a[32], a[58]); SQRADDAC(a[33], a[57]); SQRADDAC(a[34], a[56]); SQRADDAC(a[35], a[55]); SQRADDAC(a[36], a[54]); SQRADDAC(a[37], a[53]); SQRADDAC(a[38], a[52]); SQRADDAC(a[39], a[51]); SQRADDAC(a[40], a[50]); SQRADDAC(a[41], a[49]); SQRADDAC(a[42], a[48]); SQRADDAC(a[43], a[47]); SQRADDAC(a[44], a[46]); SQRADDDB; SQRADD(a[45], a[45]);
+   COMBA_STORE(b[90]);
+
+   /* output 91 */
+   CARRY_FORWARD;
+   SQRADDSC(a[28], a[63]); SQRADDAC(a[29], a[62]); SQRADDAC(a[30], a[61]); SQRADDAC(a[31], a[60]); SQRADDAC(a[32], a[59]); SQRADDAC(a[33], a[58]); SQRADDAC(a[34], a[57]); SQRADDAC(a[35], a[56]); SQRADDAC(a[36], a[55]); SQRADDAC(a[37], a[54]); SQRADDAC(a[38], a[53]); SQRADDAC(a[39], a[52]); SQRADDAC(a[40], a[51]); SQRADDAC(a[41], a[50]); SQRADDAC(a[42], a[49]); SQRADDAC(a[43], a[48]); SQRADDAC(a[44], a[47]); SQRADDAC(a[45], a[46]); SQRADDDB;
+   COMBA_STORE(b[91]);
+
+   /* output 92 */
+   CARRY_FORWARD;
+   SQRADDSC(a[29], a[63]); SQRADDAC(a[30], a[62]); SQRADDAC(a[31], a[61]); SQRADDAC(a[32], a[60]); SQRADDAC(a[33], a[59]); SQRADDAC(a[34], a[58]); SQRADDAC(a[35], a[57]); SQRADDAC(a[36], a[56]); SQRADDAC(a[37], a[55]); SQRADDAC(a[38], a[54]); SQRADDAC(a[39], a[53]); SQRADDAC(a[40], a[52]); SQRADDAC(a[41], a[51]); SQRADDAC(a[42], a[50]); SQRADDAC(a[43], a[49]); SQRADDAC(a[44], a[48]); SQRADDAC(a[45], a[47]); SQRADDDB; SQRADD(a[46], a[46]);
+   COMBA_STORE(b[92]);
+
+   /* output 93 */
+   CARRY_FORWARD;
+   SQRADDSC(a[30], a[63]); SQRADDAC(a[31], a[62]); SQRADDAC(a[32], a[61]); SQRADDAC(a[33], a[60]); SQRADDAC(a[34], a[59]); SQRADDAC(a[35], a[58]); SQRADDAC(a[36], a[57]); SQRADDAC(a[37], a[56]); SQRADDAC(a[38], a[55]); SQRADDAC(a[39], a[54]); SQRADDAC(a[40], a[53]); SQRADDAC(a[41], a[52]); SQRADDAC(a[42], a[51]); SQRADDAC(a[43], a[50]); SQRADDAC(a[44], a[49]); SQRADDAC(a[45], a[48]); SQRADDAC(a[46], a[47]); SQRADDDB;
+   COMBA_STORE(b[93]);
+
+   /* output 94 */
+   CARRY_FORWARD;
+   SQRADDSC(a[31], a[63]); SQRADDAC(a[32], a[62]); SQRADDAC(a[33], a[61]); SQRADDAC(a[34], a[60]); SQRADDAC(a[35], a[59]); SQRADDAC(a[36], a[58]); SQRADDAC(a[37], a[57]); SQRADDAC(a[38], a[56]); SQRADDAC(a[39], a[55]); SQRADDAC(a[40], a[54]); SQRADDAC(a[41], a[53]); SQRADDAC(a[42], a[52]); SQRADDAC(a[43], a[51]); SQRADDAC(a[44], a[50]); SQRADDAC(a[45], a[49]); SQRADDAC(a[46], a[48]); SQRADDDB; SQRADD(a[47], a[47]);
+   COMBA_STORE(b[94]);
+
+   /* output 95 */
+   CARRY_FORWARD;
+   SQRADDSC(a[32], a[63]); SQRADDAC(a[33], a[62]); SQRADDAC(a[34], a[61]); SQRADDAC(a[35], a[60]); SQRADDAC(a[36], a[59]); SQRADDAC(a[37], a[58]); SQRADDAC(a[38], a[57]); SQRADDAC(a[39], a[56]); SQRADDAC(a[40], a[55]); SQRADDAC(a[41], a[54]); SQRADDAC(a[42], a[53]); SQRADDAC(a[43], a[52]); SQRADDAC(a[44], a[51]); SQRADDAC(a[45], a[50]); SQRADDAC(a[46], a[49]); SQRADDAC(a[47], a[48]); SQRADDDB;
+   COMBA_STORE(b[95]);
+
+   /* output 96 */
+   CARRY_FORWARD;
+   SQRADDSC(a[33], a[63]); SQRADDAC(a[34], a[62]); SQRADDAC(a[35], a[61]); SQRADDAC(a[36], a[60]); SQRADDAC(a[37], a[59]); SQRADDAC(a[38], a[58]); SQRADDAC(a[39], a[57]); SQRADDAC(a[40], a[56]); SQRADDAC(a[41], a[55]); SQRADDAC(a[42], a[54]); SQRADDAC(a[43], a[53]); SQRADDAC(a[44], a[52]); SQRADDAC(a[45], a[51]); SQRADDAC(a[46], a[50]); SQRADDAC(a[47], a[49]); SQRADDDB; SQRADD(a[48], a[48]);
+   COMBA_STORE(b[96]);
+
+   /* output 97 */
+   CARRY_FORWARD;
+   SQRADDSC(a[34], a[63]); SQRADDAC(a[35], a[62]); SQRADDAC(a[36], a[61]); SQRADDAC(a[37], a[60]); SQRADDAC(a[38], a[59]); SQRADDAC(a[39], a[58]); SQRADDAC(a[40], a[57]); SQRADDAC(a[41], a[56]); SQRADDAC(a[42], a[55]); SQRADDAC(a[43], a[54]); SQRADDAC(a[44], a[53]); SQRADDAC(a[45], a[52]); SQRADDAC(a[46], a[51]); SQRADDAC(a[47], a[50]); SQRADDAC(a[48], a[49]); SQRADDDB;
+   COMBA_STORE(b[97]);
+
+   /* output 98 */
+   CARRY_FORWARD;
+   SQRADDSC(a[35], a[63]); SQRADDAC(a[36], a[62]); SQRADDAC(a[37], a[61]); SQRADDAC(a[38], a[60]); SQRADDAC(a[39], a[59]); SQRADDAC(a[40], a[58]); SQRADDAC(a[41], a[57]); SQRADDAC(a[42], a[56]); SQRADDAC(a[43], a[55]); SQRADDAC(a[44], a[54]); SQRADDAC(a[45], a[53]); SQRADDAC(a[46], a[52]); SQRADDAC(a[47], a[51]); SQRADDAC(a[48], a[50]); SQRADDDB; SQRADD(a[49], a[49]);
+   COMBA_STORE(b[98]);
+
+   /* output 99 */
+   CARRY_FORWARD;
+   SQRADDSC(a[36], a[63]); SQRADDAC(a[37], a[62]); SQRADDAC(a[38], a[61]); SQRADDAC(a[39], a[60]); SQRADDAC(a[40], a[59]); SQRADDAC(a[41], a[58]); SQRADDAC(a[42], a[57]); SQRADDAC(a[43], a[56]); SQRADDAC(a[44], a[55]); SQRADDAC(a[45], a[54]); SQRADDAC(a[46], a[53]); SQRADDAC(a[47], a[52]); SQRADDAC(a[48], a[51]); SQRADDAC(a[49], a[50]); SQRADDDB;
+   COMBA_STORE(b[99]);
+
+   /* output 100 */
+   CARRY_FORWARD;
+   SQRADDSC(a[37], a[63]); SQRADDAC(a[38], a[62]); SQRADDAC(a[39], a[61]); SQRADDAC(a[40], a[60]); SQRADDAC(a[41], a[59]); SQRADDAC(a[42], a[58]); SQRADDAC(a[43], a[57]); SQRADDAC(a[44], a[56]); SQRADDAC(a[45], a[55]); SQRADDAC(a[46], a[54]); SQRADDAC(a[47], a[53]); SQRADDAC(a[48], a[52]); SQRADDAC(a[49], a[51]); SQRADDDB; SQRADD(a[50], a[50]);
+   COMBA_STORE(b[100]);
+
+   /* output 101 */
+   CARRY_FORWARD;
+   SQRADDSC(a[38], a[63]); SQRADDAC(a[39], a[62]); SQRADDAC(a[40], a[61]); SQRADDAC(a[41], a[60]); SQRADDAC(a[42], a[59]); SQRADDAC(a[43], a[58]); SQRADDAC(a[44], a[57]); SQRADDAC(a[45], a[56]); SQRADDAC(a[46], a[55]); SQRADDAC(a[47], a[54]); SQRADDAC(a[48], a[53]); SQRADDAC(a[49], a[52]); SQRADDAC(a[50], a[51]); SQRADDDB;
+   COMBA_STORE(b[101]);
+
+   /* output 102 */
+   CARRY_FORWARD;
+   SQRADDSC(a[39], a[63]); SQRADDAC(a[40], a[62]); SQRADDAC(a[41], a[61]); SQRADDAC(a[42], a[60]); SQRADDAC(a[43], a[59]); SQRADDAC(a[44], a[58]); SQRADDAC(a[45], a[57]); SQRADDAC(a[46], a[56]); SQRADDAC(a[47], a[55]); SQRADDAC(a[48], a[54]); SQRADDAC(a[49], a[53]); SQRADDAC(a[50], a[52]); SQRADDDB; SQRADD(a[51], a[51]);
+   COMBA_STORE(b[102]);
+
+   /* output 103 */
+   CARRY_FORWARD;
+   SQRADDSC(a[40], a[63]); SQRADDAC(a[41], a[62]); SQRADDAC(a[42], a[61]); SQRADDAC(a[43], a[60]); SQRADDAC(a[44], a[59]); SQRADDAC(a[45], a[58]); SQRADDAC(a[46], a[57]); SQRADDAC(a[47], a[56]); SQRADDAC(a[48], a[55]); SQRADDAC(a[49], a[54]); SQRADDAC(a[50], a[53]); SQRADDAC(a[51], a[52]); SQRADDDB;
+   COMBA_STORE(b[103]);
+
+   /* output 104 */
+   CARRY_FORWARD;
+   SQRADDSC(a[41], a[63]); SQRADDAC(a[42], a[62]); SQRADDAC(a[43], a[61]); SQRADDAC(a[44], a[60]); SQRADDAC(a[45], a[59]); SQRADDAC(a[46], a[58]); SQRADDAC(a[47], a[57]); SQRADDAC(a[48], a[56]); SQRADDAC(a[49], a[55]); SQRADDAC(a[50], a[54]); SQRADDAC(a[51], a[53]); SQRADDDB; SQRADD(a[52], a[52]);
+   COMBA_STORE(b[104]);
+
+   /* output 105 */
+   CARRY_FORWARD;
+   SQRADDSC(a[42], a[63]); SQRADDAC(a[43], a[62]); SQRADDAC(a[44], a[61]); SQRADDAC(a[45], a[60]); SQRADDAC(a[46], a[59]); SQRADDAC(a[47], a[58]); SQRADDAC(a[48], a[57]); SQRADDAC(a[49], a[56]); SQRADDAC(a[50], a[55]); SQRADDAC(a[51], a[54]); SQRADDAC(a[52], a[53]); SQRADDDB;
+   COMBA_STORE(b[105]);
+
+   /* output 106 */
+   CARRY_FORWARD;
+   SQRADDSC(a[43], a[63]); SQRADDAC(a[44], a[62]); SQRADDAC(a[45], a[61]); SQRADDAC(a[46], a[60]); SQRADDAC(a[47], a[59]); SQRADDAC(a[48], a[58]); SQRADDAC(a[49], a[57]); SQRADDAC(a[50], a[56]); SQRADDAC(a[51], a[55]); SQRADDAC(a[52], a[54]); SQRADDDB; SQRADD(a[53], a[53]);
+   COMBA_STORE(b[106]);
+
+   /* output 107 */
+   CARRY_FORWARD;
+   SQRADDSC(a[44], a[63]); SQRADDAC(a[45], a[62]); SQRADDAC(a[46], a[61]); SQRADDAC(a[47], a[60]); SQRADDAC(a[48], a[59]); SQRADDAC(a[49], a[58]); SQRADDAC(a[50], a[57]); SQRADDAC(a[51], a[56]); SQRADDAC(a[52], a[55]); SQRADDAC(a[53], a[54]); SQRADDDB;
+   COMBA_STORE(b[107]);
+
+   /* output 108 */
+   CARRY_FORWARD;
+   SQRADDSC(a[45], a[63]); SQRADDAC(a[46], a[62]); SQRADDAC(a[47], a[61]); SQRADDAC(a[48], a[60]); SQRADDAC(a[49], a[59]); SQRADDAC(a[50], a[58]); SQRADDAC(a[51], a[57]); SQRADDAC(a[52], a[56]); SQRADDAC(a[53], a[55]); SQRADDDB; SQRADD(a[54], a[54]);
+   COMBA_STORE(b[108]);
+
+   /* output 109 */
+   CARRY_FORWARD;
+   SQRADDSC(a[46], a[63]); SQRADDAC(a[47], a[62]); SQRADDAC(a[48], a[61]); SQRADDAC(a[49], a[60]); SQRADDAC(a[50], a[59]); SQRADDAC(a[51], a[58]); SQRADDAC(a[52], a[57]); SQRADDAC(a[53], a[56]); SQRADDAC(a[54], a[55]); SQRADDDB;
+   COMBA_STORE(b[109]);
+
+   /* output 110 */
+   CARRY_FORWARD;
+   SQRADDSC(a[47], a[63]); SQRADDAC(a[48], a[62]); SQRADDAC(a[49], a[61]); SQRADDAC(a[50], a[60]); SQRADDAC(a[51], a[59]); SQRADDAC(a[52], a[58]); SQRADDAC(a[53], a[57]); SQRADDAC(a[54], a[56]); SQRADDDB; SQRADD(a[55], a[55]);
+   COMBA_STORE(b[110]);
+
+   /* output 111 */
+   CARRY_FORWARD;
+   SQRADDSC(a[48], a[63]); SQRADDAC(a[49], a[62]); SQRADDAC(a[50], a[61]); SQRADDAC(a[51], a[60]); SQRADDAC(a[52], a[59]); SQRADDAC(a[53], a[58]); SQRADDAC(a[54], a[57]); SQRADDAC(a[55], a[56]); SQRADDDB;
+   COMBA_STORE(b[111]);
+
+   /* output 112 */
+   CARRY_FORWARD;
+   SQRADDSC(a[49], a[63]); SQRADDAC(a[50], a[62]); SQRADDAC(a[51], a[61]); SQRADDAC(a[52], a[60]); SQRADDAC(a[53], a[59]); SQRADDAC(a[54], a[58]); SQRADDAC(a[55], a[57]); SQRADDDB; SQRADD(a[56], a[56]);
+   COMBA_STORE(b[112]);
+
+   /* output 113 */
+   CARRY_FORWARD;
+   SQRADDSC(a[50], a[63]); SQRADDAC(a[51], a[62]); SQRADDAC(a[52], a[61]); SQRADDAC(a[53], a[60]); SQRADDAC(a[54], a[59]); SQRADDAC(a[55], a[58]); SQRADDAC(a[56], a[57]); SQRADDDB;
+   COMBA_STORE(b[113]);
+
+   /* output 114 */
+   CARRY_FORWARD;
+   SQRADDSC(a[51], a[63]); SQRADDAC(a[52], a[62]); SQRADDAC(a[53], a[61]); SQRADDAC(a[54], a[60]); SQRADDAC(a[55], a[59]); SQRADDAC(a[56], a[58]); SQRADDDB; SQRADD(a[57], a[57]);
+   COMBA_STORE(b[114]);
+
+   /* output 115 */
+   CARRY_FORWARD;
+   SQRADDSC(a[52], a[63]); SQRADDAC(a[53], a[62]); SQRADDAC(a[54], a[61]); SQRADDAC(a[55], a[60]); SQRADDAC(a[56], a[59]); SQRADDAC(a[57], a[58]); SQRADDDB;
+   COMBA_STORE(b[115]);
+
+   /* output 116 */
+   CARRY_FORWARD;
+   SQRADDSC(a[53], a[63]); SQRADDAC(a[54], a[62]); SQRADDAC(a[55], a[61]); SQRADDAC(a[56], a[60]); SQRADDAC(a[57], a[59]); SQRADDDB; SQRADD(a[58], a[58]);
+   COMBA_STORE(b[116]);
+
+   /* output 117 */
+   CARRY_FORWARD;
+   SQRADDSC(a[54], a[63]); SQRADDAC(a[55], a[62]); SQRADDAC(a[56], a[61]); SQRADDAC(a[57], a[60]); SQRADDAC(a[58], a[59]); SQRADDDB;
+   COMBA_STORE(b[117]);
+
+   /* output 118 */
+   CARRY_FORWARD;
+   SQRADDSC(a[55], a[63]); SQRADDAC(a[56], a[62]); SQRADDAC(a[57], a[61]); SQRADDAC(a[58], a[60]); SQRADDDB; SQRADD(a[59], a[59]);
+   COMBA_STORE(b[118]);
+
+   /* output 119 */
+   CARRY_FORWARD;
+   SQRADDSC(a[56], a[63]); SQRADDAC(a[57], a[62]); SQRADDAC(a[58], a[61]); SQRADDAC(a[59], a[60]); SQRADDDB;
+   COMBA_STORE(b[119]);
+
+   /* output 120 */
+   CARRY_FORWARD;
+   SQRADDSC(a[57], a[63]); SQRADDAC(a[58], a[62]); SQRADDAC(a[59], a[61]); SQRADDDB; SQRADD(a[60], a[60]);
+   COMBA_STORE(b[120]);
+
+   /* output 121 */
+   CARRY_FORWARD;
+   SQRADDSC(a[58], a[63]); SQRADDAC(a[59], a[62]); SQRADDAC(a[60], a[61]); SQRADDDB;
+   COMBA_STORE(b[121]);
+
+   /* output 122 */
+   CARRY_FORWARD;
+   SQRADD2(a[59], a[63]); SQRADD2(a[60], a[62]); SQRADD(a[61], a[61]);
+   COMBA_STORE(b[122]);
+
+   /* output 123 */
+   CARRY_FORWARD;
+   SQRADD2(a[60], a[63]); SQRADD2(a[61], a[62]);
+   COMBA_STORE(b[123]);
+
+   /* output 124 */
+   CARRY_FORWARD;
+   SQRADD2(a[61], a[63]); SQRADD(a[62], a[62]);
+   COMBA_STORE(b[124]);
+
+   /* output 125 */
+   CARRY_FORWARD;
+   SQRADD2(a[62], a[63]);
+   COMBA_STORE(b[125]);
+
+   /* output 126 */
+   CARRY_FORWARD;
+   SQRADD(a[63], a[63]);
+   COMBA_STORE(b[126]);
+   COMBA_STORE2(b[127]);
+   COMBA_FINI;
+
+   B->used = 128;
+   B->sign = FP_ZPOS;
+   memcpy(B->dp, b, 128 * sizeof(fp_digit));
+   fp_clamp(B);
+}
+#endif
+
+
+/* $Source$ */
+/* $Revision$ */
+/* $Date$ */
diff --git a/tomsfastmath/src/sqr/fp_sqr_comba_7.c b/tomsfastmath/src/sqr/fp_sqr_comba_7.c
new file mode 100644 (file)
index 0000000..e9fd421
--- /dev/null
@@ -0,0 +1,94 @@
+#define TFM_DEFINES
+#include "fp_sqr_comba.c"
+
+#if defined(TFM_SQR7) && FP_SIZE >= 14
+void fp_sqr_comba7(fp_int *A, fp_int *B)
+{
+   fp_digit *a, b[14], c0, c1, c2, sc0, sc1, sc2;
+#ifdef TFM_ISO
+   fp_word tt;
+#endif
+
+   a = A->dp;
+   COMBA_START;
+
+   /* clear carries */
+   CLEAR_CARRY;
+
+   /* output 0 */
+   SQRADD(a[0],a[0]);
+   COMBA_STORE(b[0]);
+
+   /* output 1 */
+   CARRY_FORWARD;
+   SQRADD2(a[0], a[1]);
+   COMBA_STORE(b[1]);
+
+   /* output 2 */
+   CARRY_FORWARD;
+   SQRADD2(a[0], a[2]); SQRADD(a[1], a[1]);
+   COMBA_STORE(b[2]);
+
+   /* output 3 */
+   CARRY_FORWARD;
+   SQRADD2(a[0], a[3]); SQRADD2(a[1], a[2]);
+   COMBA_STORE(b[3]);
+
+   /* output 4 */
+   CARRY_FORWARD;
+   SQRADD2(a[0], a[4]); SQRADD2(a[1], a[3]); SQRADD(a[2], a[2]);
+   COMBA_STORE(b[4]);
+
+   /* output 5 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[5]); SQRADDAC(a[1], a[4]); SQRADDAC(a[2], a[3]); SQRADDDB;
+   COMBA_STORE(b[5]);
+
+   /* output 6 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[6]); SQRADDAC(a[1], a[5]); SQRADDAC(a[2], a[4]); SQRADDDB; SQRADD(a[3], a[3]);
+   COMBA_STORE(b[6]);
+
+   /* output 7 */
+   CARRY_FORWARD;
+   SQRADDSC(a[1], a[6]); SQRADDAC(a[2], a[5]); SQRADDAC(a[3], a[4]); SQRADDDB;
+   COMBA_STORE(b[7]);
+
+   /* output 8 */
+   CARRY_FORWARD;
+   SQRADD2(a[2], a[6]); SQRADD2(a[3], a[5]); SQRADD(a[4], a[4]);
+   COMBA_STORE(b[8]);
+
+   /* output 9 */
+   CARRY_FORWARD;
+   SQRADD2(a[3], a[6]); SQRADD2(a[4], a[5]);
+   COMBA_STORE(b[9]);
+
+   /* output 10 */
+   CARRY_FORWARD;
+   SQRADD2(a[4], a[6]); SQRADD(a[5], a[5]);
+   COMBA_STORE(b[10]);
+
+   /* output 11 */
+   CARRY_FORWARD;
+   SQRADD2(a[5], a[6]);
+   COMBA_STORE(b[11]);
+
+   /* output 12 */
+   CARRY_FORWARD;
+   SQRADD(a[6], a[6]);
+   COMBA_STORE(b[12]);
+   COMBA_STORE2(b[13]);
+   COMBA_FINI;
+
+   B->used = 14;
+   B->sign = FP_ZPOS;
+   memcpy(B->dp, b, 14 * sizeof(fp_digit));
+   fp_clamp(B);
+}
+#endif
+
+
+/* $Source$ */
+/* $Revision$ */
+/* $Date$ */
diff --git a/tomsfastmath/src/sqr/fp_sqr_comba_8.c b/tomsfastmath/src/sqr/fp_sqr_comba_8.c
new file mode 100644 (file)
index 0000000..d6c3189
--- /dev/null
@@ -0,0 +1,104 @@
+#define TFM_DEFINES
+#include "fp_sqr_comba.c"
+
+#if defined(TFM_SQR8) && FP_SIZE >= 16
+void fp_sqr_comba8(fp_int *A, fp_int *B)
+{
+   fp_digit *a, b[16], c0, c1, c2, sc0, sc1, sc2;
+#ifdef TFM_ISO
+   fp_word tt;
+#endif
+
+   a = A->dp;
+   COMBA_START;
+
+   /* clear carries */
+   CLEAR_CARRY;
+
+   /* output 0 */
+   SQRADD(a[0],a[0]);
+   COMBA_STORE(b[0]);
+
+   /* output 1 */
+   CARRY_FORWARD;
+   SQRADD2(a[0], a[1]);
+   COMBA_STORE(b[1]);
+
+   /* output 2 */
+   CARRY_FORWARD;
+   SQRADD2(a[0], a[2]); SQRADD(a[1], a[1]);
+   COMBA_STORE(b[2]);
+
+   /* output 3 */
+   CARRY_FORWARD;
+   SQRADD2(a[0], a[3]); SQRADD2(a[1], a[2]);
+   COMBA_STORE(b[3]);
+
+   /* output 4 */
+   CARRY_FORWARD;
+   SQRADD2(a[0], a[4]); SQRADD2(a[1], a[3]); SQRADD(a[2], a[2]);
+   COMBA_STORE(b[4]);
+
+   /* output 5 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[5]); SQRADDAC(a[1], a[4]); SQRADDAC(a[2], a[3]); SQRADDDB;
+   COMBA_STORE(b[5]);
+
+   /* output 6 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[6]); SQRADDAC(a[1], a[5]); SQRADDAC(a[2], a[4]); SQRADDDB; SQRADD(a[3], a[3]);
+   COMBA_STORE(b[6]);
+
+   /* output 7 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[7]); SQRADDAC(a[1], a[6]); SQRADDAC(a[2], a[5]); SQRADDAC(a[3], a[4]); SQRADDDB;
+   COMBA_STORE(b[7]);
+
+   /* output 8 */
+   CARRY_FORWARD;
+   SQRADDSC(a[1], a[7]); SQRADDAC(a[2], a[6]); SQRADDAC(a[3], a[5]); SQRADDDB; SQRADD(a[4], a[4]);
+   COMBA_STORE(b[8]);
+
+   /* output 9 */
+   CARRY_FORWARD;
+   SQRADDSC(a[2], a[7]); SQRADDAC(a[3], a[6]); SQRADDAC(a[4], a[5]); SQRADDDB;
+   COMBA_STORE(b[9]);
+
+   /* output 10 */
+   CARRY_FORWARD;
+   SQRADD2(a[3], a[7]); SQRADD2(a[4], a[6]); SQRADD(a[5], a[5]);
+   COMBA_STORE(b[10]);
+
+   /* output 11 */
+   CARRY_FORWARD;
+   SQRADD2(a[4], a[7]); SQRADD2(a[5], a[6]);
+   COMBA_STORE(b[11]);
+
+   /* output 12 */
+   CARRY_FORWARD;
+   SQRADD2(a[5], a[7]); SQRADD(a[6], a[6]);
+   COMBA_STORE(b[12]);
+
+   /* output 13 */
+   CARRY_FORWARD;
+   SQRADD2(a[6], a[7]);
+   COMBA_STORE(b[13]);
+
+   /* output 14 */
+   CARRY_FORWARD;
+   SQRADD(a[7], a[7]);
+   COMBA_STORE(b[14]);
+   COMBA_STORE2(b[15]);
+   COMBA_FINI;
+
+   B->used = 16;
+   B->sign = FP_ZPOS;
+   memcpy(B->dp, b, 16 * sizeof(fp_digit));
+   fp_clamp(B);
+}
+#endif
+
+
+/* $Source$ */
+/* $Revision$ */
+/* $Date$ */
diff --git a/tomsfastmath/src/sqr/fp_sqr_comba_9.c b/tomsfastmath/src/sqr/fp_sqr_comba_9.c
new file mode 100644 (file)
index 0000000..87fabbb
--- /dev/null
@@ -0,0 +1,114 @@
+#define TFM_DEFINES
+#include "fp_sqr_comba.c"
+
+#if defined(TFM_SQR9) && FP_SIZE >= 18
+void fp_sqr_comba9(fp_int *A, fp_int *B)
+{
+   fp_digit *a, b[18], c0, c1, c2, sc0, sc1, sc2;
+#ifdef TFM_ISO
+   fp_word tt;
+#endif
+
+   a = A->dp;
+   COMBA_START;
+
+   /* clear carries */
+   CLEAR_CARRY;
+
+   /* output 0 */
+   SQRADD(a[0],a[0]);
+   COMBA_STORE(b[0]);
+
+   /* output 1 */
+   CARRY_FORWARD;
+   SQRADD2(a[0], a[1]);
+   COMBA_STORE(b[1]);
+
+   /* output 2 */
+   CARRY_FORWARD;
+   SQRADD2(a[0], a[2]); SQRADD(a[1], a[1]);
+   COMBA_STORE(b[2]);
+
+   /* output 3 */
+   CARRY_FORWARD;
+   SQRADD2(a[0], a[3]); SQRADD2(a[1], a[2]);
+   COMBA_STORE(b[3]);
+
+   /* output 4 */
+   CARRY_FORWARD;
+   SQRADD2(a[0], a[4]); SQRADD2(a[1], a[3]); SQRADD(a[2], a[2]);
+   COMBA_STORE(b[4]);
+
+   /* output 5 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[5]); SQRADDAC(a[1], a[4]); SQRADDAC(a[2], a[3]); SQRADDDB;
+   COMBA_STORE(b[5]);
+
+   /* output 6 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[6]); SQRADDAC(a[1], a[5]); SQRADDAC(a[2], a[4]); SQRADDDB; SQRADD(a[3], a[3]);
+   COMBA_STORE(b[6]);
+
+   /* output 7 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[7]); SQRADDAC(a[1], a[6]); SQRADDAC(a[2], a[5]); SQRADDAC(a[3], a[4]); SQRADDDB;
+   COMBA_STORE(b[7]);
+
+   /* output 8 */
+   CARRY_FORWARD;
+   SQRADDSC(a[0], a[8]); SQRADDAC(a[1], a[7]); SQRADDAC(a[2], a[6]); SQRADDAC(a[3], a[5]); SQRADDDB; SQRADD(a[4], a[4]);
+   COMBA_STORE(b[8]);
+
+   /* output 9 */
+   CARRY_FORWARD;
+   SQRADDSC(a[1], a[8]); SQRADDAC(a[2], a[7]); SQRADDAC(a[3], a[6]); SQRADDAC(a[4], a[5]); SQRADDDB;
+   COMBA_STORE(b[9]);
+
+   /* output 10 */
+   CARRY_FORWARD;
+   SQRADDSC(a[2], a[8]); SQRADDAC(a[3], a[7]); SQRADDAC(a[4], a[6]); SQRADDDB; SQRADD(a[5], a[5]);
+   COMBA_STORE(b[10]);
+
+   /* output 11 */
+   CARRY_FORWARD;
+   SQRADDSC(a[3], a[8]); SQRADDAC(a[4], a[7]); SQRADDAC(a[5], a[6]); SQRADDDB;
+   COMBA_STORE(b[11]);
+
+   /* output 12 */
+   CARRY_FORWARD;
+   SQRADD2(a[4], a[8]); SQRADD2(a[5], a[7]); SQRADD(a[6], a[6]);
+   COMBA_STORE(b[12]);
+
+   /* output 13 */
+   CARRY_FORWARD;
+   SQRADD2(a[5], a[8]); SQRADD2(a[6], a[7]);
+   COMBA_STORE(b[13]);
+
+   /* output 14 */
+   CARRY_FORWARD;
+   SQRADD2(a[6], a[8]); SQRADD(a[7], a[7]);
+   COMBA_STORE(b[14]);
+
+   /* output 15 */
+   CARRY_FORWARD;
+   SQRADD2(a[7], a[8]);
+   COMBA_STORE(b[15]);
+
+   /* output 16 */
+   CARRY_FORWARD;
+   SQRADD(a[8], a[8]);
+   COMBA_STORE(b[16]);
+   COMBA_STORE2(b[17]);
+   COMBA_FINI;
+
+   B->used = 18;
+   B->sign = FP_ZPOS;
+   memcpy(B->dp, b, 18 * sizeof(fp_digit));
+   fp_clamp(B);
+}
+#endif
+
+
+/* $Source$ */
+/* $Revision$ */
+/* $Date$ */
diff --git a/tomsfastmath/src/sqr/fp_sqr_comba_generic.c b/tomsfastmath/src/sqr/fp_sqr_comba_generic.c
new file mode 100644 (file)
index 0000000..168bd9d
--- /dev/null
@@ -0,0 +1,98 @@
+/* TomsFastMath, a fast ISO C bignum library.
+ * 
+ * This project is meant to fill in where LibTomMath
+ * falls short.  That is speed ;-)
+ *
+ * This project is public domain and free for all purposes.
+ * 
+ * Tom St Denis, tomstdenis@gmail.com
+ */
+
+#define TFM_DEFINES
+#include "fp_sqr_comba.c"
+
+/* generic comba squarer */
+void fp_sqr_comba(fp_int *A, fp_int *B)
+{
+  int       pa, ix, iz;
+  fp_digit  c0, c1, c2;
+  fp_int    tmp, *dst;
+#ifdef TFM_ISO
+  fp_word   tt;
+#endif    
+
+  /* get size of output and trim */
+  pa = A->used + A->used;
+  if (pa >= FP_SIZE) {
+     pa = FP_SIZE-1;
+  }
+
+  /* number of output digits to produce */
+  COMBA_START;
+  CLEAR_CARRY;
+
+  if (A == B) {
+     fp_zero(&tmp);
+     dst = &tmp;
+  } else {
+     fp_zero(B);
+     dst = B;
+  }
+
+  for (ix = 0; ix < pa; ix++) { 
+      int      tx, ty, iy;
+      fp_digit *tmpy, *tmpx;
+
+      /* get offsets into the two bignums */
+      ty = MIN(A->used-1, ix);
+      tx = ix - ty;
+
+      /* setup temp aliases */
+      tmpx = A->dp + tx;
+      tmpy = A->dp + ty;
+
+      /* this is the number of times the loop will iterrate,
+         while (tx++ < a->used && ty-- >= 0) { ... }
+       */
+      iy = MIN(A->used-tx, ty+1);
+
+      /* now for squaring tx can never equal ty 
+       * we halve the distance since they approach 
+       * at a rate of 2x and we have to round because 
+       * odd cases need to be executed
+       */
+      iy = MIN(iy, (ty-tx+1)>>1);
+
+      /* forward carries */
+      CARRY_FORWARD;
+
+      /* execute loop */
+      for (iz = 0; iz < iy; iz++) {
+          fp_digit _tmpx = *tmpx++;
+          fp_digit _tmpy = *tmpy--;
+          SQRADD2(_tmpx, _tmpy);
+      }
+
+      /* even columns have the square term in them */
+      if ((ix&1) == 0) {
+          fp_digit _a_dp = A->dp[ix>>1];
+          SQRADD(_a_dp, A->dp[ix>>1]);
+      }
+
+      /* store it */
+      COMBA_STORE(dst->dp[ix]);
+  }
+
+  COMBA_FINI;
+
+  /* setup dest */
+  dst->used = pa;
+  fp_clamp (dst);
+  if (dst != B) {
+     fp_copy(dst, B);
+  }
+}
+
+/* $Source$ */
+/* $Revision$ */
+/* $Date$ */
diff --git a/tomsfastmath/src/sqr/fp_sqr_comba_small_set.c b/tomsfastmath/src/sqr/fp_sqr_comba_small_set.c
new file mode 100644 (file)
index 0000000..86ba037
--- /dev/null
@@ -0,0 +1,1523 @@
+#define TFM_DEFINES
+#include "fp_sqr_comba.c"
+
+#if defined(TFM_SMALL_SET)
+void fp_sqr_comba_small(fp_int *A, fp_int *B)
+{
+   fp_digit *a, b[32], c0, c1, c2, sc0, sc1, sc2;
+#ifdef TFM_ISO
+   fp_word tt;
+#endif
+   switch (A->used) { 
+   case 1:
+      a = A->dp;
+      COMBA_START; 
+
+      /* clear carries */
+      CLEAR_CARRY;
+
+      /* output 0 */
+      SQRADD(a[0],a[0]);
+      COMBA_STORE(b[0]);
+      COMBA_STORE2(b[1]);
+      COMBA_FINI;
+
+      B->used = 2;
+      B->sign = FP_ZPOS;
+      memcpy(B->dp, b, 2 * sizeof(fp_digit));
+      fp_clamp(B);
+      break;
+
+   case 2:
+      a = A->dp;
+      COMBA_START; 
+
+      /* clear carries */
+      CLEAR_CARRY;
+
+      /* output 0 */
+      SQRADD(a[0],a[0]);
+      COMBA_STORE(b[0]);
+
+      /* output 1 */
+      CARRY_FORWARD;
+      SQRADD2(a[0], a[1]); 
+      COMBA_STORE(b[1]);
+
+      /* output 2 */
+      CARRY_FORWARD;
+      SQRADD(a[1], a[1]); 
+      COMBA_STORE(b[2]);
+      COMBA_STORE2(b[3]);
+      COMBA_FINI;
+
+      B->used = 4;
+      B->sign = FP_ZPOS;
+      memcpy(B->dp, b, 4 * sizeof(fp_digit));
+      fp_clamp(B);
+      break;
+
+   case 3:
+      a = A->dp;
+      COMBA_START; 
+
+      /* clear carries */
+      CLEAR_CARRY;
+
+      /* output 0 */
+      SQRADD(a[0],a[0]);
+      COMBA_STORE(b[0]);
+
+      /* output 1 */
+      CARRY_FORWARD;
+      SQRADD2(a[0], a[1]); 
+      COMBA_STORE(b[1]);
+
+      /* output 2 */
+      CARRY_FORWARD;
+      SQRADD2(a[0], a[2]);    SQRADD(a[1], a[1]); 
+      COMBA_STORE(b[2]);
+
+      /* output 3 */
+      CARRY_FORWARD;
+      SQRADD2(a[1], a[2]); 
+      COMBA_STORE(b[3]);
+
+      /* output 4 */
+      CARRY_FORWARD;
+      SQRADD(a[2], a[2]); 
+      COMBA_STORE(b[4]);
+      COMBA_STORE2(b[5]);
+      COMBA_FINI;
+
+      B->used = 6;
+      B->sign = FP_ZPOS;
+      memcpy(B->dp, b, 6 * sizeof(fp_digit));
+      fp_clamp(B);
+      break;
+
+   case 4:
+      a = A->dp;
+      COMBA_START; 
+
+      /* clear carries */
+      CLEAR_CARRY;
+
+      /* output 0 */
+      SQRADD(a[0],a[0]);
+      COMBA_STORE(b[0]);
+
+      /* output 1 */
+      CARRY_FORWARD;
+      SQRADD2(a[0], a[1]); 
+      COMBA_STORE(b[1]);
+
+      /* output 2 */
+      CARRY_FORWARD;
+      SQRADD2(a[0], a[2]);    SQRADD(a[1], a[1]); 
+      COMBA_STORE(b[2]);
+
+      /* output 3 */
+      CARRY_FORWARD;
+      SQRADD2(a[0], a[3]);    SQRADD2(a[1], a[2]); 
+      COMBA_STORE(b[3]);
+
+      /* output 4 */
+      CARRY_FORWARD;
+      SQRADD2(a[1], a[3]);    SQRADD(a[2], a[2]); 
+      COMBA_STORE(b[4]);
+
+      /* output 5 */
+      CARRY_FORWARD;
+      SQRADD2(a[2], a[3]); 
+      COMBA_STORE(b[5]);
+
+      /* output 6 */
+      CARRY_FORWARD;
+      SQRADD(a[3], a[3]); 
+      COMBA_STORE(b[6]);
+      COMBA_STORE2(b[7]);
+      COMBA_FINI;
+
+      B->used = 8;
+      B->sign = FP_ZPOS;
+      memcpy(B->dp, b, 8 * sizeof(fp_digit));
+      fp_clamp(B);
+      break;
+
+   case 5:
+      a = A->dp;
+      COMBA_START; 
+
+      /* clear carries */
+      CLEAR_CARRY;
+
+      /* output 0 */
+      SQRADD(a[0],a[0]);
+      COMBA_STORE(b[0]);
+
+      /* output 1 */
+      CARRY_FORWARD;
+      SQRADD2(a[0], a[1]); 
+      COMBA_STORE(b[1]);
+
+      /* output 2 */
+      CARRY_FORWARD;
+      SQRADD2(a[0], a[2]);    SQRADD(a[1], a[1]); 
+      COMBA_STORE(b[2]);
+
+      /* output 3 */
+      CARRY_FORWARD;
+      SQRADD2(a[0], a[3]);    SQRADD2(a[1], a[2]); 
+      COMBA_STORE(b[3]);
+
+      /* output 4 */
+      CARRY_FORWARD;
+      SQRADD2(a[0], a[4]);    SQRADD2(a[1], a[3]);    SQRADD(a[2], a[2]); 
+      COMBA_STORE(b[4]);
+
+      /* output 5 */
+      CARRY_FORWARD;
+      SQRADD2(a[1], a[4]);    SQRADD2(a[2], a[3]); 
+      COMBA_STORE(b[5]);
+
+      /* output 6 */
+      CARRY_FORWARD;
+      SQRADD2(a[2], a[4]);    SQRADD(a[3], a[3]); 
+      COMBA_STORE(b[6]);
+
+      /* output 7 */
+      CARRY_FORWARD;
+      SQRADD2(a[3], a[4]); 
+      COMBA_STORE(b[7]);
+
+      /* output 8 */
+      CARRY_FORWARD;
+      SQRADD(a[4], a[4]); 
+      COMBA_STORE(b[8]);
+      COMBA_STORE2(b[9]);
+      COMBA_FINI;
+
+      B->used = 10;
+      B->sign = FP_ZPOS;
+      memcpy(B->dp, b, 10 * sizeof(fp_digit));
+      fp_clamp(B);
+      break;
+
+   case 6:
+      a = A->dp;
+      COMBA_START; 
+
+      /* clear carries */
+      CLEAR_CARRY;
+
+      /* output 0 */
+      SQRADD(a[0],a[0]);
+      COMBA_STORE(b[0]);
+
+      /* output 1 */
+      CARRY_FORWARD;
+      SQRADD2(a[0], a[1]); 
+      COMBA_STORE(b[1]);
+
+      /* output 2 */
+      CARRY_FORWARD;
+      SQRADD2(a[0], a[2]);    SQRADD(a[1], a[1]); 
+      COMBA_STORE(b[2]);
+
+      /* output 3 */
+      CARRY_FORWARD;
+      SQRADD2(a[0], a[3]);    SQRADD2(a[1], a[2]); 
+      COMBA_STORE(b[3]);
+
+      /* output 4 */
+      CARRY_FORWARD;
+      SQRADD2(a[0], a[4]);    SQRADD2(a[1], a[3]);    SQRADD(a[2], a[2]); 
+      COMBA_STORE(b[4]);
+
+      /* output 5 */
+      CARRY_FORWARD;
+   SQRADDSC(a[0], a[5]); SQRADDAC(a[1], a[4]); SQRADDAC(a[2], a[3]); SQRADDDB; 
+      COMBA_STORE(b[5]);
+
+      /* output 6 */
+      CARRY_FORWARD;
+      SQRADD2(a[1], a[5]);    SQRADD2(a[2], a[4]);    SQRADD(a[3], a[3]); 
+      COMBA_STORE(b[6]);
+
+      /* output 7 */
+      CARRY_FORWARD;
+      SQRADD2(a[2], a[5]);    SQRADD2(a[3], a[4]); 
+      COMBA_STORE(b[7]);
+
+      /* output 8 */
+      CARRY_FORWARD;
+      SQRADD2(a[3], a[5]);    SQRADD(a[4], a[4]); 
+      COMBA_STORE(b[8]);
+
+      /* output 9 */
+      CARRY_FORWARD;
+      SQRADD2(a[4], a[5]); 
+      COMBA_STORE(b[9]);
+
+      /* output 10 */
+      CARRY_FORWARD;
+      SQRADD(a[5], a[5]); 
+      COMBA_STORE(b[10]);
+      COMBA_STORE2(b[11]);
+      COMBA_FINI;
+
+      B->used = 12;
+      B->sign = FP_ZPOS;
+      memcpy(B->dp, b, 12 * sizeof(fp_digit));
+      fp_clamp(B);
+      break;
+
+   case 7:
+      a = A->dp;
+      COMBA_START; 
+
+      /* clear carries */
+      CLEAR_CARRY;
+
+      /* output 0 */
+      SQRADD(a[0],a[0]);
+      COMBA_STORE(b[0]);
+
+      /* output 1 */
+      CARRY_FORWARD;
+      SQRADD2(a[0], a[1]); 
+      COMBA_STORE(b[1]);
+
+      /* output 2 */
+      CARRY_FORWARD;
+      SQRADD2(a[0], a[2]);    SQRADD(a[1], a[1]); 
+      COMBA_STORE(b[2]);
+
+      /* output 3 */
+      CARRY_FORWARD;
+      SQRADD2(a[0], a[3]);    SQRADD2(a[1], a[2]); 
+      COMBA_STORE(b[3]);
+
+      /* output 4 */
+      CARRY_FORWARD;
+      SQRADD2(a[0], a[4]);    SQRADD2(a[1], a[3]);    SQRADD(a[2], a[2]); 
+      COMBA_STORE(b[4]);
+
+      /* output 5 */
+      CARRY_FORWARD;
+   SQRADDSC(a[0], a[5]); SQRADDAC(a[1], a[4]); SQRADDAC(a[2], a[3]); SQRADDDB; 
+      COMBA_STORE(b[5]);
+
+      /* output 6 */
+      CARRY_FORWARD;
+   SQRADDSC(a[0], a[6]); SQRADDAC(a[1], a[5]); SQRADDAC(a[2], a[4]); SQRADDDB; SQRADD(a[3], a[3]); 
+      COMBA_STORE(b[6]);
+
+      /* output 7 */
+      CARRY_FORWARD;
+   SQRADDSC(a[1], a[6]); SQRADDAC(a[2], a[5]); SQRADDAC(a[3], a[4]); SQRADDDB; 
+      COMBA_STORE(b[7]);
+
+      /* output 8 */
+      CARRY_FORWARD;
+      SQRADD2(a[2], a[6]);    SQRADD2(a[3], a[5]);    SQRADD(a[4], a[4]); 
+      COMBA_STORE(b[8]);
+
+      /* output 9 */
+      CARRY_FORWARD;
+      SQRADD2(a[3], a[6]);    SQRADD2(a[4], a[5]); 
+      COMBA_STORE(b[9]);
+
+      /* output 10 */
+      CARRY_FORWARD;
+      SQRADD2(a[4], a[6]);    SQRADD(a[5], a[5]); 
+      COMBA_STORE(b[10]);
+
+      /* output 11 */
+      CARRY_FORWARD;
+      SQRADD2(a[5], a[6]); 
+      COMBA_STORE(b[11]);
+
+      /* output 12 */
+      CARRY_FORWARD;
+      SQRADD(a[6], a[6]); 
+      COMBA_STORE(b[12]);
+      COMBA_STORE2(b[13]);
+      COMBA_FINI;
+
+      B->used = 14;
+      B->sign = FP_ZPOS;
+      memcpy(B->dp, b, 14 * sizeof(fp_digit));
+      fp_clamp(B);
+      break;
+
+   case 8:
+      a = A->dp;
+      COMBA_START; 
+
+      /* clear carries */
+      CLEAR_CARRY;
+
+      /* output 0 */
+      SQRADD(a[0],a[0]);
+      COMBA_STORE(b[0]);
+
+      /* output 1 */
+      CARRY_FORWARD;
+      SQRADD2(a[0], a[1]); 
+      COMBA_STORE(b[1]);
+
+      /* output 2 */
+      CARRY_FORWARD;
+      SQRADD2(a[0], a[2]);    SQRADD(a[1], a[1]); 
+      COMBA_STORE(b[2]);
+
+      /* output 3 */
+      CARRY_FORWARD;
+      SQRADD2(a[0], a[3]);    SQRADD2(a[1], a[2]); 
+      COMBA_STORE(b[3]);
+
+      /* output 4 */
+      CARRY_FORWARD;
+      SQRADD2(a[0], a[4]);    SQRADD2(a[1], a[3]);    SQRADD(a[2], a[2]); 
+      COMBA_STORE(b[4]);
+
+      /* output 5 */
+      CARRY_FORWARD;
+   SQRADDSC(a[0], a[5]); SQRADDAC(a[1], a[4]); SQRADDAC(a[2], a[3]); SQRADDDB; 
+      COMBA_STORE(b[5]);
+
+      /* output 6 */
+      CARRY_FORWARD;
+   SQRADDSC(a[0], a[6]); SQRADDAC(a[1], a[5]); SQRADDAC(a[2], a[4]); SQRADDDB; SQRADD(a[3], a[3]); 
+      COMBA_STORE(b[6]);
+
+      /* output 7 */
+      CARRY_FORWARD;
+   SQRADDSC(a[0], a[7]); SQRADDAC(a[1], a[6]); SQRADDAC(a[2], a[5]); SQRADDAC(a[3], a[4]); SQRADDDB; 
+      COMBA_STORE(b[7]);
+
+      /* output 8 */
+      CARRY_FORWARD;
+   SQRADDSC(a[1], a[7]); SQRADDAC(a[2], a[6]); SQRADDAC(a[3], a[5]); SQRADDDB; SQRADD(a[4], a[4]); 
+      COMBA_STORE(b[8]);
+
+      /* output 9 */
+      CARRY_FORWARD;
+   SQRADDSC(a[2], a[7]); SQRADDAC(a[3], a[6]); SQRADDAC(a[4], a[5]); SQRADDDB; 
+      COMBA_STORE(b[9]);
+
+      /* output 10 */
+      CARRY_FORWARD;
+      SQRADD2(a[3], a[7]);    SQRADD2(a[4], a[6]);    SQRADD(a[5], a[5]); 
+      COMBA_STORE(b[10]);
+
+      /* output 11 */
+      CARRY_FORWARD;
+      SQRADD2(a[4], a[7]);    SQRADD2(a[5], a[6]); 
+      COMBA_STORE(b[11]);
+
+      /* output 12 */
+      CARRY_FORWARD;
+      SQRADD2(a[5], a[7]);    SQRADD(a[6], a[6]); 
+      COMBA_STORE(b[12]);
+
+      /* output 13 */
+      CARRY_FORWARD;
+      SQRADD2(a[6], a[7]); 
+      COMBA_STORE(b[13]);
+
+      /* output 14 */
+      CARRY_FORWARD;
+      SQRADD(a[7], a[7]); 
+      COMBA_STORE(b[14]);
+      COMBA_STORE2(b[15]);
+      COMBA_FINI;
+
+      B->used = 16;
+      B->sign = FP_ZPOS;
+      memcpy(B->dp, b, 16 * sizeof(fp_digit));
+      fp_clamp(B);
+      break;
+
+   case 9:
+      a = A->dp;
+      COMBA_START; 
+
+      /* clear carries */
+      CLEAR_CARRY;
+
+      /* output 0 */
+      SQRADD(a[0],a[0]);
+      COMBA_STORE(b[0]);
+
+      /* output 1 */
+      CARRY_FORWARD;
+      SQRADD2(a[0], a[1]); 
+      COMBA_STORE(b[1]);
+
+      /* output 2 */
+      CARRY_FORWARD;
+      SQRADD2(a[0], a[2]);    SQRADD(a[1], a[1]); 
+      COMBA_STORE(b[2]);
+
+      /* output 3 */
+      CARRY_FORWARD;
+      SQRADD2(a[0], a[3]);    SQRADD2(a[1], a[2]); 
+      COMBA_STORE(b[3]);
+
+      /* output 4 */
+      CARRY_FORWARD;
+      SQRADD2(a[0], a[4]);    SQRADD2(a[1], a[3]);    SQRADD(a[2], a[2]); 
+      COMBA_STORE(b[4]);
+
+      /* output 5 */
+      CARRY_FORWARD;
+   SQRADDSC(a[0], a[5]); SQRADDAC(a[1], a[4]); SQRADDAC(a[2], a[3]); SQRADDDB; 
+      COMBA_STORE(b[5]);
+
+      /* output 6 */
+      CARRY_FORWARD;
+   SQRADDSC(a[0], a[6]); SQRADDAC(a[1], a[5]); SQRADDAC(a[2], a[4]); SQRADDDB; SQRADD(a[3], a[3]); 
+      COMBA_STORE(b[6]);
+
+      /* output 7 */
+      CARRY_FORWARD;
+   SQRADDSC(a[0], a[7]); SQRADDAC(a[1], a[6]); SQRADDAC(a[2], a[5]); SQRADDAC(a[3], a[4]); SQRADDDB; 
+      COMBA_STORE(b[7]);
+
+      /* output 8 */
+      CARRY_FORWARD;
+   SQRADDSC(a[0], a[8]); SQRADDAC(a[1], a[7]); SQRADDAC(a[2], a[6]); SQRADDAC(a[3], a[5]); SQRADDDB; SQRADD(a[4], a[4]); 
+      COMBA_STORE(b[8]);
+
+      /* output 9 */
+      CARRY_FORWARD;
+   SQRADDSC(a[1], a[8]); SQRADDAC(a[2], a[7]); SQRADDAC(a[3], a[6]); SQRADDAC(a[4], a[5]); SQRADDDB; 
+      COMBA_STORE(b[9]);
+
+      /* output 10 */
+      CARRY_FORWARD;
+   SQRADDSC(a[2], a[8]); SQRADDAC(a[3], a[7]); SQRADDAC(a[4], a[6]); SQRADDDB; SQRADD(a[5], a[5]); 
+      COMBA_STORE(b[10]);
+
+      /* output 11 */
+      CARRY_FORWARD;
+   SQRADDSC(a[3], a[8]); SQRADDAC(a[4], a[7]); SQRADDAC(a[5], a[6]); SQRADDDB; 
+      COMBA_STORE(b[11]);
+
+      /* output 12 */
+      CARRY_FORWARD;
+      SQRADD2(a[4], a[8]);    SQRADD2(a[5], a[7]);    SQRADD(a[6], a[6]); 
+      COMBA_STORE(b[12]);
+
+      /* output 13 */
+      CARRY_FORWARD;
+      SQRADD2(a[5], a[8]);    SQRADD2(a[6], a[7]); 
+      COMBA_STORE(b[13]);
+
+      /* output 14 */
+      CARRY_FORWARD;
+      SQRADD2(a[6], a[8]);    SQRADD(a[7], a[7]); 
+      COMBA_STORE(b[14]);
+
+      /* output 15 */
+      CARRY_FORWARD;
+      SQRADD2(a[7], a[8]); 
+      COMBA_STORE(b[15]);
+
+      /* output 16 */
+      CARRY_FORWARD;
+      SQRADD(a[8], a[8]); 
+      COMBA_STORE(b[16]);
+      COMBA_STORE2(b[17]);
+      COMBA_FINI;
+
+      B->used = 18;
+      B->sign = FP_ZPOS;
+      memcpy(B->dp, b, 18 * sizeof(fp_digit));
+      fp_clamp(B);
+      break;
+
+   case 10:
+      a = A->dp;
+      COMBA_START; 
+
+      /* clear carries */
+      CLEAR_CARRY;
+
+      /* output 0 */
+      SQRADD(a[0],a[0]);
+      COMBA_STORE(b[0]);
+
+      /* output 1 */
+      CARRY_FORWARD;
+      SQRADD2(a[0], a[1]); 
+      COMBA_STORE(b[1]);
+
+      /* output 2 */
+      CARRY_FORWARD;
+      SQRADD2(a[0], a[2]);    SQRADD(a[1], a[1]); 
+      COMBA_STORE(b[2]);
+
+      /* output 3 */
+      CARRY_FORWARD;
+      SQRADD2(a[0], a[3]);    SQRADD2(a[1], a[2]); 
+      COMBA_STORE(b[3]);
+
+      /* output 4 */
+      CARRY_FORWARD;
+      SQRADD2(a[0], a[4]);    SQRADD2(a[1], a[3]);    SQRADD(a[2], a[2]); 
+      COMBA_STORE(b[4]);
+
+      /* output 5 */
+      CARRY_FORWARD;
+   SQRADDSC(a[0], a[5]); SQRADDAC(a[1], a[4]); SQRADDAC(a[2], a[3]); SQRADDDB; 
+      COMBA_STORE(b[5]);
+
+      /* output 6 */
+      CARRY_FORWARD;
+   SQRADDSC(a[0], a[6]); SQRADDAC(a[1], a[5]); SQRADDAC(a[2], a[4]); SQRADDDB; SQRADD(a[3], a[3]); 
+      COMBA_STORE(b[6]);
+
+      /* output 7 */
+      CARRY_FORWARD;
+   SQRADDSC(a[0], a[7]); SQRADDAC(a[1], a[6]); SQRADDAC(a[2], a[5]); SQRADDAC(a[3], a[4]); SQRADDDB; 
+      COMBA_STORE(b[7]);
+
+      /* output 8 */
+      CARRY_FORWARD;
+   SQRADDSC(a[0], a[8]); SQRADDAC(a[1], a[7]); SQRADDAC(a[2], a[6]); SQRADDAC(a[3], a[5]); SQRADDDB; SQRADD(a[4], a[4]); 
+      COMBA_STORE(b[8]);
+
+      /* output 9 */
+      CARRY_FORWARD;
+   SQRADDSC(a[0], a[9]); SQRADDAC(a[1], a[8]); SQRADDAC(a[2], a[7]); SQRADDAC(a[3], a[6]); SQRADDAC(a[4], a[5]); SQRADDDB; 
+      COMBA_STORE(b[9]);
+
+      /* output 10 */
+      CARRY_FORWARD;
+   SQRADDSC(a[1], a[9]); SQRADDAC(a[2], a[8]); SQRADDAC(a[3], a[7]); SQRADDAC(a[4], a[6]); SQRADDDB; SQRADD(a[5], a[5]); 
+      COMBA_STORE(b[10]);
+
+      /* output 11 */
+      CARRY_FORWARD;
+   SQRADDSC(a[2], a[9]); SQRADDAC(a[3], a[8]); SQRADDAC(a[4], a[7]); SQRADDAC(a[5], a[6]); SQRADDDB; 
+      COMBA_STORE(b[11]);
+
+      /* output 12 */
+      CARRY_FORWARD;
+   SQRADDSC(a[3], a[9]); SQRADDAC(a[4], a[8]); SQRADDAC(a[5], a[7]); SQRADDDB; SQRADD(a[6], a[6]); 
+      COMBA_STORE(b[12]);
+
+      /* output 13 */
+      CARRY_FORWARD;
+   SQRADDSC(a[4], a[9]); SQRADDAC(a[5], a[8]); SQRADDAC(a[6], a[7]); SQRADDDB; 
+      COMBA_STORE(b[13]);
+
+      /* output 14 */
+      CARRY_FORWARD;
+      SQRADD2(a[5], a[9]);    SQRADD2(a[6], a[8]);    SQRADD(a[7], a[7]); 
+      COMBA_STORE(b[14]);
+
+      /* output 15 */
+      CARRY_FORWARD;
+      SQRADD2(a[6], a[9]);    SQRADD2(a[7], a[8]); 
+      COMBA_STORE(b[15]);
+
+      /* output 16 */
+      CARRY_FORWARD;
+      SQRADD2(a[7], a[9]);    SQRADD(a[8], a[8]); 
+      COMBA_STORE(b[16]);
+
+      /* output 17 */
+      CARRY_FORWARD;
+      SQRADD2(a[8], a[9]); 
+      COMBA_STORE(b[17]);
+
+      /* output 18 */
+      CARRY_FORWARD;
+      SQRADD(a[9], a[9]); 
+      COMBA_STORE(b[18]);
+      COMBA_STORE2(b[19]);
+      COMBA_FINI;
+
+      B->used = 20;
+      B->sign = FP_ZPOS;
+      memcpy(B->dp, b, 20 * sizeof(fp_digit));
+      fp_clamp(B);
+      break;
+
+   case 11:
+      a = A->dp;
+      COMBA_START; 
+
+      /* clear carries */
+      CLEAR_CARRY;
+
+      /* output 0 */
+      SQRADD(a[0],a[0]);
+      COMBA_STORE(b[0]);
+
+      /* output 1 */
+      CARRY_FORWARD;
+      SQRADD2(a[0], a[1]); 
+      COMBA_STORE(b[1]);
+
+      /* output 2 */
+      CARRY_FORWARD;
+      SQRADD2(a[0], a[2]);    SQRADD(a[1], a[1]); 
+      COMBA_STORE(b[2]);
+
+      /* output 3 */
+      CARRY_FORWARD;
+      SQRADD2(a[0], a[3]);    SQRADD2(a[1], a[2]); 
+      COMBA_STORE(b[3]);
+
+      /* output 4 */
+      CARRY_FORWARD;
+      SQRADD2(a[0], a[4]);    SQRADD2(a[1], a[3]);    SQRADD(a[2], a[2]); 
+      COMBA_STORE(b[4]);
+
+      /* output 5 */
+      CARRY_FORWARD;
+   SQRADDSC(a[0], a[5]); SQRADDAC(a[1], a[4]); SQRADDAC(a[2], a[3]); SQRADDDB; 
+      COMBA_STORE(b[5]);
+
+      /* output 6 */
+      CARRY_FORWARD;
+   SQRADDSC(a[0], a[6]); SQRADDAC(a[1], a[5]); SQRADDAC(a[2], a[4]); SQRADDDB; SQRADD(a[3], a[3]); 
+      COMBA_STORE(b[6]);
+
+      /* output 7 */
+      CARRY_FORWARD;
+   SQRADDSC(a[0], a[7]); SQRADDAC(a[1], a[6]); SQRADDAC(a[2], a[5]); SQRADDAC(a[3], a[4]); SQRADDDB; 
+      COMBA_STORE(b[7]);
+
+      /* output 8 */
+      CARRY_FORWARD;
+   SQRADDSC(a[0], a[8]); SQRADDAC(a[1], a[7]); SQRADDAC(a[2], a[6]); SQRADDAC(a[3], a[5]); SQRADDDB; SQRADD(a[4], a[4]); 
+      COMBA_STORE(b[8]);
+
+      /* output 9 */
+      CARRY_FORWARD;
+   SQRADDSC(a[0], a[9]); SQRADDAC(a[1], a[8]); SQRADDAC(a[2], a[7]); SQRADDAC(a[3], a[6]); SQRADDAC(a[4], a[5]); SQRADDDB; 
+      COMBA_STORE(b[9]);
+
+      /* output 10 */
+      CARRY_FORWARD;
+   SQRADDSC(a[0], a[10]); SQRADDAC(a[1], a[9]); SQRADDAC(a[2], a[8]); SQRADDAC(a[3], a[7]); SQRADDAC(a[4], a[6]); SQRADDDB; SQRADD(a[5], a[5]); 
+      COMBA_STORE(b[10]);
+
+      /* output 11 */
+      CARRY_FORWARD;
+   SQRADDSC(a[1], a[10]); SQRADDAC(a[2], a[9]); SQRADDAC(a[3], a[8]); SQRADDAC(a[4], a[7]); SQRADDAC(a[5], a[6]); SQRADDDB; 
+      COMBA_STORE(b[11]);
+
+      /* output 12 */
+      CARRY_FORWARD;
+   SQRADDSC(a[2], a[10]); SQRADDAC(a[3], a[9]); SQRADDAC(a[4], a[8]); SQRADDAC(a[5], a[7]); SQRADDDB; SQRADD(a[6], a[6]); 
+      COMBA_STORE(b[12]);
+
+      /* output 13 */
+      CARRY_FORWARD;
+   SQRADDSC(a[3], a[10]); SQRADDAC(a[4], a[9]); SQRADDAC(a[5], a[8]); SQRADDAC(a[6], a[7]); SQRADDDB; 
+      COMBA_STORE(b[13]);
+
+      /* output 14 */
+      CARRY_FORWARD;
+   SQRADDSC(a[4], a[10]); SQRADDAC(a[5], a[9]); SQRADDAC(a[6], a[8]); SQRADDDB; SQRADD(a[7], a[7]); 
+      COMBA_STORE(b[14]);
+
+      /* output 15 */
+      CARRY_FORWARD;
+   SQRADDSC(a[5], a[10]); SQRADDAC(a[6], a[9]); SQRADDAC(a[7], a[8]); SQRADDDB; 
+      COMBA_STORE(b[15]);
+
+      /* output 16 */
+      CARRY_FORWARD;
+      SQRADD2(a[6], a[10]);    SQRADD2(a[7], a[9]);    SQRADD(a[8], a[8]); 
+      COMBA_STORE(b[16]);
+
+      /* output 17 */
+      CARRY_FORWARD;
+      SQRADD2(a[7], a[10]);    SQRADD2(a[8], a[9]); 
+      COMBA_STORE(b[17]);
+
+      /* output 18 */
+      CARRY_FORWARD;
+      SQRADD2(a[8], a[10]);    SQRADD(a[9], a[9]); 
+      COMBA_STORE(b[18]);
+
+      /* output 19 */
+      CARRY_FORWARD;
+      SQRADD2(a[9], a[10]); 
+      COMBA_STORE(b[19]);
+
+      /* output 20 */
+      CARRY_FORWARD;
+      SQRADD(a[10], a[10]); 
+      COMBA_STORE(b[20]);
+      COMBA_STORE2(b[21]);
+      COMBA_FINI;
+
+      B->used = 22;
+      B->sign = FP_ZPOS;
+      memcpy(B->dp, b, 22 * sizeof(fp_digit));
+      fp_clamp(B);
+      break;
+
+   case 12:
+      a = A->dp;
+      COMBA_START; 
+
+      /* clear carries */
+      CLEAR_CARRY;
+
+      /* output 0 */
+      SQRADD(a[0],a[0]);
+      COMBA_STORE(b[0]);
+
+      /* output 1 */
+      CARRY_FORWARD;
+      SQRADD2(a[0], a[1]); 
+      COMBA_STORE(b[1]);
+
+      /* output 2 */
+      CARRY_FORWARD;
+      SQRADD2(a[0], a[2]);    SQRADD(a[1], a[1]); 
+      COMBA_STORE(b[2]);
+
+      /* output 3 */
+      CARRY_FORWARD;
+      SQRADD2(a[0], a[3]);    SQRADD2(a[1], a[2]); 
+      COMBA_STORE(b[3]);
+
+      /* output 4 */
+      CARRY_FORWARD;
+      SQRADD2(a[0], a[4]);    SQRADD2(a[1], a[3]);    SQRADD(a[2], a[2]); 
+      COMBA_STORE(b[4]);
+
+      /* output 5 */
+      CARRY_FORWARD;
+   SQRADDSC(a[0], a[5]); SQRADDAC(a[1], a[4]); SQRADDAC(a[2], a[3]); SQRADDDB; 
+      COMBA_STORE(b[5]);
+
+      /* output 6 */
+      CARRY_FORWARD;
+   SQRADDSC(a[0], a[6]); SQRADDAC(a[1], a[5]); SQRADDAC(a[2], a[4]); SQRADDDB; SQRADD(a[3], a[3]); 
+      COMBA_STORE(b[6]);
+
+      /* output 7 */
+      CARRY_FORWARD;
+   SQRADDSC(a[0], a[7]); SQRADDAC(a[1], a[6]); SQRADDAC(a[2], a[5]); SQRADDAC(a[3], a[4]); SQRADDDB; 
+      COMBA_STORE(b[7]);
+
+      /* output 8 */
+      CARRY_FORWARD;
+   SQRADDSC(a[0], a[8]); SQRADDAC(a[1], a[7]); SQRADDAC(a[2], a[6]); SQRADDAC(a[3], a[5]); SQRADDDB; SQRADD(a[4], a[4]); 
+      COMBA_STORE(b[8]);
+
+      /* output 9 */
+      CARRY_FORWARD;
+   SQRADDSC(a[0], a[9]); SQRADDAC(a[1], a[8]); SQRADDAC(a[2], a[7]); SQRADDAC(a[3], a[6]); SQRADDAC(a[4], a[5]); SQRADDDB; 
+      COMBA_STORE(b[9]);
+
+      /* output 10 */
+      CARRY_FORWARD;
+   SQRADDSC(a[0], a[10]); SQRADDAC(a[1], a[9]); SQRADDAC(a[2], a[8]); SQRADDAC(a[3], a[7]); SQRADDAC(a[4], a[6]); SQRADDDB; SQRADD(a[5], a[5]); 
+      COMBA_STORE(b[10]);
+
+      /* output 11 */
+      CARRY_FORWARD;
+   SQRADDSC(a[0], a[11]); SQRADDAC(a[1], a[10]); SQRADDAC(a[2], a[9]); SQRADDAC(a[3], a[8]); SQRADDAC(a[4], a[7]); SQRADDAC(a[5], a[6]); SQRADDDB; 
+      COMBA_STORE(b[11]);
+
+      /* output 12 */
+      CARRY_FORWARD;
+   SQRADDSC(a[1], a[11]); SQRADDAC(a[2], a[10]); SQRADDAC(a[3], a[9]); SQRADDAC(a[4], a[8]); SQRADDAC(a[5], a[7]); SQRADDDB; SQRADD(a[6], a[6]); 
+      COMBA_STORE(b[12]);
+
+      /* output 13 */
+      CARRY_FORWARD;
+   SQRADDSC(a[2], a[11]); SQRADDAC(a[3], a[10]); SQRADDAC(a[4], a[9]); SQRADDAC(a[5], a[8]); SQRADDAC(a[6], a[7]); SQRADDDB; 
+      COMBA_STORE(b[13]);
+
+      /* output 14 */
+      CARRY_FORWARD;
+   SQRADDSC(a[3], a[11]); SQRADDAC(a[4], a[10]); SQRADDAC(a[5], a[9]); SQRADDAC(a[6], a[8]); SQRADDDB; SQRADD(a[7], a[7]); 
+      COMBA_STORE(b[14]);
+
+      /* output 15 */
+      CARRY_FORWARD;
+   SQRADDSC(a[4], a[11]); SQRADDAC(a[5], a[10]); SQRADDAC(a[6], a[9]); SQRADDAC(a[7], a[8]); SQRADDDB; 
+      COMBA_STORE(b[15]);
+
+      /* output 16 */
+      CARRY_FORWARD;
+   SQRADDSC(a[5], a[11]); SQRADDAC(a[6], a[10]); SQRADDAC(a[7], a[9]); SQRADDDB; SQRADD(a[8], a[8]); 
+      COMBA_STORE(b[16]);
+
+      /* output 17 */
+      CARRY_FORWARD;
+   SQRADDSC(a[6], a[11]); SQRADDAC(a[7], a[10]); SQRADDAC(a[8], a[9]); SQRADDDB; 
+      COMBA_STORE(b[17]);
+
+      /* output 18 */
+      CARRY_FORWARD;
+      SQRADD2(a[7], a[11]);    SQRADD2(a[8], a[10]);    SQRADD(a[9], a[9]); 
+      COMBA_STORE(b[18]);
+
+      /* output 19 */
+      CARRY_FORWARD;
+      SQRADD2(a[8], a[11]);    SQRADD2(a[9], a[10]); 
+      COMBA_STORE(b[19]);
+
+      /* output 20 */
+      CARRY_FORWARD;
+      SQRADD2(a[9], a[11]);    SQRADD(a[10], a[10]); 
+      COMBA_STORE(b[20]);
+
+      /* output 21 */
+      CARRY_FORWARD;
+      SQRADD2(a[10], a[11]); 
+      COMBA_STORE(b[21]);
+
+      /* output 22 */
+      CARRY_FORWARD;
+      SQRADD(a[11], a[11]); 
+      COMBA_STORE(b[22]);
+      COMBA_STORE2(b[23]);
+      COMBA_FINI;
+
+      B->used = 24;
+      B->sign = FP_ZPOS;
+      memcpy(B->dp, b, 24 * sizeof(fp_digit));
+      fp_clamp(B);
+      break;
+
+   case 13:
+      a = A->dp;
+      COMBA_START; 
+
+      /* clear carries */
+      CLEAR_CARRY;
+
+      /* output 0 */
+      SQRADD(a[0],a[0]);
+      COMBA_STORE(b[0]);
+
+      /* output 1 */
+      CARRY_FORWARD;
+      SQRADD2(a[0], a[1]); 
+      COMBA_STORE(b[1]);
+
+      /* output 2 */
+      CARRY_FORWARD;
+      SQRADD2(a[0], a[2]);    SQRADD(a[1], a[1]); 
+      COMBA_STORE(b[2]);
+
+      /* output 3 */
+      CARRY_FORWARD;
+      SQRADD2(a[0], a[3]);    SQRADD2(a[1], a[2]); 
+      COMBA_STORE(b[3]);
+
+      /* output 4 */
+      CARRY_FORWARD;
+      SQRADD2(a[0], a[4]);    SQRADD2(a[1], a[3]);    SQRADD(a[2], a[2]); 
+      COMBA_STORE(b[4]);
+
+      /* output 5 */
+      CARRY_FORWARD;
+   SQRADDSC(a[0], a[5]); SQRADDAC(a[1], a[4]); SQRADDAC(a[2], a[3]); SQRADDDB; 
+      COMBA_STORE(b[5]);
+
+      /* output 6 */
+      CARRY_FORWARD;
+   SQRADDSC(a[0], a[6]); SQRADDAC(a[1], a[5]); SQRADDAC(a[2], a[4]); SQRADDDB; SQRADD(a[3], a[3]); 
+      COMBA_STORE(b[6]);
+
+      /* output 7 */
+      CARRY_FORWARD;
+   SQRADDSC(a[0], a[7]); SQRADDAC(a[1], a[6]); SQRADDAC(a[2], a[5]); SQRADDAC(a[3], a[4]); SQRADDDB; 
+      COMBA_STORE(b[7]);
+
+      /* output 8 */
+      CARRY_FORWARD;
+   SQRADDSC(a[0], a[8]); SQRADDAC(a[1], a[7]); SQRADDAC(a[2], a[6]); SQRADDAC(a[3], a[5]); SQRADDDB; SQRADD(a[4], a[4]); 
+      COMBA_STORE(b[8]);
+
+      /* output 9 */
+      CARRY_FORWARD;
+   SQRADDSC(a[0], a[9]); SQRADDAC(a[1], a[8]); SQRADDAC(a[2], a[7]); SQRADDAC(a[3], a[6]); SQRADDAC(a[4], a[5]); SQRADDDB; 
+      COMBA_STORE(b[9]);
+
+      /* output 10 */
+      CARRY_FORWARD;
+   SQRADDSC(a[0], a[10]); SQRADDAC(a[1], a[9]); SQRADDAC(a[2], a[8]); SQRADDAC(a[3], a[7]); SQRADDAC(a[4], a[6]); SQRADDDB; SQRADD(a[5], a[5]); 
+      COMBA_STORE(b[10]);
+
+      /* output 11 */
+      CARRY_FORWARD;
+   SQRADDSC(a[0], a[11]); SQRADDAC(a[1], a[10]); SQRADDAC(a[2], a[9]); SQRADDAC(a[3], a[8]); SQRADDAC(a[4], a[7]); SQRADDAC(a[5], a[6]); SQRADDDB; 
+      COMBA_STORE(b[11]);
+
+      /* output 12 */
+      CARRY_FORWARD;
+   SQRADDSC(a[0], a[12]); SQRADDAC(a[1], a[11]); SQRADDAC(a[2], a[10]); SQRADDAC(a[3], a[9]); SQRADDAC(a[4], a[8]); SQRADDAC(a[5], a[7]); SQRADDDB; SQRADD(a[6], a[6]); 
+      COMBA_STORE(b[12]);
+
+      /* output 13 */
+      CARRY_FORWARD;
+   SQRADDSC(a[1], a[12]); SQRADDAC(a[2], a[11]); SQRADDAC(a[3], a[10]); SQRADDAC(a[4], a[9]); SQRADDAC(a[5], a[8]); SQRADDAC(a[6], a[7]); SQRADDDB; 
+      COMBA_STORE(b[13]);
+
+      /* output 14 */
+      CARRY_FORWARD;
+   SQRADDSC(a[2], a[12]); SQRADDAC(a[3], a[11]); SQRADDAC(a[4], a[10]); SQRADDAC(a[5], a[9]); SQRADDAC(a[6], a[8]); SQRADDDB; SQRADD(a[7], a[7]); 
+      COMBA_STORE(b[14]);
+
+      /* output 15 */
+      CARRY_FORWARD;
+   SQRADDSC(a[3], a[12]); SQRADDAC(a[4], a[11]); SQRADDAC(a[5], a[10]); SQRADDAC(a[6], a[9]); SQRADDAC(a[7], a[8]); SQRADDDB; 
+      COMBA_STORE(b[15]);
+
+      /* output 16 */
+      CARRY_FORWARD;
+   SQRADDSC(a[4], a[12]); SQRADDAC(a[5], a[11]); SQRADDAC(a[6], a[10]); SQRADDAC(a[7], a[9]); SQRADDDB; SQRADD(a[8], a[8]); 
+      COMBA_STORE(b[16]);
+
+      /* output 17 */
+      CARRY_FORWARD;
+   SQRADDSC(a[5], a[12]); SQRADDAC(a[6], a[11]); SQRADDAC(a[7], a[10]); SQRADDAC(a[8], a[9]); SQRADDDB; 
+      COMBA_STORE(b[17]);
+
+      /* output 18 */
+      CARRY_FORWARD;
+   SQRADDSC(a[6], a[12]); SQRADDAC(a[7], a[11]); SQRADDAC(a[8], a[10]); SQRADDDB; SQRADD(a[9], a[9]); 
+      COMBA_STORE(b[18]);
+
+      /* output 19 */
+      CARRY_FORWARD;
+   SQRADDSC(a[7], a[12]); SQRADDAC(a[8], a[11]); SQRADDAC(a[9], a[10]); SQRADDDB; 
+      COMBA_STORE(b[19]);
+
+      /* output 20 */
+      CARRY_FORWARD;
+      SQRADD2(a[8], a[12]);    SQRADD2(a[9], a[11]);    SQRADD(a[10], a[10]); 
+      COMBA_STORE(b[20]);
+
+      /* output 21 */
+      CARRY_FORWARD;
+      SQRADD2(a[9], a[12]);    SQRADD2(a[10], a[11]); 
+      COMBA_STORE(b[21]);
+
+      /* output 22 */
+      CARRY_FORWARD;
+      SQRADD2(a[10], a[12]);    SQRADD(a[11], a[11]); 
+      COMBA_STORE(b[22]);
+
+      /* output 23 */
+      CARRY_FORWARD;
+      SQRADD2(a[11], a[12]); 
+      COMBA_STORE(b[23]);
+
+      /* output 24 */
+      CARRY_FORWARD;
+      SQRADD(a[12], a[12]); 
+      COMBA_STORE(b[24]);
+      COMBA_STORE2(b[25]);
+      COMBA_FINI;
+
+      B->used = 26;
+      B->sign = FP_ZPOS;
+      memcpy(B->dp, b, 26 * sizeof(fp_digit));
+      fp_clamp(B);
+      break;
+
+   case 14:
+      a = A->dp;
+      COMBA_START; 
+
+      /* clear carries */
+      CLEAR_CARRY;
+
+      /* output 0 */
+      SQRADD(a[0],a[0]);
+      COMBA_STORE(b[0]);
+
+      /* output 1 */
+      CARRY_FORWARD;
+      SQRADD2(a[0], a[1]); 
+      COMBA_STORE(b[1]);
+
+      /* output 2 */
+      CARRY_FORWARD;
+      SQRADD2(a[0], a[2]);    SQRADD(a[1], a[1]); 
+      COMBA_STORE(b[2]);
+
+      /* output 3 */
+      CARRY_FORWARD;
+      SQRADD2(a[0], a[3]);    SQRADD2(a[1], a[2]); 
+      COMBA_STORE(b[3]);
+
+      /* output 4 */
+      CARRY_FORWARD;
+      SQRADD2(a[0], a[4]);    SQRADD2(a[1], a[3]);    SQRADD(a[2], a[2]); 
+      COMBA_STORE(b[4]);
+
+      /* output 5 */
+      CARRY_FORWARD;
+   SQRADDSC(a[0], a[5]); SQRADDAC(a[1], a[4]); SQRADDAC(a[2], a[3]); SQRADDDB; 
+      COMBA_STORE(b[5]);
+
+      /* output 6 */
+      CARRY_FORWARD;
+   SQRADDSC(a[0], a[6]); SQRADDAC(a[1], a[5]); SQRADDAC(a[2], a[4]); SQRADDDB; SQRADD(a[3], a[3]); 
+      COMBA_STORE(b[6]);
+
+      /* output 7 */
+      CARRY_FORWARD;
+   SQRADDSC(a[0], a[7]); SQRADDAC(a[1], a[6]); SQRADDAC(a[2], a[5]); SQRADDAC(a[3], a[4]); SQRADDDB; 
+      COMBA_STORE(b[7]);
+
+      /* output 8 */
+      CARRY_FORWARD;
+   SQRADDSC(a[0], a[8]); SQRADDAC(a[1], a[7]); SQRADDAC(a[2], a[6]); SQRADDAC(a[3], a[5]); SQRADDDB; SQRADD(a[4], a[4]); 
+      COMBA_STORE(b[8]);
+
+      /* output 9 */
+      CARRY_FORWARD;
+   SQRADDSC(a[0], a[9]); SQRADDAC(a[1], a[8]); SQRADDAC(a[2], a[7]); SQRADDAC(a[3], a[6]); SQRADDAC(a[4], a[5]); SQRADDDB; 
+      COMBA_STORE(b[9]);
+
+      /* output 10 */
+      CARRY_FORWARD;
+   SQRADDSC(a[0], a[10]); SQRADDAC(a[1], a[9]); SQRADDAC(a[2], a[8]); SQRADDAC(a[3], a[7]); SQRADDAC(a[4], a[6]); SQRADDDB; SQRADD(a[5], a[5]); 
+      COMBA_STORE(b[10]);
+
+      /* output 11 */
+      CARRY_FORWARD;
+   SQRADDSC(a[0], a[11]); SQRADDAC(a[1], a[10]); SQRADDAC(a[2], a[9]); SQRADDAC(a[3], a[8]); SQRADDAC(a[4], a[7]); SQRADDAC(a[5], a[6]); SQRADDDB; 
+      COMBA_STORE(b[11]);
+
+      /* output 12 */
+      CARRY_FORWARD;
+   SQRADDSC(a[0], a[12]); SQRADDAC(a[1], a[11]); SQRADDAC(a[2], a[10]); SQRADDAC(a[3], a[9]); SQRADDAC(a[4], a[8]); SQRADDAC(a[5], a[7]); SQRADDDB; SQRADD(a[6], a[6]); 
+      COMBA_STORE(b[12]);
+
+      /* output 13 */
+      CARRY_FORWARD;
+   SQRADDSC(a[0], a[13]); SQRADDAC(a[1], a[12]); SQRADDAC(a[2], a[11]); SQRADDAC(a[3], a[10]); SQRADDAC(a[4], a[9]); SQRADDAC(a[5], a[8]); SQRADDAC(a[6], a[7]); SQRADDDB; 
+      COMBA_STORE(b[13]);
+
+      /* output 14 */
+      CARRY_FORWARD;
+   SQRADDSC(a[1], a[13]); SQRADDAC(a[2], a[12]); SQRADDAC(a[3], a[11]); SQRADDAC(a[4], a[10]); SQRADDAC(a[5], a[9]); SQRADDAC(a[6], a[8]); SQRADDDB; SQRADD(a[7], a[7]); 
+      COMBA_STORE(b[14]);
+
+      /* output 15 */
+      CARRY_FORWARD;
+   SQRADDSC(a[2], a[13]); SQRADDAC(a[3], a[12]); SQRADDAC(a[4], a[11]); SQRADDAC(a[5], a[10]); SQRADDAC(a[6], a[9]); SQRADDAC(a[7], a[8]); SQRADDDB; 
+      COMBA_STORE(b[15]);
+
+      /* output 16 */
+      CARRY_FORWARD;
+   SQRADDSC(a[3], a[13]); SQRADDAC(a[4], a[12]); SQRADDAC(a[5], a[11]); SQRADDAC(a[6], a[10]); SQRADDAC(a[7], a[9]); SQRADDDB; SQRADD(a[8], a[8]); 
+      COMBA_STORE(b[16]);
+
+      /* output 17 */
+      CARRY_FORWARD;
+   SQRADDSC(a[4], a[13]); SQRADDAC(a[5], a[12]); SQRADDAC(a[6], a[11]); SQRADDAC(a[7], a[10]); SQRADDAC(a[8], a[9]); SQRADDDB; 
+      COMBA_STORE(b[17]);
+
+      /* output 18 */
+      CARRY_FORWARD;
+   SQRADDSC(a[5], a[13]); SQRADDAC(a[6], a[12]); SQRADDAC(a[7], a[11]); SQRADDAC(a[8], a[10]); SQRADDDB; SQRADD(a[9], a[9]); 
+      COMBA_STORE(b[18]);
+
+      /* output 19 */
+      CARRY_FORWARD;
+   SQRADDSC(a[6], a[13]); SQRADDAC(a[7], a[12]); SQRADDAC(a[8], a[11]); SQRADDAC(a[9], a[10]); SQRADDDB; 
+      COMBA_STORE(b[19]);
+
+      /* output 20 */
+      CARRY_FORWARD;
+   SQRADDSC(a[7], a[13]); SQRADDAC(a[8], a[12]); SQRADDAC(a[9], a[11]); SQRADDDB; SQRADD(a[10], a[10]); 
+      COMBA_STORE(b[20]);
+
+      /* output 21 */
+      CARRY_FORWARD;
+   SQRADDSC(a[8], a[13]); SQRADDAC(a[9], a[12]); SQRADDAC(a[10], a[11]); SQRADDDB; 
+      COMBA_STORE(b[21]);
+
+      /* output 22 */
+      CARRY_FORWARD;
+      SQRADD2(a[9], a[13]);    SQRADD2(a[10], a[12]);    SQRADD(a[11], a[11]); 
+      COMBA_STORE(b[22]);
+
+      /* output 23 */
+      CARRY_FORWARD;
+      SQRADD2(a[10], a[13]);    SQRADD2(a[11], a[12]); 
+      COMBA_STORE(b[23]);
+
+      /* output 24 */
+      CARRY_FORWARD;
+      SQRADD2(a[11], a[13]);    SQRADD(a[12], a[12]); 
+      COMBA_STORE(b[24]);
+
+      /* output 25 */
+      CARRY_FORWARD;
+      SQRADD2(a[12], a[13]); 
+      COMBA_STORE(b[25]);
+
+      /* output 26 */
+      CARRY_FORWARD;
+      SQRADD(a[13], a[13]); 
+      COMBA_STORE(b[26]);
+      COMBA_STORE2(b[27]);
+      COMBA_FINI;
+
+      B->used = 28;
+      B->sign = FP_ZPOS;
+      memcpy(B->dp, b, 28 * sizeof(fp_digit));
+      fp_clamp(B);
+      break;
+
+   case 15:
+      a = A->dp;
+      COMBA_START; 
+
+      /* clear carries */
+      CLEAR_CARRY;
+
+      /* output 0 */
+      SQRADD(a[0],a[0]);
+      COMBA_STORE(b[0]);
+
+      /* output 1 */
+      CARRY_FORWARD;
+      SQRADD2(a[0], a[1]); 
+      COMBA_STORE(b[1]);
+
+      /* output 2 */
+      CARRY_FORWARD;
+      SQRADD2(a[0], a[2]);    SQRADD(a[1], a[1]); 
+      COMBA_STORE(b[2]);
+
+      /* output 3 */
+      CARRY_FORWARD;
+      SQRADD2(a[0], a[3]);    SQRADD2(a[1], a[2]); 
+      COMBA_STORE(b[3]);
+
+      /* output 4 */
+      CARRY_FORWARD;
+      SQRADD2(a[0], a[4]);    SQRADD2(a[1], a[3]);    SQRADD(a[2], a[2]); 
+      COMBA_STORE(b[4]);
+
+      /* output 5 */
+      CARRY_FORWARD;
+   SQRADDSC(a[0], a[5]); SQRADDAC(a[1], a[4]); SQRADDAC(a[2], a[3]); SQRADDDB; 
+      COMBA_STORE(b[5]);
+
+      /* output 6 */
+      CARRY_FORWARD;
+   SQRADDSC(a[0], a[6]); SQRADDAC(a[1], a[5]); SQRADDAC(a[2], a[4]); SQRADDDB; SQRADD(a[3], a[3]); 
+      COMBA_STORE(b[6]);
+
+      /* output 7 */
+      CARRY_FORWARD;
+   SQRADDSC(a[0], a[7]); SQRADDAC(a[1], a[6]); SQRADDAC(a[2], a[5]); SQRADDAC(a[3], a[4]); SQRADDDB; 
+      COMBA_STORE(b[7]);
+
+      /* output 8 */
+      CARRY_FORWARD;
+   SQRADDSC(a[0], a[8]); SQRADDAC(a[1], a[7]); SQRADDAC(a[2], a[6]); SQRADDAC(a[3], a[5]); SQRADDDB; SQRADD(a[4], a[4]); 
+      COMBA_STORE(b[8]);
+
+      /* output 9 */
+      CARRY_FORWARD;
+   SQRADDSC(a[0], a[9]); SQRADDAC(a[1], a[8]); SQRADDAC(a[2], a[7]); SQRADDAC(a[3], a[6]); SQRADDAC(a[4], a[5]); SQRADDDB; 
+      COMBA_STORE(b[9]);
+
+      /* output 10 */
+      CARRY_FORWARD;
+   SQRADDSC(a[0], a[10]); SQRADDAC(a[1], a[9]); SQRADDAC(a[2], a[8]); SQRADDAC(a[3], a[7]); SQRADDAC(a[4], a[6]); SQRADDDB; SQRADD(a[5], a[5]); 
+      COMBA_STORE(b[10]);
+
+      /* output 11 */
+      CARRY_FORWARD;
+   SQRADDSC(a[0], a[11]); SQRADDAC(a[1], a[10]); SQRADDAC(a[2], a[9]); SQRADDAC(a[3], a[8]); SQRADDAC(a[4], a[7]); SQRADDAC(a[5], a[6]); SQRADDDB; 
+      COMBA_STORE(b[11]);
+
+      /* output 12 */
+      CARRY_FORWARD;
+   SQRADDSC(a[0], a[12]); SQRADDAC(a[1], a[11]); SQRADDAC(a[2], a[10]); SQRADDAC(a[3], a[9]); SQRADDAC(a[4], a[8]); SQRADDAC(a[5], a[7]); SQRADDDB; SQRADD(a[6], a[6]); 
+      COMBA_STORE(b[12]);
+
+      /* output 13 */
+      CARRY_FORWARD;
+   SQRADDSC(a[0], a[13]); SQRADDAC(a[1], a[12]); SQRADDAC(a[2], a[11]); SQRADDAC(a[3], a[10]); SQRADDAC(a[4], a[9]); SQRADDAC(a[5], a[8]); SQRADDAC(a[6], a[7]); SQRADDDB; 
+      COMBA_STORE(b[13]);
+
+      /* output 14 */
+      CARRY_FORWARD;
+   SQRADDSC(a[0], a[14]); SQRADDAC(a[1], a[13]); SQRADDAC(a[2], a[12]); SQRADDAC(a[3], a[11]); SQRADDAC(a[4], a[10]); SQRADDAC(a[5], a[9]); SQRADDAC(a[6], a[8]); SQRADDDB; SQRADD(a[7], a[7]); 
+      COMBA_STORE(b[14]);
+
+      /* output 15 */
+      CARRY_FORWARD;
+   SQRADDSC(a[1], a[14]); SQRADDAC(a[2], a[13]); SQRADDAC(a[3], a[12]); SQRADDAC(a[4], a[11]); SQRADDAC(a[5], a[10]); SQRADDAC(a[6], a[9]); SQRADDAC(a[7], a[8]); SQRADDDB; 
+      COMBA_STORE(b[15]);
+
+      /* output 16 */
+      CARRY_FORWARD;
+   SQRADDSC(a[2], a[14]); SQRADDAC(a[3], a[13]); SQRADDAC(a[4], a[12]); SQRADDAC(a[5], a[11]); SQRADDAC(a[6], a[10]); SQRADDAC(a[7], a[9]); SQRADDDB; SQRADD(a[8], a[8]); 
+      COMBA_STORE(b[16]);
+
+      /* output 17 */
+      CARRY_FORWARD;
+   SQRADDSC(a[3], a[14]); SQRADDAC(a[4], a[13]); SQRADDAC(a[5], a[12]); SQRADDAC(a[6], a[11]); SQRADDAC(a[7], a[10]); SQRADDAC(a[8], a[9]); SQRADDDB; 
+      COMBA_STORE(b[17]);
+
+      /* output 18 */
+      CARRY_FORWARD;
+   SQRADDSC(a[4], a[14]); SQRADDAC(a[5], a[13]); SQRADDAC(a[6], a[12]); SQRADDAC(a[7], a[11]); SQRADDAC(a[8], a[10]); SQRADDDB; SQRADD(a[9], a[9]); 
+      COMBA_STORE(b[18]);
+
+      /* output 19 */
+      CARRY_FORWARD;
+   SQRADDSC(a[5], a[14]); SQRADDAC(a[6], a[13]); SQRADDAC(a[7], a[12]); SQRADDAC(a[8], a[11]); SQRADDAC(a[9], a[10]); SQRADDDB; 
+      COMBA_STORE(b[19]);
+
+      /* output 20 */
+      CARRY_FORWARD;
+   SQRADDSC(a[6], a[14]); SQRADDAC(a[7], a[13]); SQRADDAC(a[8], a[12]); SQRADDAC(a[9], a[11]); SQRADDDB; SQRADD(a[10], a[10]); 
+      COMBA_STORE(b[20]);
+
+      /* output 21 */
+      CARRY_FORWARD;
+   SQRADDSC(a[7], a[14]); SQRADDAC(a[8], a[13]); SQRADDAC(a[9], a[12]); SQRADDAC(a[10], a[11]); SQRADDDB; 
+      COMBA_STORE(b[21]);
+
+      /* output 22 */
+      CARRY_FORWARD;
+   SQRADDSC(a[8], a[14]); SQRADDAC(a[9], a[13]); SQRADDAC(a[10], a[12]); SQRADDDB; SQRADD(a[11], a[11]); 
+      COMBA_STORE(b[22]);
+
+      /* output 23 */
+      CARRY_FORWARD;
+   SQRADDSC(a[9], a[14]); SQRADDAC(a[10], a[13]); SQRADDAC(a[11], a[12]); SQRADDDB; 
+      COMBA_STORE(b[23]);
+
+      /* output 24 */
+      CARRY_FORWARD;
+      SQRADD2(a[10], a[14]);    SQRADD2(a[11], a[13]);    SQRADD(a[12], a[12]); 
+      COMBA_STORE(b[24]);
+
+      /* output 25 */
+      CARRY_FORWARD;
+      SQRADD2(a[11], a[14]);    SQRADD2(a[12], a[13]); 
+      COMBA_STORE(b[25]);
+
+      /* output 26 */
+      CARRY_FORWARD;
+      SQRADD2(a[12], a[14]);    SQRADD(a[13], a[13]); 
+      COMBA_STORE(b[26]);
+
+      /* output 27 */
+      CARRY_FORWARD;
+      SQRADD2(a[13], a[14]); 
+      COMBA_STORE(b[27]);
+
+      /* output 28 */
+      CARRY_FORWARD;
+      SQRADD(a[14], a[14]); 
+      COMBA_STORE(b[28]);
+      COMBA_STORE2(b[29]);
+      COMBA_FINI;
+
+      B->used = 30;
+      B->sign = FP_ZPOS;
+      memcpy(B->dp, b, 30 * sizeof(fp_digit));
+      fp_clamp(B);
+      break;
+
+   case 16:
+      a = A->dp;
+      COMBA_START; 
+
+      /* clear carries */
+      CLEAR_CARRY;
+
+      /* output 0 */
+      SQRADD(a[0],a[0]);
+      COMBA_STORE(b[0]);
+
+      /* output 1 */
+      CARRY_FORWARD;
+      SQRADD2(a[0], a[1]); 
+      COMBA_STORE(b[1]);
+
+      /* output 2 */
+      CARRY_FORWARD;
+      SQRADD2(a[0], a[2]);    SQRADD(a[1], a[1]); 
+      COMBA_STORE(b[2]);
+
+      /* output 3 */
+      CARRY_FORWARD;
+      SQRADD2(a[0], a[3]);    SQRADD2(a[1], a[2]); 
+      COMBA_STORE(b[3]);
+
+      /* output 4 */
+      CARRY_FORWARD;
+      SQRADD2(a[0], a[4]);    SQRADD2(a[1], a[3]);    SQRADD(a[2], a[2]); 
+      COMBA_STORE(b[4]);
+
+      /* output 5 */
+      CARRY_FORWARD;
+   SQRADDSC(a[0], a[5]); SQRADDAC(a[1], a[4]); SQRADDAC(a[2], a[3]); SQRADDDB; 
+      COMBA_STORE(b[5]);
+
+      /* output 6 */
+      CARRY_FORWARD;
+   SQRADDSC(a[0], a[6]); SQRADDAC(a[1], a[5]); SQRADDAC(a[2], a[4]); SQRADDDB; SQRADD(a[3], a[3]); 
+      COMBA_STORE(b[6]);
+
+      /* output 7 */
+      CARRY_FORWARD;
+   SQRADDSC(a[0], a[7]); SQRADDAC(a[1], a[6]); SQRADDAC(a[2], a[5]); SQRADDAC(a[3], a[4]); SQRADDDB; 
+      COMBA_STORE(b[7]);
+
+      /* output 8 */
+      CARRY_FORWARD;
+   SQRADDSC(a[0], a[8]); SQRADDAC(a[1], a[7]); SQRADDAC(a[2], a[6]); SQRADDAC(a[3], a[5]); SQRADDDB; SQRADD(a[4], a[4]); 
+      COMBA_STORE(b[8]);
+
+      /* output 9 */
+      CARRY_FORWARD;
+   SQRADDSC(a[0], a[9]); SQRADDAC(a[1], a[8]); SQRADDAC(a[2], a[7]); SQRADDAC(a[3], a[6]); SQRADDAC(a[4], a[5]); SQRADDDB; 
+      COMBA_STORE(b[9]);
+
+      /* output 10 */
+      CARRY_FORWARD;
+   SQRADDSC(a[0], a[10]); SQRADDAC(a[1], a[9]); SQRADDAC(a[2], a[8]); SQRADDAC(a[3], a[7]); SQRADDAC(a[4], a[6]); SQRADDDB; SQRADD(a[5], a[5]); 
+      COMBA_STORE(b[10]);
+
+      /* output 11 */
+      CARRY_FORWARD;
+   SQRADDSC(a[0], a[11]); SQRADDAC(a[1], a[10]); SQRADDAC(a[2], a[9]); SQRADDAC(a[3], a[8]); SQRADDAC(a[4], a[7]); SQRADDAC(a[5], a[6]); SQRADDDB; 
+      COMBA_STORE(b[11]);
+
+      /* output 12 */
+      CARRY_FORWARD;
+   SQRADDSC(a[0], a[12]); SQRADDAC(a[1], a[11]); SQRADDAC(a[2], a[10]); SQRADDAC(a[3], a[9]); SQRADDAC(a[4], a[8]); SQRADDAC(a[5], a[7]); SQRADDDB; SQRADD(a[6], a[6]); 
+      COMBA_STORE(b[12]);
+
+      /* output 13 */
+      CARRY_FORWARD;
+   SQRADDSC(a[0], a[13]); SQRADDAC(a[1], a[12]); SQRADDAC(a[2], a[11]); SQRADDAC(a[3], a[10]); SQRADDAC(a[4], a[9]); SQRADDAC(a[5], a[8]); SQRADDAC(a[6], a[7]); SQRADDDB; 
+      COMBA_STORE(b[13]);
+
+      /* output 14 */
+      CARRY_FORWARD;
+   SQRADDSC(a[0], a[14]); SQRADDAC(a[1], a[13]); SQRADDAC(a[2], a[12]); SQRADDAC(a[3], a[11]); SQRADDAC(a[4], a[10]); SQRADDAC(a[5], a[9]); SQRADDAC(a[6], a[8]); SQRADDDB; SQRADD(a[7], a[7]); 
+      COMBA_STORE(b[14]);
+
+      /* output 15 */
+      CARRY_FORWARD;
+   SQRADDSC(a[0], a[15]); SQRADDAC(a[1], a[14]); SQRADDAC(a[2], a[13]); SQRADDAC(a[3], a[12]); SQRADDAC(a[4], a[11]); SQRADDAC(a[5], a[10]); SQRADDAC(a[6], a[9]); SQRADDAC(a[7], a[8]); SQRADDDB; 
+      COMBA_STORE(b[15]);
+
+      /* output 16 */
+      CARRY_FORWARD;
+   SQRADDSC(a[1], a[15]); SQRADDAC(a[2], a[14]); SQRADDAC(a[3], a[13]); SQRADDAC(a[4], a[12]); SQRADDAC(a[5], a[11]); SQRADDAC(a[6], a[10]); SQRADDAC(a[7], a[9]); SQRADDDB; SQRADD(a[8], a[8]); 
+      COMBA_STORE(b[16]);
+
+      /* output 17 */
+      CARRY_FORWARD;
+   SQRADDSC(a[2], a[15]); SQRADDAC(a[3], a[14]); SQRADDAC(a[4], a[13]); SQRADDAC(a[5], a[12]); SQRADDAC(a[6], a[11]); SQRADDAC(a[7], a[10]); SQRADDAC(a[8], a[9]); SQRADDDB; 
+      COMBA_STORE(b[17]);
+
+      /* output 18 */
+      CARRY_FORWARD;
+   SQRADDSC(a[3], a[15]); SQRADDAC(a[4], a[14]); SQRADDAC(a[5], a[13]); SQRADDAC(a[6], a[12]); SQRADDAC(a[7], a[11]); SQRADDAC(a[8], a[10]); SQRADDDB; SQRADD(a[9], a[9]); 
+      COMBA_STORE(b[18]);
+
+      /* output 19 */
+      CARRY_FORWARD;
+   SQRADDSC(a[4], a[15]); SQRADDAC(a[5], a[14]); SQRADDAC(a[6], a[13]); SQRADDAC(a[7], a[12]); SQRADDAC(a[8], a[11]); SQRADDAC(a[9], a[10]); SQRADDDB; 
+      COMBA_STORE(b[19]);
+
+      /* output 20 */
+      CARRY_FORWARD;
+   SQRADDSC(a[5], a[15]); SQRADDAC(a[6], a[14]); SQRADDAC(a[7], a[13]); SQRADDAC(a[8], a[12]); SQRADDAC(a[9], a[11]); SQRADDDB; SQRADD(a[10], a[10]); 
+      COMBA_STORE(b[20]);
+
+      /* output 21 */
+      CARRY_FORWARD;
+   SQRADDSC(a[6], a[15]); SQRADDAC(a[7], a[14]); SQRADDAC(a[8], a[13]); SQRADDAC(a[9], a[12]); SQRADDAC(a[10], a[11]); SQRADDDB; 
+      COMBA_STORE(b[21]);
+
+      /* output 22 */
+      CARRY_FORWARD;
+   SQRADDSC(a[7], a[15]); SQRADDAC(a[8], a[14]); SQRADDAC(a[9], a[13]); SQRADDAC(a[10], a[12]); SQRADDDB; SQRADD(a[11], a[11]); 
+      COMBA_STORE(b[22]);
+
+      /* output 23 */
+      CARRY_FORWARD;
+   SQRADDSC(a[8], a[15]); SQRADDAC(a[9], a[14]); SQRADDAC(a[10], a[13]); SQRADDAC(a[11], a[12]); SQRADDDB; 
+      COMBA_STORE(b[23]);
+
+      /* output 24 */
+      CARRY_FORWARD;
+   SQRADDSC(a[9], a[15]); SQRADDAC(a[10], a[14]); SQRADDAC(a[11], a[13]); SQRADDDB; SQRADD(a[12], a[12]); 
+      COMBA_STORE(b[24]);
+
+      /* output 25 */
+      CARRY_FORWARD;
+   SQRADDSC(a[10], a[15]); SQRADDAC(a[11], a[14]); SQRADDAC(a[12], a[13]); SQRADDDB; 
+      COMBA_STORE(b[25]);
+
+      /* output 26 */
+      CARRY_FORWARD;
+      SQRADD2(a[11], a[15]);    SQRADD2(a[12], a[14]);    SQRADD(a[13], a[13]); 
+      COMBA_STORE(b[26]);
+
+      /* output 27 */
+      CARRY_FORWARD;
+      SQRADD2(a[12], a[15]);    SQRADD2(a[13], a[14]); 
+      COMBA_STORE(b[27]);
+
+      /* output 28 */
+      CARRY_FORWARD;
+      SQRADD2(a[13], a[15]);    SQRADD(a[14], a[14]); 
+      COMBA_STORE(b[28]);
+
+      /* output 29 */
+      CARRY_FORWARD;
+      SQRADD2(a[14], a[15]); 
+      COMBA_STORE(b[29]);
+
+      /* output 30 */
+      CARRY_FORWARD;
+      SQRADD(a[15], a[15]); 
+      COMBA_STORE(b[30]);
+      COMBA_STORE2(b[31]);
+      COMBA_FINI;
+
+      B->used = 32;
+      B->sign = FP_ZPOS;
+      memcpy(B->dp, b, 32 * sizeof(fp_digit));
+      fp_clamp(B);
+      break;
+
+}
+}
+
+#endif /* TFM_SMALL_SET */
+
+/* $Source$ */
+/* $Revision$ */
+/* $Date$ */
diff --git a/tomsfastmath/src/sqr/fp_sqrmod.c b/tomsfastmath/src/sqr/fp_sqrmod.c
new file mode 100644 (file)
index 0000000..2bd6fb1
--- /dev/null
@@ -0,0 +1,23 @@
+/* TomsFastMath, a fast ISO C bignum library.
+ * 
+ * This project is meant to fill in where LibTomMath
+ * falls short.  That is speed ;-)
+ *
+ * This project is public domain and free for all purposes.
+ * 
+ * Tom St Denis, tomstdenis@gmail.com
+ */
+#include <tfm_private.h>
+
+/* c = a * a (mod b) */
+int fp_sqrmod(fp_int *a, fp_int *b, fp_int *c)
+{
+  fp_int tmp;
+  fp_zero(&tmp);
+  fp_sqr(a, &tmp);
+  return fp_mod(&tmp, b, c);
+}
+
+/* $Source$ */
+/* $Revision$ */
+/* $Date$ */
diff --git a/zpm-fetchurl.c b/zpm-fetchurl.c
new file mode 100644 (file)
index 0000000..15fc36a
--- /dev/null
@@ -0,0 +1,513 @@
+#define _POSIX_C_SOURCE 200809L
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <string.h>
+#include <strings.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <signal.h>
+#include <time.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include "tlse.h"
+
+struct tls_uri {
+       char *scheme;
+       char *userinfo;
+       char *host;
+       char *port;
+       char *path;
+       char *query;
+       char *fragment;
+};
+int tls_parse_uri(char *, struct tls_uri *);
+void tls_free_uri(struct tls_uri *);
+
+int open_tcp_connection(char *host, int port);
+
+int verify(struct TLSContext *context, struct TLSCertificate **chain, int len) {
+       int i, err;
+
+       if (chain) {
+               for (i = 0; i < len; i++) {
+                       struct TLSCertificate *certificate = chain[i];
+                       // check validity date
+                       err = tls_certificate_is_valid(certificate);
+                       if (err)
+                               return err;
+                       // check certificate in certificate->bytes of length certificate->len
+                       // the certificate is in ASN.1 DER format
+               }
+       }
+       // check if chain is valid
+       err = tls_certificate_chain_is_valid(chain, len);
+       if (err) {
+               return err;
+       }
+
+       if (len > 0 && context->sni) {
+               err = tls_certificate_valid_subject(chain[0], context->sni);
+               if (err) {
+                       return err;
+               }
+       }
+
+       /* Perform certificate validation against ROOT CA */
+       err = tls_certificate_chain_is_valid_root(context, chain, len);
+       if (err) {
+               return err;
+       }
+
+       return no_error;
+}
+
+struct io {
+       struct tls_buffer response;
+       struct TLSContext *tls;
+       int socket;
+       int status_code;
+       time_t last_modified;
+       time_t date;
+       size_t content_length;
+       char *redirect;
+};
+
+int month(char *m) {
+       char *months[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul",
+               "Aug", "Sep", "Oct", "Nov", "Dec" };
+       int i;
+
+       for (i=0; i < 12; i++) {
+               if (!strncasecmp(m, months[i], 3)) {
+                       return i+1;
+               }
+       }
+       return 0;
+}
+
+/* Wed, 06 Feb 2019 10:06:05 GMT */
+time_t parse_date(char *d) {
+       //static const char format[] = "%a, %d %b %Y %H:%M:%S %Z"; // rfc 1123
+       struct tm tm = { 0 };
+       int rv;
+
+       //char *data = "Tue, 13 Dec 2011 16:08:21 GMT";
+       int h, m, s, dom, Y;
+       char M[4];
+       rv = sscanf(d, "%*[a-zA-Z,] %d %s %d %d:%d:%d", &dom, M, &Y, &h, &m, &s);
+       if (rv == 6) {
+               tm.tm_year = Y - 1900;
+               tm.tm_hour = h;
+               tm.tm_min = m;
+               tm.tm_sec = s;
+               tm.tm_mon = month(M)-1;
+               tm.tm_mday = dom;
+
+               return mktime(&tm);
+       }
+       return -1;
+}
+
+char *find_header(struct io *io, char *header, size_t *len) {
+       char *eoh, *soh;
+       size_t hlen;
+
+       *len = 0;
+
+       hlen = strlen(header);
+       eoh = strstr(io->response.buffer, "\r\n\r\n");
+       if (!eoh) {
+               return 0;
+       }
+       soh = io->response.buffer;
+       do {
+               soh = strstr(soh, "\r\n");
+               if (soh == eoh) {
+                       break;
+               }
+               soh += 2;
+               if (!memcmp(soh, header, hlen)) {
+                       break;
+               }
+       } while (soh < eoh);
+
+       if (soh >= eoh) {
+               return 0;
+       }
+       eoh = strstr(soh, "\r\n");
+       soh += hlen;
+       while (soh < eoh && isspace(*soh)) {
+               soh++;
+       }
+       *len = (eoh - soh);
+       return soh;
+}
+
+void parse_header(struct io *io) {
+       char *s = io->response.buffer;
+       int code = 0;
+       char *hval;
+       size_t hlen;
+
+       while (!isspace(*s)) {
+               s++;
+       }
+       while (isspace(*s)) {
+               s++;
+       }
+       code = strtol(s, 0, 10);
+       io->status_code = code;
+
+       hval = find_header(io, "Date:", &hlen);
+       if (hval) {
+               hval[hlen] = 0;
+               io->date = parse_date(hval);
+               hval[hlen] = '\r';
+       }
+       hval = find_header(io, "Last-Modified:", &hlen);
+       if (hval) {
+               hval[hlen] = 0;
+               io->last_modified = parse_date(hval);
+               hval[hlen] = '\r';
+       }
+
+       hval = find_header(io, "Content-Length:", &hlen);
+       if (hval) {
+               hval[hlen] = 0;
+               io->content_length = strtoul(hval, 0, 10);
+               hval[hlen] = '\r';
+       }
+
+       switch (code) {
+               case 301:
+               case 302:
+               case 303:
+               case 307:
+                       hval = find_header(io, "Location:", &hlen);
+                       if (hval) {
+                               io->redirect = strndup(hval, hlen);
+                       }
+                       break;
+               default:
+                       break;
+       }
+
+}
+
+ssize_t fill_buffer(struct io *io) {
+       unsigned char buffer[4096];
+       ssize_t ret;
+
+       if (io->tls) {
+               ret = tls_read(io->tls, buffer, sizeof buffer);
+       } else {
+               ret = read(io->socket, buffer, sizeof buffer);
+       }
+
+       if (ret > 0) {
+               tls_buffer_append(&io->response, buffer, ret);
+       }
+
+       return ret;
+}
+
+#if 0
+char *nextline(struct io *io) {
+       char *eol = 0;;
+
+       eol = memchr(io->response.buffer, '\n', io.response.size);
+       while (eol == 0) {
+               fill_buffer(io);
+               eol = memchr(io->response.buffer, '\n', io.response.size);
+       }
+       if (eol) {
+
+}
+#endif
+
+void append_header(struct tls_buffer *buf, char *header, char *val) {
+       tls_buffer_append(buf, header, strlen(header));
+       tls_buffer_append(buf, ": ", 2);
+       tls_buffer_append(buf, val, strlen(val));
+       tls_buffer_append(buf, "\r\n", 2);
+}
+
+static void pdots(int len, int ch, unsigned long was, unsigned long now,
+               unsigned long total) {
+       was = len * was / total;
+       if (now > total) {
+               now = total;
+       }
+       now = len * now / total;
+       while (was++ < now) {
+               putc(ch,stderr);
+       }
+}
+
+int main(int ac, char *av[]) {
+       int sockfd, port = -1, rv;
+       ssize_t ret;
+       int option;
+#if 0
+       char msg[] = "GET %s HTTP/1.1\r\nHost: %s:%i\r\nConnection: close\r\n\r\n";
+       char msg2[] = "GET %s HTTP/1.1\r\nHost: %s:%i\r\nLast-Modified: %s\r\nConnection: close\r\n\r\n";
+       char msg_buffer[1024];
+#endif
+       char *req_file = 0;
+       char *host = 0;
+       struct tls_uri uri;
+       char *outfile = 0;
+       int raw = 0, head = 0;
+       int out = 1;
+       int use_tls = 0;
+       struct io io = { {0}, 0, -1, 0, 0, 0, 0, 0 };
+       struct TLSContext *clientssl = 0;
+       int failsilent = 0;
+       char *lmfile = 0;
+       int progressbar = 0;
+       struct tls_buffer request;
+       char lmtime[80];
+       char *eoh = 0;
+       size_t total = 0;
+       size_t header_len;
+       char *url = 0;
+       int redirs = 0, redirlimit = 50, printstatus = 0;
+
+       ltc_mp = tfm_desc;
+
+       while ((option = getopt(ac, av, "o:rIfz:#R:S")) != -1) {
+               switch (option) {
+                       case 'o': outfile = optarg; break;
+                       case 'S': printstatus = 1; head = 1; break;
+                       case 'I': head = 1;
+                       case 'r': raw = 1; break;
+                       case 'f': failsilent = 1; break;
+                       case 'z': lmfile = optarg; break;
+                       case 'R': redirlimit = strtol(optarg, 0, 10); break;
+                       case '#': progressbar = 1; break;
+                       default:
+                                 exit(EXIT_FAILURE);
+                                 break;
+               }
+       }
+
+       if (ac < optind) {
+               fprintf(stderr, "Usage: %s uri\n", av[0]);
+               exit(EXIT_FAILURE);
+       }
+
+       if (lmfile) {
+               struct stat st;
+               int rv;
+               struct tm *mtime;
+               time_t ts;
+
+               rv = stat(lmfile, &st);
+               if (rv == -1) {
+                       perror("stat failed:");
+                       exit(EXIT_FAILURE);
+               }
+               ts = st.st_mtime;
+               mtime = gmtime(&ts);
+               strftime(lmtime, sizeof lmtime, "%a, %d %b %Y %H:%M:%S GMT", mtime);
+       }
+
+       url = strdup(av[optind]);
+       if (!url) {
+               exit(EXIT_FAILURE);
+       }
+
+       if (outfile) {
+               out = open(outfile, O_WRONLY|O_CREAT, 0600);
+               if (out == -1) {
+                       perror("can't open output file:");
+                       exit(EXIT_FAILURE);
+               }
+       }
+
+       signal(SIGPIPE, SIG_IGN);
+
+       tls_buffer_init(&io.response, 0);
+       tls_buffer_init(&request, 128);
+
+       while (redirs++ <= redirlimit) {
+               tls_free_uri(&uri);
+               io.response.len = 0;
+               request.len = 0;
+
+               tls_parse_uri(url, &uri);
+               host = uri.host;
+               port = atoi(uri.port);
+               req_file = uri.path;
+
+               /* construct request */
+               if (head) {
+                       tls_buffer_append(&request, "HEAD ", 5);
+               } else {
+                       tls_buffer_append(&request, "GET ", 4);
+               }
+               tls_buffer_append(&request, uri.path, strlen(uri.path));
+               tls_buffer_append(&request, " HTTP/1.1", 9);
+               tls_buffer_append(&request, "\r\n", 2);
+
+               append_header(&request, "Host", host);
+               append_header(&request, "Connection", "close");
+               if (lmfile) {
+                       append_header(&request, "If-Modified-Since", lmtime);
+               }
+               tls_buffer_append(&request, "\r\n", 2);
+               //fprintf(stderr, "msg =\n%.*s", (int)request.len, request.buffer);
+
+               if (!strcmp(uri.scheme, "https")) {
+                       use_tls = 1;
+
+                       clientssl = tls_create_context(TLS_CLIENT, TLS_V12);
+
+                       rv = tls_load_root_file(clientssl, "root.pem");
+                       if (rv == -1) {
+                               fprintf(stderr, "Error loading root certs\n");
+                               return 1;
+                       }
+
+                       /* optionally, we can set a certificate validation
+                        * callback function if set_verify is not called, and
+                        * root ca is set, `tls_default_verify` will be used
+                        * (does exactly what `verify` does in this example)
+                        */
+                       tls_set_verify(clientssl, verify);
+
+                       if (!clientssl) {
+                               fprintf(stderr, "Error initializing client context\n");
+                               return -1;
+                       }
+                       tls_sni_set(clientssl, uri.host);
+                       clientssl->sync = 1;
+                       io.tls = clientssl;
+               }
+
+               sockfd = open_tcp_connection(host, port);
+               io.socket = sockfd;
+
+               if (sockfd < 0) {
+                       exit(EXIT_FAILURE);
+               }
+
+               if (use_tls) {
+                       tls_set_fd(clientssl, sockfd);
+
+                       if ((rv = tls_connect(clientssl)) != 1) {
+                               fprintf(stderr, "Handshake Error %i\n", rv);
+                               return -5;
+                       }
+
+                       ret = tls_write(clientssl, request.buffer, request.len);
+               } else {
+                       ret = write(io.socket, request.buffer, request.len);
+               }
+
+               if (ret < 0) {
+                       fprintf(stderr, "write error %zd\n", ret);
+                       return -6;
+               }
+
+               do {
+                       ret = fill_buffer(&io);
+                       if (ret < 0) {
+                               break;
+                       }
+                       eoh = strstr(io.response.buffer, "\r\n\r\n");
+                       if (ret == 0) {
+                               break;
+                       }
+               } while (!eoh);
+
+               if (!eoh) {
+                       /* never got (complet) header */
+                       fprintf(stderr, "incomplete response to %s\n", av[optind]);
+                       exit(EXIT_FAILURE);
+               }
+
+               header_len = (size_t)(eoh - io.response.buffer) + 4;
+               parse_header(&io);
+
+               switch (io.status_code) {
+                       case 301:
+                       case 302:
+                       case 303:
+                       case 307:
+                               free(url);
+                               url = strdup(io.redirect);
+                               continue;
+                               break;
+               }
+
+               if (printstatus) {
+                       printf("%d\n", io.status_code);
+                       break;
+               }
+
+               if (io.status_code != 200) {
+                       break;
+               }
+
+               if (!raw) {
+                       tls_buffer_shift(&io.response, header_len);
+               }
+               if (head) {
+                       io.response.len -= 2;
+               }
+
+               if (progressbar) {
+                       if (io.content_length) {
+                               fprintf(stderr, "(%lu) ", io.content_length);
+                       }
+               }
+
+               do {
+                       write(out, io.response.buffer, io.response.len);
+                       ret = io.response.len;
+                       io.response.len = 0;
+
+                       if (progressbar) {
+                               if (io.content_length) {
+                                       pdots(50, '.', total, total+ret,
+                                                       io.content_length);
+                               } else {
+                                       int old = total / 1000000;
+                                       int new = (total+ret)/1000000;
+                                       while (old < new) {
+                                               putc('.',stderr);
+                                       }
+                               }
+                               total += ret;
+                       }
+                       ret = fill_buffer(&io);
+               } while (ret > 0);
+
+               if (ret < 0) {
+                       fprintf(stderr, "%s read error %zd\n", uri.scheme, ret);
+               }
+               /* futimens(out, ...) */
+               close(out);
+               tls_buffer_free(&io.response);
+               break;
+       }
+
+       if (use_tls) {
+               tls_shutdown(clientssl);
+               tls_free(clientssl);
+       }
+
+       close(sockfd);
+       if (progressbar && io.status_code == 200) {
+               fprintf(stderr, "(%lu)", total);
+               putc('\n',stderr);
+       }
+
+       return io.status_code == 200 ? 0 : EXIT_FAILURE;
+}
index 044238552d4ce8b4ae305f709af2a890b0db4eb4..4fe8845b65707434be197d20b79370b2623e109e 100755 (executable)
--- a/zpm-repo
+++ b/zpm-repo
@@ -105,10 +105,10 @@ update_info() {
                fi
                if [ -f "$rf" ]; then
                        # TODO merge in so packages aren't deleted
-                       curl -f '-#' -z "$rf" -o "$rf.tmp" "$url"
+                       zpm fetchurl -f '-#' -z "$rf" -o "$rf.tmp" "$url"
                        rv=$?
                else
-                       curl -f '-#' -o "$rf.tmp" "$url" && refresh "$repo"
+                       zpm fetchurl -f '-#' -o "$rf.tmp" "$url" && refresh "$repo"
                        rv=$?
                fi
                if [ $rv -eq 0 ]; then
@@ -120,11 +120,8 @@ update_info() {
        done
 }
 
-# response=$(curl --write-out %{http_code} --silent --output /dev/null servername)
-# --head
-
 head_response_code() {
-       curl --write-out '%{http_code}' --silent --output /dev/null -z $2 $1
+       zpm fetchurl -S -z "$2" "$1"
 }
 
 download() {
@@ -148,11 +145,11 @@ download() {
                                        continue
                                fi
                                echo downloading $pkgid
-                               curl -f '-#' -z "$dest" -o "$dest.tmp" $fetch
+                               zpm fetchurl -f '-#' -z "$dest" -o "$dest.tmp" $fetch
                                mv "$dest.tmp" "$dest"
                        else
                                echo downloading $pkgid
-                               curl -f '-#' -o "$dest.tmp" $fetch
+                               zpm fetchurl -f '-#' -o "$dest.tmp" $fetch
                                mv "$dest.tmp" "$dest"
                        fi
                fi