Falcon: crypto callback (WOLF_CRYPTO_CB) interface + CB_ONLY

Wire Falcon into the crypto callback framework like the other algorithms:

  - wc_falcon_make_key now dispatches to wc_CryptoCb_MakePqcSignatureKey
    (WC_PQC_SIG_TYPE_FALCON); wc_falcon_sign_msg / wc_falcon_verify_msg already
    dispatched to wc_CryptoCb_PqcSign / PqcVerify. All three fall through to the
    software implementation when the callback is unavailable.

  - Add WOLF_CRYPTO_CB_ONLY_FALCON (mirrors WOLF_CRYPTO_CB_ONLY_RSA/ECC): the
    callback becomes authoritative (no software fallback; returns NO_VALID_DEVID
    when no device is registered) and the native core (wc_falcon*.c) is compiled
    out entirely. WC_FALCON_HAVE_NATIVE_SIGN and the falcon_native_* prototypes
    are gated off in that build.

Tests (test.c):
  - myCryptoDevCb gains a Falcon branch for PQC keygen/sign/verify.
  - falcon_test / falcon_verify_kat now use the global test devId, so
    cryptocb_test drives every Falcon operation through the callback and asserts
    (via the exampleVar hit counter) that the cb path was actually taken.
  - Under WOLF_CRYPTO_CB_ONLY_FALCON, falcon_test instead confirms the API
    returns NO_VALID_DEVID with no device registered, and the KAT data/verifier
    (software-only) are compiled out.

Verified: default (no cryptocb), --enable-cryptocb, and
-DWOLF_CRYPTO_CB_ONLY_FALCON all build and pass testwolfcrypt (falcon_test +
crypto callback test); the CB_ONLY library contains no falcon_native_* symbols.
pull/10827/head
Daniele Lacamera 2026-07-01 07:38:23 +02:00
parent 509b29bc9c
commit debc59f70b
13 changed files with 134 additions and 20 deletions

View File

@ -67,7 +67,7 @@ static void falcon_store_pub_behind_priv(falcon_key* key)
*/
int wc_falcon_make_key(falcon_key* key, WC_RNG* rng)
{
int ret;
int ret = 0;
if ((key == NULL) || (rng == NULL)) {
return BAD_FUNC_ARG;
@ -76,10 +76,29 @@ int wc_falcon_make_key(falcon_key* key, WC_RNG* rng)
return BAD_FUNC_ARG;
}
#ifdef WOLF_CRYPTO_CB
#ifndef WOLF_CRYPTO_CB_FIND
if (key->devId != INVALID_DEVID)
#endif
{
ret = wc_CryptoCb_MakePqcSignatureKey(rng, WC_PQC_SIG_TYPE_FALCON,
key->level, key);
if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE))
return ret;
/* fall-through when unavailable */
ret = 0;
}
#endif /* WOLF_CRYPTO_CB */
#ifdef WOLF_CRYPTO_CB_ONLY_FALCON
/* No software fallback: only a crypto callback can service the request. */
ret = NO_VALID_DEVID;
#else
ret = falcon_native_make_key(key, rng);
if (ret == 0) {
falcon_store_pub_behind_priv(key);
}
#endif
return ret;
}
#endif /* !WOLFSSL_FALCON_VERIFY_ONLY */
@ -119,9 +138,14 @@ int wc_falcon_sign_msg(const byte* in, word32 inLen,
/* fall-through when unavailable */
ret = 0;
}
#endif
#endif /* WOLF_CRYPTO_CB */
#ifndef WOLFSSL_FALCON_VERIFY_ONLY
#ifdef WOLF_CRYPTO_CB_ONLY_FALCON
/* No software fallback: only a crypto callback can service the request. */
ret = NO_VALID_DEVID;
#elif defined(WOLFSSL_FALCON_VERIFY_ONLY)
ret = NOT_COMPILED_IN;
#else
if ((ret == 0) && (!key->prvKeySet)) {
ret = BAD_FUNC_ARG;
}
@ -129,8 +153,6 @@ int wc_falcon_sign_msg(const byte* in, word32 inLen,
if (ret == 0) {
ret = falcon_native_sign_msg(in, inLen, out, outLen, key, rng);
}
#else
ret = NOT_COMPILED_IN;
#endif
return ret;
}
@ -168,8 +190,12 @@ int wc_falcon_verify_msg(const byte* sig, word32 sigLen, const byte* msg,
/* fall-through when unavailable */
ret = 0;
}
#endif
#endif /* WOLF_CRYPTO_CB */
#ifdef WOLF_CRYPTO_CB_ONLY_FALCON
/* No software fallback: only a crypto callback can service the request. */
ret = NO_VALID_DEVID;
#else
if ((ret == 0) && (!key->pubKeySet)) {
ret = BAD_FUNC_ARG;
}
@ -177,6 +203,7 @@ int wc_falcon_verify_msg(const byte* sig, word32 sigLen, const byte* msg,
if (ret == 0) {
ret = falcon_native_verify_msg(sig, sigLen, msg, msgLen, res, key);
}
#endif
return ret;
}

