+const DH_METHOD *DH_get_default_method(void)
+{
+ return default_DH_method;
+}
+
+static int dh_bn_mod_exp(const DH *dh, BIGNUM *r,
+ const BIGNUM *a, const BIGNUM *p,
+ const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx)
+{
+ return BN_mod_exp_mont(r, a, p, m, ctx, m_ctx);
+}
+
+static int dh_init(DH *dh)
+{
+ dh->flags |= DH_FLAG_CACHE_MONT_P;
+ ffc_params_init(&dh->params);
+ dh->dirty_cnt++;
+ return 1;
+}
+
+static int dh_finish(DH *dh)
+{
+ BN_MONT_CTX_free(dh->method_mont_p);
+ return 1;
+}
+
+#ifndef FIPS_MODE
+void DH_set_default_method(const DH_METHOD *meth)
+{
+ default_DH_method = meth;
+}
+#endif /* FIPS_MODE */
+
+int DH_generate_key(DH *dh)
+{
+#ifdef FIPS_MODE
+ return generate_key(dh);
+#else
+ return dh->meth->generate_key(dh);
+#endif
+}
+
+int dh_generate_public_key(BN_CTX *ctx, DH *dh, const BIGNUM *priv_key,
+ BIGNUM *pub_key)
+{
+ int ret = 0;
+ BIGNUM *prk = BN_new();
+ BN_MONT_CTX *mont = NULL;
+
+ if (prk == NULL)
+ return 0;
+
+ if (dh->flags & DH_FLAG_CACHE_MONT_P) {
+ mont = BN_MONT_CTX_set_locked(&dh->method_mont_p,
+ dh->lock, dh->params.p, ctx);
+ if (mont == NULL)
+ goto err;
+ }
+ BN_with_flags(prk, priv_key, BN_FLG_CONSTTIME);
+
+ /* pub_key = g^priv_key mod p */
+ if (!dh->meth->bn_mod_exp(dh, pub_key, dh->params.g, prk, dh->params.p,
+ ctx, mont))
+ goto err;
+ ret = 1;
+err:
+ BN_clear_free(prk);
+ return ret;
+}
+