diff options
Diffstat (limited to 'lib/mpi/mpicoder.c')
| -rw-r--r-- | lib/mpi/mpicoder.c | 218 |
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 | } |
| 321 | EXPORT_SYMBOL_GPL(mpi_set_buffer); | 328 | EXPORT_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 | */ | ||
| 348 | int 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 | } | ||
| 432 | EXPORT_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 | */ | ||
| 447 | MPI 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 | } | ||
| 533 | EXPORT_SYMBOL_GPL(mpi_read_raw_from_sgl); | ||
