Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v3.5-rc7 234 lines 5.8 kB view raw
1/* mpi-add.c - MPI functions 2 * Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc. 3 * Copyright (C) 1994, 1996 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 * Add the unsigned integer V to the mpi-integer U and store the 34 * result in W. U and V may be the same. 35 */ 36int mpi_add_ui(MPI w, const MPI u, unsigned long v) 37{ 38 mpi_ptr_t wp, up; 39 mpi_size_t usize, wsize; 40 int usign, wsign; 41 42 usize = u->nlimbs; 43 usign = u->sign; 44 wsign = 0; 45 46 /* If not space for W (and possible carry), increase space. */ 47 wsize = usize + 1; 48 if (w->alloced < wsize) 49 if (mpi_resize(w, wsize) < 0) 50 return -ENOMEM; 51 52 /* These must be after realloc (U may be the same as W). */ 53 up = u->d; 54 wp = w->d; 55 56 if (!usize) { /* simple */ 57 wp[0] = v; 58 wsize = v ? 1 : 0; 59 } else if (!usign) { /* mpi is not negative */ 60 mpi_limb_t cy; 61 cy = mpihelp_add_1(wp, up, usize, v); 62 wp[usize] = cy; 63 wsize = usize + cy; 64 } else { /* The signs are different. Need exact comparison to determine 65 * which operand to subtract from which. */ 66 if (usize == 1 && up[0] < v) { 67 wp[0] = v - up[0]; 68 wsize = 1; 69 } else { 70 mpihelp_sub_1(wp, up, usize, v); 71 /* Size can decrease with at most one limb. */ 72 wsize = usize - (wp[usize - 1] == 0); 73 wsign = 1; 74 } 75 } 76 77 w->nlimbs = wsize; 78 w->sign = wsign; 79 return 0; 80} 81 82int mpi_add(MPI w, MPI u, MPI v) 83{ 84 mpi_ptr_t wp, up, vp; 85 mpi_size_t usize, vsize, wsize; 86 int usign, vsign, wsign; 87 88 if (u->nlimbs < v->nlimbs) { /* Swap U and V. */ 89 usize = v->nlimbs; 90 usign = v->sign; 91 vsize = u->nlimbs; 92 vsign = u->sign; 93 wsize = usize + 1; 94 if (RESIZE_IF_NEEDED(w, wsize) < 0) 95 return -ENOMEM; 96 /* These must be after realloc (u or v may be the same as w). */ 97 up = v->d; 98 vp = u->d; 99 } else { 100 usize = u->nlimbs; 101 usign = u->sign; 102 vsize = v->nlimbs; 103 vsign = v->sign; 104 wsize = usize + 1; 105 if (RESIZE_IF_NEEDED(w, wsize) < 0) 106 return -ENOMEM; 107 /* These must be after realloc (u or v may be the same as w). */ 108 up = u->d; 109 vp = v->d; 110 } 111 wp = w->d; 112 wsign = 0; 113 114 if (!vsize) { /* simple */ 115 MPN_COPY(wp, up, usize); 116 wsize = usize; 117 wsign = usign; 118 } else if (usign != vsign) { /* different sign */ 119 /* This test is right since USIZE >= VSIZE */ 120 if (usize != vsize) { 121 mpihelp_sub(wp, up, usize, vp, vsize); 122 wsize = usize; 123 MPN_NORMALIZE(wp, wsize); 124 wsign = usign; 125 } else if (mpihelp_cmp(up, vp, usize) < 0) { 126 mpihelp_sub_n(wp, vp, up, usize); 127 wsize = usize; 128 MPN_NORMALIZE(wp, wsize); 129 if (!usign) 130 wsign = 1; 131 } else { 132 mpihelp_sub_n(wp, up, vp, usize); 133 wsize = usize; 134 MPN_NORMALIZE(wp, wsize); 135 if (usign) 136 wsign = 1; 137 } 138 } else { /* U and V have same sign. Add them. */ 139 mpi_limb_t cy = mpihelp_add(wp, up, usize, vp, vsize); 140 wp[usize] = cy; 141 wsize = usize + cy; 142 if (usign) 143 wsign = 1; 144 } 145 146 w->nlimbs = wsize; 147 w->sign = wsign; 148 return 0; 149} 150 151/**************** 152 * Subtract the unsigned integer V from the mpi-integer U and store the 153 * result in W. 154 */ 155int mpi_sub_ui(MPI w, MPI u, unsigned long v) 156{ 157 mpi_ptr_t wp, up; 158 mpi_size_t usize, wsize; 159 int usign, wsign; 160 161 usize = u->nlimbs; 162 usign = u->sign; 163 wsign = 0; 164 165 /* If not space for W (and possible carry), increase space. */ 166 wsize = usize + 1; 167 if (w->alloced < wsize) 168 if (mpi_resize(w, wsize) < 0) 169 return -ENOMEM; 170 171 /* These must be after realloc (U may be the same as W). */ 172 up = u->d; 173 wp = w->d; 174 175 if (!usize) { /* simple */ 176 wp[0] = v; 177 wsize = v ? 1 : 0; 178 wsign = 1; 179 } else if (usign) { /* mpi and v are negative */ 180 mpi_limb_t cy; 181 cy = mpihelp_add_1(wp, up, usize, v); 182 wp[usize] = cy; 183 wsize = usize + cy; 184 } else { /* The signs are different. Need exact comparison to determine 185 * which operand to subtract from which. */ 186 if (usize == 1 && up[0] < v) { 187 wp[0] = v - up[0]; 188 wsize = 1; 189 wsign = 1; 190 } else { 191 mpihelp_sub_1(wp, up, usize, v); 192 /* Size can decrease with at most one limb. */ 193 wsize = usize - (wp[usize - 1] == 0); 194 } 195 } 196 197 w->nlimbs = wsize; 198 w->sign = wsign; 199 return 0; 200} 201 202int mpi_sub(MPI w, MPI u, MPI v) 203{ 204 int rc; 205 206 if (w == v) { 207 MPI vv; 208 if (mpi_copy(&vv, v) < 0) 209 return -ENOMEM; 210 vv->sign = !vv->sign; 211 rc = mpi_add(w, u, vv); 212 mpi_free(vv); 213 } else { 214 /* fixme: this is not thread-save (we temp. modify v) */ 215 v->sign = !v->sign; 216 rc = mpi_add(w, u, v); 217 v->sign = !v->sign; 218 } 219 return rc; 220} 221 222int mpi_addm(MPI w, MPI u, MPI v, MPI m) 223{ 224 if (mpi_add(w, u, v) < 0 || mpi_fdiv_r(w, w, m) < 0) 225 return -ENOMEM; 226 return 0; 227} 228 229int mpi_subm(MPI w, MPI u, MPI v, MPI m) 230{ 231 if (mpi_sub(w, u, v) < 0 || mpi_fdiv_r(w, w, m) < 0) 232 return -ENOMEM; 233 return 0; 234}