forked from mirrors/linux
		
	crypto: GnuPG based MPI lib - source files (part 1)
Adds the multi-precision-integer maths library which was originally taken from GnuPG and ported to the kernel by (among others) David Howells. This version is taken from Fedora kernel 2.6.32-71.14.1.el6. The difference is that checkpatch reported errors and warnings have been fixed. This library is used to implemenet RSA digital signature verification used in IMA/EVM integrity protection subsystem. Due to patch size limitation, the patch is divided into 4 parts. Signed-off-by: Dmitry Kasatkin <dmitry.kasatkin@intel.com>
This commit is contained in:
		
							parent
							
								
									1ea6b8f489
								
							
						
					
					
						commit
						cdec9cb516
					
				
					 14 changed files with 2681 additions and 0 deletions
				
			
		
							
								
								
									
										61
									
								
								lib/mpi/generic_mpih-add1.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								lib/mpi/generic_mpih-add1.c
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,61 @@ | |||
| /* mpihelp-add_1.c  -  MPI helper functions
 | ||||
|  * Copyright (C) 1994, 1996, 1997, 1998, | ||||
|  *               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 | ||||
|  * | ||||
|  * Note: This code is heavily based on the GNU MP Library. | ||||
|  *	 Actually it's the same code with only minor changes in the | ||||
|  *	 way the data is stored; this is to support the abstraction | ||||
|  *	 of an optional secure memory allocation which may be used | ||||
|  *	 to avoid revealing of sensitive data due to paging etc. | ||||
|  *	 The GNU MP Library itself is published under the LGPL; | ||||
|  *	 however I decided to publish this code under the plain GPL. | ||||
|  */ | ||||
| 
 | ||||
| #include "mpi-internal.h" | ||||
| #include "longlong.h" | ||||
| 
 | ||||
| mpi_limb_t | ||||
| mpihelp_add_n(mpi_ptr_t res_ptr, mpi_ptr_t s1_ptr, | ||||
| 	      mpi_ptr_t s2_ptr, mpi_size_t size) | ||||
| { | ||||
| 	mpi_limb_t x, y, cy; | ||||
| 	mpi_size_t j; | ||||
| 
 | ||||
| 	/* The loop counter and index J goes from -SIZE to -1.  This way
 | ||||
| 	   the loop becomes faster.  */ | ||||
| 	j = -size; | ||||
| 
 | ||||
| 	/* Offset the base pointers to compensate for the negative indices. */ | ||||
| 	s1_ptr -= j; | ||||
| 	s2_ptr -= j; | ||||
| 	res_ptr -= j; | ||||
| 
 | ||||
| 	cy = 0; | ||||
| 	do { | ||||
| 		y = s2_ptr[j]; | ||||
| 		x = s1_ptr[j]; | ||||
| 		y += cy;	/* add previous carry to one addend */ | ||||
| 		cy = y < cy;	/* get out carry from that addition */ | ||||
| 		y += x;		/* add other addend */ | ||||
| 		cy += y < x;	/* get out carry from that add, combine */ | ||||
| 		res_ptr[j] = y; | ||||
| 	} while (++j); | ||||
| 
 | ||||
| 	return cy; | ||||
| } | ||||
							
								
								
									
										63
									
								
								lib/mpi/generic_mpih-lshift.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								lib/mpi/generic_mpih-lshift.c
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,63 @@ | |||
| /* mpihelp-lshift.c  -	MPI helper functions
 | ||||
|  * Copyright (C) 1994, 1996, 1998, 2001 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 | ||||
|  * | ||||
|  * Note: This code is heavily based on the GNU MP Library. | ||||
|  *	 Actually it's the same code with only minor changes in the | ||||
|  *	 way the data is stored; this is to support the abstraction | ||||
|  *	 of an optional secure memory allocation which may be used | ||||
|  *	 to avoid revealing of sensitive data due to paging etc. | ||||
|  *	 The GNU MP Library itself is published under the LGPL; | ||||
|  *	 however I decided to publish this code under the plain GPL. | ||||
|  */ | ||||
| 
 | ||||
| #include "mpi-internal.h" | ||||
| 
 | ||||
| /* Shift U (pointed to by UP and USIZE digits long) CNT bits to the left
 | ||||
|  * and store the USIZE least significant digits of the result at WP. | ||||
|  * Return the bits shifted out from the most significant digit. | ||||
|  * | ||||
|  * Argument constraints: | ||||
|  * 1. 0 < CNT < BITS_PER_MP_LIMB | ||||
|  * 2. If the result is to be written over the input, WP must be >= UP. | ||||
|  */ | ||||
| 
 | ||||
| mpi_limb_t | ||||
| mpihelp_lshift(mpi_ptr_t wp, mpi_ptr_t up, mpi_size_t usize, unsigned int cnt) | ||||
| { | ||||
| 	mpi_limb_t high_limb, low_limb; | ||||
| 	unsigned sh_1, sh_2; | ||||
| 	mpi_size_t i; | ||||
| 	mpi_limb_t retval; | ||||
| 
 | ||||
| 	sh_1 = cnt; | ||||
| 	wp += 1; | ||||
| 	sh_2 = BITS_PER_MPI_LIMB - sh_1; | ||||
| 	i = usize - 1; | ||||
| 	low_limb = up[i]; | ||||
| 	retval = low_limb >> sh_2; | ||||
| 	high_limb = low_limb; | ||||
| 	while (--i >= 0) { | ||||
| 		low_limb = up[i]; | ||||
| 		wp[i] = (high_limb << sh_1) | (low_limb >> sh_2); | ||||
| 		high_limb = low_limb; | ||||
| 	} | ||||
| 	wp[i] = high_limb << sh_1; | ||||
| 
 | ||||
| 	return retval; | ||||
| } | ||||
							
								
								
									
										57
									
								
								lib/mpi/generic_mpih-mul1.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								lib/mpi/generic_mpih-mul1.c
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,57 @@ | |||
| /* mpihelp-mul_1.c  -  MPI helper functions
 | ||||
|  * Copyright (C) 1994, 1996, 1997, 1998, 2001 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 | ||||
|  * | ||||
|  * Note: This code is heavily based on the GNU MP Library. | ||||
|  *	 Actually it's the same code with only minor changes in the | ||||
|  *	 way the data is stored; this is to support the abstraction | ||||
|  *	 of an optional secure memory allocation which may be used | ||||
|  *	 to avoid revealing of sensitive data due to paging etc. | ||||
|  *	 The GNU MP Library itself is published under the LGPL; | ||||
|  *	 however I decided to publish this code under the plain GPL. | ||||
|  */ | ||||
| 
 | ||||
| #include "mpi-internal.h" | ||||
| #include "longlong.h" | ||||
| 
 | ||||
| mpi_limb_t | ||||
| mpihelp_mul_1(mpi_ptr_t res_ptr, mpi_ptr_t s1_ptr, mpi_size_t s1_size, | ||||
| 	      mpi_limb_t s2_limb) | ||||
| { | ||||
| 	mpi_limb_t cy_limb; | ||||
| 	mpi_size_t j; | ||||
| 	mpi_limb_t prod_high, prod_low; | ||||
| 
 | ||||
| 	/* The loop counter and index J goes from -S1_SIZE to -1.  This way
 | ||||
| 	 * the loop becomes faster.  */ | ||||
| 	j = -s1_size; | ||||
| 
 | ||||
| 	/* Offset the base pointers to compensate for the negative indices.  */ | ||||
| 	s1_ptr -= j; | ||||
| 	res_ptr -= j; | ||||
| 
 | ||||
| 	cy_limb = 0; | ||||
| 	do { | ||||
| 		umul_ppmm(prod_high, prod_low, s1_ptr[j], s2_limb); | ||||
| 		prod_low += cy_limb; | ||||
| 		cy_limb = (prod_low < cy_limb ? 1 : 0) + prod_high; | ||||
| 		res_ptr[j] = prod_low; | ||||
| 	} while (++j); | ||||
| 
 | ||||
| 	return cy_limb; | ||||
| } | ||||
							
								
								
									
										60
									
								
								lib/mpi/generic_mpih-mul2.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								lib/mpi/generic_mpih-mul2.c
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,60 @@ | |||
| /* mpihelp-mul_2.c  -  MPI helper functions
 | ||||
|  * Copyright (C) 1994, 1996, 1997, 1998, 2001 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 | ||||
|  * | ||||
|  * Note: This code is heavily based on the GNU MP Library. | ||||
|  *	 Actually it's the same code with only minor changes in the | ||||
|  *	 way the data is stored; this is to support the abstraction | ||||
|  *	 of an optional secure memory allocation which may be used | ||||
|  *	 to avoid revealing of sensitive data due to paging etc. | ||||
|  *	 The GNU MP Library itself is published under the LGPL; | ||||
|  *	 however I decided to publish this code under the plain GPL. | ||||
|  */ | ||||
| 
 | ||||
| #include "mpi-internal.h" | ||||
| #include "longlong.h" | ||||
| 
 | ||||
| mpi_limb_t | ||||
| mpihelp_addmul_1(mpi_ptr_t res_ptr, mpi_ptr_t s1_ptr, | ||||
| 		 mpi_size_t s1_size, mpi_limb_t s2_limb) | ||||
| { | ||||
| 	mpi_limb_t cy_limb; | ||||
| 	mpi_size_t j; | ||||
| 	mpi_limb_t prod_high, prod_low; | ||||
| 	mpi_limb_t x; | ||||
| 
 | ||||
| 	/* The loop counter and index J goes from -SIZE to -1.  This way
 | ||||
| 	 * the loop becomes faster.  */ | ||||
| 	j = -s1_size; | ||||
| 	res_ptr -= j; | ||||
| 	s1_ptr -= j; | ||||
| 
 | ||||
| 	cy_limb = 0; | ||||
| 	do { | ||||
| 		umul_ppmm(prod_high, prod_low, s1_ptr[j], s2_limb); | ||||
| 
 | ||||
| 		prod_low += cy_limb; | ||||
| 		cy_limb = (prod_low < cy_limb ? 1 : 0) + prod_high; | ||||
| 
 | ||||
| 		x = res_ptr[j]; | ||||
| 		prod_low = x + prod_low; | ||||
| 		cy_limb += prod_low < x ? 1 : 0; | ||||
| 		res_ptr[j] = prod_low; | ||||
| 	} while (++j); | ||||
| 	return cy_limb; | ||||
| } | ||||
							
								
								
									
										61
									
								
								lib/mpi/generic_mpih-mul3.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								lib/mpi/generic_mpih-mul3.c
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,61 @@ | |||
| /* mpihelp-mul_3.c  -  MPI helper functions
 | ||||
|  * Copyright (C) 1994, 1996, 1997, 1998, 2001 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 | ||||
|  * | ||||
|  * Note: This code is heavily based on the GNU MP Library. | ||||
|  *	 Actually it's the same code with only minor changes in the | ||||
|  *	 way the data is stored; this is to support the abstraction | ||||
|  *	 of an optional secure memory allocation which may be used | ||||
|  *	 to avoid revealing of sensitive data due to paging etc. | ||||
|  *	 The GNU MP Library itself is published under the LGPL; | ||||
|  *	 however I decided to publish this code under the plain GPL. | ||||
|  */ | ||||
| 
 | ||||
| #include "mpi-internal.h" | ||||
| #include "longlong.h" | ||||
| 
 | ||||
| mpi_limb_t | ||||
| mpihelp_submul_1(mpi_ptr_t res_ptr, mpi_ptr_t s1_ptr, | ||||
| 		 mpi_size_t s1_size, mpi_limb_t s2_limb) | ||||
| { | ||||
| 	mpi_limb_t cy_limb; | ||||
| 	mpi_size_t j; | ||||
| 	mpi_limb_t prod_high, prod_low; | ||||
| 	mpi_limb_t x; | ||||
| 
 | ||||
| 	/* The loop counter and index J goes from -SIZE to -1.  This way
 | ||||
| 	 * the loop becomes faster.  */ | ||||
| 	j = -s1_size; | ||||
| 	res_ptr -= j; | ||||
| 	s1_ptr -= j; | ||||
| 
 | ||||
| 	cy_limb = 0; | ||||
| 	do { | ||||
| 		umul_ppmm(prod_high, prod_low, s1_ptr[j], s2_limb); | ||||
| 
 | ||||
| 		prod_low += cy_limb; | ||||
| 		cy_limb = (prod_low < cy_limb ? 1 : 0) + prod_high; | ||||
| 
 | ||||
| 		x = res_ptr[j]; | ||||
| 		prod_low = x - prod_low; | ||||
| 		cy_limb += prod_low > x ? 1 : 0; | ||||
| 		res_ptr[j] = prod_low; | ||||
| 	} while (++j); | ||||
| 
 | ||||
| 	return cy_limb; | ||||
| } | ||||
							
								
								
									
										63
									
								
								lib/mpi/generic_mpih-rshift.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								lib/mpi/generic_mpih-rshift.c
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,63 @@ | |||
| /* mpih-rshift.c  -  MPI helper functions
 | ||||
|  * Copyright (C) 1994, 1996, 1998, 1999, | ||||
|  *               2000, 2001 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 | ||||
|  * | ||||
|  * Note: This code is heavily based on the GNU MP Library. | ||||
|  *	 Actually it's the same code with only minor changes in the | ||||
|  *	 way the data is stored; this is to support the abstraction | ||||
|  *	 of an optional secure memory allocation which may be used | ||||
|  *	 to avoid revealing of sensitive data due to paging etc. | ||||
|  *	 The GNU MP Library itself is published under the LGPL; | ||||
|  *	 however I decided to publish this code under the plain GPL. | ||||
|  */ | ||||
| 
 | ||||
| #include "mpi-internal.h" | ||||
| 
 | ||||
| /* Shift U (pointed to by UP and USIZE limbs long) CNT bits to the right
 | ||||
|  * and store the USIZE least significant limbs of the result at WP. | ||||
|  * The bits shifted out to the right are returned. | ||||
|  * | ||||
|  * Argument constraints: | ||||
|  * 1. 0 < CNT < BITS_PER_MP_LIMB | ||||
|  * 2. If the result is to be written over the input, WP must be <= UP. | ||||
|  */ | ||||
| 
 | ||||
