aboutsummaryrefslogtreecommitdiffstats
path: root/lib/mpi/mpicoder.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/mpi/mpicoder.c')
-rw-r--r--lib/mpi/mpicoder.c218
1 files changed, 215 insertions, 3 deletions
diff --git a/lib/mpi/mpicoder.c b/lib/mpi/mpicoder.c
index 95c52a95259e..ec533a6c77b5 100644
--- a/lib/mpi/mpicoder.c
+++ b/lib/mpi/mpicoder.c
@@ -19,7 +19,7 @@
19 */ 19 */
20 20
21#include <linux/bitops.h> 21#include <linux/bitops.h>
22#include <asm-generic/bitops/count_zeros.h> 22#include <linux/count_zeros.h>
23#include "mpi-internal.h" 23#include "mpi-internal.h"
24 24
25#define MAX_EXTERN_MPI_BITS 16384 25#define MAX_EXTERN_MPI_BITS 16384
@@ -135,7 +135,9 @@ EXPORT_SYMBOL_GPL(mpi_read_from_buffer);
135 * @buf: bufer to which the output will be written to. Needs to be at 135 * @buf: bufer to which the output will be written to. Needs to be at
136 * leaset mpi_get_size(a) long. 136 * leaset mpi_get_size(a) long.
137 * @buf_len: size of the buf. 137 * @buf_len: size of the buf.
138 * @nbytes: receives the actual length of the data written. 138 * @nbytes: receives the actual length of the data written on success and
139 * the data to-be-written on -EOVERFLOW in case buf_len was too
140 * small.
139 * @sign: if not NULL, it will be set to the sign of a. 141 * @sign: if not NULL, it will be set to the sign of a.
140 * 142 *
141 * Return: 0 on success or error code in case of error 143 * Return: 0 on success or error code in case of error
@@ -148,7 +150,7 @@ int mpi_read_buffer(MPI a, uint8_t *buf, unsigned buf_len, unsigned *nbytes,
148 unsigned int n = mpi_get_size(a); 150 unsigned int n = mpi_get_size(a);
149 int i, lzeros = 0; 151 int i, lzeros = 0;
150 152
151 if (buf_len < n || !buf || !nbytes) 153 if (!buf || !nbytes)
152 return -EINVAL; 154 return -EINVAL;
153 155
154 if (sign) 156 if (sign)
@@ -163,6 +165,11 @@ int mpi_read_buffer(MPI a, uint8_t *buf, unsigned buf_len, unsigned *nbytes,
163 break; 165 break;
164 } 166 }
165 167
168 if (buf_len < n - lzeros) {
169 *nbytes = n - lzeros;
170 return -EOVERFLOW;
171 }
172
166 p = buf; 173 p = buf;
167 *nbytes = n - lzeros; 174 *nbytes = n - lzeros;
168 175
@@ -319,3 +326,208 @@ int mpi_set_buffer(MPI a, const void *xbuffer, unsigned nbytes, int sign)
319 return 0; 326 return 0;
320} 327}
321EXPORT_SYMBOL_GPL(mpi_set_buffer); 328EXPORT_SYMBOL_GPL(mpi_set_buffer);
329
330/**
331 * mpi_write_to_sgl() - Funnction exports MPI to an sgl (msb first)
332 *
333 * This function works in the same way as the mpi_read_buffer, but it
334 * takes an sgl instead of u8 * buf.
335 *
336 * @a: a multi precision integer
337 * @sgl: scatterlist to write to. Needs to be at least
338 * mpi_get_size(a) long.
339 * @nbytes: in/out param - it has the be set to the maximum number of
340 * bytes that can be written to sgl. This has to be at least
341 * the size of the integer a. On return it receives the actual
342 * length of the data written on success or the data that would
343 * be written if buffer was too small.
344 * @sign: if not NULL, it will be set to the sign of a.
345 *
346 * Return: 0 on success or error code in case of error
347 */
348int mpi_write_to_sgl(MPI a, struct scatterlist *sgl, unsigned *nbytes,
349 int *sign)
350{
351 u8 *p, *p2;
352 mpi_limb_t alimb, alimb2;
353 unsigned int n = mpi_get_size(a);
354 int i, x, y = 0, lzeros = 0, buf_len;
355
356 if (!nbytes)
357 return -EINVAL;
358
359 if (sign)
360 *sign = a->sign;
361
362 p = (void *)&a->d[a->nlimbs] - 1;
363
364 for (i = a->nlimbs * sizeof(alimb) - 1; i >= 0; i--, p--) {
365 if (!*p)
366 lzeros++;
367 else
368 break;
369 }
370
371 if (*nbytes < n - lzeros) {
372 *nbytes = n - lzeros;
373 return -EOVERFLOW;
374 }
375
376 *nbytes = n - lzeros;
377 buf_len = sgl->length;
378 p2 = sg_virt(sgl);
379
380 for (i = a->nlimbs - 1; i >= 0; i--) {
381 alimb = a->d[i];
382 p = (u8 *)&alimb2;
383#if BYTES_PER_MPI_LIMB == 4
384 *p++ = alimb >> 24;
385 *p++ = alimb >> 16;
386 *p++ = alimb >> 8;
387 *p++ = alimb;
388#elif BYTES_PER_MPI_LIMB == 8
389 *p++ = alimb >> 56;
390 *p++ = alimb >> 48;
391 *p++ = alimb >> 40;
392 *p++ = alimb >> 32;
393 *p++ = alimb >> 24;
394 *p++ = alimb >> 16;
395 *p++ = alimb >> 8;
396 *p++ = alimb;
397#else
398#error please implement for this limb size.
399#endif
400 if (lzeros > 0) {
401 if (lzeros >= sizeof(alimb)) {
402 p -= sizeof(alimb);
403 continue;
404 } else {
405 mpi_limb_t *limb1 = (void *)p - sizeof(alimb);
406 mpi_limb_t *limb2 = (void *)p - sizeof(alimb)
407 + lzeros;
408 *limb1 = *limb2;
409 p -= lzeros;
410 y = lzeros;
411 }
412 lzeros -= sizeof(alimb);
413 }
414
415 p = p - (sizeof(alimb) - y);
416
417 for (x = 0; x < sizeof(alimb) - y; x++) {
418 if (!buf_len) {
419 sgl = sg_next(sgl);
420 if (!sgl)
421 return -EINVAL;
422 buf_len = sgl->length;
423 p2 = sg_virt(sgl);
424 }
425 *p2++ = *p++;
426 buf_len--;
427 }
428 y = 0;
429 }
430 return 0;
431}
432EXPORT_SYMBOL_GPL(mpi_write_to_sgl);
433
434/*
435 * mpi_read_raw_from_sgl() - Function allocates an MPI and populates it with
436 * data from the sgl
437 *
438 * This function works in the same way as the mpi_read_raw_data, but it
439 * takes an sgl instead of void * buffer. i.e. it allocates
440 * a new MPI and reads the content of the sgl to the MPI.
441 *
442 * @sgl: scatterlist to read from
443 * @len: number of bytes to read
444 *
445 * Return: Pointer to a new MPI or NULL on error
446 */
447MPI mpi_read_raw_from_sgl(struct scatterlist *sgl, unsigned int len)
448{
449 struct scatterlist *sg;
450 int x, i, j, z, lzeros, ents;
451 unsigned int nbits, nlimbs, nbytes;
452 mpi_limb_t a;
453 MPI val = NULL;
454
455 lzeros = 0;
456 ents = sg_nents(sgl);
457
458 for_each_sg(sgl, sg, ents, i) {
459 const u8 *buff = sg_virt(sg);
460 int len = sg->length;
461
462 while (len && !*buff) {
463 lzeros++;
464 len--;
465 buff++;
466 }
467
468 if (len && *buff)
469 break;
470
471 ents--;
472 lzeros = 0;
473 }
474
475 sgl = sg;
476
477 if (!ents)
478 nbytes = 0;
479 else
480 nbytes = len - lzeros;
481
482 nbits = nbytes * 8;
483 if (nbits > MAX_EXTERN_MPI_BITS) {
484 pr_info("MPI: mpi too large (%u bits)\n", nbits);
485 return NULL;
486 }
487
488 if (nbytes > 0)
489 nbits -= count_leading_zeros(*(u8 *)(sg_virt(sgl) + lzeros));
490 else
491 nbits = 0;
492
493 nlimbs = DIV_ROUND_UP(nbytes, BYTES_PER_MPI_LIMB);
494 val = mpi_alloc(nlimbs);
495 if (!val)
496 return NULL;
497
498 val->nbits = nbits;
499 val->sign = 0;
500 val->nlimbs = nlimbs;
501
502 if (nbytes == 0)
503 return val;
504
505 j = nlimbs - 1;
506 a = 0;
507 z = 0;
508 x = BYTES_PER_MPI_LIMB - nbytes % BYTES_PER_MPI_LIMB;
509 x %= BYTES_PER_MPI_LIMB;
510
511 for_each_sg(sgl, sg, ents, i) {
512 const u8 *buffer = sg_virt(sg) + lzeros;
513 int len = sg->length - lzeros;
514 int buf_shift = x;
515
516 if (sg_is_last(sg) && (len % BYTES_PER_MPI_LIMB))
517 len += BYTES_PER_MPI_LIMB - (len % BYTES_PER_MPI_LIMB);
518
519 for (; x < len + buf_shift; x++) {
520 a <<= 8;
521 a |= *buffer++;
522 if (((z + x + 1) % BYTES_PER_MPI_LIMB) == 0) {
523 val->d[j--] = a;
524 a = 0;
525 }
526 }
527 z += x;
528 x = 0;
529 lzeros = 0;
530 }
531 return val;
532}
533EXPORT_SYMBOL_GPL(mpi_read_raw_from_sgl);