1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263 |
- /*
- * Copyright (C) 2017 Denys Vlasenko
- *
- * Licensed under GPLv2, see file LICENSE in this source tree.
- */
- #include "tls.h"
- /* The file is taken almost verbatim from matrixssl-3-7-2b-open/crypto/math/.
- * Changes are flagged with //bbox
- */
- /**
- * @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, int b, pstm_int *c); //bbox: was int16 b
- /******************************************************************************/
- /*
- init an pstm_int for a given size
- */
- int32 pstm_init_size(psPool_t *pool, pstm_int * a, uint32 size)
- {
- //bbox
- // uint16 x;
- /*
- alloc mem
- */
- a->dp = xzalloc(sizeof (pstm_digit) * size);//bbox
- //bbox a->pool = pool;
- a->used = 0;
- a->alloc = 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)
- {
- //bbox
- // int32 i;
- /*
- allocate memory required and clear it
- */
- a->dp = xzalloc(sizeof (pstm_digit) * PSTM_DEFAULT_INIT);//bbox
- /*
- 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
- */
- //bbox 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, int size)
- {
- int i; //bbox: was int16
- 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);//bbox
- /*
- 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)
- {
- int n; //bbox: was int16
- 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 = ((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;
- }
- /******************************************************************************/
- /*
- */
- int pstm_count_bits (pstm_int * a)
- {
- int r; //bbox: was int16
- 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, int x)
- {
- int y; //bbox: was int16
- /* 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, int b)
- {
- int x; //bbox: was int16
- 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, int b)
- {
- int z; //bbox: was int16
- /* 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;
- int x, oldused; //bbox: was int16
- /*
- 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)
- {
- int oldbused, oldused; //bbox: was int16
- 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)
- {
- int x, y, oldused; //bbox: was int16
- 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;
- int sa, sb; //bbox: was int16
- 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;
- int bits; //bbox: was int16
- /* 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, int b, pstm_int *c)
- {
- pstm_digit carry, carrytmp, shift;
- int x; //bbox: was int16
- /* 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, int b, pstm_int *c) //bbox: was int16 b
- {
- int x; //bbox: was int16
- /* 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;
- int x, oldused; //bbox: was int16
- 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, int b, pstm_int *c,
- pstm_int *d)
- {
- pstm_digit D, r, rr;
- int32 res;
- int x; //bbox: was int16
- 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)
- {
- int x, oldused; //bbox: was int16
- 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, int toSqr)
- {
- int x; //bbox: was int16
- 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 <bernie@develer.com>
- Copyright (C) 1999 Hewlett-Packard Co
- Copyright (C) 1999 David Mosberger-Tang <davidm@hpl.hp.com>
- */
- #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;
- int n, t, i, norm, neg; //bbox: was int16
- /* 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;
- int size; //bbox: was int16
- 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;
- int bitcpy, bitcnt, mode, digidx, x, y, winsize; //bbox: was int16
- 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);//bbox
- /*
- 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;
- int sa, sb; //bbox: was int16
- /* 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, int len) //bbox: was 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;
- int x; //bbox: was int16
- 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;
- int x; //bbox: was int16
- 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
- */
- //bbox: pool unused
- #define pstm_invmod_slow(pool, a, b, c) \
- pstm_invmod_slow( a, b, c)
- 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 */
- /******************************************************************************/
|