Skip to content

Commit 343a199

Browse files
authored
Merge pull request #64 from jrakibi/01-02-siganture-topics
Add 11 topics on tx signature
2 parents 97fbb96 + 8045533 commit 343a199

32 files changed

+1765
-42
lines changed

decoding/transaction-signing-00.mdx

+110
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
---
2+
title: "Step 0: Create Base Transaction"
3+
date: 2024-01-25
4+
lastmod: "2024-01-25"
5+
draft: false
6+
category: Transactions
7+
layout: TopicBanner
8+
order: 0
9+
icon: "FaClipboardList"
10+
images:
11+
[
12+
"/bitcoin-topics/static/images/topics/thumbnails/transaction-module/signature/tx-thumbnail-signature-0.jpg"
13+
]
14+
---
15+
16+
In this step, we define the base structure of the transaction, which includes:
17+
18+
- Version (4 bytes)
19+
- Marker/Flag (required for SegWit transactions)
20+
- Locktime (4 bytes)
21+
22+
Inputs, outputs, and witness data will be added in the next steps.
23+
24+
<div className="dark:hidden w-full rounded-xl overflow-hidden full-width">
25+
<SvgDisplay
26+
src="/bitcoin-topics/static/images/topics/transactions/signature/signature6.svg"
27+
width="100%"
28+
height="auto"
29+
/>
30+
</div>
31+
<div className="hidden dark:block w-full rounded-xl overflow-hidden full-width">
32+
<SvgDisplay
33+
src="/bitcoin-topics/static/images/topics/transactions/signature/signature6.svg"
34+
width="100%"
35+
height="auto"
36+
/>
37+
</div>
38+
39+
<ExpandableAlert
40+
title="SegWit vs Legacy Transactions"
41+
type="important"
42+
expandable={true}
43+
initialLines={3}
44+
>
45+
If a transaction has at least one SegWit input (native or wrapped), it must
46+
include:
47+
- Marker byte (0x00)
48+
- Flag byte (0x01)
49+
</ExpandableAlert>
50+
51+
The transaction structure at this stage is:
52+
53+
<CodeSnippet
54+
language="text"
55+
highlightLines={[4, 5, 6, 12]}
56+
showLineNumbers={true}
57+
code={`Transaction Breakdown:
58+
═══════════════════════════════════════════════════════════════════════════════════
59+
60+
version: 01000000
61+
marker: 00
62+
flag: 01
63+
64+
in: # We'll add inputs in the next step
65+
66+
out: # We'll add outputs later
67+
68+
locktime: 11000000`}
69+
/>
70+
71+
## Code Implementation
72+
73+
<CodeSnippet
74+
code={`def create_basic_tx(
75+
version: int,
76+
inputs: list,
77+
outputs: list,
78+
locktime: int,
79+
segwit: bool = True
80+
) -> bytes:
81+
# 4-byte version in little-endian
82+
tx_version = int_to_little_endian(version, 4)
83+
84+
# Marker + Flag for segwit (only if segwit=True)
85+
marker_flag = b'\\x00\\x01' if segwit else b''
86+
87+
# Number of inputs/outputs (varint)
88+
in_count = varint(len(inputs))
89+
out_count = varint(len(outputs))
90+
91+
# Serialize inputs and outputs
92+
serialized_inputs = b''.join(inputs)
93+
serialized_outputs = b''.join(outputs)
94+
95+
# Locktime (4 bytes)
96+
tx_locktime = int_to_little_endian(locktime, 4)
97+
98+
return (
99+
tx_version +
100+
marker_flag +
101+
in_count +
102+
serialized_inputs +
103+
out_count +
104+
serialized_outputs +
105+
tx_locktime
106+
)`}
107+
language="python"
108+
/>
109+
110+
Let's now add inputs and outputs in the next step!

decoding/transaction-signing-01.mdx

