diff options
Diffstat (limited to 'lib/mpi/mpi-mpow.c')
| -rw-r--r-- | lib/mpi/mpi-mpow.c | 134 | 
1 files changed, 134 insertions, 0 deletions
| diff --git a/lib/mpi/mpi-mpow.c b/lib/mpi/mpi-mpow.c new file mode 100644 index 000000000000..7328d0d6c748 --- /dev/null +++ b/lib/mpi/mpi-mpow.c @@ -0,0 +1,134 @@ +/* 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) +		goto err_out; + +	/* 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); +err_out: +	return rc; +} | 
