error bignum_mult(bignum *tmp, bignum *r, const bignum *a, const bignum *b) { if (r == a || r == b) { error err = bignum_mul(tmp, a, b); if (err) return err; return bignum_dup(r, tmp); } return bignum_mul(r, a, b); }
static _rs_inline obj long_mul( INT_64 a, INT_64 b ) { int am, bm; if((am = search_one(a))<0 || (bm = search_one(b))<0) return ZERO; if(am + bm <= 63) return int_64_compact( int_64_mul(a,b) ); return bignum_mul(int64_to_bignum(a), int64_to_bignum(b)); }
/** * Algo de karatsuba pour la multiplication de grands entiers */ bignum* bignum_mul(bignum a, bignum b) { int len_a = bignum_len(a); int len_b = bignum_len(b); // Multiplication stupide pour les petits nombres if(len_a < 2 || len_b < 2) { return bignum_dumb_mul(a, b); } int max = MAX(len_a, len_b); int max_middle = max/2; bignum* high_a = bignum_init(); bignum* high_b = bignum_init(); bignum* low_a = bignum_init(); bignum* low_b = bignum_init(); bignum_split(a, max-max_middle, high_a, low_a); bignum_split(b, max-max_middle, high_b, low_b); bignum* z2 = bignum_mul(*high_a, *high_b); bignum* z0 = bignum_mul(*low_a, *low_b); // Je voudrais de l'operator overloading : (z2*10^(max))+((z1-z2-z0)*10^(max_middle))+(z0) bignum* sum_a = bignum_add(*low_a, *high_a); bignum* sum_b = bignum_add(*low_b, *high_b); bignum_destoroyah(high_a); bignum_destoroyah(high_b); bignum_destoroyah(low_a); bignum_destoroyah(low_b); // z1 = (sum_a*sum_b) - z2 - z0 bignum* mul_of_sum = bignum_mul(*sum_a, *sum_b); bignum* diff_a = bignum_sub(*mul_of_sum,*z2); bignum* z1 = bignum_sub(*diff_a, *z0); bignum_destoroyah(mul_of_sum); bignum_destoroyah(diff_a); bignum_destoroyah(sum_a); bignum_destoroyah(sum_b); //arrondir pour avoir la bonne puissance de 10 dans les shifts. float inter = (float)max; inter = inter/2.0f; inter += 0.5f; max_middle = (int) inter; if(max%2 == 1){ max++; } //r1 = z2*10^(max) bignum* r1 = bignum_copy(z2); bignum_shift_left(r1, max); //r2 = z1 bignum* r2 = bignum_copy(z1); //r2 = r2*10^(max_middle) bignum_shift_left(r2, max_middle); //r3 = r2 + z0 bignum* r3 = bignum_add(*r2, *z0); //bignum_destoroyah(z0); bignum_destoroyah(r2); //rf = r1+r3 bignum* rf = bignum_add(*r1, *r3); bignum_destoroyah(r1); bignum_destoroyah(r3); bignum_destoroyah(z0); bignum_destoroyah(z1); bignum_destoroyah(z2); return rf; }
/** * crypto_rsa_exptmod - RSA modular exponentiation * @in: Input data * @inlen: Input data length * @out: Buffer for output data * @outlen: Maximum size of the output buffer and used size on success * @key: RSA key * @use_private: 1 = Use RSA private key, 0 = Use RSA public key * Returns: 0 on success, -1 on failure */ int crypto_rsa_exptmod(const u8 *in, size_t inlen, u8 *out, size_t *outlen, struct crypto_rsa_key *key, int use_private) { struct bignum *tmp, *a = NULL, *b = NULL; int ret = -1; size_t modlen; if (use_private && !key->private_key) return -1; tmp = bignum_init(); if (tmp == NULL) return -1; if (bignum_set_unsigned_bin(tmp, in, inlen) < 0) goto error; if (bignum_cmp(key->n, tmp) < 0) { /* Too large input value for the RSA key modulus */ goto error; } if (use_private) { /* * Decrypt (or sign) using Chinese remainer theorem to speed * up calculation. This is equivalent to tmp = tmp^d mod n * (which would require more CPU to calculate directly). * * dmp1 = (1/e) mod (p-1) * dmq1 = (1/e) mod (q-1) * iqmp = (1/q) mod p, where p > q * m1 = c^dmp1 mod p * m2 = c^dmq1 mod q * h = q^-1 (m1 - m2) mod p * m = m2 + hq */ a = bignum_init(); b = bignum_init(); if (a == NULL || b == NULL) goto error; /* a = tmp^dmp1 mod p */ if (bignum_exptmod(tmp, key->dmp1, key->p, a) < 0) goto error; /* b = tmp^dmq1 mod q */ if (bignum_exptmod(tmp, key->dmq1, key->q, b) < 0) goto error; /* tmp = (a - b) * (1/q mod p) (mod p) */ if (bignum_sub(a, b, tmp) < 0 || bignum_mulmod(tmp, key->iqmp, key->p, tmp) < 0) goto error; /* tmp = b + q * tmp */ if (bignum_mul(tmp, key->q, tmp) < 0 || bignum_add(tmp, b, tmp) < 0) goto error; } else { /* Encrypt (or verify signature) */ /* tmp = tmp^e mod N */ if (bignum_exptmod(tmp, key->e, key->n, tmp) < 0) goto error; } modlen = crypto_rsa_get_modulus_len(key); if (modlen > *outlen) { *outlen = modlen; goto error; } if (bignum_get_unsigned_bin_len(tmp) > modlen) goto error; /* should never happen */ *outlen = modlen; os_memset(out, 0, modlen); if (bignum_get_unsigned_bin( tmp, out + (modlen - bignum_get_unsigned_bin_len(tmp)), NULL) < 0) goto error; ret = 0; error: bignum_deinit(tmp); bignum_deinit(a); bignum_deinit(b); return ret; }