static int ltm_rsa_private_encrypt(int flen, const unsigned char* from, unsigned char* to, RSA* rsa, int padding) { unsigned char *ptr, *ptr0; int res; int size; mp_int in, out, n, e; mp_int bi, b; int blinding = (rsa->flags & RSA_FLAG_NO_BLINDING) == 0; int do_unblind = 0; if (padding != RSA_PKCS1_PADDING) return -1; mp_init_multi(&e, &n, &in, &out, &b, &bi, NULL); size = RSA_size(rsa); if (size < RSA_PKCS1_PADDING_SIZE || size - RSA_PKCS1_PADDING_SIZE < flen) return -2; ptr0 = ptr = malloc(size); *ptr++ = 0; *ptr++ = 1; memset(ptr, 0xff, size - flen - 3); ptr += size - flen - 3; *ptr++ = 0; memcpy(ptr, from, flen); ptr += flen; assert((ptr - ptr0) == size); BN2mpz(&n, rsa->n); BN2mpz(&e, rsa->e); if (mp_cmp_d(&e, 3) == MP_LT) { size = -3; goto out; } mp_read_unsigned_bin(&in, ptr0, size); free(ptr0); if(mp_isneg(&in) || mp_cmp(&in, &n) >= 0) { size = -3; goto out; } if (blinding) { setup_blind(&n, &b, &bi); blind(&in, &b, &e, &n); do_unblind = 1; } if (rsa->p && rsa->q && rsa->dmp1 && rsa->dmq1 && rsa->iqmp) { mp_int p, q, dmp1, dmq1, iqmp; mp_init_multi(&p, &q, &dmp1, &dmq1, &iqmp, NULL); BN2mpz(&p, rsa->p); BN2mpz(&q, rsa->q); BN2mpz(&dmp1, rsa->dmp1); BN2mpz(&dmq1, rsa->dmq1); BN2mpz(&iqmp, rsa->iqmp); res = ltm_rsa_private_calculate(&in, &p, &q, &dmp1, &dmq1, &iqmp, &out); mp_clear_multi(&p, &q, &dmp1, &dmq1, &iqmp, NULL); if (res != 0) { size = -4; goto out; } } else { mp_int d; BN2mpz(&d, rsa->d); res = mp_exptmod(&in, &d, &n, &out); mp_clear(&d); if (res != 0) { size = -5; goto out; } } if (do_unblind) unblind(&out, &bi, &n); if (size > 0) { size_t ssize; ssize = mp_unsigned_bin_size(&out); assert(size >= ssize); mp_to_unsigned_bin(&out, to); size = ssize; } out: mp_clear_multi(&e, &n, &in, &out, &b, &bi, NULL); return size; }
/* hac 14.61, pp608 */ int mp_invmod_slow (mp_int * a, mp_int * b, mp_int * c) { mp_int x, y, u, v, A, B, C, D; int res; /* b cannot be negative */ if ((b->sign == MP_NEG) || (mp_iszero(b) == MP_YES)) { return MP_VAL; } /* init temps */ if ((res = mp_init_multi(&x, &y, &u, &v, &A, &B, &C, &D, NULL)) != MP_OKAY) { return res; } /* x = a, y = b */ if ((res = mp_mod(a, b, &x)) != MP_OKAY) { goto LBL_ERR; } if ((res = mp_copy (b, &y)) != MP_OKAY) { goto LBL_ERR; } /* 2. [modified] if x,y are both even then return an error! */ if ((mp_iseven (&x) == MP_YES) && (mp_iseven (&y) == MP_YES)) { res = MP_VAL; goto LBL_ERR; } /* 3. u=x, v=y, A=1, B=0, C=0,D=1 */ if ((res = mp_copy (&x, &u)) != MP_OKAY) { goto LBL_ERR; } if ((res = mp_copy (&y, &v)) != MP_OKAY) { goto LBL_ERR; } mp_set (&A, 1); mp_set (&D, 1); top: /* 4. while u is even do */ while (mp_iseven (&u) == MP_YES) { /* 4.1 u = u/2 */ if ((res = mp_div_2 (&u, &u)) != MP_OKAY) { goto LBL_ERR; } /* 4.2 if A or B is odd then */ if ((mp_isodd (&A) == MP_YES) || (mp_isodd (&B) == MP_YES)) { /* A = (A+y)/2, B = (B-x)/2 */ if ((res = mp_add (&A, &y, &A)) != MP_OKAY) { goto LBL_ERR; } if ((res = mp_sub (&B, &x, &B)) != MP_OKAY) { goto LBL_ERR; } } /* A = A/2, B = B/2 */ if ((res = mp_div_2 (&A, &A)) != MP_OKAY) { goto LBL_ERR; } if ((res = mp_div_2 (&B, &B)) != MP_OKAY) { goto LBL_ERR; } } /* 5. while v is even do */ while (mp_iseven (&v) == MP_YES) { /* 5.1 v = v/2 */ if ((res = mp_div_2 (&v, &v)) != MP_OKAY) { goto LBL_ERR; } /* 5.2 if C or D is odd then */ if ((mp_isodd (&C) == MP_YES) || (mp_isodd (&D) == MP_YES)) { /* C = (C+y)/2, D = (D-x)/2 */ if ((res = mp_add (&C, &y, &C)) != MP_OKAY) { goto LBL_ERR; } if ((res = mp_sub (&D, &x, &D)) != MP_OKAY) { goto LBL_ERR; } } /* C = C/2, D = D/2 */ if ((res = mp_div_2 (&C, &C)) != MP_OKAY) { goto LBL_ERR; } if ((res = mp_div_2 (&D, &D)) != MP_OKAY) { goto LBL_ERR; } } /* 6. if u >= v then */ if (mp_cmp (&u, &v) != MP_LT) { /* u = u - v, A = A - C, B = B - D */ if ((res = mp_sub (&u, &v, &u)) != MP_OKAY) { goto LBL_ERR; } if ((res = mp_sub (&A, &C, &A)) != MP_OKAY) { goto LBL_ERR; } if ((res = mp_sub (&B, &D, &B)) != MP_OKAY) { goto LBL_ERR; } } else { /* v - v - u, C = C - A, D = D - B */ if ((res = mp_sub (&v, &u, &v)) != MP_OKAY) { goto LBL_ERR; } if ((res = mp_sub (&C, &A, &C)) != MP_OKAY) { goto LBL_ERR; } if ((res = mp_sub (&D, &B, &D)) != MP_OKAY) { goto LBL_ERR; } } /* if not zero goto step 4 */ if (mp_iszero (&u) == MP_NO) goto top; /* now a = C, b = D, gcd == g*v */ /* if v != 1 then there is no inverse */ if (mp_cmp_d (&v, 1) != MP_EQ) { res = MP_VAL; goto LBL_ERR; } /* if its too low */ while (mp_cmp_d(&C, 0) == MP_LT) { if ((res = mp_add(&C, b, &C)) != MP_OKAY) { goto LBL_ERR; } } /* too big */ while (mp_cmp_mag(&C, b) != MP_LT) { if ((res = mp_sub(&C, b, &C)) != MP_OKAY) { goto LBL_ERR; } } /* C is now the inverse */ mp_exch (&C, c); res = MP_OKAY; LBL_ERR:mp_clear_multi (&x, &y, &u, &v, &A, &B, &C, &D, NULL); return res; }
/* computes the modular inverse via binary extended euclidean algorithm, * that is c = 1/a mod b * * Based on mp_invmod except this is optimized for the case where b is * odd as per HAC Note 14.64 on pp. 610 */ int fast_mp_invmod (mp_int * a, mp_int * b, mp_int * c) { mp_int x, y, u, v, B, D; int res, neg; /* 2. [modified] if a,b are both even then return an error! * * That is if gcd(a,b) = 2**k * q then obviously there is no inverse. */ if (mp_iseven (a) == 1 && mp_iseven (b) == 1) { return MP_VAL; } /* init all our temps */ if ((res = mp_init_multi(&x, &y, &u, &v, &B, &D, NULL)) != MP_OKAY) { return res; } /* x == modulus, y == value to invert */ if ((res = mp_copy (b, &x)) != MP_OKAY) { goto __ERR; } /* we need y = |a| */ if ((res = mp_abs (a, &y)) != MP_OKAY) { goto __ERR; } /* 3. u=x, v=y, A=1, B=0, C=0,D=1 */ if ((res = mp_copy (&x, &u)) != MP_OKAY) { goto __ERR; } if ((res = mp_copy (&y, &v)) != MP_OKAY) { goto __ERR; } mp_set (&D, 1); top: /* 4. while u is even do */ while (mp_iseven (&u) == 1) { /* 4.1 u = u/2 */ if ((res = mp_div_2 (&u, &u)) != MP_OKAY) { goto __ERR; } /* 4.2 if B is odd then */ if (mp_isodd (&B) == 1) { if ((res = mp_sub (&B, &x, &B)) != MP_OKAY) { goto __ERR; } } /* B = B/2 */ if ((res = mp_div_2 (&B, &B)) != MP_OKAY) { goto __ERR; } } /* 5. while v is even do */ while (mp_iseven (&v) == 1) { /* 5.1 v = v/2 */ if ((res = mp_div_2 (&v, &v)) != MP_OKAY) { goto __ERR; } /* 5.2 if D is odd then */ if (mp_isodd (&D) == 1) { /* D = (D-x)/2 */ if ((res = mp_sub (&D, &x, &D)) != MP_OKAY) { goto __ERR; } } /* D = D/2 */ if ((res = mp_div_2 (&D, &D)) != MP_OKAY) { goto __ERR; } } /* 6. if u >= v then */ if (mp_cmp (&u, &v) != MP_LT) { /* u = u - v, B = B - D */ if ((res = mp_sub (&u, &v, &u)) != MP_OKAY) { goto __ERR; } if ((res = mp_sub (&B, &D, &B)) != MP_OKAY) { goto __ERR; } } else { /* v - v - u, D = D - B */ if ((res = mp_sub (&v, &u, &v)) != MP_OKAY) { goto __ERR; } if ((res = mp_sub (&D, &B, &D)) != MP_OKAY) { goto __ERR; } } /* if not zero goto step 4 */ if (mp_iszero (&u) == 0) { goto top; } /* now a = C, b = D, gcd == g*v */ /* if v != 1 then there is no inverse */ if (mp_cmp_d (&v, 1) != MP_EQ) { res = MP_VAL; goto __ERR; } /* b is now the inverse */ neg = a->sign; while (D.sign == MP_NEG) { if ((res = mp_add (&D, b, &D)) != MP_OKAY) { goto __ERR; } } mp_exch (&D, c); c->sign = neg; res = MP_OKAY; __ERR:mp_clear_multi (&x, &y, &u, &v, &B, &D, NULL); return res; }
/* Double an ECC point @param P The point to double @param R [out] The destination of the double @param a Curve's a value @param modulus The modulus of the field the ECC curve is in @return GNUTLS_E_SUCCESS on success */ int ecc_projective_dbl_point (ecc_point * P, ecc_point * R, mpz_t a, mpz_t modulus) { /* Using "dbl-2004-hmv" algorithm. * It costs 4M + 4S + half. */ mpz_t t1, t2; int err; if (P == NULL || R == NULL || modulus == NULL) return GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER; if ( (err = ecc_projective_isneutral(P, modulus)) == 1 ) { if ((err = mp_init_multi(&t1, &t2, NULL)) != 0) { return err; } if (P != R) { mpz_set(R->x, P->x); mpz_set(R->y, P->y); mpz_set(R->z, P->z); } if (mpz_cmp_ui (P->z, 1) != 0) { /* t1 = Z * Z */ mpz_mul(t1, R->z, R->z); mpz_mod(t1, t1, modulus); /* Z = Y * Z */ mpz_mul(R->z, R->y, R->z); mpz_mod(R->z, R->z, modulus); /* Z = 2Z */ mpz_add(R->z, R->z, R->z); if (mpz_cmp(R->z, modulus) >= 0) { mpz_sub(R->z, R->z, modulus); } } else { /* t1 = 1 */ mpz_set(t1, P->z); /* Z = 2Y */ mpz_add(R->z, R->y, R->y); if (mpz_cmp(R->z, modulus) >= 0) { mpz_sub(R->z, R->z, modulus); } } /* T2 = X - T1 */ mpz_sub(t2, R->x, t1); if (mpz_cmp_ui(t2, 0) < 0) { mpz_add(t2, t2, modulus); } /* T1 = X + T1 */ mpz_add(t1, t1, R->x); if (mpz_cmp(t1, modulus) >= 0) { mpz_sub(t1, t1, modulus); } /* T2 = T1 * T2 */ mpz_mul(t2, t1, t2); mpz_mod(t2, t2, modulus); /* T1 = 2T2 */ mpz_add(t1, t2, t2); if (mpz_cmp(t1, modulus) >= 0) { mpz_sub(t1, t1, modulus); } /* T1 = T1 + T2 */ mpz_add(t1, t1, t2); if (mpz_cmp(t1, modulus) >= 0) { mpz_sub(t1, t1, modulus); } /* Y = 2Y */ mpz_add(R->y, R->y, R->y); if (mpz_cmp(R->y, modulus) >= 0) { mpz_sub(R->y, R->y, modulus); } /* Y = Y * Y */ mpz_mul(R->y, R->y, R->y); mpz_mod(R->y, R->y, modulus); /* T2 = Y * Y */ mpz_mul(t2, R->y, R->y); mpz_mod(t2, t2, modulus); /* T2 = T2/2 */ if (mpz_odd_p(t2)) { mpz_add(t2, t2, modulus); } mpz_divexact_ui(t2, t2, 2); /* Y = Y * X */ mpz_mul(R->y, R->y, R->x); mpz_mod(R->y, R->y, modulus); /* X = T1 * T1 */ mpz_mul(R->x, t1, t1); mpz_mod(R->x, R->x, modulus); /* X = X - Y */ mpz_sub(R->x, R->x, R->y); if (mpz_cmp_ui(R->x, 0) < 0) { mpz_add(R->x, R->x, modulus); } /* X = X - Y */ mpz_sub(R->x, R->x, R->y); if (mpz_cmp_ui(R->x, 0) < 0) { mpz_add(R->x, R->x, modulus); } /* Y = Y - X */ mpz_sub(R->y, R->y, R->x); if (mpz_cmp_ui(R->y, 0) < 0) { mpz_add(R->y, R->y, modulus); } /* Y = Y * T1 */ mpz_mul(R->y, R->y, t1); mpz_mod(R->y, R->y, modulus); /* Y = Y - T2 */ mpz_sub(R->y, R->y, t2); if (mpz_cmp_ui(R->y, 0) < 0) { mpz_add( R->y, R->y, modulus); } err = GNUTLS_E_SUCCESS; mp_clear_multi(&t1, &t2, NULL); return err; } else if (err == 0) { /* 2*neutral = neutral */ mpz_set_ui(R->x, 1); mpz_set_ui(R->y, 1); mpz_set_ui(R->z, 0); return GNUTLS_E_SUCCESS; } else { return err; } }
int ecc_make_key_ex(prng_state *prng, int wprng, ecc_key *key, const ltc_ecc_set_type *dp) { int err; ecc_point *base; void *prime, *order; unsigned char *buf; int keysize; LTC_ARGCHK(key != NULL); LTC_ARGCHK(ltc_mp.name != NULL); LTC_ARGCHK(dp != NULL); /* good prng? */ if ((err = prng_is_valid(wprng)) != CRYPT_OK) { return err; } key->idx = -1; key->dp = dp; keysize = dp->size; /* allocate ram */ base = NULL; buf = XMALLOC(ECC_MAXSIZE); if (buf == NULL) { return CRYPT_MEM; } /* make up random string */ if (prng_descriptor[wprng]->read(buf, (unsigned long)keysize, prng) != (unsigned long)keysize) { err = CRYPT_ERROR_READPRNG; goto ERR_BUF; } /* setup the key variables */ if ((err = mp_init_multi(&key->pubkey.x, &key->pubkey.y, &key->pubkey.z, &key->k, &prime, &order, NULL)) != CRYPT_OK) { goto ERR_BUF; } base = ltc_ecc_new_point(); if (base == NULL) { err = CRYPT_MEM; goto errkey; } /* read in the specs for this key */ if ((err = mp_read_radix(prime, (char *)key->dp->prime, 16)) != CRYPT_OK) { goto errkey; } if ((err = mp_read_radix(order, (char *)key->dp->order, 16)) != CRYPT_OK) { goto errkey; } if ((err = mp_read_radix(base->x, (char *)key->dp->Gx, 16)) != CRYPT_OK) { goto errkey; } if ((err = mp_read_radix(base->y, (char *)key->dp->Gy, 16)) != CRYPT_OK) { goto errkey; } if ((err = mp_set(base->z, 1)) != CRYPT_OK) { goto errkey; } if ((err = mp_read_unsigned_bin(key->k, (unsigned char *)buf, keysize)) != CRYPT_OK) { goto errkey; } /* the key should be smaller than the order of base point */ if (mp_cmp(key->k, order) != LTC_MP_LT) { if((err = mp_mod(key->k, order, key->k)) != CRYPT_OK) { goto errkey; } } /* make the public key */ if ((err = ltc_mp.ecc_ptmul(key->k, base, &key->pubkey, prime, 1)) != CRYPT_OK) { goto errkey; } key->type = PK_PRIVATE; /* free up ram */ err = CRYPT_OK; goto cleanup; errkey: mp_clear_multi(key->pubkey.x, key->pubkey.y, key->pubkey.z, key->k, NULL); cleanup: ltc_ecc_del_point(base); mp_clear_multi(prime, order, NULL); ERR_BUF: #ifdef LTC_CLEAN_STACK zeromem(buf, ECC_MAXSIZE); #endif XFREE(buf); return err; }
/** Compute an RSA modular exponentiation @param in The input data to send into RSA @param inlen The length of the input (octets) @param out [out] The destination @param outlen [in/out] The max size and resulting size of the output @param which Which exponent to use, e.g. PK_PRIVATE or PK_PUBLIC @param key The RSA key to use @return CRYPT_OK if successful */ int rsa_exptmod(const unsigned char *in, unsigned long inlen, unsigned char *out, unsigned long *outlen, int which, rsa_key *key) { void *tmp, *tmpa, *tmpb; unsigned long x; int err; LTC_ARGCHK(in != NULL); LTC_ARGCHK(out != NULL); LTC_ARGCHK(outlen != NULL); LTC_ARGCHK(key != NULL); /* is the key of the right type for the operation? */ if (which == PK_PRIVATE && (key->type != PK_PRIVATE)) { return CRYPT_PK_NOT_PRIVATE; } /* must be a private or public operation */ if (which != PK_PRIVATE && which != PK_PUBLIC) { return CRYPT_PK_INVALID_TYPE; } /* init and copy into tmp */ if ((err = mp_init_multi(&tmp, &tmpa, &tmpb, NULL)) != CRYPT_OK) { return err; } if ((err = mp_read_unsigned_bin(tmp, (unsigned char *)in, (int)inlen)) != CRYPT_OK) { goto error; } /* sanity check on the input */ if (mp_cmp(key->N, tmp) == LTC_MP_LT) { err = CRYPT_PK_INVALID_SIZE; goto error; } /* are we using the private exponent and is the key optimized? */ if (which == PK_PRIVATE) { /* tmpa = tmp^dP mod p */ if ((err = mp_exptmod(tmp, key->dP, key->p, tmpa)) != CRYPT_OK) { goto error; } /* tmpb = tmp^dQ mod q */ if ((err = mp_exptmod(tmp, key->dQ, key->q, tmpb)) != CRYPT_OK) { goto error; } /* tmp = (tmpa - tmpb) * qInv (mod p) */ if ((err = mp_sub(tmpa, tmpb, tmp)) != CRYPT_OK) { goto error; } if ((err = mp_mulmod(tmp, key->qP, key->p, tmp)) != CRYPT_OK) { goto error; } /* tmp = tmpb + q * tmp */ if ((err = mp_mul(tmp, key->q, tmp)) != CRYPT_OK) { goto error; } if ((err = mp_add(tmp, tmpb, tmp)) != CRYPT_OK) { goto error; } } else { /* exptmod it */ if ((err = mp_exptmod(tmp, key->e, key->N, tmp)) != CRYPT_OK) { goto error; } } /* read it back */ x = (unsigned long)mp_unsigned_bin_size(key->N); if (x > *outlen) { *outlen = x; err = CRYPT_BUFFER_OVERFLOW; goto error; } /* this should never happen ... */ if (mp_unsigned_bin_size(tmp) > mp_unsigned_bin_size(key->N)) { err = CRYPT_ERROR; goto error; } *outlen = x; /* convert it */ zeromem(out, x); if ((err = mp_to_unsigned_bin(tmp, out+(x-mp_unsigned_bin_size(tmp)))) != CRYPT_OK) { goto error; } /* clean up and return */ err = CRYPT_OK; error: mp_clear_multi(tmp, tmpa, tmpb, NULL); return err; }
/** Free an RSA key from memory @param key The RSA key to free */ void rsa_free(rsa_key * key) { LTC_ARGCHKVD(key != NULL); mp_clear_multi(&key->e, &key->d, &key->N, &key->dQ, &key->dP, &key->qP, &key->p, &key->q, NULL); }
/** Encrypt a symmetric key with DSA @param in The symmetric key you want to encrypt @param inlen The length of the key to encrypt (octets) @param out [out] The destination for the ciphertext @param outlen [in/out] The max size and resulting size of the ciphertext @param prng An active PRNG state @param wprng The index of the PRNG you wish to use @param hash The index of the hash you want to use @param key The DSA key you want to encrypt to @return CRYPT_OK if successful */ int dsa_encrypt_key(const unsigned char *in, unsigned long inlen, unsigned char *out, unsigned long *outlen, prng_state *prng, int wprng, int hash, dsa_key *key) { unsigned char *expt, *skey; void *g_pub, *g_priv; unsigned long x, y; int err; LTC_ARGCHK(in != NULL); LTC_ARGCHK(out != NULL); LTC_ARGCHK(outlen != NULL); LTC_ARGCHK(key != NULL); /* check that wprng/cipher/hash are not invalid */ if ((err = prng_is_valid(wprng)) != CRYPT_OK) { return err; } if ((err = hash_is_valid(hash)) != CRYPT_OK) { return err; } if (inlen > hash_descriptor[hash].hashsize) { return CRYPT_INVALID_HASH; } /* make a random key and export the public copy */ if ((err = mp_init_multi(&g_pub, &g_priv, NULL)) != CRYPT_OK) { return err; } expt = XMALLOC(mp_unsigned_bin_size(key->p) + 1); skey = XMALLOC(MAXBLOCKSIZE); if (expt == NULL || skey == NULL) { if (expt != NULL) { XFREE(expt); } if (skey != NULL) { XFREE(skey); } mp_clear_multi(g_pub, g_priv, NULL); return CRYPT_MEM; } /* make a random x, g^x pair */ x = mp_unsigned_bin_size(key->q); if (prng_descriptor[wprng].read(expt, x, prng) != x) { err = CRYPT_ERROR_READPRNG; goto LBL_ERR; } /* load x */ if ((err = mp_read_unsigned_bin(g_priv, expt, x)) != CRYPT_OK) { goto LBL_ERR; } /* compute y */ if ((err = mp_exptmod(key->g, g_priv, key->p, g_pub)) != CRYPT_OK) { goto LBL_ERR; } /* make random key */ x = mp_unsigned_bin_size(key->p) + 1; if ((err = dsa_shared_secret(g_priv, key->y, key, expt, &x)) != CRYPT_OK) { goto LBL_ERR; } y = MAXBLOCKSIZE; if ((err = hash_memory(hash, expt, x, skey, &y)) != CRYPT_OK) { goto LBL_ERR; } /* Encrypt key */ for (x = 0; x < inlen; x++) { skey[x] ^= in[x]; } err = der_encode_sequence_multi(out, outlen, LTC_ASN1_OBJECT_IDENTIFIER, hash_descriptor[hash].OIDlen, hash_descriptor[hash].OID, LTC_ASN1_INTEGER, 1UL, g_pub, LTC_ASN1_OCTET_STRING, inlen, skey, LTC_ASN1_EOL, 0UL, NULL); LBL_ERR: #ifdef LTC_CLEAN_STACK /* clean up */ zeromem(expt, mp_unsigned_bin_size(key->p) + 1); zeromem(skey, MAXBLOCKSIZE); #endif XFREE(skey); XFREE(expt); mp_clear_multi(g_pub, g_priv, NULL); return err; }
/** Verify an ECC signature @param sig The signature to verify @param siglen The length of the signature (octets) @param hash The hash (message digest) that was signed @param hashlen The length of the hash (octets) @param stat Result of signature, 1==valid, 0==invalid @param key The corresponding public ECC key @return CRYPT_OK if successful (even if the signature is not valid) */ int ecc_verify_hash(const unsigned char *sig, unsigned long siglen, const unsigned char *hash, unsigned long hashlen, int *stat, ecc_key *key) { ecc_point *mG, *mQ; void *r, *s, *v, *w, *u1, *u2, *e, *p, *m; void *mp; int err; LTC_ARGCHK(sig != NULL); LTC_ARGCHK(hash != NULL); LTC_ARGCHK(stat != NULL); LTC_ARGCHK(key != NULL); /* default to invalid signature */ *stat = 0; mp = NULL; /* is the IDX valid ? */ if (ltc_ecc_is_valid_idx(key->idx) != 1) { return CRYPT_PK_INVALID_TYPE; } /* allocate ints */ if ((err = mp_init_multi(&r, &s, &v, &w, &u1, &u2, &p, &e, &m, NULL)) != CRYPT_OK) { return CRYPT_MEM; } /* allocate points */ mG = ltc_ecc_new_point(); mQ = ltc_ecc_new_point(); if (mQ == NULL || mG == NULL) { err = CRYPT_MEM; goto error; } /* parse header */ if ((err = der_decode_sequence_multi(sig, siglen, LTC_ASN1_INTEGER, 1UL, r, LTC_ASN1_INTEGER, 1UL, s, LTC_ASN1_EOL, 0UL, NULL)) != CRYPT_OK) { goto error; } /* get the order */ if ((err = mp_read_radix(p, (char *)key->dp->order, 16)) != CRYPT_OK) { goto error; } /* get the modulus */ if ((err = mp_read_radix(m, (char *)key->dp->prime, 16)) != CRYPT_OK) { goto error; } /* check for zero */ if (mp_iszero(r) || mp_iszero(s) || mp_cmp(r, p) != LTC_MP_LT || mp_cmp(s, p) != LTC_MP_LT) { err = CRYPT_INVALID_PACKET; goto error; } /* read hash */ if ((err = mp_read_unsigned_bin(e, (unsigned char *)hash, (int)hashlen)) != CRYPT_OK) { goto error; } /* w = s^-1 mod n */ if ((err = mp_invmod(s, p, w)) != CRYPT_OK) { goto error; } /* u1 = ew */ if ((err = mp_mulmod(e, w, p, u1)) != CRYPT_OK) { goto error; } /* u2 = rw */ if ((err = mp_mulmod(r, w, p, u2)) != CRYPT_OK) { goto error; } /* find mG and mQ */ if ((err = mp_read_radix(mG->x, (char *)key->dp->Gx, 16)) != CRYPT_OK) { goto error; } if ((err = mp_read_radix(mG->y, (char *)key->dp->Gy, 16)) != CRYPT_OK) { goto error; } if ((err = mp_set(mG->z, 1)) != CRYPT_OK) { goto error; } if ((err = mp_copy(key->pubkey.x, mQ->x)) != CRYPT_OK) { goto error; } if ((err = mp_copy(key->pubkey.y, mQ->y)) != CRYPT_OK) { goto error; } if ((err = mp_copy(key->pubkey.z, mQ->z)) != CRYPT_OK) { goto error; } /* compute u1*mG + u2*mQ = mG */ if (ltc_mp.ecc_mul2add == NULL) { if ((err = ltc_mp.ecc_ptmul(u1, mG, mG, m, 0)) != CRYPT_OK) { goto error; } if ((err = ltc_mp.ecc_ptmul(u2, mQ, mQ, m, 0)) != CRYPT_OK) { goto error; } /* find the montgomery mp */ if ((err = mp_montgomery_setup(m, &mp)) != CRYPT_OK) { goto error; } /* add them */ if ((err = ltc_mp.ecc_ptadd(mQ, mG, mG, m, mp)) != CRYPT_OK) { goto error; } /* reduce */ if ((err = ltc_mp.ecc_map(mG, m, mp)) != CRYPT_OK) { goto error; } } else { /* use Shamir's trick to compute u1*mG + u2*mQ using half of the doubles */ if ((err = ltc_mp.ecc_mul2add(mG, u1, mQ, u2, mG, m)) != CRYPT_OK) { goto error; } } /* v = X_x1 mod n */ if ((err = mp_mod(mG->x, p, v)) != CRYPT_OK) { goto error; } /* does v == r */ if (mp_cmp(v, r) == LTC_MP_EQ) { *stat = 1; } /* clear up and return */ err = CRYPT_OK; error: ltc_ecc_del_point(mG); ltc_ecc_del_point(mQ); mp_clear_multi(r, s, v, w, u1, u2, p, e, m, NULL); if (mp != NULL) { mp_montgomery_free(mp); } return err; }
/** Verify the signature given @param sig The signature @param siglen The length of the signature (octets) @param hash The hash that was signed @param hashlen The length of the hash (octets) @param stat [out] Result of signature comparison, 1==valid, 0==invalid @param key The public DH key that signed the hash @return CRYPT_OK if succsessful (even if signature is invalid) */ int dh_verify_hash(const unsigned char *sig, unsigned long siglen, const unsigned char *hash, unsigned long hashlen, int *stat, dh_key *key) { mp_int a, b, p, g, m, tmp; unsigned long x, y; int err; LTC_ARGCHK(sig != NULL); LTC_ARGCHK(hash != NULL); LTC_ARGCHK(stat != NULL); LTC_ARGCHK(key != NULL); /* default to invalid */ *stat = 0; /* check initial input length */ if (siglen < PACKET_SIZE+4+4) { return CRYPT_INVALID_PACKET; } /* header ok? */ if ((err = packet_valid_header((unsigned char *)sig, PACKET_SECT_DH, PACKET_SUB_SIGNED)) != CRYPT_OK) { return err; } /* get hash out of packet */ y = PACKET_SIZE; /* init all bignums */ if ((err = mp_init_multi(&a, &p, &b, &g, &m, &tmp, NULL)) != MP_OKAY) { return mpi_to_ltc_error(err); } /* load a and b */ INPUT_BIGNUM(&a, sig, x, y, siglen); INPUT_BIGNUM(&b, sig, x, y, siglen); /* load p and g */ if ((err = mp_read_radix(&p, sets[key->idx].prime, 64)) != MP_OKAY) { goto error1; } if ((err = mp_read_radix(&g, sets[key->idx].base, 64)) != MP_OKAY) { goto error1; } /* load m */ if ((err = mp_read_unsigned_bin(&m, (unsigned char *)hash, hashlen)) != MP_OKAY) { goto error1; } /* find g^m mod p */ if ((err = mp_exptmod(&g, &m, &p, &m)) != MP_OKAY) { goto error1; } /* m = g^m mod p */ /* find y^a * a^b */ if ((err = mp_exptmod(&key->y, &a, &p, &tmp)) != MP_OKAY) { goto error1; } /* tmp = y^a mod p */ if ((err = mp_exptmod(&a, &b, &p, &a)) != MP_OKAY) { goto error1; } /* a = a^b mod p */ if ((err = mp_mulmod(&a, &tmp, &p, &a)) != MP_OKAY) { goto error1; } /* a = y^a * a^b mod p */ /* y^a * a^b == g^m ??? */ if (mp_cmp(&a, &m) == 0) { *stat = 1; } /* clean up */ err = CRYPT_OK; goto done; error1: err = mpi_to_ltc_error(err); error: done: mp_clear_multi(&tmp, &m, &g, &p, &b, &a, NULL); return err; }
/** Sign a hash with DSA @param in The hash to sign @param inlen The length of the hash to sign @param r The "r" integer of the signature (caller must initialize with mp_init() first) @param s The "s" integer of the signature (caller must initialize with mp_init() first) @param key A private DSA key @return CRYPT_OK if successful */ int dsa_sign_hash_raw(const unsigned char *in, unsigned long inlen, mp_int_t r, mp_int_t s, dsa_key * key) { mp_int k, kinv, tmp; unsigned char *buf; int err; LTC_ARGCHK(in != NULL); LTC_ARGCHK(r != NULL); LTC_ARGCHK(s != NULL); LTC_ARGCHK(key != NULL); if (key->type != PK_PRIVATE) { return CRYPT_PK_NOT_PRIVATE; } /* check group order size */ if (key->qord >= LTC_MDSA_MAX_GROUP) { return CRYPT_INVALID_ARG; } buf = XMALLOC(LTC_MDSA_MAX_GROUP); if (buf == NULL) { return CRYPT_MEM; } /* Init our temps */ if ((err = mp_init_multi(&k, &kinv, &tmp, NULL)) != CRYPT_OK) { goto ERRBUF; } retry: do { /* gen random k */ get_random_bytes(buf, key->qord); /* read k */ if ((err = mp_read_unsigned_bin(&k, buf, key->qord)) != CRYPT_OK) { goto error; } /* k > 1 ? */ if (mp_cmp_d(&k, 1) != LTC_MP_GT) { goto retry; } /* test gcd */ if ((err = mp_gcd(&k, &key->q, &tmp)) != CRYPT_OK) { goto error; } } while (mp_cmp_d(&tmp, 1) != LTC_MP_EQ); /* now find 1/k mod q */ if ((err = mp_invmod(&k, &key->q, &kinv)) != CRYPT_OK) { goto error; } /* now find r = g^k mod p mod q */ if ((err = mp_exptmod(&key->g, &k, &key->p, r)) != CRYPT_OK) { goto error; } if ((err = mp_mod(r, &key->q, r)) != CRYPT_OK) { goto error; } if (mp_iszero(r) == LTC_MP_YES) { goto retry; } /* now find s = (in + xr)/k mod q */ if ((err = mp_read_unsigned_bin(&tmp, (unsigned char *)in, inlen)) != CRYPT_OK) { goto error; } if ((err = mp_mul(&key->x, r, s)) != CRYPT_OK) { goto error; } if ((err = mp_add(s, &tmp, s)) != CRYPT_OK) { goto error; } if ((err = mp_mulmod(s, &kinv, &key->q, s)) != CRYPT_OK) { goto error; } if (mp_iszero(s) == LTC_MP_YES) { goto retry; } err = CRYPT_OK; error: mp_clear_multi(&k, &kinv, &tmp, NULL); ERRBUF: #ifdef LTC_CLEAN_STACK zeromem(buf, LTC_MDSA_MAX_GROUP); #endif XFREE(buf); return err; }
/** Sign a message digest using a DH private key @param in The data to sign @param inlen The length of the input (octets) @param out [out] The destination of the signature @param outlen [in/out] The max size and resulting size of the output @param prng An active PRNG state @param wprng The index of the PRNG desired @param key A private DH key @return CRYPT_OK if successful */ int dh_sign_hash(const unsigned char *in, unsigned long inlen, unsigned char *out, unsigned long *outlen, prng_state *prng, int wprng, dh_key *key) { mp_int a, b, k, m, g, p, p1, tmp; unsigned char *buf; unsigned long x, y; int err; LTC_ARGCHK(in != NULL); LTC_ARGCHK(out != NULL); LTC_ARGCHK(outlen != NULL); LTC_ARGCHK(key != NULL); /* check parameters */ if (key->type != PK_PRIVATE) { return CRYPT_PK_NOT_PRIVATE; } if ((err = prng_is_valid(wprng)) != CRYPT_OK) { return err; } /* is the IDX valid ? */ if (is_valid_idx(key->idx) != 1) { return CRYPT_PK_INVALID_TYPE; } /* allocate ram for buf */ buf = XMALLOC(520); /* make up a random value k, * since the order of the group is prime * we need not check if gcd(k, r) is 1 */ if (prng_descriptor[wprng].read(buf, sets[key->idx].size, prng) != (unsigned long)(sets[key->idx].size)) { err = CRYPT_ERROR_READPRNG; goto LBL_ERR; } /* init bignums */ if ((err = mp_init_multi(&a, &b, &k, &m, &p, &g, &p1, &tmp, NULL)) != MP_OKAY) { err = mpi_to_ltc_error(err); goto LBL_ERR; } /* load k and m */ if ((err = mp_read_unsigned_bin(&m, (unsigned char *)in, inlen)) != MP_OKAY) { goto error; } if ((err = mp_read_unsigned_bin(&k, buf, sets[key->idx].size)) != MP_OKAY) { goto error; } /* load g, p and p1 */ if ((err = mp_read_radix(&g, sets[key->idx].base, 64)) != MP_OKAY) { goto error; } if ((err = mp_read_radix(&p, sets[key->idx].prime, 64)) != MP_OKAY) { goto error; } if ((err = mp_sub_d(&p, 1, &p1)) != MP_OKAY) { goto error; } if ((err = mp_div_2(&p1, &p1)) != MP_OKAY) { goto error; } /* p1 = (p-1)/2 */ /* now get a = g^k mod p */ if ((err = mp_exptmod(&g, &k, &p, &a)) != MP_OKAY) { goto error; } /* now find M = xa + kb mod p1 or just b = (M - xa)/k mod p1 */ if ((err = mp_invmod(&k, &p1, &k)) != MP_OKAY) { goto error; } /* k = 1/k mod p1 */ if ((err = mp_mulmod(&a, &key->x, &p1, &tmp)) != MP_OKAY) { goto error; } /* tmp = xa */ if ((err = mp_submod(&m, &tmp, &p1, &tmp)) != MP_OKAY) { goto error; } /* tmp = M - xa */ if ((err = mp_mulmod(&k, &tmp, &p1, &b)) != MP_OKAY) { goto error; } /* b = (M - xa)/k */ /* check for overflow */ if ((unsigned long)(PACKET_SIZE + 4 + 4 + mp_unsigned_bin_size(&a) + mp_unsigned_bin_size(&b)) > *outlen) { err = CRYPT_BUFFER_OVERFLOW; goto LBL_ERR; } /* store header */ y = PACKET_SIZE; /* now store them both (a,b) */ x = (unsigned long)mp_unsigned_bin_size(&a); STORE32L(x, out+y); y += 4; if ((err = mp_to_unsigned_bin(&a, out+y)) != MP_OKAY) { goto error; } y += x; x = (unsigned long)mp_unsigned_bin_size(&b); STORE32L(x, out+y); y += 4; if ((err = mp_to_unsigned_bin(&b, out+y)) != MP_OKAY) { goto error; } y += x; /* check if size too big */ if (*outlen < y) { err = CRYPT_BUFFER_OVERFLOW; goto LBL_ERR; } /* store header */ packet_store_header(out, PACKET_SECT_DH, PACKET_SUB_SIGNED); *outlen = y; err = CRYPT_OK; goto LBL_ERR; error: err = mpi_to_ltc_error(err); LBL_ERR: mp_clear_multi(&tmp, &p1, &g, &p, &m, &k, &b, &a, NULL); XFREE(buf); return err; }
static int ltm_rsa_generate_key(RSA *rsa, int bits, BIGNUM *e, BN_GENCB *cb) { mp_int el, p, q, n, d, dmp1, dmq1, iqmp, t1, t2, t3; int counter, ret, bitsp; if (bits < 789) return -1; bitsp = (bits + 1) / 2; ret = -1; mp_init_multi(&el, &p, &q, &n, &d, &dmp1, &dmq1, &iqmp, &t1, &t2, &t3, NULL); BN2mpz(&el, e); /* generate p and q so that p != q and bits(pq) ~ bits */ counter = 0; do { BN_GENCB_call(cb, 2, counter++); CHECK(random_num(&p, bitsp), 0); CHECK(mp_find_prime(&p,128), MP_YES); mp_sub_d(&p, 1, &t1); mp_gcd(&t1, &el, &t2); } while(mp_cmp_d(&t2, 1) != 0); BN_GENCB_call(cb, 3, 0); counter = 0; do { BN_GENCB_call(cb, 2, counter++); CHECK(random_num(&q, bits - bitsp), 0); CHECK(mp_find_prime(&q,128), MP_YES); if (mp_cmp(&p, &q) == 0) /* don't let p and q be the same */ continue; mp_sub_d(&q, 1, &t1); mp_gcd(&t1, &el, &t2); } while(mp_cmp_d(&t2, 1) != 0); /* make p > q */ if (mp_cmp(&p, &q) < 0) { mp_int c; c = p; p = q; q = c; } BN_GENCB_call(cb, 3, 1); /* calculate n, n = p * q */ mp_mul(&p, &q, &n); /* calculate d, d = 1/e mod (p - 1)(q - 1) */ mp_sub_d(&p, 1, &t1); mp_sub_d(&q, 1, &t2); mp_mul(&t1, &t2, &t3); mp_invmod(&el, &t3, &d); /* calculate dmp1 dmp1 = d mod (p-1) */ mp_mod(&d, &t1, &dmp1); /* calculate dmq1 dmq1 = d mod (q-1) */ mp_mod(&d, &t2, &dmq1); /* calculate iqmp iqmp = 1/q mod p */ mp_invmod(&q, &p, &iqmp); /* fill in RSA key */ rsa->e = mpz2BN(&el); rsa->p = mpz2BN(&p); rsa->q = mpz2BN(&q); rsa->n = mpz2BN(&n); rsa->d = mpz2BN(&d); rsa->dmp1 = mpz2BN(&dmp1); rsa->dmq1 = mpz2BN(&dmq1); rsa->iqmp = mpz2BN(&iqmp); ret = 1; out: mp_clear_multi(&el, &p, &q, &n, &d, &dmp1, &dmq1, &iqmp, &t1, &t2, &t3, NULL); return ret; }
static int ltm_rsa_private_decrypt(int flen, const unsigned char* from, unsigned char* to, RSA* rsa, int padding) { unsigned char *ptr; int res, size; mp_int in, out, n, e, b, bi; int blinding = (rsa->flags & RSA_FLAG_NO_BLINDING) == 0; int do_unblind = 0; if (padding != RSA_PKCS1_PADDING) return -1; size = RSA_size(rsa); if (flen > size) return -2; mp_init_multi(&in, &n, &e, &out, &b, &bi, NULL); BN2mpz(&n, rsa->n); BN2mpz(&e, rsa->e); if (mp_cmp_d(&e, 3) == MP_LT) { size = -2; goto out; } mp_read_unsigned_bin(&in, rk_UNCONST(from), flen); if(mp_isneg(&in) || mp_cmp(&in, &n) >= 0) { size = -2; goto out; } if (blinding) { setup_blind(&n, &b, &bi); blind(&in, &b, &e, &n); do_unblind = 1; } if (rsa->p && rsa->q && rsa->dmp1 && rsa->dmq1 && rsa->iqmp) { mp_int p, q, dmp1, dmq1, iqmp; mp_init_multi(&p, &q, &dmp1, &dmq1, &iqmp, NULL); BN2mpz(&p, rsa->p); BN2mpz(&q, rsa->q); BN2mpz(&dmp1, rsa->dmp1); BN2mpz(&dmq1, rsa->dmq1); BN2mpz(&iqmp, rsa->iqmp); res = ltm_rsa_private_calculate(&in, &p, &q, &dmp1, &dmq1, &iqmp, &out); mp_clear_multi(&p, &q, &dmp1, &dmq1, &iqmp, NULL); if (res != 0) { size = -3; goto out; } } else { mp_int d; if(mp_isneg(&in) || mp_cmp(&in, &n) >= 0) return -4; BN2mpz(&d, rsa->d); res = mp_exptmod(&in, &d, &n, &out); mp_clear(&d); if (res != 0) { size = -5; goto out; } } if (do_unblind) unblind(&out, &bi, &n); ptr = to; { size_t ssize; ssize = mp_unsigned_bin_size(&out); assert(size >= ssize); mp_to_unsigned_bin(&out, ptr); size = ssize; } /* head zero was skipped by mp_int_to_unsigned */ if (*ptr != 2) { size = -6; goto out; } size--; ptr++; while (size && *ptr != 0) { size--; ptr++; } if (size == 0) return -7; size--; ptr++; memmove(to, ptr, size); out: mp_clear_multi(&e, &n, &in, &out, &b, &bi, NULL); return size; }
int ecc_test_shamir(void) { void *modulus, *mp, *kA, *kB, *rA, *rB, *a; ecc_point *G, *A, *B, *C1, *C2; int x, y, z; unsigned char buf[ECC_BUF_SIZE]; DO(mp_init_multi(&kA, &kB, &rA, &rB, &modulus, &a, NULL)); LTC_ARGCHK((G = ltc_ecc_new_point()) != NULL); LTC_ARGCHK((A = ltc_ecc_new_point()) != NULL); LTC_ARGCHK((B = ltc_ecc_new_point()) != NULL); LTC_ARGCHK((C1 = ltc_ecc_new_point()) != NULL); LTC_ARGCHK((C2 = ltc_ecc_new_point()) != NULL); for (x = 0; x < (int)(sizeof(sizes)/sizeof(sizes[0])); x++) { /* get the base point */ for (z = 0; ltc_ecc_sets[z].name; z++) { if (sizes[z] < ltc_ecc_sets[z].size) break; } LTC_ARGCHK(ltc_ecc_sets[z].name != NULL); /* load it */ DO(mp_read_radix(G->x, ltc_ecc_sets[z].Gx, 16)); DO(mp_read_radix(G->y, ltc_ecc_sets[z].Gy, 16)); DO(mp_set(G->z, 1)); DO(mp_read_radix(modulus, ltc_ecc_sets[z].prime, 16)); DO(mp_read_radix(a, ltc_ecc_sets[z].A, 16)); DO(mp_montgomery_setup(modulus, &mp)); /* do 100 random tests */ for (y = 0; y < 100; y++) { /* pick a random r1, r2 */ LTC_ARGCHK(yarrow_read(buf, sizes[x], &yarrow_prng) == sizes[x]); DO(mp_read_unsigned_bin(rA, buf, sizes[x])); LTC_ARGCHK(yarrow_read(buf, sizes[x], &yarrow_prng) == sizes[x]); DO(mp_read_unsigned_bin(rB, buf, sizes[x])); /* compute rA * G = A */ DO(ltc_mp.ecc_ptmul(rA, G, A, modulus, a, 1)); /* compute rB * G = B */ DO(ltc_mp.ecc_ptmul(rB, G, B, modulus, a, 1)); /* pick a random kA, kB */ LTC_ARGCHK(yarrow_read(buf, sizes[x], &yarrow_prng) == sizes[x]); DO(mp_read_unsigned_bin(kA, buf, sizes[x])); LTC_ARGCHK(yarrow_read(buf, sizes[x], &yarrow_prng) == sizes[x]); DO(mp_read_unsigned_bin(kB, buf, sizes[x])); /* now, compute kA*A + kB*B = C1 using the older method */ DO(ltc_mp.ecc_ptmul(kA, A, C1, modulus, a, 0)); DO(ltc_mp.ecc_ptmul(kB, B, C2, modulus, a, 0)); DO(ltc_mp.ecc_ptadd(C1, C2, C1, modulus, a, mp)); DO(ltc_mp.ecc_map(C1, modulus, mp)); /* now compute using mul2add */ DO(ltc_mp.ecc_mul2add(A, kA, B, kB, C2, modulus, a)); /* is they the sames? */ if ((mp_cmp(C1->x, C2->x) != LTC_MP_EQ) || (mp_cmp(C1->y, C2->y) != LTC_MP_EQ) || (mp_cmp(C1->z, C2->z) != LTC_MP_EQ)) { fprintf(stderr, "ECC failed shamir test: size=%d, testno=%d\n", sizes[x], y); return 1; } } mp_montgomery_free(mp); } ltc_ecc_del_point(C2); ltc_ecc_del_point(C1); ltc_ecc_del_point(B); ltc_ecc_del_point(A); ltc_ecc_del_point(G); mp_clear_multi(kA, kB, rA, rB, modulus, NULL); return 0; }
int mp_toom_cook_5_mul(mp_int *a, mp_int *b, mp_int *c) { mp_int w1, w2, w3, w4, w5, w6, w7, w8, w9; mp_int tmp1, tmp2; mp_int a0, a1, a2, a3, a4; mp_int b0, b1, b2, b3, b4; int e = MP_OKAY; int B, count, sign; B = (MAX(a->used, b->used)) / 5; sign = (a->sign != b->sign) ? MP_NEG : MP_ZPOS; if (MIN(a->used, b->used) < TOOM_COOK_5_MUL_CO) { if ((e = mp_mul(a, b, c)) != MP_OKAY) { return e; } c->sign = sign; return MP_OKAY; } if ((e = mp_init_multi(&w1, &w2, &w3, &w4, &w5, &w6, &w7, &w8, &w9, &tmp1, &tmp2, //&a0, &a1, &a2, &a3, &a4, &b0, &b1, &b2, &b3, &b4, NULL)) != MP_OKAY) { goto ERR0; //goto ERR; } if ((e = mp_init_size(&a0, B)) != MP_OKAY) { goto ERRa0; } if ((e = mp_init_size(&a1, B)) != MP_OKAY) { goto ERRa1; } if ((e = mp_init_size(&a2, B)) != MP_OKAY) { goto ERRa2; } if ((e = mp_init_size(&a3, B)) != MP_OKAY) { goto ERRa3; } if ((e = mp_init_size(&a4, B)) != MP_OKAY) { goto ERRa4; } if ((e = mp_init_size(&b0, B)) != MP_OKAY) { goto ERRb0; } if ((e = mp_init_size(&b1, B)) != MP_OKAY) { goto ERRb1; } if ((e = mp_init_size(&b2, B)) != MP_OKAY) { goto ERRb2; } if ((e = mp_init_size(&b3, B)) != MP_OKAY) { goto ERRb3; } if ((e = mp_init_size(&b4, B)) != MP_OKAY) { goto ERRb4; } // A = a4*x^4 + a3*x^3 + a2*x^2 + a1*x + a0 for (count = 0; count < a->used; count++) { switch (count / B) { case 0: a0.dp[count] = a->dp[count]; a0.used++; break; case 1: a1.dp[count - B] = a->dp[count]; a1.used++; break; case 2: a2.dp[count - 2 * B] = a->dp[count]; a2.used++; break; case 3: a3.dp[count - 3 * B] = a->dp[count]; a3.used++; break; case 4: a4.dp[count - 4 * B] = a->dp[count]; a4.used++; break; default: a4.dp[count - 4 * B] = a->dp[count]; a4.used++; break; } } mp_clamp(&a0); mp_clamp(&a1); mp_clamp(&a2); mp_clamp(&a3); mp_clamp(&a4); // B = b4*x^4 + b3*x^3 + b2*x^2 + b1*x + b0 for (count = 0; count < b->used; count++) { switch (count / B) { case 0: b0.dp[count] = b->dp[count]; b0.used++; break; case 1: b1.dp[count - B] = b->dp[count]; b1.used++; break; case 2: b2.dp[count - 2 * B] = b->dp[count]; b2.used++; break; case 3: b3.dp[count - 3 * B] = b->dp[count]; b3.used++; break; case 4: b4.dp[count - 4 * B] = b->dp[count]; b4.used++; break; default: b4.dp[count - 4 * B] = b->dp[count]; b4.used++; break; } } mp_clamp(&b0); mp_clamp(&b1); mp_clamp(&b2); mp_clamp(&b3); mp_clamp(&b4); /* if ((e = mp_mod_2d(a, DIGIT_BIT * B, &a0)) != MP_OKAY) { goto ERR; } if ((e = mp_copy(a, &a1)) != MP_OKAY) { goto ERR; } mp_rshd(&a1, B); mp_mod_2d(&a1, DIGIT_BIT * B, &a1); if ((e = mp_copy(a, &a2)) != MP_OKAY) { goto ERR; } mp_rshd(&a2, B * 2); mp_mod_2d(&a2, DIGIT_BIT * B, &a2); if ((e = mp_copy(a, &a3)) != MP_OKAY) { goto ERR; } mp_rshd(&a3, B * 3); mp_mod_2d(&a3, DIGIT_BIT * B, &a3); if ((e = mp_copy(a, &a4)) != MP_OKAY) { goto ERR; } mp_rshd(&a4, B * 4); if ((e = mp_mod_2d(b, DIGIT_BIT * B, &b0)) != MP_OKAY) { goto ERR; } if ((e = mp_copy(a, &b1)) != MP_OKAY) { goto ERR; } mp_rshd(&b1, B); mp_mod_2d(&b1, DIGIT_BIT * B, &b1); if ((e = mp_copy(b, &b2)) != MP_OKAY) { goto ERR; } mp_rshd(&b2, B * 2); mp_mod_2d(&b2, DIGIT_BIT * B, &b2); if ((e = mp_copy(b, &b3)) != MP_OKAY) { goto ERR; } mp_rshd(&b3, B * 3); mp_mod_2d(&b3, DIGIT_BIT * B, &b3); if ((e = mp_copy(b, &b4)) != MP_OKAY) { goto ERR; } mp_rshd(&b4, B * 4); */ // S1 = a4*b4 if ((e = mp_mul(&a4, &b4, &w1)) != MP_OKAY) { goto ERR; } // S9 = a0*b0 if ((e = mp_mul(&a0, &b0, &w9)) != MP_OKAY) { goto ERR; } // S2 = (a0- 2*a1 +4*a2 -8*a3 +16*a4) if ((e = mp_mul_2d(&a1, 1, &tmp1)) != MP_OKAY) { goto ERR; } // 2*a1 = tmp1 if ((e = mp_sub(&a0, &tmp1, &w2)) != MP_OKAY) { goto ERR; } // a0- 2*a1 = a0 - tmp1 = w2 if ((e = mp_mul_2d(&a2, 2, &tmp1)) != MP_OKAY) { goto ERR; } // 4*a2 = tmp1 if ((e = mp_add(&w2, &tmp1, &w2)) != MP_OKAY) { goto ERR; } // a0- 2*a1 +4*a2 = w2 + tmp1 = w2 if ((e = mp_mul_2d(&a3, 3, &tmp1)) != MP_OKAY) { goto ERR; } // 8*a3 = tmp1 if ((e = mp_sub(&w2, &tmp1, &w2)) != MP_OKAY) { goto ERR; } // a0- 2*a1 +4*a2 -8*a3 = w2 - tmp1 = w2 if ((e = mp_mul_2d(&a4, 4, &tmp1)) != MP_OKAY) { goto ERR; } // 16*a4 = tmp1 if ((e = mp_add(&w2, &tmp1, &w2)) != MP_OKAY) { goto ERR; } // a0- 2*a1 +4*a2 -8*a3 +16*a4 = w2 + tmp1 = w2 // * (b0- 2*b1 +4*b2 -8*b3 +16*b4) if ((e = mp_mul_2d(&b1, 1, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_sub(&b0, &tmp1, &tmp2)) != MP_OKAY) { goto ERR; } if ((e = mp_mul_2d(&b2, 2, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_add(&tmp2, &tmp1, &tmp2)) != MP_OKAY) { goto ERR; } if ((e = mp_mul_2d(&b3, 3, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_sub(&tmp2, &tmp1, &tmp2)) != MP_OKAY) { goto ERR; } if ((e = mp_mul_2d(&b4, 4, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_add(&tmp2, &tmp1, &tmp2)) != MP_OKAY) { goto ERR; } if ((e = mp_mul(&tmp2, &w2, &w2)) != MP_OKAY) { goto ERR; } // S5 = (a0+ 2*a1+ 4*a2+ 8*a3+ 16*a4) if ((e = mp_mul_2d(&a1, 1, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_add(&a0, &tmp1, &w5)) != MP_OKAY) { goto ERR; } if ((e = mp_mul_2d(&a2, 2, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_add(&w5, &tmp1, &w5)) != MP_OKAY) { goto ERR; } if ((e = mp_mul_2d(&a3, 3, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_add(&w5, &tmp1, &w5)) != MP_OKAY) { goto ERR; } if ((e = mp_mul_2d(&a4, 4, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_add(&w5, &tmp1, &w5)) != MP_OKAY) { goto ERR; } // *(b0+ 2*b1+ 4*b2+ 8*b3+ 16*b4) if ((e = mp_mul_2d(&b1, 1, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_add(&b0, &tmp1, &tmp2)) != MP_OKAY) { goto ERR; } if ((e = mp_mul_2d(&b2, 2, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_add(&tmp2, &tmp1, &tmp2)) != MP_OKAY) { goto ERR; } if ((e = mp_mul_2d(&b3, 3, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_add(&tmp2, &tmp1, &tmp2)) != MP_OKAY) { goto ERR; } if ((e = mp_mul_2d(&b4, 4, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_add(&tmp2, &tmp1, &tmp2)) != MP_OKAY) { goto ERR; } if ((e = mp_mul(&tmp2, &w5, &w5)) != MP_OKAY) { goto ERR; } // S3 = (a4+ 2*a3+ 4*a2+ 8*a1+ 16*a0) if ((e = mp_mul_2d(&a3, 1, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_add(&a4, &tmp1, &w3)) != MP_OKAY) { goto ERR; } if ((e = mp_mul_2d(&a2, 2, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_add(&w3, &tmp1, &w3)) != MP_OKAY) { goto ERR; } if ((e = mp_mul_2d(&a1, 3, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_add(&w3, &tmp1, &w3)) != MP_OKAY) { goto ERR; } if ((e = mp_mul_2d(&a0, 4, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_add(&w3, &tmp1, &w3)) != MP_OKAY) { goto ERR; } // * (b4+ 2*b3+ 4*b2+ 8*b1+ 16*b0) if ((e = mp_mul_2d(&b3, 1, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_add(&b4, &tmp1, &tmp2)) != MP_OKAY) { goto ERR; } if ((e = mp_mul_2d(&b2, 2, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_add(&tmp2, &tmp1, &tmp2)) != MP_OKAY) { goto ERR; } if ((e = mp_mul_2d(&b1, 3, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_add(&tmp2, &tmp1, &tmp2)) != MP_OKAY) { goto ERR; } if ((e = mp_mul_2d(&b0, 4, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_add(&tmp2, &tmp1, &tmp2)) != MP_OKAY) { goto ERR; } if ((e = mp_mul(&tmp2, &w3, &w3)) != MP_OKAY) { goto ERR; } // S8 = (a4- 2*a3+ 4*a2- 8*a1+ 16*a0) if ((e = mp_mul_2d(&a3, 1, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_sub(&a4, &tmp1, &w8)) != MP_OKAY) { goto ERR; } if ((e = mp_mul_2d(&a2, 2, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_add(&w8, &tmp1, &w8)) != MP_OKAY) { goto ERR; } if ((e = mp_mul_2d(&a1, 3, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_sub(&w8, &tmp1, &w8)) != MP_OKAY) { goto ERR; } if ((e = mp_mul_2d(&a0, 4, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_add(&w8, &tmp1, &w8)) != MP_OKAY) { goto ERR; } //* (b4- 2*b3+ 4*b2- 8*b1+ 16*b0) if ((e = mp_mul_2d(&b3, 1, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_sub(&b4, &tmp1, &tmp2)) != MP_OKAY) { goto ERR; } if ((e = mp_mul_2d(&b2, 2, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_add(&tmp2, &tmp1, &tmp2)) != MP_OKAY) { goto ERR; } if ((e = mp_mul_2d(&b1, 3, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_sub(&tmp2, &tmp1, &tmp2)) != MP_OKAY) { goto ERR; } if ((e = mp_mul_2d(&b0, 4, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_add(&tmp2, &tmp1, &tmp2)) != MP_OKAY) { goto ERR; } if ((e = mp_mul(&tmp2, &w8, &w8)) != MP_OKAY) { goto ERR; } // S4 = (a0+ 4*a1+ 16*a2+ 64*a3+ 256*a4) if ((e = mp_mul_2d(&a1, 2, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_add(&a0, &tmp1, &w4)) != MP_OKAY) { goto ERR; } if ((e = mp_mul_2d(&a2, 4, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_add(&w4, &tmp1, &w4)) != MP_OKAY) { goto ERR; } if ((e = mp_mul_2d(&a3, 6, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_add(&w4, &tmp1, &w4)) != MP_OKAY) { goto ERR; } if ((e = mp_mul_2d(&a4, 8, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_add(&w4, &tmp1, &w4)) != MP_OKAY) { goto ERR; } //* (b0+ 4*b1+ 16*b2+ 64*b3+ 256*b4) if ((e = mp_mul_2d(&b1, 2, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_add(&b0, &tmp1, &tmp2)) != MP_OKAY) { goto ERR; } if ((e = mp_mul_2d(&b2, 4, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_add(&tmp2, &tmp1, &tmp2)) != MP_OKAY) { goto ERR; } if ((e = mp_mul_2d(&b3, 6, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_add(&tmp2, &tmp1, &tmp2)) != MP_OKAY) { goto ERR; } if ((e = mp_mul_2d(&b4, 8, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_add(&tmp2, &tmp1, &tmp2)) != MP_OKAY) { goto ERR; } if ((e = mp_mul(&tmp2, &w4, &w4)) != MP_OKAY) { goto ERR; } // S6 = (a0- a1+ a2- a3 +a4) if ((e = mp_sub(&a0, &a1, &w6)) != MP_OKAY) { goto ERR; } if ((e = mp_add(&w6, &a2, &w6)) != MP_OKAY) { goto ERR; } if ((e = mp_sub(&w6, &a3, &w6)) != MP_OKAY) { goto ERR; } if ((e = mp_add(&w6, &a4, &w6)) != MP_OKAY) { goto ERR; } // * (b0- b1+ b2- b3+ b4) if ((e = mp_sub(&b0, &b1, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_add(&tmp1, &b2, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_sub(&tmp1, &b3, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_add(&tmp1, &b4, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_mul(&tmp1, &w6, &w6)) != MP_OKAY) { goto ERR; } // S7 = (a0+ a1+ a2+ a3+ a4) if ((e = mp_add(&a0, &a1, &w7)) != MP_OKAY) { goto ERR; } if ((e = mp_add(&w7, &a2, &w7)) != MP_OKAY) { goto ERR; } if ((e = mp_add(&w7, &a3, &w7)) != MP_OKAY) { goto ERR; } if ((e = mp_add(&w7, &a4, &w7)) != MP_OKAY) { goto ERR; } // * (b0+ b1+ b2+ b3+ b4) if ((e = mp_add(&b0, &b1, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_add(&tmp1, &b2, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_add(&tmp1, &b3, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_add(&tmp1, &b4, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_mul(&tmp1, &w7, &w7)) != MP_OKAY) { goto ERR; } // S6 -= S7 if ((e = mp_sub(&w6, &w7, &w6)) != MP_OKAY) { goto ERR; } // S2 -= S5 if ((e = mp_sub(&w2, &w5, &w2)) != MP_OKAY) { goto ERR; } // S4 -= S9 if ((e = mp_sub(&w4, &w9, &w4)) != MP_OKAY) { goto ERR; } // S4 -= (2^16*S1) if ((e = mp_mul_2d(&w1, 16, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_sub(&w4, &tmp1, &w4)) != MP_OKAY) { goto ERR; } // S8 -= S3 if ((e = mp_sub(&w8, &w3, &w8)) != MP_OKAY) { goto ERR; } // S6 /= 2 if ((e = mp_div_2d(&w6, 1, &w6, NULL)) != MP_OKAY) { goto ERR; } // S5 *= 2 if ((e = mp_mul_2d(&w5, 1, &w5)) != MP_OKAY) { goto ERR; } // S5 += S2 if ((e = mp_add(&w5, &w2, &w5)) != MP_OKAY) { goto ERR; } // S2 = -S2 if ((e = mp_neg(&w2, &w2)) != MP_OKAY) { goto ERR; } // S8 = -S8 if ((e = mp_neg(&w8, &w8)) != MP_OKAY) { goto ERR; } // S7 += S6 if ((e = mp_add(&w7, &w6, &w7)) != MP_OKAY) { goto ERR; } // S6 = -S6 if ((e = mp_neg(&w6, &w6)) != MP_OKAY) { goto ERR; } // S3 -= S7 if ((e = mp_sub(&w3, &w7, &w3)) != MP_OKAY) { goto ERR; } // S5 -= (512*S7) if ((e = mp_mul_2d(&w7, 9, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_sub(&w5, &tmp1, &w5)) != MP_OKAY) { goto ERR; } // S3 *= 2 if ((e = mp_mul_2d(&w3, 1, &w3)) != MP_OKAY) { goto ERR; } // S3 -= S8 if ((e = mp_sub(&w3, &w8, &w3)) != MP_OKAY) { goto ERR; } // S7 -= S1 if ((e = mp_sub(&w7, &w1, &w7)) != MP_OKAY) { goto ERR; } // S7 -= S9 if ((e = mp_sub(&w7, &w9, &w7)) != MP_OKAY) { goto ERR; } // S8 += S2 if ((e = mp_add(&w8, &w2, &w8)) != MP_OKAY) { goto ERR; } // S5 += S3 if ((e = mp_add(&w5, &w3, &w5)) != MP_OKAY) { goto ERR; } // S8 -= (80*S6) if ((e = mp_mul_d(&w6, 80, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_sub(&w8, &tmp1, &w8)) != MP_OKAY) { goto ERR; } // S3 -= (510*S9) if ((e = mp_mul_d(&w9, 510, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_sub(&w3, &tmp1, &w3)) != MP_OKAY) { goto ERR; } // S4 -= S2 if ((e = mp_sub(&w4, &w2, &w4)) != MP_OKAY) { goto ERR; } // S3 *= 3 if ((e = mp_mul_d(&w3, 3, &w3)) != MP_OKAY) { goto ERR; } // S3 += S5 if ((e = mp_add(&w3, &w5, &w3)) != MP_OKAY) { goto ERR; } // S8 /= 180 \\ division by 180 if ((e = mp_div_d(&w8, 180, &w8, NULL)) != MP_OKAY) { goto ERR; } // S5 += (378*S7) if ((e = mp_mul_d(&w7, 378, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_add(&w5, &tmp1, &w5)) != MP_OKAY) { goto ERR; } // S2 /= 4 if ((e = mp_div_2d(&w2, 2, &w2, NULL)) != MP_OKAY) { goto ERR; } // S6 -= S2 if ((e = mp_sub(&w6, &w2, &w6)) != MP_OKAY) { goto ERR; } // S5 /= (-72) \\ division by -72 if ((e = mp_div_d(&w5, 72, &w5, NULL)) != MP_OKAY) { goto ERR; } if (&w5.sign == MP_ZPOS) (&w5)->sign = MP_NEG; (&w5)->sign = MP_ZPOS; // S3 /= (-360) \\ division by -360 if ((e = mp_div_d(&w3, 360, &w3, NULL)) != MP_OKAY) { goto ERR; } if (&w3.sign == MP_ZPOS) (&w3)->sign = MP_NEG; (&w3)->sign = MP_ZPOS; // S2 -= S8 if ((e = mp_sub(&w2, &w8, &w2)) != MP_OKAY) { goto ERR; } // S7 -= S3 if ((e = mp_sub(&w7, &w3, &w7)) != MP_OKAY) { goto ERR; } // S4 -= (256*S5) if ((e = mp_mul_2d(&w5, 8, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_sub(&w4, &tmp1, &w4)) != MP_OKAY) { goto ERR; } // S3 -= S5 if ((e = mp_sub(&w3, &w5, &w3)) != MP_OKAY) { goto ERR; } // S4 -= (4096*S3) if ((e = mp_mul_2d(&w3, 12, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_sub(&w4, &tmp1, &w4)) != MP_OKAY) { goto ERR; } // S4 -= (16*S7) if ((e = mp_mul_2d(&w7, 4, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_sub(&w4, &tmp1, &w4)) != MP_OKAY) { goto ERR; } // S4 += (256*S6) if ((e = mp_mul_2d(&w6, 8, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_add(&w4, &tmp1, &w4)) != MP_OKAY) { goto ERR; } // S6 += S2 if ((e = mp_add(&w6, &w2, &w6)) != MP_OKAY) { goto ERR; } // S2 *= 180 if ((e = mp_mul_d(&w2, 180, &w2)) != MP_OKAY) { goto ERR; } // S2 += S4 if ((e = mp_add(&w2, &w4, &w2)) != MP_OKAY) { goto ERR; } // S2 /= 11340 \\ division by 11340 if ((e = mp_div_d(&w2, 11340, &w2, NULL)) != MP_OKAY) { goto ERR; } // S4 += (720*S6) if ((e = mp_mul_d(&w6, 720, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_add(&w4, &tmp1, &w4)) != MP_OKAY) { goto ERR; } // S4 /= (-2160) \\ division by -2160 if ((e = mp_div_d(&w4, 2160, &w4, NULL)) != MP_OKAY) { goto ERR; } if (&w4.sign == MP_ZPOS) (&w4)->sign = MP_NEG; (&w4)->sign = MP_ZPOS; // S6 -= S4 if ((e = mp_sub(&w6, &w4, &w6)) != MP_OKAY) { goto ERR; } // S8 -= S2 if ((e = mp_sub(&w8, &w2, &w8)) != MP_OKAY) { goto ERR; } // P = S1*x^8 + S2*x^7 + S3*x^6 + S4*x^5 + S5*x^4 + S6*x^3 + S7*x^2 + S8*x + S9 if ((e = mp_copy(&w9, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_lshd(&w8, B)) != MP_OKAY) { goto ERR; } if ((e = mp_add(&tmp1, &w8, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_lshd(&w7, 2 * B)) != MP_OKAY) { goto ERR; } if ((e = mp_add(&tmp1, &w7, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_lshd(&w6, 3 * B)) != MP_OKAY) { goto ERR; } if ((e = mp_add(&tmp1, &w6, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_lshd(&w5, 4 * B)) != MP_OKAY) { goto ERR; } if ((e = mp_add(&tmp1, &w5, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_lshd(&w4, 5 * B)) != MP_OKAY) { goto ERR; } if ((e = mp_add(&tmp1, &w4, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_lshd(&w3, 6 * B)) != MP_OKAY) { goto ERR; } if ((e = mp_add(&tmp1, &w3, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_lshd(&w2, 7 * B)) != MP_OKAY) { goto ERR; } if ((e = mp_add(&tmp1, &w2, &tmp1)) != MP_OKAY) { goto ERR; } if ((e = mp_lshd(&w1, 8 * B)) != MP_OKAY) { goto ERR; } if ((e = mp_add(&tmp1, &w1, c)) != MP_OKAY) { goto ERR; } // P - A*B \\ == zero c->sign = sign; ERR: ERRb4: mp_clear(&b4); ERRb3: mp_clear(&b3); ERRb2: mp_clear(&b2); ERRb1: mp_clear(&b1); ERRb0: mp_clear(&b0); ERRa4: mp_clear(&a4); ERRa3: mp_clear(&a3); ERRa2: mp_clear(&a2); ERRa1: mp_clear(&a1); ERRa0: mp_clear(&a0); ERR0: mp_clear_multi(&w1, &w2, &w3, &w4, &w5, &w6, &w7, &w8, &w9, &tmp1, &tmp2, // &a0, &a1, &a2, &a3, &a4, &b0, &b1, &b2, &b3, &b4, NULL); return e; }
/** Import an RSAPublicKey or RSAPrivateKey [two-prime only, only support >= 1024-bit keys, defined in LTC_PKCS #1 v2.1] @param in The packet to import from @param inlen It's length (octets) @param key [out] Destination for newly imported key @return CRYPT_OK if successful, upon error allocated memory is freed */ int rsa_import(const unsigned char *in, unsigned long inlen, rsa_key *key) { int err; void *zero; unsigned char *tmpbuf; unsigned long t, x, y, z, tmpoid[16]; ltc_asn1_list ssl_pubkey_hashoid[2]; ltc_asn1_list ssl_pubkey[2]; LTC_ARGCHK(in != NULL); LTC_ARGCHK(key != NULL); LTC_ARGCHK(ltc_mp.name != NULL); /* init key */ if ((err = mp_init_multi(&key->e, &key->d, &key->N, &key->dQ, &key->dP, &key->qP, &key->p, &key->q, NULL)) != CRYPT_OK) { return err; } /* see if the OpenSSL DER format RSA public key will work */ tmpbuf = XCALLOC(1, MAX_RSA_SIZE*8); if (tmpbuf == NULL) { err = CRYPT_MEM; goto LBL_ERR; } /* this includes the internal hash ID and optional params (NULL in this case) */ LTC_SET_ASN1(ssl_pubkey_hashoid, 0, LTC_ASN1_OBJECT_IDENTIFIER, tmpoid, sizeof(tmpoid)/sizeof(tmpoid[0])); LTC_SET_ASN1(ssl_pubkey_hashoid, 1, LTC_ASN1_NULL, NULL, 0); /* the actual format of the SSL DER key is odd, it stores a RSAPublicKey in a **BIT** string ... so we have to extract it then proceed to convert bit to octet */ LTC_SET_ASN1(ssl_pubkey, 0, LTC_ASN1_SEQUENCE, &ssl_pubkey_hashoid, 2); LTC_SET_ASN1(ssl_pubkey, 1, LTC_ASN1_BIT_STRING, tmpbuf, MAX_RSA_SIZE*8); if (der_decode_sequence(in, inlen, ssl_pubkey, 2UL) == CRYPT_OK) { /* ok now we have to reassemble the BIT STRING to an OCTET STRING. Thanks OpenSSL... */ for (t = y = z = x = 0; x < ssl_pubkey[1].size; x++) { y = (y << 1) | tmpbuf[x]; if (++z == 8) { tmpbuf[t++] = (unsigned char)y; y = 0; z = 0; } } /* now it should be SEQUENCE { INTEGER, INTEGER } */ if ((err = der_decode_sequence_multi(tmpbuf, t, LTC_ASN1_INTEGER, 1UL, key->N, LTC_ASN1_INTEGER, 1UL, key->e, LTC_ASN1_EOL, 0UL, NULL)) != CRYPT_OK) { XFREE(tmpbuf); goto LBL_ERR; } XFREE(tmpbuf); key->type = PK_PUBLIC; return CRYPT_OK; } XFREE(tmpbuf); /* not SSL public key, try to match against LTC_PKCS #1 standards */ if ((err = der_decode_sequence_multi(in, inlen, LTC_ASN1_INTEGER, 1UL, key->N, LTC_ASN1_EOL, 0UL, NULL)) != CRYPT_OK) { goto LBL_ERR; } if (mp_cmp_d(key->N, 0) == LTC_MP_EQ) { if ((err = mp_init(&zero)) != CRYPT_OK) { goto LBL_ERR; } /* it's a private key */ if ((err = der_decode_sequence_multi(in, inlen, LTC_ASN1_INTEGER, 1UL, zero, LTC_ASN1_INTEGER, 1UL, key->N, LTC_ASN1_INTEGER, 1UL, key->e, LTC_ASN1_INTEGER, 1UL, key->d, LTC_ASN1_INTEGER, 1UL, key->p, LTC_ASN1_INTEGER, 1UL, key->q, LTC_ASN1_INTEGER, 1UL, key->dP, LTC_ASN1_INTEGER, 1UL, key->dQ, LTC_ASN1_INTEGER, 1UL, key->qP, LTC_ASN1_EOL, 0UL, NULL)) != CRYPT_OK) { mp_clear(zero); goto LBL_ERR; } mp_clear(zero); key->type = PK_PRIVATE; } else if (mp_cmp_d(key->N, 1) == LTC_MP_EQ) { /* we don't support multi-prime RSA */ err = CRYPT_PK_INVALID_TYPE; goto LBL_ERR; } else { /* it's a public key and we lack e */ if ((err = der_decode_sequence_multi(in, inlen, LTC_ASN1_INTEGER, 1UL, key->N, LTC_ASN1_INTEGER, 1UL, key->e, LTC_ASN1_EOL, 0UL, NULL)) != CRYPT_OK) { goto LBL_ERR; } key->type = PK_PUBLIC; } return CRYPT_OK; LBL_ERR: mp_clear_multi(key->d, key->e, key->N, key->dQ, key->dP, key->qP, key->p, key->q, NULL); return err; }
/** Double an ECC point @param P The point to double @param R [out] The destination of the double @param modulus The modulus of the field the ECC curve is in @param mp The "b" value from montgomery_setup() @return CRYPT_OK on success */ int ltc_ecc_projective_dbl_point(ecc_point *P, ecc_point *R, void *modulus, void *mp) { void *t1, *t2; int err; LTC_ARGCHK(P != NULL); LTC_ARGCHK(R != NULL); LTC_ARGCHK(modulus != NULL); LTC_ARGCHK(mp != NULL); if ((err = mp_init_multi(&t1, &t2, NULL)) != CRYPT_OK) { return err; } if (P != R) { if ((err = mp_copy(P->x, R->x)) != CRYPT_OK) { goto done; } if ((err = mp_copy(P->y, R->y)) != CRYPT_OK) { goto done; } if ((err = mp_copy(P->z, R->z)) != CRYPT_OK) { goto done; } } /* t1 = Z * Z */ if ((err = mp_sqr(R->z, t1)) != CRYPT_OK) { goto done; } if ((err = mp_montgomery_reduce(t1, modulus, mp)) != CRYPT_OK) { goto done; } /* Z = Y * Z */ if ((err = mp_mul(R->z, R->y, R->z)) != CRYPT_OK) { goto done; } if ((err = mp_montgomery_reduce(R->z, modulus, mp)) != CRYPT_OK) { goto done; } /* Z = 2Z */ if ((err = mp_add(R->z, R->z, R->z)) != CRYPT_OK) { goto done; } if (mp_cmp(R->z, modulus) != LTC_MP_LT) { if ((err = mp_sub(R->z, modulus, R->z)) != CRYPT_OK) { goto done; } } /* T2 = X - T1 */ if ((err = mp_sub(R->x, t1, t2)) != CRYPT_OK) { goto done; } if (mp_cmp_d(t2, 0) == LTC_MP_LT) { if ((err = mp_add(t2, modulus, t2)) != CRYPT_OK) { goto done; } } /* T1 = X + T1 */ if ((err = mp_add(t1, R->x, t1)) != CRYPT_OK) { goto done; } if (mp_cmp(t1, modulus) != LTC_MP_LT) { if ((err = mp_sub(t1, modulus, t1)) != CRYPT_OK) { goto done; } } /* T2 = T1 * T2 */ if ((err = mp_mul(t1, t2, t2)) != CRYPT_OK) { goto done; } if ((err = mp_montgomery_reduce(t2, modulus, mp)) != CRYPT_OK) { goto done; } /* T1 = 2T2 */ if ((err = mp_add(t2, t2, t1)) != CRYPT_OK) { goto done; } if (mp_cmp(t1, modulus) != LTC_MP_LT) { if ((err = mp_sub(t1, modulus, t1)) != CRYPT_OK) { goto done; } } /* T1 = T1 + T2 */ if ((err = mp_add(t1, t2, t1)) != CRYPT_OK) { goto done; } if (mp_cmp(t1, modulus) != LTC_MP_LT) { if ((err = mp_sub(t1, modulus, t1)) != CRYPT_OK) { goto done; } } /* Y = 2Y */ if ((err = mp_add(R->y, R->y, R->y)) != CRYPT_OK) { goto done; } if (mp_cmp(R->y, modulus) != LTC_MP_LT) { if ((err = mp_sub(R->y, modulus, R->y)) != CRYPT_OK) { goto done; } } /* Y = Y * Y */ if ((err = mp_sqr(R->y, R->y)) != CRYPT_OK) { goto done; } if ((err = mp_montgomery_reduce(R->y, modulus, mp)) != CRYPT_OK) { goto done; } /* T2 = Y * Y */ if ((err = mp_sqr(R->y, t2)) != CRYPT_OK) { goto done; } if ((err = mp_montgomery_reduce(t2, modulus, mp)) != CRYPT_OK) { goto done; } /* T2 = T2/2 */ if (mp_isodd(t2)) { if ((err = mp_add(t2, modulus, t2)) != CRYPT_OK) { goto done; } } if ((err = mp_div_2(t2, t2)) != CRYPT_OK) { goto done; } /* Y = Y * X */ if ((err = mp_mul(R->y, R->x, R->y)) != CRYPT_OK) { goto done; } if ((err = mp_montgomery_reduce(R->y, modulus, mp)) != CRYPT_OK) { goto done; } /* X = T1 * T1 */ if ((err = mp_sqr(t1, R->x)) != CRYPT_OK) { goto done; } if ((err = mp_montgomery_reduce(R->x, modulus, mp)) != CRYPT_OK) { goto done; } /* X = X - Y */ if ((err = mp_sub(R->x, R->y, R->x)) != CRYPT_OK) { goto done; } if (mp_cmp_d(R->x, 0) == LTC_MP_LT) { if ((err = mp_add(R->x, modulus, R->x)) != CRYPT_OK) { goto done; } } /* X = X - Y */ if ((err = mp_sub(R->x, R->y, R->x)) != CRYPT_OK) { goto done; } if (mp_cmp_d(R->x, 0) == LTC_MP_LT) { if ((err = mp_add(R->x, modulus, R->x)) != CRYPT_OK) { goto done; } } /* Y = Y - X */ if ((err = mp_sub(R->y, R->x, R->y)) != CRYPT_OK) { goto done; } if (mp_cmp_d(R->y, 0) == LTC_MP_LT) { if ((err = mp_add(R->y, modulus, R->y)) != CRYPT_OK) { goto done; } } /* Y = Y * T1 */ if ((err = mp_mul(R->y, t1, R->y)) != CRYPT_OK) { goto done; } if ((err = mp_montgomery_reduce(R->y, modulus, mp)) != CRYPT_OK) { goto done; } /* Y = Y - T2 */ if ((err = mp_sub(R->y, t2, R->y)) != CRYPT_OK) { goto done; } if (mp_cmp_d(R->y, 0) == LTC_MP_LT) { if ((err = mp_add(R->y, modulus, R->y)) != CRYPT_OK) { goto done; } } err = CRYPT_OK; done: mp_clear_multi(t1, t2, NULL); return err; }
void cli_crt_clear(cli_crt *x509) { mp_clear_multi(&x509->n, &x509->e, &x509->sig, NULL); }
/** Add two ECC points @param P The point to add @param Q The point to add @param R [out] The destination of the double @param modulus The modulus of the field the ECC curve is in @param mp The "b" value from montgomery_setup() @return CRYPT_OK on success */ int ltc_ecc_projective_add_point(ecc_point *P, ecc_point *Q, ecc_point *R, void *modulus, void *mp) { void *t1, *t2, *x, *y, *z; int err; LTC_ARGCHK(P != NULL); LTC_ARGCHK(Q != NULL); LTC_ARGCHK(R != NULL); LTC_ARGCHK(modulus != NULL); LTC_ARGCHK(mp != NULL); if ((err = mp_init_multi(&t1, &t2, &x, &y, &z, NULL)) != CRYPT_OK) { return err; } /* should we dbl instead? */ if ((err = mp_sub(modulus, Q->y, t1)) != CRYPT_OK) { goto done; } if ( (mp_cmp(P->x, Q->x) == LTC_MP_EQ) && (Q->z != NULL && mp_cmp(P->z, Q->z) == LTC_MP_EQ) && (mp_cmp(P->y, Q->y) == LTC_MP_EQ || mp_cmp(P->y, t1) == LTC_MP_EQ)) { mp_clear_multi(t1, t2, x, y, z, NULL); return ltc_ecc_projective_dbl_point(P, R, modulus, mp); } if ((err = mp_copy(P->x, x)) != CRYPT_OK) { goto done; } if ((err = mp_copy(P->y, y)) != CRYPT_OK) { goto done; } if ((err = mp_copy(P->z, z)) != CRYPT_OK) { goto done; } /* if Z is one then these are no-operations */ if (Q->z != NULL) { /* T1 = Z' * Z' */ if ((err = mp_sqr(Q->z, t1)) != CRYPT_OK) { goto done; } if ((err = mp_montgomery_reduce(t1, modulus, mp)) != CRYPT_OK) { goto done; } /* X = X * T1 */ if ((err = mp_mul(t1, x, x)) != CRYPT_OK) { goto done; } if ((err = mp_montgomery_reduce(x, modulus, mp)) != CRYPT_OK) { goto done; } /* T1 = Z' * T1 */ if ((err = mp_mul(Q->z, t1, t1)) != CRYPT_OK) { goto done; } if ((err = mp_montgomery_reduce(t1, modulus, mp)) != CRYPT_OK) { goto done; } /* Y = Y * T1 */ if ((err = mp_mul(t1, y, y)) != CRYPT_OK) { goto done; } if ((err = mp_montgomery_reduce(y, modulus, mp)) != CRYPT_OK) { goto done; } } /* T1 = Z*Z */ if ((err = mp_sqr(z, t1)) != CRYPT_OK) { goto done; } if ((err = mp_montgomery_reduce(t1, modulus, mp)) != CRYPT_OK) { goto done; } /* T2 = X' * T1 */ if ((err = mp_mul(Q->x, t1, t2)) != CRYPT_OK) { goto done; } if ((err = mp_montgomery_reduce(t2, modulus, mp)) != CRYPT_OK) { goto done; } /* T1 = Z * T1 */ if ((err = mp_mul(z, t1, t1)) != CRYPT_OK) { goto done; } if ((err = mp_montgomery_reduce(t1, modulus, mp)) != CRYPT_OK) { goto done; } /* T1 = Y' * T1 */ if ((err = mp_mul(Q->y, t1, t1)) != CRYPT_OK) { goto done; } if ((err = mp_montgomery_reduce(t1, modulus, mp)) != CRYPT_OK) { goto done; } /* Y = Y - T1 */ if ((err = mp_sub(y, t1, y)) != CRYPT_OK) { goto done; } if (mp_cmp_d(y, 0) == LTC_MP_LT) { if ((err = mp_add(y, modulus, y)) != CRYPT_OK) { goto done; } } /* T1 = 2T1 */ if ((err = mp_add(t1, t1, t1)) != CRYPT_OK) { goto done; } if (mp_cmp(t1, modulus) != LTC_MP_LT) { if ((err = mp_sub(t1, modulus, t1)) != CRYPT_OK) { goto done; } } /* T1 = Y + T1 */ if ((err = mp_add(t1, y, t1)) != CRYPT_OK) { goto done; } if (mp_cmp(t1, modulus) != LTC_MP_LT) { if ((err = mp_sub(t1, modulus, t1)) != CRYPT_OK) { goto done; } } /* X = X - T2 */ if ((err = mp_sub(x, t2, x)) != CRYPT_OK) { goto done; } if (mp_cmp_d(x, 0) == LTC_MP_LT) { if ((err = mp_add(x, modulus, x)) != CRYPT_OK) { goto done; } } /* T2 = 2T2 */ if ((err = mp_add(t2, t2, t2)) != CRYPT_OK) { goto done; } if (mp_cmp(t2, modulus) != LTC_MP_LT) { if ((err = mp_sub(t2, modulus, t2)) != CRYPT_OK) { goto done; } } /* T2 = X + T2 */ if ((err = mp_add(t2, x, t2)) != CRYPT_OK) { goto done; } if (mp_cmp(t2, modulus) != LTC_MP_LT) { if ((err = mp_sub(t2, modulus, t2)) != CRYPT_OK) { goto done; } } /* if Z' != 1 */ if (Q->z != NULL) { /* Z = Z * Z' */ if ((err = mp_mul(z, Q->z, z)) != CRYPT_OK) { goto done; } if ((err = mp_montgomery_reduce(z, modulus, mp)) != CRYPT_OK) { goto done; } } /* Z = Z * X */ if ((err = mp_mul(z, x, z)) != CRYPT_OK) { goto done; } if ((err = mp_montgomery_reduce(z, modulus, mp)) != CRYPT_OK) { goto done; } /* T1 = T1 * X */ if ((err = mp_mul(t1, x, t1)) != CRYPT_OK) { goto done; } if ((err = mp_montgomery_reduce(t1, modulus, mp)) != CRYPT_OK) { goto done; } /* X = X * X */ if ((err = mp_sqr(x, x)) != CRYPT_OK) { goto done; } if ((err = mp_montgomery_reduce(x, modulus, mp)) != CRYPT_OK) { goto done; } /* T2 = T2 * x */ if ((err = mp_mul(t2, x, t2)) != CRYPT_OK) { goto done; } if ((err = mp_montgomery_reduce(t2, modulus, mp)) != CRYPT_OK) { goto done; } /* T1 = T1 * X */ if ((err = mp_mul(t1, x, t1)) != CRYPT_OK) { goto done; } if ((err = mp_montgomery_reduce(t1, modulus, mp)) != CRYPT_OK) { goto done; } /* X = Y*Y */ if ((err = mp_sqr(y, x)) != CRYPT_OK) { goto done; } if ((err = mp_montgomery_reduce(x, modulus, mp)) != CRYPT_OK) { goto done; } /* X = X - T2 */ if ((err = mp_sub(x, t2, x)) != CRYPT_OK) { goto done; } if (mp_cmp_d(x, 0) == LTC_MP_LT) { if ((err = mp_add(x, modulus, x)) != CRYPT_OK) { goto done; } } /* T2 = T2 - X */ if ((err = mp_sub(t2, x, t2)) != CRYPT_OK) { goto done; } if (mp_cmp_d(t2, 0) == LTC_MP_LT) { if ((err = mp_add(t2, modulus, t2)) != CRYPT_OK) { goto done; } } /* T2 = T2 - X */ if ((err = mp_sub(t2, x, t2)) != CRYPT_OK) { goto done; } if (mp_cmp_d(t2, 0) == LTC_MP_LT) { if ((err = mp_add(t2, modulus, t2)) != CRYPT_OK) { goto done; } } /* T2 = T2 * Y */ if ((err = mp_mul(t2, y, t2)) != CRYPT_OK) { goto done; } if ((err = mp_montgomery_reduce(t2, modulus, mp)) != CRYPT_OK) { goto done; } /* Y = T2 - T1 */ if ((err = mp_sub(t2, t1, y)) != CRYPT_OK) { goto done; } if (mp_cmp_d(y, 0) == LTC_MP_LT) { if ((err = mp_add(y, modulus, y)) != CRYPT_OK) { goto done; } } /* Y = Y/2 */ if (mp_isodd(y)) { if ((err = mp_add(y, modulus, y)) != CRYPT_OK) { goto done; } } if ((err = mp_div_2(y, y)) != CRYPT_OK) { goto done; } if ((err = mp_copy(x, R->x)) != CRYPT_OK) { goto done; } if ((err = mp_copy(y, R->y)) != CRYPT_OK) { goto done; } if ((err = mp_copy(z, R->z)) != CRYPT_OK) { goto done; } err = CRYPT_OK; done: mp_clear_multi(t1, t2, x, y, z, NULL); return err; }
// http://www.jjj.de/fxt/#fxtbook static int machin_ln_10(mp_float * a) { int err; long oldeps, eps; mp_int c1, c2, c3, a1, a2, a3, sum, zero, t1, t2, P, Q, R, EPS; oldeps = a->radix; eps = (oldeps + MP_DIGIT_BIT); // TODO: error calculation! err = MP_OKAY; if ((err = mp_init_multi(&c1, &c2, &c3, &a1, &a2, &a3, &sum, &zero, &t1, &t2, &EPS, &P, &Q, &R, NULL)) != MP_OKAY) { return err; } if ((err = mp_set_int(&EPS, (unsigned long) (eps))) != MP_OKAY) { goto _ERR; } // using acoth instead of atanh to make things simpler // atanh(x) = acoth(1/x) for x > 1 // coefficients due to P. Sebah "Machin like formulae for logarithm" (1997) // http://numbers.computation.free.fr/Constants/PiProgram/userconstants.html mp_set(&c1, 46); mp_set(&c2, 34); mp_set(&c3, 20); mp_set(&a1, 31); mp_set(&a2, 49); mp_set(&a3, 161); // http://oeis.org/A175607 mp_zero(&sum); mp_zero(&zero); if ((err = mp_acoth_binary_splitting(&a1, &zero, &EPS, &P, &Q, &R)) != MP_OKAY) { goto _ERR; } if ((err = mp_add(&P, &Q, &t1)) != MP_OKAY) { goto _ERR; } if ((err = mp_mul_2d(&t1, eps, &t1)) != MP_OKAY) { goto _ERR; } if ((err = mp_mul(&Q, &a1, &t2)) != MP_OKAY) { goto _ERR; } if ((err = mp_div(&t1, &t2, &t1, NULL)) != MP_OKAY) { goto _ERR; } if ((err = mp_mul(&t1, &c1, &sum)) != MP_OKAY) { goto _ERR; } if ((err = mp_acoth_binary_splitting(&a2, &zero, &EPS, &P, &Q, &R)) != MP_OKAY) { goto _ERR; } if ((err = mp_add(&P, &Q, &t1)) != MP_OKAY) { goto _ERR; } if ((err = mp_mul_2d(&t1, eps, &t1)) != MP_OKAY) { goto _ERR; } if ((err = mp_mul(&Q, &a2, &t2)) != MP_OKAY) { goto _ERR; } if ((err = mp_div(&t1, &t2, &t1, NULL)) != MP_OKAY) { goto _ERR; } if ((err = mp_mul(&t1, &c2, &t1)) != MP_OKAY) { goto _ERR; } if ((err = mp_add(&sum, &t1, &sum)) != MP_OKAY) { goto _ERR; } if ((err = mp_acoth_binary_splitting(&a3, &zero, &EPS, &P, &Q, &R)) != MP_OKAY) { goto _ERR; } if ((err = mp_add(&P, &Q, &t1)) != MP_OKAY) { goto _ERR; } if ((err = mp_mul_2d(&t1, eps, &t1)) != MP_OKAY) { goto _ERR; } if ((err = mp_mul(&Q, &a3, &t2)) != MP_OKAY) { goto _ERR; } if ((err = mp_div(&t1, &t2, &t1, NULL)) != MP_OKAY) { goto _ERR; } if ((err = mp_mul(&t1, &c3, &t1)) != MP_OKAY) { goto _ERR; } if ((err = mp_add(&sum, &t1, &sum)) != MP_OKAY) { goto _ERR; } if ((err = mpf_from_mp_int(&sum, a)) != MP_OKAY) { goto _ERR; } a->exp -= eps; _ERR: mp_clear_multi(&c1, &c2, &c3, &a1, &a2, &a3, &sum, &zero, &t1, &t2, &EPS, &P, &Q, &R, NULL); return err; }
/* Strong Lucas-Selfridge test. returns MP_YES if it is a strong L-S prime, MP_NO if it is composite Code ported from Thomas Ray Nicely's implementation of the BPSW test at http://www.trnicely.net/misc/bpsw.html Freeware copyright (C) 2016 Thomas R. Nicely <http://www.trnicely.net>. Released into the public domain by the author, who disclaims any legal liability arising from its use The multi-line comments are made by Thomas R. Nicely and are copied verbatim. Additional comments marked "CZ" (without the quotes) are by the code-portist. (If that name sounds familiar, he is the guy who found the fdiv bug in the Pentium (P5x, I think) Intel processor) */ int mp_prime_strong_lucas_selfridge(const mp_int *a, int *result) { /* CZ TODO: choose better variable names! */ mp_int Dz, gcd, Np1, Uz, Vz, U2mz, V2mz, Qmz, Q2mz, Qkdz, T1z, T2z, T3z, T4z, Q2kdz; /* CZ TODO: Some of them need the full 32 bit, hence the (temporary) exclusion of MP_8BIT */ int32_t D, Ds, J, sign, P, Q, r, s, u, Nbits; int e; int isset; *result = MP_NO; /* Find the first element D in the sequence {5, -7, 9, -11, 13, ...} such that Jacobi(D,N) = -1 (Selfridge's algorithm). Theory indicates that, if N is not a perfect square, D will "nearly always" be "small." Just in case, an overflow trap for D is included. */ if ((e = mp_init_multi(&Dz, &gcd, &Np1, &Uz, &Vz, &U2mz, &V2mz, &Qmz, &Q2mz, &Qkdz, &T1z, &T2z, &T3z, &T4z, &Q2kdz, NULL)) != MP_OKAY) { return e; } D = 5; sign = 1; for (;;) { Ds = sign * D; sign = -sign; if ((e = mp_set_long(&Dz, (unsigned long)D)) != MP_OKAY) { goto LBL_LS_ERR; } if ((e = mp_gcd(a, &Dz, &gcd)) != MP_OKAY) { goto LBL_LS_ERR; } /* if 1 < GCD < N then N is composite with factor "D", and Jacobi(D,N) is technically undefined (but often returned as zero). */ if ((mp_cmp_d(&gcd, 1uL) == MP_GT) && (mp_cmp(&gcd, a) == MP_LT)) { goto LBL_LS_ERR; } if (Ds < 0) { Dz.sign = MP_NEG; } if ((e = mp_kronecker(&Dz, a, &J)) != MP_OKAY) { goto LBL_LS_ERR; } if (J == -1) { break; } D += 2; if (D > (INT_MAX - 2)) { e = MP_VAL; goto LBL_LS_ERR; } } P = 1; /* Selfridge's choice */ Q = (1 - Ds) / 4; /* Required so D = P*P - 4*Q */ /* NOTE: The conditions (a) N does not divide Q, and (b) D is square-free or not a perfect square, are included by some authors; e.g., "Prime numbers and computer methods for factorization," Hans Riesel (2nd ed., 1994, Birkhauser, Boston), p. 130. For this particular application of Lucas sequences, these conditions were found to be immaterial. */ /* Now calculate N - Jacobi(D,N) = N + 1 (even), and calculate the odd positive integer d and positive integer s for which N + 1 = 2^s*d (similar to the step for N - 1 in Miller's test). The strong Lucas-Selfridge test then returns N as a strong Lucas probable prime (slprp) if any of the following conditions is met: U_d=0, V_d=0, V_2d=0, V_4d=0, V_8d=0, V_16d=0, ..., etc., ending with V_{2^(s-1)*d}=V_{(N+1)/2}=0 (all equalities mod N). Thus d is the highest index of U that must be computed (since V_2m is independent of U), compared to U_{N+1} for the standard Lucas-Selfridge test; and no index of V beyond (N+1)/2 is required, just as in the standard Lucas-Selfridge test. However, the quantity Q^d must be computed for use (if necessary) in the latter stages of the test. The result is that the strong Lucas-Selfridge test has a running time only slightly greater (order of 10 %) than that of the standard Lucas-Selfridge test, while producing only (roughly) 30 % as many pseudoprimes (and every strong Lucas pseudoprime is also a standard Lucas pseudoprime). Thus the evidence indicates that the strong Lucas-Selfridge test is more effective than the standard Lucas-Selfridge test, and a Baillie-PSW test based on the strong Lucas-Selfridge test should be more reliable. */ if ((e = mp_add_d(a, 1uL, &Np1)) != MP_OKAY) { goto LBL_LS_ERR; } s = mp_cnt_lsb(&Np1); /* CZ * This should round towards zero because * Thomas R. Nicely used GMP's mpz_tdiv_q_2exp() * and mp_div_2d() is equivalent. Additionally: * dividing an even number by two does not produce * any leftovers. */ if ((e = mp_div_2d(&Np1, s, &Dz, NULL)) != MP_OKAY) { goto LBL_LS_ERR; } /* We must now compute U_d and V_d. Since d is odd, the accumulated values U and V are initialized to U_1 and V_1 (if the target index were even, U and V would be initialized instead to U_0=0 and V_0=2). The values of U_2m and V_2m are also initialized to U_1 and V_1; the FOR loop calculates in succession U_2 and V_2, U_4 and V_4, U_8 and V_8, etc. If the corresponding bits (1, 2, 3, ...) of t are on (the zero bit having been accounted for in the initialization of U and V), these values are then combined with the previous totals for U and V, using the composition formulas for addition of indices. */ mp_set(&Uz, 1uL); /* U=U_1 */ mp_set(&Vz, (mp_digit)P); /* V=V_1 */ mp_set(&U2mz, 1uL); /* U_1 */ mp_set(&V2mz, (mp_digit)P); /* V_1 */ if (Q < 0) { Q = -Q; if ((e = mp_set_long(&Qmz, (unsigned long)Q)) != MP_OKAY) { goto LBL_LS_ERR; } if ((e = mp_mul_2(&Qmz, &Q2mz)) != MP_OKAY) { goto LBL_LS_ERR; } /* Initializes calculation of Q^d */ if ((e = mp_set_long(&Qkdz, (unsigned long)Q)) != MP_OKAY) { goto LBL_LS_ERR; } Qmz.sign = MP_NEG; Q2mz.sign = MP_NEG; Qkdz.sign = MP_NEG; Q = -Q; } else { if ((e = mp_set_long(&Qmz, (unsigned long)Q)) != MP_OKAY) { goto LBL_LS_ERR; } if ((e = mp_mul_2(&Qmz, &Q2mz)) != MP_OKAY) { goto LBL_LS_ERR; } /* Initializes calculation of Q^d */ if ((e = mp_set_long(&Qkdz, (unsigned long)Q)) != MP_OKAY) { goto LBL_LS_ERR; } } Nbits = mp_count_bits(&Dz); for (u = 1; u < Nbits; u++) { /* zero bit off, already accounted for */ /* Formulas for doubling of indices (carried out mod N). Note that * the indices denoted as "2m" are actually powers of 2, specifically * 2^(ul-1) beginning each loop and 2^ul ending each loop. * * U_2m = U_m*V_m * V_2m = V_m*V_m - 2*Q^m */ if ((e = mp_mul(&U2mz, &V2mz, &U2mz)) != MP_OKAY) { goto LBL_LS_ERR; } if ((e = mp_mod(&U2mz, a, &U2mz)) != MP_OKAY) { goto LBL_LS_ERR; } if ((e = mp_sqr(&V2mz, &V2mz)) != MP_OKAY) { goto LBL_LS_ERR; } if ((e = mp_sub(&V2mz, &Q2mz, &V2mz)) != MP_OKAY) { goto LBL_LS_ERR; } if ((e = mp_mod(&V2mz, a, &V2mz)) != MP_OKAY) { goto LBL_LS_ERR; } /* Must calculate powers of Q for use in V_2m, also for Q^d later */ if ((e = mp_sqr(&Qmz, &Qmz)) != MP_OKAY) { goto LBL_LS_ERR; } /* prevents overflow */ /* CZ still necessary without a fixed prealloc'd mem.? */ if ((e = mp_mod(&Qmz, a, &Qmz)) != MP_OKAY) { goto LBL_LS_ERR; } if ((e = mp_mul_2(&Qmz, &Q2mz)) != MP_OKAY) { goto LBL_LS_ERR; } if ((isset = mp_get_bit(&Dz, u)) == MP_VAL) { e = isset; goto LBL_LS_ERR; } if (isset == MP_YES) { /* Formulas for addition of indices (carried out mod N); * * U_(m+n) = (U_m*V_n + U_n*V_m)/2 * V_(m+n) = (V_m*V_n + D*U_m*U_n)/2 * * Be careful with division by 2 (mod N)! */ if ((e = mp_mul(&U2mz, &Vz, &T1z)) != MP_OKAY) { goto LBL_LS_ERR; } if ((e = mp_mul(&Uz, &V2mz, &T2z)) != MP_OKAY) { goto LBL_LS_ERR; } if ((e = mp_mul(&V2mz, &Vz, &T3z)) != MP_OKAY) { goto LBL_LS_ERR; } if ((e = mp_mul(&U2mz, &Uz, &T4z)) != MP_OKAY) { goto LBL_LS_ERR; } if ((e = s_mp_mul_si(&T4z, (long)Ds, &T4z)) != MP_OKAY) { goto LBL_LS_ERR; } if ((e = mp_add(&T1z, &T2z, &Uz)) != MP_OKAY) { goto LBL_LS_ERR; } if (mp_isodd(&Uz) != MP_NO) { if ((e = mp_add(&Uz, a, &Uz)) != MP_OKAY) { goto LBL_LS_ERR; } } /* CZ * This should round towards negative infinity because * Thomas R. Nicely used GMP's mpz_fdiv_q_2exp(). * But mp_div_2() does not do so, it is truncating instead. */ if ((e = mp_div_2(&Uz, &Uz)) != MP_OKAY) { goto LBL_LS_ERR; } if ((Uz.sign == MP_NEG) && (mp_isodd(&Uz) != MP_NO)) { if ((e = mp_sub_d(&Uz, 1uL, &Uz)) != MP_OKAY) { goto LBL_LS_ERR; } } if ((e = mp_add(&T3z, &T4z, &Vz)) != MP_OKAY) { goto LBL_LS_ERR; } if (mp_isodd(&Vz) != MP_NO) { if ((e = mp_add(&Vz, a, &Vz)) != MP_OKAY) { goto LBL_LS_ERR; } } if ((e = mp_div_2(&Vz, &Vz)) != MP_OKAY) { goto LBL_LS_ERR; } if ((Vz.sign == MP_NEG) && (mp_isodd(&Vz) != MP_NO)) { if ((e = mp_sub_d(&Vz, 1uL, &Vz)) != MP_OKAY) { goto LBL_LS_ERR; } } if ((e = mp_mod(&Uz, a, &Uz)) != MP_OKAY) { goto LBL_LS_ERR; } if ((e = mp_mod(&Vz, a, &Vz)) != MP_OKAY) { goto LBL_LS_ERR; } /* Calculating Q^d for later use */ if ((e = mp_mul(&Qkdz, &Qmz, &Qkdz)) != MP_OKAY) { goto LBL_LS_ERR; } if ((e = mp_mod(&Qkdz, a, &Qkdz)) != MP_OKAY) { goto LBL_LS_ERR; } } } /* If U_d or V_d is congruent to 0 mod N, then N is a prime or a strong Lucas pseudoprime. */ if ((mp_iszero(&Uz) != MP_NO) || (mp_iszero(&Vz) != MP_NO)) { *result = MP_YES; goto LBL_LS_ERR; } /* NOTE: Ribenboim ("The new book of prime number records," 3rd ed., 1995/6) omits the condition V0 on p.142, but includes it on p. 130. The condition is NECESSARY; otherwise the test will return false negatives---e.g., the primes 29 and 2000029 will be returned as composite. */ /* Otherwise, we must compute V_2d, V_4d, V_8d, ..., V_{2^(s-1)*d} by repeated use of the formula V_2m = V_m*V_m - 2*Q^m. If any of these are congruent to 0 mod N, then N is a prime or a strong Lucas pseudoprime. */ /* Initialize 2*Q^(d*2^r) for V_2m */ if ((e = mp_mul_2(&Qkdz, &Q2kdz)) != MP_OKAY) { goto LBL_LS_ERR; } for (r = 1; r < s; r++) { if ((e = mp_sqr(&Vz, &Vz)) != MP_OKAY) { goto LBL_LS_ERR; } if ((e = mp_sub(&Vz, &Q2kdz, &Vz)) != MP_OKAY) { goto LBL_LS_ERR; } if ((e = mp_mod(&Vz, a, &Vz)) != MP_OKAY) { goto LBL_LS_ERR; } if (mp_iszero(&Vz) != MP_NO) { *result = MP_YES; goto LBL_LS_ERR; } /* Calculate Q^{d*2^r} for next r (final iteration irrelevant). */ if (r < (s - 1)) { if ((e = mp_sqr(&Qkdz, &Qkdz)) != MP_OKAY) { goto LBL_LS_ERR; } if ((e = mp_mod(&Qkdz, a, &Qkdz)) != MP_OKAY) { goto LBL_LS_ERR; } if ((e = mp_mul_2(&Qkdz, &Q2kdz)) != MP_OKAY) { goto LBL_LS_ERR; } } } LBL_LS_ERR: mp_clear_multi(&Q2kdz, &T4z, &T3z, &T2z, &T1z, &Qkdz, &Q2mz, &Qmz, &V2mz, &U2mz, &Vz, &Uz, &Np1, &gcd, &Dz, NULL); return e; }
/** Verify a DSA key for validity @param key The key to verify @param stat [out] Result of test, 1==valid, 0==invalid @return CRYPT_OK if successful */ int dsa_verify_key(dsa_key *key, int *stat) { void *tmp, *tmp2; int res, err; LTC_ARGCHK(key != NULL); LTC_ARGCHK(stat != NULL); /* default to an invalid key */ *stat = 0; /* first make sure key->q and key->p are prime */ if ((err = mp_prime_is_prime(key->q, 8, &res)) != CRYPT_OK) { return err; } if (res == 0) { return CRYPT_OK; } if ((err = mp_prime_is_prime(key->p, 8, &res)) != CRYPT_OK) { return err; } if (res == 0) { return CRYPT_OK; } /* now make sure that g is not -1, 0 or 1 and <p */ if (mp_cmp_d(key->g, 0) == LTC_MP_EQ || mp_cmp_d(key->g, 1) == LTC_MP_EQ) { return CRYPT_OK; } if ((err = mp_init_multi(&tmp, &tmp2, NULL)) != CRYPT_OK) { return err; } if ((err = mp_sub_d(key->p, 1, tmp)) != CRYPT_OK) { goto error; } if (mp_cmp(tmp, key->g) == LTC_MP_EQ || mp_cmp(key->g, key->p) != LTC_MP_LT) { err = CRYPT_OK; goto error; } /* 1 < y < p-1 */ if (!(mp_cmp_d(key->y, 1) == LTC_MP_GT && mp_cmp(key->y, tmp) == LTC_MP_LT)) { err = CRYPT_OK; goto error; } /* now we have to make sure that g^q = 1, and that p-1/q gives 0 remainder */ if ((err = mp_div(tmp, key->q, tmp, tmp2)) != CRYPT_OK) { goto error; } if (mp_iszero(tmp2) != LTC_MP_YES) { err = CRYPT_OK; goto error; } if ((err = mp_exptmod(key->g, key->q, key->p, tmp)) != CRYPT_OK) { goto error; } if (mp_cmp_d(tmp, 1) != LTC_MP_EQ) { err = CRYPT_OK; goto error; } /* now we have to make sure that y^q = 1, this makes sure y \in g^x mod p */ if ((err = mp_exptmod(key->y, key->q, key->p, tmp)) != CRYPT_OK) { goto error; } if (mp_cmp_d(tmp, 1) != LTC_MP_EQ) { err = CRYPT_OK; goto error; } /* at this point we are out of tests ;-( */ err = CRYPT_OK; *stat = 1; error: mp_clear_multi(tmp, tmp2, NULL); return err; }
/** Create a DSA key @param prng An active PRNG state @param wprng The index of the PRNG desired @param group_size Size of the multiplicative group (octets) @param modulus_size Size of the modulus (octets) @param key [out] Where to store the created key @return CRYPT_OK if successful, upon error this function will free all allocated memory */ int dsa_make_key(prng_state *prng, int wprng, int group_size, int modulus_size, dsa_key *key) { mp_int tmp, tmp2; int err, res; unsigned char *buf; LTC_ARGCHK(key != NULL); /* check prng */ if ((err = prng_is_valid(wprng)) != CRYPT_OK) { return err; } /* check size */ if (group_size >= MDSA_MAX_GROUP || group_size <= 15 || group_size >= modulus_size || (modulus_size - group_size) >= MDSA_DELTA) { return CRYPT_INVALID_ARG; } /* allocate ram */ buf = XMALLOC(MDSA_DELTA); if (buf == NULL) { return CRYPT_MEM; } /* init mp_ints */ if ((err = mp_init_multi(&tmp, &tmp2, &key->g, &key->q, &key->p, &key->x, &key->y, NULL)) != MP_OKAY) { err = mpi_to_ltc_error(err); goto LBL_ERR; } /* make our prime q */ if ((err = rand_prime(&key->q, group_size*8, prng, wprng)) != CRYPT_OK) { goto LBL_ERR; } /* double q */ if ((err = mp_mul_2(&key->q, &tmp)) != MP_OKAY) { goto error; } /* now make a random string and multply it against q */ if (prng_descriptor[wprng].read(buf+1, modulus_size - group_size, prng) != (unsigned long)(modulus_size - group_size)) { err = CRYPT_ERROR_READPRNG; goto LBL_ERR; } /* force magnitude */ buf[0] = 1; /* force even */ buf[modulus_size - group_size] &= ~1; if ((err = mp_read_unsigned_bin(&tmp2, buf, modulus_size - group_size+1)) != MP_OKAY) { goto error; } if ((err = mp_mul(&key->q, &tmp2, &key->p)) != MP_OKAY) { goto error; } if ((err = mp_add_d(&key->p, 1, &key->p)) != MP_OKAY) { goto error; } /* now loop until p is prime */ for (;;) { if ((err = is_prime(&key->p, &res)) != CRYPT_OK) { goto LBL_ERR; } if (res == MP_YES) break; /* add 2q to p and 2 to tmp2 */ if ((err = mp_add(&tmp, &key->p, &key->p)) != MP_OKAY) { goto error; } if ((err = mp_add_d(&tmp2, 2, &tmp2)) != MP_OKAY) { goto error; } } /* now p = (q * tmp2) + 1 is prime, find a value g for which g^tmp2 != 1 */ mp_set(&key->g, 1); do { if ((err = mp_add_d(&key->g, 1, &key->g)) != MP_OKAY) { goto error; } if ((err = mp_exptmod(&key->g, &tmp2, &key->p, &tmp)) != MP_OKAY) { goto error; } } while (mp_cmp_d(&tmp, 1) == MP_EQ); /* at this point tmp generates a group of order q mod p */ mp_exch(&tmp, &key->g); /* so now we have our DH structure, generator g, order q, modulus p Now we need a random exponent [mod q] and it's power g^x mod p */ do { if (prng_descriptor[wprng].read(buf, group_size, prng) != (unsigned long)group_size) { err = CRYPT_ERROR_READPRNG; goto LBL_ERR; } if ((err = mp_read_unsigned_bin(&key->x, buf, group_size)) != MP_OKAY) { goto error; } } while (mp_cmp_d(&key->x, 1) != MP_GT); if ((err = mp_exptmod(&key->g, &key->x, &key->p, &key->y)) != MP_OKAY) { goto error; } key->type = PK_PRIVATE; key->qord = group_size; /* shrink the ram required */ if ((err = mp_shrink(&key->g)) != MP_OKAY) { goto error; } if ((err = mp_shrink(&key->p)) != MP_OKAY) { goto error; } if ((err = mp_shrink(&key->q)) != MP_OKAY) { goto error; } if ((err = mp_shrink(&key->x)) != MP_OKAY) { goto error; } if ((err = mp_shrink(&key->y)) != MP_OKAY) { goto error; } #ifdef LTC_CLEAN_STACK zeromem(buf, MDSA_DELTA); #endif err = CRYPT_OK; goto done; error: err = mpi_to_ltc_error(err); LBL_ERR: mp_clear_multi(&key->g, &key->q, &key->p, &key->x, &key->y, NULL); done: mp_clear_multi(&tmp, &tmp2, NULL); XFREE(buf); return err; }
/* multiplication using the Toom-Cook 3-way algorithm * * Much more complicated than Karatsuba but has a lower * asymptotic running time of O(N**1.464). This algorithm is * only particularly useful on VERY large inputs * (we're talking 1000s of digits here...). */ int mp_toom_mul(mp_int *a, mp_int *b, mp_int *c) { mp_int w0, w1, w2, w3, w4, tmp1, tmp2, a0, a1, a2, b0, b1, b2; int res, B; /* init temps */ if ((res = mp_init_multi(&w0, &w1, &w2, &w3, &w4, &a0, &a1, &a2, &b0, &b1, &b2, &tmp1, &tmp2, NULL)) != MP_OKAY) { return res; } /* B */ B = MIN(USED(a), USED(b)) / 3; /* a = a2 * B**2 + a1 * B + a0 */ if ((res = mp_mod_2d(a, DIGIT_BIT * B, &a0)) != MP_OKAY) { goto ERR; } if ((res = mp_copy(a, &a1)) != MP_OKAY) { goto ERR; } mp_rshd(&a1, B); mp_mod_2d(&a1, DIGIT_BIT * B, &a1); if ((res = mp_copy(a, &a2)) != MP_OKAY) { goto ERR; } mp_rshd(&a2, B*2); /* b = b2 * B**2 + b1 * B + b0 */ if ((res = mp_mod_2d(b, DIGIT_BIT * B, &b0)) != MP_OKAY) { goto ERR; } if ((res = mp_copy(b, &b1)) != MP_OKAY) { goto ERR; } mp_rshd(&b1, B); mp_mod_2d(&b1, DIGIT_BIT * B, &b1); if ((res = mp_copy(b, &b2)) != MP_OKAY) { goto ERR; } mp_rshd(&b2, B*2); /* w0 = a0*b0 */ if ((res = mp_mul(&a0, &b0, &w0)) != MP_OKAY) { goto ERR; } /* w4 = a2 * b2 */ if ((res = mp_mul(&a2, &b2, &w4)) != MP_OKAY) { goto ERR; } /* w1 = (a2 + 2(a1 + 2a0))(b2 + 2(b1 + 2b0)) */ if ((res = mp_mul_2(&a0, &tmp1)) != MP_OKAY) { goto ERR; } if ((res = mp_add(&tmp1, &a1, &tmp1)) != MP_OKAY) { goto ERR; } if ((res = mp_mul_2(&tmp1, &tmp1)) != MP_OKAY) { goto ERR; } if ((res = mp_add(&tmp1, &a2, &tmp1)) != MP_OKAY) { goto ERR; } if ((res = mp_mul_2(&b0, &tmp2)) != MP_OKAY) { goto ERR; } if ((res = mp_add(&tmp2, &b1, &tmp2)) != MP_OKAY) { goto ERR; } if ((res = mp_mul_2(&tmp2, &tmp2)) != MP_OKAY) { goto ERR; } if ((res = mp_add(&tmp2, &b2, &tmp2)) != MP_OKAY) { goto ERR; } if ((res = mp_mul(&tmp1, &tmp2, &w1)) != MP_OKAY) { goto ERR; } /* w3 = (a0 + 2(a1 + 2a2))(b0 + 2(b1 + 2b2)) */ if ((res = mp_mul_2(&a2, &tmp1)) != MP_OKAY) { goto ERR; } if ((res = mp_add(&tmp1, &a1, &tmp1)) != MP_OKAY) { goto ERR; } if ((res = mp_mul_2(&tmp1, &tmp1)) != MP_OKAY) { goto ERR; } if ((res = mp_add(&tmp1, &a0, &tmp1)) != MP_OKAY) { goto ERR; } if ((res = mp_mul_2(&b2, &tmp2)) != MP_OKAY) { goto ERR; } if ((res = mp_add(&tmp2, &b1, &tmp2)) != MP_OKAY) { goto ERR; } if ((res = mp_mul_2(&tmp2, &tmp2)) != MP_OKAY) { goto ERR; } if ((res = mp_add(&tmp2, &b0, &tmp2)) != MP_OKAY) { goto ERR; } if ((res = mp_mul(&tmp1, &tmp2, &w3)) != MP_OKAY) { goto ERR; } /* w2 = (a2 + a1 + a0)(b2 + b1 + b0) */ if ((res = mp_add(&a2, &a1, &tmp1)) != MP_OKAY) { goto ERR; } if ((res = mp_add(&tmp1, &a0, &tmp1)) != MP_OKAY) { goto ERR; } if ((res = mp_add(&b2, &b1, &tmp2)) != MP_OKAY) { goto ERR; } if ((res = mp_add(&tmp2, &b0, &tmp2)) != MP_OKAY) { goto ERR; } if ((res = mp_mul(&tmp1, &tmp2, &w2)) != MP_OKAY) { goto ERR; } /* now solve the matrix 0 0 0 0 1 1 2 4 8 16 1 1 1 1 1 16 8 4 2 1 1 0 0 0 0 using 12 subtractions, 4 shifts, 2 small divisions and 1 small multiplication */ /* r1 - r4 */ if ((res = mp_sub(&w1, &w4, &w1)) != MP_OKAY) { goto ERR; } /* r3 - r0 */ if ((res = mp_sub(&w3, &w0, &w3)) != MP_OKAY) { goto ERR; } /* r1/2 */ if ((res = mp_div_2(&w1, &w1)) != MP_OKAY) { goto ERR; } /* r3/2 */ if ((res = mp_div_2(&w3, &w3)) != MP_OKAY) { goto ERR; } /* r2 - r0 - r4 */ if ((res = mp_sub(&w2, &w0, &w2)) != MP_OKAY) { goto ERR; } if ((res = mp_sub(&w2, &w4, &w2)) != MP_OKAY) { goto ERR; } /* r1 - r2 */ if ((res = mp_sub(&w1, &w2, &w1)) != MP_OKAY) { goto ERR; } /* r3 - r2 */ if ((res = mp_sub(&w3, &w2, &w3)) != MP_OKAY) { goto ERR; } /* r1 - 8r0 */ if ((res = mp_mul_2d(&w0, 3, &tmp1)) != MP_OKAY) { goto ERR; } if ((res = mp_sub(&w1, &tmp1, &w1)) != MP_OKAY) { goto ERR; } /* r3 - 8r4 */ if ((res = mp_mul_2d(&w4, 3, &tmp1)) != MP_OKAY) { goto ERR; } if ((res = mp_sub(&w3, &tmp1, &w3)) != MP_OKAY) { goto ERR; } /* 3r2 - r1 - r3 */ if ((res = mp_mul_d(&w2, 3, &w2)) != MP_OKAY) { goto ERR; } if ((res = mp_sub(&w2, &w1, &w2)) != MP_OKAY) { goto ERR; } if ((res = mp_sub(&w2, &w3, &w2)) != MP_OKAY) { goto ERR; } /* r1 - r2 */ if ((res = mp_sub(&w1, &w2, &w1)) != MP_OKAY) { goto ERR; } /* r3 - r2 */ if ((res = mp_sub(&w3, &w2, &w3)) != MP_OKAY) { goto ERR; } /* r1/3 */ if ((res = mp_div_3(&w1, &w1, NULL)) != MP_OKAY) { goto ERR; } /* r3/3 */ if ((res = mp_div_3(&w3, &w3, NULL)) != MP_OKAY) { goto ERR; } /* at this point shift W[n] by B*n */ if ((res = mp_lshd(&w1, 1*B)) != MP_OKAY) { goto ERR; } if ((res = mp_lshd(&w2, 2*B)) != MP_OKAY) { goto ERR; } if ((res = mp_lshd(&w3, 3*B)) != MP_OKAY) { goto ERR; } if ((res = mp_lshd(&w4, 4*B)) != MP_OKAY) { goto ERR; } if ((res = mp_add(&w0, &w1, c)) != MP_OKAY) { goto ERR; } if ((res = mp_add(&w2, &w3, &tmp1)) != MP_OKAY) { goto ERR; } if ((res = mp_add(&w4, &tmp1, &tmp1)) != MP_OKAY) { goto ERR; } if ((res = mp_add(&tmp1, c, c)) != MP_OKAY) { goto ERR; } ERR: mp_clear_multi(&w0, &w1, &w2, &w3, &w4, &a0, &a1, &a2, &b0, &b1, &b2, &tmp1, &tmp2, NULL); return res; }
/* this is a shell function that calls either the normal or Montgomery * exptmod functions. Originally the call to the montgomery code was * embedded in the normal function but that wasted alot of stack space * for nothing (since 99% of the time the Montgomery code would be called) */ int mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y) { int dr; /* modulus P must be positive */ if (P->sign == MP_NEG) { return MP_VAL; } /* if exponent X is negative we have to recurse */ if (X->sign == MP_NEG) { #ifdef BN_MP_INVMOD_C mp_int tmpG, tmpX; int err; /* first compute 1/G mod P */ if ((err = mp_init(&tmpG)) != MP_OKAY) { return err; } if ((err = mp_invmod(G, P, &tmpG)) != MP_OKAY) { mp_clear(&tmpG); return err; } /* now get |X| */ if ((err = mp_init(&tmpX)) != MP_OKAY) { mp_clear(&tmpG); return err; } if ((err = mp_abs(X, &tmpX)) != MP_OKAY) { mp_clear_multi(&tmpG, &tmpX, NULL); return err; } /* and now compute (1/G)**|X| instead of G**X [X < 0] */ err = mp_exptmod(&tmpG, &tmpX, P, Y); mp_clear_multi(&tmpG, &tmpX, NULL); return err; #else /* no invmod */ return MP_VAL; #endif } /* modified diminished radix reduction */ #if defined(BN_MP_REDUCE_IS_2K_L_C) && defined(BN_MP_REDUCE_2K_L_C) && defined(BN_S_MP_EXPTMOD_C) if (mp_reduce_is_2k_l(P) == MP_YES) { return s_mp_exptmod(G, X, P, Y, 1); } #endif #ifdef BN_MP_DR_IS_MODULUS_C /* is it a DR modulus? */ dr = mp_dr_is_modulus(P); #else /* default to no */ dr = 0; #endif #ifdef BN_MP_REDUCE_IS_2K_C /* if not, is it a unrestricted DR modulus? */ if (dr == 0) { dr = mp_reduce_is_2k(P) << 1; } #endif /* if the modulus is odd or dr != 0 use the montgomery method */ #ifdef BN_MP_EXPTMOD_FAST_C if (mp_isodd (P) == 1 || dr != 0) { return mp_exptmod_fast (G, X, P, Y, dr); } else { #endif #ifdef BN_S_MP_EXPTMOD_C /* otherwise use the generic Barrett reduction technique */ return s_mp_exptmod (G, X, P, Y, 0); #else /* no exptmod for evens */ return MP_VAL; #endif #ifdef BN_MP_EXPTMOD_FAST_C } #endif }
/* slower bit-bang division... also smaller */ int mp_div(mp_int * a, mp_int * b, mp_int * c, mp_int * d) { mp_int ta, tb, tq, q; int res, n, n2; /* is divisor zero ? */ if (mp_iszero (b) == 1) { return MP_VAL; } /* if a < b then q=0, r = a */ if (mp_cmp_mag (a, b) == MP_LT) { if (d != NULL) { res = mp_copy (a, d); } else { res = MP_OKAY; } if (c != NULL) { mp_zero (c); } return res; } /* init our temps */ if ((res = mp_init_multi(&ta, &tb, &tq, &q, NULL) != MP_OKAY)) { return res; } mp_set(&tq, 1); n = mp_count_bits(a) - mp_count_bits(b); if (((res = mp_abs(a, &ta)) != MP_OKAY) || ((res = mp_abs(b, &tb)) != MP_OKAY) || ((res = mp_mul_2d(&tb, n, &tb)) != MP_OKAY) || ((res = mp_mul_2d(&tq, n, &tq)) != MP_OKAY)) { goto LBL_ERR; } while (n-- >= 0) { if (mp_cmp(&tb, &ta) != MP_GT) { if (((res = mp_sub(&ta, &tb, &ta)) != MP_OKAY) || ((res = mp_add(&q, &tq, &q)) != MP_OKAY)) { goto LBL_ERR; } } if (((res = mp_div_2d(&tb, 1, &tb, NULL)) != MP_OKAY) || ((res = mp_div_2d(&tq, 1, &tq, NULL)) != MP_OKAY)) { goto LBL_ERR; } } /* now q == quotient and ta == remainder */ n = a->sign; n2 = (a->sign == b->sign ? MP_ZPOS : MP_NEG); if (c != NULL) { mp_exch(c, &q); c->sign = (mp_iszero(c) == MP_YES) ? MP_ZPOS : n2; } if (d != NULL) { mp_exch(d, &ta); d->sign = (mp_iszero(d) == MP_YES) ? MP_ZPOS : n; } LBL_ERR: mp_clear_multi(&ta, &tb, &tq, &q, NULL); return res; }
/** Sign a hash with DSA @param in The hash to sign @param inlen The length of the hash to sign @param r The "r" integer of the signature (caller must initialize with mp_init() first) @param s The "s" integer of the signature (caller must initialize with mp_init() first) @param prng An active PRNG state @param wprng The index of the PRNG desired @param key A private DSA key @return CRYPT_OK if successful */ int dsa_sign_hash_raw(const unsigned char *in, unsigned long inlen, void *r, void *s, prng_state *prng, int wprng, dsa_key *key) { void *k, *kinv, *tmp; unsigned char *buf; int err, qbits; LTC_ARGCHK(in != NULL); LTC_ARGCHK(r != NULL); LTC_ARGCHK(s != NULL); LTC_ARGCHK(key != NULL); if ((err = prng_is_valid(wprng)) != CRYPT_OK) { return err; } if (key->type != PK_PRIVATE) { return CRYPT_PK_NOT_PRIVATE; } /* check group order size */ if (key->qord >= LTC_MDSA_MAX_GROUP) { return CRYPT_INVALID_ARG; } buf = XMALLOC(LTC_MDSA_MAX_GROUP); if (buf == NULL) { return CRYPT_MEM; } /* Init our temps */ if ((err = mp_init_multi(&k, &kinv, &tmp, NULL)) != CRYPT_OK) { goto ERRBUF; } qbits = mp_count_bits(key->q); retry: do { /* gen random k */ if ((err = rand_bn_bits(k, qbits, prng, wprng)) != CRYPT_OK) { goto error; } /* k should be from range: 1 <= k <= q-1 (see FIPS 186-4 B.2.2) */ if (mp_cmp_d(k, 0) != LTC_MP_GT || mp_cmp(k, key->q) != LTC_MP_LT) { goto retry; } /* test gcd */ if ((err = mp_gcd(k, key->q, tmp)) != CRYPT_OK) { goto error; } } while (mp_cmp_d(tmp, 1) != LTC_MP_EQ); /* now find 1/k mod q */ if ((err = mp_invmod(k, key->q, kinv)) != CRYPT_OK) { goto error; } /* now find r = g^k mod p mod q */ if ((err = mp_exptmod(key->g, k, key->p, r)) != CRYPT_OK) { goto error; } if ((err = mp_mod(r, key->q, r)) != CRYPT_OK) { goto error; } if (mp_iszero(r) == LTC_MP_YES) { goto retry; } /* FIPS 186-4 4.6: use leftmost min(bitlen(q), bitlen(hash)) bits of 'hash'*/ inlen = MIN(inlen, (unsigned long)(key->qord)); /* now find s = (in + xr)/k mod q */ if ((err = mp_read_unsigned_bin(tmp, (unsigned char *)in, inlen)) != CRYPT_OK) { goto error; } if ((err = mp_mul(key->x, r, s)) != CRYPT_OK) { goto error; } if ((err = mp_add(s, tmp, s)) != CRYPT_OK) { goto error; } if ((err = mp_mulmod(s, kinv, key->q, s)) != CRYPT_OK) { goto error; } if (mp_iszero(s) == LTC_MP_YES) { goto retry; } err = CRYPT_OK; error: mp_clear_multi(k, kinv, tmp, NULL); ERRBUF: #ifdef LTC_CLEAN_STACK zeromem(buf, LTC_MDSA_MAX_GROUP); #endif XFREE(buf); return err; }
/** Free an ECC key from memory @param key The key you wish to free */ void ecc_free(ecc_key *key) { LTC_ARGCHKVD(key != NULL); mp_clear_multi(key->pubkey.x, key->pubkey.y, key->pubkey.z, key->k, NULL); }
static int ltm_rsa_public_decrypt(int flen, const unsigned char* from, unsigned char* to, RSA* rsa, int padding) { unsigned char *p; int res; size_t size; mp_int s, us, n, e; if (padding != RSA_PKCS1_PADDING) return -1; if (flen > RSA_size(rsa)) return -2; mp_init_multi(&e, &n, &s, &us, NULL); BN2mpz(&n, rsa->n); BN2mpz(&e, rsa->e); if (mp_cmp_d(&e, 3) == MP_LT) { mp_clear_multi(&e, &n, &s, &us, NULL); return -3; } mp_read_unsigned_bin(&s, rk_UNCONST(from), flen); if (mp_cmp(&s, &n) >= 0) { mp_clear_multi(&e, &n, &s, &us, NULL); return -4; } res = mp_exptmod(&s, &e, &n, &us); mp_clear_multi(&e, &n, &s, NULL); if (res != 0) { mp_clear(&us); return -5; } p = to; size = mp_unsigned_bin_size(&us); assert(size <= RSA_size(rsa)); mp_to_unsigned_bin(&us, p); mp_clear(&us); /* head zero was skipped by mp_to_unsigned_bin */ if (*p == 0) return -6; if (*p != 1) return -7; size--; p++; while (size && *p == 0xff) { size--; p++; } if (size == 0 || *p != 0) return -8; size--; p++; memmove(to, p, size); return size; }