+133
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
---
2+
title: "Step 1: Create Transaction Inputs"
3+
date: 2024-01-25
4+
lastmod: "2024-01-25"
5+
draft: false
6+
category: Transactions
7+
layout: TopicBanner
8+
order: 1
9+
icon: "FaClipboardList"
10+
images:
11+
[
12+
"/bitcoin-topics/static/images/topics/thumbnails/transaction-module/signature/tx-thumbnail-signature-1.jpg"
13+
]
14+
---
15+
16+
Each input in a Bitcoin transaction must specify:
17+
18+
- Transaction ID (32 bytes): Points to the UTXO being spent
19+
- Output Index (4 bytes): Which output from that transaction
20+
- ScriptSig: Placeholder for the unlocking script
21+
- Sequence (4 bytes): Usually 0xFFFFFFFF
22+
23+
<div className="w-full rounded-xl overflow-hidden full-width">
24+
<SvgDisplay
25+
src="/bitcoin-topics/static/images/topics/transactions/signature/signature7.svg"
26+
width="100%"
27+
height="auto"
28+
/>
29+
</div>
30+
31+
The following table summarizes our UTXOs (Transaction IDs shown in big-endian format):
32+
33+
| Input | Transaction ID (big-endian) | Output Index | Sequence |
34+
| ----- | ---------------------------------------------------------------- | ------------ | -------- |
35+
| #1 | 9f96add4e4db413543df3eea1781c3be62637f1e2dd44069fa99801a88f7f7ff | 0 | eeffffff |
36+
| #2 | 8ac60eb9575db5b2d987e29f301b5b819ea83a5c6579d282d189cc04b8e151ef | 1 | ffffffff |
37+
38+
_Note: In the transaction serialization below, these Transaction IDs are converted to little-endian format as required by the Bitcoin protocol._
39+
40+
<CodeSnippet
41+
language="text"
42+
highlightLines={[6, 8, 9, 10, 11, 12, 13, 15, 16, 17, 18, 19, 20]}
43+
showLineNumbers={true}
44+
code={`Transaction Breakdown:
45+
═══════════════════════════════════════════════════════════════════════════════════
46+
47+
Version: 01000000
48+
49+
Input Count: 02
50+
51+
input[0]:
52+
Previous TXID: fff7f7881a8099afa6940d42d1e7f6362bec38171ea3edf433541db4e4ad969f
53+
Output Index: 00000000
54+
ScriptSig Size: 00
55+
ScriptSig:
56+
Sequence: eeffffff
57+
58+
input[1]:
59+
Previous TXID: ef51e1b804cc89d182d279655c3aa89e815b1b309fe287d9b2b55d57b90ec68a
60+
Output Index: 01000000
61+
ScriptSig Size: 00
62+
ScriptSig:
63+
Sequence: ffffffff
64+
65+
Locktime: 11000000`}
66+
/>
67+
68+
<ExpandableAlert
69+
title="Why are scriptSig fields empty?"
70+
type="info"
71+
expandable={true}
72+
>
73+
Transaction signing follows a specific order:
74+
1. First, we create the
75+
transaction structure with empty scriptSig fields
76+
2. Then, we calculate the
77+
signature hash (sighash) for each input
78+
3. Finally, we add the signatures to
79+
create the complete transaction
80+
</ExpandableAlert>
81+
82+
## Code Implementation
83+
84+
<CodeSnippet
85+
code={`def create_input(
86+
txid: str,
87+
vout: int,
88+
script_sig: bytes = b'',
89+
sequence: bytes = b'\\xff\\xff\\xff\\xff'
90+
) -> bytes:
91+
# Convert txid from hex string and reverse (to little-endian)
92+
txid_bytes = bytes.fromhex(txid)[::-1]
93+
94+
# Convert vout to 4 bytes, little-endian
95+
vout_bytes = int_to_little_endian(vout, 4)
96+
97+
# Script length and script
98+
script_sig_length = varint(len(script_sig))
99+
100+
return (
101+
txid_bytes + # 32 bytes
102+
vout_bytes + # 4 bytes
103+
script_sig_length + # 1 byte
104+
script_sig + # variable
105+
sequence # 4 bytes
106+
)`}
107+
language="python"
108+
/>
109+
110+
<ExpandableAlert title="Helper Functions" type="info" expandable={true}>
111+
Two essential encoding functions:
112+
1. int_to_little_endian: Converts integers to little-endian byte format
113+
2. varint: Encodes variable-length integers used for counts and lengths
114+
115+
<CodeSnippet
116+
code={`def int_to_little_endian(value: int, length: int) -> bytes:
117+
"""Convert an integer to little-endian bytes"""
118+
return value.to_bytes(length, 'little')
119+
120+
def varint(n: int) -> bytes:
121+
"""Encode an integer as a variable length integer"""
122+
if n < 0xfd:
123+
return bytes([n])
124+
elif n <= 0xffff:
125+
return b'\\xfd' + n.to_bytes(2, 'little')
126+
elif n <= 0xffffffff:
127+
return b'\\xfe' + n.to_bytes(4, 'little')
128+
else:
129+
return b'\\xff' + n.to_bytes(8, 'little')`}
130+
language="python"
131+
/>
132+
133+
</ExpandableAlert>

