mpiutil.c (6804B)
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/* Constants allocated right away at startup. */ 24static MPI constants[MPI_NUMBER_OF_CONSTANTS]; 25 26/* Initialize the MPI subsystem. This is called early and allows to 27 * do some initialization without taking care of threading issues. 28 */ 29static int __init mpi_init(void) 30{ 31 int idx; 32 unsigned long value; 33 34 for (idx = 0; idx < MPI_NUMBER_OF_CONSTANTS; idx++) { 35 switch (idx) { 36 case MPI_C_ZERO: 37 value = 0; 38 break; 39 case MPI_C_ONE: 40 value = 1; 41 break; 42 case MPI_C_TWO: 43 value = 2; 44 break; 45 case MPI_C_THREE: 46 value = 3; 47 break; 48 case MPI_C_FOUR: 49 value = 4; 50 break; 51 case MPI_C_EIGHT: 52 value = 8; 53 break; 54 default: 55 pr_err("MPI: invalid mpi_const selector %d\n", idx); 56 return -EFAULT; 57 } 58 constants[idx] = mpi_alloc_set_ui(value); 59 constants[idx]->flags = (16|32); 60 } 61 62 return 0; 63} 64postcore_initcall(mpi_init); 65 66/* Return a constant MPI descripbed by NO which is one of the 67 * MPI_C_xxx macros. There is no need to copy this returned value; it 68 * may be used directly. 69 */ 70MPI mpi_const(enum gcry_mpi_constants no) 71{ 72 if ((int)no < 0 || no > MPI_NUMBER_OF_CONSTANTS) 73 pr_err("MPI: invalid mpi_const selector %d\n", no); 74 if (!constants[no]) 75 pr_err("MPI: MPI subsystem not initialized\n"); 76 return constants[no]; 77} 78EXPORT_SYMBOL_GPL(mpi_const); 79 80/**************** 81 * Note: It was a bad idea to use the number of limbs to allocate 82 * because on a alpha the limbs are large but we normally need 83 * integers of n bits - So we should change this to bits (or bytes). 84 * 85 * But mpi_alloc is used in a lot of places :-) 86 */ 87MPI mpi_alloc(unsigned nlimbs) 88{ 89 MPI a; 90 91 a = kmalloc(sizeof *a, GFP_KERNEL); 92 if (!a) 93 return a; 94 95 if (nlimbs) { 96 a->d = mpi_alloc_limb_space(nlimbs); 97 if (!a->d) { 98 kfree(a); 99 return NULL; 100 } 101 } else { 102 a->d = NULL; 103 } 104 105 a->alloced = nlimbs; 106 a->nlimbs = 0; 107 a->sign = 0; 108 a->flags = 0; 109 a->nbits = 0; 110 return a; 111} 112EXPORT_SYMBOL_GPL(mpi_alloc); 113 114mpi_ptr_t mpi_alloc_limb_space(unsigned nlimbs) 115{ 116 size_t len = nlimbs * sizeof(mpi_limb_t); 117 118 if (!len) 119 return NULL; 120 121 return kmalloc(len, GFP_KERNEL); 122} 123 124void mpi_free_limb_space(mpi_ptr_t a) 125{ 126 if (!a) 127 return; 128 129 kfree_sensitive(a); 130} 131 132void mpi_assign_limb_space(MPI a, mpi_ptr_t ap, unsigned nlimbs) 133{ 134 mpi_free_limb_space(a->d); 135 a->d = ap; 136 a->alloced = nlimbs; 137} 138 139/**************** 140 * Resize the array of A to NLIMBS. the additional space is cleared 141 * (set to 0) [done by m_realloc()] 142 */ 143int mpi_resize(MPI a, unsigned nlimbs) 144{ 145 void *p; 146 147 if (nlimbs <= a->alloced) 148 return 0; /* no need to do it */ 149 150 if (a->d) { 151 p = kcalloc(nlimbs, sizeof(mpi_limb_t), GFP_KERNEL); 152 if (!p) 153 return -ENOMEM; 154 memcpy(p, a->d, a->alloced * sizeof(mpi_limb_t)); 155 kfree_sensitive(a->d); 156 a->d = p; 157 } else { 158 a->d = kcalloc(nlimbs, sizeof(mpi_limb_t), GFP_KERNEL); 159 if (!a->d) 160 return -ENOMEM; 161 } 162 a->alloced = nlimbs; 163 return 0; 164} 165 166void mpi_clear(MPI a) 167{ 168 if (!a) 169 return; 170 a->nlimbs = 0; 171 a->flags = 0; 172} 173EXPORT_SYMBOL_GPL(mpi_clear); 174 175void mpi_free(MPI a) 176{ 177 if (!a) 178 return; 179 180 if (a->flags & 4) 181 kfree_sensitive(a->d); 182 else 183 mpi_free_limb_space(a->d); 184 185 if (a->flags & ~7) 186 pr_info("invalid flag value in mpi\n"); 187 kfree(a); 188} 189EXPORT_SYMBOL_GPL(mpi_free); 190 191/**************** 192 * Note: This copy function should not interpret the MPI 193 * but copy it transparently. 194 */ 195MPI mpi_copy(MPI a) 196{ 197 int i; 198 MPI b; 199 200 if (a) { 201 b = mpi_alloc(a->nlimbs); 202 b->nlimbs = a->nlimbs; 203 b->sign = a->sign; 204 b->flags = a->flags; 205 b->flags &= ~(16|32); /* Reset the immutable and constant flags. */ 206 for (i = 0; i < b->nlimbs; i++) 207 b->d[i] = a->d[i]; 208 } else 209 b = NULL; 210 return b; 211} 212 213/**************** 214 * This function allocates an MPI which is optimized to hold 215 * a value as large as the one given in the argument and allocates it 216 * with the same flags as A. 217 */ 218MPI mpi_alloc_like(MPI a) 219{ 220 MPI b; 221 222 if (a) { 223 b = mpi_alloc(a->nlimbs); 224 b->nlimbs = 0; 225 b->sign = 0; 226 b->flags = a->flags; 227 } else 228 b = NULL; 229 230 return b; 231} 232 233 234/* Set U into W and release U. If W is NULL only U will be released. */ 235void mpi_snatch(MPI w, MPI u) 236{ 237 if (w) { 238 mpi_assign_limb_space(w, u->d, u->alloced); 239 w->nlimbs = u->nlimbs; 240 w->sign = u->sign; 241 w->flags = u->flags; 242 u->alloced = 0; 243 u->nlimbs = 0; 244 u->d = NULL; 245 } 246 mpi_free(u); 247} 248 249 250MPI mpi_set(MPI w, MPI u) 251{ 252 mpi_ptr_t wp, up; 253 mpi_size_t usize = u->nlimbs; 254 int usign = u->sign; 255 256 if (!w) 257 w = mpi_alloc(mpi_get_nlimbs(u)); 258 RESIZE_IF_NEEDED(w, usize); 259 wp = w->d; 260 up = u->d; 261 MPN_COPY(wp, up, usize); 262 w->nlimbs = usize; 263 w->flags = u->flags; 264 w->flags &= ~(16|32); /* Reset the immutable and constant flags. */ 265 w->sign = usign; 266 return w; 267} 268EXPORT_SYMBOL_GPL(mpi_set); 269 270MPI mpi_set_ui(MPI w, unsigned long u) 271{ 272 if (!w) 273 w = mpi_alloc(1); 274 /* FIXME: If U is 0 we have no need to resize and thus possible 275 * allocating the the limbs. 276 */ 277 RESIZE_IF_NEEDED(w, 1); 278 w->d[0] = u; 279 w->nlimbs = u ? 1 : 0; 280 w->sign = 0; 281 w->flags = 0; 282 return w; 283} 284EXPORT_SYMBOL_GPL(mpi_set_ui); 285 286MPI mpi_alloc_set_ui(unsigned long u) 287{ 288 MPI w = mpi_alloc(1); 289 w->d[0] = u; 290 w->nlimbs = u ? 1 : 0; 291 w->sign = 0; 292 return w; 293} 294 295/**************** 296 * Swap the value of A and B, when SWAP is 1. 297 * Leave the value when SWAP is 0. 298 * This implementation should be constant-time regardless of SWAP. 299 */ 300void mpi_swap_cond(MPI a, MPI b, unsigned long swap) 301{ 302 mpi_size_t i; 303 mpi_size_t nlimbs; 304 mpi_limb_t mask = ((mpi_limb_t)0) - swap; 305 mpi_limb_t x; 306 307 if (a->alloced > b->alloced) 308 nlimbs = b->alloced; 309 else 310 nlimbs = a->alloced; 311 if (a->nlimbs > nlimbs || b->nlimbs > nlimbs) 312 return; 313 314 for (i = 0; i < nlimbs; i++) { 315 x = mask & (a->d[i] ^ b->d[i]); 316 a->d[i] = a->d[i] ^ x; 317 b->d[i] = b->d[i] ^ x; 318 } 319 320 x = mask & (a->nlimbs ^ b->nlimbs); 321 a->nlimbs = a->nlimbs ^ x; 322 b->nlimbs = b->nlimbs ^ x; 323 324 x = mask & (a->sign ^ b->sign); 325 a->sign = a->sign ^ x; 326 b->sign = b->sign ^ x; 327} 328 329MODULE_DESCRIPTION("Multiprecision maths library"); 330MODULE_LICENSE("GPL");