Skip to content
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

How to calculate signature #1

Closed
coolaj86 opened this issue Dec 23, 2022 · 1 comment
Closed

How to calculate signature #1

coolaj86 opened this issue Dec 23, 2022 · 1 comment

Comments

@coolaj86
Copy link
Member

coolaj86 commented Dec 23, 2022

This is to help you

  • create a raw, signable tx
  • sign it
  • compose the signature into a full tx

This project is cryptocurrency-agnostic (BTC, BSV, BCH, DASH, DOGE, etc).

Although this module was written for Dash, the examples come from https://bitcointalk.org/index.php?topic=651344.0.

Table of Contents

  • Anatomy of a Transaction
    • Overview
    • Types of Types
    • Byte-by-Byte
      • Raw
      • Ready-to-Hash
      • Ready-to-Broadcast
  • Transaction Examples by Type
    • Raw
    • Ready-to-Hash (Signable)
    • Ready-to-Broadcast (Signed)

Basic Anatomy of a Transaction

In short, every transaction for wallet payments looks like this:

  1. VERSION
  2. # of Inputs
  3. List of INPUTs
    (note: these vary wildly between Tx types)
  4. # of Outputs
  5. List of OUTPUTs
  6. LOCKTIME
  7. (only for hashing) SIGHASH_TYPE

Types of Types

Type Desc
VarInt "Compressed" (1-9 byte) Integers. The first byte is either 0-252 (1 byte), 253=3-, 254=5-, or 255=9- bytes
Uint32LE Fixed-width ints written in CPU-order (Little-Endian) rather than Network/Storage-order (Big-Endian)0x01000000 is 1
ASN.1 Like JSON (or XML) of the stone age binary type encoding for ECDSA
ASN.1 BigInts Padded with leading 0x00 if the first byte is >= 0x80, unless the number is negative
OP_ codes Stack-based Virtual CPU commands for the network nodes
PubKeyHash (PKH) 20-byte (0x14) RIPEMD160 hash of SHA256 hash of ECDSA Public Key X value
Public Key X (& Y) "Compressed" Public Keys have a 1-byte prefix (0x02 or 0x03, indicating quadrant of the graph, since the X value indicates two possible Y values) and are 32-byte BigInts (possibly 33 with padding)
Signature R & S ECDSA Signatures have R (32-byte) and S (32-byte) components calculated from the Data, Private Key, and K (seeded, possibly random) values

Byte by Byte

Here's a look at each representation of a TX, byte by byte:

"Raw" Tx

Overview

  1. VERSION
  2. Number of Inputs (VarInt)
  3. List of neutered INPUTS
    • Previous Output TX ID (256-bit, reversed)
    • Previous Output Index (32-bit, LE)
    • 0x00 (Script is not included, therefore Size is 0)
    • Sequence Number (always 0xffffffff)
  4. Number of Outputs (VarInt)
  5. List of OUTPUTS
    • Units (Satoshis) 64-bit, LE
    • 0x19 Lock Script Size (always 25 bytes for wallet payment Txes)
    • Lock Script
      • 0x76 (OP_DUP)
      • 0xa9 (OP_HASH160)
      • 0x14 (PubKeyHash Size)
      • PubKeyHash (20 bytes)
      • 0x88 (OP_EQUALVERIFY)
      • 0xac (OP_CHECKSIG)
  6. LOCKTIME (32-bit, LE)

Example

0100000001a2bda7b7e967346fcf189cee2563b0846d7bec06bb6db6119054add1875bd3770000000000ffffffff0120f1610b000000001976a914f93af105187d21ed6adfa5d71bfada7d7324e53c88ac00000000

Decoded

01000000                 # Version Number (32-bit, Little-Endian)

# INPUTS SECTION
01                       # Number of Inputs (VarInt)
# Input 1 of 1
    a2bda7b7             # Previous TX ID (256-bit, reversed)
    e967346f
    cf189cee
    2563b084
    6d7bec06
    bb6db611
    9054add1
    875bd377
    00000000             # Previous Output Index (32-bit, LE)
    00                   # Signature Script Size (VarInt)
    ffffffff             # Sequence Number (always ffffffff)