decoding/transaction-signing-02.mdx

+113
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
---
2+
title: "Step 2: Create Transaction Outputs"
3+
date: 2024-01-25
4+
lastmod: "2024-01-25"
5+
draft: false
6+
category: Transactions
7+
layout: TopicBanner
8+
order: 2
9+
icon: "FaClipboardList"
10+
images:
11+
[
12+
"/bitcoin-topics/static/images/topics/thumbnails/transaction-module/signature/tx-thumbnail-signature-2.jpg"
13+
]
14+
---
15+
16+
Each output in a Bitcoin transaction requires:
17+
18+
- Amount (8 bytes): Value in satoshis
19+
- ScriptPubKey: Locking script that defines spending conditions
20+
21+
<div className="w-full rounded-xl overflow-hidden full-width">
22+
<SvgDisplay
23+
src="/bitcoin-topics/static/images/topics/transactions/signature/signature8.svg"
24+
width="100%"
25+
height="auto"
26+
/>
27+
</div>
28+
29+
---
30+
31+
## Code Implementation
32+
33+
<CodeSnippet
34+
code={`def create_output(
35+
amount: int,
36+
script_pubkey: bytes
37+
) -> bytes:
38+
# Amount (8 bytes, little-endian)
39+
amount_bytes = int_to_little_endian(amount, 8)
40+
41+
return (
42+
amount_bytes + # value in satoshis
43+
script_pubkey # includes length prefix
44+
)`}
45+
language="python"
46+
/>
47+
48+
The following table summarizes our outputs from test vector:
49+
50+
| Output | Amount (BTC) | ScriptPubKey |
51+
| ------ | ------------ | ---------------------------------------------------- |
52+
| #1 | 1.2 | 1976a9148280b37df378db99f66f85c95a783a76ac7a6d5988ac |
53+
| #2 | 2.2 | 1976a9143bde42dbee7e4dbe6a21b2d50ce2f0167faa815988ac |
54+
55+
Our transaction structure at this stage is:
56+
57+
<CodeSnippet
58+
language="text"
59+
highlightLines={[22, 24, 25, 26, 27, 29, 30, 31, 32]}
60+
showLineNumbers={true}
61+
code={`Transaction Breakdown:
62+
═══════════════════════════════════════════════════════════════════════════════════
63+
64+
Version: 01000000
65+
66+
Input Count: 02
67+
68+
input[0]:
69+
Previous TXID: fff7f7881a8099afa6940d42d1e7f6362bec38171ea3edf433541db4e4ad969f
70+
Output Index: 00000000
71+
ScriptSig Size: 00
72+
ScriptSig:
73+
Sequence: eeffffff
74+
75+
input[1]:
76+
Previous TXID: ef51e1b804cc89d182d279655c3aa89e815b1b309fe287d9b2b55d57b90ec68a
77+
Output Index: 01000000
78+
ScriptSig Size: 00
79+
ScriptSig:
80+
Sequence: ffffffff
81+
82+
Output Count: 02
83+
84+
output[0]:
85+
Amount: 202cb20600000000
86+
ScriptPubKey Size: 19
87+
ScriptPubKey: 76a9148280b37df378db99f66f85c95a783a76ac7a6d5988ac
88+
89+
output[1]:
90+
Amount: 9093510d00000000
91+
ScriptPubKey Size: 19
92+
ScriptPubKey: 76a9143bde42dbee7e4dbe6a21b2d50ce2f0167faa815988ac
93+
94+
Locktime: 11000000`}
95+
/>
96+
97+
## Test Vector from BIP-143
98+
99+
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>.
100+
101+
<div className="flex justify-center items-center w-full full-width">
102+
<iframe
103+
src="https://trinket.io/embed/python3/e3098585e3c8"
104+
width="100%"
105+
height="100%"
106+
style={{
107+
border: "none",
108+
margin: 0
109+
}}
110+
allowFullScreen
111+
className="rounded-md shadow-sm h-[calc(50vh)]"
112+
></iframe>
113+
</div>

0 commit comments

Comments
 (0)