0

I have a software system where signing ETH transactions happens in a black box. I give the information required, and it returns to me a DER-signature (30|totalLen|02|lenR|R|02|lenS|S).

Now I'm aware of the signature V value, which for EIP-155 transactions used to be the recId + (2 * chainId + 35). I determined this using web3.js and @ethereumjs/tx libraries with the following piece of code:

    const ethAddress = '0x123ba3f3.....3a4f1d8';
    ethjsTx.v = recId + 35 + 2 * chainId;
    const rawTx = ethjsTx.serialize().toString(16);
    const recoveredAddress = this.web3.accounts.recoverTransaction(rawTx);
    return recoveredAddress === ethAddress;

I just repeat this for 2 different recId values (0,1) until it returns true, and then I'll know the V-value.

For EIP-1559, the chainId is no longer relevant to the V value. V is simply the Y-parity of the signature. Now my question is how to find out this Y-value from a DER signature.

In this repository @line 290:

https://github.com/ethereum/go-ethereum/blob/master/crypto/secp256k1/libsecp256k1/src/ecdsa_impl.h

is the following code:

    if (recid) {
        /* The overflow condition is cryptographically unreachable as hitting it requires finding the discrete log
         * of some P where P.x >= order, and only 1 in about 2^127 points meet this criteria.
         */
        *recid = (overflow ? 2 : 0) | (secp256k1_fe_is_odd(&r.y) ? 1 : 0);
    }

They check whether r.y is odd, which is the value I need. Problem is, my R is a 32-byte hexadecimal, whereas in that code, r is an object with a separate y property. My questions are:

  1. How can I obtain this Y-value from my hexadecimal R string?
  2. Or could I also just refactor my old function like this:
    const ethAddress = '0x123ba3f3.....3a4f1d8';
    ethjsTx.v = 0 or 1;
    const rawTx = ethjsTx.serialize().toString(16);
    const recoveredAddress = this.web3.accounts.recoverTransaction(rawTx);
    return recoveredAddress === ethAddress;

and go with that instead? It just seems kinda inefficient.

0

I was looking for some way to directly acquire the Y-parity, instead of recovering it after the fact. Did some research after posting this question, particularly on this article:

http://coders-errand.com/details-of-ecdsa-signatures/

So apparently R and S are calculated using several different values. One of these values is the X-coordinate of a randomly chosen point on an Elliptic Curve. This randomly chosen point also has a Y-coordinate, but it is unused in the calculations. Still, this point is the one we need. But to extract it, you'd need to modify the signing code to return this y-parity point, which is not worth it in my case. Maybe if you want to micro-optimize you could pursue this course of action.

On top of that, Ethereum's Yellow Paper specifies the erecover() function used in Solidity to check whether a signature is valid for the given sending address. So to extract the address from the signed transaction is intended behaviour, therefore I think my original method, to try both 0 and 1 and check the public key, is good enough for me.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.