summaryrefslogtreecommitdiffstats
path: root/mpi/mpi-mpow.c
diff options
context:
space:
mode:
Diffstat (limited to 'mpi/mpi-mpow.c')
-rw-r--r--mpi/mpi-mpow.c119
1 files changed, 119 insertions, 0 deletions
diff --git a/mpi/mpi-mpow.c b/mpi/mpi-mpow.c
new file mode 100644
index 000000000..5ac3c6399
--- /dev/null
+++ b/mpi/mpi-mpow.c
@@ -0,0 +1,119 @@
+/* mpi-mpow.c - MPI functions
+ * Copyright (c) 1998 by Werner Koch (dd9jn)
+ *
+ * This file is part of G10.
+ *
+ * G10 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.
+ *
+ * G10 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 <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "mpi-internal.h"
+#include "longlong.h"
+#include <assert.h>
+
+static int
+build_index( 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;
+ }
+ /*log_debug("t=%d i=%d index=%d\n", t, i, index );*/
+ return index;
+}
+
+/****************
+ * RES = (BASE[0] ^ EXP[0]) * (BASE[1] ^ EXP[1]) * ... * mod M
+ */
+void
+mpi_mulpowm( MPI res, MPI *basearray, MPI *exparray, MPI m)
+{
+ int k; /* number of elements */
+ int t; /* bit size of largest exponent */
+ int i, j, idx;
+ MPI *G; /* table with precomputed values of size 2^k */
+ MPI tmp;
+
+ for(k=0; basearray[k]; k++ )
+ ;
+ assert(k);
+ for(t=0, i=0; (tmp=exparray[i]); i++ ) {
+ /*log_mpidump("exp: ", tmp );*/
+ j = mpi_get_nbits(tmp);
+ if( j > t )
+ t = j;
+ }
+ /*log_mpidump("mod: ", m );*/
+ assert(i==k);
+ assert(t);
+ assert( k < 10 );
+
+ G = m_alloc_clear( (1<<k) * sizeof *G );
+ #if 0
+ /* do the precomputation */
+ G[0] = mpi_alloc_set_ui( 1 );
+ for(i=1; i < (1<<k); i++ ) {
+ for(j=0; j < k; j++ ) {
+ if( (i & (1<<j) ) ) {
+ if( !G[i] )
+ G[i] = mpi_copy( basearray[j] );
+ else
+ mpi_mulm( G[i], G[i], basearray[j], m );
+ }
+ }
+ if( !G[i] )
+ G[i] = mpi_alloc(0);
+ }
+ #endif
+ /* and calculate */
+ tmp = mpi_alloc( mpi_get_nlimbs(m)+1 );
+ mpi_set_ui( res, 1 );
+ for(i = 1; i <= t; i++ ) {
+ mpi_mulm(tmp, res, res, m );
+ idx = build_index( exparray, k, i, t );
+ assert( idx >= 0 && idx < (1<<k) );
+ if( !G[idx] ) {
+ if( !idx )
+ G[0] = mpi_alloc_set_ui( 1 );
+ else {
+ for(j=0; j < k; j++ ) {
+ if( (idx & (1<<j) ) ) {
+ if( !G[idx] )
+ G[idx] = mpi_copy( basearray[j] );
+ else
+ mpi_mulm( G[idx], G[idx], basearray[j], m );
+ }
+ }
+ if( !G[idx] )
+ G[idx] = mpi_alloc(0);
+ }
+ }
+ mpi_mulm(res, tmp, G[idx], m );
+ }
+
+ /* cleanup */
+ m_free(tmp);
+ for(i=0; i < (1<<k); i++ )
+ mpi_free(G[i]);
+ m_free(G);
+}
+