# OUTPUTS SECTION
01                       # Number of Outputs (VarInt)
# Output 1 of 1
    20f1610b00000000     # Output Value / Satoshis (64-bit, LE)
    19                   # Lock Script Size (25 bytes)
    76a9                 # OP_DUP, OP_HASH160
    14                   # PubKeyHash (PKH) Size (20 bytes)
    f93af105187d21ed6adf # PubKeyHash
    a5d71bfada7d7324e53c
    88ac                 # OP_EQUALVERIFY, OP_CHECKSIG

00000000                 # Lock Time

"Hashable" Tx

  1. VERSION
  2. Number of Inputs (VarInt)
  3. List of Hashable INPUTS
    • Previous Output TX ID (256-bit, reversed)
    • Previous Output Index (32-bit, LE)
    • 0x19 (Script Size VarInt, always 25)
    • Previous Lock Script
      • 0x76 (OP_DUP)
      • 0xa9 (OP_HASH160)
      • 0x14 (PubKeyHash Size)
      • PubKeyHash (20 bytes)
      • 0x88 (OP_EQUALVERIFY)
      • 0xac (OP_CHECKSIG)
    • Sequence Number (always 0xffffffff)
  4. Number of Outputs (VarInt)
  5. List of OUTPUTS
    • Units (Satoshis) 64-bit, LE
    • 0x19 Lock Script Size (always 25 bytes for wallet payment Txes)
    • Lock Script
      • 0x76 (OP_DUP)
      • 0xa9 (OP_HASH160)
      • 0x14 (PubKeyHash Size)
      • PubKeyHash (20 bytes)
      • 0x88 (OP_EQUALVERIFY)
      • 0xac (OP_CHECKSIG)
  6. LOCKTIME (32-bit, LE)
  7. Signature Hash Type (32-bit LE, always 0x01000000)
  8. (computed value) Tx Hash

"Signed" (Ready-to-Broadcast) Tx

  1. VERSION
  2. Number of Inputs (VarInt)
  3. List of Signed INPUTS
    • Previous Output TX ID (256-bit, reversed)
    • Previous Output Index (32-bit, LE)
    • Script Byte Size (VarInt)
      106 to 109, varies due to BigInt padding
    • Signature Script
      • Signature + SigHashType Size (71, 72, or 73 bytes total)
      • ASN.1 ECDSA Signature (70, 71, or 72 bytes, due to BigInt padding)
        • 0x30 (ASN.1 Sequence Type) + Size (1 + 1 bytes)
        • 0x02 (ASN.1 Byte Type) + Size (1 + 1 bytes)
        • Signature R value (32 or 33 bytes)
        • 0x02 (ASN.1 Byte Type) + Size (1 + 1 bytes)
        • Signature S value (32 or 33 bytes)
      • Sig Hash Type (always 0x01)
      • Public Key Size (33 or 34)
      • Public Key (compression bit + 32 or 33 bytes)
    • Sequence Number (always 0xffffffff)
  4. Number of Outputs (VarInt)
  5. List of OUTPUTS
    • Units (Satoshis) 64-bit, LE
    • 0x19 Lock Script Size (always 25 bytes for wallet payment Txes)
    • Lock Script
      • 0x76 (OP_DUP)
      • 0xa9 (OP_HASH160)
      • 0x14 (PubKeyHash Size)
      • PubKeyHash (20 bytes)
      • 0x88 (OP_EQUALVERIFY)
      • 0xac (OP_CHECKSIG)
  6. LOCKTIME (32-bit, LE)
  7. (computed value) Tx ID (reverse Tx Hash, all sigs included)

