Merge commit '4cb38750d49010ae72e718d46605ac9ba5a851b4' into stable/for-linus-3.6
[pandora-kernel.git] / lib / mpi / mpicoder.c
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 MAX_EXTERN_MPI_BITS 16384
24
25 MPI mpi_read_from_buffer(const void *xbuffer, unsigned *ret_nread)
26 {
27         const uint8_t *buffer = xbuffer;
28         int i, j;
29         unsigned nbits, nbytes, nlimbs, nread = 0;
30         mpi_limb_t a;
31         MPI val = NULL;
32
33         if (*ret_nread < 2)
34                 goto leave;
35         nbits = buffer[0] << 8 | buffer[1];
36
37         if (nbits > MAX_EXTERN_MPI_BITS) {
38                 pr_info("MPI: mpi too large (%u bits)\n", nbits);
39                 goto leave;
40         }
41         buffer += 2;
42         nread = 2;
43
44         nbytes = (nbits + 7) / 8;
45         nlimbs = (nbytes + BYTES_PER_MPI_LIMB - 1) / BYTES_PER_MPI_LIMB;
46         val = mpi_alloc(nlimbs);
47         if (!val)
48                 return NULL;
49         i = BYTES_PER_MPI_LIMB - nbytes % BYTES_PER_MPI_LIMB;
50         i %= BYTES_PER_MPI_LIMB;
51         val->nbits = nbits;
52         j = val->nlimbs = nlimbs;
53         val->sign = 0;
54         for (; j > 0; j--) {
55                 a = 0;
56                 for (; i < BYTES_PER_MPI_LIMB; i++) {
57                         if (++nread > *ret_nread) {
58                                 printk
59                                     ("MPI: mpi larger than buffer nread=%d ret_nread=%d\n",
60                                      nread, *ret_nread);
61                                 goto leave;
62                         }
63                         a <<= 8;
64                         a |= *buffer++;
65                 }
66                 i = 0;
67                 val->d[j - 1] = a;
68         }
69
70 leave:
71         *ret_nread = nread;
72         return val;
73 }
74 EXPORT_SYMBOL_GPL(mpi_read_from_buffer);
75
76 /****************
77  * Return an allocated buffer with the MPI (msb first).
78  * NBYTES receives the length of this buffer. Caller must free the
79  * return string (This function does return a 0 byte buffer with NBYTES
80  * set to zero if the value of A is zero. If sign is not NULL, it will
81  * be set to the sign of the A.
82  */
83 void *mpi_get_buffer(MPI a, unsigned *nbytes, int *sign)
84 {
85         uint8_t *p, *buffer;
86         mpi_limb_t alimb;
87         int i;
88         unsigned int n;
89
90         if (sign)
91                 *sign = a->sign;
92         *nbytes = n = a->nlimbs * BYTES_PER_MPI_LIMB;
93         if (!n)
94                 n++;            /* avoid zero length allocation */
95         p = buffer = kmalloc(n, GFP_KERNEL);
96         if (!p)
97                 return NULL;
98
99         for (i = a->nlimbs - 1; i >= 0; i--) {
100                 alimb = a->d[i];
101 #if BYTES_PER_MPI_LIMB == 4
102                 *p++ = alimb >> 24;
103                 *p++ = alimb >> 16;
104                 *p++ = alimb >> 8;
105                 *p++ = alimb;
106 #elif BYTES_PER_MPI_LIMB == 8
107                 *p++ = alimb >> 56;
108                 *p++ = alimb >> 48;
109                 *p++ = alimb >> 40;
110                 *p++ = alimb >> 32;
111                 *p++ = alimb >> 24;
112                 *p++ = alimb >> 16;
113                 *p++ = alimb >> 8;
114                 *p++ = alimb;
115 #else
116 #error please implement for this limb size.
117 #endif
118         }
119
120         /* this is sub-optimal but we need to do the shift operation
121          * because the caller has to free the returned buffer */
122         for (p = buffer; !*p && *nbytes; p++, --*nbytes)
123                 ;
124         if (p != buffer)
125                 memmove(buffer, p, *nbytes);
126
127         return buffer;
128 }
129 EXPORT_SYMBOL_GPL(mpi_get_buffer);
130
131 /****************
132  * Use BUFFER to update MPI.
133  */
134 int mpi_set_buffer(MPI a, const void *xbuffer, unsigned nbytes, int sign)
135 {
136         const uint8_t *buffer = xbuffer, *p;
137         mpi_limb_t alimb;
138         int nlimbs;
139         int i;
140
141         nlimbs = (nbytes + BYTES_PER_MPI_LIMB - 1) / BYTES_PER_MPI_LIMB;
142         if (RESIZE_IF_NEEDED(a, nlimbs) < 0)
143                 return -ENOMEM;
144         a->sign = sign;
145
146         for (i = 0, p = buffer + nbytes - 1; p >= buffer + BYTES_PER_MPI_LIMB;) {
147 #if BYTES_PER_MPI_LIMB == 4
148                 alimb = (mpi_limb_t) *p--;
149                 alimb |= (mpi_limb_t) *p-- << 8;
150                 alimb |= (mpi_limb_t) *p-- << 16;
151                 alimb |= (mpi_limb_t) *p-- << 24;
152 #elif BYTES_PER_MPI_LIMB == 8
153                 alimb = (mpi_limb_t) *p--;
154                 alimb |= (mpi_limb_t) *p-- << 8;
155                 alimb |= (mpi_limb_t) *p-- << 16;
156                 alimb |= (mpi_limb_t) *p-- << 24;
157                 alimb |= (mpi_limb_t) *p-- << 32;
158                 alimb |= (mpi_limb_t) *p-- << 40;
159                 alimb |= (mpi_limb_t) *p-- << 48;
160                 alimb |= (mpi_limb_t) *p-- << 56;
161 #else
162 #error please implement for this limb size.
163 #endif
164                 a->d[i++] = alimb;
165         }
166         if (p >= buffer) {
167 #if BYTES_PER_MPI_LIMB == 4
168                 alimb = *p--;
169                 if (p >= buffer)
170                         alimb |= (mpi_limb_t) *p-- << 8;
171                 if (p >= buffer)
172                         alimb |= (mpi_limb_t) *p-- << 16;
173                 if (p >= buffer)
174                         alimb |= (mpi_limb_t) *p-- << 24;
175 #elif BYTES_PER_MPI_LIMB == 8
176                 alimb = (mpi_limb_t) *p--;
177                 if (p >= buffer)
178                         alimb |= (mpi_limb_t) *p-- << 8;
179                 if (p >= buffer)
180                         alimb |= (mpi_limb_t) *p-- << 16;
181                 if (p >= buffer)
182                         alimb |= (mpi_limb_t) *p-- << 24;
183                 if (p >= buffer)
184                         alimb |= (mpi_limb_t) *p-- << 32;
185                 if (p >= buffer)
186                         alimb |= (mpi_limb_t) *p-- << 40;
187                 if (p >= buffer)
188                         alimb |= (mpi_limb_t) *p-- << 48;
189                 if (p >= buffer)
190                         alimb |= (mpi_limb_t) *p-- << 56;
191 #else
192 #error please implement for this limb size.
193 #endif
194                 a->d[i++] = alimb;
195         }
196         a->nlimbs = i;
197
198         if (i != nlimbs) {
199                 pr_emerg("MPI: mpi_set_buffer: Assertion failed (%d != %d)", i,
200                        nlimbs);
201                 BUG();
202         }
203         return 0;
204 }
205 EXPORT_SYMBOL_GPL(mpi_set_buffer);