Script Validation (P2PKH-lite)

hard · bitcoin, script, crypto

Script Validation (P2PKH-lite)

Implement a minimal Bitcoin-like script engine for Pay-to-PubKey-Hash using HASH256 (double SHA-256) instead of HASH160.

Script encoding

Scripts are byte slices with two kinds of items:

  • Pushdata: a byte n (1..75) followed by n data bytes.
  • Opcodes (single byte):
    • 0x76 OP_DUP
    • 0xAA OP_HASH256
    • 0x88 OP_EQUALVERIFY
    • 0xAC OP_CHECKSIG

Any other opcode is invalid.

Signature hash (simplified)

For this problem, the signature hash is:

S = SHA256(SHA256(tx.ID || uint32(inputIndex) || scriptPubKey))

All concatenations are byte concatenations, and inputIndex is little-endian.

Types and function

type Outpoint struct {
    TxID  [32]byte
    Index uint32
}

type TxIn struct {
    Prev      Outpoint
    ScriptSig []byte
}

type TxOut struct {
    Value        uint64
    ScriptPubKey []byte
}

type Transaction struct {
    ID      [32]byte
    Inputs  []TxIn
    Outputs []TxOut
}

func EvalP2PKH(tx Transaction, inputIndex int, scriptSig []byte, scriptPubKey []byte) bool

Execution rules

  • Start with an empty stack.
  • Execute scriptSig then scriptPubKey.
  • OP_DUP: duplicate the top stack item.
  • OP_HASH256: replace top item with HASH256(item).
  • OP_EQUALVERIFY: pop two items; if not equal, fail.
  • OP_CHECKSIG: pop pubkey then signature, verify ECDSA over S. Push 1 if valid, else 0.
  • At end, the script succeeds iff the stack is non-empty and the top item is not all-zero bytes.

Crypto details

  • Use elliptic.P256() (toy stand-in for secp256k1).
  • Pubkey encoding is uncompressed: 0x04 || X(32) || Y(32).
  • Signature is ASN.1 DER (use ecdsa.VerifyASN1).

Notes

  • Return false on malformed scripts or stack underflow.
  • inputIndex out of range should return false.
Run tests to see results
No issues detected