View File

@ -27,7 +27,7 @@
#include <wolfssl/wolfcrypt/libwolfssl_sources.h>
#if defined(HAVE_FALCON)
#if defined(HAVE_FALCON) && !defined(WOLF_CRYPTO_CB_ONLY_FALCON)
#include <wolfssl/wolfcrypt/falcon.h>
#include <wolfssl/wolfcrypt/error-crypt.h>

View File

@ -30,7 +30,7 @@
#include <wolfssl/wolfcrypt/libwolfssl_sources.h>
#if defined(HAVE_FALCON) && !defined(WOLFSSL_FALCON_VERIFY_ONLY)
#if defined(HAVE_FALCON) && !defined(WOLFSSL_FALCON_VERIFY_ONLY) && !defined(WOLF_CRYPTO_CB_ONLY_FALCON)
#include <wolfssl/wolfcrypt/wc_falcon_bigint.h>

View File

@ -29,7 +29,7 @@
#include <wolfssl/wolfcrypt/libwolfssl_sources.h>
#if defined(HAVE_FALCON) && !defined(WOLFSSL_FALCON_VERIFY_ONLY)
#if defined(HAVE_FALCON) && !defined(WOLFSSL_FALCON_VERIFY_ONLY) && !defined(WOLF_CRYPTO_CB_ONLY_FALCON)
#include <wolfssl/wolfcrypt/falcon.h>
#include <wolfssl/wolfcrypt/wc_falcon_codec.h>

View File

@ -25,7 +25,7 @@
#include <wolfssl/wolfcrypt/libwolfssl_sources.h>
#if defined(HAVE_FALCON) && !defined(WOLFSSL_FALCON_VERIFY_ONLY)
#if defined(HAVE_FALCON) && !defined(WOLFSSL_FALCON_VERIFY_ONLY) && !defined(WOLF_CRYPTO_CB_ONLY_FALCON)
#include <wolfssl/wolfcrypt/wc_falcon_fft.h>

View File

@ -53,7 +53,7 @@
#include <wolfssl/wolfcrypt/libwolfssl_sources.h>
#if defined(HAVE_FALCON) && !defined(WOLFSSL_FALCON_VERIFY_ONLY) && \
#if defined(HAVE_FALCON) && !defined(WOLF_CRYPTO_CB_ONLY_FALCON) && !defined(WOLFSSL_FALCON_VERIFY_ONLY) && \
defined(WOLFSSL_FALCON_FFT_AVX2)
#include <wolfssl/wolfcrypt/wc_falcon_fft.h>

View File

@ -36,7 +36,7 @@
#include <wolfssl/wolfcrypt/libwolfssl_sources.h>
#if defined(HAVE_FALCON)
#if defined(HAVE_FALCON) && !defined(WOLF_CRYPTO_CB_ONLY_FALCON)
#include <wolfssl/wolfcrypt/wc_falcon_fpr.h>

View File

@ -31,7 +31,7 @@
#include <wolfssl/wolfcrypt/libwolfssl_sources.h>
#if defined(HAVE_FALCON) && !defined(WOLFSSL_FALCON_VERIFY_ONLY)
#if defined(HAVE_FALCON) && !defined(WOLFSSL_FALCON_VERIFY_ONLY) && !defined(WOLF_CRYPTO_CB_ONLY_FALCON)
#include <wolfssl/wolfcrypt/wc_falcon_keygen.h>
#include <wolfssl/wolfcrypt/wc_falcon_bigint.h>

View File

@ -25,7 +25,7 @@
#include <wolfssl/wolfcrypt/libwolfssl_sources.h>
#if defined(HAVE_FALCON) && !defined(WOLFSSL_FALCON_VERIFY_ONLY)
#if defined(HAVE_FALCON) && !defined(WOLFSSL_FALCON_VERIFY_ONLY) && !defined(WOLF_CRYPTO_CB_ONLY_FALCON)
#include <wolfssl/wolfcrypt/wc_falcon_poly.h>
#include <wolfssl/wolfcrypt/wc_falcon_fft.h> /* falcon_gm_tab */

View File

@ -57,7 +57,7 @@
#include <wolfssl/wolfcrypt/libwolfssl_sources.h>
#if defined(HAVE_FALCON) && !defined(WOLFSSL_FALCON_VERIFY_ONLY)
#if defined(HAVE_FALCON) && !defined(WOLFSSL_FALCON_VERIFY_ONLY) && !defined(WOLF_CRYPTO_CB_ONLY_FALCON)
#include <wolfssl/wolfcrypt/wc_falcon_sampler.h>
#include <wolfssl/wolfcrypt/wc_falcon_fpr.h>

