18c2ecf20Sopenharmony_ci/* mpiutil.ac - Utility functions for MPI 28c2ecf20Sopenharmony_ci * Copyright (C) 1998, 1999 Free Software Foundation, Inc. 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * This file is part of GnuPG. 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * GnuPG is free software; you can redistribute it and/or modify 78c2ecf20Sopenharmony_ci * it under the terms of the GNU General Public License as published by 88c2ecf20Sopenharmony_ci * the Free Software Foundation; either version 2 of the License, or 98c2ecf20Sopenharmony_ci * (at your option) any later version. 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * GnuPG is distributed in the hope that it will be useful, 128c2ecf20Sopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 138c2ecf20Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 148c2ecf20Sopenharmony_ci * GNU General Public License for more details. 158c2ecf20Sopenharmony_ci * 168c2ecf20Sopenharmony_ci * You should have received a copy of the GNU General Public License 178c2ecf20Sopenharmony_ci * along with this program; if not, write to the Free Software 188c2ecf20Sopenharmony_ci * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA 198c2ecf20Sopenharmony_ci */ 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#include "mpi-internal.h" 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci/* Constants allocated right away at startup. */ 248c2ecf20Sopenharmony_cistatic MPI constants[MPI_NUMBER_OF_CONSTANTS]; 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci/* Initialize the MPI subsystem. This is called early and allows to 278c2ecf20Sopenharmony_ci * do some initialization without taking care of threading issues. 288c2ecf20Sopenharmony_ci */ 298c2ecf20Sopenharmony_cistatic int __init mpi_init(void) 308c2ecf20Sopenharmony_ci{ 318c2ecf20Sopenharmony_ci int idx; 328c2ecf20Sopenharmony_ci unsigned long value; 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci for (idx = 0; idx < MPI_NUMBER_OF_CONSTANTS; idx++) { 358c2ecf20Sopenharmony_ci switch (idx) { 368c2ecf20Sopenharmony_ci case MPI_C_ZERO: 378c2ecf20Sopenharmony_ci value = 0; 388c2ecf20Sopenharmony_ci break; 398c2ecf20Sopenharmony_ci case MPI_C_ONE: 408c2ecf20Sopenharmony_ci value = 1; 418c2ecf20Sopenharmony_ci break; 428c2ecf20Sopenharmony_ci case MPI_C_TWO: 438c2ecf20Sopenharmony_ci value = 2; 448c2ecf20Sopenharmony_ci break; 458c2ecf20Sopenharmony_ci case MPI_C_THREE: 468c2ecf20Sopenharmony_ci value = 3; 478c2ecf20Sopenharmony_ci break; 488c2ecf20Sopenharmony_ci case MPI_C_FOUR: 498c2ecf20Sopenharmony_ci value = 4; 508c2ecf20Sopenharmony_ci break; 518c2ecf20Sopenharmony_ci case MPI_C_EIGHT: 528c2ecf20Sopenharmony_ci value = 8; 538c2ecf20Sopenharmony_ci break; 548c2ecf20Sopenharmony_ci default: 558c2ecf20Sopenharmony_ci pr_err("MPI: invalid mpi_const selector %d\n", idx); 568c2ecf20Sopenharmony_ci return -EFAULT; 578c2ecf20Sopenharmony_ci } 588c2ecf20Sopenharmony_ci constants[idx] = mpi_alloc_set_ui(value); 598c2ecf20Sopenharmony_ci constants[idx]->flags = (16|32); 608c2ecf20Sopenharmony_ci } 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci return 0; 638c2ecf20Sopenharmony_ci} 648c2ecf20Sopenharmony_cipostcore_initcall(mpi_init); 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci/* Return a constant MPI descripbed by NO which is one of the 678c2ecf20Sopenharmony_ci * MPI_C_xxx macros. There is no need to copy this returned value; it 688c2ecf20Sopenharmony_ci * may be used directly. 698c2ecf20Sopenharmony_ci */ 708c2ecf20Sopenharmony_ciMPI mpi_const(enum gcry_mpi_constants no) 718c2ecf20Sopenharmony_ci{ 728c2ecf20Sopenharmony_ci if ((int)no < 0 || no > MPI_NUMBER_OF_CONSTANTS) 738c2ecf20Sopenharmony_ci pr_err("MPI: invalid mpi_const selector %d\n", no); 748c2ecf20Sopenharmony_ci if (!constants[no]) 758c2ecf20Sopenharmony_ci pr_err("MPI: MPI subsystem not initialized\n"); 768c2ecf20Sopenharmony_ci return constants[no]; 778c2ecf20Sopenharmony_ci} 788c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mpi_const); 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci/**************** 818c2ecf20Sopenharmony_ci * Note: It was a bad idea to use the number of limbs to allocate 828c2ecf20Sopenharmony_ci * because on a alpha the limbs are large but we normally need 838c2ecf20Sopenharmony_ci * integers of n bits - So we should chnage this to bits (or bytes). 848c2ecf20Sopenharmony_ci * 858c2ecf20Sopenharmony_ci * But mpi_alloc is used in a lot of places :-) 868c2ecf20Sopenharmony_ci */ 878c2ecf20Sopenharmony_ciMPI mpi_alloc(unsigned nlimbs) 888c2ecf20Sopenharmony_ci{ 898c2ecf20Sopenharmony_ci MPI a; 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci a = kmalloc(sizeof *a, GFP_KERNEL); 928c2ecf20Sopenharmony_ci if (!a) 938c2ecf20Sopenharmony_ci return a; 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci if (nlimbs) { 968c2ecf20Sopenharmony_ci a->d = mpi_alloc_limb_space(nlimbs); 978c2ecf20Sopenharmony_ci if (!a->d) { 988c2ecf20Sopenharmony_ci kfree(a); 998c2ecf20Sopenharmony_ci return NULL; 1008c2ecf20Sopenharmony_ci } 1018c2ecf20Sopenharmony_ci } else { 1028c2ecf20Sopenharmony_ci a->d = NULL; 1038c2ecf20Sopenharmony_ci } 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci a->alloced = nlimbs; 1068c2ecf20Sopenharmony_ci a->nlimbs = 0; 1078c2ecf20Sopenharmony_ci a->sign = 0; 1088c2ecf20Sopenharmony_ci a->flags = 0; 1098c2ecf20Sopenharmony_ci a->nbits = 0; 1108c2ecf20Sopenharmony_ci return a; 1118c2ecf20Sopenharmony_ci} 1128c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mpi_alloc); 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_cimpi_ptr_t mpi_alloc_limb_space(unsigned nlimbs) 1158c2ecf20Sopenharmony_ci{ 1168c2ecf20Sopenharmony_ci size_t len = nlimbs * sizeof(mpi_limb_t); 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci if (!len) 1198c2ecf20Sopenharmony_ci return NULL; 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci return kmalloc(len, GFP_KERNEL); 1228c2ecf20Sopenharmony_ci} 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_civoid mpi_free_limb_space(mpi_ptr_t a) 1258c2ecf20Sopenharmony_ci{ 1268c2ecf20Sopenharmony_ci if (!a) 1278c2ecf20Sopenharmony_ci return; 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci kfree_sensitive(a); 1308c2ecf20Sopenharmony_ci} 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_civoid mpi_assign_limb_space(MPI a, mpi_ptr_t ap, unsigned nlimbs) 1338c2ecf20Sopenharmony_ci{ 1348c2ecf20Sopenharmony_ci mpi_free_limb_space(a->d); 1358c2ecf20Sopenharmony_ci a->d = ap; 1368c2ecf20Sopenharmony_ci a->alloced = nlimbs; 1378c2ecf20Sopenharmony_ci} 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci/**************** 1408c2ecf20Sopenharmony_ci * Resize the array of A to NLIMBS. the additional space is cleared 1418c2ecf20Sopenharmony_ci * (set to 0) [done by m_realloc()] 1428c2ecf20Sopenharmony_ci */ 1438c2ecf20Sopenharmony_ciint mpi_resize(MPI a, unsigned nlimbs) 1448c2ecf20Sopenharmony_ci{ 1458c2ecf20Sopenharmony_ci void *p; 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci if (nlimbs <= a->alloced) 1488c2ecf20Sopenharmony_ci return 0; /* no need to do it */ 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci if (a->d) { 1518c2ecf20Sopenharmony_ci p = kcalloc(nlimbs, sizeof(mpi_limb_t), GFP_KERNEL); 1528c2ecf20Sopenharmony_ci if (!p) 1538c2ecf20Sopenharmony_ci return -ENOMEM; 1548c2ecf20Sopenharmony_ci memcpy(p, a->d, a->alloced * sizeof(mpi_limb_t)); 1558c2ecf20Sopenharmony_ci kfree_sensitive(a->d); 1568c2ecf20Sopenharmony_ci a->d = p; 1578c2ecf20Sopenharmony_ci } else { 1588c2ecf20Sopenharmony_ci a->d = kcalloc(nlimbs, sizeof(mpi_limb_t), GFP_KERNEL); 1598c2ecf20Sopenharmony_ci if (!a->d) 1608c2ecf20Sopenharmony_ci return -ENOMEM; 1618c2ecf20Sopenharmony_ci } 1628c2ecf20Sopenharmony_ci a->alloced = nlimbs; 1638c2ecf20Sopenharmony_ci return 0; 1648c2ecf20Sopenharmony_ci} 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_civoid mpi_clear(MPI a) 1678c2ecf20Sopenharmony_ci{ 1688c2ecf20Sopenharmony_ci if (!a) 1698c2ecf20Sopenharmony_ci return; 1708c2ecf20Sopenharmony_ci a->nlimbs = 0; 1718c2ecf20Sopenharmony_ci a->flags = 0; 1728c2ecf20Sopenharmony_ci} 1738c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mpi_clear); 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_civoid mpi_free(MPI a) 1768c2ecf20Sopenharmony_ci{ 1778c2ecf20Sopenharmony_ci if (!a) 1788c2ecf20Sopenharmony_ci return; 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci if (a->flags & 4) 1818c2ecf20Sopenharmony_ci kfree_sensitive(a->d); 1828c2ecf20Sopenharmony_ci else 1838c2ecf20Sopenharmony_ci mpi_free_limb_space(a->d); 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci if (a->flags & ~7) 1868c2ecf20Sopenharmony_ci pr_info("invalid flag value in mpi\n"); 1878c2ecf20Sopenharmony_ci kfree(a); 1888c2ecf20Sopenharmony_ci} 1898c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mpi_free); 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci/**************** 1928c2ecf20Sopenharmony_ci * Note: This copy function should not interpret the MPI 1938c2ecf20Sopenharmony_ci * but copy it transparently. 1948c2ecf20Sopenharmony_ci */ 1958c2ecf20Sopenharmony_ciMPI mpi_copy(MPI a) 1968c2ecf20Sopenharmony_ci{ 1978c2ecf20Sopenharmony_ci int i; 1988c2ecf20Sopenharmony_ci MPI b; 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci if (a) { 2018c2ecf20Sopenharmony_ci b = mpi_alloc(a->nlimbs); 2028c2ecf20Sopenharmony_ci b->nlimbs = a->nlimbs; 2038c2ecf20Sopenharmony_ci b->sign = a->sign; 2048c2ecf20Sopenharmony_ci b->flags = a->flags; 2058c2ecf20Sopenharmony_ci b->flags &= ~(16|32); /* Reset the immutable and constant flags. */ 2068c2ecf20Sopenharmony_ci for (i = 0; i < b->nlimbs; i++) 2078c2ecf20Sopenharmony_ci b->d[i] = a->d[i]; 2088c2ecf20Sopenharmony_ci } else 2098c2ecf20Sopenharmony_ci b = NULL; 2108c2ecf20Sopenharmony_ci return b; 2118c2ecf20Sopenharmony_ci} 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci/**************** 2148c2ecf20Sopenharmony_ci * This function allocates an MPI which is optimized to hold 2158c2ecf20Sopenharmony_ci * a value as large as the one given in the argument and allocates it 2168c2ecf20Sopenharmony_ci * with the same flags as A. 2178c2ecf20Sopenharmony_ci */ 2188c2ecf20Sopenharmony_ciMPI mpi_alloc_like(MPI a) 2198c2ecf20Sopenharmony_ci{ 2208c2ecf20Sopenharmony_ci MPI b; 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci if (a) { 2238c2ecf20Sopenharmony_ci b = mpi_alloc(a->nlimbs); 2248c2ecf20Sopenharmony_ci b->nlimbs = 0; 2258c2ecf20Sopenharmony_ci b->sign = 0; 2268c2ecf20Sopenharmony_ci b->flags = a->flags; 2278c2ecf20Sopenharmony_ci } else 2288c2ecf20Sopenharmony_ci b = NULL; 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci return b; 2318c2ecf20Sopenharmony_ci} 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci/* Set U into W and release U. If W is NULL only U will be released. */ 2358c2ecf20Sopenharmony_civoid mpi_snatch(MPI w, MPI u) 2368c2ecf20Sopenharmony_ci{ 2378c2ecf20Sopenharmony_ci if (w) { 2388c2ecf20Sopenharmony_ci mpi_assign_limb_space(w, u->d, u->alloced); 2398c2ecf20Sopenharmony_ci w->nlimbs = u->nlimbs; 2408c2ecf20Sopenharmony_ci w->sign = u->sign; 2418c2ecf20Sopenharmony_ci w->flags = u->flags; 2428c2ecf20Sopenharmony_ci u->alloced = 0; 2438c2ecf20Sopenharmony_ci u->nlimbs = 0; 2448c2ecf20Sopenharmony_ci u->d = NULL; 2458c2ecf20Sopenharmony_ci } 2468c2ecf20Sopenharmony_ci mpi_free(u); 2478c2ecf20Sopenharmony_ci} 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ciMPI mpi_set(MPI w, MPI u) 2518c2ecf20Sopenharmony_ci{ 2528c2ecf20Sopenharmony_ci mpi_ptr_t wp, up; 2538c2ecf20Sopenharmony_ci mpi_size_t usize = u->nlimbs; 2548c2ecf20Sopenharmony_ci int usign = u->sign; 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci if (!w) 2578c2ecf20Sopenharmony_ci w = mpi_alloc(mpi_get_nlimbs(u)); 2588c2ecf20Sopenharmony_ci RESIZE_IF_NEEDED(w, usize); 2598c2ecf20Sopenharmony_ci wp = w->d; 2608c2ecf20Sopenharmony_ci up = u->d; 2618c2ecf20Sopenharmony_ci MPN_COPY(wp, up, usize); 2628c2ecf20Sopenharmony_ci w->nlimbs = usize; 2638c2ecf20Sopenharmony_ci w->flags = u->flags; 2648c2ecf20Sopenharmony_ci w->flags &= ~(16|32); /* Reset the immutable and constant flags. */ 2658c2ecf20Sopenharmony_ci w->sign = usign; 2668c2ecf20Sopenharmony_ci return w; 2678c2ecf20Sopenharmony_ci} 2688c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mpi_set); 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ciMPI mpi_set_ui(MPI w, unsigned long u) 2718c2ecf20Sopenharmony_ci{ 2728c2ecf20Sopenharmony_ci if (!w) 2738c2ecf20Sopenharmony_ci w = mpi_alloc(1); 2748c2ecf20Sopenharmony_ci /* FIXME: If U is 0 we have no need to resize and thus possible 2758c2ecf20Sopenharmony_ci * allocating the the limbs. 2768c2ecf20Sopenharmony_ci */ 2778c2ecf20Sopenharmony_ci RESIZE_IF_NEEDED(w, 1); 2788c2ecf20Sopenharmony_ci w->d[0] = u; 2798c2ecf20Sopenharmony_ci w->nlimbs = u ? 1 : 0; 2808c2ecf20Sopenharmony_ci w->sign = 0; 2818c2ecf20Sopenharmony_ci w->flags = 0; 2828c2ecf20Sopenharmony_ci return w; 2838c2ecf20Sopenharmony_ci} 2848c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(mpi_set_ui); 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ciMPI mpi_alloc_set_ui(unsigned long u) 2878c2ecf20Sopenharmony_ci{ 2888c2ecf20Sopenharmony_ci MPI w = mpi_alloc(1); 2898c2ecf20Sopenharmony_ci w->d[0] = u; 2908c2ecf20Sopenharmony_ci w->nlimbs = u ? 1 : 0; 2918c2ecf20Sopenharmony_ci w->sign = 0; 2928c2ecf20Sopenharmony_ci return w; 2938c2ecf20Sopenharmony_ci} 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci/**************** 2968c2ecf20Sopenharmony_ci * Swap the value of A and B, when SWAP is 1. 2978c2ecf20Sopenharmony_ci * Leave the value when SWAP is 0. 2988c2ecf20Sopenharmony_ci * This implementation should be constant-time regardless of SWAP. 2998c2ecf20Sopenharmony_ci */ 3008c2ecf20Sopenharmony_civoid mpi_swap_cond(MPI a, MPI b, unsigned long swap) 3018c2ecf20Sopenharmony_ci{ 3028c2ecf20Sopenharmony_ci mpi_size_t i; 3038c2ecf20Sopenharmony_ci mpi_size_t nlimbs; 3048c2ecf20Sopenharmony_ci mpi_limb_t mask = ((mpi_limb_t)0) - swap; 3058c2ecf20Sopenharmony_ci mpi_limb_t x; 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci if (a->alloced > b->alloced) 3088c2ecf20Sopenharmony_ci nlimbs = b->alloced; 3098c2ecf20Sopenharmony_ci else 3108c2ecf20Sopenharmony_ci nlimbs = a->alloced; 3118c2ecf20Sopenharmony_ci if (a->nlimbs > nlimbs || b->nlimbs > nlimbs) 3128c2ecf20Sopenharmony_ci return; 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci for (i = 0; i < nlimbs; i++) { 3158c2ecf20Sopenharmony_ci x = mask & (a->d[i] ^ b->d[i]); 3168c2ecf20Sopenharmony_ci a->d[i] = a->d[i] ^ x; 3178c2ecf20Sopenharmony_ci b->d[i] = b->d[i] ^ x; 3188c2ecf20Sopenharmony_ci } 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci x = mask & (a->nlimbs ^ b->nlimbs); 3218c2ecf20Sopenharmony_ci a->nlimbs = a->nlimbs ^ x; 3228c2ecf20Sopenharmony_ci b->nlimbs = b->nlimbs ^ x; 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci x = mask & (a->sign ^ b->sign); 3258c2ecf20Sopenharmony_ci a->sign = a->sign ^ x; 3268c2ecf20Sopenharmony_ci b->sign = b->sign ^ x; 3278c2ecf20Sopenharmony_ci} 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Multiprecision maths library"); 3308c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 331