diff options
Diffstat (limited to 'lib/mpi')
| -rw-r--r-- | lib/mpi/generic_mpih-add1.c | 61 | ||||
| -rw-r--r-- | lib/mpi/generic_mpih-lshift.c | 63 | ||||
| -rw-r--r-- | lib/mpi/generic_mpih-mul1.c | 57 | ||||
| -rw-r--r-- | lib/mpi/generic_mpih-mul2.c | 60 | ||||
| -rw-r--r-- | lib/mpi/generic_mpih-mul3.c | 61 | ||||
| -rw-r--r-- | lib/mpi/generic_mpih-rshift.c | 63 | ||||
| -rw-r--r-- | lib/mpi/generic_mpih-sub1.c | 60 | ||||
| -rw-r--r-- | lib/mpi/mpi-bit.c | 236 | ||||
| -rw-r--r-- | lib/mpi/mpi-pow.c | 323 | ||||
| -rw-r--r-- | lib/mpi/mpicoder.c | 365 | ||||
| -rw-r--r-- | lib/mpi/mpih-cmp.c | 56 | ||||
| -rw-r--r-- | lib/mpi/mpih-div.c | 541 | ||||
| -rw-r--r-- | lib/mpi/mpih-mul.c | 527 | ||||
| -rw-r--r-- | lib/mpi/mpiutil.c | 208 |
14 files changed, 2681 insertions, 0 deletions
diff --git a/lib/mpi/generic_mpih-add1.c b/lib/mpi/generic_mpih-add1.c new file mode 100644 index 000000000000..c94c7dd344b3 --- /dev/null +++ b/lib/mpi/generic_mpih-add1.c | |||
| @@ -0,0 +1,61 @@ | |||
| 1 | /* mpihelp-add_1.c - MPI helper functions | ||
| 2 | * Copyright (C) 1994, 1996, 1997, 1998, | ||
| 3 | * 2000 Free Software Foundation, Inc. | ||
| 4 | * | ||
| 5 | * This file is part of GnuPG. | ||
| 6 | * | ||
| 7 | * GnuPG is free software; you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU General Public License as published by | ||
| 9 | * the Free Software Foundation; either version 2 of the License, or | ||
| 10 | * (at your option) any later version. | ||
| 11 | * | ||
| 12 | * GnuPG is distributed in the hope that it will be useful, | ||
| 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | * GNU General Public License for more details. | ||
| 16 | * | ||
| 17 | * You should have received a copy of the GNU General Public License | ||
| 18 | * along with this program; if not, write to the Free Software | ||
| 19 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA | ||
| 20 | * | ||
| 21 | * Note: This code is heavily based on the GNU MP Library. | ||
| 22 | * Actually it's the same code with only minor changes in the | ||
| 23 | * way the data is stored; this is to support the abstraction | ||
| 24 | * of an optional secure memory allocation which may be used | ||
| 25 | * to avoid revealing of sensitive data due to paging etc. | ||
| 26 | * The GNU MP Library itself is published under the LGPL; | ||
| 27 | * however I decided to publish this code under the plain GPL. | ||
| 28 | */ | ||
| 29 | |||
| 30 | #include "mpi-internal.h" | ||
| 31 | #include "longlong.h" | ||
| 32 | |||
| 33 | mpi_limb_t | ||
| 34 | mpihelp_add_n(mpi_ptr_t res_ptr, mpi_ptr_t s1_ptr, | ||
| 35 | mpi_ptr_t s2_ptr, mpi_size_t size) | ||
| 36 | { | ||
| 37 | mpi_limb_t x, y, cy; | ||
| 38 | mpi_size_t j; | ||
| 39 | |||
| 40 | /* The loop counter and index J goes from -SIZE to -1. This way | ||
| 41 | the loop becomes faster. */ | ||
| 42 | j = -size; | ||
| 43 | |||
| 44 | /* Offset the base pointers to compensate for the negative indices. */ | ||
| 45 | s1_ptr -= j; | ||
| 46 | s2_ptr -= j; | ||
| 47 | res_ptr -= j; | ||
| 48 | |||
| 49 | cy = 0; | ||
| 50 | do { | ||
| 51 | y = s2_ptr[j]; | ||
| 52 | x = s1_ptr[j]; | ||
| 53 | y += cy; /* add previous carry to one addend */ | ||
| 54 | cy = y < cy; /* get out carry from that addition */ | ||
| 55 | y += x; /* add other addend */ | ||
| 56 | cy += y < x; /* get out carry from that add, combine */ | ||
| 57 | res_ptr[j] = y; | ||
| 58 | } while (++j); | ||
| 59 | |||
| 60 | return cy; | ||
| 61 | } | ||
diff --git a/lib/mpi/generic_mpih-lshift.c b/lib/mpi/generic_mpih-lshift.c new file mode 100644 index 000000000000..86318927231a --- /dev/null +++ b/lib/mpi/generic_mpih-lshift.c | |||
| @@ -0,0 +1,63 @@ | |||
| 1 | /* mpihelp-lshift.c - MPI helper functions | ||
| 2 | * Copyright (C) 1994, 1996, 1998, 2001 Free Software Foundation, Inc. | ||
| 3 | * | ||
| 4 | * This file is part of GnuPG. | ||
| 5 | * | ||
| 6 | * GnuPG is free software; you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU General Public License as published by | ||
| 8 | * the Free Software Foundation; either version 2 of the License, or | ||
| 9 | * (at your option) any later version. | ||
| 10 | * | ||
| 11 | * GnuPG is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License | ||
| 17 | * along with this program; if not, write to the Free Software | ||
| 18 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA | ||
| 19 | * | ||
| 20 | * Note: This code is heavily based on the GNU MP Library. | ||
| 21 | * Actually it's the same code with only minor changes in the | ||
| 22 | * way the data is stored; this is to support the abstraction | ||
| 23 | * of an optional secure memory allocation which may be used | ||
| 24 | * to avoid revealing of sensitive data due to paging etc. | ||
| 25 | * The GNU MP Library itself is published under the LGPL; | ||
| 26 | * however I decided to publish this code under the plain GPL. | ||
| 27 | */ | ||
| 28 | |||
| 29 | #include "mpi-internal.h" | ||
| 30 | |||
| 31 | /* Shift U (pointed to by UP and USIZE digits long) CNT bits to the left | ||
| 32 | * and store the USIZE least significant digits of the result at WP. | ||
| 33 | * Return the bits shifted out from the most significant digit. | ||
| 34 | * | ||
| 35 | * Argument constraints: | ||
| 36 | * 1. 0 < CNT < BITS_PER_MP_LIMB | ||
| 37 | * 2. If the result is to be written over the input, WP must be >= UP. | ||
| 38 | */ | ||
| 39 | |||
| 40 | mpi_limb_t | ||
| 41 | mpihelp_lshift(mpi_ptr_t wp, mpi_ptr_t up, mpi_size_t usize, unsigned int cnt) | ||
| 42 | { | ||
| 43 | mpi_limb_t high_limb, low_limb; | ||
| 44 | unsigned sh_1, sh_2; | ||
| 45 | mpi_size_t i; | ||
| 46 | mpi_limb_t retval; | ||
| 47 | |||
| 48 | sh_1 = cnt; | ||
| 49 | wp += 1; | ||
| 50 | sh_2 = BITS_PER_MPI_LIMB - sh_1; | ||
| 51 | i = usize - 1; | ||
| 52 | low_limb = up[i]; | ||
| 53 | retval = low_limb >> sh_2; | ||
| 54 | high_limb = low_limb; | ||
| 55 | while (--i >= 0) { | ||
| 56 | low_limb = up[i]; | ||
| 57 | wp[i] = (high_limb << sh_1) | (low_limb >> sh_2); | ||
| 58 | high_limb = low_limb; | ||
| 59 | } | ||
| 60 | wp[i] = high_limb << sh_1; | ||
| 61 | |||
| 62 | return retval; | ||
| 63 | } | ||
diff --git a/lib/mpi/generic_mpih-mul1.c b/lib/mpi/generic_mpih-mul1.c new file mode 100644 index 000000000000..1668dfd9092c --- /dev/null +++ b/lib/mpi/generic_mpih-mul1.c | |||
| @@ -0,0 +1,57 @@ | |||
| 1 | /* mpihelp-mul_1.c - MPI helper functions | ||
| 2 | * Copyright (C) 1994, 1996, 1997, 1998, 2001 Free Software Foundation, Inc. | ||
| 3 | * | ||
| 4 | * This file is part of GnuPG. | ||
| 5 | * | ||
| 6 | * GnuPG is free software; you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU General Public License as published by | ||
| 8 | * the Free Software Foundation; either version 2 of the License, or | ||
| 9 | * (at your option) any later version. | ||
| 10 | * | ||
| 11 | * GnuPG is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License | ||
| 17 | * along with this program; if not, write to the Free Software | ||
| 18 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA | ||
| 19 | * | ||
| 20 | * Note: This code is heavily based on the GNU MP Library. | ||
| 21 | * Actually it's the same code with only minor changes in the | ||
| 22 | * way the data is stored; this is to support the abstraction | ||
| 23 | * of an optional secure memory allocation which may be used | ||
| 24 | * to avoid revealing of sensitive data due to paging etc. | ||
| 25 | * The GNU MP Library itself is published under the LGPL; | ||
| 26 | * however I decided to publish this code under the plain GPL. | ||
| 27 | */ | ||
| 28 | |||
| 29 | #include "mpi-internal.h" | ||
| 30 | #include "longlong.h" | ||
| 31 | |||
| 32 | mpi_limb_t | ||
| 33 | mpihelp_mul_1(mpi_ptr_t res_ptr, mpi_ptr_t s1_ptr, mpi_size_t s1_size, | ||
| 34 | mpi_limb_t s2_limb) | ||
| 35 | { | ||
| 36 | mpi_limb_t cy_limb; | ||
| 37 | mpi_size_t j; | ||
| 38 | mpi_limb_t prod_high, prod_low; | ||
| 39 | |||
| 40 | /* The loop counter and index J goes from -S1_SIZE to -1. This way | ||
| 41 | * the loop becomes faster. */ | ||
| 42 | j = -s1_size; | ||
| 43 | |||
| 44 | /* Offset the base pointers to compensate for the negative indices. */ | ||
| 45 | s1_ptr -= j; | ||
| 46 | res_ptr -= j; | ||
| 47 | |||
| 48 | cy_limb = 0; | ||
| 49 | do { | ||
| 50 | umul_ppmm(prod_high, prod_low, s1_ptr[j], s2_limb); | ||
| 51 | prod_low += cy_limb; | ||
| 52 | cy_limb = (prod_low < cy_limb ? 1 : 0) + prod_high; | ||
| 53 | res_ptr[j] = prod_low; | ||
| 54 | } while (++j); | ||
| 55 | |||
| 56 | return cy_limb; | ||
| 57 | } | ||
diff --git a/lib/mpi/generic_mpih-mul2.c b/lib/mpi/generic_mpih-mul2.c new file mode 100644 index 000000000000..8a7b29ee1740 --- /dev/null +++ b/lib/mpi/generic_mpih-mul2.c | |||
| @@ -0,0 +1,60 @@ | |||
| 1 | /* mpihelp-mul_2.c - MPI helper functions | ||
| 2 | * Copyright (C) 1994, 1996, 1997, 1998, 2001 Free Software Foundation, Inc. | ||
| 3 | * | ||
| 4 | * This file is part of GnuPG. | ||
| 5 | * | ||
| 6 | * GnuPG is free software; you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU General Public License as published by | ||
| 8 | * the Free Software Foundation; either version 2 of the License, or | ||
| 9 | * (at your option) any later version. | ||
| 10 | * | ||
| 11 | * GnuPG is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License | ||
| 17 | * along with this program; if not, write to the Free Software | ||
| 18 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA | ||
| 19 | * | ||
| 20 | * Note: This code is heavily based on the GNU MP Library. | ||
| 21 | * Actually it's the same code with only minor changes in the | ||
| 22 | * way the data is stored; this is to support the abstraction | ||
| 23 | * of an optional secure memory allocation which may be used | ||
| 24 | * to avoid revealing of sensitive data due to paging etc. | ||
| 25 | * The GNU MP Library itself is published under the LGPL; | ||
| 26 | * however I decided to publish this code under the plain GPL. | ||
| 27 | */ | ||
| 28 | |||
| 29 | #include "mpi-internal.h" | ||
| 30 | #include "longlong.h" | ||
| 31 | |||
| 32 | mpi_limb_t | ||
| 33 | mpihelp_addmul_1(mpi_ptr_t res_ptr, mpi_ptr_t s1_ptr, | ||
| 34 | mpi_size_t s1_size, mpi_limb_t s2_limb) | ||
| 35 | { | ||
| 36 | mpi_limb_t cy_limb; | ||
| 37 | mpi_size_t j; | ||
| 38 | mpi_limb_t prod_high, prod_low; | ||
| 39 | mpi_limb_t x; | ||
| 40 | |||
| 41 | /* The loop counter and index J goes from -SIZE to -1. This way | ||
| 42 | * the loop becomes faster. */ | ||
| 43 | j = -s1_size; | ||
| 44 | res_ptr -= j; | ||
| 45 | s1_ptr -= j; | ||
| 46 | |||
| 47 | cy_limb = 0; | ||
| 48 | do { | ||
| 49 | umul_ppmm(prod_high, prod_low, s1_ptr[j], s2_limb); | ||
| 50 | |||
| 51 | prod_low += cy_limb; | ||
| 52 | cy_limb = (prod_low < cy_limb ? 1 : 0) + prod_high; | ||
| 53 | |||
| 54 | x = res_ptr[j]; | ||
| 55 | prod_low = x + prod_low; | ||
| 56 | cy_limb += prod_low < x ? 1 : 0; | ||
| 57 | res_ptr[j] = prod_low; | ||
| 58 | } while (++j); | ||
| 59 | return cy_limb; | ||
| 60 | } | ||
diff --git a/lib/mpi/generic_mpih-mul3.c b/lib/mpi/generic_mpih-mul3.c new file mode 100644 index 000000000000..f96df327be63 --- /dev/null +++ b/lib/mpi/generic_mpih-mul3.c | |||
| @@ -0,0 +1,61 @@ | |||
| 1 | /* mpihelp-mul_3.c - MPI helper functions | ||
| 2 | * Copyright (C) 1994, 1996, 1997, 1998, 2001 Free Software Foundation, Inc. | ||
| 3 | * | ||
| 4 | * This file is part of GnuPG. | ||
| 5 | * | ||
| 6 | * GnuPG is free software; you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU General Public License as published by | ||
| 8 | * the Free Software Foundation; either version 2 of the License, or | ||
| 9 | * (at your option) any later version. | ||
| 10 | * | ||
| 11 | * GnuPG is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License | ||
| 17 | * along with this program; if not, write to the Free Software | ||
| 18 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA | ||
| 19 | * | ||
| 20 | * Note: This code is heavily based on the GNU MP Library. | ||
| 21 | * Actually it's the same code with only minor changes in the | ||
| 22 | * way the data is stored; this is to support the abstraction | ||
| 23 | * of an optional secure memory allocation which may be used | ||
| 24 | * to avoid revealing of sensitive data due to paging etc. | ||
| 25 | * The GNU MP Library itself is published under the LGPL; | ||
| 26 | * however I decided to publish this code under the plain GPL. | ||
| 27 | */ | ||
| 28 | |||
| 29 | #include "mpi-internal.h" | ||
| 30 | #include "longlong.h" | ||
| 31 | |||
| 32 | mpi_limb_t | ||
| 33 | mpihelp_submul_1(mpi_ptr_t res_ptr, mpi_ptr_t s1_ptr, | ||
| 34 | mpi_size_t s1_size, mpi_limb_t s2_limb) | ||
| 35 | { | ||
| 36 | mpi_limb_t cy_limb; | ||
| 37 | mpi_size_t j; | ||
| 38 | mpi_limb_t prod_high, prod_low; | ||
| 39 | mpi_limb_t x; | ||
| 40 | |||
| 41 | /* The loop counter and index J goes from -SIZE to -1. This way | ||
| 42 | * the loop becomes faster. */ | ||
| 43 | j = -s1_size; | ||
| 44 | res_ptr -= j; | ||
| 45 | s1_ptr -= j; | ||
| 46 | |||
| 47 | cy_limb = 0; | ||
| 48 | do { | ||
| 49 | umul_ppmm(prod_high, prod_low, s1_ptr[j], s2_limb); | ||
| 50 | |||
| 51 | prod_low += cy_limb; | ||
| 52 | cy_limb = (prod_low < cy_limb ? 1 : 0) + prod_high; | ||
| 53 | |||
| 54 | x = res_ptr[j]; | ||
| 55 | prod_low = x - prod_low; | ||
| 56 | cy_limb += prod_low > x ? 1 : 0; | ||
| 57 | res_ptr[j] = prod_low; | ||
| 58 | } while (++j); | ||
| 59 | |||
| 60 | return cy_limb; | ||
| 61 | } | ||
diff --git a/lib/mpi/generic_mpih-rshift.c b/lib/mpi/generic_mpih-rshift.c new file mode 100644 index 000000000000..ffa328818ca6 --- /dev/null +++ b/lib/mpi/generic_mpih-rshift.c | |||
| @@ -0,0 +1,63 @@ | |||
| 1 | /* mpih-rshift.c - MPI helper functions | ||
| 2 | * Copyright (C) 1994, 1996, 1998, 1999, | ||
| 3 | * 2000, 2001 Free Software Foundation, Inc. | ||
| 4 | * | ||
| 5 | * This file is part of GNUPG | ||
| 6 | * | ||
| 7 | * GNUPG is free software; you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU General Public License as published by | ||
| 9 | * the Free Software Foundation; either version 2 of the License, or | ||
| 10 | * (at your option) any later version. | ||
| 11 | * | ||
| 12 | * GNUPG is distributed in the hope that it will be useful, | ||
| 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | * GNU General Public License for more details. | ||
| 16 | * | ||
| 17 | * You should have received a copy of the GNU General Public License | ||
| 18 | * along with this program; if not, write to the Free Software | ||
| 19 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA | ||
| 20 | * | ||
| 21 | * Note: This code is heavily based on the GNU MP Library. | ||
| 22 | * Actually it's the same code with only minor changes in the | ||
| 23 | * way the data is stored; this is to support the abstraction | ||
| 24 | * of an optional secure memory allocation which may be used | ||
| 25 | * to avoid revealing of sensitive data due to paging etc. | ||
| 26 | * The GNU MP Library itself is published under the LGPL; | ||
| 27 | * however I decided to publish this code under the plain GPL. | ||
| 28 | */ | ||
| 29 | |||
| 30 | #include "mpi-internal.h" | ||
| 31 | |||
| 32 | /* Shift U (pointed to by UP and USIZE limbs long) CNT bits to the right | ||
| 33 | * and store the USIZE least significant limbs of the result at WP. | ||
| 34 | * The bits shifted out to the right are returned. | ||
| 35 | * | ||
| 36 | * Argument constraints: | ||
| 37 | * 1. 0 < CNT < BITS_PER_MP_LIMB | ||
| 38 | * 2. If the result is to be written over the input, WP must be <= UP. | ||
| 39 | */ | ||
| 40 | |||
| 41 | mpi_limb_t | ||
| 42 | mpihelp_rshift(mpi_ptr_t wp, mpi_ptr_t up, mpi_size_t usize, unsigned cnt) | ||
| 43 | { | ||
| 44 | mpi_limb_t high_limb, low_limb; | ||
| 45 | unsigned sh_1, sh_2; | ||
| 46 | mpi_size_t i; | ||
| 47 | mpi_limb_t retval; | ||
| 48 | |||
| 49 | sh_1 = cnt; | ||
| 50 | wp -= 1; | ||
| 51 | sh_2 = BITS_PER_MPI_LIMB - sh_1; | ||
| 52 | high_limb = up[0]; | ||
| 53 | retval = high_limb << sh_2; | ||
| 54 | low_limb = high_limb; | ||
| 55 | for (i = 1; i < usize; i++) { | ||
| 56 | high_limb = up[i]; | ||
| 57 | wp[i] = (low_limb >> sh_1) | (high_limb << sh_2); | ||
| 58 | low_limb = high_limb; | ||
| 59 | } | ||
| 60 | wp[i] = low_limb >> sh_1; | ||
| 61 | |||
| 62 | return retval; | ||
| 63 | } | ||
diff --git a/lib/mpi/generic_mpih-sub1.c b/lib/mpi/generic_mpih-sub1.c new file mode 100644 index 000000000000..5d98ab7d6853 --- /dev/null +++ b/lib/mpi/generic_mpih-sub1.c | |||
| @@ -0,0 +1,60 @@ | |||
| 1 | /* mpihelp-add_2.c - MPI helper functions | ||
| 2 | * Copyright (C) 1994, 1996, 1997, 1998, 2001 Free Software Foundation, Inc. | ||
| 3 | * | ||
| 4 | * This file is part of GnuPG. | ||
| 5 | * | ||
| 6 | * GnuPG is free software; you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU General Public License as published by | ||
| 8 | * the Free Software Foundation; either version 2 of the License, or | ||
| 9 | * (at your option) any later version. | ||
| 10 | * | ||
| 11 | * GnuPG is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License | ||
| 17 | * along with this program; if not, write to the Free Software | ||
| 18 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA | ||
| 19 | * | ||
| 20 | * Note: This code is heavily based on the GNU MP Library. | ||
| 21 | * Actually it's the same code with only minor changes in the | ||
| 22 | * way the data is stored; this is to support the abstraction | ||
| 23 | * of an optional secure memory allocation which may be used | ||
| 24 | * to avoid revealing of sensitive data due to paging etc. | ||
| 25 | * The GNU MP Library itself is published under the LGPL; | ||
| 26 | * however I decided to publish this code under the plain GPL. | ||
| 27 | */ | ||
| 28 | |||
| 29 | #include "mpi-internal.h" | ||
| 30 | #include "longlong.h" | ||
| 31 | |||
| 32 | mpi_limb_t | ||
| 33 | mpihelp_sub_n(mpi_ptr_t res_ptr, mpi_ptr_t s1_ptr, | ||
| 34 | mpi_ptr_t s2_ptr, mpi_size_t size) | ||
| 35 | { | ||
| 36 | mpi_limb_t x, y, cy; | ||
| 37 | mpi_size_t j; | ||
| 38 | |||
| 39 | /* The loop counter and index J goes from -SIZE to -1. This way | ||
| 40 | the loop becomes faster. */ | ||
| 41 | j = -size; | ||
| 42 | |||
| 43 | /* Offset the base pointers to compensate for the negative indices. */ | ||
| 44 | s1_ptr -= j; | ||
| 45 | s2_ptr -= j; | ||
| 46 | res_ptr -= j; | ||
| 47 | |||
| 48 | cy = 0; | ||
| 49 | do { | ||
| 50 | y = s2_ptr[j]; | ||
| 51 | x = s1_ptr[j]; | ||
| 52 | y += cy; /* add previous carry to subtrahend */ | ||
| 53 | cy = y < cy; /* get out carry from that addition */ | ||
| 54 | y = x - y; /* main subtract */ | ||
| 55 | cy += y > x; /* get out carry from the subtract, combine */ | ||
| 56 | res_ptr[j] = y; | ||
| 57 | } while (++j); | ||
| 58 | |||
| 59 | return cy; | ||
| 60 | } | ||
diff --git a/lib/mpi/mpi-bit.c b/lib/mpi/mpi-bit.c new file mode 100644 index 000000000000..854c9c6da025 --- /dev/null +++ b/lib/mpi/mpi-bit.c | |||
| @@ -0,0 +1,236 @@ | |||
| 1 | /* mpi-bit.c - MPI bit level fucntions | ||
| 2 | * Copyright (C) 1998, 1999 Free Software Foundation, Inc. | ||
| 3 | * | ||
| 4 | * This file is part of GnuPG. | ||
| 5 | * | ||
| 6 | * GnuPG is free software; you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU General Public License as published by | ||
| 8 | * the Free Software Foundation; either version 2 of the License, or | ||
| 9 | * (at your option) any later version. | ||
| 10 | * | ||
| 11 | * GnuPG is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License | ||
| 17 | * along with this program; if not, write to the Free Software | ||
| 18 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA | ||
| 19 | */ | ||
| 20 | |||
| 21 | #include "mpi-internal.h" | ||
| 22 | #include "longlong.h" | ||
| 23 | |||
| 24 | const unsigned char __clz_tab[] = { | ||
| 25 | 0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, | ||
| 26 | 5, 5, 5, 5, 5, 5, 5, 5, | ||
| 27 | 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, | ||
| 28 | 6, 6, 6, 6, 6, 6, 6, 6, | ||
| 29 | 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, | ||
| 30 | 7, 7, 7, 7, 7, 7, 7, 7, | ||
| 31 | 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, | ||
| 32 | 7, 7, 7, 7, 7, 7, 7, 7, | ||
| 33 | 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, | ||
| 34 | 8, 8, 8, 8, 8, 8, 8, 8, | ||
| 35 | 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, | ||
| 36 | 8, 8, 8, 8, 8, 8, 8, 8, | ||
| 37 | 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, | ||
| 38 | 8, 8, 8, 8, 8, 8, 8, 8, | ||
| 39 | 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, | ||
| 40 | 8, 8, 8, 8, 8, 8, 8, 8, | ||
| 41 | }; | ||
| 42 | |||
| 43 | #define A_LIMB_1 ((mpi_limb_t) 1) | ||
| 44 | |||
| 45 | /**************** | ||
| 46 | * Sometimes we have MSL (most significant limbs) which are 0; | ||
| 47 | * this is for some reasons not good, so this function removes them. | ||
| 48 | */ | ||
| 49 | void mpi_normalize(MPI a) | ||
| 50 | { | ||
| 51 | for (; a->nlimbs && !a->d[a->nlimbs - 1]; a->nlimbs--) | ||
| 52 | ; | ||
| 53 | } | ||
| 54 | |||
| 55 | /**************** | ||
| 56 | * Return the number of bits in A. | ||
| 57 | */ | ||
| 58 | unsigned mpi_get_nbits(MPI a) | ||
| 59 | { | ||
| 60 | unsigned n; | ||
| 61 | |||
| 62 | mpi_normalize(a); | ||
| 63 | |||
| 64 | if (a->nlimbs) { | ||
| 65 | mpi_limb_t alimb = a->d[a->nlimbs - 1]; | ||
| 66 | if (alimb) | ||
| 67 | count_leading_zeros(n, alimb); | ||
| 68 | else | ||
| 69 | n = BITS_PER_MPI_LIMB; | ||
| 70 | n = BITS_PER_MPI_LIMB - n + (a->nlimbs - 1) * BITS_PER_MPI_LIMB; | ||
| 71 | } else | ||
| 72 | n = 0; | ||
| 73 | return n; | ||
| 74 | } | ||
| 75 | EXPORT_SYMBOL_GPL(mpi_get_nbits); | ||
| 76 | |||
| 77 | /**************** | ||
| 78 | * Test whether bit N is set. | ||
| 79 | */ | ||
| 80 | int mpi_test_bit(MPI a, unsigned n) | ||
| 81 | { | ||
| 82 | unsigned limbno, bitno; | ||
| 83 | mpi_limb_t limb; | ||
| 84 | |||
| 85 | limbno = n / BITS_PER_MPI_LIMB; | ||
| 86 | bitno = n % BITS_PER_MPI_LIMB; | ||
| 87 | |||
| 88 | if (limbno >= a->nlimbs) | ||
| 89 | return 0; /* too far left: this is a 0 */ | ||
| 90 | limb = a->d[limbno]; | ||
| 91 | return (limb & (A_LIMB_1 << bitno)) ? 1 : 0; | ||
| 92 | } | ||
| 93 | |||
| 94 | /**************** | ||
| 95 | * Set bit N of A. | ||
| 96 | */ | ||
| 97 | int mpi_set_bit(MPI a, unsigned n) | ||
| 98 | { | ||
| 99 | unsigned limbno, bitno; | ||
| 100 | |||
| 101 | limbno = n / BITS_PER_MPI_LIMB; | ||
| 102 | bitno = n % BITS_PER_MPI_LIMB; | ||
| 103 | |||
| 104 | if (limbno >= a->nlimbs) { /* resize */ | ||
| 105 | if (a->alloced >= limbno) | ||
| 106 | if (mpi_resize(a, limbno + 1) < 0) | ||
| 107 | return -ENOMEM; | ||
| 108 | a->nlimbs = limbno + 1; | ||
| 109 | } | ||
| 110 | a->d[limbno] |= (A_LIMB_1 << bitno); | ||
| 111 | return 0; | ||
| 112 | } | ||
| 113 | |||
| 114 | /**************** | ||
| 115 | * Set bit N of A. and clear all bits above | ||
| 116 | */ | ||
| 117 | int mpi_set_highbit(MPI a, unsigned n) | ||
| 118 | { | ||
| 119 | unsigned limbno, bitno; | ||
| 120 | |||
| 121 | limbno = n / BITS_PER_MPI_LIMB; | ||
| 122 | bitno = n % BITS_PER_MPI_LIMB; | ||
| 123 | |||
| 124 | if (limbno >= a->nlimbs) { /* resize */ | ||
| 125 | if (a->alloced >= limbno) | ||
| 126 | if (mpi_resize(a, limbno + 1) < 0) | ||
| 127 | return -ENOMEM; | ||
| 128 | a->nlimbs = limbno + 1; | ||
| 129 | } | ||
| 130 | a->d[limbno] |= (A_LIMB_1 << bitno); | ||
| 131 | for (bitno++; bitno < BITS_PER_MPI_LIMB; bitno++) | ||
| 132 | a->d[limbno] &= ~(A_LIMB_1 << bitno); | ||
| 133 | a->nlimbs = limbno + 1; | ||
| 134 | return 0; | ||
| 135 | } | ||
| 136 | |||
| 137 | /**************** | ||
| 138 | * clear bit N of A and all bits above | ||
| 139 | */ | ||
| 140 | void mpi_clear_highbit(MPI a, unsigned n) | ||
| 141 | { | ||
| 142 | unsigned limbno, bitno; | ||
| 143 | |||
| 144 | limbno = n / BITS_PER_MPI_LIMB; | ||
| 145 | bitno = n % BITS_PER_MPI_LIMB; | ||
| 146 | |||
| 147 | if (limbno >= a->nlimbs) | ||
| 148 | return; /* not allocated, so need to clear bits :-) */ | ||
| 149 | |||
| 150 | for (; bitno < BITS_PER_MPI_LIMB; bitno++) | ||
| 151 | a->d[limbno] &= ~(A_LIMB_1 << bitno); | ||
| 152 | a->nlimbs = limbno + 1; | ||
| 153 | } | ||
| 154 | |||
| 155 | /**************** | ||
| 156 | * Clear bit N of A. | ||
| 157 | */ | ||
| 158 | void mpi_clear_bit(MPI a, unsigned n) | ||
| 159 | { | ||
| 160 | unsigned limbno, bitno; | ||
| 161 | |||
| 162 | limbno = n / BITS_PER_MPI_LIMB; | ||
| 163 | bitno = n % BITS_PER_MPI_LIMB; | ||
| 164 | |||
| 165 | if (limbno >= a->nlimbs) | ||
| 166 | return; /* don't need to clear this bit, it's to far to left */ | ||
| 167 | a->d[limbno] &= ~(A_LIMB_1 << bitno); | ||
| 168 | } | ||
| 169 | |||
| 170 | /**************** | ||
| 171 | * Shift A by N bits to the right | ||
| 172 | * FIXME: should use alloc_limb if X and A are same. | ||
| 173 | */ | ||
| 174 | int mpi_rshift(MPI x, MPI a, unsigned n) | ||
| 175 | { | ||
| 176 | mpi_ptr_t xp; | ||
| 177 | mpi_size_t xsize; | ||
| 178 | |||
| 179 | xsize = a->nlimbs; | ||
| 180 | x->sign = a->sign; | ||
| 181 | if (RESIZE_IF_NEEDED(x, (size_t) xsize) < 0) | ||
| 182 | return -ENOMEM; | ||
| 183 | xp = x->d; | ||
| 184 | |||
| 185 | if (xsize) { | ||
| 186 | mpihelp_rshift(xp, a->d, xsize, n); | ||
| 187 | MPN_NORMALIZE(xp, xsize); | ||
| 188 | } | ||
| 189 | x->nlimbs = xsize; | ||
| 190 | return 0; | ||
| 191 | } | ||
| 192 | |||
| 193 | /**************** | ||
| 194 | * Shift A by COUNT limbs to the left | ||
| 195 | * This is used only within the MPI library | ||
| 196 | */ | ||
| 197 | int mpi_lshift_limbs(MPI a, unsigned int count) | ||
| 198 | { | ||
| 199 | mpi_ptr_t ap = a->d; | ||
| 200 | int n = a->nlimbs; | ||
| 201 | int i; | ||
| 202 | |||
| 203 | if (!count || !n) | ||
| 204 | return 0; | ||
| 205 | |||
| 206 | if (RESIZE_IF_NEEDED(a, n + count) < 0) | ||
| 207 | return -ENOMEM; | ||
| 208 | |||
| 209 | for (i = n - 1; i >= 0; i--) | ||
| 210 | ap[i + count] = ap[i]; | ||
| 211 | for (i = 0; i < count; i++) | ||
| 212 | ap[i] = 0; | ||
| 213 | a->nlimbs += count; | ||
| 214 | return 0; | ||
| 215 | } | ||
| 216 | |||
| 217 | /**************** | ||
| 218 | * Shift A by COUNT limbs to the right | ||
| 219 | * This is used only within the MPI library | ||
| 220 | */ | ||
| 221 | void mpi_rshift_limbs(MPI a, unsigned int count) | ||
| 222 | { | ||
| 223 | mpi_ptr_t ap = a->d; | ||
| 224 | mpi_size_t n = a->nlimbs; | ||
| 225 | unsigned int i; | ||
| 226 | |||
| 227 | if (count >= n) { | ||
| 228 | a->nlimbs = 0; | ||
| 229 | return; | ||
| 230 | } | ||
| 231 | |||
| 232 | for (i = 0; i < n - count; i++) | ||
| 233 | ap[i] = ap[i + count]; | ||
| 234 | ap[i] = 0; | ||
| 235 | a->nlimbs -= count; | ||
| 236 | } | ||
diff --git a/lib/mpi/mpi-pow.c b/lib/mpi/mpi-pow.c new file mode 100644 index 000000000000..b04a3cf80080 --- /dev/null +++ b/lib/mpi/mpi-pow.c | |||
| @@ -0,0 +1,323 @@ | |||
| 1 | /* mpi-pow.c - MPI functions | ||
| 2 | * Copyright (C) 1994, 1996, 1998, 2000 Free Software Foundation, Inc. | ||
| 3 | * | ||
| 4 | * This file is part of GnuPG. | ||
| 5 | * | ||
| 6 | * GnuPG is free software; you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU General Public License as published by | ||
| 8 | * the Free Software Foundation; either version 2 of the License, or | ||
| 9 | * (at your option) any later version. | ||
| 10 | * | ||
| 11 | * GnuPG is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License | ||
| 17 | * along with this program; if not, write to the Free Software | ||
| 18 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA | ||
| 19 | * | ||
| 20 | * Note: This code is heavily based on the GNU MP Library. | ||
| 21 | * Actually it's the same code with only minor changes in the | ||
| 22 | * way the data is stored; this is to support the abstraction | ||
| 23 | * of an optional secure memory allocation which may be used | ||
| 24 | * to avoid revealing of sensitive data due to paging etc. | ||
| 25 | * The GNU MP Library itself is published under the LGPL; | ||
| 26 | * however I decided to publish this code under the plain GPL. | ||
| 27 | */ | ||
| 28 | |||
| 29 | #include <linux/string.h> | ||
| 30 | #include "mpi-internal.h" | ||
| 31 | #include "longlong.h" | ||
| 32 | |||
| 33 | /**************** | ||
| 34 | * RES = BASE ^ EXP mod MOD | ||
| 35 | */ | ||
| 36 | int mpi_powm(MPI res, MPI base, MPI exp, MPI mod) | ||
| 37 | { | ||
| 38 | mpi_ptr_t mp_marker = NULL, bp_marker = NULL, ep_marker = NULL; | ||
| 39 | mpi_ptr_t xp_marker = NULL; | ||
| 40 | mpi_ptr_t tspace = NULL; | ||
| 41 | mpi_ptr_t rp, ep, mp, bp; | ||
| 42 | mpi_size_t esize, msize, bsize, rsize; | ||
| 43 | int esign, msign, bsign, rsign; | ||
| 44 | mpi_size_t size; | ||
| 45 | int mod_shift_cnt; | ||
| 46 | int negative_result; | ||
| 47 | int assign_rp = 0; | ||
| 48 | mpi_size_t tsize = 0; /* to avoid compiler warning */ | ||
| 49 | /* fixme: we should check that the warning is void */ | ||
| 50 | int rc = -ENOMEM; | ||
| 51 | |||
| 52 | esize = exp->nlimbs; | ||
| 53 | msize = mod->nlimbs; | ||
| 54 | size = 2 * msize; | ||
| 55 | esign = exp->sign; | ||
| 56 | msign = mod->sign; | ||
| 57 | |||
| 58 | rp = res->d; | ||
| 59 | ep = exp->d; | ||
| 60 | |||
| 61 | if (!msize) | ||
| 62 | msize = 1 / msize; /* provoke a signal */ | ||
| 63 | |||
| 64 | if (!esize) { | ||
| 65 | /* Exponent is zero, result is 1 mod MOD, i.e., 1 or 0 | ||
| 66 | * depending on if MOD equals 1. */ | ||
| 67 | rp[0] = 1; | ||
| 68 | res->nlimbs = (msize == 1 && mod->d[0] == 1) ? 0 : 1; | ||
| 69 | res->sign = 0; | ||
| 70 | goto leave; | ||
| 71 | } | ||
| 72 | |||
| 73 | /* Normalize MOD (i.e. make its most significant bit set) as required by | ||
| 74 | * mpn_divrem. This will make the intermediate values in the calculation | ||
| 75 | * slightly larger, but the correct result is obtained after a final | ||
| 76 | * reduction using the original MOD value. */ | ||
| 77 | mp = mp_marker = mpi_alloc_limb_space(msize); | ||
| 78 | if (!mp) | ||
| 79 | goto enomem; | ||
| 80 | count_leading_zeros(mod_shift_cnt, mod->d[msize - 1]); | ||
| 81 | if (mod_shift_cnt) | ||
| 82 | mpihelp_lshift(mp, mod->d, msize, mod_shift_cnt); | ||
| 83 | else | ||
| 84 | MPN_COPY(mp, mod->d, msize); | ||
| 85 | |||
| 86 | bsize = base->nlimbs; | ||
| 87 | bsign = base->sign; | ||
| 88 | if (bsize > msize) { /* The base is larger than the module. Reduce it. */ | ||
| 89 | /* Allocate (BSIZE + 1) with space for remainder and quotient. | ||
| 90 | * (The quotient is (bsize - msize + 1) limbs.) */ | ||
| 91 | bp = bp_marker = mpi_alloc_limb_space(bsize + 1); | ||
| 92 | if (!bp) | ||
| 93 | goto enomem; | ||
| 94 | MPN_COPY(bp, base->d, bsize); | ||
| 95 | /* We don't care about the quotient, store it above the remainder, | ||
| 96 | * at BP + MSIZE. */ | ||
| 97 | mpihelp_divrem(bp + msize, 0, bp, bsize, mp, msize); | ||
| 98 | bsize = msize; | ||
| 99 | /* Canonicalize the base, since we are going to multiply with it | ||
| 100 | * quite a few times. */ | ||
| 101 | MPN_NORMALIZE(bp, bsize); | ||
| 102 | } else | ||
| 103 | bp = base->d; | ||
| 104 | |||
| 105 | if (!bsize) { | ||
| 106 | res->nlimbs = 0; | ||
| 107 | res->sign = 0; | ||
| 108 | goto leave; | ||
| 109 | } | ||
| 110 | |||
| 111 | if (res->alloced < size) { | ||
| 112 | /* We have to allocate more space for RES. If any of the input | ||
| 113 | * parameters are identical to RES, defer deallocation of the old | ||
| 114 | * space. */ | ||
| 115 | if (rp == ep || rp == mp || rp == bp) { | ||
| 116 | rp = mpi_alloc_limb_space(size); | ||
| 117 | if (!rp) | ||
| 118 | goto enomem; | ||
| 119 | assign_rp = 1; | ||
| 120 | } else { | ||
| 121 | if (mpi_resize(res, size) < 0) | ||
| 122 | goto enomem; | ||
| 123 | rp = res->d; | ||
| 124 | } | ||
| 125 | } else { /* Make BASE, EXP and MOD not overlap with RES. */ | ||
| 126 | if (rp == bp) { | ||
| 127 | /* RES and BASE are identical. Allocate temp. space for BASE. */ | ||
| 128 | BUG_ON(bp_marker); | ||
| 129 | bp = bp_marker = mpi_alloc_limb_space(bsize); | ||
| 130 | if (!bp) | ||
| 131 | goto enomem; | ||
| 132 | MPN_COPY(bp, rp, bsize); | ||
| 133 | } | ||
| 134 | if (rp == ep) { | ||
| 135 | /* RES and EXP are identical. Allocate temp. space for EXP. */ | ||
| 136 | ep = ep_marker = mpi_alloc_limb_space(esize); | ||
| 137 | if (!ep) | ||
| 138 | goto enomem; | ||
| 139 | MPN_COPY(ep, rp, esize); | ||
| 140 | } | ||
| 141 | if (rp == mp) { | ||
| 142 | /* RES and MOD are identical. Allocate temporary space for MOD. */ | ||
| 143 | BUG_ON(mp_marker); | ||
| 144 | mp = mp_marker = mpi_alloc_limb_space(msize); | ||
| 145 | if (!mp) | ||
| 146 | goto enomem; | ||
| 147 | MPN_COPY(mp, rp, msize); | ||
| 148 | } | ||
| 149 | } | ||
| 150 | |||
| 151 | MPN_COPY(rp, bp, bsize); | ||
| 152 | rsize = bsize; | ||
| 153 | rsign = bsign; | ||
| 154 | |||
| 155 | { | ||
| 156 | mpi_size_t i; | ||
| 157 | mpi_ptr_t xp; | ||
| 158 | int c; | ||
| 159 | mpi_limb_t e; | ||
| 160 | mpi_limb_t carry_limb; | ||
| 161 | struct karatsuba_ctx karactx; | ||
| 162 | |||
| 163 | xp = xp_marker = mpi_alloc_limb_space(2 * (msize + 1)); | ||
| 164 | if (!xp) | ||
| 165 | goto enomem; | ||
| 166 | |||
| 167 | memset(&karactx, 0, sizeof karactx); | ||
| 168 | negative_result = (ep[0] & 1) && base->sign; | ||
| 169 | |||
| 170 | i = esize - 1; | ||
| 171 | e = ep[i]; | ||
| 172 | count_leading_zeros(c, e); | ||
| 173 | e = (e << c) << 1; /* shift the exp bits to the left, lose msb */ | ||
| 174 | c = BITS_PER_MPI_LIMB - 1 - c; | ||
| 175 | |||
| 176 | /* Main loop. | ||
| 177 | * | ||
| 178 | * Make the result be pointed to alternately by XP and RP. This | ||
| 179 | * helps us avoid block copying, which would otherwise be necessary | ||
| 180 | * with the overlap restrictions of mpihelp_divmod. With 50% probability | ||
| 181 | * the result after this loop will be in the area originally pointed | ||
| 182 | * by RP (==RES->d), and with 50% probability in the area originally | ||
| 183 | * pointed to by XP. | ||
| 184 | */ | ||
| 185 | |||
| 186 | for (;;) { | ||
| 187 | while (c) { | ||
| 188 | mpi_ptr_t tp; | ||
| 189 | mpi_size_t xsize; | ||
| 190 | |||
| 191 | /*if (mpihelp_mul_n(xp, rp, rp, rsize) < 0) goto enomem */ | ||
| 192 | if (rsize < KARATSUBA_THRESHOLD) | ||
| 193 | mpih_sqr_n_basecase(xp, rp, rsize); | ||
| 194 | else { | ||
| 195 | if (!tspace) { | ||
| 196 | tsize = 2 * rsize; | ||
| 197 | tspace = | ||
| 198 | mpi_alloc_limb_space(tsize); | ||
| 199 | if (!tspace) | ||
| 200 | goto enomem; | ||
| 201 | } else if (tsize < (2 * rsize)) { | ||
| 202 | mpi_free_limb_space(tspace); | ||
| 203 | tsize = 2 * rsize; | ||
| 204 | tspace = | ||
| 205 | mpi_alloc_limb_space(tsize); | ||
| 206 | if (!tspace) | ||
| 207 | goto enomem; | ||
| 208 | } | ||
| 209 | mpih_sqr_n(xp, rp, rsize, tspace); | ||
| 210 | } | ||
| 211 | |||
| 212 | xsize = 2 * rsize; | ||
| 213 | if (xsize > msize) { | ||
| 214 | mpihelp_divrem(xp + msize, 0, xp, xsize, | ||
| 215 | mp, msize); | ||
| 216 | xsize = msize; | ||
| 217 | } | ||
| 218 | |||
| 219 | tp = rp; | ||
| 220 | rp = xp; | ||
| 221 | xp = tp; | ||
| 222 | rsize = xsize; | ||
| 223 | |||
| 224 | if ((mpi_limb_signed_t) e < 0) { | ||
| 225 | /*mpihelp_mul( xp, rp, rsize, bp, bsize ); */ | ||
| 226 | if (bsize < KARATSUBA_THRESHOLD) { | ||
| 227 | mpi_limb_t tmp; | ||
| 228 | if (mpihelp_mul | ||
| 229 | (xp, rp, rsize, bp, bsize, | ||
| 230 | &tmp) < 0) | ||
| 231 | goto enomem; | ||
| 232 | } else { | ||
| 233 | if (mpihelp_mul_karatsuba_case | ||
| 234 | (xp, rp, rsize, bp, bsize, | ||
| 235 | &karactx) < 0) | ||
| 236 | goto enomem; | ||
| 237 | } | ||
| 238 | |||
| 239 | xsize = rsize + bsize; | ||
| 240 | if (xsize > msize) { | ||
| 241 | mpihelp_divrem(xp + msize, 0, | ||
| 242 | xp, xsize, mp, | ||
| 243 | msize); | ||
| 244 | xsize = msize; | ||
| 245 | } | ||
| 246 | |||
| 247 | tp = rp; | ||
| 248 | rp = xp; | ||
| 249 | xp = tp; | ||
| 250 | rsize = xsize; | ||
| 251 | } | ||
| 252 | e <<= 1; | ||
| 253 | c--; | ||
| 254 | } | ||
| 255 | |||
| 256 | i--; | ||
| 257 | if (i < 0) | ||
| 258 | break; | ||
| 259 | e = ep[i]; | ||
| 260 | c = BITS_PER_MPI_LIMB; | ||
| 261 | } | ||
| 262 | |||
| 263 | /* We shifted MOD, the modulo reduction argument, left MOD_SHIFT_CNT | ||
| 264 | * steps. Adjust the result by reducing it with the original MOD. | ||
| 265 | * | ||
| 266 | * Also make sure the result is put in RES->d (where it already | ||
| 267 | * might be, see above). | ||
| 268 | */ | ||
| 269 | if (mod_shift_cnt) { | ||
| 270 | carry_limb = | ||
| 271 | mpihelp_lshift(res->d, rp, rsize, mod_shift_cnt); | ||
| 272 | rp = res->d; | ||
| 273 | if (carry_limb) { | ||
| 274 | rp[rsize] = carry_limb; | ||
| 275 | rsize++; | ||
| 276 | } | ||
| 277 | } else { | ||
| 278 | MPN_COPY(res->d, rp, rsize); | ||
| 279 | rp = res->d; | ||
| 280 | } | ||
| 281 | |||
| 282 | if (rsize >= msize) { | ||
| 283 | mpihelp_divrem(rp + msize, 0, rp, rsize, mp, msize); | ||
| 284 | rsize = msize; | ||
| 285 | } | ||
| 286 | |||
| 287 | /* Remove any leading zero words from the result. */ | ||
| 288 | if (mod_shift_cnt) | ||
| 289 | mpihelp_rshift(rp, rp, rsize, mod_shift_cnt); | ||
| 290 | MPN_NORMALIZE(rp, rsize); | ||
| 291 | |||
| 292 | mpihelp_release_karatsuba_ctx(&karactx); | ||
| 293 | } | ||
| 294 | |||
| 295 | if (negative_result && rsize) { | ||
| 296 | if (mod_shift_cnt) | ||
| 297 | mpihelp_rshift(mp, mp, msize, mod_shift_cnt); | ||
| 298 | mpihelp_sub(rp, mp, msize, rp, rsize); | ||
| 299 | rsize = msize; | ||
| 300 | rsign = msign; | ||
| 301 | MPN_NORMALIZE(rp, rsize); | ||
| 302 | } | ||
| 303 | res->nlimbs = rsize; | ||
| 304 | res->sign = rsign; | ||
| 305 | |||
| 306 | leave: | ||
| 307 | rc = 0; | ||
| 308 | enomem: | ||
| 309 | if (assign_rp) | ||
| 310 | mpi_assign_limb_space(res, rp, size); | ||
| 311 | if (mp_marker) | ||
| 312 | mpi_free_limb_space(mp_marker); | ||
| 313 | if (bp_marker) | ||
| 314 | mpi_free_limb_space(bp_marker); | ||
| 315 | if (ep_marker) | ||
| 316 | mpi_free_limb_space(ep_marker); | ||
| 317 | if (xp_marker) | ||
| 318 | mpi_free_limb_space(xp_marker); | ||
| 319 | if (tspace) | ||
| 320 | mpi_free_limb_space(tspace); | ||
| 321 | return rc; | ||
| 322 | } | ||
| 323 | EXPORT_SYMBOL_GPL(mpi_powm); | ||
diff --git a/lib/mpi/mpicoder.c b/lib/mpi/mpicoder.c new file mode 100644 index 000000000000..fe84bb978e3b --- /dev/null +++ b/lib/mpi/mpicoder.c | |||
| @@ -0,0 +1,365 @@ | |||
| 1 | /* mpicoder.c - Coder for the external representation of MPIs | ||
| 2 | * Copyright (C) 1998, 1999 Free Software Foundation, Inc. | ||
| 3 | * | ||
| 4 | * This file is part of GnuPG. | ||
| 5 | * | ||
| 6 | * GnuPG is free software; you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU General Public License as published by | ||
| 8 | * the Free Software Foundation; either version 2 of the License, or | ||
| 9 | * (at your option) any later version. | ||
| 10 | * | ||
| 11 | * GnuPG is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License | ||
| 17 | * along with this program; if not, write to the Free Software | ||
| 18 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA | ||
| 19 | */ | ||
| 20 | |||
| 21 | #include "mpi-internal.h" | ||
| 22 | |||
| 23 | #define DIM(v) (sizeof(v)/sizeof((v)[0])) | ||
| 24 | #define MAX_EXTERN_MPI_BITS 16384 | ||
| 25 | |||
| 26 | static uint8_t asn[15] = /* Object ID is 1.3.14.3.2.26 */ | ||
| 27 | { 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, | ||
| 28 | 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14 | ||
| 29 | }; | ||
| 30 | |||
| 31 | MPI do_encode_md(const void *sha_buffer, unsigned nbits) | ||
| 32 | { | ||
| 33 | int nframe = (nbits + 7) / 8; | ||
| 34 | uint8_t *frame, *fr_pt; | ||
| 35 | int i = 0, n; | ||
| 36 | size_t asnlen = DIM(asn); | ||
| 37 | MPI a = MPI_NULL; | ||
| 38 | |||
| 39 | if (SHA1_DIGEST_LENGTH + asnlen + 4 > nframe) | ||
| 40 | pr_info("MPI: can't encode a %d bit MD into a %d bits frame\n", | ||
| 41 | (int)(SHA1_DIGEST_LENGTH * 8), (int)nbits); | ||
| 42 | |||
| 43 | /* We encode the MD in this way: | ||
| 44 | * | ||
| 45 | * 0 A PAD(n bytes) 0 ASN(asnlen bytes) MD(len bytes) | ||
| 46 | * | ||
| 47 | * PAD consists of FF bytes. | ||
| 48 | */ | ||
| 49 | frame = kmalloc(nframe, GFP_KERNEL); | ||
| 50 | if (!frame) | ||
| 51 | return MPI_NULL; | ||
| 52 | n = 0; | ||
| 53 | frame[n++] = 0; | ||
| 54 | frame[n++] = 1; /* block type */ | ||
| 55 | i = nframe - SHA1_DIGEST_LENGTH - asnlen - 3; | ||
| 56 | |||
| 57 | if (i <= 1) { | ||
| 58 | pr_info("MPI: message digest encoding failed\n"); | ||
| 59 | kfree(frame); | ||
| 60 | return a; | ||
| 61 | } | ||
| 62 | |||
| 63 | memset(frame + n, 0xff, i); | ||
| 64 | n += i; | ||
| 65 | frame[n++] = 0; | ||
| 66 | memcpy(frame + n, &asn, asnlen); | ||
| 67 | n += asnlen; | ||
| 68 | memcpy(frame + n, sha_buffer, SHA1_DIGEST_LENGTH); | ||
| 69 | n += SHA1_DIGEST_LENGTH; | ||
| 70 | |||
| 71 | i = nframe; | ||
| 72 | fr_pt = frame; | ||
| 73 | |||
| 74 | if (n != nframe) { | ||
| 75 | printk | ||
| 76 | ("MPI: message digest encoding failed, frame length is wrong\n"); | ||
| 77 | kfree(frame); | ||
| 78 | return a; | ||
| 79 | } | ||
| 80 | |||
| 81 | a = mpi_alloc((nframe + BYTES_PER_MPI_LIMB - 1) / BYTES_PER_MPI_LIMB); | ||
| 82 | mpi_set_buffer(a, frame, nframe, 0); | ||
| 83 | kfree(frame); | ||
| 84 | |||
| 85 | return a; | ||
| 86 | } | ||
| 87 | |||
| 88 | MPI mpi_read_from_buffer(const void *xbuffer, unsigned *ret_nread) | ||
| 89 | { | ||
| 90 | const uint8_t *buffer = xbuffer; | ||
| 91 | int i, j; | ||
| 92 | unsigned nbits, nbytes, nlimbs, nread = 0; | ||
| 93 | mpi_limb_t a; | ||
| 94 | MPI val = MPI_NULL; | ||
| 95 | |||
| 96 | if (*ret_nread < 2) | ||
| 97 | goto leave; | ||
| 98 | nbits = buffer[0] << 8 | buffer[1]; | ||
| 99 | |||
| 100 | if (nbits > MAX_EXTERN_MPI_BITS) { | ||
| 101 | pr_info("MPI: mpi too large (%u bits)\n", nbits); | ||
| 102 | goto leave; | ||
| 103 | } | ||
| 104 | buffer += 2; | ||
| 105 | nread = 2; | ||
| 106 | |||
| 107 | nbytes = (nbits + 7) / 8; | ||
| 108 | nlimbs = (nbytes + BYTES_PER_MPI_LIMB - 1) / BYTES_PER_MPI_LIMB; | ||
| 109 | val = mpi_alloc(nlimbs); | ||
| 110 | if (!val) | ||
| 111 | return MPI_NULL; | ||
| 112 | i = BYTES_PER_MPI_LIMB - nbytes % BYTES_PER_MPI_LIMB; | ||
| 113 | i %= BYTES_PER_MPI_LIMB; | ||
| 114 | val->nbits = nbits; | ||
| 115 | j = val->nlimbs = nlimbs; | ||
| 116 | val->sign = 0; | ||
| 117 | for (; j > 0; j--) { | ||
| 118 | a = 0; | ||
| 119 | for (; i < BYTES_PER_MPI_LIMB; i++) { | ||
| 120 | if (++nread > *ret_nread) { | ||
| 121 | printk | ||
| 122 | ("MPI: mpi larger than buffer nread=%d ret_nread=%d\n", | ||
| 123 | nread, *ret_nread); | ||
| 124 | goto leave; | ||
| 125 | } | ||
| 126 | a <<= 8; | ||
| 127 | a |= *buffer++; | ||
| 128 | } | ||
| 129 | i = 0; | ||
| 130 | val->d[j - 1] = a; | ||
| 131 | } | ||
| 132 | |||
| 133 | leave: | ||
| 134 | *ret_nread = nread; | ||
| 135 | return val; | ||
| 136 | } | ||
| 137 | EXPORT_SYMBOL_GPL(mpi_read_from_buffer); | ||
| 138 | |||
| 139 | /**************** | ||
| 140 | * Make an mpi from a character string. | ||
| 141 | */ | ||
| 142 | int mpi_fromstr(MPI val, const char *str) | ||
| 143 | { | ||
| 144 | int hexmode = 0, sign = 0, prepend_zero = 0, i, j, c, c1, c2; | ||
| 145 | unsigned nbits, nbytes, nlimbs; | ||
| 146 | mpi_limb_t a; | ||
| 147 | |||
| 148 | if (*str == '-') { | ||
| 149 | sign = 1; | ||
| 150 | str++; | ||
| 151 | } | ||
| 152 | if (*str == '0' && str[1] == 'x') | ||
| 153 | hexmode = 1; | ||
| 154 | else | ||
| 155 | return -EINVAL; /* other bases are not yet supported */ | ||
| 156 | str += 2; | ||
| 157 | |||
| 158 | nbits = strlen(str) * 4; | ||
| 159 | if (nbits % 8) | ||
| 160 | prepend_zero = 1; | ||
| 161 | nbytes = (nbits + 7) / 8; | ||
| 162 | nlimbs = (nbytes + BYTES_PER_MPI_LIMB - 1) / BYTES_PER_MPI_LIMB; | ||
| 163 | if (val->alloced < nlimbs) | ||
| 164 | if (!mpi_resize(val, nlimbs)) | ||
| 165 | return -ENOMEM; | ||
| 166 | i = BYTES_PER_MPI_LIMB - nbytes % BYTES_PER_MPI_LIMB; | ||
| 167 | i %= BYTES_PER_MPI_LIMB; | ||
| 168 | j = val->nlimbs = nlimbs; | ||
| 169 | val->sign = sign; | ||
| 170 | for (; j > 0; j--) { | ||
| 171 | a = 0; | ||
| 172 | for (; i < BYTES_PER_MPI_LIMB; i++) { | ||
| 173 | if (prepend_zero) { | ||
| 174 | c1 = '0'; | ||
| 175 | prepend_zero = 0; | ||
| 176 | } else | ||
| 177 | c1 = *str++; | ||
| 178 | assert(c1); | ||
| 179 | c2 = *str++; | ||
| 180 | assert(c2); | ||
| 181 | if (c1 >= '0' && c1 <= '9') | ||
| 182 | c = c1 - '0'; | ||
| 183 | else if (c1 >= 'a' && c1 <= 'f') | ||
| 184 | c = c1 - 'a' + 10; | ||
| 185 | else if (c1 >= 'A' && c1 <= 'F') | ||
| 186 | c = c1 - 'A' + 10; | ||
| 187 | else { | ||
| 188 | mpi_clear(val); | ||
| 189 | return 1; | ||
| 190 | } | ||
| 191 | c <<= 4; | ||
| 192 | if (c2 >= '0' && c2 <= '9') | ||
| 193 | c |= c2 - '0'; | ||
| 194 | else if (c2 >= 'a' && c2 <= 'f') | ||
| 195 | c |= c2 - 'a' + 10; | ||
| 196 | else if (c2 >= 'A' && c2 <= 'F') | ||
| 197 | c |= c2 - 'A' + 10; | ||
| 198 | else { | ||
| 199 | mpi_clear(val); | ||
| 200 | return 1; | ||
| 201 | } | ||
| 202 | a <<= 8; | ||
| 203 | a |= c; | ||
| 204 | } | ||
| 205 | i = 0; | ||
| 206 | |||
| 207 | val->d[j - 1] = a; | ||
| 208 | } | ||
| 209 | |||
| 210 | return 0; | ||
| 211 | } | ||
| 212 | EXPORT_SYMBOL_GPL(mpi_fromstr); | ||
| 213 | |||
| 214 | /**************** | ||
| 215 | * Special function to get the low 8 bytes from an mpi. | ||
| 216 | * This can be used as a keyid; KEYID is an 2 element array. | ||
| 217 | * Return the low 4 bytes. | ||
| 218 | */ | ||
| 219 | u32 mpi_get_keyid(const MPI a, u32 *keyid) | ||
| 220 | { | ||
| 221 | #if BYTES_PER_MPI_LIMB == 4 | ||
| 222 | if (keyid) { | ||
| 223 | keyid[0] = a->nlimbs >= 2 ? a->d[1] : 0; | ||
| 224 | keyid[1] = a->nlimbs >= 1 ? a->d[0] : 0; | ||
| 225 | } | ||
| 226 | return a->nlimbs >= 1 ? a->d[0] : 0; | ||
| 227 | #elif BYTES_PER_MPI_LIMB == 8 | ||
| 228 | if (keyid) { | ||
| 229 | keyid[0] = a->nlimbs ? (u32) (a->d[0] >> 32) : 0; | ||
| 230 | keyid[1] = a->nlimbs ? (u32) (a->d[0] & 0xffffffff) : 0; | ||
| 231 | } | ||
| 232 | return a->nlimbs ? (u32) (a->d[0] & 0xffffffff) : 0; | ||
| 233 | #else | ||
| 234 | #error Make this function work with other LIMB sizes | ||
| 235 | #endif | ||
| 236 | } | ||
| 237 | |||
| 238 | /**************** | ||
| 239 | * Return an allocated buffer with the MPI (msb first). | ||
| 240 | * NBYTES receives the length of this buffer. Caller must free the | ||
| 241 | * return string (This function does return a 0 byte buffer with NBYTES | ||
| 242 | * set to zero if the value of A is zero. If sign is not NULL, it will | ||
| 243 | * be set to the sign of the A. | ||
| 244 | */ | ||
| 245 | void *mpi_get_buffer(MPI a, unsigned *nbytes, int *sign) | ||
| 246 | { | ||
| 247 | uint8_t *p, *buffer; | ||
| 248 | mpi_limb_t alimb; | ||
| 249 | int i; | ||
| 250 | unsigned int n; | ||
| 251 | |||
| 252 | if (sign) | ||
| 253 | *sign = a->sign; | ||
| 254 | *nbytes = n = a->nlimbs * BYTES_PER_MPI_LIMB; | ||
| 255 | if (!n) | ||
| 256 | n++; /* avoid zero length allocation */ | ||
| 257 | p = buffer = kmalloc(n, GFP_KERNEL); | ||
| 258 | |||
| 259 | for (i = a->nlimbs - 1; i >= 0; i--) { | ||
| 260 | alimb = a->d[i]; | ||
| 261 | #if BYTES_PER_MPI_LIMB == 4 | ||
| 262 | *p++ = alimb >> 24; | ||
| 263 | *p++ = alimb >> 16; | ||
| 264 | *p++ = alimb >> 8; | ||
| 265 | *p++ = alimb; | ||
| 266 | #elif BYTES_PER_MPI_LIMB == 8 | ||
| 267 | *p++ = alimb >> 56; | ||
| 268 | *p++ = alimb >> 48; | ||
| 269 | *p++ = alimb >> 40; | ||
| 270 | *p++ = alimb >> 32; | ||
| 271 | *p++ = alimb >> 24; | ||
| 272 | *p++ = alimb >> 16; | ||
| 273 | *p++ = alimb >> 8; | ||
| 274 | *p++ = alimb; | ||
| 275 | #else | ||
| 276 | #error please implement for this limb size. | ||
| 277 | #endif | ||
| 278 | } | ||
| 279 | |||
| 280 | /* this is sub-optimal but we need to do the shift operation | ||
| 281 | * because the caller has to free the returned buffer */ | ||
| 282 | for (p = buffer; !*p && *nbytes; p++, --*nbytes) | ||
| 283 | ; | ||
| 284 | if (p != buffer) | ||
| 285 | memmove(buffer, p, *nbytes); | ||
| 286 | |||
| 287 | return buffer; | ||
| 288 | } | ||
| 289 | EXPORT_SYMBOL_GPL(mpi_get_buffer); | ||
| 290 | |||
| 291 | /**************** | ||
| 292 | * Use BUFFER to update MPI. | ||
| 293 | */ | ||
| 294 | int mpi_set_buffer(MPI a, const void *xbuffer, unsigned nbytes, int sign) | ||
| 295 | { | ||
| 296 | const uint8_t *buffer = xbuffer, *p; | ||
| 297 | mpi_limb_t alimb; | ||
| 298 | int nlimbs; | ||
| 299 | int i; | ||
| 300 | |||
| 301 | nlimbs = (nbytes + BYTES_PER_MPI_LIMB - 1) / BYTES_PER_MPI_LIMB; | ||
| 302 | if (RESIZE_IF_NEEDED(a, nlimbs) < 0) | ||
| 303 | return -ENOMEM; | ||
| 304 | a->sign = sign; | ||
| 305 | |||
| 306 | for (i = 0, p = buffer + nbytes - 1; p >= buffer + BYTES_PER_MPI_LIMB;) { | ||
| 307 | #if BYTES_PER_MPI_LIMB == 4 | ||
| 308 | alimb = (mpi_limb_t) *p--; | ||
| 309 | alimb |= (mpi_limb_t) *p-- << 8; | ||
| 310 | alimb |= (mpi_limb_t) *p-- << 16; | ||
| 311 | alimb |= (mpi_limb_t) *p-- << 24; | ||
| 312 | #elif BYTES_PER_MPI_LIMB == 8 | ||
| 313 | alimb = (mpi_limb_t) *p--; | ||
| 314 | alimb |= (mpi_limb_t) *p-- << 8; | ||
| 315 | alimb |= (mpi_limb_t) *p-- << 16; | ||
| 316 | alimb |= (mpi_limb_t) *p-- << 24; | ||
| 317 | alimb |= (mpi_limb_t) *p-- << 32; | ||
| 318 | alimb |= (mpi_limb_t) *p-- << 40; | ||
| 319 | alimb |= (mpi_limb_t) *p-- << 48; | ||
| 320 | alimb |= (mpi_limb_t) *p-- << 56; | ||
| 321 | #else | ||
| 322 | #error please implement for this limb size. | ||
| 323 | #endif | ||
| 324 | a->d[i++] = alimb; | ||
| 325 | } | ||
| 326 | if (p >= buffer) { | ||
| 327 | #if BYTES_PER_MPI_LIMB == 4 | ||
| 328 | alimb = *p--; | ||
| 329 | if (p >= buffer) | ||
| 330 | alimb |= (mpi_limb_t) *p-- << 8; | ||
| 331 | if (p >= buffer) | ||
| 332 | alimb |= (mpi_limb_t) *p-- << 16; | ||
| 333 | if (p >= buffer) | ||
| 334 | alimb |= (mpi_limb_t) *p-- << 24; | ||
| 335 | #elif BYTES_PER_MPI_LIMB == 8 | ||
| 336 | alimb = (mpi_limb_t) *p--; | ||
| 337 | if (p >= buffer) | ||
| 338 | alimb |= (mpi_limb_t) *p-- << 8; | ||
| 339 | if (p >= buffer) | ||
| 340 | alimb |= (mpi_limb_t) *p-- << 16; | ||
| 341 | if (p >= buffer) | ||
| 342 | alimb |= (mpi_limb_t) *p-- << 24; | ||
| 343 | if (p >= buffer) | ||
| 344 | alimb |= (mpi_limb_t) *p-- << 32; | ||
| 345 | if (p >= buffer) | ||
| 346 | alimb |= (mpi_limb_t) *p-- << 40; | ||
| 347 | if (p >= buffer) | ||
| 348 | alimb |= (mpi_limb_t) *p-- << 48; | ||
| 349 | if (p >= buffer) | ||
| 350 | alimb |= (mpi_limb_t) *p-- << 56; | ||
| 351 | #else | ||
| 352 | #error please implement for this limb size. | ||
| 353 | #endif | ||
| 354 | a->d[i++] = alimb; | ||
| 355 | } | ||
| 356 | a->nlimbs = i; | ||
| 357 | |||
| 358 | if (i != nlimbs) { | ||
| 359 | pr_emerg("MPI: mpi_set_buffer: Assertion failed (%d != %d)", i, | ||
| 360 | nlimbs); | ||
| 361 | BUG(); | ||
| 362 | } | ||
| 363 | return 0; | ||
| 364 | } | ||
| 365 | EXPORT_SYMBOL_GPL(mpi_set_buffer); | ||
diff --git a/lib/mpi/mpih-cmp.c b/lib/mpi/mpih-cmp.c new file mode 100644 index 000000000000..b2fd39677f1b --- /dev/null +++ b/lib/mpi/mpih-cmp.c | |||
| @@ -0,0 +1,56 @@ | |||
| 1 | /* mpihelp-sub.c - MPI helper functions | ||
| 2 | * Copyright (C) 1994, 1996 Free Software Foundation, Inc. | ||
| 3 | * Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc. | ||
| 4 | * | ||
| 5 | * This file is part of GnuPG. | ||
| 6 | * | ||
| 7 | * GnuPG is free software; you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU General Public License as published by | ||
| 9 | * the Free Software Foundation; either version 2 of the License, or | ||
| 10 | * (at your option) any later version. | ||
| 11 | * | ||
| 12 | * GnuPG is distributed in the hope that it will be useful, | ||
| 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | * GNU General Public License for more details. | ||
| 16 | * | ||
| 17 | * You should have received a copy of the GNU General Public License | ||
| 18 | * along with this program; if not, write to the Free Software | ||
| 19 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA | ||
| 20 | * | ||
| 21 | * Note: This code is heavily based on the GNU MP Library. | ||
| 22 | * Actually it's the same code with only minor changes in the | ||
| 23 | * way the data is stored; this is to support the abstraction | ||
| 24 | * of an optional secure memory allocation which may be used | ||
| 25 | * to avoid revealing of sensitive data due to paging etc. | ||
| 26 | * The GNU MP Library itself is published under the LGPL; | ||
| 27 | * however I decided to publish this code under the plain GPL. | ||
| 28 | */ | ||
| 29 | |||
| 30 | #include "mpi-internal.h" | ||
| 31 | |||
| 32 | /**************** | ||
| 33 | * Compare OP1_PTR/OP1_SIZE with OP2_PTR/OP2_SIZE. | ||
| 34 | * There are no restrictions on the relative sizes of | ||
| 35 | * the two arguments. | ||
| 36 | * Return 1 if OP1 > OP2, 0 if they are equal, and -1 if OP1 < OP2. | ||
| 37 | */ | ||
| 38 | int mpihelp_cmp(mpi_ptr_t op1_ptr, mpi_ptr_t op2_ptr, mpi_size_t size) | ||
| 39 | { | ||
| 40 | mpi_size_t i; | ||
| 41 | mpi_limb_t op1_word, op2_word; | ||
| 42 | |||
| 43 | for (i = size - 1; i >= 0; i--) { | ||
| 44 | op1_word = op1_ptr[i]; | ||
| 45 | op2_word = op2_ptr[i]; | ||
| 46 | if (op1_word != op2_word) | ||
| 47 | goto diff; | ||
| 48 | } | ||
| 49 | return 0; | ||
| 50 | |||
| 51 | diff: | ||
| 52 | /* This can *not* be simplified to | ||
| 53 | * op2_word - op2_word | ||
| 54 | * since that expression might give signed overflow. */ | ||
| 55 | return (op1_word > op2_word) ? 1 : -1; | ||
| 56 | } | ||
diff --git a/lib/mpi/mpih-div.c b/lib/mpi/mpih-div.c new file mode 100644 index 000000000000..87ede162dfab --- /dev/null +++ b/lib/mpi/mpih-div.c | |||
| @@ -0,0 +1,541 @@ | |||
| 1 | /* mpihelp-div.c - MPI helper functions | ||
| 2 | * Copyright (C) 1994, 1996 Free Software Foundation, Inc. | ||
| 3 | * Copyright (C) 1998, 1999 Free Software Foundation, Inc. | ||
| 4 | * | ||
| 5 | * This file is part of GnuPG. | ||
| 6 | * | ||
| 7 | * GnuPG is free software; you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU General Public License as published by | ||
| 9 | * the Free Software Foundation; either version 2 of the License, or | ||
| 10 | * (at your option) any later version. | ||
| 11 | * | ||
| 12 | * GnuPG is distributed in the hope that it will be useful, | ||
| 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | * GNU General Public License for more details. | ||
| 16 | * | ||
| 17 | * You should have received a copy of the GNU General Public License | ||
| 18 | * along with this program; if not, write to the Free Software | ||
| 19 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA | ||
| 20 | * | ||
| 21 | * Note: This code is heavily based on the GNU MP Library. | ||
| 22 | * Actually it's the same code with only minor changes in the | ||
| 23 | * way the data is stored; this is to support the abstraction | ||
| 24 | * of an optional secure memory allocation which may be used | ||
| 25 | * to avoid revealing of sensitive data due to paging etc. | ||
| 26 | * The GNU MP Library itself is published under the LGPL; | ||
| 27 | * however I decided to publish this code under the plain GPL. | ||
| 28 | */ | ||
| 29 | |||
| 30 | #include "mpi-internal.h" | ||
| 31 | #include "longlong.h" | ||
| 32 | |||
| 33 | #ifndef UMUL_TIME | ||
| 34 | #define UMUL_TIME 1 | ||
| 35 | #endif | ||
| 36 | #ifndef UDIV_TIME | ||
| 37 | #define UDIV_TIME UMUL_TIME | ||
| 38 | #endif | ||
| 39 | |||
| 40 | /* FIXME: We should be using invert_limb (or invert_normalized_limb) | ||
| 41 | * here (not udiv_qrnnd). | ||
| 42 | */ | ||
| 43 | |||
| 44 | mpi_limb_t | ||
| 45 | mpihelp_mod_1(mpi_ptr_t dividend_ptr, mpi_size_t dividend_size, | ||
| 46 | mpi_limb_t divisor_limb) | ||
| 47 | { | ||
| 48 | mpi_size_t i; | ||
| 49 | mpi_limb_t n1, n0, r; | ||
| 50 | int dummy; | ||
| 51 | |||
| 52 | /* Botch: Should this be handled at all? Rely on callers? */ | ||
| 53 | if (!dividend_size) | ||
| 54 | return 0; | ||
| 55 | |||
| 56 | /* If multiplication is much faster than division, and the | ||
| 57 | * dividend is large, pre-invert the divisor, and use | ||
| 58 | * only multiplications in the inner loop. | ||
| 59 | * | ||
| 60 | * This test should be read: | ||
| 61 | * Does it ever help to use udiv_qrnnd_preinv? | ||
| 62 | * && Does what we save compensate for the inversion overhead? | ||
| 63 | */ | ||
| 64 | if (UDIV_TIME > (2 * UMUL_TIME + 6) | ||
| 65 | && (UDIV_TIME - (2 * UMUL_TIME + 6)) * dividend_size > UDIV_TIME) { | ||
| 66 | int normalization_steps; | ||
| 67 | |||
| 68 | count_leading_zeros(normalization_steps, divisor_limb); | ||
| 69 | if (normalization_steps) { | ||
| 70 | mpi_limb_t divisor_limb_inverted; | ||
| 71 | |||
| 72 | divisor_limb <<= normalization_steps; | ||
| 73 | |||
| 74 | /* Compute (2**2N - 2**N * DIVISOR_LIMB) / DIVISOR_LIMB. The | ||
| 75 | * result is a (N+1)-bit approximation to 1/DIVISOR_LIMB, with the | ||
| 76 | * most significant bit (with weight 2**N) implicit. | ||
| 77 | * | ||
| 78 | * Special case for DIVISOR_LIMB == 100...000. | ||
| 79 | */ | ||
| 80 | if (!(divisor_limb << 1)) | ||
| 81 | divisor_limb_inverted = ~(mpi_limb_t) 0; | ||
| 82 | else | ||
| 83 | udiv_qrnnd(divisor_limb_inverted, dummy, | ||
| 84 | -divisor_limb, 0, divisor_limb); | ||
| 85 | |||
| 86 | n1 = dividend_ptr[dividend_size - 1]; | ||
| 87 | r = n1 >> (BITS_PER_MPI_LIMB - normalization_steps); | ||
| 88 | |||
| 89 | /* Possible optimization: | ||
| 90 | * if (r == 0 | ||
| 91 | * && divisor_limb > ((n1 << normalization_steps) | ||
| 92 | * | (dividend_ptr[dividend_size - 2] >> ...))) | ||
| 93 | * ...one division less... | ||
| 94 | */ | ||
| 95 | for (i = dividend_size - 2; i >= 0; i--) { | ||
| 96 | n0 = dividend_ptr[i]; | ||
| 97 | UDIV_QRNND_PREINV(dummy, r, r, | ||
| 98 | ((n1 << normalization_steps) | ||
| 99 | | (n0 >> | ||
| 100 | (BITS_PER_MPI_LIMB - | ||
| 101 | normalization_steps))), | ||
| 102 | divisor_limb, | ||
| 103 | divisor_limb_inverted); | ||
| 104 | n1 = n0; | ||
| 105 | } | ||
| 106 | UDIV_QRNND_PREINV(dummy, r, r, | ||
| 107 | n1 << normalization_steps, | ||
| 108 | divisor_limb, divisor_limb_inverted); | ||
| 109 | return r >> normalization_steps; | ||
| 110 | } else { | ||
| 111 | mpi_limb_t divisor_limb_inverted; | ||
| 112 | |||
| 113 | /* Compute (2**2N - 2**N * DIVISOR_LIMB) / DIVISOR_LIMB. The | ||
| 114 | * result is a (N+1)-bit approximation to 1/DIVISOR_LIMB, with the | ||
| 115 | * most significant bit (with weight 2**N) implicit. | ||
| 116 | * | ||
| 117 | * Special case for DIVISOR_LIMB == 100...000. | ||
| 118 | */ | ||
| 119 | if (!(divisor_limb << 1)) | ||
| 120 | divisor_limb_inverted = ~(mpi_limb_t) 0; | ||
| 121 | else | ||
| 122 | udiv_qrnnd(divisor_limb_inverted, dummy, | ||
| 123 | -divisor_limb, 0, divisor_limb); | ||
| 124 | |||
| 125 | i = dividend_size - 1; | ||
| 126 | r = dividend_ptr[i]; | ||
| 127 | |||
| 128 | if (r >= divisor_limb) | ||
| 129 | r = 0; | ||
| 130 | else | ||
| 131 | i--; | ||
| 132 | |||
| 133 | for (; i >= 0; i--) { | ||
| 134 | n0 = dividend_ptr[i]; | ||
| 135 | UDIV_QRNND_PREINV(dummy, r, r, | ||
| 136 | n0, divisor_limb, | ||
| 137 | divisor_limb_inverted); | ||
| 138 | } | ||
| 139 | return r; | ||
| 140 | } | ||
| 141 | } else { | ||
| 142 | if (UDIV_NEEDS_NORMALIZATION) { | ||
| 143 | int normalization_steps; | ||
| 144 | |||
| 145 | count_leading_zeros(normalization_steps, divisor_limb); | ||
| 146 | if (normalization_steps) { | ||
| 147 | divisor_limb <<= normalization_steps; | ||
| 148 | |||
| 149 | n1 = dividend_ptr[dividend_size - 1]; | ||
| 150 | r = n1 >> (BITS_PER_MPI_LIMB - | ||
| 151 | normalization_steps); | ||
| 152 | |||
| 153 | /* Possible optimization: | ||
| 154 | * if (r == 0 | ||
| 155 | * && divisor_limb > ((n1 << normalization_steps) | ||
| 156 | * | (dividend_ptr[dividend_size - 2] >> ...))) | ||
| 157 | * ...one division less... | ||
| 158 | */ | ||
| 159 | for (i = dividend_size - 2; i >= 0; i--) { | ||
| 160 | n0 = dividend_ptr[i]; | ||
| 161 | udiv_qrnnd(dummy, r, r, | ||
| 162 | ((n1 << normalization_steps) | ||
| 163 | | (n0 >> | ||
| 164 | (BITS_PER_MPI_LIMB - | ||
| 165 | normalization_steps))), | ||
| 166 | divisor_limb); | ||
| 167 | n1 = n0; | ||
| 168 | } | ||
| 169 | udiv_qrnnd(dummy, r, r, | ||
| 170 | n1 << normalization_steps, | ||
| 171 | divisor_limb); | ||
| 172 | return r >> normalization_steps; | ||
| 173 | } | ||
| 174 | } | ||
| 175 | /* No normalization needed, either because udiv_qrnnd doesn't require | ||
| 176 | * it, or because DIVISOR_LIMB is already normalized. */ | ||
| 177 | i = dividend_size - 1; | ||
| 178 | r = dividend_ptr[i]; | ||
| 179 | |||
| 180 | if (r >= divisor_limb) | ||
| 181 | r = 0; | ||
| 182 | else | ||
| 183 | i--; | ||
| 184 | |||
| 185 | for (; i >= 0; i--) { | ||
| 186 | n0 = dividend_ptr[i]; | ||
| 187 | udiv_qrnnd(dummy, r, r, n0, divisor_limb); | ||
| 188 | } | ||
| 189 | return r; | ||
| 190 | } | ||
| 191 | } | ||
| 192 | |||
| 193 | /* Divide num (NP/NSIZE) by den (DP/DSIZE) and write | ||
| 194 | * the NSIZE-DSIZE least significant quotient limbs at QP | ||
| 195 | * and the DSIZE long remainder at NP. If QEXTRA_LIMBS is | ||
| 196 | * non-zero, generate that many fraction bits and append them after the | ||
| 197 | * other quotient limbs. | ||
| 198 | * Return the most significant limb of the quotient, this is always 0 or 1. | ||
| 199 | * | ||
| 200 | * Preconditions: | ||
| 201 | * 0. NSIZE >= DSIZE. | ||
| 202 | * 1. The most significant bit of the divisor must be set. | ||
| 203 | * 2. QP must either not overlap with the input operands at all, or | ||
| 204 | * QP + DSIZE >= NP must hold true. (This means that it's | ||
| 205 | * possible to put the quotient in the high part of NUM, right after the | ||
| 206 | * remainder in NUM. | ||
| 207 | * 3. NSIZE >= DSIZE, even if QEXTRA_LIMBS is non-zero. | ||
| 208 | */ | ||
| 209 | |||
| 210 | mpi_limb_t | ||
| 211 | mpihelp_divrem(mpi_ptr_t qp, mpi_size_t qextra_limbs, | ||
| 212 | mpi_ptr_t np, mpi_size_t nsize, mpi_ptr_t dp, mpi_size_t dsize) | ||
| 213 | { | ||
| 214 | mpi_limb_t most_significant_q_limb = 0; | ||
| 215 | |||
| 216 | switch (dsize) { | ||
| 217 | case 0: | ||
| 218 | /* We are asked to divide by zero, so go ahead and do it! (To make | ||
| 219 | the compiler not remove this statement, return the value.) */ | ||
| 220 | return 1 / dsize; | ||
| 221 | |||
| 222 | case 1: | ||
| 223 | { | ||
| 224 | mpi_size_t i; | ||
| 225 | mpi_limb_t n1; | ||
| 226 | mpi_limb_t d; | ||
| 227 | |||
| 228 | d = dp[0]; | ||
| 229 | n1 = np[nsize - 1]; | ||
| 230 | |||
| 231 | if (n1 >= d) { | ||
| 232 | n1 -= d; | ||
| 233 | most_significant_q_limb = 1; | ||
| 234 | } | ||
| 235 | |||
| 236 | qp += qextra_limbs; | ||
| 237 | for (i = nsize - 2; i >= 0; i--) | ||
| 238 | udiv_qrnnd(qp[i], n1, n1, np[i], d); | ||
| 239 | qp -= qextra_limbs; | ||
| 240 | |||
| 241 | for (i = qextra_limbs - 1; i >= 0; i--) | ||
| 242 | udiv_qrnnd(qp[i], n1, n1, 0, d); | ||
| 243 | |||
| 244 | np[0] = n1; | ||
| 245 | } | ||
| 246 | break; | ||
| 247 | |||
| 248 | case 2: | ||
| 249 | { | ||
| 250 | mpi_size_t i; | ||
| 251 | mpi_limb_t n1, n0, n2; | ||
| 252 | mpi_limb_t d1, d0; | ||
| 253 | |||
| 254 | np += nsize - 2; | ||
| 255 | d1 = dp[1]; | ||
| 256 | d0 = dp[0]; | ||
| 257 | n1 = np[1]; | ||
| 258 | n0 = np[0]; | ||
| 259 | |||
| 260 | if (n1 >= d1 && (n1 > d1 || n0 >= d0)) { | ||
| 261 | sub_ddmmss(n1, n0, n1, n0, d1, d0); | ||
| 262 | most_significant_q_limb = 1; | ||
| 263 | } | ||
| 264 | |||
| 265 | for (i = qextra_limbs + nsize - 2 - 1; i >= 0; i--) { | ||
| 266 | mpi_limb_t q; | ||
| 267 | mpi_limb_t r; | ||
| 268 | |||
| 269 | if (i >= qextra_limbs) | ||
| 270 | np--; | ||
| 271 | else | ||
| 272 | np[0] = 0; | ||
| 273 | |||
| 274 | if (n1 == d1) { | ||
| 275 | /* Q should be either 111..111 or 111..110. Need special | ||
| 276 | * treatment of this rare case as normal division would | ||
| 277 | * give overflow. */ | ||
| 278 | q = ~(mpi_limb_t) 0; | ||
| 279 | |||
| 280 | r = n0 + d1; | ||
| 281 | if (r < d1) { /* Carry in the addition? */ | ||
| 282 | add_ssaaaa(n1, n0, r - d0, | ||
| 283 | np[0], 0, d0); | ||
| 284 | qp[i] = q; | ||
| 285 | continue; | ||
| 286 | } | ||
| 287 | n1 = d0 - (d0 != 0 ? 1 : 0); | ||
| 288 | n0 = -d0; | ||
| 289 | } else { | ||
| 290 | udiv_qrnnd(q, r, n1, n0, d1); | ||
| 291 | umul_ppmm(n1, n0, d0, q); | ||
| 292 | } | ||
| 293 | |||
| 294 | n2 = np[0]; | ||
| 295 | q_test: | ||
| 296 | if (n1 > r || (n1 == r && n0 > n2)) { | ||
| 297 | /* The estimated Q was too large. */ | ||
| 298 | q--; | ||
| 299 | sub_ddmmss(n1, n0, n1, n0, 0, d0); | ||
| 300 | r += d1; | ||
| 301 | if (r >= d1) /* If not carry, test Q again. */ | ||
| 302 | goto q_test; | ||
| 303 | } | ||
| 304 | |||
| 305 | qp[i] = q; | ||
| 306 | sub_ddmmss(n1, n0, r, n2, n1, n0); | ||
| 307 | } | ||
| 308 | np[1] = n1; | ||
| 309 | np[0] = n0; | ||
| 310 | } | ||
| 311 | break; | ||
| 312 | |||
| 313 | default: | ||
| 314 | { | ||
| 315 | mpi_size_t i; | ||
| 316 | mpi_limb_t dX, d1, n0; | ||
| 317 | |||
| 318 | np += nsize - dsize; | ||
| 319 | dX = dp[dsize - 1]; | ||
| 320 | d1 = dp[dsize - 2]; | ||
| 321 | n0 = np[dsize - 1]; | ||
| 322 | |||
| 323 | if (n0 >= dX) { | ||
| 324 | if (n0 > dX | ||
| 325 | || mpihelp_cmp(np, dp, dsize - 1) >= 0) { | ||
| 326 | mpihelp_sub_n(np, np, dp, dsize); | ||
| 327 | n0 = np[dsize - 1]; | ||
| 328 | most_significant_q_limb = 1; | ||
| 329 | } | ||
| 330 | } | ||
| 331 | |||
| 332 | for (i = qextra_limbs + nsize - dsize - 1; i >= 0; i--) { | ||
| 333 | mpi_limb_t q; | ||
| 334 | mpi_limb_t n1, n2; | ||
| 335 | mpi_limb_t cy_limb; | ||
| 336 | |||
| 337 | if (i >= qextra_limbs) { | ||
| 338 | np--; | ||
| 339 | n2 = np[dsize]; | ||
| 340 | } else { | ||
| 341 | n2 = np[dsize - 1]; | ||
| 342 | MPN_COPY_DECR(np + 1, np, dsize - 1); | ||
| 343 | np[0] = 0; | ||
| 344 | } | ||
| 345 | |||
| 346 | if (n0 == dX) { | ||
| 347 | /* This might over-estimate q, but it's probably not worth | ||
| 348 | * the extra code here to find out. */ | ||
| 349 | q = ~(mpi_limb_t) 0; | ||
| 350 | } else { | ||
| 351 | mpi_limb_t r; | ||
| 352 | |||
| 353 | udiv_qrnnd(q, r, n0, np[dsize - 1], dX); | ||
| 354 | umul_ppmm(n1, n0, d1, q); | ||
| 355 | |||
| 356 | while (n1 > r | ||
| 357 | || (n1 == r | ||
| 358 | && n0 > np[dsize - 2])) { | ||
| 359 | q--; | ||
| 360 | r += dX; | ||
| 361 | if (r < dX) /* I.e. "carry in previous addition?" */ | ||
| 362 | break; | ||
| 363 | n1 -= n0 < d1; | ||
| 364 | n0 -= d1; | ||
| 365 | } | ||
| 366 | } | ||
| 367 | |||
| 368 | /* Possible optimization: We already have (q * n0) and (1 * n1) | ||
| 369 | * after the calculation of q. Taking advantage of that, we | ||
| 370 | * could make this loop make two iterations less. */ | ||
| 371 | cy_limb = mpihelp_submul_1(np, dp, dsize, q); | ||
| 372 | |||
| 373 | if (n2 != cy_limb) { | ||
| 374 | mpihelp_add_n(np, np, dp, dsize); | ||
| 375 | q--; | ||
| 376 | } | ||
| 377 | |||
| 378 | qp[i] = q; | ||
| 379 | n0 = np[dsize - 1]; | ||
| 380 | } | ||
| 381 | } | ||
| 382 | } | ||
| 383 | |||
| 384 | return most_significant_q_limb; | ||
| 385 | } | ||
| 386 | |||
| 387 | /**************** | ||
| 388 | * Divide (DIVIDEND_PTR,,DIVIDEND_SIZE) by DIVISOR_LIMB. | ||
| 389 | * Write DIVIDEND_SIZE limbs of quotient at QUOT_PTR. | ||
| 390 | * Return the single-limb remainder. | ||
| 391 | * There are no constraints on the value of the divisor. | ||
| 392 | * | ||
| 393 | * QUOT_PTR and DIVIDEND_PTR might point to the same limb. | ||
| 394 | */ | ||
| 395 | |||
| 396 | mpi_limb_t | ||
| 397 | mpihelp_divmod_1(mpi_ptr_t quot_ptr, | ||
| 398 | mpi_ptr_t dividend_ptr, mpi_size_t dividend_size, | ||
| 399 | mpi_limb_t divisor_limb) | ||
| 400 | { | ||
| 401 | mpi_size_t i; | ||
| 402 | mpi_limb_t n1, n0, r; | ||
| 403 | int dummy; | ||
| 404 | |||
| 405 | if (!dividend_size) | ||
| 406 | return 0; | ||
| 407 | |||
| 408 | /* If multiplication is much faster than division, and the | ||
| 409 | * dividend is large, pre-invert the divisor, and use | ||
| 410 | * only multiplications in the inner loop. | ||
| 411 | * | ||
| 412 | * This test should be read: | ||
| 413 | * Does it ever help to use udiv_qrnnd_preinv? | ||
| 414 | * && Does what we save compensate for the inversion overhead? | ||
| 415 | */ | ||
| 416 | if (UDIV_TIME > (2 * UMUL_TIME + 6) | ||
| 417 | && (UDIV_TIME - (2 * UMUL_TIME + 6)) * dividend_size > UDIV_TIME) { | ||
| 418 | int normalization_steps; | ||
| 419 | |||
| 420 | count_leading_zeros(normalization_steps, divisor_limb); | ||
| 421 | if (normalization_steps) { | ||
| 422 | mpi_limb_t divisor_limb_inverted; | ||
| 423 | |||
| 424 | divisor_limb <<= normalization_steps; | ||
| 425 | |||
| 426 | /* Compute (2**2N - 2**N * DIVISOR_LIMB) / DIVISOR_LIMB. The | ||
| 427 | * result is a (N+1)-bit approximation to 1/DIVISOR_LIMB, with the | ||
| 428 | * most significant bit (with weight 2**N) implicit. | ||
| 429 | */ | ||
| 430 | /* Special case for DIVISOR_LIMB == 100...000. */ | ||
| 431 | if (!(divisor_limb << 1)) | ||
| 432 | divisor_limb_inverted = ~(mpi_limb_t) 0; | ||
| 433 | else | ||
| 434 | udiv_qrnnd(divisor_limb_inverted, dummy, | ||
| 435 | -divisor_limb, 0, divisor_limb); | ||
| 436 | |||
| 437 | n1 = dividend_ptr[dividend_size - 1]; | ||
| 438 | r = n1 >> (BITS_PER_MPI_LIMB - normalization_steps); | ||
| 439 | |||
| 440 | /* Possible optimization: | ||
| 441 | * if (r == 0 | ||
| 442 | * && divisor_limb > ((n1 << normalization_steps) | ||
| 443 | * | (dividend_ptr[dividend_size - 2] >> ...))) | ||
| 444 | * ...one division less... | ||
| 445 | */ | ||
| 446 | for (i = dividend_size - 2; i >= 0; i--) { | ||
| 447 | n0 = dividend_ptr[i]; | ||
| 448 | UDIV_QRNND_PREINV(quot_ptr[i + 1], r, r, | ||
| 449 | ((n1 << normalization_steps) | ||
| 450 | | (n0 >> | ||
| 451 | (BITS_PER_MPI_LIMB - | ||
| 452 | normalization_steps))), | ||
| 453 | divisor_limb, | ||
| 454 | divisor_limb_inverted); | ||
| 455 | n1 = n0; | ||
| 456 | } | ||
| 457 | UDIV_QRNND_PREINV(quot_ptr[0], r, r, | ||
| 458 | n1 << normalization_steps, | ||
| 459 | divisor_limb, divisor_limb_inverted); | ||
| 460 | return r >> normalization_steps; | ||
| 461 | } else { | ||
| 462 | mpi_limb_t divisor_limb_inverted; | ||
| 463 | |||
| 464 | /* Compute (2**2N - 2**N * DIVISOR_LIMB) / DIVISOR_LIMB. The | ||
| 465 | * result is a (N+1)-bit approximation to 1/DIVISOR_LIMB, with the | ||
| 466 | * most significant bit (with weight 2**N) implicit. | ||
| 467 | */ | ||
| 468 | /* Special case for DIVISOR_LIMB == 100...000. */ | ||
| 469 | if (!(divisor_limb << 1)) | ||
| 470 | divisor_limb_inverted = ~(mpi_limb_t) 0; | ||
| 471 | else | ||
| 472 | udiv_qrnnd(divisor_limb_inverted, dummy, | ||
| 473 | -divisor_limb, 0, divisor_limb); | ||
| 474 | |||
| 475 | i = dividend_size - 1; | ||
| 476 | r = dividend_ptr[i]; | ||
| 477 | |||
| 478 | if (r >= divisor_limb) | ||
| 479 | r = 0; | ||
| 480 | else | ||
| 481 | quot_ptr[i--] = 0; | ||
| 482 | |||
| 483 | for (; i >= 0; i--) { | ||
| 484 | n0 = dividend_ptr[i]; | ||
| 485 | UDIV_QRNND_PREINV(quot_ptr[i], r, r, | ||
| 486 | n0, divisor_limb, | ||
| 487 | divisor_limb_inverted); | ||
| 488 | } | ||
| 489 | return r; | ||
| 490 | } | ||
| 491 | } else { | ||
| 492 | if (UDIV_NEEDS_NORMALIZATION) { | ||
| 493 | int normalization_steps; | ||
| 494 | |||
| 495 | count_leading_zeros(normalization_steps, divisor_limb); | ||
| 496 | if (normalization_steps) { | ||
| 497 | divisor_limb <<= normalization_steps; | ||
| 498 | |||
| 499 | n1 = dividend_ptr[dividend_size - 1]; | ||
| 500 | r = n1 >> (BITS_PER_MPI_LIMB - | ||
| 501 | normalization_steps); | ||
| 502 | |||
| 503 | /* Possible optimization: | ||
| 504 | * if (r == 0 | ||
| 505 | * && divisor_limb > ((n1 << normalization_steps) | ||
| 506 | * | (dividend_ptr[dividend_size - 2] >> ...))) | ||
| 507 | * ...one division less... | ||
| 508 | */ | ||
| 509 | for (i = dividend_size - 2; i >= 0; i--) { | ||
| 510 | n0 = dividend_ptr[i]; | ||
| 511 | udiv_qrnnd(quot_ptr[i + 1], r, r, | ||
| 512 | ((n1 << normalization_steps) | ||
| 513 | | (n0 >> | ||
| 514 | (BITS_PER_MPI_LIMB - | ||
| 515 | normalization_steps))), | ||
| 516 | divisor_limb); | ||
| 517 | n1 = n0; | ||
| 518 | } | ||
| 519 | udiv_qrnnd(quot_ptr[0], r, r, | ||
| 520 | n1 << normalization_steps, | ||
| 521 | divisor_limb); | ||
| 522 | return r >> normalization_steps; | ||
| 523 | } | ||
| 524 | } | ||
| 525 | /* No normalization needed, either because udiv_qrnnd doesn't require | ||
| 526 | * it, or because DIVISOR_LIMB is already normalized. */ | ||
| 527 | i = dividend_size - 1; | ||
| 528 | r = dividend_ptr[i]; | ||
| 529 | |||
| 530 | if (r >= divisor_limb) | ||
| 531 | r = 0; | ||
| 532 | else | ||
| 533 | quot_ptr[i--] = 0; | ||
| 534 | |||
| 535 | for (; i >= 0; i--) { | ||
| 536 | n0 = dividend_ptr[i]; | ||
| 537 | udiv_qrnnd(quot_ptr[i], r, r, n0, divisor_limb); | ||
| 538 | } | ||
| 539 | return r; | ||
| 540 | } | ||
| 541 | } | ||
diff --git a/lib/mpi/mpih-mul.c b/lib/mpi/mpih-mul.c new file mode 100644 index 000000000000..c69c5eef233b --- /dev/null +++ b/lib/mpi/mpih-mul.c | |||
| @@ -0,0 +1,527 @@ | |||
| 1 | /* mpihelp-mul.c - MPI helper functions | ||
| 2 | * Copyright (C) 1994, 1996, 1998, 1999, | ||
| 3 | * 2000 Free Software Foundation, Inc. | ||
| 4 | * | ||
| 5 | * This file is part of GnuPG. | ||
| 6 | * | ||
| 7 | * GnuPG is free software; you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU General Public License as published by | ||
| 9 | * the Free Software Foundation; either version 2 of the License, or | ||
| 10 | * (at your option) any later version. | ||
| 11 | * | ||
| 12 | * GnuPG is distributed in the hope that it will be useful, | ||
| 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | * GNU General Public License for more details. | ||
| 16 | * | ||
| 17 | * You should have received a copy of the GNU General Public License | ||
| 18 | * along with this program; if not, write to the Free Software | ||
| 19 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA | ||
| 20 | * | ||
| 21 | * Note: This code is heavily based on the GNU MP Library. | ||
| 22 | * Actually it's the same code with only minor changes in the | ||
| 23 | * way the data is stored; this is to support the abstraction | ||
| 24 | * of an optional secure memory allocation which may be used | ||
| 25 | * to avoid revealing of sensitive data due to paging etc. | ||
| 26 | * The GNU MP Library itself is published under the LGPL; | ||
| 27 | * however I decided to publish this code under the plain GPL. | ||
| 28 | */ | ||
| 29 | |||
| 30 | #include <linux/string.h> | ||
| 31 | #include "mpi-internal.h" | ||
| 32 | #include "longlong.h" | ||
| 33 | |||
| 34 | #define MPN_MUL_N_RECURSE(prodp, up, vp, size, tspace) \ | ||
| 35 | do { \ | ||
| 36 | if ((size) < KARATSUBA_THRESHOLD) \ | ||
| 37 | mul_n_basecase(prodp, up, vp, size); \ | ||
| 38 | else \ | ||
| 39 | mul_n(prodp, up, vp, size, tspace); \ | ||
| 40 | } while (0); | ||
| 41 | |||
| 42 | #define MPN_SQR_N_RECURSE(prodp, up, size, tspace) \ | ||
| 43 | do { \ | ||
| 44 | if ((size) < KARATSUBA_THRESHOLD) \ | ||
| 45 | mpih_sqr_n_basecase(prodp, up, size); \ | ||
| 46 | else \ | ||
| 47 | mpih_sqr_n(prodp, up, size, tspace); \ | ||
| 48 | } while (0); | ||
| 49 | |||
| 50 | /* Multiply the natural numbers u (pointed to by UP) and v (pointed to by VP), | ||
| 51 | * both with SIZE limbs, and store the result at PRODP. 2 * SIZE limbs are | ||
| 52 | * always stored. Return the most significant limb. | ||
| 53 | * | ||
| 54 | * Argument constraints: | ||
| 55 | * 1. PRODP != UP and PRODP != VP, i.e. the destination | ||
| 56 | * must be distinct from the multiplier and the multiplicand. | ||
| 57 | * | ||
| 58 | * | ||
| 59 | * Handle simple cases with traditional multiplication. | ||
| 60 | * | ||
| 61 | * This is the most critical code of multiplication. All multiplies rely | ||
| 62 | * on this, both small and huge. Small ones arrive here immediately. Huge | ||
| 63 | * ones arrive here as this is the base case for Karatsuba's recursive | ||
| 64 | * algorithm below. | ||
| 65 | */ | ||
| 66 | |||
| 67 | static mpi_limb_t | ||
| 68 | mul_n_basecase(mpi_ptr_t prodp, mpi_ptr_t up, mpi_ptr_t vp, mpi_size_t size) | ||
| 69 | { | ||
| 70 | mpi_size_t i; | ||
| 71 | mpi_limb_t cy; | ||
| 72 | mpi_limb_t v_limb; | ||
| 73 | |||
| 74 | /* Multiply by the first limb in V separately, as the result can be | ||
| 75 | * stored (not added) to PROD. We also avoid a loop for zeroing. */ | ||
| 76 | v_limb = vp[0]; | ||
| 77 | if (v_limb <= 1) { | ||
| 78 | if (v_limb == 1) | ||
| 79 | MPN_COPY(prodp, up, size); | ||
| 80 | else | ||
| 81 | MPN_ZERO(prodp, size); | ||
| 82 | cy = 0; | ||
| 83 | } else | ||
| 84 | cy = mpihelp_mul_1(prodp, up, size, v_limb); | ||
| 85 | |||
| 86 | prodp[size] = cy; | ||
| 87 | prodp++; | ||
| 88 | |||
| 89 | /* For each iteration in the outer loop, multiply one limb from | ||
| 90 | * U with one limb from V, and add it to PROD. */ | ||
| 91 | for (i = 1; i < size; i++) { | ||
| 92 | v_limb = vp[i]; | ||
| 93 | if (v_limb <= 1) { | ||
| 94 | cy = 0; | ||
| 95 | if (v_limb == 1) | ||
| 96 | cy = mpihelp_add_n(prodp, prodp, up, size); | ||
| 97 | } else | ||
| 98 | cy = mpihelp_addmul_1(prodp, up, size, v_limb); | ||
| 99 | |||
| 100 | prodp[size] = cy; | ||
| 101 | prodp++; | ||
| 102 | } | ||
| 103 | |||
| 104 | return cy; | ||
| 105 | } | ||
| 106 | |||
| 107 | static void | ||
| 108 | mul_n(mpi_ptr_t prodp, mpi_ptr_t up, mpi_ptr_t vp, | ||
| 109 | mpi_size_t size, mpi_ptr_t tspace) | ||
| 110 | { | ||
| 111 | if (size & 1) { | ||
| 112 | /* The size is odd, and the code below doesn't handle that. | ||
| 113 | * Multiply the least significant (size - 1) limbs with a recursive | ||
| 114 | * call, and handle the most significant limb of S1 and S2 | ||
| 115 | * separately. | ||
| 116 | * A slightly faster way to do this would be to make the Karatsuba | ||
| 117 | * code below behave as if the size were even, and let it check for | ||
| 118 | * odd size in the end. I.e., in essence move this code to the end. | ||
| 119 | * Doing so would save us a recursive call, and potentially make the | ||
| 120 | * stack grow a lot less. | ||
| 121 | */ | ||
| 122 | mpi_size_t esize = size - 1; /* even size */ | ||
| 123 | mpi_limb_t cy_limb; | ||
| 124 | |||
| 125 | MPN_MUL_N_RECURSE(prodp, up, vp, esize, tspace); | ||
| 126 | cy_limb = mpihelp_addmul_1(prodp + esize, up, esize, vp[esize]); | ||
| 127 | prodp[esize + esize] = cy_limb; | ||
| 128 | cy_limb = mpihelp_addmul_1(prodp + esize, vp, size, up[esize]); | ||
| 129 | prodp[esize + size] = cy_limb; | ||
| 130 | } else { | ||
| 131 | /* Anatolij Alekseevich Karatsuba's divide-and-conquer algorithm. | ||
| 132 | * | ||
| 133 | * Split U in two pieces, U1 and U0, such that | ||
| 134 | * U = U0 + U1*(B**n), | ||
| 135 | * and V in V1 and V0, such that | ||
| 136 | * V = V0 + V1*(B**n). | ||
| 137 | * | ||
| 138 | * UV is then computed recursively using the identity | ||
| 139 | * | ||
| 140 | * 2n n n n | ||
| 141 | * UV = (B + B )U V + B (U -U )(V -V ) + (B + 1)U V | ||
| 142 | * 1 1 1 0 0 1 0 0 | ||
| 143 | * | ||
| 144 | * Where B = 2**BITS_PER_MP_LIMB. | ||
| 145 | */ | ||
| 146 | mpi_size_t hsize = size >> 1; | ||
| 147 | mpi_limb_t cy; | ||
| 148 | int negflg; | ||
| 149 | |||
| 150 | /* Product H. ________________ ________________ | ||
| 151 | * |_____U1 x V1____||____U0 x V0_____| | ||
| 152 | * Put result in upper part of PROD and pass low part of TSPACE | ||
| 153 | * as new TSPACE. | ||
| 154 | */ | ||
| 155 | MPN_MUL_N_RECURSE(prodp + size, up + hsize, vp + hsize, hsize, | ||
| 156 | tspace); | ||
| 157 | |||
| 158 | /* Product M. ________________ | ||
| 159 | * |_(U1-U0)(V0-V1)_| | ||
| 160 | */ | ||
| 161 | if (mpihelp_cmp(up + hsize, up, hsize) >= 0) { | ||
| 162 | mpihelp_sub_n(prodp, up + hsize, up, hsize); | ||
| 163 | negflg = 0; | ||
| 164 | } else { | ||
| 165 | mpihelp_sub_n(prodp, up, up + hsize, hsize); | ||
| 166 | negflg = 1; | ||
| 167 | } | ||
| 168 | if (mpihelp_cmp(vp + hsize, vp, hsize) >= 0) { | ||
| 169 | mpihelp_sub_n(prodp + hsize, vp + hsize, vp, hsize); | ||
| 170 | negflg ^= 1; | ||
| 171 | } else { | ||
| 172 | mpihelp_sub_n(prodp + hsize, vp, vp + hsize, hsize); | ||
| 173 | /* No change of NEGFLG. */ | ||
| 174 | } | ||
| 175 | /* Read temporary operands from low part of PROD. | ||
| 176 | * Put result in low part of TSPACE using upper part of TSPACE | ||
| 177 | * as new TSPACE. | ||
| 178 | */ | ||
| 179 | MPN_MUL_N_RECURSE(tspace, prodp, prodp + hsize, hsize, | ||
| 180 | tspace + size); | ||
| 181 | |||
| 182 | /* Add/copy product H. */ | ||
| 183 | MPN_COPY(prodp + hsize, prodp + size, hsize); | ||
| 184 | cy = mpihelp_add_n(prodp + size, prodp + size, | ||
| 185 | prodp + size + hsize, hsize); | ||
| 186 | |||
| 187 | /* Add product M (if NEGFLG M is a negative number) */ | ||
| 188 | if (negflg) | ||
| 189 | cy -= | ||
| 190 | mpihelp_sub_n(prodp + hsize, prodp + hsize, tspace, | ||
| 191 | size); | ||
| 192 | else | ||
| 193 | cy += | ||
| 194 | mpihelp_add_n(prodp + hsize, prodp + hsize, tspace, | ||
| 195 | size); | ||
| 196 | |||
| 197 | /* Product L. ________________ ________________ | ||
| 198 | * |________________||____U0 x V0_____| | ||
| 199 | * Read temporary operands from low part of PROD. | ||
| 200 | * Put result in low part of TSPACE using upper part of TSPACE | ||
| 201 | * as new TSPACE. | ||
| 202 | */ | ||
| 203 | MPN_MUL_N_RECURSE(tspace, up, vp, hsize, tspace + size); | ||
| 204 | |||
| 205 | /* Add/copy Product L (twice) */ | ||
| 206 | |||
| 207 | cy += mpihelp_add_n(prodp + hsize, prodp + hsize, tspace, size); | ||
| 208 | if (cy) | ||
| 209 | mpihelp_add_1(prodp + hsize + size, | ||
| 210 | prodp + hsize + size, hsize, cy); | ||
| 211 | |||
| 212 | MPN_COPY(prodp, tspace, hsize); | ||
| 213 | cy = mpihelp_add_n(prodp + hsize, prodp + hsize, tspace + hsize, | ||
| 214 | hsize); | ||
| 215 | if (cy) | ||
| 216 | mpihelp_add_1(prodp + size, prodp + size, size, 1); | ||
| 217 | } | ||
| 218 | } | ||
| 219 | |||
| 220 | void mpih_sqr_n_basecase(mpi_ptr_t prodp, mpi_ptr_t up, mpi_size_t size) | ||
| 221 | { | ||
| 222 | mpi_size_t i; | ||
| 223 | mpi_limb_t cy_limb; | ||
| 224 | mpi_limb_t v_limb; | ||
| 225 | |||
| 226 | /* Multiply by the first limb in V separately, as the result can be | ||
| 227 | * stored (not added) to PROD. We also avoid a loop for zeroing. */ | ||
| 228 | v_limb = up[0]; | ||
| 229 | if (v_limb <= 1) { | ||
| 230 | if (v_limb == 1) | ||
| 231 | MPN_COPY(prodp, up, size); | ||
| 232 | else | ||
| 233 | MPN_ZERO(prodp, size); | ||
| 234 | cy_limb = 0; | ||
| 235 | } else | ||
| 236 | cy_limb = mpihelp_mul_1(prodp, up, size, v_limb); | ||
| 237 | |||
| 238 | prodp[size] = cy_limb; | ||
| 239 | prodp++; | ||
| 240 | |||
| 241 | /* For each iteration in the outer loop, multiply one limb from | ||
| 242 | * U with one limb from V, and add it to PROD. */ | ||
| 243 | for (i = 1; i < size; i++) { | ||
| 244 | v_limb = up[i]; | ||
| 245 | if (v_limb <= 1) { | ||
| 246 | cy_limb = 0; | ||
| 247 | if (v_limb == 1) | ||
| 248 | cy_limb = mpihelp_add_n(prodp, prodp, up, size); | ||
| 249 | } else | ||
| 250 | cy_limb = mpihelp_addmul_1(prodp, up, size, v_limb); | ||
| 251 | |||
| 252 | prodp[size] = cy_limb; | ||
| 253 | prodp++; | ||
| 254 | } | ||
| 255 | } | ||
| 256 | |||
| 257 | void | ||
| 258 | mpih_sqr_n(mpi_ptr_t prodp, mpi_ptr_t up, mpi_size_t size, mpi_ptr_t tspace) | ||
| 259 | { | ||
| 260 | if (size & 1) { | ||
| 261 | /* The size is odd, and the code below doesn't handle that. | ||
| 262 | * Multiply the least significant (size - 1) limbs with a recursive | ||
| 263 | * call, and handle the most significant limb of S1 and S2 | ||
| 264 | * separately. | ||
| 265 | * A slightly faster way to do this would be to make the Karatsuba | ||
| 266 | * code below behave as if the size were even, and let it check for | ||
| 267 | * odd size in the end. I.e., in essence move this code to the end. | ||
| 268 | * Doing so would save us a recursive call, and potentially make the | ||
| 269 | * stack grow a lot less. | ||
| 270 | */ | ||
| 271 | mpi_size_t esize = size - 1; /* even size */ | ||
| 272 | mpi_limb_t cy_limb; | ||
| 273 | |||
| 274 | MPN_SQR_N_RECURSE(prodp, up, esize, tspace); | ||
| 275 | cy_limb = mpihelp_addmul_1(prodp + esize, up, esize, up[esize]); | ||
| 276 | prodp[esize + esize] = cy_limb; | ||
| 277 | cy_limb = mpihelp_addmul_1(prodp + esize, up, size, up[esize]); | ||
| 278 | |||
| 279 | prodp[esize + size] = cy_limb; | ||
| 280 | } else { | ||
| 281 | mpi_size_t hsize = size >> 1; | ||
| 282 | mpi_limb_t cy; | ||
| 283 | |||
| 284 | /* Product H. ________________ ________________ | ||
| 285 | * |_____U1 x U1____||____U0 x U0_____| | ||
| 286 | * Put result in upper part of PROD and pass low part of TSPACE | ||
| 287 | * as new TSPACE. | ||
| 288 | */ | ||
| 289 | MPN_SQR_N_RECURSE(prodp + size, up + hsize, hsize, tspace); | ||
| 290 | |||
| 291 | /* Product M. ________________ | ||
| 292 | * |_(U1-U0)(U0-U1)_| | ||
| 293 | */ | ||
| 294 | if (mpihelp_cmp(up + hsize, up, hsize) >= 0) | ||
| 295 | mpihelp_sub_n(prodp, up + hsize, up, hsize); | ||
| 296 | else | ||
| 297 | mpihelp_sub_n(prodp, up, up + hsize, hsize); | ||
| 298 | |||
| 299 | /* Read temporary operands from low part of PROD. | ||
| 300 | * Put result in low part of TSPACE using upper part of TSPACE | ||
| 301 | * as new TSPACE. */ | ||
| 302 | MPN_SQR_N_RECURSE(tspace, prodp, hsize, tspace + size); | ||
| 303 | |||
| 304 | /* Add/copy product H */ | ||
| 305 | MPN_COPY(prodp + hsize, prodp + size, hsize); | ||
| 306 | cy = mpihelp_add_n(prodp + size, prodp + size, | ||
| 307 | prodp + size + hsize, hsize); | ||
| 308 | |||
| 309 | /* Add product M (if NEGFLG M is a negative number). */ | ||
| 310 | cy -= mpihelp_sub_n(prodp + hsize, prodp + hsize, tspace, size); | ||
| 311 | |||
| 312 | /* Product L. ________________ ________________ | ||
| 313 | * |________________||____U0 x U0_____| | ||
| 314 | * Read temporary operands from low part of PROD. | ||
| 315 | * Put result in low part of TSPACE using upper part of TSPACE | ||
| 316 | * as new TSPACE. */ | ||
| 317 | MPN_SQR_N_RECURSE(tspace, up, hsize, tspace + size); | ||
| 318 | |||
| 319 | /* Add/copy Product L (twice). */ | ||
| 320 | cy += mpihelp_add_n(prodp + hsize, prodp + hsize, tspace, size); | ||
| 321 | if (cy) | ||
| 322 | mpihelp_add_1(prodp + hsize + size, | ||
| 323 | prodp + hsize + size, hsize, cy); | ||
| 324 | |||
| 325 | MPN_COPY(prodp, tspace, hsize); | ||
| 326 | cy = mpihelp_add_n(prodp + hsize, prodp + hsize, tspace + hsize, | ||
| 327 | hsize); | ||
| 328 | if (cy) | ||
| 329 | mpihelp_add_1(prodp + size, prodp + size, size, 1); | ||
| 330 | } | ||
| 331 | } | ||
| 332 | |||
| 333 | /* This should be made into an inline function in gmp.h. */ | ||
| 334 | int mpihelp_mul_n(mpi_ptr_t prodp, mpi_ptr_t up, mpi_ptr_t vp, mpi_size_t size) | ||
| 335 | { | ||
| 336 | if (up == vp) { | ||
| 337 | if (size < KARATSUBA_THRESHOLD) | ||
| 338 | mpih_sqr_n_basecase(prodp, up, size); | ||
| 339 | else { | ||
| 340 | mpi_ptr_t tspace; | ||
| 341 | tspace = mpi_alloc_limb_space(2 * size); | ||
| 342 | if (!tspace) | ||
| 343 | return -ENOMEM; | ||
| 344 | mpih_sqr_n(prodp, up, size, tspace); | ||
| 345 | mpi_free_limb_space(tspace); | ||
| 346 | } | ||
| 347 | } else { | ||
| 348 | if (size < KARATSUBA_THRESHOLD) | ||
| 349 | mul_n_basecase(prodp, up, vp, size); | ||
| 350 | else { | ||
| 351 | mpi_ptr_t tspace; | ||
| 352 | tspace = mpi_alloc_limb_space(2 * size); | ||
| 353 | if (!tspace) | ||
| 354 | return -ENOMEM; | ||
| 355 | mul_n(prodp, up, vp, size, tspace); | ||
| 356 | mpi_free_limb_space(tspace); | ||
| 357 | } | ||
| 358 | } | ||
| 359 | |||
| 360 | return 0; | ||
| 361 | } | ||
| 362 | |||
| 363 | int | ||
| 364 | mpihelp_mul_karatsuba_case(mpi_ptr_t prodp, | ||
| 365 | mpi_ptr_t up, mpi_size_t usize, | ||
| 366 | mpi_ptr_t vp, mpi_size_t vsize, | ||
| 367 | struct karatsuba_ctx *ctx) | ||
| 368 | { | ||
| 369 | mpi_limb_t cy; | ||
| 370 | |||
| 371 | if (!ctx->tspace || ctx->tspace_size < vsize) { | ||
| 372 | if (ctx->tspace) | ||
| 373 | mpi_free_limb_space(ctx->tspace); | ||
| 374 | ctx->tspace = mpi_alloc_limb_space(2 * vsize); | ||
| 375 | if (!ctx->tspace) | ||
| 376 | return -ENOMEM; | ||
| 377 | ctx->tspace_size = vsize; | ||
| 378 | } | ||
| 379 | |||
| 380 | MPN_MUL_N_RECURSE(prodp, up, vp, vsize, ctx->tspace); | ||
| 381 | |||
| 382 | prodp += vsize; | ||
| 383 | up += vsize; | ||
| 384 | usize -= vsize; | ||
| 385 | if (usize >= vsize) { | ||
| 386 | if (!ctx->tp || ctx->tp_size < vsize) { | ||
| 387 | if (ctx->tp) | ||
| 388 | mpi_free_limb_space(ctx->tp); | ||
| 389 | ctx->tp = mpi_alloc_limb_space(2 * vsize); | ||
| 390 | if (!ctx->tp) { | ||
| 391 | if (ctx->tspace) | ||
| 392 | mpi_free_limb_space(ctx->tspace); | ||
| 393 | ctx->tspace = NULL; | ||
| 394 | return -ENOMEM; | ||
| 395 | } | ||
| 396 | ctx->tp_size = vsize; | ||
| 397 | } | ||
| 398 | |||
| 399 | do { | ||
| 400 | MPN_MUL_N_RECURSE(ctx->tp, up, vp, vsize, ctx->tspace); | ||
| 401 | cy = mpihelp_add_n(prodp, prodp, ctx->tp, vsize); | ||
| 402 | mpihelp_add_1(prodp + vsize, ctx->tp + vsize, vsize, | ||
| 403 | cy); | ||
| 404 | prodp += vsize; | ||
| 405 | up += vsize; | ||
| 406 | usize -= vsize; | ||
| 407 | } while (usize >= vsize); | ||
| 408 | } | ||
| 409 | |||
| 410 | if (usize) { | ||
| 411 | if (usize < KARATSUBA_THRESHOLD) { | ||
| 412 | mpi_limb_t tmp; | ||
| 413 | if (mpihelp_mul(ctx->tspace, vp, vsize, up, usize, &tmp) | ||
| 414 | < 0) | ||
| 415 | return -ENOMEM; | ||
| 416 | } else { | ||
| 417 | if (!ctx->next) { | ||
| 418 | ctx->next = kzalloc(sizeof *ctx, GFP_KERNEL); | ||
| 419 | if (!ctx->next) | ||
| 420 | return -ENOMEM; | ||
| 421 | } | ||
| 422 | if (mpihelp_mul_karatsuba_case(ctx->tspace, | ||
| 423 | vp, vsize, | ||
| 424 | up, usize, | ||
| 425 | ctx->next) < 0) | ||
| 426 | return -ENOMEM; | ||
| 427 | } | ||
| 428 | |||
| 429 | cy = mpihelp_add_n(prodp, prodp, ctx->tspace, vsize); | ||
| 430 | mpihelp_add_1(prodp + vsize, ctx->tspace + vsize, usize, cy); | ||
| 431 | } | ||
| 432 | |||
| 433 | return 0; | ||
| 434 | } | ||
| 435 | |||
| 436 | void mpihelp_release_karatsuba_ctx(struct karatsuba_ctx *ctx) | ||
| 437 | { | ||
| 438 | struct karatsuba_ctx *ctx2; | ||
| 439 | |||
| 440 | if (ctx->tp) | ||
| 441 | mpi_free_limb_space(ctx->tp); | ||
| 442 | if (ctx->tspace) | ||
| 443 | mpi_free_limb_space(ctx->tspace); | ||
| 444 | for (ctx = ctx->next; ctx; ctx = ctx2) { | ||
| 445 | ctx2 = ctx->next; | ||
| 446 | if (ctx->tp) | ||
| 447 | mpi_free_limb_space(ctx->tp); | ||
| 448 | if (ctx->tspace) | ||
| 449 | mpi_free_limb_space(ctx->tspace); | ||
| 450 | kfree(ctx); | ||
| 451 | } | ||
| 452 | } | ||
| 453 | |||
| 454 | /* Multiply the natural numbers u (pointed to by UP, with USIZE limbs) | ||
| 455 | * and v (pointed to by VP, with VSIZE limbs), and store the result at | ||
| 456 | * PRODP. USIZE + VSIZE limbs are always stored, but if the input | ||
| 457 | * operands are normalized. Return the most significant limb of the | ||
| 458 | * result. | ||
| 459 | * | ||
| 460 | * NOTE: The space pointed to by PRODP is overwritten before finished | ||
| 461 | * with U and V, so overlap is an error. | ||
| 462 | * | ||
| 463 | * Argument constraints: | ||
| 464 | * 1. USIZE >= VSIZE. | ||
| 465 | * 2. PRODP != UP and PRODP != VP, i.e. the destination | ||
| 466 | * must be distinct from the multiplier and the multiplicand. | ||
| 467 | */ | ||
| 468 | |||
| 469 | int | ||
| 470 | mpihelp_mul(mpi_ptr_t prodp, mpi_ptr_t up, mpi_size_t usize, | ||
| 471 | mpi_ptr_t vp, mpi_size_t vsize, mpi_limb_t *_result) | ||
| 472 | { | ||
| 473 | mpi_ptr_t prod_endp = prodp + usize + vsize - 1; | ||
| 474 | mpi_limb_t cy; | ||
| 475 | struct karatsuba_ctx ctx; | ||
| 476 | |||
| 477 | if (vsize < KARATSUBA_THRESHOLD) { | ||
| 478 | mpi_size_t i; | ||
| 479 | mpi_limb_t v_limb; | ||
| 480 | |||
| 481 | if (!vsize) { | ||
| 482 | *_result = 0; | ||
| 483 | return 0; | ||
| 484 | } | ||
| 485 | |||
| 486 | /* Multiply by the first limb in V separately, as the result can be | ||
| 487 | * stored (not added) to PROD. We also avoid a loop for zeroing. */ | ||
| 488 | v_limb = vp[0]; | ||
| 489 | if (v_limb <= 1) { | ||
| 490 | if (v_limb == 1) | ||
| 491 | MPN_COPY(prodp, up, usize); | ||
| 492 | else | ||
| 493 | MPN_ZERO(prodp, usize); | ||
| 494 | cy = 0; | ||
| 495 | } else | ||
| 496 | cy = mpihelp_mul_1(prodp, up, usize, v_limb); | ||
| 497 | |||
| 498 | prodp[usize] = cy; | ||
| 499 | prodp++; | ||
| 500 | |||
| 501 | /* For each iteration in the outer loop, multiply one limb from | ||
| 502 | * U with one limb from V, and add it to PROD. */ | ||
| 503 | for (i = 1; i < vsize; i++) { | ||
| 504 | v_limb = vp[i]; | ||
| 505 | if (v_limb <= 1) { | ||
| 506 | cy = 0; | ||
| 507 | if (v_limb == 1) | ||
| 508 | cy = mpihelp_add_n(prodp, prodp, up, | ||
| 509 | usize); | ||
| 510 | } else | ||
| 511 | cy = mpihelp_addmul_1(prodp, up, usize, v_limb); | ||
| 512 | |||
| 513 | prodp[usize] = cy; | ||
| 514 | prodp++; | ||
| 515 | } | ||
| 516 | |||
| 517 | *_result = cy; | ||
| 518 | return 0; | ||
| 519 | } | ||
| 520 | |||
| 521 | memset(&ctx, 0, sizeof ctx); | ||
| 522 | if (mpihelp_mul_karatsuba_case(prodp, up, usize, vp, vsize, &ctx) < 0) | ||
| 523 | return -ENOMEM; | ||
| 524 | mpihelp_release_karatsuba_ctx(&ctx); | ||
| 525 | *_result = *prod_endp; | ||
| 526 | return 0; | ||
| 527 | } | ||
diff --git a/lib/mpi/mpiutil.c b/lib/mpi/mpiutil.c new file mode 100644 index 000000000000..eefc55d6b7f5 --- /dev/null +++ b/lib/mpi/mpiutil.c | |||
| @@ -0,0 +1,208 @@ | |||
| 1 | /* mpiutil.ac - Utility functions for MPI | ||
| 2 | * Copyright (C) 1998, 1999 Free Software Foundation, Inc. | ||
| 3 | * | ||
| 4 | * This file is part of GnuPG. | ||
| 5 | * | ||
| 6 | * GnuPG is free software; you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU General Public License as published by | ||
| 8 | * the Free Software Foundation; either version 2 of the License, or | ||
| 9 | * (at your option) any later version. | ||
| 10 | * | ||
| 11 | * GnuPG is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License | ||
| 17 | * along with this program; if not, write to the Free Software | ||
| 18 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA | ||
| 19 | */ | ||
| 20 | |||
| 21 | #include "mpi-internal.h" | ||
| 22 | |||
| 23 | /**************** | ||
| 24 | * Note: It was a bad idea to use the number of limbs to allocate | ||
| 25 | * because on a alpha the limbs are large but we normally need | ||
| 26 | * integers of n bits - So we should chnage this to bits (or bytes). | ||
| 27 | * | ||
| 28 | * But mpi_alloc is used in a lot of places :-) | ||
| 29 | */ | ||
| 30 | MPI mpi_alloc(unsigned nlimbs) | ||
| 31 | { | ||
| 32 | MPI a; | ||
| 33 | |||
| 34 | a = kmalloc(sizeof *a, GFP_KERNEL); | ||
| 35 | if (!a) | ||
| 36 | return a; | ||
| 37 | |||
| 38 | if (nlimbs) { | ||
| 39 | a->d = mpi_alloc_limb_space(nlimbs); | ||
| 40 | if (!a->d) { | ||
| 41 | kfree(a); | ||
| 42 | return NULL; | ||
| 43 | } | ||
| 44 | } else { | ||
| 45 | a->d = NULL; | ||
| 46 | } | ||
| 47 | |||
| 48 | a->alloced = nlimbs; | ||
| 49 | a->nlimbs = 0; | ||
| 50 | a->sign = 0; | ||
| 51 | a->flags = 0; | ||
| 52 | a->nbits = 0; | ||
| 53 | return a; | ||
| 54 | } | ||
| 55 | EXPORT_SYMBOL_GPL(mpi_alloc); | ||
| 56 | |||
| 57 | mpi_ptr_t mpi_alloc_limb_space(unsigned nlimbs) | ||
| 58 | { | ||
| 59 | size_t len = nlimbs * sizeof(mpi_limb_t); | ||
| 60 | |||
| 61 | return kmalloc(len, GFP_KERNEL); | ||
| 62 | } | ||
| 63 | |||
| 64 | void mpi_free_limb_space(mpi_ptr_t a) | ||
| 65 | { | ||
| 66 | if (!a) | ||
| 67 | return; | ||
| 68 | |||
| 69 | kfree(a); | ||
| 70 | } | ||
| 71 | |||
| 72 | void mpi_assign_limb_space(MPI a, mpi_ptr_t ap, unsigned nlimbs) | ||
| 73 | { | ||
| 74 | mpi_free_limb_space(a->d); | ||
| 75 | a->d = ap; | ||
| 76 | a->alloced = nlimbs; | ||
| 77 | } | ||
| 78 | |||
| 79 | /**************** | ||
| 80 | * Resize the array of A to NLIMBS. the additional space is cleared | ||
| 81 | * (set to 0) [done by m_realloc()] | ||
| 82 | */ | ||
| 83 | int mpi_resize(MPI a, unsigned nlimbs) | ||
| 84 | { | ||
| 85 | void *p; | ||
| 86 | |||
| 87 | if (nlimbs <= a->alloced) | ||
| 88 | return 0; /* no need to do it */ | ||
| 89 | |||
| 90 | if (a->d) { | ||
| 91 | p = kmalloc(nlimbs * sizeof(mpi_limb_t), GFP_KERNEL); | ||
| 92 | if (!p) | ||
| 93 | return -ENOMEM; | ||
| 94 | memcpy(p, a->d, a->alloced * sizeof(mpi_limb_t)); | ||
| 95 | kfree(a->d); | ||
| 96 | a->d = p; | ||
| 97 | } else { | ||
| 98 | a->d = kzalloc(nlimbs * sizeof(mpi_limb_t), GFP_KERNEL); | ||
| 99 | if (!a->d) | ||
| 100 | return -ENOMEM; | ||
| 101 | } | ||
| 102 | a->alloced = nlimbs; | ||
| 103 | return 0; | ||
| 104 | } | ||
| 105 | |||
| 106 | void mpi_clear(MPI a) | ||
| 107 | { | ||
| 108 | a->nlimbs = 0; | ||
| 109 | a->nbits = 0; | ||
| 110 | a->flags = 0; | ||
| 111 | } | ||
| 112 | |||
| 113 | void mpi_free(MPI a) | ||
| 114 | { | ||
| 115 | if (!a) | ||
| 116 | return; | ||
| 117 | |||
| 118 | if (a->flags & 4) | ||
| 119 | kfree(a->d); | ||
| 120 | else | ||
| 121 | mpi_free_limb_space(a->d); | ||
| 122 | |||
| 123 | if (a->flags & ~7) | ||
| 124 | pr_info("invalid flag value in mpi\n"); | ||
| 125 | kfree(a); | ||
| 126 | } | ||
| 127 | EXPORT_SYMBOL_GPL(mpi_free); | ||
| 128 | |||
| 129 | /**************** | ||
| 130 | * Note: This copy function should not interpret the MPI | ||
| 131 | * but copy it transparently. | ||
| 132 | */ | ||
| 133 | int mpi_copy(MPI *copied, const MPI a) | ||
| 134 | { | ||
| 135 | size_t i; | ||
| 136 | MPI b; | ||
| 137 | |||
| 138 | *copied = MPI_NULL; | ||
| 139 | |||
| 140 | if (a) { | ||
| 141 | b = mpi_alloc(a->nlimbs); | ||
| 142 | if (!b) | ||
| 143 | return -ENOMEM; | ||
| 144 | |||
| 145 | b->nlimbs = a->nlimbs; | ||
| 146 | b->sign = a->sign; | ||
| 147 | b->flags = a->flags; | ||
| 148 | b->nbits = a->nbits; | ||
| 149 | |||
| 150 | for (i = 0; i < b->nlimbs; i++) | ||
| 151 | b->d[i] = a->d[i]; | ||
| 152 | |||
| 153 | *copied = b; | ||
| 154 | } | ||
| 155 | |||
| 156 | return 0; | ||
| 157 | } | ||
| 158 | |||
| 159 | int mpi_set(MPI w, const MPI u) | ||
| 160 | { | ||
| 161 | mpi_ptr_t wp, up; | ||
| 162 | mpi_size_t usize = u->nlimbs; | ||
| 163 | int usign = u->sign; | ||
| 164 | |||
| 165 | if (RESIZE_IF_NEEDED(w, (size_t) usize) < 0) | ||
| 166 | return -ENOMEM; | ||
| 167 | |||
| 168 | wp = w->d; | ||
| 169 | up = u->d; | ||
| 170 | MPN_COPY(wp, up, usize); | ||
| 171 | w->nlimbs = usize; | ||
| 172 | w->nbits = u->nbits; | ||
| 173 | w->flags = u->flags; | ||
| 174 | w->sign = usign; | ||
| 175 | return 0; | ||
| 176 | } | ||
| 177 | |||
| 178 | int mpi_set_ui(MPI w, unsigned long u) | ||
| 179 | { | ||
| 180 | if (RESIZE_IF_NEEDED(w, 1) < 0) | ||
| 181 | return -ENOMEM; | ||
| 182 | w->d[0] = u; | ||
| 183 | w->nlimbs = u ? 1 : 0; | ||
| 184 | w->sign = 0; | ||
| 185 | w->nbits = 0; | ||
| 186 | w->flags = 0; | ||
| 187 | return 0; | ||
| 188 | } | ||
| 189 | |||
| 190 | MPI mpi_alloc_set_ui(unsigned long u) | ||
| 191 | { | ||
| 192 | MPI w = mpi_alloc(1); | ||
| 193 | if (!w) | ||
| 194 | return w; | ||
| 195 | w->d[0] = u; | ||
| 196 | w->nlimbs = u ? 1 : 0; | ||
| 197 | w->sign = 0; | ||
| 198 | return w; | ||
| 199 | } | ||
| 200 | |||
| 201 | void mpi_swap(MPI a, MPI b) | ||
| 202 | { | ||
| 203 | struct gcry_mpi tmp; | ||
| 204 | |||
| 205 | tmp = *a; | ||
| 206 | *a = *b; | ||
| 207 | *b = tmp; | ||
| 208 | } | ||
