Exemplo n.º 1
0
/****************
 * Subtract the unsigned integer V from the mpi-integer U and store the
 * result in W.
 */
void
gcry_mpi_sub_ui(gcry_mpi_t w, gcry_mpi_t 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 = _gcry_mpih_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 {
	    _gcry_mpih_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;
}
Exemplo n.º 2
0
void
_gcry_mpih_mul_karatsuba_case( mpi_ptr_t prodp,
                                  mpi_ptr_t up, mpi_size_t usize,
                                  mpi_ptr_t vp, mpi_size_t vsize,
                                  struct karatsuba_ctx *ctx )
{
    mpi_limb_t cy;

    if( !ctx->tspace || ctx->tspace_size < vsize ) {
	if( ctx->tspace )
	    _gcry_mpi_free_limb_space( ctx->tspace, ctx->tspace_nlimbs );
        ctx->tspace_nlimbs = 2 * vsize;
	ctx->tspace = mpi_alloc_limb_space (2 * vsize,
				            (_gcry_is_secure (up)
                                             || _gcry_is_secure (vp)));
	ctx->tspace_size = vsize;
    }

    MPN_MUL_N_RECURSE( prodp, up, vp, vsize, ctx->tspace );

    prodp += vsize;
    up += vsize;
    usize -= vsize;
    if( usize >= vsize ) {
	if( !ctx->tp || ctx->tp_size < vsize ) {
	    if( ctx->tp )
		_gcry_mpi_free_limb_space( ctx->tp, ctx->tp_nlimbs );
            ctx->tp_nlimbs = 2 * vsize;
	    ctx->tp = mpi_alloc_limb_space (2 * vsize,
                                            (_gcry_is_secure (up)
                                             || _gcry_is_secure (vp)));
	    ctx->tp_size = vsize;
	}

	do {
	    MPN_MUL_N_RECURSE( ctx->tp, up, vp, vsize, ctx->tspace );
	    cy = _gcry_mpih_add_n( prodp, prodp, ctx->tp, vsize );
	    _gcry_mpih_add_1( prodp + vsize, ctx->tp + vsize, vsize, cy );
	    prodp += vsize;
	    up += vsize;
	    usize -= vsize;
	} while( usize >= vsize );
    }

    if( usize ) {
	if( usize < KARATSUBA_THRESHOLD ) {
	    _gcry_mpih_mul( ctx->tspace, vp, vsize, up, usize );
	}
	else {
	    if( !ctx->next ) {
		ctx->next = xcalloc( 1, sizeof *ctx );
	    }
	    _gcry_mpih_mul_karatsuba_case( ctx->tspace,
					vp, vsize,
					up, usize,
					ctx->next );
	}

	cy = _gcry_mpih_add_n( prodp, prodp, ctx->tspace, vsize);
	_gcry_mpih_add_1( prodp + vsize, ctx->tspace + vsize, usize, cy );
    }
}
Exemplo n.º 3
0
void
_gcry_mpih_sqr_n( mpi_ptr_t prodp,
                  mpi_ptr_t up, mpi_size_t size, mpi_ptr_t tspace)
{
    if( size & 1 ) {
	/* The size is odd, and the code below doesn't handle that.
	 * Multiply the least significant (size - 1) limbs with a recursive
	 * call, and handle the most significant limb of S1 and S2
	 * separately.
	 * A slightly faster way to do this would be to make the Karatsuba
	 * code below behave as if the size were even, and let it check for
	 * odd size in the end.  I.e., in essence move this code to the end.
	 * Doing so would save us a recursive call, and potentially make the
	 * stack grow a lot less.
	 */
	mpi_size_t esize = size - 1;	   /* even size */
	mpi_limb_t cy_limb;

	MPN_SQR_N_RECURSE( prodp, up, esize, tspace );
	cy_limb = _gcry_mpih_addmul_1( prodp + esize, up, esize, up[esize] );
	prodp[esize + esize] = cy_limb;
	cy_limb = _gcry_mpih_addmul_1( prodp + esize, up, size, up[esize] );

	prodp[esize + size] = cy_limb;
    }
    else {
	mpi_size_t hsize = size >> 1;
	mpi_limb_t cy;

	/* Product H.	   ________________  ________________
	 *		  |_____U1 x U1____||____U0 x U0_____|
	 * Put result in upper part of PROD and pass low part of TSPACE
	 * as new TSPACE.
	 */
	MPN_SQR_N_RECURSE(prodp + size, up + hsize, hsize, tspace);

	/* Product M.	   ________________
	 *		  |_(U1-U0)(U0-U1)_|
	 */
	if( _gcry_mpih_cmp( up + hsize, up, hsize) >= 0 )
	    _gcry_mpih_sub_n( prodp, up + hsize, up, hsize);
	else
	    _gcry_mpih_sub_n (prodp, up, up + hsize, hsize);

	/* Read temporary operands from low part of PROD.
	 * Put result in low part of TSPACE using upper part of TSPACE
	 * as new TSPACE.  */
	MPN_SQR_N_RECURSE(tspace, prodp, hsize, tspace + size);

	/* Add/copy product H  */
	MPN_COPY(prodp + hsize, prodp + size, hsize);
	cy = _gcry_mpih_add_n(prodp + size, prodp + size,
			   prodp + size + hsize, hsize);

	/* Add product M (if NEGFLG M is a negative number).  */
	cy -= _gcry_mpih_sub_n (prodp + hsize, prodp + hsize, tspace, size);

	/* Product L.	   ________________  ________________
	 *		  |________________||____U0 x U0_____|
	 * Read temporary operands from low part of PROD.
	 * Put result in low part of TSPACE using upper part of TSPACE
	 * as new TSPACE.  */
	MPN_SQR_N_RECURSE (tspace, up, hsize, tspace + size);

	/* Add/copy Product L (twice).	*/
	cy += _gcry_mpih_add_n (prodp + hsize, prodp + hsize, tspace, size);
	if( cy )
	    _gcry_mpih_add_1(prodp + hsize + size, prodp + hsize + size,
							    hsize, cy);

	MPN_COPY(prodp, tspace, hsize);
	cy = _gcry_mpih_add_n (prodp + hsize, prodp + hsize, tspace + hsize, hsize);
	if( cy )
	    _gcry_mpih_add_1 (prodp + size, prodp + size, size, 1);
    }
}
Exemplo n.º 4
0
static void
mul_n( mpi_ptr_t prodp, mpi_ptr_t up, mpi_ptr_t vp,
			mpi_size_t size, mpi_ptr_t tspace )
{
    if( size & 1 ) {
      /* The size is odd, and the code below doesn't handle that.
       * Multiply the least significant (size - 1) limbs with a recursive
       * call, and handle the most significant limb of S1 and S2
       * separately.
       * A slightly faster way to do this would be to make the Karatsuba
       * code below behave as if the size were even, and let it check for
       * odd size in the end.  I.e., in essence move this code to the end.
       * Doing so would save us a recursive call, and potentially make the
       * stack grow a lot less.
       */
      mpi_size_t esize = size - 1;	 /* even size */
      mpi_limb_t cy_limb;

      MPN_MUL_N_RECURSE( prodp, up, vp, esize, tspace );
      cy_limb = _gcry_mpih_addmul_1( prodp + esize, up, esize, vp[esize] );
      prodp[esize + esize] = cy_limb;
      cy_limb = _gcry_mpih_addmul_1( prodp + esize, vp, size, up[esize] );
      prodp[esize + size] = cy_limb;
    }
    else {
	/* Anatolij Alekseevich Karatsuba's divide-and-conquer algorithm.
	 *
	 * Split U in two pieces, U1 and U0, such that
	 * U = U0 + U1*(B**n),
	 * and V in V1 and V0, such that
	 * V = V0 + V1*(B**n).
	 *
	 * UV is then computed recursively using the identity
	 *
	 *	  2n   n	  n			n
	 * UV = (B  + B )U V  +  B (U -U )(V -V )  +  (B + 1)U V
	 *		  1 1	     1	0   0  1	      0 0
	 *
	 * Where B = 2**BITS_PER_MP_LIMB.
	 */
	mpi_size_t hsize = size >> 1;
	mpi_limb_t cy;
	int negflg;

	/* Product H.	   ________________  ________________
	 *		  |_____U1 x V1____||____U0 x V0_____|
	 * Put result in upper part of PROD and pass low part of TSPACE
	 * as new TSPACE.
	 */
	MPN_MUL_N_RECURSE(prodp + size, up + hsize, vp + hsize, hsize, tspace);

	/* Product M.	   ________________
	 *		  |_(U1-U0)(V0-V1)_|
	 */
	if( _gcry_mpih_cmp(up + hsize, up, hsize) >= 0 ) {
	    _gcry_mpih_sub_n(prodp, up + hsize, up, hsize);
	    negflg = 0;
	}
	else {
	    _gcry_mpih_sub_n(prodp, up, up + hsize, hsize);
	    negflg = 1;
	}
	if( _gcry_mpih_cmp(vp + hsize, vp, hsize) >= 0 ) {
	    _gcry_mpih_sub_n(prodp + hsize, vp + hsize, vp, hsize);
	    negflg ^= 1;
	}
	else {
	    _gcry_mpih_sub_n(prodp + hsize, vp, vp + hsize, hsize);
	    /* No change of NEGFLG.  */
	}
	/* Read temporary operands from low part of PROD.
	 * Put result in low part of TSPACE using upper part of TSPACE
	 * as new TSPACE.
	 */
	MPN_MUL_N_RECURSE(tspace, prodp, prodp + hsize, hsize, tspace + size);

	/* Add/copy product H. */
	MPN_COPY (prodp + hsize, prodp + size, hsize);
	cy = _gcry_mpih_add_n( prodp + size, prodp + size,
			    prodp + size + hsize, hsize);

	/* Add product M (if NEGFLG M is a negative number) */
	if(negflg)
	    cy -= _gcry_mpih_sub_n(prodp + hsize, prodp + hsize, tspace, size);
	else
	    cy += _gcry_mpih_add_n(prodp + hsize, prodp + hsize, tspace, size);

	/* Product L.	   ________________  ________________
	 *		  |________________||____U0 x V0_____|
	 * Read temporary operands from low part of PROD.
	 * Put result in low part of TSPACE using upper part of TSPACE
	 * as new TSPACE.
	 */
	MPN_MUL_N_RECURSE(tspace, up, vp, hsize, tspace + size);

	/* Add/copy Product L (twice) */

	cy += _gcry_mpih_add_n(prodp + hsize, prodp + hsize, tspace, size);
	if( cy )
	  _gcry_mpih_add_1(prodp + hsize + size, prodp + hsize + size, hsize, cy);

	MPN_COPY(prodp, tspace, hsize);
	cy = _gcry_mpih_add_n(prodp + hsize, prodp + hsize, tspace + hsize, hsize);
	if( cy )
	    _gcry_mpih_add_1(prodp + size, prodp + size, size, 1);
    }
}