Amalgam (all 3 types together)

  1. VERSION
  2. Number of Inputs (VarInt)
  3. List of INPUTS
    • Previous Output TX ID (256-bit, reversed)
    • Previous Output Index (32-bit, LE)
    • Script Byte Size (VarInt)
      • 0 for "Raw" transactions
      • 25 for "Hashable" transactions
      • 106 to 109 for "Ready-to-Broadcast" transactions
    • Script (1 of these 3 options)
      1. (for "Raw" Tx) omitted
      2. (for "Hashable" Tx) Previous Lock Script
        • 0x76 (OP_DUP)
        • 0xa9 (OP_HASH160)
        • 0x14 (PubKeyHash Size)
        • PubKeyHash (20 bytes)
        • 0x88 (OP_EQUALVERIFY)
        • 0xac (OP_CHECKSIG)
      3. Signature Script
        • Signature + SigHashType Size (71, 72, or 73 bytes total)
        • ASN.1 ECDSA Signature (70, 71, or 72 bytes, due to BigInt padding)
          • 0x30 (ASN.1 Sequence Type) + Size (1 + 1 bytes)
          • 0x02 (ASN.1 Byte Type) + Size (1 + 1 bytes)
          • Signature R value (32 or 33 bytes)
          • 0x02 (ASN.1 Byte Type) + Size (1 + 1 bytes)
          • Signature S value (32 or 33 bytes)
        • Sig Hash Type (always 0x01)
        • Public Key Size (33 or 34)
        • Public Key (compression bit + 32 or 33 bytes)
    • Sequence Number (always 0xffffffff)
  4. Number of Outputs (VarInt)
  5. List of OUTPUTS
    • Units (Satoshis) 64-bit, LE
    • 0x19 Lock Script Size (always 25 bytes for wallet payment Txes)
    • Lock Script
      • 0x76 (OP_DUP)
      • 0xa9 (OP_HASH160)
      • 0x14 (PubKeyHash Size)
      • PubKeyHash (20 bytes)
      • 0x88 (OP_EQUALVERIFY)
      • 0xac (OP_CHECKSIG)
  6. LOCKTIME (32-bit, LE)
  7. (for Tx Hashes only) Signature Hash Type
  8. (computed values, not in byte sequence)
    • Tx Hashes (only for ready-to-sign Txes)
    • Tx ID (only for signed Txes)

Types of Transactions (in Bytes)

There are 3 different byte structures for the same basic transaction:

  1. The "Raw" Tx
    This is just inputs (tx ids and indexes from previous outputs) and outputs.
    It's pretty much useless. I have no idea why you'd ever want this.
  2. The "Ready-to-Hash" (Signable) Tx
    There is one "Ready-to-Hash" Tx (Signable Tx) for each input (even if from the same address)
    These are generated in order to creating unique Tx Hashes and verify signatures
  3. The "Ready-to-Broadcast" (Spendable) Tx
    These contain enough information to lookup what is needed to reconstruct the Tx Hashes from the info that exists in the blockchain indexes. These have a Tx ID.

Raw Tx (Useless)

There's nothing interesting you can do with these other than pass unit tests.

This format cannot be used to sign or broadcast. It lacks the necessary information to construct either of the useful Tx types.

That said..., here's what a Raw TX looks like, in bytes:

0100000001a2bda7b7e967346fcf189cee2563b0846d7bec06bb6db6119054add1875bd3770000000000ffffffff0120f1610b000000001976a914f93af105187d21ed6adfa5d71bfada7d7324e53c88ac00000000

If we break that down cleanly into 4 sections:

  1. VERSION
  2. INPUTS
  3. OUTPUTS
  4. LOCKTIME
01 00 00 00              # Version Number (32-bit, Little-Endian)

# INPUTS SECTION
01                       # Number of Inputs (VarInt)
# Input 1 of 1
    a2bda7b7             # Previous TX ID (256-bit, reversed)
    e967346f
    cf189cee
    2563b084
    6d7bec06
    bb6db611
    9054add1
    875bd377
    00 00 00 00          # Previous Output Index (32-bit, LE)
    00                   # Signature Script Size (VarInt)
    ffffffff             # Sequence Number (always ffffffff)

# OUTPUTS SECTION
01                       # Number of Outputs (VarInt)
# Output 1 of 1
    20f1610b00000000     # Output Value / Satoshis (64-bit, LE)
    19                   # Lock Script Size (25 bytes)
    76a9                 # OP_DUP, OP_HASH160
    14                   # PubKeyHash (PKH) Size (20 bytes)
    f93af105187d21ed6adf # PubKeyHash
    a5d71bfada7d7324e53c
    88ac                 # OP_EQUALVERIFY, OP_CHECKSIG

