1

Looking at the main API file secp256k1.h of the C library, we have:

SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_parse(
    const secp256k1_context* ctx,
    secp256k1_pubkey* pubkey,
    const unsigned char *input,
    size_t inputlen
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);

Hence I am expecting the function secp256k1_ec_pubkey_parse to fail if any of the three pointer arguments are NULL. This is indeed the case when pubkey or input are NULL (and in fact if we set up a callback function with secp256k1_context_set_illegal_callback, it will be duly called with the appropriate return value). However this function succeeds on NULL context. Does anyone know why this is happening? Is this the expected behaviour? I am guessing this isn't very important, but I am trying to learn and I don't like it when I don't understand. I attach a C snippet:

#include "secp256k1.h"
#include <assert.h>

int main()
{
  int return_value;

  secp256k1_context *ctx;         
  secp256k1_pubkey pub;           

  ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);

  // This is a valid public key
  const unsigned char *pub1 = "\x03"
    "\xf0\x28\x89\x2b\xad\x7e\xd5\x7d\x2f\xb5\x7b\xf3\x30\x81\xd5\xcf"
    "\xcf\x6f\x9e\xd3\xd3\xd7\xf1\x59\xc2\xe2\xff\xf5\x79\xdc\x34\x1a";

  // secp256k1_ec_pubkey_parse
  return_value = secp256k1_ec_pubkey_parse(ctx, &pub, pub1, 33); 
  assert(return_value == 1);  // public key is indeed valid

  // same call with NULL context
  return_value = secp256k1_ec_pubkey_parse(NULL, &pub, pub1, 33); 
  assert(return_value == 1);  // call is successfull

  // secp2561k1_context_destroy
 secp256k1_context_destroy(ctx);
}
Sven Williamson
  • 1,524
  • 10
  • 23

1 Answers1

3

If you look at the source code, secp256k1_ec_pubkey_parse doesn't actually use its ctx argument. So no harm is done if it's null.

You can see in the code that there is a VERIFY_CHECK macro to test if ctx is non-null. However, this is meant only for testing; you can see in util.h that nothing is actually done about the test unless the VERIFY macro is defined, which presumably is only the case for test builds.

The SECP256K1_ARG_NONNULL macro, defined here, uses the GCC function attribute mechanism to tell the compiler that this argument is supposed to be non-null. The compiler will optimize on this basis. It can try to issue a warning if it can determine, at compile time, that the argument is null; but only if you use the -Wnonnull option.

Nate Eldredge
  • 22,970
  • 3
  • 39
  • 80
  • 1
    I think the macro `SECP256K1_BUILD` is probably defined during the build process, and this has the effect of reducing `SECP256K1_ARG_NONNULL(_x)` to the empty string, thereby removing the `__nonnull__` `gcc` attribute. – Sven Williamson Mar 05 '17 at 16:44