Skip to content

Add 11 topics on tx signature #64

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jan 31, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
110 changes: 110 additions & 0 deletions decoding/transaction-signing-00.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
---
title: "Step 0: Create Base Transaction"
date: 2024-01-25
lastmod: "2024-01-25"
draft: false
category: Transactions
layout: TopicBanner
order: 0
icon: "FaClipboardList"
images:
[
"/bitcoin-topics/static/images/topics/thumbnails/transaction-module/signature/tx-thumbnail-signature-0.jpg"
]
---

In this step, we define the base structure of the transaction, which includes:

- Version (4 bytes)
- Marker/Flag (required for SegWit transactions)
- Locktime (4 bytes)

Inputs, outputs, and witness data will be added in the next steps.

<div className="dark:hidden w-full rounded-xl overflow-hidden full-width">
<SvgDisplay
src="/bitcoin-topics/static/images/topics/transactions/signature/signature6.svg"
width="100%"
height="auto"
/>
</div>
<div className="hidden dark:block w-full rounded-xl overflow-hidden full-width">
<SvgDisplay
src="/bitcoin-topics/static/images/topics/transactions/signature/signature6.svg"
width="100%"
height="auto"
/>
</div>

<ExpandableAlert
title="SegWit vs Legacy Transactions"
type="important"
expandable={true}
initialLines={3}
>
If a transaction has at least one SegWit input (native or wrapped), it must
include:
- Marker byte (0x00)
- Flag byte (0x01)
</ExpandableAlert>

The transaction structure at this stage is:

<CodeSnippet
language="text"
highlightLines={[4, 5, 6, 12]}
showLineNumbers={true}
code={`Transaction Breakdown:
═══════════════════════════════════════════════════════════════════════════════════

version: 01000000
marker: 00
flag: 01

in: # We'll add inputs in the next step

out: # We'll add outputs later

locktime: 11000000`}
/>

## Code Implementation

<CodeSnippet
code={`def create_basic_tx(
version: int,
inputs: list,
outputs: list,
locktime: int,
segwit: bool = True
) -> bytes:
# 4-byte version in little-endian
tx_version = int_to_little_endian(version, 4)

# Marker + Flag for segwit (only if segwit=True)
marker_flag = b'\\x00\\x01' if segwit else b''

# Number of inputs/outputs (varint)
in_count = varint(len(inputs))
out_count = varint(len(outputs))

# Serialize inputs and outputs
serialized_inputs = b''.join(inputs)
serialized_outputs = b''.join(outputs)

# Locktime (4 bytes)
tx_locktime = int_to_little_endian(locktime, 4)

return (
tx_version +
marker_flag +
in_count +
serialized_inputs +
out_count +
serialized_outputs +
tx_locktime
)`}
language="python"
/>

Let's now add inputs and outputs in the next step!
133 changes: 133 additions & 0 deletions decoding/transaction-signing-01.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
---
title: "Step 1: Create Transaction Inputs"
date: 2024-01-25
lastmod: "2024-01-25"
draft: false
category: Transactions
layout: TopicBanner
order: 1
icon: "FaClipboardList"
images:
[
"/bitcoin-topics/static/images/topics/thumbnails/transaction-module/signature/tx-thumbnail-signature-1.jpg"
]
---

Each input in a Bitcoin transaction must specify:

- Transaction ID (32 bytes): Points to the UTXO being spent
- Output Index (4 bytes): Which output from that transaction
- ScriptSig: Placeholder for the unlocking script
- Sequence (4 bytes): Usually 0xFFFFFFFF

<div className="w-full rounded-xl overflow-hidden full-width">
<SvgDisplay
src="/bitcoin-topics/static/images/topics/transactions/signature/signature7.svg"
width="100%"
height="auto"
/>
</div>

The following table summarizes our UTXOs (Transaction IDs shown in big-endian format):

| Input | Transaction ID (big-endian) | Output Index | Sequence |
| ----- | ---------------------------------------------------------------- | ------------ | -------- |
| #1 | 9f96add4e4db413543df3eea1781c3be62637f1e2dd44069fa99801a88f7f7ff | 0 | eeffffff |
| #2 | 8ac60eb9575db5b2d987e29f301b5b819ea83a5c6579d282d189cc04b8e151ef | 1 | ffffffff |

_Note: In the transaction serialization below, these Transaction IDs are converted to little-endian format as required by the Bitcoin protocol._

<CodeSnippet
language="text"
highlightLines={[6, 8, 9, 10, 11, 12, 13, 15, 16, 17, 18, 19, 20]}
showLineNumbers={true}
code={`Transaction Breakdown:
═══════════════════════════════════════════════════════════════════════════════════

Version: 01000000

Input Count: 02

input[0]:
Previous TXID: fff7f7881a8099afa6940d42d1e7f6362bec38171ea3edf433541db4e4ad969f
Output Index: 00000000
ScriptSig Size: 00
ScriptSig:
Sequence: eeffffff

input[1]:
Previous TXID: ef51e1b804cc89d182d279655c3aa89e815b1b309fe287d9b2b55d57b90ec68a
Output Index: 01000000
ScriptSig Size: 00
ScriptSig:
Sequence: ffffffff

Locktime: 11000000`}
/>

