3

I am trying to create a Segwit transaction on TESTNET from scratch while referencing an online guide: https://medium.com/coinmonks/creating-and-signing-a-segwit-transaction-from-scratch-ec98577b526a

My BIP-39 mnemonics code:

differ toast alert candy orbit raccoon wagon hour thunder kiwi home cigar

My TESTNET BIP-32 master public key derived Segwit Bech32 address with derivation path 'm':

tb1qzjgctgz9t98dmkwp4z26whg6tl4w9s6rl6hwwj

The address profile can be viewed from here.

Just for simplicity of debugging, the derivation 'm' will be used only.

For more context the Master Public Key compressed format:

03D7DE86033E1C815BA0E3589938B7AC906B728F1F2C771542E203E32B80A3385A

For more context the Master Public Key uncompressed format:

04D7DE86033E1C815BA0E3589938B7AC906B728F1F2C771542E203E32B80A3385AE1DEED79187355D35FDABAF74DFD186A8B8C9FE1D6357AA46750A47B86ED16CF

The raw BIP-32 Seed:

1CD4561EF82D35F9EE2E95ED63B68BB91ADA8967E1D98FA4080637A4CC310BE99DD285F82F45EE004ADC408F8B93C2A829A5B811104496A6FB0301E062CBC813

The raw Master Private Key used for the digital signing later:

13D84CAC526896CEF2594D71621D2AEDC90F9DAEA88A1751AD99E35868E0021B

I would like to send myself (tb1qzjgctgz9t98dmkwp4z26whg6tl4w9s6rl6hwwj) some funds (0x5503000000000000 / 853 satoshis) using my own address (tb1qzjgctgz9t98dmkwp4z26whg6tl4w9s6rl6hwwj).

So, I begin to create the Segwit inputs that would then be double-SHA256 hashed then signed.

It follows the BIP143 defined steps:

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)

// 1.  nVersion of the transaction (4-byte little endian)
<<< 01000000

// 2.  hashPrevouts (32-byte hash)
>>> printf "4E2F5CCED0DC6D7B229AB43381A7DDBAB759C457C3366D8435782120493133A0 00000000" | xxd -p -r | sha256sum -b | xxd -p -r | sha256sum -b

<<< 04dc164c0a705f5d2d57fd42e6896a94394e6966ed0b116a64adfaa9310b848f

//  3.  hashSequence (32-byte hash)

>>> printf "ffffffff" | xxd -p -r | sha256sum | xxd -p -r | sha256sum

<<< 3bb13029ce7b1f559ef5e747fcac439f1455a2ec7c5f09b72290795e70665044

//  4.  outpoint (32-byte hash + 4-byte little endian) 

<<< 4E2F5CCED0DC6D7B229AB43381A7DDBAB759C457C3366D8435782120493133A0 00000000

//  5.  scriptCode of the input (serialized as scripts inside CTxOuts)

<<< 1976a914149185A045594EDDD9C1A895A75D1A5FEAE2C34388ac

//  6.  value of the output spent by this input (8-byte little endian)

<<< e803000000000000

//  7.  nSequence of the input (4-byte little endian)

<<< ffffffff

// 8.  hashOutputs (32-byte hash)
          
>>> printf "e803000000000000 16 0014149185A045594EDDD9C1A895A75D1A5FEAE2C343" | xxd -p -r | sha256sum -b | xxd -p -r | sha256sum -b

<<< 7c007a193409e64199438db0ba4349809fbcc42c17e7167cbc06deec4cc0998f

// 9.  nLocktime of the transaction (4-byte little endian)
<<< 00000000

// 10. sighash type of the signature (4-byte little endian)
<<< 01000000

// Hashing with double Sha256

>>> printf 0100000004dc164c0a705f5d2d57fd42e6896a94394e6966ed0b116a64adfaa9310b848f3bb13029ce7b1f559ef5e747fcac439f1455a2ec7c5f09b72290795e706650444E2F5CCED0DC6D7B229AB43381A7DDBAB759C457C3366D8435782120493133A0000000001976a914149185A045594EDDD9C1A895A75D1A5FEAE2C34388ace803000000000000ffffffff7c007a193409e64199438db0ba4349809fbcc42c17e7167cbc06deec4cc0998f0000000001000000 | xxd -p -r | sha256sum -b | xxd -p -r | sha256sum -b

<<< c2636fae9487354f47e4e92458a7e856f717533c6d01e1c5fda5b06c4a1976a8

The encoded digital signature result:

30450221008B61503427B2292F781405712DF878B207D8B89FC86D60B1A68D479CA6C6FF2302203BB1F7F5F7E2B9050BA481310C997F6F078F5ED25564AEC85277EB56BA98FD76

