[RFC PATCH v1 04/13] crypto: Add DecoyAuth encoding and interpolation support
Jeff Hansen
x at jeffhansen.com
Fri Sep 11 12:20:01 PDT 2026
Add reversible point encoding and paired polynomial interpolation for
DecoyAuth while keeping OpenSSL representations behind the generic
crypto API.
Signed-off-by: Jeff Hansen <x at jeffhansen.com>
---
src/crypto/crypto.h | 70 ++++
src/crypto/crypto_openssl.c | 637 ++++++++++++++++++++++++++++++++++++
2 files changed, 707 insertions(+)
diff --git a/src/crypto/crypto.h b/src/crypto/crypto.h
index e6bc7bac3..3db2fe80e 100644
--- a/src/crypto/crypto.h
+++ b/src/crypto/crypto.h
@@ -852,6 +852,19 @@ int crypto_ec_point_to_bin(struct crypto_ec *e,
struct crypto_ec_point * crypto_ec_point_from_bin(struct crypto_ec *e,
const u8 *val);
+#ifdef CONFIG_SAE_DECOYAUTH
+/**
+ * crypto_ec_point_copy - Copy an EC point
+ * @e: EC context from crypto_ec_init()
+ * @src: Source EC point
+ * @dst: Destination EC point
+ * Returns: 0 on success, -1 on failure
+ */
+int crypto_ec_point_copy(struct crypto_ec *e,
+ const struct crypto_ec_point *src,
+ struct crypto_ec_point *dst);
+#endif /* CONFIG_SAE_DECOYAUTH */
+
/**
* crypto_ec_point_add - c = a + b
* @e: EC context from crypto_ec_init()
@@ -1386,4 +1399,61 @@ struct wpabuf * hpke_base_open(enum hpke_kem_id kem_id,
*/
void crypto_unload(void);
+#ifdef CONFIG_SAE_DECOYAUTH
+/**
+ * crypto_point_to_values - Encode an EC point as two field elements
+ * @point: EC point
+ * @ec: EC context
+ * Returns: An allocated two-element array, or %NULL on failure
+ *
+ * The caller is responsible for freeing both elements and the array.
+ */
+struct crypto_bignum **
+crypto_point_to_values(struct crypto_ec_point *point, struct crypto_ec *ec);
+
+/**
+ * crypto_values_to_point - Decode two field elements as an EC point
+ * @values: Two-element array from crypto_point_to_values()
+ * @ec: EC context
+ * Returns: An allocated EC point, or %NULL on failure
+ */
+struct crypto_ec_point *
+crypto_values_to_point(struct crypto_bignum **values, struct crypto_ec *ec);
+
+/**
+ * crypto_interpolate_pair - Interpolate two polynomials at common x values
+ * @x_values: Interpolation x coordinates
+ * @first_values: Values for the first polynomial
+ * @second_values: Values for the second polynomial
+ * @num_elements: Number of values in each input array
+ * @ec: EC context that defines the field
+ * @first_coefficients: Returned coefficients for the first polynomial
+ * @second_coefficients: Returned coefficients for the second polynomial
+ * Returns: 0 on success, -1 on failure
+ *
+ * The returned arrays contain @num_elements allocated bignums. The caller is
+ * responsible for freeing the bignums and arrays.
+ */
+int crypto_interpolate_pair(struct crypto_bignum **x_values,
+ struct crypto_bignum **first_values,
+ struct crypto_bignum **second_values,
+ int num_elements, struct crypto_ec *ec,
+ struct crypto_bignum ***first_coefficients,
+ struct crypto_bignum ***second_coefficients);
+
+
+/**
+ * crypto_evaluate - Evaluate a polynomial over an EC field
+ * @poly: Polynomial coefficients, least-significant coefficient first
+ * @x: Evaluation point
+ * @num_elements: Number of coefficients in @poly
+ * @ec: EC context that defines the field
+ * Returns: An allocated bignum containing the result, or %NULL on failure
+ */
+struct crypto_bignum * crypto_evaluate(struct crypto_bignum **poly,
+ struct crypto_bignum *x,
+ int num_elements,
+ struct crypto_ec *ec);
+#endif /* CONFIG_SAE_DECOYAUTH */
+
#endif /* CRYPTO_H */
diff --git a/src/crypto/crypto_openssl.c b/src/crypto/crypto_openssl.c
index a6bfc7a7c..2a9f6f77b 100644
--- a/src/crypto/crypto_openssl.c
+++ b/src/crypto/crypto_openssl.c
@@ -2643,6 +2643,20 @@ struct crypto_ec_point * crypto_ec_point_from_bin(struct crypto_ec *e,
}
+#ifdef CONFIG_SAE_DECOYAUTH
+int crypto_ec_point_copy(struct crypto_ec *e,
+ const struct crypto_ec_point *src,
+ struct crypto_ec_point *dst)
+{
+ (void) e;
+ if (TEST_FAIL())
+ return -1;
+ return EC_POINT_copy((EC_POINT *) dst, (const EC_POINT *) src) == 1 ?
+ 0 : -1;
+}
+#endif /* CONFIG_SAE_DECOYAUTH */
+
+
int crypto_ec_point_add(struct crypto_ec *e, const struct crypto_ec_point *a,
const struct crypto_ec_point *b,
struct crypto_ec_point *c)
@@ -5731,3 +5745,626 @@ void crypto_unload(void)
openssl_unload_legacy_provider();
openssl_unload_default_provider();
}
+
+#ifdef CONFIG_SAE_DECOYAUTH
+static BIGNUM * decoyauth_evaluate(BIGNUM **poly, const BIGNUM *x,
+ int num_elements, const BIGNUM *prime,
+ BN_CTX *ctx)
+{
+ BIGNUM *result;
+ int i;
+
+ if (!poly || !x || num_elements <= 0 || !prime || !ctx)
+ return NULL;
+
+ result = BN_dup(poly[num_elements - 1]);
+ if (!result)
+ return NULL;
+ for (i = num_elements - 2; i >= 0; i--) {
+ if (!poly[i] ||
+ !BN_mod_mul(result, result, x, prime, ctx) ||
+ !BN_mod_add(result, result, poly[i], prime, ctx)) {
+ BN_clear_free(result);
+ return NULL;
+ }
+ }
+
+ return result;
+}
+
+static BIGNUM * decoyauth_random_bignum(const BIGNUM *prime)
+{
+ BIGNUM *value;
+
+ value = BN_new();
+ if (!value || !BN_rand_range(value, prime)) {
+ BN_clear_free(value);
+ return NULL;
+ }
+
+ /* BN_rand_range() includes zero, while this encoding does not. */
+ if (BN_is_zero(value) && !BN_one(value)) {
+ BN_clear_free(value);
+ return NULL;
+ }
+
+ return value;
+}
+
+
+static int decoyauth_random_branch(void)
+{
+ u8 value;
+
+ if (RAND_bytes(&value, sizeof(value)) != 1)
+ return -1;
+
+ return value % 4;
+}
+
+
+static bool decoyauth_u_valid(const BIGNUM *u, const BIGNUM *prime)
+{
+ BIGNUM *minus_one;
+ bool valid;
+
+ minus_one = BN_dup(prime);
+ if (!minus_one || !BN_sub_word(minus_one, 1)) {
+ BN_clear_free(minus_one);
+ return false;
+ }
+
+ valid = !BN_is_zero(u) && !BN_is_one(u) &&
+ BN_cmp(u, minus_one) != 0;
+ BN_clear_free(minus_one);
+ return valid;
+}
+
+
+static BIGNUM * decoyauth_x0(const BIGNUM *u, const BIGNUM *a,
+ const BIGNUM *b, const BIGNUM *prime)
+{
+ BIGNUM *result = NULL;
+ BIGNUM *u2, *u4, *denominator, *inverse, *factor, *a_inverse;
+ BN_CTX *ctx;
+
+ ctx = BN_CTX_new();
+ if (!ctx)
+ return NULL;
+ BN_CTX_start(ctx);
+ u2 = BN_CTX_get(ctx);
+ u4 = BN_CTX_get(ctx);
+ denominator = BN_CTX_get(ctx);
+ inverse = BN_CTX_get(ctx);
+ factor = BN_CTX_get(ctx);
+ a_inverse = BN_CTX_get(ctx);
+ result = BN_new();
+ if (!a_inverse || !result ||
+ !BN_mod_sqr(u2, u, prime, ctx) ||
+ !BN_mod_sqr(u4, u2, prime, ctx) ||
+ !BN_mod_sub(denominator, u4, u2, prime, ctx) ||
+ !BN_mod_inverse(inverse, denominator, prime, ctx) ||
+ !BN_add_word(inverse, 1) ||
+ !BN_nnmod(inverse, inverse, prime, ctx) ||
+ !BN_mod_inverse(a_inverse, a, prime, ctx) ||
+ !BN_mod_mul(factor, b, a_inverse, prime, ctx) ||
+ !BN_mod_mul(result, factor, inverse, prime, ctx) ||
+ !BN_mod_sub(result, prime, result, prime, ctx)) {
+ BN_clear_free(result);
+ result = NULL;
+ }
+ BN_CTX_end(ctx);
+ BN_CTX_free(ctx);
+ return result;
+}
+
+
+static BIGNUM * decoyauth_x1(const BIGNUM *u, const BIGNUM *a,
+ const BIGNUM *b, const BIGNUM *prime)
+{
+ BIGNUM *result = NULL, *x0, *u2;
+ BN_CTX *ctx;
+
+ ctx = BN_CTX_new();
+ x0 = decoyauth_x0(u, a, b, prime);
+ if (!ctx || !x0)
+ goto out;
+ BN_CTX_start(ctx);
+ u2 = BN_CTX_get(ctx);
+ result = BN_new();
+ if (!u2 || !result || !BN_mod_sqr(u2, u, prime, ctx) ||
+ !BN_mod_mul(result, u2, x0, prime, ctx) ||
+ !BN_mod_sub(result, prime, result, prime, ctx)) {
+ BN_clear_free(result);
+ result = NULL;
+ }
+ BN_CTX_end(ctx);
+out:
+ BN_clear_free(x0);
+ BN_CTX_free(ctx);
+ return result;
+}
+
+
+static BIGNUM * decoyauth_curve_rhs(const BIGNUM *x, const BIGNUM *a,
+ const BIGNUM *b, const BIGNUM *prime)
+{
+ BIGNUM *result = NULL, *tmp;
+ BN_CTX *ctx;
+
+ ctx = BN_CTX_new();
+ if (!ctx)
+ return NULL;
+ BN_CTX_start(ctx);
+ tmp = BN_CTX_get(ctx);
+ result = BN_new();
+ if (!tmp || !result || !BN_mod_sqr(result, x, prime, ctx) ||
+ !BN_mod_mul(result, result, x, prime, ctx) ||
+ !BN_mod_mul(tmp, a, x, prime, ctx) ||
+ !BN_mod_add(result, result, tmp, prime, ctx) ||
+ !BN_mod_add(result, result, b, prime, ctx)) {
+ BN_clear_free(result);
+ result = NULL;
+ }
+ BN_CTX_end(ctx);
+ BN_CTX_free(ctx);
+ return result;
+}
+
+
+static EC_POINT * decoyauth_map_to_point(const BIGNUM *u, EC_GROUP *group,
+ const BIGNUM *a, const BIGNUM *b,
+ const BIGNUM *prime)
+{
+ EC_POINT *result = NULL;
+ BIGNUM *x = NULL, *rhs = NULL, *y = NULL;
+ BN_CTX *ctx;
+
+ ctx = BN_CTX_new();
+ result = EC_POINT_new(group);
+ if (!ctx || !result)
+ goto fail;
+ if (!decoyauth_u_valid(u, prime)) {
+ if (EC_POINT_set_to_infinity(group, result) != 1)
+ goto fail;
+ goto out;
+ }
+
+ x = decoyauth_x0(u, a, b, prime);
+ rhs = x ? decoyauth_curve_rhs(x, a, b, prime) : NULL;
+ y = BN_new();
+ if (!rhs || !y)
+ goto fail;
+ if (BN_mod_sqrt(y, rhs, prime, ctx)) {
+ if (EC_POINT_set_affine_coordinates(group, result, x, y,
+ ctx) != 1)
+ goto fail;
+ goto out;
+ }
+ BN_clear_free(x);
+ BN_clear_free(rhs);
+ x = decoyauth_x1(u, a, b, prime);
+ rhs = x ? decoyauth_curve_rhs(x, a, b, prime) : NULL;
+ if (!rhs || !BN_mod_sqrt(y, rhs, prime, ctx) ||
+ !BN_mod_sub(y, prime, y, prime, ctx) ||
+ EC_POINT_set_affine_coordinates(group, result, x, y, ctx) != 1)
+ goto fail;
+ goto out;
+
+fail:
+ EC_POINT_free(result);
+ result = NULL;
+out:
+ BN_clear_free(x);
+ BN_clear_free(rhs);
+ BN_clear_free(y);
+ BN_CTX_free(ctx);
+ return result;
+}
+
+
+static BIGNUM * decoyauth_point_to_v(const EC_POINT *q, int branch,
+ const EC_GROUP *group, const BIGNUM *a,
+ const BIGNUM *b, const BIGNUM *prime)
+{
+ BIGNUM *result = NULL;
+ BIGNUM *x, *y, *b_inverse, *omega, *root, *tmp, *multiplier;
+ BN_CTX *ctx;
+ bool y_is_square;
+
+ if (branch < 0 || branch > 3)
+ return NULL;
+ ctx = BN_CTX_new();
+ if (!ctx)
+ return NULL;
+ BN_CTX_start(ctx);
+ x = BN_CTX_get(ctx);
+ y = BN_CTX_get(ctx);
+ b_inverse = BN_CTX_get(ctx);
+ omega = BN_CTX_get(ctx);
+ root = BN_CTX_get(ctx);
+ tmp = BN_CTX_get(ctx);
+ multiplier = BN_CTX_get(ctx);
+ if (!multiplier ||
+ EC_POINT_get_affine_coordinates(group, q, x, y, ctx) != 1 ||
+ !BN_mod_inverse(b_inverse, b, prime, ctx) ||
+ !BN_mod_mul(omega, a, b_inverse, prime, ctx) ||
+ !BN_mod_mul(omega, omega, x, prime, ctx) ||
+ !BN_add_word(omega, 1) || !BN_nnmod(omega, omega, prime, ctx) ||
+ !BN_mod_sqr(root, omega, prime, ctx) ||
+ !BN_mod_lshift1(tmp, omega, prime, ctx) ||
+ !BN_mod_lshift1(tmp, tmp, prime, ctx) ||
+ !BN_mod_sub(root, root, tmp, prime, ctx) ||
+ !BN_mod_sqrt(root, root, prime, ctx))
+ goto out;
+ if (branch > 1 && !BN_mod_sub(root, prime, root, prime, ctx))
+ goto out;
+
+ y_is_square = BN_mod_sqrt(tmp, y, prime, ctx) != NULL;
+ if (y_is_square) {
+ if (!BN_mod_lshift1(multiplier, omega, prime, ctx) ||
+ !BN_mod_inverse(multiplier, multiplier, prime, ctx))
+ goto out;
+ } else {
+ if (!BN_set_word(multiplier, 2) ||
+ !BN_mod_inverse(multiplier, multiplier, prime, ctx))
+ goto out;
+ }
+ if (!BN_mod_add(tmp, omega, root, prime, ctx) ||
+ !BN_mod_mul(tmp, tmp, multiplier, prime, ctx) ||
+ !BN_mod_sqrt(tmp, tmp, prime, ctx))
+ goto out;
+ if (branch == 1 || branch == 3) {
+ if (!BN_mod_sub(tmp, prime, tmp, prime, ctx))
+ goto out;
+ }
+ result = BN_dup(tmp);
+out:
+ BN_CTX_end(ctx);
+ BN_CTX_free(ctx);
+ return result;
+}
+
+
+static BIGNUM ** point_to_values(EC_POINT *point, EC_GROUP *group,
+ BIGNUM *a, BIGNUM *b, BIGNUM *prime)
+{
+ BIGNUM **values;
+ BIGNUM *u, *v;
+ EC_POINT *mapped, *difference;
+ int branch, i;
+
+ if (!point || !group || !a || !b || !prime)
+ return NULL;
+
+ for (i = 0; i < 1000; i++) {
+ u = decoyauth_random_bignum(prime);
+ if (!u || !decoyauth_u_valid(u, prime)) {
+ BN_clear_free(u);
+ continue;
+ }
+
+ mapped = decoyauth_map_to_point(u, group, a, b, prime);
+ difference = EC_POINT_new(group);
+ if (!mapped || !difference ||
+ EC_POINT_invert(group, mapped, NULL) != 1 ||
+ EC_POINT_add(group, difference, point, mapped, NULL) != 1 ||
+ EC_POINT_is_at_infinity(group, difference)) {
+ EC_POINT_free(mapped);
+ EC_POINT_free(difference);
+ BN_clear_free(u);
+ continue;
+ }
+ EC_POINT_free(mapped);
+
+ branch = decoyauth_random_branch();
+ v = branch < 0 ? NULL :
+ decoyauth_point_to_v(difference, branch, group, a, b,
+ prime);
+ EC_POINT_free(difference);
+ if (!v) {
+ BN_clear_free(u);
+ if (branch < 0)
+ return NULL;
+ continue;
+ }
+
+ values = os_malloc(2 * sizeof(*values));
+ if (!values) {
+ BN_clear_free(u);
+ BN_clear_free(v);
+ return NULL;
+ }
+ values[0] = u;
+ values[1] = v;
+ return values;
+ }
+
+ return NULL;
+}
+
+
+static EC_POINT * values_to_point(BIGNUM **encoded_point, EC_GROUP *group,
+ BIGNUM *a, BIGNUM *b, BIGNUM *prime)
+{
+ EC_POINT *f_u = NULL, *f_v = NULL, *result = NULL;
+ BN_CTX *ctx = NULL;
+
+ if (!encoded_point || !encoded_point[0] || !encoded_point[1] ||
+ !group || !a || !b || !prime)
+ return NULL;
+
+ f_u = decoyauth_map_to_point(encoded_point[0], group, a, b, prime);
+ f_v = decoyauth_map_to_point(encoded_point[1], group, a, b, prime);
+ ctx = BN_CTX_new();
+ result = EC_POINT_new(group);
+ if (!f_u || !f_v || !ctx || !result ||
+ EC_POINT_add(group, result, f_u, f_v, ctx) != 1) {
+ EC_POINT_free(result);
+ result = NULL;
+ }
+
+ EC_POINT_free(f_u);
+ EC_POINT_free(f_v);
+ BN_CTX_free(ctx);
+ return result;
+}
+
+struct crypto_bignum **
+crypto_point_to_values(struct crypto_ec_point *point, struct crypto_ec *ec)
+{
+ if (!point || !ec)
+ return NULL;
+ return (struct crypto_bignum **)
+ point_to_values((EC_POINT *) point, ec->group, ec->a, ec->b,
+ ec->prime);
+}
+
+struct crypto_ec_point *
+crypto_values_to_point(struct crypto_bignum **point, struct crypto_ec *ec)
+{
+ BIGNUM *input[2];
+
+ if (!point || !point[0] || !point[1] || !ec)
+ return NULL;
+ input[0] = (BIGNUM *) point[0];
+ input[1] = (BIGNUM *) point[1];
+ return (struct crypto_ec_point *)
+ values_to_point(input, ec->group, ec->a, ec->b, ec->prime);
+}
+
+static void crypto_bignum_vector_free(BIGNUM **values, int count)
+{
+ if (!values)
+ return;
+ for (int i = 0; i < count; i++)
+ BN_clear_free(values[i]);
+ os_free(values);
+}
+
+
+static BIGNUM ** crypto_bignum_vector_alloc(int count)
+{
+ BIGNUM **values;
+
+ values = os_calloc(count, sizeof(*values));
+ if (!values)
+ return NULL;
+ for (int i = 0; i < count; i++) {
+ values[i] = BN_new();
+ if (!values[i]) {
+ crypto_bignum_vector_free(values, count);
+ return NULL;
+ }
+ }
+ return values;
+}
+
+
+static int crypto_interpolation_basis(BIGNUM **x, int count,
+ const BIGNUM *prime, BN_CTX *ctx,
+ BIGNUM ***poly_out,
+ BIGNUM ***weights_out)
+{
+ BIGNUM **poly = NULL, **derivative = NULL;
+ BIGNUM **denominators = NULL, **weights = NULL;
+ BIGNUM *zero = NULL, *tmp = NULL, *inverse = NULL;
+ int ret = -1;
+
+ *poly_out = NULL;
+ *weights_out = NULL;
+ poly = crypto_bignum_vector_alloc(count + 1);
+ derivative = crypto_bignum_vector_alloc(count);
+ denominators = crypto_bignum_vector_alloc(count);
+ weights = crypto_bignum_vector_alloc(count);
+ zero = BN_new();
+ tmp = BN_new();
+ inverse = BN_new();
+ if (!poly || !derivative || !denominators || !weights || !zero ||
+ !tmp || !inverse)
+ goto out;
+
+ /* P(x) = product(x - x_i), with coefficients stored low first. */
+ BN_zero(zero);
+ if (!BN_one(poly[0]))
+ goto out;
+ for (int i = 0; i < count; i++) {
+ for (int j = i + 1; j > 0; j--) {
+ if (!BN_mod_mul(tmp, x[i], poly[j], prime, ctx) ||
+ !BN_mod_sub(poly[j], poly[j - 1], tmp, prime, ctx))
+ goto out;
+ }
+ if (!BN_mod_mul(tmp, x[i], poly[0], prime, ctx) ||
+ !BN_mod_sub(poly[0], zero, tmp, prime, ctx))
+ goto out;
+ }
+
+ for (int i = 1; i <= count; i++) {
+ if (!BN_copy(derivative[i - 1], poly[i]) ||
+ !BN_mul_word(derivative[i - 1], (BN_ULONG) i) ||
+ !BN_nnmod(derivative[i - 1], derivative[i - 1], prime,
+ ctx))
+ goto out;
+ }
+ for (int i = 0; i < count; i++) {
+ if (!BN_copy(denominators[i], derivative[count - 1]))
+ goto out;
+ for (int j = count - 2; j >= 0; j--) {
+ if (!BN_mod_mul(tmp, denominators[i], x[i], prime,
+ ctx) ||
+ !BN_mod_add(denominators[i], tmp, derivative[j],
+ prime, ctx))
+ goto out;
+ }
+ if (BN_is_zero(denominators[i]))
+ goto out;
+ }
+
+ /* Batch-invert P'(x_i), requiring only one modular inversion. */
+ if (!BN_copy(weights[0], denominators[0]))
+ goto out;
+ for (int i = 1; i < count; i++) {
+ if (!BN_mod_mul(weights[i], weights[i - 1], denominators[i],
+ prime, ctx))
+ goto out;
+ }
+ if (!BN_mod_inverse(inverse, weights[count - 1], prime, ctx))
+ goto out;
+ for (int i = count - 1; i >= 0; i--) {
+ if (i > 0) {
+ if (!BN_mod_mul(tmp, inverse, weights[i - 1], prime,
+ ctx))
+ goto out;
+ } else if (!BN_copy(tmp, inverse)) {
+ goto out;
+ }
+ if (i > 0 &&
+ !BN_mod_mul(inverse, inverse, denominators[i], prime, ctx))
+ goto out;
+ if (!BN_copy(weights[i], tmp))
+ goto out;
+ }
+
+ *poly_out = poly;
+ *weights_out = weights;
+ poly = weights = NULL;
+ ret = 0;
+out:
+ crypto_bignum_vector_free(poly, count + 1);
+ crypto_bignum_vector_free(derivative, count);
+ crypto_bignum_vector_free(denominators, count);
+ crypto_bignum_vector_free(weights, count);
+ BN_clear_free(zero);
+ BN_clear_free(tmp);
+ BN_clear_free(inverse);
+ return ret;
+}
+
+
+int crypto_interpolate_pair(struct crypto_bignum **x_values,
+ struct crypto_bignum **first_values,
+ struct crypto_bignum **second_values,
+ int num_elements, struct crypto_ec *ec,
+ struct crypto_bignum ***first_coefficients,
+ struct crypto_bignum ***second_coefficients)
+{
+ BIGNUM **x = (BIGNUM **) x_values;
+ BIGNUM **first = (BIGNUM **) first_values;
+ BIGNUM **second = (BIGNUM **) second_values;
+ BIGNUM **poly = NULL, **weights = NULL;
+ BIGNUM **quotient = NULL, **first_result = NULL;
+ BIGNUM **second_result = NULL;
+ BIGNUM *tmp = NULL;
+ BIGNUM *first_factor = NULL, *second_factor = NULL;
+ BIGNUM *prime;
+ BN_CTX *ctx;
+ int ret = -1;
+
+ if (!x || !first || !second || num_elements <= 0 || !ec ||
+ !first_coefficients || !second_coefficients ||
+ first_coefficients == second_coefficients)
+ return -1;
+ *first_coefficients = NULL;
+ *second_coefficients = NULL;
+ prime = ec->prime;
+ ctx = ec->bnctx;
+ if (!prime || !ctx)
+ return -1;
+ for (int i = 0; i < num_elements; i++) {
+ if (!x[i] || !first[i] || !second[i])
+ return -1;
+ }
+
+ quotient = crypto_bignum_vector_alloc(num_elements);
+ first_result = crypto_bignum_vector_alloc(num_elements);
+ second_result = crypto_bignum_vector_alloc(num_elements);
+ tmp = BN_new();
+ first_factor = BN_new();
+ second_factor = BN_new();
+ if (!quotient || !first_result || !second_result || !tmp ||
+ !first_factor || !second_factor ||
+ crypto_interpolation_basis(x, num_elements, prime, ctx,
+ &poly, &weights) < 0)
+ goto out;
+
+ /* Accumulate both interpolants without materializing an n-by-n matrix. */
+ for (int i = 0; i < num_elements; i++) {
+ if (!BN_copy(quotient[num_elements - 1], poly[num_elements]))
+ goto out;
+ for (int j = num_elements - 2; j >= 0; j--) {
+ if (!BN_mod_mul(tmp, x[i], quotient[j + 1],
+ prime, ctx) ||
+ !BN_mod_add(quotient[j], poly[j + 1], tmp,
+ prime, ctx))
+ goto out;
+ }
+ if (!BN_mod_mul(first_factor, first[i], weights[i],
+ prime, ctx) ||
+ !BN_mod_mul(second_factor, second[i], weights[i],
+ prime, ctx))
+ goto out;
+ for (int j = 0; j < num_elements; j++) {
+ if (!BN_mod_mul(tmp, quotient[j], first_factor,
+ prime, ctx) ||
+ !BN_mod_add(first_result[j], first_result[j], tmp,
+ prime, ctx) ||
+ !BN_mod_mul(tmp, quotient[j], second_factor,
+ prime, ctx) ||
+ !BN_mod_add(second_result[j], second_result[j], tmp,
+ prime, ctx))
+ goto out;
+ }
+ }
+
+ *first_coefficients = (struct crypto_bignum **) first_result;
+ *second_coefficients = (struct crypto_bignum **) second_result;
+ first_result = NULL;
+ second_result = NULL;
+ ret = 0;
+out:
+ crypto_bignum_vector_free(poly, num_elements + 1);
+ crypto_bignum_vector_free(weights, num_elements);
+ crypto_bignum_vector_free(quotient, num_elements);
+ crypto_bignum_vector_free(first_result, num_elements);
+ crypto_bignum_vector_free(second_result, num_elements);
+ BN_clear_free(tmp);
+ BN_clear_free(first_factor);
+ BN_clear_free(second_factor);
+ return ret;
+}
+
+
+
+
+struct crypto_bignum * crypto_evaluate(struct crypto_bignum **poly,
+ struct crypto_bignum *x,
+ int num_elements,
+ struct crypto_ec *ec)
+{
+ if (!poly || !x || num_elements <= 0 || !ec)
+ return NULL;
+ return (struct crypto_bignum *)
+ decoyauth_evaluate((BIGNUM **) poly, (BIGNUM *) x,
+ num_elements, ec->prime, ec->bnctx);
+}
+#endif /* CONFIG_SAE_DECOYAUTH */
--
2.53.0
More information about the Hostap
mailing list