Author

Topic: Extract the Public Key from a "CScript CTxIn::scriptSig" object (Read 153 times)

member
Activity: 351
Merit: 37
you need tx as block of bytes. Then you can go after pubscript.
Code:
struct Transaction {
#pragma pack(1)
/* +0 */uint32_t version = 1;    /* vs bitcoin-api tx block : merkleHash[32] removed */
uint8_t  numInputs = 1;
uint8_t  prevOutput[32];
uint32_t prevoutIndex = 0xFFFFFFFF; // +41
/* +0 */uint32_t sequence = 0xFFFFFFFF;
uint8_t  numOutputs = 1;
uint64_t outValue = 50*COIN;
uint8_t  pubscriptlength = ::pubscriptlength; //it isn't in the bitcoin-api tx block also
uint8_t  pubkeyScript[::pubscriptlength];
uint32_t locktime = 0;   // +85
} ;

and then
Code:
	transaction.pubkeyScript[0] = 0x41;
hex2bin(transaction.pubkeyScript + 1, pubkey.c_str(), pubkey.length()/2); // pubkey to bytes ,  then append the OP_CHECKSIG byte
transaction.pubkeyScript[pubscriptlength - 1] = OP_CHECKSIG;

So reverse-engineer this.

https://github.com/alexeyneu/BlockZero/blob/master/BlockZero.cpp#L17-L29
newbie
Activity: 6
Merit: 18
Thanks for your detailed answer.

Yes, I understand that "CPubKey pubkey(vchPubKey);" would work on "bool EvalScript(...)", but I am trying to extract the public key from "CScript CTxIn::scriptSig" inside "CWallet::AddToWalletIfInvolvingMe(const CTransactionRef& ptx, ...)", where I have access to the scriptSig from the transaction inputs ("CTransaction::vin") and to the "CWallet::chain()", where I can retrieve the coins (`class Coin`) related to an input and get the "Coin::CTxOut:: scriptPubKey" if necessary (perhaps to infer the transaction type?).

1) and 3) For SegWit version 0 scripts (P2PWKH and P2SH-P2WPKH), I think the data will be in "CScriptWitness CTxIn::scriptWitness" and not in "CScript scriptSig". The same may apply to P2TR transactions (SegWit version 1).

2) For legacy address (P2PKH, P2SH and P2PK) I think  it will be in "CScript CTxIn::scriptSig".

So I would like to extract the Public Key inside "CWallet::AddToWalletIfInvolvingMe(const CTransactionRef& ptx, ...)". The reason is to do an ECDH operation with other keys.

I think this issue is already solved at some point in the code as it is necessary to evaluate the script, but I haven't been able to find this logic so far.
legendary
Activity: 3472
Merit: 10611
The stacktop(-1) method is peeking at the topmost element on the stack and interprets it as a public key without removing it from the stack. The popstack(stack); removes it from the stack later on.
If you want to extract it, you could potentially change the code and add a line right after the valtype& vchPubKey = stacktop(-1); and get the public key.
Code:
CPubKey pubkey(vchPubKey);
    if (pubkey.IsValid())
        // do whatever!
    else
        // fail

I'm particularly interested in extracting the public key of "CScript CTxIn::scriptSig" from P2PKH, P2WPKH, P2TR.
2) Legacy scripts (P2PKH and P2SH) will have public key in their signature script or it may already by in the pubkey script (P2PK).

1) SegWit version 0 scripts will have the pubkey (+ everything else) always in their witness and the signature script will be empty for P2WPKH and P2WSH and will contain the witness program for wrapped SegWit ie. P2SH-P2PKH and P2SH-P2WSH

3) Taproot scripts will have a tweaked public key in their pubkey script (the output) and the signature (+ everything else) in their witness

For all cases OP_CHECKSIG(VERIFY) could be run and consumes a public key.
For 1 & 2 OP_CHECKMULTISIG(VERIFY) could be run and consumes one or more public keys.
For 3 OP_CHECKSIGADD could also be run if it is found in the script that consumes a public key.


Why are you trying to extract public keys?
newbie
Activity: 6
Merit: 18
Thanks for your reply.
But I assume the steps you mentioned already exists in the code (or something like that) as the "src/script/interpreter.cpp::EvalChecksig(...)" needs the public key(s) to process the OP_CHECKSIG and OP_CHECKMULTISIG operation codes.

Code:
bool EvalScript(std::vector >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptExecutionData& execdata, ScriptError* serror)
{
    // ...
    case OP_CHECKSIG:
    case OP_CHECKSIGVERIFY:
    {
        // ....
        valtype& vchSig    = stacktop(-2);
        valtype& vchPubKey = stacktop(-1);

But I couldn't find the part of the code where the public key is extracted from the scriptSig and inserted into the script stack. I've tried debugging and grep to "stack.push_back("  but no good results.

I'm particularly interested in extracting the public key of "CScript CTxIn::scriptSig" from P2PKH, P2WPKH, P2TR.
legendary
Activity: 3472
Merit: 10611
You first have to know what the content of a scriptsig is. It could simply be empty, a wrapped witness program or any other script without a public key. Then you have to evaluate the whole script (scriptpub + scriptsig) and when you reach one of the OP_CHECK(MULTI)SIG(VERIFY) codes figure out which item(s) on is the public key.
newbie
Activity: 6
Merit: 18
In Bitcoin Core code, how can the Public Key ("class CPubKey" or "class XOnlyPubKey") be extracted from a "CScript CTxIn::scriptSig" object ?

Jump to: