static void test_keys( RSA_secret_key *sk, unsigned nbits ) { RSA_public_key pk; MPI test = mpi_alloc( (nbits+BITS_PER_MPI_LIMB-1)/BITS_PER_MPI_LIMB ); MPI out1 = mpi_alloc( (nbits+BITS_PER_MPI_LIMB-1)/BITS_PER_MPI_LIMB ); MPI out2 = mpi_alloc( (nbits+BITS_PER_MPI_LIMB-1)/BITS_PER_MPI_LIMB ); pk.n = sk->n; pk.e = sk->e; { char *p = get_random_bits( nbits, 0, 0 ); mpi_set_buffer( test, p, (nbits+7)/8, 0 ); m_free(p); } public( out1, test, &pk );
void _gcry_mpi_fdiv_q( gcry_mpi_t quot, gcry_mpi_t dividend, gcry_mpi_t divisor ) { gcry_mpi_t tmp = mpi_alloc( mpi_get_nlimbs(quot) ); _gcry_mpi_fdiv_qr( quot, tmp, dividend, divisor); mpi_free(tmp); }
mpi_copy_gpg( MPI a ) #endif { int i; MPI b; if( a && (a->flags & 4) ) { void *p = m_is_secure(a->d)? xmalloc_secure( a->nbits ) : xmalloc( a->nbits ); memcpy( p, a->d, a->nbits ); b = mpi_set_opaque( NULL, p, a->nbits ); } else if( a ) { #ifdef M_DEBUG b = mpi_is_secure(a)? mpi_debug_alloc_secure( a->nlimbs, info ) : mpi_debug_alloc( a->nlimbs, info ); #else b = mpi_is_secure(a)? mpi_alloc_secure( a->nlimbs ) : mpi_alloc( a->nlimbs ); #endif b->nlimbs = a->nlimbs; b->sign = a->sign; b->flags = a->flags; b->nbits = a->nbits; for(i=0; i < b->nlimbs; i++ ) b->d[i] = a->d[i]; } else b = NULL; return b; }
void gcry_mpi_div (gcry_mpi_t quot, gcry_mpi_t rem, gcry_mpi_t dividend, gcry_mpi_t divisor, int round) { if (!round) { if (!rem) { gcry_mpi_t tmp = mpi_alloc (mpi_get_nlimbs(quot)); _gcry_mpi_tdiv_qr (quot, tmp, dividend, divisor); mpi_free (tmp); } else _gcry_mpi_tdiv_qr (quot, rem, dividend, divisor); } else if (round < 0) { if (!rem) _gcry_mpi_fdiv_q (quot, dividend, divisor); else if (!quot) _gcry_mpi_fdiv_r (rem, dividend, divisor); else _gcry_mpi_fdiv_qr (quot, rem, dividend, divisor); } else log_bug ("mpi rounding to ceiling not yet implemented\n"); }
/**************** * Note: This copy function should not interpret the MPI * but copy it transparently. */ int mpi_copy(MPI *copied, cMPI a ) { size_t i; MPI b; *copied = MPI_NULL; if ( a ) { b = mpi_alloc( a->nlimbs ); if (!b) return -ENOMEM; b->nlimbs = a->nlimbs; b->sign = a->sign; b->flags = a->flags; b->nbits = a->nbits; for (i = 0; i < b->nlimbs; i++ ) b->d[i] = a->d[i]; *copied = b; } return 0; }
mpi_alloc_like( MPI a ) #endif { MPI b; if( a && (a->flags & 4) ) { void *p = m_is_secure(a->d)? xmalloc_secure( a->nbits ) : xmalloc( a->nbits ); memcpy( p, a->d, a->nbits ); b = mpi_set_opaque( NULL, p, a->nbits ); } else if( a ) { #ifdef M_DEBUG b = mpi_is_secure(a)? mpi_debug_alloc_secure( a->nlimbs, info ) : mpi_debug_alloc( a->nlimbs, info ); #else b = mpi_is_secure(a)? mpi_alloc_secure( a->nlimbs ) : mpi_alloc( a->nlimbs ); #endif b->nlimbs = 0; b->sign = 0; b->flags = a->flags; b->nbits = 0; } else b = NULL; return b; }
MPI mpi_set_opaque( MPI a, void *p, unsigned int len ) { if( !a ) { #ifdef M_DEBUG a = mpi_debug_alloc(0,"alloc_opaque"); #else a = mpi_alloc(0); #endif } if( a->flags & 4 ) xfree( a->d ); else { #ifdef M_DEBUG mpi_debug_free_limb_space(a->d, "alloc_opaque"); #else mpi_free_gpg_limb_space(a->d); #endif } a->d = p; a->alloced = 0; a->nlimbs = 0; a->nbits = len; a->flags = 4; return a; }
static void test_keys( RSA_secret_key *sk, unsigned nbits ) { RSA_public_key pk; MPI test = mpi_alloc ( mpi_nlimb_hint_from_nbits (nbits) ); MPI out1 = mpi_alloc ( mpi_nlimb_hint_from_nbits (nbits) ); MPI out2 = mpi_alloc ( mpi_nlimb_hint_from_nbits (nbits) ); pk.n = sk->n; pk.e = sk->e; { char *p = get_random_bits( nbits, 0, 0 ); mpi_set_buffer( test, p, (nbits+7)/8, 0 ); xfree(p); } public( out1, test, &pk );
/**************** * Note: This copy function should not interpret the MPI * but copy it transparently. */ gcry_mpi_t gcry_mpi_copy( gcry_mpi_t a ) { int i; gcry_mpi_t b; if( a && (a->flags & 4) ) { void *p = gcry_is_secure(a->d)? gcry_xmalloc_secure( (a->sign+7)/8 ) : gcry_xmalloc( (a->sign+7)/8 ); memcpy( p, a->d, (a->sign+7)/8 ); b = gcry_mpi_set_opaque( NULL, p, a->sign ); } else if( a ) { b = mpi_is_secure(a)? mpi_alloc_secure( a->nlimbs ) : mpi_alloc( a->nlimbs ); b->nlimbs = a->nlimbs; b->sign = a->sign; b->flags = a->flags; for(i=0; i < b->nlimbs; i++ ) b->d[i] = a->d[i]; } else b = NULL; return b; }
/**************** * To check the validity of the value, recalculate the correspondence * between the public value and the secret one. */ static int check_secret_key (ECC_secret_key * sk) { mpi_point_t Q; gcry_mpi_t y_2, y2 = mpi_alloc (0); mpi_ec_t ctx; /* ?primarity test of 'p' */ /* (...) //!! */ /* G in E(F_p) */ y_2 = gen_y_2 (sk->E.G.x, &sk->E); /* y^2=x^3+a*x+b */ mpi_mulm (y2, sk->E.G.y, sk->E.G.y, sk->E.p); /* y^2=y*y */ if (mpi_cmp (y_2, y2)) { if (DBG_CIPHER) log_debug ("Bad check: Point 'G' does not belong to curve 'E'!\n"); return (1); } /* G != PaI */ if (!mpi_cmp_ui (sk->E.G.z, 0)) { if (DBG_CIPHER) log_debug ("Bad check: 'G' cannot be Point at Infinity!\n"); return (1); } point_init (&Q); ctx = _gcry_mpi_ec_init (sk->E.p, sk->E.a); _gcry_mpi_ec_mul_point (&Q, sk->E.n, &sk->E.G, ctx); if (mpi_cmp_ui (Q.z, 0)) { if (DBG_CIPHER) log_debug ("check_secret_key: E is not a curve of order n\n"); point_free (&Q); _gcry_mpi_ec_free (ctx); return 1; } /* pubkey cannot be PaI */ if (!mpi_cmp_ui (sk->Q.z, 0)) { if (DBG_CIPHER) log_debug ("Bad check: Q can not be a Point at Infinity!\n"); _gcry_mpi_ec_free (ctx); return (1); } /* pubkey = [d]G over E */ _gcry_mpi_ec_mul_point (&Q, sk->d, &sk->E.G, ctx); if ((Q.x == sk->Q.x) && (Q.y == sk->Q.y) && (Q.z == sk->Q.z)) { if (DBG_CIPHER) log_debug ("Bad check: There is NO correspondence between 'd' and 'Q'!\n"); _gcry_mpi_ec_free (ctx); return (1); } _gcry_mpi_ec_free (ctx); point_free (&Q); return 0; }
static gcry_err_code_t ecc_sign (int algo, gcry_mpi_t *resarr, gcry_mpi_t data, gcry_mpi_t *skey) { gpg_err_code_t err; ECC_secret_key sk; (void)algo; if (!data || !skey[0] || !skey[1] || !skey[2] || !skey[3] || !skey[4] || !skey[5] || !skey[6] ) return GPG_ERR_BAD_MPI; sk.E.p = skey[0]; sk.E.a = skey[1]; sk.E.b = skey[2]; point_init (&sk.E.G); err = os2ec (&sk.E.G, skey[3]); if (err) { point_free (&sk.E.G); return err; } sk.E.n = skey[4]; point_init (&sk.Q); err = os2ec (&sk.Q, skey[5]); if (err) { point_free (&sk.E.G); point_free (&sk.Q); return err; } sk.d = skey[6]; resarr[0] = mpi_alloc (mpi_get_nlimbs (sk.E.p)); resarr[1] = mpi_alloc (mpi_get_nlimbs (sk.E.p)); err = sign (data, &sk, resarr[0], resarr[1]); if (err) { mpi_free (resarr[0]); mpi_free (resarr[1]); resarr[0] = NULL; /* Mark array as released. */ } point_free (&sk.E.G); point_free (&sk.Q); return err; }
gcry_mpi_t _gcry_mpi_alloc_set_ui( unsigned long u) { gcry_mpi_t w = mpi_alloc(1); w->d[0] = u; w->nlimbs = u? 1:0; w->sign = 0; return w; }
int elg_encrypt( int algo, MPI *resarr, MPI data, MPI *pkey ) { ELG_public_key pk; if( !is_ELGAMAL(algo) ) return G10ERR_PUBKEY_ALGO; if( !data || !pkey[0] || !pkey[1] || !pkey[2] ) return G10ERR_BAD_MPI; pk.p = pkey[0]; pk.g = pkey[1]; pk.y = pkey[2]; resarr[0] = mpi_alloc( mpi_get_nlimbs( pk.p ) ); resarr[1] = mpi_alloc( mpi_get_nlimbs( pk.p ) ); do_encrypt( resarr[0], resarr[1], data, &pk ); return 0; }
MPI mpi_alloc_set_ui(unsigned long u) { MPI w = mpi_alloc(1); if (!w) return w; w->d[0] = u; w->nlimbs = u? 1:0; w->sign = 0; return w; }
int mpi_fdiv_q( MPI quot, MPI dividend, MPI divisor ) { MPI tmp = mpi_alloc( mpi_get_nlimbs(quot) ); if (!tmp) return -ENOMEM; mpi_fdiv_qr( quot, tmp, dividend, divisor); mpi_free(tmp); return 0; }
MPI do_encode_md(const void *sha_buffer, unsigned nbits) { int nframe = (nbits+7) / 8; uint8_t *frame, *fr_pt; int i = 0, n; size_t asnlen = DIM(asn); MPI a = MPI_NULL; if(SHA1_DIGEST_LENGTH + asnlen + 4 > nframe ) printk("MPI: can't encode a %d bit MD into a %d bits frame\n", (int)(SHA1_DIGEST_LENGTH*8), (int)nbits); /* We encode the MD in this way: * * 0 A PAD(n bytes) 0 ASN(asnlen bytes) MD(len bytes) * * PAD consists of FF bytes. */ //daveti: hack //frame = kmalloc(nframe, GFP_KERNEL); frame = kmalloc(nframe, GFP_ATOMIC); if (!frame) return MPI_NULL; n = 0; frame[n++] = 0; frame[n++] = 1; /* block type */ i = nframe - SHA1_DIGEST_LENGTH - asnlen -3 ; if(i <= 1) { printk("MPI: message digest encoding failed\n"); kfree(frame); return a; } memset( frame+n, 0xff, i ); n += i; frame[n++] = 0; memcpy( frame+n, &asn, asnlen ); n += asnlen; memcpy( frame+n, sha_buffer, SHA1_DIGEST_LENGTH ); n += SHA1_DIGEST_LENGTH; i = nframe; fr_pt = frame; if (n != nframe) { printk("MPI: message digest encoding failed, frame length is wrong\n"); kfree(frame); return a; } a = mpi_alloc( (nframe+BYTES_PER_MPI_LIMB-1) / BYTES_PER_MPI_LIMB ); mpi_set_buffer( a, frame, nframe, 0 ); kfree(frame); return a; }
/**************** * Test whether the secret key is valid. * Returns: true if this is a valid key. */ static int check_secret_key( RSA_secret_key *sk ) { int rc; gcry_mpi_t temp = mpi_alloc( mpi_get_nlimbs(sk->p)*2 ); mpi_mul(temp, sk->p, sk->q ); rc = mpi_cmp( temp, sk->n ); mpi_free(temp); return !rc; }
/**************** * Test whether the secret key is valid. * Returns: if this is a valid key. */ static int check_secret_key( ELG_secret_key *sk ) { int rc; gcry_mpi_t y = mpi_alloc( mpi_get_nlimbs(sk->y) ); gcry_mpi_powm( y, sk->g, sk->x, sk->p ); rc = !mpi_cmp( y, sk->y ); mpi_free( y ); return rc; }
/* Accessor for helper variable. */ static gcry_mpi_t ec_get_two_inv_p (mpi_ec_t ec) { if (!ec->t.valid.two_inv_p) { ec->t.valid.two_inv_p = 1; if (!ec->t.two_inv_p) ec->t.two_inv_p = mpi_alloc (0); ec_invm (ec->t.two_inv_p, mpi_const (MPI_C_TWO), ec); } return ec->t.two_inv_p; }
static void sign(gcry_mpi_t a, gcry_mpi_t b, gcry_mpi_t input, ELG_secret_key *skey ) { gcry_mpi_t k; gcry_mpi_t t = mpi_alloc( mpi_get_nlimbs(a) ); gcry_mpi_t inv = mpi_alloc( mpi_get_nlimbs(a) ); gcry_mpi_t p_1 = mpi_copy(skey->p); /* * b = (t * inv) mod (p-1) * b = (t * inv(k,(p-1),(p-1)) mod (p-1) * b = (((M-x*a) mod (p-1)) * inv(k,(p-1),(p-1))) mod (p-1) * */ mpi_sub_ui(p_1, p_1, 1); k = gen_k( skey->p, 0 /* no small K ! */ ); gcry_mpi_powm( a, skey->g, k, skey->p ); mpi_mul(t, skey->x, a ); mpi_subm(t, input, t, p_1 ); mpi_invm(inv, k, p_1 ); mpi_mulm(b, t, inv, p_1 ); #if 0 if( DBG_CIPHER ) { log_mpidump("elg sign p= ", skey->p); log_mpidump("elg sign g= ", skey->g); log_mpidump("elg sign y= ", skey->y); log_mpidump("elg sign x= ", skey->x); log_mpidump("elg sign k= ", k); log_mpidump("elg sign M= ", input); log_mpidump("elg sign a= ", a); log_mpidump("elg sign b= ", b); } #endif mpi_free(k); mpi_free(t); mpi_free(inv); mpi_free(p_1); }
MPI mpi_read_from_buffer(byte *buffer, unsigned int *ret_nread, int secure) { int i, j; unsigned nbits, nbytes, nlimbs, nread=0; mpi_limb_t a; MPI val = NULL; if( *ret_nread < 2 ) goto leave; nbits = buffer[0] << 8 | buffer[1]; if( nbits > MAX_EXTERN_MPI_BITS ) { log_info ("mpi too large (%u bits)\n", nbits); goto leave; } buffer += 2; nread = 2; nbytes = (nbits+7) / 8; nlimbs = (nbytes+BYTES_PER_MPI_LIMB-1) / BYTES_PER_MPI_LIMB; val = secure? mpi_alloc_secure( nlimbs ) : mpi_alloc( nlimbs ); i = BYTES_PER_MPI_LIMB - nbytes % BYTES_PER_MPI_LIMB; i %= BYTES_PER_MPI_LIMB; val->nbits = nbits; j= val->nlimbs = nlimbs; val->sign = 0; for( ; j > 0; j-- ) { a = 0; for(; i < BYTES_PER_MPI_LIMB; i++ ) { if( ++nread > *ret_nread ) { /* This (as well as the above error condition) may happen if we use this function to parse a decrypted MPI which didn't turn out to be a real MPI - possible because the supplied key was wrong but the OpenPGP checksum didn't caught it. */ log_info ("mpi larger than buffer\n"); mpi_free (val); val = NULL; goto leave; } a <<= 8; a |= *buffer++; } i = 0; val->d[j-1] = a; } leave: *ret_nread = nread; return val; }
MPI mpi_alloc_set_ui( unsigned long u) { #ifdef M_DEBUG MPI w = mpi_debug_alloc(1,"alloc_set_ui"); #else MPI w = mpi_alloc(1); #endif w->d[0] = u; w->nlimbs = u? 1:0; w->sign = 0; return w; }
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--; }
mpi_read(IOBUF inp, unsigned *ret_nread, int secure) #endif { int c, i, j; unsigned nbits, nbytes, nlimbs, nread=0; mpi_limb_t a; MPI val = MPI_NULL; if( (c = iobuf_get(inp)) == -1 ) goto leave; nbits = c << 8; if( (c = iobuf_get(inp)) == -1 ) goto leave; nbits |= c; if( nbits > MAX_EXTERN_MPI_BITS ) { log_error("mpi too large (%u bits)\n", nbits); goto leave; } nread = 2; nbytes = (nbits+7) / 8; nlimbs = (nbytes+BYTES_PER_MPI_LIMB-1) / BYTES_PER_MPI_LIMB; #ifdef M_DEBUG val = secure? mpi_debug_alloc_secure( nlimbs, info ) : mpi_debug_alloc( nlimbs, info ); #else val = secure? mpi_alloc_secure( nlimbs ) : mpi_alloc( nlimbs ); #endif i = BYTES_PER_MPI_LIMB - nbytes % BYTES_PER_MPI_LIMB; i %= BYTES_PER_MPI_LIMB; val->nbits = nbits; j= val->nlimbs = nlimbs; val->sign = 0; for( ; j > 0; j-- ) { a = 0; for(; i < BYTES_PER_MPI_LIMB; i++ ) { a <<= 8; a |= iobuf_get(inp) & 0xff; nread++; } i = 0; val->d[j-1] = a; } leave: if( nread > *ret_nread ) log_bug("mpi crosses packet border\n"); else *ret_nread = nread; return val; }
gcry_err_code_t _gcry_elg_encrypt (int algo, gcry_mpi_t *resarr, gcry_mpi_t data, gcry_mpi_t *pkey, int flags) { gcry_err_code_t err = GPG_ERR_NO_ERROR; ELG_public_key pk; (void)algo; (void)flags; if ((! data) || (! pkey[0]) || (! pkey[1]) || (! pkey[2])) err = GPG_ERR_BAD_MPI; else { pk.p = pkey[0]; pk.g = pkey[1]; pk.y = pkey[2]; resarr[0] = mpi_alloc (mpi_get_nlimbs (pk.p)); resarr[1] = mpi_alloc (mpi_get_nlimbs (pk.p)); do_encrypt (resarr[0], resarr[1], data, &pk); } return err; }
/* Helper used to scan PGP style MPIs. Returns NULL on failure. */ static gcry_mpi_t mpi_read_from_buffer (const unsigned char *buffer, unsigned *ret_nread, int secure) { int i, j; unsigned int nbits, nbytes, nlimbs, nread=0; mpi_limb_t a; gcry_mpi_t val = MPI_NULL; if ( *ret_nread < 2 ) goto leave; nbits = buffer[0] << 8 | buffer[1]; if ( nbits > MAX_EXTERN_MPI_BITS ) { /* log_debug ("mpi too large (%u bits)\n", nbits); */ goto leave; } buffer += 2; nread = 2; nbytes = (nbits+7) / 8; nlimbs = (nbytes+BYTES_PER_MPI_LIMB-1) / BYTES_PER_MPI_LIMB; val = secure? mpi_alloc_secure (nlimbs) : mpi_alloc (nlimbs); i = BYTES_PER_MPI_LIMB - nbytes % BYTES_PER_MPI_LIMB; i %= BYTES_PER_MPI_LIMB; j= val->nlimbs = nlimbs; val->sign = 0; for ( ; j > 0; j-- ) { a = 0; for (; i < BYTES_PER_MPI_LIMB; i++ ) { if ( ++nread > *ret_nread ) { /* log_debug ("mpi larger than buffer"); */ mpi_free (val); val = NULL; goto leave; } a <<= 8; a |= *buffer++; } i = 0; val->d[j-1] = a; } leave: *ret_nread = nread; return val; }
static void do_powm(void) { MPI a; if( stackidx < 3 ) { fputs("stack underflow\n", stderr); return; } a= mpi_alloc(10); mpi_powm( a, stack[stackidx-3], stack[stackidx-2], stack[stackidx-1] ); mpi_free(stack[stackidx-3]); stack[stackidx-3] = a; stackidx -= 2; }
MPI mpi_read_from_buffer(const void *xbuffer, unsigned *ret_nread) { const uint8_t *buffer = xbuffer; int i, j; unsigned nbits, nbytes, nlimbs, nread = 0; mpi_limb_t a; MPI val = NULL; if (*ret_nread < 2) goto leave; nbits = buffer[0] << 8 | buffer[1]; if (nbits > MAX_EXTERN_MPI_BITS) { pr_info("MPI: mpi too large (%u bits)\n", nbits); goto leave; } buffer += 2; nread = 2; nbytes = (nbits + 7) / 8; nlimbs = (nbytes + BYTES_PER_MPI_LIMB - 1) / BYTES_PER_MPI_LIMB; val = mpi_alloc(nlimbs); if (!val) return NULL; i = BYTES_PER_MPI_LIMB - nbytes % BYTES_PER_MPI_LIMB; i %= BYTES_PER_MPI_LIMB; val->nbits = nbits; j = val->nlimbs = nlimbs; val->sign = 0; for (; j > 0; j--) { a = 0; for (; i < BYTES_PER_MPI_LIMB; i++) { if (++nread > *ret_nread) { printk ("MPI: mpi larger than buffer nread=%d ret_nread=%d\n", nread, *ret_nread); goto leave; } a <<= 8; a |= *buffer++; } i = 0; val->d[j - 1] = a; } leave: *ret_nread = nread; return val; }
gcry_err_code_t _gcry_elg_sign (int algo, gcry_mpi_t *resarr, gcry_mpi_t data, gcry_mpi_t *skey) { gcry_err_code_t err = GPG_ERR_NO_ERROR; ELG_secret_key sk; (void)algo; if ((! data) || (! skey[0]) || (! skey[1]) || (! skey[2]) || (! skey[3])) err = GPG_ERR_BAD_MPI; else { sk.p = skey[0]; sk.g = skey[1]; sk.y = skey[2]; sk.x = skey[3]; resarr[0] = mpi_alloc (mpi_get_nlimbs (sk.p)); resarr[1] = mpi_alloc (mpi_get_nlimbs (sk.p)); sign (resarr[0], resarr[1], data, &sk); } return err; }
/**************** * 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; }