Finally, formatted into a raw transaction below:

010000000001014E2F5CCED0DC6D7B229AB43381A7DDBAB759C457C3366D8435782120493133A00000000000FFFFFFFF015503000000000000160014149185A045594EDDD9C1A895A75D1A5FEAE2C343024830450221008B61503427B2292F781405712DF878B207D8B89FC86D60B1A68D479CA6C6FF2302203BB1F7F5F7E2B9050BA481310C997F6F078F5ED25564AEC85277EB56BA98FD76012103D7DE86033E1C815BA0E3589938B7AC906B728F1F2C771542E203E32B80A3385A00000000

The broadcast results throws the following error:

sendrawtransaction RPC error: {"code":-26,"message":"non-mandatory-script-verify-flag (Signature must be zero for failed CHECK(MULTI)SIG operation)"}

I have checked the digital signatures many times and ran validation on the signatures and public key with assumption that all the above addresses and scripts are valid.

How do I fix the failed broadcast ? What are the causes of the failed broadcast ?

1 Answer 1

1

OK, finally I got some things to work and there are quite some changes I had to make but it seems to have work.

I need to retrace my steps all over again later on tomorrow as its late now.

Here's the TESTNET transaction txid: e559b79981b5bcde2df389f37e2b72e5d6a132748c6dab499d10f5186568533f

Also, while trying every means to mint this transaction, it raises more questions than answers at the same time. There's quite a few "waht-ifs corner cases" I have in mind.

Firstly, I need to create a PEM file containing the private key so that I can use OpenSSL to sign the transaction later on. This is an optional step.

printf "302e0201010420 13D84CAC526896CEF2594D71621D2AEDC90F9DAEA88A1751AD99E35868E0021B a00706052b8104000a" | xxd -p -r > priv1.hex

openssl ec -inform d < priv1.hex > priv1.pem

The private key in the original post is added into a PEM format file. If you are not using OpenSSL to sign, you can omit this step.

Next is the usual layout of 10 steps.

// 1.  nVersion of the transaction (4-byte little endian)
<<< 01000000

// 2.  hashPrevouts (32-byte hash)
>>> printf "4E2F5CCED0DC6D7B229AB43381A7DDBAB759C457C3366D8435782120493133A0 00000000" | xxd -p -r | sha256sum -b | xxd -p -r | sha256sum -b

<<< 04dc164c0a705f5d2d57fd42e6896a94394e6966ed0b116a64adfaa9310b848f

//  3.  hashSequence (32-byte hash)

>>> printf "FDFFFFFF" | xxd -p -r | sha256sum | xxd -p -r | sha256sum

<<< caf35e5224de16efa3ccaf41070f6e7b9432b6f79551e629fca9d1c03b43bc52

//  4.  outpoint (32-byte hash + 4-byte little endian) 

<<< 4E2F5CCED0DC6D7B229AB43381A7DDBAB759C457C3366D8435782120493133A0 00000000

//  5.  scriptCode of the input (serialized as scripts inside CTxOuts)

<<< 1976A914149185A045594EDDD9C1A895A75D1A5FEAE2C34388AC

//  6.  value of the output spent by this input (8-byte little endian)

<<< e803000000000000

//  7.  nSequence of the input (4-byte little endian)

<<< FDFFFFFF

// 8.  hashOutputs (32-byte hash)
          
>>> printf "01000000000000001976A914149185A045594EDDD9C1A895A75D1A5FEAE2C34388AC54030000000000001976A914149185A045594EDDD9C1A895A75D1A5FEAE2C34388AC" | xxd -p -r | sha256sum -b | xxd -p -r | sha256sum -b

<<< 91f7bd32e352f7cc0cb49cbdf9f7d0f51f27a4da527c094b2ab85c2e2e0ae47f

// 9.  nLocktime of the transaction (4-byte little endian)
<<< 00000000

// 10. sighash type of the signature (4-byte little endian)
<<< 01000000

Next is the serialization of the hash pre-image by concatenating all the steps results above:

0100000004dc164c0a705f5d2d57fd42e6896a94394e6966ed0b116a64adfaa9310b848fcaf35e5224de16efa3ccaf41070f6e7b9432b6f79551e629fca9d1c03b43bc524E2F5CCED0DC6D7B229AB43381A7DDBAB759C457C3366D8435782120493133A0000000001976A914149185A045594EDDD9C1A895A75D1A5FEAE2C34388ACe803000000000000FDFFFFFF91f7bd32e352f7cc0cb49cbdf9f7d0f51f27a4da527c094b2ab85c2e2e0ae47f0000000001000000

