void mpi_sub(MPI w, MPI u, MPI v) { if( w == v ) { MPI vv = mpi_copy(v); vv->sign = !vv->sign; mpi_add( w, u, vv ); mpi_free(vv); } else { /* fixme: this is not thread-save (we temp. modify v) */ v->sign = !v->sign; mpi_add( w, u, v ); v->sign = !v->sign; } }
/* 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; }
int 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 ) { if (mpi_copy( &temp_divisor, divisor ) < 0) return -ENOMEM; divisor = temp_divisor; } if (mpi_tdiv_qr( quot, rem, dividend, divisor ) < 0) goto nomem; if( (divisor_sign ^ dividend->sign) && rem->nlimbs ) { if (mpi_sub_ui( quot, quot, 1 ) < 0) goto nomem; if (mpi_add( rem, rem, divisor) < 0) goto nomem; } if( temp_divisor ) mpi_free(temp_divisor); return 0; nomem: mpi_free(temp_divisor); return -ENOMEM; }
int mpi_fdiv_r( MPI rem, MPI dividend, MPI divisor ) { int rc = -ENOMEM; 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 ) { if (mpi_copy( &temp_divisor, divisor ) < 0) goto nomem; divisor = temp_divisor; } if (mpi_tdiv_qr(NULL, rem, dividend, divisor ) < 0) goto nomem; if( ((divisor_sign?1:0) ^ (dividend->sign?1:0)) && rem->nlimbs ) if (mpi_add( rem, rem, divisor) < 0) goto nomem; rc = 0; nomem: if( temp_divisor ) mpi_free(temp_divisor); return rc; }
int mpi_sub(MPI w, MPI u, MPI v) { int rc; if (w == v) { MPI vv; if (mpi_copy(&vv, v) < 0) return -ENOMEM; vv->sign = !vv->sign; rc = mpi_add(w, u, vv); mpi_free(vv); } else { v->sign = !v->sign; rc = mpi_add(w, u, v); v->sign = !v->sign; } return rc; }
static void do_add(void) { if( stackidx < 2 ) { fputs("stack underflow\n",stderr); return; } mpi_add( stack[stackidx-2], stack[stackidx-2], stack[stackidx-1] ); stackidx--; }
void mpi_add_u32(const mpi *a, uint32_t b, mpi *s) { /* TODO: optimize. */ mpi_t bb; mpi_init_u32(bb, b); mpi_add(a, bb, s); mpi_free(bb); }
void mpr_addi(mpr *rop, mpr *op1, long op2) { mpi prod; memset(&prod, '\0', sizeof(mpi)); mpi_muli(&prod, mpr_den(op1), op2); mpi_add(mpr_num(rop), mpr_num(op1), &prod); mpi_clear(&prod); }
int mpi_crt_finish(mpi_crt_ctx *ctx, mpi *a) { if (ctx->i == 0) return -1; if (mpi_is_neg(ctx->x)) mpi_add(ctx->x, ctx->m, a); else mpi_set_mpi(a, ctx->x); mpi_free(ctx->x); mpi_free(ctx->m); return 0; }
/* FIXME: I don't think this works for A==C or B==C .. */ void mpi_sub(const mpi *a, const mpi *b, mpi *c) { /* A - A = 0 */ if (mpi_cmp_eq(a, b)) { mpi_zero(c); return; } /* A - 0 = A */ if (b->size == 0) { mpi_set_mpi(c, a); return; } if (b == c) { c->sign ^= 1; mpi_add(a, b, c); } else { /* here, a could = c */ ((mpi *)b)->sign ^= 1; mpi_add(a, b, c); ((mpi *)b)->sign ^= 1; } }
/**************** * 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; }
/* Find multiplicative inverse B^-1 of B (mod M) such that B*B^-1 (mod M) = 1. * If such an inverse exists, stores the inverse in INV and returns 1. * Returns 0 otherwise. */ int mpi_modinv(const mpi *m, const mpi *b, mpi *inv) { ASSERT(mpi_cmp(b, m) < 0); mpi_t v, g; mpi_init(v); mpi_init(g); mpi_gcdext(b, m, inv, v, g); mpi_free(v); int g_is_one = mpi_is_one(g); mpi_free(g); if (g_is_one) { if (mpi_is_neg(inv)) mpi_add(inv, m, inv); return 1; } else { return 0; } }
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_gpg( 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_gpg(temp_divisor); }
void _gcry_mpi_fdiv_qr( gcry_mpi_t quot, gcry_mpi_t rem, gcry_mpi_t dividend, gcry_mpi_t divisor ) { int divisor_sign = divisor->sign; gcry_mpi_t temp_divisor = NULL; if( quot == divisor || rem == divisor ) { temp_divisor = mpi_copy( divisor ); divisor = temp_divisor; } _gcry_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); }
static void mpr_addsub(mpr *rop, mpr *op1, mpr *op2, int sub) { mpi prod1, prod2; memset(&prod1, '\0', sizeof(mpi)); memset(&prod2, '\0', sizeof(mpi)); mpi_mul(&prod1, mpr_num(op1), mpr_den(op2)); mpi_mul(&prod2, mpr_num(op2), mpr_den(op1)); if (sub) mpi_sub(mpr_num(rop), &prod1, &prod2); else mpi_add(mpr_num(rop), &prod1, &prod2); mpi_clear(&prod1); mpi_clear(&prod2); mpi_mul(mpr_den(rop), mpr_den(op1), mpr_den(op2)); }
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_gpg( 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_gpg(temp_divisor); }
int mpi_crt_step(mpi_crt_ctx *ctx, const mpi *a_i, const mpi *m_i) { if (ctx->i == 0) { mpi_init_mpi(ctx->x, a_i); mpi_init_mpi(ctx->m, m_i); } else { mpi_t u, v, gcd; mpi_init(u); mpi_init(v); mpi_init(gcd); mpi_gcdext(ctx->m, m_i, u, v, gcd); if (!mpi_is_one(gcd)) { mpi_free(u); mpi_free(v); mpi_free(gcd); mpi_free(ctx->x); mpi_free(ctx->m); ctx->i = 0; return -1; } mpi_mul(u, ctx->m, u); mpi_mul(u, a_i, u); mpi_mul(v, m_i, v); mpi_mul(v, ctx->x, v); mpi_add(u, v, ctx->x); mpi_mul(ctx->m, m_i, ctx->m); mpi_mod(ctx->x, ctx->m, ctx->x); mpi_free(u); mpi_free(v); mpi_free(gcd); } ctx->i++; return 0; }
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); }
void mpi_addm( MPI w, MPI u, MPI v, MPI m) { mpi_add(w, u, v); mpi_fdiv_r( w, w, m ); }
/**************** * 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; }
/**************** * 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; }
/* * Double/Single->Single modulo division (mpi/mpi) * *a %= *b * Divisor's MSW must be >= 0x8000 */ void mpi_moduu(uint16_t* a, const uint16_t* b) { uint16_t* pr = a + MPI_NUMBER_SIZE;// Initial partial remainder is the dividend's upper half uint8_t count = MPI_NUMBER_SIZE+1; uint8_t flag = 0; // If PR has N+1 significant words, this flag = 1 uint32_t pq; // Partial quotient uint32_t carry; // Loop through the lower half of the dividend, bringing digits down to the PR do { if(flag) { // Number of words in PR is 1 more than in the divisor. Apply pq guessing pq = (((uint32_t)pr[MPI_NUMBER_SIZE])<<16) | (uint32_t)pr[MPI_NUMBER_SIZE-1]; pq /= (uint32_t)b[MPI_NUMBER_SIZE-1]; if(pq>0xFFFF) pq = 0xFFFF; // Divide overflow, use pq=0xFFFF // Multiply the divisor by pq, subtract the result from PR if(!mpi_mulsubuuk(pr,b,pq)) { // trial pq was too high (max 1 or 2 too high), add the divisor back and check carry = mpi_add(pr,b); carry += pr[MPI_NUMBER_SIZE]; pr[MPI_NUMBER_SIZE] = carry&0xFFFF; if(!(carry&0x10000)) { // Trial pq was still too high, add the divisor back again carry = mpi_add(pr,b); carry += pr[MPI_NUMBER_SIZE]; pr[MPI_NUMBER_SIZE] = carry&0xFFFF; } } // pr[MPI_NUMBER_SIZE] must be 0 here, but another digit will come at the next loop iteration flag = pr[MPI_NUMBER_SIZE-1]!=0; } else { // PR has N significant words or less if(pr[MPI_NUMBER_SIZE-1]) // MSW of PR { // PR has N significant words, same as dividend if(mpi_cmp(pr,b)>=0) { // PR is >= divisor, pq=1, update PR mpi_sub(pr,b); // If MSW of PR after subtraction is >0, there will be N+1 words flag = pr[MPI_NUMBER_SIZE-1]!=0; } else { // PR is < divisor, pq=0, there will be N+1 words flag = 1; } } else { // PR has less than N significant words. pq=0, leave the flag at 0 } } pr--; // Bring in another digit from the dividend into PR } while(--count); }
int mpi_addm(MPI w, MPI u, MPI v, MPI m) { if (mpi_add(w, u, v) < 0 || mpi_fdiv_r(w, w, m) < 0) return -ENOMEM; return 0; }