tls: format and send CLIENT_KEY_EXCHANGE
No binary (build failed)
—
(log yok)
| @@ -1,7 +1,7 @@ | |
| /* | |
| - | * Licensed under GPLv2, see file LICENSE in this source tree. |
| - | * |
| * Copyright (C) 2017 Denys Vlasenko | |
| + | * |
| + | * Licensed under GPLv2, see file LICENSE in this source tree. |
| */ | |
| //config:config TLS | |
| //config: bool "tls (debugging)" | |
| @@ -10,6 +10,11 @@ | |
| //applet:IF_TLS(APPLET(tls, BB_DIR_USR_BIN, BB_SUID_DROP)) | |
| //kbuild:lib-$(CONFIG_TLS) += tls.o | |
| + | //kbuild:lib-$(CONFIG_TLS) += tls_pstm.o |
| + | //kbuild:lib-$(CONFIG_TLS) += tls_pstm_montgomery_reduce.o |
| + | //kbuild:lib-$(CONFIG_TLS) += tls_pstm_mul_comba.o |
| + | //kbuild:lib-$(CONFIG_TLS) += tls_pstm_sqr_comba.o |
| + | //kbuild:lib-$(CONFIG_TLS) += tls_rsa.o |
| ////kbuild:lib-$(CONFIG_TLS) += tls_ciphers.o | |
| ////kbuild:lib-$(CONFIG_TLS) += tls_aes.o | |
| ////kbuild:lib-$(CONFIG_TLS) += tls_aes_gcm.o | |
| @@ -18,9 +23,7 @@ | |
| //usage: "HOST[:PORT]" | |
| //usage:#define tls_full_usage "\n\n" | |
| - | #include "libbb.h" |
| - | //#include "tls_cryptoapi.h" |
| - | //#include "tls_ciphers.h" |
| + | #include "tls.h" |
| #if 1 | |
| # define dbg(...) fprintf(stderr, __VA_ARGS__) | |
| @@ -28,23 +31,26 @@ | |
| # define dbg(...) ((void)0) | |
| #endif | |
| - | #define RECORD_TYPE_CHANGE_CIPHER_SPEC 20 |
| - | #define RECORD_TYPE_ALERT 21 |
| - | #define RECORD_TYPE_HANDSHAKE 22 |
| - | #define RECORD_TYPE_APPLICATION_DATA 23 |
| - | |
| - | #define HANDSHAKE_HELLO_REQUEST 0 |
| - | #define HANDSHAKE_CLIENT_HELLO 1 |
| - | #define HANDSHAKE_SERVER_HELLO 2 |
| - | #define HANDSHAKE_HELLO_VERIFY_REQUEST 3 |
| - | #define HANDSHAKE_NEW_SESSION_TICKET 4 |
| - | #define HANDSHAKE_CERTIFICATE 11 |
| - | #define HANDSHAKE_SERVER_KEY_EXCHANGE 12 |
| - | #define HANDSHAKE_CERTIFICATE_REQUEST 13 |
| - | #define HANDSHAKE_SERVER_HELLO_DONE 14 |
| - | #define HANDSHAKE_CERTIFICATE_VERIFY 15 |
| - | #define HANDSHAKE_CLIENT_KEY_EXCHANGE 16 |
| - | #define HANDSHAKE_FINISHED 20 |
| + | #define RECORD_TYPE_CHANGE_CIPHER_SPEC 20 |
| + | #define RECORD_TYPE_ALERT 21 |
| + | #define RECORD_TYPE_HANDSHAKE 22 |
| + | #define RECORD_TYPE_APPLICATION_DATA 23 |
| + | |
| + | #define HANDSHAKE_HELLO_REQUEST 0 |
| + | #define HANDSHAKE_CLIENT_HELLO 1 |
| + | #define HANDSHAKE_SERVER_HELLO 2 |
| + | #define HANDSHAKE_HELLO_VERIFY_REQUEST 3 |
| + | #define HANDSHAKE_NEW_SESSION_TICKET 4 |
| + | #define HANDSHAKE_CERTIFICATE 11 |
| + | #define HANDSHAKE_SERVER_KEY_EXCHANGE 12 |
| + | #define HANDSHAKE_CERTIFICATE_REQUEST 13 |
| + | #define HANDSHAKE_SERVER_HELLO_DONE 14 |
| + | #define HANDSHAKE_CERTIFICATE_VERIFY 15 |
| + | #define HANDSHAKE_CLIENT_KEY_EXCHANGE 16 |
| + | #define HANDSHAKE_FINISHED 20 |
| + | |
| + | #define SSL_HS_RANDOM_SIZE 32 |
| + | #define SSL_HS_RSA_PREMASTER_SIZE 48 |
| #define SSL_NULL_WITH_NULL_NULL 0x0000 | |
| #define SSL_RSA_WITH_NULL_MD5 0x0001 | |
| @@ -112,6 +118,7 @@ | |
| //TLS 1.2 | |
| #define TLS_MAJ 3 | |
| #define TLS_MIN 3 | |
| + | //#define CIPHER_ID TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA // ok, recvs SERVER_KEY_EXCHANGE *** matrixssl uses this on my box |
| //#define CIPHER_ID TLS_RSA_WITH_AES_256_CBC_SHA256 // ok, no SERVER_KEY_EXCHANGE | |
| // All GCMs: | |
| //#define CIPHER_ID TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 // SSL_ALERT_HANDSHAKE_FAILURE | |
| @@ -123,9 +130,9 @@ | |
| //#define CIPHER_ID TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 | |
| //#define CIPHER_ID TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 // SSL_ALERT_HANDSHAKE_FAILURE | |
| //#define CIPHER_ID TLS_RSA_WITH_AES_256_GCM_SHA384 // ok, no SERVER_KEY_EXCHANGE | |
| - | #define CIPHER_ID TLS_RSA_WITH_AES_128_GCM_SHA256 // ok, no SERVER_KEY_EXCHANGE |
| + | #define CIPHER_ID TLS_RSA_WITH_AES_128_GCM_SHA256 // ok, no SERVER_KEY_EXCHANGE *** select this? |
| //#define CIPHER_ID TLS_DH_anon_WITH_AES_256_CBC_SHA // SSL_ALERT_HANDSHAKE_FAILURE | |
| - | // (tested b/c this one doesn't req server certs... no luck) |
| + | //^^^^^^^^^^^^^^^^^^^^^^^ (tested b/c this one doesn't req server certs... no luck) |
| //test TLS_RSA_WITH_AES_128_CBC_SHA, in tls 1.2 it's mandated to be always supported | |
| struct record_hdr { | |
| @@ -137,8 +144,7 @@ struct record_hdr { | |
| typedef struct tls_state { | |
| int fd; | |
| - | uint8_t *pubkey; |
| - | int pubkey_len; |
| + | psRsaKey_t server_rsa_pub_key; |
| // RFC 5246 | |
| // |6.2.1. Fragmentation | |
| @@ -170,6 +176,12 @@ typedef struct tls_state { | |
| uint8_t inbuf[18*1024]; | |
| } tls_state_t; | |
| + | void tls_get_random(void *buf, unsigned len) |
| + | { |
| + | if (len != open_read_close("/dev/urandom", buf, len)) |
| + | xfunc_die(); |
| + | } |
| + | |
| static | |
| tls_state_t *new_tls_state(void) | |
| { | |
| @@ -286,7 +298,7 @@ static void send_client_hello(tls_state_t *tls) | |
| hello.len24_lo = (sizeof(hello) - sizeof(hello.xhdr) - 4); | |
| hello.proto_maj = TLS_MAJ; | |
| hello.proto_min = TLS_MIN; | |
| - | open_read_close("/dev/urandom", hello.rand32, sizeof(hello.rand32)); |
| + | tls_get_random(hello.rand32, sizeof(hello.rand32)); |
| //hello.session_id_len = 0; | |
| //hello.cipherid_len16_hi = 0; | |
| hello.cipherid_len16_lo = 2 * 1; | |
| @@ -407,7 +419,18 @@ static uint8_t *skip_der_item(uint8_t *der, uint8_t *end) | |
| return new_der; | |
| } | |
| - | static void *find_key_in_der_cert(int *key_len, uint8_t *der, int len) |
| + | static void der_binary_to_pstm(pstm_int *pstm_n, uint8_t *der, uint8_t *end) |
| + | { |
| + | uint8_t *bin_ptr; |
| + | unsigned len = get_der_len(&bin_ptr, der, end); |
| + | |
| + | dbg("binary bytes:%u, first:0x%02x\n", len, bin_ptr[0]); |
| + | pstm_init_for_read_unsigned_bin(/*pool:*/ NULL, pstm_n, len); |
| + | pstm_read_unsigned_bin(pstm_n, bin_ptr, len); |
| + | //return bin + len; |
| + | } |
| + | |
| + | static void find_key_in_der_cert(tls_state_t *tls, uint8_t *der, int len) |
| { | |
| /* Certificate is a DER-encoded data structure. Each DER element has a length, | |
| * which makes it easy to skip over large compound elements of any complexity | |
| @@ -504,19 +527,43 @@ static void *find_key_in_der_cert(int *key_len, uint8_t *der, int len) | |
| der = skip_der_item(der, end); /* validity */ | |
| der = skip_der_item(der, end); /* subject */ | |
| - | /* enter "subjectPublicKeyInfo" */ |
| + | /* enter subjectPublicKeyInfo */ |
| der = enter_der_item(der, &end); | |
| - | |
| - | /* skip "subjectPublicKeyInfo.algorithm" */ |
| + | { /* check subjectPublicKeyInfo.algorithm */ |
| + | static const uint8_t expected[] = { |
| + | 0x30,0x0d, // SEQ 13 bytes |
| + | 0x06,0x09, 0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x01, // OID RSA_KEY_ALG 42.134.72.134.247.13.1.1.1 |
| + | //0x05,0x00, // NULL |
| + | }; |
| + | if (memcmp(der, expected, sizeof(expected)) != 0) |
| + | bb_error_msg_and_die("not RSA key"); |
| + | } |
| + | /* skip subjectPublicKeyInfo.algorithm */ |
| der = skip_der_item(der, end); | |
| - | /* enter "subjectPublicKeyInfo.publicKey" */ |
| + | /* enter subjectPublicKeyInfo.publicKey */ |
| // die_if_not_this_der_type(der, end, 0x03); /* must be BITSTRING */ | |
| der = enter_der_item(der, &end); | |
| - | /* return a copy */ |
| - | *key_len = end - der; |
| - | dbg("copying key bytes:%u, first:0x%02x\n", *key_len, der[0]); |
| - | return xmemdup(der, *key_len); |
| + | /* parse RSA key: */ |
| + | //based on getAsnRsaPubKey(), pkcs1ParsePrivBin() is also of note |
| + | dbg("key bytes:%u, first:0x%02x\n", (int)(end - der), der[0]); |
| + | if (end - der < 14) xfunc_die(); |
| + | /* example format: |
| + | * ignore bits: 00 |
| + | * SEQ 0x018a/394 bytes: 3082018a |
| + | * INTEGER 0x0181/385 bytes (modulus): 02820181 XX...XXX |
| + | * INTEGER 3 bytes (exponent): 0203 010001 |
| + | */ |
| + | if (*der != 0) /* "ignore bits", should be 0 */ |
| + | xfunc_die(); |
| + | der++; |
| + | der = enter_der_item(der, &end); /* enter SEQ */ |
| + | //memset(tls->server_rsa_pub_key, 0, sizeof(tls->server_rsa_pub_key)); |
| + | der_binary_to_pstm(&tls->server_rsa_pub_key.N, der, end); /* modulus */ |
| + | der = skip_der_item(der, end); |
| + | der_binary_to_pstm(&tls->server_rsa_pub_key.e, der, end); /* exponent */ |
| + | tls->server_rsa_pub_key.size = pstm_unsigned_bin_size(&tls->server_rsa_pub_key.N); |
| + | dbg("server_rsa_pub_key.size:%d\n", tls->server_rsa_pub_key.size); |
| } | |
| static void get_server_cert_or_die(tls_state_t *tls) | |
| @@ -553,7 +600,107 @@ static void get_server_cert_or_die(tls_state_t *tls) | |
| len = len1; | |
| if (len) | |
| - | tls->pubkey = find_key_in_der_cert(&tls->pubkey_len, certbuf + 10, len); |
| + | find_key_in_der_cert(tls, certbuf + 10, len); |
| + | } |
| + | |
| + | static void send_client_key_exchange(tls_state_t *tls) |
| + | { |
| + | #if 0 //matrixssl code snippets: |
| + | int32 csRsaEncryptPub(psPool_t *pool, psPubKey_t *key, |
| + | unsigned char *in, uint32 inlen, unsigned char *out, uint32 outlen, |
| + | void *data) |
| + | { |
| + | psAssert(key->type == PS_RSA); |
| + | return psRsaEncryptPub(pool, (psRsaKey_t*)key->key, in, inlen, out, outlen, |
| + | data); |
| + | } |
| + | ... |
| + | /* pkaAfter.user is buffer len */ |
| + | if ((rc = csRsaEncryptPub(pka->pool, &ssl->sec.cert->publicKey, |
| + | ssl->sec.premaster, ssl->sec.premasterSize, pka->outbuf, |
| + | pka->user, pka->data)) < 0) { |
| + | if (rc == PS_PENDING) { |
| + | /* For these ClientKeyExchange paths, we do want to come |
| + | back through nowDoCkePka for a double pass so each |
| + | case can manage its own pkaAfter and to make sure |
| + | psX509FreeCert and sslCreateKeys() are hit below. */ |
| + | return rc; |
| + | } |
| + | psTraceIntInfo("csRsaEncryptPub in CKE failed %d\n", rc); |
| + | return MATRIXSSL_ERROR; |
| + | } |
| + | /* RSA closed the pool on second pass */ |
| + | pka->pool = NULL; |
| + | clearPkaAfter(ssl); |
| + | ... |
| + | #ifdef USE_RSA_CIPHER_SUITE |
| + | /* |
| + | Standard RSA suite |
| + | */ |
| + | ssl->sec.premasterSize = SSL_HS_RSA_PREMASTER_SIZE; |
| + | ssl->sec.premaster = psMalloc(ssl->hsPool, |
| + | SSL_HS_RSA_PREMASTER_SIZE); |
| + | if (ssl->sec.premaster == NULL) { |
| + | return SSL_MEM_ERROR; |
| + | } |
| + | |
| + | ssl->sec.premaster[0] = ssl->reqMajVer; |
| + | ssl->sec.premaster[1] = ssl->reqMinVer; |
| + | if (matrixCryptoGetPrngData(ssl->sec.premaster + 2, |
| + | SSL_HS_RSA_PREMASTER_SIZE - 2, ssl->userPtr) < 0) { |
| + | return MATRIXSSL_ERROR; |
| + | } |
| + | |
| + | /* Shedule RSA encryption. Put tmp pool under control of After */ |
| + | pkaAfter->type = PKA_AFTER_RSA_ENCRYPT; |
| + | pkaAfter->outbuf = c; |
| + | pkaAfter->data = pkiData; |
| + | pkaAfter->pool = pkiPool; |
| + | pkaAfter->user = (uint32)(end - c); /* Available space */ |
| + | |
| + | c += keyLen; |
| + | #endif |
| + | #endif // 0 |
| + | |
| + | struct client_key_exchange { |
| + | struct record_hdr xhdr; |
| + | uint8_t type; |
| + | uint8_t len24_hi, len24_mid, len24_lo; |
| + | uint8_t keylen16_hi, keylen16_lo; /* exist for RSA, but not for some other key types */ |
| + | //had a bug when had no keylen: we: |
| + | //write(3, "\x16\x03\x03\x01\x84\x10\x00\x01\x80\xXX\xXX\xXX\xXX\xXX\xXX...", 393) = 393 |
| + | //openssl: |
| + | //write to 0xe9a090 [0xf9ac20] (395 bytes => 395 (0x18B)) |
| + | //0000 - 16 03 03 01 86 10 00 01 -82 01 80 xx xx xx xx xx |
| + | uint8_t key[384]; // size?? |
| + | }; |
| + | struct client_key_exchange record; |
| + | uint8_t premaster[SSL_HS_RSA_PREMASTER_SIZE]; |
| + | |
| + | memset(&record, 0, sizeof(record)); |
| + | record.xhdr.type = RECORD_TYPE_HANDSHAKE; |
| + | record.xhdr.proto_maj = TLS_MAJ; |
| + | record.xhdr.proto_min = TLS_MIN; |
| + | record.xhdr.len16_hi = (sizeof(record) - sizeof(record.xhdr)) >> 8; |
| + | record.xhdr.len16_lo = (sizeof(record) - sizeof(record.xhdr)) & 0xff; |
| + | record.type = HANDSHAKE_CLIENT_KEY_EXCHANGE; |
| + | //record.len24_hi = 0; |
| + | record.len24_mid = (sizeof(record) - sizeof(record.xhdr) - 4) >> 8; |
| + | record.len24_lo = (sizeof(record) - sizeof(record.xhdr) - 4) & 0xff; |
| + | record.keylen16_hi = (sizeof(record) - sizeof(record.xhdr) - 6) >> 8; |
| + | record.keylen16_lo = (sizeof(record) - sizeof(record.xhdr) - 6) & 0xff; |
| + | |
| + | tls_get_random(premaster, sizeof(premaster)); |
| + | premaster[0] = TLS_MAJ; |
| + | premaster[1] = TLS_MIN; |
| + | psRsaEncryptPub(/*pool:*/ NULL, |
| + | /* psRsaKey_t* */ &tls->server_rsa_pub_key, |
| + | premaster, /*inlen:*/ sizeof(premaster), |
| + | record.key, sizeof(record.key), |
| + | data_param_ignored |
| + | ); |
| + | |
| + | xwrite(tls->fd, &record, sizeof(record)); |
| } | |
| static void tls_handshake(tls_state_t *tls) | |
| @@ -614,6 +761,8 @@ static void tls_handshake(tls_state_t *tls) | |
| // 459 bytes: | |
| // 0c 00|01|c7 03|00|17|41|04|87|94|2e|2f|68|d0|c9|f4|97|a8|2d|ef|ed|67|ea|c6|f3|b3|56|47|5d|27|b6|bd|ee|70|25|30|5e|b0|8e|f6|21|5a... | |
| //SvKey len=455^ | |
| + | // with TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA: 461 bytes: |
| + | // 0c 00|01|c9 03|00|17|41|04|cd|9b|b4|29|1f|f6|b0|c2|84|82|7f|29|6a|47|4e|ec|87|0b|c1|9c|69|e1|f8|c6|d0|53|e9|27|90|a5|c8|02|15|75... |
| dbg("got SERVER_KEY_EXCHANGE\n"); | |
| len = xread_tls_block(tls); | |
| break; | |
| @@ -624,6 +773,8 @@ static void tls_handshake(tls_state_t *tls) | |
| case HANDSHAKE_SERVER_HELLO_DONE: | |
| // 0e 000000 (len:0) | |
| dbg("got SERVER_HELLO_DONE\n"); | |
| + | send_client_key_exchange(tls); |
| + | len = xread_tls_block(tls); |
| break; | |
| default: | |
| tls_error_die(tls); | |
| @@ -0,0 +1,73 @@ | |
| + | /* |
| + | * Copyright (C) 2017 Denys Vlasenko |
| + | * |
| + | * Licensed under GPLv2, see file LICENSE in this source tree. |
| + | */ |
| + | #include "libbb.h" |
| + | |
| + | /* config tweaks */ |
| + | #define HAVE_NATIVE_INT64 1 |
| + | #undef DISABLE_PSTM |
| + | #undef USE_1024_KEY_SPEED_OPTIMIZATIONS |
| + | #undef USE_2048_KEY_SPEED_OPTIMIZATIONS |
| + | //TODO: enable to use asm: |
| + | //#if defined(__GNUC__) && defined(__i386__) -> #define PSTM_32BIT and PSTM_X86 |
| + | //#if defined(__GNUC__) && defined(__x86_64__) -> #define PSTM_64BIT and PSTM_X86_64 |
| + | //ARM and MIPS also have these |
| + | |
| + | |
| + | #define PS_SUCCESS 0 |
| + | #define PS_FAILURE -1 |
| + | #define PS_ARG_FAIL -6 /* Failure due to bad function param */ |
| + | #define PS_PLATFORM_FAIL -7 /* Failure as a result of system call error */ |
| + | #define PS_MEM_FAIL -8 /* Failure to allocate requested memory */ |
| + | #define PS_LIMIT_FAIL -9 /* Failure on sanity/limit tests */ |
| + | |
| + | #define PS_TRUE 1 |
| + | #define PS_FALSE 0 |
| + | |
| + | #if BB_BIG_ENDIAN |
| + | # define ENDIAN_BIG 1 |
| + | # undef ENDIAN_LITTLE |
| + | //#???? ENDIAN_32BITWORD |
| + | // controls only STORE32L, which we don't use |
| + | #else |
| + | # define ENDIAN_LITTLE 1 |
| + | # undef ENDIAN_BIG |
| + | #endif |
| + | |
| + | typedef uint64_t uint64; |
| + | typedef int64_t int64; |
| + | typedef uint32_t uint32; |
| + | typedef int32_t int32; |
| + | typedef uint16_t uint16; |
| + | typedef int16_t int16; |
| + | |
| + | //FIXME |
| + | typedef char psPool_t; |
| + | |
| + | //#ifdef PS_PUBKEY_OPTIMIZE_FOR_SMALLER_RAM |
| + | #define PS_EXPTMOD_WINSIZE 3 |
| + | //#ifdef PS_PUBKEY_OPTIMIZE_FOR_FASTER_SPEED |
| + | //#define PS_EXPTMOD_WINSIZE 5 |
| + | |
| + | #define PUBKEY_TYPE 0x01 |
| + | #define PRIVKEY_TYPE 0x02 |
| + | |
| + | void tls_get_random(void *buf, unsigned len); |
| + | |
| + | #define matrixCryptoGetPrngData(buf, len, userPtr) (tls_get_random(buf, len), PS_SUCCESS) |
| + | |
| + | #define psFree(p, pool) free(p) |
| + | #define psTraceCrypto(msg) bb_error_msg_and_die(msg) |
| + | |
| + | /* Secure zerofill */ |
| + | #define memset_s(A,B,C,D) memset((A),(C),(D)) |
| + | /* Constant time memory comparison */ |
| + | #define memcmpct(s1, s2, len) memcmp((s1), (s2), (len)) |
| + | #undef min |
| + | #define min(x, y) ((x) < (y) ? (x) : (y)) |
| + | |
| + | |
| + | #include "tls_pstm.h" |
| + | #include "tls_rsa.h" |
| @@ -0,0 +1,2254 @@ | |
| + | /* |
| + | * Copyright (C) 2017 Denys Vlasenko |
| + | * |
| + | * Licensed under GPLv2, see file LICENSE in this source tree. |
| + | */ |
| + | #include "tls.h" |
| + | |
| + | /** |
| + | * @file pstm.c |
| + | * @version 33ef80f (HEAD, tag: MATRIXSSL-3-7-2-OPEN, tag: MATRIXSSL-3-7-2-COMM, origin/master, origin/HEAD, master) |
| + | * |
| + | * Multiprecision number implementation. |
| + | */ |
| + | /* |
| + | * Copyright (c) 2013-2015 INSIDE Secure Corporation |
| + | * Copyright (c) PeerSec Networks, 2002-2011 |
| + | * All Rights Reserved |
| + | * |
| + | * The latest version of this code is available at http://www.matrixssl.org |
| + | * |
| + | * This software is open source; 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 General Public License does NOT permit incorporating this software |
| + | * into proprietary programs. If you are unable to comply with the GPL, a |
| + | * commercial license for this software may be purchased from INSIDE at |
| + | * http://www.insidesecure.com/eng/Company/Locations |
| + | * |
| + | * This program is distributed in 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 |
| + | * http://www.gnu.org/copyleft/gpl.html |
| + | */ |
| + | /******************************************************************************/ |
| + | |
| + | ///bbox |
| + | //#include "../cryptoApi.h" |
| + | #ifndef DISABLE_PSTM |
| + | |
| + | static int32 pstm_mul_2d(pstm_int *a, int16 b, pstm_int *c); |
| + | |
| + | /******************************************************************************/ |
| + | /* |
| + | init an pstm_int for a given size |
| + | */ |
| + | int32 pstm_init_size(psPool_t *pool, pstm_int * a, uint32 size) |
| + | { |
| + | // uint16 x; |
| + | |
| + | /* |
| + | alloc mem |
| + | */ |
| + | a->dp = xzalloc(sizeof (pstm_digit) * size); |
| + | a->pool = pool; |
| + | a->used = 0; |
| + | a->alloc = (int16)size; |
| + | a->sign = PSTM_ZPOS; |
| + | /* |
| + | zero the digits |
| + | */ |
| + | ///bbox |
| + | // for (x = 0; x < size; x++) { |
| + | // a->dp[x] = 0; |
| + | // } |
| + | return PSTM_OKAY; |
| + | } |
| + | |
| + | /******************************************************************************/ |
| + | /* |
| + | Init a new pstm_int. |
| + | */ |
| + | int32 pstm_init(psPool_t *pool, pstm_int * a) |
| + | { |
| + | // int32 i; |
| + | /* |
| + | allocate memory required and clear it |
| + | */ |
| + | a->dp = xzalloc(sizeof (pstm_digit) * PSTM_DEFAULT_INIT); |
| + | /* |
| + | set the digits to zero |
| + | */ |
| + | ///bbox |
| + | // for (i = 0; i < PSTM_DEFAULT_INIT; i++) { |
| + | // a->dp[i] = 0; |
| + | // } |
| + | /* |
| + | set the used to zero, allocated digits to the default precision and sign |
| + | to positive |
| + | */ |
| + | a->pool = pool; |
| + | a->used = 0; |
| + | a->alloc = PSTM_DEFAULT_INIT; |
| + | a->sign = PSTM_ZPOS; |
| + | |
| + | return PSTM_OKAY; |
| + | } |
| + | |
| + | /******************************************************************************/ |
| + | /* |
| + | Grow as required |
| + | */ |
| + | int32 pstm_grow(pstm_int * a, int16 size) |
| + | { |
| + | int16 i; |
| + | pstm_digit *tmp; |
| + | |
| + | /* |
| + | If the alloc size is smaller alloc more ram. |
| + | */ |
| + | if (a->alloc < size) { |
| + | /* |
| + | 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 = xrealloc(a->dp, sizeof (pstm_digit) * size); |
| + | /* |
| + | 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 PSTM_OKAY; |
| + | } |
| + | |
| + | /******************************************************************************/ |
| + | /* |
| + | copy, b = a (b must be pre-allocated) |
| + | */ |
| + | int32 pstm_copy(pstm_int * a, pstm_int * b) |
| + | { |
| + | int32 res, n; |
| + | |
| + | /* |
| + | If dst == src do nothing |
| + | */ |
| + | if (a == b) { |
| + | return PSTM_OKAY; |
| + | } |
| + | /* |
| + | Grow dest |
| + | */ |
| + | if (b->alloc < a->used) { |
| + | if ((res = pstm_grow (b, a->used)) != PSTM_OKAY) { |
| + | return res; |
| + | } |
| + | } |
| + | /* |
| + | Zero b and copy the parameters over |
| + | */ |
| + | { |
| + | register pstm_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 PSTM_OKAY; |
| + | } |
| + | |
| + | /******************************************************************************/ |
| + | /* |
| + | 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 pstm_clamp(pstm_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 = PSTM_ZPOS; |
| + | } |
| + | } |
| + | |
| + | /******************************************************************************/ |
| + | /* |
| + | clear one (frees). |
| + | */ |
| + | void pstm_clear(pstm_int * a) |
| + | { |
| + | int32 i; |
| + | /* |
| + | only do anything if a hasn't been freed previously |
| + | */ |
| + | if (a != NULL && a->dp != NULL) { |
| + | /* |
| + | first zero the digits |
| + | */ |
| + | for (i = 0; i < a->used; i++) { |
| + | a->dp[i] = 0; |
| + | } |
| + | |
| + | psFree (a->dp, a->pool); |
| + | /* |
| + | reset members to make debugging easier |
| + | */ |
| + | a->dp = NULL; |
| + | a->alloc = a->used = 0; |
| + | a->sign = PSTM_ZPOS; |
| + | } |
| + | } |
| + | |
| + | /******************************************************************************/ |
| + | /* |
| + | clear many (frees). |
| + | */ |
| + | void pstm_clear_multi(pstm_int *mp0, pstm_int *mp1, pstm_int *mp2, |
| + | pstm_int *mp3, pstm_int *mp4, pstm_int *mp5, |
| + | pstm_int *mp6, pstm_int *mp7) |
| + | { |
| + | int32 n; /* Number of ok inits */ |
| + | |
| + | pstm_int *tempArray[9]; |
| + | |
| + | tempArray[0] = mp0; |
| + | tempArray[1] = mp1; |
| + | tempArray[2] = mp2; |
| + | tempArray[3] = mp3; |
| + | tempArray[4] = mp4; |
| + | tempArray[5] = mp5; |
| + | tempArray[6] = mp6; |
| + | tempArray[7] = mp7; |
| + | tempArray[8] = NULL; |
| + | |
| + | for (n = 0; tempArray[n] != NULL; n++) { |
| + | if ((tempArray[n] != NULL) && (tempArray[n]->dp != NULL)) { |
| + | pstm_clear(tempArray[n]); |
| + | } |
| + | } |
| + | } |
| + | |
| + | /******************************************************************************/ |
| + | /* |
| + | Set to zero. |
| + | */ |
| + | void pstm_zero(pstm_int * a) |
| + | { |
| + | int32 n; |
| + | pstm_digit *tmp; |
| + | |
| + | a->sign = PSTM_ZPOS; |
| + | a->used = 0; |
| + | |
| + | tmp = a->dp; |
| + | for (n = 0; n < a->alloc; n++) { |
| + | *tmp++ = 0; |
| + | } |
| + | } |
| + | |
| + | |
| + | /******************************************************************************/ |
| + | /* |
| + | Compare maginitude of two ints (unsigned). |
| + | */ |
| + | int32 pstm_cmp_mag(pstm_int * a, pstm_int * b) |
| + | { |
| + | int16 n; |
| + | pstm_digit *tmpa, *tmpb; |
| + | |
| + | /* |
| + | compare based on # of non-zero digits |
| + | */ |
| + | if (a->used > b->used) { |
| + | return PSTM_GT; |
| + | } |
| + | |
| + | if (a->used < b->used) { |
| + | return PSTM_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 PSTM_GT; |
| + | } |
| + | if (*tmpa < *tmpb) { |
| + | return PSTM_LT; |
| + | } |
| + | } |
| + | return PSTM_EQ; |
| + | } |
| + | |
| + | /******************************************************************************/ |
| + | /* |
| + | Compare two ints (signed) |
| + | */ |
| + | int32 pstm_cmp(pstm_int * a, pstm_int * b) |
| + | { |
| + | /* |
| + | compare based on sign |
| + | */ |
| + | if (a->sign != b->sign) { |
| + | if (a->sign == PSTM_NEG) { |
| + | return PSTM_LT; |
| + | } else { |
| + | return PSTM_GT; |
| + | } |
| + | } |
| + | /* |
| + | compare digits |
| + | */ |
| + | if (a->sign == PSTM_NEG) { |
| + | /* if negative compare opposite direction */ |
| + | return pstm_cmp_mag(b, a); |
| + | } else { |
| + | return pstm_cmp_mag(a, b); |
| + | } |
| + | } |
| + | |
| + | /******************************************************************************/ |
| + | /* |
| + | pstm_ints can be initialized more precisely when they will populated |
| + | using pstm_read_unsigned_bin since the length of the byte stream is known |
| + | */ |
| + | int32 pstm_init_for_read_unsigned_bin(psPool_t *pool, pstm_int *a, uint32 len) |
| + | { |
| + | int32 size; |
| + | /* |
| + | Need to set this based on how many words max it will take to store the bin. |
| + | The magic + 2: |
| + | 1 to round up for the remainder of this integer math |
| + | 1 for the initial carry of '1' bits that fall between DIGIT_BIT and 8 |
| + | */ |
| + | size = (((len / sizeof(pstm_digit)) * (sizeof(pstm_digit) * CHAR_BIT)) |
| + | / DIGIT_BIT) + 2; |
| + | return pstm_init_size(pool, a, size); |
| + | } |
| + | |
| + | |
| + | /******************************************************************************/ |
| + | /* |
| + | Reads a unsigned char array into pstm_int format. User should have |
| + | called pstm_init_for_read_unsigned_bin first. There is some grow logic |
| + | here if the default pstm_init was used but we don't really want to hit it. |
| + | */ |
| + | int32 pstm_read_unsigned_bin(pstm_int *a, unsigned char *b, int32 c) |
| + | { |
| + | /* zero the int */ |
| + | pstm_zero (a); |
| + | |
| + | /* |
| + | If we know the endianness of this architecture, and we're using |
| + | 32-bit pstm_digits, we can optimize this |
| + | */ |
| + | #if (defined(ENDIAN_LITTLE) || defined(ENDIAN_BIG)) && !defined(PSTM_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; |
| + | if ((unsigned)c > (PSTM_MAX_SIZE * sizeof(pstm_digit))) { |
| + | uint32 excess = c - (PSTM_MAX_SIZE * sizeof(pstm_digit)); |
| + | c -= excess; |
| + | b += excess; |
| + | } |
| + | a->used = (int16)((c + sizeof(pstm_digit) - 1)/sizeof(pstm_digit)); |
| + | if (a->alloc < a->used) { |
| + | if (pstm_grow(a, a->used) != PSTM_OKAY) { |
| + | return PSTM_MEM; |
| + | } |
| + | } |
| + | pd = (unsigned char *)a->dp; |
| + | /* read the bytes in */ |
| + | #ifdef ENDIAN_BIG |
| + | { |
| + | /* Use Duff's device to unroll the loop. */ |
| + | int32 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 |
| + | /* Big enough based on the len? */ |
| + | a->used = (((c / sizeof(pstm_digit)) * (sizeof(pstm_digit) * CHAR_BIT)) |
| + | / DIGIT_BIT) + 2; |
| + | |
| + | if (a->alloc < a->used) { |
| + | if (pstm_grow(a, a->used) != PSTM_OKAY) { |
| + | return PSTM_MEM; |
| + | } |
| + | } |
| + | /* read the bytes in */ |
| + | for (; c > 0; c--) { |
| + | if (pstm_mul_2d (a, 8, a) != PSTM_OKAY) { |
| + | return PS_MEM_FAIL; |
| + | } |
| + | a->dp[0] |= *b++; |
| + | a->used += 1; |
| + | } |
| + | #endif |
| + | |
| + | pstm_clamp (a); |
| + | return PS_SUCCESS; |
| + | } |
| + | |
| + | /******************************************************************************/ |
| + | /* |
| + | */ |
| + | int16 pstm_count_bits (pstm_int * a) |
| + | { |
| + | int16 r; |
| + | pstm_digit q; |
| + | |
| + | 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 > ((pstm_digit) 0)) { |
| + | ++r; |
| + | q >>= ((pstm_digit) 1); |
| + | } |
| + | return r; |
| + | } |
| + | |
| + | /******************************************************************************/ |
| + | int32 pstm_unsigned_bin_size(pstm_int *a) |
| + | { |
| + | int32 size = pstm_count_bits (a); |
| + | return (size / 8 + ((size & 7) != 0 ? 1 : 0)); |
| + | } |
| + | |
| + | /******************************************************************************/ |
| + | void pstm_set(pstm_int *a, pstm_digit b) |
| + | { |
| + | pstm_zero(a); |
| + | a->dp[0] = b; |
| + | a->used = a->dp[0] ? 1 : 0; |
| + | } |
| + | |
| + | /******************************************************************************/ |
| + | /* |
| + | Right shift |
| + | */ |
| + | void pstm_rshd(pstm_int *a, int16 x) |
| + | { |
| + | int16 y; |
| + | |
| + | /* too many digits just zero and return */ |
| + | if (x >= a->used) { |
| + | pstm_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; |
| + | pstm_clamp(a); |
| + | } |
| + | |
| + | /******************************************************************************/ |
| + | /* |
| + | Shift left a certain amount of digits. |
| + | */ |
| + | int32 pstm_lshd(pstm_int * a, int16 b) |
| + | { |
| + | int16 x; |
| + | int32 res; |
| + | |
| + | /* |
| + | If its less than zero return. |
| + | */ |
| + | if (b <= 0) { |
| + | return PSTM_OKAY; |
| + | } |
| + | /* |
| + | Grow to fit the new digits. |
| + | */ |
| + | if (a->alloc < a->used + b) { |
| + | if ((res = pstm_grow (a, a->used + b)) != PSTM_OKAY) { |
| + | return res; |
| + | } |
| + | } |
| + | |
| + | { |
| + | register pstm_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; |
| + | /* |
| + | This is implemented using a sliding window except the window goes the |
| + | other way around. Copying from the bottom to the top. |
| + | */ |
| + | 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 PSTM_OKAY; |
| + | } |
| + | |
| + | /******************************************************************************/ |
| + | /* |
| + | computes a = 2**b |
| + | */ |
| + | int32 pstm_2expt(pstm_int *a, int16 b) |
| + | { |
| + | int16 z; |
| + | |
| + | /* zero a as per default */ |
| + | pstm_zero (a); |
| + | |
| + | if (b < 0) { |
| + | return PSTM_OKAY; |
| + | } |
| + | |
| + | z = b / DIGIT_BIT; |
| + | if (z >= PSTM_MAX_SIZE) { |
| + | return PS_LIMIT_FAIL; |
| + | } |
| + | |
| + | /* set the used count of where the bit will go */ |
| + | a->used = z + 1; |
| + | |
| + | if (a->used > a->alloc) { |
| + | if (pstm_grow(a, a->used) != PSTM_OKAY) { |
| + | return PS_MEM_FAIL; |
| + | } |
| + | } |
| + | |
| + | /* put the single bit in its place */ |
| + | a->dp[z] = ((pstm_digit)1) << (b % DIGIT_BIT); |
| + | return PSTM_OKAY; |
| + | } |
| + | |
| + | /******************************************************************************/ |
| + | /* |
| + | |
| + | */ |
| + | int32 pstm_mul_2(pstm_int * a, pstm_int * b) |
| + | { |
| + | int32 res; |
| + | int16 x, oldused; |
| + | |
| + | /* |
| + | grow to accomodate result |
| + | */ |
| + | if (b->alloc < a->used + 1) { |
| + | if ((res = pstm_grow (b, a->used + 1)) != PSTM_OKAY) { |
| + | return res; |
| + | } |
| + | } |
| + | oldused = b->used; |
| + | b->used = a->used; |
| + | |
| + | { |
| + | register pstm_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 >> ((pstm_digit)(DIGIT_BIT - 1)); |
| + | /* |
| + | now shift up this digit, add in the carry [from the previous] |
| + | */ |
| + | *tmpb++ = ((*tmpa++ << ((pstm_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 != (PSTM_MAX_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; |
| + | return PSTM_OKAY; |
| + | } |
| + | |
| + | /******************************************************************************/ |
| + | /* |
| + | unsigned subtraction ||a|| >= ||b|| ALWAYS! |
| + | */ |
| + | int32 s_pstm_sub(pstm_int *a, pstm_int *b, pstm_int *c) |
| + | { |
| + | int16 oldbused, oldused; |
| + | int32 x; |
| + | pstm_word t; |
| + | |
| + | if (b->used > a->used) { |
| + | return PS_LIMIT_FAIL; |
| + | } |
| + | if (c->alloc < a->used) { |
| + | if ((x = pstm_grow (c, a->used)) != PSTM_OKAY) { |
| + | return x; |
| + | } |
| + | } |
| + | oldused = c->used; |
| + | oldbused = b->used; |
| + | c->used = a->used; |
| + | t = 0; |
| + | |
| + | for (x = 0; x < oldbused; x++) { |
| + | t = ((pstm_word)a->dp[x]) - (((pstm_word)b->dp[x]) + t); |
| + | c->dp[x] = (pstm_digit)t; |
| + | t = (t >> DIGIT_BIT)&1; |
| + | } |
| + | for (; x < a->used; x++) { |
| + | t = ((pstm_word)a->dp[x]) - t; |
| + | c->dp[x] = (pstm_digit)t; |
| + | t = (t >> DIGIT_BIT); |
| + | } |
| + | for (; x < oldused; x++) { |
| + | c->dp[x] = 0; |
| + | } |
| + | pstm_clamp(c); |
| + | return PSTM_OKAY; |
| + | } |
| + | |
| + | /******************************************************************************/ |
| + | /* |
| + | unsigned addition |
| + | */ |
| + | static int32 s_pstm_add(pstm_int *a, pstm_int *b, pstm_int *c) |
| + | { |
| + | int16 x, y, oldused; |
| + | register pstm_word t, adp, bdp; |
| + | |
| + | y = a->used; |
| + | if (b->used > y) { |
| + | y = b->used; |
| + | } |
| + | oldused = c->used; |
| + | c->used = y; |
| + | |
| + | if (c->used > c->alloc) { |
| + | if (pstm_grow(c, c->used) != PSTM_OKAY) { |
| + | return PS_MEM_FAIL; |
| + | } |
| + | } |
| + | |
| + | t = 0; |
| + | for (x = 0; x < y; x++) { |
| + | if (a->used < x) { |
| + | adp = 0; |
| + | } else { |
| + | adp = (pstm_word)a->dp[x]; |
| + | } |
| + | if (b->used < x) { |
| + | bdp = 0; |
| + | } else { |
| + | bdp = (pstm_word)b->dp[x]; |
| + | } |
| + | t += (adp) + (bdp); |
| + | c->dp[x] = (pstm_digit)t; |
| + | t >>= DIGIT_BIT; |
| + | } |
| + | if (t != 0 && x < PSTM_MAX_SIZE) { |
| + | if (c->used == c->alloc) { |
| + | if (pstm_grow(c, c->alloc + 1) != PSTM_OKAY) { |
| + | return PS_MEM_FAIL; |
| + | } |
| + | } |
| + | c->dp[c->used++] = (pstm_digit)t; |
| + | ++x; |
| + | } |
| + | |
| + | c->used = x; |
| + | for (; x < oldused; x++) { |
| + | c->dp[x] = 0; |
| + | } |
| + | pstm_clamp(c); |
| + | return PSTM_OKAY; |
| + | } |
| + | |
| + | |
| + | /******************************************************************************/ |
| + | /* |
| + | |
| + | */ |
| + | int32 pstm_sub(pstm_int *a, pstm_int *b, pstm_int *c) |
| + | { |
| + | int32 res; |
| + | int16 sa, sb; |
| + | |
| + | sa = a->sign; |
| + | sb = b->sign; |
| + | |
| + | if (sa != sb) { |
| + | /* |
| + | subtract a negative from a positive, OR a positive from a negative. |
| + | For both, ADD their magnitudes, and use the sign of the first number. |
| + | */ |
| + | c->sign = sa; |
| + | if ((res = s_pstm_add (a, b, c)) != PSTM_OKAY) { |
| + | return res; |
| + | } |
| + | } else { |
| + | /* |
| + | subtract a positive from a positive, OR a negative from a negative. |
| + | First, take the difference between their magnitudes, then... |
| + | */ |
| + | if (pstm_cmp_mag (a, b) != PSTM_LT) { |
| + | /* Copy the sign from the first */ |
| + | c->sign = sa; |
| + | /* The first has a larger or equal magnitude */ |
| + | if ((res = s_pstm_sub (a, b, c)) != PSTM_OKAY) { |
| + | return res; |
| + | } |
| + | } else { |
| + | /* The result has the _opposite_ sign from the first number. */ |
| + | c->sign = (sa == PSTM_ZPOS) ? PSTM_NEG : PSTM_ZPOS; |
| + | /* The second has a larger magnitude */ |
| + | if ((res = s_pstm_sub (b, a, c)) != PSTM_OKAY) { |
| + | return res; |
| + | } |
| + | } |
| + | } |
| + | return PS_SUCCESS; |
| + | } |
| + | |
| + | /******************************************************************************/ |
| + | /* |
| + | c = a - b |
| + | */ |
| + | int32 pstm_sub_d(psPool_t *pool, pstm_int *a, pstm_digit b, pstm_int *c) |
| + | { |
| + | pstm_int tmp; |
| + | int32 res; |
| + | |
| + | if (pstm_init_size(pool, &tmp, sizeof(pstm_digit)) != PSTM_OKAY) { |
| + | return PS_MEM_FAIL; |
| + | } |
| + | pstm_set(&tmp, b); |
| + | res = pstm_sub(a, &tmp, c); |
| + | pstm_clear(&tmp); |
| + | return res; |
| + | } |
| + | |
| + | /******************************************************************************/ |
| + | /* |
| + | setups the montgomery reduction |
| + | */ |
| + | int32 pstm_montgomery_setup(pstm_int *a, pstm_digit *rho) |
| + | { |
| + | pstm_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) { |
| + | psTraceCrypto("pstm_montogomery_setup failure\n"); |
| + | return PS_ARG_FAIL; |
| + | } |
| + | |
| + | 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 PSTM_64BIT |
| + | x *= 2 - b * x; /* here x*a==1 mod 2**64 */ |
| + | #endif |
| + | /* rho = -1/m mod b */ |
| + | *rho = (pstm_digit)(((pstm_word) 1 << ((pstm_word) DIGIT_BIT)) - |
| + | ((pstm_word)x)); |
| + | return PSTM_OKAY; |
| + | } |
| + | |
| + | /******************************************************************************/ |
| + | /* |
| + | * computes a = B**n mod b without division or multiplication useful for |
| + | * normalizing numbers in a Montgomery system. |
| + | */ |
| + | int32 pstm_montgomery_calc_normalization(pstm_int *a, pstm_int *b) |
| + | { |
| + | int32 x; |
| + | int16 bits; |
| + | |
| + | /* how many bits of last digit does b use */ |
| + | bits = pstm_count_bits (b) % DIGIT_BIT; |
| + | if (!bits) bits = DIGIT_BIT; |
| + | |
| + | /* compute A = B^(n-1) * 2^(bits-1) */ |
| + | if (b->used > 1) { |
| + | if ((x = pstm_2expt (a, (b->used - 1) * DIGIT_BIT + bits - 1)) != |
| + | PSTM_OKAY) { |
| + | return x; |
| + | } |
| + | } else { |
| + | pstm_set(a, 1); |
| + | bits = 1; |
| + | } |
| + | |
| + | /* now compute C = A * B mod b */ |
| + | for (x = bits - 1; x < (int32)DIGIT_BIT; x++) { |
| + | if (pstm_mul_2 (a, a) != PSTM_OKAY) { |
| + | return PS_MEM_FAIL; |
| + | } |
| + | if (pstm_cmp_mag (a, b) != PSTM_LT) { |
| + | if (s_pstm_sub (a, b, a) != PSTM_OKAY) { |
| + | return PS_MEM_FAIL; |
| + | } |
| + | } |
| + | } |
| + | return PSTM_OKAY; |
| + | } |
| + | |
| + | /******************************************************************************/ |
| + | /* |
| + | c = a * 2**d |
| + | */ |
| + | static int32 pstm_mul_2d(pstm_int *a, int16 b, pstm_int *c) |
| + | { |
| + | pstm_digit carry, carrytmp, shift; |
| + | int16 x; |
| + | |
| + | /* copy it */ |
| + | if (pstm_copy(a, c) != PSTM_OKAY) { |
| + | return PS_MEM_FAIL; |
| + | } |
| + | |
| + | /* handle whole digits */ |
| + | if (b >= DIGIT_BIT) { |
| + | if (pstm_lshd(c, b/DIGIT_BIT) != PSTM_OKAY) { |
| + | return PS_MEM_FAIL; |
| + | } |
| + | } |
| + | 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 < PSTM_MAX_SIZE) { |
| + | if (c->used == c->alloc) { |
| + | if (pstm_grow(c, c->alloc + 1) != PSTM_OKAY) { |
| + | return PS_MEM_FAIL; |
| + | } |
| + | } |
| + | c->dp[c->used++] = carry; |
| + | } |
| + | } |
| + | pstm_clamp(c); |
| + | return PSTM_OKAY; |
| + | } |
| + | |
| + | /******************************************************************************/ |
| + | /* |
| + | c = a mod 2**d |
| + | */ |
| + | static int32 pstm_mod_2d(pstm_int *a, int16 b, pstm_int *c) |
| + | { |
| + | int16 x; |
| + | |
| + | /* zero if count less than or equal to zero */ |
| + | if (b <= 0) { |
| + | pstm_zero(c); |
| + | return PSTM_OKAY; |
| + | } |
| + | |
| + | /* get copy of input */ |
| + | if (pstm_copy(a, c) != PSTM_OKAY) { |
| + | return PS_MEM_FAIL; |
| + | } |
| + | |
| + | /* if 2**d is larger than we just return */ |
| + | if (b >= (DIGIT_BIT * a->used)) { |
| + | return PSTM_OKAY; |
| + | } |
| + | |
| + | /* 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] &= ~((pstm_digit)0) >> (DIGIT_BIT - b); |
| + | pstm_clamp (c); |
| + | return PSTM_OKAY; |
| + | } |
| + | |
| + | |
| + | /******************************************************************************/ |
| + | /* |
| + | c = a * b |
| + | */ |
| + | int32 pstm_mul_d(pstm_int *a, pstm_digit b, pstm_int *c) |
| + | { |
| + | pstm_word w; |
| + | int32 res; |
| + | int16 x, oldused; |
| + | |
| + | if (c->alloc < a->used + 1) { |
| + | if ((res = pstm_grow (c, a->used + 1)) != PSTM_OKAY) { |
| + | return res; |
| + | } |
| + | } |
| + | oldused = c->used; |
| + | c->used = a->used; |
| + | c->sign = a->sign; |
| + | w = 0; |
| + | for (x = 0; x < a->used; x++) { |
| + | w = ((pstm_word)a->dp[x]) * ((pstm_word)b) + w; |
| + | c->dp[x] = (pstm_digit)w; |
| + | w = w >> DIGIT_BIT; |
| + | } |
| + | if (w != 0 && (a->used != PSTM_MAX_SIZE)) { |
| + | c->dp[c->used++] = (pstm_digit)w; |
| + | ++x; |
| + | } |
| + | for (; x < oldused; x++) { |
| + | c->dp[x] = 0; |
| + | } |
| + | pstm_clamp(c); |
| + | return PSTM_OKAY; |
| + | } |
| + | |
| + | /******************************************************************************/ |
| + | /* |
| + | c = a / 2**b |
| + | */ |
| + | int32 pstm_div_2d(psPool_t *pool, pstm_int *a, int16 b, pstm_int *c, |
| + | pstm_int *d) |
| + | { |
| + | pstm_digit D, r, rr; |
| + | int32 res; |
| + | int16 x; |
| + | pstm_int t; |
| + | |
| + | /* if the shift count is <= 0 then we do no work */ |
| + | if (b <= 0) { |
| + | if (pstm_copy (a, c) != PSTM_OKAY) { |
| + | return PS_MEM_FAIL; |
| + | } |
| + | if (d != NULL) { |
| + | pstm_zero (d); |
| + | } |
| + | return PSTM_OKAY; |
| + | } |
| + | |
| + | /* get the remainder */ |
| + | if (d != NULL) { |
| + | if (pstm_init(pool, &t) != PSTM_OKAY) { |
| + | return PS_MEM_FAIL; |
| + | } |
| + | if (pstm_mod_2d (a, b, &t) != PSTM_OKAY) { |
| + | res = PS_MEM_FAIL; |
| + | goto LBL_DONE; |
| + | } |
| + | } |
| + | |
| + | /* copy */ |
| + | if (pstm_copy(a, c) != PSTM_OKAY) { |
| + | res = PS_MEM_FAIL; |
| + | goto LBL_DONE; |
| + | } |
| + | |
| + | /* shift by as many digits in the bit count */ |
| + | if (b >= (int32)DIGIT_BIT) { |
| + | pstm_rshd (c, b / DIGIT_BIT); |
| + | } |
| + | |
| + | /* shift any bit count < DIGIT_BIT */ |
| + | D = (pstm_digit) (b % DIGIT_BIT); |
| + | if (D != 0) { |
| + | register pstm_digit *tmpc, mask, shift; |
| + | |
| + | /* mask */ |
| + | mask = (((pstm_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 previous */ |
| + | *tmpc = (*tmpc >> D) | (r << shift); |
| + | --tmpc; |
| + | |
| + | /* set the carry to the carry bits of the current word above */ |
| + | r = rr; |
| + | } |
| + | } |
| + | pstm_clamp (c); |
| + | |
| + | res = PSTM_OKAY; |
| + | LBL_DONE: |
| + | if (d != NULL) { |
| + | if (pstm_copy(&t, d) != PSTM_OKAY) { |
| + | res = PS_MEM_FAIL; |
| + | } |
| + | pstm_clear(&t); |
| + | } |
| + | return res; |
| + | } |
| + | |
| + | /******************************************************************************/ |
| + | /* |
| + | b = a/2 |
| + | */ |
| + | int32 pstm_div_2(pstm_int * a, pstm_int * b) |
| + | { |
| + | int16 x, oldused; |
| + | |
| + | if (b->alloc < a->used) { |
| + | if (pstm_grow(b, a->used) != PSTM_OKAY) { |
| + | return PS_MEM_FAIL; |
| + | } |
| + | } |
| + | oldused = b->used; |
| + | b->used = a->used; |
| + | { |
| + | register pstm_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; |
| + | pstm_clamp (b); |
| + | return PSTM_OKAY; |
| + | } |
| + | |
| + | /******************************************************************************/ |
| + | /* |
| + | Creates "a" then copies b into it |
| + | */ |
| + | int32 pstm_init_copy(psPool_t *pool, pstm_int * a, pstm_int * b, int16 toSqr) |
| + | { |
| + | int16 x; |
| + | int32 res; |
| + | |
| + | if (a == b) { |
| + | return PSTM_OKAY; |
| + | } |
| + | x = b->alloc; |
| + | |
| + | if (toSqr) { |
| + | /* |
| + | Smart-size: Increasing size of a if b->used is roughly half |
| + | of b->alloc because usage has shown that a lot of these copies |
| + | go on to be squared and need these extra digits |
| + | */ |
| + | if ((b->used * 2) + 2 >= x) { |
| + | x = (b->used * 2) + 3; |
| + | } |
| + | } |
| + | if ((res = pstm_init_size(pool, a, x)) != PSTM_OKAY) { |
| + | return res; |
| + | } |
| + | return pstm_copy(b, a); |
| + | } |
| + | |
| + | /******************************************************************************/ |
| + | /* |
| + | With some compilers, we have seen issues linking with the builtin |
| + | 64 bit division routine. The issues with either manifest in a failure |
| + | to find 'udivdi3' at link time, or a runtime invalid instruction fault |
| + | during an RSA operation. |
| + | The routine below divides a 64 bit unsigned int by a 32 bit unsigned int |
| + | explicitly, rather than using the division operation |
| + | The 64 bit result is placed in the 'numerator' parameter |
| + | The 32 bit mod (remainder) of the division is the return parameter |
| + | Based on implementations by: |
| + | Copyright (C) 2003 Bernardo Innocenti <[email protected]> |
| + | Copyright (C) 1999 Hewlett-Packard Co |
| + | Copyright (C) 1999 David Mosberger-Tang <[email protected]> |
| + | */ |
| + | #if defined(USE_MATRIX_DIV64) && defined(PSTM_32BIT) |
| + | static uint32 psDiv64(uint64 *numerator, uint32 denominator) |
| + | { |
| + | uint64 rem = *numerator; |
| + | uint64 b = denominator; |
| + | uint64 res = 0; |
| + | uint64 d = 1; |
| + | uint32 high = rem >> 32; |
| + | |
| + | if (high >= denominator) { |
| + | high /= denominator; |
| + | res = (uint64) high << 32; |
| + | rem -= (uint64) (high * denominator) << 32; |
| + | } |
| + | while ((int64)b > 0 && b < rem) { |
| + | b = b+b; |
| + | d = d+d; |
| + | } |
| + | do { |
| + | if (rem >= b) { |
| + | rem -= b; |
| + | res += d; |
| + | } |
| + | b >>= 1; |
| + | d >>= 1; |
| + | } while (d); |
| + | *numerator = res; |
| + | return rem; |
| + | } |
| + | #endif /* USE_MATRIX_DIV64 */ |
| + | |
| + | #if defined(USE_MATRIX_DIV128) && defined(PSTM_64BIT) |
| + | typedef unsigned long uint128 __attribute__ ((mode(TI))); |
| + | static uint64 psDiv128(uint128 *numerator, uint64 denominator) |
| + | { |
| + | uint128 rem = *numerator; |
| + | uint128 b = denominator; |
| + | uint128 res = 0; |
| + | uint128 d = 1; |
| + | uint64 high = rem >> 64; |
| + | |
| + | if (high >= denominator) { |
| + | high /= denominator; |
| + | res = (uint128) high << 64; |
| + | rem -= (uint128) (high * denominator) << 64; |
| + | } |
| + | while ((uint128)b > 0 && b < rem) { |
| + | b = b+b; |
| + | d = d+d; |
| + | } |
| + | do { |
| + | if (rem >= b) { |
| + | rem -= b; |
| + | res += d; |
| + | } |
| + | b >>= 1; |
| + | d >>= 1; |
| + | } while (d); |
| + | *numerator = res; |
| + | return rem; |
| + | } |
| + | #endif /* USE_MATRIX_DIV128 */ |
| + | |
| + | /******************************************************************************/ |
| + | /* |
| + | a/b => cb + d == a |
| + | */ |
| + | int32 pstm_div(psPool_t *pool, pstm_int *a, pstm_int *b, pstm_int *c, |
| + | pstm_int *d) |
| + | { |
| + | pstm_int q, x, y, t1, t2; |
| + | int32 res; |
| + | int16 n, t, i, norm, neg; |
| + | |
| + | /* is divisor zero ? */ |
| + | if (pstm_iszero (b) == 1) { |
| + | return PS_LIMIT_FAIL; |
| + | } |
| + | |
| + | /* if a < b then q=0, r = a */ |
| + | if (pstm_cmp_mag (a, b) == PSTM_LT) { |
| + | if (d != NULL) { |
| + | if (pstm_copy(a, d) != PSTM_OKAY) { |
| + | return PS_MEM_FAIL; |
| + | } |
| + | } |
| + | if (c != NULL) { |
| + | pstm_zero (c); |
| + | } |
| + | return PSTM_OKAY; |
| + | } |
| + | /* |
| + | Smart-size inits |
| + | */ |
| + | if ((res = pstm_init_size(pool, &t1, a->alloc)) != PSTM_OKAY) { |
| + | return res; |
| + | } |
| + | if ((res = pstm_init_size(pool, &t2, 3)) != PSTM_OKAY) { |
| + | goto LBL_T1; |
| + | } |
| + | if ((res = pstm_init_copy(pool, &x, a, 0)) != PSTM_OKAY) { |
| + | goto LBL_T2; |
| + | } |
| + | /* |
| + | Used to be an init_copy on b but pstm_grow was always hit with triple size |
| + | */ |
| + | if ((res = pstm_init_size(pool, &y, b->used * 3)) != PSTM_OKAY) { |
| + | goto LBL_X; |
| + | } |
| + | if ((res = pstm_copy(b, &y)) != PSTM_OKAY) { |
| + | goto LBL_Y; |
| + | } |
| + | |
| + | /* fix the sign */ |
| + | neg = (a->sign == b->sign) ? PSTM_ZPOS : PSTM_NEG; |
| + | x.sign = y.sign = PSTM_ZPOS; |
| + | |
| + | /* normalize both x and y, ensure that y >= b/2, [b == 2**DIGIT_BIT] */ |
| + | norm = pstm_count_bits(&y) % DIGIT_BIT; |
| + | if (norm < (int32)(DIGIT_BIT-1)) { |
| + | norm = (DIGIT_BIT-1) - norm; |
| + | if ((res = pstm_mul_2d(&x, norm, &x)) != PSTM_OKAY) { |
| + | goto LBL_Y; |
| + | } |
| + | if ((res = pstm_mul_2d(&y, norm, &y)) != PSTM_OKAY) { |
| + | goto LBL_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; |
| + | |
| + | if ((res = pstm_init_size(pool, &q, n - t + 1)) != PSTM_OKAY) { |
| + | goto LBL_Y; |
| + | } |
| + | q.used = n - t + 1; |
| + | |
| + | /* while (x >= y*b**n-t) do { q[n-t] += 1; x -= y*b**{n-t} } */ |
| + | if ((res = pstm_lshd(&y, n - t)) != PSTM_OKAY) { /* y = y*b**{n-t} */ |
| + | goto LBL_Q; |
| + | } |
| + | |
| + | while (pstm_cmp (&x, &y) != PSTM_LT) { |
| + | ++(q.dp[n - t]); |
| + | if ((res = pstm_sub(&x, &y, &x)) != PSTM_OKAY) { |
| + | goto LBL_Q; |
| + | } |
| + | } |
| + | |
| + | /* reset y by shifting it back down */ |
| + | pstm_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] = (pstm_digit)((((pstm_word)1) << DIGIT_BIT) - 1); |
| + | } else { |
| + | pstm_word tmp; |
| + | tmp = ((pstm_word) x.dp[i]) << ((pstm_word) DIGIT_BIT); |
| + | tmp |= ((pstm_word) x.dp[i - 1]); |
| + | #if defined(USE_MATRIX_DIV64) && defined(PSTM_32BIT) |
| + | psDiv64(&tmp, y.dp[t]); |
| + | #elif defined(USE_MATRIX_DIV128) && defined(PSTM_64BIT) |
| + | psDiv128(&tmp, y.dp[t]); |
| + | #else |
| + | tmp /= ((pstm_word) y.dp[t]); |
| + | #endif /* USE_MATRIX_DIV64 */ |
| + | q.dp[i - t - 1] = (pstm_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 */ |
| + | pstm_zero (&t1); |
| + | t1.dp[0] = (t - 1 < 0) ? 0 : y.dp[t - 1]; |
| + | t1.dp[1] = y.dp[t]; |
| + | t1.used = 2; |
| + | if ((res = pstm_mul_d (&t1, q.dp[i - t - 1], &t1)) != PSTM_OKAY) { |
| + | goto LBL_Q; |
| + | } |
| + | |
| + | /* 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 (pstm_cmp_mag(&t1, &t2) == PSTM_GT); |
| + | |
| + | /* step 3.3 x = x - q{i-t-1} * y * b**{i-t-1} */ |
| + | if ((res = pstm_mul_d(&y, q.dp[i - t - 1], &t1)) != PSTM_OKAY) { |
| + | goto LBL_Q; |
| + | } |
| + | |
| + | if ((res = pstm_lshd(&t1, i - t - 1)) != PSTM_OKAY) { |
| + | goto LBL_Q; |
| + | } |
| + | |
| + | if ((res = pstm_sub(&x, &t1, &x)) != PSTM_OKAY) { |
| + | goto LBL_Q; |
| + | } |
| + | |
| + | /* if x < 0 then { x = x + y*b**{i-t-1}; q{i-t-1} -= 1; } */ |
| + | if (x.sign == PSTM_NEG) { |
| + | if ((res = pstm_copy(&y, &t1)) != PSTM_OKAY) { |
| + | goto LBL_Q; |
| + | } |
| + | if ((res = pstm_lshd (&t1, i - t - 1)) != PSTM_OKAY) { |
| + | goto LBL_Q; |
| + | } |
| + | if ((res = pstm_add (&x, &t1, &x)) != PSTM_OKAY) { |
| + | goto LBL_Q; |
| + | } |
| + | 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 ? PSTM_ZPOS : a->sign; |
| + | |
| + | if (c != NULL) { |
| + | pstm_clamp (&q); |
| + | if (pstm_copy (&q, c) != PSTM_OKAY) { |
| + | res = PS_MEM_FAIL; |
| + | goto LBL_Q; |
| + | } |
| + | c->sign = neg; |
| + | } |
| + | |
| + | if (d != NULL) { |
| + | if ((res = pstm_div_2d (pool, &x, norm, &x, NULL)) != PSTM_OKAY) { |
| + | goto LBL_Q; |
| + | } |
| + | /* |
| + | 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; |
| + | } |
| + | pstm_clamp(&x); |
| + | if (pstm_copy (&x, d) != PSTM_OKAY) { |
| + | res = PS_MEM_FAIL; |
| + | goto LBL_Q; |
| + | } |
| + | } |
| + | |
| + | res = PSTM_OKAY; |
| + | |
| + | LBL_Q:pstm_clear (&q); |
| + | LBL_Y:pstm_clear (&y); |
| + | LBL_X:pstm_clear (&x); |
| + | LBL_T2:pstm_clear (&t2); |
| + | LBL_T1:pstm_clear (&t1); |
| + | |
| + | return res; |
| + | } |
| + | |
| + | /******************************************************************************/ |
| + | /* |
| + | Swap the elements of two integers, for cases where you can't simply swap |
| + | the pstm_int pointers around |
| + | */ |
| + | void pstm_exch(pstm_int * a, pstm_int * b) |
| + | { |
| + | pstm_int t; |
| + | |
| + | t = *a; |
| + | *a = *b; |
| + | *b = t; |
| + | } |
| + | |
| + | /******************************************************************************/ |
| + | /* |
| + | c = a mod b, 0 <= c < b |
| + | */ |
| + | int32 pstm_mod(psPool_t *pool, pstm_int *a, pstm_int *b, pstm_int *c) |
| + | { |
| + | pstm_int t; |
| + | int32 err; |
| + | /* |
| + | Smart-size |
| + | */ |
| + | if ((err = pstm_init_size(pool, &t, b->alloc)) != PSTM_OKAY) { |
| + | return err; |
| + | } |
| + | if ((err = pstm_div(pool, a, b, NULL, &t)) != PSTM_OKAY) { |
| + | pstm_clear (&t); |
| + | return err; |
| + | } |
| + | if (t.sign != b->sign) { |
| + | err = pstm_add(&t, b, c); |
| + | } else { |
| + | pstm_exch (&t, c); |
| + | } |
| + | pstm_clear (&t); |
| + | return err; |
| + | } |
| + | |
| + | /******************************************************************************/ |
| + | /* |
| + | d = a * b (mod c) |
| + | */ |
| + | int32 pstm_mulmod(psPool_t *pool, pstm_int *a, pstm_int *b, pstm_int *c, |
| + | pstm_int *d) |
| + | { |
| + | int32 res; |
| + | int16 size; |
| + | pstm_int tmp; |
| + | |
| + | /* |
| + | Smart-size pstm_inits. d is an output that is influenced by this local 't' |
| + | so don't shrink 'd' if it wants to becuase this will lead to an pstm_grow |
| + | in RSA operations |
| + | */ |
| + | size = a->used + b->used + 1; |
| + | if ((a == d) && (size < a->alloc)) { |
| + | size = a->alloc; |
| + | } |
| + | if ((res = pstm_init_size(pool, &tmp, size)) != PSTM_OKAY) { |
| + | return res; |
| + | } |
| + | if ((res = pstm_mul_comba(pool, a, b, &tmp, NULL, 0)) != PSTM_OKAY) { |
| + | pstm_clear(&tmp); |
| + | return res; |
| + | } |
| + | res = pstm_mod(pool, &tmp, c, d); |
| + | pstm_clear(&tmp); |
| + | return res; |
| + | } |
| + | |
| + | /******************************************************************************/ |
| + | /* |
| + | * y = g**x (mod b) |
| + | * Some restrictions... x must be positive and < b |
| + | */ |
| + | int32 pstm_exptmod(psPool_t *pool, pstm_int *G, pstm_int *X, pstm_int *P, |
| + | pstm_int *Y) |
| + | { |
| + | pstm_int M[32], res; /* Keep this winsize based: (1 << max_winsize) */ |
| + | pstm_digit buf, mp; |
| + | pstm_digit *paD; |
| + | int32 err, bitbuf; |
| + | int16 bitcpy, bitcnt, mode, digidx, x, y, winsize; |
| + | uint32 paDlen; |
| + | |
| + | /* set window size from what user set as optimization */ |
| + | x = pstm_count_bits(X); |
| + | if (x < 50) { |
| + | winsize = 2; |
| + | } else { |
| + | winsize = PS_EXPTMOD_WINSIZE; |
| + | } |
| + | |
| + | /* now setup montgomery */ |
| + | if ((err = pstm_montgomery_setup (P, &mp)) != PSTM_OKAY) { |
| + | return err; |
| + | } |
| + | |
| + | /* setup result */ |
| + | if ((err = pstm_init_size(pool, &res, (P->used * 2) + 1)) != PSTM_OKAY) { |
| + | return err; |
| + | } |
| + | /* |
| + | 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 except for M[0] and M[1] |
| + | */ |
| + | /* now we need R mod m */ |
| + | if ((err = pstm_montgomery_calc_normalization (&res, P)) != PSTM_OKAY) { |
| + | goto LBL_RES; |
| + | } |
| + | /* |
| + | init M array |
| + | init first cell |
| + | */ |
| + | if ((err = pstm_init_size(pool, &M[1], res.used)) != PSTM_OKAY) { |
| + | goto LBL_RES; |
| + | } |
| + | |
| + | /* now set M[1] to G * R mod m */ |
| + | if (pstm_cmp_mag(P, G) != PSTM_GT) { |
| + | /* G > P so we reduce it first */ |
| + | if ((err = pstm_mod(pool, G, P, &M[1])) != PSTM_OKAY) { |
| + | goto LBL_M; |
| + | } |
| + | } else { |
| + | if ((err = pstm_copy(G, &M[1])) != PSTM_OKAY) { |
| + | goto LBL_M; |
| + | } |
| + | } |
| + | if ((err = pstm_mulmod (pool, &M[1], &res, P, &M[1])) != PSTM_OKAY) { |
| + | goto LBL_M; |
| + | } |
| + | /* |
| + | Pre-allocated digit. Used for mul, sqr, AND reduce |
| + | */ |
| + | paDlen = ((M[1].used + 3) * 2) * sizeof(pstm_digit); |
| + | paD = xzalloc(paDlen); |
| + | /* |
| + | compute the value at M[1<<(winsize-1)] by squaring M[1] (winsize-1) times |
| + | */ |
| + | if (pstm_init_copy(pool, &M[1 << (winsize - 1)], &M[1], 1) != PSTM_OKAY) { |
| + | err = PS_MEM_FAIL; |
| + | goto LBL_PAD; |
| + | } |
| + | for (x = 0; x < (winsize - 1); x++) { |
| + | if ((err = pstm_sqr_comba (pool, &M[1 << (winsize - 1)], |
| + | &M[1 << (winsize - 1)], paD, paDlen)) != PSTM_OKAY) { |
| + | goto LBL_PAD; |
| + | } |
| + | if ((err = pstm_montgomery_reduce(pool, &M[1 << (winsize - 1)], P, mp, |
| + | paD, paDlen)) != PSTM_OKAY) { |
| + | goto LBL_PAD; |
| + | } |
| + | } |
| + | /* |
| + | now init the second half of the array |
| + | */ |
| + | for (x = (1<<(winsize-1)) + 1; x < (1 << winsize); x++) { |
| + | if ((err = pstm_init_size(pool, &M[x], M[1<<(winsize-1)].alloc + 1)) |
| + | != PSTM_OKAY) { |
| + | for (y = 1<<(winsize-1); y < x; y++) { |
| + | pstm_clear(&M[y]); |
| + | } |
| + | goto LBL_PAD; |
| + | } |
| + | } |
| + | |
| + | /* create upper table */ |
| + | for (x = (1 << (winsize - 1)) + 1; x < (1 << winsize); x++) { |
| + | if ((err = pstm_mul_comba(pool, &M[x - 1], &M[1], &M[x], paD, paDlen)) |
| + | != PSTM_OKAY) { |
| + | goto LBL_MARRAY; |
| + | } |
| + | if ((err = pstm_montgomery_reduce(pool, &M[x], P, mp, paD, paDlen)) != |
| + | PSTM_OKAY) { |
| + | goto LBL_MARRAY; |
| + | } |
| + | } |
| + | |
| + | /* 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 = (int32)DIGIT_BIT; |
| + | } |
| + | |
| + | /* grab the next msb from the exponent */ |
| + | y = (pstm_digit)(buf >> (DIGIT_BIT - 1)) & 1; |
| + | buf <<= (pstm_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 = pstm_sqr_comba(pool, &res, &res, paD, paDlen)) != |
| + | PSTM_OKAY) { |
| + | goto LBL_MARRAY; |
| + | } |
| + | if ((err = pstm_montgomery_reduce(pool, &res, P, mp, paD, paDlen)) |
| + | != PSTM_OKAY) { |
| + | goto LBL_MARRAY; |
| + | } |
| + | 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 mul square first */ |
| + | for (x = 0; x < winsize; x++) { |
| + | if ((err = pstm_sqr_comba(pool, &res, &res, paD, paDlen)) != |
| + | PSTM_OKAY) { |
| + | goto LBL_MARRAY; |
| + | } |
| + | if ((err = pstm_montgomery_reduce(pool, &res, P, mp, paD, |
| + | paDlen)) != PSTM_OKAY) { |
| + | goto LBL_MARRAY; |
| + | } |
| + | } |
| + | |
| + | /* then multiply */ |
| + | if ((err = pstm_mul_comba(pool, &res, &M[bitbuf], &res, paD, |
| + | paDlen)) != PSTM_OKAY) { |
| + | goto LBL_MARRAY; |
| + | } |
| + | if ((err = pstm_montgomery_reduce(pool, &res, P, mp, paD, paDlen)) |
| + | != PSTM_OKAY) { |
| + | goto LBL_MARRAY; |
| + | } |
| + | |
| + | /* 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 = pstm_sqr_comba(pool, &res, &res, paD, paDlen)) != |
| + | PSTM_OKAY) { |
| + | goto LBL_MARRAY; |
| + | } |
| + | if ((err = pstm_montgomery_reduce(pool, &res, P, mp, paD, paDlen)) |
| + | != PSTM_OKAY) { |
| + | goto LBL_MARRAY; |
| + | } |
| + | |
| + | /* get next bit of the window */ |
| + | bitbuf <<= 1; |
| + | if ((bitbuf & (1 << winsize)) != 0) { |
| + | /* then multiply */ |
| + | if ((err = pstm_mul_comba(pool, &res, &M[1], &res, paD, paDlen)) |
| + | != PSTM_OKAY) { |
| + | goto LBL_MARRAY; |
| + | } |
| + | if ((err = pstm_montgomery_reduce(pool, &res, P, mp, paD, |
| + | paDlen)) != PSTM_OKAY) { |
| + | goto LBL_MARRAY; |
| + | } |
| + | } |
| + | } |
| + | } |
| + | /* |
| + | Fix up 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 = pstm_montgomery_reduce(pool, &res, P, mp, paD, paDlen)) != |
| + | PSTM_OKAY) { |
| + | goto LBL_MARRAY; |
| + | } |
| + | /* swap res with Y */ |
| + | if ((err = pstm_copy (&res, Y)) != PSTM_OKAY) { |
| + | goto LBL_MARRAY; |
| + | } |
| + | err = PSTM_OKAY; |
| + | LBL_MARRAY: |
| + | for (x = 1<<(winsize-1); x < (1 << winsize); x++) { |
| + | pstm_clear(&M[x]); |
| + | } |
| + | LBL_PAD:psFree(paD, pool); |
| + | LBL_M: pstm_clear(&M[1]); |
| + | LBL_RES:pstm_clear(&res); |
| + | return err; |
| + | } |
| + | |
| + | /******************************************************************************/ |
| + | /* |
| + | |
| + | */ |
| + | int32 pstm_add(pstm_int *a, pstm_int *b, pstm_int *c) |
| + | { |
| + | int32 res; |
| + | int16 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 mags, copy the sign */ |
| + | c->sign = sa; |
| + | if ((res = s_pstm_add (a, b, c)) != PSTM_OKAY) { |
| + | return res; |
| + | } |
| + | } 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 mag. |
| + | */ |
| + | if (pstm_cmp_mag (a, b) == PSTM_LT) { |
| + | c->sign = sb; |
| + | if ((res = s_pstm_sub (b, a, c)) != PSTM_OKAY) { |
| + | return res; |
| + | } |
| + | } else { |
| + | c->sign = sa; |
| + | if ((res = s_pstm_sub (a, b, c)) != PSTM_OKAY) { |
| + | return res; |
| + | } |
| + | } |
| + | } |
| + | return PS_SUCCESS; |
| + | } |
| + | |
| + | /******************************************************************************/ |
| + | /* |
| + | reverse an array, used for radix code |
| + | */ |
| + | static void pstm_reverse (unsigned char *s, int16 len) |
| + | { |
| + | int32 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; |
| + | } |
| + | } |
| + | /******************************************************************************/ |
| + | /* |
| + | No reverse. Useful in some of the EIP-154 PKA stuff where special byte |
| + | order seems to come into play more often |
| + | */ |
| + | int32 pstm_to_unsigned_bin_nr(psPool_t *pool, pstm_int *a, unsigned char *b) |
| + | { |
| + | int32 res; |
| + | int16 x; |
| + | pstm_int t = { 0 }; |
| + | |
| + | if ((res = pstm_init_copy(pool, &t, a, 0)) != PSTM_OKAY) { |
| + | return res; |
| + | } |
| + | |
| + | x = 0; |
| + | while (pstm_iszero (&t) == 0) { |
| + | b[x++] = (unsigned char) (t.dp[0] & 255); |
| + | if ((res = pstm_div_2d (pool, &t, 8, &t, NULL)) != PSTM_OKAY) { |
| + | pstm_clear(&t); |
| + | return res; |
| + | } |
| + | } |
| + | pstm_clear(&t); |
| + | return PS_SUCCESS; |
| + | } |
| + | /******************************************************************************/ |
| + | /* |
| + | |
| + | */ |
| + | int32 pstm_to_unsigned_bin(psPool_t *pool, pstm_int *a, unsigned char *b) |
| + | { |
| + | int32 res; |
| + | int16 x; |
| + | pstm_int t = { 0 }; |
| + | |
| + | if ((res = pstm_init_copy(pool, &t, a, 0)) != PSTM_OKAY) { |
| + | return res; |
| + | } |
| + | |
| + | x = 0; |
| + | while (pstm_iszero (&t) == 0) { |
| + | b[x++] = (unsigned char) (t.dp[0] & 255); |
| + | if ((res = pstm_div_2d (pool, &t, 8, &t, NULL)) != PSTM_OKAY) { |
| + | pstm_clear(&t); |
| + | return res; |
| + | } |
| + | } |
| + | pstm_reverse (b, x); |
| + | pstm_clear(&t); |
| + | return PS_SUCCESS; |
| + | } |
| + | |
| + | /******************************************************************************/ |
| + | /* |
| + | compare against a single digit |
| + | */ |
| + | int32 pstm_cmp_d(pstm_int *a, pstm_digit b) |
| + | { |
| + | /* compare based on sign */ |
| + | if ((b && a->used == 0) || a->sign == PSTM_NEG) { |
| + | return PSTM_LT; |
| + | } |
| + | |
| + | /* compare based on magnitude */ |
| + | if (a->used > 1) { |
| + | return PSTM_GT; |
| + | } |
| + | |
| + | /* compare the only digit of a to b */ |
| + | if (a->dp[0] > b) { |
| + | return PSTM_GT; |
| + | } else if (a->dp[0] < b) { |
| + | return PSTM_LT; |
| + | } else { |
| + | return PSTM_EQ; |
| + | } |
| + | } |
| + | |
| + | /* |
| + | Need invmod for ECC and also private key loading for hardware crypto |
| + | in cases where dQ > dP. The values must be switched and a new qP must be |
| + | calculated using this function |
| + | */ |
| + | static int32 pstm_invmod_slow(psPool_t *pool, pstm_int * a, pstm_int * b, |
| + | pstm_int * c) |
| + | { |
| + | pstm_int x, y, u, v, A, B, C, D; |
| + | int32 res; |
| + | |
| + | /* b cannot be negative */ |
| + | if (b->sign == PSTM_NEG || pstm_iszero(b) == 1) { |
| + | return PS_LIMIT_FAIL; |
| + | } |
| + | |
| + | /* init temps */ |
| + | if (pstm_init_size(pool, &x, b->used) != PSTM_OKAY) { |
| + | return PS_MEM_FAIL; |
| + | } |
| + | |
| + | /* x = a, y = b */ |
| + | if ((res = pstm_mod(pool, a, b, &x)) != PSTM_OKAY) { |
| + | goto LBL_X; |
| + | } |
| + | |
| + | if (pstm_init_copy(pool, &y, b, 0) != PSTM_OKAY) { |
| + | goto LBL_X; |
| + | } |
| + | |
| + | /* 2. [modified] if x,y are both even then return an error! */ |
| + | if (pstm_iseven (&x) == 1 && pstm_iseven (&y) == 1) { |
| + | res = PS_FAILURE; |
| + | goto LBL_Y; |
| + | } |
| + | |
| + | /* 3. u=x, v=y, A=1, B=0, C=0,D=1 */ |
| + | if ((res = pstm_init_copy(pool, &u, &x, 0)) != PSTM_OKAY) { |
| + | goto LBL_Y; |
| + | } |
| + | if ((res = pstm_init_copy(pool, &v, &y, 0)) != PSTM_OKAY) { |
| + | goto LBL_U; |
| + | } |
| + | |
| + | if ((res = pstm_init_size(pool, &A, sizeof(pstm_digit))) != PSTM_OKAY) { |
| + | goto LBL_V; |
| + | } |
| + | |
| + | if ((res = pstm_init_size(pool, &D, sizeof(pstm_digit))) != PSTM_OKAY) { |
| + | goto LBL_A; |
| + | } |
| + | pstm_set (&A, 1); |
| + | pstm_set (&D, 1); |
| + | |
| + | if ((res = pstm_init(pool, &B)) != PSTM_OKAY) { |
| + | goto LBL_D; |
| + | } |
| + | if ((res = pstm_init(pool, &C)) != PSTM_OKAY) { |
| + | goto LBL_B; |
| + | } |
| + | |
| + | top: |
| + | /* 4. while u is even do */ |
| + | while (pstm_iseven (&u) == 1) { |
| + | /* 4.1 u = u/2 */ |
| + | if ((res = pstm_div_2 (&u, &u)) != PSTM_OKAY) { |
| + | goto LBL_C; |
| + | } |
| + | |
| + | /* 4.2 if A or B is odd then */ |
| + | if (pstm_isodd (&A) == 1 || pstm_isodd (&B) == 1) { |
| + | /* A = (A+y)/2, B = (B-x)/2 */ |
| + | if ((res = pstm_add (&A, &y, &A)) != PSTM_OKAY) { |
| + | goto LBL_C; |
| + | } |
| + | if ((res = pstm_sub (&B, &x, &B)) != PSTM_OKAY) { |
| + | goto LBL_C; |
| + | } |
| + | } |
| + | /* A = A/2, B = B/2 */ |
| + | if ((res = pstm_div_2 (&A, &A)) != PSTM_OKAY) { |
| + | goto LBL_C; |
| + | } |
| + | if ((res = pstm_div_2 (&B, &B)) != PSTM_OKAY) { |
| + | goto LBL_C; |
| + | } |
| + | } |
| + | |
| + | /* 5. while v is even do */ |
| + | while (pstm_iseven (&v) == 1) { |
| + | /* 5.1 v = v/2 */ |
| + | if ((res = pstm_div_2 (&v, &v)) != PSTM_OKAY) { |
| + | goto LBL_C; |
| + | } |
| + | |
| + | /* 5.2 if C or D is odd then */ |
| + | if (pstm_isodd (&C) == 1 || pstm_isodd (&D) == 1) { |
| + | /* C = (C+y)/2, D = (D-x)/2 */ |
| + | if ((res = pstm_add (&C, &y, &C)) != PSTM_OKAY) { |
| + | goto LBL_C; |
| + | } |
| + | if ((res = pstm_sub (&D, &x, &D)) != PSTM_OKAY) { |
| + | goto LBL_C; |
| + | } |
| + | } |
| + | /* C = C/2, D = D/2 */ |
| + | if ((res = pstm_div_2 (&C, &C)) != PSTM_OKAY) { |
| + | goto LBL_C; |
| + | } |
| + | if ((res = pstm_div_2 (&D, &D)) != PSTM_OKAY) { |
| + | goto LBL_C; |
| + | } |
| + | } |
| + | |
| + | /* 6. if u >= v then */ |
| + | if (pstm_cmp (&u, &v) != PSTM_LT) { |
| + | /* u = u - v, A = A - C, B = B - D */ |
| + | if ((res = pstm_sub (&u, &v, &u)) != PSTM_OKAY) { |
| + | goto LBL_C; |
| + | } |
| + | if ((res = pstm_sub (&A, &C, &A)) != PSTM_OKAY) { |
| + | goto LBL_C; |
| + | } |
| + | if ((res = pstm_sub (&B, &D, &B)) != PSTM_OKAY) { |
| + | goto LBL_C; |
| + | } |
| + | } else { |
| + | /* v - v - u, C = C - A, D = D - B */ |
| + | if ((res = pstm_sub (&v, &u, &v)) != PSTM_OKAY) { |
| + | goto LBL_C; |
| + | } |
| + | if ((res = pstm_sub (&C, &A, &C)) != PSTM_OKAY) { |
| + | goto LBL_C; |
| + | } |
| + | if ((res = pstm_sub (&D, &B, &D)) != PSTM_OKAY) { |
| + | goto LBL_C; |
| + | } |
| + | } |
| + | |
| + | /* if not zero goto step 4 */ |
| + | if (pstm_iszero (&u) == 0) |
| + | goto top; |
| + | |
| + | /* now a = C, b = D, gcd == g*v */ |
| + | |
| + | /* if v != 1 then there is no inverse */ |
| + | if (pstm_cmp_d (&v, 1) != PSTM_EQ) { |
| + | res = PS_FAILURE; |
| + | goto LBL_C; |
| + | } |
| + | |
| + | /* if its too low */ |
| + | while (pstm_cmp_d(&C, 0) == PSTM_LT) { |
| + | if ((res = pstm_add(&C, b, &C)) != PSTM_OKAY) { |
| + | goto LBL_C; |
| + | } |
| + | } |
| + | |
| + | /* too big */ |
| + | while (pstm_cmp_mag(&C, b) != PSTM_LT) { |
| + | if ((res = pstm_sub(&C, b, &C)) != PSTM_OKAY) { |
| + | goto LBL_C; |
| + | } |
| + | } |
| + | |
| + | /* C is now the inverse */ |
| + | if ((res = pstm_copy(&C, c)) != PSTM_OKAY) { |
| + | goto LBL_C; |
| + | } |
| + | res = PSTM_OKAY; |
| + | |
| + | LBL_C: pstm_clear(&C); |
| + | LBL_D: pstm_clear(&D); |
| + | LBL_B: pstm_clear(&B); |
| + | LBL_A: pstm_clear(&A); |
| + | LBL_V: pstm_clear(&v); |
| + | LBL_U: pstm_clear(&u); |
| + | LBL_Y: pstm_clear(&y); |
| + | LBL_X: pstm_clear(&x); |
| + | |
| + | return res; |
| + | } |
| + | |
| + | /* c = 1/a (mod b) for odd b only */ |
| + | int32 pstm_invmod(psPool_t *pool, pstm_int *a, pstm_int *b, pstm_int *c) |
| + | { |
| + | pstm_int x, y, u, v, B, D; |
| + | int32 res; |
| + | uint16 neg, sanity; |
| + | |
| + | /* 2. [modified] b must be odd */ |
| + | if (pstm_iseven (b) == 1) { |
| + | return pstm_invmod_slow(pool, a,b,c); |
| + | } |
| + | |
| + | /* x == modulus, y == value to invert */ |
| + | if ((res = pstm_init_copy(pool, &x, b, 0)) != PSTM_OKAY) { |
| + | return res; |
| + | } |
| + | |
| + | if ((res = pstm_init_size(pool, &y, a->alloc)) != PSTM_OKAY) { |
| + | goto LBL_X; |
| + | } |
| + | |
| + | /* we need y = |a| */ |
| + | pstm_abs(a, &y); |
| + | |
| + | /* 3. u=x, v=y, A=1, B=0, C=0,D=1 */ |
| + | if ((res = pstm_init_copy(pool, &u, &x, 0)) != PSTM_OKAY) { |
| + | goto LBL_Y; |
| + | } |
| + | if ((res = pstm_init_copy(pool, &v, &y, 0)) != PSTM_OKAY) { |
| + | goto LBL_U; |
| + | } |
| + | if ((res = pstm_init(pool, &B)) != PSTM_OKAY) { |
| + | goto LBL_V; |
| + | } |
| + | if ((res = pstm_init(pool, &D)) != PSTM_OKAY) { |
| + | goto LBL_B; |
| + | } |
| + | |
| + | pstm_set (&D, 1); |
| + | |
| + | sanity = 0; |
| + | top: |
| + | /* 4. while u is even do */ |
| + | while (pstm_iseven (&u) == 1) { |
| + | /* 4.1 u = u/2 */ |
| + | if ((res = pstm_div_2 (&u, &u)) != PSTM_OKAY) { |
| + | goto LBL_D; |
| + | } |
| + | |
| + | /* 4.2 if B is odd then */ |
| + | if (pstm_isodd (&B) == 1) { |
| + | if ((res = pstm_sub (&B, &x, &B)) != PSTM_OKAY) { |
| + | goto LBL_D; |
| + | } |
| + | } |
| + | /* B = B/2 */ |
| + | if ((res = pstm_div_2 (&B, &B)) != PSTM_OKAY) { |
| + | goto LBL_D; |
| + | } |
| + | } |
| + | |
| + | /* 5. while v is even do */ |
| + | while (pstm_iseven (&v) == 1) { |
| + | /* 5.1 v = v/2 */ |
| + | if ((res = pstm_div_2 (&v, &v)) != PSTM_OKAY) { |
| + | goto LBL_D; |
| + | } |
| + | /* 5.2 if D is odd then */ |
| + | if (pstm_isodd (&D) == 1) { |
| + | /* D = (D-x)/2 */ |
| + | if ((res = pstm_sub (&D, &x, &D)) != PSTM_OKAY) { |
| + | goto LBL_D; |
| + | } |
| + | } |
| + | /* D = D/2 */ |
| + | if ((res = pstm_div_2 (&D, &D)) != PSTM_OKAY) { |
| + | goto LBL_D; |
| + | } |
| + | } |
| + | |
| + | /* 6. if u >= v then */ |
| + | if (pstm_cmp (&u, &v) != PSTM_LT) { |
| + | /* u = u - v, B = B - D */ |
| + | if ((res = pstm_sub (&u, &v, &u)) != PSTM_OKAY) { |
| + | goto LBL_D; |
| + | } |
| + | if ((res = pstm_sub (&B, &D, &B)) != PSTM_OKAY) { |
| + | goto LBL_D; |
| + | } |
| + | } else { |
| + | /* v - v - u, D = D - B */ |
| + | if ((res = pstm_sub (&v, &u, &v)) != PSTM_OKAY) { |
| + | goto LBL_D; |
| + | } |
| + | if ((res = pstm_sub (&D, &B, &D)) != PSTM_OKAY) { |
| + | goto LBL_D; |
| + | } |
| + | } |
| + | |
| + | /* if not zero goto step 4 */ |
| + | if (sanity++ > 1000) { |
| + | res = PS_LIMIT_FAIL; |
| + | goto LBL_D; |
| + | } |
| + | if (pstm_iszero (&u) == 0) { |
| + | goto top; |
| + | } |
| + | |
| + | /* now a = C, b = D, gcd == g*v */ |
| + | |
| + | /* if v != 1 then there is no inverse */ |
| + | if (pstm_cmp_d (&v, 1) != PSTM_EQ) { |
| + | res = PS_FAILURE; |
| + | goto LBL_D; |
| + | } |
| + | |
| + | /* b is now the inverse */ |
| + | neg = a->sign; |
| + | while (D.sign == PSTM_NEG) { |
| + | if ((res = pstm_add (&D, b, &D)) != PSTM_OKAY) { |
| + | goto LBL_D; |
| + | } |
| + | } |
| + | if ((res = pstm_copy (&D, c)) != PSTM_OKAY) { |
| + | goto LBL_D; |
| + | } |
| + | c->sign = neg; |
| + | res = PSTM_OKAY; |
| + | |
| + | LBL_D: pstm_clear(&D); |
| + | LBL_B: pstm_clear(&B); |
| + | LBL_V: pstm_clear(&v); |
| + | LBL_U: pstm_clear(&u); |
| + | LBL_Y: pstm_clear(&y); |
| + | LBL_X: pstm_clear(&x); |
| + | return res; |
| + | } |
| + | #endif /* !DISABLE_PSTM */ |
| + | /******************************************************************************/ |
| @@ -0,0 +1,238 @@ | |
| + | /** |
| + | * @file pstm.h |
| + | * @version 33ef80f (HEAD, tag: MATRIXSSL-3-7-2-OPEN, tag: MATRIXSSL-3-7-2-COMM, origin/master, origin/HEAD, master) |
| + | * |
| + | * multiple-precision integer library. |
| + | */ |
| + | /* |
| + | * Copyright (c) 2013-2015 INSIDE Secure Corporation |
| + | * Copyright (c) PeerSec Networks, 2002-2011 |
| + | * All Rights Reserved |
| + | * |
| + | * The latest version of this code is available at http://www.matrixssl.org |
| + | * |
| + | * This software is open source; 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 General Public License does NOT permit incorporating this software |
| + | * into proprietary programs. If you are unable to comply with the GPL, a |
| + | * commercial license for this software may be purchased from INSIDE at |
| + | * http://www.insidesecure.com/eng/Company/Locations |
| + | * |
| + | * This program is distributed in 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 |
| + | * http://www.gnu.org/copyleft/gpl.html |
| + | */ |
| + | /******************************************************************************/ |
| + | |
| + | #ifndef _h_PSTMATH |
| + | #define _h_PSTMATH |
| + | #ifndef DISABLE_PSTM |
| + | |
| + | /* Define this here to avoid including circular limits.h on some platforms */ |
| + | #ifndef CHAR_BIT |
| + | #define CHAR_BIT 8 |
| + | #endif |
| + | |
| + | /******************************************************************************/ |
| + | /* |
| + | If native 64 bit integers are not supported, we do not support 32x32->64 |
| + | in hardware, so we must set the 16 bit flag to produce 16x16->32 products. |
| + | */ |
| + | #ifndef HAVE_NATIVE_INT64 |
| + | #define PSTM_16BIT |
| + | #endif /* ! HAVE_NATIVE_INT64 */ |
| + | |
| + | /******************************************************************************/ |
| + | /* |
| + | Some default configurations. |
| + | |
| + | pstm_word should be the largest value the processor can hold as the product |
| + | of a multiplication. Most platforms support a 32x32->64 MAC instruction, |
| + | so 64bits is the default pstm_word size. |
| + | pstm_digit should be half the size of pstm_word |
| + | */ |
| + | #ifdef PSTM_8BIT |
| + | /* 8-bit digits, 16-bit word products */ |
| + | typedef unsigned char pstm_digit; |
| + | typedef unsigned short pstm_word; |
| + | #define DIGIT_BIT 8 |
| + | |
| + | #elif defined(PSTM_16BIT) |
| + | /* 16-bit digits, 32-bit word products */ |
| + | typedef unsigned short pstm_digit; |
| + | typedef unsigned long pstm_word; |
| + | #define DIGIT_BIT 16 |
| + | |
| + | #elif defined(PSTM_64BIT) |
| + | /* 64-bit digits, 128-bit word products */ |
| + | #ifndef __GNUC__ |
| + | #error "64bit digits requires GCC" |
| + | #endif |
| + | typedef unsigned long pstm_digit; |
| + | typedef unsigned long pstm_word __attribute__ ((mode(TI))); |
| + | #define DIGIT_BIT 64 |
| + | |
| + | #else |
| + | /* This is the default case, 32-bit digits, 64-bit word products */ |
| + | typedef uint32 pstm_digit; |
| + | typedef uint64 pstm_word; |
| + | #define DIGIT_BIT 32 |
| + | #define PSTM_32BIT |
| + | #endif /* digit and word size */ |
| + | |
| + | #define PSTM_MASK (pstm_digit)(-1) |
| + | #define PSTM_DIGIT_MAX PSTM_MASK |
| + | |
| + | /******************************************************************************/ |
| + | /* |
| + | equalities |
| + | */ |
| + | #define PSTM_LT -1 /* less than */ |
| + | #define PSTM_EQ 0 /* equal to */ |
| + | #define PSTM_GT 1 /* greater than */ |
| + | |
| + | #define PSTM_ZPOS 0 /* positive integer */ |
| + | #define PSTM_NEG 1 /* negative */ |
| + | |
| + | #define PSTM_OKAY PS_SUCCESS |
| + | #define PSTM_MEM PS_MEM_FAIL |
| + | |
| + | /******************************************************************************/ |
| + | /* |
| + | Various build options |
| + | */ |
| + | #define PSTM_DEFAULT_INIT 64 /* default (64) digits of allocation */ |
| + | #define PSTM_MAX_SIZE 4096 |
| + | |
| + | typedef struct { |
| + | int16 used, alloc, sign; |
| + | pstm_digit *dp; |
| + | psPool_t *pool; |
| + | } pstm_int; |
| + | |
| + | /******************************************************************************/ |
| + | /* |
| + | Operations on large integers |
| + | */ |
| + | #define pstm_iszero(a) (((a)->used == 0) ? PS_TRUE : PS_FALSE) |
| + | #define pstm_iseven(a) (((a)->used > 0 && (((a)->dp[0] & 1) == 0)) ? PS_TRUE : PS_FALSE) |
| + | #define pstm_isodd(a) (((a)->used > 0 && (((a)->dp[0] & 1) == 1)) ? PS_TRUE : PS_FALSE) |
| + | #define pstm_abs(a, b) { pstm_copy(a, b); (b)->sign = 0; } |
| + | |
| + | extern void pstm_set(pstm_int *a, pstm_digit b); |
| + | |
| + | extern void pstm_zero(pstm_int * a); |
| + | |
| + | extern int32 pstm_init(psPool_t *pool, pstm_int * a); |
| + | |
| + | extern int32 pstm_init_size(psPool_t *pool, pstm_int * a, uint32 size); |
| + | |
| + | extern int32 pstm_init_copy(psPool_t *pool, pstm_int * a, pstm_int * b, |
| + | int16 toSqr); |
| + | |
| + | extern int16 pstm_count_bits (pstm_int * a); |
| + | |
| + | extern int32 pstm_init_for_read_unsigned_bin(psPool_t *pool, pstm_int *a, |
| + | uint32 len); |
| + | |
| + | extern int32 pstm_read_unsigned_bin(pstm_int *a, unsigned char *b, int32 c); |
| + | |
| + | extern int32 pstm_unsigned_bin_size(pstm_int *a); |
| + | |
| + | extern int32 pstm_copy(pstm_int * a, pstm_int * b); |
| + | |
| + | extern void pstm_exch(pstm_int * a, pstm_int * b); |
| + | |
| + | extern void pstm_clear(pstm_int * a); |
| + | |
| + | extern void pstm_clear_multi(pstm_int *mp0, pstm_int *mp1, pstm_int *mp2, |
| + | pstm_int *mp3, pstm_int *mp4, pstm_int *mp5, pstm_int *mp6, |
| + | pstm_int *mp7); |
| + | |
| + | extern int32 pstm_grow(pstm_int * a, int16 size); |
| + | |
| + | extern void pstm_clamp(pstm_int * a); |
| + | |
| + | extern int32 pstm_cmp(pstm_int * a, pstm_int * b); |
| + | |
| + | extern int32 pstm_cmp_mag(pstm_int * a, pstm_int * b); |
| + | |
| + | extern void pstm_rshd(pstm_int *a, int16 x); |
| + | |
| + | extern int32 pstm_lshd(pstm_int * a, int16 b); |
| + | |
| + | extern int32 pstm_div(psPool_t *pool, pstm_int *a, pstm_int *b, pstm_int *c, |
| + | pstm_int *d); |
| + | |
| + | extern int32 pstm_div_2d(psPool_t *pool, pstm_int *a, int16 b, pstm_int *c, |
| + | pstm_int *d); |
| + | |
| + | extern int32 pstm_div_2(pstm_int * a, pstm_int * b); |
| + | |
| + | extern int32 s_pstm_sub(pstm_int *a, pstm_int *b, pstm_int *c); |
| + | |
| + | extern int32 pstm_sub(pstm_int *a, pstm_int *b, pstm_int *c); |
| + | |
| + | extern int32 pstm_sub_d(psPool_t *pool, pstm_int *a, pstm_digit b, pstm_int *c); |
| + | |
| + | extern int32 pstm_mul_2(pstm_int * a, pstm_int * b); |
| + | |
| + | extern int32 pstm_mod(psPool_t *pool, pstm_int *a, pstm_int *b, pstm_int *c); |
| + | |
| + | extern int32 pstm_mulmod(psPool_t *pool, pstm_int *a, pstm_int *b, pstm_int *c, |
| + | pstm_int *d); |
| + | |
| + | extern int32 pstm_exptmod(psPool_t *pool, pstm_int *G, pstm_int *X, pstm_int *P, |
| + | pstm_int *Y); |
| + | |
| + | extern int32 pstm_2expt(pstm_int *a, int16 b); |
| + | |
| + | extern int32 pstm_add(pstm_int *a, pstm_int *b, pstm_int *c); |
| + | |
| + | extern int32 pstm_to_unsigned_bin(psPool_t *pool, pstm_int *a, |
| + | unsigned char *b); |
| + | |
| + | extern int32 pstm_to_unsigned_bin_nr(psPool_t *pool, pstm_int *a, |
| + | unsigned char *b); |
| + | |
| + | extern int32 pstm_montgomery_setup(pstm_int *a, pstm_digit *rho); |
| + | |
| + | ///bbox: pool unused |
| + | #define pstm_montgomery_reduce(pool, a, m, mp, paD, paDlen) \ |
| + | pstm_montgomery_reduce( a, m, mp, paD, paDlen) |
| + | extern int32 pstm_montgomery_reduce(psPool_t *pool, pstm_int *a, pstm_int *m, |
| + | pstm_digit mp, pstm_digit *paD, uint32 paDlen); |
| + | |
| + | #define pstm_mul_comba(pool, A, B, C, paD, paDlen) \ |
| + | pstm_mul_comba( A, B, C, paD, paDlen) |
| + | extern int32 pstm_mul_comba(psPool_t *pool, pstm_int *A, pstm_int *B, |
| + | pstm_int *C, pstm_digit *paD, uint32 paDlen); |
| + | |
| + | ///bbox: pool unused |
| + | #define pstm_sqr_comba(pool, A, B, paD, paDlen) \ |
| + | pstm_sqr_comba( A, B, paD, paDlen) |
| + | extern int32 pstm_sqr_comba(psPool_t *pool, pstm_int *A, pstm_int *B, |
| + | pstm_digit *paD, uint32 paDlen); |
| + | |
| + | extern int32 pstm_cmp_d(pstm_int *a, pstm_digit b); |
| + | |
| + | extern int32 pstm_montgomery_calc_normalization(pstm_int *a, pstm_int *b); |
| + | |
| + | extern int32 pstm_mul_d(pstm_int *a, pstm_digit b, pstm_int *c); |
| + | |
| + | extern int32 pstm_invmod(psPool_t *pool, pstm_int * a, pstm_int * b, |
| + | pstm_int * c); |
| + | |
| + | #else /* DISABLE_PSTM */ |
| + | typedef int32 pstm_int; |
| + | #endif /* !DISABLE_PSTM */ |
| + | #endif /* _h_PSTMATH */ |
| + | |
| @@ -0,0 +1,423 @@ | |
| + | /* |
| + | * Copyright (C) 2017 Denys Vlasenko |
| + | * |
| + | * Licensed under GPLv2, see file LICENSE in this source tree. |
| + | */ |
| + | #include "tls.h" |
| + | |
| + | /** |
| + | * @file pstm_montgomery_reduce.c |
| + | * @version 33ef80f (HEAD, tag: MATRIXSSL-3-7-2-OPEN, tag: MATRIXSSL-3-7-2-COMM, origin/master, origin/HEAD, master) |
| + | * |
| + | * Multiprecision Montgomery Reduction. |
| + | */ |
| + | /* |
| + | * Copyright (c) 2013-2015 INSIDE Secure Corporation |
| + | * Copyright (c) PeerSec Networks, 2002-2011 |
| + | * All Rights Reserved |
| + | * |
| + | * The latest version of this code is available at http://www.matrixssl.org |
| + | * |
| + | * This software is open source; 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 General Public License does NOT permit incorporating this software |
| + | * into proprietary programs. If you are unable to comply with the GPL, a |
| + | * commercial license for this software may be purchased from INSIDE at |
| + | * http://www.insidesecure.com/eng/Company/Locations |
| + | * |
| + | * This program is distributed in 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 |
| + | * http://www.gnu.org/copyleft/gpl.html |
| + | */ |
| + | /******************************************************************************/ |
| + | |
| + | ///bbox |
| + | //#include "../cryptoApi.h" |
| + | #ifndef DISABLE_PSTM |
| + | |
| + | /******************************************************************************/ |
| + | |
| + | #if defined(PSTM_X86) |
| + | /* x86-32 optimized for 32 bit platforms. For 64 bit mode use X86_64 instead */ |
| + | #if !defined(__GNUC__) || !defined(__i386__) || !defined(PSTM_32BIT) |
| + | #error "PSTM_X86 option requires GCC and 32 bit mode x86 processor" |
| + | #endif |
| + | //#pragma message ("Using 32 bit x86 Assembly Optimizations") |
| + | |
| + | #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(PSTM_X86_64) |
| + | /* x86-64 optimized */ |
| + | #if !defined(__GNUC__) || !defined(__x86_64__) || !defined(PSTM_64BIT) |
| + | #error "PSTM_X86_64 option requires PSTM_64BIT, GCC and 64 bit mode x86 processor" |
| + | #endif |
| + | //#pragma message ("Using 64 bit x86_64 Assembly Optimizations") |
| + | |
| + | #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(PSTM_ARM) |
| + | |
| + | #define MONT_START |
| + | #define MONT_FINI |
| + | #define LOOP_END |
| + | #define LOOP_START \ |
| + | mu = c[x] * mp |
| + | |
| + | #ifdef __thumb2__ |
| + | //#pragma message ("Using 32 bit ARM Thumb2 Assembly Optimizations") |
| + | #define INNERMUL \ |
| + | asm( \ |
| + | " LDR r0,%1 \n\t" \ |
| + | " ADDS r0,r0,%0 \n\t" \ |
| + | " ITE CS \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++),"m"(_c[0])\ |
| + | :"r0","%cc"); |
| + | #define PROPCARRY \ |
| + | asm( \ |
| + | " LDR r0,%1 \n\t" \ |
| + | " ADDS r0,r0,%0 \n\t" \ |
| + | " STR r0,%1 \n\t" \ |
| + | " ITE CS \n\t" \ |
| + | " MOVCS %0,#1 \n\t" \ |
| + | " MOVCC %0,#0 \n\t" \ |
| + | :"=r"(cy),"=m"(_c[0])\ |
| + | :"0"(cy),"m"(_c[0])\ |
| + | :"r0","%cc"); |
| + | #else /* Non-Thumb2 code */ |
| + | //#pragma message ("Using 32 bit ARM Assembly Optimizations") |
| + | #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++),"m"(_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),"m"(_c[0])\ |
| + | :"r0","%cc"); |
| + | #endif /* __thumb2__ */ |
| + | |
| + | |
| + | /******************************************************************************/ |
| + | #elif defined(PSTM_MIPS) |
| + | /* MIPS32 */ |
| + | //#pragma message ("Using 32 bit MIPS Assembly Optimizations") |
| + | #define MONT_START |
| + | #define MONT_FINI |
| + | #define LOOP_END |
| + | #define LOOP_START \ |
| + | mu = c[x] * mp |
| + | |
| + | #define INNERMUL \ |
| + | asm( \ |
| + | " multu %3,%4 \n\t" \ |
| + | " mflo $12 \n\t" \ |
| + | " mfhi $13 \n\t" \ |
| + | " addu $12,$12,%0 \n\t" \ |
| + | " sltu $10,$12,%0 \n\t" \ |
| + | " addu $13,$13,$10 \n\t" \ |
| + | " lw $10,%1 \n\t" \ |
| + | " addu $12,$12,$10 \n\t" \ |
| + | " sltu $10,$12,$10 \n\t" \ |
| + | " addu %0,$13,$10 \n\t" \ |
| + | " sw $12,%1 \n\t" \ |
| + | :"=r"(cy),"=m"(_c[0])\ |
| + | :"r"(cy),"r"(mu),"r"(tmpm[0]),"r"(_c[0])\ |
| + | :"$10","$12","$13")\ |
| + | ; ++tmpm; |
| + | |
| + | #define PROPCARRY \ |
| + | asm( \ |
| + | " lw $10,%1 \n\t" \ |
| + | " addu $10,$10,%0 \n\t" \ |
| + | " sw $10,%1 \n\t" \ |
| + | " sltu %0,$10,%0 \n\t" \ |
| + | :"=r"(cy),"=m"(_c[0])\ |
| + | :"r"(cy),"r"(_c[0])\ |
| + | :"$10"); |
| + | |
| + | |
| + | /******************************************************************************/ |
| + | #else |
| + | |
| + | /* ISO C code */ |
| + | #define MONT_START |
| + | #define MONT_FINI |
| + | #define LOOP_END |
| + | #define LOOP_START \ |
| + | mu = c[x] * mp |
| + | |
| + | #define INNERMUL \ |
| + | do { pstm_word t; \ |
| + | t = ((pstm_word)_c[0] + (pstm_word)cy) + \ |
| + | (((pstm_word)mu) * ((pstm_word)*tmpm++)); \ |
| + | _c[0] = (pstm_digit)t; \ |
| + | cy = (pstm_digit)(t >> DIGIT_BIT); \ |
| + | } while (0) |
| + | |
| + | #define PROPCARRY \ |
| + | do { pstm_digit t = _c[0] += cy; cy = (t < cy); } while (0) |
| + | |
| + | #endif |
| + | |
| + | /******************************************************************************/ |
| + | |
| + | #define LO 0 |
| + | |
| + | /* computes x/R == x (mod N) via Montgomery Reduction */ |
| + | int32 pstm_montgomery_reduce(psPool_t *pool, pstm_int *a, pstm_int *m, |
| + | pstm_digit mp, pstm_digit *paD, uint32 paDlen) |
| + | { |
| + | pstm_digit *c, *_c, *tmpm, mu; |
| + | int32 oldused, x, y; |
| + | int16 pa; |
| + | |
| + | pa = m->used; |
| + | if (pa > a->alloc) { |
| + | /* Sanity test for bad numbers. This will confirm no buffer overruns */ |
| + | return PS_LIMIT_FAIL; |
| + | } |
| + | |
| + | if (paD && paDlen >= (uint32)2*pa+1) { |
| + | c = paD; |
| + | memset(c, 0x0, paDlen); |
| + | } else { |
| + | c = xzalloc(2*pa+1); |
| + | } |
| + | /* copy the input */ |
| + | oldused = a->used; |
| + | for (x = 0; x < oldused; x++) { |
| + | c[x] = a->dp[x]; |
| + | } |
| + | |
| + | MONT_START; |
| + | |
| + | for (x = 0; x < pa; x++) { |
| + | pstm_digit cy = 0; |
| + | /* get Mu for this round */ |
| + | LOOP_START; |
| + | _c = c + x; |
| + | tmpm = m->dp; |
| + | y = 0; |
| + | #ifdef PSTM_X86_64 |
| + | for (; y < (pa & ~7); y += 8) { |
| + | INNERMUL8; |
| + | _c += 8; |
| + | tmpm += 8; |
| + | } |
| + | #endif /* PSTM_X86_64 */ |
| + | 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; |
| + | pstm_clamp(a); |
| + | |
| + | /* reuse x as return code */ |
| + | x = PSTM_OKAY; |
| + | |
| + | /* if A >= m then A = A - m */ |
| + | if (pstm_cmp_mag (a, m) != PSTM_LT) { |
| + | if (s_pstm_sub (a, m, a) != PSTM_OKAY) { |
| + | x = PS_MEM_FAIL; |
| + | } |
| + | } |
| + | if (paDlen < (uint32)2*pa+1) { |
| + | psFree(c, pool); |
| + | } |
| + | return x; |
| + | } |
| + | |
| + | #endif /* !DISABLE_PSTM */ |
| + | /******************************************************************************/ |
| @@ -0,0 +1,777 @@ | |
| + | /* |
| + | * Copyright (C) 2017 Denys Vlasenko |
| + | * |
| + | * Licensed under GPLv2, see file LICENSE in this source tree. |
| + | */ |
| + | #include "tls.h" |
| + | |
| + | /** |
| + | * @file pstm_mul_comba.c |
| + | * @version 33ef80f (HEAD, tag: MATRIXSSL-3-7-2-OPEN, tag: MATRIXSSL-3-7-2-COMM, origin/master, origin/HEAD, master) |
| + | * |
| + | * Multiprecision multiplication with Comba technique. |
| + | */ |
| + | /* |
| + | * Copyright (c) 2013-2015 INSIDE Secure Corporation |
| + | * Copyright (c) PeerSec Networks, 2002-2011 |
| + | * All Rights Reserved |
| + | * |
| + | * The latest version of this code is available at http://www.matrixssl.org |
| + | * |
| + | * This software is open source; 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 General Public License does NOT permit incorporating this software |
| + | * into proprietary programs. If you are unable to comply with the GPL, a |
| + | * commercial license for this software may be purchased from INSIDE at |
| + | * http://www.insidesecure.com/eng/Company/Locations |
| + | * |
| + | * This program is distributed in 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 |
| + | * http://www.gnu.org/copyleft/gpl.html |
| + | */ |
| + | /******************************************************************************/ |
| + | |
| + | ///bbox |
| + | //#include "../cryptoApi.h" |
| + | #ifndef DISABLE_PSTM |
| + | |
| + | /******************************************************************************/ |
| + | #if defined(PSTM_X86) |
| + | /* x86-32 optimized for 32 bit platforms. For 64 bit mode use X86_64 instead */ |
| + | #if !defined(__GNUC__) || !defined(__i386__) || !defined(PSTM_32BIT) |
| + | #error "PSTM_X86 option requires GCC and 32 bit mode x86 processor" |
| + | #endif |
| + | //#pragma message ("Using 32 bit x86 Assembly 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 |
| + | |
| + | /* 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(PSTM_X86_64) |
| + | /* x86-64 optimized */ |
| + | #if !defined(__GNUC__) || !defined(__x86_64__) || !defined(PSTM_64BIT) |
| + | #error "PSTM_X86_64 option requires PSTM_64BIT, GCC and 64 bit mode x86 processor" |
| + | #endif |
| + | //#pragma message ("Using 64 bit x86_64 Assembly 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 |
| + | |
| + | /* 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(PSTM_ARM) |
| + | /* ARM code */ |
| + | //#pragma message ("Using 32 bit ARM Assembly Optimizations") |
| + | |
| + | #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(PSTM_MIPS) |
| + | /* MIPS32 code */ |
| + | //#pragma message ("Using 32 bit MIPS Assembly Optimizations") |
| + | |
| + | #define COMBA_START |
| + | |
| + | #define COMBA_CLEAR \ |
| + | c0 = c1 = c2 = 0; |
| + | |
| + | #define COMBA_FORWARD \ |
| + | do { c0 = c1; c1 = c2; c2 = 0; } while (0); |
| + | |
| + | #define COMBA_STORE(x) \ |
| + | x = c0; |
| + | |
| + | #define COMBA_STORE2(x) \ |
| + | x = c1; |
| + | |
| + | #define COMBA_FINI |
| + | |
| + | #define MULADD(i, j) \ |
| + | asm( \ |
| + | " multu %6,%7 \n\t" \ |
| + | " mflo $12 \n\t" \ |
| + | " mfhi $13 \n\t" \ |
| + | " addu %0,%0,$12 \n\t" \ |
| + | " sltu $12,%0,$12 \n\t" \ |
| + | " addu %1,%1,$13 \n\t" \ |
| + | " sltu $13,%1,$13 \n\t" \ |
| + | " addu %1,%1,$12 \n\t" \ |
| + | " sltu $12,%1,$12 \n\t" \ |
| + | " addu %2,%2,$13 \n\t" \ |
| + | " addu %2,%2,$12 \n\t" \ |
| + | :"=r"(c0), "=r"(c1), "=r"(c2):"0"(c0), "1"(c1), "2"(c2), "r"(i), "r"(j):"$12","$13"); |
| + | |
| + | /******************************************************************************/ |
| + | #else |
| + | |
| + | #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 { pstm_word t; \ |
| + | t = (pstm_word)c0 + ((pstm_word)i) * ((pstm_word)j); c0 = (pstm_digit)t; \ |
| + | t = (pstm_word)c1 + (t >> DIGIT_BIT); \ |
| + | c1 = (pstm_digit)t; c2 += (pstm_digit)(t >> DIGIT_BIT); \ |
| + | } while (0); |
| + | |
| + | #endif |
| + | |
| + | /******************************************************************************/ |
| + | /* generic PxQ multiplier */ |
| + | ///bbox: pool unused |
| + | #define pstm_mul_comba_gen(pool, A, B, C, paD, paDlen) \ |
| + | pstm_mul_comba_gen( A, B, C, paD, paDlen) |
| + | static int32 pstm_mul_comba_gen(psPool_t *pool, pstm_int *A, pstm_int *B, |
| + | pstm_int *C, pstm_digit *paD, uint32 paDlen) |
| + | { |
| + | int16 paDfail, pa; |
| + | int32 ix, iy, iz, tx, ty; |
| + | pstm_digit c0, c1, c2, *tmpx, *tmpy, *dst; |
| + | |
| + | COMBA_START; |
| + | COMBA_CLEAR; |
| + | |
| + | paDfail = 0; |
| + | /* get size of output and trim */ |
| + | pa = A->used + B->used; |
| + | |
| + | /* |
| + | If c is not large enough grow it and continue |
| + | */ |
| + | if (C->alloc < pa) { |
| + | if (pstm_grow(C, pa) != PSTM_OKAY) { |
| + | return PS_MEM_FAIL; |
| + | } |
| + | } |
| + | if (paD != NULL) { |
| + | if (paDlen < (sizeof(pstm_digit) * pa)) { |
| + | paDfail = 1; /* have a paD but it's not large enough */ |
| + | dst = xzalloc(sizeof(pstm_digit) * pa); |
| + | } else { |
| + | dst = paD; |
| + | memset(dst, 0x0, paDlen); |
| + | } |
| + | } else { |
| + | dst = xzalloc(sizeof(pstm_digit) * pa); |
| + | } |
| + | |
| + | 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 iterate, essentially it's |
| + | while (tx++ < a->used && ty-- >= 0) { ... } |
| + | */ |
| + | iy = min(A->used-tx, ty+1); |
| + | |
| + | /* execute loop */ |
| + | COMBA_FORWARD; |
| + | for (iz = 0; iz < iy; ++iz) { |
| + | MULADD(*tmpx++, *tmpy--); |
| + | } |
| + | |
| + | /* store term */ |
| + | COMBA_STORE(dst[ix]); |
| + | } |
| + | COMBA_FINI; |
| + | /* |
| + | setup dest |
| + | */ |
| + | iy = C->used; |
| + | C->used = pa; |
| + | C->sign = A->sign ^ B->sign; |
| + | { |
| + | pstm_digit *tmpc; |
| + | tmpc = C->dp; |
| + | for (ix = 0; ix < pa; ix++) { |
| + | *tmpc++ = dst[ix]; |
| + | } |
| + | /* |
| + | clear unused digits [that existed in the old copy of c] |
| + | */ |
| + | for (; ix < iy; ix++) { |
| + | *tmpc++ = 0; |
| + | } |
| + | } |
| + | pstm_clamp(C); |
| + | |
| + | if ((paD == NULL) || (paDfail == 1)) { |
| + | psFree(dst, pool); |
| + | } |
| + | |
| + | return PS_SUCCESS; |
| + | } |
| + | |
| + | /******************************************************************************/ |
| + | #ifdef USE_1024_KEY_SPEED_OPTIMIZATIONS |
| + | static int32 pstm_mul_comba16(pstm_int *A, pstm_int *B, pstm_int *C) |
| + | { |
| + | pstm_digit c0, c1, c2, at[32]; |
| + | |
| + | if (C->alloc < 32) { |
| + | if (pstm_grow(C, 32) != PSTM_OKAY) { |
| + | return PS_MEM_FAIL; |
| + | } |
| + | } |
| + | memcpy(at, A->dp, 16 * sizeof(pstm_digit)); |
| + | memcpy(at+16, B->dp, 16 * sizeof(pstm_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; |
| + | pstm_clamp(C); |
| + | COMBA_FINI; |
| + | return PSTM_OKAY; |
| + | } |
| + | #endif /* USE_1024_KEY_SPEED_OPTIMIZATIONS */ |
| + | |
| + | |
| + | #ifdef USE_2048_KEY_SPEED_OPTIMIZATIONS |
| + | static int32 pstm_mul_comba32(pstm_int *A, pstm_int *B, pstm_int *C) |
| + | { |
| + | pstm_digit c0, c1, c2, at[64]; |
| + | int32 out_size; |
| + | |
| + | if (C->alloc < 64) { |
| + | if (pstm_grow(C, 64) != PSTM_OKAY) { |
| + | return PS_MEM_FAIL; |
| + | } |
| + | } |
| + | |
| + | out_size = A->used + B->used; |
| + | memcpy(at, A->dp, 32 * sizeof(pstm_digit)); |
| + | memcpy(at+32, B->dp, 32 * sizeof(pstm_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; pstm_clamp(C); COMBA_FINI; return PSTM_OKAY; } |
| + | |
| + | /* 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; pstm_clamp(C); COMBA_FINI; return PSTM_OKAY; } |
| + | |
| + | /* 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; pstm_clamp(C); COMBA_FINI; return PSTM_OKAY; } |
| + | |
| + | /* 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; |
| + | pstm_clamp(C); |
| + | COMBA_FINI; |
| + | return PSTM_OKAY; |
| + | } |
| + | #endif /* USE_2048_KEY_SPEED_OPTIMIZATIONS */ |
| + | |
| + | /******************************************************************************/ |
| + | |
| + | int32 pstm_mul_comba(psPool_t *pool, pstm_int *A, pstm_int *B, pstm_int *C, |
| + | pstm_digit *paD, uint32 paDlen) |
| + | { |
| + | #ifdef USE_1024_KEY_SPEED_OPTIMIZATIONS |
| + | if (A->used == 16 && B->used == 16) { |
| + | return pstm_mul_comba16(A, B, C); |
| + | } else { |
| + | #ifdef USE_2048_KEY_SPEED_OPTIMIZATIONS |
| + | if (A->used == 32 && B->used == 32) { |
| + | return pstm_mul_comba32(A, B, C); |
| + | } |
| + | #endif /* USE_2048_KEY_SPEED_OPTIMIZATIONS */ |
| + | return pstm_mul_comba_gen(pool, A, B, C, paD, paDlen); |
| + | } |
| + | #else |
| + | #ifdef USE_2048_KEY_SPEED_OPTIMIZATIONS |
| + | if (A->used == 32 && B->used == 32) { |
| + | return pstm_mul_comba32(A, B, C); |
| + | } |
| + | #endif /* USE_2048_KEY_SPEED_OPTIMIZATIONS */ |
| + | return pstm_mul_comba_gen(pool, A, B, C, paD, paDlen); |
| + | #endif |
| + | } |
| + | |
| + | #endif /* !DISABLE_PSTM */ |
| + | /******************************************************************************/ |
| @@ -0,0 +1,1107 @@ | |
| + | /* |
| + | * Copyright (C) 2017 Denys Vlasenko |
| + | * |
| + | * Licensed under GPLv2, see file LICENSE in this source tree. |
| + | */ |
| + | #include "tls.h" |
| + | |
| + | /** |
| + | * @file pstm_sqr_comba.c |
| + | * @version 33ef80f (HEAD, tag: MATRIXSSL-3-7-2-OPEN, tag: MATRIXSSL-3-7-2-COMM, origin/master, origin/HEAD, master) |
| + | * |
| + | * Multiprecision Squaring with Comba technique. |
| + | */ |
| + | /* |
| + | * Copyright (c) 2013-2015 INSIDE Secure Corporation |
| + | * Copyright (c) PeerSec Networks, 2002-2011 |
| + | * All Rights Reserved |
| + | * |
| + | * The latest version of this code is available at http://www.matrixssl.org |
| + | * |
| + | * This software is open source; 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 General Public License does NOT permit incorporating this software |
| + | * into proprietary programs. If you are unable to comply with the GPL, a |
| + | * commercial license for this software may be purchased from INSIDE at |
| + | * http://www.insidesecure.com/eng/Company/Locations |
| + | * |
| + | * This program is distributed in 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 |
| + | * http://www.gnu.org/copyleft/gpl.html |
| + | */ |
| + | /******************************************************************************/ |
| + | |
| + | ///bbox |
| + | //#include "../cryptoApi.h" |
| + | #ifndef DISABLE_PSTM |
| + | |
| + | /******************************************************************************/ |
| + | #if defined(PSTM_X86) |
| + | /* x86-32 optimized for 32 bit platforms. For 64 bit mode use X86_64 instead */ |
| + | #if !defined(__GNUC__) || !defined(__i386__) |
| + | #error "PSTM_X86 option requires GCC and 32 bit mode x86 processor" |
| + | #endif |
| + | //#pragma message ("Using 32 bit x86 Assembly Optimizations") |
| + | |
| + | #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 %6,%%eax \n\t" \ |
| + | "mull %7 \n\t" \ |
| + | "movl %%eax,%0 \n\t" \ |
| + | "movl %%edx,%1 \n\t" \ |
| + | "xorl %2,%2 \n\t" \ |
| + | :"=r"(sc0), "=r"(sc1), "=r"(sc2): "0"(sc0), "1"(sc1), "2"(sc2), "g"(i), "g"(j) :"%eax","%edx","%cc"); |
| + | |
| + | #define SQRADDAC(i, j) \ |
| + | asm( \ |
| + | "movl %6,%%eax \n\t" \ |
| + | "mull %7 \n\t" \ |
| + | "addl %%eax,%0 \n\t" \ |
| + | "adcl %%edx,%1 \n\t" \ |
| + | "adcl $0,%2 \n\t" \ |
| + | :"=r"(sc0), "=r"(sc1), "=r"(sc2): "0"(sc0), "1"(sc1), "2"(sc2), "g"(i), "g"(j) :"%eax","%edx","%cc"); |
| + | |
| + | #define SQRADDDB \ |
| + | asm( \ |
| + | "addl %6,%0 \n\t" \ |
| + | "adcl %7,%1 \n\t" \ |
| + | "adcl %8,%2 \n\t" \ |
| + | "addl %6,%0 \n\t" \ |
| + | "adcl %7,%1 \n\t" \ |
| + | "adcl %8,%2 \n\t" \ |
| + | :"=r"(c0), "=r"(c1), "=r"(c2) : "0"(c0), "1"(c1), "2"(c2), "r"(sc0), "r"(sc1), "r"(sc2) : "%cc"); |
| + | |
| + | /******************************************************************************/ |
| + | #elif defined(PSTM_X86_64) |
| + | /* x86-64 optimized */ |
| + | #if !defined(__GNUC__) || !defined(__x86_64__) || !defined(PSTM_64BIT) |
| + | #error "PSTM_X86_64 option requires PSTM_64BIT, GCC and 64 bit mode x86 processor" |
| + | #endif |
| + | //#pragma message ("Using 64 bit x86_64 Assembly Optimizations") |
| + | |
| + | #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 %6,%%rax \n\t" \ |
| + | "mulq %7 \n\t" \ |
| + | "movq %%rax,%0 \n\t" \ |
| + | "movq %%rdx,%1 \n\t" \ |
| + | "xorq %2,%2 \n\t" \ |
| + | :"=r"(sc0), "=r"(sc1), "=r"(sc2): "0"(sc0), "1"(sc1), "2"(sc2), "g"(i), "g"(j) :"%rax","%rdx","cc"); |
| + | |
| + | #define SQRADDAC(i, j) \ |
| + | asm( \ |
| + | "movq %6,%%rax \n\t" \ |
| + | "mulq %7 \n\t" \ |
| + | "addq %%rax,%0 \n\t" \ |
| + | "adcq %%rdx,%1 \n\t" \ |
| + | "adcq $0,%2 \n\t" \ |
| + | :"=r"(sc0), "=r"(sc1), "=r"(sc2): "0"(sc0), "1"(sc1), "2"(sc2), "g"(i), "g"(j) :"%rax","%rdx","cc"); |
| + | |
| + | #define SQRADDDB \ |
| + | asm( \ |
| + | "addq %6,%0 \n\t" \ |
| + | "adcq %7,%1 \n\t" \ |
| + | "adcq %8,%2 \n\t" \ |
| + | "addq %6,%0 \n\t" \ |
| + | "adcq %7,%1 \n\t" \ |
| + | "adcq %8,%2 \n\t" \ |
| + | :"=r"(c0), "=r"(c1), "=r"(c2) : "0"(c0), "1"(c1), "2"(c2), "r"(sc0), "r"(sc1), "r"(sc2) : "cc"); |
| + | |
| + | /******************************************************************************/ |
| + | #elif defined(PSTM_ARM) |
| + | /* ARM code */ |
| + | //#pragma message ("Using 32 bit ARM Assembly Optimizations") |
| + | |
| + | #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(PSTM_MIPS) |
| + | /* MIPS32 */ |
| + | //#pragma message ("Using 32 bit MIPS Assembly Optimizations") |
| + | |
| + | #define COMBA_START |
| + | |
| + | #define CLEAR_CARRY \ |
| + | c0 = c1 = c2 = 0; |
| + | |
| + | #define COMBA_STORE(x) \ |
| + | x = c0; |
| + | |
| + | #define COMBA_STORE2(x) \ |
| + | x = c1; |
| + | |
| + | #define CARRY_FORWARD \ |
| + | do { c0 = c1; c1 = c2; c2 = 0; } while (0); |
| + | |
| + | #define COMBA_FINI |
| + | |
| + | /* multiplies point i and j, updates carry "c1" and digit c2 */ |
| + | #define SQRADD(i, j) \ |
| + | asm( \ |
| + | " multu %6,%6 \n\t" \ |
| + | " mflo $12 \n\t" \ |
| + | " mfhi $13 \n\t" \ |
| + | " addu %0,%0,$12 \n\t" \ |
| + | " sltu $12,%0,$12 \n\t" \ |
| + | " addu %1,%1,$13 \n\t" \ |
| + | " sltu $13,%1,$13 \n\t" \ |
| + | " addu %1,%1,$12 \n\t" \ |
| + | " sltu $12,%1,$12 \n\t" \ |
| + | " addu %2,%2,$13 \n\t" \ |
| + | " addu %2,%2,$12 \n\t" \ |
| + | :"=r"(c0), "=r"(c1), "=r"(c2):"0"(c0), "1"(c1), "2"(c2), "r"(i):"$12","$13"); |
| + | |
| + | /* for squaring some of the terms are doubled... */ |
| + | #define SQRADD2(i, j) \ |
| + | asm( \ |
| + | " multu %6,%7 \n\t" \ |
| + | " mflo $12 \n\t" \ |
| + | " mfhi $13 \n\t" \ |
| + | \ |
| + | " addu %0,%0,$12 \n\t" \ |
| + | " sltu $14,%0,$12 \n\t" \ |
| + | " addu %1,%1,$13 \n\t" \ |
| + | " sltu $15,%1,$13 \n\t" \ |
| + | " addu %1,%1,$14 \n\t" \ |
| + | " sltu $14,%1,$14 \n\t" \ |
| + | " addu %2,%2,$15 \n\t" \ |
| + | " addu %2,%2,$14 \n\t" \ |
| + | \ |
| + | " addu %0,%0,$12 \n\t" \ |
| + | " sltu $14,%0,$12 \n\t" \ |
| + | " addu %1,%1,$13 \n\t" \ |
| + | " sltu $15,%1,$13 \n\t" \ |
| + | " addu %1,%1,$14 \n\t" \ |
| + | " sltu $14,%1,$14 \n\t" \ |
| + | " addu %2,%2,$15 \n\t" \ |
| + | " addu %2,%2,$14 \n\t" \ |
| + | :"=r"(c0), "=r"(c1), "=r"(c2):"0"(c0), "1"(c1), "2"(c2), "r"(i), "r"(j):"$12", "$13", "$14", "$15"); |
| + | |
| + | #define SQRADDSC(i, j) \ |
| + | asm( \ |
| + | " multu %6,%7 \n\t" \ |
| + | " mflo %0 \n\t" \ |
| + | " mfhi %1 \n\t" \ |
| + | " xor %2,%2,%2 \n\t" \ |
| + | :"=r"(sc0), "=r"(sc1), "=r"(sc2):"0"(sc0), "1"(sc1), "2"(sc2), "r"(i),"r"(j) : "%cc"); |
| + | |
| + | #define SQRADDAC(i, j) \ |
| + | asm( \ |
| + | " multu %6,%7 \n\t" \ |
| + | " mflo $12 \n\t" \ |
| + | " mfhi $13 \n\t" \ |
| + | " addu %0,%0,$12 \n\t" \ |
| + | " sltu $12,%0,$12 \n\t" \ |
| + | " addu %1,%1,$13 \n\t" \ |
| + | " sltu $13,%1,$13 \n\t" \ |
| + | " addu %1,%1,$12 \n\t" \ |
| + | " sltu $12,%1,$12 \n\t" \ |
| + | " addu %2,%2,$13 \n\t" \ |
| + | " addu %2,%2,$12 \n\t" \ |
| + | :"=r"(sc0), "=r"(sc1), "=r"(sc2):"0"(sc0), "1"(sc1), "2"(sc2), "r"(i), "r"(j):"$12", "$13", "$14"); |
| + | |
| + | #define SQRADDDB \ |
| + | asm( \ |
| + | " addu %0,%0,%3 \n\t" \ |
| + | " sltu $10,%0,%3 \n\t" \ |
| + | " addu %1,%1,$10 \n\t" \ |
| + | " sltu $10,%1,$10 \n\t" \ |
| + | " addu %1,%1,%4 \n\t" \ |
| + | " sltu $11,%1,%4 \n\t" \ |
| + | " addu %2,%2,$10 \n\t" \ |
| + | " addu %2,%2,$11 \n\t" \ |
| + | " addu %2,%2,%5 \n\t" \ |
| + | \ |
| + | " addu %0,%0,%3 \n\t" \ |
| + | " sltu $10,%0,%3 \n\t" \ |
| + | " addu %1,%1,$10 \n\t" \ |
| + | " sltu $10,%1,$10 \n\t" \ |
| + | " addu %1,%1,%4 \n\t" \ |
| + | " sltu $11,%1,%4 \n\t" \ |
| + | " addu %2,%2,$10 \n\t" \ |
| + | " addu %2,%2,$11 \n\t" \ |
| + | " addu %2,%2,%5 \n\t" \ |
| + | :"=r"(c0), "=r"(c1), "=r"(c2) : "r"(sc0), "r"(sc1), "r"(sc2), "0"(c0), "1"(c1), "2"(c2) : "$10", "$11"); |
| + | |
| + | #else |
| + | /******************************************************************************/ |
| + | #define PSTM_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 { pstm_word t; \ |
| + | t = c0 + ((pstm_word)i) * ((pstm_word)j); c0 = (pstm_digit)t; \ |
| + | t = c1 + (t >> DIGIT_BIT); \ |
| + | c1 = (pstm_digit)t; c2 += (pstm_digit)(t >> DIGIT_BIT); \ |
| + | } while (0); |
| + | |
| + | |
| + | /* for squaring some of the terms are doubled... */ |
| + | #define SQRADD2(i, j) \ |
| + | do { pstm_word t; \ |
| + | t = ((pstm_word)i) * ((pstm_word)j); \ |
| + | tt = (pstm_word)c0 + t; c0 = (pstm_digit)tt; \ |
| + | tt = (pstm_word)c1 + (tt >> DIGIT_BIT); \ |
| + | c1 = (pstm_digit)tt; c2 += (pstm_digit)(tt >> DIGIT_BIT); \ |
| + | tt = (pstm_word)c0 + t; c0 = (pstm_digit)tt; \ |
| + | tt = (pstm_word)c1 + (tt >> DIGIT_BIT); \ |
| + | c1 = (pstm_digit)tt; c2 += (pstm_digit)(tt >> DIGIT_BIT); \ |
| + | } while (0); |
| + | |
| + | #define SQRADDSC(i, j) \ |
| + | do { pstm_word t; \ |
| + | t = ((pstm_word)i) * ((pstm_word)j); \ |
| + | sc0 = (pstm_digit)t; sc1 = (pstm_digit)(t >> DIGIT_BIT); sc2 = 0; \ |
| + | } while (0); |
| + | |
| + | #define SQRADDAC(i, j) \ |
| + | do { pstm_word t; \ |
| + | t = ((pstm_word)sc0) + ((pstm_word)i) * ((pstm_word)j); \ |
| + | sc0 = (pstm_digit)t; \ |
| + | t = ((pstm_word)sc1) + (t >> DIGIT_BIT); sc1 = (pstm_digit)t; \ |
| + | sc2 += (pstm_digit)(t >> DIGIT_BIT); \ |
| + | } while (0); |
| + | |
| + | #define SQRADDDB \ |
| + | do { pstm_word t; \ |
| + | t = ((pstm_word)sc0) + ((pstm_word)sc0) + ((pstm_word)c0); \ |
| + | c0 = (pstm_digit)t; \ |
| + | t = ((pstm_word)sc1) + ((pstm_word)sc1) + c1 + (t >> DIGIT_BIT); \ |
| + | c1 = (pstm_digit)t; \ |
| + | c2 = c2 + sc2 + sc2 + (pstm_digit)(t >> DIGIT_BIT); \ |
| + | } while (0); |
| + | |
| + | #endif /* ISO_C */ |
| + | |
| + | /******************************************************************************/ |
| + | /* |
| + | Non-unrolled comba squarer |
| + | */ |
| + | ///bbox: pool unused |
| + | #define pstm_sqr_comba_gen(pool, A, B, paD, paDlen) \ |
| + | pstm_sqr_comba_gen( A, B, paD, paDlen) |
| + | static int32 pstm_sqr_comba_gen(psPool_t *pool, pstm_int *A, pstm_int *B, |
| + | pstm_digit *paD, uint32 paDlen) |
| + | { |
| + | int16 paDfail, pa; |
| + | int32 ix, iz; |
| + | pstm_digit c0, c1, c2, *dst; |
| + | #ifdef PSTM_ISO |
| + | pstm_word tt; |
| + | #endif |
| + | |
| + | paDfail = 0; |
| + | /* get size of output and trim */ |
| + | pa = A->used + A->used; |
| + | |
| + | /* number of output digits to produce */ |
| + | COMBA_START; |
| + | CLEAR_CARRY; |
| + | /* |
| + | If b is not large enough grow it and continue |
| + | */ |
| + | if (B->alloc < pa) { |
| + | if (pstm_grow(B, pa) != PSTM_OKAY) { |
| + | return PS_MEM_FAIL; |
| + | } |
| + | } |
| + | if (paD != NULL) { |
| + | if (paDlen < (sizeof(pstm_digit) * pa)) { |
| + | paDfail = 1; /* have a paD, but it's not big enough */ |
| + | dst = xzalloc(sizeof(pstm_digit) * pa); |
| + | } else { |
| + | dst = paD; |
| + | memset(dst, 0x0, paDlen); |
| + | } |
| + | } else { |
| + | dst = xzalloc(sizeof(pstm_digit) * pa); |
| + | } |
| + | |
| + | for (ix = 0; ix < pa; ix++) { |
| + | int32 tx, ty, iy; |
| + | pstm_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 iterate, |
| + | while (tx++ < a->used && ty-- >= 0) { ... } |
| + | */ |
| + | iy = min(A->used-tx, ty+1); |
| + | |
| + | /* |
| + | now for squaring tx can never equal ty. We halve the distance since |
| + | they approach at a rate of 2x and we have to round because odd cases |
| + | need to be executed |
| + | */ |
| + | iy = min(iy, (ty-tx+1)>>1); |
| + | |
| + | /* forward carries */ |
| + | CARRY_FORWARD; |
| + | |
| + | /* execute loop */ |
| + | for (iz = 0; iz < iy; iz++) { |
| + | SQRADD2(*tmpx++, *tmpy--); |
| + | } |
| + | |
| + | /* even columns have the square term in them */ |
| + | if ((ix&1) == 0) { |
| + | SQRADD(A->dp[ix>>1], A->dp[ix>>1]); |
| + | } |
| + | |
| + | /* store it */ |
| + | COMBA_STORE(dst[ix]); |
| + | } |
| + | |
| + | COMBA_FINI; |
| + | /* |
| + | setup dest |
| + | */ |
| + | iz = B->used; |
| + | B->used = pa; |
| + | { |
| + | pstm_digit *tmpc; |
| + | tmpc = B->dp; |
| + | for (ix = 0; ix < pa; ix++) { |
| + | *tmpc++ = dst[ix]; |
| + | } |
| + | /* clear unused digits (that existed in the old copy of c) */ |
| + | for (; ix < iz; ix++) { |
| + | *tmpc++ = 0; |
| + | } |
| + | } |
| + | pstm_clamp(B); |
| + | |
| + | if ((paD == NULL) || paDfail == 1) { |
| + | psFree(dst, pool); |
| + | } |
| + | return PS_SUCCESS; |
| + | } |
| + | |
| + | /******************************************************************************/ |
| + | /* |
| + | Unrolled Comba loop for 1024 bit keys |
| + | */ |
| + | #ifdef USE_1024_KEY_SPEED_OPTIMIZATIONS |
| + | static int32 pstm_sqr_comba16(pstm_int *A, pstm_int *B) |
| + | { |
| + | pstm_digit *a, b[32], c0, c1, c2, sc0, sc1, sc2; |
| + | #ifdef PSTM_ISO |
| + | pstm_word tt; |
| + | #endif |
| + | |
| + | if (B->alloc < 32) { |
| + | if (pstm_grow(B, 32) != PSTM_OKAY) { |
| + | return PS_MEM_FAIL; |
| + | } |
| + | } |
| + | a = A->dp; |
| + | sc0 = sc1 = sc2 = 0; |
| + | |
| + | 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 = PSTM_ZPOS; |
| + | memcpy(B->dp, b, 32 * sizeof(pstm_digit)); |
| + | pstm_clamp(B); |
| + | return PSTM_OKAY; |
| + | } |
| + | #endif /* USE_1024_KEY_SPEED_OPTIMIZATIONS */ |
| + | |
| + | |
| + | #ifdef USE_2048_KEY_SPEED_OPTIMIZATIONS |
| + | static int32 pstm_sqr_comba32(pstm_int *A, pstm_int *B) |
| + | { |
| + | pstm_digit *a, b[64], c0, c1, c2, sc0, sc1, sc2; |
| + | #ifdef PSTM_ISO |
| + | pstm_word tt; |
| + | #endif |
| + | |
| + | if (B->alloc < 64) { |
| + | if (pstm_grow(B, 64) != PSTM_OKAY) { |
| + | return PS_MEM_FAIL; |
| + | } |
| + | } |
| + | sc0 = sc1 = sc2 = 0; |
| + | 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 = PSTM_ZPOS; |
| + | memcpy(B->dp, b, 64 * sizeof(pstm_digit)); |
| + | pstm_clamp(B); |
| + | return PSTM_OKAY; |
| + | } |
| + | #endif /* USE_2048_KEY_SPEED_OPTIMIZATIONS */ |
| + | |
| + | /******************************************************************************/ |
| + | /* |
| + | */ |
| + | int32 pstm_sqr_comba(psPool_t *pool, pstm_int *A, pstm_int *B, pstm_digit *paD, |
| + | uint32 paDlen) |
| + | { |
| + | #ifdef USE_1024_KEY_SPEED_OPTIMIZATIONS |
| + | if (A->used == 16) { |
| + | return pstm_sqr_comba16(A, B); |
| + | } else { |
| + | #ifdef USE_2048_KEY_SPEED_OPTIMIZATIONS |
| + | if (A->used == 32) { |
| + | return pstm_sqr_comba32(A, B); |
| + | } |
| + | #endif /* USE_2048_KEY_SPEED_OPTIMIZATIONS */ |
| + | return pstm_sqr_comba_gen(pool, A, B, paD, paDlen); |
| + | } |
| + | #else |
| + | #ifdef USE_2048_KEY_SPEED_OPTIMIZATIONS |
| + | if (A->used == 32) { |
| + | return pstm_sqr_comba32(A, B); |
| + | } |
| + | #endif /* USE_2048_KEY_SPEED_OPTIMIZATIONS */ |
| + | return pstm_sqr_comba_gen(pool, A, B, paD, paDlen); |
| + | #endif |
| + | } |
| + | |
| + | #endif /* DISABLE_PSTM */ |
| + | /******************************************************************************/ |
| @@ -0,0 +1,203 @@ | |
| + | /* |
| + | * Copyright (C) 2017 Denys Vlasenko |
| + | * |
| + | * Licensed under GPLv2, see file LICENSE in this source tree. |
| + | */ |
| + | #include "tls.h" |
| + | |
| + | #define pkcs1Pad(in, inlen, out, outlen, cryptType, userPtr) \ |
| + | pkcs1Pad(in, inlen, out, outlen, cryptType) |
| + | static ///bbox |
| + | int32 pkcs1Pad(unsigned char *in, uint32 inlen, unsigned char *out, |
| + | uint32 outlen, int32 cryptType, void *userPtr) |
| + | { |
| + | unsigned char *c; |
| + | int32 randomLen; |
| + | |
| + | randomLen = outlen - 3 - inlen; |
| + | if (randomLen < 8) { |
| + | psTraceCrypto("pkcs1Pad failure\n"); |
| + | return PS_LIMIT_FAIL; |
| + | } |
| + | c = out; |
| + | *c = 0x00; |
| + | c++; |
| + | *c = (unsigned char)cryptType; |
| + | c++; |
| + | if (cryptType == PUBKEY_TYPE) { |
| + | while (randomLen-- > 0) { |
| + | *c++ = 0xFF; |
| + | } |
| + | } else { |
| + | if (matrixCryptoGetPrngData(c, (uint32)randomLen, userPtr) < 0) { |
| + | return PS_PLATFORM_FAIL; |
| + | } |
| + | /* |
| + | SECURITY: Read through the random data and change all 0x0 to 0x01. |
| + | This is per spec that no random bytes should be 0 |
| + | */ |
| + | while (randomLen-- > 0) { |
| + | if (*c == 0x0) { |
| + | *c = 0x01; |
| + | } |
| + | c++; |
| + | } |
| + | } |
| + | *c = 0x00; |
| + | c++; |
| + | memcpy(c, in, inlen); |
| + | |
| + | return outlen; |
| + | } |
| + | |
| + | #define psRsaCrypt(pool, in, inlen, out, outlen, key, type, data) \ |
| + | psRsaCrypt(pool, in, inlen, out, outlen, key, type) |
| + | static ///bbox |
| + | int32 psRsaCrypt(psPool_t *pool, const unsigned char *in, uint32 inlen, |
| + | unsigned char *out, uint32 *outlen, psRsaKey_t *key, int32 type, |
| + | void *data) |
| + | { |
| + | pstm_int tmp, tmpa, tmpb; |
| + | int32 res; |
| + | uint32 x; |
| + | |
| + | if (in == NULL || out == NULL || outlen == NULL || key == NULL) { |
| + | psTraceCrypto("NULL parameter error in psRsaCrypt\n"); |
| + | return PS_ARG_FAIL; |
| + | } |
| + | |
| + | tmp.dp = tmpa.dp = tmpb.dp = NULL; |
| + | |
| + | /* Init and copy into tmp */ |
| + | if (pstm_init_for_read_unsigned_bin(pool, &tmp, inlen + sizeof(pstm_digit)) |
| + | != PS_SUCCESS) { |
| + | return PS_FAILURE; |
| + | } |
| + | if (pstm_read_unsigned_bin(&tmp, (unsigned char *)in, inlen) != PS_SUCCESS){ |
| + | pstm_clear(&tmp); |
| + | return PS_FAILURE; |
| + | } |
| + | /* Sanity check on the input */ |
| + | if (pstm_cmp(&key->N, &tmp) == PSTM_LT) { |
| + | res = PS_LIMIT_FAIL; |
| + | goto done; |
| + | } |
| + | if (type == PRIVKEY_TYPE) { |
| + | if (key->optimized) { |
| + | if (pstm_init_size(pool, &tmpa, key->p.alloc) != PS_SUCCESS) { |
| + | res = PS_FAILURE; |
| + | goto done; |
| + | } |
| + | if (pstm_init_size(pool, &tmpb, key->q.alloc) != PS_SUCCESS) { |
| + | pstm_clear(&tmpa); |
| + | res = PS_FAILURE; |
| + | goto done; |
| + | } |
| + | if (pstm_exptmod(pool, &tmp, &key->dP, &key->p, &tmpa) != |
| + | PS_SUCCESS) { |
| + | psTraceCrypto("decrypt error: pstm_exptmod dP, p\n"); |
| + | goto error; |
| + | } |
| + | if (pstm_exptmod(pool, &tmp, &key->dQ, &key->q, &tmpb) != |
| + | PS_SUCCESS) { |
| + | psTraceCrypto("decrypt error: pstm_exptmod dQ, q\n"); |
| + | goto error; |
| + | } |
| + | if (pstm_sub(&tmpa, &tmpb, &tmp) != PS_SUCCESS) { |
| + | psTraceCrypto("decrypt error: sub tmpb, tmp\n"); |
| + | goto error; |
| + | } |
| + | if (pstm_mulmod(pool, &tmp, &key->qP, &key->p, &tmp) != PS_SUCCESS) { |
| + | psTraceCrypto("decrypt error: pstm_mulmod qP, p\n"); |
| + | goto error; |
| + | } |
| + | if (pstm_mul_comba(pool, &tmp, &key->q, &tmp, NULL, 0) |
| + | != PS_SUCCESS){ |
| + | psTraceCrypto("decrypt error: pstm_mul q \n"); |
| + | goto error; |
| + | } |
| + | if (pstm_add(&tmp, &tmpb, &tmp) != PS_SUCCESS) { |
| + | psTraceCrypto("decrypt error: pstm_add tmp \n"); |
| + | goto error; |
| + | } |
| + | } else { |
| + | if (pstm_exptmod(pool, &tmp, &key->d, &key->N, &tmp) != |
| + | PS_SUCCESS) { |
| + | psTraceCrypto("psRsaCrypt error: pstm_exptmod\n"); |
| + | goto error; |
| + | } |
| + | } |
| + | } else if (type == PUBKEY_TYPE) { |
| + | if (pstm_exptmod(pool, &tmp, &key->e, &key->N, &tmp) != PS_SUCCESS) { |
| + | psTraceCrypto("psRsaCrypt error: pstm_exptmod\n"); |
| + | goto error; |
| + | } |
| + | } else { |
| + | psTraceCrypto("psRsaCrypt error: invalid type param\n"); |
| + | goto error; |
| + | } |
| + | /* Read it back */ |
| + | x = pstm_unsigned_bin_size(&key->N); |
| + | |
| + | if ((uint32)x > *outlen) { |
| + | res = -1; |
| + | psTraceCrypto("psRsaCrypt error: pstm_unsigned_bin_size\n"); |
| + | goto done; |
| + | } |
| + | /* We want the encrypted value to always be the key size. Pad with 0x0 */ |
| + | while ((uint32)x < (unsigned long)key->size) { |
| + | *out++ = 0x0; |
| + | x++; |
| + | } |
| + | |
| + | *outlen = x; |
| + | /* Convert it */ |
| + | memset(out, 0x0, x); |
| + | |
| + | if (pstm_to_unsigned_bin(pool, &tmp, out+(x-pstm_unsigned_bin_size(&tmp))) |
| + | != PS_SUCCESS) { |
| + | psTraceCrypto("psRsaCrypt error: pstm_to_unsigned_bin\n"); |
| + | goto error; |
| + | } |
| + | /* Clean up and return */ |
| + | res = PS_SUCCESS; |
| + | goto done; |
| + | error: |
| + | res = PS_FAILURE; |
| + | done: |
| + | if (type == PRIVKEY_TYPE && key->optimized) { |
| + | pstm_clear_multi(&tmpa, &tmpb, NULL, NULL, NULL, NULL, NULL, NULL); |
| + | } |
| + | pstm_clear(&tmp); |
| + | return res; |
| + | } |
| + | |
| + | int32 psRsaEncryptPub(psPool_t *pool, psRsaKey_t *key, |
| + | unsigned char *in, uint32 inlen, |
| + | unsigned char *out, uint32 outlen, void *data) |
| + | { |
| + | int32 err; |
| + | uint32 size; |
| + | |
| + | size = key->size; |
| + | if (outlen < size) { |
| + | psTraceCrypto("Error on bad outlen parameter to psRsaEncryptPub\n"); |
| + | return PS_ARG_FAIL; |
| + | } |
| + | |
| + | if ((err = pkcs1Pad(in, inlen, out, size, PRIVKEY_TYPE, data)) |
| + | < PS_SUCCESS) { |
| + | psTraceCrypto("Error padding psRsaEncryptPub. Likely data too long\n"); |
| + | return err; |
| + | } |
| + | if ((err = psRsaCrypt(pool, out, size, out, (uint32*)&outlen, key, |
| + | PUBKEY_TYPE, data)) < PS_SUCCESS) { |
| + | psTraceCrypto("Error performing psRsaEncryptPub\n"); |
| + | return err; |
| + | } |
| + | if (outlen != size) { |
| + | psTraceCrypto("Encrypted size error in psRsaEncryptPub\n"); |
| + | return PS_FAILURE; |
| + | } |
| + | return size; |
| + | } |
| @@ -0,0 +1,18 @@ | |
| + | /* |
| + | * Copyright (C) 2017 Denys Vlasenko |
| + | * |
| + | * Licensed under GPLv2, see file LICENSE in this source tree. |
| + | */ |
| + | |
| + | typedef struct { |
| + | pstm_int e, d, N, qP, dP, dQ, p, q; |
| + | uint32 size; /* Size of the key in bytes */ |
| + | int32 optimized; /* 1 for optimized */ |
| + | psPool_t *pool; |
| + | } psRsaKey_t; |
| + | |
| + | #define psRsaEncryptPub(pool, key, in, inlen, out, outlen, data) \ |
| + | psRsaEncryptPub(pool, key, in, inlen, out, outlen) |
| + | int32 psRsaEncryptPub(psPool_t *pool, psRsaKey_t *key, |
| + | unsigned char *in, uint32 inlen, |
| + | unsigned char *out, uint32 outlen, void *data); |