| mpi_limb_t | ||||
| mpihelp_rshift(mpi_ptr_t wp, mpi_ptr_t up, mpi_size_t usize, unsigned cnt) | ||||
| { | ||||
| 	mpi_limb_t high_limb, low_limb; | ||||
| 	unsigned sh_1, sh_2; | ||||
| 	mpi_size_t i; | ||||
| 	mpi_limb_t retval; | ||||
| 
 | ||||
| 	sh_1 = cnt; | ||||
| 	wp -= 1; | ||||
| 	sh_2 = BITS_PER_MPI_LIMB - sh_1; | ||||
| 	high_limb = up[0]; | ||||
| 	retval = high_limb << sh_2; | ||||
| 	low_limb = high_limb; | ||||
| 	for (i = 1; i < usize; i++) { | ||||
| 		high_limb = up[i]; | ||||
| 		wp[i] = (low_limb >> sh_1) | (high_limb << sh_2); | ||||
| 		low_limb = high_limb; | ||||
| 	} | ||||
| 	wp[i] = low_limb >> sh_1; | ||||
| 
 | ||||
| 	return retval; | ||||
| } | ||||
							
								
								
									
										60
									
								
								lib/mpi/generic_mpih-sub1.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								lib/mpi/generic_mpih-sub1.c
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,60 @@ | |||
| /* mpihelp-add_2.c  -  MPI helper functions
 | ||||
|  * Copyright (C) 1994, 1996, 1997, 1998, 2001 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 | ||||
|  * | ||||
|  * Note: This code is heavily based on the GNU MP Library. | ||||
|  *	 Actually it's the same code with only minor changes in the | ||||
|  *	 way the data is stored; this is to support the abstraction | ||||
|  *	 of an optional secure memory allocation which may be used | ||||
|  *	 to avoid revealing of sensitive data due to paging etc. | ||||
|  *	 The GNU MP Library itself is published under the LGPL; | ||||
|  *	 however I decided to publish this code under the plain GPL. | ||||
|  */ | ||||
| 
 | ||||
| #include "mpi-internal.h" | ||||
| #include "longlong.h" | ||||
| 
 | ||||
| mpi_limb_t | ||||
| mpihelp_sub_n(mpi_ptr_t res_ptr, mpi_ptr_t s1_ptr, | ||||
| 	      mpi_ptr_t s2_ptr, mpi_size_t size) | ||||
| { | ||||
| 	mpi_limb_t x, y, cy; | ||||
| 	mpi_size_t j; | ||||
| 
 | ||||
| 	/* The loop counter and index J goes from -SIZE to -1.  This way
 | ||||
| 	   the loop becomes faster.  */ | ||||
| 	j = -size; | ||||
| 
 | ||||
| 	/* Offset the base pointers to compensate for the negative indices.  */ | ||||
| 	s1_ptr -= j; | ||||
| 	s2_ptr -= j; | ||||
| 	res_ptr -= j; | ||||
| 
 | ||||
| 	cy = 0; | ||||
| 	do { | ||||
| 		y = s2_ptr[j]; | ||||
| 		x = s1_ptr[j]; | ||||
| 		y += cy;	/* add previous carry to subtrahend */ | ||||
| 		cy = y < cy;	/* get out carry from that addition */ | ||||
| 		y = x - y;	/* main subtract */ | ||||
| 		cy += y > x;	/* get out carry from the subtract, combine */ | ||||
| 		res_ptr[j] = y; | ||||
| 	} while (++j); | ||||
| 
 | ||||
| 	return cy; | ||||
| } | ||||
							
								
								
									
										236
									
								
								lib/mpi/mpi-bit.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										236
									
								
								lib/mpi/mpi-bit.c
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,236 @@ | |||
| /* mpi-bit.c  -  MPI bit level fucntions
 | ||||
|  * Copyright (C) 1998, 1999 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" | ||||
| 
 | ||||
| const unsigned char __clz_tab[] = { | ||||
| 	0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, | ||||
| 	    5, 5, 5, 5, 5, 5, 5, 5, | ||||
| 	6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, | ||||
| 	    6, 6, 6, 6, 6, 6, 6, 6, | ||||
| 	7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, | ||||
| 	    7, 7, 7, 7, 7, 7, 7, 7, | ||||
| 	7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, | ||||
| 	    7, 7, 7, 7, 7, 7, 7, 7, | ||||
| 	8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, | ||||
| 	    8, 8, 8, 8, 8, 8, 8, 8, | ||||
| 	8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, | ||||
| 	    8, 8, 8, 8, 8, 8, 8, 8, | ||||
| 	8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, | ||||
| 	    8, 8, 8, 8, 8, 8, 8, 8, | ||||
| 	8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, | ||||
| 	    8, 8, 8, 8, 8, 8, 8, 8, | ||||
| }; | ||||
| 
 | ||||
| #define A_LIMB_1 ((mpi_limb_t) 1) | ||||
| 
 | ||||
| /****************
 | ||||
|  * Sometimes we have MSL (most significant limbs) which are 0; | ||||
|  * this is for some reasons not good, so this function removes them. | ||||
|  */ | ||||
| void mpi_normalize(MPI a) | ||||
| { | ||||
| 	for (; a->nlimbs && !a->d[a->nlimbs - 1]; a->nlimbs--) | ||||
| 		; | ||||
| } | ||||
| 
 | ||||
| /****************
 | ||||
|  * Return the number of bits in A. | ||||
|  */ | ||||
| unsigned mpi_get_nbits(MPI a) | ||||
| { | ||||
| 	unsigned n; | ||||
| 
 | ||||
| 	mpi_normalize(a); | ||||
| 
 | ||||
| 	if (a->nlimbs) { | ||||
| 		mpi_limb_t alimb = a->d[a->nlimbs - 1]; | ||||
| 		if (alimb) | ||||
| 			count_leading_zeros(n, alimb); | ||||
| 		else | ||||
| 			n = BITS_PER_MPI_LIMB; | ||||
| 		n = BITS_PER_MPI_LIMB - n + (a->nlimbs - 1) * BITS_PER_MPI_LIMB; | ||||
| 	} else | ||||
| 		n = 0; | ||||
| 	return n; | ||||
| } | ||||
| EXPORT_SYMBOL_GPL(mpi_get_nbits); | ||||
| 
 | ||||
| /****************
 | ||||
|  * Test whether bit N is set. | ||||
|  */ | ||||
| int mpi_test_bit(MPI a, unsigned n) | ||||
| { | ||||
| 	unsigned limbno, bitno; | ||||
| 	mpi_limb_t limb; | ||||
| 
 | ||||
| 	limbno = n / BITS_PER_MPI_LIMB; | ||||
| 	bitno = n % BITS_PER_MPI_LIMB; | ||||
| 
 | ||||
| 	if (limbno >= a->nlimbs) | ||||
| 		return 0;	/* too far left: this is a 0 */ | ||||
| 	limb = a->d[limbno]; | ||||
| 	return (limb & (A_LIMB_1 << bitno)) ? 1 : 0; | ||||
| } | ||||
| 
 | ||||
| /****************
 | ||||
|  * Set bit N of A. | ||||
|  */ | ||||
| int mpi_set_bit(MPI a, unsigned n) | ||||
| { | ||||
| 	unsigned limbno, bitno; | ||||
| 
 | ||||
| 	limbno = n / BITS_PER_MPI_LIMB; | ||||
| 	bitno = n % BITS_PER_MPI_LIMB; | ||||
| 
 | ||||
| 	if (limbno >= a->nlimbs) {	/* resize */ | ||||
| 		if (a->alloced >= limbno) | ||||
| 			if (mpi_resize(a, limbno + 1) < 0) | ||||
| 				return -ENOMEM; | ||||
| 		a->nlimbs = limbno + 1; | ||||
| 	} | ||||
| 	a->d[limbno] |= (A_LIMB_1 << bitno); | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| /****************
 | ||||
|  * Set bit N of A. and clear all bits above | ||||
|  */ | ||||
| int mpi_set_highbit(MPI a, unsigned n) | ||||
| { | ||||
| 	unsigned limbno, bitno; | ||||
| 
 | ||||
| 	limbno = n / BITS_PER_MPI_LIMB; | ||||
| 	bitno = n % BITS_PER_MPI_LIMB; | ||||
| 
 | ||||
| 	if (limbno >= a->nlimbs) {	/* resize */ | ||||
| 		if (a->alloced >= limbno) | ||||
| 			if (mpi_resize(a, limbno + 1) < 0) | ||||
| 				return -ENOMEM; | ||||
| 		a->nlimbs = limbno + 1; | ||||
| 	} | ||||
| 	a->d[limbno] |= (A_LIMB_1 << bitno); | ||||
| 	for (bitno++; bitno < BITS_PER_MPI_LIMB; bitno++) | ||||
| 		a->d[limbno] &= ~(A_LIMB_1 << bitno); | ||||
| 	a->nlimbs = limbno + 1; | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| /****************
 | ||||
|  * clear bit N of A and all bits above | ||||
|  */ | ||||
| void mpi_clear_highbit(MPI a, unsigned n) | ||||
| { | ||||
| 	unsigned limbno, bitno; | ||||
| 
 | ||||
| 	limbno = n / BITS_PER_MPI_LIMB; | ||||
| 	bitno = n % BITS_PER_MPI_LIMB; | ||||
| 
 | ||||
| 	if (limbno >= a->nlimbs) | ||||
| 		return;		/* not allocated, so need to clear bits :-) */ | ||||
| 
 | ||||
| 	for (; bitno < BITS_PER_MPI_LIMB; bitno++) | ||||
| 		a->d[limbno] &= ~(A_LIMB_1 << bitno); | ||||
| 	a->nlimbs = limbno + 1; | ||||
| } | ||||
| 
 | ||||
| /****************
 | ||||
|  * Clear bit N of A. | ||||
|  */ | ||||
| void mpi_clear_bit(MPI a, unsigned n) | ||||
| { | ||||
| 	unsigned limbno, bitno; | ||||
| 
 | ||||
| 	limbno = n / BITS_PER_MPI_LIMB; | ||||
| 	bitno = n % BITS_PER_MPI_LIMB; | ||||
| 
 | ||||
| 	if (limbno >= a->nlimbs) | ||||
| 		return;		/* don't need to clear this bit, it's to far to left */ | ||||
| 	a->d[limbno] &= ~(A_LIMB_1 << bitno); | ||||
| } | ||||
| 
 | ||||
| /****************
 | ||||
|  * Shift A by N bits to the right | ||||
|  * FIXME: should use alloc_limb if X and A are same. | ||||
|  */ | ||||
| int mpi_rshift(MPI x, MPI a, unsigned n) | ||||
| { | ||||
| 	mpi_ptr_t xp; | ||||
| 	mpi_size_t xsize; | ||||
| 
 | ||||
| 	xsize = a->nlimbs; | ||||
| 	x->sign = a->sign; | ||||
| 	if (RESIZE_IF_NEEDED(x, (size_t) xsize) < 0) | ||||
| 		return -ENOMEM; | ||||
| 	xp = x->d; | ||||
| 
 | ||||
| 	if (xsize) { | ||||
| 		mpihelp_rshift(xp, a->d, xsize, n); | ||||
| 		MPN_NORMALIZE(xp, xsize); | ||||
| 	} | ||||
| 	x->nlimbs = xsize; | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| /****************
 | ||||
|  * Shift A by COUNT limbs to the left | ||||
|  * This is used only within the MPI library | ||||
|  */ | ||||
| int mpi_lshift_limbs(MPI a, unsigned int count) | ||||
| { | ||||
| 	mpi_ptr_t ap = a->d; | ||||
| 	int n = a->nlimbs; | ||||
| 	int i; | ||||
| 
 | ||||
| 	if (!count || !n) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	if (RESIZE_IF_NEEDED(a, n + count) < 0) | ||||
| 		return -ENOMEM; | ||||
| 
 | ||||
| 	for (i = n - 1; i >= 0; i--) | ||||
| 		ap[i + count] = ap[i]; | ||||
| 	for (i = 0; i < count; i++) | ||||
| 		ap[i] = 0; | ||||
| 	a->nlimbs += count; | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| /****************
 | ||||
|  * Shift A by COUNT limbs to the right | ||||
|  * This is used only within the MPI library | ||||
|  */ | ||||
| void mpi_rshift_limbs(MPI a, unsigned int count) | ||||
| { | ||||
| 	mpi_ptr_t ap = a->d; | ||||
| 	mpi_size_t n = a->nlimbs; | ||||
| 	unsigned int i; | ||||
| 
 | ||||
| 	if (count >= n) { | ||||
| 		a->nlimbs = 0; | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	for (i = 0; i < n - count; i++) | ||||
| 		ap[i] = ap[i + count]; | ||||
| 	ap[i] = 0; | ||||
| 	a->nlimbs -= count; | ||||
| } | ||||
							
								
								
									
										323
									
								
								lib/mpi/mpi-pow.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										323
									
								
								lib/mpi/mpi-pow.c
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,323 @@ | |||
| /* mpi-pow.c  -  MPI functions
 | ||||
|  *	Copyright (C) 1994, 1996, 1998, 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 | ||||
|  * | ||||
|  * Note: This code is heavily based on the GNU MP Library. | ||||
|  *	 Actually it's the same code with only minor changes in the | ||||
|  *	 way the data is stored; this is to support the abstraction | ||||
|  *	 of an optional secure memory allocation which may be used | ||||
|  *	 to avoid revealing of sensitive data due to paging etc. | ||||
|  *	 The GNU MP Library itself is published under the LGPL; | ||||
|  *	 however I decided to publish this code under the plain GPL. | ||||
|  */ | ||||
| 
 | ||||
| #include <linux/string.h> | ||||
| #include "mpi-internal.h" | ||||
| #include "longlong.h" | ||||
| 
 | ||||
| /****************
 | ||||
|  * RES = BASE ^ EXP mod MOD | ||||
|  */ | ||||
| int mpi_powm(MPI res, MPI base, MPI exp, MPI mod) | ||||
| { | ||||
| 	mpi_ptr_t mp_marker = NULL, bp_marker = NULL, ep_marker = NULL; | ||||
| 	mpi_ptr_t xp_marker = NULL; | ||||
| 	mpi_ptr_t tspace = NULL; | ||||
| 	mpi_ptr_t rp, ep, mp, bp; | ||||
| 	mpi_size_t esize, msize, bsize, rsize; | ||||
| 	int esign, msign, bsign, rsign; | ||||
| 	mpi_size_t size; | ||||
| 	int mod_shift_cnt; | ||||
| 	int negative_result; | ||||
| 	int assign_rp = 0; | ||||
| 	mpi_size_t tsize = 0;	/* to avoid compiler warning */ | ||||
| 	/* fixme: we should check that the warning is void */ | ||||
| 	int rc = -ENOMEM; | ||||
| 
 | ||||
| 	esize = exp->nlimbs; | ||||
| 	msize = mod->nlimbs; | ||||
| 	size = 2 * msize; | ||||
| 	esign = exp->sign; | ||||
| 	msign = mod->sign; | ||||
| 
 | ||||
| 	rp = res->d; | ||||
| 	ep = exp->d; | ||||
| 
 | ||||
| 	if (!msize) | ||||
| 		msize = 1 / msize;	/* provoke a signal */ | ||||
| 
 | ||||
| 	if (!esize) { | ||||
| 		/* Exponent is zero, result is 1 mod MOD, i.e., 1 or 0
 | ||||
| 		 * depending on if MOD equals 1.  */ | ||||
| 		rp[0] = 1; | ||||
| 		res->nlimbs = (msize == 1 && mod->d[0] == 1) ? 0 : 1; | ||||
| 		res->sign = 0; | ||||
| 		goto leave; | ||||
| 	} | ||||
| 
 | ||||
| 	/* Normalize MOD (i.e. make its most significant bit set) as required by
 | ||||
| 	 * mpn_divrem.  This will make the intermediate values in the calculation | ||||
| 	 * slightly larger, but the correct result is obtained after a final | ||||
| 	 * reduction using the original MOD value.  */ | ||||
| 	mp = mp_marker = mpi_alloc_limb_space(msize); | ||||
| 	if (!mp) | ||||
| 		goto enomem; | ||||
| 	count_leading_zeros(mod_shift_cnt, mod->d[msize - 1]); | ||||
| 	if (mod_shift_cnt) | ||||
| 		mpihelp_lshift(mp, mod->d, msize, mod_shift_cnt); | ||||
| 	else | ||||
| 		MPN_COPY(mp, mod->d, msize); | ||||
| 
 | ||||
| 	bsize = base->nlimbs; | ||||
| 	bsign = base->sign; | ||||
| 	if (bsize > msize) {	/* The base is larger than the module. Reduce it. */ | ||||
| 		/* Allocate (BSIZE + 1) with space for remainder and quotient.
 | ||||
| 		 * (The quotient is (bsize - msize + 1) limbs.)  */ | ||||
| 		bp = bp_marker = mpi_alloc_limb_space(bsize + 1); | ||||
| 		if (!bp) | ||||
| 			goto enomem; | ||||
| 		MPN_COPY(bp, base->d, bsize); | ||||
| 		/* We don't care about the quotient, store it above the remainder,
 | ||||
| 		 * at BP + MSIZE.  */ | ||||
| 		mpihelp_divrem(bp + msize, 0, bp, bsize, mp, msize); | ||||
| 		bsize = msize; | ||||
| 		/* Canonicalize the base, since we are going to multiply with it
 | ||||
| 		 * quite a few times.  */ | ||||
| 		MPN_NORMALIZE(bp, bsize); | ||||
| 	} else | ||||
| 		bp = base->d; | ||||
| 
 | ||||
| 	if (!bsize) { | ||||
| 		res->nlimbs = 0; | ||||
| 		res->sign = 0; | ||||
| 		goto leave; | ||||
| 	} | ||||
| 
 | ||||
| 	if (res->alloced < size) { | ||||
| 		/* We have to allocate more space for RES.  If any of the input
 | ||||
| 		 * parameters are identical to RES, defer deallocation of the old | ||||
| 		 * space.  */ | ||||
| 		if (rp == ep || rp == mp || rp == bp) { | ||||
| 			rp = mpi_alloc_limb_space(size); | ||||
| 			if (!rp) | ||||
| 				goto enomem; | ||||
| 			assign_rp = 1; | ||||
| 		} else { | ||||
| 			if (mpi_resize(res, size) < 0) | ||||
| 				goto enomem; | ||||
| 			rp = res->d; | ||||
| 		} | ||||
| 	} else {		/* Make BASE, EXP and MOD not overlap with RES.  */ | ||||
| 		if (rp == bp) { | ||||
| 			/* RES and BASE are identical.  Allocate temp. space for BASE.  */ | ||||
| 			BUG_ON(bp_marker); | ||||
| 			bp = bp_marker = mpi_alloc_limb_space(bsize); | ||||
| 			if (!bp) | ||||
| 				goto enomem; | ||||
| 			MPN_COPY(bp, rp, bsize); | ||||
| 		} | ||||
| 		if (rp == ep) { | ||||
| 			/* RES and EXP are identical.  Allocate temp. space for EXP.  */ | ||||
| 			ep = ep_marker = mpi_alloc_limb_space(esize); | ||||
| 			if (!ep) | ||||
| 				goto enomem; | ||||
| 			MPN_COPY(ep, rp, esize); | ||||
| 		} | ||||
| 		if (rp == mp) { | ||||
| 			/* RES and MOD are identical.  Allocate temporary space for MOD. */ | ||||
| 			BUG_ON(mp_marker); | ||||
| 			mp = mp_marker = mpi_alloc_limb_space(msize); | ||||
| 			if (!mp) | ||||
| 				goto enomem; | ||||
| 			MPN_COPY(mp, rp, msize); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	MPN_COPY(rp, bp, bsize); | ||||
| 	rsize = bsize; | ||||
| 	rsign = bsign; | ||||
| 
 | ||||
| 	{ | ||||
| 		mpi_size_t i; | ||||
| 		mpi_ptr_t xp; | ||||
| 		int c; | ||||
| 		mpi_limb_t e; | ||||
| 		mpi_limb_t carry_limb; | ||||
| 		struct karatsuba_ctx karactx; | ||||
| 
 | ||||
| 		xp = xp_marker = mpi_alloc_limb_space(2 * (msize + 1)); | ||||
| 		if (!xp) | ||||
| 			goto enomem; | ||||
| 
 | ||||
| 		memset(&karactx, 0, sizeof karactx); | ||||
| 		negative_result = (ep[0] & 1) && base->sign; | ||||
| 
 | ||||
| 		i = esize - 1; | ||||
| 		e = ep[i]; | ||||
| 		count_leading_zeros(c, e); | ||||
| 		e = (e << c) << 1;	/* shift the exp bits to the left, lose msb */ | ||||
| 		c = BITS_PER_MPI_LIMB - 1 - c; | ||||
| 
 | ||||
| 		/* Main loop.
 | ||||
| 		 * | ||||
| 		 * Make the result be pointed to alternately by XP and RP.  This | ||||
| 		 * helps us avoid block copying, which would otherwise be necessary | ||||
| 		 * with the overlap restrictions of mpihelp_divmod. With 50% probability | ||||
| 		 * the result after this loop will be in the area originally pointed | ||||
| 		 * by RP (==RES->d), and with 50% probability in the area originally | ||||
| 		 * pointed to by XP. | ||||
| 		 */ | ||||
| 
 | ||||
| 		for (;;) { | ||||
| 			while (c) { | ||||
| 				mpi_ptr_t tp; | ||||
| 				mpi_size_t xsize; | ||||
| 
 | ||||
| 				/*if (mpihelp_mul_n(xp, rp, rp, rsize) < 0) goto enomem */ | ||||
| 				if (rsize < KARATSUBA_THRESHOLD) | ||||
| 					mpih_sqr_n_basecase(xp, rp, rsize); | ||||
| 				else { | ||||
| 					if (!tspace) { | ||||
| 						tsize = 2 * rsize; | ||||
| 						tspace = | ||||
| 						    mpi_alloc_limb_space(tsize); | ||||
| 						if (!tspace) | ||||
| 							goto enomem; | ||||
| 					} else if (tsize < (2 * rsize)) { | ||||
| 						mpi_free_limb_space(tspace); | ||||
| 						tsize = 2 * rsize; | ||||
| 						tspace = | ||||
| 						    mpi_alloc_limb_space(tsize); | ||||
| 						if (!tspace) | ||||
| 							goto enomem; | ||||
| 					} | ||||
| 					mpih_sqr_n(xp, rp, rsize, tspace); | ||||
| 				} | ||||
| 
 | ||||
| 				xsize = 2 * rsize; | ||||
| 				if (xsize > msize) { | ||||
| 					mpihelp_divrem(xp + msize, 0, xp, xsize, | ||||
| 						       mp, msize); | ||||
| 					xsize = msize; | ||||
| 				} | ||||
| 
 | ||||
| 				tp = rp; | ||||
| 				rp = xp; | ||||
| 				xp = tp; | ||||
| 				rsize = xsize; | ||||
| 
 | ||||
| 				if ((mpi_limb_signed_t) e < 0) { | ||||
| 					/*mpihelp_mul( xp, rp, rsize, bp, bsize ); */ | ||||
| 					if (bsize < KARATSUBA_THRESHOLD) { | ||||
| 						mpi_limb_t tmp; | ||||
| 						if (mpihelp_mul | ||||
| 						    (xp, rp, rsize, bp, bsize, | ||||
| 						     &tmp) < 0) | ||||
| 							goto enomem; | ||||
| 					} else { | ||||
| 						if (mpihelp_mul_karatsuba_case | ||||
| 						    (xp, rp, rsize, bp, bsize, | ||||
| 						     &karactx) < 0) | ||||
| 							goto enomem; | ||||
| 					} | ||||
| 
 | ||||
| 					xsize = rsize + bsize; | ||||
| 					if (xsize > msize) { | ||||
| 						mpihelp_divrem(xp + msize, 0, | ||||
| 							       xp, xsize, mp, | ||||
| 							       msize); | ||||
| 						xsize = msize; | ||||
| 					} | ||||
| 
 | ||||
| 					tp = rp; | ||||
| 					rp = xp; | ||||
| 					xp = tp; | ||||
| 					rsize = xsize; | ||||
| 				} | ||||
| 				e <<= 1; | ||||
| 				c--; | ||||
| 			} | ||||
| 
 | ||||
| 			i--; | ||||
| 			if (i < 0) | ||||
| 				break; | ||||
| 			e = ep[i]; | ||||
| 			c = BITS_PER_MPI_LIMB; | ||||
| 		} | ||||
| 
 | ||||
| 		/* We shifted MOD, the modulo reduction argument, left MOD_SHIFT_CNT
 | ||||
| 		 * steps.  Adjust the result by reducing it with the original MOD. | ||||
| 		 * | ||||
| 		 * Also make sure the result is put in RES->d (where it already | ||||
| 		 * might be, see above). | ||||
| 		 */ | ||||
| 		if (mod_shift_cnt) { | ||||
| 			carry_limb = | ||||
| 			    mpihelp_lshift(res->d, rp, rsize, mod_shift_cnt); | ||||
| 			rp = res->d; | ||||
| 			if (carry_limb) { | ||||
| 				rp[rsize] = carry_limb; | ||||
| 				rsize++; | ||||
| 			} | ||||
| 		} else { | ||||
| 			MPN_COPY(res->d, rp, rsize); | ||||
| 			rp = res->d; | ||||
| 		} | ||||
| 
 | ||||
| 		if (rsize >= msize) { | ||||
| 			mpihelp_divrem(rp + msize, 0, rp, rsize, mp, msize); | ||||
| 			rsize = msize; | ||||
| 		} | ||||
| 
 | ||||
| 		/* Remove any leading zero words from the result.  */ | ||||
| 		if (mod_shift_cnt) | ||||
| 			mpihelp_rshift(rp, rp, rsize, mod_shift_cnt); | ||||
| 		MPN_NORMALIZE(rp, rsize); | ||||
| 
 | ||||
| 		mpihelp_release_karatsuba_ctx(&karactx); | ||||
| 	} | ||||
| 
 | ||||
| 	if (negative_result && rsize) { | ||||
| 		if (mod_shift_cnt) | ||||
| 			mpihelp_rshift(mp, mp, msize, mod_shift_cnt); | ||||
| 		mpihelp_sub(rp, mp, msize, rp, rsize); | ||||
| 		rsize = msize; | ||||
| 		rsign = msign; | ||||
| 		MPN_NORMALIZE(rp, rsize); | ||||
| 	} | ||||
| 	res->nlimbs = rsize; | ||||
| 	res->sign = rsign; | ||||
| 
 | ||||
| leave: | ||||
| 	rc = 0; | ||||
| enomem: | ||||
| 	if (assign_rp) | ||||
| 		mpi_assign_limb_space(res, rp, size); | ||||
| 	if (mp_marker) | ||||
| 		mpi_free_limb_space(mp_marker); | ||||
| 	if (bp_marker) | ||||
| 		mpi_free_limb_space(bp_marker); | ||||
| 	if (ep_marker) | ||||
| 		mpi_free_limb_space(ep_marker); | ||||
| 	if (xp_marker) | ||||
| 		mpi_free_limb_space(xp_marker); | ||||
| 	if (tspace) | ||||
| 		mpi_free_limb_space(tspace); | ||||
| 	return rc; | ||||
| } | ||||
| EXPORT_SYMBOL_GPL(mpi_powm); | ||||
							
								
								
									
										365
									
								
								lib/mpi/mpicoder.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										365
									
								
								lib/mpi/mpicoder.c
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,365 @@ | |||
| /* mpicoder.c  -  Coder for the external representation of MPIs
 | ||||
|  * Copyright (C) 1998, 1999 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" | ||||
| 
 | ||||
| #define DIM(v) (sizeof(v)/sizeof((v)[0])) | ||||
| #define MAX_EXTERN_MPI_BITS 16384 | ||||
| 
 | ||||
| static uint8_t asn[15] =	/* Object ID is 1.3.14.3.2.26 */ | ||||
| { 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, | ||||
| 	0x02, 0x1a, 0x05, 0x00, 0x04, 0x14 | ||||
| }; | ||||
| 
 | ||||
| MPI do_encode_md(const void *sha_buffer, unsigned nbits) | ||||
| { | ||||
| 	int nframe = (nbits + 7) / 8; | ||||
| 	uint8_t *frame, *fr_pt; | ||||
| 	int i = 0, n; | ||||
| 	size_t asnlen = DIM(asn); | ||||
| 	MPI a = MPI_NULL; | ||||
| 
 | ||||
| 	if (SHA1_DIGEST_LENGTH + asnlen + 4 > nframe) | ||||
| 		pr_info("MPI: can't encode a %d bit MD into a %d bits frame\n", | ||||
| 		       (int)(SHA1_DIGEST_LENGTH * 8), (int)nbits); | ||||
| 
 | ||||
| 	/* We encode the MD in this way:
 | ||||
| 	 * | ||||
| 	 *       0  A PAD(n bytes)   0  ASN(asnlen bytes)  MD(len bytes) | ||||
| 	 * | ||||
| 	 * PAD consists of FF bytes. | ||||
| 	 */ | ||||
| 	frame = kmalloc(nframe, GFP_KERNEL); | ||||
| 	if (!frame) | ||||
| 		return MPI_NULL; | ||||
| 	n = 0; | ||||
| 	frame[n++] = 0; | ||||
| 	frame[n++] = 1;		/* block type */ | ||||
| 	i = nframe - SHA1_DIGEST_LENGTH - asnlen - 3; | ||||
| 
 | ||||
| 	if (i <= 1) { | ||||
| 		pr_info("MPI: message digest encoding failed\n"); | ||||
| 		kfree(frame); | ||||
| 		return a; | ||||
| 	} | ||||
| 
 | ||||
| 	memset(frame + n, 0xff, i); | ||||
| 	n += i; | ||||
| 	frame[n++] = 0; | ||||
| 	memcpy(frame + n, &asn, asnlen); | ||||
| 	n += asnlen; | ||||
| 	memcpy(frame + n, sha_buffer, SHA1_DIGEST_LENGTH); | ||||
| 	n += SHA1_DIGEST_LENGTH; | ||||
| 
 | ||||
| 	i = nframe; | ||||
| 	fr_pt = frame; | ||||
| 
 | ||||
| 	if (n != nframe) { | ||||
| 		printk | ||||
| 		    ("MPI: message digest encoding failed, frame length is wrong\n"); | ||||
| 		kfree(frame); | ||||
| 		return a; | ||||
| 	} | ||||
| 
 | ||||
| 	a = mpi_alloc((nframe + BYTES_PER_MPI_LIMB - 1) / BYTES_PER_MPI_LIMB); | ||||
| 	mpi_set_buffer(a, frame, nframe, 0); | ||||
| 	kfree(frame); | ||||
| 
 | ||||
| 	return a; | ||||
| } | ||||
| 
 | ||||
| MPI mpi_read_from_buffer(const void *xbuffer, unsigned *ret_nread) | ||||
| { | ||||
| 	const uint8_t *buffer = xbuffer; | ||||
| 	int i, j; | ||||
| 	unsigned nbits, nbytes, nlimbs, nread = 0; | ||||
| 	mpi_limb_t a; | ||||
| 	MPI val = MPI_NULL; | ||||
| 
 | ||||
| 	if (*ret_nread < 2) | ||||
| 		goto leave; | ||||
| 	nbits = buffer[0] << 8 | buffer[1]; | ||||
| 
 | ||||
| 	if (nbits > MAX_EXTERN_MPI_BITS) { | ||||
| 		pr_info("MPI: mpi too large (%u bits)\n", nbits); | ||||
| 		goto leave; | ||||
| 	} | ||||
| 	buffer += 2; | ||||
| 	nread = 2; | ||||
| 
 | ||||
| 	nbytes = (nbits + 7) / 8; | ||||
| 	nlimbs = (nbytes + BYTES_PER_MPI_LIMB - 1) / BYTES_PER_MPI_LIMB; | ||||
| 	val = mpi_alloc(nlimbs); | ||||
| 	if (!val) | ||||
| 		return MPI_NULL; | ||||
| 	i = BYTES_PER_MPI_LIMB - nbytes % BYTES_PER_MPI_LIMB; | ||||
| 	i %= BYTES_PER_MPI_LIMB; | ||||
| 	val->nbits = nbits; | ||||
| 	j = val->nlimbs = nlimbs; | ||||
| 	val->sign = 0; | ||||
| 	for (; j > 0; j--) { | ||||
| 		a = 0; | ||||
| 		for (; i < BYTES_PER_MPI_LIMB; i++) { | ||||
| 			if (++nread > *ret_nread) { | ||||
| 				printk | ||||
| 				    ("MPI: mpi larger than buffer nread=%d ret_nread=%d\n", | ||||
| 				     nread, *ret_nread); | ||||
| 				goto leave; | ||||
| 			} | ||||
| 			a <<= 8; | ||||
| 			a |= *buffer++; | ||||
| 		} | ||||
| 		i = 0; | ||||
| 		val->d[j - 1] = a; | ||||
| 	} | ||||
| 
 | ||||
| leave: | ||||
| 	*ret_nread = nread; | ||||
| 	return val; | ||||
| } | ||||
| EXPORT_SYMBOL_GPL(mpi_read_from_buffer); | ||||
| 
 | ||||
| /****************
 | ||||
|  * Make an mpi from a character string. | ||||
|  */ | ||||
| int mpi_fromstr(MPI val, const char *str) | ||||
| { | ||||
| 	int hexmode = 0, sign = 0, prepend_zero = 0, i, j, c, c1, c2; | ||||
| 	unsigned nbits, nbytes, nlimbs; | ||||
| 	mpi_limb_t a; | ||||
| 
 | ||||
| 	if (*str == '-') { | ||||
| 		sign = 1; | ||||
| 		str++; | ||||
| 	} | ||||
| 	if (*str == '0' && str[1] == 'x') | ||||
| 		hexmode = 1; | ||||
| 	else | ||||
| 		return -EINVAL;	/* other bases are not yet supported */ | ||||
| 	str += 2; | ||||
| 
 | ||||
| 	nbits = strlen(str) * 4; | ||||
| 	if (nbits % 8) | ||||
| 		prepend_zero = 1; | ||||
| 	nbytes = (nbits + 7) / 8; | ||||
| 	nlimbs = (nbytes + BYTES_PER_MPI_LIMB - 1) / BYTES_PER_MPI_LIMB; | ||||
| 	if (val->alloced < nlimbs) | ||||
| 		if (!mpi_resize(val, nlimbs)) | ||||
| 			return -ENOMEM; | ||||
| 	i = BYTES_PER_MPI_LIMB - nbytes % BYTES_PER_MPI_LIMB; | ||||
| 	i %= BYTES_PER_MPI_LIMB; | ||||
| 	j = val->nlimbs = nlimbs; | ||||
| 	val->sign = sign; | ||||
| 	for (; j > 0; j--) { | ||||
| 		a = 0; | ||||
| 		for (; i < BYTES_PER_MPI_LIMB; i++) { | ||||
| 			if (prepend_zero) { | ||||
| 				c1 = '0'; | ||||
| 				prepend_zero = 0; | ||||
| 			} else | ||||
| 				c1 = *str++; | ||||
| 			assert(c1); | ||||
| 			c2 = *str++; | ||||
| 			assert(c2); | ||||
| 			if (c1 >= '0' && c1 <= '9') | ||||
| 				c = c1 - '0'; | ||||
| 			else if (c1 >= 'a' && c1 <= 'f') | ||||
| 				c = c1 - 'a' + 10; | ||||
| 			else if (c1 >= 'A' && c1 <= 'F') | ||||
| 				c = c1 - 'A' + 10; | ||||
| 			else { | ||||
| 				mpi_clear(val); | ||||
| 				return 1; | ||||
| 			} | ||||
| 			c <<= 4; | ||||
| 			if (c2 >= '0' && c2 <= '9') | ||||
| 				c |= c2 - '0'; | ||||
| 			else if (c2 >= 'a' && c2 <= 'f') | ||||
| 				c |= c2 - 'a' + 10; | ||||
| 			else if (c2 >= 'A' && c2 <= 'F') | ||||
| 				c |= c2 - 'A' + 10; | ||||
| 			else { | ||||
| 				mpi_clear(val); | ||||
| 				return 1; | ||||
| 			} | ||||
| 			a <<= 8; | ||||
| 			a |= c; | ||||
| 		} | ||||
| 		i = 0; | ||||
| 
 | ||||
| 		val->d[j - 1] = a; | ||||
| 	} | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| EXPORT_SYMBOL_GPL(mpi_fromstr); | ||||
| 
 | ||||
| /****************
 | ||||
|  * Special function to get the low 8 bytes from an mpi. | ||||
|  * This can be used as a keyid; KEYID is an 2 element array. | ||||
|  * Return the low 4 bytes. | ||||
|  */ | ||||
| u32 mpi_get_keyid(const MPI a, u32 *keyid) | ||||
| { | ||||
| #if BYTES_PER_MPI_LIMB == 4 | ||||
| 	if (keyid) { | ||||
| 		keyid[0] = a->nlimbs >= 2 ? a->d[1] : 0; | ||||
| 		keyid[1] = a->nlimbs >= 1 ? a->d[0] : 0; | ||||
| 	} | ||||
| 	return a->nlimbs >= 1 ? a->d[0] : 0; | ||||
| #elif BYTES_PER_MPI_LIMB == 8 | ||||
| 	if (keyid) { | ||||
| 		keyid[0] = a->nlimbs ? (u32) (a->d[0] >> 32) : 0; | ||||
| 		keyid[1] = a->nlimbs ? (u32) (a->d[0] & 0xffffffff) : 0; | ||||
| 	} | ||||
| 	return a->nlimbs ? (u32) (a->d[0] & 0xffffffff) : 0; | ||||
| #else | ||||
| #error Make this function work with other LIMB sizes | ||||
| #endif | ||||
| } | ||||
| 
 | ||||
| /****************
 | ||||
|  * Return an allocated buffer with the MPI (msb first). | ||||
|  * NBYTES receives the length of this buffer. Caller must free the | ||||
|  * return string (This function does return a 0 byte buffer with NBYTES | ||||
|  * set to zero if the value of A is zero. If sign is not NULL, it will | ||||
|  * be set to the sign of the A. | ||||
|  */ | ||||
| void *mpi_get_buffer(MPI a, unsigned *nbytes, int *sign) | ||||
| { | ||||
| 	uint8_t *p, *buffer; | ||||
| 	mpi_limb_t alimb; | ||||
| 	int i; | ||||
| 	unsigned int n; | ||||
| 
 | ||||
| 	if (sign) | ||||
| 		*sign = a->sign; | ||||
| 	*nbytes = n = a->nlimbs * BYTES_PER_MPI_LIMB; | ||||
| 	if (!n) | ||||
| 		n++;		/* avoid zero length allocation */ | ||||
| 	p = buffer = kmalloc(n, GFP_KERNEL); | ||||
| 
 | ||||
| 	for (i = a->nlimbs - 1; i >= 0; i--) { | ||||
| 		alimb = a->d[i]; | ||||
| #if BYTES_PER_MPI_LIMB == 4 | ||||
| 		*p++ = alimb >> 24; | ||||
| 		*p++ = alimb >> 16; | ||||
| 		*p++ = alimb >> 8; | ||||
| 		*p++ = alimb; | ||||
| #elif BYTES_PER_MPI_LIMB == 8 | ||||
| 		*p++ = alimb >> 56; | ||||
| 		*p++ = alimb >> 48; | ||||
| 		*p++ = alimb >> 40; | ||||
| 		*p++ = alimb >> 32; | ||||
| 		*p++ = alimb >> 24; | ||||
| 		*p++ = alimb >> 16; | ||||
| 		*p++ = alimb >> 8; | ||||
| 		*p++ = alimb; | ||||
| #else | ||||
| #error please implement for this limb size. | ||||
| #endif | ||||
| 	} | ||||
| 
 | ||||
| 	/* this is sub-optimal but we need to do the shift operation
 | ||||
| 	 * because the caller has to free the returned buffer */ | ||||
| 	for (p = buffer; !*p && *nbytes; p++, --*nbytes) | ||||
| 		; | ||||
| 	if (p != buffer) | ||||
| 		memmove(buffer, p, *nbytes); | ||||
| 
 | ||||
| 	return buffer; | ||||
| } | ||||
| EXPORT_SYMBOL_GPL(mpi_get_buffer); | ||||
| 
 | ||||
| /****************
 | ||||
|  * Use BUFFER to update MPI. | ||||
|  */ | ||||
| int mpi_set_buffer(MPI a, const void *xbuffer, unsigned nbytes, int sign) | ||||
| { | ||||
| 	const uint8_t *buffer = xbuffer, *p; | ||||
| 	mpi_limb_t alimb; | ||||
| 	int nlimbs; | ||||
| 	int i; | ||||
| 
 | ||||
| 	nlimbs = (nbytes + BYTES_PER_MPI_LIMB - 1) / BYTES_PER_MPI_LIMB; | ||||
| 	if (RESIZE_IF_NEEDED(a, nlimbs) < 0) | ||||
| 		return -ENOMEM; | ||||
| 	a->sign = sign; | ||||
| 
 | ||||
| 	for (i = 0, p = buffer + nbytes - 1; p >= buffer + BYTES_PER_MPI_LIMB;) { | ||||
| #if BYTES_PER_MPI_LIMB == 4 | ||||
| 		alimb = (mpi_limb_t) *p--; | ||||
| 		alimb |= (mpi_limb_t) *p-- << 8; | ||||
| 		alimb |= (mpi_limb_t) *p-- << 16; | ||||
| 		alimb |= (mpi_limb_t) *p-- << 24; | ||||
| #elif BYTES_PER_MPI_LIMB == 8 | ||||
| 		alimb = (mpi_limb_t) *p--; | ||||
| 		alimb |= (mpi_limb_t) *p-- << 8; | ||||
| 		alimb |= (mpi_limb_t) *p-- << 16; | ||||
| 		alimb |= (mpi_limb_t) *p-- << 24; | ||||
| 		alimb |= (mpi_limb_t) *p-- << 32; | ||||
| 		alimb |= (mpi_limb_t) *p-- << 40; | ||||
| 		alimb |= (mpi_limb_t) *p-- << 48; | ||||
| 		alimb |= (mpi_limb_t) *p-- << 56; | ||||
| #else | ||||
| #error please implement for this limb size. | ||||
| #endif | ||||
| 		a->d[i++] = alimb; | ||||
| 	} | ||||
| 	if (p >= buffer) { | ||||
| #if BYTES_PER_MPI_LIMB == 4 | ||||
| 		alimb = *p--; | ||||
| 		if (p >= buffer) | ||||
| 			alimb |= (mpi_limb_t) *p-- << 8; | ||||
| 		if (p >= buffer) | ||||
| 			alimb |= (mpi_limb_t) *p-- << 16; | ||||
| 		if (p >= buffer) | ||||
| 			alimb |= (mpi_limb_t) *p-- << 24; | ||||
| #elif BYTES_PER_MPI_LIMB == 8 | ||||
| 		alimb = (mpi_limb_t) *p--; | ||||
| 		if (p >= buffer) | ||||
| 			alimb |= (mpi_limb_t) *p-- << 8; | ||||
| 		if (p >= buffer) | ||||
| 			alimb |= (mpi_limb_t) *p-- << 16; | ||||
| 		if (p >= buffer) | ||||
| 			alimb |= (mpi_limb_t) *p-- << 24; | ||||
| 		if (p >= buffer) | ||||
| 			alimb |= (mpi_limb_t) *p-- << 32; | ||||
| 		if (p >= buffer) | ||||
| 			alimb |= (mpi_limb_t) *p-- << 40; | ||||
| 		if (p >= buffer) | ||||
| 			alimb |= (mpi_limb_t) *p-- << 48; | ||||
| 		if (p >= buffer) | ||||
| 			alimb |= (mpi_limb_t) *p-- << 56; | ||||
| #else | ||||
| #error please implement for this limb size. | ||||
| #endif | ||||
| 		a->d[i++] = alimb; | ||||
| 	} | ||||
| 	a->nlimbs = i; | ||||
| 
 | ||||
| 	if (i != nlimbs) { | ||||
| 		pr_emerg("MPI: mpi_set_buffer: Assertion failed (%d != %d)", i, | ||||
| 		       nlimbs); | ||||
| 		BUG(); | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
| EXPORT_SYMBOL_GPL(mpi_set_buffer); | ||||
							
								
								
									
										56
									
								
								lib/mpi/mpih-cmp.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								lib/mpi/mpih-cmp.c
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,56 @@ | |||
| /* mpihelp-sub.c  -  MPI helper functions
 | ||||
|  *	Copyright (C) 1994, 1996 Free Software Foundation, Inc. | ||||
|  *	Copyright (C) 1998, 1999, 2000, 2001 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 | ||||
|  * | ||||
|  * Note: This code is heavily based on the GNU MP Library. | ||||
|  *	 Actually it's the same code with only minor changes in the | ||||
|  *	 way the data is stored; this is to support the abstraction | ||||
|  *	 of an optional secure memory allocation which may be used | ||||
|  *	 to avoid revealing of sensitive data due to paging etc. | ||||
|  *	 The GNU MP Library itself is published under the LGPL; | ||||
|  *	 however I decided to publish this code under the plain GPL. | ||||
|  */ | ||||
| 
 | ||||
| #include "mpi-internal.h" | ||||
| 
 | ||||
| /****************
 | ||||
|  * Compare OP1_PTR/OP1_SIZE with OP2_PTR/OP2_SIZE. | ||||
|  * There are no restrictions on the relative sizes of | ||||
|  * the two arguments. | ||||
|  * Return 1 if OP1 > OP2, 0 if they are equal, and -1 if OP1 < OP2. | ||||
|  */ | ||||
| int mpihelp_cmp(mpi_ptr_t op1_ptr, mpi_ptr_t op2_ptr, mpi_size_t size) | ||||
| { | ||||
| 	mpi_size_t i; | ||||
| 	mpi_limb_t op1_word, op2_word; | ||||
| 
 | ||||
| 	for (i = size - 1; i >= 0; i--) { | ||||
| 		op1_word = op1_ptr[i]; | ||||
| 		op2_word = op2_ptr[i]; | ||||
| 		if (op1_word != op2_word) | ||||
| 			goto diff; | ||||
| 	} | ||||
| 	return 0; | ||||
| 
 | ||||
| diff: | ||||
| 	/* This can *not* be simplified to
 | ||||
| 	 *   op2_word - op2_word | ||||
| 	 * since that expression might give signed overflow.  */ | ||||
| 	return (op1_word > op2_word) ? 1 : -1; | ||||
| } | ||||
							
								
								
									
										541
									
								
								lib/mpi/mpih-div.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										541
									
								
								lib/mpi/mpih-div.c
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,541 @@ | |||
| /* mpihelp-div.c  -  MPI helper functions
 | ||||
|  *	Copyright (C) 1994, 1996 Free Software Foundation, Inc. | ||||
|  *	Copyright (C) 1998, 1999 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 | ||||
|  * | ||||
|  * Note: This code is heavily based on the GNU MP Library. | ||||
|  *	 Actually it's the same code with only minor changes in the | ||||
|  *	 way the data is stored; this is to support the abstraction | ||||
|  *	 of an optional secure memory allocation which may be used | ||||
|  *	 to avoid revealing of sensitive data due to paging etc. | ||||
|  *	 The GNU MP Library itself is published under the LGPL; | ||||
|  *	 however I decided to publish this code under the plain GPL. | ||||
|  */ | ||||
| 
 | ||||
| #include "mpi-internal.h" | ||||
| #include "longlong.h" | ||||
| 
 | ||||
| #ifndef UMUL_TIME | ||||
| #define UMUL_TIME 1 | ||||
| #endif | ||||
| #ifndef UDIV_TIME | ||||
| #define UDIV_TIME UMUL_TIME | ||||
| #endif | ||||
| 
 | ||||
| /* FIXME: We should be using invert_limb (or invert_normalized_limb)
 | ||||
|  * here (not udiv_qrnnd). | ||||
|  */ | ||||
| 
 | ||||
| mpi_limb_t | ||||
| mpihelp_mod_1(mpi_ptr_t dividend_ptr, mpi_size_t dividend_size, | ||||
| 	      mpi_limb_t divisor_limb) | ||||
| { | ||||
| 	mpi_size_t i; | ||||
| 	mpi_limb_t n1, n0, r; | ||||
| 	int dummy; | ||||
| 
 | ||||
| 	/* Botch: Should this be handled at all?  Rely on callers?  */ | ||||
| 	if (!dividend_size) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	/* If multiplication is much faster than division, and the
 | ||||
| 	 * dividend is large, pre-invert the divisor, and use | ||||
| 	 * only multiplications in the inner loop. | ||||
| 	 * | ||||
| 	 * This test should be read: | ||||
| 	 *   Does it ever help to use udiv_qrnnd_preinv? | ||||
| 	 *     && Does what we save compensate for the inversion overhead? | ||||
| 	 */ | ||||
| 	if (UDIV_TIME > (2 * UMUL_TIME + 6) | ||||
| 	    && (UDIV_TIME - (2 * UMUL_TIME + 6)) * dividend_size > UDIV_TIME) { | ||||
| 		int normalization_steps; | ||||
| 
 | ||||
| 		count_leading_zeros(normalization_steps, divisor_limb); | ||||
| 		if (normalization_steps) { | ||||
| 			mpi_limb_t divisor_limb_inverted; | ||||
| 
 | ||||
| 			divisor_limb <<= normalization_steps; | ||||
| 
 | ||||
| 			/* Compute (2**2N - 2**N * DIVISOR_LIMB) / DIVISOR_LIMB.  The
 | ||||
| 			 * result is a (N+1)-bit approximation to 1/DIVISOR_LIMB, with the | ||||
| 			 * most significant bit (with weight 2**N) implicit. | ||||
| 			 * | ||||
| 			 * Special case for DIVISOR_LIMB == 100...000. | ||||
| 			 */ | ||||
| 			if (!(divisor_limb << 1)) | ||||
| 				divisor_limb_inverted = ~(mpi_limb_t) 0; | ||||
| 			else | ||||
| 				udiv_qrnnd(divisor_limb_inverted, dummy, | ||||
| 					   -divisor_limb, 0, divisor_limb); | ||||
| 
 | ||||
| 			n1 = dividend_ptr[dividend_size - 1]; | ||||
| 			r = n1 >> (BITS_PER_MPI_LIMB - normalization_steps); | ||||
| 
 | ||||
| 			/* Possible optimization:
 | ||||
| 			 * if (r == 0 | ||||
| 			 * && divisor_limb > ((n1 << normalization_steps) | ||||
| 			 *                 | (dividend_ptr[dividend_size - 2] >> ...))) | ||||
| 			 * ...one division less... | ||||
| 			 */ | ||||
| 			for (i = dividend_size - 2; i >= 0; i--) { | ||||
| 				n0 = dividend_ptr[i]; | ||||
| 				UDIV_QRNND_PREINV(dummy, r, r, | ||||
| 						  ((n1 << normalization_steps) | ||||
| 						   | (n0 >> | ||||
| 						      (BITS_PER_MPI_LIMB - | ||||
| 						       normalization_steps))), | ||||
| 						  divisor_limb, | ||||
| 						  divisor_limb_inverted); | ||||
| 				n1 = n0; | ||||
| 			} | ||||
| 			UDIV_QRNND_PREINV(dummy, r, r, | ||||
| 					  n1 << normalization_steps, | ||||
| 					  divisor_limb, divisor_limb_inverted); | ||||
| 			return r >> normalization_steps; | ||||
| 		} else { | ||||
| 			mpi_limb_t divisor_limb_inverted; | ||||
| 
 | ||||
| 			/* Compute (2**2N - 2**N * DIVISOR_LIMB) / DIVISOR_LIMB.  The
 | ||||
| 			 * result is a (N+1)-bit approximation to 1/DIVISOR_LIMB, with the | ||||
| 			 * most significant bit (with weight 2**N) implicit. | ||||
| 			 * | ||||
| 			 * Special case for DIVISOR_LIMB == 100...000. | ||||
| 			 */ | ||||
| 			if (!(divisor_limb << 1)) | ||||
| 				divisor_limb_inverted = ~(mpi_limb_t) 0; | ||||
| 			else | ||||
| 				udiv_qrnnd(divisor_limb_inverted, dummy, | ||||
| 					   -divisor_limb, 0, divisor_limb); | ||||
| 
 | ||||
| 			i = dividend_size - 1; | ||||
| 			r = dividend_ptr[i]; | ||||
| 
 | ||||
| 			if (r >= divisor_limb) | ||||
| 				r = 0; | ||||
| 			else | ||||
| 				i--; | ||||
| 
 | ||||
| 			for (; i >= 0; i--) { | ||||
| 				n0 = dividend_ptr[i]; | ||||
| 				UDIV_QRNND_PREINV(dummy, r, r, | ||||
| 						  n0, divisor_limb, | ||||
| 						  divisor_limb_inverted); | ||||
| 			} | ||||
| 			return r; | ||||
| 		} | ||||
| 	} else { | ||||
| 		if (UDIV_NEEDS_NORMALIZATION) { | ||||
| 			int normalization_steps; | ||||
| 
 | ||||
| 			count_leading_zeros(normalization_steps, divisor_limb); | ||||
| 			if (normalization_steps) { | ||||
| 				divisor_limb <<= normalization_steps; | ||||
| 
 | ||||
| 				n1 = dividend_ptr[dividend_size - 1]; | ||||
| 				r = n1 >> (BITS_PER_MPI_LIMB - | ||||
| 					   normalization_steps); | ||||
| 
 | ||||
| 				/* Possible optimization:
 | ||||
| 				 * if (r == 0 | ||||
| 				 * && divisor_limb > ((n1 << normalization_steps) | ||||
| 				 *                 | (dividend_ptr[dividend_size - 2] >> ...))) | ||||
| 				 * ...one division less... | ||||
| 				 */ | ||||
| 				for (i = dividend_size - 2; i >= 0; i--) { | ||||
| 					n0 = dividend_ptr[i]; | ||||
| 					udiv_qrnnd(dummy, r, r, | ||||
| 						   ((n1 << normalization_steps) | ||||
| 						    | (n0 >> | ||||
| 						       (BITS_PER_MPI_LIMB - | ||||
| 							normalization_steps))), | ||||
| 						   divisor_limb); | ||||
| 					n1 = n0; | ||||
| 				} | ||||
| 				udiv_qrnnd(dummy, r, r, | ||||
| 					   n1 << normalization_steps, | ||||
| 					   divisor_limb); | ||||
| 				return r >> normalization_steps; | ||||
| 			} | ||||
| 		} | ||||
| 		/* No normalization needed, either because udiv_qrnnd doesn't require
 | ||||
| 		 * it, or because DIVISOR_LIMB is already normalized.  */ | ||||
| 		i = dividend_size - 1; | ||||
| 		r = dividend_ptr[i]; | ||||
| 
 | ||||
| 		if (r >= divisor_limb) | ||||
| 			r = 0; | ||||
| 		else | ||||
| 			i--; | ||||
| 
 | ||||
| 		for (; i >= 0; i--) { | ||||
| 			n0 = dividend_ptr[i]; | ||||
| 			udiv_qrnnd(dummy, r, r, n0, divisor_limb); | ||||
| 		} | ||||
| 		return r; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| /* Divide num (NP/NSIZE) by den (DP/DSIZE) and write
 | ||||
|  * the NSIZE-DSIZE least significant quotient limbs at QP | ||||
|  * and the DSIZE long remainder at NP.	If QEXTRA_LIMBS is | ||||
|  * non-zero, generate that many fraction bits and append them after the | ||||
|  * other quotient limbs. | ||||
|  * Return the most significant limb of the quotient, this is always 0 or 1. | ||||
|  * | ||||
|  * Preconditions: | ||||
|  * 0. NSIZE >= DSIZE. | ||||
|  * 1. The most significant bit of the divisor must be set. | ||||
|  * 2. QP must either not overlap with the input operands at all, or | ||||
|  *    QP + DSIZE >= NP must hold true.	(This means that it's | ||||
|  *    possible to put the quotient in the high part of NUM, right after the | ||||
|  *    remainder in NUM. | ||||
|  * 3. NSIZE >= DSIZE, even if QEXTRA_LIMBS is non-zero. | ||||
|  */ | ||||
| 
 | ||||
| mpi_limb_t | ||||
| mpihelp_divrem(mpi_ptr_t qp, mpi_size_t qextra_limbs, | ||||
| 	       mpi_ptr_t np, mpi_size_t nsize, mpi_ptr_t dp, mpi_size_t dsize) | ||||
| { | ||||
| 	mpi_limb_t most_significant_q_limb = 0; | ||||
| 
 | ||||
| 	switch (dsize) { | ||||
| 	case 0: | ||||
| 		/* We are asked to divide by zero, so go ahead and do it!  (To make
 | ||||
| 		   the compiler not remove this statement, return the value.)  */ | ||||
| 		return 1 / dsize; | ||||
| 
 | ||||
| 	case 1: | ||||
| 		{ | ||||
| 			mpi_size_t i; | ||||
| 			mpi_limb_t n1; | ||||
| 			mpi_limb_t d; | ||||
| 
 | ||||
| 			d = dp[0]; | ||||
| 			n1 = np[nsize - 1]; | ||||
| 
 | ||||
| 			if (n1 >= d) { | ||||
| 				n1 -= d; | ||||
| 				most_significant_q_limb = 1; | ||||
| 			} | ||||
| 
 | ||||
| 			qp += qextra_limbs; | ||||
| 			for (i = nsize - 2; i >= 0; i--) | ||||
| 				udiv_qrnnd(qp[i], n1, n1, np[i], d); | ||||
| 			qp -= qextra_limbs; | ||||
| 
 | ||||
| 			for (i = qextra_limbs - 1; i >= 0; i--) | ||||
| 				udiv_qrnnd(qp[i], n1, n1, 0, d); | ||||
| 
 | ||||
| 			np[0] = n1; | ||||
| 		} | ||||
| 		break; | ||||
| 
 | ||||
| 	case 2: | ||||
| 		{ | ||||
| 			mpi_size_t i; | ||||
| 			mpi_limb_t n1, n0, n2; | ||||
| 			mpi_limb_t d1, d0; | ||||
| 
 | ||||
| 			np += nsize - 2; | ||||
| 			d1 = dp[1]; | ||||
| 			d0 = dp[0]; | ||||
| 			n1 = np[1]; | ||||
| 			n0 = np[0]; | ||||
| 
 | ||||
| 			if (n1 >= d1 && (n1 > d1 || n0 >= d0)) { | ||||
| 				sub_ddmmss(n1, n0, n1, n0, d1, d0); | ||||
| 				most_significant_q_limb = 1; | ||||
| 			} | ||||
| 
 | ||||
| 			for (i = qextra_limbs + nsize - 2 - 1; i >= 0; i--) { | ||||
| 				mpi_limb_t q; | ||||
| 				mpi_limb_t r; | ||||
| 
 | ||||
| 				if (i >= qextra_limbs) | ||||
| 					np--; | ||||
| 				else | ||||
| 					np[0] = 0; | ||||
| 
 | ||||
| 				if (n1 == d1) { | ||||
| 					/* Q should be either 111..111 or 111..110.  Need special
 | ||||
| 					 * treatment of this rare case as normal division would | ||||
| 					 * give overflow.  */ | ||||
| 					q = ~(mpi_limb_t) 0; | ||||
| 
 | ||||
| 					r = n0 + d1; | ||||
| 					if (r < d1) {	/* Carry in the addition? */ | ||||
| 						add_ssaaaa(n1, n0, r - d0, | ||||
| 							   np[0], 0, d0); | ||||
| 						qp[i] = q; | ||||
| 						continue; | ||||
| 					} | ||||
| 					n1 = d0 - (d0 != 0 ? 1 : 0); | ||||
| 					n0 = -d0; | ||||
| 				} else { | ||||
| 					udiv_qrnnd(q, r, n1, n0, d1); | ||||
| 					umul_ppmm(n1, n0, d0, q); | ||||
| 				} | ||||
| 
 | ||||
| 				n2 = np[0]; | ||||
| q_test: | ||||
| 				if (n1 > r || (n1 == r && n0 > n2)) { | ||||
| 					/* The estimated Q was too large.  */ | ||||
| 					q--; | ||||
| 					sub_ddmmss(n1, n0, n1, n0, 0, d0); | ||||
| 					r += d1; | ||||
| 					if (r >= d1)	/* If not carry, test Q again.  */ | ||||
| 						goto q_test; | ||||
| 				} | ||||
| 
 | ||||
| 				qp[i] = q; | ||||
| 				sub_ddmmss(n1, n0, r, n2, n1, n0); | ||||
| 			} | ||||
| 			np[1] = n1; | ||||
| 			np[0] = n0; | ||||
| 		} | ||||
| 		break; | ||||
| 
 | ||||
| 	default: | ||||
| 		{ | ||||
| 			mpi_size_t i; | ||||
| 			mpi_limb_t dX, d1, n0; | ||||
| 
 | ||||
| 			np += nsize - dsize; | ||||
| 			dX = dp[dsize - 1]; | ||||
| 			d1 = dp[dsize - 2]; | ||||
| 			n0 = np[dsize - 1]; | ||||
| 
 | ||||
| 			if (n0 >= dX) { | ||||
| 				if (n0 > dX | ||||
| 				    || mpihelp_cmp(np, dp, dsize - 1) >= 0) { | ||||
| 					mpihelp_sub_n(np, np, dp, dsize); | ||||
| 					n0 = np[dsize - 1]; | ||||
| 					most_significant_q_limb = 1; | ||||
| 				} | ||||
| 			} | ||||
| 
 | ||||
| 			for (i = qextra_limbs + nsize - dsize - 1; i >= 0; i--) { | ||||
| 				mpi_limb_t q; | ||||
| 				mpi_limb_t n1, n2; | ||||
| 				mpi_limb_t cy_limb; | ||||
| 
 | ||||
| 				if (i >= qextra_limbs) { | ||||
| 					np--; | ||||
| 					n2 = np[dsize]; | ||||
| 				} else { | ||||
| 					n2 = np[dsize - 1]; | ||||
| 					MPN_COPY_DECR(np + 1, np, dsize - 1); | ||||
| 					np[0] = 0; | ||||
| 				} | ||||
| 
 | ||||
| 				if (n0 == dX) { | ||||
| 					/* This might over-estimate q, but it's probably not worth
 | ||||
| 					 * the extra code here to find out.  */ | ||||
| 					q = ~(mpi_limb_t) 0; | ||||
| 				} else { | ||||
| 					mpi_limb_t r; | ||||
| 
 | ||||
| 					udiv_qrnnd(q, r, n0, np[dsize - 1], dX); | ||||
| 					umul_ppmm(n1, n0, d1, q); | ||||
| 
 | ||||
| 					while (n1 > r | ||||
| 					       || (n1 == r | ||||
| 						   && n0 > np[dsize - 2])) { | ||||
| 						q--; | ||||
| 						r += dX; | ||||
| 						if (r < dX)	/* I.e. "carry in previous addition?" */ | ||||
| 							break; | ||||
| 						n1 -= n0 < d1; | ||||
| 						n0 -= d1; | ||||
| 					} | ||||
| 				} | ||||
| 
 | ||||
| 				/* Possible optimization: We already have (q * n0) and (1 * n1)
 | ||||
| 				 * after the calculation of q.  Taking advantage of that, we | ||||
| 				 * could make this loop make two iterations less.  */ | ||||
| 				cy_limb = mpihelp_submul_1(np, dp, dsize, q); | ||||
| 
 | ||||
| 				if (n2 != cy_limb) { | ||||
| 					mpihelp_add_n(np, np, dp, dsize); | ||||
| 					q--; | ||||
| 				} | ||||
| 
 | ||||
| 				qp[i] = q; | ||||
| 				n0 = np[dsize - 1]; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return most_significant_q_limb; | ||||
| } | ||||
| 
 | ||||
| /****************
 | ||||
|  * Divide (DIVIDEND_PTR,,DIVIDEND_SIZE) by DIVISOR_LIMB. | ||||
|  * Write DIVIDEND_SIZE limbs of quotient at QUOT_PTR. | ||||
|  * Return the single-limb remainder. | ||||
|  * There are no constraints on the value of the divisor. | ||||
|  * | ||||
|  * QUOT_PTR and DIVIDEND_PTR might point to the same limb. | ||||
|  */ | ||||
| 
 | ||||
| mpi_limb_t | ||||
| mpihelp_divmod_1(mpi_ptr_t quot_ptr, | ||||
| 		 mpi_ptr_t dividend_ptr, mpi_size_t dividend_size, | ||||
| 		 mpi_limb_t divisor_limb) | ||||
| { | ||||
| 	mpi_size_t i; | ||||
| 	mpi_limb_t n1, n0, r; | ||||
| 	int dummy; | ||||
| 
 | ||||
| 	if (!dividend_size) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	/* If multiplication is much faster than division, and the
 | ||||
| 	 * dividend is large, pre-invert the divisor, and use | ||||
| 	 * only multiplications in the inner loop. | ||||
| 	 * | ||||
| 	 * This test should be read: | ||||
| 	 * Does it ever help to use udiv_qrnnd_preinv? | ||||
| 	 * && Does what we save compensate for the inversion overhead? | ||||
| 	 */ | ||||
| 	if (UDIV_TIME > (2 * UMUL_TIME + 6) | ||||
| 	    && (UDIV_TIME - (2 * UMUL_TIME + 6)) * dividend_size > UDIV_TIME) { | ||||
| 		int normalization_steps; | ||||
| 
 | ||||
| 		count_leading_zeros(normalization_steps, divisor_limb); | ||||
| 		if (normalization_steps) { | ||||
| 			mpi_limb_t divisor_limb_inverted; | ||||
| 
 | ||||
| 			divisor_limb <<= normalization_steps; | ||||
| 
 | ||||
| 			/* Compute (2**2N - 2**N * DIVISOR_LIMB) / DIVISOR_LIMB.  The
 | ||||
| 			 * result is a (N+1)-bit approximation to 1/DIVISOR_LIMB, with the | ||||
| 			 * most significant bit (with weight 2**N) implicit. | ||||
| 			 */ | ||||
| 			/* Special case for DIVISOR_LIMB == 100...000.  */ | ||||
| 			if (!(divisor_limb << 1)) | ||||
| 				divisor_limb_inverted = ~(mpi_limb_t) 0; | ||||
| 			else | ||||
| 				udiv_qrnnd(divisor_limb_inverted, dummy, | ||||
| 					   -divisor_limb, 0, divisor_limb); | ||||
| 
 | ||||
| 			n1 = dividend_ptr[dividend_size - 1]; | ||||
| 			r = n1 >> (BITS_PER_MPI_LIMB - normalization_steps); | ||||
| 
 | ||||
| 			/* Possible optimization:
 | ||||
| 			 * if (r == 0 | ||||
| 			 * && divisor_limb > ((n1 << normalization_steps) | ||||
| 			 *                 | (dividend_ptr[dividend_size - 2] >> ...))) | ||||
| 			 * ...one division less... | ||||
| 			 */ | ||||
| 			for (i = dividend_size - 2; i >= 0; i--) { | ||||
| 				n0 = dividend_ptr[i]; | ||||
| 				UDIV_QRNND_PREINV(quot_ptr[i + 1], r, r, | ||||
| 						  ((n1 << normalization_steps) | ||||
| 						   | (n0 >> | ||||
| 						      (BITS_PER_MPI_LIMB - | ||||
| 						       normalization_steps))), | ||||
| 						  divisor_limb, | ||||
| 						  divisor_limb_inverted); | ||||
| 				n1 = n0; | ||||
| 			} | ||||
| 			UDIV_QRNND_PREINV(quot_ptr[0], r, r, | ||||
| 					  n1 << normalization_steps, | ||||
| 					  divisor_limb, divisor_limb_inverted); | ||||
| 			return r >> normalization_steps; | ||||
| 		} else { | ||||
| 			mpi_limb_t divisor_limb_inverted; | ||||
| 
 | ||||
| 			/* Compute (2**2N - 2**N * DIVISOR_LIMB) / DIVISOR_LIMB.  The
 | ||||
| 			 * result is a (N+1)-bit approximation to 1/DIVISOR_LIMB, with the | ||||
| 			 * most significant bit (with weight 2**N) implicit. | ||||
| 			 */ | ||||
| 			/* Special case for DIVISOR_LIMB == 100...000.  */ | ||||
| 			if (!(divisor_limb << 1)) | ||||
| 				divisor_limb_inverted = ~(mpi_limb_t) 0; | ||||
| 			else | ||||
| 				udiv_qrnnd(divisor_limb_inverted, dummy, | ||||
| 					   -divisor_limb, 0, divisor_limb); | ||||
| 
 | ||||
| 			i = dividend_size - 1; | ||||
| 			r = dividend_ptr[i]; | ||||
| 
 | ||||
| 			if (r >= divisor_limb) | ||||
| 				r = 0; | ||||
| 			else | ||||
| 				quot_ptr[i--] = 0; | ||||
| 
 | ||||
| 			for (; i >= 0; i--) { | ||||
| 				n0 = dividend_ptr[i]; | ||||
| 				UDIV_QRNND_PREINV(quot_ptr[i], r, r, | ||||
| 						  n0, divisor_limb, | ||||
| 						  divisor_limb_inverted); | ||||
| 			} | ||||
| 			return r; | ||||
| 		} | ||||
| 	} else { | ||||
| 		if (UDIV_NEEDS_NORMALIZATION) { | ||||
| 			int normalization_steps; | ||||
| 
 | ||||
| 			count_leading_zeros(normalization_steps, divisor_limb); | ||||
| 			if (normalization_steps) { | ||||
| 				divisor_limb <<= normalization_steps; | ||||
| 
 | ||||
| 				n1 = dividend_ptr[dividend_size - 1]; | ||||
| 				r = n1 >> (BITS_PER_MPI_LIMB - | ||||
| 					   normalization_steps); | ||||
| 
 | ||||
| 				/* Possible optimization:
 | ||||
| 				 * if (r == 0 | ||||
| 				 * && divisor_limb > ((n1 << normalization_steps) | ||||
| 				 *                 | (dividend_ptr[dividend_size - 2] >> ...))) | ||||
| 				 * ...one division less... | ||||
| 				 */ | ||||
| 				for (i = dividend_size - 2; i >= 0; i--) { | ||||
| 					n0 = dividend_ptr[i]; | ||||
| 					udiv_qrnnd(quot_ptr[i + 1], r, r, | ||||
| 						   ((n1 << normalization_steps) | ||||
| 						    | (n0 >> | ||||
| 						       (BITS_PER_MPI_LIMB - | ||||
| 							normalization_steps))), | ||||
| 						   divisor_limb); | ||||
| 					n1 = n0; | ||||
| 				} | ||||
| 				udiv_qrnnd(quot_ptr[0], r, r, | ||||
| 					   n1 << normalization_steps, | ||||
| 					   divisor_limb); | ||||
| 				return r >> normalization_steps; | ||||
| 			} | ||||
| 		} | ||||
| 		/* No normalization needed, either because udiv_qrnnd doesn't require
 | ||||
| 		 * it, or because DIVISOR_LIMB is already normalized.  */ | ||||
| 		i = dividend_size - 1; | ||||
| 		r = dividend_ptr[i]; | ||||
| 
 | ||||
| 		if (r >= divisor_limb) | ||||
| 			r = 0; | ||||
| 		else | ||||
| 			quot_ptr[i--] = 0; | ||||
| 
 | ||||
| 		for (; i >= 0; i--) { | ||||
| 			n0 = dividend_ptr[i]; | ||||
| 			udiv_qrnnd(quot_ptr[i], r, r, n0, divisor_limb); | ||||
| 		} | ||||
| 		return r; | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										527
									
								
								lib/mpi/mpih-mul.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										527
									
								
								lib/mpi/mpih-mul.c
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,527 @@ | |||
| /* mpihelp-mul.c  -  MPI helper functions
 | ||||
|  * Copyright (C) 1994, 1996, 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 | ||||
|  * | ||||
|  * Note: This code is heavily based on the GNU MP Library. | ||||
|  *	 Actually it's the same code with only minor changes in the | ||||
|  *	 way the data is stored; this is to support the abstraction | ||||
|  *	 of an optional secure memory allocation which may be used | ||||
|  *	 to avoid revealing of sensitive data due to paging etc. | ||||
|  *	 The GNU MP Library itself is published under the LGPL; | ||||
|  *	 however I decided to publish this code under the plain GPL. | ||||
|  */ | ||||
| 
 | ||||
| #include <linux/string.h> | ||||
| #include "mpi-internal.h" | ||||
| #include "longlong.h" | ||||
| 
 | ||||
| #define MPN_MUL_N_RECURSE(prodp, up, vp, size, tspace)		\ | ||||
| 	do {							\ | ||||
| 		if ((size) < KARATSUBA_THRESHOLD)		\ | ||||
| 			mul_n_basecase(prodp, up, vp, size);	\ | ||||
| 		else						\ | ||||
| 			mul_n(prodp, up, vp, size, tspace);	\ | ||||
| 	} while (0); | ||||
| 
 | ||||
| #define MPN_SQR_N_RECURSE(prodp, up, size, tspace)		\ | ||||
| 	do {							\ | ||||
| 		if ((size) < KARATSUBA_THRESHOLD)		\ | ||||
| 			mpih_sqr_n_basecase(prodp, up, size);	\ | ||||
| 		else						\ | ||||
| 			mpih_sqr_n(prodp, up, size, tspace);	\ | ||||
| 	} while (0); | ||||
| 
 | ||||
| /* Multiply the natural numbers u (pointed to by UP) and v (pointed to by VP),
 | ||||
|  * both with SIZE limbs, and store the result at PRODP.  2 * SIZE limbs are | ||||
|  * always stored.  Return the most significant limb. | ||||
|  * | ||||
|  * Argument constraints: | ||||
|  * 1. PRODP != UP and PRODP != VP, i.e. the destination | ||||
|  *    must be distinct from the multiplier and the multiplicand. | ||||
|  * | ||||
|  * | ||||
|  * Handle simple cases with traditional multiplication. | ||||
|  * | ||||
|  * This is the most critical code of multiplication.  All multiplies rely | ||||
|  * on this, both small and huge.  Small ones arrive here immediately.  Huge | ||||
|  * ones arrive here as this is the base case for Karatsuba's recursive | ||||
|  * algorithm below. | ||||
|  */ | ||||
| 
 | ||||
| static mpi_limb_t | ||||
| mul_n_basecase(mpi_ptr_t prodp, mpi_ptr_t up, mpi_ptr_t vp, mpi_size_t size) | ||||
| { | ||||
| 	mpi_size_t i; | ||||
| 	mpi_limb_t cy; | ||||
| 	mpi_limb_t v_limb; | ||||
| 
 | ||||
| 	/* Multiply by the first limb in V separately, as the result can be
 | ||||
| 	 * stored (not added) to PROD.  We also avoid a loop for zeroing.  */ | ||||
| 	v_limb = vp[0]; | ||||
| 	if (v_limb <= 1) { | ||||
| 		if (v_limb == 1) | ||||
| 			MPN_COPY(prodp, up, size); | ||||
| 		else | ||||
| 			MPN_ZERO(prodp, size); | ||||
| 		cy = 0; | ||||
| 	} else | ||||
| 		cy = mpihelp_mul_1(prodp, up, size, v_limb); | ||||
| 
 | ||||
| 	prodp[size] = cy; | ||||
| 	prodp++; | ||||
| 
 | ||||
| 	/* For each iteration in the outer loop, multiply one limb from
 | ||||
| 	 * U with one limb from V, and add it to PROD.  */ | ||||
| 	for (i = 1; i < size; i++) { | ||||
| 		v_limb = vp[i]; | ||||
| 		if (v_limb <= 1) { | ||||
| 			cy = 0; | ||||
| 			if (v_limb == 1) | ||||
| 				cy = mpihelp_add_n(prodp, prodp, up, size); | ||||
| 		} else | ||||
| 			cy = mpihelp_addmul_1(prodp, up, size, v_limb); | ||||
| 
 | ||||
| 		prodp[size] = cy; | ||||
| 		prodp++; | ||||
| 	} | ||||
| 
 | ||||
| 	return cy; | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| mul_n(mpi_ptr_t prodp, mpi_ptr_t up, mpi_ptr_t vp, | ||||
| 		mpi_size_t size, mpi_ptr_t tspace) | ||||
| { | ||||
| 	if (size & 1) { | ||||
| 		/* The size is odd, and the code below doesn't handle that.
 | ||||
| 		 * Multiply the least significant (size - 1) limbs with a recursive | ||||
| 		 * call, and handle the most significant limb of S1 and S2 | ||||
| 		 * separately. | ||||
| 		 * A slightly faster way to do this would be to make the Karatsuba | ||||
| 		 * code below behave as if the size were even, and let it check for | ||||
| 		 * odd size in the end.  I.e., in essence move this code to the end. | ||||
| 		 * Doing so would save us a recursive call, and potentially make the | ||||
| 		 * stack grow a lot less. | ||||
| 		 */ | ||||
| 		mpi_size_t esize = size - 1;	/* even size */ | ||||
| 		mpi_limb_t cy_limb; | ||||
| 
 | ||||
| 		MPN_MUL_N_RECURSE(prodp, up, vp, esize, tspace); | ||||
| 		cy_limb = mpihelp_addmul_1(prodp + esize, up, esize, vp[esize]); | ||||
| 		prodp[esize + esize] = cy_limb; | ||||
| 		cy_limb = mpihelp_addmul_1(prodp + esize, vp, size, up[esize]); | ||||
| 		prodp[esize + size] = cy_limb; | ||||
| 	} else { | ||||
| 		/* Anatolij Alekseevich Karatsuba's divide-and-conquer algorithm.
 | ||||
| 		 * | ||||
| 		 * Split U in two pieces, U1 and U0, such that | ||||
| 		 * U = U0 + U1*(B**n), | ||||
| 		 * and V in V1 and V0, such that | ||||
| 		 * V = V0 + V1*(B**n). | ||||
| 		 * | ||||
| 		 * UV is then computed recursively using the identity | ||||
| 		 * | ||||
| 		 *        2n   n          n                     n | ||||
| 		 * UV = (B  + B )U V  +  B (U -U )(V -V )  +  (B + 1)U V | ||||
| 		 *                1 1        1  0   0  1              0 0 | ||||
| 		 * | ||||
| 		 * Where B = 2**BITS_PER_MP_LIMB. | ||||
| 		 */ | ||||
| 		mpi_size_t hsize = size >> 1; | ||||
| 		mpi_limb_t cy; | ||||
| 		int negflg; | ||||
| 
 | ||||
| 		/* Product H.      ________________  ________________
 | ||||
| 		 *                |_____U1 x V1____||____U0 x V0_____| | ||||
| 		 * Put result in upper part of PROD and pass low part of TSPACE | ||||
| 		 * as new TSPACE. | ||||
| 		 */ | ||||
| 		MPN_MUL_N_RECURSE(prodp + size, up + hsize, vp + hsize, hsize, | ||||
| 				  tspace); | ||||
| 
 | ||||
| 		/* Product M.      ________________
 | ||||
| 		 *                |_(U1-U0)(V0-V1)_| | ||||
| 		 */ | ||||
| 		if (mpihelp_cmp(up + hsize, up, hsize) >= 0) { | ||||
| 			mpihelp_sub_n(prodp, up + hsize, up, hsize); | ||||
| 			negflg = 0; | ||||
| 		} else { | ||||
| 			mpihelp_sub_n(prodp, up, up + hsize, hsize); | ||||
| 			negflg = 1; | ||||
| 		} | ||||
| 		if (mpihelp_cmp(vp + hsize, vp, hsize) >= 0) { | ||||
| 			mpihelp_sub_n(prodp + hsize, vp + hsize, vp, hsize); | ||||
| 			negflg ^= 1; | ||||
| 		} else { | ||||
| 			mpihelp_sub_n(prodp + hsize, vp, vp + hsize, hsize); | ||||
| 			/* No change of NEGFLG.  */ | ||||
| 		} | ||||
| 		/* Read temporary operands from low part of PROD.
 | ||||
| 		 * Put result in low part of TSPACE using upper part of TSPACE | ||||
| 		 * as new TSPACE. | ||||
| 		 */ | ||||
| 		MPN_MUL_N_RECURSE(tspace, prodp, prodp + hsize, hsize, | ||||
| 				  tspace + size); | ||||
| 
 | ||||
| 		/* Add/copy product H. */ | ||||
| 		MPN_COPY(prodp + hsize, prodp + size, hsize); | ||||
| 		cy = mpihelp_add_n(prodp + size, prodp + size, | ||||
| 				   prodp + size + hsize, hsize); | ||||
| 
 | ||||
| 		/* Add product M (if NEGFLG M is a negative number) */ | ||||
| 		if (negflg) | ||||
| 			cy -= | ||||
| 			    mpihelp_sub_n(prodp + hsize, prodp + hsize, tspace, | ||||
| 					  size); | ||||
| 		else | ||||
| 			cy += | ||||
| 			    mpihelp_add_n(prodp + hsize, prodp + hsize, tspace, | ||||
| 					  size); | ||||
| 
 | ||||
| 		/* Product L.      ________________  ________________
 | ||||
| 		 *                |________________||____U0 x V0_____| | ||||
| 		 * Read temporary operands from low part of PROD. | ||||
| 		 * Put result in low part of TSPACE using upper part of TSPACE | ||||
| 		 * as new TSPACE. | ||||
| 		 */ | ||||
| 		MPN_MUL_N_RECURSE(tspace, up, vp, hsize, tspace + size); | ||||
| 
 | ||||
| 		/* Add/copy Product L (twice) */ | ||||
| 
 | ||||
| 		cy += mpihelp_add_n(prodp + hsize, prodp + hsize, tspace, size); | ||||
| 		if (cy) | ||||
| 			mpihelp_add_1(prodp + hsize + size, | ||||
| 				      prodp + hsize + size, hsize, cy); | ||||
| 
 | ||||
| 		MPN_COPY(prodp, tspace, hsize); | ||||
| 		cy = mpihelp_add_n(prodp + hsize, prodp + hsize, tspace + hsize, | ||||
| 				   hsize); | ||||
| 		if (cy) | ||||
| 			mpihelp_add_1(prodp + size, prodp + size, size, 1); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void mpih_sqr_n_basecase(mpi_ptr_t prodp, mpi_ptr_t up, mpi_size_t size) | ||||
| { | ||||
| 	mpi_size_t i; | ||||
| 	mpi_limb_t cy_limb; | ||||
| 	mpi_limb_t v_limb; | ||||
| 
 | ||||
| 	/* Multiply by the first limb in V separately, as the result can be
 | ||||
| 	 * stored (not added) to PROD.  We also avoid a loop for zeroing.  */ | ||||
| 	v_limb = up[0]; | ||||
| 	if (v_limb <= 1) { | ||||
| 		if (v_limb == 1) | ||||
| 			MPN_COPY(prodp, up, size); | ||||
| 		else | ||||
| 			MPN_ZERO(prodp, size); | ||||
| 		cy_limb = 0; | ||||
| 	} else | ||||
| 		cy_limb = mpihelp_mul_1(prodp, up, size, v_limb); | ||||
| 
 | ||||
| 	prodp[size] = cy_limb; | ||||
| 	prodp++; | ||||
| 
 | ||||
| 	/* For each iteration in the outer loop, multiply one limb from
 | ||||
| 	 * U with one limb from V, and add it to PROD.  */ | ||||
| 	for (i = 1; i < size; i++) { | ||||
| 		v_limb = up[i]; | ||||
| 		if (v_limb <= 1) { | ||||
| 			cy_limb = 0; | ||||
| 			if (v_limb == 1) | ||||
| 				cy_limb = mpihelp_add_n(prodp, prodp, up, size); | ||||
| 		} else | ||||
| 			cy_limb = mpihelp_addmul_1(prodp, up, size, v_limb); | ||||
| 
 | ||||
| 		prodp[size] = cy_limb; | ||||
| 		prodp++; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void | ||||
| mpih_sqr_n(mpi_ptr_t prodp, mpi_ptr_t up, mpi_size_t size, mpi_ptr_t tspace) | ||||
| { | ||||
| 	if (size & 1) { | ||||
| 		/* The size is odd, and the code below doesn't handle that.
 | ||||
| 		 * Multiply the least significant (size - 1) limbs with a recursive | ||||
| 		 * call, and handle the most significant limb of S1 and S2 | ||||
| 		 * separately. | ||||
| 		 * A slightly faster way to do this would be to make the Karatsuba | ||||
| 		 * code below behave as if the size were even, and let it check for | ||||
| 		 * odd size in the end.  I.e., in essence move this code to the end. | ||||
| 		 * Doing so would save us a recursive call, and potentially make the | ||||
| 		 * stack grow a lot less. | ||||
| 		 */ | ||||
| 		mpi_size_t esize = size - 1;	/* even size */ | ||||
| 		mpi_limb_t cy_limb; | ||||
| 
 | ||||
| 		MPN_SQR_N_RECURSE(prodp, up, esize, tspace); | ||||
| 		cy_limb = mpihelp_addmul_1(prodp + esize, up, esize, up[esize]); | ||||
| 		prodp[esize + esize] = cy_limb; | ||||
| 		cy_limb = mpihelp_addmul_1(prodp + esize, up, size, up[esize]); | ||||
| 
 | ||||
| 		prodp[esize + size] = cy_limb; | ||||
| 	} else { | ||||
| 		mpi_size_t hsize = size >> 1; | ||||
| 		mpi_limb_t cy; | ||||
| 
 | ||||
| 		/* Product H.      ________________  ________________
 | ||||
| 		 *                |_____U1 x U1____||____U0 x U0_____| | ||||
| 		 * Put result in upper part of PROD and pass low part of TSPACE | ||||
| 		 * as new TSPACE. | ||||
| 		 */ | ||||
| 		MPN_SQR_N_RECURSE(prodp + size, up + hsize, hsize, tspace); | ||||
| 
 | ||||
| 		/* Product M.      ________________
 | ||||
| 		 *                |_(U1-U0)(U0-U1)_| | ||||
| 		 */ | ||||
| 		if (mpihelp_cmp(up + hsize, up, hsize) >= 0) | ||||
| 			mpihelp_sub_n(prodp, up + hsize, up, hsize); | ||||
| 		else | ||||
| 			mpihelp_sub_n(prodp, up, up + hsize, hsize); | ||||
| 
 | ||||
| 		/* Read temporary operands from low part of PROD.
 | ||||
| 		 * Put result in low part of TSPACE using upper part of TSPACE | ||||
| 		 * as new TSPACE.  */ | ||||
| 		MPN_SQR_N_RECURSE(tspace, prodp, hsize, tspace + size); | ||||
| 
 | ||||
| 		/* Add/copy product H  */ | ||||
| 		MPN_COPY(prodp + hsize, prodp + size, hsize); | ||||
| 		cy = mpihelp_add_n(prodp + size, prodp + size, | ||||
| 				   prodp + size + hsize, hsize); | ||||
| 
 | ||||
| 		/* Add product M (if NEGFLG M is a negative number).  */ | ||||
| 		cy -= mpihelp_sub_n(prodp + hsize, prodp + hsize, tspace, size); | ||||
| 
 | ||||
| 		/* Product L.      ________________  ________________
 | ||||
| 		 *                |________________||____U0 x U0_____| | ||||
| 		 * Read temporary operands from low part of PROD. | ||||
| 		 * Put result in low part of TSPACE using upper part of TSPACE | ||||
| 		 * as new TSPACE.  */ | ||||
| 		MPN_SQR_N_RECURSE(tspace, up, hsize, tspace + size); | ||||
| 
 | ||||
| 		/* Add/copy Product L (twice).  */ | ||||
| 		cy += mpihelp_add_n(prodp + hsize, prodp + hsize, tspace, size); | ||||
| 		if (cy) | ||||
| 			mpihelp_add_1(prodp + hsize + size, | ||||
| 				      prodp + hsize + size, hsize, cy); | ||||
| 
 | ||||
| 		MPN_COPY(prodp, tspace, hsize); | ||||
| 		cy = mpihelp_add_n(prodp + hsize, prodp + hsize, tspace + hsize, | ||||
| 				   hsize); | ||||
| 		if (cy) | ||||
| 			mpihelp_add_1(prodp + size, prodp + size, size, 1); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| /* This should be made into an inline function in gmp.h.  */ | ||||
| int mpihelp_mul_n(mpi_ptr_t prodp, mpi_ptr_t up, mpi_ptr_t vp, mpi_size_t size) | ||||
| { | ||||
| 	if (up == vp) { | ||||
| 		if (size < KARATSUBA_THRESHOLD) | ||||
| 			mpih_sqr_n_basecase(prodp, up, size); | ||||
| 		else { | ||||
| 			mpi_ptr_t tspace; | ||||
| 			tspace = mpi_alloc_limb_space(2 * size); | ||||
| 			if (!tspace) | ||||
| 				return -ENOMEM; | ||||
| 			mpih_sqr_n(prodp, up, size, tspace); | ||||
| 			mpi_free_limb_space(tspace); | ||||
| 		} | ||||
| 	} else { | ||||
| 		if (size < KARATSUBA_THRESHOLD) | ||||
| 			mul_n_basecase(prodp, up, vp, size); | ||||
| 		else { | ||||
| 			mpi_ptr_t tspace; | ||||
| 			tspace = mpi_alloc_limb_space(2 * size); | ||||
| 			if (!tspace) | ||||
| 				return -ENOMEM; | ||||
| 			mul_n(prodp, up, vp, size, tspace); | ||||
| 			mpi_free_limb_space(tspace); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| int | ||||
| mpihelp_mul_karatsuba_case(mpi_ptr_t prodp, | ||||
| 			   mpi_ptr_t up, mpi_size_t usize, | ||||
| 			   mpi_ptr_t vp, mpi_size_t vsize, | ||||
| 			   struct karatsuba_ctx *ctx) | ||||
| { | ||||
| 	mpi_limb_t cy; | ||||
| 
 | ||||
| 	if (!ctx->tspace || ctx->tspace_size < vsize) { | ||||
| 		if (ctx->tspace) | ||||
| 			mpi_free_limb_space(ctx->tspace); | ||||
| 		ctx->tspace = mpi_alloc_limb_space(2 * vsize); | ||||
| 		if (!ctx->tspace) | ||||
| 			return -ENOMEM; | ||||
| 		ctx->tspace_size = vsize; | ||||
| 	} | ||||
| 
 | ||||
| 	MPN_MUL_N_RECURSE(prodp, up, vp, vsize, ctx->tspace); | ||||
| 
 | ||||
| 	prodp += vsize; | ||||
| 	up += vsize; | ||||
| 	usize -= vsize; | ||||
| 	if (usize >= vsize) { | ||||
| 		if (!ctx->tp || ctx->tp_size < vsize) { | ||||
| 			if (ctx->tp) | ||||
| 				mpi_free_limb_space(ctx->tp); | ||||
| 			ctx->tp = mpi_alloc_limb_space(2 * vsize); | ||||
| 			if (!ctx->tp) { | ||||
| 				if (ctx->tspace) | ||||
| 					mpi_free_limb_space(ctx->tspace); | ||||
| 				ctx->tspace = NULL; | ||||
| 				return -ENOMEM; | ||||
| 			} | ||||
| 			ctx->tp_size = vsize; | ||||
| 		} | ||||
| 
 | ||||
| 		do { | ||||
| 			MPN_MUL_N_RECURSE(ctx->tp, up, vp, vsize, ctx->tspace); | ||||
| 			cy = mpihelp_add_n(prodp, prodp, ctx->tp, vsize); | ||||
| 			mpihelp_add_1(prodp + vsize, ctx->tp + vsize, vsize, | ||||
| 				      cy); | ||||
| 			prodp += vsize; | ||||
| 			up += vsize; | ||||
| 			usize -= vsize; | ||||
| 		} while (usize >= vsize); | ||||
| 	} | ||||
| 
 | ||||
| 	if (usize) { | ||||
| 		if (usize < KARATSUBA_THRESHOLD) { | ||||
| 			mpi_limb_t tmp; | ||||
| 			if (mpihelp_mul(ctx->tspace, vp, vsize, up, usize, &tmp) | ||||
| 			    < 0) | ||||
| 				return -ENOMEM; | ||||
| 		} else { | ||||
| 			if (!ctx->next) { | ||||
| 				ctx->next = kzalloc(sizeof *ctx, GFP_KERNEL); | ||||
| 				if (!ctx->next) | ||||
| 					return -ENOMEM; | ||||
| 			} | ||||
| 			if (mpihelp_mul_karatsuba_case(ctx->tspace, | ||||
| 						       vp, vsize, | ||||
| 						       up, usize, | ||||
| 						       ctx->next) < 0) | ||||
| 				return -ENOMEM; | ||||
| 		} | ||||
| 
 | ||||
| 		cy = mpihelp_add_n(prodp, prodp, ctx->tspace, vsize); | ||||
| 		mpihelp_add_1(prodp + vsize, ctx->tspace + vsize, usize, cy); | ||||
| 	} | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| void mpihelp_release_karatsuba_ctx(struct karatsuba_ctx *ctx) | ||||
| { | ||||
| 	struct karatsuba_ctx *ctx2; | ||||
| 
 | ||||
| 	if (ctx->tp) | ||||
| 		mpi_free_limb_space(ctx->tp); | ||||
| 	if (ctx->tspace) | ||||
| 		mpi_free_limb_space(ctx->tspace); | ||||
| 	for (ctx = ctx->next; ctx; ctx = ctx2) { | ||||
| 		ctx2 = ctx->next; | ||||
| 		if (ctx->tp) | ||||
| 			mpi_free_limb_space(ctx->tp); | ||||
| 		if (ctx->tspace) | ||||
| 			mpi_free_limb_space(ctx->tspace); | ||||
| 		kfree(ctx); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| /* Multiply the natural numbers u (pointed to by UP, with USIZE limbs)
 | ||||
|  * and v (pointed to by VP, with VSIZE limbs), and store the result at | ||||
|  * PRODP.  USIZE + VSIZE limbs are always stored, but if the input | ||||
|  * operands are normalized.  Return the most significant limb of the | ||||
|  * result. | ||||
|  * | ||||
|  * NOTE: The space pointed to by PRODP is overwritten before finished | ||||
|  * with U and V, so overlap is an error. | ||||
|  * | ||||
|  * Argument constraints: | ||||
|  * 1. USIZE >= VSIZE. | ||||
|  * 2. PRODP != UP and PRODP != VP, i.e. the destination | ||||
|  *    must be distinct from the multiplier and the multiplicand. | ||||
|  */ | ||||
| 
 | ||||
| int | ||||
| mpihelp_mul(mpi_ptr_t prodp, mpi_ptr_t up, mpi_size_t usize, | ||||
| 	    mpi_ptr_t vp, mpi_size_t vsize, mpi_limb_t *_result) | ||||
| { | ||||
| 	mpi_ptr_t prod_endp = prodp + usize + vsize - 1; | ||||
| 	mpi_limb_t cy; | ||||
| 	struct karatsuba_ctx ctx; | ||||
| 
 | ||||
| 	if (vsize < KARATSUBA_THRESHOLD) { | ||||
| 		mpi_size_t i; | ||||
| 		mpi_limb_t v_limb; | ||||
| 
 | ||||
| 		if (!vsize) { | ||||
| 			*_result = 0; | ||||
| 			return 0; | ||||
| 		} | ||||
| 
 | ||||
| 		/* Multiply by the first limb in V separately, as the result can be
 | ||||
| 		 * stored (not added) to PROD.  We also avoid a loop for zeroing.  */ | ||||
| 		v_limb = vp[0]; | ||||
| 		if (v_limb <= 1) { | ||||
| 			if (v_limb == 1) | ||||
| 				MPN_COPY(prodp, up, usize); | ||||
| 			else | ||||
| 				MPN_ZERO(prodp, usize); | ||||
| 			cy = 0; | ||||
| 		} else | ||||
| 			cy = mpihelp_mul_1(prodp, up, usize, v_limb); | ||||
| 
 | ||||
| 		prodp[usize] = cy; | ||||
| 		prodp++; | ||||
| 
 | ||||
| 		/* For each iteration in the outer loop, multiply one limb from
 | ||||
| 		 * U with one limb from V, and add it to PROD.  */ | ||||
| 		for (i = 1; i < vsize; i++) { | ||||
| 			v_limb = vp[i]; | ||||
| 			if (v_limb <= 1) { | ||||
| 				cy = 0; | ||||
| 				if (v_limb == 1) | ||||
| 					cy = mpihelp_add_n(prodp, prodp, up, | ||||
| 							   usize); | ||||
| 			} else | ||||
| 				cy = mpihelp_addmul_1(prodp, up, usize, v_limb); | ||||
| 
 | ||||
| 			prodp[usize] = cy; | ||||
| 			prodp++; | ||||
| 		} | ||||
| 
 | ||||
| 		*_result = cy; | ||||
| 		return 0; | ||||
| 	} | ||||
| 
 | ||||
| 	memset(&ctx, 0, sizeof ctx); | ||||
| 	if (mpihelp_mul_karatsuba_case(prodp, up, usize, vp, vsize, &ctx) < 0) | ||||
| 		return -ENOMEM; | ||||
| 	mpihelp_release_karatsuba_ctx(&ctx); | ||||
| 	*_result = *prod_endp; | ||||
| 	return 0; | ||||
| } | ||||
							
								
								
									
										208
									
								
								lib/mpi/mpiutil.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										208
									
								
								lib/mpi/mpiutil.c
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,208 @@ | |||
| /* mpiutil.ac  -  Utility functions for MPI
 | ||||
|  * Copyright (C) 1998, 1999 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" | ||||
| 
 | ||||
| /****************
 | ||||
|  * Note:  It was a bad idea to use the number of limbs to allocate | ||||
|  *	  because on a alpha the limbs are large but we normally need | ||||
|  *	  integers of n bits - So we should chnage this to bits (or bytes). | ||||
|  * | ||||
|  *	  But mpi_alloc is used in a lot of places :-) | ||||
|  */ | ||||
| MPI mpi_alloc(unsigned nlimbs) | ||||
| { | ||||
| 	MPI a; | ||||
| 
 | ||||
| 	a = kmalloc(sizeof *a, GFP_KERNEL); | ||||
| 	if (!a) | ||||
| 		return a; | ||||
| 
 | ||||
| 	if (nlimbs) { | ||||
| 		a->d = mpi_alloc_limb_space(nlimbs); | ||||
| 		if (!a->d) { | ||||
| 			kfree(a); | ||||
| 			return NULL; | ||||
| 		} | ||||
| 	} else { | ||||
| 		a->d = NULL; | ||||
| 	} | ||||
| 
 | ||||
| 	a->alloced = nlimbs; | ||||
| 	a->nlimbs = 0; | ||||
| 	a->sign = 0; | ||||
| 	a->flags = 0; | ||||
| 	a->nbits = 0; | ||||
| 	return a; | ||||
| } | ||||
| EXPORT_SYMBOL_GPL(mpi_alloc); | ||||
| 
 | ||||
| mpi_ptr_t mpi_alloc_limb_space(unsigned nlimbs) | ||||
| { | ||||
| 	size_t len = nlimbs * sizeof(mpi_limb_t); | ||||
| 
 | ||||
| 	return kmalloc(len, GFP_KERNEL); | ||||
| } | ||||
| 
 | ||||
| void mpi_free_limb_space(mpi_ptr_t a) | ||||
| { | ||||
| 	if (!a) | ||||
| 		return; | ||||
| 
 | ||||
| 	kfree(a); | ||||
| } | ||||
| 
 | ||||
| void mpi_assign_limb_space(MPI a, mpi_ptr_t ap, unsigned nlimbs) | ||||
| { | ||||
| 	mpi_free_limb_space(a->d); | ||||
| 	a->d = ap; | ||||
| 	a->alloced = nlimbs; | ||||
| } | ||||
| 
 | ||||
| /****************
 | ||||
|  * Resize the array of A to NLIMBS. the additional space is cleared | ||||
|  * (set to 0) [done by m_realloc()] | ||||
|  */ | ||||
| int mpi_resize(MPI a, unsigned nlimbs) | ||||
| { | ||||
| 	void *p; | ||||
| 
 | ||||
| 	if (nlimbs <= a->alloced) | ||||
| 		return 0;	/* no need to do it */ | ||||
| 
 | ||||
| 	if (a->d) { | ||||
| 		p = kmalloc(nlimbs * sizeof(mpi_limb_t), GFP_KERNEL); | ||||
| 		if (!p) | ||||
| 			return -ENOMEM; | ||||
| 		memcpy(p, a->d, a->alloced * sizeof(mpi_limb_t)); | ||||
| 		kfree(a->d); | ||||
| 		a->d = p; | ||||
| 	} else { | ||||
| 		a->d = kzalloc(nlimbs * sizeof(mpi_limb_t), GFP_KERNEL); | ||||
| 		if (!a->d) | ||||
| 			return -ENOMEM; | ||||
| 	} | ||||
| 	a->alloced = nlimbs; | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| void mpi_clear(MPI a) | ||||
| { | ||||
| 	a->nlimbs = 0; | ||||
| 	a->nbits = 0; | ||||
| 	a->flags = 0; | ||||
| } | ||||
| 
 | ||||
| void mpi_free(MPI a) | ||||
| { | ||||
| 	if (!a) | ||||
| 		return; | ||||
| 
 | ||||
| 	if (a->flags & 4) | ||||
| 		kfree(a->d); | ||||
| 	else | ||||
| 		mpi_free_limb_space(a->d); | ||||
| 
 | ||||
| 	if (a->flags & ~7) | ||||
| 		pr_info("invalid flag value in mpi\n"); | ||||
| 	kfree(a); | ||||
| } | ||||
| EXPORT_SYMBOL_GPL(mpi_free); | ||||
| 
 | ||||
| /****************
 | ||||
|  * Note: This copy function should not interpret the MPI | ||||
|  *	 but copy it transparently. | ||||
|  */ | ||||
| int mpi_copy(MPI *copied, const MPI a) | ||||
| { | ||||
| 	size_t i; | ||||
| 	MPI b; | ||||
| 
 | ||||
| 	*copied = MPI_NULL; | ||||
| 
 | ||||
| 	if (a) { | ||||
| 		b = mpi_alloc(a->nlimbs); | ||||
| 		if (!b) | ||||
| 			return -ENOMEM; | ||||
| 
 | ||||
| 		b->nlimbs = a->nlimbs; | ||||
| 		b->sign = a->sign; | ||||
| 		b->flags = a->flags; | ||||
| 		b->nbits = a->nbits; | ||||
| 
 | ||||
| 		for (i = 0; i < b->nlimbs; i++) | ||||
| 			b->d[i] = a->d[i]; | ||||
| 
 | ||||
| 		*copied = b; | ||||
| 	} | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| int mpi_set(MPI w, const MPI u) | ||||
| { | ||||
| 	mpi_ptr_t wp, up; | ||||
| 	mpi_size_t usize = u->nlimbs; | ||||
| 	int usign = u->sign; | ||||
| 
 | ||||
| 	if (RESIZE_IF_NEEDED(w, (size_t) usize) < 0) | ||||
| 		return -ENOMEM; | ||||
| 
 | ||||
| 	wp = w->d; | ||||
| 	up = u->d; | ||||
| 	MPN_COPY(wp, up, usize); | ||||
| 	w->nlimbs = usize; | ||||
| 	w->nbits = u->nbits; | ||||
| 	w->flags = u->flags; | ||||
| 	w->sign = usign; | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| int mpi_set_ui(MPI w, unsigned long u) | ||||
| { | ||||
| 	if (RESIZE_IF_NEEDED(w, 1) < 0) | ||||
| 		return -ENOMEM; | ||||
| 	w->d[0] = u; | ||||
| 	w->nlimbs = u ? 1 : 0; | ||||
| 	w->sign = 0; | ||||
| 	w->nbits = 0; | ||||
| 	w->flags = 0; | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| MPI mpi_alloc_set_ui(unsigned long u) | ||||
| { | ||||
| 	MPI w = mpi_alloc(1); | ||||
| 	if (!w) | ||||
| 		return w; | ||||
| 	w->d[0] = u; | ||||
| 	w->nlimbs = u ? 1 : 0; | ||||
| 	w->sign = 0; | ||||
| 	return w; | ||||
| } | ||||
| 
 | ||||
| void mpi_swap(MPI a, MPI b) | ||||
| { | ||||
| 	struct gcry_mpi tmp; | ||||
| 
 | ||||
| 	tmp = *a; | ||||
| 	*a = *b; | ||||
| 	*b = tmp; | ||||
| } | ||||
		Loading…
	
		Reference in a new issue
	
	 Dmitry Kasatkin
						Dmitry Kasatkin