2011-11-07 17:16:37 +04:00
/* mpi-mpow.c - MPI functions
* Copyright ( C ) 1998 , 1999 , 2000 Free Software Foundation , Inc .
*
* This file is part of GnuPG .
*
* GnuPG is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* GnuPG is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 59 Temple Place - Suite 330 , Boston , MA 02111 - 1307 , USA
*/
# include "mpi-internal.h"
# include "longlong.h"
static int build_index ( const MPI * exparray , int k , int i , int t )
{
int j , bitno ;
int index = 0 ;
bitno = t - i ;
for ( j = k - 1 ; j > = 0 ; j - - ) {
index < < = 1 ;
if ( mpi_test_bit ( exparray [ j ] , bitno ) )
index | = 1 ;
}
return index ;
}
/****************
* RES = ( BASE [ 0 ] ^ EXP [ 0 ] ) * ( BASE [ 1 ] ^ EXP [ 1 ] ) * . . . * mod M
*/
int mpi_mulpowm ( MPI res , MPI * basearray , MPI * exparray , MPI m )
{
int rc = - ENOMEM ;
int k ; /* number of elements */
int t ; /* bit size of largest exponent */
int i , j , idx ;
MPI * G = NULL ; /* table with precomputed values of size 2^k */
MPI tmp = NULL ;
for ( k = 0 ; basearray [ k ] ; k + + )
;
if ( ! k ) {
pr_emerg ( " mpi_mulpowm: assert(k) failed \n " ) ;
BUG ( ) ;
}
for ( t = 0 , i = 0 ; ( tmp = exparray [ i ] ) ; i + + ) {
j = mpi_get_nbits ( tmp ) ;
if ( j > t )
t = j ;
}
if ( i ! = k ) {
pr_emerg ( " mpi_mulpowm: assert(i==k) failed \n " ) ;
BUG ( ) ;
}
if ( ! t ) {
pr_emerg ( " mpi_mulpowm: assert(t) failed \n " ) ;
BUG ( ) ;
}
if ( k > = 10 ) {
pr_emerg ( " mpi_mulpowm: assert(k<10) failed \n " ) ;
BUG ( ) ;
}
G = kzalloc ( ( 1 < < k ) * sizeof * G , GFP_KERNEL ) ;
if ( ! G )
2011-12-07 15:58:26 +04:00
goto err_out ;
2011-11-07 17:16:37 +04:00
/* and calculate */
tmp = mpi_alloc ( mpi_get_nlimbs ( m ) + 1 ) ;
if ( ! tmp )
goto nomem ;
if ( mpi_set_ui ( res , 1 ) < 0 )
goto nomem ;
for ( i = 1 ; i < = t ; i + + ) {
if ( mpi_mulm ( tmp , res , res , m ) < 0 )
goto nomem ;
idx = build_index ( exparray , k , i , t ) ;
if ( ! ( idx > = 0 & & idx < ( 1 < < k ) ) ) {
pr_emerg ( " mpi_mulpowm: assert(idx >= 0 && idx < (1<<k)) failed \n " ) ;
BUG ( ) ;
}
if ( ! G [ idx ] ) {
if ( ! idx ) {
G [ 0 ] = mpi_alloc_set_ui ( 1 ) ;
if ( ! G [ 0 ] )
goto nomem ;
} else {
for ( j = 0 ; j < k ; j + + ) {
if ( ( idx & ( 1 < < j ) ) ) {
if ( ! G [ idx ] ) {
if ( mpi_copy
( & G [ idx ] ,
basearray [ j ] ) < 0 )
goto nomem ;
} else {
if ( mpi_mulm
( G [ idx ] , G [ idx ] ,
basearray [ j ] ,
m ) < 0 )
goto nomem ;
}
}
}
if ( ! G [ idx ] ) {
G [ idx ] = mpi_alloc ( 0 ) ;
if ( ! G [ idx ] )
goto nomem ;
}
}
}
if ( mpi_mulm ( res , tmp , G [ idx ] , m ) < 0 )
goto nomem ;
}
rc = 0 ;
nomem :
/* cleanup */
mpi_free ( tmp ) ;
for ( i = 0 ; i < ( 1 < < k ) ; i + + )
mpi_free ( G [ i ] ) ;
kfree ( G ) ;
2011-12-07 15:58:26 +04:00
err_out :
2011-11-07 17:16:37 +04:00
return rc ;
}