diff --git a/src/secp256k1.c b/src/secp256k1.c index 4c11e7f0b8..7faf445760 100644 --- a/src/secp256k1.c +++ b/src/secp256k1.c @@ -83,6 +83,11 @@ static int secp256k1_context_is_proper(const secp256k1_context* ctx) { } void secp256k1_selftest(void) { + if (!SECP256K1_CHECKMEM_RUNNING()) { + if (!secp256k1_selftest_cpuid()) { + secp256k1_callback_call(&default_error_callback, "required CPU flags are not present."); + } + } if (!secp256k1_selftest_passes()) { secp256k1_callback_call(&default_error_callback, "self test failed"); } diff --git a/src/selftest.h b/src/selftest.h index d083ac9524..c2097d911a 100644 --- a/src/selftest.h +++ b/src/selftest.h @@ -25,6 +25,31 @@ static int secp256k1_selftest_sha256(void) { return secp256k1_memcmp_var(out, output32, 32) == 0; } +static int secp256k1_selftest_cpuid(void) { + int ret = 1; + +#if defined(USE_ASM_X86_64) + // getting the CPU flags from the cpu, more information in the Intel manual, + // Table 3-8 Information Returned by CPUID instruction (3-194, Vol.2A) + const int CPU_FLAG_ENUMERATION = 7; + const int LEAF_NODE_ZERO = 0; + + // for the cpu self test, we need BMI2 and ADX support + const int BIT_ADX = 19; + const int BIT_BMI2 = 8; + int flags = 0; + __asm__ __volatile__("cpuid\n" + : "=b"(flags) + : "a"(CPU_FLAG_ENUMERATION), "c"(LEAF_NODE_ZERO) + : "rdx", "rbx", "cc"); + + int has_adx = (flags >> BIT_ADX) & 1; + int has_bmi2 = (flags >> BIT_BMI2) & 1; + ret = has_adx && has_bmi2; +#endif + return ret; +} + static int secp256k1_selftest_passes(void) { return secp256k1_selftest_sha256(); }