Hi, Tianjia. On Thu, Jul 09, 2020 at 04:40:09PM +0800, Tianjia Zhang wrote: > Expand the mpi library based on libgcrypt, and the ECC algorithm of > mpi based on libgcrypt requires these functions. > Some other algorithms will be developed based on mpi ecc, such as SM2. > > Signed-off-by: Tianjia Zhang <tianjia.zhang@xxxxxxxxxxxxxxxxx> > --- > include/linux/mpi.h | 88 +++++++++++ > lib/mpi/Makefile | 5 + > lib/mpi/mpi-add.c | 207 +++++++++++++++++++++++++ > lib/mpi/mpi-bit.c | 251 ++++++++++++++++++++++++++++++ > lib/mpi/mpi-cmp.c | 46 ++++-- > lib/mpi/mpi-div.c | 238 +++++++++++++++++++++++++++++ > lib/mpi/mpi-internal.h | 53 +++++++ > lib/mpi/mpi-inv.c | 143 ++++++++++++++++++ > lib/mpi/mpi-mod.c | 155 +++++++++++++++++++ > lib/mpi/mpi-mul.c | 94 ++++++++++++ > lib/mpi/mpicoder.c | 336 +++++++++++++++++++++++++++++++++++++++++ > lib/mpi/mpih-div.c | 294 ++++++++++++++++++++++++++++++++++++ > lib/mpi/mpih-mul.c | 25 +++ > lib/mpi/mpiutil.c | 204 +++++++++++++++++++++++++ > 14 files changed, 2129 insertions(+), 10 deletions(-) > create mode 100644 lib/mpi/mpi-add.c > create mode 100644 lib/mpi/mpi-div.c > create mode 100644 lib/mpi/mpi-inv.c > create mode 100644 lib/mpi/mpi-mod.c > create mode 100644 lib/mpi/mpi-mul.c > > diff --git a/include/linux/mpi.h b/include/linux/mpi.h > index 7bd6d8af0004..2dddf4c6e011 100644 > --- a/include/linux/mpi.h > +++ b/include/linux/mpi.h > @@ -40,21 +40,79 @@ struct gcry_mpi { > typedef struct gcry_mpi *MPI; > > #define mpi_get_nlimbs(a) ((a)->nlimbs) > +#define mpi_has_sign(a) ((a)->sign) > > /*-- mpiutil.c --*/ > MPI mpi_alloc(unsigned nlimbs); > +void mpi_clear(MPI a); > void mpi_free(MPI a); > int mpi_resize(MPI a, unsigned nlimbs); > > +static inline MPI mpi_new(unsigned int nbits) > +{ > + return mpi_alloc((nbits + BITS_PER_MPI_LIMB - 1) / BITS_PER_MPI_LIMB); > +} > + > +MPI mpi_copy(MPI a); > +MPI mpi_alloc_like(MPI a); > +void mpi_snatch(MPI w, MPI u); > +MPI mpi_set(MPI w, MPI u); > +MPI mpi_set_ui(MPI w, unsigned long u); > +MPI mpi_alloc_set_ui(unsigned long u); > +void mpi_swap_cond(MPI a, MPI b, unsigned long swap); > + > +/* Constants used to return constant MPIs. See mpi_init if you > + * want to add more constants. > + */ > +#define MPI_NUMBER_OF_CONSTANTS 6 > +enum gcry_mpi_constants { > + MPI_C_ZERO, > + MPI_C_ONE, > + MPI_C_TWO, > + MPI_C_THREE, > + MPI_C_FOUR, > + MPI_C_EIGHT > +}; > + > +MPI mpi_const(enum gcry_mpi_constants no); > + > /*-- mpicoder.c --*/ > + > +/* Different formats of external big integer representation. */ > +enum gcry_mpi_format { > + GCRYMPI_FMT_NONE = 0, > + GCRYMPI_FMT_STD = 1, /* Twos complement stored without length. */ > + GCRYMPI_FMT_PGP = 2, /* As used by OpenPGP (unsigned only). */ > + GCRYMPI_FMT_SSH = 3, /* As used by SSH (like STD but with length). */ > + GCRYMPI_FMT_HEX = 4, /* Hex format. */ > + GCRYMPI_FMT_USG = 5, /* Like STD but unsigned. */ > + GCRYMPI_FMT_OPAQUE = 8 /* Opaque format (some functions only). */ > +}; > + > MPI mpi_read_raw_data(const void *xbuffer, size_t nbytes); > MPI mpi_read_from_buffer(const void *buffer, unsigned *ret_nread); > +int mpi_fromstr(MPI val, const char *str); > +MPI mpi_scanval(const char *string); > MPI mpi_read_raw_from_sgl(struct scatterlist *sgl, unsigned int len); > void *mpi_get_buffer(MPI a, unsigned *nbytes, int *sign); > int mpi_read_buffer(MPI a, uint8_t *buf, unsigned buf_len, unsigned *nbytes, > int *sign); > int mpi_write_to_sgl(MPI a, struct scatterlist *sg, unsigned nbytes, > int *sign); > +int mpi_print(enum gcry_mpi_format format, unsigned char *buffer, > + size_t buflen, size_t *nwritten, MPI a); > + > +/*-- mpi-mod.c --*/ > +void mpi_mod(MPI rem, MPI dividend, MPI divisor); > + > +/* Context used with Barrett reduction. */ > +struct barrett_ctx_s; > +typedef struct barrett_ctx_s *mpi_barrett_t; > + > +mpi_barrett_t mpi_barrett_init(MPI m, int copy); > +void mpi_barrett_free(mpi_barrett_t ctx); > +void mpi_mod_barrett(MPI r, MPI x, mpi_barrett_t ctx); > +void mpi_mul_barrett(MPI w, MPI u, MPI v, mpi_barrett_t ctx); > > /*-- mpi-pow.c --*/ > int mpi_powm(MPI res, MPI base, MPI exp, MPI mod); > @@ -62,10 +120,40 @@ int mpi_powm(MPI res, MPI base, MPI exp, MPI mod); > /*-- mpi-cmp.c --*/ > int mpi_cmp_ui(MPI u, ulong v); > int mpi_cmp(MPI u, MPI v); > +int mpi_cmpabs(MPI u, MPI v); > > /*-- mpi-bit.c --*/ > void mpi_normalize(MPI a); > unsigned mpi_get_nbits(MPI a); > +int mpi_test_bit(MPI a, unsigned int n); > +void mpi_set_bit(MPI a, unsigned int n); > +void mpi_set_highbit(MPI a, unsigned int n); > +void mpi_clear_highbit(MPI a, unsigned int n); > +void mpi_clear_bit(MPI a, unsigned int n); > +void mpi_rshift_limbs(MPI a, unsigned int count); > +void mpi_rshift(MPI x, MPI a, unsigned int n); > +void mpi_lshift_limbs(MPI a, unsigned int count); > +void mpi_lshift(MPI x, MPI a, unsigned int n); > + > +/*-- mpi-add.c --*/ > +void mpi_add_ui(MPI w, MPI u, unsigned long v); > +void mpi_add(MPI w, MPI u, MPI v); > +void mpi_sub_ui(MPI w, MPI u, unsigned long v); > +void mpi_sub(MPI w, MPI u, MPI v); > +void mpi_addm(MPI w, MPI u, MPI v, MPI m); > +void mpi_subm(MPI w, MPI u, MPI v, MPI m); > + > +/*-- mpi-mul.c --*/ > +void mpi_mul(MPI w, MPI u, MPI v); > +void mpi_mulm(MPI w, MPI u, MPI v, MPI m); > + > +/*-- mpi-div.c --*/ > +void mpi_tdiv_r(MPI rem, MPI num, MPI den); > +void mpi_fdiv_r(MPI rem, MPI dividend, MPI divisor); > +void mpi_fdiv_q(MPI quot, MPI dividend, MPI divisor); > + > +/*-- mpi-inv.c --*/ > +int mpi_invm(MPI x, MPI a, MPI n); > > /* inline functions */ > > diff --git a/lib/mpi/Makefile b/lib/mpi/Makefile > index d5874a7f5ff9..5f40f93ff3d9 100644 > --- a/lib/mpi/Makefile > +++ b/lib/mpi/Makefile > @@ -14,8 +14,13 @@ mpi-y = \ > generic_mpih-sub1.o \ > generic_mpih-add1.o \ > mpicoder.o \ > + mpi-add.o \ > mpi-bit.o \ > mpi-cmp.o \ > + mpi-div.o \ > + mpi-inv.o \ > + mpi-mod.o \ > + mpi-mul.o \ > mpih-cmp.o \ > mpih-div.o \ > mpih-mul.o \ > diff --git a/lib/mpi/mpi-add.c b/lib/mpi/mpi-add.c > new file mode 100644 > index 000000000000..9afad7832737 > --- /dev/null > +++ b/lib/mpi/mpi-add.c > @@ -0,0 +1,207 @@ > +/* mpi-add.c - MPI functions > + * Copyright (C) 1994, 1996, 1998, 2001, 2002, > + * 2003 Free Software Foundation, Inc. > + * > + * This file is part of Libgcrypt. > + * > + * Note: This code is heavily based on the GNU MP Library. > + * Actually it's the same code with only minor changes in the > + * way the data is stored; this is to support the abstraction > + * of an optional secure memory allocation which may be used > + * to avoid revealing of sensitive data due to paging etc. > + */ > + > +#include "mpi-internal.h" > + > +/**************** > + * Add the unsigned integer V to the mpi-integer U and store the > + * result in W. U and V may be the same. > + */ > +void mpi_add_ui(MPI w, MPI u, unsigned long v) > +{ > + mpi_ptr_t wp, up; > + mpi_size_t usize, wsize; > + int usign, wsign; > + > + usize = u->nlimbs; > + usign = u->sign; > + wsign = 0; > + > + /* If not space for W (and possible carry), increase space. */ > + wsize = usize + 1; > + if (w->alloced < wsize) > + mpi_resize(w, wsize); You are ignoring the mpi_resize() return. I believe these new functions need to return an int to indicate errors as mpi_powm() does. > + > + /* These must be after realloc (U may be the same as W). */ > + up = u->d; > + wp = w->d; > + > + if (!usize) { /* simple */ > + wp[0] = v; > + wsize = v ? 1:0; > + } else if (!usign) { /* mpi is not negative */ > + mpi_limb_t cy; > + cy = mpihelp_add_1(wp, up, usize, v); > + wp[usize] = cy; > + wsize = usize + cy; > + } else { > + /* The signs are different. Need exact comparison to determine > + * which operand to subtract from which. > + */ > + if (usize == 1 && up[0] < v) { > + wp[0] = v - up[0]; > + wsize = 1; > + } else { > + mpihelp_sub_1(wp, up, usize, v); > + /* Size can decrease with at most one limb. */ > + wsize = usize - (wp[usize-1] == 0); > + wsign = 1; > + } > + } > + > + w->nlimbs = wsize; > + w->sign = wsign; > +} > + > + > +void mpi_add(MPI w, MPI u, MPI v) > +{ > + mpi_ptr_t wp, up, vp; > + mpi_size_t usize, vsize, wsize; > + int usign, vsign, wsign; > + > + if (u->nlimbs < v->nlimbs) { /* Swap U and V. */ > + usize = v->nlimbs; > + usign = v->sign; > + vsize = u->nlimbs; > + vsign = u->sign; > + wsize = usize + 1; > + RESIZE_IF_NEEDED(w, wsize); > + /* These must be after realloc (u or v may be the same as w). */ > + up = v->d; > + vp = u->d; > + } else { > + usize = u->nlimbs; > + usign = u->sign; > + vsize = v->nlimbs; > + vsign = v->sign; > + wsize = usize + 1; > + RESIZE_IF_NEEDED(w, wsize); > + /* These must be after realloc (u or v may be the same as w). */ > + up = u->d; > + vp = v->d; > + } > + wp = w->d; > + wsign = 0; > + > + if (!vsize) { /* simple */ > + MPN_COPY(wp, up, usize); > + wsize = usize; > + wsign = usign; > + } else if (usign != vsign) { /* different sign */ > + /* This test is right since USIZE >= VSIZE */ > + if (usize != vsize) { > + mpihelp_sub(wp, up, usize, vp, vsize); > + wsize = usize; > + MPN_NORMALIZE(wp, wsize); > + wsign = usign; > + } else if (mpihelp_cmp(up, vp, usize) < 0) { > + mpihelp_sub_n(wp, vp, up, usize); > + wsize = usize; > + MPN_NORMALIZE(wp, wsize); > + if (!usign) > + wsign = 1; > + } else { > + mpihelp_sub_n(wp, up, vp, usize); > + wsize = usize; > + MPN_NORMALIZE(wp, wsize); > + if (usign) > + wsign = 1; > + } > + } else { /* U and V have same sign. Add them. */ > + mpi_limb_t cy = mpihelp_add(wp, up, usize, vp, vsize); > + wp[usize] = cy; > + wsize = usize + cy; > + if (usign) > + wsign = 1; > + } > + > + w->nlimbs = wsize; > + w->sign = wsign; > +} > +EXPORT_SYMBOL_GPL(mpi_add); > + > + > +/**************** > + * Subtract the unsigned integer V from the mpi-integer U and store the > + * result in W. > + */ > +void mpi_sub_ui(MPI w, MPI u, unsigned long v) > +{ > + mpi_ptr_t wp, up; > + mpi_size_t usize, wsize; > + int usign, wsign; > + > + usize = u->nlimbs; > + usign = u->sign; > + wsign = 0; > + > + /* If not space for W (and possible carry), increase space. */ > + wsize = usize + 1; > + if (w->alloced < wsize) > + mpi_resize(w, wsize); > + > + /* These must be after realloc (U may be the same as W). */ > + up = u->d; > + wp = w->d; > + > + if (!usize) { /* simple */ > + wp[0] = v; > + wsize = v ? 1:0; > + wsign = 1; > + } else if (usign) { /* mpi and v are negative */ > + mpi_limb_t cy; > + cy = mpihelp_add_1(wp, up, usize, v); > + wp[usize] = cy; > + wsize = usize + cy; > + } else { > + /* The signs are different. Need exact comparison to determine > + * which operand to subtract from which. > + */ > + if (usize == 1 && up[0] < v) { > + wp[0] = v - up[0]; > + wsize = 1; > + wsign = 1; > + } else { > + mpihelp_sub_1(wp, up, usize, v); > + /* Size can decrease with at most one limb. */ > + wsize = usize - (wp[usize-1] == 0); > + } > + } > + > + w->nlimbs = wsize; > + w->sign = wsign; > +} > + > +void mpi_sub(MPI w, MPI u, MPI v) > +{ > + MPI vv = mpi_copy(v); > + vv->sign = !vv->sign; > + mpi_add(w, u, vv); > + mpi_free(vv); > +} > + > + > +void mpi_addm(MPI w, MPI u, MPI v, MPI m) > +{ > + mpi_add(w, u, v); > + mpi_mod(w, w, m); > +} > +EXPORT_SYMBOL_GPL(mpi_addm); > + > +void mpi_subm(MPI w, MPI u, MPI v, MPI m) > +{ > + mpi_sub(w, u, v); > + mpi_mod(w, w, m); > +} > +EXPORT_SYMBOL_GPL(mpi_subm); > diff --git a/lib/mpi/mpi-bit.c b/lib/mpi/mpi-bit.c > index 503537e08436..a5119a2bcdd4 100644 > --- a/lib/mpi/mpi-bit.c > +++ b/lib/mpi/mpi-bit.c > @@ -32,6 +32,7 @@ void mpi_normalize(MPI a) > for (; a->nlimbs && !a->d[a->nlimbs - 1]; a->nlimbs--) > ; > } > +EXPORT_SYMBOL_GPL(mpi_normalize); > > /**************** > * Return the number of bits in A. > @@ -54,3 +55,253 @@ unsigned mpi_get_nbits(MPI a) > return n; > } > EXPORT_SYMBOL_GPL(mpi_get_nbits); > + > +/**************** > + * Test whether bit N is set. > + */ > +int mpi_test_bit(MPI a, unsigned int n) > +{ > + unsigned int limbno, bitno; > + mpi_limb_t limb; > + > + limbno = n / BITS_PER_MPI_LIMB; > + bitno = n % BITS_PER_MPI_LIMB; > + > + if (limbno >= a->nlimbs) > + return 0; /* too far left: this is a 0 */ > + limb = a->d[limbno]; > + return (limb & (A_LIMB_1 << bitno)) ? 1 : 0; > +} > +EXPORT_SYMBOL_GPL(mpi_test_bit); > + > +/**************** > + * Set bit N of A. > + */ > +void mpi_set_bit(MPI a, unsigned int n) > +{ > + unsigned int i, limbno, bitno; > + > + limbno = n / BITS_PER_MPI_LIMB; > + bitno = n % BITS_PER_MPI_LIMB; > + > + if (limbno >= a->nlimbs) { > + for (i = a->nlimbs; i < a->alloced; i++) > + a->d[i] = 0; > + mpi_resize(a, limbno+1); > + a->nlimbs = limbno+1; > + } > + a->d[limbno] |= (A_LIMB_1<<bitno); > +} > + > +/**************** > + * Set bit N of A. and clear all bits above > + */ > +void mpi_set_highbit(MPI a, unsigned int n) > +{ > + unsigned int i, limbno, bitno; > + > + limbno = n / BITS_PER_MPI_LIMB; > + bitno = n % BITS_PER_MPI_LIMB; > + > + if (limbno >= a->nlimbs) { > + for (i = a->nlimbs; i < a->alloced; i++) > + a->d[i] = 0; > + mpi_resize(a, limbno+1); > + a->nlimbs = limbno+1; > + } > + a->d[limbno] |= (A_LIMB_1<<bitno); > + for (bitno++; bitno < BITS_PER_MPI_LIMB; bitno++) > + a->d[limbno] &= ~(A_LIMB_1 << bitno); > + a->nlimbs = limbno+1; > +} > +EXPORT_SYMBOL_GPL(mpi_set_highbit); > + > +/**************** > + * clear bit N of A and all bits above > + */ > +void mpi_clear_highbit(MPI a, unsigned int n) > +{ > + unsigned int limbno, bitno; > + > + limbno = n / BITS_PER_MPI_LIMB; > + bitno = n % BITS_PER_MPI_LIMB; > + > + if (limbno >= a->nlimbs) > + return; /* not allocated, therefore no need to clear bits :-) */ > + > + for ( ; bitno < BITS_PER_MPI_LIMB; bitno++) > + a->d[limbno] &= ~(A_LIMB_1 << bitno); > + a->nlimbs = limbno+1; > +} > + > +/**************** > + * Clear bit N of A. > + */ > +void mpi_clear_bit(MPI a, unsigned int n) > +{ > + unsigned int limbno, bitno; > + > + limbno = n / BITS_PER_MPI_LIMB; > + bitno = n % BITS_PER_MPI_LIMB; > + > + if (limbno >= a->nlimbs) > + return; /* Don't need to clear this bit, it's far too left. */ > + a->d[limbno] &= ~(A_LIMB_1 << bitno); > +} > +EXPORT_SYMBOL_GPL(mpi_clear_bit); > + > + > +/**************** > + * Shift A by COUNT limbs to the right > + * This is used only within the MPI library > + */ > +void mpi_rshift_limbs(MPI a, unsigned int count) > +{ > + mpi_ptr_t ap = a->d; > + mpi_size_t n = a->nlimbs; > + unsigned int i; > + > + if (count >= n) { > + a->nlimbs = 0; > + return; > + } > + > + for (i = 0; i < n - count; i++) > + ap[i] = ap[i+count]; > + ap[i] = 0; > + a->nlimbs -= count; > +} > + > +/* > + * Shift A by N bits to the right. > + */ > +void mpi_rshift(MPI x, MPI a, unsigned int n) > +{ > + mpi_size_t xsize; > + unsigned int i; > + unsigned int nlimbs = (n/BITS_PER_MPI_LIMB); > + unsigned int nbits = (n%BITS_PER_MPI_LIMB); > + > + if (x == a) { > + /* In-place operation. */ > + if (nlimbs >= x->nlimbs) { > + x->nlimbs = 0; > + return; > + } > + > + if (nlimbs) { > + for (i = 0; i < x->nlimbs - nlimbs; i++) > + x->d[i] = x->d[i+nlimbs]; > + x->d[i] = 0; > + x->nlimbs -= nlimbs; > + } > + if (x->nlimbs && nbits) > + mpihelp_rshift(x->d, x->d, x->nlimbs, nbits); > + } else if (nlimbs) { > + /* Copy and shift by more or equal bits than in a limb. */ > + xsize = a->nlimbs; > + x->sign = a->sign; > + RESIZE_IF_NEEDED(x, xsize); > + x->nlimbs = xsize; > + for (i = 0; i < a->nlimbs; i++) > + x->d[i] = a->d[i]; > + x->nlimbs = i; > + > + if (nlimbs >= x->nlimbs) { > + x->nlimbs = 0; > + return; > + } > + > + if (nlimbs) { > + for (i = 0; i < x->nlimbs - nlimbs; i++) > + x->d[i] = x->d[i+nlimbs]; > + x->d[i] = 0; > + x->nlimbs -= nlimbs; > + } > + > + if (x->nlimbs && nbits) > + mpihelp_rshift(x->d, x->d, x->nlimbs, nbits); > + } else { > + /* Copy and shift by less than bits in a limb. */ > + xsize = a->nlimbs; > + x->sign = a->sign; > + RESIZE_IF_NEEDED(x, xsize); > + x->nlimbs = xsize; > + > + if (xsize) { > + if (nbits) > + mpihelp_rshift(x->d, a->d, x->nlimbs, nbits); > + else { > + /* The rshift helper function is not specified for > + * NBITS==0, thus we do a plain copy here. > + */ > + for (i = 0; i < x->nlimbs; i++) > + x->d[i] = a->d[i]; > + } > + } > + } > + MPN_NORMALIZE(x->d, x->nlimbs); > +} > + > +/**************** > + * Shift A by COUNT limbs to the left > + * This is used only within the MPI library > + */ > +void mpi_lshift_limbs(MPI a, unsigned int count) > +{ > + mpi_ptr_t ap; > + int n = a->nlimbs; > + int i; > + > + if (!count || !n) > + return; > + > + RESIZE_IF_NEEDED(a, n+count); > + > + ap = a->d; > + for (i = n-1; i >= 0; i--) > + ap[i+count] = ap[i]; > + for (i = 0; i < count; i++) > + ap[i] = 0; > + a->nlimbs += count; > +} > + > +/* > + * Shift A by N bits to the left. > + */ > +void mpi_lshift(MPI x, MPI a, unsigned int n) > +{ > + unsigned int nlimbs = (n/BITS_PER_MPI_LIMB); > + unsigned int nbits = (n%BITS_PER_MPI_LIMB); > + > + if (x == a && !n) > + return; /* In-place shift with an amount of zero. */ > + > + if (x != a) { > + /* Copy A to X. */ > + unsigned int alimbs = a->nlimbs; > + int asign = a->sign; > + mpi_ptr_t xp, ap; > + > + RESIZE_IF_NEEDED(x, alimbs+nlimbs+1); > + xp = x->d; > + ap = a->d; > + MPN_COPY(xp, ap, alimbs); > + x->nlimbs = alimbs; > + x->flags = a->flags; > + x->sign = asign; > + } > + > + if (nlimbs && !nbits) { > + /* Shift a full number of limbs. */ > + mpi_lshift_limbs(x, nlimbs); > + } else if (n) { > + /* We use a very dump approach: Shift left by the number of > + * limbs plus one and than fix it up by an rshift. > + */ > + mpi_lshift_limbs(x, nlimbs+1); > + mpi_rshift(x, x, BITS_PER_MPI_LIMB - nbits); > + } > + > + MPN_NORMALIZE(x->d, x->nlimbs); > +} > diff --git a/lib/mpi/mpi-cmp.c b/lib/mpi/mpi-cmp.c > index d25e9e96c310..c4cfa3ff0581 100644 > --- a/lib/mpi/mpi-cmp.c > +++ b/lib/mpi/mpi-cmp.c > @@ -41,28 +41,54 @@ int mpi_cmp_ui(MPI u, unsigned long v) > } > EXPORT_SYMBOL_GPL(mpi_cmp_ui); > > -int mpi_cmp(MPI u, MPI v) > +static int do_mpi_cmp(MPI u, MPI v, int absmode) > { > - mpi_size_t usize, vsize; > + mpi_size_t usize; > + mpi_size_t vsize; > + int usign; > + int vsign; > int cmp; > > mpi_normalize(u); > mpi_normalize(v); > + > usize = u->nlimbs; > vsize = v->nlimbs; > - if (!u->sign && v->sign) > + usign = absmode ? 0 : u->sign; > + vsign = absmode ? 0 : v->sign; > + > + /* Compare sign bits. */ > + > + if (!usign && vsign) > return 1; > - if (u->sign && !v->sign) > + if (usign && !vsign) > return -1; > - if (usize != vsize && !u->sign && !v->sign) > + > + /* U and V are either both positive or both negative. */ > + > + if (usize != vsize && !usign && !vsign) > return usize - vsize; > - if (usize != vsize && u->sign && v->sign) > - return vsize - usize; > + if (usize != vsize && usign && vsign) > + return vsize + usize; > if (!usize) > return 0; > cmp = mpihelp_cmp(u->d, v->d, usize); > - if (u->sign) > - return -cmp; > - return cmp; > + if (!cmp) > + return 0; > + if ((cmp < 0?1:0) == (usign?1:0)) > + return 1; > + > + return -1; > +} > + > +int mpi_cmp(MPI u, MPI v) > +{ > + return do_mpi_cmp(u, v, 0); > } > EXPORT_SYMBOL_GPL(mpi_cmp); > + > +int mpi_cmpabs(MPI u, MPI v) > +{ > + return do_mpi_cmp(u, v, 1); > +} > +EXPORT_SYMBOL_GPL(mpi_cmpabs); > diff --git a/lib/mpi/mpi-div.c b/lib/mpi/mpi-div.c > new file mode 100644 > index 000000000000..21332dab97d4 > --- /dev/null > +++ b/lib/mpi/mpi-div.c > @@ -0,0 +1,238 @@ > +/* mpi-div.c - MPI functions > + * Copyright (C) 1994, 1996, 1998, 2001, 2002, > + * 2003 Free Software Foundation, Inc. > + * > + * This file is part of Libgcrypt. > + * > + * Note: This code is heavily based on the GNU MP Library. > + * Actually it's the same code with only minor changes in the > + * way the data is stored; this is to support the abstraction > + * of an optional secure memory allocation which may be used > + * to avoid revealing of sensitive data due to paging etc. > + */ > + > +#include "mpi-internal.h" > +#include "longlong.h" > + > +void mpi_tdiv_qr(MPI quot, MPI rem, MPI num, MPI den); > +void mpi_fdiv_qr(MPI quot, MPI rem, MPI dividend, MPI divisor); > + > +void mpi_fdiv_r(MPI rem, MPI dividend, MPI divisor) > +{ > + int divisor_sign = divisor->sign; > + MPI temp_divisor = NULL; > + > + /* We need the original value of the divisor after the remainder has been > + * preliminary calculated. We have to copy it to temporary space if it's > + * the same variable as REM. > + */ > + if (rem == divisor) { > + temp_divisor = mpi_copy(divisor); > + divisor = temp_divisor; > + } > + > + mpi_tdiv_r(rem, dividend, divisor); > + > + if (((divisor_sign?1:0) ^ (dividend->sign?1:0)) && rem->nlimbs) > + mpi_add(rem, rem, divisor); > + > + if (temp_divisor) > + mpi_free(temp_divisor); > +} > + > +void mpi_fdiv_q(MPI quot, MPI dividend, MPI divisor) > +{ > + MPI tmp = mpi_alloc(mpi_get_nlimbs(quot)); > + mpi_fdiv_qr(quot, tmp, dividend, divisor); > + mpi_free(tmp); > +} > + > +void mpi_fdiv_qr(MPI quot, MPI rem, MPI dividend, MPI divisor) > +{ > + int divisor_sign = divisor->sign; > + MPI temp_divisor = NULL; > + > + if (quot == divisor || rem == divisor) { > + temp_divisor = mpi_copy(divisor); > + divisor = temp_divisor; > + } > + > + mpi_tdiv_qr(quot, rem, dividend, divisor); > + > + if ((divisor_sign ^ dividend->sign) && rem->nlimbs) { > + mpi_sub_ui(quot, quot, 1); > + mpi_add(rem, rem, divisor); > + } > + > + if (temp_divisor) > + mpi_free(temp_divisor); > +} > + > +/* If den == quot, den needs temporary storage. > + * If den == rem, den needs temporary storage. > + * If num == quot, num needs temporary storage. > + * If den has temporary storage, it can be normalized while being copied, > + * i.e no extra storage should be allocated. > + */ > + > +void mpi_tdiv_r(MPI rem, MPI num, MPI den) > +{ > + mpi_tdiv_qr(NULL, rem, num, den); > +} > + > +void mpi_tdiv_qr(MPI quot, MPI rem, MPI num, MPI den) > +{ > + mpi_ptr_t np, dp; > + mpi_ptr_t qp, rp; > + mpi_size_t nsize = num->nlimbs; > + mpi_size_t dsize = den->nlimbs; > + mpi_size_t qsize, rsize; > + mpi_size_t sign_remainder = num->sign; > + mpi_size_t sign_quotient = num->sign ^ den->sign; > + unsigned int normalization_steps; > + mpi_limb_t q_limb; > + mpi_ptr_t marker[5]; > + unsigned int marker_nlimbs[5]; > + int markidx = 0; > + > + /* Ensure space is enough for quotient and remainder. > + * We need space for an extra limb in the remainder, because it's > + * up-shifted (normalized) below. > + */ > + rsize = nsize + 1; > + mpi_resize(rem, rsize); > + > + qsize = rsize - dsize; /* qsize cannot be bigger than this. */ > + if (qsize <= 0) { > + if (num != rem) { > + rem->nlimbs = num->nlimbs; > + rem->sign = num->sign; > + MPN_COPY(rem->d, num->d, nsize); > + } > + if (quot) { > + /* This needs to follow the assignment to rem, in case the > + * numerator and quotient are the same. > + */ > + quot->nlimbs = 0; > + quot->sign = 0; > + } > + return; > + } > + > + if (quot) > + mpi_resize(quot, qsize); > + > + /* Read pointers here, when reallocation is finished. */ > + np = num->d; > + dp = den->d; > + rp = rem->d; > + > + /* Optimize division by a single-limb divisor. */ > + if (dsize == 1) { > + mpi_limb_t rlimb; > + if (quot) { > + qp = quot->d; > + rlimb = mpihelp_divmod_1(qp, np, nsize, dp[0]); > + qsize -= qp[qsize - 1] == 0; > + quot->nlimbs = qsize; > + quot->sign = sign_quotient; > + } else > + rlimb = mpihelp_mod_1(np, nsize, dp[0]); > + rp[0] = rlimb; > + rsize = rlimb != 0?1:0; > + rem->nlimbs = rsize; > + rem->sign = sign_remainder; > + return; > + } > + > + > + if (quot) { > + qp = quot->d; > + /* Make sure QP and NP point to different objects. Otherwise the > + * numerator would be gradually overwritten by the quotient limbs. > + */ > + if (qp == np) { /* Copy NP object to temporary space. */ > + marker_nlimbs[markidx] = nsize; > + np = marker[markidx++] = mpi_alloc_limb_space(nsize); > + MPN_COPY(np, qp, nsize); > + } > + } else /* Put quotient at top of remainder. */ > + qp = rp + dsize; > + > + normalization_steps = count_leading_zeros(dp[dsize - 1]); > + > + /* Normalize the denominator, i.e. make its most significant bit set by > + * shifting it NORMALIZATION_STEPS bits to the left. Also shift the > + * numerator the same number of steps (to keep the quotient the same!). > + */ > + if (normalization_steps) { > + mpi_ptr_t tp; > + mpi_limb_t nlimb; > + > + /* Shift up the denominator setting the most significant bit of > + * the most significant word. Use temporary storage not to clobber > + * the original contents of the denominator. > + */ > + marker_nlimbs[markidx] = dsize; > + tp = marker[markidx++] = mpi_alloc_limb_space(dsize); > + mpihelp_lshift(tp, dp, dsize, normalization_steps); > + dp = tp; > + > + /* Shift up the numerator, possibly introducing a new most > + * significant word. Move the shifted numerator in the remainder > + * meanwhile. > + */ > + nlimb = mpihelp_lshift(rp, np, nsize, normalization_steps); > + if (nlimb) { > + rp[nsize] = nlimb; > + rsize = nsize + 1; > + } else > + rsize = nsize; > + } else { > + /* The denominator is already normalized, as required. Copy it to > + * temporary space if it overlaps with the quotient or remainder. > + */ > + if (dp == rp || (quot && (dp == qp))) { > + mpi_ptr_t tp; > + > + marker_nlimbs[markidx] = dsize; > + tp = marker[markidx++] = mpi_alloc_limb_space(dsize); > + MPN_COPY(tp, dp, dsize); > + dp = tp; > + } > + > + /* Move the numerator to the remainder. */ > + if (rp != np) > + MPN_COPY(rp, np, nsize); > + > + rsize = nsize; > + } > + > + q_limb = mpihelp_divrem(qp, 0, rp, rsize, dp, dsize); > + > + if (quot) { > + qsize = rsize - dsize; > + if (q_limb) { > + qp[qsize] = q_limb; > + qsize += 1; > + } > + > + quot->nlimbs = qsize; > + quot->sign = sign_quotient; > + } > + > + rsize = dsize; > + MPN_NORMALIZE(rp, rsize); > + > + if (normalization_steps && rsize) { > + mpihelp_rshift(rp, rp, rsize, normalization_steps); > + rsize -= rp[rsize - 1] == 0?1:0; > + } > + > + rem->nlimbs = rsize; > + rem->sign = sign_remainder; > + while (markidx) { > + markidx--; > + mpi_free_limb_space(marker[markidx]); > + } > +} > diff --git a/lib/mpi/mpi-internal.h b/lib/mpi/mpi-internal.h > index 91df5f0b70f2..d29c4537c3a3 100644 > --- a/lib/mpi/mpi-internal.h > +++ b/lib/mpi/mpi-internal.h > @@ -52,6 +52,12 @@ > typedef mpi_limb_t *mpi_ptr_t; /* pointer to a limb */ > typedef int mpi_size_t; /* (must be a signed type) */ > > +#define RESIZE_IF_NEEDED(a, b) \ > + do { \ > + if ((a)->alloced < (b)) \ > + mpi_resize((a), (b)); \ > + } while (0) > + > /* Copy N limbs from S to D. */ > #define MPN_COPY(d, s, n) \ > do { \ > @@ -60,6 +66,14 @@ typedef int mpi_size_t; /* (must be a signed type) */ > (d)[_i] = (s)[_i]; \ > } while (0) > > +#define MPN_COPY_INCR(d, s, n) \ > + do { \ > + mpi_size_t _i; \ > + for (_i = 0; _i < (n); _i++) \ > + (d)[_i] = (s)[_i]; \ > + } while (0) > + > + > #define MPN_COPY_DECR(d, s, n) \ > do { \ > mpi_size_t _i; \ > @@ -92,6 +106,38 @@ typedef int mpi_size_t; /* (must be a signed type) */ > mul_n(prodp, up, vp, size, tspace); \ > } while (0); > > +/* Divide the two-limb number in (NH,,NL) by D, with DI being the largest > + * limb not larger than (2**(2*BITS_PER_MP_LIMB))/D - (2**BITS_PER_MP_LIMB). > + * If this would yield overflow, DI should be the largest possible number > + * (i.e., only ones). For correct operation, the most significant bit of D > + * has to be set. Put the quotient in Q and the remainder in R. > + */ > +#define UDIV_QRNND_PREINV(q, r, nh, nl, d, di) \ > + do { \ > + mpi_limb_t _ql; \ > + mpi_limb_t _q, _r; \ > + mpi_limb_t _xh, _xl; \ > + umul_ppmm(_q, _ql, (nh), (di)); \ > + _q += (nh); /* DI is 2**BITS_PER_MPI_LIMB too small */ \ > + umul_ppmm(_xh, _xl, _q, (d)); \ > + sub_ddmmss(_xh, _r, (nh), (nl), _xh, _xl); \ > + if (_xh) { \ > + sub_ddmmss(_xh, _r, _xh, _r, 0, (d)); \ > + _q++; \ > + if (_xh) { \ > + sub_ddmmss(_xh, _r, _xh, _r, 0, (d)); \ > + _q++; \ > + } \ > + } \ > + if (_r >= (d)) { \ > + _r -= (d); \ > + _q++; \ > + } \ > + (r) = _r; \ > + (q) = _q; \ > + } while (0) > + > + > /*-- mpiutil.c --*/ > mpi_ptr_t mpi_alloc_limb_space(unsigned nlimbs); > void mpi_free_limb_space(mpi_ptr_t a); > @@ -135,6 +181,8 @@ int mpihelp_mul(mpi_ptr_t prodp, mpi_ptr_t up, mpi_size_t usize, > void mpih_sqr_n_basecase(mpi_ptr_t prodp, mpi_ptr_t up, mpi_size_t size); > void mpih_sqr_n(mpi_ptr_t prodp, mpi_ptr_t up, mpi_size_t size, > mpi_ptr_t tspace); > +void mpihelp_mul_n(mpi_ptr_t prodp, > + mpi_ptr_t up, mpi_ptr_t vp, mpi_size_t size); > > int mpihelp_mul_karatsuba_case(mpi_ptr_t prodp, > mpi_ptr_t up, mpi_size_t usize, > @@ -146,9 +194,14 @@ mpi_limb_t mpihelp_mul_1(mpi_ptr_t res_ptr, mpi_ptr_t s1_ptr, > mpi_size_t s1_size, mpi_limb_t s2_limb); > > /*-- mpih-div.c --*/ > +mpi_limb_t mpihelp_mod_1(mpi_ptr_t dividend_ptr, mpi_size_t dividend_size, > + mpi_limb_t divisor_limb); > mpi_limb_t mpihelp_divrem(mpi_ptr_t qp, mpi_size_t qextra_limbs, > mpi_ptr_t np, mpi_size_t nsize, > mpi_ptr_t dp, mpi_size_t dsize); > +mpi_limb_t mpihelp_divmod_1(mpi_ptr_t quot_ptr, > + mpi_ptr_t dividend_ptr, mpi_size_t dividend_size, > + mpi_limb_t divisor_limb); > > /*-- generic_mpih-[lr]shift.c --*/ > mpi_limb_t mpihelp_lshift(mpi_ptr_t wp, mpi_ptr_t up, mpi_size_t usize, > diff --git a/lib/mpi/mpi-inv.c b/lib/mpi/mpi-inv.c > new file mode 100644 > index 000000000000..61e37d18f793 > --- /dev/null > +++ b/lib/mpi/mpi-inv.c > @@ -0,0 +1,143 @@ > +/* mpi-inv.c - MPI functions > + * Copyright (C) 1998, 2001, 2002, 2003 Free Software Foundation, Inc. > + * > + * This file is part of Libgcrypt. > + * > + * Libgcrypt is free software; you can redistribute it and/or modify > + * it under the terms of the GNU Lesser General Public License as > + * published by the Free Software Foundation; either version 2.1 of > + * the License, or (at your option) any later version. > + * > + * Libgcrypt is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU Lesser General Public License for more details. > + * > + * You should have received a copy of the GNU Lesser General Public > + * License along with this program; if not, see <http://www.gnu.org/licenses/>. > + */ > + > +#include "mpi-internal.h" > + > +/**************** > + * Calculate the multiplicative inverse X of A mod N > + * That is: Find the solution x for > + * 1 = (a*x) mod n > + */ > +int mpi_invm(MPI x, MPI a, MPI n) > +{ > + /* Extended Euclid's algorithm (See TAOCP Vol II, 4.5.2, Alg X) > + * modified according to Michael Penk's solution for Exercise 35 > + * with further enhancement > + */ > + MPI u, v, u1, u2 = NULL, u3, v1, v2 = NULL, v3, t1, t2 = NULL, t3; > + unsigned int k; > + int sign; > + int odd; > + > + if (!mpi_cmp_ui(a, 0)) > + return 0; /* Inverse does not exists. */ > + if (!mpi_cmp_ui(n, 1)) > + return 0; /* Inverse does not exists. */ > + > + u = mpi_copy(a); > + v = mpi_copy(n); > + > + for (k = 0; !mpi_test_bit(u, 0) && !mpi_test_bit(v, 0); k++) { > + mpi_rshift(u, u, 1); > + mpi_rshift(v, v, 1); > + } > + odd = mpi_test_bit(v, 0); > + > + u1 = mpi_alloc_set_ui(1); > + if (!odd) > + u2 = mpi_alloc_set_ui(0); > + u3 = mpi_copy(u); > + v1 = mpi_copy(v); > + if (!odd) { > + v2 = mpi_alloc(mpi_get_nlimbs(u)); > + mpi_sub(v2, u1, u); /* U is used as const 1 */ > + } > + v3 = mpi_copy(v); > + if (mpi_test_bit(u, 0)) { /* u is odd */ > + t1 = mpi_alloc_set_ui(0); > + if (!odd) { > + t2 = mpi_alloc_set_ui(1); > + t2->sign = 1; > + } > + t3 = mpi_copy(v); > + t3->sign = !t3->sign; > + goto Y4; > + } else { > + t1 = mpi_alloc_set_ui(1); > + if (!odd) > + t2 = mpi_alloc_set_ui(0); > + t3 = mpi_copy(u); > + } > + > + do { > + do { > + if (!odd) { > + if (mpi_test_bit(t1, 0) || mpi_test_bit(t2, 0)) { > + /* one is odd */ > + mpi_add(t1, t1, v); > + mpi_sub(t2, t2, u); > + } > + mpi_rshift(t1, t1, 1); > + mpi_rshift(t2, t2, 1); > + mpi_rshift(t3, t3, 1); > + } else { > + if (mpi_test_bit(t1, 0)) > + mpi_add(t1, t1, v); > + mpi_rshift(t1, t1, 1); > + mpi_rshift(t3, t3, 1); > + } > +Y4: > + ; > + } while (!mpi_test_bit(t3, 0)); /* while t3 is even */ > + > + if (!t3->sign) { > + mpi_set(u1, t1); > + if (!odd) > + mpi_set(u2, t2); > + mpi_set(u3, t3); > + } else { > + mpi_sub(v1, v, t1); > + sign = u->sign; u->sign = !u->sign; > + if (!odd) > + mpi_sub(v2, u, t2); > + u->sign = sign; > + sign = t3->sign; t3->sign = !t3->sign; > + mpi_set(v3, t3); > + t3->sign = sign; > + } > + mpi_sub(t1, u1, v1); > + if (!odd) > + mpi_sub(t2, u2, v2); > + mpi_sub(t3, u3, v3); > + if (t1->sign) { > + mpi_add(t1, t1, v); > + if (!odd) > + mpi_sub(t2, t2, u); > + } > + } while (mpi_cmp_ui(t3, 0)); /* while t3 != 0 */ > + /* mpi_lshift( u3, k ); */ > + mpi_set(x, u1); > + > + mpi_free(u1); > + mpi_free(v1); > + mpi_free(t1); > + if (!odd) { > + mpi_free(u2); > + mpi_free(v2); > + mpi_free(t2); > + } > + mpi_free(u3); > + mpi_free(v3); > + mpi_free(t3); > + > + mpi_free(u); > + mpi_free(v); > + return 1; > +} > +EXPORT_SYMBOL_GPL(mpi_invm); > diff --git a/lib/mpi/mpi-mod.c b/lib/mpi/mpi-mod.c > new file mode 100644 > index 000000000000..47bc59edd4ff > --- /dev/null > +++ b/lib/mpi/mpi-mod.c > @@ -0,0 +1,155 @@ > +/* mpi-mod.c - Modular reduction > + * Copyright (C) 1998, 1999, 2001, 2002, 2003, > + * 2007 Free Software Foundation, Inc. > + * > + * This file is part of Libgcrypt. > + */ > + > + > +#include "mpi-internal.h" > +#include "longlong.h" > + > +/* Context used with Barrett reduction. */ > +struct barrett_ctx_s { > + MPI m; /* The modulus - may not be modified. */ > + int m_copied; /* If true, M needs to be released. */ > + int k; > + MPI y; > + MPI r1; /* Helper MPI. */ > + MPI r2; /* Helper MPI. */ > + MPI r3; /* Helper MPI allocated on demand. */ > +}; > + > + > + > +void mpi_mod(MPI rem, MPI dividend, MPI divisor) > +{ > + mpi_fdiv_r(rem, dividend, divisor); > +} > + > +/* This function returns a new context for Barrett based operations on > + * the modulus M. This context needs to be released using > + * _gcry_mpi_barrett_free. If COPY is true M will be transferred to > + * the context and the user may change M. If COPY is false, M may not > + * be changed until gcry_mpi_barrett_free has been called. > + */ > +mpi_barrett_t mpi_barrett_init(MPI m, int copy) > +{ > + mpi_barrett_t ctx; > + MPI tmp; > + > + mpi_normalize(m); > + ctx = kcalloc(1, sizeof(*ctx), GFP_KERNEL); > + > + if (copy) { > + ctx->m = mpi_copy(m); > + ctx->m_copied = 1; > + } else > + ctx->m = m; > + > + ctx->k = mpi_get_nlimbs(m); > + tmp = mpi_alloc(ctx->k + 1); > + > + /* Barrett precalculation: y = floor(b^(2k) / m). */ > + mpi_set_ui(tmp, 1); > + mpi_lshift_limbs(tmp, 2 * ctx->k); > + mpi_fdiv_q(tmp, tmp, m); > + > + ctx->y = tmp; > + ctx->r1 = mpi_alloc(2 * ctx->k + 1); > + ctx->r2 = mpi_alloc(2 * ctx->k + 1); > + > + return ctx; > +} > + > +void mpi_barrett_free(mpi_barrett_t ctx) > +{ > + if (ctx) { > + mpi_free(ctx->y); > + mpi_free(ctx->r1); > + mpi_free(ctx->r2); > + if (ctx->r3) > + mpi_free(ctx->r3); > + if (ctx->m_copied) > + mpi_free(ctx->m); > + kfree(ctx); > + } > +} > + > + > +/* R = X mod M > + * > + * Using Barrett reduction. Before using this function > + * _gcry_mpi_barrett_init must have been called to do the > + * precalculations. CTX is the context created by this precalculation > + * and also conveys M. If the Barret reduction could no be done a > + * straightforward reduction method is used. > + * > + * We assume that these conditions are met: > + * Input: x =(x_2k-1 ...x_0)_b > + * m =(m_k-1 ....m_0)_b with m_k-1 != 0 > + * Output: r = x mod m > + */ > +void mpi_mod_barrett(MPI r, MPI x, mpi_barrett_t ctx) > +{ > + MPI m = ctx->m; > + int k = ctx->k; > + MPI y = ctx->y; > + MPI r1 = ctx->r1; > + MPI r2 = ctx->r2; > + int sign; > + > + mpi_normalize(x); > + if (mpi_get_nlimbs(x) > 2*k) { > + mpi_mod(r, x, m); > + return; > + } > + > + sign = x->sign; > + x->sign = 0; > + > + /* 1. q1 = floor( x / b^k-1) > + * q2 = q1 * y > + * q3 = floor( q2 / b^k+1 ) > + * Actually, we don't need qx, we can work direct on r2 > + */ > + mpi_set(r2, x); > + mpi_rshift_limbs(r2, k-1); > + mpi_mul(r2, r2, y); > + mpi_rshift_limbs(r2, k+1); > + > + /* 2. r1 = x mod b^k+1 > + * r2 = q3 * m mod b^k+1 > + * r = r1 - r2 > + * 3. if r < 0 then r = r + b^k+1 > + */ > + mpi_set(r1, x); > + if (r1->nlimbs > k+1) /* Quick modulo operation. */ > + r1->nlimbs = k+1; > + mpi_mul(r2, r2, m); > + if (r2->nlimbs > k+1) /* Quick modulo operation. */ > + r2->nlimbs = k+1; > + mpi_sub(r, r1, r2); > + > + if (mpi_has_sign(r)) { > + if (!ctx->r3) { > + ctx->r3 = mpi_alloc(k + 2); > + mpi_set_ui(ctx->r3, 1); > + mpi_lshift_limbs(ctx->r3, k + 1); > + } > + mpi_add(r, r, ctx->r3); > + } > + > + /* 4. while r >= m do r = r - m */ > + while (mpi_cmp(r, m) >= 0) > + mpi_sub(r, r, m); > + > + x->sign = sign; > +} > + > + > +void mpi_mul_barrett(MPI w, MPI u, MPI v, mpi_barrett_t ctx) > +{ > + mpi_mul(w, u, v); > + mpi_mod_barrett(w, w, ctx); > +} > diff --git a/lib/mpi/mpi-mul.c b/lib/mpi/mpi-mul.c > new file mode 100644 > index 000000000000..587e6335cc12 > --- /dev/null > +++ b/lib/mpi/mpi-mul.c > @@ -0,0 +1,94 @@ > +/* mpi-mul.c - MPI functions > + * Copyright (C) 1994, 1996, 1998, 2001, 2002, > + * 2003 Free Software Foundation, Inc. > + * > + * This file is part of Libgcrypt. > + * > + * Note: This code is heavily based on the GNU MP Library. > + * Actually it's the same code with only minor changes in the > + * way the data is stored; this is to support the abstraction > + * of an optional secure memory allocation which may be used > + * to avoid revealing of sensitive data due to paging etc. > + */ > + > +#include "mpi-internal.h" > + > +void mpi_mul(MPI w, MPI u, MPI v) > +{ > + mpi_size_t usize, vsize, wsize; > + mpi_ptr_t up, vp, wp; > + mpi_limb_t cy; > + int usign, vsign, sign_product; > + int assign_wp = 0; > + mpi_ptr_t tmp_limb = NULL; > + unsigned int tmp_limb_nlimbs = 0; > + > + if (u->nlimbs < v->nlimbs) { > + /* Swap U and V. */ > + usize = v->nlimbs; > + usign = v->sign; > + up = v->d; > + vsize = u->nlimbs; > + vsign = u->sign; > + vp = u->d; > + } else { > + usize = u->nlimbs; > + usign = u->sign; > + up = u->d; > + vsize = v->nlimbs; > + vsign = v->sign; > + vp = v->d; > + } > + sign_product = usign ^ vsign; > + wp = w->d; > + > + /* Ensure W has space enough to store the result. */ > + wsize = usize + vsize; > + if (w->alloced < wsize) { > + if (wp == up || wp == vp) { > + wp = mpi_alloc_limb_space(wsize); > + assign_wp = 1; > + } else { > + mpi_resize(w, wsize); > + wp = w->d; > + } > + } else { /* Make U and V not overlap with W. */ > + if (wp == up) { > + /* W and U are identical. Allocate temporary space for U. */ > + tmp_limb_nlimbs = usize; > + up = tmp_limb = mpi_alloc_limb_space(usize); > + /* Is V identical too? Keep it identical with U. */ > + if (wp == vp) > + vp = up; > + /* Copy to the temporary space. */ > + MPN_COPY(up, wp, usize); > + } else if (wp == vp) { > + /* W and V are identical. Allocate temporary space for V. */ > + tmp_limb_nlimbs = vsize; > + vp = tmp_limb = mpi_alloc_limb_space(vsize); > + /* Copy to the temporary space. */ > + MPN_COPY(vp, wp, vsize); > + } > + } > + > + if (!vsize) > + wsize = 0; > + else { > + mpihelp_mul(wp, up, usize, vp, vsize, &cy); > + wsize -= cy ? 0:1; > + } > + > + if (assign_wp) > + mpi_assign_limb_space(w, wp, wsize); > + w->nlimbs = wsize; > + w->sign = sign_product; > + if (tmp_limb) > + mpi_free_limb_space(tmp_limb); > +} > + > +void mpi_mulm(MPI w, MPI u, MPI v, MPI m) > +{ > + mpi_mul(w, u, v); > + mpi_tdiv_r(w, w, m); > +} > +EXPORT_SYMBOL_GPL(mpi_mulm); > diff --git a/lib/mpi/mpicoder.c b/lib/mpi/mpicoder.c > index eead4b339466..7ea225b2204f 100644 > --- a/lib/mpi/mpicoder.c > +++ b/lib/mpi/mpicoder.c > @@ -25,6 +25,7 @@ > #include <linux/string.h> > #include "mpi-internal.h" > > +#define MAX_EXTERN_SCAN_BYTES (16*1024*1024) > #define MAX_EXTERN_MPI_BITS 16384 > > /** > @@ -109,6 +110,112 @@ MPI mpi_read_from_buffer(const void *xbuffer, unsigned *ret_nread) > } > EXPORT_SYMBOL_GPL(mpi_read_from_buffer); > > +/**************** > + * Fill the mpi VAL from the hex string in STR. > + */ > +int mpi_fromstr(MPI val, const char *str) > +{ > + int sign = 0; > + int prepend_zero = 0; > + int i, j, c, c1, c2; > + unsigned int nbits, nbytes, nlimbs; > + mpi_limb_t a; > + > + if (*str == '-') { > + sign = 1; > + str++; > + } > + > + /* Skip optional hex prefix. */ > + if (*str == '0' && str[1] == 'x') > + str += 2; > + > + nbits = strlen(str); > + if (nbits > MAX_EXTERN_SCAN_BYTES) { > + mpi_clear(val); > + return -EINVAL; > + } > + nbits *= 4; > + if ((nbits % 8)) > + prepend_zero = 1; > + > + nbytes = (nbits+7) / 8; > + nlimbs = (nbytes+BYTES_PER_MPI_LIMB-1) / BYTES_PER_MPI_LIMB; > + > + if (val->alloced < nlimbs) > + mpi_resize(val, nlimbs); > + > + i = BYTES_PER_MPI_LIMB - (nbytes % BYTES_PER_MPI_LIMB); > + i %= BYTES_PER_MPI_LIMB; > + j = val->nlimbs = nlimbs; > + val->sign = sign; > + for (; j > 0; j--) { > + a = 0; > + for (; i < BYTES_PER_MPI_LIMB; i++) { > + if (prepend_zero) { > + c1 = '0'; > + prepend_zero = 0; > + } else > + c1 = *str++; > + > + if (!c1) { > + mpi_clear(val); > + return -EINVAL; > + } > + c2 = *str++; > + if (!c2) { > + mpi_clear(val); > + return -EINVAL; > + } > + if (c1 >= '0' && c1 <= '9') > + c = c1 - '0'; > + else if (c1 >= 'a' && c1 <= 'f') > + c = c1 - 'a' + 10; > + else if (c1 >= 'A' && c1 <= 'F') > + c = c1 - 'A' + 10; > + else { > + mpi_clear(val); > + return -EINVAL; > + } > + c <<= 4; > + if (c2 >= '0' && c2 <= '9') > + c |= c2 - '0'; > + else if (c2 >= 'a' && c2 <= 'f') > + c |= c2 - 'a' + 10; > + else if (c2 >= 'A' && c2 <= 'F') > + c |= c2 - 'A' + 10; > + else { > + mpi_clear(val); > + return -EINVAL; > + } > + a <<= 8; > + a |= c; > + } > + i = 0; > + val->d[j-1] = a; > + } > + > + return 0; > +} > +EXPORT_SYMBOL_GPL(mpi_fromstr); > + > +MPI mpi_scanval(const char *string) > +{ > + MPI a; > + > + a = mpi_alloc(0); > + if (!a) > + return NULL; > + > + if (mpi_fromstr(a, string)) { > + mpi_free(a); > + return NULL; > + } > + mpi_normalize(a); > + return a; > +} > +EXPORT_SYMBOL_GPL(mpi_scanval); > + > static int count_lzeros(MPI a) > { > mpi_limb_t alimb; > @@ -413,3 +520,232 @@ MPI mpi_read_raw_from_sgl(struct scatterlist *sgl, unsigned int nbytes) > return val; > } > EXPORT_SYMBOL_GPL(mpi_read_raw_from_sgl); > + > +/* Perform a two's complement operation on buffer P of size N bytes. */ > +static void twocompl(unsigned char *p, unsigned int n) > +{ > + int i; > + > + for (i = n-1; i >= 0 && !p[i]; i--) > + ; > + if (i >= 0) { > + if ((p[i] & 0x01)) > + p[i] = (((p[i] ^ 0xfe) | 0x01) & 0xff); > + else if ((p[i] & 0x02)) > + p[i] = (((p[i] ^ 0xfc) | 0x02) & 0xfe); > + else if ((p[i] & 0x04)) > + p[i] = (((p[i] ^ 0xf8) | 0x04) & 0xfc); > + else if ((p[i] & 0x08)) > + p[i] = (((p[i] ^ 0xf0) | 0x08) & 0xf8); > + else if ((p[i] & 0x10)) > + p[i] = (((p[i] ^ 0xe0) | 0x10) & 0xf0); > + else if ((p[i] & 0x20)) > + p[i] = (((p[i] ^ 0xc0) | 0x20) & 0xe0); > + else if ((p[i] & 0x40)) > + p[i] = (((p[i] ^ 0x80) | 0x40) & 0xc0); > + else > + p[i] = 0x80; > + > + for (i--; i >= 0; i--) > + p[i] ^= 0xff; > + } > +} > + > +int mpi_print(enum gcry_mpi_format format, unsigned char *buffer, > + size_t buflen, size_t *nwritten, MPI a) > +{ > + unsigned int nbits = mpi_get_nbits(a); > + size_t len; > + size_t dummy_nwritten; > + int negative; > + > + if (!nwritten) > + nwritten = &dummy_nwritten; > + > + /* Libgcrypt does no always care to set clear the sign if the value > + * is 0. For printing this is a bit of a surprise, in particular > + * because if some of the formats don't support negative numbers but > + * should be able to print a zero. Thus we need this extra test > + * for a negative number. > + */ > + if (a->sign && mpi_cmp_ui(a, 0)) > + negative = 1; > + else > + negative = 0; > + > + len = buflen; > + *nwritten = 0; > + if (format == GCRYMPI_FMT_STD) { > + unsigned char *tmp; > + int extra = 0; > + unsigned int n; > + > + tmp = mpi_get_buffer(a, &n, NULL); > + if (!tmp) > + return -EINVAL; > + > + if (negative) { > + twocompl(tmp, n); > + if (!(*tmp & 0x80)) { > + /* Need to extend the sign. */ > + n++; > + extra = 2; > + } > + } else if (n && (*tmp & 0x80)) { > + /* Positive but the high bit of the returned buffer is set. > + * Thus we need to print an extra leading 0x00 so that the > + * output is interpreted as a positive number. > + */ > + n++; > + extra = 1; > + } > + > + if (buffer && n > len) { > + /* The provided buffer is too short. */ > + kfree(tmp); > + return -E2BIG; > + } > + if (buffer) { > + unsigned char *s = buffer; > + > + if (extra == 1) > + *s++ = 0; > + else if (extra) > + *s++ = 0xff; > + memcpy(s, tmp, n-!!extra); > + } > + kfree(tmp); > + *nwritten = n; > + return 0; > + } else if (format == GCRYMPI_FMT_USG) { > + unsigned int n = (nbits + 7)/8; > + > + /* Note: We ignore the sign for this format. */ > + /* FIXME: for performance reasons we should put this into > + * mpi_aprint because we can then use the buffer directly. > + */ > + > + if (buffer && n > len) > + return -E2BIG; > + if (buffer) { > + unsigned char *tmp; > + > + tmp = mpi_get_buffer(a, &n, NULL); > + if (!tmp) > + return -EINVAL; > + memcpy(buffer, tmp, n); > + kfree(tmp); > + } > + *nwritten = n; > + return 0; > + } else if (format == GCRYMPI_FMT_PGP) { > + unsigned int n = (nbits + 7)/8; > + > + /* The PGP format can only handle unsigned integers. */ > + if (negative) > + return -EINVAL; > + > + if (buffer && n+2 > len) > + return -E2BIG; > + > + if (buffer) { > + unsigned char *tmp; > + unsigned char *s = buffer; > + > + s[0] = nbits >> 8; > + s[1] = nbits; > + > + tmp = mpi_get_buffer(a, &n, NULL); > + if (!tmp) > + return -EINVAL; > + memcpy(s+2, tmp, n); > + kfree(tmp); > + } > + *nwritten = n+2; > + return 0; > + } else if (format == GCRYMPI_FMT_SSH) { > + unsigned char *tmp; > + int extra = 0; > + unsigned int n; > + > + tmp = mpi_get_buffer(a, &n, NULL); > + if (!tmp) > + return -EINVAL; > + > + if (negative) { > + twocompl(tmp, n); > + if (!(*tmp & 0x80)) { > + /* Need to extend the sign. */ > + n++; > + extra = 2; > + } > + } else if (n && (*tmp & 0x80)) { > + n++; > + extra = 1; > + } > + > + if (buffer && n+4 > len) { > + kfree(tmp); > + return -E2BIG; > + } > + > + if (buffer) { > + unsigned char *s = buffer; > + > + *s++ = n >> 24; > + *s++ = n >> 16; > + *s++ = n >> 8; > + *s++ = n; > + if (extra == 1) > + *s++ = 0; > + else if (extra) > + *s++ = 0xff; > + memcpy(s, tmp, n-!!extra); > + } > + kfree(tmp); > + *nwritten = 4+n; > + return 0; > + } else if (format == GCRYMPI_FMT_HEX) { > + unsigned char *tmp; > + int i; > + int extra = 0; > + unsigned int n = 0; > + > + tmp = mpi_get_buffer(a, &n, NULL); > + if (!tmp) > + return -EINVAL; > + if (!n || (*tmp & 0x80)) > + extra = 2; > + > + if (buffer && 2*n + extra + negative + 1 > len) { > + kfree(tmp); > + return -E2BIG; > + } > + if (buffer) { > + unsigned char *s = buffer; > + > + if (negative) > + *s++ = '-'; > + if (extra) { > + *s++ = '0'; > + *s++ = '0'; > + } > + > + for (i = 0; i < n; i++) { > + unsigned int c = tmp[i]; > + > + *s++ = (c >> 4) < 10 ? '0'+(c>>4) : 'A'+(c>>4)-10; > + c &= 15; > + *s++ = c < 10 ? '0'+c : 'A'+c-10; > + } > + *s++ = 0; > + *nwritten = s - buffer; > + } else { > + *nwritten = 2*n + extra + negative + 1; > + } > + kfree(tmp); > + return 0; > + } else > + return -EINVAL; > +} > +EXPORT_SYMBOL_GPL(mpi_print); > diff --git a/lib/mpi/mpih-div.c b/lib/mpi/mpih-div.c > index 913a519eb005..182a656a1ba0 100644 > --- a/lib/mpi/mpih-div.c > +++ b/lib/mpi/mpih-div.c > @@ -24,6 +24,150 @@ > #define UDIV_TIME UMUL_TIME > #endif > > + > +mpi_limb_t > +mpihelp_mod_1(mpi_ptr_t dividend_ptr, mpi_size_t dividend_size, > + mpi_limb_t divisor_limb) > +{ > + mpi_size_t i; > + mpi_limb_t n1, n0, r; > + mpi_limb_t dummy; > + > + /* Botch: Should this be handled at all? Rely on callers? */ > + if (!dividend_size) > + return 0; > + > + /* If multiplication is much faster than division, and the > + * dividend is large, pre-invert the divisor, and use > + * only multiplications in the inner loop. > + * > + * This test should be read: > + * Does it ever help to use udiv_qrnnd_preinv? > + * && Does what we save compensate for the inversion overhead? > + */ > + if (UDIV_TIME > (2 * UMUL_TIME + 6) > + && (UDIV_TIME - (2 * UMUL_TIME + 6)) * dividend_size > UDIV_TIME) { > + int normalization_steps; > + > + normalization_steps = count_leading_zeros(divisor_limb); > + if (normalization_steps) { > + mpi_limb_t divisor_limb_inverted; > + > + divisor_limb <<= normalization_steps; > + > + /* Compute (2**2N - 2**N * DIVISOR_LIMB) / DIVISOR_LIMB. The > + * result is a (N+1)-bit approximation to 1/DIVISOR_LIMB, with the > + * most significant bit (with weight 2**N) implicit. > + * > + * Special case for DIVISOR_LIMB == 100...000. > + */ > + if (!(divisor_limb << 1)) > + divisor_limb_inverted = ~(mpi_limb_t)0; > + else > + udiv_qrnnd(divisor_limb_inverted, dummy, > + -divisor_limb, 0, divisor_limb); > + > + n1 = dividend_ptr[dividend_size - 1]; > + r = n1 >> (BITS_PER_MPI_LIMB - normalization_steps); > + > + /* Possible optimization: > + * if (r == 0 > + * && divisor_limb > ((n1 << normalization_steps) > + * | (dividend_ptr[dividend_size - 2] >> ...))) > + * ...one division less... > + */ > + for (i = dividend_size - 2; i >= 0; i--) { > + n0 = dividend_ptr[i]; > + UDIV_QRNND_PREINV(dummy, r, r, > + ((n1 << normalization_steps) > + | (n0 >> (BITS_PER_MPI_LIMB - normalization_steps))), > + divisor_limb, divisor_limb_inverted); > + n1 = n0; > + } > + UDIV_QRNND_PREINV(dummy, r, r, > + n1 << normalization_steps, > + divisor_limb, divisor_limb_inverted); > + return r >> normalization_steps; > + } else { > + mpi_limb_t divisor_limb_inverted; > + > + /* Compute (2**2N - 2**N * DIVISOR_LIMB) / DIVISOR_LIMB. The > + * result is a (N+1)-bit approximation to 1/DIVISOR_LIMB, with the > + * most significant bit (with weight 2**N) implicit. > + * > + * Special case for DIVISOR_LIMB == 100...000. > + */ > + if (!(divisor_limb << 1)) > + divisor_limb_inverted = ~(mpi_limb_t)0; > + else > + udiv_qrnnd(divisor_limb_inverted, dummy, > + -divisor_limb, 0, divisor_limb); > + > + i = dividend_size - 1; > + r = dividend_ptr[i]; > + > + if (r >= divisor_limb) > + r = 0; > + else > + i--; > + > + for ( ; i >= 0; i--) { > + n0 = dividend_ptr[i]; > + UDIV_QRNND_PREINV(dummy, r, r, > + n0, divisor_limb, divisor_limb_inverted); > + } > + return r; > + } > + } else { > + if (UDIV_NEEDS_NORMALIZATION) { > + int normalization_steps; > + > + normalization_steps = count_leading_zeros(divisor_limb); > + if (normalization_steps) { > + divisor_limb <<= normalization_steps; > + > + n1 = dividend_ptr[dividend_size - 1]; > + r = n1 >> (BITS_PER_MPI_LIMB - normalization_steps); > + > + /* Possible optimization: > + * if (r == 0 > + * && divisor_limb > ((n1 << normalization_steps) > + * | (dividend_ptr[dividend_size - 2] >> ...))) > + * ...one division less... > + */ > + for (i = dividend_size - 2; i >= 0; i--) { > + n0 = dividend_ptr[i]; > + udiv_qrnnd(dummy, r, r, > + ((n1 << normalization_steps) > + | (n0 >> (BITS_PER_MPI_LIMB - normalization_steps))), > + divisor_limb); > + n1 = n0; > + } > + udiv_qrnnd(dummy, r, r, > + n1 << normalization_steps, > + divisor_limb); > + return r >> normalization_steps; > + } > + } > + /* No normalization needed, either because udiv_qrnnd doesn't require > + * it, or because DIVISOR_LIMB is already normalized. > + */ > + i = dividend_size - 1; > + r = dividend_ptr[i]; > + > + if (r >= divisor_limb) > + r = 0; > + else > + i--; > + > + for (; i >= 0; i--) { > + n0 = dividend_ptr[i]; > + udiv_qrnnd(dummy, r, r, n0, divisor_limb); > + } > + return r; > + } > +} > + > /* Divide num (NP/NSIZE) by den (DP/DSIZE) and write > * the NSIZE-DSIZE least significant quotient limbs at QP > * and the DSIZE long remainder at NP. If QEXTRA_LIMBS is > @@ -221,3 +365,153 @@ mpihelp_divrem(mpi_ptr_t qp, mpi_size_t qextra_limbs, > > return most_significant_q_limb; > } > + > +/**************** > + * Divide (DIVIDEND_PTR,,DIVIDEND_SIZE) by DIVISOR_LIMB. > + * Write DIVIDEND_SIZE limbs of quotient at QUOT_PTR. > + * Return the single-limb remainder. > + * There are no constraints on the value of the divisor. > + * > + * QUOT_PTR and DIVIDEND_PTR might point to the same limb. > + */ > + > +mpi_limb_t > +mpihelp_divmod_1(mpi_ptr_t quot_ptr, > + mpi_ptr_t dividend_ptr, mpi_size_t dividend_size, > + mpi_limb_t divisor_limb) > +{ > + mpi_size_t i; > + mpi_limb_t n1, n0, r; > + mpi_limb_t dummy; > + > + if (!dividend_size) > + return 0; > + > + /* If multiplication is much faster than division, and the > + * dividend is large, pre-invert the divisor, and use > + * only multiplications in the inner loop. > + * > + * This test should be read: > + * Does it ever help to use udiv_qrnnd_preinv? > + * && Does what we save compensate for the inversion overhead? > + */ > + if (UDIV_TIME > (2 * UMUL_TIME + 6) > + && (UDIV_TIME - (2 * UMUL_TIME + 6)) * dividend_size > UDIV_TIME) { > + int normalization_steps; > + > + normalization_steps = count_leading_zeros(divisor_limb); > + if (normalization_steps) { > + mpi_limb_t divisor_limb_inverted; > + > + divisor_limb <<= normalization_steps; > + > + /* Compute (2**2N - 2**N * DIVISOR_LIMB) / DIVISOR_LIMB. The > + * result is a (N+1)-bit approximation to 1/DIVISOR_LIMB, with the > + * most significant bit (with weight 2**N) implicit. > + */ > + /* Special case for DIVISOR_LIMB == 100...000. */ > + if (!(divisor_limb << 1)) > + divisor_limb_inverted = ~(mpi_limb_t)0; > + else > + udiv_qrnnd(divisor_limb_inverted, dummy, > + -divisor_limb, 0, divisor_limb); > + > + n1 = dividend_ptr[dividend_size - 1]; > + r = n1 >> (BITS_PER_MPI_LIMB - normalization_steps); > + > + /* Possible optimization: > + * if (r == 0 > + * && divisor_limb > ((n1 << normalization_steps) > + * | (dividend_ptr[dividend_size - 2] >> ...))) > + * ...one division less... > + */ > + for (i = dividend_size - 2; i >= 0; i--) { > + n0 = dividend_ptr[i]; > + UDIV_QRNND_PREINV(quot_ptr[i + 1], r, r, > + ((n1 << normalization_steps) > + | (n0 >> (BITS_PER_MPI_LIMB - normalization_steps))), > + divisor_limb, divisor_limb_inverted); > + n1 = n0; > + } > + UDIV_QRNND_PREINV(quot_ptr[0], r, r, > + n1 << normalization_steps, > + divisor_limb, divisor_limb_inverted); > + return r >> normalization_steps; > + } else { > + mpi_limb_t divisor_limb_inverted; > + > + /* Compute (2**2N - 2**N * DIVISOR_LIMB) / DIVISOR_LIMB. The > + * result is a (N+1)-bit approximation to 1/DIVISOR_LIMB, with the > + * most significant bit (with weight 2**N) implicit. > + */ > + /* Special case for DIVISOR_LIMB == 100...000. */ > + if (!(divisor_limb << 1)) > + divisor_limb_inverted = ~(mpi_limb_t) 0; > + else > + udiv_qrnnd(divisor_limb_inverted, dummy, > + -divisor_limb, 0, divisor_limb); > + > + i = dividend_size - 1; > + r = dividend_ptr[i]; > + > + if (r >= divisor_limb) > + r = 0; > + else > + quot_ptr[i--] = 0; > + > + for ( ; i >= 0; i--) { > + n0 = dividend_ptr[i]; > + UDIV_QRNND_PREINV(quot_ptr[i], r, r, > + n0, divisor_limb, divisor_limb_inverted); > + } > + return r; > + } > + } else { > + if (UDIV_NEEDS_NORMALIZATION) { > + int normalization_steps; > + > + normalization_steps = count_leading_zeros(divisor_limb); > + if (normalization_steps) { > + divisor_limb <<= normalization_steps; > + > + n1 = dividend_ptr[dividend_size - 1]; > + r = n1 >> (BITS_PER_MPI_LIMB - normalization_steps); > + > + /* Possible optimization: > + * if (r == 0 > + * && divisor_limb > ((n1 << normalization_steps) > + * | (dividend_ptr[dividend_size - 2] >> ...))) > + * ...one division less... > + */ > + for (i = dividend_size - 2; i >= 0; i--) { > + n0 = dividend_ptr[i]; > + udiv_qrnnd(quot_ptr[i + 1], r, r, > + ((n1 << normalization_steps) > + | (n0 >> (BITS_PER_MPI_LIMB - normalization_steps))), > + divisor_limb); > + n1 = n0; > + } > + udiv_qrnnd(quot_ptr[0], r, r, > + n1 << normalization_steps, > + divisor_limb); > + return r >> normalization_steps; > + } > + } > + /* No normalization needed, either because udiv_qrnnd doesn't require > + * it, or because DIVISOR_LIMB is already normalized. > + */ > + i = dividend_size - 1; > + r = dividend_ptr[i]; > + > + if (r >= divisor_limb) > + r = 0; > + else > + quot_ptr[i--] = 0; > + > + for (; i >= 0; i--) { > + n0 = dividend_ptr[i]; > + udiv_qrnnd(quot_ptr[i], r, r, n0, divisor_limb); > + } > + return r; > + } > +} > diff --git a/lib/mpi/mpih-mul.c b/lib/mpi/mpih-mul.c > index a93647564054..e5f1c84e3c48 100644 > --- a/lib/mpi/mpih-mul.c > +++ b/lib/mpi/mpih-mul.c > @@ -317,6 +317,31 @@ mpih_sqr_n(mpi_ptr_t prodp, mpi_ptr_t up, mpi_size_t size, mpi_ptr_t tspace) > } > } > > + > +void mpihelp_mul_n(mpi_ptr_t prodp, > + mpi_ptr_t up, mpi_ptr_t vp, mpi_size_t size) > +{ > + if (up == vp) { > + if (size < KARATSUBA_THRESHOLD) > + mpih_sqr_n_basecase(prodp, up, size); > + else { > + mpi_ptr_t tspace; > + tspace = mpi_alloc_limb_space(2 * size); > + mpih_sqr_n(prodp, up, size, tspace); > + mpi_free_limb_space(tspace); > + } > + } else { > + if (size < KARATSUBA_THRESHOLD) > + mul_n_basecase(prodp, up, vp, size); > + else { > + mpi_ptr_t tspace; > + tspace = mpi_alloc_limb_space(2 * size); > + mul_n(prodp, up, vp, size, tspace); > + mpi_free_limb_space(tspace); > + } > + } > +} > + > int > mpihelp_mul_karatsuba_case(mpi_ptr_t prodp, > mpi_ptr_t up, mpi_size_t usize, > diff --git a/lib/mpi/mpiutil.c b/lib/mpi/mpiutil.c > index 20ed0f766787..e4046f74f336 100644 > --- a/lib/mpi/mpiutil.c > +++ b/lib/mpi/mpiutil.c > @@ -20,6 +20,63 @@ > > #include "mpi-internal.h" > > +/* Constants allocated right away at startup. */ > +static MPI constants[MPI_NUMBER_OF_CONSTANTS]; > + > +/* Initialize the MPI subsystem. This is called early and allows to > + * do some initialization without taking care of threading issues. > + */ > +static int __init mpi_init(void) > +{ > + int idx; > + unsigned long value; > + > + for (idx = 0; idx < MPI_NUMBER_OF_CONSTANTS; idx++) { > + switch (idx) { > + case MPI_C_ZERO: > + value = 0; > + break; > + case MPI_C_ONE: > + value = 1; > + break; > + case MPI_C_TWO: > + value = 2; > + break; > + case MPI_C_THREE: > + value = 3; > + break; > + case MPI_C_FOUR: > + value = 4; > + break; > + case MPI_C_EIGHT: > + value = 8; > + break; > + default: > + pr_err("MPI: invalid mpi_const selector %d\n", idx); > + return -EFAULT; > + } > + constants[idx] = mpi_alloc_set_ui(value); > + constants[idx]->flags = (16|32); > + } > + > + return 0; > +} > +postcore_initcall(mpi_init); > + > +/* Return a constant MPI descripbed by NO which is one of the > + * MPI_C_xxx macros. There is no need to copy this returned value; it > + * may be used directly. > + */ > +MPI mpi_const(enum gcry_mpi_constants no) > +{ > + if ((int)no < 0 || no > MPI_NUMBER_OF_CONSTANTS) > + pr_err("MPI: invalid mpi_const selector %d\n", no); > + if (!constants[no]) > + pr_err("MPI: MPI subsystem not initialized\n"); > + return constants[no]; > +} > +EXPORT_SYMBOL_GPL(mpi_const); > + > /**************** > * Note: It was a bad idea to use the number of limbs to allocate > * because on a alpha the limbs are large but we normally need > @@ -106,6 +163,15 @@ int mpi_resize(MPI a, unsigned nlimbs) > return 0; > } > > +void mpi_clear(MPI a) > +{ > + if (!a) > + return; > + a->nlimbs = 0; > + a->flags = 0; > +} > +EXPORT_SYMBOL_GPL(mpi_clear); > + > void mpi_free(MPI a) > { > if (!a) > @@ -122,5 +188,143 @@ void mpi_free(MPI a) > } > EXPORT_SYMBOL_GPL(mpi_free); > > +/**************** > + * Note: This copy function should not interpret the MPI > + * but copy it transparently. > + */ > +MPI mpi_copy(MPI a) > +{ > + int i; > + MPI b; > + > + if (a) { > + b = mpi_alloc(a->nlimbs); > + b->nlimbs = a->nlimbs; > + b->sign = a->sign; > + b->flags = a->flags; > + b->flags &= ~(16|32); /* Reset the immutable and constant flags. */ > + for (i = 0; i < b->nlimbs; i++) > + b->d[i] = a->d[i]; > + } else > + b = NULL; > + return b; > +} > + > +/**************** > + * This function allocates an MPI which is optimized to hold > + * a value as large as the one given in the argument and allocates it > + * with the same flags as A. > + */ > +MPI mpi_alloc_like(MPI a) > +{ > + MPI b; > + > + if (a) { > + b = mpi_alloc(a->nlimbs); > + b->nlimbs = 0; > + b->sign = 0; > + b->flags = a->flags; > + } else > + b = NULL; > + > + return b; > +} > + > + > +/* Set U into W and release U. If W is NULL only U will be released. */ > +void mpi_snatch(MPI w, MPI u) > +{ > + if (w) { > + mpi_assign_limb_space(w, u->d, u->alloced); > + w->nlimbs = u->nlimbs; > + w->sign = u->sign; > + w->flags = u->flags; > + u->alloced = 0; > + u->nlimbs = 0; > + u->d = NULL; > + } > + mpi_free(u); > +} > + > + > +MPI mpi_set(MPI w, MPI u) > +{ > + mpi_ptr_t wp, up; > + mpi_size_t usize = u->nlimbs; > + int usign = u->sign; > + > + if (!w) > + w = mpi_alloc(mpi_get_nlimbs(u)); > + RESIZE_IF_NEEDED(w, usize); > + wp = w->d; > + up = u->d; > + MPN_COPY(wp, up, usize); > + w->nlimbs = usize; > + w->flags = u->flags; > + w->flags &= ~(16|32); /* Reset the immutable and constant flags. */ > + w->sign = usign; > + return w; > +} > +EXPORT_SYMBOL_GPL(mpi_set); > + > +MPI mpi_set_ui(MPI w, unsigned long u) > +{ > + if (!w) > + w = mpi_alloc(1); > + /* FIXME: If U is 0 we have no need to resize and thus possible > + * allocating the the limbs. > + */ > + RESIZE_IF_NEEDED(w, 1); > + w->d[0] = u; > + w->nlimbs = u ? 1 : 0; > + w->sign = 0; > + w->flags = 0; > + return w; > +} > +EXPORT_SYMBOL_GPL(mpi_set_ui); > + > +MPI mpi_alloc_set_ui(unsigned long u) > +{ > + MPI w = mpi_alloc(1); > + w->d[0] = u; > + w->nlimbs = u ? 1 : 0; > + w->sign = 0; > + return w; > +} > + > +/**************** > + * Swap the value of A and B, when SWAP is 1. > + * Leave the value when SWAP is 0. > + * This implementation should be constant-time regardless of SWAP. > + */ > +void mpi_swap_cond(MPI a, MPI b, unsigned long swap) > +{ > + mpi_size_t i; > + mpi_size_t nlimbs; > + mpi_limb_t mask = ((mpi_limb_t)0) - swap; > + mpi_limb_t x; > + > + if (a->alloced > b->alloced) > + nlimbs = b->alloced; > + else > + nlimbs = a->alloced; > + if (a->nlimbs > nlimbs || b->nlimbs > nlimbs) > + return; > + > + for (i = 0; i < nlimbs; i++) { > + x = mask & (a->d[i] ^ b->d[i]); > + a->d[i] = a->d[i] ^ x; > + b->d[i] = b->d[i] ^ x; > + } > + > + x = mask & (a->nlimbs ^ b->nlimbs); > + a->nlimbs = a->nlimbs ^ x; > + b->nlimbs = b->nlimbs ^ x; > + > + x = mask & (a->sign ^ b->sign); > + a->sign = a->sign ^ x; > + b->sign = b->sign ^ x; > +} > + > MODULE_DESCRIPTION("Multiprecision maths library"); > MODULE_LICENSE("GPL"); > -- > 2.17.1 > -- Regards, Marcelo
Attachment:
signature.asc
Description: PGP signature