00000000                 # Lock Time

Signable Tx

As stated above, a Raw Tx is useless. It's like an idiot-savant's version of JSON.

The signable TX is similar (example forthcoming), but:

  • sigScript (and its size) is replaced by the previous transaction's output's lock Script (rather than being 0-length, as in the raw)
  • The SigHashType (0x01) must be appended as a 32-bit LittleEndian
  • The double-sha256sum is taken and then reversed

Note: this example was added in haste and may not be perfectly correct. TODO make it perfect!

# version (int32)
01 00 00 00

# number of outputs as inputs (varint)
01
    # output at index 0
    # byte-reversed txid of input's previous output
    a2bda7b7e967346fcf189cee2563b0846d7bec06bb6db6119054add1875bd377
    # index of input's previous output
    00 00 00 00 # prev vout index
    # size of signature script (actually previous output lock script)
    19
    # previous output's lock script (TODO use the real one from the tx)
    76a9
    14
    f93af105187d21ed6adfa5d71bfada7d7324e53c
    88ac
    # sequence of this input
    ffffffff

# number of outputs
01
    # output at index 0
    # satoshis (reverse byte order)
    20 f1 61 0b 00 00 00 00
    # varint size of this output's pubkeyhash script
    19
    # some op codes
    76 a9
    # decimal 20, the size of the pubkeyhash
    14
    # the pubkeyhash (no magic byte or checksum)
    f93af105187d21ed6adfa5d71bfada7d7324e53c
    # more op codes
    88 ac

# locktime
00000000

A Signed Tx

The signed transaction will look like this:

0100000001a2bda7b7e967346fcf189cee2563b0846d7bec06bb6db6119054add1875bd377000000006a4730440220528e92bc890b362efcab0ab1af0f9427d501909be59fe22dbdb4c26eac17418102206eb9c83360ad46c9f17be32ea15a08d2765a934e08ce6f2578b3379bbfa03afd0121024451fc7d9e271fab77265bd0292fc274ee231e7ecc076bf6269999c0cbbf9f90ffffffff0120f1610b000000001976a914f93af105187d21ed6adfa5d71bfada7d7324e53c88ac00000000

Which can be broken down like this:

  # version (int32)
  01 00 00 00
  
  # number of outputs as inputs (varint)
  01
      # output at index 0
      # byte-reversed txid of input's previous output
      a2bda7b7e967346fcf189cee2563b0846d7bec06bb6db6119054add1875bd377
      # index of input's previous output
      00 00 00 00 # prev vout index
      # size of signature script (106 decimal)
-     00
+     6a
+         # size of signature + sighashtype (71 in decimal)
+         47
+         # ASN.1 Sequence + Size
+         30 44
+         # ASN.1 Bytes + Len
+         02 20
+         # Signature R value
+         528e92bc890b362efcab0ab1af0f9427d501909be59fe22dbdb4c26eac174181
+         # ASN.1 Bytes + Len
+         02 20
+         # Signature S Value 
+         6eb9c83360ad46c9f17be32ea15a08d2765a934e08ce6f2578b3379bbfa03afd
+         # SigHashType
+         01
+         # Varint PubKey Len (33)
+         21
+         # Full Public Key (first byte is quadrant)
+         02 4451fc7d9e271fab77265bd0292fc274ee231e7ecc076bf6269999c0cbbf9f90
      # sequence of this input
      ffffffff

  # number of outputs
  01
      # output at index 0
      # satoshis (reverse byte order)
      20 f1 61 0b 00 00 00 00
      # varint size of this output's pubkeyhash script
      19
      # some op codes
      76 a9
      # decimal 20, the size of the pubkeyhash
      14
      # the pubkeyhash (no magic byte or checksum)
      f93af105187d21ed6adfa5d71bfada7d7324e53c
      # more op codes
      88 ac

  # locktime
  00000000
@coolaj86
Copy link
Member Author

closing as sticky

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant