{"id":19178056,"url":"https://github.com/cmdruid/tapscript","last_synced_at":"2025-04-08T00:40:01.355Z","repository":{"id":60940714,"uuid":"542695903","full_name":"cmdruid/tapscript","owner":"cmdruid","description":"A humble library for working with Tapscript and Bitcoin Transactions.","archived":false,"fork":false,"pushed_at":"2024-09-26T02:36:40.000Z","size":10598,"stargazers_count":192,"open_issues_count":2,"forks_count":49,"subscribers_count":7,"default_branch":"master","last_synced_at":"2024-10-17T04:23:10.980Z","etag":null,"topics":["bitcoin","blockchain","library","taproot","tapscript"],"latest_commit_sha":null,"homepage":"https://www.npmjs.com/package/@cmdcode/tapscript","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"cc0-1.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/cmdruid.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"bitcoin":"bitcoin:bc1qnx8julmud2vqdqngxw9rmuv3js67kq9rzvtmm5","lnurl":"lnurl:cmd@stacker.news"}},"created_at":"2022-09-28T16:49:24.000Z","updated_at":"2024-10-14T16:12:55.000Z","dependencies_parsed_at":"2022-10-07T04:06:02.880Z","dependency_job_id":"2bd8f55a-1067-4bba-8f9a-29b244c179a8","html_url":"https://github.com/cmdruid/tapscript","commit_stats":{"total_commits":109,"total_committers":3,"mean_commits":"36.333333333333336","dds":0.04587155963302747,"last_synced_commit":"2962f4385890b99fdf9b3ed3fa9af915fbd46021"},"previous_names":["cmdruid/bton"],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cmdruid%2Ftapscript","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cmdruid%2Ftapscript/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cmdruid%2Ftapscript/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cmdruid%2Ftapscript/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cmdruid","download_url":"https://codeload.github.com/cmdruid/tapscript/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247755560,"owners_count":20990620,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bitcoin","blockchain","library","taproot","tapscript"],"created_at":"2024-11-09T10:36:41.990Z","updated_at":"2025-04-08T00:40:01.317Z","avatar_url":"https://github.com/cmdruid.png","language":"TypeScript","readme":"# Tapscript\n\nA basic library for working with Taproot, Schnorr Signatures, and Bitcoin transactions.\n\n\u003e Note: For nodejs users, please upgrade to version 19+ for globalThis support.\n\n## Introduction\n\nTapscript uses the latest feature upgrade to Bitcoin called Taproot. If you are new to Bitcoin or the Taproot upgrade, please continue reading for a brief overview of how it works. This library will be easier to follow if you know what taproot is doing under the hood.\n\nIf you already have a good understanding of Bitcoin and Taproot, feel free to skip ahead by clicking [here](#tool-index).\n\n## What is Taproot?\n\nBitcoin uses a simple scripting language (called Bitcoin Script) that allows you to lock up coins into a contract. These contracts are published to the blockchain and enforced by all nodes in the network.\n\nIn order to settle a contract (and claim its coins), you are required to publish the *entire* contract, including parts that are not relevant to the settlement. This is expensive and wasteful, plus it leaks information that could have otherwise been kept private.\n\nTaproot is a new way to publish these contracts to the blockchain that fixes the above concerns. It allows you to settle contracts by publishing only the portion of the contract that is relevant. This means smaller transactions, cheaper fees, and better privacy guarantees for the contract as a whole.\n\nTaproot also comes with many other benefits, including:\n\n * It drastically simplifies the flow and logic of writing a contract.\n * You can create large, complex contracts that only need a small transaction to settle.\n * Commitments to data and other arbitrary things can be thrown into your contract for free.\n * The new schnorr-based signature format lets you do some crazy cool stuff (BIP340).\n\nRead more about the Taproot upgrade in 2019 [here](https://cointelegraph.com/bitcoin-for-beginners/a-beginners-guide-to-the-bitcoin-taproot-upgrade).\n\n## How does Taproot work?\n\nTaproot uses a simple trick involving something called a \"merkle tree\".\n\n```\n                hash(ab, cd)                  \u003c- Final hash    (the root)\n              /             \\                \n      hash(a, b)             hash(c, d)       \u003c- Combined hash (the branches)\n     /          \\           /          \\    \n    hash(a) hash(b)        hash(c) hash(d)    \u003c- Initial hash  (the leaves)\n[ script(a), script(b), script(c), script(d) ]  \n```\n\nA merkle tree is simply a list of data that is reduced down into a single hash value. We do this by hashing values together in pairs of two, repeatedly, until we are naturally left with one value (the root).\n\nThe great thing about merkle trees is that you can use the root hash to prove that a piece of data (such as a script) was included somewhere in the tree, without having to reveal the entire tree.\n\nFor example, to prove that script(a) exists in the tree, we simply provide hash(b) and hash(c, d). This is all the information we need to recreate the root hash(ab, cd). We do not reveal any of the other scripts.\n\nThis allows us to break up a contract into many scripts, then lock coins to the root hash of our combined scripts. To redeem coins, we simply need to provide one of the scripts, plus a 'path' of hashes that lead us to the root hash of the tree.\n\n## About Key Tweaking\n\nAnother clever trick that Taproot uses, is something called \"key tweaking\".\n\nIn order to create a pair of keys used for signatures, we start with a secret number, or \"key\". We then multiply this key by a very large prime number, called a \"generator\" (G). This process is done in a way that is computationally impossible to reverse without knowing the secret. The resulting number then becomes our public key.\n\n```\nseckey * G =\u003e pubkey\n```\n\nWe use a special set of numbers when making key-pairs, so that some arithmetic still works between the keys, without breaking their secret relationship with G. This is how we produce signatures and proofs.\n\n```\nseckey +    randomkey    +    msg    = signature      \u003c= Does not reveal seckey.\npubkey + (randomkey * G) + (msg * G) = signature * G  \u003c= Proves that seckey was used.\n```\n\nKey tweaking is just an extention of this. We use a piece of data to \"tweak\" both keys in our key-pair, then use the modified keys to sign and verify transactions.\n\n```\nseckey +    tweak    = tweaked_seckey\npubkey + (tweak * G) = tweaked_pubkey\n```\n\nLater, we can choose to reveal the original public key and tweak, as proof that both were used to construct the modified key. Or we can simply choose to sign using the modified key, and not reveal anything!\n\nTaproot uses key tweaking in order to lock coins to our pubkey + root of our tree. This provides us with two paths for spending coins:\n\n * Using the tweaked pubkey (without revealing anything).\n * Using the interal pubkey + script + proof.\n\n\u003e Note: the \"proof\" is the path of hashes we described earlier, which is needed to recompute the root hash.\n\nIf you want to eliminate the key-spending path (so that a script *must* be used to redeem funds), you can replace the pubkey with a random number. However, it is best to use a number that everyone can verify has an unknown secret key. One example of such a number is the following:\n\n```js\n// BIP0341 specifies using the following pubkey value for script-only contracts.\n// It is created by hashing the DER encoded coordinates of secp256k1 base point G:\n'0250929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0'\n// Since this pubkey was generated using a hash function, there is no feasible way \n// to compute what the matching private key would be.\n```\n\n## Tool Index\n\nThis library provides a suite of tools for working with scripts, taproot, key tweaking, signatures and transactions. Use the links below to jump to the documentation for a certain tool.\n\n[**Address Tool**](#address-tool)  \nEncode, decode, check, and convert various address types.  \n[**Script Tool**](#script-tool)  \nEncode scripts into hex, or decode into a script array.  \n[**Signer Tool**](#signer-tool)  \nProduce signatures and validate signed transactions.  \n[**Tap Tool**](#tap-tool)  \nBuild, tweak, and validate trees of data / scripts.  \n[**Tx Tool**](#tx-tool)  \nEncode transactions into hex, or decode into a JSON object.\n\n### About Buff\n\nThis library makes heavy use of the [Buff](https://github.com/cmdruid/buff-utils) tool for converting between data types. Buff is an extention of the Uint8Array type, so all Buff objects can naturally be treated as Uint8Array objects. Buff objects however incude an extensive API for converting into different types (*for ex: buff.hex for hex strings*). Please check the above link for more information on how to use Buff.\n\n### Import\n\nExample import into a browser-based project:\n```html\n\u003cscript src=\"https://unpkg.com/@cmdcode/tapscript\"\u003e\u003c/script\u003e\n\u003cscript\u003e const { Address, Script, Signer, Tap, Tx } = window.tapscript \u003c/script\u003e\n```\nExample import into a commonjs project:\n```ts\nconst { Address, Script, Signer, Tap, Tx } = require('@cmdcode/tapscript')\n```\nExample import into an ES module project:\n```ts\nimport { Address, Script, Signer, Tap, Tx } from '@cmdcode/tapscript'\n```\n\n### Address Tool\n\nThis tool allows you to encode, decode, check, an convert various address types.\n\n```ts\nAddress = {\n  // Work with Pay-to-Pubkey-Hash addresses (Base58 encoded).\n  p2pkh  : =\u003e AddressTool,\n  // Work with Pay-to-Script-Hash addresses (Base58 encoded).\n  p2sh   : =\u003e AddressTool,\n  // Work with Pay-to-Witness PubKey-Hash addresses (Bech32 encoded).\n  p2wpkh : =\u003e AddressTool,\n  // Work with Pay-to-Witness Script-Hash addresses (Bech32 encoded).\n  p2wsh  : =\u003e AddressTool,\n  // Work with Pay-to-Taproot addresses (Bech32m encoded).\n  p2tr   : =\u003e AddressTool,\n  // Decode any address format into a detailed object.\n  decode   : (address : string) =\u003e AddressData,\n  // Convert any address into its scriptPubKey format.\n  toScriptPubKey : (address : string) =\u003e Buff\n}\n\ninterface AddressTool {\n  // Check if an address is valid.\n  check  : (address : string, network ?: Networks) =\u003e boolean\n  // Decode an address into a pubkey hash or script hash.\n  decode : (address : string, network ?: Networks) =\u003e Buff\n  // Convert a key or script into the proper hash.\n  hash   : (input : Bytes | ScriptData) =\u003e Buff\n  // Encode a pubkey hash or script hash into an address.\n  encode : (input : Bytes,  network ?: Networks) =\u003e string\n  // Return the scriptPubKey script for an address type.\n  scriptPubKey : (input : string) =\u003e string[]\n  // Return an address based on a public key (PKH type addresses only).\n  fromPubKey : (pubkey : Bytes, network ?: Networks) =\u003e string\n  // Return an address based on a script key (SH type addresses only).\n  fromScript : (script : ScriptData, network ?: Networks) =\u003e string\n}\n\ninterface AddressData {\n  data    : Buff\n  network : Networks\n  prefix  : string\n  script  : string[]\n  type    : keyof AddressTools\n}\n\ntype Networks = 'main' | 'testnet' | 'signet' | 'regtest'\n```\n\n#### Examples\n\nExample of using the main `Address` API.\n\n```ts\nconst address = 'bcrt1q738hdjlatdx9xmg3679kwq9cwd7fa2c84my9zk'\n// You can decode any address, extract data, or convert to a scriptPubKey format.\nconst decoded = Address.decode(address)\n// Example of the decoded data object.\n{ \n  prefix  : 'bcrt1q', \n  type    : 'p2w', \n  network : 'regtest', \n  data    : 'f44f76cbfd5b4c536d11d78b6700b8737c9eab07',\n  script  : [ 'OP_0', 'f44f76cbfd5b4c536d11d78b6700b8737c9eab07' ]\n}\n// You can also quickly convert between address and scriptPubKey formats.\nconst bytes = Address.toScriptPubKey(address)\n// Bytes: 0014f44f76cbfd5b4c536d11d78b6700b8737c9eab07\nconst address = Address.fromScriptPubKey(scriptPubKey)\n// Address : bcrt1q738hdjlatdx9xmg3679kwq9cwd7fa2c84my9zk\n```\n\nExample of using the AddressTool API for a given address type.\n\n```ts\n// Example 33-byte public key.\nconst pubkey  = '03d5af2a3e89cb72ff9ca1b36091ca46e4d4399abc5574b13d3e56bca6c0784679'\n// You can encode / decode / convert keys and script hashes.\nconst address = Address.p2wpkh.fromPubKey(pubkey, 'regtest')\n// Address: bcrt1q738hdjlatdx9xmg3679kwq9cwd7fa2c84my9zk\nconst address = Address.p2wpkh.encode(keyhash, 'regtest')\n// Address: bcrt1q738hdjlatdx9xmg3679kwq9cwd7fa2c84my9zk\nconst bytes   = Address.p2wpkh.decode(address)\n// KeyHash: f44f76cbfd5b4c536d11d78b6700b8737c9eab07\nconst script  = Address.p2wpkh.scriptPubKey(bytes)\n// script: script: [ 'OP_0', 'f44f76cbfd5b4c536d11d78b6700b8737c9eab07' ]\n```\n\n### Script Tool\n\nThis tool helps with parsing / serializing scripts.\n\n```ts\nScript = {\n  // Encode a JSON formatted script into hex.\n  encode : (script : ScriptData, varint = true) =\u003e string,\n  // Decode a hex formatted script into JSON.\n  decode : (script : string, varint = false)    =\u003e ScriptData\n  // Normalize script / data to a particular format:\n  fmt : {\n    // Convert script to opcodes / hex data (asm format).\n    toAsm()   =\u003e string[]  (asm format).\n    // Convert script to bytes (script hex).\n    toBytes() =\u003e Buff\n     // Convert non-script witness data to bytes.\n    toParam() =\u003e Buff  \n  }\n}\n```\n\n### Signer Tool.\n\nThis tool helps with signatures and validation.\n\n```ts\nSigner.taproot = {\n  // Calculate the signature hash for a transaction.\n  hash : (\n    txdata  : TxData | Bytes,\n    index   : number,\n    config  : HashConfig = {}\n  ) =\u003e Uint8Array,\n  // Sign a transaction using your *tweaked* private key.\n  sign : (\n    seckey  : Bytes,\n    txdata  : TxData | Bytes,\n    index   : number,\n    config  : HashConfig = {}\n  ) =\u003e Uint8Array,\n  // Verify a transaction using the included tapkey (or specify a pubkey).\n  verify : (\n    txdata  : TxData | Bytes,\n    index   : number,\n    config  : HashConfig = {}\n  ) =\u003e boolean\n}\n\ninterface HashConfig {\n  extension     ?: Bytes    // Hash and sign using this tapleaf.\n  pubkey        ?: Bytes    // Verify using this pubkey instead of the tapkey.\n  script        ?: Bytes    // Hash and sign using this script (for segwit spends).\n  sigflag       ?: number   // Set the signature type flag.\n  separator_pos ?: number   // If using OP_CODESEPARATOR, specify the latest opcode position.\n  extflag       ?: number   // Set the extention version flag (future use).\n  key_version   ?: number   // Set the key version flag (future use).\n  throws        ?: boolean  // Should throw an exception on failure.\n}\n```\n\n#### Example\n\nExample of a basic pay-to-taproot key spend (similar to pay-to-pubkey):\n\n```ts\n// Sample secret / public key pair.\nconst seckey  = '730fff80e1413068a05b57d6a58261f07551163369787f349438ea38ca80fac6'\nconst pubkey  = '0307b8ae49ac90a048e9b53357a2354b3334e9c8bee813ecb98e99a7e07e8c3ba3'\n\n// For key-spends, we need to tweak both the secret key and public key.\nconst [ tseckey ] = Tap.getSecKey(seckey)\nconst [ tpubkey ] = Tap.getPubKey(pubkey)\n\n// Our taproot address is the encoded version of our public tapkey.\nconst address = Address.p2tr.encode(tpubkey, 'regtest')\n\n// NOTE: For the next step, you need to send 100_000 sats to the above address.\n// Make note of the txid of this transaction, plus the index of the output that\n// you are spending.\n\nconst txdata = Tx.create({\n  vin  : [{\n    // The txid of your funding transaction.\n    txid: 'fbde7872cc1aca4bc93ac9a923f14c3355b4216cac3f43b91663ede7a929471b',\n    // The index of the output you are spending.\n    vout: 0,\n    // For Taproot, we need to specify this data when signing.\n    prevout: {\n      // The value of the output we are spending.\n      value: 100000,\n      // This is the script that our taproot address decodes into.\n      scriptPubKey: [ 'OP_1', tpubkey ]\n    },\n  }],\n  vout : [{\n    // We are locking up 99_000 sats (minus 1000 sats for fees.)\n    value: 99000,\n    // We are locking up funds to this address.\n    scriptPubKey: Address.toScriptPubKey('bcrt1q6zpf4gefu4ckuud3pjch563nm7x27u4ruahz3y')\n  }]\n})\n\n// For this example, we are signing for input 0.\n\n// Provide your tweaked secret key with the transaction, \n// plus the index # of the input you are signing for.\nconst sig = Signer.taproot.sign(tseckey, txdata, 0)\n\n// Add your signature to the witness data for that input.\ntxdata.vin[0].witness = [ sig ]\n\n// For verification, provided your \nawait Signer.taproot.verify(txdata, 0, { throws: true })\n\nconsole.log('Your address:', address)\nconsole.log('Your txhex:', Tx.encode(txdata).hex)\n```\n\nYou can find more examples in the main **Examples** section further down.\n\n\u003e Note: There is also an identical `Signer.segwit` tool for signing and validating segwit (BIP0143) transactions. The segwit signer currently does not support the use of OP_CODESEAPRATOR. Any scripts containing this opcode will throw an exception by default.\n\n### Tap Tool\n\n```ts\nTap = {\n  // Returns the tweaked public key (and cblock) for a given tree (and target).\n  getPubKey    : (pubkey : Bytes, config ?: TapConfig)  =\u003e TapKey,\n  // Returns the tweaked secret key (and cblock) for a given tree (and target).\n  getSecKey    : (seckey : Bytes, config ?: TapConfig)  =\u003e TapKey,\n  // Converts a script into a tapleaf (for script-based spending).\n  encodeScript : (script: ScriptData, version?: number) =\u003e string,\n  // Checks the validity of a given leaf target and control block.\n  checkPath    : (  \n    tapkey : Bytes, \n    target : Bytes, \n    cblock : Bytes, \n    config ?: TapConfig  \n  ) =\u003e boolean,  \n  // Gives access to the various sub-tools (described below).\n  tree  : TreeTool,\n  tweak : TweakTool,\n  util  : UtilTool\n}\n\ninterface TapConfig {\n  isPrivate ?: boolean\n  target    ?: Bytes\n  tree      ?: TapTree\n  throws    ?: boolean\n  version   ?: number\n}\n\ntype TapKey = [\n  tapkey : string,  // The tweaked public key.\n  cblock : string   // The control block needed for spending the tapleaf target.\n]\n```\n\n#### Examples\n\nExample of tapping a key with no scripts (key-spend).\n\n```ts\nconst [ tapkey ] = Tap.getPubKey(pubkey)\n```\n\nExample of tapping a key with a single script and returning a proof.\n\n```ts\n// Encode the script as bytes.\nconst bytes = Script.encode([ 'script' ])\n// Convert the bytes into a tapleaf.\nconst target = Tap.tree.getLeaf(bytes)\n// Provide the tapleaf as a target for generating the proof.\nconst [ tapkey, cblock ] = Tap.getPubKey(pubkey, { target })\n```\n\nExample of tapping a key with many scripts.\n\n```ts\nconst scripts = [\n  [ 'scripta' ],\n  [ 'scriptb' ],\n  [ 'scriptc' ]\n]\n\n// Convert the scripts into an array of tap leaves.\nconst tree = scripts\n  .map(e =\u003e Script.encode(e))\n  .map(e =\u003e Tap.tree.getLeaf(e))\n\n// Optional: You can also add data to the tree.\nconst bytes = encodeData('some data')\nconst leaf  = Tap.tree.getLeaf(bytes)\ntree.push(leaf)\n\n// Select a target leaf for generating the proof.\nconst target = tree[0]\n\n// Provide the tree and target leaf as arguments.\nconst [ tapkey, cblock ] = Tap.getPubKey(pubkey, { tree, target })\n```\n\n### Tree Tool\n\nThis tool helps with creating a tree of scripts / data, plus the proofs to validate items in the tree.\n\n```ts\nTap.tree = {\n  // Returns a 'hashtag' used for padding. Mainly for internal use.\n  getTag    : (tag : string) =\u003e Buff,\n  // Returns a 'tapleaf' used for building a tree. \n  getLeaf   : (data : Bytes, version ?: number) =\u003e string,\n  // Returns a 'branch' which combines two leaves (or branches).\n  getBranch : (leafA : string, leafB : string) =\u003e string,\n  // Returns the root hash of a tree.\n  getRoot   : (leaves : TapTree) =\u003e Buff,\n}\n\n// A tree is an array of leaves, formatted as strings.\n// These arrays can also be nested in multiple layers.\ntype TapTree = Array\u003cstring | string[]\u003e\n```\n\n### Tweak Tool\n\nThis tool helps with tweaking public / secret (private) keys.\n\n```ts\nTap.tweak = {\n  // Return a tweaked private key using the provided raw data.\n  getSeckey   : (seckey: Bytes, data ?: Bytes | undefined) =\u003e Buff,\n  // Return a tweaked public key using the provided raw data.\n  getPubkey   : (pubkey: Bytes, data ?: Bytes | undefined) =\u003e Buff,\n  // Return a 'taptweak' which is used for key tweaking.\n  getTweak    : (key : Bytes, data ?: Bytes, isPrivate ?: boolean) =\u003e Buff,\n  // Return a tweaked secret key using the provided tweak.\n  tweakSeckey : (seckey: Bytes, tweak: Bytes) =\u003e Buff,\n  // Return a tweaked public key using the provided tweak.\n  tweakPubkey : (seckey: Bytes, tweak: Bytes) =\u003e Buff\n}\n```\n\n### Util Tool\n\nThis tool provides helper methods for reading and parsing data related to taproot.\n\n```ts\nTap.util = {\n  readCtrlBlock : (cblock : Bytes) =\u003e CtrlBlock,\n  readParityBit : (parity ?: string | number) =\u003e number\n}\n\ninterface CtrlBlock {\n  version : number\n  parity  : number\n  intkey  : Buff\n  paths   : string[]\n}\n```\n\n#### Example\n\n```ts\nconst cblock = 'c1187791b6f712a8ea41c8ecdd0ee77fab3e85263b37e1ec18a3651926b3a6cf27'\nconst { intkey, parity, paths, version } = Tap.util.readCtrlBlock(cblock)\n// Expected output, with key formatted as hex instead of bytes (for readability).\n{\n  intkey: '187791b6f712a8ea41c8ecdd0ee77fab3e85263b37e1ec18a3651926b3a6cf27',\n  parity: 3,\n  paths: [],\n  version: 192\n}\n```\n\n### Tx Tool\n\nThis tool helps with parsing / serializing transaction data.\n\n```ts\nTx = {\n  // Create a transaction object from partial JSON. \n  // Any missing fields will be repalced with default values.\n  create : (data : Partial\u003cTxData\u003e) =\u003e TxData,\n  // Serialize a JSON transaction into a hex-encoded string.\n  encode : (\n    txdata       : TxData,  // The transaction JSON.\n    omitWitness ?: boolean  // If you wish to omit the witness data.\n  ) =\u003e string,\n  // Parse a hex-encoded transaction into a JSON object.\n  decode : (bytes : string | Uint8Array) =\u003e TxData,\n  // Normalize transaction data to a particular format.\n  fmt : {\n    // Convert transaction data into JSON format.\n    toJson  : (txdata ?: TxData | Bytes) =\u003e TxData,\n    // Convert transaction data into a byte format.\n    toBytes : (txdata ?: TxData | Bytes) =\u003e Buff\n  },\n  util : {\n    // Get the transaction Id of a transaction.\n    getTxid : (txdata : TxData | Bytes) =\u003e Buff,\n    // Get the size data of a transaction.\n    getTxSize : (txdata : TxData | Bytes) =\u003e TxSizeData,\n    // Parse a scriptPubKey and get the type plus hash data.\n    readScriptPubKey : (script : ScriptData) =\u003e ScriptPubKeyData,\n    // Parse an array of witness data into named values.\n    readWitness : (witness : ScriptData[])  =\u003e WitnessData\n  }\n}\n\ninterface TxData {\n  version  ?: number           // The transaction verion. Defaults to version 2.\n  vin       : InputData[]      // An array of transaction inputs.\n  vout      : OutputData[]     // An array of transaction outputs.\n  locktime ?: LockData         // The locktime of the transaction. Defautls to 0.\n}\n\ninterface InputData {\n  txid : string               // The txid of the UTXO being spent.\n  vout : number               // The output index of the UTXO being spent.\n  prevout   ?: OutputData     // The output data of the UTXO being spent.\n  scriptSig ?: ScriptData     // The ScriptSig field (mostly deprecated).\n  sequence  ?: SequenceData   // The sequence field for the input.\n  witness   ?: ScriptData[]   // An array of witness data for the input.\n}\n\ninterface OutputData {\n  value : number | bigint     // The satoshi value of the output.\n  scriptPubKey : ScriptData   // The locking script data.\n}\n\nexport interface ScriptPubKeyData {\n  type : OutputType\n  data : Buff\n}\n\ninterface WitnessData {\n  annex  : Buff | null  // The annex data (if present) or null.\n  cblock : Buff | null  // The control block (if present) or null.\n  script : Buff | null  // The redeem script (if present) or null.\n  params : Bytes[]      // Any remaining witness arguments.\n}\n\ninterface TxSizeData {\n  size   : number       // Size of the transaction in bytes.\n  bsize  : number       // Base size of the tx (without witness data).\n  vsize  : number       // Size of the tx with witness discount applied.\n  weight : number       // Used to calculate the vsize of the tx.\n}\n\ntype SequenceData = string | number\ntype LockData     = number\ntype ScriptData   = Bytes  | Word[]\ntype Word         = string | number | Uint8Array\ntype Bytes        = string | Uint8Array\n```\n\n#### Transaction Object\n\nThis is an example transaction in JSON format.\n\n```ts\nconst txdata = {\n  version: 2\n  vin: [\n    {\n      txid: '1351f611fa0ae6124d0f55c625ae5c929ca09ae93f9e88656a4a82d160d99052',\n      vout: 0,\n      prevout: { \n        value: 10000,\n        scriptPubkey: '512005a18fccd1909f3317e4dd7f11257e4428884902b1c7466c34e7f490e0e627da'\n        \n      },\n      sequence: 0xfffffffd,\n      witness: []\n    }\n  ],\n  vout: [\n    { \n      value: 9000, \n      address: 'bcrt1pqksclnx3jz0nx9lym4l3zft7gs5gsjgzk8r5vmp5ul6fpc8xyldqaxu8ys'\n    }\n  ],\n  locktime: 0\n}\n```\n\n## Example Transactions\n\nHere are a few partial examples to help demonstrate using the library. Check out the [`test/example/taproot`](test/example/taproot/) directory to see a full implementation of each example.\n\nPlease feel free to contribute more!\n\n### Basic Pay-to-Pubkey Spending\n\nFull example: [keyspend.test.ts](test/example/taproot/keyspend.test.ts)\n\n```ts\n// Create a keypair to use for testing.\nconst secret = 'ccd54b99acec77d0537b01431579baef998efac6b08e9564bc3047b20ec1bb4c'\nconst seckey = new SecretKey(secret, { type: 'taproot' })\nconst pubkey = seckey.pub\n\n// For key spends, we need to get the tweaked versions\n// of the secret key and public key.\nconst [ tseckey ] = Tap.getSecKey(seckey)\nconst [ tpubkey ] = Tap.getPubKey(pubkey)\n\n// Optional: You could also derive the public key from the tweaked secret key.\nconst _tpubkey_example = new SecretKey(tseckey).pub.x.hex\n\n// A taproot address is simply the tweaked public key, encoded in bech32 format.\nconst address = Address.p2tr.fromPubKey(tpubkey, 'regtest')\n\n/* NOTE: To continue with this example, send 100_000 sats to the above address.\n  You will also need to make a note of the txid and vout of that transaction,\n  so that you can include that information below in the redeem tx.\n*/ \n\nconst txdata = Tx.create({\n  vin  : [{\n    // Use the txid of the funding transaction used to send the sats.\n    txid: '1ec5b5403bbc7f26a5d3a3ee30d69166a19fa81b49928f010af38fa96986d472',\n    // Specify the index value of the output that you are going to spend from.\n    vout: 1,\n    // Also include the value and script of that ouput.\n    prevout: {\n      // Feel free to change this if you sent a different amount.\n      value: 100_000,\n      // This is what our address looks like in script form.\n      scriptPubKey: [ 'OP_1', tpubkey ]\n    },\n  }],\n  vout : [{\n    // We are leaving behind 1000 sats as a fee to the miners.\n    value: 99_000,\n    // This is the new script that we are locking our funds to.\n    scriptPubKey: Address.toScriptPubKey('bcrt1q6zpf4gefu4ckuud3pjch563nm7x27u4ruahz3y')\n  }]\n})\n\n// For this example, we are signing for input 0 of our transaction,\n// using the tweaked secret key.\nconst sig = Signer.taproot.sign(tseckey, txdata, 0)\n\n// Let's add this signature to our witness data for input 0.\ntxdata.vin[0].witness = [ sig ]\n\n// Check if the signature and transaction are valid.\nconst isValid = await Signer.taproot.verify(txdata, 0)\n```\n### Basic Pay-to-TapScript\n\nFull example: [tapscript.test.ts](test/example/taproot/tapscript.test.ts)\n\n```ts\nconst secret = '0a7d01d1c2e1592a02ea7671bb79ecd31d8d5e660b008f4b10e67787f4f24712'\nconst seckey = new SecretKey(secret, { type: 'taproot' })\nconst pubkey = seckey.pub\n\n// Specify a basic script to use for testing.\nconst script = [ pubkey, 'OP_CHECKSIG' ]\nconst sbytes = Script.encode(script)\n\n// For tapscript spends, we need to convert this script into a 'tapleaf'.\nconst tapleaf = Tap.tree.getLeaf(sbytes)\n\n// Optional: There is a convenience method that converts scripts directly.\nconst _tapleaf = Tap.encodeScript(script)\n\n// Generate a tapkey that includes our leaf script. Also, create a merlke proof \n// (cblock) that targets our leaf and proves its inclusion in the tapkey.\nconst [ tpubkey, cblock ] = Tap.getPubKey(pubkey, { target: tapleaf })\n\n// A taproot address is simply the tweaked public key, encoded in bech32 format.\nconst address = Address.p2tr.fromPubKey(tpubkey, 'regtest')\n\n/* NOTE: To continue with this example, send 100_000 sats to the above address.\n  You will also need to make a note of the txid and vout of that transaction,\n  so that you can include that information below in the redeem tx.\n*/ \n\nconst txdata = Tx.create({\n  vin  : [{\n    // Use the txid of the funding transaction used to send the sats.\n    txid: '181508e3be1107372f1ffcbd52de87b2c3e7c8b2495f1bc25f8cf42c0ae167c2',\n    // Specify the index value of the output that you are going to spend from.\n    vout: 0,\n    // Also include the value and script of that ouput.\n    prevout: {\n      // Feel free to change this if you sent a different amount.\n      value: 100_000,\n      // This is what our address looks like in script form.\n      scriptPubKey: [ 'OP_1', tpubkey ]\n    },\n  }],\n  vout : [{\n    // We are leaving behind 1000 sats as a fee to the miners.\n    value: 99_000,\n    // This is the new script that we are locking our funds to.\n    scriptPubKey: Address.toScriptPubKey('bcrt1q6zpf4gefu4ckuud3pjch563nm7x27u4ruahz3y')\n  }]\n})\n\n// For this example, we are signing for input 0 of our transaction,\n// using the untweaked secret key. We are also extending the signature \n// to include a commitment to the tapleaf script that we wish to use.\nconst sig = Signer.taproot.sign(seckey, txdata, 0, { extension: tapleaf })\n\n// Add the signature to our witness data for input 0, along with the script\n// and merkle proof (cblock) for the script.\ntxdata.vin[0].witness = [ sig.hex, script, cblock ]\n\n// Check if the signature is valid for the provided public key, and that the\n// transaction is also valid (the merkle proof will be validated as well).\nconst isValid = await Signer.taproot.verify(txdata, 0, { pubkey })\n```\n\n### Create / Spend from a Tree of Scripts\n\nFull example: [taptree.test.ts](test/example/taproot/taptree.test.ts)\n\n```ts\n// Create a keypair to use for testing.\nconst secret = '0a7d01d1c2e1592a02ea7671bb79ecd31d8d5e660b008f4b10e67787f4f24712'\nconst seckey = new SecretKey(secret, { type: 'taproot' })\nconst pubkey = seckey.pub\n\n// Specify an array of scripts to use for testing.\nconst scripts = [\n  [ 1, 7, 'OP_ADD', 8, 'OP_EQUALVERIFY', pubkey, 'OP_CHECKSIG' ],\n  [ 2, 6, 'OP_ADD', 8, 'OP_EQUALVERIFY', pubkey, 'OP_CHECKSIG' ],\n  [ 3, 5, 'OP_ADD', 8, 'OP_EQUALVERIFY', pubkey, 'OP_CHECKSIG' ],\n  [ 4, 4, 'OP_ADD', 8, 'OP_EQUALVERIFY', pubkey, 'OP_CHECKSIG' ],\n  [ 5, 3, 'OP_ADD', 8, 'OP_EQUALVERIFY', pubkey, 'OP_CHECKSIG' ],\n  [ 6, 2, 'OP_ADD', 8, 'OP_EQUALVERIFY', pubkey, 'OP_CHECKSIG' ],\n  [ 7, 1, 'OP_ADD', 8, 'OP_EQUALVERIFY', pubkey, 'OP_CHECKSIG' ]\n]\n\n// Convert our array of scripts into tapleaves.\nconst tree = scripts.map(s =\u003e Tap.encodeScript(s))\n\n// Pick one of our scripts as a target for spending.\nconst index  = Math.floor(Math.random() * 10) % 7\nconst script = scripts[index]\nconst target = Tap.encodeScript(script)\n\n// Generate a tapkey that includes our tree. Also, create a merlke proof \n// (cblock) that targets our leaf and proves its inclusion in the tapkey.\nconst [ tpubkey, cblock ] = Tap.getPubKey(pubkey, { tree, target })\n\n// A taproot address is simply the tweaked public key, encoded in bech32 format.\nconst address = Address.p2tr.fromPubKey(tpubkey, 'regtest')\n\n/* NOTE: To continue with this example, send 100_000 sats to the above address.\n * You will also need to make a note of the txid and vout of that transaction,\n * so that you can include that information below in the redeem tx.\n */ \n\nconst txdata = Tx.create({\n  vin  : [{\n    // Use the txid of the funding transaction used to send the sats.\n    txid: 'e0b1b0aea95095bf7e113c37562a51cb8c3f50f5145c17952e766f7a84fcc5d7',\n    // Specify the index value of the output that you are going to spend from.\n    vout: 0,\n    // Also include the value and script of that ouput.\n    prevout: {\n      // Feel free to change this if you sent a different amount.\n      value: 100_000,\n      // This is what our address looks like in script form.\n      scriptPubKey: [ 'OP_1', tpubkey ]\n    },\n  }],\n  vout : [{\n    // We are leaving behind 1000 sats as a fee to the miners.\n    value: 99_000,\n    // This is the new script that we are locking our funds to.\n    scriptPubKey: Address.toScriptPubKey('bcrt1q6zpf4gefu4ckuud3pjch563nm7x27u4ruahz3y')\n  }]\n})\n\n// For this example, we are signing for input 0 of our transaction,\n// using the untweaked secret key. We are also extending the signature \n// to include a commitment to the tapleaf script that we wish to use.\nconst sig = Signer.taproot.sign(seckey, txdata, 0, { extension: target })\n\n// Add the signature to our witness data for input 0, along with the script\n// and merkle proof (cblock) for the script.\ntxdata.vin[0].witness = [ sig.hex, script, cblock ]\n\n// Check if the signature is valid for the provided public key, and that the\n// transaction is also valid (the merkle proof will be validated as well).\nconst isValid = await Signer.taproot.verify(txdata, 0, { pubkey })\n```\n\n### Create / Publish an Inscription\n\nCreating an inscription is a three-step process:\n 1. We create a script for publishing the inscription, and convert it into a bitcoin address.\n 2. Send funds to the bitcoin address.\n 3. Create a redeem transaction, which claims the previous funds (and publishes the data).\n\nFull example: [inscribe.test.ts](test/example/taproot/inscribe.test.ts)\n\n```ts\n// The 'marker' bytes. Part of the ordinal inscription format.\nconst marker   = Buff.encode('ord')\n/* Specify the media type of the file. Applications use this when rendering \n  * content. See: https://developer.mozilla.org/en-US/docs/Glossary/MIME_type \n  */\nconst mimetype = Buff.encode('image/png')\n// Create a keypair to use for testing.\nconst secret = '0a7d01d1c2e1592a02ea7671bb79ecd31d8d5e660b008f4b10e67787f4f24712'\nconst seckey = new SecretKey(secret, { type: 'taproot' })\nconst pubkey = seckey.pub\n// Basic format of an 'inscription' script.\nconst script  = [ pubkey, 'OP_CHECKSIG', 'OP_0', 'OP_IF', marker, '01', mimetype, 'OP_0', imgdata, 'OP_ENDIF' ]\n// For tapscript spends, we need to convert this script into a 'tapleaf'.\nconst tapleaf = Tap.encodeScript(script)\n// Generate a tapkey that includes our leaf script. Also, create a merlke proof \n// (cblock) that targets our leaf and proves its inclusion in the tapkey.\nconst [ tpubkey, cblock ] = Tap.getPubKey(pubkey, { target: tapleaf })\n// A taproot address is simply the tweaked public key, encoded in bech32 format.\nconst address = Address.p2tr.fromPubKey(tpubkey, 'regtest')\n\n/* NOTE: To continue with this example, send 100_000 sats to the above address.\n * You will also need to make a note of the txid and vout of that transaction,\n * so that you can include that information below in the redeem tx.\n */ \n\nconst txdata = Tx.create({\n  vin  : [{\n    // Use the txid of the funding transaction used to send the sats.\n    txid: 'b8ed81aca92cd85458966de90bc0ab03409a321758c09e46090988b783459a4d',\n    // Specify the index value of the output that you are going to spend from.\n    vout: 0,\n    // Also include the value and script of that ouput.\n    prevout: {\n      // Feel free to change this if you sent a different amount.\n      value: 100_000,\n      // This is what our address looks like in script form.\n      scriptPubKey: [ 'OP_1', tpubkey ]\n    },\n  }],\n  vout : [{\n    // We are leaving behind 1000 sats as a fee to the miners.\n    value: 99_000,\n    // This is the new script that we are locking our funds to.\n    scriptPubKey: Address.toScriptPubKey('bcrt1q6zpf4gefu4ckuud3pjch563nm7x27u4ruahz3y')\n  }]\n})\n\n// For this example, we are signing for input 0 of our transaction,\n// using the untweaked secret key. We are also extending the signature \n// to include a commitment to the tapleaf script that we wish to use.\nconst sig = Signer.taproot.sign(seckey, txdata, 0, { extension: tapleaf })\n\n// Add the signature to our witness data for input 0, along with the script\n// and merkle proof (cblock) for the script.\ntxdata.vin[0].witness = [ sig, script, cblock ]\n\n// Check if the signature is valid for the provided public key, and that the\n// transaction is also valid (the merkle proof will be validated as well).\nconst isValid = await Signer.taproot.verify(txdata, 0, { pubkey, throws: true })\n\n// You can publish your transaction data using 'sendrawtransaction' in Bitcoin Core, or you \n// can use an external API (such as https://mempool.space/docs/api/rest#post-transaction).\n```\n\nMore examples to come!\n\n## Development / Testing\n\nThis library uses yarn for package management, tape for writing tests, and rollup for bundling cross-platform compatible code. Here are a few scripts that are useful for development.\n\n```bash\n## Compiles types and builds release candidates in /dist folder.\nyarn build\n## Run any typescript file using real-time compilation.\nyarn start contrib/example.ts\n## Runs all tests listed in test/tape.ts \nyarn test\n## Full macro script for generating a new release candidate.\nyarn release\n```\n\n## Bugs / Issues\n\nIf you run into any bugs or have any questions, please submit an issue ticket.\n\n## Contribution\n\nFeel free to fork and make contributions. Suggestions are welcome!\n\n## Future Roadmap\n\n - Add signature and validation for ecdsa (segwit and earlier).\n - Refactor and stress-test tree compilation with many (many) leaves.\n - Allow arbitrary ordering of tree elements.\n - Write more unit and vector tests (cover all the things).\n\n## Dependencies\n\nThis library contains minimal dependencies.  \n\n**Buff-Utils**  \nThe swiss-army-knife of byte manipulation.  \nhttps://github.com/cmdruid/buff-utils\n\n**Crypto-Utils**  \nUser-friendly cryptography tools.  \nhttps://github.com/cmdruid/crypto-utils\n\n## Resources  \n\n**BIP340 Wiki Page**  \nThis BIP covers schnorr signatures and verification.  \nhttps://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki\n\n**BIP341 Wiki Page**  \nThis BIP covers the construction of trees, signature hashes, and proofs.  \nhttps://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki\n\n**BIP342 Wiki Page**  \nThis BIP covers changes to opcodes and signature verification.  \nhttps://github.com/bitcoin/bips/blob/master/bip-0342.mediawiki\n\n**Tapscript example using Tap**  \nThis is a guide on how to use a command-line tool called btcdeb and Tap.  \nThis tool will help you create a taproot transaction from scratch, which  \nis great for learning (and to debug any issues with this library :-)).  \nhttps://github.com/bitcoin-core/btcdeb/blob/master/doc/tapscript-example-with-tap.md\n\n## License\n\nUse this library however you want!\n\n## Contact\n\nYou can find me on twitter at `@btctechsupport` or on nostr at `npub1gg5uy8cpqx4u8wj9yvlpwm5ht757vudmrzn8y27lwunt5f2ytlusklulq3`","funding_links":["bitcoin:bc1qnx8julmud2vqdqngxw9rmuv3js67kq9rzvtmm5","lnurl:cmd@stacker.news"],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcmdruid%2Ftapscript","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcmdruid%2Ftapscript","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcmdruid%2Ftapscript/lists"}