Next is the double hashing of the hash pre-image:

// Double hashing and storing double hashed result

>>> printf 0100000004dc164c0a705f5d2d57fd42e6896a94394e6966ed0b116a64adfaa9310b848fcaf35e5224de16efa3ccaf41070f6e7b9432b6f79551e629fca9d1c03b43bc524E2F5CCED0DC6D7B229AB43381A7DDBAB759C457C3366D8435782120493133A0000000001976A914149185A045594EDDD9C1A895A75D1A5FEAE2C34388ACe803000000000000FDFFFFFF91f7bd32e352f7cc0cb49cbdf9f7d0f51f27a4da527c094b2ab85c2e2e0ae47f0000000001000000 | xxd -p -r | sha256sum -b | xxd -p -r | sha256sum -b | xxd -p -r > msg-segwit

Next is using the PEM private key to sign in OpenSSL with a SHA-256 digest:

// Signing

>>> openssl pkeyutl -inkey priv1.pem -sign -in msg-segwit -pkeyopt digest:sha256 | xxd -p -c 256

<<< 30450221008f56dd07c3637ba6bc00e4e8e05bd2e9c3d6a5c073201df8aaf52e9847d0e01c0220752381278c83287c975a147b20daef443f68d85c84650ab2d061375b6f6ef739

Append your sighash (SIGHASH_ALL - 0x01) to the back of the signature:

<<< 30450221008f56dd07c3637ba6bc00e4e8e05bd2e9c3d6a5c073201df8aaf52e9847d0e01c0220752381278c83287c975a147b20daef443f68d85c84650ab2d061375b6f6ef739 01

Finally, serialize and merge all the transaction data with the digital signature into a single transaction:

// Serialization

01000000 // version
0001 // witness

01 // 1 input

4E2F5CCED0DC6D7B229AB43381A7DDBAB759C457C3366D8435782120493133A0 00000000 // outpoint with output index
00 // 0 bytes script
FDFFFFFF // sequence

02 // 2 outputs

0100000000000000 // output amount
1976A914149185A045594EDDD9C1A895A75D1A5FEAE2C34388AC // output script
5403000000000000 // output amount
1976A914149185A045594EDDD9C1A895A75D1A5FEAE2C34388AC // output script

02 // First input has witness script of 2 elements

48 // signature length
30450221008f56dd07c3637ba6bc00e4e8e05bd2e9c3d6a5c073201df8aaf52e9847d0e01c0220752381278c83287c975a147b20daef443f68d85c84650ab2d061375b6f6ef739 01 // signature with sighash (01) 
21 // compressed pubkey length
03D7DE86033E1C815BA0E3589938B7AC906B728F1F2C771542E203E32B80A3385A // compressed pubkey

00000000 // Locktime

<<< 010000000001014E2F5CCED0DC6D7B229AB43381A7DDBAB759C457C3366D8435782120493133A00000000000FDFFFFFF0201000000000000001976A914149185A045594EDDD9C1A895A75D1A5FEAE2C34388AC54030000000000001976A914149185A045594EDDD9C1A895A75D1A5FEAE2C34388AC024830450221008f56dd07c3637ba6bc00e4e8e05bd2e9c3d6a5c073201df8aaf52e9847d0e01c0220752381278c83287c975a147b20daef443f68d85c84650ab2d061375b6f6ef739012103D7DE86033E1C815BA0E3589938B7AC906B728F1F2C771542E203E32B80A3385A00000000

End Result:

  • A transaction (txid is on top of this post in the link) manages to fire off successfully.
  • The targeted receipt addresses are INCORRECT in the transaction. I will need to figure out again on the txouts side and update here again.

What changed:

  • Step 3 & 7. Hash Sequence & nSequence. The input transaction (a033314920217835846d36c357c459b7badda78133b49a227b6ddcd0ce5c2f4e) utilizes an nSequence of (0xfffffffd) which after formatting will become (0xFDFFFFFF) so the step 3 for hashSequence has changed. Subsequently its double hash for this step also changed.
  • Step 8. Hash Outputs & Outputs. For the original outputs, I used e803000000000000 16 0014149185A045594EDDD9C1A895A75D1A5FEAE2C343 which is the amount to spent in little endian with the Bitcoin opcodes of OP_0 <pubkey hash> but I changed it to the OP_DUP OP_HASH160 OP_PUSHBYTES_20 <pubkey hash> OP_EQUALVERIFY OP_CHECKSIG. I have added two transactions but the recipient address is not what I want so this has to be updated later on.

Future Questions:

  • What happens if there is an input with vins containing multiple inputs and each vins input uses a different nSequence, then which nSequence should be used to generate the transaction signature ?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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