C secp256k1 : ec_pubkey_parse successful on NULL context despite attribute

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

Posted 2017-03-05T16:07:37.537

Reputation: 1 314

Answers

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

Posted 2017-03-05T16:07:37.537

Reputation: 21 420

1I 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 2017-03-05T16:44:39.897