From 6b88eb05b11a43a48a80fbabfa0ad4b87eb46fbc Mon Sep 17 00:00:00 2001 From: Todd A Ouska Date: Sat, 5 Feb 2011 11:14:47 -0800 Subject: [PATCH] 1.8.8 init --- AUTHORS | 0 COPYING | 340 ++ ChangeLog | 0 INSTALL | 234 + Makefile.am | 28 + NEWS | 0 README | 525 ++ acx_pthread.m4 | 242 + certs/ca-cert.pem | 56 + certs/ca-key.der | Bin 0 -> 317 bytes certs/ca-key.pem | 9 + certs/client-cert.der | Bin 0 -> 786 bytes certs/client-cert.pem | 55 + certs/client-key.der | Bin 0 -> 320 bytes certs/client-key.pem | 9 + certs/client-keyEnc.pem | 12 + certs/dh1024.der | Bin 0 -> 138 bytes certs/dsa-cert.pem | 70 + certs/dsa512.der | Bin 0 -> 250 bytes certs/dsa512.pem | 8 + certs/ecc-key.der | Bin 0 -> 121 bytes certs/ecc-key.pem | 9 + certs/ntru-cert.pem | 24 + certs/ntru-key.raw | Bin 0 -> 607 bytes certs/server-cert.pem | 39 + certs/server-ecc.pem | 55 + certs/server-key.pem | 9 + certs/server-keyEnc.pem | 12 + certs/server-keyPkcs8.pem | 10 + certs/taoCert.txt | 86 + configure.in | 431 ++ ctaocrypt/Makefile.am | 3 + ctaocrypt/benchmark/Makefile.am | 7 + ctaocrypt/benchmark/benchmark.c | 538 ++ ctaocrypt/benchmark/benchmark.sln | 20 + ctaocrypt/benchmark/benchmark.vcproj | 195 + ctaocrypt/benchmark/dh1024.der | Bin 0 -> 138 bytes ctaocrypt/benchmark/rsa1024.der | Bin 0 -> 608 bytes ctaocrypt/ctaocrypt.sln | 38 + ctaocrypt/ctaocrypt.vcproj | 323 + ctaocrypt/include/arc4.h | 56 + ctaocrypt/include/asn.h | 319 + ctaocrypt/include/coding.h | 47 + ctaocrypt/include/config.h | 86 + ctaocrypt/include/config.h.in | 85 + ctaocrypt/include/ctc_aes.h | 84 + ctaocrypt/include/ctc_dh.h | 59 + ctaocrypt/include/ctc_dsa.h | 61 + ctaocrypt/include/ctc_ecc.h | 119 + ctaocrypt/include/ctc_hmac.h | 85 + ctaocrypt/include/ctc_md4.h | 65 + ctaocrypt/include/ctc_md5.h | 62 + ctaocrypt/include/ctc_ripemd.h | 65 + ctaocrypt/include/ctc_rsa.h | 74 + ctaocrypt/include/ctc_sha.h | 63 + ctaocrypt/include/des3.h | 75 + ctaocrypt/include/error.h | 106 + ctaocrypt/include/hc128.h | 57 + ctaocrypt/include/integer.h | 329 + ctaocrypt/include/misc.h | 55 + ctaocrypt/include/mpi_class.h | 996 ++++ ctaocrypt/include/mpi_superclass.h | 73 + ctaocrypt/include/os_settings.h | 268 + ctaocrypt/include/pwdbased.h | 47 + ctaocrypt/include/rabbit.h | 60 + ctaocrypt/include/random.h | 72 + ctaocrypt/include/sha256.h | 69 + ctaocrypt/include/sha512.h | 65 + ctaocrypt/include/tfm.h | 667 +++ ctaocrypt/include/types.h | 198 + ctaocrypt/src/Makefile.am | 2 + ctaocrypt/src/aes.c | 1308 ++++ ctaocrypt/src/aes_asm.s | 484 ++ ctaocrypt/src/arc4.c | 76 + ctaocrypt/src/asm.c | 1302 ++++ ctaocrypt/src/asn.c | 2866 +++++++++ ctaocrypt/src/coding.c | 229 + ctaocrypt/src/des3.c | 493 ++ ctaocrypt/src/dh.c | 165 + ctaocrypt/src/dsa.c | 216 + ctaocrypt/src/fp_mont_small.i | 3838 ++++++++++++ ctaocrypt/src/fp_mul_comba_12.i | 108 + ctaocrypt/src/fp_mul_comba_17.i | 148 + ctaocrypt/src/fp_mul_comba_20.i | 172 + ctaocrypt/src/fp_mul_comba_24.i | 204 + ctaocrypt/src/fp_mul_comba_28.i | 236 + ctaocrypt/src/fp_mul_comba_3.i | 36 + ctaocrypt/src/fp_mul_comba_32.i | 282 + ctaocrypt/src/fp_mul_comba_4.i | 44 + ctaocrypt/src/fp_mul_comba_48.i | 396 ++ ctaocrypt/src/fp_mul_comba_6.i | 60 + ctaocrypt/src/fp_mul_comba_64.i | 524 ++ ctaocrypt/src/fp_mul_comba_7.i | 68 + ctaocrypt/src/fp_mul_comba_8.i | 76 + ctaocrypt/src/fp_mul_comba_9.i | 84 + ctaocrypt/src/fp_mul_comba_small_set.i | 1225 ++++ ctaocrypt/src/fp_sqr_comba_12.i | 135 + ctaocrypt/src/fp_sqr_comba_17.i | 185 + ctaocrypt/src/fp_sqr_comba_20.i | 218 + ctaocrypt/src/fp_sqr_comba_24.i | 258 + ctaocrypt/src/fp_sqr_comba_28.i | 298 + ctaocrypt/src/fp_sqr_comba_3.i | 45 + ctaocrypt/src/fp_sqr_comba_32.i | 338 ++ ctaocrypt/src/fp_sqr_comba_4.i | 55 + ctaocrypt/src/fp_sqr_comba_48.i | 498 ++ ctaocrypt/src/fp_sqr_comba_6.i | 75 + ctaocrypt/src/fp_sqr_comba_64.i | 658 ++ ctaocrypt/src/fp_sqr_comba_7.i | 85 + ctaocrypt/src/fp_sqr_comba_8.i | 95 + ctaocrypt/src/fp_sqr_comba_9.i | 105 + ctaocrypt/src/fp_sqr_comba_small_set.i | 1515 +++++ ctaocrypt/src/hc128.c | 317 + ctaocrypt/src/hmac.c | 158 + ctaocrypt/src/integer.c | 4357 ++++++++++++++ ctaocrypt/src/md4.c | 215 + ctaocrypt/src/md5.c | 222 + ctaocrypt/src/misc.c | 171 + ctaocrypt/src/pwdbased.c | 76 + ctaocrypt/src/rabbit.c | 239 + ctaocrypt/src/random.c | 182 + ctaocrypt/src/ripemd.c | 347 ++ ctaocrypt/src/rsa.c | 536 ++ ctaocrypt/src/sha.c | 198 + ctaocrypt/src/sha256.c | 206 + ctaocrypt/src/sha512.c | 242 + ctaocrypt/src/tfm.c | 2429 ++++++++ ctaocrypt/test/Makefile.am | 7 + ctaocrypt/test/test.c | 1783 ++++++ ctaocrypt/test/test.sln | 20 + ctaocrypt/test/test.vcproj | 195 + cyassl-iphone.xcodeproj/project.pbxproj | 430 ++ cyassl-ntru.sln | 65 + cyassl-ntru.vcproj | 377 ++ cyassl.sln | 74 + cyassl.vcproj | 377 ++ doc/CyaSSL-Manual.pdf | Bin 0 -> 1104776 bytes examples/Makefile.am | 2 + examples/client/Makefile.am | 7 + examples/client/client-ntru.vcproj | 199 + examples/client/client.c | 303 + examples/client/client.sln | 20 + examples/client/client.vcproj | 197 + examples/echoclient/Makefile.am | 7 + examples/echoclient/echoclient-ntru.vcproj | 199 + examples/echoclient/echoclient.c | 149 + examples/echoclient/echoclient.sln | 20 + examples/echoclient/echoclient.vcproj | 197 + examples/echoclient/input | 87 + examples/echoclient/quit | 2 + examples/echoserver/Makefile.am | 7 + examples/echoserver/echoserver-ntru.vcproj | 199 + examples/echoserver/echoserver.c | 226 + examples/echoserver/echoserver.sln | 20 + examples/echoserver/echoserver.vcproj | 197 + examples/server/Makefile.am | 7 + examples/server/server-ntru.vcproj | 199 + examples/server/server.c | 199 + examples/server/server.sln | 20 + examples/server/server.vcproj | 197 + include/cyassl_error.h | 117 + include/cyassl_int.h | 1214 ++++ include/openssl/asn1.h | 2 + include/openssl/bio.h | 2 + include/openssl/bn.h | 2 + include/openssl/conf.h | 2 + include/openssl/crypto.h | 19 + include/openssl/cyassl_callbacks.h | 81 + include/openssl/cyassl_test.h | 563 ++ include/openssl/des.h | 70 + include/openssl/dh.h | 2 + include/openssl/dsa.h | 2 + include/openssl/ec.h | 2 + include/openssl/ecdsa.h | 2 + include/openssl/engine.h | 5 + include/openssl/err.h | 2 + include/openssl/evp.h | 79 + include/openssl/hmac.h | 51 + include/openssl/lhash.h | 2 + include/openssl/md4.h | 1 + include/openssl/md5.h | 32 + include/openssl/ocsp.h | 1 + include/openssl/opensslconf.h | 8 + include/openssl/opensslv.h | 12 + include/openssl/ossl_typ.h | 2 + include/openssl/pem.h | 2 + include/openssl/pkcs12.h | 2 + include/openssl/rand.h | 4 + include/openssl/rsa.h | 10 + include/openssl/sha.h | 32 + include/openssl/ssl.h | 675 +++ include/openssl/stack.h | 2 + include/openssl/ui.h | 2 + include/openssl/x509.h | 3 + include/openssl/x509v3.h | 2 + include/sniffer.h | 72 + include/sniffer_error.h | 102 + include/sniffer_error.rc | 78 + lib/dummy | 2 + lib_socket_nsl.m4 | 25 + src/Makefile.am | 43 + src/cyassl_int.c | 5297 +++++++++++++++++ src/cyassl_io.c | 190 + src/keys.c | 751 +++ src/sniffer.c | 2187 +++++++ src/ssl.c | 3484 +++++++++++ src/tls.c | 451 ++ sslSniffer/Makefile.am | 3 + sslSniffer/sslSniffer.vcproj | 206 + sslSniffer/sslSnifferTest/Makefile.am | 11 + sslSniffer/sslSnifferTest/snifftest.c | 214 + sslSniffer/sslSnifferTest/sslSniffTest.vcproj | 199 + swig/PythonBuild.sh | 9 + swig/README | 44 + swig/cyassl.i | 42 + swig/cyassl_adds.c | 208 + swig/python_cyassl.vcproj | 225 + swig/rsasign.py | 35 + swig/runme.py | 30 + testsuite/Makefile.am | 10 + testsuite/input | 87 + testsuite/quit | 2 + testsuite/testsuite-ntru.vcproj | 219 + testsuite/testsuite.c | 200 + testsuite/testsuite.sln | 20 + testsuite/testsuite.vcproj | 217 + 225 files changed, 60614 insertions(+) create mode 100644 AUTHORS create mode 100644 COPYING create mode 100644 ChangeLog create mode 100644 INSTALL create mode 100644 Makefile.am create mode 100644 NEWS create mode 100644 README create mode 100644 acx_pthread.m4 create mode 100644 certs/ca-cert.pem create mode 100644 certs/ca-key.der create mode 100644 certs/ca-key.pem create mode 100644 certs/client-cert.der create mode 100644 certs/client-cert.pem create mode 100644 certs/client-key.der create mode 100644 certs/client-key.pem create mode 100644 certs/client-keyEnc.pem create mode 100644 certs/dh1024.der create mode 100644 certs/dsa-cert.pem create mode 100644 certs/dsa512.der create mode 100644 certs/dsa512.pem create mode 100644 certs/ecc-key.der create mode 100644 certs/ecc-key.pem create mode 100644 certs/ntru-cert.pem create mode 100644 certs/ntru-key.raw create mode 100644 certs/server-cert.pem create mode 100644 certs/server-ecc.pem create mode 100644 certs/server-key.pem create mode 100644 certs/server-keyEnc.pem create mode 100644 certs/server-keyPkcs8.pem create mode 100644 certs/taoCert.txt create mode 100644 configure.in create mode 100644 ctaocrypt/Makefile.am create mode 100644 ctaocrypt/benchmark/Makefile.am create mode 100644 ctaocrypt/benchmark/benchmark.c create mode 100755 ctaocrypt/benchmark/benchmark.sln create mode 100755 ctaocrypt/benchmark/benchmark.vcproj create mode 100644 ctaocrypt/benchmark/dh1024.der create mode 100644 ctaocrypt/benchmark/rsa1024.der create mode 100755 ctaocrypt/ctaocrypt.sln create mode 100755 ctaocrypt/ctaocrypt.vcproj create mode 100644 ctaocrypt/include/arc4.h create mode 100644 ctaocrypt/include/asn.h create mode 100644 ctaocrypt/include/coding.h create mode 100644 ctaocrypt/include/config.h create mode 100644 ctaocrypt/include/config.h.in create mode 100644 ctaocrypt/include/ctc_aes.h create mode 100644 ctaocrypt/include/ctc_dh.h create mode 100644 ctaocrypt/include/ctc_dsa.h create mode 100644 ctaocrypt/include/ctc_ecc.h create mode 100644 ctaocrypt/include/ctc_hmac.h create mode 100644 ctaocrypt/include/ctc_md4.h create mode 100644 ctaocrypt/include/ctc_md5.h create mode 100644 ctaocrypt/include/ctc_ripemd.h create mode 100644 ctaocrypt/include/ctc_rsa.h create mode 100644 ctaocrypt/include/ctc_sha.h create mode 100644 ctaocrypt/include/des3.h create mode 100644 ctaocrypt/include/error.h create mode 100644 ctaocrypt/include/hc128.h create mode 100644 ctaocrypt/include/integer.h create mode 100644 ctaocrypt/include/misc.h create mode 100644 ctaocrypt/include/mpi_class.h create mode 100644 ctaocrypt/include/mpi_superclass.h create mode 100644 ctaocrypt/include/os_settings.h create mode 100644 ctaocrypt/include/pwdbased.h create mode 100644 ctaocrypt/include/rabbit.h create mode 100644 ctaocrypt/include/random.h create mode 100644 ctaocrypt/include/sha256.h create mode 100644 ctaocrypt/include/sha512.h create mode 100644 ctaocrypt/include/tfm.h create mode 100644 ctaocrypt/include/types.h create mode 100644 ctaocrypt/src/Makefile.am create mode 100644 ctaocrypt/src/aes.c create mode 100755 ctaocrypt/src/aes_asm.s create mode 100644 ctaocrypt/src/arc4.c create mode 100644 ctaocrypt/src/asm.c create mode 100644 ctaocrypt/src/asn.c create mode 100644 ctaocrypt/src/coding.c create mode 100644 ctaocrypt/src/des3.c create mode 100644 ctaocrypt/src/dh.c create mode 100644 ctaocrypt/src/dsa.c create mode 100644 ctaocrypt/src/fp_mont_small.i create mode 100644 ctaocrypt/src/fp_mul_comba_12.i create mode 100644 ctaocrypt/src/fp_mul_comba_17.i create mode 100644 ctaocrypt/src/fp_mul_comba_20.i create mode 100644 ctaocrypt/src/fp_mul_comba_24.i create mode 100644 ctaocrypt/src/fp_mul_comba_28.i create mode 100644 ctaocrypt/src/fp_mul_comba_3.i create mode 100644 ctaocrypt/src/fp_mul_comba_32.i create mode 100644 ctaocrypt/src/fp_mul_comba_4.i create mode 100644 ctaocrypt/src/fp_mul_comba_48.i create mode 100644 ctaocrypt/src/fp_mul_comba_6.i create mode 100644 ctaocrypt/src/fp_mul_comba_64.i create mode 100644 ctaocrypt/src/fp_mul_comba_7.i create mode 100644 ctaocrypt/src/fp_mul_comba_8.i create mode 100644 ctaocrypt/src/fp_mul_comba_9.i create mode 100644 ctaocrypt/src/fp_mul_comba_small_set.i create mode 100644 ctaocrypt/src/fp_sqr_comba_12.i create mode 100644 ctaocrypt/src/fp_sqr_comba_17.i create mode 100644 ctaocrypt/src/fp_sqr_comba_20.i create mode 100644 ctaocrypt/src/fp_sqr_comba_24.i create mode 100644 ctaocrypt/src/fp_sqr_comba_28.i create mode 100644 ctaocrypt/src/fp_sqr_comba_3.i create mode 100644 ctaocrypt/src/fp_sqr_comba_32.i create mode 100644 ctaocrypt/src/fp_sqr_comba_4.i create mode 100644 ctaocrypt/src/fp_sqr_comba_48.i create mode 100644 ctaocrypt/src/fp_sqr_comba_6.i create mode 100644 ctaocrypt/src/fp_sqr_comba_64.i create mode 100644 ctaocrypt/src/fp_sqr_comba_7.i create mode 100644 ctaocrypt/src/fp_sqr_comba_8.i create mode 100644 ctaocrypt/src/fp_sqr_comba_9.i create mode 100644 ctaocrypt/src/fp_sqr_comba_small_set.i create mode 100644 ctaocrypt/src/hc128.c create mode 100644 ctaocrypt/src/hmac.c create mode 100644 ctaocrypt/src/integer.c create mode 100644 ctaocrypt/src/md4.c create mode 100644 ctaocrypt/src/md5.c create mode 100644 ctaocrypt/src/misc.c create mode 100644 ctaocrypt/src/pwdbased.c create mode 100644 ctaocrypt/src/rabbit.c create mode 100644 ctaocrypt/src/random.c create mode 100644 ctaocrypt/src/ripemd.c create mode 100644 ctaocrypt/src/rsa.c create mode 100644 ctaocrypt/src/sha.c create mode 100644 ctaocrypt/src/sha256.c create mode 100644 ctaocrypt/src/sha512.c create mode 100644 ctaocrypt/src/tfm.c create mode 100644 ctaocrypt/test/Makefile.am create mode 100644 ctaocrypt/test/test.c create mode 100755 ctaocrypt/test/test.sln create mode 100755 ctaocrypt/test/test.vcproj create mode 100644 cyassl-iphone.xcodeproj/project.pbxproj create mode 100755 cyassl-ntru.sln create mode 100755 cyassl-ntru.vcproj create mode 100755 cyassl.sln create mode 100755 cyassl.vcproj create mode 100644 doc/CyaSSL-Manual.pdf create mode 100644 examples/Makefile.am create mode 100644 examples/client/Makefile.am create mode 100755 examples/client/client-ntru.vcproj create mode 100644 examples/client/client.c create mode 100755 examples/client/client.sln create mode 100755 examples/client/client.vcproj create mode 100644 examples/echoclient/Makefile.am create mode 100755 examples/echoclient/echoclient-ntru.vcproj create mode 100644 examples/echoclient/echoclient.c create mode 100755 examples/echoclient/echoclient.sln create mode 100755 examples/echoclient/echoclient.vcproj create mode 100644 examples/echoclient/input create mode 100644 examples/echoclient/quit create mode 100644 examples/echoserver/Makefile.am create mode 100755 examples/echoserver/echoserver-ntru.vcproj create mode 100644 examples/echoserver/echoserver.c create mode 100755 examples/echoserver/echoserver.sln create mode 100755 examples/echoserver/echoserver.vcproj create mode 100644 examples/server/Makefile.am create mode 100755 examples/server/server-ntru.vcproj create mode 100644 examples/server/server.c create mode 100755 examples/server/server.sln create mode 100755 examples/server/server.vcproj create mode 100644 include/cyassl_error.h create mode 100644 include/cyassl_int.h create mode 100644 include/openssl/asn1.h create mode 100644 include/openssl/bio.h create mode 100644 include/openssl/bn.h create mode 100644 include/openssl/conf.h create mode 100644 include/openssl/crypto.h create mode 100644 include/openssl/cyassl_callbacks.h create mode 100644 include/openssl/cyassl_test.h create mode 100644 include/openssl/des.h create mode 100644 include/openssl/dh.h create mode 100644 include/openssl/dsa.h create mode 100644 include/openssl/ec.h create mode 100644 include/openssl/ecdsa.h create mode 100644 include/openssl/engine.h create mode 100644 include/openssl/err.h create mode 100644 include/openssl/evp.h create mode 100644 include/openssl/hmac.h create mode 100644 include/openssl/lhash.h create mode 100644 include/openssl/md4.h create mode 100644 include/openssl/md5.h create mode 100644 include/openssl/ocsp.h create mode 100644 include/openssl/opensslconf.h create mode 100644 include/openssl/opensslv.h create mode 100644 include/openssl/ossl_typ.h create mode 100644 include/openssl/pem.h create mode 100644 include/openssl/pkcs12.h create mode 100644 include/openssl/rand.h create mode 100644 include/openssl/rsa.h create mode 100644 include/openssl/sha.h create mode 100644 include/openssl/ssl.h create mode 100644 include/openssl/stack.h create mode 100644 include/openssl/ui.h create mode 100644 include/openssl/x509.h create mode 100644 include/openssl/x509v3.h create mode 100644 include/sniffer.h create mode 100644 include/sniffer_error.h create mode 100644 include/sniffer_error.rc create mode 100644 lib/dummy create mode 100644 lib_socket_nsl.m4 create mode 100644 src/Makefile.am create mode 100644 src/cyassl_int.c create mode 100644 src/cyassl_io.c create mode 100644 src/keys.c create mode 100644 src/sniffer.c create mode 100644 src/ssl.c create mode 100644 src/tls.c create mode 100644 sslSniffer/Makefile.am create mode 100755 sslSniffer/sslSniffer.vcproj create mode 100644 sslSniffer/sslSnifferTest/Makefile.am create mode 100755 sslSniffer/sslSnifferTest/snifftest.c create mode 100755 sslSniffer/sslSnifferTest/sslSniffTest.vcproj create mode 100755 swig/PythonBuild.sh create mode 100644 swig/README create mode 100644 swig/cyassl.i create mode 100644 swig/cyassl_adds.c create mode 100755 swig/python_cyassl.vcproj create mode 100644 swig/rsasign.py create mode 100644 swig/runme.py create mode 100644 testsuite/Makefile.am create mode 100644 testsuite/input create mode 100644 testsuite/quit create mode 100755 testsuite/testsuite-ntru.vcproj create mode 100644 testsuite/testsuite.c create mode 100755 testsuite/testsuite.sln create mode 100755 testsuite/testsuite.vcproj diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 000000000..e69de29bb diff --git a/COPYING b/COPYING new file mode 100644 index 000000000..d60c31a97 --- /dev/null +++ b/COPYING @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 000000000..e69de29bb diff --git a/INSTALL b/INSTALL new file mode 100644 index 000000000..5458714e1 --- /dev/null +++ b/INSTALL @@ -0,0 +1,234 @@ +Installation Instructions +************************* + +Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005, +2006 Free Software Foundation, Inc. + +This file is free documentation; the Free Software Foundation gives +unlimited permission to copy, distribute and modify it. + +Basic Installation +================== + +Briefly, the shell commands `./configure; make; make install' should +configure, build, and install this package. The following +more-detailed instructions are generic; see the `README' file for +instructions specific to this package. + + The `configure' shell script attempts to guess correct values for +various system-dependent variables used during compilation. It uses +those values to create a `Makefile' in each directory of the package. +It may also create one or more `.h' files containing system-dependent +definitions. Finally, it creates a shell script `config.status' that +you can run in the future to recreate the current configuration, and a +file `config.log' containing compiler output (useful mainly for +debugging `configure'). + + It can also use an optional file (typically called `config.cache' +and enabled with `--cache-file=config.cache' or simply `-C') that saves +the results of its tests to speed up reconfiguring. Caching is +disabled by default to prevent problems with accidental use of stale +cache files. + + If you need to do unusual things to compile the package, please try +to figure out how `configure' could check whether to do them, and mail +diffs or instructions to the address given in the `README' so they can +be considered for the next release. If you are using the cache, and at +some point `config.cache' contains results you don't want to keep, you +may remove or edit it. + + The file `configure.ac' (or `configure.in') is used to create +`configure' by a program called `autoconf'. You need `configure.ac' if +you want to change it or regenerate `configure' using a newer version +of `autoconf'. + +The simplest way to compile this package is: + + 1. `cd' to the directory containing the package's source code and type + `./configure' to configure the package for your system. + + Running `configure' might take a while. While running, it prints + some messages telling which features it is checking for. + + 2. Type `make' to compile the package. + + 3. Optionally, type `make check' to run any self-tests that come with + the package. + + 4. Type `make install' to install the programs and any data files and + documentation. + + 5. You can remove the program binaries and object files from the + source code directory by typing `make clean'. To also remove the + files that `configure' created (so you can compile the package for + a different kind of computer), type `make distclean'. There is + also a `make maintainer-clean' target, but that is intended mainly + for the package's developers. If you use it, you may have to get + all sorts of other programs in order to regenerate files that came + with the distribution. + +Compilers and Options +===================== + +Some systems require unusual options for compilation or linking that the +`configure' script does not know about. Run `./configure --help' for +details on some of the pertinent environment variables. + + You can give `configure' initial values for configuration parameters +by setting variables in the command line or in the environment. Here +is an example: + + ./configure CC=c99 CFLAGS=-g LIBS=-lposix + + *Note Defining Variables::, for more details. + +Compiling For Multiple Architectures +==================================== + +You can compile the package for more than one kind of computer at the +same time, by placing the object files for each architecture in their +own directory. To do this, you can use GNU `make'. `cd' to the +directory where you want the object files and executables to go and run +the `configure' script. `configure' automatically checks for the +source code in the directory that `configure' is in and in `..'. + + With a non-GNU `make', it is safer to compile the package for one +architecture at a time in the source code directory. After you have +installed the package for one architecture, use `make distclean' before +reconfiguring for another architecture. + +Installation Names +================== + +By default, `make install' installs the package's commands under +`/usr/local/bin', include files under `/usr/local/include', etc. You +can specify an installation prefix other than `/usr/local' by giving +`configure' the option `--prefix=PREFIX'. + + You can specify separate installation prefixes for +architecture-specific files and architecture-independent files. If you +pass the option `--exec-prefix=PREFIX' to `configure', the package uses +PREFIX as the prefix for installing programs and libraries. +Documentation and other data files still use the regular prefix. + + In addition, if you use an unusual directory layout you can give +options like `--bindir=DIR' to specify different values for particular +kinds of files. Run `configure --help' for a list of the directories +you can set and what kinds of files go in them. + + If the package supports it, you can cause programs to be installed +with an extra prefix or suffix on their names by giving `configure' the +option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. + +Optional Features +================= + +Some packages pay attention to `--enable-FEATURE' options to +`configure', where FEATURE indicates an optional part of the package. +They may also pay attention to `--with-PACKAGE' options, where PACKAGE +is something like `gnu-as' or `x' (for the X Window System). The +`README' should mention any `--enable-' and `--with-' options that the +package recognizes. + + For packages that use the X Window System, `configure' can usually +find the X include and library files automatically, but if it doesn't, +you can use the `configure' options `--x-includes=DIR' and +`--x-libraries=DIR' to specify their locations. + +Specifying the System Type +========================== + +There may be some features `configure' cannot figure out automatically, +but needs to determine by the type of machine the package will run on. +Usually, assuming the package is built to be run on the _same_ +architectures, `configure' can figure that out, but if it prints a +message saying it cannot guess the machine type, give it the +`--build=TYPE' option. TYPE can either be a short name for the system +type, such as `sun4', or a canonical name which has the form: + + CPU-COMPANY-SYSTEM + +where SYSTEM can have one of these forms: + + OS KERNEL-OS + + See the file `config.sub' for the possible values of each field. If +`config.sub' isn't included in this package, then this package doesn't +need to know the machine type. + + If you are _building_ compiler tools for cross-compiling, you should +use the option `--target=TYPE' to select the type of system they will +produce code for. + + If you want to _use_ a cross compiler, that generates code for a +platform different from the build platform, you should specify the +"host" platform (i.e., that on which the generated programs will +eventually be run) with `--host=TYPE'. + +Sharing Defaults +================ + +If you want to set default values for `configure' scripts to share, you +can create a site shell script called `config.site' that gives default +values for variables like `CC', `cache_file', and `prefix'. +`configure' looks for `PREFIX/share/config.site' if it exists, then +`PREFIX/etc/config.site' if it exists. Or, you can set the +`CONFIG_SITE' environment variable to the location of the site script. +A warning: not all `configure' scripts look for a site script. + +Defining Variables +================== + +Variables not defined in a site shell script can be set in the +environment passed to `configure'. However, some packages may run +configure again during the build, and the customized values of these +variables may be lost. In order to avoid this problem, you should set +them in the `configure' command line, using `VAR=value'. For example: + + ./configure CC=/usr/local2/bin/gcc + +causes the specified `gcc' to be used as the C compiler (unless it is +overridden in the site shell script). + +Unfortunately, this technique does not work for `CONFIG_SHELL' due to +an Autoconf bug. Until the bug is fixed you can use this workaround: + + CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash + +`configure' Invocation +====================== + +`configure' recognizes the following options to control how it operates. + +`--help' +`-h' + Print a summary of the options to `configure', and exit. + +`--version' +`-V' + Print the version of Autoconf used to generate the `configure' + script, and exit. + +`--cache-file=FILE' + Enable the cache: use and save the results of the tests in FILE, + traditionally `config.cache'. FILE defaults to `/dev/null' to + disable caching. + +`--config-cache' +`-C' + Alias for `--cache-file=config.cache'. + +`--quiet' +`--silent' +`-q' + Do not print messages saying which checks are being made. To + suppress all normal output, redirect it to `/dev/null' (any error + messages will still be shown). + +`--srcdir=DIR' + Look for the package's source code in directory DIR. Usually + `configure' can determine that directory automatically. + +`configure' also accepts some other, not widely useful, options. Run +`configure --help' for more details. + diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 000000000..09fbc776e --- /dev/null +++ b/Makefile.am @@ -0,0 +1,28 @@ +SUBDIRS = src ctaocrypt examples testsuite sslSniffer +EXTRA_DIST = certs/*.pem certs/*.der certs/*.txt certs/*.raw \ + lib/dummy *.sln *.vcproj cyassl-iphone.xcodeproj/project.pbxproj \ + doc/*.pdf swig/README swig/*.i swig/cyassl_adds.c swig/*.sh swig/runme.* \ + swig/python_cyassl.vcproj swig/rsasign.py + +# !!!! first line of rule has to start with a hard (real) tab, not spaces +basic: + cd src; $(MAKE); cd ../testsuite; $(MAKE); cd ../ + +openssl-links: + cd lib; ln -s ../src/.libs/libcyassl.a libcrypto.a; \ + ln -s ../src/.libs/libcyassl.a libssl.a; \ + ln -s ../src/.libs/libcyassl.a libcyassl.a; cd ../ + +# !!! test -e with a .name like .libs then a * like *dylib fails so just +# look for the .dylib on OS X, and .so otherwise but copy all parts +install: + $(mkinstalldirs) $(DESTDIR)$(includedir) $(DESTDIR)$(libdir); \ + cp -fpR include/* $(DESTDIR)$(includedir); \ + cp -fpR ctaocrypt/include/* $(DESTDIR)$(includedir); \ + cp -fpR src/libcyassl.la $(DESTDIR)$(libdir); \ + if test -e src/.libs/libcyassl.a; then \ + cp -fp src/.libs/libcyassl.a $(DESTDIR)$(libdir); fi; \ + if test -e src/.libs/libcyassl.so; then \ + cp -fpR src/.libs/libcyassl.so* $(DESTDIR)$(libdir); fi; \ + if test -e src/.libs/libcyassl.dylib; then \ + cp -fpR src/.libs/libcyassl.*dylib $(DESTDIR)$(libdir); fi; diff --git a/NEWS b/NEWS new file mode 100644 index 000000000..e69de29bb diff --git a/README b/README new file mode 100644 index 000000000..046f0e938 --- /dev/null +++ b/README @@ -0,0 +1,525 @@ +*** Note, Please read *** + +CyaSSL takes a different approach to certificate verification than OpenSSL does. +The default policy for the client is to verify the server, this means that if +you don't load CAs to verify the server you'll get a connect error, unable to +verify. It you want to mimic OpenSSL behavior of having SSL_connect succeed +even if verifying the server fails and reducing security you can do this by +calling: + +SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, 0); + +before calling SSL_new(); Though it's not recommended. + +*** end Note *** + +CyaSSL Release 1.8.0 (12/23/2010) + +Release 1.8.0 for CyaSSL adds bug fixes, x509 v3 CA signed certificate +generation, a C standard library abstraction layer, lower memory use, increased +portability through the os_settings.h file, and the ability to use NTRU cipher +suites when used in conjunction with an NTRU license and library. + +The initial CyaSSL manual offering is included in the doc/ directory. For +build instructions and comments about the new features please check the manual. + +Please send any comments or questions to support@yassl.com. + +Happy Holidays. + + +********************* CyaSSL Release 1.6.5 (9/9/2010) + +Release 1.6.5 for CyaSSL adds bug fixes and x509 v3 self signed certificate +generation. + +For general build instructions see doc/Building_CyaSSL.pdf. + +To enable certificate generation support add this option to ./configure +./configure --enable-certgen + +An example is included in ctaocrypt/test/test.c and documentation is provided +in doc/CyaSSL_Extensions_Reference.pdf item 11. + +********************** CyaSSL Release 1.6.0 (8/27/2010) + +Release 1.6.0 for CyaSSL adds bug fixes, RIPEMD-160, SHA-512, and RSA key +generation. + +For general build instructions see doc/Building_CyaSSL.pdf. + +To add RIPEMD-160 support add this option to ./configure +./configure --enable-ripemd + +To add SHA-512 support add this option to ./configure +./configure --enable-sha512 + +To add RSA key generation support add this option to ./configure +./configure --enable-keygen + +Please see ctaocrypt/test/test.c for examples and usage. + +For Windows, RIPEMD-160 and SHA-512 are enabled by default but key generation is +off by default. To turn key generation on add the define CYASSL_KEY_GEN to +CyaSSL. + + +************* CyaSSL Release 1.5.6 (7/28/2010) + +Release 1.5.6 for CyaSSL adds bug fixes, compatibility for our JSSE provider, +and a fix for GCC builds on some systems. + +For general build instructions see doc/Building_CyaSSL.pdf. + +To add AES-NI support add this option to ./configure +./configure --enable-aesni + +You'll need GCC 4.4.3 or later to make use of the assembly. + +************** CyaSSL Release 1.5.4 (7/7/2010) + +Release 1.5.4 for CyaSSL adds bug fixes, support for AES-NI, SHA1 speed +improvements from loop unrolling, and support for the Mongoose Web Server. + +For general build instructions see doc/Building_CyaSSL.pdf. + +To add AES-NI support add this option to ./configure +./configure --enable-aesni + +You'll need GCC 4.4.3 or later to make use of the assembly. + +*************** CyaSSL Release 1.5.0 (5/11/2010) + +Release 1.5.0 for CyaSSL adds bug fixes, GoAhead WebServer support, sniffer +support, and initial swig interface support. + +For general build instructions see doc/Building_CyaSSL.pdf. + +To add support for GoAhead WebServer either --enable-opensslExtra or if you +don't want all the features of opensslExtra you can just define GOAHEAD_WS +instead. GOAHEAD_WS can be added to ./configure with CFLAGS=-DGOAHEAD_WS or +you can define it yourself. + +To look at the sniffer support please see the sniffertest app in +sslSniffer/sslSnifferTest. Build with --enable-sniffer on *nix or use the +vcproj files on windows. You'll need to have pcap installed on *nix and +WinPcap on windows. + +A swig interface file is now located in the swig directory for using Python, +Java, Perl, and others with CyaSSL. This is initial support and experimental, +please send questions or comments to support@yassl.com. + +When doing load testing with CyaSSL, on the echoserver example say, the client +machine may run out of tcp ephemeral ports, they will end up in the TIME_WAIT +queue, and can't be reused by default. There are generally two ways to fix +this. 1) Reduce the length sockets remain on the TIME_WAIT queue or 2) Allow +items on the TIME_WAIT queue to be reused. + + +To reduce the TIME_WAIT length in OS X to 3 seconds (3000 milliseconds) + +sudo sysctl -w net.inet.tcp.msl=3000 + +In Linux + +sudo sysctl -w net.ipv4.tcp_tw_reuse=1 + +allows reuse of sockets in TIME_WAIT + +sudo sysctl -w net.ipv4.tcp_tw_recycle=1 + +works but seems to remove sockets from TIME_WAIT entirely? + +sudo sysctl -w net.ipv4.tcp_fin_timeout=1 + +doen't control TIME_WAIT, it controls FIN_WAIT(2) contrary to some posts + + +******************** CyaSSL Release 1.4.0 (2/18/2010) + +Release 1.3.0 for CyaSSL adds bug fixes, better multi TLS/SSL version support +through SSLv23_server_method(), and improved documentation in the doc/ folder. + +For general build instructions doc/Building_CyaSSL.pdf. + +******************** CyaSSL Release 1.3.0 (1/21/2010) + +Release 1.3.0 for CyaSSL adds bug fixes, a potential security problem fix, +better porting support, removal of assert()s, and a complete THREADX port. + +For general build instructions see rc1 below. + +******************** CyaSSL Release 1.2.0 (11/2/2009) + +Release 1.2.0 for CyaSSL adds bug fixes and session negotiation if first use is +read or write. + +For general build instructions see rc1 below. + +******************** CyaSSL Release 1.1.0 (9/2/2009) + +Release 1.1.0 for CyaSSL adds bug fixes, a check against malicious session +cache use, support for lighttpd, and TLS 1.2. + +To get TLS 1.2 support please use the client and server functions: + +SSL_METHOD *TLSv1_2_server_method(void); +SSL_METHOD *TLSv1_2_client_method(void); + +CyaSSL was tested against lighttpd 1.4.23. To build CyaSSL for use with +lighttpd use the following commands from the CyaSSL install dir : + +./configure --disable-shared --enable-opensslExtra --enable-fastmath --without-zlib + +make +make openssl-links + +Then to build lighttpd with CyaSSL use the following commands from the +lighttpd install dir: + +./configure --with-openssl --with-openssl-includes=/include --with-openssl-libs=/lib LDFLAGS=-lm + +make + +On some systems you may get a linker error about a duplicate symbol for +MD5_Init or other MD5 calls. This seems to be caused by the lighttpd src file +md5.c, which defines MD5_Init(), and is included in liblightcomp_la-md5.o. +When liblightcomp is linked with the SSL_LIBs the linker may complain about +the duplicate symbol. This can be fixed by editing the lighttpd src file md5.c +and adding this line to the beginning of the file: + +#if 0 + +and this line to the end of the file + +#endif + +Then from the lighttpd src dir do a: + +make clean +make + + +If you get link errors about undefined symbols more than likely the actual +OpenSSL libraries are found by the linker before the CyaSSL openssl-links that +point to the CyaSSL library, causing the linker confusion. This can be fixed +by editing the Makefile in the lighttpd src directory and changing the line: + +SSL_LIB = -lssl -lcrypto + +to + +SSL_LIB = -lcyassl + +Then from the lighttpd src dir do a: + +make clean +make + +This should remove any confusion the linker may be having with missing symbols. + +For any questions or concerns please contact support@yassl.com . + +For general build instructions see rc1 below. + +******************CyaSSL Release 1.0.6 (8/03/2009) + +Release 1.0.6 for CyaSSL adds bug fixes, an improved session cache, and faster +math with a huge code option. + +The session cache now defaults to a client mode, also good for embedded servers. +For servers not under heavy load (less than 200 new sessions per minute), define +BIG_SESSION_CACHE. If the server will be under heavy load, define +HUGE_SESSION_CACHE. + +There is now a fasthugemath option for configure. This enables fastmath plus +even faster math by greatly increasing the code size of the math library. Use +the benchmark utility to compare public key operations. + + +For general build instructions see rc1 below. + +******************CyaSSL Release 1.0.3 (5/10/2009) + +Release 1.0.3 for CyaSSL adds bug fixes and add increased support for OpenSSL +compatibility when building other applications. + +Release 1.0.3 includes an alpha release of DTLS for both client and servers. +This is only for testing purposes at this time. Rebroadcast and reordering +aren't fully implemented at this time but will be for the next release. + +For general build instructions see rc1 below. + +******************CyaSSL Release 1.0.2 (4/3/2009) + +Release 1.0.2 for CyaSSL adds bug fixes for a couple I/O issues. Some systems +will send a SIGPIPE on socket recv() at any time and this should be handled by +the application by turning off SIGPIPE through setsockopt() or returning from +the handler. + +Release 1.0.2 includes an alpha release of DTLS for both client and servers. +This is only for testing purposes at this time. Rebroadcast and reordering +aren't fully implemented at this time but will be for the next release. + +For general build instructions see rc1 below. + +*****************CyaSSL Release Candidiate 3 rc3-1.0.0 (2/25/2009) + + +Release Candidate 3 for CyaSSL 1.0.0 adds bug fixes and adds a project file for +iPhone development with Xcode. cyassl-iphone.xcodeproj is located in the root +directory. This release also includes a fix for supporting other +implementations that bundle multiple messages at the record layer, this was +lost when cyassl i/o was re-implemented but is now fixed. + +For general build instructions see rc1 below. + +*****************CyaSSL Release Candidiate 2 rc2-1.0.0 (1/21/2009) + + +Release Candidate 2 for CyaSSL 1.0.0 adds bug fixes and adds two new stream +ciphers along with their respective cipher suites. CyaSSL adds support for +HC-128 and RABBIT stream ciphers. The new suites are: + +TLS_RSA_WITH_HC_128_CBC_SHA +TLS_RSA_WITH_RABBIT_CBC_SHA + +And the corresponding cipher names are + +HC128-SHA +RABBIT-SHA + +CyaSSL also adds support for building with devkitPro for PPC by changing the +library proper to use libogc. The examples haven't been changed yet but if +there's interest they can be. Here's an example ./configure to build CyaSSL +for devkitPro: + +./configure --disable-shared CC=/pathTo/devkitpro/devkitPPC/bin/powerpc-gekko-gcc --host=ppc --without-zlib --enable-singleThreaded RANLIB=/pathTo/devkitpro/devkitPPC/bin/powerpc-gekko-ranlib CFLAGS="-DDEVKITPRO -DGEKKO" + +For linking purposes you'll need + +LDFLAGS="-g -mrvl -mcpu=750 -meabi -mhard-float -Wl,-Map,$(notdir $@).map" + +For general build instructions see rc1 below. + + +********************CyaSSL Release Candidiate 1 rc1-1.0.0 (12/17/2008) + + +Release Candidate 1 for CyaSSL 1.0.0 contains major internal changes. Several +areas have optimization improvements, less dynamic memory use, and the I/O +strategy has been refactored to allow alternate I/O handling or Library use. +Many thanks to Thierry Fournier for providing these ideas and most of the work. + +Because of these changes, this release is only a candidate since some problems +are probably inevitable on some platform with some I/O use. Please report any +problems and we'll try to resolve them as soon as possible. You can contact us +at support@yassl.com or todd@yassl.com. + +Using TomsFastMath by passing --enable-fastmath to ./configure now uses assembly +on some platforms. This is new so please report any problems as every compiler, +mode, OS combination hasn't been tested. On ia32 all of the registers need to +be available so be sure to pass these options to CFLAGS: + +CFLAGS="-O3 -fomit-frame-pointer" + +OS X will also need -mdynamic-no-pic added to CFLAGS + +Also if you're building in shared mode for ia32 you'll need to pass options to +LDFLAGS as well on OS X: + +LDFLAGS=-Wl,-read_only_relocs,warning + +This gives warnings for some symbols but seems to work. + + +--To build on Linux, Solaris, *BSD, Mac OS X, or Cygwin: + + ./configure + make + + from the ./testsuite/ directory run ./testsuite + +to make a debug build: + + ./configure --enable-debug --disable-shared + make + + + +--To build on Win32 + +Choose (Re)Build All from the project workspace + +Run the testsuite program + + + + + +*************************CyaSSL version 0.9.9 (7/25/2008) + +This release of CyaSSL adds bug fixes, Pre-Shared Keys, over-rideable memory +handling, and optionally TomsFastMath. Thanks to Moisés Guimarães for the +work on TomsFastMath. + +To optionally use TomsFastMath pass --enable-fastmath to ./configure +Or define USE_FAST_MATH in each project from CyaSSL for MSVC. + +Please use the benchmark routine before and after to see the performance +difference, on some platforms the gains will be little but RSA encryption +always seems to be faster. On x86-64 machines with GCC the normal math library +may outperform the fast one when using CFLAGS=-m64 because TomsFastMath can't +yet use -m64 because of GCCs inability to do 128bit division. + + **** UPDATE GCC 4.2.1 can now do 128bit division *** + +See notes below (0.2.0) for complete build instructions. + + +****************CyaSSL version 0.9.8 (5/7/2008) + +This release of CyaSSL adds bug fixes, client side Diffie-Hellman, and better +socket handling. + +See notes below (0.2.0) for complete build instructions. + + +****************CyaSSL version 0.9.6 (1/31/2008) + +This release of CyaSSL adds bug fixes, increased session management, and a fix +for gnutls. + +See notes below (0.2.0) for complete build instructions. + + +****************CyaSSL version 0.9.0 (10/15/2007) + +This release of CyaSSL adds bug fixes, MSVC 2005 support, GCC 4.2 support, +IPV6 support and test, and new test certificates. + +See notes below (0.2.0) for complete build instructions. + + +****************CyaSSL version 0.8.0 (1/10/2007) + +This release of CyaSSL adds increased socket support, for non-blocking writes, +connects, and interrupted system calls. + +See notes below (0.2.0) for complete build instructions. + + +****************CyaSSL version 0.6.3 (10/30/2006) + +This release of CyaSSL adds debug logging to stderr to aid in the debugging of +CyaSSL on systems that may not provide the best support. + +If CyaSSL is built with debugging support then you need to call +CyaSSL_Debugging_ON() to turn logging on. + +On Unix use ./configure --enable-debug + +On Windows define DEBUG_CYASSL when building CyaSSL + + +To turn logging back off call CyaSSL_Debugging_OFF() + +See notes below (0.2.0) for complete build instructions. + + +*****************CyaSSL version 0.6.2 (10/29/2006) + +This release of CyaSSL adds TLS 1.1. + +Note that CyaSSL has certificate verification on by default, unlike OpenSSL. +To emulate OpenSSL behavior, you must call SSL_CTX_set_verify() with +SSL_VERIFY_NONE. In order to have full security you should never do this, +provide CyaSSL with the proper certificates to eliminate impostors and call +CyaSSL_check_domain_name() to prevent man in the middle attacks. + +See notes below (0.2.0) for build instructions. + +*****************CyaSSL version 0.6.0 (10/25/2006) + +This release of CyaSSL adds more SSL functions, better autoconf, nonblocking +I/O for accept, connect, and read. There is now an --enable-small configure +option that turns off TLS, AES, DES3, HMAC, and ERROR_STRINGS, see configure.in +for the defines. Note that TLS requires HMAC and AES requires TLS. + +See notes below (0.2.0) for build instructions. + + +*****************CyaSSL version 0.5.5 (09/27/2006) + +This mini release of CyaSSL adds better input processing through buffered input +and big message support. Added SSL_pending() and some sanity checks on user +settings. + +See notes below (0.2.0) for build instructions. + + +*****************CyaSSL version 0.5.0 (03/27/2006) + +This release of CyaSSL adds AES support and minor bug fixes. + +See notes below (0.2.0) for build instructions. + + +*****************CyaSSL version 0.4.0 (03/15/2006) + +This release of CyaSSL adds TLSv1 client/server support and libtool. + +See notes below for build instructions. + + +*****************CyaSSL version 0.3.0 (02/26/2006) + +This release of CyaSSL adds SSLv3 server support and session resumption. + +See notes below for build instructions. + + +*****************CyaSSL version 0.2.0 (02/19/2006) + + +This is the first release of CyaSSL and its crypt brother, CTaoCrypt. CyaSSL +is written in ANSI C with the idea of a small code size, footprint, and memory +usage in mind. CTaoCrypt can be as small as 32K, and the current client +version of CyaSSL can be as small as 12K. + + +The first release of CTaoCrypt supports MD5, SHA-1, 3DES, ARC4, Big Integer +Support, RSA, ASN parsing, and basic x509 (en/de)coding. + +The first release of CyaSSL supports normal client RSA mode SSLv3 connections +with support for SHA-1 and MD5 digests. Ciphers include 3DES and RC4. + + +--To build on Linux, Solaris, *BSD, Mac OS X, or Cygwin: + + ./configure + make + + from the ./testsuite/ directory run ./testsuite + +to make a debug build: + + ./configure --enable-debug --disable-shared + make + + + +--To build on Win32 + +Choose (Re)Build All from the project workspace + +Run the testsuite program + + + +*** The next release of CyaSSL will support a server and more OpenSSL +compatibility functions. + + +Please send questions or comments to todd@yassl.com + diff --git a/acx_pthread.m4 b/acx_pthread.m4 new file mode 100644 index 000000000..e4e91d3c9 --- /dev/null +++ b/acx_pthread.m4 @@ -0,0 +1,242 @@ +dnl @synopsis ACX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]]) +dnl +dnl @summary figure out how to build C programs using POSIX threads +dnl +dnl This macro figures out how to build C programs using POSIX threads. +dnl It sets the PTHREAD_LIBS output variable to the threads library and +dnl linker flags, and the PTHREAD_CFLAGS output variable to any special +dnl C compiler flags that are needed. (The user can also force certain +dnl compiler flags/libs to be tested by setting these environment +dnl variables.) +dnl +dnl Also sets PTHREAD_CC to any special C compiler that is needed for +dnl multi-threaded programs (defaults to the value of CC otherwise). +dnl (This is necessary on AIX to use the special cc_r compiler alias.) +dnl +dnl NOTE: You are assumed to not only compile your program with these +dnl flags, but also link it with them as well. e.g. you should link +dnl with $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS +dnl $LIBS +dnl +dnl If you are only building threads programs, you may wish to use +dnl these variables in your default LIBS, CFLAGS, and CC: +dnl +dnl LIBS="$PTHREAD_LIBS $LIBS" +dnl CFLAGS="$CFLAGS $PTHREAD_CFLAGS" +dnl CC="$PTHREAD_CC" +dnl +dnl In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute +dnl constant has a nonstandard name, defines PTHREAD_CREATE_JOINABLE to +dnl that name (e.g. PTHREAD_CREATE_UNDETACHED on AIX). +dnl +dnl ACTION-IF-FOUND is a list of shell commands to run if a threads +dnl library is found, and ACTION-IF-NOT-FOUND is a list of commands to +dnl run it if it is not found. If ACTION-IF-FOUND is not specified, the +dnl default action will define HAVE_PTHREAD. +dnl +dnl Please let the authors know if this macro fails on any platform, or +dnl if you have any other suggestions or comments. This macro was based +dnl on work by SGJ on autoconf scripts for FFTW (www.fftw.org) (with +dnl help from M. Frigo), as well as ac_pthread and hb_pthread macros +dnl posted by Alejandro Forero Cuervo to the autoconf macro repository. +dnl We are also grateful for the helpful feedback of numerous users. +dnl +dnl @category InstalledPackages +dnl @author Steven G. Johnson +dnl @version 2006-05-29 +dnl @license GPLWithACException + +AC_DEFUN([ACX_PTHREAD], [ +AC_REQUIRE([AC_CANONICAL_HOST]) +AC_LANG_SAVE +AC_LANG_C +acx_pthread_ok=no + +# We used to check for pthread.h first, but this fails if pthread.h +# requires special compiler flags (e.g. on True64 or Sequent). +# It gets checked for in the link test anyway. + +# First of all, check if the user has set any of the PTHREAD_LIBS, +# etcetera environment variables, and if threads linking works using +# them: +if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $PTHREAD_CFLAGS" + save_LIBS="$LIBS" + LIBS="$PTHREAD_LIBS $LIBS" + AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS]) + AC_TRY_LINK_FUNC(pthread_join, acx_pthread_ok=yes) + AC_MSG_RESULT($acx_pthread_ok) + if test x"$acx_pthread_ok" = xno; then + PTHREAD_LIBS="" + PTHREAD_CFLAGS="" + fi + LIBS="$save_LIBS" + CFLAGS="$save_CFLAGS" +fi + +# We must check for the threads library under a number of different +# names; the ordering is very important because some systems +# (e.g. DEC) have both -lpthread and -lpthreads, where one of the +# libraries is broken (non-POSIX). + +# Create a list of thread flags to try. Items starting with a "-" are +# C compiler flags, and other items are library names, except for "none" +# which indicates that we try without any flags at all, and "pthread-config" +# which is a program returning the flags for the Pth emulation library. + +acx_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config" + +# The ordering *is* (sometimes) important. Some notes on the +# individual items follow: + +# pthreads: AIX (must check this before -lpthread) +# none: in case threads are in libc; should be tried before -Kthread and +# other compiler flags to prevent continual compiler warnings +# -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h) +# -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able) +# lthread: LinuxThreads port on FreeBSD (also preferred to -pthread) +# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads) +# -pthreads: Solaris/gcc +# -mthreads: Mingw32/gcc, Lynx/gcc +# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it +# doesn't hurt to check since this sometimes defines pthreads too; +# also defines -D_REENTRANT) +# ... -mt is also the pthreads flag for HP/aCC +# pthread: Linux, etcetera +# --thread-safe: KAI C++ +# pthread-config: use pthread-config program (for GNU Pth library) + +case "${host_cpu}-${host_os}" in + *solaris*) + + # On Solaris (at least, for some versions), libc contains stubbed + # (non-functional) versions of the pthreads routines, so link-based + # tests will erroneously succeed. (We need to link with -pthreads/-mt/ + # -lpthread.) (The stubs are missing pthread_cleanup_push, or rather + # a function called by this macro, so we could check for that, but + # who knows whether they'll stub that too in a future libc.) So, + # we'll just look for -pthreads and -lpthread first: + + acx_pthread_flags="-pthreads pthread -mt -pthread $acx_pthread_flags" + ;; +esac + +if test x"$acx_pthread_ok" = xno; then +for flag in $acx_pthread_flags; do + + case $flag in + none) + AC_MSG_CHECKING([whether pthreads work without any flags]) + ;; + + -*) + AC_MSG_CHECKING([whether pthreads work with $flag]) + PTHREAD_CFLAGS="$flag" + ;; + + pthread-config) + AC_CHECK_PROG(acx_pthread_config, pthread-config, yes, no) + if test x"$acx_pthread_config" = xno; then continue; fi + PTHREAD_CFLAGS="`pthread-config --cflags`" + PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`" + ;; + + *) + AC_MSG_CHECKING([for the pthreads library -l$flag]) + PTHREAD_LIBS="-l$flag" + ;; + esac + + save_LIBS="$LIBS" + save_CFLAGS="$CFLAGS" + LIBS="$PTHREAD_LIBS $LIBS" + CFLAGS="$CFLAGS $PTHREAD_CFLAGS" + + # Check for various functions. We must include pthread.h, + # since some functions may be macros. (On the Sequent, we + # need a special flag -Kthread to make this header compile.) + # We check for pthread_join because it is in -lpthread on IRIX + # while pthread_create is in libc. We check for pthread_attr_init + # due to DEC craziness with -lpthreads. We check for + # pthread_cleanup_push because it is one of the few pthread + # functions on Solaris that doesn't have a non-functional libc stub. + # We try pthread_create on general principles. + AC_TRY_LINK([#include ], + [pthread_t th; pthread_join(th, 0); + pthread_attr_init(0); pthread_cleanup_push(0, 0); + pthread_create(0,0,0,0); pthread_cleanup_pop(0); ], + [acx_pthread_ok=yes]) + + LIBS="$save_LIBS" + CFLAGS="$save_CFLAGS" + + AC_MSG_RESULT($acx_pthread_ok) + if test "x$acx_pthread_ok" = xyes; then + break; + fi + + PTHREAD_LIBS="" + PTHREAD_CFLAGS="" +done +fi + +# Various other checks: +if test "x$acx_pthread_ok" = xyes; then + save_LIBS="$LIBS" + LIBS="$PTHREAD_LIBS $LIBS" + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $PTHREAD_CFLAGS" + + # Detect AIX lossage: JOINABLE attribute is called UNDETACHED. + AC_MSG_CHECKING([for joinable pthread attribute]) + attr_name=unknown + for attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do + AC_TRY_LINK([#include ], [int attr=$attr; return attr;], + [attr_name=$attr; break]) + done + AC_MSG_RESULT($attr_name) + if test "$attr_name" != PTHREAD_CREATE_JOINABLE; then + AC_DEFINE_UNQUOTED(PTHREAD_CREATE_JOINABLE, $attr_name, + [Define to necessary symbol if this constant + uses a non-standard name on your system.]) + fi + + AC_MSG_CHECKING([if more special flags are required for pthreads]) + flag=no + case "${host_cpu}-${host_os}" in + *-aix* | *-freebsd* | *-darwin*) flag="-D_THREAD_SAFE";; + *solaris* | *-osf* | *-hpux*) flag="-D_REENTRANT";; + esac + AC_MSG_RESULT(${flag}) + if test "x$flag" != xno; then + PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS" + fi + + LIBS="$save_LIBS" + CFLAGS="$save_CFLAGS" + + # More AIX lossage: must compile with xlc_r or cc_r + if test x"$GCC" != xyes; then + AC_CHECK_PROGS(PTHREAD_CC, xlc_r cc_r, ${CC}) + else + PTHREAD_CC=$CC + fi +else + PTHREAD_CC="$CC" +fi + +AC_SUBST(PTHREAD_LIBS) +AC_SUBST(PTHREAD_CFLAGS) +AC_SUBST(PTHREAD_CC) + +# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND: +if test x"$acx_pthread_ok" = xyes; then + ifelse([$1],,AC_DEFINE(HAVE_PTHREAD,1,[Define if you have POSIX threads libraries and header files.]),[$1]) + : +else + acx_pthread_ok=no + $2 +fi +AC_LANG_RESTORE +])dnl ACX_PTHREAD diff --git a/certs/ca-cert.pem b/certs/ca-cert.pem new file mode 100644 index 000000000..6a0cf898e --- /dev/null +++ b/certs/ca-cert.pem @@ -0,0 +1,56 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 8a:37:22:65:73:f5:aa:e8 + Signature Algorithm: md5WithRSAEncryption + Issuer: C=US, ST=Montana, L=Bozeman, O=sawtooth, OU=consulting, CN=www.sawtooth-consulting.com/emailAddress=info@yassl.com + Validity + Not Before: Jun 30 18:47:10 2010 GMT + Not After : Mar 26 18:47:10 2013 GMT + Subject: C=US, ST=Montana, L=Bozeman, O=sawtooth, OU=consulting, CN=www.sawtooth-consulting.com/emailAddress=info@yassl.com + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public Key: (512 bit) + Modulus (512 bit): + 00:97:30:b9:1a:92:ef:25:4f:ca:4c:11:31:95:1a: + e1:c0:10:19:0a:20:b9:37:80:1a:57:38:02:4e:1b: + c5:0f:28:4f:da:e3:c9:16:aa:50:bd:4a:fb:b7:71: + c7:35:cc:63:81:c1:dd:9d:33:f9:38:16:88:32:a0: + aa:56:23:03:a3 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Subject Key Identifier: + 3B:66:FD:A0:40:C6:F4:E2:70:CF:21:1A:0C:4F:67:FE:B7:4B:42:09 + X509v3 Authority Key Identifier: + keyid:3B:66:FD:A0:40:C6:F4:E2:70:CF:21:1A:0C:4F:67:FE:B7:4B:42:09 + DirName:/C=US/ST=Montana/L=Bozeman/O=sawtooth/OU=consulting/CN=www.sawtooth-consulting.com/emailAddress=info@yassl.com + serial:8A:37:22:65:73:F5:AA:E8 + + X509v3 Basic Constraints: + CA:TRUE + Signature Algorithm: md5WithRSAEncryption + 32:65:a2:b1:dc:6d:e0:8d:8b:c8:58:29:8e:b8:18:4b:62:88: + 13:67:f8:6c:75:46:75:8f:8a:19:a6:a3:d5:3c:fc:57:4e:7a: + 68:a9:fc:93:dc:ae:29:7d:bb:4e:ec:ea:55:fa:a4:e3:00:61: + f4:b0:34:6d:d1:d5:a4:64:24:f8 +-----BEGIN CERTIFICATE----- +MIIDQDCCAuqgAwIBAgIJAIo3ImVz9aroMA0GCSqGSIb3DQEBBAUAMIGeMQswCQYD +VQQGEwJVUzEQMA4GA1UECBMHTW9udGFuYTEQMA4GA1UEBxMHQm96ZW1hbjERMA8G +A1UEChMIc2F3dG9vdGgxEzARBgNVBAsTCmNvbnN1bHRpbmcxJDAiBgNVBAMTG3d3 +dy5zYXd0b290aC1jb25zdWx0aW5nLmNvbTEdMBsGCSqGSIb3DQEJARYOaW5mb0B5 +YXNzbC5jb20wHhcNMTAwNjMwMTg0NzEwWhcNMTMwMzI2MTg0NzEwWjCBnjELMAkG +A1UEBhMCVVMxEDAOBgNVBAgTB01vbnRhbmExEDAOBgNVBAcTB0JvemVtYW4xETAP +BgNVBAoTCHNhd3Rvb3RoMRMwEQYDVQQLEwpjb25zdWx0aW5nMSQwIgYDVQQDExt3 +d3cuc2F3dG9vdGgtY29uc3VsdGluZy5jb20xHTAbBgkqhkiG9w0BCQEWDmluZm9A +eWFzc2wuY29tMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAJcwuRqS7yVPykwRMZUa +4cAQGQoguTeAGlc4Ak4bxQ8oT9rjyRaqUL1K+7dxxzXMY4HB3Z0z+TgWiDKgqlYj +A6MCAwEAAaOCAQcwggEDMB0GA1UdDgQWBBQ7Zv2gQMb04nDPIRoMT2f+t0tCCTCB +0wYDVR0jBIHLMIHIgBQ7Zv2gQMb04nDPIRoMT2f+t0tCCaGBpKSBoTCBnjELMAkG +A1UEBhMCVVMxEDAOBgNVBAgTB01vbnRhbmExEDAOBgNVBAcTB0JvemVtYW4xETAP +BgNVBAoTCHNhd3Rvb3RoMRMwEQYDVQQLEwpjb25zdWx0aW5nMSQwIgYDVQQDExt3 +d3cuc2F3dG9vdGgtY29uc3VsdGluZy5jb20xHTAbBgkqhkiG9w0BCQEWDmluZm9A +eWFzc2wuY29tggkAijciZXP1qugwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQQF +AANBADJlorHcbeCNi8hYKY64GEtiiBNn+Gx1RnWPihmmo9U8/FdOemip/JPcril9 +u07s6lX6pOMAYfSwNG3R1aRkJPg= +-----END CERTIFICATE----- diff --git a/certs/ca-key.der b/certs/ca-key.der new file mode 100644 index 0000000000000000000000000000000000000000..879f52771c8927193f9d6932add97e8ca2866fb3 GIT binary patch literal 317 zcmXqLVzgvpWMFb+m~OCBYSMdE|5HAKhEt^;9uSb^QrKzUAQf)Gn_fu$Z*7Z?}K-iod2Ze%@4eE zBX4H^g_T)Olhwr-;aI!In zvaks=g$5h)8}NcS9Kvk=MXBled4_@p{2&2#VUB?OqLQ4%yc9z|10IkNmoRH(VsNmJ zp@@MHh|ev|T~L&tUX+-do0*qxC}to65@i zGcPUQ0WNJIC(dhVU|?o!U}#}%X>1uK&TD9FU~FUt;+hyl4L%3QAO|TUD+9APgMkN= zBg5W6FOk1lk}W*O7Jt-@=1k}QvqT~x)9>buiU97H3bEH@3uJgy<|{Xyv0}VBU3^n< zPTTpdAD^Df;JLX-$g<{BFcUK)1LNYxZw8H@4P@DvLuL6`#8^aPzH2IGR&iF$t3Dg- z#PsHzCa>UqgT})kd1aQy-3E<28nCKa*f?cLD+&oNF-$X-Mmo|!2MDo_L^*g43Elu z<)$-Mj8~_NZz|4dJHPeg({mX-Hx~(6)_e+PVrFDuWO4{eyrviQaM|kX8yv;CzAlte z)0o%a^|96MoWv|!l`FSn=X14apXkYnWol!ya4ns=_k~&5@~5%??!WsXCt0~_#!n_i zh6gUS8*@u%EqU^CcCNHw$S3QcZE8DrNL)4buv@uNmXDW7k>Q5aWhakw`PECAzs$7u zlUH@inY}sTdt#W3QI6}%JD&HM6d9IDZqZ5++UmQqGkv*3^1F*+3WopYP1t9>+3@N4 zppCJvOo|LA<=G@`bF>zVYuDHapPT*r^XF#?X@MqxCWu$Yov=}jXHsNnoWmrRo6wSz dmeo*kyN&6A;XU5R_04w*R7!peJ+?La4gg-NiTMBk literal 0 HcmV?d00001 diff --git a/certs/client-key.pem b/certs/client-key.pem new file mode 100644 index 000000000..92c052fef --- /dev/null +++ b/certs/client-key.pem @@ -0,0 +1,9 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIBPAIBAAJBAL1RShT9ahmEDDM4/CcynJcL/KQYYGlO2dh4UAvpIF3WHXAcDCSf +I4LMOgHVlxeyc2yGz7Xx5c5oDNmiEjl88lMCAwEAAQJAVGHWLlLhpqvXsEEXCvWh +HCYono+K8YVGzhiaPSTU212fCoQryIxsXQKGBjhFdZm96DZWp+Vd/t/u+B4ZeaqY ++QIhAOBEfbFtdZqk5OmbbRsRVPI7+YYmubgY1TVIPqmxHQ4NAiEA2BrTQkjOb3ul +A/SZO04fJUZsm7Ng92FWHDJsRancSd8CIQCmGbQqZBK1TamJZ6dAY+7RViAx/p6Q +vjuzMeXPUrFdRQIhAMkfBhg9bCqjFyt8PBPOm/vz8+ZgZlE0/JAXeV7IPCVfAiEA +gZwCFm1ghGxmaoB424YC4DHeDeN/g9xwJHT7EuM9Mvc= +-----END RSA PRIVATE KEY----- diff --git a/certs/client-keyEnc.pem b/certs/client-keyEnc.pem new file mode 100644 index 000000000..0097c0760 --- /dev/null +++ b/certs/client-keyEnc.pem @@ -0,0 +1,12 @@ +-----BEGIN RSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: DES-EDE3-CBC,BDE979D13CCC0ABD + +N7yz2JV13EmQ7MZPL5wamid5+G1V1gp8FKqMemAC5JDxonS/W9oViMLUcxbfPTDx +FznKdYSVTIQ7vv3ofmDG4MEyV/2C568N2kdtAw+jTfrZFN+IU9CI+W+In/nacirF +02sAcvDMofustnooKNOO7/iyb5+3vRvEt5vSSRQn5WuSQ9sUKjuzoLs/lbf7fyAt +4NeqfI3rYBZXxiUOLITOGXzGNRuFoY+o2uDCfelLAJ8uhiVG6ME3LeJEo1dT5lZ8 +CSJOLPasKg0iG4V7olM4j9FvAfZr48RRsSfUen756Jo2HpI4bad8LKhFYIdNs2Au +WwKLmjpo6QB9hBmRshR04rEXPdrgTqLBExCE08PyaGYnWU8ggWritCeBzDQFj/n4 +sI+NO0Mymuvg98e5RpO52lg3Xnqv9RIK3guLFOmI6aEHC0PS4WwOEQ== +-----END RSA PRIVATE KEY----- diff --git a/certs/dh1024.der b/certs/dh1024.der new file mode 100644 index 0000000000000000000000000000000000000000..09f81ee14c1433f2976ecbd6f005f08bab148fc9 GIT binary patch literal 138 zcmXqLY-eh0WO&RIpi(vaiNK1>U5){(4{hE5JSj!i_12xBeL{`SVY8o9l->#0e&rB< zmvwp2T#tmwDe_Gxo8o5)PG8hjtbU>CAitF4;)(lzJgYlA<%RFec-=P(W%t)?y0FQv xSiJ4j^q}$!CsTeaF1xm5jEv-8Cxob(RKGTU*0*)|2dIM zb@nGk#;miedd#1nO1mBQg}=7yqQp+8ztVzCq6}+QHCJ=Z=af0PmRX^!e%bcBzRa9V z4niF>Z#}=jJ$d%CcQ%Ukb2e}3UE1@=yun`lVx#}w4~5%|I7063XMD7|oGqoai{)CS z zIS!?8ncckQ6VFGRz5T4xG@)^UZD->7JYNO8eJo1x`yHu@{Lem^HyPW#M;#IlS=!;coypIO$tn{@U2R?pVk88&|F7*w7aBN3olDCKvd-=bS}AR!jxWAZ$hp*};m zCFAqVe`1kKk}ajgp66~bCR^TDkT)oav3qFpZbs>+-H3;Ef)FzM`3l?eL_MmN)UKYkD& zn;BrgEcJP4V~5MM>31bR7O*53tKfSfdxc(~XI#Dh#{FCCR2i2R7~HsKvt!Pq1hWln`@c(j zM84pTT`FyOwSASxy|Z!?%>U;Zt10~5aL?(<=ERTVh+MOmJooJ#ozBya!w8 z%d3f(BQF;yT client-key.pem + +2) openssl req -new -x509 -nodes -md5 -days 1000 -key client-key.pem > client-cert.pem + +3) note sha1 would be -sha1 + +-- adding metadata to beginning + +3) openssl x509 -in client-cert.pem -text > tmp.pem + +4) mv tmp.pem client-cert.pem + + +***** Create a CA, signing authority ********** + +same as self signed, use ca prefix instead of client + + +***** Create a cert signed by CA ************** + +1) openssl req -newkey rsa:512 -md5 -days 1000 -nodes -keyout server-key.pem > server-req.pem + +* note if using exisitng key do: -new -key keyName + +2) copy ca-key.pem ca-cert.srl (why ????) + +3) openssl x509 -req -in server-req.pem -days 1000 -md5 -CA ca-cert.pem -CAkey ca-key.pem -set_serial 01 > server-cert.pem + + + +***** To create a dsa cert ******************** + +1) openssl dsaparam 512 > dsa512.param # creates group params + +2) openssl gendsa dsa512.param > dsa512.pem # creates private key + +3) openssl req -new -x509 -nodes -days 1000 -key dsa512.pem > dsa-cert.pem + + + + +***** To convert from PEM to DER ************** + +a) openssl x509 -in cert.pem -inform PEM -out cert.der -outform DER + +to convert rsa private PEM to DER : + +b) openssl rsa -in key.pem -outform DER -out key.der + + +**** To encrypt rsa key already in pem ********** + +a) openssl rsa server-keyEnc.pem + +note location of des, pass = yassl123 + + +*** To make a public key from a private key ****** + + +openssl rsa -in 1024rsa.priv -pubout -out 1024rsa.pub + + +**** To convert to pkcs8 ******* + +openssl pkcs8 -nocrypt -topk8 -in server-key.pem -out server-keyPkcs8.pem + + +**** To convert from pkcs8 to traditional **** + +openssl pkcs8 -nocrypt -in server-keyPkcs8.pem -out server-key.pem + + +**** ECC ****** + +1) make a key + + to see types available do + openssl ecparam -list_curves + + make a new key + openssl ecparam -genkey -text -name secp256r1 -out ecc-key.pem + diff --git a/configure.in b/configure.in new file mode 100644 index 000000000..a6802c984 --- /dev/null +++ b/configure.in @@ -0,0 +1,431 @@ +AC_INIT +AC_CANONICAL_SYSTEM +AM_INIT_AUTOMAKE(cyassl,1.8.8) +AM_CONFIG_HEADER(ctaocrypt/include/config.h) + + +dnl Include m4 +sinclude(lib_socket_nsl.m4) +sinclude(acx_pthread.m4) + + +# make sure configure doesn't add to CFLAGS +CFLAGS="$CFLAGS $C_EXTRA_FLAGS" + +AC_PROG_CC +AC_PROG_CC_C_O +AM_PROG_AS +AC_PROG_INSTALL +AC_LIBTOOL_WIN32_DLL +AC_PROG_LIBTOOL + +AC_PREFIX_DEFAULT(/usr/local/cyassl) + +AC_C_BIGENDIAN + +AC_CHECK_SIZEOF(long, 4) +AC_CHECK_SIZEOF(long long, 8) + +AC_CHECK_LIB(network,socket) +AC_CHECK_LIBM + +AC_CHECK_HEADERS(errno.h) + +OPTIMIZE_CFLAGS="-Os -fomit-frame-pointer" +OPTIMIZE_FAST_CFLAGS="-O3 -fomit-frame-pointer" +OPTIMIZE_HUGE_CFLAGS="-funroll-loops -DTFM_SMALL_SET" +DEBUG_CFLAGS="-g -DDEBUG -DDEBUG_CYASSL" + + +# DEBUG +AC_ARG_ENABLE(debug, + [ --enable-debug Enable CyaSSL debugging support (default: disabled)], + [ ENABLED_DEBUG=$enableval ], + [ ENABLED_DEBUG=no ] + ) +if test "$ENABLED_DEBUG" = "yes" +then + # Full debug. Very slow in some cases + CFLAGS="$DEBUG_CFLAGS $CFLAGS" +else + # Optimized version. No debug + CFLAGS="$CFLAGS -DNDEBUG" +fi + + +# SMALL BUILD +AC_ARG_ENABLE(small, + [ --enable-small Enable smallest build (default: disabled)], + [ ENABLED_SMALL=$enableval ], + [ ENABLED_SMALL=no ] + ) +if test "$ENABLED_SMALL" = "yes" +then + # make small no tls build with smallest cipher + # if you only want server or client you can define NO_CYASSL_SERVER or + # NO_CYASSL_CLIENT but then some of the examples and testsuite won't build + # note that TLS needs HMAC + CFLAGS="-DNO_TLS -DNO_HMAC -DNO_AES -DNO_DES3 -DNO_SHA256 -DNO_ERROR_STRINGS -DNO_HC128 -DNO_RABBIT -DNO_PSK -DNO_DSA -DNO_DH $CFLAGS" +fi + + +# SINGLE THREADED +AC_ARG_ENABLE(singleThreaded, + [ --enable-singleThreaded Enable CyaSSL single threaded (default: disabled)], + [ ENABLED_SINGLETHREADED=$enableval ], + [ ENABLED_SINGLETHREADED=no ] + ) +if test "$ENABLED_SINGLETHREADED" = "yes" +then + CFLAGS="-DSINGLE_THREADED $CFLAGS" +fi + + +# DTLS +AC_ARG_ENABLE(dtls, + [ --enable-dtls Enable CyaSSL DTLS (default: disabled)], + [ ENABLED_DTLS=$enableval ], + [ ENABLED_DTLS=no ] + ) +if test "$ENABLED_DTLS" = "yes" +then + CFLAGS="-DCYASSL_DTLS $CFLAGS" +fi + + +# OPENSSL Extra Compatibility +AC_ARG_ENABLE(opensslExtra, + [ --enable-opensslExtra Enable extra OpenSSL API, size+ (default: disabled)], + [ ENABLED_OPENSSLEXTRA=$enableval ], + [ ENABLED_OPENSSLEXTRA=no ] + ) +if test "$ENABLED_OPENSSLEXTRA" = "yes" +then + CFLAGS="-DOPENSSL_EXTRA $CFLAGS" +fi + + +# IPv6 Test Apps +AC_ARG_ENABLE(ipv6, + [ --enable-ipv6 Enable testing of IPV6 (default: disabled)], + [ ENABLED_IPV6=$enableval ], + [ ENABLED_IPV6=no ] + ) + +if test "$ENABLED_IPV6" = "yes" +then + CFLAGS="$CFLAGS -DTEST_IPV6" +fi + + +# fastmath +AC_ARG_ENABLE(fastmath, + [ --enable-fastmath Enable fast math for BigInts(default: disabled)], + [ ENABLED_FASTMATH=$enableval ], + [ ENABLED_FASTMATH=no ] + ) + +if test "$ENABLED_FASTMATH" = "yes" +then + CFLAGS="$CFLAGS -DUSE_FAST_MATH" +fi + + +# fast HUGE math +AC_ARG_ENABLE(fasthugemath, + [ --enable-fasthugemath Enable fast math + huge code for BigInts(def: off)], + [ ENABLED_FASTHUGEMATH=$enableval ], + [ ENABLED_FASTHUGEMATH=no ] + ) + +if test "$ENABLED_FASTHUGEMATH" = "yes" +then + ENABLED_FASTMATH="yes" + CFLAGS="$CFLAGS -DUSE_FAST_MATH" +fi + +AM_CONDITIONAL([BUILD_FASTMATH], [test "x$ENABLED_FASTMATH" = "xyes"]) + + +# big cache +AC_ARG_ENABLE(bigcache, + [ --enable-bigcache Enable big session cache (default: disabled)], + [ ENABLED_BIGCACHE=$enableval ], + [ ENABLED_BIGCACHE=no ] + ) + +if test "$ENABLED_BIGCACHE" = "yes" +then + CFLAGS="$CFLAGS -DBIG_SESSION_CACHE" +fi + + +# HUGE cache +AC_ARG_ENABLE(hugecache, + [ --enable-hugecache Enable huge session cache (default: disabled)], + [ ENABLED_HUGECACHE=$enableval ], + [ ENABLED_HUGECACHE=no ] + ) + +if test "$ENABLED_HUGECACHE" = "yes" +then + CFLAGS="$CFLAGS -DHUGE_SESSION_CACHE" +fi + + +# SNIFFER +AC_ARG_ENABLE(sniffer, + [ --enable-sniffer Enable CyaSSL sniffer support (default: disabled)], + [ ENABLED_SNIFFER=$enableval ], + [ ENABLED_SNIFFER=no ] + ) + +if test "$ENABLED_SNIFFER" = "yes" +then + CFLAGS="$CFLAGS -DCYASSL_SNIFFER -DOPENSSL_EXTRA" +fi + +AM_CONDITIONAL([BUILD_SNIFFER], [test "x$ENABLED_SNIFFER" = "xyes"]) + +# AES-NI +AC_ARG_ENABLE(aesni, + [ --enable-aesni Enable CyaSSL AES-NI support (default: disabled)], + [ ENABLED_AESNI=$enableval ], + [ ENABLED_AESNI=no ] + ) + +if test "$ENABLED_AESNI" = "yes" +then + CFLAGS="$CFLAGS -DCYASSL_AESNI" + if test "$GCC" = "yes" + then + # GCC needs these flags, icc doesn't + CFLAGS="$CFLAGS -maes -msse4" + fi +fi + +AM_CONDITIONAL([BUILD_AESNI], [test "x$ENABLED_AESNI" = "xyes"]) + + +# RIPEMD +AC_ARG_ENABLE(ripemd, + [ --enable-ripemd Enable CyaSSL RIPEMD-160 support (default: disabled)], + [ ENABLED_RIPEMD=$enableval ], + [ ENABLED_RIPEMD=no ] + ) + +if test "$ENABLED_RIPEMD" = "yes" +then + CFLAGS="$CFLAGS -DCYASSL_RIPEMD" +fi + +AM_CONDITIONAL([BUILD_RIPEMD], [test "x$ENABLED_RIPEMD" = "xyes"]) + + +# SHA512 +AC_ARG_ENABLE(sha512, + [ --enable-sha512 Enable CyaSSL SHA-160 support (default: disabled)], + [ ENABLED_SHA512=$enableval ], + [ ENABLED_SHA512=no ] + ) + +if test "$ENABLED_SHA512" = "yes" +then + CFLAGS="$CFLAGS -DCYASSL_SHA512" +fi + +AM_CONDITIONAL([BUILD_SHA512], [test "x$ENABLED_SHA512" = "xyes"]) + + +# SESSION CERTS +AC_ARG_ENABLE(sessioncerts, + [ --enable-sessioncerts Enable session cert storing (default: disabled)], + [ ENABLED_SESSIONCERTS=$enableval ], + [ ENABLED_SESSIONCERTS=no ] + ) + +if test "$ENABLED_SESSIONCERTS" = "yes" +then + CFLAGS="$CFLAGS -DSESSION_CERTS" +fi + + +# KEY GENERATION +AC_ARG_ENABLE(keygen, + [ --enable-keygen Enable key generation (default: disabled)], + [ ENABLED_KEYGEN=$enableval ], + [ ENABLED_KEYGEN=no ] + ) + +if test "$ENABLED_KEYGEN" = "yes" +then + CFLAGS="$CFLAGS -DCYASSL_KEY_GEN" +fi + + +# CERT GENERATION +AC_ARG_ENABLE(certgen, + [ --enable-certgen Enable cert generation (default: disabled)], + [ ENABLED_CERTGEN=$enableval ], + [ ENABLED_CERTGEN=no ] + ) + +if test "$ENABLED_CERTGEN" = "yes" +then + CFLAGS="$CFLAGS -DCYASSL_CERT_GEN" +fi + + +# HC128 +AC_ARG_ENABLE(hc128, + [ --enable-hc128 Enable HC-128 (default: disabled)], + [ ENABLED_HC128=$enableval ], + [ ENABLED_HC128=no ] + ) + +if test "$ENABLED_HC128" = "no" +then + CFLAGS="$CFLAGS -DNO_HC128" +fi + +AM_CONDITIONAL([BUILD_HC128], [test "x$ENABLED_HC128" = "xyes"]) + + +# PSK +AC_ARG_ENABLE(psk, + [ --enable-psk Enable PSK (default: disabled)], + [ ENABLED_PSK=$enableval ], + [ ENABLED_PSK=no ] + ) + +if test "$ENABLED_PSK" = "no" +then + CFLAGS="$CFLAGS -DNO_PSK" +fi + + +# ECC +AC_ARG_ENABLE(ecc, + [ --enable-ecc Enable ECC (default: disabled)], + [ ENABLED_ECC=$enableval ], + [ ENABLED_ECC=no ] + ) + +if test "$ENABLED_ECC" = "yes" +then + CFLAGS="$CFLAGS -DHAVE_ECC" +fi + +AM_CONDITIONAL([BUILD_ECC], [test "x$ENABLED_ECC" = "xyes"]) + + +# NTRU +ntruHome=`pwd`/NTRU_algorithm +ntruInclude=$ntruHome/cryptolib +ntruLib=$ntruHome +AC_ARG_ENABLE(ntru, + [ --enable-ntru Enable NTRU (default: disabled)], + [ ENABLED_NTRU=$enableval ], + [ ENABLED_NTRU=no ] + ) + +if test "$ENABLED_NTRU" = "yes" +then + CFLAGS="$CFLAGS -DHAVE_NTRU -I$ntruInclude" + LDFLAGS="$LDFLAGS -L$ntruLib" + LIBS="$LIBS -lntru_encrypt" +fi + +AM_CONDITIONAL([BUILD_NTRU], [test "x$ENABLED_NTRU" = "xyes"]) + + +# LIBZ +trylibzdir="" +AC_ARG_WITH(libz, + [ --with-libz=PATH PATH to libz install (default /usr/) ], + [ + AC_MSG_CHECKING([for libz]) + CPPFLAGS="$CPPFLAGS -DHAVE_LIBZ" + LIBS="$LIBS -lz" + + AC_TRY_LINK([#include ], [ deflateInit(NULL, 8); ], + [ libz_linked=yes ], [ libz_linked=no ]) + + if test "x$libz_linked" == "xno" ; then + if test "x$withval" != "xno" ; then + trylibzdir=$withval + fi + if test "x$withval" == "xyes" ; then + trylibzdir="/usr" + fi + + LDFLAGS="$LDFLAGS -L$trylibzdir/lib" + CPPFLAGS="$CPPFLAGS -I$trylibzdir/include" + + AC_TRY_LINK([#include ], [ deflateInit(NULL, 8); ], + [ libz_linked=yes ], [ libz_linked=no ]) + + if test "x$libz_linked" == "xno" ; then + AC_MSG_ERROR([libz isn't found. + If it's already installed, specify its path using --with-libz=/dir/]) + fi + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([yes]) + fi + + ] +) + + +# OPTIMIZE FLAGS +if test "$GCC" = "yes" +then + CFLAGS="$CFLAGS -Wall -Wno-unused" + if test "$ENABLED_DEBUG" = "no" + then + if test "$ENABLED_FASTMATH" = "yes" + then + CFLAGS="$CFLAGS $OPTIMIZE_FAST_CFLAGS" + if test "$ENABLED_FASTHUGEMATH" = "yes" + then + CFLAGS="$CFLAGS $OPTIMIZE_HUGE_CFLAGS" + fi + else + CFLAGS="$CFLAGS $OPTIMIZE_CFLAGS" + fi + fi +fi + + + + +ACX_PTHREAD + +LIBS="$PTHREAD_LIBS $LIBM $LIBS" +CFLAGS="$CFLAGS $PTHREAD_CFLAGS" + +LIB_SOCKET_NSL + +AC_SUBST(CFLAGS) +AC_SUBST(LIBS) + + + +# FINAL +AC_CONFIG_FILES(Makefile dnl + ctaocrypt/Makefile dnl + ctaocrypt/src/Makefile dnl + ctaocrypt/test/Makefile dnl + ctaocrypt/benchmark/Makefile dnl + src/Makefile dnl + examples/Makefile dnl + examples/client/Makefile dnl + examples/server/Makefile dnl + examples/echoclient/Makefile dnl + examples/echoserver/Makefile dnl + testsuite/Makefile dnl + sslSniffer/Makefile dnl + sslSniffer/sslSnifferTest/Makefile) +AC_OUTPUT + diff --git a/ctaocrypt/Makefile.am b/ctaocrypt/Makefile.am new file mode 100644 index 000000000..e36e5bc82 --- /dev/null +++ b/ctaocrypt/Makefile.am @@ -0,0 +1,3 @@ +SUBDIRS = src test benchmark +EXTRA_DIST = ctaocrypt.sln ctaocrypt.vcproj + diff --git a/ctaocrypt/benchmark/Makefile.am b/ctaocrypt/benchmark/Makefile.am new file mode 100644 index 000000000..80f1c9326 --- /dev/null +++ b/ctaocrypt/benchmark/Makefile.am @@ -0,0 +1,7 @@ +INCLUDES = -I../include +bin_PROGRAMS = benchmark +benchmark_SOURCES = benchmark.c +benchmark_LDFLAGS = -L../src +benchmark_LDADD = ../../src/libcyassl.la +benchmark_DEPENDENCIES = ../../src/libcyassl.la +EXTRA_DIST = *.der benchmark.sln benchmark.vcproj diff --git a/ctaocrypt/benchmark/benchmark.c b/ctaocrypt/benchmark/benchmark.c new file mode 100644 index 000000000..9e0170abc --- /dev/null +++ b/ctaocrypt/benchmark/benchmark.c @@ -0,0 +1,538 @@ +/* benchmark.c */ +/* CTaoCrypt benchmark */ + +#include +#include + +#include "des3.h" +#include "arc4.h" +#include "hc128.h" +#include "rabbit.h" +#include "ctc_aes.h" +#include "ctc_md5.h" +#include "ctc_sha.h" +#include "sha256.h" +#include "sha512.h" +#include "ctc_rsa.h" +#include "asn.h" +#include "ctc_ripemd.h" + +#include "ctc_dh.h" + + +#ifdef _MSC_VER + /* 4996 warning to use MS extensions e.g., strcpy_s instead of strncpy */ + #pragma warning(disable: 4996) +#endif + +void bench_des(); +void bench_arc4(); +void bench_hc128(); +void bench_rabbit(); +void bench_aes(int); + +void bench_md5(); +void bench_sha(); +void bench_sha256(); +void bench_sha512(); +void bench_ripemd(); + +void bench_rsa(); +void bench_rsaKeyGen(); +void bench_dh(); + +double current_time(); + + + +int main(int argc, char** argv) +{ +#ifndef NO_AES + bench_aes(0); + bench_aes(1); +#endif + bench_arc4(); +#ifndef NO_HC128 + bench_hc128(); +#endif +#ifndef NO_RABBIT + bench_rabbit(); +#endif +#ifndef NO_DES3 + bench_des(); +#endif + + printf("\n"); + + bench_md5(); + bench_sha(); +#ifndef NO_SHA256 + bench_sha256(); +#endif +#ifdef CYASSL_SHA512 + bench_sha512(); +#endif +#ifdef CYASSL_RIPEMD + bench_ripemd(); +#endif + + printf("\n"); + + bench_rsa(); + +#ifndef NO_DH + bench_dh(); +#endif + +#ifdef CYASSL_KEY_GEN + bench_rsaKeyGen(); +#endif + + return 0; +} + +const int megs = 5; /* how many megs to test (en/de)cryption */ +const int times = 100; /* public key iterations */ + +const byte key[] = +{ + 0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef, + 0xfe,0xde,0xba,0x98,0x76,0x54,0x32,0x10, + 0x89,0xab,0xcd,0xef,0x01,0x23,0x45,0x67 +}; + +const byte iv[] = +{ + 0x12,0x34,0x56,0x78,0x90,0xab,0xcd,0xef, + 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, + 0x11,0x21,0x31,0x41,0x51,0x61,0x71,0x81 + +}; + + +byte plain [1024*1024]; +byte cipher[1024*1024]; + + +#ifndef NO_AES +void bench_aes(int show) +{ + Aes enc; + double start, total, persec; + int i; + + AesSetKey(&enc, key, 16, iv, AES_ENCRYPTION); + start = current_time(); + + for(i = 0; i < megs; i++) + AesCbcEncrypt(&enc, plain, cipher, sizeof(plain)); + + total = current_time() - start; + + persec = 1 / total * megs; + + if (show) + printf("AES %d megs took %5.3f seconds, %6.2f MB/s\n", megs, total, + persec); +} +#endif + + +#ifndef NO_DES3 +void bench_des() +{ + Des3 enc; + double start, total, persec; + int i; + + Des3_SetKey(&enc, key, iv, DES_ENCRYPTION); + start = current_time(); + + for(i = 0; i < megs; i++) + Des3_CbcEncrypt(&enc, plain, cipher, sizeof(plain)); + + total = current_time() - start; + + persec = 1 / total * megs; + + printf("3DES %d megs took %5.3f seconds, %6.2f MB/s\n", megs, total, + persec); +} +#endif + + +void bench_arc4() +{ + Arc4 enc; + double start, total, persec; + int i; + + Arc4SetKey(&enc, key, 16); + start = current_time(); + + for(i = 0; i < megs; i++) + Arc4Process(&enc, cipher, plain, sizeof(plain)); + + total = current_time() - start; + persec = 1 / total * megs; + + printf("ARC4 %d megs took %5.3f seconds, %6.2f MB/s\n", megs, total, + persec); +} + + +#ifndef NO_HC128 +void bench_hc128() +{ + HC128 enc; + double start, total, persec; + int i; + + Hc128_SetKey(&enc, key, iv); + start = current_time(); + + for(i = 0; i < megs; i++) + Hc128_Process(&enc, cipher, plain, sizeof(plain)); + + total = current_time() - start; + persec = 1 / total * megs; + + printf("HC128 %d megs took %5.3f seconds, %6.2f MB/s\n", megs, total, + persec); +} +#endif /* NO_HC128 */ + + +#ifndef NO_RABBIT +void bench_rabbit() +{ + Rabbit enc; + double start, total, persec; + int i; + + RabbitSetKey(&enc, key, iv); + start = current_time(); + + for(i = 0; i < megs; i++) + RabbitProcess(&enc, cipher, plain, sizeof(plain)); + + total = current_time() - start; + persec = 1 / total * megs; + + printf("RABBIT %d megs took %5.3f seconds, %6.2f MB/s\n", megs, total, + persec); +} +#endif /* NO_RABBIT */ + + +void bench_md5() +{ + Md5 hash; + byte digest[MD5_DIGEST_SIZE]; + double start, total, persec; + int i; + + InitMd5(&hash); + start = current_time(); + + for(i = 0; i < megs; i++) + Md5Update(&hash, plain, sizeof(plain)); + + Md5Final(&hash, digest); + + total = current_time() - start; + persec = 1 / total * megs; + + printf("MD5 %d megs took %5.3f seconds, %6.2f MB/s\n", megs, total, + persec); +} + + +void bench_sha() +{ + Sha hash; + byte digest[SHA_DIGEST_SIZE]; + double start, total, persec; + int i; + + InitSha(&hash); + start = current_time(); + + for(i = 0; i < megs; i++) + ShaUpdate(&hash, plain, sizeof(plain)); + + ShaFinal(&hash, digest); + + total = current_time() - start; + persec = 1 / total * megs; + + printf("SHA %d megs took %5.3f seconds, %6.2f MB/s\n", megs, total, + persec); +} + + +#ifndef NO_SHA256 +void bench_sha256() +{ + Sha256 hash; + byte digest[SHA256_DIGEST_SIZE]; + double start, total, persec; + int i; + + InitSha256(&hash); + start = current_time(); + + for(i = 0; i < megs; i++) + Sha256Update(&hash, plain, sizeof(plain)); + + Sha256Final(&hash, digest); + + total = current_time() - start; + persec = 1 / total * megs; + + printf("SHA-256 %d megs took %5.3f seconds, %6.2f MB/s\n", megs, total, + persec); +} +#endif + +#ifdef CYASSL_SHA512 +void bench_sha512() +{ + Sha512 hash; + byte digest[SHA512_DIGEST_SIZE]; + double start, total, persec; + int i; + + InitSha512(&hash); + start = current_time(); + + for(i = 0; i < megs; i++) + Sha512Update(&hash, plain, sizeof(plain)); + + Sha512Final(&hash, digest); + + total = current_time() - start; + persec = 1 / total * megs; + + printf("SHA-512 %d megs took %5.3f seconds, %6.2f MB/s\n", megs, total, + persec); +} +#endif + +#ifdef CYASSL_RIPEMD +void bench_ripemd() +{ + RipeMd hash; + byte digest[RIPEMD_DIGEST_SIZE]; + double start, total, persec; + int i; + + InitRipeMd(&hash); + start = current_time(); + + for(i = 0; i < megs; i++) + RipeMdUpdate(&hash, plain, sizeof(plain)); + + RipeMdFinal(&hash, digest); + + total = current_time() - start; + persec = 1 / total * megs; + + printf("RIPEMD %d megs took %5.3f seconds, %6.2f MB/s\n", megs, total, + persec); +} +#endif + + +RNG rng; + +void bench_rsa() +{ + int i; + byte tmp[4096]; + size_t bytes; + word32 idx = 0; + + byte message[] = "Everyone gets Friday off."; + byte cipher[512]; /* for up to 4096 bit */ + byte* output; + const int len = (int)strlen((char*)message); + double start, total, each, milliEach; + + RsaKey key; + FILE* file = fopen("./rsa1024.der", "rb"); + + if (!file) { + printf("can't find ./rsa1024.der\n"); + return; + } + + InitRng(&rng); + bytes = fread(tmp, 1, sizeof(tmp), file); + InitRsaKey(&key, 0); + bytes = RsaPrivateKeyDecode(tmp, &idx, &key, (word32)bytes); + + start = current_time(); + + for (i = 0; i < times; i++) + bytes = RsaPublicEncrypt(message,len,cipher,sizeof(cipher), &key, &rng); + + total = current_time() - start; + each = total / times; /* per second */ + milliEach = each * 1000; /* milliseconds */ + + printf("RSA 1024 encryption took %6.2f milliseconds, avg over %d" + " iterations\n", milliEach, times); + + start = current_time(); + + for (i = 0; i < times; i++) + RsaPrivateDecryptInline(cipher, (word32)bytes, &output, &key); + + total = current_time() - start; + each = total / times; /* per second */ + milliEach = each * 1000; /* milliseconds */ + + printf("RSA 1024 decryption took %6.2f milliseconds, avg over %d" + " iterations\n", milliEach, times); + + fclose(file); + FreeRsaKey(&key); +} + + +#ifndef NO_DH +void bench_dh() +{ + int i; + byte tmp[1024]; + size_t bytes; + word32 idx = 0, pubSz, privSz, pubSz2, privSz2, agreeSz; + + byte pub[128]; /* for 1024 bit */ + byte priv[128]; /* for 1024 bit */ + byte pub2[128]; /* for 1024 bit */ + byte priv2[128]; /* for 1024 bit */ + byte agree[128]; /* for 1024 bit */ + + double start, total, each, milliEach; + DhKey key; + FILE* file = fopen("./dh1024.der", "rb"); + + if (!file) { + printf("can't find ./dh1024.der\n"); + return; + } + + bytes = fread(tmp, 1, 1024, file); + InitDhKey(&key); + bytes = DhKeyDecode(tmp, &idx, &key, (word32)bytes); + + start = current_time(); + + for (i = 0; i < times; i++) + DhGenerateKeyPair(&key, &rng, priv, &privSz, pub, &pubSz); + + total = current_time() - start; + each = total / times; /* per second */ + milliEach = each * 1000; /* milliseconds */ + + printf("DH 1024 key generation %6.2f milliseconds, avg over %d" + " iterations\n", milliEach, times); + + DhGenerateKeyPair(&key, &rng, priv2, &privSz2, pub2, &pubSz2); + start = current_time(); + + for (i = 0; i < times; i++) + DhAgree(&key, agree, &agreeSz, priv, privSz, pub2, pubSz2); + + total = current_time() - start; + each = total / times; /* per second */ + milliEach = each * 1000; /* milliseconds */ + + printf("DH 1024 key agreement %6.2f milliseconds, avg over %d" + " iterations\n", milliEach, times); + + fclose(file); + FreeDhKey(&key); +} +#endif + +#ifdef CYASSL_KEY_GEN +void bench_rsaKeyGen() +{ + RsaKey genKey; + double start, total, each, milliEach; + int i; + const int genTimes = 5; + + /* 1024 bit */ + start = current_time(); + + for(i = 0; i < genTimes; i++) { + InitRsaKey(&genKey, 0); + MakeRsaKey(&genKey, 1024, 65537, &rng); + FreeRsaKey(&genKey); + } + + total = current_time() - start; + each = total / genTimes; /* per second */ + milliEach = each * 1000; /* millisconds */ + printf("\n"); + printf("RSA 1024 key generation %6.2f milliseconds, avg over %d" + " iterations\n", milliEach, genTimes); + + /* 2048 bit */ + start = current_time(); + + for(i = 0; i < genTimes; i++) { + InitRsaKey(&genKey, 0); + MakeRsaKey(&genKey, 2048, 65537, &rng); + FreeRsaKey(&genKey); + } + + total = current_time() - start; + each = total / genTimes; /* per second */ + milliEach = each * 1000; /* millisconds */ + printf("RSA 2048 key generation %6.2f milliseconds, avg over %d" + " iterations\n", milliEach, genTimes); +} +#endif /* CYASSL_KEY_GEN */ + + +#ifdef _WIN32 + + #define WIN32_LEAN_AND_MEAN + #include + + double current_time() + { + static int init = 0; + static LARGE_INTEGER freq; + + LARGE_INTEGER count; + + if (!init) { + QueryPerformanceFrequency(&freq); + init = 1; + } + + QueryPerformanceCounter(&count); + + return (double)count.QuadPart / freq.QuadPart; + } + +#else + + #include + + double current_time() + { + struct timeval tv; + gettimeofday(&tv, 0); + + return (double)tv.tv_sec + (double)tv.tv_usec / 1000000; + } + +#endif /* _WIN32 */ + diff --git a/ctaocrypt/benchmark/benchmark.sln b/ctaocrypt/benchmark/benchmark.sln new file mode 100755 index 000000000..e3e9483b8 --- /dev/null +++ b/ctaocrypt/benchmark/benchmark.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual C++ Express 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "benchmark", "benchmark.vcproj", "{615AEC46-5595-4DEA-9490-DBD5DE0F8772}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {615AEC46-5595-4DEA-9490-DBD5DE0F8772}.Debug|Win32.ActiveCfg = Debug|Win32 + {615AEC46-5595-4DEA-9490-DBD5DE0F8772}.Debug|Win32.Build.0 = Debug|Win32 + {615AEC46-5595-4DEA-9490-DBD5DE0F8772}.Release|Win32.ActiveCfg = Release|Win32 + {615AEC46-5595-4DEA-9490-DBD5DE0F8772}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/ctaocrypt/benchmark/benchmark.vcproj b/ctaocrypt/benchmark/benchmark.vcproj new file mode 100755 index 000000000..5db23c372 --- /dev/null +++ b/ctaocrypt/benchmark/benchmark.vcproj @@ -0,0 +1,195 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ctaocrypt/benchmark/dh1024.der b/ctaocrypt/benchmark/dh1024.der new file mode 100644 index 0000000000000000000000000000000000000000..09f81ee14c1433f2976ecbd6f005f08bab148fc9 GIT binary patch literal 138 zcmXqLY-eh0WO&RIpi(vaiNK1>U5){(4{hE5JSj!i_12xBeL{`SVY8o9l->#0e&rB< zmvwp2T#tmwDe_Gxo8o5)PG8hjtbU>CAitF4;)(lzJgYlA<%RFec-=P(W%t)?y0FQv xSiJ4j^q}$!CsTeaF1xm5jEv-8Cxob;FLv$oQf!m`}>9G2%M zyvGG3)UwmtMb~^vQ0VVIrX;Go)w6hs-xKrwA$xkhB@VpS-8G{vuJ?UD6Ehif1Cf3`ITz#$)6MF?!J3(YV7_s2g`+nIFfd5l>ePD**-Oh zaS~&n@(jJo5c8jNURGH9zi`c8kz;n}!RE(Xw>cf(w^YNX-Dx`0q|NtcHOvZNIC{kY z^LoWy`HIgt&enC@s;{!!o5m+ENUp%W=`k(mG4NFedT>8r7 z$Z&TZ+f1K6i%UB~j?WaIDE!e}iTlT7tHaazx^B+aS#f8ALgc%RSL8ZudPEl(-|IW` zM#s;l%J>WKrb)eJ%Eh`$!AuS{LSCm?J)b5_W9`mb;3vf@@^Q)B6&t5*R@7n{VNZT;D>+jCTyPQx##)40~6an W+pO9UZ)U#c*v7`Rv?BA1i7x;c#~z*l literal 0 HcmV?d00001 diff --git a/ctaocrypt/ctaocrypt.sln b/ctaocrypt/ctaocrypt.sln new file mode 100755 index 000000000..f2154d0d0 --- /dev/null +++ b/ctaocrypt/ctaocrypt.sln @@ -0,0 +1,38 @@ + +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual C++ Express 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ctaocrypt", "ctaocrypt.vcproj", "{BF0EA0C1-3F4C-4767-B79E-7B2A391F7D62}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test", "test\test.vcproj", "{D04BDF66-664A-4D59-BEAC-8AB2D5809C21}" + ProjectSection(ProjectDependencies) = postProject + {BF0EA0C1-3F4C-4767-B79E-7B2A391F7D62} = {BF0EA0C1-3F4C-4767-B79E-7B2A391F7D62} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "benchmark", "benchmark\benchmark.vcproj", "{615AEC46-5595-4DEA-9490-DBD5DE0F8772}" + ProjectSection(ProjectDependencies) = postProject + {BF0EA0C1-3F4C-4767-B79E-7B2A391F7D62} = {BF0EA0C1-3F4C-4767-B79E-7B2A391F7D62} + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {BF0EA0C1-3F4C-4767-B79E-7B2A391F7D62}.Debug|Win32.ActiveCfg = Debug|Win32 + {BF0EA0C1-3F4C-4767-B79E-7B2A391F7D62}.Debug|Win32.Build.0 = Debug|Win32 + {BF0EA0C1-3F4C-4767-B79E-7B2A391F7D62}.Release|Win32.ActiveCfg = Release|Win32 + {BF0EA0C1-3F4C-4767-B79E-7B2A391F7D62}.Release|Win32.Build.0 = Release|Win32 + {D04BDF66-664A-4D59-BEAC-8AB2D5809C21}.Debug|Win32.ActiveCfg = Debug|Win32 + {D04BDF66-664A-4D59-BEAC-8AB2D5809C21}.Debug|Win32.Build.0 = Debug|Win32 + {D04BDF66-664A-4D59-BEAC-8AB2D5809C21}.Release|Win32.ActiveCfg = Release|Win32 + {D04BDF66-664A-4D59-BEAC-8AB2D5809C21}.Release|Win32.Build.0 = Release|Win32 + {615AEC46-5595-4DEA-9490-DBD5DE0F8772}.Debug|Win32.ActiveCfg = Debug|Win32 + {615AEC46-5595-4DEA-9490-DBD5DE0F8772}.Debug|Win32.Build.0 = Debug|Win32 + {615AEC46-5595-4DEA-9490-DBD5DE0F8772}.Release|Win32.ActiveCfg = Release|Win32 + {615AEC46-5595-4DEA-9490-DBD5DE0F8772}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/ctaocrypt/ctaocrypt.vcproj b/ctaocrypt/ctaocrypt.vcproj new file mode 100755 index 000000000..26ba69662 --- /dev/null +++ b/ctaocrypt/ctaocrypt.vcproj @@ -0,0 +1,323 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ctaocrypt/include/arc4.h b/ctaocrypt/include/arc4.h new file mode 100644 index 000000000..1ffff6f35 --- /dev/null +++ b/ctaocrypt/include/arc4.h @@ -0,0 +1,56 @@ +/* arc4.h + * + * Copyright (C) 2006-2011 Sawtooth Consulting Ltd. + * + * This file is part of CyaSSL. + * + * CyaSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * CyaSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + + +#ifndef CTAO_CRYPT_ARC4_H +#define CTAO_CRYPT_ARC4_H + + +#include "types.h" + + +#ifdef __cplusplus + extern "C" { +#endif + + +enum { + ARC4_STATE_SIZE = 256 +}; + +/* ARC4 encryption and decryption */ +typedef struct Arc4 { + byte x; + byte y; + byte state[ARC4_STATE_SIZE]; +} Arc4; + +void Arc4Process(Arc4*, byte*, const byte*, word32); +void Arc4SetKey(Arc4*, const byte*, word32); + + +#ifdef __cplusplus + } /* extern "C" */ +#endif + + +#endif /* CTAO_CRYPT_ARC4_H */ + diff --git a/ctaocrypt/include/asn.h b/ctaocrypt/include/asn.h new file mode 100644 index 000000000..4623da953 --- /dev/null +++ b/ctaocrypt/include/asn.h @@ -0,0 +1,319 @@ +/* asn.h + * + * Copyright (C) 2006-2011 Sawtooth Consulting Ltd. + * + * This file is part of CyaSSL. + * + * CyaSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * CyaSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + + +#ifndef CTAO_CRYPT_ASN_H +#define CTAO_CRYPT_ASN_H + +#include "types.h" +#include "ctc_rsa.h" +#include "ctc_dh.h" +#include "ctc_dsa.h" +#include "ctc_sha.h" +#ifdef HAVE_ECC + #include "ctc_ecc.h" +#endif + +#ifdef __cplusplus + extern "C" { +#endif + + +enum { + ISSUER = 0, + SUBJECT = 1, + + BEFORE = 0, + AFTER = 1 +}; + +/* ASN Tags */ +enum ASN_Tags { + ASN_INTEGER = 0x02, + ASN_BIT_STRING = 0x03, + ASN_OCTET_STRING = 0x04, + ASN_TAG_NULL = 0x05, + ASN_OBJECT_ID = 0x06, + ASN_SEQUENCE = 0x10, + ASN_SET = 0x11, + ASN_UTC_TIME = 0x17, + ASN_GENERALIZED_TIME = 0x18, + ASN_LONG_LENGTH = 0x80 +}; + + +enum ASN_Flags{ + ASN_CONSTRUCTED = 0x20, + ASN_CONTEXT_SPECIFIC = 0x80 +}; + +enum DN_Tags { + ASN_COMMON_NAME = 0x03, /* CN */ + ASN_SUR_NAME = 0x04, /* SN */ + ASN_COUNTRY_NAME = 0x06, /* C */ + ASN_LOCALITY_NAME = 0x07, /* L */ + ASN_STATE_NAME = 0x08, /* ST */ + ASN_ORG_NAME = 0x0a, /* O */ + ASN_ORGUNIT_NAME = 0x0b /* OU */ +}; + +enum Misc_ASN { + ASN_NAME_MAX = 256, + SHA_SIZE = 20, + RSA_INTS = 8, /* RSA ints in private key */ + MIN_DATE_SIZE = 13, + MAX_DATE_SIZE = 32, + ASN_GEN_TIME_SZ = 15, /* 7 numbers * 2 + Zulu tag */ + MAX_ENCODED_SIG_SZ = 512, + MAX_SIG_SZ = 256, + MAX_ALGO_SZ = 20, + MAX_SEQ_SZ = 5, /* enum(seq | con) + length(4) */ + MAX_SET_SZ = 5, /* enum(set | con) + length(4) */ + MAX_VERSION_SZ = 5, /* enum + id + version(byte) + (header(2))*/ + MAX_ENCODED_DIG_SZ = 25, /* sha + enum(bit or octet) + legnth(4) */ + MAX_RSA_INT_SZ = 517, /* RSA raw sz 4096 for bits + tag + len(4) */ + MAX_NTRU_KEY_SZ = 610, /* NTRU 112 bit public key */ + MAX_NTRU_ENC_SZ = 628, /* NTRU 112 bit DER public encoding */ + MAX_RSA_E_SZ = 16, /* Max RSA public e size */ + MAX_PUBLIC_KEY_SZ = MAX_NTRU_ENC_SZ + MAX_ALGO_SZ + MAX_SEQ_SZ * 2, + /* use bigger NTRU size */ + MAX_LENGTH_SZ = 4 +}; + + +enum Oid_Types { + hashType = 0, + sigType = 1, + keyType = 2 +}; + + +enum Sig_Sum { + SHAwDSA = 517, + MD2wRSA = 646, + MD5wRSA = 648, + SHAwRSA = 649, + SHAwECDSA = 520 +}; + +enum Hash_Sum { + MD2h = 646, + MD5h = 649, + SHAh = 88 +}; + +enum Key_Sum { + DSAk = 515, + RSAk = 645, + NTRUk = 364, + ECDSAk = 518 +}; + +enum Ecc_Sum { + ECC_256R1 = 526, + ECC_384R1 = 210, + ECC_521R1 = 211, + ECC_160R1 = 184, + ECC_192R1 = 520, + ECC_224R1 = 209 +}; + + +/* Certificate file Type */ +enum CertType { + CERT_TYPE = 0, + PRIVATEKEY_TYPE, + CA_TYPE +}; + + +enum VerifyType { + NO_VERIFY = 0, + VERIFY = 1 +}; + + +typedef struct DecodedCert { + byte* publicKey; + word32 pubKeySize; + int pubKeyStored; + word32 certBegin; /* offset to start of cert */ + word32 sigIndex; /* offset to start of signature */ + word32 sigLength; /* length of signature */ + word32 signatureOID; /* sum of algorithm object id */ + word32 keyOID; /* sum of key algo object id */ + byte subjectHash[SHA_SIZE]; /* hash of all Names */ + byte issuerHash[SHA_SIZE]; /* hash of all Names */ + byte* signature; /* not owned, points into raw cert */ + char* subjectCN; /* CommonName */ + int subjectCNLen; + char issuer[ASN_NAME_MAX]; /* full name including common name */ + char subject[ASN_NAME_MAX]; /* full name including common name */ + int verify; /* Default to yes, but could be off */ + byte* source; /* byte buffer holder cert, NOT owner */ + word32 srcIdx; /* current offset into buffer */ + void* heap; /* for user memory overrides */ +#ifdef CYASSL_CERT_GEN + /* easy access to sujbect info for other sign */ + char* subjectSN; + int subjectSNLen; + char* subjectC; + int subjectCLen; + char* subjectL; + int subjectLLen; + char* subjectST; + int subjectSTLen; + char* subjectO; + int subjectOLen; + char* subjectOU; + int subjectOULen; + char* subjectEmail; + int subjectEmailLen; +#endif /* CYASSL_CERT_GEN */ +} DecodedCert; + + +typedef struct Signer Signer; + +/* CA Signers */ +struct Signer { + byte* publicKey; + word32 pubKeySize; + word32 keyOID; /* key type */ + char* name; /* common name */ + byte hash[SHA_DIGEST_SIZE]; /* sha hash of names in certificate */ + Signer* next; +}; + + +void InitDecodedCert(DecodedCert*, byte*, void*); +void FreeDecodedCert(DecodedCert*); +int ParseCert(DecodedCert*, word32, int type, int verify, Signer* signer); +int ParseCertRelative(DecodedCert*, word32, int type, int verify, + Signer* signer); + +word32 EncodeSignature(byte* out, const byte* digest, word32 digSz,int hashOID); + +Signer* MakeSigner(void*); +void FreeSigners(Signer*, void*); + + +int RsaPrivateKeyDecode(const byte* input, word32* inOutIdx, RsaKey*, word32); +int RsaPublicKeyDecode(const byte* input, word32* inOutIdx, RsaKey*, word32); +int ToTraditional(byte* buffer, word32 length); + +#ifndef NO_DH +int DhKeyDecode(const byte* input, word32* inOutIdx, DhKey* key, word32); +int DhSetKey(DhKey* key, const byte* p, word32 pSz, const byte* g, word32 gSz); +#endif + +#ifndef NO_DSA +int DsaPublicKeyDecode(const byte* input, word32* inOutIdx, DsaKey*, word32); +int DsaPrivateKeyDecode(const byte* input, word32* inOutIdx, DsaKey*, word32); +#endif + +#ifdef CYASSL_KEY_GEN +int RsaKeyToDer(RsaKey*, byte* output, word32 inLen); +#endif + +#ifdef HAVE_ECC + /* ASN sig helpers */ + int StoreECC_DSA_Sig(byte* out, word32* outLen, mp_int* r, mp_int* s); + int DecodeECC_DSA_Sig(const byte* sig, word32 sigLen, mp_int* r, mp_int* s); + /* private key helpers */ + int EccPrivateKeyDecode(const byte* input,word32* inOutIdx,ecc_key*,word32); +#endif + +#if defined(CYASSL_KEY_GEN) || defined(CYASSL_CERT_GEN) +int DerToPem(const byte* der, word32 derSz, byte* output, word32 outputSz, + int type); +#endif + +#ifdef CYASSL_CERT_GEN + +enum cert_enums { + SERIAL_SIZE = 8, + NAME_SIZE = 64, + NAME_ENTRIES = 8, + JOINT_LEN = 2, + EMAIL_JOINT_LEN = 9, + RSA_KEY = 10, + NTRU_KEY = 11 +}; + + +typedef struct CertName { + char country[NAME_SIZE]; + char state[NAME_SIZE]; + char locality[NAME_SIZE]; + char sur[NAME_SIZE]; + char org[NAME_SIZE]; + char unit[NAME_SIZE]; + char commonName[NAME_SIZE]; + char email[NAME_SIZE]; /* !!!! email has to be last !!!! */ +} CertName; + + +/* for user to fill for certificate generation */ +typedef struct Cert { + int version; /* x509 version */ + byte serial[SERIAL_SIZE]; /* serial number */ + int sigType; /* signature algo type */ + CertName issuer; /* issuer info */ + int daysValid; /* validity days */ + int selfSigned; /* self signed flag */ + CertName subject; /* subject info */ + /* internal use only */ + int bodySz; /* pre sign total size */ + int keyType; /* public key type of subject */ +} Cert; + + +/* Initialize and Set Certficate defaults: + version = 3 (0x2) + serial = 0 (Will be randomly generated) + sigType = MD5_WITH_RSA + issuer = blank + daysValid = 500 + selfSigned = 1 (true) use subject as issuer + subject = blank + keyType = RSA_KEY (default) +*/ +void InitCert(Cert*); +int MakeCert(Cert*, byte* derBuffer, word32 derSz, RsaKey*, RNG*); +int SignCert(Cert*, byte* derBuffer, word32 derSz, RsaKey*, RNG*); +int MakeSelfCert(Cert*, byte* derBuffer, word32 derSz, RsaKey*, RNG*); +int SetIssuer(Cert*, const char*); +#ifdef HAVE_NTRU +int MakeNtruCert(Cert*, byte* derBuffer, word32 derSz, const byte* ntruKey, + word16 keySz, RNG*); +#endif + + +#endif /* CYASSL_CERT_GEN */ + + +#ifdef __cplusplus + } /* extern "C" */ +#endif + +#endif /* CTAO_CRYPT_ASN_H */ + diff --git a/ctaocrypt/include/coding.h b/ctaocrypt/include/coding.h new file mode 100644 index 000000000..454a3e028 --- /dev/null +++ b/ctaocrypt/include/coding.h @@ -0,0 +1,47 @@ +/* coding.h + * + * Copyright (C) 2006-2011 Sawtooth Consulting Ltd. + * + * This file is part of CyaSSL. + * + * CyaSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * CyaSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + + +#ifndef CTAO_CRYPT_CODING_H +#define CTAO_CRYPT_CODING_H + +#include "types.h" + +#ifdef __cplusplus + extern "C" { +#endif + + +/* decode needed by CyaSSL */ +int Base64Decode(const byte* in, word32 inLen, byte* out, word32* outLen); + +#if defined(OPENSSL_EXTRA) || defined(SESSION_CERTS) || defined(CYASSL_KEY_GEN) || defined(CYASSL_CERT_GEN) + /* encode isn't */ + int Base64Encode(const byte* in, word32 inLen, byte* out, word32* outLen); + int Base16Decode(const byte* in, word32 inLen, byte* out, word32* outLen); +#endif + +#ifdef __cplusplus + } /* extern "C" */ +#endif + +#endif /* CTAO_CRYPT_CODING_H */ + diff --git a/ctaocrypt/include/config.h b/ctaocrypt/include/config.h new file mode 100644 index 000000000..1a294f5bb --- /dev/null +++ b/ctaocrypt/include/config.h @@ -0,0 +1,86 @@ +/* ctaocrypt/include/config.h. Generated from config.h.in by configure. */ +/* ctaocrypt/include/config.h.in. Generated from configure.in by autoheader. */ + +/* Define to 1 if you have the header file. */ +#define HAVE_DLFCN_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_ERRNO_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the `network' library (-lnetwork). */ +/* #undef HAVE_LIBNETWORK */ + +/* Define to 1 if you have the header file. */ +#define HAVE_MEMORY_H 1 + +/* Define if you have POSIX threads libraries and header files. */ +#define HAVE_PTHREAD 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_UNISTD_H 1 + +/* Define to the sub-directory in which libtool stores uninstalled libraries. + */ +#define LT_OBJDIR ".libs/" + +/* Define to 1 if your C compiler doesn't accept -c and -o together. */ +/* #undef NO_MINUS_C_MINUS_O */ + +/* Name of package */ +#define PACKAGE "cyassl" + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "" + +/* Define to necessary symbol if this constant uses a non-standard name on + your system. */ +/* #undef PTHREAD_CREATE_JOINABLE */ + +/* The size of `long', as computed by sizeof. */ +#define SIZEOF_LONG 8 + +/* The size of `long long', as computed by sizeof. */ +#define SIZEOF_LONG_LONG 8 + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Version number of package */ +#define VERSION "1.8.8" + +/* Define to 1 if your processor stores words with the most significant byte + first (like Motorola and SPARC, unlike Intel and VAX). */ +/* #undef WORDS_BIGENDIAN */ diff --git a/ctaocrypt/include/config.h.in b/ctaocrypt/include/config.h.in new file mode 100644 index 000000000..4a3601353 --- /dev/null +++ b/ctaocrypt/include/config.h.in @@ -0,0 +1,85 @@ +/* ctaocrypt/include/config.h.in. Generated from configure.in by autoheader. */ + +/* Define to 1 if you have the header file. */ +#undef HAVE_DLFCN_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_ERRNO_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_INTTYPES_H + +/* Define to 1 if you have the `network' library (-lnetwork). */ +#undef HAVE_LIBNETWORK + +/* Define to 1 if you have the header file. */ +#undef HAVE_MEMORY_H + +/* Define if you have POSIX threads libraries and header files. */ +#undef HAVE_PTHREAD + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDINT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDLIB_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRINGS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRING_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_STAT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TYPES_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_UNISTD_H + +/* Define to the sub-directory in which libtool stores uninstalled libraries. + */ +#undef LT_OBJDIR + +/* Define to 1 if your C compiler doesn't accept -c and -o together. */ +#undef NO_MINUS_C_MINUS_O + +/* Name of package */ +#undef PACKAGE + +/* Define to the address where bug reports for this package should be sent. */ +#undef PACKAGE_BUGREPORT + +/* Define to the full name of this package. */ +#undef PACKAGE_NAME + +/* Define to the full name and version of this package. */ +#undef PACKAGE_STRING + +/* Define to the one symbol short name of this package. */ +#undef PACKAGE_TARNAME + +/* Define to the version of this package. */ +#undef PACKAGE_VERSION + +/* Define to necessary symbol if this constant uses a non-standard name on + your system. */ +#undef PTHREAD_CREATE_JOINABLE + +/* The size of `long', as computed by sizeof. */ +#undef SIZEOF_LONG + +/* The size of `long long', as computed by sizeof. */ +#undef SIZEOF_LONG_LONG + +/* Define to 1 if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* Version number of package */ +#undef VERSION + +/* Define to 1 if your processor stores words with the most significant byte + first (like Motorola and SPARC, unlike Intel and VAX). */ +#undef WORDS_BIGENDIAN diff --git a/ctaocrypt/include/ctc_aes.h b/ctaocrypt/include/ctc_aes.h new file mode 100644 index 000000000..64fc7426e --- /dev/null +++ b/ctaocrypt/include/ctc_aes.h @@ -0,0 +1,84 @@ +/* ctc_aes.h + * + * Copyright (C) 2006-2011 Sawtooth Consulting Ltd. + * + * This file is part of CyaSSL. + * + * CyaSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * CyaSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#ifndef NO_AES + +#ifndef CTAO_CRYPT_AES_H +#define CTAO_CRYPT_AES_H + + +#include "types.h" + +#ifdef CYASSL_AESNI + +#include + +#if !defined (ALIGN16) + #if defined (__GNUC__) + #define ALIGN16 __attribute__ ( (aligned (16))) + #elif defined(_MSC_VER) + #define ALIGN16 __declspec (align (16)) + #else + #define ALIGN16 + #endif +#endif + +#endif /* CYASSL_AESNI */ + +#if !defined (ALIGN16) + #define ALIGN16 +#endif + +#ifdef __cplusplus + extern "C" { +#endif + + +enum { + AES_ENCRYPTION = 0, + AES_DECRYPTION = 1, + AES_BLOCK_SIZE = 16 +}; + + +typedef struct Aes { + /* AESNI needs key first, rounds 2nd, not sure why yet */ + ALIGN16 word32 key[60]; + word32 rounds; + + ALIGN16 word32 reg[AES_BLOCK_SIZE / sizeof(word32)]; /* for CBC mode */ + ALIGN16 word32 tmp[AES_BLOCK_SIZE / sizeof(word32)]; /* same */ +} Aes; + + +int AesSetKey(Aes* aes, const byte* key, word32 len, const byte* iv, int dir); +void AesCbcEncrypt(Aes* aes, byte* out, const byte* in, word32 sz); +void AesCbcDecrypt(Aes* aes, byte* out, const byte* in, word32 sz); + + +#ifdef __cplusplus + } /* extern "C" */ +#endif + + +#endif /* CTAO_CRYPT_AES_H */ +#endif /* NO_AES */ + diff --git a/ctaocrypt/include/ctc_dh.h b/ctaocrypt/include/ctc_dh.h new file mode 100644 index 000000000..f94b6d720 --- /dev/null +++ b/ctaocrypt/include/ctc_dh.h @@ -0,0 +1,59 @@ +/* ctc_dh.h + * + * Copyright (C) 2006-2011 Sawtooth Consulting Ltd. + * + * This file is part of CyaSSL. + * + * CyaSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * CyaSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#ifndef NO_DH + +#ifndef CTAO_CRYPT_DH_H +#define CTAO_CRYPT_DH_H + +#include "types.h" +#include "integer.h" +#include "random.h" + +#ifdef __cplusplus + extern "C" { +#endif + + + +/* Diffie-Hellman Key */ +typedef struct DhKey { + mp_int p, g; /* group parameters */ +} DhKey; + + +void InitDhKey(DhKey* key); +void FreeDhKey(DhKey* key); + +int DhGenerateKeyPair(DhKey* key, RNG* rng, byte* priv, word32* privSz, + byte* pub, word32* pubSz); +int DhAgree(DhKey* key, byte* agree, word32* agreeSz, const byte* priv, + word32 privSz, const byte* otherPub, word32 pubSz); + + +#ifdef __cplusplus + } /* extern "C" */ +#endif + +#endif /* CTAO_CRYPT_DH_H */ + +#endif /* NO_DH */ + diff --git a/ctaocrypt/include/ctc_dsa.h b/ctaocrypt/include/ctc_dsa.h new file mode 100644 index 000000000..1779e2097 --- /dev/null +++ b/ctaocrypt/include/ctc_dsa.h @@ -0,0 +1,61 @@ +/* ctc_dsa.h + * + * Copyright (C) 2006-2011 Sawtooth Consulting Ltd. + * + * This file is part of CyaSSL. + * + * CyaSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * CyaSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#ifndef NO_DSA + +#ifndef CTAO_CRYPT_DSA_H +#define CTAO_CRYPT_DSA_H + +#include "types.h" +#include "integer.h" +#include "random.h" + +#ifdef __cplusplus + extern "C" { +#endif + + +enum { + DSA_PUBLIC = 0, + DSA_PRIVATE = 1 +}; + +/* DSA */ +typedef struct DsaKey { + mp_int p, q, g, y, x; + int type; /* public or private */ +} DsaKey; + + +void InitDsaKey(DsaKey* key); +void FreeDsaKey(DsaKey* key); + +int DsaSign(const byte* digest, byte* out, DsaKey* key, RNG* rng); +int DsaVerify(const byte* digest, const byte* sig, DsaKey* key, int* answer); + + +#ifdef __cplusplus + } /* extern "C" */ +#endif + +#endif /* CTAO_CRYPT_DSA_H */ +#endif /* NO_DSA */ + diff --git a/ctaocrypt/include/ctc_ecc.h b/ctaocrypt/include/ctc_ecc.h new file mode 100644 index 000000000..207a96c41 --- /dev/null +++ b/ctaocrypt/include/ctc_ecc.h @@ -0,0 +1,119 @@ +/* ctc_ecc.h + * + * Copyright (C) 2006-2011 Sawtooth Consulting Ltd. + * + * This file is part of CyaSSL. + * + * CyaSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * CyaSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#ifdef HAVE_ECC + +#ifndef CTAO_CRYPT_ECC_H +#define CTAO_CRYPT_ECC_H + +#include "types.h" +#include "integer.h" +#include "random.h" + +#ifdef __cplusplus + extern "C" { +#endif + + +enum { + ECC_PUBLICKEY = 1, + ECC_PRIVATEKEY = 2, + ECC_MAXNAME = 16, /* MAX CURVE NAME LENGTH */ + SIG_HEADER_SZ = 6, /* ECC signature header size */ + ECC_BUFSIZE = 256, /* for exported keys temp buffer */ + ECC_MAXSIZE = 66 /* MAX Private Key size */ +}; + + +/* ECC set type defined a NIST GF(p) curve */ +typedef struct { + int size; /* The size of the curve in octets */ + char* name; /* name of this curve */ + char* prime; /* prime that defines the field the curve is in (hex) */ + char* B; /* fields B param (hex) */ + char* order; /* order of the curve (hex) */ + char* Gx; /* x coordinate of the base point on curve (hex) */ + char* Gy; /* y coordinate of the base point on curve (hex) */ +} ecc_set_type; + + +/* A point on an ECC curve, stored in Jacbobian format such that (x,y,z) => + (x/z^2, y/z^3, 1) when interpreted as affine */ +typedef struct { + mp_int x; /* The x coordinate */ + mp_int y; /* The y coordinate */ + mp_int z; /* The z coordinate */ +} ecc_point; + +/* An ECC Key */ +typedef struct { + int type; /* Public or Private */ + int idx; /* Index into the ecc_sets[] for the parameters of + this curve if -1, this key is using user supplied + curve in dp */ + const ecc_set_type* dp; /* domain parameters, either points to NIST + curves (idx >= 0) or user supplied */ + ecc_point pubkey; /* public key */ + mp_int k; /* private key */ +} ecc_key; + + +/* ECC predefined curve sets */ +extern const ecc_set_type ecc_sets[]; + + +int ecc_make_key(RNG* rng, int keysize, ecc_key* key); +int ecc_shared_secret(ecc_key* private_key, ecc_key* public_key, byte* out, + word32* outlen); + +int ecc_sign_hash(const byte* in, word32 inlen, byte* out, word32 *outlen, + RNG* rng, ecc_key* key); +int ecc_verify_hash(const byte* sig, word32 siglen, byte* hash, word32 hashlen, + int* stat, ecc_key* key); + +void ecc_init(ecc_key* key); +void ecc_free(ecc_key* key); + + +/* ASN key helpers */ +int ecc_export_x963(ecc_key*, byte* out, word32* outLen); +int ecc_import_x963(const byte* in, word32 inLen, ecc_key* key); + +int ecc_import_private_key(const byte* priv, word32 privSz, const byte* pub, + word32 pubSz, ecc_key* key); + +/* size helper */ +int ecc_size(ecc_key* key); +int ecc_sig_size(ecc_key* key); + +/* TODO: fix mutex types */ +#define MUTEX_GLOBAL(x) int (x); +#define MUTEX_LOCK(x) +#define MUTEX_UNLOCK(x) + + + +#ifdef __cplusplus + } /* extern "C" */ +#endif + +#endif /* CTAO_CRYPT_ECC_H */ +#endif /* HAVE_ECC */ diff --git a/ctaocrypt/include/ctc_hmac.h b/ctaocrypt/include/ctc_hmac.h new file mode 100644 index 000000000..27ecb605c --- /dev/null +++ b/ctaocrypt/include/ctc_hmac.h @@ -0,0 +1,85 @@ +/* ctc_hmac.h + * + * Copyright (C) 2006-2011 Sawtooth Consulting Ltd. + * + * This file is part of CyaSSL. + * + * CyaSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * CyaSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#ifndef NO_HMAC + +#ifndef CTAO_CRYPT_HMAC_H +#define CTAO_CRYPT_HMAC_H + +#include "ctc_md5.h" +#include "ctc_sha.h" + +#ifndef NO_SHA256 + #include "sha256.h" +#endif + +#ifdef __cplusplus + extern "C" { +#endif + + + +enum { + IPAD = 0x36, + OPAD = 0x5C, +#ifndef NO_SHA256 + INNER_HASH_SIZE = SHA256_DIGEST_SIZE, +#else + INNER_HASH_SIZE = SHA_DIGEST_SIZE, + SHA256 = 2, /* hash type unique */ +#endif + HMAC_BLOCK_SIZE = MD5_BLOCK_SIZE +}; + + +/* hash union */ +typedef union { + Md5 md5; + Sha sha; + #ifndef NO_SHA256 + Sha256 sha256; + #endif +} Hash; + +/* Hmac digest */ +typedef struct Hmac { + Hash hash; + word32 ipad[HMAC_BLOCK_SIZE / sizeof(word32)]; /* same block size all*/ + word32 opad[HMAC_BLOCK_SIZE / sizeof(word32)]; + word32 innerHash[INNER_HASH_SIZE / sizeof(word32)]; /* max size */ + byte macType; /* md5 sha or sha256 */ + byte innerHashKeyed; /* keyed flag */ +} Hmac; + + +void HmacSetKey(Hmac*, int type, const byte* key, word32 keySz); /* does init */ +void HmacUpdate(Hmac*, const byte*, word32); +void HmacFinal(Hmac*, byte*); + + +#ifdef __cplusplus + } /* extern "C" */ +#endif + +#endif /* CTAO_CRYPT_HMAC_H */ + +#endif /* NO_HMAC */ + diff --git a/ctaocrypt/include/ctc_md4.h b/ctaocrypt/include/ctc_md4.h new file mode 100644 index 000000000..2bb389d28 --- /dev/null +++ b/ctaocrypt/include/ctc_md4.h @@ -0,0 +1,65 @@ +/* ctc_md4.h + * + * Copyright (C) 2006-2011 Sawtooth Consulting Ltd. + * + * This file is part of CyaSSL. + * + * CyaSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * CyaSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + + +#ifndef NO_MD4 + +#ifndef CTAO_CRYPT_MD4_H +#define CTAO_CRYPT_MD4_H + +#include "types.h" + +#ifdef __cplusplus + extern "C" { +#endif + + +/* in bytes */ +enum { + MD4_BLOCK_SIZE = 64, + MD4_DIGEST_SIZE = 16, + MD4_PAD_SIZE = 56 +}; + + +/* MD4 digest */ +typedef struct Md4 { + word32 buffLen; /* in bytes */ + word32 loLen; /* length in bytes */ + word32 hiLen; /* length in bytes */ + word32 digest[MD4_DIGEST_SIZE / sizeof(word32)]; + word32 buffer[MD4_BLOCK_SIZE / sizeof(word32)]; +} Md4; + + +void InitMd4(Md4*); +void Md4Update(Md4*, const byte*, word32); +void Md4Final(Md4*, byte*); + + +#ifdef __cplusplus + } /* extern "C" */ +#endif + +#endif /* CTAO_CRYPT_MD4_H */ + +#endif /* NO_MD4 */ + diff --git a/ctaocrypt/include/ctc_md5.h b/ctaocrypt/include/ctc_md5.h new file mode 100644 index 000000000..058f3ed24 --- /dev/null +++ b/ctaocrypt/include/ctc_md5.h @@ -0,0 +1,62 @@ +/* ctc_md5.h + * + * Copyright (C) 2006-2011 Sawtooth Consulting Ltd. + * + * This file is part of CyaSSL. + * + * CyaSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * CyaSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + + +#ifndef CTAO_CRYPT_MD5_H +#define CTAO_CRYPT_MD5_H + +#include "types.h" + +#ifdef __cplusplus + extern "C" { +#endif + + +/* in bytes */ +enum { + MD5 = 0, /* hash type unique */ + MD5_BLOCK_SIZE = 64, + MD5_DIGEST_SIZE = 16, + MD5_PAD_SIZE = 56 +}; + + +/* MD5 digest */ +typedef struct Md5 { + word32 buffLen; /* in bytes */ + word32 loLen; /* length in bytes */ + word32 hiLen; /* length in bytes */ + word32 digest[MD5_DIGEST_SIZE / sizeof(word32)]; + word32 buffer[MD5_BLOCK_SIZE / sizeof(word32)]; +} Md5; + + +void InitMd5(Md5*); +void Md5Update(Md5*, const byte*, word32); +void Md5Final(Md5*, byte*); + + +#ifdef __cplusplus + } /* extern "C" */ +#endif + +#endif /* CTAO_CRYPT_MD5_H */ + diff --git a/ctaocrypt/include/ctc_ripemd.h b/ctaocrypt/include/ctc_ripemd.h new file mode 100644 index 000000000..dff207199 --- /dev/null +++ b/ctaocrypt/include/ctc_ripemd.h @@ -0,0 +1,65 @@ +/* ctc_ripemd.h + * + * Copyright (C) 2006-2011 Sawtooth Consulting Ltd. + * + * This file is part of CyaSSL. + * + * CyaSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * CyaSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + + +#ifdef CYASSL_RIPEMD + +#ifndef CTAO_CRYPT_RIPEMD_H +#define CTAO_CRYPT_RIPEME_H + +#include "types.h" + +#ifdef __cplusplus + extern "C" { +#endif + + + +/* in bytes */ +enum { + RIPEMD = 3, /* hash type unique */ + RIPEMD_BLOCK_SIZE = 64, + RIPEMD_DIGEST_SIZE = 20, + RIPEMD_PAD_SIZE = 56 +}; + + +/* RipeMd 160 digest */ +typedef struct RipeMd { + word32 buffLen; /* in bytes */ + word32 loLen; /* length in bytes */ + word32 hiLen; /* length in bytes */ + word32 digest[RIPEMD_DIGEST_SIZE / sizeof(word32)]; + word32 buffer[RIPEMD_BLOCK_SIZE / sizeof(word32)]; +} RipeMd; + + +void InitRipeMd(RipeMd*); +void RipeMdUpdate(RipeMd*, const byte*, word32); +void RipeMdFinal(RipeMd*, byte*); + + +#ifdef __cplusplus + } /* extern "C" */ +#endif + +#endif /* CTAO_CRYPT_RIPEMD_H */ +#endif /* CYASSL_RIPEMD */ diff --git a/ctaocrypt/include/ctc_rsa.h b/ctaocrypt/include/ctc_rsa.h new file mode 100644 index 000000000..f47bbe296 --- /dev/null +++ b/ctaocrypt/include/ctc_rsa.h @@ -0,0 +1,74 @@ +/* ctc_rsa.h + * + * Copyright (C) 2006-2011 Sawtooth Consulting Ltd. + * + * This file is part of CyaSSL. + * + * CyaSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * CyaSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + + +#ifndef CTAO_CRYPT_RSA_H +#define CTAO_CRYPT_RSA_H + +#include "types.h" +#include "integer.h" +#include "random.h" + +#ifdef __cplusplus + extern "C" { +#endif + + +enum { + RSA_PUBLIC = 0, + RSA_PRIVATE = 1 +}; + +/* RSA */ +typedef struct RsaKey { + mp_int n, e, d, p, q, dP, dQ, u; + int type; /* public or private */ + void* heap; /* for user memory overrides */ +} RsaKey; + + +void InitRsaKey(RsaKey* key, void*); +void FreeRsaKey(RsaKey* key); + +int RsaPublicEncrypt(const byte* in, word32 inLen, byte* out, word32 outLen, + RsaKey* key, RNG* rng); +int RsaPrivateDecryptInline(byte* in, word32 inLen, byte** out, RsaKey* key); +int RsaPrivateDecrypt(const byte* in, word32 inLen, byte* out, word32 outLen, + RsaKey* key); +int RsaSSL_Sign(const byte* in, word32 inLen, byte* out, word32 outLen, + RsaKey* key, RNG* rng); +int RsaSSL_VerifyInline(byte* in, word32 inLen, byte** out, RsaKey* key); +int RsaSSL_Verify(const byte* in, word32 inLen, byte* out, word32 outLen, + RsaKey* key); + +int RsaEncryptSize(RsaKey* key); + +#ifdef CYASSL_KEY_GEN + int MakeRsaKey(RsaKey* key, int size, long e, RNG* rng); +#endif + + +#ifdef __cplusplus + } /* extern "C" */ +#endif + +#endif /* CTAO_CRYPT_RSA_H */ + diff --git a/ctaocrypt/include/ctc_sha.h b/ctaocrypt/include/ctc_sha.h new file mode 100644 index 000000000..ab7f6cb1f --- /dev/null +++ b/ctaocrypt/include/ctc_sha.h @@ -0,0 +1,63 @@ +/* ctc_sha.h + * + * Copyright (C) 2006-2011 Sawtooth Consulting Ltd. + * + * This file is part of CyaSSL. + * + * CyaSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * CyaSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + + +#ifndef CTAO_CRYPT_SHA_H +#define CTAO_CRYPT_SHA_H + +#include "types.h" + +#ifdef __cplusplus + extern "C" { +#endif + + + +/* in bytes */ +enum { + SHA = 1, /* hash type unique */ + SHA_BLOCK_SIZE = 64, + SHA_DIGEST_SIZE = 20, + SHA_PAD_SIZE = 56 +}; + + +/* Sha digest */ +typedef struct Sha { + word32 buffLen; /* in bytes */ + word32 loLen; /* length in bytes */ + word32 hiLen; /* length in bytes */ + word32 digest[SHA_DIGEST_SIZE / sizeof(word32)]; + word32 buffer[SHA_BLOCK_SIZE / sizeof(word32)]; +} Sha; + + +void InitSha(Sha*); +void ShaUpdate(Sha*, const byte*, word32); +void ShaFinal(Sha*, byte*); + + +#ifdef __cplusplus + } /* extern "C" */ +#endif + +#endif /* CTAO_CRYPT_SHA_H */ + diff --git a/ctaocrypt/include/des3.h b/ctaocrypt/include/des3.h new file mode 100644 index 000000000..3af40fb36 --- /dev/null +++ b/ctaocrypt/include/des3.h @@ -0,0 +1,75 @@ +/* des3.h + * + * Copyright (C) 2006-2011 Sawtooth Consulting Ltd. + * + * This file is part of CyaSSL. + * + * CyaSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * CyaSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#ifndef NO_DES3 + +#ifndef CTAO_CRYPT_DES3_H +#define CTAO_CRYPT_DES3_H + + +#include "types.h" + + +#ifdef __cplusplus + extern "C" { +#endif + +enum { + DES_BLOCK_SIZE = 8, + DES_KS_SIZE = 32, + + DES_ENCRYPTION = 0, + DES_DECRYPTION = 1, +}; + + +/* DES encryption and decryption */ +typedef struct Des { + word32 key[DES_KS_SIZE]; + word32 reg[DES_BLOCK_SIZE / sizeof(word32)]; /* for CBC mode */ + word32 tmp[DES_BLOCK_SIZE / sizeof(word32)]; /* same */ +} Des; + + +/* DES3 encryption and decryption */ +typedef struct Des3 { + word32 key[3][DES_KS_SIZE]; + word32 reg[DES_BLOCK_SIZE / sizeof(word32)]; /* for CBC mode */ + word32 tmp[DES_BLOCK_SIZE / sizeof(word32)]; /* same */ +} Des3; + + +void Des_SetKey(Des* des, const byte* key, const byte* iv, int dir); +void Des_CbcEncrypt(Des* des, byte* out, const byte* in, word32 sz); +void Des_CbcDecrypt(Des* des, byte* out, const byte* in, word32 sz); + +void Des3_SetKey(Des3* des, const byte* key, const byte* iv, int dir); +void Des3_CbcEncrypt(Des3* des, byte* out, const byte* in, word32 sz); +void Des3_CbcDecrypt(Des3* des, byte* out, const byte* in, word32 sz); + + +#ifdef __cplusplus + } /* extern "C" */ +#endif + +#endif /* NO_DES3 */ +#endif /* CTAO_CRYPT_DES3_H */ + diff --git a/ctaocrypt/include/error.h b/ctaocrypt/include/error.h new file mode 100644 index 000000000..5dd6508bc --- /dev/null +++ b/ctaocrypt/include/error.h @@ -0,0 +1,106 @@ +/* error.h + * + * Copyright (C) 2006-2011 Sawtooth Consulting Ltd. + * + * This file is part of CyaSSL. + * + * CyaSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * CyaSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + + +#ifndef CTAO_CRYPT_ERROR_H +#define CTAO_CRYPT_ERROR_H + +#include "types.h" + + +#ifdef __cplusplus + extern "C" { +#endif + + +/* error codes */ +enum { + MAX_ERROR_SZ = 80, /* max size of error string */ + MAX_CODE_E = -100, /* errors -101 - -199 */ + OPEN_RAN_E = -101, /* opening random device error */ + READ_RAN_E = -102, /* reading random device error */ + WINCRYPT_E = -103, /* windows crypt init error */ + CRYPTGEN_E = -104, /* windows crypt generation error */ + RAN_BLOCK_E = -105, /* reading random device would block */ + + MP_INIT_E = -110, /* mp_init error state */ + MP_READ_E = -111, /* mp_read error state */ + MP_EXPTMOD_E = -112, /* mp_exptmod error state */ + MP_TO_E = -113, /* mp_to_xxx error state, can't convert */ + MP_SUB_E = -114, /* mp_sub error state, can't subtract */ + MP_ADD_E = -115, /* mp_add error state, can't add */ + MP_MUL_E = -116, /* mp_mul error state, can't multiply */ + MP_MULMOD_E = -117, /* mp_mulmod error state, can't multiply mod */ + MP_MOD_E = -118, /* mp_mod error state, can't mod */ + MP_INVMOD_E = -119, /* mp_invmod error state, can't inv mod */ + MP_CMP_E = -120, /* mp_cmp error state */ + + MEMORY_E = -125, /* out of memory error */ + + RSA_WRONG_TYPE_E = -130, /* RSA wrong block type for RSA function */ + RSA_BUFFER_E = -131, /* RSA buffer error, output too small or + input too large */ + BUFFER_E = -132, /* output buffer too small or input too large */ + ALGO_ID_E = -133, /* setting algo id error */ + PUBLIC_KEY_E = -134, /* setting public key error */ + DATE_E = -135, /* setting date validity error */ + SUBJECT_E = -136, /* setting subject name error */ + ISSUER_E = -137, /* setting issuer name error */ + + ASN_PARSE_E = -140, /* ASN parsing error, invalid input */ + ASN_VERSION_E = -141, /* ASN version error, invalid number */ + ASN_GETINT_E = -142, /* ASN get big int error, invalid data */ + ASN_RSA_KEY_E = -143, /* ASN key init error, invalid input */ + ASN_OBJECT_ID_E = -144, /* ASN object id error, invalid id */ + ASN_TAG_NULL_E = -145, /* ASN tag error, not null */ + ASN_EXPECT_0_E = -146, /* ASN expect error, not zero */ + ASN_BITSTR_E = -147, /* ASN bit string error, wrong id */ + ASN_UNKNOWN_OID_E = -148, /* ASN oid error, unknown sum id */ + ASN_DATE_SZ_E = -149, /* ASN date error, bad size */ + ASN_BEFORE_DATE_E = -150, /* ASN date error, current date before */ + ASN_AFTER_DATE_E = -151, /* ASN date error, current date after */ + ASN_SIG_OID_E = -152, /* ASN signature error, mismatched oid */ + ASN_TIME_E = -153, /* ASN time error, unkown time type */ + ASN_INPUT_E = -154, /* ASN input error, not enough data */ + ASN_SIG_CONFIRM_E = -155, /* ASN sig error, confirm failure */ + ASN_SIG_HASH_E = -156, /* ASN sig error, unsupported hash type */ + ASN_SIG_KEY_E = -157, /* ASN sig error, unsupported key type */ + ASN_DH_KEY_E = -158, /* ASN key init error, invalid input */ + ASN_NTRU_KEY_E = -159, /* ASN ntru key decode error, invalid input */ + + /* TODO: TAO add ECC error strings to ErrorString() */ + ECC_BAD_ARG_E = -170, /* ECC input argument of wrong type */ + ASN_ECC_KEY_E = -171, /* ASN ECC bad input */ + ECC_CURVE_OID_E = -172, /* Unsupported ECC OID curve type */ + + MIN_CODE_E = -200 /* errors -101 - -199 */ +}; + + +void CTaoCryptErrorString(int error, char* buffer); + + +#ifdef __cplusplus + } /* extern "C" */ +#endif + +#endif /* CTAO_CRYPT_ERROR_H */ + diff --git a/ctaocrypt/include/hc128.h b/ctaocrypt/include/hc128.h new file mode 100644 index 000000000..aa58304d0 --- /dev/null +++ b/ctaocrypt/include/hc128.h @@ -0,0 +1,57 @@ +/* hc128.h + * + * Copyright (C) 2006-2011 Sawtooth Consulting Ltd. + * + * This file is part of CyaSSL. + * + * CyaSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * CyaSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + + +#ifndef NO_HC128 + +#ifndef CTAO_CRYPT_HC128_H +#define CTAO_CRYPT_HC128_H + +#include "types.h" + +#ifdef __cplusplus + extern "C" { +#endif + + + +/* HC-128 stream cipher */ +typedef struct HC128 { + word32 T[1024]; /* P[i] = T[i]; Q[i] = T[1024 + i ]; */ + word32 X[16]; + word32 Y[16]; + word32 counter1024; /* counter1024 = i mod 1024 at the ith step */ + word32 key[8]; + word32 iv[8]; +} HC128; + + +void Hc128_Process(HC128*, byte*, const byte*, word32); +void Hc128_SetKey(HC128*, const byte* key, const byte* iv); + + +#ifdef __cplusplus + } /* extern "C" */ +#endif + +#endif /* CTAO_CRYPT_HC128_H */ + +#endif /* NO_HC128 */ diff --git a/ctaocrypt/include/integer.h b/ctaocrypt/include/integer.h new file mode 100644 index 000000000..aaa2c7b1a --- /dev/null +++ b/ctaocrypt/include/integer.h @@ -0,0 +1,329 @@ +/* integer.h + * + * Copyright (C) 2006-2011 Sawtooth Consulting Ltd. + * + * This file is part of CyaSSL. + * + * CyaSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * CyaSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + + + +/* + * Based on public domain LibTomMath 0.38 by Tom St Denis, tomstdenis@iahu.ca, + * http://math.libtomcrypt.com + */ + + +#ifndef CTAO_CRYPT_INTEGER_H +#define CTAO_CRYPT_INTEGER_H + +/* may optionally use fast math instead, not yet supported on all platforms and + may not be faster on all +*/ +#include "types.h" /* will set MP_xxBIT if not default */ +#ifdef USE_FAST_MATH + #include "tfm.h" +#else + +#ifndef CHAR_BIT + #include +#endif + +#include "mpi_class.h" + +#ifndef MIN + #define MIN(x,y) ((x)<(y)?(x):(y)) +#endif + +#ifndef MAX + #define MAX(x,y) ((x)>(y)?(x):(y)) +#endif + +#ifdef __cplusplus +extern "C" { + +/* C++ compilers don't like assigning void * to mp_digit * */ +#define OPT_CAST(x) (x *) + +#else + +/* C on the other hand doesn't care */ +#define OPT_CAST(x) + +#endif + + +/* detect 64-bit mode if possible */ +#if defined(__x86_64__) + #if !(defined(MP_64BIT) && defined(MP_16BIT) && defined(MP_8BIT)) + #define MP_64BIT + #endif +#endif + +/* some default configurations. + * + * A "mp_digit" must be able to hold DIGIT_BIT + 1 bits + * A "mp_word" must be able to hold 2*DIGIT_BIT + 1 bits + * + * At the very least a mp_digit must be able to hold 7 bits + * [any size beyond that is ok provided it doesn't overflow the data type] + */ +#ifdef MP_8BIT + typedef unsigned char mp_digit; + typedef unsigned short mp_word; +#elif defined(MP_16BIT) + typedef unsigned short mp_digit; + typedef unsigned long mp_word; +#elif defined(MP_64BIT) + /* for GCC only on supported platforms */ +#ifndef CRYPT + typedef unsigned long long ulong64; + typedef signed long long long64; +#endif + + typedef unsigned long mp_digit; + typedef unsigned long mp_word __attribute__ ((mode(TI))); + + #define DIGIT_BIT 60 +#else + /* this is the default case, 28-bit digits */ + + /* 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 +#endif + + typedef unsigned long mp_digit; + typedef ulong64 mp_word; + +#ifdef MP_31BIT + /* this is an extension that uses 31-bit digits */ + #define DIGIT_BIT 31 +#else + /* default case is 28-bit digits, defines MP_28BIT as a handy test macro */ + #define DIGIT_BIT 28 + #define MP_28BIT +#endif +#endif + + +/* otherwise the bits per digit is calculated automatically from the size of + a mp_digit */ +#ifndef DIGIT_BIT + #define DIGIT_BIT ((int)((CHAR_BIT * sizeof(mp_digit) - 1))) + /* bits per digit */ +#endif + +#define MP_DIGIT_BIT DIGIT_BIT +#define MP_MASK ((((mp_digit)1)<<((mp_digit)DIGIT_BIT))-((mp_digit)1)) +#define MP_DIGIT_MAX MP_MASK + +/* equalities */ +#define MP_LT -1 /* less than */ +#define MP_EQ 0 /* equal to */ +#define MP_GT 1 /* greater than */ + +#define MP_ZPOS 0 /* positive integer */ +#define MP_NEG 1 /* negative */ + +#define MP_OKAY 0 /* ok result */ +#define MP_MEM -2 /* out of mem */ +#define MP_VAL -3 /* invalid input */ +#define MP_RANGE MP_VAL + +#define MP_YES 1 /* yes response */ +#define MP_NO 0 /* no response */ + +/* Primality generation flags */ +#define LTM_PRIME_BBS 0x0001 /* BBS style prime */ +#define LTM_PRIME_SAFE 0x0002 /* Safe prime (p-1)/2 == prime */ +#define LTM_PRIME_2MSB_ON 0x0008 /* force 2nd MSB to 1 */ + +typedef int mp_err; + +/* define this to use lower memory usage routines (exptmods mostly) */ +#define MP_LOW_MEM + +/* default precision */ +#ifndef MP_PREC + #ifndef MP_LOW_MEM + #define MP_PREC 32 /* default digits of precision */ + #else + #define MP_PREC 1 /* default digits of precision */ + #endif +#endif + +/* size of comba arrays, should be at least 2 * 2**(BITS_PER_WORD - + BITS_PER_DIGIT*2) */ +#define MP_WARRAY (1 << (sizeof(mp_word) * CHAR_BIT - 2 * DIGIT_BIT + 1)) + +/* the infamous mp_int structure */ +typedef struct { + int used, alloc, sign; + mp_digit *dp; +} mp_int; + +/* callback for mp_prime_random, should fill dst with random bytes and return + how many read [upto len] */ +typedef int ltm_prime_callback(unsigned char *dst, int len, void *dat); + + +#define USED(m) ((m)->used) +#define DIGIT(m,k) ((m)->dp[(k)]) +#define SIGN(m) ((m)->sign) + + +/* ---> Basic Manipulations <--- */ +#define mp_iszero(a) (((a)->used == 0) ? MP_YES : MP_NO) +#define mp_iseven(a) \ + (((a)->used > 0 && (((a)->dp[0] & 1) == 0)) ? MP_YES : MP_NO) +#define mp_isodd(a) \ + (((a)->used > 0 && (((a)->dp[0] & 1) == 1)) ? MP_YES : MP_NO) + + +/* number of primes */ +#ifdef MP_8BIT + #define PRIME_SIZE 31 +#else + #define PRIME_SIZE 256 +#endif + +#define mp_prime_random(a, t, size, bbs, cb, dat) \ + mp_prime_random_ex(a, t, ((size) * 8) + 1, (bbs==1)?LTM_PRIME_BBS:0, cb, dat) + +#define mp_read_raw(mp, str, len) mp_read_signed_bin((mp), (str), (len)) +#define mp_raw_size(mp) mp_signed_bin_size(mp) +#define mp_toraw(mp, str) mp_to_signed_bin((mp), (str)) +#define mp_read_mag(mp, str, len) mp_read_unsigned_bin((mp), (str), (len)) +#define mp_mag_size(mp) mp_unsigned_bin_size(mp) +#define mp_tomag(mp, str) mp_to_unsigned_bin((mp), (str)) + +#define mp_tobinary(M, S) mp_toradix((M), (S), 2) +#define mp_tooctal(M, S) mp_toradix((M), (S), 8) +#define mp_todecimal(M, S) mp_toradix((M), (S), 10) +#define mp_tohex(M, S) mp_toradix((M), (S), 16) + +#define s_mp_mul(a, b, c) s_mp_mul_digs(a, b, c, (a)->used + (b)->used + 1) + +extern const char *mp_s_rmap; + +/* 6 functions needed by Rsa */ +int mp_init (mp_int * a); +void mp_clear (mp_int * a); +int mp_unsigned_bin_size(mp_int * a); +int mp_read_unsigned_bin (mp_int * a, const unsigned char *b, int c); +int mp_to_unsigned_bin (mp_int * a, unsigned char *b); +int mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y); +/* end functions needed by Rsa */ + +/* functions added to support above needed, removed TOOM and KARATSUBA */ +int mp_count_bits (mp_int * a); +int mp_init_copy (mp_int * a, mp_int * b); +int mp_copy (mp_int * a, mp_int * b); +int mp_grow (mp_int * a, int size); +void bn_reverse (unsigned char *s, int len); +int mp_div_2d (mp_int * a, int b, mp_int * c, mp_int * d); +void mp_zero (mp_int * a); +void mp_clamp (mp_int * a); +void mp_exch (mp_int * a, mp_int * b); +void mp_rshd (mp_int * a, int b); +int mp_mod_2d (mp_int * a, int b, mp_int * c); +int mp_read_unsigned_bin (mp_int * a, const unsigned char *b, int c); +int mp_mul_2d (mp_int * a, int b, mp_int * c); +int mp_lshd (mp_int * a, int b); +int mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y); +int mp_abs (mp_int * a, mp_int * b); +int mp_invmod (mp_int * a, mp_int * b, mp_int * c); +int fast_mp_invmod (mp_int * a, mp_int * b, mp_int * c); +int mp_invmod_slow (mp_int * a, mp_int * b, mp_int * c); +int mp_cmp_mag (mp_int * a, mp_int * b); +int mp_cmp (mp_int * a, mp_int * b); +int mp_cmp_d(mp_int * a, mp_digit b); +void mp_set (mp_int * a, mp_digit b); +int mp_mod (mp_int * a, mp_int * b, mp_int * c); +int mp_div(mp_int * a, mp_int * b, mp_int * c, mp_int * d); +int mp_div_2(mp_int * a, mp_int * b); +int mp_add (mp_int * a, mp_int * b, mp_int * c); +int s_mp_add (mp_int * a, mp_int * b, mp_int * c); +int s_mp_sub (mp_int * a, mp_int * b, mp_int * c); +int mp_sub (mp_int * a, mp_int * b, mp_int * c); +int mp_init (mp_int * a); +int mp_reduce_is_2k_l(mp_int *a); +int mp_reduce_is_2k(mp_int *a); +int mp_dr_is_modulus(mp_int *a); +int mp_exptmod_fast (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int); +int mp_montgomery_setup (mp_int * n, mp_digit * rho); +int fast_mp_montgomery_reduce (mp_int * x, mp_int * n, mp_digit rho); +int mp_montgomery_reduce (mp_int * x, mp_int * n, mp_digit rho); +void mp_dr_setup(mp_int *a, mp_digit *d); +int mp_dr_reduce (mp_int * x, mp_int * n, mp_digit k); +int mp_reduce_2k(mp_int *a, mp_int *n, mp_digit d); +int fast_s_mp_mul_high_digs (mp_int * a, mp_int * b, mp_int * c, int digs); +int s_mp_mul_high_digs (mp_int * a, mp_int * b, mp_int * c, int digs); +int mp_reduce_2k_setup_l(mp_int *a, mp_int *d); +int mp_reduce_2k_l(mp_int *a, mp_int *n, mp_int *d); +int mp_reduce (mp_int * x, mp_int * m, mp_int * mu); +int mp_reduce_setup (mp_int * a, mp_int * b); +int s_mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode); +int mp_montgomery_calc_normalization (mp_int * a, mp_int * b); +int s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs); +int s_mp_sqr (mp_int * a, mp_int * b); +int fast_s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs); +int fast_s_mp_sqr (mp_int * a, mp_int * b); +int mp_init_size (mp_int * a, int size); +int mp_div_3 (mp_int * a, mp_int *c, mp_digit * d); +int mp_mul_2(mp_int * a, mp_int * b); +int mp_mul (mp_int * a, mp_int * b, mp_int * c); +int mp_sqr (mp_int * a, mp_int * b); +int mp_mulmod (mp_int * a, mp_int * b, mp_int * c, mp_int * d); +int mp_mul_d (mp_int * a, mp_digit b, mp_int * c); +int mp_2expt (mp_int * a, int b); +int mp_reduce_2k_setup(mp_int *a, mp_digit *d); +/* end support added functions */ + +/* added */ +int mp_init_multi(mp_int* a, mp_int* b, mp_int* c, mp_int* d, mp_int* e, + mp_int* f); + +#ifdef HAVE_ECC + int mp_sqrmod(mp_int* a, mp_int* b, mp_int* c); + int mp_read_radix(mp_int* a, const char* str, int radix); +#endif + +#ifdef CYASSL_KEY_GEN + int mp_prime_is_prime (mp_int * a, int t, int *result); + int mp_set_int (mp_int * a, unsigned long b); + int mp_gcd (mp_int * a, mp_int * b, mp_int * c); + int mp_lcm (mp_int * a, mp_int * b, mp_int * c); + int mp_sub_d (mp_int * a, mp_digit b, mp_int * c); +#endif + + +#ifdef __cplusplus + } +#endif + + +#endif /* USE_FAST_MATH */ + +#endif /* CTAO_CRYPT_INTEGER_H */ + diff --git a/ctaocrypt/include/misc.h b/ctaocrypt/include/misc.h new file mode 100644 index 000000000..63ab10685 --- /dev/null +++ b/ctaocrypt/include/misc.h @@ -0,0 +1,55 @@ +/* misc.h + * + * Copyright (C) 2006-2011 Sawtooth Consulting Ltd. + * + * This file is part of CyaSSL. + * + * CyaSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * CyaSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + + +#ifndef CTAO_CRYPT_MISC_H +#define CTAO_CRYPT_MISC_H + + +#include "types.h" + + + +#ifdef __cplusplus + extern "C" { +#endif + + +#ifdef NO_INLINE +word32 rotlFixed(word32, word32); +word32 rotrFixed(word32, word32); + +word32 ByteReverseWord32(word32); +void ByteReverseWords(word32*, const word32*, word32); +void ByteReverseBytes(byte*, const byte*, word32); + +void XorWords(word*, const word*, word32); +void xorbuf(byte*, const byte*, word32); +#endif /* NO_INLINE */ + + +#ifdef __cplusplus + } /* extern "C" */ +#endif + + +#endif /* CTAO_CRYPT_MISC_H */ + diff --git a/ctaocrypt/include/mpi_class.h b/ctaocrypt/include/mpi_class.h new file mode 100644 index 000000000..e2b20bf95 --- /dev/null +++ b/ctaocrypt/include/mpi_class.h @@ -0,0 +1,996 @@ +#if !(defined(LTM1) && defined(LTM2) && defined(LTM3)) +#if defined(LTM2) +#define LTM3 +#endif +#if defined(LTM1) +#define LTM2 +#endif +#define LTM1 + +#if defined(LTM_ALL) +#define BN_ERROR_C +#define BN_FAST_MP_INVMOD_C +#define BN_FAST_MP_MONTGOMERY_REDUCE_C +#define BN_FAST_S_MP_MUL_DIGS_C +#define BN_FAST_S_MP_MUL_HIGH_DIGS_C +#define BN_FAST_S_MP_SQR_C +#define BN_MP_2EXPT_C +#define BN_MP_ABS_C +#define BN_MP_ADD_C +#define BN_MP_ADD_D_C +#define BN_MP_ADDMOD_C +#define BN_MP_AND_C +#define BN_MP_CLAMP_C +#define BN_MP_CLEAR_C +#define BN_MP_CLEAR_MULTI_C +#define BN_MP_CMP_C +#define BN_MP_CMP_D_C +#define BN_MP_CMP_MAG_C +#define BN_MP_CNT_LSB_C +#define BN_MP_COPY_C +#define BN_MP_COUNT_BITS_C +#define BN_MP_DIV_C +#define BN_MP_DIV_2_C +#define BN_MP_DIV_2D_C +#define BN_MP_DIV_3_C +#define BN_MP_DIV_D_C +#define BN_MP_DR_IS_MODULUS_C +#define BN_MP_DR_REDUCE_C +#define BN_MP_DR_SETUP_C +#define BN_MP_EXCH_C +#define BN_MP_EXPT_D_C +#define BN_MP_EXPTMOD_C +#define BN_MP_EXPTMOD_FAST_C +#define BN_MP_EXTEUCLID_C +#define BN_MP_FREAD_C +#define BN_MP_FWRITE_C +#define BN_MP_GCD_C +#define BN_MP_GET_INT_C +#define BN_MP_GROW_C +#define BN_MP_INIT_C +#define BN_MP_INIT_COPY_C +#define BN_MP_INIT_MULTI_C +#define BN_MP_INIT_SET_C +#define BN_MP_INIT_SET_INT_C +#define BN_MP_INIT_SIZE_C +#define BN_MP_INVMOD_C +#define BN_MP_INVMOD_SLOW_C +#define BN_MP_IS_SQUARE_C +#define BN_MP_JACOBI_C +#define BN_MP_KARATSUBA_MUL_C +#define BN_MP_KARATSUBA_SQR_C +#define BN_MP_LCM_C +#define BN_MP_LSHD_C +#define BN_MP_MOD_C +#define BN_MP_MOD_2D_C +#define BN_MP_MOD_D_C +#define BN_MP_MONTGOMERY_CALC_NORMALIZATION_C +#define BN_MP_MONTGOMERY_REDUCE_C +#define BN_MP_MONTGOMERY_SETUP_C +#define BN_MP_MUL_C +#define BN_MP_MUL_2_C +#define BN_MP_MUL_2D_C +#define BN_MP_MUL_D_C +#define BN_MP_MULMOD_C +#define BN_MP_N_ROOT_C +#define BN_MP_NEG_C +#define BN_MP_OR_C +#define BN_MP_PRIME_FERMAT_C +#define BN_MP_PRIME_IS_DIVISIBLE_C +#define BN_MP_PRIME_IS_PRIME_C +#define BN_MP_PRIME_MILLER_RABIN_C +#define BN_MP_PRIME_NEXT_PRIME_C +#define BN_MP_PRIME_RABIN_MILLER_TRIALS_C +#define BN_MP_PRIME_RANDOM_EX_C +#define BN_MP_RADIX_SIZE_C +#define BN_MP_RADIX_SMAP_C +#define BN_MP_RAND_C +#define BN_MP_READ_RADIX_C +#define BN_MP_READ_SIGNED_BIN_C +#define BN_MP_READ_UNSIGNED_BIN_C +#define BN_MP_REDUCE_C +#define BN_MP_REDUCE_2K_C +#define BN_MP_REDUCE_2K_L_C +#define BN_MP_REDUCE_2K_SETUP_C +#define BN_MP_REDUCE_2K_SETUP_L_C +#define BN_MP_REDUCE_IS_2K_C +#define BN_MP_REDUCE_IS_2K_L_C +#define BN_MP_REDUCE_SETUP_C +#define BN_MP_RSHD_C +#define BN_MP_SET_C +#define BN_MP_SET_INT_C +#define BN_MP_SHRINK_C +#define BN_MP_SIGNED_BIN_SIZE_C +#define BN_MP_SQR_C +#define BN_MP_SQRMOD_C +#define BN_MP_SQRT_C +#define BN_MP_SUB_C +#define BN_MP_SUB_D_C +#define BN_MP_SUBMOD_C +#define BN_MP_TO_SIGNED_BIN_C +#define BN_MP_TO_SIGNED_BIN_N_C +#define BN_MP_TO_UNSIGNED_BIN_C +#define BN_MP_TO_UNSIGNED_BIN_N_C +#define BN_MP_TOOM_MUL_C +#define BN_MP_TOOM_SQR_C +#define BN_MP_TORADIX_C +#define BN_MP_TORADIX_N_C +#define BN_MP_UNSIGNED_BIN_SIZE_C +#define BN_MP_XOR_C +#define BN_MP_ZERO_C +#define BN_PRIME_TAB_C +#define BN_REVERSE_C +#define BN_S_MP_ADD_C +#define BN_S_MP_EXPTMOD_C +#define BN_S_MP_MUL_DIGS_C +#define BN_S_MP_MUL_HIGH_DIGS_C +#define BN_S_MP_SQR_C +#define BN_S_MP_SUB_C +#define BNCORE_C +#endif + +#if defined(BN_ERROR_C) + #define BN_MP_ERROR_TO_STRING_C +#endif + +#if defined(BN_FAST_MP_INVMOD_C) + #define BN_MP_ISEVEN_C + #define BN_MP_INIT_MULTI_C + #define BN_MP_COPY_C + #define BN_MP_MOD_C + #define BN_MP_SET_C + #define BN_MP_DIV_2_C + #define BN_MP_ISODD_C + #define BN_MP_SUB_C + #define BN_MP_CMP_C + #define BN_MP_ISZERO_C + #define BN_MP_CMP_D_C + #define BN_MP_ADD_C + #define BN_MP_EXCH_C + #define BN_MP_CLEAR_MULTI_C +#endif + +#if defined(BN_FAST_MP_MONTGOMERY_REDUCE_C) + #define BN_MP_GROW_C + #define BN_MP_RSHD_C + #define BN_MP_CLAMP_C + #define BN_MP_CMP_MAG_C + #define BN_S_MP_SUB_C +#endif + +#if defined(BN_FAST_S_MP_MUL_DIGS_C) + #define BN_MP_GROW_C + #define BN_MP_CLAMP_C +#endif + +#if defined(BN_FAST_S_MP_MUL_HIGH_DIGS_C) + #define BN_MP_GROW_C + #define BN_MP_CLAMP_C +#endif + +#if defined(BN_FAST_S_MP_SQR_C) + #define BN_MP_GROW_C + #define BN_MP_CLAMP_C +#endif + +#if defined(BN_MP_2EXPT_C) + #define BN_MP_ZERO_C + #define BN_MP_GROW_C +#endif + +#if defined(BN_MP_ABS_C) + #define BN_MP_COPY_C +#endif + +#if defined(BN_MP_ADD_C) + #define BN_S_MP_ADD_C + #define BN_MP_CMP_MAG_C + #define BN_S_MP_SUB_C +#endif + +#if defined(BN_MP_ADD_D_C) + #define BN_MP_GROW_C + #define BN_MP_SUB_D_C + #define BN_MP_CLAMP_C +#endif + +#if defined(BN_MP_ADDMOD_C) + #define BN_MP_INIT_C + #define BN_MP_ADD_C + #define BN_MP_CLEAR_C + #define BN_MP_MOD_C +#endif + +#if defined(BN_MP_AND_C) + #define BN_MP_INIT_COPY_C + #define BN_MP_CLAMP_C + #define BN_MP_EXCH_C + #define BN_MP_CLEAR_C +#endif + +#if defined(BN_MP_CLAMP_C) +#endif + +#if defined(BN_MP_CLEAR_C) +#endif + +#if defined(BN_MP_CLEAR_MULTI_C) + #define BN_MP_CLEAR_C +#endif + +#if defined(BN_MP_CMP_C) + #define BN_MP_CMP_MAG_C +#endif + +#if defined(BN_MP_CMP_D_C) +#endif + +#if defined(BN_MP_CMP_MAG_C) +#endif + +#if defined(BN_MP_CNT_LSB_C) + #define BN_MP_ISZERO_C +#endif + +#if defined(BN_MP_COPY_C) + #define BN_MP_GROW_C +#endif + +#if defined(BN_MP_COUNT_BITS_C) +#endif + +#if defined(BN_MP_DIV_C) + #define BN_MP_ISZERO_C + #define BN_MP_CMP_MAG_C + #define BN_MP_COPY_C + #define BN_MP_ZERO_C + #define BN_MP_INIT_MULTI_C + #define BN_MP_SET_C + #define BN_MP_COUNT_BITS_C + #define BN_MP_ABS_C + #define BN_MP_MUL_2D_C + #define BN_MP_CMP_C + #define BN_MP_SUB_C + #define BN_MP_ADD_C + #define BN_MP_DIV_2D_C + #define BN_MP_EXCH_C + #define BN_MP_CLEAR_MULTI_C + #define BN_MP_INIT_SIZE_C + #define BN_MP_INIT_C + #define BN_MP_INIT_COPY_C + #define BN_MP_LSHD_C + #define BN_MP_RSHD_C + #define BN_MP_MUL_D_C + #define BN_MP_CLAMP_C + #define BN_MP_CLEAR_C +#endif + +#if defined(BN_MP_DIV_2_C) + #define BN_MP_GROW_C + #define BN_MP_CLAMP_C +#endif + +#if defined(BN_MP_DIV_2D_C) + #define BN_MP_COPY_C + #define BN_MP_ZERO_C + #define BN_MP_INIT_C + #define BN_MP_MOD_2D_C + #define BN_MP_CLEAR_C + #define BN_MP_RSHD_C + #define BN_MP_CLAMP_C + #define BN_MP_EXCH_C +#endif + +#if defined(BN_MP_DIV_3_C) + #define BN_MP_INIT_SIZE_C + #define BN_MP_CLAMP_C + #define BN_MP_EXCH_C + #define BN_MP_CLEAR_C +#endif + +#if defined(BN_MP_DIV_D_C) + #define BN_MP_ISZERO_C + #define BN_MP_COPY_C + #define BN_MP_DIV_2D_C + #define BN_MP_DIV_3_C + #define BN_MP_INIT_SIZE_C + #define BN_MP_CLAMP_C + #define BN_MP_EXCH_C + #define BN_MP_CLEAR_C +#endif + +#if defined(BN_MP_DR_IS_MODULUS_C) +#endif + +#if defined(BN_MP_DR_REDUCE_C) + #define BN_MP_GROW_C + #define BN_MP_CLAMP_C + #define BN_MP_CMP_MAG_C + #define BN_S_MP_SUB_C +#endif + +#if defined(BN_MP_DR_SETUP_C) +#endif + +#if defined(BN_MP_EXCH_C) +#endif + +#if defined(BN_MP_EXPT_D_C) + #define BN_MP_INIT_COPY_C + #define BN_MP_SET_C + #define BN_MP_SQR_C + #define BN_MP_CLEAR_C + #define BN_MP_MUL_C +#endif + +#if defined(BN_MP_EXPTMOD_C) + #define BN_MP_INIT_C + #define BN_MP_INVMOD_C + #define BN_MP_CLEAR_C + #define BN_MP_ABS_C + #define BN_MP_CLEAR_MULTI_C + #define BN_MP_REDUCE_IS_2K_L_C + #define BN_S_MP_EXPTMOD_C + #define BN_MP_DR_IS_MODULUS_C + #define BN_MP_REDUCE_IS_2K_C + #define BN_MP_ISODD_C + #define BN_MP_EXPTMOD_FAST_C +#endif + +#if defined(BN_MP_EXPTMOD_FAST_C) + #define BN_MP_COUNT_BITS_C + #define BN_MP_INIT_C + #define BN_MP_CLEAR_C + #define BN_MP_MONTGOMERY_SETUP_C + #define BN_FAST_MP_MONTGOMERY_REDUCE_C + #define BN_MP_MONTGOMERY_REDUCE_C + #define BN_MP_DR_SETUP_C + #define BN_MP_DR_REDUCE_C + #define BN_MP_REDUCE_2K_SETUP_C + #define BN_MP_REDUCE_2K_C + #define BN_MP_MONTGOMERY_CALC_NORMALIZATION_C + #define BN_MP_MULMOD_C + #define BN_MP_SET_C + #define BN_MP_MOD_C + #define BN_MP_COPY_C + #define BN_MP_SQR_C + #define BN_MP_MUL_C + #define BN_MP_EXCH_C +#endif + +#if defined(BN_MP_EXTEUCLID_C) + #define BN_MP_INIT_MULTI_C + #define BN_MP_SET_C + #define BN_MP_COPY_C + #define BN_MP_ISZERO_C + #define BN_MP_DIV_C + #define BN_MP_MUL_C + #define BN_MP_SUB_C + #define BN_MP_NEG_C + #define BN_MP_EXCH_C + #define BN_MP_CLEAR_MULTI_C +#endif + +#if defined(BN_MP_FREAD_C) + #define BN_MP_ZERO_C + #define BN_MP_S_RMAP_C + #define BN_MP_MUL_D_C + #define BN_MP_ADD_D_C + #define BN_MP_CMP_D_C +#endif + +#if defined(BN_MP_FWRITE_C) + #define BN_MP_RADIX_SIZE_C + #define BN_MP_TORADIX_C +#endif + +#if defined(BN_MP_GCD_C) + #define BN_MP_ISZERO_C + #define BN_MP_ABS_C + #define BN_MP_ZERO_C + #define BN_MP_INIT_COPY_C + #define BN_MP_CNT_LSB_C + #define BN_MP_DIV_2D_C + #define BN_MP_CMP_MAG_C + #define BN_MP_EXCH_C + #define BN_S_MP_SUB_C + #define BN_MP_MUL_2D_C + #define BN_MP_CLEAR_C +#endif + +#if defined(BN_MP_GET_INT_C) +#endif + +#if defined(BN_MP_GROW_C) +#endif + +#if defined(BN_MP_INIT_C) +#endif + +#if defined(BN_MP_INIT_COPY_C) + #define BN_MP_COPY_C +#endif + +#if defined(BN_MP_INIT_MULTI_C) + #define BN_MP_ERR_C + #define BN_MP_INIT_C + #define BN_MP_CLEAR_C +#endif + +#if defined(BN_MP_INIT_SET_C) + #define BN_MP_INIT_C + #define BN_MP_SET_C +#endif + +#if defined(BN_MP_INIT_SET_INT_C) + #define BN_MP_INIT_C + #define BN_MP_SET_INT_C +#endif + +#if defined(BN_MP_INIT_SIZE_C) + #define BN_MP_INIT_C +#endif + +#if defined(BN_MP_INVMOD_C) + #define BN_MP_ISZERO_C + #define BN_MP_ISODD_C + #define BN_FAST_MP_INVMOD_C + #define BN_MP_INVMOD_SLOW_C +#endif + +#if defined(BN_MP_INVMOD_SLOW_C) + #define BN_MP_ISZERO_C + #define BN_MP_INIT_MULTI_C + #define BN_MP_MOD_C + #define BN_MP_COPY_C + #define BN_MP_ISEVEN_C + #define BN_MP_SET_C + #define BN_MP_DIV_2_C + #define BN_MP_ISODD_C + #define BN_MP_ADD_C + #define BN_MP_SUB_C + #define BN_MP_CMP_C + #define BN_MP_CMP_D_C + #define BN_MP_CMP_MAG_C + #define BN_MP_EXCH_C + #define BN_MP_CLEAR_MULTI_C +#endif + +#if defined(BN_MP_IS_SQUARE_C) + #define BN_MP_MOD_D_C + #define BN_MP_INIT_SET_INT_C + #define BN_MP_MOD_C + #define BN_MP_GET_INT_C + #define BN_MP_SQRT_C + #define BN_MP_SQR_C + #define BN_MP_CMP_MAG_C + #define BN_MP_CLEAR_C +#endif + +#if defined(BN_MP_JACOBI_C) + #define BN_MP_CMP_D_C + #define BN_MP_ISZERO_C + #define BN_MP_INIT_COPY_C + #define BN_MP_CNT_LSB_C + #define BN_MP_DIV_2D_C + #define BN_MP_MOD_C + #define BN_MP_CLEAR_C +#endif + +#if defined(BN_MP_KARATSUBA_MUL_C) + #define BN_MP_MUL_C + #define BN_MP_INIT_SIZE_C + #define BN_MP_CLAMP_C + #define BN_MP_SUB_C + #define BN_MP_ADD_C + #define BN_MP_LSHD_C + #define BN_MP_CLEAR_C +#endif + +#if defined(BN_MP_KARATSUBA_SQR_C) + #define BN_MP_INIT_SIZE_C + #define BN_MP_CLAMP_C + #define BN_MP_SQR_C + #define BN_MP_SUB_C + #define BN_S_MP_ADD_C + #define BN_MP_LSHD_C + #define BN_MP_ADD_C + #define BN_MP_CLEAR_C +#endif + +#if defined(BN_MP_LCM_C) + #define BN_MP_INIT_MULTI_C + #define BN_MP_GCD_C + #define BN_MP_CMP_MAG_C + #define BN_MP_DIV_C + #define BN_MP_MUL_C + #define BN_MP_CLEAR_MULTI_C +#endif + +#if defined(BN_MP_LSHD_C) + #define BN_MP_GROW_C + #define BN_MP_RSHD_C +#endif + +#if defined(BN_MP_MOD_C) + #define BN_MP_INIT_C + #define BN_MP_DIV_C + #define BN_MP_CLEAR_C + #define BN_MP_ADD_C + #define BN_MP_EXCH_C +#endif + +#if defined(BN_MP_MOD_2D_C) + #define BN_MP_ZERO_C + #define BN_MP_COPY_C + #define BN_MP_CLAMP_C +#endif + +#if defined(BN_MP_MOD_D_C) + #define BN_MP_DIV_D_C +#endif + +#if defined(BN_MP_MONTGOMERY_CALC_NORMALIZATION_C) + #define BN_MP_COUNT_BITS_C + #define BN_MP_2EXPT_C + #define BN_MP_SET_C + #define BN_MP_MUL_2_C + #define BN_MP_CMP_MAG_C + #define BN_S_MP_SUB_C +#endif + +#if defined(BN_MP_MONTGOMERY_REDUCE_C) + #define BN_FAST_MP_MONTGOMERY_REDUCE_C + #define BN_MP_GROW_C + #define BN_MP_CLAMP_C + #define BN_MP_RSHD_C + #define BN_MP_CMP_MAG_C + #define BN_S_MP_SUB_C +#endif + +#if defined(BN_MP_MONTGOMERY_SETUP_C) +#endif + +#if defined(BN_MP_MUL_C) + #define BN_MP_TOOM_MUL_C + #define BN_MP_KARATSUBA_MUL_C + #define BN_FAST_S_MP_MUL_DIGS_C + #define BN_S_MP_MUL_C + #define BN_S_MP_MUL_DIGS_C +#endif + +#if defined(BN_MP_MUL_2_C) + #define BN_MP_GROW_C +#endif + +#if defined(BN_MP_MUL_2D_C) + #define BN_MP_COPY_C + #define BN_MP_GROW_C + #define BN_MP_LSHD_C + #define BN_MP_CLAMP_C +#endif + +#if defined(BN_MP_MUL_D_C) + #define BN_MP_GROW_C + #define BN_MP_CLAMP_C +#endif + +#if defined(BN_MP_MULMOD_C) + #define BN_MP_INIT_C + #define BN_MP_MUL_C + #define BN_MP_CLEAR_C + #define BN_MP_MOD_C +#endif + +#if defined(BN_MP_N_ROOT_C) + #define BN_MP_INIT_C + #define BN_MP_SET_C + #define BN_MP_COPY_C + #define BN_MP_EXPT_D_C + #define BN_MP_MUL_C + #define BN_MP_SUB_C + #define BN_MP_MUL_D_C + #define BN_MP_DIV_C + #define BN_MP_CMP_C + #define BN_MP_SUB_D_C + #define BN_MP_EXCH_C + #define BN_MP_CLEAR_C +#endif + +#if defined(BN_MP_NEG_C) + #define BN_MP_COPY_C + #define BN_MP_ISZERO_C +#endif + +#if defined(BN_MP_OR_C) + #define BN_MP_INIT_COPY_C + #define BN_MP_CLAMP_C + #define BN_MP_EXCH_C + #define BN_MP_CLEAR_C +#endif + +#if defined(BN_MP_PRIME_FERMAT_C) + #define BN_MP_CMP_D_C + #define BN_MP_INIT_C + #define BN_MP_EXPTMOD_C + #define BN_MP_CMP_C + #define BN_MP_CLEAR_C +#endif + +#if defined(BN_MP_PRIME_IS_DIVISIBLE_C) + #define BN_MP_MOD_D_C +#endif + +#if defined(BN_MP_PRIME_IS_PRIME_C) + #define BN_MP_CMP_D_C + #define BN_MP_PRIME_IS_DIVISIBLE_C + #define BN_MP_INIT_C + #define BN_MP_SET_C + #define BN_MP_PRIME_MILLER_RABIN_C + #define BN_MP_CLEAR_C +#endif + +#if defined(BN_MP_PRIME_MILLER_RABIN_C) + #define BN_MP_CMP_D_C + #define BN_MP_INIT_COPY_C + #define BN_MP_SUB_D_C + #define BN_MP_CNT_LSB_C + #define BN_MP_DIV_2D_C + #define BN_MP_EXPTMOD_C + #define BN_MP_CMP_C + #define BN_MP_SQRMOD_C + #define BN_MP_CLEAR_C +#endif + +#if defined(BN_MP_PRIME_NEXT_PRIME_C) + #define BN_MP_CMP_D_C + #define BN_MP_SET_C + #define BN_MP_SUB_D_C + #define BN_MP_ISEVEN_C + #define BN_MP_MOD_D_C + #define BN_MP_INIT_C + #define BN_MP_ADD_D_C + #define BN_MP_PRIME_MILLER_RABIN_C + #define BN_MP_CLEAR_C +#endif + +#if defined(BN_MP_PRIME_RABIN_MILLER_TRIALS_C) +#endif + +#if defined(BN_MP_PRIME_RANDOM_EX_C) + #define BN_MP_READ_UNSIGNED_BIN_C + #define BN_MP_PRIME_IS_PRIME_C + #define BN_MP_SUB_D_C + #define BN_MP_DIV_2_C + #define BN_MP_MUL_2_C + #define BN_MP_ADD_D_C +#endif + +#if defined(BN_MP_RADIX_SIZE_C) + #define BN_MP_COUNT_BITS_C + #define BN_MP_INIT_COPY_C + #define BN_MP_ISZERO_C + #define BN_MP_DIV_D_C + #define BN_MP_CLEAR_C +#endif + +#if defined(BN_MP_RADIX_SMAP_C) + #define BN_MP_S_RMAP_C +#endif + +#if defined(BN_MP_RAND_C) + #define BN_MP_ZERO_C + #define BN_MP_ADD_D_C + #define BN_MP_LSHD_C +#endif + +#if defined(BN_MP_READ_RADIX_C) + #define BN_MP_ZERO_C + #define BN_MP_S_RMAP_C + #define BN_MP_RADIX_SMAP_C + #define BN_MP_MUL_D_C + #define BN_MP_ADD_D_C + #define BN_MP_ISZERO_C +#endif + +#if defined(BN_MP_READ_SIGNED_BIN_C) + #define BN_MP_READ_UNSIGNED_BIN_C +#endif + +#if defined(BN_MP_READ_UNSIGNED_BIN_C) + #define BN_MP_GROW_C + #define BN_MP_ZERO_C + #define BN_MP_MUL_2D_C + #define BN_MP_CLAMP_C +#endif + +#if defined(BN_MP_REDUCE_C) + #define BN_MP_REDUCE_SETUP_C + #define BN_MP_INIT_COPY_C + #define BN_MP_RSHD_C + #define BN_MP_MUL_C + #define BN_S_MP_MUL_HIGH_DIGS_C + #define BN_FAST_S_MP_MUL_HIGH_DIGS_C + #define BN_MP_MOD_2D_C + #define BN_S_MP_MUL_DIGS_C + #define BN_MP_SUB_C + #define BN_MP_CMP_D_C + #define BN_MP_SET_C + #define BN_MP_LSHD_C + #define BN_MP_ADD_C + #define BN_MP_CMP_C + #define BN_S_MP_SUB_C + #define BN_MP_CLEAR_C +#endif + +#if defined(BN_MP_REDUCE_2K_C) + #define BN_MP_INIT_C + #define BN_MP_COUNT_BITS_C + #define BN_MP_DIV_2D_C + #define BN_MP_MUL_D_C + #define BN_S_MP_ADD_C + #define BN_MP_CMP_MAG_C + #define BN_S_MP_SUB_C + #define BN_MP_CLEAR_C +#endif + +#if defined(BN_MP_REDUCE_2K_L_C) + #define BN_MP_INIT_C + #define BN_MP_COUNT_BITS_C + #define BN_MP_DIV_2D_C + #define BN_MP_MUL_C + #define BN_S_MP_ADD_C + #define BN_MP_CMP_MAG_C + #define BN_S_MP_SUB_C + #define BN_MP_CLEAR_C +#endif + +#if defined(BN_MP_REDUCE_2K_SETUP_C) + #define BN_MP_INIT_C + #define BN_MP_COUNT_BITS_C + #define BN_MP_2EXPT_C + #define BN_MP_CLEAR_C + #define BN_S_MP_SUB_C +#endif + +#if defined(BN_MP_REDUCE_2K_SETUP_L_C) + #define BN_MP_INIT_C + #define BN_MP_2EXPT_C + #define BN_MP_COUNT_BITS_C + #define BN_S_MP_SUB_C + #define BN_MP_CLEAR_C +#endif + +#if defined(BN_MP_REDUCE_IS_2K_C) + #define BN_MP_REDUCE_2K_C + #define BN_MP_COUNT_BITS_C +#endif + +#if defined(BN_MP_REDUCE_IS_2K_L_C) +#endif + +#if defined(BN_MP_REDUCE_SETUP_C) + #define BN_MP_2EXPT_C + #define BN_MP_DIV_C +#endif + +#if defined(BN_MP_RSHD_C) + #define BN_MP_ZERO_C +#endif + +#if defined(BN_MP_SET_C) + #define BN_MP_ZERO_C +#endif + +#if defined(BN_MP_SET_INT_C) + #define BN_MP_ZERO_C + #define BN_MP_MUL_2D_C + #define BN_MP_CLAMP_C +#endif + +#if defined(BN_MP_SHRINK_C) +#endif + +#if defined(BN_MP_SIGNED_BIN_SIZE_C) + #define BN_MP_UNSIGNED_BIN_SIZE_C +#endif + +#if defined(BN_MP_SQR_C) + #define BN_MP_TOOM_SQR_C + #define BN_MP_KARATSUBA_SQR_C + #define BN_FAST_S_MP_SQR_C + #define BN_S_MP_SQR_C +#endif + +#if defined(BN_MP_SQRMOD_C) + #define BN_MP_INIT_C + #define BN_MP_SQR_C + #define BN_MP_CLEAR_C + #define BN_MP_MOD_C +#endif + +#if defined(BN_MP_SQRT_C) + #define BN_MP_N_ROOT_C + #define BN_MP_ISZERO_C + #define BN_MP_ZERO_C + #define BN_MP_INIT_COPY_C + #define BN_MP_RSHD_C + #define BN_MP_DIV_C + #define BN_MP_ADD_C + #define BN_MP_DIV_2_C + #define BN_MP_CMP_MAG_C + #define BN_MP_EXCH_C + #define BN_MP_CLEAR_C +#endif + +#if defined(BN_MP_SUB_C) + #define BN_S_MP_ADD_C + #define BN_MP_CMP_MAG_C + #define BN_S_MP_SUB_C +#endif + +#if defined(BN_MP_SUB_D_C) + #define BN_MP_GROW_C + #define BN_MP_ADD_D_C + #define BN_MP_CLAMP_C +#endif + +#if defined(BN_MP_SUBMOD_C) + #define BN_MP_INIT_C + #define BN_MP_SUB_C + #define BN_MP_CLEAR_C + #define BN_MP_MOD_C +#endif + +#if defined(BN_MP_TO_SIGNED_BIN_C) + #define BN_MP_TO_UNSIGNED_BIN_C +#endif + +#if defined(BN_MP_TO_SIGNED_BIN_N_C) + #define BN_MP_SIGNED_BIN_SIZE_C + #define BN_MP_TO_SIGNED_BIN_C +#endif + +#if defined(BN_MP_TO_UNSIGNED_BIN_C) + #define BN_MP_INIT_COPY_C + #define BN_MP_ISZERO_C + #define BN_MP_DIV_2D_C + #define BN_MP_CLEAR_C +#endif + +#if defined(BN_MP_TO_UNSIGNED_BIN_N_C) + #define BN_MP_UNSIGNED_BIN_SIZE_C + #define BN_MP_TO_UNSIGNED_BIN_C +#endif + +#if defined(BN_MP_TOOM_MUL_C) + #define BN_MP_INIT_MULTI_C + #define BN_MP_MOD_2D_C + #define BN_MP_COPY_C + #define BN_MP_RSHD_C + #define BN_MP_MUL_C + #define BN_MP_MUL_2_C + #define BN_MP_ADD_C + #define BN_MP_SUB_C + #define BN_MP_DIV_2_C + #define BN_MP_MUL_2D_C + #define BN_MP_MUL_D_C + #define BN_MP_DIV_3_C + #define BN_MP_LSHD_C + #define BN_MP_CLEAR_MULTI_C +#endif + +#if defined(BN_MP_TOOM_SQR_C) + #define BN_MP_INIT_MULTI_C + #define BN_MP_MOD_2D_C + #define BN_MP_COPY_C + #define BN_MP_RSHD_C + #define BN_MP_SQR_C + #define BN_MP_MUL_2_C + #define BN_MP_ADD_C + #define BN_MP_SUB_C + #define BN_MP_DIV_2_C + #define BN_MP_MUL_2D_C + #define BN_MP_MUL_D_C + #define BN_MP_DIV_3_C + #define BN_MP_LSHD_C + #define BN_MP_CLEAR_MULTI_C +#endif + +#if defined(BN_MP_TORADIX_C) + #define BN_MP_ISZERO_C + #define BN_MP_INIT_COPY_C + #define BN_MP_DIV_D_C + #define BN_MP_CLEAR_C + #define BN_MP_S_RMAP_C +#endif + +#if defined(BN_MP_TORADIX_N_C) + #define BN_MP_ISZERO_C + #define BN_MP_INIT_COPY_C + #define BN_MP_DIV_D_C + #define BN_MP_CLEAR_C + #define BN_MP_S_RMAP_C +#endif + +#if defined(BN_MP_UNSIGNED_BIN_SIZE_C) + #define BN_MP_COUNT_BITS_C +#endif + +#if defined(BN_MP_XOR_C) + #define BN_MP_INIT_COPY_C + #define BN_MP_CLAMP_C + #define BN_MP_EXCH_C + #define BN_MP_CLEAR_C +#endif + +#if defined(BN_MP_ZERO_C) +#endif + +#if defined(BN_PRIME_TAB_C) +#endif + +#if defined(BN_REVERSE_C) +#endif + +#if defined(BN_S_MP_ADD_C) + #define BN_MP_GROW_C + #define BN_MP_CLAMP_C +#endif + +#if defined(BN_S_MP_EXPTMOD_C) + #define BN_MP_COUNT_BITS_C + #define BN_MP_INIT_C + #define BN_MP_CLEAR_C + #define BN_MP_REDUCE_SETUP_C + #define BN_MP_REDUCE_C + #define BN_MP_REDUCE_2K_SETUP_L_C + #define BN_MP_REDUCE_2K_L_C + #define BN_MP_MOD_C + #define BN_MP_COPY_C + #define BN_MP_SQR_C + #define BN_MP_MUL_C + #define BN_MP_SET_C + #define BN_MP_EXCH_C +#endif + +#if defined(BN_S_MP_MUL_DIGS_C) + #define BN_FAST_S_MP_MUL_DIGS_C + #define BN_MP_INIT_SIZE_C + #define BN_MP_CLAMP_C + #define BN_MP_EXCH_C + #define BN_MP_CLEAR_C +#endif + +#if defined(BN_S_MP_MUL_HIGH_DIGS_C) + #define BN_FAST_S_MP_MUL_HIGH_DIGS_C + #define BN_MP_INIT_SIZE_C + #define BN_MP_CLAMP_C + #define BN_MP_EXCH_C + #define BN_MP_CLEAR_C +#endif + +#if defined(BN_S_MP_SQR_C) + #define BN_MP_INIT_SIZE_C + #define BN_MP_CLAMP_C + #define BN_MP_EXCH_C + #define BN_MP_CLEAR_C +#endif + +#if defined(BN_S_MP_SUB_C) + #define BN_MP_GROW_C + #define BN_MP_CLAMP_C +#endif + +#if defined(BNCORE_C) +#endif + +#ifdef LTM3 +#define LTM_LAST +#endif +#include "mpi_superclass.h" +#include "mpi_class.h" +#else +#define LTM_LAST +#endif + diff --git a/ctaocrypt/include/mpi_superclass.h b/ctaocrypt/include/mpi_superclass.h new file mode 100644 index 000000000..a7d16f017 --- /dev/null +++ b/ctaocrypt/include/mpi_superclass.h @@ -0,0 +1,73 @@ +/* super class file for PK algos */ + +/* default ... include all MPI */ +#define LTM_ALL + +/* RSA only (does not support DH/DSA/ECC) */ +/* #define SC_RSA_1 */ + +/* For reference.... On an Athlon64 optimizing for speed... + + LTM's mpi.o with all functions [striped] is 142KiB in size. + +*/ + +/* Works for RSA only, mpi.o is 68KiB */ +#ifdef SC_RSA_1 + #define BN_MP_SHRINK_C + #define BN_MP_LCM_C + #define BN_MP_PRIME_RANDOM_EX_C + #define BN_MP_INVMOD_C + #define BN_MP_GCD_C + #define BN_MP_MOD_C + #define BN_MP_MULMOD_C + #define BN_MP_ADDMOD_C + #define BN_MP_EXPTMOD_C + #define BN_MP_SET_INT_C + #define BN_MP_INIT_MULTI_C + #define BN_MP_CLEAR_MULTI_C + #define BN_MP_UNSIGNED_BIN_SIZE_C + #define BN_MP_TO_UNSIGNED_BIN_C + #define BN_MP_MOD_D_C + #define BN_MP_PRIME_RABIN_MILLER_TRIALS_C + #define BN_REVERSE_C + #define BN_PRIME_TAB_C + + /* other modifiers */ + #define BN_MP_DIV_SMALL /* Slower division, not critical */ + + /* here we are on the last pass so we turn things off. The functions classes are still there + * but we remove them specifically from the build. This also invokes tweaks in functions + * like removing support for even moduli, etc... + */ +#ifdef LTM_LAST + #undef BN_MP_TOOM_MUL_C + #undef BN_MP_TOOM_SQR_C + #undef BN_MP_KARATSUBA_MUL_C + #undef BN_MP_KARATSUBA_SQR_C + #undef BN_MP_REDUCE_C + #undef BN_MP_REDUCE_SETUP_C + #undef BN_MP_DR_IS_MODULUS_C + #undef BN_MP_DR_SETUP_C + #undef BN_MP_DR_REDUCE_C + #undef BN_MP_REDUCE_IS_2K_C + #undef BN_MP_REDUCE_2K_SETUP_C + #undef BN_MP_REDUCE_2K_C + #undef BN_S_MP_EXPTMOD_C + #undef BN_MP_DIV_3_C + #undef BN_S_MP_MUL_HIGH_DIGS_C + #undef BN_FAST_S_MP_MUL_HIGH_DIGS_C + #undef BN_FAST_MP_INVMOD_C + + /* To safely undefine these you have to make sure your RSA key won't exceed the Comba threshold + * which is roughly 255 digits [7140 bits for 32-bit machines, 15300 bits for 64-bit machines] + * which means roughly speaking you can handle upto 2536-bit RSA keys with these defined without + * trouble. + */ + #undef BN_S_MP_MUL_DIGS_C + #undef BN_S_MP_SQR_C + #undef BN_MP_MONTGOMERY_REDUCE_C +#endif + +#endif + diff --git a/ctaocrypt/include/os_settings.h b/ctaocrypt/include/os_settings.h new file mode 100644 index 000000000..f74c12f8d --- /dev/null +++ b/ctaocrypt/include/os_settings.h @@ -0,0 +1,268 @@ +/* os_settings.h + * + * Copyright (C) 2006-2011 Sawtooth Consulting Ltd. + * + * This file is part of CyaSSL. + * + * CyaSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * CyaSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +/* Place OS specific preprocessor flags, defines, includes here, will be + included into every file because types.h includes it */ + +#ifndef CTAO_CRYPT_OS_SETTINGS_H +#define CTAO_CRYPT_OS_SETTINGS_H + +#ifdef __cplusplus + extern "C" { +#endif + +/* Uncomment next line if using IPHONE */ +/* #define IPHONE */ + +/* Uncomment next line if using ThreadX */ +/* #define THREADX */ + +/* Uncomment next line if using Micrium ucOS */ +/* #define MICRIUM */ + +/* Uncomment next line if using Mbed */ +/* #define MBED */ + + +#ifdef IPHONE + #define SIZEOF_LONG_LONG 8 +#endif + +#ifdef THREADX + #define SIZEOF_LONG_LONG 8 +#endif + +#ifdef MBED + #define SINGLE_THREADED + #define CYASSL_USER_IO + #define NO_WRITEV + #define NO_DEV_RANDOM + #define NO_SHA512 + #define NO_DH + #define NO_DSA + #define NO_HC128 +#endif /* MBED */ + + +#ifdef MICRIUM + + #include "net_cfg.h" + #include "ssl_cfg.h" + #include "net_secure_os.h" + + #define CYASSL_TYPES + + typedef CPU_INT08U byte; + typedef CPU_INT16U word16; + typedef CPU_INT32U word32; + + #if (NET_SECURE_MGR_CFG_WORD_SIZE == CPU_WORD_SIZE_32) + #define SIZEOF_LONG 4 + #undef SIZEOF_LONG_LONG + #else + #undef SIZEOF_LONG + #define SIZEOF_LONG_LONG 8 + #endif + + #define STRING_USER + + #define XSTRLEN(pstr) ((CPU_SIZE_T)Str_Len((CPU_CHAR *)(pstr))) + #define XSTRNCPY(pstr_dest, pstr_src, len_max) \ + ((CPU_CHAR *)Str_Copy_N((CPU_CHAR *)(pstr_dest), \ + (CPU_CHAR *)(pstr_src), (CPU_SIZE_T)(len_max))) + #define XSTRNCMP(pstr_1, pstr_2, len_max) \ + ((CPU_INT16S)Str_Cmp_N((CPU_CHAR *)(pstr_1), \ + (CPU_CHAR *)(pstr_2), (CPU_SIZE_T)(len_max))) + #define XSTRSTR(pstr, pstr_srch) \ + ((CPU_CHAR *)Str_Str((CPU_CHAR *)(pstr), \ + (CPU_CHAR *)(pstr_srch))) + #define XMEMSET(pmem, data_val, size) \ + ((void)Mem_Set((void *)(pmem), (CPU_INT08U) (data_val), \ + (CPU_SIZE_T)(size))) + #define XMEMCPY(pdest, psrc, size) ((void)Mem_Copy((void *)(pdest), \ + (void *)(psrc), (CPU_SIZE_T)(size))) + #define XMEMCMP(pmem_1, pmem_2, size) \ + (((CPU_BOOLEAN)Mem_Cmp((void *)(pmem_1), (void *)(pmem_2), \ + (CPU_SIZE_T)(size))) ? DEF_NO : DEF_YES) + #define XMEMMOVE XMEMCPY + +#if (NET_SECURE_MGR_CFG_EN == DEF_ENABLED) + #define MICRIUM_MALLOC + #define XMALLOC(s, h, type) ((void *)NetSecure_BlkGet((CPU_INT08U)(type), \ + (CPU_SIZE_T)(s), (void *)0)) + #define XFREE(p, h, type) (NetSecure_BlkFree((CPU_INT08U)(type), \ + (p), (void *)0)) + #define XREALLOC(p, n, h, t) realloc((p), (n)) +#endif + + #if (NET_SECURE_MGR_CFG_FS_EN == DEF_ENABLED) + #undef NO_FILESYSTEM + #else + #define NO_FILESYSTEM + #endif + + #if (SSL_CFG_TRACE_LEVEL == CYASSL_TRACE_LEVEL_DBG) + #define DEBUG_CYASSL + #else + #undef DEBUG_CYASSL + #endif + + #if (SSL_CFG_OPENSSL_EN == DEF_ENABLED) + #define OPENSSL_EXTRA + #else + #undef OPENSSL_EXTRA + #endif + + #if (SSL_CFG_MULTI_THREAD_EN == DEF_ENABLED) + #undef SINGLE_THREADED + #else + #define SINGLE_THREADED + #endif + + #if (SSL_CFG_DH_EN == DEF_ENABLED) + #undef NO_DH + #else + #define NO_DH + #endif + + #if (SSL_CFG_DSA_EN == DEF_ENABLED) + #undef NO_DSA + #else + #define NO_DSA + #endif + + #if (SSL_CFG_PSK_EN == DEF_ENABLED) + #undef NO_PSK + #else + #define NO_PSK + #endif + + #if (SSL_CFG_3DES_EN == DEF_ENABLED) + #undef NO_DES + #else + #define NO_DES + #endif + + #if (SSL_CFG_AES_EN == DEF_ENABLED) + #undef NO_AES + #else + #define NO_AES + #endif + + #if (SSL_CFG_RC4_EN == DEF_ENABLED) + #undef NO_RC4 + #else + #define NO_RC4 + #endif + + #if (SSL_CFG_RABBIT_EN == DEF_ENABLED) + #undef NO_RABBIT + #else + #define NO_RABBIT + #endif + + #if (SSL_CFG_HC128_EN == DEF_ENABLED) + #undef NO_HC128 + #else + #define NO_HC128 + #endif + + #if (CPU_CFG_ENDIAN_TYPE == CPU_ENDIAN_TYPE_BIG) + #define BIG_ENDIAN_ORDER + #else + #undef BIG_ENDIAN_ORDER + #define LITTLE_ENDIAN_ORDER + #endif + + #if (SSL_CFG_MD4_EN == DEF_ENABLED) + #undef NO_MD4 + #else + #define NO_MD4 + #endif + + #if (SSL_CFG_WRITEV_EN == DEF_ENABLED) + #undef NO_WRITEV + #else + #define NO_WRITEV + #endif + + #if (SSL_CFG_USER_RNG_SEED_EN == DEF_ENABLED) + #define NO_DEV_RANDOM + #else + #undef NO_DEV_RANDOM + #endif + + #if (SSL_CFG_USER_IO_EN == DEF_ENABLED) + #define CYASSL_USER_IO + #else + #undef CYASSL_USER_IO + #endif + + #if (SSL_CFG_DYNAMIC_BUFFERS_EN == DEF_ENABLED) + #undef LARGE_STATIC_BUFFERS + #undef STATIC_CHUNKS_ONLY + #else + #define LARGE_STATIC_BUFFERS + #define STATIC_CHUNKS_ONLY + #endif + + #if (SSL_CFG_DER_LOAD_EN == DEF_ENABLED) + #define CYASSL_DER_LOAD + #else + #undef CYASSL_DER_LOAD + #endif + + #if (SSL_CFG_DTLS_EN == DEF_ENABLED) + #define CYASSL_DTLS + #else + #undef CYASSL_DTLS + #endif + + #if (SSL_CFG_CALLBACKS_EN == DEF_ENABLED) + #define CYASSL_CALLBACKS + #else + #undef CYASSL_CALLBACKS + #endif + + #if (SSL_CFG_FAST_MATH_EN == DEF_ENABLED) + #define USE_FAST_MATH + #else + #undef USE_FAST_MATH + #endif + + #if (SSL_CFG_TFM_TIMING_RESISTANT_EN == DEF_ENABLED) + #define TFM_TIMING_RESISTANT + #else + #undef TFM_TIMING_RESISTANT + #endif + +#endif /* MICRIUM */ + +/* Place any other flags or defines here */ + + +#ifdef __cplusplus + } /* extern "C" */ +#endif + + +#endif /* CTAO_CRYPT_OS_SETTINGS_H */ + diff --git a/ctaocrypt/include/pwdbased.h b/ctaocrypt/include/pwdbased.h new file mode 100644 index 000000000..431948975 --- /dev/null +++ b/ctaocrypt/include/pwdbased.h @@ -0,0 +1,47 @@ +/* pwdbased.h + * + * Copyright (C) 2006-2011 Sawtooth Consulting Ltd. + * + * This file is part of CyaSSL. + * + * CyaSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * CyaSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + + +#ifndef NO_PWDBASED + +#ifndef CTAO_CRYPT_PWDBASED_H +#define CTAO_CRYPT_PWDBASED_H + +#include "types.h" +#include "ctc_md5.h" /* for hash type */ +#include "ctc_sha.h" + +#ifdef __cplusplus + extern "C" { +#endif + + +int PBKDF1(byte* output, const byte* passwd, int pLen, const byte* salt, + int sLen, int iterations, int kLen, int hashType); + + + +#ifdef __cplusplus + } /* extern "C" */ +#endif + +#endif /* CTAO_CRYPT_PWDBASED_H */ +#endif /* NO_PWDBASED */ diff --git a/ctaocrypt/include/rabbit.h b/ctaocrypt/include/rabbit.h new file mode 100644 index 000000000..dd9165dd1 --- /dev/null +++ b/ctaocrypt/include/rabbit.h @@ -0,0 +1,60 @@ +/* rabbit.h + * + * Copyright (C) 2006-2011 Sawtooth Consulting Ltd. + * + * This file is part of CyaSSL. + * + * CyaSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * CyaSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + + +#ifndef NO_RABBIT + +#ifndef CTAO_CRYPT_RABBIT_H +#define CTAO_CRYPT_RABBIT_H + +#include "types.h" + +#ifdef __cplusplus + extern "C" { +#endif + + +/* Rabbit Context */ +typedef struct RabbitCtx { + word32 x[8]; + word32 c[8]; + word32 carry; +} RabbitCtx; + + +/* Rabbit stream cipher */ +typedef struct Rabbit { + RabbitCtx masterCtx; + RabbitCtx workCtx; +} Rabbit; + + +void RabbitProcess(Rabbit*, byte*, const byte*, word32); +void RabbitSetKey(Rabbit*, const byte* key, const byte* iv); + + +#ifdef __cplusplus + } /* extern "C" */ +#endif + +#endif /* CTAO_CRYPT_RABBIT_H */ + +#endif /* NO_RABBIT */ diff --git a/ctaocrypt/include/random.h b/ctaocrypt/include/random.h new file mode 100644 index 000000000..f153b1e8b --- /dev/null +++ b/ctaocrypt/include/random.h @@ -0,0 +1,72 @@ +/* random.h + * + * Copyright (C) 2006-2011 Sawtooth Consulting Ltd. + * + * This file is part of CyaSSL. + * + * CyaSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * CyaSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + + +#ifndef CTAO_CRYPT_RANDOM_H +#define CTAO_CRYPT_RANDOM_H + +#include "arc4.h" + +#ifdef __cplusplus + extern "C" { +#endif + + +#if defined(USE_WINDOWS_API) + #if defined(_WIN64) + typedef unsigned __int64 ProviderHandle; + /* type HCRYPTPROV, avoid #include */ + #else + typedef unsigned long ProviderHandle; + #endif +#endif + + +/* OS specific seeder */ +typedef struct OS_Seed { + #if defined(USE_WINDOWS_API) + ProviderHandle handle; + #else + int fd; + #endif +} OS_Seed; + +int GenerateSeed(OS_Seed* os, byte* seed, word32 sz); + + +/* secure Random Nnumber Generator */ +typedef struct RNG { + OS_Seed seed; + Arc4 cipher; +} RNG; + + +int InitRng(RNG*); +void RNG_GenerateBlock(RNG*, byte*, word32 sz); +byte RNG_GenerateByte(RNG*); + + +#ifdef __cplusplus + } /* extern "C" */ +#endif + +#endif /* CTAO_CRYPT_RANDOM_H */ + diff --git a/ctaocrypt/include/sha256.h b/ctaocrypt/include/sha256.h new file mode 100644 index 000000000..811b6f698 --- /dev/null +++ b/ctaocrypt/include/sha256.h @@ -0,0 +1,69 @@ +/* sha256.h + * + * Copyright (C) 2006-2011 Sawtooth Consulting Ltd. + * + * This file is part of CyaSSL. + * + * CyaSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * CyaSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + + +/* code submitted by raphael.huck@efixo.com */ + + +#ifndef NO_SHA256 + +#ifndef CTAO_CRYPT_SHA256_H +#define CTAO_CRYPT_SHA256_H + +#include "types.h" + +#ifdef __cplusplus + extern "C" { +#endif + + + +/* in bytes */ +enum { + SHA256 = 2, /* hash type unique */ + SHA256_BLOCK_SIZE = 64, + SHA256_DIGEST_SIZE = 32, + SHA256_PAD_SIZE = 56 +}; + + +/* Sha256 digest */ +typedef struct Sha256 { + word32 buffLen; /* in bytes */ + word32 loLen; /* length in bytes */ + word32 hiLen; /* length in bytes */ + word32 digest[SHA256_DIGEST_SIZE / sizeof(word32)]; + word32 buffer[SHA256_BLOCK_SIZE / sizeof(word32)]; +} Sha256; + + +void InitSha256(Sha256*); +void Sha256Update(Sha256*, const byte*, word32); +void Sha256Final(Sha256*, byte*); + + +#ifdef __cplusplus + } /* extern "C" */ +#endif + +#endif /* CTAO_CRYPT_SHA256_H */ +#endif /* NO_SHA256 */ + diff --git a/ctaocrypt/include/sha512.h b/ctaocrypt/include/sha512.h new file mode 100644 index 000000000..f892a4fb2 --- /dev/null +++ b/ctaocrypt/include/sha512.h @@ -0,0 +1,65 @@ +/* sha512.h + * + * Copyright (C) 2006-2011 Sawtooth Consulting Ltd. + * + * This file is part of CyaSSL. + * + * CyaSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * CyaSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + + +#ifdef CYASSL_SHA512 + +#ifndef CTAO_CRYPT_SHA512_H +#define CTAO_CRYPT_SHA512_H + +#include "types.h" + +#ifdef __cplusplus + extern "C" { +#endif + + + +/* in bytes */ +enum { + SHA512 = 4, /* hash type unique */ + SHA512_BLOCK_SIZE = 128, + SHA512_DIGEST_SIZE = 64, + SHA512_PAD_SIZE = 112 +}; + + +/* Sha512 digest */ +typedef struct Sha512 { + word32 buffLen; /* in bytes */ + word32 loLen; /* length in bytes */ + word32 hiLen; /* length in bytes */ + word64 digest[SHA512_DIGEST_SIZE / sizeof(word64)]; + word64 buffer[SHA512_BLOCK_SIZE / sizeof(word64)]; +} Sha512; + + +void InitSha512(Sha512*); +void Sha512Update(Sha512*, const byte*, word32); +void Sha512Final(Sha512*, byte*); + + +#ifdef __cplusplus + } /* extern "C" */ +#endif + +#endif /* CTAO_CRYPT_SHA512_H */ +#endif /* CYASSL_SHA512 */ diff --git a/ctaocrypt/include/tfm.h b/ctaocrypt/include/tfm.h new file mode 100644 index 000000000..75eb15c09 --- /dev/null +++ b/ctaocrypt/include/tfm.h @@ -0,0 +1,667 @@ +/* tfm.h + * + * Copyright (C) 2006-2011 Sawtooth Consulting Ltd. + * + * This file is part of CyaSSL. + * + * CyaSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * CyaSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + + + +/* + * Based on public domain TomsFastMath 0.10 by Tom St Denis, tomstdenis@iahu.ca, + * http://math.libtomcrypt.com + */ + + +/** + * Edited by Moisés Guimarães (moises.guimaraes@phoebus.com.br) + * to fit CyaSSL's needs. + */ + + +#ifndef CTAO_CRYPT_TFM_H +#define CTAO_CRYPT_TFM_H + +#include "types.h" +#ifndef CHAR_BIT + #include +#endif + + +#ifdef __cplusplus + extern "C" { +#endif + +#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 ;-) + */ +/* need to refactor the function */ +/*#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 +#ifdef TFM_SMALL_SET +#define TFM_MUL20 +#define TFM_MUL24 +#define TFM_MUL28 +#define TFM_MUL32 +#define TFM_MUL48 +#define TFM_MUL64 +#endif + +#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 +#ifdef TFM_SMALL_SET +#define TFM_SQR20 +#define TFM_SQR24 +#define TFM_SQR28 +#define TFM_SQR32 +#define TFM_SQR48 +#define TFM_SQR64 +#endif + +/* 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 (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 + +/* 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 + + +/* some default configurations. + */ +#if defined(FP_64BIT) + /* for GCC only on supported platforms */ +#ifndef CRYPT + typedef unsigned long ulong64; +#endif + typedef ulong64 fp_digit; + 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 +#endif + typedef unsigned long fp_digit; + typedef ulong64 fp_word; +#endif + +/* # of digits this is */ +#define DIGIT_BIT (int)((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)XMEMSET((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); + +/* copy from a to b */ +#define fp_copy(a, b) (void)(((a) != (b)) ? (XMEMCPY((b), (a), sizeof(fp_int))) : (void)0) +#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);*/ + +/* 256 trial divisions + 8 Miller-Rabins, returns FP_YES if probable prime */ +/*int fp_isprime(fp_int *a);*/ + +/* 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, 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, unsigned char *b, int c);*/ +/*void fp_to_signed_bin(fp_int *a, unsigned char *b);*/ + +/*int fp_read_radix(fp_int *a, char *str, int radix);*/ +/*int fp_toradix(fp_int *a, char *str, int radix);*/ +/*int fp_toradix_n(fp_int * a, char *str, int radix, int maxlen);*/ + + +/* 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;*/ + + +/** + * Used by CyaSSL + */ + +/* Types */ + typedef fp_digit mp_digit; + typedef fp_word mp_word; + typedef fp_int mp_int; + +/* Constants */ + #define MP_LT FP_LT /* less than */ + #define MP_EQ FP_EQ /* equal to */ + #define MP_GT FP_GT /* greater than */ + #define MP_OKAY FP_OKAY /* ok result */ + #define MP_NO FP_NO /* yes/no result */ + #define MP_YES FP_YES /* yes/no result */ + +/* Prototypes */ +int mp_init (mp_int * a); +void mp_clear (mp_int * a); +int mp_init_multi(mp_int* a, mp_int* b, mp_int* c, mp_int* d, mp_int* e, mp_int* f); + +int mp_add (mp_int * a, mp_int * b, mp_int * c); +int mp_sub (mp_int * a, mp_int * b, mp_int * c); + +int mp_mul (mp_int * a, mp_int * b, mp_int * c); +int mp_mulmod (mp_int * a, mp_int * b, mp_int * c, mp_int * d); +int mp_mod(mp_int *a, mp_int *b, mp_int *c); +int mp_invmod(mp_int *a, mp_int *b, mp_int *c); +int mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y); + +int mp_cmp(mp_int *a, mp_int *b); +int mp_cmp_d(mp_int *a, mp_digit b); + +int mp_unsigned_bin_size(mp_int * a); +int mp_read_unsigned_bin (mp_int * a, const unsigned char *b, int c); +int mp_to_unsigned_bin (mp_int * a, unsigned char *b); + +#ifdef HAVE_ECC + int mp_sqrmod(mp_int* a, mp_int* b, mp_int* c); + int mp_montgomery_calc_normalization(mp_int *a, mp_int *b); + int mp_read_radix(mp_int* a, const char* str, int radix); + int mp_iszero(mp_int* a); + int mp_set(fp_int *a, fp_digit b); + int mp_sqr(fp_int *A, fp_int *B); + int mp_montgomery_reduce(fp_int *a, fp_int *m, fp_digit mp); + int mp_montgomery_setup(fp_int *a, fp_digit *rho); + int mp_isodd(mp_int* a); + int mp_div_2(fp_int * a, fp_int * b); +#endif + +#if defined(HAVE_ECC) || defined(CYASSL_KEY_GEN) + int mp_copy(fp_int* a, fp_int* b); +#endif + +#ifdef CYASSL_KEY_GEN +int mp_set_int(fp_int *a, fp_digit b); +int mp_gcd(fp_int *a, fp_int *b, fp_int *c); +int mp_lcm(fp_int *a, fp_int *b, fp_int *c); +int mp_sub_d(fp_int *a, fp_digit b, fp_int *c); +int mp_prime_is_prime(mp_int* a, int t, int* result); +#endif /* CYASSL_KEY_GEN */ + +#ifdef __cplusplus + } +#endif + + +#endif /* CTAO_CRYPT_TFM_H */ diff --git a/ctaocrypt/include/types.h b/ctaocrypt/include/types.h new file mode 100644 index 000000000..fd8e5bcac --- /dev/null +++ b/ctaocrypt/include/types.h @@ -0,0 +1,198 @@ +/* types.h + * + * Copyright (C) 2006-2011 Sawtooth Consulting Ltd. + * + * This file is part of CyaSSL. + * + * CyaSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * CyaSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + + +#ifndef CTAO_CRYPT_TYPES_H +#define CTAO_CRYPT_TYPES_H + +#include "os_settings.h" + +#ifdef HAVE_CONFIG_H + #include "config.h" +#endif + +#ifdef __cplusplus + extern "C" { +#endif + + +#if defined(WORDS_BIGENDIAN) || (defined(__MWERKS__) && !defined(__INTEL__)) + #define BIG_ENDIAN_ORDER +#endif + +#ifndef BIG_ENDIAN_ORDER + #define LITTLE_ENDIAN_ORDER +#endif + +#ifndef CYASSL_TYPES + typedef unsigned char byte; + typedef unsigned short word16; + typedef unsigned int word32; +#endif + +#if defined(_MSC_VER) || defined(__BCPLUSPLUS__) + #define WORD64_AVAILABLE + #define W64LIT(x) x##ui64 + typedef unsigned __int64 word64; +#elif SIZEOF_LONG == 8 + #define WORD64_AVAILABLE + #define W64LIT(x) x##LL + typedef unsigned long word64; +#elif SIZEOF_LONG_LONG == 8 + #define WORD64_AVAILABLE + #define W64LIT(x) x##LL + typedef unsigned long long word64; +#else + #define MP_16BIT /* for mp_int, mp_word needs to be twice as big as + mp_digit, no 64 bit type so make mp_digit 16 bit */ +#endif + + +/* These platforms have 64-bit CPU registers. */ +#if (defined(__alpha__) || defined(__ia64__) || defined(_ARCH_PPC64) || \ + defined(__mips64) || defined(__x86_64__)) + typedef word64 word; +#else + typedef word32 word; + #ifdef WORD64_AVAILABLE + #define CTAOCRYPT_SLOW_WORD64 + #endif +#endif + + +enum { + WORD_SIZE = sizeof(word), + BIT_SIZE = 8, + WORD_BITS = WORD_SIZE * BIT_SIZE +}; + + +/* use inlining if compiler allows */ +#ifndef INLINE +#ifndef NO_INLINE + #ifdef _MSC_VER + #define INLINE __inline + #elif defined(__GNUC__) + #define INLINE inline + #elif defined(THREADX) + #define INLINE _Inline + #else + #define INLINE + #endif +#else + #define INLINE +#endif +#endif + + +/* set up rotate style */ +#if defined(_MSC_VER) || defined(__BCPLUSPLUS__) + #define INTEL_INTRINSICS + #define FAST_ROTATE +#elif defined(__MWERKS__) && TARGET_CPU_PPC + #define PPC_INTRINSICS + #define FAST_ROTATE +#elif defined(__GNUC__) && defined(__i386__) + /* GCC does peephole optimizations which should result in using rotate + instructions */ + #define FAST_ROTATE +#endif + + +/* Micrium will use Visual Studio for compilation but not the Win32 API */ +#if defined(_WIN32) && !defined(MICRIUM) + #define USE_WINDOWS_API +#endif + + +/* idea to add global alloc override by Moisés Guimarães */ +/* default to libc stuff */ +/* XREALLOC is used once in mormal math lib, not in fast math lib */ +/* XFREE on some embeded systems doesn't like free(0) so test */ +#ifdef XMALLOC_USER + /* prototypes for user heap override functions */ + #include /* for size_t */ + extern void *XMALLOC(size_t n, void* heap, int type); + extern void *XREALLOC(void *p, size_t n, void* heap, int type); + extern void XFREE(void *p, void* heap, int type); +#elif !defined(MICRIUM_MALLOC) + /* defaults to C runtime if user doesn't override and not Micrium */ + #include + #define XMALLOC(s, h, t) malloc((s)) + #define XFREE(p, h, t) {void* xp = (p); if((xp)) free((xp));} + #define XREALLOC(p, n, h, t) realloc((p), (n)) +#endif + +#ifndef STRING_USER + #include + #define XMEMCPY(d,s,l) memcpy((d),(s),(l)) + #define XMEMSET(b,c,l) memset((b),(c),(l)) + #define XMEMCMP(s1,s2,n) memcmp((s1),(s2),(n)) + #define XMEMMOVE(d,s,l) memmove((d),(s),(l)) + + #define XSTRLEN(s1) strlen((s1)) + #define XSTRNCPY(s1,s2,n) strncpy((s1),(s2),(n)) + /* strstr and strncmp only used by CyaSSL proper, not required for + CTaoCrypt only */ + #define XSTRSTR(s1,s2) strstr((s1),(s2)) + #define XSTRNCMP(s1,s2,n) strncmp((s1),(s2),(n)) +#endif + +#ifdef HAVE_ECC + #ifndef CTYPE_USER + #include + #define XTOUPPER(c) toupper((c)) + #endif +#endif + + +/* memory allocation types for user hints */ +enum { + DYNAMIC_TYPE_CA = 1, + DYNAMIC_TYPE_CERT = 2, + DYNAMIC_TYPE_KEY = 3, + DYNAMIC_TYPE_FILE = 4, + DYNAMIC_TYPE_ISSUER_CN = 5, + DYNAMIC_TYPE_PUBLIC_KEY = 6, + DYNAMIC_TYPE_SIGNER = 7, + DYNAMIC_TYPE_NONE = 8, + DYNAMIC_TYPE_BIGINT = 9, + DYNAMIC_TYPE_RSA = 10, + DYNAMIC_TYPE_METHOD = 11, + DYNAMIC_TYPE_OUT_BUFFER = 12, + DYNAMIC_TYPE_IN_BUFFER = 13, + DYNAMIC_TYPE_INFO = 14, + DYNAMIC_TYPE_DH = 15, + DYNAMIC_TYPE_DOMAIN = 16, + DYNAMIC_TYPE_SSL = 17, + DYNAMIC_TYPE_CTX = 18, + DYNAMIC_TYPE_WRITEV = 19, + DYNAMIC_TYPE_OPENSSL = 20 +}; + + +#ifdef __cplusplus + } /* extern "C" */ +#endif + + +#endif /* CTAO_CRYPT_TYPES_H */ + diff --git a/ctaocrypt/src/Makefile.am b/ctaocrypt/src/Makefile.am new file mode 100644 index 000000000..357c2ed23 --- /dev/null +++ b/ctaocrypt/src/Makefile.am @@ -0,0 +1,2 @@ +EXTRA_DIST = ../include/*.h *.c *.i + diff --git a/ctaocrypt/src/aes.c b/ctaocrypt/src/aes.c new file mode 100644 index 000000000..92c858d72 --- /dev/null +++ b/ctaocrypt/src/aes.c @@ -0,0 +1,1308 @@ +/* aes.c + * + * Copyright (C) 2006-2011 Sawtooth Consulting Ltd. + * + * This file is part of CyaSSL. + * + * CyaSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * CyaSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#ifndef NO_AES + +#include "ctc_aes.h" +#ifdef NO_INLINE + #include "misc.h" +#else + #include "misc.c" +#endif + + +static const word32 rcon[] = { + 0x01000000, 0x02000000, 0x04000000, 0x08000000, + 0x10000000, 0x20000000, 0x40000000, 0x80000000, + 0x1B000000, 0x36000000, + /* for 128-bit blocks, Rijndael never uses more than 10 rcon values */ +}; + + +static const word32 Te[5][256] = { +{ + 0xc66363a5U, 0xf87c7c84U, 0xee777799U, 0xf67b7b8dU, + 0xfff2f20dU, 0xd66b6bbdU, 0xde6f6fb1U, 0x91c5c554U, + 0x60303050U, 0x02010103U, 0xce6767a9U, 0x562b2b7dU, + 0xe7fefe19U, 0xb5d7d762U, 0x4dababe6U, 0xec76769aU, + 0x8fcaca45U, 0x1f82829dU, 0x89c9c940U, 0xfa7d7d87U, + 0xeffafa15U, 0xb25959ebU, 0x8e4747c9U, 0xfbf0f00bU, + 0x41adadecU, 0xb3d4d467U, 0x5fa2a2fdU, 0x45afafeaU, + 0x239c9cbfU, 0x53a4a4f7U, 0xe4727296U, 0x9bc0c05bU, + 0x75b7b7c2U, 0xe1fdfd1cU, 0x3d9393aeU, 0x4c26266aU, + 0x6c36365aU, 0x7e3f3f41U, 0xf5f7f702U, 0x83cccc4fU, + 0x6834345cU, 0x51a5a5f4U, 0xd1e5e534U, 0xf9f1f108U, + 0xe2717193U, 0xabd8d873U, 0x62313153U, 0x2a15153fU, + 0x0804040cU, 0x95c7c752U, 0x46232365U, 0x9dc3c35eU, + 0x30181828U, 0x379696a1U, 0x0a05050fU, 0x2f9a9ab5U, + 0x0e070709U, 0x24121236U, 0x1b80809bU, 0xdfe2e23dU, + 0xcdebeb26U, 0x4e272769U, 0x7fb2b2cdU, 0xea75759fU, + 0x1209091bU, 0x1d83839eU, 0x582c2c74U, 0x341a1a2eU, + 0x361b1b2dU, 0xdc6e6eb2U, 0xb45a5aeeU, 0x5ba0a0fbU, + 0xa45252f6U, 0x763b3b4dU, 0xb7d6d661U, 0x7db3b3ceU, + 0x5229297bU, 0xdde3e33eU, 0x5e2f2f71U, 0x13848497U, + 0xa65353f5U, 0xb9d1d168U, 0x00000000U, 0xc1eded2cU, + 0x40202060U, 0xe3fcfc1fU, 0x79b1b1c8U, 0xb65b5bedU, + 0xd46a6abeU, 0x8dcbcb46U, 0x67bebed9U, 0x7239394bU, + 0x944a4adeU, 0x984c4cd4U, 0xb05858e8U, 0x85cfcf4aU, + 0xbbd0d06bU, 0xc5efef2aU, 0x4faaaae5U, 0xedfbfb16U, + 0x864343c5U, 0x9a4d4dd7U, 0x66333355U, 0x11858594U, + 0x8a4545cfU, 0xe9f9f910U, 0x04020206U, 0xfe7f7f81U, + 0xa05050f0U, 0x783c3c44U, 0x259f9fbaU, 0x4ba8a8e3U, + 0xa25151f3U, 0x5da3a3feU, 0x804040c0U, 0x058f8f8aU, + 0x3f9292adU, 0x219d9dbcU, 0x70383848U, 0xf1f5f504U, + 0x63bcbcdfU, 0x77b6b6c1U, 0xafdada75U, 0x42212163U, + 0x20101030U, 0xe5ffff1aU, 0xfdf3f30eU, 0xbfd2d26dU, + 0x81cdcd4cU, 0x180c0c14U, 0x26131335U, 0xc3ecec2fU, + 0xbe5f5fe1U, 0x359797a2U, 0x884444ccU, 0x2e171739U, + 0x93c4c457U, 0x55a7a7f2U, 0xfc7e7e82U, 0x7a3d3d47U, + 0xc86464acU, 0xba5d5de7U, 0x3219192bU, 0xe6737395U, + 0xc06060a0U, 0x19818198U, 0x9e4f4fd1U, 0xa3dcdc7fU, + 0x44222266U, 0x542a2a7eU, 0x3b9090abU, 0x0b888883U, + 0x8c4646caU, 0xc7eeee29U, 0x6bb8b8d3U, 0x2814143cU, + 0xa7dede79U, 0xbc5e5ee2U, 0x160b0b1dU, 0xaddbdb76U, + 0xdbe0e03bU, 0x64323256U, 0x743a3a4eU, 0x140a0a1eU, + 0x924949dbU, 0x0c06060aU, 0x4824246cU, 0xb85c5ce4U, + 0x9fc2c25dU, 0xbdd3d36eU, 0x43acacefU, 0xc46262a6U, + 0x399191a8U, 0x319595a4U, 0xd3e4e437U, 0xf279798bU, + 0xd5e7e732U, 0x8bc8c843U, 0x6e373759U, 0xda6d6db7U, + 0x018d8d8cU, 0xb1d5d564U, 0x9c4e4ed2U, 0x49a9a9e0U, + 0xd86c6cb4U, 0xac5656faU, 0xf3f4f407U, 0xcfeaea25U, + 0xca6565afU, 0xf47a7a8eU, 0x47aeaee9U, 0x10080818U, + 0x6fbabad5U, 0xf0787888U, 0x4a25256fU, 0x5c2e2e72U, + 0x381c1c24U, 0x57a6a6f1U, 0x73b4b4c7U, 0x97c6c651U, + 0xcbe8e823U, 0xa1dddd7cU, 0xe874749cU, 0x3e1f1f21U, + 0x964b4bddU, 0x61bdbddcU, 0x0d8b8b86U, 0x0f8a8a85U, + 0xe0707090U, 0x7c3e3e42U, 0x71b5b5c4U, 0xcc6666aaU, + 0x904848d8U, 0x06030305U, 0xf7f6f601U, 0x1c0e0e12U, + 0xc26161a3U, 0x6a35355fU, 0xae5757f9U, 0x69b9b9d0U, + 0x17868691U, 0x99c1c158U, 0x3a1d1d27U, 0x279e9eb9U, + 0xd9e1e138U, 0xebf8f813U, 0x2b9898b3U, 0x22111133U, + 0xd26969bbU, 0xa9d9d970U, 0x078e8e89U, 0x339494a7U, + 0x2d9b9bb6U, 0x3c1e1e22U, 0x15878792U, 0xc9e9e920U, + 0x87cece49U, 0xaa5555ffU, 0x50282878U, 0xa5dfdf7aU, + 0x038c8c8fU, 0x59a1a1f8U, 0x09898980U, 0x1a0d0d17U, + 0x65bfbfdaU, 0xd7e6e631U, 0x844242c6U, 0xd06868b8U, + 0x824141c3U, 0x299999b0U, 0x5a2d2d77U, 0x1e0f0f11U, + 0x7bb0b0cbU, 0xa85454fcU, 0x6dbbbbd6U, 0x2c16163aU, +}, +{ + 0xa5c66363U, 0x84f87c7cU, 0x99ee7777U, 0x8df67b7bU, + 0x0dfff2f2U, 0xbdd66b6bU, 0xb1de6f6fU, 0x5491c5c5U, + 0x50603030U, 0x03020101U, 0xa9ce6767U, 0x7d562b2bU, + 0x19e7fefeU, 0x62b5d7d7U, 0xe64dababU, 0x9aec7676U, + 0x458fcacaU, 0x9d1f8282U, 0x4089c9c9U, 0x87fa7d7dU, + 0x15effafaU, 0xebb25959U, 0xc98e4747U, 0x0bfbf0f0U, + 0xec41adadU, 0x67b3d4d4U, 0xfd5fa2a2U, 0xea45afafU, + 0xbf239c9cU, 0xf753a4a4U, 0x96e47272U, 0x5b9bc0c0U, + 0xc275b7b7U, 0x1ce1fdfdU, 0xae3d9393U, 0x6a4c2626U, + 0x5a6c3636U, 0x417e3f3fU, 0x02f5f7f7U, 0x4f83ccccU, + 0x5c683434U, 0xf451a5a5U, 0x34d1e5e5U, 0x08f9f1f1U, + 0x93e27171U, 0x73abd8d8U, 0x53623131U, 0x3f2a1515U, + 0x0c080404U, 0x5295c7c7U, 0x65462323U, 0x5e9dc3c3U, + 0x28301818U, 0xa1379696U, 0x0f0a0505U, 0xb52f9a9aU, + 0x090e0707U, 0x36241212U, 0x9b1b8080U, 0x3ddfe2e2U, + 0x26cdebebU, 0x694e2727U, 0xcd7fb2b2U, 0x9fea7575U, + 0x1b120909U, 0x9e1d8383U, 0x74582c2cU, 0x2e341a1aU, + 0x2d361b1bU, 0xb2dc6e6eU, 0xeeb45a5aU, 0xfb5ba0a0U, + 0xf6a45252U, 0x4d763b3bU, 0x61b7d6d6U, 0xce7db3b3U, + 0x7b522929U, 0x3edde3e3U, 0x715e2f2fU, 0x97138484U, + 0xf5a65353U, 0x68b9d1d1U, 0x00000000U, 0x2cc1ededU, + 0x60402020U, 0x1fe3fcfcU, 0xc879b1b1U, 0xedb65b5bU, + 0xbed46a6aU, 0x468dcbcbU, 0xd967bebeU, 0x4b723939U, + 0xde944a4aU, 0xd4984c4cU, 0xe8b05858U, 0x4a85cfcfU, + 0x6bbbd0d0U, 0x2ac5efefU, 0xe54faaaaU, 0x16edfbfbU, + 0xc5864343U, 0xd79a4d4dU, 0x55663333U, 0x94118585U, + 0xcf8a4545U, 0x10e9f9f9U, 0x06040202U, 0x81fe7f7fU, + 0xf0a05050U, 0x44783c3cU, 0xba259f9fU, 0xe34ba8a8U, + 0xf3a25151U, 0xfe5da3a3U, 0xc0804040U, 0x8a058f8fU, + 0xad3f9292U, 0xbc219d9dU, 0x48703838U, 0x04f1f5f5U, + 0xdf63bcbcU, 0xc177b6b6U, 0x75afdadaU, 0x63422121U, + 0x30201010U, 0x1ae5ffffU, 0x0efdf3f3U, 0x6dbfd2d2U, + 0x4c81cdcdU, 0x14180c0cU, 0x35261313U, 0x2fc3ececU, + 0xe1be5f5fU, 0xa2359797U, 0xcc884444U, 0x392e1717U, + 0x5793c4c4U, 0xf255a7a7U, 0x82fc7e7eU, 0x477a3d3dU, + 0xacc86464U, 0xe7ba5d5dU, 0x2b321919U, 0x95e67373U, + 0xa0c06060U, 0x98198181U, 0xd19e4f4fU, 0x7fa3dcdcU, + 0x66442222U, 0x7e542a2aU, 0xab3b9090U, 0x830b8888U, + 0xca8c4646U, 0x29c7eeeeU, 0xd36bb8b8U, 0x3c281414U, + 0x79a7dedeU, 0xe2bc5e5eU, 0x1d160b0bU, 0x76addbdbU, + 0x3bdbe0e0U, 0x56643232U, 0x4e743a3aU, 0x1e140a0aU, + 0xdb924949U, 0x0a0c0606U, 0x6c482424U, 0xe4b85c5cU, + 0x5d9fc2c2U, 0x6ebdd3d3U, 0xef43acacU, 0xa6c46262U, + 0xa8399191U, 0xa4319595U, 0x37d3e4e4U, 0x8bf27979U, + 0x32d5e7e7U, 0x438bc8c8U, 0x596e3737U, 0xb7da6d6dU, + 0x8c018d8dU, 0x64b1d5d5U, 0xd29c4e4eU, 0xe049a9a9U, + 0xb4d86c6cU, 0xfaac5656U, 0x07f3f4f4U, 0x25cfeaeaU, + 0xafca6565U, 0x8ef47a7aU, 0xe947aeaeU, 0x18100808U, + 0xd56fbabaU, 0x88f07878U, 0x6f4a2525U, 0x725c2e2eU, + 0x24381c1cU, 0xf157a6a6U, 0xc773b4b4U, 0x5197c6c6U, + 0x23cbe8e8U, 0x7ca1ddddU, 0x9ce87474U, 0x213e1f1fU, + 0xdd964b4bU, 0xdc61bdbdU, 0x860d8b8bU, 0x850f8a8aU, + 0x90e07070U, 0x427c3e3eU, 0xc471b5b5U, 0xaacc6666U, + 0xd8904848U, 0x05060303U, 0x01f7f6f6U, 0x121c0e0eU, + 0xa3c26161U, 0x5f6a3535U, 0xf9ae5757U, 0xd069b9b9U, + 0x91178686U, 0x5899c1c1U, 0x273a1d1dU, 0xb9279e9eU, + 0x38d9e1e1U, 0x13ebf8f8U, 0xb32b9898U, 0x33221111U, + 0xbbd26969U, 0x70a9d9d9U, 0x89078e8eU, 0xa7339494U, + 0xb62d9b9bU, 0x223c1e1eU, 0x92158787U, 0x20c9e9e9U, + 0x4987ceceU, 0xffaa5555U, 0x78502828U, 0x7aa5dfdfU, + 0x8f038c8cU, 0xf859a1a1U, 0x80098989U, 0x171a0d0dU, + 0xda65bfbfU, 0x31d7e6e6U, 0xc6844242U, 0xb8d06868U, + 0xc3824141U, 0xb0299999U, 0x775a2d2dU, 0x111e0f0fU, + 0xcb7bb0b0U, 0xfca85454U, 0xd66dbbbbU, 0x3a2c1616U, +}, +{ + 0x63a5c663U, 0x7c84f87cU, 0x7799ee77U, 0x7b8df67bU, + 0xf20dfff2U, 0x6bbdd66bU, 0x6fb1de6fU, 0xc55491c5U, + 0x30506030U, 0x01030201U, 0x67a9ce67U, 0x2b7d562bU, + 0xfe19e7feU, 0xd762b5d7U, 0xabe64dabU, 0x769aec76U, + 0xca458fcaU, 0x829d1f82U, 0xc94089c9U, 0x7d87fa7dU, + 0xfa15effaU, 0x59ebb259U, 0x47c98e47U, 0xf00bfbf0U, + 0xadec41adU, 0xd467b3d4U, 0xa2fd5fa2U, 0xafea45afU, + 0x9cbf239cU, 0xa4f753a4U, 0x7296e472U, 0xc05b9bc0U, + 0xb7c275b7U, 0xfd1ce1fdU, 0x93ae3d93U, 0x266a4c26U, + 0x365a6c36U, 0x3f417e3fU, 0xf702f5f7U, 0xcc4f83ccU, + 0x345c6834U, 0xa5f451a5U, 0xe534d1e5U, 0xf108f9f1U, + 0x7193e271U, 0xd873abd8U, 0x31536231U, 0x153f2a15U, + 0x040c0804U, 0xc75295c7U, 0x23654623U, 0xc35e9dc3U, + 0x18283018U, 0x96a13796U, 0x050f0a05U, 0x9ab52f9aU, + 0x07090e07U, 0x12362412U, 0x809b1b80U, 0xe23ddfe2U, + 0xeb26cdebU, 0x27694e27U, 0xb2cd7fb2U, 0x759fea75U, + 0x091b1209U, 0x839e1d83U, 0x2c74582cU, 0x1a2e341aU, + 0x1b2d361bU, 0x6eb2dc6eU, 0x5aeeb45aU, 0xa0fb5ba0U, + 0x52f6a452U, 0x3b4d763bU, 0xd661b7d6U, 0xb3ce7db3U, + 0x297b5229U, 0xe33edde3U, 0x2f715e2fU, 0x84971384U, + 0x53f5a653U, 0xd168b9d1U, 0x00000000U, 0xed2cc1edU, + 0x20604020U, 0xfc1fe3fcU, 0xb1c879b1U, 0x5bedb65bU, + 0x6abed46aU, 0xcb468dcbU, 0xbed967beU, 0x394b7239U, + 0x4ade944aU, 0x4cd4984cU, 0x58e8b058U, 0xcf4a85cfU, + 0xd06bbbd0U, 0xef2ac5efU, 0xaae54faaU, 0xfb16edfbU, + 0x43c58643U, 0x4dd79a4dU, 0x33556633U, 0x85941185U, + 0x45cf8a45U, 0xf910e9f9U, 0x02060402U, 0x7f81fe7fU, + 0x50f0a050U, 0x3c44783cU, 0x9fba259fU, 0xa8e34ba8U, + 0x51f3a251U, 0xa3fe5da3U, 0x40c08040U, 0x8f8a058fU, + 0x92ad3f92U, 0x9dbc219dU, 0x38487038U, 0xf504f1f5U, + 0xbcdf63bcU, 0xb6c177b6U, 0xda75afdaU, 0x21634221U, + 0x10302010U, 0xff1ae5ffU, 0xf30efdf3U, 0xd26dbfd2U, + 0xcd4c81cdU, 0x0c14180cU, 0x13352613U, 0xec2fc3ecU, + 0x5fe1be5fU, 0x97a23597U, 0x44cc8844U, 0x17392e17U, + 0xc45793c4U, 0xa7f255a7U, 0x7e82fc7eU, 0x3d477a3dU, + 0x64acc864U, 0x5de7ba5dU, 0x192b3219U, 0x7395e673U, + 0x60a0c060U, 0x81981981U, 0x4fd19e4fU, 0xdc7fa3dcU, + 0x22664422U, 0x2a7e542aU, 0x90ab3b90U, 0x88830b88U, + 0x46ca8c46U, 0xee29c7eeU, 0xb8d36bb8U, 0x143c2814U, + 0xde79a7deU, 0x5ee2bc5eU, 0x0b1d160bU, 0xdb76addbU, + 0xe03bdbe0U, 0x32566432U, 0x3a4e743aU, 0x0a1e140aU, + 0x49db9249U, 0x060a0c06U, 0x246c4824U, 0x5ce4b85cU, + 0xc25d9fc2U, 0xd36ebdd3U, 0xacef43acU, 0x62a6c462U, + 0x91a83991U, 0x95a43195U, 0xe437d3e4U, 0x798bf279U, + 0xe732d5e7U, 0xc8438bc8U, 0x37596e37U, 0x6db7da6dU, + 0x8d8c018dU, 0xd564b1d5U, 0x4ed29c4eU, 0xa9e049a9U, + 0x6cb4d86cU, 0x56faac56U, 0xf407f3f4U, 0xea25cfeaU, + 0x65afca65U, 0x7a8ef47aU, 0xaee947aeU, 0x08181008U, + 0xbad56fbaU, 0x7888f078U, 0x256f4a25U, 0x2e725c2eU, + 0x1c24381cU, 0xa6f157a6U, 0xb4c773b4U, 0xc65197c6U, + 0xe823cbe8U, 0xdd7ca1ddU, 0x749ce874U, 0x1f213e1fU, + 0x4bdd964bU, 0xbddc61bdU, 0x8b860d8bU, 0x8a850f8aU, + 0x7090e070U, 0x3e427c3eU, 0xb5c471b5U, 0x66aacc66U, + 0x48d89048U, 0x03050603U, 0xf601f7f6U, 0x0e121c0eU, + 0x61a3c261U, 0x355f6a35U, 0x57f9ae57U, 0xb9d069b9U, + 0x86911786U, 0xc15899c1U, 0x1d273a1dU, 0x9eb9279eU, + 0xe138d9e1U, 0xf813ebf8U, 0x98b32b98U, 0x11332211U, + 0x69bbd269U, 0xd970a9d9U, 0x8e89078eU, 0x94a73394U, + 0x9bb62d9bU, 0x1e223c1eU, 0x87921587U, 0xe920c9e9U, + 0xce4987ceU, 0x55ffaa55U, 0x28785028U, 0xdf7aa5dfU, + 0x8c8f038cU, 0xa1f859a1U, 0x89800989U, 0x0d171a0dU, + 0xbfda65bfU, 0xe631d7e6U, 0x42c68442U, 0x68b8d068U, + 0x41c38241U, 0x99b02999U, 0x2d775a2dU, 0x0f111e0fU, + 0xb0cb7bb0U, 0x54fca854U, 0xbbd66dbbU, 0x163a2c16U, +}, +{ + 0x6363a5c6U, 0x7c7c84f8U, 0x777799eeU, 0x7b7b8df6U, + 0xf2f20dffU, 0x6b6bbdd6U, 0x6f6fb1deU, 0xc5c55491U, + 0x30305060U, 0x01010302U, 0x6767a9ceU, 0x2b2b7d56U, + 0xfefe19e7U, 0xd7d762b5U, 0xababe64dU, 0x76769aecU, + 0xcaca458fU, 0x82829d1fU, 0xc9c94089U, 0x7d7d87faU, + 0xfafa15efU, 0x5959ebb2U, 0x4747c98eU, 0xf0f00bfbU, + 0xadadec41U, 0xd4d467b3U, 0xa2a2fd5fU, 0xafafea45U, + 0x9c9cbf23U, 0xa4a4f753U, 0x727296e4U, 0xc0c05b9bU, + 0xb7b7c275U, 0xfdfd1ce1U, 0x9393ae3dU, 0x26266a4cU, + 0x36365a6cU, 0x3f3f417eU, 0xf7f702f5U, 0xcccc4f83U, + 0x34345c68U, 0xa5a5f451U, 0xe5e534d1U, 0xf1f108f9U, + 0x717193e2U, 0xd8d873abU, 0x31315362U, 0x15153f2aU, + 0x04040c08U, 0xc7c75295U, 0x23236546U, 0xc3c35e9dU, + 0x18182830U, 0x9696a137U, 0x05050f0aU, 0x9a9ab52fU, + 0x0707090eU, 0x12123624U, 0x80809b1bU, 0xe2e23ddfU, + 0xebeb26cdU, 0x2727694eU, 0xb2b2cd7fU, 0x75759feaU, + 0x09091b12U, 0x83839e1dU, 0x2c2c7458U, 0x1a1a2e34U, + 0x1b1b2d36U, 0x6e6eb2dcU, 0x5a5aeeb4U, 0xa0a0fb5bU, + 0x5252f6a4U, 0x3b3b4d76U, 0xd6d661b7U, 0xb3b3ce7dU, + 0x29297b52U, 0xe3e33eddU, 0x2f2f715eU, 0x84849713U, + 0x5353f5a6U, 0xd1d168b9U, 0x00000000U, 0xeded2cc1U, + 0x20206040U, 0xfcfc1fe3U, 0xb1b1c879U, 0x5b5bedb6U, + 0x6a6abed4U, 0xcbcb468dU, 0xbebed967U, 0x39394b72U, + 0x4a4ade94U, 0x4c4cd498U, 0x5858e8b0U, 0xcfcf4a85U, + 0xd0d06bbbU, 0xefef2ac5U, 0xaaaae54fU, 0xfbfb16edU, + 0x4343c586U, 0x4d4dd79aU, 0x33335566U, 0x85859411U, + 0x4545cf8aU, 0xf9f910e9U, 0x02020604U, 0x7f7f81feU, + 0x5050f0a0U, 0x3c3c4478U, 0x9f9fba25U, 0xa8a8e34bU, + 0x5151f3a2U, 0xa3a3fe5dU, 0x4040c080U, 0x8f8f8a05U, + 0x9292ad3fU, 0x9d9dbc21U, 0x38384870U, 0xf5f504f1U, + 0xbcbcdf63U, 0xb6b6c177U, 0xdada75afU, 0x21216342U, + 0x10103020U, 0xffff1ae5U, 0xf3f30efdU, 0xd2d26dbfU, + 0xcdcd4c81U, 0x0c0c1418U, 0x13133526U, 0xecec2fc3U, + 0x5f5fe1beU, 0x9797a235U, 0x4444cc88U, 0x1717392eU, + 0xc4c45793U, 0xa7a7f255U, 0x7e7e82fcU, 0x3d3d477aU, + 0x6464acc8U, 0x5d5de7baU, 0x19192b32U, 0x737395e6U, + 0x6060a0c0U, 0x81819819U, 0x4f4fd19eU, 0xdcdc7fa3U, + 0x22226644U, 0x2a2a7e54U, 0x9090ab3bU, 0x8888830bU, + 0x4646ca8cU, 0xeeee29c7U, 0xb8b8d36bU, 0x14143c28U, + 0xdede79a7U, 0x5e5ee2bcU, 0x0b0b1d16U, 0xdbdb76adU, + 0xe0e03bdbU, 0x32325664U, 0x3a3a4e74U, 0x0a0a1e14U, + 0x4949db92U, 0x06060a0cU, 0x24246c48U, 0x5c5ce4b8U, + 0xc2c25d9fU, 0xd3d36ebdU, 0xacacef43U, 0x6262a6c4U, + 0x9191a839U, 0x9595a431U, 0xe4e437d3U, 0x79798bf2U, + 0xe7e732d5U, 0xc8c8438bU, 0x3737596eU, 0x6d6db7daU, + 0x8d8d8c01U, 0xd5d564b1U, 0x4e4ed29cU, 0xa9a9e049U, + 0x6c6cb4d8U, 0x5656faacU, 0xf4f407f3U, 0xeaea25cfU, + 0x6565afcaU, 0x7a7a8ef4U, 0xaeaee947U, 0x08081810U, + 0xbabad56fU, 0x787888f0U, 0x25256f4aU, 0x2e2e725cU, + 0x1c1c2438U, 0xa6a6f157U, 0xb4b4c773U, 0xc6c65197U, + 0xe8e823cbU, 0xdddd7ca1U, 0x74749ce8U, 0x1f1f213eU, + 0x4b4bdd96U, 0xbdbddc61U, 0x8b8b860dU, 0x8a8a850fU, + 0x707090e0U, 0x3e3e427cU, 0xb5b5c471U, 0x6666aaccU, + 0x4848d890U, 0x03030506U, 0xf6f601f7U, 0x0e0e121cU, + 0x6161a3c2U, 0x35355f6aU, 0x5757f9aeU, 0xb9b9d069U, + 0x86869117U, 0xc1c15899U, 0x1d1d273aU, 0x9e9eb927U, + 0xe1e138d9U, 0xf8f813ebU, 0x9898b32bU, 0x11113322U, + 0x6969bbd2U, 0xd9d970a9U, 0x8e8e8907U, 0x9494a733U, + 0x9b9bb62dU, 0x1e1e223cU, 0x87879215U, 0xe9e920c9U, + 0xcece4987U, 0x5555ffaaU, 0x28287850U, 0xdfdf7aa5U, + 0x8c8c8f03U, 0xa1a1f859U, 0x89898009U, 0x0d0d171aU, + 0xbfbfda65U, 0xe6e631d7U, 0x4242c684U, 0x6868b8d0U, + 0x4141c382U, 0x9999b029U, 0x2d2d775aU, 0x0f0f111eU, + 0xb0b0cb7bU, 0x5454fca8U, 0xbbbbd66dU, 0x16163a2cU, +}, +{ + 0x63636363U, 0x7c7c7c7cU, 0x77777777U, 0x7b7b7b7bU, + 0xf2f2f2f2U, 0x6b6b6b6bU, 0x6f6f6f6fU, 0xc5c5c5c5U, + 0x30303030U, 0x01010101U, 0x67676767U, 0x2b2b2b2bU, + 0xfefefefeU, 0xd7d7d7d7U, 0xababababU, 0x76767676U, + 0xcacacacaU, 0x82828282U, 0xc9c9c9c9U, 0x7d7d7d7dU, + 0xfafafafaU, 0x59595959U, 0x47474747U, 0xf0f0f0f0U, + 0xadadadadU, 0xd4d4d4d4U, 0xa2a2a2a2U, 0xafafafafU, + 0x9c9c9c9cU, 0xa4a4a4a4U, 0x72727272U, 0xc0c0c0c0U, + 0xb7b7b7b7U, 0xfdfdfdfdU, 0x93939393U, 0x26262626U, + 0x36363636U, 0x3f3f3f3fU, 0xf7f7f7f7U, 0xccccccccU, + 0x34343434U, 0xa5a5a5a5U, 0xe5e5e5e5U, 0xf1f1f1f1U, + 0x71717171U, 0xd8d8d8d8U, 0x31313131U, 0x15151515U, + 0x04040404U, 0xc7c7c7c7U, 0x23232323U, 0xc3c3c3c3U, + 0x18181818U, 0x96969696U, 0x05050505U, 0x9a9a9a9aU, + 0x07070707U, 0x12121212U, 0x80808080U, 0xe2e2e2e2U, + 0xebebebebU, 0x27272727U, 0xb2b2b2b2U, 0x75757575U, + 0x09090909U, 0x83838383U, 0x2c2c2c2cU, 0x1a1a1a1aU, + 0x1b1b1b1bU, 0x6e6e6e6eU, 0x5a5a5a5aU, 0xa0a0a0a0U, + 0x52525252U, 0x3b3b3b3bU, 0xd6d6d6d6U, 0xb3b3b3b3U, + 0x29292929U, 0xe3e3e3e3U, 0x2f2f2f2fU, 0x84848484U, + 0x53535353U, 0xd1d1d1d1U, 0x00000000U, 0xededededU, + 0x20202020U, 0xfcfcfcfcU, 0xb1b1b1b1U, 0x5b5b5b5bU, + 0x6a6a6a6aU, 0xcbcbcbcbU, 0xbebebebeU, 0x39393939U, + 0x4a4a4a4aU, 0x4c4c4c4cU, 0x58585858U, 0xcfcfcfcfU, + 0xd0d0d0d0U, 0xefefefefU, 0xaaaaaaaaU, 0xfbfbfbfbU, + 0x43434343U, 0x4d4d4d4dU, 0x33333333U, 0x85858585U, + 0x45454545U, 0xf9f9f9f9U, 0x02020202U, 0x7f7f7f7fU, + 0x50505050U, 0x3c3c3c3cU, 0x9f9f9f9fU, 0xa8a8a8a8U, + 0x51515151U, 0xa3a3a3a3U, 0x40404040U, 0x8f8f8f8fU, + 0x92929292U, 0x9d9d9d9dU, 0x38383838U, 0xf5f5f5f5U, + 0xbcbcbcbcU, 0xb6b6b6b6U, 0xdadadadaU, 0x21212121U, + 0x10101010U, 0xffffffffU, 0xf3f3f3f3U, 0xd2d2d2d2U, + 0xcdcdcdcdU, 0x0c0c0c0cU, 0x13131313U, 0xececececU, + 0x5f5f5f5fU, 0x97979797U, 0x44444444U, 0x17171717U, + 0xc4c4c4c4U, 0xa7a7a7a7U, 0x7e7e7e7eU, 0x3d3d3d3dU, + 0x64646464U, 0x5d5d5d5dU, 0x19191919U, 0x73737373U, + 0x60606060U, 0x81818181U, 0x4f4f4f4fU, 0xdcdcdcdcU, + 0x22222222U, 0x2a2a2a2aU, 0x90909090U, 0x88888888U, + 0x46464646U, 0xeeeeeeeeU, 0xb8b8b8b8U, 0x14141414U, + 0xdedededeU, 0x5e5e5e5eU, 0x0b0b0b0bU, 0xdbdbdbdbU, + 0xe0e0e0e0U, 0x32323232U, 0x3a3a3a3aU, 0x0a0a0a0aU, + 0x49494949U, 0x06060606U, 0x24242424U, 0x5c5c5c5cU, + 0xc2c2c2c2U, 0xd3d3d3d3U, 0xacacacacU, 0x62626262U, + 0x91919191U, 0x95959595U, 0xe4e4e4e4U, 0x79797979U, + 0xe7e7e7e7U, 0xc8c8c8c8U, 0x37373737U, 0x6d6d6d6dU, + 0x8d8d8d8dU, 0xd5d5d5d5U, 0x4e4e4e4eU, 0xa9a9a9a9U, + 0x6c6c6c6cU, 0x56565656U, 0xf4f4f4f4U, 0xeaeaeaeaU, + 0x65656565U, 0x7a7a7a7aU, 0xaeaeaeaeU, 0x08080808U, + 0xbabababaU, 0x78787878U, 0x25252525U, 0x2e2e2e2eU, + 0x1c1c1c1cU, 0xa6a6a6a6U, 0xb4b4b4b4U, 0xc6c6c6c6U, + 0xe8e8e8e8U, 0xddddddddU, 0x74747474U, 0x1f1f1f1fU, + 0x4b4b4b4bU, 0xbdbdbdbdU, 0x8b8b8b8bU, 0x8a8a8a8aU, + 0x70707070U, 0x3e3e3e3eU, 0xb5b5b5b5U, 0x66666666U, + 0x48484848U, 0x03030303U, 0xf6f6f6f6U, 0x0e0e0e0eU, + 0x61616161U, 0x35353535U, 0x57575757U, 0xb9b9b9b9U, + 0x86868686U, 0xc1c1c1c1U, 0x1d1d1d1dU, 0x9e9e9e9eU, + 0xe1e1e1e1U, 0xf8f8f8f8U, 0x98989898U, 0x11111111U, + 0x69696969U, 0xd9d9d9d9U, 0x8e8e8e8eU, 0x94949494U, + 0x9b9b9b9bU, 0x1e1e1e1eU, 0x87878787U, 0xe9e9e9e9U, + 0xcecececeU, 0x55555555U, 0x28282828U, 0xdfdfdfdfU, + 0x8c8c8c8cU, 0xa1a1a1a1U, 0x89898989U, 0x0d0d0d0dU, + 0xbfbfbfbfU, 0xe6e6e6e6U, 0x42424242U, 0x68686868U, + 0x41414141U, 0x99999999U, 0x2d2d2d2dU, 0x0f0f0f0fU, + 0xb0b0b0b0U, 0x54545454U, 0xbbbbbbbbU, 0x16161616U, +} +}; + + +static const word32 Td[5][256] = { +{ + 0x51f4a750U, 0x7e416553U, 0x1a17a4c3U, 0x3a275e96U, + 0x3bab6bcbU, 0x1f9d45f1U, 0xacfa58abU, 0x4be30393U, + 0x2030fa55U, 0xad766df6U, 0x88cc7691U, 0xf5024c25U, + 0x4fe5d7fcU, 0xc52acbd7U, 0x26354480U, 0xb562a38fU, + 0xdeb15a49U, 0x25ba1b67U, 0x45ea0e98U, 0x5dfec0e1U, + 0xc32f7502U, 0x814cf012U, 0x8d4697a3U, 0x6bd3f9c6U, + 0x038f5fe7U, 0x15929c95U, 0xbf6d7aebU, 0x955259daU, + 0xd4be832dU, 0x587421d3U, 0x49e06929U, 0x8ec9c844U, + 0x75c2896aU, 0xf48e7978U, 0x99583e6bU, 0x27b971ddU, + 0xbee14fb6U, 0xf088ad17U, 0xc920ac66U, 0x7dce3ab4U, + 0x63df4a18U, 0xe51a3182U, 0x97513360U, 0x62537f45U, + 0xb16477e0U, 0xbb6bae84U, 0xfe81a01cU, 0xf9082b94U, + 0x70486858U, 0x8f45fd19U, 0x94de6c87U, 0x527bf8b7U, + 0xab73d323U, 0x724b02e2U, 0xe31f8f57U, 0x6655ab2aU, + 0xb2eb2807U, 0x2fb5c203U, 0x86c57b9aU, 0xd33708a5U, + 0x302887f2U, 0x23bfa5b2U, 0x02036abaU, 0xed16825cU, + 0x8acf1c2bU, 0xa779b492U, 0xf307f2f0U, 0x4e69e2a1U, + 0x65daf4cdU, 0x0605bed5U, 0xd134621fU, 0xc4a6fe8aU, + 0x342e539dU, 0xa2f355a0U, 0x058ae132U, 0xa4f6eb75U, + 0x0b83ec39U, 0x4060efaaU, 0x5e719f06U, 0xbd6e1051U, + 0x3e218af9U, 0x96dd063dU, 0xdd3e05aeU, 0x4de6bd46U, + 0x91548db5U, 0x71c45d05U, 0x0406d46fU, 0x605015ffU, + 0x1998fb24U, 0xd6bde997U, 0x894043ccU, 0x67d99e77U, + 0xb0e842bdU, 0x07898b88U, 0xe7195b38U, 0x79c8eedbU, + 0xa17c0a47U, 0x7c420fe9U, 0xf8841ec9U, 0x00000000U, + 0x09808683U, 0x322bed48U, 0x1e1170acU, 0x6c5a724eU, + 0xfd0efffbU, 0x0f853856U, 0x3daed51eU, 0x362d3927U, + 0x0a0fd964U, 0x685ca621U, 0x9b5b54d1U, 0x24362e3aU, + 0x0c0a67b1U, 0x9357e70fU, 0xb4ee96d2U, 0x1b9b919eU, + 0x80c0c54fU, 0x61dc20a2U, 0x5a774b69U, 0x1c121a16U, + 0xe293ba0aU, 0xc0a02ae5U, 0x3c22e043U, 0x121b171dU, + 0x0e090d0bU, 0xf28bc7adU, 0x2db6a8b9U, 0x141ea9c8U, + 0x57f11985U, 0xaf75074cU, 0xee99ddbbU, 0xa37f60fdU, + 0xf701269fU, 0x5c72f5bcU, 0x44663bc5U, 0x5bfb7e34U, + 0x8b432976U, 0xcb23c6dcU, 0xb6edfc68U, 0xb8e4f163U, + 0xd731dccaU, 0x42638510U, 0x13972240U, 0x84c61120U, + 0x854a247dU, 0xd2bb3df8U, 0xaef93211U, 0xc729a16dU, + 0x1d9e2f4bU, 0xdcb230f3U, 0x0d8652ecU, 0x77c1e3d0U, + 0x2bb3166cU, 0xa970b999U, 0x119448faU, 0x47e96422U, + 0xa8fc8cc4U, 0xa0f03f1aU, 0x567d2cd8U, 0x223390efU, + 0x87494ec7U, 0xd938d1c1U, 0x8ccaa2feU, 0x98d40b36U, + 0xa6f581cfU, 0xa57ade28U, 0xdab78e26U, 0x3fadbfa4U, + 0x2c3a9de4U, 0x5078920dU, 0x6a5fcc9bU, 0x547e4662U, + 0xf68d13c2U, 0x90d8b8e8U, 0x2e39f75eU, 0x82c3aff5U, + 0x9f5d80beU, 0x69d0937cU, 0x6fd52da9U, 0xcf2512b3U, + 0xc8ac993bU, 0x10187da7U, 0xe89c636eU, 0xdb3bbb7bU, + 0xcd267809U, 0x6e5918f4U, 0xec9ab701U, 0x834f9aa8U, + 0xe6956e65U, 0xaaffe67eU, 0x21bccf08U, 0xef15e8e6U, + 0xbae79bd9U, 0x4a6f36ceU, 0xea9f09d4U, 0x29b07cd6U, + 0x31a4b2afU, 0x2a3f2331U, 0xc6a59430U, 0x35a266c0U, + 0x744ebc37U, 0xfc82caa6U, 0xe090d0b0U, 0x33a7d815U, + 0xf104984aU, 0x41ecdaf7U, 0x7fcd500eU, 0x1791f62fU, + 0x764dd68dU, 0x43efb04dU, 0xccaa4d54U, 0xe49604dfU, + 0x9ed1b5e3U, 0x4c6a881bU, 0xc12c1fb8U, 0x4665517fU, + 0x9d5eea04U, 0x018c355dU, 0xfa877473U, 0xfb0b412eU, + 0xb3671d5aU, 0x92dbd252U, 0xe9105633U, 0x6dd64713U, + 0x9ad7618cU, 0x37a10c7aU, 0x59f8148eU, 0xeb133c89U, + 0xcea927eeU, 0xb761c935U, 0xe11ce5edU, 0x7a47b13cU, + 0x9cd2df59U, 0x55f2733fU, 0x1814ce79U, 0x73c737bfU, + 0x53f7cdeaU, 0x5ffdaa5bU, 0xdf3d6f14U, 0x7844db86U, + 0xcaaff381U, 0xb968c43eU, 0x3824342cU, 0xc2a3405fU, + 0x161dc372U, 0xbce2250cU, 0x283c498bU, 0xff0d9541U, + 0x39a80171U, 0x080cb3deU, 0xd8b4e49cU, 0x6456c190U, + 0x7bcb8461U, 0xd532b670U, 0x486c5c74U, 0xd0b85742U, +}, +{ + 0x5051f4a7U, 0x537e4165U, 0xc31a17a4U, 0x963a275eU, + 0xcb3bab6bU, 0xf11f9d45U, 0xabacfa58U, 0x934be303U, + 0x552030faU, 0xf6ad766dU, 0x9188cc76U, 0x25f5024cU, + 0xfc4fe5d7U, 0xd7c52acbU, 0x80263544U, 0x8fb562a3U, + 0x49deb15aU, 0x6725ba1bU, 0x9845ea0eU, 0xe15dfec0U, + 0x02c32f75U, 0x12814cf0U, 0xa38d4697U, 0xc66bd3f9U, + 0xe7038f5fU, 0x9515929cU, 0xebbf6d7aU, 0xda955259U, + 0x2dd4be83U, 0xd3587421U, 0x2949e069U, 0x448ec9c8U, + 0x6a75c289U, 0x78f48e79U, 0x6b99583eU, 0xdd27b971U, + 0xb6bee14fU, 0x17f088adU, 0x66c920acU, 0xb47dce3aU, + 0x1863df4aU, 0x82e51a31U, 0x60975133U, 0x4562537fU, + 0xe0b16477U, 0x84bb6baeU, 0x1cfe81a0U, 0x94f9082bU, + 0x58704868U, 0x198f45fdU, 0x8794de6cU, 0xb7527bf8U, + 0x23ab73d3U, 0xe2724b02U, 0x57e31f8fU, 0x2a6655abU, + 0x07b2eb28U, 0x032fb5c2U, 0x9a86c57bU, 0xa5d33708U, + 0xf2302887U, 0xb223bfa5U, 0xba02036aU, 0x5ced1682U, + 0x2b8acf1cU, 0x92a779b4U, 0xf0f307f2U, 0xa14e69e2U, + 0xcd65daf4U, 0xd50605beU, 0x1fd13462U, 0x8ac4a6feU, + 0x9d342e53U, 0xa0a2f355U, 0x32058ae1U, 0x75a4f6ebU, + 0x390b83ecU, 0xaa4060efU, 0x065e719fU, 0x51bd6e10U, + 0xf93e218aU, 0x3d96dd06U, 0xaedd3e05U, 0x464de6bdU, + 0xb591548dU, 0x0571c45dU, 0x6f0406d4U, 0xff605015U, + 0x241998fbU, 0x97d6bde9U, 0xcc894043U, 0x7767d99eU, + 0xbdb0e842U, 0x8807898bU, 0x38e7195bU, 0xdb79c8eeU, + 0x47a17c0aU, 0xe97c420fU, 0xc9f8841eU, 0x00000000U, + 0x83098086U, 0x48322bedU, 0xac1e1170U, 0x4e6c5a72U, + 0xfbfd0effU, 0x560f8538U, 0x1e3daed5U, 0x27362d39U, + 0x640a0fd9U, 0x21685ca6U, 0xd19b5b54U, 0x3a24362eU, + 0xb10c0a67U, 0x0f9357e7U, 0xd2b4ee96U, 0x9e1b9b91U, + 0x4f80c0c5U, 0xa261dc20U, 0x695a774bU, 0x161c121aU, + 0x0ae293baU, 0xe5c0a02aU, 0x433c22e0U, 0x1d121b17U, + 0x0b0e090dU, 0xadf28bc7U, 0xb92db6a8U, 0xc8141ea9U, + 0x8557f119U, 0x4caf7507U, 0xbbee99ddU, 0xfda37f60U, + 0x9ff70126U, 0xbc5c72f5U, 0xc544663bU, 0x345bfb7eU, + 0x768b4329U, 0xdccb23c6U, 0x68b6edfcU, 0x63b8e4f1U, + 0xcad731dcU, 0x10426385U, 0x40139722U, 0x2084c611U, + 0x7d854a24U, 0xf8d2bb3dU, 0x11aef932U, 0x6dc729a1U, + 0x4b1d9e2fU, 0xf3dcb230U, 0xec0d8652U, 0xd077c1e3U, + 0x6c2bb316U, 0x99a970b9U, 0xfa119448U, 0x2247e964U, + 0xc4a8fc8cU, 0x1aa0f03fU, 0xd8567d2cU, 0xef223390U, + 0xc787494eU, 0xc1d938d1U, 0xfe8ccaa2U, 0x3698d40bU, + 0xcfa6f581U, 0x28a57adeU, 0x26dab78eU, 0xa43fadbfU, + 0xe42c3a9dU, 0x0d507892U, 0x9b6a5fccU, 0x62547e46U, + 0xc2f68d13U, 0xe890d8b8U, 0x5e2e39f7U, 0xf582c3afU, + 0xbe9f5d80U, 0x7c69d093U, 0xa96fd52dU, 0xb3cf2512U, + 0x3bc8ac99U, 0xa710187dU, 0x6ee89c63U, 0x7bdb3bbbU, + 0x09cd2678U, 0xf46e5918U, 0x01ec9ab7U, 0xa8834f9aU, + 0x65e6956eU, 0x7eaaffe6U, 0x0821bccfU, 0xe6ef15e8U, + 0xd9bae79bU, 0xce4a6f36U, 0xd4ea9f09U, 0xd629b07cU, + 0xaf31a4b2U, 0x312a3f23U, 0x30c6a594U, 0xc035a266U, + 0x37744ebcU, 0xa6fc82caU, 0xb0e090d0U, 0x1533a7d8U, + 0x4af10498U, 0xf741ecdaU, 0x0e7fcd50U, 0x2f1791f6U, + 0x8d764dd6U, 0x4d43efb0U, 0x54ccaa4dU, 0xdfe49604U, + 0xe39ed1b5U, 0x1b4c6a88U, 0xb8c12c1fU, 0x7f466551U, + 0x049d5eeaU, 0x5d018c35U, 0x73fa8774U, 0x2efb0b41U, + 0x5ab3671dU, 0x5292dbd2U, 0x33e91056U, 0x136dd647U, + 0x8c9ad761U, 0x7a37a10cU, 0x8e59f814U, 0x89eb133cU, + 0xeecea927U, 0x35b761c9U, 0xede11ce5U, 0x3c7a47b1U, + 0x599cd2dfU, 0x3f55f273U, 0x791814ceU, 0xbf73c737U, + 0xea53f7cdU, 0x5b5ffdaaU, 0x14df3d6fU, 0x867844dbU, + 0x81caaff3U, 0x3eb968c4U, 0x2c382434U, 0x5fc2a340U, + 0x72161dc3U, 0x0cbce225U, 0x8b283c49U, 0x41ff0d95U, + 0x7139a801U, 0xde080cb3U, 0x9cd8b4e4U, 0x906456c1U, + 0x617bcb84U, 0x70d532b6U, 0x74486c5cU, 0x42d0b857U, +}, +{ + 0xa75051f4U, 0x65537e41U, 0xa4c31a17U, 0x5e963a27U, + 0x6bcb3babU, 0x45f11f9dU, 0x58abacfaU, 0x03934be3U, + 0xfa552030U, 0x6df6ad76U, 0x769188ccU, 0x4c25f502U, + 0xd7fc4fe5U, 0xcbd7c52aU, 0x44802635U, 0xa38fb562U, + 0x5a49deb1U, 0x1b6725baU, 0x0e9845eaU, 0xc0e15dfeU, + 0x7502c32fU, 0xf012814cU, 0x97a38d46U, 0xf9c66bd3U, + 0x5fe7038fU, 0x9c951592U, 0x7aebbf6dU, 0x59da9552U, + 0x832dd4beU, 0x21d35874U, 0x692949e0U, 0xc8448ec9U, + 0x896a75c2U, 0x7978f48eU, 0x3e6b9958U, 0x71dd27b9U, + 0x4fb6bee1U, 0xad17f088U, 0xac66c920U, 0x3ab47dceU, + 0x4a1863dfU, 0x3182e51aU, 0x33609751U, 0x7f456253U, + 0x77e0b164U, 0xae84bb6bU, 0xa01cfe81U, 0x2b94f908U, + 0x68587048U, 0xfd198f45U, 0x6c8794deU, 0xf8b7527bU, + 0xd323ab73U, 0x02e2724bU, 0x8f57e31fU, 0xab2a6655U, + 0x2807b2ebU, 0xc2032fb5U, 0x7b9a86c5U, 0x08a5d337U, + 0x87f23028U, 0xa5b223bfU, 0x6aba0203U, 0x825ced16U, + 0x1c2b8acfU, 0xb492a779U, 0xf2f0f307U, 0xe2a14e69U, + 0xf4cd65daU, 0xbed50605U, 0x621fd134U, 0xfe8ac4a6U, + 0x539d342eU, 0x55a0a2f3U, 0xe132058aU, 0xeb75a4f6U, + 0xec390b83U, 0xefaa4060U, 0x9f065e71U, 0x1051bd6eU, + + 0x8af93e21U, 0x063d96ddU, 0x05aedd3eU, 0xbd464de6U, + 0x8db59154U, 0x5d0571c4U, 0xd46f0406U, 0x15ff6050U, + 0xfb241998U, 0xe997d6bdU, 0x43cc8940U, 0x9e7767d9U, + 0x42bdb0e8U, 0x8b880789U, 0x5b38e719U, 0xeedb79c8U, + 0x0a47a17cU, 0x0fe97c42U, 0x1ec9f884U, 0x00000000U, + 0x86830980U, 0xed48322bU, 0x70ac1e11U, 0x724e6c5aU, + 0xfffbfd0eU, 0x38560f85U, 0xd51e3daeU, 0x3927362dU, + 0xd9640a0fU, 0xa621685cU, 0x54d19b5bU, 0x2e3a2436U, + 0x67b10c0aU, 0xe70f9357U, 0x96d2b4eeU, 0x919e1b9bU, + 0xc54f80c0U, 0x20a261dcU, 0x4b695a77U, 0x1a161c12U, + 0xba0ae293U, 0x2ae5c0a0U, 0xe0433c22U, 0x171d121bU, + 0x0d0b0e09U, 0xc7adf28bU, 0xa8b92db6U, 0xa9c8141eU, + 0x198557f1U, 0x074caf75U, 0xddbbee99U, 0x60fda37fU, + 0x269ff701U, 0xf5bc5c72U, 0x3bc54466U, 0x7e345bfbU, + 0x29768b43U, 0xc6dccb23U, 0xfc68b6edU, 0xf163b8e4U, + 0xdccad731U, 0x85104263U, 0x22401397U, 0x112084c6U, + 0x247d854aU, 0x3df8d2bbU, 0x3211aef9U, 0xa16dc729U, + 0x2f4b1d9eU, 0x30f3dcb2U, 0x52ec0d86U, 0xe3d077c1U, + 0x166c2bb3U, 0xb999a970U, 0x48fa1194U, 0x642247e9U, + 0x8cc4a8fcU, 0x3f1aa0f0U, 0x2cd8567dU, 0x90ef2233U, + 0x4ec78749U, 0xd1c1d938U, 0xa2fe8ccaU, 0x0b3698d4U, + 0x81cfa6f5U, 0xde28a57aU, 0x8e26dab7U, 0xbfa43fadU, + 0x9de42c3aU, 0x920d5078U, 0xcc9b6a5fU, 0x4662547eU, + 0x13c2f68dU, 0xb8e890d8U, 0xf75e2e39U, 0xaff582c3U, + 0x80be9f5dU, 0x937c69d0U, 0x2da96fd5U, 0x12b3cf25U, + 0x993bc8acU, 0x7da71018U, 0x636ee89cU, 0xbb7bdb3bU, + 0x7809cd26U, 0x18f46e59U, 0xb701ec9aU, 0x9aa8834fU, + 0x6e65e695U, 0xe67eaaffU, 0xcf0821bcU, 0xe8e6ef15U, + 0x9bd9bae7U, 0x36ce4a6fU, 0x09d4ea9fU, 0x7cd629b0U, + 0xb2af31a4U, 0x23312a3fU, 0x9430c6a5U, 0x66c035a2U, + 0xbc37744eU, 0xcaa6fc82U, 0xd0b0e090U, 0xd81533a7U, + 0x984af104U, 0xdaf741ecU, 0x500e7fcdU, 0xf62f1791U, + 0xd68d764dU, 0xb04d43efU, 0x4d54ccaaU, 0x04dfe496U, + 0xb5e39ed1U, 0x881b4c6aU, 0x1fb8c12cU, 0x517f4665U, + 0xea049d5eU, 0x355d018cU, 0x7473fa87U, 0x412efb0bU, + 0x1d5ab367U, 0xd25292dbU, 0x5633e910U, 0x47136dd6U, + 0x618c9ad7U, 0x0c7a37a1U, 0x148e59f8U, 0x3c89eb13U, + 0x27eecea9U, 0xc935b761U, 0xe5ede11cU, 0xb13c7a47U, + 0xdf599cd2U, 0x733f55f2U, 0xce791814U, 0x37bf73c7U, + 0xcdea53f7U, 0xaa5b5ffdU, 0x6f14df3dU, 0xdb867844U, + 0xf381caafU, 0xc43eb968U, 0x342c3824U, 0x405fc2a3U, + 0xc372161dU, 0x250cbce2U, 0x498b283cU, 0x9541ff0dU, + 0x017139a8U, 0xb3de080cU, 0xe49cd8b4U, 0xc1906456U, + 0x84617bcbU, 0xb670d532U, 0x5c74486cU, 0x5742d0b8U, +}, +{ + 0xf4a75051U, 0x4165537eU, 0x17a4c31aU, 0x275e963aU, + 0xab6bcb3bU, 0x9d45f11fU, 0xfa58abacU, 0xe303934bU, + 0x30fa5520U, 0x766df6adU, 0xcc769188U, 0x024c25f5U, + 0xe5d7fc4fU, 0x2acbd7c5U, 0x35448026U, 0x62a38fb5U, + 0xb15a49deU, 0xba1b6725U, 0xea0e9845U, 0xfec0e15dU, + 0x2f7502c3U, 0x4cf01281U, 0x4697a38dU, 0xd3f9c66bU, + 0x8f5fe703U, 0x929c9515U, 0x6d7aebbfU, 0x5259da95U, + 0xbe832dd4U, 0x7421d358U, 0xe0692949U, 0xc9c8448eU, + 0xc2896a75U, 0x8e7978f4U, 0x583e6b99U, 0xb971dd27U, + 0xe14fb6beU, 0x88ad17f0U, 0x20ac66c9U, 0xce3ab47dU, + 0xdf4a1863U, 0x1a3182e5U, 0x51336097U, 0x537f4562U, + 0x6477e0b1U, 0x6bae84bbU, 0x81a01cfeU, 0x082b94f9U, + 0x48685870U, 0x45fd198fU, 0xde6c8794U, 0x7bf8b752U, + 0x73d323abU, 0x4b02e272U, 0x1f8f57e3U, 0x55ab2a66U, + 0xeb2807b2U, 0xb5c2032fU, 0xc57b9a86U, 0x3708a5d3U, + 0x2887f230U, 0xbfa5b223U, 0x036aba02U, 0x16825cedU, + 0xcf1c2b8aU, 0x79b492a7U, 0x07f2f0f3U, 0x69e2a14eU, + 0xdaf4cd65U, 0x05bed506U, 0x34621fd1U, 0xa6fe8ac4U, + 0x2e539d34U, 0xf355a0a2U, 0x8ae13205U, 0xf6eb75a4U, + 0x83ec390bU, 0x60efaa40U, 0x719f065eU, 0x6e1051bdU, + 0x218af93eU, 0xdd063d96U, 0x3e05aeddU, 0xe6bd464dU, + 0x548db591U, 0xc45d0571U, 0x06d46f04U, 0x5015ff60U, + 0x98fb2419U, 0xbde997d6U, 0x4043cc89U, 0xd99e7767U, + 0xe842bdb0U, 0x898b8807U, 0x195b38e7U, 0xc8eedb79U, + 0x7c0a47a1U, 0x420fe97cU, 0x841ec9f8U, 0x00000000U, + 0x80868309U, 0x2bed4832U, 0x1170ac1eU, 0x5a724e6cU, + 0x0efffbfdU, 0x8538560fU, 0xaed51e3dU, 0x2d392736U, + 0x0fd9640aU, 0x5ca62168U, 0x5b54d19bU, 0x362e3a24U, + 0x0a67b10cU, 0x57e70f93U, 0xee96d2b4U, 0x9b919e1bU, + 0xc0c54f80U, 0xdc20a261U, 0x774b695aU, 0x121a161cU, + 0x93ba0ae2U, 0xa02ae5c0U, 0x22e0433cU, 0x1b171d12U, + 0x090d0b0eU, 0x8bc7adf2U, 0xb6a8b92dU, 0x1ea9c814U, + 0xf1198557U, 0x75074cafU, 0x99ddbbeeU, 0x7f60fda3U, + 0x01269ff7U, 0x72f5bc5cU, 0x663bc544U, 0xfb7e345bU, + 0x4329768bU, 0x23c6dccbU, 0xedfc68b6U, 0xe4f163b8U, + 0x31dccad7U, 0x63851042U, 0x97224013U, 0xc6112084U, + 0x4a247d85U, 0xbb3df8d2U, 0xf93211aeU, 0x29a16dc7U, + 0x9e2f4b1dU, 0xb230f3dcU, 0x8652ec0dU, 0xc1e3d077U, + 0xb3166c2bU, 0x70b999a9U, 0x9448fa11U, 0xe9642247U, + 0xfc8cc4a8U, 0xf03f1aa0U, 0x7d2cd856U, 0x3390ef22U, + 0x494ec787U, 0x38d1c1d9U, 0xcaa2fe8cU, 0xd40b3698U, + 0xf581cfa6U, 0x7ade28a5U, 0xb78e26daU, 0xadbfa43fU, + 0x3a9de42cU, 0x78920d50U, 0x5fcc9b6aU, 0x7e466254U, + 0x8d13c2f6U, 0xd8b8e890U, 0x39f75e2eU, 0xc3aff582U, + 0x5d80be9fU, 0xd0937c69U, 0xd52da96fU, 0x2512b3cfU, + 0xac993bc8U, 0x187da710U, 0x9c636ee8U, 0x3bbb7bdbU, + 0x267809cdU, 0x5918f46eU, 0x9ab701ecU, 0x4f9aa883U, + 0x956e65e6U, 0xffe67eaaU, 0xbccf0821U, 0x15e8e6efU, + 0xe79bd9baU, 0x6f36ce4aU, 0x9f09d4eaU, 0xb07cd629U, + 0xa4b2af31U, 0x3f23312aU, 0xa59430c6U, 0xa266c035U, + 0x4ebc3774U, 0x82caa6fcU, 0x90d0b0e0U, 0xa7d81533U, + 0x04984af1U, 0xecdaf741U, 0xcd500e7fU, 0x91f62f17U, + 0x4dd68d76U, 0xefb04d43U, 0xaa4d54ccU, 0x9604dfe4U, + 0xd1b5e39eU, 0x6a881b4cU, 0x2c1fb8c1U, 0x65517f46U, + 0x5eea049dU, 0x8c355d01U, 0x877473faU, 0x0b412efbU, + 0x671d5ab3U, 0xdbd25292U, 0x105633e9U, 0xd647136dU, + 0xd7618c9aU, 0xa10c7a37U, 0xf8148e59U, 0x133c89ebU, + 0xa927eeceU, 0x61c935b7U, 0x1ce5ede1U, 0x47b13c7aU, + 0xd2df599cU, 0xf2733f55U, 0x14ce7918U, 0xc737bf73U, + 0xf7cdea53U, 0xfdaa5b5fU, 0x3d6f14dfU, 0x44db8678U, + 0xaff381caU, 0x68c43eb9U, 0x24342c38U, 0xa3405fc2U, + 0x1dc37216U, 0xe2250cbcU, 0x3c498b28U, 0x0d9541ffU, + 0xa8017139U, 0x0cb3de08U, 0xb4e49cd8U, 0x56c19064U, + 0xcb84617bU, 0x32b670d5U, 0x6c5c7448U, 0xb85742d0U, +}, +{ + 0x52525252U, 0x09090909U, 0x6a6a6a6aU, 0xd5d5d5d5U, + 0x30303030U, 0x36363636U, 0xa5a5a5a5U, 0x38383838U, + 0xbfbfbfbfU, 0x40404040U, 0xa3a3a3a3U, 0x9e9e9e9eU, + 0x81818181U, 0xf3f3f3f3U, 0xd7d7d7d7U, 0xfbfbfbfbU, + 0x7c7c7c7cU, 0xe3e3e3e3U, 0x39393939U, 0x82828282U, + 0x9b9b9b9bU, 0x2f2f2f2fU, 0xffffffffU, 0x87878787U, + 0x34343434U, 0x8e8e8e8eU, 0x43434343U, 0x44444444U, + 0xc4c4c4c4U, 0xdedededeU, 0xe9e9e9e9U, 0xcbcbcbcbU, + 0x54545454U, 0x7b7b7b7bU, 0x94949494U, 0x32323232U, + 0xa6a6a6a6U, 0xc2c2c2c2U, 0x23232323U, 0x3d3d3d3dU, + 0xeeeeeeeeU, 0x4c4c4c4cU, 0x95959595U, 0x0b0b0b0bU, + 0x42424242U, 0xfafafafaU, 0xc3c3c3c3U, 0x4e4e4e4eU, + 0x08080808U, 0x2e2e2e2eU, 0xa1a1a1a1U, 0x66666666U, + 0x28282828U, 0xd9d9d9d9U, 0x24242424U, 0xb2b2b2b2U, + 0x76767676U, 0x5b5b5b5bU, 0xa2a2a2a2U, 0x49494949U, + 0x6d6d6d6dU, 0x8b8b8b8bU, 0xd1d1d1d1U, 0x25252525U, + 0x72727272U, 0xf8f8f8f8U, 0xf6f6f6f6U, 0x64646464U, + 0x86868686U, 0x68686868U, 0x98989898U, 0x16161616U, + 0xd4d4d4d4U, 0xa4a4a4a4U, 0x5c5c5c5cU, 0xccccccccU, + 0x5d5d5d5dU, 0x65656565U, 0xb6b6b6b6U, 0x92929292U, + 0x6c6c6c6cU, 0x70707070U, 0x48484848U, 0x50505050U, + 0xfdfdfdfdU, 0xededededU, 0xb9b9b9b9U, 0xdadadadaU, + 0x5e5e5e5eU, 0x15151515U, 0x46464646U, 0x57575757U, + 0xa7a7a7a7U, 0x8d8d8d8dU, 0x9d9d9d9dU, 0x84848484U, + 0x90909090U, 0xd8d8d8d8U, 0xababababU, 0x00000000U, + 0x8c8c8c8cU, 0xbcbcbcbcU, 0xd3d3d3d3U, 0x0a0a0a0aU, + 0xf7f7f7f7U, 0xe4e4e4e4U, 0x58585858U, 0x05050505U, + 0xb8b8b8b8U, 0xb3b3b3b3U, 0x45454545U, 0x06060606U, + 0xd0d0d0d0U, 0x2c2c2c2cU, 0x1e1e1e1eU, 0x8f8f8f8fU, + 0xcacacacaU, 0x3f3f3f3fU, 0x0f0f0f0fU, 0x02020202U, + 0xc1c1c1c1U, 0xafafafafU, 0xbdbdbdbdU, 0x03030303U, + 0x01010101U, 0x13131313U, 0x8a8a8a8aU, 0x6b6b6b6bU, + 0x3a3a3a3aU, 0x91919191U, 0x11111111U, 0x41414141U, + 0x4f4f4f4fU, 0x67676767U, 0xdcdcdcdcU, 0xeaeaeaeaU, + 0x97979797U, 0xf2f2f2f2U, 0xcfcfcfcfU, 0xcecececeU, + 0xf0f0f0f0U, 0xb4b4b4b4U, 0xe6e6e6e6U, 0x73737373U, + 0x96969696U, 0xacacacacU, 0x74747474U, 0x22222222U, + 0xe7e7e7e7U, 0xadadadadU, 0x35353535U, 0x85858585U, + 0xe2e2e2e2U, 0xf9f9f9f9U, 0x37373737U, 0xe8e8e8e8U, + 0x1c1c1c1cU, 0x75757575U, 0xdfdfdfdfU, 0x6e6e6e6eU, + 0x47474747U, 0xf1f1f1f1U, 0x1a1a1a1aU, 0x71717171U, + 0x1d1d1d1dU, 0x29292929U, 0xc5c5c5c5U, 0x89898989U, + 0x6f6f6f6fU, 0xb7b7b7b7U, 0x62626262U, 0x0e0e0e0eU, + 0xaaaaaaaaU, 0x18181818U, 0xbebebebeU, 0x1b1b1b1bU, + 0xfcfcfcfcU, 0x56565656U, 0x3e3e3e3eU, 0x4b4b4b4bU, + 0xc6c6c6c6U, 0xd2d2d2d2U, 0x79797979U, 0x20202020U, + 0x9a9a9a9aU, 0xdbdbdbdbU, 0xc0c0c0c0U, 0xfefefefeU, + 0x78787878U, 0xcdcdcdcdU, 0x5a5a5a5aU, 0xf4f4f4f4U, + 0x1f1f1f1fU, 0xddddddddU, 0xa8a8a8a8U, 0x33333333U, + 0x88888888U, 0x07070707U, 0xc7c7c7c7U, 0x31313131U, + 0xb1b1b1b1U, 0x12121212U, 0x10101010U, 0x59595959U, + 0x27272727U, 0x80808080U, 0xececececU, 0x5f5f5f5fU, + 0x60606060U, 0x51515151U, 0x7f7f7f7fU, 0xa9a9a9a9U, + 0x19191919U, 0xb5b5b5b5U, 0x4a4a4a4aU, 0x0d0d0d0dU, + 0x2d2d2d2dU, 0xe5e5e5e5U, 0x7a7a7a7aU, 0x9f9f9f9fU, + 0x93939393U, 0xc9c9c9c9U, 0x9c9c9c9cU, 0xefefefefU, + 0xa0a0a0a0U, 0xe0e0e0e0U, 0x3b3b3b3bU, 0x4d4d4d4dU, + 0xaeaeaeaeU, 0x2a2a2a2aU, 0xf5f5f5f5U, 0xb0b0b0b0U, + 0xc8c8c8c8U, 0xebebebebU, 0xbbbbbbbbU, 0x3c3c3c3cU, + 0x83838383U, 0x53535353U, 0x99999999U, 0x61616161U, + 0x17171717U, 0x2b2b2b2bU, 0x04040404U, 0x7e7e7e7eU, + 0xbabababaU, 0x77777777U, 0xd6d6d6d6U, 0x26262626U, + 0xe1e1e1e1U, 0x69696969U, 0x14141414U, 0x63636363U, + 0x55555555U, 0x21212121U, 0x0c0c0c0cU, 0x7d7d7d7dU, +} +}; + + + +#define GETBYTE(x, y) (word32)((byte)((x) >> (8 * (y)))) + + +#ifdef CYASSL_AESNI + +#define cpuid(func,ax,bx,cx,dx)\ + __asm__ __volatile__ ("cpuid":\ + "=a" (ax), "=b" (bx), "=c" (cx), "=d" (dx) : "a" (func)); + +static int Check_CPU_support_AES() +{ + unsigned int a,b,c,d; + cpuid(1,a,b,c,d); + + if (c & 0x2000000) + return 1; + + return 0; +} + +static int checkAESNI = 0; +static int haveAESNI = 0; + + +void AES_CBC_encrypt(const unsigned char* in, unsigned char* out, + unsigned char* ivec, unsigned long length, + const unsigned char* KS, int nr); + + +void AES_CBC_decrypt(const unsigned char* in, unsigned char* out, + unsigned char* ivec, unsigned long length, + const unsigned char* KS, int nr); + +void AES_128_Key_Expansion(const unsigned char* userkey, + unsigned char* key_schedule); + +void AES_192_Key_Expansion(const unsigned char* userkey, + unsigned char* key_schedule); + +void AES_256_Key_Expansion(const unsigned char* userkey, + unsigned char* key_schedule); + + +int AES_set_encrypt_key (const unsigned char *userKey, const int bits, + Aes* aes) +{ + if (!userKey || !aes) + return -1; + + if (bits == 128) { + AES_128_Key_Expansion (userKey,(byte*)aes->key); aes->rounds = 10; + return 0; + } + else if (bits == 192) { + AES_192_Key_Expansion (userKey,(byte*)aes->key); aes->rounds = 12; + return 0; + } + else if (bits == 256) { + AES_256_Key_Expansion (userKey,(byte*)aes->key); aes->rounds = 14; + return 0; + } + return -1; +} + + +int AES_set_decrypt_key (const unsigned char* userKey, const int bits, + Aes* aes) +{ + int nr; + Aes temp_key; + __m128i *Key_Schedule = (__m128i*)aes->key; + __m128i *Temp_Key_Schedule = (__m128i*)temp_key.key; + + if (!userKey || !aes) + return -1; + + if (AES_set_encrypt_key(userKey,bits,&temp_key) == -1) + return -1; + + nr = temp_key.rounds; + aes->rounds = nr; + + Key_Schedule[nr] = Temp_Key_Schedule[0]; + Key_Schedule[nr-1] = _mm_aesimc_si128(Temp_Key_Schedule[1]); + Key_Schedule[nr-2] = _mm_aesimc_si128(Temp_Key_Schedule[2]); + Key_Schedule[nr-3] = _mm_aesimc_si128(Temp_Key_Schedule[3]); + Key_Schedule[nr-4] = _mm_aesimc_si128(Temp_Key_Schedule[4]); + Key_Schedule[nr-5] = _mm_aesimc_si128(Temp_Key_Schedule[5]); + Key_Schedule[nr-6] = _mm_aesimc_si128(Temp_Key_Schedule[6]); + Key_Schedule[nr-7] = _mm_aesimc_si128(Temp_Key_Schedule[7]); + Key_Schedule[nr-8] = _mm_aesimc_si128(Temp_Key_Schedule[8]); + Key_Schedule[nr-9] = _mm_aesimc_si128(Temp_Key_Schedule[9]); + + if(nr>10) { + Key_Schedule[nr-10] = _mm_aesimc_si128(Temp_Key_Schedule[10]); + Key_Schedule[nr-11] = _mm_aesimc_si128(Temp_Key_Schedule[11]); + } + + if(nr>12) { + Key_Schedule[nr-12] = _mm_aesimc_si128(Temp_Key_Schedule[12]); + Key_Schedule[nr-13] = _mm_aesimc_si128(Temp_Key_Schedule[13]); + } + + Key_Schedule[0] = Temp_Key_Schedule[nr]; + + return 0; +} + + + +#endif /* CYASSL_AESNI */ + + +int AesSetKey(Aes* aes, const byte* userKey, word32 keylen, const byte* iv, + int dir) +{ + word32 temp, *rk = aes->key; + unsigned int i = 0; + + if (!((keylen == 16) || (keylen == 24) || (keylen == 32))) + return -1; + +#ifdef CYASSL_AESNI + if (checkAESNI == 0) { + haveAESNI = Check_CPU_support_AES(); + checkAESNI = 1; + } + if (haveAESNI) { + XMEMCPY(aes->reg, iv, AES_BLOCK_SIZE); + if (dir == AES_ENCRYPTION) + return AES_set_encrypt_key(userKey, keylen * 8, aes); + else + return AES_set_decrypt_key(userKey, keylen * 8, aes); + } +#endif /* CYASSL_AESNI */ + + aes->rounds = keylen/4 + 6; + + XMEMCPY(rk, userKey, keylen); + #ifdef LITTLE_ENDIAN_ORDER + ByteReverseWords(rk, rk, keylen); + #endif + + switch(keylen) + { + case 16: + while (1) + { + temp = rk[3]; + rk[4] = rk[0] ^ + (Te[4][GETBYTE(temp, 2)] & 0xff000000) ^ + (Te[4][GETBYTE(temp, 1)] & 0x00ff0000) ^ + (Te[4][GETBYTE(temp, 0)] & 0x0000ff00) ^ + (Te[4][GETBYTE(temp, 3)] & 0x000000ff) ^ + 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; + } + break; + + case 24: + while (1) /* for (;;) here triggers a bug in VC60 SP4 w/ Pro Pack */ + { + temp = rk[ 5]; + rk[ 6] = rk[ 0] ^ + (Te[4][GETBYTE(temp, 2)] & 0xff000000) ^ + (Te[4][GETBYTE(temp, 1)] & 0x00ff0000) ^ + (Te[4][GETBYTE(temp, 0)] & 0x0000ff00) ^ + (Te[4][GETBYTE(temp, 3)] & 0x000000ff) ^ + 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; + } + break; + + case 32: + while (1) + { + temp = rk[ 7]; + rk[ 8] = rk[ 0] ^ + (Te[4][GETBYTE(temp, 2)] & 0xff000000) ^ + (Te[4][GETBYTE(temp, 1)] & 0x00ff0000) ^ + (Te[4][GETBYTE(temp, 0)] & 0x0000ff00) ^ + (Te[4][GETBYTE(temp, 3)] & 0x000000ff) ^ + 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] ^ + (Te[4][GETBYTE(temp, 3)] & 0xff000000) ^ + (Te[4][GETBYTE(temp, 2)] & 0x00ff0000) ^ + (Te[4][GETBYTE(temp, 1)] & 0x0000ff00) ^ + (Te[4][GETBYTE(temp, 0)] & 0x000000ff); + rk[13] = rk[ 5] ^ rk[12]; + rk[14] = rk[ 6] ^ rk[13]; + rk[15] = rk[ 7] ^ rk[14]; + + rk += 8; + } + break; + } + + if (dir == AES_DECRYPTION) + { + unsigned int i, j; + rk = aes->key; + + /* invert the order of the round keys: */ + for (i = 0, j = 4* aes->rounds; i < j; i += 4, j -= 4) { + temp = rk[i ]; rk[i ] = rk[j ]; rk[j ] = temp; + temp = rk[i + 1]; rk[i + 1] = rk[j + 1]; rk[j + 1] = temp; + temp = rk[i + 2]; rk[i + 2] = rk[j + 2]; rk[j + 2] = temp; + temp = rk[i + 3]; rk[i + 3] = rk[j + 3]; rk[j + 3] = temp; + } + /* apply the inverse MixColumn transform to all round keys but the + first and the last: */ + for (i = 1; i < aes->rounds; i++) { + rk += 4; + rk[0] = + Td[0][Te[4][GETBYTE(rk[0], 3)] & 0xff] ^ + Td[1][Te[4][GETBYTE(rk[0], 2)] & 0xff] ^ + Td[2][Te[4][GETBYTE(rk[0], 1)] & 0xff] ^ + Td[3][Te[4][GETBYTE(rk[0], 0)] & 0xff]; + rk[1] = + Td[0][Te[4][GETBYTE(rk[1], 3)] & 0xff] ^ + Td[1][Te[4][GETBYTE(rk[1], 2)] & 0xff] ^ + Td[2][Te[4][GETBYTE(rk[1], 1)] & 0xff] ^ + Td[3][Te[4][GETBYTE(rk[1], 0)] & 0xff]; + rk[2] = + Td[0][Te[4][GETBYTE(rk[2], 3)] & 0xff] ^ + Td[1][Te[4][GETBYTE(rk[2], 2)] & 0xff] ^ + Td[2][Te[4][GETBYTE(rk[2], 1)] & 0xff] ^ + Td[3][Te[4][GETBYTE(rk[2], 0)] & 0xff]; + rk[3] = + Td[0][Te[4][GETBYTE(rk[3], 3)] & 0xff] ^ + Td[1][Te[4][GETBYTE(rk[3], 2)] & 0xff] ^ + Td[2][Te[4][GETBYTE(rk[3], 1)] & 0xff] ^ + Td[3][Te[4][GETBYTE(rk[3], 0)] & 0xff]; + } + } + XMEMCPY(aes->reg, iv, AES_BLOCK_SIZE); + + return 0; +} + + +void AesEncrypt(Aes* aes, const byte* inBlock, byte* outBlock) +{ + word32 s0, s1, s2, s3; + word32 t0, t1, t2, t3; + word32 r = aes->rounds >> 1; + + const word32* rk = aes->key; + /* + * map byte array block to cipher state + * and add initial round key: + */ + XMEMCPY(&s0, inBlock, sizeof(s0)); + XMEMCPY(&s1, inBlock + sizeof(s0), sizeof(s1)); + XMEMCPY(&s2, inBlock + 2 * sizeof(s0), sizeof(s2)); + XMEMCPY(&s3, inBlock + 3 * sizeof(s0), sizeof(s3)); + + #ifdef LITTLE_ENDIAN_ORDER + s0 = ByteReverseWord32(s0); + s1 = ByteReverseWord32(s1); + s2 = ByteReverseWord32(s2); + s3 = ByteReverseWord32(s3); + #endif + + s0 ^= rk[0]; + s1 ^= rk[1]; + s2 ^= rk[2]; + s3 ^= rk[3]; + + /* + * Nr - 1 full rounds: + */ + + for (;;) { + t0 = + Te[0][GETBYTE(s0, 3)] ^ + Te[1][GETBYTE(s1, 2)] ^ + Te[2][GETBYTE(s2, 1)] ^ + Te[3][GETBYTE(s3, 0)] ^ + rk[4]; + t1 = + Te[0][GETBYTE(s1, 3)] ^ + Te[1][GETBYTE(s2, 2)] ^ + Te[2][GETBYTE(s3, 1)] ^ + Te[3][GETBYTE(s0, 0)] ^ + rk[5]; + t2 = + Te[0][GETBYTE(s2, 3)] ^ + Te[1][GETBYTE(s3, 2)] ^ + Te[2][GETBYTE(s0, 1)] ^ + Te[3][GETBYTE(s1, 0)] ^ + rk[6]; + t3 = + Te[0][GETBYTE(s3, 3)] ^ + Te[1][GETBYTE(s0, 2)] ^ + Te[2][GETBYTE(s1, 1)] ^ + Te[3][GETBYTE(s2, 0)] ^ + rk[7]; + + rk += 8; + if (--r == 0) { + break; + } + + s0 = + Te[0][GETBYTE(t0, 3)] ^ + Te[1][GETBYTE(t1, 2)] ^ + Te[2][GETBYTE(t2, 1)] ^ + Te[3][GETBYTE(t3, 0)] ^ + rk[0]; + s1 = + Te[0][GETBYTE(t1, 3)] ^ + Te[1][GETBYTE(t2, 2)] ^ + Te[2][GETBYTE(t3, 1)] ^ + Te[3][GETBYTE(t0, 0)] ^ + rk[1]; + s2 = + Te[0][GETBYTE(t2, 3)] ^ + Te[1][GETBYTE(t3, 2)] ^ + Te[2][GETBYTE(t0, 1)] ^ + Te[3][GETBYTE(t1, 0)] ^ + rk[2]; + s3 = + Te[0][GETBYTE(t3, 3)] ^ + Te[1][GETBYTE(t0, 2)] ^ + Te[2][GETBYTE(t1, 1)] ^ + Te[3][GETBYTE(t2, 0)] ^ + rk[3]; + } + + /* + * apply last round and + * map cipher state to byte array block: + */ + + s0 = + (Te[4][GETBYTE(t0, 3)] & 0xff000000) ^ + (Te[4][GETBYTE(t1, 2)] & 0x00ff0000) ^ + (Te[4][GETBYTE(t2, 1)] & 0x0000ff00) ^ + (Te[4][GETBYTE(t3, 0)] & 0x000000ff) ^ + rk[0]; + s1 = + (Te[4][GETBYTE(t1, 3)] & 0xff000000) ^ + (Te[4][GETBYTE(t2, 2)] & 0x00ff0000) ^ + (Te[4][GETBYTE(t3, 1)] & 0x0000ff00) ^ + (Te[4][GETBYTE(t0, 0)] & 0x000000ff) ^ + rk[1]; + s2 = + (Te[4][GETBYTE(t2, 3)] & 0xff000000) ^ + (Te[4][GETBYTE(t3, 2)] & 0x00ff0000) ^ + (Te[4][GETBYTE(t0, 1)] & 0x0000ff00) ^ + (Te[4][GETBYTE(t1, 0)] & 0x000000ff) ^ + rk[2]; + s3 = + (Te[4][GETBYTE(t3, 3)] & 0xff000000) ^ + (Te[4][GETBYTE(t0, 2)] & 0x00ff0000) ^ + (Te[4][GETBYTE(t1, 1)] & 0x0000ff00) ^ + (Te[4][GETBYTE(t2, 0)] & 0x000000ff) ^ + rk[3]; + + /* write out */ + #ifdef LITTLE_ENDIAN_ORDER + s0 = ByteReverseWord32(s0); + s1 = ByteReverseWord32(s1); + s2 = ByteReverseWord32(s2); + s3 = ByteReverseWord32(s3); + #endif + + XMEMCPY(outBlock, &s0, sizeof(s0)); + XMEMCPY(outBlock + sizeof(s0), &s1, sizeof(s1)); + XMEMCPY(outBlock + 2 * sizeof(s0), &s2, sizeof(s2)); + XMEMCPY(outBlock + 3 * sizeof(s0), &s3, sizeof(s3)); +} + + +void AesDecrypt(Aes* aes, const byte* inBlock, byte* outBlock) +{ + word32 s0, s1, s2, s3; + word32 t0, t1, t2, t3; + word32 r = aes->rounds >> 1; + + const word32* rk = aes->key; + /* + * map byte array block to cipher state + * and add initial round key: + */ + XMEMCPY(&s0, inBlock, sizeof(s0)); + XMEMCPY(&s1, inBlock + sizeof(s0), sizeof(s1)); + XMEMCPY(&s2, inBlock + 2 * sizeof(s0), sizeof(s2)); + XMEMCPY(&s3, inBlock + 3 * sizeof(s0), sizeof(s3)); + + #ifdef LITTLE_ENDIAN_ORDER + s0 = ByteReverseWord32(s0); + s1 = ByteReverseWord32(s1); + s2 = ByteReverseWord32(s2); + s3 = ByteReverseWord32(s3); + #endif + + s0 ^= rk[0]; + s1 ^= rk[1]; + s2 ^= rk[2]; + s3 ^= rk[3]; + + /* + * Nr - 1 full rounds: + */ + + for (;;) { + t0 = + Td[0][GETBYTE(s0, 3)] ^ + Td[1][GETBYTE(s3, 2)] ^ + Td[2][GETBYTE(s2, 1)] ^ + Td[3][GETBYTE(s1, 0)] ^ + rk[4]; + t1 = + Td[0][GETBYTE(s1, 3)] ^ + Td[1][GETBYTE(s0, 2)] ^ + Td[2][GETBYTE(s3, 1)] ^ + Td[3][GETBYTE(s2, 0)] ^ + rk[5]; + t2 = + Td[0][GETBYTE(s2, 3)] ^ + Td[1][GETBYTE(s1, 2)] ^ + Td[2][GETBYTE(s0, 1)] ^ + Td[3][GETBYTE(s3, 0)] ^ + rk[6]; + t3 = + Td[0][GETBYTE(s3, 3)] ^ + Td[1][GETBYTE(s2, 2)] ^ + Td[2][GETBYTE(s1, 1)] ^ + Td[3][GETBYTE(s0, 0)] ^ + rk[7]; + + rk += 8; + if (--r == 0) { + break; + } + + s0 = + Td[0][GETBYTE(t0, 3)] ^ + Td[1][GETBYTE(t3, 2)] ^ + Td[2][GETBYTE(t2, 1)] ^ + Td[3][GETBYTE(t1, 0)] ^ + rk[0]; + s1 = + Td[0][GETBYTE(t1, 3)] ^ + Td[1][GETBYTE(t0, 2)] ^ + Td[2][GETBYTE(t3, 1)] ^ + Td[3][GETBYTE(t2, 0)] ^ + rk[1]; + s2 = + Td[0][GETBYTE(t2, 3)] ^ + Td[1][GETBYTE(t1, 2)] ^ + Td[2][GETBYTE(t0, 1)] ^ + Td[3][GETBYTE(t3, 0)] ^ + rk[2]; + s3 = + Td[0][GETBYTE(t3, 3)] ^ + Td[1][GETBYTE(t2, 2)] ^ + Td[2][GETBYTE(t1, 1)] ^ + Td[3][GETBYTE(t0, 0)] ^ + rk[3]; + } + /* + * apply last round and + * map cipher state to byte array block: + */ + s0 = + (Td[4][GETBYTE(t0, 3)] & 0xff000000) ^ + (Td[4][GETBYTE(t3, 2)] & 0x00ff0000) ^ + (Td[4][GETBYTE(t2, 1)] & 0x0000ff00) ^ + (Td[4][GETBYTE(t1, 0)] & 0x000000ff) ^ + rk[0]; + s1 = + (Td[4][GETBYTE(t1, 3)] & 0xff000000) ^ + (Td[4][GETBYTE(t0, 2)] & 0x00ff0000) ^ + (Td[4][GETBYTE(t3, 1)] & 0x0000ff00) ^ + (Td[4][GETBYTE(t2, 0)] & 0x000000ff) ^ + rk[1]; + s2 = + (Td[4][GETBYTE(t2, 3)] & 0xff000000) ^ + (Td[4][GETBYTE(t1, 2)] & 0x00ff0000) ^ + (Td[4][GETBYTE(t0, 1)] & 0x0000ff00) ^ + (Td[4][GETBYTE(t3, 0)] & 0x000000ff) ^ + rk[2]; + s3 = + (Td[4][GETBYTE(t3, 3)] & 0xff000000) ^ + (Td[4][GETBYTE(t2, 2)] & 0x00ff0000) ^ + (Td[4][GETBYTE(t1, 1)] & 0x0000ff00) ^ + (Td[4][GETBYTE(t0, 0)] & 0x000000ff) ^ + rk[3]; + + /* write out */ + #ifdef LITTLE_ENDIAN_ORDER + s0 = ByteReverseWord32(s0); + s1 = ByteReverseWord32(s1); + s2 = ByteReverseWord32(s2); + s3 = ByteReverseWord32(s3); + #endif + + XMEMCPY(outBlock, &s0, sizeof(s0)); + XMEMCPY(outBlock + sizeof(s0), &s1, sizeof(s1)); + XMEMCPY(outBlock + 2 * sizeof(s0), &s2, sizeof(s2)); + XMEMCPY(outBlock + 3 * sizeof(s0), &s3, sizeof(s3)); +} + + +void AesCbcEncrypt(Aes* aes, byte* out, const byte* in, word32 sz) +{ + word32 blocks = sz / AES_BLOCK_SIZE; + +#ifdef CYASSL_AESNI + if (haveAESNI) { + #ifdef DEBUG_AESNI + printf("about to aes cbc encrypt\n"); + printf("in = %p\n", in); + printf("out = %p\n", out); + printf("aes->key = %p\n", aes->key); + printf("aes->reg = %p\n", aes->reg); + printf("aes->rounds = %d\n", aes->rounds); + printf("sz = %d\n", sz); + #endif + AES_CBC_encrypt(in, out, (byte*)aes->reg, sz, (byte*)aes->key, + aes->rounds); + /* store iv for next call */ + XMEMCPY(aes->reg, out + sz - AES_BLOCK_SIZE, AES_BLOCK_SIZE); + return; + } +#endif + + while (blocks--) { + xorbuf((byte*)aes->reg, in, AES_BLOCK_SIZE); + AesEncrypt(aes, (byte*)aes->reg, (byte*)aes->reg); + XMEMCPY(out, aes->reg, AES_BLOCK_SIZE); + + out += AES_BLOCK_SIZE; + in += AES_BLOCK_SIZE; + } +} + + +void AesCbcDecrypt(Aes* aes, byte* out, const byte* in, word32 sz) +{ + word32 blocks = sz / AES_BLOCK_SIZE; + +#ifdef CYASSL_AESNI + if (haveAESNI) { + #ifdef DEBUG_AESNI + printf("about to aes cbc decrypt\n"); + printf("in = %p\n", in); + printf("out = %p\n", out); + printf("aes->key = %p\n", aes->key); + printf("aes->reg = %p\n", aes->reg); + printf("aes->rounds = %d\n", aes->rounds); + printf("sz = %d\n", sz); + #endif + + /* if input and output same will overwirte input iv */ + XMEMCPY(aes->tmp, in + sz - AES_BLOCK_SIZE, AES_BLOCK_SIZE); + AES_CBC_decrypt(in, out, (byte*)aes->reg, sz, (byte*)aes->key, + aes->rounds); + /* store iv for next call */ + XMEMCPY(aes->reg, aes->tmp, AES_BLOCK_SIZE); + return; + } +#endif + + while (blocks--) { + XMEMCPY(aes->tmp, in, AES_BLOCK_SIZE); + AesDecrypt(aes, (byte*)aes->tmp, out); + xorbuf(out, (byte*)aes->reg, AES_BLOCK_SIZE); + XMEMCPY(aes->reg, aes->tmp, AES_BLOCK_SIZE); + + out += AES_BLOCK_SIZE; + in += AES_BLOCK_SIZE; + } +} + + +#endif /* NO_AES */ + diff --git a/ctaocrypt/src/aes_asm.s b/ctaocrypt/src/aes_asm.s new file mode 100755 index 000000000..4aa358619 --- /dev/null +++ b/ctaocrypt/src/aes_asm.s @@ -0,0 +1,484 @@ +/* aes_asm.s + * + * Copyright (C) 2006-2011 Sawtooth Consulting Ltd. + * + * This file is part of CyaSSL. + * + * CyaSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * CyaSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + + +/* See Intel® Advanced Encryption Standard (AES) Instructions Set White Paper + * by Intel Mobility Group, Israel Development Center, Israel Shay Gueron + */ + + +//AES_CBC_encrypt (const unsigned char *in, +// unsigned char *out, +// unsigned char ivec[16], +// unsigned long length, +// const unsigned char *KS, +// int nr) +.globl AES_CBC_encrypt +AES_CBC_encrypt: +# parameter 1: %rdi +# parameter 2: %rsi +# parameter 3: %rdx +# parameter 4: %rcx +# parameter 5: %r8 +# parameter 6: %r9d +movq %rcx, %r10 +shrq $4, %rcx +shlq $60, %r10 +je NO_PARTS +addq $1, %rcx +NO_PARTS: +subq $16, %rsi +movdqa (%rdx), %xmm1 +LOOP: +pxor (%rdi), %xmm1 +pxor (%r8), %xmm1 +addq $16,%rsi +addq $16,%rdi +cmpl $12, %r9d +aesenc 16(%r8),%xmm1 +aesenc 32(%r8),%xmm1 +aesenc 48(%r8),%xmm1 +aesenc 64(%r8),%xmm1 +aesenc 80(%r8),%xmm1 +aesenc 96(%r8),%xmm1 +aesenc 112(%r8),%xmm1 +aesenc 128(%r8),%xmm1 +aesenc 144(%r8),%xmm1 +movdqa 160(%r8),%xmm2 +jb LAST +cmpl $14, %r9d + +aesenc 160(%r8),%xmm1 +aesenc 176(%r8),%xmm1 +movdqa 192(%r8),%xmm2 +jb LAST +aesenc 192(%r8),%xmm1 +aesenc 208(%r8),%xmm1 +movdqa 224(%r8),%xmm2 +LAST: +decq %rcx +aesenclast %xmm2,%xmm1 +movdqu %xmm1,(%rsi) +jne LOOP +ret + + + +//AES_CBC_decrypt (const unsigned char *in, +// unsigned char *out, +// unsigned char ivec[16], +// unsigned long length, +// const unsigned char *KS, +// int nr) +.globl AES_CBC_decrypt +AES_CBC_decrypt: +# parameter 1: %rdi +# parameter 2: %rsi +# parameter 3: %rdx +# parameter 4: %rcx +# parameter 5: %r8 +# parameter 6: %r9d + +movq %rcx, %r10 +shrq $4, %rcx +shlq $60, %r10 +je DNO_PARTS_4 +addq $1, %rcx +DNO_PARTS_4: +movq %rcx, %r10 +shlq $62, %r10 +shrq $62, %r10 +shrq $2, %rcx +movdqu (%rdx),%xmm5 +je DREMAINDER_4 +subq $64, %rsi +DLOOP_4: +movdqu (%rdi), %xmm1 +movdqu 16(%rdi), %xmm2 +movdqu 32(%rdi), %xmm3 +movdqu 48(%rdi), %xmm4 +movdqa %xmm1, %xmm6 +movdqa %xmm2, %xmm7 +movdqa %xmm3, %xmm8 +movdqa %xmm4, %xmm15 +movdqa (%r8), %xmm9 +movdqa 16(%r8), %xmm10 +movdqa 32(%r8), %xmm11 +movdqa 48(%r8), %xmm12 +pxor %xmm9, %xmm1 +pxor %xmm9, %xmm2 +pxor %xmm9, %xmm3 + +pxor %xmm9, %xmm4 +aesdec %xmm10, %xmm1 +aesdec %xmm10, %xmm2 +aesdec %xmm10, %xmm3 +aesdec %xmm10, %xmm4 +aesdec %xmm11, %xmm1 +aesdec %xmm11, %xmm2 +aesdec %xmm11, %xmm3 +aesdec %xmm11, %xmm4 +aesdec %xmm12, %xmm1 +aesdec %xmm12, %xmm2 +aesdec %xmm12, %xmm3 +aesdec %xmm12, %xmm4 +movdqa 64(%r8), %xmm9 +movdqa 80(%r8), %xmm10 +movdqa 96(%r8), %xmm11 +movdqa 112(%r8), %xmm12 +aesdec %xmm9, %xmm1 +aesdec %xmm9, %xmm2 +aesdec %xmm9, %xmm3 +aesdec %xmm9, %xmm4 +aesdec %xmm10, %xmm1 +aesdec %xmm10, %xmm2 +aesdec %xmm10, %xmm3 +aesdec %xmm10, %xmm4 +aesdec %xmm11, %xmm1 +aesdec %xmm11, %xmm2 +aesdec %xmm11, %xmm3 +aesdec %xmm11, %xmm4 +aesdec %xmm12, %xmm1 +aesdec %xmm12, %xmm2 +aesdec %xmm12, %xmm3 +aesdec %xmm12, %xmm4 +movdqa 128(%r8), %xmm9 +movdqa 144(%r8), %xmm10 +movdqa 160(%r8), %xmm11 +cmpl $12, %r9d +aesdec %xmm9, %xmm1 +aesdec %xmm9, %xmm2 +aesdec %xmm9, %xmm3 +aesdec %xmm9, %xmm4 +aesdec %xmm10, %xmm1 +aesdec %xmm10, %xmm2 +aesdec %xmm10, %xmm3 +aesdec %xmm10, %xmm4 +jb DLAST_4 +movdqa 160(%r8), %xmm9 +movdqa 176(%r8), %xmm10 +movdqa 192(%r8), %xmm11 +cmpl $14, %r9d +aesdec %xmm9, %xmm1 +aesdec %xmm9, %xmm2 +aesdec %xmm9, %xmm3 +aesdec %xmm9, %xmm4 +aesdec %xmm10, %xmm1 +aesdec %xmm10, %xmm2 +aesdec %xmm10, %xmm3 +aesdec %xmm10, %xmm4 +jb DLAST_4 + +movdqa 192(%r8), %xmm9 +movdqa 208(%r8), %xmm10 +movdqa 224(%r8), %xmm11 +aesdec %xmm9, %xmm1 +aesdec %xmm9, %xmm2 +aesdec %xmm9, %xmm3 +aesdec %xmm9, %xmm4 +aesdec %xmm10, %xmm1 +aesdec %xmm10, %xmm2 +aesdec %xmm10, %xmm3 +aesdec %xmm10, %xmm4 +DLAST_4: +addq $64, %rdi +addq $64, %rsi +decq %rcx +aesdeclast %xmm11, %xmm1 +aesdeclast %xmm11, %xmm2 +aesdeclast %xmm11, %xmm3 +aesdeclast %xmm11, %xmm4 +pxor %xmm5 ,%xmm1 +pxor %xmm6 ,%xmm2 +pxor %xmm7 ,%xmm3 +pxor %xmm8 ,%xmm4 +movdqu %xmm1, (%rsi) +movdqu %xmm2, 16(%rsi) +movdqu %xmm3, 32(%rsi) +movdqu %xmm4, 48(%rsi) +movdqa %xmm15,%xmm5 +jne DLOOP_4 +addq $64, %rsi +DREMAINDER_4: +cmpq $0, %r10 +je DEND_4 +DLOOP_4_2: +movdqu (%rdi), %xmm1 +movdqa %xmm1 ,%xmm15 +addq $16, %rdi +pxor (%r8), %xmm1 +movdqu 160(%r8), %xmm2 +cmpl $12, %r9d +aesdec 16(%r8), %xmm1 +aesdec 32(%r8), %xmm1 +aesdec 48(%r8), %xmm1 +aesdec 64(%r8), %xmm1 +aesdec 80(%r8), %xmm1 +aesdec 96(%r8), %xmm1 +aesdec 112(%r8), %xmm1 +aesdec 128(%r8), %xmm1 +aesdec 144(%r8), %xmm1 +jb DLAST_4_2 +movdqu 192(%r8), %xmm2 +cmpl $14, %r9d +aesdec 160(%r8), %xmm1 +aesdec 176(%r8), %xmm1 +jb DLAST_4_2 +movdqu 224(%r8), %xmm2 +aesdec 192(%r8), %xmm1 +aesdec 208(%r8), %xmm1 +DLAST_4_2: +aesdeclast %xmm2, %xmm1 +pxor %xmm5, %xmm1 +movdqa %xmm15, %xmm5 +movdqu %xmm1, (%rsi) + +addq $16, %rsi +decq %r10 +jne DLOOP_4_2 +DEND_4: +ret + + + + +//void AES_128_Key_Expansion(const unsigned char* userkey, +// unsigned char* key_schedule); +.align 16,0x90 +.globl AES_128_Key_Expansion +AES_128_Key_Expansion: +# parameter 1: %rdi +# parameter 2: %rsi +movl $10, 240(%rsi) + +movdqu (%rdi), %xmm1 +movdqa %xmm1, (%rsi) + + +ASSISTS: +aeskeygenassist $1, %xmm1, %xmm2 +call PREPARE_ROUNDKEY_128 +movdqa %xmm1, 16(%rsi) +aeskeygenassist $2, %xmm1, %xmm2 +call PREPARE_ROUNDKEY_128 +movdqa %xmm1, 32(%rsi) +aeskeygenassist $4, %xmm1, %xmm2 +call PREPARE_ROUNDKEY_128 +movdqa %xmm1, 48(%rsi) +aeskeygenassist $8, %xmm1, %xmm2 +call PREPARE_ROUNDKEY_128 +movdqa %xmm1, 64(%rsi) +aeskeygenassist $16, %xmm1, %xmm2 +call PREPARE_ROUNDKEY_128 +movdqa %xmm1, 80(%rsi) +aeskeygenassist $32, %xmm1, %xmm2 +call PREPARE_ROUNDKEY_128 +movdqa %xmm1, 96(%rsi) +aeskeygenassist $64, %xmm1, %xmm2 +call PREPARE_ROUNDKEY_128 +movdqa %xmm1, 112(%rsi) +aeskeygenassist $0x80, %xmm1, %xmm2 +call PREPARE_ROUNDKEY_128 +movdqa %xmm1, 128(%rsi) +aeskeygenassist $0x1b, %xmm1, %xmm2 +call PREPARE_ROUNDKEY_128 +movdqa %xmm1, 144(%rsi) +aeskeygenassist $0x36, %xmm1, %xmm2 +call PREPARE_ROUNDKEY_128 +movdqa %xmm1, 160(%rsi) +ret + +PREPARE_ROUNDKEY_128: +pshufd $255, %xmm2, %xmm2 +movdqa %xmm1, %xmm3 +pslldq $4, %xmm3 +pxor %xmm3, %xmm1 +pslldq $4, %xmm3 +pxor %xmm3, %xmm1 +pslldq $4, %xmm3 +pxor %xmm3, %xmm1 +pxor %xmm2, %xmm1 +ret + + +//void AES_192_Key_Expansion (const unsigned char *userkey, +// unsigned char *key) +.globl AES_192_Key_Expansion +AES_192_Key_Expansion: +# parameter 1: %rdi +# parameter 2: %rsi + +movdqu (%rdi), %xmm1 +movdqu 16(%rdi), %xmm3 +movdqa %xmm1, (%rsi) +movdqa %xmm3, %xmm5 + +aeskeygenassist $0x1, %xmm3, %xmm2 +call PREPARE_ROUNDKEY_192 +shufpd $0, %xmm1, %xmm5 +movdqa %xmm5, 16(%rsi) +movdqa %xmm1, %xmm6 +shufpd $1, %xmm3, %xmm6 +movdqa %xmm6, 32(%rsi) + +aeskeygenassist $0x2, %xmm3, %xmm2 +call PREPARE_ROUNDKEY_192 +movdqa %xmm1, 48(%rsi) +movdqa %xmm3, %xmm5 + +aeskeygenassist $0x4, %xmm3, %xmm2 +call PREPARE_ROUNDKEY_192 +shufpd $0, %xmm1, %xmm5 +movdqa %xmm5, 64(%rsi) +movdqa %xmm1, %xmm6 +shufpd $1, %xmm3, %xmm6 +movdqa %xmm6, 80(%rsi) + +aeskeygenassist $0x8, %xmm3, %xmm2 +call PREPARE_ROUNDKEY_192 +movdqa %xmm1, 96(%rsi) +movdqa %xmm3, %xmm5 + +aeskeygenassist $0x10, %xmm3, %xmm2 +call PREPARE_ROUNDKEY_192 +shufpd $0, %xmm1, %xmm5 +movdqa %xmm5, 112(%rsi) +movdqa %xmm1, %xmm6 +shufpd $1, %xmm3, %xmm6 +movdqa %xmm6, 128(%rsi) + +aeskeygenassist $0x20, %xmm3, %xmm2 +call PREPARE_ROUNDKEY_192 +movdqa %xmm1, 144(%rsi) +movdqa %xmm3, %xmm5 + +aeskeygenassist $0x40, %xmm3, %xmm2 +call PREPARE_ROUNDKEY_192 +shufpd $0, %xmm1, %xmm5 +movdqa %xmm5, 160(%rsi) +movdqa %xmm1, %xmm6 +shufpd $1, %xmm3, %xmm6 +movdqa %xmm6, 176(%rsi) + +aeskeygenassist $0x80, %xmm3, %xmm2 +call PREPARE_ROUNDKEY_192 +movdqa %xmm1, 192(%rsi) +movdqa %xmm3, 208(%rsi) +ret + +PREPARE_ROUNDKEY_192: +pshufd $0x55, %xmm2, %xmm2 +movdqu %xmm1, %xmm4 +pslldq $4, %xmm4 +pxor %xmm4, %xmm1 + +pslldq $4, %xmm4 +pxor %xmm4, %xmm1 +pslldq $4, %xmm4 +pxor %xmm4, %xmm1 +pxor %xmm2, %xmm1 +pshufd $0xff, %xmm1, %xmm2 +movdqu %xmm3, %xmm4 +pslldq $4, %xmm4 +pxor %xmm4, %xmm3 +pxor %xmm2, %xmm3 +ret + + +//void AES_256_Key_Expansion (const unsigned char *userkey, +// unsigned char *key) +.globl AES_256_Key_Expansion +AES_256_Key_Expansion: +# parameter 1: %rdi +# parameter 2: %rsi + +movdqu (%rdi), %xmm1 +movdqu 16(%rdi), %xmm3 +movdqa %xmm1, (%rsi) +movdqa %xmm3, 16(%rsi) + +aeskeygenassist $0x1, %xmm3, %xmm2 +call MAKE_RK256_a +movdqa %xmm1, 32(%rsi) +aeskeygenassist $0x0, %xmm1, %xmm2 +call MAKE_RK256_b +movdqa %xmm3, 48(%rsi) +aeskeygenassist $0x2, %xmm3, %xmm2 +call MAKE_RK256_a +movdqa %xmm1, 64(%rsi) +aeskeygenassist $0x0, %xmm1, %xmm2 +call MAKE_RK256_b +movdqa %xmm3, 80(%rsi) +aeskeygenassist $0x4, %xmm3, %xmm2 +call MAKE_RK256_a +movdqa %xmm1, 96(%rsi) +aeskeygenassist $0x0, %xmm1, %xmm2 +call MAKE_RK256_b +movdqa %xmm3, 112(%rsi) +aeskeygenassist $0x8, %xmm3, %xmm2 +call MAKE_RK256_a +movdqa %xmm1, 128(%rsi) +aeskeygenassist $0x0, %xmm1, %xmm2 +call MAKE_RK256_b +movdqa %xmm3, 144(%rsi) +aeskeygenassist $0x10, %xmm3, %xmm2 +call MAKE_RK256_a +movdqa %xmm1, 160(%rsi) +aeskeygenassist $0x0, %xmm1, %xmm2 +call MAKE_RK256_b +movdqa %xmm3, 176(%rsi) +aeskeygenassist $0x20, %xmm3, %xmm2 +call MAKE_RK256_a +movdqa %xmm1, 192(%rsi) + +aeskeygenassist $0x0, %xmm1, %xmm2 +call MAKE_RK256_b +movdqa %xmm3, 208(%rsi) +aeskeygenassist $0x40, %xmm3, %xmm2 +call MAKE_RK256_a +movdqa %xmm1, 224(%rsi) + +ret + +MAKE_RK256_a: +pshufd $0xff, %xmm2, %xmm2 +movdqa %xmm1, %xmm4 +pslldq $4, %xmm4 +pxor %xmm4, %xmm1 +pslldq $4, %xmm4 +pxor %xmm4, %xmm1 +pslldq $4, %xmm4 +pxor %xmm4, %xmm1 +pxor %xmm2, %xmm1 +ret + +MAKE_RK256_b: +pshufd $0xaa, %xmm2, %xmm2 +movdqa %xmm3, %xmm4 +pslldq $4, %xmm4 +pxor %xmm4, %xmm3 +pslldq $4, %xmm4 +pxor %xmm4, %xmm3 +pslldq $4, %xmm4 +pxor %xmm4, %xmm3 +pxor %xmm2, %xmm3 +ret + diff --git a/ctaocrypt/src/arc4.c b/ctaocrypt/src/arc4.c new file mode 100644 index 000000000..a9b9729ef --- /dev/null +++ b/ctaocrypt/src/arc4.c @@ -0,0 +1,76 @@ +/* arc4.c + * + * Copyright (C) 2006-2011 Sawtooth Consulting Ltd. + * + * This file is part of CyaSSL. + * + * CyaSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * CyaSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + + +#include "arc4.h" + + + +void Arc4SetKey(Arc4* arc4, const byte* key, word32 length) +{ + word32 i; + word32 keyIndex = 0, stateIndex = 0; + + arc4->x = 1; + arc4->y = 0; + + for (i = 0; i < ARC4_STATE_SIZE; i++) + arc4->state[i] = i; + + for (i = 0; i < ARC4_STATE_SIZE; i++) { + word32 a = arc4->state[i]; + stateIndex += key[keyIndex] + a; + stateIndex &= 0xFF; + arc4->state[i] = arc4->state[stateIndex]; + arc4->state[stateIndex] = a; + + if (++keyIndex >= length) + keyIndex = 0; + } +} + + +static INLINE word32 MakeByte(word32* x, word32* y, byte* s) +{ + word32 a = s[*x], b; + *y = (*y+a) & 0xff; + + b = s[*y]; + s[*x] = b; + s[*y] = a; + *x = (*x+1) & 0xff; + + return s[(a+b) & 0xff]; +} + + +void Arc4Process(Arc4* arc4, byte* out, const byte* in, word32 length) +{ + word32 x = arc4->x; + word32 y = arc4->y; + + while(length--) + *out++ = *in++ ^ MakeByte(&x, &y, arc4->state); + + arc4->x = x; + arc4->y = y; +} + diff --git a/ctaocrypt/src/asm.c b/ctaocrypt/src/asm.c new file mode 100644 index 000000000..0a5084e09 --- /dev/null +++ b/ctaocrypt/src/asm.c @@ -0,0 +1,1302 @@ +/* asm.c + * + * Copyright (C) 2006-2011 Sawtooth Consulting Ltd. + * + * This file is part of CyaSSL. + * + * CyaSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * CyaSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +/* + * Based on public domain TomsFastMath 0.10 by Tom St Denis, tomstdenis@iahu.ca, + * http://math.libtomcrypt.com + */ + + + +/******************************************************************/ +/* fp_montgomery_reduce.c asm or generic */ +#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), "g"(mu), "g"(*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), "r"(tmpm) ); + +/* TAO switched tmpm from "g" to "r" after gcc tried to index the indexed stack + pointer */ + +#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,%0 \n\t" \ + " addze 17,17 \n\t" \ + " lwz 18,%1 \n\t" \ + " addc 16,16,18 \n\t" \ + " addze %0,17 \n\t" \ + " stw 16,%1 \n\t" \ +:"=r"(cy),"=m"(_c[0]):"0"(cy),"r"(mu),"r"(tmpm[0]),"1"(_c[0]):"16", "17", "18","%cc"); ++tmpm; + +#define PROPCARRY \ +asm( \ + " lwz 16,%1 \n\t" \ + " addc 16,16,%0 \n\t" \ + " stw 16,%1 \n\t" \ + " xor %0,%0,%0 \n\t" \ + " addze %0,%0 \n\t" \ +:"=r"(cy),"=m"(_c[0]):"0"(cy),"1"(_c[0]):"16","%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 16,%3,%4 \n\t" \ + " mulhdu 17,%3,%4 \n\t" \ + " addc 16,16,%0 \n\t" \ + " addze 17,17 \n\t" \ + " ldx 18,0,%1 \n\t" \ + " addc 16,16,18 \n\t" \ + " addze %0,17 \n\t" \ + " sdx 16,0,%1 \n\t" \ +:"=r"(cy),"=m"(_c[0]):"0"(cy),"r"(mu),"r"(tmpm[0]),"1"(_c[0]):"16", "17", "18","%cc"); ++tmpm; + +#define PROPCARRY \ +asm( \ + " ldx 16,0,%1 \n\t" \ + " addc 16,16,%0 \n\t" \ + " sdx 16,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]):"16","%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"); + +#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 +/* end fp_montogomery_reduce.c asm */ + + +/* start fp_sqr_comba.c asm */ +#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"); + +/* TAO removed sc0,1,2 as input to remove warning so %6,%7 become %3,%4 */ + +#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), "g"(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"); + +/* TAO removed sc0,1,2 as input to remove warning so %6,%7 become %3,%4 */ + +#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 %3,%%mm0 \n\t" \ + "movd %4,%%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): "m"(i), "m"(j)); + +/* TAO removed sc0,1,2 as input to remove warning so %6,%7 become %3,%4 */ + +#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 16,%6,%6 \n\t" \ + " addc %0,%0,16 \n\t" \ + " mulhdu 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( \ + " mulld 16,%6,%7 \n\t" \ + " mulhdu 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( \ + " 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 16,%6,%7 \n\t" \ + " addc %0,%0,16 \n\t" \ + " mulhdu 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_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"); + + +#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 + +#ifdef TFM_SMALL_SET +#include "fp_sqr_comba_small_set.i" +#include "fp_sqr_comba_3.i" +#include "fp_sqr_comba_4.i" +#include "fp_sqr_comba_6.i" +#include "fp_sqr_comba_7.i" +#include "fp_sqr_comba_8.i" +#include "fp_sqr_comba_9.i" +#include "fp_sqr_comba_12.i" +#include "fp_sqr_comba_17.i" +#include "fp_sqr_comba_20.i" +#include "fp_sqr_comba_24.i" +#include "fp_sqr_comba_28.i" +#include "fp_sqr_comba_32.i" +#include "fp_sqr_comba_48.i" +#include "fp_sqr_comba_64.i" +#endif +/* end fp_sqr_comba.c asm */ + +/* start fp_mul_comba.c asm */ +/* 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 mulhwu change the flags? Docs say no */ +#define MULADD(i, j) \ +asm( \ + " mulld 16,%6,%7 \n\t" \ + " addc %0,%0,16 \n\t" \ + " mulhdu 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_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"); + +#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 + + +#ifdef TFM_SMALL_SET +#include "fp_mul_comba_small_set.i" +#include "fp_mul_comba_3.i" +#include "fp_mul_comba_4.i" +#include "fp_mul_comba_6.i" +#include "fp_mul_comba_7.i" +#include "fp_mul_comba_8.i" +#include "fp_mul_comba_9.i" +#include "fp_mul_comba_12.i" +#include "fp_mul_comba_17.i" +#include "fp_mul_comba_20.i" +#include "fp_mul_comba_24.i" +#include "fp_mul_comba_28.i" +#include "fp_mul_comba_32.i" +#include "fp_mul_comba_48.i" +#include "fp_mul_comba_64.i" +#endif + +/* end fp_mul_comba.c asm */ + diff --git a/ctaocrypt/src/asn.c b/ctaocrypt/src/asn.c new file mode 100644 index 000000000..844ab71d7 --- /dev/null +++ b/ctaocrypt/src/asn.c @@ -0,0 +1,2866 @@ +/* asn.c + * + * Copyright (C) 2006-2011 Sawtooth Consulting Ltd. + * + * This file is part of CyaSSL. + * + * CyaSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * CyaSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + + +#ifdef THREADX + #include "os.h" /* dc_rtc_api needs */ + #include "dc_rtc_api.h" /* to get current time */ +#endif +#include "asn.h" +#include "coding.h" +#include "ctc_sha.h" +#include "ctc_md5.h" +#include "error.h" + +#ifdef HAVE_NTRU + #include "crypto_ntru.h" +#endif + +#ifdef HAVE_ECC + #include "ctc_ecc.h" +#endif + + +#ifdef _MSC_VER + /* 4996 warning to use MS extensions e.g., strcpy_s instead of XSTRNCPY */ + #pragma warning(disable: 4996) +#endif + + +#ifndef TRUE +enum { + FALSE = 0, + TRUE = 1 +}; +#endif + + +#ifdef THREADX + /* uses parital structures */ + #define XTIME(tl) (0) + #define XGMTIME(c) my_gmtime((c)) + #define XVALIDATE_DATE(d, f, t) ValidateDate((d), (f), (t)) +#elif defined(MICRIUM) + #if (NET_SECURE_MGR_CFG_EN == DEF_ENABLED) + #define XVALIDATE_DATE(d,f,t) NetSecure_ValidateDateHandler((d),(f),(t)) + #else + #define XVALIDATE_DATE(d, f, t) (0) + #endif + #define NO_TIME_H + /* since Micrium not defining XTIME or XGMTIME, CERT_GEN not available */ +#elif defined(USER_TIME) + /* no strucutres used */ + #define NO_TIME_H + /* user time, and gmtime compatible functions, there is a gmtime + implementation here that WINCE uses, so really just need some ticks + since the EPOCH + */ +#else + /* default */ + /* uses complete facility */ + #include + #define XTIME(tl) time((tl)) + #define XGMTIME(c) gmtime((c)) + #define XVALIDATE_DATE(d, f, t) ValidateDate((d), (f), (t)) +#endif + + +#ifdef _WIN32_WCE +/* no time() or gmtime() even though in time.h header?? */ + +#include + + +time_t time(time_t* timer) +{ + SYSTEMTIME sysTime; + FILETIME fTime; + ULARGE_INTEGER intTime; + time_t localTime; + + if (timer == NULL) + timer = &localTime; + + GetSystemTime(&sysTime); + SystemTimeToFileTime(&sysTime, &fTime); + + XMEMCPY(&intTime, &fTime, sizeof(FILETIME)); + /* subtract EPOCH */ + intTime.QuadPart -= 0x19db1ded53e8000; + /* to secs */ + intTime.QuadPart /= 10000000; + *timer = (time_t)intTime.QuadPart; + + return *timer; +} + + + +struct tm* gmtime(const time_t* timer) +{ + #define YEAR0 1900 + #define EPOCH_YEAR 1970 + #define SECS_DAY (24L * 60L * 60L) + #define LEAPYEAR(year) (!((year) % 4) && (((year) % 100) || !((year) %400))) + #define YEARSIZE(year) (LEAPYEAR(year) ? 366 : 365) + + static const int _ytab[2][12] = + { + {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, + {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31} + }; + + static struct tm st_time; + struct tm* ret = &st_time; + time_t time = *timer; + unsigned long dayclock, dayno; + int year = EPOCH_YEAR; + + dayclock = (unsigned long)time % SECS_DAY; + dayno = (unsigned long)time / SECS_DAY; + + ret->tm_sec = dayclock % 60; + ret->tm_min = (dayclock % 3600) / 60; + ret->tm_hour = dayclock / 3600; + ret->tm_wday = (dayno + 4) % 7; /* day 0 a Thursday */ + + while(dayno >= (unsigned long)YEARSIZE(year)) { + dayno -= YEARSIZE(year); + year++; + } + + ret->tm_year = year - YEAR0; + ret->tm_yday = dayno; + ret->tm_mon = 0; + + while(dayno >= (unsigned long)_ytab[LEAPYEAR(year)][ret->tm_mon]) { + dayno -= _ytab[LEAPYEAR(year)][ret->tm_mon]; + ret->tm_mon++; + } + + ret->tm_mday = ++dayno; + ret->tm_isdst = 0; + + return ret; +} + +#endif /* _WIN32_WCE */ + + + +#ifdef THREADX + +#define YEAR0 1900 + +struct tm* my_gmtime(const time_t* timer) /* has a gmtime() but hangs */ +{ + static struct tm st_time; + struct tm* ret = &st_time; + + DC_RTC_CALENDAR cal; + dc_rtc_time_get(&cal, TRUE); + + ret->tm_year = cal.year - YEAR0; /* gm starts at 1900 */ + ret->tm_mon = cal.month - 1; /* gm starts at 0 */ + ret->tm_mday = cal.day; + ret->tm_hour = cal.hour; + ret->tm_min = cal.minute; + ret->tm_sec = cal.second; + + return ret; +} + +#endif /* THREADX */ + + +static INLINE word32 btoi(byte b) +{ + return b - 0x30; +} + + +/* two byte date/time, add to value */ +static INLINE void GetTime(int* value, const byte* date, int* idx) +{ + int i = *idx; + + *value += btoi(date[i++]) * 10; + *value += btoi(date[i++]); + + *idx = i; +} + + +#if defined(MICRIUM) + +CPU_INT32S NetSecure_ValidateDateHandler(CPU_INT08U *date, CPU_INT08U format, + CPU_INT08U dateType) +{ + CPU_BOOLEAN rtn_code; + CPU_INT32S i; + CPU_INT32S val; + CPU_INT16U year; + CPU_INT08U month; + CPU_INT16U day; + CPU_INT08U hour; + CPU_INT08U min; + CPU_INT08U sec; + + i = 0; + year = 0u; + + if (format == ASN_UTC_TIME) { + if (btoi(date[0]) >= 5) + year = 1900; + else + year = 2000; + } + else { /* format == GENERALIZED_TIME */ + year += btoi(date[i++]) * 1000; + year += btoi(date[i++]) * 100; + } + + val = year; + GetTime(&val, date, &i); + year = (CPU_INT16U)val; + + val = 0; + GetTime(&val, date, &i); + month = (CPU_INT08U)val; + + val = 0; + GetTime(&val, date, &i); + day = (CPU_INT16U)val; + + val = 0; + GetTime(&val, date, &i); + hour = (CPU_INT08U)val; + + val = 0; + GetTime(&val, date, &i); + min = (CPU_INT08U)val; + + val = 0; + GetTime(&val, date, &i); + sec = (CPU_INT08U)val; + + return NetSecure_ValidateDate(year, month, day, hour, min, sec, dateType); +} + +#endif /* MICRIUM */ + + +int GetLength(const byte* input, word32* inOutIdx, int* len) +{ + int length = 0; + word32 i = *inOutIdx; + + byte b = input[i++]; + if (b >= ASN_LONG_LENGTH) { + word32 bytes = b & 0x7F; + + while (bytes--) { + b = input[i++]; + length = (length << 8) | b; + } + } + else + length = b; + + *inOutIdx = i; + *len = length; + + return length; +} + + +int GetSequence(const byte* input, word32* inOutIdx, int* len) +{ + int length = -1; + word32 idx = *inOutIdx; + + if (input[idx++] != (ASN_SEQUENCE | ASN_CONSTRUCTED) || + GetLength(input, &idx, &length) < 0) + return ASN_PARSE_E; + + *len = length; + *inOutIdx = idx; + + return length; +} + + +int GetSet(const byte* input, word32* inOutIdx, int* len) +{ + int length = -1; + word32 idx = *inOutIdx; + + if (input[idx++] != (ASN_SET | ASN_CONSTRUCTED) || + GetLength(input, &idx, &length) < 0) + return ASN_PARSE_E; + + *len = length; + *inOutIdx = idx; + + return length; +} + + +/* winodws header clash for WinCE using GetVersion */ +int GetMyVersion(const byte* input, word32* inOutIdx, int* version) +{ + word32 idx = *inOutIdx; + + if (input[idx++] != ASN_INTEGER) + return ASN_PARSE_E; + + if (input[idx++] != 0x01) + return ASN_VERSION_E; + + *version = input[idx++]; + *inOutIdx = idx; + + return *version; +} + + +/* May not have one, not an error */ +int GetExplicitVersion(const byte* input, word32* inOutIdx, int* version) +{ + word32 idx = *inOutIdx; + + if (input[idx++] == (ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED)) { + *inOutIdx = ++idx; /* eat header */ + return GetMyVersion(input, inOutIdx, version); + } + + /* go back as is */ + *version = 0; + + return 0; +} + + +int GetInt(mp_int* mpi, const byte* input, word32* inOutIdx ) +{ + word32 i = *inOutIdx; + byte b = input[i++]; + int length; + + if (b != ASN_INTEGER) + return ASN_PARSE_E; + + if (GetLength(input, &i, &length) < 0) + return ASN_PARSE_E; + + if ( (b = input[i++]) == 0x00) + length--; + else + i--; + + mp_init(mpi); + if (mp_read_unsigned_bin(mpi, (byte*)input + i, length) != 0) { + mp_clear(mpi); + return ASN_GETINT_E; + } + + *inOutIdx = i + length; + return 0; +} + + +static int GetAlgoId(const byte* input, word32* inOutIdx, word32* oid) +{ + int length; + word32 i = *inOutIdx; + byte b; + *oid = 0; + + if (GetSequence(input, &i, &length) < 0) + return ASN_PARSE_E; + + b = input[i++]; + if (b != ASN_OBJECT_ID) + return ASN_OBJECT_ID_E; + + if (GetLength(input, &i, &length) < 0) + return ASN_PARSE_E; + + while(length--) + *oid += input[i++]; + /* just sum it up for now */ + + /* could have NULL tag and 0 terminator, but may not */ + b = input[i++]; + + if (b == ASN_TAG_NULL) { + b = input[i++]; + if (b != 0) + return ASN_EXPECT_0_E; + } + else + /* go back, didn't have it */ + i--; + + *inOutIdx = i; + + return 0; +} + + +int RsaPrivateKeyDecode(const byte* input, word32* inOutIdx, RsaKey* key, + word32 inSz) +{ + word32 begin = *inOutIdx; + int version, length; + + if (GetSequence(input, inOutIdx, &length) < 0) + return ASN_PARSE_E; + + if ((word32)length > (inSz - (*inOutIdx - begin))) + return ASN_INPUT_E; + + if (GetMyVersion(input, inOutIdx, &version) < 0) + return ASN_PARSE_E; + + key->type = RSA_PRIVATE; + + if (GetInt(&key->n, input, inOutIdx) < 0 || + GetInt(&key->e, input, inOutIdx) < 0 || + GetInt(&key->d, input, inOutIdx) < 0 || + GetInt(&key->p, input, inOutIdx) < 0 || + GetInt(&key->q, input, inOutIdx) < 0 || + GetInt(&key->dP, input, inOutIdx) < 0 || + GetInt(&key->dQ, input, inOutIdx) < 0 || + GetInt(&key->u, input, inOutIdx) < 0 ) return ASN_RSA_KEY_E; + + return 0; +} + + +/* Remove PKCS8 header, move beginning of traditional to beginning of input */ +int ToTraditional(byte* input, word32 sz) +{ + word32 inOutIdx = 0, oid; + int version, length; + + if (GetSequence(input, &inOutIdx, &length) < 0) + return ASN_PARSE_E; + + if ((word32)length > (sz - inOutIdx)) + return ASN_INPUT_E; + + if (GetMyVersion(input, &inOutIdx, &version) < 0) + return ASN_PARSE_E; + + if (GetAlgoId(input, &inOutIdx, &oid) < 0) + return ASN_PARSE_E; + + if (input[inOutIdx++] != ASN_OCTET_STRING) + return ASN_PARSE_E; + + if (GetLength(input, &inOutIdx, &length) < 0) + return ASN_PARSE_E; + + if ((word32)length > (sz - inOutIdx)) + return ASN_INPUT_E; + + XMEMMOVE(input, input + inOutIdx, length); + + return 0; +} + + +int RsaPublicKeyDecode(const byte* input, word32* inOutIdx, RsaKey* key, + word32 inSz) +{ + word32 begin = *inOutIdx; + int length; + byte b; + + if (GetSequence(input, inOutIdx, &length) < 0) + return ASN_PARSE_E; + + if ((word32)length > (inSz - (*inOutIdx - begin))) + return ASN_INPUT_E; + + key->type = RSA_PUBLIC; + b = input[*inOutIdx]; + +#ifdef OPENSSL_EXTRA + if (b != ASN_INTEGER) { + /* not from decoded cert, will have algo id, skip past */ + if (GetSequence(input, inOutIdx, &length) < 0) + return ASN_PARSE_E; + + b = input[(*inOutIdx)++]; + if (b != ASN_OBJECT_ID) + return ASN_OBJECT_ID_E; + + if (GetLength(input, inOutIdx, &length) < 0) + return ASN_PARSE_E; + + *inOutIdx += length; /* skip past */ + + /* could have NULL tag and 0 terminator, but may not */ + b = input[(*inOutIdx)++]; + + if (b == ASN_TAG_NULL) { + b = input[(*inOutIdx)++]; + if (b != 0) + return ASN_EXPECT_0_E; + } + else + /* go back, didn't have it */ + (*inOutIdx)--; + + /* should have bit tag length and seq next */ + b = input[(*inOutIdx)++]; + if (b != ASN_BIT_STRING) + return ASN_BITSTR_E; + + if (GetLength(input, inOutIdx, &length) < 0) + return ASN_PARSE_E; + + /* could have 0 */ + b = input[(*inOutIdx)++]; + if (b != 0) + (*inOutIdx)--; + + if (GetSequence(input, inOutIdx, &length) < 0) + return ASN_PARSE_E; + } +#endif /* OPENSSL_EXTRA */ + + if (GetInt(&key->n, input, inOutIdx) < 0 || + GetInt(&key->e, input, inOutIdx) < 0 ) return ASN_RSA_KEY_E; + + return 0; +} + + +#ifndef NO_DH + +int DhKeyDecode(const byte* input, word32* inOutIdx, DhKey* key, word32 inSz) +{ + word32 begin = *inOutIdx; + int length; + + if (GetSequence(input, inOutIdx, &length) < 0) + return ASN_PARSE_E; + + if ((word32)length > (inSz - (*inOutIdx - begin))) + return ASN_INPUT_E; + + if (GetInt(&key->p, input, inOutIdx) < 0 || + GetInt(&key->g, input, inOutIdx) < 0 ) return ASN_DH_KEY_E; + + return 0; +} + +int DhSetKey(DhKey* key, const byte* p, word32 pSz, const byte* g, word32 gSz) +{ + /* may have leading 0 */ + if (p[0] == 0) { + pSz--; p++; + } + + if (g[0] == 0) { + gSz--; g++; + } + + mp_init(&key->p); + if (mp_read_unsigned_bin(&key->p, p, pSz) != 0) { + mp_clear(&key->p); + return ASN_DH_KEY_E; + } + + mp_init(&key->g); + if (mp_read_unsigned_bin(&key->g, g, gSz) != 0) { + mp_clear(&key->p); + return ASN_DH_KEY_E; + } + + return 0; +} + + +#endif /* NO_DH */ + + +#ifndef NO_DSA + +int DsaPublicKeyDecode(const byte* input, word32* inOutIdx, DsaKey* key, + word32 inSz) +{ + word32 begin = *inOutIdx; + int length; + + if (GetSequence(input, inOutIdx, &length) < 0) + return ASN_PARSE_E; + + if ((word32)length > (inSz - (*inOutIdx - begin))) + return ASN_INPUT_E; + + if (GetInt(&key->p, input, inOutIdx) < 0 || + GetInt(&key->q, input, inOutIdx) < 0 || + GetInt(&key->g, input, inOutIdx) < 0 || + GetInt(&key->y, input, inOutIdx) < 0 ) return ASN_DH_KEY_E; + + key->type = DSA_PUBLIC; + return 0; +} + + +int DsaPrivateKeyDecode(const byte* input, word32* inOutIdx, DsaKey* key, + word32 inSz) +{ + word32 begin = *inOutIdx; + int length, version; + + if (GetSequence(input, inOutIdx, &length) < 0) + return ASN_PARSE_E; + + if ((word32)length > (inSz - (*inOutIdx - begin))) + return ASN_INPUT_E; + + if (GetMyVersion(input, inOutIdx, &version) < 0) + return ASN_PARSE_E; + + if (GetInt(&key->p, input, inOutIdx) < 0 || + GetInt(&key->q, input, inOutIdx) < 0 || + GetInt(&key->g, input, inOutIdx) < 0 || + GetInt(&key->y, input, inOutIdx) < 0 || + GetInt(&key->x, input, inOutIdx) < 0 ) return ASN_DH_KEY_E; + + key->type = DSA_PRIVATE; + return 0; +} + +#endif /* NO_DSA */ + + +void InitDecodedCert(DecodedCert* cert, byte* source, void* heap) +{ + cert->publicKey = 0; + cert->pubKeyStored = 0; + cert->signature = 0; + cert->subjectCN = 0; + cert->subjectCNLen = 0; + cert->source = source; /* don't own */ + cert->srcIdx = 0; + cert->heap = heap; +#ifdef CYASSL_CERT_GEN + cert->subjectSN = 0; + cert->subjectSNLen = 0; + cert->subjectC = 0; + cert->subjectCLen = 0; + cert->subjectL = 0; + cert->subjectLLen = 0; + cert->subjectST = 0; + cert->subjectSTLen = 0; + cert->subjectO = 0; + cert->subjectOLen = 0; + cert->subjectOU = 0; + cert->subjectOULen = 0; + cert->subjectEmail = 0; + cert->subjectEmailLen = 0; +#endif /* CYASSL_CERT_GEN */ +} + + +void FreeDecodedCert(DecodedCert* cert) +{ + if (cert->subjectCNLen == 0) /* 0 means no longer pointer to raw, we own */ + XFREE(cert->subjectCN, cert->heap, DYNAMIC_TYPE_SUBJECT_CN); + if (cert->pubKeyStored == 1) + XFREE(cert->publicKey, cert->heap, DYNAMIC_TYPE_PUBLIC_KEY); +} + + +static int GetCertHeader(DecodedCert* cert, word32 inSz) +{ + int ret = 0, version, len; + word32 begin = cert->srcIdx; + mp_int mpi; + + if (GetSequence(cert->source, &cert->srcIdx, &len) < 0) + return ASN_PARSE_E; + + if ((word32)len > (inSz - (cert->srcIdx - begin))) return ASN_INPUT_E; + + cert->certBegin = cert->srcIdx; + + GetSequence(cert->source, &cert->srcIdx, &len); + cert->sigIndex = len + cert->srcIdx; + + if (GetExplicitVersion(cert->source, &cert->srcIdx, &version) < 0) + return ASN_PARSE_E; + + if (GetInt(&mpi, cert->source, &cert->srcIdx) < 0) + ret = ASN_PARSE_E; + + mp_clear(&mpi); + return ret; +} + + +/* Store Rsa Key, may save later, Dsa could use in future */ +static int StoreRsaKey(DecodedCert* cert) +{ + int length; + word32 read = cert->srcIdx; + + if (GetSequence(cert->source, &cert->srcIdx, &length) < 0) + return ASN_PARSE_E; + + read = cert->srcIdx - read; + length += read; + + while (read--) + cert->srcIdx--; + + cert->pubKeySize = length; + cert->publicKey = cert->source + cert->srcIdx; + cert->srcIdx += length; + + return 0; +} + + +#ifdef HAVE_ECC + + /* return 0 on sucess if the ECC curve oid sum is supported */ + static int CheckCurve(word32 oid) + { + if (oid != ECC_256R1 && oid != ECC_384R1 && oid != ECC_521R1 && oid != + ECC_160R1 && oid != ECC_192R1 && oid != ECC_224R1) + return -1; + + return 0; + } + +#endif /* HAVE_ECC */ + + +static int GetKey(DecodedCert* cert) +{ + int length; +#ifdef HAVE_NTRU + int tmpIdx = cert->srcIdx; +#endif + + if (GetSequence(cert->source, &cert->srcIdx, &length) < 0) + return ASN_PARSE_E; + + if (GetAlgoId(cert->source, &cert->srcIdx, &cert->keyOID) < 0) + return ASN_PARSE_E; + + if (cert->keyOID == RSAk) { + byte b = cert->source[cert->srcIdx++]; + if (b != ASN_BIT_STRING) + return ASN_BITSTR_E; + + if (GetLength(cert->source, &cert->srcIdx, &length) < 0) + return ASN_PARSE_E; + b = cert->source[cert->srcIdx++]; + if (b != 0x00) + return ASN_EXPECT_0_E; + } + else if (cert->keyOID == DSAk ) + ; /* do nothing */ +#ifdef HAVE_NTRU + else if (cert->keyOID == NTRUk ) { + const byte* key = &cert->source[tmpIdx]; + byte* next = (byte*)key; + word16 keyLen; + byte keyBlob[MAX_NTRU_KEY_SZ]; + + word32 rc = crypto_ntru_encrypt_subjectPublicKeyInfo2PublicKey(key, + &keyLen, NULL, &next); + + if (rc != NTRU_OK) + return ASN_NTRU_KEY_E; + if (keyLen > sizeof(keyBlob)) + return ASN_NTRU_KEY_E; + + rc = crypto_ntru_encrypt_subjectPublicKeyInfo2PublicKey(key, &keyLen, + keyBlob, &next); + if (rc != NTRU_OK) + return ASN_NTRU_KEY_E; + + if ( (next - key) < 0) + return ASN_NTRU_KEY_E; + + cert->srcIdx = tmpIdx + (next - key); + + cert->publicKey = (byte*) XMALLOC(keyLen, cert->heap, + DYNAMIC_TYPE_PUBLIC_KEY); + if (cert->publicKey == NULL) + return MEMORY_E; + memcpy(cert->publicKey, keyBlob, keyLen); + cert->pubKeyStored = 1; + cert->pubKeySize = keyLen; + } +#endif /* HAVE_NTRU */ +#ifdef HAVE_ECC + else if (cert->keyOID == ECDSAk ) { + word32 oid = 0; + int oidSz = 0; + byte b = cert->source[cert->srcIdx++]; + + if (b != ASN_OBJECT_ID) + return ASN_OBJECT_ID_E; + + if (GetLength(cert->source, &cert->srcIdx, &oidSz) < 0) + return ASN_PARSE_E; + + while(oidSz--) + oid += cert->source[cert->srcIdx++]; + if (CheckCurve(oid) < 0) + return ECC_CURVE_OID_E; + + /* key header */ + b = cert->source[cert->srcIdx++]; + if (b != ASN_BIT_STRING) + return ASN_BITSTR_E; + + if (GetLength(cert->source, &cert->srcIdx, &length) < 0) + return ASN_PARSE_E; + b = cert->source[cert->srcIdx++]; + if (b != 0x00) + return ASN_EXPECT_0_E; + + /* actual key, use length - 1 since preceding 0 */ + cert->publicKey = (byte*) XMALLOC(length - 1, cert->heap, + DYNAMIC_TYPE_PUBLIC_KEY); + if (cert->publicKey == NULL) + return MEMORY_E; + memcpy(cert->publicKey, &cert->source[cert->srcIdx], length - 1); + cert->pubKeyStored = 1; + cert->pubKeySize = length - 1; + + cert->srcIdx += length; + } +#endif /* HAVE_ECC */ + else + return ASN_UNKNOWN_OID_E; + + if (cert->keyOID == RSAk) + return StoreRsaKey(cert); + return 0; +} + + +/* process NAME, either issuer or subject */ +static int GetName(DecodedCert* cert, int nameType) +{ + Sha sha; + int length; /* length of all distinguished names */ + int dummy; + char* full = (nameType == ISSUER) ? cert->issuer : cert->subject; + word32 idx = 0; + + InitSha(&sha); + + if (GetSequence(cert->source, &cert->srcIdx, &length) < 0) + return ASN_PARSE_E; + + length += cert->srcIdx; + + while (cert->srcIdx < (word32)length) { + byte b; + byte joint[2]; + int oidSz; + + if (GetSet(cert->source, &cert->srcIdx, &dummy) < 0) + return ASN_PARSE_E; + + if (GetSequence(cert->source, &cert->srcIdx, &dummy) < 0) + return ASN_PARSE_E; + + b = cert->source[cert->srcIdx++]; + if (b != ASN_OBJECT_ID) + return ASN_OBJECT_ID_E; + + if (GetLength(cert->source, &cert->srcIdx, &oidSz) < 0) + return ASN_PARSE_E; + + XMEMCPY(joint, &cert->source[cert->srcIdx], sizeof(joint)); + + /* v1 name types */ + if (joint[0] == 0x55 && joint[1] == 0x04) { + byte id; + byte copy = FALSE; + int strLen; + + cert->srcIdx += 2; + id = cert->source[cert->srcIdx++]; + b = cert->source[cert->srcIdx++]; /* strType */ + + if (GetLength(cert->source, &cert->srcIdx, &strLen) < 0) + return ASN_PARSE_E; + + if (strLen > (int)(ASN_NAME_MAX - idx)) + return ASN_PARSE_E; + + if (4 > (ASN_NAME_MAX - idx)) /* make sure room for biggest */ + return ASN_PARSE_E; /* pre fix header too "/CN=" */ + + if (id == ASN_COMMON_NAME) { + if (nameType == SUBJECT) { + cert->subjectCN = (char *)&cert->source[cert->srcIdx]; + cert->subjectCNLen = strLen; + } + + XMEMCPY(&full[idx], "/CN=", 4); + idx += 4; + copy = TRUE; + } + else if (id == ASN_SUR_NAME) { + XMEMCPY(&full[idx], "/SN=", 4); + idx += 4; + copy = TRUE; +#ifdef CYASSL_CERT_GEN + if (nameType == SUBJECT) { + cert->subjectSN = (char*)&cert->source[cert->srcIdx]; + cert->subjectSNLen = strLen; + } +#endif /* CYASSL_CERT_GEN */ + } + else if (id == ASN_COUNTRY_NAME) { + XMEMCPY(&full[idx], "/C=", 3); + idx += 3; + copy = TRUE; +#ifdef CYASSL_CERT_GEN + if (nameType == SUBJECT) { + cert->subjectC = (char*)&cert->source[cert->srcIdx]; + cert->subjectCLen = strLen; + } +#endif /* CYASSL_CERT_GEN */ + } + else if (id == ASN_LOCALITY_NAME) { + XMEMCPY(&full[idx], "/L=", 3); + idx += 3; + copy = TRUE; +#ifdef CYASSL_CERT_GEN + if (nameType == SUBJECT) { + cert->subjectL = (char*)&cert->source[cert->srcIdx]; + cert->subjectLLen = strLen; + } +#endif /* CYASSL_CERT_GEN */ + } + else if (id == ASN_STATE_NAME) { + XMEMCPY(&full[idx], "/ST=", 4); + idx += 4; + copy = TRUE; +#ifdef CYASSL_CERT_GEN + if (nameType == SUBJECT) { + cert->subjectST = (char*)&cert->source[cert->srcIdx]; + cert->subjectSTLen = strLen; + } +#endif /* CYASSL_CERT_GEN */ + } + else if (id == ASN_ORG_NAME) { + XMEMCPY(&full[idx], "/O=", 3); + idx += 3; + copy = TRUE; +#ifdef CYASSL_CERT_GEN + if (nameType == SUBJECT) { + cert->subjectO = (char*)&cert->source[cert->srcIdx]; + cert->subjectOLen = strLen; + } +#endif /* CYASSL_CERT_GEN */ + } + else if (id == ASN_ORGUNIT_NAME) { + XMEMCPY(&full[idx], "/OU=", 4); + idx += 4; + copy = TRUE; +#ifdef CYASSL_CERT_GEN + if (nameType == SUBJECT) { + cert->subjectOU = (char*)&cert->source[cert->srcIdx]; + cert->subjectOULen = strLen; + } +#endif /* CYASSL_CERT_GEN */ + } + + if (copy) { + XMEMCPY(&full[idx], &cert->source[cert->srcIdx], strLen); + idx += strLen; + } + + ShaUpdate(&sha, &cert->source[cert->srcIdx], strLen); + cert->srcIdx += strLen; + } + else { + /* skip */ + byte email = FALSE; + int adv; + + if (joint[0] == 0x2a && joint[1] == 0x86) /* email id hdr */ + email = TRUE; + + cert->srcIdx += oidSz + 1; + + if (GetLength(cert->source, &cert->srcIdx, &adv) < 0) + return ASN_PARSE_E; + + if (adv > (int)(ASN_NAME_MAX - idx)) + return ASN_PARSE_E; + + if (email) { + if (14 > (ASN_NAME_MAX - idx)) + return ASN_PARSE_E; + XMEMCPY(&full[idx], "/emailAddress=", 14); + idx += 14; + +#ifdef CYASSL_CERT_GEN + if (nameType == SUBJECT) { + cert->subjectEmail = (char*)&cert->source[cert->srcIdx]; + cert->subjectEmailLen = adv; + } +#endif /* CYASSL_CERT_GEN */ + + XMEMCPY(&full[idx], &cert->source[cert->srcIdx], adv); + idx += adv; + } + + cert->srcIdx += adv; + } + } + full[idx++] = 0; + + if (nameType == ISSUER) + ShaFinal(&sha, cert->issuerHash); + else + ShaFinal(&sha, cert->subjectHash); + + return 0; +} + + +#ifndef NO_TIME_H + +/* to the second */ +static int DateGreaterThan(const struct tm* a, const struct tm* b) +{ + if (a->tm_year > b->tm_year) + return 1; + + if (a->tm_year == b->tm_year && a->tm_mon > b->tm_mon) + return 1; + + if (a->tm_year == b->tm_year && a->tm_mon == b->tm_mon && + a->tm_mday > b->tm_mday) + return 1; + + if (a->tm_year == b->tm_year && a->tm_mon == b->tm_mon && + a->tm_mday == b->tm_mday && a->tm_hour > b->tm_hour) + return 1; + + if (a->tm_year == b->tm_year && a->tm_mon == b->tm_mon && + a->tm_mday == b->tm_mday && a->tm_hour == b->tm_hour && + a->tm_min > b->tm_min) + return 1; + + if (a->tm_year == b->tm_year && a->tm_mon == b->tm_mon && + a->tm_mday == b->tm_mday && a->tm_hour == b->tm_hour && + a->tm_min == b->tm_min && a->tm_sec > b->tm_sec) + return 1; + + return 0; /* false */ +} + + +static INLINE int DateLessThan(const struct tm* a, const struct tm* b) +{ + return !DateGreaterThan(a,b); +} + + +/* like atoi but only use first byte */ +/* Make sure before and after dates are valid */ +static int ValidateDate(const byte* date, byte format, int dateType) +{ + time_t ltime; + struct tm certTime; + struct tm* localTime; + int i = 0; + + ltime = XTIME(0); + XMEMSET(&certTime, 0, sizeof(certTime)); + + if (format == ASN_UTC_TIME) { + if (btoi(date[0]) >= 5) + certTime.tm_year = 1900; + else + certTime.tm_year = 2000; + } + else { /* format == GENERALIZED_TIME */ + certTime.tm_year += btoi(date[i++]) * 1000; + certTime.tm_year += btoi(date[i++]) * 100; + } + + GetTime(&certTime.tm_year, date, &i); certTime.tm_year -= 1900; /* adjust */ + GetTime(&certTime.tm_mon, date, &i); certTime.tm_mon -= 1; /* adjust */ + GetTime(&certTime.tm_mday, date, &i); + GetTime(&certTime.tm_hour, date, &i); + GetTime(&certTime.tm_min, date, &i); + GetTime(&certTime.tm_sec, date, &i); + + if (date[i] != 'Z') /* only Zulu supported for this profile */ + return 0; + + localTime = XGMTIME(<ime); + + if (dateType == BEFORE) { + if (DateLessThan(localTime, &certTime)) + return 0; + } + else + if (DateGreaterThan(localTime, &certTime)) + return 0; + + return 1; +} + +#endif /* NO_TIME_H */ + + +static int GetDate(DecodedCert* cert, int dateType) +{ + int length; + byte date[MAX_DATE_SIZE]; + byte b = cert->source[cert->srcIdx++]; + + if (b != ASN_UTC_TIME && b != ASN_GENERALIZED_TIME) + return ASN_TIME_E; + + if (GetLength(cert->source, &cert->srcIdx, &length) < 0) + return ASN_PARSE_E; + + if (length > MAX_DATE_SIZE || length < MIN_DATE_SIZE) + return ASN_DATE_SZ_E; + + XMEMCPY(date, &cert->source[cert->srcIdx], length); + cert->srcIdx += length; + + if (!XVALIDATE_DATE(date, b, dateType)) { + if (dateType == BEFORE) + return ASN_BEFORE_DATE_E; + else + return ASN_AFTER_DATE_E; + } + + return 0; +} + + +static int GetValidity(DecodedCert* cert, int verify) +{ + int length; + int badDate = 0; + + if (GetSequence(cert->source, &cert->srcIdx, &length) < 0) + return ASN_PARSE_E; + + if (GetDate(cert, BEFORE) < 0 && verify) + badDate = ASN_BEFORE_DATE_E; /* continue parsing */ + + if (GetDate(cert, AFTER) < 0 && verify) + return ASN_AFTER_DATE_E; + + if (badDate != 0) + return badDate; + + return 0; +} + + +static int DecodeToKey(DecodedCert* cert, word32 inSz, int verify) +{ + int badDate = 0; + int ret; + + if ( (ret = GetCertHeader(cert, inSz)) < 0) + return ret; + + if ( (ret = GetAlgoId(cert->source, &cert->srcIdx,&cert->signatureOID)) < 0) + return ret; + + if ( (ret = GetName(cert, ISSUER)) < 0) + return ret; + + if ( (ret = GetValidity(cert, verify)) < 0) + badDate = ret; + + if ( (ret = GetName(cert, SUBJECT)) < 0) + return ret; + + if ( (ret = GetKey(cert)) < 0) + return ret; + + if (badDate != 0) + return badDate; + + return ret; +} + + +static int GetSignature(DecodedCert* cert) +{ + int length; + byte b = cert->source[cert->srcIdx++]; + + if (b != ASN_BIT_STRING) + return ASN_BITSTR_E; + + if (GetLength(cert->source, &cert->srcIdx, &length) < 0) + return ASN_PARSE_E; + + cert->sigLength = length; + + b = cert->source[cert->srcIdx++]; + if (b != 0x00) + return ASN_EXPECT_0_E; + + cert->sigLength--; + cert->signature = &cert->source[cert->srcIdx]; + cert->srcIdx += cert->sigLength; + + return 0; +} + + +static word32 SetDigest(const byte* digest, word32 digSz, byte* output) +{ + output[0] = ASN_OCTET_STRING; + output[1] = digSz; + XMEMCPY(&output[2], digest, digSz); + + return digSz + 2; +} + + +static word32 BytePrecision(word32 value) +{ + word32 i; + for (i = sizeof(value); i; --i) + if (value >> (i - 1) * 8) + break; + + return i; +} + + +static word32 SetLength(word32 length, byte* output) +{ + word32 i = 0, j; + + if (length < ASN_LONG_LENGTH) + output[i++] = length; + else { + output[i++] = BytePrecision(length) | ASN_LONG_LENGTH; + + for (j = BytePrecision(length); j; --j) { + output[i] = length >> (j - 1) * 8; + i++; + } + } + + return i; +} + + +static word32 SetSequence(word32 len, byte* output) +{ + output[0] = ASN_SEQUENCE | ASN_CONSTRUCTED; + return SetLength(len, output + 1) + 1; +} + + +static word32 SetAlgoID(int algoOID, byte* output, int type) +{ + /* adding TAG_NULL and 0 to end */ + + /* hashTypes */ + static const byte shaAlgoID[] = { 0x2b, 0x0e, 0x03, 0x02, 0x1a, + 0x05, 0x00 }; + static const byte md5AlgoID[] = { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, + 0x02, 0x05, 0x05, 0x00 }; + static const byte md2AlgoID[] = { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, + 0x02, 0x02, 0x05, 0x00}; + + /* sigTypes */ + static const byte md5wRSA_AlgoID[] = { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, + 0x01, 0x01, 0x04, 0x05, 0x00}; + + /* keyTypes */ + static const byte RSA_AlgoID[] = { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, + 0x01, 0x01, 0x01, 0x05, 0x00}; + + int algoSz = 0; + word32 idSz, seqSz; + const byte* algoName = 0; + byte ID_Length[MAX_LENGTH_SZ]; + byte seqArray[MAX_SEQ_SZ + 1]; /* add object_id to end */ + + if (type == hashType) { + switch (algoOID) { + case SHAh: + algoSz = sizeof(shaAlgoID); + algoName = shaAlgoID; + break; + + case MD2h: + algoSz = sizeof(md2AlgoID); + algoName = md2AlgoID; + break; + + case MD5h: + algoSz = sizeof(md5AlgoID); + algoName = md5AlgoID; + break; + + default: + return 0; /* UNKOWN_HASH_E; */ + } + } + else if (type == sigType) { /* sigType */ + switch (algoOID) { + case MD5wRSA: + algoSz = sizeof(md5wRSA_AlgoID); + algoName = md5wRSA_AlgoID; + break; + + default: + return 0; /* UNKOWN_HASH_E; */ + } + } + else if (type == keyType) { /* keyType */ + switch (algoOID) { + case RSAk: + algoSz = sizeof(RSA_AlgoID); + algoName = RSA_AlgoID; + break; + + default: + return 0; /* UNKOWN_HASH_E; */ + } + } + else + return 0; /* UNKNOWN_TYPE */ + + + idSz = SetLength(algoSz - 2, ID_Length); /* don't include TAG_NULL/0 */ + seqSz = SetSequence(idSz + algoSz + 1, seqArray); + seqArray[seqSz++] = ASN_OBJECT_ID; + + XMEMCPY(output, seqArray, seqSz); + XMEMCPY(output + seqSz, ID_Length, idSz); + XMEMCPY(output + seqSz + idSz, algoName, algoSz); + + return seqSz + idSz + algoSz; + +} + + +word32 EncodeSignature(byte* out, const byte* digest, word32 digSz, int hashOID) +{ + byte digArray[MAX_ENCODED_DIG_SZ]; + byte algoArray[MAX_ALGO_SZ]; + byte seqArray[MAX_SEQ_SZ]; + word32 encDigSz, algoSz, seqSz; + + encDigSz = SetDigest(digest, digSz, digArray); + algoSz = SetAlgoID(hashOID, algoArray, hashType); + seqSz = SetSequence(encDigSz + algoSz, seqArray); + + XMEMCPY(out, seqArray, seqSz); + XMEMCPY(out + seqSz, algoArray, algoSz); + XMEMCPY(out + seqSz + algoSz, digArray, encDigSz); + + return encDigSz + algoSz + seqSz; +} + + +/* return true (1) for Confirmation */ +static int ConfirmSignature(DecodedCert* cert, const byte* key, word32 keySz, + word32 keyOID) +{ + byte digest[SHA_DIGEST_SIZE]; /* max size */ + int hashType, digestSz, ret; + + if (cert->signatureOID == MD5wRSA) { + Md5 md5; + InitMd5(&md5); + Md5Update(&md5, cert->source + cert->certBegin, + cert->sigIndex - cert->certBegin); + Md5Final(&md5, digest); + hashType = MD5h; + digestSz = MD5_DIGEST_SIZE; + } + else if (cert->signatureOID == SHAwRSA || cert->signatureOID == SHAwDSA || + cert->signatureOID == SHAwECDSA) { + Sha sha; + InitSha(&sha); + ShaUpdate(&sha, cert->source + cert->certBegin, + cert->sigIndex - cert->certBegin); + ShaFinal(&sha, digest); + hashType = SHAh; + digestSz = SHA_DIGEST_SIZE; + } + else + return 0; /* ASN_SIG_HASH_E; */ + + if (keyOID == RSAk) { + RsaKey pubKey; + byte encodedSig[MAX_ENCODED_SIG_SZ]; + byte plain[MAX_ENCODED_SIG_SZ]; + word32 idx = 0; + int sigSz, verifySz; + byte* out; + + if (cert->sigLength > MAX_ENCODED_SIG_SZ) + return 0; /* the key is too big */ + + InitRsaKey(&pubKey, cert->heap); + if (RsaPublicKeyDecode(key, &idx, &pubKey, keySz) < 0) + ret = 0; /* ASN_KEY_DECODE_E; */ + + else { + XMEMCPY(plain, cert->signature, cert->sigLength); + if ( (verifySz = RsaSSL_VerifyInline(plain, cert->sigLength, &out, + &pubKey)) < 0) + ret = 0; /* ASN_VERIFY_E; */ + else { + /* make sure we're right justified */ + sigSz = EncodeSignature(encodedSig, digest, digestSz, hashType); + if (sigSz != verifySz || XMEMCMP(out, encodedSig, sigSz) != 0) + ret = 0; /* ASN_VERIFY_MATCH_E; */ + else + ret = 1; /* match */ + } + } + FreeRsaKey(&pubKey); + return ret; + } +#ifdef HAVE_ECC + else if (keyOID == ECDSAk) { + ecc_key pubKey; + int verify = 0; + + if (ecc_import_x963(key, keySz, &pubKey) < 0) + return 0; /* ASN_KEY_DECODE_E */ + + ret = ecc_verify_hash(cert->signature, cert->sigLength, digest, + digestSz, &verify, &pubKey); + ecc_free(&pubKey); + if (ret == 0 && verify == 1) + return 1; /* match */ + + return 0; /* ASN_VERIFY_E */ + } +#endif /* HAVE_ECC */ + else + return 0; /* ASN_SIG_KEY_E; */ +} + + +int ParseCert(DecodedCert* cert, word32 inSz, int type, int verify, + Signer* signers) +{ + int ret; + char* ptr; + + ret = ParseCertRelative(cert, inSz, type, verify, signers); + if (ret < 0) + return ret; + + if (cert->subjectCNLen > 0) { + ptr = (char*) XMALLOC(cert->subjectCNLen + 1, cert->heap, + DYNAMIC_TYPE_SUBJECT_CN); + if (ptr == NULL) + return MEMORY_E; + XMEMCPY(ptr, cert->subjectCN, cert->subjectCNLen); + ptr[cert->subjectCNLen] = '\0'; + cert->subjectCN = ptr; + cert->subjectCNLen = 0; + } + + if (cert->keyOID == RSAk && cert->pubKeySize > 0) { + ptr = (char*) XMALLOC(cert->pubKeySize, cert->heap, + DYNAMIC_TYPE_PUBLIC_KEY); + if (ptr == NULL) + return MEMORY_E; + XMEMCPY(ptr, cert->publicKey, cert->pubKeySize); + cert->publicKey = (byte *)ptr; + cert->pubKeyStored = 1; + } + + return ret; +} + + +int ParseCertRelative(DecodedCert* cert, word32 inSz, int type, int verify, + Signer* signers) +{ + word32 confirmOID; + int ret; + int badDate = 0; + int confirm = 0; + + if ((ret = DecodeToKey(cert, inSz, verify)) < 0) { + if (ret == ASN_BEFORE_DATE_E || ret == ASN_AFTER_DATE_E) + badDate = ret; + else + return ret; + } + + if (cert->srcIdx != cert->sigIndex) + cert->srcIdx = cert->sigIndex; + + if ((ret = GetAlgoId(cert->source, &cert->srcIdx, &confirmOID)) < 0) + return ret; + + if ((ret = GetSignature(cert)) < 0) + return ret; + + if (confirmOID != cert->signatureOID) + return ASN_SIG_OID_E; + + if (verify && type != CA_TYPE) { + while (signers) { + if (XMEMCMP(cert->issuerHash, signers->hash, SHA_DIGEST_SIZE) + == 0) { + /* other confirm */ + if (!ConfirmSignature(cert, signers->publicKey, + signers->pubKeySize, signers->keyOID)) + return ASN_SIG_CONFIRM_E; + else { + confirm = 1; + break; + } + } + signers = signers->next; + } + if (!confirm) + return ASN_SIG_CONFIRM_E; + } + if (badDate != 0) + return badDate; + + return 0; +} + + +Signer* MakeSigner(void* heap) +{ + Signer* signer = (Signer*) XMALLOC(sizeof(Signer), heap, + DYNAMIC_TYPE_SIGNER); + if (signer) { + signer->name = 0; + signer->publicKey = 0; + signer->next = 0; + } + + return signer; +} + + +void FreeSigners(Signer* signer, void* heap) +{ + Signer* next = signer; + + while( (signer = next) ) { + next = signer->next; + XFREE(signer->name, heap, DYNAMIC_TYPE_SUBJECT_CN); + XFREE(signer->publicKey, heap, DYNAMIC_TYPE_PUBLIC_KEY); + XFREE(signer, heap, DYNAMIC_TYPE_SIGNER); + } +} + + +void CTaoCryptErrorString(int error, char* buffer) +{ + const int max = MAX_ERROR_SZ; /* shorthand */ + +#ifdef NO_ERROR_STRINGS + + XSTRNCPY(buffer, "no support for error strings built in", max); + +#else + + switch (error) { + + case OPEN_RAN_E : + XSTRNCPY(buffer, "opening random device error", max); + break; + + case READ_RAN_E : + XSTRNCPY(buffer, "reading random device error", max); + break; + + case WINCRYPT_E : + XSTRNCPY(buffer, "windows crypt init error", max); + break; + + case CRYPTGEN_E : + XSTRNCPY(buffer, "windows crypt generation error", max); + break; + + case RAN_BLOCK_E : + XSTRNCPY(buffer, "random device read would block error", max); + break; + + case MP_INIT_E : + XSTRNCPY(buffer, "mp_init error state", max); + break; + + case MP_READ_E : + XSTRNCPY(buffer, "mp_read error state", max); + break; + + case MP_EXPTMOD_E : + XSTRNCPY(buffer, "mp_exptmod error state", max); + break; + + case MP_TO_E : + XSTRNCPY(buffer, "mp_to_xxx error state, can't convert", max); + break; + + case MP_SUB_E : + XSTRNCPY(buffer, "mp_sub error state, can't subtract", max); + break; + + case MP_ADD_E : + XSTRNCPY(buffer, "mp_add error state, can't add", max); + break; + + case MP_MUL_E : + XSTRNCPY(buffer, "mp_mul error state, can't multiply", max); + break; + + case MP_MULMOD_E : + XSTRNCPY(buffer, "mp_mulmod error state, can't multiply mod", max); + break; + + case MP_MOD_E : + XSTRNCPY(buffer, "mp_mod error state, can't mod", max); + break; + + case MP_INVMOD_E : + XSTRNCPY(buffer, "mp_invmod error state, can't inv mod", max); + break; + + case MP_CMP_E : + XSTRNCPY(buffer, "mp_cmp error state", max); + break; + + case MEMORY_E : + XSTRNCPY(buffer, "out of memory error", max); + break; + + case RSA_WRONG_TYPE_E : + XSTRNCPY(buffer, "RSA wrong block type for RSA function", max); + break; + + case RSA_BUFFER_E : + XSTRNCPY(buffer, "RSA buffer error, output too small or input too big", + max); + break; + + case BUFFER_E : + XSTRNCPY(buffer, "Buffer error, output too small or input too big", max); + break; + + case ALGO_ID_E : + XSTRNCPY(buffer, "Setting Cert AlogID error", max); + break; + + case PUBLIC_KEY_E : + XSTRNCPY(buffer, "Setting Cert Public Key error", max); + break; + + case DATE_E : + XSTRNCPY(buffer, "Setting Cert Date validity error", max); + break; + + case SUBJECT_E : + XSTRNCPY(buffer, "Setting Cert Subject name error", max); + break; + + case ISSUER_E : + XSTRNCPY(buffer, "Setting Cert Issuer name error", max); + break; + + case ASN_PARSE_E : + XSTRNCPY(buffer, "ASN parsing error, invalid input", max); + break; + + case ASN_VERSION_E : + XSTRNCPY(buffer, "ASN version error, invalid number", max); + break; + + case ASN_GETINT_E : + XSTRNCPY(buffer, "ASN get big int error, invalid data", max); + break; + + case ASN_RSA_KEY_E : + XSTRNCPY(buffer, "ASN key init error, invalid input", max); + break; + + case ASN_OBJECT_ID_E : + XSTRNCPY(buffer, "ASN object id error, invalid id", max); + break; + + case ASN_TAG_NULL_E : + XSTRNCPY(buffer, "ASN tag error, not null", max); + break; + + case ASN_EXPECT_0_E : + XSTRNCPY(buffer, "ASN expect error, not zero", max); + break; + + case ASN_BITSTR_E : + XSTRNCPY(buffer, "ASN bit string error, wrong id", max); + break; + + case ASN_UNKNOWN_OID_E : + XSTRNCPY(buffer, "ASN oid error, unknown sum id", max); + break; + + case ASN_DATE_SZ_E : + XSTRNCPY(buffer, "ASN date error, bad size", max); + break; + + case ASN_BEFORE_DATE_E : + XSTRNCPY(buffer, "ASN date error, current date before", max); + break; + + case ASN_AFTER_DATE_E : + XSTRNCPY(buffer, "ASN date error, current date after", max); + break; + + case ASN_SIG_OID_E : + XSTRNCPY(buffer, "ASN signature error, mismatched oid", max); + break; + + case ASN_TIME_E : + XSTRNCPY(buffer, "ASN time error, unkown time type", max); + break; + + case ASN_INPUT_E : + XSTRNCPY(buffer, "ASN input error, not enough data", max); + break; + + case ASN_SIG_CONFIRM_E : + XSTRNCPY(buffer, "ASN sig error, confirm failure", max); + break; + + case ASN_SIG_HASH_E : + XSTRNCPY(buffer, "ASN sig error, unsupported hash type", max); + break; + + case ASN_SIG_KEY_E : + XSTRNCPY(buffer, "ASN sig error, unsupported key type", max); + break; + + case ASN_DH_KEY_E : + XSTRNCPY(buffer, "ASN key init error, invalid input", max); + break; + + case ASN_NTRU_KEY_E : + XSTRNCPY(buffer, "ASN NTRU key decode error, invalid input", max); + break; + + case ECC_BAD_ARG_E : + XSTRNCPY(buffer, "ECC input argument wrong type, invalid input", max); + break; + + case ASN_ECC_KEY_E : + XSTRNCPY(buffer, "ECC ASN1 bad key data, invalid input", max); + break; + + case ECC_CURVE_OID_E : + XSTRNCPY(buffer, "ECC curve sum OID unsupported, invalid input", max); + break; + + default: + XSTRNCPY(buffer, "unknown error number", max); + + } + +#endif /* NO_ERROR_STRINGS */ + +} + + +#if defined(CYASSL_KEY_GEN) || defined(CYASSL_CERT_GEN) + +static int SetMyVersion(word32 version, byte* output, int header) +{ + int i = 0; + + if (header) { + output[i++] = ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED; + output[i++] = ASN_BIT_STRING; + } + output[i++] = ASN_INTEGER; + output[i++] = 0x01; + output[i++] = version; + + return i; +} + + +int DerToPem(const byte* der, word32 derSz, byte* output, word32 outSz, + int type) +{ + char header[80]; + char footer[80]; + + int headerLen; + int footerLen; + int i; + int outLen; /* return length or error */ + + if (type == CERT_TYPE) { + XSTRNCPY(header, "-----BEGIN CERTIFICATE-----\n", sizeof(header)); + XSTRNCPY(footer, "-----END CERTIFICATE-----\n", sizeof(footer)); + } else { + XSTRNCPY(header, "-----BEGIN RSA PRIVATE KEY-----\n", sizeof(header)); + XSTRNCPY(footer, "-----END RSA PRIVATE KEY-----\n", sizeof(footer)); + } + + headerLen = XSTRLEN(header); + footerLen = XSTRLEN(footer); + + if (!der || !output) + return -1; + + /* don't even try if outSz too short */ + if (outSz < headerLen + footerLen + derSz) + return -1; + + /* header */ + XMEMCPY(output, header, headerLen); + i = headerLen; + + /* body */ + outLen = outSz; /* input to Base64Encode */ + if (Base64Encode(der, derSz, output + i, (word32*)&outLen) < 0) + return -1; + i += outLen; + + /* footer */ + if ( (i + footerLen) > (int)outSz) + return -1; + XMEMCPY(output + i, footer, footerLen); + + return outLen + headerLen + footerLen; +} + + +#endif /* CYASSL_KEY_GEN || CYASSL_CERT_GEN */ + + +#ifdef CYASSL_KEY_GEN + + +static mp_int* GetRsaInt(RsaKey* key, int index) +{ + if (index == 0) + return &key->n; + if (index == 1) + return &key->e; + if (index == 2) + return &key->d; + if (index == 3) + return &key->p; + if (index == 4) + return &key->q; + if (index == 5) + return &key->dP; + if (index == 6) + return &key->dQ; + if (index == 7) + return &key->u; + + return NULL; +} + + +/* Convert RsaKey key to DER format, write to output (inLen), return bytes + written */ +int RsaKeyToDer(RsaKey* key, byte* output, word32 inLen) +{ + word32 seqSz, verSz, rawLen, intTotalLen = 0; + word32 sizes[RSA_INTS]; + int i, j, outLen; + + byte seq[MAX_SEQ_SZ]; + byte ver[MAX_VERSION_SZ]; + byte tmps[RSA_INTS][MAX_RSA_INT_SZ]; + + if (!key || !output) + return -1; + + if (key->type != RSA_PRIVATE) + return -1; + + /* write all big ints from key to DER tmps */ + for (i = 0; i < RSA_INTS; i++) { + mp_int* keyInt = GetRsaInt(key, i); + rawLen = mp_unsigned_bin_size(keyInt); + + tmps[i][0] = ASN_INTEGER; + sizes[i] = SetLength(rawLen, tmps[i] + 1) + 1; /* int tag */ + + if ( (sizes[i] + rawLen) < sizeof(tmps[i])) { + int err = mp_to_unsigned_bin(keyInt, tmps[i] + sizes[i]); + if (err == MP_OKAY) { + sizes[i] += rawLen; + intTotalLen += sizes[i]; + } + else + return err; + } + else + return -1; + } + + /* make headers */ + verSz = SetMyVersion(0, ver, FALSE); + seqSz = SetSequence(verSz + intTotalLen, seq); + + outLen = seqSz + verSz + intTotalLen; + if (outLen > (int)inLen) + return -1; + + /* write to output */ + XMEMCPY(output, seq, seqSz); + j = seqSz; + XMEMCPY(output + j, ver, verSz); + j += verSz; + + for (i = 0; i < RSA_INTS; i++) { + XMEMCPY(output + j, tmps[i], sizes[i]); + j += sizes[i]; + } + + return outLen; +} + +#endif /* CYASSL_KEY_GEN */ + + +#ifdef CYASSL_CERT_GEN + +/* Initialize and Set Certficate defaults: + version = 3 (0x2) + serial = 0 + sigType = MD5_WITH_RSA + issuer = blank + daysValid = 500 + selfSigned = 1 (true) use subject as issuer + subject = blank +*/ +void InitCert(Cert* cert) +{ + cert->version = 2; /* version 3 is hex 2 */ + cert->sigType = MD5wRSA; + cert->daysValid = 500; + cert->selfSigned = 1; + cert->bodySz = 0; + cert->keyType = RSA_KEY; + XMEMSET(cert->serial, 0, SERIAL_SIZE); + + cert->issuer.country[0] = '\0'; + cert->issuer.state[0] = '\0'; + cert->issuer.locality[0] = '\0'; + cert->issuer.sur[0] = '\0'; + cert->issuer.org[0] = '\0'; + cert->issuer.unit[0] = '\0'; + cert->issuer.commonName[0] = '\0'; + cert->issuer.email[0] = '\0'; + + cert->subject.country[0] = '\0'; + cert->subject.state[0] = '\0'; + cert->subject.locality[0] = '\0'; + cert->subject.sur[0] = '\0'; + cert->subject.org[0] = '\0'; + cert->subject.unit[0] = '\0'; + cert->subject.commonName[0] = '\0'; + cert->subject.email[0] = '\0'; +} + + +/* DER encoded x509 Certificate */ +typedef struct DerCert { + byte size[MAX_LENGTH_SZ]; /* length encoded */ + byte version[MAX_VERSION_SZ]; /* version encoded */ + byte serial[SERIAL_SIZE + MAX_LENGTH_SZ]; /* serial number encoded */ + byte sigAlgo[MAX_ALGO_SZ]; /* signature algo encoded */ + byte issuer[ASN_NAME_MAX]; /* issuer encoded */ + byte subject[ASN_NAME_MAX]; /* subject encoded */ + byte validity[MAX_DATE_SIZE*2 + MAX_SEQ_SZ*2]; /* before and after dates */ + byte publicKey[MAX_PUBLIC_KEY_SZ]; /* rsa / ntru public key encoded */ + int sizeSz; /* encoded size length */ + int versionSz; /* encoded version length */ + int serialSz; /* encoded serial length */ + int sigAlgoSz; /* enocded sig alog length */ + int issuerSz; /* encoded issuer length */ + int subjectSz; /* encoded subject length */ + int validitySz; /* encoded validity length */ + int publicKeySz; /* encoded public key length */ + int total; /* total encoded lengths */ +} DerCert; + + +/* Write a set header to output */ +static word32 SetSet(word32 len, byte* output) +{ + output[0] = ASN_SET | ASN_CONSTRUCTED; + return SetLength(len, output + 1) + 1; +} + + +/* Write a serial number to output */ +static int SetSerial(const byte* serial, byte* output) +{ + int length = 0; + + output[length++] = ASN_INTEGER; + length += SetLength(SERIAL_SIZE, &output[length]); + XMEMCPY(&output[length], serial, SERIAL_SIZE); + + return length + SERIAL_SIZE; +} + + +/* Write a public RSA key to output */ +static int SetPublicKey(byte* output, RsaKey* key) +{ + byte n[MAX_RSA_INT_SZ]; + byte e[MAX_RSA_E_SZ]; + byte algo[MAX_ALGO_SZ]; + byte seq[MAX_SEQ_SZ]; + byte len[MAX_LENGTH_SZ + 1]; /* trailing 0 */ + int nSz; + int eSz; + int algoSz; + int seqSz; + int lenSz; + int idx; + int rawLen; + + /* n */ + rawLen = mp_unsigned_bin_size(&key->n); + n[0] = ASN_INTEGER; + nSz = SetLength(rawLen, n + 1) + 1; /* int tag */ + + if ( (nSz + rawLen) < sizeof(n)) { + int err = mp_to_unsigned_bin(&key->n, n + nSz); + if (err == MP_OKAY) + nSz += rawLen; + else + return MP_TO_E; + } + else + return BUFFER_E; + + /* e */ + rawLen = mp_unsigned_bin_size(&key->e); + e[0] = ASN_INTEGER; + eSz = SetLength(rawLen, e + 1) + 1; /* int tag */ + + if ( (eSz + rawLen) < sizeof(e)) { + int err = mp_to_unsigned_bin(&key->e, e + eSz); + if (err == MP_OKAY) + eSz += rawLen; + else + return MP_TO_E; + } + else + return BUFFER_E; + + /* headers */ + algoSz = SetAlgoID(RSAk, algo, keyType); + seqSz = SetSequence(nSz + eSz, seq); + lenSz = SetLength(seqSz + nSz + eSz + 1, len); + len[lenSz++] = 0; /* trailing 0 */ + + /* write */ + idx = SetSequence(nSz + eSz + seqSz + lenSz + 1 + algoSz, output); + /* 1 is for ASN_BIT_STRING */ + /* algo */ + XMEMCPY(output + idx, algo, algoSz); + idx += algoSz; + /* bit string */ + output[idx++] = ASN_BIT_STRING; + /* length */ + XMEMCPY(output + idx, len, lenSz); + idx += lenSz; + /* seq */ + XMEMCPY(output + idx, seq, seqSz); + idx += seqSz; + /* n */ + XMEMCPY(output + idx, n, nSz); + idx += nSz; + /* e */ + XMEMCPY(output + idx, e, eSz); + idx += eSz; + + return idx; +} + + +static INLINE byte itob(int number) +{ + return (byte)number + 0x30; +} + + +/* write time to output, format */ +static void SetTime(struct tm* date, byte* output) +{ + int i = 0; + + output[i++] = itob((date->tm_year % 10000) / 1000); + output[i++] = itob((date->tm_year % 1000) / 100); + output[i++] = itob((date->tm_year % 100) / 10); + output[i++] = itob( date->tm_year % 10); + + output[i++] = itob(date->tm_mon / 10); + output[i++] = itob(date->tm_mon % 10); + + output[i++] = itob(date->tm_mday / 10); + output[i++] = itob(date->tm_mday % 10); + + output[i++] = itob(date->tm_hour / 10); + output[i++] = itob(date->tm_hour % 10); + + output[i++] = itob(date->tm_min / 10); + output[i++] = itob(date->tm_min % 10); + + output[i++] = itob(date->tm_sec / 10); + output[i++] = itob(date->tm_sec % 10); + + output[i] = 'Z'; /* Zulu profiel */ +} + + +/* Set Date validity from now until now + daysValid */ +static int SetValidity(byte* output, int daysValid) +{ + byte before[MAX_DATE_SIZE]; + byte after[MAX_DATE_SIZE]; + + int beforeSz; + int afterSz; + int seqSz; + + time_t ticks; + struct tm* now; + struct tm local; + + ticks = XTIME(0); + now = XGMTIME(&ticks); + + /* before now */ + local = *now; + before[0] = ASN_GENERALIZED_TIME; + beforeSz = SetLength(ASN_GEN_TIME_SZ, before + 1) + 1; /* gen tag */ + + /* adjust */ + local.tm_year += 1900; + local.tm_mon += 1; + + SetTime(&local, before + beforeSz); + beforeSz += ASN_GEN_TIME_SZ; + + /* after now + daysValid */ + local = *now; + after[0] = ASN_GENERALIZED_TIME; + afterSz = SetLength(ASN_GEN_TIME_SZ, after + 1) + 1; /* gen tag */ + + /* add daysValid */ + local.tm_mday += daysValid; + mktime(&local); + + /* adjust */ + local.tm_year += 1900; + local.tm_mon += 1; + + SetTime(&local, after + afterSz); + afterSz += ASN_GEN_TIME_SZ; + + /* headers and output */ + seqSz = SetSequence(beforeSz + afterSz, output); + XMEMCPY(output + seqSz, before, beforeSz); + XMEMCPY(output + seqSz + beforeSz, after, afterSz); + + return seqSz + beforeSz + afterSz; +} + + +/* ASN Encoded Name field */ +typedef struct EncodedName { + int nameLen; /* actual string value length */ + int totalLen; /* total encodeding length */ + int type; /* type of name */ + int used; /* are we actually using this one */ + byte encoded[NAME_SIZE * 2]; /* encoding */ +} EncodedName; + + +/* Get Which Name from index */ +static const char* GetOneName(CertName* name, int index) +{ + switch (index) { + case 0: + return name->country; + break; + case 1: + return name->state; + break; + case 2: + return name->locality; + break; + case 3: + return name->sur; + break; + case 4: + return name->org; + break; + case 5: + return name->unit; + break; + case 6: + return name->commonName; + break; + case 7: + return name->email; + break; + default: + return 0; + } + + return 0; +} + + +/* Get ASN Name from index */ +static byte GetNameId(int index) +{ + switch (index) { + case 0: + return ASN_COUNTRY_NAME; + break; + case 1: + return ASN_STATE_NAME; + break; + case 2: + return ASN_LOCALITY_NAME; + break; + case 3: + return ASN_SUR_NAME; + break; + case 4: + return ASN_ORG_NAME; + break; + case 5: + return ASN_ORGUNIT_NAME; + break; + case 6: + return ASN_COMMON_NAME; + break; + case 7: + /* email uses different id type */ + return 0; + break; + default: + return 0; + } + + return 0; +} + + +/* encode CertName into output, return total bytes written */ +static int SetName(byte* output, CertName* name) +{ + int totalBytes = 0, i, idx; + EncodedName names[NAME_ENTRIES]; + + for (i = 0; i < NAME_ENTRIES; i++) { + const char* nameStr = GetOneName(name, i); + if (nameStr) { + /* bottom up */ + byte firstLen[MAX_LENGTH_SZ]; + byte secondLen[MAX_LENGTH_SZ]; + byte sequence[MAX_SEQ_SZ]; + byte set[MAX_SET_SZ]; + + int email = i == (NAME_ENTRIES - 1) ? 1 : 0; + int strLen = XSTRLEN(nameStr); + int thisLen = strLen; + int firstSz, secondSz, seqSz, setSz; + + if (strLen == 0) { /* no user data for this item */ + names[i].used = 0; + continue; + } + + secondSz = SetLength(strLen, secondLen); + thisLen += secondSz; + if (email) { + thisLen += EMAIL_JOINT_LEN; + thisLen ++; /* id type */ + firstSz = SetLength(EMAIL_JOINT_LEN, firstLen); + } + else { + thisLen++; /* str type */ + thisLen++; /* id type */ + thisLen += JOINT_LEN; + firstSz = SetLength(JOINT_LEN + 1, firstLen); + } + thisLen += firstSz; + thisLen++; /* object id */ + + seqSz = SetSequence(thisLen, sequence); + thisLen += seqSz; + setSz = SetSet(thisLen, set); + thisLen += setSz; + + if (thisLen > sizeof(names[i].encoded)) + return BUFFER_E; + + /* store it */ + idx = 0; + /* set */ + XMEMCPY(names[i].encoded, set, setSz); + idx += setSz; + /* seq */ + XMEMCPY(names[i].encoded + idx, sequence, seqSz); + idx += seqSz; + /* asn object id */ + names[i].encoded[idx++] = ASN_OBJECT_ID; + /* first length */ + XMEMCPY(names[i].encoded + idx, firstLen, firstSz); + idx += firstSz; + if (email) { + const byte EMAIL_OID[] = { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, + 0x01, 0x09, 0x01, 0x16 }; + /* email joint id */ + XMEMCPY(names[i].encoded + idx, EMAIL_OID, sizeof(EMAIL_OID)); + idx += sizeof(EMAIL_OID); + } + else { + /* joint id */ + names[i].encoded[idx++] = 0x55; + names[i].encoded[idx++] = 0x04; + /* id type */ + names[i].encoded[idx++] = GetNameId(i); + /* str type */ + names[i].encoded[idx++] = 0x13; + } + /* second length */ + XMEMCPY(names[i].encoded + idx, secondLen, secondSz); + idx += secondSz; + /* str value */ + XMEMCPY(names[i].encoded + idx, nameStr, strLen); + idx += strLen; + + totalBytes += idx; + names[i].totalLen = idx; + names[i].used = 1; + } + else + names[i].used = 0; + } + + /* header */ + idx = SetSequence(totalBytes, output); + totalBytes += idx; + if (totalBytes > ASN_NAME_MAX) + return BUFFER_E; + + for (i = 0; i < NAME_ENTRIES; i++) { + if (names[i].used) { + XMEMCPY(output + idx, names[i].encoded, names[i].totalLen); + idx += names[i].totalLen; + } + } + return totalBytes; +} + + +/* encode info from cert into DER enocder format */ +static int EncodeCert(Cert* cert, DerCert* der, RsaKey* rsaKey, RNG* rng, + const byte* ntruKey, word16 ntruSz) +{ + /* version */ + der->versionSz = SetMyVersion(cert->version, der->version, TRUE); + + /* serial number */ + RNG_GenerateBlock(rng, cert->serial, SERIAL_SIZE); + cert->serial[0] = 0x01; /* ensure positive */ + der->serialSz = SetSerial(cert->serial, der->serial); + + /* signature algo */ + der->sigAlgoSz = SetAlgoID(cert->sigType, der->sigAlgo, sigType); + if (der->sigAlgoSz == 0) + return ALGO_ID_E; + + /* public key */ + if (cert->keyType == RSA_KEY) { + der->publicKeySz = SetPublicKey(der->publicKey, rsaKey); + if (der->publicKeySz == 0) + return PUBLIC_KEY_E; + } + else { +#ifdef HAVE_NTRU + word32 rc; + word16 encodedSz; + + rc = crypto_ntru_encrypt_publicKey2SubjectPublicKeyInfo( ntruSz, + ntruKey, &encodedSz, NULL); + if (rc != NTRU_OK) + return PUBLIC_KEY_E; + if (encodedSz > MAX_PUBLIC_KEY_SZ) + return PUBLIC_KEY_E; + + rc = crypto_ntru_encrypt_publicKey2SubjectPublicKeyInfo( ntruSz, + ntruKey, &encodedSz, der->publicKey); + if (rc != NTRU_OK) + return PUBLIC_KEY_E; + + der->publicKeySz = encodedSz; +#endif + } + + /* date validity */ + der->validitySz = SetValidity(der->validity, cert->daysValid); + if (der->validitySz == 0) + return DATE_E; + + /* subject name */ + der->subjectSz = SetName(der->subject, &cert->subject); + if (der->subjectSz == 0) + return SUBJECT_E; + + /* issuer name */ + der->issuerSz = SetName(der->issuer, cert->selfSigned ? + &cert->subject : &cert->issuer); + if (der->issuerSz == 0) + return ISSUER_E; + + der->total = der->versionSz + der->serialSz + der->sigAlgoSz + + der->publicKeySz + der->validitySz + der->subjectSz + der->issuerSz; + + return 0; +} + + +/* write DER encoded cert to buffer, size already checked */ +static int WriteCertBody(DerCert* der, byte* buffer) +{ + int idx; + + /* signed part header */ + idx = SetSequence(der->total, buffer); + /* version */ + XMEMCPY(buffer + idx, der->version, der->versionSz); + idx += der->versionSz; + /* serial */ + XMEMCPY(buffer + idx, der->serial, der->serialSz); + idx += der->serialSz; + /* sig algo */ + XMEMCPY(buffer + idx, der->sigAlgo, der->sigAlgoSz); + idx += der->sigAlgoSz; + /* issuer */ + XMEMCPY(buffer + idx, der->issuer, der->issuerSz); + idx += der->issuerSz; + /* validity */ + XMEMCPY(buffer + idx, der->validity, der->validitySz); + idx += der->validitySz; + /* subject */ + XMEMCPY(buffer + idx, der->subject, der->subjectSz); + idx += der->subjectSz; + /* public key */ + XMEMCPY(buffer + idx, der->publicKey, der->publicKeySz); + idx += der->publicKeySz; + + return idx; +} + + +/* Make MD5wRSA signature from buffer (sz), write to sig (sigSz) */ +static int MakeSignature(const byte* buffer, int sz, byte* sig, int sigSz, + RsaKey* key, RNG* rng) +{ + byte digest[SHA_DIGEST_SIZE]; /* max size */ + byte encSig[MAX_ENCODED_DIG_SZ + MAX_ALGO_SZ + MAX_SEQ_SZ]; + int encSigSz, digestSz, hashType; + Md5 md5; /* md5 for now */ + + InitMd5(&md5); + Md5Update(&md5, buffer, sz); + Md5Final(&md5, digest); + digestSz = MD5_DIGEST_SIZE; + hashType = MD5h; + + /* signature */ + encSigSz = EncodeSignature(encSig, digest, digestSz, hashType); + return RsaSSL_Sign(encSig, encSigSz, sig, sigSz, key, rng); +} + + +/* add signature to end of buffer, size of buffer assumed checked, return + new length */ +static int AddSignature(byte* buffer, int bodySz, const byte* sig, int sigSz) +{ + byte seq[MAX_SEQ_SZ]; + int idx = bodySz, seqSz; + + /* algo */ + idx += SetAlgoID(MD5wRSA, buffer + idx, sigType); + /* bit string */ + buffer[idx++] = ASN_BIT_STRING; + /* length */ + idx += SetLength(sigSz + 1, buffer + idx); + buffer[idx++] = 0; /* trailing 0 */ + /* signature */ + XMEMCPY(buffer + idx, sig, sigSz); + idx += sigSz; + + /* make room for overall header */ + seqSz = SetSequence(idx, seq); + XMEMMOVE(buffer + seqSz, buffer, idx); + XMEMCPY(buffer, seq, seqSz); + + return idx + seqSz; +} + + +/* Make an x509 Certificate v3 any key type from cert input, write to buffer */ +static int MakeAnyCert(Cert* cert, byte* derBuffer, word32 derSz, + RsaKey* rsaKey, RNG* rng, const byte* ntruKey, word16 ntruSz) +{ + DerCert der; + int ret; + + cert->keyType = rsaKey ? RSA_KEY : NTRU_KEY; + ret = EncodeCert(cert, &der, rsaKey, rng, ntruKey, ntruSz); + if (ret != 0) + return ret; + + if (der.total + MAX_SEQ_SZ * 2 > (int)derSz) + return BUFFER_E; + + return cert->bodySz = WriteCertBody(&der, derBuffer); +} + + +/* Make an x509 Certificate v3 RSA from cert input, write to buffer */ +int MakeCert(Cert* cert, byte* derBuffer, word32 derSz, RsaKey* rsaKey,RNG* rng) +{ + return MakeAnyCert(cert, derBuffer, derSz, rsaKey, rng, NULL, 0); +} + + +#ifdef HAVE_NTRU + +int MakeNtruCert(Cert* cert, byte* derBuffer, word32 derSz, + const byte* ntruKey, word16 keySz, RNG* rng) +{ + return MakeAnyCert(cert, derBuffer, derSz, NULL, rng, ntruKey, keySz); +} + +#endif /* HAVE_NTRU */ + + +int SignCert(Cert* cert, byte* buffer, word32 buffSz, RsaKey* key, RNG* rng) +{ + byte sig[MAX_ENCODED_SIG_SZ]; + int sigSz; + int bodySz = cert->bodySz; + + if (bodySz < 0) + return bodySz; + + sigSz = MakeSignature(buffer, bodySz, sig, sizeof(sig), key, rng); + if (sigSz < 0) + return sigSz; + + if (bodySz + MAX_SEQ_SZ * 2 + sigSz > (int)buffSz) + return BUFFER_E; + + return AddSignature(buffer, bodySz, sig, sigSz); +} + + +int MakeSelfCert(Cert* cert, byte* buffer, word32 buffSz, RsaKey* key, RNG* rng) +{ + int ret = MakeCert(cert, buffer, buffSz, key, rng); + + if (ret < 0) + return ret; + + return SignCert(cert, buffer, buffSz, key, rng); +} + + +/* forward from CyaSSL */ +int CyaSSL_PemCertToDer(const char* fileName, unsigned char* derBuf, int derSz); + +#ifndef NO_FILESYSTEM + +int SetIssuer(Cert* cert, const char* issuerCertFile) +{ + DecodedCert decoded; + byte der[8192]; + int derSz = CyaSSL_PemCertToDer(issuerCertFile, der, sizeof(der)); + int ret; + int sz; + + if (derSz < 0) + return derSz; + + cert->selfSigned = 0; + + InitDecodedCert(&decoded, der, 0); + ret = ParseCertRelative(&decoded, derSz, CA_TYPE, NO_VERIFY, 0); + + if (ret < 0) + return ret; + + if (decoded.subjectCN) { + sz = (decoded.subjectCNLen < NAME_SIZE) ? decoded.subjectCNLen : + NAME_SIZE - 1; + strncpy(cert->issuer.commonName, decoded.subjectCN, NAME_SIZE); + cert->issuer.commonName[sz] = 0; + } + if (decoded.subjectC) { + sz = (decoded.subjectCLen < NAME_SIZE) ? decoded.subjectCLen : + NAME_SIZE - 1; + strncpy(cert->issuer.country, decoded.subjectC, NAME_SIZE); + cert->issuer.country[sz] = 0; + } + if (decoded.subjectST) { + sz = (decoded.subjectSTLen < NAME_SIZE) ? decoded.subjectSTLen : + NAME_SIZE - 1; + strncpy(cert->issuer.state, decoded.subjectST, NAME_SIZE); + cert->issuer.state[sz] = 0; + } + if (decoded.subjectL) { + sz = (decoded.subjectLLen < NAME_SIZE) ? decoded.subjectLLen : + NAME_SIZE - 1; + strncpy(cert->issuer.locality, decoded.subjectL, NAME_SIZE); + cert->issuer.locality[sz] = 0; + } + if (decoded.subjectO) { + sz = (decoded.subjectOLen < NAME_SIZE) ? decoded.subjectOLen : + NAME_SIZE - 1; + strncpy(cert->issuer.org, decoded.subjectO, NAME_SIZE); + cert->issuer.org[sz] = 0; + } + if (decoded.subjectOU) { + sz = (decoded.subjectOULen < NAME_SIZE) ? decoded.subjectOULen : + NAME_SIZE - 1; + strncpy(cert->issuer.unit, decoded.subjectOU, NAME_SIZE); + cert->issuer.unit[sz] = 0; + } + if (decoded.subjectSN) { + sz = (decoded.subjectSNLen < NAME_SIZE) ? decoded.subjectSNLen : + NAME_SIZE - 1; + strncpy(cert->issuer.sur, decoded.subjectSN, NAME_SIZE); + cert->issuer.sur[sz] = 0; + } + if (decoded.subjectEmail) { + sz = (decoded.subjectEmailLen < NAME_SIZE) ? decoded.subjectEmailLen : + NAME_SIZE - 1; + strncpy(cert->issuer.email, decoded.subjectEmail, NAME_SIZE); + cert->issuer.email[sz] = 0; + } + + FreeDecodedCert(&decoded); + + return 0; +} + +#endif /* NO_FILESYSTEM */ +#endif /* CYASSL_CERT_GEN */ + + +#ifdef HAVE_ECC + +/* Der Eoncde r & s ints into out, outLen is (in/out) size */ +int StoreECC_DSA_Sig(byte* out, word32* outLen, mp_int* r, mp_int* s) +{ + word32 idx = 0; + word32 rSz; /* encoding size */ + word32 sSz; + word32 headerSz = 4; /* 2*ASN_TAG + 2*LEN(ENUM) */ + + int rLen = mp_unsigned_bin_size(r); /* big int size */ + int sLen = mp_unsigned_bin_size(s); + int err; + + if (*outLen < (rLen + sLen + headerSz + 2)) /* SEQ_TAG + LEN(ENUM) */ + return -1; + + idx = SetSequence(rLen + sLen + headerSz, out); + + /* store r */ + out[idx++] = ASN_INTEGER; + rSz = SetLength(rLen, &out[idx]); + idx += rSz; + err = mp_to_unsigned_bin(r, &out[idx]); + if (err != MP_OKAY) return err; + idx += rLen; + + /* store s */ + out[idx++] = ASN_INTEGER; + sSz = SetLength(sLen, &out[idx]); + idx += sSz; + err = mp_to_unsigned_bin(s, &out[idx]); + if (err != MP_OKAY) return err; + idx += sLen; + + *outLen = idx; + + return 0; +} + + +/* Der Decode ECC-DSA Signautre, r & s stored as big ints */ +int DecodeECC_DSA_Sig(const byte* sig, word32 sigLen, mp_int* r, mp_int* s) +{ + word32 idx = 0; + int len = 0; + + if (GetSequence(sig, &idx, &len) < 0) + return ASN_ECC_KEY_E; + + if ((word32)len > (sigLen - idx)) + return ASN_ECC_KEY_E; + + if (GetInt(r, sig, &idx) < 0) + return ASN_ECC_KEY_E; + + if (GetInt(s, sig, &idx) < 0) + return ASN_ECC_KEY_E; + + return 0; +} + + +int EccPrivateKeyDecode(const byte* input, word32* inOutIdx, ecc_key* key, + word32 inSz) +{ + word32 begin = *inOutIdx; + word32 oid = 0; + int version, length; + int privSz, pubSz; + byte b; + byte priv[ECC_MAXSIZE]; + byte pub[ECC_MAXSIZE * 2 + 1]; /* public key has two parts plus header */ + + if (GetSequence(input, inOutIdx, &length) < 0) + return ASN_PARSE_E; + + if ((word32)length > (inSz - (*inOutIdx - begin))) + return ASN_INPUT_E; + + if (GetMyVersion(input, inOutIdx, &version) < 0) + return ASN_PARSE_E; + + b = input[*inOutIdx]; + *inOutIdx += 1; + + /* priv type */ + if (b != 4 && b != 6 && b != 7) + return ASN_PARSE_E; + + if (GetLength(input, inOutIdx, &length) < 0) + return ASN_PARSE_E; + + /* priv key */ + privSz = length; + XMEMCPY(priv, &input[*inOutIdx], privSz); + *inOutIdx += length; + + /* prefix 0 */ + b = input[*inOutIdx]; + *inOutIdx += 1; + + if (GetLength(input, inOutIdx, &length) < 0) + return ASN_PARSE_E; + + /* object id */ + b = input[*inOutIdx]; + *inOutIdx += 1; + + if (b != ASN_OBJECT_ID) + return ASN_OBJECT_ID_E; + + if (GetLength(input, inOutIdx, &length) < 0) + return ASN_PARSE_E; + + while(length--) { + oid += input[*inOutIdx]; + *inOutIdx += 1; + } + if (CheckCurve(oid) < 0) + return ECC_CURVE_OID_E; + + /* prefix 1 */ + b = input[*inOutIdx]; + *inOutIdx += 1; + + if (GetLength(input, inOutIdx, &length) < 0) + return ASN_PARSE_E; + + /* key header */ + b = input[*inOutIdx]; + *inOutIdx += 1; + if (b != ASN_BIT_STRING) + return ASN_BITSTR_E; + + if (GetLength(input, inOutIdx, &length) < 0) + return ASN_PARSE_E; + b = input[*inOutIdx]; + *inOutIdx += 1; + if (b != 0x00) + return ASN_EXPECT_0_E; + + pubSz = length - 1; /* null prefix */ + XMEMCPY(pub, &input[*inOutIdx], pubSz); + + *inOutIdx += length; + + return ecc_import_private_key(priv, privSz, pub, pubSz, key); +} + +#endif /* HAVE_ECC */ diff --git a/ctaocrypt/src/coding.c b/ctaocrypt/src/coding.c new file mode 100644 index 000000000..1e1f98c5c --- /dev/null +++ b/ctaocrypt/src/coding.c @@ -0,0 +1,229 @@ +/* coding.c + * + * Copyright (C) 2006-2011 Sawtooth Consulting Ltd. + * + * This file is part of CyaSSL. + * + * CyaSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * CyaSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + + +#include "coding.h" + + +enum { + BAD = 0xFF, /* invalid encoding */ + PAD = '=', + PEM_LINE_SZ = 64 +}; + + +static +const byte base64Decode[] = { 62, BAD, BAD, BAD, 63, /* + starts at 0x2B */ + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, + BAD, BAD, BAD, BAD, BAD, BAD, BAD, + 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, + BAD, BAD, BAD, BAD, BAD, BAD, + 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 + }; + + +int Base64Decode(const byte* in, word32 inLen, byte* out, word32* outLen) +{ + word32 i = 0; + word32 j = 0; + word32 plainSz = inLen - ((inLen + (PEM_LINE_SZ - 1)) / PEM_LINE_SZ ); + + plainSz = (plainSz * 3 + 3) / 4; + if (plainSz > *outLen) return -1; + + while (inLen > 3) { + byte b1, b2, b3; + byte e1 = in[j++]; + byte e2 = in[j++]; + byte e3 = in[j++]; + byte e4 = in[j++]; + + int pad3 = 0; + int pad4 = 0; + + if (e1 == 0) /* end file 0's */ + break; + if (e3 == PAD) + pad3 = 1; + if (e4 == PAD) + pad4 = 1; + + e1 = base64Decode[e1 - 0x2B]; + e2 = base64Decode[e2 - 0x2B]; + e3 = (e3 == PAD) ? 0 : base64Decode[e3 - 0x2B]; + e4 = (e4 == PAD) ? 0 : base64Decode[e4 - 0x2B]; + + b1 = (e1 << 2) | (e2 >> 4); + b2 = ((e2 & 0xF) << 4) | (e3 >> 2); + b3 = ((e3 & 0x3) << 6) | e4; + + out[i++] = b1; + if (!pad3) + out[i++] = b2; + if (!pad4) + out[i++] = b3; + else + break; + + inLen -= 4; + if (in[j] == ' ' || in[j] == '\r' || in[j] == '\n') { + byte endLine = in[j++]; + inLen--; + while (endLine == ' ') { /* allow trailing whitespace */ + endLine = in[j++]; + inLen--; + } + if (endLine == '\r') { + endLine = in[j++]; + inLen--; + } + if (endLine != '\n') + return -1; + } + } + *outLen = i; + + return 0; +} + + +#if defined(OPENSSL_EXTRA) || defined (SESSION_CERTS) || defined(CYASSL_KEY_GEN) || defined(CYASSL_CERT_GEN) + +static +const byte base64Encode[] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', + 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', + 'U', 'V', 'W', 'X', 'Y', 'Z', + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', + 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', + 'u', 'v', 'w', 'x', 'y', 'z', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + '+', '/' + }; + + +/* porting assistance from yaSSL by Raphael HUCK */ +int Base64Encode(const byte* in, word32 inLen, byte* out, word32* outLen) +{ + word32 i = 0, + j = 0, + n = 0; /* new line counter */ + + word32 outSz = (inLen + 3 - 1) / 3 * 4; + outSz += (outSz + PEM_LINE_SZ - 1) / PEM_LINE_SZ; /* new lines */ + + if (outSz > *outLen) return -1; + + while (inLen > 2) { + byte b1 = in[j++]; + byte b2 = in[j++]; + byte b3 = in[j++]; + + /* encoded idx */ + byte e1 = b1 >> 2; + byte e2 = ((b1 & 0x3) << 4) | (b2 >> 4); + byte e3 = ((b2 & 0xF) << 2) | (b3 >> 6); + byte e4 = b3 & 0x3F; + + /* store */ + out[i++] = base64Encode[e1]; + out[i++] = base64Encode[e2]; + out[i++] = base64Encode[e3]; + out[i++] = base64Encode[e4]; + + inLen -= 3; + + if ((++n % (PEM_LINE_SZ / 4)) == 0 && inLen) + out[i++] = '\n'; + } + + /* last integral */ + if (inLen) { + int twoBytes = (inLen == 2); + + byte b1 = in[j++]; + byte b2 = (twoBytes) ? in[j++] : 0; + + byte e1 = b1 >> 2; + byte e2 = ((b1 & 0x3) << 4) | (b2 >> 4); + byte e3 = (b2 & 0xF) << 2; + + out[i++] = base64Encode[e1]; + out[i++] = base64Encode[e2]; + out[i++] = (twoBytes) ? base64Encode[e3] : PAD; + out[i++] = PAD; + } + + out[i++] = '\n'; + if (i != outSz) + return -1; + *outLen = outSz; + + return 0; +} + + +static +const byte hexDecode[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + BAD, BAD, BAD, BAD, BAD, BAD, BAD, + 10, 11, 12, 13, 14, 15 + }; /* A starts at 0x41 not 0x3A */ + +int Base16Decode(const byte* in, word32 inLen, byte* out, word32* outLen) +{ + word32 inIdx = 0; + word32 outIdx = 0; + + if (inLen % 2) + return -1; + + if (*outLen < (inLen / 2)) + return -1; + + while (inLen) { + byte b = in[inIdx++] - 0x30; /* 0 starts at 0x30 */ + byte b2 = in[inIdx++] - 0x30; + + /* sanity checks */ + if (b >= sizeof(hexDecode)/sizeof(hexDecode[0])) + return -1; + if (b2 >= sizeof(hexDecode)/sizeof(hexDecode[0])) + return -1; + + b = hexDecode[b]; + b2 = hexDecode[b2]; + + if (b == BAD || b2 == BAD) + return -1; + + out[outIdx++] = (b << 4) | b2; + inLen -= 2; + } + + *outLen = outIdx; + return 0; +} + + +#endif /* OPENSSL_EXTRA */ diff --git a/ctaocrypt/src/des3.c b/ctaocrypt/src/des3.c new file mode 100644 index 000000000..d7792fc30 --- /dev/null +++ b/ctaocrypt/src/des3.c @@ -0,0 +1,493 @@ +/* des3.c + * + * Copyright (C) 2006-2011 Sawtooth Consulting Ltd. + * + * This file is part of CyaSSL. + * + * CyaSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * CyaSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + + +#ifndef NO_DES3 + +#include "des3.h" +#ifdef NO_INLINE + #include "misc.h" +#else + #include "misc.c" +#endif + + +/* permuted choice table (key) */ +static const byte pc1[] = { + 57, 49, 41, 33, 25, 17, 9, + 1, 58, 50, 42, 34, 26, 18, + 10, 2, 59, 51, 43, 35, 27, + 19, 11, 3, 60, 52, 44, 36, + + 63, 55, 47, 39, 31, 23, 15, + 7, 62, 54, 46, 38, 30, 22, + 14, 6, 61, 53, 45, 37, 29, + 21, 13, 5, 28, 20, 12, 4 +}; + +/* number left rotations of pc1 */ +static const byte totrot[] = { + 1,2,4,6,8,10,12,14,15,17,19,21,23,25,27,28 +}; + +/* permuted choice key (table) */ +static const byte pc2[] = { + 14, 17, 11, 24, 1, 5, + 3, 28, 15, 6, 21, 10, + 23, 19, 12, 4, 26, 8, + 16, 7, 27, 20, 13, 2, + 41, 52, 31, 37, 47, 55, + 30, 40, 51, 45, 33, 48, + 44, 49, 39, 56, 34, 53, + 46, 42, 50, 36, 29, 32 +}; + +/* End of DES-defined tables */ + +/* bit 0 is left-most in byte */ +static const int bytebit[] = { + 0200,0100,040,020,010,04,02,01 +}; + +const word32 Spbox[8][64] = { +{ +0x01010400,0x00000000,0x00010000,0x01010404, +0x01010004,0x00010404,0x00000004,0x00010000, +0x00000400,0x01010400,0x01010404,0x00000400, +0x01000404,0x01010004,0x01000000,0x00000004, +0x00000404,0x01000400,0x01000400,0x00010400, +0x00010400,0x01010000,0x01010000,0x01000404, +0x00010004,0x01000004,0x01000004,0x00010004, +0x00000000,0x00000404,0x00010404,0x01000000, +0x00010000,0x01010404,0x00000004,0x01010000, +0x01010400,0x01000000,0x01000000,0x00000400, +0x01010004,0x00010000,0x00010400,0x01000004, +0x00000400,0x00000004,0x01000404,0x00010404, +0x01010404,0x00010004,0x01010000,0x01000404, +0x01000004,0x00000404,0x00010404,0x01010400, +0x00000404,0x01000400,0x01000400,0x00000000, +0x00010004,0x00010400,0x00000000,0x01010004}, +{ +0x80108020,0x80008000,0x00008000,0x00108020, +0x00100000,0x00000020,0x80100020,0x80008020, +0x80000020,0x80108020,0x80108000,0x80000000, +0x80008000,0x00100000,0x00000020,0x80100020, +0x00108000,0x00100020,0x80008020,0x00000000, +0x80000000,0x00008000,0x00108020,0x80100000, +0x00100020,0x80000020,0x00000000,0x00108000, +0x00008020,0x80108000,0x80100000,0x00008020, +0x00000000,0x00108020,0x80100020,0x00100000, +0x80008020,0x80100000,0x80108000,0x00008000, +0x80100000,0x80008000,0x00000020,0x80108020, +0x00108020,0x00000020,0x00008000,0x80000000, +0x00008020,0x80108000,0x00100000,0x80000020, +0x00100020,0x80008020,0x80000020,0x00100020, +0x00108000,0x00000000,0x80008000,0x00008020, +0x80000000,0x80100020,0x80108020,0x00108000}, +{ +0x00000208,0x08020200,0x00000000,0x08020008, +0x08000200,0x00000000,0x00020208,0x08000200, +0x00020008,0x08000008,0x08000008,0x00020000, +0x08020208,0x00020008,0x08020000,0x00000208, +0x08000000,0x00000008,0x08020200,0x00000200, +0x00020200,0x08020000,0x08020008,0x00020208, +0x08000208,0x00020200,0x00020000,0x08000208, +0x00000008,0x08020208,0x00000200,0x08000000, +0x08020200,0x08000000,0x00020008,0x00000208, +0x00020000,0x08020200,0x08000200,0x00000000, +0x00000200,0x00020008,0x08020208,0x08000200, +0x08000008,0x00000200,0x00000000,0x08020008, +0x08000208,0x00020000,0x08000000,0x08020208, +0x00000008,0x00020208,0x00020200,0x08000008, +0x08020000,0x08000208,0x00000208,0x08020000, +0x00020208,0x00000008,0x08020008,0x00020200}, +{ +0x00802001,0x00002081,0x00002081,0x00000080, +0x00802080,0x00800081,0x00800001,0x00002001, +0x00000000,0x00802000,0x00802000,0x00802081, +0x00000081,0x00000000,0x00800080,0x00800001, +0x00000001,0x00002000,0x00800000,0x00802001, +0x00000080,0x00800000,0x00002001,0x00002080, +0x00800081,0x00000001,0x00002080,0x00800080, +0x00002000,0x00802080,0x00802081,0x00000081, +0x00800080,0x00800001,0x00802000,0x00802081, +0x00000081,0x00000000,0x00000000,0x00802000, +0x00002080,0x00800080,0x00800081,0x00000001, +0x00802001,0x00002081,0x00002081,0x00000080, +0x00802081,0x00000081,0x00000001,0x00002000, +0x00800001,0x00002001,0x00802080,0x00800081, +0x00002001,0x00002080,0x00800000,0x00802001, +0x00000080,0x00800000,0x00002000,0x00802080}, +{ +0x00000100,0x02080100,0x02080000,0x42000100, +0x00080000,0x00000100,0x40000000,0x02080000, +0x40080100,0x00080000,0x02000100,0x40080100, +0x42000100,0x42080000,0x00080100,0x40000000, +0x02000000,0x40080000,0x40080000,0x00000000, +0x40000100,0x42080100,0x42080100,0x02000100, +0x42080000,0x40000100,0x00000000,0x42000000, +0x02080100,0x02000000,0x42000000,0x00080100, +0x00080000,0x42000100,0x00000100,0x02000000, +0x40000000,0x02080000,0x42000100,0x40080100, +0x02000100,0x40000000,0x42080000,0x02080100, +0x40080100,0x00000100,0x02000000,0x42080000, +0x42080100,0x00080100,0x42000000,0x42080100, +0x02080000,0x00000000,0x40080000,0x42000000, +0x00080100,0x02000100,0x40000100,0x00080000, +0x00000000,0x40080000,0x02080100,0x40000100}, +{ +0x20000010,0x20400000,0x00004000,0x20404010, +0x20400000,0x00000010,0x20404010,0x00400000, +0x20004000,0x00404010,0x00400000,0x20000010, +0x00400010,0x20004000,0x20000000,0x00004010, +0x00000000,0x00400010,0x20004010,0x00004000, +0x00404000,0x20004010,0x00000010,0x20400010, +0x20400010,0x00000000,0x00404010,0x20404000, +0x00004010,0x00404000,0x20404000,0x20000000, +0x20004000,0x00000010,0x20400010,0x00404000, +0x20404010,0x00400000,0x00004010,0x20000010, +0x00400000,0x20004000,0x20000000,0x00004010, +0x20000010,0x20404010,0x00404000,0x20400000, +0x00404010,0x20404000,0x00000000,0x20400010, +0x00000010,0x00004000,0x20400000,0x00404010, +0x00004000,0x00400010,0x20004010,0x00000000, +0x20404000,0x20000000,0x00400010,0x20004010}, +{ +0x00200000,0x04200002,0x04000802,0x00000000, +0x00000800,0x04000802,0x00200802,0x04200800, +0x04200802,0x00200000,0x00000000,0x04000002, +0x00000002,0x04000000,0x04200002,0x00000802, +0x04000800,0x00200802,0x00200002,0x04000800, +0x04000002,0x04200000,0x04200800,0x00200002, +0x04200000,0x00000800,0x00000802,0x04200802, +0x00200800,0x00000002,0x04000000,0x00200800, +0x04000000,0x00200800,0x00200000,0x04000802, +0x04000802,0x04200002,0x04200002,0x00000002, +0x00200002,0x04000000,0x04000800,0x00200000, +0x04200800,0x00000802,0x00200802,0x04200800, +0x00000802,0x04000002,0x04200802,0x04200000, +0x00200800,0x00000000,0x00000002,0x04200802, +0x00000000,0x00200802,0x04200000,0x00000800, +0x04000002,0x04000800,0x00000800,0x00200002}, +{ +0x10001040,0x00001000,0x00040000,0x10041040, +0x10000000,0x10001040,0x00000040,0x10000000, +0x00040040,0x10040000,0x10041040,0x00041000, +0x10041000,0x00041040,0x00001000,0x00000040, +0x10040000,0x10000040,0x10001000,0x00001040, +0x00041000,0x00040040,0x10040040,0x10041000, +0x00001040,0x00000000,0x00000000,0x10040040, +0x10000040,0x10001000,0x00041040,0x00040000, +0x00041040,0x00040000,0x10041000,0x00001000, +0x00000040,0x10040040,0x00001000,0x00041040, +0x10001000,0x00000040,0x10000040,0x10040000, +0x10040040,0x10000000,0x00040000,0x10001040, +0x00000000,0x10041040,0x00040040,0x10000040, +0x10040000,0x10001000,0x10001040,0x00000000, +0x10041040,0x00041000,0x00041000,0x00001040, +0x00001040,0x00040040,0x10000000,0x10041000} +}; + + +static INLINE void IPERM(word32* left, word32* right) +{ + word32 work; + + *right = rotlFixed(*right, 4U); + work = (*left ^ *right) & 0xf0f0f0f0; + *left ^= work; + + *right = rotrFixed(*right^work, 20U); + work = (*left ^ *right) & 0xffff0000; + *left ^= work; + + *right = rotrFixed(*right^work, 18U); + work = (*left ^ *right) & 0x33333333; + *left ^= work; + + *right = rotrFixed(*right^work, 6U); + work = (*left ^ *right) & 0x00ff00ff; + *left ^= work; + + *right = rotlFixed(*right^work, 9U); + work = (*left ^ *right) & 0xaaaaaaaa; + *left = rotlFixed(*left^work, 1U); + *right ^= work; +} + + +static INLINE void FPERM(word32* left, word32* right) +{ + word32 work; + + *right = rotrFixed(*right, 1U); + work = (*left ^ *right) & 0xaaaaaaaa; + *right ^= work; + + *left = rotrFixed(*left^work, 9U); + work = (*left ^ *right) & 0x00ff00ff; + *right ^= work; + + *left = rotlFixed(*left^work, 6U); + work = (*left ^ *right) & 0x33333333; + *right ^= work; + + *left = rotlFixed(*left^work, 18U); + work = (*left ^ *right) & 0xffff0000; + *right ^= work; + + *left = rotlFixed(*left^work, 20U); + work = (*left ^ *right) & 0xf0f0f0f0; + *right ^= work; + + *left = rotrFixed(*left^work, 4U); +} + + +static void DesSetKey(const byte* key, int dir, word32* out) +{ + byte buffer[56+56+8]; + byte *const pc1m = buffer; /* place to modify pc1 into */ + byte *const pcr = pc1m + 56; /* place to rotate pc1 into */ + byte *const ks = pcr + 56; + register int i,j,l; + int m; + + for (j = 0; j < 56; j++) { /* convert pc1 to bits of key */ + l = pc1[j] - 1; /* integer bit location */ + m = l & 07; /* find bit */ + pc1m[j] = (key[l >> 3] & /* find which key byte l is in */ + bytebit[m]) /* and which bit of that byte */ + ? 1 : 0; /* and store 1-bit result */ + } + for (i = 0; i < 16; i++) { /* key chunk for each iteration */ + XMEMSET(ks, 0, 8); /* Clear key schedule */ + for (j = 0; j < 56; j++) /* rotate pc1 the right amount */ + pcr[j] = pc1m[(l = j + totrot[i]) < (j < 28 ? 28 : 56) ? l: l-28]; + /* rotate left and right halves independently */ + for (j = 0; j < 48; j++){ /* select bits individually */ + /* check bit that goes to ks[j] */ + if (pcr[pc2[j] - 1]){ + /* mask it in if it's there */ + l= j % 6; + ks[j/6] |= bytebit[l] >> 2; + } + } + /* Now convert to odd/even interleaved form for use in F */ + out[2*i] = ((word32)ks[0] << 24) + | ((word32)ks[2] << 16) + | ((word32)ks[4] << 8) + | ((word32)ks[6]); + out[2*i + 1] = ((word32)ks[1] << 24) + | ((word32)ks[3] << 16) + | ((word32)ks[5] << 8) + | ((word32)ks[7]); + } + + /* reverse key schedule order */ + if (dir == DES_DECRYPTION) + for (i = 0; i < 16; i += 2) { + word32 swap = out[i]; + out[i] = out[DES_KS_SIZE - 2 - i]; + out[DES_KS_SIZE - 2 - i] = swap; + + swap = out[i + 1]; + out[i + 1] = out[DES_KS_SIZE - 1 - i]; + out[DES_KS_SIZE - 1 - i] = swap; + } + +} + + +static INLINE int Reverse(int dir) +{ + return !dir; +} + + +void Des_SetKey(Des* des, const byte* key, const byte* iv, int dir) +{ + DesSetKey(key, dir, des->key); + + XMEMCPY(des->reg, iv, DES_BLOCK_SIZE); +} + + +void Des3_SetKey(Des3* des, const byte* key, const byte* iv, int dir) +{ + DesSetKey(key + (dir == DES_ENCRYPTION ? 0 : 16), dir, des->key[0]); + DesSetKey(key + 8, Reverse(dir), des->key[1]); + DesSetKey(key + (dir == DES_DECRYPTION ? 0 : 16), dir, des->key[2]); + + XMEMCPY(des->reg, iv, DES_BLOCK_SIZE); +} + + +void DesRawProcessBlock(word32* lIn, word32* rIn, const word32* kptr) +{ + word32 l = *lIn, r = *rIn, i; + + for (i=0; i<8; i++) + { + word32 work = rotrFixed(r, 4U) ^ kptr[4*i+0]; + l ^= Spbox[6][(work) & 0x3f] + ^ Spbox[4][(work >> 8) & 0x3f] + ^ Spbox[2][(work >> 16) & 0x3f] + ^ Spbox[0][(work >> 24) & 0x3f]; + work = r ^ kptr[4*i+1]; + l ^= Spbox[7][(work) & 0x3f] + ^ Spbox[5][(work >> 8) & 0x3f] + ^ Spbox[3][(work >> 16) & 0x3f] + ^ Spbox[1][(work >> 24) & 0x3f]; + + work = rotrFixed(l, 4U) ^ kptr[4*i+2]; + r ^= Spbox[6][(work) & 0x3f] + ^ Spbox[4][(work >> 8) & 0x3f] + ^ Spbox[2][(work >> 16) & 0x3f] + ^ Spbox[0][(work >> 24) & 0x3f]; + work = l ^ kptr[4*i+3]; + r ^= Spbox[7][(work) & 0x3f] + ^ Spbox[5][(work >> 8) & 0x3f] + ^ Spbox[3][(work >> 16) & 0x3f] + ^ Spbox[1][(work >> 24) & 0x3f]; + } + + *lIn = l; *rIn = r; +} + + +static void DesProcessBlock(Des* des, const byte* in, byte* out) +{ + word32 l, r; + + XMEMCPY(&l, in, sizeof(l)); + XMEMCPY(&r, in + sizeof(l), sizeof(r)); + #ifdef LITTLE_ENDIAN_ORDER + l = ByteReverseWord32(l); + r = ByteReverseWord32(r); + #endif + IPERM(&l,&r); + + DesRawProcessBlock(&l, &r, des->key); + + FPERM(&l,&r); + #ifdef LITTLE_ENDIAN_ORDER + l = ByteReverseWord32(l); + r = ByteReverseWord32(r); + #endif + XMEMCPY(out, &r, sizeof(r)); + XMEMCPY(out + sizeof(r), &l, sizeof(l)); +} + + +static void Des3ProcessBlock(Des3* des, const byte* in, byte* out) +{ + word32 l, r; + + XMEMCPY(&l, in, sizeof(l)); + XMEMCPY(&r, in + sizeof(l), sizeof(r)); + #ifdef LITTLE_ENDIAN_ORDER + l = ByteReverseWord32(l); + r = ByteReverseWord32(r); + #endif + IPERM(&l,&r); + + DesRawProcessBlock(&l, &r, des->key[0]); + DesRawProcessBlock(&r, &l, des->key[1]); + DesRawProcessBlock(&l, &r, des->key[2]); + + FPERM(&l,&r); + #ifdef LITTLE_ENDIAN_ORDER + l = ByteReverseWord32(l); + r = ByteReverseWord32(r); + #endif + XMEMCPY(out, &r, sizeof(r)); + XMEMCPY(out + sizeof(r), &l, sizeof(l)); +} + + +void Des_CbcEncrypt(Des* des, byte* out, const byte* in, word32 sz) +{ + word32 blocks = sz / DES_BLOCK_SIZE; + + while (blocks--) { + xorbuf((byte*)des->reg, in, DES_BLOCK_SIZE); + DesProcessBlock(des, (byte*)des->reg, (byte*)des->reg); + XMEMCPY(out, des->reg, DES_BLOCK_SIZE); + + out += DES_BLOCK_SIZE; + in += DES_BLOCK_SIZE; + } +} + + +void Des_CbcDecrypt(Des* des, byte* out, const byte* in, word32 sz) +{ + word32 blocks = sz / DES_BLOCK_SIZE; + byte hold[16]; + + while (blocks--) { + XMEMCPY(des->tmp, in, DES_BLOCK_SIZE); + DesProcessBlock(des, (byte*)des->tmp, out); + xorbuf(out, (byte*)des->reg, DES_BLOCK_SIZE); + + XMEMCPY(hold, des->reg, DES_BLOCK_SIZE); + XMEMCPY(des->reg, des->tmp, DES_BLOCK_SIZE); + XMEMCPY(des->tmp, hold, DES_BLOCK_SIZE); + + out += DES_BLOCK_SIZE; + in += DES_BLOCK_SIZE; + } +} + + +void Des3_CbcEncrypt(Des3* des, byte* out, const byte* in, word32 sz) +{ + word32 blocks = sz / DES_BLOCK_SIZE; + + while (blocks--) { + xorbuf((byte*)des->reg, in, DES_BLOCK_SIZE); + Des3ProcessBlock(des, (byte*)des->reg, (byte*)des->reg); + XMEMCPY(out, des->reg, DES_BLOCK_SIZE); + + out += DES_BLOCK_SIZE; + in += DES_BLOCK_SIZE; + } +} + + +void Des3_CbcDecrypt(Des3* des, byte* out, const byte* in, word32 sz) +{ + word32 blocks = sz / DES_BLOCK_SIZE; + + while (blocks--) { + XMEMCPY(des->tmp, in, DES_BLOCK_SIZE); + Des3ProcessBlock(des, (byte*)des->tmp, out); + xorbuf(out, (byte*)des->reg, DES_BLOCK_SIZE); + XMEMCPY(des->reg, des->tmp, DES_BLOCK_SIZE); + + out += DES_BLOCK_SIZE; + in += DES_BLOCK_SIZE; + } +} + + +#endif /* NO_DES3 */ diff --git a/ctaocrypt/src/dh.c b/ctaocrypt/src/dh.c new file mode 100644 index 000000000..8b3d94b41 --- /dev/null +++ b/ctaocrypt/src/dh.c @@ -0,0 +1,165 @@ +/* dh.c + * + * Copyright (C) 2006-2011 Sawtooth Consulting Ltd. + * + * This file is part of CyaSSL. + * + * CyaSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * CyaSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#ifndef NO_DH + +#include "ctc_dh.h" +#include "error.h" + +#ifndef USER_MATH_LIB + #include + #define XPOW(x,y) pow((x),(y)) + #define XLOG(x) log((x)) +#else + /* user's own math lib */ +#endif + + + +#ifndef min + + static INLINE word32 min(word32 a, word32 b) + { + return a > b ? b : a; + } + +#endif /* min */ + + + +void InitDhKey(DhKey* key) +{ +/* TomsFastMath doesn't use memory allocation */ +#ifndef USE_FAST_MATH + key->p.dp = 0; + key->g.dp = 0; +#endif +} + + +void FreeDhKey(DhKey* key) +{ +/* TomsFastMath doesn't use memory allocation */ +#ifndef USE_FAST_MATH + mp_clear(&key->p); + mp_clear(&key->g); +#endif +} + + +static word32 DiscreteLogWorkFactor(word32 n) +{ + /* assuming discrete log takes about the same time as factoring */ + if (n<5) + return 0; + else + return (word32)(2.4 * XPOW((double)n, 1.0/3.0) * + XPOW(XLOG((double)n), 2.0/3.0) - 5); +} + + +static void GeneratePrivate(DhKey* key, RNG* rng, byte* priv, word32* privSz) +{ + word32 sz = mp_unsigned_bin_size(&key->p); + sz = min(sz, 2 * DiscreteLogWorkFactor(sz * BIT_SIZE) / BIT_SIZE + 1); + + RNG_GenerateBlock(rng, priv, sz); + priv[0] |= 0x0C; + + *privSz = sz; +} + + +static int GeneratePublic(DhKey* key, const byte* priv, word32 privSz, + byte* pub, word32* pubSz) +{ + int ret = 0; + + mp_int x; + mp_int y; + + if (mp_init_multi(&x, &y, 0, 0, 0, 0) != MP_OKAY) + return MP_INIT_E; + + if (mp_read_unsigned_bin(&x, priv, privSz) != MP_OKAY) + ret = MP_READ_E; + + if (ret == 0 && mp_exptmod(&key->g, &x, &key->p, &y) != MP_OKAY) + ret = MP_EXPTMOD_E; + + if (ret == 0 && mp_to_unsigned_bin(&y, pub) != MP_OKAY) + ret = MP_TO_E; + + if (ret == 0) + *pubSz = mp_unsigned_bin_size(&y); + + mp_clear(&y); + mp_clear(&x); + + return ret; +} + + +int DhGenerateKeyPair(DhKey* key, RNG* rng, byte* priv, word32* privSz, + byte* pub, word32* pubSz) +{ + GeneratePrivate(key, rng, priv, privSz); + return GeneratePublic(key, priv, *privSz, pub, pubSz); + +} + +int DhAgree(DhKey* key, byte* agree, word32* agreeSz, const byte* priv, + word32 privSz, const byte* otherPub, word32 pubSz) +{ + int ret = 0; + + mp_int x; + mp_int y; + mp_int z; + + if (mp_init_multi(&x, &y, &z, 0, 0, 0) != MP_OKAY) + return MP_INIT_E; + + if (mp_read_unsigned_bin(&x, priv, privSz) != MP_OKAY) + ret = MP_READ_E; + + if (ret == 0 && mp_read_unsigned_bin(&y, otherPub, pubSz) != MP_OKAY) + ret = MP_READ_E; + + if (ret == 0 && mp_exptmod(&y, &x, &key->p, &z) != MP_OKAY) + ret = MP_EXPTMOD_E; + + if (ret == 0 && mp_to_unsigned_bin(&z, agree) != MP_OKAY) + ret = MP_TO_E; + + if (ret == 0) + *agreeSz = mp_unsigned_bin_size(&z); + + mp_clear(&z); + mp_clear(&y); + mp_clear(&x); + + return ret; +} + + +#endif /* NO_DH */ + diff --git a/ctaocrypt/src/dsa.c b/ctaocrypt/src/dsa.c new file mode 100644 index 000000000..28e328ad4 --- /dev/null +++ b/ctaocrypt/src/dsa.c @@ -0,0 +1,216 @@ +/* dsa.c + * + * Copyright (C) 2006-2011 Sawtooth Consulting Ltd. + * + * This file is part of CyaSSL. + * + * CyaSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * CyaSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#ifndef NO_DSA + +#include "ctc_dsa.h" +#include "ctc_sha.h" +#include "random.h" +#include "error.h" + + +enum { + DSA_HALF_SIZE = 20, /* r and s size */ + DSA_SIG_SIZE = 40 /* signaure size */ +}; + + +#ifndef min + + static INLINE word32 min(word32 a, word32 b) + { + return a > b ? b : a; + } + +#endif /* min */ + + +void InitDsaKey(DsaKey* key) +{ + key->type = -1; /* haven't decdied yet */ + +/* TomsFastMath doesn't use memory allocation */ +#ifndef USE_FAST_MATH + key->p.dp = 0; /* public alloc parts */ + key->q.dp = 0; + key->g.dp = 0; + key->y.dp = 0; + + key->x.dp = 0; /* private alloc parts */ +#endif +} + + +void FreeDsaKey(DsaKey* key) +{ +/* TomsFastMath doesn't use memory allocation */ +#ifndef USE_FAST_MATH + if (key->type == DSA_PRIVATE) + mp_clear(&key->x); + mp_clear(&key->y); + mp_clear(&key->g); + mp_clear(&key->q); + mp_clear(&key->p); +#endif +} + + +int DsaSign(const byte* digest, byte* out, DsaKey* key, RNG* rng) +{ + mp_int k, kInv, r, s, H; + int ret = 0, sz; + byte buffer[DSA_HALF_SIZE]; + + if (mp_init_multi(&k, &kInv, &r, &s, &H, 0) != MP_OKAY) + return MP_INIT_E; + + sz = min(sizeof(buffer), mp_unsigned_bin_size(&key->q)); + + /* generate k */ + RNG_GenerateBlock(rng, buffer, sz); + buffer[0] |= 0x0C; + + if (mp_read_unsigned_bin(&k, buffer, sz) != MP_OKAY) + ret = MP_READ_E; + + if (mp_cmp_d(&k, 1) != MP_GT) + ret = MP_CMP_E; + + /* inverse k mod q */ + if (ret == 0 && mp_invmod(&k, &key->q, &kInv) != MP_OKAY) + ret = MP_INVMOD_E; + + /* generate r, r = (g exp k mod p) mod q */ + if (ret == 0 && mp_exptmod(&key->g, &k, &key->p, &r) != MP_OKAY) + ret = MP_EXPTMOD_E; + + if (ret == 0 && mp_mod(&r, &key->q, &r) != MP_OKAY) + ret = MP_MOD_E; + + /* generate H from sha digest */ + if (ret == 0 && mp_read_unsigned_bin(&H, digest,SHA_DIGEST_SIZE) != MP_OKAY) + ret = MP_READ_E; + + /* generate s, s = (kInv * (H + x*r)) % q */ + if (ret == 0 && mp_mul(&key->x, &r, &s) != MP_OKAY) + ret = MP_MUL_E; + + if (ret == 0 && mp_add(&s, &H, &s) != MP_OKAY) + ret = MP_ADD_E; + + if (ret == 0 && mp_mulmod(&s, &kInv, &key->q, &s) != MP_OKAY) + ret = MP_MULMOD_E; + + /* write out */ + if (ret == 0) { + int rSz = mp_unsigned_bin_size(&r); + int sSz = mp_unsigned_bin_size(&s); + + if (rSz == DSA_HALF_SIZE - 1) { + out[0] = 0; + out++; + } + + if (mp_to_unsigned_bin(&r, out) != MP_OKAY) + ret = MP_TO_E; + else { + if (sSz == DSA_HALF_SIZE - 1) { + out[rSz] = 0; + out++; + } + ret = mp_to_unsigned_bin(&s, out + rSz); + } + } + + mp_clear(&H); + mp_clear(&s); + mp_clear(&r); + mp_clear(&kInv); + mp_clear(&k); + + return ret; +} + + +int DsaVerify(const byte* digest, const byte* sig, DsaKey* key, int* answer) +{ + mp_int w, u1, u2, v, r, s; + int ret = 0; + + if (mp_init_multi(&w, &u1, &u2, &v, &r, &s) != MP_OKAY) + return MP_INIT_E; + + /* set r and s from signature */ + if (mp_read_unsigned_bin(&r, sig, DSA_HALF_SIZE) != MP_OKAY || + mp_read_unsigned_bin(&s, sig + DSA_HALF_SIZE, DSA_HALF_SIZE) != MP_OKAY) + ret = MP_READ_E; + + /* sanity checks */ + + + /* put H into u1 from sha digest */ + if (ret == 0 && mp_read_unsigned_bin(&u1,digest,SHA_DIGEST_SIZE) != MP_OKAY) + ret = MP_READ_E; + + /* w = s invmod q */ + if (ret == 0 && mp_invmod(&s, &key->q, &w) != MP_OKAY) + ret = MP_INVMOD_E; + + /* u1 = (H * w) % q */ + if (ret == 0 && mp_mulmod(&u1, &w, &key->q, &u1) != MP_OKAY) + ret = MP_MULMOD_E; + + /* u2 = (r * w) % q */ + if (ret == 0 && mp_mulmod(&r, &w, &key->q, &u2) != MP_OKAY) + ret = MP_MULMOD_E; + + /* verify v = ((g^u1 * y^u2) mod p) mod q */ + if (ret == 0 && mp_exptmod(&key->g, &u1, &key->p, &u1) != MP_OKAY) + ret = MP_EXPTMOD_E; + + if (ret == 0 && mp_exptmod(&key->y, &u2, &key->p, &u2) != MP_OKAY) + ret = MP_EXPTMOD_E; + + if (ret == 0 && mp_mulmod(&u1, &u2, &key->p, &v) != MP_OKAY) + ret = MP_MULMOD_E; + + if (ret == 0 && mp_mod(&v, &key->q, &v) != MP_OKAY) + ret = MP_MULMOD_E; + + /* do they match */ + if (ret == 0 && mp_cmp(&r, &v) == MP_EQ) + *answer = 1; + else + *answer = 0; + + mp_clear(&s); + mp_clear(&r); + mp_clear(&u1); + mp_clear(&u2); + mp_clear(&w); + mp_clear(&v); + + return ret; +} + + +#endif /* NO_DSA */ + diff --git a/ctaocrypt/src/fp_mont_small.i b/ctaocrypt/src/fp_mont_small.i new file mode 100644 index 000000000..5617d2f47 --- /dev/null +++ b/ctaocrypt/src/fp_mont_small.i @@ -0,0 +1,3838 @@ +#ifdef TFM_SMALL_MONT_SET +/* computes x/R == x (mod N) via Montgomery Reduction */ +void fp_montgomery_reduce_small(fp_int *a, fp_int *m, fp_digit mp) +{ + fp_digit c[FP_SIZE], *_c, *tmpm, mu, cy; + int oldused, x, y, pa; + +#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+3; x++) { + c[x] = 0; + } +#endif + MONT_START; + + switch (pa) { + case 1: + x = 0; cy = 0; + LOOP_START; + _c = c + 0; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL; ++_c; +#else + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + break; + case 2: + x = 0; cy = 0; + LOOP_START; + _c = c + 0; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL; ++_c; + INNERMUL; ++_c; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 1; cy = 0; + LOOP_START; + _c = c + 1; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL; ++_c; + INNERMUL; ++_c; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + break; + case 3: + x = 0; cy = 0; + LOOP_START; + _c = c + 0; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 1; cy = 0; + LOOP_START; + _c = c + 1; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 2; cy = 0; + LOOP_START; + _c = c + 2; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + break; + case 4: + x = 0; cy = 0; + LOOP_START; + _c = c + 0; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 1; cy = 0; + LOOP_START; + _c = c + 1; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 2; cy = 0; + LOOP_START; + _c = c + 2; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 3; cy = 0; + LOOP_START; + _c = c + 3; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + break; + case 5: + x = 0; cy = 0; + LOOP_START; + _c = c + 0; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 1; cy = 0; + LOOP_START; + _c = c + 1; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 2; cy = 0; + LOOP_START; + _c = c + 2; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 3; cy = 0; + LOOP_START; + _c = c + 3; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 4; cy = 0; + LOOP_START; + _c = c + 4; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + break; + case 6: + x = 0; cy = 0; + LOOP_START; + _c = c + 0; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 1; cy = 0; + LOOP_START; + _c = c + 1; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 2; cy = 0; + LOOP_START; + _c = c + 2; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 3; cy = 0; + LOOP_START; + _c = c + 3; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 4; cy = 0; + LOOP_START; + _c = c + 4; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 5; cy = 0; + LOOP_START; + _c = c + 5; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + break; + case 7: + x = 0; cy = 0; + LOOP_START; + _c = c + 0; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 1; cy = 0; + LOOP_START; + _c = c + 1; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 2; cy = 0; + LOOP_START; + _c = c + 2; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 3; cy = 0; + LOOP_START; + _c = c + 3; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 4; cy = 0; + LOOP_START; + _c = c + 4; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 5; cy = 0; + LOOP_START; + _c = c + 5; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 6; cy = 0; + LOOP_START; + _c = c + 6; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + break; + case 8: + x = 0; cy = 0; + LOOP_START; + _c = c + 0; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL8; _c += 8; tmpm += 8; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 1; cy = 0; + LOOP_START; + _c = c + 1; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL8; _c += 8; tmpm += 8; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 2; cy = 0; + LOOP_START; + _c = c + 2; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL8; _c += 8; tmpm += 8; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 3; cy = 0; + LOOP_START; + _c = c + 3; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL8; _c += 8; tmpm += 8; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 4; cy = 0; + LOOP_START; + _c = c + 4; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL8; _c += 8; tmpm += 8; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 5; cy = 0; + LOOP_START; + _c = c + 5; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL8; _c += 8; tmpm += 8; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 6; cy = 0; + LOOP_START; + _c = c + 6; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL8; _c += 8; tmpm += 8; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 7; cy = 0; + LOOP_START; + _c = c + 7; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL8; _c += 8; tmpm += 8; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + break; + case 9: + x = 0; cy = 0; + LOOP_START; + _c = c + 0; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL8; _c += 8; tmpm += 8; + INNERMUL; ++_c; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 1; cy = 0; + LOOP_START; + _c = c + 1; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL8; _c += 8; tmpm += 8; + INNERMUL; ++_c; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 2; cy = 0; + LOOP_START; + _c = c + 2; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL8; _c += 8; tmpm += 8; + INNERMUL; ++_c; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 3; cy = 0; + LOOP_START; + _c = c + 3; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL8; _c += 8; tmpm += 8; + INNERMUL; ++_c; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 4; cy = 0; + LOOP_START; + _c = c + 4; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL8; _c += 8; tmpm += 8; + INNERMUL; ++_c; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 5; cy = 0; + LOOP_START; + _c = c + 5; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL8; _c += 8; tmpm += 8; + INNERMUL; ++_c; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 6; cy = 0; + LOOP_START; + _c = c + 6; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL8; _c += 8; tmpm += 8; + INNERMUL; ++_c; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 7; cy = 0; + LOOP_START; + _c = c + 7; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL8; _c += 8; tmpm += 8; + INNERMUL; ++_c; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 8; cy = 0; + LOOP_START; + _c = c + 8; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL8; _c += 8; tmpm += 8; + INNERMUL; ++_c; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + break; + case 10: + x = 0; cy = 0; + LOOP_START; + _c = c + 0; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL8; _c += 8; tmpm += 8; + INNERMUL; ++_c; + INNERMUL; ++_c; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 1; cy = 0; + LOOP_START; + _c = c + 1; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL8; _c += 8; tmpm += 8; + INNERMUL; ++_c; + INNERMUL; ++_c; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 2; cy = 0; + LOOP_START; + _c = c + 2; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL8; _c += 8; tmpm += 8; + INNERMUL; ++_c; + INNERMUL; ++_c; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 3; cy = 0; + LOOP_START; + _c = c + 3; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL8; _c += 8; tmpm += 8; + INNERMUL; ++_c; + INNERMUL; ++_c; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 4; cy = 0; + LOOP_START; + _c = c + 4; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL8; _c += 8; tmpm += 8; + INNERMUL; ++_c; + INNERMUL; ++_c; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 5; cy = 0; + LOOP_START; + _c = c + 5; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL8; _c += 8; tmpm += 8; + INNERMUL; ++_c; + INNERMUL; ++_c; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 6; cy = 0; + LOOP_START; + _c = c + 6; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL8; _c += 8; tmpm += 8; + INNERMUL; ++_c; + INNERMUL; ++_c; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 7; cy = 0; + LOOP_START; + _c = c + 7; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL8; _c += 8; tmpm += 8; + INNERMUL; ++_c; + INNERMUL; ++_c; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 8; cy = 0; + LOOP_START; + _c = c + 8; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL8; _c += 8; tmpm += 8; + INNERMUL; ++_c; + INNERMUL; ++_c; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 9; cy = 0; + LOOP_START; + _c = c + 9; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL8; _c += 8; tmpm += 8; + INNERMUL; ++_c; + INNERMUL; ++_c; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + break; + case 11: + x = 0; cy = 0; + LOOP_START; + _c = c + 0; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL8; _c += 8; tmpm += 8; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 1; cy = 0; + LOOP_START; + _c = c + 1; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL8; _c += 8; tmpm += 8; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 2; cy = 0; + LOOP_START; + _c = c + 2; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL8; _c += 8; tmpm += 8; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 3; cy = 0; + LOOP_START; + _c = c + 3; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL8; _c += 8; tmpm += 8; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 4; cy = 0; + LOOP_START; + _c = c + 4; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL8; _c += 8; tmpm += 8; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 5; cy = 0; + LOOP_START; + _c = c + 5; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL8; _c += 8; tmpm += 8; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 6; cy = 0; + LOOP_START; + _c = c + 6; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL8; _c += 8; tmpm += 8; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 7; cy = 0; + LOOP_START; + _c = c + 7; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL8; _c += 8; tmpm += 8; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 8; cy = 0; + LOOP_START; + _c = c + 8; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL8; _c += 8; tmpm += 8; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 9; cy = 0; + LOOP_START; + _c = c + 9; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL8; _c += 8; tmpm += 8; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 10; cy = 0; + LOOP_START; + _c = c + 10; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL8; _c += 8; tmpm += 8; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + break; + case 12: + x = 0; cy = 0; + LOOP_START; + _c = c + 0; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL8; _c += 8; tmpm += 8; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 1; cy = 0; + LOOP_START; + _c = c + 1; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL8; _c += 8; tmpm += 8; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 2; cy = 0; + LOOP_START; + _c = c + 2; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL8; _c += 8; tmpm += 8; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 3; cy = 0; + LOOP_START; + _c = c + 3; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL8; _c += 8; tmpm += 8; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 4; cy = 0; + LOOP_START; + _c = c + 4; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL8; _c += 8; tmpm += 8; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 5; cy = 0; + LOOP_START; + _c = c + 5; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL8; _c += 8; tmpm += 8; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 6; cy = 0; + LOOP_START; + _c = c + 6; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL8; _c += 8; tmpm += 8; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 7; cy = 0; + LOOP_START; + _c = c + 7; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL8; _c += 8; tmpm += 8; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 8; cy = 0; + LOOP_START; + _c = c + 8; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL8; _c += 8; tmpm += 8; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 9; cy = 0; + LOOP_START; + _c = c + 9; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL8; _c += 8; tmpm += 8; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 10; cy = 0; + LOOP_START; + _c = c + 10; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL8; _c += 8; tmpm += 8; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 11; cy = 0; + LOOP_START; + _c = c + 11; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL8; _c += 8; tmpm += 8; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + break; + case 13: + x = 0; cy = 0; + LOOP_START; + _c = c + 0; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL8; _c += 8; tmpm += 8; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 1; cy = 0; + LOOP_START; + _c = c + 1; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL8; _c += 8; tmpm += 8; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 2; cy = 0; + LOOP_START; + _c = c + 2; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL8; _c += 8; tmpm += 8; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 3; cy = 0; + LOOP_START; + _c = c + 3; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL8; _c += 8; tmpm += 8; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 4; cy = 0; + LOOP_START; + _c = c + 4; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL8; _c += 8; tmpm += 8; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 5; cy = 0; + LOOP_START; + _c = c + 5; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL8; _c += 8; tmpm += 8; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 6; cy = 0; + LOOP_START; + _c = c + 6; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL8; _c += 8; tmpm += 8; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 7; cy = 0; + LOOP_START; + _c = c + 7; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL8; _c += 8; tmpm += 8; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 8; cy = 0; + LOOP_START; + _c = c + 8; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL8; _c += 8; tmpm += 8; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 9; cy = 0; + LOOP_START; + _c = c + 9; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL8; _c += 8; tmpm += 8; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 10; cy = 0; + LOOP_START; + _c = c + 10; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL8; _c += 8; tmpm += 8; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 11; cy = 0; + LOOP_START; + _c = c + 11; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL8; _c += 8; tmpm += 8; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 12; cy = 0; + LOOP_START; + _c = c + 12; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL8; _c += 8; tmpm += 8; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + break; + case 14: + x = 0; cy = 0; + LOOP_START; + _c = c + 0; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL8; _c += 8; tmpm += 8; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 1; cy = 0; + LOOP_START; + _c = c + 1; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL8; _c += 8; tmpm += 8; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 2; cy = 0; + LOOP_START; + _c = c + 2; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL8; _c += 8; tmpm += 8; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 3; cy = 0; + LOOP_START; + _c = c + 3; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL8; _c += 8; tmpm += 8; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 4; cy = 0; + LOOP_START; + _c = c + 4; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL8; _c += 8; tmpm += 8; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 5; cy = 0; + LOOP_START; + _c = c + 5; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL8; _c += 8; tmpm += 8; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 6; cy = 0; + LOOP_START; + _c = c + 6; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL8; _c += 8; tmpm += 8; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 7; cy = 0; + LOOP_START; + _c = c + 7; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL8; _c += 8; tmpm += 8; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 8; cy = 0; + LOOP_START; + _c = c + 8; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL8; _c += 8; tmpm += 8; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 9; cy = 0; + LOOP_START; + _c = c + 9; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL8; _c += 8; tmpm += 8; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 10; cy = 0; + LOOP_START; + _c = c + 10; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL8; _c += 8; tmpm += 8; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 11; cy = 0; + LOOP_START; + _c = c + 11; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL8; _c += 8; tmpm += 8; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 12; cy = 0; + LOOP_START; + _c = c + 12; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL8; _c += 8; tmpm += 8; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 13; cy = 0; + LOOP_START; + _c = c + 13; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL8; _c += 8; tmpm += 8; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + break; + case 15: + x = 0; cy = 0; + LOOP_START; + _c = c + 0; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL8; _c += 8; tmpm += 8; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 1; cy = 0; + LOOP_START; + _c = c + 1; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL8; _c += 8; tmpm += 8; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 2; cy = 0; + LOOP_START; + _c = c + 2; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL8; _c += 8; tmpm += 8; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 3; cy = 0; + LOOP_START; + _c = c + 3; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL8; _c += 8; tmpm += 8; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 4; cy = 0; + LOOP_START; + _c = c + 4; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL8; _c += 8; tmpm += 8; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 5; cy = 0; + LOOP_START; + _c = c + 5; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL8; _c += 8; tmpm += 8; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 6; cy = 0; + LOOP_START; + _c = c + 6; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL8; _c += 8; tmpm += 8; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 7; cy = 0; + LOOP_START; + _c = c + 7; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL8; _c += 8; tmpm += 8; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 8; cy = 0; + LOOP_START; + _c = c + 8; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL8; _c += 8; tmpm += 8; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 9; cy = 0; + LOOP_START; + _c = c + 9; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL8; _c += 8; tmpm += 8; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 10; cy = 0; + LOOP_START; + _c = c + 10; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL8; _c += 8; tmpm += 8; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 11; cy = 0; + LOOP_START; + _c = c + 11; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL8; _c += 8; tmpm += 8; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 12; cy = 0; + LOOP_START; + _c = c + 12; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL8; _c += 8; tmpm += 8; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 13; cy = 0; + LOOP_START; + _c = c + 13; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL8; _c += 8; tmpm += 8; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 14; cy = 0; + LOOP_START; + _c = c + 14; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL8; _c += 8; tmpm += 8; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + break; + case 16: + x = 0; cy = 0; + LOOP_START; + _c = c + 0; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL8; _c += 8; tmpm += 8; + INNERMUL8; _c += 8; tmpm += 8; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 1; cy = 0; + LOOP_START; + _c = c + 1; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL8; _c += 8; tmpm += 8; + INNERMUL8; _c += 8; tmpm += 8; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 2; cy = 0; + LOOP_START; + _c = c + 2; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL8; _c += 8; tmpm += 8; + INNERMUL8; _c += 8; tmpm += 8; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 3; cy = 0; + LOOP_START; + _c = c + 3; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL8; _c += 8; tmpm += 8; + INNERMUL8; _c += 8; tmpm += 8; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 4; cy = 0; + LOOP_START; + _c = c + 4; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL8; _c += 8; tmpm += 8; + INNERMUL8; _c += 8; tmpm += 8; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 5; cy = 0; + LOOP_START; + _c = c + 5; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL8; _c += 8; tmpm += 8; + INNERMUL8; _c += 8; tmpm += 8; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 6; cy = 0; + LOOP_START; + _c = c + 6; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL8; _c += 8; tmpm += 8; + INNERMUL8; _c += 8; tmpm += 8; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 7; cy = 0; + LOOP_START; + _c = c + 7; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL8; _c += 8; tmpm += 8; + INNERMUL8; _c += 8; tmpm += 8; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 8; cy = 0; + LOOP_START; + _c = c + 8; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL8; _c += 8; tmpm += 8; + INNERMUL8; _c += 8; tmpm += 8; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 9; cy = 0; + LOOP_START; + _c = c + 9; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL8; _c += 8; tmpm += 8; + INNERMUL8; _c += 8; tmpm += 8; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 10; cy = 0; + LOOP_START; + _c = c + 10; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL8; _c += 8; tmpm += 8; + INNERMUL8; _c += 8; tmpm += 8; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 11; cy = 0; + LOOP_START; + _c = c + 11; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL8; _c += 8; tmpm += 8; + INNERMUL8; _c += 8; tmpm += 8; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 12; cy = 0; + LOOP_START; + _c = c + 12; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL8; _c += 8; tmpm += 8; + INNERMUL8; _c += 8; tmpm += 8; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 13; cy = 0; + LOOP_START; + _c = c + 13; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL8; _c += 8; tmpm += 8; + INNERMUL8; _c += 8; tmpm += 8; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 14; cy = 0; + LOOP_START; + _c = c + 14; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL8; _c += 8; tmpm += 8; + INNERMUL8; _c += 8; tmpm += 8; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + x = 15; cy = 0; + LOOP_START; + _c = c + 15; + tmpm = m->dp; +#ifdef INNERMUL8 + INNERMUL8; _c += 8; tmpm += 8; + INNERMUL8; _c += 8; tmpm += 8; +#else + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; + INNERMUL; ++_c; +#endif + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + break; + } + /* 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); + } +} + +#endif diff --git a/ctaocrypt/src/fp_mul_comba_12.i b/ctaocrypt/src/fp_mul_comba_12.i new file mode 100644 index 000000000..5ec50b870 --- /dev/null +++ b/ctaocrypt/src/fp_mul_comba_12.i @@ -0,0 +1,108 @@ +#ifdef TFM_MUL12 +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 diff --git a/ctaocrypt/src/fp_mul_comba_17.i b/ctaocrypt/src/fp_mul_comba_17.i new file mode 100644 index 000000000..d324513f0 --- /dev/null +++ b/ctaocrypt/src/fp_mul_comba_17.i @@ -0,0 +1,148 @@ +#ifdef TFM_MUL17 +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 diff --git a/ctaocrypt/src/fp_mul_comba_20.i b/ctaocrypt/src/fp_mul_comba_20.i new file mode 100644 index 000000000..9af6d2c9a --- /dev/null +++ b/ctaocrypt/src/fp_mul_comba_20.i @@ -0,0 +1,172 @@ +#ifdef TFM_MUL20 +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 diff --git a/ctaocrypt/src/fp_mul_comba_24.i b/ctaocrypt/src/fp_mul_comba_24.i new file mode 100644 index 000000000..bb518c0a8 --- /dev/null +++ b/ctaocrypt/src/fp_mul_comba_24.i @@ -0,0 +1,204 @@ +#ifdef TFM_MUL24 +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 diff --git a/ctaocrypt/src/fp_mul_comba_28.i b/ctaocrypt/src/fp_mul_comba_28.i new file mode 100644 index 000000000..be7d776b8 --- /dev/null +++ b/ctaocrypt/src/fp_mul_comba_28.i @@ -0,0 +1,236 @@ +#ifdef TFM_MUL28 +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 diff --git a/ctaocrypt/src/fp_mul_comba_3.i b/ctaocrypt/src/fp_mul_comba_3.i new file mode 100644 index 000000000..7b1675d6a --- /dev/null +++ b/ctaocrypt/src/fp_mul_comba_3.i @@ -0,0 +1,36 @@ +#ifdef TFM_MUL3 +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 diff --git a/ctaocrypt/src/fp_mul_comba_32.i b/ctaocrypt/src/fp_mul_comba_32.i new file mode 100644 index 000000000..f7e722e72 --- /dev/null +++ b/ctaocrypt/src/fp_mul_comba_32.i @@ -0,0 +1,282 @@ +#ifdef TFM_MUL32 +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 diff --git a/ctaocrypt/src/fp_mul_comba_4.i b/ctaocrypt/src/fp_mul_comba_4.i new file mode 100644 index 000000000..f84c15d7c --- /dev/null +++ b/ctaocrypt/src/fp_mul_comba_4.i @@ -0,0 +1,44 @@ +#ifdef TFM_MUL4 +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 diff --git a/ctaocrypt/src/fp_mul_comba_48.i b/ctaocrypt/src/fp_mul_comba_48.i new file mode 100644 index 000000000..ce64bf50a --- /dev/null +++ b/ctaocrypt/src/fp_mul_comba_48.i @@ -0,0 +1,396 @@ +#ifdef TFM_MUL48 +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 diff --git a/ctaocrypt/src/fp_mul_comba_6.i b/ctaocrypt/src/fp_mul_comba_6.i new file mode 100644 index 000000000..2be49a858 --- /dev/null +++ b/ctaocrypt/src/fp_mul_comba_6.i @@ -0,0 +1,60 @@ +#ifdef TFM_MUL6 +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 diff --git a/ctaocrypt/src/fp_mul_comba_64.i b/ctaocrypt/src/fp_mul_comba_64.i new file mode 100644 index 000000000..4eb0b9231 --- /dev/null +++ b/ctaocrypt/src/fp_mul_comba_64.i @@ -0,0 +1,524 @@ +#ifdef TFM_MUL64 +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 diff --git a/ctaocrypt/src/fp_mul_comba_7.i b/ctaocrypt/src/fp_mul_comba_7.i new file mode 100644 index 000000000..15486c5cc --- /dev/null +++ b/ctaocrypt/src/fp_mul_comba_7.i @@ -0,0 +1,68 @@ +#ifdef TFM_MUL7 +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 diff --git a/ctaocrypt/src/fp_mul_comba_8.i b/ctaocrypt/src/fp_mul_comba_8.i new file mode 100644 index 000000000..acd0c6a53 --- /dev/null +++ b/ctaocrypt/src/fp_mul_comba_8.i @@ -0,0 +1,76 @@ +#ifdef TFM_MUL8 +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 diff --git a/ctaocrypt/src/fp_mul_comba_9.i b/ctaocrypt/src/fp_mul_comba_9.i new file mode 100644 index 000000000..902276dfc --- /dev/null +++ b/ctaocrypt/src/fp_mul_comba_9.i @@ -0,0 +1,84 @@ +#ifdef TFM_MUL9 +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 diff --git a/ctaocrypt/src/fp_mul_comba_small_set.i b/ctaocrypt/src/fp_mul_comba_small_set.i new file mode 100644 index 000000000..75c07a66a --- /dev/null +++ b/ctaocrypt/src/fp_mul_comba_small_set.i @@ -0,0 +1,1225 @@ +#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 diff --git a/ctaocrypt/src/fp_sqr_comba_12.i b/ctaocrypt/src/fp_sqr_comba_12.i new file mode 100644 index 000000000..95e82d777 --- /dev/null +++ b/ctaocrypt/src/fp_sqr_comba_12.i @@ -0,0 +1,135 @@ +#ifdef TFM_SQR12 +void fp_sqr_comba12(fp_int *A, fp_int *B) +{ + fp_digit *a, b[24], c0, c1, c2, sc0, sc1, sc2; + + 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 + + diff --git a/ctaocrypt/src/fp_sqr_comba_17.i b/ctaocrypt/src/fp_sqr_comba_17.i new file mode 100644 index 000000000..0084d6c03 --- /dev/null +++ b/ctaocrypt/src/fp_sqr_comba_17.i @@ -0,0 +1,185 @@ +#ifdef TFM_SQR17 +void fp_sqr_comba17(fp_int *A, fp_int *B) +{ + fp_digit *a, b[34], c0, c1, c2, sc0, sc1, sc2; + + 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 + + diff --git a/ctaocrypt/src/fp_sqr_comba_20.i b/ctaocrypt/src/fp_sqr_comba_20.i new file mode 100644 index 000000000..5011ffeb6 --- /dev/null +++ b/ctaocrypt/src/fp_sqr_comba_20.i @@ -0,0 +1,218 @@ +#ifdef TFM_SQR20 +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 + + diff --git a/ctaocrypt/src/fp_sqr_comba_24.i b/ctaocrypt/src/fp_sqr_comba_24.i new file mode 100644 index 000000000..20d484c4e --- /dev/null +++ b/ctaocrypt/src/fp_sqr_comba_24.i @@ -0,0 +1,258 @@ +#ifdef TFM_SQR24 +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 + + diff --git a/ctaocrypt/src/fp_sqr_comba_28.i b/ctaocrypt/src/fp_sqr_comba_28.i new file mode 100644 index 000000000..57f6c60c7 --- /dev/null +++ b/ctaocrypt/src/fp_sqr_comba_28.i @@ -0,0 +1,298 @@ +#ifdef TFM_SQR28 +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 + + diff --git a/ctaocrypt/src/fp_sqr_comba_3.i b/ctaocrypt/src/fp_sqr_comba_3.i new file mode 100644 index 000000000..c776702b6 --- /dev/null +++ b/ctaocrypt/src/fp_sqr_comba_3.i @@ -0,0 +1,45 @@ +#ifdef TFM_SQR3 +void fp_sqr_comba3(fp_int *A, fp_int *B) +{ + fp_digit *a, b[6], c0, c1, c2, sc0, sc1, sc2; + + 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 + + diff --git a/ctaocrypt/src/fp_sqr_comba_32.i b/ctaocrypt/src/fp_sqr_comba_32.i new file mode 100644 index 000000000..baaee43bd --- /dev/null +++ b/ctaocrypt/src/fp_sqr_comba_32.i @@ -0,0 +1,338 @@ +#ifdef TFM_SQR32 +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 + + diff --git a/ctaocrypt/src/fp_sqr_comba_4.i b/ctaocrypt/src/fp_sqr_comba_4.i new file mode 100644 index 000000000..dcf1b705b --- /dev/null +++ b/ctaocrypt/src/fp_sqr_comba_4.i @@ -0,0 +1,55 @@ +#ifdef TFM_SQR4 +void fp_sqr_comba4(fp_int *A, fp_int *B) +{ + fp_digit *a, b[8], c0, c1, c2, sc0, sc1, sc2; + + 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 + + diff --git a/ctaocrypt/src/fp_sqr_comba_48.i b/ctaocrypt/src/fp_sqr_comba_48.i new file mode 100644 index 000000000..26fbd46fc --- /dev/null +++ b/ctaocrypt/src/fp_sqr_comba_48.i @@ -0,0 +1,498 @@ +#ifdef TFM_SQR48 +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 + + diff --git a/ctaocrypt/src/fp_sqr_comba_6.i b/ctaocrypt/src/fp_sqr_comba_6.i new file mode 100644 index 000000000..011678078 --- /dev/null +++ b/ctaocrypt/src/fp_sqr_comba_6.i @@ -0,0 +1,75 @@ +#ifdef TFM_SQR6 +void fp_sqr_comba6(fp_int *A, fp_int *B) +{ + fp_digit *a, b[12], c0, c1, c2, sc0, sc1, sc2; + + 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 + + diff --git a/ctaocrypt/src/fp_sqr_comba_64.i b/ctaocrypt/src/fp_sqr_comba_64.i new file mode 100644 index 000000000..68beed1a9 --- /dev/null +++ b/ctaocrypt/src/fp_sqr_comba_64.i @@ -0,0 +1,658 @@ +#ifdef TFM_SQR64 +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 + + diff --git a/ctaocrypt/src/fp_sqr_comba_7.i b/ctaocrypt/src/fp_sqr_comba_7.i new file mode 100644 index 000000000..9774991bf --- /dev/null +++ b/ctaocrypt/src/fp_sqr_comba_7.i @@ -0,0 +1,85 @@ +#ifdef TFM_SQR7 +void fp_sqr_comba7(fp_int *A, fp_int *B) +{ + fp_digit *a, b[14], c0, c1, c2, sc0, sc1, sc2; + + 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 + + diff --git a/ctaocrypt/src/fp_sqr_comba_8.i b/ctaocrypt/src/fp_sqr_comba_8.i new file mode 100644 index 000000000..e9d003b07 --- /dev/null +++ b/ctaocrypt/src/fp_sqr_comba_8.i @@ -0,0 +1,95 @@ +#ifdef TFM_SQR8 +void fp_sqr_comba8(fp_int *A, fp_int *B) +{ + fp_digit *a, b[16], c0, c1, c2, sc0, sc1, sc2; + + 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 + + diff --git a/ctaocrypt/src/fp_sqr_comba_9.i b/ctaocrypt/src/fp_sqr_comba_9.i new file mode 100644 index 000000000..531a32526 --- /dev/null +++ b/ctaocrypt/src/fp_sqr_comba_9.i @@ -0,0 +1,105 @@ +#ifdef TFM_SQR9 +void fp_sqr_comba9(fp_int *A, fp_int *B) +{ + fp_digit *a, b[18], c0, c1, c2, sc0, sc1, sc2; + + 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 + + diff --git a/ctaocrypt/src/fp_sqr_comba_small_set.i b/ctaocrypt/src/fp_sqr_comba_small_set.i new file mode 100644 index 000000000..29c3d1dd0 --- /dev/null +++ b/ctaocrypt/src/fp_sqr_comba_small_set.i @@ -0,0 +1,1515 @@ +#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 */ diff --git a/ctaocrypt/src/hc128.c b/ctaocrypt/src/hc128.c new file mode 100644 index 000000000..1ecb8f003 --- /dev/null +++ b/ctaocrypt/src/hc128.c @@ -0,0 +1,317 @@ +/* hc128.c + * + * Copyright (C) 2006-2011 Sawtooth Consulting Ltd. + * + * This file is part of CyaSSL. + * + * CyaSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * CyaSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + + +#ifndef NO_HC128 + +#include "hc128.h" +#include "misc.c" + + +#ifdef BIG_ENDIAN_ORDER + #define LITTLE32(x) ByteReverseWord32(x) +#else + #define LITTLE32(x) (x) +#endif + + +/*h1 function*/ +#define h1(ctx, x, y) { \ + byte a,c; \ + a = (byte) (x); \ + c = (byte) ((x) >> 16); \ + y = (ctx->T[512+a])+(ctx->T[512+256+c]); \ +} + +/*h2 function*/ +#define h2(ctx, x, y) { \ + byte a,c; \ + a = (byte) (x); \ + c = (byte) ((x) >> 16); \ + y = (ctx->T[a])+(ctx->T[256+c]); \ +} + +/*one step of HC-128, update P and generate 32 bits keystream*/ +#define step_P(ctx,u,v,a,b,c,d,n){ \ + word32 tem0,tem1,tem2,tem3; \ + h1((ctx),(ctx->X[(d)]),tem3); \ + tem0 = rotrFixed((ctx->T[(v)]),23); \ + tem1 = rotrFixed((ctx->X[(c)]),10); \ + tem2 = rotrFixed((ctx->X[(b)]),8); \ + (ctx->T[(u)]) += tem2+(tem0 ^ tem1); \ + (ctx->X[(a)]) = (ctx->T[(u)]); \ + (n) = tem3 ^ (ctx->T[(u)]) ; \ +} + +/*one step of HC-128, update Q and generate 32 bits keystream*/ +#define step_Q(ctx,u,v,a,b,c,d,n){ \ + word32 tem0,tem1,tem2,tem3; \ + h2((ctx),(ctx->Y[(d)]),tem3); \ + tem0 = rotrFixed((ctx->T[(v)]),(32-23)); \ + tem1 = rotrFixed((ctx->Y[(c)]),(32-10)); \ + tem2 = rotrFixed((ctx->Y[(b)]),(32-8)); \ + (ctx->T[(u)]) += tem2 + (tem0 ^ tem1); \ + (ctx->Y[(a)]) = (ctx->T[(u)]); \ + (n) = tem3 ^ (ctx->T[(u)]) ; \ +} + +/*16 steps of HC-128, generate 512 bits keystream*/ +static void generate_keystream(HC128* ctx, word32* keystream) +{ + word32 cc,dd; + cc = ctx->counter1024 & 0x1ff; + dd = (cc+16)&0x1ff; + + if (ctx->counter1024 < 512) + { + ctx->counter1024 = (ctx->counter1024 + 16) & 0x3ff; + step_P(ctx, cc+0, cc+1, 0, 6, 13,4, keystream[0]); + step_P(ctx, cc+1, cc+2, 1, 7, 14,5, keystream[1]); + step_P(ctx, cc+2, cc+3, 2, 8, 15,6, keystream[2]); + step_P(ctx, cc+3, cc+4, 3, 9, 0, 7, keystream[3]); + step_P(ctx, cc+4, cc+5, 4, 10,1, 8, keystream[4]); + step_P(ctx, cc+5, cc+6, 5, 11,2, 9, keystream[5]); + step_P(ctx, cc+6, cc+7, 6, 12,3, 10,keystream[6]); + step_P(ctx, cc+7, cc+8, 7, 13,4, 11,keystream[7]); + step_P(ctx, cc+8, cc+9, 8, 14,5, 12,keystream[8]); + step_P(ctx, cc+9, cc+10,9, 15,6, 13,keystream[9]); + step_P(ctx, cc+10,cc+11,10,0, 7, 14,keystream[10]); + step_P(ctx, cc+11,cc+12,11,1, 8, 15,keystream[11]); + step_P(ctx, cc+12,cc+13,12,2, 9, 0, keystream[12]); + step_P(ctx, cc+13,cc+14,13,3, 10,1, keystream[13]); + step_P(ctx, cc+14,cc+15,14,4, 11,2, keystream[14]); + step_P(ctx, cc+15,dd+0, 15,5, 12,3, keystream[15]); + } + else + { + ctx->counter1024 = (ctx->counter1024 + 16) & 0x3ff; + step_Q(ctx, 512+cc+0, 512+cc+1, 0, 6, 13,4, keystream[0]); + step_Q(ctx, 512+cc+1, 512+cc+2, 1, 7, 14,5, keystream[1]); + step_Q(ctx, 512+cc+2, 512+cc+3, 2, 8, 15,6, keystream[2]); + step_Q(ctx, 512+cc+3, 512+cc+4, 3, 9, 0, 7, keystream[3]); + step_Q(ctx, 512+cc+4, 512+cc+5, 4, 10,1, 8, keystream[4]); + step_Q(ctx, 512+cc+5, 512+cc+6, 5, 11,2, 9, keystream[5]); + step_Q(ctx, 512+cc+6, 512+cc+7, 6, 12,3, 10,keystream[6]); + step_Q(ctx, 512+cc+7, 512+cc+8, 7, 13,4, 11,keystream[7]); + step_Q(ctx, 512+cc+8, 512+cc+9, 8, 14,5, 12,keystream[8]); + step_Q(ctx, 512+cc+9, 512+cc+10,9, 15,6, 13,keystream[9]); + step_Q(ctx, 512+cc+10,512+cc+11,10,0, 7, 14,keystream[10]); + step_Q(ctx, 512+cc+11,512+cc+12,11,1, 8, 15,keystream[11]); + step_Q(ctx, 512+cc+12,512+cc+13,12,2, 9, 0, keystream[12]); + step_Q(ctx, 512+cc+13,512+cc+14,13,3, 10,1, keystream[13]); + step_Q(ctx, 512+cc+14,512+cc+15,14,4, 11,2, keystream[14]); + step_Q(ctx, 512+cc+15,512+dd+0, 15,5, 12,3, keystream[15]); + } +} + + +/* The following defines the initialization functions */ +#define f1(x) (rotrFixed((x),7) ^ rotrFixed((x),18) ^ ((x) >> 3)) +#define f2(x) (rotrFixed((x),17) ^ rotrFixed((x),19) ^ ((x) >> 10)) + +/*update table P*/ +#define update_P(ctx,u,v,a,b,c,d){ \ + word32 tem0,tem1,tem2,tem3; \ + tem0 = rotrFixed((ctx->T[(v)]),23); \ + tem1 = rotrFixed((ctx->X[(c)]),10); \ + tem2 = rotrFixed((ctx->X[(b)]),8); \ + h1((ctx),(ctx->X[(d)]),tem3); \ + (ctx->T[(u)]) = ((ctx->T[(u)]) + tem2+(tem0^tem1)) ^ tem3; \ + (ctx->X[(a)]) = (ctx->T[(u)]); \ +} + +/*update table Q*/ +#define update_Q(ctx,u,v,a,b,c,d){ \ + word32 tem0,tem1,tem2,tem3; \ + tem0 = rotrFixed((ctx->T[(v)]),(32-23)); \ + tem1 = rotrFixed((ctx->Y[(c)]),(32-10)); \ + tem2 = rotrFixed((ctx->Y[(b)]),(32-8)); \ + h2((ctx),(ctx->Y[(d)]),tem3); \ + (ctx->T[(u)]) = ((ctx->T[(u)]) + tem2+(tem0^tem1)) ^ tem3; \ + (ctx->Y[(a)]) = (ctx->T[(u)]); \ +} + +/*16 steps of HC-128, without generating keystream, */ +/*but use the outputs to update P and Q*/ +static void setup_update(HC128* ctx) /*each time 16 steps*/ +{ + word32 cc,dd; + cc = ctx->counter1024 & 0x1ff; + dd = (cc+16)&0x1ff; + + if (ctx->counter1024 < 512) + { + ctx->counter1024 = (ctx->counter1024 + 16) & 0x3ff; + update_P(ctx, cc+0, cc+1, 0, 6, 13, 4); + update_P(ctx, cc+1, cc+2, 1, 7, 14, 5); + update_P(ctx, cc+2, cc+3, 2, 8, 15, 6); + update_P(ctx, cc+3, cc+4, 3, 9, 0, 7); + update_P(ctx, cc+4, cc+5, 4, 10,1, 8); + update_P(ctx, cc+5, cc+6, 5, 11,2, 9); + update_P(ctx, cc+6, cc+7, 6, 12,3, 10); + update_P(ctx, cc+7, cc+8, 7, 13,4, 11); + update_P(ctx, cc+8, cc+9, 8, 14,5, 12); + update_P(ctx, cc+9, cc+10,9, 15,6, 13); + update_P(ctx, cc+10,cc+11,10,0, 7, 14); + update_P(ctx, cc+11,cc+12,11,1, 8, 15); + update_P(ctx, cc+12,cc+13,12,2, 9, 0); + update_P(ctx, cc+13,cc+14,13,3, 10, 1); + update_P(ctx, cc+14,cc+15,14,4, 11, 2); + update_P(ctx, cc+15,dd+0, 15,5, 12, 3); + } + else + { + ctx->counter1024 = (ctx->counter1024 + 16) & 0x3ff; + update_Q(ctx, 512+cc+0, 512+cc+1, 0, 6, 13, 4); + update_Q(ctx, 512+cc+1, 512+cc+2, 1, 7, 14, 5); + update_Q(ctx, 512+cc+2, 512+cc+3, 2, 8, 15, 6); + update_Q(ctx, 512+cc+3, 512+cc+4, 3, 9, 0, 7); + update_Q(ctx, 512+cc+4, 512+cc+5, 4, 10,1, 8); + update_Q(ctx, 512+cc+5, 512+cc+6, 5, 11,2, 9); + update_Q(ctx, 512+cc+6, 512+cc+7, 6, 12,3, 10); + update_Q(ctx, 512+cc+7, 512+cc+8, 7, 13,4, 11); + update_Q(ctx, 512+cc+8, 512+cc+9, 8, 14,5, 12); + update_Q(ctx, 512+cc+9, 512+cc+10,9, 15,6, 13); + update_Q(ctx, 512+cc+10,512+cc+11,10,0, 7, 14); + update_Q(ctx, 512+cc+11,512+cc+12,11,1, 8, 15); + update_Q(ctx, 512+cc+12,512+cc+13,12,2, 9, 0); + update_Q(ctx, 512+cc+13,512+cc+14,13,3, 10, 1); + update_Q(ctx, 512+cc+14,512+cc+15,14,4, 11, 2); + update_Q(ctx, 512+cc+15,512+dd+0, 15,5, 12, 3); + } +} + + +/* for the 128-bit key: key[0]...key[15] +* key[0] is the least significant byte of ctx->key[0] (K_0); +* key[3] is the most significant byte of ctx->key[0] (K_0); +* ... +* key[12] is the least significant byte of ctx->key[3] (K_3) +* key[15] is the most significant byte of ctx->key[3] (K_3) +* +* for the 128-bit iv: iv[0]...iv[15] +* iv[0] is the least significant byte of ctx->iv[0] (IV_0); +* iv[3] is the most significant byte of ctx->iv[0] (IV_0); +* ... +* iv[12] is the least significant byte of ctx->iv[3] (IV_3) +* iv[15] is the most significant byte of ctx->iv[3] (IV_3) +*/ + + + +static void Hc128_SetIV(HC128* ctx, const byte* iv) +{ + word32 i; + + for (i = 0; i < (128 >> 5); i++) + ctx->iv[i] = LITTLE32(((word32*)iv)[i]); + + for (; i < 8; i++) ctx->iv[i] = ctx->iv[i-4]; + + /* expand the key and IV into the table T */ + /* (expand the key and IV into the table P and Q) */ + + for (i = 0; i < 8; i++) ctx->T[i] = ctx->key[i]; + for (i = 8; i < 16; i++) ctx->T[i] = ctx->iv[i-8]; + + for (i = 16; i < (256+16); i++) + ctx->T[i] = f2(ctx->T[i-2]) + ctx->T[i-7] + f1(ctx->T[i-15]) + + ctx->T[i-16]+i; + + for (i = 0; i < 16; i++) ctx->T[i] = ctx->T[256+i]; + + for (i = 16; i < 1024; i++) + ctx->T[i] = f2(ctx->T[i-2]) + ctx->T[i-7] + f1(ctx->T[i-15]) + + ctx->T[i-16]+256+i; + + /* initialize counter1024, X and Y */ + ctx->counter1024 = 0; + for (i = 0; i < 16; i++) ctx->X[i] = ctx->T[512-16+i]; + for (i = 0; i < 16; i++) ctx->Y[i] = ctx->T[512+512-16+i]; + + /* run the cipher 1024 steps before generating the output */ + for (i = 0; i < 64; i++) setup_update(ctx); +} + + +void Hc128_SetKey(HC128* ctx, const byte* key, const byte* iv) +{ + word32 i; + + /* Key size in bits 128 */ + for (i = 0; i < (128 >> 5); i++) + ctx->key[i] = LITTLE32(((word32*)key)[i]); + + for ( ; i < 8 ; i++) ctx->key[i] = ctx->key[i-4]; + + Hc128_SetIV(ctx, iv); +} + + +/* The following defines the encryption of data stream */ +void Hc128_Process(HC128* ctx, byte* output, const byte* input, word32 msglen) +{ + word32 i, keystream[16]; + + for ( ; msglen >= 64; msglen -= 64, input += 64, output += 64) + { + generate_keystream(ctx, keystream); + + /* unroll loop */ + ((word32*)output)[0] = ((word32*)input)[0] ^ LITTLE32(keystream[0]); + ((word32*)output)[1] = ((word32*)input)[1] ^ LITTLE32(keystream[1]); + ((word32*)output)[2] = ((word32*)input)[2] ^ LITTLE32(keystream[2]); + ((word32*)output)[3] = ((word32*)input)[3] ^ LITTLE32(keystream[3]); + ((word32*)output)[4] = ((word32*)input)[4] ^ LITTLE32(keystream[4]); + ((word32*)output)[5] = ((word32*)input)[5] ^ LITTLE32(keystream[5]); + ((word32*)output)[6] = ((word32*)input)[6] ^ LITTLE32(keystream[6]); + ((word32*)output)[7] = ((word32*)input)[7] ^ LITTLE32(keystream[7]); + ((word32*)output)[8] = ((word32*)input)[8] ^ LITTLE32(keystream[8]); + ((word32*)output)[9] = ((word32*)input)[9] ^ LITTLE32(keystream[9]); + ((word32*)output)[10] = ((word32*)input)[10] ^ LITTLE32(keystream[10]); + ((word32*)output)[11] = ((word32*)input)[11] ^ LITTLE32(keystream[11]); + ((word32*)output)[12] = ((word32*)input)[12] ^ LITTLE32(keystream[12]); + ((word32*)output)[13] = ((word32*)input)[13] ^ LITTLE32(keystream[13]); + ((word32*)output)[14] = ((word32*)input)[14] ^ LITTLE32(keystream[14]); + ((word32*)output)[15] = ((word32*)input)[15] ^ LITTLE32(keystream[15]); + } + + if (msglen > 0) + { + generate_keystream(ctx, keystream); + +#ifdef BIG_ENDIAN_ORDER + { + word32 wordsLeft = msglen / sizeof(word32); + if (msglen % sizeof(word32)) wordsLeft++; + + ByteReverseWords(keystream, keystream, wordsLeft * sizeof(word32)); + } +#endif + + for (i = 0; i < msglen; i++) + output[i] = input[i] ^ ((byte*)keystream)[i]; + } + +} + + +#endif /* NO_HC128 */ diff --git a/ctaocrypt/src/hmac.c b/ctaocrypt/src/hmac.c new file mode 100644 index 000000000..abeacb2f4 --- /dev/null +++ b/ctaocrypt/src/hmac.c @@ -0,0 +1,158 @@ +/* hmac.c + * + * Copyright (C) 2006-2011 Sawtooth Consulting Ltd. + * + * This file is part of CyaSSL. + * + * CyaSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * CyaSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + + +#ifndef NO_HMAC + +#include "ctc_hmac.h" + + + +static int InitHmac(Hmac* hmac, int type) +{ + hmac->innerHashKeyed = 0; + hmac->macType = type; + + if (!(type == MD5 || type == SHA || type == SHA256)) + return -1; + + if (type == MD5) + InitMd5(&hmac->hash.md5); + else if (type == SHA) + InitSha(&hmac->hash.sha); +#ifndef NO_SHA256 + else if (type == SHA256) + InitSha256(&hmac->hash.sha256); +#endif + + return 0; +} + + +void HmacSetKey(Hmac* hmac, int type, const byte* key, word32 length) +{ + byte* ip = (byte*) hmac->ipad; + byte* op = (byte*) hmac->opad; + word32 i; + + InitHmac(hmac, type); + + if (length <= HMAC_BLOCK_SIZE) + XMEMCPY(ip, key, length); + else { + if (hmac->macType == MD5) { + Md5Update(&hmac->hash.md5, key, length); + Md5Final(&hmac->hash.md5, ip); + length = MD5_DIGEST_SIZE; + } + else if (hmac->macType == SHA) { + ShaUpdate(&hmac->hash.sha, key, length); + ShaFinal(&hmac->hash.sha, ip); + length = SHA_DIGEST_SIZE; + } +#ifndef NO_SHA256 + else if (hmac->macType == SHA256) { + Sha256Update(&hmac->hash.sha256, key, length); + Sha256Final(&hmac->hash.sha256, ip); + length = SHA256_DIGEST_SIZE; + } +#endif + } + XMEMSET(ip + length, 0, HMAC_BLOCK_SIZE - length); + + for(i = 0; i < HMAC_BLOCK_SIZE; i++) { + op[i] = ip[i] ^ OPAD; + ip[i] ^= IPAD; + } +} + + +static void HmacKeyInnerHash(Hmac* hmac) +{ + if (hmac->macType == MD5) + Md5Update(&hmac->hash.md5, (byte*) hmac->ipad, HMAC_BLOCK_SIZE); + else if (hmac->macType == SHA) + ShaUpdate(&hmac->hash.sha, (byte*) hmac->ipad, HMAC_BLOCK_SIZE); +#ifndef NO_SHA256 + else if (hmac->macType == SHA256) + Sha256Update(&hmac->hash.sha256, (byte*) hmac->ipad, HMAC_BLOCK_SIZE); +#endif + + hmac->innerHashKeyed = 1; +} + + +void HmacUpdate(Hmac* hmac, const byte* msg, word32 length) +{ + if (!hmac->innerHashKeyed) + HmacKeyInnerHash(hmac); + + if (hmac->macType == MD5) + Md5Update(&hmac->hash.md5, msg, length); + else if (hmac->macType == SHA) + ShaUpdate(&hmac->hash.sha, msg, length); +#ifndef NO_SHA256 + else if (hmac->macType == SHA256) + Sha256Update(&hmac->hash.sha256, msg, length); +#endif + +} + + +void HmacFinal(Hmac* hmac, byte* hash) +{ + if (!hmac->innerHashKeyed) + HmacKeyInnerHash(hmac); + + if (hmac->macType == MD5) { + Md5Final(&hmac->hash.md5, (byte*) hmac->innerHash); + + Md5Update(&hmac->hash.md5, (byte*) hmac->opad, HMAC_BLOCK_SIZE); + Md5Update(&hmac->hash.md5, (byte*) hmac->innerHash, MD5_DIGEST_SIZE); + + Md5Final(&hmac->hash.md5, hash); + } + else if (hmac->macType ==SHA) { + ShaFinal(&hmac->hash.sha, (byte*) hmac->innerHash); + + ShaUpdate(&hmac->hash.sha, (byte*) hmac->opad, HMAC_BLOCK_SIZE); + ShaUpdate(&hmac->hash.sha, (byte*) hmac->innerHash, SHA_DIGEST_SIZE); + + ShaFinal(&hmac->hash.sha, hash); + } +#ifndef NO_SHA256 + else if (hmac->macType ==SHA256) { + Sha256Final(&hmac->hash.sha256, (byte*) hmac->innerHash); + + Sha256Update(&hmac->hash.sha256, (byte*) hmac->opad, HMAC_BLOCK_SIZE); + Sha256Update(&hmac->hash.sha256, (byte*) hmac->innerHash, + SHA256_DIGEST_SIZE); + + Sha256Final(&hmac->hash.sha256, hash); + } +#endif + + hmac->innerHashKeyed = 0; +} + + +#endif /* NO_HMAC */ + diff --git a/ctaocrypt/src/integer.c b/ctaocrypt/src/integer.c new file mode 100644 index 000000000..699fe1040 --- /dev/null +++ b/ctaocrypt/src/integer.c @@ -0,0 +1,4357 @@ +/* integer.c + * + * Copyright (C) 2006-2011 Sawtooth Consulting Ltd. + * + * This file is part of CyaSSL. + * + * CyaSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * CyaSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +/* + * Based on public domain LibTomMath 0.38 by Tom St Denis, tomstdenis@iahu.ca, + * http://math.libtomcrypt.com + */ + + +#ifndef USE_FAST_MATH + +#include "integer.h" + + +/* handle up to 6 inits */ +int mp_init_multi(mp_int* a, mp_int* b, mp_int* c, mp_int* d, mp_int* e, + mp_int* f) +{ + int res = MP_OKAY; + + if (a && ((res = mp_init(a)) != MP_OKAY)) + return res; + + if (b && ((res = mp_init(b)) != MP_OKAY)) { + mp_clear(a); + return res; + } + + if (c && ((res = mp_init(c)) != MP_OKAY)) { + mp_clear(a); mp_clear(b); + return res; + } + + if (d && ((res = mp_init(d)) != MP_OKAY)) { + mp_clear(a); mp_clear(b); mp_clear(c); + return res; + } + + if (e && ((res = mp_init(e)) != MP_OKAY)) { + mp_clear(a); mp_clear(b); mp_clear(c); mp_clear(d); + return res; + } + + if (f && ((res = mp_init(f)) != MP_OKAY)) { + mp_clear(a); mp_clear(b); mp_clear(c); mp_clear(d); mp_clear(e); + return res; + } + + return res; +} + + +/* init a new mp_int */ +int mp_init (mp_int * a) +{ + int i; + + /* allocate memory required and clear it */ + a->dp = OPT_CAST(mp_digit) XMALLOC (sizeof (mp_digit) * MP_PREC, 0, + DYNAMIC_TYPE_BIGINT); + if (a->dp == NULL) { + return MP_MEM; + } + + /* set the digits to zero */ + for (i = 0; i < MP_PREC; i++) { + a->dp[i] = 0; + } + + /* set the used to zero, allocated digits to the default precision + * and sign to positive */ + a->used = 0; + a->alloc = MP_PREC; + a->sign = MP_ZPOS; + + return MP_OKAY; +} + + +/* clear one (frees) */ +void +mp_clear (mp_int * a) +{ + int i; + + /* only do anything if a hasn't been freed previously */ + if (a->dp != NULL) { + /* first zero the digits */ + for (i = 0; i < a->used; i++) { + a->dp[i] = 0; + } + + /* free ram */ + XFREE(a->dp, 0, DYNAMIC_TYPE_BIGINT); + + /* reset members to make debugging easier */ + a->dp = NULL; + a->alloc = a->used = 0; + a->sign = MP_ZPOS; + } +} + + +/* get the size for an unsigned equivalent */ +int mp_unsigned_bin_size (mp_int * a) +{ + int size = mp_count_bits (a); + return (size / 8 + ((size & 7) != 0 ? 1 : 0)); +} + + +/* returns the number of bits in an int */ +int +mp_count_bits (mp_int * a) +{ + int r; + mp_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 > ((mp_digit) 0)) { + ++r; + q >>= ((mp_digit) 1); + } + return r; +} + + +/* store in unsigned [big endian] format */ +int mp_to_unsigned_bin (mp_int * a, unsigned char *b) +{ + int x, res; + mp_int t; + + if ((res = mp_init_copy (&t, a)) != MP_OKAY) { + return res; + } + + x = 0; + while (mp_iszero (&t) == 0) { +#ifndef MP_8BIT + b[x++] = (unsigned char) (t.dp[0] & 255); +#else + b[x++] = (unsigned char) (t.dp[0] | ((t.dp[1] & 0x01) << 7)); +#endif + if ((res = mp_div_2d (&t, 8, &t, NULL)) != MP_OKAY) { + mp_clear (&t); + return res; + } + } + bn_reverse (b, x); + mp_clear (&t); + return MP_OKAY; +} + + +/* creates "a" then copies b into it */ +int mp_init_copy (mp_int * a, mp_int * b) +{ + int res; + + if ((res = mp_init (a)) != MP_OKAY) { + return res; + } + return mp_copy (b, a); +} + + +/* copy, b = a */ +int +mp_copy (mp_int * a, mp_int * b) +{ + int res, n; + + /* if dst == src do nothing */ + if (a == b) { + return MP_OKAY; + } + + /* grow dest */ + if (b->alloc < a->used) { + if ((res = mp_grow (b, a->used)) != MP_OKAY) { + return res; + } + } + + /* zero b and copy the parameters over */ + { + register mp_digit *tmpa, *tmpb; + + /* pointer aliases */ + + /* source */ + tmpa = a->dp; + + /* destination */ + tmpb = b->dp; + + /* copy all the digits */ + for (n = 0; n < a->used; n++) { + *tmpb++ = *tmpa++; + } + + /* clear high digits */ + for (; n < b->used; n++) { + *tmpb++ = 0; + } + } + + /* copy used count and sign */ + b->used = a->used; + b->sign = a->sign; + return MP_OKAY; +} + + +/* grow as required */ +int mp_grow (mp_int * a, int size) +{ + int i; + mp_digit *tmp; + + /* if the alloc size is smaller alloc more ram */ + if (a->alloc < size) { + /* ensure there are always at least MP_PREC digits extra on top */ + size += (MP_PREC * 2) - (size % MP_PREC); + + /* reallocate the array a->dp + * + * We store the return in a temporary variable + * in case the operation failed we don't want + * to overwrite the dp member of a. + */ + tmp = OPT_CAST(mp_digit) XREALLOC (a->dp, sizeof (mp_digit) * size, 0, + DYNAMIC_TYPE_BIGINT); + if (tmp == NULL) { + /* reallocation failed but "a" is still valid [can be freed] */ + return MP_MEM; + } + + /* reallocation succeeded so set a->dp */ + a->dp = tmp; + + /* zero excess digits */ + i = a->alloc; + a->alloc = size; + for (; i < a->alloc; i++) { + a->dp[i] = 0; + } + } + return MP_OKAY; +} + + +/* reverse an array, used for radix code */ +void +bn_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; + } +} + + +/* shift right by a certain bit count (store quotient in c, optional + remainder in d) */ +int mp_div_2d (mp_int * a, int b, mp_int * c, mp_int * d) +{ + mp_digit D, r, rr; + int x, res; + mp_int t; + + + /* if the shift count is <= 0 then we do no work */ + if (b <= 0) { + res = mp_copy (a, c); + if (d != NULL) { + mp_zero (d); + } + return res; + } + + if ((res = mp_init (&t)) != MP_OKAY) { + return res; + } + + /* get the remainder */ + if (d != NULL) { + if ((res = mp_mod_2d (a, b, &t)) != MP_OKAY) { + mp_clear (&t); + return res; + } + } + + /* copy */ + if ((res = mp_copy (a, c)) != MP_OKAY) { + mp_clear (&t); + return res; + } + + /* shift by as many digits in the bit count */ + if (b >= (int)DIGIT_BIT) { + mp_rshd (c, b / DIGIT_BIT); + } + + /* shift any bit count < DIGIT_BIT */ + D = (mp_digit) (b % DIGIT_BIT); + if (D != 0) { + register mp_digit *tmpc, mask, shift; + + /* mask */ + mask = (((mp_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; + } + } + mp_clamp (c); + if (d != NULL) { + mp_exch (&t, d); + } + mp_clear (&t); + return MP_OKAY; +} + + +/* set to zero */ +void mp_zero (mp_int * a) +{ + int n; + mp_digit *tmp; + + a->sign = MP_ZPOS; + a->used = 0; + + tmp = a->dp; + for (n = 0; n < a->alloc; n++) { + *tmp++ = 0; + } +} + + +/* trim unused digits + * + * This is used to ensure that leading zero digits are + * trimed and the leading "used" digit will be non-zero + * Typically very fast. Also fixes the sign if there + * are no more leading digits + */ +void +mp_clamp (mp_int * a) +{ + /* decrease used while the most significant digit is + * zero. + */ + while (a->used > 0 && a->dp[a->used - 1] == 0) { + --(a->used); + } + + /* reset the sign flag if used == 0 */ + if (a->used == 0) { + a->sign = MP_ZPOS; + } +} + + +/* swap the elements of two integers, for cases where you can't simply swap the + * mp_int pointers around + */ +void +mp_exch (mp_int * a, mp_int * b) +{ + mp_int t; + + t = *a; + *a = *b; + *b = t; +} + + +/* shift right a certain amount of digits */ +void mp_rshd (mp_int * a, int b) +{ + int x; + + /* if b <= 0 then ignore it */ + if (b <= 0) { + return; + } + + /* if b > used then simply zero it and return */ + if (a->used <= b) { + mp_zero (a); + return; + } + + { + register mp_digit *bottom, *top; + + /* shift the digits down */ + + /* bottom */ + bottom = a->dp; + + /* top [offset into digits] */ + top = a->dp + b; + + /* this is implemented as a sliding window where + * the window is b-digits long and digits from + * the top of the window are copied to the bottom + * + * e.g. + + b-2 | b-1 | b0 | b1 | b2 | ... | bb | ----> + /\ | ----> + \-------------------/ ----> + */ + for (x = 0; x < (a->used - b); x++) { + *bottom++ = *top++; + } + + /* zero the top digits */ + for (; x < a->used; x++) { + *bottom++ = 0; + } + } + + /* remove excess digits */ + a->used -= b; +} + + +/* calc a value mod 2**b */ +int +mp_mod_2d (mp_int * a, int b, mp_int * c) +{ + int x, res; + + /* if b is <= 0 then zero the int */ + if (b <= 0) { + mp_zero (c); + return MP_OKAY; + } + + /* if the modulus is larger than the value than return */ + if (b >= (int) (a->used * DIGIT_BIT)) { + res = mp_copy (a, c); + return res; + } + + /* copy */ + if ((res = mp_copy (a, c)) != MP_OKAY) { + return res; + } + + /* 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] &= (mp_digit) ((((mp_digit) 1) << + (((mp_digit) b) % DIGIT_BIT)) - ((mp_digit) 1)); + mp_clamp (c); + return MP_OKAY; +} + + +/* reads a unsigned char array, assumes the msb is stored first [big endian] */ +int mp_read_unsigned_bin (mp_int * a, const unsigned char *b, int c) +{ + int res; + + /* make sure there are at least two digits */ + if (a->alloc < 2) { + if ((res = mp_grow(a, 2)) != MP_OKAY) { + return res; + } + } + + /* zero the int */ + mp_zero (a); + + /* read the bytes in */ + while (c-- > 0) { + if ((res = mp_mul_2d (a, 8, a)) != MP_OKAY) { + return res; + } + +#ifndef MP_8BIT + a->dp[0] |= *b++; + a->used += 1; +#else + a->dp[0] = (*b & MP_MASK); + a->dp[1] |= ((*b++ >> 7U) & 1); + a->used += 2; +#endif + } + mp_clamp (a); + return MP_OKAY; +} + + +/* shift left by a certain bit count */ +int mp_mul_2d (mp_int * a, int b, mp_int * c) +{ + mp_digit d; + int res; + + /* copy */ + if (a != c) { + if ((res = mp_copy (a, c)) != MP_OKAY) { + return res; + } + } + + if (c->alloc < (int)(c->used + b/DIGIT_BIT + 1)) { + if ((res = mp_grow (c, c->used + b / DIGIT_BIT + 1)) != MP_OKAY) { + return res; + } + } + + /* shift by as many digits in the bit count */ + if (b >= (int)DIGIT_BIT) { + if ((res = mp_lshd (c, b / DIGIT_BIT)) != MP_OKAY) { + return res; + } + } + + /* shift any bit count < DIGIT_BIT */ + d = (mp_digit) (b % DIGIT_BIT); + if (d != 0) { + register mp_digit *tmpc, shift, mask, r, rr; + register int x; + + /* bitmask for carries */ + mask = (((mp_digit)1) << d) - 1; + + /* shift for msbs */ + shift = DIGIT_BIT - d; + + /* alias */ + tmpc = c->dp; + + /* carry */ + r = 0; + for (x = 0; x < c->used; x++) { + /* get the higher bits of the current word */ + rr = (*tmpc >> shift) & mask; + + /* shift the current word and OR in the carry */ + *tmpc = ((*tmpc << d) | r) & MP_MASK; + ++tmpc; + + /* set the carry to the carry bits of the current word */ + r = rr; + } + + /* set final carry */ + if (r != 0) { + c->dp[(c->used)++] = r; + } + } + mp_clamp (c); + return MP_OKAY; +} + + +/* shift left a certain amount of digits */ +int mp_lshd (mp_int * a, int b) +{ + int x, res; + + /* if its less than zero return */ + if (b <= 0) { + return MP_OKAY; + } + + /* grow to fit the new digits */ + if (a->alloc < a->used + b) { + if ((res = mp_grow (a, a->used + b)) != MP_OKAY) { + return res; + } + } + + { + register mp_digit *top, *bottom; + + /* increment the used by the shift amount then copy upwards */ + a->used += b; + + /* top */ + top = a->dp + a->used - 1; + + /* base */ + bottom = a->dp + a->used - 1 - b; + + /* much like mp_rshd this is implemented using a sliding window + * except the window goes the otherway around. Copying from + * the bottom to the top. see bn_mp_rshd.c for more info. + */ + for (x = a->used - 1; x >= b; x--) { + *top-- = *bottom--; + } + + /* zero the lower digits */ + top = a->dp; + for (x = 0; x < b; x++) { + *top++ = 0; + } + } + return MP_OKAY; +} + + +/* this is a shell function that calls either the normal or Montgomery + * exptmod functions. Originally the call to the montgomery code was + * embedded in the normal function but that wasted alot of stack space + * for nothing (since 99% of the time the Montgomery code would be called) + */ +int mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y) +{ + int dr; + + /* modulus P must be positive */ + if (P->sign == MP_NEG) { + return MP_VAL; + } + + /* if exponent X is negative we have to recurse */ + if (X->sign == MP_NEG) { +#ifdef BN_MP_INVMOD_C + mp_int tmpG, tmpX; + int err; + + /* first compute 1/G mod P */ + if ((err = mp_init(&tmpG)) != MP_OKAY) { + return err; + } + if ((err = mp_invmod(G, P, &tmpG)) != MP_OKAY) { + mp_clear(&tmpG); + return err; + } + + /* now get |X| */ + if ((err = mp_init(&tmpX)) != MP_OKAY) { + mp_clear(&tmpG); + return err; + } + if ((err = mp_abs(X, &tmpX)) != MP_OKAY) { + mp_clear(&tmpG); + mp_clear(&tmpX); + return err; + } + + /* and now compute (1/G)**|X| instead of G**X [X < 0] */ + err = mp_exptmod(&tmpG, &tmpX, P, Y); + mp_clear(&tmpG); + mp_clear(&tmpX); + return err; +#else + /* no invmod */ + return MP_VAL; +#endif + } + +/* modified diminished radix reduction */ +#if defined(BN_MP_REDUCE_IS_2K_L_C) && defined(BN_MP_REDUCE_2K_L_C) && \ + defined(BN_S_MP_EXPTMOD_C) + if (mp_reduce_is_2k_l(P) == MP_YES) { + return s_mp_exptmod(G, X, P, Y, 1); + } +#endif + +#ifdef BN_MP_DR_IS_MODULUS_C + /* is it a DR modulus? */ + dr = mp_dr_is_modulus(P); +#else + /* default to no */ + dr = 0; +#endif + +#ifdef BN_MP_REDUCE_IS_2K_C + /* if not, is it a unrestricted DR modulus? */ + if (dr == 0) { + dr = mp_reduce_is_2k(P) << 1; + } +#endif + + /* if the modulus is odd or dr != 0 use the montgomery method */ +#ifdef BN_MP_EXPTMOD_FAST_C + if (mp_isodd (P) == 1 || dr != 0) { + return mp_exptmod_fast (G, X, P, Y, dr); + } else { +#endif +#ifdef BN_S_MP_EXPTMOD_C + /* otherwise use the generic Barrett reduction technique */ + return s_mp_exptmod (G, X, P, Y, 0); +#else + /* no exptmod for evens */ + return MP_VAL; +#endif +#ifdef BN_MP_EXPTMOD_FAST_C + } +#endif +} + + +/* b = |a| + * + * Simple function copies the input and fixes the sign to positive + */ +int +mp_abs (mp_int * a, mp_int * b) +{ + int res; + + /* copy a to b */ + if (a != b) { + if ((res = mp_copy (a, b)) != MP_OKAY) { + return res; + } + } + + /* force the sign of b to positive */ + b->sign = MP_ZPOS; + + return MP_OKAY; +} + + +/* hac 14.61, pp608 */ +int mp_invmod (mp_int * a, mp_int * b, mp_int * c) +{ + /* b cannot be negative */ + if (b->sign == MP_NEG || mp_iszero(b) == 1) { + return MP_VAL; + } + +#ifdef BN_FAST_MP_INVMOD_C + /* if the modulus is odd we can use a faster routine instead */ + if (mp_isodd (b) == 1) { + return fast_mp_invmod (a, b, c); + } +#endif + +#ifdef BN_MP_INVMOD_SLOW_C + return mp_invmod_slow(a, b, c); +#endif +} + + +/* computes the modular inverse via binary extended euclidean algorithm, + * that is c = 1/a mod b + * + * Based on slow invmod except this is optimized for the case where b is + * odd as per HAC Note 14.64 on pp. 610 + */ +int fast_mp_invmod (mp_int * a, mp_int * b, mp_int * c) +{ + mp_int x, y, u, v, B, D; + int res, neg; + + /* 2. [modified] b must be odd */ + if (mp_iseven (b) == 1) { + return MP_VAL; + } + + /* init all our temps */ + if ((res = mp_init_multi(&x, &y, &u, &v, &B, &D)) != MP_OKAY) { + return res; + } + + /* x == modulus, y == value to invert */ + if ((res = mp_copy (b, &x)) != MP_OKAY) { + goto LBL_ERR; + } + + /* we need y = |a| */ + if ((res = mp_mod (a, b, &y)) != MP_OKAY) { + goto LBL_ERR; + } + + /* 3. u=x, v=y, A=1, B=0, C=0,D=1 */ + if ((res = mp_copy (&x, &u)) != MP_OKAY) { + goto LBL_ERR; + } + if ((res = mp_copy (&y, &v)) != MP_OKAY) { + goto LBL_ERR; + } + mp_set (&D, 1); + +top: + /* 4. while u is even do */ + while (mp_iseven (&u) == 1) { + /* 4.1 u = u/2 */ + if ((res = mp_div_2 (&u, &u)) != MP_OKAY) { + goto LBL_ERR; + } + /* 4.2 if B is odd then */ + if (mp_isodd (&B) == 1) { + if ((res = mp_sub (&B, &x, &B)) != MP_OKAY) { + goto LBL_ERR; + } + } + /* B = B/2 */ + if ((res = mp_div_2 (&B, &B)) != MP_OKAY) { + goto LBL_ERR; + } + } + + /* 5. while v is even do */ + while (mp_iseven (&v) == 1) { + /* 5.1 v = v/2 */ + if ((res = mp_div_2 (&v, &v)) != MP_OKAY) { + goto LBL_ERR; + } + /* 5.2 if D is odd then */ + if (mp_isodd (&D) == 1) { + /* D = (D-x)/2 */ + if ((res = mp_sub (&D, &x, &D)) != MP_OKAY) { + goto LBL_ERR; + } + } + /* D = D/2 */ + if ((res = mp_div_2 (&D, &D)) != MP_OKAY) { + goto LBL_ERR; + } + } + + /* 6. if u >= v then */ + if (mp_cmp (&u, &v) != MP_LT) { + /* u = u - v, B = B - D */ + if ((res = mp_sub (&u, &v, &u)) != MP_OKAY) { + goto LBL_ERR; + } + + if ((res = mp_sub (&B, &D, &B)) != MP_OKAY) { + goto LBL_ERR; + } + } else { + /* v - v - u, D = D - B */ + if ((res = mp_sub (&v, &u, &v)) != MP_OKAY) { + goto LBL_ERR; + } + + if ((res = mp_sub (&D, &B, &D)) != MP_OKAY) { + goto LBL_ERR; + } + } + + /* if not zero goto step 4 */ + if (mp_iszero (&u) == 0) { + goto top; + } + + /* now a = C, b = D, gcd == g*v */ + + /* if v != 1 then there is no inverse */ + if (mp_cmp_d (&v, 1) != MP_EQ) { + res = MP_VAL; + goto LBL_ERR; + } + + /* b is now the inverse */ + neg = a->sign; + while (D.sign == MP_NEG) { + if ((res = mp_add (&D, b, &D)) != MP_OKAY) { + goto LBL_ERR; + } + } + mp_exch (&D, c); + c->sign = neg; + res = MP_OKAY; + +LBL_ERR:mp_clear(&x); + mp_clear(&y); + mp_clear(&u); + mp_clear(&v); + mp_clear(&B); + mp_clear(&D); + return res; +} + + +/* hac 14.61, pp608 */ +int mp_invmod_slow (mp_int * a, mp_int * b, mp_int * c) +{ + mp_int x, y, u, v, A, B, C, D; + int res; + + /* b cannot be negative */ + if (b->sign == MP_NEG || mp_iszero(b) == 1) { + return MP_VAL; + } + + /* init temps */ + if ((res = mp_init_multi(&x, &y, &u, &v, + &A, &B)) != MP_OKAY) { + return res; + } + + /* init rest of tmps temps */ + if ((res = mp_init_multi(&C, &D, 0, 0, 0, 0)) != MP_OKAY) { + return res; + } + + /* x = a, y = b */ + if ((res = mp_mod(a, b, &x)) != MP_OKAY) { + goto LBL_ERR; + } + if ((res = mp_copy (b, &y)) != MP_OKAY) { + goto LBL_ERR; + } + + /* 2. [modified] if x,y are both even then return an error! */ + if (mp_iseven (&x) == 1 && mp_iseven (&y) == 1) { + res = MP_VAL; + goto LBL_ERR; + } + + /* 3. u=x, v=y, A=1, B=0, C=0,D=1 */ + if ((res = mp_copy (&x, &u)) != MP_OKAY) { + goto LBL_ERR; + } + if ((res = mp_copy (&y, &v)) != MP_OKAY) { + goto LBL_ERR; + } + mp_set (&A, 1); + mp_set (&D, 1); + +top: + /* 4. while u is even do */ + while (mp_iseven (&u) == 1) { + /* 4.1 u = u/2 */ + if ((res = mp_div_2 (&u, &u)) != MP_OKAY) { + goto LBL_ERR; + } + /* 4.2 if A or B is odd then */ + if (mp_isodd (&A) == 1 || mp_isodd (&B) == 1) { + /* A = (A+y)/2, B = (B-x)/2 */ + if ((res = mp_add (&A, &y, &A)) != MP_OKAY) { + goto LBL_ERR; + } + if ((res = mp_sub (&B, &x, &B)) != MP_OKAY) { + goto LBL_ERR; + } + } + /* A = A/2, B = B/2 */ + if ((res = mp_div_2 (&A, &A)) != MP_OKAY) { + goto LBL_ERR; + } + if ((res = mp_div_2 (&B, &B)) != MP_OKAY) { + goto LBL_ERR; + } + } + + /* 5. while v is even do */ + while (mp_iseven (&v) == 1) { + /* 5.1 v = v/2 */ + if ((res = mp_div_2 (&v, &v)) != MP_OKAY) { + goto LBL_ERR; + } + /* 5.2 if C or D is odd then */ + if (mp_isodd (&C) == 1 || mp_isodd (&D) == 1) { + /* C = (C+y)/2, D = (D-x)/2 */ + if ((res = mp_add (&C, &y, &C)) != MP_OKAY) { + goto LBL_ERR; + } + if ((res = mp_sub (&D, &x, &D)) != MP_OKAY) { + goto LBL_ERR; + } + } + /* C = C/2, D = D/2 */ + if ((res = mp_div_2 (&C, &C)) != MP_OKAY) { + goto LBL_ERR; + } + if ((res = mp_div_2 (&D, &D)) != MP_OKAY) { + goto LBL_ERR; + } + } + + /* 6. if u >= v then */ + if (mp_cmp (&u, &v) != MP_LT) { + /* u = u - v, A = A - C, B = B - D */ + if ((res = mp_sub (&u, &v, &u)) != MP_OKAY) { + goto LBL_ERR; + } + + if ((res = mp_sub (&A, &C, &A)) != MP_OKAY) { + goto LBL_ERR; + } + + if ((res = mp_sub (&B, &D, &B)) != MP_OKAY) { + goto LBL_ERR; + } + } else { + /* v - v - u, C = C - A, D = D - B */ + if ((res = mp_sub (&v, &u, &v)) != MP_OKAY) { + goto LBL_ERR; + } + + if ((res = mp_sub (&C, &A, &C)) != MP_OKAY) { + goto LBL_ERR; + } + + if ((res = mp_sub (&D, &B, &D)) != MP_OKAY) { + goto LBL_ERR; + } + } + + /* if not zero goto step 4 */ + if (mp_iszero (&u) == 0) + goto top; + + /* now a = C, b = D, gcd == g*v */ + + /* if v != 1 then there is no inverse */ + if (mp_cmp_d (&v, 1) != MP_EQ) { + res = MP_VAL; + goto LBL_ERR; + } + + /* if its too low */ + while (mp_cmp_d(&C, 0) == MP_LT) { + if ((res = mp_add(&C, b, &C)) != MP_OKAY) { + goto LBL_ERR; + } + } + + /* too big */ + while (mp_cmp_mag(&C, b) != MP_LT) { + if ((res = mp_sub(&C, b, &C)) != MP_OKAY) { + goto LBL_ERR; + } + } + + /* C is now the inverse */ + mp_exch (&C, c); + res = MP_OKAY; +LBL_ERR:mp_clear(&x); + mp_clear(&y); + mp_clear(&u); + mp_clear(&v); + mp_clear(&A); + mp_clear(&B); + mp_clear(&C); + mp_clear(&D); + return res; +} + + +/* compare maginitude of two ints (unsigned) */ +int mp_cmp_mag (mp_int * a, mp_int * b) +{ + int n; + mp_digit *tmpa, *tmpb; + + /* compare based on # of non-zero digits */ + if (a->used > b->used) { + return MP_GT; + } + + if (a->used < b->used) { + return MP_LT; + } + + /* alias for a */ + tmpa = a->dp + (a->used - 1); + + /* alias for b */ + tmpb = b->dp + (a->used - 1); + + /* compare based on digits */ + for (n = 0; n < a->used; ++n, --tmpa, --tmpb) { + if (*tmpa > *tmpb) { + return MP_GT; + } + + if (*tmpa < *tmpb) { + return MP_LT; + } + } + return MP_EQ; +} + + +/* compare two ints (signed)*/ +int +mp_cmp (mp_int * a, mp_int * b) +{ + /* compare based on sign */ + if (a->sign != b->sign) { + if (a->sign == MP_NEG) { + return MP_LT; + } else { + return MP_GT; + } + } + + /* compare digits */ + if (a->sign == MP_NEG) { + /* if negative compare opposite direction */ + return mp_cmp_mag(b, a); + } else { + return mp_cmp_mag(a, b); + } +} + + +/* compare a digit */ +int mp_cmp_d(mp_int * a, mp_digit b) +{ + /* compare based on sign */ + if (a->sign == MP_NEG) { + return MP_LT; + } + + /* compare based on magnitude */ + if (a->used > 1) { + return MP_GT; + } + + /* compare the only digit of a to b */ + if (a->dp[0] > b) { + return MP_GT; + } else if (a->dp[0] < b) { + return MP_LT; + } else { + return MP_EQ; + } +} + + +/* set to a digit */ +void mp_set (mp_int * a, mp_digit b) +{ + mp_zero (a); + a->dp[0] = b & MP_MASK; + a->used = (a->dp[0] != 0) ? 1 : 0; +} + + +/* c = a mod b, 0 <= c < b */ +int +mp_mod (mp_int * a, mp_int * b, mp_int * c) +{ + mp_int t; + int res; + + if ((res = mp_init (&t)) != MP_OKAY) { + return res; + } + + if ((res = mp_div (a, b, NULL, &t)) != MP_OKAY) { + mp_clear (&t); + return res; + } + + if (t.sign != b->sign) { + res = mp_add (b, &t, c); + } else { + res = MP_OKAY; + mp_exch (&t, c); + } + + mp_clear (&t); + return res; +} + + +/* slower bit-bang division... also smaller */ +int mp_div(mp_int * a, mp_int * b, mp_int * c, mp_int * d) +{ + mp_int ta, tb, tq, q; + int res, n, n2; + + /* is divisor zero ? */ + if (mp_iszero (b) == 1) { + return MP_VAL; + } + + /* if a < b then q=0, r = a */ + if (mp_cmp_mag (a, b) == MP_LT) { + if (d != NULL) { + res = mp_copy (a, d); + } else { + res = MP_OKAY; + } + if (c != NULL) { + mp_zero (c); + } + return res; + } + + /* init our temps */ + if ((res = mp_init_multi(&ta, &tb, &tq, &q, 0, 0) != MP_OKAY)) { + return res; + } + + + mp_set(&tq, 1); + n = mp_count_bits(a) - mp_count_bits(b); + if (((res = mp_abs(a, &ta)) != MP_OKAY) || + ((res = mp_abs(b, &tb)) != MP_OKAY) || + ((res = mp_mul_2d(&tb, n, &tb)) != MP_OKAY) || + ((res = mp_mul_2d(&tq, n, &tq)) != MP_OKAY)) { + goto LBL_ERR; + } + + while (n-- >= 0) { + if (mp_cmp(&tb, &ta) != MP_GT) { + if (((res = mp_sub(&ta, &tb, &ta)) != MP_OKAY) || + ((res = mp_add(&q, &tq, &q)) != MP_OKAY)) { + goto LBL_ERR; + } + } + if (((res = mp_div_2d(&tb, 1, &tb, NULL)) != MP_OKAY) || + ((res = mp_div_2d(&tq, 1, &tq, NULL)) != MP_OKAY)) { + goto LBL_ERR; + } + } + + /* now q == quotient and ta == remainder */ + n = a->sign; + n2 = (a->sign == b->sign ? MP_ZPOS : MP_NEG); + if (c != NULL) { + mp_exch(c, &q); + c->sign = (mp_iszero(c) == MP_YES) ? MP_ZPOS : n2; + } + if (d != NULL) { + mp_exch(d, &ta); + d->sign = (mp_iszero(d) == MP_YES) ? MP_ZPOS : n; + } +LBL_ERR: + mp_clear(&ta); + mp_clear(&tb); + mp_clear(&tq); + mp_clear(&q); + return res; +} + + +/* b = a/2 */ +int mp_div_2(mp_int * a, mp_int * b) +{ + int x, res, oldused; + + /* copy */ + if (b->alloc < a->used) { + if ((res = mp_grow (b, a->used)) != MP_OKAY) { + return res; + } + } + + oldused = b->used; + b->used = a->used; + { + register mp_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; + mp_clamp (b); + return MP_OKAY; +} + + +/* high level addition (handles signs) */ +int mp_add (mp_int * a, mp_int * b, mp_int * c) +{ + int sa, sb, res; + + /* 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; + res = s_mp_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 (mp_cmp_mag (a, b) == MP_LT) { + c->sign = sb; + res = s_mp_sub (b, a, c); + } else { + c->sign = sa; + res = s_mp_sub (a, b, c); + } + } + return res; +} + + +/* low level addition, based on HAC pp.594, Algorithm 14.7 */ +int +s_mp_add (mp_int * a, mp_int * b, mp_int * c) +{ + mp_int *x; + int olduse, res, min, max; + + /* find sizes, we let |a| <= |b| which means we have to sort + * them. "x" will point to the input with the most digits + */ + if (a->used > b->used) { + min = b->used; + max = a->used; + x = a; + } else { + min = a->used; + max = b->used; + x = b; + } + + /* init result */ + if (c->alloc < max + 1) { + if ((res = mp_grow (c, max + 1)) != MP_OKAY) { + return res; + } + } + + /* get old used digit count and set new one */ + olduse = c->used; + c->used = max + 1; + + { + register mp_digit u, *tmpa, *tmpb, *tmpc; + register int i; + + /* alias for digit pointers */ + + /* first input */ + tmpa = a->dp; + + /* second input */ + tmpb = b->dp; + + /* destination */ + tmpc = c->dp; + + /* zero the carry */ + u = 0; + for (i = 0; i < min; i++) { + /* Compute the sum at one digit, T[i] = A[i] + B[i] + U */ + *tmpc = *tmpa++ + *tmpb++ + u; + + /* U = carry bit of T[i] */ + u = *tmpc >> ((mp_digit)DIGIT_BIT); + + /* take away carry bit from T[i] */ + *tmpc++ &= MP_MASK; + } + + /* now copy higher words if any, that is in A+B + * if A or B has more digits add those in + */ + if (min != max) { + for (; i < max; i++) { + /* T[i] = X[i] + U */ + *tmpc = x->dp[i] + u; + + /* U = carry bit of T[i] */ + u = *tmpc >> ((mp_digit)DIGIT_BIT); + + /* take away carry bit from T[i] */ + *tmpc++ &= MP_MASK; + } + } + + /* add carry */ + *tmpc++ = u; + + /* clear digits above oldused */ + for (i = c->used; i < olduse; i++) { + *tmpc++ = 0; + } + } + + mp_clamp (c); + return MP_OKAY; +} + + +/* low level subtraction (assumes |a| > |b|), HAC pp.595 Algorithm 14.9 */ +int +s_mp_sub (mp_int * a, mp_int * b, mp_int * c) +{ + int olduse, res, min, max; + + /* find sizes */ + min = b->used; + max = a->used; + + /* init result */ + if (c->alloc < max) { + if ((res = mp_grow (c, max)) != MP_OKAY) { + return res; + } + } + olduse = c->used; + c->used = max; + + { + register mp_digit u, *tmpa, *tmpb, *tmpc; + register int i; + + /* alias for digit pointers */ + tmpa = a->dp; + tmpb = b->dp; + tmpc = c->dp; + + /* set carry to zero */ + u = 0; + for (i = 0; i < min; i++) { + /* T[i] = A[i] - B[i] - U */ + *tmpc = *tmpa++ - *tmpb++ - u; + + /* U = carry bit of T[i] + * Note this saves performing an AND operation since + * if a carry does occur it will propagate all the way to the + * MSB. As a result a single shift is enough to get the carry + */ + u = *tmpc >> ((mp_digit)(CHAR_BIT * sizeof (mp_digit) - 1)); + + /* Clear carry from T[i] */ + *tmpc++ &= MP_MASK; + } + + /* now copy higher words if any, e.g. if A has more digits than B */ + for (; i < max; i++) { + /* T[i] = A[i] - U */ + *tmpc = *tmpa++ - u; + + /* U = carry bit of T[i] */ + u = *tmpc >> ((mp_digit)(CHAR_BIT * sizeof (mp_digit) - 1)); + + /* Clear carry from T[i] */ + *tmpc++ &= MP_MASK; + } + + /* clear digits above used (since we may not have grown result above) */ + for (i = c->used; i < olduse; i++) { + *tmpc++ = 0; + } + } + + mp_clamp (c); + return MP_OKAY; +} + + +/* high level subtraction (handles signs) */ +int +mp_sub (mp_int * a, mp_int * b, mp_int * c) +{ + int sa, sb, res; + + 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; + res = s_mp_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 (mp_cmp_mag (a, b) != MP_LT) { + /* Copy the sign from the first */ + c->sign = sa; + /* The first has a larger or equal magnitude */ + res = s_mp_sub (a, b, c); + } else { + /* The result has the *opposite* sign from */ + /* the first number. */ + c->sign = (sa == MP_ZPOS) ? MP_NEG : MP_ZPOS; + /* The second has a larger magnitude */ + res = s_mp_sub (b, a, c); + } + } + return res; +} + + +/* determines if reduce_2k_l can be used */ +int mp_reduce_is_2k_l(mp_int *a) +{ + int ix, iy; + + if (a->used == 0) { + return MP_NO; + } else if (a->used == 1) { + return MP_YES; + } else if (a->used > 1) { + /* if more than half of the digits are -1 we're sold */ + for (iy = ix = 0; ix < a->used; ix++) { + if (a->dp[ix] == MP_MASK) { + ++iy; + } + } + return (iy >= (a->used/2)) ? MP_YES : MP_NO; + + } + return MP_NO; +} + + +/* determines if mp_reduce_2k can be used */ +int mp_reduce_is_2k(mp_int *a) +{ + int ix, iy, iw; + mp_digit iz; + + if (a->used == 0) { + return MP_NO; + } else if (a->used == 1) { + return MP_YES; + } else if (a->used > 1) { + iy = mp_count_bits(a); + iz = 1; + iw = 1; + + /* Test every bit from the second digit up, must be 1 */ + for (ix = DIGIT_BIT; ix < iy; ix++) { + if ((a->dp[iw] & iz) == 0) { + return MP_NO; + } + iz <<= 1; + if (iz > (mp_digit)MP_MASK) { + ++iw; + iz = 1; + } + } + } + return MP_YES; +} + + +/* determines if a number is a valid DR modulus */ +int mp_dr_is_modulus(mp_int *a) +{ + int ix; + + /* must be at least two digits */ + if (a->used < 2) { + return 0; + } + + /* must be of the form b**k - a [a <= b] so all + * but the first digit must be equal to -1 (mod b). + */ + for (ix = 1; ix < a->used; ix++) { + if (a->dp[ix] != MP_MASK) { + return 0; + } + } + return 1; +} + + +/* computes Y == G**X mod P, HAC pp.616, Algorithm 14.85 + * + * Uses a left-to-right k-ary sliding window to compute the modular + * exponentiation. + * The value of k changes based on the size of the exponent. + * + * Uses Montgomery or Diminished Radix reduction [whichever appropriate] + */ + +#ifdef MP_LOW_MEM + #define TAB_SIZE 32 +#else + #define TAB_SIZE 256 +#endif + +int mp_exptmod_fast (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, + int redmode) +{ + mp_int M[TAB_SIZE], res; + mp_digit buf, mp; + int err, bitbuf, bitcpy, bitcnt, mode, digidx, x, y, winsize; + + /* use a pointer to the reduction algorithm. This allows us to use + * one of many reduction algorithms without modding the guts of + * the code with if statements everywhere. + */ + int (*redux)(mp_int*,mp_int*,mp_digit); + + /* find window size */ + x = mp_count_bits (X); + if (x <= 7) { + winsize = 2; + } else if (x <= 36) { + winsize = 3; + } else if (x <= 140) { + winsize = 4; + } else if (x <= 450) { + winsize = 5; + } else if (x <= 1303) { + winsize = 6; + } else if (x <= 3529) { + winsize = 7; + } else { + winsize = 8; + } + +#ifdef MP_LOW_MEM + if (winsize > 5) { + winsize = 5; + } +#endif + + /* init M array */ + /* init first cell */ + if ((err = mp_init(&M[1])) != MP_OKAY) { + return err; + } + + /* now init the second half of the array */ + for (x = 1<<(winsize-1); x < (1 << winsize); x++) { + if ((err = mp_init(&M[x])) != MP_OKAY) { + for (y = 1<<(winsize-1); y < x; y++) { + mp_clear (&M[y]); + } + mp_clear(&M[1]); + return err; + } + } + + /* determine and setup reduction code */ + if (redmode == 0) { +#ifdef BN_MP_MONTGOMERY_SETUP_C + /* now setup montgomery */ + if ((err = mp_montgomery_setup (P, &mp)) != MP_OKAY) { + goto LBL_M; + } +#else + err = MP_VAL; + goto LBL_M; +#endif + + /* automatically pick the comba one if available (saves quite a few + calls/ifs) */ +#ifdef BN_FAST_MP_MONTGOMERY_REDUCE_C + if (((P->used * 2 + 1) < MP_WARRAY) && + P->used < (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) { + redux = fast_mp_montgomery_reduce; + } else +#endif + { +#ifdef BN_MP_MONTGOMERY_REDUCE_C + /* use slower baseline Montgomery method */ + redux = mp_montgomery_reduce; +#else + err = MP_VAL; + goto LBL_M; +#endif + } + } else if (redmode == 1) { +#if defined(BN_MP_DR_SETUP_C) && defined(BN_MP_DR_REDUCE_C) + /* setup DR reduction for moduli of the form B**k - b */ + mp_dr_setup(P, &mp); + redux = mp_dr_reduce; +#else + err = MP_VAL; + goto LBL_M; +#endif + } else { +#if defined(BN_MP_REDUCE_2K_SETUP_C) && defined(BN_MP_REDUCE_2K_C) + /* setup DR reduction for moduli of the form 2**k - b */ + if ((err = mp_reduce_2k_setup(P, &mp)) != MP_OKAY) { + goto LBL_M; + } + redux = mp_reduce_2k; +#else + err = MP_VAL; + goto LBL_M; +#endif + } + + /* setup result */ + if ((err = mp_init (&res)) != MP_OKAY) { + goto LBL_M; + } + + /* create M table + * + + * + * The first half of the table is not computed though accept for M[0] and M[1] + */ + + if (redmode == 0) { +#ifdef BN_MP_MONTGOMERY_CALC_NORMALIZATION_C + /* now we need R mod m */ + if ((err = mp_montgomery_calc_normalization (&res, P)) != MP_OKAY) { + goto LBL_RES; + } +#else + err = MP_VAL; + goto LBL_RES; +#endif + + /* now set M[1] to G * R mod m */ + if ((err = mp_mulmod (G, &res, P, &M[1])) != MP_OKAY) { + goto LBL_RES; + } + } else { + mp_set(&res, 1); + if ((err = mp_mod(G, P, &M[1])) != MP_OKAY) { + goto LBL_RES; + } + } + + /* compute the value at M[1<<(winsize-1)] by squaring M[1] (winsize-1) times*/ + if ((err = mp_copy (&M[1], &M[1 << (winsize - 1)])) != MP_OKAY) { + goto LBL_RES; + } + + for (x = 0; x < (winsize - 1); x++) { + if ((err = mp_sqr (&M[1 << (winsize - 1)], &M[1 << (winsize - 1)])) != MP_OKAY) { + goto LBL_RES; + } + if ((err = redux (&M[1 << (winsize - 1)], P, mp)) != MP_OKAY) { + goto LBL_RES; + } + } + + /* create upper table */ + for (x = (1 << (winsize - 1)) + 1; x < (1 << winsize); x++) { + if ((err = mp_mul (&M[x - 1], &M[1], &M[x])) != MP_OKAY) { + goto LBL_RES; + } + if ((err = redux (&M[x], P, mp)) != MP_OKAY) { + goto LBL_RES; + } + } + + /* 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 = (mp_digit)(buf >> (DIGIT_BIT - 1)) & 1; + buf <<= (mp_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) { + if ((err = mp_sqr (&res, &res)) != MP_OKAY) { + goto LBL_RES; + } + if ((err = redux (&res, P, mp)) != MP_OKAY) { + goto LBL_RES; + } + 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++) { + if ((err = mp_sqr (&res, &res)) != MP_OKAY) { + goto LBL_RES; + } + if ((err = redux (&res, P, mp)) != MP_OKAY) { + goto LBL_RES; + } + } + + /* then multiply */ + if ((err = mp_mul (&res, &M[bitbuf], &res)) != MP_OKAY) { + goto LBL_RES; + } + if ((err = redux (&res, P, mp)) != MP_OKAY) { + goto LBL_RES; + } + + /* 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++) { + if ((err = mp_sqr (&res, &res)) != MP_OKAY) { + goto LBL_RES; + } + if ((err = redux (&res, P, mp)) != MP_OKAY) { + goto LBL_RES; + } + + /* get next bit of the window */ + bitbuf <<= 1; + if ((bitbuf & (1 << winsize)) != 0) { + /* then multiply */ + if ((err = mp_mul (&res, &M[1], &res)) != MP_OKAY) { + goto LBL_RES; + } + if ((err = redux (&res, P, mp)) != MP_OKAY) { + goto LBL_RES; + } + } + } + } + + if (redmode == 0) { + /* 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. + */ + if ((err = redux(&res, P, mp)) != MP_OKAY) { + goto LBL_RES; + } + } + + /* swap res with Y */ + mp_exch (&res, Y); + err = MP_OKAY; +LBL_RES:mp_clear (&res); +LBL_M: + mp_clear(&M[1]); + for (x = 1<<(winsize-1); x < (1 << winsize); x++) { + mp_clear (&M[x]); + } + return err; +} + + +/* setups the montgomery reduction stuff */ +int +mp_montgomery_setup (mp_int * n, mp_digit * rho) +{ + mp_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 = n->dp[0]; + + if ((b & 1) == 0) { + return MP_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 */ +#if !defined(MP_8BIT) + x *= 2 - b * x; /* here x*a==1 mod 2**16 */ +#endif +#if defined(MP_64BIT) || !(defined(MP_8BIT) || defined(MP_16BIT)) + x *= 2 - b * x; /* here x*a==1 mod 2**32 */ +#endif +#ifdef MP_64BIT + x *= 2 - b * x; /* here x*a==1 mod 2**64 */ +#endif + + /* rho = -1/m mod b */ + /* TAO, switched mp_word casts to mp_digit to shut up compiler */ + *rho = (((mp_digit)1 << ((mp_digit) DIGIT_BIT)) - x) & MP_MASK; + + return MP_OKAY; +} + + +/* computes xR**-1 == x (mod N) via Montgomery Reduction + * + * This is an optimized implementation of montgomery_reduce + * which uses the comba method to quickly calculate the columns of the + * reduction. + * + * Based on Algorithm 14.32 on pp.601 of HAC. +*/ +int fast_mp_montgomery_reduce (mp_int * x, mp_int * n, mp_digit rho) +{ + int ix, res, olduse; + mp_word W[MP_WARRAY]; + + /* get old used count */ + olduse = x->used; + + /* grow a as required */ + if (x->alloc < n->used + 1) { + if ((res = mp_grow (x, n->used + 1)) != MP_OKAY) { + return res; + } + } + + /* first we have to get the digits of the input into + * an array of double precision words W[...] + */ + { + register mp_word *_W; + register mp_digit *tmpx; + + /* alias for the W[] array */ + _W = W; + + /* alias for the digits of x*/ + tmpx = x->dp; + + /* copy the digits of a into W[0..a->used-1] */ + for (ix = 0; ix < x->used; ix++) { + *_W++ = *tmpx++; + } + + /* zero the high words of W[a->used..m->used*2] */ + for (; ix < n->used * 2 + 1; ix++) { + *_W++ = 0; + } + } + + /* now we proceed to zero successive digits + * from the least significant upwards + */ + for (ix = 0; ix < n->used; ix++) { + /* mu = ai * m' mod b + * + * We avoid a double precision multiplication (which isn't required) + * by casting the value down to a mp_digit. Note this requires + * that W[ix-1] have the carry cleared (see after the inner loop) + */ + register mp_digit mu; + mu = (mp_digit) (((W[ix] & MP_MASK) * rho) & MP_MASK); + + /* a = a + mu * m * b**i + * + * This is computed in place and on the fly. The multiplication + * by b**i is handled by offseting which columns the results + * are added to. + * + * Note the comba method normally doesn't handle carries in the + * inner loop In this case we fix the carry from the previous + * column since the Montgomery reduction requires digits of the + * result (so far) [see above] to work. This is + * handled by fixing up one carry after the inner loop. The + * carry fixups are done in order so after these loops the + * first m->used words of W[] have the carries fixed + */ + { + register int iy; + register mp_digit *tmpn; + register mp_word *_W; + + /* alias for the digits of the modulus */ + tmpn = n->dp; + + /* Alias for the columns set by an offset of ix */ + _W = W + ix; + + /* inner loop */ + for (iy = 0; iy < n->used; iy++) { + *_W++ += ((mp_word)mu) * ((mp_word)*tmpn++); + } + } + + /* now fix carry for next digit, W[ix+1] */ + W[ix + 1] += W[ix] >> ((mp_word) DIGIT_BIT); + } + + /* now we have to propagate the carries and + * shift the words downward [all those least + * significant digits we zeroed]. + */ + { + register mp_digit *tmpx; + register mp_word *_W, *_W1; + + /* nox fix rest of carries */ + + /* alias for current word */ + _W1 = W + ix; + + /* alias for next word, where the carry goes */ + _W = W + ++ix; + + for (; ix <= n->used * 2 + 1; ix++) { + *_W++ += *_W1++ >> ((mp_word) DIGIT_BIT); + } + + /* copy out, A = A/b**n + * + * The result is A/b**n but instead of converting from an + * array of mp_word to mp_digit than calling mp_rshd + * we just copy them in the right order + */ + + /* alias for destination word */ + tmpx = x->dp; + + /* alias for shifted double precision result */ + _W = W + n->used; + + for (ix = 0; ix < n->used + 1; ix++) { + *tmpx++ = (mp_digit)(*_W++ & ((mp_word) MP_MASK)); + } + + /* zero oldused digits, if the input a was larger than + * m->used+1 we'll have to clear the digits + */ + for (; ix < olduse; ix++) { + *tmpx++ = 0; + } + } + + /* set the max used and clamp */ + x->used = n->used + 1; + mp_clamp (x); + + /* if A >= m then A = A - m */ + if (mp_cmp_mag (x, n) != MP_LT) { + return s_mp_sub (x, n, x); + } + return MP_OKAY; +} + + +/* computes xR**-1 == x (mod N) via Montgomery Reduction */ +int +mp_montgomery_reduce (mp_int * x, mp_int * n, mp_digit rho) +{ + int ix, res, digs; + mp_digit mu; + + /* can the fast reduction [comba] method be used? + * + * Note that unlike in mul you're safely allowed *less* + * than the available columns [255 per default] since carries + * are fixed up in the inner loop. + */ + digs = n->used * 2 + 1; + if ((digs < MP_WARRAY) && + n->used < + (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) { + return fast_mp_montgomery_reduce (x, n, rho); + } + + /* grow the input as required */ + if (x->alloc < digs) { + if ((res = mp_grow (x, digs)) != MP_OKAY) { + return res; + } + } + x->used = digs; + + for (ix = 0; ix < n->used; ix++) { + /* mu = ai * rho mod b + * + * The value of rho must be precalculated via + * montgomery_setup() such that + * it equals -1/n0 mod b this allows the + * following inner loop to reduce the + * input one digit at a time + */ + mu = (mp_digit) (((mp_word)x->dp[ix]) * ((mp_word)rho) & MP_MASK); + + /* a = a + mu * m * b**i */ + { + register int iy; + register mp_digit *tmpn, *tmpx, u; + register mp_word r; + + /* alias for digits of the modulus */ + tmpn = n->dp; + + /* alias for the digits of x [the input] */ + tmpx = x->dp + ix; + + /* set the carry to zero */ + u = 0; + + /* Multiply and add in place */ + for (iy = 0; iy < n->used; iy++) { + /* compute product and sum */ + r = ((mp_word)mu) * ((mp_word)*tmpn++) + + ((mp_word) u) + ((mp_word) * tmpx); + + /* get carry */ + u = (mp_digit)(r >> ((mp_word) DIGIT_BIT)); + + /* fix digit */ + *tmpx++ = (mp_digit)(r & ((mp_word) MP_MASK)); + } + /* At this point the ix'th digit of x should be zero */ + + + /* propagate carries upwards as required*/ + while (u) { + *tmpx += u; + u = *tmpx >> DIGIT_BIT; + *tmpx++ &= MP_MASK; + } + } + } + + /* at this point the n.used'th least + * significant digits of x are all zero + * which means we can shift x to the + * right by n.used digits and the + * residue is unchanged. + */ + + /* x = x/b**n.used */ + mp_clamp(x); + mp_rshd (x, n->used); + + /* if x >= n then x = x - n */ + if (mp_cmp_mag (x, n) != MP_LT) { + return s_mp_sub (x, n, x); + } + + return MP_OKAY; +} + + +/* determines the setup value */ +void mp_dr_setup(mp_int *a, mp_digit *d) +{ + /* the casts are required if DIGIT_BIT is one less than + * the number of bits in a mp_digit [e.g. DIGIT_BIT==31] + */ + *d = (mp_digit)((((mp_word)1) << ((mp_word)DIGIT_BIT)) - + ((mp_word)a->dp[0])); +} + + +/* reduce "x" in place modulo "n" using the Diminished Radix algorithm. + * + * Based on algorithm from the paper + * + * "Generating Efficient Primes for Discrete Log Cryptosystems" + * Chae Hoon Lim, Pil Joong Lee, + * POSTECH Information Research Laboratories + * + * The modulus must be of a special format [see manual] + * + * Has been modified to use algorithm 7.10 from the LTM book instead + * + * Input x must be in the range 0 <= x <= (n-1)**2 + */ +int +mp_dr_reduce (mp_int * x, mp_int * n, mp_digit k) +{ + int err, i, m; + mp_word r; + mp_digit mu, *tmpx1, *tmpx2; + + /* m = digits in modulus */ + m = n->used; + + /* ensure that "x" has at least 2m digits */ + if (x->alloc < m + m) { + if ((err = mp_grow (x, m + m)) != MP_OKAY) { + return err; + } + } + +/* top of loop, this is where the code resumes if + * another reduction pass is required. + */ +top: + /* aliases for digits */ + /* alias for lower half of x */ + tmpx1 = x->dp; + + /* alias for upper half of x, or x/B**m */ + tmpx2 = x->dp + m; + + /* set carry to zero */ + mu = 0; + + /* compute (x mod B**m) + k * [x/B**m] inline and inplace */ + for (i = 0; i < m; i++) { + r = ((mp_word)*tmpx2++) * ((mp_word)k) + *tmpx1 + mu; + *tmpx1++ = (mp_digit)(r & MP_MASK); + mu = (mp_digit)(r >> ((mp_word)DIGIT_BIT)); + } + + /* set final carry */ + *tmpx1++ = mu; + + /* zero words above m */ + for (i = m + 1; i < x->used; i++) { + *tmpx1++ = 0; + } + + /* clamp, sub and return */ + mp_clamp (x); + + /* if x >= n then subtract and reduce again + * Each successive "recursion" makes the input smaller and smaller. + */ + if (mp_cmp_mag (x, n) != MP_LT) { + s_mp_sub(x, n, x); + goto top; + } + return MP_OKAY; +} + + +/* reduces a modulo n where n is of the form 2**p - d */ +int mp_reduce_2k(mp_int *a, mp_int *n, mp_digit d) +{ + mp_int q; + int p, res; + + if ((res = mp_init(&q)) != MP_OKAY) { + return res; + } + + p = mp_count_bits(n); +top: + /* q = a/2**p, a = a mod 2**p */ + if ((res = mp_div_2d(a, p, &q, a)) != MP_OKAY) { + goto ERR; + } + + if (d != 1) { + /* q = q * d */ + if ((res = mp_mul_d(&q, d, &q)) != MP_OKAY) { + goto ERR; + } + } + + /* a = a + q */ + if ((res = s_mp_add(a, &q, a)) != MP_OKAY) { + goto ERR; + } + + if (mp_cmp_mag(a, n) != MP_LT) { + s_mp_sub(a, n, a); + goto top; + } + +ERR: + mp_clear(&q); + return res; +} + + +/* determines the setup value */ +int mp_reduce_2k_setup(mp_int *a, mp_digit *d) +{ + int res, p; + mp_int tmp; + + if ((res = mp_init(&tmp)) != MP_OKAY) { + return res; + } + + p = mp_count_bits(a); + if ((res = mp_2expt(&tmp, p)) != MP_OKAY) { + mp_clear(&tmp); + return res; + } + + if ((res = s_mp_sub(&tmp, a, &tmp)) != MP_OKAY) { + mp_clear(&tmp); + return res; + } + + *d = tmp.dp[0]; + mp_clear(&tmp); + return MP_OKAY; +} + + +/* computes a = 2**b + * + * Simple algorithm which zeroes the int, grows it then just sets one bit + * as required. + */ +int +mp_2expt (mp_int * a, int b) +{ + int res; + + /* zero a as per default */ + mp_zero (a); + + /* grow a to accomodate the single bit */ + if ((res = mp_grow (a, b / DIGIT_BIT + 1)) != MP_OKAY) { + return res; + } + + /* set the used count of where the bit will go */ + a->used = b / DIGIT_BIT + 1; + + /* put the single bit in its place */ + a->dp[b / DIGIT_BIT] = ((mp_digit)1) << (b % DIGIT_BIT); + + return MP_OKAY; +} + + +/* multiply by a digit */ +int +mp_mul_d (mp_int * a, mp_digit b, mp_int * c) +{ + mp_digit u, *tmpa, *tmpc; + mp_word r; + int ix, res, olduse; + + /* make sure c is big enough to hold a*b */ + if (c->alloc < a->used + 1) { + if ((res = mp_grow (c, a->used + 1)) != MP_OKAY) { + return res; + } + } + + /* get the original destinations used count */ + olduse = c->used; + + /* set the sign */ + c->sign = a->sign; + + /* alias for a->dp [source] */ + tmpa = a->dp; + + /* alias for c->dp [dest] */ + tmpc = c->dp; + + /* zero carry */ + u = 0; + + /* compute columns */ + for (ix = 0; ix < a->used; ix++) { + /* compute product and carry sum for this term */ + r = ((mp_word) u) + ((mp_word)*tmpa++) * ((mp_word)b); + + /* mask off higher bits to get a single digit */ + *tmpc++ = (mp_digit) (r & ((mp_word) MP_MASK)); + + /* send carry into next iteration */ + u = (mp_digit) (r >> ((mp_word) DIGIT_BIT)); + } + + /* store final carry [if any] and increment ix offset */ + *tmpc++ = u; + ++ix; + + /* now zero digits above the top */ + while (ix++ < olduse) { + *tmpc++ = 0; + } + + /* set used count */ + c->used = a->used + 1; + mp_clamp(c); + + return MP_OKAY; +} + + +/* d = a * b (mod c) */ +int mp_mulmod (mp_int * a, mp_int * b, mp_int * c, mp_int * d) +{ + int res; + mp_int t; + + if ((res = mp_init (&t)) != MP_OKAY) { + return res; + } + + if ((res = mp_mul (a, b, &t)) != MP_OKAY) { + mp_clear (&t); + return res; + } + res = mp_mod (&t, c, d); + mp_clear (&t); + return res; +} + + +/* computes b = a*a */ +int +mp_sqr (mp_int * a, mp_int * b) +{ + int res; + + { +#ifdef BN_FAST_S_MP_SQR_C + /* can we use the fast comba multiplier? */ + if ((a->used * 2 + 1) < MP_WARRAY && + a->used < + (1 << (sizeof(mp_word) * CHAR_BIT - 2*DIGIT_BIT - 1))) { + res = fast_s_mp_sqr (a, b); + } else +#endif +#ifdef BN_S_MP_SQR_C + res = s_mp_sqr (a, b); +#else + res = MP_VAL; +#endif + } + b->sign = MP_ZPOS; + return res; +} + + +/* high level multiplication (handles sign) */ +int mp_mul (mp_int * a, mp_int * b, mp_int * c) +{ + int res, neg; + neg = (a->sign == b->sign) ? MP_ZPOS : MP_NEG; + + { + /* can we use the fast multiplier? + * + * The fast multiplier can be used if the output will + * have less than MP_WARRAY digits and the number of + * digits won't affect carry propagation + */ + int digs = a->used + b->used + 1; + +#ifdef BN_FAST_S_MP_MUL_DIGS_C + if ((digs < MP_WARRAY) && + MIN(a->used, b->used) <= + (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) { + res = fast_s_mp_mul_digs (a, b, c, digs); + } else +#endif +#ifdef BN_S_MP_MUL_DIGS_C + res = s_mp_mul (a, b, c); /* uses s_mp_mul_digs */ +#else + res = MP_VAL; +#endif + + } + c->sign = (c->used > 0) ? neg : MP_ZPOS; + return res; +} + + +/* b = a*2 */ +int mp_mul_2(mp_int * a, mp_int * b) +{ + int x, res, oldused; + + /* grow to accomodate result */ + if (b->alloc < a->used + 1) { + if ((res = mp_grow (b, a->used + 1)) != MP_OKAY) { + return res; + } + } + + oldused = b->used; + b->used = a->used; + + { + register mp_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 >> ((mp_digit)(DIGIT_BIT - 1)); + + /* now shift up this digit, add in the carry [from the previous] */ + *tmpb++ = ((*tmpa++ << ((mp_digit)1)) | r) & MP_MASK; + + /* copy the carry that would be from the source + * digit into the next iteration + */ + r = rr; + } + + /* new leading digit? */ + if (r != 0) { + /* 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; + return MP_OKAY; +} + + +/* divide by three (based on routine from MPI and the GMP manual) */ +int +mp_div_3 (mp_int * a, mp_int *c, mp_digit * d) +{ + mp_int q; + mp_word w, t; + mp_digit b; + int res, ix; + + /* b = 2**DIGIT_BIT / 3 */ + b = (((mp_word)1) << ((mp_word)DIGIT_BIT)) / ((mp_word)3); + + if ((res = mp_init_size(&q, a->used)) != MP_OKAY) { + return res; + } + + q.used = a->used; + q.sign = a->sign; + w = 0; + for (ix = a->used - 1; ix >= 0; ix--) { + w = (w << ((mp_word)DIGIT_BIT)) | ((mp_word)a->dp[ix]); + + if (w >= 3) { + /* multiply w by [1/3] */ + t = (w * ((mp_word)b)) >> ((mp_word)DIGIT_BIT); + + /* now subtract 3 * [w/3] from w, to get the remainder */ + w -= t+t+t; + + /* fixup the remainder as required since + * the optimization is not exact. + */ + while (w >= 3) { + t += 1; + w -= 3; + } + } else { + t = 0; + } + q.dp[ix] = (mp_digit)t; + } + + /* [optional] store the remainder */ + if (d != NULL) { + *d = (mp_digit)w; + } + + /* [optional] store the quotient */ + if (c != NULL) { + mp_clamp(&q); + mp_exch(&q, c); + } + mp_clear(&q); + + return res; +} + + +/* init an mp_init for a given size */ +int mp_init_size (mp_int * a, int size) +{ + int x; + + /* pad size so there are always extra digits */ + size += (MP_PREC * 2) - (size % MP_PREC); + + /* alloc mem */ + a->dp = OPT_CAST(mp_digit) XMALLOC (sizeof (mp_digit) * size, 0, + DYNAMIC_TYPE_BIGINT); + if (a->dp == NULL) { + return MP_MEM; + } + + /* set the members */ + a->used = 0; + a->alloc = size; + a->sign = MP_ZPOS; + + /* zero the digits */ + for (x = 0; x < size; x++) { + a->dp[x] = 0; + } + + return MP_OKAY; +} + + +/* the jist of squaring... + * you do like mult except the offset of the tmpx [one that + * starts closer to zero] can't equal the offset of tmpy. + * So basically you set up iy like before then you min it with + * (ty-tx) so that it never happens. You double all those + * you add in the inner loop + +After that loop you do the squares and add them in. +*/ + +int fast_s_mp_sqr (mp_int * a, mp_int * b) +{ + int olduse, res, pa, ix, iz; + mp_digit W[MP_WARRAY], *tmpx; + mp_word W1; + + /* grow the destination as required */ + pa = a->used + a->used; + if (b->alloc < pa) { + if ((res = mp_grow (b, pa)) != MP_OKAY) { + return res; + } + } + + /* number of output digits to produce */ + W1 = 0; + for (ix = 0; ix < pa; ix++) { + int tx, ty, iy; + mp_word _W; + mp_digit *tmpy; + + /* clear counter */ + _W = 0; + + /* 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, essentially + 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); + + /* execute loop */ + for (iz = 0; iz < iy; iz++) { + _W += ((mp_word)*tmpx++)*((mp_word)*tmpy--); + } + + /* double the inner product and add carry */ + _W = _W + _W + W1; + + /* even columns have the square term in them */ + if ((ix&1) == 0) { + _W += ((mp_word)a->dp[ix>>1])*((mp_word)a->dp[ix>>1]); + } + + /* store it */ + W[ix] = (mp_digit)(_W & MP_MASK); + + /* make next carry */ + W1 = _W >> ((mp_word)DIGIT_BIT); + } + + /* setup dest */ + olduse = b->used; + b->used = a->used+a->used; + + { + mp_digit *tmpb; + tmpb = b->dp; + for (ix = 0; ix < pa; ix++) { + *tmpb++ = W[ix] & MP_MASK; + } + + /* clear unused digits [that existed in the old copy of c] */ + for (; ix < olduse; ix++) { + *tmpb++ = 0; + } + } + mp_clamp (b); + return MP_OKAY; +} + + +/* Fast (comba) multiplier + * + * This is the fast column-array [comba] multiplier. It is + * designed to compute the columns of the product first + * then handle the carries afterwards. This has the effect + * of making the nested loops that compute the columns very + * simple and schedulable on super-scalar processors. + * + * This has been modified to produce a variable number of + * digits of output so if say only a half-product is required + * you don't have to compute the upper half (a feature + * required for fast Barrett reduction). + * + * Based on Algorithm 14.12 on pp.595 of HAC. + * + */ +int fast_s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs) +{ + int olduse, res, pa, ix, iz; + mp_digit W[MP_WARRAY]; + register mp_word _W; + + /* grow the destination as required */ + if (c->alloc < digs) { + if ((res = mp_grow (c, digs)) != MP_OKAY) { + return res; + } + } + + /* number of output digits to produce */ + pa = MIN(digs, a->used + b->used); + + /* clear the carry */ + _W = 0; + for (ix = 0; ix < pa; ix++) { + int tx, ty; + int iy; + mp_digit *tmpx, *tmpy; + + /* get offsets into the two bignums */ + ty = MIN(b->used-1, ix); + 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 + while (tx++ < a->used && ty-- >= 0) { ... } + */ + iy = MIN(a->used-tx, ty+1); + + /* execute loop */ + for (iz = 0; iz < iy; ++iz) { + _W += ((mp_word)*tmpx++)*((mp_word)*tmpy--); + + } + + /* store term */ + W[ix] = ((mp_digit)_W) & MP_MASK; + + /* make next carry */ + _W = _W >> ((mp_word)DIGIT_BIT); + } + + /* setup dest */ + olduse = c->used; + c->used = pa; + + { + register mp_digit *tmpc; + tmpc = c->dp; + for (ix = 0; ix < pa+1; ix++) { + /* now extract the previous digit [below the carry] */ + *tmpc++ = W[ix]; + } + + /* clear unused digits [that existed in the old copy of c] */ + for (; ix < olduse; ix++) { + *tmpc++ = 0; + } + } + mp_clamp (c); + return MP_OKAY; +} + + +/* low level squaring, b = a*a, HAC pp.596-597, Algorithm 14.16 */ +int s_mp_sqr (mp_int * a, mp_int * b) +{ + mp_int t; + int res, ix, iy, pa; + mp_word r; + mp_digit u, tmpx, *tmpt; + + pa = a->used; + if ((res = mp_init_size (&t, 2*pa + 1)) != MP_OKAY) { + return res; + } + + /* default used is maximum possible size */ + t.used = 2*pa + 1; + + for (ix = 0; ix < pa; ix++) { + /* first calculate the digit at 2*ix */ + /* calculate double precision result */ + r = ((mp_word) t.dp[2*ix]) + + ((mp_word)a->dp[ix])*((mp_word)a->dp[ix]); + + /* store lower part in result */ + t.dp[ix+ix] = (mp_digit) (r & ((mp_word) MP_MASK)); + + /* get the carry */ + u = (mp_digit)(r >> ((mp_word) DIGIT_BIT)); + + /* left hand side of A[ix] * A[iy] */ + tmpx = a->dp[ix]; + + /* alias for where to store the results */ + tmpt = t.dp + (2*ix + 1); + + for (iy = ix + 1; iy < pa; iy++) { + /* first calculate the product */ + r = ((mp_word)tmpx) * ((mp_word)a->dp[iy]); + + /* now calculate the double precision result, note we use + * addition instead of *2 since it's easier to optimize + */ + r = ((mp_word) *tmpt) + r + r + ((mp_word) u); + + /* store lower part */ + *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK)); + + /* get carry */ + u = (mp_digit)(r >> ((mp_word) DIGIT_BIT)); + } + /* propagate upwards */ + while (u != ((mp_digit) 0)) { + r = ((mp_word) *tmpt) + ((mp_word) u); + *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK)); + u = (mp_digit)(r >> ((mp_word) DIGIT_BIT)); + } + } + + mp_clamp (&t); + mp_exch (&t, b); + mp_clear (&t); + return MP_OKAY; +} + + +/* multiplies |a| * |b| and only computes upto digs digits of result + * HAC pp. 595, Algorithm 14.12 Modified so you can control how + * many digits of output are created. + */ +int s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs) +{ + mp_int t; + int res, pa, pb, ix, iy; + mp_digit u; + mp_word r; + mp_digit tmpx, *tmpt, *tmpy; + + /* can we use the fast multiplier? */ + if (((digs) < MP_WARRAY) && + MIN (a->used, b->used) < + (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) { + return fast_s_mp_mul_digs (a, b, c, digs); + } + + if ((res = mp_init_size (&t, digs)) != MP_OKAY) { + return res; + } + t.used = digs; + + /* compute the digits of the product directly */ + pa = a->used; + for (ix = 0; ix < pa; ix++) { + /* set the carry to zero */ + u = 0; + + /* limit ourselves to making digs digits of output */ + pb = MIN (b->used, digs - ix); + + /* setup some aliases */ + /* copy of the digit from a used within the nested loop */ + tmpx = a->dp[ix]; + + /* an alias for the destination shifted ix places */ + tmpt = t.dp + ix; + + /* an alias for the digits of b */ + tmpy = b->dp; + + /* compute the columns of the output and propagate the carry */ + for (iy = 0; iy < pb; iy++) { + /* compute the column as a mp_word */ + r = ((mp_word)*tmpt) + + ((mp_word)tmpx) * ((mp_word)*tmpy++) + + ((mp_word) u); + + /* the new column is the lower part of the result */ + *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK)); + + /* get the carry word from the result */ + u = (mp_digit) (r >> ((mp_word) DIGIT_BIT)); + } + /* set carry if it is placed below digs */ + if (ix + iy < digs) { + *tmpt = u; + } + } + + mp_clamp (&t); + mp_exch (&t, c); + + mp_clear (&t); + return MP_OKAY; +} + + +/* + * shifts with subtractions when the result is greater than b. + * + * The method is slightly modified to shift B unconditionally upto just under + * the leading bit of b. This saves alot of multiple precision shifting. + */ +int mp_montgomery_calc_normalization (mp_int * a, mp_int * b) +{ + int x, bits, res; + + /* how many bits of last digit does b use */ + bits = mp_count_bits (b) % DIGIT_BIT; + + if (b->used > 1) { + if ((res = mp_2expt (a, (b->used - 1) * DIGIT_BIT + bits - 1)) != MP_OKAY) { + return res; + } + } else { + mp_set(a, 1); + bits = 1; + } + + + /* now compute C = A * B mod b */ + for (x = bits - 1; x < (int)DIGIT_BIT; x++) { + if ((res = mp_mul_2 (a, a)) != MP_OKAY) { + return res; + } + if (mp_cmp_mag (a, b) != MP_LT) { + if ((res = s_mp_sub (a, b, a)) != MP_OKAY) { + return res; + } + } + } + + return MP_OKAY; +} + + +#ifdef MP_LOW_MEM + #define TAB_SIZE 32 +#else + #define TAB_SIZE 256 +#endif + +int s_mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode) +{ + mp_int M[TAB_SIZE], res, mu; + mp_digit buf; + int err, bitbuf, bitcpy, bitcnt, mode, digidx, x, y, winsize; + int (*redux)(mp_int*,mp_int*,mp_int*); + + /* find window size */ + x = mp_count_bits (X); + if (x <= 7) { + winsize = 2; + } else if (x <= 36) { + winsize = 3; + } else if (x <= 140) { + winsize = 4; + } else if (x <= 450) { + winsize = 5; + } else if (x <= 1303) { + winsize = 6; + } else if (x <= 3529) { + winsize = 7; + } else { + winsize = 8; + } + +#ifdef MP_LOW_MEM + if (winsize > 5) { + winsize = 5; + } +#endif + + /* init M array */ + /* init first cell */ + if ((err = mp_init(&M[1])) != MP_OKAY) { + return err; + } + + /* now init the second half of the array */ + for (x = 1<<(winsize-1); x < (1 << winsize); x++) { + if ((err = mp_init(&M[x])) != MP_OKAY) { + for (y = 1<<(winsize-1); y < x; y++) { + mp_clear (&M[y]); + } + mp_clear(&M[1]); + return err; + } + } + + /* create mu, used for Barrett reduction */ + if ((err = mp_init (&mu)) != MP_OKAY) { + goto LBL_M; + } + + if (redmode == 0) { + if ((err = mp_reduce_setup (&mu, P)) != MP_OKAY) { + goto LBL_MU; + } + redux = mp_reduce; + } else { + if ((err = mp_reduce_2k_setup_l (P, &mu)) != MP_OKAY) { + goto LBL_MU; + } + redux = mp_reduce_2k_l; + } + + /* create M table + * + * The M table contains powers of the 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] + */ + if ((err = mp_mod (G, P, &M[1])) != MP_OKAY) { + goto LBL_MU; + } + + /* compute the value at M[1<<(winsize-1)] by squaring + * M[1] (winsize-1) times + */ + if ((err = mp_copy (&M[1], &M[1 << (winsize - 1)])) != MP_OKAY) { + goto LBL_MU; + } + + for (x = 0; x < (winsize - 1); x++) { + /* square it */ + if ((err = mp_sqr (&M[1 << (winsize - 1)], + &M[1 << (winsize - 1)])) != MP_OKAY) { + goto LBL_MU; + } + + /* reduce modulo P */ + if ((err = redux (&M[1 << (winsize - 1)], P, &mu)) != MP_OKAY) { + goto LBL_MU; + } + } + + /* create upper table, that is M[x] = M[x-1] * M[1] (mod P) + * for x = (2**(winsize - 1) + 1) to (2**winsize - 1) + */ + for (x = (1 << (winsize - 1)) + 1; x < (1 << winsize); x++) { + if ((err = mp_mul (&M[x - 1], &M[1], &M[x])) != MP_OKAY) { + goto LBL_MU; + } + if ((err = redux (&M[x], P, &mu)) != MP_OKAY) { + goto LBL_MU; + } + } + + /* setup result */ + if ((err = mp_init (&res)) != MP_OKAY) { + goto LBL_MU; + } + mp_set (&res, 1); + + /* 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 */ + if (digidx == -1) { + break; + } + /* read next digit and reset the bitcnt */ + buf = X->dp[digidx--]; + bitcnt = (int) DIGIT_BIT; + } + + /* grab the next msb from the exponent */ + y = (buf >> (mp_digit)(DIGIT_BIT - 1)) & 1; + buf <<= (mp_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) { + if ((err = mp_sqr (&res, &res)) != MP_OKAY) { + goto LBL_RES; + } + if ((err = redux (&res, P, &mu)) != MP_OKAY) { + goto LBL_RES; + } + 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++) { + if ((err = mp_sqr (&res, &res)) != MP_OKAY) { + goto LBL_RES; + } + if ((err = redux (&res, P, &mu)) != MP_OKAY) { + goto LBL_RES; + } + } + + /* then multiply */ + if ((err = mp_mul (&res, &M[bitbuf], &res)) != MP_OKAY) { + goto LBL_RES; + } + if ((err = redux (&res, P, &mu)) != MP_OKAY) { + goto LBL_RES; + } + + /* 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++) { + if ((err = mp_sqr (&res, &res)) != MP_OKAY) { + goto LBL_RES; + } + if ((err = redux (&res, P, &mu)) != MP_OKAY) { + goto LBL_RES; + } + + bitbuf <<= 1; + if ((bitbuf & (1 << winsize)) != 0) { + /* then multiply */ + if ((err = mp_mul (&res, &M[1], &res)) != MP_OKAY) { + goto LBL_RES; + } + if ((err = redux (&res, P, &mu)) != MP_OKAY) { + goto LBL_RES; + } + } + } + } + + mp_exch (&res, Y); + err = MP_OKAY; +LBL_RES:mp_clear (&res); +LBL_MU:mp_clear (&mu); +LBL_M: + mp_clear(&M[1]); + for (x = 1<<(winsize-1); x < (1 << winsize); x++) { + mp_clear (&M[x]); + } + return err; +} + + +/* pre-calculate the value required for Barrett reduction + * For a given modulus "b" it calulates the value required in "a" + */ +int mp_reduce_setup (mp_int * a, mp_int * b) +{ + int res; + + if ((res = mp_2expt (a, b->used * 2 * DIGIT_BIT)) != MP_OKAY) { + return res; + } + return mp_div (a, b, a, NULL); +} + + +/* reduces x mod m, assumes 0 < x < m**2, mu is + * precomputed via mp_reduce_setup. + * From HAC pp.604 Algorithm 14.42 + */ +int mp_reduce (mp_int * x, mp_int * m, mp_int * mu) +{ + mp_int q; + int res, um = m->used; + + /* q = x */ + if ((res = mp_init_copy (&q, x)) != MP_OKAY) { + return res; + } + + /* q1 = x / b**(k-1) */ + mp_rshd (&q, um - 1); + + /* according to HAC this optimization is ok */ + if (((unsigned long) um) > (((mp_digit)1) << (DIGIT_BIT - 1))) { + if ((res = mp_mul (&q, mu, &q)) != MP_OKAY) { + goto CLEANUP; + } + } else { +#ifdef BN_S_MP_MUL_HIGH_DIGS_C + if ((res = s_mp_mul_high_digs (&q, mu, &q, um)) != MP_OKAY) { + goto CLEANUP; + } +#elif defined(BN_FAST_S_MP_MUL_HIGH_DIGS_C) + if ((res = fast_s_mp_mul_high_digs (&q, mu, &q, um)) != MP_OKAY) { + goto CLEANUP; + } +#else + { + res = MP_VAL; + goto CLEANUP; + } +#endif + } + + /* q3 = q2 / b**(k+1) */ + mp_rshd (&q, um + 1); + + /* x = x mod b**(k+1), quick (no division) */ + if ((res = mp_mod_2d (x, DIGIT_BIT * (um + 1), x)) != MP_OKAY) { + goto CLEANUP; + } + + /* q = q * m mod b**(k+1), quick (no division) */ + if ((res = s_mp_mul_digs (&q, m, &q, um + 1)) != MP_OKAY) { + goto CLEANUP; + } + + /* x = x - q */ + if ((res = mp_sub (x, &q, x)) != MP_OKAY) { + goto CLEANUP; + } + + /* If x < 0, add b**(k+1) to it */ + if (mp_cmp_d (x, 0) == MP_LT) { + mp_set (&q, 1); + if ((res = mp_lshd (&q, um + 1)) != MP_OKAY) + goto CLEANUP; + if ((res = mp_add (x, &q, x)) != MP_OKAY) + goto CLEANUP; + } + + /* Back off if it's too big */ + while (mp_cmp (x, m) != MP_LT) { + if ((res = s_mp_sub (x, m, x)) != MP_OKAY) { + goto CLEANUP; + } + } + +CLEANUP: + mp_clear (&q); + + return res; +} + + +/* reduces a modulo n where n is of the form 2**p - d + This differs from reduce_2k since "d" can be larger + than a single digit. +*/ +int mp_reduce_2k_l(mp_int *a, mp_int *n, mp_int *d) +{ + mp_int q; + int p, res; + + if ((res = mp_init(&q)) != MP_OKAY) { + return res; + } + + p = mp_count_bits(n); +top: + /* q = a/2**p, a = a mod 2**p */ + if ((res = mp_div_2d(a, p, &q, a)) != MP_OKAY) { + goto ERR; + } + + /* q = q * d */ + if ((res = mp_mul(&q, d, &q)) != MP_OKAY) { + goto ERR; + } + + /* a = a + q */ + if ((res = s_mp_add(a, &q, a)) != MP_OKAY) { + goto ERR; + } + + if (mp_cmp_mag(a, n) != MP_LT) { + s_mp_sub(a, n, a); + goto top; + } + +ERR: + mp_clear(&q); + return res; +} + + +/* determines the setup value */ +int mp_reduce_2k_setup_l(mp_int *a, mp_int *d) +{ + int res; + mp_int tmp; + + if ((res = mp_init(&tmp)) != MP_OKAY) { + return res; + } + + if ((res = mp_2expt(&tmp, mp_count_bits(a))) != MP_OKAY) { + goto ERR; + } + + if ((res = s_mp_sub(&tmp, a, d)) != MP_OKAY) { + goto ERR; + } + +ERR: + mp_clear(&tmp); + return res; +} + + +/* multiplies |a| * |b| and does not compute the lower digs digits + * [meant to get the higher part of the product] + */ +int +s_mp_mul_high_digs (mp_int * a, mp_int * b, mp_int * c, int digs) +{ + mp_int t; + int res, pa, pb, ix, iy; + mp_digit u; + mp_word r; + mp_digit tmpx, *tmpt, *tmpy; + + /* can we use the fast multiplier? */ +#ifdef BN_FAST_S_MP_MUL_HIGH_DIGS_C + if (((a->used + b->used + 1) < MP_WARRAY) + && MIN (a->used, b->used) < (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) { + return fast_s_mp_mul_high_digs (a, b, c, digs); + } +#endif + + if ((res = mp_init_size (&t, a->used + b->used + 1)) != MP_OKAY) { + return res; + } + t.used = a->used + b->used + 1; + + pa = a->used; + pb = b->used; + for (ix = 0; ix < pa; ix++) { + /* clear the carry */ + u = 0; + + /* left hand side of A[ix] * B[iy] */ + tmpx = a->dp[ix]; + + /* alias to the address of where the digits will be stored */ + tmpt = &(t.dp[digs]); + + /* alias for where to read the right hand side from */ + tmpy = b->dp + (digs - ix); + + for (iy = digs - ix; iy < pb; iy++) { + /* calculate the double precision result */ + r = ((mp_word)*tmpt) + + ((mp_word)tmpx) * ((mp_word)*tmpy++) + + ((mp_word) u); + + /* get the lower part */ + *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK)); + + /* carry the carry */ + u = (mp_digit) (r >> ((mp_word) DIGIT_BIT)); + } + *tmpt = u; + } + mp_clamp (&t); + mp_exch (&t, c); + mp_clear (&t); + return MP_OKAY; +} + + +/* this is a modified version of fast_s_mul_digs that only produces + * output digits *above* digs. See the comments for fast_s_mul_digs + * to see how it works. + * + * This is used in the Barrett reduction since for one of the multiplications + * only the higher digits were needed. This essentially halves the work. + * + * Based on Algorithm 14.12 on pp.595 of HAC. + */ +int fast_s_mp_mul_high_digs (mp_int * a, mp_int * b, mp_int * c, int digs) +{ + int olduse, res, pa, ix, iz; + mp_digit W[MP_WARRAY]; + mp_word _W; + + /* grow the destination as required */ + pa = a->used + b->used; + if (c->alloc < pa) { + if ((res = mp_grow (c, pa)) != MP_OKAY) { + return res; + } + } + + /* number of output digits to produce */ + pa = a->used + b->used; + _W = 0; + for (ix = digs; ix < pa; ix++) { + int tx, ty, iy; + mp_digit *tmpx, *tmpy; + + /* get offsets into the two bignums */ + ty = MIN(b->used-1, ix); + 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 */ + for (iz = 0; iz < iy; iz++) { + _W += ((mp_word)*tmpx++)*((mp_word)*tmpy--); + } + + /* store term */ + W[ix] = ((mp_digit)_W) & MP_MASK; + + /* make next carry */ + _W = _W >> ((mp_word)DIGIT_BIT); + } + + /* setup dest */ + olduse = c->used; + c->used = pa; + + { + register mp_digit *tmpc; + + tmpc = c->dp + digs; + for (ix = digs; ix <= pa; ix++) { + /* now extract the previous digit [below the carry] */ + *tmpc++ = W[ix]; + } + + /* clear unused digits [that existed in the old copy of c] */ + for (; ix < olduse; ix++) { + *tmpc++ = 0; + } + } + mp_clamp (c); + return MP_OKAY; +} + + +#if defined(CYASSL_KEY_GEN) || defined(HAVE_ECC) + +/* c = a * a (mod b) */ +int mp_sqrmod (mp_int * a, mp_int * b, mp_int * c) +{ + int res; + mp_int t; + + if ((res = mp_init (&t)) != MP_OKAY) { + return res; + } + + if ((res = mp_sqr (a, &t)) != MP_OKAY) { + mp_clear (&t); + return res; + } + res = mp_mod (&t, b, c); + mp_clear (&t); + return res; +} + + +int mp_sub_d (mp_int* a, mp_digit b, mp_int* c); + +/* single digit addition */ +int mp_add_d (mp_int* a, mp_digit b, mp_int* c) +{ + int res, ix, oldused; + mp_digit *tmpa, *tmpc, mu; + + /* grow c as required */ + if (c->alloc < a->used + 1) { + if ((res = mp_grow(c, a->used + 1)) != MP_OKAY) { + return res; + } + } + + /* if a is negative and |a| >= b, call c = |a| - b */ + if (a->sign == MP_NEG && (a->used > 1 || a->dp[0] >= b)) { + /* temporarily fix sign of a */ + a->sign = MP_ZPOS; + + /* c = |a| - b */ + res = mp_sub_d(a, b, c); + + /* fix sign */ + a->sign = c->sign = MP_NEG; + + /* clamp */ + mp_clamp(c); + + return res; + } + + /* old number of used digits in c */ + oldused = c->used; + + /* sign always positive */ + c->sign = MP_ZPOS; + + /* source alias */ + tmpa = a->dp; + + /* destination alias */ + tmpc = c->dp; + + /* if a is positive */ + if (a->sign == MP_ZPOS) { + /* add digit, after this we're propagating + * the carry. + */ + *tmpc = *tmpa++ + b; + mu = *tmpc >> DIGIT_BIT; + *tmpc++ &= MP_MASK; + + /* now handle rest of the digits */ + for (ix = 1; ix < a->used; ix++) { + *tmpc = *tmpa++ + mu; + mu = *tmpc >> DIGIT_BIT; + *tmpc++ &= MP_MASK; + } + /* set final carry */ + ix++; + *tmpc++ = mu; + + /* setup size */ + c->used = a->used + 1; + } else { + /* a was negative and |a| < b */ + c->used = 1; + + /* the result is a single digit */ + if (a->used == 1) { + *tmpc++ = b - a->dp[0]; + } else { + *tmpc++ = b; + } + + /* setup count so the clearing of oldused + * can fall through correctly + */ + ix = 1; + } + + /* now zero to oldused */ + while (ix++ < oldused) { + *tmpc++ = 0; + } + mp_clamp(c); + + return MP_OKAY; +} + + +/* single digit subtraction */ +int mp_sub_d (mp_int * a, mp_digit b, mp_int * c) +{ + mp_digit *tmpa, *tmpc, mu; + int res, ix, oldused; + + /* grow c as required */ + if (c->alloc < a->used + 1) { + if ((res = mp_grow(c, a->used + 1)) != MP_OKAY) { + return res; + } + } + + /* if a is negative just do an unsigned + * addition [with fudged signs] + */ + if (a->sign == MP_NEG) { + a->sign = MP_ZPOS; + res = mp_add_d(a, b, c); + a->sign = c->sign = MP_NEG; + + /* clamp */ + mp_clamp(c); + + return res; + } + + /* setup regs */ + oldused = c->used; + tmpa = a->dp; + tmpc = c->dp; + + /* if a <= b simply fix the single digit */ + if ((a->used == 1 && a->dp[0] <= b) || a->used == 0) { + if (a->used == 1) { + *tmpc++ = b - *tmpa; + } else { + *tmpc++ = b; + } + ix = 1; + + /* negative/1digit */ + c->sign = MP_NEG; + c->used = 1; + } else { + /* positive/size */ + c->sign = MP_ZPOS; + c->used = a->used; + + /* subtract first digit */ + *tmpc = *tmpa++ - b; + mu = *tmpc >> (sizeof(mp_digit) * CHAR_BIT - 1); + *tmpc++ &= MP_MASK; + + /* handle rest of the digits */ + for (ix = 1; ix < a->used; ix++) { + *tmpc = *tmpa++ - mu; + mu = *tmpc >> (sizeof(mp_digit) * CHAR_BIT - 1); + *tmpc++ &= MP_MASK; + } + } + + /* zero excess digits */ + while (ix++ < oldused) { + *tmpc++ = 0; + } + mp_clamp(c); + return MP_OKAY; +} + +#endif /* CYASSL_KEY_GEN || HAVE_ECC */ + + +#ifdef CYASSL_KEY_GEN + +int mp_cnt_lsb(mp_int *a); + +static int s_is_power_of_two(mp_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 == (((mp_digit)1)<dp[0] & ((((mp_digit)1)<used)) != MP_OKAY) { + return res; + } + + q.used = a->used; + q.sign = a->sign; + w = 0; + for (ix = a->used - 1; ix >= 0; ix--) { + w = (w << ((mp_word)DIGIT_BIT)) | ((mp_word)a->dp[ix]); + + if (w >= b) { + t = (mp_digit)(w / b); + w -= ((mp_word)t) * ((mp_word)b); + } else { + t = 0; + } + q.dp[ix] = (mp_digit)t; + } + + if (d != NULL) { + *d = (mp_digit)w; + } + + if (c != NULL) { + mp_clamp(&q); + mp_exch(&q, c); + } + mp_clear(&q); + + return res; +} + + +int mp_mod_d (mp_int * a, mp_digit b, mp_digit * c) +{ + return mp_div_d(a, b, NULL, c); +} + + +const mp_digit ltm_prime_tab[] = { + 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, +#ifndef MP_8BIT + 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 +#endif +}; + + +/* 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. + */ +int mp_prime_miller_rabin (mp_int * a, mp_int * b, int *result) +{ + mp_int n1, y, r; + int s, j, err; + + /* default */ + *result = MP_NO; + + /* ensure b > 1 */ + if (mp_cmp_d(b, 1) != MP_GT) { + return MP_VAL; + } + + /* get n1 = a - 1 */ + if ((err = mp_init_copy (&n1, a)) != MP_OKAY) { + return err; + } + if ((err = mp_sub_d (&n1, 1, &n1)) != MP_OKAY) { + goto LBL_N1; + } + + /* set 2**s * r = n1 */ + if ((err = mp_init_copy (&r, &n1)) != MP_OKAY) { + goto LBL_N1; + } + + /* count the number of least significant bits + * which are zero + */ + s = mp_cnt_lsb(&r); + + /* now divide n - 1 by 2**s */ + if ((err = mp_div_2d (&r, s, &r, NULL)) != MP_OKAY) { + goto LBL_R; + } + + /* compute y = b**r mod a */ + if ((err = mp_init (&y)) != MP_OKAY) { + goto LBL_R; + } + if ((err = mp_exptmod (b, &r, a, &y)) != MP_OKAY) { + goto LBL_Y; + } + + /* if y != 1 and y != n1 do */ + if (mp_cmp_d (&y, 1) != MP_EQ && mp_cmp (&y, &n1) != MP_EQ) { + j = 1; + /* while j <= s-1 and y != n1 */ + while ((j <= (s - 1)) && mp_cmp (&y, &n1) != MP_EQ) { + if ((err = mp_sqrmod (&y, a, &y)) != MP_OKAY) { + goto LBL_Y; + } + + /* if y == 1 then composite */ + if (mp_cmp_d (&y, 1) == MP_EQ) { + goto LBL_Y; + } + + ++j; + } + + /* if y != n1 then composite */ + if (mp_cmp (&y, &n1) != MP_EQ) { + goto LBL_Y; + } + } + + /* probably prime now */ + *result = MP_YES; +LBL_Y:mp_clear (&y); +LBL_R:mp_clear (&r); +LBL_N1:mp_clear (&n1); + return err; +} + + +/* determines if an integers is divisible by one + * of the first PRIME_SIZE primes or not + * + * sets result to 0 if not, 1 if yes + */ +int mp_prime_is_divisible (mp_int * a, int *result) +{ + int err, ix; + mp_digit res; + + /* default to not */ + *result = MP_NO; + + for (ix = 0; ix < PRIME_SIZE; ix++) { + /* what is a mod LBL_prime_tab[ix] */ + if ((err = mp_mod_d (a, ltm_prime_tab[ix], &res)) != MP_OKAY) { + return err; + } + + /* is the residue zero? */ + if (res == 0) { + *result = MP_YES; + return MP_OKAY; + } + } + + return MP_OKAY; +} + + +/* + * Sets result to 1 if probably prime, 0 otherwise + */ +int mp_prime_is_prime (mp_int * a, int t, int *result) +{ + mp_int b; + int ix, err, res; + + /* default to no */ + *result = MP_NO; + + /* valid value of t? */ + if (t <= 0 || t > PRIME_SIZE) { + return MP_VAL; + } + + /* is the input equal to one of the primes in the table? */ + for (ix = 0; ix < PRIME_SIZE; ix++) { + if (mp_cmp_d(a, ltm_prime_tab[ix]) == MP_EQ) { + *result = 1; + return MP_OKAY; + } + } + + /* first perform trial division */ + if ((err = mp_prime_is_divisible (a, &res)) != MP_OKAY) { + return err; + } + + /* return if it was trivially divisible */ + if (res == MP_YES) { + return MP_OKAY; + } + + /* now perform the miller-rabin rounds */ + if ((err = mp_init (&b)) != MP_OKAY) { + return err; + } + + for (ix = 0; ix < t; ix++) { + /* set the prime */ + mp_set (&b, ltm_prime_tab[ix]); + + if ((err = mp_prime_miller_rabin (a, &b, &res)) != MP_OKAY) { + goto LBL_B; + } + + if (res == MP_NO) { + goto LBL_B; + } + } + + /* passed the test */ + *result = MP_YES; +LBL_B:mp_clear (&b); + return err; +} + + +/* computes least common multiple as |a*b|/(a, b) */ +int mp_lcm (mp_int * a, mp_int * b, mp_int * c) +{ + int res; + mp_int t1, t2; + + + if ((res = mp_init_multi (&t1, &t2, NULL, NULL, NULL, NULL)) != MP_OKAY) { + return res; + } + + /* t1 = get the GCD of the two inputs */ + if ((res = mp_gcd (a, b, &t1)) != MP_OKAY) { + goto LBL_T; + } + + /* divide the smallest by the GCD */ + if (mp_cmp_mag(a, b) == MP_LT) { + /* store quotient in t2 such that t2 * b is the LCM */ + if ((res = mp_div(a, &t1, &t2, NULL)) != MP_OKAY) { + goto LBL_T; + } + res = mp_mul(b, &t2, c); + } else { + /* store quotient in t2 such that t2 * a is the LCM */ + if ((res = mp_div(b, &t1, &t2, NULL)) != MP_OKAY) { + goto LBL_T; + } + res = mp_mul(a, &t2, c); + } + + /* fix the sign to positive */ + c->sign = MP_ZPOS; + +LBL_T: + mp_clear(&t1); + mp_clear(&t2); + return res; +} + + +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 mp_cnt_lsb(mp_int *a) +{ + int x; + mp_digit q, qq; + + /* easy out */ + if (mp_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; +} + + +/* Greatest Common Divisor using the binary method */ +int mp_gcd (mp_int * a, mp_int * b, mp_int * c) +{ + mp_int u, v; + int k, u_lsb, v_lsb, res; + + /* either zero than gcd is the largest */ + if (mp_iszero (a) == MP_YES) { + return mp_abs (b, c); + } + if (mp_iszero (b) == MP_YES) { + return mp_abs (a, c); + } + + /* get copies of a and b we can modify */ + if ((res = mp_init_copy (&u, a)) != MP_OKAY) { + return res; + } + + if ((res = mp_init_copy (&v, b)) != MP_OKAY) { + goto LBL_U; + } + + /* must be positive for the remainder of the algorithm */ + u.sign = v.sign = MP_ZPOS; + + /* B1. Find the common power of two for u and v */ + u_lsb = mp_cnt_lsb(&u); + v_lsb = mp_cnt_lsb(&v); + k = MIN(u_lsb, v_lsb); + + if (k > 0) { + /* divide the power of two out */ + if ((res = mp_div_2d(&u, k, &u, NULL)) != MP_OKAY) { + goto LBL_V; + } + + if ((res = mp_div_2d(&v, k, &v, NULL)) != MP_OKAY) { + goto LBL_V; + } + } + + /* divide any remaining factors of two out */ + if (u_lsb != k) { + if ((res = mp_div_2d(&u, u_lsb - k, &u, NULL)) != MP_OKAY) { + goto LBL_V; + } + } + + if (v_lsb != k) { + if ((res = mp_div_2d(&v, v_lsb - k, &v, NULL)) != MP_OKAY) { + goto LBL_V; + } + } + + while (mp_iszero(&v) == 0) { + /* make sure v is the largest */ + if (mp_cmp_mag(&u, &v) == MP_GT) { + /* swap u and v to make sure v is >= u */ + mp_exch(&u, &v); + } + + /* subtract smallest from largest */ + if ((res = s_mp_sub(&v, &u, &v)) != MP_OKAY) { + goto LBL_V; + } + + /* Divide out all factors of two */ + if ((res = mp_div_2d(&v, mp_cnt_lsb(&v), &v, NULL)) != MP_OKAY) { + goto LBL_V; + } + } + + /* multiply by 2**k which we divided out at the beginning */ + if ((res = mp_mul_2d (&u, k, c)) != MP_OKAY) { + goto LBL_V; + } + c->sign = MP_ZPOS; + res = MP_OKAY; +LBL_V:mp_clear (&u); +LBL_U:mp_clear (&v); + return res; +} + + +/* set a 32-bit const */ +int mp_set_int (mp_int * a, unsigned long b) +{ + int x, res; + + mp_zero (a); + + /* set four bits at a time */ + for (x = 0; x < 8; x++) { + /* shift the number up four bits */ + if ((res = mp_mul_2d (a, 4, a)) != MP_OKAY) { + return res; + } + + /* OR in the top four bits of the source */ + a->dp[0] |= (b >> 28) & 15; + + /* shift the source up to the next four bits */ + b <<= 4; + + /* ensure that digits are not clamped off */ + a->used += 1; + } + mp_clamp (a); + return MP_OKAY; +} + +#endif /* CYASSL_KEY_GEN */ + + +#ifdef HAVE_ECC + +/* chars used in radix conversions */ +const char *mp_s_rmap = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+/"; + +/* read a string [ASCII] in a given radix */ +int mp_read_radix (mp_int * a, const char *str, int radix) +{ + int y, res, neg; + char ch; + + /* zero the digit bignum */ + mp_zero(a); + + /* make sure the radix is ok */ + if (radix < 2 || radix > 64) { + return MP_VAL; + } + + /* if the leading digit is a + * minus set the sign to negative. + */ + if (*str == '-') { + ++str; + neg = MP_NEG; + } else { + neg = MP_ZPOS; + } + + /* set the integer to the default of zero */ + mp_zero (a); + + /* 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) ? XTOUPPER(*str) : *str); + for (y = 0; y < 64; y++) { + if (ch == mp_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) { + if ((res = mp_mul_d (a, (mp_digit) radix, a)) != MP_OKAY) { + return res; + } + if ((res = mp_add_d (a, (mp_digit) y, a)) != MP_OKAY) { + return res; + } + } else { + break; + } + ++str; + } + + /* set the sign only if a != 0 */ + if (mp_iszero(a) != 1) { + a->sign = neg; + } + return MP_OKAY; +} + +#endif /* HAVE_ECC */ + +#endif /* USE_FAST_MATH */ + diff --git a/ctaocrypt/src/md4.c b/ctaocrypt/src/md4.c new file mode 100644 index 000000000..0dcc59d09 --- /dev/null +++ b/ctaocrypt/src/md4.c @@ -0,0 +1,215 @@ +/* md4.c + * + * Copyright (C) 2006-2011 Sawtooth Consulting Ltd. + * + * This file is part of CyaSSL. + * + * CyaSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * CyaSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + + +#ifndef NO_MD4 + +#include "ctc_md4.h" +#ifdef NO_INLINE + #include "misc.h" +#else + #include "misc.c" +#endif + + + +#ifndef min + + static INLINE word32 min(word32 a, word32 b) + { + return a > b ? b : a; + } + +#endif /* min */ + + +void InitMd4(Md4* md4) +{ + md4->digest[0] = 0x67452301L; + md4->digest[1] = 0xefcdab89L; + md4->digest[2] = 0x98badcfeL; + md4->digest[3] = 0x10325476L; + + md4->buffLen = 0; + md4->loLen = 0; + md4->hiLen = 0; +} + + +static void Transform(Md4* md4) +{ +#define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z)))) +#define G(x, y, z) (((x) & (y)) | ((x) & (z)) | ((y) & (z))) +#define H(x, y, z) ((x) ^ (y) ^ (z)) + + /* Copy context->state[] to working vars */ + word32 A = md4->digest[0]; + word32 B = md4->digest[1]; + word32 C = md4->digest[2]; + word32 D = md4->digest[3]; + +#define function(a,b,c,d,k,s) a=rotlFixed(a+F(b,c,d)+md4->buffer[k],s); + function(A,B,C,D, 0, 3); + function(D,A,B,C, 1, 7); + function(C,D,A,B, 2,11); + function(B,C,D,A, 3,19); + function(A,B,C,D, 4, 3); + function(D,A,B,C, 5, 7); + function(C,D,A,B, 6,11); + function(B,C,D,A, 7,19); + function(A,B,C,D, 8, 3); + function(D,A,B,C, 9, 7); + function(C,D,A,B,10,11); + function(B,C,D,A,11,19); + function(A,B,C,D,12, 3); + function(D,A,B,C,13, 7); + function(C,D,A,B,14,11); + function(B,C,D,A,15,19); + +#undef function +#define function(a,b,c,d,k,s) \ + a=rotlFixed(a+G(b,c,d)+md4->buffer[k]+0x5a827999,s); + + function(A,B,C,D, 0, 3); + function(D,A,B,C, 4, 5); + function(C,D,A,B, 8, 9); + function(B,C,D,A,12,13); + function(A,B,C,D, 1, 3); + function(D,A,B,C, 5, 5); + function(C,D,A,B, 9, 9); + function(B,C,D,A,13,13); + function(A,B,C,D, 2, 3); + function(D,A,B,C, 6, 5); + function(C,D,A,B,10, 9); + function(B,C,D,A,14,13); + function(A,B,C,D, 3, 3); + function(D,A,B,C, 7, 5); + function(C,D,A,B,11, 9); + function(B,C,D,A,15,13); + +#undef function +#define function(a,b,c,d,k,s) \ + a=rotlFixed(a+H(b,c,d)+md4->buffer[k]+0x6ed9eba1,s); + + function(A,B,C,D, 0, 3); + function(D,A,B,C, 8, 9); + function(C,D,A,B, 4,11); + function(B,C,D,A,12,15); + function(A,B,C,D, 2, 3); + function(D,A,B,C,10, 9); + function(C,D,A,B, 6,11); + function(B,C,D,A,14,15); + function(A,B,C,D, 1, 3); + function(D,A,B,C, 9, 9); + function(C,D,A,B, 5,11); + function(B,C,D,A,13,15); + function(A,B,C,D, 3, 3); + function(D,A,B,C,11, 9); + function(C,D,A,B, 7,11); + function(B,C,D,A,15,15); + + /* Add the working vars back into digest state[] */ + md4->digest[0] += A; + md4->digest[1] += B; + md4->digest[2] += C; + md4->digest[3] += D; +} + + +static INLINE void AddLength(Md4* md4, word32 len) +{ + word32 tmp = md4->loLen; + if ( (md4->loLen += len) < tmp) + md4->hiLen++; /* carry low to high */ +} + + +void Md4Update(Md4* md4, const byte* data, word32 len) +{ + /* do block size increments */ + byte* local = (byte*)md4->buffer; + + while (len) { + word32 add = min(len, MD4_BLOCK_SIZE - md4->buffLen); + XMEMCPY(&local[md4->buffLen], data, add); + + md4->buffLen += add; + data += add; + len -= add; + + if (md4->buffLen == MD4_BLOCK_SIZE) { + #ifdef BIG_ENDIAN_ORDER + ByteReverseBytes(local, local, MD4_BLOCK_SIZE); + #endif + Transform(md4); + AddLength(md4, MD4_BLOCK_SIZE); + md4->buffLen = 0; + } + } +} + + +void Md4Final(Md4* md4, byte* hash) +{ + byte* local = (byte*)md4->buffer; + + AddLength(md4, md4->buffLen); /* before adding pads */ + + local[md4->buffLen++] = 0x80; /* add 1 */ + + /* pad with zeros */ + if (md4->buffLen > MD4_PAD_SIZE) { + XMEMSET(&local[md4->buffLen], 0, MD4_BLOCK_SIZE - md4->buffLen); + md4->buffLen += MD4_BLOCK_SIZE - md4->buffLen; + + #ifdef BIG_ENDIAN_ORDER + ByteReverseBytes(local, local, MD4_BLOCK_SIZE); + #endif + Transform(md4); + md4->buffLen = 0; + } + XMEMSET(&local[md4->buffLen], 0, MD4_PAD_SIZE - md4->buffLen); + + /* put lengths in bits */ + md4->loLen = md4->loLen << 3; + md4->hiLen = (md4->loLen >> (8*sizeof(md4->loLen) - 3)) + + (md4->hiLen << 3); + + /* store lengths */ + #ifdef BIG_ENDIAN_ORDER + ByteReverseBytes(local, local, MD4_BLOCK_SIZE); + #endif + /* ! length ordering dependent on digest endian type ! */ + XMEMCPY(&local[MD4_PAD_SIZE], &md4->loLen, sizeof(word32)); + XMEMCPY(&local[MD4_PAD_SIZE + sizeof(word32)], &md4->hiLen, sizeof(word32)); + + Transform(md4); + #ifdef BIG_ENDIAN_ORDER + ByteReverseWords(md4->digest, md4->digest, MD4_DIGEST_SIZE); + #endif + XMEMCPY(hash, md4->digest, MD4_DIGEST_SIZE); + + InitMd4(md4); /* reset state */ +} + + +#endif /* NO_MD4 */ + diff --git a/ctaocrypt/src/md5.c b/ctaocrypt/src/md5.c new file mode 100644 index 000000000..6ee957ae9 --- /dev/null +++ b/ctaocrypt/src/md5.c @@ -0,0 +1,222 @@ +/* md5.c + * + * Copyright (C) 2006-2011 Sawtooth Consulting Ltd. + * + * This file is part of CyaSSL. + * + * CyaSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * CyaSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + + +#include "ctc_md5.h" +#ifdef NO_INLINE + #include "misc.h" +#else + #include "misc.c" +#endif + + + +#ifndef min + + static INLINE word32 min(word32 a, word32 b) + { + return a > b ? b : a; + } + +#endif /* min */ + + +void InitMd5(Md5* md5) +{ + md5->digest[0] = 0x67452301L; + md5->digest[1] = 0xefcdab89L; + md5->digest[2] = 0x98badcfeL; + md5->digest[3] = 0x10325476L; + + md5->buffLen = 0; + md5->loLen = 0; + md5->hiLen = 0; +} + + +static void Transform(Md5* md5) +{ +#define F1(x, y, z) (z ^ (x & (y ^ z))) +#define F2(x, y, z) F1(z, x, y) +#define F3(x, y, z) (x ^ y ^ z) +#define F4(x, y, z) (y ^ (x | ~z)) + +#define MD5STEP(f, w, x, y, z, data, s) \ + w = rotlFixed(w + f(x, y, z) + data, s) + x + + /* Copy context->state[] to working vars */ + word32 a = md5->digest[0]; + word32 b = md5->digest[1]; + word32 c = md5->digest[2]; + word32 d = md5->digest[3]; + + MD5STEP(F1, a, b, c, d, md5->buffer[0] + 0xd76aa478, 7); + MD5STEP(F1, d, a, b, c, md5->buffer[1] + 0xe8c7b756, 12); + MD5STEP(F1, c, d, a, b, md5->buffer[2] + 0x242070db, 17); + MD5STEP(F1, b, c, d, a, md5->buffer[3] + 0xc1bdceee, 22); + MD5STEP(F1, a, b, c, d, md5->buffer[4] + 0xf57c0faf, 7); + MD5STEP(F1, d, a, b, c, md5->buffer[5] + 0x4787c62a, 12); + MD5STEP(F1, c, d, a, b, md5->buffer[6] + 0xa8304613, 17); + MD5STEP(F1, b, c, d, a, md5->buffer[7] + 0xfd469501, 22); + MD5STEP(F1, a, b, c, d, md5->buffer[8] + 0x698098d8, 7); + MD5STEP(F1, d, a, b, c, md5->buffer[9] + 0x8b44f7af, 12); + MD5STEP(F1, c, d, a, b, md5->buffer[10] + 0xffff5bb1, 17); + MD5STEP(F1, b, c, d, a, md5->buffer[11] + 0x895cd7be, 22); + MD5STEP(F1, a, b, c, d, md5->buffer[12] + 0x6b901122, 7); + MD5STEP(F1, d, a, b, c, md5->buffer[13] + 0xfd987193, 12); + MD5STEP(F1, c, d, a, b, md5->buffer[14] + 0xa679438e, 17); + MD5STEP(F1, b, c, d, a, md5->buffer[15] + 0x49b40821, 22); + + MD5STEP(F2, a, b, c, d, md5->buffer[1] + 0xf61e2562, 5); + MD5STEP(F2, d, a, b, c, md5->buffer[6] + 0xc040b340, 9); + MD5STEP(F2, c, d, a, b, md5->buffer[11] + 0x265e5a51, 14); + MD5STEP(F2, b, c, d, a, md5->buffer[0] + 0xe9b6c7aa, 20); + MD5STEP(F2, a, b, c, d, md5->buffer[5] + 0xd62f105d, 5); + MD5STEP(F2, d, a, b, c, md5->buffer[10] + 0x02441453, 9); + MD5STEP(F2, c, d, a, b, md5->buffer[15] + 0xd8a1e681, 14); + MD5STEP(F2, b, c, d, a, md5->buffer[4] + 0xe7d3fbc8, 20); + MD5STEP(F2, a, b, c, d, md5->buffer[9] + 0x21e1cde6, 5); + MD5STEP(F2, d, a, b, c, md5->buffer[14] + 0xc33707d6, 9); + MD5STEP(F2, c, d, a, b, md5->buffer[3] + 0xf4d50d87, 14); + MD5STEP(F2, b, c, d, a, md5->buffer[8] + 0x455a14ed, 20); + MD5STEP(F2, a, b, c, d, md5->buffer[13] + 0xa9e3e905, 5); + MD5STEP(F2, d, a, b, c, md5->buffer[2] + 0xfcefa3f8, 9); + MD5STEP(F2, c, d, a, b, md5->buffer[7] + 0x676f02d9, 14); + MD5STEP(F2, b, c, d, a, md5->buffer[12] + 0x8d2a4c8a, 20); + + MD5STEP(F3, a, b, c, d, md5->buffer[5] + 0xfffa3942, 4); + MD5STEP(F3, d, a, b, c, md5->buffer[8] + 0x8771f681, 11); + MD5STEP(F3, c, d, a, b, md5->buffer[11] + 0x6d9d6122, 16); + MD5STEP(F3, b, c, d, a, md5->buffer[14] + 0xfde5380c, 23); + MD5STEP(F3, a, b, c, d, md5->buffer[1] + 0xa4beea44, 4); + MD5STEP(F3, d, a, b, c, md5->buffer[4] + 0x4bdecfa9, 11); + MD5STEP(F3, c, d, a, b, md5->buffer[7] + 0xf6bb4b60, 16); + MD5STEP(F3, b, c, d, a, md5->buffer[10] + 0xbebfbc70, 23); + MD5STEP(F3, a, b, c, d, md5->buffer[13] + 0x289b7ec6, 4); + MD5STEP(F3, d, a, b, c, md5->buffer[0] + 0xeaa127fa, 11); + MD5STEP(F3, c, d, a, b, md5->buffer[3] + 0xd4ef3085, 16); + MD5STEP(F3, b, c, d, a, md5->buffer[6] + 0x04881d05, 23); + MD5STEP(F3, a, b, c, d, md5->buffer[9] + 0xd9d4d039, 4); + MD5STEP(F3, d, a, b, c, md5->buffer[12] + 0xe6db99e5, 11); + MD5STEP(F3, c, d, a, b, md5->buffer[15] + 0x1fa27cf8, 16); + MD5STEP(F3, b, c, d, a, md5->buffer[2] + 0xc4ac5665, 23); + + MD5STEP(F4, a, b, c, d, md5->buffer[0] + 0xf4292244, 6); + MD5STEP(F4, d, a, b, c, md5->buffer[7] + 0x432aff97, 10); + MD5STEP(F4, c, d, a, b, md5->buffer[14] + 0xab9423a7, 15); + MD5STEP(F4, b, c, d, a, md5->buffer[5] + 0xfc93a039, 21); + MD5STEP(F4, a, b, c, d, md5->buffer[12] + 0x655b59c3, 6); + MD5STEP(F4, d, a, b, c, md5->buffer[3] + 0x8f0ccc92, 10); + MD5STEP(F4, c, d, a, b, md5->buffer[10] + 0xffeff47d, 15); + MD5STEP(F4, b, c, d, a, md5->buffer[1] + 0x85845dd1, 21); + MD5STEP(F4, a, b, c, d, md5->buffer[8] + 0x6fa87e4f, 6); + MD5STEP(F4, d, a, b, c, md5->buffer[15] + 0xfe2ce6e0, 10); + MD5STEP(F4, c, d, a, b, md5->buffer[6] + 0xa3014314, 15); + MD5STEP(F4, b, c, d, a, md5->buffer[13] + 0x4e0811a1, 21); + MD5STEP(F4, a, b, c, d, md5->buffer[4] + 0xf7537e82, 6); + MD5STEP(F4, d, a, b, c, md5->buffer[11] + 0xbd3af235, 10); + MD5STEP(F4, c, d, a, b, md5->buffer[2] + 0x2ad7d2bb, 15); + MD5STEP(F4, b, c, d, a, md5->buffer[9] + 0xeb86d391, 21); + + /* Add the working vars back into digest state[] */ + md5->digest[0] += a; + md5->digest[1] += b; + md5->digest[2] += c; + md5->digest[3] += d; +} + + +static INLINE void AddLength(Md5* md5, word32 len) +{ + word32 tmp = md5->loLen; + if ( (md5->loLen += len) < tmp) + md5->hiLen++; /* carry low to high */ +} + + +void Md5Update(Md5* md5, const byte* data, word32 len) +{ + /* do block size increments */ + byte* local = (byte*)md5->buffer; + + while (len) { + word32 add = min(len, MD5_BLOCK_SIZE - md5->buffLen); + XMEMCPY(&local[md5->buffLen], data, add); + + md5->buffLen += add; + data += add; + len -= add; + + if (md5->buffLen == MD5_BLOCK_SIZE) { + #ifdef BIG_ENDIAN_ORDER + ByteReverseBytes(local, local, MD5_BLOCK_SIZE); + #endif + Transform(md5); + AddLength(md5, MD5_BLOCK_SIZE); + md5->buffLen = 0; + } + } +} + + +void Md5Final(Md5* md5, byte* hash) +{ + byte* local = (byte*)md5->buffer; + + AddLength(md5, md5->buffLen); /* before adding pads */ + + local[md5->buffLen++] = 0x80; /* add 1 */ + + /* pad with zeros */ + if (md5->buffLen > MD5_PAD_SIZE) { + XMEMSET(&local[md5->buffLen], 0, MD5_BLOCK_SIZE - md5->buffLen); + md5->buffLen += MD5_BLOCK_SIZE - md5->buffLen; + + #ifdef BIG_ENDIAN_ORDER + ByteReverseBytes(local, local, MD5_BLOCK_SIZE); + #endif + Transform(md5); + md5->buffLen = 0; + } + XMEMSET(&local[md5->buffLen], 0, MD5_PAD_SIZE - md5->buffLen); + + /* put lengths in bits */ + md5->loLen = md5->loLen << 3; + md5->hiLen = (md5->loLen >> (8*sizeof(md5->loLen) - 3)) + + (md5->hiLen << 3); + + /* store lengths */ + #ifdef BIG_ENDIAN_ORDER + ByteReverseBytes(local, local, MD5_BLOCK_SIZE); + #endif + /* ! length ordering dependent on digest endian type ! */ + XMEMCPY(&local[MD5_PAD_SIZE], &md5->loLen, sizeof(word32)); + XMEMCPY(&local[MD5_PAD_SIZE + sizeof(word32)], &md5->hiLen, sizeof(word32)); + + Transform(md5); + #ifdef BIG_ENDIAN_ORDER + ByteReverseWords(md5->digest, md5->digest, MD5_DIGEST_SIZE); + #endif + XMEMCPY(hash, md5->digest, MD5_DIGEST_SIZE); + + InitMd5(md5); /* reset state */ +} + diff --git a/ctaocrypt/src/misc.c b/ctaocrypt/src/misc.c new file mode 100644 index 000000000..bd2830642 --- /dev/null +++ b/ctaocrypt/src/misc.c @@ -0,0 +1,171 @@ +/* misc.c + * + * Copyright (C) 2006-2011 Sawtooth Consulting Ltd. + * + * This file is part of CyaSSL. + * + * CyaSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * CyaSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + + +#include "misc.h" + +/* inlining these functions is a huge speed increase and a small size decrease, + because the functions are smaller than function call setup/cleanup, e.g., + md5 benchmark is twice as fast with inline. If you don't want it, then + define NO_INLINE and compile this file into cyassl, otherwise it's used as + a source header + */ + +#ifdef NO_INLINE + #define STATIC +#else + #define STATIC static +#endif + + +#ifdef INTEL_INTRINSICS + + #include /* get intrinsic definitions */ + + #pragma intrinsic(_lrotl, _lrotr) + + STATIC INLINE word32 rotlFixed(word32 x, word32 y) + { + return y ? _lrotl(x, y) : x; + } + + STATIC INLINE word32 rotrFixed(word32 x, word32 y) + { + return y ? _lrotr(x, y) : x; + } + +#else /* generic */ + + STATIC INLINE word32 rotlFixed(word32 x, word32 y) + { + return (x << y) | (x >> (sizeof(y) * 8 - y)); + } + + + STATIC INLINE word32 rotrFixed(word32 x, word32 y) + { + return (x >> y) | (x << (sizeof(y) * 8 - y)); + } + +#endif + + +STATIC INLINE word32 ByteReverseWord32(word32 value) +{ +#ifdef PPC_INTRINSICS + /* PPC: load reverse indexed instruction */ + return (word32)__lwbrx(&value,0); +#elif defined(FAST_ROTATE) + /* 5 instructions with rotate instruction, 9 without */ + return (rotrFixed(value, 8U) & 0xff00ff00) | + (rotlFixed(value, 8U) & 0x00ff00ff); +#else + /* 6 instructions with rotate instruction, 8 without */ + value = ((value & 0xFF00FF00) >> 8) | ((value & 0x00FF00FF) << 8); + return rotlFixed(value, 16U); +#endif +} + + +STATIC INLINE void ByteReverseWords(word32* out, const word32* in, + word32 byteCount) +{ + word32 count = byteCount/sizeof(word32), i; + + for (i = 0; i < count; i++) + out[i] = ByteReverseWord32(in[i]); + +} + + +#ifdef WORD64_AVAILABLE + + +STATIC INLINE word64 rotlFixed64(word64 x, word64 y) +{ + return (x << y) | (x >> (sizeof(y) * 8 - y)); +} + + +STATIC INLINE word64 rotrFixed64(word64 x, word64 y) +{ + return (x >> y) | (x << (sizeof(y) * 8 - y)); +} + + +STATIC INLINE word64 ByteReverseWord64(word64 value) +{ +#ifdef CTAOCRYPT_SLOW_WORD64 + return (word64)(ByteReverseWord32((word32)value)) << 32 | + ByteReverseWord32((word32)(value>>32)); +#else + value = ((value & W64LIT(0xFF00FF00FF00FF00)) >> 8) | + ((value & W64LIT(0x00FF00FF00FF00FF)) << 8); + value = ((value & W64LIT(0xFFFF0000FFFF0000)) >> 16) | + ((value & W64LIT(0x0000FFFF0000FFFF)) << 16); + return rotlFixed64(value, 32U); +#endif +} + + +STATIC INLINE void ByteReverseWords64(word64* out, const word64* in, + word32 byteCount) +{ + word32 count = byteCount/sizeof(word64), i; + + for (i = 0; i < count; i++) + out[i] = ByteReverseWord64(in[i]); + +} + +#endif /* WORD64_AVAILABLE */ + + +STATIC INLINE void ByteReverseBytes(byte* out, const byte* in, word32 byteCount) +{ + word32* op = (word32*)out; + const word32* ip = (const word32*)in; + + ByteReverseWords(op, ip, byteCount); +} + + +STATIC INLINE void XorWords(word* r, const word* a, word32 n) +{ + word32 i; + + for (i = 0; i < n; i++) r[i] ^= a[i]; +} + + +STATIC INLINE void xorbuf(byte* buf, const byte* mask, word32 count) +{ + if (((size_t)buf | (size_t)mask | count) % WORD_SIZE == 0) + XorWords( (word*)buf, (const word*)mask, count / WORD_SIZE); + else { + word32 i; + for (i = 0; i < count; i++) buf[i] ^= mask[i]; + } +} + + +#undef STATIC + diff --git a/ctaocrypt/src/pwdbased.c b/ctaocrypt/src/pwdbased.c new file mode 100644 index 000000000..2cd380f08 --- /dev/null +++ b/ctaocrypt/src/pwdbased.c @@ -0,0 +1,76 @@ +/* pwdbased.c + * + * Copyright (C) 2006-2011 Sawtooth Consulting Ltd. + * + * This file is part of CyaSSL. + * + * CyaSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * CyaSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + + +#ifndef NO_PWDBASED + +#include "pwdbased.h" + + +int PBKDF1(byte* output, const byte* passwd, int pLen, const byte* salt, + int sLen, int iterations, int kLen, int hashType) +{ + Md5 md5; + Sha sha; + int hLen = (hashType == MD5) ? MD5_DIGEST_SIZE : SHA_DIGEST_SIZE; + int i; + byte buffer[SHA_DIGEST_SIZE]; /* max size */ + + if (hashType != MD5 && hashType != SHA) + return -1; + + if (kLen > hLen) + return -1; + + if (iterations < 1) + return -1; + + if (hashType == MD5) { + InitMd5(&md5); + Md5Update(&md5, passwd, pLen); + Md5Update(&md5, salt, sLen); + Md5Final(&md5, buffer); + } + else { + InitSha(&sha); + ShaUpdate(&sha, passwd, pLen); + ShaUpdate(&sha, salt, sLen); + ShaFinal(&sha, buffer); + } + + for (i = 1; i < iterations; i++) { + if (hashType == MD5) { + Md5Update(&md5, buffer, hLen); + Md5Final(&md5, buffer); + } + else { + ShaUpdate(&sha, buffer, hLen); + ShaFinal(&sha, buffer); + } + } + XMEMCPY(output, buffer, kLen); + + return 0; +} + + +#endif /* NO_PWDBASED */ + diff --git a/ctaocrypt/src/rabbit.c b/ctaocrypt/src/rabbit.c new file mode 100644 index 000000000..2cb5241a7 --- /dev/null +++ b/ctaocrypt/src/rabbit.c @@ -0,0 +1,239 @@ +/* rabbit.c + * + * Copyright (C) 2006-2011 Sawtooth Consulting Ltd. + * + * This file is part of CyaSSL. + * + * CyaSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * CyaSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + + +#ifndef NO_RABBIT + +#include "rabbit.h" +#include "misc.c" + + +#ifdef BIG_ENDIAN_ORDER + #define LITTLE32(x) ByteReverseWord32(x) +#else + #define LITTLE32(x) (x) +#endif + +#define U32V(x) (word32)(x) + + +/* Square a 32-bit unsigned integer to obtain the 64-bit result and return */ +/* the upper 32 bits XOR the lower 32 bits */ +static word32 RABBIT_g_func(word32 x) +{ + /* Temporary variables */ + word32 a, b, h, l; + + /* Construct high and low argument for squaring */ + a = x&0xFFFF; + b = x>>16; + + /* Calculate high and low result of squaring */ + h = (((U32V(a*a)>>17) + U32V(a*b))>>15) + b*b; + l = x*x; + + /* Return high XOR low */ + return U32V(h^l); +} + + +/* Calculate the next internal state */ +static void RABBIT_next_state(RabbitCtx* ctx) +{ + /* Temporary variables */ + word32 g[8], c_old[8], i; + + /* Save old counter values */ + for (i=0; i<8; i++) + c_old[i] = ctx->c[i]; + + /* Calculate new counter values */ + ctx->c[0] = U32V(ctx->c[0] + 0x4D34D34D + ctx->carry); + ctx->c[1] = U32V(ctx->c[1] + 0xD34D34D3 + (ctx->c[0] < c_old[0])); + ctx->c[2] = U32V(ctx->c[2] + 0x34D34D34 + (ctx->c[1] < c_old[1])); + ctx->c[3] = U32V(ctx->c[3] + 0x4D34D34D + (ctx->c[2] < c_old[2])); + ctx->c[4] = U32V(ctx->c[4] + 0xD34D34D3 + (ctx->c[3] < c_old[3])); + ctx->c[5] = U32V(ctx->c[5] + 0x34D34D34 + (ctx->c[4] < c_old[4])); + ctx->c[6] = U32V(ctx->c[6] + 0x4D34D34D + (ctx->c[5] < c_old[5])); + ctx->c[7] = U32V(ctx->c[7] + 0xD34D34D3 + (ctx->c[6] < c_old[6])); + ctx->carry = (ctx->c[7] < c_old[7]); + + /* Calculate the g-values */ + for (i=0;i<8;i++) + g[i] = RABBIT_g_func(U32V(ctx->x[i] + ctx->c[i])); + + /* Calculate new state values */ + ctx->x[0] = U32V(g[0] + rotlFixed(g[7],16) + rotlFixed(g[6], 16)); + ctx->x[1] = U32V(g[1] + rotlFixed(g[0], 8) + g[7]); + ctx->x[2] = U32V(g[2] + rotlFixed(g[1],16) + rotlFixed(g[0], 16)); + ctx->x[3] = U32V(g[3] + rotlFixed(g[2], 8) + g[1]); + ctx->x[4] = U32V(g[4] + rotlFixed(g[3],16) + rotlFixed(g[2], 16)); + ctx->x[5] = U32V(g[5] + rotlFixed(g[4], 8) + g[3]); + ctx->x[6] = U32V(g[6] + rotlFixed(g[5],16) + rotlFixed(g[4], 16)); + ctx->x[7] = U32V(g[7] + rotlFixed(g[6], 8) + g[5]); +} + + +/* IV setup */ +static void RabbitSetIV(Rabbit* ctx, const byte* iv) +{ + /* Temporary variables */ + word32 i0, i1, i2, i3, i; + + /* Generate four subvectors */ + i0 = LITTLE32(*(word32*)(iv+0)); + i2 = LITTLE32(*(word32*)(iv+4)); + i1 = (i0>>16) | (i2&0xFFFF0000); + i3 = (i2<<16) | (i0&0x0000FFFF); + + /* Modify counter values */ + ctx->workCtx.c[0] = ctx->masterCtx.c[0] ^ i0; + ctx->workCtx.c[1] = ctx->masterCtx.c[1] ^ i1; + ctx->workCtx.c[2] = ctx->masterCtx.c[2] ^ i2; + ctx->workCtx.c[3] = ctx->masterCtx.c[3] ^ i3; + ctx->workCtx.c[4] = ctx->masterCtx.c[4] ^ i0; + ctx->workCtx.c[5] = ctx->masterCtx.c[5] ^ i1; + ctx->workCtx.c[6] = ctx->masterCtx.c[6] ^ i2; + ctx->workCtx.c[7] = ctx->masterCtx.c[7] ^ i3; + + /* Copy state variables */ + for (i=0; i<8; i++) + ctx->workCtx.x[i] = ctx->masterCtx.x[i]; + ctx->workCtx.carry = ctx->masterCtx.carry; + + /* Iterate the system four times */ + for (i=0; i<4; i++) + RABBIT_next_state(&(ctx->workCtx)); +} + + +/* Key setup */ +void RabbitSetKey(Rabbit* ctx, const byte* key, const byte* iv) +{ + /* Temporary variables */ + word32 k0, k1, k2, k3, i; + + /* Generate four subkeys */ + k0 = LITTLE32(*(word32*)(key+ 0)); + k1 = LITTLE32(*(word32*)(key+ 4)); + k2 = LITTLE32(*(word32*)(key+ 8)); + k3 = LITTLE32(*(word32*)(key+12)); + + /* Generate initial state variables */ + ctx->masterCtx.x[0] = k0; + ctx->masterCtx.x[2] = k1; + ctx->masterCtx.x[4] = k2; + ctx->masterCtx.x[6] = k3; + ctx->masterCtx.x[1] = U32V(k3<<16) | (k2>>16); + ctx->masterCtx.x[3] = U32V(k0<<16) | (k3>>16); + ctx->masterCtx.x[5] = U32V(k1<<16) | (k0>>16); + ctx->masterCtx.x[7] = U32V(k2<<16) | (k1>>16); + + /* Generate initial counter values */ + ctx->masterCtx.c[0] = rotlFixed(k2, 16); + ctx->masterCtx.c[2] = rotlFixed(k3, 16); + ctx->masterCtx.c[4] = rotlFixed(k0, 16); + ctx->masterCtx.c[6] = rotlFixed(k1, 16); + ctx->masterCtx.c[1] = (k0&0xFFFF0000) | (k1&0xFFFF); + ctx->masterCtx.c[3] = (k1&0xFFFF0000) | (k2&0xFFFF); + ctx->masterCtx.c[5] = (k2&0xFFFF0000) | (k3&0xFFFF); + ctx->masterCtx.c[7] = (k3&0xFFFF0000) | (k0&0xFFFF); + + /* Clear carry bit */ + ctx->masterCtx.carry = 0; + + /* Iterate the system four times */ + for (i=0; i<4; i++) + RABBIT_next_state(&(ctx->masterCtx)); + + /* Modify the counters */ + for (i=0; i<8; i++) + ctx->masterCtx.c[i] ^= ctx->masterCtx.x[(i+4)&0x7]; + + /* Copy master instance to work instance */ + for (i=0; i<8; i++) { + ctx->workCtx.x[i] = ctx->masterCtx.x[i]; + ctx->workCtx.c[i] = ctx->masterCtx.c[i]; + } + ctx->workCtx.carry = ctx->masterCtx.carry; + + if (iv) RabbitSetIV(ctx, iv); +} + + +/* Encrypt/decrypt a message of any size */ +void RabbitProcess(Rabbit* ctx, byte* output, const byte* input, word32 msglen) +{ + + /* Encrypt/decrypt all full blocks */ + while (msglen >= 16) { + /* Iterate the system */ + RABBIT_next_state(&(ctx->workCtx)); + + /* Encrypt/decrypt 16 bytes of data */ + *(word32*)(output+ 0) = *(word32*)(input+ 0) ^ + LITTLE32(ctx->workCtx.x[0] ^ (ctx->workCtx.x[5]>>16) ^ + U32V(ctx->workCtx.x[3]<<16)); + *(word32*)(output+ 4) = *(word32*)(input+ 4) ^ + LITTLE32(ctx->workCtx.x[2] ^ (ctx->workCtx.x[7]>>16) ^ + U32V(ctx->workCtx.x[5]<<16)); + *(word32*)(output+ 8) = *(word32*)(input+ 8) ^ + LITTLE32(ctx->workCtx.x[4] ^ (ctx->workCtx.x[1]>>16) ^ + U32V(ctx->workCtx.x[7]<<16)); + *(word32*)(output+12) = *(word32*)(input+12) ^ + LITTLE32(ctx->workCtx.x[6] ^ (ctx->workCtx.x[3]>>16) ^ + U32V(ctx->workCtx.x[1]<<16)); + + /* Increment pointers and decrement length */ + input += 16; + output += 16; + msglen -= 16; + } + + /* Encrypt/decrypt remaining data */ + if (msglen) { + + word32 i; + word32 tmp[4]; + byte* buffer = (byte*)tmp; + + /* Iterate the system */ + RABBIT_next_state(&(ctx->workCtx)); + + /* Generate 16 bytes of pseudo-random data */ + tmp[0] = LITTLE32(ctx->workCtx.x[0] ^ + (ctx->workCtx.x[5]>>16) ^ U32V(ctx->workCtx.x[3]<<16)); + tmp[1] = LITTLE32(ctx->workCtx.x[2] ^ + (ctx->workCtx.x[7]>>16) ^ U32V(ctx->workCtx.x[5]<<16)); + tmp[2] = LITTLE32(ctx->workCtx.x[4] ^ + (ctx->workCtx.x[1]>>16) ^ U32V(ctx->workCtx.x[7]<<16)); + tmp[3] = LITTLE32(ctx->workCtx.x[6] ^ + (ctx->workCtx.x[3]>>16) ^ U32V(ctx->workCtx.x[1]<<16)); + + /* Encrypt/decrypt the data */ + for (i=0; i + #include +#else + #ifndef NO_DEV_RANDOM + #include + #include + #else + /* include headers that may be needed to get good seed */ + #endif +#endif /* USE_WINDOWS_API */ + + + +/* Get seed and key cipher */ +int InitRng(RNG* rng) +{ + byte key[32]; + byte junk[256]; + + int ret = GenerateSeed(&rng->seed, key, sizeof(key)); + + if (ret == 0) { + Arc4SetKey(&rng->cipher, key, sizeof(key)); + RNG_GenerateBlock(rng, junk, sizeof(junk)); /* rid initial state */ + } + + return ret; +} + + +/* place a generated block in output */ +void RNG_GenerateBlock(RNG* rng, byte* output, word32 sz) +{ + XMEMSET(output, 0, sz); + Arc4Process(&rng->cipher, output, output, sz); +} + + +byte RNG_GenerateByte(RNG* rng) +{ + byte b; + RNG_GenerateBlock(rng, &b, 1); + + return b; +} + + +#if defined(USE_WINDOWS_API) + + +int GenerateSeed(OS_Seed* os, byte* output, word32 sz) +{ + if(!CryptAcquireContext(&os->handle, 0, 0, PROV_RSA_FULL, + CRYPT_VERIFYCONTEXT)) + return WINCRYPT_E; + + if (!CryptGenRandom(os->handle, sz, output)) + return CRYPTGEN_E; + + CryptReleaseContext(os->handle, 0); + + return 0; +} + + +#elif defined(THREADX) + +#include "rtprand.h" /* rtp_rand () */ +#include "rtptime.h" /* rtp_get_system_msec() */ + + +int GenerateSeed(OS_Seed* os, byte* output, word32 sz) +{ + int i; + rtp_srand(rtp_get_system_msec()); + + for (i = 0; i < sz; i++ ) { + output[i] = rtp_rand() % 256; + if ( (i % 8) == 7) + rtp_srand(rtp_get_system_msec()); + } + + return 0; +} + + +#elif defined(MICRIUM) + +int GenerateSeed(OS_Seed* os, byte* output, word32 sz) +{ + #if (NET_SECURE_MGR_CFG_EN == DEF_ENABLED) + NetSecure_InitSeed(output, sz); + #endif + return 0; +} + +#elif defined(MBED) + +/* write a real one !!!, just for testing board */ +int GenerateSeed(OS_Seed* os, byte* output, word32 sz) +{ + int i; + for (i = 0; i < sz; i++ ) + output[i] = i; + + return 0; +} + +#elif defined(NO_DEV_RANDOM) + +#error "you need to write an os specific GenerateSeed() here" + + +#else /* !USE_WINDOWS_API && !THREADX && !MICRIUM && !NO_DEV_RANDOM */ + + +/* may block */ +int GenerateSeed(OS_Seed* os, byte* output, word32 sz) +{ + os->fd = open("/dev/urandom",O_RDONLY); + if (os->fd == -1) { + /* may still have /dev/random */ + os->fd = open("/dev/random",O_RDONLY); + if (os->fd == -1) + return OPEN_RAN_E; + } + + while (sz) { + int len = read(os->fd, output, sz); + if (len == -1) + return READ_RAN_E; + + sz -= len; + output += len; + + if (sz) +#ifdef BLOCKING + sleep(0); /* context switch */ +#else + return RAN_BLOCK_E; +#endif + } + close(os->fd); + + return 0; +} + +#endif /* USE_WINDOWS_API */ + diff --git a/ctaocrypt/src/ripemd.c b/ctaocrypt/src/ripemd.c new file mode 100644 index 000000000..ae0fab32b --- /dev/null +++ b/ctaocrypt/src/ripemd.c @@ -0,0 +1,347 @@ +/* ripemd.c + * + * Copyright (C) 2006-2011 Sawtooth Consulting Ltd. + * + * This file is part of CyaSSL. + * + * CyaSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * CyaSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + + +#ifdef CYASSL_RIPEMD + +#include "ctc_ripemd.h" +#ifdef NO_INLINE + #include "misc.h" +#else + #include "misc.c" +#endif + + +#ifndef min + + static INLINE word32 min(word32 a, word32 b) + { + return a > b ? b : a; + } + +#endif /* min */ + + +void InitRipeMd(RipeMd* ripemd) +{ + ripemd->digest[0] = 0x67452301L; + ripemd->digest[1] = 0xEFCDAB89L; + ripemd->digest[2] = 0x98BADCFEL; + ripemd->digest[3] = 0x10325476L; + ripemd->digest[4] = 0xC3D2E1F0L; + + ripemd->buffLen = 0; + ripemd->loLen = 0; + ripemd->hiLen = 0; +} + + +/* for all */ +#define F(x, y, z) (x ^ y ^ z) +#define G(x, y, z) (z ^ (x & (y^z))) +#define H(x, y, z) (z ^ (x | ~y)) +#define I(x, y, z) (y ^ (z & (x^y))) +#define J(x, y, z) (x ^ (y | ~z)) + +#define k0 0 +#define k1 0x5a827999 +#define k2 0x6ed9eba1 +#define k3 0x8f1bbcdc +#define k4 0xa953fd4e +#define k5 0x50a28be6 +#define k6 0x5c4dd124 +#define k7 0x6d703ef3 +#define k8 0x7a6d76e9 +#define k9 0 + +/* for 160 and 320 */ +#define Subround(f, a, b, c, d, e, x, s, k) \ + a += f(b, c, d) + x + k;\ + a = rotlFixed((word32)a, s) + e;\ + c = rotlFixed((word32)c, 10U) + +static void Transform(RipeMd* ripemd) +{ + word32 a1, b1, c1, d1, e1, a2, b2, c2, d2, e2; + a1 = a2 = ripemd->digest[0]; + b1 = b2 = ripemd->digest[1]; + c1 = c2 = ripemd->digest[2]; + d1 = d2 = ripemd->digest[3]; + e1 = e2 = ripemd->digest[4]; + + Subround(F, a1, b1, c1, d1, e1, ripemd->buffer[ 0], 11, k0); + Subround(F, e1, a1, b1, c1, d1, ripemd->buffer[ 1], 14, k0); + Subround(F, d1, e1, a1, b1, c1, ripemd->buffer[ 2], 15, k0); + Subround(F, c1, d1, e1, a1, b1, ripemd->buffer[ 3], 12, k0); + Subround(F, b1, c1, d1, e1, a1, ripemd->buffer[ 4], 5, k0); + Subround(F, a1, b1, c1, d1, e1, ripemd->buffer[ 5], 8, k0); + Subround(F, e1, a1, b1, c1, d1, ripemd->buffer[ 6], 7, k0); + Subround(F, d1, e1, a1, b1, c1, ripemd->buffer[ 7], 9, k0); + Subround(F, c1, d1, e1, a1, b1, ripemd->buffer[ 8], 11, k0); + Subround(F, b1, c1, d1, e1, a1, ripemd->buffer[ 9], 13, k0); + Subround(F, a1, b1, c1, d1, e1, ripemd->buffer[10], 14, k0); + Subround(F, e1, a1, b1, c1, d1, ripemd->buffer[11], 15, k0); + Subround(F, d1, e1, a1, b1, c1, ripemd->buffer[12], 6, k0); + Subround(F, c1, d1, e1, a1, b1, ripemd->buffer[13], 7, k0); + Subround(F, b1, c1, d1, e1, a1, ripemd->buffer[14], 9, k0); + Subround(F, a1, b1, c1, d1, e1, ripemd->buffer[15], 8, k0); + + Subround(G, e1, a1, b1, c1, d1, ripemd->buffer[ 7], 7, k1); + Subround(G, d1, e1, a1, b1, c1, ripemd->buffer[ 4], 6, k1); + Subround(G, c1, d1, e1, a1, b1, ripemd->buffer[13], 8, k1); + Subround(G, b1, c1, d1, e1, a1, ripemd->buffer[ 1], 13, k1); + Subround(G, a1, b1, c1, d1, e1, ripemd->buffer[10], 11, k1); + Subround(G, e1, a1, b1, c1, d1, ripemd->buffer[ 6], 9, k1); + Subround(G, d1, e1, a1, b1, c1, ripemd->buffer[15], 7, k1); + Subround(G, c1, d1, e1, a1, b1, ripemd->buffer[ 3], 15, k1); + Subround(G, b1, c1, d1, e1, a1, ripemd->buffer[12], 7, k1); + Subround(G, a1, b1, c1, d1, e1, ripemd->buffer[ 0], 12, k1); + Subround(G, e1, a1, b1, c1, d1, ripemd->buffer[ 9], 15, k1); + Subround(G, d1, e1, a1, b1, c1, ripemd->buffer[ 5], 9, k1); + Subround(G, c1, d1, e1, a1, b1, ripemd->buffer[ 2], 11, k1); + Subround(G, b1, c1, d1, e1, a1, ripemd->buffer[14], 7, k1); + Subround(G, a1, b1, c1, d1, e1, ripemd->buffer[11], 13, k1); + Subround(G, e1, a1, b1, c1, d1, ripemd->buffer[ 8], 12, k1); + + Subround(H, d1, e1, a1, b1, c1, ripemd->buffer[ 3], 11, k2); + Subround(H, c1, d1, e1, a1, b1, ripemd->buffer[10], 13, k2); + Subround(H, b1, c1, d1, e1, a1, ripemd->buffer[14], 6, k2); + Subround(H, a1, b1, c1, d1, e1, ripemd->buffer[ 4], 7, k2); + Subround(H, e1, a1, b1, c1, d1, ripemd->buffer[ 9], 14, k2); + Subround(H, d1, e1, a1, b1, c1, ripemd->buffer[15], 9, k2); + Subround(H, c1, d1, e1, a1, b1, ripemd->buffer[ 8], 13, k2); + Subround(H, b1, c1, d1, e1, a1, ripemd->buffer[ 1], 15, k2); + Subround(H, a1, b1, c1, d1, e1, ripemd->buffer[ 2], 14, k2); + Subround(H, e1, a1, b1, c1, d1, ripemd->buffer[ 7], 8, k2); + Subround(H, d1, e1, a1, b1, c1, ripemd->buffer[ 0], 13, k2); + Subround(H, c1, d1, e1, a1, b1, ripemd->buffer[ 6], 6, k2); + Subround(H, b1, c1, d1, e1, a1, ripemd->buffer[13], 5, k2); + Subround(H, a1, b1, c1, d1, e1, ripemd->buffer[11], 12, k2); + Subround(H, e1, a1, b1, c1, d1, ripemd->buffer[ 5], 7, k2); + Subround(H, d1, e1, a1, b1, c1, ripemd->buffer[12], 5, k2); + + Subround(I, c1, d1, e1, a1, b1, ripemd->buffer[ 1], 11, k3); + Subround(I, b1, c1, d1, e1, a1, ripemd->buffer[ 9], 12, k3); + Subround(I, a1, b1, c1, d1, e1, ripemd->buffer[11], 14, k3); + Subround(I, e1, a1, b1, c1, d1, ripemd->buffer[10], 15, k3); + Subround(I, d1, e1, a1, b1, c1, ripemd->buffer[ 0], 14, k3); + Subround(I, c1, d1, e1, a1, b1, ripemd->buffer[ 8], 15, k3); + Subround(I, b1, c1, d1, e1, a1, ripemd->buffer[12], 9, k3); + Subround(I, a1, b1, c1, d1, e1, ripemd->buffer[ 4], 8, k3); + Subround(I, e1, a1, b1, c1, d1, ripemd->buffer[13], 9, k3); + Subround(I, d1, e1, a1, b1, c1, ripemd->buffer[ 3], 14, k3); + Subround(I, c1, d1, e1, a1, b1, ripemd->buffer[ 7], 5, k3); + Subround(I, b1, c1, d1, e1, a1, ripemd->buffer[15], 6, k3); + Subround(I, a1, b1, c1, d1, e1, ripemd->buffer[14], 8, k3); + Subround(I, e1, a1, b1, c1, d1, ripemd->buffer[ 5], 6, k3); + Subround(I, d1, e1, a1, b1, c1, ripemd->buffer[ 6], 5, k3); + Subround(I, c1, d1, e1, a1, b1, ripemd->buffer[ 2], 12, k3); + + Subround(J, b1, c1, d1, e1, a1, ripemd->buffer[ 4], 9, k4); + Subround(J, a1, b1, c1, d1, e1, ripemd->buffer[ 0], 15, k4); + Subround(J, e1, a1, b1, c1, d1, ripemd->buffer[ 5], 5, k4); + Subround(J, d1, e1, a1, b1, c1, ripemd->buffer[ 9], 11, k4); + Subround(J, c1, d1, e1, a1, b1, ripemd->buffer[ 7], 6, k4); + Subround(J, b1, c1, d1, e1, a1, ripemd->buffer[12], 8, k4); + Subround(J, a1, b1, c1, d1, e1, ripemd->buffer[ 2], 13, k4); + Subround(J, e1, a1, b1, c1, d1, ripemd->buffer[10], 12, k4); + Subround(J, d1, e1, a1, b1, c1, ripemd->buffer[14], 5, k4); + Subround(J, c1, d1, e1, a1, b1, ripemd->buffer[ 1], 12, k4); + Subround(J, b1, c1, d1, e1, a1, ripemd->buffer[ 3], 13, k4); + Subround(J, a1, b1, c1, d1, e1, ripemd->buffer[ 8], 14, k4); + Subround(J, e1, a1, b1, c1, d1, ripemd->buffer[11], 11, k4); + Subround(J, d1, e1, a1, b1, c1, ripemd->buffer[ 6], 8, k4); + Subround(J, c1, d1, e1, a1, b1, ripemd->buffer[15], 5, k4); + Subround(J, b1, c1, d1, e1, a1, ripemd->buffer[13], 6, k4); + + Subround(J, a2, b2, c2, d2, e2, ripemd->buffer[ 5], 8, k5); + Subround(J, e2, a2, b2, c2, d2, ripemd->buffer[14], 9, k5); + Subround(J, d2, e2, a2, b2, c2, ripemd->buffer[ 7], 9, k5); + Subround(J, c2, d2, e2, a2, b2, ripemd->buffer[ 0], 11, k5); + Subround(J, b2, c2, d2, e2, a2, ripemd->buffer[ 9], 13, k5); + Subround(J, a2, b2, c2, d2, e2, ripemd->buffer[ 2], 15, k5); + Subround(J, e2, a2, b2, c2, d2, ripemd->buffer[11], 15, k5); + Subround(J, d2, e2, a2, b2, c2, ripemd->buffer[ 4], 5, k5); + Subround(J, c2, d2, e2, a2, b2, ripemd->buffer[13], 7, k5); + Subround(J, b2, c2, d2, e2, a2, ripemd->buffer[ 6], 7, k5); + Subround(J, a2, b2, c2, d2, e2, ripemd->buffer[15], 8, k5); + Subround(J, e2, a2, b2, c2, d2, ripemd->buffer[ 8], 11, k5); + Subround(J, d2, e2, a2, b2, c2, ripemd->buffer[ 1], 14, k5); + Subround(J, c2, d2, e2, a2, b2, ripemd->buffer[10], 14, k5); + Subround(J, b2, c2, d2, e2, a2, ripemd->buffer[ 3], 12, k5); + Subround(J, a2, b2, c2, d2, e2, ripemd->buffer[12], 6, k5); + + Subround(I, e2, a2, b2, c2, d2, ripemd->buffer[ 6], 9, k6); + Subround(I, d2, e2, a2, b2, c2, ripemd->buffer[11], 13, k6); + Subround(I, c2, d2, e2, a2, b2, ripemd->buffer[ 3], 15, k6); + Subround(I, b2, c2, d2, e2, a2, ripemd->buffer[ 7], 7, k6); + Subround(I, a2, b2, c2, d2, e2, ripemd->buffer[ 0], 12, k6); + Subround(I, e2, a2, b2, c2, d2, ripemd->buffer[13], 8, k6); + Subround(I, d2, e2, a2, b2, c2, ripemd->buffer[ 5], 9, k6); + Subround(I, c2, d2, e2, a2, b2, ripemd->buffer[10], 11, k6); + Subround(I, b2, c2, d2, e2, a2, ripemd->buffer[14], 7, k6); + Subround(I, a2, b2, c2, d2, e2, ripemd->buffer[15], 7, k6); + Subround(I, e2, a2, b2, c2, d2, ripemd->buffer[ 8], 12, k6); + Subround(I, d2, e2, a2, b2, c2, ripemd->buffer[12], 7, k6); + Subround(I, c2, d2, e2, a2, b2, ripemd->buffer[ 4], 6, k6); + Subround(I, b2, c2, d2, e2, a2, ripemd->buffer[ 9], 15, k6); + Subround(I, a2, b2, c2, d2, e2, ripemd->buffer[ 1], 13, k6); + Subround(I, e2, a2, b2, c2, d2, ripemd->buffer[ 2], 11, k6); + + Subround(H, d2, e2, a2, b2, c2, ripemd->buffer[15], 9, k7); + Subround(H, c2, d2, e2, a2, b2, ripemd->buffer[ 5], 7, k7); + Subround(H, b2, c2, d2, e2, a2, ripemd->buffer[ 1], 15, k7); + Subround(H, a2, b2, c2, d2, e2, ripemd->buffer[ 3], 11, k7); + Subround(H, e2, a2, b2, c2, d2, ripemd->buffer[ 7], 8, k7); + Subround(H, d2, e2, a2, b2, c2, ripemd->buffer[14], 6, k7); + Subround(H, c2, d2, e2, a2, b2, ripemd->buffer[ 6], 6, k7); + Subround(H, b2, c2, d2, e2, a2, ripemd->buffer[ 9], 14, k7); + Subround(H, a2, b2, c2, d2, e2, ripemd->buffer[11], 12, k7); + Subround(H, e2, a2, b2, c2, d2, ripemd->buffer[ 8], 13, k7); + Subround(H, d2, e2, a2, b2, c2, ripemd->buffer[12], 5, k7); + Subround(H, c2, d2, e2, a2, b2, ripemd->buffer[ 2], 14, k7); + Subround(H, b2, c2, d2, e2, a2, ripemd->buffer[10], 13, k7); + Subround(H, a2, b2, c2, d2, e2, ripemd->buffer[ 0], 13, k7); + Subround(H, e2, a2, b2, c2, d2, ripemd->buffer[ 4], 7, k7); + Subround(H, d2, e2, a2, b2, c2, ripemd->buffer[13], 5, k7); + + Subround(G, c2, d2, e2, a2, b2, ripemd->buffer[ 8], 15, k8); + Subround(G, b2, c2, d2, e2, a2, ripemd->buffer[ 6], 5, k8); + Subround(G, a2, b2, c2, d2, e2, ripemd->buffer[ 4], 8, k8); + Subround(G, e2, a2, b2, c2, d2, ripemd->buffer[ 1], 11, k8); + Subround(G, d2, e2, a2, b2, c2, ripemd->buffer[ 3], 14, k8); + Subround(G, c2, d2, e2, a2, b2, ripemd->buffer[11], 14, k8); + Subround(G, b2, c2, d2, e2, a2, ripemd->buffer[15], 6, k8); + Subround(G, a2, b2, c2, d2, e2, ripemd->buffer[ 0], 14, k8); + Subround(G, e2, a2, b2, c2, d2, ripemd->buffer[ 5], 6, k8); + Subround(G, d2, e2, a2, b2, c2, ripemd->buffer[12], 9, k8); + Subround(G, c2, d2, e2, a2, b2, ripemd->buffer[ 2], 12, k8); + Subround(G, b2, c2, d2, e2, a2, ripemd->buffer[13], 9, k8); + Subround(G, a2, b2, c2, d2, e2, ripemd->buffer[ 9], 12, k8); + Subround(G, e2, a2, b2, c2, d2, ripemd->buffer[ 7], 5, k8); + Subround(G, d2, e2, a2, b2, c2, ripemd->buffer[10], 15, k8); + Subround(G, c2, d2, e2, a2, b2, ripemd->buffer[14], 8, k8); + + Subround(F, b2, c2, d2, e2, a2, ripemd->buffer[12], 8, k9); + Subround(F, a2, b2, c2, d2, e2, ripemd->buffer[15], 5, k9); + Subround(F, e2, a2, b2, c2, d2, ripemd->buffer[10], 12, k9); + Subround(F, d2, e2, a2, b2, c2, ripemd->buffer[ 4], 9, k9); + Subround(F, c2, d2, e2, a2, b2, ripemd->buffer[ 1], 12, k9); + Subround(F, b2, c2, d2, e2, a2, ripemd->buffer[ 5], 5, k9); + Subround(F, a2, b2, c2, d2, e2, ripemd->buffer[ 8], 14, k9); + Subround(F, e2, a2, b2, c2, d2, ripemd->buffer[ 7], 6, k9); + Subround(F, d2, e2, a2, b2, c2, ripemd->buffer[ 6], 8, k9); + Subround(F, c2, d2, e2, a2, b2, ripemd->buffer[ 2], 13, k9); + Subround(F, b2, c2, d2, e2, a2, ripemd->buffer[13], 6, k9); + Subround(F, a2, b2, c2, d2, e2, ripemd->buffer[14], 5, k9); + Subround(F, e2, a2, b2, c2, d2, ripemd->buffer[ 0], 15, k9); + Subround(F, d2, e2, a2, b2, c2, ripemd->buffer[ 3], 13, k9); + Subround(F, c2, d2, e2, a2, b2, ripemd->buffer[ 9], 11, k9); + Subround(F, b2, c2, d2, e2, a2, ripemd->buffer[11], 11, k9); + + c1 = ripemd->digest[1] + c1 + d2; + ripemd->digest[1] = ripemd->digest[2] + d1 + e2; + ripemd->digest[2] = ripemd->digest[3] + e1 + a2; + ripemd->digest[3] = ripemd->digest[4] + a1 + b2; + ripemd->digest[4] = ripemd->digest[0] + b1 + c2; + ripemd->digest[0] = c1; +} + + +static INLINE void AddLength(RipeMd* ripemd, word32 len) +{ + word32 tmp = ripemd->loLen; + if ( (ripemd->loLen += len) < tmp) + ripemd->hiLen++; /* carry low to high */ +} + + +void RipeMdUpdate(RipeMd* ripemd, const byte* data, word32 len) +{ + /* do block size increments */ + byte* local = (byte*)ripemd->buffer; + + while (len) { + word32 add = min(len, RIPEMD_BLOCK_SIZE - ripemd->buffLen); + XMEMCPY(&local[ripemd->buffLen], data, add); + + ripemd->buffLen += add; + data += add; + len -= add; + + if (ripemd->buffLen == RIPEMD_BLOCK_SIZE) { + #ifdef BIG_ENDIAN_ORDER + ByteReverseBytes(local, local, RIPEMD_BLOCK_SIZE); + #endif + Transform(ripemd); + AddLength(ripemd, RIPEMD_BLOCK_SIZE); + ripemd->buffLen = 0; + } + } +} + + +void RipeMdFinal(RipeMd* ripemd, byte* hash) +{ + byte* local = (byte*)ripemd->buffer; + + AddLength(ripemd, ripemd->buffLen); /* before adding pads */ + + local[ripemd->buffLen++] = 0x80; /* add 1 */ + + /* pad with zeros */ + if (ripemd->buffLen > RIPEMD_PAD_SIZE) { + XMEMSET(&local[ripemd->buffLen], 0, RIPEMD_BLOCK_SIZE - ripemd->buffLen); + ripemd->buffLen += RIPEMD_BLOCK_SIZE - ripemd->buffLen; + + #ifdef BIG_ENDIAN_ORDER + ByteReverseBytes(local, local, RIPEMD_BLOCK_SIZE); + #endif + Transform(ripemd); + ripemd->buffLen = 0; + } + XMEMSET(&local[ripemd->buffLen], 0, RIPEMD_PAD_SIZE - ripemd->buffLen); + + /* put lengths in bits */ + ripemd->loLen = ripemd->loLen << 3; + ripemd->hiLen = (ripemd->loLen >> (8*sizeof(ripemd->loLen) - 3)) + + (ripemd->hiLen << 3); + + /* store lengths */ + #ifdef BIG_ENDIAN_ORDER + ByteReverseBytes(local, local, RIPEMD_BLOCK_SIZE); + #endif + /* ! length ordering dependent on digest endian type ! */ + XMEMCPY(&local[RIPEMD_PAD_SIZE], &ripemd->loLen, sizeof(word32)); + XMEMCPY(&local[RIPEMD_PAD_SIZE + sizeof(word32)], &ripemd->hiLen, + sizeof(word32)); + + Transform(ripemd); + #ifdef BIG_ENDIAN_ORDER + ByteReverseWords(ripemd->digest, ripemd->digest, RIPEMD_DIGEST_SIZE); + #endif + XMEMCPY(hash, ripemd->digest, RIPEMD_DIGEST_SIZE); + + InitRipeMd(ripemd); /* reset state */ +} + + +#endif /* CYASSL_RIPEMD */ diff --git a/ctaocrypt/src/rsa.c b/ctaocrypt/src/rsa.c new file mode 100644 index 000000000..5757c94db --- /dev/null +++ b/ctaocrypt/src/rsa.c @@ -0,0 +1,536 @@ +/* rsa.c + * + * Copyright (C) 2006-2011 Sawtooth Consulting Ltd. + * + * This file is part of CyaSSL. + * + * CyaSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * CyaSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + + + +#include "ctc_rsa.h" +#include "random.h" +#include "error.h" + +#ifdef SHOW_GEN + #include +#endif + + +enum { + RSA_PUBLIC_ENCRYPT = 0, + RSA_PUBLIC_DECRYPT = 1, + RSA_PRIVATE_ENCRYPT = 2, + RSA_PRIVATE_DECRYPT = 3, + + RSA_BLOCK_TYPE_1 = 1, + RSA_BLOCK_TYPE_2 = 2, + + RSA_MIN_SIZE = 512, + RSA_MAX_SIZE = 4096, + + RSA_MIN_PAD_SZ = 11 /* seperator + 0 + pad value + 8 pads */ +}; + + +void InitRsaKey(RsaKey* key, void* heap) +{ + key->type = -1; /* haven't decdied yet */ + key->heap = heap; + +/* TomsFastMath doesn't use memory allocation */ +#ifndef USE_FAST_MATH + key->n.dp = key->e.dp = 0; /* public alloc parts */ + + key->d.dp = key->p.dp = 0; /* private alloc parts */ + key->q.dp = key->dP.dp = 0; + key->u.dp = key->dQ.dp = 0; +#endif +} + + +void FreeRsaKey(RsaKey* key) +{ +/* TomsFastMath doesn't use memory allocation */ +#ifndef USE_FAST_MATH + if (key->type == RSA_PRIVATE) { + mp_clear(&key->u); + mp_clear(&key->dQ); + mp_clear(&key->dP); + mp_clear(&key->q); + mp_clear(&key->p); + mp_clear(&key->d); + } + mp_clear(&key->e); + mp_clear(&key->n); +#endif +} + +static void RsaPad(const byte* input, word32 inputLen, byte* pkcsBlock, + word32 pkcsBlockLen, byte padValue, RNG* rng) +{ + if (inputLen == 0) return; + + pkcsBlock[0] = 0x0; /* set first byte to zero and advance */ + pkcsBlock++; pkcsBlockLen--; + pkcsBlock[0] = padValue; /* insert padValue */ + + if (padValue == RSA_BLOCK_TYPE_1) + /* pad with 0xff bytes */ + XMEMSET(&pkcsBlock[1], 0xFF, pkcsBlockLen - inputLen - 2); + else { + /* pad with non-zero random bytes */ + word32 padLen = pkcsBlockLen - inputLen - 1, i; + RNG_GenerateBlock(rng, &pkcsBlock[1], padLen); + + /* remove zeros */ + for (i = 1; i < padLen; i++) + if (pkcsBlock[i] == 0) pkcsBlock[i] = 0x01; + } + + pkcsBlock[pkcsBlockLen-inputLen-1] = 0; /* separator */ + XMEMCPY(pkcsBlock+pkcsBlockLen-inputLen, input, inputLen); +} + + +static word32 RsaUnPad(const byte *pkcsBlock, unsigned int pkcsBlockLen, + byte **output, byte padValue) +{ + word32 maxOutputLen = (pkcsBlockLen > 10) ? (pkcsBlockLen - 10) : 0, + invalid = 0, + i = 1, + outputLen; + + if (pkcsBlock[0] != 0x0) /* skip past zero */ + invalid = 1; + pkcsBlock++; pkcsBlockLen--; + + /* Require block type padValue */ + invalid = (pkcsBlock[0] != padValue) || invalid; + + /* skip past the padding until we find the separator */ + while (i maxOutputLen) || invalid; + + if (invalid) + return 0; + + *output = (byte *)(pkcsBlock + i); + return outputLen; +} + + +static int RsaFunction(const byte* in, word32 inLen, byte* out, word32* outLen, + int type, RsaKey* key) +{ + #define ERROR_OUT(x) { ret = x; goto done;} + + mp_int tmp; + int ret = 0; + word32 keyLen, len; + + if (mp_init(&tmp) != MP_OKAY) + return MP_INIT_E; + + if (mp_read_unsigned_bin(&tmp, (byte*)in, inLen) != MP_OKAY) + ERROR_OUT(MP_READ_E); + + if (type == RSA_PRIVATE_DECRYPT || type == RSA_PRIVATE_ENCRYPT) { + #ifdef RSA_LOW_MEM /* half as much memory but twice as slow */ + if (mp_exptmod(&tmp, &key->d, &key->n, &tmp) != MP_OKAY) + ERROR_OUT(MP_EXPTMOD_E); + #else + #define INNER_ERROR_OUT(x) { ret = x; goto inner_done; } + + mp_int tmpa, tmpb; + + if (mp_init(&tmpa) != MP_OKAY) + ERROR_OUT(MP_INIT_E); + + if (mp_init(&tmpb) != MP_OKAY) { + mp_clear(&tmpa); + ERROR_OUT(MP_INIT_E); + } + + /* tmpa = tmp^dP mod p */ + if (mp_exptmod(&tmp, &key->dP, &key->p, &tmpa) != MP_OKAY) + INNER_ERROR_OUT(MP_EXPTMOD_E); + + /* tmpb = tmp^dQ mod q */ + if (mp_exptmod(&tmp, &key->dQ, &key->q, &tmpb) != MP_OKAY) + INNER_ERROR_OUT(MP_EXPTMOD_E); + + /* tmp = (tmpa - tmpb) * qInv (mod p) */ + if (mp_sub(&tmpa, &tmpb, &tmp) != MP_OKAY) + INNER_ERROR_OUT(MP_SUB_E); + + if (mp_mulmod(&tmp, &key->u, &key->p, &tmp) != MP_OKAY) + INNER_ERROR_OUT(MP_MULMOD_E); + + /* tmp = tmpb + q * tmp */ + if (mp_mul(&tmp, &key->q, &tmp) != MP_OKAY) + INNER_ERROR_OUT(MP_MUL_E); + + if (mp_add(&tmp, &tmpb, &tmp) != MP_OKAY) + INNER_ERROR_OUT(MP_ADD_E); + + inner_done: + mp_clear(&tmpa); + mp_clear(&tmpb); + + if (ret != 0) return ret; + + #endif /* RSA_LOW_MEM */ + } + else if (type == RSA_PUBLIC_ENCRYPT || type == RSA_PUBLIC_DECRYPT) { + if (mp_exptmod(&tmp, &key->e, &key->n, &tmp) != MP_OKAY) + ERROR_OUT(MP_EXPTMOD_E); + } + else + ERROR_OUT(RSA_WRONG_TYPE_E); + + keyLen = mp_unsigned_bin_size(&key->n); + if (keyLen > *outLen) + ERROR_OUT(RSA_BUFFER_E); + + len = mp_unsigned_bin_size(&tmp); + + /* pad front w/ zeros to match key length */ + while (len < keyLen) { + *out++ = 0x00; + len++; + } + + *outLen = keyLen; + + /* convert */ + if (mp_to_unsigned_bin(&tmp, out) != MP_OKAY) + ERROR_OUT(MP_TO_E); + +done: + mp_clear(&tmp); + return ret; +} + + + +int RsaPublicEncrypt(const byte* in, word32 inLen, byte* out, word32 outLen, + RsaKey* key, RNG* rng) +{ + int sz = mp_unsigned_bin_size(&key->n), ret; + + if (sz > (int)outLen) + return RSA_BUFFER_E; + + if (inLen > (word32)(sz - RSA_MIN_PAD_SZ)) + return RSA_BUFFER_E; + + RsaPad(in, inLen, out, sz, RSA_BLOCK_TYPE_2, rng); + + if ((ret = RsaFunction(out, sz, out, &outLen, RSA_PUBLIC_ENCRYPT, key)) < 0) + sz = ret; + + return sz; +} + + +int RsaPrivateDecryptInline(byte* in, word32 inLen, byte** out, RsaKey* key) +{ + int plainLen, ret; + + if ((ret = RsaFunction(in, inLen, in, &inLen, RSA_PRIVATE_DECRYPT, key)) + < 0) { + return ret; + } + + plainLen = RsaUnPad(in, inLen, out, RSA_BLOCK_TYPE_2); + + return plainLen; +} + +int RsaPrivateDecrypt(const byte* in, word32 inLen, byte* out, word32 outLen, + RsaKey* key) +{ + int plainLen, ret; + byte* tmp; + byte* pad = 0; + + if ( !(tmp = (byte*)XMALLOC(inLen, key->heap, DYNAMIC_TYPE_RSA)) ) + return MEMORY_E; + + XMEMCPY(tmp, in, inLen); + + if ((ret = plainLen = RsaPrivateDecryptInline(tmp, inLen, &pad, key)) + < 0) { + XFREE(tmp, key->heap, DYNAMIC_TYPE_RSA); + return ret; + } + XMEMCPY(out, pad, plainLen); + XMEMSET(tmp, 0x00, inLen); + + XFREE(tmp, key->heap, DYNAMIC_TYPE_RSA); + return plainLen; +} + + +/* for Rsa Verify */ +int RsaSSL_VerifyInline(byte* in, word32 inLen, byte** out, RsaKey* key) +{ + int plainLen, ret; + + if ((ret = RsaFunction(in, inLen, in, &inLen, RSA_PUBLIC_DECRYPT, key)) + < 0) { + return ret; + } + + plainLen = RsaUnPad(in, inLen, out, RSA_BLOCK_TYPE_1); + + return plainLen; +} + +int RsaSSL_Verify(const byte* in, word32 inLen, byte* out, word32 outLen, + RsaKey* key) +{ + int plainLen, ret; + byte* tmp; + byte* pad = 0; + + if ( !(tmp = (byte*)XMALLOC(inLen, key->heap, DYNAMIC_TYPE_RSA)) ) + return MEMORY_E; + + XMEMCPY(tmp, in, inLen); + + if ((ret = plainLen = RsaSSL_VerifyInline(tmp, inLen, &pad, key)) + < 0) { + XFREE(tmp, key->heap, DYNAMIC_TYPE_RSA); + return ret; + } + + XMEMCPY(out, pad, plainLen); + XMEMSET(tmp, 0x00, inLen); + + XFREE(tmp, key->heap, DYNAMIC_TYPE_RSA); + return plainLen; +} + + +/* for Rsa Sign */ +int RsaSSL_Sign(const byte* in, word32 inLen, byte* out, word32 outLen, + RsaKey* key, RNG* rng) +{ + int sz = mp_unsigned_bin_size(&key->n), ret; + + if (sz > (int)outLen) + return RSA_BUFFER_E; + + if (inLen > (word32)(sz - RSA_MIN_PAD_SZ)) + return RSA_BUFFER_E; + + RsaPad(in, inLen, out, sz, RSA_BLOCK_TYPE_1, rng); + + if ((ret = RsaFunction(out, sz, out, &outLen, RSA_PRIVATE_ENCRYPT,key)) < 0) + sz = ret; + + return sz; +} + + +int RsaEncryptSize(RsaKey* key) +{ + return mp_unsigned_bin_size(&key->n); +} + + +#ifdef CYASSL_KEY_GEN + +static const int USE_BBS = 1; + +static int rand_prime(mp_int* N, int len, RNG* rng, void* heap) +{ + int err, res, type; + byte* buf; + + if (N == NULL || rng == NULL) + return -1; + + /* 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 -1; + } + + /* allocate buffer to work with */ + buf = XMALLOC(len, heap, DYNAMIC_TYPE_RSA); + if (buf == NULL) { + return -1; + } + XMEMSET(buf, 0, len); + + do { +#ifdef SHOW_GEN + printf("."); + fflush(stdout); +#endif + /* generate value */ + RNG_GenerateBlock(rng, buf, len); + + /* 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)) != MP_OKAY) { + XFREE(buf, heap, DYNAMIC_TYPE_RSA); + return err; + } + + /* test */ + if ((err = mp_prime_is_prime(N, 8, &res)) != MP_OKAY) { + XFREE(buf, heap, DYNAMIC_TYPE_RSA); + return err; + } + } while (res == MP_NO); + +#ifdef LTC_CLEAN_STACK + XMEMSET(buf, 0, len); +#endif + + XFREE(buf, heap, DYNAMIC_TYPE_RSA); + return 0; +} + + +/* Make an RSA key for size bits, with e specified, 65537 is a good e */ +int MakeRsaKey(RsaKey* key, int size, long e, RNG* rng) +{ + mp_int p, q, tmp1, tmp2, tmp3; + int err; + + if (key == NULL || rng == NULL) + return -1; + + if (size < RSA_MIN_SIZE || size > RSA_MAX_SIZE) + return -1; + + if (e < 3 || (e & 1) == 0) + return -1; + + if ((err = mp_init_multi(&p, &q, &tmp1, &tmp2, &tmp3, NULL)) != MP_OKAY) + return err; + + err = mp_set_int(&tmp3, e); + + /* make p */ + if (err == MP_OKAY) { + do { + err = rand_prime(&p, size/16, rng, key->heap); /* size in bytes/2 */ + + if (err == MP_OKAY) + err = mp_sub_d(&p, 1, &tmp1); /* tmp1 = p-1 */ + + if (err == MP_OKAY) + err = mp_gcd(&tmp1, &tmp3, &tmp2); /* tmp2 = gcd(p-1, e) */ + } while (err == MP_OKAY && mp_cmp_d(&tmp2, 1) != 0); /* e divdes p-1 */ + } + + /* make q */ + if (err == MP_OKAY) { + do { + err = rand_prime(&q, size/16, rng, key->heap); /* size in bytes/2 */ + + if (err == MP_OKAY) + err = mp_sub_d(&q, 1, &tmp1); /* tmp1 = q-1 */ + + if (err == MP_OKAY) + err = mp_gcd(&tmp1, &tmp3, &tmp2); /* tmp2 = gcd(q-1, e) */ + } while (err == MP_OKAY && mp_cmp_d(&tmp2, 1) != 0); /* e divdes q-1 */ + } + + if (err == MP_OKAY) + err = mp_init_multi(&key->n, &key->e, &key->d, &key->p, &key->q, NULL); + + if (err == MP_OKAY) + err = mp_init_multi(&key->dP, &key->dP, &key->u, NULL, NULL, NULL); + + if (err == MP_OKAY) + err = mp_sub_d(&p, 1, &tmp2); /* tmp2 = p-1 */ + + if (err == MP_OKAY) + err = mp_lcm(&tmp1, &tmp2, &tmp1); /* tmp1 = lcm(p-1, q-1),last loop */ + + /* make key */ + if (err == MP_OKAY) + err = mp_set_int(&key->e, e); /* key->e = e */ + + if (err == MP_OKAY) /* key->d = 1/e mod lcm(p-1, q-1) */ + err = mp_invmod(&key->e, &tmp1, &key->d); + + if (err == MP_OKAY) + err = mp_mul(&p, &q, &key->n); /* key->n = pq */ + + if (err == MP_OKAY) + err = mp_sub_d(&p, 1, &tmp1); + + if (err == MP_OKAY) + err = mp_sub_d(&q, 1, &tmp2); + + if (err == MP_OKAY) + err = mp_mod(&key->d, &tmp1, &key->dP); + + if (err == MP_OKAY) + err = mp_mod(&key->d, &tmp2, &key->dQ); + + if (err == MP_OKAY) + err = mp_invmod(&q, &p, &key->u); + + if (err == MP_OKAY) + err = mp_copy(&p, &key->p); + + if (err == MP_OKAY) + err = mp_copy(&q, &key->q); + + if (err == MP_OKAY) + key->type = RSA_PRIVATE; + + mp_clear(&tmp3); + mp_clear(&tmp2); + mp_clear(&tmp1); + mp_clear(&q); + mp_clear(&p); + + if (err != MP_OKAY) { + FreeRsaKey(key); + return err; + } + + return 0; +} + + +#endif /* CYASLS_KEY_GEN */ + diff --git a/ctaocrypt/src/sha.c b/ctaocrypt/src/sha.c new file mode 100644 index 000000000..e0c132bc0 --- /dev/null +++ b/ctaocrypt/src/sha.c @@ -0,0 +1,198 @@ +/* sha.c + * + * Copyright (C) 2006-2011 Sawtooth Consulting Ltd. + * + * This file is part of CyaSSL. + * + * CyaSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * CyaSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + + +#include "ctc_sha.h" +#ifdef NO_INLINE + #include "misc.h" +#else + #include "misc.c" +#endif + + +#ifndef min + + static INLINE word32 min(word32 a, word32 b) + { + return a > b ? b : a; + } + +#endif /* min */ + + +void InitSha(Sha* sha) +{ + sha->digest[0] = 0x67452301L; + sha->digest[1] = 0xEFCDAB89L; + sha->digest[2] = 0x98BADCFEL; + sha->digest[3] = 0x10325476L; + sha->digest[4] = 0xC3D2E1F0L; + + sha->buffLen = 0; + sha->loLen = 0; + sha->hiLen = 0; +} + +#define blk0(i) (W[i] = sha->buffer[i]) +#define blk1(i) (W[i&15] = \ + rotlFixed(W[(i+13)&15]^W[(i+8)&15]^W[(i+2)&15]^W[i&15],1)) + +#define f1(x,y,z) (z^(x &(y^z))) +#define f2(x,y,z) (x^y^z) +#define f3(x,y,z) ((x&y)|(z&(x|y))) +#define f4(x,y,z) (x^y^z) + +/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */ +#define R0(v,w,x,y,z,i) z+= f1(w,x,y) + blk0(i) + 0x5A827999+ \ + rotlFixed(v,5); w = rotlFixed(w,30); +#define R1(v,w,x,y,z,i) z+= f1(w,x,y) + blk1(i) + 0x5A827999+ \ + rotlFixed(v,5); w = rotlFixed(w,30); +#define R2(v,w,x,y,z,i) z+= f2(w,x,y) + blk1(i) + 0x6ED9EBA1+ \ + rotlFixed(v,5); w = rotlFixed(w,30); +#define R3(v,w,x,y,z,i) z+= f3(w,x,y) + blk1(i) + 0x8F1BBCDC+ \ + rotlFixed(v,5); w = rotlFixed(w,30); +#define R4(v,w,x,y,z,i) z+= f4(w,x,y) + blk1(i) + 0xCA62C1D6+ \ + rotlFixed(v,5); w = rotlFixed(w,30); + + +static void Transform(Sha* sha) +{ + word32 W[SHA_BLOCK_SIZE / sizeof(word32)]; + + /* Copy context->state[] to working vars */ + word32 a = sha->digest[0]; + word32 b = sha->digest[1]; + word32 c = sha->digest[2]; + word32 d = sha->digest[3]; + word32 e = sha->digest[4]; + + /* nearly 1 K bigger in code size but 25% faster */ + /* 4 rounds of 20 operations each. Loop unrolled. */ + R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3); + R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7); + R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11); + R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15); + + R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19); + + R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23); + R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27); + R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31); + R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35); + R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39); + + R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43); + R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47); + R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51); + R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55); + R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59); + + R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63); + R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67); + R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71); + R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75); + R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79); + + /* Add the working vars back into digest state[] */ + sha->digest[0] += a; + sha->digest[1] += b; + sha->digest[2] += c; + sha->digest[3] += d; + sha->digest[4] += e; +} + + +static INLINE void AddLength(Sha* sha, word32 len) +{ + word32 tmp = sha->loLen; + if ( (sha->loLen += len) < tmp) + sha->hiLen++; /* carry low to high */ +} + + +void ShaUpdate(Sha* sha, const byte* data, word32 len) +{ + /* do block size increments */ + byte* local = (byte*)sha->buffer; + + while (len) { + word32 add = min(len, SHA_BLOCK_SIZE - sha->buffLen); + XMEMCPY(&local[sha->buffLen], data, add); + + sha->buffLen += add; + data += add; + len -= add; + + if (sha->buffLen == SHA_BLOCK_SIZE) { + #ifdef LITTLE_ENDIAN_ORDER + ByteReverseBytes(local, local, SHA_BLOCK_SIZE); + #endif + Transform(sha); + AddLength(sha, SHA_BLOCK_SIZE); + sha->buffLen = 0; + } + } +} + + +void ShaFinal(Sha* sha, byte* hash) +{ + byte* local = (byte*)sha->buffer; + + AddLength(sha, sha->buffLen); /* before adding pads */ + + local[sha->buffLen++] = 0x80; /* add 1 */ + + /* pad with zeros */ + if (sha->buffLen > SHA_PAD_SIZE) { + XMEMSET(&local[sha->buffLen], 0, SHA_BLOCK_SIZE - sha->buffLen); + sha->buffLen += SHA_BLOCK_SIZE - sha->buffLen; + + #ifdef LITTLE_ENDIAN_ORDER + ByteReverseBytes(local, local, SHA_BLOCK_SIZE); + #endif + Transform(sha); + sha->buffLen = 0; + } + XMEMSET(&local[sha->buffLen], 0, SHA_PAD_SIZE - sha->buffLen); + + /* put lengths in bits */ + sha->loLen = sha->loLen << 3; + sha->hiLen = (sha->loLen >> (8*sizeof(sha->loLen) - 3)) + + (sha->hiLen << 3); + + /* store lengths */ + #ifdef LITTLE_ENDIAN_ORDER + ByteReverseBytes(local, local, SHA_BLOCK_SIZE); + #endif + /* ! length ordering dependent on digest endian type ! */ + XMEMCPY(&local[SHA_PAD_SIZE], &sha->hiLen, sizeof(word32)); + XMEMCPY(&local[SHA_PAD_SIZE + sizeof(word32)], &sha->loLen, sizeof(word32)); + + Transform(sha); + #ifdef LITTLE_ENDIAN_ORDER + ByteReverseWords(sha->digest, sha->digest, SHA_DIGEST_SIZE); + #endif + XMEMCPY(hash, sha->digest, SHA_DIGEST_SIZE); + + InitSha(sha); /* reset state */ +} + diff --git a/ctaocrypt/src/sha256.c b/ctaocrypt/src/sha256.c new file mode 100644 index 000000000..e94aa4250 --- /dev/null +++ b/ctaocrypt/src/sha256.c @@ -0,0 +1,206 @@ +/* sha256.c + * + * Copyright (C) 2006-2011 Sawtooth Consulting Ltd. + * + * This file is part of CyaSSL. + * + * CyaSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * CyaSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +/* code submitted by raphael.huck@efixo.com */ + + + +#ifndef NO_SHA256 + +#include "sha256.h" +#ifdef NO_INLINE + #include "misc.h" +#else + #include "misc.c" +#endif + + +#ifndef min + + static INLINE word32 min(word32 a, word32 b) + { + return a > b ? b : a; + } + +#endif /* min */ + + +void InitSha256(Sha256* sha256) +{ + sha256->digest[0] = 0x6A09E667L; + sha256->digest[1] = 0xBB67AE85L; + sha256->digest[2] = 0x3C6EF372L; + sha256->digest[3] = 0xA54FF53AL; + sha256->digest[4] = 0x510E527FL; + sha256->digest[5] = 0x9B05688CL; + sha256->digest[6] = 0x1F83D9ABL; + sha256->digest[7] = 0x5BE0CD19L; + + sha256->buffLen = 0; + sha256->loLen = 0; + sha256->hiLen = 0; +} + +static const word32 K[64] = { + 0x428A2F98L, 0x71374491L, 0xB5C0FBCFL, 0xE9B5DBA5L, 0x3956C25BL, + 0x59F111F1L, 0x923F82A4L, 0xAB1C5ED5L, 0xD807AA98L, 0x12835B01L, + 0x243185BEL, 0x550C7DC3L, 0x72BE5D74L, 0x80DEB1FEL, 0x9BDC06A7L, + 0xC19BF174L, 0xE49B69C1L, 0xEFBE4786L, 0x0FC19DC6L, 0x240CA1CCL, + 0x2DE92C6FL, 0x4A7484AAL, 0x5CB0A9DCL, 0x76F988DAL, 0x983E5152L, + 0xA831C66DL, 0xB00327C8L, 0xBF597FC7L, 0xC6E00BF3L, 0xD5A79147L, + 0x06CA6351L, 0x14292967L, 0x27B70A85L, 0x2E1B2138L, 0x4D2C6DFCL, + 0x53380D13L, 0x650A7354L, 0x766A0ABBL, 0x81C2C92EL, 0x92722C85L, + 0xA2BFE8A1L, 0xA81A664BL, 0xC24B8B70L, 0xC76C51A3L, 0xD192E819L, + 0xD6990624L, 0xF40E3585L, 0x106AA070L, 0x19A4C116L, 0x1E376C08L, + 0x2748774CL, 0x34B0BCB5L, 0x391C0CB3L, 0x4ED8AA4AL, 0x5B9CCA4FL, + 0x682E6FF3L, 0x748F82EEL, 0x78A5636FL, 0x84C87814L, 0x8CC70208L, + 0x90BEFFFAL, 0xA4506CEBL, 0xBEF9A3F7L, 0xC67178F2L +}; + +#define Ch(x,y,z) (z ^ (x & (y ^ z))) +#define Maj(x,y,z) (((x | y) & z) | (x & y)) +#define S(x, n) rotrFixed(x, n) +#define R(x, n) (((x)&0xFFFFFFFFL)>>(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)) + +#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; + + +static void Transform(Sha256* sha256) +{ + word32 S[8], W[64], t0, t1; + int i; + + /* Copy context->state[] to working vars */ + for (i = 0; i < 8; i++) + S[i] = sha256->digest[i]; + + for (i = 0; i < 16; i++) + W[i] = sha256->buffer[i]; + + for (i = 16; i < 64; i++) + W[i] = Gamma1(W[i-2]) + W[i-7] + Gamma0(W[i-15]) + W[i-16]; + + for (i = 0; i < 64; 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); + } + + /* Add the working vars back into digest state[] */ + for (i = 0; i < 8; i++) { + sha256->digest[i] += S[i]; + } +} + + +static INLINE void AddLength(Sha256* sha256, word32 len) +{ + word32 tmp = sha256->loLen; + if ( (sha256->loLen += len) < tmp) + sha256->hiLen++; /* carry low to high */ +} + + +void Sha256Update(Sha256* sha256, const byte* data, word32 len) +{ + /* do block size increments */ + byte* local = (byte*)sha256->buffer; + + while (len) { + word32 add = min(len, SHA256_BLOCK_SIZE - sha256->buffLen); + XMEMCPY(&local[sha256->buffLen], data, add); + + sha256->buffLen += add; + data += add; + len -= add; + + if (sha256->buffLen == SHA256_BLOCK_SIZE) { + #ifdef LITTLE_ENDIAN_ORDER + ByteReverseBytes(local, local, SHA256_BLOCK_SIZE); + #endif + Transform(sha256); + AddLength(sha256, SHA256_BLOCK_SIZE); + sha256->buffLen = 0; + } + } +} + + +void Sha256Final(Sha256* sha256, byte* hash) +{ + byte* local = (byte*)sha256->buffer; + + AddLength(sha256, sha256->buffLen); /* before adding pads */ + + local[sha256->buffLen++] = 0x80; /* add 1 */ + + /* pad with zeros */ + if (sha256->buffLen > SHA256_PAD_SIZE) { + XMEMSET(&local[sha256->buffLen], 0, SHA256_BLOCK_SIZE - sha256->buffLen); + sha256->buffLen += SHA256_BLOCK_SIZE - sha256->buffLen; + + #ifdef LITTLE_ENDIAN_ORDER + ByteReverseBytes(local, local, SHA256_BLOCK_SIZE); + #endif + Transform(sha256); + sha256->buffLen = 0; + } + XMEMSET(&local[sha256->buffLen], 0, SHA256_PAD_SIZE - sha256->buffLen); + + /* put lengths in bits */ + sha256->loLen = sha256->loLen << 3; + sha256->hiLen = (sha256->loLen >> (8*sizeof(sha256->loLen) - 3)) + + (sha256->hiLen << 3); + + /* store lengths */ + #ifdef LITTLE_ENDIAN_ORDER + ByteReverseBytes(local, local, SHA256_BLOCK_SIZE); + #endif + /* ! length ordering dependent on digest endian type ! */ + XMEMCPY(&local[SHA256_PAD_SIZE], &sha256->hiLen, sizeof(word32)); + XMEMCPY(&local[SHA256_PAD_SIZE + sizeof(word32)], &sha256->loLen, + sizeof(word32)); + + Transform(sha256); + #ifdef LITTLE_ENDIAN_ORDER + ByteReverseWords(sha256->digest, sha256->digest, SHA256_DIGEST_SIZE); + #endif + XMEMCPY(hash, sha256->digest, SHA256_DIGEST_SIZE); + + InitSha256(sha256); /* reset state */ +} + + +#endif /* NO_SHA256 */ + diff --git a/ctaocrypt/src/sha512.c b/ctaocrypt/src/sha512.c new file mode 100644 index 000000000..8bdfd96ac --- /dev/null +++ b/ctaocrypt/src/sha512.c @@ -0,0 +1,242 @@ +/* sha512.c + * + * Copyright (C) 2006-2011 Sawtooth Consulting Ltd. + * + * This file is part of CyaSSL. + * + * CyaSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * CyaSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + + +#ifdef CYASSL_SHA512 + +#include "sha512.h" +#ifdef NO_INLINE + #include "misc.h" +#else + #include "misc.c" +#endif + + +#ifndef min + + static INLINE word32 min(word32 a, word32 b) + { + return a > b ? b : a; + } + +#endif /* min */ + + +void InitSha512(Sha512* sha512) +{ + sha512->digest[0] = W64LIT(0x6a09e667f3bcc908); + sha512->digest[1] = W64LIT(0xbb67ae8584caa73b); + sha512->digest[2] = W64LIT(0x3c6ef372fe94f82b); + sha512->digest[3] = W64LIT(0xa54ff53a5f1d36f1); + sha512->digest[4] = W64LIT(0x510e527fade682d1); + sha512->digest[5] = W64LIT(0x9b05688c2b3e6c1f); + sha512->digest[6] = W64LIT(0x1f83d9abfb41bd6b); + sha512->digest[7] = W64LIT(0x5be0cd19137e2179); + + sha512->buffLen = 0; + sha512->loLen = 0; + sha512->hiLen = 0; +} + + +static const word64 K512[80] = { + W64LIT(0x428a2f98d728ae22), W64LIT(0x7137449123ef65cd), + W64LIT(0xb5c0fbcfec4d3b2f), W64LIT(0xe9b5dba58189dbbc), + W64LIT(0x3956c25bf348b538), W64LIT(0x59f111f1b605d019), + W64LIT(0x923f82a4af194f9b), W64LIT(0xab1c5ed5da6d8118), + W64LIT(0xd807aa98a3030242), W64LIT(0x12835b0145706fbe), + W64LIT(0x243185be4ee4b28c), W64LIT(0x550c7dc3d5ffb4e2), + W64LIT(0x72be5d74f27b896f), W64LIT(0x80deb1fe3b1696b1), + W64LIT(0x9bdc06a725c71235), W64LIT(0xc19bf174cf692694), + W64LIT(0xe49b69c19ef14ad2), W64LIT(0xefbe4786384f25e3), + W64LIT(0x0fc19dc68b8cd5b5), W64LIT(0x240ca1cc77ac9c65), + W64LIT(0x2de92c6f592b0275), W64LIT(0x4a7484aa6ea6e483), + W64LIT(0x5cb0a9dcbd41fbd4), W64LIT(0x76f988da831153b5), + W64LIT(0x983e5152ee66dfab), W64LIT(0xa831c66d2db43210), + W64LIT(0xb00327c898fb213f), W64LIT(0xbf597fc7beef0ee4), + W64LIT(0xc6e00bf33da88fc2), W64LIT(0xd5a79147930aa725), + W64LIT(0x06ca6351e003826f), W64LIT(0x142929670a0e6e70), + W64LIT(0x27b70a8546d22ffc), W64LIT(0x2e1b21385c26c926), + W64LIT(0x4d2c6dfc5ac42aed), W64LIT(0x53380d139d95b3df), + W64LIT(0x650a73548baf63de), W64LIT(0x766a0abb3c77b2a8), + W64LIT(0x81c2c92e47edaee6), W64LIT(0x92722c851482353b), + W64LIT(0xa2bfe8a14cf10364), W64LIT(0xa81a664bbc423001), + W64LIT(0xc24b8b70d0f89791), W64LIT(0xc76c51a30654be30), + W64LIT(0xd192e819d6ef5218), W64LIT(0xd69906245565a910), + W64LIT(0xf40e35855771202a), W64LIT(0x106aa07032bbd1b8), + W64LIT(0x19a4c116b8d2d0c8), W64LIT(0x1e376c085141ab53), + W64LIT(0x2748774cdf8eeb99), W64LIT(0x34b0bcb5e19b48a8), + W64LIT(0x391c0cb3c5c95a63), W64LIT(0x4ed8aa4ae3418acb), + W64LIT(0x5b9cca4f7763e373), W64LIT(0x682e6ff3d6b2b8a3), + W64LIT(0x748f82ee5defb2fc), W64LIT(0x78a5636f43172f60), + W64LIT(0x84c87814a1f0ab72), W64LIT(0x8cc702081a6439ec), + W64LIT(0x90befffa23631e28), W64LIT(0xa4506cebde82bde9), + W64LIT(0xbef9a3f7b2c67915), W64LIT(0xc67178f2e372532b), + W64LIT(0xca273eceea26619c), W64LIT(0xd186b8c721c0c207), + W64LIT(0xeada7dd6cde0eb1e), W64LIT(0xf57d4f7fee6ed178), + W64LIT(0x06f067aa72176fba), W64LIT(0x0a637dc5a2c898a6), + W64LIT(0x113f9804bef90dae), W64LIT(0x1b710b35131c471b), + W64LIT(0x28db77f523047d84), W64LIT(0x32caab7b40c72493), + W64LIT(0x3c9ebe0a15c9bebc), W64LIT(0x431d67c49c100d4c), + W64LIT(0x4cc5d4becb3e42b6), W64LIT(0x597f299cfc657e2a), + W64LIT(0x5fcb6fab3ad6faec), W64LIT(0x6c44198c4a475817) +}; + + +#define blk0(i) (W[i] = sha512->buffer[i]) +#define blk2(i) (W[i&15]+=s1(W[(i-2)&15])+W[(i-7)&15]+s0(W[(i-15)&15])) + +#define Ch(x,y,z) (z^(x&(y^z))) +#define Maj(x,y,z) ((x&y)|(z&(x|y))) + +#define a(i) T[(0-i)&7] +#define b(i) T[(1-i)&7] +#define c(i) T[(2-i)&7] +#define d(i) T[(3-i)&7] +#define e(i) T[(4-i)&7] +#define f(i) T[(5-i)&7] +#define g(i) T[(6-i)&7] +#define h(i) T[(7-i)&7] + +#define S0(x) (rotrFixed64(x,28)^rotrFixed64(x,34)^rotrFixed64(x,39)) +#define S1(x) (rotrFixed64(x,14)^rotrFixed64(x,18)^rotrFixed64(x,41)) +#define s0(x) (rotrFixed64(x,1)^rotrFixed64(x,8)^(x>>7)) +#define s1(x) (rotrFixed64(x,19)^rotrFixed64(x,61)^(x>>6)) + +#define R(i) h(i)+=S1(e(i))+Ch(e(i),f(i),g(i))+K[i+j]+(j?blk2(i):blk0(i));\ + d(i)+=h(i);h(i)+=S0(a(i))+Maj(a(i),b(i),c(i)) + + +static void Transform(Sha512* sha512) +{ + const word64* K = K512; + + word32 j; + word64 W[16]; + word64 T[8]; + + /* Copy digest to working vars */ + XMEMCPY(T, sha512->digest, sizeof(T)); + + /* 64 operations, partially loop unrolled */ + for (j = 0; j < 80; j += 16) { + R( 0); R( 1); R( 2); R( 3); + R( 4); R( 5); R( 6); R( 7); + R( 8); R( 9); R(10); R(11); + R(12); R(13); R(14); R(15); + } + + /* Add the working vars back into digest */ + + sha512->digest[0] += a(0); + sha512->digest[1] += b(0); + sha512->digest[2] += c(0); + sha512->digest[3] += d(0); + sha512->digest[4] += e(0); + sha512->digest[5] += f(0); + sha512->digest[6] += g(0); + sha512->digest[7] += h(0); + + /* Wipe variables */ + XMEMSET(W, 0, sizeof(W)); + XMEMSET(T, 0, sizeof(T)); +} + + +static INLINE void AddLength(Sha512* sha512, word32 len) +{ + word32 tmp = sha512->loLen; + if ( (sha512->loLen += len) < tmp) + sha512->hiLen++; /* carry low to high */ +} + + +void Sha512Update(Sha512* sha512, const byte* data, word32 len) +{ + /* do block size increments */ + byte* local = (byte*)sha512->buffer; + + while (len) { + word32 add = min(len, SHA512_BLOCK_SIZE - sha512->buffLen); + XMEMCPY(&local[sha512->buffLen], data, add); + + sha512->buffLen += add; + data += add; + len -= add; + + if (sha512->buffLen == SHA512_BLOCK_SIZE) { + #ifdef LITTLE_ENDIAN_ORDER + ByteReverseWords64(sha512->buffer, sha512->buffer, + SHA512_BLOCK_SIZE); + #endif + Transform(sha512); + AddLength(sha512, SHA512_BLOCK_SIZE); + sha512->buffLen = 0; + } + } +} + + +void Sha512Final(Sha512* sha512, byte* hash) +{ + byte* local = (byte*)sha512->buffer; + + AddLength(sha512, sha512->buffLen); /* before adding pads */ + + local[sha512->buffLen++] = 0x80; /* add 1 */ + + /* pad with zeros */ + if (sha512->buffLen > SHA512_PAD_SIZE) { + XMEMSET(&local[sha512->buffLen], 0, SHA512_BLOCK_SIZE - sha512->buffLen); + sha512->buffLen += SHA512_BLOCK_SIZE - sha512->buffLen; + + #ifdef LITTLE_ENDIAN_ORDER + ByteReverseWords64(sha512->buffer,sha512->buffer,SHA512_BLOCK_SIZE); + #endif + Transform(sha512); + sha512->buffLen = 0; + } + XMEMSET(&local[sha512->buffLen], 0, SHA512_PAD_SIZE - sha512->buffLen); + + /* put lengths in bits */ + sha512->loLen = sha512->loLen << 3; + sha512->hiLen = (sha512->loLen >> (8*sizeof(sha512->loLen) - 3)) + + (sha512->hiLen << 3); + + /* store lengths */ + #ifdef LITTLE_ENDIAN_ORDER + ByteReverseWords64(sha512->buffer, sha512->buffer, SHA512_PAD_SIZE); + #endif + /* ! length ordering dependent on digest endian type ! */ + sha512->buffer[SHA512_BLOCK_SIZE / sizeof(word64) - 2] = sha512->hiLen; + sha512->buffer[SHA512_BLOCK_SIZE / sizeof(word64) - 1] = sha512->loLen; + + Transform(sha512); + #ifdef LITTLE_ENDIAN_ORDER + ByteReverseWords64(sha512->digest, sha512->digest, SHA512_DIGEST_SIZE); + #endif + XMEMCPY(hash, sha512->digest, SHA512_DIGEST_SIZE); + + InitSha512(sha512); /* reset state */ +} + + +#endif /* CYASSL_SHA512 */ diff --git a/ctaocrypt/src/tfm.c b/ctaocrypt/src/tfm.c new file mode 100644 index 000000000..f8089415f --- /dev/null +++ b/ctaocrypt/src/tfm.c @@ -0,0 +1,2429 @@ +/* tfm.c + * + * Copyright (C) 2006-2011 Sawtooth Consulting Ltd. + * + * This file is part of CyaSSL. + * + * CyaSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * CyaSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +/* + * Based on public domain TomsFastMath 0.10 by Tom St Denis, tomstdenis@iahu.ca, + * http://math.libtomcrypt.com + */ + +/** + * Edited by Moisés Guimarães (moises.guimaraes@phoebus.com.br) + * to fit CyaSSL's needs. + */ + + +#ifdef USE_FAST_MATH + +#include "tfm.h" +#include "asm.c" /* will define asm MACROS or C ones */ + + + +/* Functions */ + +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); + } + } +} + +/* 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 = c->used; + 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); +} + +/* 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); + } + } +} + +/* 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); + } + for (; x < oldused; x++) { + c->dp[x] = 0; + } + fp_clamp(c); +} + +/* c = a * b */ +void fp_mul(fp_int *A, fp_int *B, fp_int *C) +{ + int y, yy; + + y = MAX(A->used, B->used); + yy = MIN(A->used, B->used); + + /* call generic if we're out of range */ + if (y + yy > FP_SIZE) { + fp_mul_comba(A, B, C); + return ; + } + + /* 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 + */ + +#ifdef TFM_MUL3 + if (y <= 3) { + fp_mul_comba3(A,B,C); + return; + } +#endif +#ifdef TFM_MUL4 + if (y == 4) { + fp_mul_comba4(A,B,C); + return; + } +#endif +#ifdef TFM_MUL6 + if (y <= 6) { + fp_mul_comba6(A,B,C); + return; + } +#endif +#ifdef TFM_MUL7 + if (y == 7) { + fp_mul_comba7(A,B,C); + return; + } +#endif +#ifdef TFM_MUL8 + if (y == 8) { + fp_mul_comba8(A,B,C); + return; + } +#endif +#ifdef TFM_MUL9 + if (y == 9) { + fp_mul_comba9(A,B,C); + return; + } +#endif +#ifdef TFM_MUL12 + if (y <= 12) { + fp_mul_comba12(A,B,C); + return; + } +#endif +#ifdef TFM_MUL17 + if (y <= 17) { + fp_mul_comba17(A,B,C); + return; + } +#endif + +#ifdef TFM_SMALL_SET + if (y <= 16) { + fp_mul_comba_small(A,B,C); + return; + } +#endif +#if defined(TFM_MUL20) + if (y <= 20) { + fp_mul_comba20(A,B,C); + return; + } +#endif +#if defined(TFM_MUL24) + if (yy >= 16 && y <= 24) { + fp_mul_comba24(A,B,C); + return; + } +#endif +#if defined(TFM_MUL28) + if (yy >= 20 && y <= 28) { + fp_mul_comba28(A,B,C); + return; + } +#endif +#if defined(TFM_MUL32) + if (yy >= 24 && y <= 32) { + fp_mul_comba32(A,B,C); + return; + } +#endif +#if defined(TFM_MUL48) + if (yy >= 40 && y <= 48) { + fp_mul_comba48(A,B,C); + return; + } +#endif +#if defined(TFM_MUL64) + if (yy >= 56 && y <= 64) { + fp_mul_comba64(A,B,C); + return; + } +#endif + fp_mul_comba(A,B,C); +} + +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; +} + +/* 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++] = (fp_digit) w; + ++x; + } + for (; x < oldused; x++) { + c->dp[x] = 0; + } + fp_clamp(c); +} + +/* 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); +} + +/* 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) { + /* TAO change COMBA_ADD back to MULADD */ + 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); +} + +/* 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; +} + +/* 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); +} + +/* 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); + } +} + +/* 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; +} + +/* 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); +} + +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; +} + +/* 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); +} + +#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 */ + XMEMSET(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; + + /* prevent overflows */ + if (P->used > (FP_SIZE/2)) { + return FP_VAL; + } + + /* 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); + } +} + +/* 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); +} + +/* b = a*a */ +void fp_sqr(fp_int *A, fp_int *B) +{ + int y = A->used; + + /* call generic if we're out of range */ + if (y + y > FP_SIZE) { + fp_sqr_comba(A, B); + return ; + } + +#if defined(TFM_SQR3) + if (y <= 3) { + fp_sqr_comba3(A,B); + return; + } +#endif +#if defined(TFM_SQR4) + if (y == 4) { + fp_sqr_comba4(A,B); + return; + } +#endif +#if defined(TFM_SQR6) + if (y <= 6) { + fp_sqr_comba6(A,B); + return; + } +#endif +#if defined(TFM_SQR7) + if (y == 7) { + fp_sqr_comba7(A,B); + return; + } +#endif +#if defined(TFM_SQR8) + if (y == 8) { + fp_sqr_comba8(A,B); + return; + } +#endif +#if defined(TFM_SQR9) + if (y == 9) { + fp_sqr_comba9(A,B); + return; + } +#endif +#if defined(TFM_SQR12) + if (y <= 12) { + fp_sqr_comba12(A,B); + return; + } +#endif +#if defined(TFM_SQR17) + if (y <= 17) { + fp_sqr_comba17(A,B); + return; + } +#endif +#if defined(TFM_SMALL_SET) + if (y <= 16) { + fp_sqr_comba_small(A,B); + return; + } +#endif +#if defined(TFM_SQR20) + if (y <= 20) { + fp_sqr_comba20(A,B); + return; + } +#endif +#if defined(TFM_SQR24) + if (y <= 24) { + fp_sqr_comba24(A,B); + return; + } +#endif +#if defined(TFM_SQR28) + if (y <= 28) { + fp_sqr_comba28(A,B); + return; + } +#endif +#if defined(TFM_SQR32) + if (y <= 32) { + fp_sqr_comba32(A,B); + return; + } +#endif +#if defined(TFM_SQR48) + if (y <= 48) { + fp_sqr_comba48(A,B); + return; + } +#endif +#if defined(TFM_SQR64) + if (y <= 64) { + fp_sqr_comba64(A,B); + return; + } +#endif + fp_sqr_comba(A, B); +} + +/* 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; + COMBA_CLEAR; + + 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 */ + COMBA_FORWARD; + + /* execute loop */ + for (iz = 0; iz < iy; iz++) { + SQRADD2(*tmpx++, *tmpy--); + } + + /* even columns have the square term in them */ + if ((ix&1) == 0) { + /* TAO change COMBA_ADD back to SQRADD */ + SQRADD(A->dp[ix>>1], 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); + } +} + +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); + } + } +} + +/* 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; + } + +} + +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; +} + +/* 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_digit) (((fp_word) 1 << ((fp_word) DIGIT_BIT)) - ((fp_word)x)); + + return FP_OKAY; +} + +/* 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); + } + } +} + + +#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)) { + (void)mu; /* shut up compiler */ + 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 */ + XMEMSET(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(TFM_SSE2) || defined(TFM_X86_64)) + 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); + } +} + +void fp_read_unsigned_bin(fp_int *a, 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); +} + +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); +} + +int fp_unsigned_bin_size(fp_int *a) +{ + int size = fp_count_bits (a); + return (size / 8 + ((size & 7) != 0 ? 1 : 0)); +} + +void fp_set(fp_int *a, fp_digit b) +{ + fp_zero(a); + a->dp[0] = b; + a->used = a->dp[0] ? 1 : 0; +} + +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; +} + +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); +} + +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); +} + +/* 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; + } +} + + +/* CyaSSL callers from normal lib */ + +/* init a new mp_int */ +int mp_init (mp_int * a) +{ + if (a) + fp_init(a); + return MP_OKAY; +} + +/* clear one (frees) */ +void mp_clear (mp_int * a) +{ + fp_zero(a); +} + +/* handle up to 6 inits */ +int mp_init_multi(mp_int* a, mp_int* b, mp_int* c, mp_int* d, mp_int* e, mp_int* f) +{ + if (a) + fp_init(a); + if (b) + fp_init(b); + if (c) + fp_init(c); + if (d) + fp_init(d); + if (e) + fp_init(e); + if (f) + fp_init(f); + + return MP_OKAY; +} + +/* high level addition (handles signs) */ +int mp_add (mp_int * a, mp_int * b, mp_int * c) +{ + fp_add(a, b, c); + return MP_OKAY; +} + +/* high level subtraction (handles signs) */ +int mp_sub (mp_int * a, mp_int * b, mp_int * c) +{ + fp_sub(a, b, c); + return MP_OKAY; +} + +/* high level multiplication (handles sign) */ +int mp_mul (mp_int * a, mp_int * b, mp_int * c) +{ + fp_mul(a, b, c); + return MP_OKAY; +} + +/* d = a * b (mod c) */ +int mp_mulmod (mp_int * a, mp_int * b, mp_int * c, mp_int * d) +{ + return fp_mulmod(a, b, c, d); +} + +/* c = a mod b, 0 <= c < b */ +int mp_mod (mp_int * a, mp_int * b, mp_int * c) +{ + return fp_mod (a, b, c); +} + +/* hac 14.61, pp608 */ +int mp_invmod (mp_int * a, mp_int * b, mp_int * c) +{ + return fp_invmod(a, b, c); +} + +/* this is a shell function that calls either the normal or Montgomery + * exptmod functions. Originally the call to the montgomery code was + * embedded in the normal function but that wasted alot of stack space + * for nothing (since 99% of the time the Montgomery code would be called) + */ +int mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y) +{ + return fp_exptmod(G, X, P, Y); +} + +/* compare two ints (signed)*/ +int mp_cmp (mp_int * a, mp_int * b) +{ + return fp_cmp(a, b); +} + +/* compare a digit */ +int mp_cmp_d(mp_int * a, mp_digit b) +{ + return fp_cmp_d(a, b); +} + +/* get the size for an unsigned equivalent */ +int mp_unsigned_bin_size (mp_int * a) +{ + return fp_unsigned_bin_size(a); +} + +/* store in unsigned [big endian] format */ +int mp_to_unsigned_bin (mp_int * a, unsigned char *b) +{ + fp_to_unsigned_bin(a,b); + return MP_OKAY; +} + +/* reads a unsigned char array, assumes the msb is stored first [big endian] */ +int mp_read_unsigned_bin (mp_int * a, const unsigned char *b, int c) +{ + fp_read_unsigned_bin(a, (unsigned char *)b, c); + return MP_OKAY; +} + + +#if defined(CYASSL_KEY_GEN) || defined (HAVE_ECC) + +/* 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); +} + +/* fast math conversion */ +int mp_sqrmod(mp_int *a, mp_int *b, mp_int *c) +{ + return fp_sqrmod(a, b, c); +} + +/* fast math conversion */ +int mp_montgomery_calc_normalization(mp_int *a, mp_int *b) +{ + fp_montgomery_calc_normalization(a, b); + return MP_OKAY; +} + +/* fast math conversion */ +int mp_copy(fp_int* a, fp_int* b) +{ + fp_copy(a, b); + return MP_OKAY; +} + + +#endif /* CYASSL_KEYGEN || HAVE_ECC */ + + +#ifdef CYASSL_KEY_GEN + +void fp_gcd(fp_int *a, fp_int *b, fp_int *c); +void fp_lcm(fp_int *a, fp_int *b, fp_int *c); +void fp_sub_d(fp_int *a, fp_digit b, fp_int *c); +int fp_isprime(fp_int *a); +int fp_cnt_lsb(fp_int *a); + +/* fast math wrappers */ +int mp_set_int(fp_int *a, fp_digit b) +{ + fp_set(a, b); + return MP_OKAY; +} + + +int mp_gcd(fp_int *a, fp_int *b, fp_int *c) +{ + fp_gcd(a, b, c); + return MP_OKAY; +} + + +int mp_lcm(fp_int *a, fp_int *b, fp_int *c) +{ + fp_lcm(a, b, c); + return MP_OKAY; +} + + +int mp_sub_d(fp_int *a, fp_digit b, fp_int *c) +{ + fp_sub_d(a, b, c); + return MP_OKAY; +} + + +int mp_prime_is_prime(mp_int* a, int t, int* result) +{ + *result = fp_isprime(a); + return MP_OKAY; +} + + + +/* 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); +} + + +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)< 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)<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; +} + + +/* 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); +} + + +/* 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; +} + + +/* a few primes */ +static const fp_digit primes[256] = { + 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(fp_int *a) +{ + fp_int b; + fp_digit d; + int r, res; + + /* do trial division */ + for (r = 0; r < 256; r++) { + fp_mod_d(a, primes[r], &d); + if (d == 0) { + return FP_NO; + } + } + + /* now do 8 miller rabins */ + fp_init(&b); + for (r = 0; r < 8; r++) { + fp_set(&b, primes[r]); + fp_prime_miller_rabin(a, &b, &res); + if (res == FP_NO) { + return FP_NO; + } + } + return FP_YES; +} + + +/* 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); + } +} + + +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; +} + + +/* 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); +} + +#endif /* CYASSL_KEY_GEN */ + + +#ifdef HAVE_ECC + +/* chars used in radix conversions */ +const char *fp_s_rmap = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+/"; + +/* 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); +} + + +int fp_read_radix(fp_int *a, const char *str, int radix) +{ + int y, neg; + char ch; + + /* 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; + } + + /* set the integer to the default of zero */ + fp_zero (a); + + /* 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) ? XTOUPPER(*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; +} + +/* fast math conversion */ +int mp_read_radix(mp_int *a, const char *str, int radix) +{ + return fp_read_radix(a, str, radix); +} + +/* fast math conversion */ +int mp_iszero(mp_int* a) +{ + return fp_iszero(a); +} + +/* fast math conversion */ +int mp_set(fp_int *a, fp_digit b) +{ + fp_set(a,b); + return MP_OKAY; +} + +/* fast math conversion */ +int mp_sqr(fp_int *A, fp_int *B) +{ + fp_sqr(A, B); + return MP_OKAY; +} + +/* fast math conversion */ +int mp_montgomery_reduce(fp_int *a, fp_int *m, fp_digit mp) +{ + fp_montgomery_reduce(a, m, mp); + return MP_OKAY; +} + + +/* fast math conversion */ +int mp_montgomery_setup(fp_int *a, fp_digit *rho) +{ + return fp_montgomery_setup(a, rho); +} + +/* fast math conversion */ +int mp_isodd(mp_int* a) +{ + return fp_isodd(a); +} + + +int mp_div_2(fp_int * a, fp_int * b) +{ + fp_div_2(a, b); + return MP_OKAY; +} + +#endif /* HAVE_ECC */ + +#endif /* USE_FAST_MATH */ diff --git a/ctaocrypt/test/Makefile.am b/ctaocrypt/test/Makefile.am new file mode 100644 index 000000000..429df045e --- /dev/null +++ b/ctaocrypt/test/Makefile.am @@ -0,0 +1,7 @@ +INCLUDES = -I../include -I../../include -I../../include/openssl +bin_PROGRAMS = test +test_SOURCES = test.c +test_LDFLAGS = -L../src +test_LDADD = ../../src/libcyassl.la +test_DEPENDENCIES = ../../src/libcyassl.la +EXTRA_DIST = test.sln test.vcproj diff --git a/ctaocrypt/test/test.c b/ctaocrypt/test/test.c new file mode 100644 index 000000000..50fecd38c --- /dev/null +++ b/ctaocrypt/test/test.c @@ -0,0 +1,1783 @@ +/* test.c */ + + +#include +#include +#include + +#include "ctc_md5.h" +#include "ctc_md4.h" +#include "ctc_sha.h" +#include "sha256.h" +#include "sha512.h" +#include "arc4.h" +#include "random.h" +#include "coding.h" +#include "asn.h" +#include "des3.h" +#include "ctc_aes.h" +#include "ctc_hmac.h" +#include "ctc_dh.h" +#include "ctc_dsa.h" +#include "hc128.h" +#include "rabbit.h" +#include "pwdbased.h" +#include "ctc_ripemd.h" +#ifdef HAVE_ECC + #include "ctc_ecc.h" +#endif + +#ifdef _MSC_VER + /* 4996 warning to use MS extensions e.g., strcpy_s instead of strncpy */ + #pragma warning(disable: 4996) +#endif + +#ifdef OPENSSL_EXTRA + #include "evp.h" + #include "rand.h" + #include "hmac.h" + #include "des.h" +#endif + +#ifdef HAVE_NTRU + #include "crypto_ntru.h" +#endif + + +#ifdef THREADX + /* since just testing, use THREADX log printf instead */ + int dc_log_printf(char*, ...); + #undef printf + #define printf dc_log_printf +#endif + + +typedef struct testVector { + char* input; + char* output; + size_t inLen; + size_t outLen; +} testVector; + +int md5_test(); +int md4_test(); +int sha_test(); +int sha256_test(); +int sha512_test(); +int hmac_test(); +int arc4_test(); +int hc128_test(); +int rabbit_test(); +int des_test(); +int des3_test(); +int aes_test(); +int rsa_test(); +int dh_test(); +int dsa_test(); +int random_test(); +int pwdbased_test(); +int ripemd_test(); +int openssl_test(); /* test mini api */ +#ifdef HAVE_ECC + int ecc_test(); +#endif + +int PemToDer(const char* inName, const char* outName); + + +void err_sys(const char* msg, int es) +{ + printf("%s error = %d\n", msg, es); +#ifndef THREADX + exit(es); +#endif +} + +/* func_args from cyassl_test.h, so don't have to pull in other junk */ +typedef struct func_args { + int argc; + char** argv; + int return_code; +} func_args; + + +void ctaocrypt_test(void* args) +{ + int ret = 0; + + ((func_args*)args)->return_code = -1; /* error state */ + + if ( (ret = md5_test()) ) + err_sys("MD5 test failed!\n", ret); + else + printf( "MD5 test passed!\n"); + +#ifndef NO_MD4 + if ( (ret = md4_test()) ) + err_sys("MD4 test failed!\n", ret); + else + printf( "MD4 test passed!\n"); +#endif + + if ( (ret = sha_test()) ) + err_sys("SHA test failed!\n", ret); + else + printf( "SHA test passed!\n"); + +#ifndef NO_SHA256 + if ( (ret = sha256_test()) ) + err_sys("SHA-256 test failed!\n", ret); + else + printf( "SHA-256 test passed!\n"); +#endif + +#ifdef CYASSL_SHA512 + if ( (ret = sha512_test()) ) + err_sys("SHA-512 test failed!\n", ret); + else + printf( "SHA-512 test passed!\n"); +#endif + +#ifdef CYASSL_RIPEMD + if ( (ret = ripemd_test()) ) + err_sys("RIPEMD test failed!\n", ret); + else + printf( "RIPEMD test passed!\n"); +#endif + +#ifndef NO_HMAC + if ( (ret = hmac_test()) ) + err_sys("HMAC test failed!\n", ret); + else + printf( "HMAC test passed!\n"); +#endif + + if ( (ret = arc4_test()) ) + err_sys("ARC4 test failed!\n", ret); + else + printf( "ARC4 test passed!\n"); + +#ifndef NO_HC128 + if ( (ret = hc128_test()) ) + err_sys("HC-128 test failed!\n", ret); + else + printf( "HC-128 test passed!\n"); +#endif + +#ifndef NO_RABBIT + if ( (ret = rabbit_test()) ) + err_sys("Rabbit test failed!\n", ret); + else + printf( "Rabbit test passed!\n"); +#endif + +#ifndef NO_DES3 + if ( (ret = des_test()) ) + err_sys("DES test failed!\n", ret); + else + printf( "DES test passed!\n"); +#endif + +#ifndef NO_DES3 + if ( (ret = des3_test()) ) + err_sys("DES3 test failed!\n", ret); + else + printf( "DES3 test passed!\n"); +#endif + +#ifndef NO_AES + if ( (ret = aes_test()) ) + err_sys("AES test failed!\n", ret); + else + printf( "AES test passed!\n"); +#endif + + if ( (ret = random_test()) ) + err_sys("RANDOM test failed!\n", ret); + else + printf( "RANDOM test passed!\n"); + + if ( (ret = rsa_test()) ) + err_sys("RSA test failed!\n", ret); + else + printf( "RSA test passed!\n"); + +#ifndef NO_DH + if ( (ret = dh_test()) ) + err_sys("DH test failed!\n", ret); + else + printf( "DH test passed!\n"); +#endif + +#ifndef NO_DSA + if ( (ret = dsa_test()) ) + err_sys("DSA test failed!\n", ret); + else + printf( "DSA test passed!\n"); +#endif + +#ifndef NO_PWDBASED + if ( (ret = pwdbased_test()) ) + err_sys("PWDBASED test failed!\n", ret); + else + printf( "PWDBASED test passed!\n"); +#endif + +#ifdef OPENSSL_EXTRA + if ( (ret = openssl_test()) ) + err_sys("OPENSSL test failed!\n", ret); + else + printf( "OPENSSL test passed!\n"); +#endif + +#ifdef HAVE_ECC + if ( (ret = ecc_test()) ) + err_sys("ECC test failed!\n", ret); + else + printf( "ECC test passed!\n"); +#endif + + ((func_args*)args)->return_code = ret; +} + + +/* so overall tests can pull in test function */ +#ifndef NO_MAIN_DRIVER + + int main(int argc, char** argv) + { + func_args args; + + args.argc = argc; + args.argv = argv; + + ctaocrypt_test(&args); + return args.return_code; + } + +#endif /* NO_MAIN_DRIVER */ + + +int md5_test() +{ + Md5 md5; + byte hash[MD5_DIGEST_SIZE]; + + testVector a, b, c, d, e; + testVector test_md5[5]; + int times = sizeof(test_md5) / sizeof(testVector), i; + + a.input = "abc"; + a.output = "\x90\x01\x50\x98\x3c\xd2\x4f\xb0\xd6\x96\x3f\x7d\x28\xe1\x7f" + "\x72"; + a.inLen = strlen(a.input); + a.outLen = strlen(a.output); + + b.input = "message digest"; + b.output = "\xf9\x6b\x69\x7d\x7c\xb7\x93\x8d\x52\x5a\x2f\x31\xaa\xf1\x61" + "\xd0"; + b.inLen = strlen(b.input); + b.outLen = strlen(b.output); + + c.input = "abcdefghijklmnopqrstuvwxyz"; + c.output = "\xc3\xfc\xd3\xd7\x61\x92\xe4\x00\x7d\xfb\x49\x6c\xca\x67\xe1" + "\x3b"; + c.inLen = strlen(c.input); + c.outLen = strlen(c.output); + + d.input = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz012345" + "6789"; + d.output = "\xd1\x74\xab\x98\xd2\x77\xd9\xf5\xa5\x61\x1c\x2c\x9f\x41\x9d" + "\x9f"; + d.inLen = strlen(d.input); + d.outLen = strlen(d.output); + + e.input = "1234567890123456789012345678901234567890123456789012345678" + "9012345678901234567890"; + e.output = "\x57\xed\xf4\xa2\x2b\xe3\xc9\x55\xac\x49\xda\x2e\x21\x07\xb6" + "\x7a"; + e.inLen = strlen(e.input); + e.outLen = strlen(e.output); + + test_md5[0] = a; + test_md5[1] = b; + test_md5[2] = c; + test_md5[3] = d; + test_md5[4] = e; + + InitMd5(&md5); + + for (i = 0; i < times; ++i) { + Md5Update(&md5, (byte*)test_md5[i].input, (word32)test_md5[i].inLen); + Md5Final(&md5, hash); + + if (memcmp(hash, test_md5[i].output, MD5_DIGEST_SIZE) != 0) + return -5 - i; + } + + return 0; +} + + +#ifndef NO_MD4 + +int md4_test() +{ + Md4 md4; + byte hash[MD4_DIGEST_SIZE]; + + testVector a, b, c, d, e, f, g; + testVector test_md4[7]; + int times = sizeof(test_md4) / sizeof(testVector), i; + + a.input = ""; + a.output = "\x31\xd6\xcf\xe0\xd1\x6a\xe9\x31\xb7\x3c\x59\xd7\xe0\xc0\x89" + "\xc0"; + a.inLen = strlen(a.input); + a.outLen = strlen(a.output); + + b.input = "a"; + b.output = "\xbd\xe5\x2c\xb3\x1d\xe3\x3e\x46\x24\x5e\x05\xfb\xdb\xd6\xfb" + "\x24"; + b.inLen = strlen(b.input); + b.outLen = strlen(b.output); + + c.input = "abc"; + c.output = "\xa4\x48\x01\x7a\xaf\x21\xd8\x52\x5f\xc1\x0a\xe8\x7a\xa6\x72" + "\x9d"; + c.inLen = strlen(c.input); + c.outLen = strlen(c.output); + + d.input = "message digest"; + d.output = "\xd9\x13\x0a\x81\x64\x54\x9f\xe8\x18\x87\x48\x06\xe1\xc7\x01" + "\x4b"; + d.inLen = strlen(d.input); + d.outLen = strlen(d.output); + + e.input = "abcdefghijklmnopqrstuvwxyz"; + e.output = "\xd7\x9e\x1c\x30\x8a\xa5\xbb\xcd\xee\xa8\xed\x63\xdf\x41\x2d" + "\xa9"; + e.inLen = strlen(e.input); + e.outLen = strlen(e.output); + + f.input = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz012345" + "6789"; + f.output = "\x04\x3f\x85\x82\xf2\x41\xdb\x35\x1c\xe6\x27\xe1\x53\xe7\xf0" + "\xe4"; + f.inLen = strlen(f.input); + f.outLen = strlen(f.output); + + g.input = "1234567890123456789012345678901234567890123456789012345678" + "9012345678901234567890"; + g.output = "\xe3\x3b\x4d\xdc\x9c\x38\xf2\x19\x9c\x3e\x7b\x16\x4f\xcc\x05" + "\x36"; + g.inLen = strlen(g.input); + g.outLen = strlen(g.output); + + test_md4[0] = a; + test_md4[1] = b; + test_md4[2] = c; + test_md4[3] = d; + test_md4[4] = e; + test_md4[5] = f; + test_md4[6] = g; + + InitMd4(&md4); + + for (i = 0; i < times; ++i) { + Md4Update(&md4, (byte*)test_md4[i].input, (word32)test_md4[i].inLen); + Md4Final(&md4, hash); + + if (memcmp(hash, test_md4[i].output, MD4_DIGEST_SIZE) != 0) + return -205 - i; + } + + return 0; +} + +#endif /* NO_MD4 */ + +int sha_test() +{ + Sha sha; + byte hash[SHA_DIGEST_SIZE]; + + testVector a, b, c, d; + testVector test_sha[4]; + int times = sizeof(test_sha) / sizeof(struct testVector), i; + + a.input = "abc"; + a.output = "\xA9\x99\x3E\x36\x47\x06\x81\x6A\xBA\x3E\x25\x71\x78\x50\xC2" + "\x6C\x9C\xD0\xD8\x9D"; + a.inLen = strlen(a.input); + a.outLen = strlen(a.output); + + b.input = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"; + b.output = "\x84\x98\x3E\x44\x1C\x3B\xD2\x6E\xBA\xAE\x4A\xA1\xF9\x51\x29" + "\xE5\xE5\x46\x70\xF1"; + b.inLen = strlen(b.input); + b.outLen = strlen(b.output); + + c.input = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaa"; + c.output = "\x00\x98\xBA\x82\x4B\x5C\x16\x42\x7B\xD7\xA1\x12\x2A\x5A\x44" + "\x2A\x25\xEC\x64\x4D"; + c.inLen = strlen(c.input); + c.outLen = strlen(c.output); + + d.input = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaa"; + d.output = "\xAD\x5B\x3F\xDB\xCB\x52\x67\x78\xC2\x83\x9D\x2F\x15\x1E\xA7" + "\x53\x99\x5E\x26\xA0"; + d.inLen = strlen(d.input); + d.outLen = strlen(d.output); + + test_sha[0] = a; + test_sha[1] = b; + test_sha[2] = c; + test_sha[3] = d; + + InitSha(&sha); + + for (i = 0; i < times; ++i) { + ShaUpdate(&sha, (byte*)test_sha[i].input, (word32)test_sha[i].inLen); + ShaFinal(&sha, hash); + + if (memcmp(hash, test_sha[i].output, SHA_DIGEST_SIZE) != 0) + return -10 - i; + } + + return 0; +} + + +#ifdef CYASSL_RIPEMD +int ripemd_test() +{ + RipeMd ripemd; + byte hash[RIPEMD_DIGEST_SIZE]; + + testVector a, b, c, d; + testVector test_ripemd[4]; + int times = sizeof(test_ripemd) / sizeof(struct testVector), i; + + a.input = "abc"; + a.output = "\x8e\xb2\x08\xf7\xe0\x5d\x98\x7a\x9b\x04\x4a\x8e\x98\xc6" + "\xb0\x87\xf1\x5a\x0b\xfc"; + a.inLen = strlen(a.input); + a.outLen = strlen(a.output); + + b.input = "message digest"; + b.output = "\x5d\x06\x89\xef\x49\xd2\xfa\xe5\x72\xb8\x81\xb1\x23\xa8" + "\x5f\xfa\x21\x59\x5f\x36"; + b.inLen = strlen(b.input); + b.outLen = strlen(b.output); + + c.input = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"; + c.output = "\x12\xa0\x53\x38\x4a\x9c\x0c\x88\xe4\x05\xa0\x6c\x27\xdc" + "\xf4\x9a\xda\x62\xeb\x2b"; + c.inLen = strlen(c.input); + c.outLen = strlen(c.output); + + d.input = "12345678901234567890123456789012345678901234567890123456" + "789012345678901234567890"; + d.output = "\x9b\x75\x2e\x45\x57\x3d\x4b\x39\xf4\xdb\xd3\x32\x3c\xab" + "\x82\xbf\x63\x32\x6b\xfb"; + d.inLen = strlen(d.input); + d.outLen = strlen(d.output); + + test_ripemd[0] = a; + test_ripemd[1] = b; + test_ripemd[2] = c; + test_ripemd[3] = d; + + InitRipeMd(&ripemd); + + for (i = 0; i < times; ++i) { + RipeMdUpdate(&ripemd, (byte*)test_ripemd[i].input, + (word32)test_ripemd[i].inLen); + RipeMdFinal(&ripemd, hash); + + if (memcmp(hash, test_ripemd[i].output, RIPEMD_DIGEST_SIZE) != 0) + return -10 - i; + } + + return 0; +} +#endif /* CYASSL_RIPEMD */ + + +#ifndef NO_SHA256 +int sha256_test() +{ + Sha256 sha; + byte hash[SHA256_DIGEST_SIZE]; + + testVector a, b; + testVector test_sha[2]; + int times = sizeof(test_sha) / sizeof(struct testVector), i; + + a.input = "abc"; + a.output = "\xBA\x78\x16\xBF\x8F\x01\xCF\xEA\x41\x41\x40\xDE\x5D\xAE\x22" + "\x23\xB0\x03\x61\xA3\x96\x17\x7A\x9C\xB4\x10\xFF\x61\xF2\x00" + "\x15\xAD"; + a.inLen = strlen(a.input); + a.outLen = strlen(a.output); + + b.input = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"; + b.output = "\x24\x8D\x6A\x61\xD2\x06\x38\xB8\xE5\xC0\x26\x93\x0C\x3E\x60" + "\x39\xA3\x3C\xE4\x59\x64\xFF\x21\x67\xF6\xEC\xED\xD4\x19\xDB" + "\x06\xC1"; + b.inLen = strlen(b.input); + b.outLen = strlen(b.output); + + test_sha[0] = a; + test_sha[1] = b; + + InitSha256(&sha); + + for (i = 0; i < times; ++i) { + Sha256Update(&sha, (byte*)test_sha[i].input,(word32)test_sha[i].inLen); + Sha256Final(&sha, hash); + + if (memcmp(hash, test_sha[i].output, SHA256_DIGEST_SIZE) != 0) + return -10 - i; + } + + return 0; +} +#endif + + +#ifdef CYASSL_SHA512 +int sha512_test() +{ + Sha512 sha; + byte hash[SHA512_DIGEST_SIZE]; + + testVector a, b; + testVector test_sha[2]; + int times = sizeof(test_sha) / sizeof(struct testVector), i; + + a.input = "abc"; + a.output = "\xdd\xaf\x35\xa1\x93\x61\x7a\xba\xcc\x41\x73\x49\xae\x20\x41" + "\x31\x12\xe6\xfa\x4e\x89\xa9\x7e\xa2\x0a\x9e\xee\xe6\x4b\x55" + "\xd3\x9a\x21\x92\x99\x2a\x27\x4f\xc1\xa8\x36\xba\x3c\x23\xa3" + "\xfe\xeb\xbd\x45\x4d\x44\x23\x64\x3c\xe8\x0e\x2a\x9a\xc9\x4f" + "\xa5\x4c\xa4\x9f"; + a.inLen = strlen(a.input); + a.outLen = strlen(a.output); + + b.input = "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhi" + "jklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"; + b.output = "\x8e\x95\x9b\x75\xda\xe3\x13\xda\x8c\xf4\xf7\x28\x14\xfc\x14" + "\x3f\x8f\x77\x79\xc6\xeb\x9f\x7f\xa1\x72\x99\xae\xad\xb6\x88" + "\x90\x18\x50\x1d\x28\x9e\x49\x00\xf7\xe4\x33\x1b\x99\xde\xc4" + "\xb5\x43\x3a\xc7\xd3\x29\xee\xb6\xdd\x26\x54\x5e\x96\xe5\x5b" + "\x87\x4b\xe9\x09"; + b.inLen = strlen(b.input); + b.outLen = strlen(b.output); + + test_sha[0] = a; + test_sha[1] = b; + + InitSha512(&sha); + + for (i = 0; i < times; ++i) { + Sha512Update(&sha, (byte*)test_sha[i].input,(word32)test_sha[i].inLen); + Sha512Final(&sha, hash); + + if (memcmp(hash, test_sha[i].output, SHA512_DIGEST_SIZE) != 0) + return -10 - i; + } + + return 0; +} +#endif + + +#ifndef NO_HMAC +int hmac_test() +{ + Hmac hmac; + byte hash[MD5_DIGEST_SIZE]; + + const char* keys[]= + { + "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b", + "Jefe", + "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA" + }; + + testVector a, b, c; + testVector test_hmac[3]; + + int times = sizeof(test_hmac) / sizeof(testVector), i; + + a.input = "Hi There"; + a.output = "\x92\x94\x72\x7a\x36\x38\xbb\x1c\x13\xf4\x8e\xf8\x15\x8b\xfc" + "\x9d"; + a.inLen = strlen(a.input); + a.outLen = strlen(a.output); + + b.input = "what do ya want for nothing?"; + b.output = "\x75\x0c\x78\x3e\x6a\xb0\xb5\x03\xea\xa8\x6e\x31\x0a\x5d\xb7" + "\x38"; + b.inLen = strlen(b.input); + b.outLen = strlen(b.output); + + c.input = "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" + "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" + "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" + "\xDD\xDD\xDD\xDD\xDD\xDD"; + c.output = "\x56\xbe\x34\x52\x1d\x14\x4c\x88\xdb\xb8\xc7\x33\xf0\xe8\xb3" + "\xf6"; + c.inLen = strlen(c.input); + c.outLen = strlen(c.output); + + test_hmac[0] = a; + test_hmac[1] = b; + test_hmac[2] = c; + + for (i = 0; i < times; ++i) { + HmacSetKey(&hmac, MD5, (byte*)keys[i], (word32)strlen(keys[i])); + HmacUpdate(&hmac, (byte*)test_hmac[i].input, + (word32)test_hmac[i].inLen); + HmacFinal(&hmac, hash); + + if (memcmp(hash, test_hmac[i].output, MD5_DIGEST_SIZE) != 0) + return -20 - i; + } + + return 0; +} +#endif + + +int arc4_test() +{ + byte cipher[16]; + byte plain[16]; + + const char* keys[] = + { + "\x01\x23\x45\x67\x89\xab\xcd\xef", + "\x01\x23\x45\x67\x89\xab\xcd\xef", + "\x00\x00\x00\x00\x00\x00\x00\x00", + "\xef\x01\x23\x45" + }; + + testVector a, b, c, d; + testVector test_arc4[4]; + + int times = sizeof(test_arc4) / sizeof(testVector), i; + + a.input = "\x01\x23\x45\x67\x89\xab\xcd\xef"; + a.output = "\x75\xb7\x87\x80\x99\xe0\xc5\x96"; + a.inLen = strlen(a.input); + a.outLen = strlen(a.output); + + b.input = "\x00\x00\x00\x00\x00\x00\x00\x00"; + b.output = "\x74\x94\xc2\xe7\x10\x4b\x08\x79"; + b.inLen = strlen(b.input); + b.outLen = strlen(b.output); + + c.input = "\x00\x00\x00\x00\x00\x00\x00\x00"; + c.output = "\xde\x18\x89\x41\xa3\x37\x5d\x3a"; + c.inLen = strlen(c.input); + c.outLen = strlen(c.output); + + d.input = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"; + d.output = "\xd6\xa1\x41\xa7\xec\x3c\x38\xdf\xbd\x61"; + d.inLen = strlen(d.input); + d.outLen = strlen(d.output); + + test_arc4[0] = a; + test_arc4[1] = b; + test_arc4[2] = c; + test_arc4[3] = d; + + for (i = 0; i < times; ++i) { + Arc4 enc; + Arc4 dec; + + Arc4SetKey(&enc, (byte*)keys[i], (word32)strlen(keys[i])); + Arc4SetKey(&dec, (byte*)keys[i], (word32)strlen(keys[i])); + + Arc4Process(&enc, cipher, (byte*)test_arc4[i].input, + (word32)test_arc4[i].outLen); + Arc4Process(&dec, plain, cipher, (word32)test_arc4[i].outLen); + + if (memcmp(plain, test_arc4[i].input, test_arc4[i].outLen)) + return -20 - i; + + if (memcmp(cipher, test_arc4[i].output, test_arc4[i].outLen)) + return -20 - 5 - i; + } + + return 0; +} + + +#ifndef NO_HC128 +int hc128_test() +{ + byte cipher[16]; + byte plain[16]; + + const char* keys[] = + { + "\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", + "\x00\x53\xA6\xF9\x4C\x9F\xF2\x45\x98\xEB\x3E\x91\xE4\x37\x8A\xDD", + "\x0F\x62\xB5\x08\x5B\xAE\x01\x54\xA7\xFA\x4D\xA0\xF3\x46\x99\xEC" + }; + + const char* ivs[] = + { + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", + "\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", + "\x0D\x74\xDB\x42\xA9\x10\x77\xDE\x45\xAC\x13\x7A\xE1\x48\xAF\x16", + "\x28\x8F\xF6\x5D\xC4\x2B\x92\xF9\x60\xC7\x2E\x95\xFC\x63\xCA\x31" + }; + + + testVector a, b, c, d; + testVector test_hc128[4]; + + int times = sizeof(test_hc128) / sizeof(testVector), i; + + a.input = "\x00\x00\x00\x00\x00\x00\x00\x00"; + a.output = "\x37\x86\x02\xB9\x8F\x32\xA7\x48"; + a.inLen = strlen(a.input); + a.outLen = strlen(a.output); + + b.input = "\x00\x00\x00\x00\x00\x00\x00\x00"; + b.output = "\x33\x7F\x86\x11\xC6\xED\x61\x5F"; + b.inLen = strlen(b.input); + b.outLen = strlen(b.output); + + c.input = "\x00\x00\x00\x00\x00\x00\x00\x00"; + c.output = "\x2E\x1E\xD1\x2A\x85\x51\xC0\x5A"; + c.inLen = strlen(c.input); + c.outLen = strlen(c.output); + + d.input = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"; + d.output = "\x1C\xD8\xAE\xDD\xFE\x52\xE2\x17\xE8\x35\xD0\xB7\xE8\x4E\x29"; + d.inLen = strlen(d.input); + d.outLen = strlen(d.output); + + test_hc128[0] = a; + test_hc128[1] = b; + test_hc128[2] = c; + test_hc128[3] = d; + + for (i = 0; i < times; ++i) { + HC128 enc; + HC128 dec; + + Hc128_SetKey(&enc, (byte*)keys[i], (byte*)ivs[i]); + Hc128_SetKey(&dec, (byte*)keys[i], (byte*)ivs[i]); + + Hc128_Process(&enc, cipher, (byte*)test_hc128[i].input, + (word32)test_hc128[i].outLen); + Hc128_Process(&dec, plain, cipher, (word32)test_hc128[i].outLen); + + if (memcmp(plain, test_hc128[i].input, test_hc128[i].outLen)) + return -120 - i; + + if (memcmp(cipher, test_hc128[i].output, test_hc128[i].outLen)) + return -120 - 5 - i; + } + + return 0; +} +#endif /* NO_HC128 */ + + +#ifndef NO_RABBIT +int rabbit_test() +{ + byte cipher[16]; + byte plain[16]; + + const char* keys[] = + { + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", + "\xAC\xC3\x51\xDC\xF1\x62\xFC\x3B\xFE\x36\x3D\x2E\x29\x13\x28\x91" + }; + + const char* ivs[] = + { + "\x00\x00\x00\x00\x00\x00\x00\x00", + "\x59\x7E\x26\xC1\x75\xF5\x73\xC3", + 0 + }; + + + testVector a, b, c; + testVector test_rabbit[3]; + + int times = sizeof(test_rabbit) / sizeof(testVector), i; + + a.input = "\x00\x00\x00\x00\x00\x00\x00\x00"; + a.output = "\xED\xB7\x05\x67\x37\x5D\xCD\x7C"; + a.inLen = strlen(a.input); + a.outLen = strlen(a.output); + + b.input = "\x00\x00\x00\x00\x00\x00\x00\x00"; + b.output = "\x6D\x7D\x01\x22\x92\xCC\xDC\xE0"; + b.inLen = strlen(b.input); + b.outLen = strlen(b.output); + + c.input = "\x00\x00\x00\x00\x00\x00\x00\x00"; + c.output = "\x9C\x51\xE2\x87\x84\xC3\x7F\xE9"; + c.inLen = strlen(c.input); + c.outLen = strlen(c.output); + + test_rabbit[0] = a; + test_rabbit[1] = b; + test_rabbit[2] = c; + + for (i = 0; i < times; ++i) { + Rabbit enc; + Rabbit dec; + + RabbitSetKey(&enc, (byte*)keys[i], (byte*)ivs[i]); + RabbitSetKey(&dec, (byte*)keys[i], (byte*)ivs[i]); + + RabbitProcess(&enc, cipher, (byte*)test_rabbit[i].input, + (word32)test_rabbit[i].outLen); + RabbitProcess(&dec, plain, cipher, (word32)test_rabbit[i].outLen); + + if (memcmp(plain, test_rabbit[i].input, test_rabbit[i].outLen)) + return -130 - i; + + if (memcmp(cipher, test_rabbit[i].output, test_rabbit[i].outLen)) + return -130 - 5 - i; + } + + return 0; +} +#endif /* NO_RABBIT */ + + +#ifndef NO_DES3 +int des_test() +{ + const byte vector[] = { /* "now is the time for all " w/o trailing 0 */ + 0x6e,0x6f,0x77,0x20,0x69,0x73,0x20,0x74, + 0x68,0x65,0x20,0x74,0x69,0x6d,0x65,0x20, + 0x66,0x6f,0x72,0x20,0x61,0x6c,0x6c,0x20 + }; + + byte plain[24]; + byte cipher[24]; + + Des enc; + Des dec; + + const byte key[] = + { + 0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef + }; + + const byte iv[] = + { + 0x12,0x34,0x56,0x78,0x90,0xab,0xcd,0xef + }; + + const byte verify[] = + { + 0x8b,0x7c,0x52,0xb0,0x01,0x2b,0x6c,0xb8, + 0x4f,0x0f,0xeb,0xf3,0xfb,0x5f,0x86,0x73, + 0x15,0x85,0xb3,0x22,0x4b,0x86,0x2b,0x4b + }; + + + Des_SetKey(&enc, key, iv, DES_ENCRYPTION); + Des_CbcEncrypt(&enc, cipher, vector, sizeof(vector)); + Des_SetKey(&dec, key, iv, DES_DECRYPTION); + Des_CbcDecrypt(&dec, plain, cipher, sizeof(cipher)); + + if (memcmp(plain, vector, sizeof(plain))) + return -31; + + if (memcmp(cipher, verify, sizeof(cipher))) + return -32; + + return 0; +} +#endif /* NO_DES3 */ + + +#ifndef NO_DES3 +int des3_test() +{ + const byte vector[] = { /* "Now is the time for all " w/o trailing 0 */ + 0x4e,0x6f,0x77,0x20,0x69,0x73,0x20,0x74, + 0x68,0x65,0x20,0x74,0x69,0x6d,0x65,0x20, + 0x66,0x6f,0x72,0x20,0x61,0x6c,0x6c,0x20 + }; + + byte plain[24]; + byte cipher[24]; + + Des3 enc; + Des3 dec; + + const byte key3[] = + { + 0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef, + 0xfe,0xde,0xba,0x98,0x76,0x54,0x32,0x10, + 0x89,0xab,0xcd,0xef,0x01,0x23,0x45,0x67 + }; + const byte iv3[] = + { + 0x12,0x34,0x56,0x78,0x90,0xab,0xcd,0xef, + 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, + 0x11,0x21,0x31,0x41,0x51,0x61,0x71,0x81 + + }; + + const byte verify3[] = + { + 0x43,0xa0,0x29,0x7e,0xd1,0x84,0xf8,0x0e, + 0x89,0x64,0x84,0x32,0x12,0xd5,0x08,0x98, + 0x18,0x94,0x15,0x74,0x87,0x12,0x7d,0xb0 + }; + + + Des3_SetKey(&enc, key3, iv3, DES_ENCRYPTION); + Des3_CbcEncrypt(&enc, cipher, vector, sizeof(vector)); + Des3_SetKey(&dec, key3, iv3, DES_DECRYPTION); + Des3_CbcDecrypt(&dec, plain, cipher, sizeof(cipher)); + + if (memcmp(plain, vector, sizeof(plain))) + return -33; + + if (memcmp(cipher, verify3, sizeof(cipher))) + return -34; + + return 0; +} +#endif /* NO_DES */ + + +#ifndef NO_AES +int aes_test() +{ + Aes enc; + Aes dec; + + const byte msg[] = { /* "Now is the time for all " w/o trailing 0 */ + 0x6e,0x6f,0x77,0x20,0x69,0x73,0x20,0x74, + 0x68,0x65,0x20,0x74,0x69,0x6d,0x65,0x20, + 0x66,0x6f,0x72,0x20,0x61,0x6c,0x6c,0x20 + }; + + const byte verify[] = + { + 0x95,0x94,0x92,0x57,0x5f,0x42,0x81,0x53, + 0x2c,0xcc,0x9d,0x46,0x77,0xa2,0x33,0xcb + }; + + byte key[] = "0123456789abcdef "; /* align */ + byte iv[] = "1234567890abcdef "; /* align */ + + byte cipher[AES_BLOCK_SIZE]; + byte plain [AES_BLOCK_SIZE]; + + AesSetKey(&enc, key, AES_BLOCK_SIZE, iv, AES_ENCRYPTION); + AesSetKey(&dec, key, AES_BLOCK_SIZE, iv, AES_DECRYPTION); + + AesCbcEncrypt(&enc, cipher, msg, AES_BLOCK_SIZE); + AesCbcDecrypt(&dec, plain, cipher, AES_BLOCK_SIZE); + + if (memcmp(plain, msg, AES_BLOCK_SIZE)) + return -60; + + if (memcmp(cipher, verify, AES_BLOCK_SIZE)) + return -61; + + return 0; +} +#endif /* NO_AES */ + + +int random_test() +{ + RNG rng; + byte block[32]; + int ret = InitRng(&rng); + if (ret != 0) return -39; + + RNG_GenerateBlock(&rng, block, sizeof(block)); + + return 0; +} + + +#ifndef NO_MAIN_DRIVER + static const char* clientKey = "../../certs/client-key.der"; + static const char* clientCert = "../../certs/client-cert.der"; + #ifdef CYASSL_CERT_GEN + static const char* caKeyFile = "../../certs/ca-key.der"; + static const char* caCertFile = "../../certs/ca-cert.pem"; + #endif +#else + static const char* clientKey = "../certs/client-key.der"; + static const char* clientCert = "../certs/client-cert.der"; + #ifdef CYASSL_CERT_GEN + static const char* caKeyFile = "../certs/ca-key.der"; + static const char* caCertFile = "../certs/ca-cert.pem"; + #endif +#endif + + +#ifdef HAVE_NTRU + +static byte GetEntropy(ENTROPY_CMD cmd, byte* out) +{ + static RNG rng; + + if (cmd == INIT) { + int ret = InitRng(&rng); + if (ret == 0) + return 1; + else + return 0; + } + + if (out == NULL) + return 0; + + if (cmd == GET_BYTE_OF_ENTROPY) { + RNG_GenerateBlock(&rng, out, 1); + return 1; + } + + if (cmd == GET_NUM_BYTES_PER_BYTE_OF_ENTROPY) { + *out = 1; + return 1; + } + + return 0; +} + +#endif /* HAVE_NTRU */ + +int rsa_test() +{ + byte tmp[2048], tmp2[2048]; + size_t bytes, bytes2; + RsaKey key; + RNG rng; + word32 idx = 0; + int ret; + byte in[] = "Everyone gets Friday off."; + word32 inLen = (word32)strlen((char*)in); + byte out[256]; + byte plain[256]; + DecodedCert cert; + + FILE* file = fopen(clientKey, "rb"), * file2; + + if (!file) + return -40; + + bytes = fread(tmp, 1, sizeof(tmp), file); + + InitRsaKey(&key, 0); + ret = RsaPrivateKeyDecode(tmp, &idx, &key, (word32)bytes); + if (ret != 0) return -41; + + ret = InitRng(&rng); + if (ret != 0) return -42; + + ret = RsaPublicEncrypt(in, inLen, out, sizeof(out), &key, &rng); + + ret = RsaPrivateDecrypt(out, ret, plain, sizeof(plain), &key); + + if (memcmp(plain, in, inLen)) return -45; + + ret = RsaSSL_Sign(in, inLen, out, sizeof(out), &key, &rng); + memset(plain, 0, sizeof(plain)); + ret = RsaSSL_Verify(out, ret, plain, sizeof(plain), &key); + + if (memcmp(plain, in, ret)) return -46; + + file2 = fopen(clientCert, "rb"); + if (!file2) + return -47; + + bytes2 = fread(tmp2, 1, sizeof(tmp2), file2); + + InitDecodedCert(&cert, (byte*)&tmp2, 0); + + ret = ParseCert(&cert, (word32)bytes2, CERT_TYPE, NO_VERIFY, 0); + if (ret != 0) return -48; + + FreeDecodedCert(&cert); + + fclose(file2); + fclose(file); + +#ifdef CYASSL_KEY_GEN + { + byte der[4096]; + byte pem[4096]; + word32 derSz = 0; + word32 pemSz = 0; + RsaKey derIn; + RsaKey genKey; + FILE* keyFile; + FILE* pemFile; + + InitRsaKey(&genKey, 0); + ret = MakeRsaKey(&genKey, 1024, 65537, &rng); + if (ret != 0) + return -301; + + derSz = RsaKeyToDer(&genKey, der, sizeof(der)); + if (derSz < 0) + return -302; + + keyFile = fopen("./ker.der", "wb"); + if (!keyFile) + return -303; + ret = fwrite(der, derSz, 1, keyFile); + fclose(keyFile); + + pemSz = DerToPem(der, derSz, pem, sizeof(pem), PRIVATEKEY_TYPE); + if (pemSz < 0) + return -304; + + pemFile = fopen("./key.pem", "wb"); + if (!pemFile) + return -305; + ret = fwrite(pem, pemSz, 1, pemFile); + fclose(pemFile); + + InitRsaKey(&derIn, 0); + idx = 0; + ret = RsaPrivateKeyDecode(der, &idx, &derIn, derSz); + if (ret != 0) + return -306; + + FreeRsaKey(&derIn); + FreeRsaKey(&genKey); + } +#endif /* CYASSL_KEY_GEN */ + + +#ifdef CYASSL_CERT_GEN + /* self signed */ + { + Cert myCert; + byte derCert[4096]; + byte pem[4096]; + DecodedCert decode; + FILE* derFile; + FILE* pemFile; + int certSz; + int pemSz; + + InitCert(&myCert); + + strncpy(myCert.subject.country, "US", NAME_SIZE); + strncpy(myCert.subject.state, "OR", NAME_SIZE); + strncpy(myCert.subject.locality, "Portland", NAME_SIZE); + strncpy(myCert.subject.org, "yaSSL", NAME_SIZE); + strncpy(myCert.subject.unit, "Development", NAME_SIZE); + strncpy(myCert.subject.commonName, "www.yassl.com", NAME_SIZE); + strncpy(myCert.subject.email, "info@yassl.com", NAME_SIZE); + + certSz = MakeSelfCert(&myCert, derCert, sizeof(derCert), &key, &rng); + if (certSz < 0) + return -401; + + InitDecodedCert(&decode, derCert, 0); + ret = ParseCert(&decode, certSz, CERT_TYPE, NO_VERIFY, 0); + if (ret != 0) + return -402; + + derFile = fopen("./cert.der", "wb"); + if (!derFile) + return -403; + ret = fwrite(derCert, certSz, 1, derFile); + fclose(derFile); + + pemSz = DerToPem(derCert, certSz, pem, sizeof(pem), CERT_TYPE); + if (pemSz < 0) + return -404; + + pemFile = fopen("./cert.pem", "wb"); + if (!pemFile) + return -405; + ret = fwrite(pem, pemSz, 1, pemFile); + fclose(pemFile); + + FreeDecodedCert(&decode); + + } + /* CA style */ + { + RsaKey caKey; + Cert myCert; + byte derCert[4096]; + byte pem[4096]; + DecodedCert decode; + FILE* derFile; + FILE* pemFile; + int certSz; + int pemSz; + byte tmp[2048]; + size_t bytes; + word32 idx = 0; + + FILE* file = fopen(caKeyFile, "rb"); + + if (!file) + return -412; + + bytes = fread(tmp, 1, sizeof(tmp), file); + + InitRsaKey(&caKey, 0); + ret = RsaPrivateKeyDecode(tmp, &idx, &caKey, (word32)bytes); + if (ret != 0) return -413; + + InitCert(&myCert); + + strncpy(myCert.subject.country, "US", NAME_SIZE); + strncpy(myCert.subject.state, "OR", NAME_SIZE); + strncpy(myCert.subject.locality, "Portland", NAME_SIZE); + strncpy(myCert.subject.org, "yaSSL", NAME_SIZE); + strncpy(myCert.subject.unit, "Development", NAME_SIZE); + strncpy(myCert.subject.commonName, "www.yassl.com", NAME_SIZE); + strncpy(myCert.subject.email, "info@yassl.com", NAME_SIZE); + + ret = SetIssuer(&myCert, caCertFile); + if (ret < 0) + return -406; + + certSz = MakeCert(&myCert, derCert, sizeof(derCert), &key, &rng); + if (certSz < 0) + return -407; + + certSz = SignCert(&myCert, derCert, sizeof(derCert), &caKey, &rng); + if (certSz < 0) + return -408; + + + InitDecodedCert(&decode, derCert, 0); + ret = ParseCert(&decode, certSz, CERT_TYPE, NO_VERIFY, 0); + if (ret != 0) + return -409; + + derFile = fopen("./othercert.der", "wb"); + if (!derFile) + return -410; + ret = fwrite(derCert, certSz, 1, derFile); + fclose(derFile); + + pemSz = DerToPem(derCert, certSz, pem, sizeof(pem), CERT_TYPE); + if (pemSz < 0) + return -411; + + pemFile = fopen("./othercert.pem", "wb"); + if (!pemFile) + return -412; + ret = fwrite(pem, pemSz, 1, pemFile); + fclose(pemFile); + + FreeDecodedCert(&decode); + + } +#ifdef HAVE_NTRU + { + RsaKey caKey; + Cert myCert; + byte derCert[4096]; + byte pem[4096]; + DecodedCert decode; + FILE* derFile; + FILE* pemFile; + FILE* caFile; + FILE* ntruPrivFile; + int certSz; + int pemSz; + byte tmp[2048]; + size_t bytes; + word32 idx = 0; + + byte public_key[557]; /* sized for EES401EP2 */ + word16 public_key_len; /* no. of octets in public key */ + byte private_key[607]; /* sized for EES401EP2 */ + word16 private_key_len; /* no. of octets in private key */ + DRBG_HANDLE drbg; + static uint8_t const pers_str[] = { + 'C', 'y', 'a', 'S', 'S', 'L', ' ', 't', 'e', 's', 't' + }; + word32 rc = crypto_drbg_instantiate(112, pers_str, sizeof(pers_str), + GetEntropy, &drbg); + if (rc != DRBG_OK) + return -450; + + rc = crypto_ntru_encrypt_keygen(drbg, NTRU_EES401EP2, &public_key_len, + NULL, &private_key_len, NULL); + if (rc != NTRU_OK) + return -451; + + rc = crypto_ntru_encrypt_keygen(drbg, NTRU_EES401EP2, &public_key_len, + public_key, &private_key_len, private_key); + crypto_drbg_uninstantiate(drbg); + + if (rc != NTRU_OK) + return -452; + + caFile = fopen(caKeyFile, "rb"); + + if (!caFile) + return -453; + + bytes = fread(tmp, 1, sizeof(tmp), caFile); + fclose(caFile); + + InitRsaKey(&caKey, 0); + ret = RsaPrivateKeyDecode(tmp, &idx, &caKey, (word32)bytes); + if (ret != 0) return -454; + + InitCert(&myCert); + + strncpy(myCert.subject.country, "US", NAME_SIZE); + strncpy(myCert.subject.state, "OR", NAME_SIZE); + strncpy(myCert.subject.locality, "Portland", NAME_SIZE); + strncpy(myCert.subject.org, "yaSSL", NAME_SIZE); + strncpy(myCert.subject.unit, "Development", NAME_SIZE); + strncpy(myCert.subject.commonName, "www.yassl.com", NAME_SIZE); + strncpy(myCert.subject.email, "info@yassl.com", NAME_SIZE); + + ret = SetIssuer(&myCert, caCertFile); + if (ret < 0) + return -455; + + certSz = MakeNtruCert(&myCert, derCert, sizeof(derCert), public_key, + public_key_len, &rng); + if (certSz < 0) + return -456; + + certSz = SignCert(&myCert, derCert, sizeof(derCert), &caKey, &rng); + if (certSz < 0) + return -457; + + + InitDecodedCert(&decode, derCert, 0); + ret = ParseCert(&decode, certSz, CERT_TYPE, NO_VERIFY, 0); + if (ret != 0) + return -458; + + derFile = fopen("./ntru-cert.der", "wb"); + if (!derFile) + return -459; + ret = fwrite(derCert, certSz, 1, derFile); + fclose(derFile); + + pemSz = DerToPem(derCert, certSz, pem, sizeof(pem), CERT_TYPE); + if (pemSz < 0) + return -460; + + pemFile = fopen("./ntru-cert.pem", "wb"); + if (!pemFile) + return -461; + ret = fwrite(pem, pemSz, 1, pemFile); + fclose(pemFile); + + ntruPrivFile = fopen("./ntru-key.raw", "wb"); + if (!ntruPrivFile) + return -462; + ret = fwrite(private_key, private_key_len, 1, ntruPrivFile); + fclose(ntruPrivFile); + + + + FreeDecodedCert(&decode); + } +#endif /* HAVE_NTRU */ +#endif /* CYASSL_CERT_GEN */ + + FreeRsaKey(&key); + + return 0; +} + + +#ifndef NO_MAIN_DRIVER + static const char* dhKey = "../../certs/dh1024.der"; +#else + static const char* dhKey = "../certs/dh1024.der"; +#endif + +#ifndef NO_DH + +int dh_test() +{ + int ret; + word32 bytes; + word32 idx = 0, privSz, pubSz, privSz2, pubSz2, agreeSz, agreeSz2; + byte tmp[1024]; + byte priv[128]; + byte pub[128]; + byte priv2[128]; + byte pub2[128]; + byte agree[128]; + byte agree2[128]; + DhKey key; + DhKey key2; + RNG rng; + FILE* file = fopen(dhKey, "rb"); + + if (!file) + return -50; + + bytes = (word32) fread(tmp, 1, sizeof(tmp), file); + + InitDhKey(&key); + InitDhKey(&key2); + ret = DhKeyDecode(tmp, &idx, &key, bytes); + if (ret != 0) + return -51; + + idx = 0; + ret = DhKeyDecode(tmp, &idx, &key2, bytes); + if (ret != 0) + return -52; + + ret = InitRng(&rng); + if (ret != 0) + return -53; + + ret = DhGenerateKeyPair(&key, &rng, priv, &privSz, pub, &pubSz); + ret = DhGenerateKeyPair(&key2, &rng, priv2, &privSz2, pub2, &pubSz2); + if (ret != 0) + return -54; + + ret = DhAgree(&key, agree, &agreeSz, priv, privSz, pub2, pubSz2); + ret = DhAgree(&key2, agree2, &agreeSz2, priv2, privSz2, pub, pubSz); + if (ret != 0) + return -55; + + if (memcmp(agree, agree2, agreeSz)) + return -56; + + FreeDhKey(&key); + FreeDhKey(&key2); + fclose(file); + + return 0; +} + +#endif /* NO_DH */ + + +#ifndef NO_MAIN_DRIVER + static const char* dsaKey = "../../certs/dsa512.der"; +#else + static const char* dsaKey = "../certs/dsa512.der"; +#endif + +#ifndef NO_DSA + +int dsa_test() +{ + int ret, answer; + word32 bytes; + word32 idx = 0; + byte tmp[1024]; + DsaKey key; + RNG rng; + FILE* file = fopen(dsaKey, "rb"); + Sha sha; + byte hash[SHA_DIGEST_SIZE]; + byte signature[40]; + + if (!file) + return -60; + + bytes = (word32) fread(tmp, 1, sizeof(tmp), file); + + InitSha(&sha); + ShaUpdate(&sha, tmp, bytes); + ShaFinal(&sha, hash); + + InitDsaKey(&key); + ret = DsaPrivateKeyDecode(tmp, &idx, &key, bytes); + if (ret != 0) return -61; + + ret = InitRng(&rng); + if (ret != 0) return -62; + + ret = DsaSign(hash, signature, &key, &rng); + if (ret != 0) return -63; + + ret = DsaVerify(hash, signature, &key, &answer); + if (ret != 0) return -64; + if (answer != 1) return -65; + + FreeDsaKey(&key); + fclose(file); + + return 0; +} + +#endif /* NO_DSA */ + + +#ifdef OPENSSL_EXTRA + +int openssl_test() +{ + EVP_MD_CTX md_ctx; + testVector a, b, c; + byte hash[SHA_DIGEST_SIZE]; + + a.input = "1234567890123456789012345678901234567890123456789012345678" + "9012345678901234567890"; + a.output = "\x57\xed\xf4\xa2\x2b\xe3\xc9\x55\xac\x49\xda\x2e\x21\x07\xb6" + "\x7a"; + a.inLen = strlen(a.input); + a.outLen = strlen(a.output); + + EVP_MD_CTX_init(&md_ctx); + EVP_DigestInit(&md_ctx, EVP_md5()); + + EVP_DigestUpdate(&md_ctx, a.input, a.inLen); + EVP_DigestFinal(&md_ctx, hash, 0); + + if (memcmp(hash, a.output, MD5_DIGEST_SIZE) != 0) + return -71; + + b.input = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaa"; + b.output = "\xAD\x5B\x3F\xDB\xCB\x52\x67\x78\xC2\x83\x9D\x2F\x15\x1E\xA7" + "\x53\x99\x5E\x26\xA0"; + b.inLen = strlen(b.input); + b.outLen = strlen(b.output); + + EVP_MD_CTX_init(&md_ctx); + EVP_DigestInit(&md_ctx, EVP_sha1()); + + EVP_DigestUpdate(&md_ctx, b.input, b.inLen); + EVP_DigestFinal(&md_ctx, hash, 0); + + if (memcmp(hash, b.output, SHA_DIGEST_SIZE) != 0) + return -72; + + if (RAND_bytes(hash, sizeof(hash)) != 1) + return -73; + + c.input = "what do ya want for nothing?"; + c.output = "\x75\x0c\x78\x3e\x6a\xb0\xb5\x03\xea\xa8\x6e\x31\x0a\x5d\xb7" + "\x38"; + c.inLen = strlen(c.input); + c.outLen = strlen(c.output); + + HMAC(EVP_md5(), "Jefe", 4, (byte*)c.input, (int)c.inLen, hash, 0); + + if (memcmp(hash, c.output, MD5_DIGEST_SIZE) != 0) + return -74; + + { /* des test */ + const byte vector[] = { /* "now is the time for all " w/o trailing 0 */ + 0x6e,0x6f,0x77,0x20,0x69,0x73,0x20,0x74, + 0x68,0x65,0x20,0x74,0x69,0x6d,0x65,0x20, + 0x66,0x6f,0x72,0x20,0x61,0x6c,0x6c,0x20 + }; + + byte plain[24]; + byte cipher[24]; + + const_DES_cblock key = + { + 0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef + }; + + DES_cblock iv = + { + 0x12,0x34,0x56,0x78,0x90,0xab,0xcd,0xef + }; + + DES_key_schedule sched; + + const byte verify[] = + { + 0x8b,0x7c,0x52,0xb0,0x01,0x2b,0x6c,0xb8, + 0x4f,0x0f,0xeb,0xf3,0xfb,0x5f,0x86,0x73, + 0x15,0x85,0xb3,0x22,0x4b,0x86,0x2b,0x4b + }; + + DES_key_sched(&key, &sched); + + DES_cbc_encrypt(vector, cipher, sizeof(vector), &sched, &iv, DES_ENCRYPT); + DES_cbc_encrypt(cipher, plain, sizeof(vector), &sched, &iv, DES_DECRYPT); + + if (memcmp(plain, vector, sizeof(vector)) != 0) + return -75; + + if (memcmp(cipher, verify, sizeof(verify)) != 0) + return -76; + + /* test changing iv */ + DES_ncbc_encrypt(vector, cipher, 8, &sched, &iv, DES_ENCRYPT); + DES_ncbc_encrypt(vector + 8, cipher + 8, 16, &sched, &iv, DES_ENCRYPT); + + if (memcmp(cipher, verify, sizeof(verify)) != 0) + return -77; + + } /* end des test */ + + return 0; +} + +#endif /* OPENSSL_EXTRA */ + + +#ifndef NO_PWDBASED + +int pbkdf2_test() +{ + char passwd[] = "password"; + const byte salt[] = { 0x78, 0x57, 0x8E, 0x5a, 0x5d, 0x63, 0xcb, 0x06 }; + int iterations = 2048; + int kLen = 24; + + const byte verify[] = { + 0xBF, 0xDE, 0x6B, 0xE9, 0x4D, 0xF7, 0xE1, 0x1D, 0xD4, 0x09, 0xBC, 0xE2, + 0x0A, 0x02, 0x55, 0xEC, 0x32, 0x7C, 0xB9, 0x36, 0xFF, 0xE9, 0x36, 0x43 + + }; + + return 0; +} + + +int pbkdf1_test() +{ + char passwd[] = "password"; + const byte salt[] = { 0x78, 0x57, 0x8E, 0x5a, 0x5d, 0x63, 0xcb, 0x06 }; + int iterations = 1000; + int kLen = 16; + byte derived[16]; + + const byte verify[] = { + 0xDC, 0x19, 0x84, 0x7E, 0x05, 0xC6, 0x4D, 0x2F, 0xAF, 0x10, 0xEB, 0xFB, + 0x4A, 0x3D, 0x2A, 0x20 + }; + + PBKDF1(derived, (byte*)passwd, strlen(passwd), salt, 8, iterations, kLen, + SHA); + + if (memcmp(derived, verify, sizeof(verify)) != 0) + return -101; + + return 0; +} + + +int pwdbased_test() +{ + return pbkdf1_test(); +} + +#endif /* NO_PWDBASED */ + + +#ifdef HAVE_ECC + +int ecc_test() +{ + RNG rng; + byte sharedA[1024]; + byte sharedB[1024]; + byte sig[1024]; + byte digest[20]; + byte export[1024]; + word32 x, y; + int i, verify, ret; + ecc_key userA, userB, pubKey; + + ret = InitRng(&rng); + if (ret != 0) + return -1001; + + ecc_init(&userA); + ecc_init(&userB); + ecc_init(&pubKey); + + ret = ecc_make_key(&rng, 32, &userA); + ret = ecc_make_key(&rng, 32, &userB); + + if (ret != 0) + return -1002; + + x = sizeof(sharedA); + ret = ecc_shared_secret(&userA, &userB, sharedA, &x); + + y = sizeof(sharedB); + ret = ecc_shared_secret(&userB, &userA, sharedB, &y); + + if (ret != 0) + return -1003; + + if (y != x) + return -1004; + + if (memcmp(sharedA, sharedB, x)) + return -1005; + + x = sizeof(export); + ret = ecc_export_x963(&userA, export, &x); + if (ret != 0) + return -1006; + + ret = ecc_import_x963(export, x, &pubKey); + + if (ret != 0) + return -1007; + + y = sizeof(sharedB); + ret = ecc_shared_secret(&userB, &pubKey, sharedB, &y); + + if (ret != 0) + return -1008; + + if (memcmp(sharedA, sharedB, y)) + return -1010; + + /* test DSA sign hash */ + for (i = 0; i < sizeof(digest); i++) + digest[i] = i; + + x = sizeof(sig); + ret = ecc_sign_hash(digest, sizeof(digest), sig, &x, &rng, &userA); + + verify = 0; + ret = ecc_verify_hash(sig, x, digest, sizeof(digest), &verify, &userA); + + if (ret != 0) + return -1011; + + if (verify != 1) + return -1012; + + ecc_free(&pubKey); + ecc_free(&userB); + ecc_free(&userA); + + return 0; +} + +#endif /* HAVE_ECC */ diff --git a/ctaocrypt/test/test.sln b/ctaocrypt/test/test.sln new file mode 100755 index 000000000..97b2e8dfd --- /dev/null +++ b/ctaocrypt/test/test.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual C++ Express 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test", "test.vcproj", "{D04BDF66-664A-4D59-BEAC-8AB2D5809C21}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {D04BDF66-664A-4D59-BEAC-8AB2D5809C21}.Debug|Win32.ActiveCfg = Debug|Win32 + {D04BDF66-664A-4D59-BEAC-8AB2D5809C21}.Debug|Win32.Build.0 = Debug|Win32 + {D04BDF66-664A-4D59-BEAC-8AB2D5809C21}.Release|Win32.ActiveCfg = Release|Win32 + {D04BDF66-664A-4D59-BEAC-8AB2D5809C21}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/ctaocrypt/test/test.vcproj b/ctaocrypt/test/test.vcproj new file mode 100755 index 000000000..38c5c6bed --- /dev/null +++ b/ctaocrypt/test/test.vcproj @@ -0,0 +1,195 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/cyassl-iphone.xcodeproj/project.pbxproj b/cyassl-iphone.xcodeproj/project.pbxproj new file mode 100644 index 000000000..8349a503b --- /dev/null +++ b/cyassl-iphone.xcodeproj/project.pbxproj @@ -0,0 +1,430 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 45; + objects = { + +/* Begin PBXBuildFile section */ + 43809E9B0FB7AD1C0050922E /* md4.c in Sources */ = {isa = PBXBuildFile; fileRef = 43809E9A0FB7AD1C0050922E /* md4.c */; }; + 43962ADF0DE7ED48003C5E5B /* ssl.c in Sources */ = {isa = PBXBuildFile; fileRef = 43C6C2790DDF984100F2D488 /* ssl.c */; }; + 43AC92CA0EB154210049F588 /* cyassl_io.c in Sources */ = {isa = PBXBuildFile; fileRef = 43AC92C90EB154210049F588 /* cyassl_io.c */; }; + 43C6C27B0DDF984100F2D488 /* cyassl_int.c in Sources */ = {isa = PBXBuildFile; fileRef = 43C6C2770DDF984100F2D488 /* cyassl_int.c */; }; + 43C6C27C0DDF984100F2D488 /* keys.c in Sources */ = {isa = PBXBuildFile; fileRef = 43C6C2780DDF984100F2D488 /* keys.c */; }; + 43C6C27E0DDF984100F2D488 /* tls.c in Sources */ = {isa = PBXBuildFile; fileRef = 43C6C27A0DDF984100F2D488 /* tls.c */; }; + 43C6C2920DDF98D400F2D488 /* aes.c in Sources */ = {isa = PBXBuildFile; fileRef = 43C6C2830DDF98D400F2D488 /* aes.c */; }; + 43C6C2930DDF98D400F2D488 /* arc4.c in Sources */ = {isa = PBXBuildFile; fileRef = 43C6C2840DDF98D400F2D488 /* arc4.c */; }; + 43C6C2940DDF98D400F2D488 /* asn.c in Sources */ = {isa = PBXBuildFile; fileRef = 43C6C2850DDF98D400F2D488 /* asn.c */; }; + 43C6C2950DDF98D400F2D488 /* coding.c in Sources */ = {isa = PBXBuildFile; fileRef = 43C6C2860DDF98D400F2D488 /* coding.c */; }; + 43C6C2960DDF98D400F2D488 /* des3.c in Sources */ = {isa = PBXBuildFile; fileRef = 43C6C2870DDF98D400F2D488 /* des3.c */; }; + 43C6C2970DDF98D400F2D488 /* dh.c in Sources */ = {isa = PBXBuildFile; fileRef = 43C6C2880DDF98D400F2D488 /* dh.c */; }; + 43C6C2980DDF98D400F2D488 /* dsa.c in Sources */ = {isa = PBXBuildFile; fileRef = 43C6C2890DDF98D400F2D488 /* dsa.c */; }; + 43C6C2990DDF98D400F2D488 /* hmac.c in Sources */ = {isa = PBXBuildFile; fileRef = 43C6C28A0DDF98D400F2D488 /* hmac.c */; }; + 43C6C29A0DDF98D400F2D488 /* integer.c in Sources */ = {isa = PBXBuildFile; fileRef = 43C6C28B0DDF98D400F2D488 /* integer.c */; }; + 43C6C29B0DDF98D400F2D488 /* md5.c in Sources */ = {isa = PBXBuildFile; fileRef = 43C6C28C0DDF98D400F2D488 /* md5.c */; }; + 43C6C29C0DDF98D400F2D488 /* misc.c in Sources */ = {isa = PBXBuildFile; fileRef = 43C6C28D0DDF98D400F2D488 /* misc.c */; }; + 43C6C29D0DDF98D400F2D488 /* random.c in Sources */ = {isa = PBXBuildFile; fileRef = 43C6C28E0DDF98D400F2D488 /* random.c */; }; + 43C6C29E0DDF98D400F2D488 /* rsa.c in Sources */ = {isa = PBXBuildFile; fileRef = 43C6C28F0DDF98D400F2D488 /* rsa.c */; }; + 43C6C29F0DDF98D400F2D488 /* sha.c in Sources */ = {isa = PBXBuildFile; fileRef = 43C6C2900DDF98D400F2D488 /* sha.c */; }; + 43C6C2A00DDF98D400F2D488 /* sha256.c in Sources */ = {isa = PBXBuildFile; fileRef = 43C6C2910DDF98D400F2D488 /* sha256.c */; }; + 43CA4B3F12C14EAE0001AF79 /* ctc_hmac.h in Headers */ = {isa = PBXBuildFile; fileRef = 43CA4B3612C14EAE0001AF79 /* ctc_hmac.h */; }; + 43CA4B4012C14EAE0001AF79 /* ctc_sha.h in Headers */ = {isa = PBXBuildFile; fileRef = 43CA4B3712C14EAE0001AF79 /* ctc_sha.h */; }; + 43CA4B4112C14EAE0001AF79 /* ctc_rsa.h in Headers */ = {isa = PBXBuildFile; fileRef = 43CA4B3812C14EAE0001AF79 /* ctc_rsa.h */; }; + 43CA4B4212C14EAE0001AF79 /* ctc_ripemd.h in Headers */ = {isa = PBXBuildFile; fileRef = 43CA4B3912C14EAE0001AF79 /* ctc_ripemd.h */; }; + 43CA4B4312C14EAE0001AF79 /* ctc_md5.h in Headers */ = {isa = PBXBuildFile; fileRef = 43CA4B3A12C14EAE0001AF79 /* ctc_md5.h */; }; + 43CA4B4412C14EAE0001AF79 /* ctc_md4.h in Headers */ = {isa = PBXBuildFile; fileRef = 43CA4B3B12C14EAE0001AF79 /* ctc_md4.h */; }; + 43CA4B4512C14EAE0001AF79 /* ctc_dsa.h in Headers */ = {isa = PBXBuildFile; fileRef = 43CA4B3C12C14EAE0001AF79 /* ctc_dsa.h */; }; + 43CA4B4612C14EAE0001AF79 /* ctc_dh.h in Headers */ = {isa = PBXBuildFile; fileRef = 43CA4B3D12C14EAE0001AF79 /* ctc_dh.h */; }; + 43CA4B4712C14EAE0001AF79 /* ctc_aes.h in Headers */ = {isa = PBXBuildFile; fileRef = 43CA4B3E12C14EAE0001AF79 /* ctc_aes.h */; }; + 43D565650F1EC9A600550C88 /* hc128.c in Sources */ = {isa = PBXBuildFile; fileRef = 43D565640F1EC9A600550C88 /* hc128.c */; }; + 43D565670F1EC9CC00550C88 /* rabbit.c in Sources */ = {isa = PBXBuildFile; fileRef = 43D565660F1EC9CC00550C88 /* rabbit.c */; }; + 43D565A40F29040000550C88 /* rabbit.h in Headers */ = {isa = PBXBuildFile; fileRef = 43D565A30F29040000550C88 /* rabbit.h */; }; + 43D565A60F29041C00550C88 /* hc128.h in Headers */ = {isa = PBXBuildFile; fileRef = 43D565A50F29041C00550C88 /* hc128.h */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 43C6C3160DDFAC6A00F2D488 /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 7; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 43C6C3170DDFAC6A00F2D488 /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 8; + dstPath = ""; + dstSubfolderSpec = 7; + files = ( + ); + runOnlyForDeploymentPostprocessing = 1; + }; + 43C6C3180DDFAC6A00F2D488 /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 7; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 4368F6E40E9EA1140002A123 /* test.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; lineEnding = 2; name = test.c; path = ctaocrypt/test/test.c; sourceTree = ""; }; + 43809E9A0FB7AD1C0050922E /* md4.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = md4.c; path = ctaocrypt/src/md4.c; sourceTree = ""; }; + 43AC92C90EB154210049F588 /* cyassl_io.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; lineEnding = 0; name = cyassl_io.c; path = src/cyassl_io.c; sourceTree = ""; }; + 43C6C2770DDF984100F2D488 /* cyassl_int.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; lineEnding = 0; name = cyassl_int.c; path = src/cyassl_int.c; sourceTree = ""; }; + 43C6C2780DDF984100F2D488 /* keys.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; lineEnding = 2; name = keys.c; path = src/keys.c; sourceTree = ""; }; + 43C6C2790DDF984100F2D488 /* ssl.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; lineEnding = 0; name = ssl.c; path = src/ssl.c; sourceTree = ""; }; + 43C6C27A0DDF984100F2D488 /* tls.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; lineEnding = 2; name = tls.c; path = src/tls.c; sourceTree = ""; }; + 43C6C2830DDF98D400F2D488 /* aes.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; lineEnding = 2; name = aes.c; path = ctaocrypt/src/aes.c; sourceTree = ""; }; + 43C6C2840DDF98D400F2D488 /* arc4.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; lineEnding = 2; name = arc4.c; path = ctaocrypt/src/arc4.c; sourceTree = ""; }; + 43C6C2850DDF98D400F2D488 /* asn.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; lineEnding = 2; name = asn.c; path = ctaocrypt/src/asn.c; sourceTree = ""; }; + 43C6C2860DDF98D400F2D488 /* coding.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; lineEnding = 2; name = coding.c; path = ctaocrypt/src/coding.c; sourceTree = ""; }; + 43C6C2870DDF98D400F2D488 /* des3.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; lineEnding = 2; name = des3.c; path = ctaocrypt/src/des3.c; sourceTree = ""; }; + 43C6C2880DDF98D400F2D488 /* dh.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; lineEnding = 2; name = dh.c; path = ctaocrypt/src/dh.c; sourceTree = ""; }; + 43C6C2890DDF98D400F2D488 /* dsa.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; lineEnding = 2; name = dsa.c; path = ctaocrypt/src/dsa.c; sourceTree = ""; }; + 43C6C28A0DDF98D400F2D488 /* hmac.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; lineEnding = 0; name = hmac.c; path = ctaocrypt/src/hmac.c; sourceTree = ""; }; + 43C6C28B0DDF98D400F2D488 /* integer.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; lineEnding = 2; name = integer.c; path = ctaocrypt/src/integer.c; sourceTree = ""; }; + 43C6C28C0DDF98D400F2D488 /* md5.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; lineEnding = 2; name = md5.c; path = ctaocrypt/src/md5.c; sourceTree = ""; }; + 43C6C28D0DDF98D400F2D488 /* misc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; lineEnding = 2; name = misc.c; path = ctaocrypt/src/misc.c; sourceTree = ""; }; + 43C6C28E0DDF98D400F2D488 /* random.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; lineEnding = 2; name = random.c; path = ctaocrypt/src/random.c; sourceTree = ""; }; + 43C6C28F0DDF98D400F2D488 /* rsa.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; lineEnding = 2; name = rsa.c; path = ctaocrypt/src/rsa.c; sourceTree = ""; }; + 43C6C2900DDF98D400F2D488 /* sha.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; lineEnding = 2; name = sha.c; path = ctaocrypt/src/sha.c; sourceTree = ""; }; + 43C6C2910DDF98D400F2D488 /* sha256.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; lineEnding = 0; name = sha256.c; path = ctaocrypt/src/sha256.c; sourceTree = ""; }; + 43CA25BA0EA400BE0011ECA2 /* cyassl_error.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.c.h; fileEncoding = 4; lineEnding = 2; name = cyassl_error.h; path = include/cyassl_error.h; sourceTree = ""; }; + 43CA25BB0EA400BE0011ECA2 /* cyassl_int.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.c.h; fileEncoding = 4; lineEnding = 2; name = cyassl_int.h; path = include/cyassl_int.h; sourceTree = ""; }; + 43CA25BC0EA400DC0011ECA2 /* test.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.c.h; fileEncoding = 4; lineEnding = 2; name = test.h; path = examples/test.h; sourceTree = ""; }; + 43CA25BE0EA4010C0011ECA2 /* arc4.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.c.h; fileEncoding = 4; lineEnding = 2; name = arc4.h; path = ctaocrypt/include/arc4.h; sourceTree = ""; }; + 43CA25C10EA4010C0011ECA2 /* mpi_superclass.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.c.h; fileEncoding = 4; lineEnding = 0; name = mpi_superclass.h; path = ctaocrypt/include/mpi_superclass.h; sourceTree = ""; }; + 43CA25C20EA4010C0011ECA2 /* random.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.c.h; fileEncoding = 4; lineEnding = 2; name = random.h; path = ctaocrypt/include/random.h; sourceTree = ""; }; + 43CA25C40EA4010C0011ECA2 /* sha256.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.c.h; fileEncoding = 4; lineEnding = 0; name = sha256.h; path = ctaocrypt/include/sha256.h; sourceTree = ""; }; + 43CA25C50EA4010C0011ECA2 /* coding.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.c.h; fileEncoding = 4; lineEnding = 2; name = coding.h; path = ctaocrypt/include/coding.h; sourceTree = ""; }; + 43CA25C60EA4010C0011ECA2 /* des3.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.c.h; fileEncoding = 4; lineEnding = 2; name = des3.h; path = ctaocrypt/include/des3.h; sourceTree = ""; }; + 43CA25C70EA4010C0011ECA2 /* error.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.c.h; fileEncoding = 4; lineEnding = 2; name = error.h; path = ctaocrypt/include/error.h; sourceTree = ""; }; + 43CA25C80EA4010C0011ECA2 /* misc.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.c.h; fileEncoding = 4; lineEnding = 2; name = misc.h; path = ctaocrypt/include/misc.h; sourceTree = ""; }; + 43CA25C90EA4010C0011ECA2 /* integer.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.c.h; fileEncoding = 4; lineEnding = 2; name = integer.h; path = ctaocrypt/include/integer.h; sourceTree = ""; }; + 43CA25CA0EA4010C0011ECA2 /* tfm.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.c.h; fileEncoding = 4; lineEnding = 0; name = tfm.h; path = ctaocrypt/include/tfm.h; sourceTree = ""; }; + 43CA25CB0EA4010C0011ECA2 /* asn.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.c.h; fileEncoding = 4; lineEnding = 2; name = asn.h; path = ctaocrypt/include/asn.h; sourceTree = ""; }; + 43CA25CD0EA4010C0011ECA2 /* mpi_class.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.c.h; fileEncoding = 4; lineEnding = 0; name = mpi_class.h; path = ctaocrypt/include/mpi_class.h; sourceTree = ""; }; + 43CA25CE0EA4010C0011ECA2 /* types.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.c.h; fileEncoding = 4; lineEnding = 2; name = types.h; path = ctaocrypt/include/types.h; sourceTree = ""; }; + 43CA25D10EA401550011ECA2 /* cyassl_callbacks.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.c.h; fileEncoding = 4; lineEnding = 2; name = cyassl_callbacks.h; path = include/openssl/cyassl_callbacks.h; sourceTree = ""; }; + 43CA25D20EA401550011ECA2 /* ssl.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.c.h; fileEncoding = 4; lineEnding = 2; name = ssl.h; path = include/openssl/ssl.h; sourceTree = ""; }; + 43CA4B3612C14EAE0001AF79 /* ctc_hmac.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; name = ctc_hmac.h; path = ctaocrypt/include/ctc_hmac.h; sourceTree = ""; }; + 43CA4B3712C14EAE0001AF79 /* ctc_sha.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 2; name = ctc_sha.h; path = ctaocrypt/include/ctc_sha.h; sourceTree = ""; }; + 43CA4B3812C14EAE0001AF79 /* ctc_rsa.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 2; name = ctc_rsa.h; path = ctaocrypt/include/ctc_rsa.h; sourceTree = ""; }; + 43CA4B3912C14EAE0001AF79 /* ctc_ripemd.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 2; name = ctc_ripemd.h; path = ctaocrypt/include/ctc_ripemd.h; sourceTree = ""; }; + 43CA4B3A12C14EAE0001AF79 /* ctc_md5.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 2; name = ctc_md5.h; path = ctaocrypt/include/ctc_md5.h; sourceTree = ""; }; + 43CA4B3B12C14EAE0001AF79 /* ctc_md4.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 2; name = ctc_md4.h; path = ctaocrypt/include/ctc_md4.h; sourceTree = ""; }; + 43CA4B3C12C14EAE0001AF79 /* ctc_dsa.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 2; name = ctc_dsa.h; path = ctaocrypt/include/ctc_dsa.h; sourceTree = ""; }; + 43CA4B3D12C14EAE0001AF79 /* ctc_dh.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 2; name = ctc_dh.h; path = ctaocrypt/include/ctc_dh.h; sourceTree = ""; }; + 43CA4B3E12C14EAE0001AF79 /* ctc_aes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 2; name = ctc_aes.h; path = ctaocrypt/include/ctc_aes.h; sourceTree = ""; }; + 43CB530D116E9FD5000A264B /* iphone-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "iphone-Info.plist"; sourceTree = ""; }; + 43D565640F1EC9A600550C88 /* hc128.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; lineEnding = 2; name = hc128.c; path = ctaocrypt/src/hc128.c; sourceTree = ""; }; + 43D565660F1EC9CC00550C88 /* rabbit.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; lineEnding = 2; name = rabbit.c; path = ctaocrypt/src/rabbit.c; sourceTree = ""; }; + 43D565A30F29040000550C88 /* rabbit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 2; name = rabbit.h; path = ctaocrypt/include/rabbit.h; sourceTree = ""; }; + 43D565A50F29041C00550C88 /* hc128.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 2; name = hc128.h; path = ctaocrypt/include/hc128.h; sourceTree = ""; }; + D2AAC046055464E500DB518D /* libcyassl.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libcyassl.a; sourceTree = BUILT_PRODUCTS_DIR; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + D289987405E68DCB004EDB86 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 08FB7794FE84155DC02AAC07 /* cyassl */ = { + isa = PBXGroup; + children = ( + 08FB7795FE84155DC02AAC07 /* Source */, + C6A0FF2B0290797F04C91782 /* Documentation */, + 1AB674ADFE9D54B511CA2CBB /* Products */, + 43CB530D116E9FD5000A264B /* iphone-Info.plist */, + ); + name = cyassl; + sourceTree = ""; + }; + 08FB7795FE84155DC02AAC07 /* Source */ = { + isa = PBXGroup; + children = ( + 43CA25B90EA400A60011ECA2 /* headers */, + 43CA25720EA3F9B20011ECA2 /* src */, + ); + name = Source; + sourceTree = ""; + }; + 1AB674ADFE9D54B511CA2CBB /* Products */ = { + isa = PBXGroup; + children = ( + D2AAC046055464E500DB518D /* libcyassl.a */, + ); + name = Products; + sourceTree = ""; + }; + 43CA25720EA3F9B20011ECA2 /* src */ = { + isa = PBXGroup; + children = ( + 43809E9A0FB7AD1C0050922E /* md4.c */, + 43D565660F1EC9CC00550C88 /* rabbit.c */, + 43D565640F1EC9A600550C88 /* hc128.c */, + 43AC92C90EB154210049F588 /* cyassl_io.c */, + 43C6C2830DDF98D400F2D488 /* aes.c */, + 43C6C2840DDF98D400F2D488 /* arc4.c */, + 43C6C2850DDF98D400F2D488 /* asn.c */, + 43C6C2860DDF98D400F2D488 /* coding.c */, + 43C6C2870DDF98D400F2D488 /* des3.c */, + 4368F6E40E9EA1140002A123 /* test.c */, + 43C6C2880DDF98D400F2D488 /* dh.c */, + 43C6C2890DDF98D400F2D488 /* dsa.c */, + 43C6C28A0DDF98D400F2D488 /* hmac.c */, + 43C6C28B0DDF98D400F2D488 /* integer.c */, + 43C6C28C0DDF98D400F2D488 /* md5.c */, + 43C6C28D0DDF98D400F2D488 /* misc.c */, + 43C6C28E0DDF98D400F2D488 /* random.c */, + 43C6C28F0DDF98D400F2D488 /* rsa.c */, + 43C6C2900DDF98D400F2D488 /* sha.c */, + 43C6C2910DDF98D400F2D488 /* sha256.c */, + 43C6C2770DDF984100F2D488 /* cyassl_int.c */, + 43C6C2780DDF984100F2D488 /* keys.c */, + 43C6C2790DDF984100F2D488 /* ssl.c */, + 43C6C27A0DDF984100F2D488 /* tls.c */, + ); + name = src; + sourceTree = ""; + }; + 43CA25B90EA400A60011ECA2 /* headers */ = { + isa = PBXGroup; + children = ( + 43CA4B3612C14EAE0001AF79 /* ctc_hmac.h */, + 43CA4B3712C14EAE0001AF79 /* ctc_sha.h */, + 43CA4B3812C14EAE0001AF79 /* ctc_rsa.h */, + 43CA4B3912C14EAE0001AF79 /* ctc_ripemd.h */, + 43CA4B3A12C14EAE0001AF79 /* ctc_md5.h */, + 43CA4B3B12C14EAE0001AF79 /* ctc_md4.h */, + 43CA4B3C12C14EAE0001AF79 /* ctc_dsa.h */, + 43CA4B3D12C14EAE0001AF79 /* ctc_dh.h */, + 43CA4B3E12C14EAE0001AF79 /* ctc_aes.h */, + 43D565A50F29041C00550C88 /* hc128.h */, + 43D565A30F29040000550C88 /* rabbit.h */, + 43CA25D10EA401550011ECA2 /* cyassl_callbacks.h */, + 43CA25D20EA401550011ECA2 /* ssl.h */, + 43CA25BE0EA4010C0011ECA2 /* arc4.h */, + 43CA25C10EA4010C0011ECA2 /* mpi_superclass.h */, + 43CA25C20EA4010C0011ECA2 /* random.h */, + 43CA25C40EA4010C0011ECA2 /* sha256.h */, + 43CA25C50EA4010C0011ECA2 /* coding.h */, + 43CA25C60EA4010C0011ECA2 /* des3.h */, + 43CA25C70EA4010C0011ECA2 /* error.h */, + 43CA25C80EA4010C0011ECA2 /* misc.h */, + 43CA25C90EA4010C0011ECA2 /* integer.h */, + 43CA25CA0EA4010C0011ECA2 /* tfm.h */, + 43CA25CB0EA4010C0011ECA2 /* asn.h */, + 43CA25CD0EA4010C0011ECA2 /* mpi_class.h */, + 43CA25CE0EA4010C0011ECA2 /* types.h */, + 43CA25BC0EA400DC0011ECA2 /* test.h */, + 43CA25BA0EA400BE0011ECA2 /* cyassl_error.h */, + 43CA25BB0EA400BE0011ECA2 /* cyassl_int.h */, + ); + name = headers; + sourceTree = ""; + }; + C6A0FF2B0290797F04C91782 /* Documentation */ = { + isa = PBXGroup; + children = ( + ); + name = Documentation; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + D2AAC043055464E500DB518D /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 43D565A40F29040000550C88 /* rabbit.h in Headers */, + 43D565A60F29041C00550C88 /* hc128.h in Headers */, + 43CA4B3F12C14EAE0001AF79 /* ctc_hmac.h in Headers */, + 43CA4B4012C14EAE0001AF79 /* ctc_sha.h in Headers */, + 43CA4B4112C14EAE0001AF79 /* ctc_rsa.h in Headers */, + 43CA4B4212C14EAE0001AF79 /* ctc_ripemd.h in Headers */, + 43CA4B4312C14EAE0001AF79 /* ctc_md5.h in Headers */, + 43CA4B4412C14EAE0001AF79 /* ctc_md4.h in Headers */, + 43CA4B4512C14EAE0001AF79 /* ctc_dsa.h in Headers */, + 43CA4B4612C14EAE0001AF79 /* ctc_dh.h in Headers */, + 43CA4B4712C14EAE0001AF79 /* ctc_aes.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXNativeTarget section */ + D2AAC045055464E500DB518D /* cyassl */ = { + isa = PBXNativeTarget; + buildConfigurationList = 1DEB91EB08733DB70010E9CD /* Build configuration list for PBXNativeTarget "cyassl" */; + buildPhases = ( + D2AAC043055464E500DB518D /* Headers */, + D2AAC044055464E500DB518D /* Sources */, + D289987405E68DCB004EDB86 /* Frameworks */, + 43C6C3160DDFAC6A00F2D488 /* CopyFiles */, + 43C6C3170DDFAC6A00F2D488 /* CopyFiles */, + 43C6C3180DDFAC6A00F2D488 /* CopyFiles */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = cyassl; + productName = cyassl; + productReference = D2AAC046055464E500DB518D /* libcyassl.a */; + productType = "com.apple.product-type.library.static"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 08FB7793FE84155DC02AAC07 /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = YES; + }; + buildConfigurationList = 1DEB91EF08733DB70010E9CD /* Build configuration list for PBXProject "cyassl-iphone" */; + compatibilityVersion = "Xcode 3.1"; + hasScannedForEncodings = 1; + mainGroup = 08FB7794FE84155DC02AAC07 /* cyassl */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + D2AAC045055464E500DB518D /* cyassl */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXSourcesBuildPhase section */ + D2AAC044055464E500DB518D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 43C6C27B0DDF984100F2D488 /* cyassl_int.c in Sources */, + 43C6C27C0DDF984100F2D488 /* keys.c in Sources */, + 43C6C27E0DDF984100F2D488 /* tls.c in Sources */, + 43C6C2920DDF98D400F2D488 /* aes.c in Sources */, + 43C6C2930DDF98D400F2D488 /* arc4.c in Sources */, + 43C6C2940DDF98D400F2D488 /* asn.c in Sources */, + 43C6C2950DDF98D400F2D488 /* coding.c in Sources */, + 43C6C2960DDF98D400F2D488 /* des3.c in Sources */, + 43C6C2970DDF98D400F2D488 /* dh.c in Sources */, + 43C6C2980DDF98D400F2D488 /* dsa.c in Sources */, + 43C6C2990DDF98D400F2D488 /* hmac.c in Sources */, + 43C6C29A0DDF98D400F2D488 /* integer.c in Sources */, + 43C6C29B0DDF98D400F2D488 /* md5.c in Sources */, + 43C6C29C0DDF98D400F2D488 /* misc.c in Sources */, + 43C6C29D0DDF98D400F2D488 /* random.c in Sources */, + 43C6C29E0DDF98D400F2D488 /* rsa.c in Sources */, + 43C6C29F0DDF98D400F2D488 /* sha.c in Sources */, + 43C6C2A00DDF98D400F2D488 /* sha256.c in Sources */, + 43962ADF0DE7ED48003C5E5B /* ssl.c in Sources */, + 43AC92CA0EB154210049F588 /* cyassl_io.c in Sources */, + 43D565650F1EC9A600550C88 /* hc128.c in Sources */, + 43D565670F1EC9CC00550C88 /* rabbit.c in Sources */, + 43809E9B0FB7AD1C0050922E /* md4.c in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 1DEB91EC08733DB70010E9CD /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(ARCHS_STANDARD_32_BIT)"; + COPY_PHASE_STRIP = NO; + GCC_DYNAMIC_NO_PIC = NO; + GCC_ENABLE_FIX_AND_CONTINUE = YES; + GCC_MODEL_TUNING = G5; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = IPHONE; + INSTALL_PATH = /usr/local/lib; + PRODUCT_NAME = cyassl; + SDKROOT = iphonesimulator3.1.2; + USER_HEADER_SEARCH_PATHS = "include/openssl include ctaocrypt/include"; + WARNING_CFLAGS = "-Wall"; + ZERO_LINK = YES; + }; + name = Debug; + }; + 1DEB91ED08733DB70010E9CD /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(ARCHS_STANDARD_32_BIT)"; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + GCC_MODEL_TUNING = G5; + GCC_PREPROCESSOR_DEFINITIONS = IPHONE; + INSTALL_PATH = /usr/local/lib; + PRODUCT_NAME = cyassl; + USER_HEADER_SEARCH_PATHS = "include/openssl include ctaocrypt/include"; + WARNING_CFLAGS = "-Wall"; + }; + name = Release; + }; + 1DEB91F008733DB70010E9CD /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(ARCHS_STANDARD_32_BIT)"; + GCC_PREPROCESSOR_DEFINITIONS = IPHONE; + GCC_VERSION = 4.2; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + PREBINDING = NO; + SDKROOT = iphonesimulator2.2; + USER_HEADER_SEARCH_PATHS = "include ctaocrypt/include"; + }; + name = Debug; + }; + 1DEB91F108733DB70010E9CD /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(ARCHS_STANDARD_32_BIT)"; + GCC_PREPROCESSOR_DEFINITIONS = IPHONE; + GCC_VERSION = 4.2; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + PREBINDING = NO; + SDKROOT = iphonesimulator2.2; + USER_HEADER_SEARCH_PATHS = "include ctaocrypt/include"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 1DEB91EB08733DB70010E9CD /* Build configuration list for PBXNativeTarget "cyassl" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1DEB91EC08733DB70010E9CD /* Debug */, + 1DEB91ED08733DB70010E9CD /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 1DEB91EF08733DB70010E9CD /* Build configuration list for PBXProject "cyassl-iphone" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1DEB91F008733DB70010E9CD /* Debug */, + 1DEB91F108733DB70010E9CD /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 08FB7793FE84155DC02AAC07 /* Project object */; +} diff --git a/cyassl-ntru.sln b/cyassl-ntru.sln new file mode 100755 index 000000000..1c6d70701 --- /dev/null +++ b/cyassl-ntru.sln @@ -0,0 +1,65 @@ + +Microsoft Visual Studio Solution File, Format Version 10.00 +# Visual C++ Express 2008 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cyassl", "cyassl-ntru.vcproj", "{73973223-5EE8-41CA-8E88-1D60E89A237B}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testsuite", "testsuite\testsuite-ntru.vcproj", "{611E8971-46E0-4D0A-B5A1-632C3B00CB80}" + ProjectSection(ProjectDependencies) = postProject + {73973223-5EE8-41CA-8E88-1D60E89A237B} = {73973223-5EE8-41CA-8E88-1D60E89A237B} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "echoserver", "examples\echoserver\echoserver-ntru.vcproj", "{07D97C48-E08F-4E34-9F67-3064039FF2CB}" + ProjectSection(ProjectDependencies) = postProject + {73973223-5EE8-41CA-8E88-1D60E89A237B} = {73973223-5EE8-41CA-8E88-1D60E89A237B} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "echoclient", "examples\echoclient\echoclient-ntru.vcproj", "{8362A816-C5DC-4E22-B5C5-9E6806387073}" + ProjectSection(ProjectDependencies) = postProject + {73973223-5EE8-41CA-8E88-1D60E89A237B} = {73973223-5EE8-41CA-8E88-1D60E89A237B} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "client", "examples\client\client-ntru.vcproj", "{3ADE9549-582D-4D8E-9826-B172197A7959}" + ProjectSection(ProjectDependencies) = postProject + {73973223-5EE8-41CA-8E88-1D60E89A237B} = {73973223-5EE8-41CA-8E88-1D60E89A237B} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "server", "examples\server\server-ntru.vcproj", "{E9FB0BA5-BA46-4A59-A953-39C18CD1DCB1}" + ProjectSection(ProjectDependencies) = postProject + {73973223-5EE8-41CA-8E88-1D60E89A237B} = {73973223-5EE8-41CA-8E88-1D60E89A237B} + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {73973223-5EE8-41CA-8E88-1D60E89A237B}.Debug|Win32.ActiveCfg = Debug|Win32 + {73973223-5EE8-41CA-8E88-1D60E89A237B}.Debug|Win32.Build.0 = Debug|Win32 + {73973223-5EE8-41CA-8E88-1D60E89A237B}.Release|Win32.ActiveCfg = Release|Win32 + {73973223-5EE8-41CA-8E88-1D60E89A237B}.Release|Win32.Build.0 = Release|Win32 + {611E8971-46E0-4D0A-B5A1-632C3B00CB80}.Debug|Win32.ActiveCfg = Debug|Win32 + {611E8971-46E0-4D0A-B5A1-632C3B00CB80}.Debug|Win32.Build.0 = Debug|Win32 + {611E8971-46E0-4D0A-B5A1-632C3B00CB80}.Release|Win32.ActiveCfg = Release|Win32 + {611E8971-46E0-4D0A-B5A1-632C3B00CB80}.Release|Win32.Build.0 = Release|Win32 + {07D97C48-E08F-4E34-9F67-3064039FF2CB}.Debug|Win32.ActiveCfg = Debug|Win32 + {07D97C48-E08F-4E34-9F67-3064039FF2CB}.Debug|Win32.Build.0 = Debug|Win32 + {07D97C48-E08F-4E34-9F67-3064039FF2CB}.Release|Win32.ActiveCfg = Release|Win32 + {07D97C48-E08F-4E34-9F67-3064039FF2CB}.Release|Win32.Build.0 = Release|Win32 + {8362A816-C5DC-4E22-B5C5-9E6806387073}.Debug|Win32.ActiveCfg = Debug|Win32 + {8362A816-C5DC-4E22-B5C5-9E6806387073}.Debug|Win32.Build.0 = Debug|Win32 + {8362A816-C5DC-4E22-B5C5-9E6806387073}.Release|Win32.ActiveCfg = Release|Win32 + {8362A816-C5DC-4E22-B5C5-9E6806387073}.Release|Win32.Build.0 = Release|Win32 + {3ADE9549-582D-4D8E-9826-B172197A7959}.Debug|Win32.ActiveCfg = Debug|Win32 + {3ADE9549-582D-4D8E-9826-B172197A7959}.Debug|Win32.Build.0 = Debug|Win32 + {3ADE9549-582D-4D8E-9826-B172197A7959}.Release|Win32.ActiveCfg = Release|Win32 + {3ADE9549-582D-4D8E-9826-B172197A7959}.Release|Win32.Build.0 = Release|Win32 + {E9FB0BA5-BA46-4A59-A953-39C18CD1DCB1}.Debug|Win32.ActiveCfg = Debug|Win32 + {E9FB0BA5-BA46-4A59-A953-39C18CD1DCB1}.Debug|Win32.Build.0 = Debug|Win32 + {E9FB0BA5-BA46-4A59-A953-39C18CD1DCB1}.Release|Win32.ActiveCfg = Release|Win32 + {E9FB0BA5-BA46-4A59-A953-39C18CD1DCB1}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/cyassl-ntru.vcproj b/cyassl-ntru.vcproj new file mode 100755 index 000000000..98bc3b05d --- /dev/null +++ b/cyassl-ntru.vcproj @@ -0,0 +1,377 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/cyassl.sln b/cyassl.sln new file mode 100755 index 000000000..7fa922f74 --- /dev/null +++ b/cyassl.sln @@ -0,0 +1,74 @@ + +Microsoft Visual Studio Solution File, Format Version 10.00 +# Visual C++ Express 2008 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cyassl", "cyassl.vcproj", "{73973223-5EE8-41CA-8E88-1D60E89A237B}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testsuite", "testsuite\testsuite.vcproj", "{611E8971-46E0-4D0A-B5A1-632C3B00CB80}" + ProjectSection(ProjectDependencies) = postProject + {73973223-5EE8-41CA-8E88-1D60E89A237B} = {73973223-5EE8-41CA-8E88-1D60E89A237B} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sslSniffer", "sslSniffer\sslSniffer.vcproj", "{34FAE5A6-2B0F-4B55-86FE-0C43E4810F4D}" + ProjectSection(ProjectDependencies) = postProject + {73973223-5EE8-41CA-8E88-1D60E89A237B} = {73973223-5EE8-41CA-8E88-1D60E89A237B} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "echoserver", "examples\echoserver\echoserver.vcproj", "{07D97C48-E08F-4E34-9F67-3064039FF2CB}" + ProjectSection(ProjectDependencies) = postProject + {73973223-5EE8-41CA-8E88-1D60E89A237B} = {73973223-5EE8-41CA-8E88-1D60E89A237B} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "echoclient", "examples\echoclient\echoclient.vcproj", "{8362A816-C5DC-4E22-B5C5-9E6806387073}" + ProjectSection(ProjectDependencies) = postProject + {73973223-5EE8-41CA-8E88-1D60E89A237B} = {73973223-5EE8-41CA-8E88-1D60E89A237B} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "client", "examples\client\client.vcproj", "{3ADE9549-582D-4D8E-9826-B172197A7959}" + ProjectSection(ProjectDependencies) = postProject + {73973223-5EE8-41CA-8E88-1D60E89A237B} = {73973223-5EE8-41CA-8E88-1D60E89A237B} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "server", "examples\server\server.vcproj", "{E9FB0BA5-BA46-4A59-A953-39C18CD1DCB1}" + ProjectSection(ProjectDependencies) = postProject + {73973223-5EE8-41CA-8E88-1D60E89A237B} = {73973223-5EE8-41CA-8E88-1D60E89A237B} + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {73973223-5EE8-41CA-8E88-1D60E89A237B}.Debug|Win32.ActiveCfg = Debug|Win32 + {73973223-5EE8-41CA-8E88-1D60E89A237B}.Debug|Win32.Build.0 = Debug|Win32 + {73973223-5EE8-41CA-8E88-1D60E89A237B}.Release|Win32.ActiveCfg = Release|Win32 + {73973223-5EE8-41CA-8E88-1D60E89A237B}.Release|Win32.Build.0 = Release|Win32 + {611E8971-46E0-4D0A-B5A1-632C3B00CB80}.Debug|Win32.ActiveCfg = Debug|Win32 + {611E8971-46E0-4D0A-B5A1-632C3B00CB80}.Debug|Win32.Build.0 = Debug|Win32 + {611E8971-46E0-4D0A-B5A1-632C3B00CB80}.Release|Win32.ActiveCfg = Release|Win32 + {611E8971-46E0-4D0A-B5A1-632C3B00CB80}.Release|Win32.Build.0 = Release|Win32 + {34FAE5A6-2B0F-4B55-86FE-0C43E4810F4D}.Debug|Win32.ActiveCfg = Debug|Win32 + {34FAE5A6-2B0F-4B55-86FE-0C43E4810F4D}.Debug|Win32.Build.0 = Debug|Win32 + {34FAE5A6-2B0F-4B55-86FE-0C43E4810F4D}.Release|Win32.ActiveCfg = Release|Win32 + {34FAE5A6-2B0F-4B55-86FE-0C43E4810F4D}.Release|Win32.Build.0 = Release|Win32 + {07D97C48-E08F-4E34-9F67-3064039FF2CB}.Debug|Win32.ActiveCfg = Debug|Win32 + {07D97C48-E08F-4E34-9F67-3064039FF2CB}.Debug|Win32.Build.0 = Debug|Win32 + {07D97C48-E08F-4E34-9F67-3064039FF2CB}.Release|Win32.ActiveCfg = Release|Win32 + {07D97C48-E08F-4E34-9F67-3064039FF2CB}.Release|Win32.Build.0 = Release|Win32 + {8362A816-C5DC-4E22-B5C5-9E6806387073}.Debug|Win32.ActiveCfg = Debug|Win32 + {8362A816-C5DC-4E22-B5C5-9E6806387073}.Debug|Win32.Build.0 = Debug|Win32 + {8362A816-C5DC-4E22-B5C5-9E6806387073}.Release|Win32.ActiveCfg = Release|Win32 + {8362A816-C5DC-4E22-B5C5-9E6806387073}.Release|Win32.Build.0 = Release|Win32 + {3ADE9549-582D-4D8E-9826-B172197A7959}.Debug|Win32.ActiveCfg = Debug|Win32 + {3ADE9549-582D-4D8E-9826-B172197A7959}.Debug|Win32.Build.0 = Debug|Win32 + {3ADE9549-582D-4D8E-9826-B172197A7959}.Release|Win32.ActiveCfg = Release|Win32 + {3ADE9549-582D-4D8E-9826-B172197A7959}.Release|Win32.Build.0 = Release|Win32 + {E9FB0BA5-BA46-4A59-A953-39C18CD1DCB1}.Debug|Win32.ActiveCfg = Debug|Win32 + {E9FB0BA5-BA46-4A59-A953-39C18CD1DCB1}.Debug|Win32.Build.0 = Debug|Win32 + {E9FB0BA5-BA46-4A59-A953-39C18CD1DCB1}.Release|Win32.ActiveCfg = Release|Win32 + {E9FB0BA5-BA46-4A59-A953-39C18CD1DCB1}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/cyassl.vcproj b/cyassl.vcproj new file mode 100755 index 000000000..3b9d4671c --- /dev/null +++ b/cyassl.vcproj @@ -0,0 +1,377 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/CyaSSL-Manual.pdf b/doc/CyaSSL-Manual.pdf new file mode 100644 index 0000000000000000000000000000000000000000..f5c3c06b14167425b5d4f950860e17a29c04d1d9 GIT binary patch literal 1104776 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Î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Ξ#;`xZ0ywa{XeDqRsuhz9_lnx!ID= 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

=Cp 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

Lw`Y8tb=*J5 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 z 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 gDiw4tj-4G>aY + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/client/client.c b/examples/client/client.c new file mode 100644 index 000000000..bf01d621d --- /dev/null +++ b/examples/client/client.c @@ -0,0 +1,303 @@ +/* client.c */ +#include "ssl.h" +#include "cyassl_test.h" + + +/* +#define TEST_RESUME +*/ + + +#ifdef CYASSL_CALLBACKS + int handShakeCB(HandShakeInfo*); + int timeoutCB(TimeoutInfo*); + Timeval timeout; +#endif + +#if defined(NON_BLOCKING) || defined(CYASSL_CALLBACKS) + void NonBlockingSSL_Connect(SSL* ssl) + { +#ifndef CYASSL_CALLBACKS + int ret = SSL_connect(ssl); +#else + int ret = CyaSSL_connect_ex(ssl, handShakeCB, timeoutCB, timeout); +#endif + int error = SSL_get_error(ssl, 0); + while (ret != SSL_SUCCESS && (error == SSL_ERROR_WANT_READ || + error == SSL_ERROR_WANT_WRITE)) { + if (error == SSL_ERROR_WANT_READ) + printf("... client would read block\n"); + else + printf("... client would write block\n"); + #ifdef USE_WINDOWS_API + Sleep(100); + #else + sleep(1); + #endif + #ifndef CYASSL_CALLBACKS + ret = SSL_connect(ssl); + #else + ret = CyaSSL_connect_ex(ssl, handShakeCB, timeoutCB, timeout); + #endif + error = SSL_get_error(ssl, 0); + } + if (ret != SSL_SUCCESS) + err_sys("SSL_connect failed"); + } +#endif + + +void client_test(void* args) +{ + SOCKET_T sockfd = 0; + + SSL_METHOD* method = 0; + SSL_CTX* ctx = 0; + SSL* ssl = 0; + +#ifdef TEST_RESUME + SSL* sslResume = 0; + SSL_SESSION* session = 0; + char resumeMsg[] = "resuming cyassl!"; + int resumeSz = sizeof(resumeMsg); +#endif + + char msg[] = "hello cyassl!"; + char reply[1024]; + int input; + int msgSz = sizeof(msg); + + int argc = ((func_args*)args)->argc; + char** argv = ((func_args*)args)->argv; + + ((func_args*)args)->return_code = -1; /* error state */ + +#if defined(CYASSL_DTLS) + method = DTLSv1_client_method(); +#elif !defined(NO_TLS) + method = TLSv1_client_method(); +#else + method = SSLv3_client_method(); +#endif + ctx = SSL_CTX_new(method); + +#ifndef NO_PSK + SSL_CTX_set_psk_client_callback(ctx, my_psk_client_cb); +#endif + +#ifdef OPENSSL_EXTRA + SSL_CTX_set_default_passwd_cb(ctx, PasswordCallBack); +#endif + +#ifndef NO_FILESYSTEM + if (SSL_CTX_load_verify_locations(ctx, caCert, 0) != SSL_SUCCESS) + err_sys("can't load ca file"); + #ifdef HAVE_ECC + if (SSL_CTX_load_verify_locations(ctx, eccCert, 0) != SSL_SUCCESS) + err_sys("can't load ca file"); + #endif +#else + load_buffer(ctx, caCert, CYASSL_CA); +#endif + +#ifdef VERIFY_CALLBACK + SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, myVerify); +#endif + + if (argc == 3) { + /* ./client server securePort */ + SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, 0); /* TODO: add ca cert */ + /* this is just to allow easy testing of other servers */ + tcp_connect(&sockfd, argv[1], (short)atoi(argv[2])); + } + else if (argc == 1) { + /* ./client // plain mode */ + /* for client cert authentication if server requests */ +#ifndef NO_FILESYSTEM + if (SSL_CTX_use_certificate_file(ctx, cliCert, SSL_FILETYPE_PEM) + != SSL_SUCCESS) + err_sys("can't load client cert file"); + + if (SSL_CTX_use_PrivateKey_file(ctx, cliKey, SSL_FILETYPE_PEM) + != SSL_SUCCESS) + err_sys("can't load client key file"); +#else + load_buffer(ctx, cliCert, CYASSL_CERT); + load_buffer(ctx, cliKey, CYASSL_KEY); +#endif + + tcp_connect(&sockfd, yasslIP, yasslPort); + } + else if (argc == 2) { + /* time passed in number of connects give average */ + int times = atoi(argv[1]); + int i = 0; + + double start = current_time(), avg; + + for (i = 0; i < times; i++) { + tcp_connect(&sockfd, yasslIP, yasslPort); + ssl = SSL_new(ctx); + SSL_set_fd(ssl, sockfd); + if (SSL_connect(ssl) != SSL_SUCCESS) + err_sys("SSL_connect failed"); + + SSL_shutdown(ssl); + SSL_free(ssl); + CloseSocket(sockfd); + } + avg = current_time() - start; + avg /= times; + avg *= 1000; /* milliseconds */ + printf("SSL_connect avg took:%6.3f milliseconds\n", avg); + + SSL_CTX_free(ctx); + ((func_args*)args)->return_code = 0; + return; + } + else + err_sys("usage: ./client server securePort"); + + ssl = SSL_new(ctx); + SSL_set_fd(ssl, sockfd); + CyaSSL_check_domain_name(ssl, "www.yassl.com"); +#ifdef NON_BLOCKING + tcp_set_nonblocking(&sockfd); + NonBlockingSSL_Connect(ssl); +#else + #ifndef CYASSL_CALLBACKS + if (SSL_connect(ssl) != SSL_SUCCESS) { /* see note at top of README */ + int err = SSL_get_error(ssl, 0); + char buffer[80]; + printf("err = %d, %s\n", err, ERR_error_string(err, buffer)); + err_sys("SSL_connect failed");/* if you're getting an error here */ + } + #else + timeout.tv_sec = 2; + timeout.tv_usec = 0; + NonBlockingSSL_Connect(ssl); /* will keep retrying on timeout */ + #endif +#endif + showPeer(ssl); + + if (argc == 3) { + printf("SSL connect ok, sending GET...\n"); + strncpy(msg, "GET\r\n", 6); + msgSz = 6; + } + if (SSL_write(ssl, msg, msgSz) != msgSz) + err_sys("SSL_write failed"); + + input = SSL_read(ssl, reply, sizeof(reply)); + if (input > 0) { + reply[input] = 0; + printf("Server response: %s\n", reply); + } + +#ifdef TEST_RESUME + #ifdef CYASSL_DTLS + strncpy(msg, "break", 6); + msgSz = (int)strlen(msg); + /* try to send session close */ + SSL_write(ssl, msg, msgSz); + #endif + session = SSL_get_session(ssl); + sslResume = SSL_new(ctx); +#endif + + SSL_shutdown(ssl); + SSL_free(ssl); + CloseSocket(sockfd); + +#ifdef TEST_RESUME + #ifdef CYASSL_DTLS + #ifdef USE_WINDOWS_API + Sleep(500); + #else + sleep(1); + #endif + #endif + if (argc == 3) + tcp_connect(&sockfd, argv[1], (short)atoi(argv[2])); + else + tcp_connect(&sockfd, yasslIP, yasslPort); + SSL_set_fd(sslResume, sockfd); + SSL_set_session(sslResume, session); + + showPeer(sslResume); + if (SSL_connect(sslResume) != SSL_SUCCESS) err_sys("SSL resume failed"); + +#ifdef OPENSSL_EXTRA + if (SSL_session_reused(sslResume)) + printf("reused session id\n"); + else + printf("didn't reuse session id!!!\n"); +#endif + + if (SSL_write(sslResume, resumeMsg, resumeSz) != resumeSz) + err_sys("SSL_write failed"); + + input = SSL_read(sslResume, reply, sizeof(reply)); + if (input > 0) { + reply[input] = 0; + printf("Server resume response: %s\n", reply); + } + + /* try to send session break */ + SSL_write(sslResume, msg, msgSz); + + SSL_shutdown(sslResume); + SSL_free(sslResume); +#endif /* TEST_RESUME */ + + SSL_CTX_free(ctx); + CloseSocket(sockfd); + + ((func_args*)args)->return_code = 0; +} + + +/* so overall tests can pull in test function */ +#ifndef NO_MAIN_DRIVER + + int main(int argc, char** argv) + { + func_args args; + + StartTCP(); + + args.argc = argc; + args.argv = argv; + + InitCyaSSL(); +#ifdef DEBUG_CYASSL + CyaSSL_Debugging_ON(); +#endif + client_test(&args); + FreeCyaSSL(); + + return args.return_code; + } + +#endif /* NO_MAIN_DRIVER */ + + + +#ifdef CYASSL_CALLBACKS + + int handShakeCB(HandShakeInfo* info) + { + + return 0; + } + + + int timeoutCB(TimeoutInfo* info) + { + + return 0; + } + +#endif + + diff --git a/examples/client/client.sln b/examples/client/client.sln new file mode 100755 index 000000000..3c4bbb12d --- /dev/null +++ b/examples/client/client.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual C++ Express 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "client", "client.vcproj", "{F117DD21-2672-4001-9FF8-8DBEBBFCA380}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {F117DD21-2672-4001-9FF8-8DBEBBFCA380}.Debug|Win32.ActiveCfg = Debug|Win32 + {F117DD21-2672-4001-9FF8-8DBEBBFCA380}.Debug|Win32.Build.0 = Debug|Win32 + {F117DD21-2672-4001-9FF8-8DBEBBFCA380}.Release|Win32.ActiveCfg = Release|Win32 + {F117DD21-2672-4001-9FF8-8DBEBBFCA380}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/examples/client/client.vcproj b/examples/client/client.vcproj new file mode 100755 index 000000000..f5cd663fc --- /dev/null +++ b/examples/client/client.vcproj @@ -0,0 +1,197 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/echoclient/Makefile.am b/examples/echoclient/Makefile.am new file mode 100644 index 000000000..96b4f5e5c --- /dev/null +++ b/examples/echoclient/Makefile.am @@ -0,0 +1,7 @@ +INCLUDES = -I../../include -I../../include/openssl +bin_PROGRAMS = echoclient +echoclient_SOURCES = echoclient.c +echoclient_LDFLAGS = -L../../src +echoclient_LDADD = ../../src/libcyassl.la +echoclient_DEPENDENCIES= ../../src/libcyassl.la +EXTRA_DIST = input quit echoclient.sln *.vcproj diff --git a/examples/echoclient/echoclient-ntru.vcproj b/examples/echoclient/echoclient-ntru.vcproj new file mode 100755 index 000000000..fd99ced70 --- /dev/null +++ b/examples/echoclient/echoclient-ntru.vcproj @@ -0,0 +1,199 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/echoclient/echoclient.c b/examples/echoclient/echoclient.c new file mode 100644 index 000000000..66bd9fd46 --- /dev/null +++ b/examples/echoclient/echoclient.c @@ -0,0 +1,149 @@ +/* echoclient.c */ + +#include "ssl.h" +#include "cyassl_test.h" + + +void echoclient_test(void* args) +{ + SOCKET_T sockfd = 0; + + FILE* fin = stdin; + FILE* fout = stdout; + + int inCreated = 0; + int outCreated = 0; + + char send[1024]; + char reply[1024]; + + SSL_METHOD* method = 0; + SSL_CTX* ctx = 0; + SSL* ssl = 0; + + int sendSz; + int argc = 0; + char** argv = 0; + + ((func_args*)args)->return_code = -1; /* error state */ + argc = ((func_args*)args)->argc; + argv = ((func_args*)args)->argv; + + if (argc >= 2) { + fin = fopen(argv[1], "r"); + inCreated = 1; + } + if (argc >= 3) { + fout = fopen(argv[2], "w"); + outCreated = 1; + } + + if (!fin) err_sys("can't open input file"); + if (!fout) err_sys("can't open output file"); + + tcp_connect(&sockfd, yasslIP, yasslPort); + +#if defined(CYASSL_DTLS) + method = DTLSv1_client_method(); +#elif !defined(NO_TLS) + method = TLSv1_client_method(); +#else + method = SSLv3_client_method(); +#endif + ctx = SSL_CTX_new(method); + +#ifndef NO_FILESYSTEM + if (SSL_CTX_load_verify_locations(ctx, caCert, 0) != SSL_SUCCESS) + err_sys("can't load ca file"); + #ifdef HAVE_ECC + if (SSL_CTX_load_verify_locations(ctx, eccCert, 0) != SSL_SUCCESS) + err_sys("can't load ca file"); + #endif +#else + load_buffer(ctx, caCert, CYASSL_CA); +#endif + +#ifdef OPENSSL_EXTRA + SSL_CTX_set_default_passwd_cb(ctx, PasswordCallBack); +#endif + ssl = SSL_new(ctx); + + SSL_set_fd(ssl, sockfd); +#if defined(USE_WINDOWS_API) && defined(CYASSL_DTLS) && defined(NO_MAIN_DRIVER) + /* let echoserver bind first, TODO: add Windows signal like pthreads does */ + Sleep(100); +#endif + if (SSL_connect(ssl) != SSL_SUCCESS) err_sys("SSL_connect failed"); + + while (fgets(send, sizeof(send), fin)) { + + sendSz = (int)strlen(send) + 1; + + if (SSL_write(ssl, send, sendSz) != sendSz) + err_sys("SSL_write failed"); + + if (strncmp(send, "quit", 4) == 0) { + fputs("sending server shutdown command: quit!\n", fout); + break; + } + + if (strncmp(send, "break", 4) == 0) { + fputs("sending server session close: break!\n", fout); + break; + } + + while (sendSz) { + int got; + if ( (got = SSL_read(ssl, reply, sizeof(reply))) > 0) { + fputs(reply, fout); + sendSz -= got; + } + else + break; + } + } + +#ifdef CYASSL_DTLS + strncpy(send, "break", 6); + sendSz = (int)strlen(send); + /* try to tell server done */ + SSL_write(ssl, send, sendSz); +#else + SSL_shutdown(ssl); +#endif + + SSL_free(ssl); + SSL_CTX_free(ctx); + + fflush(fout); + if (inCreated) fclose(fin); + if (outCreated) fclose(fout); + + CloseSocket(sockfd); + ((func_args*)args)->return_code = 0; +} + + +/* so overall tests can pull in test function */ +#ifndef NO_MAIN_DRIVER + + int main(int argc, char** argv) + { + func_args args; + + StartTCP(); + + args.argc = argc; + args.argv = argv; + + InitCyaSSL(); + echoclient_test(&args); + FreeCyaSSL(); + + return args.return_code; + } + +#endif /* NO_MAIN_DRIVER */ + + + diff --git a/examples/echoclient/echoclient.sln b/examples/echoclient/echoclient.sln new file mode 100755 index 000000000..3fb7851d7 --- /dev/null +++ b/examples/echoclient/echoclient.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual C++ Express 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "echoclient", "echoclient.vcproj", "{A7AA93AD-AFF0-4FF0-8AED-14685DE55CF3}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {A7AA93AD-AFF0-4FF0-8AED-14685DE55CF3}.Debug|Win32.ActiveCfg = Debug|Win32 + {A7AA93AD-AFF0-4FF0-8AED-14685DE55CF3}.Debug|Win32.Build.0 = Debug|Win32 + {A7AA93AD-AFF0-4FF0-8AED-14685DE55CF3}.Release|Win32.ActiveCfg = Release|Win32 + {A7AA93AD-AFF0-4FF0-8AED-14685DE55CF3}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/examples/echoclient/echoclient.vcproj b/examples/echoclient/echoclient.vcproj new file mode 100755 index 000000000..099b47f8b --- /dev/null +++ b/examples/echoclient/echoclient.vcproj @@ -0,0 +1,197 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/echoclient/input b/examples/echoclient/input new file mode 100644 index 000000000..7364d4d0e --- /dev/null +++ b/examples/echoclient/input @@ -0,0 +1,87 @@ +/* echoclient.c */ + +#include "openssl/ssl.h" +#include "../test.h" + + +int main(int argc, char** argv) +{ + SOCKET_T sockfd = 0; + + FILE* fin = stdin; + FILE* fout = stdout; + + int inCreated = 0; + int outCreated = 0; + + char send[1024]; + char reply[1024]; + + SSL_METHOD* method = 0; + SSL_CTX* ctx = 0; + SSL* ssl = 0; + +#ifdef _WIN32 + WSADATA wsd; + WSAStartup(0x0002, &wsd); +#endif + + if (argc >= 2) { + fin = fopen(argv[1], "r"); + inCreated = 1; + } + if (argc >= 3) { + fout = fopen(argv[2], "w"); + outCreated = 1; + } + + if (!fin) err_sys("can't open input file"); + if (!fout) err_sys("can't open output file"); + + tcp_connect(&sockfd); + + method = SSLv3_client_method(); + ctx = SSL_CTX_new(method); + + if (SSL_CTX_load_verify_locations(ctx, caCert, 0) != SSL_SUCCESS) + err_sys("can't load ca file"); + + ssl = SSL_new(ctx); + + SSL_set_fd(ssl, sockfd); + if (SSL_connect(ssl) != SSL_SUCCESS) err_sys("SSL_connect failed"); + + while (fgets(send, sizeof(send), fin)) { + + int sendSz = strlen(send) + 1; + + if (SSL_write(ssl, send, sendSz) != sendSz) + err_sys("SSL_write failed"); + + if (strncmp(send, "quit", 4) == 0) { + fputs("sending server shutdown command: quit!\n", fout); + break; + } + + if (SSL_read(ssl, reply, sizeof(reply)) > 0) + fputs(reply, fout); + } + + SSL_shutdown(ssl); + SSL_free(ssl); + SSL_CTX_free(ctx); + + fflush(fout); + if (inCreated) fclose(fin); + if (outCreated) fclose(fout); + +#ifdef _WIN32 + closesocket(sockfd); +#else + close(sockfd); +#endif + + return 0; +} + + diff --git a/examples/echoclient/quit b/examples/echoclient/quit new file mode 100644 index 000000000..3db49b3ad --- /dev/null +++ b/examples/echoclient/quit @@ -0,0 +1,2 @@ +quit + diff --git a/examples/echoserver/Makefile.am b/examples/echoserver/Makefile.am new file mode 100644 index 000000000..dcb0657c3 --- /dev/null +++ b/examples/echoserver/Makefile.am @@ -0,0 +1,7 @@ +INCLUDES = -I../../include -I../../include/openssl +bin_PROGRAMS = echoserver +echoserver_SOURCES = echoserver.c +echoserver_LDFLAGS = -L../../src +echoserver_LDADD = ../../src/libcyassl.la +echoserver_DEPENDENCIES= ../../src/libcyassl.la +EXTRA_DIST = echoserver.sln *.vcproj diff --git a/examples/echoserver/echoserver-ntru.vcproj b/examples/echoserver/echoserver-ntru.vcproj new file mode 100755 index 000000000..939f2ddc7 --- /dev/null +++ b/examples/echoserver/echoserver-ntru.vcproj @@ -0,0 +1,199 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/echoserver/echoserver.c b/examples/echoserver/echoserver.c new file mode 100644 index 000000000..fa2a4acab --- /dev/null +++ b/examples/echoserver/echoserver.c @@ -0,0 +1,226 @@ +/* echoserver.c */ + +#include "ssl.h" +#include "cyassl_test.h" + +#ifndef NO_MAIN_DRIVER + #define ECHO_OUT +#endif + + +#ifdef SESSION_STATS + void PrintSessionStats(void); +#endif + + +static void SignalReady(void* args) +{ +#if defined(_POSIX_THREADS) && defined(NO_MAIN_DRIVER) + /* signal ready to tcp_accept */ + func_args* server_args = (func_args*)args; + tcp_ready* ready = server_args->signal; + pthread_mutex_lock(&ready->mutex); + ready->ready = 1; + pthread_cond_signal(&ready->cond); + pthread_mutex_unlock(&ready->mutex); +#endif +} + + +THREAD_RETURN CYASSL_API echoserver_test(void* args) +{ + SOCKET_T sockfd = 0; + SSL_METHOD* method = 0; + SSL_CTX* ctx = 0; + + int outCreated = 0; + int shutdown = 0; + int argc = ((func_args*)args)->argc; + char** argv = ((func_args*)args)->argv; + +#ifdef ECHO_OUT + FILE* fout = stdout; + if (argc >= 2) { + fout = fopen(argv[1], "w"); + outCreated = 1; + } + if (!fout) err_sys("can't open output file"); +#endif + + ((func_args*)args)->return_code = -1; /* error state */ + + tcp_listen(&sockfd); + +#if defined(CYASSL_DTLS) + method = DTLSv1_server_method(); +#elif !defined(NO_TLS) + method = SSLv23_server_method(); +#else + method = SSLv3_server_method(); +#endif + ctx = SSL_CTX_new(method); + /* SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF); */ + +#ifdef OPENSSL_EXTRA + SSL_CTX_set_default_passwd_cb(ctx, PasswordCallBack); +#endif + +#ifndef NO_FILESYSTEM + #ifdef HAVE_NTRU + /* ntru */ + if (SSL_CTX_use_certificate_file(ctx, ntruCert, SSL_FILETYPE_PEM) + != SSL_SUCCESS) + err_sys("can't load ntru cert file"); + + if (CyaSSL_CTX_use_NTRUPrivateKey_file(ctx, ntruKey) + != SSL_SUCCESS) + err_sys("can't load ntru key file"); + #elif HAVE_ECC + /* ecc */ + if (SSL_CTX_use_certificate_file(ctx, eccCert, SSL_FILETYPE_PEM) + != SSL_SUCCESS) + err_sys("can't load server cert file"); + + if (SSL_CTX_use_PrivateKey_file(ctx, eccKey, SSL_FILETYPE_PEM) + != SSL_SUCCESS) + err_sys("can't load server key file"); + #else + /* normal */ + if (SSL_CTX_use_certificate_file(ctx, svrCert, SSL_FILETYPE_PEM) + != SSL_SUCCESS) + err_sys("can't load server cert file"); + + if (SSL_CTX_use_PrivateKey_file(ctx, svrKey, SSL_FILETYPE_PEM) + != SSL_SUCCESS) + err_sys("can't load server key file"); + #endif +#else + load_buffer(ctx, svrCert, CYASSL_CERT); + load_buffer(ctx, svrKey, CYASSL_KEY); +#endif + + SignalReady(args); + + while (!shutdown) { + SSL* ssl = 0; + char command[1024]; + int echoSz = 0; + int clientfd; + +#ifndef CYASSL_DTLS + SOCKADDR_IN_T client; + socklen_t client_len = sizeof(client); + clientfd = accept(sockfd, (struct sockaddr*)&client, + (ACCEPT_THIRD_T)&client_len); +#else + clientfd = udp_read_connect(sockfd); +#endif + if (clientfd == -1) err_sys("tcp accept failed"); + + ssl = SSL_new(ctx); + if (ssl == NULL) err_sys("SSL_new failed"); + SSL_set_fd(ssl, clientfd); + if (SSL_accept(ssl) != SSL_SUCCESS) { + printf("SSL_accept failed"); + SSL_free(ssl); + CloseSocket(clientfd); + continue; + } + + while ( (echoSz = SSL_read(ssl, command, sizeof(command))) > 0) { + + if ( strncmp(command, "quit", 4) == 0) { + printf("client sent quit command: shutting down!\n"); + shutdown = 1; + break; + } + if ( strncmp(command, "break", 5) == 0) { + printf("client sent break command: closing session!\n"); + break; + } +#ifdef SESSION_STATS + if ( strncmp(command, "printstats", 10) == 0) { + PrintSessionStats(); + break; + } +#endif + if ( strncmp(command, "GET", 3) == 0) { + char type[] = "HTTP/1.0 200 ok\r\nContent-type:" + " text/html\r\n\r\n"; + char header[] = "\n

\n";
+                char body[]   = "greetings from CyaSSL\n";
+                char footer[] = "\r\n\r\n";
+            
+                strncpy(command, type, sizeof(type));
+                echoSz = sizeof(type) - 1;
+
+                strncpy(&command[echoSz], header, sizeof(header));
+                echoSz += sizeof(header) - 1;
+                strncpy(&command[echoSz], body, sizeof(body));
+                echoSz += sizeof(body) - 1;
+                strncpy(&command[echoSz], footer, sizeof(footer));
+                echoSz += sizeof(footer);
+
+                if (SSL_write(ssl, command, echoSz) != echoSz)
+                    err_sys("SSL_write failed");
+                break;
+            }
+            command[echoSz] = 0;
+
+            #ifdef ECHO_OUT
+                fputs(command, fout);
+            #endif
+
+            if (SSL_write(ssl, command, echoSz) != echoSz)
+                err_sys("SSL_write failed");
+        }
+#ifndef CYASSL_DTLS
+        SSL_shutdown(ssl);
+#endif
+        SSL_free(ssl);
+        CloseSocket(clientfd);
+#ifdef CYASSL_DTLS
+        tcp_listen(&sockfd);
+        SignalReady(args);
+#endif
+    }
+
+    CloseSocket(sockfd);
+    SSL_CTX_free(ctx);
+
+#ifdef ECHO_OUT
+    if (outCreated)
+        fclose(fout);
+#endif
+
+    ((func_args*)args)->return_code = 0;
+    return 0;
+}
+
+
+/* so overall tests can pull in test function */
+#ifndef NO_MAIN_DRIVER
+
+    int main(int argc, char** argv)
+    {
+        func_args args;
+
+        StartTCP();
+
+        args.argc = argc;
+        args.argv = argv;
+
+        InitCyaSSL();
+#ifdef DEBUG_CYASSL
+        CyaSSL_Debugging_ON();
+#endif
+        echoserver_test(&args);
+        FreeCyaSSL();
+
+        return args.return_code;
+    }
+
+#endif /* NO_MAIN_DRIVER */
+
+
+
diff --git a/examples/echoserver/echoserver.sln b/examples/echoserver/echoserver.sln
new file mode 100755
index 000000000..6bda3549c
--- /dev/null
+++ b/examples/echoserver/echoserver.sln
@@ -0,0 +1,20 @@
+
+Microsoft Visual Studio Solution File, Format Version 9.00
+# Visual C++ Express 2005
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "echoserver", "echoserver.vcproj", "{4F3F3EF1-BB95-466A-87B2-A91C059D0197}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Win32 = Debug|Win32
+		Release|Win32 = Release|Win32
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{4F3F3EF1-BB95-466A-87B2-A91C059D0197}.Debug|Win32.ActiveCfg = Debug|Win32
+		{4F3F3EF1-BB95-466A-87B2-A91C059D0197}.Debug|Win32.Build.0 = Debug|Win32
+		{4F3F3EF1-BB95-466A-87B2-A91C059D0197}.Release|Win32.ActiveCfg = Release|Win32
+		{4F3F3EF1-BB95-466A-87B2-A91C059D0197}.Release|Win32.Build.0 = Release|Win32
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+EndGlobal
diff --git a/examples/echoserver/echoserver.vcproj b/examples/echoserver/echoserver.vcproj
new file mode 100755
index 000000000..16805abd9
--- /dev/null
+++ b/examples/echoserver/echoserver.vcproj
@@ -0,0 +1,197 @@
+
+
+	
+		
+	
+	
+	
+	
+		
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+		
+		
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+		
+	
+	
+	
+	
+		
+			
+			
+		
+		
+		
+		
+		
+	
+	
+	
+
diff --git a/examples/server/Makefile.am b/examples/server/Makefile.am
new file mode 100644
index 000000000..93d3f5853
--- /dev/null
+++ b/examples/server/Makefile.am
@@ -0,0 +1,7 @@
+INCLUDES = -I../../include -I../../include/openssl
+bin_PROGRAMS    = server
+server_SOURCES  = server.c
+server_LDFLAGS      = -L../../src
+server_LDADD        = ../../src/libcyassl.la
+server_DEPENDENCIES = ../../src/libcyassl.la
+EXTRA_DIST = server.sln *.vcproj
diff --git a/examples/server/server-ntru.vcproj b/examples/server/server-ntru.vcproj
new file mode 100755
index 000000000..9f82252ce
--- /dev/null
+++ b/examples/server/server-ntru.vcproj
@@ -0,0 +1,199 @@
+
+
+	
+		
+	
+	
+	
+	
+		
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+		
+		
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+		
+	
+	
+	
+	
+		
+			
+			
+		
+		
+		
+		
+		
+	
+	
+	
+
diff --git a/examples/server/server.c b/examples/server/server.c
new file mode 100644
index 000000000..b695a38d6
--- /dev/null
+++ b/examples/server/server.c
@@ -0,0 +1,199 @@
+/* server.c */
+#include "ssl.h"
+#include "cyassl_test.h"
+
+
+#ifdef CYASSL_CALLBACKS
+    int srvHandShakeCB(HandShakeInfo*);
+    int srvTimeoutCB(TimeoutInfo*);
+    Timeval srvTo;
+#endif
+
+#if defined(NON_BLOCKING) || defined(CYASSL_CALLBACKS)
+    void NonBlockingSSL_Accept(SSL* ssl)
+    {
+    #ifndef CYASSL_CALLBACKS
+        int ret = SSL_accept(ssl);
+    #else
+        int ret = CyaSSL_accept_ex(ssl, srvHandShakeCB, srvTimeoutCB, srvTo);
+    #endif
+        int error = SSL_get_error(ssl, 0);
+        while (ret != SSL_SUCCESS && (error == SSL_ERROR_WANT_READ ||
+                                      error == SSL_ERROR_WANT_WRITE)) {
+            printf("... server would block\n");
+            #ifdef USE_WINDOWS_API 
+                Sleep(1000);
+            #else
+                sleep(1);
+            #endif
+            #ifndef CYASSL_CALLBACKS
+                ret = SSL_accept(ssl);
+            #else
+                ret = CyaSSL_accept_ex(ssl, srvHandShakeCB, srvTimeoutCB,srvTo);
+            #endif
+            error = SSL_get_error(ssl, 0);
+        }
+        if (ret != SSL_SUCCESS)
+            err_sys("SSL_accept failed");
+    }
+#endif
+
+
+THREAD_RETURN CYASSL_API server_test(void* args)
+{
+    SOCKET_T sockfd   = 0;
+    int      clientfd = 0;
+
+    SSL_METHOD* method = 0;
+    SSL_CTX*    ctx    = 0;
+    SSL*        ssl    = 0;
+
+    char msg[] = "I hear you fa shizzle!";
+    char input[1024];
+    int  idx;
+   
+    ((func_args*)args)->return_code = -1; /* error state */
+#if defined(CYASSL_DTLS)
+    method  = DTLSv1_server_method();
+#elif  !defined(NO_TLS)
+    method = TLSv1_server_method();
+#else
+    method = SSLv3_server_method();
+#endif
+    ctx    = SSL_CTX_new(method);
+
+#ifndef NO_PSK
+    SSL_CTX_set_psk_server_callback(ctx, my_psk_server_cb);
+    SSL_CTX_use_psk_identity_hint(ctx, "cyassl server");
+#endif
+
+#ifdef OPENSSL_EXTRA
+    SSL_CTX_set_default_passwd_cb(ctx, PasswordCallBack);
+#endif
+
+    SSL_CTX_set_verify(ctx,SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT,0);
+
+
+#ifndef NO_FILESYSTEM
+    /* for client auth */
+    if (SSL_CTX_load_verify_locations(ctx, cliCert, 0) != SSL_SUCCESS)
+        err_sys("can't load ca file");
+
+    #ifdef HAVE_ECC
+        if (SSL_CTX_use_certificate_file(ctx, eccCert, SSL_FILETYPE_PEM)
+                != SSL_SUCCESS)
+            err_sys("can't load server ecc cert file");
+
+        if (SSL_CTX_use_PrivateKey_file(ctx, eccKey, SSL_FILETYPE_PEM)
+                != SSL_SUCCESS)
+            err_sys("can't load server ecc key file");
+    #elif HAVE_NTRU
+        if (SSL_CTX_use_certificate_file(ctx, ntruCert, SSL_FILETYPE_PEM)
+                != SSL_SUCCESS)
+            err_sys("can't load ntru cert file");
+
+        if (CyaSSL_CTX_use_NTRUPrivateKey_file(ctx, ntruKey)
+                != SSL_SUCCESS)
+            err_sys("can't load ntru key file");
+    #else  /* normal */
+        if (SSL_CTX_use_certificate_file(ctx, svrCert, SSL_FILETYPE_PEM)
+                != SSL_SUCCESS)
+            err_sys("can't load server cert file");
+
+        if (SSL_CTX_use_PrivateKey_file(ctx, svrKey, SSL_FILETYPE_PEM)
+                != SSL_SUCCESS)
+            err_sys("can't load server key file");
+    #endif /* NTRU */
+#else
+    load_buffer(ctx, cliCert, CYASSL_CA);
+    load_buffer(ctx, svrCert, CYASSL_CERT);
+    load_buffer(ctx, svrKey,  CYASSL_KEY);
+#endif /* NO_FILESYSTEM */
+
+    ssl = SSL_new(ctx);
+    tcp_accept(&sockfd, &clientfd, (func_args*)args);
+#ifndef CYASSL_DTLS
+    CloseSocket(sockfd);
+#endif
+
+    SSL_set_fd(ssl, clientfd);
+
+#ifdef NON_BLOCKING
+    tcp_set_nonblocking(&clientfd);
+    NonBlockingSSL_Accept(ssl);
+#else
+    #ifndef CYASSL_CALLBACKS
+        if (SSL_accept(ssl) != SSL_SUCCESS) {
+            int err = SSL_get_error(ssl, 0);
+            char buffer[80];
+            printf("error = %d, %s\n", err, ERR_error_string(err, buffer));
+            err_sys("SSL_accept failed");
+        }
+    #else
+        NonBlockingSSL_Accept(ssl);
+    #endif
+#endif
+    showPeer(ssl);
+
+    idx = SSL_read(ssl, input, sizeof(input));
+    if (idx > 0) {
+        input[idx] = 0;
+        printf("Client message: %s\n", input);
+    }
+    
+    if (SSL_write(ssl, msg, sizeof(msg)) != sizeof(msg))
+        err_sys("SSL_write failed");
+
+    SSL_shutdown(ssl);
+    SSL_free(ssl);
+    SSL_CTX_free(ctx);
+    
+    CloseSocket(clientfd);
+    ((func_args*)args)->return_code = 0;
+    return 0;
+}
+
+
+/* so overall tests can pull in test function */
+#ifndef NO_MAIN_DRIVER
+
+    int main(int argc, char** argv)
+    {
+        func_args args;
+
+        StartTCP();
+
+        args.argc = argc;
+        args.argv = argv;
+
+        InitCyaSSL();
+#ifdef DEBUG_CYASSL
+        CyaSSL_Debugging_ON();
+#endif
+        server_test(&args);
+        FreeCyaSSL();
+
+        return args.return_code;
+    }
+
+#endif /* NO_MAIN_DRIVER */
+
+
+#ifdef CYASSL_CALLBACKS
+
+    int srvHandShakeCB(HandShakeInfo* info)
+    {
+
+        return 0;
+    }
+
+
+    int srvTimeoutCB(TimeoutInfo* info)
+    {
+
+        return 0;
+    }
+
+#endif
+
+
diff --git a/examples/server/server.sln b/examples/server/server.sln
new file mode 100755
index 000000000..7c9de3020
--- /dev/null
+++ b/examples/server/server.sln
@@ -0,0 +1,20 @@
+
+Microsoft Visual Studio Solution File, Format Version 9.00
+# Visual C++ Express 2005
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "server", "server.vcproj", "{13A60276-EFB2-4D3F-AFC3-D66E4C4CC27B}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Win32 = Debug|Win32
+		Release|Win32 = Release|Win32
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{13A60276-EFB2-4D3F-AFC3-D66E4C4CC27B}.Debug|Win32.ActiveCfg = Debug|Win32
+		{13A60276-EFB2-4D3F-AFC3-D66E4C4CC27B}.Debug|Win32.Build.0 = Debug|Win32
+		{13A60276-EFB2-4D3F-AFC3-D66E4C4CC27B}.Release|Win32.ActiveCfg = Release|Win32
+		{13A60276-EFB2-4D3F-AFC3-D66E4C4CC27B}.Release|Win32.Build.0 = Release|Win32
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+EndGlobal
diff --git a/examples/server/server.vcproj b/examples/server/server.vcproj
new file mode 100755
index 000000000..556bd5970
--- /dev/null
+++ b/examples/server/server.vcproj
@@ -0,0 +1,197 @@
+
+
+	
+		
+	
+	
+	
+	
+		
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+		
+		
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+		
+	
+	
+	
+	
+		
+			
+			
+		
+		
+		
+		
+		
+	
+	
+	
+
diff --git a/include/cyassl_error.h b/include/cyassl_error.h
new file mode 100644
index 000000000..02eab6908
--- /dev/null
+++ b/include/cyassl_error.h
@@ -0,0 +1,117 @@
+/* cyassl_error.h
+ *
+ * Copyright (C) 2006-2011 Sawtooth Consulting Ltd.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * CyaSSL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+
+
+#ifndef CYASSL_ERROR_H
+#define CYASSL_ERROR_H
+
+#include "error.h"   /* CTaoCrypt errors */
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+enum CyaSSL_ErrorCodes {
+    PREFIX_ERROR           = -202,            /* bad index to key rounds  */
+    MEMORY_ERROR           = -203,            /* out of memory            */
+    VERIFY_FINISHED_ERROR  = -204,            /* verify problem on finished */
+    VERIFY_MAC_ERROR       = -205,            /* verify mac problem       */
+    PARSE_ERROR            = -206,            /* parse error on header    */
+    UNKNOWN_HANDSHAKE_TYPE = -207,            /* weird handshake type     */
+    SOCKET_ERROR_E         = -208,            /* error state on socket    */
+    SOCKET_NODATA          = -209,            /* expected data, not there */
+    INCOMPLETE_DATA        = -210,            /* don't have enough data to 
+                                                 complete task            */
+    UNKNOWN_RECORD_TYPE    = -211,            /* unknown type in record hdr */
+    DECRYPT_ERROR          = -212,            /* error during decryption  */
+    FATAL_ERROR            = -213,            /* revcd alert fatal error  */
+    ENCRYPT_ERROR          = -214,            /* error during encryption  */
+    FREAD_ERROR            = -215,            /* fread problem            */
+    NO_PEER_KEY            = -216,            /* need peer's key          */
+    NO_PRIVATE_KEY         = -217,            /* need the private key     */
+    RSA_PRIVATE_ERROR      = -218,            /* error during rsa priv op */
+    BUILD_MSG_ERROR        = -220,            /* build message failure    */
+
+    BAD_HELLO              = -221,            /* client hello malformed   */
+    DOMAIN_NAME_MISMATCH   = -222,            /* peer subject name mismatch */
+    WANT_READ              = -223,            /* want read, call again    */
+    NOT_READY_ERROR        = -224,            /* handshake layer not ready */
+    PMS_VERSION_ERROR      = -225,            /* pre m secret version error */
+    VERSION_ERROR          = -226,            /* record layer version error */
+    WANT_WRITE             = -227,            /* want write, call again   */
+    BUFFER_ERROR           = -228,            /* malformed buffer input   */
+    VERIFY_CERT_ERROR      = -229,            /* verify cert error        */
+    VERIFY_SIGN_ERROR      = -230,            /* verify sign error        */
+    CLIENT_ID_ERROR        = -231,            /* psk client identity error  */
+    SERVER_HINT_ERROR      = -232,            /* psk server hint error  */
+    PSK_KEY_ERROR          = -233,            /* psk key error  */
+    ZLIB_INIT_ERROR        = -234,            /* zlib init error  */
+    ZLIB_COMPRESS_ERROR    = -235,            /* zlib compression error  */
+    ZLIB_DECOMPRESS_ERROR  = -236,            /* zlib decompression error  */
+
+    GETTIME_ERROR          = -237,            /* gettimeofday failed ??? */
+    GETITIMER_ERROR        = -238,            /* getitimer failed ??? */
+    SIGACT_ERROR           = -239,            /* sigaction failed ??? */
+    SETITIMER_ERROR        = -240,            /* setitimer failed ??? */
+    LENGTH_ERROR           = -241,            /* record layer length error */
+    PEER_KEY_ERROR         = -242,            /* cant decode peer key */
+    ZERO_RETURN            = -243,            /* peer sent close notify */
+    SIDE_ERROR             = -244,            /* wrong client/server type */
+    NO_PEER_CERT           = -245,            /* peer didn't send key */
+    NTRU_KEY_ERROR         = -246,            /* NTRU key error  */
+    NTRU_DRBG_ERROR        = -247,            /* NTRU drbg error  */
+    NTRU_ENCRYPT_ERROR     = -248,            /* NTRU encrypt error  */
+    NTRU_DECRYPT_ERROR     = -249,            /* NTRU decrypt error  */
+    ECC_CURVETYPE_ERROR    = -250,            /* Bad ECC Curve Type */
+    ECC_CURVE_ERROR        = -251,            /* Bad ECC Curve */
+    ECC_PEERKEY_ERROR      = -252,            /* Bad Peer ECC Key */
+    ECC_MAKEKEY_ERROR      = -253,            /* Bad Make ECC Key */
+    ECC_EXPORT_ERROR       = -254,            /* Bad ECC Export Key */
+    ECC_SHARED_ERROR       = -255,            /* Bad ECC Shared Secret */
+    /* add strings to SetErrorString !!!!! */
+
+    /* begin negotiation parameter errors */
+    UNSUPPORTED_SUITE      = -260,            /* unsupported cipher suite */
+    MATCH_SUITE_ERROR      = -261             /* can't match cipher suite */
+    /* end   negotiation parameter errors only 10 for now */
+    /* add strings to SetErrorString !!!!! */
+};
+
+
+#ifdef CYASSL_CALLBACKS
+    enum {
+        MIN_PARAM_ERR = UNSUPPORTED_SUITE,
+        MAX_PARAM_ERR = MIN_PARAM_ERR - 10
+    };
+#endif
+
+
+void SetErrorString(int error, char* buffer);
+
+
+#ifdef __cplusplus
+    }  /* extern "C" */
+#endif
+
+
+#endif /* CyaSSL_ERROR_H */
+
diff --git a/include/cyassl_int.h b/include/cyassl_int.h
new file mode 100644
index 000000000..857ad4056
--- /dev/null
+++ b/include/cyassl_int.h
@@ -0,0 +1,1214 @@
+/* cyassl_int.h
+ *
+ * Copyright (C) 2006-2011 Sawtooth Consulting Ltd.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * CyaSSL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+
+
+#ifndef CYASSL_INT_H
+#define CYASSL_INT_H
+
+
+#include "types.h"
+#include "random.h"
+#include "des3.h"
+#include "hc128.h"
+#include "rabbit.h"
+#include "asn.h"
+#include "ctc_md5.h"
+#include "ctc_aes.h"
+#ifdef HAVE_ECC
+    #include "ctc_ecc.h"
+#endif
+
+#ifdef CYASSL_CALLBACKS
+    #include "cyassl_callbacks.h"
+    #include 
+#endif
+
+#ifdef USE_WINDOWS_API 
+    #include 
+#elif defined(THREADX)
+    #ifndef SINGLE_THREADED
+        #include "tx_api.h"
+    #endif
+#elif defined(MICRIUM)
+    /* do nothing, just don't pick Unix */
+#else
+    #ifndef SINGLE_THREADED
+        #define CYASSL_PTHREADS
+        #include 
+    #endif
+    #if defined(OPENSSL_EXTRA) || defined(GOAHEAD_WS)
+        #include       /* for close of BIO */
+    #endif
+#endif
+
+#ifdef HAVE_LIBZ
+    #include "zlib.h"
+#endif
+
+#ifdef _MSC_VER
+    /* 4996 warning to use MS extensions e.g., strcpy_s instead of strncpy */
+    #pragma warning(disable: 4996)
+#endif
+
+#ifdef NO_AES
+    #if !defined (ALIGN16)
+        #define ALIGN16
+    #endif
+#endif
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+
+#ifdef USE_WINDOWS_API 
+    typedef unsigned int SOCKET_T;
+#else
+    typedef int SOCKET_T;
+#endif
+
+
+typedef byte word24[3];
+
+/* Define or comment out the cipher suites you'd like to be compiled in
+   make sure to use at least one BUILD_SSL_xxx or BUILD_TLS_xxx is defined
+
+   When adding cipher suites, add name to cipher_names, idx to cipher_name_idx
+*/
+#ifndef NO_RC4
+    #define BUILD_SSL_RSA_WITH_RC4_128_SHA
+    #define BUILD_SSL_RSA_WITH_RC4_128_MD5
+    #if !defined(NO_TLS) && defined(HAVE_NTRU)
+        #define BUILD_TLS_NTRU_RSA_WITH_RC4_128_SHA
+    #endif
+#endif
+
+#ifndef NO_DES3
+    #define BUILD_SSL_RSA_WITH_3DES_EDE_CBC_SHA
+    #if !defined(NO_TLS) && defined(HAVE_NTRU)
+        #define BUILD_TLS_NTRU_RSA_WITH_3DES_EDE_CBC_SHA
+    #endif
+#endif
+
+#if !defined(NO_AES) && !defined(NO_TLS)
+    #define BUILD_TLS_RSA_WITH_AES_128_CBC_SHA
+    #define BUILD_TLS_RSA_WITH_AES_256_CBC_SHA
+    #if !defined (NO_PSK)
+        #define BUILD_TLS_PSK_WITH_AES_128_CBC_SHA
+        #define BUILD_TLS_PSK_WITH_AES_256_CBC_SHA
+    #endif
+    #if defined(HAVE_NTRU)
+        #define BUILD_TLS_NTRU_RSA_WITH_AES_128_CBC_SHA
+        #define BUILD_TLS_NTRU_RSA_WITH_AES_256_CBC_SHA
+    #endif
+#endif
+
+#if !defined(NO_HC128) && !defined(NO_TLS)
+    #define BUILD_TLS_RSA_WITH_HC_128_CBC_MD5
+    #define BUILD_TLS_RSA_WITH_HC_128_CBC_SHA
+#endif
+
+#if !defined(NO_RABBIT) && !defined(NO_TLS)
+    #define BUILD_TLS_RSA_WITH_RABBIT_CBC_SHA
+#endif
+
+#if !defined(NO_DH) && !defined(NO_AES) && !defined(NO_TLS) && defined(OPENSSL_EXTRA)
+    #define BUILD_TLS_DHE_RSA_WITH_AES_128_CBC_SHA
+    #define BUILD_TLS_DHE_RSA_WITH_AES_256_CBC_SHA
+#endif
+
+#if defined(HAVE_ECC) && !defined(NO_TLS)
+    #if !defined(NO_AES)
+        #define BUILD_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
+        #define BUILD_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
+        #define BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA
+        #define BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
+    #endif
+    #if !defined(NO_RC4)
+        #define BUILD_TLS_ECDHE_RSA_WITH_RC4_128_SHA
+        #define BUILD_TLS_ECDHE_ECDSA_WITH_RC4_128_SHA
+    #endif
+    #if !defined(NO_DES3)
+        #define BUILD_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA
+        #define BUILD_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA
+    #endif
+#endif
+
+
+#if defined(BUILD_SSL_RSA_WITH_RC4_128_SHA) || \
+    defined(BUILD_SSL_RSA_WITH_RC4_128_MD5)
+    #define BUILD_ARC4
+#endif
+
+#if defined(BUILD_SSL_RSA_WITH_3DES_EDE_CBC_SHA)
+    #define BUILD_DES3
+#endif
+
+#if defined(BUILD_TLS_RSA_WITH_AES_128_CBC_SHA) || \
+    defined(BUILD_TLS_RSA_WITH_AES_256_CBC_SHA)
+    #define BUILD_AES
+#endif
+
+#if defined(BUILD_TLS_RSA_WITH_HC_128_CBC_SHA) || \
+    defined(BUILD_TLS_RSA_WITH_HC_128_CBC_MD5)
+    #define BUILD_HC128
+#endif
+
+#if defined(BUILD_TLS_RSA_WITH_RABBIT_CBC_SHA)
+    #define BUILD_RABBIT
+#endif
+
+#ifdef NO_DES3
+    #define DES_BLOCK_SIZE 8
+#endif
+
+#ifdef NO_AES
+    #define AES_BLOCK_SIZE 16
+#endif
+
+
+/* actual cipher values, 2nd byte */
+enum {
+    TLS_DHE_RSA_WITH_AES_256_CBC_SHA  = 0x39,
+    TLS_DHE_RSA_WITH_AES_128_CBC_SHA  = 0x33,
+    TLS_RSA_WITH_AES_256_CBC_SHA      = 0x35,
+    TLS_RSA_WITH_AES_128_CBC_SHA      = 0x2F,
+    TLS_PSK_WITH_AES_256_CBC_SHA      = 0x8d,
+    TLS_PSK_WITH_AES_128_CBC_SHA      = 0x8c,
+    SSL_RSA_WITH_RC4_128_SHA          = 0x05,
+    SSL_RSA_WITH_RC4_128_MD5          = 0x04,
+    SSL_RSA_WITH_3DES_EDE_CBC_SHA     = 0x0A,
+
+    /* ECC suites, first byte is 0xC0 (ECC_BYTE) */
+    TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA    = 0x14,
+    TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA    = 0x13,
+    TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA  = 0x0A,
+    TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA  = 0x09,
+    TLS_ECDHE_RSA_WITH_RC4_128_SHA        = 0x11,
+    TLS_ECDHE_ECDSA_WITH_RC4_128_SHA      = 0x07,
+    TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA   = 0x12,
+    TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA = 0x08,
+
+    /* CyaSSL extension - eSTREAM */
+    TLS_RSA_WITH_HC_128_CBC_MD5       = 0xFB,
+    TLS_RSA_WITH_HC_128_CBC_SHA       = 0xFC,
+    TLS_RSA_WITH_RABBIT_CBC_SHA       = 0xFD,
+
+    /* CyaSSL extension - NTRU */
+    TLS_NTRU_RSA_WITH_RC4_128_SHA      = 0x65,
+    TLS_NTRU_RSA_WITH_3DES_EDE_CBC_SHA = 0x66,
+    TLS_NTRU_RSA_WITH_AES_128_CBC_SHA  = 0x67,
+    TLS_NTRU_RSA_WITH_AES_256_CBC_SHA  = 0x68
+};
+
+
+enum Misc {
+    SERVER_END = 0,
+    CLIENT_END,
+
+    ECC_BYTE =  0xC0,           /* ECC first cipher suite byte */
+
+    SEND_CERT       = 1,
+    SEND_BLANK_CERT = 2,
+
+    DTLS_MAJOR      = 0xfe,     /* DTLS major version number */
+    DTLS_MINOR      = 0xff,     /* DTLS minor version number */
+    SSLv3_MAJOR     = 3,        /* SSLv3 and TLSv1+  major version number */
+    SSLv3_MINOR     = 0,        /* TLSv1   minor version number */
+    TLSv1_MINOR     = 1,        /* TLSv1   minor version number */
+    TLSv1_1_MINOR   = 2,        /* TLSv1_1 minor version number */
+    TLSv1_2_MINOR   = 3,        /* TLSv1_2 minor version number */
+    NO_COMPRESSION  =  0,
+    ZLIB_COMPRESSION = 221,     /* CyaSSL zlib compression */
+    SECRET_LEN      = 48,       /* pre RSA and all master */
+    ENCRYPT_LEN     = 256,      /* allow 2048 bit static buffer */
+    SIZEOF_SENDER   =  4,       /* clnt or srvr           */
+    FINISHED_SZ     = MD5_DIGEST_SIZE + SHA_DIGEST_SIZE,
+    MAX_RECORD_SIZE = 16384,    /* 2^14, max size by standard */
+    MAX_UDP_SIZE    = 1400,     /* don't exceed MTU */
+    MAX_MSG_EXTRA   = 68,       /* max added to msg, mac + pad */
+    MAX_COMP_EXTRA  = 1024,     /* max compression extra */
+    MAX_MTU         = 1500,     /* max expected MTU */
+    MAX_DH_SZ       = 612,      /* 2240 p, pub, g + 2 byte size for each */
+    MAX_STR_VERSION = 8,        /* string rep of protocol version */
+
+    PAD_MD5        = 48,       /* pad length for finished */
+    PAD_SHA        = 40,       /* pad length for finished */
+    PEM_LINE_LEN   = 80,       /* PEM line max + fudge */
+    LENGTH_SZ      =  2,       /* length field for HMAC, data only */
+    VERSION_SZ     =  2,       /* length of proctocol version */
+    SEQ_SZ         =  8,       /* 64 bit sequence number  */
+    BYTE3_LEN      =  3,       /* up to 24 bit byte lengths */
+    ALERT_SIZE     =  2,       /* level + description     */
+    REQUEST_HEADER =  2,       /* always use 2 bytes      */
+    VERIFY_HEADER  =  2,       /* always use 2 bytes      */
+
+    MAX_SUITE_SZ = 200,        /* 100 suites for now! */
+    RAN_LEN      = 32,         /* random length           */
+    SEED_LEN     = RAN_LEN * 2, /* tls prf seed length    */
+    ID_LEN       = 32,         /* session id length       */
+    MAX_COOKIE_LEN = 32,       /* max dtls cookie size    */
+    SUITE_LEN    =  2,         /* cipher suite sz length  */
+    ENUM_LEN     =  1,         /* always a byte           */
+    COMP_LEN     =  1,         /* compression length      */
+    CURVE_LEN    =  2,         /* ecc named curve length  */
+    
+    HANDSHAKE_HEADER_SZ = 4,   /* type + length(3)        */
+    RECORD_HEADER_SZ    = 5,   /* type + version + len(2) */
+    CERT_HEADER_SZ      = 3,   /* always 3 bytes          */
+    REQ_HEADER_SZ       = 2,   /* cert request header sz  */
+    HINT_LEN_SZ         = 2,   /* length of hint size field */
+
+    DTLS_HANDSHAKE_HEADER_SZ = 12, /* normal + seq(2) + offset(3) + length(3) */
+    DTLS_RECORD_HEADER_SZ    = 13, /* normal + epoch(2) + seq_num(6) */
+    DTLS_HANDSHAKE_EXTRA     = 8,  /* diff from normal */
+    DTLS_RECORD_EXTRA        = 8,  /* diff from normal */
+
+    FINISHED_LABEL_SZ   = 15,  /* TLS finished label size */
+    TLS_FINISHED_SZ     = 12,  /* TLS has a shorter size  */
+    MASTER_LABEL_SZ     = 13,  /* TLS master secret label sz */
+    KEY_LABEL_SZ        = 13,  /* TLS key block expansion sz */
+    MAX_PRF_HALF        = 128, /* Maximum half secret len */
+    MAX_PRF_LABSEED     = 80,  /* Maximum label + seed len */
+    MAX_PRF_DIG         = 148, /* Maximum digest len      */
+    MAX_REQUEST_SZ      = 256, /* Maximum cert req len (no auth yet */
+    SESSION_FLUSH_COUNT = 256, /* Flush session cache unless user turns off */ 
+
+    RC4_KEY_SIZE        = 16,  /* always 128bit           */
+    DES_KEY_SIZE        =  8,  /* des                     */
+    DES3_KEY_SIZE       = 24,  /* 3 des ede               */
+    DES_IV_SIZE         = DES_BLOCK_SIZE,
+    AES_256_KEY_SIZE    = 32,  /* for 256 bit             */
+    AES_192_KEY_SIZE    = 24,  /* for 192 bit             */
+    AES_IV_SIZE         = 16,  /* always block size       */
+    AES_128_KEY_SIZE    = 16,  /* for 128 bit             */
+
+    HC_128_KEY_SIZE     = 16,  /* 128 bits                */
+    HC_128_IV_SIZE      = 16,  /* also 128 bits           */
+
+    RABBIT_KEY_SIZE     = 16,  /* 128 bits                */
+    RABBIT_IV_SIZE      =  8,  /* 64 bits for iv          */
+
+    EVP_SALT_SIZE       =  8,  /* evp salt size 64 bits   */
+
+    ECDHE_SIZE          = 32,  /* ECHDE server size defaults to 256 bit */
+    MAX_EXPORT_ECC_SZ   = 256, /* Export ANS X9.62 max future size */
+
+    MAX_HELLO_SZ       = 128,  /* max client or server hello */
+    MAX_CERT_VERIFY_SZ = 1024, /* max   */
+    CLIENT_HELLO_FIRST =  35,  /* Protocol + RAN_LEN + sizeof(id_len) */
+    MAX_SUITE_NAME     =  48,  /* maximum length of cipher suite string */
+    DEFAULT_TIMEOUT    = 500,  /* default resumption timeout in seconds */
+
+    MAX_PSK_ID_LEN     = 128,  /* max psk identity/hint supported */
+    MAX_PSK_KEY_LEN    =  64,  /* max psk key supported */
+
+    MAX_CHAIN_DEPTH    =   4,  /* max cert chain peer depth */
+    MAX_X509_SIZE      = 2048, /* max static x509 buffer size */
+    FILE_BUFFER_SIZE   = 1024, /* default static file buffer size for input,
+                                  will use dynamic buffer if not big enough */
+
+    MAX_NTRU_PUB_KEY_SZ = 1027, /* NTRU max for now */
+    MAX_NTRU_ENCRYPT_SZ = 1027, /* NTRU max for now */
+    MAX_NTRU_BITS       =  256, /* max symmetric bit strength */
+    NO_SNIFF           =   0,  /* not sniffing */
+    SNIFF              =   1,  /* currently sniffing */
+
+    NO_COPY            =   0,  /* should we copy static buffer for write */
+    COPY               =   1   /* should we copy static buffer for write */
+};
+
+
+/* states */
+enum states {
+    NULL_STATE = 0,
+
+    SERVER_HELLOVERIFYREQUEST_COMPLETE,
+    SERVER_HELLO_COMPLETE,
+    SERVER_CERT_COMPLETE,
+    SERVER_KEYEXCHANGE_COMPLETE,
+    SERVER_HELLODONE_COMPLETE,
+    SERVER_FINISHED_COMPLETE,
+
+    CLIENT_HELLO_COMPLETE,
+    CLIENT_KEYEXCHANGE_COMPLETE,
+    CLIENT_FINISHED_COMPLETE,
+
+    HANDSHAKE_DONE
+};
+
+
+#ifndef SSL_TYPES_DEFINED
+    typedef struct SSL_METHOD  SSL_METHOD;
+    typedef struct SSL_CTX     SSL_CTX;
+    typedef struct SSL_SESSION SSL_SESSION;
+    typedef struct SSL_CIPHER  SSL_CIPHER;
+    typedef struct SSL         SSL;
+    typedef struct X509        X509;
+    typedef struct X509_CHAIN  X509_CHAIN;
+    typedef struct BIO         BIO;
+    typedef struct BIO_METHOD  BIO_METHOD;
+
+    #undef X509_NAME
+    typedef struct X509_NAME   X509_NAME;
+
+    typedef struct X509_STORE_CTX {
+        int   error;
+        int   error_depth;
+        X509* current_cert;          /* stunnel dereference */
+        char* domain;                /* subject CN domain name */
+    } X509_STORE_CTX;
+
+
+    typedef int (*pem_password_cb)(char*, int, int, void*);
+    typedef int (*CallbackIORecv)(char *buf, int sz, void *ctx);
+    typedef int (*CallbackIOSend)(char *buf, int sz, void *ctx);
+    typedef int (*VerifyCallback)(int, X509_STORE_CTX*);
+
+    /* make sure external "C" linkage for C++ programs with callbacks */
+    void CyaSSL_SetIORecv(SSL_CTX*, CallbackIORecv);
+    void CyaSSL_SetIOSend(SSL_CTX*, CallbackIOSend);
+
+    void CyaSSL_SetIOReadCtx(SSL* ssl, void *ctx);
+    void CyaSSL_SetIOWriteCtx(SSL* ssl, void *ctx);
+#endif /* SSL_TYPES_DEFINED */
+
+
+/* SSL Version */
+typedef struct ProtocolVersion {
+    byte major;
+    byte minor;
+} ProtocolVersion;
+
+
+ProtocolVersion MakeSSLv3(void);
+ProtocolVersion MakeTLSv1(void);
+ProtocolVersion MakeTLSv1_1(void);
+ProtocolVersion MakeTLSv1_2(void);
+
+#ifdef CYASSL_DTLS
+    ProtocolVersion MakeDTLSv1(void);
+#endif
+
+
+enum BIO_TYPE {
+    BIO_BUFFER = 1,
+    BIO_SOCKET = 2,
+    BIO_SSL    = 3
+};
+
+
+/* OpenSSL BIO_METHOD type */
+struct BIO_METHOD {
+    byte type;               /* method type */
+};
+
+
+/* OpenSSL BIO type */
+struct BIO {
+    byte type;          /* method type */
+    byte close;         /* close flag */
+    byte eof;           /* eof flag */
+    SSL* ssl;           /* possible associated ssl */
+    int  fd;            /* possible file descriptor */
+    BIO* prev;          /* previous in chain */
+    BIO* next;          /* next in chain */
+};
+
+
+/* OpenSSL method type */
+struct SSL_METHOD {
+    ProtocolVersion version;
+    int             side;         /* connection side, server or client */
+    int             verifyPeer;   /* request or send certificate       */
+    int             verifyNone;   /* whether to verify certificate     */
+    int             failNoCert;   /* fail if no certificate            */
+    int             downgrade;    /* whether to downgrade version, default no */
+};
+
+
+/* defautls to client */
+void InitSSL_Method(SSL_METHOD*, ProtocolVersion);
+
+/* for sniffer */
+int DoFinished(SSL* ssl, const byte* input, word32* inOutIdx, int sniff);
+int DoApplicationData(SSL* ssl, byte* input, word32* inOutIdx);
+
+
+/* CyaSSL buffer type */
+typedef struct buffer {
+    word32 length;
+    byte*  buffer;
+} buffer;
+
+
+enum {
+    FORCED_FREE = 1,
+    NO_FORCED_FREE = 0
+};
+
+
+/* only use compression extra if using compression */
+#ifdef HAVE_LIBZ
+    #define COMP_EXTRA MAX_COMP_EXTRA
+#else
+    #define COMP_EXTRA 0
+#endif
+
+/* only the sniffer needs space in the buffer for an extra MTU record */
+#ifdef CYASSL_SNIFFER
+    #define MTU_EXTRA MAX_MTU
+#else
+    #define MTU_EXTRA 0
+#endif
+
+/* give user option to use 16K static buffers, sniffer needs them too */
+#if defined(LARGE_STATIC_BUFFERS) || defined(CYASSL_SNIFFER)
+    #define RECORD_SIZE MAX_RECORD_SIZE
+#else
+    #ifdef CYASSL_DTLS
+        #define RECORD_SIZE 1500
+    #else
+        #define RECORD_SIZE 128 
+    #endif
+#endif
+
+
+/* user option to turn off 16K output option */
+/* if using small static buffers (default) and SSL_write tries to write data
+   larger than the record we have, dynamically get it, unless user says only
+   write in static buffer chuncks  */
+#ifndef STATIC_CHUNKS_ONLY
+    #define OUTPUT_RECORD_SIZE MAX_RECORD_SIZE
+#else
+    #define OUTPUT_RECORD_SIZE RECORD_SIZE
+#endif
+
+/* CyaSSL input buffer
+
+   RFC 2246:
+
+   length
+       The length (in bytes) of the following TLSPlaintext.fragment.
+       The length should not exceed 2^14.
+*/
+#define STATIC_BUFFER_LEN RECORD_HEADER_SZ + RECORD_SIZE + COMP_EXTRA + \
+        MTU_EXTRA + MAX_MSG_EXTRA
+
+typedef struct {
+    word32 length;       /* total buffer length used */
+    word32 idx;          /* idx to part of length already consumed */
+    byte*  buffer;       /* place holder for static or dynamic buffer */
+    ALIGN16 byte staticBuffer[STATIC_BUFFER_LEN];
+    word32 bufferSize;   /* current buffer size */
+    byte   dynamicFlag;  /* dynamic memory currently in use */
+} bufferStatic;
+
+/* Cipher Suites holder */
+typedef struct Suites {
+    int    setSuites;               /* user set suites from default */
+    byte   suites[MAX_SUITE_SZ];  
+    word16 suiteSz;                 /* suite length in bytes        */
+} Suites;
+
+
+void InitSuites(Suites*, ProtocolVersion, byte, byte, byte, byte, int);
+int  SetCipherList(SSL_CTX* ctx, const char* list);
+
+#ifndef PSK_TYPES_DEFINED
+    typedef unsigned int (*psk_client_callback)(SSL*, const char*, char*,
+                          unsigned int, unsigned char*, unsigned int);
+    typedef unsigned int (*psk_server_callback)(SSL*, const char*,
+                          unsigned char*, unsigned int);
+#endif /* PSK_TYPES_DEFINED */
+
+
+#ifndef CYASSL_USER_IO
+    /* default IO callbacks */
+    int EmbedReceive(char *buf, int sz, void *ctx);
+    int EmbedSend(char *buf, int sz, void *ctx);
+#endif
+
+#ifdef CYASSL_DTLS
+    int IsUDP(void*);
+#endif
+
+
+/* OpenSSL Cipher type just points back to SSL */
+struct SSL_CIPHER {
+    SSL* ssl;
+};
+
+
+/* OpenSSL context type */
+struct SSL_CTX {
+    SSL_METHOD* method;
+    buffer      certificate;
+    buffer      privateKey;
+    Signer*     caList;           /* SSL_CTX owns this, SSL will reference */
+    Suites      suites;
+    void*       heap;             /* for user memory overrides */
+    byte        verifyPeer;
+    byte        verifyNone;
+    byte        failNoCert;
+    byte        sessionCacheOff;
+    byte        sessionCacheFlushOff;
+    byte        sendVerify;       /* for client side */
+    byte        haveDH;           /* server DH parms set by user */
+    byte        haveNTRU;         /* server private NTRU  key loaded */
+    byte        haveECDSA;        /* server private ECDSA key loaded */
+    byte        partialWrite;     /* only one msg per write call */
+    byte        quietShutdown;    /* don't send close notify */
+    CallbackIORecv CBIORecv;
+    CallbackIOSend CBIOSend;
+    VerifyCallback verifyCallback;      /* cert verification callback */
+#ifndef NO_PSK
+    byte        havePSK;                /* psk key set by user */
+    psk_client_callback client_psk_cb;  /* client callback */
+    psk_server_callback server_psk_cb;  /* server callback */
+    char        server_hint[MAX_PSK_ID_LEN];
+#endif /* NO_PSK */
+#ifdef OPENSSL_EXTRA
+    pem_password_cb passwd_cb;
+    void*            userdata;
+#endif /* OPENSSL_EXTRA */
+};
+
+
+void InitSSL_Ctx(SSL_CTX*, SSL_METHOD*);
+void FreeSSL_Ctx(SSL_CTX*);
+void SSL_CtxResourceFree(SSL_CTX*);
+
+int DeriveTlsKeys(SSL* ssl);
+int ProcessOldClientHello(SSL* ssl, const byte* input, word32* inOutIdx,
+                          word32 inSz, word16 sz);
+
+/* All cipher suite related info */
+typedef struct CipherSpecs {
+    byte bulk_cipher_algorithm;
+    byte cipher_type;               /* block or stream */
+    byte mac_algorithm;
+    byte kea;                       /* key exchange algo */
+    byte sig_algo;
+    byte hash_size;
+    byte pad_size;
+    word16 key_size;
+    word16 iv_size;
+    word16 block_size;
+} CipherSpecs;
+
+
+
+/* Supported Ciphers from page 43  */
+enum BulkCipherAlgorithm { 
+    cipher_null,
+    rc4,
+    rc2,
+    des,
+    triple_des,             /* leading 3 (3des) not valid identifier */
+    des40,
+    idea,
+    aes,
+    hc128,                  /* CyaSSL extensions */
+    rabbit
+};
+
+
+/* Supported Message Authentication Codes from page 43 */
+enum MACAlgorithm { 
+    no_mac,
+    md5_mac,
+    sha_mac,
+    rmd_mac,
+    sha256_mac
+};
+
+
+/* Supported Key Exchange Protocols */
+enum KeyExchangeAlgorithm { 
+    no_kea = 0,
+    rsa_kea, 
+    diffie_hellman_kea, 
+    fortezza_kea,
+    psk_kea,
+    ntru_kea,
+    ecc_diffie_hellman_kea
+};
+
+
+/* Supported Authentication Schemes */
+enum SignatureAlgorithm {
+    anonymous_sa_algo = 0,
+    rsa_sa_algo,
+    dsa_sa_algo,
+    ecc_dsa_sa_algo
+};
+
+
+/* Supprted ECC Curve Types */
+enum EccCurves {
+    named_curve = 3
+};
+
+
+/* Supprted ECC Named Curves */
+enum EccNamedCurves {
+    secp256r1 = 0x17,         /* default, OpenSSL also calls it prime256v1 */
+    secp384r1 = 0x18,
+    secp521r1 = 0x19,
+
+    secp160r1 = 0x10,
+    secp192r1 = 0x13,        /*           Openssl also call it prime192v1 */
+    secp224r1 = 0x15
+};
+
+
+/* Valid client certificate request types from page 27 */
+enum ClientCertificateType {    
+    rsa_sign            = 1, 
+    dss_sign            = 2,
+    rsa_fixed_dh        = 3,
+    dss_fixed_dh        = 4,
+    rsa_ephemeral_dh    = 5,
+    dss_ephemeral_dh    = 6,
+    fortezza_kea_cert   = 20
+};
+
+
+enum CipherType { stream, block };
+
+
+/* keys and secrets */
+typedef struct Keys {
+    byte client_write_MAC_secret[SHA_DIGEST_SIZE];   /* max sizes */
+    byte server_write_MAC_secret[SHA_DIGEST_SIZE]; 
+    byte client_write_key[AES_256_KEY_SIZE];         /* max sizes */
+    byte server_write_key[AES_256_KEY_SIZE]; 
+    byte client_write_IV[AES_IV_SIZE];               /* max sizes */
+    byte server_write_IV[AES_IV_SIZE];
+
+    word32 peer_sequence_number;
+    word32 sequence_number;
+    
+#ifdef CYASSL_DTLS
+    word32 dtls_sequence_number;
+    word32 dtls_peer_sequence_number;
+    word16 dtls_handshake_number;
+    word16 dtls_epoch;
+    word16 dtls_peer_epoch;
+#endif
+
+    word32 encryptSz;             /* last size of encrypted data   */
+    byte   encryptionOn;          /* true after change cipher spec */
+} Keys;
+
+
+/* cipher for now */
+typedef union {
+#ifdef BUILD_ARC4
+    Arc4   arc4;
+#endif
+#ifdef BUILD_DES3
+    Des3   des3;
+#endif
+#ifdef BUILD_AES
+    Aes    aes;
+#endif
+#ifdef BUILD_HC128
+    HC128  hc128;
+#endif
+#ifdef BUILD_RABBIT
+    Rabbit rabbit;
+#endif
+} Ciphers;
+
+
+/* hashes type */
+typedef struct Hashes {
+    byte md5[MD5_DIGEST_SIZE];
+    byte sha[SHA_DIGEST_SIZE];
+} Hashes;
+
+
+/* Static x509 buffer */
+typedef struct x509_buffer {
+    int  length;                  /* actual size */
+    byte buffer[MAX_X509_SIZE];   /* max static cert size */
+} x509_buffer;
+
+
+/* CyaSSL X509_CHAIN, for no dynamic memory SESSION_CACHE */
+struct X509_CHAIN {
+    int         count;                    /* total number in chain */
+    x509_buffer certs[MAX_CHAIN_DEPTH];   /* only allow max depth 4 for now */
+};
+
+
+/* openSSL session type */
+struct SSL_SESSION {
+    byte         sessionID[ID_LEN];
+    byte         masterSecret[SECRET_LEN];
+    word32       bornOn;                        /* create time in seconds   */
+    word32       timeout;                       /* timeout in seconds       */
+#ifdef SESSION_CERTS
+    X509_CHAIN      chain;                      /* peer cert chain, static  */
+    ProtocolVersion version;
+    byte            cipherSuite0;               /* first byte, normally 0 */
+    byte            cipherSuite;                /* 2nd byte, actual suite */
+#endif
+};
+
+
+SSL_SESSION* GetSession(SSL*, byte*);
+int          SetSession(SSL*, SSL_SESSION*);
+
+typedef void (*hmacfp) (SSL*, byte*, const byte*, word32, int, int);
+
+
+/* client connect state for nonblocking restart */
+enum ConnectState {
+    CONNECT_BEGIN = 0,
+    CLIENT_HELLO_SENT,
+    HELLO_AGAIN,               /* HELLO_AGAIN s for DTLS case */
+    HELLO_AGAIN_REPLY,
+    FIRST_REPLY_DONE,
+    FIRST_REPLY_FIRST,
+    FIRST_REPLY_SECOND,
+    FIRST_REPLY_THIRD,
+    FIRST_REPLY_FOURTH,
+    FINISHED_DONE,
+    SECOND_REPLY_DONE
+};
+
+
+/* server accpet state for nonblocking restart */
+enum AcceptState {
+    ACCEPT_BEGIN = 0,
+    ACCEPT_CLIENT_HELLO_DONE,
+    HELLO_VERIFY_SENT,
+    ACCEPT_FIRST_REPLY_DONE,
+    SERVER_HELLO_SENT,
+    CERT_SENT,
+    KEY_EXCHANGE_SENT,
+    CERT_REQ_SENT,
+    SERVER_HELLO_DONE,
+    ACCEPT_SECOND_REPLY_DONE,
+    CHANGE_CIPHER_SENT,
+    ACCEPT_FINISHED_DONE,
+    ACCEPT_THIRD_REPLY_DONE
+};
+
+
+typedef struct Buffers {
+    buffer          certificate;            /* SSL_CTX owns */
+    buffer          key;                    /* SSL_CTX owns */
+    buffer          domainName;             /* for client check */
+    buffer          serverDH_P;
+    buffer          serverDH_G;
+    buffer          serverDH_Pub;
+    buffer          serverDH_Priv;
+    bufferStatic    inputBuffer;
+    bufferStatic    outputBuffer;
+    buffer          clearOutputBuffer;
+    int             prevSent;              /* previous plain text bytes sent
+                                              when got WANT_WRITE            */
+    int             plainSz;               /* plain text bytes in buffer to send
+                                              when got WANT_WRITE            */
+} Buffers;
+
+
+typedef struct Options {
+    byte            sessionCacheOff;
+    byte            sessionCacheFlushOff;
+    byte            cipherSuite0;           /* first byte, normally 0 */
+    byte            cipherSuite;            /* second byte, actual suite */
+    byte            serverState;
+    byte            clientState;
+    byte            handShakeState;
+    byte            side;               /* client or server end */
+    byte            verifyPeer;
+    byte            verifyNone;
+    byte            failNoCert;
+    byte            downgrade;          /* allow downgrade of versions */
+    byte            sendVerify;         /* false = 0, true = 1, sendBlank = 2 */
+    byte            resuming;
+    byte            tls;                /* using TLS ? */
+    byte            tls1_1;             /* using TLSv1.1+ ? */
+    byte            dtls;               /* using datagrams ? */
+    byte            connReset;          /* has the peer reset */
+    byte            isClosed;           /* if we consider conn closed */
+    byte            closeNotify;        /* we've recieved a close notify */
+    byte            sentNotify;         /* we've sent a close notify */
+    byte            connectState;       /* nonblocking resume */
+    byte            acceptState;        /* nonblocking resume */
+    byte            usingCompression;   /* are we using compression */
+    byte            haveDH;             /* server DH parms set by user */
+    byte            haveNTRU;           /* server NTRU  private key loaded */
+    byte            haveECDSA;          /* server ECDSA private key loaded */
+    byte            havePeerCert;       /* do we have peer's cert */
+    byte            usingPSK_cipher;    /* whether we're using psk as cipher */
+    byte            sendAlertState;     /* nonblocking resume */ 
+    byte            processReply;       /* nonblocking resume */
+    byte            partialWrite;       /* only one msg per write call */
+    byte            quietShutdown;      /* don't send close notify */
+#ifndef NO_PSK
+    byte            havePSK;            /* psk key set by user */
+    psk_client_callback client_psk_cb;
+    psk_server_callback server_psk_cb;
+#endif /* NO_PSK */
+} Options;
+
+
+typedef struct Arrays {
+    byte            clientRandom[RAN_LEN];
+    byte            serverRandom[RAN_LEN];
+    byte            sessionID[ID_LEN];
+    byte            preMasterSecret[ENCRYPT_LEN];
+    byte            masterSecret[SECRET_LEN];
+#ifdef CYASSL_DTLS
+    byte            cookie[MAX_COOKIE_LEN];
+#endif
+#ifndef NO_PSK
+    char            client_identity[MAX_PSK_ID_LEN];
+    char            server_hint[MAX_PSK_ID_LEN];
+    byte            psk_key[MAX_PSK_KEY_LEN];
+    word32          psk_keySz;          /* acutal size */
+#endif
+    word32          preMasterSz;        /* differs for DH, actual size */
+} Arrays;
+
+
+#undef X509_NAME
+
+struct X509_NAME {
+    char  name[ASN_NAME_MAX];
+    int   sz;
+};
+
+
+struct X509 {
+    X509_NAME issuer;
+    X509_NAME subject;
+};
+
+
+/* record layer header for PlainText, Compressed, and CipherText */
+typedef struct RecordLayerHeader {
+    byte            type;
+    ProtocolVersion version;
+    byte            length[2];
+} RecordLayerHeader;
+
+
+/* record layer header for DTLS PlainText, Compressed, and CipherText */
+typedef struct DtlsRecordLayerHeader {
+    byte            type;
+    ProtocolVersion version;
+    byte            epoch[2];             /* increment on cipher state change */
+    byte            sequence_number[6];   /* per record */
+    byte            length[2];
+} DtlsRecordLayerHeader;
+
+
+/* OpenSSL ssl type */
+struct SSL {
+    SSL_CTX*        ctx;
+    int             error;
+    ProtocolVersion version;            /* negotiated version */
+    ProtocolVersion chVersion;          /* client hello version */
+    Suites          suites;
+    Ciphers         encrypt;
+    Ciphers         decrypt;
+    CipherSpecs     specs;
+    Keys            keys;
+    int             rfd;                /* read  file descriptor */
+    int             wfd;                /* write file descriptor */
+    BIO*            biord;              /* socket bio read  to free/close */
+    BIO*            biowr;              /* socket bio write to free/close */
+    void*           IOCB_ReadCtx;
+    void*           IOCB_WriteCtx;
+    RNG             rng;
+    Md5             hashMd5;            /* md5 hash of handshake msgs */
+    Sha             hashSha;            /* sha hash of handshake msgs */
+    Hashes          verifyHashes;
+    Hashes          certHashes;         /* for cert verify */
+    Signer*         caList;             /* SSL_CTX owns */
+    Buffers         buffers;
+    Options         options;
+    Arrays          arrays;
+    SSL_SESSION     session;
+    RsaKey          peerRsaKey;
+    byte            peerRsaKeyPresent;
+#ifdef HAVE_NTRU
+    word16          peerNtruKeyLen;
+    byte            peerNtruKey[MAX_NTRU_PUB_KEY_SZ];
+    byte            peerNtruKeyPresent;
+#endif
+#ifdef HAVE_ECC
+    ecc_key         peerEccKey;              /* peer's  ECDHE key */
+    byte            peerEccKeyPresent;
+    ecc_key         peerEccDsaKey;           /* peer's  ECDSA key */
+    byte            peerEccDsaKeyPresent;
+    ecc_key         eccTempKey;              /* private ECDHE key */
+    byte            eccTempKeyPresent;
+    ecc_key         eccDsaKey;               /* private ECDSA key */
+    byte            eccDsaKeyPresent;
+#endif
+    hmacfp          hmac;
+    void*           heap;               /* for user overrides */
+    RecordLayerHeader curRL;
+    word16            curSize;
+    SSL_CIPHER      cipher;
+#ifdef HAVE_LIBZ
+    z_stream        c_stream;           /* compression   stream */
+    z_stream        d_stream;           /* decompression stream */
+    byte            didStreamInit;      /* for stream init and end */
+#endif
+#ifdef CYASSL_CALLBACKS
+    HandShakeInfo   handShakeInfo;      /* info saved during handshake */
+    TimeoutInfo     timeoutInfo;        /* info saved during handshake */
+    byte            hsInfoOn;           /* track handshake info        */
+    byte            toInfoOn;           /* track timeout   info        */
+#endif
+#ifdef OPENSSL_EXTRA
+    X509            peerCert;           /* X509 peer cert */
+#endif
+};
+
+
+int  InitSSL(SSL*, SSL_CTX*);
+void FreeSSL(SSL*);
+void SSL_ResourceFree(SSL*);
+
+
+enum {
+    IV_SZ   = 32,          /* max iv sz */
+    NAME_SZ = 80,          /* max one line */
+};
+
+
+typedef struct EncryptedInfo {
+    char   name[NAME_SZ];
+    byte   iv[IV_SZ];
+    word32 ivSz;
+    byte   set;
+} EncryptedInfo;
+
+
+#ifdef CYASSL_CALLBACKS
+    void InitHandShakeInfo(HandShakeInfo*);
+    void FinishHandShakeInfo(HandShakeInfo*, const SSL*);
+    void AddPacketName(const char*, HandShakeInfo*);
+
+    void InitTimeoutInfo(TimeoutInfo*);
+    void FreeTimeoutInfo(TimeoutInfo*, void*);
+    void AddPacketInfo(const char*, TimeoutInfo*, const byte*, int, void*);
+    void AddLateName(const char*, TimeoutInfo*);
+    void AddLateRecordHeader(const RecordLayerHeader* rl, TimeoutInfo* info);
+#endif
+
+
+/* Record Layer Header identifier from page 12 */
+enum ContentType {
+    no_type            = 0,
+    change_cipher_spec = 20, 
+    alert              = 21, 
+    handshake          = 22, 
+    application_data   = 23 
+};
+
+
+/* handshake header, same for each message type, pgs 20/21 */
+typedef struct HandShakeHeader {
+    byte            type;
+    word24          length;
+} HandShakeHeader;
+
+
+/* DTLS handshake header, same for each message type */
+typedef struct DtlsHandShakeHeader {
+    byte            type;
+    word24          length;
+    byte            message_seq[2];    /* start at 0, restransmit gets same # */
+    word24          fragment_offset;   /* bytes in previous fragments */
+    word24          fragment_length;   /* length of this fragment */
+} DtlsHandShakeHeader;
+
+
+enum HandShakeType {
+    no_shake            = -1,
+    hello_request       = 0, 
+    client_hello        = 1, 
+    server_hello        = 2,
+    hello_verify_request = 3,       /* DTLS addition */
+    certificate         = 11, 
+    server_key_exchange = 12,
+    certificate_request = 13, 
+    server_hello_done   = 14,
+    certificate_verify  = 15, 
+    client_key_exchange = 16,
+    finished            = 20
+};
+
+
+/* Valid Alert types from page 16/17 */
+enum AlertDescription {
+    close_notify            = 0,
+    unexpected_message      = 10,
+    bad_record_mac          = 20,
+    decompression_failure   = 30,
+    handshake_failure       = 40,
+    no_certificate          = 41,
+    bad_certificate         = 42,
+    unsupported_certificate = 43,
+    certificate_revoked     = 44,
+    certificate_expired     = 45,
+    certificate_unknown     = 46,
+    illegal_parameter       = 47,
+    decrypt_error           = 51
+};
+
+
+/* I/O Callback default errors */
+enum IOerrors {
+    IO_ERR_GENERAL    = -1,     /* general unexpected err, not in below group */
+    IO_ERR_WANT_READ  = -2,     /* need to call read  again */
+    IO_ERR_WANT_WRITE = -2,     /* need to call write again */
+    IO_ERR_CONN_RST   = -3,     /* connection reset */
+    IO_ERR_ISR        = -4,     /* interrupt */
+    IO_ERR_CONN_CLOSE = -5      /* connection closed or epipe */
+};
+
+
+enum AlertLevel { 
+    alert_warning = 1, 
+    alert_fatal = 2
+};
+
+
+static const byte client[SIZEOF_SENDER] = { 0x43, 0x4C, 0x4E, 0x54 };
+static const byte server[SIZEOF_SENDER] = { 0x53, 0x52, 0x56, 0x52 };
+
+static const byte tls_client[FINISHED_LABEL_SZ + 1] = "client finished";
+static const byte tls_server[FINISHED_LABEL_SZ + 1] = "server finished";
+
+
+/* internal functions */
+int SendChangeCipher(SSL*);
+int SendData(SSL*, const void*, int);
+int SendCertificate(SSL*);
+int SendCertificateRequest(SSL*);
+int SendServerKeyExchange(SSL*);
+int SendBuffered(SSL*);
+int ReceiveData(SSL*, byte*, int);
+int SendFinished(SSL*);
+int SendAlert(SSL*, int, int);
+int ProcessReply(SSL*);
+
+int SetCipherSpecs(SSL*);
+int MakeMasterSecret(SSL*);
+
+int  AddSession(SSL*);
+int  DeriveKeys(SSL* ssl);
+int  StoreKeys(SSL* ssl, const byte* keyData);
+
+int IsTLS(const SSL* ssl);
+int IsAtLeastTLSv1_2(const SSL* ssl);
+
+void ShrinkInputBuffer(SSL* ssl, int forcedFree);
+void ShrinkOutputBuffer(SSL* ssl);
+
+#ifndef NO_CYASSL_CLIENT
+    int SendClientHello(SSL*);
+    int SendClientKeyExchange(SSL*);
+    int SendCertificateVerify(SSL*);
+#endif /* NO_CYASSL_CLIENT */
+
+#ifndef NO_CYASSL_SERVER
+    int SendServerHello(SSL*);
+    int SendServerHelloDone(SSL*);
+    #ifdef CYASSL_DTLS
+        int SendHelloVerifyRequest(SSL*);
+    #endif
+#endif /* NO_CYASSL_SERVER */
+
+
+#ifndef NO_TLS
+    
+
+#endif /* NO_TLS */
+
+
+
+typedef double timer_d;
+
+timer_d Timer(void);
+word32  LowResTimer(void);
+
+
+#ifdef SINGLE_THREADED
+    typedef int CyaSSL_Mutex;
+#else /* MULTI_THREADED */
+    #ifdef USE_WINDOWS_API 
+        typedef CRITICAL_SECTION CyaSSL_Mutex;
+    #elif defined(CYASSL_PTHREADS)
+        typedef pthread_mutex_t CyaSSL_Mutex;
+    #elif defined(THREADX)
+        typedef TX_MUTEX CyaSSL_Mutex;
+    #elif defined(MICRIUM)
+        typedef OS_MUTEX CyaSSL_Mutex;
+    #else
+        #error Need a mutex type in multithreaded mode
+    #endif /* USE_WINDOWS_API */
+#endif /* SINGLE_THREADED */
+
+int InitMutex(CyaSSL_Mutex*);
+int FreeMutex(CyaSSL_Mutex*);
+int LockMutex(CyaSSL_Mutex*);
+int UnLockMutex(CyaSSL_Mutex*);
+
+
+#ifdef DEBUG_CYASSL
+
+    void CYASSL_ENTER(const char* msg);
+    void CYASSL_LEAVE(const char* msg, int ret);
+
+    void CYASSL_ERROR(int);
+    void CYASSL_MSG(const char* msg);
+
+#else /* DEBUG_CYASSL   */
+
+    #define CYASSL_ENTER(m)
+    #define CYASSL_LEAVE(m, r)
+
+    #define CYASSL_ERROR(e) 
+    #define CYASSL_MSG(m)
+
+#endif /* DEBUG_CYASSL  */
+
+
+#ifdef __cplusplus
+    }  /* extern "C" */
+#endif
+
+#endif /* CyaSSL_INT_H */
+
diff --git a/include/openssl/asn1.h b/include/openssl/asn1.h
new file mode 100644
index 000000000..3f34d7d2c
--- /dev/null
+++ b/include/openssl/asn1.h
@@ -0,0 +1,2 @@
+/* asn1.h for openssl */
+
diff --git a/include/openssl/bio.h b/include/openssl/bio.h
new file mode 100644
index 000000000..bbdcc0f2b
--- /dev/null
+++ b/include/openssl/bio.h
@@ -0,0 +1,2 @@
+/* bio.h for openssl */
+
diff --git a/include/openssl/bn.h b/include/openssl/bn.h
new file mode 100644
index 000000000..39770e990
--- /dev/null
+++ b/include/openssl/bn.h
@@ -0,0 +1,2 @@
+/* bn.h for openssl */
+
diff --git a/include/openssl/conf.h b/include/openssl/conf.h
new file mode 100644
index 000000000..1e328cf47
--- /dev/null
+++ b/include/openssl/conf.h
@@ -0,0 +1,2 @@
+/* conf.h for openssl */
+
diff --git a/include/openssl/crypto.h b/include/openssl/crypto.h
new file mode 100644
index 000000000..603943bc1
--- /dev/null
+++ b/include/openssl/crypto.h
@@ -0,0 +1,19 @@
+/* crypto.h for openSSL */
+
+#ifndef CYASSL_CRYPTO_H_
+#define CYASSL_CRYPTO_H_
+
+#ifdef YASSL_PREFIX
+#include "prefix_crypto.h"
+#endif
+
+const char*   SSLeay_version(int type);
+unsigned long SSLeay(void);
+
+
+#define SSLEAY_VERSION 0x0090600fL
+#define SSLEAY_VERSION_NUMBER SSLEAY_VERSION
+
+
+#endif /* header */
+
diff --git a/include/openssl/cyassl_callbacks.h b/include/openssl/cyassl_callbacks.h
new file mode 100644
index 000000000..87998aa2d
--- /dev/null
+++ b/include/openssl/cyassl_callbacks.h
@@ -0,0 +1,81 @@
+/* cyassl_callbacks.h
+ *
+ * Copyright (C) 2011 Sawtooth Consulting Ltd.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * CyaSSL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+
+
+#ifndef CYASSL_CALLBACKS_H
+#define CYASSL_CALLBACKS_H
+
+#include 
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+
+enum { /* CALLBACK CONTSTANTS */
+    MAX_PACKETNAME_SZ     =  24,
+    MAX_CIPHERNAME_SZ     =  24,
+    MAX_TIMEOUT_NAME_SZ   =  24,       
+    MAX_PACKETS_HANDSHAKE =  14,       /* 12 for client auth plus 2 alerts */
+    MAX_VALUE_SZ          = 128,       /* all handshake packets but Cert should
+                                          fit here  */
+};
+
+
+typedef struct handShakeInfo_st {
+    char   cipherName[MAX_CIPHERNAME_SZ + 1];    /* negotiated cipher */
+    char   packetNames[MAX_PACKETS_HANDSHAKE][MAX_PACKETNAME_SZ + 1];
+                                                 /* SSL packet names  */ 
+    int    numberPackets;                        /* actual # of packets */
+    int    negotiationError;                     /* cipher/parameter err */
+} HandShakeInfo;
+
+
+typedef struct timeval Timeval;
+
+
+typedef struct packetInfo_st {
+    char           packetName[MAX_PACKETNAME_SZ + 1]; /* SSL packet name */
+    Timeval        timestamp;                       /* when it occured    */
+    unsigned char  value[MAX_VALUE_SZ];             /* if fits, it's here */ 
+    unsigned char* bufferValue;                     /* otherwise here (non 0) */
+    int            valueSz;                         /* sz of value or buffer */
+} PacketInfo;
+
+
+typedef struct timeoutInfo_st {
+    char       timeoutName[MAX_TIMEOUT_NAME_SZ + 1]; /* timeout Name */
+    int        flags;                              /* for future use */
+    int        numberPackets;                      /* actual # of packets */
+    PacketInfo packets[MAX_PACKETS_HANDSHAKE];     /* list of all packets  */
+    Timeval    timeoutValue;                       /* timer that caused it */
+} TimeoutInfo;
+
+
+
+#ifdef __cplusplus
+    }  /* extern "C" */
+#endif
+
+
+#endif /* CyaSSL_CALLBACKS_H */
+
diff --git a/include/openssl/cyassl_test.h b/include/openssl/cyassl_test.h
new file mode 100644
index 000000000..555f3e19c
--- /dev/null
+++ b/include/openssl/cyassl_test.h
@@ -0,0 +1,563 @@
+/* cyassl_test.h */
+
+#ifndef CyaSSL_TEST_H
+#define CyaSSL_TEST_H
+
+#include 
+#include 
+#include 
+#include 
+#include "types.h"
+
+#ifdef USE_WINDOWS_API 
+    #include 
+    #include 
+    #ifdef TEST_IPV6            /* don't require newer SDK for IPV4 */
+	    #include 
+        #include 
+    #endif
+    #define SOCKET_T int
+#else
+    #include 
+    #include 
+    #include 
+    #include 
+    #include 
+    #include 
+    #include 
+    #include 
+    #include 
+    #include 
+    #include 
+    #ifdef NON_BLOCKING
+        #include 
+    #endif
+    #ifdef TEST_IPV6
+        #include 
+    #endif
+    #define SOCKET_T unsigned int
+#endif /* USE_WINDOWS_API */
+
+#ifdef _MSC_VER
+    /* disable conversion warning */
+    /* 4996 warning to use MS extensions e.g., strcpy_s instead of strncpy */
+    #pragma warning(disable:4244 4996)
+#endif
+
+#if defined(__MACH__) || defined(USE_WINDOWS_API)
+    #ifndef _SOCKLEN_T
+        typedef int socklen_t;
+    #endif
+#endif
+
+
+/* HPUX doesn't use socklent_t for third parameter to accept */
+#if !defined(__hpux__)
+    typedef socklen_t* ACCEPT_THIRD_T;
+#else
+    typedef int*       ACCEPT_THIRD_T;
+#endif
+
+
+#ifdef USE_WINDOWS_API 
+    #define CloseSocket(s) closesocket(s)
+    #define StartTCP() { WSADATA wsd; WSAStartup(0x0002, &wsd); }
+#else
+    #define CloseSocket(s) close(s)
+    #define StartTCP() 
+#endif
+
+
+#ifdef SINGLE_THREADED
+    typedef unsigned int  THREAD_RETURN;
+    typedef void*         THREAD_TYPE;
+    #define CYASSL_API
+#else
+    #ifndef _POSIX_THREADS
+        typedef unsigned int  THREAD_RETURN;
+        typedef HANDLE        THREAD_TYPE;
+        #define CYASSL_API __stdcall
+    #else
+        typedef void*         THREAD_RETURN;
+        typedef pthread_t     THREAD_TYPE;
+        #define CYASSL_API 
+    #endif
+#endif
+
+
+#ifdef TEST_IPV6
+    typedef struct sockaddr_in6 SOCKADDR_IN_T;
+    #define AF_INET_V    AF_INET6
+#else
+    typedef struct sockaddr_in  SOCKADDR_IN_T;
+    #define AF_INET_V    AF_INET
+#endif
+   
+
+#ifndef NO_MAIN_DRIVER
+    const char* caCert   = "../../certs/ca-cert.pem";
+    const char* eccCert  = "../../certs/server-ecc.pem";
+    const char* eccKey   = "../../certs/ecc-key.pem";
+    const char* svrCert  = "../../certs/server-cert.pem";
+    const char* svrKey   = "../../certs/server-key.pem";
+    const char* cliCert  = "../../certs/client-cert.pem";
+    const char* cliKey   = "../../certs/client-key.pem";
+    const char* ntruCert = "../../certs/ntru-cert.pem";
+    const char* ntruKey  = "../../certs/ntru-key.raw";
+#else
+    static const char* caCert   = "../certs/ca-cert.pem";
+    static const char* eccCert  = "../certs/server-ecc.pem";
+    static const char* eccKey   = "../certs/ecc-key.pem";
+    static const char* svrCert  = "../certs/server-cert.pem";
+    static const char* svrKey   = "../certs/server-key.pem";
+    static const char* cliCert  = "../certs/client-cert.pem";
+    static const char* cliKey   = "../certs/client-key.pem";
+    static const char* ntruCert = "../certs/ntru-cert.pem";
+    static const char* ntruKey  = "../certs/ntru-key.raw";
+#endif
+
+typedef struct tcp_ready {
+    int ready;              /* predicate */
+#ifdef _POSIX_THREADS
+    pthread_mutex_t mutex;
+    pthread_cond_t  cond;
+#endif
+} tcp_ready;    
+
+
+void InitTcpReady();
+void FreeTcpReady();
+
+
+typedef struct func_args {
+    int    argc;
+    char** argv;
+    int    return_code;
+    tcp_ready* signal;
+} func_args;
+
+
+typedef THREAD_RETURN CYASSL_API THREAD_FUNC(void*);
+
+void start_thread(THREAD_FUNC, func_args*, THREAD_TYPE*);
+void join_thread(THREAD_TYPE);
+
+/* yaSSL */
+static const char* const yasslIP   = "127.0.0.1";
+static const word16      yasslPort = 11111;
+
+
+static INLINE void err_sys(const char* msg)
+{
+    printf("yassl error: %s\n", msg);
+    exit(EXIT_FAILURE);
+}
+
+
+#ifdef OPENSSL_EXTRA
+
+static int PasswordCallBack(char* passwd, int sz, int rw, void* userdata)
+{
+    strncpy(passwd, "yassl123", sz);
+    return 8;
+}
+
+#endif
+
+
+static INLINE void showPeer(SSL* ssl)
+{
+#ifdef OPENSSL_EXTRA
+
+    SSL_CIPHER* cipher;
+    X509*       peer = SSL_get_peer_certificate(ssl);
+    if (peer) {
+        char* issuer  = X509_NAME_oneline(X509_get_issuer_name(peer), 0, 0);
+        char* subject = X509_NAME_oneline(X509_get_subject_name(peer), 0, 0);
+        
+        printf("peer's cert info:\n issuer : %s\n subject: %s\n", issuer,
+                                                                  subject);
+        XFREE(subject, 0, DYNAMIC_TYPE_OPENSSL);
+        XFREE(issuer,  0, DYNAMIC_TYPE_OPENSSL);
+    }
+    else
+        printf("peer has no cert!\n");
+    printf("SSL version is %s\n", SSL_get_version(ssl));
+
+    cipher = SSL_get_current_cipher(ssl);
+    printf("SSL cipher suite is %s\n", SSL_CIPHER_get_name(cipher));
+#endif
+
+#ifdef SESSION_CERTS
+    {
+        X509_CHAIN* chain = CyaSSL_get_peer_chain(ssl);
+        int         count = CyaSSL_get_chain_count(chain);
+        int i;
+
+        for (i = 0; i < count; i++) {
+            int length;
+            unsigned char buffer[3072];
+
+            CyaSSL_get_chain_cert_pem(chain,i,buffer, sizeof(buffer), &length);
+            buffer[length] = 0;
+            printf("cert %d has length %d data = \n%s\n", i, length, buffer);
+        }
+    }
+#endif
+
+}
+
+
+static INLINE void tcp_socket(SOCKET_T* sockfd, SOCKADDR_IN_T* addr,
+                              const char* peer, word16 port)
+{
+#ifndef TEST_IPV6
+    const char* host = peer;
+
+    /* peer could be in human readable form */
+    if (peer != INADDR_ANY && isalpha(peer[0])) {
+        struct hostent* entry = gethostbyname(peer);
+
+        if (entry) {
+            struct sockaddr_in tmp;
+            memset(&tmp, 0, sizeof(struct sockaddr_in));
+            memcpy(&tmp.sin_addr.s_addr, entry->h_addr_list[0],
+                   entry->h_length);
+            host = inet_ntoa(tmp.sin_addr);
+        }
+        else
+            err_sys("no entry for host");
+    }
+#endif
+
+#ifdef CYASSL_DTLS
+    *sockfd = socket(AF_INET_V, SOCK_DGRAM, 0);
+#else
+    *sockfd = socket(AF_INET_V, SOCK_STREAM, 0);
+#endif
+    memset(addr, 0, sizeof(SOCKADDR_IN_T));
+
+#ifndef TEST_IPV6
+    addr->sin_family = AF_INET_V;
+    addr->sin_port = htons(port);
+    if (host == INADDR_ANY)
+        addr->sin_addr.s_addr = INADDR_ANY;
+    else
+        addr->sin_addr.s_addr = inet_addr(host);
+#else
+    addr->sin6_family = AF_INET_V;
+    addr->sin6_port = htons(port);
+    addr->sin6_addr = in6addr_loopback;
+#endif
+
+#ifndef USE_WINDOWS_API 
+#ifdef SO_NOSIGPIPE
+    {
+        int       on = 1;
+        socklen_t len = sizeof(on);
+        int       res = setsockopt(*sockfd, SOL_SOCKET, SO_NOSIGPIPE, &on, len);
+        if (res < 0)
+            err_sys("setsockopt SO_NOSIGPIPE failed\n");
+    }
+#endif
+
+#if defined(TCP_NODELAY) && !defined(CYASSL_DTLS)
+    {
+        int       on = 1;
+        socklen_t len = sizeof(on);
+        int       res = setsockopt(*sockfd, IPPROTO_TCP, TCP_NODELAY, &on, len);
+        if (res < 0)
+            err_sys("setsockopt TCP_NODELAY failed\n");
+    }
+#endif
+#endif  /* USE_WINDOWS_API */
+}
+
+
+static INLINE void tcp_connect(SOCKET_T* sockfd, const char* ip, word16 port)
+{
+    SOCKADDR_IN_T addr;
+    tcp_socket(sockfd, &addr, ip, port);
+
+    if (connect(*sockfd, (const struct sockaddr*)&addr, sizeof(addr)) != 0)
+        err_sys("tcp connect failed");
+}
+
+
+static INLINE void tcp_listen(SOCKET_T* sockfd)
+{
+    SOCKADDR_IN_T addr;
+
+    /* don't use INADDR_ANY by default, firewall may block, make user switch
+       on */
+#ifdef USE_ANY_ADDR
+    tcp_socket(sockfd, &addr, INADDR_ANY, yasslPort);
+#else
+    tcp_socket(sockfd, &addr, yasslIP, yasslPort);
+#endif
+
+#ifndef USE_WINDOWS_API 
+    {
+        int       on  = 1;
+        socklen_t len = sizeof(on);
+        setsockopt(*sockfd, SOL_SOCKET, SO_REUSEADDR, &on, len);
+    }
+#endif
+
+    if (bind(*sockfd, (const struct sockaddr*)&addr, sizeof(addr)) != 0)
+        err_sys("tcp bind failed");
+#ifndef CYASSL_DTLS
+    if (listen(*sockfd, 5) != 0)
+        err_sys("tcp listen failed");
+#endif
+}
+
+
+static INLINE int udp_read_connect(SOCKET_T sockfd)
+{
+    SOCKADDR_IN_T cliaddr;
+    byte          b[1500];
+    int           n;
+    socklen_t     len = sizeof(cliaddr);
+
+    n = recvfrom(sockfd, b, sizeof(b), MSG_PEEK, (struct sockaddr*)&cliaddr,
+                 &len);
+    if (n > 0) {
+        if (connect(sockfd, (const struct sockaddr*)&cliaddr,
+                    sizeof(cliaddr)) != 0)
+            err_sys("udp connect failed");
+    }
+    else
+        err_sys("recvfrom failed");
+
+    return sockfd;
+}
+
+static INLINE void udp_accept(SOCKET_T* sockfd, int* clientfd, func_args* args)
+{
+    SOCKADDR_IN_T addr;
+
+    tcp_socket(sockfd, &addr, yasslIP, yasslPort);
+
+
+#ifndef USE_WINDOWS_API 
+    {
+        int       on  = 1;
+        socklen_t len = sizeof(on);
+        setsockopt(*sockfd, SOL_SOCKET, SO_REUSEADDR, &on, len);
+    }
+#endif
+
+    if (bind(*sockfd, (const struct sockaddr*)&addr, sizeof(addr)) != 0)
+        err_sys("tcp bind failed");
+
+#if defined(_POSIX_THREADS) && defined(NO_MAIN_DRIVER)
+    /* signal ready to accept data */
+    {
+    tcp_ready* ready = args->signal;
+    pthread_mutex_lock(&ready->mutex);
+    ready->ready = 1;
+    pthread_cond_signal(&ready->cond);
+    pthread_mutex_unlock(&ready->mutex);
+    }
+#endif
+
+    *clientfd = udp_read_connect(*sockfd);
+}
+
+static INLINE void tcp_accept(SOCKET_T* sockfd, int* clientfd, func_args* args)
+{
+    SOCKADDR_IN_T client;
+    socklen_t client_len = sizeof(client);
+
+    #ifdef CYASSL_DTLS
+        udp_accept(sockfd, clientfd, args);
+        return;
+    #endif
+
+    tcp_listen(sockfd);
+
+#if defined(_POSIX_THREADS) && defined(NO_MAIN_DRIVER)
+    /* signal ready to tcp_accept */
+    {
+    tcp_ready* ready = args->signal;
+    pthread_mutex_lock(&ready->mutex);
+    ready->ready = 1;
+    pthread_cond_signal(&ready->cond);
+    pthread_mutex_unlock(&ready->mutex);
+    }
+#endif
+
+    *clientfd = accept(*sockfd, (struct sockaddr*)&client,
+                      (ACCEPT_THIRD_T)&client_len);
+    if (*clientfd == -1)
+        err_sys("tcp accept failed");
+}
+
+
+static INLINE void tcp_set_nonblocking(SOCKET_T* sockfd)
+{
+#ifdef NON_BLOCKING
+    #ifdef USE_WINDOWS_API 
+        unsigned long blocking = 1;
+        int ret = ioctlsocket(*sockfd, FIONBIO, &blocking);
+    #else
+        int flags = fcntl(*sockfd, F_GETFL, 0);
+        int ret = fcntl(*sockfd, F_SETFL, flags | O_NONBLOCK);
+    #endif
+#endif
+}
+
+
+#ifndef NO_PSK
+
+static INLINE unsigned int my_psk_client_cb(SSL* ssl, const char* hint,
+        char* identity, unsigned int id_max_len, unsigned char* key,
+        unsigned int key_max_len)
+{
+    /* identity is OpenSSL testing default for openssl s_client, keep same */
+    strncpy(identity, "Client_identity", id_max_len);
+
+
+    /* test key in hex is 0x1a2b3c4d , in decimal 439,041,101 , we're using
+       unsigned binary */
+    key[0] = 26;
+    key[1] = 43;
+    key[2] = 60;
+    key[3] = 77;
+
+    return 4;   /* length of key in octets or 0 for error */
+}
+
+
+static INLINE unsigned int my_psk_server_cb(SSL* ssl, const char* identity,
+        unsigned char* key, unsigned int key_max_len)
+{
+    /* identity is OpenSSL testing default for openssl s_client, keep same */
+    if (strncmp(identity, "Client_identity", 15) != 0)
+        return 0;
+
+    /* test key in hex is 0x1a2b3c4d , in decimal 439,041,101 , we're using
+       unsigned binary */
+    key[0] = 26;
+    key[1] = 43;
+    key[2] = 60;
+    key[3] = 77;
+
+    return 4;   /* length of key in octets or 0 for error */
+}
+
+#endif /* NO_PSK */
+
+
+#ifdef USE_WINDOWS_API 
+
+    #define WIN32_LEAN_AND_MEAN
+    #include 
+
+    static INLINE double current_time()
+    {
+        static int init = 0;
+        static LARGE_INTEGER freq;
+    
+        LARGE_INTEGER count;
+
+        if (!init) {
+            QueryPerformanceFrequency(&freq);
+            init = 1;
+        }
+
+        QueryPerformanceCounter(&count);
+
+        return (double)count.QuadPart / freq.QuadPart;
+    }
+
+#else
+
+    #include 
+
+    static INLINE double current_time()
+    {
+        struct timeval tv;
+        gettimeofday(&tv, 0);
+
+        return (double)tv.tv_sec + (double)tv.tv_usec / 1000000;
+    }
+
+#endif /* USE_WINDOWS_API */
+
+
+#ifdef NO_FILESYSTEM
+
+    enum {
+        CYASSL_CA   = 1,
+        CYASSL_CERT = 2,
+        CYASSL_KEY  = 3
+    };
+
+    static INLINE void load_buffer(SSL_CTX* ctx, const char* fname, int type)
+    {
+        /* test buffer load */
+        long  sz = 0;
+        byte  buff[4096];
+        FILE* file = fopen(fname, "rb");
+
+        if (!file)
+            err_sys("can't open file for buffer load");
+        fseek(file, 0, SEEK_END);
+        sz = ftell(file);
+        rewind(file);
+        fread(buff, sizeof(buff), 1, file);
+  
+        if (type == CYASSL_CA) {
+            if (CyaSSL_CTX_load_verify_buffer(ctx, buff, sz, SSL_FILETYPE_PEM)
+                                              != SSL_SUCCESS)
+                err_sys("can't load buffer ca file");
+        }
+        else if (type == CYASSL_CERT) {
+            if (CyaSSL_CTX_use_certificate_buffer(ctx, buff, sz,
+                        SSL_FILETYPE_PEM) != SSL_SUCCESS)
+                err_sys("can't load buffer cert file");
+        }
+        else if (type == CYASSL_KEY) {
+            if (CyaSSL_CTX_use_PrivateKey_buffer(ctx, buff, sz,
+                        SSL_FILETYPE_PEM) != SSL_SUCCESS)
+                err_sys("can't load buffer key file");
+        }
+    }
+
+#endif /* NO_FILESYSTEM */
+
+#ifdef VERIFY_CALLBACK
+
+static int myVerify(int preverify, X509_STORE_CTX* store)
+{
+    char buffer[80];
+
+    printf("In verification callback, error = %d, %s\n", store->error,
+                                        ERR_error_string(store->error, buffer));
+#ifdef OPENSSL_EXTRA
+    X509* peer = store->current_cert;
+    if (peer) {
+        char* issuer  = X509_NAME_oneline(X509_get_issuer_name(peer), 0, 0);
+        char* subject = X509_NAME_oneline(X509_get_subject_name(peer), 0, 0);
+        
+        printf("peer's cert info:\n issuer : %s\n subject: %s\n", issuer,
+                                                                  subject);
+        XFREE(subject, 0, DYNAMIC_TYPE_OPENSSL);
+        XFREE(issuer,  0, DYNAMIC_TYPE_OPENSSL);
+    }
+    else
+        printf("peer has no cert!\n");
+#endif
+    printf("Subject's domain name is %s\n", store->domain);
+
+    printf("Allowing to continue anyway (shouldn't do this, EVER!!!)\n");
+    return 1;
+}
+
+#endif /* VERIFY_CALLBACK */
+
+
+#endif /* CyaSSL_TEST_H */
+
diff --git a/include/openssl/des.h b/include/openssl/des.h
new file mode 100644
index 000000000..b74409b2a
--- /dev/null
+++ b/include/openssl/des.h
@@ -0,0 +1,70 @@
+/* des.h
+ *
+ * Copyright (C) 2011 Sawtooth Consulting Ltd.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * CyaSSL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+
+/*  des.h defines mini des openssl compatibility layer 
+ *
+ */
+
+
+
+#ifndef CYASSL_DES_H_
+#define CYASSL_DES_H_
+
+#ifdef YASSL_PREFIX
+#include "prefix_des.h"
+#endif
+
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+typedef unsigned char DES_cblock[8];
+typedef /* const */ DES_cblock const_DES_cblock;
+typedef DES_cblock DES_key_schedule;
+
+
+enum {
+    DES_ENCRYPT = 1,
+    DES_DECRYPT = 0
+};
+
+
+void DES_set_key_unchecked(const_DES_cblock*, DES_key_schedule*);
+int  DES_key_sched(const_DES_cblock* key, DES_key_schedule* schedule);
+void DES_cbc_encrypt(const unsigned char* input, unsigned char* output,
+                     long length, DES_key_schedule* schedule, DES_cblock* ivec,
+                     int enc);
+void DES_ncbc_encrypt(const unsigned char* input, unsigned char* output,
+                      long length, DES_key_schedule* schedule, DES_cblock* ivec,
+                      int enc);
+
+
+void DES_set_odd_parity(DES_cblock*);
+void DES_ecb_encrypt(DES_cblock*, DES_cblock*, DES_key_schedule*, int);
+
+#ifdef __cplusplus
+    } /* extern "C" */
+#endif
+
+
+#endif /* CYASSL_DES_H_ */
diff --git a/include/openssl/dh.h b/include/openssl/dh.h
new file mode 100644
index 000000000..f3a6a7fcd
--- /dev/null
+++ b/include/openssl/dh.h
@@ -0,0 +1,2 @@
+/* dh.h for openssl */
+
diff --git a/include/openssl/dsa.h b/include/openssl/dsa.h
new file mode 100644
index 000000000..756f8ea2c
--- /dev/null
+++ b/include/openssl/dsa.h
@@ -0,0 +1,2 @@
+/* dsa.h for openssl */
+
diff --git a/include/openssl/ec.h b/include/openssl/ec.h
new file mode 100644
index 000000000..5ffdaf6e5
--- /dev/null
+++ b/include/openssl/ec.h
@@ -0,0 +1,2 @@
+/* ec.h for openssl */
+
diff --git a/include/openssl/ecdsa.h b/include/openssl/ecdsa.h
new file mode 100644
index 000000000..f3cf0de35
--- /dev/null
+++ b/include/openssl/ecdsa.h
@@ -0,0 +1,2 @@
+/* ecdsa.h for openssl */
+
diff --git a/include/openssl/engine.h b/include/openssl/engine.h
new file mode 100644
index 000000000..39952fcae
--- /dev/null
+++ b/include/openssl/engine.h
@@ -0,0 +1,5 @@
+/* engine.h for libcurl */
+
+#undef HAVE_OPENSSL_ENGINE_H
+
+
diff --git a/include/openssl/err.h b/include/openssl/err.h
new file mode 100644
index 000000000..7e7f1eb78
--- /dev/null
+++ b/include/openssl/err.h
@@ -0,0 +1,2 @@
+/* err.h for openssl */
+
diff --git a/include/openssl/evp.h b/include/openssl/evp.h
new file mode 100644
index 000000000..a795dcab8
--- /dev/null
+++ b/include/openssl/evp.h
@@ -0,0 +1,79 @@
+/* evp.h
+ *
+ * Copyright (C) 2011 Sawtooth Consulting Ltd.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * CyaSSL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+
+/*  evp.h defines mini evp openssl compatibility layer 
+ *
+ */
+
+
+
+#ifndef CYASSL_EVP_H_
+#define CYASSL_EVP_H_
+
+#ifdef YASSL_PREFIX
+#include "prefix_evp.h"
+#endif
+
+#include "md5.h"
+#include "sha.h"
+
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+typedef char EVP_MD;
+typedef char EVP_CIPHER;
+
+const EVP_MD* EVP_md5(void);
+const EVP_MD* EVP_sha1(void);
+
+
+typedef union {
+    MD5_CTX md5;
+    SHA_CTX sha;
+} Hasher;
+
+
+typedef struct EVP_MD_CTX {
+    unsigned char macType;               /* md5 or sha for now */
+    Hasher        hash;
+} EVP_MD_CTX;
+
+
+void EVP_MD_CTX_init(EVP_MD_CTX* ctx);
+int  EVP_MD_CTX_cleanup(EVP_MD_CTX* ctx);
+
+int EVP_DigestInit(EVP_MD_CTX* ctx, const EVP_MD* type);
+int EVP_DigestUpdate(EVP_MD_CTX* ctx, const void* data, size_t sz);
+int EVP_DigestFinal(EVP_MD_CTX* ctx, unsigned char* md, unsigned int* s);
+int EVP_DigestFinal_ex(EVP_MD_CTX* ctx, unsigned char* md, unsigned int* s);
+
+int EVP_BytesToKey(const EVP_CIPHER*, const EVP_MD*, const unsigned char*,
+                const unsigned char*, int, int, unsigned char*, unsigned char*);
+
+#ifdef __cplusplus
+    } /* extern "C" */
+#endif
+
+
+#endif /* CYASSL_EVP_H_ */
diff --git a/include/openssl/hmac.h b/include/openssl/hmac.h
new file mode 100644
index 000000000..10cff93f5
--- /dev/null
+++ b/include/openssl/hmac.h
@@ -0,0 +1,51 @@
+/* hmac.h
+ *
+ * Copyright (C) 2011 Sawtooth Consulting Ltd.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * CyaSSL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+
+/*  hmac.h defines mini hamc openssl compatibility layer 
+ *
+ */
+
+
+
+#ifndef CYASSL_HMAC_H_
+#define CYASSL_HMAC_H_
+
+#ifdef YASSL_PREFIX
+#include "prefix_hmac.h"
+#endif
+
+unsigned char* HMAC(const EVP_MD* evp_md, const void* key, int key_len,
+    const unsigned char* d, int n, unsigned char* md, unsigned int* md_len);
+
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+
+
+#ifdef __cplusplus
+    } /* extern "C" */
+#endif
+
+
+#endif /* CYASSL_HMAC_H_ */
diff --git a/include/openssl/lhash.h b/include/openssl/lhash.h
new file mode 100644
index 000000000..01f8535f8
--- /dev/null
+++ b/include/openssl/lhash.h
@@ -0,0 +1,2 @@
+/* lhash.h for openSSL */
+
diff --git a/include/openssl/md4.h b/include/openssl/md4.h
new file mode 100644
index 000000000..2e99f977f
--- /dev/null
+++ b/include/openssl/md4.h
@@ -0,0 +1 @@
+/* md4.h for libcurl */
diff --git a/include/openssl/md5.h b/include/openssl/md5.h
new file mode 100644
index 000000000..467db4cc8
--- /dev/null
+++ b/include/openssl/md5.h
@@ -0,0 +1,32 @@
+/* md5.h for openssl */
+
+
+#ifndef CYASSL_MD5_H_
+#define CYASSL_MD5_H_
+
+#ifdef YASSL_PREFIX
+#include "prefix_md5.h"
+#endif
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+
+typedef struct MD5_CTX {
+    int holder[24];   /* big enough to hold ctaocrypt md5, but check on init */
+} MD5_CTX;
+
+void MD5_Init(MD5_CTX*);
+void MD5_Update(MD5_CTX*, const void*, unsigned long);
+void MD5_Final(unsigned char*, MD5_CTX*);
+
+
+
+#ifdef __cplusplus
+    }  /* extern "C" */ 
+#endif
+
+
+#endif /* CYASSL_MD5_H_ */
+
diff --git a/include/openssl/ocsp.h b/include/openssl/ocsp.h
new file mode 100644
index 000000000..7463eec96
--- /dev/null
+++ b/include/openssl/ocsp.h
@@ -0,0 +1 @@
+/* ocsp.h for libcurl */
diff --git a/include/openssl/opensslconf.h b/include/openssl/opensslconf.h
new file mode 100644
index 000000000..ac6b55bc7
--- /dev/null
+++ b/include/openssl/opensslconf.h
@@ -0,0 +1,8 @@
+/* opensslconf.h for openSSL */
+
+
+#ifndef OPENSSL_THREADS
+    #define OPENSSL_THREADS
+#endif
+
+
diff --git a/include/openssl/opensslv.h b/include/openssl/opensslv.h
new file mode 100644
index 000000000..bdcc805ee
--- /dev/null
+++ b/include/openssl/opensslv.h
@@ -0,0 +1,12 @@
+/* opensslv.h compatibility */
+
+#ifndef CYASSL_OPENSSLV_H_
+#define CYASSL_OPENSSLV_H_
+
+
+/* api version compatibility */
+#define OPENSSL_VERSION_NUMBER 0x0090410fL
+
+
+#endif /* header */
+
diff --git a/include/openssl/ossl_typ.h b/include/openssl/ossl_typ.h
new file mode 100644
index 000000000..65b00c728
--- /dev/null
+++ b/include/openssl/ossl_typ.h
@@ -0,0 +1,2 @@
+/* ossl_typ.h for openssl */
+
diff --git a/include/openssl/pem.h b/include/openssl/pem.h
new file mode 100644
index 000000000..fe7cab885
--- /dev/null
+++ b/include/openssl/pem.h
@@ -0,0 +1,2 @@
+/* pem.h for openssl */
+
diff --git a/include/openssl/pkcs12.h b/include/openssl/pkcs12.h
new file mode 100644
index 000000000..544b6f092
--- /dev/null
+++ b/include/openssl/pkcs12.h
@@ -0,0 +1,2 @@
+/* pkcs12.h for openssl */
+
diff --git a/include/openssl/rand.h b/include/openssl/rand.h
new file mode 100644
index 000000000..ba8187299
--- /dev/null
+++ b/include/openssl/rand.h
@@ -0,0 +1,4 @@
+/* rand.h for openSSL */
+
+#include "openssl/ssl.h"
+
diff --git a/include/openssl/rsa.h b/include/openssl/rsa.h
new file mode 100644
index 000000000..55038c13d
--- /dev/null
+++ b/include/openssl/rsa.h
@@ -0,0 +1,10 @@
+/* rsa.h for openSSL */
+
+
+#ifndef CYASSL_RSA_H_
+#define CYASSL_RSA_H_
+
+enum { RSA_F4 = 1 };
+
+
+#endif /* header */
diff --git a/include/openssl/sha.h b/include/openssl/sha.h
new file mode 100644
index 000000000..501274f4a
--- /dev/null
+++ b/include/openssl/sha.h
@@ -0,0 +1,32 @@
+/* sha.h for openssl */
+
+
+#ifndef CYASSL_SHA_H_
+#define CYASSL_SHA_H_
+
+#ifdef YASSL_PREFIX
+#include "prefix_sha.h"
+#endif
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+
+typedef struct SHA_CTX {
+    int holder[24];   /* big enough to hold ctaocrypt sha, but check on init */
+} SHA_CTX;
+
+void SHA_Init(SHA_CTX*);
+void SHA_Update(SHA_CTX*, const void*, unsigned long);
+void SHA_Final(unsigned char*, SHA_CTX*);
+
+
+
+#ifdef __cplusplus
+    }  /* extern "C" */ 
+#endif
+
+
+#endif /* CYASSL_SHA_H_ */
+
diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h
new file mode 100644
index 000000000..dd1e56532
--- /dev/null
+++ b/include/openssl/ssl.h
@@ -0,0 +1,675 @@
+/* ssl.h
+ *
+ * Copyright (C) 2006-2011 Sawtooth Consulting Ltd.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * CyaSSL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+
+/*  ssl.h defines openssl compatibility layer 
+ *
+ */
+
+
+
+#ifndef CYASSL_OPENSSL_H_
+#define CYASSL_OPENSSL_H_
+
+#include "os_settings.h"   /* for users not using preprocessor flags */
+
+#ifndef NO_FILESYSTEM
+    #include    /* ERR_print fp */
+#endif
+
+#ifdef YASSL_PREFIX
+    #include "prefix_ssl.h"
+#endif
+
+#undef X509_NAME   /* wincrypt.h clash */
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+
+
+typedef struct SSL          SSL;          
+typedef struct SSL_SESSION  SSL_SESSION;
+typedef struct SSL_METHOD   SSL_METHOD;
+typedef struct SSL_CTX      SSL_CTX;
+
+typedef struct X509       X509;
+typedef struct X509_NAME  X509_NAME;
+typedef struct X509_CHAIN X509_CHAIN;
+
+
+/* redeclare guard */
+#define SSL_TYPES_DEFINED
+
+
+
+
+typedef struct EVP_PKEY       EVP_PKEY;
+typedef struct RSA            RSA;
+typedef struct BIO            BIO;
+typedef struct BIO_METHOD     BIO_METHOD;
+typedef struct SSL_CIPHER     SSL_CIPHER;
+typedef struct X509_LOOKUP    X509_LOOKUP;
+typedef struct X509_LOOKUP_METHOD X509_LOOKUP_METHOD;
+typedef struct X509_CRL       X509_CRL;
+typedef struct X509_EXTENSION X509_EXTENSION;
+typedef struct ASN1_TIME      ASN1_TIME;
+typedef struct ASN1_INTEGER   ASN1_INTEGER;
+typedef struct ASN1_OBJECT    ASN1_OBJECT;
+typedef struct ASN1_STRING    ASN1_STRING;
+typedef struct CRYPTO_dynlock_value CRYPTO_dynlock_value;
+
+#define ASN1_UTCTIME ASN1_TIME
+
+typedef struct MD4_CTX {
+    int buffer[32];      /* big enough to hold, check size in Init */
+} MD4_CTX;
+
+
+typedef struct COMP_METHOD {
+    int type;            /* stunnel dereference */
+} COMP_METHOD;
+
+
+typedef struct X509_STORE {
+    int cache;          /* stunnel dereference */
+} X509_STORE;
+
+
+typedef struct X509_REVOKED {
+    ASN1_INTEGER* serialNumber;          /* stunnel dereference */
+} X509_REVOKED;
+
+
+typedef struct X509_OBJECT {
+    union {
+        char* ptr;
+        X509_CRL* crl;           /* stunnel dereference */
+    } data;
+} X509_OBJECT;
+
+
+/* in cyassl_int.h too, change there !! */
+typedef struct X509_STORE_CTX {
+    int   error;
+    int   error_depth;
+    X509* current_cert;          /* stunnel dereference */
+    char* domain;                /* subject CN domain name */
+    /* in cyassl_int.h too, change there !! */
+} X509_STORE_CTX;
+
+
+SSL_METHOD *SSLv3_server_method(void);
+SSL_METHOD *SSLv3_client_method(void);
+SSL_METHOD *TLSv1_server_method(void);  
+SSL_METHOD *TLSv1_client_method(void);
+SSL_METHOD *TLSv1_1_server_method(void);  
+SSL_METHOD *TLSv1_1_client_method(void);
+SSL_METHOD *TLSv1_2_server_method(void);  
+SSL_METHOD *TLSv1_2_client_method(void);
+
+#ifdef CYASSL_DTLS
+    SSL_METHOD *DTLSv1_client_method(void);
+    SSL_METHOD *DTLSv1_server_method(void);
+#endif
+
+#ifndef NO_FILESYSTEM
+
+int SSL_CTX_use_certificate_file(SSL_CTX*, const char*, int);
+int SSL_CTX_use_PrivateKey_file(SSL_CTX*, const char*, int);
+int SSL_CTX_load_verify_locations(SSL_CTX*, const char*, const char*);
+int SSL_CTX_use_certificate_chain_file(SSL_CTX *ctx, const char *file);
+int SSL_CTX_use_RSAPrivateKey_file(SSL_CTX*, const char*, int);
+
+#ifdef CYASSL_DER_LOAD
+    int CyaSSL_CTX_load_verify_locations(SSL_CTX*, const char*, int);
+#endif
+
+#ifdef HAVE_NTRU
+    int CyaSSL_CTX_use_NTRUPrivateKey_file(SSL_CTX*, const char*); /* load NTRU 
+                                                             private key blob */
+#endif
+
+int CyaSSL_PemCertToDer(const char*, unsigned char*, int);
+
+#endif /* NO_FILESYSTEM */
+
+SSL_CTX* SSL_CTX_new(SSL_METHOD*);
+SSL* SSL_new(SSL_CTX*);
+int  SSL_set_fd (SSL*, int);
+int  SSL_get_fd(const SSL*);
+int  SSL_connect(SSL*);                   /* please see note at top of README
+                                             if you get an error from connect */
+int  SSL_write(SSL*, const void*, int);
+int  SSL_read(SSL*, void*, int);
+int  SSL_accept(SSL*);
+void SSL_CTX_free(SSL_CTX*);
+void SSL_free(SSL*);
+int  SSL_shutdown(SSL*);
+
+void SSL_CTX_set_quiet_shutdown(SSL_CTX*, int);
+
+int  SSL_get_error(SSL*, int);
+
+int          SSL_set_session(SSL *ssl, SSL_SESSION *session);
+SSL_SESSION* SSL_get_session(SSL* ssl);
+void         SSL_flush_sessions(SSL_CTX *ctx, long tm);
+
+
+typedef int (*VerifyCallback)(int, X509_STORE_CTX*);
+typedef int (*pem_password_cb)(char*, int, int, void*);
+
+void SSL_CTX_set_verify(SSL_CTX*, int, VerifyCallback verify_callback);
+
+
+int  SSL_pending(SSL*);
+
+
+void SSL_load_error_strings(void);
+int  SSL_library_init(void);
+long SSL_CTX_set_session_cache_mode(SSL_CTX*, long);
+
+/* only supports full name from cipher_name[] delimited by : */
+int  SSL_CTX_set_cipher_list(SSL_CTX*, const char*);
+
+char* ERR_error_string(unsigned long,char*);
+void  ERR_error_string_n(unsigned long e, char *buf, size_t len);
+
+
+/* extras */
+
+#define STACK_OF(x) x
+
+int  SSL_set_ex_data(SSL*, int, void*);
+int  SSL_get_shutdown(const SSL*);
+int  SSL_set_rfd(SSL*, int);
+int  SSL_set_wfd(SSL*, int);
+void SSL_set_shutdown(SSL*, int);
+int  SSL_set_session_id_context(SSL*, const unsigned char*, unsigned int);
+void SSL_set_connect_state(SSL*);
+void SSL_set_accept_state(SSL*);
+int  SSL_session_reused(SSL*);
+void SSL_SESSION_free(SSL_SESSION* session);
+
+const char*  SSL_get_version(SSL*);
+SSL_CIPHER*  SSL_get_current_cipher(SSL*);
+char*        SSL_CIPHER_description(SSL_CIPHER*, char*, int);
+const char*  SSL_CIPHER_get_name(const SSL_CIPHER* cipher);
+SSL_SESSION* SSL_get1_session(SSL* ssl);  /* what's ref count */
+
+void X509_free(X509*);
+void OPENSSL_free(void*);
+
+int OCSP_parse_url(char* url, char** host, char** port, char** path, int* ssl);
+
+SSL_METHOD* SSLv23_client_method(void);
+SSL_METHOD* SSLv2_client_method(void);
+SSL_METHOD* SSLv2_server_method(void);
+
+void MD4_Init(MD4_CTX*);
+void MD4_Update(MD4_CTX*, const void*, size_t);
+void MD4_Final(unsigned char*, MD4_CTX*);
+
+BIO* BIO_new(BIO_METHOD*);
+int  BIO_free(BIO*);
+int  BIO_free_all(BIO*);
+int  BIO_read(BIO*, void*, int);
+int  BIO_write(BIO*, const void*, int);
+BIO* BIO_push(BIO*, BIO* append);
+BIO* BIO_pop(BIO*);
+int  BIO_flush(BIO*);
+int  BIO_pending(BIO*);
+
+BIO_METHOD* BIO_f_buffer(void);
+long        BIO_set_write_buffer_size(BIO*, long size);
+BIO_METHOD* BIO_f_ssl(void);
+BIO*        BIO_new_socket(int sfd, int flag);
+void        SSL_set_bio(SSL*, BIO* rd, BIO* wr);
+int         BIO_eof(BIO*);
+long        BIO_set_ssl(BIO*, SSL*, int flag);
+
+BIO_METHOD* BIO_s_mem(void);
+BIO_METHOD* BIO_f_base64(void);
+void        BIO_set_flags(BIO*, int);
+
+void OpenSSL_add_all_algorithms(void);
+int  SSLeay_add_ssl_algorithms(void);
+int  SSLeay_add_all_algorithms(void);
+
+void        RAND_screen(void);
+const char* RAND_file_name(char*, size_t);
+int         RAND_write_file(const char*);
+int         RAND_load_file(const char*, long);
+int         RAND_egd(const char*);
+
+COMP_METHOD* COMP_zlib(void);
+COMP_METHOD* COMP_rle(void);
+int SSL_COMP_add_compression_method(int, void*);
+
+int SSL_get_ex_new_index(long, void*, void*, void*, void*);
+
+void CRYPTO_set_id_callback(unsigned long (*f)(void));
+void CRYPTO_set_locking_callback(void (*f)(int, int, const char*, int));
+void CRYPTO_set_dynlock_create_callback(CRYPTO_dynlock_value* (*f)(const char*,
+                                                                   int));
+void CRYPTO_set_dynlock_lock_callback(void (*f)(int, CRYPTO_dynlock_value*,
+                                                const char*, int));
+void CRYPTO_set_dynlock_destroy_callback(void (*f)(CRYPTO_dynlock_value*,
+                                                   const char*, int));
+
+X509* X509_STORE_CTX_get_current_cert(X509_STORE_CTX*);
+int   X509_STORE_CTX_get_error(X509_STORE_CTX*);
+int   X509_STORE_CTX_get_error_depth(X509_STORE_CTX*);
+
+char*       X509_NAME_oneline(X509_NAME*, char*, int);
+X509_NAME*  X509_get_issuer_name(X509*);
+X509_NAME*  X509_get_subject_name(X509*);
+const char* X509_verify_cert_error_string(long);
+
+int                 X509_LOOKUP_add_dir(X509_LOOKUP*, const char*, long);
+int                 X509_LOOKUP_load_file(X509_LOOKUP*, const char*, long);
+X509_LOOKUP_METHOD* X509_LOOKUP_hash_dir(void);
+X509_LOOKUP_METHOD* X509_LOOKUP_file(void);
+
+X509_LOOKUP* X509_STORE_add_lookup(X509_STORE*, X509_LOOKUP_METHOD*);
+X509_STORE*  X509_STORE_new(void);
+int          X509_STORE_get_by_subject(X509_STORE_CTX*, int, X509_NAME*,
+                                       X509_OBJECT*);
+int  X509_STORE_CTX_init(X509_STORE_CTX*, X509_STORE*, X509*, STACK_OF(X509)*);
+void X509_STORE_CTX_cleanup(X509_STORE_CTX*);
+
+ASN1_TIME* X509_CRL_get_lastUpdate(X509_CRL*);
+ASN1_TIME* X509_CRL_get_nextUpdate(X509_CRL*);
+
+EVP_PKEY* X509_get_pubkey(X509*);
+int       X509_CRL_verify(X509_CRL*, EVP_PKEY*);
+void      X509_STORE_CTX_set_error(X509_STORE_CTX*, int);
+void      X509_OBJECT_free_contents(X509_OBJECT*);
+void      EVP_PKEY_free(EVP_PKEY*);
+int       X509_cmp_current_time(const ASN1_TIME*);
+int       sk_X509_REVOKED_num(X509_REVOKED*);
+
+X509_REVOKED* X509_CRL_get_REVOKED(X509_CRL*);
+X509_REVOKED* sk_X509_REVOKED_value(X509_REVOKED*, int);
+
+ASN1_INTEGER* X509_get_serialNumber(X509*);
+
+int ASN1_TIME_print(BIO*, const ASN1_TIME*);
+
+int  ASN1_INTEGER_cmp(const ASN1_INTEGER*, const ASN1_INTEGER*);
+long ASN1_INTEGER_get(const ASN1_INTEGER*);
+
+STACK_OF(X509_NAME)* SSL_load_client_CA_file(const char*);
+
+void  SSL_CTX_set_client_CA_list(SSL_CTX*, STACK_OF(X509_NAME)*);
+void* X509_STORE_CTX_get_ex_data(X509_STORE_CTX*, int);
+int   SSL_get_ex_data_X509_STORE_CTX_idx(void);
+void* SSL_get_ex_data(const SSL*, int);
+
+void SSL_CTX_set_default_passwd_cb_userdata(SSL_CTX*, void* userdata);
+void SSL_CTX_set_default_passwd_cb(SSL_CTX*, pem_password_cb);
+
+
+long SSL_CTX_set_timeout(SSL_CTX*, long);
+void SSL_CTX_set_info_callback(SSL_CTX*, void (*)());
+
+unsigned long ERR_peek_error(void);
+int           ERR_GET_REASON(int);
+
+char* SSL_alert_type_string_long(int);
+char* SSL_alert_desc_string_long(int);
+char* SSL_state_string_long(SSL*);
+
+void RSA_free(RSA*);
+RSA* RSA_generate_key(int, unsigned long, void(*)(int, int, void*), void*);
+void SSL_CTX_set_tmp_rsa_callback(SSL_CTX*, RSA*(*)(SSL*, int, int));
+
+int PEM_def_callback(char*, int num, int w, void* key);
+
+long SSL_CTX_sess_accept(SSL_CTX*);
+long SSL_CTX_sess_connect(SSL_CTX*);
+long SSL_CTX_sess_accept_good(SSL_CTX*);
+long SSL_CTX_sess_connect_good(SSL_CTX*);
+long SSL_CTX_sess_accept_renegotiate(SSL_CTX*);
+long SSL_CTX_sess_connect_renegotiate(SSL_CTX*);
+long SSL_CTX_sess_hits(SSL_CTX*);
+long SSL_CTX_sess_cb_hits(SSL_CTX*);
+long SSL_CTX_sess_cache_full(SSL_CTX*);
+long SSL_CTX_sess_misses(SSL_CTX*);
+long SSL_CTX_sess_timeouts(SSL_CTX*);
+long SSL_CTX_sess_number(SSL_CTX*);
+long SSL_CTX_sess_get_cache_size(SSL_CTX*);
+
+
+#define SSL_DEFAULT_CIPHER_LIST ""   /* default all */
+#define RSA_F4 0x10001L
+
+enum {
+    OCSP_NOCERTS     = 1,
+    OCSP_NOINTERN    = 2,
+    OCSP_NOSIGS      = 4,
+    OCSP_NOCHAIN     = 8,
+    OCSP_NOVERIFY    = 16,
+    OCSP_NOEXPLICIT  = 32,
+    OCSP_NOCASIGN    = 64,
+    OCSP_NODELEGATED = 128,
+    OCSP_NOCHECKS    = 256,
+    OCSP_TRUSTOTHER  = 512,
+    OCSP_RESPID_KEY  = 1024,
+    OCSP_NOTIME      = 2048,
+
+    OCSP_CERTID   = 2,
+    OCSP_REQUEST  = 4,
+    OCSP_RESPONSE = 8,
+    OCSP_BASICRESP = 16,
+
+    ASN1_GENERALIZEDTIME = 4,
+
+    SSL_OP_MICROSOFT_SESS_ID_BUG = 1,
+    SSL_OP_NETSCAPE_CHALLENGE_BUG = 2,
+    SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG = 3,
+    SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG = 4,
+    SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER = 5,
+    SSL_OP_MSIE_SSLV2_RSA_PADDING = 6,
+    SSL_OP_SSLEAY_080_CLIENT_DH_BUG = 7,
+    SSL_OP_TLS_D5_BUG = 8,
+    SSL_OP_TLS_BLOCK_PADDING_BUG = 9,
+    SSL_OP_TLS_ROLLBACK_BUG = 10,
+    SSL_OP_ALL = 11,
+    SSL_OP_EPHEMERAL_RSA = 12,
+    SSL_OP_NO_SSLv3 = 13,
+    SSL_OP_NO_TLSv1 = 14,
+    SSL_OP_PKCS1_CHECK_1 = 15,
+    SSL_OP_PKCS1_CHECK_2 = 16,
+    SSL_OP_NETSCAPE_CA_DN_BUG = 17,
+    SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG = 18,
+    SSL_OP_SINGLE_DH_USE = 19,
+    SSL_OP_NO_TICKET = 20,
+    SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS = 21,
+    SSL_OP_NO_QUERY_MTU = 22,
+    SSL_OP_COOKIE_EXCHANGE = 23,
+    SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION = 24,
+    SSL_OP_SINGLE_ECDH_USE = 25,
+    SSL_OP_CIPHER_SERVER_PREFERENCE = 26,
+
+    SSL_MAX_SSL_SESSION_ID_LENGTH = 32,
+
+    EVP_R_BAD_DECRYPT = 2,
+
+    SSL_CB_LOOP = 4,
+    SSL_ST_CONNECT = 5,
+    SSL_ST_ACCEPT  = 6,
+    SSL_CB_ALERT   = 7,
+    SSL_CB_READ    = 8,
+    SSL_CB_HANDSHAKE_DONE = 9,
+
+    SSL_MODE_ENABLE_PARTIAL_WRITE = 2,
+
+    BIO_FLAGS_BASE64_NO_NL = 1,
+    BIO_CLOSE   = 1,
+    BIO_NOCLOSE = 0,
+
+    NID_undef = 0,
+
+    X509_FILETYPE_PEM = 8,
+    X509_LU_X509      = 9,
+    X509_LU_CRL       = 12,
+    
+    X509_V_ERR_CRL_SIGNATURE_FAILURE = 13,
+    X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD = 14,
+    X509_V_ERR_CRL_HAS_EXPIRED                = 15,
+    X509_V_ERR_CERT_REVOKED                   = 16,
+    X509_V_ERR_CERT_CHAIN_TOO_LONG            = 17,
+    X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT      = 18,
+    X509_V_ERR_CERT_NOT_YET_VALID             = 19,
+    X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD = 20,
+    X509_V_ERR_CERT_HAS_EXPIRED               = 21,
+    X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD  = 22,
+
+    X509_V_OK = 0,
+
+    CRYPTO_LOCK = 1,
+    CRYPTO_NUM_LOCKS = 10,
+
+};
+
+/* extras end */
+
+#ifndef NO_FILESYSTEM
+/* CyaSSL extension, provide last error from SSL_get_error
+   since not using thread storage error queue */
+void  ERR_print_errors_fp(FILE*, int err);
+#endif
+
+enum { /* ssl Constants */
+    SSL_ERROR_NONE      =  0,   /* for most functions */
+    SSL_FAILURE         =  0,   /* for some functions */
+    SSL_SUCCESS	        =  1,
+
+    SSL_BAD_CERTTYPE    = -8,
+    SSL_BAD_STAT        = -7,
+    SSL_BAD_PATH        = -6,
+    SSL_BAD_FILETYPE    = -5,
+    SSL_BAD_FILE        = -4,
+    SSL_NOT_IMPLEMENTED = -3,
+    SSL_UNKNOWN         = -2,
+    SSL_FATAL_ERROR     = -1,
+
+    SSL_FILETYPE_ASN1    = 2,
+    SSL_FILETYPE_PEM     = 1,
+    SSL_FILETYPE_DEFAULT = 2, /* ASN1 */
+    SSL_FILETYPE_RAW     = 3, /* NTRU raw key blob */
+
+    SSL_VERIFY_NONE                 = 0,
+    SSL_VERIFY_PEER                 = 1,
+    SSL_VERIFY_FAIL_IF_NO_PEER_CERT = 2,
+    SSL_VERIFY_CLIENT_ONCE          = 4,
+
+    SSL_SESS_CACHE_OFF                = 30,
+    SSL_SESS_CACHE_CLIENT             = 31,
+    SSL_SESS_CACHE_SERVER             = 32,
+    SSL_SESS_CACHE_BOTH               = 33,
+    SSL_SESS_CACHE_NO_AUTO_CLEAR      = 34,
+    SSL_SESS_CACHE_NO_INTERNAL_LOOKUP = 35,
+
+    SSL_ERROR_WANT_READ        =  2,
+    SSL_ERROR_WANT_WRITE       =  3,
+    SSL_ERROR_WANT_CONNECT     =  7,
+    SSL_ERROR_WANT_ACCEPT      =  8,
+    SSL_ERROR_SYSCALL          =  5,
+    SSL_ERROR_WANT_X509_LOOKUP = 83,
+    SSL_ERROR_ZERO_RETURN      =  6,
+    SSL_ERROR_SSL              = 85,
+
+    SSL_SENT_SHUTDOWN     = 1,
+    SSL_RECEIVED_SHUTDOWN = 2,
+    SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER = 4,
+    SSL_OP_NO_SSLv2       = 8,
+
+    SSL_R_SSL_HANDSHAKE_FAILURE           = 101,
+    SSL_R_TLSV1_ALERT_UNKNOWN_CA          = 102,
+    SSL_R_SSLV3_ALERT_CERTIFICATE_UNKNOWN = 103,
+    SSL_R_SSLV3_ALERT_BAD_CERTIFICATE     = 104,
+
+    PEM_BUFSIZE = 1024,
+};
+
+
+#ifndef NO_PSK
+    typedef unsigned int (*psk_client_callback)(SSL*, const char*, char*,
+                          unsigned int, unsigned char*, unsigned int);
+    void SSL_CTX_set_psk_client_callback(SSL_CTX*, psk_client_callback);
+    void SSL_set_psk_client_callback(SSL*, psk_client_callback);
+
+    const char* SSL_get_psk_identity_hint(const SSL*);
+    const char* SSL_get_psk_identity(const SSL*);
+
+    int SSL_CTX_use_psk_identity_hint(SSL_CTX*, const char*);
+    int SSL_use_psk_identity_hint(SSL*, const char*);
+
+    typedef unsigned int (*psk_server_callback)(SSL*, const char*,
+                          unsigned char*, unsigned int);
+    void SSL_CTX_set_psk_server_callback(SSL_CTX*, psk_server_callback);
+    void SSL_set_psk_server_callback(SSL*, psk_server_callback);
+
+    #define PSK_TYPES_DEFINED
+#endif /* NO_PSK */
+
+
+/* extra begins */
+
+enum {  /* ERR Constants */
+    ERR_TXT_STRING = 1,
+};
+
+unsigned long ERR_get_error_line_data(const char**, int*, const char**, int *);
+
+unsigned long ERR_get_error(void);
+void          ERR_clear_error(void);
+
+
+int  RAND_status(void);
+int  RAND_bytes(unsigned char* buf, int num);
+SSL_METHOD *SSLv23_server_method(void);
+long SSL_CTX_set_options(SSL_CTX*, long);
+int  SSL_CTX_check_private_key(SSL_CTX*);
+
+
+void ERR_free_strings(void);
+void ERR_remove_state(unsigned long);
+void EVP_cleanup(void);
+
+void CRYPTO_cleanup_all_ex_data(void);
+long SSL_CTX_set_mode(SSL_CTX* ctx, long mode);
+long SSL_CTX_get_mode(SSL_CTX* ctx);
+void SSL_CTX_set_default_read_ahead(SSL_CTX* ctx, int m);
+
+long SSL_CTX_sess_set_cache_size(SSL_CTX*, long);
+
+int  SSL_CTX_set_default_verify_paths(SSL_CTX*);
+int  SSL_CTX_set_session_id_context(SSL_CTX*, const unsigned char*,
+                                    unsigned int);
+
+X509*      SSL_get_peer_certificate(SSL* ssl);
+
+int SSL_want_read(SSL*);
+int SSL_want_write(SSL*);
+
+int BIO_printf(BIO*, const char*, ...);
+int ASN1_UTCTIME_print(BIO*, const ASN1_UTCTIME*);
+
+int   sk_num(X509_REVOKED*);
+void* sk_value(X509_REVOKED*, int);
+
+/* stunnel 4.28 needs */
+void* SSL_CTX_get_ex_data(const SSL_CTX*, int);
+int   SSL_CTX_set_ex_data(SSL_CTX*, int, void*);
+void  SSL_CTX_sess_set_get_cb(SSL_CTX*, SSL_SESSION*(*f)(SSL*, unsigned char*,
+                                                         int, int*));
+void  SSL_CTX_sess_set_new_cb(SSL_CTX*, int (*f)(SSL*, SSL_SESSION*));
+void  SSL_CTX_sess_set_remove_cb(SSL_CTX*, void (*f)(SSL_CTX*, SSL_SESSION*));
+
+int          i2d_SSL_SESSION(SSL_SESSION*, unsigned char**);
+SSL_SESSION* d2i_SSL_SESSION(SSL_SESSION**,const unsigned char**, long);
+
+long SSL_SESSION_get_timeout(const SSL_SESSION*);
+long SSL_SESSION_get_time(const SSL_SESSION*);
+int  SSL_CTX_get_ex_new_index(long, void*, void*, void*, void*);
+
+/* extra ends */
+
+
+/* CyaSSL extensions */
+
+/* call before SSL_connect, if verifying will add name check to
+   date check and signature check */
+int CyaSSL_check_domain_name(SSL* ssl, const char* dn);
+
+int InitCyaSSL(void);   /* need to call once to load library (session cache) */
+int FreeCyaSSL(void);   /* call when done to free session cache mutex        */
+
+int  CyaSSL_Debugging_ON(void);   /* turn logging on, only if compiled in */
+void CyaSSL_Debugging_OFF(void);  /* turn logging off */
+
+int CyaSSL_set_compression(SSL* ssl);  /* turn on CyaSSL data compression */
+
+int CyaSSL_CTX_use_NTRUPrivateKey_file(SSL_CTX*, const char*); /* load NTRU
+                                                             private key blob */
+X509_CHAIN* CyaSSL_get_peer_chain(SSL* ssl);   /* get CyaSSL peer X509_CHAIN */
+int  CyaSSL_get_chain_count(X509_CHAIN* chain);   /* peer chain count */
+int  CyaSSL_get_chain_length(X509_CHAIN*, int idx); /* index cert length */
+unsigned char* CyaSSL_get_chain_cert(X509_CHAIN*, int idx);   /* index cert */
+int  CyaSSL_get_chain_cert_pem(X509_CHAIN*, int idx, unsigned char* buffer,
+                          int inLen, int* outLen); /* get index cert in PEM */
+const unsigned char* CyaSSL_get_sessionID(const SSL_SESSION* session);
+
+#ifndef _WIN32
+    #ifndef NO_WRITEV
+        #include 
+        /* allow writev style writing */
+        int CyaSSL_writev(SSL* ssl, const struct iovec* iov, int iovcnt);
+    #endif
+#endif
+
+#if defined(NO_FILESYSTEM) || defined(MICRIUM)
+
+int CyaSSL_CTX_load_verify_buffer(SSL_CTX*, const unsigned char*, long, int);
+int CyaSSL_CTX_use_certificate_buffer(SSL_CTX*, const unsigned char*, long,int);
+int CyaSSL_CTX_use_PrivateKey_buffer(SSL_CTX*, const unsigned char*, long, int);
+int CyaSSL_CTX_use_certificate_chain_buffer(SSL_CTX*,const unsigned char*,long);
+
+#endif /* NO_FILESYSTEM || MICRIUM */
+
+
+/* I/O callbacks */
+typedef int (*CallbackIORecv)(char *buf, int sz, void *ctx);
+typedef int (*CallbackIOSend)(char *buf, int sz, void *ctx);
+
+void CyaSSL_SetIORecv(SSL_CTX*, CallbackIORecv);
+void CyaSSL_SetIOSend(SSL_CTX*, CallbackIOSend);
+
+void CyaSSL_SetIOReadCtx(SSL* ssl, void *ctx);
+void CyaSSL_SetIOWriteCtx(SSL* ssl, void *ctx);
+
+
+#ifdef CYASSL_CALLBACKS
+
+/* used internally by CyaSSL while OpenSSL types aren't */
+#include "cyassl_callbacks.h"
+
+typedef int (*HandShakeCallBack)(HandShakeInfo*);
+typedef int (*TimeoutCallBack)(TimeoutInfo*);
+
+/* CyaSSL connect extension allowing HandShakeCallBack and/or TimeoutCallBack
+   for diagnostics */
+int CyaSSL_connect_ex(SSL*, HandShakeCallBack, TimeoutCallBack, Timeval);
+int CyaSSL_accept_ex(SSL*, HandShakeCallBack, TimeoutCallBack, Timeval);
+
+#endif /* CYASSL_CALLBACKS */
+
+
+#ifdef __cplusplus
+    } /* extern "C" */
+#endif
+
+
+#endif /* CyaSSL_openssl_h__ */
diff --git a/include/openssl/stack.h b/include/openssl/stack.h
new file mode 100644
index 000000000..374c1fcda
--- /dev/null
+++ b/include/openssl/stack.h
@@ -0,0 +1,2 @@
+/* stack.h for openssl */
+
diff --git a/include/openssl/ui.h b/include/openssl/ui.h
new file mode 100644
index 000000000..a25393031
--- /dev/null
+++ b/include/openssl/ui.h
@@ -0,0 +1,2 @@
+/* ui.h for openssl */
+
diff --git a/include/openssl/x509.h b/include/openssl/x509.h
new file mode 100644
index 000000000..2d1da2487
--- /dev/null
+++ b/include/openssl/x509.h
@@ -0,0 +1,3 @@
+/* x509.h for openssl */
+
+#include "openssl/ssl.h"
diff --git a/include/openssl/x509v3.h b/include/openssl/x509v3.h
new file mode 100644
index 000000000..77828a33b
--- /dev/null
+++ b/include/openssl/x509v3.h
@@ -0,0 +1,2 @@
+/* x509v3.h for openssl */
+
diff --git a/include/sniffer.h b/include/sniffer.h
new file mode 100644
index 000000000..40aa15b48
--- /dev/null
+++ b/include/sniffer.h
@@ -0,0 +1,72 @@
+/* sniffer.h
+ *
+ * Copyright (C) 2006-2011 Sawtooth Consulting Ltd.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * CyaSSL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+
+
+#ifndef CYASSL_SNIFFER_H
+#define CYASSL_SNIFFER_H
+
+
+#ifdef _WIN32
+    #ifdef SSL_SNIFFER_EXPORTS
+        #define SSL_SNIFFER_API __declspec(dllexport)
+    #else
+        #define SSL_SNIFFER_API __declspec(dllimport)
+    #endif
+#else
+    #define SSL_SNIFFER_API
+#endif /* _WIN32 */
+
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+
+
+SSL_SNIFFER_API int ssl_SetPrivateKey(const char* address, int port,
+                                      const char* keyFile, int keyType,
+                                      const char* password, char* error);
+
+SSL_SNIFFER_API int ssl_DecodePacket(const unsigned char* packet, int length,
+                                     unsigned char* data, char* error);
+
+SSL_SNIFFER_API int ssl_Trace(const char* traceFile, char* error);
+        
+        
+void ssl_InitSniffer(void);
+        
+void ssl_FreeSniffer(void);
+
+        
+/* ssl_SetPrivateKey keyTypes */
+enum {
+    FILETYPE_PEM = 1,
+    FILETYPE_DER = 2,
+};
+
+
+#ifdef __cplusplus
+    }  /* extern "C" */
+#endif
+
+#endif /* CyaSSL_SNIFFER_H */
+
diff --git a/include/sniffer_error.h b/include/sniffer_error.h
new file mode 100644
index 000000000..7157ee12d
--- /dev/null
+++ b/include/sniffer_error.h
@@ -0,0 +1,102 @@
+/* sniffer_error.h
+ *
+ * Copyright (C) 2006-2011 Sawtooth Consulting Ltd.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * CyaSSL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+
+
+#ifndef CYASSL_SNIFFER_ERROR_H
+#define CYASSL_SNIFFER_ERROR_H
+
+/* need to have errors as #defines since .rc files can't handle enums */
+/* need to start at 1 and go in order for same reason */
+
+#define MEMORY_STR 1
+#define NEW_SERVER_STR 2
+#define IP_CHECK_STR 3
+#define SERVER_NOT_REG_STR 4
+#define TCP_CHECK_STR 5
+#define SERVER_PORT_NOT_REG_STR 6
+#define RSA_DECRYPT_STR 7
+#define RSA_DECODE_STR 8
+#define BAD_CIPHER_SPEC_STR 9
+#define SERVER_HELLO_INPUT_STR 10
+
+#define BAD_SESSION_RESUME_STR 11
+#define SERVER_DID_RESUMPTION_STR 12
+#define CLIENT_HELLO_INPUT_STR 13
+#define CLIENT_RESUME_TRY_STR 14
+#define HANDSHAKE_INPUT_STR 15
+#define GOT_HELLO_VERIFY_STR 16
+#define GOT_SERVER_HELLO_STR 17
+#define GOT_CERT_REQ_STR 18
+#define GOT_SERVER_KEY_EX_STR 19
+#define GOT_CERT_STR 20
+
+#define GOT_SERVER_HELLO_DONE_STR 21
+#define GOT_FINISHED_STR 22
+#define GOT_CLIENT_HELLO_STR 23
+#define GOT_CLIENT_KEY_EX_STR 24
+#define GOT_CERT_VER_STR 25
+#define GOT_UNKNOWN_HANDSHAKE_STR 26
+#define NEW_SESSION_STR 27
+#define BAD_NEW_SSL_STR 28
+#define GOT_PACKET_STR 29
+#define NO_DATA_STR 30
+
+#define BAD_SESSION_STR 31
+#define GOT_OLD_CLIENT_HELLO_STR 32
+#define OLD_CLIENT_INPUT_STR 33
+#define OLD_CLIENT_OK_STR 34
+#define BAD_OLD_CLIENT_STR 35
+#define BAD_RECORD_HDR_STR 36
+#define RECORD_INPUT_STR 37
+#define GOT_HANDSHAKE_STR 38
+#define BAD_HANDSHAKE_STR 39
+#define GOT_CHANGE_CIPHER_STR 40
+
+#define GOT_APP_DATA_STR 41
+#define BAD_APP_DATA_STR 42
+#define GOT_ALERT_STR 43
+#define ANOTHER_MSG_STR 44
+#define REMOVE_SESSION_STR 45
+#define KEY_FILE_STR 46
+#define BAD_IPVER_STR 47
+#define BAD_PROTO_STR 48
+#define PACKET_HDR_SHORT_STR 49
+#define GOT_UNKNOWN_RECORD_STR 50
+
+#define BAD_TRACE_FILE_STR 51
+#define FATAL_ERROR_STR 52
+#define PARTIAL_INPUT_STR 53
+#define BUFFER_ERROR_STR 54
+#define PARTIAL_ADD_STR 55
+#define DUPLICATE_STR 56
+#define OUT_OF_ORDER_STR 57
+#define OVERLAP_DUPLICATE_STR 58
+#define OVERLAP_REASSEMBLY_BEGIN_STR 59
+
+#define OVERLAP_REASSEMBLY_END_STR 60
+#define MISSED_CLIENT_HELLO_STR 61
+
+/* !!!! also add to msgTable in sniffer.c and .rc file !!!! */
+
+
+#endif /* CyaSSL_SNIFFER_ERROR_H */
+
diff --git a/include/sniffer_error.rc b/include/sniffer_error.rc
new file mode 100644
index 000000000..89b12e2e9
--- /dev/null
+++ b/include/sniffer_error.rc
@@ -0,0 +1,78 @@
+
+STRINGTABLE 
+{
+    1, "Out of Memory"
+    2, "New SSL Sniffer Server Registered"
+    3, "Checking IP Header"
+    4, "SSL Sniffer Server Not Registered"
+    5, "Checking TCP Header"
+
+    6, "SSL Sniffer Server Port Not Registered"
+    7, "RSA Private Decrypt Error"
+    8, "RSA Private Decode Error"
+    9, "Set Cipher Spec Error"
+    10, "Server Hello Input Malformed"
+
+    11, "Couldn't Resume Session Error"
+    12, "Server Did Resumption"
+    13, "Client Hello Input Malformed"
+    14, "Client Trying to Resume"
+    15, "Handshake Input Malformed"
+
+    16, "Got Hello Verify msg"
+    17, "Got Server Hello msg"
+    18, "Got Cert Request msg"
+    19, "Got Server Key Exchange msg"
+    20, "Got Cert msg"
+
+    21, "Got Server Hello Done msg"
+    22, "Got Finished msg"
+    23, "Got Client Hello msg"
+    24, "Got Client Key Exchange msg"
+    25, "Got Cert Verify msg"
+
+    26, "Got Unknown Handshake msg"
+    27, "New SSL Sniffer Session created"
+    28, "Couldn't create new SSL"
+    29, "Got a Packet to decode"
+    30, "No data present"
+
+    31, "Session Not Found"
+    32, "Got an Old Client Hello msg"
+    33, "Old Client Hello Input Malformed"
+    34, "Old Client Hello OK"
+    35, "Bad Old Client Hello"
+
+    36, "Bad Record Header"
+    37, "Record Header Input Malformed"
+    38, "Got a HandShake msg"
+    39, "Bad HandShake msg"
+    40, "Got a Change Cipher Spec msg"
+
+    41, "Got Application Data msg"
+    42, "Bad Application Data"
+    43, "Got an Alert msg"
+    44, "Another msg to Process"
+    45, "Removing Session From Table"
+
+    46, "Bad Key File"
+    47, "Wrong IP Version"
+    48, "Wrong Protocol type"
+    49, "Packet Short for header processing"
+    50, "Got Unknown Record Type"
+    
+    51, "Can't Open Trace File"
+    52, "Session in Fatal Error State"
+    53, "Partial SSL record received"
+    54, "Buffer Error, malformed input"
+    55, "Added to Partial Input"
+
+    56, "Received a Duplicate Packet"
+    57, "Received an Out of Order Packet"
+    58, "Received an Overlap Duplicate Packet"
+    59, "Received an Overlap Reassembly Begin Duplicate Packet"
+    60, "Received an Overlap Reassembly End Duplicate Packet"
+    
+    61, "Missed the Client Hello Entirely"
+}
+
diff --git a/lib/dummy b/lib/dummy
new file mode 100644
index 000000000..13c3b18cd
--- /dev/null
+++ b/lib/dummy
@@ -0,0 +1,2 @@
+// this is a dummy file
+
diff --git a/lib_socket_nsl.m4 b/lib_socket_nsl.m4
new file mode 100644
index 000000000..e786e61c5
--- /dev/null
+++ b/lib_socket_nsl.m4
@@ -0,0 +1,25 @@
+dnl @synopsis LIB_SOCKET_NSL
+dnl
+dnl This macro figures out what libraries are required on this platform
+dnl to link sockets programs.
+dnl
+dnl The common cases are not to need any extra libraries, or to need
+dnl -lsocket and -lnsl. We need to avoid linking with libnsl unless we
+dnl need it, though, since on some OSes where it isn't necessary it
+dnl will totally break networking. Unisys also includes gethostbyname()
+dnl in libsocket but needs libnsl for socket().
+dnl
+dnl @category Misc
+dnl @author Russ Allbery 
+dnl @author Stepan Kasal 
+dnl @author Warren Young 
+dnl @version 2005-09-06
+dnl @license AllPermissive
+
+AC_DEFUN([LIB_SOCKET_NSL],
+[
+	AC_SEARCH_LIBS([gethostbyname], [nsl])
+	AC_SEARCH_LIBS([socket], [socket], [], [
+		AC_CHECK_LIB([socket], [socket], [LIBS="-lsocket -lnsl $LIBS"],
+		[], [-lnsl])])
+])
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 000000000..5d3181bad
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,43 @@
+INCLUDES = -I../include -I../ctaocrypt/include -I../include/openssl
+
+lib_LTLIBRARIES = libcyassl.la
+libcyassl_la_SOURCES = \
+    cyassl_int.c cyassl_io.c keys.c ssl.c tls.c  \
+    ../ctaocrypt/src/asn.c ../ctaocrypt/src/coding.c ../ctaocrypt/src/des3.c \
+    ../ctaocrypt/src/hmac.c ../ctaocrypt/src/md5.c ../ctaocrypt/src/md4.c  \
+    ../ctaocrypt/src/random.c ../ctaocrypt/src/rsa.c ../ctaocrypt/src/sha.c \
+    ../ctaocrypt/src/aes.c ../ctaocrypt/src/sha256.c ../ctaocrypt/src/dh.c \
+    ../ctaocrypt/src/dsa.c ../ctaocrypt/src/arc4.c ../ctaocrypt/src/rabbit.c \
+    ../ctaocrypt/src/pwdbased.c
+libcyassl_la_LDFLAGS = -no-undefined -version-info 0:0:0
+EXTRA_DIST = ../include/*.h ../include/openssl/*.h ../include/*.rc
+
+if BUILD_AESNI
+libcyassl_la_SOURCES += ../ctaocrypt/src/aes_asm.s
+endif
+
+if BUILD_RIPEMD
+libcyassl_la_SOURCES += ../ctaocrypt/src/ripemd.c
+endif
+
+if BUILD_SHA512
+libcyassl_la_SOURCES += ../ctaocrypt/src/sha512.c
+endif
+
+if BUILD_SNIFFER
+libcyassl_la_SOURCES += sniffer.c
+endif
+
+if BUILD_HC128
+libcyassl_la_SOURCES += ../ctaocrypt/src/hc128.c
+endif
+
+if BUILD_FASTMATH
+libcyassl_la_SOURCES += ../ctaocrypt/src/tfm.c
+else
+libcyassl_la_SOURCES += ../ctaocrypt/src/integer.c
+endif
+
+if BUILD_ECC
+libcyassl_la_SOURCES += ../ctaocrypt/src/ecc.c
+endif
diff --git a/src/cyassl_int.c b/src/cyassl_int.c
new file mode 100644
index 000000000..2558958c5
--- /dev/null
+++ b/src/cyassl_int.c
@@ -0,0 +1,5297 @@
+/* cyassl_int.c
+ *
+ * Copyright (C) 2006-2011 Sawtooth Consulting Ltd.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * CyaSSL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+
+
+#include "cyassl_int.h"
+#include "cyassl_error.h"
+#include "asn.h"
+
+#ifdef HAVE_LIBZ
+    #include "zlib.h"
+#endif
+
+#ifdef HAVE_NTRU
+    #include "crypto_ntru.h"
+#endif
+
+#if defined(DEBUG_CYASSL) || defined(SHOW_SECRETS)
+    #include 
+#endif
+
+#ifdef __sun
+    #include 
+#endif
+
+#define TRUE  1
+#define FALSE 0
+
+
+#if defined(OPENSSL_EXTRA) && defined(NO_DH)
+    #error OPENSSL_EXTRA needs DH, please remove NO_DH
+#endif
+
+
+int CyaSSL_negotiate(SSL*);
+
+
+#ifndef NO_CYASSL_CLIENT
+    static int DoHelloVerifyRequest(SSL* ssl, const byte* input, word32*);
+    static int DoServerHello(SSL* ssl, const byte* input, word32*);
+    static int DoCertificateRequest(SSL* ssl, const byte* input, word32*);
+    static int DoServerKeyExchange(SSL* ssl, const byte* input, word32*);
+#endif
+
+
+#ifndef NO_CYASSL_SERVER
+    static int DoClientHello(SSL* ssl, const byte* input, word32*, word32,
+                             word32);
+    static int DoCertificateVerify(SSL* ssl, byte*, word32*, word32);
+    static int DoClientKeyExchange(SSL* ssl, byte* input, word32*);
+#endif
+
+typedef enum {
+    doProcessInit = 0,
+#ifndef NO_CYASSL_SERVER
+    runProcessOldClientHello,
+#endif
+    getRecordLayerHeader,
+    getData,
+    runProcessingOneMessage
+} processReply;
+
+static void Hmac(SSL* ssl, byte* digest, const byte* buffer, word32 sz,
+                 int content, int verify);
+
+static void BuildCertHashes(SSL* ssl, Hashes* hashes);
+
+
+void BuildTlsFinished(SSL* ssl, Hashes* hashes, const byte* sender);
+
+
+#ifndef min
+
+    static INLINE word32 min(word32 a, word32 b)
+    {
+        return a > b ? b : a;
+    }
+
+#endif /* min */
+
+
+int IsTLS(const SSL* ssl)
+{
+    if (ssl->version.major == SSLv3_MAJOR && ssl->version.minor >=TLSv1_MINOR)
+        return 1;
+
+    return 0;
+}
+
+
+int IsAtLeastTLSv1_2(const SSL* ssl)
+{
+    if (ssl->version.major == SSLv3_MAJOR && ssl->version.minor >=TLSv1_2_MINOR)
+        return 1;
+
+    return 0;
+}
+
+
+#ifdef HAVE_NTRU
+
+static byte GetEntropy(ENTROPY_CMD cmd, byte* out)
+{
+    /* TODO: add locking? */
+    static RNG rng;
+
+    if (cmd == INIT) {
+        int ret = InitRng(&rng);
+        if (ret == 0)
+            return 1;
+        else
+            return 0;
+    }
+
+    if (out == NULL)
+        return 0;
+
+    if (cmd == GET_BYTE_OF_ENTROPY) {
+        RNG_GenerateBlock(&rng, out, 1);
+        return 1;
+    }
+
+    if (cmd == GET_NUM_BYTES_PER_BYTE_OF_ENTROPY) {
+        *out = 1;
+        return 1;
+    }
+
+    return 0;
+}
+
+#endif /* HAVE_NTRU */
+
+static INLINE void c32to24(word32 in, word24 out)
+{
+    out[0] = (in >> 16) & 0xff;
+    out[1] = (in >>  8) & 0xff;
+    out[2] =  in & 0xff;
+}
+
+
+static INLINE void c32to48(word32 in, byte out[6])
+{
+    out[0] = 0;
+    out[1] = 0;
+    out[2] = (in >> 24) & 0xff;
+    out[3] = (in >> 16) & 0xff;
+    out[4] = (in >>  8) & 0xff;
+    out[5] =  in & 0xff;
+}
+
+
+/* convert 16 bit integer to opaque */
+static void INLINE c16toa(word16 u16, byte* c)
+{
+    c[0] = (u16 >> 8) & 0xff;
+    c[1] =  u16 & 0xff;
+}
+
+
+/* convert 32 bit integer to opaque */
+static INLINE void c32toa(word32 u32, byte* c)
+{
+    c[0] = (u32 >> 24) & 0xff;
+    c[1] = (u32 >> 16) & 0xff;
+    c[2] = (u32 >>  8) & 0xff;
+    c[3] =  u32 & 0xff;
+}
+
+
+/* convert a 24 bit integer into a 32 bit one */
+static INLINE void c24to32(const word24 u24, word32* u32)
+{
+    *u32 = 0;
+    *u32 = (u24[0] << 16) | (u24[1] << 8) | u24[2];
+}
+
+
+/* convert opaque to 16 bit integer */
+static INLINE void ato16(const byte* c, word16* u16)
+{
+    *u16 = 0;
+    *u16 = (c[0] << 8) | (c[1]);
+}
+
+
+/* convert opaque to 32 bit integer */
+static INLINE void ato32(const byte* c, word32* u32)
+{
+    *u32 = 0;
+    *u32 = (c[0] << 24) | (c[1] << 16) | (c[2] << 8) | c[3];
+}
+
+
+#ifdef HAVE_LIBZ
+
+    /* alloc user allocs to work with zlib */
+    void* myAlloc(void* opaque, unsigned int item, unsigned int size)
+    {
+        return XMALLOC(item * size, opaque, DYNAMIC_TYPE_LIBZ);
+    }
+
+
+    void myFree(void* opaque, void* memory)
+    {
+        XFREE(memory, opaque, DYNAMIC_TYPE_LIBZ);
+    }
+
+
+    /* init zlib comp/decomp streams, 0 on success */
+    static int InitStreams(SSL* ssl)
+    {
+        ssl->c_stream.zalloc = (alloc_func)myAlloc;
+        ssl->c_stream.zfree  = (free_func)myFree;
+        ssl->c_stream.opaque = (voidpf)ssl->heap;
+
+        if (deflateInit(&ssl->c_stream, 8) != Z_OK) return ZLIB_INIT_ERROR;
+
+        ssl->didStreamInit = 1;
+
+        ssl->d_stream.zalloc = (alloc_func)myAlloc;
+        ssl->d_stream.zfree  = (free_func)myFree;
+        ssl->d_stream.opaque = (voidpf)ssl->heap;
+
+        if (inflateInit(&ssl->d_stream) != Z_OK) return ZLIB_INIT_ERROR;
+
+        return 0;
+    }
+
+
+    static void FreeStreams(SSL* ssl)
+    {
+        if (ssl->didStreamInit) {
+            deflateEnd(&ssl->c_stream);
+            inflateEnd(&ssl->d_stream);
+        }
+    }
+
+
+    /* compress in to out, return out size or error */
+    static int Compress(SSL* ssl, byte* in, int inSz, byte* out, int outSz)
+    {
+        int    err;
+        int    currTotal = ssl->c_stream.total_out;
+
+        /* put size in front of compression */
+        c16toa((word16)inSz, out);
+        out   += 2;
+        outSz -= 2;
+
+        ssl->c_stream.next_in   = in;
+        ssl->c_stream.avail_in  = inSz;
+        ssl->c_stream.next_out  = out;
+        ssl->c_stream.avail_out = outSz;
+
+        err = deflate(&ssl->c_stream, Z_SYNC_FLUSH);
+        if (err != Z_OK && err != Z_STREAM_END) return ZLIB_COMPRESS_ERROR;
+
+        return ssl->c_stream.total_out - currTotal + sizeof(word16);
+    }
+        
+
+    /* decompress in to out, returnn out size or error */
+    static int DeCompress(SSL* ssl, byte* in, int inSz, byte* out, int outSz)
+    {
+        int    err;
+        int    currTotal = ssl->d_stream.total_out;
+        word16 len;
+
+        /* find size in front of compression */
+        ato16(in, &len);
+        in   += 2;
+        inSz -= 2;
+
+        ssl->d_stream.next_in   = in;
+        ssl->d_stream.avail_in  = inSz;
+        ssl->d_stream.next_out  = out;
+        ssl->d_stream.avail_out = outSz;
+
+        err = inflate(&ssl->d_stream, Z_SYNC_FLUSH);
+        if (err != Z_OK && err != Z_STREAM_END) return ZLIB_DECOMPRESS_ERROR;
+
+        return ssl->d_stream.total_out - currTotal;
+    }
+        
+#endif /* HAVE_LIBZ */
+
+
+void InitSSL_Method(SSL_METHOD* method, ProtocolVersion pv)
+{
+    method->version    = pv;
+    method->side       = CLIENT_END;
+    method->verifyPeer = 0;
+    method->verifyNone = 0;
+    method->failNoCert = 0;
+    method->downgrade  = 0;
+}
+
+
+void InitSSL_Ctx(SSL_CTX* ctx, SSL_METHOD* method)
+{
+    ctx->method = method;
+    ctx->certificate.buffer = 0;
+    ctx->privateKey.buffer  = 0;
+    ctx->haveDH             = 0;
+    ctx->haveNTRU           = 0;    /* start off */
+    ctx->haveECDSA          = 0;    /* start off */
+    ctx->heap               = ctx;  /* defaults to self */
+#ifndef NO_PSK
+    ctx->havePSK            = 0;
+    ctx->server_hint[0]     = 0;
+    ctx->client_psk_cb      = 0;
+    ctx->server_psk_cb      = 0;
+#endif /* NO_PSK */
+
+#ifdef OPENSSL_EXTRA
+    ctx->passwd_cb   = 0;
+    ctx->userdata    = 0;
+#endif /* OPENSSL_EXTRA */
+
+#ifndef CYASSL_USER_IO
+    ctx->CBIORecv = EmbedReceive;
+    ctx->CBIOSend = EmbedSend;
+#else
+    /* user will set */
+    ctx->CBIORecv = NULL;
+    ctx->CBIOSend = NULL;
+#endif
+    ctx->partialWrite   = 0;
+    ctx->verifyCallback = 0;
+
+    ctx->caList = 0;
+#ifdef HAVE_NTRU
+    if (method->side == CLIENT_END)
+        ctx->haveNTRU = 1;           /* always on cliet side */
+                                     /* server can turn on by loading key */
+#endif
+#ifdef HAVE_ECC
+    if (method->side == CLIENT_END)
+        ctx->haveECDSA = 1;          /* always on cliet side */
+                                     /* server can turn on by loading key */
+#endif
+    /* remove DH later if server didn't set, add psk later */
+    InitSuites(&ctx->suites, method->version, TRUE, FALSE, ctx->haveNTRU,
+               ctx->haveECDSA, method->side);  
+    ctx->verifyPeer = 0;
+    ctx->verifyNone = 0;
+    ctx->failNoCert = 0;
+    ctx->sessionCacheOff      = 0;  /* initially on */
+    ctx->sessionCacheFlushOff = 0;  /* initially on */
+    ctx->sendVerify = 0;
+    ctx->quietShutdown = 0;
+
+}
+
+
+/* In case contexts are held in array and don't want to free actual ctx */
+void SSL_CtxResourceFree(SSL_CTX* ctx)
+{
+    XFREE(ctx->privateKey.buffer, ctx->heap, DYNAMIC_TYPE_KEY);
+    XFREE(ctx->certificate.buffer, ctx->heap, DYNAMIC_TYPE_CERT);
+    XFREE(ctx->method, ctx->heap, DYNAMIC_TYPE_METHOD);
+
+    FreeSigners(ctx->caList, ctx->heap);
+}
+
+
+void FreeSSL_Ctx(SSL_CTX* ctx)
+{
+    SSL_CtxResourceFree(ctx);
+    XFREE(ctx, ctx->heap, DYNAMIC_TYPE_CTX);
+}
+
+    
+
+void InitSuites(Suites* suites, ProtocolVersion pv, byte haveDH, byte havePSK,
+                byte haveNTRU, byte haveECDSA, int side)
+{
+    word32 idx = 0;
+    int    tls = pv.major == 3 && pv.minor >= 1;
+    int    haveRSA = 1;
+
+    (void)tls;  /* shut up compiler */
+
+    if (side == SERVER_END && haveECDSA)
+        haveRSA = 0;   /* can't do RSA with ECDSA cert */
+
+#ifdef CYASSL_DTLS
+    if (pv.major == DTLS_MAJOR && pv.minor == DTLS_MINOR)
+        tls = 1;
+#endif
+
+    suites->setSuites = 0;  /* user hasn't set yet */
+
+#ifdef BUILD_TLS_NTRU_RSA_WITH_AES_256_CBC_SHA
+    if (tls && haveNTRU && haveRSA) {
+        suites->suites[idx++] = 0; 
+        suites->suites[idx++] = TLS_NTRU_RSA_WITH_AES_256_CBC_SHA;
+    }
+#endif
+
+#ifdef BUILD_TLS_NTRU_RSA_WITH_AES_128_CBC_SHA
+    if (tls && haveNTRU && haveRSA) {
+        suites->suites[idx++] = 0; 
+        suites->suites[idx++] = TLS_NTRU_RSA_WITH_AES_128_CBC_SHA;
+    }
+#endif
+
+#ifdef BUILD_TLS_NTRU_RSA_WITH_RC4_128_SHA
+    if (tls && haveNTRU && haveRSA) {
+        suites->suites[idx++] = 0; 
+        suites->suites[idx++] = TLS_NTRU_RSA_WITH_RC4_128_SHA;
+    }
+#endif
+
+#ifdef BUILD_TLS_NTRU_RSA_WITH_3DES_EDE_CBC_SHA
+    if (tls && haveNTRU && haveRSA) {
+        suites->suites[idx++] = 0; 
+        suites->suites[idx++] = TLS_NTRU_RSA_WITH_3DES_EDE_CBC_SHA;
+    }
+#endif
+
+#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
+    if (tls && haveECDSA) {
+        suites->suites[idx++] = ECC_BYTE; 
+        suites->suites[idx++] = TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA;
+    }
+#endif
+
+#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA
+    if (tls && haveECDSA) {
+        suites->suites[idx++] = ECC_BYTE; 
+        suites->suites[idx++] = TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA;
+    }
+#endif
+
+#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_RC4_128_SHA
+    if (tls && haveECDSA) {
+        suites->suites[idx++] = ECC_BYTE; 
+        suites->suites[idx++] = TLS_ECDHE_ECDSA_WITH_RC4_128_SHA;
+    }
+#endif
+
+#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA
+    if (tls && haveECDSA) {
+        suites->suites[idx++] = ECC_BYTE; 
+        suites->suites[idx++] = TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA;
+    }
+#endif
+
+#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
+    if (tls && haveRSA) {
+        suites->suites[idx++] = ECC_BYTE; 
+        suites->suites[idx++] = TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA;
+    }
+#endif
+
+#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
+    if (tls && haveRSA) {
+        suites->suites[idx++] = ECC_BYTE; 
+        suites->suites[idx++] = TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA;
+    }
+#endif
+
+#ifdef BUILD_TLS_ECDHE_RSA_WITH_RC4_128_SHA
+    if (tls && haveRSA) {
+        suites->suites[idx++] = ECC_BYTE; 
+        suites->suites[idx++] = TLS_ECDHE_RSA_WITH_RC4_128_SHA;
+    }
+#endif
+
+#ifdef BUILD_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA
+    if (tls && haveRSA) {
+        suites->suites[idx++] = ECC_BYTE; 
+        suites->suites[idx++] = TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA;
+    }
+#endif
+
+#ifdef BUILD_TLS_DHE_RSA_WITH_AES_256_CBC_SHA
+    if (tls && haveDH && haveRSA) {
+        suites->suites[idx++] = 0; 
+        suites->suites[idx++] = TLS_DHE_RSA_WITH_AES_256_CBC_SHA;
+    }
+#endif
+
+#ifdef BUILD_TLS_DHE_RSA_WITH_AES_128_CBC_SHA
+    if (tls && haveDH && haveRSA) {
+        suites->suites[idx++] = 0; 
+        suites->suites[idx++] = TLS_DHE_RSA_WITH_AES_128_CBC_SHA;
+    }
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_AES_256_CBC_SHA
+    if (tls && haveRSA) {
+        suites->suites[idx++] = 0; 
+        suites->suites[idx++] = TLS_RSA_WITH_AES_256_CBC_SHA;
+    }
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_AES_128_CBC_SHA
+    if (tls && haveRSA) {
+        suites->suites[idx++] = 0; 
+        suites->suites[idx++] = TLS_RSA_WITH_AES_128_CBC_SHA;
+    }
+#endif
+
+#ifdef BUILD_TLS_PSK_WITH_AES_256_CBC_SHA
+    if (tls && havePSK) {
+        suites->suites[idx++] = 0; 
+        suites->suites[idx++] = TLS_PSK_WITH_AES_256_CBC_SHA;
+    }
+#endif
+
+#ifdef BUILD_TLS_PSK_WITH_AES_128_CBC_SHA
+    if (tls && havePSK) {
+        suites->suites[idx++] = 0; 
+        suites->suites[idx++] = TLS_PSK_WITH_AES_128_CBC_SHA;
+    }
+#endif
+
+#ifdef BUILD_SSL_RSA_WITH_RC4_128_SHA
+    if (haveRSA ) {
+        suites->suites[idx++] = 0; 
+        suites->suites[idx++] = SSL_RSA_WITH_RC4_128_SHA;
+    }
+#endif
+
+#ifdef BUILD_SSL_RSA_WITH_RC4_128_MD5
+    if (haveRSA ) {
+        suites->suites[idx++] = 0; 
+        suites->suites[idx++] = SSL_RSA_WITH_RC4_128_MD5;
+    }
+#endif
+
+#ifdef BUILD_SSL_RSA_WITH_3DES_EDE_CBC_SHA
+    if (haveRSA ) {
+        suites->suites[idx++] = 0; 
+        suites->suites[idx++] = SSL_RSA_WITH_3DES_EDE_CBC_SHA;
+    }
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_HC_128_CBC_MD5
+    if (tls && haveRSA) {
+        suites->suites[idx++] = 0; 
+        suites->suites[idx++] = TLS_RSA_WITH_HC_128_CBC_MD5;
+    }
+#endif
+    
+#ifdef BUILD_TLS_RSA_WITH_HC_128_CBC_SHA
+    if (tls && haveRSA) {
+        suites->suites[idx++] = 0; 
+        suites->suites[idx++] = TLS_RSA_WITH_HC_128_CBC_SHA;
+    }
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_RABBIT_CBC_SHA
+    if (tls && haveRSA) {
+        suites->suites[idx++] = 0; 
+        suites->suites[idx++] = TLS_RSA_WITH_RABBIT_CBC_SHA;
+    }
+#endif
+
+    suites->suiteSz = idx;
+}
+
+
+int InitSSL(SSL* ssl, SSL_CTX* ctx)
+{
+    int  ret;
+    byte havePSK = 0;
+
+    ssl->ctx     = ctx; /* only for passing to calls, options could change */
+    ssl->version = ctx->method->version;
+    ssl->suites  = ctx->suites;
+
+#ifdef HAVE_LIBZ
+    ssl->didStreamInit = 0;
+#endif
+   
+    ssl->buffers.certificate.buffer   = 0;
+    ssl->buffers.key.buffer           = 0;
+    ssl->buffers.inputBuffer.length   = 0;
+    ssl->buffers.inputBuffer.idx      = 0;
+    ssl->buffers.inputBuffer.buffer = ssl->buffers.inputBuffer.staticBuffer;
+    ssl->buffers.inputBuffer.bufferSize  = STATIC_BUFFER_LEN;
+    ssl->buffers.inputBuffer.dynamicFlag = 0;
+    ssl->buffers.outputBuffer.length  = 0;
+    ssl->buffers.outputBuffer.idx     = 0;
+    ssl->buffers.outputBuffer.buffer = ssl->buffers.outputBuffer.staticBuffer;
+    ssl->buffers.outputBuffer.bufferSize  = STATIC_BUFFER_LEN;
+    ssl->buffers.outputBuffer.dynamicFlag = 0;
+    ssl->buffers.domainName.buffer    = 0;
+    ssl->buffers.serverDH_P.buffer    = 0;
+    ssl->buffers.serverDH_G.buffer    = 0;
+    ssl->buffers.serverDH_Pub.buffer  = 0;
+    ssl->buffers.serverDH_Priv.buffer = 0;
+    ssl->buffers.clearOutputBuffer.buffer  = 0;
+    ssl->buffers.clearOutputBuffer.length  = 0;
+    ssl->buffers.prevSent                  = 0;
+    ssl->buffers.plainSz                   = 0;
+
+    if ( (ret = InitRng(&ssl->rng)) )
+        return ret;
+
+    InitMd5(&ssl->hashMd5);
+    InitSha(&ssl->hashSha);
+    InitRsaKey(&ssl->peerRsaKey, ctx->heap);
+
+    ssl->peerRsaKeyPresent = 0;
+    ssl->options.side      = ctx->method->side;
+    ssl->options.downgrade = ctx->method->downgrade;
+    ssl->error = 0;
+    ssl->options.connReset = 0;
+    ssl->options.isClosed  = 0;
+    ssl->options.closeNotify  = 0;
+    ssl->options.sentNotify   = 0;
+    ssl->options.usingCompression = 0;
+    ssl->options.haveDH    = ctx->haveDH;
+    ssl->options.haveNTRU  = ctx->haveNTRU;
+    ssl->options.haveECDSA = ctx->haveECDSA;
+    ssl->options.havePeerCert = 0; 
+    ssl->options.usingPSK_cipher = 0;
+    ssl->options.sendAlertState = 0;
+#ifndef NO_PSK
+    havePSK = ctx->havePSK;
+    ssl->options.havePSK   = ctx->havePSK;
+    ssl->options.client_psk_cb = ctx->client_psk_cb;
+    ssl->options.server_psk_cb = ctx->server_psk_cb;
+#endif /* NO_PSK */
+
+    ssl->options.serverState = NULL_STATE;
+    ssl->options.clientState = NULL_STATE;
+    ssl->options.connectState = CONNECT_BEGIN;
+    ssl->options.acceptState  = ACCEPT_BEGIN; 
+    ssl->options.handShakeState  = NULL_STATE; 
+    ssl->options.processReply = doProcessInit;
+
+#ifdef CYASSL_DTLS
+    ssl->keys.dtls_sequence_number       = 0;
+    ssl->keys.dtls_peer_sequence_number  = 0;
+    ssl->keys.dtls_handshake_number      = 0;
+    ssl->keys.dtls_epoch      = 0;
+    ssl->keys.dtls_peer_epoch = 0;
+#endif
+    ssl->keys.encryptionOn = 0;     /* initially off */
+    ssl->options.sessionCacheOff      = ctx->sessionCacheOff;
+    ssl->options.sessionCacheFlushOff = ctx->sessionCacheFlushOff;
+
+    ssl->options.verifyPeer = ctx->verifyPeer;
+    ssl->options.verifyNone = ctx->verifyNone;
+    ssl->options.failNoCert = ctx->failNoCert;
+    ssl->options.sendVerify = ctx->sendVerify;
+    
+    ssl->options.resuming = 0;
+    ssl->hmac = Hmac;         /* default to SSLv3 */
+    ssl->heap = ctx->heap;    /* defaults to self */
+    ssl->options.tls    = 0;
+    ssl->options.tls1_1 = 0;
+    ssl->options.dtls   = 0;
+    ssl->options.partialWrite  = ctx->partialWrite;
+    ssl->options.quietShutdown = ctx->quietShutdown;
+
+    /* SSL_CTX still owns certificate, key, and caList buffers */
+    ssl->buffers.certificate = ctx->certificate;
+    ssl->buffers.key = ctx->privateKey;
+    ssl->caList = ctx->caList;
+
+#ifdef OPENSSL_EXTRA
+    ssl->peerCert.issuer.sz    = 0;
+    ssl->peerCert.subject.sz   = 0;
+#endif
+    
+    /* make sure server has cert and key unless using PSK */
+    if (ssl->options.side == SERVER_END && !havePSK)
+        if (!ssl->buffers.certificate.buffer || !ssl->buffers.key.buffer)
+            return NO_PRIVATE_KEY;
+
+#ifndef NO_PSK
+    ssl->arrays.client_identity[0] = 0;
+    if (ctx->server_hint[0])   /* set in CTX */
+        XSTRNCPY(ssl->arrays.server_hint, ctx->server_hint, MAX_PSK_ID_LEN);
+    else
+        ssl->arrays.server_hint[0] = 0;
+#endif /* NO_PSK */
+
+#ifdef CYASSL_CALLBACKS
+    ssl->hsInfoOn = 0;
+    ssl->toInfoOn = 0;
+#endif
+
+#ifdef HAVE_ECC
+    ssl->peerEccKeyPresent = 0;
+    ecc_init(&ssl->peerEccKey);
+    ssl->peerEccDsaKeyPresent = 0;
+    ecc_init(&ssl->peerEccDsaKey);
+    ssl->eccDsaKeyPresent = 0;
+    ecc_init(&ssl->eccDsaKey);
+    ssl->eccTempKeyPresent = 0;
+    ecc_init(&ssl->eccTempKey);
+
+    /* make ECDHE for server side */
+    if (ssl->options.side == SERVER_END) {
+        if (ecc_make_key(&ssl->rng, ECDHE_SIZE, &ssl->eccTempKey) != 0)
+            return ECC_MAKEKEY_ERROR;
+        ssl->eccTempKeyPresent = 1;
+    }
+#endif
+
+    /* make sure server has DH parms, and add PSK if there, add NTRU too */
+    if (!ssl->ctx->suites.setSuites) {    /* trust user override */
+        if (ssl->options.side == SERVER_END) 
+            InitSuites(&ssl->suites, ssl->version,ssl->options.haveDH, havePSK,
+                       ssl->options.haveNTRU, ssl->options.haveECDSA,
+                       ssl->ctx->method->side);
+        else 
+            InitSuites(&ssl->suites, ssl->version, TRUE, havePSK,
+                       ssl->options.haveNTRU, ssl->options.haveECDSA,
+                       ssl->ctx->method->side);
+    }
+
+    ssl->rfd = -1;   /* set to invalid descriptor */
+    ssl->wfd = -1;
+    ssl->biord = 0;
+    ssl->biowr = 0;
+
+    ssl->IOCB_ReadCtx  = &ssl->rfd;   /* prevent invalid pointer acess if not */
+    ssl->IOCB_WriteCtx = &ssl->wfd;   /* correctly set */
+
+#ifdef SESSION_CERTS
+    ssl->session.chain.count = 0;
+#endif
+
+    ssl->cipher.ssl = ssl;
+
+    return 0;
+}
+
+
+int BIO_free(BIO*);  /* cyassl_int doesn't have */
+
+
+/* In case holding SSL object in array and don't want to free actual ssl */
+void SSL_ResourceFree(SSL* ssl)
+{
+    XFREE(ssl->buffers.serverDH_Priv.buffer, ssl->heap, DYNAMIC_TYPE_DH);
+    XFREE(ssl->buffers.serverDH_Pub.buffer, ssl->heap, DYNAMIC_TYPE_DH);
+    XFREE(ssl->buffers.serverDH_G.buffer, ssl->heap, DYNAMIC_TYPE_DH);
+    XFREE(ssl->buffers.serverDH_P.buffer, ssl->heap, DYNAMIC_TYPE_DH);
+    XFREE(ssl->buffers.domainName.buffer, ssl->heap, DYNAMIC_TYPE_DOMAIN);
+    FreeRsaKey(&ssl->peerRsaKey);
+    if (ssl->buffers.inputBuffer.dynamicFlag)
+        ShrinkInputBuffer(ssl, FORCED_FREE);
+    if (ssl->buffers.outputBuffer.dynamicFlag)
+        ShrinkOutputBuffer(ssl);
+#if defined(OPENSSL_EXTRA) || defined(GOAHEAD_WS)
+    BIO_free(ssl->biord);
+    if (ssl->biord != ssl->biowr)        /* in case same as write */
+        BIO_free(ssl->biowr);
+#endif
+#ifdef HAVE_LIBZ
+    FreeStreams(ssl);
+#endif
+#ifdef HAVE_ECC
+    ecc_free(&ssl->peerEccKey);
+    ecc_free(&ssl->peerEccDsaKey);
+    ecc_free(&ssl->eccTempKey);
+    ecc_free(&ssl->eccDsaKey);
+#endif
+}
+
+
+void FreeSSL(SSL* ssl)
+{
+    SSL_ResourceFree(ssl);
+    XFREE(ssl, ssl->heap, DYNAMIC_TYPE_SSL);
+}
+
+
+ProtocolVersion MakeSSLv3(void)
+{
+    ProtocolVersion pv;
+    pv.major = SSLv3_MAJOR;
+    pv.minor = SSLv3_MINOR;
+
+    return pv;
+}
+
+
+#ifdef CYASSL_DTLS
+
+ProtocolVersion MakeDTLSv1(void)
+{
+    ProtocolVersion pv;
+    pv.major = DTLS_MAJOR;
+    pv.minor = DTLS_MINOR;
+
+    return pv;
+}
+
+#endif /* CYASSL_DTLS */
+
+
+
+
+#ifdef USE_WINDOWS_API 
+
+    timer_d Timer(void)
+    {
+        static int           init = 0;
+        static LARGE_INTEGER freq;
+        LARGE_INTEGER        count;
+    
+        if (!init) {
+            QueryPerformanceFrequency(&freq);
+            init = 1;
+        }
+
+        QueryPerformanceCounter(&count);
+
+        return (double)count.QuadPart / freq.QuadPart;
+    }
+
+
+    word32 LowResTimer(void)
+    {
+        return (word32)Timer();
+    }
+
+
+#elif defined(THREADX)
+
+    #include "rtptime.h"
+
+    word32 LowResTimer(void)
+    {
+        return (word32)rtp_get_system_sec();
+    }
+
+
+#elif defined(MICRIUM)
+
+    word32 LowResTimer(void)
+    {
+        NET_SECURE_OS_TICK  clk;
+
+        #if (NET_SECURE_MGR_CFG_EN == DEF_ENABLED)
+            clk = NetSecure_OS_TimeGet();
+        #endif
+        return (word32)clk;
+    }
+
+#elif defined(USER_TICKS)
+
+    word32 LowResTimer(void)
+    {
+        /*
+        write your own clock tick function if don't want time(0)
+        needs second accuracy but doesn't have to correlated to EPOCH
+        */
+    }
+
+#else /* !USE_WINDOWS_API && !THREADX && !MICRIUM && !USER_TICKS */
+
+    #include 
+
+    word32 LowResTimer(void)
+    {
+        return time(0); 
+    }
+
+
+#endif /* USE_WINDOWS_API */
+
+
+/* add output to md5 and sha handshake hashes, exclude record header */
+static void HashOutput(SSL* ssl, const byte* output, int sz, int ivSz)
+{
+    const byte* buffer = output + RECORD_HEADER_SZ + ivSz;
+    sz -= RECORD_HEADER_SZ;
+    
+#ifdef CYASSL_DTLS
+    if (ssl->options.dtls) {
+        buffer += DTLS_RECORD_EXTRA;
+        sz     -= DTLS_RECORD_EXTRA;
+    }
+#endif
+
+    Md5Update(&ssl->hashMd5, buffer, sz);
+    ShaUpdate(&ssl->hashSha, buffer, sz);
+}
+
+
+/* add input to md5 and sha handshake hashes, include handshake header */
+static void HashInput(SSL* ssl, const byte* input, int sz)
+{
+    const byte* buffer = input - HANDSHAKE_HEADER_SZ;
+    sz += HANDSHAKE_HEADER_SZ;
+    
+#ifdef CYASSL_DTLS
+    if (ssl->options.dtls) {
+        buffer -= DTLS_HANDSHAKE_EXTRA;
+        sz     += DTLS_HANDSHAKE_EXTRA;
+    }
+#endif
+
+    Md5Update(&ssl->hashMd5, buffer, sz);
+    ShaUpdate(&ssl->hashSha, buffer, sz);
+}
+
+
+/* add record layer header for message */
+static void AddRecordHeader(byte* output, word32 length, byte type, SSL* ssl)
+{
+    RecordLayerHeader* rl;
+  
+    /* record layer header */
+    rl = (RecordLayerHeader*)output;
+    rl->type    = type;
+    rl->version = ssl->version;           /* type and version same in each */
+
+    if (!ssl->options.dtls)
+        c16toa((word16)length, rl->length);
+    else {
+#ifdef CYASSL_DTLS
+        DtlsRecordLayerHeader* dtls;
+    
+        /* dtls record layer header extensions */
+        dtls = (DtlsRecordLayerHeader*)output;
+        c16toa(ssl->keys.dtls_epoch, dtls->epoch);
+        c32to48(ssl->keys.dtls_sequence_number++, dtls->sequence_number);
+        c16toa((word16)length, dtls->length);
+#endif
+    }
+}
+
+
+/* add handshake header for message */
+static void AddHandShakeHeader(byte* output, word32 length, byte type, SSL* ssl)
+{
+    HandShakeHeader* hs;
+ 
+    /* handshake header */
+    hs = (HandShakeHeader*)output;
+    hs->type = type;
+    c32to24(length, hs->length);         /* type and length same for each */
+#ifdef CYASSL_DTLS
+    if (ssl->options.dtls) {
+        DtlsHandShakeHeader* dtls;
+    
+        /* dtls handshake header extensions */
+        dtls = (DtlsHandShakeHeader*)output;
+        c16toa(ssl->keys.dtls_handshake_number++, dtls->message_seq);
+        c32to24(0, dtls->fragment_offset);
+        c32to24(length, dtls->fragment_length);
+    }
+#endif
+}
+
+
+/* add both headers for handshake message */
+static void AddHeaders(byte* output, word32 length, byte type, SSL* ssl)
+{
+    if (!ssl->options.dtls) {
+        AddRecordHeader(output, length + HANDSHAKE_HEADER_SZ, handshake, ssl);
+        AddHandShakeHeader(output + RECORD_HEADER_SZ, length, type, ssl);
+    }
+    else  {
+        AddRecordHeader(output, length+DTLS_HANDSHAKE_HEADER_SZ, handshake,ssl);
+        AddHandShakeHeader(output + DTLS_RECORD_HEADER_SZ, length, type, ssl);
+    }
+}
+
+
+static int Receive(SSL* ssl, byte* buf, word32 sz, int flags)
+{
+    int recvd;
+
+retry:
+    recvd = ssl->ctx->CBIORecv((char *)buf, (int)sz, ssl->IOCB_ReadCtx);
+    if (recvd < 0)
+        switch (recvd) {
+            case IO_ERR_GENERAL:        /* general/unknown error */
+                return -1;
+
+            case IO_ERR_WANT_READ:      /* want read, would block */
+                return WANT_READ;
+
+            case IO_ERR_CONN_RST:       /* connection reset */
+                ssl->options.connReset = 1;
+                return -1;
+
+            case IO_ERR_ISR:            /* interrupt */
+                /* see if we got our timeout */
+                #ifdef CYASSL_CALLBACKS
+                    if (ssl->toInfoOn) {
+                        struct itimerval timeout;
+                        getitimer(ITIMER_REAL, &timeout);
+                        if (timeout.it_value.tv_sec == 0 && 
+                                                timeout.it_value.tv_usec == 0) {
+                            XSTRNCPY(ssl->timeoutInfo.timeoutName,
+                                    "recv() timeout", MAX_TIMEOUT_NAME_SZ);
+                            return 0;
+                        }
+                    }
+                #endif
+                goto retry;
+
+            case IO_ERR_CONN_CLOSE:     /* peer closed connection */
+                ssl->options.isClosed = 1;
+                return -1;
+        }
+
+    return recvd;
+}
+
+
+/* Switch dynamic output buffer back to static, buffer is assumed clear */
+void ShrinkOutputBuffer(SSL* ssl)
+{
+    CYASSL_MSG("Shrinking output buffer\n");
+    XFREE(ssl->buffers.outputBuffer.buffer, ssl->heap, DYNAMIC_TYPE_OUT_BUFFER);
+    ssl->buffers.outputBuffer.buffer = ssl->buffers.outputBuffer.staticBuffer;
+    ssl->buffers.outputBuffer.bufferSize  = STATIC_BUFFER_LEN;
+    ssl->buffers.outputBuffer.dynamicFlag = 0;
+}
+
+
+/* Switch dynamic input buffer back to static, keep any remaining input */
+/* forced free means cleaning up */
+void ShrinkInputBuffer(SSL* ssl, int forcedFree)
+{
+    int usedLength = ssl->buffers.inputBuffer.length -
+                     ssl->buffers.inputBuffer.idx;
+    if (!forcedFree && usedLength > STATIC_BUFFER_LEN)
+        return;
+
+    CYASSL_MSG("Shrinking input buffer\n");
+
+    if (!forcedFree && usedLength)
+        XMEMCPY(ssl->buffers.inputBuffer.staticBuffer,
+               ssl->buffers.inputBuffer.buffer + ssl->buffers.inputBuffer.idx,
+               usedLength);
+
+    XFREE(ssl->buffers.inputBuffer.buffer, ssl->heap, DYNAMIC_TYPE_IN_BUFFER);
+    ssl->buffers.inputBuffer.buffer = ssl->buffers.inputBuffer.staticBuffer;
+    ssl->buffers.inputBuffer.bufferSize  = STATIC_BUFFER_LEN;
+    ssl->buffers.inputBuffer.dynamicFlag = 0;
+    ssl->buffers.inputBuffer.idx = 0;
+    ssl->buffers.inputBuffer.length = usedLength;
+}
+
+
+int SendBuffered(SSL* ssl)
+{
+    while (ssl->buffers.outputBuffer.length > 0) {
+        int sent = ssl->ctx->CBIOSend((char*)ssl->buffers.outputBuffer.buffer +
+                                      ssl->buffers.outputBuffer.idx,
+                                      (int)ssl->buffers.outputBuffer.length,
+                                      ssl->IOCB_WriteCtx);
+        if (sent < 0) {
+            switch (sent) {
+
+                case IO_ERR_WANT_WRITE:        /* would block */
+                    return WANT_WRITE;
+
+                case IO_ERR_CONN_RST:          /* connection reset */
+                    ssl->options.connReset = 1;
+                    break;
+
+                case IO_ERR_ISR:               /* interrupt */
+                    /* see if we got our timeout */
+                    #ifdef CYASSL_CALLBACKS
+                        if (ssl->toInfoOn) {
+                            struct itimerval timeout;
+                            getitimer(ITIMER_REAL, &timeout);
+                            if (timeout.it_value.tv_sec == 0 && 
+                                                timeout.it_value.tv_usec == 0) {
+                                XSTRNCPY(ssl->timeoutInfo.timeoutName,
+                                        "send() timeout", MAX_TIMEOUT_NAME_SZ);
+                                return WANT_WRITE;
+                            }
+                        }
+                    #endif
+                    continue;
+
+                case IO_ERR_CONN_CLOSE: /* epipe / conn closed, same as reset */
+                    ssl->options.connReset = 1;
+                    break;
+            }
+
+            return SOCKET_ERROR_E;
+        }
+
+        ssl->buffers.outputBuffer.idx += sent;
+        ssl->buffers.outputBuffer.length -= sent;
+    }
+      
+    ssl->buffers.outputBuffer.idx = 0;
+
+    if (ssl->buffers.outputBuffer.dynamicFlag)
+        ShrinkOutputBuffer(ssl);
+
+    return 0;
+}
+
+
+/* Grow the output buffer, should only be to send cert, should be blank */
+static INLINE int GrowOutputBuffer(SSL* ssl, int size)
+{
+    byte* tmp = (byte*) XMALLOC(size + ssl->buffers.outputBuffer.length,
+                                ssl->heap, DYNAMIC_TYPE_OUT_BUFFER);
+    CYASSL_MSG("growing output buffer\n");
+   
+    if (!tmp) return -1;
+
+    if (ssl->buffers.outputBuffer.length)
+        XMEMCPY(tmp, ssl->buffers.outputBuffer.buffer,
+               ssl->buffers.outputBuffer.length);
+
+    if (ssl->buffers.outputBuffer.dynamicFlag)
+        XFREE(ssl->buffers.outputBuffer.buffer, ssl->heap,
+              DYNAMIC_TYPE_OUT_BUFFER);
+    ssl->buffers.outputBuffer.dynamicFlag = 1;
+    ssl->buffers.outputBuffer.buffer = tmp;
+    ssl->buffers.outputBuffer.bufferSize = size +
+                                           ssl->buffers.outputBuffer.length; 
+    return 0;
+}
+
+
+/* Grow the input buffer, should only be to read cert or big app data */
+static INLINE int GrowInputBuffer(SSL* ssl, int size, int usedLength)
+{
+    byte* tmp = (byte*) XMALLOC(size + usedLength, ssl->heap,
+                                DYNAMIC_TYPE_IN_BUFFER);
+    CYASSL_MSG("growing input buffer\n");
+   
+    if (!tmp) return -1;
+
+    if (usedLength)
+        XMEMCPY(tmp, ssl->buffers.inputBuffer.buffer +
+                    ssl->buffers.inputBuffer.idx, usedLength);
+
+    if (ssl->buffers.inputBuffer.dynamicFlag)
+        XFREE(ssl->buffers.inputBuffer.buffer,ssl->heap,DYNAMIC_TYPE_IN_BUFFER);
+
+    ssl->buffers.inputBuffer.dynamicFlag = 1;
+    ssl->buffers.inputBuffer.buffer = tmp;
+    ssl->buffers.inputBuffer.bufferSize = size + usedLength;
+    ssl->buffers.inputBuffer.idx    = 0;
+    ssl->buffers.inputBuffer.length = usedLength;
+
+    return 0;
+}
+
+
+/* check avalaible size into outbut buffer */
+static INLINE int CheckAvalaibleSize(SSL *ssl, int size)
+{
+    if ((word32)size > ssl->buffers.outputBuffer.bufferSize)
+        if (GrowOutputBuffer(ssl, size) < 0)
+            return MEMORY_E;
+
+    if (ssl->buffers.outputBuffer.bufferSize - ssl->buffers.outputBuffer.length
+                                             < (word32)size) {
+        if (SendBuffered(ssl) == SOCKET_ERROR_E)
+            return SOCKET_ERROR_E;
+        if (ssl->buffers.outputBuffer.bufferSize -
+                                ssl->buffers.outputBuffer.length < (word32)size)
+            return WANT_WRITE;
+    }
+    return 0;
+}
+
+/* do all verify and sanity checks on record header */
+static int GetRecordHeader(SSL* ssl, const byte* input, word32* inOutIdx,
+                           RecordLayerHeader* rh, word16 *size)
+{
+    if (!ssl->options.dtls) {
+        XMEMCPY(rh, input + *inOutIdx, RECORD_HEADER_SZ);
+        *inOutIdx += RECORD_HEADER_SZ;
+        ato16(rh->length, size);
+    }
+    else {
+#ifdef CYASSL_DTLS
+        /* type and version in same sport */
+        XMEMCPY(rh, input + *inOutIdx, ENUM_LEN + VERSION_SZ);
+        *inOutIdx += ENUM_LEN + VERSION_SZ;
+        *inOutIdx += 4;  /* skip epoch and first 2 seq bytes for now */
+        ato32(input + *inOutIdx, &ssl->keys.dtls_peer_sequence_number);
+        *inOutIdx += 4;  /* advance past rest of seq */
+        ato16(input + *inOutIdx, size);
+        *inOutIdx += LENGTH_SZ;
+#endif
+    }
+
+    /* catch version mismatch */
+    if (rh->version.major != ssl->version.major || 
+        rh->version.minor != ssl->version.minor) {
+        
+        if (ssl->options.side == SERVER_END && ssl->options.downgrade == 1 &&
+            ssl->options.acceptState == ACCEPT_BEGIN)
+            ;                                  /* haven't negotiated yet */
+        else
+            return VERSION_ERROR;              /* only use requested version */
+    }
+
+    /* record layer length check */
+    if (*size > (MAX_RECORD_SIZE + MAX_COMP_EXTRA + MAX_MSG_EXTRA))
+        return LENGTH_ERROR;
+
+    /* verify record type here as well */
+    switch ((enum ContentType)rh->type) {
+        case handshake:
+        case change_cipher_spec:
+        case application_data:
+        case alert:
+            break;
+        default:
+            return UNKNOWN_RECORD_TYPE;
+    }
+
+    return 0;
+}
+
+
+static int GetHandShakeHeader(SSL* ssl, const byte* input, word32* inOutIdx,
+                              byte *type, word32 *size)
+{
+    const byte *ptr = input + *inOutIdx;
+    *inOutIdx += HANDSHAKE_HEADER_SZ;
+    
+#ifdef CYASSL_DTLS
+    if (ssl->options.dtls)
+        *inOutIdx += DTLS_HANDSHAKE_EXTRA;
+#endif
+
+    *type = ptr[0];
+    c24to32(&ptr[1], size);
+
+    return 0;
+}
+
+
+/* fill with MD5 pad size since biggest required */
+static const byte PAD1[PAD_MD5] = 
+                              { 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+                                0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+                                0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+                                0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+                                0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+                                0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36
+                              };
+static const byte PAD2[PAD_MD5] =
+                              { 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
+                                0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
+                                0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
+                                0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
+                                0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
+                                0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c
+                              };
+
+/* calculate MD5 hash for finished */
+static void BuildMD5(SSL* ssl, Hashes* hashes, const byte* sender)
+{
+    byte md5_result[MD5_DIGEST_SIZE];
+
+    /* make md5 inner */    
+    Md5Update(&ssl->hashMd5, sender, SIZEOF_SENDER);
+    Md5Update(&ssl->hashMd5, ssl->arrays.masterSecret, SECRET_LEN);
+    Md5Update(&ssl->hashMd5, PAD1, PAD_MD5);
+    Md5Final(&ssl->hashMd5, md5_result);
+
+    /* make md5 outer */
+    Md5Update(&ssl->hashMd5, ssl->arrays.masterSecret, SECRET_LEN);
+    Md5Update(&ssl->hashMd5, PAD2, PAD_MD5);
+    Md5Update(&ssl->hashMd5, md5_result, MD5_DIGEST_SIZE);
+
+    Md5Final(&ssl->hashMd5, hashes->md5);
+}
+
+
+/* calculate SHA hash for finished */
+static void BuildSHA(SSL* ssl, Hashes* hashes, const byte* sender)
+{
+    byte sha_result[SHA_DIGEST_SIZE];
+
+    /* make sha inner */
+    ShaUpdate(&ssl->hashSha, sender, SIZEOF_SENDER);
+    ShaUpdate(&ssl->hashSha, ssl->arrays.masterSecret, SECRET_LEN);
+    ShaUpdate(&ssl->hashSha, PAD1, PAD_SHA);
+    ShaFinal(&ssl->hashSha, sha_result);
+
+    /* make sha outer */
+    ShaUpdate(&ssl->hashSha, ssl->arrays.masterSecret, SECRET_LEN);
+    ShaUpdate(&ssl->hashSha, PAD2, PAD_SHA);
+    ShaUpdate(&ssl->hashSha, sha_result, SHA_DIGEST_SIZE);
+
+    ShaFinal(&ssl->hashSha, hashes->sha);
+}
+
+
+static void BuildFinished(SSL* ssl, Hashes* hashes, const byte* sender)
+{
+    /* store current states, building requires get_digest which resets state */
+    Md5 md5 = ssl->hashMd5;
+    Sha sha = ssl->hashSha;
+
+    if (ssl->options.tls)
+        BuildTlsFinished(ssl, hashes, sender);
+    else {
+        BuildMD5(ssl, hashes, sender);
+        BuildSHA(ssl, hashes, sender);
+    }
+    
+    /* restore */
+    ssl->hashMd5 = md5;
+    ssl->hashSha = sha;
+}
+
+
+static int DoCertificate(SSL* ssl, byte* input, word32* inOutIdx)
+{
+    word32 listSz, i = *inOutIdx;
+    int    ret = 0;
+    int    firstTime = 1;  /* peer's is at front */
+    char   domain[ASN_NAME_MAX];
+
+    #ifdef CYASSL_CALLBACKS
+        if (ssl->hsInfoOn) AddPacketName("Certificate", &ssl->handShakeInfo);
+        if (ssl->toInfoOn) AddLateName("Certificate", &ssl->timeoutInfo);
+    #endif
+    c24to32(&input[i], &listSz);
+    i += CERT_HEADER_SZ;
+    
+    while (listSz && ret == 0) {
+        /* cert size */
+        buffer      myCert;
+        word32      certSz;
+        DecodedCert dCert;
+        word32      idx = 0;
+
+        c24to32(&input[i], &certSz);
+        i += CERT_HEADER_SZ;
+        
+        myCert.length = certSz;
+        myCert.buffer = input + i;
+        i += certSz;
+
+        listSz -= certSz + CERT_HEADER_SZ;
+
+#ifdef SESSION_CERTS
+        if (ssl->session.chain.count < MAX_CHAIN_DEPTH &&
+                                       myCert.length < MAX_X509_SIZE) {
+            ssl->session.chain.certs[ssl->session.chain.count].length =
+                 myCert.length;
+            XMEMCPY(ssl->session.chain.certs[ssl->session.chain.count].buffer,
+                   myCert.buffer, myCert.length);
+            ssl->session.chain.count++;
+        } else {
+            CYASSL_MSG("Couldn't store chain cert for session");
+        }
+#endif
+
+        InitDecodedCert(&dCert, myCert.buffer, ssl->heap);
+        ret = ParseCertRelative(&dCert, myCert.length, CERT_TYPE,
+                                !ssl->options.verifyNone, ssl->caList);
+
+        if (!firstTime) {
+            FreeDecodedCert(&dCert);
+            continue;
+        }
+
+        /* get rest of peer info in case user wants to continue */
+        if (ret != 0) {
+            if (!(ret == ASN_BEFORE_DATE_E || ret == ASN_AFTER_DATE_E ||
+                                              ret == ASN_SIG_CONFIRM_E)) {
+                FreeDecodedCert(&dCert);
+                continue;
+            }
+        }
+        
+        /* first one has peer's key */
+        firstTime = 0;
+
+        ssl->options.havePeerCert = 1;
+        /* set X509 format */
+#ifdef OPENSSL_EXTRA
+        ssl->peerCert.issuer.sz    = (int)XSTRLEN(dCert.issuer) + 1;
+        XSTRNCPY(ssl->peerCert.issuer.name, dCert.issuer, ASN_NAME_MAX);
+        ssl->peerCert.subject.sz   = (int)XSTRLEN(dCert.subject) + 1;
+        XSTRNCPY(ssl->peerCert.subject.name, dCert.subject, ASN_NAME_MAX);
+#endif    
+
+        XMEMCPY(domain, dCert.subjectCN, dCert.subjectCNLen);
+        domain[dCert.subjectCNLen] = '\0';
+
+        if (!ssl->options.verifyNone && ssl->buffers.domainName.buffer)
+            if (XSTRNCMP((char*)ssl->buffers.domainName.buffer,
+                        dCert.subjectCN,
+                        ssl->buffers.domainName.length - 1)) {
+                ret = DOMAIN_NAME_MISMATCH;   /* try to get peer key still */
+            }
+
+        /* decode peer key */
+        if (dCert.keyOID == RSAk) {
+            if (RsaPublicKeyDecode(dCert.publicKey, &idx,
+                               &ssl->peerRsaKey, dCert.pubKeySize) != 0) {
+                ret = PEER_KEY_ERROR;
+                FreeDecodedCert(&dCert);
+                continue;
+            }
+            ssl->peerRsaKeyPresent = 1;
+        }
+#ifdef HAVE_NTRU
+        else if (dCert.keyOID == NTRUk) {
+            if (dCert.pubKeySize > sizeof(ssl->peerNtruKey)) {
+                ret = PEER_KEY_ERROR;
+                FreeDecodedCert(&dCert);
+                continue;
+            }
+            XMEMCPY(ssl->peerNtruKey, dCert.publicKey, dCert.pubKeySize);
+            ssl->peerNtruKeyLen = (word16)dCert.pubKeySize;
+            ssl->peerNtruKeyPresent = 1;
+        }
+#endif /* HAVE_NTRU */
+#ifdef HAVE_ECC
+        else if (dCert.keyOID == ECDSAk) {
+            if (ecc_import_x963(dCert.publicKey, dCert.pubKeySize,
+                                &ssl->peerEccDsaKey) != 0) {
+                ret = PEER_KEY_ERROR;
+                FreeDecodedCert(&dCert);
+                continue;
+            }
+            ssl->peerEccDsaKeyPresent = 1;
+        }
+#endif /* HAVE_ECC */
+
+        FreeDecodedCert(&dCert);
+    }
+
+    if (ret == 0 && ssl->options.side == CLIENT_END)
+        ssl->options.serverState = SERVER_CERT_COMPLETE;
+
+    if (ret != 0) {
+        if (!ssl->options.verifyNone) {
+            int why = bad_certificate;
+            if (ret == ASN_AFTER_DATE_E || ret == ASN_BEFORE_DATE_E)
+                why = certificate_expired;
+            if (ssl->ctx->verifyCallback) {
+                int            ok;
+                X509_STORE_CTX store;
+
+                store.error = ret;
+                store.error_depth = 1;
+                store.domain = domain;
+#ifdef OPENSSL_EXTRA
+                store.current_cert = &ssl->peerCert;
+#else
+                store.current_cert = NULL;
+#endif
+                ok = ssl->ctx->verifyCallback(0, &store);
+                if (ok)
+                    ret = 0;
+            }
+            if (ret != 0) {
+                SendAlert(ssl, alert_fatal, why);   /* try to send */
+                ssl->options.isClosed = 1;
+            }
+        }
+        ssl->error = ret;
+    }
+
+    *inOutIdx = i;
+    return ret;
+}
+
+
+int DoFinished(SSL* ssl, const byte* input, word32* inOutIdx, int sniff)
+{
+    byte   verifyMAC[SHA_DIGEST_SIZE];
+    int    finishedSz = ssl->options.tls ? TLS_FINISHED_SZ : FINISHED_SZ;
+    int    headerSz = HANDSHAKE_HEADER_SZ;
+    word32 macSz = finishedSz + HANDSHAKE_HEADER_SZ,
+           idx = *inOutIdx,
+           padSz = ssl->keys.encryptSz - HANDSHAKE_HEADER_SZ - finishedSz -
+                   ssl->specs.hash_size;
+    const byte* mac;
+
+    #ifdef CYASSL_DTLS
+        if (ssl->options.dtls) {
+            headerSz += DTLS_HANDSHAKE_EXTRA;
+            macSz    += DTLS_HANDSHAKE_EXTRA;
+            padSz    -= DTLS_HANDSHAKE_EXTRA;
+        }
+    #endif
+
+    #ifdef CYASSL_CALLBACKS
+        if (ssl->hsInfoOn) AddPacketName("Finished", &ssl->handShakeInfo);
+        if (ssl->toInfoOn) AddLateName("Finished", &ssl->timeoutInfo);
+    #endif
+    if (sniff == NO_SNIFF) {
+        if (XMEMCMP(input + idx, &ssl->verifyHashes, finishedSz))
+            return VERIFY_FINISHED_ERROR;
+    }
+
+    ssl->hmac(ssl, verifyMAC, input + idx - headerSz, macSz,
+         handshake, 1);
+    idx += finishedSz;
+
+    /* read mac and fill */
+    mac = input + idx;
+    idx += ssl->specs.hash_size;
+
+    if (ssl->options.tls1_1 && ssl->specs.cipher_type == block)
+        padSz -= ssl->specs.block_size;
+
+    idx += padSz;
+
+    /* verify mac */
+    if (XMEMCMP(mac, verifyMAC, ssl->specs.hash_size))
+        return VERIFY_MAC_ERROR;
+
+    if (ssl->options.side == CLIENT_END) {
+        ssl->options.serverState = SERVER_FINISHED_COMPLETE;
+        if (!ssl->options.resuming)
+            ssl->options.handShakeState = HANDSHAKE_DONE;
+    }
+    else {
+        ssl->options.clientState = CLIENT_FINISHED_COMPLETE;
+        if (ssl->options.resuming)
+            ssl->options.handShakeState = HANDSHAKE_DONE;
+    }
+
+    *inOutIdx = idx;
+    return 0;
+}
+
+
+static int DoHandShakeMsg(SSL* ssl, byte* input, word32* inOutIdx,
+                          word32 totalSz)
+{
+    byte type;
+    word32 size;
+    int ret = 0;
+
+    CYASSL_ENTER("DoHandShakeMsg()");
+
+    if (GetHandShakeHeader(ssl, input, inOutIdx, &type, &size) != 0)
+        return PARSE_ERROR;
+
+    if (*inOutIdx + size > totalSz)
+        return INCOMPLETE_DATA;
+    
+    HashInput(ssl, input + *inOutIdx, size);
+#ifdef CYASSL_CALLBACKS
+    /* add name later, add on record and handshake header  part back on */
+    if (ssl->toInfoOn) {
+        int add = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ;
+        AddPacketInfo(0, &ssl->timeoutInfo, input + *inOutIdx - add,
+                      size + add, ssl->heap);
+        AddLateRecordHeader(&ssl->curRL, &ssl->timeoutInfo);
+    }
+#endif
+
+    switch (type) {
+
+#ifndef NO_CYASSL_CLIENT
+    case hello_verify_request:
+        CYASSL_MSG("processing hello verify request");
+        ret = DoHelloVerifyRequest(ssl, input,inOutIdx);
+        break;
+            
+    case server_hello:
+        CYASSL_MSG("processing server hello");
+        ret = DoServerHello(ssl, input, inOutIdx);
+        break;
+
+    case certificate_request:
+        CYASSL_MSG("processing certificate request");
+        ret = DoCertificateRequest(ssl, input, inOutIdx);
+        break;
+
+    case server_key_exchange:
+        CYASSL_MSG("processing server key exchange");
+        ret = DoServerKeyExchange(ssl, input, inOutIdx);
+        break;
+#endif
+
+    case certificate:
+        CYASSL_MSG("processing certificate");
+        ret =  DoCertificate(ssl, input, inOutIdx);
+        break;
+
+    case server_hello_done:
+        CYASSL_MSG("processing server hello done");
+        #ifdef CYASSL_CALLBACKS
+            if (ssl->hsInfoOn) 
+                AddPacketName("ServerHelloDone", &ssl->handShakeInfo);
+            if (ssl->toInfoOn)
+                AddLateName("ServerHelloDone", &ssl->timeoutInfo);
+        #endif
+        ssl->options.serverState = SERVER_HELLODONE_COMPLETE;
+        break;
+
+    case finished:
+        CYASSL_MSG("processing finished");
+        ret = DoFinished(ssl, input, inOutIdx, NO_SNIFF);
+        break;
+
+#ifndef NO_CYASSL_SERVER
+    case client_hello:
+        CYASSL_MSG("processing client hello");
+        ret = DoClientHello(ssl, input, inOutIdx, totalSz, size);
+        break;
+
+    case client_key_exchange:
+        CYASSL_MSG("processing client key exchange");
+        ret = DoClientKeyExchange(ssl, input, inOutIdx);
+        break;
+
+    case certificate_verify:
+        CYASSL_MSG("processing certificate verify");
+        ret = DoCertificateVerify(ssl, input, inOutIdx, totalSz);
+        break;
+
+#endif
+
+    default:
+        ret = UNKNOWN_HANDSHAKE_TYPE;
+    }
+
+    CYASSL_LEAVE("DoHandShakeMsg()", ret);
+    return ret;
+}
+
+
+static INLINE void Encrypt(SSL* ssl, byte* out, const byte* input, word32 sz)
+{
+    switch (ssl->specs.bulk_cipher_algorithm) {
+        #ifdef BUILD_ARC4
+            case rc4:
+                Arc4Process(&ssl->encrypt.arc4, out, input, sz);
+                break;
+        #endif
+
+        #ifdef BUILD_DES3
+            case triple_des:
+                Des3_CbcEncrypt(&ssl->encrypt.des3, out, input, sz);
+                break;
+        #endif
+
+        #ifdef BUILD_AES
+            case aes:
+#ifdef CYASSL_AESNI
+                if ((word)input % 16) {
+                    byte buffer[MAX_RECORD_SIZE + MAX_COMP_EXTRA+MAX_MSG_EXTRA];
+                    XMEMCPY(buffer, input, sz);
+                    AesCbcEncrypt(&ssl->encrypt.aes, buffer, buffer, sz);
+                    XMEMCPY(out, buffer, sz);
+                    break;
+                }
+#endif
+                AesCbcEncrypt(&ssl->encrypt.aes, out, input, sz);
+                break;
+        #endif
+
+        #ifdef BUILD_HC128
+            case hc128:
+                Hc128_Process(&ssl->encrypt.hc128, out, input, sz);
+                break;
+        #endif
+
+        #ifdef BUILD_RABBIT
+            case rabbit:
+                RabbitProcess(&ssl->encrypt.rabbit, out, input, sz);
+                break;
+        #endif
+    }
+}
+
+
+static INLINE void Decrypt(SSL* ssl, byte* plain, const byte* input, word32 sz)
+{
+    switch (ssl->specs.bulk_cipher_algorithm) {
+        #ifdef BUILD_ARC4
+            case rc4:
+                Arc4Process(&ssl->decrypt.arc4, plain, input, sz);
+                break;
+        #endif
+
+        #ifdef BUILD_DES3
+            case triple_des:
+                Des3_CbcDecrypt(&ssl->decrypt.des3, plain, input, sz);
+                break;
+        #endif
+
+        #ifdef BUILD_AES
+            case aes:
+                AesCbcDecrypt(&ssl->decrypt.aes, plain, input, sz);
+                break;
+        #endif
+
+        #ifdef BUILD_HC128
+            case hc128:
+                Hc128_Process(&ssl->decrypt.hc128, plain, input, sz);
+                break;
+        #endif
+
+        #ifdef BUILD_RABBIT
+            case rabbit:
+                RabbitProcess(&ssl->decrypt.rabbit, plain, input, sz);
+                break;
+        #endif
+    }
+}
+
+
+/* decrypt input message in place */
+static int DecryptMessage(SSL* ssl, byte* input, word32 sz, word32* idx)
+{
+    Decrypt(ssl, input, input, sz);
+    ssl->keys.encryptSz = sz;
+    if (ssl->options.tls1_1 && ssl->specs.cipher_type == block)
+        *idx += ssl->specs.block_size;  /* go past TLSv1.1 IV */
+
+    return 0;
+}
+
+
+static INLINE word32 GetSEQIncrement(SSL* ssl, int verify)
+{
+    if (verify)
+        return ssl->keys.peer_sequence_number++; 
+    else
+        return ssl->keys.sequence_number++; 
+}
+
+
+int DoApplicationData(SSL* ssl, byte* input, word32* inOutIdx)
+{
+    word32 msgSz   = ssl->keys.encryptSz;
+    word32 pad     = 0, 
+           padByte = 0,
+           idx     = *inOutIdx,
+           digestSz = ssl->specs.hash_size;
+    int    dataSz;
+    int    ivExtra = 0;
+    byte*  rawData = input + idx;  /* keep current  for hmac */
+#ifdef HAVE_LIBZ
+    byte   decomp[MAX_RECORD_SIZE + MAX_COMP_EXTRA];
+#endif
+
+    byte        verify[SHA_DIGEST_SIZE];
+    const byte* mac;
+
+    if (ssl->specs.cipher_type == block) {
+        if (ssl->options.tls1_1)
+            ivExtra = ssl->specs.block_size;
+        pad = *(input + idx + msgSz - ivExtra - 1);
+        padByte = 1;
+    }
+
+    dataSz = msgSz - ivExtra - digestSz - pad - padByte;
+    if (dataSz < 0)
+        return BUFFER_ERROR;
+
+    /* read data */
+    if (dataSz) {
+        int    rawSz   = dataSz;       /* keep raw size for hmac */
+
+        ssl->hmac(ssl, verify, rawData, rawSz, application_data, 1);
+
+#ifdef HAVE_LIBZ
+        byte  decomp[MAX_RECORD_SIZE + MAX_COMP_EXTRA];
+        
+        if (ssl->options.usingCompression) {
+            dataSz = DeCompress(ssl, rawData, dataSz, decomp, sizeof(decomp));
+            if (dataSz < 0) return dataSz;
+        }
+#endif
+
+        if (ssl->options.usingCompression)
+            idx += rawSz;
+        else
+            idx += dataSz;
+
+        ssl->buffers.clearOutputBuffer.buffer = rawData;
+        ssl->buffers.clearOutputBuffer.length = dataSz;
+    }
+
+    /* read mac and fill */
+    mac = input + idx;
+    idx += digestSz;
+   
+    idx += pad;
+    if (padByte)
+        idx++;
+
+#ifdef HAVE_LIBZ
+    if (ssl->options.usingCompression)
+        XMEMMOVE(rawData, decomp, dataSz);
+#endif
+
+    /* verify */
+    if (dataSz) {
+        if (XMEMCMP(mac, verify, digestSz))
+            return VERIFY_MAC_ERROR;
+    }
+    else 
+        GetSEQIncrement(ssl, 1);  /* even though no data, increment verify */
+
+    *inOutIdx = idx;
+    return 0;
+}
+
+
+/* process alert, return level */
+static int DoAlert(SSL* ssl, byte* input, word32* inOutIdx, int* type)
+{
+    byte level;
+
+    #ifdef CYASSL_CALLBACKS
+        if (ssl->hsInfoOn)
+            AddPacketName("Alert", &ssl->handShakeInfo);
+        if (ssl->toInfoOn)
+            /* add record header back on to info + 2 byte level, data */
+            AddPacketInfo("Alert", &ssl->timeoutInfo, input + *inOutIdx -
+                          RECORD_HEADER_SZ, 2 + RECORD_HEADER_SZ, ssl->heap);
+    #endif
+    level = input[(*inOutIdx)++];
+    *type  = (int)input[(*inOutIdx)++];
+
+    if (*type == close_notify)
+        ssl->options.closeNotify = 1;
+
+    if (ssl->keys.encryptionOn) {
+        int         aSz = ALERT_SIZE;
+        const byte* mac;
+        byte        verify[SHA_DIGEST_SIZE];
+        int         padSz = ssl->keys.encryptSz - aSz - ssl->specs.hash_size;
+        
+        ssl->hmac(ssl, verify, input + *inOutIdx - aSz, aSz, alert, 1);
+
+        /* read mac and fill */
+        mac = input + *inOutIdx;
+        *inOutIdx += (ssl->specs.hash_size + padSz);
+
+        /* verify */
+        if (XMEMCMP(mac, verify, ssl->specs.hash_size))
+            return VERIFY_MAC_ERROR;
+    }
+
+    return level;
+}
+
+static int GetInputData(SSL *ssl, size_t size)
+{
+    int in;
+    int inSz;
+    int maxLength;
+    int usedLength;
+
+    
+    /* check max input length */
+    usedLength = ssl->buffers.inputBuffer.length - ssl->buffers.inputBuffer.idx;
+    maxLength  = ssl->buffers.inputBuffer.bufferSize - usedLength;
+    inSz       = (int)(size - usedLength);      /* from last partial read */
+
+#ifdef CYASSL_DTLS
+    if (ssl->options.dtls)
+        inSz = 1500;       /* read ahead up to MTU */
+#endif
+    
+    if (inSz > maxLength) {
+        if (GrowInputBuffer(ssl, size, usedLength) < 0)
+            return MEMORY_E;
+    }
+           
+    if (inSz <= 0)
+        return BUFFER_ERROR;
+    
+    /* Put buffer data at start if not there */
+    if (usedLength > 0 && ssl->buffers.inputBuffer.idx != 0)
+        XMEMMOVE(ssl->buffers.inputBuffer.buffer,
+                ssl->buffers.inputBuffer.buffer + ssl->buffers.inputBuffer.idx,
+                usedLength);
+    
+    /* remove processed data */
+    ssl->buffers.inputBuffer.idx    = 0;
+    ssl->buffers.inputBuffer.length = usedLength;
+  
+    /* read data from network */
+    do {
+        in = Receive(ssl, 
+                     ssl->buffers.inputBuffer.buffer +
+                     ssl->buffers.inputBuffer.length, 
+                     inSz, 0);
+        if (in == -1)
+            return SOCKET_ERROR_E;
+   
+        if (in == WANT_READ)
+            return WANT_READ;
+        
+        ssl->buffers.inputBuffer.length += in;
+        inSz -= in;
+
+    } while (ssl->buffers.inputBuffer.length < size);
+
+    return 0;
+}
+
+/* process input requests, return 0 is done, 1 is call again to complete, and
+   negative number is error */
+int ProcessReply(SSL* ssl)
+{
+    int    ret, type, readSz;
+    word32 startIdx = 0;
+    byte   b0, b1;
+#ifdef CYASSL_DTLS
+    int    used;
+#endif
+
+    for (;;) {
+        switch ((processReply)ssl->options.processReply) {
+
+        /* in the CYASSL_SERVER case, get the first byte for detecting 
+         * old client hello */
+        case doProcessInit:
+            
+            readSz = RECORD_HEADER_SZ;
+            
+            #ifdef CYASSL_DTLS
+                if (ssl->options.dtls)
+                    readSz = DTLS_RECORD_HEADER_SZ;
+            #endif
+
+            /* get header or return error */
+            if (!ssl->options.dtls) {
+                if ((ret = GetInputData(ssl, readSz)) < 0)
+                    return ret;
+            } else {
+            #ifdef CYASSL_DTLS
+                /* read ahead may already have header */
+                used = ssl->buffers.inputBuffer.length -
+                       ssl->buffers.inputBuffer.idx;
+                if (used < readSz)
+                    if ((ret = GetInputData(ssl, readSz)) < 0)
+                        return ret;
+            #endif
+            }
+
+#ifndef NO_CYASSL_SERVER
+
+            /* see if sending SSLv2 client hello */
+            if ( ssl->options.side == SERVER_END &&
+                 ssl->options.clientState == NULL_STATE &&
+                 ssl->buffers.inputBuffer.buffer[ssl->buffers.inputBuffer.idx]
+                         != handshake) {
+                ssl->options.processReply = runProcessOldClientHello;
+
+                /* how many bytes need ProcessOldClientHello */
+                b0 =
+                ssl->buffers.inputBuffer.buffer[ssl->buffers.inputBuffer.idx++];
+                b1 =
+                ssl->buffers.inputBuffer.buffer[ssl->buffers.inputBuffer.idx++];
+                ssl->curSize = ((b0 & 0x7f) << 8) | b1;
+            }
+            else {
+                ssl->options.processReply = getRecordLayerHeader;
+                continue;
+            }
+
+        /* in the CYASSL_SERVER case, run the old client hello */
+        case runProcessOldClientHello:     
+
+            /* get sz bytes or return error */
+            if (!ssl->options.dtls) {
+                if ((ret = GetInputData(ssl, ssl->curSize)) < 0)
+                    return ret;
+            } else {
+            #ifdef CYASSL_DTLS
+                /* read ahead may already have */
+                used = ssl->buffers.inputBuffer.length -
+                       ssl->buffers.inputBuffer.idx;
+                if (used < ssl->curSize)
+                    if ((ret = GetInputData(ssl, ssl->curSize)) < 0)
+                        return ret;
+            #endif  /* CYASSL_DTLS */
+            }
+
+            ret = ProcessOldClientHello(ssl, ssl->buffers.inputBuffer.buffer,
+                                        &ssl->buffers.inputBuffer.idx,
+                                        ssl->buffers.inputBuffer.length -
+                                        ssl->buffers.inputBuffer.idx,
+                                        ssl->curSize);
+            if (ret < 0)
+                return ret;
+
+            else if (ssl->buffers.inputBuffer.idx ==
+                     ssl->buffers.inputBuffer.length) {
+                ssl->options.processReply = doProcessInit;
+                return 0;
+            }
+
+#endif  /* NO_CYASSL_SERVER */
+
+        /* get the record layer header */
+        case getRecordLayerHeader:
+
+            ret = GetRecordHeader(ssl, ssl->buffers.inputBuffer.buffer,
+                                       &ssl->buffers.inputBuffer.idx,
+                                       &ssl->curRL, &ssl->curSize);
+            if (ret != 0)
+                return ret;
+
+            ssl->options.processReply = getData;
+
+        /* retrieve record layer data */
+        case getData:
+
+            /* get sz bytes or return error */
+            if (!ssl->options.dtls) {
+                if ((ret = GetInputData(ssl, ssl->curSize)) < 0)
+                    return ret;
+            } else {
+#ifdef CYASSL_DTLS
+                /* read ahead may already have */
+                used = ssl->buffers.inputBuffer.length -
+                       ssl->buffers.inputBuffer.idx;
+                if (used < ssl->curSize)
+                    if ((ret = GetInputData(ssl, ssl->curSize)) < 0)
+                        return ret;
+#endif
+            }
+            
+            ssl->options.processReply = runProcessingOneMessage;
+            startIdx = ssl->buffers.inputBuffer.idx;  /* in case > 1 msg per */
+
+        /* the record layer is here */
+        case runProcessingOneMessage:
+
+            if (ssl->keys.encryptionOn)
+                if (DecryptMessage(ssl, ssl->buffers.inputBuffer.buffer + 
+                                        ssl->buffers.inputBuffer.idx,
+                                        ssl->curSize,
+                                        &ssl->buffers.inputBuffer.idx) < 0)
+                    return DECRYPT_ERROR;
+
+            CYASSL_MSG("received record layer msg");
+
+            switch (ssl->curRL.type) {
+                case handshake :
+                    /* debugging in DoHandShakeMsg */
+                    if ((ret = DoHandShakeMsg(ssl, 
+                                              ssl->buffers.inputBuffer.buffer,
+                                              &ssl->buffers.inputBuffer.idx,
+                                              ssl->buffers.inputBuffer.length))
+                                                                           != 0)
+                        return ret;
+                    break;
+
+                case change_cipher_spec:
+                    CYASSL_MSG("got CHANGE CIPHER SPEC");
+                    #ifdef CYASSL_CALLBACKS
+                        if (ssl->hsInfoOn)
+                            AddPacketName("ChangeCipher", &ssl->handShakeInfo);
+                        /* add record header back on info */
+                        if (ssl->toInfoOn) {
+                            AddPacketInfo("ChangeCipher", &ssl->timeoutInfo,
+                                ssl->buffers.inputBuffer.buffer +
+                                ssl->buffers.inputBuffer.idx - RECORD_HEADER_SZ,
+                                1 + RECORD_HEADER_SZ, ssl->heap);
+                            AddLateRecordHeader(&ssl->curRL, &ssl->timeoutInfo);
+                        }
+                    #endif
+                    ssl->buffers.inputBuffer.idx++;
+                    ssl->keys.encryptionOn = 1;
+
+                    #ifdef CYASSL_DTLS
+                        if (ssl->options.dtls)
+                            ssl->keys.dtls_peer_epoch++;
+                    #endif
+
+                    #ifdef HAVE_LIBZ
+                        if (ssl->options.usingCompression)
+                            if ( (ret = InitStreams(ssl)) != 0)
+                                return ret;
+                    #endif
+                    if (ssl->options.resuming && ssl->options.side ==
+                                                                    CLIENT_END)
+                        BuildFinished(ssl, &ssl->verifyHashes, server);
+                    else if (!ssl->options.resuming && ssl->options.side ==
+                                                                    SERVER_END)
+                        BuildFinished(ssl, &ssl->verifyHashes, client);
+                    break;
+
+                case application_data:
+                    CYASSL_MSG("got app DATA");
+                    if ((ret = DoApplicationData(ssl,
+                                                ssl->buffers.inputBuffer.buffer,
+                                               &ssl->buffers.inputBuffer.idx))
+                                                                         != 0) {
+                        CYASSL_ERROR(ret);
+                        return ret;
+                    }
+                    break;
+
+                case alert:
+                    CYASSL_MSG("got ALERT!");
+                    if (DoAlert(ssl, ssl->buffers.inputBuffer.buffer,
+                           &ssl->buffers.inputBuffer.idx, &type) == alert_fatal)
+                        return FATAL_ERROR;
+
+                    /* catch warnings that are handled as errors */
+                    if (type == close_notify)
+                        return ssl->error = ZERO_RETURN;
+                           
+                    if (type == decrypt_error)
+                        return FATAL_ERROR;
+                    break;
+            
+                default:
+                    CYASSL_ERROR(UNKNOWN_RECORD_TYPE);
+                    return UNKNOWN_RECORD_TYPE;
+            }
+
+            ssl->options.processReply = doProcessInit;
+
+            /* input exhausted? */
+            if (ssl->buffers.inputBuffer.idx == ssl->buffers.inputBuffer.length)
+                return 0;
+            /* more messages per record */
+            else if ((ssl->buffers.inputBuffer.idx - startIdx) < ssl->curSize) {
+                #ifdef CYASSL_DTLS
+                    /* read-ahead but dtls doesn't bundle messages per record */
+                    if (ssl->options.dtls) {
+                        ssl->options.processReply = doProcessInit;
+                        continue;
+                    }
+                #endif
+                ssl->options.processReply = runProcessingOneMessage;
+                continue;
+            }
+            /* more records */
+            else {
+                ssl->options.processReply = doProcessInit;
+                continue;
+            }
+        }
+    }
+}
+
+
+int SendChangeCipher(SSL* ssl)
+{
+    byte              *output;
+    int                sendSz = RECORD_HEADER_SZ + ENUM_LEN;
+    int                idx    = RECORD_HEADER_SZ;
+    int                ret;
+
+    #ifdef CYASSL_DTLS
+        if (ssl->options.dtls) {
+            sendSz += DTLS_RECORD_EXTRA;
+            idx    += DTLS_RECORD_EXTRA;
+        }
+    #endif
+
+    /* check for avalaible size */
+    if ((ret = CheckAvalaibleSize(ssl, sendSz)) != 0)
+        return ret;
+
+    /* get ouput buffer */
+    output = ssl->buffers.outputBuffer.buffer + 
+             ssl->buffers.outputBuffer.idx;
+
+    AddRecordHeader(output, 1, change_cipher_spec, ssl);
+
+    output[idx] = 1;             /* turn it on */
+
+    #ifdef CYASSL_CALLBACKS
+        if (ssl->hsInfoOn) AddPacketName("ChangeCipher", &ssl->handShakeInfo);
+        if (ssl->toInfoOn)
+            AddPacketInfo("ChangeCipher", &ssl->timeoutInfo, output, sendSz,
+                           ssl->heap);
+    #endif
+    ssl->buffers.outputBuffer.length += sendSz;
+    return SendBuffered(ssl);
+}
+
+
+static INLINE const byte* GetMacSecret(SSL* ssl, int verify)
+{
+    if ( (ssl->options.side == CLIENT_END && !verify) ||
+         (ssl->options.side == SERVER_END &&  verify) )
+        return ssl->keys.client_write_MAC_secret;
+    else
+        return ssl->keys.server_write_MAC_secret;
+}
+
+
+static void Hmac(SSL* ssl, byte* digest, const byte* buffer, word32 sz,
+                 int content, int verify)
+{
+    byte   result[SHA_DIGEST_SIZE];                    /* max possible sizes */
+    word32 digestSz = ssl->specs.hash_size;            /* actual sizes */
+    word32 padSz    = ssl->specs.pad_size;
+
+    Md5 md5;
+    Sha sha;
+
+    /* data */
+    byte seq[SEQ_SZ] = { 0x00, 0x00, 0x00, 0x00 };
+    byte conLen[ENUM_LEN + LENGTH_SZ];     /* content & length */
+    const byte* macSecret = GetMacSecret(ssl, verify);
+    
+    conLen[0] = content;
+    c16toa((word16)sz, &conLen[ENUM_LEN]);
+    c32toa(GetSEQIncrement(ssl, verify), &seq[sizeof(word32)]);
+
+    if (ssl->specs.mac_algorithm == md5_mac) {
+        InitMd5(&md5);
+        /* inner */
+        Md5Update(&md5, macSecret, digestSz);
+        Md5Update(&md5, PAD1, padSz);
+        Md5Update(&md5, seq, SEQ_SZ);
+        Md5Update(&md5, conLen, sizeof(conLen));
+        /* buffer */
+        Md5Update(&md5, buffer, sz);
+        Md5Final(&md5, result);
+        /* outer */
+        Md5Update(&md5, macSecret, digestSz);
+        Md5Update(&md5, PAD2, padSz);
+        Md5Update(&md5, result, digestSz);
+        Md5Final(&md5, digest);        
+    }
+    else {
+        InitSha(&sha);
+        /* inner */
+        ShaUpdate(&sha, macSecret, digestSz);
+        ShaUpdate(&sha, PAD1, padSz);
+        ShaUpdate(&sha, seq, SEQ_SZ);
+        ShaUpdate(&sha, conLen, sizeof(conLen));
+        /* buffer */
+        ShaUpdate(&sha, buffer, sz);
+        ShaFinal(&sha, result);
+        /* outer */
+        ShaUpdate(&sha, macSecret, digestSz);
+        ShaUpdate(&sha, PAD2, padSz);
+        ShaUpdate(&sha, result, digestSz);
+        ShaFinal(&sha, digest);        
+    }
+}
+
+
+static void BuildMD5_CertVerify(SSL* ssl, byte* digest)
+{
+    byte md5_result[MD5_DIGEST_SIZE];
+
+    /* make md5 inner */
+    Md5Update(&ssl->hashMd5, ssl->arrays.masterSecret, SECRET_LEN);
+    Md5Update(&ssl->hashMd5, PAD1, PAD_MD5);
+    Md5Final(&ssl->hashMd5, md5_result);
+
+    /* make md5 outer */
+    Md5Update(&ssl->hashMd5, ssl->arrays.masterSecret, SECRET_LEN);
+    Md5Update(&ssl->hashMd5, PAD2, PAD_MD5);
+    Md5Update(&ssl->hashMd5, md5_result, MD5_DIGEST_SIZE);
+
+    Md5Final(&ssl->hashMd5, digest);
+}
+
+
+static void BuildSHA_CertVerify(SSL* ssl, byte* digest)
+{
+    byte sha_result[SHA_DIGEST_SIZE];
+    
+    /* make sha inner */
+    ShaUpdate(&ssl->hashSha, ssl->arrays.masterSecret, SECRET_LEN);
+    ShaUpdate(&ssl->hashSha, PAD1, PAD_SHA);
+    ShaFinal(&ssl->hashSha, sha_result);
+
+    /* make sha outer */
+    ShaUpdate(&ssl->hashSha, ssl->arrays.masterSecret, SECRET_LEN);
+    ShaUpdate(&ssl->hashSha, PAD2, PAD_SHA);
+    ShaUpdate(&ssl->hashSha, sha_result, SHA_DIGEST_SIZE);
+
+    ShaFinal(&ssl->hashSha, digest);
+}
+
+
+static void BuildCertHashes(SSL* ssl, Hashes* hashes)
+{
+    /* store current states, building requires get_digest which resets state */
+    Md5 md5 = ssl->hashMd5;
+    Sha sha = ssl->hashSha;
+
+    if (ssl->options.tls) {
+        Md5Final(&ssl->hashMd5, hashes->md5);
+        ShaFinal(&ssl->hashSha, hashes->sha);
+    }
+    else {
+        BuildMD5_CertVerify(ssl, hashes->md5);
+        BuildSHA_CertVerify(ssl, hashes->sha);
+    }
+    
+    /* restore */
+    ssl->hashMd5 = md5;
+    ssl->hashSha = sha;
+}
+
+
+/* Build SSL Message, encrypted */
+static int BuildMessage(SSL* ssl, byte* output, const byte* input, int inSz,
+                        int type)
+{
+    word32 digestSz = ssl->specs.hash_size;
+    word32 sz = RECORD_HEADER_SZ + inSz + digestSz;                
+    word32 pad  = 0, i;
+    word32 idx  = RECORD_HEADER_SZ;
+    word32 ivSz = 0;      /* TLSv1.1  IV */
+    word32 headerSz = RECORD_HEADER_SZ;
+    word16 size;
+    byte               iv[AES_BLOCK_SIZE];                  /* max size */
+
+#ifdef CYASSL_DTLS
+    if (ssl->options.dtls) {
+        sz       += DTLS_RECORD_EXTRA;
+        idx      += DTLS_RECORD_EXTRA; 
+        headerSz += DTLS_RECORD_EXTRA;
+    }
+#endif
+
+    if (ssl->specs.cipher_type == block) {
+        word32 blockSz = ssl->specs.block_size;
+        if (ssl->options.tls1_1) {
+            ivSz = blockSz;
+            sz  += ivSz;
+            RNG_GenerateBlock(&ssl->rng, iv, ivSz);
+        }
+        sz += 1;       /* pad byte */
+        pad = (sz - headerSz) % blockSz;
+        pad = blockSz - pad;
+        sz += pad;
+    }
+
+    size = sz - headerSz;    /* include mac and digest */
+    AddRecordHeader(output, size, type, ssl);    
+
+    /* write to output */
+    if (ivSz) {
+        XMEMCPY(output + idx, iv, ivSz);
+        idx += ivSz;
+    }
+    XMEMCPY(output + idx, input, inSz);
+    idx += inSz;
+
+    if (type == handshake)
+        HashOutput(ssl, output, headerSz + inSz, ivSz);
+    ssl->hmac(ssl, output+idx, output + headerSz + ivSz, inSz, type, 0);
+    idx += digestSz;
+
+    if (ssl->specs.cipher_type == block)
+        for (i = 0; i <= pad; i++) output[idx++] = pad; /* pad byte gets */
+                                                        /* pad value too */
+    Encrypt(ssl, output + headerSz, output + headerSz, size);
+
+    return sz;
+}
+
+
+int SendFinished(SSL* ssl)
+{
+    int              sendSz,
+                     finishedSz = ssl->options.tls ? TLS_FINISHED_SZ :
+                                                     FINISHED_SZ;
+    byte             input[FINISHED_SZ + DTLS_HANDSHAKE_HEADER_SZ];  /* max */
+    byte            *output;
+    Hashes*          hashes;
+    int              ret;
+    int              headerSz = HANDSHAKE_HEADER_SZ;
+
+
+    #ifdef CYASSL_DTLS
+        if (ssl->options.dtls) {
+            headerSz += DTLS_HANDSHAKE_EXTRA;
+            ssl->keys.dtls_epoch++;
+            ssl->keys.dtls_sequence_number = 0;  /* reset after epoch change */
+        }
+    #endif
+    
+    /* check for avalaible size */
+    if ((ret = CheckAvalaibleSize(ssl, sizeof(input) + MAX_MSG_EXTRA)) != 0)
+        return ret;
+
+    /* get ouput buffer */
+    output = ssl->buffers.outputBuffer.buffer + 
+             ssl->buffers.outputBuffer.idx;
+
+    AddHandShakeHeader(input, finishedSz, finished, ssl);
+
+    /* make finished hashes */
+    hashes = (Hashes*)&input[headerSz];
+    BuildFinished(ssl, hashes, ssl->options.side == CLIENT_END ? client :
+                  server);
+
+    if ( (sendSz = BuildMessage(ssl, output, input, headerSz +
+                                finishedSz, handshake)) == -1)
+        return BUILD_MSG_ERROR;
+
+    if (!ssl->options.resuming) {
+        AddSession(ssl);    /* just try */
+        if (ssl->options.side == CLIENT_END)
+            BuildFinished(ssl, &ssl->verifyHashes, server);
+        else
+            ssl->options.handShakeState = HANDSHAKE_DONE;
+    }
+    else {
+        if (ssl->options.side == CLIENT_END)
+            ssl->options.handShakeState = HANDSHAKE_DONE;
+        else
+            BuildFinished(ssl, &ssl->verifyHashes, client);
+    }
+
+    #ifdef CYASSL_CALLBACKS
+        if (ssl->hsInfoOn) AddPacketName("Finished", &ssl->handShakeInfo);
+        if (ssl->toInfoOn)
+            AddPacketInfo("Finished", &ssl->timeoutInfo, output, sendSz,
+                          ssl->heap);
+    #endif
+
+    ssl->buffers.outputBuffer.length += sendSz;
+
+    return SendBuffered(ssl);
+}
+
+
+int SendCertificate(SSL* ssl)
+{
+    int    sendSz, length, ret = 0;
+    word32 i = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ;
+    word32 certSz, listSz;
+    byte*  output = 0;
+
+    if (ssl->options.usingPSK_cipher) return 0;  /* not needed */
+
+    if (ssl->options.sendVerify == SEND_BLANK_CERT) {
+        certSz = 0;
+        length = CERT_HEADER_SZ;
+        listSz = 0;
+    }
+    else {
+        certSz = ssl->buffers.certificate.length;
+        /* list + cert size */
+        length = certSz + 2 * CERT_HEADER_SZ;
+        listSz = certSz + CERT_HEADER_SZ;
+    }
+    sendSz = length + RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ;
+
+    #ifdef CYASSL_DTLS
+        if (ssl->options.dtls) {
+            sendSz += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA;
+            i      += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA;
+        }
+    #endif
+
+    /* check for avalaible size */
+    if ((ret = CheckAvalaibleSize(ssl, sendSz)) != 0)
+        return ret;
+
+    /* get ouput buffer */
+    output = ssl->buffers.outputBuffer.buffer +
+             ssl->buffers.outputBuffer.idx;
+
+    AddHeaders(output, length, certificate, ssl);
+
+    /* list total */
+    c32to24(listSz, output + i);
+    i += CERT_HEADER_SZ;
+
+    /* member */
+    if (certSz) {
+        c32to24(certSz, output + i);
+        i += CERT_HEADER_SZ;
+        XMEMCPY(output + i, ssl->buffers.certificate.buffer, certSz);
+        i += certSz;
+    }
+    HashOutput(ssl, output, sendSz, 0);
+    #ifdef CYASSL_CALLBACKS
+        if (ssl->hsInfoOn) AddPacketName("Certificate", &ssl->handShakeInfo);
+        if (ssl->toInfoOn)
+            AddPacketInfo("Certificate", &ssl->timeoutInfo, output, sendSz,
+                           ssl->heap);
+    #endif
+
+    if (ssl->options.side == SERVER_END)
+        ssl->options.serverState = SERVER_CERT_COMPLETE;
+
+    ssl->buffers.outputBuffer.length += sendSz;
+    return SendBuffered(ssl);
+}
+
+
+int SendCertificateRequest(SSL* ssl)
+{
+    byte   *output;
+    int    ret;
+    int    sendSz;
+    word32 i = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ;
+    
+    int  typeTotal = 1;  /* only rsa for now */
+    int  reqSz = ENUM_LEN + typeTotal + REQ_HEADER_SZ;  /* add auth later */
+
+    if (ssl->options.usingPSK_cipher) return 0;  /* not needed */
+
+    sendSz = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ + reqSz;
+
+    #ifdef CYASSL_DTLS
+        if (ssl->options.dtls) {
+            sendSz += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA;
+            i      += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA;
+        }
+    #endif
+    /* check for avalaible size */
+    if ((ret = CheckAvalaibleSize(ssl, sendSz)) != 0)
+        return ret;
+
+    /* get ouput buffer */
+    output = ssl->buffers.outputBuffer.buffer + ssl->buffers.outputBuffer.idx;
+
+    AddHeaders(output, reqSz, certificate_request, ssl);
+
+    /* write to output */
+    output[i++] = typeTotal;  /* # of types */
+    output[i++] = rsa_sign;
+
+    c16toa(0, &output[i]);  /* auth's */
+    i += REQ_HEADER_SZ;
+
+    HashOutput(ssl, output, sendSz, 0);
+
+    #ifdef CYASSL_CALLBACKS
+        if (ssl->hsInfoOn)
+            AddPacketName("CertificateRequest", &ssl->handShakeInfo);
+        if (ssl->toInfoOn)
+            AddPacketInfo("CertificateRequest", &ssl->timeoutInfo, output,
+                          sendSz, ssl->heap);
+    #endif
+    ssl->buffers.outputBuffer.length += sendSz;
+    return SendBuffered(ssl);
+}
+
+
+int SendData(SSL* ssl, const void* buffer, int sz)
+{
+    int sent = 0,  /* plainText size */
+        sendSz,
+        ret;
+
+    if (ssl->error == WANT_WRITE)
+        ssl->error = 0;
+
+    if (ssl->options.handShakeState != HANDSHAKE_DONE) {
+        int err;
+        if ( (err = CyaSSL_negotiate(ssl)) != 0) 
+            return  err;
+    }
+
+    /* last time system socket output buffer was full, try again to send */
+    if (ssl->buffers.outputBuffer.length > 0) {
+        if ( (ssl->error = SendBuffered(ssl)) < 0) {
+            CYASSL_ERROR(ssl->error);
+            if (ssl->error == SOCKET_ERROR_E && ssl->options.connReset)
+                return 0;     /* peer reset */
+            return ssl->error;
+        }
+        else {
+            /* advance sent to previous sent + plain size just sent */
+            sent = ssl->buffers.prevSent + ssl->buffers.plainSz;
+            CYASSL_MSG("sent write buffered data");
+        }
+    }
+
+    for (;;) {
+        int   len = min(sz - sent, OUTPUT_RECORD_SIZE);
+        byte* out;
+        byte* sendBuffer = (byte*)buffer + sent;  /* may switch on comp */
+        int   buffSz = len;                       /* may switch on comp */
+#ifdef HAVE_LIBZ
+        byte  comp[MAX_RECORD_SIZE + MAX_COMP_EXTRA];
+#endif
+
+        if (sent == sz) break;
+
+#ifdef CYASSL_DTLS
+        if (ssl->options.dtls) {
+            len    = min(len, MAX_UDP_SIZE);
+            buffSz = len;
+        }
+#endif
+
+        /* check for avalaible size */
+        if ((ret = CheckAvalaibleSize(ssl, len + COMP_EXTRA +
+                                      MAX_MSG_EXTRA)) != 0)
+            return ret;
+
+        /* get ouput buffer */
+        out = ssl->buffers.outputBuffer.buffer +
+              ssl->buffers.outputBuffer.idx;
+
+#ifdef HAVE_LIBZ
+        if (ssl->options.usingCompression) {
+            buffSz = Compress(ssl, sendBuffer, buffSz, comp, sizeof(comp));
+            if (buffSz < 0) {
+                return buffSz;
+            }
+            sendBuffer = comp;
+        }
+#endif
+        sendSz = BuildMessage(ssl, out, sendBuffer, buffSz,
+                              application_data);
+
+        ssl->buffers.outputBuffer.length += sendSz;
+
+        if ( (ret = SendBuffered(ssl)) < 0) {
+            CYASSL_ERROR(ret);
+            /* store for next call if WANT_WRITE or user embedSend() that
+               doesn't present like WANT_WRITE */
+            ssl->buffers.plainSz  = len;
+            ssl->buffers.prevSent = sent;
+            if (ret == SOCKET_ERROR_E && ssl->options.connReset)
+                return 0;  /* peer reset */
+            return ssl->error = ret;
+        }
+
+        sent += len;
+
+        /* only one message per attempt */
+        if (ssl->options.partialWrite == 1)
+            break;
+    }
+ 
+    return sent;
+}
+
+/* process input data */
+int ReceiveData(SSL* ssl, byte* output, int sz)
+{
+    int size;
+
+    CYASSL_ENTER("ReceiveData()");
+
+    if (ssl->error == WANT_READ)
+        ssl->error = 0;
+
+    if (ssl->options.handShakeState != HANDSHAKE_DONE) {
+        int err;
+        if ( (err = CyaSSL_negotiate(ssl)) != 0)
+            return  err;
+    }
+
+    while (ssl->buffers.clearOutputBuffer.length == 0)
+        if ( (ssl->error = ProcessReply(ssl)) < 0) {
+            CYASSL_ERROR(ssl->error);
+            if (ssl->error == ZERO_RETURN) {
+                ssl->options.isClosed = 1;
+                return 0;         /* no more data coming */
+            }
+            if (ssl->error == SOCKET_ERROR_E)
+                if (ssl->options.connReset || ssl->options.isClosed)
+                    return 0;     /* peer reset or closed */
+            return ssl->error;
+        }
+
+    if (sz < (int)ssl->buffers.clearOutputBuffer.length)
+        size = sz;
+    else
+        size = ssl->buffers.clearOutputBuffer.length;
+
+    XMEMCPY(output, ssl->buffers.clearOutputBuffer.buffer, size);
+    ssl->buffers.clearOutputBuffer.length -= size;
+    ssl->buffers.clearOutputBuffer.buffer += size;
+   
+    if (ssl->buffers.clearOutputBuffer.length == 0 && 
+                                           ssl->buffers.inputBuffer.dynamicFlag)
+       ShrinkInputBuffer(ssl, NO_FORCED_FREE);
+
+    CYASSL_LEAVE("ReceiveData()", size);
+    return size;
+}
+
+
+/* send alert message */
+int SendAlert(SSL* ssl, int severity, int type)
+{
+    byte input[ALERT_SIZE];
+    byte *output;
+    int  sendSz;
+    int  ret;
+
+    /* if sendalert is called again for nonbloking */
+    if (ssl->options.sendAlertState != 0) {
+        ret = SendBuffered(ssl);
+        if (ret == 0)
+            ssl->options.sendAlertState = 0;
+        return ret;
+    }
+
+    /* check for avalaible size */
+    if ((ret = CheckAvalaibleSize(ssl, ALERT_SIZE + MAX_MSG_EXTRA)) != 0)
+        return ret;
+
+    /* get ouput buffer */
+    output = ssl->buffers.outputBuffer.buffer +
+             ssl->buffers.outputBuffer.idx;
+
+    input[0] = severity;
+    input[1] = type;
+
+    if (ssl->keys.encryptionOn)
+        sendSz = BuildMessage(ssl, output, input, sizeof(input), alert);
+    else {
+        RecordLayerHeader *const rl = (RecordLayerHeader*)output;
+        rl->type    = alert;
+        rl->version = ssl->version;
+        c16toa(ALERT_SIZE, rl->length);      
+
+        XMEMCPY(output + RECORD_HEADER_SZ, input, sizeof(input));
+        sendSz = RECORD_HEADER_SZ + sizeof(input);
+    }
+
+    #ifdef CYASSL_CALLBACKS
+        if (ssl->hsInfoOn)
+            AddPacketName("Alert", &ssl->handShakeInfo);
+        if (ssl->toInfoOn)
+            AddPacketInfo("Alert", &ssl->timeoutInfo, output, sendSz,ssl->heap);
+    #endif
+
+    ssl->buffers.outputBuffer.length += sendSz;
+    ssl->options.sendAlertState = 1;
+
+    return SendBuffered(ssl);
+}
+
+
+
+void SetErrorString(int error, char* buffer)
+{
+    const int max = MAX_ERROR_SZ;  /* shorthand */
+
+#ifdef NO_ERROR_STRINGS
+
+    XSTRNCPY(buffer, "no support for error strings built in", max);
+
+#else
+
+    /* pass to CTaoCrypt */
+    if (error < MAX_CODE_E && error > MIN_CODE_E) {
+        CTaoCryptErrorString(error, buffer);
+        return;
+    }
+
+    switch (error) {
+
+    case UNSUPPORTED_SUITE :
+        XSTRNCPY(buffer, "unsupported cipher suite", max);
+        break;
+
+    case PREFIX_ERROR :
+        XSTRNCPY(buffer, "bad index to key rounds", max);
+        break;
+
+    case MEMORY_ERROR :
+        XSTRNCPY(buffer, "out of memory", max);
+        break;
+
+    case VERIFY_FINISHED_ERROR :
+        XSTRNCPY(buffer, "verify problem on finished", max);
+        break;
+
+    case VERIFY_MAC_ERROR :
+        XSTRNCPY(buffer, "verify mac problem", max);
+        break;
+
+    case PARSE_ERROR :
+        XSTRNCPY(buffer, "parse error on header", max);
+        break;
+
+    case SIDE_ERROR :
+        XSTRNCPY(buffer, "wrong client/server type", max);
+        break;
+
+    case NO_PEER_CERT :
+        XSTRNCPY(buffer, "peer didn't send cert", max);
+        break;
+
+    case UNKNOWN_HANDSHAKE_TYPE :
+        XSTRNCPY(buffer, "weird handshake type", max);
+        break;
+
+    case SOCKET_ERROR_E :
+        XSTRNCPY(buffer, "error state on socket", max);
+        break;
+
+    case SOCKET_NODATA :
+        XSTRNCPY(buffer, "expected data, not there", max);
+        break;
+
+    case INCOMPLETE_DATA :
+        XSTRNCPY(buffer, "don't have enough data to complete task", max);
+        break;
+
+    case UNKNOWN_RECORD_TYPE :
+        XSTRNCPY(buffer, "unknown type in record hdr", max);
+        break;
+
+    case DECRYPT_ERROR :
+        XSTRNCPY(buffer, "error during decryption", max);
+        break;
+
+    case FATAL_ERROR :
+        XSTRNCPY(buffer, "revcd alert fatal error", max);
+        break;
+
+    case ENCRYPT_ERROR :
+        XSTRNCPY(buffer, "error during encryption", max);
+        break;
+
+    case FREAD_ERROR :
+        XSTRNCPY(buffer, "fread problem", max);
+        break;
+
+    case NO_PEER_KEY :
+        XSTRNCPY(buffer, "need peer's key", max);
+        break;
+
+    case NO_PRIVATE_KEY :
+        XSTRNCPY(buffer, "need the private key", max);
+        break;
+
+    case RSA_PRIVATE_ERROR :
+        XSTRNCPY(buffer, "error during rsa priv op", max);
+        break;
+
+    case MATCH_SUITE_ERROR :
+        XSTRNCPY(buffer, "can't match cipher suite", max);
+        break;
+
+    case BUILD_MSG_ERROR :
+        XSTRNCPY(buffer, "build message failure", max);
+        break;
+
+    case BAD_HELLO :
+        XSTRNCPY(buffer, "client hello malformed", max);
+        break;
+
+    case DOMAIN_NAME_MISMATCH :
+        XSTRNCPY(buffer, "peer subject name mismatch", max);
+        break;
+
+    case WANT_READ :
+        XSTRNCPY(buffer, "non-blocking socket wants data to be read", max);
+        break;
+
+    case NOT_READY_ERROR :
+        XSTRNCPY(buffer, "handshake layer not ready yet, complete first", max);
+        break;
+
+    case PMS_VERSION_ERROR :
+        XSTRNCPY(buffer, "premaster secret version mismatch error", max);
+        break;
+
+    case VERSION_ERROR :
+        XSTRNCPY(buffer, "record layer version error", max);
+        break;
+
+    case WANT_WRITE :
+        XSTRNCPY(buffer, "non-blocking socket write buffer full", max);
+        break;
+
+    case BUFFER_ERROR :
+        XSTRNCPY(buffer, "malformed buffer input error", max);
+        break;
+
+    case VERIFY_CERT_ERROR :
+        XSTRNCPY(buffer, "verify problem on certificate", max);
+        break;
+
+    case VERIFY_SIGN_ERROR :
+        XSTRNCPY(buffer, "verify problem based on signature", max);
+        break;
+
+    case CLIENT_ID_ERROR :
+        XSTRNCPY(buffer, "psk client identity error", max);
+        break;
+
+    case SERVER_HINT_ERROR:
+        XSTRNCPY(buffer, "psk server hint error", max);
+        break;
+
+    case PSK_KEY_ERROR:
+        XSTRNCPY(buffer, "psk key callback error", max);
+        break;
+
+    case NTRU_KEY_ERROR:
+        XSTRNCPY(buffer, "NTRU key error", max);
+        break;
+
+    case NTRU_DRBG_ERROR:
+        XSTRNCPY(buffer, "NTRU drbg error", max);
+        break;
+
+    case NTRU_ENCRYPT_ERROR:
+        XSTRNCPY(buffer, "NTRU encrypt error", max);
+        break;
+
+    case NTRU_DECRYPT_ERROR:
+        XSTRNCPY(buffer, "NTRU decrypt error", max);
+        break;
+
+    case ZLIB_INIT_ERROR:
+        XSTRNCPY(buffer, "zlib init error", max);
+        break;
+
+    case ZLIB_COMPRESS_ERROR:
+        XSTRNCPY(buffer, "zlib compress error", max);
+        break;
+
+    case ZLIB_DECOMPRESS_ERROR:
+        XSTRNCPY(buffer, "zlib decompress error", max);
+        break;
+
+    case GETTIME_ERROR:
+        XSTRNCPY(buffer, "gettimeofday() error", max);
+        break;
+
+    case GETITIMER_ERROR:
+        XSTRNCPY(buffer, "getitimer() error", max);
+        break;
+
+    case SIGACT_ERROR:
+        XSTRNCPY(buffer, "sigaction() error", max);
+        break;
+
+    case SETITIMER_ERROR:
+        XSTRNCPY(buffer, "setitimer() error", max);
+        break;
+
+    case LENGTH_ERROR:
+        XSTRNCPY(buffer, "record layer length error", max);
+        break;
+
+    case PEER_KEY_ERROR:
+        XSTRNCPY(buffer, "cant decode peer key", max);
+        break;
+
+    case ZERO_RETURN:
+        XSTRNCPY(buffer, "peer sent close notify alert", max);
+        break;
+
+    case ECC_CURVETYPE_ERROR:
+        XSTRNCPY(buffer, "Bad ECC Curve Type or unsupported", max);
+        break;
+
+    case ECC_CURVE_ERROR:
+        XSTRNCPY(buffer, "Bad ECC Curve or unsupported", max);
+        break;
+
+    case ECC_PEERKEY_ERROR:
+        XSTRNCPY(buffer, "Bad ECC Peer Key", max);
+        break;
+
+    case ECC_MAKEKEY_ERROR:
+        XSTRNCPY(buffer, "ECC Make Key failutre", max);
+        break;
+
+    case ECC_EXPORT_ERROR:
+        XSTRNCPY(buffer, "ECC Export Key failutre", max);
+        break;
+
+    case ECC_SHARED_ERROR:
+        XSTRNCPY(buffer, "ECC DHE shared failutre", max);
+        break;
+
+    default :
+        XSTRNCPY(buffer, "unknown error number", max);
+    }
+
+#endif /* NO_ERROR_STRINGS */
+}
+
+
+
+/* be sure to add to cipher_name_idx too !!!! */
+const char* const cipher_names[] = 
+{
+#ifdef BUILD_SSL_RSA_WITH_RC4_128_SHA
+    "RC4-SHA",
+#endif
+
+#ifdef BUILD_SSL_RSA_WITH_RC4_128_MD5
+    "RC4-MD5",
+#endif
+
+#ifdef BUILD_SSL_RSA_WITH_3DES_EDE_CBC_SHA
+    "DES-CBC3-SHA",
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_AES_128_CBC_SHA
+    "AES128-SHA",
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_AES_256_CBC_SHA
+    "AES256-SHA",
+#endif
+
+#ifdef BUILD_TLS_DHE_RSA_WITH_AES_128_CBC_SHA
+    "DHE-RSA-AES128-SHA",
+#endif
+
+#ifdef BUILD_TLS_DHE_RSA_WITH_AES_256_CBC_SHA
+    "DHE-RSA-AES256-SHA",
+#endif
+
+#ifdef BUILD_TLS_PSK_WITH_AES_128_CBC_SHA
+    "PSK-AES128-CBC-SHA",
+#endif
+
+#ifdef BUILD_TLS_PSK_WITH_AES_256_CBC_SHA
+    "PSK-AES256-CBC-SHA",
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_HC_128_CBC_MD5
+    "HC128-MD5",
+#endif
+    
+#ifdef BUILD_TLS_RSA_WITH_HC_128_CBC_SHA
+    "HC128-SHA",
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_RABBIT_CBC_SHA
+    "RABBIT-SHA",
+#endif
+
+#ifdef BUILD_TLS_NTRU_RSA_WITH_RC4_128_SHA
+    "NTRU-RC4-SHA",
+#endif
+
+#ifdef BUILD_TLS_NTRU_RSA_WITH_3DES_EDE_CBC_SHA
+    "NTRU-DES-CBC3-SHA",
+#endif
+
+#ifdef BUILD_TLS_NTRU_RSA_WITH_AES_128_CBC_SHA
+    "NTRU-AES128-SHA",
+#endif
+
+#ifdef BUILD_TLS_NTRU_RSA_WITH_AES_256_CBC_SHA
+    "NTRU-AES256-SHA",
+#endif
+
+#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
+    "ECDHE-RSA-AES128-SHA",
+#endif
+
+#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
+    "ECDHE-RSA-AES256-SHA",
+#endif
+
+#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA
+    "ECDHE-ECDSA-AES128-SHA",
+#endif
+
+#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
+    "ECDHE-ECDSA-AES256-SHA",
+#endif
+
+#ifdef BUILD_TLS_ECDHE_RSA_WITH_RC4_128_SHA
+    "ECDHE-RSA-RC4-SHA",
+#endif
+
+#ifdef BUILD_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA
+    "ECDHE-RSA-DES-CBC3-SHA",
+#endif
+
+#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_RC4_128_SHA
+    "ECDHE-ECDSA-RC4-SHA",
+#endif
+
+#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA
+    "ECDHE-ECDSA-DES-CBC3-SHA",
+#endif
+
+};
+
+
+
+/* cipher suite number that matches above name table */
+int cipher_name_idx[] =
+{
+
+#ifdef BUILD_SSL_RSA_WITH_RC4_128_SHA
+    SSL_RSA_WITH_RC4_128_SHA,
+#endif
+
+#ifdef BUILD_SSL_RSA_WITH_RC4_128_MD5
+    SSL_RSA_WITH_RC4_128_MD5,
+#endif
+
+#ifdef BUILD_SSL_RSA_WITH_3DES_EDE_CBC_SHA
+    SSL_RSA_WITH_3DES_EDE_CBC_SHA,
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_AES_128_CBC_SHA
+    TLS_RSA_WITH_AES_128_CBC_SHA,    
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_AES_256_CBC_SHA
+    TLS_RSA_WITH_AES_256_CBC_SHA,
+#endif
+
+#ifdef BUILD_TLS_DHE_RSA_WITH_AES_128_CBC_SHA
+    TLS_DHE_RSA_WITH_AES_128_CBC_SHA,    
+#endif
+
+#ifdef BUILD_TLS_DHE_RSA_WITH_AES_256_CBC_SHA
+    TLS_DHE_RSA_WITH_AES_256_CBC_SHA,
+#endif
+
+#ifdef BUILD_TLS_PSK_WITH_AES_128_CBC_SHA
+    TLS_PSK_WITH_AES_128_CBC_SHA,    
+#endif
+
+#ifdef BUILD_TLS_PSK_WITH_AES_256_CBC_SHA
+    TLS_PSK_WITH_AES_256_CBC_SHA,
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_HC_128_CBC_MD5
+    TLS_RSA_WITH_HC_128_CBC_MD5,    
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_HC_128_CBC_SHA
+    TLS_RSA_WITH_HC_128_CBC_SHA,    
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_RABBIT_CBC_SHA
+    TLS_RSA_WITH_RABBIT_CBC_SHA,    
+#endif
+
+#ifdef BUILD_TLS_NTRU_RSA_WITH_RC4_128_SHA
+    TLS_NTRU_RSA_WITH_RC4_128_SHA,
+#endif
+
+#ifdef BUILD_TLS_NTRU_RSA_WITH_3DES_EDE_CBC_SHA
+    TLS_NTRU_RSA_WITH_3DES_EDE_CBC_SHA,
+#endif
+
+#ifdef BUILD_TLS_NTRU_RSA_WITH_AES_128_CBC_SHA
+    TLS_NTRU_RSA_WITH_AES_128_CBC_SHA,    
+#endif
+
+#ifdef BUILD_TLS_NTRU_RSA_WITH_AES_256_CBC_SHA
+    TLS_NTRU_RSA_WITH_AES_256_CBC_SHA,    
+#endif
+
+#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
+    TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,    
+#endif
+
+#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
+    TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
+#endif
+
+#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA
+    TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,    
+#endif
+
+#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
+    TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
+#endif
+
+#ifdef BUILD_TLS_ECDHE_RSA_WITH_RC4_128_SHA
+    TLS_ECDHE_RSA_WITH_RC4_128_SHA,    
+#endif
+
+#ifdef BUILD_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA
+    TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,    
+#endif
+
+#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_RC4_128_SHA
+    TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,    
+#endif
+
+#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA
+    TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA,    
+#endif
+
+};
+
+
+/* return true if set, else false */
+/* only supports full name from cipher_name[] delimited by : */
+int SetCipherList(SSL_CTX* ctx, const char* list)
+{
+    int  ret = 0, i;
+    char name[MAX_SUITE_NAME];
+
+    char  needle[] = ":";
+    char* haystack = (char*)list;
+    char* prev;
+
+    const int suiteSz = sizeof(cipher_names) / sizeof(cipher_names[0]);
+    int idx = 0;
+
+    if (!list)
+        return 0;
+    
+    if (*list == 0) return 1;   /* CyaSSL default */
+
+    if (XSTRNCMP(haystack, "ALL", 3) == 0) return 1;  /* CyaSSL defualt */
+
+    for(;;) {
+        size_t len;
+        prev = haystack;
+        haystack = XSTRSTR(haystack, needle);
+
+        if (!haystack)    /* last cipher */
+            len = min(sizeof(name), XSTRLEN(prev));
+        else
+            len = min(sizeof(name), (size_t)(haystack - prev));
+
+        XSTRNCPY(name, prev, len);
+        name[(len == sizeof(name)) ? len - 1 : len] = 0;
+
+        for (i = 0; i < suiteSz; i++)
+            if (XSTRNCMP(name, cipher_names[i], sizeof(name)) == 0) {
+                if (XSTRSTR(name, "EC"))
+                    ctx->suites.suites[idx++] = ECC_BYTE;  /* ECC suite */
+                else
+                    ctx->suites.suites[idx++] = 0x00;      /* normal */
+                ctx->suites.suites[idx++] = cipher_name_idx[i];
+
+                if (!ret) ret = 1;   /* found at least one */
+                break;
+            }
+        if (!haystack) break;
+        haystack++;
+    }
+
+    if (ret) {
+        ctx->suites.setSuites = 1;
+        ctx->suites.suiteSz   = idx;
+    }
+
+    return ret;
+}
+
+
+#ifdef CYASSL_CALLBACKS
+
+    /* Initialisze HandShakeInfo */
+    void InitHandShakeInfo(HandShakeInfo* info)
+    {
+        int i;
+
+        info->cipherName[0] = 0;
+        for (i = 0; i < MAX_PACKETS_HANDSHAKE; i++)
+            info->packetNames[i][0] = 0;
+        info->numberPackets = 0;
+        info->negotiationError = 0;
+    }
+
+    /* Set Final HandShakeInfo parameters */
+    void FinishHandShakeInfo(HandShakeInfo* info, const SSL* ssl)
+    {
+        int i;
+        int sz = sizeof(cipher_name_idx)/sizeof(int); 
+
+        for (i = 0; i < sz; i++)
+            if (ssl->options.cipherSuite == (byte)cipher_name_idx[i]) {
+                if (ssl->options.cipherSuite0 == ECC_BYTE)
+                    continue;   /* ECC suites at end */
+                XSTRNCPY(info->cipherName, cipher_names[i], MAX_CIPHERNAME_SZ);
+                break;
+            }
+
+        /* error max and min are negative numbers */
+        if (ssl->error <= MIN_PARAM_ERR && ssl->error >= MAX_PARAM_ERR)
+            info->negotiationError = ssl->error;
+    }
+
+   
+    /* Add name to info packet names, increase packet name count */
+    void AddPacketName(const char* name, HandShakeInfo* info)
+    {
+        if (info->numberPackets < MAX_PACKETS_HANDSHAKE) {
+            XSTRNCPY(info->packetNames[info->numberPackets++], name,
+                    MAX_PACKETNAME_SZ);
+        }
+    } 
+
+
+    /* Initialisze TimeoutInfo */
+    void InitTimeoutInfo(TimeoutInfo* info)
+    {
+        int i;
+
+        info->timeoutName[0] = 0;
+        info->flags          = 0;
+
+        for (i = 0; i < MAX_PACKETS_HANDSHAKE; i++) {
+            info->packets[i].packetName[0]     = 0;
+            info->packets[i].timestamp.tv_sec  = 0;
+            info->packets[i].timestamp.tv_usec = 0;
+            info->packets[i].bufferValue       = 0;
+            info->packets[i].valueSz           = 0;
+        }
+        info->numberPackets        = 0;
+        info->timeoutValue.tv_sec  = 0;
+        info->timeoutValue.tv_usec = 0;
+    }
+
+
+    /* Free TimeoutInfo */
+    void FreeTimeoutInfo(TimeoutInfo* info, void* heap)
+    {
+        int i;
+        for (i = 0; i < MAX_PACKETS_HANDSHAKE; i++)
+            if (info->packets[i].bufferValue) {
+                XFREE(info->packets[i].bufferValue, heap, DYNAMIC_TYPE_INFO);
+                info->packets[i].bufferValue = 0;
+            }
+
+    }
+
+
+    /* Add PacketInfo to TimeoutInfo */
+    void AddPacketInfo(const char* name, TimeoutInfo* info, const byte* data,
+                       int sz, void* heap)
+    {
+        if (info->numberPackets < (MAX_PACKETS_HANDSHAKE - 1)) {
+            Timeval currTime;
+
+            /* may add name after */
+            if (name)
+                XSTRNCPY(info->packets[info->numberPackets].packetName, name,
+                        MAX_PACKETNAME_SZ);
+
+            /* add data, put in buffer if bigger than static buffer */
+            info->packets[info->numberPackets].valueSz = sz;
+            if (sz < MAX_VALUE_SZ)
+                XMEMCPY(info->packets[info->numberPackets].value, data, sz);
+            else {
+                info->packets[info->numberPackets].bufferValue =
+                           XMALLOC(sz, heap, DYNAMIC_TYPE_INFO);
+                if (!info->packets[info->numberPackets].bufferValue)
+                    /* let next alloc catch, just don't fill, not fatal here  */
+                    info->packets[info->numberPackets].valueSz = 0;
+                else
+                    XMEMCPY(info->packets[info->numberPackets].bufferValue,
+                           data, sz);
+            }
+            gettimeofday(&currTime, 0);
+            info->packets[info->numberPackets].timestamp.tv_sec  =
+                                                             currTime.tv_sec;
+            info->packets[info->numberPackets].timestamp.tv_usec =
+                                                             currTime.tv_usec;
+            info->numberPackets++;
+        }
+    }
+
+
+    /* Add packet name to previsouly added packet info */
+    void AddLateName(const char* name, TimeoutInfo* info)
+    {
+        /* make sure we have a valid previous one */
+        if (info->numberPackets > 0 && info->numberPackets <
+                                                        MAX_PACKETS_HANDSHAKE) {
+            XSTRNCPY(info->packets[info->numberPackets - 1].packetName, name,
+                    MAX_PACKETNAME_SZ);
+        }
+    }
+
+    /* Add record header to previsouly added packet info */
+    void AddLateRecordHeader(const RecordLayerHeader* rl, TimeoutInfo* info)
+    {
+        /* make sure we have a valid previous one */
+        if (info->numberPackets > 0 && info->numberPackets <
+                                                        MAX_PACKETS_HANDSHAKE) {
+            if (info->packets[info->numberPackets - 1].bufferValue)
+                XMEMCPY(info->packets[info->numberPackets - 1].bufferValue, rl,
+                       RECORD_HEADER_SZ);
+            else
+                XMEMCPY(info->packets[info->numberPackets - 1].value, rl,
+                       RECORD_HEADER_SZ);
+        }
+    }
+
+#endif /* CYASSL_CALLBACKS */
+
+
+
+/* client only parts */
+#ifndef NO_CYASSL_CLIENT
+
+    int SendClientHello(SSL* ssl)
+    {
+        byte              *output;
+        word32             length, idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ;
+        int                sendSz;
+        int                idSz = ssl->options.resuming ? ID_LEN : 0;
+        int                ret;
+
+        length = sizeof(ProtocolVersion) + RAN_LEN
+               + idSz + ENUM_LEN                      
+               + ssl->suites.suiteSz + SUITE_LEN
+               + COMP_LEN  + ENUM_LEN;
+
+        sendSz = length + HANDSHAKE_HEADER_SZ + RECORD_HEADER_SZ;
+
+#ifdef CYASSL_DTLS
+        if (ssl->options.dtls) {
+            length += ENUM_LEN;   /* cookie */
+            sendSz  = length + DTLS_HANDSHAKE_HEADER_SZ + DTLS_RECORD_HEADER_SZ;
+            idx    += DTLS_HANDSHAKE_EXTRA + DTLS_RECORD_EXTRA;
+        }
+#endif
+
+        /* check for avalaible size */
+        if ((ret = CheckAvalaibleSize(ssl, sendSz)) != 0)
+            return ret;
+
+        /* get ouput buffer */
+        output = ssl->buffers.outputBuffer.buffer +
+                 ssl->buffers.outputBuffer.idx;
+
+        AddHeaders(output, length, client_hello, ssl);
+
+            /* client hello, first version */
+        XMEMCPY(output + idx, &ssl->version, sizeof(ProtocolVersion));
+        idx += sizeof(ProtocolVersion);
+        ssl->chVersion = ssl->version;  /* store in case changed */
+
+            /* then random */
+        if (ssl->options.connectState == CONNECT_BEGIN) {
+            RNG_GenerateBlock(&ssl->rng, output + idx, RAN_LEN);
+            
+                /* store random */
+            XMEMCPY(ssl->arrays.clientRandom, output + idx, RAN_LEN);
+        } else {
+#ifdef CYASSL_DTLS
+                /* send same random on hello again */
+            XMEMCPY(output + idx, ssl->arrays.clientRandom, RAN_LEN);
+#endif
+        }
+        idx += RAN_LEN;
+
+            /* then session id */
+        output[idx++] = idSz;
+        if (idSz) {
+            XMEMCPY(output + idx, ssl->session.sessionID, ID_LEN);
+            idx += ID_LEN;
+        }
+        
+            /* then DTLS cookie */
+#ifdef CYASSL_DTLS
+        if (ssl->options.dtls) {
+            output[idx++] = 0;
+        }
+#endif
+            /* then cipher suites */
+        c16toa(ssl->suites.suiteSz, output + idx);
+        idx += 2;
+        XMEMCPY(output + idx, &ssl->suites.suites, ssl->suites.suiteSz);
+        idx += ssl->suites.suiteSz;
+
+            /* last, compression */
+        output[idx++] = COMP_LEN;
+        if (ssl->options.usingCompression)
+            output[idx++] = ZLIB_COMPRESSION;
+        else
+            output[idx++] = NO_COMPRESSION;
+            
+        HashOutput(ssl, output, sendSz, 0);
+
+        ssl->options.clientState = CLIENT_HELLO_COMPLETE;
+
+#ifdef CYASSL_CALLBACKS
+        if (ssl->hsInfoOn) AddPacketName("ClientHello", &ssl->handShakeInfo);
+        if (ssl->toInfoOn)
+            AddPacketInfo("ClientHello", &ssl->timeoutInfo, output, sendSz,
+                          ssl->heap);
+#endif
+
+        ssl->buffers.outputBuffer.length += sendSz;
+
+        return SendBuffered(ssl);
+    }
+
+
+    static int DoHelloVerifyRequest(SSL* ssl, const byte* input,
+                                    word32* inOutIdx)
+    {
+        ProtocolVersion pv;
+        byte            cookieSz;
+        
+#ifdef CYASSL_CALLBACKS
+        if (ssl->hsInfoOn) AddPacketName("HelloVerifyRequest",
+                                         &ssl->handShakeInfo);
+        if (ssl->toInfoOn) AddLateName("HelloVerifyRequest", &ssl->timeoutInfo);
+#endif
+        XMEMCPY(&pv, input + *inOutIdx, sizeof(pv));
+        *inOutIdx += sizeof(pv);
+        
+        cookieSz = input[(*inOutIdx)++];
+        
+        if (cookieSz)
+            *inOutIdx += cookieSz;   /* skip for now */
+        
+        ssl->options.serverState = SERVER_HELLOVERIFYREQUEST_COMPLETE;
+        return 0;
+    }
+
+
+    static int DoServerHello(SSL* ssl, const byte* input, word32* inOutIdx)
+    {
+        byte b;
+        byte compression;
+        ProtocolVersion pv;
+        word32 i = *inOutIdx;
+
+#ifdef CYASSL_CALLBACKS
+        if (ssl->hsInfoOn) AddPacketName("ServerHello", &ssl->handShakeInfo);
+        if (ssl->toInfoOn) AddLateName("ServerHello", &ssl->timeoutInfo);
+#endif
+        XMEMCPY(&pv, input + i, sizeof(pv));
+        i += sizeof(pv);
+        XMEMCPY(ssl->arrays.serverRandom, input + i, RAN_LEN);
+        i += RAN_LEN;
+        b = input[i++];
+        if (b) {
+            XMEMCPY(ssl->arrays.sessionID, input + i, b);
+            i += b;
+        }
+        ssl->options.cipherSuite0 = input[i++];
+        ssl->options.cipherSuite  = input[i++];  
+        compression = input[i++];
+
+        if (compression != ZLIB_COMPRESSION && ssl->options.usingCompression)
+            ssl->options.usingCompression = 0;  /* turn off if server refused */
+        
+        ssl->options.serverState = SERVER_HELLO_COMPLETE;
+
+        *inOutIdx = i;
+
+        if (ssl->options.resuming) {
+            if (XMEMCMP(ssl->arrays.sessionID, ssl->session.sessionID, ID_LEN)
+                                                                        == 0) {
+                if (SetCipherSpecs(ssl) == 0) {
+                    XMEMCPY(ssl->arrays.masterSecret, ssl->session.masterSecret,
+                           SECRET_LEN);
+                    if (ssl->options.tls)
+                        DeriveTlsKeys(ssl);
+                    else
+                        DeriveKeys(ssl);
+                    ssl->options.serverState = SERVER_HELLODONE_COMPLETE;
+                    return 0;
+                }
+                else
+                    return UNSUPPORTED_SUITE;
+            }
+            else
+                ssl->options.resuming = 0; /* server denied resumption try */
+        }
+
+        return SetCipherSpecs(ssl);
+    }
+
+
+    /* just read in and ignore for now TODO: */
+    static int DoCertificateRequest(SSL* ssl, const byte* input, word32*
+                                    inOutIdx)
+    {
+        word16 len;
+       
+        #ifdef CYASSL_CALLBACKS
+            if (ssl->hsInfoOn)
+                AddPacketName("CertificateRequest", &ssl->handShakeInfo);
+            if (ssl->toInfoOn)
+                AddLateName("CertificateRequest", &ssl->timeoutInfo);
+        #endif
+        len = input[(*inOutIdx)++];
+
+        /* types, read in here */
+        *inOutIdx += len;
+        ato16(&input[*inOutIdx], &len);
+        *inOutIdx += LENGTH_SZ;
+
+        /* authorities */
+        while (len) {
+            word16 dnSz;
+       
+            ato16(&input[*inOutIdx], &dnSz);
+            *inOutIdx += (REQUEST_HEADER + dnSz);
+            len -= dnSz + REQUEST_HEADER;
+        }
+
+        /* don't send client cert or cert verify if user hasn't provided
+           cert and private key */
+        if (ssl->buffers.certificate.buffer && ssl->buffers.key.buffer)
+            ssl->options.sendVerify = SEND_CERT;
+        else if (IsAtLeastTLSv1_2(ssl))
+            ssl->options.sendVerify = SEND_BLANK_CERT;
+
+        return 0;
+    }
+
+
+    static int DoServerKeyExchange(SSL* ssl, const byte* input, word32*
+                                   inOutIdx)
+    {
+        word16 sigLen;
+        word16 verifySz;
+        word16 length;
+        byte*  signature;
+
+        sigLen    = 0;
+        signature = 0;
+
+        /* keep start idx */
+        verifySz = *inOutIdx;
+
+    #ifdef CYASSL_CALLBACKS
+        if (ssl->hsInfoOn)
+            AddPacketName("ServerKeyExchange", &ssl->handShakeInfo);
+        if (ssl->toInfoOn)
+            AddLateName("ServerKeyExchange", &ssl->timeoutInfo);
+    #endif
+
+    #ifndef NO_PSK
+        if (ssl->specs.kea == psk_kea) {
+            ato16(&input[*inOutIdx], &length);
+            *inOutIdx += LENGTH_SZ;
+            XMEMCPY(ssl->arrays.server_hint, &input[*inOutIdx],
+                   min(length, MAX_PSK_ID_LEN));
+            if (length < MAX_PSK_ID_LEN)
+                ssl->arrays.server_hint[length] = 0;
+            else
+                ssl->arrays.server_hint[MAX_PSK_ID_LEN - 1] = 0;
+            *inOutIdx += length;
+
+            return 0;
+        }
+    #endif
+    #ifdef OPENSSL_EXTRA
+        if (ssl->specs.kea == diffie_hellman_kea)
+        {
+        /* p */
+        ato16(&input[*inOutIdx], &length);
+        *inOutIdx += LENGTH_SZ;
+
+        ssl->buffers.serverDH_P.buffer = (byte*) XMALLOC(length, ssl->heap,
+                                                         DYNAMIC_TYPE_DH);
+        if (ssl->buffers.serverDH_P.buffer)
+            ssl->buffers.serverDH_P.length = length;
+        else
+            return MEMORY_ERROR;
+        XMEMCPY(ssl->buffers.serverDH_P.buffer, &input[*inOutIdx], length);
+        *inOutIdx += length;
+
+        /* g */
+        ato16(&input[*inOutIdx], &length);
+        *inOutIdx += LENGTH_SZ;
+
+        ssl->buffers.serverDH_G.buffer = (byte*) XMALLOC(length, ssl->heap,
+                                                         DYNAMIC_TYPE_DH);
+        if (ssl->buffers.serverDH_G.buffer)
+            ssl->buffers.serverDH_G.length = length;
+        else
+            return MEMORY_ERROR;
+        XMEMCPY(ssl->buffers.serverDH_G.buffer, &input[*inOutIdx], length);
+        *inOutIdx += length;
+
+        /* pub */
+        ato16(&input[*inOutIdx], &length);
+        *inOutIdx += LENGTH_SZ;
+
+        ssl->buffers.serverDH_Pub.buffer = (byte*) XMALLOC(length, ssl->heap,
+                                                           DYNAMIC_TYPE_DH);
+        if (ssl->buffers.serverDH_Pub.buffer)
+            ssl->buffers.serverDH_Pub.length = length;
+        else
+            return MEMORY_ERROR;
+        XMEMCPY(ssl->buffers.serverDH_Pub.buffer, &input[*inOutIdx], length);
+        *inOutIdx += length;
+        }  /* dh_kea */
+    #endif /* OPENSSL_EXTRA */
+
+    #ifdef HAVE_ECC
+        if (ssl->specs.kea == ecc_diffie_hellman_kea)
+        {
+        byte b = input[*inOutIdx];
+        *inOutIdx += 1;
+
+        if (b != named_curve)
+            return ECC_CURVETYPE_ERROR;
+
+        *inOutIdx += 1;   /* curve type, eat leading 0 */
+        b = input[*inOutIdx];
+        *inOutIdx += 1;
+
+        if (b != secp256r1 && b != secp384r1 && b != secp521r1 && b !=
+                 secp160r1 && b != secp192r1 && b != secp224r1)
+            return ECC_CURVE_ERROR;
+
+        length = input[*inOutIdx];
+        *inOutIdx += 1;
+
+        if (ecc_import_x963(&input[*inOutIdx], length, &ssl->peerEccKey) != 0)
+            return ECC_PEERKEY_ERROR;
+
+        *inOutIdx += length;
+        ssl->peerEccKeyPresent = 1;
+        }
+    #endif /* HAVE_ECC */
+
+    #if defined(OPENSSL_EXTRA) || defined(HAVE_ECC)
+    {
+        Md5    md5;
+        Sha    sha;
+        byte   hash[FINISHED_SZ];
+        byte   messageVerify[MAX_DH_SZ];
+
+        /* adjust from start idx */
+        verifySz = *inOutIdx - verifySz;
+
+        /* save message for hash verify */
+        if (verifySz > sizeof(messageVerify))
+            return BUFFER_ERROR;
+        XMEMCPY(messageVerify, &input[*inOutIdx - verifySz], verifySz);
+
+        /* signature */
+        ato16(&input[*inOutIdx], &length);
+        *inOutIdx += LENGTH_SZ;
+
+        signature = (byte*)&input[*inOutIdx];
+        *inOutIdx += length;
+        sigLen = length;
+
+        /* verify signature */
+
+        /* md5 */
+        InitMd5(&md5);
+        Md5Update(&md5, ssl->arrays.clientRandom, RAN_LEN);
+        Md5Update(&md5, ssl->arrays.serverRandom, RAN_LEN);
+        Md5Update(&md5, messageVerify, verifySz);
+        Md5Final(&md5, hash);
+
+        /* sha */
+        InitSha(&sha);
+        ShaUpdate(&sha, ssl->arrays.clientRandom, RAN_LEN);
+        ShaUpdate(&sha, ssl->arrays.serverRandom, RAN_LEN);
+        ShaUpdate(&sha, messageVerify, verifySz);
+        ShaFinal(&sha, &hash[MD5_DIGEST_SIZE]);
+
+        /* rsa */
+        if (ssl->specs.sig_algo == rsa_sa_algo)
+        {
+            int   ret;
+            byte* out;
+
+            if (!ssl->peerRsaKeyPresent)
+                return NO_PEER_KEY;
+
+            ret = RsaSSL_VerifyInline(signature, sigLen,&out, &ssl->peerRsaKey);
+
+            if (IsAtLeastTLSv1_2(ssl)) {
+                byte   encodedSig[MAX_ENCODED_SIG_SZ];
+                word32 encSigSz;
+                byte*  digest;
+                int    hashType;
+                int    digestSz;
+
+                /* sha1 for now */
+                digest   = &hash[MD5_DIGEST_SIZE];
+                hashType = SHAh;
+                digestSz = SHA_DIGEST_SIZE;
+
+                encSigSz = EncodeSignature(encodedSig,digest,digestSz,hashType);
+
+                if (encSigSz != ret || XMEMCMP(out, encodedSig, encSigSz) != 0)
+                    return VERIFY_SIGN_ERROR;
+            }
+            else { 
+                if (ret != sizeof(hash) || XMEMCMP(out, hash, sizeof(hash)))
+                    return VERIFY_SIGN_ERROR;
+            }
+        }
+#ifdef HAVE_ECC
+        /* ecdsa */
+        else if (ssl->specs.sig_algo == ecc_dsa_sa_algo) {
+            int verify = 0, ret;
+            if (!ssl->peerEccDsaKeyPresent)
+                return NO_PEER_KEY;
+
+            ret = ecc_verify_hash(signature, sigLen, &hash[MD5_DIGEST_SIZE],
+                                 SHA_DIGEST_SIZE, &verify, &ssl->peerEccDsaKey);
+            if (ret != 0 || verify == 0)
+                return VERIFY_SIGN_ERROR;
+        }
+#endif /* HAVE_ECC */
+        else
+            return -1;
+
+        ssl->options.serverState = SERVER_KEYEXCHANGE_COMPLETE;
+
+        return 0;
+
+    }
+#endif  /* HAVE_OPENSSL or HAVE_ECC */
+        return -1;  /* not supported by build */
+    }
+
+
+    int SendClientKeyExchange(SSL* ssl)
+    {
+        byte   encSecret[MAX_NTRU_ENCRYPT_SZ];
+        word32 encSz = 0;
+        word32 idx = 0;
+        int    ret = 0;
+
+        if (ssl->specs.kea == rsa_kea) {
+            RNG_GenerateBlock(&ssl->rng, ssl->arrays.preMasterSecret,
+                              SECRET_LEN);
+            ssl->arrays.preMasterSecret[0] = ssl->chVersion.major;
+            ssl->arrays.preMasterSecret[1] = ssl->chVersion.minor;
+            ssl->arrays.preMasterSz = SECRET_LEN;
+
+            if (ssl->peerRsaKeyPresent == 0)
+                return NO_PEER_KEY;
+
+            ret = RsaPublicEncrypt(ssl->arrays.preMasterSecret, SECRET_LEN,
+                             encSecret, sizeof(encSecret), &ssl->peerRsaKey,
+                             &ssl->rng);
+            if (ret > 0) {
+                encSz = ret;
+                ret = 0;   /* set success to 0 */
+            }
+        #ifdef OPENSSL_EXTRA
+        } else if (ssl->specs.kea == diffie_hellman_kea) {
+            buffer  serverP   = ssl->buffers.serverDH_P;
+            buffer  serverG   = ssl->buffers.serverDH_G;
+            buffer  serverPub = ssl->buffers.serverDH_Pub;
+            byte    priv[ENCRYPT_LEN];
+            word32  privSz;
+            DhKey   key;
+
+            if (serverP.buffer == 0 || serverG.buffer == 0 ||
+                                       serverPub.buffer == 0)
+                return NO_PEER_KEY;
+
+            InitDhKey(&key);
+            ret = DhSetKey(&key, serverP.buffer, serverP.length,
+                           serverG.buffer, serverG.length);
+            if (ret == 0)
+                /* for DH, encSecret is Yc, agree is pre-master */
+                ret = DhGenerateKeyPair(&key, &ssl->rng, priv, &privSz,
+                                        encSecret, &encSz);
+            if (ret == 0)
+                ret = DhAgree(&key, ssl->arrays.preMasterSecret,
+                              &ssl->arrays.preMasterSz, priv, privSz,
+                              serverPub.buffer, serverPub.length);
+            FreeDhKey(&key);
+        #endif /* OPENSSL_EXTRA */
+        #ifndef NO_PSK
+        } else if (ssl->specs.kea == psk_kea) {
+            byte* pms = ssl->arrays.preMasterSecret;
+
+            ssl->arrays.psk_keySz = ssl->options.client_psk_cb(ssl,
+                ssl->arrays.server_hint, ssl->arrays.client_identity,
+                MAX_PSK_ID_LEN, ssl->arrays.psk_key, MAX_PSK_KEY_LEN);
+            if (ssl->arrays.psk_keySz == 0 || 
+                ssl->arrays.psk_keySz > MAX_PSK_KEY_LEN)
+                return PSK_KEY_ERROR;
+            encSz = (word32)XSTRLEN(ssl->arrays.client_identity);
+            if (encSz > MAX_PSK_ID_LEN) return CLIENT_ID_ERROR;
+            XMEMCPY(encSecret, ssl->arrays.client_identity, encSz);
+
+            /* make psk pre master secret */
+            /* length of key + length 0s + length of key + key */
+            c16toa((word16)ssl->arrays.psk_keySz, pms);
+            pms += 2;
+            XMEMSET(pms, 0, ssl->arrays.psk_keySz);
+            pms += ssl->arrays.psk_keySz;
+            c16toa((word16)ssl->arrays.psk_keySz, pms);
+            pms += 2;
+            XMEMCPY(pms, ssl->arrays.psk_key, ssl->arrays.psk_keySz);
+            ssl->arrays.preMasterSz = ssl->arrays.psk_keySz * 2 + 4;
+        #endif /* NO_PSK */
+        #ifdef HAVE_NTRU
+        } else if (ssl->specs.kea == ntru_kea) {
+            word32 rc;
+            word16 cipherLen = sizeof(encSecret);
+            DRBG_HANDLE drbg;
+            static uint8_t const cyasslStr[] = {
+                'C', 'y', 'a', 'S', 'S', 'L', ' ', 'N', 'T', 'R', 'U'
+            };
+
+            RNG_GenerateBlock(&ssl->rng, ssl->arrays.preMasterSecret,
+                              SECRET_LEN);
+            ssl->arrays.preMasterSz = SECRET_LEN;
+
+            if (ssl->peerNtruKeyPresent == 0)
+                return NO_PEER_KEY;
+
+            rc = crypto_drbg_instantiate(MAX_NTRU_BITS, cyasslStr,
+                                          sizeof(cyasslStr), GetEntropy, &drbg);
+            if (rc != DRBG_OK)
+                return NTRU_DRBG_ERROR; 
+
+            rc = crypto_ntru_encrypt(drbg, ssl->peerNtruKeyLen,ssl->peerNtruKey,
+                                     ssl->arrays.preMasterSz,
+                                     ssl->arrays.preMasterSecret,
+                                     &cipherLen, encSecret);
+            crypto_drbg_uninstantiate(drbg);
+            if (rc != NTRU_OK)
+                return NTRU_ENCRYPT_ERROR;
+
+            encSz = cipherLen;
+            ret = 0;
+        #endif /* HAVE_NTRU */
+        #ifdef HAVE_ECC
+        } else if (ssl->specs.kea == ecc_diffie_hellman_kea) {
+            ecc_key myKey;
+            word32  size = sizeof(encSecret);
+
+            if (!ssl->peerEccKeyPresent || !ssl->peerEccKey.dp)
+                return NO_PEER_KEY;
+
+            ecc_init(&myKey);
+            ret = ecc_make_key(&ssl->rng, ssl->peerEccKey.dp->size, &myKey);
+            if (ret != 0)
+                return ECC_MAKEKEY_ERROR;
+
+            /* precede export with 1 byte length */
+            ret = ecc_export_x963(&myKey, encSecret + 1, &size);
+            encSecret[0] = size;
+            encSz = size + 1;
+
+            if (ret != 0)
+                ret = ECC_EXPORT_ERROR;
+            else {
+                size = sizeof(ssl->arrays.preMasterSecret);
+                ret  = ecc_shared_secret(&myKey, &ssl->peerEccKey,
+                                         ssl->arrays.preMasterSecret, &size);
+                if (ret != 0)
+                    ret = ECC_SHARED_ERROR;
+            }
+
+            ssl->arrays.preMasterSz = size;
+            ecc_free(&myKey);
+        #endif /* HAVE_ECC */
+        } else
+            return -1; /* unsupported kea */
+
+        if (ret == 0) {
+            byte              *output;
+            int                sendSz;
+            word32             tlsSz = 0;
+            
+            if (ssl->options.tls || ssl->specs.kea == diffie_hellman_kea)
+                tlsSz = 2;
+
+            if (ssl->specs.kea == ecc_diffie_hellman_kea)  /* always off */
+                tlsSz = 0;
+
+            sendSz = encSz + tlsSz + HANDSHAKE_HEADER_SZ + RECORD_HEADER_SZ;
+            idx    = HANDSHAKE_HEADER_SZ + RECORD_HEADER_SZ;
+
+            #ifdef CYASSL_DTLS
+                if (ssl->options.dtls) {
+                    sendSz += DTLS_HANDSHAKE_EXTRA + DTLS_RECORD_EXTRA;
+                    idx    += DTLS_HANDSHAKE_EXTRA + DTLS_RECORD_EXTRA;
+                }
+            #endif
+
+            /* check for avalaible size */
+            if ((ret = CheckAvalaibleSize(ssl, sendSz)) != 0)
+                return ret;
+
+            /* get ouput buffer */
+            output = ssl->buffers.outputBuffer.buffer + 
+                     ssl->buffers.outputBuffer.idx;
+
+            AddHeaders(output, encSz + tlsSz, client_key_exchange, ssl);
+
+            if (tlsSz) {
+                c16toa((word16)encSz, &output[idx]);
+                idx += 2;
+            }
+            XMEMCPY(output + idx, encSecret, encSz);
+            idx += encSz;
+
+            HashOutput(ssl, output, sendSz, 0);
+
+            #ifdef CYASSL_CALLBACKS
+                if (ssl->hsInfoOn)
+                    AddPacketName("ClientKeyExchange", &ssl->handShakeInfo);
+                if (ssl->toInfoOn)
+                    AddPacketInfo("ClientKeyExchange", &ssl->timeoutInfo,
+                                  output, sendSz, ssl->heap);
+            #endif
+
+            ssl->buffers.outputBuffer.length += sendSz;
+
+            ret = SendBuffered(ssl);
+        }
+    
+        if (ret == 0 || ret == WANT_WRITE) {
+            int tmpRet = MakeMasterSecret(ssl);
+            if (tmpRet != 0)
+                ret = tmpRet;   /* save WANT_WRITE unless more serious */
+            ssl->options.clientState = CLIENT_KEYEXCHANGE_COMPLETE;
+        }
+
+        return ret;
+    }
+
+    int SendCertificateVerify(SSL* ssl)
+    {
+        byte              *output;
+        int                sendSz = 0, length, ret;
+        word32             idx = 0;
+        RsaKey             key;
+
+        if (ssl->options.sendVerify == SEND_BLANK_CERT)
+            return 0;  /* sent blank cert, can't verify */
+
+        /* check for avalaible size */
+        if ((ret = CheckAvalaibleSize(ssl, MAX_CERT_VERIFY_SZ)) != 0)
+            return ret;
+
+        /* get ouput buffer */
+        output = ssl->buffers.outputBuffer.buffer +
+                 ssl->buffers.outputBuffer.idx;
+
+        BuildCertHashes(ssl, &ssl->certHashes);
+
+        /* TODO: when add DSS support check here  */
+        InitRsaKey(&key, ssl->heap);
+        ret = RsaPrivateKeyDecode(ssl->buffers.key.buffer, &idx, &key,
+                                  ssl->buffers.key.length); 
+        if (ret == 0) {
+            byte*  verify = (byte*)&output[RECORD_HEADER_SZ +
+                                           HANDSHAKE_HEADER_SZ];
+            byte*  signBuffer = ssl->certHashes.md5;
+            word32 signSz = sizeof(Hashes);
+            byte  encodedSig[MAX_ENCODED_SIG_SZ];
+
+            #ifdef CYASSL_DTLS
+                if (ssl->options.dtls)
+                    verify += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA;
+            #endif
+            length = RsaEncryptSize(&key);
+            c16toa((word16)length, verify);   /* prepend verify header */
+
+            if (IsAtLeastTLSv1_2(ssl)) {
+                byte* digest;
+                int   hashType;
+                int   digestSz;
+
+                /* sha1 for now */
+                digest   = ssl->certHashes.sha;
+                hashType = SHAh;
+                digestSz = SHA_DIGEST_SIZE;
+
+                signSz = EncodeSignature(encodedSig, digest, digestSz,hashType);
+                signBuffer = encodedSig;
+            }
+
+            ret = RsaSSL_Sign(signBuffer, signSz, verify +
+                  VERIFY_HEADER, ENCRYPT_LEN, &key, &ssl->rng);
+
+            if (ret > 0) {
+                ret = 0;  /* reset */
+
+                AddHeaders(output, length + VERIFY_HEADER, certificate_verify,
+                           ssl);
+
+                sendSz = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ + length +
+                                            VERIFY_HEADER;
+                #ifdef CYASSL_DTLS
+                    if (ssl->options.dtls)
+                        sendSz += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA;
+                #endif
+                HashOutput(ssl, output, sendSz, 0);
+            }
+        }
+
+        FreeRsaKey(&key);
+
+        if (ret == 0) {
+            #ifdef CYASSL_CALLBACKS
+                if (ssl->hsInfoOn)
+                    AddPacketName("CertificateVerify", &ssl->handShakeInfo);
+                if (ssl->toInfoOn)
+                    AddPacketInfo("CertificateVerify", &ssl->timeoutInfo,
+                                  output, sendSz, ssl->heap);
+            #endif
+            ssl->buffers.outputBuffer.length += sendSz;
+            return SendBuffered(ssl);
+        }
+        else
+            return ret;
+    }
+
+
+
+#endif /* NO_CYASSL_CLIENT */
+
+
+#ifndef NO_CYASSL_SERVER
+
+    int SendServerHello(SSL* ssl)
+    {
+        byte              *output;
+        word32             length, idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ;
+        int                sendSz;
+        int                ret;
+
+        length = sizeof(ProtocolVersion) + RAN_LEN
+               + ID_LEN + ENUM_LEN                 
+               + SUITE_LEN 
+               + ENUM_LEN;
+
+        /* check for avalaible size */
+        if ((ret = CheckAvalaibleSize(ssl, MAX_HELLO_SZ)) != 0)
+            return ret;
+
+        /* get ouput buffer */
+        output = ssl->buffers.outputBuffer.buffer + 
+                 ssl->buffers.outputBuffer.idx;
+
+        sendSz = length + HANDSHAKE_HEADER_SZ + RECORD_HEADER_SZ;
+        AddHeaders(output, length, server_hello, ssl);
+
+        #ifdef CYASSL_DTLS
+            if (ssl->options.dtls) {
+                idx    += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA;
+                sendSz += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA;
+            }
+        #endif
+        /* now write to output */
+            /* first version */
+        XMEMCPY(output + idx, &ssl->version, sizeof(ProtocolVersion));
+        idx += sizeof(ProtocolVersion);
+
+            /* then random */
+        if (!ssl->options.resuming)         
+            RNG_GenerateBlock(&ssl->rng, ssl->arrays.serverRandom, RAN_LEN);
+        XMEMCPY(output + idx, ssl->arrays.serverRandom, RAN_LEN);
+        idx += RAN_LEN;
+
+#ifdef SHOW_SECRETS
+        {
+            int j;
+            printf("server random: ");
+            for (j = 0; j < RAN_LEN; j++)
+                printf("%02x", ssl->arrays.serverRandom[j]);
+            printf("\n");
+        }
+#endif
+            /* then session id */
+        output[idx++] = ID_LEN;
+        if (!ssl->options.resuming)
+            RNG_GenerateBlock(&ssl->rng, ssl->arrays.sessionID, ID_LEN);
+        XMEMCPY(output + idx, ssl->arrays.sessionID, ID_LEN);
+        idx += ID_LEN;
+
+            /* then cipher suite */
+        output[idx++] = ssl->options.cipherSuite0; 
+        output[idx++] = ssl->options.cipherSuite;
+
+            /* last, compression */
+        if (ssl->options.usingCompression)
+            output[idx++] = ZLIB_COMPRESSION;
+        else
+            output[idx++] = NO_COMPRESSION;
+            
+        ssl->buffers.outputBuffer.length += sendSz;
+        HashOutput(ssl, output, sendSz, 0);
+
+        #ifdef CYASSL_CALLBACKS
+            if (ssl->hsInfoOn)
+                AddPacketName("ServerHello", &ssl->handShakeInfo);
+            if (ssl->toInfoOn)
+                AddPacketInfo("ServerHello", &ssl->timeoutInfo, output, sendSz,
+                              ssl->heap);
+        #endif
+
+        ssl->options.serverState = SERVER_HELLO_COMPLETE;
+
+        return SendBuffered(ssl);
+    }
+
+
+#ifdef HAVE_ECC
+
+    byte SetCurveId(int size)
+    {
+        switch(size) {
+            case 20:
+                return secp160r1;
+                break;
+            case 24:
+                return secp192r1;
+                break;
+            case 28:
+                return secp224r1;
+                break;
+            case 32:
+                return secp256r1;
+                break;
+            case 48:
+                return secp384r1;
+                break;
+            case 66:
+                return secp521r1;
+                break;
+            default:
+                return 0;
+        }        
+    }
+
+#endif /* HAVE_ECC */
+
+
+    int SendServerKeyExchange(SSL* ssl)
+    {
+        int ret = 0;
+
+        #ifndef NO_PSK
+        if (ssl->specs.kea == psk_kea)
+        {
+            byte    *output;
+            word32   length, idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ;
+            int      sendSz;
+            if (ssl->arrays.server_hint[0] == 0) return 0; /* don't send */
+
+            /* include size part */
+            length = (word32)XSTRLEN(ssl->arrays.server_hint);
+            if (length > MAX_PSK_ID_LEN) return SERVER_HINT_ERROR;
+            length += HINT_LEN_SZ;
+            sendSz = length + HANDSHAKE_HEADER_SZ + RECORD_HEADER_SZ;
+
+            #ifdef CYASSL_DTLS 
+                if (ssl->options.dtls) {
+                    sendSz += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA;
+                    idx    += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA;
+                }
+            #endif
+            /* check for avalaible size */
+            if ((ret = CheckAvalaibleSize(ssl, sendSz)) != 0)
+               return ret;
+
+            /* get ouput buffer */
+            output = ssl->buffers.outputBuffer.buffer + 
+                     ssl->buffers.outputBuffer.idx;
+
+            AddHeaders(output, length, server_key_exchange, ssl);
+
+            /* key data */
+            c16toa((word16)(length - HINT_LEN_SZ), output + idx);
+            idx += HINT_LEN_SZ;
+            XMEMCPY(output + idx, ssl->arrays.server_hint, length -HINT_LEN_SZ);
+
+            HashOutput(ssl, output, sendSz, 0);
+
+            #ifdef CYASSL_CALLBACKS
+                if (ssl->hsInfoOn)
+                    AddPacketName("ServerKeyExchange", &ssl->handShakeInfo);
+                if (ssl->toInfoOn)
+                    AddPacketInfo("ServerKeyExchange", &ssl->timeoutInfo,
+                                  output, sendSz, ssl->heap);
+            #endif
+
+            ssl->buffers.outputBuffer.length += sendSz;
+            ret = SendBuffered(ssl);
+            ssl->options.serverState = SERVER_KEYEXCHANGE_COMPLETE;
+        }
+        #endif /*NO_PSK */
+
+        #ifdef HAVE_ECC
+        if (ssl->specs.kea == ecc_diffie_hellman_kea)
+        {
+            byte    *output;
+            word32   length, idx = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ;
+            int      sendSz;
+            byte     export[MAX_EXPORT_ECC_SZ];
+            word32   expSz = sizeof(export);
+            word32   sigSz;
+            word32   preSigSz, preSigIdx;
+            RsaKey   rsaKey;
+            ecc_key  dsaKey;
+
+            /* curve type, named curve, length(1) */
+            length = ENUM_LEN + CURVE_LEN + ENUM_LEN;
+            /* pub key size */
+            if (ecc_export_x963(&ssl->eccTempKey, export, &expSz) != 0)
+                return ECC_EXPORT_ERROR;
+            length += expSz;
+
+            preSigSz  = length;
+            preSigIdx = idx;
+
+            InitRsaKey(&rsaKey, ssl->heap);
+            ecc_init(&dsaKey);
+
+            /* sig length */
+            length += LENGTH_SZ;
+
+            if (!ssl->buffers.key.buffer) {
+                FreeRsaKey(&rsaKey);
+                ecc_free(&dsaKey);
+                return NO_PRIVATE_KEY;
+            }
+
+            if (ssl->specs.sig_algo == rsa_sa_algo) {
+                /* rsa sig size */
+                word32 i = 0;
+                ret = RsaPrivateKeyDecode(ssl->buffers.key.buffer, &i,
+                                          &rsaKey, ssl->buffers.key.length);
+                if (ret != 0) return ret;
+                sigSz = RsaEncryptSize(&rsaKey); 
+            }
+            else if (ssl->specs.sig_algo == ecc_dsa_sa_algo) {
+                /* ecdsa sig size */
+                word32 i = 0;
+                ret = EccPrivateKeyDecode(ssl->buffers.key.buffer, &i,
+                                          &dsaKey, ssl->buffers.key.length);
+                if (ret != 0) return ret;
+                sigSz = ecc_sig_size(&dsaKey);
+            }
+            else {
+                FreeRsaKey(&rsaKey);
+                ecc_free(&dsaKey);
+                return -1;  /* unsupported type */
+            }
+            length += sigSz;
+
+            sendSz = length + HANDSHAKE_HEADER_SZ + RECORD_HEADER_SZ;
+
+            #ifdef CYASSL_DTLS 
+                if (ssl->options.dtls) {
+                    sendSz += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA;
+                    idx    += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA;
+                }
+            #endif
+            /* check for avalaible size */
+            if ((ret = CheckAvalaibleSize(ssl, sendSz)) != 0) {
+                FreeRsaKey(&rsaKey);
+                ecc_free(&dsaKey); 
+                return ret;
+            } 
+
+            /* get ouput buffer */
+            output = ssl->buffers.outputBuffer.buffer + 
+                     ssl->buffers.outputBuffer.idx;
+
+            AddHeaders(output, length, server_key_exchange, ssl);
+
+            /* key exchange data */
+            output[idx++] = named_curve;
+            output[idx++] = 0x00;          /* leading zero */
+            output[idx++] = SetCurveId(ecc_size(&ssl->eccTempKey)); 
+            output[idx++] = expSz;
+            XMEMCPY(output + idx, export, expSz);
+            idx += expSz;
+            c16toa(sigSz, output + idx);
+            idx += LENGTH_SZ;
+
+            /* do signature */
+            {
+                Md5    md5;
+                Sha    sha;
+                byte   hash[FINISHED_SZ];
+                byte*  signBuffer = hash;
+                word32 signSz    = sizeof(hash);
+
+                /* md5 */
+                InitMd5(&md5);
+                Md5Update(&md5, ssl->arrays.clientRandom, RAN_LEN);
+                Md5Update(&md5, ssl->arrays.serverRandom, RAN_LEN);
+                Md5Update(&md5, output + preSigIdx, preSigSz);
+                Md5Final(&md5, hash);
+
+                /* sha */
+                InitSha(&sha);
+                ShaUpdate(&sha, ssl->arrays.clientRandom, RAN_LEN);
+                ShaUpdate(&sha, ssl->arrays.serverRandom, RAN_LEN);
+                ShaUpdate(&sha, output + preSigIdx, preSigSz);
+                ShaFinal(&sha, &hash[MD5_DIGEST_SIZE]);
+
+                if (ssl->specs.sig_algo == rsa_sa_algo) {
+                    byte encodedSig[MAX_ENCODED_SIG_SZ];
+                    if (IsAtLeastTLSv1_2(ssl)) {
+                        byte* digest;
+                        int   hashType;
+                        int   digestSz;
+
+                        /* sha1 for now */
+                        digest   = &hash[MD5_DIGEST_SIZE];
+                        hashType = SHAh;
+                        digestSz = SHA_DIGEST_SIZE;
+
+                        signSz = EncodeSignature(encodedSig, digest, digestSz,
+                                                 hashType);
+                        signBuffer = encodedSig;
+                    }
+                    ret = RsaSSL_Sign(signBuffer, signSz, output + idx, sigSz,
+                                      &rsaKey, &ssl->rng);
+                    FreeRsaKey(&rsaKey);
+                    if (ret > 0)
+                        ret = 0;  /* reset on success */
+                    else
+                        return ret;
+                }
+                else if (ssl->specs.sig_algo == ecc_dsa_sa_algo) {
+                    word32 sz = sigSz;
+
+                    FreeRsaKey(&rsaKey);
+                    ret = ecc_sign_hash(&hash[MD5_DIGEST_SIZE], SHA_DIGEST_SIZE,
+                            output + idx, &sz, &ssl->rng, &dsaKey);
+                }
+            }
+
+            HashOutput(ssl, output, sendSz, 0);
+
+            #ifdef CYASSL_CALLBACKS
+                if (ssl->hsInfoOn)
+                    AddPacketName("ServerKeyExchange", &ssl->handShakeInfo);
+                if (ssl->toInfoOn)
+                    AddPacketInfo("ServerKeyExchange", &ssl->timeoutInfo,
+                                  output, sendSz, ssl->heap);
+            #endif
+
+            ssl->buffers.outputBuffer.length += sendSz;
+            ret = SendBuffered(ssl);
+            ssl->options.serverState = SERVER_KEYEXCHANGE_COMPLETE;
+        }
+        #endif /* HAVE_ECC */
+
+        return ret;
+    }
+
+
+    static int MatchSuite(SSL* ssl, Suites* peerSuites)
+    {
+        word16 i, j;
+
+        /* & 0x1 equivalent % 2 */
+        if (peerSuites->suiteSz == 0 || peerSuites->suiteSz & 0x1)
+            return MATCH_SUITE_ERROR;
+
+        /* start with best, if a match we are good */
+        for (i = 0; i < ssl->suites.suiteSz; i += 2)
+            for (j = 0; j < peerSuites->suiteSz; j += 2)
+                if (ssl->suites.suites[i]   == peerSuites->suites[j] &&
+                    ssl->suites.suites[i+1] == peerSuites->suites[j+1] ) {
+
+                    ssl->options.cipherSuite0 = ssl->suites.suites[i];
+                    ssl->options.cipherSuite  = ssl->suites.suites[i+1];
+                    return SetCipherSpecs(ssl);
+                }
+
+        return MATCH_SUITE_ERROR;
+    }
+
+
+    /* process alert, return level */
+    int ProcessOldClientHello(SSL* ssl, const byte* input, word32* inOutIdx,
+                              word32 inSz, word16 sz)
+    {
+        word32          idx = *inOutIdx;
+        word16          sessionSz;
+        word16          randomSz;
+        word16          i, j;
+        ProtocolVersion pv;
+        Suites          clSuites;
+
+#ifdef CYASSL_CALLBACKS
+        if (ssl->hsInfoOn)
+            AddPacketName("ClientHello", &ssl->handShakeInfo);
+        if (ssl->toInfoOn)
+            AddLateName("ClientHello", &ssl->timeoutInfo);
+#endif
+
+        /* manually hash input since different format */
+        Md5Update(&ssl->hashMd5, input + idx, sz);
+        ShaUpdate(&ssl->hashSha, input + idx, sz);
+
+        /* does this value mean client_hello? */
+        idx++;
+
+        /* version */
+        pv.major = input[idx++];
+        pv.minor = input[idx++];
+        ssl->chVersion = pv;  /* store */
+
+        if (ssl->version.minor > 0 && pv.minor == 0) {
+            if (!ssl->options.downgrade)
+                return VERSION_ERROR;
+            /* turn off tls */
+            ssl->options.tls    = 0;
+            ssl->options.tls1_1 = 0;
+            ssl->version.minor  = 0;
+            InitSuites(&ssl->suites, ssl->version, ssl->options.haveDH, FALSE,
+                       ssl->options.haveNTRU, ssl->options.haveECDSA,
+                       ssl->ctx->method->side);
+        }
+
+        /* suite size */
+        ato16(&input[idx], &clSuites.suiteSz);
+        idx += 2;
+
+        if (clSuites.suiteSz > MAX_SUITE_SZ)
+            return BUFFER_ERROR;
+
+        /* session size */
+        ato16(&input[idx], &sessionSz);
+        idx += 2;
+
+        if (sessionSz > ID_LEN)
+            return BUFFER_ERROR;
+    
+        /* random size */
+        ato16(&input[idx], &randomSz);
+        idx += 2;
+
+        if (randomSz > RAN_LEN)
+            return BUFFER_ERROR;
+
+        /* suites */
+        for (i = 0, j = 0; i < clSuites.suiteSz; i += 3) {    
+            byte first = input[idx++];
+            if (!first) { /* implicit: skip sslv2 type */
+                XMEMCPY(&clSuites.suites[j], &input[idx], 2);
+                j += 2;
+            }
+            idx += 2;
+        }
+        clSuites.suiteSz = j;
+
+        /* session id */
+        if (sessionSz) {
+            XMEMCPY(ssl->arrays.sessionID, input + idx, sessionSz);
+            idx += sessionSz;
+            ssl->options.resuming = 1;
+        }
+
+        /* random */
+        if (randomSz < RAN_LEN)
+            XMEMSET(ssl->arrays.clientRandom, 0, RAN_LEN - randomSz);
+        XMEMCPY(&ssl->arrays.clientRandom[RAN_LEN - randomSz], input + idx,
+               randomSz);
+        idx += randomSz;
+
+        if (ssl->options.usingCompression)
+            ssl->options.usingCompression = 0;  /* turn off */
+
+        ssl->options.clientState = CLIENT_HELLO_COMPLETE;
+        *inOutIdx = idx;
+
+        /* DoClientHello uses same resume code */
+        while (ssl->options.resuming) {  /* let's try */
+            SSL_SESSION* session = GetSession(ssl, ssl->arrays.masterSecret);
+            if (!session) {
+                ssl->options.resuming = 0;
+                break;   /* session lookup failed */
+            }
+            if (MatchSuite(ssl, &clSuites) < 0)
+                return UNSUPPORTED_SUITE;
+
+            RNG_GenerateBlock(&ssl->rng, ssl->arrays.serverRandom, RAN_LEN);
+            if (ssl->options.tls)
+                DeriveTlsKeys(ssl);
+            else
+                DeriveKeys(ssl);
+            ssl->options.clientState = CLIENT_KEYEXCHANGE_COMPLETE;
+
+            return 0;
+        }
+
+        return MatchSuite(ssl, &clSuites);
+    }
+
+
+    static int DoClientHello(SSL* ssl, const byte* input, word32* inOutIdx,
+                             word32 totalSz, word32 helloSz)
+    {
+        byte b;
+        ProtocolVersion pv;
+        Suites          clSuites;
+        word32 i = *inOutIdx;
+        word32 begin = i;
+
+#ifdef CYASSL_CALLBACKS
+        if (ssl->hsInfoOn) AddPacketName("ClientHello", &ssl->handShakeInfo);
+        if (ssl->toInfoOn) AddLateName("ClientHello", &ssl->timeoutInfo);
+#endif
+        /* make sure can read up to session */
+        if (i + sizeof(pv) + RAN_LEN + ENUM_LEN > totalSz)
+            return INCOMPLETE_DATA;
+
+        XMEMCPY(&pv, input + i, sizeof(pv));
+        ssl->chVersion = pv;   /* store */
+        i += sizeof(pv);
+        if (ssl->version.minor > 0 && pv.minor == 0) {
+            if (!ssl->options.downgrade)
+                return VERSION_ERROR;
+            /* turn off tls */
+            ssl->options.tls    = 0;
+            ssl->options.tls1_1 = 0;
+            ssl->version.minor  = 0;
+            InitSuites(&ssl->suites, ssl->version, ssl->options.haveDH, FALSE,
+                       ssl->options.haveNTRU, ssl->options.haveECDSA,
+                       ssl->ctx->method->side);
+        }
+        /* random */
+        XMEMCPY(ssl->arrays.clientRandom, input + i, RAN_LEN);
+        i += RAN_LEN;
+
+#ifdef SHOW_SECRETS
+        {
+            int j;
+            printf("client random: ");
+            for (j = 0; j < RAN_LEN; j++)
+                printf("%02x", ssl->arrays.clientRandom[j]);
+            printf("\n");
+        }
+#endif
+        /* session id */
+        b = input[i++];
+        if (b) {
+            if (i + ID_LEN > totalSz)
+                return INCOMPLETE_DATA;
+            XMEMCPY(ssl->arrays.sessionID, input + i, ID_LEN);
+            i += b;
+            ssl->options.resuming= 1; /* client wants to resume */
+        }
+        
+        #ifdef CYASSL_DTLS
+            /* cookie */
+            if (ssl->options.dtls) {
+                b = input[i++];
+                if (b) {
+                    if (b > MAX_COOKIE_LEN)
+                        return BUFFER_ERROR;
+                    if (i + b > totalSz)
+                        return INCOMPLETE_DATA;
+                    XMEMCPY(ssl->arrays.cookie, input + i, b);
+                    i += b;
+                }
+            }
+        #endif
+
+        if (i + LENGTH_SZ > totalSz)
+            return INCOMPLETE_DATA;
+        /* suites */
+        ato16(&input[i], &clSuites.suiteSz);
+        i += 2;
+
+        /* suites and comp len */
+        if (i + clSuites.suiteSz + ENUM_LEN > totalSz)
+            return INCOMPLETE_DATA;
+        if (clSuites.suiteSz > MAX_SUITE_SZ)
+            return BUFFER_ERROR;
+        XMEMCPY(clSuites.suites, input + i, clSuites.suiteSz);
+        i += clSuites.suiteSz;
+
+        b = input[i++];  /* comp len */
+        if (i + b > totalSz)
+            return INCOMPLETE_DATA;
+
+        if (ssl->options.usingCompression) {
+            int match = 0;
+            while (b--) {
+                byte comp = input[i++];
+                if (comp == ZLIB_COMPRESSION)
+                    match = 1;
+            }
+            if (!match)
+                ssl->options.usingCompression = 0;  /* turn off */
+        }
+        else
+            i += b;  /* ignore, since we're not on */
+
+        ssl->options.clientState = CLIENT_HELLO_COMPLETE;
+
+        *inOutIdx = i;
+        if ( (i - begin) < helloSz)
+            *inOutIdx = begin + helloSz;  /* skip extensions */
+        
+        /* ProcessOld uses same resume code */
+        while (ssl->options.resuming) {  /* let's try */
+            SSL_SESSION* session = GetSession(ssl, ssl->arrays.masterSecret);
+            if (!session) {
+                ssl->options.resuming = 0;
+                break;   /* session lookup failed */
+            }
+            if (MatchSuite(ssl, &clSuites) < 0)
+                return UNSUPPORTED_SUITE;
+
+            RNG_GenerateBlock(&ssl->rng, ssl->arrays.serverRandom, RAN_LEN);
+            if (ssl->options.tls)
+                DeriveTlsKeys(ssl);
+            else
+                DeriveKeys(ssl);
+            ssl->options.clientState = CLIENT_KEYEXCHANGE_COMPLETE;
+
+            return 0;
+        }
+        return MatchSuite(ssl, &clSuites);
+    }
+
+
+    static int DoCertificateVerify(SSL* ssl, byte* input, word32* inOutsz,
+                                   word32 totalSz)
+    {
+        word16      sz = 0;
+        word32      i = *inOutsz;
+        int         ret = VERIFY_CERT_ERROR;   /* start in error state */
+        byte*       sig;
+        byte*       out;
+        int         outLen;
+
+        #ifdef CYASSL_CALLBACKS
+            if (ssl->hsInfoOn)
+                AddPacketName("CertificateVerify", &ssl->handShakeInfo);
+            if (ssl->toInfoOn)
+                AddLateName("CertificateVerify", &ssl->timeoutInfo);
+        #endif
+        if ( (i + VERIFY_HEADER) > totalSz)
+            return INCOMPLETE_DATA;
+
+        ato16(&input[i], &sz);
+        i += VERIFY_HEADER;
+
+        if ( (i + sz) > totalSz)
+            return INCOMPLETE_DATA;
+
+        if (sz > ENCRYPT_LEN)
+            return BUFFER_ERROR;
+
+        sig = &input[i];
+        *inOutsz = i + sz;
+        /* TODO: when add DSS support check here  */
+        if (ssl->peerRsaKeyPresent != 0) {
+            outLen = RsaSSL_VerifyInline(sig, sz, &out, &ssl->peerRsaKey);
+
+            if (IsAtLeastTLSv1_2(ssl)) {
+                byte   encodedSig[MAX_ENCODED_SIG_SZ];
+                word32 sigSz;
+                byte*  digest;
+                int    hashType;
+                int    digestSz;
+
+                /* sha1 for now */
+                digest   = ssl->certHashes.sha;
+                hashType = SHAh;
+                digestSz = SHA_DIGEST_SIZE;
+
+                sigSz = EncodeSignature(encodedSig, digest, digestSz, hashType);
+
+                if (outLen == sigSz && XMEMCMP(out, encodedSig, sigSz) == 0)
+                    ret = 0;
+            }
+            else {
+                if (outLen == sizeof(ssl->certHashes) && XMEMCMP(out,
+                             ssl->certHashes.md5, sizeof(ssl->certHashes)) == 0)
+                    ret = 0;
+            }
+        }
+        return ret;
+    }
+
+
+    int SendServerHelloDone(SSL* ssl)
+    {
+        byte              *output;
+        int                sendSz = RECORD_HEADER_SZ + HANDSHAKE_HEADER_SZ;
+        int                ret;
+
+        #ifdef CYASSL_DTLS
+            if (ssl->options.dtls)
+                sendSz += DTLS_RECORD_EXTRA + DTLS_HANDSHAKE_EXTRA;
+        #endif
+        /* check for avalaible size */
+        if ((ret = CheckAvalaibleSize(ssl, sendSz)) != 0)
+            return ret;
+
+        /* get ouput buffer */
+        output = ssl->buffers.outputBuffer.buffer +
+                 ssl->buffers.outputBuffer.idx;
+
+        AddHeaders(output, 0, server_hello_done, ssl);
+
+        HashOutput(ssl, output, sendSz, 0);
+#ifdef CYASSL_CALLBACKS
+        if (ssl->hsInfoOn)
+            AddPacketName("ServerHelloDone", &ssl->handShakeInfo);
+        if (ssl->toInfoOn)
+            AddPacketInfo("ServerHelloDone", &ssl->timeoutInfo, output, sendSz,
+                          ssl->heap);
+#endif
+        ssl->options.serverState = SERVER_HELLODONE_COMPLETE;
+
+        ssl->buffers.outputBuffer.length += sendSz;
+
+        return SendBuffered(ssl);
+    }
+
+
+    int SendHelloVerifyRequest(SSL* ssl)
+    {
+        byte* output;
+        int   length = VERSION_SZ + ENUM_LEN;
+        int   idx    = DTLS_RECORD_HEADER_SZ + DTLS_HANDSHAKE_HEADER_SZ;
+        int   sendSz = length + idx;
+        int   ret;
+
+        /* check for avalaible size */
+        if ((ret = CheckAvalaibleSize(ssl, sendSz)) != 0)
+            return ret;
+
+        /* get ouput buffer */
+        output = ssl->buffers.outputBuffer.buffer +
+                 ssl->buffers.outputBuffer.idx;
+
+        AddHeaders(output, length, hello_verify_request, ssl);
+
+        XMEMCPY(output + idx, &ssl->chVersion, VERSION_SZ);
+        idx += VERSION_SZ;
+        output[idx++] = 0;     /* no cookie for now */
+
+        HashOutput(ssl, output, sendSz, 0);
+#ifdef CYASSL_CALLBACKS
+        if (ssl->hsInfoOn)
+            AddPacketName("HelloVerifyRequest", &ssl->handShakeInfo);
+        if (ssl->toInfoOn)
+            AddPacketInfo("HelloVerifyRequest", &ssl->timeoutInfo, output,
+                          sendSz, ssl->heap);
+#endif
+        ssl->options.serverState = SERVER_HELLOVERIFYREQUEST_COMPLETE;
+
+        ssl->buffers.outputBuffer.length += sendSz;
+
+        return SendBuffered(ssl);
+    }
+
+
+    static int DoClientKeyExchange(SSL* ssl, byte* input,
+                                   word32* inOutIdx)
+    {
+        int    ret = 0;
+        word32 length = 0;
+        byte*  out;
+
+        if (ssl->options.verifyPeer && ssl->options.failNoCert)
+            if (!ssl->options.havePeerCert) {
+                CYASSL_MSG("client didn't present peer cert");
+                return NO_PEER_CERT;
+            }
+
+        #ifdef CYASSL_CALLBACKS
+            if (ssl->hsInfoOn)
+                AddPacketName("ClientKeyExchange", &ssl->handShakeInfo);
+            if (ssl->toInfoOn)
+                AddLateName("ClientKeyExchange", &ssl->timeoutInfo);
+        #endif
+        if (ssl->specs.kea == rsa_kea) {
+            word32 idx = 0;
+            RsaKey key;
+            byte*  tmp = 0;
+
+            InitRsaKey(&key, ssl->heap);
+
+            if (ssl->buffers.key.buffer)
+                ret = RsaPrivateKeyDecode(ssl->buffers.key.buffer, &idx, &key,
+                                          ssl->buffers.key.length);
+            else
+                return NO_PRIVATE_KEY;
+
+            if (ret == 0) {
+                length = RsaEncryptSize(&key);
+                ssl->arrays.preMasterSz = SECRET_LEN;
+
+                if (ssl->options.tls)
+                    (*inOutIdx) += 2;
+                tmp = input + *inOutIdx;
+                *inOutIdx += length;
+
+                if (RsaPrivateDecryptInline(tmp, length, &out, &key) ==
+                                                             SECRET_LEN) {
+                    XMEMCPY(ssl->arrays.preMasterSecret, out, SECRET_LEN);
+                    if (ssl->arrays.preMasterSecret[0] != ssl->chVersion.major
+                     ||
+                        ssl->arrays.preMasterSecret[1] != ssl->chVersion.minor)
+
+                        ret = PMS_VERSION_ERROR;
+                    else
+                        ret = MakeMasterSecret(ssl);
+                }
+                else
+                    ret = RSA_PRIVATE_ERROR;
+            }
+
+            FreeRsaKey(&key);
+#ifndef NO_PSK
+        } else if (ssl->specs.kea == psk_kea) {
+            byte* pms = ssl->arrays.preMasterSecret;
+            word16 ci_sz;
+
+            ato16(&input[*inOutIdx], &ci_sz);
+            *inOutIdx += LENGTH_SZ;
+            if (ci_sz > MAX_PSK_ID_LEN) return CLIENT_ID_ERROR;
+
+            XMEMCPY(ssl->arrays.client_identity, &input[*inOutIdx], ci_sz);
+            *inOutIdx += ci_sz;
+            ssl->arrays.client_identity[ci_sz] = 0;
+
+            ssl->arrays.psk_keySz = ssl->options.server_psk_cb(ssl,
+                ssl->arrays.client_identity, ssl->arrays.psk_key,
+                MAX_PSK_KEY_LEN);
+            if (ssl->arrays.psk_keySz == 0 || 
+                ssl->arrays.psk_keySz > MAX_PSK_KEY_LEN) return PSK_KEY_ERROR;
+            
+            /* make psk pre master secret */
+            /* length of key + length 0s + length of key + key */
+            c16toa((word16)ssl->arrays.psk_keySz, pms);
+            pms += 2;
+            XMEMSET(pms, 0, ssl->arrays.psk_keySz);
+            pms += ssl->arrays.psk_keySz;
+            c16toa((word16)ssl->arrays.psk_keySz, pms);
+            pms += 2;
+            XMEMCPY(pms, ssl->arrays.psk_key, ssl->arrays.psk_keySz);
+            ssl->arrays.preMasterSz = ssl->arrays.psk_keySz * 2 + 4;
+
+            ret = MakeMasterSecret(ssl);
+#endif /* NO_PSK */
+#ifdef HAVE_NTRU
+        } else if (ssl->specs.kea == ntru_kea) {
+            word32 rc;
+            word16 cipherLen;
+            word16 plainLen = sizeof(ssl->arrays.preMasterSecret);
+            byte*  tmp;
+
+            if (!ssl->buffers.key.buffer)
+                return NO_PRIVATE_KEY;
+
+            ato16(&input[*inOutIdx], &cipherLen);
+            *inOutIdx += LENGTH_SZ;
+            if (cipherLen > MAX_NTRU_ENCRYPT_SZ)
+                return NTRU_KEY_ERROR;
+
+            tmp = input + *inOutIdx;
+            rc = crypto_ntru_decrypt((word16)ssl->buffers.key.length,
+                        ssl->buffers.key.buffer, cipherLen, tmp, &plainLen,
+                        ssl->arrays.preMasterSecret);
+
+            if (rc != NTRU_OK || plainLen != SECRET_LEN)
+                return NTRU_DECRYPT_ERROR;
+            *inOutIdx += cipherLen;
+
+            ssl->arrays.preMasterSz = plainLen;
+            ret = MakeMasterSecret(ssl);
+#endif /* HAVE_NTRU */
+#ifdef HAVE_ECC
+        } else if (ssl->specs.kea == ecc_diffie_hellman_kea) {
+            word32 size;
+            word32 length = input[*inOutIdx];  /* one byte length */
+            *inOutIdx += 1;
+
+            ret = ecc_import_x963(&input[*inOutIdx], length, &ssl->peerEccKey);
+            if (ret != 0)
+                return ECC_PEERKEY_ERROR;
+            *inOutIdx += length;
+            ssl->peerEccKeyPresent = 1;
+
+            size = sizeof(ssl->arrays.preMasterSecret);
+            ret = ecc_shared_secret(&ssl->eccTempKey, &ssl->peerEccKey,
+                                    ssl->arrays.preMasterSecret, &size);
+            if (ret != 0)
+                return ECC_SHARED_ERROR;
+            ssl->arrays.preMasterSz = size;
+            ret = MakeMasterSecret(ssl);
+#endif /* HAVE_ECC */
+        }
+
+        if (ret == 0) {
+            ssl->options.clientState = CLIENT_KEYEXCHANGE_COMPLETE;
+            if (ssl->options.verifyPeer)
+                BuildCertHashes(ssl, &ssl->certHashes);
+        }
+
+        return ret;
+    }
+
+#endif /* NO_CYASSL_SERVER */
+
+
+#ifdef SINGLE_THREADED
+
+int InitMutex(CyaSSL_Mutex* m)
+{
+    return 0;
+}
+
+
+int FreeMutex(CyaSSL_Mutex* m)
+{
+    return 0;
+}
+
+
+int LockMutex(CyaSSL_Mutex* m)
+{
+    return 0;
+}
+
+
+int UnLockMutex(CyaSSL_Mutex* m)
+{
+    return 0;
+}
+
+#else /* MULTI_THREAD */
+
+    #ifdef USE_WINDOWS_API
+
+        int InitMutex(CyaSSL_Mutex* m)
+        {
+            InitializeCriticalSection(m);
+            return 0;
+        }
+
+
+        int FreeMutex(CyaSSL_Mutex* m)
+        {
+            DeleteCriticalSection(m);
+            return 0;
+        }
+
+
+        int LockMutex(CyaSSL_Mutex* m)
+        {
+            EnterCriticalSection(m);
+            return 0;
+        }
+
+
+        int UnLockMutex(CyaSSL_Mutex* m)
+        {
+            LeaveCriticalSection(m);
+            return 0;
+        }
+
+    #elif defined(CYASSL_PTHREADS)
+
+        int InitMutex(CyaSSL_Mutex* m)
+        {
+            if (pthread_mutex_init(m, 0) == 0)
+                return 0;
+            else
+                return -1;
+        }
+
+
+        int FreeMutex(CyaSSL_Mutex* m)
+        {
+            if (pthread_mutex_destroy(m) == 0)
+                return 0;
+            else
+                return -1;
+        }
+
+
+        int LockMutex(CyaSSL_Mutex* m)
+        {
+            if (pthread_mutex_lock(m) == 0)
+                return 0;
+            else
+                return -1;
+        }
+
+
+        int UnLockMutex(CyaSSL_Mutex* m)
+        {
+            if (pthread_mutex_unlock(m) == 0)
+                return 0;
+            else
+                return -1;
+        }
+
+    #elif defined(THREADX)
+
+        int InitMutex(CyaSSL_Mutex* m)
+        {
+            if (tx_mutex_create(m, "CyaSSL Mutex", TX_NO_INHERIT) == 0)
+                return 0;
+            else
+                return -1;
+        }
+
+
+        int FreeMutex(CyaSSL_Mutex* m)
+        {
+            if (tx_mutex_delete(m) == 0)
+                return 0;
+            else
+                return -1;
+        }
+
+
+        int LockMutex(CyaSSL_Mutex* m)
+        {
+            if (tx_mutex_get(m, TX_WAIT_FOREVER) == 0)
+                return 0;
+            else
+                return -1;
+        }
+
+
+        int UnLockMutex(CyaSSL_Mutex* m)
+        {
+            if (tx_mutex_put(m) == 0)
+                return 0;
+            else
+                return -1;
+        }
+
+    #elif defined(MICRIUM)
+
+        int InitMutex(CyaSSL_Mutex* m)
+        {
+            #if (NET_SECURE_MGR_CFG_EN == DEF_ENABLED)
+                if (NetSecure_OS_MutexCreate(m) == 0)
+                    return 0;
+                else
+                    return -1;
+            #else
+                return 0;
+            #endif
+        }
+
+
+        int FreeMutex(CyaSSL_Mutex* m)
+        {
+            #if (NET_SECURE_MGR_CFG_EN == DEF_ENABLED)
+                if (NetSecure_OS_FreeMutex(m) == 0)
+                    return 0;
+                else
+                    return -1;
+            #else
+                return 0;
+            #endif
+        }
+
+
+        int LockMutex(CyaSSL_Mutex* m)
+        {
+            #if (NET_SECURE_MGR_CFG_EN == DEF_ENABLED)
+                if (NetSecure_OS_LockMutex(m) == 0)
+                    return 0;
+                else
+                    return -1;
+            #else
+                return 0;
+            #endif
+        }
+
+
+        int UnLockMutex(CyaSSL_Mutex* m)
+        {
+            #if (NET_SECURE_MGR_CFG_EN == DEF_ENABLED)
+                if (NetSecure_OS_UnLockMutex(m) == 0)
+                    return 0;
+                else
+                    return -1;
+            #else
+                return 0;
+            #endif
+
+        }
+
+    #endif /* USE_WINDOWS_API */
+#endif /* SINGLE_THREADED */
+
+
+#ifdef DEBUG_CYASSL
+
+    static int logging = 0;
+
+
+    int CyaSSL_Debugging_ON(void)
+    {
+        logging = 1;
+        return 0;
+    }
+
+
+    void CyaSSL_Debugging_OFF(void)
+    {
+        logging = 0;
+    }
+
+
+#ifdef THREADX
+    int dc_log_printf(char*, ...);
+#endif
+
+    void CYASSL_MSG(const char* msg)
+    {
+        if (logging) {
+#ifdef THREADX
+            dc_log_printf("%s\n", msg);
+#elif defined(MICRIUM)
+        #if (NET_SECURE_MGR_CFG_EN == DEF_ENABLED)
+            NetSecure_TraceOut((CPU_CHAR *)msg);
+        #endif
+#else
+            fprintf(stderr, "%s\n", msg);
+#endif
+        }
+    }
+
+
+    void CYASSL_ENTER(const char* msg)
+    {
+        if (logging) {
+            char buffer[80];
+            sprintf(buffer, "CyaSSL Entering %s", msg);
+            CYASSL_MSG(buffer);
+        }
+    }
+
+
+    void CYASSL_LEAVE(const char* msg, int ret)
+    {
+        if (logging) {
+            char buffer[80];
+            sprintf(buffer, "CyaSSL Leaving %s, return %d", msg, ret);
+            CYASSL_MSG(buffer);
+        }
+    }
+
+
+    void CYASSL_ERROR(int error)
+    {
+        if (logging) {
+            char buffer[80];
+            sprintf(buffer, "CyaSSL error occured, error = %d", error);
+            CYASSL_MSG(buffer);
+        }
+    }
+
+
+#else   /* DEBUG_CYASSL */
+
+    int CyaSSL_Debugging_ON(void)
+    {
+        return -1;    /* not compiled in */
+    }
+
+
+    void CyaSSL_Debugging_OFF(void)
+    {
+        /* already off */
+    }
+
+#endif  /* DEBUG_CYASSL */
diff --git a/src/cyassl_io.c b/src/cyassl_io.c
new file mode 100644
index 000000000..a5f5283f8
--- /dev/null
+++ b/src/cyassl_io.c
@@ -0,0 +1,190 @@
+/* cyassl_io.c
+ *
+ * Copyright (C) 2006-2011 Sawtooth Consulting Ltd.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * CyaSSL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+
+#ifdef _WIN32_WCE
+    /* On WinCE winsock2.h must be included before windows.h for socket stuff */
+    #include 
+#endif
+
+#include "cyassl_int.h"
+
+/* if user writes own I/O callbacks they can define CYASSL_USER_IO to remove
+   automatic setting of default I/O functions EmbedSend() and EmbedReceive()
+   but they'll still nedd SetCallback xxx() at end of file 
+*/
+#ifndef CYASSL_USER_IO
+
+#ifdef HAVE_LIBZ
+    #include "zlib.h"
+#endif
+
+#ifndef USE_WINDOWS_API 
+    #include 
+    #include 
+    #include 
+    #include 
+    #if !(defined(DEVKITPRO) || defined(THREADX))
+        #include 
+        #include 
+        #include 
+        #include 
+        #include 
+    #endif
+    #ifdef THREADX
+        #include 
+    #endif
+#endif /* USE_WINDOWS_API */
+
+#ifdef __sun
+    #include 
+#endif
+
+#ifdef USE_WINDOWS_API 
+    /* no epipe yet */
+    #ifndef WSAEPIPE
+        #define WSAEPIPE       -12345
+    #endif
+    #define SOCKET_EWOULDBLOCK WSAEWOULDBLOCK
+    #define SOCKET_EAGAIN      WSAEWOULDBLOCK
+    #define SOCKET_ECONNRESET  WSAECONNRESET
+    #define SOCKET_EINTR       WSAEINTR
+    #define SOCKET_EPIPE       WSAEPIPE
+#else
+    #define SOCKET_EWOULDBLOCK EWOULDBLOCK
+    #define SOCKET_EAGAIN      EAGAIN
+    #define SOCKET_ECONNRESET  ECONNRESET
+    #define SOCKET_EINTR       EINTR
+    #define SOCKET_EPIPE       EPIPE
+#endif /* USE_WINDOWS_API */
+
+
+#ifdef DEVKITPRO
+    /* from network.h */
+    int net_send(int, const void*, int, unsigned int);
+    int net_recv(int, void*, int, unsigned int);
+    #define SEND_FUNCTION net_send
+    #define RECV_FUNCTION net_recv
+#else
+    #define SEND_FUNCTION send
+    #define RECV_FUNCTION recv
+#endif
+
+
+static INLINE int LastError(void)
+{
+#ifdef USE_WINDOWS_API 
+    return WSAGetLastError();
+#else
+    return errno;
+#endif
+}
+
+/* The receive embedded callback
+ *  return : nb bytes read, or error
+ */
+int EmbedReceive(char *buf, int sz, void *ctx)
+{
+    int recvd;
+    int err;
+    int socket = *(int*)ctx;
+
+    recvd = RECV_FUNCTION(socket, (char *)buf, sz, 0);
+
+    if (recvd == -1) {
+        err = LastError();
+        if (err == SOCKET_EWOULDBLOCK ||
+            err == SOCKET_EAGAIN)
+            return IO_ERR_WANT_READ;
+
+        else if (err == SOCKET_ECONNRESET)
+            return IO_ERR_CONN_RST;
+
+        else if (err == SOCKET_EINTR)
+            return IO_ERR_ISR;
+
+        else
+            return IO_ERR_GENERAL;
+    }
+    else if (recvd == 0)
+        return IO_ERR_CONN_CLOSE;
+
+    return recvd;
+}
+
+/* The send embedded callback
+ *  return : nb bytes sent, or error
+ */
+int EmbedSend(char *buf, int sz, void *ctx)
+{
+    int socket = *(int*)ctx;
+    int sent;
+    int len = sz;
+
+    sent = SEND_FUNCTION(socket, &buf[sz - len], len, 0);
+
+    if (sent == -1) {
+        if (LastError() == SOCKET_EWOULDBLOCK || 
+            LastError() == SOCKET_EAGAIN)
+            return IO_ERR_WANT_WRITE;
+
+        else if (LastError() == SOCKET_ECONNRESET)
+            return IO_ERR_CONN_RST;
+
+        else if (LastError() == SOCKET_EINTR)
+            return IO_ERR_ISR;
+
+        else if (LastError() == SOCKET_EPIPE)
+            return IO_ERR_CONN_CLOSE;
+
+        else
+            return IO_ERR_GENERAL;
+    }
+ 
+    return sent;
+}
+
+
+#endif /* CYASSL_USER_IO */
+
+void CyaSSL_SetIORecv(SSL_CTX *ctx, CallbackIORecv CBIORecv)
+{
+    ctx->CBIORecv = CBIORecv;
+}
+
+
+void CyaSSL_SetIOSend(SSL_CTX *ctx, CallbackIOSend CBIOSend)
+{
+    ctx->CBIOSend = CBIOSend;
+}
+
+
+void CyaSSL_SetIOReadCtx(SSL* ssl, void *rctx)
+{
+	ssl->IOCB_ReadCtx = rctx;
+}
+
+
+void CyaSSL_SetIOWriteCtx(SSL* ssl, void *wctx)
+{
+	ssl->IOCB_WriteCtx = wctx;
+}
+
diff --git a/src/keys.c b/src/keys.c
new file mode 100644
index 000000000..2fc4c710a
--- /dev/null
+++ b/src/keys.c
@@ -0,0 +1,751 @@
+/* keys.c
+ *
+ * Copyright (C) 2006-2011 Sawtooth Consulting Ltd.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * CyaSSL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+
+
+#include "cyassl_int.h"
+#include "cyassl_error.h"
+#ifdef SHOW_SECRETS
+    #include 
+#endif
+
+
+#ifndef NO_TLS
+    int MakeTlsMasterSecret(SSL*);
+    void TLS_hmac(SSL* ssl, byte* digest, const byte* buffer, word32 sz,
+                  int content, int verify);
+#endif
+
+
+
+int SetCipherSpecs(SSL* ssl)
+{
+    /* ECC extensions */
+    if (ssl->options.cipherSuite0 == ECC_BYTE) {
+    
+    switch (ssl->options.cipherSuite) {
+
+#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
+    case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA :
+        ssl->specs.bulk_cipher_algorithm = aes;
+        ssl->specs.cipher_type           = block;
+        ssl->specs.mac_algorithm         = sha_mac;
+        ssl->specs.kea                   = ecc_diffie_hellman_kea;
+        ssl->specs.sig_algo              = rsa_sa_algo;
+        ssl->specs.hash_size             = SHA_DIGEST_SIZE;
+        ssl->specs.pad_size              = PAD_SHA;
+        ssl->specs.key_size              = AES_128_KEY_SIZE;
+        ssl->specs.block_size            = AES_BLOCK_SIZE;
+        ssl->specs.iv_size               = AES_IV_SIZE;
+
+        break;
+#endif
+
+#ifdef BUILD_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA
+    case TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA :
+        ssl->specs.bulk_cipher_algorithm = triple_des;
+        ssl->specs.cipher_type           = block;
+        ssl->specs.mac_algorithm         = sha_mac;
+        ssl->specs.kea                   = ecc_diffie_hellman_kea;
+        ssl->specs.sig_algo              = rsa_sa_algo;
+        ssl->specs.hash_size             = SHA_DIGEST_SIZE;
+        ssl->specs.pad_size              = PAD_SHA;
+        ssl->specs.key_size              = DES3_KEY_SIZE;
+        ssl->specs.block_size            = DES_BLOCK_SIZE;
+        ssl->specs.iv_size               = DES_IV_SIZE;
+
+        break;
+#endif
+
+#ifdef BUILD_TLS_ECDHE_RSA_WITH_RC4_128_SHA
+    case TLS_ECDHE_RSA_WITH_RC4_128_SHA :
+        ssl->specs.bulk_cipher_algorithm = rc4;
+        ssl->specs.cipher_type           = stream;
+        ssl->specs.mac_algorithm         = sha_mac;
+        ssl->specs.kea                   = ecc_diffie_hellman_kea;
+        ssl->specs.sig_algo              = rsa_sa_algo;
+        ssl->specs.hash_size             = SHA_DIGEST_SIZE;
+        ssl->specs.pad_size              = PAD_SHA;
+        ssl->specs.key_size              = RC4_KEY_SIZE;
+        ssl->specs.iv_size               = 0;
+        ssl->specs.block_size            = 0;
+
+        break;
+#endif
+
+#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA
+    case TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA :
+        ssl->specs.bulk_cipher_algorithm = triple_des;
+        ssl->specs.cipher_type           = block;
+        ssl->specs.mac_algorithm         = sha_mac;
+        ssl->specs.kea                   = ecc_diffie_hellman_kea;
+        ssl->specs.sig_algo              = ecc_dsa_sa_algo;
+        ssl->specs.hash_size             = SHA_DIGEST_SIZE;
+        ssl->specs.pad_size              = PAD_SHA;
+        ssl->specs.key_size              = DES3_KEY_SIZE;
+        ssl->specs.block_size            = DES_BLOCK_SIZE;
+        ssl->specs.iv_size               = DES_IV_SIZE;
+
+        break;
+#endif
+
+#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_RC4_128_SHA
+    case TLS_ECDHE_ECDSA_WITH_RC4_128_SHA :
+        ssl->specs.bulk_cipher_algorithm = rc4;
+        ssl->specs.cipher_type           = stream;
+        ssl->specs.mac_algorithm         = sha_mac;
+        ssl->specs.kea                   = ecc_diffie_hellman_kea;
+        ssl->specs.sig_algo              = ecc_dsa_sa_algo;
+        ssl->specs.hash_size             = SHA_DIGEST_SIZE;
+        ssl->specs.pad_size              = PAD_SHA;
+        ssl->specs.key_size              = RC4_KEY_SIZE;
+        ssl->specs.iv_size               = 0;
+        ssl->specs.block_size            = 0;
+
+        break;
+#endif
+
+#ifdef BUILD_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
+    case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA :
+        ssl->specs.bulk_cipher_algorithm = aes;
+        ssl->specs.cipher_type           = block;
+        ssl->specs.mac_algorithm         = sha_mac;
+        ssl->specs.kea                   = ecc_diffie_hellman_kea;
+        ssl->specs.sig_algo              = rsa_sa_algo;
+        ssl->specs.hash_size             = SHA_DIGEST_SIZE;
+        ssl->specs.pad_size              = PAD_SHA;
+        ssl->specs.key_size              = AES_256_KEY_SIZE;
+        ssl->specs.block_size            = AES_BLOCK_SIZE;
+        ssl->specs.iv_size               = AES_IV_SIZE;
+
+        break;
+#endif
+
+#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA
+    case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA :
+        ssl->specs.bulk_cipher_algorithm = aes;
+        ssl->specs.cipher_type           = block;
+        ssl->specs.mac_algorithm         = sha_mac;
+        ssl->specs.kea                   = ecc_diffie_hellman_kea;
+        ssl->specs.sig_algo              = ecc_dsa_sa_algo;
+        ssl->specs.hash_size             = SHA_DIGEST_SIZE;
+        ssl->specs.pad_size              = PAD_SHA;
+        ssl->specs.key_size              = AES_128_KEY_SIZE;
+        ssl->specs.block_size            = AES_BLOCK_SIZE;
+        ssl->specs.iv_size               = AES_IV_SIZE;
+
+        break;
+#endif
+
+#ifdef BUILD_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
+    case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA :
+        ssl->specs.bulk_cipher_algorithm = aes;
+        ssl->specs.cipher_type           = block;
+        ssl->specs.mac_algorithm         = sha_mac;
+        ssl->specs.kea                   = ecc_diffie_hellman_kea;
+        ssl->specs.sig_algo              = ecc_dsa_sa_algo;
+        ssl->specs.hash_size             = SHA_DIGEST_SIZE;
+        ssl->specs.pad_size              = PAD_SHA;
+        ssl->specs.key_size              = AES_256_KEY_SIZE;
+        ssl->specs.block_size            = AES_BLOCK_SIZE;
+        ssl->specs.iv_size               = AES_IV_SIZE;
+
+        break;
+#endif
+
+    default:
+        return UNSUPPORTED_SUITE;
+    }
+    } else {  /* Normal suites */
+    switch (ssl->options.cipherSuite) {
+
+#ifdef BUILD_SSL_RSA_WITH_RC4_128_SHA
+    case SSL_RSA_WITH_RC4_128_SHA :
+        ssl->specs.bulk_cipher_algorithm = rc4;
+        ssl->specs.cipher_type           = stream;
+        ssl->specs.mac_algorithm         = sha_mac;
+        ssl->specs.kea                   = rsa_kea;
+        ssl->specs.hash_size             = SHA_DIGEST_SIZE;
+        ssl->specs.pad_size              = PAD_SHA;
+        ssl->specs.key_size              = RC4_KEY_SIZE;
+        ssl->specs.iv_size               = 0;
+        ssl->specs.block_size            = 0;
+
+        break;
+#endif
+
+#ifdef BUILD_TLS_NTRU_RSA_WITH_RC4_128_SHA
+    case TLS_NTRU_RSA_WITH_RC4_128_SHA :
+        ssl->specs.bulk_cipher_algorithm = rc4;
+        ssl->specs.cipher_type           = stream;
+        ssl->specs.mac_algorithm         = sha_mac;
+        ssl->specs.kea                   = ntru_kea;
+        ssl->specs.hash_size             = SHA_DIGEST_SIZE;
+        ssl->specs.pad_size              = PAD_SHA;
+        ssl->specs.key_size              = RC4_KEY_SIZE;
+        ssl->specs.iv_size               = 0;
+        ssl->specs.block_size            = 0;
+
+        break;
+#endif
+
+#ifdef BUILD_SSL_RSA_WITH_RC4_128_MD5
+    case SSL_RSA_WITH_RC4_128_MD5 :
+        ssl->specs.bulk_cipher_algorithm = rc4;
+        ssl->specs.cipher_type           = stream;
+        ssl->specs.mac_algorithm         = md5_mac;
+        ssl->specs.kea                   = rsa_kea;
+        ssl->specs.hash_size             = MD5_DIGEST_SIZE;
+        ssl->specs.pad_size              = PAD_MD5;
+        ssl->specs.key_size              = RC4_KEY_SIZE;
+        ssl->specs.iv_size               = 0;
+        ssl->specs.block_size            = 0;
+
+        break;
+#endif
+
+#ifdef BUILD_SSL_RSA_WITH_3DES_EDE_CBC_SHA
+    case SSL_RSA_WITH_3DES_EDE_CBC_SHA :
+        ssl->specs.bulk_cipher_algorithm = triple_des;
+        ssl->specs.cipher_type           = block;
+        ssl->specs.mac_algorithm         = sha_mac;
+        ssl->specs.kea                   = rsa_kea;
+        ssl->specs.hash_size             = SHA_DIGEST_SIZE;
+        ssl->specs.pad_size              = PAD_SHA;
+        ssl->specs.key_size              = DES3_KEY_SIZE;
+        ssl->specs.block_size            = DES_BLOCK_SIZE;
+        ssl->specs.iv_size               = DES_IV_SIZE;
+
+        break;
+#endif
+
+#ifdef BUILD_TLS_NTRU_RSA_WITH_3DES_EDE_CBC_SHA
+    case TLS_NTRU_RSA_WITH_3DES_EDE_CBC_SHA :
+        ssl->specs.bulk_cipher_algorithm = triple_des;
+        ssl->specs.cipher_type           = block;
+        ssl->specs.mac_algorithm         = sha_mac;
+        ssl->specs.kea                   = ntru_kea;
+        ssl->specs.hash_size             = SHA_DIGEST_SIZE;
+        ssl->specs.pad_size              = PAD_SHA;
+        ssl->specs.key_size              = DES3_KEY_SIZE;
+        ssl->specs.block_size            = DES_BLOCK_SIZE;
+        ssl->specs.iv_size               = DES_IV_SIZE;
+
+        break;
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_AES_128_CBC_SHA
+    case TLS_RSA_WITH_AES_128_CBC_SHA :
+        ssl->specs.bulk_cipher_algorithm = aes;
+        ssl->specs.cipher_type           = block;
+        ssl->specs.mac_algorithm         = sha_mac;
+        ssl->specs.kea                   = rsa_kea;
+        ssl->specs.hash_size             = SHA_DIGEST_SIZE;
+        ssl->specs.pad_size              = PAD_SHA;
+        ssl->specs.key_size              = AES_128_KEY_SIZE;
+        ssl->specs.block_size            = AES_BLOCK_SIZE;
+        ssl->specs.iv_size               = AES_IV_SIZE;
+
+        break;
+#endif
+
+#ifdef BUILD_TLS_NTRU_RSA_WITH_AES_128_CBC_SHA
+    case TLS_NTRU_RSA_WITH_AES_128_CBC_SHA :
+        ssl->specs.bulk_cipher_algorithm = aes;
+        ssl->specs.cipher_type           = block;
+        ssl->specs.mac_algorithm         = sha_mac;
+        ssl->specs.kea                   = ntru_kea;
+        ssl->specs.hash_size             = SHA_DIGEST_SIZE;
+        ssl->specs.pad_size              = PAD_SHA;
+        ssl->specs.key_size              = AES_128_KEY_SIZE;
+        ssl->specs.block_size            = AES_BLOCK_SIZE;
+        ssl->specs.iv_size               = AES_IV_SIZE;
+
+        break;
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_AES_256_CBC_SHA
+    case TLS_RSA_WITH_AES_256_CBC_SHA :
+        ssl->specs.bulk_cipher_algorithm = aes;
+        ssl->specs.cipher_type           = block;
+        ssl->specs.mac_algorithm         = sha_mac;
+        ssl->specs.kea                   = rsa_kea;
+        ssl->specs.hash_size             = SHA_DIGEST_SIZE;
+        ssl->specs.pad_size              = PAD_SHA;
+        ssl->specs.key_size              = AES_256_KEY_SIZE;
+        ssl->specs.block_size            = AES_BLOCK_SIZE;
+        ssl->specs.iv_size               = AES_IV_SIZE;
+
+        break;
+#endif
+
+#ifdef BUILD_TLS_NTRU_RSA_WITH_AES_256_CBC_SHA
+    case TLS_NTRU_RSA_WITH_AES_256_CBC_SHA :
+        ssl->specs.bulk_cipher_algorithm = aes;
+        ssl->specs.cipher_type           = block;
+        ssl->specs.mac_algorithm         = sha_mac;
+        ssl->specs.kea                   = ntru_kea;
+        ssl->specs.hash_size             = SHA_DIGEST_SIZE;
+        ssl->specs.pad_size              = PAD_SHA;
+        ssl->specs.key_size              = AES_256_KEY_SIZE;
+        ssl->specs.block_size            = AES_BLOCK_SIZE;
+        ssl->specs.iv_size               = AES_IV_SIZE;
+
+        break;
+#endif
+
+#ifdef BUILD_TLS_PSK_WITH_AES_128_CBC_SHA
+    case TLS_PSK_WITH_AES_128_CBC_SHA :
+        ssl->specs.bulk_cipher_algorithm = aes;
+        ssl->specs.cipher_type           = block;
+        ssl->specs.mac_algorithm         = sha_mac;
+        ssl->specs.kea                   = psk_kea;
+        ssl->specs.hash_size             = SHA_DIGEST_SIZE;
+        ssl->specs.pad_size              = PAD_SHA;
+        ssl->specs.key_size              = AES_128_KEY_SIZE;
+        ssl->specs.block_size            = AES_BLOCK_SIZE;
+        ssl->specs.iv_size               = AES_IV_SIZE;
+
+        ssl->options.usingPSK_cipher     = 1;
+        break;
+#endif
+
+#ifdef BUILD_TLS_PSK_WITH_AES_256_CBC_SHA
+    case TLS_PSK_WITH_AES_256_CBC_SHA :
+        ssl->specs.bulk_cipher_algorithm = aes;
+        ssl->specs.cipher_type           = block;
+        ssl->specs.mac_algorithm         = sha_mac;
+        ssl->specs.kea                   = psk_kea;
+        ssl->specs.hash_size             = SHA_DIGEST_SIZE;
+        ssl->specs.pad_size              = PAD_SHA;
+        ssl->specs.key_size              = AES_256_KEY_SIZE;
+        ssl->specs.block_size            = AES_BLOCK_SIZE;
+        ssl->specs.iv_size               = AES_IV_SIZE;
+
+        ssl->options.usingPSK_cipher     = 1;
+        break;
+#endif
+
+#ifdef BUILD_TLS_DHE_RSA_WITH_AES_128_CBC_SHA
+    case TLS_DHE_RSA_WITH_AES_128_CBC_SHA :
+        ssl->specs.bulk_cipher_algorithm = aes;
+        ssl->specs.cipher_type           = block;
+        ssl->specs.mac_algorithm         = sha_mac;
+        ssl->specs.kea                   = diffie_hellman_kea;
+        ssl->specs.sig_algo              = rsa_sa_algo;
+        ssl->specs.hash_size             = SHA_DIGEST_SIZE;
+        ssl->specs.pad_size              = PAD_SHA;
+        ssl->specs.key_size              = AES_128_KEY_SIZE;
+        ssl->specs.block_size            = AES_BLOCK_SIZE;
+        ssl->specs.iv_size               = AES_IV_SIZE;
+
+        break;
+#endif
+
+#ifdef BUILD_TLS_DHE_RSA_WITH_AES_256_CBC_SHA
+    case TLS_DHE_RSA_WITH_AES_256_CBC_SHA :
+        ssl->specs.bulk_cipher_algorithm = aes;
+        ssl->specs.cipher_type           = block;
+        ssl->specs.mac_algorithm         = sha_mac;
+        ssl->specs.kea                   = diffie_hellman_kea;
+        ssl->specs.sig_algo              = rsa_sa_algo;
+        ssl->specs.hash_size             = SHA_DIGEST_SIZE;
+        ssl->specs.pad_size              = PAD_SHA;
+        ssl->specs.key_size              = AES_256_KEY_SIZE;
+        ssl->specs.block_size            = AES_BLOCK_SIZE;
+        ssl->specs.iv_size               = AES_IV_SIZE;
+
+        break;
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_HC_128_CBC_MD5
+    case TLS_RSA_WITH_HC_128_CBC_MD5 :
+        ssl->specs.bulk_cipher_algorithm = hc128;
+        ssl->specs.cipher_type           = stream;
+        ssl->specs.mac_algorithm         = md5_mac;
+        ssl->specs.kea                   = rsa_kea;
+        ssl->specs.hash_size             = MD5_DIGEST_SIZE;
+        ssl->specs.pad_size              = PAD_MD5;
+        ssl->specs.key_size              = HC_128_KEY_SIZE;
+        ssl->specs.block_size            = 0;
+        ssl->specs.iv_size               = HC_128_IV_SIZE;
+
+        break;
+#endif
+            
+#ifdef BUILD_TLS_RSA_WITH_HC_128_CBC_SHA
+        case TLS_RSA_WITH_HC_128_CBC_SHA :
+            ssl->specs.bulk_cipher_algorithm = hc128;
+            ssl->specs.cipher_type           = stream;
+            ssl->specs.mac_algorithm         = sha_mac;
+            ssl->specs.kea                   = rsa_kea;
+            ssl->specs.hash_size             = SHA_DIGEST_SIZE;
+            ssl->specs.pad_size              = PAD_SHA;
+            ssl->specs.key_size              = HC_128_KEY_SIZE;
+            ssl->specs.block_size            = 0;
+            ssl->specs.iv_size               = HC_128_IV_SIZE;
+            
+            break;
+#endif
+
+#ifdef BUILD_TLS_RSA_WITH_RABBIT_CBC_SHA
+    case TLS_RSA_WITH_RABBIT_CBC_SHA :
+        ssl->specs.bulk_cipher_algorithm = rabbit;
+        ssl->specs.cipher_type           = stream;
+        ssl->specs.mac_algorithm         = sha_mac;
+        ssl->specs.kea                   = rsa_kea;
+        ssl->specs.hash_size             = SHA_DIGEST_SIZE;
+        ssl->specs.pad_size              = PAD_SHA;
+        ssl->specs.key_size              = RABBIT_KEY_SIZE;
+        ssl->specs.block_size            = 0;
+        ssl->specs.iv_size               = RABBIT_IV_SIZE;
+
+        break;
+#endif
+
+    default:
+        return UNSUPPORTED_SUITE;
+    }
+    }  /* ECC / Normal suites else */
+
+    /* set TLS if it hasn't been turned off */
+    if (ssl->version.major == 3 && ssl->version.minor >= 1) {
+#ifndef NO_TLS
+        ssl->options.tls = 1;
+        ssl->hmac = TLS_hmac;
+        if (ssl->version.minor == 2)
+            ssl->options.tls1_1 = 1;
+#endif
+    }
+
+#ifdef CYASSL_DTLS
+    if (ssl->options.dtls)
+        ssl->hmac = TLS_hmac;
+#endif
+
+    return 0;
+}
+
+
+enum KeyStuff {
+    MASTER_ROUNDS = 3,
+    PREFIX        = 3,     /* up to three letters for master prefix */
+    KEY_PREFIX    = 7      /* up to 7 prefix letters for key rounds */
+
+
+};
+
+
+/* true or false, zero for error */
+static int SetPrefix(byte* sha_input, int index)
+{
+    switch (index) {
+    case 0:
+        XMEMCPY(sha_input, "A", 1);
+        break;
+    case 1:
+        XMEMCPY(sha_input, "BB", 2);
+        break;
+    case 2:
+        XMEMCPY(sha_input, "CCC", 3);
+        break;
+    case 3:
+        XMEMCPY(sha_input, "DDDD", 4);
+        break;
+    case 4:
+        XMEMCPY(sha_input, "EEEEE", 5);
+        break;
+    case 5:
+        XMEMCPY(sha_input, "FFFFFF", 6);
+        break;
+    case 6:
+        XMEMCPY(sha_input, "GGGGGGG", 7);
+        break;
+    default:
+        return 0; 
+    }
+    return 1;
+}
+
+
+static int SetKeys(Ciphers* encrypt, Ciphers* decrypt, Keys* keys,
+                   CipherSpecs* specs, byte side)
+{
+#ifdef BUILD_ARC4
+    word32 sz = specs->key_size;
+    if (specs->bulk_cipher_algorithm == rc4) {
+        if (side == CLIENT_END) {
+            Arc4SetKey(&encrypt->arc4, keys->client_write_key, sz);
+            Arc4SetKey(&decrypt->arc4, keys->server_write_key, sz);
+        }
+        else {
+            Arc4SetKey(&encrypt->arc4, keys->server_write_key, sz);
+            Arc4SetKey(&decrypt->arc4, keys->client_write_key, sz);
+        }
+    }
+#endif
+    
+#ifdef BUILD_HC128
+    if (specs->bulk_cipher_algorithm == hc128) {
+        if (side == CLIENT_END) {
+            Hc128_SetKey(&encrypt->hc128, keys->client_write_key,
+                                          keys->client_write_IV);
+            Hc128_SetKey(&decrypt->hc128, keys->server_write_key,
+                                          keys->server_write_IV);
+        }
+        else {
+            Hc128_SetKey(&encrypt->hc128, keys->server_write_key,
+                                         keys->server_write_IV);
+            Hc128_SetKey(&decrypt->hc128, keys->client_write_key,
+                                         keys->client_write_IV);
+        }
+    }
+#endif
+    
+#ifdef BUILD_RABBIT
+    if (specs->bulk_cipher_algorithm == rabbit) {
+        if (side == CLIENT_END) {
+            RabbitSetKey(&encrypt->rabbit, keys->client_write_key,
+                                           keys->client_write_IV);
+            RabbitSetKey(&decrypt->rabbit, keys->server_write_key,
+                                           keys->server_write_IV);
+        }
+        else {
+            RabbitSetKey(&encrypt->rabbit, keys->server_write_key,
+                                           keys->server_write_IV);
+            RabbitSetKey(&decrypt->rabbit, keys->client_write_key,
+                                           keys->client_write_IV);
+        }
+    }
+#endif
+    
+#ifdef BUILD_DES3
+    if (specs->bulk_cipher_algorithm == triple_des) {
+        if (side == CLIENT_END) {
+            Des3_SetKey(&encrypt->des3, keys->client_write_key,
+                        keys->client_write_IV, DES_ENCRYPTION);
+            Des3_SetKey(&decrypt->des3, keys->server_write_key,
+                        keys->server_write_IV, DES_DECRYPTION);
+        }
+        else {
+            Des3_SetKey(&encrypt->des3, keys->server_write_key,
+                        keys->server_write_IV, DES_ENCRYPTION);
+            Des3_SetKey(&decrypt->des3, keys->client_write_key,
+                keys->client_write_IV, DES_DECRYPTION);
+        }
+    }
+#endif
+
+#ifdef BUILD_AES
+    if (specs->bulk_cipher_algorithm == aes) {
+        if (side == CLIENT_END) {
+            AesSetKey(&encrypt->aes, keys->client_write_key,
+                      specs->key_size, keys->client_write_IV,
+                      AES_ENCRYPTION);
+            AesSetKey(&decrypt->aes, keys->server_write_key,
+                      specs->key_size, keys->server_write_IV,
+                      AES_DECRYPTION);
+        }
+        else {
+            AesSetKey(&encrypt->aes, keys->server_write_key,
+                      specs->key_size, keys->server_write_IV,
+                      AES_ENCRYPTION);
+            AesSetKey(&decrypt->aes, keys->client_write_key,
+                      specs->key_size, keys->client_write_IV,
+                      AES_DECRYPTION);
+        }
+    }
+#endif
+
+    keys->sequence_number      = 0;
+    keys->peer_sequence_number = 0;
+    keys->encryptionOn         = 0;
+
+    return 0;
+}
+
+
+/* TLS can call too */
+int StoreKeys(SSL* ssl, const byte* keyData)
+{
+    int sz = ssl->specs.hash_size, i;
+
+    XMEMCPY(ssl->keys.client_write_MAC_secret, keyData, sz);
+    i = sz;
+    XMEMCPY(ssl->keys.server_write_MAC_secret,&keyData[i], sz);
+    i += sz;
+
+    sz = ssl->specs.key_size;
+    XMEMCPY(ssl->keys.client_write_key, &keyData[i], sz);
+    i += sz;
+    XMEMCPY(ssl->keys.server_write_key, &keyData[i], sz);
+    i += sz;
+
+    sz = ssl->specs.iv_size;
+    XMEMCPY(ssl->keys.client_write_IV, &keyData[i], sz);
+    i += sz;
+    XMEMCPY(ssl->keys.server_write_IV, &keyData[i], sz);
+
+    return SetKeys(&ssl->encrypt, &ssl->decrypt, &ssl->keys, &ssl->specs,
+                   ssl->options.side);
+}
+
+
+int DeriveKeys(SSL* ssl)
+{
+    int length = 2 * ssl->specs.hash_size + 
+                 2 * ssl->specs.key_size  +
+                 2 * ssl->specs.iv_size;
+    int rounds = (length + MD5_DIGEST_SIZE - 1 ) / MD5_DIGEST_SIZE, i;
+
+    byte shaOutput[SHA_DIGEST_SIZE];
+    byte md5Input[SECRET_LEN + SHA_DIGEST_SIZE];
+    byte shaInput[KEY_PREFIX + SECRET_LEN + 2 * RAN_LEN];
+  
+    Md5 md5;
+    Sha sha;
+
+    byte keyData[KEY_PREFIX * MD5_DIGEST_SIZE];  /* max size */
+
+    InitMd5(&md5);
+    InitSha(&sha);
+
+    XMEMCPY(md5Input, ssl->arrays.masterSecret, SECRET_LEN);
+
+    for (i = 0; i < rounds; ++i) {
+        int j   = i + 1;
+        int idx = j;
+
+        if (!SetPrefix(shaInput, i)) {
+            return PREFIX_ERROR;
+        }
+
+        XMEMCPY(shaInput + idx, ssl->arrays.masterSecret, SECRET_LEN);
+        idx += SECRET_LEN;
+        XMEMCPY(shaInput + idx, ssl->arrays.serverRandom, RAN_LEN);
+        idx += RAN_LEN;
+        XMEMCPY(shaInput + idx, ssl->arrays.clientRandom, RAN_LEN);
+        idx += RAN_LEN;
+
+        ShaUpdate(&sha, shaInput, sizeof(shaInput) - KEY_PREFIX + j);
+        ShaFinal(&sha, shaOutput);
+
+        XMEMCPY(&md5Input[SECRET_LEN], shaOutput, SHA_DIGEST_SIZE);
+        Md5Update(&md5, md5Input, sizeof(md5Input));
+        Md5Final(&md5, keyData + i * MD5_DIGEST_SIZE);
+    }
+
+    return StoreKeys(ssl, keyData);
+}
+
+
+void CleanPreMaster(SSL* ssl)
+{
+    int i, sz = ssl->arrays.preMasterSz;
+
+    for (i = 0; i < sz; i++)
+        ssl->arrays.preMasterSecret[i] = 0;
+
+    RNG_GenerateBlock(&ssl->rng, ssl->arrays.preMasterSecret, sz);
+
+    for (i = 0; i < sz; i++)
+        ssl->arrays.preMasterSecret[i] = 0;
+
+}
+
+
+/* Create and store the master secret see page 32, 6.1 */
+int MakeMasterSecret(SSL* ssl)
+{
+    byte   shaOutput[SHA_DIGEST_SIZE];
+    byte   md5Input[ENCRYPT_LEN + SHA_DIGEST_SIZE];
+    byte   shaInput[PREFIX + ENCRYPT_LEN + 2 * RAN_LEN];
+    int    i;
+    word32 idx;
+    word32 pmsSz = ssl->arrays.preMasterSz;
+
+    Md5 md5;
+    Sha sha;
+
+#ifdef SHOW_SECRETS
+    {
+        int j;
+        printf("pre master secret: ");
+        for (j = 0; j < pmsSz; j++)
+            printf("%02x", ssl->arrays.preMasterSecret[j]);
+        printf("\n");
+    }
+#endif
+
+#ifndef NO_TLS
+    if (ssl->options.tls) return MakeTlsMasterSecret(ssl);
+#endif
+
+    InitMd5(&md5);
+    InitSha(&sha);
+
+    XMEMCPY(md5Input, ssl->arrays.preMasterSecret, pmsSz);
+
+    for (i = 0; i < MASTER_ROUNDS; ++i) {
+        byte prefix[PREFIX];
+        if (!SetPrefix(prefix, i)) {
+            return PREFIX_ERROR;
+        }
+
+        idx = 0;
+        XMEMCPY(shaInput, prefix, i + 1);
+        idx += i + 1;
+
+        XMEMCPY(shaInput + idx, ssl->arrays.preMasterSecret, pmsSz);
+        idx += pmsSz;
+        XMEMCPY(shaInput + idx, ssl->arrays.clientRandom, RAN_LEN);
+        idx += RAN_LEN;
+        XMEMCPY(shaInput + idx, ssl->arrays.serverRandom, RAN_LEN);
+        idx += RAN_LEN;
+        ShaUpdate(&sha, shaInput, idx);
+        ShaFinal(&sha, shaOutput);
+
+        idx = pmsSz;  /* preSz */
+        XMEMCPY(md5Input + idx, shaOutput, SHA_DIGEST_SIZE);
+        idx += SHA_DIGEST_SIZE;
+        Md5Update(&md5, md5Input, idx);
+        Md5Final(&md5, &ssl->arrays.masterSecret[i * MD5_DIGEST_SIZE]);
+    }
+
+#ifdef SHOW_SECRETS
+    {
+        int i;
+        printf("master secret: ");
+        for (i = 0; i < SECRET_LEN; i++)
+            printf("%02x", ssl->arrays.masterSecret[i]);
+        printf("\n");
+    }
+#endif
+
+    DeriveKeys(ssl);
+    CleanPreMaster(ssl);
+
+    return 0;
+}
+
+
+
+
diff --git a/src/sniffer.c b/src/sniffer.c
new file mode 100644
index 000000000..95877f88f
--- /dev/null
+++ b/src/sniffer.c
@@ -0,0 +1,2187 @@
+/* sniffer.c
+ *
+ * Copyright (C) 2006-2011 Sawtooth Consulting Ltd.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * CyaSSL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#ifdef CYASSL_SNIFFER
+
+#include "ssl.h"
+#include "cyassl_int.h"
+#include "cyassl_error.h"
+#include "sniffer.h"
+#include "sniffer_error.h"
+#include 
+
+#ifndef _WIN32
+	#include 
+#endif
+
+#include 
+
+
+#ifdef _WIN32
+    #define SNPRINTF _snprintf
+#else
+    #define SNPRINTF snprintf
+#endif
+
+
+/* Misc constants */
+enum {
+    MAX_SERVER_ADDRESS = 128, /* maximum server address length */
+    MAX_ERROR_LEN      = 80,  /* maximum error length */
+    ETHER_IF_ADDR_LEN  = 6,   /* ethernet interface address length */
+    LOCAL_IF_ADDR_LEN  = 4,   /* localhost interface address length, !windows */
+    TCP_PROTO          = 6,   /* TCP_PROTOCOL */
+    IP_HDR_SZ          = 20,  /* IP header legnth, min */
+    TCP_HDR_SZ         = 20,  /* TCP header legnth, min */
+    IPV4               = 4,   /* IP version 4 */
+    TCP_PROTOCOL       = 6,   /* TCP Protocol id */
+    TRACE_MSG_SZ       = 80,  /* Trace Message buffer size */
+    HASH_SIZE          = 499, /* Session Hash Table Rows */
+    PSEUDO_HDR_SZ      = 12,  /* TCP Pseudo Header size in bytes */
+    FATAL_ERROR_STATE  =  1,  /* SnifferSession fatal error state */
+    SNIFFER_TIMEOUT    = 900, /* Cache unclosed Sessions for 15 minutes */
+};
+
+
+#ifdef _WIN32
+
+static HMODULE dllModule;  /* for error string resources */
+
+BOOL APIENTRY DllMain( HMODULE hModule,
+                       DWORD  ul_reason_for_call,
+                       LPVOID lpReserved
+                     )
+{
+	static int didInit = 0;
+
+    switch (ul_reason_for_call)
+    {
+    case DLL_PROCESS_ATTACH:
+		if (didInit == 0) {
+            dllModule = hModule;
+			ssl_InitSniffer();
+			didInit = 1;
+		}
+        break;
+    case DLL_THREAD_ATTACH:
+        break;
+    case DLL_THREAD_DETACH:
+        break;
+    case DLL_PROCESS_DETACH:
+		if (didInit) {
+			ssl_FreeSniffer();
+			didInit = 0;
+		}
+        break;
+    }
+    return TRUE;
+}
+
+#endif /* _WIN32 */
+
+
+static int TraceOn = 0;         /* Trace is off by default */
+static FILE* TraceFile = 0;
+
+
+/* windows uses .rc talbe for this */
+#ifndef _WIN32
+
+static const char* const msgTable[] =
+{
+    /* 1 */
+    "Out of Memory",
+    "New SSL Sniffer Server Registered",
+    "Checking IP Header",
+    "SSL Sniffer Server Not Registered",
+    "Checking TCP Header",
+
+    /* 6 */
+    "SSL Sniffer Server Port Not Registered",
+    "RSA Private Decrypt Error",
+    "RSA Private Decode Error",
+    "Set Cipher Spec Error",
+    "Server Hello Input Malformed",
+
+    /* 11 */
+    "Couldn't Resume Session Error",
+    "Server Did Resumption",
+    "Client Hello Input Malformed",
+    "Client Trying to Resume",
+    "Handshake Input Malformed",
+
+    /* 16 */
+    "Got Hello Verify msg",
+    "Got Server Hello msg",
+    "Got Cert Request msg",
+    "Got Server Key Exchange msg",
+    "Got Cert msg",
+
+    /* 21 */
+    "Got Server Hello Done msg",
+    "Got Finished msg",
+    "Got Client Hello msg",
+    "Got Client Key Exchange msg",
+    "Got Cert Verify msg",
+
+    /* 26 */
+    "Got Unknown Handshake msg",
+    "New SSL Sniffer Session created",
+    "Couldn't create new SSL",
+    "Got a Packet to decode",
+    "No data present",
+
+    /* 31 */
+    "Session Not Found",
+    "Got an Old Client Hello msg",
+    "Old Client Hello Input Malformed",
+    "Old Client Hello OK",
+    "Bad Old Client Hello",
+
+    /* 36 */
+    "Bad Record Header",
+    "Record Header Input Malformed",
+    "Got a HandShake msg",
+    "Bad HandShake msg",
+    "Got a Change Cipher Spec msg",
+
+    /* 41 */
+    "Got Application Data msg",
+    "Bad Application Data",
+    "Got an Alert msg",
+    "Another msg to Process",
+    "Removing Session From Table",
+    
+    /* 46 */
+    "Bad Key File",
+    "Wrong IP Version",
+    "Wrong Protocol type",
+    "Packet Short for header processing",
+    "Got Unknown Record Type",
+    
+    /* 51 */
+    "Can't Open Trace File",
+    "Session in Fatal Error State",
+    "Partial SSL record received",
+    "Buffer Error, malformed input",
+    "Added to Partial Input",
+    
+    /* 56 */
+    "Received a Duplicate Packet",
+    "Received an Out of Order Packet",
+    "Received an Overlap Duplicate Packet",
+    "Received an Overlap Reassembly Begin Duplicate Packet",
+    "Received an Overlap Reassembly End Duplicate Packet",
+
+    /* 61 */
+    "Missed the Client Hello Entirely",
+};
+
+
+/* *nix version uses table above */
+static void GetError(int idx, char* buffer)
+{
+    XSTRNCPY(buffer, msgTable[idx - 1], MAX_ERROR_LEN);
+}
+
+
+#else /* _WIN32 */
+
+
+/* Windows version uses .rc table */
+static void GetError(int idx, char* buffer)
+{
+    if (!LoadStringA(dllModule, idx, buffer, MAX_ERROR_LEN))
+        buffer[0] = 0;
+}
+
+
+#endif /* _WIN32 */
+
+
+/* Packet Buffer for reassembly list and ready list */
+typedef struct PacketBuffer {
+    word32  begin;      /* relative sequence begin */
+    word32  end;        /* relative sequence end   */
+    byte*   data;       /* actual data             */
+    struct PacketBuffer* next; /* next on reassembly list or ready list */
+} PacketBuffer;
+
+
+/* Sniffer Server holds info for each server/port monitored */
+typedef struct SnifferServer {
+    SSL_CTX*       ctx;                          /* SSL context */
+    char           address[MAX_SERVER_ADDRESS];  /* passed in server address */
+    word32         server;                       /* netowrk order address */
+    int            port;                         /* server port */
+    struct SnifferServer* next;                  /* for list */
+} SnifferServer;
+
+
+/* Session Flags */
+typedef struct Flags {
+    byte           side;            /* which end is current packet headed */
+    byte           serverCipherOn;  /* indicates whether cipher is active */
+    byte           clientCipherOn;  /* indicates whether cipher is active */
+    byte           resuming;        /* did this session come from resumption */
+    byte           cached;          /* have we cached this session yet */
+    byte           clientHello;     /* processed client hello yet, for SSLv2 */
+    byte           finCount;        /* get both FINs before removing */
+    byte           fatalError;      /* fatal error state */    
+} Flags;
+
+
+/* Out of Order FIN caputre */
+typedef struct FinCaputre {
+    word32 cliFinSeq;               /* client relative sequence FIN  0 is no */
+    word32 srvFinSeq;               /* server relative sequence FIN, 0 is no */
+    byte   cliCounted;              /* did we count yet, detects duplicates */
+    byte   srvCounted;              /* did we count yet, detects duplicates */
+} FinCaputre;
+
+
+/* Sniffer Session holds info for each client/server SSL/TLS session */
+typedef struct SnifferSession {
+    SnifferServer* context;         /* server context */
+    SSL*           sslServer;       /* SSL server side decode */
+    SSL*           sslClient;       /* SSL client side decode */
+    word32         server;          /* server address in network byte order */
+    word32         client;          /* client address in network byte order */
+    word16         srvPort;         /* server port */
+    word16         cliPort;         /* client port */
+    word32         cliSeqStart;     /* client start sequence */
+    word32         srvSeqStart;     /* server start sequence */
+    word32         cliExpected;     /* client expected sequence (relative) */
+    word32         srvExpected;     /* server expected sequence (relative) */
+    FinCaputre     finCaputre;      /* retain out of order FIN s */
+    Flags          flags;           /* session flags */
+    time_t         bornOn;          /* born on ticks */
+    PacketBuffer*  cliReassemblyList; /* client out of order packets */
+    PacketBuffer*  srvReassemblyList; /* server out of order packets */
+    struct SnifferSession* next;    /* for hash table list */
+} SnifferSession;
+
+
+/* Sniffer Server List and mutex */
+static SnifferServer* ServerList = 0;
+static CyaSSL_Mutex ServerListMutex;
+
+
+/* Session Hash Table, mutex, and count */
+static SnifferSession* SessionTable[HASH_SIZE];
+static CyaSSL_Mutex SessionMutex;
+static int SessionCount = 0;
+
+
+/* Initialize overall Sniffer */
+void ssl_InitSniffer(void)
+{
+    InitCyaSSL();
+    InitMutex(&ServerListMutex);
+    InitMutex(&SessionMutex);
+}
+
+
+/* Free Sniffer Server's resources/self */
+static void FreeSnifferServer(SnifferServer* server)
+{
+    if (server)
+        SSL_CTX_free(server->ctx);
+    free(server);
+}
+
+
+/* free PacketBuffer's resources/self */
+static void FreePacketBuffer(PacketBuffer* remove)
+{
+    if (remove) {
+        free(remove->data);
+        free(remove);
+    }
+}
+
+
+/* remove PacketBuffer List */
+static void FreePacketList(PacketBuffer* buffer)
+{
+    if (buffer) {
+        PacketBuffer* remove;
+        PacketBuffer* packet = buffer;
+        
+        while (packet) {
+            remove = packet;
+            packet = packet->next;
+            FreePacketBuffer(remove);
+        }
+    }
+}
+
+
+/* Free Sniffer Session's resources/self */
+static void FreeSnifferSession(SnifferSession* session)
+{
+    if (session) {
+        SSL_free(session->sslClient);
+        SSL_free(session->sslServer);
+        
+        FreePacketList(session->cliReassemblyList);
+        FreePacketList(session->srvReassemblyList);
+    }
+    free(session);
+}
+
+
+/* Free overall Sniffer */
+void ssl_FreeSniffer(void)
+{
+    SnifferServer*  server;
+    SnifferServer*  removeServer;
+    SnifferSession* session;
+    SnifferSession* removeSession;
+    int i;
+
+    LockMutex(&ServerListMutex);
+    LockMutex(&SessionMutex);
+    
+    server = ServerList;
+    while (server) {
+        removeServer = server;
+        server = server->next;
+        FreeSnifferServer(removeServer);
+    }
+
+    for (i = 0; i < HASH_SIZE; i++) {
+        session = SessionTable[i];
+        while (session) {
+            removeSession = session;
+            session = session->next;
+            FreeSnifferSession(removeSession);
+        }
+    }
+
+    UnLockMutex(&SessionMutex);
+    UnLockMutex(&ServerListMutex);
+
+    FreeMutex(&SessionMutex);
+    FreeMutex(&ServerListMutex);
+    FreeCyaSSL();
+}
+
+
+/* Initialize a SnifferServer */
+static void InitSnifferServer(SnifferServer* sniffer)
+{
+    sniffer->ctx = 0;
+    XMEMSET(sniffer->address, 0, MAX_SERVER_ADDRESS);
+    sniffer->server   = 0;
+    sniffer->port     = 0;
+    sniffer->next     = 0;
+}
+
+
+/* Initialize session flags */
+static void InitFlags(Flags* flags)
+{
+    flags->side           = 0;
+    flags->serverCipherOn = 0;
+    flags->clientCipherOn = 0;
+    flags->resuming       = 0;
+    flags->cached         = 0;
+    flags->clientHello    = 0;
+    flags->finCount       = 0;
+    flags->fatalError     = 0;
+}
+
+
+/* Initialize FIN Capture */
+static void InitFinCapture(FinCaputre* cap)
+{
+    cap->cliFinSeq  = 0;
+    cap->srvFinSeq  = 0;
+    cap->cliCounted = 0;
+    cap->srvCounted = 0;
+}
+
+
+/* Initialize a Sniffer Session */
+static void InitSession(SnifferSession* session)
+{
+    session->context        = 0;
+    session->sslServer      = 0;
+    session->sslClient      = 0;
+    session->server         = 0;
+    session->client         = 0;
+    session->srvPort        = 0;
+    session->cliPort        = 0;
+    session->cliSeqStart    = 0;
+    session->srvSeqStart    = 0;
+    session->cliExpected    = 0;
+    session->srvExpected    = 0;
+    session->bornOn         = 0;
+    session->cliReassemblyList = 0;
+    session->srvReassemblyList = 0;
+    session->next           = 0;
+    
+    InitFlags(&session->flags);
+    InitFinCapture(&session->finCaputre);
+}
+
+
+/* IP Info from IP Header */
+typedef struct IpInfo {
+    int    length;        /* length of this header */
+    int    total;         /* total length of fragment */
+    word32 src;           /* network order source address */
+    word32 dst;           /* network order destination address */
+} IpInfo;
+
+
+/* TCP Info from TCP Header */
+typedef struct TcpInfo {
+    int    srcPort;       /* source port */
+    int    dstPort;       /* source port */
+    int    length;        /* length of this header */
+    word32 sequence;      /* sequence number */
+    byte   fin;           /* FIN set */
+    byte   rst;           /* RST set */
+    byte   syn;           /* SYN set */
+    byte   ack;           /* ACK set */
+} TcpInfo;
+
+
+/* Tcp Pseudo Header for Checksum calculation */
+typedef struct TcpPseudoHdr {
+    word32  src;        /* source address */
+    word32  dst;        /* destination address */
+    byte    rsv;        /* reserved, always 0 */
+    byte    protocol;   /* IP protocol */
+    word16  legnth;     /* tcp header length + data length (doesn't include */
+                        /* pseudo header length) network order */
+} TcpPseudoHdr;
+
+
+/* Password Setting Callback */
+static int SetPassword(char* passwd, int sz, int rw, void* userdata)
+{
+    XSTRNCPY(passwd, userdata, sz);
+    return XSTRLEN(userdata);
+}
+
+
+/* Ethernet Header */
+typedef struct EthernetHdr {
+    byte   dst[ETHER_IF_ADDR_LEN];    /* destination host address */ 
+    byte   src[ETHER_IF_ADDR_LEN];    /* source  host address */ 
+    word16 type;                      /* IP, ARP, etc */ 
+} EthernetHdr;
+
+
+/* IP Header */
+typedef struct IpHdr {
+    byte    ver_hl;              /* version/header length */
+    byte    tos;                 /* type of service */
+    word16  length;              /* total length */
+    word16  id;                  /* identification */
+    word16  offset;              /* fragment offset field */
+    byte    ttl;                 /* time to live */
+    byte    protocol;            /* protocol */
+    word16  sum;                 /* checksum */
+    word32  src;                 /* source address */
+    word32  dst;                 /* destination address */
+} IpHdr;
+
+
+#define IP_HL(ip)      ( (((ip)->ver_hl) & 0x0f) * 4)
+#define IP_V(ip)       ( ((ip)->ver_hl) >> 4)
+
+/* TCP Header */
+typedef struct TcpHdr {
+    word16  srcPort;            /* source port */
+    word16  dstPort;            /* destination port */
+    word32  sequence;           /* sequence number */ 
+    word32  ack;                /* acknoledgment number */ 
+    byte    offset;             /* data offset, reserved */
+    byte    flags;              /* option flags */
+    word16  window;             /* window */
+    word16  sum;                /* checksum */
+    word16  urgent;             /* urgent pointer */
+} TcpHdr;
+
+#define TCP_LEN(tcp)  ( (((tcp)->offset & 0xf0) >> 4) * 4)
+#define TCP_FIN 0x01
+#define TCP_SYN 0x02
+#define TCP_RST 0x04
+#define TCP_ACK 0x10
+
+
+
+
+
+/* Use platform specific GetError to write to tracfile if tracing */ 
+static void Trace(int idx) 
+{
+    if (TraceOn) {
+        char buffer[MAX_ERROR_LEN];
+        GetError(idx, buffer);
+        fprintf(TraceFile, "\t%s\n", buffer);
+#ifdef DEBUG_SNIFFER
+        fprintf(stderr,    "\t%s\n", buffer);
+#endif
+    }
+}
+
+
+/* Show TimeStamp for beginning of packet Trace */
+static void TraceHeader(void)
+{
+    if (TraceOn) {
+        time_t ticks = time(NULL);
+        fprintf(TraceFile, "\n%s", ctime(&ticks));
+    }
+}
+
+
+/* Show Set Server info for Trace */
+static void TraceSetServer(const char* server, int port, const char* keyFile)
+{
+    if (TraceOn) {
+        fprintf(TraceFile, "\tTrying to install a new Sniffer Server with\n");
+        fprintf(TraceFile, "\tserver: %s, port: %d, keyFile: %s\n", server,
+                port, keyFile);
+    }
+}
+
+
+/* Trace got packet number */
+static void TracePacket(void)
+{
+    if (TraceOn) {
+        static word32 packetNumber = 0;
+        fprintf(TraceFile, "\tGot a Packet to decode, packet %u\n",
+                ++packetNumber);
+    }
+}
+
+
+/* Convert network byte order address into human readable */
+static char* IpToS(word32 addr, char* str)
+{
+    byte* p = (byte*)&addr;
+    
+    SNPRINTF(str, TRACE_MSG_SZ, "%d.%d.%d.%d", p[0], p[1], p[2], p[3]);
+    
+    return str;
+}
+
+
+/* Show destination and source address from Ip Hdr for packet Trace */
+static void TraceIP(IpHdr* iphdr)
+{
+    if (TraceOn) {
+        char src[TRACE_MSG_SZ];
+        char dst[TRACE_MSG_SZ];
+        fprintf(TraceFile, "\tdst:%s src:%s\n", IpToS(iphdr->dst, dst),
+                IpToS(iphdr->src, src));
+    }
+}
+
+
+/* Show destination and source port from Tcp Hdr for packet Trace */
+static void TraceTcp(TcpHdr* tcphdr)
+{
+    if (TraceOn) {
+        fprintf(TraceFile, "\tdstPort:%u srcPort:%u\n", ntohs(tcphdr->dstPort),
+                ntohs(tcphdr->srcPort));
+    }
+}
+
+
+/* Show sequence and payload length for Trace */
+static void TraceSequence(word32 seq, int len)
+{
+    if (TraceOn) {
+        fprintf(TraceFile, "\tSequence:%u, payload length:%d\n", seq, len);
+    }
+}
+
+
+/* Show relative expected and relative received sequences */
+static void TraceRelativeSequence(word32 expected, word32 got)
+{
+    if (TraceOn) {
+        fprintf(TraceFile, "\tExpected sequence:%u, received sequence:%u\n",
+                expected, got);
+    }
+}
+
+
+/* Show server sequence startup from SYN */
+static void TraceServerSyn(word32 seq)
+{
+    if (TraceOn) {
+        fprintf(TraceFile, "\tServer SYN, Sequence Start:%u\n", seq);
+    }
+}
+
+
+/* Show client sequence startup from SYN */
+static void TraceClientSyn(word32 seq)
+{
+    if (TraceOn) {
+        fprintf(TraceFile, "\tClient SYN, Sequence Start:%u\n", seq);
+    }
+}
+
+
+/* Show client FIN capture */
+static void TraceClientFin(word32 finSeq, word32 relSeq)
+{
+    if (TraceOn) {
+        fprintf(TraceFile, "\tClient FIN capture:%u, current SEQ:%u\n",
+                finSeq, relSeq);
+    }
+}
+
+
+/* Show server FIN capture */
+static void TraceServerFin(word32 finSeq, word32 relSeq)
+{
+    if (TraceOn) {
+        fprintf(TraceFile, "\tServer FIN capture:%u, current SEQ:%u\n",
+                finSeq, relSeq);
+    }
+}
+
+
+/* Show number of SSL data bytes decoded, could be 0 (ok) */
+static void TraceGotData(int bytes)
+{
+    if (TraceOn) {
+        fprintf(TraceFile, "\t%d bytes of SSL App data processed\n", bytes);
+    }
+}
+
+
+/* Show bytes added to old SSL App data */
+static void TraceAddedData(int newBytes, int existingBytes)
+{
+    if (TraceOn) {
+        fprintf(TraceFile,
+                "\t%d bytes added to %d exisiting bytes in User Buffer\n",
+                newBytes, existingBytes);
+    }
+}
+
+
+/* Show Stale Session */
+static void TraceStaleSession(SnifferSession* session)
+{
+    if (TraceOn) {
+        fprintf(TraceFile, "\tFound a stale session\n");
+    }
+}
+
+
+/* Show Finding Stale Sessions */
+static void TraceFindingStale()
+{
+    if (TraceOn) {
+        fprintf(TraceFile, "\tTrying to find Stale Sessions\n");
+    }
+}
+
+
+/* Show Removed Session */
+static void TraceRemovedSession()
+{
+    if (TraceOn) {
+        fprintf(TraceFile, "\tRemoved it\n");
+    }
+}
+
+
+/* Set user error string */
+static void SetError(int idx, char* error, SnifferSession* session, int fatal)
+{
+    GetError(idx, error);
+    Trace(idx);
+    if (session && fatal == FATAL_ERROR_STATE)
+        session->flags.fatalError = 1;
+}
+
+
+/* See if this IPV4 network order address has been registered */
+/* return 1 is true, 0 is false */
+static int IsServerRegistered(word32 addr)
+{
+    int ret = 0;     /* false */
+    SnifferServer* sniffer;
+
+    LockMutex(&ServerListMutex);
+    
+    sniffer = ServerList;
+    while (sniffer) {
+        if (sniffer->server == addr) {
+            ret = 1;
+            break;
+        }
+        sniffer = sniffer->next;
+    }
+    
+    UnLockMutex(&ServerListMutex);
+
+    return ret;
+}
+
+
+/* See if this port has been registered to watch */
+/* return 1 is true, 0 is false */
+static int IsPortRegistered(word32 port)
+{
+    int ret = 0;    /* false */
+    SnifferServer* sniffer;
+    
+    LockMutex(&ServerListMutex);
+    
+    sniffer = ServerList;
+    while (sniffer) {
+        if (sniffer->port == port) {
+            ret = 1; 
+            break;
+        }
+        sniffer = sniffer->next;
+    }
+    
+    UnLockMutex(&ServerListMutex);
+
+    return ret;
+}
+
+
+/* Get SnifferServer from IP and Port */
+static SnifferServer* GetSnifferServer(IpInfo* ipInfo, TcpInfo* tcpInfo)
+{
+    SnifferServer* sniffer;
+    
+    LockMutex(&ServerListMutex);
+    
+    sniffer = ServerList;
+    while (sniffer) {
+        if (sniffer->port == tcpInfo->srcPort && sniffer->server == ipInfo->src)
+            break;
+        if (sniffer->port == tcpInfo->dstPort && sniffer->server == ipInfo->dst)
+            break;
+        sniffer = sniffer->next;
+    }
+    
+    UnLockMutex(&ServerListMutex);
+    
+    return sniffer;
+}
+
+
+/* Hash the Session Info, return hash row */
+static word32 SessionHash(IpInfo* ipInfo, TcpInfo* tcpInfo)
+{
+    word32 hash = ipInfo->src * ipInfo->dst;
+    hash *= tcpInfo->srcPort * tcpInfo->dstPort;
+    
+    return hash % HASH_SIZE;
+}
+
+
+/* Get Exisiting SnifferSession from IP and Port */
+static SnifferSession* GetSnifferSession(IpInfo* ipInfo, TcpInfo* tcpInfo)
+{
+    SnifferSession* session;
+    
+    word32 row = SessionHash(ipInfo, tcpInfo);
+    assert(row >= 0 && row <= HASH_SIZE);
+    
+    LockMutex(&SessionMutex);
+    
+    session = SessionTable[row];
+    while (session) {
+        if (session->server == ipInfo->src && session->client == ipInfo->dst &&
+                    session->srvPort == tcpInfo->srcPort &&
+                    session->cliPort == tcpInfo->dstPort)
+            break;
+        if (session->client == ipInfo->src && session->server == ipInfo->dst &&
+                    session->cliPort == tcpInfo->srcPort &&
+                    session->srvPort == tcpInfo->dstPort)
+            break;
+        
+        session = session->next;
+    }
+    
+    UnLockMutex(&SessionMutex);
+    
+    /* determine side */
+    if (session) {
+        if (ipInfo->dst == session->context->server &&
+            tcpInfo->dstPort == session->context->port)
+            session->flags.side = SERVER_END;
+        else
+            session->flags.side = CLIENT_END;
+    }    
+    
+    return session;
+}
+
+
+/* Sets the private key for a specific server and port  */
+/* returns 0 on success, -1 on error */
+int ssl_SetPrivateKey(const char* serverAddress, int port, const char* keyFile,
+                      int keyType, const char* password, char* error)
+{
+    int            ret;
+    int            type = (keyType == FILETYPE_PEM) ? SSL_FILETYPE_PEM :
+                                                      SSL_FILETYPE_ASN1;
+    SnifferServer* sniffer;
+    
+    TraceHeader();
+    TraceSetServer(serverAddress, port, keyFile);
+
+    sniffer = (SnifferServer*)malloc(sizeof(SnifferServer));
+    if (sniffer == NULL) {
+        SetError(MEMORY_STR, error, NULL, 0);
+        return -1;
+    }
+    InitSnifferServer(sniffer);
+
+    XSTRNCPY(sniffer->address, serverAddress, MAX_SERVER_ADDRESS);
+    sniffer->server = inet_addr(sniffer->address);
+    sniffer->port = port;
+    
+    /* start in client mode since SSL_new needs a cert for server */
+    sniffer->ctx = SSL_CTX_new(SSLv3_client_method());
+    if (!sniffer->ctx) {
+        SetError(MEMORY_STR, error, NULL, 0);
+        FreeSnifferServer(sniffer);
+        return -1;
+    }
+
+    if (password){
+        SSL_CTX_set_default_passwd_cb(sniffer->ctx, SetPassword);
+        SSL_CTX_set_default_passwd_cb_userdata(sniffer->ctx, (void*)password);
+    }
+    ret = SSL_CTX_use_PrivateKey_file(sniffer->ctx, keyFile, type);
+    if (ret != SSL_SUCCESS) {
+        SetError(KEY_FILE_STR, error, NULL, 0);
+        FreeSnifferServer(sniffer);
+        return -1;
+    }
+    Trace(NEW_SERVER_STR);
+    
+    LockMutex(&ServerListMutex);
+    
+    sniffer->next = ServerList;
+    ServerList = sniffer;
+    
+    UnLockMutex(&ServerListMutex);
+    
+    return 0;
+}
+
+
+/* Check IP Header for IPV4, TCP, and a registered server address */
+/* returns 0 on success, -1 on error */
+static int CheckIpHdr(IpHdr* iphdr, IpInfo* info, char* error)
+{
+    int    version = IP_V(iphdr);
+
+    TraceIP(iphdr);
+    Trace(IP_CHECK_STR);
+    if (version != IPV4) {
+        SetError(BAD_IPVER_STR, error, NULL, 0); 
+        return -1;
+    }
+
+    if (iphdr->protocol != TCP_PROTOCOL) { 
+        SetError(BAD_PROTO_STR, error, NULL, 0);
+        return -1;
+    }
+
+    if (!IsServerRegistered(iphdr->src) && !IsServerRegistered(iphdr->dst)) {
+        SetError(SERVER_NOT_REG_STR, error, NULL, 0);
+        return -1;
+    }
+
+    info->length  = IP_HL(iphdr);
+    info->total   = ntohs(iphdr->length);
+    info->src     = iphdr->src;
+    info->dst     = iphdr->dst;
+
+    return 0;
+}
+
+
+/* Check TCP Header for a registered port */
+/* returns 0 on success, -1 on error */
+static int CheckTcpHdr(TcpHdr* tcphdr, TcpInfo* info, char* error)
+{
+    TraceTcp(tcphdr);
+    Trace(TCP_CHECK_STR);
+    info->srcPort   = ntohs(tcphdr->srcPort);
+    info->dstPort   = ntohs(tcphdr->dstPort);
+    info->length    = TCP_LEN(tcphdr);
+    info->sequence  = ntohl(tcphdr->sequence);
+    info->fin       = tcphdr->flags & TCP_FIN;
+    info->rst       = tcphdr->flags & TCP_RST;
+    info->syn       = tcphdr->flags & TCP_SYN;
+    info->ack       = tcphdr->flags & TCP_ACK;
+
+    if (!IsPortRegistered(info->srcPort) && !IsPortRegistered(info->dstPort)) {
+        SetError(SERVER_PORT_NOT_REG_STR, error, NULL, 0);
+        return -1;
+    }
+
+    return 0;
+}
+
+
+/* Decode Record Layer Header */
+static int GetRecordHeader(const byte* input, RecordLayerHeader* rh, int* size)
+{
+    XMEMCPY(rh, input, RECORD_HEADER_SZ);
+    *size = (rh->length[0] << 8) | rh->length[1];
+
+    if (*size > (RECORD_SIZE + MAX_COMP_EXTRA + MAX_MSG_EXTRA))
+        return LENGTH_ERROR;
+
+    return 0;
+}
+
+
+/* Process Client Key Exchange, RSA only */
+static int ProcessClientKeyExchange(const byte* input, int* sslBytes,
+                                    SnifferSession* session, char* error)
+{
+    word32 idx = 0;
+    RsaKey key;
+    int    ret;
+    
+    InitRsaKey(&key, 0);
+   
+    ret = RsaPrivateKeyDecode(session->context->ctx->privateKey.buffer,
+                          &idx, &key, session->context->ctx->privateKey.length);
+    if (ret == 0) {
+        int length = RsaEncryptSize(&key);
+        
+        if (IsTLS(session->sslServer)) 
+            input += 2;     /* tls pre length */
+        
+        ret = RsaPrivateDecrypt(input, length, 
+                  session->sslServer->arrays.preMasterSecret, SECRET_LEN, &key);
+        
+        if (ret != SECRET_LEN) {
+            SetError(RSA_DECRYPT_STR, error, session, FATAL_ERROR_STATE);
+            FreeRsaKey(&key);
+            return -1;
+        }
+        ret = 0;  /* not in error state */
+        session->sslServer->arrays.preMasterSz = SECRET_LEN;
+        
+        /* store for client side as well */
+        XMEMCPY(session->sslClient->arrays.preMasterSecret,
+               session->sslServer->arrays.preMasterSecret, SECRET_LEN);
+        session->sslClient->arrays.preMasterSz = SECRET_LEN;
+        
+        #ifdef SHOW_SECRETS
+        {
+            int i;
+            printf("pre master secret: ");
+            for (i = 0; i < SECRET_LEN; i++)
+                printf("%02x", session->sslServer->arrays.preMasterSecret[i]);
+            printf("\n");
+        }
+        #endif
+    }
+    else {
+        SetError(RSA_DECODE_STR, error, session, FATAL_ERROR_STATE);
+        FreeRsaKey(&key);
+        return -1;
+    }
+    
+    if (SetCipherSpecs(session->sslServer) != 0) {
+        SetError(BAD_CIPHER_SPEC_STR, error, session, FATAL_ERROR_STATE);
+        FreeRsaKey(&key);
+        return -1;
+    }
+   
+    if (SetCipherSpecs(session->sslClient) != 0) {
+        SetError(BAD_CIPHER_SPEC_STR, error, session, FATAL_ERROR_STATE);
+        FreeRsaKey(&key);
+        return -1;
+    }
+    
+    MakeMasterSecret(session->sslServer);
+    MakeMasterSecret(session->sslClient);
+#ifdef SHOW_SECRETS
+    {
+        int i;
+        printf("server master secret: ");
+        for (i = 0; i < SECRET_LEN; i++)
+            printf("%02x", session->sslServer->arrays.masterSecret[i]);
+        printf("\n");
+        
+        printf("client master secret: ");
+        for (i = 0; i < SECRET_LEN; i++)
+            printf("%02x", session->sslClient->arrays.masterSecret[i]);
+        printf("\n");
+
+        printf("server suite = %d\n", session->sslServer->options.cipherSuite);
+        printf("client suite = %d\n", session->sslClient->options.cipherSuite);
+    }
+#endif   
+    
+    FreeRsaKey(&key);
+    return ret;
+}
+
+
+/* Process Server Hello */
+static int ProcessServerHello(const byte* input, int* sslBytes,
+                              SnifferSession* session, char* error)
+{
+    ProtocolVersion pv;
+    byte            b;
+    int             toRead = sizeof(ProtocolVersion) + RAN_LEN + ENUM_LEN;
+    
+    /* make sure we didn't miss ClientHello */
+    if (session->flags.clientHello == 0) {
+        SetError(MISSED_CLIENT_HELLO_STR, error, session, FATAL_ERROR_STATE);
+        return -1;
+    }
+
+    /* make sure can read through session len */
+    if (toRead > *sslBytes) {
+        SetError(SERVER_HELLO_INPUT_STR, error, session, FATAL_ERROR_STATE);
+        return -1;
+    }
+    
+    XMEMCPY(&pv, input, sizeof(ProtocolVersion));
+    input     += sizeof(ProtocolVersion);
+    *sslBytes -= sizeof(ProtocolVersion);
+           
+    session->sslServer->version = pv;
+    session->sslClient->version = pv;
+           
+    XMEMCPY(session->sslServer->arrays.serverRandom, input, RAN_LEN);
+    XMEMCPY(session->sslClient->arrays.serverRandom, input, RAN_LEN);
+    input    += RAN_LEN;
+    *sslBytes -= RAN_LEN;
+    
+    b = *input++;
+    *sslBytes -= 1;
+    
+    /* make sure can read through compression */
+    if ( (b + SUITE_LEN + ENUM_LEN) > *sslBytes) {
+        SetError(SERVER_HELLO_INPUT_STR, error, session, FATAL_ERROR_STATE);
+        return -1;
+    }
+    XMEMCPY(session->sslServer->arrays.sessionID, input, ID_LEN);
+    input     += b;
+    *sslBytes -= b;
+    
+    (void)*input++;  /* eat first byte, always 0 */
+    b = *input++;
+    session->sslServer->options.cipherSuite = b;
+    session->sslClient->options.cipherSuite = b;
+    *sslBytes -= SUITE_LEN;
+    
+    if (XMEMCMP(session->sslServer->arrays.sessionID,
+               session->sslClient->arrays.sessionID, ID_LEN) == 0) {
+        /* resuming */
+        SSL_SESSION* resume = GetSession(session->sslServer,
+                                       session->sslServer->arrays.masterSecret);
+        if (resume == NULL) {
+            SetError(BAD_SESSION_RESUME_STR, error, session, FATAL_ERROR_STATE);
+            return -1;
+        }
+        /* make sure client has master secret too */
+        XMEMCPY(session->sslClient->arrays.masterSecret,
+               session->sslServer->arrays.masterSecret, SECRET_LEN);
+        session->flags.resuming = 1;
+        
+        Trace(SERVER_DID_RESUMPTION_STR);
+        if (SetCipherSpecs(session->sslServer) != 0) {
+            SetError(BAD_CIPHER_SPEC_STR, error, session, FATAL_ERROR_STATE);
+            return -1;
+        }
+        
+        if (SetCipherSpecs(session->sslClient) != 0) {
+            SetError(BAD_CIPHER_SPEC_STR, error, session, FATAL_ERROR_STATE);
+            return -1;
+        }
+        
+        if (session->sslServer->options.tls) {
+            DeriveTlsKeys(session->sslServer);
+            DeriveTlsKeys(session->sslClient);
+        }
+        else {
+            DeriveKeys(session->sslServer);
+            DeriveKeys(session->sslClient);
+        }
+    }
+#ifdef SHOW_SECRETS
+    {
+        int i;
+        printf("cipher suite = 0x%02x\n",
+               session->sslServer->options.cipherSuite);
+        printf("server random: ");
+        for (i = 0; i < RAN_LEN; i++)
+            printf("%02x", session->sslServer->arrays.serverRandom[i]);
+        printf("\n");
+    }
+#endif   
+    return 0;
+}
+
+
+/* Process normal Client Hello */
+static int ProcessClientHello(const byte* input, int* sslBytes, 
+                              SnifferSession* session, char* error)
+{
+    byte sessionLen;
+    int  toRead = sizeof(ProtocolVersion) + RAN_LEN + ENUM_LEN;
+    
+    session->flags.clientHello = 1;  /* don't process again */
+    
+    /* make sure can read up to session len */
+    if (toRead > *sslBytes) {
+        SetError(CLIENT_HELLO_INPUT_STR, error, session, FATAL_ERROR_STATE);
+        return -1;
+    }
+    
+    /* skip, get negotiated one from server hello */
+    input     += sizeof(ProtocolVersion);
+    *sslBytes -= sizeof(ProtocolVersion);
+    
+    XMEMCPY(session->sslServer->arrays.clientRandom, input, RAN_LEN);
+    XMEMCPY(session->sslClient->arrays.clientRandom, input, RAN_LEN);
+    
+    input     += RAN_LEN;
+    *sslBytes -= RAN_LEN;
+    
+    /* store session in case trying to resume */
+    sessionLen = *input++;
+    if (sessionLen) {
+        if (ID_LEN > *sslBytes) {
+            SetError(CLIENT_HELLO_INPUT_STR, error, session, FATAL_ERROR_STATE);
+            return -1;
+        }
+        Trace(CLIENT_RESUME_TRY_STR);
+        XMEMCPY(session->sslClient->arrays.sessionID, input, ID_LEN);
+    }
+#ifdef SHOW_SECRETS
+    {
+        int i;
+        printf("client random: ");
+        for (i = 0; i < RAN_LEN; i++)
+            printf("%02x", session->sslServer->arrays.clientRandom[i]);
+        printf("\n");
+    }
+#endif
+    
+    return 0;
+}
+
+
+/* Process HandShake input */
+static int DoHandShake(const byte* input, int* sslBytes, IpInfo* ipInfo,
+                       TcpInfo* tcpInfo, SnifferSession* session, char* error)
+{
+    byte type;
+    int  size;
+    int  ret = 0;
+    
+    if (*sslBytes < HANDSHAKE_HEADER_SZ) {
+        SetError(HANDSHAKE_INPUT_STR, error, session, FATAL_ERROR_STATE);
+        return -1;
+    }
+    type = input[0];
+    size = (input[1] << 16) | (input[2] << 8) | input[3];
+    
+    input     += HANDSHAKE_HEADER_SZ;
+    *sslBytes -= HANDSHAKE_HEADER_SZ;
+    
+    if (*sslBytes < size) {
+        SetError(HANDSHAKE_INPUT_STR, error, session, FATAL_ERROR_STATE);
+        return -1;
+    }
+    
+    switch (type) {
+        case hello_verify_request:
+            Trace(GOT_HELLO_VERIFY_STR);
+            break;
+        case server_hello:
+            Trace(GOT_SERVER_HELLO_STR);
+            ret = ProcessServerHello(input, sslBytes, session, error);
+            break;
+        case certificate_request:
+            Trace(GOT_CERT_REQ_STR);
+            break;
+        case server_key_exchange:
+            Trace(GOT_SERVER_KEY_EX_STR);
+            break;
+        case certificate:
+            Trace(GOT_CERT_STR);
+            break;
+        case server_hello_done:
+            Trace(GOT_SERVER_HELLO_DONE_STR);
+            break;
+        case finished:
+            Trace(GOT_FINISHED_STR);
+            {
+                SSL*   ssl;
+                word32 inOutIdx = 0;
+                
+                if (session->flags.side == SERVER_END)
+                    ssl = session->sslServer;
+                else
+                    ssl = session->sslClient;
+                ret = DoFinished(ssl, input, &inOutIdx, SNIFF);
+                
+                if (ret == 0 && session->flags.cached == 0) {
+                    AddSession(session->sslServer);
+                    session->flags.cached = 1;
+                }
+            }
+            break;
+        case client_hello:
+            Trace(GOT_CLIENT_HELLO_STR);
+            ret = ProcessClientHello(input, sslBytes, session, error);
+            break;
+        case client_key_exchange:
+            Trace(GOT_CLIENT_KEY_EX_STR);
+            ret = ProcessClientKeyExchange(input, sslBytes, session, error);
+            break;
+        case certificate_verify:
+            Trace(GOT_CERT_VER_STR);
+            break;
+        default:
+            SetError(GOT_UNKNOWN_HANDSHAKE_STR, error, session, 0);
+            return -1;
+    }   
+
+    return ret;
+}
+
+
+/* Decrypt input into plain output */
+static void Decrypt(SSL* ssl, byte* output, const byte* input, word32 sz)
+{
+    switch (ssl->specs.bulk_cipher_algorithm) {
+        #ifdef BUILD_ARC4
+        case rc4:
+            Arc4Process(&ssl->decrypt.arc4, output, input, sz);
+            break;
+        #endif
+            
+        #ifdef BUILD_DES3
+        case triple_des:
+            Des3_CbcDecrypt(&ssl->decrypt.des3, output, input, sz);
+            break;
+        #endif
+            
+        #ifdef BUILD_AES
+        case aes:
+            AesCbcDecrypt(&ssl->decrypt.aes, output, input, sz);
+            break;
+        #endif
+            
+        #ifdef BUILD_HC128
+        case hc128:
+            Hc128_Process(&ssl->decrypt.hc128, output, input, sz);
+            break;
+        #endif
+            
+        #ifdef BUILD_RABBIT
+        case rabbit:
+            RabbitProcess(&ssl->decrypt.rabbit, output, input, sz);
+            break;
+        #endif
+    }
+}
+
+
+/* Decrypt input message into output, adjust output steam if needed */
+static const byte* DecryptMessage(SSL* ssl, const byte* input, word32 sz,
+                                  byte* output)
+{
+    Decrypt(ssl, output, input, sz);
+    ssl->keys.encryptSz = sz;
+    if (ssl->options.tls1_1 && ssl->specs.cipher_type == block)
+        return output + ssl->specs.block_size;     /* go past TLSv1.1 IV */
+    
+    return output;
+}
+
+
+/* remove session from table, use rowHint if no info (means we have a lock) */
+static void RemoveSession(SnifferSession* session, IpInfo* ipInfo,
+                        TcpInfo* tcpInfo, word32 rowHint)
+{
+    SnifferSession* previous = 0;
+    SnifferSession* current;
+    word32          row = rowHint;
+    int             haveLock = 0;
+   
+    if (ipInfo && tcpInfo)
+        row = SessionHash(ipInfo, tcpInfo);
+    else
+        haveLock = 1;
+    
+    assert(row >= 0 && row <= HASH_SIZE);
+    Trace(REMOVE_SESSION_STR);
+    
+    if (!haveLock)
+        LockMutex(&SessionMutex);
+    
+    current = SessionTable[row];
+    
+    while (current) {
+        if (current == session) {
+            if (previous)
+                previous->next = current->next;
+            else
+                SessionTable[row] = current->next;
+            FreeSnifferSession(session);
+            TraceRemovedSession();
+            break;
+        }
+        previous = current;
+        current  = current->next;
+    }
+    
+    if (!haveLock)
+        UnLockMutex(&SessionMutex);
+}
+
+
+/* Remove stale sessions from the Session Table, have a lock */
+static void RemoveStaleSessions()
+{
+    word32 i;
+    SnifferSession* session;
+    
+    for (i = 0; i < HASH_SIZE; i++) {
+        session = SessionTable[i];
+        while (session) {
+            SnifferSession* next = session->next; 
+            if (time(NULL) >= session->bornOn + SNIFFER_TIMEOUT) {
+                TraceStaleSession(session);
+                RemoveSession(session, NULL, NULL, i);
+            }
+            session = next;
+        }
+    }
+}
+
+
+/* Create a new Sniffer Session */
+static SnifferSession* CreateSession(IpInfo* ipInfo, TcpInfo* tcpInfo,
+                                     char* error)
+{
+    SnifferSession* session = 0;
+    int row;
+        
+    Trace(NEW_SESSION_STR);
+    /* create a new one */
+    session = (SnifferSession*)malloc(sizeof(SnifferSession));
+    if (session == NULL) {
+        SetError(MEMORY_STR, error, NULL, 0);
+        return 0;
+    }
+    InitSession(session);
+    session->server  = ipInfo->dst;
+    session->client  = ipInfo->src;
+    session->srvPort = tcpInfo->dstPort;
+    session->cliPort = tcpInfo->srcPort;
+    session->cliSeqStart = tcpInfo->sequence;
+    session->cliExpected = 1;  /* relative */
+    session->bornOn = time(NULL);
+                
+    session->context = GetSnifferServer(ipInfo, tcpInfo);
+    if (session->context == NULL) {
+        SetError(SERVER_NOT_REG_STR, error, NULL, 0);
+        free(session);
+        return 0;
+    }
+        
+    session->sslServer = SSL_new(session->context->ctx);
+    session->sslClient = SSL_new(session->context->ctx);
+    if (session->sslClient == NULL) {
+        if (session->sslServer) {
+            SSL_free(session->sslClient);
+            session->sslClient = 0;
+        }
+        SetError(BAD_NEW_SSL_STR, error, session, FATAL_ERROR_STATE);
+        free(session);
+        return 0;
+    }
+    /* put server back into server mode */
+    session->sslServer->options.side = SERVER_END;
+        
+    row = SessionHash(ipInfo, tcpInfo);
+    
+    /* add it to the session table */
+    LockMutex(&SessionMutex);
+        
+    session->next = SessionTable[row];
+    SessionTable[row] = session;
+    
+    SessionCount++;
+    
+    if ( (SessionCount % HASH_SIZE) == 0) {
+        TraceFindingStale();
+        RemoveStaleSessions();
+    }
+        
+    UnLockMutex(&SessionMutex);
+        
+    /* determine headed side */
+    if (ipInfo->dst == session->context->server &&
+        tcpInfo->dstPort == session->context->port)
+        session->flags.side = SERVER_END;
+    else
+        session->flags.side = CLIENT_END;        
+    
+    return session;
+}
+
+
+/* Process Old Client Hello Input */
+static int DoOldHello(SnifferSession* session, const byte* sslFrame,
+                      int* rhSize, int* sslBytes, char* error)
+{
+    const byte* input = sslFrame;
+    byte        b0, b1;
+    word32      idx = 0;
+    int         ret;
+
+    Trace(GOT_OLD_CLIENT_HELLO_STR);
+    session->flags.clientHello = 1;    /* don't process again */
+    b0 = *input++;
+    b1 = *input++;
+    *sslBytes -= 2;
+    *rhSize = ((b0 & 0x7f) << 8) | b1;
+
+    if (*rhSize > *sslBytes) {
+        SetError(OLD_CLIENT_INPUT_STR, error, session, FATAL_ERROR_STATE);
+        return -1;
+    }
+
+    ret = ProcessOldClientHello(session->sslServer, input, &idx, *sslBytes,
+                                *rhSize);    
+    if (ret < 0) {
+        SetError(BAD_OLD_CLIENT_STR, error, session, FATAL_ERROR_STATE);
+        return -1;
+    }
+    
+    Trace(OLD_CLIENT_OK_STR);
+    XMEMCPY(session->sslClient->arrays.clientRandom,
+           session->sslServer->arrays.clientRandom, RAN_LEN);
+    
+    *sslBytes -= *rhSize;
+    return 0;
+}
+
+
+/* Calculate the TCP checksum, see RFC 1071 */
+/* return 0 for success, -1 on error */
+/* can be called from decode() with
+   TcpChecksum(&ipInfo, &tcpInfo, sslBytes, packet + ipInfo.length);
+   could also add a 64bit version if type available and using this
+*/
+int TcpChecksum(IpInfo* ipInfo, TcpInfo* tcpInfo, int dataLen,
+                const byte* packet)
+{
+    TcpPseudoHdr  pseudo;
+    int           count = PSEUDO_HDR_SZ;
+    const word16* data = (word16*)&pseudo;
+    word32        sum = 0;
+    word16        checksum;
+    
+    pseudo.src = ipInfo->src;
+    pseudo.dst = ipInfo->dst;
+    pseudo.rsv = 0;
+    pseudo.protocol = TCP_PROTO;
+    pseudo.legnth = htons(tcpInfo->length + dataLen);
+    
+    /* pseudo header sum */
+    while (count >= 2) {
+        sum   += *data++;
+        count -= 2;
+    }
+    
+    count = tcpInfo->length + dataLen;
+    data = (word16*)packet;
+    
+    /* main sum */
+    while (count > 1) {
+        sum   += *data++;
+        count -=2;
+    }
+    
+    /* get left-over, if any */
+    packet = (byte*)data;
+    if (count > 0) {
+        sum += *packet;
+    }
+    
+    /* fold 32bit sum into 16 bits */
+    while (sum >> 16)
+        sum = (sum & 0xffff) + (sum >> 16);
+    
+    checksum = (word16)~sum;
+    /* checksum should now equal 0, since included already calcd checksum */
+    /* field, but tcp checksum offloading could negate calculation */
+    if (checksum == 0)
+        return 0;
+    return -1;
+}
+
+
+/* Check IP and TCP headers, set payload */
+/* returns 0 on success, -1 on error */
+int CheckHeaders(IpInfo* ipInfo, TcpInfo* tcpInfo, const byte* packet,
+                 int length, const byte** sslFrame, int* sslBytes, char* error)
+{
+    TraceHeader();
+    TracePacket();
+    if (length < IP_HDR_SZ) {
+        SetError(PACKET_HDR_SHORT_STR, error, NULL, 0);
+        return -1;
+    }
+    if (CheckIpHdr((IpHdr*)packet, ipInfo, error) != 0)
+        return -1;
+    
+    if (length < (ipInfo->length + TCP_HDR_SZ)) {
+        SetError(PACKET_HDR_SHORT_STR, error, NULL, 0);
+        return -1;
+    }
+    if (CheckTcpHdr((TcpHdr*)(packet + ipInfo->length), tcpInfo, error) != 0)
+        return -1;
+    
+    *sslFrame = packet + ipInfo->length + tcpInfo->length;
+    if (*sslFrame > packet + length) {
+        SetError(PACKET_HDR_SHORT_STR, error, NULL, 0);
+        return -1;
+    }
+    *sslBytes = packet + length - *sslFrame;
+    
+    return 0;
+}
+
+
+/* Create or Find existing session */
+/* returns 0 on success (continue), -1 on error, 1 on success (end) */
+static int CheckSession(IpInfo* ipInfo, TcpInfo* tcpInfo, int sslBytes,
+                        SnifferSession** session, char* error)
+{
+    /* create a new SnifferSession on client SYN */
+    if (tcpInfo->syn && !tcpInfo->ack) {
+        TraceClientSyn(tcpInfo->sequence);
+        *session = CreateSession(ipInfo, tcpInfo, error);
+        if (*session == NULL) {
+            *session = GetSnifferSession(ipInfo, tcpInfo);
+            /* already had exisiting, so OK */
+            if (*session)
+                return 1;
+            
+            SetError(MEMORY_STR, error, NULL, 0);
+            return -1;
+        }
+        return 1;
+    }
+    /* get existing sniffer session */
+    else {
+        *session = GetSnifferSession(ipInfo, tcpInfo);
+        if (*session == NULL) {
+            /* don't worry about extraneous RST or duplicate FINs */
+            if (tcpInfo->fin || tcpInfo->rst)
+                return 1;
+            /* don't worry about duplicate ACKs either */
+            if (sslBytes == 0 && tcpInfo->ack)
+                return 1;
+            
+            SetError(BAD_SESSION_STR, error, NULL, 0);
+            return -1;
+        }        
+    }
+    return 0;
+}
+
+
+#ifndef min
+
+static INLINE word32 min(word32 a, word32 b)
+{
+    return a > b ? b : a;
+}
+
+#endif
+
+
+/* Create a Packet Buffer from *begin - end, adjust new *begin and bytesLeft */
+static PacketBuffer* CreateBuffer(word32* begin, word32 end, const byte* data,
+                                  int* bytesLeft)
+{
+    PacketBuffer* pb;
+    
+    int added = end - *begin + 1;
+    assert(*begin <= end);
+    
+    pb = (PacketBuffer*)malloc(sizeof(PacketBuffer));
+    if (pb == NULL) return NULL;
+    
+    pb->next  = 0;
+    pb->begin = *begin;
+    pb->end   = end;
+    pb->data = (byte*)malloc(added);
+    
+    if (pb->data == NULL) {
+        free(pb);
+        return NULL;
+    }
+    XMEMCPY(pb->data, data, added);
+    
+    *bytesLeft -= added;
+    *begin      = pb->end + 1;
+    
+    return pb;
+}
+
+
+/* Add sslFrame to Reassembly List */
+/* returns 1 (end) on success, -1, on error */
+static int AddToReassembly(byte from, word32 seq, const byte* sslFrame,
+                           int sslBytes, SnifferSession* session, char* error)
+{
+    PacketBuffer*  add;
+    PacketBuffer** front = (from == SERVER_END) ? &session->cliReassemblyList:
+                                                  &session->srvReassemblyList;
+    PacketBuffer*  curr = *front;
+    PacketBuffer*  prev = curr;
+    
+    word32  startSeq = seq;
+    word32  added;
+    int     bytesLeft = sslBytes;  /* could be overlapping fragment */
+
+    /* if list is empty add full frame to front */
+    if (!curr) {
+        add = CreateBuffer(&seq, seq + sslBytes - 1, sslFrame, &bytesLeft);
+        if (add == NULL) {
+            SetError(MEMORY_STR, error, session, FATAL_ERROR_STATE);
+            return -1;
+        }
+        *front = add;
+        return 1;
+    }
+    
+    /* add to front if before current front, up to next->begin */
+    if (seq < curr->begin) {
+        word32 end = seq + sslBytes - 1;
+        
+        if (end >= curr->begin)
+            end = curr->begin - 1;
+        
+        add = CreateBuffer(&seq, end, sslFrame, &bytesLeft);
+        if (add == NULL) {
+            SetError(MEMORY_STR, error, session, FATAL_ERROR_STATE);
+            return -1;
+        }
+        add->next = curr;
+        *front = add;
+    }
+    
+    /* while we have bytes left, try to find a gap to fill */
+    while (bytesLeft > 0) {
+        /* get previous packet in list */
+        while (curr && (seq >= curr->begin)) {
+            prev = curr;
+            curr = curr->next;
+        }
+        
+        /* don't add  duplicate data */
+        if (prev->end >= seq) {
+            if ( (seq + bytesLeft - 1) <= prev->end)
+                return 1;
+            seq = prev->end + 1;
+            bytesLeft = startSeq + sslBytes - seq;
+        }
+        
+        if (!curr)
+            /* we're at the end */
+            added = bytesLeft;
+        else 
+            /* we're in between two frames */
+            added = min((word32)bytesLeft, curr->begin - seq);
+        
+        /* data already there */
+        if (added == 0)
+            continue;
+        
+        add = CreateBuffer(&seq, seq + added - 1, &sslFrame[seq - startSeq],
+                           &bytesLeft);
+        if (add == NULL) {
+            SetError(MEMORY_STR, error, session, FATAL_ERROR_STATE);
+            return -1;
+        }
+        add->next  = prev->next;
+        prev->next = add;
+    }
+    return 1;
+}
+
+
+/* Add out of order FIN capture */
+/* returns 1 for success (end) */
+static int AddFinCapture(SnifferSession* session, word32 sequence)
+{
+    if (session->flags.side == SERVER_END) {
+        if (session->finCaputre.cliCounted == 0)
+            session->finCaputre.cliFinSeq = sequence;
+    }
+    else {
+        if (session->finCaputre.srvCounted == 0)
+            session->finCaputre.srvFinSeq = sequence;
+    }
+    return 1;
+}
+
+
+/* Adjust incoming sequence based on side */
+/* returns 0 on success (continue), -1 on error, 1 on success (end) */
+static int AdjustSequence(TcpInfo* tcpInfo, SnifferSession* session,
+                          int* sslBytes, const byte** sslFrame, char* error)
+{
+    word32  seqStart = (session->flags.side == SERVER_END) ? 
+                                     session->cliSeqStart :session->srvSeqStart;
+    word32  real     = tcpInfo->sequence - seqStart;
+    word32* expected = (session->flags.side == SERVER_END) ?
+                                  &session->cliExpected : &session->srvExpected;
+    PacketBuffer* reassemblyList = (session->flags.side == SERVER_END) ?
+                        session->cliReassemblyList : session->srvReassemblyList;
+    
+    /* handle rollover of sequence */
+    if (tcpInfo->sequence < seqStart)
+        real = 0xffffffffU - seqStart + tcpInfo->sequence;
+        
+    TraceRelativeSequence(*expected, real);
+    
+    if (real < *expected) {
+        Trace(DUPLICATE_STR);
+        if (real + *sslBytes > *expected) {
+            int overlap = *expected - real;
+            Trace(OVERLAP_DUPLICATE_STR);
+                
+            /* adjust to expected, remove duplicate */
+            *sslFrame += overlap;
+            *sslBytes -= overlap;
+                
+            if (reassemblyList) {
+                word32 newEnd = *expected + *sslBytes;
+                    
+                if (newEnd > reassemblyList->begin) {
+                    Trace(OVERLAP_REASSEMBLY_BEGIN_STR);
+                    
+                    /* remove bytes already on reassembly list */
+                    *sslBytes -= newEnd - reassemblyList->begin;
+                }
+                if (newEnd > reassemblyList->end) {
+                    Trace(OVERLAP_REASSEMBLY_END_STR);
+                    
+                    /* may be past reassembly list end (could have more on list)
+                       so try to add what's past the front->end */
+                    AddToReassembly(session->flags.side, reassemblyList->end +1,
+                                *sslFrame + reassemblyList->end - *expected + 1,
+                                 newEnd - reassemblyList->end, session, error);
+                }
+            }
+        }
+        else
+            return 1;
+    }
+    else if (real > *expected) {
+        Trace(OUT_OF_ORDER_STR);
+        if (*sslBytes > 0)
+            return AddToReassembly(session->flags.side, real, *sslFrame,
+                                   *sslBytes, session, error);
+        else if (tcpInfo->fin)
+            return AddFinCapture(session, real);
+    }
+    /* got expected sequence */
+    *expected += *sslBytes;
+    if (tcpInfo->fin)
+        *expected += 1;
+    
+    return 0;
+}
+
+
+/* Check TCP Sequence status */
+/* returns 0 on success (continue), -1 on error, 1 on success (end) */
+static int CheckSequence(IpInfo* ipInfo, TcpInfo* tcpInfo,
+                         SnifferSession* session, int* sslBytes,
+                         const byte** sslFrame, char* error)
+{
+    int actualLen;
+    
+    /* init SEQ from server to client */
+    if (tcpInfo->syn && tcpInfo->ack) {
+        session->srvSeqStart = tcpInfo->sequence;
+        session->srvExpected = 1;
+        TraceServerSyn(tcpInfo->sequence);
+        return 1;
+    }
+    
+    /* adjust potential ethernet trailer */
+    actualLen = ipInfo->total - ipInfo->length - tcpInfo->length;
+    if (*sslBytes > actualLen) {
+        *sslBytes = actualLen;
+    }
+    
+    TraceSequence(tcpInfo->sequence, *sslBytes);
+    
+    return AdjustSequence(tcpInfo, session, sslBytes, sslFrame, error);    
+}
+
+
+/* Check Status before record processing */
+/* returns 0 on success (continue), -1 on error, 1 on success (end) */
+static int CheckPreRecord(IpInfo* ipInfo, TcpInfo* tcpInfo,
+                          const byte** sslFrame, SnifferSession* session,
+                          int* sslBytes, const byte** end, char* error)
+{
+    word32 length;
+    SSL*   ssl = (session->flags.side == SERVER_END) ? session->sslServer :
+                                                       session->sslClient;
+    /* remove SnifferSession on 2nd FIN or RST */
+    if (tcpInfo->fin || tcpInfo->rst) {
+        /* flag FIN and RST */
+        if (tcpInfo->fin)
+            session->flags.finCount += 1;
+        else if (tcpInfo->rst)
+            session->flags.finCount += 2;
+        
+        if (session->flags.finCount >= 2) {
+            RemoveSession(session, ipInfo, tcpInfo, 0);
+            return 1;
+        }
+    }
+    
+    if (session->flags.fatalError == FATAL_ERROR_STATE) {
+        SetError(FATAL_ERROR_STR, error, NULL, 0);
+        return -1;
+    }
+    
+    if (*sslBytes == 0) {
+        Trace(NO_DATA_STR);
+        return 1;
+    }
+    
+    /* if current partial data, add to end of partial */
+    if ( (length = ssl->buffers.inputBuffer.length) ) {
+        Trace(PARTIAL_ADD_STR);
+        
+        if ( (*sslBytes + length) > sizeof(ssl->buffers.inputBuffer.buffer)) {
+            SetError(BUFFER_ERROR_STR, error, session, FATAL_ERROR_STATE);
+            return -1;
+        }
+        XMEMCPY(&ssl->buffers.inputBuffer.buffer[length], *sslFrame, *sslBytes);
+        *sslBytes += length;
+        ssl->buffers.inputBuffer.length = *sslBytes;
+        *sslFrame = ssl->buffers.inputBuffer.buffer;
+        *end = *sslFrame + *sslBytes;
+    }
+    
+    if (session->flags.clientHello == 0 && **sslFrame != handshake) {
+        int rhSize;
+        int ret = DoOldHello(session, *sslFrame, &rhSize, sslBytes, error);
+        if (ret < 0)
+            return -1;  /* error already set */
+        if (*sslBytes <= 0)
+            return 1;
+    }
+    
+    return 0;
+}
+
+
+/* See if input on the reassembly list is ready for consuming */
+/* returns 1 for TRUE, 0 for FALSE */
+static int HaveMoreInput(SnifferSession* session, const byte** sslFrame,
+                         int* sslBytes, const byte** end)
+{
+    /* sequence and reassembly based on from, not to */
+    int            moreInput = 0;
+    PacketBuffer** front = (session->flags.side == SERVER_END) ?
+                      &session->cliReassemblyList : &session->srvReassemblyList;
+    word32*        expected = (session->flags.side == SERVER_END) ?
+                                  &session->cliExpected : &session->srvExpected;
+    /* buffer is on receiving end */
+    word32*        length = (session->flags.side == SERVER_END) ?
+                               &session->sslServer->buffers.inputBuffer.length :
+                               &session->sslClient->buffers.inputBuffer.length;
+    byte*          buffer = (session->flags.side == SERVER_END) ?
+                                session->sslServer->buffers.inputBuffer.buffer :
+                                session->sslClient->buffers.inputBuffer.buffer;
+    
+    while (*front && ((*front)->begin == *expected) ) {
+        word32 room = STATIC_BUFFER_LEN - *length;
+        word32 packetLen = (*front)->end - (*front)->begin + 1;
+        
+        if (packetLen <= room) {
+            PacketBuffer* remove = *front;
+            
+            XMEMCPY(&buffer[*length], (*front)->data, packetLen);
+            *length   += packetLen;
+            *expected += packetLen;
+            
+            /* remove used packet */
+            *front = (*front)->next;
+            FreePacketBuffer(remove);
+            
+            moreInput = 1;
+        }
+        else
+            break;
+    }
+    if (moreInput) {
+        *sslFrame = buffer;
+        *sslBytes = *length;
+        *end      = buffer + *length;
+    }
+    return moreInput;
+}
+                         
+
+
+/* Process Message(s) from sslFrame */
+/* return Number of bytes on success, 0 for no data yet, and -1 on error */
+static int ProcessMessage(IpInfo* ipInfo, TcpInfo* tcpInfo,const byte* sslFrame,
+                          SnifferSession* session, int sslBytes, byte* data,
+                          const byte* end, char* error)
+{
+    const byte*       sslBegin = sslFrame;
+    const byte*       tmp;
+    RecordLayerHeader rh;
+    int               rhSize;
+    int               ret;
+    int               decoded = 0;      /* bytes stored for user in data */
+    int               notEnough;        /* notEnough bytes yet flag */
+    SSL*              ssl = (session->flags.side == SERVER_END) ?
+                                        session->sslServer : session->sslClient;
+doMessage:
+    notEnough = 0;
+    if (sslBytes >= RECORD_HEADER_SZ) {
+        if (GetRecordHeader(sslFrame, &rh, &rhSize) != 0) {
+            SetError(BAD_RECORD_HDR_STR, error, session, FATAL_ERROR_STATE);
+            return -1;
+        }
+    }
+    else
+        notEnough = 1;
+
+    if (notEnough || rhSize > (sslBytes - RECORD_HEADER_SZ)) {
+        /* don't have enough input yet to process full SSL record */
+        Trace(PARTIAL_INPUT_STR);
+        
+        /* store partial if not there already or we advanced */
+        if (ssl->buffers.inputBuffer.length == 0 || sslBegin != sslFrame) {
+            if (sslBytes > sizeof(ssl->buffers.inputBuffer.buffer)) {
+                SetError(BUFFER_ERROR_STR, error, session, FATAL_ERROR_STATE);
+                return -1;
+            }
+            XMEMCPY(ssl->buffers.inputBuffer.buffer, sslFrame, sslBytes);
+            ssl->buffers.inputBuffer.length = sslBytes;
+        }
+        if (HaveMoreInput(session, &sslFrame, &sslBytes, &end))
+            goto doMessage;
+        return decoded;
+    }
+    sslFrame += RECORD_HEADER_SZ;
+    sslBytes -= RECORD_HEADER_SZ;
+    tmp = sslFrame + rhSize;   /* may have more than one record to process */
+    
+    /* decrypt if needed */
+    if (session->flags.side == SERVER_END && session->flags.serverCipherOn)
+        sslFrame = DecryptMessage(ssl, sslFrame, rhSize,
+                                  ssl->buffers.outputBuffer.buffer);
+    else if (session->flags.side == CLIENT_END && session->flags.clientCipherOn)
+        sslFrame = DecryptMessage(ssl, sslFrame, rhSize,
+                                  ssl->buffers.outputBuffer.buffer);
+            
+    switch ((enum ContentType)rh.type) {
+        case handshake:
+            Trace(GOT_HANDSHAKE_STR);
+            ret = DoHandShake(sslFrame, &sslBytes, ipInfo, tcpInfo, session,
+                              error);
+            if (ret != 0) {
+                if (session->flags.fatalError == 0)
+                    SetError(BAD_HANDSHAKE_STR,error,session,FATAL_ERROR_STATE);
+                return -1;
+            }
+            break;
+        case change_cipher_spec:
+            if (session->flags.side == SERVER_END)
+                session->flags.serverCipherOn = 1;
+            else
+                session->flags.clientCipherOn = 1;
+            Trace(GOT_CHANGE_CIPHER_STR);
+            break;
+        case application_data:
+            Trace(GOT_APP_DATA_STR);
+            {
+                word32 inOutIdx = 0;
+                    
+                ret = DoApplicationData(ssl, (byte*)sslFrame, &inOutIdx);
+                if (ret == 0) {
+                    ret = ssl->buffers.clearOutputBuffer.length;
+                    TraceGotData(ret);
+                    if (ret) {  /* may be blank message */
+                        XMEMCPY(&data[decoded],
+                               ssl->buffers.clearOutputBuffer.buffer, ret);
+                        TraceAddedData(ret, decoded);
+                        decoded += ret;
+                        ssl->buffers.clearOutputBuffer.length = 0;
+                    }
+                }
+                else {
+                    SetError(BAD_APP_DATA_STR, error,session,FATAL_ERROR_STATE);
+                    return -1;
+                }
+            }
+            break;
+        case alert:
+            Trace(GOT_ALERT_STR);
+            break;
+        default:
+            SetError(GOT_UNKNOWN_RECORD_STR, error, session, FATAL_ERROR_STATE);
+            return -1;
+    }
+    
+    if (tmp < end) {
+        Trace(ANOTHER_MSG_STR);
+        sslFrame = tmp;
+        sslBytes = end - tmp;
+        goto doMessage;
+    }
+    
+    /* clear used input */
+    ssl->buffers.inputBuffer.length = 0;
+    
+    /* could have more input ready now */
+    if (HaveMoreInput(session, &sslFrame, &sslBytes, &end))
+        goto doMessage;
+    
+    return decoded;
+}
+
+
+/* See if we need to process any pending FIN captures */
+static void CheckFinCapture(IpInfo* ipInfo, TcpInfo* tcpInfo, 
+                            SnifferSession* session)
+{
+    if (session->finCaputre.cliFinSeq && session->finCaputre.cliFinSeq <= 
+                                         session->cliExpected) {
+        if (session->finCaputre.cliCounted == 0) {
+            session->flags.finCount += 1;
+            session->finCaputre.cliCounted = 1;
+            TraceClientFin(session->finCaputre.cliFinSeq, session->cliExpected);
+        }
+    }
+        
+    if (session->finCaputre.srvFinSeq && session->finCaputre.srvFinSeq <= 
+                                         session->srvExpected) {
+        if (session->finCaputre.srvCounted == 0) {
+            session->flags.finCount += 1;
+            session->finCaputre.srvCounted = 1;
+            TraceServerFin(session->finCaputre.srvFinSeq, session->srvExpected);
+        }
+    }
+                
+    if (session->flags.finCount >= 2) 
+        RemoveSession(session, ipInfo, tcpInfo, 0);
+}
+
+
+/* Passes in an IP/TCP packet for decoding (ethernet/localhost frame) removed */
+/* returns Number of bytes on success, 0 for no data yet, and -1 on error */
+int ssl_DecodePacket(const byte* packet, int length, byte* data, char* error)
+{
+    TcpInfo           tcpInfo;
+    IpInfo            ipInfo;
+    const byte*       sslFrame;
+    const byte*       end = packet + length;
+    int               sslBytes;                /* ssl bytes unconsumed */
+    int               ret;
+    SnifferSession*   session = 0;
+
+    if (CheckHeaders(&ipInfo, &tcpInfo, packet, length, &sslFrame, &sslBytes,
+                     error) != 0)
+        return -1;
+    
+    ret = CheckSession(&ipInfo, &tcpInfo, sslBytes, &session, error);
+    if (ret == -1)     return -1;
+    else if (ret == 1) return  0;   /* done for now */
+    
+    ret = CheckSequence(&ipInfo, &tcpInfo, session, &sslBytes, &sslFrame,error);
+    if (ret == -1)     return -1;
+    else if (ret == 1) return  0;   /* done for now */
+    
+    ret = CheckPreRecord(&ipInfo, &tcpInfo, &sslFrame, session, &sslBytes,
+                         &end, error);
+    if (ret == -1)     return -1;
+    else if (ret == 1) return  0;   /* done for now */
+
+    ret = ProcessMessage(&ipInfo, &tcpInfo, sslFrame, session, sslBytes, data,
+                         end, error);
+    CheckFinCapture(&ipInfo, &tcpInfo, session);
+    return ret;
+}
+
+
+/* Enables (if traceFile)/ Disables debug tracing */
+/* returns 0 on success, -1 on error */
+int ssl_Trace(const char* traceFile, char* error)
+{
+    if (traceFile) {
+        TraceFile = fopen(traceFile, "a");
+        if (!TraceFile) {
+            SetError(BAD_TRACE_FILE_STR, error, NULL, 0);
+            return -1;
+        }
+        TraceOn = 1;
+    }
+    else 
+        TraceOn = 0;
+
+    return 0;
+}
+
+
+
+
+#endif /* CYASSL_SNIFFER */
diff --git a/src/ssl.c b/src/ssl.c
new file mode 100644
index 000000000..18d0a9988
--- /dev/null
+++ b/src/ssl.c
@@ -0,0 +1,3484 @@
+/* ssl.c
+ *
+ * Copyright (C) 2006-2011 Sawtooth Consulting Ltd.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * CyaSSL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+
+#include "ssl.h"
+#include "cyassl_int.h"
+#include "cyassl_error.h"
+#include "coding.h"
+
+#ifdef OPENSSL_EXTRA
+    /* openssl headers begin */
+    #include "evp.h"
+    #include "hmac.h"
+    #include "crypto.h"
+    #include "des.h"
+    /* openssl headers end, cyassl internal headers next */
+    #include "ctc_hmac.h"
+    #include "random.h"
+    #include "des3.h"
+    #include "ctc_md4.h"
+    #include "coding.h"
+#endif
+
+#ifdef HAVE_ERRNO_H 
+    #include 
+#endif
+
+#define TRUE  1
+#define FALSE 0
+
+
+#ifndef min
+
+    static INLINE word32 min(word32 a, word32 b)
+    {
+        return a > b ? b : a;
+    }
+
+#endif /* min */
+
+
+
+SSL_CTX* SSL_CTX_new(SSL_METHOD* method)
+{
+    SSL_CTX* ctx = (SSL_CTX*) XMALLOC(sizeof(SSL_CTX), 0, DYNAMIC_TYPE_CTX);
+    if (ctx)
+        InitSSL_Ctx(ctx, method);
+
+    return ctx;
+}
+
+
+void SSL_CTX_free(SSL_CTX* ctx)
+{
+    if (ctx)
+        FreeSSL_Ctx(ctx);
+}
+
+
+SSL* SSL_new(SSL_CTX* ctx)
+{
+
+    SSL* ssl = (SSL*) XMALLOC(sizeof(SSL), ctx->heap, DYNAMIC_TYPE_SSL);
+    if (ssl)
+        if (InitSSL(ssl, ctx) < 0) {
+            FreeSSL(ssl);
+            ssl = 0;
+        }
+
+    return ssl;
+}
+
+
+void SSL_free(SSL* ssl)
+{
+    CYASSL_ENTER("SSL_free");
+    if (ssl)
+        FreeSSL(ssl);
+    CYASSL_LEAVE("SSL_free", 0);
+}
+
+
+int SSL_set_fd(SSL* ssl, int fd)
+{
+    ssl->rfd = fd;      /* not used directly to allow IO callbacks */
+    ssl->wfd = fd;
+
+    ssl->IOCB_ReadCtx  = &ssl->rfd;
+    ssl->IOCB_WriteCtx = &ssl->wfd;
+
+    return SSL_SUCCESS;
+}
+
+
+int SSL_get_fd(const SSL* ssl)
+{
+    return ssl->rfd;
+}
+
+
+int CyaSSL_negotiate(SSL* ssl)
+{
+    int err = -1;
+
+#ifndef NO_CYASSL_SERVER
+    if (ssl->options.side == SERVER_END)
+        err = SSL_accept(ssl);
+#endif
+
+#ifndef NO_CYASSL_CLIENT
+    if (ssl->options.side == CLIENT_END)
+        err = SSL_connect(ssl);
+#endif
+
+    if (err == SSL_SUCCESS)
+        return 0;
+    else
+        return err;
+}
+
+
+int SSL_write(SSL* ssl, const void* buffer, int sz)
+{
+    int ret;
+
+    CYASSL_ENTER("SSL_write()");
+
+#ifdef HAVE_ERRNO_H 
+    errno = 0;
+#endif
+
+    ret = SendData(ssl, buffer, sz);
+
+    CYASSL_LEAVE("SSL_write()", ret);
+
+    if (ret < 0)
+        return SSL_FATAL_ERROR;
+    else
+        return ret;
+}
+
+
+int SSL_read(SSL* ssl, void* buffer, int sz)
+{
+    int ret; 
+
+    CYASSL_ENTER("SSL_read()");
+
+#ifdef HAVE_ERRNO_H 
+        errno = 0;
+#endif
+
+    ret = ReceiveData(ssl, (byte*)buffer, min(sz, OUTPUT_RECORD_SIZE));
+
+    CYASSL_LEAVE("SSL_read()", ret);
+
+    if (ret < 0)
+        return SSL_FATAL_ERROR;
+    else
+        return ret;
+}
+
+
+int SSL_shutdown(SSL* ssl)
+{
+    CYASSL_ENTER("SSL_shutdown()");
+
+    if (ssl->options.quietShutdown) {
+        CYASSL_MSG("quiet shutdown, no close notify sent"); 
+        return 0;
+    }
+
+    /* try to send close notify, not an error if can't */
+    if (!ssl->options.isClosed && !ssl->options.connReset &&
+                                  !ssl->options.sentNotify) {
+        ssl->error = SendAlert(ssl, alert_warning, close_notify);
+        if (ssl->error < 0) {
+            CYASSL_ERROR(ssl->error);
+            return SSL_FATAL_ERROR;
+        }
+        ssl->options.sentNotify = 1;  /* don't send close_notify twice */
+    }
+
+    CYASSL_LEAVE("SSL_shutdown()", ssl->error);
+
+    ssl->error = SSL_ERROR_SYSCALL;   /* simulate OpenSSL behavior */
+
+    return 0;
+}
+
+
+int SSL_get_error(SSL* ssl, int dummy)
+{
+    if (ssl->error == WANT_READ)
+        return SSL_ERROR_WANT_READ;         /* convert to OpenSSL type */
+    else if (ssl->error == WANT_WRITE)
+        return SSL_ERROR_WANT_WRITE;        /* convert to OpenSSL type */
+    else if (ssl->error == ZERO_RETURN) 
+        return SSL_ERROR_ZERO_RETURN;       /* convert to OpenSSL type */
+    return ssl->error;
+}
+
+
+int SSL_want_read(SSL* ssl)
+{
+    if (ssl->error == WANT_READ)
+        return 1;
+
+    return 0;
+}
+
+
+int SSL_want_write(SSL* ssl)
+{
+    if (ssl->error == WANT_WRITE)
+        return 1;
+
+    return 0;
+}
+
+
+char* ERR_error_string(unsigned long errNumber, char* buffer)
+{
+    static char* msg = "Please supply a buffer for error string";
+
+    if (buffer) {
+        SetErrorString(errNumber, buffer);
+        return buffer;
+    }
+
+    return msg;
+}
+
+
+void ERR_error_string_n(unsigned long e, char* buf, size_t len)
+{
+    if (len) ERR_error_string(e, buf);
+}
+
+
+#ifndef NO_FILESYSTEM
+
+void ERR_print_errors_fp(FILE* fp, int err)
+{
+    char buffer[MAX_ERROR_SZ + 1];
+
+    SetErrorString(err, buffer);
+    fprintf(fp, "%s", buffer);
+}
+
+#endif
+
+
+int SSL_pending(SSL* ssl)
+{
+    return ssl->buffers.clearOutputBuffer.length;
+}
+
+
+/* owns der */
+static int AddCA(SSL_CTX* ctx, buffer der)
+{
+    word32      ret;
+    DecodedCert cert;
+    Signer*     signer = 0;
+
+    InitDecodedCert(&cert, der.buffer, ctx->heap);
+    ret = ParseCert(&cert, der.length, CA_TYPE, ctx->verifyPeer, 0);
+
+    if (ret == 0) {
+        /* take over signer parts */
+        signer = MakeSigner(ctx->heap);
+        if (!signer)
+            ret = MEMORY_ERROR;
+        else {
+            signer->keyOID     = cert.keyOID;
+            signer->publicKey  = cert.publicKey;
+            signer->pubKeySize = cert.pubKeySize;
+            signer->name = cert.subjectCN;
+            XMEMCPY(signer->hash, cert.subjectHash, SHA_DIGEST_SIZE);
+
+            cert.publicKey = 0;  /* don't free here */
+            cert.subjectCN = 0;
+
+            signer->next = ctx->caList;
+            ctx->caList  = signer;   /* takes ownership */
+        }
+    }
+
+    FreeDecodedCert(&cert);
+    XFREE(der.buffer, ctx->heap, DYNAMIC_TYPE_CA);
+
+    if (ret == 0) return SSL_SUCCESS;
+    return ret;
+}
+
+
+#ifndef NO_SESSION_CACHE
+
+    /* basic config gives a cache with 33 sessions, adequate for clients and
+       embedded servers
+
+       BIG_SESSION_CACHE allows 1055 sessions, adequate for servers that aren't
+       under heavy load, basically allows 200 new sessions per minute
+
+       HUGE_SESSION_CACHE yields 65,791 sessions, for servers under heavy load,
+       allows over 13,000 new sessions per minute or over 200 new sessions per
+       second
+    */
+    #ifdef HUGE_SESSION_CACHE
+        #define SESSIONS_PER_ROW 11
+        #define SESSION_ROWS 5981
+    #elif defined(BIG_SESSION_CACHE)
+        #define SESSIONS_PER_ROW 5
+        #define SESSION_ROWS 211
+    #else
+        #define SESSIONS_PER_ROW 3
+        #define SESSION_ROWS 11
+    #endif
+
+    typedef struct SessionRow {
+        int nextIdx;                           /* where to place next one   */
+        int totalCount;                        /* sessions ever on this row */
+        SSL_SESSION Sessions[SESSIONS_PER_ROW];
+    } SessionRow;
+
+    static SessionRow SessionCache[SESSION_ROWS];
+
+    static CyaSSL_Mutex mutex;   /* SessionCache mutex */
+
+#endif /* NO_SESSION_CACHE */
+
+
+    static int PemToDer(const unsigned char* buff, long sz, int type,
+                      buffer* der, void* heap, EncryptedInfo* info, int* eccKey)
+    {
+        char  header[PEM_LINE_LEN];
+        char  footer[PEM_LINE_LEN];
+        char* headerEnd;
+        char* footerEnd;
+        long  neededSz;
+        int   pkcs8 = 0;
+        int   dynamicType;
+
+        if (type == CERT_TYPE || type == CA_TYPE)  {
+            XSTRNCPY(header, "-----BEGIN CERTIFICATE-----", sizeof(header));
+            XSTRNCPY(footer, "-----END CERTIFICATE-----", sizeof(footer));
+            dynamicType = (type == CA_TYPE) ? DYNAMIC_TYPE_CA :
+                                              DYNAMIC_TYPE_CERT;
+        } else {
+            XSTRNCPY(header, "-----BEGIN RSA PRIVATE KEY-----", sizeof(header));
+            XSTRNCPY(footer, "-----END RSA PRIVATE KEY-----", sizeof(footer));
+            dynamicType = DYNAMIC_TYPE_KEY;
+        }
+
+        /* find header */
+        headerEnd = XSTRSTR((char*)buff, header);
+        if (!headerEnd && type == PRIVATEKEY_TYPE) {  /* may be pkcs8 */
+            XSTRNCPY(header, "-----BEGIN PRIVATE KEY-----", sizeof(header));
+            XSTRNCPY(footer, "-----END PRIVATE KEY-----", sizeof(footer));
+        
+            headerEnd = XSTRSTR((char*)buff, header);
+            if (headerEnd)
+                pkcs8 = 1;
+            /*
+            else
+                maybe encrypted "-----BEGIN ENCRYPTED PRIVATE KEY-----"
+            */
+        }
+        if (!headerEnd && type == PRIVATEKEY_TYPE) {  /* may be ecc */
+            XSTRNCPY(header, "-----BEGIN EC PRIVATE KEY-----", sizeof(header));
+            XSTRNCPY(footer, "-----END EC PRIVATE KEY-----", sizeof(footer));
+        
+            headerEnd = XSTRSTR((char*)buff, header);
+            if (headerEnd)
+                *eccKey = 1;
+        }
+        if (!headerEnd)
+            return SSL_BAD_FILE;
+        headerEnd += XSTRLEN(header);
+
+        /* get next line */
+        if (headerEnd[0] == '\n')
+            headerEnd++;
+        else if (headerEnd[1] == '\n')
+            headerEnd += 2;
+        else
+            return SSL_BAD_FILE;
+
+#ifdef OPENSSL_EXTRA
+    {
+        /* remove encrypted header if there */
+        char encHeader[] = "Proc-Type";
+        char* line = XSTRSTR((char*)buff, encHeader);
+        if (line) {
+            char* newline;
+            char* finish;
+            char* start  = XSTRSTR(line, "DES");
+    
+            if (!start)
+                start = XSTRSTR(line, "AES");
+            
+            if (!start) return SSL_BAD_FILE;
+            if (!info)  return SSL_BAD_FILE;
+            
+            finish = XSTRSTR(start, ",");
+
+            if (start && finish && (start < finish)) {
+                newline = XSTRSTR(finish, "\r");
+
+                XMEMCPY(info->name, start, finish - start);
+                info->name[finish - start] = 0;
+                XMEMCPY(info->iv, finish + 1, sizeof(info->iv));
+
+                if (!newline) newline = XSTRSTR(finish, "\n");
+                if (newline && (newline > finish)) {
+                    info->ivSz = (word32)(newline - (finish + 1));
+                    info->set = 1;
+                }
+                else
+                    return SSL_BAD_FILE;
+            }
+            else
+                return SSL_BAD_FILE;
+
+            /* eat blank line */
+            while (*newline == '\r' || *newline == '\n')
+                newline++;
+            headerEnd = newline;
+        }
+    }
+#endif /* OPENSSL_EXTRA */
+
+        /* find footer */
+        footerEnd = XSTRSTR((char*)buff, footer);
+        if (!footerEnd) return SSL_BAD_FILE;
+
+        /* set up der buffer */
+        neededSz = (long)(footerEnd - headerEnd);
+        if (neededSz > sz || neededSz < 0) return SSL_BAD_FILE;
+        der->buffer = (byte*) XMALLOC(neededSz, heap, dynamicType);
+        if (!der->buffer) return MEMORY_ERROR;
+        der->length = neededSz;
+
+        if (Base64Decode((byte*)headerEnd, neededSz, der->buffer,
+                         &der->length) < 0)
+            return SSL_BAD_FILE;
+
+        if (pkcs8)
+            return ToTraditional(der->buffer, der->length);
+
+        /* not full support yet 
+         if (pkcs8Enc)
+            return ToTraditionalEnc(der->buffer, der->length);
+        */
+
+        return 0;
+    }
+
+
+    static int ProcessBuffer(SSL_CTX* ctx, const unsigned char* buff,
+                             long sz, int format, int type)
+    {
+        EncryptedInfo info;
+        buffer        der;        /* holds DER or RAW (for NTRU) */
+        int           dynamicType;
+        int           eccKey = 0;
+
+        info.set   = 0;
+        der.buffer = 0;
+
+        if (format != SSL_FILETYPE_ASN1 && format != SSL_FILETYPE_PEM 
+                                        && format != SSL_FILETYPE_RAW)
+            return SSL_BAD_FILETYPE;
+
+        if (type == CA_TYPE)
+            dynamicType = DYNAMIC_TYPE_CA;
+        else if (type == CERT_TYPE)
+            dynamicType = DYNAMIC_TYPE_CERT;
+        else
+            dynamicType = DYNAMIC_TYPE_KEY;
+
+        if (format == SSL_FILETYPE_PEM) {
+            if (PemToDer(buff, sz, type, &der, ctx->heap, &info, &eccKey) < 0) {
+                XFREE(der.buffer, ctx->heap, dynamicType);
+                return SSL_BAD_FILE;
+            }
+        }
+        else {  /* ASN1 (DER) or RAW (NTRU) */
+            der.buffer = (byte*) XMALLOC(sz, ctx->heap, dynamicType);
+            if (!der.buffer) return MEMORY_ERROR;
+            XMEMCPY(der.buffer, buff, sz);
+            der.length = sz;
+        }
+
+#ifdef OPENSSL_EXTRA
+        if (info.set) {
+            /* decrypt */
+            char password[80];
+            int  passwordSz;
+
+            byte key[AES_256_KEY_SIZE];
+            byte  iv[AES_IV_SIZE];
+
+            if (!ctx->passwd_cb) return -1;
+
+            /* use file's salt for key derivation, hex decode first */
+            if (Base16Decode(info.iv, info.ivSz, info.iv, &info.ivSz) != 0)
+                return -1;
+
+            passwordSz = ctx->passwd_cb(password, sizeof(password), 0,
+                                    ctx->userdata);
+            if (EVP_BytesToKey(info.name, "MD5", info.iv, (byte*)password,
+                               passwordSz, 1, key, iv) <= 0)
+                return -1;
+
+            if (XSTRNCMP(info.name, "DES-CBC", 7) == 0) {
+                Des des;
+                Des_SetKey(&des, key, info.iv, DES_DECRYPTION);
+                Des_CbcDecrypt(&des, der.buffer, der.buffer, der.length);
+            }
+            else if (XSTRNCMP(info.name, "DES-EDE3-CBC", 13) == 0) {
+                Des3 des;
+                Des3_SetKey(&des, key, info.iv, DES_DECRYPTION);
+                Des3_CbcDecrypt(&des, der.buffer, der.buffer, der.length);
+            }
+            else if (XSTRNCMP(info.name, "AES-128-CBC", 13) == 0) {
+                Aes aes;
+                AesSetKey(&aes, key, AES_128_KEY_SIZE, info.iv, AES_DECRYPTION);
+                AesCbcDecrypt(&aes, der.buffer, der.buffer, der.length);
+            }
+            else if (XSTRNCMP(info.name, "AES-192-CBC", 13) == 0) {
+                Aes aes;
+                AesSetKey(&aes, key, AES_192_KEY_SIZE, info.iv, AES_DECRYPTION);
+                AesCbcDecrypt(&aes, der.buffer, der.buffer, der.length);
+            }
+            else if (XSTRNCMP(info.name, "AES-256-CBC", 13) == 0) {
+                Aes aes;
+                AesSetKey(&aes, key, AES_256_KEY_SIZE, info.iv, AES_DECRYPTION);
+                AesCbcDecrypt(&aes, der.buffer, der.buffer, der.length);
+            }
+            else 
+                return SSL_BAD_FILE;
+        }
+#endif /* OPENSSL_EXTRA */
+
+        if (type == CA_TYPE)
+            return AddCA(ctx, der);     /* takes der over */
+        else if (type == CERT_TYPE) {
+            if (ctx->certificate.buffer)
+                XFREE(ctx->certificate.buffer, ctx->heap, dynamicType);
+            ctx->certificate = der;     /* takes der over */
+        }
+        else if (type == PRIVATEKEY_TYPE) {
+            if (ctx->privateKey.buffer)
+                XFREE(ctx->privateKey.buffer, ctx->heap, dynamicType);
+            ctx->privateKey = der;      /* takes der over */
+        }
+        else {
+            XFREE(der.buffer, ctx->heap, dynamicType);
+            return SSL_BAD_CERTTYPE;
+        }
+
+        if (type == PRIVATEKEY_TYPE && format != SSL_FILETYPE_RAW) {
+            if (!eccKey) { 
+                /* make sure RSA key can be used */
+                RsaKey key;
+                word32 idx = 0;
+        
+                InitRsaKey(&key, 0);
+                if (RsaPrivateKeyDecode(der.buffer,&idx,&key,der.length) != 0) {
+#ifdef HAVE_ECC  
+                    /* could have DER ECC, no easy way to tell */
+                    if (format == SSL_FILETYPE_ASN1)
+                        eccKey = 1;  /* try it out */
+#endif
+                    if (!eccKey) {
+                        FreeRsaKey(&key);
+                        return SSL_BAD_FILE;
+                    }
+                }
+                FreeRsaKey(&key);
+            }
+#ifdef HAVE_ECC  
+            if (eccKey ) {
+                /* make sure ECC key can be used */
+                word32  idx = 0;
+                ecc_key key;
+
+                ecc_init(&key);
+                if (EccPrivateKeyDecode(der.buffer,&idx,&key,der.length) != 0) {
+                    ecc_free(&key);
+                    return SSL_BAD_FILE;
+                }
+                ecc_free(&key);
+                ctx->haveECDSA = 1;
+            }
+#endif /* HAVE_ECC */
+        }
+
+        return SSL_SUCCESS;
+    }
+
+
+#ifndef NO_FILESYSTEM
+
+#ifndef MICRIUM
+    #define XFILE      FILE
+    #define XFOPEN     fopen 
+    #define XFSEEK     fseek
+    #define XFTELL     ftell
+    #define XREWIND    rewind
+    #define XFREAD     fread
+    #define XFCLOSE    fclose
+    #define XSEEK_END  SEEK_END
+#else
+    #include 
+    #define XFILE      FS_FILE
+    #define XFOPEN     fs_fopen 
+    #define XFSEEK     fs_fseek
+    #define XFTELL     fs_ftell
+    #define XREWIND    fs_rewind
+    #define XFREAD     fs_fread
+    #define XFCLOSE    fs_fclose
+    #define XSEEK_END  FS_SEEK_END
+#endif
+
+static int ProcessFile(SSL_CTX* ctx, const char* fname, int format, int type)
+{
+    byte   staticBuffer[FILE_BUFFER_SIZE];
+    byte*  buffer = staticBuffer;
+    int    dynamic = 0;
+    int    ret;
+    long   sz = 0;
+    XFILE* file = XFOPEN(fname, "rb"); 
+
+    if (!file) return SSL_BAD_FILE;
+    XFSEEK(file, 0, XSEEK_END);
+    sz = XFTELL(file);
+    XREWIND(file);
+
+    if (sz > sizeof(staticBuffer)) {
+        buffer = (byte*) XMALLOC(sz, ctx->heap, DYNAMIC_TYPE_FILE);
+        if (buffer == NULL) {
+            XFCLOSE(file);
+            return SSL_BAD_FILE;
+        }
+        dynamic = 1;
+    }
+
+    if ( (ret = XFREAD(buffer, sz, 1, file)) < 0)
+        ret = SSL_BAD_FILE;
+    else
+        ret = ProcessBuffer(ctx, buffer, sz, format, type);
+
+    XFCLOSE(file);
+    if (dynamic) XFREE(buffer, ctx->heap, DYNAMIC_TYPE_FILE);
+
+    return ret;
+}
+
+
+/* just one for now TODO: add dir support from path */
+int SSL_CTX_load_verify_locations(SSL_CTX* ctx, const char* file,
+                                  const char* path)
+{
+    if (ProcessFile(ctx, file, SSL_FILETYPE_PEM, CA_TYPE) == SSL_SUCCESS)
+        return SSL_SUCCESS;
+
+    return SSL_FAILURE;
+}
+
+
+#ifdef CYASSL_DER_LOAD
+
+/* Add format parameter to allow DER load of CA files */
+int CyaSSL_CTX_load_verify_locations(SSL_CTX* ctx, const char* file, int format)
+{
+    if (ProcessFile(ctx, file, format, CA_TYPE) == SSL_SUCCESS)
+        return SSL_SUCCESS;
+
+    return SSL_FAILURE;
+}
+
+#endif /* CYASSL_DER_LOAD */
+
+
+#ifdef CYASSL_CERT_GEN
+
+/* load pem cert from file into der buffer, return der size or error */
+int CyaSSL_PemCertToDer(const char* fileName, unsigned char* derBuf, int derSz) 
+{
+    byte   staticBuffer[FILE_BUFFER_SIZE];
+    byte*  fileBuf = staticBuffer;
+    int    dynamic = 0;
+    int    ret;
+    int    ecc = 0;
+    long   sz = 0;
+    XFILE* file = XFOPEN(fileName, "rb"); 
+    EncryptedInfo info;
+    buffer        converted;
+
+    converted.buffer = 0;
+
+    if (!file) return SSL_BAD_FILE;
+    XFSEEK(file, 0, XSEEK_END);
+    sz = XFTELL(file);
+    XREWIND(file);
+
+    if (sz > sizeof(staticBuffer)) {
+        fileBuf = (byte*) XMALLOC(sz, 0, DYNAMIC_TYPE_FILE);
+        if (fileBuf == NULL) {
+            XFCLOSE(file);
+            return SSL_BAD_FILE;
+        }
+        dynamic = 1;
+    }
+
+    if ( (ret = XFREAD(fileBuf, sz, 1, file)) < 0)
+        ret = SSL_BAD_FILE;
+    else
+        ret = PemToDer(fileBuf, sz, CA_TYPE, &converted, 0, &info, &ecc);
+
+    if (ret == 0) {
+        if (converted.length < derSz) {
+            memcpy(derBuf, converted.buffer, converted.length);
+            ret = converted.length;
+        }
+        else
+            ret = BUFFER_E;
+    }       
+
+    XFREE(converted.buffer, 0, DYNAMIC_TYPE_CA); 
+    if (dynamic)
+        XFREE(fileBuf, 0, DYNAMIC_TYPE_FILE); 
+    XFCLOSE(file);
+
+    return ret;
+}
+
+#endif /* CYASSL_CERT_GEN */
+
+
+int SSL_CTX_use_certificate_file(SSL_CTX* ctx, const char* file, int format)
+{
+    if (ProcessFile(ctx, file, format, CERT_TYPE) == SSL_SUCCESS)
+        return SSL_SUCCESS;
+
+    return SSL_FAILURE;
+}
+
+
+int SSL_CTX_use_PrivateKey_file(SSL_CTX* ctx, const char* file, int format)
+{
+    if (ProcessFile(ctx, file, format, PRIVATEKEY_TYPE) == SSL_SUCCESS)
+        return SSL_SUCCESS;
+
+    return SSL_FAILURE;
+}
+
+
+int SSL_CTX_use_certificate_chain_file(SSL_CTX* ctx, const char* file)
+{
+    /* add first to ctx, all tested implementations support this */
+   if (ProcessFile(ctx, file, SSL_FILETYPE_PEM, CERT_TYPE) == SSL_SUCCESS)
+       return SSL_SUCCESS;
+
+   return SSL_FAILURE;
+}
+
+
+#ifdef HAVE_NTRU
+
+int CyaSSL_CTX_use_NTRUPrivateKey_file(SSL_CTX* ctx, const char* file)
+{
+    if (ProcessFile(ctx, file, SSL_FILETYPE_RAW, PRIVATEKEY_TYPE)
+                         == SSL_SUCCESS) {
+        ctx->haveNTRU = 1;
+        return SSL_SUCCESS;
+    }
+
+    return SSL_FAILURE;
+}
+
+#endif /* HAVE_NTRU */
+
+
+
+#ifdef OPENSSL_EXTRA
+
+    int SSL_CTX_use_RSAPrivateKey_file(SSL_CTX* ctx,const char* file,int format)
+    {
+        if (ProcessFile(ctx, file, format, PRIVATEKEY_TYPE) == SSL_SUCCESS)
+            return SSL_SUCCESS;
+
+        return SSL_FAILURE;
+    }
+
+#endif /* OPENSSL_EXTRA */
+
+#endif /* NO_FILESYSTEM */
+
+
+void SSL_CTX_set_verify(SSL_CTX* ctx, int mode, VerifyCallback vc)
+{
+    if (mode & SSL_VERIFY_PEER) {
+        ctx->verifyPeer = 1;
+        ctx->verifyNone = 0;  /* in case perviously set */
+    }
+
+    if (mode == SSL_VERIFY_NONE) {
+        ctx->verifyNone = 1;
+        ctx->verifyPeer = 0;  /* in case previously set */
+    }
+
+    if (mode & SSL_VERIFY_FAIL_IF_NO_PEER_CERT)
+        ctx->failNoCert = 1;
+
+    ctx->verifyCallback = vc;
+}
+
+
+#ifndef NO_SESSION_CACHE
+
+SSL_SESSION* SSL_get_session(SSL* ssl)
+{
+    return GetSession(ssl, 0);
+}
+
+
+int SSL_set_session(SSL* ssl, SSL_SESSION* session)
+{
+    if (session)
+        return SetSession(ssl, session);
+
+    return SSL_FAILURE;
+}
+
+#endif /* NO_SESSION_CACHE */
+
+
+void SSL_load_error_strings(void)   /* compatibility only */
+{}
+
+
+int SSL_library_init(void)
+{
+    if (InitCyaSSL() == 0)
+        return SSL_SUCCESS;
+    else
+        return -1;
+}
+
+
+#ifndef NO_SESSION_CACHE
+
+/* on by default if built in but allow user to turn off */
+long SSL_CTX_set_session_cache_mode(SSL_CTX* ctx, long mode)
+{
+    if (mode == SSL_SESS_CACHE_OFF)
+        ctx->sessionCacheOff = 1;
+
+    if (mode == SSL_SESS_CACHE_NO_AUTO_CLEAR)
+        ctx->sessionCacheFlushOff = 1;
+
+    return SSL_SUCCESS;
+}
+
+#endif /* NO_SESSION_CACHE */
+
+
+int SSL_CTX_set_cipher_list(SSL_CTX* ctx, const char* list)
+{
+    if (SetCipherList(ctx, list))
+        return SSL_SUCCESS;
+    else
+        return SSL_FAILURE;
+}
+
+
+/* client only parts */
+#ifndef NO_CYASSL_CLIENT
+
+    SSL_METHOD* SSLv3_client_method(void)
+    {
+        SSL_METHOD* method = (SSL_METHOD*) XMALLOC(sizeof(SSL_METHOD), 0,
+                                                   DYNAMIC_TYPE_METHOD);
+        if (method)
+            InitSSL_Method(method, MakeSSLv3());
+        return method;
+    }
+
+    #ifdef CYASSL_DTLS
+        SSL_METHOD* DTLSv1_client_method(void)
+        {
+            SSL_METHOD* method = (SSL_METHOD*) XMALLOC(sizeof(SSL_METHOD), 0,
+                                                       DYNAMIC_TYPE_METHOD);
+            if (method)
+                InitSSL_Method(method, MakeDTLSv1());
+            return method;
+        }
+    #endif
+
+
+    /* please see note at top of README if you get an error from connect */
+    int SSL_connect(SSL* ssl)
+    {
+        int neededState;
+
+        CYASSL_ENTER("SSL_connect()");
+
+        #ifdef HAVE_ERRNO_H 
+            errno = 0;
+        #endif
+
+        if (ssl->options.side != CLIENT_END) {
+            CYASSL_ERROR(ssl->error = SIDE_ERROR);
+            return SSL_FATAL_ERROR;
+        }
+
+        #ifdef CYASSL_DTLS
+            if (ssl->version.major == DTLS_MAJOR && 
+                                      ssl->version.minor == DTLS_MINOR) {
+                ssl->options.dtls   = 1;
+                ssl->options.tls    = 1;
+                ssl->options.tls1_1 = 1;
+            }
+        #endif
+
+        if (ssl->buffers.outputBuffer.length > 0) {
+            if ( (ssl->error = SendBuffered(ssl)) == 0) {
+                ssl->options.connectState++;
+                CYASSL_MSG("connect state: Advanced from buffered send");
+            }
+            else {
+                CYASSL_ERROR(ssl->error);
+                return SSL_FATAL_ERROR;
+            }
+        }
+
+        switch (ssl->options.connectState) {
+
+        case CONNECT_BEGIN :
+            /* always send client hello first */
+            if ( (ssl->error = SendClientHello(ssl)) != 0) {
+                CYASSL_ERROR(ssl->error);
+                return SSL_FATAL_ERROR;
+            }
+            ssl->options.connectState = CLIENT_HELLO_SENT;
+            CYASSL_MSG("connect state: CLIENT_HELLO_SENT");
+
+        case CLIENT_HELLO_SENT :
+            neededState = ssl->options.resuming ? SERVER_FINISHED_COMPLETE :
+                                          SERVER_HELLODONE_COMPLETE;
+            #ifdef CYASSL_DTLS
+                if (ssl->options.dtls && !ssl->options.resuming)
+                    neededState = SERVER_HELLOVERIFYREQUEST_COMPLETE;
+            #endif
+            /* get response */
+            while (ssl->options.serverState < neededState) {
+                if ( (ssl->error = ProcessReply(ssl)) < 0) {
+                    CYASSL_ERROR(ssl->error);
+                    return SSL_FATAL_ERROR;
+                }
+                /* if resumption failed, reset needed state */
+                else if (neededState == SERVER_FINISHED_COMPLETE)
+                    if (!ssl->options.resuming) {
+                        if (!ssl->options.dtls)
+                            neededState = SERVER_HELLODONE_COMPLETE;
+                        else
+                            neededState = SERVER_HELLOVERIFYREQUEST_COMPLETE;
+                    }
+            }
+
+            ssl->options.connectState = HELLO_AGAIN;
+            CYASSL_MSG("connect state: HELLO_AGAIN");
+
+        case HELLO_AGAIN :
+            #ifdef CYASSL_DTLS
+                if (ssl->options.dtls && !ssl->options.resuming) {
+                    /* re-init hashes, exclude first hello and verify request */
+                    InitMd5(&ssl->hashMd5);
+                    InitSha(&ssl->hashSha);
+                    if ( (ssl->error = SendClientHello(ssl)) != 0) {
+                        CYASSL_ERROR(ssl->error);
+                        return SSL_FATAL_ERROR;
+                    }
+                }
+            #endif
+
+            ssl->options.connectState = HELLO_AGAIN_REPLY;
+            CYASSL_MSG("connect state: HELLO_AGAIN_REPLY");
+
+        case HELLO_AGAIN_REPLY :
+            #ifdef CYASSL_DTLS
+                if (ssl->options.dtls) {
+                    neededState = ssl->options.resuming ?
+                           SERVER_FINISHED_COMPLETE : SERVER_HELLODONE_COMPLETE;
+            
+                    /* get response */
+                    while (ssl->options.serverState < neededState) {
+                        if ( (ssl->error = ProcessReply(ssl)) < 0) {
+                                CYASSL_ERROR(ssl->error);
+                                return SSL_FATAL_ERROR;
+                        }
+                        /* if resumption failed, reset needed state */
+                        else if (neededState == SERVER_FINISHED_COMPLETE)
+                            if (!ssl->options.resuming)
+                                neededState = SERVER_HELLODONE_COMPLETE;
+                    }
+                }
+            #endif
+
+            ssl->options.connectState = FIRST_REPLY_DONE;
+            CYASSL_MSG("connect state: FIRST_REPLY_DONE");
+
+        case FIRST_REPLY_DONE :
+            if (ssl->options.sendVerify)
+                if ( (ssl->error = SendCertificate(ssl)) != 0) {
+                    CYASSL_ERROR(ssl->error);
+                    return SSL_FATAL_ERROR;
+                }
+
+            ssl->options.connectState = FIRST_REPLY_FIRST;
+            CYASSL_MSG("connect state: FIRST_REPLY_FIRST");
+
+        case FIRST_REPLY_FIRST :
+            if (!ssl->options.resuming)
+                if ( (ssl->error = SendClientKeyExchange(ssl)) != 0) {
+                    CYASSL_ERROR(ssl->error);
+                    return SSL_FATAL_ERROR;
+                }
+
+            ssl->options.connectState = FIRST_REPLY_SECOND;
+            CYASSL_MSG("connect state: FIRST_REPLY_SECOND");
+
+        case FIRST_REPLY_SECOND :
+            if (ssl->options.sendVerify)
+                if ( (ssl->error = SendCertificateVerify(ssl)) != 0) {
+                    CYASSL_ERROR(ssl->error);
+                    return SSL_FATAL_ERROR;
+            }
+            ssl->options.connectState = FIRST_REPLY_THIRD;
+            CYASSL_MSG("connect state: FIRST_REPLY_THIRD");
+
+        case FIRST_REPLY_THIRD :
+            if ( (ssl->error = SendChangeCipher(ssl)) != 0) {
+                CYASSL_ERROR(ssl->error);
+                return SSL_FATAL_ERROR;
+            }
+            ssl->options.connectState = FIRST_REPLY_FOURTH;
+            CYASSL_MSG("connect state: FIRST_REPLY_FOURTH");
+
+        case FIRST_REPLY_FOURTH :
+            if ( (ssl->error = SendFinished(ssl)) != 0) {
+                CYASSL_ERROR(ssl->error);
+                return SSL_FATAL_ERROR;
+            }
+
+            ssl->options.connectState = FINISHED_DONE;
+            CYASSL_MSG("connect state: FINISHED_DONE");
+
+        case FINISHED_DONE :
+            /* get response */
+            while (ssl->options.serverState < SERVER_FINISHED_COMPLETE)
+                if ( (ssl->error = ProcessReply(ssl)) < 0) {
+                    CYASSL_ERROR(ssl->error);
+                    return SSL_FATAL_ERROR;
+                }
+          
+            ssl->options.connectState = SECOND_REPLY_DONE;
+            CYASSL_MSG("connect state: SECOND_REPLY_DONE");
+
+        case SECOND_REPLY_DONE:
+            if (ssl->buffers.inputBuffer.dynamicFlag)
+                ShrinkInputBuffer(ssl, NO_FORCED_FREE);
+            CYASSL_LEAVE("SSL_connect()", SSL_SUCCESS);
+            return SSL_SUCCESS;
+
+        default:
+            CYASSL_MSG("Unknown connect state ERROR");
+            return SSL_FATAL_ERROR; /* unknown connect state */
+        }
+    }
+
+#endif /* NO_CYASSL_CLIENT */
+
+
+/* server only parts */
+#ifndef NO_CYASSL_SERVER
+
+    SSL_METHOD* SSLv3_server_method(void)
+    {
+        SSL_METHOD* method = (SSL_METHOD*) XMALLOC(sizeof(SSL_METHOD), 0,
+                                                   DYNAMIC_TYPE_METHOD);
+        if (method) {
+            InitSSL_Method(method, MakeSSLv3());
+            method->side = SERVER_END;
+        }
+        return method;
+    }
+
+
+    #ifdef CYASSL_DTLS
+        SSL_METHOD* DTLSv1_server_method(void)
+        {
+            SSL_METHOD* method = (SSL_METHOD*) XMALLOC(sizeof(SSL_METHOD), 0,
+                                                       DYNAMIC_TYPE_METHOD);
+            if (method) {
+                InitSSL_Method(method, MakeDTLSv1());
+                method->side = SERVER_END;
+            }
+            return method;
+        }
+    #endif
+
+
+    int SSL_accept(SSL* ssl)
+    {
+        CYASSL_ENTER("SSL_accept()");
+
+        #ifdef HAVE_ERRNO_H 
+            errno = 0;
+        #endif
+
+        if (ssl->options.side != SERVER_END) {
+            CYASSL_ERROR(ssl->error = SIDE_ERROR);
+            return SSL_FATAL_ERROR;
+        }
+
+        #ifdef CYASSL_DTLS
+            if (ssl->version.major == DTLS_MAJOR &&
+                                      ssl->version.minor == DTLS_MINOR) {
+                ssl->options.dtls   = 1;
+                ssl->options.tls    = 1;
+                ssl->options.tls1_1 = 1;
+            }
+        #endif
+
+        if (ssl->buffers.outputBuffer.length > 0) {
+            if ( (ssl->error = SendBuffered(ssl)) == 0) {
+                ssl->options.acceptState++;
+                CYASSL_MSG("accept state: Advanced from buffered send");
+            }
+            else {
+                CYASSL_ERROR(ssl->error);
+                return SSL_FATAL_ERROR;
+            }
+        }
+
+        switch (ssl->options.acceptState) {
+    
+        case ACCEPT_BEGIN :
+            /* get response */
+            while (ssl->options.clientState < CLIENT_HELLO_COMPLETE)
+                if ( (ssl->error = ProcessReply(ssl)) < 0) {
+                    CYASSL_ERROR(ssl->error);
+                    return SSL_FATAL_ERROR;
+                }
+            ssl->options.acceptState = ACCEPT_CLIENT_HELLO_DONE;
+            CYASSL_MSG("accept state ACCEPT_CLIENT_HELLO_DONE");
+
+        case ACCEPT_CLIENT_HELLO_DONE :
+            #ifdef CYASSL_DTLS
+                if (ssl->options.dtls && !ssl->options.resuming)
+                    if ( (ssl->error = SendHelloVerifyRequest(ssl)) != 0) {
+                        CYASSL_ERROR(ssl->error);
+                        return SSL_FATAL_ERROR;
+                    }
+            #endif
+            ssl->options.acceptState = HELLO_VERIFY_SENT;
+            CYASSL_MSG("accept state HELLO_VERIFY_SENT");
+
+        case HELLO_VERIFY_SENT:
+            #ifdef CYASSL_DTLS
+                if (ssl->options.dtls && !ssl->options.resuming) {
+                    ssl->options.clientState = NULL_STATE;  /* get again */
+                    /* re-init hashes, exclude first hello and verify request */
+                    InitMd5(&ssl->hashMd5);
+                    InitSha(&ssl->hashSha);
+
+                    while (ssl->options.clientState < CLIENT_HELLO_COMPLETE)
+                        if ( (ssl->error = ProcessReply(ssl)) < 0) {
+                            CYASSL_ERROR(ssl->error);
+                            return SSL_FATAL_ERROR;
+                        }
+                }
+            #endif
+            ssl->options.acceptState = ACCEPT_FIRST_REPLY_DONE;
+            CYASSL_MSG("accept state ACCEPT_FIRST_REPLY_DONE");
+
+        case ACCEPT_FIRST_REPLY_DONE :
+            if ( (ssl->error = SendServerHello(ssl)) != 0) {
+                CYASSL_ERROR(ssl->error);
+                return SSL_FATAL_ERROR;
+            }
+            ssl->options.acceptState = SERVER_HELLO_SENT;
+            CYASSL_MSG("accept state SERVER_HELLO_SENT");
+
+        case SERVER_HELLO_SENT :
+            if (!ssl->options.resuming) 
+                if ( (ssl->error = SendCertificate(ssl)) != 0) {
+                    CYASSL_ERROR(ssl->error);
+                    return SSL_FATAL_ERROR;
+                }
+            ssl->options.acceptState = CERT_SENT;
+            CYASSL_MSG("accept state CERT_SENT");
+
+        case CERT_SENT :
+            if (!ssl->options.resuming) 
+                if ( (ssl->error = SendServerKeyExchange(ssl)) != 0) {
+                    CYASSL_ERROR(ssl->error);
+                    return SSL_FATAL_ERROR;
+                }
+            ssl->options.acceptState = KEY_EXCHANGE_SENT;
+            CYASSL_MSG("accept state KEY_EXCHANGE_SENT");
+
+        case KEY_EXCHANGE_SENT :
+            if (!ssl->options.resuming) 
+                if (ssl->options.verifyPeer)
+                    if ( (ssl->error = SendCertificateRequest(ssl)) != 0) {
+                        CYASSL_ERROR(ssl->error);
+                        return SSL_FATAL_ERROR;
+                    }
+            ssl->options.acceptState = CERT_REQ_SENT;
+            CYASSL_MSG("accept state CERT_REQ_SENT");
+
+        case CERT_REQ_SENT :
+            if (!ssl->options.resuming) 
+                if ( (ssl->error = SendServerHelloDone(ssl)) != 0) {
+                    CYASSL_ERROR(ssl->error);
+                    return SSL_FATAL_ERROR;
+                }
+            ssl->options.acceptState = SERVER_HELLO_DONE;
+            CYASSL_MSG("accept state SERVER_HELLO_DONE");
+
+        case SERVER_HELLO_DONE :
+            if (!ssl->options.resuming) {
+                while (ssl->options.clientState < CLIENT_FINISHED_COMPLETE)
+                    if ( (ssl->error = ProcessReply(ssl)) < 0) {
+                        CYASSL_ERROR(ssl->error);
+                        return SSL_FATAL_ERROR;
+                    }
+            }
+            ssl->options.acceptState = ACCEPT_SECOND_REPLY_DONE;
+            CYASSL_MSG("accept state  ACCEPT_SECOND_REPLY_DONE");
+          
+        case ACCEPT_SECOND_REPLY_DONE : 
+            if ( (ssl->error = SendChangeCipher(ssl)) != 0) {
+                CYASSL_ERROR(ssl->error);
+                return SSL_FATAL_ERROR;
+            }
+            ssl->options.acceptState = CHANGE_CIPHER_SENT;
+            CYASSL_MSG("accept state  CHANGE_CIPHER_SENT");
+
+        case CHANGE_CIPHER_SENT : 
+            if ( (ssl->error = SendFinished(ssl)) != 0) {
+                CYASSL_ERROR(ssl->error);
+                return SSL_FATAL_ERROR;
+            }
+
+            ssl->options.acceptState = ACCEPT_FINISHED_DONE;
+            CYASSL_MSG("accept state ACCEPT_FINISHED_DONE");
+
+        case ACCEPT_FINISHED_DONE :
+            if (ssl->options.resuming)
+                while (ssl->options.clientState < CLIENT_FINISHED_COMPLETE)
+                    if ( (ssl->error = ProcessReply(ssl)) < 0) {
+                        CYASSL_ERROR(ssl->error);
+                        return SSL_FATAL_ERROR;
+                    }
+
+            ssl->options.acceptState = ACCEPT_THIRD_REPLY_DONE;
+            CYASSL_MSG("accept state ACCEPT_THIRD_REPLY_DONE");
+
+        case ACCEPT_THIRD_REPLY_DONE :
+            if (ssl->buffers.inputBuffer.dynamicFlag)
+                ShrinkInputBuffer(ssl, NO_FORCED_FREE);
+            CYASSL_LEAVE("SSL_accept()", SSL_SUCCESS);
+            return SSL_SUCCESS;
+
+        default :
+            CYASSL_MSG("Unknown accept state ERROR");
+            return SSL_FATAL_ERROR;
+        }
+    }
+
+#endif /* NO_CYASSL_SERVER */
+
+
+int InitCyaSSL(void)
+{
+#ifndef NO_SESSION_CACHE
+    if (InitMutex(&mutex) == 0)
+        return 0;
+    else
+        return -1;
+#else
+    return 0;
+#endif
+}
+
+
+int FreeCyaSSL(void)
+{
+#ifndef NO_SESSION_CACHE
+    if (FreeMutex(&mutex) == 0)
+        return 0;
+    else
+        return -1;
+#else
+    return 0;
+#endif
+}
+
+
+#ifndef NO_SESSION_CACHE
+
+
+static INLINE word32 HashSession(const byte* sessionID)
+{
+    /* id is random, just make 32 bit number from first 4 bytes for now */
+    return (sessionID[0] << 24) | (sessionID[1] << 16) | (sessionID[2] <<  8) |
+            sessionID[3];
+}
+
+
+void SSL_flush_sessions(SSL_CTX* ctx, long tm)
+{
+    /* static table now, no flusing needed */
+}
+
+
+SSL_SESSION* GetSession(SSL* ssl, byte* masterSecret)
+{
+    SSL_SESSION* ret = 0;
+    const byte*  id = ssl->arrays.sessionID;
+    word32       row;
+    int          idx;
+    
+    if (ssl->options.sessionCacheOff)
+        return 0;
+
+    row = HashSession(id) % SESSION_ROWS;
+
+    if (LockMutex(&mutex) != 0)
+        return 0;
+   
+    if (SessionCache[row].totalCount >= SESSIONS_PER_ROW)
+        idx = SESSIONS_PER_ROW - 1;
+    else
+        idx = SessionCache[row].nextIdx - 1;
+
+    for (; idx >= 0; idx--) {
+        SSL_SESSION* current;
+        
+        if (idx >= SESSIONS_PER_ROW)    /* server could have restarted, idx  */
+            break;                      /* would be word32(-1) and seg fault */
+        
+        current = &SessionCache[row].Sessions[idx];
+        if (XMEMCMP(current->sessionID, id, ID_LEN) == 0) {
+            if (LowResTimer() < (current->bornOn + current->timeout)) {
+                ret = current;
+                if (masterSecret)
+                    XMEMCPY(masterSecret, current->masterSecret, SECRET_LEN);
+            }
+            break;
+        }   
+    }
+
+    UnLockMutex(&mutex);
+    
+    return ret;
+}
+
+
+int SetSession(SSL* ssl, SSL_SESSION* session)
+{
+    if (ssl->options.sessionCacheOff)
+        return SSL_FAILURE;
+
+    if (LowResTimer() < (session->bornOn + session->timeout)) {
+        ssl->session  = *session;
+        ssl->options.resuming = 1;
+
+#ifdef SESSION_CERTS
+        ssl->version              = session->version;
+        ssl->options.cipherSuite0 = session->cipherSuite0;
+        ssl->options.cipherSuite  = session->cipherSuite;
+#endif
+
+        return SSL_SUCCESS;
+    }
+    return SSL_FAILURE;  /* session timed out */
+}
+
+
+int AddSession(SSL* ssl)
+{
+    word32 row, idx;
+
+    if (ssl->options.sessionCacheOff)
+        return 0;
+
+    row = HashSession(ssl->arrays.sessionID) % SESSION_ROWS;
+
+    if (LockMutex(&mutex) != 0)
+        return -1;
+
+    idx = SessionCache[row].nextIdx++;
+
+    XMEMCPY(SessionCache[row].Sessions[idx].masterSecret,
+           ssl->arrays.masterSecret, SECRET_LEN);
+    XMEMCPY(SessionCache[row].Sessions[idx].sessionID, ssl->arrays.sessionID,
+           ID_LEN);
+
+    SessionCache[row].Sessions[idx].timeout = DEFAULT_TIMEOUT;
+    SessionCache[row].Sessions[idx].bornOn  = LowResTimer();
+
+#ifdef SESSION_CERTS
+    SessionCache[row].Sessions[idx].chain.count = ssl->session.chain.count;
+    XMEMCPY(SessionCache[row].Sessions[idx].chain.certs,
+           ssl->session.chain.certs, sizeof(x509_buffer) * MAX_CHAIN_DEPTH);
+
+    SessionCache[row].Sessions[idx].version      = ssl->version;
+    SessionCache[row].Sessions[idx].cipherSuite0 = ssl->options.cipherSuite0;
+    SessionCache[row].Sessions[idx].cipherSuite  = ssl->options.cipherSuite;
+#endif
+
+    SessionCache[row].totalCount++;
+    if (SessionCache[row].nextIdx == SESSIONS_PER_ROW)
+        SessionCache[row].nextIdx = 0;
+
+    if (UnLockMutex(&mutex) != 0)
+        return -1;
+
+    return 0;
+}
+
+
+    #ifdef SESSION_STATS
+
+    void PrintSessionStats(void)
+    {
+        word32 totalSessionsSeen = 0;
+        word32 totalSessionsNow = 0;
+        word32 rowNow;
+        int    i;
+        double E;               /* expected freq */
+        double chiSquare = 0;
+        
+        for (i = 0; i < SESSION_ROWS; i++) {
+            totalSessionsSeen += SessionCache[i].totalCount;
+
+            if (SessionCache[i].totalCount >= SESSIONS_PER_ROW)
+                rowNow = SESSIONS_PER_ROW;
+            else if (SessionCache[i].nextIdx == 0)
+                rowNow = 0;
+            else
+                rowNow = SessionCache[i].nextIdx;
+        
+            totalSessionsNow += rowNow;
+        }
+
+        printf("Total Sessions Seen = %d\n", totalSessionsSeen);
+        printf("Total Sessions Now  = %d\n", totalSessionsNow);
+
+        E = (double)totalSessionsSeen / SESSION_ROWS;
+
+        for (i = 0; i < SESSION_ROWS; i++) {
+            double diff = SessionCache[i].totalCount - E;
+            diff *= diff;                /* sqaure    */
+            diff /= E;                   /* normalize */
+
+            chiSquare += diff;
+        }
+        printf("  chi-square = %5.1f, d.f. = %d\n", chiSquare,
+                                                     SESSION_ROWS - 1);
+        if (SESSION_ROWS == 11)
+            printf(" .05 p value =  18.3, chi-square should be less\n");
+        else if (SESSION_ROWS == 211)
+            printf(".05 p value  = 244.8, chi-square should be less\n");
+        else if (SESSION_ROWS == 5981)
+            printf(".05 p value  = 6161.0, chi-square should be less\n");
+        printf("\n");
+    }
+
+    #endif /* SESSION_STATS */
+
+#endif /* NO_SESSION_CACHE */
+
+
+/* call before SSL_connect, if verifying will add name check to
+   date check and signature check */
+int CyaSSL_check_domain_name(SSL* ssl, const char* dn)
+{
+    if (ssl->buffers.domainName.buffer)
+        XFREE(ssl->buffers.domainName.buffer, ssl->heap, DYNAMIC_TYPE_DOMAIN);
+
+    ssl->buffers.domainName.length = (word32)XSTRLEN(dn) + 1;
+    ssl->buffers.domainName.buffer = (byte*) XMALLOC(
+                ssl->buffers.domainName.length, ssl->heap, DYNAMIC_TYPE_DOMAIN);
+
+    if (ssl->buffers.domainName.buffer) {
+        XSTRNCPY((char*)ssl->buffers.domainName.buffer, dn,
+                ssl->buffers.domainName.length);
+        return SSL_SUCCESS;
+    }
+    else {
+        ssl->error = MEMORY_ERROR;
+        return SSL_FAILURE;
+    }
+}
+
+
+/* turn on CyaSSL zlib compression
+   returns 0 for success, else error (not built in)
+*/
+int CyaSSL_set_compression(SSL* ssl)
+{
+#ifdef HAVE_LIBZ
+    ssl->options.usingCompression = 1;
+    return 0;
+#else
+    return -1;
+#endif
+}
+
+
+#ifndef USE_WINDOWS_API 
+    #ifndef NO_WRITEV
+
+        /* simulate writev semantics, doesn't actually do block at a time though
+           because of SSL_write behavior and because front adds may be small */
+        int CyaSSL_writev(SSL* ssl, const struct iovec* iov, int iovcnt)
+        {
+            byte  tmp[OUTPUT_RECORD_SIZE];
+            byte* buffer    = tmp;
+            int   send      = 0;
+            int   newBuffer = 0;
+            int   idx       = 0;
+            int   i;
+            int   ret;
+
+            for (i = 0; i < iovcnt; i++)
+                send += iov[i].iov_len;
+
+            if (send > sizeof(tmp)) {
+                byte* tmp2 = (byte*) XMALLOC(send, ssl->heap,
+                                             DYNAMIC_TYPE_WRITEV);
+                if (!tmp2)
+                    return MEMORY_ERROR;
+                buffer = tmp2;
+                newBuffer = 1;
+            }
+
+            for (i = 0; i < iovcnt; i++) {
+                XMEMCPY(&buffer[idx], iov[i].iov_base, iov[i].iov_len);
+                idx += iov[i].iov_len;
+            }
+
+            ret = SSL_write(ssl, buffer, send);
+
+            if (newBuffer) XFREE(buffer, ssl->heap, DYNAMIC_TYPE_WRITEV);
+
+            return ret;
+        }
+    #endif
+#endif
+
+
+#ifdef CYASSL_CALLBACKS
+
+    typedef struct itimerval Itimerval;
+
+    /* don't keep calling simple functions while setting up timer and singals
+       if no inlining these are the next best */
+
+    #define AddTimes(a, b, c)                       \
+        do {                                        \
+            c.tv_sec  = a.tv_sec  + b.tv_sec;       \
+            c.tv_usec = a.tv_usec + b.tv_usec;      \
+            if (c.tv_sec >=  1000000) {             \
+                c.tv_sec++;                         \
+                c.tv_usec -= 1000000;               \
+            }                                       \
+        } while (0)
+
+
+    #define SubtractTimes(a, b, c)                  \
+        do {                                        \
+            c.tv_sec  = a.tv_sec  - b.tv_sec;       \
+            c.tv_usec = a.tv_usec - b.tv_usec;      \
+            if (c.tv_sec < 0) {                     \
+                c.tv_sec--;                         \
+                c.tv_usec += 1000000;               \
+            }                                       \
+        } while (0)
+
+    #define CmpTimes(a, b, cmp)                     \
+        ((a.tv_sec  ==  b.tv_sec) ?                 \
+            (a.tv_usec cmp b.tv_usec) :             \
+            (a.tv_sec  cmp b.tv_sec))               \
+
+
+    /* do nothing handler */
+    static void myHandler(int signo)
+    {
+        return;
+    }
+
+
+    static int CyaSSL_ex_wrapper(SSL* ssl, HandShakeCallBack hsCb,
+                                 TimeoutCallBack toCb, Timeval timeout)
+    {
+        int       ret        = -1;
+        int       oldTimerOn = 0;   /* was timer already on */
+        Timeval   startTime;
+        Timeval   endTime;
+        Timeval   totalTime;
+        Itimerval myTimeout;
+        Itimerval oldTimeout; /* if old timer adjust from total time to reset */
+        struct sigaction act, oact;
+       
+        #define ERR_OUT(x) { ssl->hsInfoOn = 0; ssl->toInfoOn = 0; return x; }
+
+        if (hsCb) {
+            ssl->hsInfoOn = 1;
+            InitHandShakeInfo(&ssl->handShakeInfo);
+        }
+        if (toCb) {
+            ssl->toInfoOn = 1;
+            InitTimeoutInfo(&ssl->timeoutInfo);
+            
+            if (gettimeofday(&startTime, 0) < 0)
+                ERR_OUT(GETTIME_ERROR);
+
+            /* use setitimer to simulate getitimer, init 0 myTimeout */
+            myTimeout.it_interval.tv_sec  = 0;
+            myTimeout.it_interval.tv_usec = 0;
+            myTimeout.it_value.tv_sec     = 0;
+            myTimeout.it_value.tv_usec    = 0;
+            if (setitimer(ITIMER_REAL, &myTimeout, &oldTimeout) < 0)
+                ERR_OUT(SETITIMER_ERROR);
+
+            if (oldTimeout.it_value.tv_sec || oldTimeout.it_value.tv_usec) {
+                oldTimerOn = 1;
+                
+                /* is old timer going to expire before ours */
+                if (CmpTimes(oldTimeout.it_value, timeout, <)) { 
+                    timeout.tv_sec  = oldTimeout.it_value.tv_sec;
+                    timeout.tv_usec = oldTimeout.it_value.tv_usec;
+                }       
+            }
+            myTimeout.it_value.tv_sec  = timeout.tv_sec;
+            myTimeout.it_value.tv_usec = timeout.tv_usec;
+            
+            /* set up signal handler, don't restart socket send/recv */
+            act.sa_handler = myHandler;
+            sigemptyset(&act.sa_mask);
+            act.sa_flags = 0;
+#ifdef SA_INTERRUPT
+            act.sa_flags |= SA_INTERRUPT;
+#endif
+            if (sigaction(SIGALRM, &act, &oact) < 0)
+                ERR_OUT(SIGACT_ERROR);
+
+            if (setitimer(ITIMER_REAL, &myTimeout, 0) < 0)
+                ERR_OUT(SETITIMER_ERROR);
+        }
+
+        /* do main work */
+#ifndef NO_CYASSL_CLIENT
+        if (ssl->options.side == CLIENT_END)
+            ret = SSL_connect(ssl);
+#endif
+#ifndef NO_CYASSL_SERVER
+        if (ssl->options.side == SERVER_END)
+            ret = SSL_accept(ssl);
+#endif
+       
+        /* do callbacks */ 
+        if (toCb) {
+            if (oldTimerOn) {
+                gettimeofday(&endTime, 0);
+                SubtractTimes(endTime, startTime, totalTime);
+                /* adjust old timer for elapsed time */
+                if (CmpTimes(totalTime, oldTimeout.it_value, <))
+                    SubtractTimes(oldTimeout.it_value, totalTime,
+                                  oldTimeout.it_value);
+                else {
+                    /* reset value to interval, may be off */
+                    oldTimeout.it_value.tv_sec = oldTimeout.it_interval.tv_sec;
+                    oldTimeout.it_value.tv_usec =oldTimeout.it_interval.tv_usec;
+                }
+                /* keep iter the same whether there or not */
+            }
+            /* restore old handler */
+            if (sigaction(SIGALRM, &oact, 0) < 0)
+                ret = SIGACT_ERROR;    /* more pressing error, stomp */
+            else
+                /* use old settings which may turn off (expired or not there) */
+                if (setitimer(ITIMER_REAL, &oldTimeout, 0) < 0)
+                    ret = SETITIMER_ERROR;
+            
+            /* if we had a timeout call callback */
+            if (ssl->timeoutInfo.timeoutName[0]) {
+                ssl->timeoutInfo.timeoutValue.tv_sec  = timeout.tv_sec;
+                ssl->timeoutInfo.timeoutValue.tv_usec = timeout.tv_usec;
+                (toCb)(&ssl->timeoutInfo);
+            }
+            /* clean up */
+            FreeTimeoutInfo(&ssl->timeoutInfo, ssl->heap);
+            ssl->toInfoOn = 0;
+        }
+        if (hsCb) {
+            FinishHandShakeInfo(&ssl->handShakeInfo, ssl);
+            (hsCb)(&ssl->handShakeInfo);
+            ssl->hsInfoOn = 0;
+        }
+        return ret;
+    }
+
+
+#ifndef NO_CYASSL_CLIENT
+
+    int CyaSSL_connect_ex(SSL* ssl, HandShakeCallBack hsCb,
+                          TimeoutCallBack toCb, Timeval timeout)
+    {
+        return CyaSSL_ex_wrapper(ssl, hsCb, toCb, timeout);
+    }
+
+#endif
+
+
+#ifndef NO_CYASSL_SERVER
+
+    int CyaSSL_accept_ex(SSL* ssl, HandShakeCallBack hsCb,
+                         TimeoutCallBack toCb,Timeval timeout)
+    {
+        return CyaSSL_ex_wrapper(ssl, hsCb, toCb, timeout);
+    }
+
+#endif
+
+#endif /* CYASSL_CALLBACKS */
+
+
+#ifndef NO_PSK
+
+    void SSL_CTX_set_psk_client_callback(SSL_CTX* ctx, psk_client_callback cb)
+    {
+        ctx->havePSK = 1;
+        ctx->client_psk_cb = cb;
+    }
+
+
+    void SSL_set_psk_client_callback(SSL* ssl, psk_client_callback cb)
+    {
+        ssl->options.havePSK = 1;
+        ssl->options.client_psk_cb = cb;
+
+        InitSuites(&ssl->suites, ssl->version,TRUE,TRUE, ssl->options.haveNTRU,
+                   ssl->options.haveECDSA, ssl->ctx->method->side);
+    }
+
+
+    void SSL_CTX_set_psk_server_callback(SSL_CTX* ctx, psk_server_callback cb)
+    {
+        ctx->havePSK = 1;
+        ctx->server_psk_cb = cb;
+    }
+
+
+    void SSL_set_psk_server_callback(SSL* ssl, psk_server_callback cb)
+    {
+        ssl->options.havePSK = 1;
+        ssl->options.server_psk_cb = cb;
+
+        InitSuites(&ssl->suites, ssl->version, ssl->options.haveDH, TRUE,
+                   ssl->options.haveNTRU, ssl->options.haveECDSA,
+                   ssl->ctx->method->side);
+    }
+
+
+    const char* SSL_get_psk_identity_hint(const SSL* ssl)
+    {
+        return ssl->arrays.server_hint;
+    }
+
+
+    const char* SSL_get_psk_identity(const SSL* ssl)
+    {
+        return ssl->arrays.client_identity;
+    }
+
+
+    int SSL_CTX_use_psk_identity_hint(SSL_CTX* ctx, const char* hint)
+    {
+        if (hint == 0)
+            ctx->server_hint[0] = 0;
+        else
+            XSTRNCPY(ctx->server_hint, hint, MAX_PSK_ID_LEN);
+        return SSL_SUCCESS;
+    }
+
+
+    int SSL_use_psk_identity_hint(SSL* ssl, const char* hint)
+    {
+        if (hint == 0)
+            ssl->arrays.server_hint[0] = 0;
+        else
+            XSTRNCPY(ssl->arrays.server_hint, hint, MAX_PSK_ID_LEN);
+        return SSL_SUCCESS;
+    }
+
+#endif /* NO_PSK */
+
+
+#if defined(NO_FILESYSTEM) || defined(MICRIUM)
+
+    /* CyaSSL extension allows DER files to be loaded from buffers as well */
+    int CyaSSL_CTX_load_verify_buffer(SSL_CTX* ctx, const unsigned char* buffer,
+                                      long sz, int format)
+    {
+        return ProcessBuffer(ctx, buffer, sz, format, CA_TYPE);
+    }
+
+
+    int CyaSSL_CTX_use_certificate_buffer(SSL_CTX* ctx,
+                                 const unsigned char* buffer,long sz,int format)
+    {
+        return ProcessBuffer(ctx, buffer, sz, format, CERT_TYPE);
+    }
+
+
+    int CyaSSL_CTX_use_PrivateKey_buffer(SSL_CTX* ctx,
+                                 const unsigned char* buffer,long sz,int format)
+    {
+        return ProcessBuffer(ctx, buffer, sz, format, PRIVATEKEY_TYPE);
+    }
+
+
+    int CyaSSL_CTX_use_certificate_chain_buffer(SSL_CTX* ctx,
+                                 const unsigned char* buffer, long sz)
+    {
+        /* add first to ctx, all tested implementations support this */
+        return ProcessBuffer(ctx, buffer, sz, SSL_FILETYPE_PEM, CA_TYPE);
+    }
+
+#endif /* NO_FILESYSTEM || MICRIUM */
+
+
+#if defined(OPENSSL_EXTRA) || defined(GOAHEAD_WS)
+
+
+    int SSLeay_add_ssl_algorithms(void)
+    {
+        OpenSSL_add_all_algorithms(); 
+        return SSL_SUCCESS;
+    }
+
+
+    long SSL_CTX_sess_set_cache_size(SSL_CTX* ctx, long sz)
+    {
+        /* cache size fixed at compile time in CyaSSL */
+        return 0;
+    }
+
+
+    void SSL_CTX_set_quiet_shutdown(SSL_CTX* ctx, int mode)
+    {
+        if (mode)
+            ctx->quietShutdown = 1;
+    }
+
+
+    int SSL_CTX_check_private_key(SSL_CTX* ctx)
+    {
+        /* TODO: check private against public for RSA match */
+        return SSL_SUCCESS;
+    }
+
+
+    void SSL_set_bio(SSL* ssl, BIO* rd, BIO* wr)
+    {
+        SSL_set_rfd(ssl, rd->fd);
+        SSL_set_wfd(ssl, wr->fd);
+
+        ssl->biord = rd;
+        ssl->biowr = wr;
+    }
+
+
+    void SSL_CTX_set_client_CA_list(SSL_CTX* ctx, STACK_OF(X509_NAME)* names)
+    {
+   
+    }
+
+
+    STACK_OF(X509_NAME)* SSL_load_client_CA_file(const char* fname)
+    {
+        return 0;
+    }
+
+
+    int SSL_CTX_set_default_verify_paths(SSL_CTX* ctx)
+    {
+        /* TODO:, not needed in goahead */
+        return SSL_NOT_IMPLEMENTED;
+    }
+
+
+    void SSL_set_accept_state(SSL* ssl)
+    {
+        byte havePSK = 0;
+
+        ssl->options.side = SERVER_END;
+        /* reset suites in case user switched */
+#ifndef NO_PSK
+        havePSK = ssl->options.havePSK;
+#endif
+        InitSuites(&ssl->suites, ssl->version, ssl->options.haveDH, havePSK,
+                   ssl->options.haveNTRU, ssl->options.haveECDSA,
+                   ssl->ctx->method->side);
+    }
+
+
+    void OpenSSL_add_all_algorithms(void)
+    {
+        InitCyaSSL(); 
+    }
+
+
+    int SSLeay_add_all_algorithms(void)
+    {
+        OpenSSL_add_all_algorithms(); 
+        return SSL_SUCCESS;
+    }
+
+    
+    void SSL_CTX_set_tmp_rsa_callback(SSL_CTX* ctx, RSA*(*f)(SSL*, int, int))
+    {
+        /* CyaSSL verifies all these internally */   
+    }
+
+
+    void SSL_set_shutdown(SSL* ssl, int opt)
+    {
+       
+    }
+
+
+    long SSL_CTX_set_options(SSL_CTX* ctx, long opt)
+    {
+        /* goahead calls with 0, do nothing */ 
+        return opt;
+    }
+
+
+    int SSL_set_rfd(SSL* ssl, int rfd)
+    {
+        ssl->rfd = rfd;      /* not used directly to allow IO callbacks */
+
+        ssl->IOCB_ReadCtx  = &ssl->rfd;
+
+        return SSL_SUCCESS;
+    }
+
+
+    int SSL_set_wfd(SSL* ssl, int wfd)
+    {
+        ssl->wfd = wfd;      /* not used directly to allow IO callbacks */
+
+        ssl->IOCB_WriteCtx  = &ssl->wfd;
+
+        return SSL_SUCCESS;
+    }
+
+
+    RSA* RSA_generate_key(int len, unsigned long bits, void(*f)(int,
+                                                        int, void*), void* data)
+    {
+        /* no tmp key needed, actual generation not supported */
+        return 0;
+    }
+
+
+    X509_NAME* X509_get_issuer_name(X509* cert)
+    {
+        return &cert->issuer;
+    }
+
+
+    X509_NAME* X509_get_subject_name(X509* cert)
+    {
+        return &cert->subject;
+    }
+
+
+    /* copy name into buffer, at most sz bytes, if buffer is null will
+       malloc buffer, call responsible for freeing                     */
+    char* X509_NAME_oneline(X509_NAME* name, char* buffer, int sz)
+    {
+        int copySz = min(sz, name->sz);
+        if (!name->sz) return buffer;
+
+        if (!buffer) {
+            buffer = (char*)XMALLOC(name->sz, 0, DYNAMIC_TYPE_OPENSSL);
+            if (!buffer) return buffer;
+            copySz = name->sz;
+        }
+
+        if (copySz == 0)
+            return buffer;
+
+        XMEMCPY(buffer, name->name, copySz - 1);
+        buffer[copySz - 1] = 0;
+
+        return buffer;
+    }
+
+
+    X509* X509_STORE_CTX_get_current_cert(X509_STORE_CTX* ctx)
+    {
+        return 0;
+    }
+
+
+    int X509_STORE_CTX_get_error(X509_STORE_CTX* ctx)
+    {
+        return 0;
+    }
+
+
+    int X509_STORE_CTX_get_error_depth(X509_STORE_CTX* ctx)
+    {
+        return 0;
+    }
+
+
+    BIO_METHOD* BIO_f_buffer(void)
+    {
+        static BIO_METHOD meth;
+        meth.type = BIO_BUFFER;
+
+        return &meth;
+    }
+
+
+    long BIO_set_write_buffer_size(BIO* bio, long size)
+    {
+        /* CyaSSL has internal buffer, compatibility only */
+        return size; 
+    }
+
+
+    BIO_METHOD* BIO_f_ssl(void)
+    {
+        static BIO_METHOD meth;
+        meth.type = BIO_SSL;
+
+        return &meth;
+    }
+
+
+    BIO* BIO_new_socket(int sfd, int close)
+    {
+        BIO* bio = (BIO*) XMALLOC(sizeof(BIO), 0, DYNAMIC_TYPE_OPENSSL);
+        if (bio) { 
+            bio->type  = BIO_SOCKET;
+            bio->close = close;
+            bio->eof   = 0;
+            bio->ssl   = 0;
+            bio->fd    = sfd;
+            bio->prev  = 0;
+            bio->next  = 0;
+        }
+        return bio; 
+    }
+
+
+    int BIO_eof(BIO* b)
+    {
+        if (b->eof)
+            return 1;
+
+        return 0;        
+    }
+
+
+    long BIO_set_ssl(BIO* b, SSL* ssl, int close)
+    {
+        b->ssl   = ssl;
+        b->close = close;
+    /* add to ssl for bio free if SSL_free called before/instead of free_all? */
+
+        return 0;
+    }
+
+
+    BIO* BIO_new(BIO_METHOD* method)
+    {
+        BIO* bio = (BIO*) XMALLOC(sizeof(BIO), 0, DYNAMIC_TYPE_OPENSSL);
+        if (bio) {
+            bio->type  = method->type;
+            bio->close = 0;
+            bio->eof   = 0;
+            bio->ssl   = 0;
+            bio->fd    = 0;
+            bio->prev  = 0;
+            bio->next  = 0;
+        }
+        return bio;
+    }
+
+
+#ifdef USE_WINDOWS_API 
+    #define CloseSocket(s) closesocket(s)
+#else
+    #define CloseSocket(s) close(s)
+#endif
+
+    int BIO_free(BIO* bio)
+    {
+        /* unchain?, doesn't matter in goahead since from free all */
+        if (bio) {
+            if (bio->close) {
+                if (bio->ssl)
+                    SSL_free(bio->ssl);
+                if (bio->fd)
+                    CloseSocket(bio->fd);
+            }
+            XFREE(bio, 0, DYNAMIC_TYPE_OPENSSL);
+        }
+        return 0;
+    }
+
+
+    int BIO_free_all(BIO* bio)
+    {
+        BIO* next = bio;
+
+        while ( (bio = next) ) {
+            next = bio->next;
+            BIO_free(bio);
+        }
+        return 0;
+    }
+
+
+    int BIO_read(BIO* bio, void* buf, int len)
+    {
+        int  ret;
+        SSL* ssl = 0;
+        BIO* front = bio;
+
+        /* already got eof, again is error */
+        if (front->eof)
+            return -1;
+
+        while(bio && ((ssl = bio->ssl) == 0) )
+            bio = bio->next;
+
+        if (ssl == 0) return -1;
+
+        ret = SSL_read(ssl, buf, len);
+        if (ret == 0)
+            front->eof = 1;
+        else if (ret < 0) {
+            int err = SSL_get_error(ssl, 0);
+            if ( !(err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) )
+                front->eof = 1;
+        }
+        return ret;
+    }
+
+
+    int BIO_write(BIO* bio, const void* data, int len)
+    {
+        int  ret;
+        SSL* ssl = 0;
+        BIO* front = bio;
+
+        /* already got eof, again is error */
+        if (front->eof)
+            return -1;
+
+        while(bio && ((ssl = bio->ssl) == 0) )
+            bio = bio->next;
+
+        if (ssl == 0) return -1;
+
+        ret = SSL_write(ssl, data, len);
+        if (ret == 0)
+            front->eof = 1;
+        else if (ret < 0) {
+            int err = SSL_get_error(ssl, 0);
+            if ( !(err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) )
+                front->eof = 1;
+        }
+
+        return ret;
+    }
+
+
+    BIO* BIO_push(BIO* top, BIO* append)
+    {
+        top->next    = append;
+        append->prev = top;
+
+        return top;
+    }
+
+
+    int BIO_flush(BIO* bio)
+    {
+        /* for CyaSSL no flushing needed */
+        return 1;
+    }
+
+
+#endif /* OPENSSL_EXTRA || GOAHEAD_WS */
+
+
+#ifdef OPENSSL_EXTRA
+
+    unsigned long SSLeay(void)
+    {
+        return SSLEAY_VERSION_NUMBER;
+    }
+
+
+    const char* SSLeay_version(int type)
+    {
+        static const char* version = "SSLeay CyaSSL compatibility";
+        return version;
+    }
+
+
+    void MD5_Init(MD5_CTX* md5)
+    {
+        typedef char md5_test[sizeof(MD5_CTX) >= sizeof(Md5) ? 1 : -1];
+        (void)sizeof(md5_test);
+
+        InitMd5((Md5*)md5);
+    }
+
+
+    void MD5_Update(MD5_CTX* md5, const void* input, unsigned long sz)
+    {
+        Md5Update((Md5*)md5, (const byte*)input, sz);
+    }
+
+
+    void MD5_Final(byte* input, MD5_CTX* md5)
+    {
+        Md5Final((Md5*)md5, input);
+    }
+
+
+    void SHA_Init(SHA_CTX* sha)
+    {
+        typedef char sha_test[sizeof(SHA_CTX) >= sizeof(Sha) ? 1 : -1];
+        (void)sizeof(sha_test);
+
+        InitSha((Sha*)sha);
+    }
+
+
+    void SHA_Update(SHA_CTX* sha, const void* input, unsigned long sz)
+    {
+        ShaUpdate((Sha*)sha, (const byte*)input, sz);
+    }
+
+
+    void SHA_Final(byte* input, SHA_CTX* sha)
+    {
+        ShaFinal((Sha*)sha, input);
+    }
+
+
+    const EVP_MD* EVP_md5(void)
+    {
+        static const char* type = "MD5";
+        return type;
+    }
+
+
+    const EVP_MD* EVP_sha1(void)
+    {
+        static const char* type = "SHA";
+        return type;
+    }
+
+
+    void EVP_MD_CTX_init(EVP_MD_CTX* ctx)
+    {
+        /* do nothing */ 
+    }
+
+
+    int EVP_MD_CTX_cleanup(EVP_MD_CTX* ctx)
+    {
+        return 0;
+    }    
+
+
+    int EVP_DigestInit(EVP_MD_CTX* ctx, const EVP_MD* type)
+    {
+        if (XSTRNCMP(type, "MD5", 3) == 0) {
+             ctx->macType = MD5;
+             MD5_Init((MD5_CTX*)&ctx->hash);
+        }
+        else if (XSTRNCMP(type, "SHA", 3) == 0) {
+             ctx->macType = SHA;
+             SHA_Init((SHA_CTX*)&ctx->hash);
+        }
+        else
+             return -1;
+
+        return 0;
+    }
+
+
+    int EVP_DigestUpdate(EVP_MD_CTX* ctx, const void* data, size_t sz)
+    {
+        if (ctx->macType == MD5) 
+            MD5_Update((MD5_CTX*)&ctx->hash, data, (unsigned long)sz);
+        else if (ctx->macType == SHA) 
+            SHA_Update((SHA_CTX*)&ctx->hash, data, (unsigned long)sz);
+        else
+            return -1;
+
+        return 0;
+    }
+
+
+    int EVP_DigestFinal(EVP_MD_CTX* ctx, unsigned char* md, unsigned int* s)
+    {
+        if (ctx->macType == MD5) {
+            MD5_Final(md, (MD5_CTX*)&ctx->hash);
+            if (s) *s = MD5_DIGEST_SIZE;
+        }
+        else if (ctx->macType == SHA) {
+            SHA_Final(md, (SHA_CTX*)&ctx->hash);
+            if (s) *s = SHA_DIGEST_SIZE;
+        }
+        else
+            return -1;
+
+        return 0;
+    }
+
+
+    int EVP_DigestFinal_ex(EVP_MD_CTX* ctx, unsigned char* md, unsigned int* s)
+    {
+        return EVP_DigestFinal(ctx, md, s);
+    }
+
+
+    unsigned char* HMAC(const EVP_MD* evp_md, const void* key, int key_len,
+        const unsigned char* d, int n, unsigned char* md, unsigned int* md_len)
+    {
+        Hmac hmac;
+
+        if (!md) return 0;  /* no static buffer support */
+
+        if (XSTRNCMP(evp_md, "MD5", 3) == 0) {
+            HmacSetKey(&hmac, MD5, key, key_len);
+            if (md_len) *md_len = MD5_DIGEST_SIZE;
+        }
+        else if (XSTRNCMP(evp_md, "SHA", 3) == 0) {
+            HmacSetKey(&hmac, SHA, key, key_len);    
+            if (md_len) *md_len = SHA_DIGEST_SIZE;
+        }
+        else
+            return 0;
+
+        HmacUpdate(&hmac, d, n);
+        HmacFinal(&hmac, md);
+    
+        return md;
+    }
+
+    unsigned long ERR_get_error(void)
+    {
+        /* TODO: */
+        return 0;
+    }
+
+    void ERR_clear_error(void)
+    {
+        /* TODO: */
+    }
+
+
+    int RAND_status(void)
+    {
+        return 1;  /* CTaoCrypt provides enough seed internally */
+    }
+
+
+    int RAND_bytes(unsigned char* buf, int num)
+    {
+        RNG rng;
+
+        if (InitRng(&rng))
+           return 0;
+
+        RNG_GenerateBlock(&rng, buf, num);
+
+        return 1;
+    }
+
+
+    int DES_key_sched(const_DES_cblock* key, DES_key_schedule* schedule)
+    {
+        XMEMCPY(schedule, key, sizeof(const_DES_cblock));
+        return 0;
+    }
+
+
+    void DES_cbc_encrypt(const unsigned char* input, unsigned char* output,
+                     long length, DES_key_schedule* schedule, DES_cblock* ivec,
+                     int enc)
+    {
+        Des des;
+        Des_SetKey(&des, (const byte*)schedule, (const byte*)ivec, !enc);
+
+        if (enc)
+            Des_CbcEncrypt(&des, output, input, length);
+        else
+            Des_CbcDecrypt(&des, output, input, length);
+    }
+
+
+    /* correctly sets ivec for next call */
+    void DES_ncbc_encrypt(const unsigned char* input, unsigned char* output,
+                     long length, DES_key_schedule* schedule, DES_cblock* ivec,
+                     int enc)
+    {
+        Des des;
+        Des_SetKey(&des, (const byte*)schedule, (const byte*)ivec, !enc);
+
+        if (enc)
+            Des_CbcEncrypt(&des, output, input, length);
+        else
+            Des_CbcDecrypt(&des, output, input, length);
+
+        XMEMCPY(ivec, output + length - sizeof(DES_cblock), sizeof(DES_cblock));
+    }
+
+
+    void ERR_free_strings(void)
+    {
+        /* handled internally */
+    }
+
+
+    void ERR_remove_state(unsigned long state)
+    {
+        /* TODO: GetErrors().Remove(); */
+    }
+
+
+    void EVP_cleanup(void)
+    {
+        /* nothing to do here */
+    }
+
+
+    void CRYPTO_cleanup_all_ex_data(void)
+    {
+        /* nothing to do here */
+    }
+
+
+    long SSL_CTX_set_mode(SSL_CTX* ctx, long mode)
+    {
+        /* SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER is CyaSSL default mode */
+
+        if (mode == SSL_MODE_ENABLE_PARTIAL_WRITE)
+            ctx->partialWrite = 1;
+
+        return mode;
+    }
+
+
+    long SSL_CTX_get_mode(SSL_CTX* ctx)
+    {
+        /* TODO: */
+        return 0;
+    }
+
+
+    void SSL_CTX_set_default_read_ahead(SSL_CTX* ctx, int m)
+    {
+        /* TODO: maybe? */
+    }
+
+
+    int SSL_CTX_set_session_id_context(SSL_CTX* ctx,
+                                       const unsigned char* sid_ctx,
+                                       unsigned int sid_ctx_len)
+    {
+        /* No application specific context needed for cyaSSL */
+        return SSL_SUCCESS;
+    }
+
+
+    long SSL_CTX_sess_get_cache_size(SSL_CTX* ctx)
+    {
+        /* TODO: maybe? */
+        return (~0);
+    }
+
+    unsigned long ERR_get_error_line_data(const char** file, int* line,
+                                          const char** data, int *flags)
+    {
+        /* Not implemented */
+        return 0;
+    }
+
+
+    X509* SSL_get_peer_certificate(SSL* ssl)
+    {
+        if (ssl->peerCert.issuer.sz)
+            return &ssl->peerCert;
+        else
+            return 0;
+    }
+
+
+
+    int SSL_set_ex_data(SSL* ssl, int idx, void* data)
+    {
+        return 0;
+    }
+
+
+    int SSL_get_shutdown(const SSL* ssl)
+    {
+        return 0;
+    }
+
+
+    int SSL_set_session_id_context(SSL* ssl, const unsigned char* id,
+                                   unsigned int len)
+    {
+        return 0;
+    }
+
+
+    void SSL_set_connect_state(SSL* ssl)
+    {
+        /* client by default */ 
+    }
+
+
+    int SSL_session_reused(SSL* ssl)
+    {
+        return ssl->options.resuming;
+    }
+
+
+    void SSL_SESSION_free(SSL_SESSION* session)
+    {
+     
+    }
+
+
+    const char* SSL_get_version(SSL* ssl)
+    {
+        if (ssl->version.major == 3) {
+            switch (ssl->version.minor) {
+                case 0 :
+                    return "SSLv3";
+                case 1 :
+                    return "TLSv1";
+                case 2 :
+                    return "TLSv1.1";
+                case 3 :
+                    return "TLSv1.2";
+            }
+        }
+        return "unknown";
+    }
+
+
+    SSL_CIPHER*  SSL_get_current_cipher(SSL* ssl)
+    {
+        return &ssl->cipher;
+    }
+
+
+    const char* SSL_CIPHER_get_name(const SSL_CIPHER* cipher)
+    {
+        if (cipher) {
+            if (cipher->ssl->options.cipherSuite0 == ECC_BYTE) {
+            /* ECC suites */
+            switch (cipher->ssl->options.cipherSuite) {
+                case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA :
+                    return "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA";
+                case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA :
+                    return "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA";
+                case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA :
+                    return "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA";
+                case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA :
+                    return "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA";
+                case TLS_ECDHE_RSA_WITH_RC4_128_SHA :
+                    return "TLS_ECDHE_RSA_WITH_RC4_128_SHA";
+                case TLS_ECDHE_ECDSA_WITH_RC4_128_SHA :
+                    return "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA";
+                case TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA :
+                    return "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA";
+                case TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA :
+                    return "TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA";
+            }
+            } else {
+            /* normal suites */
+            switch (cipher->ssl->options.cipherSuite) {
+                case SSL_RSA_WITH_RC4_128_SHA :
+                    return "SSL_RSA_WITH_RC4_128_SHA";
+                case SSL_RSA_WITH_RC4_128_MD5 :
+                    return "SSL_RSA_WITH_RC4_128_MD5";
+                case SSL_RSA_WITH_3DES_EDE_CBC_SHA :
+                    return "SSL_RSA_WITH_3DES_EDE_CBC_SHA";
+                case TLS_RSA_WITH_AES_128_CBC_SHA :
+                    return "TLS_RSA_WITH_AES_128_CBC_SHA";
+                case TLS_RSA_WITH_AES_256_CBC_SHA :
+                    return "TLS_RSA_WITH_AES_256_CBC_SHA";
+                case TLS_PSK_WITH_AES_128_CBC_SHA :
+                    return "TLS_PSK_WITH_AES_128_CBC_SHA";
+                case TLS_PSK_WITH_AES_256_CBC_SHA :
+                    return "TLS_PSK_WITH_AES_256_CBC_SHA";
+                case TLS_DHE_RSA_WITH_AES_128_CBC_SHA :
+                    return "TLS_DHE_RSA_WITH_AES_128_CBC_SHA";
+                case TLS_DHE_RSA_WITH_AES_256_CBC_SHA :
+                    return "TLS_DHE_RSA_WITH_AES_256_CBC_SHA";
+                case TLS_RSA_WITH_HC_128_CBC_MD5 :
+                    return "TLS_RSA_WITH_HC_128_CBC_MD5";
+                case TLS_RSA_WITH_HC_128_CBC_SHA :
+                    return "TLS_RSA_WITH_HC_128_CBC_SHA";
+                case TLS_RSA_WITH_RABBIT_CBC_SHA :
+                    return "TLS_RSA_WITH_RABBIT_CBC_SHA";
+                case TLS_NTRU_RSA_WITH_RC4_128_SHA :
+                    return "TLS_NTRU_RSA_WITH_RC4_128_SHA";
+                case TLS_NTRU_RSA_WITH_3DES_EDE_CBC_SHA :
+                    return "TLS_NTRU_RSA_WITH_3DES_EDE_CBC_SHA";
+                case TLS_NTRU_RSA_WITH_AES_128_CBC_SHA :
+                    return "TLS_NTRU_RSA_WITH_AES_128_CBC_SHA";
+                case TLS_NTRU_RSA_WITH_AES_256_CBC_SHA :
+                    return "TLS_NTRU_RSA_WITH_AES_256_CBC_SHA";
+            }
+            }  /* normal / ECC */
+        }
+
+        return "NONE";
+    }
+
+
+    char* SSL_CIPHER_description(SSL_CIPHER* cipher, char* buffer, int len)
+    {
+        return 0;
+    }
+
+
+    SSL_SESSION* SSL_get1_session(SSL* ssl)  /* what's ref count */
+    {
+        return 0;
+    }
+
+
+    void X509_free(X509* buf)
+    {
+       
+    }
+
+
+    void OPENSSL_free(void* buf)
+    {
+  
+    }
+
+
+    int OCSP_parse_url(char* url, char** host, char** port, char** path,
+                       int* ssl)
+    {
+        return 0;
+    }
+
+
+    SSL_METHOD* SSLv2_client_method(void)
+    {
+        return 0;
+    }
+
+
+    SSL_METHOD* SSLv2_server_method(void)
+    {
+        return 0;
+    }
+
+
+#ifndef NO_MD4
+
+    void MD4_Init(MD4_CTX* md4)
+    {
+        /* make sure we have a big enough buffer */
+        typedef char ok[sizeof(md4->buffer) >= sizeof(Md4) ? 1 : -1];
+        (void) sizeof(ok);
+ 
+        InitMd4((Md4*)md4);    
+    }
+
+
+    void MD4_Update(MD4_CTX* md4, const void* data, size_t len)
+    {
+        Md4Update((Md4*)md4, (const byte*)data, (word32)len); 
+    }
+
+
+    void MD4_Final(unsigned char* digest, MD4_CTX* md4)
+    {
+        Md4Final((Md4*)md4, digest); 
+    }
+
+#endif /* NO_MD4 */
+
+
+    BIO* BIO_pop(BIO* top)
+    {
+        return 0;
+    }
+
+
+    int BIO_pending(BIO* bio)
+    {
+        return 0;
+    }
+
+
+
+    BIO_METHOD* BIO_s_mem(void)
+    {
+        return 0;
+    }
+
+
+    BIO_METHOD* BIO_f_base64(void)
+    {
+        return 0;
+    }
+
+
+    void BIO_set_flags(BIO* bio, int flags)
+    {
+     
+    }
+
+
+
+    void RAND_screen(void)
+    {
+    
+    }
+
+
+    const char* RAND_file_name(char* fname, size_t len)
+    {
+        return 0;
+    }
+
+
+    int RAND_write_file(const char* fname)
+    {
+        return 0;
+    }
+
+
+    int RAND_load_file(const char* fname, long len)
+    {
+        /* CTaoCrypt provides enough entropy internally or will report error */
+        if (len == -1)
+            return 1024;
+        else
+            return (int)len;
+    }
+
+
+    int RAND_egd(const char* path)
+    {
+        return 0;
+    }
+
+
+
+    COMP_METHOD* COMP_zlib(void)
+    {
+        return 0;
+    }
+
+
+    COMP_METHOD* COMP_rle(void)
+    {
+        return 0;
+    }
+
+
+    int SSL_COMP_add_compression_method(int method, void* data)
+    {
+        return 0;
+    }
+
+
+
+    int SSL_get_ex_new_index(long idx, void* data, void* cb1, void* cb2,
+                             void* cb3)
+    {
+        return 0;
+    }
+
+
+    int CRYPTO_num_locks(void)
+    {
+        return 0;
+    }
+
+
+    void CRYPTO_set_id_callback(unsigned long (*f)(void))
+    {
+    
+    }
+
+
+    void CRYPTO_set_locking_callback(void (*f)(int, int, const char*, int))
+    {
+      
+    }
+
+
+    void CRYPTO_set_dynlock_create_callback(CRYPTO_dynlock_value* (*f)(
+                                                              const char*, int))
+    {
+     
+    }
+
+
+    void CRYPTO_set_dynlock_lock_callback(void (*f)(int, CRYPTO_dynlock_value*,
+                                                const char*, int))
+    {
+     
+    }
+
+
+    void CRYPTO_set_dynlock_destroy_callback(void (*f)(CRYPTO_dynlock_value*,
+                                                   const char*, int))
+    {
+      
+    }
+
+
+
+    const char* X509_verify_cert_error_string(long err)
+    {
+        return 0;
+    }
+
+
+
+    int X509_LOOKUP_add_dir(X509_LOOKUP* lookup, const char* dir, long len)
+    {
+        return 0;
+    }
+
+
+    int X509_LOOKUP_load_file(X509_LOOKUP* lookup, const char* file, long len)
+    {
+        return 0;
+    }
+
+
+    X509_LOOKUP_METHOD* X509_LOOKUP_hash_dir(void)
+    {
+        return 0;
+    }
+
+
+    X509_LOOKUP_METHOD* X509_LOOKUP_file(void)
+    {
+        return 0;
+    }
+
+
+
+    X509_LOOKUP* X509_STORE_add_lookup(X509_STORE* store, X509_LOOKUP_METHOD* m)
+    {
+        return 0;
+    }
+
+
+    X509_STORE* X509_STORE_new(void)
+    {
+        return 0;
+    }
+
+
+    int X509_STORE_get_by_subject(X509_STORE_CTX* ctx, int idx, X509_NAME* name,
+                                       X509_OBJECT* obj)
+    {
+        return 0;
+    }
+
+
+    int X509_STORE_CTX_init(X509_STORE_CTX* ctx, X509_STORE* store, X509* x509,
+                            STACK_OF(X509)* sk)
+    {
+        return 0;
+    }
+
+
+    void X509_STORE_CTX_cleanup(X509_STORE_CTX* ctx)
+    {
+ 
+    }
+
+
+
+    ASN1_TIME* X509_CRL_get_lastUpdate(X509_CRL* crl)
+    {
+        return 0;
+    }
+
+
+    ASN1_TIME* X509_CRL_get_nextUpdate(X509_CRL* crl)
+    {
+        return 0;
+    }
+
+
+
+    EVP_PKEY* X509_get_pubkey(X509* x509)
+    {
+        return 0;
+    }
+
+
+    int X509_CRL_verify(X509_CRL* crl, EVP_PKEY* key)
+    {
+        return 0;
+    }
+
+
+    void X509_STORE_CTX_set_error(X509_STORE_CTX* ctx, int err)
+    {
+ 
+    }
+
+
+    void X509_OBJECT_free_contents(X509_OBJECT* obj)
+    {
+  
+    }
+
+
+    void EVP_PKEY_free(EVP_PKEY* key)
+    {
+     
+    }
+
+
+    int X509_cmp_current_time(const ASN1_TIME* time)
+    {
+        return 0;
+    }
+
+
+    int sk_X509_REVOKED_num(X509_REVOKED* revoked)
+    {
+        return 0;
+    }
+
+
+
+    X509_REVOKED* X509_CRL_get_REVOKED(X509_CRL* crl)
+    {
+        return 0;
+    }
+
+
+    X509_REVOKED* sk_X509_REVOKED_value(X509_REVOKED* revoked, int value)
+    {
+        return 0;
+    }
+
+
+
+    ASN1_INTEGER* X509_get_serialNumber(X509* x509)
+    {
+        return 0;
+    }
+
+
+
+    int ASN1_TIME_print(BIO* bio, const ASN1_TIME* time)
+    {
+        return 0;
+    }
+
+
+
+    int ASN1_INTEGER_cmp(const ASN1_INTEGER* a, const ASN1_INTEGER* b)
+    {
+        return 0;
+    }
+
+
+    long ASN1_INTEGER_get(const ASN1_INTEGER* i)
+    {
+        return 0;
+    }
+
+
+
+    void* X509_STORE_CTX_get_ex_data(X509_STORE_CTX* ctx, int idx)
+    {
+        return 0;
+    }
+
+
+    int SSL_get_ex_data_X509_STORE_CTX_idx(void)
+    {
+        return 0;
+    }
+
+
+    void* SSL_get_ex_data(const SSL* ssl, int idx)
+    {
+        return 0;
+    }
+
+
+    void SSL_CTX_set_default_passwd_cb_userdata(SSL_CTX* ctx, void* userdata)
+    {
+        ctx->userdata = userdata;
+    }
+
+
+    void SSL_CTX_set_default_passwd_cb(SSL_CTX* ctx, pem_password_cb cb)
+    {
+        ctx->passwd_cb = cb;
+    }
+
+
+    long SSL_CTX_set_timeout(SSL_CTX* ctx, long to)
+    {
+        return 0;
+    }
+
+
+    void SSL_CTX_set_info_callback(SSL_CTX* ctx, void (*f)())
+    {
+        
+    }
+
+
+    unsigned long ERR_peek_error(void)
+    {
+        return 0;
+    }
+
+
+    int ERR_GET_REASON(int err)
+    {
+        return 0;
+    }
+
+
+    char* SSL_alert_type_string_long(int alert)
+    {
+        return 0;
+    }
+
+
+    char* SSL_alert_desc_string_long(int alert)
+    {
+        return 0;
+    }
+
+
+    char* SSL_state_string_long(SSL* ssl)
+    {
+        return 0;
+    }
+
+
+
+    void RSA_free(RSA* rsa)
+    {
+        
+    }
+
+
+    int PEM_def_callback(char* name, int num, int w, void* key)
+    {
+        return 0;
+    }
+    
+
+    long SSL_CTX_sess_accept(SSL_CTX* ctx)
+    {
+        return 0;
+    }
+
+
+    long SSL_CTX_sess_connect(SSL_CTX* ctx)
+    {
+        return 0;
+    }
+
+
+    long SSL_CTX_sess_accept_good(SSL_CTX* ctx)
+    {
+        return 0;
+    }
+
+
+    long SSL_CTX_sess_connect_good(SSL_CTX* ctx)
+    {
+        return 0;
+    }
+
+
+    long SSL_CTX_sess_accept_renegotiate(SSL_CTX* ctx)
+    {
+        return 0;
+    }
+
+
+    long SSL_CTX_sess_connect_renegotiate(SSL_CTX* ctx)
+    {
+        return 0;
+    }
+
+
+    long SSL_CTX_sess_hits(SSL_CTX* ctx)
+    {
+        return 0;
+    }
+
+
+    long SSL_CTX_sess_cb_hits(SSL_CTX* ctx)
+    {
+        return 0;
+    }
+
+
+    long SSL_CTX_sess_cache_full(SSL_CTX* ctx)
+    {
+        return 0;
+    }
+
+
+    long SSL_CTX_sess_misses(SSL_CTX* ctx)
+    {
+        return 0;
+    }
+
+
+    long SSL_CTX_sess_timeouts(SSL_CTX* ctx)
+    {
+        return 0;
+    }
+
+
+    long SSL_CTX_sess_number(SSL_CTX* ctx)
+    {
+        return 0;
+    }
+
+
+    void DES_set_key_unchecked(const_DES_cblock* des, DES_key_schedule* key)
+    {
+    }
+
+
+    void DES_set_odd_parity(DES_cblock* des)
+    {
+    }
+
+    
+    void DES_ecb_encrypt(DES_cblock* desa, DES_cblock* desb,
+                         DES_key_schedule* key, int len)
+    {
+    }
+
+    int BIO_printf(BIO* bio, const char* format, ...)
+    {
+        return 0;
+    }
+
+
+    int ASN1_UTCTIME_print(BIO* bio, const ASN1_UTCTIME* a)
+    {
+        return 0;
+    }
+    
+
+    int  sk_num(X509_REVOKED* rev)
+    {
+        return 0;
+    }
+
+
+    void* sk_value(X509_REVOKED* rev, int i)
+    {
+        return 0;
+    }
+
+
+    int EVP_BytesToKey(const EVP_CIPHER* type, const EVP_MD* md,
+                       const byte* salt, const byte* data, int sz, int count,
+                       byte* key, byte* iv)
+    {
+        int keyLen = 0;
+        int ivLen  = 0;
+
+        Md5    myMD;
+        byte   digest[MD5_DIGEST_SIZE];
+
+        int j;
+        int keyLeft;
+        int ivLeft;
+        int keyOutput = 0;
+
+        InitMd5(&myMD);
+
+        /* only support MD5 for now */
+        if (XSTRNCMP(md, "MD5", 3)) return 0;
+
+        /* only support CBC DES and AES for now */
+        if (XSTRNCMP(type, "DES-CBC", 7) == 0) {
+            keyLen = DES_KEY_SIZE;
+            ivLen  = DES_IV_SIZE;
+        }
+        else if (XSTRNCMP(type, "DES-EDE3-CBC", 12) == 0) {
+            keyLen = DES3_KEY_SIZE;
+            ivLen  = DES_IV_SIZE;
+        }
+        else if (XSTRNCMP(type, "AES-128-CBC", 11) == 0) {
+            keyLen = AES_128_KEY_SIZE;
+            ivLen  = AES_IV_SIZE;
+        }
+        else if (XSTRNCMP(type, "AES-192-CBC", 11) == 0) {
+            keyLen = AES_192_KEY_SIZE;
+            ivLen  = AES_IV_SIZE;
+        }
+        else if (XSTRNCMP(type, "AES-256-CBC", 11) == 0) {
+            keyLen = AES_256_KEY_SIZE;
+            ivLen  = AES_IV_SIZE;
+        }
+        else
+            return 0;
+
+        keyLeft   = keyLen;
+        ivLeft    = ivLen;
+
+        while (keyOutput < (keyLen + ivLen)) {
+            int digestLeft = MD5_DIGEST_SIZE;
+            /* D_(i - 1) */
+            if (keyOutput)                      /* first time D_0 is empty */
+                Md5Update(&myMD, digest, MD5_DIGEST_SIZE);
+            /* data */
+            Md5Update(&myMD, data, sz);
+            /* salt */
+            if (salt)
+                Md5Update(&myMD, salt, EVP_SALT_SIZE);
+            Md5Final(&myMD, digest);
+            /* count */
+            for (j = 1; j < count; j++) {
+                Md5Update(&myMD, digest, MD5_DIGEST_SIZE);
+                Md5Final(&myMD, digest);
+            }
+
+            if (keyLeft) {
+                int store = min(keyLeft, MD5_DIGEST_SIZE);
+                XMEMCPY(&key[keyLen - keyLeft], digest, store);
+
+                keyOutput  += store;
+                keyLeft    -= store;
+                digestLeft -= store;
+            }
+
+            if (ivLeft && digestLeft) {
+                int store = min(ivLeft, digestLeft);
+                XMEMCPY(&iv[ivLen - ivLeft], &digest[MD5_DIGEST_SIZE -
+                                                    digestLeft], store);
+                keyOutput += store;
+                ivLeft    -= store;
+            }
+        }
+        if (keyOutput != (keyLen + ivLen))
+            return 0;
+        return keyOutput;
+    }
+
+    /* stunnel 4.28 needs */
+    void* SSL_CTX_get_ex_data(const SSL_CTX* ctx, int d)
+    {
+        return 0;
+    }
+
+
+    int SSL_CTX_set_ex_data(SSL_CTX* ctx, int d, void* p)
+    {
+        return SSL_SUCCESS;
+    }
+
+
+    void SSL_CTX_sess_set_get_cb(SSL_CTX* ctx, SSL_SESSION*(*f)(SSL*,
+                                                    unsigned char*, int, int*))
+    {
+       
+    }
+
+
+    void SSL_CTX_sess_set_new_cb(SSL_CTX* ctx, int (*f)(SSL*, SSL_SESSION*))
+    {
+
+    }
+
+
+    void SSL_CTX_sess_set_remove_cb(SSL_CTX* ctx, void (*f)(SSL_CTX*,
+                                                            SSL_SESSION*))
+    {
+
+    }
+
+
+    int i2d_SSL_SESSION(SSL_SESSION* sess, unsigned char** p)
+    {
+        return sizeof(SSL_SESSION);
+    }
+
+
+    SSL_SESSION* d2i_SSL_SESSION(SSL_SESSION** sess, const unsigned char** p,
+                                 long i)
+    {
+        return *sess;
+    }
+
+
+    long SSL_SESSION_get_timeout(const SSL_SESSION* sess)
+    {
+        return sess->timeout;
+    }
+
+
+    long SSL_SESSION_get_time(const SSL_SESSION* sess)
+    {
+        return sess->bornOn;
+    }
+
+
+    int SSL_CTX_get_ex_new_index(long idx, void* arg, void* a, void* b, void* c)
+    {
+        return 0; 
+    }
+
+
+#endif /* OPENSSL_EXTRA */
+
+
+#ifdef SESSION_CERTS
+
+
+/* Get peer's certificate chain */
+X509_CHAIN* CyaSSL_get_peer_chain(SSL* ssl)
+{
+    if (ssl)
+        return &ssl->session.chain;
+
+    return 0;
+}
+
+
+/* Get peer's certificate chain total count */
+int CyaSSL_get_chain_count(X509_CHAIN* chain)
+{
+    if (chain)
+        return chain->count;
+
+    return 0;
+}
+
+
+/* Get peer's ASN.1 DER ceritifcate at index (idx) length in bytes */
+int CyaSSL_get_chain_length(X509_CHAIN* chain, int idx)
+{
+    if (chain)
+        return chain->certs[idx].length;
+
+    return 0;
+}
+
+
+/* Get peer's ASN.1 DER ceritifcate at index (idx) */
+byte* CyaSSL_get_chain_cert(X509_CHAIN* chain, int idx)
+{
+    if (chain)
+        return chain->certs[idx].buffer;
+
+    return 0;
+}
+
+
+/* Get peer's PEM ceritifcate at index (idx), output to buffer if inLen big
+   enough else return error (-1), output length is in *outLen */
+int  CyaSSL_get_chain_cert_pem(X509_CHAIN* chain, int idx,
+                               unsigned char* buffer, int inLen, int* outLen)
+{
+    const char header[] = "-----BEGIN CERTIFICATE-----\n";
+    const char footer[] = "-----END CERTIFICATE-----\n";
+
+    int headerLen = sizeof(header) - 1;
+    int footerLen = sizeof(footer) - 1;
+    int i;
+
+    if (!chain || !outLen || !buffer)
+        return -1;
+
+    /* don't even try if inLen too short */
+    if (inLen < headerLen + footerLen + chain->certs[idx].length)
+        return -1;
+
+    /* header */
+    XMEMCPY(buffer, header, headerLen);
+    i = headerLen;
+
+    /* body */
+    *outLen = inLen;  /* input to Base64Encode */
+    if (Base64Encode(chain->certs[idx].buffer, chain->certs[idx].length,
+                     buffer + i, (word32*)outLen) < 0)
+        return -1;
+    i += *outLen;
+
+    /* footer */
+    if ( (i + footerLen) > inLen)
+        return -1;
+    XMEMCPY(buffer + i, footer, footerLen);
+    *outLen += headerLen + footerLen; 
+
+    return 0;
+}
+
+
+/* get session ID */
+const byte* CyaSSL_get_sessionID(const SSL_SESSION* session)
+{
+    return session->sessionID;
+}
+
+
+#endif /* SESSION_CERTS */
+
diff --git a/src/tls.c b/src/tls.c
new file mode 100644
index 000000000..4d823115a
--- /dev/null
+++ b/src/tls.c
@@ -0,0 +1,451 @@
+/* tls.c
+ *
+ * Copyright (C) 2006-2011 Sawtooth Consulting Ltd.
+ *
+ * This file is part of CyaSSL.
+ *
+ * CyaSSL is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * CyaSSL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+
+#include "ssl.h"
+#include "cyassl_int.h"
+#include "cyassl_error.h"
+#include "ctc_hmac.h"
+
+
+
+#ifndef NO_TLS
+
+
+#ifndef min
+
+    static INLINE word32 min(word32 a, word32 b)
+    {
+        return a > b ? b : a;
+    }
+
+#endif /* min */
+
+
+/* calculate XOR for TLSv1 PRF */
+static INLINE void get_xor(byte *digest, word32 digLen, byte* md5, byte* sha)
+{
+    word32 i;
+
+    for (i = 0; i < digLen; i++) 
+        digest[i] = md5[i] ^ sha[i];
+}
+
+
+
+/* compute p_hash for MD5, SHA-1, or SHA-256 for TLSv1 PRF */
+void p_hash(byte* result, word32 resLen, const byte* secret, word32 secLen,
+            const byte* seed, word32 seedLen, int hash)
+{
+    word32   len = hash == md5_mac ? MD5_DIGEST_SIZE : hash == sha_mac ?
+                                           SHA_DIGEST_SIZE : SHA256_DIGEST_SIZE;
+    word32   times = resLen / len;
+    word32   lastLen = resLen % len;
+    word32   lastTime;
+    word32   i;
+    word32   idx = 0;
+    byte     previous[SHA256_DIGEST_SIZE];  /* max size */
+    byte     current[SHA256_DIGEST_SIZE];   /* max size */
+
+    Hmac hmac;
+
+    if (lastLen) times += 1;
+    lastTime = times - 1;
+
+    HmacSetKey(&hmac, hash == md5_mac ? MD5 : hash == sha_mac ? SHA : SHA256,
+               secret, secLen);
+    HmacUpdate(&hmac, seed, seedLen);       /* A0 = seed */
+    HmacFinal(&hmac, previous);             /* A1 */
+
+    for (i = 0; i < times; i++) {
+        HmacUpdate(&hmac, previous, len);
+        HmacUpdate(&hmac, seed, seedLen);
+        HmacFinal(&hmac, current);
+
+        if ( (i == lastTime) && lastLen)
+            XMEMCPY(&result[idx], current, lastLen);
+        else {
+            XMEMCPY(&result[idx], current, len);
+            idx += len;
+            HmacUpdate(&hmac, previous, len);
+            HmacFinal(&hmac, previous);
+        }
+    }
+}
+
+
+
+/* compute TLSv1 PRF (pseudo random function using HMAC) */
+static void PRF(byte* digest, word32 digLen, const byte* secret, word32 secLen,
+            const byte* label, word32 labLen, const byte* seed, word32 seedLen,
+            int useSha256)
+{
+    word32 half = (secLen + 1) / 2;
+
+    byte md5_half[MAX_PRF_HALF];        /* half is real size */
+    byte sha_half[MAX_PRF_HALF];        /* half is real size */
+    byte labelSeed[MAX_PRF_LABSEED];    /* labLen + seedLen is real size */
+    byte md5_result[MAX_PRF_DIG];       /* digLen is real size */
+    byte sha_result[MAX_PRF_DIG];       /* digLen is real size */
+
+    if (half > MAX_PRF_HALF)
+        return;
+    if (labLen + seedLen > MAX_PRF_LABSEED)
+        return;
+    if (digLen > MAX_PRF_DIG)
+        return;
+    
+    XMEMCPY(md5_half, secret, half);
+    XMEMCPY(sha_half, secret + half - secLen % 2, half);
+
+    XMEMCPY(labelSeed, label, labLen);
+    XMEMCPY(labelSeed + labLen, seed, seedLen);
+
+    if (useSha256) {
+        p_hash(digest, digLen, secret, secLen, labelSeed, labLen + seedLen,
+               sha256_mac);
+        return;
+    }
+
+    p_hash(md5_result, digLen, md5_half, half, labelSeed, labLen + seedLen,
+           md5_mac);
+    p_hash(sha_result, digLen, sha_half, half, labelSeed, labLen + seedLen,
+           sha_mac);
+    get_xor(digest, digLen, md5_result, sha_result);
+}
+
+
+void BuildTlsFinished(SSL* ssl, Hashes* hashes, const byte* sender)
+{
+    const byte* side;
+    byte handshake_hash[FINISHED_SZ];
+
+    Md5Final(&ssl->hashMd5, handshake_hash);
+    ShaFinal(&ssl->hashSha, &handshake_hash[MD5_DIGEST_SIZE]);
+   
+    if ( XSTRNCMP((const char*)sender, (const char*)client, SIZEOF_SENDER) == 0)
+        side = tls_client;
+    else
+        side = tls_server;
+
+    PRF(hashes->md5, TLS_FINISHED_SZ, ssl->arrays.masterSecret, SECRET_LEN,
+        side, FINISHED_LABEL_SZ, handshake_hash, FINISHED_SZ,
+        IsAtLeastTLSv1_2(ssl));
+}
+
+
+ProtocolVersion MakeTLSv1(void)
+{
+    ProtocolVersion pv;
+    pv.major = SSLv3_MAJOR;
+    pv.minor = TLSv1_MINOR;
+
+    return pv;
+}
+
+
+ProtocolVersion MakeTLSv1_1(void)
+{
+    ProtocolVersion pv;
+    pv.major = SSLv3_MAJOR;
+    pv.minor = TLSv1_1_MINOR;
+
+    return pv;
+}
+
+
+ProtocolVersion MakeTLSv1_2(void)
+{
+    ProtocolVersion pv;
+    pv.major = SSLv3_MAJOR;
+    pv.minor = TLSv1_2_MINOR;
+
+    return pv;
+}
+
+
+static const byte master_label[MASTER_LABEL_SZ + 1] = "master secret";
+static const byte key_label   [KEY_LABEL_SZ + 1]    = "key expansion";
+
+
+int DeriveTlsKeys(SSL* ssl)
+{
+    int length = 2 * ssl->specs.hash_size + 
+                 2 * ssl->specs.key_size  +
+                 2 * ssl->specs.iv_size;
+    byte         seed[SEED_LEN];
+    byte         key_data[MAX_PRF_DIG];
+
+    XMEMCPY(seed, ssl->arrays.serverRandom, RAN_LEN);
+    XMEMCPY(&seed[RAN_LEN], ssl->arrays.clientRandom, RAN_LEN);
+
+    PRF(key_data, length, ssl->arrays.masterSecret, SECRET_LEN, key_label,
+        KEY_LABEL_SZ, seed, SEED_LEN, IsAtLeastTLSv1_2(ssl));
+
+    return StoreKeys(ssl, key_data);
+}
+
+
+int MakeTlsMasterSecret(SSL* ssl)
+{
+    byte seed[SEED_LEN];
+    
+    XMEMCPY(seed, ssl->arrays.clientRandom, RAN_LEN);
+    XMEMCPY(&seed[RAN_LEN], ssl->arrays.serverRandom, RAN_LEN);
+
+    PRF(ssl->arrays.masterSecret, SECRET_LEN,
+        ssl->arrays.preMasterSecret, ssl->arrays.preMasterSz,
+        master_label, MASTER_LABEL_SZ, 
+        seed, SEED_LEN, IsAtLeastTLSv1_2(ssl));
+
+#ifdef SHOW_SECRETS
+    {
+        int i;
+        printf("master secret: ");
+        for (i = 0; i < SECRET_LEN; i++)
+            printf("%02x", ssl->arrays.masterSecret[i]);
+        printf("\n");
+    }
+#endif
+
+    return DeriveTlsKeys(ssl);
+}
+
+
+/*** next for static INLINE s copied from cyassl_int.c ***/
+
+/* convert 16 bit integer to opaque */
+static void INLINE c16toa(word16 u16, byte* c)
+{
+    c[0] = (u16 >> 8) & 0xff;
+    c[1] =  u16 & 0xff;
+}
+
+
+/* convert 32 bit integer to opaque */
+static INLINE void c32toa(word32 u32, byte* c)
+{
+    c[0] = (u32 >> 24) & 0xff;
+    c[1] = (u32 >> 16) & 0xff;
+    c[2] = (u32 >>  8) & 0xff;
+    c[3] =  u32 & 0xff;
+}
+
+
+static INLINE word32 GetSEQIncrement(SSL* ssl, int verify)
+{
+#ifdef CYASSL_DTLS
+    if (ssl->options.dtls) {
+        if (verify)
+            return ssl->keys.dtls_peer_sequence_number; /* explicit from peer */
+        else
+            return ssl->keys.dtls_sequence_number - 1; /* already incremented */
+    }
+#endif
+    if (verify)
+        return ssl->keys.peer_sequence_number++; 
+    else
+        return ssl->keys.sequence_number++; 
+}
+
+
+#ifdef CYASSL_DTLS
+
+static INLINE word32 GetEpoch(SSL* ssl, int verify)
+{
+    if (verify)
+        return ssl->keys.dtls_peer_epoch; 
+    else
+        return ssl->keys.dtls_epoch; 
+}
+
+#endif /* CYASSL_DTLS */
+
+
+static INLINE const byte* GetMacSecret(SSL* ssl, int verify)
+{
+    if ( (ssl->options.side == CLIENT_END && !verify) ||
+         (ssl->options.side == SERVER_END &&  verify) )
+        return ssl->keys.client_write_MAC_secret;
+    else
+        return ssl->keys.server_write_MAC_secret;
+}
+
+/*** end copy ***/
+
+
+/* TLS type HAMC */
+void TLS_hmac(SSL* ssl, byte* digest, const byte* buffer, word32 sz,
+              int content, int verify)
+{
+    Hmac hmac;
+    byte seq[SEQ_SZ] = { 0x00, 0x00, 0x00, 0x00 };
+    byte length[LENGTH_SZ];
+    byte inner[ENUM_LEN + VERSION_SZ + LENGTH_SZ]; /* type + version +len */
+    int  type;
+
+    c16toa((word16)sz, length);
+#ifdef CYASSL_DTLS
+    if (ssl->options.dtls)
+        c16toa(GetEpoch(ssl, verify), seq);
+#endif
+    c32toa(GetSEQIncrement(ssl, verify), &seq[sizeof(word32)]);
+    
+    if (ssl->specs.mac_algorithm == md5_mac)
+        type = MD5;
+    else
+        type = SHA;
+    HmacSetKey(&hmac, type, GetMacSecret(ssl, verify), ssl->specs.hash_size);
+    
+    HmacUpdate(&hmac, seq, SEQ_SZ);                               /* seq_num */
+    inner[0] = content;                                           /* type */
+    inner[ENUM_LEN] = ssl->version.major;
+    inner[ENUM_LEN + ENUM_LEN] = ssl->version.minor;              /* version */
+    XMEMCPY(&inner[ENUM_LEN + VERSION_SZ], length, LENGTH_SZ);     /* length */
+    HmacUpdate(&hmac, inner, sizeof(inner));
+    HmacUpdate(&hmac, buffer, sz);                                /* content */
+    HmacFinal(&hmac, digest);
+}
+
+
+#ifndef NO_CYASSL_CLIENT
+
+    SSL_METHOD* TLSv1_client_method(void)
+    {
+        SSL_METHOD* method = (SSL_METHOD*) XMALLOC(sizeof(SSL_METHOD), 0,
+                                                   DYNAMIC_TYPE_METHOD);
+        if (method)
+            InitSSL_Method(method, MakeTLSv1());
+        return method;
+    }
+
+
+    SSL_METHOD* TLSv1_1_client_method(void)
+    {
+        SSL_METHOD* method = (SSL_METHOD*) XMALLOC(sizeof(SSL_METHOD), 0,
+                                                   DYNAMIC_TYPE_METHOD);
+        if (method)
+            InitSSL_Method(method, MakeTLSv1_1());
+        return method;
+    }
+
+
+    SSL_METHOD* TLSv1_2_client_method(void)
+    {
+        SSL_METHOD* method = (SSL_METHOD*) XMALLOC(sizeof(SSL_METHOD), 0,
+                                                   DYNAMIC_TYPE_METHOD);
+        if (method)
+            InitSSL_Method(method, MakeTLSv1_2());
+        return method;
+    }
+
+
+    /* TODO: add downgrade */
+    SSL_METHOD* SSLv23_client_method(void)
+    {
+        SSL_METHOD* method = (SSL_METHOD*) XMALLOC(sizeof(SSL_METHOD), 0,
+                                                   DYNAMIC_TYPE_METHOD);
+        if (method)
+            InitSSL_Method(method, MakeTLSv1());
+        return method;
+    }
+
+
+#endif /* NO_CYASSL_CLIENT */
+
+
+
+#ifndef NO_CYASSL_SERVER
+
+    SSL_METHOD* TLSv1_server_method(void)
+    {
+        SSL_METHOD* method = (SSL_METHOD*) XMALLOC(sizeof(SSL_METHOD), 0, 
+                                                   DYNAMIC_TYPE_METHOD);
+        if (method) {
+            InitSSL_Method(method, MakeTLSv1());
+            method->side = SERVER_END;
+        }
+        return method;
+    }
+
+
+    SSL_METHOD* TLSv1_1_server_method(void)
+    {
+        SSL_METHOD* method = (SSL_METHOD*) XMALLOC(sizeof(SSL_METHOD), 0,
+                                                   DYNAMIC_TYPE_METHOD);
+        if (method) {
+            InitSSL_Method(method, MakeTLSv1_1());
+            method->side = SERVER_END;
+        }
+        return method;
+    }
+
+
+    SSL_METHOD* TLSv1_2_server_method(void)
+    {
+        SSL_METHOD* method = (SSL_METHOD*) XMALLOC(sizeof(SSL_METHOD), 0,
+                                                   DYNAMIC_TYPE_METHOD);
+        if (method) {
+            InitSSL_Method(method, MakeTLSv1_2());
+            method->side = SERVER_END;
+        }
+        return method;
+    }
+
+
+    SSL_METHOD *SSLv23_server_method(void)
+    {
+        SSL_METHOD* method = (SSL_METHOD*) XMALLOC(sizeof(SSL_METHOD), 0,
+                                                   DYNAMIC_TYPE_METHOD);
+        if (method) {
+            InitSSL_Method(method, MakeTLSv1());
+            method->side      = SERVER_END;
+            method->downgrade = 1;
+        }
+        return method;
+    }
+
+
+
+#endif /* NO_CYASSL_SERVER */
+
+#else /* NO_TLS */
+
+/* catch CyaSSL programming errors */
+void BuildTlsFinished(SSL* ssl, Hashes* hashes, const byte* sender)
+{
+   
+}
+
+
+int DeriveTlsKeys(SSL* ssl)
+{
+    return -1;
+}
+
+
+int MakeTlsMasterSecret(SSL* ssl)
+{ 
+    return -1;
+}
+
+#endif /* NO_TLS */
+
diff --git a/sslSniffer/Makefile.am b/sslSniffer/Makefile.am
new file mode 100644
index 000000000..09b20a2ca
--- /dev/null
+++ b/sslSniffer/Makefile.am
@@ -0,0 +1,3 @@
+SUBDIRS = sslSnifferTest
+EXTRA_DIST = sslSniffer.vcproj
+
diff --git a/sslSniffer/sslSniffer.vcproj b/sslSniffer/sslSniffer.vcproj
new file mode 100755
index 000000000..e6e33c626
--- /dev/null
+++ b/sslSniffer/sslSniffer.vcproj
@@ -0,0 +1,206 @@
+
+
+	
+		
+	
+	
+	
+	
+		
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+		
+		
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+		
+	
+	
+	
+	
+		
+			
+			
+		
+		
+			
+			
+		
+		
+			
+			
+		
+	
+	
+	
+
diff --git a/sslSniffer/sslSnifferTest/Makefile.am b/sslSniffer/sslSnifferTest/Makefile.am
new file mode 100644
index 000000000..3d6ff1fe6
--- /dev/null
+++ b/sslSniffer/sslSnifferTest/Makefile.am
@@ -0,0 +1,11 @@
+INCLUDES = -I../../include
+bin_PROGRAMS    = snifftest
+snifftest_SOURCES  = snifftest.c
+snifftest_LDFLAGS  = -L../../src
+
+if BUILD_SNIFFER
+snifftest_LDADD        = ../../src/libcyassl.la -lpcap
+snifftest_DEPENDENCIES = ../../src/libcyassl.la
+endif
+
+EXTRA_DIST = sslSniffTest.vcproj
diff --git a/sslSniffer/sslSnifferTest/snifftest.c b/sslSniffer/sslSnifferTest/snifftest.c
new file mode 100755
index 000000000..f63f84c69
--- /dev/null
+++ b/sslSniffer/sslSnifferTest/snifftest.c
@@ -0,0 +1,214 @@
+/* snifftest.c */
+
+#ifdef _WIN32
+    #define CYASSL_SNIFFER
+#endif
+
+#ifndef CYASSL_SNIFFER
+
+/* blank build */
+#include 
+int main()
+{
+    printf("do ./configure --enable-sniffer to enable build support\n");
+    return 0;
+}
+
+#else
+/* do a full build */
+
+#ifdef _MSC_VER
+	/* builds on *nix too, for scanf device and port */
+	#define _CRT_SECURE_NO_WARNINGS
+#endif
+
+#include      /* pcap stuff */
+#include          /* printf */
+#include         /* EXIT_SUCCESS */
+#include         /* signal */
+
+#include "sniffer.h"
+
+
+#ifndef _WIN32
+    #include 
+#endif
+
+typedef unsigned char byte;
+
+enum {
+    ETHER_IF_FRAME_LEN = 14,   /* ethernet interface frame length */
+    LOCAL_IF_FRAME_LEN =  4,   /* localhost interface frame length  */
+};
+
+
+pcap_t* pcap = 0;
+pcap_if_t *alldevs;
+
+static void sig_handler(const int sig) 
+{
+    printf("SIGINT handled.\n");
+    if (pcap)
+        pcap_close(pcap);
+	pcap_freealldevs(alldevs);
+#ifndef _WIN32
+    ssl_FreeSniffer();
+#endif
+    exit(EXIT_SUCCESS);
+}
+
+
+void err_sys(const char* msg)
+{
+	fprintf(stderr, "%s\n", msg);
+	exit(EXIT_FAILURE);
+}
+
+
+#ifdef _WIN32
+	#define SNPRINTF _snprintf
+#else
+	#define SNPRINTF snprintf
+#endif
+
+
+char* iptos(unsigned int addr)
+{
+	static char    output[32];
+	byte *p = (byte*)&addr;
+
+	SNPRINTF(output, sizeof(output), "%d.%d.%d.%d", p[0], p[1], p[2], p[3]);
+
+	return output;
+}
+
+
+int main(int argc, char** argv)
+{
+    int          ret;
+	int		     inum;
+	int		     port;
+	int		     i = 0;
+    char         err[PCAP_ERRBUF_SIZE];
+	char         filter[32];
+	char         loopback = 0;
+	char        *server = NULL;
+	struct       bpf_program fp;
+	pcap_if_t   *d;
+	pcap_addr_t *a;
+
+    signal(SIGINT, sig_handler);
+
+#ifndef _WIN32
+    ssl_InitSniffer();
+#endif
+    ssl_Trace("./tracefile.txt", err);
+
+	if (pcap_findalldevs(&alldevs, err) == -1)
+		err_sys("Error in pcap_findalldevs");
+
+	for (d = alldevs; d; d=d->next) {
+		printf("%d. %s", ++i, d->name);
+		if (d->description)
+			printf(" (%s)\n", d->description);
+		else
+			printf(" (No description available)\n");
+	}
+
+	if (i == 0)
+		err_sys("No interfaces found! Make sure pcap or WinPcap is installed "
+                "correctly and you have sufficient permissions");
+
+	printf("Enter the interface number (1-%d): ", i);
+	scanf("%d", &inum);
+
+	if (inum < 1 || inum > i)
+		err_sys("Interface number out of range");
+
+	/* Jump to the selected adapter */
+	for (d = alldevs, i = 0; i < inum - 1; d = d->next, i++);
+
+	pcap = pcap_create(d->name, err);
+
+    if (pcap == NULL) printf("pcap_create failed %s\n", err);
+
+	if (d->flags & PCAP_IF_LOOPBACK)
+		loopback = 1;
+
+	/* get an IPv4 address */
+	for (a = d->addresses; a; a = a->next) {
+		switch(a->addr->sa_family)
+		{
+			case AF_INET:
+				server =iptos(((struct sockaddr_in *)a->addr)->sin_addr.s_addr);
+				printf("server = %s\n", server);
+				break;
+		}
+	}
+	if (server == NULL)
+		err_sys("Unable to get device IPv4 address");
+
+    ret = pcap_set_snaplen(pcap, 65536);
+    if (ret != 0) printf("pcap_set_snaplen failed %s\n", pcap_geterr(pcap));
+
+    ret = pcap_set_timeout(pcap, 1000); 
+    if (ret != 0) printf("pcap_set_timeout failed %s\n", pcap_geterr(pcap));
+
+    ret = pcap_set_buffer_size(pcap, 1000000); 
+    if (ret != 0)
+		printf("pcap_set_buffer_size failed %s\n", pcap_geterr(pcap));
+
+    ret = pcap_set_promisc(pcap, 1); 
+    if (ret != 0) printf("pcap_set_promisc failed %s\n", pcap_geterr(pcap));
+
+
+    ret = pcap_activate(pcap);
+    if (ret != 0) printf("pcap_activate failed %s\n", pcap_geterr(pcap));
+
+	printf("Enter the port to scan: ");
+	scanf("%d", &port);
+
+	SNPRINTF(filter, sizeof(filter), "tcp and port %d", port);
+
+	ret = pcap_compile(pcap, &fp, filter, 0, 0);
+    if (ret != 0) printf("pcap_compile failed %s\n", pcap_geterr(pcap));
+
+    ret = pcap_setfilter(pcap, &fp);
+    if (ret != 0) printf("pcap_setfilter failed %s\n", pcap_geterr(pcap));
+
+    ret = ssl_SetPrivateKey(server, port, "../../certs/server-key.pem",
+                            FILETYPE_PEM, NULL, err);
+    if (ret != 0)
+        err_sys(err);
+
+    while (1) {
+        struct pcap_pkthdr header;
+        const unsigned char* packet = pcap_next(pcap, &header);
+        if (packet) {
+
+            byte data[65535];
+
+            if (header.caplen > 40)  { /* min ip(20) + min tcp(20) */
+				int frame = ETHER_IF_FRAME_LEN;
+				if (loopback)
+					frame = LOCAL_IF_FRAME_LEN;
+				packet        += frame;
+				header.caplen -= frame;					
+            }
+            else
+                continue;
+
+            ret = ssl_DecodePacket(packet, header.caplen, data, err);
+            if (ret < 0)
+                printf("ssl_Decode ret = %d, %s\n", ret, err);
+            if (ret > 0) {
+                data[ret] = 0;
+				printf("SSL App Data:%s\n", data);
+            }
+        }
+    }
+
+    return 0;
+}
+
+#endif /* full build */
diff --git a/sslSniffer/sslSnifferTest/sslSniffTest.vcproj b/sslSniffer/sslSnifferTest/sslSniffTest.vcproj
new file mode 100755
index 000000000..0a45e3ea1
--- /dev/null
+++ b/sslSniffer/sslSnifferTest/sslSniffTest.vcproj
@@ -0,0 +1,199 @@
+
+
+	
+		
+	
+	
+	
+	
+		
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+		
+		
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+		
+	
+	
+	
+	
+		
+			
+			
+		
+		
+		
+		
+		
+	
+	
+	
+
diff --git a/swig/PythonBuild.sh b/swig/PythonBuild.sh
new file mode 100755
index 000000000..0fc2a880a
--- /dev/null
+++ b/swig/PythonBuild.sh
@@ -0,0 +1,9 @@
+#!/bin/bash
+echo
+swig -python cyassl.i
+pythonIncludes=`python-config --includes`
+pythonLibs=`python-config --libs`
+gcc -c -fpic cyassl_wrap.c -I$pythonIncludes -I/usr/local/cyassl/include -DHAVE_CONFIG_H
+gcc -c -fpic cyassl_adds.c -I/usr/local/cyassl/include
+gcc -shared -flat_namespace  cyassl_adds.o  cyassl_wrap.o -lcyassl -L/usr/local/cyassl/lib $pythonLibs -o _cyassl.so
+python runme.py
diff --git a/swig/README b/swig/README
new file mode 100644
index 000000000..302bc6be7
--- /dev/null
+++ b/swig/README
@@ -0,0 +1,44 @@
+
+
+Initial swig interface file
+
+Please send questions to support@yassl.com
+
+
+
+**Python Support**
+
+    For Linux, OS X, or *nix
+
+1) build CyaSSL with fpic on Linux, not needed on OS X
+    ./configure --disable-shared CFLAGS=-fpic
+    make
+    sudo make install
+
+
+2) start the example echoserver from the examples/echoserver directory
+    ./echoserver
+
+3) run ./PtyonBuild.sh from this directory it will
+    a) build the swig wrapper file
+    b) compile the swig wrapper and cyassl wrapper files
+    c) place them into a cyassl shared library for python
+    d) run runme.py which will connect to the CyaSSL echo server, write a
+       string, then read the result and output it
+
+
+    Windows only 
+
+1) Make sure the install path to cyassl doesn't have any spaces anywhere in the
+   directory path because swig doesn't like that
+2) Have python for Windows installed, note install directory
+3) Have swigwin installed, note install directory
+4) Make sure swigwin install direcotry is added to PATH env. variable
+5) Make sure env. variables PYTHON_INCLUDE and PYTHON_LIB are set correctly e.g.
+    PYTHON_INCLUE="c:\Python26\include"
+    PYTHON_LIB="c:\Python26\libs\python26.lib"
+6) Build python_cyassl in Release mode only, Debug build fails to find a debug
+    python library that isn't included by default
+7) The outputs _cyassl.pyd and cyassl.py are the cyassl import library
+8) Can now run python runme.py from the swig directory 
+
diff --git a/swig/cyassl.i b/swig/cyassl.i
new file mode 100644
index 000000000..8e5c53cc7
--- /dev/null
+++ b/swig/cyassl.i
@@ -0,0 +1,42 @@
+
+
+%module cyassl
+%{
+    #include "openssl/ssl.h"
+    #include "rsa.h"
+
+    /* defn adds */
+    char* CyaSSL_error_string(int err);
+    int   CyaSSL_connect(SSL*, const char* server, int port);
+    RNG*  GetRng(void);
+    RsaKey* GetRsaPrivateKey(const char* file);
+    void    FillSignStr(unsigned char*, const char*, int);
+%}
+
+
+SSL_METHOD* TLSv1_client_method(void);
+SSL_CTX*    SSL_CTX_new(SSL_METHOD*);
+int         SSL_CTX_load_verify_locations(SSL_CTX*, const char*, const char*);
+SSL*        SSL_new(SSL_CTX*);
+int         SSL_get_error(SSL*, int);
+int         SSL_write(SSL*, const char*, int);
+char*       CyaSSL_error_string(int);
+int         CyaSSL_connect(SSL*, const char* server, int port);
+
+int         RsaSSL_Sign(const unsigned char* in, int inLen, unsigned char* out, int outLen, RsaKey* key, RNG* rng);
+
+int         RsaSSL_Verify(const unsigned char* in, int inLen, unsigned char* out, int outLen, RsaKey* key);
+
+RNG* GetRng(void);
+RsaKey* GetRsaPrivateKey(const char* file);
+void    FillSignStr(unsigned char*, const char*, int);
+
+%include carrays.i
+%include cdata.i
+%array_class(unsigned char, byteArray);
+int         SSL_read(SSL*, unsigned char*, int);
+
+
+#define    SSL_FAILURE      0
+#define    SSL_SUCCESS      1
+
diff --git a/swig/cyassl_adds.c b/swig/cyassl_adds.c
new file mode 100644
index 000000000..9dfae43b0
--- /dev/null
+++ b/swig/cyassl_adds.c
@@ -0,0 +1,208 @@
+/* cyassl_adds.c */
+#ifndef _WIN32
+    #define HAVE_CONFIG_H
+#endif
+
+#include "openssl/ssl.h"
+#include "rsa.h"
+#include "asn.h"
+
+#include 
+#include 
+#include 
+#include 
+
+#ifdef _WIN32
+    #include 
+    #include 
+    #ifdef TEST_IPV6            /* don't require newer SDK for IPV4 */
+	    #include 
+        #include 
+    #endif
+    #define SOCKET_T int
+#else
+    #include 
+    #include 
+    #include 
+    #include 
+    #include 
+    #include 
+    #include 
+    #include 
+    #include 
+    #include 
+    #ifdef NON_BLOCKING
+        #include 
+    #endif
+    #ifdef TEST_IPV6
+        #include 
+    #endif
+    #define SOCKET_T unsigned int
+#endif /* _WIN32 */
+
+#ifdef _MSC_VER
+    /* disable conversion warning */
+    /* 4996 warning to use MS extensions e.g., strcpy_s instead of strncpy */
+    #pragma warning(disable:4244 4996)
+#endif
+
+#if defined(__MACH__) || defined(_WIN32)
+    #ifndef _SOCKLEN_T
+        typedef int socklen_t;
+    #endif
+#endif
+
+
+/* HPUX doesn't use socklent_t for third parameter to accept */
+#if !defined(__hpux__)
+    typedef socklen_t* ACCEPT_THIRD_T;
+#else
+    typedef int*       ACCEPT_THIRD_T;
+#endif
+
+
+#ifdef _WIN32
+    #define CloseSocket(s) closesocket(s)
+    #define StartTCP() { WSADATA wsd; WSAStartup(0x0002, &wsd); }
+#else
+    #define CloseSocket(s) close(s)
+    #define StartTCP() 
+#endif
+
+
+#ifdef TEST_IPV6
+    typedef struct sockaddr_in6 SOCKADDR_IN_T;
+    #define AF_INET_V    AF_INET6
+#else
+    typedef struct sockaddr_in  SOCKADDR_IN_T;
+    #define AF_INET_V    AF_INET
+#endif
+   
+
+enum {
+    SSL_BLOCKING    = 2,
+    SSL_NONBLOCKING = 4
+};
+
+
+static int tcp_socket(SOCKET_T* sockfd, SOCKADDR_IN_T* addr, const char* peer,
+                       short port)
+{
+    const char* host = peer;
+
+    /* peer could be in human readable form */
+    if (isalpha(peer[0])) {
+        struct hostent* entry = gethostbyname(peer);
+
+        if (entry) {
+            struct sockaddr_in tmp;
+            memset(&tmp, 0, sizeof(struct sockaddr_in));
+            memcpy(&tmp.sin_addr.s_addr, entry->h_addr_list[0],entry->h_length);
+            host = inet_ntoa(tmp.sin_addr);
+        }
+        else
+            return -1;   /* no entry for host */ 
+    }
+
+    *sockfd = socket(AF_INET, SOCK_STREAM, 0);
+    memset(addr, 0, sizeof(SOCKADDR_IN_T));
+
+    addr->sin_family = AF_INET;
+    addr->sin_port = htons(port);
+    addr->sin_addr.s_addr = inet_addr(host);
+
+#ifdef SO_NOSIGPIPE
+    {
+        int on = 1;
+        socklen_t len = sizeof(on);
+        setsockopt(*sockfd, SOL_SOCKET, SO_NOSIGPIPE, &on, len);
+    }
+#endif
+
+    return 0;
+}
+
+
+static int tcp_connect(SOCKET_T* sockfd, const char* ip, short port)
+{
+    SOCKADDR_IN_T addr;
+    int ret = tcp_socket(sockfd, &addr, ip, port);
+    if (ret != 0) return ret;
+
+    if (connect(*sockfd, (const struct sockaddr*)&addr, sizeof(addr)) != 0)
+        return -2; /* can't connect */
+
+    return 0;
+}
+    
+
+int CyaSSL_connect(SSL* ssl, const char* server, int port)
+{
+    SOCKET_T sockfd;
+    int ret = tcp_connect(&sockfd, server, port);
+    if (ret != 0) return ret;
+    
+    SSL_set_fd(ssl, sockfd);
+
+    return SSL_connect(ssl);
+}
+
+
+char* CyaSSL_error_string(int err)
+{
+    static char buffer[80];
+
+    return ERR_error_string(err, buffer);
+}
+
+
+RNG* GetRng(void)
+{
+    RNG* rng = (RNG*)malloc(sizeof(RNG));
+
+    if (rng)
+        if (InitRng(rng) != 0) {
+            free(rng);
+            rng = 0;
+        }
+
+    return rng;
+}
+
+
+RsaKey* GetRsaPrivateKey(const char* keyFile)
+{
+    RsaKey* key = (RsaKey*)malloc(sizeof(RsaKey));
+
+    if (key) {
+        byte   tmp[1024];
+        size_t bytes;
+        int    ret;
+        word32 idx = 0;
+        FILE*  file = fopen(keyFile, "rb");
+
+        if (!file) {
+            free(key);
+            return 0;
+        }
+
+        bytes = fread(tmp, 1, sizeof(tmp), file);
+        fclose(file);
+        InitRsaKey(key, 0);
+
+        ret = RsaPrivateKeyDecode(tmp, &idx, key, (word32)bytes);
+        if (ret != 0) {
+            FreeRsaKey(key);
+            free(key);
+            return 0;
+        }
+    }
+    return key;
+}
+
+
+void FillSignStr(unsigned char* dst, const char* src, int size)
+{
+    memcpy(dst, src, size);
+}
+
diff --git a/swig/python_cyassl.vcproj b/swig/python_cyassl.vcproj
new file mode 100755
index 000000000..d4373a949
--- /dev/null
+++ b/swig/python_cyassl.vcproj
@@ -0,0 +1,225 @@
+
+
+	
+		
+	
+	
+	
+	
+		
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+		
+		
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+		
+	
+	
+	
+	
+		
+			
+			
+			
+			
+		
+		
+		
+		
+		
+		
+			
+				
+			
+			
+				
+			
+		
+	
+	
+	
+
diff --git a/swig/rsasign.py b/swig/rsasign.py
new file mode 100644
index 000000000..ad2e114f8
--- /dev/null
+++ b/swig/rsasign.py
@@ -0,0 +1,35 @@
+# file: rsasign.py
+
+import cyassl 
+
+
+# start Random Number Generator
+rng = cyassl.GetRng()
+if rng == None:
+    print "Couldn't get an RNG"
+    exit(-1)
+
+# load RSA private key in DER format
+key = cyassl.GetRsaPrivateKey("../certs/client-key.der")
+if key == None:
+    print "Couldn't load DER private key file"
+    exit(-1)
+
+# Make byte Arrays and fill input
+signOutput = cyassl.byteArray(128)   # 128 allows 1024 bit private key
+signStr    = cyassl.byteArray(25)    # input can't be larger then key size
+                                     # 64 for 512 bit 128 for 1024 bit
+cyassl.FillSignStr(signStr, "Everybody gets Friday off", 25)
+
+# Do RSA Sign
+signedSize = cyassl.RsaSSL_Sign(signStr, 25, signOutput, 128, key, rng) 
+
+# Show output 
+print "Signed Size = ", signedSize, " signed array = ", cyassl.cdata(signOutput, signedSize)
+
+# let's verify this worked
+signVerify = cyassl.byteArray(signedSize)
+verifySize = cyassl.RsaSSL_Verify(signOutput, signedSize, signVerify, signedSize, key)
+
+print "Verify Size = ", verifySize, " verify array = ", cyassl.cdata(signVerify, verifySize)
+
diff --git a/swig/runme.py b/swig/runme.py
new file mode 100644
index 000000000..1734a0196
--- /dev/null
+++ b/swig/runme.py
@@ -0,0 +1,30 @@
+# file: runme.py
+
+import cyassl 
+
+print ""
+print "Trying to connect to the echo server..."
+
+ctx    = cyassl.SSL_CTX_new(cyassl.TLSv1_client_method())
+ret    = cyassl.SSL_CTX_load_verify_locations(ctx, "../certs/ca-cert.pem", None)
+ssl    = cyassl.SSL_new(ctx)
+
+ret    = cyassl.CyaSSL_connect(ssl, "localhost", 11111)
+
+if ret != cyassl.SSL_SUCCESS:
+    print "Couldn't do SSL connect"
+    err    = cyassl.SSL_get_error(ssl, 0)
+    print "error string = ", cyassl.CyaSSL_error_string(err)
+    exit(-1)
+
+print "...Connected"
+written = cyassl.SSL_write(ssl, "hello from python\r\n", 19)
+
+if written > 0:
+    print "Wrote ", written, " bytes"
+
+byteArray = cyassl.byteArray(100)
+readBytes = cyassl.SSL_read(ssl, byteArray, 100)
+
+print "server reply: ", cyassl.cdata(byteArray, readBytes) 
+
diff --git a/testsuite/Makefile.am b/testsuite/Makefile.am
new file mode 100644
index 000000000..f06ff6f44
--- /dev/null
+++ b/testsuite/Makefile.am
@@ -0,0 +1,10 @@
+INCLUDES = -I../include -I../ctaocrypt/include -I../include/openssl
+bin_PROGRAMS    = testsuite
+testsuite_SOURCES = testsuite.c ../ctaocrypt/test/test.c \
+    ../examples/client/client.c ../examples/server/server.c \
+    ../examples/echoclient/echoclient.c ../examples/echoserver/echoserver.c
+AM_CFLAGS  = -DNO_MAIN_DRIVER
+testsuite_LDFLAGS      = -L../src
+testsuite_LDADD        = ../src/libcyassl.la
+testsuite_DEPENDENCIES = ../src/libcyassl.la 
+EXTRA_DIST = input quit testsuite.sln *.vcproj
diff --git a/testsuite/input b/testsuite/input
new file mode 100644
index 000000000..7364d4d0e
--- /dev/null
+++ b/testsuite/input
@@ -0,0 +1,87 @@
+/* echoclient.c  */
+
+#include "openssl/ssl.h"
+#include "../test.h"
+
+
+int main(int argc, char** argv)
+{
+    SOCKET_T sockfd = 0;
+
+    FILE* fin  = stdin;
+    FILE* fout = stdout;
+
+    int inCreated  = 0;
+    int outCreated = 0;
+
+    char send[1024];
+    char reply[1024];
+
+    SSL_METHOD* method = 0;
+    SSL_CTX*    ctx    = 0;
+    SSL*        ssl    = 0;
+
+#ifdef _WIN32
+    WSADATA wsd;
+    WSAStartup(0x0002, &wsd);
+#endif
+
+    if (argc >= 2) {
+        fin  = fopen(argv[1], "r"); 
+        inCreated = 1;
+    }
+    if (argc >= 3) {
+        fout = fopen(argv[2], "w");
+        outCreated = 1;
+    }
+
+    if (!fin)  err_sys("can't open input file");
+    if (!fout) err_sys("can't open output file");
+
+    tcp_connect(&sockfd);
+
+    method = SSLv3_client_method();
+    ctx    = SSL_CTX_new(method);
+
+    if (SSL_CTX_load_verify_locations(ctx, caCert, 0) != SSL_SUCCESS)
+        err_sys("can't load ca file");
+
+    ssl = SSL_new(ctx);
+
+    SSL_set_fd(ssl, sockfd);
+    if (SSL_connect(ssl) != SSL_SUCCESS) err_sys("SSL_connect failed");
+
+    while (fgets(send, sizeof(send), fin)) {
+
+        int  sendSz = strlen(send) + 1;
+
+        if (SSL_write(ssl, send, sendSz) != sendSz)
+            err_sys("SSL_write failed");
+
+        if (strncmp(send, "quit", 4) == 0) {
+            fputs("sending server shutdown command: quit!\n", fout);
+            break;
+        }
+
+        if (SSL_read(ssl, reply, sizeof(reply)) > 0) 
+            fputs(reply, fout);
+    }
+
+    SSL_shutdown(ssl);
+    SSL_free(ssl);
+    SSL_CTX_free(ctx);
+
+    fflush(fout);
+    if (inCreated)  fclose(fin);
+    if (outCreated) fclose(fout);
+
+#ifdef _WIN32
+    closesocket(sockfd);
+#else
+    close(sockfd);
+#endif
+
+    return 0;
+}
+
+
diff --git a/testsuite/quit b/testsuite/quit
new file mode 100644
index 000000000..3db49b3ad
--- /dev/null
+++ b/testsuite/quit
@@ -0,0 +1,2 @@
+quit
+
diff --git a/testsuite/testsuite-ntru.vcproj b/testsuite/testsuite-ntru.vcproj
new file mode 100755
index 000000000..09aac980b
--- /dev/null
+++ b/testsuite/testsuite-ntru.vcproj
@@ -0,0 +1,219 @@
+
+
+	
+		
+	
+	
+	
+	
+		
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+		
+		
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+		
+	
+	
+	
+	
+		
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+		
+		
+		
+		
+		
+	
+	
+	
+
diff --git a/testsuite/testsuite.c b/testsuite/testsuite.c
new file mode 100644
index 000000000..09e445372
--- /dev/null
+++ b/testsuite/testsuite.c
@@ -0,0 +1,200 @@
+/* testsuite.c */
+
+#include "ssl.h"
+#include "cyassl_test.h"
+#include "ctc_md5.h"
+
+#ifdef SINGLE_THREADED
+    #error testsuite needs threads to run, please run ctaocrypt/test, \
+           and the examples/ individually
+#endif
+
+void wait_tcp_ready(func_args*);
+void ctaocrypt_test(void*);
+
+void client_test(void*);
+void echoclient_test(void*);
+
+THREAD_RETURN CYASSL_API server_test(void*);
+THREAD_RETURN CYASSL_API echoserver_test(void*);
+
+void file_test(char* file, byte* hash);
+
+enum {
+    NUMARGS = 3
+};
+
+
+int main(int argc, char** argv)
+{
+    func_args args;
+    func_args server_args;
+
+    tcp_ready ready;
+    THREAD_TYPE serverThread;
+
+    StartTCP();
+
+    args.argc = server_args.argc = argc;
+    args.argv = server_args.argv = argv;
+   
+    /* CTaoCrypt test */
+    ctaocrypt_test(&args);
+    if (args.return_code != 0) return args.return_code;
+ 
+    /* Simple CyaSSL client server test */
+    InitCyaSSL();
+    InitTcpReady(&ready);
+    server_args.signal = &ready;
+    start_thread(server_test, &server_args, &serverThread);
+    wait_tcp_ready(&server_args);
+
+    client_test(&args);
+    if (args.return_code != 0) return args.return_code;
+    join_thread(serverThread);
+    if (server_args.return_code != 0) return server_args.return_code;
+
+    /* Echo input yaSSL client server test */
+    start_thread(echoserver_test, &server_args, &serverThread);
+    wait_tcp_ready(&server_args);
+    {
+        func_args echo_args;
+        char* myArgv[NUMARGS];
+
+        char argc0[32];
+        char argc1[32];
+        char argc2[32];
+
+        myArgv[0] = argc0;
+        myArgv[1] = argc1;
+        myArgv[2] = argc2;
+
+        echo_args.argc = NUMARGS;
+        echo_args.argv = myArgv;
+   
+        strcpy(echo_args.argv[0], "echoclient");
+        strcpy(echo_args.argv[1], "input");
+        strcpy(echo_args.argv[2], "output");
+        remove("output");
+
+        /* make sure OK */
+        echoclient_test(&echo_args);
+        if (echo_args.return_code != 0) return echo_args.return_code;  
+
+#ifdef CYASSL_DTLS
+        wait_tcp_ready(&server_args);
+#endif
+        /* send quit to echoserver */
+        echo_args.argc = 2;
+        strcpy(echo_args.argv[1], "quit");
+
+        echoclient_test(&echo_args);
+        if (echo_args.return_code != 0) return echo_args.return_code;
+        join_thread(serverThread);
+        if (server_args.return_code != 0) return server_args.return_code;
+    }
+
+    /* validate output equals input */
+    {
+        byte input[MD5_DIGEST_SIZE];
+        byte output[MD5_DIGEST_SIZE];
+
+        file_test("input",  input);
+        file_test("output", output);
+        if (memcmp(input, output, sizeof(input)) != 0)
+            return -1;
+    }
+
+    FreeCyaSSL();
+    FreeTcpReady(&ready);
+
+    printf("\nAll tests passed!\n");
+    return 0;
+}
+
+
+
+void wait_tcp_ready(func_args* args)
+{
+#ifdef _POSIX_THREADS
+    pthread_mutex_lock(&args->signal->mutex);
+    
+    if (!args->signal->ready)
+        pthread_cond_wait(&args->signal->cond, &args->signal->mutex);
+    args->signal->ready = 0; /* reset */
+
+    pthread_mutex_unlock(&args->signal->mutex);
+#endif
+}
+
+
+void start_thread(THREAD_FUNC fun, func_args* args, THREAD_TYPE* thread)
+{
+#ifndef _POSIX_THREADS
+    *thread = (HANDLE)_beginthreadex(0, 0, fun, args, 0, 0);
+#else
+    pthread_create(thread, 0, fun, args);
+#endif
+}
+
+
+void join_thread(THREAD_TYPE thread)
+{
+#ifndef _POSIX_THREADS
+    int res = WaitForSingleObject(thread, INFINITE);
+    assert(res == WAIT_OBJECT_0);
+    res = CloseHandle(thread);
+    assert(res);
+#else
+    pthread_join(thread, 0);
+#endif
+}
+
+
+void InitTcpReady(tcp_ready* ready)
+{
+    ready->ready = 0;
+#ifdef _POSIX_THREADS
+    pthread_mutex_init(&ready->mutex, 0);
+    pthread_cond_init(&ready->cond, 0);
+#endif
+}
+
+
+void FreeTcpReady(tcp_ready* ready)
+{
+#ifdef _POSIX_THREADS
+    pthread_mutex_destroy(&ready->mutex);
+    pthread_cond_destroy(&ready->cond);
+#endif
+}
+
+
+void file_test(char* file, byte* check)
+{
+    FILE* f;
+    int   i = 0, j;
+    Md5   md5;
+    byte  buf[1024];
+    byte  md5sum[MD5_DIGEST_SIZE];
+   
+    InitMd5(&md5); 
+    if( !( f = fopen( file, "rb" ) )) {
+        printf("Can't open %s\n", file);
+        return;
+    }
+    while( ( i = (int)fread(buf, 1, sizeof(buf), f )) > 0 )
+        Md5Update(&md5, buf, i);
+    
+    Md5Final(&md5, md5sum);
+    memcpy(check, md5sum, sizeof(md5sum));
+
+    for(j = 0; j < MD5_DIGEST_SIZE; ++j ) 
+        printf( "%02x", md5sum[j] );
+   
+    printf("  %s\n", file);
+
+    fclose(f);
+}
+
+
diff --git a/testsuite/testsuite.sln b/testsuite/testsuite.sln
new file mode 100755
index 000000000..b89dcc1f4
--- /dev/null
+++ b/testsuite/testsuite.sln
@@ -0,0 +1,20 @@
+
+Microsoft Visual Studio Solution File, Format Version 9.00
+# Visual C++ Express 2005
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testsuite", "testsuite.vcproj", "{9D4D8446-CE91-4F7A-AFF2-90D0B5DCD717}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Win32 = Debug|Win32
+		Release|Win32 = Release|Win32
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{9D4D8446-CE91-4F7A-AFF2-90D0B5DCD717}.Debug|Win32.ActiveCfg = Debug|Win32
+		{9D4D8446-CE91-4F7A-AFF2-90D0B5DCD717}.Debug|Win32.Build.0 = Debug|Win32
+		{9D4D8446-CE91-4F7A-AFF2-90D0B5DCD717}.Release|Win32.ActiveCfg = Release|Win32
+		{9D4D8446-CE91-4F7A-AFF2-90D0B5DCD717}.Release|Win32.Build.0 = Release|Win32
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+EndGlobal
diff --git a/testsuite/testsuite.vcproj b/testsuite/testsuite.vcproj
new file mode 100755
index 000000000..649ab3bab
--- /dev/null
+++ b/testsuite/testsuite.vcproj
@@ -0,0 +1,217 @@
+
+
+	
+		
+	
+	
+	
+	
+		
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+		
+		
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+		
+	
+	
+	
+	
+		
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+			
+		
+		
+		
+		
+		
+	
+	
+	
+