View File

@ -31,7 +31,7 @@
#include <wolfssl/wolfcrypt/libwolfssl_sources.h>
#if defined(HAVE_FALCON) && !defined(WOLFSSL_FALCON_VERIFY_ONLY)
#if defined(HAVE_FALCON) && !defined(WOLFSSL_FALCON_VERIFY_ONLY) && !defined(WOLF_CRYPTO_CB_ONLY_FALCON)
#include <wolfssl/wolfcrypt/wc_falcon_sign.h>
#include <wolfssl/wolfcrypt/wc_falcon_fpr.h>

View File

@ -57713,6 +57713,9 @@ static wc_test_ret_t mldsa_decode_test(void)
* then drop pk / sig / siglen into the arrays below. (liboqs >= 0.11 API.)
*/
/* The KAT vectors and their verifier exercise the software verify path, which
* is not present in a WOLF_CRYPTO_CB_ONLY_FALCON build. */
#ifndef WOLF_CRYPTO_CB_ONLY_FALCON
#define FALCON_KAT_MSG "wolfSSL FN-DSA differential KAT"
static const byte FALCON512_pk[] = {
@ -58125,7 +58128,9 @@ static wc_test_ret_t falcon_verify_kat(byte level, const byte* pk, word32 pkLen,
const byte* msg = (const byte*)FALCON_KAT_MSG;
word32 msgLen = (word32)XSTRLEN(FALCON_KAT_MSG);
ret = wc_falcon_init(&key);
/* Use the global test devId so that, when cryptocb_test() has registered a
* device, verification is routed through the crypto callback. */
ret = wc_falcon_init_ex(&key, HEAP_HINT, devId);
if (ret != 0)
return WC_TEST_RET_ENC_EC(ret);
@ -58135,7 +58140,7 @@ static wc_test_ret_t falcon_verify_kat(byte level, const byte* pk, word32 pkLen,
ret = wc_falcon_import_public(pk, pkLen, &key);
if (ret != 0) { ret = WC_TEST_RET_ENC_EC(ret); goto out; }
/* A genuine liboqs-produced signature must verify (res == 1). */
/* A genuine reference-produced signature must verify (res == 1). */
res = 0;
ret = wc_falcon_verify_msg(sig, sigLen, msg, msgLen, &res, &key);
if (ret != 0) { ret = WC_TEST_RET_ENC_EC(ret); goto out; }
@ -58157,11 +58162,13 @@ out:
wc_falcon_free(&key);
return ret;
}
#endif /* !WOLF_CRYPTO_CB_ONLY_FALCON */
WOLFSSL_TEST_SUBROUTINE wc_test_ret_t falcon_test(void)
{
wc_test_ret_t ret;
#ifndef WOLF_CRYPTO_CB_ONLY_FALCON
ret = falcon_verify_kat(FALCON_LEVEL1, FALCON512_pk,
(word32)sizeof(FALCON512_pk), FALCON512_sig, FALCON512_SIGLEN);
if (ret != 0)
@ -58190,7 +58197,7 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t falcon_test(void)
word32 siglen = (word32)sizeof(sig);
int res = 0;
ret = wc_falcon_init(&k);
ret = wc_falcon_init_ex(&k, HEAP_HINT, devId);
if (ret == 0)
ret = wc_falcon_set_level(&k, falconLvls[li]);
if (ret == 0)
@ -58220,6 +58227,29 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t falcon_test(void)
wc_FreeRng(&rng);
}
#endif /* WC_FALCON_HAVE_NATIVE_SIGN */
#else /* WOLF_CRYPTO_CB_ONLY_FALCON */
/* Software Falcon is compiled out. Confirm the public API refuses an
* operation when no crypto-callback device is available (INVALID_DEVID),
* rather than silently doing nothing. */
{
falcon_key k;
int res = 0;
int r;
ret = wc_falcon_init(&k);
if (ret == 0)
ret = wc_falcon_set_level(&k, FALCON_LEVEL1);
if (ret == 0) {
r = wc_falcon_verify_msg((const byte*)"m", 1, (const byte*)"m", 1,
&res, &k);
if (r != WC_NO_ERR_TRACE(NO_VALID_DEVID))
ret = WC_TEST_RET_ENC_NC;
}
wc_falcon_free(&k);
if (ret != 0)
return ret;
}
#endif /* !WOLF_CRYPTO_CB_ONLY_FALCON */
return 0;
}
@ -77679,6 +77709,45 @@ static int myCryptoDevCb(int devIdArg, wc_CryptoInfo* info, void* ctx)
}
}
#endif /* WOLFSSL_HAVE_SLHDSA */
#if defined(HAVE_FALCON) && !defined(WOLF_CRYPTO_CB_ONLY_FALCON)
#ifndef WOLFSSL_FALCON_VERIFY_ONLY
if (info->pk.type == WC_PK_TYPE_PQC_SIG_KEYGEN &&
info->pk.pqc_sig_kg.type == WC_PQC_SIG_TYPE_FALCON) {
falcon_key* fk = (falcon_key*)info->pk.pqc_sig_kg.key;
/* set devId invalid so the software path is used (no recursion) */
fk->devId = INVALID_DEVID;
ret = wc_falcon_make_key(fk, info->pk.pqc_sig_kg.rng);
fk->devId = devIdArg;
myCtx->exampleVar++;
}
else if (info->pk.type == WC_PK_TYPE_PQC_SIG_SIGN &&
info->pk.pqc_sign.type == WC_PQC_SIG_TYPE_FALCON) {
falcon_key* fk = (falcon_key*)info->pk.pqc_sign.key;
fk->devId = INVALID_DEVID;
ret = wc_falcon_sign_msg(info->pk.pqc_sign.in,
info->pk.pqc_sign.inlen, info->pk.pqc_sign.out,
info->pk.pqc_sign.outlen, fk, info->pk.pqc_sign.rng);
fk->devId = devIdArg;
myCtx->exampleVar++;
}
else
#endif /* !WOLFSSL_FALCON_VERIFY_ONLY */
if (info->pk.type == WC_PK_TYPE_PQC_SIG_VERIFY &&
info->pk.pqc_verify.type == WC_PQC_SIG_TYPE_FALCON) {
falcon_key* fk = (falcon_key*)info->pk.pqc_verify.key;
int verifyRet;
fk->devId = INVALID_DEVID;
verifyRet = wc_falcon_verify_msg(info->pk.pqc_verify.sig,
info->pk.pqc_verify.siglen, info->pk.pqc_verify.msg,
info->pk.pqc_verify.msglen, info->pk.pqc_verify.res, fk);
fk->devId = devIdArg;
/* SIG_VERIFY_E is a validity signal, not a crypto error. */
if (verifyRet == WC_NO_ERR_TRACE(SIG_VERIFY_E))
verifyRet = 0;
ret = verifyRet;
myCtx->exampleVar++;
}
#endif /* HAVE_FALCON && !WOLF_CRYPTO_CB_ONLY_FALCON */
#ifdef WOLFSSL_HAVE_MLKEM
if (info->pk.type == WC_PK_TYPE_PQC_KEM_KEYGEN) {
if ((info->pk.pqc_kem_kg.type == WC_PQC_KEM_TYPE_MLKEM) &&
@ -79639,6 +79708,20 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t cryptocb_test(void)
myCtx.exampleVar = baseline;
}
#endif
#if defined(HAVE_FALCON) && !defined(WOLF_CRYPTO_CB_ONLY_FALCON)
if (ret == 0) {
/* Route Falcon through the crypto callback (global devId is set) and
* confirm the cb path was actually exercised via the hit counter, so a
* silent software fallback can't mask a dispatch regression. Both the
* KAT verify and (when built) the native keygen/sign/verify round-trip
* use the test devId. */
int baseline = myCtx.exampleVar;
ret = falcon_test();
if ((ret == 0) && (myCtx.exampleVar == baseline))
ret = WC_TEST_RET_ENC_NC;
myCtx.exampleVar = baseline;
}
#endif
#if defined(WOLFSSL_HAVE_XMSS) && !defined(WOLFSSL_XMSS_VERIFY_ONLY)
if (ret == 0)
ret = xmss_test();

View File

@ -213,7 +213,10 @@ WOLFSSL_API int wc_Falcon_PublicKeyToDer(falcon_key* key, byte* output,
word32 inLen, int withAlg);
/* Native implementation core (internal). The public wc_falcon_* functions in
* falcon.c wrap these with cryptocb dispatch and argument checking. */
* falcon.c wrap these with cryptocb dispatch and argument checking. With
* WOLF_CRYPTO_CB_ONLY_FALCON the native core is not compiled: all operations go
* through the crypto callback. */
#ifndef WOLF_CRYPTO_CB_ONLY_FALCON
#ifndef WOLFSSL_FALCON_VERIFY_ONLY
/* Signals that native signing and key generation are available. */
#define WC_FALCON_HAVE_NATIVE_SIGN
@ -223,6 +226,7 @@ WOLFSSL_LOCAL int falcon_native_sign_msg(const byte* in, word32 inLen,
#endif
WOLFSSL_LOCAL int falcon_native_verify_msg(const byte* sig, word32 sigLen,
const byte* msg, word32 msgLen, int* res, falcon_key* key);
#endif /* !WOLF_CRYPTO_CB_ONLY_FALCON */
#ifdef __cplusplus
} /* extern "C" */