3

I'm studying the segwit part, and I want to sign P2WSH (native) manually (openssl).

I just read the BIP0143 and I see the new transaction digest.

Double SHA256 of the serialization of:
     1. nVersion of the transaction (4-byte little endian)
     2. hashPrevouts (32-byte hash)
     3. hashSequence (32-byte hash)
     4. outpoint (32-byte hash + 4-byte little endian) 
     5. scriptCode of the input (serialized as scripts inside CTxOuts)
     6. value of the output spent by this input (8-byte little endian)
     7. nSequence of the input (4-byte little endian)
     8. hashOutputs (32-byte hash)
     9. nLocktime of the transaction (4-byte little endian)
    10. sighash type of the signature (4-byte little endian

I'm using regtest and I create a transaction from my P2WSH to P2WPKH where I move ~49.999991 bitcoins.

It's my UTXO

   020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff03510101ffffffff0200f2052a01000000220020896386cc04087d76450a506b09e88de6d68bba45f50c4967818e6fd10e6eaade0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000
{
  "txid": "0237415f2eb789a48e43ed68862ea9db3455f7b21203f4b526cd88b970b1329b",
  "hash": "76069338f9fd11b43901b6b5260e6b279dd26071148643a1b31fc41190dc73f1",
  "version": 2,
  "size": 180,
  "vsize": 153,
  "weight": 612,
  "locktime": 0,
  "vin": [
    {
      "coinbase": "510101",
      "sequence": 4294967295
    }
  ],
  "vout": [
    {
      "value": 50,
      "n": 0,
      "scriptPubKey": {
        "asm": "0 896386cc04087d76450a506b09e88de6d68bba45f50c4967818e6fd10e6eaade",
        "hex": "0020896386cc04087d76450a506b09e88de6d68bba45f50c4967818e6fd10e6eaade",
        "reqSigs": 1,
        "type": "witness_v0_scripthash",
        "addresses": [
          "bcrt1q393cdnqypp7hv3g22p4sn6ydumtghwj975xyjeup3ehazrnw4t0q7p0v3p"
        ]
      }
    },
    {
      "value": 0,
      "n": 1,
      "scriptPubKey": {
        "asm": "OP_RETURN aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf9",
        "hex": "6a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf9",
        "type": "nulldata"
      }
    }
  ],
  "hex": "020000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff03510101ffffffff0200f2052a01000000220020896386cc04087d76450a506b09e88de6d68bba45f50c4967818e6fd10e6eaade0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf90120000000000000000000000000000000000000000000000000000000000000000000000000",
  "blockhash": "42f85575b186494c8ac18487a0f21f4645346c6d9740d17f764a8a56e74fa2e3",
  "confirmations": 101,
  "time": 1587537959,
  "blocktime": 1587537959
}

My raw transaction data is:

02000000019b32b170b988cd26b5f40312b2f75534dba92e8668ed438ea489b72e5f4137020000000000ffffffff017cee052a01000000160014f545040775837a55962bb8abfcc341f574d6791700000000

And I create the new transaction digest like this:

    TX_VERSION: 02000000
    OUTPOINT: 9b32b170b988cd26b5f40312b2f75534dba92e8668ed438ea489b72e5f41370200000000
    HASH_PREV_OUT: b98dd14dcfff442ee1562d70b507402d6ba089dc8af7fe0360f422ff5d60a206
(HASH_PREV_OUT is SHA256 twice of $OUTPOINT)
    SEQUENCE: ffffffff
    HASH_SEQUENCE: 3bb13029ce7b1f559ef5e747fcac439f1455a2ec7c5f09b72290795e70665044
(HASH_SEQUENCE is SHA256 twice of $SEQUENCE)
    SCRIPTCODE: 1976a91427275283377b40957701cecd37d2e170c41d387488AC
    AMOUNT: 00f2052a01000000
 (TOTAL AMOUNT - 50 bitcoin )
    OUTPUT: 160014f545040775837a55962bb8abfcc341f574d67917
    OUTPUT_HASH: 9fbf0bcf967eb3f1fcd41f60ce73e69f8b5073185ff81f787d9caac0e5992fd2
(OUTPUT_HASH is SHA256 twice of $AMOUNT$OUTPUT)
    LOCKTIME_PART: 00000000
    SIGHASH: 01000000

Where SCRIPT-CODE is my UTXO witness script (the script is P2PKH) Then I "merge" all values like this:

$ WITNESS_V0_DIGEST=$TX_VERSION$HASH_PREV_OUT$HASH_SEQUENCE$OUTPOINT$SCRIPTCODE$AMOUNT$SEQUENCE$OUTPUT_HASH$LOCKTIME_PART$SIGHASH
$ echo $WITNESS_V0_DIGEST
02000000b98dd14dcfff442ee1562d70b507402d6ba089dc8af7fe0360f422ff5d60a2063bb13029ce7b1f559ef5e747fcac439f1455a2ec7c5f09b72290795e706650449b32b170b988cd26b5f40312b2f75534dba92e8668ed438ea489b72e5f413702000000001976a91427275283377b40957701cecd37d2e170c41d387488AC00f2052a01000000ffffffff9fbf0bcf967eb3f1fcd41f60ce73e69f8b5073185ff81f787d9caac0e5992fd20000000001000000

Then I can do the double SHA56 and sign it:

printf $WITNESS_V0_DIGEST | xxd -r -p | sha256sum -b | xxd -r -p | sha256sum -b | xxd -r -p > WITNESS_V0_DIGEST.txt

SIGNATURE=`openssl pkeyutl -inkey private_key_1.pem -sign -in WITNESS_V0_DIGEST.txt -pkeyopt digest:sha256 | xxd -p -c 256`

SIGNATURE="${SIGNATURE}01"

Now I can create my transaction like this:

020000000001019b32b170b988cd26b5f40312b2f75534dba92e8668ed438ea489b72e5f4137020000000000ffffffff017cee052a01000000160014f545040775837a55962bb8abfcc341f574d679170347304402202d7d72d425e407160554e9c29688164a7e5c2f380c86e26c0595a7c6c8d526df02206ff13970212a77d6febcdcdcc2945db3947f02137324ae7d822b4fa7f81292100121024633c32245c6709e7f756c41e0f163919fa00977798f30245d3498f88c53e8941976a91427275283377b40957701cecd37d2e170c41d387488AC00000000

It's the decoded version

     {
  "txid": "23704afa715351b1d1810f41015fd3bfc33fed75842530ae0c00564eb7f16103",
  "hash": "5f6b1edafdd814d8c9ec85bad6125dbf2efbb245c28017b62ee4aa35ab712789",
  "version": 2,
  "size": 217,
  "vsize": 116,
  "weight": 463,
  "locktime": 0,
  "vin": [
    {
      "txid": "0237415f2eb789a48e43ed68862ea9db3455f7b21203f4b526cd88b970b1329b",
      "vout": 0,
      "scriptSig": {
        "asm": "",
        "hex": ""
      },
      "txinwitness": [
        "304402202d7d72d425e407160554e9c29688164a7e5c2f380c86e26c0595a7c6c8d526df02206ff13970212a77d6febcdcdcc2945db3947f02137324ae7d822b4fa7f812921001",
        "024633c32245c6709e7f756c41e0f163919fa00977798f30245d3498f88c53e894",
        "76a91427275283377b40957701cecd37d2e170c41d387488ac"
      ],
      "sequence": 4294967295
    }
  ],
  "vout": [
    {
      "value": 49.999991,
      "n": 0,
      "scriptPubKey": {
        "asm": "0 f545040775837a55962bb8abfcc341f574d67917",
        "hex": "0014f545040775837a55962bb8abfcc341f574d67917",
        "reqSigs": 1,
        "type": "witness_v0_keyhash",
        "addresses": [
          "bcrt1q74zsgpm4sda9t93thz4les6p746dv7gh4jhqxz"
        ]
      }
    }
  ]
}

But when I try to send it (sendrawtransaction), I get this error:

error code: -26
error message:
non-mandatory-script-verify-flag (Signature must be zero for failed CHECK(MULTI)SIG operation) (code 64)
2

Where SCRIPT-CODE is my UTXO scriptpubkey hex (witness version-witness program) Then I "merge" all values like this:

This is your problem. Like P2SH, the scriptCode for P2WSH is not the scriptPubKey. It is the script that that P2WSH output has the hash of. So the scriptCode is the witnessScript in this case, not the scriptPubKey.

| improve this answer | |
  • thanks for reply. I tried with witness script instead of hash (I'm using p2pkh for script) then my scriptCode become (SCRIPTCODE: 76a914b32be131fb46d9e937f52be3fff9df7e4cca63cf88AC). But I get the same error non-mandatory-script-verify-flag (Signature must be zero for failed CHECK(MULTI)SIG operation) (code 64) thanks! – monkeyUser Apr 20 at 7:00
  • 1
    Can you edit your question with the results of doing that change? – Andrew Chow Apr 20 at 16:15
  • sure! I updated my question. Thanks – monkeyUser Apr 20 at 17:56
  • 1
    The scriptCode needs to be length prefixed with a compact size unsigned int. – Andrew Chow Apr 20 at 23:16
  • 1
    Now your hashOutputs is incorrect. You are using the wrong amount in that hash. hashOutputs is the hash of the outputs as they are serialized. For each output, it's its amount followed by the output script, regardless of the amount for the input being signed. What you have done is used the amount for the input being signed. This is incorrect. In hashOutputs, you need to use 49.99.... In the sighash amount field, you need to use 50. – Andrew Chow Apr 22 at 16:11

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.