mirror of https://gitee.com/openkylin/linux.git
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
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
|
@ -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);
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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 New Issue