summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoel Sing <jsing@cvs.openbsd.org>2023-01-21 09:21:12 +0000
committerJoel Sing <jsing@cvs.openbsd.org>2023-01-21 09:21:12 +0000
commit35975edb5c0b7835aabccd3cfc4cca172cd264cf (patch)
tree7eec2725f86ab34cd516106e8bd4f356eb5c4710
parent23959297239bbe36ffcc5cba59d0755ee699a727 (diff)
Reorder functions and drop unnessary static prototypes.
No functional change.
-rw-r--r--lib/libcrypto/bn/bn_gcd.c735
1 files changed, 363 insertions, 372 deletions
diff --git a/lib/libcrypto/bn/bn_gcd.c b/lib/libcrypto/bn/bn_gcd.c
index 0d8bdf07ebd..84c3d858500 100644
--- a/lib/libcrypto/bn/bn_gcd.c
+++ b/lib/libcrypto/bn/bn_gcd.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: bn_gcd.c,v 1.20 2022/12/26 07:18:51 jmc Exp $ */
+/* $OpenBSD: bn_gcd.c,v 1.21 2023/01/21 09:21:11 jsing Exp $ */
/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
* All rights reserved.
*
@@ -113,63 +113,6 @@
#include "bn_local.h"
-static BIGNUM *euclid(BIGNUM *a, BIGNUM *b);
-static BIGNUM *BN_gcd_no_branch(BIGNUM *in, const BIGNUM *a, const BIGNUM *n,
- BN_CTX *ctx);
-
-int
-BN_gcd(BIGNUM *r, const BIGNUM *in_a, const BIGNUM *in_b, BN_CTX *ctx)
-{
- BIGNUM *a, *b, *t;
- int ret = 0;
-
-
- BN_CTX_start(ctx);
- if ((a = BN_CTX_get(ctx)) == NULL)
- goto err;
- if ((b = BN_CTX_get(ctx)) == NULL)
- goto err;
-
- if (BN_copy(a, in_a) == NULL)
- goto err;
- if (BN_copy(b, in_b) == NULL)
- goto err;
- a->neg = 0;
- b->neg = 0;
-
- if (BN_cmp(a, b) < 0) {
- t = a;
- a = b;
- b = t;
- }
- t = euclid(a, b);
- if (t == NULL)
- goto err;
-
- if (BN_copy(r, t) == NULL)
- goto err;
- ret = 1;
-
-err:
- BN_CTX_end(ctx);
- return (ret);
-}
-
-int
-BN_gcd_ct(BIGNUM *r, const BIGNUM *in_a, const BIGNUM *in_b, BN_CTX *ctx)
-{
- if (BN_gcd_no_branch(r, in_a, in_b, ctx) == NULL)
- return 0;
- return 1;
-}
-
-int
-BN_gcd_nonct(BIGNUM *r, const BIGNUM *in_a, const BIGNUM *in_b, BN_CTX *ctx)
-{
- return BN_gcd(r, in_a, in_b, ctx);
-}
-
-
static BIGNUM *
euclid(BIGNUM *a, BIGNUM *b)
{
@@ -237,11 +180,370 @@ err:
return (NULL);
}
+/*
+ * BN_gcd_no_branch is a special version of BN_mod_inverse_no_branch.
+ * that returns the GCD.
+ */
+static BIGNUM *
+BN_gcd_no_branch(BIGNUM *in, const BIGNUM *a, const BIGNUM *n,
+ BN_CTX *ctx)
+{
+ BIGNUM *A, *B, *X, *Y, *M, *D, *T, *R = NULL;
+ BIGNUM local_A, local_B;
+ BIGNUM *pA, *pB;
+ BIGNUM *ret = NULL;
+ int sign;
-/* solves ax == 1 (mod n) */
-static BIGNUM *BN_mod_inverse_no_branch(BIGNUM *in, const BIGNUM *a,
- const BIGNUM *n, BN_CTX *ctx);
+ if (in == NULL)
+ goto err;
+ R = in;
+
+ BN_init(&local_A);
+ BN_init(&local_B);
+
+
+ BN_CTX_start(ctx);
+ if ((A = BN_CTX_get(ctx)) == NULL)
+ goto err;
+ if ((B = BN_CTX_get(ctx)) == NULL)
+ goto err;
+ if ((X = BN_CTX_get(ctx)) == NULL)
+ goto err;
+ if ((D = BN_CTX_get(ctx)) == NULL)
+ goto err;
+ if ((M = BN_CTX_get(ctx)) == NULL)
+ goto err;
+ if ((Y = BN_CTX_get(ctx)) == NULL)
+ goto err;
+ if ((T = BN_CTX_get(ctx)) == NULL)
+ goto err;
+
+ if (!BN_one(X))
+ goto err;
+ BN_zero(Y);
+ if (BN_copy(B, a) == NULL)
+ goto err;
+ if (BN_copy(A, n) == NULL)
+ goto err;
+ A->neg = 0;
+
+ if (B->neg || (BN_ucmp(B, A) >= 0)) {
+ /*
+ * Turn BN_FLG_CONSTTIME flag on, so that when BN_div is invoked,
+ * BN_div_no_branch will be called eventually.
+ */
+ pB = &local_B;
+ /* BN_init() done at the top of the function. */
+ BN_with_flags(pB, B, BN_FLG_CONSTTIME);
+ if (!BN_nnmod(B, pB, A, ctx))
+ goto err;
+ }
+ sign = -1;
+ /* From B = a mod |n|, A = |n| it follows that
+ *
+ * 0 <= B < A,
+ * -sign*X*a == B (mod |n|),
+ * sign*Y*a == A (mod |n|).
+ */
+
+ while (!BN_is_zero(B)) {
+ BIGNUM *tmp;
+
+ /*
+ * 0 < B < A,
+ * (*) -sign*X*a == B (mod |n|),
+ * sign*Y*a == A (mod |n|)
+ */
+
+ /*
+ * Turn BN_FLG_CONSTTIME flag on, so that when BN_div is invoked,
+ * BN_div_no_branch will be called eventually.
+ */
+ pA = &local_A;
+ /* BN_init() done at the top of the function. */
+ BN_with_flags(pA, A, BN_FLG_CONSTTIME);
+
+ /* (D, M) := (A/B, A%B) ... */
+ if (!BN_div_ct(D, M, pA, B, ctx))
+ goto err;
+
+ /* Now
+ * A = D*B + M;
+ * thus we have
+ * (**) sign*Y*a == D*B + M (mod |n|).
+ */
+ tmp = A; /* keep the BIGNUM object, the value does not matter */
+
+ /* (A, B) := (B, A mod B) ... */
+ A = B;
+ B = M;
+ /* ... so we have 0 <= B < A again */
+
+ /* Since the former M is now B and the former B is now A,
+ * (**) translates into
+ * sign*Y*a == D*A + B (mod |n|),
+ * i.e.
+ * sign*Y*a - D*A == B (mod |n|).
+ * Similarly, (*) translates into
+ * -sign*X*a == A (mod |n|).
+ *
+ * Thus,
+ * sign*Y*a + D*sign*X*a == B (mod |n|),
+ * i.e.
+ * sign*(Y + D*X)*a == B (mod |n|).
+ *
+ * So if we set (X, Y, sign) := (Y + D*X, X, -sign), we arrive back at
+ * -sign*X*a == B (mod |n|),
+ * sign*Y*a == A (mod |n|).
+ * Note that X and Y stay non-negative all the time.
+ */
+
+ if (!BN_mul(tmp, D, X, ctx))
+ goto err;
+ if (!BN_add(tmp, tmp, Y))
+ goto err;
+
+ M = Y; /* keep the BIGNUM object, the value does not matter */
+ Y = X;
+ X = tmp;
+ sign = -sign;
+ }
+
+ /*
+ * The while loop (Euclid's algorithm) ends when
+ * A == gcd(a,n);
+ */
+
+ if (!BN_copy(R, A))
+ goto err;
+ ret = R;
+err:
+ if ((ret == NULL) && (in == NULL))
+ BN_free(R);
+ BN_CTX_end(ctx);
+ return (ret);
+}
+
+int
+BN_gcd(BIGNUM *r, const BIGNUM *in_a, const BIGNUM *in_b, BN_CTX *ctx)
+{
+ BIGNUM *a, *b, *t;
+ int ret = 0;
+
+
+ BN_CTX_start(ctx);
+ if ((a = BN_CTX_get(ctx)) == NULL)
+ goto err;
+ if ((b = BN_CTX_get(ctx)) == NULL)
+ goto err;
+
+ if (BN_copy(a, in_a) == NULL)
+ goto err;
+ if (BN_copy(b, in_b) == NULL)
+ goto err;
+ a->neg = 0;
+ b->neg = 0;
+
+ if (BN_cmp(a, b) < 0) {
+ t = a;
+ a = b;
+ b = t;
+ }
+ t = euclid(a, b);
+ if (t == NULL)
+ goto err;
+
+ if (BN_copy(r, t) == NULL)
+ goto err;
+ ret = 1;
+
+err:
+ BN_CTX_end(ctx);
+ return (ret);
+}
+
+int
+BN_gcd_ct(BIGNUM *r, const BIGNUM *in_a, const BIGNUM *in_b, BN_CTX *ctx)
+{
+ if (BN_gcd_no_branch(r, in_a, in_b, ctx) == NULL)
+ return 0;
+ return 1;
+}
+
+int
+BN_gcd_nonct(BIGNUM *r, const BIGNUM *in_a, const BIGNUM *in_b, BN_CTX *ctx)
+{
+ return BN_gcd(r, in_a, in_b, ctx);
+}
+
+/* BN_mod_inverse_no_branch is a special version of BN_mod_inverse.
+ * It does not contain branches that may leak sensitive information.
+ */
+static BIGNUM *
+BN_mod_inverse_no_branch(BIGNUM *in, const BIGNUM *a, const BIGNUM *n,
+ BN_CTX *ctx)
+{
+ BIGNUM *A, *B, *X, *Y, *M, *D, *T, *R = NULL;
+ BIGNUM local_A, local_B;
+ BIGNUM *pA, *pB;
+ BIGNUM *ret = NULL;
+ int sign;
+
+
+ BN_init(&local_A);
+ BN_init(&local_B);
+
+ BN_CTX_start(ctx);
+ if ((A = BN_CTX_get(ctx)) == NULL)
+ goto err;
+ if ((B = BN_CTX_get(ctx)) == NULL)
+ goto err;
+ if ((X = BN_CTX_get(ctx)) == NULL)
+ goto err;
+ if ((D = BN_CTX_get(ctx)) == NULL)
+ goto err;
+ if ((M = BN_CTX_get(ctx)) == NULL)
+ goto err;
+ if ((Y = BN_CTX_get(ctx)) == NULL)
+ goto err;
+ if ((T = BN_CTX_get(ctx)) == NULL)
+ goto err;
+
+ if (in == NULL)
+ R = BN_new();
+ else
+ R = in;
+ if (R == NULL)
+ goto err;
+
+ if (!BN_one(X))
+ goto err;
+ BN_zero(Y);
+ if (BN_copy(B, a) == NULL)
+ goto err;
+ if (BN_copy(A, n) == NULL)
+ goto err;
+ A->neg = 0;
+
+ if (B->neg || (BN_ucmp(B, A) >= 0)) {
+ /*
+ * Turn BN_FLG_CONSTTIME flag on, so that when BN_div is invoked,
+ * BN_div_no_branch will be called eventually.
+ */
+ pB = &local_B;
+ /* BN_init() done at the top of the function. */
+ BN_with_flags(pB, B, BN_FLG_CONSTTIME);
+ if (!BN_nnmod(B, pB, A, ctx))
+ goto err;
+ }
+ sign = -1;
+ /* From B = a mod |n|, A = |n| it follows that
+ *
+ * 0 <= B < A,
+ * -sign*X*a == B (mod |n|),
+ * sign*Y*a == A (mod |n|).
+ */
+
+ while (!BN_is_zero(B)) {
+ BIGNUM *tmp;
+
+ /*
+ * 0 < B < A,
+ * (*) -sign*X*a == B (mod |n|),
+ * sign*Y*a == A (mod |n|)
+ */
+
+ /*
+ * Turn BN_FLG_CONSTTIME flag on, so that when BN_div is invoked,
+ * BN_div_no_branch will be called eventually.
+ */
+ pA = &local_A;
+ /* BN_init() done at the top of the function. */
+ BN_with_flags(pA, A, BN_FLG_CONSTTIME);
+
+ /* (D, M) := (A/B, A%B) ... */
+ if (!BN_div_ct(D, M, pA, B, ctx))
+ goto err;
+
+ /* Now
+ * A = D*B + M;
+ * thus we have
+ * (**) sign*Y*a == D*B + M (mod |n|).
+ */
+ tmp = A; /* keep the BIGNUM object, the value does not matter */
+
+ /* (A, B) := (B, A mod B) ... */
+ A = B;
+ B = M;
+ /* ... so we have 0 <= B < A again */
+
+ /* Since the former M is now B and the former B is now A,
+ * (**) translates into
+ * sign*Y*a == D*A + B (mod |n|),
+ * i.e.
+ * sign*Y*a - D*A == B (mod |n|).
+ * Similarly, (*) translates into
+ * -sign*X*a == A (mod |n|).
+ *
+ * Thus,
+ * sign*Y*a + D*sign*X*a == B (mod |n|),
+ * i.e.
+ * sign*(Y + D*X)*a == B (mod |n|).
+ *
+ * So if we set (X, Y, sign) := (Y + D*X, X, -sign), we arrive back at
+ * -sign*X*a == B (mod |n|),
+ * sign*Y*a == A (mod |n|).
+ * Note that X and Y stay non-negative all the time.
+ */
+
+ if (!BN_mul(tmp, D, X, ctx))
+ goto err;
+ if (!BN_add(tmp, tmp, Y))
+ goto err;
+
+ M = Y; /* keep the BIGNUM object, the value does not matter */
+ Y = X;
+ X = tmp;
+ sign = -sign;
+ }
+
+ /*
+ * The while loop (Euclid's algorithm) ends when
+ * A == gcd(a,n);
+ * we have
+ * sign*Y*a == A (mod |n|),
+ * where Y is non-negative.
+ */
+
+ if (sign < 0) {
+ if (!BN_sub(Y, n, Y))
+ goto err;
+ }
+ /* Now Y*a == A (mod |n|). */
+ if (BN_is_one(A)) {
+ /* Y*a == 1 (mod |n|) */
+ if (!Y->neg && BN_ucmp(Y, n) < 0) {
+ if (!BN_copy(R, Y))
+ goto err;
+ } else {
+ if (!BN_nnmod(R, Y, n, ctx))
+ goto err;
+ }
+ } else {
+ BNerror(BN_R_NO_INVERSE);
+ goto err;
+ }
+ ret = R;
+
+err:
+ if ((ret == NULL) && (in == NULL))
+ BN_free(R);
+ BN_CTX_end(ctx);
+ return (ret);
+}
+
+/* solves ax == 1 (mod n) */
static BIGNUM *
BN_mod_inverse_internal(BIGNUM *in, const BIGNUM *a, const BIGNUM *n, BN_CTX *ctx,
int ct)
@@ -551,314 +853,3 @@ BN_mod_inverse_ct(BIGNUM *in, const BIGNUM *a, const BIGNUM *n, BN_CTX *ctx)
{
return BN_mod_inverse_internal(in, a, n, ctx, 1);
}
-
-/* BN_mod_inverse_no_branch is a special version of BN_mod_inverse.
- * It does not contain branches that may leak sensitive information.
- */
-static BIGNUM *
-BN_mod_inverse_no_branch(BIGNUM *in, const BIGNUM *a, const BIGNUM *n,
- BN_CTX *ctx)
-{
- BIGNUM *A, *B, *X, *Y, *M, *D, *T, *R = NULL;
- BIGNUM local_A, local_B;
- BIGNUM *pA, *pB;
- BIGNUM *ret = NULL;
- int sign;
-
-
- BN_init(&local_A);
- BN_init(&local_B);
-
- BN_CTX_start(ctx);
- if ((A = BN_CTX_get(ctx)) == NULL)
- goto err;
- if ((B = BN_CTX_get(ctx)) == NULL)
- goto err;
- if ((X = BN_CTX_get(ctx)) == NULL)
- goto err;
- if ((D = BN_CTX_get(ctx)) == NULL)
- goto err;
- if ((M = BN_CTX_get(ctx)) == NULL)
- goto err;
- if ((Y = BN_CTX_get(ctx)) == NULL)
- goto err;
- if ((T = BN_CTX_get(ctx)) == NULL)
- goto err;
-
- if (in == NULL)
- R = BN_new();
- else
- R = in;
- if (R == NULL)
- goto err;
-
- if (!BN_one(X))
- goto err;
- BN_zero(Y);
- if (BN_copy(B, a) == NULL)
- goto err;
- if (BN_copy(A, n) == NULL)
- goto err;
- A->neg = 0;
-
- if (B->neg || (BN_ucmp(B, A) >= 0)) {
- /*
- * Turn BN_FLG_CONSTTIME flag on, so that when BN_div is invoked,
- * BN_div_no_branch will be called eventually.
- */
- pB = &local_B;
- /* BN_init() done at the top of the function. */
- BN_with_flags(pB, B, BN_FLG_CONSTTIME);
- if (!BN_nnmod(B, pB, A, ctx))
- goto err;
- }
- sign = -1;
- /* From B = a mod |n|, A = |n| it follows that
- *
- * 0 <= B < A,
- * -sign*X*a == B (mod |n|),
- * sign*Y*a == A (mod |n|).
- */
-
- while (!BN_is_zero(B)) {
- BIGNUM *tmp;
-
- /*
- * 0 < B < A,
- * (*) -sign*X*a == B (mod |n|),
- * sign*Y*a == A (mod |n|)
- */
-
- /*
- * Turn BN_FLG_CONSTTIME flag on, so that when BN_div is invoked,
- * BN_div_no_branch will be called eventually.
- */
- pA = &local_A;
- /* BN_init() done at the top of the function. */
- BN_with_flags(pA, A, BN_FLG_CONSTTIME);
-
- /* (D, M) := (A/B, A%B) ... */
- if (!BN_div_ct(D, M, pA, B, ctx))
- goto err;
-
- /* Now
- * A = D*B + M;
- * thus we have
- * (**) sign*Y*a == D*B + M (mod |n|).
- */
- tmp = A; /* keep the BIGNUM object, the value does not matter */
-
- /* (A, B) := (B, A mod B) ... */
- A = B;
- B = M;
- /* ... so we have 0 <= B < A again */
-
- /* Since the former M is now B and the former B is now A,
- * (**) translates into
- * sign*Y*a == D*A + B (mod |n|),
- * i.e.
- * sign*Y*a - D*A == B (mod |n|).
- * Similarly, (*) translates into
- * -sign*X*a == A (mod |n|).
- *
- * Thus,
- * sign*Y*a + D*sign*X*a == B (mod |n|),
- * i.e.
- * sign*(Y + D*X)*a == B (mod |n|).
- *
- * So if we set (X, Y, sign) := (Y + D*X, X, -sign), we arrive back at
- * -sign*X*a == B (mod |n|),
- * sign*Y*a == A (mod |n|).
- * Note that X and Y stay non-negative all the time.
- */
-
- if (!BN_mul(tmp, D, X, ctx))
- goto err;
- if (!BN_add(tmp, tmp, Y))
- goto err;
-
- M = Y; /* keep the BIGNUM object, the value does not matter */
- Y = X;
- X = tmp;
- sign = -sign;
- }
-
- /*
- * The while loop (Euclid's algorithm) ends when
- * A == gcd(a,n);
- * we have
- * sign*Y*a == A (mod |n|),
- * where Y is non-negative.
- */
-
- if (sign < 0) {
- if (!BN_sub(Y, n, Y))
- goto err;
- }
- /* Now Y*a == A (mod |n|). */
-
- if (BN_is_one(A)) {
- /* Y*a == 1 (mod |n|) */
- if (!Y->neg && BN_ucmp(Y, n) < 0) {
- if (!BN_copy(R, Y))
- goto err;
- } else {
- if (!BN_nnmod(R, Y, n, ctx))
- goto err;
- }
- } else {
- BNerror(BN_R_NO_INVERSE);
- goto err;
- }
- ret = R;
-
-err:
- if ((ret == NULL) && (in == NULL))
- BN_free(R);
- BN_CTX_end(ctx);
- return (ret);
-}
-
-/*
- * BN_gcd_no_branch is a special version of BN_mod_inverse_no_branch.
- * that returns the GCD.
- */
-static BIGNUM *
-BN_gcd_no_branch(BIGNUM *in, const BIGNUM *a, const BIGNUM *n,
- BN_CTX *ctx)
-{
- BIGNUM *A, *B, *X, *Y, *M, *D, *T, *R = NULL;
- BIGNUM local_A, local_B;
- BIGNUM *pA, *pB;
- BIGNUM *ret = NULL;
- int sign;
-
- if (in == NULL)
- goto err;
- R = in;
-
- BN_init(&local_A);
- BN_init(&local_B);
-
-
- BN_CTX_start(ctx);
- if ((A = BN_CTX_get(ctx)) == NULL)
- goto err;
- if ((B = BN_CTX_get(ctx)) == NULL)
- goto err;
- if ((X = BN_CTX_get(ctx)) == NULL)
- goto err;
- if ((D = BN_CTX_get(ctx)) == NULL)
- goto err;
- if ((M = BN_CTX_get(ctx)) == NULL)
- goto err;
- if ((Y = BN_CTX_get(ctx)) == NULL)
- goto err;
- if ((T = BN_CTX_get(ctx)) == NULL)
- goto err;
-
- if (!BN_one(X))
- goto err;
- BN_zero(Y);
- if (BN_copy(B, a) == NULL)
- goto err;
- if (BN_copy(A, n) == NULL)
- goto err;
- A->neg = 0;
-
- if (B->neg || (BN_ucmp(B, A) >= 0)) {
- /*
- * Turn BN_FLG_CONSTTIME flag on, so that when BN_div is invoked,
- * BN_div_no_branch will be called eventually.
- */
- pB = &local_B;
- /* BN_init() done at the top of the function. */
- BN_with_flags(pB, B, BN_FLG_CONSTTIME);
- if (!BN_nnmod(B, pB, A, ctx))
- goto err;
- }
- sign = -1;
- /* From B = a mod |n|, A = |n| it follows that
- *
- * 0 <= B < A,
- * -sign*X*a == B (mod |n|),
- * sign*Y*a == A (mod |n|).
- */
-
- while (!BN_is_zero(B)) {
- BIGNUM *tmp;
-
- /*
- * 0 < B < A,
- * (*) -sign*X*a == B (mod |n|),
- * sign*Y*a == A (mod |n|)
- */
-
- /*
- * Turn BN_FLG_CONSTTIME flag on, so that when BN_div is invoked,
- * BN_div_no_branch will be called eventually.
- */
- pA = &local_A;
- /* BN_init() done at the top of the function. */
- BN_with_flags(pA, A, BN_FLG_CONSTTIME);
-
- /* (D, M) := (A/B, A%B) ... */
- if (!BN_div_ct(D, M, pA, B, ctx))
- goto err;
-
- /* Now
- * A = D*B + M;
- * thus we have
- * (**) sign*Y*a == D*B + M (mod |n|).
- */
- tmp = A; /* keep the BIGNUM object, the value does not matter */
-
- /* (A, B) := (B, A mod B) ... */
- A = B;
- B = M;
- /* ... so we have 0 <= B < A again */
-
- /* Since the former M is now B and the former B is now A,
- * (**) translates into
- * sign*Y*a == D*A + B (mod |n|),
- * i.e.
- * sign*Y*a - D*A == B (mod |n|).
- * Similarly, (*) translates into
- * -sign*X*a == A (mod |n|).
- *
- * Thus,
- * sign*Y*a + D*sign*X*a == B (mod |n|),
- * i.e.
- * sign*(Y + D*X)*a == B (mod |n|).
- *
- * So if we set (X, Y, sign) := (Y + D*X, X, -sign), we arrive back at
- * -sign*X*a == B (mod |n|),
- * sign*Y*a == A (mod |n|).
- * Note that X and Y stay non-negative all the time.
- */
-
- if (!BN_mul(tmp, D, X, ctx))
- goto err;
- if (!BN_add(tmp, tmp, Y))
- goto err;
-
- M = Y; /* keep the BIGNUM object, the value does not matter */
- Y = X;
- X = tmp;
- sign = -sign;
- }
-
- /*
- * The while loop (Euclid's algorithm) ends when
- * A == gcd(a,n);
- */
-
- if (!BN_copy(R, A))
- goto err;
- ret = R;
-err:
- if ((ret == NULL) && (in == NULL))
- BN_free(R);
- BN_CTX_end(ctx);
- return (ret);
-}