defmodule BitcoinLib.Script.Opcodes.Crypto.CheckSig do @moduledoc """ Based on https://en.bitcoin.it/wiki/Script Word OP_CHECKSIG Opcode 172 Hex 0xac Input sig pubkey Output True / false Description The entire transaction's outputs, inputs, and script (from the most recently-executed OP_CODESEPARATOR to the end) are hashed. The signature used by OP_CHECKSIG must be a valid signature for this hash and public key. If it is, 1 is returned, 0 otherwise. """ @behaviour BitcoinLib.Script.Opcode defstruct [:script] alias BitcoinLib.Crypto.Secp256k1 alias BitcoinLib.Script.Opcodes.Crypto.CheckSig alias BitcoinLib.Key.PublicKey @type t :: CheckSig @value 0xAC @doc """ Returns 0xac ## Examples iex> BitcoinLib.Script.Opcodes.Crypto.CheckSig.v() 0xac """ @spec v() :: 0xAC def v do @value end @doc """ Returns <<0xac>> ## Examples iex> BitcoinLib.Script.Opcodes.Crypto.CheckSig.encode() <<0xac>> """ @spec encode() :: <<_::8>> def encode() do <<@value::8>> end @doc """ The entire transaction's outputs, inputs, and script (from the most recently-executed OP_CODESEPARATOR to the end) are hashed. The signature used by OP_CHECKSIG must be a valid signature for this hash and public key. If it is, 1 is returned, 0 otherwise. ## Examples iex> sig_pub_key = <<0x0218fb7aff2c6cb9c25b7cd9aa0b9bdd712e5617f07cb0c96bdda0b44c25a5d25f::264>> ...> signature = <<0x304402202911998439e90fc7c3e12c8fd9e5b65d451c3e157fdfdf0991281fb90038eaf20220623615e5e4a768edc19fd480ac67b7f39d46689fdbfb54ffa49145117d17aa71::560>> ...> %BitcoinLib.Script.Opcodes.Crypto.CheckSig{ ...> script: <<0x76a91417cdc02e31846f9e7c25952700f53e9752a0a3c288ac::200>> ...> } ...> |> BitcoinLib.Script.Opcodes.Crypto.CheckSig.execute([sig_pub_key, signature, 3]) {:ok, [1, 3]} """ @spec execute(CheckSig.t(), list()) :: {:ok, list()} def execute(%CheckSig{script: script}, [sig_pub_key | [sig | remaining]]) do script_hex = script |> Binary.to_hex() case Secp256k1.validate(sig, script_hex, %PublicKey{key: sig_pub_key}) do true -> {:ok, [1 | remaining]} false -> {:ok, [0 | remaining]} end end end defimpl Inspect, for: BitcoinLib.Script.Opcodes.Crypto.CheckSig do alias BitcoinLib.Script.Opcodes.Crypto.CheckSig alias BitcoinLib.Formatting.HexBinary def inspect(%CheckSig{script: nil}, _opts) do "%BitcoinLib.Script.Opcodes.Crypto.CheckSig{}" end def inspect(%CheckSig{} = check_sig, _opts) do %CheckSig{script: script} = check_sig hex_binary = %HexBinary{data: script} "%BitcoinLib.Script.Opcodes.Crypto.CheckSig{script: #{inspect(hex_binary)}}" end end