15dfecf96Smrg/* 25dfecf96Smrg * Copyright (c) 2002 by The XFree86 Project, Inc. 35dfecf96Smrg * 45dfecf96Smrg * Permission is hereby granted, free of charge, to any person obtaining a 55dfecf96Smrg * copy of this software and associated documentation files (the "Software"), 65dfecf96Smrg * to deal in the Software without restriction, including without limitation 75dfecf96Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 85dfecf96Smrg * and/or sell copies of the Software, and to permit persons to whom the 95dfecf96Smrg * Software is furnished to do so, subject to the following conditions: 105dfecf96Smrg * 115dfecf96Smrg * The above copyright notice and this permission notice shall be included in 125dfecf96Smrg * all copies or substantial portions of the Software. 135dfecf96Smrg * 145dfecf96Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 155dfecf96Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 165dfecf96Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 175dfecf96Smrg * THE XFREE86 PROJECT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 185dfecf96Smrg * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF 195dfecf96Smrg * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 205dfecf96Smrg * SOFTWARE. 215dfecf96Smrg * 225dfecf96Smrg * Except as contained in this notice, the name of the XFree86 Project shall 235dfecf96Smrg * not be used in advertising or otherwise to promote the sale, use or other 245dfecf96Smrg * dealings in this Software without prior written authorization from the 255dfecf96Smrg * XFree86 Project. 265dfecf96Smrg * 275dfecf96Smrg * Author: Paulo César Pereira de Andrade 285dfecf96Smrg */ 295dfecf96Smrg 305dfecf96Smrg/* $XFree86: xc/programs/xedit/lisp/mp/mpi.c,v 1.12 2002/11/20 07:44:43 paulo Exp $ */ 315dfecf96Smrg 325dfecf96Smrg#include "mp.h" 335dfecf96Smrg 34c2cbb186Smrg#ifdef __APPLE__ 355dfecf96Smrg# define finite(x) isfinite(x) 365dfecf96Smrg#endif 375dfecf96Smrg 385dfecf96Smrg/* 395dfecf96Smrg * Prototypes 405dfecf96Smrg */ 415dfecf96Smrg /* do the hard work of mpi_add and mpi_sub */ 425dfecf96Smrgstatic void mpi_addsub(mpi *rop, mpi *op1, mpi *op2, int sub); 435dfecf96Smrg 445dfecf96Smrg /* logical functions implementation */ 455dfecf96Smrgstatic INLINE BNS mpi_logic(BNS op1, BNS op2, BNS op); 465dfecf96Smrgstatic void mpi_log(mpi *rop, mpi *op1, mpi *op2, BNS op); 475dfecf96Smrg 485dfecf96Smrg /* internal mpi_seti, whithout memory allocation */ 495dfecf96Smrgstatic void _mpi_seti(mpi *rop, long si); 505dfecf96Smrg 515dfecf96Smrg/* 525dfecf96Smrg * Initialization 535dfecf96Smrg */ 545dfecf96Smrgstatic BNS onedig[1] = { 1 }; 555dfecf96Smrgstatic mpi mpone = { 1, 1, 0, (BNS*)&onedig }; 565dfecf96Smrg 575dfecf96Smrg/* 585dfecf96Smrg * Implementation 595dfecf96Smrg */ 605dfecf96Smrgvoid 615dfecf96Smrgmpi_init(mpi *op) 625dfecf96Smrg{ 635dfecf96Smrg op->sign = 0; 645dfecf96Smrg op->size = op->alloc = 1; 655dfecf96Smrg op->digs = mp_malloc(sizeof(BNS)); 665dfecf96Smrg op->digs[0] = 0; 675dfecf96Smrg} 685dfecf96Smrg 695dfecf96Smrgvoid 705dfecf96Smrgmpi_clear(mpi *op) 715dfecf96Smrg{ 725dfecf96Smrg op->sign = 0; 735dfecf96Smrg op->size = op->alloc = 0; 745dfecf96Smrg mp_free(op->digs); 755dfecf96Smrg} 765dfecf96Smrg 775dfecf96Smrgvoid 785dfecf96Smrgmpi_set(mpi *rop, mpi *op) 795dfecf96Smrg{ 805dfecf96Smrg if (rop != op) { 815dfecf96Smrg if (rop->alloc < op->size) { 825dfecf96Smrg rop->digs = mp_realloc(rop->digs, sizeof(BNS) * op->size); 835dfecf96Smrg rop->alloc = op->size; 845dfecf96Smrg } 855dfecf96Smrg rop->size = op->size; 865dfecf96Smrg memcpy(rop->digs, op->digs, sizeof(BNS) * op->size); 875dfecf96Smrg rop->sign = op->sign; 885dfecf96Smrg } 895dfecf96Smrg} 905dfecf96Smrg 915dfecf96Smrgvoid 925dfecf96Smrgmpi_seti(mpi *rop, long si) 935dfecf96Smrg{ 945dfecf96Smrg unsigned long ui; 955dfecf96Smrg int sign = si < 0; 965dfecf96Smrg int size; 975dfecf96Smrg 985dfecf96Smrg if (si == MINSLONG) { 995dfecf96Smrg ui = MINSLONG; 1005dfecf96Smrg size = 2; 1015dfecf96Smrg } 1025dfecf96Smrg else { 1035dfecf96Smrg if (sign) 1045dfecf96Smrg ui = -si; 1055dfecf96Smrg else 1065dfecf96Smrg ui = si; 1075dfecf96Smrg if (ui < CARRY) 1085dfecf96Smrg size = 1; 1095dfecf96Smrg else 1105dfecf96Smrg size = 2; 1115dfecf96Smrg } 1125dfecf96Smrg 1135dfecf96Smrg if (rop->alloc < size) { 1145dfecf96Smrg rop->digs = mp_realloc(rop->digs, sizeof(BNS) * size); 1155dfecf96Smrg rop->alloc = size; 1165dfecf96Smrg } 1175dfecf96Smrg rop->size = size; 1185dfecf96Smrg 1195dfecf96Smrg /* store data in small mp integer */ 1205dfecf96Smrg rop->digs[0] = (BNS)ui; 1215dfecf96Smrg if (size > 1) 1225dfecf96Smrg rop->digs[1] = (BNS)(ui >> BNSBITS); 1235dfecf96Smrg rop->size = size; 1245dfecf96Smrg 1255dfecf96Smrg /* adjust result sign */ 1265dfecf96Smrg rop->sign = sign; 1275dfecf96Smrg} 1285dfecf96Smrg 1295dfecf96Smrgstatic void 1305dfecf96Smrg_mpi_seti(mpi *rop, long si) 1315dfecf96Smrg{ 1325dfecf96Smrg unsigned long ui; 1335dfecf96Smrg int sign = si < 0; 1345dfecf96Smrg int size; 1355dfecf96Smrg 1365dfecf96Smrg if (si == MINSLONG) { 1375dfecf96Smrg ui = MINSLONG; 1385dfecf96Smrg size = 2; 1395dfecf96Smrg } 1405dfecf96Smrg else { 1415dfecf96Smrg if (sign) 1425dfecf96Smrg ui = -si; 1435dfecf96Smrg else 1445dfecf96Smrg ui = si; 1455dfecf96Smrg if (ui < CARRY) 1465dfecf96Smrg size = 1; 1475dfecf96Smrg else 1485dfecf96Smrg size = 2; 1495dfecf96Smrg } 1505dfecf96Smrg 1515dfecf96Smrg rop->digs[0] = (BNS)ui; 1525dfecf96Smrg if (size > 1) 1535dfecf96Smrg rop->digs[1] = (BNS)(ui >> BNSBITS); 1545dfecf96Smrg rop->size = size; 1555dfecf96Smrg 1565dfecf96Smrg rop->sign = sign; 1575dfecf96Smrg} 1585dfecf96Smrg 1595dfecf96Smrgvoid 1605dfecf96Smrgmpi_setd(mpi *rop, double d) 1615dfecf96Smrg{ 1625dfecf96Smrg long i; 1635dfecf96Smrg double mantissa; 1645dfecf96Smrg int shift, exponent; 1655dfecf96Smrg BNI size; 1665dfecf96Smrg 1675dfecf96Smrg if (isnan(d)) 1685dfecf96Smrg d = 0.0; 1695dfecf96Smrg else if (!finite(d)) 1705dfecf96Smrg d = copysign(1.0, d) * DBL_MAX; 1715dfecf96Smrg 1725dfecf96Smrg /* check if number is larger than 1 */ 1735dfecf96Smrg if (fabs(d) < 1.0) { 1745dfecf96Smrg rop->digs[0] = 0; 1755dfecf96Smrg rop->size = 1; 1765dfecf96Smrg rop->sign = d < 0.0; 1775dfecf96Smrg 1785dfecf96Smrg return; 1795dfecf96Smrg } 1805dfecf96Smrg 1815dfecf96Smrg mantissa = frexp(d, &exponent); 1825dfecf96Smrg if (mantissa < 0) 1835dfecf96Smrg mantissa = -mantissa; 1845dfecf96Smrg 1855dfecf96Smrg size = (exponent + (BNSBITS - 1)) / BNSBITS; 1865dfecf96Smrg shift = BNSBITS - (exponent & (BNSBITS - 1)); 1875dfecf96Smrg 1885dfecf96Smrg /* adjust amount of memory */ 1895dfecf96Smrg if (rop->alloc < size) { 1905dfecf96Smrg rop->digs = mp_realloc(rop->digs, sizeof(BNS) * size); 1915dfecf96Smrg rop->alloc = size; 1925dfecf96Smrg } 1935dfecf96Smrg rop->size = size; 1945dfecf96Smrg 1955dfecf96Smrg /* adjust the exponent */ 1965dfecf96Smrg if (shift < BNSBITS) 1975dfecf96Smrg mantissa = ldexp(mantissa, -shift); 1985dfecf96Smrg 1995dfecf96Smrg /* convert double */ 2005dfecf96Smrg for (i = size - 1; i >= 0 && mantissa != 0.0; i--) { 2015dfecf96Smrg mantissa = ldexp(mantissa, BNSBITS); 2025dfecf96Smrg rop->digs[i] = (BNS)mantissa; 2035dfecf96Smrg mantissa -= rop->digs[i]; 2045dfecf96Smrg } 2055dfecf96Smrg for (; i >= 0; i--) 2065dfecf96Smrg rop->digs[i] = 0; 2075dfecf96Smrg 2085dfecf96Smrg /* normalize */ 2095dfecf96Smrg if (size > 1 && rop->digs[size - 1] == 0) 2105dfecf96Smrg --rop->size; 2115dfecf96Smrg 2125dfecf96Smrg rop->sign = d < 0.0; 2135dfecf96Smrg} 2145dfecf96Smrg 2155dfecf96Smrg/* how many BNS in the given base, log(base) / log(CARRY) */ 2165dfecf96Smrg#ifdef LONG64 2175dfecf96Smrgstatic double str_bases[37] = { 2185dfecf96Smrg 0.0000000000000000, 0.0000000000000000, 0.0312500000000000, 2195dfecf96Smrg 0.0495300781475362, 0.0625000000000000, 0.0725602529652301, 2205dfecf96Smrg 0.0807800781475362, 0.0877298413143002, 0.0937500000000000, 2215dfecf96Smrg 0.0990601562950723, 0.1038102529652301, 0.1081072380824156, 2225dfecf96Smrg 0.1120300781475362, 0.1156387411919092, 0.1189798413143002, 2235dfecf96Smrg 0.1220903311127662, 0.1250000000000000, 0.1277332137890731, 2245dfecf96Smrg 0.1303101562950723, 0.1327477347951120, 0.1350602529652300, 2255dfecf96Smrg 0.1372599194618363, 0.1393572380824156, 0.1413613111267817, 2265dfecf96Smrg 0.1432800781475362, 0.1451205059304602, 0.1468887411919092, 2275dfecf96Smrg 0.1485902344426084, 0.1502298413143002, 0.1518119060977367, 2285dfecf96Smrg 0.1533403311127662, 0.1548186346995899, 0.1562500000000000, 2295dfecf96Smrg 0.1576373162299517, 0.1589832137890731, 0.1602900942795302, 2305dfecf96Smrg 0.1615601562950723, 2315dfecf96Smrg}; 2325dfecf96Smrg#else 2335dfecf96Smrgstatic double str_bases[37] = { 2345dfecf96Smrg 0.0000000000000000, 0.0000000000000000, 0.0625000000000000, 2355dfecf96Smrg 0.0990601562950723, 0.1250000000000000, 0.1451205059304602, 2365dfecf96Smrg 0.1615601562950723, 0.1754596826286003, 0.1875000000000000, 2375dfecf96Smrg 0.1981203125901446, 0.2076205059304602, 0.2162144761648311, 2385dfecf96Smrg 0.2240601562950723, 0.2312774823838183, 0.2379596826286003, 2395dfecf96Smrg 0.2441806622255325, 0.2500000000000000, 0.2554664275781462, 2405dfecf96Smrg 0.2606203125901445, 0.2654954695902241, 0.2701205059304602, 2415dfecf96Smrg 0.2745198389236725, 0.2787144761648311, 0.2827226222535633, 2425dfecf96Smrg 0.2865601562950723, 0.2902410118609203, 0.2937774823838183, 2435dfecf96Smrg 0.2971804688852168, 0.3004596826286003, 0.3036238121954733, 2445dfecf96Smrg 0.3066806622255324, 0.3096372693991797, 0.3125000000000000, 2455dfecf96Smrg 0.3152746324599034, 0.3179664275781462, 0.3205801885590604, 2465dfecf96Smrg 0.3231203125901446, 2475dfecf96Smrg}; 2485dfecf96Smrg#endif 2495dfecf96Smrg 2505dfecf96Smrgvoid 2515dfecf96Smrgmpi_setstr(mpi *rop, char *str, int base) 2525dfecf96Smrg{ 2535dfecf96Smrg long i; /* counter */ 2545dfecf96Smrg int sign; /* result sign */ 2555dfecf96Smrg BNI carry; /* carry value */ 2565dfecf96Smrg BNI value; /* temporary value */ 2575dfecf96Smrg BNI size; /* size of result */ 2585dfecf96Smrg char *ptr; /* end of valid input */ 2595dfecf96Smrg 2605dfecf96Smrg /* initialization */ 2615dfecf96Smrg sign = 0; 2625dfecf96Smrg carry = 0; 2635dfecf96Smrg 2645dfecf96Smrg /* skip leading spaces */ 2655dfecf96Smrg while (isspace(*str)) 2665dfecf96Smrg ++str; 2675dfecf96Smrg 2685dfecf96Smrg /* check if sign supplied */ 2695dfecf96Smrg if (*str == '-') { 2705dfecf96Smrg sign = 1; 2715dfecf96Smrg ++str; 2725dfecf96Smrg } 2735dfecf96Smrg else if (*str == '+') 2745dfecf96Smrg ++str; 2755dfecf96Smrg 2765dfecf96Smrg /* skip leading zeros */ 2775dfecf96Smrg while (*str == '0') 2785dfecf96Smrg ++str; 2795dfecf96Smrg 2805dfecf96Smrg ptr = str; 2815dfecf96Smrg while (*ptr) { 2825dfecf96Smrg if (*ptr >= '0' && *ptr <= '9') { 2835dfecf96Smrg if (*ptr - '0' >= base) 2845dfecf96Smrg break; 2855dfecf96Smrg } 2865dfecf96Smrg else if (*ptr >= 'A' && *ptr <= 'Z') { 2875dfecf96Smrg if (*ptr - 'A' + 10 >= base) 2885dfecf96Smrg break; 2895dfecf96Smrg } 2905dfecf96Smrg else if (*ptr >= 'a' && *ptr <= 'z') { 2915dfecf96Smrg if (*ptr - 'a' + 10 >= base) 2925dfecf96Smrg break; 2935dfecf96Smrg } 2945dfecf96Smrg else 2955dfecf96Smrg break; 2965dfecf96Smrg ++ptr; 2975dfecf96Smrg } 2985dfecf96Smrg 2995dfecf96Smrg /* resulting size */ 3005dfecf96Smrg size = (ptr - str) * str_bases[base] + 1; 3015dfecf96Smrg 3025dfecf96Smrg /* make sure rop has enough storage */ 3035dfecf96Smrg if (rop->alloc < size) { 3045dfecf96Smrg rop->digs = mp_realloc(rop->digs, size * sizeof(BNS)); 3055dfecf96Smrg rop->alloc = size; 3065dfecf96Smrg } 3075dfecf96Smrg rop->size = size; 3085dfecf96Smrg 3095dfecf96Smrg /* initialize rop to zero */ 3105dfecf96Smrg memset(rop->digs, '\0', size * sizeof(BNS)); 3115dfecf96Smrg 3125dfecf96Smrg /* set result sign */ 3135dfecf96Smrg rop->sign = sign; 3145dfecf96Smrg 3155dfecf96Smrg /* convert string */ 3165dfecf96Smrg for (; str < ptr; str++) { 3175dfecf96Smrg value = *str; 3185dfecf96Smrg if (islower(value)) 3195dfecf96Smrg value = toupper(value); 3205dfecf96Smrg value = value > '9' ? value - 'A' + 10 : value - '0'; 32131de2854Smrg value += (BNI)rop->digs[0] * base; 3225dfecf96Smrg carry = value >> BNSBITS; 3235dfecf96Smrg rop->digs[0] = (BNS)value; 3245dfecf96Smrg for (i = 1; i < size; i++) { 3255dfecf96Smrg value = (BNI)rop->digs[i] * base + carry; 3265dfecf96Smrg carry = value >> BNSBITS; 3275dfecf96Smrg rop->digs[i] = (BNS)value; 3285dfecf96Smrg } 3295dfecf96Smrg } 3305dfecf96Smrg 3315dfecf96Smrg /* normalize */ 3325dfecf96Smrg if (rop->size > 1 && rop->digs[rop->size - 1] == 0) 3335dfecf96Smrg --rop->size; 3345dfecf96Smrg} 3355dfecf96Smrg 3365dfecf96Smrgvoid 3375dfecf96Smrgmpi_add(mpi *rop, mpi *op1, mpi *op2) 3385dfecf96Smrg{ 3395dfecf96Smrg mpi_addsub(rop, op1, op2, 0); 3405dfecf96Smrg} 3415dfecf96Smrg 3425dfecf96Smrgvoid 3435dfecf96Smrgmpi_addi(mpi *rop, mpi *op1, long op2) 3445dfecf96Smrg{ 3455dfecf96Smrg BNS digs[2]; 3465dfecf96Smrg mpi op; 3475dfecf96Smrg 3485dfecf96Smrg op.digs = (BNS*)digs; 3495dfecf96Smrg _mpi_seti(&op, op2); 3505dfecf96Smrg 3515dfecf96Smrg mpi_addsub(rop, op1, &op, 0); 3525dfecf96Smrg} 3535dfecf96Smrg 3545dfecf96Smrgvoid 3555dfecf96Smrgmpi_sub(mpi *rop, mpi *op1, mpi *op2) 3565dfecf96Smrg{ 3575dfecf96Smrg mpi_addsub(rop, op1, op2, 1); 3585dfecf96Smrg} 3595dfecf96Smrg 3605dfecf96Smrgvoid 3615dfecf96Smrgmpi_subi(mpi *rop, mpi *op1, long op2) 3625dfecf96Smrg{ 3635dfecf96Smrg BNS digs[2]; 3645dfecf96Smrg mpi op; 3655dfecf96Smrg 3665dfecf96Smrg op.digs = (BNS*)digs; 3675dfecf96Smrg _mpi_seti(&op, op2); 3685dfecf96Smrg 3695dfecf96Smrg mpi_addsub(rop, op1, &op, 1); 3705dfecf96Smrg} 3715dfecf96Smrg 3725dfecf96Smrgstatic void 3735dfecf96Smrgmpi_addsub(mpi *rop, mpi *op1, mpi *op2, int sub) 3745dfecf96Smrg{ 3755dfecf96Smrg long xlen; /* maximum result size */ 3765dfecf96Smrg 3775dfecf96Smrg if (sub ^ (op1->sign == op2->sign)) { 3785dfecf96Smrg /* plus one for possible carry */ 3795dfecf96Smrg xlen = MAX(op1->size, op2->size) + 1; 3805dfecf96Smrg if (rop->alloc < xlen) { 3815dfecf96Smrg rop->digs = mp_realloc(rop->digs, sizeof(BNS) * xlen); 3825dfecf96Smrg rop->alloc = xlen; 3835dfecf96Smrg } 3845dfecf96Smrg rop->size = mp_add(rop->digs, op1->digs, op2->digs, 3855dfecf96Smrg op1->size, op2->size); 3865dfecf96Smrg rop->sign = op1->sign; 3875dfecf96Smrg } 3885dfecf96Smrg else { 3895dfecf96Smrg long cmp; /* check for larger operator */ 3905dfecf96Smrg 3915dfecf96Smrg cmp = mpi_cmpabs(op1, op2); 3925dfecf96Smrg if (cmp == 0) { 3935dfecf96Smrg rop->digs[0] = 0; 3945dfecf96Smrg rop->size = 1; 3955dfecf96Smrg rop->sign = 0; 3965dfecf96Smrg } 3975dfecf96Smrg else { 3985dfecf96Smrg xlen = MAX(op1->size, op2->size); 3995dfecf96Smrg if (rop->alloc < xlen) { 4005dfecf96Smrg rop->digs = mp_realloc(rop->digs, sizeof(BNS) * xlen); 4015dfecf96Smrg rop->alloc = xlen; 4025dfecf96Smrg } 4035dfecf96Smrg if (cmp > 0) { 4045dfecf96Smrg rop->size = mp_sub(rop->digs, op1->digs, op2->digs, 4055dfecf96Smrg op1->size, op2->size); 4065dfecf96Smrg rop->sign = op1->sign; 4075dfecf96Smrg } 4085dfecf96Smrg else { 4095dfecf96Smrg rop->size = mp_sub(rop->digs, op2->digs, op1->digs, 4105dfecf96Smrg op2->size, op1->size); 4115dfecf96Smrg rop->sign = sub ^ op2->sign; 4125dfecf96Smrg } 4135dfecf96Smrg } 4145dfecf96Smrg } 4155dfecf96Smrg} 4165dfecf96Smrg 4175dfecf96Smrgvoid 4185dfecf96Smrgmpi_mul(mpi *rop, mpi *op1, mpi *op2) 4195dfecf96Smrg{ 4205dfecf96Smrg int sign; /* sign flag */ 4215dfecf96Smrg BNS *digs; /* result data */ 4225dfecf96Smrg long xsize; /* result size */ 4235dfecf96Smrg 4245dfecf96Smrg /* get result sign */ 4255dfecf96Smrg sign = op1->sign ^ op2->sign; 4265dfecf96Smrg 4275dfecf96Smrg /* check for special cases */ 4285dfecf96Smrg if (op1->size == 1) { 4295dfecf96Smrg if (*op1->digs == 0) { 4305dfecf96Smrg /* multiply by 0 */ 4315dfecf96Smrg mpi_seti(rop, 0); 4325dfecf96Smrg return; 4335dfecf96Smrg } 4345dfecf96Smrg else if (*op1->digs == 1) { 4355dfecf96Smrg /* multiply by +-1 */ 4365dfecf96Smrg if (rop->alloc < op2->size) { 4375dfecf96Smrg rop->digs = mp_realloc(rop->digs, sizeof(BNS) * op2->size); 4385dfecf96Smrg rop->alloc = op2->size; 4395dfecf96Smrg } 4405dfecf96Smrg rop->size = op2->size; 4415dfecf96Smrg memmove(rop->digs, op2->digs, sizeof(BNS) * op2->size); 4425dfecf96Smrg rop->sign = op2->size > 1 || *op2->digs ? sign : 0; 4435dfecf96Smrg 4445dfecf96Smrg return; 4455dfecf96Smrg } 4465dfecf96Smrg } 4475dfecf96Smrg else if (op2->size == 1) { 4485dfecf96Smrg if (*op2->digs == 0) { 4495dfecf96Smrg /* multiply by 0 */ 4505dfecf96Smrg mpi_seti(rop, 0); 4515dfecf96Smrg return; 4525dfecf96Smrg } 4535dfecf96Smrg else if (*op2->digs == 1) { 4545dfecf96Smrg /* multiply by +-1 */ 4555dfecf96Smrg if (rop->alloc < op1->size) { 4565dfecf96Smrg rop->digs = mp_realloc(rop->digs, sizeof(BNS) * op1->size); 4575dfecf96Smrg rop->alloc = op1->size; 4585dfecf96Smrg } 4595dfecf96Smrg rop->size = op1->size; 4605dfecf96Smrg memmove(rop->digs, op1->digs, sizeof(BNS) * op1->size); 4615dfecf96Smrg rop->sign = op1->size > 1 || *op1->digs ? sign : 0; 4625dfecf96Smrg 4635dfecf96Smrg return; 4645dfecf96Smrg } 4655dfecf96Smrg } 4665dfecf96Smrg 4675dfecf96Smrg /* allocate result data and set it to zero */ 4685dfecf96Smrg xsize = op1->size + op2->size; 4695dfecf96Smrg if (rop->digs == op1->digs || rop->digs == op2->digs) 4705dfecf96Smrg /* rop is also an operand */ 4715dfecf96Smrg digs = mp_calloc(1, sizeof(BNS) * xsize); 4725dfecf96Smrg else { 4735dfecf96Smrg if (rop->alloc < xsize) { 4745dfecf96Smrg rop->digs = mp_realloc(rop->digs, sizeof(BNS) * xsize); 4755dfecf96Smrg rop->alloc = xsize; 4765dfecf96Smrg } 4775dfecf96Smrg digs = rop->digs; 4785dfecf96Smrg memset(digs, '\0', sizeof(BNS) * xsize); 4795dfecf96Smrg } 4805dfecf96Smrg 4815dfecf96Smrg /* multiply operands */ 4825dfecf96Smrg xsize = mp_mul(digs, op1->digs, op2->digs, op1->size, op2->size); 4835dfecf96Smrg 4845dfecf96Smrg /* store result in rop */ 4855dfecf96Smrg if (digs != rop->digs) { 4865dfecf96Smrg /* if rop was an operand, free old data */ 4875dfecf96Smrg mp_free(rop->digs); 4885dfecf96Smrg rop->digs = digs; 4895dfecf96Smrg } 4905dfecf96Smrg rop->size = xsize; 4915dfecf96Smrg 4925dfecf96Smrg /* set result sign */ 4935dfecf96Smrg rop->sign = sign; 4945dfecf96Smrg} 4955dfecf96Smrg 4965dfecf96Smrgvoid 4975dfecf96Smrgmpi_muli(mpi *rop, mpi *op1, long op2) 4985dfecf96Smrg{ 4995dfecf96Smrg BNS digs[2]; 5005dfecf96Smrg mpi op; 5015dfecf96Smrg 5025dfecf96Smrg op.digs = (BNS*)digs; 5035dfecf96Smrg _mpi_seti(&op, op2); 5045dfecf96Smrg 5055dfecf96Smrg mpi_mul(rop, op1, &op); 5065dfecf96Smrg} 5075dfecf96Smrg 5085dfecf96Smrgvoid 5095dfecf96Smrgmpi_div(mpi *rop, mpi *num, mpi *den) 5105dfecf96Smrg{ 5115dfecf96Smrg mpi_divqr(rop, NULL, num, den); 5125dfecf96Smrg} 5135dfecf96Smrg 5145dfecf96Smrgvoid 5155dfecf96Smrgmpi_rem(mpi *rop, mpi *num, mpi *den) 5165dfecf96Smrg{ 5175dfecf96Smrg mpi_divqr(NULL, rop, num, den); 5185dfecf96Smrg} 5195dfecf96Smrg 5205dfecf96Smrg/* 5215dfecf96Smrg * Could/should be changed to not allocate qdigs if qrop is NULL 5225dfecf96Smrg * Performance wouldn't suffer too much with a test on every loop iteration. 5235dfecf96Smrg */ 5245dfecf96Smrgvoid 5255dfecf96Smrgmpi_divqr(mpi *qrop, mpi *rrop, mpi *num, mpi *den) 5265dfecf96Smrg{ 5275dfecf96Smrg long i, j; /* counters */ 5285dfecf96Smrg int qsign; /* sign of quotient */ 5295dfecf96Smrg int rsign; /* sign of remainder */ 5305dfecf96Smrg BNI qsize; /* size of quotient */ 5315dfecf96Smrg BNI rsize; /* size of remainder */ 5325dfecf96Smrg BNS qest; /* estimative of quotient value */ 5335dfecf96Smrg BNS *qdigs, *rdigs; /* work copy or result */ 5345dfecf96Smrg BNS *ndigs, *ddigs; /* work copy or divisor and dividend */ 5355dfecf96Smrg BNI value; /* temporary result */ 5365dfecf96Smrg long svalue; /* signed temporary result (2's complement) */ 5375dfecf96Smrg BNS carry, scarry, denorm; /* carry and normalization */ 5385dfecf96Smrg BNI dpos, npos; /* offsets in data */ 5395dfecf96Smrg 5405dfecf96Smrg /* get signs */ 5415dfecf96Smrg rsign = num->sign; 5425dfecf96Smrg qsign = rsign ^ den->sign; 5435dfecf96Smrg 5445dfecf96Smrg /* check for special case */ 5455dfecf96Smrg if (num->size < den->size) { 5465dfecf96Smrg /* quotient is zero and remainder is numerator */ 5475dfecf96Smrg if (rrop && rrop->digs != num->digs) { 5485dfecf96Smrg if (rrop->alloc < num->size) { 5495dfecf96Smrg rrop->digs = mp_realloc(rrop->digs, sizeof(BNS) * num->size); 5505dfecf96Smrg rrop->alloc = num->size; 5515dfecf96Smrg } 5525dfecf96Smrg rrop->size = num->size; 5535dfecf96Smrg memcpy(rrop->digs, num->digs, sizeof(BNS) * num->size); 5545dfecf96Smrg rrop->sign = rsign; 5555dfecf96Smrg } 5565dfecf96Smrg if (qrop) 5575dfecf96Smrg mpi_seti(qrop, 0); 5585dfecf96Smrg 5595dfecf96Smrg return; 5605dfecf96Smrg } 5615dfecf96Smrg 5625dfecf96Smrg /* estimate result sizes */ 5635dfecf96Smrg rsize = den->size; 5645dfecf96Smrg qsize = num->size - den->size + 1; 5655dfecf96Smrg 5665dfecf96Smrg /* offsets */ 5675dfecf96Smrg npos = num->size - 1; 5685dfecf96Smrg dpos = den->size - 1; 5695dfecf96Smrg 5705dfecf96Smrg /* allocate space for quotient and remainder */ 5715dfecf96Smrg if (qrop == NULL || qrop->digs == num->digs || qrop->digs == den->digs) 5725dfecf96Smrg qdigs = mp_calloc(1, sizeof(BNS) * qsize); 5735dfecf96Smrg else { 5745dfecf96Smrg if (qrop->alloc < qsize) { 5755dfecf96Smrg qrop->digs = mp_realloc(qrop->digs, sizeof(BNS) * qsize); 5765dfecf96Smrg qrop->alloc = qsize; 5775dfecf96Smrg } 5785dfecf96Smrg memset(qrop->digs, '\0', sizeof(BNS) * qsize); 5795dfecf96Smrg qdigs = qrop->digs; 5805dfecf96Smrg } 5815dfecf96Smrg if (rrop) { 5825dfecf96Smrg if (rrop->digs == num->digs || rrop->digs == den->digs) 5835dfecf96Smrg rdigs = mp_calloc(1, sizeof(BNS) * rsize); 5845dfecf96Smrg else { 5855dfecf96Smrg if (rrop->alloc < rsize) { 5865dfecf96Smrg rrop->digs = mp_realloc(rrop->digs, sizeof(BNS) * rsize); 5875dfecf96Smrg rrop->alloc = rsize; 5885dfecf96Smrg } 5895dfecf96Smrg memset(rrop->digs, '\0', sizeof(BNS) * rsize); 5905dfecf96Smrg rdigs = rrop->digs; 5915dfecf96Smrg } 5925dfecf96Smrg } 5935dfecf96Smrg else 5945dfecf96Smrg rdigs = NULL; /* fix gcc warning */ 5955dfecf96Smrg 5965dfecf96Smrg /* special case, only one word in divisor */ 5975dfecf96Smrg if (dpos == 0) { 5985dfecf96Smrg for (carry = 0, i = npos; i >= 0; i--) { 5995dfecf96Smrg value = ((BNI)carry << BNSBITS) + num->digs[i]; 6005dfecf96Smrg qdigs[i] = (BNS)(value / den->digs[0]); 6015dfecf96Smrg carry = (BNS)(value % den->digs[0]); 6025dfecf96Smrg } 6035dfecf96Smrg if (rrop) 6045dfecf96Smrg rdigs[0] = carry; 6055dfecf96Smrg 6065dfecf96Smrg goto mpi_divqr_done; 6075dfecf96Smrg } 6085dfecf96Smrg 6095dfecf96Smrg /* make work copy of numerator */ 6105dfecf96Smrg ndigs = mp_malloc(sizeof(BNS) * (num->size + 1)); 6115dfecf96Smrg /* allocate one extra word an update offset */ 6125dfecf96Smrg memcpy(ndigs, num->digs, sizeof(BNS) * num->size); 6135dfecf96Smrg ndigs[num->size] = 0; 6145dfecf96Smrg ++npos; 6155dfecf96Smrg 6165dfecf96Smrg /* normalize */ 6175dfecf96Smrg denorm = (BNS)((BNI)CARRY / ((BNI)(den->digs[dpos]) + 1)); 6185dfecf96Smrg 6195dfecf96Smrg if (denorm > 1) { 6205dfecf96Smrg /* i <= num->size because ndigs has an extra word */ 6215dfecf96Smrg for (carry = 0, i = 0; i <= num->size; i++) { 6225dfecf96Smrg value = ndigs[i] * (BNI)denorm + carry; 6235dfecf96Smrg ndigs[i] = (BNS)value; 6245dfecf96Smrg carry = (BNS)(value >> BNSBITS); 6255dfecf96Smrg } 6265dfecf96Smrg /* make work copy of denominator */ 6275dfecf96Smrg ddigs = mp_malloc(sizeof(BNS) * den->size); 6285dfecf96Smrg memcpy(ddigs, den->digs, sizeof(BNS) * den->size); 6295dfecf96Smrg for (carry = 0, i = 0; i < den->size; i++) { 6305dfecf96Smrg value = ddigs[i] * (BNI)denorm + carry; 6315dfecf96Smrg ddigs[i] = (BNS)value; 6325dfecf96Smrg carry = (BNS)(value >> BNSBITS); 6335dfecf96Smrg } 6345dfecf96Smrg } 6355dfecf96Smrg else 6365dfecf96Smrg /* only allocate copy of denominator if going to change it */ 6375dfecf96Smrg ddigs = den->digs; 6385dfecf96Smrg 6395dfecf96Smrg /* divide mp integers */ 6405dfecf96Smrg for (j = qsize - 1; j >= 0; j--, npos--) { 6415dfecf96Smrg /* estimate quotient */ 6425dfecf96Smrg if (ndigs[npos] == ddigs[dpos]) 6435dfecf96Smrg qest = (BNS)SMASK; 6445dfecf96Smrg else 64531de2854Smrg qest = (BNS)((((BNI)(ndigs[npos]) << BNSBITS) + ndigs[npos - 1]) / 6465dfecf96Smrg ddigs[dpos]); 6475dfecf96Smrg 64831de2854Smrg while ((value = ((BNI)(ndigs[npos]) << BNSBITS) + ndigs[npos - 1] - 6495dfecf96Smrg qest * (BNI)(ddigs[dpos])) < CARRY && 6505dfecf96Smrg ddigs[dpos - 1] * (BNI)qest > 6515dfecf96Smrg (value << BNSBITS) + ndigs[npos - 2]) 6525dfecf96Smrg --qest; 6535dfecf96Smrg 6545dfecf96Smrg /* multiply and subtract */ 6555dfecf96Smrg carry = scarry = 0; 6565dfecf96Smrg for (i = 0; i < den->size; i++) { 6575dfecf96Smrg value = qest * (BNI)ddigs[i] + carry; 6585dfecf96Smrg carry = (BNS)(value >> BNSBITS); 6595dfecf96Smrg svalue = (long)ndigs[npos - dpos + i - 1] - (long)(value & SMASK) - 6605dfecf96Smrg (long)scarry; 6615dfecf96Smrg ndigs[npos - dpos + i - 1] = (BNS)svalue; 6625dfecf96Smrg scarry = svalue < 0; 6635dfecf96Smrg } 6645dfecf96Smrg 6655dfecf96Smrg svalue = (long)ndigs[npos] - (long)(carry & SMASK) - (long)scarry; 6665dfecf96Smrg ndigs[npos] = (BNS)svalue; 6675dfecf96Smrg 6685dfecf96Smrg if (svalue & LMASK) { 6695dfecf96Smrg /* quotient too big */ 6705dfecf96Smrg --qest; 6715dfecf96Smrg carry = 0; 6725dfecf96Smrg for (i = 0; i < den->size; i++) { 6735dfecf96Smrg value = ndigs[npos - dpos + i - 1] + (BNI)carry + (BNI)ddigs[i]; 6745dfecf96Smrg ndigs[npos - dpos + i - 1] = (BNS)value; 6755dfecf96Smrg carry = (BNS)(value >> BNSBITS); 6765dfecf96Smrg } 6775dfecf96Smrg ndigs[npos] += carry; 6785dfecf96Smrg } 6795dfecf96Smrg 6805dfecf96Smrg qdigs[j] = qest; 6815dfecf96Smrg } 6825dfecf96Smrg 6835dfecf96Smrg /* calculate remainder */ 6845dfecf96Smrg if (rrop) { 6855dfecf96Smrg for (carry = 0, j = dpos; j >= 0; j--) { 6865dfecf96Smrg value = ((BNI)carry << BNSBITS) + ndigs[j]; 6875dfecf96Smrg rdigs[j] = (BNS)(value / denorm); 6885dfecf96Smrg carry = (BNS)(value % denorm); 6895dfecf96Smrg } 6905dfecf96Smrg } 6915dfecf96Smrg 6925dfecf96Smrg mp_free(ndigs); 6935dfecf96Smrg if (ddigs != den->digs) 6945dfecf96Smrg mp_free(ddigs); 6955dfecf96Smrg 6965dfecf96Smrgmpi_divqr_done: 6975dfecf96Smrg if (rrop) { 6985dfecf96Smrg if (rrop->digs != rdigs) 6995dfecf96Smrg mp_free(rrop->digs); 7005dfecf96Smrg /* normalize remainder */ 7015dfecf96Smrg for (i = rsize - 1; i >= 0; i--) 7025dfecf96Smrg if (rdigs[i] != 0) 7035dfecf96Smrg break; 7045dfecf96Smrg if (i != rsize - 1) { 7055dfecf96Smrg if (i < 0) { 7065dfecf96Smrg rsign = 0; 7075dfecf96Smrg rsize = 1; 7085dfecf96Smrg } 7095dfecf96Smrg else 7105dfecf96Smrg rsize = i + 1; 7115dfecf96Smrg } 7125dfecf96Smrg rrop->digs = rdigs; 7135dfecf96Smrg rrop->sign = rsign; 7145dfecf96Smrg rrop->size = rsize; 7155dfecf96Smrg } 7165dfecf96Smrg 7175dfecf96Smrg /* normalize quotient */ 7185dfecf96Smrg if (qrop) { 7195dfecf96Smrg if (qrop->digs != qdigs) 7205dfecf96Smrg mp_free(qrop->digs); 7215dfecf96Smrg for (i = qsize - 1; i >= 0; i--) 7225dfecf96Smrg if (qdigs[i] != 0) 7235dfecf96Smrg break; 7245dfecf96Smrg if (i != qsize - 1) { 7255dfecf96Smrg if (i < 0) { 7265dfecf96Smrg qsign = 0; 7275dfecf96Smrg qsize = 1; 7285dfecf96Smrg } 7295dfecf96Smrg else 7305dfecf96Smrg qsize = i + 1; 7315dfecf96Smrg } 7325dfecf96Smrg qrop->digs = qdigs; 7335dfecf96Smrg qrop->sign = qsign; 7345dfecf96Smrg qrop->size = qsize; 7355dfecf96Smrg } 7365dfecf96Smrg else 7375dfecf96Smrg mp_free(qdigs); 7385dfecf96Smrg} 7395dfecf96Smrg 7405dfecf96Smrglong 7415dfecf96Smrgmpi_divqri(mpi *qrop, mpi *num, long den) 7425dfecf96Smrg{ 7435dfecf96Smrg BNS ddigs[2]; 7445dfecf96Smrg mpi dop, rrop; 7455dfecf96Smrg long remainder; 7465dfecf96Smrg 7475dfecf96Smrg dop.digs = (BNS*)ddigs; 7485dfecf96Smrg _mpi_seti(&dop, den); 7495dfecf96Smrg 7505dfecf96Smrg memset(&rrop, '\0', sizeof(mpi)); 7515dfecf96Smrg mpi_init(&rrop); 7525dfecf96Smrg mpi_divqr(qrop, &rrop, num, &dop); 7535dfecf96Smrg remainder = rrop.digs[0]; 7545dfecf96Smrg if (rrop.size > 1) 7555dfecf96Smrg remainder |= (BNI)(rrop.digs[1]) << BNSBITS; 7565dfecf96Smrg if (rrop.sign) 7575dfecf96Smrg remainder = -remainder; 7585dfecf96Smrg mpi_clear(&rrop); 7595dfecf96Smrg 7605dfecf96Smrg return (remainder); 7615dfecf96Smrg} 7625dfecf96Smrg 7635dfecf96Smrgvoid 7645dfecf96Smrgmpi_divi(mpi *rop, mpi *num, long den) 7655dfecf96Smrg{ 7665dfecf96Smrg BNS ddigs[2]; 7675dfecf96Smrg mpi dop; 7685dfecf96Smrg 7695dfecf96Smrg dop.digs = (BNS*)ddigs; 7705dfecf96Smrg _mpi_seti(&dop, den); 7715dfecf96Smrg 7725dfecf96Smrg mpi_divqr(rop, NULL, num, &dop); 7735dfecf96Smrg} 7745dfecf96Smrg 7755dfecf96Smrglong 7765dfecf96Smrgmpi_remi(mpi *num, long den) 7775dfecf96Smrg{ 7785dfecf96Smrg return (mpi_divqri(NULL, num, den)); 7795dfecf96Smrg} 7805dfecf96Smrg 7815dfecf96Smrgvoid 7825dfecf96Smrgmpi_mod(mpi *rop, mpi *num, mpi *den) 7835dfecf96Smrg{ 7845dfecf96Smrg mpi_rem(rop, num, den); 7855dfecf96Smrg if (num->sign ^ den->sign) 7865dfecf96Smrg mpi_add(rop, rop, den); 7875dfecf96Smrg} 7885dfecf96Smrg 7895dfecf96Smrglong 7905dfecf96Smrgmpi_modi(mpi *num, long den) 7915dfecf96Smrg{ 7925dfecf96Smrg long remainder; 7935dfecf96Smrg 7945dfecf96Smrg remainder = mpi_remi(num, den); 7955dfecf96Smrg if (num->sign ^ (den < 0)) 7965dfecf96Smrg remainder += den; 7975dfecf96Smrg 7985dfecf96Smrg return (remainder); 7995dfecf96Smrg} 8005dfecf96Smrg 8015dfecf96Smrgvoid 8025dfecf96Smrgmpi_gcd(mpi *rop, mpi *num, mpi *den) 8035dfecf96Smrg{ 8045dfecf96Smrg long cmp; 8055dfecf96Smrg mpi rem; 8065dfecf96Smrg 8075dfecf96Smrg /* check if result already given */ 8085dfecf96Smrg cmp = mpi_cmpabs(num, den); 8095dfecf96Smrg 8105dfecf96Smrg /* check if num is equal to den or if num is zero */ 8115dfecf96Smrg if (cmp == 0 || (num->size == 1 && num->digs[0] == 0)) { 8125dfecf96Smrg mpi_set(rop, den); 8135dfecf96Smrg rop->sign = 0; 8145dfecf96Smrg return; 8155dfecf96Smrg } 8165dfecf96Smrg /* check if den is not zero */ 8175dfecf96Smrg if (den->size == 1 && den->digs[0] == 0) { 8185dfecf96Smrg mpi_set(rop, num); 8195dfecf96Smrg rop->sign = 0; 8205dfecf96Smrg return; 8215dfecf96Smrg } 8225dfecf96Smrg 8235dfecf96Smrg /* don't call mpi_init, relies on realloc(0, size) == malloc(size) */ 8245dfecf96Smrg memset(&rem, '\0', sizeof(mpi)); 8255dfecf96Smrg 8265dfecf96Smrg /* if num larger than den */ 8275dfecf96Smrg if (cmp > 0) { 8285dfecf96Smrg mpi_rem(&rem, num, den); 8295dfecf96Smrg if (rem.size == 1 && rem.digs[0] == 0) { 8305dfecf96Smrg /* exact division */ 8315dfecf96Smrg mpi_set(rop, den); 8325dfecf96Smrg rop->sign = 0; 8335dfecf96Smrg mpi_clear(&rem); 8345dfecf96Smrg return; 8355dfecf96Smrg } 8365dfecf96Smrg mpi_set(rop, den); 8375dfecf96Smrg } 8385dfecf96Smrg else { 8395dfecf96Smrg mpi_rem(&rem, den, num); 8405dfecf96Smrg if (rem.size == 1 && rem.digs[0] == 0) { 8415dfecf96Smrg /* exact division */ 8425dfecf96Smrg mpi_set(rop, num); 8435dfecf96Smrg rop->sign = 0; 8445dfecf96Smrg mpi_clear(&rem); 8455dfecf96Smrg return; 8465dfecf96Smrg } 8475dfecf96Smrg mpi_set(rop, num); 8485dfecf96Smrg } 8495dfecf96Smrg 8505dfecf96Smrg /* loop using positive values */ 8515dfecf96Smrg rop->sign = rem.sign = 0; 8525dfecf96Smrg 8535dfecf96Smrg /* cannot optimize this inverting rem/rop assignment earlier 8545dfecf96Smrg * because rop mais be an operand */ 8555dfecf96Smrg mpi_swap(rop, &rem); 8565dfecf96Smrg 8575dfecf96Smrg /* Euclides algorithm */ 8585dfecf96Smrg for (;;) { 8595dfecf96Smrg mpi_rem(&rem, &rem, rop); 8605dfecf96Smrg if (rem.size == 1 && rem.digs[0] == 0) 8615dfecf96Smrg break; 8625dfecf96Smrg mpi_swap(rop, &rem); 8635dfecf96Smrg } 8645dfecf96Smrg mpi_clear(&rem); 8655dfecf96Smrg} 8665dfecf96Smrg 8675dfecf96Smrgvoid 8685dfecf96Smrgmpi_lcm(mpi *rop, mpi *num, mpi *den) 8695dfecf96Smrg{ 8705dfecf96Smrg mpi gcd; 8715dfecf96Smrg 8725dfecf96Smrg /* check for zero operand */ 8735dfecf96Smrg if ((num->size == 1 && num->digs[0] == 0) || 8745dfecf96Smrg (den->size == 1 && den->digs[0] == 0)) { 8755dfecf96Smrg rop->digs[0] = 0; 8765dfecf96Smrg rop->sign = 0; 8775dfecf96Smrg return; 8785dfecf96Smrg } 8795dfecf96Smrg 8805dfecf96Smrg /* don't call mpi_init, relies on realloc(0, size) == malloc(size) */ 8815dfecf96Smrg memset(&gcd, '\0', sizeof(mpi)); 8825dfecf96Smrg 8835dfecf96Smrg mpi_gcd(&gcd, num, den); 8845dfecf96Smrg mpi_div(&gcd, den, &gcd); 8855dfecf96Smrg mpi_mul(rop, &gcd, num); 8865dfecf96Smrg rop->sign = 0; 8875dfecf96Smrg 8885dfecf96Smrg mpi_clear(&gcd); 8895dfecf96Smrg} 8905dfecf96Smrg 8915dfecf96Smrgvoid 8925dfecf96Smrgmpi_pow(mpi *rop, mpi *op, unsigned long exp) 8935dfecf96Smrg{ 8945dfecf96Smrg mpi zop, top; 8955dfecf96Smrg 8965dfecf96Smrg if (exp == 2) { 8975dfecf96Smrg mpi_mul(rop, op, op); 8985dfecf96Smrg return; 8995dfecf96Smrg } 9005dfecf96Smrg /* check for op**0 */ 9015dfecf96Smrg else if (exp == 0) { 9025dfecf96Smrg rop->digs[0] = 1; 9035dfecf96Smrg rop->size = 1; 9045dfecf96Smrg rop->sign = 0; 9055dfecf96Smrg return; 9065dfecf96Smrg } 9075dfecf96Smrg else if (exp == 1) { 9085dfecf96Smrg mpi_set(rop, op); 9095dfecf96Smrg return; 9105dfecf96Smrg } 9115dfecf96Smrg else if (op->size == 1) { 9125dfecf96Smrg if (op->digs[0] == 0) { 9135dfecf96Smrg mpi_seti(rop, 0); 9145dfecf96Smrg return; 9155dfecf96Smrg } 9165dfecf96Smrg else if (op->digs[0] == 1) { 9175dfecf96Smrg mpi_seti(rop, op->sign && (exp & 1) ? -1 : 1); 9185dfecf96Smrg return; 9195dfecf96Smrg } 9205dfecf96Smrg } 9215dfecf96Smrg 9225dfecf96Smrg memset(&zop, '\0', sizeof(mpi)); 9235dfecf96Smrg memset(&top, '\0', sizeof(mpi)); 9245dfecf96Smrg mpi_set(&zop, op); 9255dfecf96Smrg mpi_set(&top, op); 9265dfecf96Smrg for (--exp; exp; exp >>= 1) { 9275dfecf96Smrg if (exp & 1) 9285dfecf96Smrg mpi_mul(&zop, &top, &zop); 9295dfecf96Smrg mpi_mul(&top, &top, &top); 9305dfecf96Smrg } 9315dfecf96Smrg 9325dfecf96Smrg mpi_clear(&top); 9335dfecf96Smrg rop->sign = zop.sign; 9345dfecf96Smrg mp_free(rop->digs); 9355dfecf96Smrg rop->digs = zop.digs; 9365dfecf96Smrg rop->size = zop.size; 9375dfecf96Smrg} 9385dfecf96Smrg 9395dfecf96Smrg/* Find integer root of given number using the iteration 9405dfecf96Smrg * x{n+1} = ((K-1) * x{n} + N / x{n}^(K-1)) / K 9415dfecf96Smrg */ 9425dfecf96Smrgint 9435dfecf96Smrgmpi_root(mpi *rop, mpi *op, unsigned long nth) 9445dfecf96Smrg{ 9455dfecf96Smrg long bits, cmp; 9465dfecf96Smrg int exact; 9475dfecf96Smrg int sign; 9485dfecf96Smrg mpi *r, t, temp, quot, old, rem; 9495dfecf96Smrg 9505dfecf96Smrg sign = op->sign; 9515dfecf96Smrg 9525dfecf96Smrg /* divide by zero op**1/0 */ 9535dfecf96Smrg if (nth == 0) { 9545dfecf96Smrg int one = 1, zero = 0; 9555dfecf96Smrg one = one / zero; 9565dfecf96Smrg } 9575dfecf96Smrg /* result is complex */ 9585dfecf96Smrg if (sign && !(nth & 1)) { 9595dfecf96Smrg int one = 1, zero = 0; 9605dfecf96Smrg one = one / zero; 9615dfecf96Smrg } 9625dfecf96Smrg 9635dfecf96Smrg /* special case op**1/1 = op */ 9645dfecf96Smrg if (nth == 1) { 9655dfecf96Smrg mpi_set(rop, op); 9665dfecf96Smrg return (1); 9675dfecf96Smrg } 9685dfecf96Smrg 9695dfecf96Smrg bits = mpi_getsize(op, 2) - 2; 9705dfecf96Smrg 9715dfecf96Smrg if (bits < 0 || bits / nth == 0) { 9725dfecf96Smrg /* integral root is surely less than 2 */ 9735dfecf96Smrg exact = op->size == 1 && (op->digs[0] == 1 || op->digs[0] == 0); 9745dfecf96Smrg mpi_seti(rop, sign ? -1 : op->digs[0] == 0 ? 0 : 1); 9755dfecf96Smrg 9765dfecf96Smrg return (exact == 1); 9775dfecf96Smrg } 9785dfecf96Smrg 9795dfecf96Smrg /* initialize */ 9805dfecf96Smrg if (rop != op) 9815dfecf96Smrg r = rop; 9825dfecf96Smrg else { 9835dfecf96Smrg r = &t; 9845dfecf96Smrg memset(r, '\0', sizeof(mpi)); 9855dfecf96Smrg } 9865dfecf96Smrg memset(&temp, '\0', sizeof(mpi)); 9875dfecf96Smrg memset(", '\0', sizeof(mpi)); 9885dfecf96Smrg memset(&old, '\0', sizeof(mpi)); 9895dfecf96Smrg memset(&rem, '\0', sizeof(mpi)); 9905dfecf96Smrg 9915dfecf96Smrg if (sign) 9925dfecf96Smrg r->sign = 0; 9935dfecf96Smrg 9945dfecf96Smrg /* root aproximation */ 9955dfecf96Smrg mpi_ash(r, op, -(bits - (bits / nth))); 9965dfecf96Smrg 9975dfecf96Smrg for (;;) { 9985dfecf96Smrg mpi_pow(&temp, r, nth - 1); 9995dfecf96Smrg mpi_divqr(", &rem, op, &temp); 10005dfecf96Smrg cmp = mpi_cmpabs(r, "); 10015dfecf96Smrg if (cmp == 0) { 10025dfecf96Smrg exact = mpi_cmpi(&rem, 0) == 0; 10035dfecf96Smrg break; 10045dfecf96Smrg } 10055dfecf96Smrg else if (cmp < 0) { 10065dfecf96Smrg if (mpi_cmpabs(r, &old) == 0) { 10075dfecf96Smrg exact = 0; 10085dfecf96Smrg break; 10095dfecf96Smrg } 10105dfecf96Smrg mpi_set(&old, r); 10115dfecf96Smrg } 10125dfecf96Smrg mpi_muli(&temp, r, nth - 1); 10135dfecf96Smrg mpi_add(", ", &temp); 10145dfecf96Smrg mpi_divi(r, ", nth); 10155dfecf96Smrg } 10165dfecf96Smrg 10175dfecf96Smrg mpi_clear(&temp); 10185dfecf96Smrg mpi_clear("); 10195dfecf96Smrg mpi_clear(&old); 10205dfecf96Smrg mpi_clear(&rem); 10215dfecf96Smrg if (r != rop) { 10225dfecf96Smrg mpi_set(rop, r); 10235dfecf96Smrg mpi_clear(r); 10245dfecf96Smrg } 10255dfecf96Smrg rop->sign = sign; 10265dfecf96Smrg 10275dfecf96Smrg return (exact); 10285dfecf96Smrg} 10295dfecf96Smrg 10305dfecf96Smrg/* 10315dfecf96Smrg * Find square root using the iteration: 10325dfecf96Smrg * x{n+1} = (x{n}+N/x{n})/2 10335dfecf96Smrg */ 10345dfecf96Smrgint 10355dfecf96Smrgmpi_sqrt(mpi *rop, mpi *op) 10365dfecf96Smrg{ 10375dfecf96Smrg long bits, cmp; 10385dfecf96Smrg int exact; 10395dfecf96Smrg mpi *r, t, quot, rem, old; 10405dfecf96Smrg 10415dfecf96Smrg /* result is complex */ 10425dfecf96Smrg if (op->sign) { 10435dfecf96Smrg int one = 1, zero = 0; 10445dfecf96Smrg one = one / zero; 10455dfecf96Smrg } 10465dfecf96Smrg 10475dfecf96Smrg bits = mpi_getsize(op, 2) - 2; 10485dfecf96Smrg 10495dfecf96Smrg if (bits < 2) { 10505dfecf96Smrg /* integral root is surely less than 2 */ 10515dfecf96Smrg exact = op->size == 1 && (op->digs[0] == 1 || op->digs[0] == 0); 10525dfecf96Smrg mpi_seti(rop, op->digs[0] == 0 ? 0 : 1); 10535dfecf96Smrg 10545dfecf96Smrg return (exact == 1); 10555dfecf96Smrg } 10565dfecf96Smrg 10575dfecf96Smrg /* initialize */ 10585dfecf96Smrg if (rop != op) 10595dfecf96Smrg r = rop; 10605dfecf96Smrg else { 10615dfecf96Smrg r = &t; 10625dfecf96Smrg memset(r, '\0', sizeof(mpi)); 10635dfecf96Smrg } 10645dfecf96Smrg memset(", '\0', sizeof(mpi)); 10655dfecf96Smrg memset(&rem, '\0', sizeof(mpi)); 10665dfecf96Smrg memset(&old, '\0', sizeof(mpi)); 10675dfecf96Smrg 10685dfecf96Smrg /* root aproximation */ 10695dfecf96Smrg mpi_ash(r, op, -(bits - (bits / 2))); 10705dfecf96Smrg 10715dfecf96Smrg for (;;) { 10725dfecf96Smrg if (mpi_cmpabs(r, &old) == 0) { 10735dfecf96Smrg exact = 0; 10745dfecf96Smrg break; 10755dfecf96Smrg } 10765dfecf96Smrg mpi_divqr(", &rem, op, r); 10775dfecf96Smrg cmp = mpi_cmpabs(", r); 10785dfecf96Smrg if (cmp == 0) { 10795dfecf96Smrg exact = mpi_cmpi(&rem, 0) == 0; 10805dfecf96Smrg break; 10815dfecf96Smrg } 10825dfecf96Smrg else if (cmp > 0 && rem.size == 1 && rem.digs[0] == 0) 10835dfecf96Smrg mpi_subi(", ", 1); 10845dfecf96Smrg mpi_set(&old, r); 10855dfecf96Smrg mpi_add(r, r, "); 10865dfecf96Smrg mpi_ash(r, r, -1); 10875dfecf96Smrg } 10885dfecf96Smrg mpi_clear("); 10895dfecf96Smrg mpi_clear(&rem); 10905dfecf96Smrg mpi_clear(&old); 10915dfecf96Smrg if (r != rop) { 10925dfecf96Smrg mpi_set(rop, r); 10935dfecf96Smrg mpi_clear(r); 10945dfecf96Smrg } 10955dfecf96Smrg 10965dfecf96Smrg return (exact); 10975dfecf96Smrg} 10985dfecf96Smrg 10995dfecf96Smrgvoid 11005dfecf96Smrgmpi_ash(mpi *rop, mpi *op, long shift) 11015dfecf96Smrg{ 11025dfecf96Smrg long i; /* counter */ 11035dfecf96Smrg long xsize; /* maximum result size */ 11045dfecf96Smrg BNS *digs; 11055dfecf96Smrg 11065dfecf96Smrg /* check for 0 shift, multiply/divide by 1 */ 11075dfecf96Smrg if (shift == 0) { 11085dfecf96Smrg if (rop != op) { 11095dfecf96Smrg if (rop->alloc < op->size) { 11105dfecf96Smrg rop->digs = mp_realloc(rop->digs, sizeof(BNS) * op->size); 11115dfecf96Smrg rop->alloc = op->size; 11125dfecf96Smrg } 11135dfecf96Smrg rop->size = op->size; 11145dfecf96Smrg memcpy(rop->digs, op->digs, sizeof(BNS) * op->size); 11155dfecf96Smrg } 11165dfecf96Smrg 11175dfecf96Smrg return; 11185dfecf96Smrg } 11195dfecf96Smrg else if (op->size == 1 && op->digs[0] == 0) { 11205dfecf96Smrg rop->sign = 0; 11215dfecf96Smrg rop->size = 1; 11225dfecf96Smrg rop->digs[0] = 0; 11235dfecf96Smrg 11245dfecf96Smrg return; 11255dfecf96Smrg } 11265dfecf96Smrg 11275dfecf96Smrg /* check shift and initialize */ 11285dfecf96Smrg if (shift > 0) 11295dfecf96Smrg xsize = op->size + (shift / BNSBITS) + 1; 11305dfecf96Smrg else { 11315dfecf96Smrg xsize = op->size - ((-shift) / BNSBITS); 11325dfecf96Smrg if (xsize <= 0) { 11335dfecf96Smrg rop->size = 1; 11345dfecf96Smrg rop->sign = op->sign; 11355dfecf96Smrg rop->digs[0] = op->sign ? 1 : 0; 11365dfecf96Smrg 11375dfecf96Smrg return; 11385dfecf96Smrg } 11395dfecf96Smrg } 11405dfecf96Smrg 11415dfecf96Smrg /* allocate/adjust memory for result */ 11425dfecf96Smrg if (rop == op) 11435dfecf96Smrg digs = mp_malloc(sizeof(BNS) * xsize); 11445dfecf96Smrg else { 11455dfecf96Smrg if (rop->alloc < xsize) { 11465dfecf96Smrg rop->digs = mp_realloc(rop->digs, sizeof(BNS) * xsize); 11475dfecf96Smrg rop->alloc = xsize; 11485dfecf96Smrg } 11495dfecf96Smrg digs = rop->digs; 11505dfecf96Smrg } 11515dfecf96Smrg 11525dfecf96Smrg /* left shift, multiply by power of two */ 11535dfecf96Smrg if (shift > 0) 11545dfecf96Smrg rop->size = mp_lshift(digs, op->digs, op->size, shift); 11555dfecf96Smrg /* right shift, divide by power of two */ 11565dfecf96Smrg else { 11575dfecf96Smrg long carry = 0; 11585dfecf96Smrg 11595dfecf96Smrg if (op->sign) { 11605dfecf96Smrg BNI words, bits; 11615dfecf96Smrg 11625dfecf96Smrg words = -shift / BNSBITS; 11635dfecf96Smrg bits = -shift % BNSBITS; 11645dfecf96Smrg for (i = 0; i < words; i++) 11655dfecf96Smrg carry |= op->digs[xsize + i]; 11665dfecf96Smrg if (!carry) { 11675dfecf96Smrg for (i = 0; i < bits; i++) 11685dfecf96Smrg if (op->digs[op->size - xsize] & (1 << i)) { 11695dfecf96Smrg carry = 1; 11705dfecf96Smrg break; 11715dfecf96Smrg } 11725dfecf96Smrg } 11735dfecf96Smrg } 11745dfecf96Smrg rop->size = mp_rshift(digs, op->digs, op->size, -shift); 11755dfecf96Smrg 11765dfecf96Smrg if (carry) 11775dfecf96Smrg /* emulates two's complement subtracting 1 from the result */ 11785dfecf96Smrg rop->size = mp_add(digs, digs, mpone.digs, rop->size, 1); 11795dfecf96Smrg } 11805dfecf96Smrg 11815dfecf96Smrg if (rop->digs != digs) { 11825dfecf96Smrg mp_free(rop->digs); 11835dfecf96Smrg rop->alloc = rop->size; 11845dfecf96Smrg rop->digs = digs; 11855dfecf96Smrg } 11865dfecf96Smrg rop->sign = op->sign; 11875dfecf96Smrg} 11885dfecf96Smrg 11895dfecf96Smrgstatic INLINE BNS 11905dfecf96Smrgmpi_logic(BNS op1, BNS op2, BNS op) 11915dfecf96Smrg{ 11925dfecf96Smrg switch (op) { 11935dfecf96Smrg case '&': 11945dfecf96Smrg return (op1 & op2); 11955dfecf96Smrg case '|': 11965dfecf96Smrg return (op1 | op2); 11975dfecf96Smrg case '^': 11985dfecf96Smrg return (op1 ^ op2); 11995dfecf96Smrg } 12005dfecf96Smrg 12015dfecf96Smrg return (SMASK); 12025dfecf96Smrg} 12035dfecf96Smrg 12045dfecf96Smrgstatic void 12055dfecf96Smrgmpi_log(mpi *rop, mpi *op1, mpi *op2, BNS op) 12065dfecf96Smrg{ 12075dfecf96Smrg long i; /* counter */ 12085dfecf96Smrg long c, c1, c2; /* carry */ 12095dfecf96Smrg BNS *digs, *digs1, *digs2; /* pointers to mp data */ 12105dfecf96Smrg BNI size, size1, size2; 12115dfecf96Smrg BNS sign, sign1, sign2; 12125dfecf96Smrg BNS n, n1, n2; /* logical operands */ 12135dfecf96Smrg BNI sum; 12145dfecf96Smrg 12155dfecf96Smrg /* initialize */ 12165dfecf96Smrg size1 = op1->size; 12175dfecf96Smrg size2 = op2->size; 12185dfecf96Smrg 12195dfecf96Smrg sign1 = op1->sign ? SMASK : 0; 12205dfecf96Smrg sign2 = op2->sign ? SMASK : 0; 12215dfecf96Smrg 12225dfecf96Smrg sign = mpi_logic(sign1, sign2, op); 12235dfecf96Smrg 12245dfecf96Smrg size = MAX(size1, size2); 12255dfecf96Smrg if (sign) 12265dfecf96Smrg ++size; 12275dfecf96Smrg if (rop->alloc < size) { 12285dfecf96Smrg rop->digs = mp_realloc(rop->digs, sizeof(BNS) * size); 12295dfecf96Smrg rop->alloc = size; 12305dfecf96Smrg } 12315dfecf96Smrg 12325dfecf96Smrg digs = rop->digs; 12335dfecf96Smrg digs1 = op1->digs; 12345dfecf96Smrg digs2 = op2->digs; 12355dfecf96Smrg 12365dfecf96Smrg c = c1 = c2 = 1; 12375dfecf96Smrg 12385dfecf96Smrg /* apply logical operation */ 12395dfecf96Smrg for (i = 0; i < size; i++) { 12405dfecf96Smrg if (i >= size1) 12415dfecf96Smrg n1 = sign1; 12425dfecf96Smrg else if (sign1) { 12435dfecf96Smrg sum = (BNI)(BNS)(~digs1[i]) + c1; 12445dfecf96Smrg c1 = (long)(sum >> BNSBITS); 12455dfecf96Smrg n1 = (BNS)sum; 12465dfecf96Smrg } 12475dfecf96Smrg else 12485dfecf96Smrg n1 = digs1[i]; 12495dfecf96Smrg 12505dfecf96Smrg if (i >= size2) 12515dfecf96Smrg n2 = sign2; 12525dfecf96Smrg else if (sign2) { 12535dfecf96Smrg sum = (BNI)(BNS)(~digs2[i]) + c2; 12545dfecf96Smrg c2 = (long)(sum >> BNSBITS); 12555dfecf96Smrg n2 = (BNS)sum; 12565dfecf96Smrg } 12575dfecf96Smrg else 12585dfecf96Smrg n2 = digs2[i]; 12595dfecf96Smrg 12605dfecf96Smrg n = mpi_logic(n1, n2, op); 12615dfecf96Smrg if (sign) { 12625dfecf96Smrg sum = (BNI)(BNS)(~n) + c; 12635dfecf96Smrg c = (long)(sum >> BNSBITS); 12645dfecf96Smrg digs[i] = (BNS)sum; 12655dfecf96Smrg } 12665dfecf96Smrg else 12675dfecf96Smrg digs[i] = n; 12685dfecf96Smrg } 12695dfecf96Smrg 12705dfecf96Smrg /* normalize */ 12715dfecf96Smrg for (i = size - 1; i >= 0; i--) 12725dfecf96Smrg if (digs[i] != 0) 12735dfecf96Smrg break; 12745dfecf96Smrg if (i != size - 1) { 12755dfecf96Smrg if (i < 0) { 12765dfecf96Smrg sign = 0; 12775dfecf96Smrg size = 1; 12785dfecf96Smrg } 12795dfecf96Smrg else 12805dfecf96Smrg size = i + 1; 12815dfecf96Smrg } 12825dfecf96Smrg 12835dfecf96Smrg rop->sign = sign != 0; 12845dfecf96Smrg rop->size = size; 12855dfecf96Smrg} 12865dfecf96Smrg 12875dfecf96Smrgvoid 12885dfecf96Smrgmpi_and(mpi *rop, mpi *op1, mpi *op2) 12895dfecf96Smrg{ 12905dfecf96Smrg mpi_log(rop, op1, op2, '&'); 12915dfecf96Smrg} 12925dfecf96Smrg 12935dfecf96Smrgvoid 12945dfecf96Smrgmpi_ior(mpi *rop, mpi *op1, mpi *op2) 12955dfecf96Smrg{ 12965dfecf96Smrg mpi_log(rop, op1, op2, '|'); 12975dfecf96Smrg} 12985dfecf96Smrg 12995dfecf96Smrgvoid 13005dfecf96Smrgmpi_xor(mpi *rop, mpi *op1, mpi *op2) 13015dfecf96Smrg{ 13025dfecf96Smrg mpi_log(rop, op1, op2, '^'); 13035dfecf96Smrg} 13045dfecf96Smrg 13055dfecf96Smrgvoid 13065dfecf96Smrgmpi_com(mpi *rop, mpi *op) 13075dfecf96Smrg{ 13085dfecf96Smrg static BNS digs[1] = { 1 }; 13095dfecf96Smrg static mpi one = { 0, 1, 1, (BNS*)&digs }; 13105dfecf96Smrg 13115dfecf96Smrg mpi_log(rop, rop, &one, '^'); 13125dfecf96Smrg} 13135dfecf96Smrg 13145dfecf96Smrgvoid 13155dfecf96Smrgmpi_neg(mpi *rop, mpi *op) 13165dfecf96Smrg{ 13175dfecf96Smrg int sign = op->sign ^ 1; 13185dfecf96Smrg 13195dfecf96Smrg if (rop->digs != op->digs) { 13205dfecf96Smrg if (rop->alloc < op->size) { 13215dfecf96Smrg rop->digs = mp_realloc(rop->digs, sizeof(BNS) * rop->size); 13225dfecf96Smrg rop->alloc = op->size; 13235dfecf96Smrg } 13245dfecf96Smrg rop->size = op->size; 13255dfecf96Smrg memcpy(rop->digs, op->digs, sizeof(BNS) * rop->size); 13265dfecf96Smrg } 13275dfecf96Smrg 13285dfecf96Smrg rop->sign = sign; 13295dfecf96Smrg} 13305dfecf96Smrg 13315dfecf96Smrgvoid 13325dfecf96Smrgmpi_abs(mpi *rop, mpi *op) 13335dfecf96Smrg{ 13345dfecf96Smrg if (rop->digs != op->digs) { 13355dfecf96Smrg if (rop->alloc < op->size) { 13365dfecf96Smrg rop->digs = mp_realloc(rop->digs, sizeof(BNS) * rop->size); 13375dfecf96Smrg rop->alloc = op->size; 13385dfecf96Smrg } 13395dfecf96Smrg rop->size = op->size; 13405dfecf96Smrg memcpy(rop->digs, op->digs, sizeof(BNS) * rop->size); 13415dfecf96Smrg } 13425dfecf96Smrg 13435dfecf96Smrg rop->sign = 0; 13445dfecf96Smrg} 13455dfecf96Smrg 13465dfecf96Smrgint 13475dfecf96Smrgmpi_cmp(mpi *op1, mpi *op2) 13485dfecf96Smrg{ 13495dfecf96Smrg if (op1->sign ^ op2->sign) 13505dfecf96Smrg return (op1->sign ? -1 : 1); 13515dfecf96Smrg 13525dfecf96Smrg if (op1->size == op2->size) { 13535dfecf96Smrg long i, cmp = 0; 13545dfecf96Smrg 13555dfecf96Smrg for (i = op1->size - 1; i >= 0; i--) 13565dfecf96Smrg if ((cmp = (long)op1->digs[i] - (long)op2->digs[i]) != 0) 13575dfecf96Smrg break; 13585dfecf96Smrg 13595dfecf96Smrg return (cmp == 0 ? 0 : (cmp < 0) ^ op1->sign ? -1 : 1); 13605dfecf96Smrg } 13615dfecf96Smrg 13625dfecf96Smrg return ((op1->size < op2->size) ^ op1->sign ? -1 : 1); 13635dfecf96Smrg} 13645dfecf96Smrg 13655dfecf96Smrgint 13665dfecf96Smrgmpi_cmpi(mpi *op1, long op2) 13675dfecf96Smrg{ 13685dfecf96Smrg long cmp; 13695dfecf96Smrg 13705dfecf96Smrg if (op1->size > 2) 13715dfecf96Smrg return (op1->sign ? -1 : 1); 13725dfecf96Smrg 13735dfecf96Smrg cmp = op1->digs[0]; 13745dfecf96Smrg if (op1->size == 2) { 13755dfecf96Smrg cmp |= (long)op1->digs[1] << BNSBITS; 13765dfecf96Smrg if (cmp == MINSLONG) 13775dfecf96Smrg return (op2 == cmp && op1->sign ? 0 : op1->sign ? -1 : 1); 13785dfecf96Smrg } 13795dfecf96Smrg if (op1->sign) 13805dfecf96Smrg cmp = -cmp; 13815dfecf96Smrg 13825dfecf96Smrg return (cmp - op2); 13835dfecf96Smrg} 13845dfecf96Smrg 13855dfecf96Smrgint 13865dfecf96Smrgmpi_cmpabs(mpi *op1, mpi *op2) 13875dfecf96Smrg{ 13885dfecf96Smrg if (op1->size == op2->size) { 13895dfecf96Smrg long i, cmp = 0; 13905dfecf96Smrg 13915dfecf96Smrg for (i = op1->size - 1; i >= 0; i--) 13925dfecf96Smrg if ((cmp = (long)op1->digs[i] - (long)op2->digs[i]) != 0) 13935dfecf96Smrg break; 13945dfecf96Smrg 13955dfecf96Smrg return (cmp); 13965dfecf96Smrg } 13975dfecf96Smrg 13985dfecf96Smrg return ((op1->size < op2->size) ? -1 : 1); 13995dfecf96Smrg} 14005dfecf96Smrg 14015dfecf96Smrgint 14025dfecf96Smrgmpi_cmpabsi(mpi *op1, long op2) 14035dfecf96Smrg{ 14045dfecf96Smrg unsigned long cmp; 14055dfecf96Smrg 14065dfecf96Smrg if (op1->size > 2) 14075dfecf96Smrg return (1); 14085dfecf96Smrg 14095dfecf96Smrg cmp = op1->digs[0]; 14105dfecf96Smrg if (op1->size == 2) 14115dfecf96Smrg cmp |= (unsigned long)op1->digs[1] << BNSBITS; 14125dfecf96Smrg 14135dfecf96Smrg return (cmp > op2 ? 1 : cmp == op2 ? 0 : -1); 14145dfecf96Smrg} 14155dfecf96Smrg 14165dfecf96Smrgint 14175dfecf96Smrgmpi_sgn(mpi *op) 14185dfecf96Smrg{ 14195dfecf96Smrg return (op->sign ? -1 : op->size > 1 || op->digs[0] ? 1 : 0); 14205dfecf96Smrg} 14215dfecf96Smrg 14225dfecf96Smrgvoid 14235dfecf96Smrgmpi_swap(mpi *op1, mpi *op2) 14245dfecf96Smrg{ 14255dfecf96Smrg if (op1 != op2) { 14265dfecf96Smrg mpi swap; 14275dfecf96Smrg 14285dfecf96Smrg memcpy(&swap, op1, sizeof(mpi)); 14295dfecf96Smrg memcpy(op1, op2, sizeof(mpi)); 14305dfecf96Smrg memcpy(op2, &swap, sizeof(mpi)); 14315dfecf96Smrg } 14325dfecf96Smrg} 14335dfecf96Smrg 14345dfecf96Smrgint 14355dfecf96Smrgmpi_fiti(mpi *op) 14365dfecf96Smrg{ 14375dfecf96Smrg if (op->size == 1) 14385dfecf96Smrg return (1); 14395dfecf96Smrg else if (op->size == 2) { 14405dfecf96Smrg unsigned long value = ((BNI)(op->digs[1]) << BNSBITS) | op->digs[0]; 14415dfecf96Smrg 14425dfecf96Smrg if (value & MINSLONG) 14435dfecf96Smrg return (op->sign && value == MINSLONG) ? 1 : 0; 14445dfecf96Smrg 14455dfecf96Smrg return (1); 14465dfecf96Smrg } 14475dfecf96Smrg 14485dfecf96Smrg return (0); 14495dfecf96Smrg} 14505dfecf96Smrg 14515dfecf96Smrglong 14525dfecf96Smrgmpi_geti(mpi *op) 14535dfecf96Smrg{ 14545dfecf96Smrg long value; 14555dfecf96Smrg 14565dfecf96Smrg value = op->digs[0]; 14575dfecf96Smrg if (op->size > 1) 14585dfecf96Smrg value |= (BNI)(op->digs[1]) << BNSBITS; 14595dfecf96Smrg 14605dfecf96Smrg return (op->sign && value != MINSLONG ? -value : value); 14615dfecf96Smrg} 14625dfecf96Smrg 14635dfecf96Smrgdouble 14645dfecf96Smrgmpi_getd(mpi *op) 14655dfecf96Smrg{ 14665dfecf96Smrg long i, len; 14675dfecf96Smrg double d = 0.0; 14685dfecf96Smrg int exponent; 14695dfecf96Smrg 14705dfecf96Smrg#define FLOATDIGS sizeof(double) / sizeof(BNS) 14715dfecf96Smrg 14725dfecf96Smrg switch (op->size) { 14735dfecf96Smrg case 2: 14745dfecf96Smrg d = (BNI)(op->digs[1]) << BNSBITS; 14755dfecf96Smrg case 1: 14765dfecf96Smrg d += op->digs[0]; 14775dfecf96Smrg return (op->sign ? -d : d); 14785dfecf96Smrg default: 14795dfecf96Smrg break; 14805dfecf96Smrg } 14815dfecf96Smrg 14825dfecf96Smrg for (i = 0, len = op->size; len > 0 && i < FLOATDIGS; i++) 14835dfecf96Smrg d = ldexp(d, BNSBITS) + op->digs[--len]; 14845dfecf96Smrg d = frexp(d, &exponent); 14855dfecf96Smrg if (len > 0) 14865dfecf96Smrg exponent += len * BNSBITS; 14875dfecf96Smrg 14885dfecf96Smrg if (d == 0.0) 14895dfecf96Smrg return (d); 14905dfecf96Smrg 14915dfecf96Smrg d = ldexp(d, exponent); 14925dfecf96Smrg 14935dfecf96Smrg return (op->sign ? -d : d); 14945dfecf96Smrg} 14955dfecf96Smrg 14965dfecf96Smrg/* how many digits in a given base, floor(log(CARRY) / log(base)) */ 14975dfecf96Smrg#ifdef LONG64 14985dfecf96Smrgstatic char dig_bases[37] = { 14995dfecf96Smrg 0, 0, 32, 20, 16, 13, 12, 11, 10, 10, 9, 9, 8, 8, 8, 8, 15005dfecf96Smrg 8, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 15015dfecf96Smrg 6, 6, 6, 6, 6, 15025dfecf96Smrg}; 15035dfecf96Smrg#else 15045dfecf96Smrgstatic char dig_bases[37] = { 15055dfecf96Smrg 0, 0, 16, 10, 8, 6, 6, 5, 5, 5, 4, 4, 4, 4, 4, 4, 15065dfecf96Smrg 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 15075dfecf96Smrg 3, 3, 3, 3, 3, 15085dfecf96Smrg}; 15095dfecf96Smrg#endif 15105dfecf96Smrg 15115dfecf96Smrg/* how many digits per bit in a given base, log(2) / log(base) */ 15125dfecf96Smrgstatic double bit_bases[37] = { 15135dfecf96Smrg 0.0000000000000000, 0.0000000000000000, 1.0000000000000000, 15145dfecf96Smrg 0.6309297535714575, 0.5000000000000000, 0.4306765580733931, 15155dfecf96Smrg 0.3868528072345416, 0.3562071871080222, 0.3333333333333334, 15165dfecf96Smrg 0.3154648767857287, 0.3010299956639811, 0.2890648263178878, 15175dfecf96Smrg 0.2789429456511298, 0.2702381544273197, 0.2626495350371936, 15185dfecf96Smrg 0.2559580248098155, 0.2500000000000000, 0.2446505421182260, 15195dfecf96Smrg 0.2398124665681315, 0.2354089133666382, 0.2313782131597592, 15205dfecf96Smrg 0.2276702486969530, 0.2242438242175754, 0.2210647294575037, 15215dfecf96Smrg 0.2181042919855316, 0.2153382790366965, 0.2127460535533632, 15225dfecf96Smrg 0.2103099178571525, 0.2080145976765095, 0.2058468324604344, 15235dfecf96Smrg 0.2037950470905062, 0.2018490865820999, 0.2000000000000000, 15245dfecf96Smrg 0.1982398631705605, 0.1965616322328226, 0.1949590218937863, 15255dfecf96Smrg 0.1934264036172708, 15265dfecf96Smrg}; 15275dfecf96Smrg 15285dfecf96Smrg/* normalization base for string conversion, pow(base, dig_bases[base]) & ~CARRY */ 15295dfecf96Smrg#ifdef LONG64 15305dfecf96Smrgstatic BNS big_bases[37] = { 15315dfecf96Smrg 0x00000001, 0x00000001, 0x00000000, 0xCFD41B91, 0x00000000, 0x48C27395, 15325dfecf96Smrg 0x81BF1000, 0x75DB9C97, 0x40000000, 0xCFD41B91, 0x3B9ACA00, 0x8C8B6D2B, 15335dfecf96Smrg 0x19A10000, 0x309F1021, 0x57F6C100, 0x98C29B81, 0x00000000, 0x18754571, 15345dfecf96Smrg 0x247DBC80, 0x3547667B, 0x4C4B4000, 0x6B5A6E1D, 0x94ACE180, 0xCAF18367, 15355dfecf96Smrg 0x0B640000, 0x0E8D4A51, 0x1269AE40, 0x17179149, 0x1CB91000, 0x23744899, 15365dfecf96Smrg 0x2B73A840, 0x34E63B41, 0x40000000, 0x4CFA3CC1, 0x5C13D840, 0x6D91B519, 15375dfecf96Smrg 0x81BF1000, 15385dfecf96Smrg}; 15395dfecf96Smrg#else 15405dfecf96Smrgstatic BNS big_bases[37] = { 15415dfecf96Smrg 0x0001, 0x0001, 0x0000, 0xE6A9, 0x0000, 0x3D09, 0xB640, 0x41A7, 0x8000, 15425dfecf96Smrg 0xE6A9, 0x2710, 0x3931, 0x5100, 0x6F91, 0x9610, 0xC5C1, 0x0000, 0x1331, 15435dfecf96Smrg 0x16C8, 0x1ACB, 0x1F40, 0x242D, 0x2998, 0x2F87, 0x3600, 0x3D09, 0x44A8, 15445dfecf96Smrg 0x4CE3, 0x55C0, 0x5F45, 0x6978, 0x745F, 0x8000, 0x8C61, 0x9988, 0xA77B, 15455dfecf96Smrg 0xb640, 15465dfecf96Smrg}; 15475dfecf96Smrg#endif 15485dfecf96Smrg 15495dfecf96Smrgunsigned long 15505dfecf96Smrgmpi_getsize(mpi *op, int base) 15515dfecf96Smrg{ 15525dfecf96Smrg unsigned long value, bits; 15535dfecf96Smrg 15545dfecf96Smrg value = op->digs[op->size - 1]; 15555dfecf96Smrg 15565dfecf96Smrg /* count leading bits */ 15575dfecf96Smrg if (value) { 15585dfecf96Smrg unsigned long count, carry; 15595dfecf96Smrg 15605dfecf96Smrg for (count = 0, carry = CARRY >> 1; carry; count++, carry >>= 1) 15615dfecf96Smrg if (value & carry) 15625dfecf96Smrg break; 15635dfecf96Smrg 15645dfecf96Smrg bits = BNSBITS - count; 15655dfecf96Smrg } 15665dfecf96Smrg else 15675dfecf96Smrg bits = 0; 15685dfecf96Smrg 15695dfecf96Smrg return ((bits + (op->size - 1) * BNSBITS) * bit_bases[base] + 1); 15705dfecf96Smrg} 15715dfecf96Smrg 15725dfecf96Smrgchar * 15735dfecf96Smrgmpi_getstr(char *str, mpi *op, int base) 15745dfecf96Smrg{ 15755dfecf96Smrg long i; /* counter */ 15765dfecf96Smrg BNS *digs, *xdigs; /* copy of op data */ 15775dfecf96Smrg BNI size; /* size of op */ 15785dfecf96Smrg BNI digits; /* digits per word in given base */ 15795dfecf96Smrg BNI bigbase; /* big base of given base */ 15805dfecf96Smrg BNI strsize; /* size of resulting string */ 15815dfecf96Smrg char *cp; /* pointer in str for conversion */ 15825dfecf96Smrg 15835dfecf96Smrg /* initialize */ 15845dfecf96Smrg size = op->size; 15855dfecf96Smrg strsize = mpi_getsize(op, base) + op->sign + 1; 15865dfecf96Smrg 15875dfecf96Smrg if (str == NULL) 15885dfecf96Smrg str = mp_malloc(strsize); 15895dfecf96Smrg 15905dfecf96Smrg /* check for zero */ 15915dfecf96Smrg if (size == 1 && op->digs[0] == 0) { 15925dfecf96Smrg str[0] = '0'; 15935dfecf96Smrg str[1] = '\0'; 15945dfecf96Smrg 15955dfecf96Smrg return (str); 15965dfecf96Smrg } 15975dfecf96Smrg 15985dfecf96Smrg digits = dig_bases[base]; 15995dfecf96Smrg bigbase = big_bases[base]; 16005dfecf96Smrg 16015dfecf96Smrg cp = str + strsize; 16025dfecf96Smrg *--cp = '\0'; 16035dfecf96Smrg 16045dfecf96Smrg /* make copy of op data and adjust digs */ 16055dfecf96Smrg xdigs = mp_malloc(size * sizeof(BNS)); 160631de2854Smrg memcpy(xdigs, op->digs, size * sizeof(BNS)); 16075dfecf96Smrg digs = xdigs + size - 1; 16085dfecf96Smrg 16095dfecf96Smrg /* convert to string */ 16105dfecf96Smrg for (;;) { 16115dfecf96Smrg long count = -1; 16125dfecf96Smrg BNI value; 16135dfecf96Smrg BNS quotient, remainder = 0; 16145dfecf96Smrg 16155dfecf96Smrg /* if power of two base */ 16165dfecf96Smrg if ((base & (base - 1)) == 0) { 16175dfecf96Smrg for (i = 0; i < size; i++) { 16185dfecf96Smrg quotient = remainder; 16195dfecf96Smrg remainder = digs[-i]; 16205dfecf96Smrg digs[-i] = quotient; 16215dfecf96Smrg if (count < 0 && quotient) 16225dfecf96Smrg count = i; 16235dfecf96Smrg } 16245dfecf96Smrg } 16255dfecf96Smrg else { 16265dfecf96Smrg for (i = 0; i < size; i++) { 16275dfecf96Smrg value = digs[-i] + ((BNI)remainder << BNSBITS); 16285dfecf96Smrg quotient = (BNS)(value / bigbase); 16295dfecf96Smrg remainder = (BNS)(value % bigbase); 16305dfecf96Smrg digs[-i] = quotient; 16315dfecf96Smrg if (count < 0 && quotient) 16325dfecf96Smrg count = i; 16335dfecf96Smrg } 16345dfecf96Smrg } 16355dfecf96Smrg quotient = remainder; 16365dfecf96Smrg for (i = 0; i < digits; i++) { 16375dfecf96Smrg if (quotient == 0 && count < 0) 16385dfecf96Smrg break; 16395dfecf96Smrg remainder = quotient % base; 16405dfecf96Smrg quotient /= base; 16415dfecf96Smrg *--cp = remainder < 10 ? remainder + '0' : remainder - 10 + 'A'; 16425dfecf96Smrg } 16435dfecf96Smrg if (count < 0) 16445dfecf96Smrg break; 16455dfecf96Smrg digs -= count; 16465dfecf96Smrg size -= count; 16475dfecf96Smrg } 16485dfecf96Smrg 16495dfecf96Smrg /* adjust sign */ 16505dfecf96Smrg if (op->sign) 16515dfecf96Smrg *--cp = '-'; 16525dfecf96Smrg 16535dfecf96Smrg /* remove any extra characters */ 16545dfecf96Smrg if (cp > str) 16555dfecf96Smrg strcpy(str, cp); 16565dfecf96Smrg 16575dfecf96Smrg mp_free(xdigs); 16585dfecf96Smrg 16595dfecf96Smrg return (str); 16605dfecf96Smrg} 1661