From 2a66f620783cdf8d5aaf6e84e685c3579eea6829 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dag-Erling=20Sm=C3=B8rgrav?= Date: Wed, 5 Apr 2017 21:04:16 +0200 Subject: [PATCH] Implement MPI multiplication. --- include/cryb/mpi.h | 4 ++ lib/mpi/Makefile.am | 2 + lib/mpi/cryb_mpi_mul.c | 54 +++++++++++++++++++ lib/mpi/cryb_mpi_mul_abs.c | 104 +++++++++++++++++++++++++++++++++++++ t/t_mpi_muldiv.c | 46 ++++++++++++++-- 5 files changed, 206 insertions(+), 4 deletions(-) create mode 100644 lib/mpi/cryb_mpi_mul.c create mode 100644 lib/mpi/cryb_mpi_mul_abs.c diff --git a/include/cryb/mpi.h b/include/cryb/mpi.h index de147ff..d45d3fd 100644 --- a/include/cryb/mpi.h +++ b/include/cryb/mpi.h @@ -65,6 +65,8 @@ const char *cryb_mpi_version(void); #define mpi_lsb cryb_mpi_lsb #define mpi_lshift cryb_mpi_lshift #define mpi_msb cryb_mpi_msb +#define mpi_mul cryb_mpi_mul +#define mpi_mul_abs cryb_mpi_mul_abs #define mpi_negate cryb_mpi_negate #define mpi_rshift cryb_mpi_rshift #define mpi_set cryb_mpi_set @@ -113,6 +115,8 @@ int mpi_load(cryb_mpi *, const uint8_t *, size_t); unsigned int mpi_lsb(const cryb_mpi *); int mpi_lshift(cryb_mpi *, unsigned int); unsigned int mpi_msb(const cryb_mpi *); +int mpi_mul(cryb_mpi *, const cryb_mpi *, const cryb_mpi *); +int mpi_mul_abs(cryb_mpi *, const cryb_mpi *, const cryb_mpi *); void mpi_negate(cryb_mpi *); int mpi_rshift(cryb_mpi *, unsigned int); int mpi_set(cryb_mpi *, int32_t); diff --git a/lib/mpi/Makefile.am b/lib/mpi/Makefile.am index 0458d7a..df4c455 100644 --- a/lib/mpi/Makefile.am +++ b/lib/mpi/Makefile.am @@ -22,6 +22,8 @@ libcryb_mpi_la_SOURCES = \ cryb_mpi_lsb.c \ cryb_mpi_lshift.c \ cryb_mpi_msb.c \ + cryb_mpi_mul.c \ + cryb_mpi_mul_abs.c \ cryb_mpi_negate.c \ cryb_mpi_rshift.c \ cryb_mpi_set.c \ diff --git a/lib/mpi/cryb_mpi_mul.c b/lib/mpi/cryb_mpi_mul.c new file mode 100644 index 0000000..b0363e2 --- /dev/null +++ b/lib/mpi/cryb_mpi_mul.c @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2017 Dag-Erling Smørgrav + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "cryb/impl.h" + +#include +#include + +#include + +#include "cryb_mpi_impl.h" + +/* + * Store the product of A and B in X. + */ +int +mpi_mul(cryb_mpi *X, const cryb_mpi *A, const cryb_mpi *B) +{ + int neg; + + neg = A->neg ^ B->neg; + if (mpi_mul_abs(X, A, B) < 0) + return (-1); + if (X->msb > 0) + X->neg = neg; + return (0); +} + diff --git a/lib/mpi/cryb_mpi_mul_abs.c b/lib/mpi/cryb_mpi_mul_abs.c new file mode 100644 index 0000000..37f5ad6 --- /dev/null +++ b/lib/mpi/cryb_mpi_mul_abs.c @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2017 Dag-Erling Smørgrav + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "cryb/impl.h" + +#include +#include +#include + +#include +#include + +#include "cryb_mpi_impl.h" + +/* + * Store the product of the absolutes values of A and B in X. + * + * Note: this is loosely based on HAC 14.2.3. However, the first + * paragraph speaks of x and y having n and t digits respectively, with + * the most significant digits being x[n - 1] and y[t - 1], but the rest + * of the section refers to x and y having n + 1 and t + 1 digits. We + * follow the former convention, but use a and b instead of n and t to + * distance ourselves from this confusing text. + */ +int +mpi_mul_abs(cryb_mpi *X, const cryb_mpi *A, const cryb_mpi *B) +{ + cryb_mpi *P, T = CRYB_MPI_ZERO; + uint64_t p; + unsigned int a, b, i, j; + uint32_t c; + + /* + * Trivial cases: A and / or B is zero. + */ + if (A->msb == 0 || B->msb == 0) { + mpi_zero(X); + return (0); + } + + /* + * Unlike addition or subtraction, we can't multiply in place, so + * if the destination is identical with one of the operands, we + * will have to use temporary storage. Either way, make sure we + * have enough room for the product. + */ + P = (X == A || X == B) ? &T : X; + mpi_zero(P); + a = (A->msb + 31) / 32; + b = (B->msb + 31) / 32; + if (mpi_grow(P, (a + b) * 32) != 0) + return (-1); + + /* + * Multiply... + */ + for (i = 0; i < b; ++i) { + for (c = j = 0; j < a; ++j) { + p = 1ULL * A->words[j] * B->words[i] + c; + P->words[i + j] += p & 0xffffffffUL; + c = p >> 32; + } + P->words[i + j] = c; + } + if (P->words[i = a + b - 1] == 0) + --i; + P->msb = i * 32 + flsl(P->words[i]); + + /* + * If we used temporary storage, copy back and clean up. + */ + if (P == &T) { + cryb_mpi_swap(X, P); + cryb_mpi_destroy(P); + } + + return (0); +} diff --git a/t/t_mpi_muldiv.c b/t/t_mpi_muldiv.c index e4c6be9..dcbad57 100644 --- a/t/t_mpi_muldiv.c +++ b/t/t_mpi_muldiv.c @@ -59,12 +59,54 @@ static struct t_mul_case { size_t emsb; int eneg:1; } t_mul_cases[] = { + { + "0 * 0 == 0", + { }, 0, 0, + { }, 0, 0, + { }, 0, 0, + }, + { + "0 * 1 == 0", + { }, 0, 0, + { 0x01 }, 1, 0, + { }, 0, 0, + }, + { + "1 * 0 == 0", + { 0x01 }, 1, 0, + { }, 0, 0, + { }, 0, 0, + }, { "1 * 1 == 1", { 0x01 }, 1, 0, { 0x01 }, 1, 0, { 0x01 }, 1, 0, }, + { + "(2^32 + 1) * (2^32 + 1) == 2^64 + 2^33 + 1", + { 0x01, 0x00, 0x00, 0x00, 0x01 }, 33, 0, + { 0x01, 0x00, 0x00, 0x00, 0x01 }, 33, 0, + { 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01 }, 65, 0, + }, + { + "(2^32 + 1) * (2^32 - 1) == 2^64 - 1", + { 0x01, 0x00, 0x00, 0x00, 0x01 }, 33, 0, + { 0xff, 0xff, 0xff, 0xff }, 32, 0, + { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, 63, 0, + }, + { + "(2^32 - 1) * (2^32 + 1) == 2^64 - 1", + { 0xff, 0xff, 0xff, 0xff }, 32, 0, + { 0x01, 0x00, 0x00, 0x00, 0x01 }, 33, 0, + { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, 63, 0, + }, + { + "(2^32 - 1) * (2^32 - 1) == 2^64 - 2^33 + 1", + { 0xff, 0xff, 0xff, 0xff }, 32, 0, + { 0xff, 0xff, 0xff, 0xff }, 32, 0, + { 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x01 }, 64, 0, + }, }; static int @@ -81,11 +123,7 @@ t_mpi_mul_tc(char **desc CRYB_UNUSED, void *arg) b.neg = tc->bneg; mpi_load(&e, tc->e, (tc->emsb + 7) / 8); e.neg = tc->eneg; -#if 0 ret &= t_compare_i(0, mpi_mul_abs(&x, &a, &b)); -#else - mpi_load(&x, tc->e, (tc->emsb + 7) / 8); -#endif ret &= t_compare_mpi(&e, &x); mpi_destroy(&a); mpi_destroy(&b);