Howto calculate v (parity / recovery Id) for ECDSA signature using secp256k1 library in C++?

Viewed 240

I use the following code (secp256k1 lib for linux) to create an ethereum tx signature in C++:

secp256k1_context *ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);

int res = secp256k1_ec_seckey_verify(ctx, secret);
if(!res)
{
    secp256k1_context_destroy(ctx);
    return false;
}

secp256k1_ecdsa_signature sig;
res = secp256k1_ecdsa_sign(ctx, &sig, (uint8_t*) hash.data(), secret, NULL/*secp256k1_nonce_function_rfc6979*/, NULL);
if(!res)
{
    secp256k1_context_destroy(ctx);
    return false;
}

unsigned char buf[64];
secp256k1_ecdsa_signature_serialize_compact(ctx, buf, &sig);

char r[65], s[65];
r = byteArrayToCharArray(r, buf, 32);
s = byteArrayToCharArray(s, buf + 32, 32);
// v = ???

My problem is that I don't know how to calculate v using this library. Can anybody give me a hint?

1 Answers

Here is the life-saving code for everyone reads it afterward:

secp256k1_ecdsa_recoverable_signature rawSig;
int res = secp256k1_ecdsa_sign_recoverable(ctx, &rawSig, (uint8_t*) hash.data(), secret, NULL/*secp256k1_nonce_function_rfc6979*/, NULL);
if(!res)
{
    secp256k1_context_destroy(ctx);
    return false;
}

Signature sig;
v = 0;
secp256k1_ecdsa_recoverable_signature_serialize_compact(ctx, sig.data(), &v, &rawSig);
SignatureStruct& ss = *reinterpret_cast<SignatureStruct*>(&sig);
ss.v = static_cast<byte>(v);
if (ss.s > c_secp256k1n / 2)
{
    ss.v = static_cast<byte>(ss.v ^ 1);
    ss.s = h256(c_secp256k1n - u256(ss.s));
}

if (ss.s > c_secp256k1n / 2)
{
    secp256k1_context_destroy(ctx);
    return false;
}

char r[65], s[65];
r = byteArrayToCharArray(r, (uint8_t*) ss.r.data(), 32);
s = byteArrayToCharArray(s, (uint8_t*) ss.s.data(), 32);
v = ss.v % 2;

Note that you must have already compiled secp256k1 library with the recovery module enabled or you will get a linkage error.
I hope it helps somebody.

Related