Implement MPI multiplication.

This commit is contained in:
Dag-Erling Smørgrav 2017-04-05 21:04:16 +02:00
parent 5170c0bc41
commit 2a66f62078
5 changed files with 206 additions and 4 deletions

View file

@ -65,6 +65,8 @@ const char *cryb_mpi_version(void);
#define mpi_lsb cryb_mpi_lsb #define mpi_lsb cryb_mpi_lsb
#define mpi_lshift cryb_mpi_lshift #define mpi_lshift cryb_mpi_lshift
#define mpi_msb cryb_mpi_msb #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_negate cryb_mpi_negate
#define mpi_rshift cryb_mpi_rshift #define mpi_rshift cryb_mpi_rshift
#define mpi_set cryb_mpi_set #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 *); unsigned int mpi_lsb(const cryb_mpi *);
int mpi_lshift(cryb_mpi *, unsigned int); int mpi_lshift(cryb_mpi *, unsigned int);
unsigned int mpi_msb(const cryb_mpi *); 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 *); void mpi_negate(cryb_mpi *);
int mpi_rshift(cryb_mpi *, unsigned int); int mpi_rshift(cryb_mpi *, unsigned int);
int mpi_set(cryb_mpi *, int32_t); int mpi_set(cryb_mpi *, int32_t);

View file

@ -22,6 +22,8 @@ libcryb_mpi_la_SOURCES = \
cryb_mpi_lsb.c \ cryb_mpi_lsb.c \
cryb_mpi_lshift.c \ cryb_mpi_lshift.c \
cryb_mpi_msb.c \ cryb_mpi_msb.c \
cryb_mpi_mul.c \
cryb_mpi_mul_abs.c \
cryb_mpi_negate.c \ cryb_mpi_negate.c \
cryb_mpi_rshift.c \ cryb_mpi_rshift.c \
cryb_mpi_set.c \ cryb_mpi_set.c \

54
lib/mpi/cryb_mpi_mul.c Normal file
View file

@ -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 <stddef.h>
#include <stdint.h>
#include <cryb/mpi.h>
#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);
}

104
lib/mpi/cryb_mpi_mul_abs.c Normal file
View file

@ -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 <stddef.h>
#include <stdint.h>
#include <strings.h>
#include <cryb/bitwise.h>
#include <cryb/mpi.h>
#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);
}

View file

@ -59,12 +59,54 @@ static struct t_mul_case {
size_t emsb; size_t emsb;
int eneg:1; int eneg:1;
} t_mul_cases[] = { } 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", "1 * 1 == 1",
{ 0x01 }, 1, 0, { 0x01 }, 1, 0,
{ 0x01 }, 1, 0, { 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 static int
@ -81,11 +123,7 @@ t_mpi_mul_tc(char **desc CRYB_UNUSED, void *arg)
b.neg = tc->bneg; b.neg = tc->bneg;
mpi_load(&e, tc->e, (tc->emsb + 7) / 8); mpi_load(&e, tc->e, (tc->emsb + 7) / 8);
e.neg = tc->eneg; e.neg = tc->eneg;
#if 0
ret &= t_compare_i(0, mpi_mul_abs(&x, &a, &b)); 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); ret &= t_compare_mpi(&e, &x);
mpi_destroy(&a); mpi_destroy(&a);
mpi_destroy(&b); mpi_destroy(&b);