[RFC PATCH v1 08/13] SAE: Add DecoyAuth worker support
Jeff Hansen
x at jeffhansen.com
Fri Sep 11 12:20:03 PDT 2026
Parallelize cached H2E candidate preparation and interpolation matrix
construction and weaving. Retain the serial paths when worker support is
not selected.
Signed-off-by: Jeff Hansen <x at jeffhansen.com>
---
src/common/sae.c | 329 ++++++++++++++++++++++++++++++++++++
src/crypto/crypto_openssl.c | 268 +++++++++++++++++++++++++++++
2 files changed, 597 insertions(+)
diff --git a/src/common/sae.c b/src/common/sae.c
index 687407d58..c5491490e 100644
--- a/src/common/sae.c
+++ b/src/common/sae.c
@@ -21,6 +21,9 @@
#include "ieee802_11_defs.h"
#include "dragonfly.h"
#include "sae.h"
+#ifdef CONFIG_SAE_DECOYAUTH_THREADS
+#include <pthread.h>
+#endif /* CONFIG_SAE_DECOYAUTH_THREADS */
int sae_set_group(struct sae_data *sae, int group)
@@ -1474,6 +1477,320 @@ int sae_prepare_commit(const u8 *addr1, const u8 *addr2,
#ifdef CONFIG_SAE_DECOYAUTH
+#ifdef CONFIG_SAE_DECOYAUTH_THREADS
+struct sae_candidate_batch {
+ const u8 **passwords;
+ const size_t *password_lens;
+ const u8 *pt_bins;
+ const u8 *mask_bin;
+ const u8 *addr_scalar_bin;
+ size_t prime_len;
+ size_t order_len;
+ int group;
+ int num_passwords;
+ int next;
+ int failed;
+ int failed_candidate;
+ struct crypto_bignum **hash_values;
+ struct crypto_bignum **u_values;
+ struct crypto_bignum **v_values;
+ u8 *pwe_bins;
+ u8 *commit_bins;
+ pthread_mutex_t lock;
+};
+
+
+static struct crypto_bignum *
+sae_decoyauth_addr_scalar(struct crypto_ec *ec, size_t prime_len,
+ const u8 *addr1, const u8 *addr2)
+{
+ const u8 *addr[2];
+ size_t len[2];
+ u8 salt[64], hash[64];
+ size_t hash_len;
+ const struct crypto_bignum *order;
+ struct crypto_bignum *tmp = NULL, *val = NULL, *one = NULL;
+
+ sae_max_min_addr(addr, len, addr1, addr2);
+ hash_len = sae_ecc_prime_len_2_hash_len(prime_len);
+ os_memset(salt, 0, hash_len);
+ if (hkdf_extract(hash_len, salt, hash_len, 2, addr, len, hash) < 0)
+ return NULL;
+
+ order = crypto_ec_get_order(ec);
+ tmp = crypto_bignum_init();
+ val = crypto_bignum_init_set(hash, hash_len);
+ one = crypto_bignum_init_uint(1);
+ if (!order || !tmp || !val || !one ||
+ crypto_bignum_sub(order, one, tmp) < 0 ||
+ crypto_bignum_mod(val, tmp, val) < 0 ||
+ crypto_bignum_add(val, one, val) < 0) {
+ crypto_bignum_deinit(val, 1);
+ val = NULL;
+ }
+ crypto_bignum_deinit(tmp, 1);
+ crypto_bignum_deinit(one, 0);
+ forced_memzero(hash, sizeof(hash));
+ return val;
+}
+
+
+static int sae_decoyauth_prepare_candidate(struct sae_candidate_batch *batch,
+ struct sae_data *worker,
+ struct crypto_bignum *mask,
+ struct crypto_bignum *addr_scalar,
+ int candidate)
+{
+ struct crypto_ec_point *pt = NULL;
+ struct crypto_bignum **encoded = NULL;
+ struct crypto_bignum *hash_value = NULL;
+ struct crypto_bignum *u_value = NULL, *v_value = NULL;
+ const u8 *pt_bin = batch->pt_bins +
+ 2 * batch->prime_len * (size_t) candidate;
+ u8 hash[SHA256_MAC_LEN];
+ int ret = -1;
+
+ pt = crypto_ec_point_from_bin(worker->tmp->ec, pt_bin);
+ worker->tmp->pwe_ecc = crypto_ec_point_init(worker->tmp->ec);
+ if (!pt || !worker->tmp->pwe_ecc ||
+ crypto_ec_point_mul(worker->tmp->ec, pt, addr_scalar,
+ worker->tmp->pwe_ecc) < 0 ||
+ sae_derive_commit_element_ecc(worker, mask) < 0 ||
+ sha256_vector(1, &batch->passwords[candidate],
+ &batch->password_lens[candidate], hash) < 0)
+ goto out;
+
+ hash_value = crypto_bignum_init_set(hash, sizeof(hash));
+ encoded = crypto_point_to_values(worker->tmp->own_commit_element_ecc,
+ worker->tmp->ec);
+ if (!hash_value || !encoded || !encoded[0] || !encoded[1] ||
+ crypto_ec_point_to_bin(
+ worker->tmp->ec, worker->tmp->pwe_ecc,
+ batch->pwe_bins + 2 * batch->prime_len * candidate,
+ batch->pwe_bins +
+ batch->prime_len * (2 * candidate + 1)) < 0 ||
+ crypto_ec_point_to_bin(
+ worker->tmp->ec, worker->tmp->own_commit_element_ecc,
+ batch->commit_bins + 2 * batch->prime_len * candidate,
+ batch->commit_bins +
+ batch->prime_len * (2 * candidate + 1)) < 0)
+ goto out;
+
+ u_value = encoded[0];
+ v_value = encoded[1];
+ encoded[0] = encoded[1] = NULL;
+ batch->hash_values[candidate] = hash_value;
+ batch->u_values[candidate] = u_value;
+ batch->v_values[candidate] = v_value;
+ hash_value = u_value = v_value = NULL;
+ ret = 0;
+out:
+ forced_memzero(hash, sizeof(hash));
+ crypto_ec_point_deinit(pt, 1);
+ crypto_bignum_deinit(hash_value, 1);
+ crypto_bignum_deinit(u_value, 1);
+ crypto_bignum_deinit(v_value, 1);
+ sae_free_bignum_array(&encoded, 2, 1);
+ crypto_ec_point_deinit(worker->tmp->pwe_ecc, 1);
+ worker->tmp->pwe_ecc = NULL;
+ crypto_ec_point_deinit(worker->tmp->own_commit_element_ecc, 1);
+ worker->tmp->own_commit_element_ecc = NULL;
+ return ret;
+}
+
+
+static void * sae_decoyauth_candidate_worker(void *ctx)
+{
+ struct sae_candidate_batch *batch = ctx;
+ struct sae_data worker;
+ struct crypto_bignum *mask = NULL, *addr_scalar = NULL;
+ int candidate;
+
+ os_memset(&worker, 0, sizeof(worker));
+ if (sae_set_group(&worker, batch->group) < 0)
+ goto init_fail;
+ mask = crypto_bignum_init_set(batch->mask_bin, batch->order_len);
+ addr_scalar = crypto_bignum_init_set(batch->addr_scalar_bin,
+ batch->order_len);
+ if (!mask || !addr_scalar)
+ goto init_fail;
+
+ for (;;) {
+ pthread_mutex_lock(&batch->lock);
+ if (batch->failed || batch->next >= batch->num_passwords) {
+ pthread_mutex_unlock(&batch->lock);
+ break;
+ }
+ candidate = batch->next++;
+ pthread_mutex_unlock(&batch->lock);
+
+ if (sae_decoyauth_prepare_candidate(batch, &worker, mask,
+ addr_scalar, candidate) < 0) {
+ pthread_mutex_lock(&batch->lock);
+ batch->failed = 1;
+ batch->failed_candidate = candidate;
+ pthread_mutex_unlock(&batch->lock);
+ break;
+ }
+ }
+ goto out;
+
+init_fail:
+ pthread_mutex_lock(&batch->lock);
+ batch->failed = 1;
+ batch->failed_candidate = -1;
+ pthread_mutex_unlock(&batch->lock);
+out:
+ crypto_bignum_deinit(mask, 1);
+ crypto_bignum_deinit(addr_scalar, 1);
+ sae_clear_data(&worker);
+ return NULL;
+}
+
+
+/*
+ * Return 1 when the cached H2E candidates were prepared in parallel, 0 when
+ * the parallel path is unavailable, and -1 after a worker failure.
+ */
+static int sae_decoyauth_prepare_candidates_parallel(
+ const u8 *addr1, const u8 *addr2,
+ const u8 **passwords, const size_t *password_lens,
+ const struct sae_pt * const *password_pts, int num_passwords,
+ struct crypto_bignum *mask, struct sae_data *sae,
+ struct crypto_bignum **hash_values,
+ struct crypto_bignum **u_values,
+ struct crypto_bignum **v_values)
+{
+ struct sae_candidate_batch batch;
+ struct crypto_bignum *addr_scalar = NULL;
+ struct os_reltime started_at, finished_at, elapsed;
+ pthread_t *threads = NULL;
+ u8 *mask_bin = NULL, *addr_scalar_bin = NULL;
+ u8 *pt_bins = NULL, *pwe_bins = NULL, *commit_bins = NULL;
+ long cpus;
+ int workers, started = 0, ret = 0, timed;
+ size_t point_bytes;
+
+ if (!password_pts || num_passwords < 2)
+ return 0;
+ cpus = sysconf(_SC_NPROCESSORS_ONLN);
+ if (cpus < 2)
+ return 0;
+ timed = os_get_reltime(&started_at) == 0;
+ workers = (int) cpus - 1;
+ if (workers > num_passwords)
+ workers = num_passwords;
+
+ os_memset(&batch, 0, sizeof(batch));
+ batch.passwords = passwords;
+ batch.password_lens = password_lens;
+ batch.prime_len = sae->tmp->prime_len;
+ batch.order_len = sae->tmp->order_len;
+ batch.group = sae->group;
+ batch.num_passwords = num_passwords;
+ batch.failed_candidate = -1;
+ batch.hash_values = hash_values;
+ batch.u_values = u_values;
+ batch.v_values = v_values;
+ point_bytes = 2 * batch.prime_len * (size_t) num_passwords;
+ mask_bin = os_malloc(batch.order_len);
+ addr_scalar_bin = os_malloc(batch.order_len);
+ pt_bins = os_malloc(point_bytes);
+ pwe_bins = os_malloc(point_bytes);
+ commit_bins = os_malloc(point_bytes);
+ threads = os_calloc(workers, sizeof(*threads));
+ if (!mask_bin || !addr_scalar_bin || !pt_bins || !pwe_bins ||
+ !commit_bins || !threads)
+ goto out;
+
+ for (int i = 0; i < num_passwords; i++) {
+ const struct sae_pt *pt = password_pts[i];
+
+ while (pt && pt->group != sae->group)
+ pt = pt->next;
+ if (!pt || !pt->ec || !pt->ecc_pt ||
+ crypto_ec_point_to_bin(
+ pt->ec, pt->ecc_pt,
+ pt_bins + 2 * batch.prime_len * i,
+ pt_bins + batch.prime_len * (2 * i + 1)) < 0)
+ goto out;
+ }
+
+ addr_scalar = sae_decoyauth_addr_scalar(sae->tmp->ec,
+ batch.prime_len, addr1, addr2);
+ if (!addr_scalar ||
+ crypto_bignum_to_bin(mask, mask_bin, batch.order_len,
+ batch.order_len) < 0 ||
+ crypto_bignum_to_bin(addr_scalar, addr_scalar_bin,
+ batch.order_len, batch.order_len) < 0)
+ goto out;
+
+ batch.pt_bins = pt_bins;
+ batch.mask_bin = mask_bin;
+ batch.addr_scalar_bin = addr_scalar_bin;
+ batch.pwe_bins = pwe_bins;
+ batch.commit_bins = commit_bins;
+ if (pthread_mutex_init(&batch.lock, NULL) != 0)
+ goto out;
+
+ for (started = 0; started < workers; started++) {
+ if (pthread_create(&threads[started], NULL,
+ sae_decoyauth_candidate_worker, &batch) != 0)
+ break;
+ }
+ if (!started)
+ sae_decoyauth_candidate_worker(&batch);
+ for (int i = 0; i < started; i++)
+ pthread_join(threads[i], NULL);
+ pthread_mutex_destroy(&batch.lock);
+
+ if (batch.failed) {
+ wpa_printf(MSG_DEBUG,
+ "SAE: DecoyAuth parallel candidate preparation "
+ "failed candidate=%d workers=%d",
+ batch.failed_candidate, started ? started : 1);
+ ret = -1;
+ goto out;
+ }
+ for (int i = 0; i < num_passwords; i++) {
+ sae->tmp->pwe_eccs[i] = crypto_ec_point_from_bin(
+ sae->tmp->ec, pwe_bins + 2 * batch.prime_len * i);
+ sae->tmp->own_commit_element_eccs[i] =
+ crypto_ec_point_from_bin(
+ sae->tmp->ec,
+ commit_bins + 2 * batch.prime_len * i);
+ if (!sae->tmp->pwe_eccs[i] ||
+ !sae->tmp->own_commit_element_eccs[i]) {
+ ret = -1;
+ goto out;
+ }
+ }
+ if (timed && os_get_reltime(&finished_at) == 0) {
+ os_reltime_sub(&finished_at, &started_at, &elapsed);
+ wpa_printf(MSG_DEBUG,
+ "SAE: DecoyAuth prepared %d cached H2E "
+ "candidates with %d workers in %ld ms",
+ num_passwords, started ? started : 1,
+ elapsed.sec * 1000L + elapsed.usec / 1000);
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "SAE: DecoyAuth prepared %d cached H2E candidates with %d workers",
+ num_passwords, started ? started : 1);
+ }
+ ret = 1;
+out:
+ crypto_bignum_deinit(addr_scalar, 1);
+ bin_clear_free(mask_bin, batch.order_len);
+ bin_clear_free(addr_scalar_bin, batch.order_len);
+ bin_clear_free(pt_bins, point_bytes);
+ bin_clear_free(pwe_bins, point_bytes);
+ bin_clear_free(commit_bins, point_bytes);
+ os_free(threads);
+ return ret;
+}
+#endif /* CONFIG_SAE_DECOYAUTH_THREADS */
+
+
static int sae_ap_prepare_commit_internal(const u8 *addr1, const u8 *addr2,
const u8 *ssid, size_t ssid_len,
const u8 **passwords,
@@ -1542,6 +1859,18 @@ static int sae_ap_prepare_commit_internal(const u8 *addr1, const u8 *addr2,
goto fail;
}
+#ifdef CONFIG_SAE_DECOYAUTH_THREADS
+ if (password_pts) {
+ fail_stage = "prepare cached H2E candidates in parallel";
+ candidates_ready = sae_decoyauth_prepare_candidates_parallel(
+ addr1, addr2, passwords, password_lens, password_pts,
+ num_passwords, mask, sae, hash_values, u_values,
+ v_values);
+ if (candidates_ready < 0)
+ goto fail;
+ }
+#endif /* CONFIG_SAE_DECOYAUTH_THREADS */
+
for (int i = 0; !candidates_ready && i < num_passwords; i++) {
struct crypto_bignum **encoded_point;
const struct sae_pt *pt = NULL;
diff --git a/src/crypto/crypto_openssl.c b/src/crypto/crypto_openssl.c
index 82dcc4f60..48a08d409 100644
--- a/src/crypto/crypto_openssl.c
+++ b/src/crypto/crypto_openssl.c
@@ -24,6 +24,9 @@
#include <limits.h>
#include <sys/mman.h>
#include <sys/stat.h>
+#ifdef CONFIG_SAE_DECOYAUTH_THREADS
+#include <pthread.h>
+#endif /* CONFIG_SAE_DECOYAUTH_THREADS */
#endif /* CONFIG_SAE_DECOYAUTH_CACHE */
#ifdef CONFIG_ECC
#include <openssl/ec.h>
@@ -6371,6 +6374,270 @@ out:
#define DECOYAUTH_CACHE_HEADER_LEN 64
#define DECOYAUTH_CACHE_PREFIX "decoyauth-matrix-v1-"
+#ifdef CONFIG_SAE_DECOYAUTH_THREADS
+struct interpolation_matrix_batch {
+ BIGNUM **x;
+ BIGNUM **poly;
+ BIGNUM **weights;
+ const BIGNUM *prime;
+ u8 *matrix;
+ size_t element_len;
+ int count;
+ int next;
+ int failed;
+ pthread_mutex_t lock;
+};
+
+struct interpolation_weave_batch {
+ BIGNUM **first;
+ BIGNUM **second;
+ BIGNUM **first_result;
+ BIGNUM **second_result;
+ const BIGNUM *prime;
+ const u8 *matrix;
+ size_t element_len;
+ int count;
+ int next;
+ int failed;
+ pthread_mutex_t lock;
+};
+
+
+static long interpolation_elapsed_ms(const struct os_reltime *start,
+ const struct os_reltime *end)
+{
+ struct os_reltime elapsed;
+
+ os_reltime_sub(end, start, &elapsed);
+ return elapsed.sec * 1000L + elapsed.usec / 1000;
+}
+
+
+static int interpolation_worker_count(int count)
+{
+ long cpus = sysconf(_SC_NPROCESSORS_ONLN);
+ int workers = cpus > 1 ? (int) cpus - 1 : 1;
+
+ return workers < count ? workers : count;
+}
+
+
+static void * interpolation_matrix_worker(void *ctx)
+{
+ struct interpolation_matrix_batch *batch = ctx;
+ BIGNUM **quotient = NULL;
+ BIGNUM *tmp = NULL;
+ BN_CTX *bnctx = NULL;
+ int column;
+
+ quotient = crypto_bignum_vector_alloc(batch->count);
+ tmp = BN_new();
+ bnctx = BN_CTX_new();
+ if (!quotient || !tmp || !bnctx)
+ goto fail;
+
+ for (;;) {
+ pthread_mutex_lock(&batch->lock);
+ column = batch->failed ? batch->count : batch->next++;
+ pthread_mutex_unlock(&batch->lock);
+ if (column >= batch->count)
+ break;
+
+ if (!BN_copy(quotient[batch->count - 1],
+ batch->poly[batch->count]))
+ goto fail;
+ for (int row = batch->count - 2; row >= 0; row--) {
+ if (!BN_mod_mul(tmp, batch->x[column], quotient[row + 1],
+ batch->prime, bnctx) ||
+ !BN_mod_add(quotient[row], batch->poly[row + 1], tmp,
+ batch->prime, bnctx))
+ goto fail;
+ }
+ for (int row = 0; row < batch->count; row++) {
+ u8 *out = batch->matrix +
+ ((size_t) row * batch->count + column) *
+ batch->element_len;
+
+ if (!BN_mod_mul(tmp, quotient[row], batch->weights[column],
+ batch->prime, bnctx) ||
+ BN_bn2binpad(tmp, out, batch->element_len) !=
+ (int) batch->element_len)
+ goto fail;
+ }
+ }
+ goto out;
+
+fail:
+ pthread_mutex_lock(&batch->lock);
+ batch->failed = 1;
+ pthread_mutex_unlock(&batch->lock);
+out:
+ crypto_bignum_vector_free(quotient, batch->count);
+ BN_clear_free(tmp);
+ BN_CTX_free(bnctx);
+ return NULL;
+}
+
+
+static int interpolation_matrix_build(BIGNUM **x, int count,
+ const BIGNUM *prime, BN_CTX *ctx,
+ u8 *matrix, size_t element_len)
+{
+ struct interpolation_matrix_batch batch;
+ BIGNUM **poly = NULL, **weights = NULL;
+ pthread_t *threads = NULL;
+ int workers, started = 0, ret = -1;
+
+ if (crypto_interpolation_basis(x, count, prime, ctx,
+ &poly, &weights) < 0)
+ return -1;
+
+ os_memset(&batch, 0, sizeof(batch));
+ batch.x = x;
+ batch.poly = poly;
+ batch.weights = weights;
+ batch.prime = prime;
+ batch.matrix = matrix;
+ batch.element_len = element_len;
+ batch.count = count;
+ workers = interpolation_worker_count(count);
+ threads = os_calloc(workers, sizeof(*threads));
+ if (!threads || pthread_mutex_init(&batch.lock, NULL) != 0)
+ goto out;
+
+ for (; started < workers; started++) {
+ if (pthread_create(&threads[started], NULL,
+ interpolation_matrix_worker, &batch) != 0)
+ break;
+ }
+ if (!started)
+ interpolation_matrix_worker(&batch);
+ for (int i = 0; i < started; i++)
+ pthread_join(threads[i], NULL);
+ pthread_mutex_destroy(&batch.lock);
+ ret = batch.failed ? -1 : 0;
+out:
+ os_free(threads);
+ crypto_bignum_vector_free(poly, count + 1);
+ crypto_bignum_vector_free(weights, count);
+ return ret;
+}
+
+
+static void * interpolation_weave_worker(void *ctx)
+{
+ struct interpolation_weave_batch *batch = ctx;
+ BIGNUM *matrix_value = NULL, *product = NULL;
+ BIGNUM *first_sum = NULL, *second_sum = NULL;
+ BN_CTX *bnctx = NULL;
+ int row;
+
+ matrix_value = BN_new();
+ product = BN_new();
+ first_sum = BN_new();
+ second_sum = BN_new();
+ bnctx = BN_CTX_new();
+ if (!matrix_value || !product || !first_sum || !second_sum || !bnctx)
+ goto fail;
+
+ for (;;) {
+ pthread_mutex_lock(&batch->lock);
+ row = batch->failed ? batch->count : batch->next++;
+ pthread_mutex_unlock(&batch->lock);
+ if (row >= batch->count)
+ break;
+
+ BN_zero(first_sum);
+ BN_zero(second_sum);
+ for (int column = 0; column < batch->count; column++) {
+ const u8 *value = batch->matrix +
+ ((size_t) row * batch->count + column) *
+ batch->element_len;
+
+ if (!BN_bin2bn(value, batch->element_len, matrix_value) ||
+ !BN_mul(product, matrix_value, batch->first[column],
+ bnctx) ||
+ !BN_add(first_sum, first_sum, product) ||
+ !BN_mul(product, matrix_value, batch->second[column],
+ bnctx) ||
+ !BN_add(second_sum, second_sum, product))
+ goto fail;
+ }
+ if (!BN_nnmod(batch->first_result[row], first_sum,
+ batch->prime, bnctx) ||
+ !BN_nnmod(batch->second_result[row], second_sum,
+ batch->prime, bnctx))
+ goto fail;
+ }
+ goto out;
+
+fail:
+ pthread_mutex_lock(&batch->lock);
+ batch->failed = 1;
+ pthread_mutex_unlock(&batch->lock);
+out:
+ BN_clear_free(matrix_value);
+ BN_clear_free(product);
+ BN_clear_free(first_sum);
+ BN_clear_free(second_sum);
+ BN_CTX_free(bnctx);
+ return NULL;
+}
+
+
+static int interpolation_matrix_weave_pair(
+ const u8 *matrix, size_t element_len,
+ BIGNUM **first, BIGNUM **second, int count, const BIGNUM *prime,
+ BIGNUM ***first_out, BIGNUM ***second_out)
+{
+ struct interpolation_weave_batch batch;
+ BIGNUM **first_result = NULL, **second_result = NULL;
+ pthread_t *threads = NULL;
+ int workers, started = 0, ret = -1;
+
+ first_result = crypto_bignum_vector_alloc(count);
+ second_result = crypto_bignum_vector_alloc(count);
+ if (!first_result || !second_result)
+ goto out;
+
+ os_memset(&batch, 0, sizeof(batch));
+ batch.first = first;
+ batch.second = second;
+ batch.first_result = first_result;
+ batch.second_result = second_result;
+ batch.prime = prime;
+ batch.matrix = matrix;
+ batch.element_len = element_len;
+ batch.count = count;
+ workers = interpolation_worker_count(count);
+ threads = os_calloc(workers, sizeof(*threads));
+ if (!threads || pthread_mutex_init(&batch.lock, NULL) != 0)
+ goto out;
+
+ for (; started < workers; started++) {
+ if (pthread_create(&threads[started], NULL,
+ interpolation_weave_worker, &batch) != 0)
+ break;
+ }
+ if (!started)
+ interpolation_weave_worker(&batch);
+ for (int i = 0; i < started; i++)
+ pthread_join(threads[i], NULL);
+ pthread_mutex_destroy(&batch.lock);
+ if (batch.failed)
+ goto out;
+
+ *first_out = first_result;
+ *second_out = second_result;
+ first_result = second_result = NULL;
+ ret = 0;
+out:
+ os_free(threads);
+ crypto_bignum_vector_free(first_result, count);
+ crypto_bignum_vector_free(second_result, count);
+ return ret;
+}
+#else /* CONFIG_SAE_DECOYAUTH_THREADS */
static int interpolation_matrix_build(BIGNUM **x, int count,
const BIGNUM *prime, BN_CTX *ctx,
u8 *matrix, size_t element_len)
@@ -6473,6 +6740,7 @@ out:
BN_CTX_free(ctx);
return ret;
}
+#endif /* CONFIG_SAE_DECOYAUTH_THREADS */
static int interpolation_cache_mkdir(const char *directory)
--
2.53.0
More information about the Hostap
mailing list