<ExpandableAlert
title="Why are scriptSig fields empty?"
type="info"
expandable={true}
>
Transaction signing follows a specific order:
1. First, we create the
transaction structure with empty scriptSig fields
2. Then, we calculate the
signature hash (sighash) for each input
3. Finally, we add the signatures to
create the complete transaction
</ExpandableAlert>

## Code Implementation

<CodeSnippet
code={`def create_input(
txid: str,
vout: int,
script_sig: bytes = b'',
sequence: bytes = b'\\xff\\xff\\xff\\xff'
) -> bytes:
# Convert txid from hex string and reverse (to little-endian)
txid_bytes = bytes.fromhex(txid)[::-1]

# Convert vout to 4 bytes, little-endian
vout_bytes = int_to_little_endian(vout, 4)

# Script length and script
script_sig_length = varint(len(script_sig))

return (
txid_bytes + # 32 bytes
vout_bytes + # 4 bytes
script_sig_length + # 1 byte
script_sig + # variable
sequence # 4 bytes
)`}
language="python"
/>

<ExpandableAlert title="Helper Functions" type="info" expandable={true}>
Two essential encoding functions:
1. int_to_little_endian: Converts integers to little-endian byte format
2. varint: Encodes variable-length integers used for counts and lengths

<CodeSnippet
code={`def int_to_little_endian(value: int, length: int) -> bytes:
"""Convert an integer to little-endian bytes"""
return value.to_bytes(length, 'little')

def varint(n: int) -> bytes:
"""Encode an integer as a variable length integer"""
if n < 0xfd:
return bytes([n])
elif n <= 0xffff:
return b'\\xfd' + n.to_bytes(2, 'little')
elif n <= 0xffffffff:
return b'\\xfe' + n.to_bytes(4, 'little')
else:
return b'\\xff' + n.to_bytes(8, 'little')`}
language="python"
/>

</ExpandableAlert>
113 changes: 113 additions & 0 deletions decoding/transaction-signing-02.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
---
title: "Step 2: Create Transaction Outputs"
date: 2024-01-25
lastmod: "2024-01-25"
draft: false
category: Transactions
layout: TopicBanner
order: 2
icon: "FaClipboardList"
images:
[
"/bitcoin-topics/static/images/topics/thumbnails/transaction-module/signature/tx-thumbnail-signature-2.jpg"
]
---

Each output in a Bitcoin transaction requires:

- Amount (8 bytes): Value in satoshis
- ScriptPubKey: Locking script that defines spending conditions

<div className="w-full rounded-xl overflow-hidden full-width">
<SvgDisplay
src="/bitcoin-topics/static/images/topics/transactions/signature/signature8.svg"
width="100%"
height="auto"
/>
</div>

---

## Code Implementation

<CodeSnippet
code={`def create_output(
amount: int,
script_pubkey: bytes
) -> bytes:
# Amount (8 bytes, little-endian)
amount_bytes = int_to_little_endian(amount, 8)

return (
amount_bytes + # value in satoshis
script_pubkey # includes length prefix
)`}
language="python"
/>

The following table summarizes our outputs from test vector:

| Output | Amount (BTC) | ScriptPubKey |
| ------ | ------------ | ---------------------------------------------------- |
| #1 | 1.2 | 1976a9148280b37df378db99f66f85c95a783a76ac7a6d5988ac |
| #2 | 2.2 | 1976a9143bde42dbee7e4dbe6a21b2d50ce2f0167faa815988ac |

Our transaction structure at this stage is:

<CodeSnippet
language="text"
highlightLines={[22, 24, 25, 26, 27, 29, 30, 31, 32]}
showLineNumbers={true}
code={`Transaction Breakdown:
═══════════════════════════════════════════════════════════════════════════════════

Version: 01000000

Input Count: 02

input[0]:
Previous TXID: fff7f7881a8099afa6940d42d1e7f6362bec38171ea3edf433541db4e4ad969f
Output Index: 00000000
ScriptSig Size: 00
ScriptSig:
Sequence: eeffffff

input[1]:
Previous TXID: ef51e1b804cc89d182d279655c3aa89e815b1b309fe287d9b2b55d57b90ec68a
Output Index: 01000000
ScriptSig Size: 00
ScriptSig:
Sequence: ffffffff

Output Count: 02

output[0]:
Amount: 202cb20600000000
ScriptPubKey Size: 19
ScriptPubKey: 76a9148280b37df378db99f66f85c95a783a76ac7a6d5988ac

output[1]:
Amount: 9093510d00000000
ScriptPubKey Size: 19
ScriptPubKey: 76a9143bde42dbee7e4dbe6a21b2d50ce2f0167faa815988ac

Locktime: 11000000`}
/>

## Test Vector from BIP-143

Let's test our code with the test vector from the <a href="https://github.com/bitcoin/bips/blob/58ffd93812ff25e87d53d1f202fbb389fdfb85bb/bip-0143.mediawiki?plain=1#L146" target="_blank">official BIP143 proposal</a>.

<div className="flex justify-center items-center w-full full-width">
<iframe
src="https://trinket.io/embed/python3/e3098585e3c8"
width="100%"
height="100%"
style={{
border: "none",
margin: 0
}}
allowFullScreen
className="rounded-md shadow-sm h-[calc(50vh)]"
></iframe>
</div>
Loading