mpi-genesis             1 
mpi-genesis             2  *	Copyright (C) 1994, 1996, 1998, 2000 Free Software Foundation, Inc.
mpi-genesis             3  *
mpi-genesis             4  * This file is part of GnuPG.
mpi-genesis             5  *
mpi-genesis             6  * GnuPG is free software; you can redistribute it and/or modify
mpi-genesis             7  * it under the terms of the GNU General Public License as published by
mpi-genesis             8  * the Free Software Foundation; either version 3 of the License, or
mpi-genesis             9  * (at your option) any later version.
mpi-genesis            10  *
mpi-genesis            11  * GnuPG is distributed in the hope that it will be useful,
mpi-genesis            12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
mpi-genesis            13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
mpi-genesis            14  * GNU General Public License for more details.
mpi-genesis            15  *
mpi-genesis            16  * You should have received a copy of the GNU General Public License
mpi-genesis            17  * along with this program; if not, see <http:
mpi-genesis            18  *
mpi-genesis            19  * Note: This code is heavily based on the GNU MP Library.
mpi-genesis            20  *	 Actually it's the same code with only minor changes in the
mpi-genesis            21  *	 way the data is stored; this is to support the abstraction
mpi-genesis            22  *	 of an optional secure memory allocation which may be used
mpi-genesis            23  *	 to avoid revealing of sensitive data due to paging etc.
mpi-genesis            24  *	 The GNU MP Library itself is published under the LGPL;
mpi-genesis            25  *	 however I decided to publish this code under the plain GPL.
mpi-genesis            26  */
mpi-genesis            27 
mpi-genesis            28 #include <config.h>
mpi-genesis            29 #include <stdio.h>
mpi-genesis            30 #include <stdlib.h>
mpi-genesis            31 #include <string.h>
mpi-genesis            32 #include "mpi-internal.h"
mpi-genesis            33 #include "longlong.h"
mpi-genesis            34 #include <assert.h>
mpi-genesis            35 
mpi-genesis            36 
mpi-genesis            37 
mpi-genesis            38  * RES = BASE ^ EXP mod MOD
mpi-genesis            39  */
mpi-genesis            40 void
mpi-genesis            41 mpi_powm( MPI res, MPI base, MPI exponent, MPI mod)
mpi-genesis            42 {
mpi-genesis            43     mpi_ptr_t  rp, ep, mp, bp;
mpi-genesis            44     mpi_size_t esize, msize, bsize, rsize;
mpi-genesis            45     int        esign, msign, bsign, rsign;
mpi-genesis            46     int        esec,  msec,  bsec,  rsec;
mpi-genesis            47     mpi_size_t size;
mpi-genesis            48     int mod_shift_cnt;
mpi-genesis            49     int negative_result;
mpi-genesis            50     mpi_ptr_t mp_marker=NULL, bp_marker=NULL, ep_marker=NULL;
mpi-genesis            51     mpi_ptr_t xp_marker=NULL;
mpi-genesis            52     int assign_rp=0;
mpi-genesis            53     mpi_ptr_t tspace = NULL;
mpi-genesis            54     mpi_size_t tsize=0;   
mpi-genesis            55 			  
mpi-genesis            56 
mpi-genesis            57     esize = exponent->nlimbs;
mpi-genesis            58     msize = mod->nlimbs;
mpi-genesis            59     size = 2 * msize;
mpi-genesis            60     esign = exponent->sign;
mpi-genesis            61     msign = mod->sign;
mpi-genesis            62 
mpi-genesis            63     esec = mpi_is_secure(exponent);
mpi-genesis            64     msec = mpi_is_secure(mod);
mpi-genesis            65     bsec = mpi_is_secure(base);
mpi-genesis            66     rsec = mpi_is_secure(res);
mpi-genesis            67 
mpi-genesis            68     rp = res->d;
mpi-genesis            69     ep = exponent->d;
mpi-genesis            70 
mpi-genesis            71     if( !msize )
mpi-genesis            72 	msize = 1 / msize;	    
mpi-genesis            73 
mpi-genesis            74     if( !esize ) {
mpi-genesis            75 	
mpi-genesis            76 	 * depending on if MOD equals 1.  */
mpi-genesis            77 	rp[0] = 1;
mpi-genesis            78 	res->nlimbs = (msize == 1 && mod->d[0] == 1) ? 0 : 1;
mpi-genesis            79 	res->sign = 0;
mpi-genesis            80 	goto leave;
mpi-genesis            81     }
mpi-genesis            82 
mpi-genesis            83     
mpi-genesis            84      * mpn_divrem.  This will make the intermediate values in the calculation
mpi-genesis            85      * slightly larger, but the correct result is obtained after a final
mpi-genesis            86      * reduction using the original MOD value.	*/
mpi-genesis            87     mp = mp_marker = mpi_alloc_limb_space(msize, msec);
mpi-genesis            88     count_leading_zeros( mod_shift_cnt, mod->d[msize-1] );
mpi-genesis            89     if( mod_shift_cnt )
mpi-genesis            90 	mpihelp_lshift( mp, mod->d, msize, mod_shift_cnt );
mpi-genesis            91     else
mpi-genesis            92 	MPN_COPY( mp, mod->d, msize );
mpi-genesis            93 
mpi-genesis            94     bsize = base->nlimbs;
mpi-genesis            95     bsign = base->sign;
mpi-genesis            96     if( bsize > msize ) { 
mpi-genesis            97 	
mpi-genesis            98 	 * (The quotient is (bsize - msize + 1) limbs.)  */
mpi-genesis            99 	bp = bp_marker = mpi_alloc_limb_space( bsize + 1, bsec );
mpi-genesis           100 	MPN_COPY( bp, base->d, bsize );
mpi-genesis           101 	
mpi-genesis           102 	 * at BP + MSIZE.  */
mpi-genesis           103 	mpihelp_divrem( bp + msize, 0, bp, bsize, mp, msize );
mpi-genesis           104 	bsize = msize;
mpi-genesis           105 	
mpi-genesis           106 	 * quite a few times.  */
mpi-genesis           107 	MPN_NORMALIZE( bp, bsize );
mpi-genesis           108     }
mpi-genesis           109     else
mpi-genesis           110 	bp = base->d;
mpi-genesis           111 
mpi-genesis           112     if( !bsize ) {
mpi-genesis           113 	res->nlimbs = 0;
mpi-genesis           114 	res->sign = 0;
mpi-genesis           115 	goto leave;
mpi-genesis           116     }
mpi-genesis           117 
mpi-genesis           118     if( res->alloced < size ) {
mpi-genesis           119 	
mpi-genesis           120 	 * parameters are identical to RES, defer deallocation of the old
mpi-genesis           121 	 * space.  */
mpi-genesis           122 	if( rp == ep || rp == mp || rp == bp ) {
mpi-genesis           123 	    rp = mpi_alloc_limb_space( size, rsec );
mpi-genesis           124 	    assign_rp = 1;
mpi-genesis           125 	}
mpi-genesis           126 	else {
mpi-genesis           127 	    mpi_resize( res, size );
mpi-genesis           128 	    rp = res->d;
mpi-genesis           129 	}
mpi-genesis           130     }
mpi-genesis           131     else { 
mpi-genesis           132 	if( rp == bp ) {
mpi-genesis           133 	    
mpi-genesis           134 	    assert( !bp_marker );
mpi-genesis           135 	    bp = bp_marker = mpi_alloc_limb_space( bsize, bsec );
mpi-genesis           136 	    MPN_COPY(bp, rp, bsize);
mpi-genesis           137 	}
mpi-genesis           138 	if( rp == ep ) {
mpi-genesis           139 	    
mpi-genesis           140                Allocate temp. space for EXPONENT.  */
mpi-genesis           141 	    ep = ep_marker = mpi_alloc_limb_space( esize, esec );
mpi-genesis           142 	    MPN_COPY(ep, rp, esize);
mpi-genesis           143 	}
mpi-genesis           144 	if( rp == mp ) {
mpi-genesis           145 	    
mpi-genesis           146 	    assert( !mp_marker );
mpi-genesis           147 	    mp = mp_marker = mpi_alloc_limb_space( msize, msec );
mpi-genesis           148 	    MPN_COPY(mp, rp, msize);
mpi-genesis           149 	}
mpi-genesis           150     }
mpi-genesis           151 
mpi-genesis           152     MPN_COPY( rp, bp, bsize );
mpi-genesis           153     rsize = bsize;
mpi-genesis           154     rsign = bsign;
mpi-genesis           155 
mpi-genesis           156     {
mpi-genesis           157 	mpi_size_t i;
mpi-genesis           158 	mpi_ptr_t xp = xp_marker = mpi_alloc_limb_space( 2 * (msize + 1), msec );
mpi-genesis           159 	int c;
mpi-genesis           160 	mpi_limb_t e;
mpi-genesis           161 	mpi_limb_t carry_limb;
mpi-genesis           162 	struct karatsuba_ctx karactx;
mpi-genesis           163 
mpi-genesis           164 	memset( &karactx, 0, sizeof karactx );
mpi-genesis           165 	negative_result = (ep[0] & 1) && base->sign;
mpi-genesis           166 
mpi-genesis           167 	i = esize - 1;
mpi-genesis           168 	e = ep[i];
mpi-genesis           169 	count_leading_zeros (c, e);
mpi-genesis           170 	e = (e << c) << 1;     
mpi-genesis           171 	c = BITS_PER_MPI_LIMB - 1 - c;
mpi-genesis           172 
mpi-genesis           173 	
mpi-genesis           174 	 *
mpi-genesis           175 	 * Make the result be pointed to alternately by XP and RP.  This
mpi-genesis           176 	 * helps us avoid block copying, which would otherwise be necessary
mpi-genesis           177 	 * with the overlap restrictions of mpihelp_divmod. With 50% probability
mpi-genesis           178 	 * the result after this loop will be in the area originally pointed
mpi-genesis           179 	 * by RP (==RES->d), and with 50% probability in the area originally
mpi-genesis           180 	 * pointed to by XP.
mpi-genesis           181 	 */
mpi-genesis           182 
mpi-genesis           183 	for(;;) {
mpi-genesis           184 	    while( c ) {
mpi-genesis           185 		mpi_ptr_t tp;
mpi-genesis           186 		mpi_size_t xsize;
mpi-genesis           187 
mpi-genesis           188 		
mpi-genesis           189 		if( rsize < KARATSUBA_THRESHOLD )
mpi-genesis           190 		    mpih_sqr_n_basecase( xp, rp, rsize );
mpi-genesis           191 		else {
mpi-genesis           192 		    if( !tspace ) {
mpi-genesis           193 			tsize = 2 * rsize;
mpi-genesis           194 			tspace = mpi_alloc_limb_space( tsize, 0 );
mpi-genesis           195 		    }
mpi-genesis           196 		    else if( tsize < (2*rsize) ) {
mpi-genesis           197 			mpi_free_limb_space( tspace );
mpi-genesis           198 			tsize = 2 * rsize;
mpi-genesis           199 			tspace = mpi_alloc_limb_space( tsize, 0 );
mpi-genesis           200 		    }
mpi-genesis           201 		    mpih_sqr_n( xp, rp, rsize, tspace );
mpi-genesis           202 		}
mpi-genesis           203 
mpi-genesis           204 		xsize = 2 * rsize;
mpi-genesis           205 		if( xsize > msize ) {
mpi-genesis           206 		    mpihelp_divrem(xp + msize, 0, xp, xsize, mp, msize);
mpi-genesis           207 		    xsize = msize;
mpi-genesis           208 		}
mpi-genesis           209 
mpi-genesis           210 		tp = rp; rp = xp; xp = tp;
mpi-genesis           211 		rsize = xsize;
mpi-genesis           212 
mpi-genesis           213 		if( (mpi_limb_signed_t)e < 0 ) {
mpi-genesis           214 		    
mpi-genesis           215 		    if( bsize < KARATSUBA_THRESHOLD ) {
mpi-genesis           216 			mpihelp_mul( xp, rp, rsize, bp, bsize );
mpi-genesis           217 		    }
mpi-genesis           218 		    else {
mpi-genesis           219 			mpihelp_mul_karatsuba_case(
mpi-genesis           220 				     xp, rp, rsize, bp, bsize, &karactx );
mpi-genesis           221 		    }
mpi-genesis           222 
mpi-genesis           223 		    xsize = rsize + bsize;
mpi-genesis           224 		    if( xsize > msize ) {
mpi-genesis           225 			mpihelp_divrem(xp + msize, 0, xp, xsize, mp, msize);
mpi-genesis           226 			xsize = msize;
mpi-genesis           227 		    }
mpi-genesis           228 
mpi-genesis           229 		    tp = rp; rp = xp; xp = tp;
mpi-genesis           230 		    rsize = xsize;
mpi-genesis           231 		}
mpi-genesis           232 		e <<= 1;
mpi-genesis           233 		c--;
mpi-genesis           234 	    }
mpi-genesis           235 
mpi-genesis           236 	    i--;
mpi-genesis           237 	    if( i < 0 )
mpi-genesis           238 		break;
mpi-genesis           239 	    e = ep[i];
mpi-genesis           240 	    c = BITS_PER_MPI_LIMB;
mpi-genesis           241 	}
mpi-genesis           242 
mpi-genesis           243 	
mpi-genesis           244 	 * steps.  Adjust the result by reducing it with the original MOD.
mpi-genesis           245 	 *
mpi-genesis           246 	 * Also make sure the result is put in RES->d (where it already
mpi-genesis           247 	 * might be, see above).
mpi-genesis           248 	 */
mpi-genesis           249 	if( mod_shift_cnt ) {
mpi-genesis           250 	    carry_limb = mpihelp_lshift( res->d, rp, rsize, mod_shift_cnt);
mpi-genesis           251 	    rp = res->d;
mpi-genesis           252 	    if( carry_limb ) {
mpi-genesis           253 		rp[rsize] = carry_limb;
mpi-genesis           254 		rsize++;
mpi-genesis           255 	    }
mpi-genesis           256 	}
mpi-genesis           257 	else {
mpi-genesis           258 	    MPN_COPY( res->d, rp, rsize);
mpi-genesis           259 	    rp = res->d;
mpi-genesis           260 	}
mpi-genesis           261 
mpi-genesis           262 	if( rsize >= msize ) {
mpi-genesis           263 	    mpihelp_divrem(rp + msize, 0, rp, rsize, mp, msize);
mpi-genesis           264 	    rsize = msize;
mpi-genesis           265 	}
mpi-genesis           266 
mpi-genesis           267 	
mpi-genesis           268 	if( mod_shift_cnt )
mpi-genesis           269 	    mpihelp_rshift( rp, rp, rsize, mod_shift_cnt);
mpi-genesis           270 	MPN_NORMALIZE (rp, rsize);
mpi-genesis           271 
mpi-genesis           272 	mpihelp_release_karatsuba_ctx( &karactx );
mpi-genesis           273     }
mpi-genesis           274 
mpi-genesis           275     if( negative_result && rsize ) {
mpi-genesis           276 	if( mod_shift_cnt )
mpi-genesis           277 	    mpihelp_rshift( mp, mp, msize, mod_shift_cnt);
mpi-genesis           278 	mpihelp_sub( rp, mp, msize, rp, rsize);
mpi-genesis           279 	rsize = msize;
mpi-genesis           280 	rsign = msign;
mpi-genesis           281 	MPN_NORMALIZE(rp, rsize);
mpi-genesis           282     }
mpi-genesis           283     res->nlimbs = rsize;
mpi-genesis           284     res->sign = rsign;
mpi-genesis           285 
mpi-genesis           286   leave:
mpi-genesis           287     if( assign_rp ) mpi_assign_limb_space( res, rp, size );
mpi-genesis           288     if( mp_marker ) mpi_free_limb_space( mp_marker );
mpi-genesis           289     if( bp_marker ) mpi_free_limb_space( bp_marker );
mpi-genesis           290     if( ep_marker ) mpi_free_limb_space( ep_marker );
mpi-genesis           291     if( xp_marker ) mpi_free_limb_space( xp_marker );
mpi-genesis           292     if( tspace )    mpi_free_limb_space( tspace );
mpi-genesis           293 }
mpi-genesis           294