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?
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.