/* 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 _gcry_mpi_mod_barrett (gcry_mpi_t r, gcry_mpi_t x, mpi_barrett_t ctx) { gcry_mpi_t m = ctx->m; int k = ctx->k; gcry_mpi_t y = ctx->y; gcry_mpi_t r1 = ctx->r1; gcry_mpi_t 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; }
/* Set the value from S into D. */ static void point_set (mpi_point_t d, mpi_point_t s) { mpi_set (d->x, s->x); mpi_set (d->y, s->y); mpi_set (d->z, s->z); }
/**************** * Find the greatest common divisor G of A and B. * Return: true if this 1, false in all other cases */ int mpi_gcd( MPI g, const MPI xa, const MPI xb ) { MPI a = NULL, b = NULL; if (mpi_copy(&a, xa) < 0) goto nomem; if (mpi_copy(&b, xb) < 0) goto nomem; /* TAOCP Vol II, 4.5.2, Algorithm A */ a->sign = 0; b->sign = 0; while( mpi_cmp_ui( b, 0 ) ) { if (mpi_fdiv_r( g, a, b ) < 0) /* g used as temorary variable */ goto nomem; if (mpi_set(a,b) < 0) goto nomem; if (mpi_set(b,g) < 0) goto nomem; } if (mpi_set(g, a) < 0) goto nomem; mpi_free(a); mpi_free(b); return !mpi_cmp_ui( g, 1); nomem: mpi_free(a); mpi_free(b); return -ENOMEM; }
void mpr_set(mpr *rop, mpr *op) { if (rop != op) { mpi_set(mpr_num(rop), mpr_num(op)); mpi_set(mpr_den(rop), mpr_den(op)); } }
void mpr_inv(mpr *rop, mpr *op) { if (rop == op) mpi_swap(mpr_num(op), mpr_den(op)); else { mpi_set(mpr_num(rop), mpr_den(op)); mpi_set(mpr_den(rop), mpr_num(op)); } }
/* RESULT must have been initialized and is set on success to the point given by VALUE. */ static gcry_error_t os2ec (mpi_point_t *result, gcry_mpi_t value) { gcry_error_t err; size_t n; unsigned char *buf; gcry_mpi_t x, y; n = (mpi_get_nbits (value)+7)/8; buf = gcry_xmalloc (n); err = gcry_mpi_print (GCRYMPI_FMT_USG, buf, n, &n, value); if (err) { gcry_free (buf); return err; } if (n < 1) { gcry_free (buf); return GPG_ERR_INV_OBJ; } if (*buf != 4) { gcry_free (buf); return GPG_ERR_NOT_IMPLEMENTED; /* No support for point compression. */ } if ( ((n-1)%2) ) { gcry_free (buf); return GPG_ERR_INV_OBJ; } n = (n-1)/2; err = gcry_mpi_scan (&x, GCRYMPI_FMT_USG, buf+1, n, NULL); if (err) { gcry_free (buf); return err; } err = gcry_mpi_scan (&y, GCRYMPI_FMT_USG, buf+1+n, n, NULL); gcry_free (buf); if (err) { mpi_free (x); return err; } mpi_set (result->x, x); mpi_set (result->y, y); mpi_set_ui (result->z, 1); mpi_free (x); mpi_free (y); return 0; }
/* Set the projective coordinates from POINT into X, Y, and Z. If a coordinate is not required, X, Y, or Z may be passed as NULL. */ void gcry_mpi_point_get (gcry_mpi_t x, gcry_mpi_t y, gcry_mpi_t z, mpi_point_t point) { if (x) mpi_set (x, point->x); if (y) mpi_set (y, point->y); if (z) mpi_set (z, point->z); }
void mpr_abs(mpr *rop, mpr *op) { if (mpr_num(op)->sign) mpi_neg(mpr_num(rop), mpr_num(op)); else mpi_set(mpr_num(rop), mpr_num(op)); /* op may not be canonicalized */ if (mpr_den(op)->sign) mpi_neg(mpr_den(rop), mpr_den(op)); else mpi_set(mpr_den(rop), mpr_den(op)); }
/**************** * Barrett reduction: We assume that these conditions are met: * Given x =(x_2k-1 ...x_0)_b * m =(m_k-1 ....m_0)_b with m_k-1 != 0 * Output r = x mod m * Before using this function init_barret must be used to calucalte y and k. * Returns: false = no error * true = can't perform barret reduction */ static int calc_barrett( gcry_mpi_t r, gcry_mpi_t x, gcry_mpi_t m, gcry_mpi_t y, int k, gcry_mpi_t r1, gcry_mpi_t r2 ) { int xx = k > 3 ? k-3:0; mpi_normalize( x ); if( mpi_get_nlimbs(x) > 2*k ) return 1; /* can't do it */ /* 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) ) { gcry_mpi_t tmp; tmp = mpi_alloc( k + 2 ); mpi_set_ui( tmp, 1 ); mpi_lshift_limbs( tmp, k+1 ); mpi_add( r, r, tmp ); mpi_free(tmp); } /* 4. while r >= m do r = r - m */ while( mpi_cmp( r, m ) >= 0 ) mpi_sub( r, r, m ); return 0; }
static void do_gcd(void) { MPI a = mpi_alloc(40); if( stackidx < 2 ) { fputs("stack underflow\n", stderr); return; } mpi_gcd( a, stack[stackidx-2], stack[stackidx-1] ); mpi_set(stack[stackidx-2],a); mpi_free(a); stackidx--; }
/* W = - U */ void _gcry_mpi_neg (gcry_mpi_t w, gcry_mpi_t u) { if (w != u) mpi_set (w, u); else if (mpi_is_immutable (w)) { mpi_immutable_failed (); return; } w->sign = !u->sign; }
/* Set the projective coordinates from X, Y, and Z into POINT. If a coordinate is given as NULL, the value 0 is stored into point. If POINT is given as NULL a new point object is allocated. Returns POINT or the newly allocated point object. */ mpi_point_t gcry_mpi_point_set (mpi_point_t point, gcry_mpi_t x, gcry_mpi_t y, gcry_mpi_t z) { if (!point) point = gcry_mpi_point_new (0); if (x) mpi_set (point->x, x); else mpi_clear (point->x); if (y) mpi_set (point->y, y); else mpi_clear (point->y); if (z) mpi_set (point->z, z); else mpi_clear (point->z); return point; }
/**************** * Find the greatest common divisor G of A and B. * Return: true if this 1, false in all other cases */ int mpi_gcd( MPI g, MPI xa, MPI xb ) { MPI a, b; a = mpi_copy(xa); b = mpi_copy(xb); /* TAOCP Vol II, 4.5.2, Algorithm A */ a->sign = 0; b->sign = 0; while( mpi_cmp_ui( b, 0 ) ) { mpi_fdiv_r( g, a, b ); /* g used as temorary variable */ mpi_set(a,b); mpi_set(b,g); } mpi_set(g, a); mpi_free(a); mpi_free(b); return !mpi_cmp_ui( g, 1); }
static int scan_mpi (gcry_mpi_t retval, const char *string) { gpg_error_t err; gcry_mpi_t val; err = gcry_mpi_scan (&val, GCRYMPI_FMT_HEX, string, 0, NULL); if (err) { fprintf (stderr, "scanning input failed: %s\n", gpg_strerror (err)); return -1; } mpi_set (retval, val); mpi_release (val); return 0; }
static void do_gcd (void) { gcry_mpi_t a; if (stackidx < 2) { fputs ("stack underflow\n", stderr); return; } a = mpi_new (0); mpi_gcd (a, stack[stackidx - 2], stack[stackidx - 1]); mpi_set (stack[stackidx - 2], a); mpi_release (a); stackidx--; }
void mpr_div(mpr *rop, mpr *op1, mpr *op2) { /* check if temporary storage is required */ if (op1 == op2 && rop == op1) { mpi prod; memset(&prod, '\0', sizeof(mpi)); mpi_mul(&prod, mpr_num(op1), mpr_den(op2)); mpi_mul(mpr_den(rop), mpr_num(op2), mpr_den(op1)); mpi_set(mpr_num(rop), &prod); mpi_clear(&prod); } else { mpi_mul(mpr_num(rop), mpr_num(op1), mpr_den(op2)); mpi_mul(mpr_den(rop), mpr_num(op2), mpr_den(op1)); } }
/* Scalar point multiplication - the main function for ECC. If takes an integer SCALAR and a POINT as well as the usual context CTX. RESULT will be set to the resulting point. */ void _gcry_mpi_ec_mul_point (mpi_point_t result, gcry_mpi_t scalar, mpi_point_t point, mpi_ec_t ctx) { #if 0 /* Simple left to right binary method. GECC Algorithm 3.27 */ unsigned int nbits; int i; nbits = mpi_get_nbits (scalar); mpi_set_ui (result->x, 1); mpi_set_ui (result->y, 1); mpi_set_ui (result->z, 0); for (i=nbits-1; i >= 0; i--) { _gcry_mpi_ec_dup_point (result, result, ctx); if (mpi_test_bit (scalar, i) == 1) _gcry_mpi_ec_add_points (result, result, point, ctx); } #else gcry_mpi_t x1, y1, z1, k, h, yy; unsigned int i, loops; mpi_point_struct p1, p2, p1inv; x1 = mpi_alloc_like (ctx->p); y1 = mpi_alloc_like (ctx->p); h = mpi_alloc_like (ctx->p); k = mpi_copy (scalar); yy = mpi_copy (point->y); if ( mpi_is_neg (k) ) { k->sign = 0; ec_invm (yy, yy, ctx); } if (!mpi_cmp_ui (point->z, 1)) { mpi_set (x1, point->x); mpi_set (y1, yy); } else { gcry_mpi_t z2, z3; z2 = mpi_alloc_like (ctx->p); z3 = mpi_alloc_like (ctx->p); ec_mulm (z2, point->z, point->z, ctx); ec_mulm (z3, point->z, z2, ctx); ec_invm (z2, z2, ctx); ec_mulm (x1, point->x, z2, ctx); ec_invm (z3, z3, ctx); ec_mulm (y1, yy, z3, ctx); mpi_free (z2); mpi_free (z3); } z1 = mpi_copy (mpi_const (MPI_C_ONE)); mpi_mul (h, k, mpi_const (MPI_C_THREE)); /* h = 3k */ loops = mpi_get_nbits (h); if (loops < 2) { /* If SCALAR is zero, the above mpi_mul sets H to zero and thus LOOPs will be zero. To avoid an underflow of I in the main loop we set LOOP to 2 and the result to (0,0,0). */ loops = 2; mpi_clear (result->x); mpi_clear (result->y); mpi_clear (result->z); } else { mpi_set (result->x, point->x); mpi_set (result->y, yy); mpi_set (result->z, point->z); } mpi_free (yy); yy = NULL; p1.x = x1; x1 = NULL; p1.y = y1; y1 = NULL; p1.z = z1; z1 = NULL; point_init (&p2); point_init (&p1inv); for (i=loops-2; i > 0; i--) { _gcry_mpi_ec_dup_point (result, result, ctx); if (mpi_test_bit (h, i) == 1 && mpi_test_bit (k, i) == 0) { point_set (&p2, result); _gcry_mpi_ec_add_points (result, &p2, &p1, ctx); } if (mpi_test_bit (h, i) == 0 && mpi_test_bit (k, i) == 1) { point_set (&p2, result); /* Invert point: y = p - y mod p */ point_set (&p1inv, &p1); ec_subm (p1inv.y, ctx->p, p1inv.y, ctx); _gcry_mpi_ec_add_points (result, &p2, &p1inv, ctx); } } point_free (&p1); point_free (&p2); point_free (&p1inv); mpi_free (h); mpi_free (k); #endif }
/* RESULT must have been initialized and is set on success to the point given by VALUE. */ gcry_err_code_t _gcry_ecc_os2ec (mpi_point_t result, gcry_mpi_t value) { gcry_err_code_t rc; size_t n; const unsigned char *buf; unsigned char *buf_memory; gcry_mpi_t x, y; if (mpi_is_opaque (value)) { unsigned int nbits; buf = mpi_get_opaque (value, &nbits); if (!buf) return GPG_ERR_INV_OBJ; n = (nbits + 7)/8; buf_memory = NULL; } else { n = (mpi_get_nbits (value)+7)/8; buf_memory = xmalloc (n); rc = _gcry_mpi_print (GCRYMPI_FMT_USG, buf_memory, n, &n, value); if (rc) { xfree (buf_memory); return rc; } buf = buf_memory; } if (n < 1) { xfree (buf_memory); return GPG_ERR_INV_OBJ; } if (*buf != 4) { xfree (buf_memory); return GPG_ERR_NOT_IMPLEMENTED; /* No support for point compression. */ } if ( ((n-1)%2) ) { xfree (buf_memory); return GPG_ERR_INV_OBJ; } n = (n-1)/2; rc = _gcry_mpi_scan (&x, GCRYMPI_FMT_USG, buf+1, n, NULL); if (rc) { xfree (buf_memory); return rc; } rc = _gcry_mpi_scan (&y, GCRYMPI_FMT_USG, buf+1+n, n, NULL); xfree (buf_memory); if (rc) { mpi_free (x); return rc; } mpi_set (result->x, x); mpi_set (result->y, y); mpi_set_ui (result->z, 1); mpi_free (x); mpi_free (y); return 0; }
/* RESULT = P1 + P2 */ void _gcry_mpi_ec_add_points (mpi_point_t result, mpi_point_t p1, mpi_point_t p2, mpi_ec_t ctx) { #define x1 (p1->x ) #define y1 (p1->y ) #define z1 (p1->z ) #define x2 (p2->x ) #define y2 (p2->y ) #define z2 (p2->z ) #define x3 (result->x) #define y3 (result->y) #define z3 (result->z) #define l1 (ctx->t.scratch[0]) #define l2 (ctx->t.scratch[1]) #define l3 (ctx->t.scratch[2]) #define l4 (ctx->t.scratch[3]) #define l5 (ctx->t.scratch[4]) #define l6 (ctx->t.scratch[5]) #define l7 (ctx->t.scratch[6]) #define l8 (ctx->t.scratch[7]) #define l9 (ctx->t.scratch[8]) #define t1 (ctx->t.scratch[9]) #define t2 (ctx->t.scratch[10]) if ( (!mpi_cmp (x1, x2)) && (!mpi_cmp (y1, y2)) && (!mpi_cmp (z1, z2)) ) { /* Same point; need to call the duplicate function. */ _gcry_mpi_ec_dup_point (result, p1, ctx); } else if (!mpi_cmp_ui (z1, 0)) { /* P1 is at infinity. */ mpi_set (x3, p2->x); mpi_set (y3, p2->y); mpi_set (z3, p2->z); } else if (!mpi_cmp_ui (z2, 0)) { /* P2 is at infinity. */ mpi_set (x3, p1->x); mpi_set (y3, p1->y); mpi_set (z3, p1->z); } else { int z1_is_one = !mpi_cmp_ui (z1, 1); int z2_is_one = !mpi_cmp_ui (z2, 1); /* l1 = x1 z2^2 */ /* l2 = x2 z1^2 */ if (z2_is_one) mpi_set (l1, x1); else { ec_powm (l1, z2, mpi_const (MPI_C_TWO), ctx); ec_mulm (l1, l1, x1, ctx); } if (z1_is_one) mpi_set (l2, x2); else { ec_powm (l2, z1, mpi_const (MPI_C_TWO), ctx); ec_mulm (l2, l2, x2, ctx); } /* l3 = l1 - l2 */ ec_subm (l3, l1, l2, ctx); /* l4 = y1 z2^3 */ ec_powm (l4, z2, mpi_const (MPI_C_THREE), ctx); ec_mulm (l4, l4, y1, ctx); /* l5 = y2 z1^3 */ ec_powm (l5, z1, mpi_const (MPI_C_THREE), ctx); ec_mulm (l5, l5, y2, ctx); /* l6 = l4 - l5 */ ec_subm (l6, l4, l5, ctx); if (!mpi_cmp_ui (l3, 0)) { if (!mpi_cmp_ui (l6, 0)) { /* P1 and P2 are the same - use duplicate function. */ _gcry_mpi_ec_dup_point (result, p1, ctx); } else { /* P1 is the inverse of P2. */ mpi_set_ui (x3, 1); mpi_set_ui (y3, 1); mpi_set_ui (z3, 0); } } else { /* l7 = l1 + l2 */ ec_addm (l7, l1, l2, ctx); /* l8 = l4 + l5 */ ec_addm (l8, l4, l5, ctx); /* z3 = z1 z2 l3 */ ec_mulm (z3, z1, z2, ctx); ec_mulm (z3, z3, l3, ctx); /* x3 = l6^2 - l7 l3^2 */ ec_powm (t1, l6, mpi_const (MPI_C_TWO), ctx); ec_powm (t2, l3, mpi_const (MPI_C_TWO), ctx); ec_mulm (t2, t2, l7, ctx); ec_subm (x3, t1, t2, ctx); /* l9 = l7 l3^2 - 2 x3 */ ec_mulm (t1, x3, mpi_const (MPI_C_TWO), ctx); ec_subm (l9, t2, t1, ctx); /* y3 = (l9 l6 - l8 l3^3)/2 */ ec_mulm (l9, l9, l6, ctx); ec_powm (t1, l3, mpi_const (MPI_C_THREE), ctx); /* fixme: Use saved value*/ ec_mulm (t1, t1, l8, ctx); ec_subm (y3, l9, t1, ctx); ec_mulm (y3, y3, ec_get_two_inv_p (ctx), ctx); } } #undef x1 #undef y1 #undef z1 #undef x2 #undef y2 #undef z2 #undef x3 #undef y3 #undef z3 #undef l1 #undef l2 #undef l3 #undef l4 #undef l5 #undef l6 #undef l7 #undef l8 #undef l9 #undef t1 #undef t2 }
static void ec_mulm (gcry_mpi_t w, gcry_mpi_t u, gcry_mpi_t v, mpi_ec_t ctx) { #if 0 /* NOTE: This code works only for limb sizes of 32 bit. */ mpi_limb_t *wp, *sp; if (ctx->nist_nbits == 192) { mpi_mul (w, u, v); mpi_resize (w, 12); wp = w->d; sp = ctx->s[0]->d; sp[0*2+0] = wp[0*2+0]; sp[0*2+1] = wp[0*2+1]; sp[1*2+0] = wp[1*2+0]; sp[1*2+1] = wp[1*2+1]; sp[2*2+0] = wp[2*2+0]; sp[2*2+1] = wp[2*2+1]; sp = ctx->s[1]->d; sp[0*2+0] = wp[3*2+0]; sp[0*2+1] = wp[3*2+1]; sp[1*2+0] = wp[3*2+0]; sp[1*2+1] = wp[3*2+1]; sp[2*2+0] = 0; sp[2*2+1] = 0; sp = ctx->s[2]->d; sp[0*2+0] = 0; sp[0*2+1] = 0; sp[1*2+0] = wp[4*2+0]; sp[1*2+1] = wp[4*2+1]; sp[2*2+0] = wp[4*2+0]; sp[2*2+1] = wp[4*2+1]; sp = ctx->s[3]->d; sp[0*2+0] = wp[5*2+0]; sp[0*2+1] = wp[5*2+1]; sp[1*2+0] = wp[5*2+0]; sp[1*2+1] = wp[5*2+1]; sp[2*2+0] = wp[5*2+0]; sp[2*2+1] = wp[5*2+1]; ctx->s[0]->nlimbs = 6; ctx->s[1]->nlimbs = 6; ctx->s[2]->nlimbs = 6; ctx->s[3]->nlimbs = 6; mpi_add (ctx->c, ctx->s[0], ctx->s[1]); mpi_add (ctx->c, ctx->c, ctx->s[2]); mpi_add (ctx->c, ctx->c, ctx->s[3]); while ( mpi_cmp (ctx->c, ctx->p ) >= 0 ) mpi_sub ( ctx->c, ctx->c, ctx->p ); mpi_set (w, ctx->c); } else if (ctx->nist_nbits == 384) { int i; mpi_mul (w, u, v); mpi_resize (w, 24); wp = w->d; #define NEXT(a) do { ctx->s[(a)]->nlimbs = 12; \ sp = ctx->s[(a)]->d; \ i = 0; } while (0) #define X(a) do { sp[i++] = wp[(a)];} while (0) #define X0(a) do { sp[i++] = 0; } while (0) NEXT(0); X(0);X(1);X(2);X(3);X(4);X(5);X(6);X(7);X(8);X(9);X(10);X(11); NEXT(1); X0();X0();X0();X0();X(21);X(22);X(23);X0();X0();X0();X0();X0(); NEXT(2); X(12);X(13);X(14);X(15);X(16);X(17);X(18);X(19);X(20);X(21);X(22);X(23); NEXT(3); X(21);X(22);X(23);X(12);X(13);X(14);X(15);X(16);X(17);X(18);X(19);X(20); NEXT(4); X0();X(23);X0();X(20);X(12);X(13);X(14);X(15);X(16);X(17);X(18);X(19); NEXT(5); X0();X0();X0();X0();X(20);X(21);X(22);X(23);X0();X0();X0();X0(); NEXT(6); X(20);X0();X0();X(21);X(22);X(23);X0();X0();X0();X0();X0();X0(); NEXT(7); X(23);X(12);X(13);X(14);X(15);X(16);X(17);X(18);X(19);X(20);X(21);X(22); NEXT(8); X0();X(20);X(21);X(22);X(23);X0();X0();X0();X0();X0();X0();X0(); NEXT(9); X0();X0();X0();X(23);X(23);X0();X0();X0();X0();X0();X0();X0(); #undef X0 #undef X #undef NEXT mpi_add (ctx->c, ctx->s[0], ctx->s[1]); mpi_add (ctx->c, ctx->c, ctx->s[1]); mpi_add (ctx->c, ctx->c, ctx->s[2]); mpi_add (ctx->c, ctx->c, ctx->s[3]); mpi_add (ctx->c, ctx->c, ctx->s[4]); mpi_add (ctx->c, ctx->c, ctx->s[5]); mpi_add (ctx->c, ctx->c, ctx->s[6]); mpi_sub (ctx->c, ctx->c, ctx->s[7]); mpi_sub (ctx->c, ctx->c, ctx->s[8]); mpi_sub (ctx->c, ctx->c, ctx->s[9]); while ( mpi_cmp (ctx->c, ctx->p ) >= 0 ) mpi_sub ( ctx->c, ctx->c, ctx->p ); while ( ctx->c->sign ) mpi_add ( ctx->c, ctx->c, ctx->p ); mpi_set (w, ctx->c); } else #endif /*0*/ mpi_mulm (w, u, v, ctx->p); }
/**************** * We do not need to use the strongest RNG because we gain no extra * security from it - The prime number is public and we could also * offer the factors for those who are willing to check that it is * indeed a strong prime. * * mode 0: Standard * 1: Make sure that at least one factor is of size qbits. */ MPI generate_elg_prime( int mode, unsigned pbits, unsigned qbits, MPI g, MPI **ret_factors ) { int n; /* number of factors */ int m; /* number of primes in pool */ unsigned fbits; /* length of prime factors */ MPI *factors; /* current factors */ MPI *pool; /* pool of primes */ MPI q; /* first prime factor (variable)*/ MPI prime; /* prime test value */ MPI q_factor; /* used for mode 1 */ byte *perms = NULL; int i, j; int count1, count2; unsigned nprime; unsigned req_qbits = qbits; /* the requested q bits size */ MPI val_2 = mpi_alloc_set_ui( 2 ); /* find number of needed prime factors */ for(n=1; (pbits - qbits - 1) / n >= qbits; n++ ) ; n--; if( !n || (mode==1 && n < 2) ) log_fatal("can't gen prime with pbits=%u qbits=%u\n", pbits, qbits ); if( mode == 1 ) { n--; fbits = (pbits - 2*req_qbits -1) / n; qbits = pbits - req_qbits - n*fbits; } else { fbits = (pbits - req_qbits -1) / n; qbits = pbits - n*fbits; } if( DBG_CIPHER ) log_debug("gen prime: pbits=%u qbits=%u fbits=%u/%u n=%d\n", pbits, req_qbits, qbits, fbits, n ); prime = mpi_alloc( (pbits + BITS_PER_MPI_LIMB - 1) / BITS_PER_MPI_LIMB ); q = gen_prime( qbits, 0, 0 ); q_factor = mode==1? gen_prime( req_qbits, 0, 0 ) : NULL; /* allocate an array to hold the factors + 2 for later usage */ factors = m_alloc_clear( (n+2) * sizeof *factors ); /* make a pool of 3n+5 primes (this is an arbitrary value) */ m = n*3+5; if( mode == 1 ) m += 5; /* need some more for DSA */ if( m < 25 ) m = 25; pool = m_alloc_clear( m * sizeof *pool ); /* permutate over the pool of primes */ count1=count2=0; do { next_try: if( !perms ) { /* allocate new primes */ for(i=0; i < m; i++ ) { mpi_free(pool[i]); pool[i] = NULL; } /* init m_out_of_n() */ perms = m_alloc_clear( m ); for(i=0; i < n; i++ ) { perms[i] = 1; pool[i] = gen_prime( fbits, 0, 0 ); factors[i] = pool[i]; } } else { m_out_of_n( perms, n, m ); for(i=j=0; i < m && j < n ; i++ ) if( perms[i] ) { if( !pool[i] ) pool[i] = gen_prime( fbits, 0, 0 ); factors[j++] = pool[i]; } if( i == n ) { m_free(perms); perms = NULL; progress('!'); goto next_try; /* allocate new primes */ } } mpi_set( prime, q ); mpi_mul_ui( prime, prime, 2 ); if( mode == 1 ) mpi_mul( prime, prime, q_factor ); for(i=0; i < n; i++ ) mpi_mul( prime, prime, factors[i] ); mpi_add_ui( prime, prime, 1 ); nprime = mpi_get_nbits(prime); if( nprime < pbits ) { if( ++count1 > 20 ) { count1 = 0; qbits++; progress('>'); mpi_free (q); q = gen_prime( qbits, 0, 0 ); goto next_try; } } else count1 = 0; if( nprime > pbits ) { if( ++count2 > 20 ) { count2 = 0; qbits--; progress('<'); mpi_free (q); q = gen_prime( qbits, 0, 0 ); goto next_try; } } else count2 = 0; } while( !(nprime == pbits && check_prime( prime, val_2 )) ); if( DBG_CIPHER ) { progress('\n'); log_mpidump( "prime : ", prime ); log_mpidump( "factor q: ", q ); if( mode == 1 ) log_mpidump( "factor q0: ", q_factor ); for(i=0; i < n; i++ ) log_mpidump( "factor pi: ", factors[i] ); log_debug("bit sizes: prime=%u, q=%u", mpi_get_nbits(prime), mpi_get_nbits(q) ); if( mode == 1 ) fprintf(stderr, ", q0=%u", mpi_get_nbits(q_factor) ); for(i=0; i < n; i++ ) fprintf(stderr, ", p%d=%u", i, mpi_get_nbits(factors[i]) ); progress('\n'); } if( ret_factors ) { /* caller wants the factors */ *ret_factors = m_alloc_clear( (n+2) * sizeof **ret_factors); i = 0; if( mode == 1 ) { (*ret_factors)[i++] = mpi_copy( q_factor ); for(; i <= n; i++ ) (*ret_factors)[i] = mpi_copy( factors[i] ); } else { for(; i < n; i++ ) (*ret_factors)[i] = mpi_copy( factors[i] ); } } if( g ) { /* create a generator (start with 3)*/ MPI tmp = mpi_alloc( mpi_get_nlimbs(prime) ); MPI b = mpi_alloc( mpi_get_nlimbs(prime) ); MPI pmin1 = mpi_alloc( mpi_get_nlimbs(prime) ); if( mode == 1 ) BUG(); /* not yet implemented */ factors[n] = q; factors[n+1] = mpi_alloc_set_ui(2); mpi_sub_ui( pmin1, prime, 1 ); mpi_set_ui(g,2); do { mpi_add_ui(g, g, 1); if( DBG_CIPHER ) { log_debug("checking g: "); mpi_print( stderr, g, 1 ); } else progress('^'); for(i=0; i < n+2; i++ ) { /*fputc('~', stderr);*/ mpi_fdiv_q(tmp, pmin1, factors[i] ); /* (no mpi_pow(), but it is okay to use this with mod prime) */ mpi_powm(b, g, tmp, prime ); if( !mpi_cmp_ui(b, 1) ) break; } if( DBG_CIPHER ) progress('\n'); } while( i < n+2 ); mpi_free(factors[n+1]); mpi_free(tmp); mpi_free(b); mpi_free(pmin1); } if( !DBG_CIPHER ) progress('\n'); m_free( factors ); /* (factors are shallow copies) */ for(i=0; i < m; i++ ) mpi_free( pool[i] ); m_free( pool ); m_free(perms); mpi_free(val_2); mpi_free(q); return prime; }
/**************** * We do not need to use the strongest RNG because we gain no extra * security from it - The prime number is public and we could also * offer the factors for those who are willing to check that it is * indeed a strong prime. With ALL_FACTORS set to true all afcors of * prime-1 are returned in FACTORS. * * mode 0: Standard * 1: Make sure that at least one factor is of size qbits. */ static gcry_err_code_t prime_generate_internal (int mode, gcry_mpi_t *prime_generated, unsigned int pbits, unsigned int qbits, gcry_mpi_t g, gcry_mpi_t **ret_factors, gcry_random_level_t randomlevel, unsigned int flags, int all_factors, gcry_prime_check_func_t cb_func, void *cb_arg) { gcry_err_code_t err = 0; gcry_mpi_t *factors_new = NULL; /* Factors to return to the caller. */ gcry_mpi_t *factors = NULL; /* Current factors. */ gcry_mpi_t *pool = NULL; /* Pool of primes. */ unsigned char *perms = NULL; /* Permutations of POOL. */ gcry_mpi_t q_factor = NULL; /* Used if QBITS is non-zero. */ unsigned int fbits = 0; /* Length of prime factors. */ unsigned int n = 0; /* Number of factors. */ unsigned int m = 0; /* Number of primes in pool. */ gcry_mpi_t q = NULL; /* First prime factor. */ gcry_mpi_t prime = NULL; /* Prime candidate. */ unsigned int nprime = 0; /* Bits of PRIME. */ unsigned int req_qbits; /* The original QBITS value. */ gcry_mpi_t val_2; /* For check_prime(). */ unsigned int is_secret = (flags & GCRY_PRIME_FLAG_SECRET); unsigned int count1 = 0, count2 = 0; unsigned int i = 0, j = 0; if (pbits < 48) return GPG_ERR_INV_ARG; /* If QBITS is not given, assume a reasonable value. */ if (!qbits) qbits = pbits / 3; req_qbits = qbits; /* Find number of needed prime factors. */ for (n = 1; (pbits - qbits - 1) / n >= qbits; n++) ; n--; val_2 = mpi_alloc_set_ui (2); if ((! n) || ((mode == 1) && (n < 2))) { err = GPG_ERR_INV_ARG; goto leave; } if (mode == 1) { n--; fbits = (pbits - 2 * req_qbits -1) / n; qbits = pbits - req_qbits - n * fbits; } else { fbits = (pbits - req_qbits -1) / n; qbits = pbits - n * fbits; } if (DBG_CIPHER) log_debug ("gen prime: pbits=%u qbits=%u fbits=%u/%u n=%d\n", pbits, req_qbits, qbits, fbits, n); prime = gcry_mpi_new (pbits); /* Generate first prime factor. */ q = gen_prime (qbits, is_secret, randomlevel, NULL, NULL); if (mode == 1) q_factor = gen_prime (req_qbits, is_secret, randomlevel, NULL, NULL); /* Allocate an array to hold the factors + 2 for later usage. */ factors = gcry_calloc (n + 2, sizeof (*factors)); if (!factors) { err = gpg_err_code_from_errno (errno); goto leave; } /* Make a pool of 3n+5 primes (this is an arbitrary value). */ m = n * 3 + 5; if (mode == 1) /* Need some more (for e.g. DSA). */ m += 5; if (m < 25) m = 25; pool = gcry_calloc (m , sizeof (*pool)); if (! pool) { err = gpg_err_code_from_errno (errno); goto leave; } /* Permutate over the pool of primes. */ do { next_try: if (! perms) { /* Allocate new primes. */ for(i = 0; i < m; i++) { mpi_free (pool[i]); pool[i] = NULL; } /* Init m_out_of_n(). */ perms = gcry_calloc (1, m); if (! perms) { err = gpg_err_code_from_errno (errno); goto leave; } for(i = 0; i < n; i++) { perms[i] = 1; pool[i] = gen_prime (fbits, is_secret, randomlevel, NULL, NULL); factors[i] = pool[i]; } } else { m_out_of_n ((char*)perms, n, m); for (i = j = 0; (i < m) && (j < n); i++) if (perms[i]) { if(! pool[i]) pool[i] = gen_prime (fbits, 0, 1, NULL, NULL); factors[j++] = pool[i]; } if (i == n) { gcry_free (perms); perms = NULL; progress ('!'); goto next_try; /* Allocate new primes. */ } } /* Generate next prime candidate: p = 2 * q [ * q_factor] * factor_0 * factor_1 * ... * factor_n + 1. */ mpi_set (prime, q); mpi_mul_ui (prime, prime, 2); if (mode == 1) mpi_mul (prime, prime, q_factor); for(i = 0; i < n; i++) mpi_mul (prime, prime, factors[i]); mpi_add_ui (prime, prime, 1); nprime = mpi_get_nbits (prime); if (nprime < pbits) { if (++count1 > 20) { count1 = 0; qbits++; progress('>'); mpi_free (q); q = gen_prime (qbits, 0, 0, NULL, NULL); goto next_try; } } else count1 = 0; if (nprime > pbits) { if (++count2 > 20) { count2 = 0; qbits--; progress('<'); mpi_free (q); q = gen_prime (qbits, 0, 0, NULL, NULL); goto next_try; } } else count2 = 0; } while (! ((nprime == pbits) && check_prime (prime, val_2, cb_func, cb_arg))); if (DBG_CIPHER) { progress ('\n'); log_mpidump ("prime : ", prime); log_mpidump ("factor q: ", q); if (mode == 1) log_mpidump ("factor q0: ", q_factor); for (i = 0; i < n; i++) log_mpidump ("factor pi: ", factors[i]); log_debug ("bit sizes: prime=%u, q=%u", mpi_get_nbits (prime), mpi_get_nbits (q)); if (mode == 1) log_debug (", q0=%u", mpi_get_nbits (q_factor)); for (i = 0; i < n; i++) log_debug (", p%d=%u", i, mpi_get_nbits (factors[i])); progress('\n'); } if (ret_factors) { /* Caller wants the factors. */ factors_new = gcry_calloc (n + 4, sizeof (*factors_new)); if (! factors_new) { err = gpg_err_code_from_errno (errno); goto leave; } if (all_factors) { i = 0; factors_new[i++] = gcry_mpi_set_ui (NULL, 2); factors_new[i++] = mpi_copy (q); if (mode == 1) factors_new[i++] = mpi_copy (q_factor); for(j=0; j < n; j++) factors_new[i++] = mpi_copy (factors[j]); } else { i = 0; if (mode == 1) { factors_new[i++] = mpi_copy (q_factor); for (; i <= n; i++) factors_new[i] = mpi_copy (factors[i]); } else for (; i < n; i++ ) factors_new[i] = mpi_copy (factors[i]); } } if (g) { /* Create a generator (start with 3). */ gcry_mpi_t tmp = mpi_alloc (mpi_get_nlimbs (prime)); gcry_mpi_t b = mpi_alloc (mpi_get_nlimbs (prime)); gcry_mpi_t pmin1 = mpi_alloc (mpi_get_nlimbs (prime)); if (mode == 1) err = GPG_ERR_NOT_IMPLEMENTED; else { factors[n] = q; factors[n + 1] = mpi_alloc_set_ui (2); mpi_sub_ui (pmin1, prime, 1); mpi_set_ui (g, 2); do { mpi_add_ui (g, g, 1); if (DBG_CIPHER) { log_debug ("checking g:"); gcry_mpi_dump (g); log_printf ("\n"); } else progress('^'); for (i = 0; i < n + 2; i++) { mpi_fdiv_q (tmp, pmin1, factors[i]); /* No mpi_pow(), but it is okay to use this with mod prime. */ gcry_mpi_powm (b, g, tmp, prime); if (! mpi_cmp_ui (b, 1)) break; } if (DBG_CIPHER) progress('\n'); } while (i < n + 2); mpi_free (factors[n+1]); mpi_free (tmp); mpi_free (b); mpi_free (pmin1); } } if (! DBG_CIPHER) progress ('\n'); leave: if (pool) { for(i = 0; i < m; i++) mpi_free (pool[i]); gcry_free (pool); } if (factors) gcry_free (factors); /* Factors are shallow copies. */ if (perms) gcry_free (perms); mpi_free (val_2); mpi_free (q); mpi_free (q_factor); if (! err) { *prime_generated = prime; if (ret_factors) *ret_factors = factors_new; } else { if (factors_new) { for (i = 0; factors_new[i]; i++) mpi_free (factors_new[i]); gcry_free (factors_new); } mpi_free (prime); } return err; }
/**************** * Calculate the multiplicative inverse X of A mod N * That is: Find the solution x for * 1 = (a*x) mod n */ int _gcry_mpi_invm (gcry_mpi_t x, gcry_mpi_t a, gcry_mpi_t n) { #if 0 gcry_mpi_t u, v, u1, u2, u3, v1, v2, v3, q, t1, t2, t3; gcry_mpi_t ta, tb, tc; u = mpi_copy(a); v = mpi_copy(n); u1 = mpi_alloc_set_ui(1); u2 = mpi_alloc_set_ui(0); u3 = mpi_copy(u); v1 = mpi_alloc_set_ui(0); v2 = mpi_alloc_set_ui(1); v3 = mpi_copy(v); q = mpi_alloc( mpi_get_nlimbs(u)+1 ); t1 = mpi_alloc( mpi_get_nlimbs(u)+1 ); t2 = mpi_alloc( mpi_get_nlimbs(u)+1 ); t3 = mpi_alloc( mpi_get_nlimbs(u)+1 ); while( mpi_cmp_ui( v3, 0 ) ) { mpi_fdiv_q( q, u3, v3 ); mpi_mul(t1, v1, q); mpi_mul(t2, v2, q); mpi_mul(t3, v3, q); mpi_sub(t1, u1, t1); mpi_sub(t2, u2, t2); mpi_sub(t3, u3, t3); mpi_set(u1, v1); mpi_set(u2, v2); mpi_set(u3, v3); mpi_set(v1, t1); mpi_set(v2, t2); mpi_set(v3, t3); } /* log_debug("result:\n"); log_mpidump("q =", q ); log_mpidump("u1=", u1); log_mpidump("u2=", u2); log_mpidump("u3=", u3); log_mpidump("v1=", v1); log_mpidump("v2=", v2); */ mpi_set(x, u1); mpi_free(u1); mpi_free(u2); mpi_free(u3); mpi_free(v1); mpi_free(v2); mpi_free(v3); mpi_free(q); mpi_free(t1); mpi_free(t2); mpi_free(t3); mpi_free(u); mpi_free(v); #elif 0 /* Extended Euclid's algorithm (See TAOCP Vol II, 4.5.2, Alg X) * modified according to Michael Penk's solution for Exercise 35 */ /* FIXME: we can simplify this in most cases (see Knuth) */ gcry_mpi_t u, v, u1, u2, u3, v1, v2, v3, t1, t2, t3; unsigned k; int sign; 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); } u1 = mpi_alloc_set_ui(1); u2 = mpi_alloc_set_ui(0); u3 = mpi_copy(u); v1 = mpi_copy(v); /* !-- used as const 1 */ v2 = mpi_alloc( mpi_get_nlimbs(u) ); mpi_sub( v2, u1, u ); v3 = mpi_copy(v); if( mpi_test_bit(u, 0) ) { /* u is odd */ t1 = mpi_alloc_set_ui(0); 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); t2 = mpi_alloc_set_ui(0); t3 = mpi_copy(u); } do { do { 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); Y4: ; } while( !mpi_test_bit( t3, 0 ) ); /* while t3 is even */ if( !t3->sign ) { mpi_set(u1, t1); mpi_set(u2, t2); mpi_set(u3, t3); } else { mpi_sub(v1, v, t1); sign = u->sign; u->sign = !u->sign; 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); mpi_sub(t2, u2, v2); mpi_sub(t3, u3, v3); if( t1->sign ) { mpi_add(t1, t1, v); 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(u2); mpi_free(u3); mpi_free(v1); mpi_free(v2); mpi_free(v3); mpi_free(t1); mpi_free(t2); mpi_free(t3); #else /* 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 */ gcry_mpi_t u, v, u1, u2=NULL, u3, v1, v2=NULL, v3, t1, t2=NULL, t3; unsigned 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); #endif return 1; }
void mpr_neg(mpr *rop, mpr *op) { mpi_neg(mpr_num(rop), mpr_num(op)); mpi_set(mpr_den(rop), mpr_den(op)); }
/**************** * 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, const MPI a, const MPI n) { /* Extended Euclid's algorithm (See TAOPC Vol II, 4.5.2, Alg X) * modified according to Michael Penk's solution for Exercice 35 * with further enhancement */ MPI u = NULL, v = NULL; MPI u1 = NULL, u2 = NULL, u3 = NULL; MPI v1 = NULL, v2 = NULL, v3 = NULL; MPI t1 = NULL, t2 = NULL, t3 = NULL; unsigned k; int sign; int odd = 0; int rc = -ENOMEM; if (mpi_copy(&u, a) < 0) goto cleanup; if (mpi_copy(&v, n) < 0) goto cleanup; for (k = 0; !mpi_test_bit(u, 0) && !mpi_test_bit(v, 0); k++) { if (mpi_rshift(u, u, 1) < 0) goto cleanup; if (mpi_rshift(v, v, 1) < 0) goto cleanup; } odd = mpi_test_bit(v, 0); u1 = mpi_alloc_set_ui(1); if (!u1) goto cleanup; if (!odd) { u2 = mpi_alloc_set_ui(0); if (!u2) goto cleanup; } if (mpi_copy(&u3, u) < 0) goto cleanup; if (mpi_copy(&v1, v) < 0) goto cleanup; if (!odd) { v2 = mpi_alloc(mpi_get_nlimbs(u)); if (!v2) goto cleanup; if (mpi_sub(v2, u1, u) < 0) goto cleanup; /* U is used as const 1 */ } if (mpi_copy(&v3, v) < 0) goto cleanup; if (mpi_test_bit(u, 0)) { /* u is odd */ t1 = mpi_alloc_set_ui(0); if (!t1) goto cleanup; if (!odd) { t2 = mpi_alloc_set_ui(1); if (!t2) goto cleanup; t2->sign = 1; } if (mpi_copy(&t3, v) < 0) goto cleanup; t3->sign = !t3->sign; goto Y4; } else { t1 = mpi_alloc_set_ui(1); if (!t1) goto cleanup; if (!odd) { t2 = mpi_alloc_set_ui(0); if (!t2) goto cleanup; } if (mpi_copy(&t3, u) < 0) goto cleanup; } do { do { if (!odd) { if (mpi_test_bit(t1, 0) || mpi_test_bit(t2, 0)) { /* one is odd */ if (mpi_add(t1, t1, v) < 0) goto cleanup; if (mpi_sub(t2, t2, u) < 0) goto cleanup; } if (mpi_rshift(t1, t1, 1) < 0) goto cleanup; if (mpi_rshift(t2, t2, 1) < 0) goto cleanup; if (mpi_rshift(t3, t3, 1) < 0) goto cleanup; } else { if (mpi_test_bit(t1, 0)) if (mpi_add(t1, t1, v) < 0) goto cleanup; if (mpi_rshift(t1, t1, 1) < 0) goto cleanup; if (mpi_rshift(t3, t3, 1) < 0) goto cleanup; } Y4: ; } while (!mpi_test_bit(t3, 0)); /* while t3 is even */ if (!t3->sign) { if (mpi_set(u1, t1) < 0) goto cleanup; if (!odd) if (mpi_set(u2, t2) < 0) goto cleanup; if (mpi_set(u3, t3) < 0) goto cleanup; } else { if (mpi_sub(v1, v, t1) < 0) goto cleanup; sign = u->sign; u->sign = !u->sign; if (!odd) if (mpi_sub(v2, u, t2) < 0) goto cleanup; u->sign = sign; sign = t3->sign; t3->sign = !t3->sign; if (mpi_set(v3, t3) < 0) goto cleanup; t3->sign = sign; } if (mpi_sub(t1, u1, v1) < 0) goto cleanup; if (!odd) if (mpi_sub(t2, u2, v2) < 0) goto cleanup; if (mpi_sub(t3, u3, v3) < 0) goto cleanup; if (t1->sign) { if (mpi_add(t1, t1, v) < 0) goto cleanup; if (!odd) if (mpi_sub(t2, t2, u) < 0) goto cleanup; } } while (mpi_cmp_ui(t3, 0)); /* while t3 != 0 */ /* mpi_lshift( u3, k ); */ rc = mpi_set(x, u1); cleanup: 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 rc; }