{"id":16563890,"url":"https://github.com/kanzure/python-vaults","last_synced_at":"2025-03-21T11:32:46.961Z","repository":{"id":66902654,"uuid":"234373457","full_name":"kanzure/python-vaults","owner":"kanzure","description":"Prototype bitcoin vault: cold storage and theft minimization","archived":false,"fork":false,"pushed_at":"2021-12-08T13:19:54.000Z","size":1501,"stargazers_count":53,"open_issues_count":1,"forks_count":8,"subscribers_count":8,"default_branch":"master","last_synced_at":"2024-10-11T20:43:03.826Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/kanzure.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"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}},"created_at":"2020-01-16T17:24:53.000Z","updated_at":"2024-06-11T20:09:12.000Z","dependencies_parsed_at":"2023-05-14T13:45:45.770Z","dependency_job_id":null,"html_url":"https://github.com/kanzure/python-vaults","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kanzure%2Fpython-vaults","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kanzure%2Fpython-vaults/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kanzure%2Fpython-vaults/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kanzure%2Fpython-vaults/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kanzure","download_url":"https://codeload.github.com/kanzure/python-vaults/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":221814965,"owners_count":16885086,"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":[],"created_at":"2024-10-11T20:42:34.067Z","updated_at":"2024-10-28T10:05:03.855Z","avatar_url":"https://github.com/kanzure.png","language":"Python","readme":"# Bitcoin vaults\n\nThis project provides a prototype for bitcoin vaults based around the concept\nof sharding and pre-signed transactions. The advantage of sharding into many\nUTXOs with different relative timelocks is that it gives the user an\nopportunity to observe on-chain thefts and react to them, without losing 100%\nof the funds.\n\nSee a\n**[visualization](https://diyhpl.us/~bryan/irc/graphviz-transaction-tree.png)**\nof the planned transaction tree:\n\n\u003ca href=\"https://diyhpl.us/~bryan/irc/graphviz-transaction-tree.png\"\u003e\u003cimg src=\"https://diyhpl.us/~bryan/irc/graphviz-transaction-tree.png\" width=510 height=401\u003e\u003c/a\u003e\n\n# WARNING\n\nThis is not production-ready code. Do not use this on bitcoin mainnet or any\nother mainnet. In fact, the private keys are static and hard coded into the\nprototype. Don't use this right now. It's only been used for about ~50 vaults,\nand before any real-world usage there should be many thousands of tested\nvaults.\n\n# Background (summary)\n\nA **vault** is an on-chain construct that keeps coins locked up until someone\nopens the vault. Upon opening the vault, the user has the option of sending\ncoins back into a new vault configured with identical keys, sweeping the coins\nto a cold storage wallet or more-deep cold storage vault, or allowing the coins\nto exit the vault and be used by some hot wallet.\n\n**Sharding** refers to a policy recommendation of splitting a bitcoin UTXO into\nmultiple new UTXOs that can each become un-vaulted only on a specific schedule.\nThe purpose of sharding is to minimize the total amount lost due to theft. By\nsampling the hot wallet with only one sharded UTXO at a time, the user can\nimmediately push the remaining UTXOs to cold storage the moment a theft on the\nhot wallet is detected. Without this feature, a user might keep 100% of their\nfunds in a single UTXO which can be stolen by that same kind of thief.\n\nAdditional background:\n\n\u003chttps://www.coindesk.com/the-vault-is-back-bitcoin-coder-to-revive-plan-to-shield-wallets-from-theft\u003e\n\n\u003chttps://bitcoinmagazine.com/articles/revamped-idea-bitcoin-vaults-may-end-exchange-hacks-good\u003e\n\n\u003chttps://lists.linuxfoundation.org/pipermail/bitcoin-dev/2019-August/017229.html\u003e\n\n\u003chttps://lists.linuxfoundation.org/pipermail/bitcoin-dev/2019-August/017231.html\u003e\n\n# What's in here?\n\nThis repository contains an experimental prototype of Bitcoin vaults using\npre-signed transactions.\n\nThe main entry point is in [initialize.py](vaults/commands/initialize.py) in\nthe `commands/` directory.\n\nIt works by connecting to bitcoind using RPC, mining some BTC to a specific\naddress, and then begins planning an entire tree of pre-signed transactions\nthat implement the vault. After tree planning, the tree is signed.\n\nTo run the vault program do something like:\n\n```\nmkdir -p /tmp/vaults/001/\ncd /tmp/vaults/001/\n\nvault init\n```\n\nThis will produce a few files. The interesting one is `log.txt` and\n`transaction-store.json` which has the list of transactions.\n\nIn `log.txt` or `text-rendering.txt` scroll to the line that starts with\n\"Start\" and those will be the signed transactions ready for broadcast.\n\nModules:\n\n* [vaults](vaults/) - primary python source code\n* [vaults.commands](vaults/commands/) - functions for command line interface\n  (see also [cli.py](vaults/cli.py)).\n* [vaults.models](vaults/models/) - script templates and transaction tree\n  modeling\n* [vaults.tests](vaults/tests/) - basic tests, nothing special\n\nSource code:\n\n* [models/plans.py](vaults/models/plans.py) - transaction tree models\n* [models/script_templates.py](vaults/models/script_templates.py) - script templates\n  defining scriptpubkeys and witness templates\n* [planner.py](vaults/planner.py) - transaction tree generator\n* [signing.py](vaults/signing.py) - sign the planned transaction tree\n* [state.py](vaults/state.py) - tools to check vault state on blockchain\n* [bip119_ctv.py](vaults/bip119_ctv.py) - bip119 OP_CHECKTEMPLATEVERIFY\n  implementation\n* [persist.py](vaults/persist.py) - save/load data\n* [graphics.py](vaults/graphics.py) - graphviz visualization for the planned\n  transaction tree\n* [rpc.py](vaults/rpc.py) - bitcoind RPC\n* [cli.py](vaults/cli.py) - command line interface, main wrapper\n* [config.py](vaults/config.py) - static configuration, not interesting\n* [loggingconfig.py](vaults/loggingconfig.py) - python logging configuration\n* [exceptions.py](vaults/exceptions.py) - vault-related exception definitions\n* [utils.py](vaults/utils.py) - miscellaneous functions (see also\n  [helpers](vaults/helpers/))\n* [vaultfile.py](vaults/vaultfile.py) - safety check for current working\n  directory\n* [loggingserver.py](vaults/loggingserver.py) - a sketch of what a logging\n  server might look like\n* [watchtower.py](vaults/watchtower.py) - a sketch of what a watchtower might\n  look like\n\n# Internal details\n\n\nThe two main entrypoints of interest are `setup_vault` in the\n[planner.py](vaults/planner.py) file and `sign_transaction_tree` in the\n[signing.py](vaults/signing.py) file. In practical usage, `vault init` calls\nthe entrypoint [commands/initialize.py](vaults/commands/initialize.py) which\ncalls the subsequent functions.\n\nThe project can only be run if `bitcoind -regtest` is running in the background.\nIt currently looks for `~/bitcoin/bitcoin.conf` to figure out the bitcoin RPC\nparameters. (TODO: Spin up regtest nodes automatically, especially for tests.)\n\n`PlannedInput`, `PlannedOutput`, and `PlannedTransaction` are custom classes\nthat represent the transaction tree, as defined in the\n[models](vaults/models/). The real bitcoin transactions are assembled in place\nhanging off of these objects. `output_utxos` is for the outputs on the current\ntransaction, while `child_transactions` on a `PlannedUTXO` are a list of\npossible child transactions. Obviously, because double spending is forbidden,\nonly one of those child transactions can make it into the blockchain.\n\n`ScriptTemplate` and its [descendents](vaults/models/script_templates.py) are\nhow UTXOs can describe themselves.  Each UTXO in the planned transaction tree\ncan use one of a limited number of scripts that were used to design the\ntransaction tree. `ScriptTemplate` is used to derive the `scriptPubKey` value\nand the witness necessary to spend that UTXO. The witness is obviously applied\nto the input that spends the UTXO.\n\n`PlannedInput.parameterize_witness_template_by_signing` is responsible for\nparsing a witness template, signing, and producing a valid witness. This is\nbased off of one of those `ScriptTemplate` classes that each UTXO picks: the\ninput has to have a witness that satisfies that UTXO's script template and\nscript.\n\nAfter running `vault init`, to load the serialized data, do the following:\n\n```\nfrom vaults.experiment import *\ninitial_planned_transaction = load()\n```\n\nBut it is probably simpler to do a one-liner like:\n\n```\nfrom experiment import *; initial_tx = from_dict(json.loads(open(\"output-auto.txt\", \"r\").read()));\n\ninitial_tx.name\ninitial_tx.output_utxos\ninitial_tx.output_utxos[0].name\ninitial_tx.output_utxos[0].child_transactions\nname = initial_tx.output_utxos[0].child_transactions[0].name\nassert name == \"Vault locking transaction\"\n```\n\n# Usage\n\nThis package installs the `vault` command, which is an interface for working\nwith the vault library based on vault files stored in the current working\ndirectory. The vault subcommands are as follows:\n\n```\nvault init\nvault info\nvault broadcast\n```\n\n**vault init** turns the current working directory into a new vault with new\nparameters. It creates all of the pre-signed transaction trees and also creates\nthe signatures. Note that `vault init` does not broadcast the transaction\nputting the coins into the vault-- that is the user's responsibility using the\nother commands, as are any other broadcast actions- again using the other\navailable commands.\n\n**vault info** gives information about the current status of the vault.\n\n**vault broadcast** transmits a pre-signed bitcoin transaction to the bitcoin\nnetwork.\n\n# Filesystem\n\nThe `vault init` should be run after creating a new directory via the `mkdir`\ncommand. Inside of the directory, run `vault init` and it will check for the\npresence of a `vaultfile` file. The purpose of the `vaultfile` is to place a\nmarker on the filesystem indicating that the folder already contains a vault\nand that the program should not overwrite it. Inside the file is some\nversioning information for future upgrade and file format version management\nreasons.\n\n# Installation\n\n```\n# clone the repository\ngit clone ...\n\n# setup a new virtualenv to avoid system-wide installation\npython3 -m venv venv/\n\n# enter into the virtualenv\nsource ./venv/bin/activate\n\n# install all python requirements\npip3 install -r requirements.txt\n\n# Use install to copy the code into the virtualenv's python modules directory,\n# or \"develop\" to use symlinks such that updates to the code propagate without\n# requiring re-installation.\npython3 setup.py install\n```\n\n# bitcoin.conf\n\nbitcoind configuration must include:\n\n```\nregtest=1\n\n# Data directory: where should this regtest blockchain live?\n#datadir=/tmp/bitcoin/regtest/\n\ntxindex=1\n\ndebug=1\nlogtimestamps=1\nprinttoconsole=1\n\nserver=1\nlisten=1\nmaxconnections=500\nnoconnec=1\n\n# Override fallback fee estimation.\n# (perhaps it can be disabled with =0?)\nfallbackfee=0.0001\n\n# To allow for creating zero-value CPFP hook outputs.\nacceptnonstdtxn=1\n\n# To allow for zero-fee transactions.\nminrelaytxfee=0\n\n# To mine zero-fee transactions (CPFP not implemented yet)\nblockmintxfee=0\n```\n\nRun with `bitcoind -regtest` if this is your `~/.bitcoin/bitcoin.conf` file,\notherwise you will have to run with `-conf=/path/to/bitcoin.conf` each time.\n\n```\nbitcoin-cli -regtest getblockchaininfo\n```\n\n# Testing\n\nRun the tests like this:\n\n```\npython3 -m unittest\n```\n\nFor regtest testing, some setup is required (and this changes based on the\nsecret key, and also based on the amount that is being inserted into the vault\nas defined in the initialization function):\n\n```\nbitcoin-cli -regtest generatetoaddress 100 bcrt1q08alc0e5ua69scxhvyma568nvguqccrvah6ml0\nbitcoin-cli -regtest sendtoaddress bcrt1q08alc0e5ua69scxhvyma568nvguqccrvah6ml0 5\n```\n\n# Private key\n\nPre-signed vaults are reliant on secure key deletion of a private key.\n\nIn python-vaults, the prototype has two ways to provide a private key-- one way\nis the default private key is constructed using the \"correct horse battery\nstaple\" passphrase, and the other way is to pass\n`--private-key=$regtestprivatekey` to the `vault init` command.\n\nIn the prototype, all of the keys- including for cold storage- are equal to the\ngiven private key. In the future, this needs to be updated and configured to\ninclude real values for the user's cold storage system and the other required\nkeys.\n\nThe default private key is not secure. Instead of passing an override private\nkey, another option (in the future) would be to implement something that uses\nsystem entropy to generate keys. However, the keys for cold storage and the hot\nwallet should be from other machines.\n\n# License\n\nBSD\n\n# Is this ready for production?\n\nNo, this software is not ready for production. There are a number of things\nthat need to be done before this could be used in production. This list is a\ngood starting point, but it is not exhaustive.\n\n**Private keys**: The way that private keys are handled should be improved.\nSecure key deletion is currently not happening. Private keys could be generated\nfrom some entropy- or from dice rolls- but this is also currently not\noccurring.\n\n**Multi-client protocol**: Right now the prototype assumes control of two\nprivate keys for the pre-signed transaction tree. However, in practice, there\nshould be multiple clients that pass data off to each other.\n\n**Extensive testing**: There should be substantial more unit testing of all the\nvarious functions, and a test framework to simulate many thousands of different\nscenarios with different initial configurations or parameters. Also, these\ntests should all be performed on not just the regtest network but also signet\nand testnet, and only then moving on to small-scale mainnet tests.\n\n**Improved initialization**: The current workflow for working with Bitcoin Core\nwallets is a little weird-- based on using RPC against a bitcoin wallet with\nbitcoin stored on the wallet. Instead, the initial transaction should be\nconstructed another way, perhaps with some steps that the user has to manually\nrun to feed in a txid, vout, etc.\n\n**User guides**: User documentation should be written for all procedures and\noperations, including information about how to operate airgapped devices and\nhow to store the key material.\n\n**Watchtower**: A watchtower implementation is required. This also needs to be\ntested and setup for production use.\n\n**Rust implementation**: Using python in production may not be a good idea.\nEvaluate which segments of the source code should be written in rust, and then\nbuild a rust implementation. Also convert all appropriate tests.\n\n**Code review**: This work should be extensively reviewed for best practices\nwith a deep knowledge of bitcoin software development.\n\nThe burn transactions are pretty dangerous. Users should store those in either\ntheir cold storage system or in a similar secure offline system.\n\n# See also\n\n* [bip119 OP\\_CHECKTEMPLATEVERIFY workshop transcript](https://diyhpl.us/wiki/transcripts/ctv-bip-review-workshop/)\n\n## Other pre-signed vault implementations\n\n* [python-vaults](https://github.com/kanzure/python-vaults) (you are here)\n* \u003chttps://github.com/fmr-llc/Vault-mbed\u003e\n* \u003chttps://github.com/JSwambo/bitcoin-vault\u003e (see also the [dynamic fee allocation](https://github.com/JSwambo/bitcoin-vault/pull/2) pull request)\n* kloaec's implementation [re-vault](https://github.com/re-vault/re-vault) --  see a [comparison video](https://www.youtube.com/watch?v=kmb2UDcbi50\u0026t=21m38s)\n* [ANYPREVOUT vaults](https://yakshaver.org/2021/11/18/covenants.html)\n\nThere are also two related upcoming manuscripts presently nearing final draft\nstatus. (As of 2020-03-28)\n\n\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkanzure%2Fpython-vaults","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkanzure%2Fpython-vaults","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkanzure%2Fpython-vaults/lists"}